Merge "Add warning about thread safety to deprecated methods" into androidx-main am: d5d49509dc
Original change: https://android-review.googlesource.com/c/platform/frameworks/support/+/2431454
Change-Id: If2c2a0e3c9ab07cf6efe7979a35a1e7ba87784c7
Signed-off-by: Automerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com>
diff --git a/activity/activity-ktx/api/current.ignore b/activity/activity-ktx/api/current.ignore
index 1c56f4f..f970b04 100644
--- a/activity/activity-ktx/api/current.ignore
+++ b/activity/activity-ktx/api/current.ignore
@@ -1,3 +1,9 @@
// Baseline format: 1.0
+RemovedClass: androidx.activity.OnBackPressedDispatcherKt:
+ Removed class androidx.activity.OnBackPressedDispatcherKt
RemovedClass: androidx.activity.PipHintTrackerKt:
Removed class androidx.activity.PipHintTrackerKt
+
+
+RemovedPackage: androidx.activity.contextaware:
+ Removed package androidx.activity.contextaware
diff --git a/activity/activity-ktx/api/restricted_current.ignore b/activity/activity-ktx/api/restricted_current.ignore
index 1c56f4f..f970b04 100644
--- a/activity/activity-ktx/api/restricted_current.ignore
+++ b/activity/activity-ktx/api/restricted_current.ignore
@@ -1,3 +1,9 @@
// Baseline format: 1.0
+RemovedClass: androidx.activity.OnBackPressedDispatcherKt:
+ Removed class androidx.activity.OnBackPressedDispatcherKt
RemovedClass: androidx.activity.PipHintTrackerKt:
Removed class androidx.activity.PipHintTrackerKt
+
+
+RemovedPackage: androidx.activity.contextaware:
+ Removed package androidx.activity.contextaware
diff --git a/activity/activity/api/current.txt b/activity/activity/api/current.txt
index bf98034..9f3e6ed 100644
--- a/activity/activity/api/current.txt
+++ b/activity/activity/api/current.txt
@@ -78,7 +78,10 @@
public abstract class OnBackPressedCallback {
ctor public OnBackPressedCallback(boolean enabled);
+ method @MainThread @RequiresApi(34) public void handleOnBackCancelled();
method @MainThread public abstract void handleOnBackPressed();
+ method @MainThread @RequiresApi(34) public void handleOnBackProgressed(android.window.BackEvent backEvent);
+ method @MainThread @RequiresApi(34) public void handleOnBackStarted(android.window.BackEvent backEvent);
method @MainThread public final boolean isEnabled();
method @MainThread public final void remove();
method @MainThread public final void setEnabled(boolean);
@@ -90,6 +93,9 @@
ctor public OnBackPressedDispatcher();
method @MainThread public void addCallback(androidx.activity.OnBackPressedCallback onBackPressedCallback);
method @MainThread public void addCallback(androidx.lifecycle.LifecycleOwner owner, androidx.activity.OnBackPressedCallback onBackPressedCallback);
+ method @MainThread @RequiresApi(34) @VisibleForTesting public void dispatchOnBackCancelled();
+ method @MainThread @RequiresApi(34) @VisibleForTesting public void dispatchOnBackProgressed(android.window.BackEvent backEvent);
+ method @MainThread @RequiresApi(34) @VisibleForTesting public void dispatchOnBackStarted(android.window.BackEvent backEvent);
method @MainThread public boolean hasEnabledCallbacks();
method @MainThread public void onBackPressed();
method @RequiresApi(android.os.Build.VERSION_CODES.TIRAMISU) public void setOnBackInvokedDispatcher(android.window.OnBackInvokedDispatcher invoker);
diff --git a/activity/activity/api/public_plus_experimental_current.txt b/activity/activity/api/public_plus_experimental_current.txt
index bf98034..9f3e6ed 100644
--- a/activity/activity/api/public_plus_experimental_current.txt
+++ b/activity/activity/api/public_plus_experimental_current.txt
@@ -78,7 +78,10 @@
public abstract class OnBackPressedCallback {
ctor public OnBackPressedCallback(boolean enabled);
+ method @MainThread @RequiresApi(34) public void handleOnBackCancelled();
method @MainThread public abstract void handleOnBackPressed();
+ method @MainThread @RequiresApi(34) public void handleOnBackProgressed(android.window.BackEvent backEvent);
+ method @MainThread @RequiresApi(34) public void handleOnBackStarted(android.window.BackEvent backEvent);
method @MainThread public final boolean isEnabled();
method @MainThread public final void remove();
method @MainThread public final void setEnabled(boolean);
@@ -90,6 +93,9 @@
ctor public OnBackPressedDispatcher();
method @MainThread public void addCallback(androidx.activity.OnBackPressedCallback onBackPressedCallback);
method @MainThread public void addCallback(androidx.lifecycle.LifecycleOwner owner, androidx.activity.OnBackPressedCallback onBackPressedCallback);
+ method @MainThread @RequiresApi(34) @VisibleForTesting public void dispatchOnBackCancelled();
+ method @MainThread @RequiresApi(34) @VisibleForTesting public void dispatchOnBackProgressed(android.window.BackEvent backEvent);
+ method @MainThread @RequiresApi(34) @VisibleForTesting public void dispatchOnBackStarted(android.window.BackEvent backEvent);
method @MainThread public boolean hasEnabledCallbacks();
method @MainThread public void onBackPressed();
method @RequiresApi(android.os.Build.VERSION_CODES.TIRAMISU) public void setOnBackInvokedDispatcher(android.window.OnBackInvokedDispatcher invoker);
diff --git a/activity/activity/api/restricted_current.txt b/activity/activity/api/restricted_current.txt
index 7561e11..57307e5 100644
--- a/activity/activity/api/restricted_current.txt
+++ b/activity/activity/api/restricted_current.txt
@@ -77,7 +77,10 @@
public abstract class OnBackPressedCallback {
ctor public OnBackPressedCallback(boolean enabled);
+ method @MainThread @RequiresApi(34) public void handleOnBackCancelled();
method @MainThread public abstract void handleOnBackPressed();
+ method @MainThread @RequiresApi(34) public void handleOnBackProgressed(android.window.BackEvent backEvent);
+ method @MainThread @RequiresApi(34) public void handleOnBackStarted(android.window.BackEvent backEvent);
method @MainThread public final boolean isEnabled();
method @MainThread public final void remove();
method @MainThread public final void setEnabled(boolean);
@@ -89,6 +92,9 @@
ctor public OnBackPressedDispatcher();
method @MainThread public void addCallback(androidx.activity.OnBackPressedCallback onBackPressedCallback);
method @MainThread public void addCallback(androidx.lifecycle.LifecycleOwner owner, androidx.activity.OnBackPressedCallback onBackPressedCallback);
+ method @MainThread @RequiresApi(34) @VisibleForTesting public void dispatchOnBackCancelled();
+ method @MainThread @RequiresApi(34) @VisibleForTesting public void dispatchOnBackProgressed(android.window.BackEvent backEvent);
+ method @MainThread @RequiresApi(34) @VisibleForTesting public void dispatchOnBackStarted(android.window.BackEvent backEvent);
method @MainThread public boolean hasEnabledCallbacks();
method @MainThread public void onBackPressed();
method @RequiresApi(android.os.Build.VERSION_CODES.TIRAMISU) public void setOnBackInvokedDispatcher(android.window.OnBackInvokedDispatcher invoker);
diff --git a/activity/activity/src/androidTest/java/androidx/activity/OnBackPressedDispatcherInvokerTest.kt b/activity/activity/src/androidTest/java/androidx/activity/OnBackPressedDispatcherInvokerTest.kt
index 1ff31b7..47717b5 100644
--- a/activity/activity/src/androidTest/java/androidx/activity/OnBackPressedDispatcherInvokerTest.kt
+++ b/activity/activity/src/androidTest/java/androidx/activity/OnBackPressedDispatcherInvokerTest.kt
@@ -17,6 +17,8 @@
package androidx.activity
import android.os.Build
+import android.window.BackEvent
+import android.window.BackEvent.EDGE_LEFT
import android.window.OnBackInvokedCallback
import android.window.OnBackInvokedDispatcher
import androidx.annotation.RequiresApi
@@ -180,4 +182,59 @@
assertThat(unregisterCount).isEqualTo(1)
}
+
+ @Test
+ @RequiresApi(34)
+ @SdkSuppress(minSdkVersion = 34)
+ fun testSimpleAnimatedCallback() {
+ var registerCount = 0
+ var unregisterCount = 0
+ val invoker = object : OnBackInvokedDispatcher {
+ override fun registerOnBackInvokedCallback(p0: Int, p1: OnBackInvokedCallback) {
+ registerCount++
+ }
+
+ override fun unregisterOnBackInvokedCallback(p0: OnBackInvokedCallback) {
+ unregisterCount++
+ }
+ }
+
+ val dispatcher = OnBackPressedDispatcher()
+
+ dispatcher.setOnBackInvokedDispatcher(invoker)
+
+ var startedCount = 0
+ var progressedCount = 0
+ var cancelledCount = 0
+ val callback = object : OnBackPressedCallback(true) {
+ override fun handleOnBackStarted(backEvent: BackEvent) {
+ startedCount++
+ }
+
+ override fun handleOnBackProgressed(backEvent: BackEvent) {
+ progressedCount++
+ }
+ override fun handleOnBackPressed() { }
+ override fun handleOnBackCancelled() {
+ cancelledCount++
+ }
+ }
+
+ dispatcher.addCallback(callback)
+
+ assertThat(registerCount).isEqualTo(1)
+
+ dispatcher.dispatchOnBackStarted(BackEvent(0.1F, 0.1F, 0.1F, EDGE_LEFT))
+ assertThat(startedCount).isEqualTo(1)
+
+ dispatcher.dispatchOnBackProgressed(BackEvent(0.1F, 0.1F, 0.1F, EDGE_LEFT))
+ assertThat(progressedCount).isEqualTo(1)
+
+ dispatcher.dispatchOnBackCancelled()
+ assertThat(cancelledCount).isEqualTo(1)
+
+ callback.remove()
+
+ assertThat(unregisterCount).isEqualTo(1)
+ }
}
diff --git a/activity/activity/src/main/java/androidx/activity/OnBackPressedCallback.kt b/activity/activity/src/main/java/androidx/activity/OnBackPressedCallback.kt
index 3101ef7..bc4b001 100644
--- a/activity/activity/src/main/java/androidx/activity/OnBackPressedCallback.kt
+++ b/activity/activity/src/main/java/androidx/activity/OnBackPressedCallback.kt
@@ -15,7 +15,9 @@
*/
package androidx.activity
+import android.window.BackEvent
import androidx.annotation.MainThread
+import androidx.annotation.RequiresApi
import java.util.concurrent.CopyOnWriteArrayList
/**
@@ -67,11 +69,38 @@
fun remove() = cancellables.forEach { it.cancel() }
/**
+ * Callback for handling the system UI generated equivalent to
+ * [OnBackPressedDispatcher.dispatchOnBackStarted].
+ */
+ @Suppress("CallbackMethodName") /* mirror handleOnBackPressed local style */
+ @RequiresApi(34)
+ @MainThread
+ open fun handleOnBackStarted(backEvent: BackEvent) {}
+
+ /**
+ * Callback for handling the system UI generated equivalent to
+ * [OnBackPressedDispatcher.dispatchOnBackProgressed].
+ */
+ @Suppress("CallbackMethodName") /* mirror handleOnBackPressed local style */
+ @RequiresApi(34)
+ @MainThread
+ open fun handleOnBackProgressed(backEvent: BackEvent) {}
+
+ /**
* Callback for handling the [OnBackPressedDispatcher.onBackPressed] event.
*/
@MainThread
abstract fun handleOnBackPressed()
+ /**
+ * Callback for handling the system UI generated equivalent to
+ * [OnBackPressedDispatcher.dispatchOnBackCancelled].
+ */
+ @Suppress("CallbackMethodName") /* mirror handleOnBackPressed local style */
+ @RequiresApi(34)
+ @MainThread
+ open fun handleOnBackCancelled() {}
+
@JvmName("addCancellable")
internal fun addCancellable(cancellable: Cancellable) {
cancellables.add(cancellable)
diff --git a/activity/activity/src/main/java/androidx/activity/OnBackPressedDispatcher.kt b/activity/activity/src/main/java/androidx/activity/OnBackPressedDispatcher.kt
index 5319d9e..a4eed5d 100644
--- a/activity/activity/src/main/java/androidx/activity/OnBackPressedDispatcher.kt
+++ b/activity/activity/src/main/java/androidx/activity/OnBackPressedDispatcher.kt
@@ -16,11 +16,17 @@
package androidx.activity
import android.os.Build
+import android.window.BackEvent
+import android.window.OnBackAnimationCallback
import android.window.OnBackInvokedCallback
import android.window.OnBackInvokedDispatcher
import androidx.annotation.DoNotInline
import androidx.annotation.MainThread
+import androidx.annotation.OptIn
import androidx.annotation.RequiresApi
+import androidx.annotation.VisibleForTesting
+import androidx.core.os.BuildCompat
+import androidx.core.os.BuildCompat.PrereleaseSdkCheck
import androidx.lifecycle.Lifecycle
import androidx.lifecycle.LifecycleEventObserver
import androidx.lifecycle.LifecycleOwner
@@ -51,6 +57,7 @@
* When constructing an instance of this class, the [fallbackOnBackPressed] can be set to
* receive a callback if [onBackPressed] is called when [hasEnabledCallbacks] returns `false`.
*/
+@OptIn(PrereleaseSdkCheck::class)
class OnBackPressedDispatcher @JvmOverloads constructor(
private val fallbackOnBackPressed: Runnable? = null
) {
@@ -99,7 +106,16 @@
enabledChangedCallback = {
updateBackInvokedCallbackState()
}
- onBackInvokedCallback = Api33Impl.createOnBackInvokedCallback { onBackPressed() }
+ onBackInvokedCallback = if (BuildCompat.isAtLeastU()) {
+ Api34Impl.createOnBackAnimationCallback(
+ { backEvent -> onBackStarted(backEvent) },
+ { backEvent -> onBackProgressed(backEvent) },
+ { onBackPressed() },
+ { onBackCancelled() }
+ )
+ } else {
+ Api33Impl.createOnBackInvokedCallback { onBackPressed() }
+ }
}
}
@@ -195,6 +211,44 @@
it.isEnabled
}
+ @VisibleForTesting
+ @RequiresApi(34)
+ @MainThread
+ fun dispatchOnBackStarted(backEvent: BackEvent) {
+ onBackStarted(backEvent)
+ }
+
+ @RequiresApi(34)
+ @MainThread
+ private fun onBackStarted(backEvent: BackEvent) {
+ val callback = onBackPressedCallbacks.lastOrNull {
+ it.isEnabled
+ }
+ if (callback != null) {
+ callback.handleOnBackStarted(backEvent)
+ return
+ }
+ }
+
+ @VisibleForTesting
+ @RequiresApi(34)
+ @MainThread
+ fun dispatchOnBackProgressed(backEvent: BackEvent) {
+ onBackProgressed(backEvent)
+ }
+
+ @RequiresApi(34)
+ @MainThread
+ private fun onBackProgressed(backEvent: BackEvent) {
+ val callback = onBackPressedCallbacks.lastOrNull {
+ it.isEnabled
+ }
+ if (callback != null) {
+ callback.handleOnBackProgressed(backEvent)
+ return
+ }
+ }
+
/**
* Trigger a call to the currently added [callbacks][OnBackPressedCallback] in reverse
* order in which they were added. Only if the most recently added callback is not
@@ -216,6 +270,25 @@
fallbackOnBackPressed?.run()
}
+ @VisibleForTesting
+ @RequiresApi(34)
+ @MainThread
+ fun dispatchOnBackCancelled() {
+ onBackCancelled()
+ }
+
+ @RequiresApi(34)
+ @MainThread
+ private fun onBackCancelled() {
+ val callback = onBackPressedCallbacks.lastOrNull {
+ it.isEnabled
+ }
+ if (callback != null) {
+ callback.handleOnBackCancelled()
+ return
+ }
+ }
+
private inner class OnBackPressedCancellable(
private val onBackPressedCallback: OnBackPressedCallback
) : Cancellable {
@@ -286,6 +359,35 @@
return OnBackInvokedCallback { onBackInvoked() }
}
}
+
+ @RequiresApi(34)
+ internal object Api34Impl {
+ @DoNotInline
+ fun createOnBackAnimationCallback(
+ onBackStarted: (backEvent: BackEvent) -> Unit,
+ onBackProgressed: (backEvent: BackEvent) -> Unit,
+ onBackInvoked: () -> Unit,
+ onBackCancelled: () -> Unit
+ ): OnBackInvokedCallback {
+ return object : OnBackAnimationCallback {
+ override fun onBackStarted(backEvent: BackEvent) {
+ onBackStarted(backEvent)
+ }
+
+ override fun onBackProgressed(backEvent: BackEvent) {
+ onBackProgressed(backEvent)
+ }
+
+ override fun onBackInvoked() {
+ onBackInvoked()
+ }
+
+ override fun onBackCancelled() {
+ onBackCancelled()
+ }
+ }
+ }
+ }
}
/**
diff --git a/appcompat/appcompat-resources/api/api_lint.ignore b/appcompat/appcompat-resources/api/api_lint.ignore
index 0cfa261..dd0cf8d 100644
--- a/appcompat/appcompat-resources/api/api_lint.ignore
+++ b/appcompat/appcompat-resources/api/api_lint.ignore
@@ -17,6 +17,8 @@
Missing nullability on parameter `tint` in method `setTintList`
MissingNullability: androidx.appcompat.graphics.drawable.DrawableWrapperCompat#DrawableWrapperCompat(android.graphics.drawable.Drawable) parameter #0:
Missing nullability on parameter `drawable` in method `DrawableWrapperCompat`
+MissingNullability: androidx.appcompat.graphics.drawable.DrawableWrapperCompat#draw(android.graphics.Canvas) parameter #0:
+ Missing nullability on parameter `canvas` in method `draw`
MissingNullability: androidx.appcompat.graphics.drawable.DrawableWrapperCompat#getCurrent():
Missing nullability on method `getCurrent` return
MissingNullability: androidx.appcompat.graphics.drawable.DrawableWrapperCompat#getPadding(android.graphics.Rect) parameter #0:
diff --git a/appcompat/appcompat/api/api_lint.ignore b/appcompat/appcompat/api/api_lint.ignore
index ff1d34f..90541cfd 100644
--- a/appcompat/appcompat/api/api_lint.ignore
+++ b/appcompat/appcompat/api/api_lint.ignore
@@ -91,12 +91,8 @@
Invalid nullability on parameter `filters` in method `setFilters`. Parameters of overrides cannot be NonNull if the super parameter is unannotated.
InvalidNullabilityOverride: androidx.appcompat.widget.AppCompatToggleButton#setFilters(android.text.InputFilter[]) parameter #0:
Invalid nullability on parameter `filters` in method `setFilters`. Parameters of overrides cannot be NonNull if the super parameter is unannotated.
-InvalidNullabilityOverride: androidx.appcompat.widget.LinearLayoutCompat#onDraw(android.graphics.Canvas) parameter #0:
- Invalid nullability on parameter `canvas` in method `onDraw`. Parameters of overrides cannot be NonNull if the super parameter is unannotated.
InvalidNullabilityOverride: androidx.appcompat.widget.ListPopupWindow#getListView():
Invalid nullability on method `getListView` return. Overrides of unannotated super method cannot be Nullable.
-InvalidNullabilityOverride: androidx.appcompat.widget.SwitchCompat#draw(android.graphics.Canvas) parameter #0:
- Invalid nullability on parameter `c` in method `draw`. Parameters of overrides cannot be NonNull if the super parameter is unannotated.
InvalidNullabilityOverride: androidx.appcompat.widget.SwitchCompat#getCustomSelectionActionModeCallback():
Invalid nullability on method `getCustomSelectionActionModeCallback` return. Overrides of unannotated super method cannot be Nullable.
InvalidNullabilityOverride: androidx.appcompat.widget.SwitchCompat#setFilters(android.text.InputFilter[]) parameter #0:
@@ -555,6 +551,8 @@
Missing nullability on parameter `attrs` in method `createView`
MissingNullability: androidx.appcompat.graphics.drawable.DrawerArrowDrawable#DrawerArrowDrawable(android.content.Context) parameter #0:
Missing nullability on parameter `context` in method `DrawerArrowDrawable`
+MissingNullability: androidx.appcompat.graphics.drawable.DrawerArrowDrawable#draw(android.graphics.Canvas) parameter #0:
+ Missing nullability on parameter `canvas` in method `draw`
MissingNullability: androidx.appcompat.graphics.drawable.DrawerArrowDrawable#getPaint():
Missing nullability on method `getPaint` return
MissingNullability: androidx.appcompat.graphics.drawable.DrawerArrowDrawable#setColorFilter(android.graphics.ColorFilter) parameter #0:
@@ -727,6 +725,8 @@
Missing nullability on parameter `p` in method `generateLayoutParams`
MissingNullability: androidx.appcompat.widget.LinearLayoutCompat#getDividerDrawable():
Missing nullability on method `getDividerDrawable` return
+MissingNullability: androidx.appcompat.widget.LinearLayoutCompat#onDraw(android.graphics.Canvas) parameter #0:
+ Missing nullability on parameter `canvas` in method `onDraw`
MissingNullability: androidx.appcompat.widget.LinearLayoutCompat#onInitializeAccessibilityEvent(android.view.accessibility.AccessibilityEvent) parameter #0:
Missing nullability on parameter `event` in method `onInitializeAccessibilityEvent`
MissingNullability: androidx.appcompat.widget.LinearLayoutCompat#onInitializeAccessibilityNodeInfo(android.view.accessibility.AccessibilityNodeInfo) parameter #0:
@@ -797,6 +797,8 @@
Missing nullability on parameter `source` in method `onShareTargetSelected`
MissingNullability: androidx.appcompat.widget.ShareActionProvider.OnShareTargetSelectedListener#onShareTargetSelected(androidx.appcompat.widget.ShareActionProvider, android.content.Intent) parameter #1:
Missing nullability on parameter `intent` in method `onShareTargetSelected`
+MissingNullability: androidx.appcompat.widget.SwitchCompat#draw(android.graphics.Canvas) parameter #0:
+ Missing nullability on parameter `c` in method `draw`
MissingNullability: androidx.appcompat.widget.SwitchCompat#getTextOff():
Missing nullability on method `getTextOff` return
MissingNullability: androidx.appcompat.widget.SwitchCompat#getTextOn():
@@ -831,6 +833,8 @@
Missing nullability on parameter `thumb` in method `setThumbDrawable`
MissingNullability: androidx.appcompat.widget.SwitchCompat#setTrackDrawable(android.graphics.drawable.Drawable) parameter #0:
Missing nullability on parameter `track` in method `setTrackDrawable`
+MissingNullability: androidx.appcompat.widget.SwitchCompat#verifyDrawable(android.graphics.drawable.Drawable) parameter #0:
+ Missing nullability on parameter `who` in method `verifyDrawable`
MissingNullability: androidx.appcompat.widget.Toolbar#checkLayoutParams(android.view.ViewGroup.LayoutParams) parameter #0:
Missing nullability on parameter `p` in method `checkLayoutParams`
MissingNullability: androidx.appcompat.widget.Toolbar#generateDefaultLayoutParams():
diff --git a/appcompat/appcompat/src/androidTest/java/androidx/appcompat/app/LocalesActivityA.java b/appcompat/appcompat/src/androidTest/java/androidx/appcompat/app/LocalesActivityA.java
index 069c76c..5719451 100644
--- a/appcompat/appcompat/src/androidTest/java/androidx/appcompat/app/LocalesActivityA.java
+++ b/appcompat/appcompat/src/androidTest/java/androidx/appcompat/app/LocalesActivityA.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2022 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,4 +20,3 @@
* An activity for locales with a unique class name.
*/
public class LocalesActivityA extends LocalesUpdateActivity {}
-
diff --git a/appsearch/appsearch-local-storage/proguard-rules.pro b/appsearch/appsearch-local-storage/proguard-rules.pro
index 82c4b719..335e9e8 100644
--- a/appsearch/appsearch-local-storage/proguard-rules.pro
+++ b/appsearch/appsearch-local-storage/proguard-rules.pro
@@ -19,7 +19,7 @@
<fields>;
}
-keep class com.google.android.icing.BreakIteratorBatcher { *; }
--keepclassmembers public class com.google.android.icing.IcingSearchEngine {
+-keepclassmembers public class com.google.android.icing.IcingSearchEngineImpl {
private long nativePointer;
}
diff --git a/appsearch/appsearch-local-storage/src/androidTest/java/androidx/appsearch/localstorage/AppSearchImplTest.java b/appsearch/appsearch-local-storage/src/androidTest/java/androidx/appsearch/localstorage/AppSearchImplTest.java
index 4fef3f4..6adfa73 100644
--- a/appsearch/appsearch-local-storage/src/androidTest/java/androidx/appsearch/localstorage/AppSearchImplTest.java
+++ b/appsearch/appsearch-local-storage/src/androidTest/java/androidx/appsearch/localstorage/AppSearchImplTest.java
@@ -3326,7 +3326,10 @@
@Test
public void testRemoveByQuery_withJoinSpec_throwsException() {
Exception e = assertThrows(IllegalArgumentException.class,
- () -> mAppSearchImpl.removeByQuery("", "", "",
+ () -> mAppSearchImpl.removeByQuery(
+ /*packageName=*/"",
+ /*databaseName=*/"",
+ /*queryExpression=*/"",
new SearchSpec.Builder()
.setJoinSpec(new JoinSpec.Builder("childProp").build())
.build(),
diff --git a/appsearch/appsearch-local-storage/src/androidTest/java/androidx/appsearch/localstorage/converter/SearchSpecToProtoConverterTest.java b/appsearch/appsearch-local-storage/src/androidTest/java/androidx/appsearch/localstorage/converter/SearchSpecToProtoConverterTest.java
index 271bf2a..5b2ced5 100644
--- a/appsearch/appsearch-local-storage/src/androidTest/java/androidx/appsearch/localstorage/converter/SearchSpecToProtoConverterTest.java
+++ b/appsearch/appsearch-local-storage/src/androidTest/java/androidx/appsearch/localstorage/converter/SearchSpecToProtoConverterTest.java
@@ -70,19 +70,19 @@
searchSpec,
/*prefixes=*/ImmutableSet.of(prefix1, prefix2),
/*namespaceMap=*/ImmutableMap.of(
- prefix1, ImmutableSet.of(
- prefix1 + "namespace1",
- prefix1 + "namespace2"),
- prefix2, ImmutableSet.of(
- prefix2 + "namespace1",
- prefix2 + "namespace2")),
+ prefix1, ImmutableSet.of(
+ prefix1 + "namespace1",
+ prefix1 + "namespace2"),
+ prefix2, ImmutableSet.of(
+ prefix2 + "namespace1",
+ prefix2 + "namespace2")),
/*schemaMap=*/ImmutableMap.of(
- prefix1, ImmutableMap.of(
- prefix1 + "typeA", configProto,
- prefix1 + "typeB", configProto),
- prefix2, ImmutableMap.of(
- prefix2 + "typeA", configProto,
- prefix2 + "typeB", configProto)));
+ prefix1, ImmutableMap.of(
+ prefix1 + "typeA", configProto,
+ prefix1 + "typeB", configProto),
+ prefix2, ImmutableMap.of(
+ prefix2 + "typeA", configProto,
+ prefix2 + "typeB", configProto)));
// Convert SearchSpec to proto.
SearchSpecProto searchSpecProto = converter.toSearchSpecProto();
@@ -161,6 +161,93 @@
ScoringSpecProto.RankingStrategy.Code.CREATION_TIMESTAMP);
}
+ @Test
+ public void testToSearchSpec_withJoinSpec_childSearchesOtherSchema() throws Exception {
+ String prefix1 = PrefixUtil.createPrefix("package", "database1");
+ String prefix2 = PrefixUtil.createPrefix("package", "database2");
+
+ SearchSpec nestedSearchSpec =
+ new SearchSpec.Builder()
+ .addFilterPackageNames("package")
+ .addFilterSchemas("typeA")
+ .build();
+ SearchSpec.Builder searchSpec =
+ new SearchSpec.Builder()
+ .addFilterPackageNames("package")
+ .addFilterSchemas("typeB");
+
+ // Create a JoinSpec object and set it in the converter
+ JoinSpec joinSpec =
+ new JoinSpec.Builder("childPropertyExpression")
+ .setNestedSearch("nestedQuery", nestedSearchSpec)
+ .setMaxJoinedResultCount(10)
+ .build();
+
+ searchSpec.setJoinSpec(joinSpec);
+
+ SchemaTypeConfigProto configProto = SchemaTypeConfigProto.getDefaultInstance();
+ SearchSpecToProtoConverter converter =
+ new SearchSpecToProtoConverter(
+ /*queryExpression=*/ "query",
+ searchSpec.build(),
+ /*prefixes=*/ ImmutableSet.of(prefix1, prefix2),
+ /*namespaceMap=*/ ImmutableMap.of(
+ prefix1,
+ ImmutableSet.of(
+ prefix1 + "namespace1", prefix1 + "namespace2"),
+ prefix2,
+ ImmutableSet.of(
+ prefix2 + "namespace1", prefix2 + "namespace2")),
+ /*schemaMap=*/ ImmutableMap.of(
+ prefix1,
+ ImmutableMap.of(
+ prefix1 + "typeA", configProto,
+ prefix1 + "typeB", configProto),
+ prefix2,
+ ImmutableMap.of(
+ prefix2 + "typeA", configProto,
+ prefix2 + "typeB", configProto)));
+
+ AppSearchImpl appSearchImpl = AppSearchImpl.create(
+ mTemporaryFolder.newFolder(),
+ new UnlimitedLimitConfig(),
+ /*initStatsBuilder=*/null,
+ ALWAYS_OPTIMIZE,
+ /*visibilityChecker=*/null);
+ VisibilityStore visibilityStore = new VisibilityStore(appSearchImpl);
+ converter.removeInaccessibleSchemaFilter(
+ new CallerAccess(/*callingPackageName=*/"package"),
+ visibilityStore,
+ AppSearchTestUtils.createMockVisibilityChecker(
+ /*visiblePrefixedSchemas=*/ ImmutableSet.of(
+ prefix1 + "typeA", prefix1 + "typeB", prefix2 + "typeA",
+ prefix2 + "typeB")));
+
+ // Convert SearchSpec to proto.
+ SearchSpecProto searchSpecProto = converter.toSearchSpecProto();
+
+ assertThat(searchSpecProto.getQuery()).isEqualTo("query");
+ assertThat(searchSpecProto.getSchemaTypeFiltersList())
+ .containsExactly(
+ "package$database1/typeB",
+ "package$database2/typeB");
+ assertThat(searchSpecProto.getNamespaceFiltersList())
+ .containsExactly(
+ "package$database1/namespace1", "package$database1/namespace2",
+ "package$database2/namespace1", "package$database2/namespace2");
+
+ // Assert that the joinSpecProto is set correctly in the searchSpecProto
+ assertThat(searchSpecProto.hasJoinSpec()).isTrue();
+
+ JoinSpecProto joinSpecProto = searchSpecProto.getJoinSpec();
+ assertThat(joinSpecProto.hasNestedSpec()).isTrue();
+
+ JoinSpecProto.NestedSpecProto nestedSpecProto = joinSpecProto.getNestedSpec();
+ assertThat(nestedSpecProto.getSearchSpec().getSchemaTypeFiltersList())
+ .containsExactly(
+ "package$database1/typeA",
+ "package$database2/typeA");
+ }
@Test
public void testToScoringSpecProto() {
@@ -567,9 +654,14 @@
final String prefix = PrefixUtil.createPrefix("package", "database");
SchemaTypeConfigProto schemaTypeConfigProto =
SchemaTypeConfigProto.newBuilder().getDefaultInstanceForType();
+
+ SearchSpec nestedSearchSpec = new SearchSpec.Builder().build();
+ JoinSpec joinSpec = new JoinSpec.Builder("entity")
+ .setNestedSearch("", nestedSearchSpec).build();
+
SearchSpecToProtoConverter converter = new SearchSpecToProtoConverter(
/*queryExpression=*/"",
- new SearchSpec.Builder().build(),
+ new SearchSpec.Builder().setJoinSpec(joinSpec).build(),
/*prefixes=*/ImmutableSet.of(prefix),
/*namespaceMap=*/ImmutableMap.of(
prefix, ImmutableSet.of("package$database/namespace1")),
@@ -590,12 +682,21 @@
// schema 2 is filtered out since it is not searchable for user.
assertThat(searchSpecProto.getSchemaTypeFiltersList()).containsExactly(
prefix + "schema1", prefix + "schema3");
+
+ SearchSpecProto nestedSearchProto =
+ searchSpecProto.getJoinSpec().getNestedSpec().getSearchSpec();
+ assertThat(nestedSearchProto.getSchemaTypeFiltersList()).containsExactly(
+ prefix + "schema1", prefix + "schema3");
}
@Test
public void testIsNothingToSearch() {
String prefix = PrefixUtil.createPrefix("package", "database");
+ SearchSpec nestedSearchSpec = new SearchSpec.Builder().build();
+ JoinSpec joinSpec = new JoinSpec.Builder("entity")
+ .setNestedSearch("nested", nestedSearchSpec).build();
SearchSpec searchSpec = new SearchSpec.Builder()
+ .setJoinSpec(joinSpec)
.addFilterSchemas("schema").addFilterNamespaces("namespace").build();
// build maps
@@ -638,6 +739,54 @@
/*visibilityStore=*/null,
/*visibilityChecker=*/null);
assertThat(nonEmptyConverter.hasNothingToSearch()).isTrue();
+ // As the JoinSpec has nothing to search, it should not be part of the SearchSpec
+ assertThat(nonEmptyConverter.toSearchSpecProto().hasJoinSpec()).isFalse();
+ }
+
+ @Test
+ public void testRemoveInaccessibleSchemaFilterWithEmptyNestedFilter() throws Exception {
+ AppSearchImpl appSearchImpl = AppSearchImpl.create(
+ mTemporaryFolder.newFolder(),
+ new UnlimitedLimitConfig(),
+ /*initStatsBuilder=*/null,
+ ALWAYS_OPTIMIZE,
+ /*visibilityChecker=*/null);
+ VisibilityStore visibilityStore = new VisibilityStore(appSearchImpl);
+
+ final String prefix = PrefixUtil.createPrefix("package", "database");
+ SchemaTypeConfigProto schemaTypeConfigProto =
+ SchemaTypeConfigProto.newBuilder().getDefaultInstanceForType();
+
+ SearchSpec nestedSearchSpec = new SearchSpec.Builder()
+ .addFilterSchemas(ImmutableSet.of(prefix + "schema1", prefix + "schema2"))
+ .build();
+ JoinSpec joinSpec = new JoinSpec.Builder("entity")
+ .setNestedSearch("nested", nestedSearchSpec).build();
+
+ SearchSpecToProtoConverter converter = new SearchSpecToProtoConverter(
+ /*queryExpression=*/"",
+ new SearchSpec.Builder().setJoinSpec(joinSpec).build(),
+ /*prefixes=*/ImmutableSet.of(prefix),
+ /*namespaceMap=*/ImmutableMap.of(
+ prefix, ImmutableSet.of("package$database/namespace1")),
+ /*schemaMap=*/ImmutableMap.of(
+ prefix, ImmutableMap.of(
+ "package$database/schema1", schemaTypeConfigProto,
+ "package$database/schema2", schemaTypeConfigProto,
+ "package$database/schema3", schemaTypeConfigProto)));
+
+ converter.removeInaccessibleSchemaFilter(
+ new CallerAccess(/*callingPackageName=*/"otherPackageName"),
+ visibilityStore,
+ AppSearchTestUtils.createMockVisibilityChecker(
+ /*visiblePrefixedSchemas=*/ ImmutableSet.of(prefix + "schema3")));
+
+ SearchSpecProto searchSpecProto = converter.toSearchSpecProto();
+ assertThat(searchSpecProto.getSchemaTypeFiltersList()).containsExactly(prefix + "schema3");
+
+ // Schema 1 and 2 are filtered out of the nested spec. As the JoinSpec has nothing to
+ // search, it should not be part of the SearchSpec.
+ assertThat(searchSpecProto.hasJoinSpec()).isFalse();
}
@Test
diff --git a/appsearch/appsearch-local-storage/src/main/java/androidx/appsearch/localstorage/AppSearchImpl.java b/appsearch/appsearch-local-storage/src/main/java/androidx/appsearch/localstorage/AppSearchImpl.java
index f445af7..49388be 100644
--- a/appsearch/appsearch-local-storage/src/main/java/androidx/appsearch/localstorage/AppSearchImpl.java
+++ b/appsearch/appsearch-local-storage/src/main/java/androidx/appsearch/localstorage/AppSearchImpl.java
@@ -2218,6 +2218,9 @@
mReadWriteLock.writeLock().lock();
try {
throwIfClosedLocked();
+ if (LogUtil.DEBUG) {
+ Log.d(TAG, "Clear data for package: " + packageName);
+ }
// TODO(b/193494000): We are calling getPackageToDatabases here and in several other
// places within AppSearchImpl. This method is not efficient and does a lot of string
// manipulation. We should find a way to cache the package to database map so it can
diff --git a/appsearch/appsearch-local-storage/src/main/java/androidx/appsearch/localstorage/converter/SearchSpecToProtoConverter.java b/appsearch/appsearch-local-storage/src/main/java/androidx/appsearch/localstorage/converter/SearchSpecToProtoConverter.java
index 0e80ebe..dc7965c 100644
--- a/appsearch/appsearch-local-storage/src/main/java/androidx/appsearch/localstorage/converter/SearchSpecToProtoConverter.java
+++ b/appsearch/appsearch-local-storage/src/main/java/androidx/appsearch/localstorage/converter/SearchSpecToProtoConverter.java
@@ -26,6 +26,7 @@
import androidx.annotation.Nullable;
import androidx.annotation.RestrictTo;
import androidx.appsearch.app.JoinSpec;
+import androidx.appsearch.app.SearchResult;
import androidx.appsearch.app.SearchSpec;
import androidx.appsearch.exceptions.AppSearchException;
import androidx.appsearch.localstorage.visibilitystore.CallerAccess;
@@ -79,12 +80,13 @@
* filters which are stored in AppSearch. This is a field so that we can generate nested protos.
*/
private final Map<String, Set<String>> mNamespaceMap;
+
/**
- *The cached Map of {@code <Prefix, Map<PrefixedSchemaType, schemaProto>>} stores all
- * prefixed schema filters which are stored inAppSearch. This is a field so that we can
- * generated nested protos.
+ * The nested converter, which contains SearchSpec, ResultSpec, and ScoringSpec information
+ * about the nested query. This will remain null if there is no nested {@link JoinSpec}.
*/
- private final Map<String, Map<String, SchemaTypeConfigProto>> mSchemaMap;
+ @Nullable
+ private SearchSpecToProtoConverter mNestedConverter = null;
/**
* Creates a {@link SearchSpecToProtoConverter} for given {@link SearchSpec}.
@@ -107,7 +109,6 @@
mSearchSpec = Preconditions.checkNotNull(searchSpec);
mPrefixes = Preconditions.checkNotNull(prefixes);
mNamespaceMap = Preconditions.checkNotNull(namespaceMap);
- mSchemaMap = Preconditions.checkNotNull(schemaMap);
mTargetPrefixedNamespaceFilters =
SearchSpecToProtoConverterUtil.generateTargetNamespaceFilters(
prefixes, namespaceMap, searchSpec.getFilterNamespaces());
@@ -120,11 +121,27 @@
} else {
mTargetPrefixedSchemaFilters = new ArraySet<>();
}
+
+ JoinSpec joinSpec = searchSpec.getJoinSpec();
+ if (joinSpec == null) {
+ return;
+ }
+
+ mNestedConverter = new SearchSpecToProtoConverter(
+ joinSpec.getNestedQuery(),
+ joinSpec.getNestedSearchSpec(),
+ mPrefixes,
+ namespaceMap,
+ schemaMap);
}
/**
* @return whether this search's target filters are empty. If any target filter is empty, we
* should skip send request to Icing.
+ *
+ * <p> The nestedConverter is not checked as {@link SearchResult}s from the nested query have
+ * to be joined to a {@link SearchResult} from the parent query. If the parent query has
+ * nothing to search, then so does the child query.
*/
public boolean hasNothingToSearch() {
return mTargetPrefixedNamespaceFilters.isEmpty() || mTargetPrefixedSchemaFilters.isEmpty();
@@ -146,23 +163,68 @@
@NonNull CallerAccess callerAccess,
@Nullable VisibilityStore visibilityStore,
@Nullable VisibilityChecker visibilityChecker) {
+ removeInaccessibleSchemaFilterCached(callerAccess, visibilityStore,
+ /*inaccessibleSchemaPrefixes=*/new ArraySet<>(),
+ /*accessibleSchemaPrefixes=*/new ArraySet<>(), visibilityChecker);
+ }
+
+ /**
+ * For each target schema, we will check visibility store is that accessible to the caller. And
+ * remove this schemas if it is not allowed for caller to query. This private version accepts
+ * two additional parameters to minimize the amount of calls to
+ * {@link VisibilityUtil#isSchemaSearchableByCaller}.
+ *
+ * @param callerAccess Visibility access info of the calling app
+ * @param visibilityStore The {@link VisibilityStore} that store all visibility
+ * information.
+ * @param visibilityChecker Optional visibility checker to check whether the caller
+ * could access target schemas. Pass {@code null} will
+ * reject access for all documents which doesn't belong
+ * to the calling package.
+ * @param inaccessibleSchemaPrefixes A set of schemas that are known to be inaccessible. This
+ * is helpful for reducing duplicate calls to
+ * {@link VisibilityUtil}.
+ * @param accessibleSchemaPrefixes A set of schemas that are known to be accessible. This is
+ * helpful for reducing duplicate calls to
+ * {@link VisibilityUtil}.
+ */
+ private void removeInaccessibleSchemaFilterCached(
+ @NonNull CallerAccess callerAccess,
+ @Nullable VisibilityStore visibilityStore,
+ @NonNull Set<String> inaccessibleSchemaPrefixes,
+ @NonNull Set<String> accessibleSchemaPrefixes,
+ @Nullable VisibilityChecker visibilityChecker) {
Iterator<String> targetPrefixedSchemaFilterIterator =
mTargetPrefixedSchemaFilters.iterator();
while (targetPrefixedSchemaFilterIterator.hasNext()) {
String targetPrefixedSchemaFilter = targetPrefixedSchemaFilterIterator.next();
String packageName = getPackageName(targetPrefixedSchemaFilter);
- if (!VisibilityUtil.isSchemaSearchableByCaller(
+ if (accessibleSchemaPrefixes.contains(targetPrefixedSchemaFilter)) {
+ continue;
+ } else if (inaccessibleSchemaPrefixes.contains(targetPrefixedSchemaFilter)) {
+ targetPrefixedSchemaFilterIterator.remove();
+ } else if (!VisibilityUtil.isSchemaSearchableByCaller(
callerAccess,
packageName,
targetPrefixedSchemaFilter,
visibilityStore,
visibilityChecker)) {
targetPrefixedSchemaFilterIterator.remove();
+ inaccessibleSchemaPrefixes.add(targetPrefixedSchemaFilter);
+ } else {
+ accessibleSchemaPrefixes.add(targetPrefixedSchemaFilter);
}
}
+
+ if (mNestedConverter != null) {
+ mNestedConverter.removeInaccessibleSchemaFilterCached(
+ callerAccess, visibilityStore, inaccessibleSchemaPrefixes,
+ accessibleSchemaPrefixes, visibilityChecker);
+ }
}
+
/** Extracts {@link SearchSpecProto} information from a {@link SearchSpec}. */
@NonNull
public SearchSpecProto toSearchSpecProto() {
@@ -181,25 +243,25 @@
}
protoBuilder.setTermMatchType(termMatchCodeProto);
- JoinSpec joinSpec = mSearchSpec.getJoinSpec();
- if (joinSpec != null) {
- SearchSpecToProtoConverter nestedConverter = new SearchSpecToProtoConverter(
- joinSpec.getNestedQuery(), joinSpec.getNestedSearchSpec(), mPrefixes,
- mNamespaceMap, mSchemaMap);
+ if (mNestedConverter != null && !mNestedConverter.hasNothingToSearch()) {
+ JoinSpecProto.NestedSpecProto nestedSpec =
+ JoinSpecProto.NestedSpecProto.newBuilder()
+ .setResultSpec(mNestedConverter.toResultSpecProto(mNamespaceMap))
+ .setScoringSpec(mNestedConverter.toScoringSpecProto())
+ .setSearchSpec(mNestedConverter.toSearchSpecProto())
+ .build();
- JoinSpecProto.NestedSpecProto nestedSpec = JoinSpecProto.NestedSpecProto.newBuilder()
- .setResultSpec(nestedConverter.toResultSpecProto(mNamespaceMap))
- .setScoringSpec(nestedConverter.toScoringSpecProto())
- .setSearchSpec(nestedConverter.toSearchSpecProto())
- .build();
-
- JoinSpecProto.Builder joinSpecProtoBuilder = JoinSpecProto.newBuilder()
- .setNestedSpec(nestedSpec)
- .setParentPropertyExpression(JoinSpec.QUALIFIED_ID)
- .setChildPropertyExpression(joinSpec.getChildPropertyExpression())
- .setAggregationScoringStrategy(
- toAggregationScoringStrategy(joinSpec.getAggregationScoringStrategy()))
- .setMaxJoinedChildCount(joinSpec.getMaxJoinedResultCount());
+ // This cannot be null, otherwise mNestedConverter would be null as well.
+ JoinSpec joinSpec = mSearchSpec.getJoinSpec();
+ JoinSpecProto.Builder joinSpecProtoBuilder =
+ JoinSpecProto.newBuilder()
+ .setNestedSpec(nestedSpec)
+ .setParentPropertyExpression(JoinSpec.QUALIFIED_ID)
+ .setChildPropertyExpression(joinSpec.getChildPropertyExpression())
+ .setAggregationScoringStrategy(
+ toAggregationScoringStrategy(
+ joinSpec.getAggregationScoringStrategy()))
+ .setMaxJoinedChildCount(joinSpec.getMaxJoinedResultCount());
protoBuilder.setJoinSpec(joinSpecProtoBuilder);
}
diff --git a/appsearch/appsearch-local-storage/src/main/java/androidx/appsearch/localstorage/stats/CallStats.java b/appsearch/appsearch-local-storage/src/main/java/androidx/appsearch/localstorage/stats/CallStats.java
index cb29317..3a5b3d9 100644
--- a/appsearch/appsearch-local-storage/src/main/java/androidx/appsearch/localstorage/stats/CallStats.java
+++ b/appsearch/appsearch-local-storage/src/main/java/androidx/appsearch/localstorage/stats/CallStats.java
@@ -20,6 +20,7 @@
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.annotation.RestrictTo;
+import androidx.appsearch.annotation.CanIgnoreReturnValue;
import androidx.appsearch.app.AppSearchResult;
import androidx.core.util.Preconditions;
@@ -195,6 +196,7 @@
int mNumOperationsFailed;
/** Sets the PackageName used by the session. */
+ @CanIgnoreReturnValue
@NonNull
public Builder setPackageName(@NonNull String packageName) {
mPackageName = Preconditions.checkNotNull(packageName);
@@ -202,6 +204,7 @@
}
/** Sets the database used by the session. */
+ @CanIgnoreReturnValue
@NonNull
public Builder setDatabase(@NonNull String database) {
mDatabase = Preconditions.checkNotNull(database);
@@ -209,6 +212,7 @@
}
/** Sets the status code. */
+ @CanIgnoreReturnValue
@NonNull
public Builder setStatusCode(@AppSearchResult.ResultCode int statusCode) {
mStatusCode = statusCode;
@@ -216,6 +220,7 @@
}
/** Sets total latency in millis. */
+ @CanIgnoreReturnValue
@NonNull
public Builder setTotalLatencyMillis(int totalLatencyMillis) {
mTotalLatencyMillis = totalLatencyMillis;
@@ -223,6 +228,7 @@
}
/** Sets type of the call. */
+ @CanIgnoreReturnValue
@NonNull
public Builder setCallType(@CallType int callType) {
mCallType = callType;
@@ -230,6 +236,7 @@
}
/** Sets estimated binder latency, in milliseconds. */
+ @CanIgnoreReturnValue
@NonNull
public Builder setEstimatedBinderLatencyMillis(int estimatedBinderLatencyMillis) {
mEstimatedBinderLatencyMillis = estimatedBinderLatencyMillis;
@@ -250,6 +257,7 @@
* {@link CallStats#getNumOperationsFailed()} is always 1 since there is only one
* operation.
*/
+ @CanIgnoreReturnValue
@NonNull
public Builder setNumOperationsSucceeded(int numOperationsSucceeded) {
mNumOperationsSucceeded = numOperationsSucceeded;
@@ -269,6 +277,7 @@
* {@link CallStats#getNumOperationsFailed()} is always 1 since there is only one
* operation.
*/
+ @CanIgnoreReturnValue
@NonNull
public Builder setNumOperationsFailed(int numOperationsFailed) {
mNumOperationsFailed = numOperationsFailed;
diff --git a/appsearch/appsearch-local-storage/src/main/java/androidx/appsearch/localstorage/stats/InitializeStats.java b/appsearch/appsearch-local-storage/src/main/java/androidx/appsearch/localstorage/stats/InitializeStats.java
index f88d257..6effe35 100644
--- a/appsearch/appsearch-local-storage/src/main/java/androidx/appsearch/localstorage/stats/InitializeStats.java
+++ b/appsearch/appsearch-local-storage/src/main/java/androidx/appsearch/localstorage/stats/InitializeStats.java
@@ -19,6 +19,7 @@
import androidx.annotation.IntDef;
import androidx.annotation.NonNull;
import androidx.annotation.RestrictTo;
+import androidx.appsearch.annotation.CanIgnoreReturnValue;
import androidx.appsearch.app.AppSearchResult;
import androidx.core.util.Preconditions;
@@ -288,6 +289,7 @@
int mResetStatusCode;
/** Sets the status of the initialization. */
+ @CanIgnoreReturnValue
@NonNull
public Builder setStatusCode(@AppSearchResult.ResultCode int statusCode) {
mStatusCode = statusCode;
@@ -295,6 +297,7 @@
}
/** Sets the total latency of the initialization in milliseconds. */
+ @CanIgnoreReturnValue
@NonNull
public Builder setTotalLatencyMillis(int totalLatencyMillis) {
mTotalLatencyMillis = totalLatencyMillis;
@@ -307,6 +310,7 @@
* <p>If there is a deSync, it means AppSearch and IcingSearchEngine have an inconsistent
* view of what data should exist.
*/
+ @CanIgnoreReturnValue
@NonNull
public Builder setHasDeSync(boolean hasDeSync) {
mHasDeSync = hasDeSync;
@@ -314,6 +318,7 @@
}
/** Sets time used to read and process the schema and namespaces. */
+ @CanIgnoreReturnValue
@NonNull
public Builder setPrepareSchemaAndNamespacesLatencyMillis(
int prepareSchemaAndNamespacesLatencyMillis) {
@@ -322,6 +327,7 @@
}
/** Sets time used to read and process the visibility file. */
+ @CanIgnoreReturnValue
@NonNull
public Builder setPrepareVisibilityStoreLatencyMillis(
int prepareVisibilityStoreLatencyMillis) {
@@ -330,6 +336,7 @@
}
/** Sets overall time used for the native function call. */
+ @CanIgnoreReturnValue
@NonNull
public Builder setNativeLatencyMillis(int nativeLatencyMillis) {
mNativeLatencyMillis = nativeLatencyMillis;
@@ -344,6 +351,7 @@
* <li> {@link InitializeStats#RECOVERY_CAUSE_TOTAL_CHECKSUM_MISMATCH}
* <li> {@link InitializeStats#RECOVERY_CAUSE_IO_ERROR}
*/
+ @CanIgnoreReturnValue
@NonNull
public Builder setDocumentStoreRecoveryCause(
@RecoveryCause int documentStoreRecoveryCause) {
@@ -358,6 +366,7 @@
* <li> {@link InitializeStats#RECOVERY_CAUSE_TOTAL_CHECKSUM_MISMATCH}
* <li> {@link InitializeStats#RECOVERY_CAUSE_IO_ERROR}
*/
+ @CanIgnoreReturnValue
@NonNull
public Builder setIndexRestorationCause(
@RecoveryCause int indexRestorationCause) {
@@ -370,6 +379,7 @@
* <p> Possible causes:
* <li> {@link InitializeStats#RECOVERY_CAUSE_IO_ERROR}
*/
+ @CanIgnoreReturnValue
@NonNull
public Builder setSchemaStoreRecoveryCause(
@RecoveryCause int schemaStoreRecoveryCause) {
@@ -378,6 +388,7 @@
}
/** Sets time used to recover the document store. */
+ @CanIgnoreReturnValue
@NonNull
public Builder setDocumentStoreRecoveryLatencyMillis(
int documentStoreRecoveryLatencyMillis) {
@@ -386,6 +397,7 @@
}
/** Sets time used to restore the index. */
+ @CanIgnoreReturnValue
@NonNull
public Builder setIndexRestorationLatencyMillis(
int indexRestorationLatencyMillis) {
@@ -394,6 +406,7 @@
}
/** Sets time used to recover the schema store. */
+ @CanIgnoreReturnValue
@NonNull
public Builder setSchemaStoreRecoveryLatencyMillis(
int schemaStoreRecoveryLatencyMillis) {
@@ -405,6 +418,7 @@
* Sets Native Document Store Data status.
* status is defined in external/icing/proto/icing/proto/logging.proto
*/
+ @CanIgnoreReturnValue
@NonNull
public Builder setDocumentStoreDataStatus(
@DocumentStoreDataStatus int documentStoreDataStatus) {
@@ -416,6 +430,7 @@
* Sets number of documents currently in document store. Those may include alive, deleted,
* and expired documents.
*/
+ @CanIgnoreReturnValue
@NonNull
public Builder setDocumentCount(int numDocuments) {
mNativeNumDocuments = numDocuments;
@@ -423,6 +438,7 @@
}
/** Sets number of schema types currently in the schema store. */
+ @CanIgnoreReturnValue
@NonNull
public Builder setSchemaTypeCount(int numSchemaTypes) {
mNativeNumSchemaTypes = numSchemaTypes;
@@ -430,6 +446,7 @@
}
/** Sets whether we had to reset the index, losing all data, as part of initialization. */
+ @CanIgnoreReturnValue
@NonNull
public Builder setHasReset(boolean hasReset) {
mHasReset = hasReset;
@@ -437,6 +454,7 @@
}
/** Sets the status of the reset, if one was performed according to {@link #setHasReset}. */
+ @CanIgnoreReturnValue
@NonNull
public Builder setResetStatusCode(@AppSearchResult.ResultCode int resetStatusCode) {
mResetStatusCode = resetStatusCode;
diff --git a/appsearch/appsearch-local-storage/src/main/java/androidx/appsearch/localstorage/stats/OptimizeStats.java b/appsearch/appsearch-local-storage/src/main/java/androidx/appsearch/localstorage/stats/OptimizeStats.java
index b7dcae0..2a47183 100644
--- a/appsearch/appsearch-local-storage/src/main/java/androidx/appsearch/localstorage/stats/OptimizeStats.java
+++ b/appsearch/appsearch-local-storage/src/main/java/androidx/appsearch/localstorage/stats/OptimizeStats.java
@@ -18,6 +18,7 @@
import androidx.annotation.NonNull;
import androidx.annotation.RestrictTo;
+import androidx.appsearch.annotation.CanIgnoreReturnValue;
import androidx.appsearch.app.AppSearchResult;
import androidx.core.util.Preconditions;
@@ -156,6 +157,7 @@
long mNativeTimeSinceLastOptimizeMillis;
/** Sets the status code. */
+ @CanIgnoreReturnValue
@NonNull
public Builder setStatusCode(@AppSearchResult.ResultCode int statusCode) {
mStatusCode = statusCode;
@@ -163,6 +165,7 @@
}
/** Sets total latency in millis. */
+ @CanIgnoreReturnValue
@NonNull
public Builder setTotalLatencyMillis(int totalLatencyMillis) {
mTotalLatencyMillis = totalLatencyMillis;
@@ -170,6 +173,7 @@
}
/** Sets native latency in millis. */
+ @CanIgnoreReturnValue
@NonNull
public Builder setNativeLatencyMillis(int nativeLatencyMillis) {
mNativeLatencyMillis = nativeLatencyMillis;
@@ -177,6 +181,7 @@
}
/** Sets time used to optimize the document store. */
+ @CanIgnoreReturnValue
@NonNull
public Builder setDocumentStoreOptimizeLatencyMillis(
int documentStoreOptimizeLatencyMillis) {
@@ -185,6 +190,7 @@
}
/** Sets time used to restore the index. */
+ @CanIgnoreReturnValue
@NonNull
public Builder setIndexRestorationLatencyMillis(int indexRestorationLatencyMillis) {
mNativeIndexRestorationLatencyMillis = indexRestorationLatencyMillis;
@@ -192,6 +198,7 @@
}
/** Sets number of documents before the optimization. */
+ @CanIgnoreReturnValue
@NonNull
public Builder setOriginalDocumentCount(int originalDocumentCount) {
mNativeOriginalDocumentCount = originalDocumentCount;
@@ -199,6 +206,7 @@
}
/** Sets number of documents deleted during the optimization. */
+ @CanIgnoreReturnValue
@NonNull
public Builder setDeletedDocumentCount(int deletedDocumentCount) {
mNativeDeletedDocumentCount = deletedDocumentCount;
@@ -206,6 +214,7 @@
}
/** Sets number of documents expired during the optimization. */
+ @CanIgnoreReturnValue
@NonNull
public Builder setExpiredDocumentCount(int expiredDocumentCount) {
mNativeExpiredDocumentCount = expiredDocumentCount;
@@ -213,6 +222,7 @@
}
/** Sets Storage size in bytes before optimization. */
+ @CanIgnoreReturnValue
@NonNull
public Builder setStorageSizeBeforeBytes(long storageSizeBeforeBytes) {
mNativeStorageSizeBeforeBytes = storageSizeBeforeBytes;
@@ -220,6 +230,7 @@
}
/** Sets storage size in bytes after optimization. */
+ @CanIgnoreReturnValue
@NonNull
public Builder setStorageSizeAfterBytes(long storageSizeAfterBytes) {
mNativeStorageSizeAfterBytes = storageSizeAfterBytes;
@@ -229,6 +240,7 @@
/**
* Sets the amount the time since the last optimize ran calculated using wall clock time.
*/
+ @CanIgnoreReturnValue
@NonNull
public Builder setTimeSinceLastOptimizeMillis(long timeSinceLastOptimizeMillis) {
mNativeTimeSinceLastOptimizeMillis = timeSinceLastOptimizeMillis;
diff --git a/appsearch/appsearch-local-storage/src/main/java/androidx/appsearch/localstorage/stats/PutDocumentStats.java b/appsearch/appsearch-local-storage/src/main/java/androidx/appsearch/localstorage/stats/PutDocumentStats.java
index e9a25fd..3378df7 100644
--- a/appsearch/appsearch-local-storage/src/main/java/androidx/appsearch/localstorage/stats/PutDocumentStats.java
+++ b/appsearch/appsearch-local-storage/src/main/java/androidx/appsearch/localstorage/stats/PutDocumentStats.java
@@ -18,6 +18,7 @@
import androidx.annotation.NonNull;
import androidx.annotation.RestrictTo;
+import androidx.appsearch.annotation.CanIgnoreReturnValue;
import androidx.appsearch.app.AppSearchResult;
import androidx.core.util.Preconditions;
@@ -169,6 +170,7 @@
}
/** Sets the status code. */
+ @CanIgnoreReturnValue
@NonNull
public Builder setStatusCode(@AppSearchResult.ResultCode int statusCode) {
mStatusCode = statusCode;
@@ -176,6 +178,7 @@
}
/** Sets total latency in millis. */
+ @CanIgnoreReturnValue
@NonNull
public Builder setTotalLatencyMillis(int totalLatencyMillis) {
mTotalLatencyMillis = totalLatencyMillis;
@@ -183,6 +186,7 @@
}
/** Sets how much time we spend for generating document proto, in milliseconds. */
+ @CanIgnoreReturnValue
@NonNull
public Builder setGenerateDocumentProtoLatencyMillis(
int generateDocumentProtoLatencyMillis) {
@@ -194,6 +198,7 @@
* Sets how much time we spend for rewriting types and namespaces in document, in
* milliseconds.
*/
+ @CanIgnoreReturnValue
@NonNull
public Builder setRewriteDocumentTypesLatencyMillis(int rewriteDocumentTypesLatencyMillis) {
mRewriteDocumentTypesLatencyMillis = rewriteDocumentTypesLatencyMillis;
@@ -201,6 +206,7 @@
}
/** Sets the native latency, in milliseconds. */
+ @CanIgnoreReturnValue
@NonNull
public Builder setNativeLatencyMillis(int nativeLatencyMillis) {
mNativeLatencyMillis = nativeLatencyMillis;
@@ -208,6 +214,7 @@
}
/** Sets how much time we spend on document store, in milliseconds. */
+ @CanIgnoreReturnValue
@NonNull
public Builder setNativeDocumentStoreLatencyMillis(int nativeDocumentStoreLatencyMillis) {
mNativeDocumentStoreLatencyMillis = nativeDocumentStoreLatencyMillis;
@@ -215,6 +222,7 @@
}
/** Sets the native index latency, in milliseconds. */
+ @CanIgnoreReturnValue
@NonNull
public Builder setNativeIndexLatencyMillis(int nativeIndexLatencyMillis) {
mNativeIndexLatencyMillis = nativeIndexLatencyMillis;
@@ -222,6 +230,7 @@
}
/** Sets how much time we spend on merging indices, in milliseconds. */
+ @CanIgnoreReturnValue
@NonNull
public Builder setNativeIndexMergeLatencyMillis(int nativeIndexMergeLatencyMillis) {
mNativeIndexMergeLatencyMillis = nativeIndexMergeLatencyMillis;
@@ -229,6 +238,7 @@
}
/** Sets document size, in bytes. */
+ @CanIgnoreReturnValue
@NonNull
public Builder setNativeDocumentSizeBytes(int nativeDocumentSizeBytes) {
mNativeDocumentSizeBytes = nativeDocumentSizeBytes;
@@ -236,6 +246,7 @@
}
/** Sets number of tokens indexed in native. */
+ @CanIgnoreReturnValue
@NonNull
public Builder setNativeNumTokensIndexed(int nativeNumTokensIndexed) {
mNativeNumTokensIndexed = nativeNumTokensIndexed;
diff --git a/appsearch/appsearch-local-storage/src/main/java/androidx/appsearch/localstorage/stats/RemoveStats.java b/appsearch/appsearch-local-storage/src/main/java/androidx/appsearch/localstorage/stats/RemoveStats.java
index 7eb4820..ffb3f3a 100644
--- a/appsearch/appsearch-local-storage/src/main/java/androidx/appsearch/localstorage/stats/RemoveStats.java
+++ b/appsearch/appsearch-local-storage/src/main/java/androidx/appsearch/localstorage/stats/RemoveStats.java
@@ -19,6 +19,7 @@
import androidx.annotation.IntDef;
import androidx.annotation.NonNull;
import androidx.annotation.RestrictTo;
+import androidx.appsearch.annotation.CanIgnoreReturnValue;
import androidx.appsearch.app.AppSearchResult;
import androidx.appsearch.app.RemoveByDocumentIdRequest;
import androidx.appsearch.app.SearchSpec;
@@ -148,6 +149,7 @@
}
/** Sets the status code. */
+ @CanIgnoreReturnValue
@NonNull
public Builder setStatusCode(@AppSearchResult.ResultCode int statusCode) {
mStatusCode = statusCode;
@@ -155,6 +157,7 @@
}
/** Sets total latency in millis. */
+ @CanIgnoreReturnValue
@NonNull
public Builder setTotalLatencyMillis(int totalLatencyMillis) {
mTotalLatencyMillis = totalLatencyMillis;
@@ -162,6 +165,7 @@
}
/** Sets native latency in millis. */
+ @CanIgnoreReturnValue
@NonNull
public Builder setNativeLatencyMillis(int nativeLatencyMillis) {
mNativeLatencyMillis = nativeLatencyMillis;
@@ -169,6 +173,7 @@
}
/** Sets delete type for this call. */
+ @CanIgnoreReturnValue
@NonNull
public Builder setDeleteType(@DeleteType int nativeDeleteType) {
mNativeDeleteType = nativeDeleteType;
@@ -176,6 +181,7 @@
}
/** Sets how many documents get deleted for this call. */
+ @CanIgnoreReturnValue
@NonNull
public Builder setDeletedDocumentCount(int nativeNumDocumentsDeleted) {
mNativeNumDocumentsDeleted = nativeNumDocumentsDeleted;
diff --git a/appsearch/appsearch-local-storage/src/main/java/androidx/appsearch/localstorage/stats/SearchStats.java b/appsearch/appsearch-local-storage/src/main/java/androidx/appsearch/localstorage/stats/SearchStats.java
index bc46326..c0b9958 100644
--- a/appsearch/appsearch-local-storage/src/main/java/androidx/appsearch/localstorage/stats/SearchStats.java
+++ b/appsearch/appsearch-local-storage/src/main/java/androidx/appsearch/localstorage/stats/SearchStats.java
@@ -19,6 +19,7 @@
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.annotation.RestrictTo;
+import androidx.appsearch.annotation.CanIgnoreReturnValue;
import androidx.appsearch.app.AppSearchResult;
import androidx.appsearch.app.SearchSpec;
import androidx.core.util.Preconditions;
@@ -363,6 +364,7 @@
}
/** Sets the database used by the session. */
+ @CanIgnoreReturnValue
@NonNull
public Builder setDatabase(@NonNull String database) {
mDatabase = Preconditions.checkNotNull(database);
@@ -370,6 +372,7 @@
}
/** Sets the status of the search. */
+ @CanIgnoreReturnValue
@NonNull
public Builder setStatusCode(@AppSearchResult.ResultCode int statusCode) {
mStatusCode = statusCode;
@@ -377,6 +380,7 @@
}
/** Sets total latency for the search. */
+ @CanIgnoreReturnValue
@NonNull
public Builder setTotalLatencyMillis(int totalLatencyMillis) {
mTotalLatencyMillis = totalLatencyMillis;
@@ -384,6 +388,7 @@
}
/** Sets time used to rewrite the search spec. */
+ @CanIgnoreReturnValue
@NonNull
public Builder setRewriteSearchSpecLatencyMillis(int rewriteSearchSpecLatencyMillis) {
mRewriteSearchSpecLatencyMillis = rewriteSearchSpecLatencyMillis;
@@ -391,6 +396,7 @@
}
/** Sets time used to rewrite the search results. */
+ @CanIgnoreReturnValue
@NonNull
public Builder setRewriteSearchResultLatencyMillis(int rewriteSearchResultLatencyMillis) {
mRewriteSearchResultLatencyMillis = rewriteSearchResultLatencyMillis;
@@ -398,6 +404,7 @@
}
/** Sets time passed while waiting to acquire the lock during Java function calls. */
+ @CanIgnoreReturnValue
@NonNull
public Builder setJavaLockAcquisitionLatencyMillis(int javaLockAcquisitionLatencyMillis) {
mJavaLockAcquisitionLatencyMillis = javaLockAcquisitionLatencyMillis;
@@ -408,6 +415,7 @@
* Sets time spent on ACL checking, which is the time spent filtering namespaces based on
* package permissions and Android permission access.
*/
+ @CanIgnoreReturnValue
@NonNull
public Builder setAclCheckLatencyMillis(int aclCheckLatencyMillis) {
mAclCheckLatencyMillis = aclCheckLatencyMillis;
@@ -415,6 +423,7 @@
}
/** Sets overall time used for the native function calls. */
+ @CanIgnoreReturnValue
@NonNull
public Builder setNativeLatencyMillis(int nativeLatencyMillis) {
mNativeLatencyMillis = nativeLatencyMillis;
@@ -422,6 +431,7 @@
}
/** Sets number of terms in the search string. */
+ @CanIgnoreReturnValue
@NonNull
public Builder setTermCount(int termCount) {
mNativeNumTerms = termCount;
@@ -429,6 +439,7 @@
}
/** Sets length of the search string. */
+ @CanIgnoreReturnValue
@NonNull
public Builder setQueryLength(int queryLength) {
mNativeQueryLength = queryLength;
@@ -436,6 +447,7 @@
}
/** Sets number of namespaces filtered. */
+ @CanIgnoreReturnValue
@NonNull
public Builder setFilteredNamespaceCount(int filteredNamespaceCount) {
mNativeNumNamespacesFiltered = filteredNamespaceCount;
@@ -443,6 +455,7 @@
}
/** Sets number of schema types filtered. */
+ @CanIgnoreReturnValue
@NonNull
public Builder setFilteredSchemaTypeCount(int filteredSchemaTypeCount) {
mNativeNumSchemaTypesFiltered = filteredSchemaTypeCount;
@@ -450,6 +463,7 @@
}
/** Sets the requested number of results in one page. */
+ @CanIgnoreReturnValue
@NonNull
public Builder setRequestedPageSize(int requestedPageSize) {
mNativeRequestedPageSize = requestedPageSize;
@@ -457,6 +471,7 @@
}
/** Sets the actual number of results returned in the current page. */
+ @CanIgnoreReturnValue
@NonNull
public Builder setCurrentPageReturnedResultCount(
int currentPageReturnedResultCount) {
@@ -469,6 +484,7 @@
* not, Icing will fetch the results from cache so that some steps
* may be skipped.
*/
+ @CanIgnoreReturnValue
@NonNull
public Builder setIsFirstPage(boolean nativeIsFirstPage) {
mNativeIsFirstPage = nativeIsFirstPage;
@@ -479,6 +495,7 @@
* Sets time used to parse the query, including 2 parts: tokenizing and
* transforming tokens into an iterator tree.
*/
+ @CanIgnoreReturnValue
@NonNull
public Builder setParseQueryLatencyMillis(int parseQueryLatencyMillis) {
mNativeParseQueryLatencyMillis = parseQueryLatencyMillis;
@@ -486,6 +503,7 @@
}
/** Sets strategy of scoring and ranking. */
+ @CanIgnoreReturnValue
@NonNull
public Builder setRankingStrategy(
@SearchSpec.RankingStrategy int rankingStrategy) {
@@ -494,6 +512,7 @@
}
/** Sets number of documents scored. */
+ @CanIgnoreReturnValue
@NonNull
public Builder setScoredDocumentCount(int scoredDocumentCount) {
mNativeNumDocumentsScored = scoredDocumentCount;
@@ -501,6 +520,7 @@
}
/** Sets time used to score the raw results. */
+ @CanIgnoreReturnValue
@NonNull
public Builder setScoringLatencyMillis(int scoringLatencyMillis) {
mNativeScoringLatencyMillis = scoringLatencyMillis;
@@ -508,6 +528,7 @@
}
/** Sets time used to rank the scored results. */
+ @CanIgnoreReturnValue
@NonNull
public Builder setRankingLatencyMillis(int rankingLatencyMillis) {
mNativeRankingLatencyMillis = rankingLatencyMillis;
@@ -515,6 +536,7 @@
}
/** Sets time used to fetch the document protos. */
+ @CanIgnoreReturnValue
@NonNull
public Builder setDocumentRetrievingLatencyMillis(
int documentRetrievingLatencyMillis) {
@@ -523,6 +545,7 @@
}
/** Sets how many snippets are calculated. */
+ @CanIgnoreReturnValue
@NonNull
public Builder setResultWithSnippetsCount(int resultWithSnippetsCount) {
mNativeNumResultsWithSnippets = resultWithSnippetsCount;
@@ -530,6 +553,7 @@
}
/** Sets time passed while waiting to acquire the lock during native function calls. */
+ @CanIgnoreReturnValue
@NonNull
public Builder setNativeLockAcquisitionLatencyMillis(
int nativeLockAcquisitionLatencyMillis) {
@@ -538,6 +562,7 @@
}
/** Sets time used to send data across the JNI boundary from java to native side. */
+ @CanIgnoreReturnValue
@NonNull
public Builder setJavaToNativeJniLatencyMillis(int javaToNativeJniLatencyMillis) {
mJavaToNativeJniLatencyMillis = javaToNativeJniLatencyMillis;
@@ -545,6 +570,7 @@
}
/** Sets time used to send data across the JNI boundary from native to java side. */
+ @CanIgnoreReturnValue
@NonNull
public Builder setNativeToJavaJniLatencyMillis(int nativeToJavaJniLatencyMillis) {
mNativeToJavaJniLatencyMillis = nativeToJavaJniLatencyMillis;
diff --git a/appsearch/appsearch-local-storage/src/main/java/androidx/appsearch/localstorage/stats/SetSchemaStats.java b/appsearch/appsearch-local-storage/src/main/java/androidx/appsearch/localstorage/stats/SetSchemaStats.java
index c052eb8..6ff7d8e 100644
--- a/appsearch/appsearch-local-storage/src/main/java/androidx/appsearch/localstorage/stats/SetSchemaStats.java
+++ b/appsearch/appsearch-local-storage/src/main/java/androidx/appsearch/localstorage/stats/SetSchemaStats.java
@@ -21,6 +21,7 @@
import androidx.annotation.NonNull;
import androidx.annotation.RestrictTo;
+import androidx.appsearch.annotation.CanIgnoreReturnValue;
import androidx.appsearch.app.AppSearchResult;
import androidx.appsearch.stats.SchemaMigrationStats;
import androidx.core.util.Preconditions;
@@ -224,7 +225,8 @@
}
/** Gets the type indicate how this set schema call relative to schema migration cases */
- public @SchemaMigrationStats.SchemaMigrationCallType int getSchemaMigrationCallType() {
+ @SchemaMigrationStats.SchemaMigrationCallType
+ public int getSchemaMigrationCallType() {
return mSchemaMigrationCallType;
}
@@ -266,6 +268,7 @@
}
/** Sets the status of the SetSchema action. */
+ @CanIgnoreReturnValue
@NonNull
public Builder setStatusCode(@AppSearchResult.ResultCode int statusCode) {
mStatusCode = statusCode;
@@ -273,6 +276,7 @@
}
/** Sets total latency for the SetSchema action in milliseconds. */
+ @CanIgnoreReturnValue
@NonNull
public Builder setTotalLatencyMillis(int totalLatencyMillis) {
mTotalLatencyMillis = totalLatencyMillis;
@@ -280,6 +284,7 @@
}
/** Sets number of new types. */
+ @CanIgnoreReturnValue
@NonNull
public Builder setNewTypeCount(int newTypeCount) {
mNewTypeCount = newTypeCount;
@@ -287,6 +292,7 @@
}
/** Sets number of deleted types. */
+ @CanIgnoreReturnValue
@NonNull
public Builder setDeletedTypeCount(int deletedTypeCount) {
mDeletedTypeCount = deletedTypeCount;
@@ -294,6 +300,7 @@
}
/** Sets number of compatible type changes. */
+ @CanIgnoreReturnValue
@NonNull
public Builder setCompatibleTypeChangeCount(int compatibleTypeChangeCount) {
mCompatibleTypeChangeCount = compatibleTypeChangeCount;
@@ -301,6 +308,7 @@
}
/** Sets number of index-incompatible type changes. */
+ @CanIgnoreReturnValue
@NonNull
public Builder setIndexIncompatibleTypeChangeCount(int indexIncompatibleTypeChangeCount) {
mIndexIncompatibleTypeChangeCount = indexIncompatibleTypeChangeCount;
@@ -308,6 +316,7 @@
}
/** Sets number of backwards-incompatible type changes. */
+ @CanIgnoreReturnValue
@NonNull
public Builder setBackwardsIncompatibleTypeChangeCount(
int backwardsIncompatibleTypeChangeCount) {
@@ -316,6 +325,7 @@
}
/** Sets total latency for the SetSchema in native action in milliseconds. */
+ @CanIgnoreReturnValue
@NonNull
public Builder setVerifyIncomingCallLatencyMillis(int verifyIncomingCallLatencyMillis) {
mVerifyIncomingCallLatencyMillis = verifyIncomingCallLatencyMillis;
@@ -323,6 +333,7 @@
}
/** Sets total latency for the SetSchema in native action in milliseconds. */
+ @CanIgnoreReturnValue
@NonNull
public Builder setExecutorAcquisitionLatencyMillis(int executorAcquisitionLatencyMillis) {
mExecutorAcquisitionLatencyMillis = executorAcquisitionLatencyMillis;
@@ -330,6 +341,7 @@
}
/** Sets latency for the rebuild schema object from bundle action in milliseconds. */
+ @CanIgnoreReturnValue
@NonNull
public Builder setRebuildFromBundleLatencyMillis(int rebuildFromBundleLatencyMillis) {
mRebuildFromBundleLatencyMillis = rebuildFromBundleLatencyMillis;
@@ -339,6 +351,7 @@
/**
* Sets latency for waiting to acquire the lock during Java function calls in milliseconds.
*/
+ @CanIgnoreReturnValue
@NonNull
public Builder setJavaLockAcquisitionLatencyMillis(int javaLockAcquisitionLatencyMillis) {
mJavaLockAcquisitionLatencyMillis = javaLockAcquisitionLatencyMillis;
@@ -346,6 +359,7 @@
}
/** Sets latency for the rewrite the schema proto action in milliseconds. */
+ @CanIgnoreReturnValue
@NonNull
public Builder setRewriteSchemaLatencyMillis(int rewriteSchemaLatencyMillis) {
mRewriteSchemaLatencyMillis = rewriteSchemaLatencyMillis;
@@ -353,6 +367,7 @@
}
/** Sets total latency for a single set schema in native action in milliseconds. */
+ @CanIgnoreReturnValue
@NonNull
public Builder setTotalNativeLatencyMillis(int totalNativeLatencyMillis) {
mTotalNativeLatencyMillis = totalNativeLatencyMillis;
@@ -360,6 +375,7 @@
}
/** Sets latency for the apply visibility settings action in milliseconds. */
+ @CanIgnoreReturnValue
@NonNull
public Builder setVisibilitySettingLatencyMillis(int visibilitySettingLatencyMillis) {
mVisibilitySettingLatencyMillis = visibilitySettingLatencyMillis;
@@ -367,6 +383,7 @@
}
/** Sets latency for converting to SetSchemaResponseInternal object in milliseconds. */
+ @CanIgnoreReturnValue
@NonNull
public Builder setConvertToResponseLatencyMillis(int convertToResponseLatencyMillis) {
mConvertToResponseLatencyMillis = convertToResponseLatencyMillis;
@@ -374,6 +391,7 @@
}
/** Sets latency for the dispatch change notification action in milliseconds. */
+ @CanIgnoreReturnValue
@NonNull
public Builder setDispatchChangeNotificationsLatencyMillis(
int dispatchChangeNotificationsLatencyMillis) {
@@ -382,6 +400,7 @@
}
/** Sets latency for the optimization action in milliseconds. */
+ @CanIgnoreReturnValue
@NonNull
public Builder setOptimizeLatencyMillis(int optimizeLatencyMillis) {
mOptimizeLatencyMillis = optimizeLatencyMillis;
@@ -389,6 +408,7 @@
}
/** Sets whether this package is observed and we should prepare change notifications. */
+ @CanIgnoreReturnValue
@NonNull
public Builder setIsPackageObserved(boolean isPackageObserved) {
mIsPackageObserved = isPackageObserved;
@@ -396,6 +416,7 @@
}
/** Sets latency for the old schema action in milliseconds. */
+ @CanIgnoreReturnValue
@NonNull
public Builder setGetOldSchemaLatencyMillis(int getOldSchemaLatencyMillis) {
mGetOldSchemaLatencyMillis = getOldSchemaLatencyMillis;
@@ -403,6 +424,7 @@
}
/** Sets latency for the registered observer action in milliseconds. */
+ @CanIgnoreReturnValue
@NonNull
public Builder setGetObserverLatencyMillis(int getObserverLatencyMillis) {
mGetObserverLatencyMillis = getObserverLatencyMillis;
@@ -410,6 +432,7 @@
}
/** Sets latency for the preparing change notification action in milliseconds. */
+ @CanIgnoreReturnValue
@NonNull
public Builder setPreparingChangeNotificationLatencyMillis(
int preparingChangeNotificationLatencyMillis) {
@@ -418,6 +441,7 @@
}
/** Sets the type indicate how this set schema call relative to schema migration cases */
+ @CanIgnoreReturnValue
@NonNull
public Builder setSchemaMigrationCallType(
@SchemaMigrationStats.SchemaMigrationCallType int schemaMigrationCallType) {
diff --git a/appsearch/appsearch-platform-storage/lint-baseline.xml b/appsearch/appsearch-platform-storage/lint-baseline.xml
index e1f4abe..b61f0f5 100644
--- a/appsearch/appsearch-platform-storage/lint-baseline.xml
+++ b/appsearch/appsearch-platform-storage/lint-baseline.xml
@@ -19,94 +19,4 @@
file="src/main/java/androidx/appsearch/platformstorage/SearchSessionImpl.java"/>
</issue>
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 33; however, the containing class androidx.appsearch.platformstorage.converter.GetSchemaResponseToPlatformConverter is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" platformResponse.getSchemaTypesNotDisplayedBySystem()) {"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/appsearch/platformstorage/converter/GetSchemaResponseToPlatformConverter.java"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 33; however, the containing class androidx.appsearch.platformstorage.converter.GetSchemaResponseToPlatformConverter is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" platformResponse.getRequiredPermissionsForSchemaTypeVisibility().entrySet()) {"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/appsearch/platformstorage/converter/GetSchemaResponseToPlatformConverter.java"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 33; however, the containing class androidx.appsearch.platformstorage.converter.GetSchemaResponseToPlatformConverter is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" platformResponse.getSchemaTypesVisibleToPackages();"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/appsearch/platformstorage/converter/GetSchemaResponseToPlatformConverter.java"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 33; however, the containing class androidx.appsearch.platformstorage.GlobalSearchSessionImpl is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" mPlatformSession.getByDocumentId(packageName, databaseName,"
- errorLine2=" ~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/appsearch/platformstorage/GlobalSearchSessionImpl.java"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 33; however, the containing class androidx.appsearch.platformstorage.GlobalSearchSessionImpl is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" mPlatformSession.getSchema("
- errorLine2=" ~~~~~~~~~">
- <location
- file="src/main/java/androidx/appsearch/platformstorage/GlobalSearchSessionImpl.java"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 33; however, the containing class androidx.appsearch.platformstorage.GlobalSearchSessionImpl is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" mPlatformSession.registerObserverCallback("
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/appsearch/platformstorage/GlobalSearchSessionImpl.java"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 33; however, the containing class androidx.appsearch.platformstorage.GlobalSearchSessionImpl is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" mPlatformSession.unregisterObserverCallback(targetPackageName, frameworkCallback);"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/appsearch/platformstorage/GlobalSearchSessionImpl.java"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 33; however, the containing class androidx.appsearch.platformstorage.converter.SearchResultToPlatformConverter is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" platformMatchInfo.getSubmatchRange().getStart(),"
- errorLine2=" ~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/appsearch/platformstorage/converter/SearchResultToPlatformConverter.java"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 33; however, the containing class androidx.appsearch.platformstorage.converter.SearchResultToPlatformConverter is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" platformMatchInfo.getSubmatchRange().getEnd()));"
- errorLine2=" ~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/appsearch/platformstorage/converter/SearchResultToPlatformConverter.java"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 33; however, the containing class androidx.appsearch.platformstorage.converter.SetSchemaRequestToPlatformConverter is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" platformBuilder.addRequiredPermissionsForSchemaTypeVisibility("
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/appsearch/platformstorage/converter/SetSchemaRequestToPlatformConverter.java"/>
- </issue>
-
</issues>
diff --git a/appsearch/appsearch-platform-storage/src/main/java/androidx/appsearch/platformstorage/FeaturesImpl.java b/appsearch/appsearch-platform-storage/src/main/java/androidx/appsearch/platformstorage/FeaturesImpl.java
index 2f9336e..c1ff683 100644
--- a/appsearch/appsearch-platform-storage/src/main/java/androidx/appsearch/platformstorage/FeaturesImpl.java
+++ b/appsearch/appsearch-platform-storage/src/main/java/androidx/appsearch/platformstorage/FeaturesImpl.java
@@ -15,6 +15,9 @@
*/
package androidx.appsearch.platformstorage;
+import android.annotation.SuppressLint;
+import android.os.Build;
+
import androidx.annotation.NonNull;
import androidx.appsearch.app.Features;
import androidx.core.os.BuildCompat;
@@ -26,7 +29,8 @@
final class FeaturesImpl implements Features {
@Override
- // TODO(b/201316758): Remove once BuildCompat.isAtLeastT is removed
+ // TODO(b/265311462): Remove these two lines once BuildCompat.isAtLeastU() is removed
+ @SuppressLint("NewApi")
@BuildCompat.PrereleaseSdkCheck
public boolean isFeatureSupported(@NonNull String feature) {
switch (feature) {
@@ -40,10 +44,11 @@
case Features.GLOBAL_SEARCH_SESSION_REGISTER_OBSERVER_CALLBACK:
// fall through
case Features.SEARCH_RESULT_MATCH_INFO_SUBMATCH:
- // fall through
- return BuildCompat.isAtLeastT();
+ return Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU;
// Android U Features
+ case Features.JOIN_SPEC_AND_QUALIFIED_ID:
+ return BuildCompat.isAtLeastU();
case Features.SEARCH_SPEC_PROPERTY_WEIGHTS:
// TODO(b/203700301) : Update to reflect support in Android U+ once this feature is
// synced over into service-appsearch.
@@ -60,10 +65,6 @@
// TODO(b/261474063) : Update to reflect support in Android U+ once advanced
// ranking becomes available.
// fall through
- case Features.JOIN_SPEC_AND_QUALIFIED_ID:
- // TODO(b/256022027) : Update to reflect support in Android U+ once this feature is
- // synced over into service-appsearch.
- // fall through
case Features.VERBATIM_SEARCH:
// TODO(b/204333391) : Update to reflect support in Android U+ once this feature is
// synced over into service-appsearch.
diff --git a/appsearch/appsearch-platform-storage/src/main/java/androidx/appsearch/platformstorage/GlobalSearchSessionImpl.java b/appsearch/appsearch-platform-storage/src/main/java/androidx/appsearch/platformstorage/GlobalSearchSessionImpl.java
index 6ed63ee..1f10cef 100644
--- a/appsearch/appsearch-platform-storage/src/main/java/androidx/appsearch/platformstorage/GlobalSearchSessionImpl.java
+++ b/appsearch/appsearch-platform-storage/src/main/java/androidx/appsearch/platformstorage/GlobalSearchSessionImpl.java
@@ -16,8 +16,11 @@
package androidx.appsearch.platformstorage;
import android.annotation.SuppressLint;
+import android.app.appsearch.AppSearchResult;
+import android.app.appsearch.BatchResultCallback;
import android.os.Build;
+import androidx.annotation.DoNotInline;
import androidx.annotation.GuardedBy;
import androidx.annotation.NonNull;
import androidx.annotation.RequiresApi;
@@ -52,9 +55,10 @@
import java.util.Map;
import java.util.concurrent.Executor;
+import java.util.function.Consumer;
/**
- * An implementation of {@link androidx.appsearch.app.GlobalSearchSession} which proxies to a
+ * An implementation of {@link GlobalSearchSession} which proxies to a
* platform {@link android.app.appsearch.GlobalSearchSession}.
*
* @hide
@@ -80,13 +84,12 @@
mFeatures = Preconditions.checkNotNull(features);
}
- @BuildCompat.PrereleaseSdkCheck
@NonNull
@Override
public ListenableFuture<AppSearchBatchResult<String, GenericDocument>> getByDocumentIdAsync(
@NonNull String packageName, @NonNull String databaseName,
@NonNull GetByDocumentIdRequest request) {
- if (!BuildCompat.isAtLeastT()) {
+ if (Build.VERSION.SDK_INT < Build.VERSION_CODES.TIRAMISU) {
throw new UnsupportedOperationException(Features.GLOBAL_SEARCH_SESSION_GET_BY_ID
+ " is not supported on this AppSearch implementation.");
}
@@ -95,14 +98,16 @@
Preconditions.checkNotNull(request);
ResolvableFuture<AppSearchBatchResult<String, GenericDocument>> future =
ResolvableFuture.create();
- mPlatformSession.getByDocumentId(packageName, databaseName,
- RequestToPlatformConverter.toPlatformGetByDocumentIdRequest(request),
- mExecutor,
+ ApiHelperForT.getByDocumentId(mPlatformSession, packageName, databaseName,
+ RequestToPlatformConverter.toPlatformGetByDocumentIdRequest(request), mExecutor,
new BatchResultCallbackAdapter<>(
future, GenericDocumentToPlatformConverter::toJetpackGenericDocument));
return future;
}
+ // TODO(b/265311462): Remove these two lines once BuildCompat.isAtLeastU() is removed
+ @SuppressLint("NewApi")
+ @BuildCompat.PrereleaseSdkCheck
@Override
@NonNull
public SearchResults search(
@@ -131,6 +136,8 @@
return future;
}
+ // TODO(b/265311462): Remove BuildCompat.PrereleaseSdkCheck annotation once usage of
+ // BuildCompat.isAtLeastU() is removed.
@BuildCompat.PrereleaseSdkCheck
@NonNull
@Override
@@ -138,16 +145,13 @@
@NonNull String databaseName) {
// Superclass is annotated with @RequiresFeature, so we shouldn't get here on an
// unsupported build.
- if (!BuildCompat.isAtLeastT()) {
+ if (Build.VERSION.SDK_INT < Build.VERSION_CODES.TIRAMISU) {
throw new UnsupportedOperationException(
Features.GLOBAL_SEARCH_SESSION_GET_SCHEMA
+ " is not supported on this AppSearch implementation.");
}
ResolvableFuture<GetSchemaResponse> future = ResolvableFuture.create();
- mPlatformSession.getSchema(
- packageName,
- databaseName,
- mExecutor,
+ ApiHelperForT.getSchema(mPlatformSession, packageName, databaseName, mExecutor,
result -> AppSearchResultToPlatformConverter.platformAppSearchResultToFuture(
result,
future,
@@ -161,9 +165,7 @@
return mFeatures;
}
- // TODO(b/193494000): Remove these two lines once BuildCompat.isAtLeastT() is removed.
- @SuppressLint("NewApi")
- @BuildCompat.PrereleaseSdkCheck
+ @RequiresApi(Build.VERSION_CODES.TIRAMISU)
@Override
public void registerObserverCallback(
@NonNull String targetPackageName,
@@ -176,7 +178,7 @@
Preconditions.checkNotNull(observer);
// Superclass is annotated with @RequiresFeature, so we shouldn't get here on an
// unsupported build.
- if (!BuildCompat.isAtLeastT()) {
+ if (Build.VERSION.SDK_INT < Build.VERSION_CODES.TIRAMISU) {
throw new UnsupportedOperationException(
Features.GLOBAL_SEARCH_SESSION_REGISTER_OBSERVER_CALLBACK
+ " is not supported on this AppSearch implementation");
@@ -213,10 +215,8 @@
// Regardless of whether this stub was fresh or not, we have to register it again
// because the user might be supplying a different spec.
try {
- mPlatformSession.registerObserverCallback(
- targetPackageName,
- ObserverSpecToPlatformConverter.toPlatformObserverSpec(spec),
- executor,
+ ApiHelperForT.registerObserverCallback(mPlatformSession, targetPackageName,
+ ObserverSpecToPlatformConverter.toPlatformObserverSpec(spec), executor,
frameworkCallback);
} catch (android.app.appsearch.exceptions.AppSearchException e) {
throw new AppSearchException((int) e.getResultCode(), e.getMessage(), e.getCause());
@@ -229,8 +229,6 @@
}
}
- @SuppressLint("NewApi")
- @BuildCompat.PrereleaseSdkCheck
@Override
public void unregisterObserverCallback(
@NonNull String targetPackageName, @NonNull ObserverCallback observer)
@@ -239,7 +237,7 @@
Preconditions.checkNotNull(observer);
// Superclass is annotated with @RequiresFeature, so we shouldn't get here on an
// unsupported build.
- if (!BuildCompat.isAtLeastT()) {
+ if (Build.VERSION.SDK_INT < Build.VERSION_CODES.TIRAMISU) {
throw new UnsupportedOperationException(
Features.GLOBAL_SEARCH_SESSION_REGISTER_OBSERVER_CALLBACK
+ " is not supported on this AppSearch implementation");
@@ -253,7 +251,8 @@
}
try {
- mPlatformSession.unregisterObserverCallback(targetPackageName, frameworkCallback);
+ ApiHelperForT.unregisterObserverCallback(mPlatformSession, targetPackageName,
+ frameworkCallback);
} catch (android.app.appsearch.exceptions.AppSearchException e) {
throw new AppSearchException((int) e.getResultCode(), e.getMessage(), e.getCause());
}
@@ -267,4 +266,43 @@
public void close() {
mPlatformSession.close();
}
+
+ @RequiresApi(Build.VERSION_CODES.TIRAMISU)
+ private static class ApiHelperForT {
+ private ApiHelperForT() {
+ // This class is not instantiable.
+ }
+
+ @DoNotInline
+ static void getByDocumentId(android.app.appsearch.GlobalSearchSession platformSession,
+ String packageName, String databaseName,
+ android.app.appsearch.GetByDocumentIdRequest request, Executor executor,
+ BatchResultCallback<String, android.app.appsearch.GenericDocument> callback) {
+ platformSession.getByDocumentId(packageName, databaseName, request, executor, callback);
+ }
+
+ @DoNotInline
+ static void getSchema(android.app.appsearch.GlobalSearchSession platformSessions,
+ String packageName, String databaseName, Executor executor,
+ Consumer<AppSearchResult<android.app.appsearch.GetSchemaResponse>> callback) {
+ platformSessions.getSchema(packageName, databaseName, executor, callback);
+ }
+
+ @DoNotInline
+ static void registerObserverCallback(
+ android.app.appsearch.GlobalSearchSession platformSession, String targetPackageName,
+ android.app.appsearch.observer.ObserverSpec spec, Executor executor,
+ android.app.appsearch.observer.ObserverCallback observer)
+ throws android.app.appsearch.exceptions.AppSearchException {
+ platformSession.registerObserverCallback(targetPackageName, spec, executor, observer);
+ }
+
+ @DoNotInline
+ static void unregisterObserverCallback(
+ android.app.appsearch.GlobalSearchSession platformSession, String targetPackageName,
+ android.app.appsearch.observer.ObserverCallback observer)
+ throws android.app.appsearch.exceptions.AppSearchException {
+ platformSession.unregisterObserverCallback(targetPackageName, observer);
+ }
+ }
}
diff --git a/appsearch/appsearch-platform-storage/src/main/java/androidx/appsearch/platformstorage/SearchResultsImpl.java b/appsearch/appsearch-platform-storage/src/main/java/androidx/appsearch/platformstorage/SearchResultsImpl.java
index 6fde6d6..1217bf6 100644
--- a/appsearch/appsearch-platform-storage/src/main/java/androidx/appsearch/platformstorage/SearchResultsImpl.java
+++ b/appsearch/appsearch-platform-storage/src/main/java/androidx/appsearch/platformstorage/SearchResultsImpl.java
@@ -58,13 +58,14 @@
mExecutor = Preconditions.checkNotNull(executor);
}
+ // TODO(b/265311462): Remove BuildCompat.PrereleaseSdkCheck annotation once usage of
+ // BuildCompat.isAtLeastU() is removed.
@SuppressLint("WrongConstant")
@Override
@NonNull
@BuildCompat.PrereleaseSdkCheck
public ListenableFuture<List<SearchResult>> getNextPageAsync() {
- // TODO(b/256022027): add isAtLeastU check after Android U.
- if (mSearchSpec.getJoinSpec() != null) {
+ if (!BuildCompat.isAtLeastU() && mSearchSpec.getJoinSpec() != null) {
throw new UnsupportedOperationException("Searching with a SearchSpec containing a "
+ "JoinSpec is not supported on this AppSearch implementation.");
}
diff --git a/appsearch/appsearch-platform-storage/src/main/java/androidx/appsearch/platformstorage/SearchSessionImpl.java b/appsearch/appsearch-platform-storage/src/main/java/androidx/appsearch/platformstorage/SearchSessionImpl.java
index a4621c2..e291819 100644
--- a/appsearch/appsearch-platform-storage/src/main/java/androidx/appsearch/platformstorage/SearchSessionImpl.java
+++ b/appsearch/appsearch-platform-storage/src/main/java/androidx/appsearch/platformstorage/SearchSessionImpl.java
@@ -15,6 +15,7 @@
*/
package androidx.appsearch.platformstorage;
+import android.annotation.SuppressLint;
import android.os.Build;
import androidx.annotation.NonNull;
@@ -76,9 +77,11 @@
mFeatures = Preconditions.checkNotNull(features);
}
+ // TODO(b/265311462): Remove these two lines once BuildCompat.isAtLeastU() is removed
+ @SuppressLint("NewApi")
+ @BuildCompat.PrereleaseSdkCheck
@Override
@NonNull
- @BuildCompat.PrereleaseSdkCheck
public ListenableFuture<SetSchemaResponse> setSchemaAsync(@NonNull SetSchemaRequest request) {
Preconditions.checkNotNull(request);
ResolvableFuture<SetSchemaResponse> future = ResolvableFuture.create();
@@ -93,9 +96,11 @@
return future;
}
+ // TODO(b/265311462): Remove BuildCompat.PrereleaseSdkCheck annotation once usage of
+ // BuildCompat.isAtLeastU() is removed.
+ @BuildCompat.PrereleaseSdkCheck
@Override
@NonNull
- @BuildCompat.PrereleaseSdkCheck
public ListenableFuture<GetSchemaResponse> getSchemaAsync() {
ResolvableFuture<GetSchemaResponse> future = ResolvableFuture.create();
mPlatformSession.getSchema(
@@ -146,6 +151,9 @@
return future;
}
+ // TODO(b/265311462): Remove BuildCompat.PrereleaseSdkCheck annotation once usage of
+ // BuildCompat.isAtLeastU() is removed.
+ @BuildCompat.PrereleaseSdkCheck
@Override
@NonNull
public SearchResults search(
@@ -195,9 +203,11 @@
return future;
}
+ // TODO(b/265311462): Remove BuildCompat.PrereleaseSdkCheck annotation once usage of
+ // BuildCompat.isAtLeastU() is removed.
+ @BuildCompat.PrereleaseSdkCheck
@Override
@NonNull
- @BuildCompat.PrereleaseSdkCheck
public ListenableFuture<Void> removeAsync(
@NonNull String queryExpression, @NonNull SearchSpec searchSpec) {
Preconditions.checkNotNull(queryExpression);
@@ -209,7 +219,8 @@
+ "JoinSpec was provided.");
}
- if (!BuildCompat.isAtLeastT() && !searchSpec.getFilterNamespaces().isEmpty()) {
+ if (Build.VERSION.SDK_INT < Build.VERSION_CODES.TIRAMISU
+ && !searchSpec.getFilterNamespaces().isEmpty()) {
// This is a patch for b/197361770, framework-appsearch in Android S will
// disable the given namespace filter if it is not empty and none of given namespaces
// exist.
diff --git a/appsearch/appsearch-platform-storage/src/main/java/androidx/appsearch/platformstorage/converter/GetSchemaResponseToPlatformConverter.java b/appsearch/appsearch-platform-storage/src/main/java/androidx/appsearch/platformstorage/converter/GetSchemaResponseToPlatformConverter.java
index b69caca..d38567c 100644
--- a/appsearch/appsearch-platform-storage/src/main/java/androidx/appsearch/platformstorage/converter/GetSchemaResponseToPlatformConverter.java
+++ b/appsearch/appsearch-platform-storage/src/main/java/androidx/appsearch/platformstorage/converter/GetSchemaResponseToPlatformConverter.java
@@ -18,6 +18,7 @@
import android.os.Build;
+import androidx.annotation.DoNotInline;
import androidx.annotation.NonNull;
import androidx.annotation.RequiresApi;
import androidx.annotation.RestrictTo;
@@ -43,13 +44,15 @@
* Translates a platform {@link android.app.appsearch.GetSchemaResponse} into a jetpack
* {@link GetSchemaResponse}.
*/
- @NonNull
+ // TODO(b/265311462): Remove BuildCompat.PrereleaseSdkCheck annotation once usage of
+ // BuildCompat.isAtLeastU() is removed.
@BuildCompat.PrereleaseSdkCheck
+ @NonNull
public static GetSchemaResponse toJetpackGetSchemaResponse(
@NonNull android.app.appsearch.GetSchemaResponse platformResponse) {
Preconditions.checkNotNull(platformResponse);
GetSchemaResponse.Builder jetpackBuilder;
- if (!BuildCompat.isAtLeastT()) {
+ if (Build.VERSION.SDK_INT < Build.VERSION_CODES.TIRAMISU) {
// Android API level in S-v2 and lower won't have any supported feature.
jetpackBuilder = new GetSchemaResponse.Builder(/*getVisibilitySettingSupported=*/false);
} else {
@@ -60,17 +63,18 @@
jetpackBuilder.addSchema(SchemaToPlatformConverter.toJetpackSchema(platformSchema));
}
jetpackBuilder.setVersion(platformResponse.getVersion());
- if (BuildCompat.isAtLeastT()) {
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
// Convert schemas not displayed by system
for (String schemaTypeNotDisplayedBySystem :
- platformResponse.getSchemaTypesNotDisplayedBySystem()) {
+ ApiHelperForT.getSchemaTypesNotDisplayedBySystem(platformResponse)) {
jetpackBuilder.addSchemaTypeNotDisplayedBySystem(schemaTypeNotDisplayedBySystem);
}
// Convert schemas visible to packages
convertSchemasVisibleToPackages(platformResponse, jetpackBuilder);
// Convert schemas visible to permissions
for (Map.Entry<String, Set<Set<Integer>>> entry :
- platformResponse.getRequiredPermissionsForSchemaTypeVisibility().entrySet()) {
+ ApiHelperForT.getRequiredPermissionsForSchemaTypeVisibility(platformResponse)
+ .entrySet()) {
jetpackBuilder.setRequiredPermissionsForSchemaTypeVisibility(entry.getKey(),
entry.getValue());
}
@@ -90,7 +94,7 @@
// incorrectly returns {@code null} in some prerelease versions of Android T. Remove
// this workaround after the issue is fixed in T.
Map<String, Set<android.app.appsearch.PackageIdentifier>> schemaTypesVisibleToPackages =
- platformResponse.getSchemaTypesVisibleToPackages();
+ ApiHelperForT.getSchemaTypesVisibleToPackage(platformResponse);
if (schemaTypesVisibleToPackages != null) {
for (Map.Entry<String, Set<android.app.appsearch.PackageIdentifier>> entry
: schemaTypesVisibleToPackages.entrySet()) {
@@ -107,4 +111,30 @@
}
}
}
+
+ @RequiresApi(Build.VERSION_CODES.TIRAMISU)
+ private static class ApiHelperForT {
+ private ApiHelperForT() {
+ // This class is not instantiable.
+ }
+
+ @DoNotInline
+ static Set<String> getSchemaTypesNotDisplayedBySystem(
+ android.app.appsearch.GetSchemaResponse platformResponse) {
+ return platformResponse.getSchemaTypesNotDisplayedBySystem();
+ }
+
+ @DoNotInline
+ static Map<String, Set<android.app.appsearch.PackageIdentifier>>
+ getSchemaTypesVisibleToPackage(
+ android.app.appsearch.GetSchemaResponse platformResponse) {
+ return platformResponse.getSchemaTypesVisibleToPackages();
+ }
+
+ @DoNotInline
+ static Map<String, Set<Set<Integer>>> getRequiredPermissionsForSchemaTypeVisibility(
+ android.app.appsearch.GetSchemaResponse platformResponse) {
+ return platformResponse.getRequiredPermissionsForSchemaTypeVisibility();
+ }
+ }
}
diff --git a/appsearch/appsearch-platform-storage/src/main/java/androidx/appsearch/platformstorage/converter/JoinSpecToPlatformConverter.java b/appsearch/appsearch-platform-storage/src/main/java/androidx/appsearch/platformstorage/converter/JoinSpecToPlatformConverter.java
new file mode 100644
index 0000000..9696cec
--- /dev/null
+++ b/appsearch/appsearch-platform-storage/src/main/java/androidx/appsearch/platformstorage/converter/JoinSpecToPlatformConverter.java
@@ -0,0 +1,56 @@
+/*
+ * Copyright 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR 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.annotation.SuppressLint;
+
+import androidx.annotation.NonNull;
+import androidx.annotation.RequiresApi;
+import androidx.annotation.RestrictTo;
+import androidx.appsearch.app.JoinSpec;
+import androidx.core.os.BuildCompat;
+import androidx.core.util.Preconditions;
+
+/**
+ * Translates between Platform and Jetpack versions of {@link JoinSpec}.
+ */
+// TODO(b/265311462): Remove BuildCompat.PrereleaseSdkCheck annotation once
+// SearchSpecToPlatformConverter.toPlatformSearchSpec() removes it. Also, replace literal '34' with
+// Build.VERSION_CODES.UPSIDE_DOWN_CAKE once the SDK_INT is finalized.
+@BuildCompat.PrereleaseSdkCheck
+@RestrictTo(RestrictTo.Scope.LIBRARY)
+@RequiresApi(34)
+public class JoinSpecToPlatformConverter {
+ private JoinSpecToPlatformConverter() {}
+
+ /**
+ * Translates a Jetpack {@link JoinSpec} into a platform {@link android.app.appsearch.JoinSpec}.
+ */
+ @SuppressLint("WrongConstant")
+ @NonNull
+ public static android.app.appsearch.JoinSpec toPlatformJoinSpec(@NonNull JoinSpec jetpackSpec) {
+ Preconditions.checkNotNull(jetpackSpec);
+ return new android.app.appsearch.JoinSpec.Builder(jetpackSpec.getChildPropertyExpression())
+ .setNestedSearch(
+ jetpackSpec.getNestedQuery(),
+ SearchSpecToPlatformConverter.toPlatformSearchSpec(
+ jetpackSpec.getNestedSearchSpec()))
+ .setMaxJoinedResultCount(jetpackSpec.getMaxJoinedResultCount())
+ .setAggregationScoringStrategy(jetpackSpec.getAggregationScoringStrategy())
+ .build();
+ }
+}
diff --git a/appsearch/appsearch-platform-storage/src/main/java/androidx/appsearch/platformstorage/converter/SchemaToPlatformConverter.java b/appsearch/appsearch-platform-storage/src/main/java/androidx/appsearch/platformstorage/converter/SchemaToPlatformConverter.java
index eba43cf..5a8e34f 100644
--- a/appsearch/appsearch-platform-storage/src/main/java/androidx/appsearch/platformstorage/converter/SchemaToPlatformConverter.java
+++ b/appsearch/appsearch-platform-storage/src/main/java/androidx/appsearch/platformstorage/converter/SchemaToPlatformConverter.java
@@ -19,16 +19,18 @@
import android.annotation.SuppressLint;
import android.os.Build;
+import androidx.annotation.DoNotInline;
import androidx.annotation.NonNull;
import androidx.annotation.RequiresApi;
import androidx.annotation.RestrictTo;
import androidx.appsearch.app.AppSearchSchema;
+import androidx.core.os.BuildCompat;
import androidx.core.util.Preconditions;
import java.util.List;
/**
- * Translates a jetpack {@link androidx.appsearch.app.AppSearchSchema} into a platform
+ * Translates a jetpack {@link AppSearchSchema} into a platform
* {@link android.app.appsearch.AppSearchSchema}.
* @hide
*/
@@ -38,9 +40,12 @@
private SchemaToPlatformConverter() {}
/**
- * Translates a jetpack {@link androidx.appsearch.app.AppSearchSchema} into a platform
+ * Translates a jetpack {@link AppSearchSchema} into a platform
* {@link android.app.appsearch.AppSearchSchema}.
*/
+ // TODO(b/265311462): Remove BuildCompat.PrereleaseSdkCheck annotation once
+ // toPlatformProperty() doesn't have it either.
+ @BuildCompat.PrereleaseSdkCheck
@NonNull
public static android.app.appsearch.AppSearchSchema toPlatformSchema(
@NonNull AppSearchSchema jetpackSchema) {
@@ -58,8 +63,11 @@
/**
* Translates a platform {@link android.app.appsearch.AppSearchSchema} to a jetpack
- * {@link androidx.appsearch.app.AppSearchSchema}.
+ * {@link AppSearchSchema}.
*/
+ // TODO(b/265311462): Remove BuildCompat.PrereleaseSdkCheck annotation once usage of
+ // BuildCompat.isAtLeastU() is removed.
+ @BuildCompat.PrereleaseSdkCheck
@NonNull
public static AppSearchSchema toJetpackSchema(
@NonNull android.app.appsearch.AppSearchSchema platformSchema) {
@@ -78,6 +86,9 @@
// Most stringProperty.get calls cause WrongConstant lint errors because the methods are not
// defined as returning the same constants as the corresponding setter expects, but they do
@SuppressLint("WrongConstant")
+ // TODO(b/265311462): Remove BuildCompat.PrereleaseSdkCheck annotation once usage of
+ // BuildCompat.isAtLeastU() is removed.
+ @BuildCompat.PrereleaseSdkCheck
@NonNull
private static android.app.appsearch.AppSearchSchema.PropertyConfig toPlatformProperty(
@NonNull AppSearchSchema.PropertyConfig jetpackProperty) {
@@ -85,20 +96,24 @@
if (jetpackProperty instanceof AppSearchSchema.StringPropertyConfig) {
AppSearchSchema.StringPropertyConfig stringProperty =
(AppSearchSchema.StringPropertyConfig) jetpackProperty;
- // TODO(b/256022027): add isAtLeastU check to allow JOINABLE_VALUE_TYPE_QUALIFIED_ID
- // after Android U, and set joinable value type to PropertyConfig.
- if (stringProperty.getJoinableValueType()
- == AppSearchSchema.StringPropertyConfig.JOINABLE_VALUE_TYPE_QUALIFIED_ID) {
- throw new UnsupportedOperationException(
- "StringPropertyConfig.JOINABLE_VALUE_TYPE_QUALIFIED_ID is not supported on "
- + "this AppSearch implementation.");
- }
- return new android.app.appsearch.AppSearchSchema.StringPropertyConfig.Builder(
+ android.app.appsearch.AppSearchSchema.StringPropertyConfig.Builder platformBuilder =
+ new android.app.appsearch.AppSearchSchema.StringPropertyConfig.Builder(
stringProperty.getName())
.setCardinality(stringProperty.getCardinality())
.setIndexingType(stringProperty.getIndexingType())
- .setTokenizerType(stringProperty.getTokenizerType())
- .build();
+ .setTokenizerType(stringProperty.getTokenizerType());
+
+ if (stringProperty.getJoinableValueType()
+ == AppSearchSchema.StringPropertyConfig.JOINABLE_VALUE_TYPE_QUALIFIED_ID) {
+ if (!BuildCompat.isAtLeastU()) {
+ throw new UnsupportedOperationException(
+ "StringPropertyConfig.JOINABLE_VALUE_TYPE_QUALIFIED_ID is not supported"
+ + " on this AppSearch implementation.");
+ }
+ ApiHelperForU.setJoinableValueType(platformBuilder,
+ stringProperty.getJoinableValueType());
+ }
+ return platformBuilder.build();
} else if (jetpackProperty instanceof AppSearchSchema.LongPropertyConfig) {
AppSearchSchema.LongPropertyConfig longProperty =
(AppSearchSchema.LongPropertyConfig) jetpackProperty;
@@ -145,6 +160,9 @@
// Most stringProperty.get calls cause WrongConstant lint errors because the methods are not
// defined as returning the same constants as the corresponding setter expects, but they do
@SuppressLint("WrongConstant")
+ // TODO(b/265311462): Remove BuildCompat.PrereleaseSdkCheck annotation once usage of
+ // BuildCompat.isAtLeastU() is removed.
+ @BuildCompat.PrereleaseSdkCheck
@NonNull
private static AppSearchSchema.PropertyConfig toJetpackProperty(
@NonNull android.app.appsearch.AppSearchSchema.PropertyConfig platformProperty) {
@@ -153,11 +171,16 @@
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();
+ AppSearchSchema.StringPropertyConfig.Builder jetpackBuilder =
+ new AppSearchSchema.StringPropertyConfig.Builder(stringProperty.getName())
+ .setCardinality(stringProperty.getCardinality())
+ .setIndexingType(stringProperty.getIndexingType())
+ .setTokenizerType(stringProperty.getTokenizerType());
+ if (BuildCompat.isAtLeastU()) {
+ jetpackBuilder.setJoinableValueType(
+ ApiHelperForU.getJoinableValueType(stringProperty));
+ }
+ return jetpackBuilder.build();
} else if (platformProperty
instanceof android.app.appsearch.AppSearchSchema.LongPropertyConfig) {
return new AppSearchSchema.LongPropertyConfig.Builder(platformProperty.getName())
@@ -194,4 +217,30 @@
+ ": " + platformProperty);
}
}
+
+ // TODO(b/265311462): Replace literal '34' with Build.VERSION_CODES.UPSIDE_DOWN_CAKE when the
+ // SDK_INT is finalized.
+ @RequiresApi(34)
+ private static class ApiHelperForU {
+ private ApiHelperForU() {
+ // This class is not instantiable.
+ }
+
+ @DoNotInline
+ static void setJoinableValueType(
+ android.app.appsearch.AppSearchSchema.StringPropertyConfig.Builder builder,
+ @AppSearchSchema.StringPropertyConfig.JoinableValueType int joinableValueType) {
+ builder.setJoinableValueType(joinableValueType);
+ }
+
+ // Most stringProperty.get calls cause WrongConstant lint errors because the methods are not
+ // defined as returning the same constants as the corresponding setter expects, but they do
+ @SuppressLint("WrongConstant")
+ @DoNotInline
+ @AppSearchSchema.StringPropertyConfig.JoinableValueType
+ static int getJoinableValueType(
+ android.app.appsearch.AppSearchSchema.StringPropertyConfig stringPropertyConfig) {
+ return stringPropertyConfig.getJoinableValueType();
+ }
+ }
}
diff --git a/appsearch/appsearch-platform-storage/src/main/java/androidx/appsearch/platformstorage/converter/SearchResultToPlatformConverter.java b/appsearch/appsearch-platform-storage/src/main/java/androidx/appsearch/platformstorage/converter/SearchResultToPlatformConverter.java
index 707234d..a36e9cf 100644
--- a/appsearch/appsearch-platform-storage/src/main/java/androidx/appsearch/platformstorage/converter/SearchResultToPlatformConverter.java
+++ b/appsearch/appsearch-platform-storage/src/main/java/androidx/appsearch/platformstorage/converter/SearchResultToPlatformConverter.java
@@ -18,6 +18,7 @@
import android.os.Build;
+import androidx.annotation.DoNotInline;
import androidx.annotation.NonNull;
import androidx.annotation.RequiresApi;
import androidx.annotation.RestrictTo;
@@ -38,6 +39,8 @@
private SearchResultToPlatformConverter() {}
/** Translates from Platform to Jetpack versions of {@link SearchResult}. */
+ // TODO(b/265311462): Remove BuildCompat.PrereleaseSdkCheck annotation once usage of
+ // BuildCompat.isAtLeastU() is removed.
@BuildCompat.PrereleaseSdkCheck
@NonNull
public static SearchResult toJetpackSearchResult(
@@ -55,10 +58,15 @@
SearchResult.MatchInfo jetpackMatchInfo = toJetpackMatchInfo(platformMatches.get(i));
builder.addMatchInfo(jetpackMatchInfo);
}
+ if (BuildCompat.isAtLeastU()) {
+ for (android.app.appsearch.SearchResult joinedResult :
+ ApiHelperForU.getJoinedResults(platformResult)) {
+ builder.addJoinedResult(toJetpackSearchResult(joinedResult));
+ }
+ }
return builder.build();
}
- @BuildCompat.PrereleaseSdkCheck
@NonNull
private static SearchResult.MatchInfo toJetpackMatchInfo(
@NonNull android.app.appsearch.SearchResult.MatchInfo platformMatchInfo) {
@@ -73,12 +81,46 @@
new SearchResult.MatchRange(
platformMatchInfo.getSnippetRange().getStart(),
platformMatchInfo.getSnippetRange().getEnd()));
- if (BuildCompat.isAtLeastT()) {
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
builder.setSubmatchRange(
new SearchResult.MatchRange(
- platformMatchInfo.getSubmatchRange().getStart(),
- platformMatchInfo.getSubmatchRange().getEnd()));
+ ApiHelperForT.getSubmatchRangeStart(platformMatchInfo),
+ ApiHelperForT.getSubmatchRangeEnd(platformMatchInfo)));
}
return builder.build();
}
+
+ @RequiresApi(Build.VERSION_CODES.TIRAMISU)
+ private static class ApiHelperForT {
+ private ApiHelperForT() {
+ // This class is not instantiable.
+ }
+
+ @DoNotInline
+ static int getSubmatchRangeStart(@NonNull
+ android.app.appsearch.SearchResult.MatchInfo platformMatchInfo) {
+ return platformMatchInfo.getSubmatchRange().getStart();
+ }
+
+ @DoNotInline
+ static int getSubmatchRangeEnd(@NonNull
+ android.app.appsearch.SearchResult.MatchInfo platformMatchInfo) {
+ return platformMatchInfo.getSubmatchRange().getEnd();
+ }
+ }
+
+ // TODO(b/265311462): Replace literal '34' with Build.VERSION_CODES.UPSIDE_DOWN_CAKE when the
+ // SDK_INT is finalized.
+ @RequiresApi(34)
+ private static class ApiHelperForU {
+ private ApiHelperForU() {
+ // This class is not instantiable.
+ }
+
+ @DoNotInline
+ static List<android.app.appsearch.SearchResult> getJoinedResults(@NonNull
+ android.app.appsearch.SearchResult result) {
+ return result.getJoinedResults();
+ }
+ }
}
diff --git a/appsearch/appsearch-platform-storage/src/main/java/androidx/appsearch/platformstorage/converter/SearchSpecToPlatformConverter.java b/appsearch/appsearch-platform-storage/src/main/java/androidx/appsearch/platformstorage/converter/SearchSpecToPlatformConverter.java
index cc2bd0a..5f69b3c 100644
--- a/appsearch/appsearch-platform-storage/src/main/java/androidx/appsearch/platformstorage/converter/SearchSpecToPlatformConverter.java
+++ b/appsearch/appsearch-platform-storage/src/main/java/androidx/appsearch/platformstorage/converter/SearchSpecToPlatformConverter.java
@@ -19,11 +19,14 @@
import android.annotation.SuppressLint;
import android.os.Build;
+import androidx.annotation.DoNotInline;
import androidx.annotation.NonNull;
import androidx.annotation.RequiresApi;
import androidx.annotation.RestrictTo;
import androidx.appsearch.app.Features;
+import androidx.appsearch.app.JoinSpec;
import androidx.appsearch.app.SearchSpec;
+import androidx.core.os.BuildCompat;
import androidx.core.util.Preconditions;
import java.util.List;
@@ -44,6 +47,9 @@
// Most jetpackSearchSpec.get calls cause WrongConstant lint errors because the methods are not
// defined as returning the same constants as the corresponding setter expects, but they do
@SuppressLint("WrongConstant")
+ // TODO(b/265311462): Remove BuildCompat.PrereleaseSdkCheck annotation once usage of
+ // BuildCompat.isAtLeastU() is removed.
+ @BuildCompat.PrereleaseSdkCheck
@NonNull
public static android.app.appsearch.SearchSpec toPlatformSearchSpec(
@NonNull SearchSpec jetpackSearchSpec) {
@@ -89,6 +95,31 @@
"Property weights are not supported with this backend/Android API level "
+ "combination.");
}
+
+ if (jetpackSearchSpec.getJoinSpec() != null) {
+ if (!BuildCompat.isAtLeastU()) {
+ throw new UnsupportedOperationException("JoinSpec is not available on this "
+ + "AppSearch implementation.");
+ }
+ ApiHelperForU.setJoinSpec(platformBuilder, jetpackSearchSpec.getJoinSpec());
+ }
return platformBuilder.build();
}
+
+ // TODO(b/265311462): Remove BuildCompat.PrereleaseSdkCheck annotation once usage of
+ // BuildCompat.isAtLeastU() is removed. Also, replace literal '34' with
+ // Build.VERSION_CODES.UPSIDE_DOWN_CAKE once the SDK_INT is finalized.
+ @BuildCompat.PrereleaseSdkCheck
+ @RequiresApi(34)
+ private static class ApiHelperForU {
+ private ApiHelperForU() {
+ // This class is not instantiable.
+ }
+
+ @DoNotInline
+ static void setJoinSpec(@NonNull android.app.appsearch.SearchSpec.Builder builder,
+ JoinSpec jetpackJoinSpec) {
+ builder.setJoinSpec(JoinSpecToPlatformConverter.toPlatformJoinSpec(jetpackJoinSpec));
+ }
+ }
}
diff --git a/appsearch/appsearch-platform-storage/src/main/java/androidx/appsearch/platformstorage/converter/SetSchemaRequestToPlatformConverter.java b/appsearch/appsearch-platform-storage/src/main/java/androidx/appsearch/platformstorage/converter/SetSchemaRequestToPlatformConverter.java
index 6950427..4dec86b 100644
--- a/appsearch/appsearch-platform-storage/src/main/java/androidx/appsearch/platformstorage/converter/SetSchemaRequestToPlatformConverter.java
+++ b/appsearch/appsearch-platform-storage/src/main/java/androidx/appsearch/platformstorage/converter/SetSchemaRequestToPlatformConverter.java
@@ -18,6 +18,7 @@
import android.os.Build;
+import androidx.annotation.DoNotInline;
import androidx.annotation.NonNull;
import androidx.annotation.RequiresApi;
import androidx.annotation.RestrictTo;
@@ -47,6 +48,8 @@
* Translates a jetpack {@link SetSchemaRequest} into a platform
* {@link android.app.appsearch.SetSchemaRequest}.
*/
+ // TODO(b/265311462): Remove BuildCompat.PrereleaseSdkCheck annotation once usage of
+ // BuildCompat.isAtLeastU() is removed.
@BuildCompat.PrereleaseSdkCheck
@NonNull
public static android.app.appsearch.SetSchemaRequest toPlatformSetSchemaRequest(
@@ -74,7 +77,7 @@
}
}
if (!jetpackRequest.getRequiredPermissionsForSchemaTypeVisibility().isEmpty()) {
- if (!BuildCompat.isAtLeastT()) {
+ if (Build.VERSION.SDK_INT < Build.VERSION_CODES.TIRAMISU) {
throw new UnsupportedOperationException(
"Set required permissions for schema type visibility are not supported "
+ "with this backend/Android API level combination.");
@@ -82,7 +85,7 @@
for (Map.Entry<String, Set<Set<Integer>>> entry :
jetpackRequest.getRequiredPermissionsForSchemaTypeVisibility().entrySet()) {
for (Set<Integer> permissionGroup : entry.getValue()) {
- platformBuilder.addRequiredPermissionsForSchemaTypeVisibility(
+ ApiHelperForT.addRequiredPermissionsForSchemaTypeVisibility(platformBuilder,
entry.getKey(), permissionGroup);
}
}
@@ -163,4 +166,18 @@
}
return jetpackBuilder.build();
}
+
+ @RequiresApi(Build.VERSION_CODES.TIRAMISU)
+ private static class ApiHelperForT {
+ private ApiHelperForT() {
+ // This class is not instantiable.
+ }
+
+ @DoNotInline
+ static void addRequiredPermissionsForSchemaTypeVisibility(
+ android.app.appsearch.SetSchemaRequest.Builder platformBuilder,
+ String schemaType, Set<Integer> permissions) {
+ platformBuilder.addRequiredPermissionsForSchemaTypeVisibility(schemaType, permissions);
+ }
+ }
}
diff --git a/appsearch/appsearch-test-util/src/main/java/androidx/appsearch/testutil/AppSearchEmail.java b/appsearch/appsearch-test-util/src/main/java/androidx/appsearch/testutil/AppSearchEmail.java
index 5aec156..08b1840 100644
--- a/appsearch/appsearch-test-util/src/main/java/androidx/appsearch/testutil/AppSearchEmail.java
+++ b/appsearch/appsearch-test-util/src/main/java/androidx/appsearch/testutil/AppSearchEmail.java
@@ -19,6 +19,7 @@
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.annotation.RestrictTo;
+import androidx.appsearch.annotation.CanIgnoreReturnValue;
import androidx.appsearch.app.AppSearchSchema;
import androidx.appsearch.app.AppSearchSchema.PropertyConfig;
import androidx.appsearch.app.AppSearchSchema.StringPropertyConfig;
@@ -170,6 +171,7 @@
/**
* Sets the from address of {@link AppSearchEmail}
*/
+ @CanIgnoreReturnValue
@NonNull
public Builder setFrom(@NonNull String from) {
return setPropertyString(KEY_FROM, from);
@@ -178,6 +180,7 @@
/**
* Sets the destination address of {@link AppSearchEmail}
*/
+ @CanIgnoreReturnValue
@NonNull
public Builder setTo(@NonNull String... to) {
return setPropertyString(KEY_TO, to);
@@ -186,6 +189,7 @@
/**
* Sets the CC list of {@link AppSearchEmail}
*/
+ @CanIgnoreReturnValue
@NonNull
public Builder setCc(@NonNull String... cc) {
return setPropertyString(KEY_CC, cc);
@@ -194,6 +198,7 @@
/**
* Sets the BCC list of {@link AppSearchEmail}
*/
+ @CanIgnoreReturnValue
@NonNull
public Builder setBcc(@NonNull String... bcc) {
return setPropertyString(KEY_BCC, bcc);
@@ -202,6 +207,7 @@
/**
* Sets the subject of {@link AppSearchEmail}
*/
+ @CanIgnoreReturnValue
@NonNull
public Builder setSubject(@NonNull String subject) {
return setPropertyString(KEY_SUBJECT, subject);
@@ -210,6 +216,7 @@
/**
* Sets the body of {@link AppSearchEmail}
*/
+ @CanIgnoreReturnValue
@NonNull
public Builder setBody(@NonNull String body) {
return setPropertyString(KEY_BODY, body);
diff --git a/appsearch/appsearch/api/current.txt b/appsearch/appsearch/api/current.txt
index 289cdbf..df8eeaa 100644
--- a/appsearch/appsearch/api/current.txt
+++ b/appsearch/appsearch/api/current.txt
@@ -46,6 +46,7 @@
@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 int joinableValueType() default androidx.appsearch.app.AppSearchSchema.StringPropertyConfig.JOINABLE_VALUE_TYPE_NONE;
method public abstract String name() default "";
method public abstract boolean required() default false;
method public abstract int tokenizerType() default androidx.appsearch.app.AppSearchSchema.StringPropertyConfig.TOKENIZER_TYPE_PLAIN;
diff --git a/appsearch/appsearch/api/public_plus_experimental_current.txt b/appsearch/appsearch/api/public_plus_experimental_current.txt
index 289cdbf..df8eeaa 100644
--- a/appsearch/appsearch/api/public_plus_experimental_current.txt
+++ b/appsearch/appsearch/api/public_plus_experimental_current.txt
@@ -46,6 +46,7 @@
@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 int joinableValueType() default androidx.appsearch.app.AppSearchSchema.StringPropertyConfig.JOINABLE_VALUE_TYPE_NONE;
method public abstract String name() default "";
method public abstract boolean required() default false;
method public abstract int tokenizerType() default androidx.appsearch.app.AppSearchSchema.StringPropertyConfig.TOKENIZER_TYPE_PLAIN;
diff --git a/appsearch/appsearch/api/restricted_current.txt b/appsearch/appsearch/api/restricted_current.txt
index 289cdbf..df8eeaa 100644
--- a/appsearch/appsearch/api/restricted_current.txt
+++ b/appsearch/appsearch/api/restricted_current.txt
@@ -46,6 +46,7 @@
@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 int joinableValueType() default androidx.appsearch.app.AppSearchSchema.StringPropertyConfig.JOINABLE_VALUE_TYPE_NONE;
method public abstract String name() default "";
method public abstract boolean required() default false;
method public abstract int tokenizerType() default androidx.appsearch.app.AppSearchSchema.StringPropertyConfig.TOKENIZER_TYPE_PLAIN;
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 2e657eb..8179d57 100644
--- a/appsearch/appsearch/src/androidTest/java/androidx/appsearch/app/AnnotationProcessorTestBase.java
+++ b/appsearch/appsearch/src/androidTest/java/androidx/appsearch/app/AnnotationProcessorTestBase.java
@@ -17,15 +17,23 @@
package androidx.appsearch.app;
import static androidx.appsearch.app.AppSearchSchema.StringPropertyConfig.INDEXING_TYPE_PREFIXES;
+import static androidx.appsearch.app.AppSearchSchema.StringPropertyConfig.JOINABLE_VALUE_TYPE_QUALIFIED_ID;
import static androidx.appsearch.app.AppSearchSchema.StringPropertyConfig.TOKENIZER_TYPE_PLAIN;
import static androidx.appsearch.testutil.AppSearchTestUtils.checkIsBatchResultSuccess;
import static androidx.appsearch.testutil.AppSearchTestUtils.convertSearchResultsToDocuments;
import static com.google.common.truth.Truth.assertThat;
+import static org.junit.Assert.assertThrows;
+import static org.junit.Assume.assumeFalse;
+import static org.junit.Assume.assumeTrue;
+
import androidx.annotation.NonNull;
import androidx.appsearch.annotation.Document;
+import androidx.appsearch.exceptions.AppSearchException;
import androidx.appsearch.testutil.AppSearchEmail;
+import androidx.appsearch.util.DocumentIdUtil;
+import androidx.test.core.app.ApplicationProvider;
import com.google.auto.value.AutoValue;
import com.google.common.util.concurrent.ListenableFuture;
@@ -40,6 +48,8 @@
public abstract class AnnotationProcessorTestBase {
private AppSearchSession mSession;
+ private static final String TEST_PACKAGE_NAME =
+ ApplicationProvider.getApplicationContext().getPackageName();
private static final String DB_NAME_1 = "";
protected abstract ListenableFuture<AppSearchSession> createSearchSessionAsync(
@@ -241,7 +251,7 @@
assertThat(first.toArray()).isEqualTo(second.toArray());
}
- public static Gift createPopulatedGift() {
+ public static Gift createPopulatedGift() throws AppSearchException {
Gift gift = new Gift();
gift.mNamespace = "gift.namespace";
gift.mId = "gift.id";
@@ -295,6 +305,33 @@
}
}
+
+ @Document
+ static class CardAction {
+ @Document.Namespace
+ String mNamespace;
+
+ @Document.Id
+ String mId;
+ @Document.StringProperty(name = "cardRef",
+ joinableValueType = JOINABLE_VALUE_TYPE_QUALIFIED_ID)
+ String mCardReference; // 3a
+ @Override
+ public boolean equals(Object other) {
+ if (this == other) {
+ return true;
+ }
+ if (!(other instanceof CardAction)) {
+ return false;
+ }
+ CardAction otherGift = (CardAction) other;
+ assertThat(otherGift.mNamespace).isEqualTo(this.mNamespace);
+ assertThat(otherGift.mId).isEqualTo(this.mId);
+ assertThat(otherGift.mCardReference).isEqualTo(this.mCardReference);
+ return true;
+ }
+ }
+
@Test
public void testAnnotationProcessor() throws Exception {
//TODO(b/156296904) add test for int, float, GenericDocument, and class with
@@ -323,9 +360,9 @@
@Test
public void testAnnotationProcessor_queryByType() throws Exception {
mSession.setSchemaAsync(
- new SetSchemaRequest.Builder()
- .addDocumentClasses(Card.class, Gift.class)
- .addSchemas(AppSearchEmail.SCHEMA).build())
+ new SetSchemaRequest.Builder()
+ .addDocumentClasses(Card.class, Gift.class)
+ .addSchemas(AppSearchEmail.SCHEMA).build())
.get();
// Create documents and index them
@@ -377,6 +414,61 @@
}
@Test
+ public void testAnnotationProcessor_simpleJoin() throws Exception {
+ assumeTrue(mSession.getFeatures().isFeatureSupported(Features.JOIN_SPEC_AND_QUALIFIED_ID));
+ mSession.setSchemaAsync(
+ new SetSchemaRequest.Builder()
+ .addDocumentClasses(Card.class, CardAction.class)
+ .build())
+ .get();
+
+ // Index a Card and a Gift referencing it.
+ Card peetsCard = new Card();
+ peetsCard.mNamespace = "personal";
+ peetsCard.mId = "peets1";
+ CardAction bdayGift = new CardAction();
+ bdayGift.mNamespace = "personal";
+ bdayGift.mId = "2023-jan-31";
+ bdayGift.mCardReference = DocumentIdUtil.createQualifiedId(TEST_PACKAGE_NAME, DB_NAME_1,
+ GenericDocument.fromDocumentClass(peetsCard));
+ checkIsBatchResultSuccess(mSession.putAsync(
+ new PutDocumentsRequest.Builder().addDocuments(peetsCard, bdayGift).build()));
+
+ // Retrieve cards with any given gifts.
+ SearchSpec innerSpec = new SearchSpec.Builder()
+ .addFilterDocumentClasses(CardAction.class)
+ .build();
+ JoinSpec js = new JoinSpec.Builder("cardRef")
+ .setNestedSearch(/*nestedQuery*/ "", innerSpec)
+ .build();
+ SearchResults resultsIter = mSession.search(/*queryExpression*/ "",
+ new SearchSpec.Builder()
+ .addFilterDocumentClasses(Card.class)
+ .setJoinSpec(js)
+ .build());
+
+ // Verify that search results include card(s) joined with gift(s).
+ List<SearchResult> results = resultsIter.getNextPageAsync().get();
+ assertThat(results).hasSize(1);
+ GenericDocument cardResultDoc = results.get(0).getGenericDocument();
+ assertThat(cardResultDoc.getId()).isEqualTo(peetsCard.mId);
+ List<SearchResult> joinedCardResults = results.get(0).getJoinedResults();
+ assertThat(joinedCardResults).hasSize(1);
+ GenericDocument giftResultDoc = joinedCardResults.get(0).getGenericDocument();
+ assertThat(giftResultDoc.getId()).isEqualTo(bdayGift.mId);
+ }
+
+ @Test
+ public void testAnnotationProcessor_onTAndBelow_joinNotSupported() throws Exception {
+ assumeFalse(mSession.getFeatures().isFeatureSupported(Features.JOIN_SPEC_AND_QUALIFIED_ID));
+ Exception e = assertThrows(UnsupportedOperationException.class,
+ () -> mSession.setSchemaAsync(
+ new SetSchemaRequest.Builder()
+ .addDocumentClasses(Card.class, CardAction.class)
+ .build()));
+ }
+
+ @Test
public void testGenericDocumentConversion() throws Exception {
Gift inGift = Gift.createPopulatedGift();
GenericDocument genericDocument1 = GenericDocument.fromDocumentClass(inGift);
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
index 75b3888..0d0ac6e 100644
--- a/appsearch/appsearch/src/androidTest/java/androidx/appsearch/cts/app/AppSearchSchemaMigrationLocalCtsTest.java
+++ b/appsearch/appsearch/src/androidTest/java/androidx/appsearch/cts/app/AppSearchSchemaMigrationLocalCtsTest.java
@@ -22,12 +22,10 @@
import androidx.appsearch.app.AppSearchSession;
import androidx.appsearch.localstorage.LocalStorage;
import androidx.test.core.app.ApplicationProvider;
-import androidx.test.filters.FlakyTest;
import com.google.common.util.concurrent.ListenableFuture;
-@FlakyTest(bugId = 242761389)
-public class AppSearchSchemaMigrationLocalCtsTest extends AppSearchSchemaMigrationCtsTestBase{
+public class AppSearchSchemaMigrationLocalCtsTest extends AppSearchSchemaMigrationCtsTestBase {
@Override
protected ListenableFuture<AppSearchSession> createSearchSessionAsync(@NonNull String dbName) {
Context context = ApplicationProvider.getApplicationContext();
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
index bf470fd..7103f31 100644
--- a/appsearch/appsearch/src/androidTest/java/androidx/appsearch/cts/app/AppSearchSessionCtsTestBase.java
+++ b/appsearch/appsearch/src/androidTest/java/androidx/appsearch/cts/app/AppSearchSessionCtsTestBase.java
@@ -4159,7 +4159,7 @@
.isFeatureSupported(Features.JOIN_SPEC_AND_QUALIFIED_ID));
// A full example of how join might be used
- AppSearchSchema actionSchema = new AppSearchSchema.Builder("BookmarkAction")
+ AppSearchSchema actionSchema = new AppSearchSchema.Builder("ViewAction")
.addProperty(new StringPropertyConfig.Builder("entityId")
.setCardinality(PropertyConfig.CARDINALITY_OPTIONAL)
.setIndexingType(StringPropertyConfig.INDEXING_TYPE_EXACT_TERMS)
@@ -4203,18 +4203,29 @@
String qualifiedId = DocumentIdUtil.createQualifiedId(mContext.getPackageName(), DB_NAME_1,
"namespace", "id1");
- GenericDocument join = new GenericDocument.Builder<>("NS", "id3", "BookmarkAction")
+ GenericDocument viewAction1 = new GenericDocument.Builder<>("NS", "id3", "ViewAction")
+ .setScore(1)
.setPropertyString("entityId", qualifiedId)
- .setPropertyString("note", "Hi this is a joined doc").build();
+ .setPropertyString("note", "Viewed email on Monday").build();
+ GenericDocument viewAction2 = new GenericDocument.Builder<>("NS", "id4", "ViewAction")
+ .setScore(2)
+ .setPropertyString("entityId", qualifiedId)
+ .setPropertyString("note", "Viewed email on Tuesday").build();
checkIsBatchResultSuccess(mDb1.putAsync(
- new PutDocumentsRequest.Builder().addGenericDocuments(inEmail, inEmail2, join)
+ new PutDocumentsRequest.Builder().addGenericDocuments(inEmail, inEmail2,
+ viewAction1, viewAction2)
.build()));
- SearchSpec nestedSearchSpec = new SearchSpec.Builder().build();
+ SearchSpec nestedSearchSpec =
+ new SearchSpec.Builder()
+ .setRankingStrategy(SearchSpec.RANKING_STRATEGY_DOCUMENT_SCORE)
+ .setOrder(SearchSpec.ORDER_ASCENDING)
+ .build();
JoinSpec js = new JoinSpec.Builder("entityId")
.setNestedSearch("", nestedSearchSpec)
.setAggregationScoringStrategy(JoinSpec.AGGREGATION_SCORING_RESULT_COUNT)
+ .setMaxJoinedResultCount(1)
.build();
SearchResults searchResults = mDb1.search("body email", new SearchSpec.Builder()
@@ -4230,7 +4241,7 @@
assertThat(sr.get(0).getGenericDocument().getId()).isEqualTo("id1");
assertThat(sr.get(0).getJoinedResults()).hasSize(1);
- assertThat(sr.get(0).getJoinedResults().get(0).getGenericDocument()).isEqualTo(join);
+ assertThat(sr.get(0).getJoinedResults().get(0).getGenericDocument()).isEqualTo(viewAction1);
assertThat(sr.get(0).getRankingSignal()).isEqualTo(1.0);
assertThat(sr.get(1).getGenericDocument().getId()).isEqualTo("id2");
@@ -4239,22 +4250,20 @@
}
@Test
- public void testJoinWithoutSupport() throws Exception {
+ public void testJoin_unsupportedFeature_throwsException() throws Exception {
assumeFalse(mDb1.getFeatures().isFeatureSupported(Features.JOIN_SPEC_AND_QUALIFIED_ID));
SearchSpec nestedSearchSpec = new SearchSpec.Builder().build();
JoinSpec js = new JoinSpec.Builder("entityId").setNestedSearch("", nestedSearchSpec)
.build();
- SearchResults searchResults = mDb1.search("", new SearchSpec.Builder()
- .setJoinSpec(js)
- .setTermMatch(SearchSpec.TERM_MATCH_EXACT_ONLY)
- .build());
-
- Exception e = assertThrows(UnsupportedOperationException.class, () ->
- searchResults.getNextPageAsync().get());
- assertThat(e).isInstanceOf(UnsupportedOperationException.class);
- assertThat(e.getMessage()).isEqualTo("Searching with a SearchSpec containing a JoinSpec "
- + "is not supported on this AppSearch implementation.");
+ Exception e = assertThrows(UnsupportedOperationException.class, () -> mDb1.search(
+ /*queryExpression */ "",
+ new SearchSpec.Builder()
+ .setJoinSpec(js)
+ .setTermMatch(SearchSpec.TERM_MATCH_EXACT_ONLY)
+ .build()));
+ assertThat(e.getMessage()).isEqualTo("JoinSpec is not available on this AppSearch "
+ + "implementation.");
}
@Test
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
index dd71fc5..3b44155 100644
--- a/appsearch/appsearch/src/androidTest/java/androidx/appsearch/cts/app/GlobalSearchSessionCtsTestBase.java
+++ b/appsearch/appsearch/src/androidTest/java/androidx/appsearch/cts/app/GlobalSearchSessionCtsTestBase.java
@@ -1837,15 +1837,22 @@
public void testGlobalQuery_propertyWeights() throws Exception {
assumeTrue(mDb1.getFeatures().isFeatureSupported(Features.SEARCH_SPEC_PROPERTY_WEIGHTS));
- // Schema registration
+ // RELEVANCE scoring depends on stats for the namespace+type of the scored document, namely
+ // the average document length. This average document length calculation is only updated
+ // when documents are added and when compaction runs. This means that old deleted
+ // documents of the same namespace and type combination *can* affect RELEVANCE scores
+ // through this channel.
+ // To avoid this, we use a unique namespace that will not be shared by any other test
+ // case or any other run of this test.
mDb1.setSchemaAsync(
new SetSchemaRequest.Builder().addSchemas(AppSearchEmail.SCHEMA).build()).get();
mDb2.setSchemaAsync(
new SetSchemaRequest.Builder().addSchemas(AppSearchEmail.SCHEMA).build()).get();
+ String namespace = "propertyWeightsNamespace" + System.currentTimeMillis();
// Put two documents in separate databases.
AppSearchEmail emailDb1 =
- new AppSearchEmail.Builder("namespace", "id1")
+ new AppSearchEmail.Builder(namespace, "id1")
.setCreationTimestampMillis(1000)
.setSubject("foo")
.build();
@@ -1853,7 +1860,7 @@
new PutDocumentsRequest.Builder()
.addGenericDocuments(emailDb1).build()));
AppSearchEmail emailDb2 =
- new AppSearchEmail.Builder("namespace", "id2")
+ new AppSearchEmail.Builder(namespace, "id2")
.setCreationTimestampMillis(1000)
.setBody("foo")
.build();
@@ -1868,6 +1875,7 @@
.setPropertyWeights(AppSearchEmail.SCHEMA_TYPE,
ImmutableMap.of("subject",
2.0, "body", 0.5))
+ .addFilterNamespaces(namespace)
.build());
List<SearchResult> globalResults = retrieveAllSearchResults(searchResults);
@@ -1889,6 +1897,7 @@
.setTermMatch(SearchSpec.TERM_MATCH_EXACT_ONLY)
.setRankingStrategy(SearchSpec.RANKING_STRATEGY_RELEVANCE_SCORE)
.setOrder(SearchSpec.ORDER_DESCENDING)
+ .addFilterNamespaces(namespace)
.build());
List<SearchResult> resultsWithoutWeights =
retrieveAllSearchResults(searchResultsWithoutWeights);
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
index 038cd56..d7cf08b 100644
--- a/appsearch/appsearch/src/androidTest/java/androidx/appsearch/cts/app/SearchSpecCtsTest.java
+++ b/appsearch/appsearch/src/androidTest/java/androidx/appsearch/cts/app/SearchSpecCtsTest.java
@@ -479,12 +479,13 @@
assertThat(e.getMessage()).isEqualTo("Attempting to rank based on joined documents, but"
+ " no JoinSpec provided");
+ JoinSpec joinSpec = new JoinSpec.Builder("childProp")
+ .setAggregationScoringStrategy(
+ JoinSpec.AGGREGATION_SCORING_SUM_RANKING_SIGNAL)
+ .build();
e = assertThrows(IllegalStateException.class, () -> new SearchSpec.Builder()
.setRankingStrategy(SearchSpec.RANKING_STRATEGY_CREATION_TIMESTAMP)
- .setJoinSpec(new JoinSpec.Builder("childProp")
- .setAggregationScoringStrategy(
- JoinSpec.AGGREGATION_SCORING_SUM_RANKING_SIGNAL)
- .build())
+ .setJoinSpec(joinSpec)
.build());
assertThat(e.getMessage()).isEqualTo("Aggregate scoring strategy has been set in the "
+ "nested JoinSpec, but ranking strategy is not "
diff --git a/appsearch/appsearch/src/main/java/androidx/appsearch/annotation/CanIgnoreReturnValue.java b/appsearch/appsearch/src/main/java/androidx/appsearch/annotation/CanIgnoreReturnValue.java
new file mode 100644
index 0000000..7fa14d3
--- /dev/null
+++ b/appsearch/appsearch/src/main/java/androidx/appsearch/annotation/CanIgnoreReturnValue.java
@@ -0,0 +1,36 @@
+/*
+ * Copyright 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.appsearch.annotation;
+
+import static java.lang.annotation.ElementType.CONSTRUCTOR;
+import static java.lang.annotation.ElementType.METHOD;
+import static java.lang.annotation.ElementType.TYPE;
+import static java.lang.annotation.RetentionPolicy.CLASS;
+
+import java.lang.annotation.Documented;
+import java.lang.annotation.Retention;
+import java.lang.annotation.Target;
+
+/**
+ * Indicates that the return value of the annotated API is ignorable.
+ *
+ * @hide
+ */
+@Documented
+@Target({METHOD, CONSTRUCTOR, TYPE})
+@Retention(CLASS)
+public @interface CanIgnoreReturnValue {}
diff --git a/appsearch/appsearch/src/main/java/androidx/appsearch/annotation/Document.java b/appsearch/appsearch/src/main/java/androidx/appsearch/annotation/Document.java
index 04989eb..893a197 100644
--- a/appsearch/appsearch/src/main/java/androidx/appsearch/annotation/Document.java
+++ b/appsearch/appsearch/src/main/java/androidx/appsearch/annotation/Document.java
@@ -215,6 +215,28 @@
default AppSearchSchema.StringPropertyConfig.INDEXING_TYPE_NONE;
/**
+ * Configures how a property should be processed so that the document can be joined.
+ *
+ * <p>Properties configured with
+ * {@link AppSearchSchema.StringPropertyConfig#JOINABLE_VALUE_TYPE_QUALIFIED_ID} enable
+ * the documents to be joined with other documents that have the same qualified ID as the
+ * value of this field. (A qualified ID is a compact representation of the tuple <package
+ * name, database name, namespace, document ID> that uniquely identifies a document
+ * indexed in the AppSearch storage backend.) This property name can be specified as the
+ * child property expression in {@link androidx.appsearch.app.JoinSpec.Builder(String)} for
+ * join operations.
+ *
+ * <p>This attribute doesn't apply to properties of a repeated type (e.g., a list).
+ *
+ * <p>If not specified, defaults to
+ * {@link AppSearchSchema.StringPropertyConfig#JOINABLE_VALUE_TYPE_NONE}, which means the
+ * property can not be used in a child property expression to configure a
+ * {@link androidx.appsearch.app.JoinSpec.Builder(String)}.
+ */
+ @AppSearchSchema.StringPropertyConfig.JoinableValueType int joinableValueType()
+ default AppSearchSchema.StringPropertyConfig.JOINABLE_VALUE_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).
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 3cdf6ce..72dca86 100644
--- a/appsearch/appsearch/src/main/java/androidx/appsearch/app/AppSearchBatchResult.java
+++ b/appsearch/appsearch/src/main/java/androidx/appsearch/app/AppSearchBatchResult.java
@@ -17,6 +17,7 @@
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
+import androidx.appsearch.annotation.CanIgnoreReturnValue;
import androidx.collection.ArrayMap;
import androidx.core.util.Preconditions;
@@ -138,6 +139,7 @@
* @param value An optional value to associate with the successful result of the operation
* being performed.
*/
+ @CanIgnoreReturnValue
@SuppressWarnings("MissingGetterMatchingBuilder") // See getSuccesses
@NonNull
public Builder<KeyType, ValueType> setSuccess(
@@ -161,6 +163,7 @@
* {@link AppSearchResult#getResultCode}.
* @param errorMessage An optional string describing the reason or nature of the failure.
*/
+ @CanIgnoreReturnValue
@SuppressWarnings("MissingGetterMatchingBuilder") // See getFailures
@NonNull
public Builder<KeyType, ValueType> setFailure(
@@ -181,6 +184,7 @@
* identifier from the input like an ID or name.
* @param result The result to associate with the key.
*/
+ @CanIgnoreReturnValue
@SuppressWarnings("MissingGetterMatchingBuilder") // See getAll
@NonNull
public Builder<KeyType, ValueType> setResult(
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 31b0a88..0c2010a 100644
--- a/appsearch/appsearch/src/main/java/androidx/appsearch/app/AppSearchResult.java
+++ b/appsearch/appsearch/src/main/java/androidx/appsearch/app/AppSearchResult.java
@@ -114,7 +114,8 @@
}
/** Returns one of the {@code RESULT} constants defined in {@link AppSearchResult}. */
- public @ResultCode int getResultCode() {
+ @ResultCode
+ public int getResultCode() {
return mResultCode;
}
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 8a05b92..0005cfc 100644
--- a/appsearch/appsearch/src/main/java/androidx/appsearch/app/AppSearchSchema.java
+++ b/appsearch/appsearch/src/main/java/androidx/appsearch/app/AppSearchSchema.java
@@ -23,6 +23,7 @@
import androidx.annotation.Nullable;
import androidx.annotation.RequiresFeature;
import androidx.annotation.RestrictTo;
+import androidx.appsearch.annotation.CanIgnoreReturnValue;
import androidx.appsearch.exceptions.IllegalSchemaException;
import androidx.appsearch.util.BundleUtil;
import androidx.appsearch.util.IndentingStringBuilder;
@@ -172,6 +173,7 @@
}
/** Adds a property to the given type. */
+ @CanIgnoreReturnValue
@NonNull
public AppSearchSchema.Builder addProperty(@NonNull PropertyConfig propertyConfig) {
Preconditions.checkNotNull(propertyConfig);
@@ -215,10 +217,12 @@
/**
* Physical data-types of the contents of the property.
+ *
+ * <p>NOTE: The integer values of these constants must match the proto enum constants in
+ * com.google.android.icing.proto.PropertyConfigProto.DataType.Code.
+ *
* @hide
*/
- // NOTE: The integer values of these constants must match the proto enum constants in
- // com.google.android.icing.proto.PropertyConfigProto.DataType.Code.
@IntDef(value = {
DATA_TYPE_STRING,
DATA_TYPE_LONG,
@@ -262,10 +266,12 @@
/**
* The cardinality of the property (whether it is required, optional or repeated).
+ *
+ * <p>NOTE: The integer values of these constants must match the proto enum constants in
+ * com.google.android.icing.proto.PropertyConfigProto.Cardinality.Code.
+ *
* @hide
*/
- // NOTE: The integer values of these constants must match the proto enum constants in
- // com.google.android.icing.proto.PropertyConfigProto.Cardinality.Code.
@IntDef(value = {
CARDINALITY_REPEATED,
CARDINALITY_OPTIONAL,
@@ -375,14 +381,16 @@
*
* @hide
*/
- public @DataType int getDataType() {
+ @DataType
+ public 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() {
+ @Cardinality
+ public int getCardinality() {
return mBundle.getInt(CARDINALITY_FIELD, CARDINALITY_OPTIONAL);
}
@@ -480,10 +488,12 @@
/**
* Configures how tokens should be extracted from this property.
+ *
+ * <p>NOTE: The integer values of these constants must match the proto enum constants in
+ * com.google.android.icing.proto.IndexingConfig.TokenizerType.Code.
+ *
* @hide
*/
- // NOTE: The integer values of these constants must match the proto enum constants in
- // com.google.android.icing.proto.IndexingConfig.TokenizerType.Code.
@IntDef(value = {
TOKENIZER_TYPE_NONE,
TOKENIZER_TYPE_PLAIN,
@@ -592,29 +602,32 @@
}
/** Returns how the property is indexed. */
- public @IndexingType int getIndexingType() {
+ @IndexingType
+ public int getIndexingType() {
return mBundle.getInt(INDEXING_TYPE_FIELD);
}
/** Returns how this property is tokenized (split into words). */
- public @TokenizerType int getTokenizerType() {
+ @TokenizerType
+ public int getTokenizerType() {
return mBundle.getInt(TOKENIZER_TYPE_FIELD);
}
/**
* Returns how this property is going to be used to join documents from other schema types.
*/
- public @JoinableValueType int getJoinableValueType() {
+ @JoinableValueType
+ public int getJoinableValueType() {
return mBundle.getInt(JOINABLE_VALUE_TYPE_FIELD, JOINABLE_VALUE_TYPE_NONE);
}
/** Builder for {@link StringPropertyConfig}. */
public static final class Builder {
private final String mPropertyName;
- private @Cardinality int mCardinality = CARDINALITY_OPTIONAL;
- private @IndexingType int mIndexingType = INDEXING_TYPE_NONE;
- private @TokenizerType int mTokenizerType = TOKENIZER_TYPE_NONE;
- private @JoinableValueType int mJoinableValueType = JOINABLE_VALUE_TYPE_NONE;
+ @Cardinality private int mCardinality = CARDINALITY_OPTIONAL;
+ @IndexingType private int mIndexingType = INDEXING_TYPE_NONE;
+ @TokenizerType private int mTokenizerType = TOKENIZER_TYPE_NONE;
+ @JoinableValueType private int mJoinableValueType = JOINABLE_VALUE_TYPE_NONE;
/** Creates a new {@link StringPropertyConfig.Builder}. */
public Builder(@NonNull String propertyName) {
@@ -627,6 +640,7 @@
* <p>If this method is not called, the default cardinality is
* {@link PropertyConfig#CARDINALITY_OPTIONAL}.
*/
+ @CanIgnoreReturnValue
@SuppressWarnings("MissingGetterMatchingBuilder") // getter defined in superclass
@NonNull
public StringPropertyConfig.Builder setCardinality(@Cardinality int cardinality) {
@@ -643,6 +657,7 @@
* {@link StringPropertyConfig#INDEXING_TYPE_NONE}, so that it cannot be matched by
* queries.
*/
+ @CanIgnoreReturnValue
@NonNull
public StringPropertyConfig.Builder setIndexingType(@IndexingType int indexingType) {
Preconditions.checkArgumentInRange(
@@ -662,6 +677,7 @@
* if {@link #setIndexingType} has been called with a value other than
* {@link StringPropertyConfig#INDEXING_TYPE_NONE}).
*/
+ @CanIgnoreReturnValue
@NonNull
public StringPropertyConfig.Builder setTokenizerType(@TokenizerType int tokenizerType) {
Preconditions.checkArgumentInRange(
@@ -676,6 +692,7 @@
* <p>If this method is not called, the default joinable value type is
* {@link StringPropertyConfig#JOINABLE_VALUE_TYPE_NONE}, so that it is not joinable.
*/
+ @CanIgnoreReturnValue
@NonNull
public StringPropertyConfig.Builder setJoinableValueType(
@JoinableValueType int joinableValueType) {
@@ -807,15 +824,16 @@
}
/** Returns how the property is indexed. */
- public @IndexingType int getIndexingType() {
+ @IndexingType
+ public int getIndexingType() {
return mBundle.getInt(INDEXING_TYPE_FIELD, INDEXING_TYPE_NONE);
}
/** Builder for {@link LongPropertyConfig}. */
public static final class Builder {
private final String mPropertyName;
- private @Cardinality int mCardinality = CARDINALITY_OPTIONAL;
- private @IndexingType int mIndexingType = INDEXING_TYPE_NONE;
+ @Cardinality private int mCardinality = CARDINALITY_OPTIONAL;
+ @IndexingType private int mIndexingType = INDEXING_TYPE_NONE;
/** Creates a new {@link LongPropertyConfig.Builder}. */
public Builder(@NonNull String propertyName) {
@@ -828,6 +846,7 @@
* <p>If this method is not called, the default cardinality is
* {@link PropertyConfig#CARDINALITY_OPTIONAL}.
*/
+ @CanIgnoreReturnValue
@SuppressWarnings("MissingGetterMatchingBuilder") // getter defined in superclass
@NonNull
public LongPropertyConfig.Builder setCardinality(@Cardinality int cardinality) {
@@ -844,6 +863,7 @@
* {@link LongPropertyConfig#INDEXING_TYPE_NONE}, so that it will not be indexed
* and cannot be matched by queries.
*/
+ @CanIgnoreReturnValue
@NonNull
public LongPropertyConfig.Builder setIndexingType(@IndexingType int indexingType) {
Preconditions.checkArgumentInRange(
@@ -895,7 +915,7 @@
/** Builder for {@link DoublePropertyConfig}. */
public static final class Builder {
private final String mPropertyName;
- private @Cardinality int mCardinality = CARDINALITY_OPTIONAL;
+ @Cardinality private int mCardinality = CARDINALITY_OPTIONAL;
/** Creates a new {@link DoublePropertyConfig.Builder}. */
public Builder(@NonNull String propertyName) {
@@ -908,6 +928,7 @@
* <p>If this method is not called, the default cardinality is
* {@link PropertyConfig#CARDINALITY_OPTIONAL}.
*/
+ @CanIgnoreReturnValue
@SuppressWarnings("MissingGetterMatchingBuilder") // getter defined in superclass
@NonNull
public DoublePropertyConfig.Builder setCardinality(@Cardinality int cardinality) {
@@ -938,7 +959,7 @@
/** Builder for {@link BooleanPropertyConfig}. */
public static final class Builder {
private final String mPropertyName;
- private @Cardinality int mCardinality = CARDINALITY_OPTIONAL;
+ @Cardinality private int mCardinality = CARDINALITY_OPTIONAL;
/** Creates a new {@link BooleanPropertyConfig.Builder}. */
public Builder(@NonNull String propertyName) {
@@ -951,6 +972,7 @@
* <p>If this method is not called, the default cardinality is
* {@link PropertyConfig#CARDINALITY_OPTIONAL}.
*/
+ @CanIgnoreReturnValue
@SuppressWarnings("MissingGetterMatchingBuilder") // getter defined in superclass
@NonNull
public BooleanPropertyConfig.Builder setCardinality(@Cardinality int cardinality) {
@@ -981,7 +1003,7 @@
/** Builder for {@link BytesPropertyConfig}. */
public static final class Builder {
private final String mPropertyName;
- private @Cardinality int mCardinality = CARDINALITY_OPTIONAL;
+ @Cardinality private int mCardinality = CARDINALITY_OPTIONAL;
/** Creates a new {@link BytesPropertyConfig.Builder}. */
public Builder(@NonNull String propertyName) {
@@ -994,6 +1016,7 @@
* <p>If this method is not called, the default cardinality is
* {@link PropertyConfig#CARDINALITY_OPTIONAL}.
*/
+ @CanIgnoreReturnValue
@SuppressWarnings("MissingGetterMatchingBuilder") // getter defined in superclass
@NonNull
public BytesPropertyConfig.Builder setCardinality(@Cardinality int cardinality) {
@@ -1047,7 +1070,7 @@
public static final class Builder {
private final String mPropertyName;
private final String mSchemaType;
- private @Cardinality int mCardinality = CARDINALITY_OPTIONAL;
+ @Cardinality private int mCardinality = CARDINALITY_OPTIONAL;
private boolean mShouldIndexNestedProperties = false;
/**
@@ -1071,6 +1094,7 @@
* <p>If this method is not called, the default cardinality is
* {@link PropertyConfig#CARDINALITY_OPTIONAL}.
*/
+ @CanIgnoreReturnValue
@SuppressWarnings("MissingGetterMatchingBuilder") // getter defined in superclass
@NonNull
public DocumentPropertyConfig.Builder setCardinality(@Cardinality int cardinality) {
@@ -1087,6 +1111,7 @@
* <p>If false, the nested document's properties are not indexed regardless of its own
* schema.
*/
+ @CanIgnoreReturnValue
@NonNull
public DocumentPropertyConfig.Builder setShouldIndexNestedProperties(
boolean indexNestedProperties) {
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 5dd5a6c..ca04fab 100644
--- a/appsearch/appsearch/src/main/java/androidx/appsearch/app/GenericDocument.java
+++ b/appsearch/appsearch/src/main/java/androidx/appsearch/app/GenericDocument.java
@@ -25,6 +25,7 @@
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.annotation.RestrictTo;
+import androidx.appsearch.annotation.CanIgnoreReturnValue;
import androidx.appsearch.annotation.Document;
import androidx.appsearch.app.PropertyPath.PathSegment;
import androidx.appsearch.exceptions.AppSearchException;
@@ -1127,6 +1128,7 @@
* <p>The number of namespaces per app should be kept small for efficiency reasons.
* <!--@exportToFramework:hide-->
*/
+ @CanIgnoreReturnValue
@NonNull
public BuilderType setNamespace(@NonNull String namespace) {
Preconditions.checkNotNull(namespace);
@@ -1142,6 +1144,7 @@
* <p>Document IDs are unique within a namespace.
* <!--@exportToFramework:hide-->
*/
+ @CanIgnoreReturnValue
@NonNull
public BuilderType setId(@NonNull String id) {
Preconditions.checkNotNull(id);
@@ -1157,6 +1160,7 @@
* {@link AppSearchSchema} object previously provided to {@link AppSearchSession#setSchemaAsync}.
* <!--@exportToFramework:hide-->
*/
+ @CanIgnoreReturnValue
@NonNull
public BuilderType setSchemaType(@NonNull String schemaType) {
Preconditions.checkNotNull(schemaType);
@@ -1178,6 +1182,7 @@
*
* @param score any non-negative {@code int} representing the document's score.
*/
+ @CanIgnoreReturnValue
@NonNull
public BuilderType setScore(@IntRange(from = 0, to = Integer.MAX_VALUE) int score) {
if (score < 0) {
@@ -1198,6 +1203,7 @@
*
* @param creationTimestampMillis a creation timestamp in milliseconds.
*/
+ @CanIgnoreReturnValue
@NonNull
public BuilderType setCreationTimestampMillis(
/*@exportToFramework:CurrentTimeMillisLong*/ long creationTimestampMillis) {
@@ -1220,6 +1226,7 @@
*
* @param ttlMillis a non-negative duration in milliseconds.
*/
+ @CanIgnoreReturnValue
@NonNull
public BuilderType setTtlMillis(long ttlMillis) {
if (ttlMillis < 0) {
@@ -1241,6 +1248,7 @@
* @throws IllegalArgumentException if no values are provided, or if a passed in
* {@code String} is {@code null} or "".
*/
+ @CanIgnoreReturnValue
@NonNull
public BuilderType setPropertyString(@NonNull String name, @NonNull String... values) {
Preconditions.checkNotNull(name);
@@ -1260,6 +1268,7 @@
* @param values the {@code boolean} values of the property.
* @throws IllegalArgumentException if the name is empty or {@code null}.
*/
+ @CanIgnoreReturnValue
@NonNull
public BuilderType setPropertyBoolean(@NonNull String name, @NonNull boolean... values) {
Preconditions.checkNotNull(name);
@@ -1279,6 +1288,7 @@
* @param values the {@code long} values of the property.
* @throws IllegalArgumentException if the name is empty or {@code null}.
*/
+ @CanIgnoreReturnValue
@NonNull
public BuilderType setPropertyLong(@NonNull String name, @NonNull long... values) {
Preconditions.checkNotNull(name);
@@ -1298,6 +1308,7 @@
* @param values the {@code double} values of the property.
* @throws IllegalArgumentException if the name is empty or {@code null}.
*/
+ @CanIgnoreReturnValue
@NonNull
public BuilderType setPropertyDouble(@NonNull String name, @NonNull double... values) {
Preconditions.checkNotNull(name);
@@ -1317,6 +1328,7 @@
* @throws IllegalArgumentException if no values are provided, or if a passed in
* {@code byte[]} is {@code null}, or if name is empty.
*/
+ @CanIgnoreReturnValue
@NonNull
public BuilderType setPropertyBytes(@NonNull String name, @NonNull byte[]... values) {
Preconditions.checkNotNull(name);
@@ -1338,6 +1350,7 @@
* {@link GenericDocument} is {@code null}, or if name
* is empty.
*/
+ @CanIgnoreReturnValue
@NonNull
public BuilderType setPropertyDocument(
@NonNull String name, @NonNull GenericDocument... values) {
@@ -1356,6 +1369,7 @@
* @param name The name of the property to clear.
* <!--@exportToFramework:hide-->
*/
+ @CanIgnoreReturnValue
@NonNull
public BuilderType clearProperty(@NonNull String name) {
Preconditions.checkNotNull(name);
diff --git a/appsearch/appsearch/src/main/java/androidx/appsearch/app/GetByDocumentIdRequest.java b/appsearch/appsearch/src/main/java/androidx/appsearch/app/GetByDocumentIdRequest.java
index d7ff30b..2bee987 100644
--- a/appsearch/appsearch/src/main/java/androidx/appsearch/app/GetByDocumentIdRequest.java
+++ b/appsearch/appsearch/src/main/java/androidx/appsearch/app/GetByDocumentIdRequest.java
@@ -18,6 +18,7 @@
import androidx.annotation.NonNull;
import androidx.annotation.RestrictTo;
+import androidx.appsearch.annotation.CanIgnoreReturnValue;
import androidx.collection.ArrayMap;
import androidx.collection.ArraySet;
import androidx.core.util.Preconditions;
@@ -134,6 +135,7 @@
}
/** Adds one or more document IDs to the request. */
+ @CanIgnoreReturnValue
@NonNull
public Builder addIds(@NonNull String... ids) {
Preconditions.checkNotNull(ids);
@@ -142,6 +144,7 @@
}
/** Adds a collection of IDs to the request. */
+ @CanIgnoreReturnValue
@NonNull
public Builder addIds(@NonNull Collection<String> ids) {
Preconditions.checkNotNull(ids);
@@ -166,6 +169,7 @@
*
* @see SearchSpec.Builder#addProjectionPaths
*/
+ @CanIgnoreReturnValue
@NonNull
public Builder addProjection(
@NonNull String schemaType, @NonNull Collection<String> propertyPaths) {
@@ -197,6 +201,7 @@
*
* @see SearchSpec.Builder#addProjectionPaths
*/
+ @CanIgnoreReturnValue
@NonNull
public Builder addProjectionPaths(
@NonNull String schemaType, @NonNull Collection<PropertyPath> propertyPaths) {
diff --git a/appsearch/appsearch/src/main/java/androidx/appsearch/app/GetSchemaResponse.java b/appsearch/appsearch/src/main/java/androidx/appsearch/app/GetSchemaResponse.java
index 3475576..b00e904 100644
--- a/appsearch/appsearch/src/main/java/androidx/appsearch/app/GetSchemaResponse.java
+++ b/appsearch/appsearch/src/main/java/androidx/appsearch/app/GetSchemaResponse.java
@@ -24,6 +24,7 @@
import androidx.annotation.Nullable;
import androidx.annotation.RequiresFeature;
import androidx.annotation.RestrictTo;
+import androidx.appsearch.annotation.CanIgnoreReturnValue;
import androidx.collection.ArrayMap;
import androidx.collection.ArraySet;
import androidx.core.util.Preconditions;
@@ -276,6 +277,7 @@
*
* <p>Default version is 0
*/
+ @CanIgnoreReturnValue
@NonNull
public Builder setVersion(@IntRange(from = 0) int version) {
resetIfBuilt();
@@ -284,6 +286,7 @@
}
/** Adds one {@link AppSearchSchema} to the schema list. */
+ @CanIgnoreReturnValue
@NonNull
public Builder addSchema(@NonNull AppSearchSchema schema) {
Preconditions.checkNotNull(schema);
@@ -300,6 +303,7 @@
* {@link GetSchemaResponse}, which won't be displayed by system.
*/
// Getter getSchemaTypesNotDisplayedBySystem returns plural objects.
+ @CanIgnoreReturnValue
@SuppressLint("MissingGetterMatchingBuilder")
@NonNull
public Builder addSchemaTypeNotDisplayedBySystem(@NonNull String schemaType) {
@@ -331,6 +335,7 @@
* schema type.
*/
// Getter getSchemaTypesVisibleToPackages returns a map contains all schema types.
+ @CanIgnoreReturnValue
@SuppressLint("MissingGetterMatchingBuilder")
@NonNull
public Builder setSchemaTypeVisibleToPackages(
@@ -378,6 +383,7 @@
* the given schema.
*/
// Getter getRequiredPermissionsForSchemaTypeVisibility returns a map for all schemaTypes.
+ @CanIgnoreReturnValue
@SuppressLint("MissingGetterMatchingBuilder")
@NonNull
public Builder setRequiredPermissionsForSchemaTypeVisibility(
diff --git a/appsearch/appsearch/src/main/java/androidx/appsearch/app/JoinSpec.java b/appsearch/appsearch/src/main/java/androidx/appsearch/app/JoinSpec.java
index b5dcd55..3cc362d 100644
--- a/appsearch/appsearch/src/main/java/androidx/appsearch/app/JoinSpec.java
+++ b/appsearch/appsearch/src/main/java/androidx/appsearch/app/JoinSpec.java
@@ -21,6 +21,7 @@
import androidx.annotation.IntDef;
import androidx.annotation.NonNull;
import androidx.annotation.RestrictTo;
+import androidx.appsearch.annotation.CanIgnoreReturnValue;
import androidx.core.util.Preconditions;
import java.lang.annotation.Retention;
@@ -204,7 +205,8 @@
*
* @see SearchSpec#RANKING_STRATEGY_JOIN_AGGREGATE_SCORE
*/
- public @AggregationScoringStrategy int getAggregationScoringStrategy() {
+ @AggregationScoringStrategy
+ public int getAggregationScoringStrategy() {
return mBundle.getInt(AGGREGATION_SCORING_STRATEGY);
}
@@ -218,7 +220,7 @@
private SearchSpec mNestedSearchSpec = EMPTY_SEARCH_SPEC;
private final String mChildPropertyExpression;
private int mMaxJoinedResultCount = DEFAULT_MAX_JOINED_RESULT_COUNT;
- private @AggregationScoringStrategy int mAggregationScoringStrategy =
+ @AggregationScoringStrategy private int mAggregationScoringStrategy =
AGGREGATION_SCORING_OUTER_RESULT_RANKING_SIGNAL;
/**
@@ -262,6 +264,7 @@
*/
@SuppressWarnings("MissingGetterMatchingBuilder")
// See getNestedQuery & getNestedSearchSpec
+ @CanIgnoreReturnValue
@NonNull
public Builder setNestedSearch(@NonNull String nestedQuery,
@NonNull SearchSpec nestedSearchSpec) {
@@ -277,6 +280,7 @@
* Sets the max amount of {@link SearchResults} to join to the parent document, with a
* default of 10 SearchResults.
*/
+ @CanIgnoreReturnValue
@NonNull
public Builder setMaxJoinedResultCount(int maxJoinedResultCount) {
mMaxJoinedResultCount = maxJoinedResultCount;
@@ -292,6 +296,7 @@
*
* @see SearchSpec#RANKING_STRATEGY_JOIN_AGGREGATE_SCORE
*/
+ @CanIgnoreReturnValue
@NonNull
public Builder setAggregationScoringStrategy(
@AggregationScoringStrategy int aggregationScoringStrategy) {
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 dff69b2..6edf85e 100644
--- a/appsearch/appsearch/src/main/java/androidx/appsearch/app/PutDocumentsRequest.java
+++ b/appsearch/appsearch/src/main/java/androidx/appsearch/app/PutDocumentsRequest.java
@@ -19,6 +19,7 @@
import android.annotation.SuppressLint;
import androidx.annotation.NonNull;
+import androidx.appsearch.annotation.CanIgnoreReturnValue;
import androidx.appsearch.exceptions.AppSearchException;
import androidx.core.util.Preconditions;
@@ -58,6 +59,7 @@
private boolean mBuilt = false;
/** Adds one or more {@link GenericDocument} objects to the request. */
+ @CanIgnoreReturnValue
@NonNull
public Builder addGenericDocuments(@NonNull GenericDocument... documents) {
Preconditions.checkNotNull(documents);
@@ -66,6 +68,7 @@
}
/** Adds a collection of {@link GenericDocument} objects to the request. */
+ @CanIgnoreReturnValue
@NonNull
public Builder addGenericDocuments(
@NonNull Collection<? extends GenericDocument> documents) {
@@ -87,6 +90,7 @@
*/
// Merged list available from getGenericDocuments()
@SuppressLint("MissingGetterMatchingBuilder")
+ @CanIgnoreReturnValue
@NonNull
public Builder addDocuments(@NonNull Object... documents) throws AppSearchException {
Preconditions.checkNotNull(documents);
@@ -105,6 +109,7 @@
*/
// Merged list available from getGenericDocuments()
@SuppressLint("MissingGetterMatchingBuilder")
+ @CanIgnoreReturnValue
@NonNull
public Builder addDocuments(@NonNull Collection<?> documents) throws AppSearchException {
Preconditions.checkNotNull(documents);
diff --git a/appsearch/appsearch/src/main/java/androidx/appsearch/app/RemoveByDocumentIdRequest.java b/appsearch/appsearch/src/main/java/androidx/appsearch/app/RemoveByDocumentIdRequest.java
index 38be17a..40cd591 100644
--- a/appsearch/appsearch/src/main/java/androidx/appsearch/app/RemoveByDocumentIdRequest.java
+++ b/appsearch/appsearch/src/main/java/androidx/appsearch/app/RemoveByDocumentIdRequest.java
@@ -17,6 +17,7 @@
package androidx.appsearch.app;
import androidx.annotation.NonNull;
+import androidx.appsearch.annotation.CanIgnoreReturnValue;
import androidx.collection.ArraySet;
import androidx.core.util.Preconditions;
@@ -64,6 +65,7 @@
}
/** Adds one or more document IDs to the request. */
+ @CanIgnoreReturnValue
@NonNull
public Builder addIds(@NonNull String... ids) {
Preconditions.checkNotNull(ids);
@@ -72,6 +74,7 @@
}
/** Adds a collection of IDs to the request. */
+ @CanIgnoreReturnValue
@NonNull
public Builder addIds(@NonNull Collection<String> ids) {
Preconditions.checkNotNull(ids);
diff --git a/appsearch/appsearch/src/main/java/androidx/appsearch/app/ReportSystemUsageRequest.java b/appsearch/appsearch/src/main/java/androidx/appsearch/app/ReportSystemUsageRequest.java
index 12422eb..d873a99 100644
--- a/appsearch/appsearch/src/main/java/androidx/appsearch/app/ReportSystemUsageRequest.java
+++ b/appsearch/appsearch/src/main/java/androidx/appsearch/app/ReportSystemUsageRequest.java
@@ -17,6 +17,7 @@
package androidx.appsearch.app;
import androidx.annotation.NonNull;
+import androidx.appsearch.annotation.CanIgnoreReturnValue;
import androidx.core.util.Preconditions;
/**
@@ -123,6 +124,7 @@
* <p>If unset, this defaults to the current timestamp at the time that the
* {@link ReportSystemUsageRequest} is constructed.
*/
+ @CanIgnoreReturnValue
@NonNull
public ReportSystemUsageRequest.Builder setUsageTimestampMillis(
/*@exportToFramework:CurrentTimeMillisLong*/ long usageTimestampMillis) {
diff --git a/appsearch/appsearch/src/main/java/androidx/appsearch/app/ReportUsageRequest.java b/appsearch/appsearch/src/main/java/androidx/appsearch/app/ReportUsageRequest.java
index 14b70c7..567cd40 100644
--- a/appsearch/appsearch/src/main/java/androidx/appsearch/app/ReportUsageRequest.java
+++ b/appsearch/appsearch/src/main/java/androidx/appsearch/app/ReportUsageRequest.java
@@ -17,6 +17,7 @@
package androidx.appsearch.app;
import androidx.annotation.NonNull;
+import androidx.appsearch.annotation.CanIgnoreReturnValue;
import androidx.core.util.Preconditions;
/**
@@ -89,6 +90,7 @@
* <p>If unset, this defaults to the current timestamp at the time that the
* {@link ReportUsageRequest} is constructed.
*/
+ @CanIgnoreReturnValue
@NonNull
public ReportUsageRequest.Builder setUsageTimestampMillis(
/*@exportToFramework:CurrentTimeMillisLong*/ long usageTimestampMillis) {
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 32e4507..efda86b 100644
--- a/appsearch/appsearch/src/main/java/androidx/appsearch/app/SearchResult.java
+++ b/appsearch/appsearch/src/main/java/androidx/appsearch/app/SearchResult.java
@@ -22,6 +22,7 @@
import androidx.annotation.Nullable;
import androidx.annotation.RequiresFeature;
import androidx.annotation.RestrictTo;
+import androidx.appsearch.annotation.CanIgnoreReturnValue;
import androidx.appsearch.exceptions.AppSearchException;
import androidx.core.util.ObjectsCompat;
import androidx.core.util.Preconditions;
@@ -244,6 +245,7 @@
* @throws AppSearchException if an error occurs converting a document class into a
* {@link GenericDocument}.
*/
+ @CanIgnoreReturnValue
@NonNull
public Builder setDocument(@NonNull Object document) throws AppSearchException {
Preconditions.checkNotNull(document);
@@ -253,6 +255,7 @@
// @exportToFramework:endStrip()
/** Sets the document which matched. */
+ @CanIgnoreReturnValue
@NonNull
public Builder setGenericDocument(@NonNull GenericDocument document) {
Preconditions.checkNotNull(document);
@@ -262,6 +265,7 @@
}
/** Adds another match to this SearchResult. */
+ @CanIgnoreReturnValue
@NonNull
public Builder addMatchInfo(@NonNull MatchInfo matchInfo) {
Preconditions.checkState(
@@ -274,6 +278,7 @@
}
/** Sets the ranking signal of the matched document in this SearchResult. */
+ @CanIgnoreReturnValue
@NonNull
public Builder setRankingSignal(double rankingSignal) {
resetIfBuilt();
@@ -285,6 +290,7 @@
* Adds a {@link SearchResult} that was joined by the {@link JoinSpec}.
* @param joinedResult The joined SearchResult to add.
*/
+ @CanIgnoreReturnValue
@NonNull
public Builder addJoinedResult(@NonNull SearchResult joinedResult) {
resetIfBuilt();
@@ -645,6 +651,7 @@
}
/** Sets the exact {@link MatchRange} corresponding to the given entry. */
+ @CanIgnoreReturnValue
@NonNull
public Builder setExactMatchRange(@NonNull MatchRange matchRange) {
mExactMatchRange = Preconditions.checkNotNull(matchRange);
@@ -653,6 +660,7 @@
/** Sets the submatch {@link MatchRange} corresponding to the given entry. */
+ @CanIgnoreReturnValue
@NonNull
public Builder setSubmatchRange(@NonNull MatchRange matchRange) {
mSubmatchRange = Preconditions.checkNotNull(matchRange);
@@ -660,6 +668,7 @@
}
/** Sets the snippet {@link MatchRange} corresponding to the given entry. */
+ @CanIgnoreReturnValue
@NonNull
public Builder setSnippetRange(@NonNull MatchRange matchRange) {
mSnippetRange = Preconditions.checkNotNull(matchRange);
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 9f951fd..e1afd9b 100644
--- a/appsearch/appsearch/src/main/java/androidx/appsearch/app/SearchSpec.java
+++ b/appsearch/appsearch/src/main/java/androidx/appsearch/app/SearchSpec.java
@@ -25,6 +25,7 @@
import androidx.annotation.Nullable;
import androidx.annotation.RequiresFeature;
import androidx.annotation.RestrictTo;
+import androidx.appsearch.annotation.CanIgnoreReturnValue;
import androidx.appsearch.annotation.Document;
import androidx.appsearch.exceptions.AppSearchException;
import androidx.appsearch.util.BundleUtil;
@@ -227,7 +228,8 @@
}
/** Returns how the query terms should match terms in the index. */
- public @TermMatch int getTermMatch() {
+ @TermMatch
+ public int getTermMatch() {
return mBundle.getInt(TERM_MATCH_TYPE_FIELD, -1);
}
@@ -281,12 +283,14 @@
}
/** Returns the ranking strategy. */
- public @RankingStrategy int getRankingStrategy() {
+ @RankingStrategy
+ public int getRankingStrategy() {
return mBundle.getInt(RANKING_STRATEGY_FIELD);
}
/** Returns the order of returned search results (descending or ascending). */
- public @Order int getOrder() {
+ @Order
+ public int getOrder() {
return mBundle.getInt(ORDER_FIELD);
}
@@ -415,7 +419,8 @@
* Get the type of grouping limit to apply, or 0 if {@link Builder#setResultGrouping} was not
* called.
*/
- public @GroupingType int getResultGroupingTypeFlags() {
+ @GroupingType
+ public int getResultGroupingTypeFlags() {
return mBundle.getInt(RESULT_GROUPING_TYPE_FLAGS);
}
@@ -493,13 +498,13 @@
private Bundle mTypePropertyWeights = new Bundle();
private int mResultCountPerPage = DEFAULT_NUM_PER_PAGE;
- private @TermMatch int mTermMatchType = TERM_MATCH_PREFIX;
+ @TermMatch private 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;
+ @RankingStrategy private int mRankingStrategy = RANKING_STRATEGY_NONE;
+ @Order private int mOrder = ORDER_DESCENDING;
+ @GroupingType private int mGroupingTypeFlags = 0;
private int mGroupingLimit = 0;
private JoinSpec mJoinSpec;
private String mAdvancedRankingExpression = "";
@@ -511,6 +516,7 @@
* <p>If this method is not called, the default term match type is
* {@link SearchSpec#TERM_MATCH_PREFIX}.
*/
+ @CanIgnoreReturnValue
@NonNull
public Builder setTermMatch(@TermMatch int termMatchType) {
Preconditions.checkArgumentInRange(termMatchType, TERM_MATCH_EXACT_ONLY,
@@ -526,6 +532,7 @@
*
* <p>If unset, the query will search over all schema types.
*/
+ @CanIgnoreReturnValue
@NonNull
public Builder addFilterSchemas(@NonNull String... schemas) {
Preconditions.checkNotNull(schemas);
@@ -539,6 +546,7 @@
*
* <p>If unset, the query will search over all schema types.
*/
+ @CanIgnoreReturnValue
@NonNull
public Builder addFilterSchemas(@NonNull Collection<String> schemas) {
Preconditions.checkNotNull(schemas);
@@ -558,6 +566,7 @@
* @param documentClasses classes annotated with {@link Document}.
*/
// Merged list available from getFilterSchemas
+ @CanIgnoreReturnValue
@SuppressLint("MissingGetterMatchingBuilder")
@NonNull
public Builder addFilterDocumentClasses(
@@ -586,6 +595,7 @@
* @param documentClasses classes annotated with {@link Document}.
*/
// Merged list available from getFilterSchemas()
+ @CanIgnoreReturnValue
@SuppressLint("MissingGetterMatchingBuilder")
@NonNull
public Builder addFilterDocumentClasses(@NonNull Class<?>... documentClasses)
@@ -601,6 +611,7 @@
* have the specified namespaces.
* <p>If unset, the query will search over all namespaces.
*/
+ @CanIgnoreReturnValue
@NonNull
public Builder addFilterNamespaces(@NonNull String... namespaces) {
Preconditions.checkNotNull(namespaces);
@@ -613,6 +624,7 @@
* have the specified namespaces.
* <p>If unset, the query will search over all namespaces.
*/
+ @CanIgnoreReturnValue
@NonNull
public Builder addFilterNamespaces(@NonNull Collection<String> namespaces) {
Preconditions.checkNotNull(namespaces);
@@ -629,6 +641,7 @@
* If package names are specified which caller doesn't have access to, then those package
* names will be ignored.
*/
+ @CanIgnoreReturnValue
@NonNull
public Builder addFilterPackageNames(@NonNull String... packageNames) {
Preconditions.checkNotNull(packageNames);
@@ -644,6 +657,7 @@
* If package names are specified which caller doesn't have access to, then those package
* names will be ignored.
*/
+ @CanIgnoreReturnValue
@NonNull
public Builder addFilterPackageNames(@NonNull Collection<String> packageNames) {
Preconditions.checkNotNull(packageNames);
@@ -657,6 +671,7 @@
*
* <p>The default number of results per page is 10.
*/
+ @CanIgnoreReturnValue
@NonNull
public SearchSpec.Builder setResultCountPerPage(
@IntRange(from = 0, to = MAX_NUM_PER_PAGE) int resultCountPerPage) {
@@ -668,6 +683,7 @@
}
/** Sets ranking strategy for AppSearch results. */
+ @CanIgnoreReturnValue
@NonNull
public Builder setRankingStrategy(@RankingStrategy int rankingStrategy) {
Preconditions.checkArgumentInRange(rankingStrategy, RANKING_STRATEGY_NONE,
@@ -768,13 +784,14 @@
* </ul>
*
* <p>Syntax errors and type errors will fail the entire search and will cause
- * {@link SearchResults#getNextPageAsync()} to throw an {@link AppSearchException}.
+ * {@link SearchResults#getNextPageAsync} to throw an {@link AppSearchException}.
* <p>Evaluation errors will result in the offending documents receiving the default score.
* For {@link #ORDER_DESCENDING}, the default score will be 0, for
* {@link #ORDER_ASCENDING} the default score will be infinity.
*
* @param advancedRankingExpression a non-empty string representing the ranking expression.
*/
+ @CanIgnoreReturnValue
@NonNull
// @exportToFramework:startStrip()
@RequiresFeature(
@@ -795,6 +812,7 @@
*
* <p>This order field will be ignored if RankingStrategy = {@code RANKING_STRATEGY_NONE}.
*/
+ @CanIgnoreReturnValue
@NonNull
public Builder setOrder(@Order int order) {
Preconditions.checkArgumentInRange(order, ORDER_DESCENDING, ORDER_ASCENDING,
@@ -814,6 +832,7 @@
* <p>If set to 0 (default), snippeting is disabled and the list returned from
* {@link SearchResult#getMatchInfos} will be empty.
*/
+ @CanIgnoreReturnValue
@NonNull
public SearchSpec.Builder setSnippetCount(
@IntRange(from = 0, to = MAX_SNIPPET_COUNT) int snippetCount) {
@@ -834,6 +853,7 @@
* <p>The default behavior is to snippet all matches a property contains, up to the maximum
* value of 10,000.
*/
+ @CanIgnoreReturnValue
@NonNull
public SearchSpec.Builder setSnippetCountPerProperty(
@IntRange(from = 0, to = MAX_SNIPPET_PER_PROPERTY_COUNT)
@@ -857,6 +877,7 @@
* <p>Ex. {@code maxSnippetSize} = 16. "foo bar baz bat rat" with a query of "baz" will
* return a window of "bar baz bat" which is only 11 bytes long.
*/
+ @CanIgnoreReturnValue
@NonNull
public SearchSpec.Builder setMaxSnippetSize(
@IntRange(from = 0, to = MAX_SNIPPET_SIZE_LIMIT) int maxSnippetSize) {
@@ -878,6 +899,7 @@
* @param schema a string corresponding to the schema to add projections to.
* @param propertyPaths the projections to add.
*/
+ @CanIgnoreReturnValue
@NonNull
public SearchSpec.Builder addProjection(
@NonNull String schema, @NonNull Collection<String> propertyPaths) {
@@ -956,6 +978,7 @@
* @param schema a string corresponding to the schema to add projections to.
* @param propertyPaths the projections to add.
*/
+ @CanIgnoreReturnValue
@NonNull
public SearchSpec.Builder addProjectionPaths(
@NonNull String schema, @NonNull Collection<PropertyPath> propertyPaths) {
@@ -981,6 +1004,7 @@
* add projections to.
* @param propertyPaths the projections to add.
*/
+ @CanIgnoreReturnValue
@SuppressLint("MissingGetterMatchingBuilder") // Projections available from getProjections
@NonNull
public SearchSpec.Builder addProjectionsForDocumentClass(
@@ -1001,6 +1025,7 @@
* add projections to.
* @param propertyPaths the projections to add.
*/
+ @CanIgnoreReturnValue
@SuppressLint("MissingGetterMatchingBuilder") // Projections available from getProjections
@NonNull
public SearchSpec.Builder addProjectionPathsForDocumentClass(
@@ -1034,6 +1059,7 @@
*/
// Individual parameters available from getResultGroupingTypeFlags and
// getResultGroupingLimit
+ @CanIgnoreReturnValue
@SuppressLint("MissingGetterMatchingBuilder")
@NonNull
public Builder setResultGrouping(@GroupingType int groupingTypeFlags, int limit) {
@@ -1076,6 +1102,7 @@
* @throws IllegalArgumentException if a weight is equal to or less than 0.0.
*/
// @exportToFramework:startStrip()
+ @CanIgnoreReturnValue
@RequiresFeature(
enforcement = "androidx.appsearch.app.Features#isFeatureSupported",
name = Features.SEARCH_SPEC_PROPERTY_WEIGHTS)
@@ -1110,6 +1137,7 @@
* @param joinSpec a specification on how to perform the Join operation.
*/
// @exportToFramework:startStrip()
+ @CanIgnoreReturnValue
@RequiresFeature(
enforcement = "androidx.appsearch.app.Features#isFeatureSupported",
name = Features.JOIN_SPEC_AND_QUALIFIED_ID)
@@ -1152,6 +1180,7 @@
* @throws IllegalArgumentException if a weight is equal to or less than 0.0.
*/
// @exportToFramework:startStrip()
+ @CanIgnoreReturnValue
@RequiresFeature(
enforcement = "androidx.appsearch.app.Features#isFeatureSupported",
name = Features.SEARCH_SPEC_PROPERTY_WEIGHTS)
@@ -1206,6 +1235,7 @@
* classpath
* @throws IllegalArgumentException if a weight is equal to or less than 0.0.
*/
+ @CanIgnoreReturnValue
@SuppressLint("MissingGetterMatchingBuilder")
@RequiresFeature(
enforcement = "androidx.appsearch.app.Features#isFeatureSupported",
@@ -1253,6 +1283,7 @@
* classpath
* @throws IllegalArgumentException if a weight is equal to or less than 0.0.
*/
+ @CanIgnoreReturnValue
@SuppressLint("MissingGetterMatchingBuilder")
@RequiresFeature(
enforcement = "androidx.appsearch.app.Features#isFeatureSupported",
diff --git a/appsearch/appsearch/src/main/java/androidx/appsearch/app/SearchSuggestionResult.java b/appsearch/appsearch/src/main/java/androidx/appsearch/app/SearchSuggestionResult.java
index 2fea497..6f6d1cb 100644
--- a/appsearch/appsearch/src/main/java/androidx/appsearch/app/SearchSuggestionResult.java
+++ b/appsearch/appsearch/src/main/java/androidx/appsearch/app/SearchSuggestionResult.java
@@ -21,6 +21,7 @@
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.annotation.RestrictTo;
+import androidx.appsearch.annotation.CanIgnoreReturnValue;
import androidx.appsearch.util.BundleUtil;
import androidx.core.util.Preconditions;
@@ -92,6 +93,7 @@
*
* <p>The suggested result should only contain lowercase or special characters.
*/
+ @CanIgnoreReturnValue
@NonNull
public Builder setSuggestedResult(@NonNull String suggestedResult) {
Preconditions.checkNotNull(suggestedResult);
diff --git a/appsearch/appsearch/src/main/java/androidx/appsearch/app/SearchSuggestionSpec.java b/appsearch/appsearch/src/main/java/androidx/appsearch/app/SearchSuggestionSpec.java
index b195591..d527a88 100644
--- a/appsearch/appsearch/src/main/java/androidx/appsearch/app/SearchSuggestionSpec.java
+++ b/appsearch/appsearch/src/main/java/androidx/appsearch/app/SearchSuggestionSpec.java
@@ -24,6 +24,7 @@
import androidx.annotation.IntRange;
import androidx.annotation.NonNull;
import androidx.annotation.RestrictTo;
+import androidx.appsearch.annotation.CanIgnoreReturnValue;
import androidx.appsearch.annotation.Document;
import androidx.appsearch.exceptions.AppSearchException;
import androidx.appsearch.util.BundleUtil;
@@ -45,7 +46,7 @@
* This class represents the specification logic for AppSearch. It can be used to set the filter
* and settings of search a suggestions.
*
- * @see AppSearchSession#searchSuggestionAsync(String, SearchSuggestionSpec)
+ * @see AppSearchSession#searchSuggestionAsync
*/
public class SearchSuggestionSpec {
static final String NAMESPACE_FIELD = "namespace";
@@ -143,7 +144,8 @@
}
/** Returns the ranking strategy. */
- public @SuggestionRankingStrategy int getRankingStrategy() {
+ @SuggestionRankingStrategy
+ public int getRankingStrategy() {
return mBundle.getInt(RANKING_STRATEGY_FIELD);
}
@@ -222,7 +224,7 @@
private Bundle mTypePropertyFilters = new Bundle();
private Bundle mDocumentIds = new Bundle();
private final int mTotalResultCount;
- private @SuggestionRankingStrategy int mRankingStrategy =
+ @SuggestionRankingStrategy private int mRankingStrategy =
SUGGESTION_RANKING_STRATEGY_DOCUMENT_COUNT;
private boolean mBuilt = false;
@@ -243,6 +245,7 @@
*
* <p>If unset, the query will search over all namespaces.
*/
+ @CanIgnoreReturnValue
@NonNull
public Builder addFilterNamespaces(@NonNull String... namespaces) {
Preconditions.checkNotNull(namespaces);
@@ -256,6 +259,7 @@
*
* <p>If unset, the query will search over all namespaces.
*/
+ @CanIgnoreReturnValue
@NonNull
public Builder addFilterNamespaces(@NonNull Collection<String> namespaces) {
Preconditions.checkNotNull(namespaces);
@@ -270,6 +274,7 @@
* <p>The default value {@link #SUGGESTION_RANKING_STRATEGY_DOCUMENT_COUNT} will be used if
* this method is never called.
*/
+ @CanIgnoreReturnValue
@NonNull
public Builder setRankingStrategy(@SuggestionRankingStrategy int rankingStrategy) {
Preconditions.checkArgumentInRange(rankingStrategy,
@@ -286,6 +291,7 @@
*
* <p>If unset, the query will search over all schema.
*/
+ @CanIgnoreReturnValue
@NonNull
public Builder addFilterSchemas(@NonNull String... schemaTypes) {
Preconditions.checkNotNull(schemaTypes);
@@ -299,6 +305,7 @@
*
* <p>If unset, the query will search over all schema.
*/
+ @CanIgnoreReturnValue
@NonNull
public Builder addFilterSchemas(@NonNull Collection<String> schemaTypes) {
Preconditions.checkNotNull(schemaTypes);
@@ -319,6 +326,7 @@
*/
// Merged list available from getFilterSchemas()
@SuppressLint("MissingGetterMatchingBuilder")
+ @CanIgnoreReturnValue
@NonNull
public Builder addFilterDocumentClasses(@NonNull Class<?>... documentClasses)
throws AppSearchException {
@@ -341,6 +349,7 @@
*/
// Merged list available from getFilterSchemas
@SuppressLint("MissingGetterMatchingBuilder")
+ @CanIgnoreReturnValue
@NonNull
public Builder addFilterDocumentClasses(
@NonNull Collection<? extends Class<?>> documentClasses) throws AppSearchException {
@@ -496,6 +505,7 @@
*
* <p>If unset, the query will search over all documents.
*/
+ @CanIgnoreReturnValue
@NonNull
public Builder addFilterDocumentIds(@NonNull String namespace,
@NonNull String... documentIds) {
@@ -511,6 +521,7 @@
*
* <p>If unset, the query will search over all documents.
*/
+ @CanIgnoreReturnValue
@NonNull
public Builder addFilterDocumentIds(@NonNull String namespace,
@NonNull Collection<String> documentIds) {
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 52e953a..07387df 100644
--- a/appsearch/appsearch/src/main/java/androidx/appsearch/app/SetSchemaRequest.java
+++ b/appsearch/appsearch/src/main/java/androidx/appsearch/app/SetSchemaRequest.java
@@ -23,6 +23,7 @@
import androidx.annotation.NonNull;
import androidx.annotation.RequiresFeature;
import androidx.annotation.RestrictTo;
+import androidx.appsearch.annotation.CanIgnoreReturnValue;
import androidx.appsearch.exceptions.AppSearchException;
import androidx.collection.ArrayMap;
import androidx.collection.ArraySet;
@@ -318,6 +319,7 @@
*
* <p>Any documents of these types will be displayed on system UI surfaces by default.
*/
+ @CanIgnoreReturnValue
@NonNull
public Builder addSchemas(@NonNull AppSearchSchema... schemas) {
Preconditions.checkNotNull(schemas);
@@ -330,6 +332,7 @@
*
* <p>An {@link AppSearchSchema} object represents one type of structured data.
*/
+ @CanIgnoreReturnValue
@NonNull
public Builder addSchemas(@NonNull Collection<AppSearchSchema> schemas) {
Preconditions.checkNotNull(schemas);
@@ -348,6 +351,7 @@
* @throws AppSearchException if {@code androidx.appsearch.compiler.AppSearchCompiler}
* has not generated a schema for the given document classes.
*/
+ @CanIgnoreReturnValue
@SuppressLint("MissingGetterMatchingBuilder") // Merged list available from getSchemas()
@NonNull
public Builder addDocumentClasses(@NonNull Class<?>... documentClasses)
@@ -366,6 +370,7 @@
* @throws AppSearchException if {@code androidx.appsearch.compiler.AppSearchCompiler}
* has not generated a schema for the given document classes.
*/
+ @CanIgnoreReturnValue
@SuppressLint("MissingGetterMatchingBuilder") // Merged list available from getSchemas()
@NonNull
public Builder addDocumentClasses(@NonNull Collection<? extends Class<?>> documentClasses)
@@ -397,6 +402,7 @@
* @param displayed Whether documents of this type will be displayed on system UI surfaces.
*/
// Merged list available from getSchemasNotDisplayedBySystem
+ @CanIgnoreReturnValue
@SuppressLint("MissingGetterMatchingBuilder")
@NonNull
public Builder setSchemaTypeDisplayedBySystem(
@@ -438,6 +444,7 @@
* @throws IllegalArgumentException – if input unsupported permission.
*/
// Merged list available from getRequiredPermissionsForSchemaTypeVisibility
+ @CanIgnoreReturnValue
@SuppressLint("MissingGetterMatchingBuilder")
// @exportToFramework:startStrip()
@RequiresFeature(
@@ -465,6 +472,7 @@
/** Clears all required permissions combinations for the given schema type. */
// @exportToFramework:startStrip()
+ @CanIgnoreReturnValue
@RequiresFeature(
enforcement = "androidx.appsearch.app.Features#isFeatureSupported",
name = Features.ADD_PERMISSIONS_AND_GET_VISIBILITY)
@@ -498,6 +506,7 @@
* @param packageIdentifier Represents the package that will be granted visibility.
*/
// Merged list available from getSchemasVisibleToPackages
+ @CanIgnoreReturnValue
@SuppressLint("MissingGetterMatchingBuilder")
@NonNull
public Builder setSchemaTypeVisibilityForPackage(
@@ -553,6 +562,7 @@
* @see SetSchemaRequest.Builder#addSchemas
* @see AppSearchSession#setSchemaAsync
*/
+ @CanIgnoreReturnValue
@NonNull
@SuppressLint("MissingGetterMatchingBuilder") // Getter return plural objects.
public Builder setMigrator(@NonNull String schemaType, @NonNull Migrator migrator) {
@@ -588,6 +598,7 @@
* @see SetSchemaRequest.Builder#addSchemas
* @see AppSearchSession#setSchemaAsync
*/
+ @CanIgnoreReturnValue
@NonNull
public Builder setMigrators(@NonNull Map<String, Migrator> migrators) {
Preconditions.checkNotNull(migrators);
@@ -619,6 +630,7 @@
* has not generated a schema for the given document class.
*/
// Merged list available from getSchemasNotDisplayedBySystem
+ @CanIgnoreReturnValue
@SuppressLint("MissingGetterMatchingBuilder")
@NonNull
public Builder setDocumentClassDisplayedBySystem(@NonNull Class<?> documentClass,
@@ -655,6 +667,7 @@
* has not generated a schema for the given document class.
*/
// Merged list available from getSchemasVisibleToPackages
+ @CanIgnoreReturnValue
@SuppressLint("MissingGetterMatchingBuilder")
@NonNull
public Builder setDocumentClassVisibilityForPackage(@NonNull Class<?> documentClass,
@@ -696,6 +709,7 @@
* @throws IllegalArgumentException – if input unsupported permission.
*/
// Merged map available from getRequiredPermissionsForSchemaTypeVisibility
+ @CanIgnoreReturnValue
@SuppressLint("MissingGetterMatchingBuilder")
@RequiresFeature(
enforcement = "androidx.appsearch.app.Features#isFeatureSupported",
@@ -714,6 +728,7 @@
}
/** Clears all required permissions combinations for the given schema type. */
+ @CanIgnoreReturnValue
@RequiresFeature(
enforcement = "androidx.appsearch.app.Features#isFeatureSupported",
name = Features.ADD_PERMISSIONS_AND_GET_VISIBILITY)
@@ -740,6 +755,7 @@
*
* <p>By default, this is {@code false}.
*/
+ @CanIgnoreReturnValue
@NonNull
public Builder setForceOverride(boolean forceOverride) {
resetIfBuilt();
@@ -775,6 +791,7 @@
* @see Migrator
* @see SetSchemaRequest.Builder#setMigrator
*/
+ @CanIgnoreReturnValue
@NonNull
public Builder setVersion(@IntRange(from = 1) int version) {
Preconditions.checkArgument(version >= 1, "Version must be a positive number.");
diff --git a/appsearch/appsearch/src/main/java/androidx/appsearch/app/SetSchemaResponse.java b/appsearch/appsearch/src/main/java/androidx/appsearch/app/SetSchemaResponse.java
index 3f8ce5e..ade162c 100644
--- a/appsearch/appsearch/src/main/java/androidx/appsearch/app/SetSchemaResponse.java
+++ b/appsearch/appsearch/src/main/java/androidx/appsearch/app/SetSchemaResponse.java
@@ -21,6 +21,7 @@
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.annotation.RestrictTo;
+import androidx.appsearch.annotation.CanIgnoreReturnValue;
import androidx.collection.ArraySet;
import androidx.core.util.Preconditions;
@@ -182,6 +183,7 @@
private boolean mBuilt = false;
/** Adds {@link MigrationFailure}s to the list of migration failures. */
+ @CanIgnoreReturnValue
@NonNull
public Builder addMigrationFailures(
@NonNull Collection<MigrationFailure> migrationFailures) {
@@ -192,6 +194,7 @@
}
/** Adds a {@link MigrationFailure} to the list of migration failures. */
+ @CanIgnoreReturnValue
@NonNull
public Builder addMigrationFailure(@NonNull MigrationFailure migrationFailure) {
Preconditions.checkNotNull(migrationFailure);
@@ -201,6 +204,7 @@
}
/** Adds deletedTypes to the list of deleted schema types. */
+ @CanIgnoreReturnValue
@NonNull
public Builder addDeletedTypes(@NonNull Collection<String> deletedTypes) {
Preconditions.checkNotNull(deletedTypes);
@@ -210,6 +214,7 @@
}
/** Adds one deletedType to the list of deleted schema types. */
+ @CanIgnoreReturnValue
@NonNull
public Builder addDeletedType(@NonNull String deletedType) {
Preconditions.checkNotNull(deletedType);
@@ -219,6 +224,7 @@
}
/** Adds incompatibleTypes to the list of incompatible schema types. */
+ @CanIgnoreReturnValue
@NonNull
public Builder addIncompatibleTypes(@NonNull Collection<String> incompatibleTypes) {
Preconditions.checkNotNull(incompatibleTypes);
@@ -228,6 +234,7 @@
}
/** Adds one incompatibleType to the list of incompatible schema types. */
+ @CanIgnoreReturnValue
@NonNull
public Builder addIncompatibleType(@NonNull String incompatibleType) {
Preconditions.checkNotNull(incompatibleType);
@@ -237,6 +244,7 @@
}
/** Adds migratedTypes to the list of migrated schema types. */
+ @CanIgnoreReturnValue
@NonNull
public Builder addMigratedTypes(@NonNull Collection<String> migratedTypes) {
Preconditions.checkNotNull(migratedTypes);
@@ -246,6 +254,7 @@
}
/** Adds one migratedType to the list of migrated schema types. */
+ @CanIgnoreReturnValue
@NonNull
public Builder addMigratedType(@NonNull String migratedType) {
Preconditions.checkNotNull(migratedType);
diff --git a/appsearch/appsearch/src/main/java/androidx/appsearch/app/StorageInfo.java b/appsearch/appsearch/src/main/java/androidx/appsearch/app/StorageInfo.java
index 0d7901d..5778bf8 100644
--- a/appsearch/appsearch/src/main/java/androidx/appsearch/app/StorageInfo.java
+++ b/appsearch/appsearch/src/main/java/androidx/appsearch/app/StorageInfo.java
@@ -20,6 +20,7 @@
import androidx.annotation.NonNull;
import androidx.annotation.RestrictTo;
+import androidx.appsearch.annotation.CanIgnoreReturnValue;
import androidx.core.util.Preconditions;
/** The response class of {@code AppSearchSession#getStorageInfo}. */
@@ -78,6 +79,7 @@
private int mAliveNamespacesCount;
/** Sets the size in bytes. */
+ @CanIgnoreReturnValue
@NonNull
public StorageInfo.Builder setSizeBytes(long sizeBytes) {
mSizeBytes = sizeBytes;
@@ -85,6 +87,7 @@
}
/** Sets the number of alive documents. */
+ @CanIgnoreReturnValue
@NonNull
public StorageInfo.Builder setAliveDocumentsCount(int aliveDocumentsCount) {
mAliveDocumentsCount = aliveDocumentsCount;
@@ -92,6 +95,7 @@
}
/** Sets the number of alive namespaces. */
+ @CanIgnoreReturnValue
@NonNull
public StorageInfo.Builder setAliveNamespacesCount(int aliveNamespacesCount) {
mAliveNamespacesCount = aliveNamespacesCount;
diff --git a/appsearch/appsearch/src/main/java/androidx/appsearch/app/VisibilityDocument.java b/appsearch/appsearch/src/main/java/androidx/appsearch/app/VisibilityDocument.java
index fd79bd6..86053b0 100644
--- a/appsearch/appsearch/src/main/java/androidx/appsearch/app/VisibilityDocument.java
+++ b/appsearch/appsearch/src/main/java/androidx/appsearch/app/VisibilityDocument.java
@@ -20,6 +20,7 @@
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.annotation.RestrictTo;
+import androidx.appsearch.annotation.CanIgnoreReturnValue;
import androidx.collection.ArraySet;
import androidx.core.util.Preconditions;
@@ -162,6 +163,7 @@
}
/** Sets whether this schema has opted out of platform surfacing. */
+ @CanIgnoreReturnValue
@NonNull
public Builder setNotDisplayedBySystem(boolean notDisplayedBySystem) {
return setPropertyBoolean(NOT_DISPLAYED_BY_SYSTEM_PROPERTY,
@@ -169,6 +171,7 @@
}
/** Add {@link PackageIdentifier} of packages which has access to this schema. */
+ @CanIgnoreReturnValue
@NonNull
public Builder addVisibleToPackages(@NonNull Set<PackageIdentifier> packageIdentifiers) {
Preconditions.checkNotNull(packageIdentifiers);
@@ -177,6 +180,7 @@
}
/** Add {@link PackageIdentifier} of packages which has access to this schema. */
+ @CanIgnoreReturnValue
@NonNull
public Builder addVisibleToPackage(@NonNull PackageIdentifier packageIdentifier) {
Preconditions.checkNotNull(packageIdentifier);
@@ -191,6 +195,7 @@
* <p> The querier could have access if they holds ALL required permissions of ANY of the
* individual value sets.
*/
+ @CanIgnoreReturnValue
@NonNull
public Builder setVisibleToPermissions(@NonNull Set<Set<Integer>> visibleToPermissions) {
Preconditions.checkNotNull(visibleToPermissions);
diff --git a/appsearch/appsearch/src/main/java/androidx/appsearch/app/VisibilityPermissionDocument.java b/appsearch/appsearch/src/main/java/androidx/appsearch/app/VisibilityPermissionDocument.java
index e859cb9..b8adf9a 100644
--- a/appsearch/appsearch/src/main/java/androidx/appsearch/app/VisibilityPermissionDocument.java
+++ b/appsearch/appsearch/src/main/java/androidx/appsearch/app/VisibilityPermissionDocument.java
@@ -19,6 +19,7 @@
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.annotation.RestrictTo;
+import androidx.appsearch.annotation.CanIgnoreReturnValue;
import androidx.collection.ArraySet;
import java.util.Set;
@@ -76,6 +77,7 @@
}
/** Sets whether this schema has opted out of platform surfacing. */
+ @CanIgnoreReturnValue
@NonNull
public Builder setVisibleToAllRequiredPermissions(
@NonNull Set<Integer> allRequiredPermissions) {
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 98689f5..2930d2d 100644
--- a/appsearch/appsearch/src/main/java/androidx/appsearch/exceptions/AppSearchException.java
+++ b/appsearch/appsearch/src/main/java/androidx/appsearch/exceptions/AppSearchException.java
@@ -73,7 +73,8 @@
*
* @return One of the constants documented in {@link AppSearchResult#getResultCode}.
*/
- public @AppSearchResult.ResultCode int getResultCode() {
+ @AppSearchResult.ResultCode
+ public int getResultCode() {
return mResultCode;
}
diff --git a/appsearch/appsearch/src/main/java/androidx/appsearch/observer/ObserverSpec.java b/appsearch/appsearch/src/main/java/androidx/appsearch/observer/ObserverSpec.java
index 6e3705e..dc9d83f 100644
--- a/appsearch/appsearch/src/main/java/androidx/appsearch/observer/ObserverSpec.java
+++ b/appsearch/appsearch/src/main/java/androidx/appsearch/observer/ObserverSpec.java
@@ -22,6 +22,7 @@
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.annotation.RestrictTo;
+import androidx.appsearch.annotation.CanIgnoreReturnValue;
import androidx.appsearch.annotation.Document;
import androidx.appsearch.app.DocumentClassFactory;
import androidx.appsearch.app.DocumentClassFactoryRegistry;
@@ -96,6 +97,7 @@
*
* <p>If unset, the observer will match documents of all types.
*/
+ @CanIgnoreReturnValue
@NonNull
public Builder addFilterSchemas(@NonNull String... schemas) {
Preconditions.checkNotNull(schemas);
@@ -109,6 +111,7 @@
*
* <p>If unset, the observer will match documents of all types.
*/
+ @CanIgnoreReturnValue
@NonNull
public Builder addFilterSchemas(@NonNull Collection<String> schemas) {
Preconditions.checkNotNull(schemas);
@@ -128,6 +131,7 @@
*/
// Merged list available from getFilterSchemas()
@SuppressLint("MissingGetterMatchingBuilder")
+ @CanIgnoreReturnValue
@NonNull
public Builder addFilterDocumentClasses(@NonNull Class<?>... documentClasses)
throws AppSearchException {
@@ -146,6 +150,7 @@
*/
// Merged list available from getFilterSchemas
@SuppressLint("MissingGetterMatchingBuilder")
+ @CanIgnoreReturnValue
@NonNull
public Builder addFilterDocumentClasses(
@NonNull Collection<? extends Class<?>> documentClasses) throws AppSearchException {
diff --git a/appsearch/appsearch/src/main/java/androidx/appsearch/stats/SchemaMigrationStats.java b/appsearch/appsearch/src/main/java/androidx/appsearch/stats/SchemaMigrationStats.java
index 3cff1133..48d5b23 100644
--- a/appsearch/appsearch/src/main/java/androidx/appsearch/stats/SchemaMigrationStats.java
+++ b/appsearch/appsearch/src/main/java/androidx/appsearch/stats/SchemaMigrationStats.java
@@ -21,6 +21,7 @@
import androidx.annotation.IntDef;
import androidx.annotation.NonNull;
import androidx.annotation.RestrictTo;
+import androidx.appsearch.annotation.CanIgnoreReturnValue;
import androidx.appsearch.app.AppSearchResult;
import androidx.appsearch.app.SetSchemaRequest;
import androidx.appsearch.util.BundleUtil;
@@ -220,6 +221,7 @@
}
/** Sets status code for the schema migration action. */
+ @CanIgnoreReturnValue
@NonNull
public Builder setStatusCode(@AppSearchResult.ResultCode int statusCode) {
mBundle.putInt(STATUS_CODE_FIELD, statusCode);
@@ -227,6 +229,7 @@
}
/** Sets the latency for waiting the executor. */
+ @CanIgnoreReturnValue
@NonNull
public Builder setExecutorAcquisitionLatencyMillis(int executorAcquisitionLatencyMillis) {
mBundle.putInt(EXECUTOR_ACQUISITION_MILLIS_FIELD, executorAcquisitionLatencyMillis);
@@ -235,6 +238,7 @@
/** Sets total latency for the schema migration action in milliseconds. */
+ @CanIgnoreReturnValue
@NonNull
public Builder setTotalLatencyMillis(int totalLatencyMillis) {
mBundle.putInt(TOTAL_LATENCY_MILLIS_FIELD, totalLatencyMillis);
@@ -242,6 +246,7 @@
}
/** Sets latency for the GetSchema action in milliseconds. */
+ @CanIgnoreReturnValue
@NonNull
public Builder setGetSchemaLatencyMillis(int getSchemaLatencyMillis) {
mBundle.putInt(GET_SCHEMA_LATENCY_MILLIS_FIELD, getSchemaLatencyMillis);
@@ -252,6 +257,7 @@
* Sets latency for querying all documents that need to be migrated to new version and
* transforming documents to new version in milliseconds.
*/
+ @CanIgnoreReturnValue
@NonNull
public Builder setQueryAndTransformLatencyMillis(
int queryAndTransformLatencyMillis) {
@@ -261,6 +267,7 @@
}
/** Sets latency of first SetSchema action in milliseconds. */
+ @CanIgnoreReturnValue
@NonNull
public Builder setFirstSetSchemaLatencyMillis(
int firstSetSchemaLatencyMillis) {
@@ -269,6 +276,7 @@
}
/** Returns status of the first SetSchema action. */
+ @CanIgnoreReturnValue
@NonNull
public Builder setIsFirstSetSchemaSuccess(boolean isFirstSetSchemaSuccess) {
mBundle.putBoolean(IS_FIRST_SET_SCHEMA_SUCCESS_FIELD, isFirstSetSchemaSuccess);
@@ -276,6 +284,7 @@
}
/** Sets latency of second SetSchema action in milliseconds. */
+ @CanIgnoreReturnValue
@NonNull
public Builder setSecondSetSchemaLatencyMillis(
int secondSetSchemaLatencyMillis) {
@@ -284,6 +293,7 @@
}
/** Sets latency for putting migrated document to Icing lib in milliseconds. */
+ @CanIgnoreReturnValue
@NonNull
public Builder setSaveDocumentLatencyMillis(
int saveDocumentLatencyMillis) {
@@ -292,6 +302,7 @@
}
/** Sets number of document that need to be migrated to another version. */
+ @CanIgnoreReturnValue
@NonNull
public Builder setTotalNeedMigratedDocumentCount(int migratedDocumentCount) {
mBundle.putInt(TOTAL_NEED_MIGRATED_DOCUMENT_COUNT_FIELD, migratedDocumentCount);
@@ -299,6 +310,7 @@
}
/** Sets total document count of successfully migrated and saved in Icing. */
+ @CanIgnoreReturnValue
@NonNull
public Builder setTotalSuccessMigratedDocumentCount(
int totalSuccessMigratedDocumentCount) {
@@ -308,6 +320,7 @@
}
/** Sets number of {@link androidx.appsearch.app.SetSchemaResponse.MigrationFailure}. */
+ @CanIgnoreReturnValue
@NonNull
public Builder setMigrationFailureCount(int migrationFailureCount) {
mBundle.putInt(MIGRATION_FAILURE_COUNT_FIELD, migrationFailureCount);
diff --git a/appsearch/appsearch/src/main/java/androidx/appsearch/util/IndentingStringBuilder.java b/appsearch/appsearch/src/main/java/androidx/appsearch/util/IndentingStringBuilder.java
index ea5717e..20ef8fa 100644
--- a/appsearch/appsearch/src/main/java/androidx/appsearch/util/IndentingStringBuilder.java
+++ b/appsearch/appsearch/src/main/java/androidx/appsearch/util/IndentingStringBuilder.java
@@ -18,6 +18,7 @@
import androidx.annotation.NonNull;
import androidx.annotation.RestrictTo;
+import androidx.appsearch.annotation.CanIgnoreReturnValue;
/**
* Utility for building indented strings.
@@ -41,6 +42,7 @@
/**
* Increases the indent level by one for appended strings.
*/
+ @CanIgnoreReturnValue
@NonNull
public IndentingStringBuilder increaseIndentLevel() {
mIndentLevel++;
@@ -50,6 +52,7 @@
/**
* Decreases the indent level by one for appended strings.
*/
+ @CanIgnoreReturnValue
@NonNull
public IndentingStringBuilder decreaseIndentLevel() throws IllegalStateException {
if (mIndentLevel == 0) {
@@ -64,6 +67,7 @@
*
* <p>Indentation is applied after each newline character.
*/
+ @CanIgnoreReturnValue
@NonNull
public IndentingStringBuilder append(@NonNull String str) {
applyIndentToString(str);
@@ -76,6 +80,7 @@
*
* <p>Indentation is applied after each newline character.
*/
+ @CanIgnoreReturnValue
@NonNull
public IndentingStringBuilder append(@NonNull Object obj) {
applyIndentToString(obj.toString());
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 a80f718..c5e6703 100644
--- a/appsearch/compiler/src/main/java/androidx/appsearch/compiler/SchemaCodeGenerator.java
+++ b/appsearch/compiler/src/main/java/androidx/appsearch/compiler/SchemaCodeGenerator.java
@@ -227,6 +227,28 @@
}
codeBlock.add("\n.setIndexingType($T)", indexingEnum);
+ int joinableValueType = Integer.parseInt(params.get("joinableValueType").toString());
+ ClassName joinableEnum;
+ if (joinableValueType == 0) { // JOINABLE_VALUE_TYPE_NONE
+ joinableEnum = mHelper.getAppSearchClass(
+ "AppSearchSchema", "StringPropertyConfig", "JOINABLE_VALUE_TYPE_NONE");
+
+ } else if (joinableValueType == 1) { // JOINABLE_VALUE_TYPE_QUALIFIED_ID
+ if (repeated) {
+ throw new ProcessingException(
+ "Joinable value type " + joinableValueType + " not allowed on repeated "
+ + "properties.", property);
+
+ }
+ joinableEnum = mHelper.getAppSearchClass(
+ "AppSearchSchema", "StringPropertyConfig",
+ "JOINABLE_VALUE_TYPE_QUALIFIED_ID");
+ } else {
+ throw new ProcessingException(
+ "Unknown joinable value type " + joinableValueType, property);
+ }
+ codeBlock.add("\n.setJoinableValueType($T)", joinableEnum);
+
} else if (isPropertyDocument) {
if (params.containsKey("indexNestedProperties")) {
boolean indexNestedProperties = Boolean.parseBoolean(
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 b36c5877..dc1ff19 100644
--- a/appsearch/compiler/src/test/java/androidx/appsearch/compiler/AppSearchCompilerTest.java
+++ b/appsearch/compiler/src/test/java/androidx/appsearch/compiler/AppSearchCompilerTest.java
@@ -1190,6 +1190,38 @@
}
@Test
+ public void testStringPropertyJoinableType() throws Exception {
+ Compilation compilation = compile(
+ "import java.util.*;\n"
+ + "@Document\n"
+ + "public class Gift {\n"
+ + " @Document.Namespace String namespace;\n"
+ + " @Document.Id String id;\n"
+ + " @Document.StringProperty(joinableValueType=1)\n"
+ + " String object;\n"
+ + "}\n");
+
+ assertThat(compilation).succeededWithoutWarnings();
+ checkEqualsGolden("Gift.java");
+ }
+
+ @Test
+ public void testRepeatedPropertyJoinableType_throwsError() throws Exception {
+ Compilation compilation = compile(
+ "import java.util.*;\n"
+ + "@Document\n"
+ + "public class Gift {\n"
+ + " @Document.Namespace String namespace;\n"
+ + " @Document.Id String id;\n"
+ + " @Document.StringProperty(joinableValueType=1)\n"
+ + " List<String> object;\n"
+ + "}\n");
+
+ assertThat(compilation).hadErrorContaining(
+ "Joinable value type 1 not allowed on repeated properties.");
+ }
+
+ @Test
public void testPropertyName() throws Exception {
Compilation compilation = compile(
"import java.util.*;\n"
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 094d178..1b903fe 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
@@ -29,6 +29,7 @@
.setCardinality(AppSearchSchema.PropertyConfig.CARDINALITY_OPTIONAL)
.setTokenizerType(AppSearchSchema.StringPropertyConfig.TOKENIZER_TYPE_NONE)
.setIndexingType(AppSearchSchema.StringPropertyConfig.INDEXING_TYPE_NONE)
+ .setJoinableValueType(AppSearchSchema.StringPropertyConfig.JOINABLE_VALUE_TYPE_NONE)
.build())
.addProperty(new AppSearchSchema.LongPropertyConfig.Builder("integerProp")
.setCardinality(AppSearchSchema.PropertyConfig.CARDINALITY_OPTIONAL)
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
index ab783ed..5884187 100644
--- a/appsearch/compiler/src/test/resources/androidx/appsearch/compiler/goldens/testAutoValueDocument.JAVA
+++ b/appsearch/compiler/src/test/resources/androidx/appsearch/compiler/goldens/testAutoValueDocument.JAVA
@@ -24,6 +24,7 @@
.setCardinality(AppSearchSchema.PropertyConfig.CARDINALITY_OPTIONAL)
.setTokenizerType(AppSearchSchema.StringPropertyConfig.TOKENIZER_TYPE_NONE)
.setIndexingType(AppSearchSchema.StringPropertyConfig.INDEXING_TYPE_NONE)
+ .setJoinableValueType(AppSearchSchema.StringPropertyConfig.JOINABLE_VALUE_TYPE_NONE)
.build())
.build();
}
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 0f275a7..17123b2 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
@@ -27,11 +27,13 @@
.setCardinality(AppSearchSchema.PropertyConfig.CARDINALITY_REPEATED)
.setTokenizerType(AppSearchSchema.StringPropertyConfig.TOKENIZER_TYPE_NONE)
.setIndexingType(AppSearchSchema.StringPropertyConfig.INDEXING_TYPE_NONE)
+ .setJoinableValueType(AppSearchSchema.StringPropertyConfig.JOINABLE_VALUE_TYPE_NONE)
.build())
.addProperty(new AppSearchSchema.StringPropertyConfig.Builder("repeatNoReq")
.setCardinality(AppSearchSchema.PropertyConfig.CARDINALITY_REPEATED)
.setTokenizerType(AppSearchSchema.StringPropertyConfig.TOKENIZER_TYPE_NONE)
.setIndexingType(AppSearchSchema.StringPropertyConfig.INDEXING_TYPE_NONE)
+ .setJoinableValueType(AppSearchSchema.StringPropertyConfig.JOINABLE_VALUE_TYPE_NONE)
.build())
.addProperty(new AppSearchSchema.DoublePropertyConfig.Builder("req")
.setCardinality(AppSearchSchema.PropertyConfig.CARDINALITY_REQUIRED)
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 810a16f..acac398 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
@@ -24,16 +24,19 @@
.setCardinality(AppSearchSchema.PropertyConfig.CARDINALITY_OPTIONAL)
.setTokenizerType(AppSearchSchema.StringPropertyConfig.TOKENIZER_TYPE_NONE)
.setIndexingType(AppSearchSchema.StringPropertyConfig.INDEXING_TYPE_NONE)
+ .setJoinableValueType(AppSearchSchema.StringPropertyConfig.JOINABLE_VALUE_TYPE_NONE)
.build())
.addProperty(new AppSearchSchema.StringPropertyConfig.Builder("indexExact")
.setCardinality(AppSearchSchema.PropertyConfig.CARDINALITY_OPTIONAL)
.setTokenizerType(AppSearchSchema.StringPropertyConfig.TOKENIZER_TYPE_PLAIN)
.setIndexingType(AppSearchSchema.StringPropertyConfig.INDEXING_TYPE_EXACT_TERMS)
+ .setJoinableValueType(AppSearchSchema.StringPropertyConfig.JOINABLE_VALUE_TYPE_NONE)
.build())
.addProperty(new AppSearchSchema.StringPropertyConfig.Builder("indexPrefix")
.setCardinality(AppSearchSchema.PropertyConfig.CARDINALITY_OPTIONAL)
.setTokenizerType(AppSearchSchema.StringPropertyConfig.TOKENIZER_TYPE_PLAIN)
.setIndexingType(AppSearchSchema.StringPropertyConfig.INDEXING_TYPE_PREFIXES)
+ .setJoinableValueType(AppSearchSchema.StringPropertyConfig.JOINABLE_VALUE_TYPE_NONE)
.build())
.build();
}
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 ac333bc..8e84986 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
@@ -24,6 +24,7 @@
.setCardinality(AppSearchSchema.PropertyConfig.CARDINALITY_REPEATED)
.setTokenizerType(AppSearchSchema.StringPropertyConfig.TOKENIZER_TYPE_NONE)
.setIndexingType(AppSearchSchema.StringPropertyConfig.INDEXING_TYPE_NONE)
+ .setJoinableValueType(AppSearchSchema.StringPropertyConfig.JOINABLE_VALUE_TYPE_NONE)
.build())
.build();
}
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 f6672c0..2dbc6ef 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
@@ -24,6 +24,7 @@
.setCardinality(AppSearchSchema.PropertyConfig.CARDINALITY_OPTIONAL)
.setTokenizerType(AppSearchSchema.StringPropertyConfig.TOKENIZER_TYPE_NONE)
.setIndexingType(AppSearchSchema.StringPropertyConfig.INDEXING_TYPE_NONE)
+ .setJoinableValueType(AppSearchSchema.StringPropertyConfig.JOINABLE_VALUE_TYPE_NONE)
.build())
.build();
}
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 f46d524..1aa73c0 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
@@ -29,6 +29,7 @@
.setCardinality(AppSearchSchema.PropertyConfig.CARDINALITY_REPEATED)
.setTokenizerType(AppSearchSchema.StringPropertyConfig.TOKENIZER_TYPE_NONE)
.setIndexingType(AppSearchSchema.StringPropertyConfig.INDEXING_TYPE_NONE)
+ .setJoinableValueType(AppSearchSchema.StringPropertyConfig.JOINABLE_VALUE_TYPE_NONE)
.build())
.addProperty(new AppSearchSchema.LongPropertyConfig.Builder("setOfInt")
.setCardinality(AppSearchSchema.PropertyConfig.CARDINALITY_REPEATED)
diff --git a/appsearch/compiler/src/test/resources/androidx/appsearch/compiler/goldens/testStringPropertyJoinableType.JAVA b/appsearch/compiler/src/test/resources/androidx/appsearch/compiler/goldens/testStringPropertyJoinableType.JAVA
new file mode 100644
index 0000000..79242a5
--- /dev/null
+++ b/appsearch/compiler/src/test/resources/androidx/appsearch/compiler/goldens/testStringPropertyJoinableType.JAVA
@@ -0,0 +1,58 @@
+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 final class $$__AppSearch__Gift implements DocumentClassFactory<Gift> {
+ public static final String SCHEMA_NAME = "Gift";
+
+ @Override
+ public String getSchemaName() {
+ return SCHEMA_NAME;
+ }
+
+ @Override
+ public AppSearchSchema getSchema() throws AppSearchException {
+ return new AppSearchSchema.Builder(SCHEMA_NAME)
+ .addProperty(new AppSearchSchema.StringPropertyConfig.Builder("object")
+ .setCardinality(AppSearchSchema.PropertyConfig.CARDINALITY_OPTIONAL)
+ .setTokenizerType(AppSearchSchema.StringPropertyConfig.TOKENIZER_TYPE_NONE)
+ .setIndexingType(AppSearchSchema.StringPropertyConfig.INDEXING_TYPE_NONE)
+ .setJoinableValueType(AppSearchSchema.StringPropertyConfig.JOINABLE_VALUE_TYPE_QUALIFIED_ID)
+ .build())
+ .build();
+ }
+
+ @Override
+ public GenericDocument toGenericDocument(Gift document) throws AppSearchException {
+ GenericDocument.Builder<?> builder =
+ new GenericDocument.Builder<>(document.namespace, document.id, SCHEMA_NAME);
+ String objectCopy = document.object;
+ if (objectCopy != null) {
+ builder.setPropertyString("object", objectCopy);
+ }
+ return builder.build();
+ }
+
+ @Override
+ public Gift fromGenericDocument(GenericDocument genericDoc) throws AppSearchException {
+ String idConv = genericDoc.getId();
+ String namespaceConv = genericDoc.getNamespace();
+ String[] objectCopy = genericDoc.getPropertyStringArray("object");
+ String objectConv = null;
+ if (objectCopy != null && objectCopy.length != 0) {
+ objectConv = objectCopy[0];
+ }
+ Gift document = new Gift();
+ document.namespace = namespaceConv;
+ document.id = idConv;
+ document.object = objectConv;
+ return document;
+ }
+}
diff --git a/appsearch/compiler/src/test/resources/androidx/appsearch/compiler/goldens/testSuperClass.JAVA b/appsearch/compiler/src/test/resources/androidx/appsearch/compiler/goldens/testSuperClass.JAVA
index ef1410d..7b00f42 100644
--- a/appsearch/compiler/src/test/resources/androidx/appsearch/compiler/goldens/testSuperClass.JAVA
+++ b/appsearch/compiler/src/test/resources/androidx/appsearch/compiler/goldens/testSuperClass.JAVA
@@ -24,11 +24,13 @@
.setCardinality(AppSearchSchema.PropertyConfig.CARDINALITY_OPTIONAL)
.setTokenizerType(AppSearchSchema.StringPropertyConfig.TOKENIZER_TYPE_NONE)
.setIndexingType(AppSearchSchema.StringPropertyConfig.INDEXING_TYPE_NONE)
+ .setJoinableValueType(AppSearchSchema.StringPropertyConfig.JOINABLE_VALUE_TYPE_NONE)
.build())
.addProperty(new AppSearchSchema.StringPropertyConfig.Builder("sender")
.setCardinality(AppSearchSchema.PropertyConfig.CARDINALITY_OPTIONAL)
.setTokenizerType(AppSearchSchema.StringPropertyConfig.TOKENIZER_TYPE_NONE)
.setIndexingType(AppSearchSchema.StringPropertyConfig.INDEXING_TYPE_NONE)
+ .setJoinableValueType(AppSearchSchema.StringPropertyConfig.JOINABLE_VALUE_TYPE_NONE)
.build())
.addProperty(new AppSearchSchema.BooleanPropertyConfig.Builder("foo")
.setCardinality(AppSearchSchema.PropertyConfig.CARDINALITY_OPTIONAL)
diff --git a/appsearch/compiler/src/test/resources/androidx/appsearch/compiler/goldens/testSuperClassPojoAncestor.JAVA b/appsearch/compiler/src/test/resources/androidx/appsearch/compiler/goldens/testSuperClassPojoAncestor.JAVA
index f51fa57..0ae95a1 100644
--- a/appsearch/compiler/src/test/resources/androidx/appsearch/compiler/goldens/testSuperClassPojoAncestor.JAVA
+++ b/appsearch/compiler/src/test/resources/androidx/appsearch/compiler/goldens/testSuperClassPojoAncestor.JAVA
@@ -24,11 +24,13 @@
.setCardinality(AppSearchSchema.PropertyConfig.CARDINALITY_OPTIONAL)
.setTokenizerType(AppSearchSchema.StringPropertyConfig.TOKENIZER_TYPE_NONE)
.setIndexingType(AppSearchSchema.StringPropertyConfig.INDEXING_TYPE_NONE)
+ .setJoinableValueType(AppSearchSchema.StringPropertyConfig.JOINABLE_VALUE_TYPE_NONE)
.build())
.addProperty(new AppSearchSchema.StringPropertyConfig.Builder("sender")
.setCardinality(AppSearchSchema.PropertyConfig.CARDINALITY_OPTIONAL)
.setTokenizerType(AppSearchSchema.StringPropertyConfig.TOKENIZER_TYPE_NONE)
.setIndexingType(AppSearchSchema.StringPropertyConfig.INDEXING_TYPE_NONE)
+ .setJoinableValueType(AppSearchSchema.StringPropertyConfig.JOINABLE_VALUE_TYPE_NONE)
.build())
.addProperty(new AppSearchSchema.BooleanPropertyConfig.Builder("foo")
.setCardinality(AppSearchSchema.PropertyConfig.CARDINALITY_OPTIONAL)
diff --git a/appsearch/compiler/src/test/resources/androidx/appsearch/compiler/goldens/testSuperClassWithPrivateFields.JAVA b/appsearch/compiler/src/test/resources/androidx/appsearch/compiler/goldens/testSuperClassWithPrivateFields.JAVA
index 3fed9e3..556a3f8 100644
--- a/appsearch/compiler/src/test/resources/androidx/appsearch/compiler/goldens/testSuperClassWithPrivateFields.JAVA
+++ b/appsearch/compiler/src/test/resources/androidx/appsearch/compiler/goldens/testSuperClassWithPrivateFields.JAVA
@@ -24,16 +24,19 @@
.setCardinality(AppSearchSchema.PropertyConfig.CARDINALITY_OPTIONAL)
.setTokenizerType(AppSearchSchema.StringPropertyConfig.TOKENIZER_TYPE_NONE)
.setIndexingType(AppSearchSchema.StringPropertyConfig.INDEXING_TYPE_NONE)
+ .setJoinableValueType(AppSearchSchema.StringPropertyConfig.JOINABLE_VALUE_TYPE_NONE)
.build())
.addProperty(new AppSearchSchema.StringPropertyConfig.Builder("receiver")
.setCardinality(AppSearchSchema.PropertyConfig.CARDINALITY_OPTIONAL)
.setTokenizerType(AppSearchSchema.StringPropertyConfig.TOKENIZER_TYPE_NONE)
.setIndexingType(AppSearchSchema.StringPropertyConfig.INDEXING_TYPE_NONE)
+ .setJoinableValueType(AppSearchSchema.StringPropertyConfig.JOINABLE_VALUE_TYPE_NONE)
.build())
.addProperty(new AppSearchSchema.StringPropertyConfig.Builder("sender")
.setCardinality(AppSearchSchema.PropertyConfig.CARDINALITY_OPTIONAL)
.setTokenizerType(AppSearchSchema.StringPropertyConfig.TOKENIZER_TYPE_NONE)
.setIndexingType(AppSearchSchema.StringPropertyConfig.INDEXING_TYPE_NONE)
+ .setJoinableValueType(AppSearchSchema.StringPropertyConfig.JOINABLE_VALUE_TYPE_NONE)
.build())
.build();
}
diff --git a/appsearch/compiler/src/test/resources/androidx/appsearch/compiler/goldens/testSuperClass_changeSchemaName.JAVA b/appsearch/compiler/src/test/resources/androidx/appsearch/compiler/goldens/testSuperClass_changeSchemaName.JAVA
index 812463a..d900d78 100644
--- a/appsearch/compiler/src/test/resources/androidx/appsearch/compiler/goldens/testSuperClass_changeSchemaName.JAVA
+++ b/appsearch/compiler/src/test/resources/androidx/appsearch/compiler/goldens/testSuperClass_changeSchemaName.JAVA
@@ -24,11 +24,13 @@
.setCardinality(AppSearchSchema.PropertyConfig.CARDINALITY_OPTIONAL)
.setTokenizerType(AppSearchSchema.StringPropertyConfig.TOKENIZER_TYPE_NONE)
.setIndexingType(AppSearchSchema.StringPropertyConfig.INDEXING_TYPE_NONE)
+ .setJoinableValueType(AppSearchSchema.StringPropertyConfig.JOINABLE_VALUE_TYPE_NONE)
.build())
.addProperty(new AppSearchSchema.StringPropertyConfig.Builder("sender")
.setCardinality(AppSearchSchema.PropertyConfig.CARDINALITY_OPTIONAL)
.setTokenizerType(AppSearchSchema.StringPropertyConfig.TOKENIZER_TYPE_NONE)
.setIndexingType(AppSearchSchema.StringPropertyConfig.INDEXING_TYPE_NONE)
+ .setJoinableValueType(AppSearchSchema.StringPropertyConfig.JOINABLE_VALUE_TYPE_NONE)
.build())
.build();
}
diff --git a/appsearch/compiler/src/test/resources/androidx/appsearch/compiler/goldens/testSuperClass_multipleChangedSchemaNames.JAVA b/appsearch/compiler/src/test/resources/androidx/appsearch/compiler/goldens/testSuperClass_multipleChangedSchemaNames.JAVA
index b77c03b..7bb44e1 100644
--- a/appsearch/compiler/src/test/resources/androidx/appsearch/compiler/goldens/testSuperClass_multipleChangedSchemaNames.JAVA
+++ b/appsearch/compiler/src/test/resources/androidx/appsearch/compiler/goldens/testSuperClass_multipleChangedSchemaNames.JAVA
@@ -24,11 +24,13 @@
.setCardinality(AppSearchSchema.PropertyConfig.CARDINALITY_OPTIONAL)
.setTokenizerType(AppSearchSchema.StringPropertyConfig.TOKENIZER_TYPE_NONE)
.setIndexingType(AppSearchSchema.StringPropertyConfig.INDEXING_TYPE_NONE)
+ .setJoinableValueType(AppSearchSchema.StringPropertyConfig.JOINABLE_VALUE_TYPE_NONE)
.build())
.addProperty(new AppSearchSchema.StringPropertyConfig.Builder("sender")
.setCardinality(AppSearchSchema.PropertyConfig.CARDINALITY_OPTIONAL)
.setTokenizerType(AppSearchSchema.StringPropertyConfig.TOKENIZER_TYPE_NONE)
.setIndexingType(AppSearchSchema.StringPropertyConfig.INDEXING_TYPE_NONE)
+ .setJoinableValueType(AppSearchSchema.StringPropertyConfig.JOINABLE_VALUE_TYPE_NONE)
.build())
.addProperty(new AppSearchSchema.BooleanPropertyConfig.Builder("foo")
.setCardinality(AppSearchSchema.PropertyConfig.CARDINALITY_OPTIONAL)
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 d7e9290..96e8369 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
@@ -54,6 +54,7 @@
.setCardinality(AppSearchSchema.PropertyConfig.CARDINALITY_REPEATED)
.setTokenizerType(AppSearchSchema.StringPropertyConfig.TOKENIZER_TYPE_NONE)
.setIndexingType(AppSearchSchema.StringPropertyConfig.INDEXING_TYPE_NONE)
+ .setJoinableValueType(AppSearchSchema.StringPropertyConfig.JOINABLE_VALUE_TYPE_NONE)
.build())
.addProperty(new AppSearchSchema.DocumentPropertyConfig.Builder("collectGift", $$__AppSearch__Gift.SCHEMA_NAME)
.setCardinality(AppSearchSchema.PropertyConfig.CARDINALITY_REPEATED)
@@ -103,6 +104,7 @@
.setCardinality(AppSearchSchema.PropertyConfig.CARDINALITY_REPEATED)
.setTokenizerType(AppSearchSchema.StringPropertyConfig.TOKENIZER_TYPE_NONE)
.setIndexingType(AppSearchSchema.StringPropertyConfig.INDEXING_TYPE_NONE)
+ .setJoinableValueType(AppSearchSchema.StringPropertyConfig.JOINABLE_VALUE_TYPE_NONE)
.build())
.addProperty(new AppSearchSchema.DocumentPropertyConfig.Builder("arrGift", $$__AppSearch__Gift.SCHEMA_NAME)
.setCardinality(AppSearchSchema.PropertyConfig.CARDINALITY_REPEATED)
@@ -112,6 +114,7 @@
.setCardinality(AppSearchSchema.PropertyConfig.CARDINALITY_OPTIONAL)
.setTokenizerType(AppSearchSchema.StringPropertyConfig.TOKENIZER_TYPE_NONE)
.setIndexingType(AppSearchSchema.StringPropertyConfig.INDEXING_TYPE_NONE)
+ .setJoinableValueType(AppSearchSchema.StringPropertyConfig.JOINABLE_VALUE_TYPE_NONE)
.build())
.addProperty(new AppSearchSchema.LongPropertyConfig.Builder("boxLong")
.setCardinality(AppSearchSchema.PropertyConfig.CARDINALITY_OPTIONAL)
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 678c212..15b3095 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
@@ -24,61 +24,73 @@
.setCardinality(AppSearchSchema.PropertyConfig.CARDINALITY_OPTIONAL)
.setTokenizerType(AppSearchSchema.StringPropertyConfig.TOKENIZER_TYPE_NONE)
.setIndexingType(AppSearchSchema.StringPropertyConfig.INDEXING_TYPE_NONE)
+ .setJoinableValueType(AppSearchSchema.StringPropertyConfig.JOINABLE_VALUE_TYPE_NONE)
.build())
.addProperty(new AppSearchSchema.StringPropertyConfig.Builder("tokPlainInvalid")
.setCardinality(AppSearchSchema.PropertyConfig.CARDINALITY_OPTIONAL)
.setTokenizerType(AppSearchSchema.StringPropertyConfig.TOKENIZER_TYPE_NONE)
.setIndexingType(AppSearchSchema.StringPropertyConfig.INDEXING_TYPE_NONE)
+ .setJoinableValueType(AppSearchSchema.StringPropertyConfig.JOINABLE_VALUE_TYPE_NONE)
.build())
.addProperty(new AppSearchSchema.StringPropertyConfig.Builder("tokVerbatimInvalid")
.setCardinality(AppSearchSchema.PropertyConfig.CARDINALITY_OPTIONAL)
.setTokenizerType(AppSearchSchema.StringPropertyConfig.TOKENIZER_TYPE_NONE)
.setIndexingType(AppSearchSchema.StringPropertyConfig.INDEXING_TYPE_NONE)
+ .setJoinableValueType(AppSearchSchema.StringPropertyConfig.JOINABLE_VALUE_TYPE_NONE)
.build())
.addProperty(new AppSearchSchema.StringPropertyConfig.Builder("tokRfc822Invalid")
.setCardinality(AppSearchSchema.PropertyConfig.CARDINALITY_OPTIONAL)
.setTokenizerType(AppSearchSchema.StringPropertyConfig.TOKENIZER_TYPE_NONE)
.setIndexingType(AppSearchSchema.StringPropertyConfig.INDEXING_TYPE_NONE)
+ .setJoinableValueType(AppSearchSchema.StringPropertyConfig.JOINABLE_VALUE_TYPE_NONE)
.build())
.addProperty(new AppSearchSchema.StringPropertyConfig.Builder("tokNone")
.setCardinality(AppSearchSchema.PropertyConfig.CARDINALITY_OPTIONAL)
.setTokenizerType(AppSearchSchema.StringPropertyConfig.TOKENIZER_TYPE_NONE)
.setIndexingType(AppSearchSchema.StringPropertyConfig.INDEXING_TYPE_EXACT_TERMS)
+ .setJoinableValueType(AppSearchSchema.StringPropertyConfig.JOINABLE_VALUE_TYPE_NONE)
.build())
.addProperty(new AppSearchSchema.StringPropertyConfig.Builder("tokPlain")
.setCardinality(AppSearchSchema.PropertyConfig.CARDINALITY_OPTIONAL)
.setTokenizerType(AppSearchSchema.StringPropertyConfig.TOKENIZER_TYPE_PLAIN)
.setIndexingType(AppSearchSchema.StringPropertyConfig.INDEXING_TYPE_EXACT_TERMS)
+ .setJoinableValueType(AppSearchSchema.StringPropertyConfig.JOINABLE_VALUE_TYPE_NONE)
.build())
.addProperty(new AppSearchSchema.StringPropertyConfig.Builder("tokVerbatim")
.setCardinality(AppSearchSchema.PropertyConfig.CARDINALITY_OPTIONAL)
.setTokenizerType(AppSearchSchema.StringPropertyConfig.TOKENIZER_TYPE_VERBATIM)
.setIndexingType(AppSearchSchema.StringPropertyConfig.INDEXING_TYPE_EXACT_TERMS)
+ .setJoinableValueType(AppSearchSchema.StringPropertyConfig.JOINABLE_VALUE_TYPE_NONE)
.build())
.addProperty(new AppSearchSchema.StringPropertyConfig.Builder("tokRfc822")
.setCardinality(AppSearchSchema.PropertyConfig.CARDINALITY_OPTIONAL)
.setTokenizerType(AppSearchSchema.StringPropertyConfig.TOKENIZER_TYPE_RFC822)
.setIndexingType(AppSearchSchema.StringPropertyConfig.INDEXING_TYPE_EXACT_TERMS)
+ .setJoinableValueType(AppSearchSchema.StringPropertyConfig.JOINABLE_VALUE_TYPE_NONE)
.build())
.addProperty(new AppSearchSchema.StringPropertyConfig.Builder("tokNonePrefix")
.setCardinality(AppSearchSchema.PropertyConfig.CARDINALITY_OPTIONAL)
.setTokenizerType(AppSearchSchema.StringPropertyConfig.TOKENIZER_TYPE_NONE)
.setIndexingType(AppSearchSchema.StringPropertyConfig.INDEXING_TYPE_PREFIXES)
+ .setJoinableValueType(AppSearchSchema.StringPropertyConfig.JOINABLE_VALUE_TYPE_NONE)
.build())
.addProperty(new AppSearchSchema.StringPropertyConfig.Builder("tokPlainPrefix")
.setCardinality(AppSearchSchema.PropertyConfig.CARDINALITY_OPTIONAL)
.setTokenizerType(AppSearchSchema.StringPropertyConfig.TOKENIZER_TYPE_PLAIN)
.setIndexingType(AppSearchSchema.StringPropertyConfig.INDEXING_TYPE_PREFIXES)
+ .setJoinableValueType(AppSearchSchema.StringPropertyConfig.JOINABLE_VALUE_TYPE_NONE)
.build())
.addProperty(new AppSearchSchema.StringPropertyConfig.Builder("tokVerbatimPrefix")
.setCardinality(AppSearchSchema.PropertyConfig.CARDINALITY_OPTIONAL)
.setTokenizerType(AppSearchSchema.StringPropertyConfig.TOKENIZER_TYPE_VERBATIM)
.setIndexingType(AppSearchSchema.StringPropertyConfig.INDEXING_TYPE_PREFIXES)
+ .setJoinableValueType(AppSearchSchema.StringPropertyConfig.JOINABLE_VALUE_TYPE_NONE)
.build())
.addProperty(new AppSearchSchema.StringPropertyConfig.Builder("tokRfc822Prefix")
.setCardinality(AppSearchSchema.PropertyConfig.CARDINALITY_OPTIONAL)
.setTokenizerType(AppSearchSchema.StringPropertyConfig.TOKENIZER_TYPE_RFC822)
.setIndexingType(AppSearchSchema.StringPropertyConfig.INDEXING_TYPE_PREFIXES)
+ .setJoinableValueType(AppSearchSchema.StringPropertyConfig.JOINABLE_VALUE_TYPE_NONE)
.build())
.build();
}
diff --git a/buildSrc/public/src/main/kotlin/androidx/build/SupportConfig.kt b/buildSrc/public/src/main/kotlin/androidx/build/SupportConfig.kt
index 51626cc..33a5655 100644
--- a/buildSrc/public/src/main/kotlin/androidx/build/SupportConfig.kt
+++ b/buildSrc/public/src/main/kotlin/androidx/build/SupportConfig.kt
@@ -33,7 +33,7 @@
* 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-33-ext4"
+ const val COMPILE_SDK_VERSION = "android-UpsideDownCake"
/**
* The Android SDK version to use for targetSdkVersion meta-data.
diff --git a/busytown/impl/check_translations.sh b/busytown/impl/check_translations.sh
index 35501ad..0f9e440 100755
--- a/busytown/impl/check_translations.sh
+++ b/busytown/impl/check_translations.sh
@@ -20,6 +20,7 @@
find . \
\( \
-iname '*sample*' \
+ -o -iname '*demo*' \
-o -iname '*donottranslate*' \
-o -iname '*debug*' \
-o -iname '*test*' \
diff --git a/car/app/app/src/main/aidl/androidx/car/app/IAppHost.aidl b/car/app/app/src/main/aidl/androidx/car/app/IAppHost.aidl
index a56087a..bdd0065 100644
--- a/car/app/app/src/main/aidl/androidx/car/app/IAppHost.aidl
+++ b/car/app/app/src/main/aidl/androidx/car/app/IAppHost.aidl
@@ -16,6 +16,7 @@
package androidx.car.app;
+import android.location.Location;
import androidx.car.app.ISurfaceCallback;
import androidx.car.app.serialization.Bundleable;
diff --git a/compose/material3/material3/src/androidMain/res/values-ms/strings.xml b/compose/material3/material3/src/androidMain/res/values-ms/strings.xml
index 1bef8e7..8370e97 100644
--- a/compose/material3/material3/src/androidMain/res/values-ms/strings.xml
+++ b/compose/material3/material3/src/androidMain/res/values-ms/strings.xml
@@ -44,10 +44,14 @@
<string name="date_input_invalid_year_range" msgid="8434112129235255568">"Tarikh di luar julat tahun yang dijangkakan %1$s - %2$s"</string>
<string name="date_picker_switch_to_calendar_mode" msgid="9029369254443419167">"Beralih kepada mod input kalendar"</string>
<string name="date_picker_switch_to_input_mode" msgid="1496750567914156598">"Beralih kepada mod input teks"</string>
- <string name="date_range_picker_title" msgid="690080476639943577">"Pilih tarikh"</string>
- <string name="date_range_picker_start_headline" msgid="5759491386723090559">"Tarikh mula"</string>
- <string name="date_range_picker_end_headline" msgid="4766270708882012148">"Tarikh tamat"</string>
- <string name="date_range_input_title" msgid="2366412111888449406">"Masukkan tarikh"</string>
+ <!-- no translation found for date_range_picker_title (690080476639943577) -->
+ <skip />
+ <!-- no translation found for date_range_picker_start_headline (5759491386723090559) -->
+ <skip />
+ <!-- no translation found for date_range_picker_end_headline (4766270708882012148) -->
+ <skip />
+ <!-- no translation found for date_range_input_title (2366412111888449406) -->
+ <skip />
<string name="tooltip_long_press_label" msgid="2732804537909054941">"Tunjukkan tip alat"</string>
<string name="time_picker_pm" msgid="2232702812657998674">"P/M"</string>
<string name="time_picker_am" msgid="5096144640014509074">"PG"</string>
diff --git a/constraintlayout/constraintlayout/api/api_lint.ignore b/constraintlayout/constraintlayout/api/api_lint.ignore
index 1f05e12..422e6ca 100644
--- a/constraintlayout/constraintlayout/api/api_lint.ignore
+++ b/constraintlayout/constraintlayout/api/api_lint.ignore
@@ -217,24 +217,6 @@
Invalid nullability on parameter `target` in method `onNestedFling`. Parameters of overrides cannot be NonNull if the super parameter is unannotated.
InvalidNullabilityOverride: androidx.constraintlayout.motion.widget.MotionLayout#onNestedPreFling(android.view.View, float, float) parameter #0:
Invalid nullability on parameter `target` in method `onNestedPreFling`. Parameters of overrides cannot be NonNull if the super parameter is unannotated.
-InvalidNullabilityOverride: androidx.constraintlayout.utils.widget.ImageFilterButton#draw(android.graphics.Canvas) parameter #0:
- Invalid nullability on parameter `canvas` in method `draw`. Parameters of overrides cannot be NonNull if the super parameter is unannotated.
-InvalidNullabilityOverride: androidx.constraintlayout.utils.widget.ImageFilterView#draw(android.graphics.Canvas) parameter #0:
- Invalid nullability on parameter `canvas` in method `draw`. Parameters of overrides cannot be NonNull if the super parameter is unannotated.
-InvalidNullabilityOverride: androidx.constraintlayout.utils.widget.MockView#onDraw(android.graphics.Canvas) parameter #0:
- Invalid nullability on parameter `canvas` in method `onDraw`. Parameters of overrides cannot be NonNull if the super parameter is unannotated.
-InvalidNullabilityOverride: androidx.constraintlayout.utils.widget.MotionButton#draw(android.graphics.Canvas) parameter #0:
- Invalid nullability on parameter `canvas` in method `draw`. Parameters of overrides cannot be NonNull if the super parameter is unannotated.
-InvalidNullabilityOverride: androidx.constraintlayout.utils.widget.MotionLabel#onDraw(android.graphics.Canvas) parameter #0:
- Invalid nullability on parameter `canvas` in method `onDraw`. Parameters of overrides cannot be NonNull if the super parameter is unannotated.
-InvalidNullabilityOverride: androidx.constraintlayout.widget.ConstraintHelper#onDraw(android.graphics.Canvas) parameter #0:
- Invalid nullability on parameter `canvas` in method `onDraw`. Parameters of overrides cannot be NonNull if the super parameter is unannotated.
-InvalidNullabilityOverride: androidx.constraintlayout.widget.Guideline#draw(android.graphics.Canvas) parameter #0:
- Invalid nullability on parameter `canvas` in method `draw`. Parameters of overrides cannot be NonNull if the super parameter is unannotated.
-InvalidNullabilityOverride: androidx.constraintlayout.widget.Placeholder#onDraw(android.graphics.Canvas) parameter #0:
- Invalid nullability on parameter `canvas` in method `onDraw`. Parameters of overrides cannot be NonNull if the super parameter is unannotated.
-InvalidNullabilityOverride: androidx.constraintlayout.widget.ReactiveGuide#draw(android.graphics.Canvas) parameter #0:
- Invalid nullability on parameter `canvas` in method `draw`. Parameters of overrides cannot be NonNull if the super parameter is unannotated.
KotlinOperator: androidx.constraintlayout.motion.utils.ViewTimeCycle#get(float, long, android.view.View, androidx.constraintlayout.core.motion.utils.KeyCache):
@@ -349,6 +331,8 @@
Missing nullability on method `getSpans` return
MissingNullability: androidx.constraintlayout.helper.widget.Grid#init(android.util.AttributeSet) parameter #0:
Missing nullability on parameter `attrs` in method `init`
+MissingNullability: androidx.constraintlayout.helper.widget.Grid#onDraw(android.graphics.Canvas) parameter #0:
+ Missing nullability on parameter `canvas` in method `onDraw`
MissingNullability: androidx.constraintlayout.helper.widget.Grid#setColumnWeights(String) parameter #0:
Missing nullability on parameter `columnWeights` in method `setColumnWeights`
MissingNullability: androidx.constraintlayout.helper.widget.Grid#setRowWeights(String) parameter #0:
@@ -1089,6 +1073,8 @@
Missing nullability on parameter `context` in method `ImageFilterButton`
MissingNullability: androidx.constraintlayout.utils.widget.ImageFilterButton#ImageFilterButton(android.content.Context, android.util.AttributeSet, int) parameter #1:
Missing nullability on parameter `attrs` in method `ImageFilterButton`
+MissingNullability: androidx.constraintlayout.utils.widget.ImageFilterButton#draw(android.graphics.Canvas) parameter #0:
+ Missing nullability on parameter `canvas` in method `draw`
MissingNullability: androidx.constraintlayout.utils.widget.ImageFilterButton#setImageDrawable(android.graphics.drawable.Drawable) parameter #0:
Missing nullability on parameter `drawable` in method `setImageDrawable`
MissingNullability: androidx.constraintlayout.utils.widget.ImageFilterView#ImageFilterView(android.content.Context) parameter #0:
@@ -1101,6 +1087,8 @@
Missing nullability on parameter `context` in method `ImageFilterView`
MissingNullability: androidx.constraintlayout.utils.widget.ImageFilterView#ImageFilterView(android.content.Context, android.util.AttributeSet, int) parameter #1:
Missing nullability on parameter `attrs` in method `ImageFilterView`
+MissingNullability: androidx.constraintlayout.utils.widget.ImageFilterView#draw(android.graphics.Canvas) parameter #0:
+ Missing nullability on parameter `canvas` in method `draw`
MissingNullability: androidx.constraintlayout.utils.widget.ImageFilterView#setAltImageDrawable(android.graphics.drawable.Drawable) parameter #0:
Missing nullability on parameter `altDrawable` in method `setAltImageDrawable`
MissingNullability: androidx.constraintlayout.utils.widget.ImageFilterView#setImageDrawable(android.graphics.drawable.Drawable) parameter #0:
@@ -1117,6 +1105,8 @@
Missing nullability on parameter `attrs` in method `MockView`
MissingNullability: androidx.constraintlayout.utils.widget.MockView#mText:
Missing nullability on field `mText` in class `class androidx.constraintlayout.utils.widget.MockView`
+MissingNullability: androidx.constraintlayout.utils.widget.MockView#onDraw(android.graphics.Canvas) parameter #0:
+ Missing nullability on parameter `canvas` in method `onDraw`
MissingNullability: androidx.constraintlayout.utils.widget.MotionButton#MotionButton(android.content.Context) parameter #0:
Missing nullability on parameter `context` in method `MotionButton`
MissingNullability: androidx.constraintlayout.utils.widget.MotionButton#MotionButton(android.content.Context, android.util.AttributeSet) parameter #0:
@@ -1127,6 +1117,8 @@
Missing nullability on parameter `context` in method `MotionButton`
MissingNullability: androidx.constraintlayout.utils.widget.MotionButton#MotionButton(android.content.Context, android.util.AttributeSet, int) parameter #1:
Missing nullability on parameter `attrs` in method `MotionButton`
+MissingNullability: androidx.constraintlayout.utils.widget.MotionButton#draw(android.graphics.Canvas) parameter #0:
+ Missing nullability on parameter `canvas` in method `draw`
MissingNullability: androidx.constraintlayout.utils.widget.MotionLabel#MotionLabel(android.content.Context) parameter #0:
Missing nullability on parameter `context` in method `MotionLabel`
MissingNullability: androidx.constraintlayout.utils.widget.MotionLabel#MotionLabel(android.content.Context, android.util.AttributeSet) parameter #0:
@@ -1135,6 +1127,8 @@
Missing nullability on parameter `context` in method `MotionLabel`
MissingNullability: androidx.constraintlayout.utils.widget.MotionLabel#getTypeface():
Missing nullability on method `getTypeface` return
+MissingNullability: androidx.constraintlayout.utils.widget.MotionLabel#onDraw(android.graphics.Canvas) parameter #0:
+ Missing nullability on parameter `canvas` in method `onDraw`
MissingNullability: androidx.constraintlayout.utils.widget.MotionLabel#setText(CharSequence) parameter #0:
Missing nullability on parameter `text` in method `setText`
MissingNullability: androidx.constraintlayout.utils.widget.MotionLabel#setTypeface(android.graphics.Typeface) parameter #0:
@@ -1149,6 +1143,8 @@
Missing nullability on parameter `context` in method `MotionTelltales`
MissingNullability: androidx.constraintlayout.utils.widget.MotionTelltales#MotionTelltales(android.content.Context, android.util.AttributeSet, int) parameter #1:
Missing nullability on parameter `attrs` in method `MotionTelltales`
+MissingNullability: androidx.constraintlayout.utils.widget.MotionTelltales#onDraw(android.graphics.Canvas) parameter #0:
+ Missing nullability on parameter `canvas` in method `onDraw`
MissingNullability: androidx.constraintlayout.utils.widget.MotionTelltales#setText(CharSequence) parameter #0:
Missing nullability on parameter `text` in method `setText`
MissingNullability: androidx.constraintlayout.widget.Barrier#Barrier(android.content.Context) parameter #0:
@@ -1267,6 +1263,8 @@
Missing nullability on field `mReferenceTags` in class `class androidx.constraintlayout.widget.ConstraintHelper`
MissingNullability: androidx.constraintlayout.widget.ConstraintHelper#myContext:
Missing nullability on field `myContext` in class `class androidx.constraintlayout.widget.ConstraintHelper`
+MissingNullability: androidx.constraintlayout.widget.ConstraintHelper#onDraw(android.graphics.Canvas) parameter #0:
+ Missing nullability on parameter `canvas` in method `onDraw`
MissingNullability: androidx.constraintlayout.widget.ConstraintHelper#removeView(android.view.View) parameter #0:
Missing nullability on parameter `view` in method `removeView`
MissingNullability: androidx.constraintlayout.widget.ConstraintHelper#resolveRtl(androidx.constraintlayout.core.widgets.ConstraintWidget, boolean) parameter #0:
@@ -1713,6 +1711,8 @@
Missing nullability on parameter `context` in method `Guideline`
MissingNullability: androidx.constraintlayout.widget.Guideline#Guideline(android.content.Context, android.util.AttributeSet, int, int) parameter #1:
Missing nullability on parameter `attrs` in method `Guideline`
+MissingNullability: androidx.constraintlayout.widget.Guideline#draw(android.graphics.Canvas) parameter #0:
+ Missing nullability on parameter `canvas` in method `draw`
MissingNullability: androidx.constraintlayout.widget.Placeholder#Placeholder(android.content.Context) parameter #0:
Missing nullability on parameter `context` in method `Placeholder`
MissingNullability: androidx.constraintlayout.widget.Placeholder#Placeholder(android.content.Context, android.util.AttributeSet) parameter #0:
@@ -1729,6 +1729,8 @@
Missing nullability on parameter `attrs` in method `Placeholder`
MissingNullability: androidx.constraintlayout.widget.Placeholder#getContent():
Missing nullability on method `getContent` return
+MissingNullability: androidx.constraintlayout.widget.Placeholder#onDraw(android.graphics.Canvas) parameter #0:
+ Missing nullability on parameter `canvas` in method `onDraw`
MissingNullability: androidx.constraintlayout.widget.Placeholder#updatePostMeasure(androidx.constraintlayout.widget.ConstraintLayout) parameter #0:
Missing nullability on parameter `container` in method `updatePostMeasure`
MissingNullability: androidx.constraintlayout.widget.Placeholder#updatePreLayout(androidx.constraintlayout.widget.ConstraintLayout) parameter #0:
@@ -1747,6 +1749,8 @@
Missing nullability on parameter `context` in method `ReactiveGuide`
MissingNullability: androidx.constraintlayout.widget.ReactiveGuide#ReactiveGuide(android.content.Context, android.util.AttributeSet, int, int) parameter #1:
Missing nullability on parameter `attrs` in method `ReactiveGuide`
+MissingNullability: androidx.constraintlayout.widget.ReactiveGuide#draw(android.graphics.Canvas) parameter #0:
+ Missing nullability on parameter `canvas` in method `draw`
MissingNullability: androidx.constraintlayout.widget.SharedValues#addListener(int, androidx.constraintlayout.widget.SharedValues.SharedValuesListener) parameter #1:
Missing nullability on parameter `listener` in method `addListener`
MissingNullability: androidx.constraintlayout.widget.SharedValues#removeListener(androidx.constraintlayout.widget.SharedValues.SharedValuesListener) parameter #0:
diff --git a/coordinatorlayout/coordinatorlayout/api/api_lint.ignore b/coordinatorlayout/coordinatorlayout/api/api_lint.ignore
index f200680..06d3c6e 100644
--- a/coordinatorlayout/coordinatorlayout/api/api_lint.ignore
+++ b/coordinatorlayout/coordinatorlayout/api/api_lint.ignore
@@ -1,6 +1,4 @@
// Baseline format: 1.0
-InvalidNullabilityOverride: androidx.coordinatorlayout.widget.CoordinatorLayout#onDraw(android.graphics.Canvas) parameter #0:
- Invalid nullability on parameter `c` in method `onDraw`. Parameters of overrides cannot be NonNull if the super parameter is unannotated.
InvalidNullabilityOverride: androidx.coordinatorlayout.widget.CoordinatorLayout#onNestedPreScroll(android.view.View, int, int, int[]) parameter #0:
Invalid nullability on parameter `target` in method `onNestedPreScroll`. Parameters of overrides cannot be NonNull if the super parameter is unannotated.
InvalidNullabilityOverride: androidx.coordinatorlayout.widget.CoordinatorLayout#onNestedPreScroll(android.view.View, int, int, int[]) parameter #3:
@@ -35,6 +33,8 @@
Missing nullability on method `generateLayoutParams` return
MissingNullability: androidx.coordinatorlayout.widget.CoordinatorLayout#generateLayoutParams(android.view.ViewGroup.LayoutParams) parameter #0:
Missing nullability on parameter `p` in method `generateLayoutParams`
+MissingNullability: androidx.coordinatorlayout.widget.CoordinatorLayout#onDraw(android.graphics.Canvas) parameter #0:
+ Missing nullability on parameter `c` in method `onDraw`
MissingNullability: androidx.coordinatorlayout.widget.CoordinatorLayout#onInterceptTouchEvent(android.view.MotionEvent) parameter #0:
Missing nullability on parameter `ev` in method `onInterceptTouchEvent`
MissingNullability: androidx.coordinatorlayout.widget.CoordinatorLayout#onNestedFling(android.view.View, float, float, boolean) parameter #0:
diff --git a/coordinatorlayout/coordinatorlayout/lint-baseline.xml b/coordinatorlayout/coordinatorlayout/lint-baseline.xml
index eb4748e..b3144af 100644
--- a/coordinatorlayout/coordinatorlayout/lint-baseline.xml
+++ b/coordinatorlayout/coordinatorlayout/lint-baseline.xml
@@ -1,5 +1,14 @@
<?xml version="1.0" encoding="UTF-8"?>
-<issues format="6" by="lint 7.4.0-alpha08" type="baseline" client="gradle" dependencies="false" name="AGP (7.4.0-alpha08)" variant="all" version="7.4.0-alpha08">
+<issues format="6" by="lint 8.0.0-alpha07" type="baseline" client="gradle" dependencies="false" name="AGP (8.0.0-alpha07)" variant="all" version="8.0.0-alpha07">
+
+ <issue
+ id="UnknownNullness"
+ message="Unknown nullability; explicitly declare as `@Nullable` or `@NonNull` to improve Kotlin interoperability; see https://developer.android.com/kotlin/interop#nullability_annotations"
+ errorLine1=" protected boolean drawChild(Canvas canvas, View child, long drawingTime) {"
+ errorLine2=" ~~~~~~">
+ <location
+ file="src/main/java/androidx/coordinatorlayout/widget/CoordinatorLayout.java"/>
+ </issue>
<issue
id="UnknownNullness"
diff --git a/core/core-ktx/api/1.10.0-beta01.txt b/core/core-ktx/api/1.10.0-beta01.txt
new file mode 100644
index 0000000..801b56b
--- /dev/null
+++ b/core/core-ktx/api/1.10.0-beta01.txt
@@ -0,0 +1,634 @@
+// Signature format: 4.0
+package androidx.core.animation {
+
+ public final class AnimatorKt {
+ method public static inline android.animation.Animator.AnimatorListener addListener(android.animation.Animator, optional kotlin.jvm.functions.Function1<? super android.animation.Animator,kotlin.Unit> onEnd, optional kotlin.jvm.functions.Function1<? super android.animation.Animator,kotlin.Unit> onStart, optional kotlin.jvm.functions.Function1<? super android.animation.Animator,kotlin.Unit> onCancel, optional kotlin.jvm.functions.Function1<? super android.animation.Animator,kotlin.Unit> onRepeat);
+ method @RequiresApi(19) public static android.animation.Animator.AnimatorPauseListener addPauseListener(android.animation.Animator, optional kotlin.jvm.functions.Function1<? super android.animation.Animator,kotlin.Unit> onResume, optional kotlin.jvm.functions.Function1<? super android.animation.Animator,kotlin.Unit> onPause);
+ method public static inline android.animation.Animator.AnimatorListener doOnCancel(android.animation.Animator, kotlin.jvm.functions.Function1<? super android.animation.Animator,kotlin.Unit> action);
+ method public static inline android.animation.Animator.AnimatorListener doOnEnd(android.animation.Animator, kotlin.jvm.functions.Function1<? super android.animation.Animator,kotlin.Unit> action);
+ method @RequiresApi(19) public static android.animation.Animator.AnimatorPauseListener doOnPause(android.animation.Animator, kotlin.jvm.functions.Function1<? super android.animation.Animator,kotlin.Unit> action);
+ method public static inline android.animation.Animator.AnimatorListener doOnRepeat(android.animation.Animator, kotlin.jvm.functions.Function1<? super android.animation.Animator,kotlin.Unit> action);
+ method @RequiresApi(19) public static android.animation.Animator.AnimatorPauseListener doOnResume(android.animation.Animator, kotlin.jvm.functions.Function1<? super android.animation.Animator,kotlin.Unit> action);
+ method public static inline android.animation.Animator.AnimatorListener doOnStart(android.animation.Animator, kotlin.jvm.functions.Function1<? super android.animation.Animator,kotlin.Unit> action);
+ }
+
+}
+
+package androidx.core.content {
+
+ public final class ContentValuesKt {
+ method public static android.content.ContentValues contentValuesOf(kotlin.Pair<java.lang.String,?>... pairs);
+ }
+
+ public final class ContextKt {
+ method public static inline <reified T> T! getSystemService(android.content.Context);
+ method public static inline void withStyledAttributes(android.content.Context, optional android.util.AttributeSet? set, int[] attrs, optional @AttrRes int defStyleAttr, optional @StyleRes int defStyleRes, kotlin.jvm.functions.Function1<? super android.content.res.TypedArray,kotlin.Unit> block);
+ method public static inline void withStyledAttributes(android.content.Context, @StyleRes int resourceId, int[] attrs, kotlin.jvm.functions.Function1<? super android.content.res.TypedArray,kotlin.Unit> block);
+ }
+
+ public final class SharedPreferencesKt {
+ method public static inline void edit(android.content.SharedPreferences, optional boolean commit, kotlin.jvm.functions.Function1<? super android.content.SharedPreferences.Editor,kotlin.Unit> action);
+ }
+
+}
+
+package androidx.core.content.res {
+
+ public final class TypedArrayKt {
+ method public static boolean getBooleanOrThrow(android.content.res.TypedArray, @StyleableRes int index);
+ method @ColorInt public static int getColorOrThrow(android.content.res.TypedArray, @StyleableRes int index);
+ method public static android.content.res.ColorStateList getColorStateListOrThrow(android.content.res.TypedArray, @StyleableRes int index);
+ method public static float getDimensionOrThrow(android.content.res.TypedArray, @StyleableRes int index);
+ method @Dimension public static int getDimensionPixelOffsetOrThrow(android.content.res.TypedArray, @StyleableRes int index);
+ method @Dimension public static int getDimensionPixelSizeOrThrow(android.content.res.TypedArray, @StyleableRes int index);
+ method public static android.graphics.drawable.Drawable getDrawableOrThrow(android.content.res.TypedArray, @StyleableRes int index);
+ method public static float getFloatOrThrow(android.content.res.TypedArray, @StyleableRes int index);
+ method @RequiresApi(26) public static android.graphics.Typeface getFontOrThrow(android.content.res.TypedArray, @StyleableRes int index);
+ method public static int getIntOrThrow(android.content.res.TypedArray, @StyleableRes int index);
+ method public static int getIntegerOrThrow(android.content.res.TypedArray, @StyleableRes int index);
+ method @AnyRes public static int getResourceIdOrThrow(android.content.res.TypedArray, @StyleableRes int index);
+ method public static String getStringOrThrow(android.content.res.TypedArray, @StyleableRes int index);
+ method public static CharSequence![] getTextArrayOrThrow(android.content.res.TypedArray, @StyleableRes int index);
+ method public static CharSequence getTextOrThrow(android.content.res.TypedArray, @StyleableRes int index);
+ method public static inline <R> R! use(android.content.res.TypedArray, kotlin.jvm.functions.Function1<? super android.content.res.TypedArray,? extends R> block);
+ }
+
+}
+
+package androidx.core.database {
+
+ public final class CursorKt {
+ method public static inline byte[]? getBlobOrNull(android.database.Cursor, int index);
+ method public static inline Double? getDoubleOrNull(android.database.Cursor, int index);
+ method public static inline Float? getFloatOrNull(android.database.Cursor, int index);
+ method public static inline Integer? getIntOrNull(android.database.Cursor, int index);
+ method public static inline Long? getLongOrNull(android.database.Cursor, int index);
+ method public static inline Short? getShortOrNull(android.database.Cursor, int index);
+ method public static inline String? getStringOrNull(android.database.Cursor, int index);
+ }
+
+}
+
+package androidx.core.database.sqlite {
+
+ public final class SQLiteDatabaseKt {
+ method public static inline <T> T! transaction(android.database.sqlite.SQLiteDatabase, optional boolean exclusive, kotlin.jvm.functions.Function1<? super android.database.sqlite.SQLiteDatabase,? extends T> body);
+ }
+
+}
+
+package androidx.core.graphics {
+
+ public final class BitmapKt {
+ method public static inline android.graphics.Bitmap applyCanvas(android.graphics.Bitmap, kotlin.jvm.functions.Function1<? super android.graphics.Canvas,kotlin.Unit> block);
+ method public static inline operator boolean contains(android.graphics.Bitmap, android.graphics.Point p);
+ method public static inline operator boolean contains(android.graphics.Bitmap, android.graphics.PointF p);
+ method public static inline android.graphics.Bitmap createBitmap(int width, int height, optional android.graphics.Bitmap.Config config);
+ method @RequiresApi(26) public static inline android.graphics.Bitmap createBitmap(int width, int height, optional android.graphics.Bitmap.Config config, optional boolean hasAlpha, optional android.graphics.ColorSpace colorSpace);
+ method public static inline operator int get(android.graphics.Bitmap, int x, int y);
+ method public static inline android.graphics.Bitmap scale(android.graphics.Bitmap, int width, int height, optional boolean filter);
+ method public static inline operator void set(android.graphics.Bitmap, int x, int y, @ColorInt int color);
+ }
+
+ public final class CanvasKt {
+ method public static inline void withClip(android.graphics.Canvas, android.graphics.Rect clipRect, kotlin.jvm.functions.Function1<? super android.graphics.Canvas,kotlin.Unit> block);
+ method public static inline void withClip(android.graphics.Canvas, android.graphics.RectF clipRect, kotlin.jvm.functions.Function1<? super android.graphics.Canvas,kotlin.Unit> block);
+ method public static inline void withClip(android.graphics.Canvas, int left, int top, int right, int bottom, kotlin.jvm.functions.Function1<? super android.graphics.Canvas,kotlin.Unit> block);
+ method public static inline void withClip(android.graphics.Canvas, float left, float top, float right, float bottom, kotlin.jvm.functions.Function1<? super android.graphics.Canvas,kotlin.Unit> block);
+ method public static inline void withClip(android.graphics.Canvas, android.graphics.Path clipPath, kotlin.jvm.functions.Function1<? super android.graphics.Canvas,kotlin.Unit> block);
+ method public static inline void withMatrix(android.graphics.Canvas, optional android.graphics.Matrix matrix, kotlin.jvm.functions.Function1<? super android.graphics.Canvas,kotlin.Unit> block);
+ method public static inline void withRotation(android.graphics.Canvas, optional float degrees, optional float pivotX, optional float pivotY, kotlin.jvm.functions.Function1<? super android.graphics.Canvas,kotlin.Unit> block);
+ method public static inline void withSave(android.graphics.Canvas, kotlin.jvm.functions.Function1<? super android.graphics.Canvas,kotlin.Unit> block);
+ method public static inline void withScale(android.graphics.Canvas, optional float x, optional float y, optional float pivotX, optional float pivotY, kotlin.jvm.functions.Function1<? super android.graphics.Canvas,kotlin.Unit> block);
+ method public static inline void withSkew(android.graphics.Canvas, optional float x, optional float y, kotlin.jvm.functions.Function1<? super android.graphics.Canvas,kotlin.Unit> block);
+ method public static inline void withTranslation(android.graphics.Canvas, optional float x, optional float y, kotlin.jvm.functions.Function1<? super android.graphics.Canvas,kotlin.Unit> block);
+ }
+
+ public final class ColorKt {
+ method @RequiresApi(26) public static inline operator float component1(android.graphics.Color);
+ method public static inline operator int component1(@ColorInt int);
+ method @RequiresApi(26) public static inline operator float component1(@ColorLong long);
+ method @RequiresApi(26) public static inline operator float component2(android.graphics.Color);
+ method public static inline operator int component2(@ColorInt int);
+ method @RequiresApi(26) public static inline operator float component2(@ColorLong long);
+ method @RequiresApi(26) public static inline operator float component3(android.graphics.Color);
+ method public static inline operator int component3(@ColorInt int);
+ method @RequiresApi(26) public static inline operator float component3(@ColorLong long);
+ method @RequiresApi(26) public static inline operator float component4(android.graphics.Color);
+ method public static inline operator int component4(@ColorInt int);
+ method @RequiresApi(26) public static inline operator float component4(@ColorLong long);
+ method @ColorLong @RequiresApi(26) public static inline infix long convertTo(@ColorInt int, android.graphics.ColorSpace.Named colorSpace);
+ method @ColorLong @RequiresApi(26) public static inline infix long convertTo(@ColorInt int, android.graphics.ColorSpace colorSpace);
+ method @ColorLong @RequiresApi(26) public static inline infix long convertTo(@ColorLong long, android.graphics.ColorSpace.Named colorSpace);
+ method @ColorLong @RequiresApi(26) public static inline infix long convertTo(@ColorLong long, android.graphics.ColorSpace colorSpace);
+ method @RequiresApi(26) public static inline infix android.graphics.Color convertTo(android.graphics.Color, android.graphics.ColorSpace.Named colorSpace);
+ method @RequiresApi(26) public static inline infix android.graphics.Color convertTo(android.graphics.Color, android.graphics.ColorSpace colorSpace);
+ method public static inline int getAlpha(@ColorInt int);
+ method @RequiresApi(26) public static inline float getAlpha(@ColorLong long);
+ method public static inline int getBlue(@ColorInt int);
+ method @RequiresApi(26) public static inline float getBlue(@ColorLong long);
+ method @RequiresApi(26) public static inline android.graphics.ColorSpace getColorSpace(@ColorLong long);
+ method public static inline int getGreen(@ColorInt int);
+ method @RequiresApi(26) public static inline float getGreen(@ColorLong long);
+ method @RequiresApi(26) public static inline float getLuminance(@ColorInt int);
+ method @RequiresApi(26) public static inline float getLuminance(@ColorLong long);
+ method public static inline int getRed(@ColorInt int);
+ method @RequiresApi(26) public static inline float getRed(@ColorLong long);
+ method @RequiresApi(26) public static inline boolean isSrgb(@ColorLong long);
+ method @RequiresApi(26) public static inline boolean isWideGamut(@ColorLong long);
+ method @RequiresApi(26) public static operator android.graphics.Color plus(android.graphics.Color, android.graphics.Color c);
+ method @RequiresApi(26) public static inline android.graphics.Color toColor(@ColorInt int);
+ method @RequiresApi(26) public static inline android.graphics.Color toColor(@ColorLong long);
+ method @ColorInt @RequiresApi(26) public static inline int toColorInt(@ColorLong long);
+ method @ColorInt public static inline int toColorInt(String);
+ method @ColorLong @RequiresApi(26) public static inline long toColorLong(@ColorInt int);
+ }
+
+ public final class ImageDecoderKt {
+ method @RequiresApi(28) public static inline android.graphics.Bitmap decodeBitmap(android.graphics.ImageDecoder.Source, kotlin.jvm.functions.Function3<? super android.graphics.ImageDecoder,? super android.graphics.ImageDecoder.ImageInfo,? super android.graphics.ImageDecoder.Source,kotlin.Unit> action);
+ method @RequiresApi(28) public static inline android.graphics.drawable.Drawable decodeDrawable(android.graphics.ImageDecoder.Source, kotlin.jvm.functions.Function3<? super android.graphics.ImageDecoder,? super android.graphics.ImageDecoder.ImageInfo,? super android.graphics.ImageDecoder.Source,kotlin.Unit> action);
+ }
+
+ public final class MatrixKt {
+ method public static android.graphics.Matrix rotationMatrix(float degrees, optional float px, optional float py);
+ method public static android.graphics.Matrix scaleMatrix(optional float sx, optional float sy);
+ method public static inline operator android.graphics.Matrix times(android.graphics.Matrix, android.graphics.Matrix m);
+ method public static android.graphics.Matrix translationMatrix(optional float tx, optional float ty);
+ method public static inline float[] values(android.graphics.Matrix);
+ }
+
+ public final class PaintKt {
+ method public static inline boolean setBlendMode(android.graphics.Paint, androidx.core.graphics.BlendModeCompat? blendModeCompat);
+ }
+
+ public final class PathKt {
+ method @RequiresApi(19) public static inline infix android.graphics.Path and(android.graphics.Path, android.graphics.Path p);
+ method @RequiresApi(26) public static Iterable<androidx.core.graphics.PathSegment> flatten(android.graphics.Path, optional float error);
+ method @RequiresApi(19) public static inline operator android.graphics.Path minus(android.graphics.Path, android.graphics.Path p);
+ method @RequiresApi(19) public static inline infix android.graphics.Path or(android.graphics.Path, android.graphics.Path p);
+ method @RequiresApi(19) public static inline operator android.graphics.Path plus(android.graphics.Path, android.graphics.Path p);
+ method @RequiresApi(19) public static inline infix android.graphics.Path xor(android.graphics.Path, android.graphics.Path p);
+ }
+
+ public final class PictureKt {
+ method public static inline android.graphics.Picture record(android.graphics.Picture, int width, int height, kotlin.jvm.functions.Function1<? super android.graphics.Canvas,kotlin.Unit> block);
+ }
+
+ public final class PointKt {
+ method public static inline operator int component1(android.graphics.Point);
+ method public static inline operator float component1(android.graphics.PointF);
+ method public static inline operator int component2(android.graphics.Point);
+ method public static inline operator float component2(android.graphics.PointF);
+ method public static inline operator android.graphics.Point div(android.graphics.Point, float scalar);
+ method public static inline operator android.graphics.PointF div(android.graphics.PointF, float scalar);
+ method public static inline operator android.graphics.Point minus(android.graphics.Point, android.graphics.Point p);
+ method public static inline operator android.graphics.PointF minus(android.graphics.PointF, android.graphics.PointF p);
+ method public static inline operator android.graphics.Point minus(android.graphics.Point, int xy);
+ method public static inline operator android.graphics.PointF minus(android.graphics.PointF, float xy);
+ method public static inline operator android.graphics.Point plus(android.graphics.Point, android.graphics.Point p);
+ method public static inline operator android.graphics.PointF plus(android.graphics.PointF, android.graphics.PointF p);
+ method public static inline operator android.graphics.Point plus(android.graphics.Point, int xy);
+ method public static inline operator android.graphics.PointF plus(android.graphics.PointF, float xy);
+ method public static inline operator android.graphics.Point times(android.graphics.Point, float scalar);
+ method public static inline operator android.graphics.PointF times(android.graphics.PointF, float scalar);
+ method public static inline android.graphics.Point toPoint(android.graphics.PointF);
+ method public static inline android.graphics.PointF toPointF(android.graphics.Point);
+ method public static inline operator android.graphics.Point unaryMinus(android.graphics.Point);
+ method public static inline operator android.graphics.PointF unaryMinus(android.graphics.PointF);
+ }
+
+ public final class PorterDuffKt {
+ method public static inline android.graphics.PorterDuffColorFilter toColorFilter(android.graphics.PorterDuff.Mode, int color);
+ method public static inline android.graphics.PorterDuffXfermode toXfermode(android.graphics.PorterDuff.Mode);
+ }
+
+ public final class RectKt {
+ method public static inline infix android.graphics.Rect and(android.graphics.Rect, android.graphics.Rect r);
+ method public static inline infix android.graphics.RectF and(android.graphics.RectF, android.graphics.RectF r);
+ method public static inline operator int component1(android.graphics.Rect);
+ method public static inline operator float component1(android.graphics.RectF);
+ method public static inline operator int component2(android.graphics.Rect);
+ method public static inline operator float component2(android.graphics.RectF);
+ method public static inline operator int component3(android.graphics.Rect);
+ method public static inline operator float component3(android.graphics.RectF);
+ method public static inline operator int component4(android.graphics.Rect);
+ method public static inline operator float component4(android.graphics.RectF);
+ method public static inline operator boolean contains(android.graphics.Rect, android.graphics.Point p);
+ method public static inline operator boolean contains(android.graphics.RectF, android.graphics.PointF p);
+ method public static inline operator android.graphics.Region minus(android.graphics.Rect, android.graphics.Rect r);
+ method public static inline operator android.graphics.Region minus(android.graphics.RectF, android.graphics.RectF r);
+ method public static inline operator android.graphics.Rect minus(android.graphics.Rect, int xy);
+ method public static inline operator android.graphics.RectF minus(android.graphics.RectF, float xy);
+ method public static inline operator android.graphics.Rect minus(android.graphics.Rect, android.graphics.Point xy);
+ method public static inline operator android.graphics.RectF minus(android.graphics.RectF, android.graphics.PointF xy);
+ method public static inline infix android.graphics.Rect or(android.graphics.Rect, android.graphics.Rect r);
+ method public static inline infix android.graphics.RectF or(android.graphics.RectF, android.graphics.RectF r);
+ method public static inline operator android.graphics.Rect plus(android.graphics.Rect, android.graphics.Rect r);
+ method public static inline operator android.graphics.RectF plus(android.graphics.RectF, android.graphics.RectF r);
+ method public static inline operator android.graphics.Rect plus(android.graphics.Rect, int xy);
+ method public static inline operator android.graphics.RectF plus(android.graphics.RectF, float xy);
+ method public static inline operator android.graphics.Rect plus(android.graphics.Rect, android.graphics.Point xy);
+ method public static inline operator android.graphics.RectF plus(android.graphics.RectF, android.graphics.PointF xy);
+ method public static inline operator android.graphics.Rect times(android.graphics.Rect, int factor);
+ method public static inline operator android.graphics.RectF times(android.graphics.RectF, int factor);
+ method public static inline operator android.graphics.RectF times(android.graphics.RectF, float factor);
+ method public static inline android.graphics.Rect toRect(android.graphics.RectF);
+ method public static inline android.graphics.RectF toRectF(android.graphics.Rect);
+ method public static inline android.graphics.Region toRegion(android.graphics.Rect);
+ method public static inline android.graphics.Region toRegion(android.graphics.RectF);
+ method public static inline android.graphics.RectF transform(android.graphics.RectF, android.graphics.Matrix m);
+ method public static inline infix android.graphics.Region xor(android.graphics.Rect, android.graphics.Rect r);
+ method public static inline infix android.graphics.Region xor(android.graphics.RectF, android.graphics.RectF r);
+ }
+
+ public final class RegionKt {
+ method public static inline infix android.graphics.Region and(android.graphics.Region, android.graphics.Rect r);
+ method public static inline infix android.graphics.Region and(android.graphics.Region, android.graphics.Region r);
+ method public static inline operator boolean contains(android.graphics.Region, android.graphics.Point p);
+ method public static inline void forEach(android.graphics.Region, kotlin.jvm.functions.Function1<? super android.graphics.Rect,kotlin.Unit> action);
+ method public static operator java.util.Iterator<android.graphics.Rect> iterator(android.graphics.Region);
+ method public static inline operator android.graphics.Region minus(android.graphics.Region, android.graphics.Rect r);
+ method public static inline operator android.graphics.Region minus(android.graphics.Region, android.graphics.Region r);
+ method public static inline operator android.graphics.Region not(android.graphics.Region);
+ method public static inline infix android.graphics.Region or(android.graphics.Region, android.graphics.Rect r);
+ method public static inline infix android.graphics.Region or(android.graphics.Region, android.graphics.Region r);
+ method public static inline operator android.graphics.Region plus(android.graphics.Region, android.graphics.Rect r);
+ method public static inline operator android.graphics.Region plus(android.graphics.Region, android.graphics.Region r);
+ method public static inline operator android.graphics.Region unaryMinus(android.graphics.Region);
+ method public static inline infix android.graphics.Region xor(android.graphics.Region, android.graphics.Rect r);
+ method public static inline infix android.graphics.Region xor(android.graphics.Region, android.graphics.Region r);
+ }
+
+ public final class ShaderKt {
+ method public static inline void transform(android.graphics.Shader, kotlin.jvm.functions.Function1<? super android.graphics.Matrix,kotlin.Unit> block);
+ }
+
+}
+
+package androidx.core.graphics.drawable {
+
+ public final class BitmapDrawableKt {
+ method public static inline android.graphics.drawable.BitmapDrawable toDrawable(android.graphics.Bitmap, android.content.res.Resources resources);
+ }
+
+ public final class ColorDrawableKt {
+ method public static inline android.graphics.drawable.ColorDrawable toDrawable(@ColorInt int);
+ method @RequiresApi(26) public static inline android.graphics.drawable.ColorDrawable toDrawable(android.graphics.Color);
+ }
+
+ public final class DrawableKt {
+ method public static android.graphics.Bitmap toBitmap(android.graphics.drawable.Drawable, optional @Px int width, optional @Px int height, optional android.graphics.Bitmap.Config? config);
+ method public static android.graphics.Bitmap? toBitmapOrNull(android.graphics.drawable.Drawable, optional @Px int width, optional @Px int height, optional android.graphics.Bitmap.Config? config);
+ method public static void updateBounds(android.graphics.drawable.Drawable, optional @Px int left, optional @Px int top, optional @Px int right, optional @Px int bottom);
+ }
+
+ public final class IconKt {
+ method @RequiresApi(26) public static inline android.graphics.drawable.Icon toAdaptiveIcon(android.graphics.Bitmap);
+ method @RequiresApi(26) public static inline android.graphics.drawable.Icon toIcon(android.graphics.Bitmap);
+ method @RequiresApi(26) public static inline android.graphics.drawable.Icon toIcon(android.net.Uri);
+ method @RequiresApi(26) public static inline android.graphics.drawable.Icon toIcon(byte[]);
+ }
+
+}
+
+package androidx.core.location {
+
+ public final class LocationKt {
+ method public static inline operator double component1(android.location.Location);
+ method public static inline operator double component2(android.location.Location);
+ }
+
+}
+
+package androidx.core.net {
+
+ public final class UriKt {
+ method public static java.io.File toFile(android.net.Uri);
+ method public static inline android.net.Uri toUri(String);
+ method public static inline android.net.Uri toUri(java.io.File);
+ }
+
+}
+
+package androidx.core.os {
+
+ public final class BundleKt {
+ method public static android.os.Bundle bundleOf(kotlin.Pair<java.lang.String,?>... pairs);
+ method public static android.os.Bundle bundleOf();
+ }
+
+ public final class HandlerKt {
+ method public static inline Runnable postAtTime(android.os.Handler, long uptimeMillis, optional Object? token, kotlin.jvm.functions.Function0<kotlin.Unit> action);
+ method public static inline Runnable postDelayed(android.os.Handler, long delayInMillis, optional Object? token, kotlin.jvm.functions.Function0<kotlin.Unit> action);
+ }
+
+ @RequiresApi(31) public final class OutcomeReceiverKt {
+ method @RequiresApi(31) public static <R, E extends java.lang.Throwable> android.os.OutcomeReceiver<R,E> asOutcomeReceiver(kotlin.coroutines.Continuation<? super R>);
+ }
+
+ public final class PersistableBundleKt {
+ method @RequiresApi(21) public static android.os.PersistableBundle persistableBundleOf(kotlin.Pair<java.lang.String,?>... pairs);
+ method @RequiresApi(21) public static android.os.PersistableBundle persistableBundleOf();
+ method @RequiresApi(21) public static android.os.PersistableBundle toPersistableBundle(java.util.Map<java.lang.String,?>);
+ }
+
+ public final class TraceKt {
+ method @Deprecated public static inline <T> T! trace(String sectionName, kotlin.jvm.functions.Function0<? extends T> block);
+ }
+
+}
+
+package androidx.core.text {
+
+ public final class CharSequenceKt {
+ method public static inline boolean isDigitsOnly(CharSequence);
+ method public static inline int trimmedLength(CharSequence);
+ }
+
+ public final class HtmlKt {
+ method public static inline android.text.Spanned parseAsHtml(String, optional int flags, optional android.text.Html.ImageGetter? imageGetter, optional android.text.Html.TagHandler? tagHandler);
+ method public static inline String toHtml(android.text.Spanned, optional int option);
+ }
+
+ public final class LocaleKt {
+ method @RequiresApi(17) public static inline int getLayoutDirection(java.util.Locale);
+ }
+
+ public final class SpannableStringBuilderKt {
+ method public static inline android.text.SpannableStringBuilder backgroundColor(android.text.SpannableStringBuilder, @ColorInt int color, kotlin.jvm.functions.Function1<? super android.text.SpannableStringBuilder,kotlin.Unit> builderAction);
+ method public static inline android.text.SpannableStringBuilder bold(android.text.SpannableStringBuilder, kotlin.jvm.functions.Function1<? super android.text.SpannableStringBuilder,kotlin.Unit> builderAction);
+ method public static inline android.text.SpannedString buildSpannedString(kotlin.jvm.functions.Function1<? super android.text.SpannableStringBuilder,kotlin.Unit> builderAction);
+ method public static inline android.text.SpannableStringBuilder color(android.text.SpannableStringBuilder, @ColorInt int color, kotlin.jvm.functions.Function1<? super android.text.SpannableStringBuilder,kotlin.Unit> builderAction);
+ method public static inline android.text.SpannableStringBuilder inSpans(android.text.SpannableStringBuilder, Object![] spans, kotlin.jvm.functions.Function1<? super android.text.SpannableStringBuilder,kotlin.Unit> builderAction);
+ method public static inline android.text.SpannableStringBuilder inSpans(android.text.SpannableStringBuilder, Object span, kotlin.jvm.functions.Function1<? super android.text.SpannableStringBuilder,kotlin.Unit> builderAction);
+ method public static inline android.text.SpannableStringBuilder italic(android.text.SpannableStringBuilder, kotlin.jvm.functions.Function1<? super android.text.SpannableStringBuilder,kotlin.Unit> builderAction);
+ method public static inline android.text.SpannableStringBuilder scale(android.text.SpannableStringBuilder, float proportion, kotlin.jvm.functions.Function1<? super android.text.SpannableStringBuilder,kotlin.Unit> builderAction);
+ method public static inline android.text.SpannableStringBuilder strikeThrough(android.text.SpannableStringBuilder, kotlin.jvm.functions.Function1<? super android.text.SpannableStringBuilder,kotlin.Unit> builderAction);
+ method public static inline android.text.SpannableStringBuilder subscript(android.text.SpannableStringBuilder, kotlin.jvm.functions.Function1<? super android.text.SpannableStringBuilder,kotlin.Unit> builderAction);
+ method public static inline android.text.SpannableStringBuilder superscript(android.text.SpannableStringBuilder, kotlin.jvm.functions.Function1<? super android.text.SpannableStringBuilder,kotlin.Unit> builderAction);
+ method public static inline android.text.SpannableStringBuilder underline(android.text.SpannableStringBuilder, kotlin.jvm.functions.Function1<? super android.text.SpannableStringBuilder,kotlin.Unit> builderAction);
+ }
+
+ public final class SpannableStringKt {
+ method public static inline void clearSpans(android.text.Spannable);
+ method public static inline operator void set(android.text.Spannable, int start, int end, Object span);
+ method public static inline operator void set(android.text.Spannable, kotlin.ranges.IntRange range, Object span);
+ method public static inline android.text.Spannable toSpannable(CharSequence);
+ }
+
+ public final class SpannedStringKt {
+ method public static inline <reified T> T![] getSpans(android.text.Spanned, optional int start, optional int end);
+ method public static inline android.text.Spanned toSpanned(CharSequence);
+ }
+
+ public final class StringKt {
+ method public static inline String htmlEncode(String);
+ }
+
+}
+
+package androidx.core.transition {
+
+ public final class TransitionKt {
+ method @RequiresApi(19) public static inline android.transition.Transition.TransitionListener addListener(android.transition.Transition, optional kotlin.jvm.functions.Function1<? super android.transition.Transition,kotlin.Unit> onEnd, optional kotlin.jvm.functions.Function1<? super android.transition.Transition,kotlin.Unit> onStart, optional kotlin.jvm.functions.Function1<? super android.transition.Transition,kotlin.Unit> onCancel, optional kotlin.jvm.functions.Function1<? super android.transition.Transition,kotlin.Unit> onResume, optional kotlin.jvm.functions.Function1<? super android.transition.Transition,kotlin.Unit> onPause);
+ method @RequiresApi(19) public static inline android.transition.Transition.TransitionListener doOnCancel(android.transition.Transition, kotlin.jvm.functions.Function1<? super android.transition.Transition,kotlin.Unit> action);
+ method @RequiresApi(19) public static inline android.transition.Transition.TransitionListener doOnEnd(android.transition.Transition, kotlin.jvm.functions.Function1<? super android.transition.Transition,kotlin.Unit> action);
+ method @RequiresApi(19) public static inline android.transition.Transition.TransitionListener doOnPause(android.transition.Transition, kotlin.jvm.functions.Function1<? super android.transition.Transition,kotlin.Unit> action);
+ method @RequiresApi(19) public static inline android.transition.Transition.TransitionListener doOnResume(android.transition.Transition, kotlin.jvm.functions.Function1<? super android.transition.Transition,kotlin.Unit> action);
+ method @RequiresApi(19) public static inline android.transition.Transition.TransitionListener doOnStart(android.transition.Transition, kotlin.jvm.functions.Function1<? super android.transition.Transition,kotlin.Unit> action);
+ }
+
+}
+
+package androidx.core.util {
+
+ public final class AndroidXConsumerKt {
+ method public static <T> androidx.core.util.Consumer<T> asAndroidXConsumer(kotlin.coroutines.Continuation<? super T>);
+ }
+
+ public final class AtomicFileKt {
+ method @RequiresApi(17) public static inline byte[] readBytes(android.util.AtomicFile);
+ method @RequiresApi(17) public static String readText(android.util.AtomicFile, optional java.nio.charset.Charset charset);
+ method @RequiresApi(17) public static inline void tryWrite(android.util.AtomicFile, kotlin.jvm.functions.Function1<? super java.io.FileOutputStream,kotlin.Unit> block);
+ method @RequiresApi(17) public static void writeBytes(android.util.AtomicFile, byte[] array);
+ method @RequiresApi(17) public static void writeText(android.util.AtomicFile, String text, optional java.nio.charset.Charset charset);
+ }
+
+ @RequiresApi(24) public final class ConsumerKt {
+ method @RequiresApi(24) public static <T> java.util.function.Consumer<T> asConsumer(kotlin.coroutines.Continuation<? super T>);
+ }
+
+ public final class HalfKt {
+ method @RequiresApi(26) public static inline android.util.Half toHalf(@HalfFloat short);
+ method @RequiresApi(26) public static inline android.util.Half toHalf(float);
+ method @RequiresApi(26) public static inline android.util.Half toHalf(double);
+ method @RequiresApi(26) public static inline android.util.Half toHalf(String);
+ }
+
+ public final class LongSparseArrayKt {
+ method @RequiresApi(16) public static inline operator <T> boolean contains(android.util.LongSparseArray<T>, long key);
+ method @RequiresApi(16) public static inline <T> boolean containsKey(android.util.LongSparseArray<T>, long key);
+ method @RequiresApi(16) public static inline <T> boolean containsValue(android.util.LongSparseArray<T>, T? value);
+ method @RequiresApi(16) public static inline <T> void forEach(android.util.LongSparseArray<T>, kotlin.jvm.functions.Function2<? super java.lang.Long,? super T,kotlin.Unit> action);
+ method @RequiresApi(16) public static inline <T> T! getOrDefault(android.util.LongSparseArray<T>, long key, T? defaultValue);
+ method @RequiresApi(16) public static inline <T> T! getOrElse(android.util.LongSparseArray<T>, long key, kotlin.jvm.functions.Function0<? extends T> defaultValue);
+ method @RequiresApi(16) public static inline <T> int getSize(android.util.LongSparseArray<T>);
+ method @RequiresApi(16) public static inline <T> boolean isEmpty(android.util.LongSparseArray<T>);
+ method @RequiresApi(16) public static inline <T> boolean isNotEmpty(android.util.LongSparseArray<T>);
+ method @RequiresApi(16) public static <T> kotlin.collections.LongIterator keyIterator(android.util.LongSparseArray<T>);
+ method @RequiresApi(16) public static operator <T> android.util.LongSparseArray<T> plus(android.util.LongSparseArray<T>, android.util.LongSparseArray<T> other);
+ method @RequiresApi(16) public static <T> void putAll(android.util.LongSparseArray<T>, android.util.LongSparseArray<T> other);
+ method @RequiresApi(16) public static <T> boolean remove(android.util.LongSparseArray<T>, long key, T? value);
+ method @RequiresApi(16) public static inline operator <T> void set(android.util.LongSparseArray<T>, long key, T? value);
+ method @RequiresApi(16) public static <T> java.util.Iterator<T> valueIterator(android.util.LongSparseArray<T>);
+ }
+
+ public final class LruCacheKt {
+ method public static inline <K, V> android.util.LruCache<K,V> lruCache(int maxSize, optional kotlin.jvm.functions.Function2<? super K,? super V,java.lang.Integer> sizeOf, optional kotlin.jvm.functions.Function1<? super K,? extends V> create, optional kotlin.jvm.functions.Function4<? super java.lang.Boolean,? super K,? super V,? super V,kotlin.Unit> onEntryRemoved);
+ }
+
+ public final class PairKt {
+ method public static inline operator <F, S> F! component1(androidx.core.util.Pair<F,S>);
+ method public static inline operator <F, S> F! component1(android.util.Pair<F,S>);
+ method public static inline operator <F, S> S! component2(androidx.core.util.Pair<F,S>);
+ method public static inline operator <F, S> S! component2(android.util.Pair<F,S>);
+ method public static inline <F, S> android.util.Pair<F,S> toAndroidPair(kotlin.Pair<? extends F,? extends S>);
+ method public static inline <F, S> androidx.core.util.Pair<F,S> toAndroidXPair(kotlin.Pair<? extends F,? extends S>);
+ method public static inline <F, S> kotlin.Pair<F,S> toKotlinPair(androidx.core.util.Pair<F,S>);
+ method public static inline <F, S> kotlin.Pair<F,S> toKotlinPair(android.util.Pair<F,S>);
+ }
+
+ public final class RangeKt {
+ method @RequiresApi(21) public static inline infix <T extends java.lang.Comparable<? super T>> android.util.Range<T> and(android.util.Range<T>, android.util.Range<T> other);
+ method @RequiresApi(21) public static inline operator <T extends java.lang.Comparable<? super T>> android.util.Range<T> plus(android.util.Range<T>, T value);
+ method @RequiresApi(21) public static inline operator <T extends java.lang.Comparable<? super T>> android.util.Range<T> plus(android.util.Range<T>, android.util.Range<T> other);
+ method @RequiresApi(21) public static inline infix <T extends java.lang.Comparable<? super T>> android.util.Range<T> rangeTo(T, T that);
+ method @RequiresApi(21) public static <T extends java.lang.Comparable<? super T>> kotlin.ranges.ClosedRange<T> toClosedRange(android.util.Range<T>);
+ method @RequiresApi(21) public static <T extends java.lang.Comparable<? super T>> android.util.Range<T> toRange(kotlin.ranges.ClosedRange<T>);
+ }
+
+ public final class RunnableKt {
+ method public static Runnable asRunnable(kotlin.coroutines.Continuation<? super kotlin.Unit>);
+ }
+
+ public final class SizeKt {
+ method @RequiresApi(21) public static inline operator int component1(android.util.Size);
+ method @RequiresApi(21) public static inline operator float component1(android.util.SizeF);
+ method public static inline operator float component1(androidx.core.util.SizeFCompat);
+ method @RequiresApi(21) public static inline operator int component2(android.util.Size);
+ method @RequiresApi(21) public static inline operator float component2(android.util.SizeF);
+ method public static inline operator float component2(androidx.core.util.SizeFCompat);
+ }
+
+ public final class SparseArrayKt {
+ method public static inline operator <T> boolean contains(android.util.SparseArray<T>, int key);
+ method public static inline <T> boolean containsKey(android.util.SparseArray<T>, int key);
+ method public static inline <T> boolean containsValue(android.util.SparseArray<T>, T? value);
+ method public static inline <T> void forEach(android.util.SparseArray<T>, kotlin.jvm.functions.Function2<? super java.lang.Integer,? super T,kotlin.Unit> action);
+ method public static inline <T> T! getOrDefault(android.util.SparseArray<T>, int key, T? defaultValue);
+ method public static inline <T> T! getOrElse(android.util.SparseArray<T>, int key, kotlin.jvm.functions.Function0<? extends T> defaultValue);
+ method public static inline <T> int getSize(android.util.SparseArray<T>);
+ method public static inline <T> boolean isEmpty(android.util.SparseArray<T>);
+ method public static inline <T> boolean isNotEmpty(android.util.SparseArray<T>);
+ method public static <T> kotlin.collections.IntIterator keyIterator(android.util.SparseArray<T>);
+ method public static operator <T> android.util.SparseArray<T> plus(android.util.SparseArray<T>, android.util.SparseArray<T> other);
+ method public static <T> void putAll(android.util.SparseArray<T>, android.util.SparseArray<T> other);
+ method public static <T> boolean remove(android.util.SparseArray<T>, int key, T? value);
+ method public static inline operator <T> void set(android.util.SparseArray<T>, int key, T? value);
+ method public static <T> java.util.Iterator<T> valueIterator(android.util.SparseArray<T>);
+ }
+
+ public final class SparseBooleanArrayKt {
+ method public static inline operator boolean contains(android.util.SparseBooleanArray, int key);
+ method public static inline boolean containsKey(android.util.SparseBooleanArray, int key);
+ method public static inline boolean containsValue(android.util.SparseBooleanArray, boolean value);
+ method public static inline void forEach(android.util.SparseBooleanArray, kotlin.jvm.functions.Function2<? super java.lang.Integer,? super java.lang.Boolean,kotlin.Unit> action);
+ method public static inline boolean getOrDefault(android.util.SparseBooleanArray, int key, boolean defaultValue);
+ method public static inline boolean getOrElse(android.util.SparseBooleanArray, int key, kotlin.jvm.functions.Function0<java.lang.Boolean> defaultValue);
+ method public static inline int getSize(android.util.SparseBooleanArray);
+ method public static inline boolean isEmpty(android.util.SparseBooleanArray);
+ method public static inline boolean isNotEmpty(android.util.SparseBooleanArray);
+ method public static kotlin.collections.IntIterator keyIterator(android.util.SparseBooleanArray);
+ method public static operator android.util.SparseBooleanArray plus(android.util.SparseBooleanArray, android.util.SparseBooleanArray other);
+ method public static void putAll(android.util.SparseBooleanArray, android.util.SparseBooleanArray other);
+ method public static boolean remove(android.util.SparseBooleanArray, int key, boolean value);
+ method public static inline operator void set(android.util.SparseBooleanArray, int key, boolean value);
+ method public static kotlin.collections.BooleanIterator valueIterator(android.util.SparseBooleanArray);
+ }
+
+ public final class SparseIntArrayKt {
+ method public static inline operator boolean contains(android.util.SparseIntArray, int key);
+ method public static inline boolean containsKey(android.util.SparseIntArray, int key);
+ method public static inline boolean containsValue(android.util.SparseIntArray, int value);
+ method public static inline void forEach(android.util.SparseIntArray, kotlin.jvm.functions.Function2<? super java.lang.Integer,? super java.lang.Integer,kotlin.Unit> action);
+ method public static inline int getOrDefault(android.util.SparseIntArray, int key, int defaultValue);
+ method public static inline int getOrElse(android.util.SparseIntArray, int key, kotlin.jvm.functions.Function0<java.lang.Integer> defaultValue);
+ method public static inline int getSize(android.util.SparseIntArray);
+ method public static inline boolean isEmpty(android.util.SparseIntArray);
+ method public static inline boolean isNotEmpty(android.util.SparseIntArray);
+ method public static kotlin.collections.IntIterator keyIterator(android.util.SparseIntArray);
+ method public static operator android.util.SparseIntArray plus(android.util.SparseIntArray, android.util.SparseIntArray other);
+ method public static void putAll(android.util.SparseIntArray, android.util.SparseIntArray other);
+ method public static boolean remove(android.util.SparseIntArray, int key, int value);
+ method public static inline operator void set(android.util.SparseIntArray, int key, int value);
+ method public static kotlin.collections.IntIterator valueIterator(android.util.SparseIntArray);
+ }
+
+ public final class SparseLongArrayKt {
+ method @RequiresApi(18) public static inline operator boolean contains(android.util.SparseLongArray, int key);
+ method @RequiresApi(18) public static inline boolean containsKey(android.util.SparseLongArray, int key);
+ method @RequiresApi(18) public static inline boolean containsValue(android.util.SparseLongArray, long value);
+ method @RequiresApi(18) public static inline void forEach(android.util.SparseLongArray, kotlin.jvm.functions.Function2<? super java.lang.Integer,? super java.lang.Long,kotlin.Unit> action);
+ method @RequiresApi(18) public static inline long getOrDefault(android.util.SparseLongArray, int key, long defaultValue);
+ method @RequiresApi(18) public static inline long getOrElse(android.util.SparseLongArray, int key, kotlin.jvm.functions.Function0<java.lang.Long> defaultValue);
+ method @RequiresApi(18) public static inline int getSize(android.util.SparseLongArray);
+ method @RequiresApi(18) public static inline boolean isEmpty(android.util.SparseLongArray);
+ method @RequiresApi(18) public static inline boolean isNotEmpty(android.util.SparseLongArray);
+ method @RequiresApi(18) public static kotlin.collections.IntIterator keyIterator(android.util.SparseLongArray);
+ method @RequiresApi(18) public static operator android.util.SparseLongArray plus(android.util.SparseLongArray, android.util.SparseLongArray other);
+ method @RequiresApi(18) public static void putAll(android.util.SparseLongArray, android.util.SparseLongArray other);
+ method @RequiresApi(18) public static boolean remove(android.util.SparseLongArray, int key, long value);
+ method @RequiresApi(18) public static inline operator void set(android.util.SparseLongArray, int key, long value);
+ method @RequiresApi(18) public static kotlin.collections.LongIterator valueIterator(android.util.SparseLongArray);
+ }
+
+}
+
+package androidx.core.view {
+
+ public final class MenuKt {
+ method public static operator boolean contains(android.view.Menu, android.view.MenuItem item);
+ method public static inline void forEach(android.view.Menu, kotlin.jvm.functions.Function1<? super android.view.MenuItem,kotlin.Unit> action);
+ method public static inline void forEachIndexed(android.view.Menu, kotlin.jvm.functions.Function2<? super java.lang.Integer,? super android.view.MenuItem,kotlin.Unit> action);
+ method public static inline operator android.view.MenuItem get(android.view.Menu, int index);
+ method public static kotlin.sequences.Sequence<android.view.MenuItem> getChildren(android.view.Menu);
+ method public static inline int getSize(android.view.Menu);
+ method public static inline boolean isEmpty(android.view.Menu);
+ method public static inline boolean isNotEmpty(android.view.Menu);
+ method public static operator java.util.Iterator<android.view.MenuItem> iterator(android.view.Menu);
+ method public static inline operator void minusAssign(android.view.Menu, android.view.MenuItem item);
+ method public static inline void removeItemAt(android.view.Menu, int index);
+ }
+
+ public final class ViewGroupKt {
+ method public static inline operator boolean contains(android.view.ViewGroup, android.view.View view);
+ method public static inline void forEach(android.view.ViewGroup, kotlin.jvm.functions.Function1<? super android.view.View,kotlin.Unit> action);
+ method public static inline void forEachIndexed(android.view.ViewGroup, kotlin.jvm.functions.Function2<? super java.lang.Integer,? super android.view.View,kotlin.Unit> action);
+ method public static operator android.view.View get(android.view.ViewGroup, int index);
+ method public static kotlin.sequences.Sequence<android.view.View> getChildren(android.view.ViewGroup);
+ method public static kotlin.sequences.Sequence<android.view.View> getDescendants(android.view.ViewGroup);
+ method public static inline kotlin.ranges.IntRange getIndices(android.view.ViewGroup);
+ method public static inline int getSize(android.view.ViewGroup);
+ method public static inline boolean isEmpty(android.view.ViewGroup);
+ method public static inline boolean isNotEmpty(android.view.ViewGroup);
+ method public static operator java.util.Iterator<android.view.View> iterator(android.view.ViewGroup);
+ method public static inline operator void minusAssign(android.view.ViewGroup, android.view.View view);
+ method public static inline operator void plusAssign(android.view.ViewGroup, android.view.View view);
+ method public static inline void setMargins(android.view.ViewGroup.MarginLayoutParams, @Px int size);
+ method public static inline void updateMargins(android.view.ViewGroup.MarginLayoutParams, optional @Px int left, optional @Px int top, optional @Px int right, optional @Px int bottom);
+ method @RequiresApi(17) public static inline void updateMarginsRelative(android.view.ViewGroup.MarginLayoutParams, optional @Px int start, optional @Px int top, optional @Px int end, optional @Px int bottom);
+ }
+
+ public final class ViewKt {
+ method public static inline void doOnAttach(android.view.View, kotlin.jvm.functions.Function1<? super android.view.View,kotlin.Unit> action);
+ method public static inline void doOnDetach(android.view.View, kotlin.jvm.functions.Function1<? super android.view.View,kotlin.Unit> action);
+ method public static inline void doOnLayout(android.view.View, kotlin.jvm.functions.Function1<? super android.view.View,kotlin.Unit> action);
+ method public static inline void doOnNextLayout(android.view.View, kotlin.jvm.functions.Function1<? super android.view.View,kotlin.Unit> action);
+ method public static inline androidx.core.view.OneShotPreDrawListener doOnPreDraw(android.view.View, kotlin.jvm.functions.Function1<? super android.view.View,kotlin.Unit> action);
+ method public static android.graphics.Bitmap drawToBitmap(android.view.View, optional android.graphics.Bitmap.Config config);
+ method public static kotlin.sequences.Sequence<android.view.View> getAllViews(android.view.View);
+ method public static kotlin.sequences.Sequence<android.view.ViewParent> getAncestors(android.view.View);
+ method public static inline int getMarginBottom(android.view.View);
+ method public static inline int getMarginEnd(android.view.View);
+ method public static inline int getMarginLeft(android.view.View);
+ method public static inline int getMarginRight(android.view.View);
+ method public static inline int getMarginStart(android.view.View);
+ method public static inline int getMarginTop(android.view.View);
+ method public static inline boolean isGone(android.view.View);
+ method public static inline boolean isInvisible(android.view.View);
+ method public static inline boolean isVisible(android.view.View);
+ method public static inline Runnable postDelayed(android.view.View, long delayInMillis, kotlin.jvm.functions.Function0<kotlin.Unit> action);
+ method @RequiresApi(16) public static Runnable postOnAnimationDelayed(android.view.View, long delayInMillis, kotlin.jvm.functions.Function0<kotlin.Unit> action);
+ method public static inline void setGone(android.view.View, boolean);
+ method public static inline void setInvisible(android.view.View, boolean);
+ method public static inline void setPadding(android.view.View, @Px int size);
+ method public static inline void setVisible(android.view.View, boolean);
+ method public static inline void updateLayoutParams(android.view.View, kotlin.jvm.functions.Function1<? super android.view.ViewGroup.LayoutParams,kotlin.Unit> block);
+ method public static inline <reified T extends android.view.ViewGroup.LayoutParams> void updateLayoutParams(android.view.View, kotlin.jvm.functions.Function1<? super T,? extends kotlin.Unit> block);
+ method public static inline void updatePadding(android.view.View, optional @Px int left, optional @Px int top, optional @Px int right, optional @Px int bottom);
+ method @RequiresApi(17) public static inline void updatePaddingRelative(android.view.View, optional @Px int start, optional @Px int top, optional @Px int end, optional @Px int bottom);
+ }
+
+}
+
+package androidx.core.widget {
+
+ public final class TextViewKt {
+ method public static inline android.text.TextWatcher addTextChangedListener(android.widget.TextView, optional kotlin.jvm.functions.Function4<? super java.lang.CharSequence,? super java.lang.Integer,? super java.lang.Integer,? super java.lang.Integer,kotlin.Unit> beforeTextChanged, optional kotlin.jvm.functions.Function4<? super java.lang.CharSequence,? super java.lang.Integer,? super java.lang.Integer,? super java.lang.Integer,kotlin.Unit> onTextChanged, optional kotlin.jvm.functions.Function1<? super android.text.Editable,kotlin.Unit> afterTextChanged);
+ method public static inline android.text.TextWatcher doAfterTextChanged(android.widget.TextView, kotlin.jvm.functions.Function1<? super android.text.Editable,kotlin.Unit> action);
+ method public static inline android.text.TextWatcher doBeforeTextChanged(android.widget.TextView, kotlin.jvm.functions.Function4<? super java.lang.CharSequence,? super java.lang.Integer,? super java.lang.Integer,? super java.lang.Integer,kotlin.Unit> action);
+ method public static inline android.text.TextWatcher doOnTextChanged(android.widget.TextView, kotlin.jvm.functions.Function4<? super java.lang.CharSequence,? super java.lang.Integer,? super java.lang.Integer,? super java.lang.Integer,kotlin.Unit> action);
+ }
+
+}
+
diff --git a/core/core-ktx/api/public_plus_experimental_1.10.0-beta01.txt b/core/core-ktx/api/public_plus_experimental_1.10.0-beta01.txt
new file mode 100644
index 0000000..801b56b
--- /dev/null
+++ b/core/core-ktx/api/public_plus_experimental_1.10.0-beta01.txt
@@ -0,0 +1,634 @@
+// Signature format: 4.0
+package androidx.core.animation {
+
+ public final class AnimatorKt {
+ method public static inline android.animation.Animator.AnimatorListener addListener(android.animation.Animator, optional kotlin.jvm.functions.Function1<? super android.animation.Animator,kotlin.Unit> onEnd, optional kotlin.jvm.functions.Function1<? super android.animation.Animator,kotlin.Unit> onStart, optional kotlin.jvm.functions.Function1<? super android.animation.Animator,kotlin.Unit> onCancel, optional kotlin.jvm.functions.Function1<? super android.animation.Animator,kotlin.Unit> onRepeat);
+ method @RequiresApi(19) public static android.animation.Animator.AnimatorPauseListener addPauseListener(android.animation.Animator, optional kotlin.jvm.functions.Function1<? super android.animation.Animator,kotlin.Unit> onResume, optional kotlin.jvm.functions.Function1<? super android.animation.Animator,kotlin.Unit> onPause);
+ method public static inline android.animation.Animator.AnimatorListener doOnCancel(android.animation.Animator, kotlin.jvm.functions.Function1<? super android.animation.Animator,kotlin.Unit> action);
+ method public static inline android.animation.Animator.AnimatorListener doOnEnd(android.animation.Animator, kotlin.jvm.functions.Function1<? super android.animation.Animator,kotlin.Unit> action);
+ method @RequiresApi(19) public static android.animation.Animator.AnimatorPauseListener doOnPause(android.animation.Animator, kotlin.jvm.functions.Function1<? super android.animation.Animator,kotlin.Unit> action);
+ method public static inline android.animation.Animator.AnimatorListener doOnRepeat(android.animation.Animator, kotlin.jvm.functions.Function1<? super android.animation.Animator,kotlin.Unit> action);
+ method @RequiresApi(19) public static android.animation.Animator.AnimatorPauseListener doOnResume(android.animation.Animator, kotlin.jvm.functions.Function1<? super android.animation.Animator,kotlin.Unit> action);
+ method public static inline android.animation.Animator.AnimatorListener doOnStart(android.animation.Animator, kotlin.jvm.functions.Function1<? super android.animation.Animator,kotlin.Unit> action);
+ }
+
+}
+
+package androidx.core.content {
+
+ public final class ContentValuesKt {
+ method public static android.content.ContentValues contentValuesOf(kotlin.Pair<java.lang.String,?>... pairs);
+ }
+
+ public final class ContextKt {
+ method public static inline <reified T> T! getSystemService(android.content.Context);
+ method public static inline void withStyledAttributes(android.content.Context, optional android.util.AttributeSet? set, int[] attrs, optional @AttrRes int defStyleAttr, optional @StyleRes int defStyleRes, kotlin.jvm.functions.Function1<? super android.content.res.TypedArray,kotlin.Unit> block);
+ method public static inline void withStyledAttributes(android.content.Context, @StyleRes int resourceId, int[] attrs, kotlin.jvm.functions.Function1<? super android.content.res.TypedArray,kotlin.Unit> block);
+ }
+
+ public final class SharedPreferencesKt {
+ method public static inline void edit(android.content.SharedPreferences, optional boolean commit, kotlin.jvm.functions.Function1<? super android.content.SharedPreferences.Editor,kotlin.Unit> action);
+ }
+
+}
+
+package androidx.core.content.res {
+
+ public final class TypedArrayKt {
+ method public static boolean getBooleanOrThrow(android.content.res.TypedArray, @StyleableRes int index);
+ method @ColorInt public static int getColorOrThrow(android.content.res.TypedArray, @StyleableRes int index);
+ method public static android.content.res.ColorStateList getColorStateListOrThrow(android.content.res.TypedArray, @StyleableRes int index);
+ method public static float getDimensionOrThrow(android.content.res.TypedArray, @StyleableRes int index);
+ method @Dimension public static int getDimensionPixelOffsetOrThrow(android.content.res.TypedArray, @StyleableRes int index);
+ method @Dimension public static int getDimensionPixelSizeOrThrow(android.content.res.TypedArray, @StyleableRes int index);
+ method public static android.graphics.drawable.Drawable getDrawableOrThrow(android.content.res.TypedArray, @StyleableRes int index);
+ method public static float getFloatOrThrow(android.content.res.TypedArray, @StyleableRes int index);
+ method @RequiresApi(26) public static android.graphics.Typeface getFontOrThrow(android.content.res.TypedArray, @StyleableRes int index);
+ method public static int getIntOrThrow(android.content.res.TypedArray, @StyleableRes int index);
+ method public static int getIntegerOrThrow(android.content.res.TypedArray, @StyleableRes int index);
+ method @AnyRes public static int getResourceIdOrThrow(android.content.res.TypedArray, @StyleableRes int index);
+ method public static String getStringOrThrow(android.content.res.TypedArray, @StyleableRes int index);
+ method public static CharSequence![] getTextArrayOrThrow(android.content.res.TypedArray, @StyleableRes int index);
+ method public static CharSequence getTextOrThrow(android.content.res.TypedArray, @StyleableRes int index);
+ method public static inline <R> R! use(android.content.res.TypedArray, kotlin.jvm.functions.Function1<? super android.content.res.TypedArray,? extends R> block);
+ }
+
+}
+
+package androidx.core.database {
+
+ public final class CursorKt {
+ method public static inline byte[]? getBlobOrNull(android.database.Cursor, int index);
+ method public static inline Double? getDoubleOrNull(android.database.Cursor, int index);
+ method public static inline Float? getFloatOrNull(android.database.Cursor, int index);
+ method public static inline Integer? getIntOrNull(android.database.Cursor, int index);
+ method public static inline Long? getLongOrNull(android.database.Cursor, int index);
+ method public static inline Short? getShortOrNull(android.database.Cursor, int index);
+ method public static inline String? getStringOrNull(android.database.Cursor, int index);
+ }
+
+}
+
+package androidx.core.database.sqlite {
+
+ public final class SQLiteDatabaseKt {
+ method public static inline <T> T! transaction(android.database.sqlite.SQLiteDatabase, optional boolean exclusive, kotlin.jvm.functions.Function1<? super android.database.sqlite.SQLiteDatabase,? extends T> body);
+ }
+
+}
+
+package androidx.core.graphics {
+
+ public final class BitmapKt {
+ method public static inline android.graphics.Bitmap applyCanvas(android.graphics.Bitmap, kotlin.jvm.functions.Function1<? super android.graphics.Canvas,kotlin.Unit> block);
+ method public static inline operator boolean contains(android.graphics.Bitmap, android.graphics.Point p);
+ method public static inline operator boolean contains(android.graphics.Bitmap, android.graphics.PointF p);
+ method public static inline android.graphics.Bitmap createBitmap(int width, int height, optional android.graphics.Bitmap.Config config);
+ method @RequiresApi(26) public static inline android.graphics.Bitmap createBitmap(int width, int height, optional android.graphics.Bitmap.Config config, optional boolean hasAlpha, optional android.graphics.ColorSpace colorSpace);
+ method public static inline operator int get(android.graphics.Bitmap, int x, int y);
+ method public static inline android.graphics.Bitmap scale(android.graphics.Bitmap, int width, int height, optional boolean filter);
+ method public static inline operator void set(android.graphics.Bitmap, int x, int y, @ColorInt int color);
+ }
+
+ public final class CanvasKt {
+ method public static inline void withClip(android.graphics.Canvas, android.graphics.Rect clipRect, kotlin.jvm.functions.Function1<? super android.graphics.Canvas,kotlin.Unit> block);
+ method public static inline void withClip(android.graphics.Canvas, android.graphics.RectF clipRect, kotlin.jvm.functions.Function1<? super android.graphics.Canvas,kotlin.Unit> block);
+ method public static inline void withClip(android.graphics.Canvas, int left, int top, int right, int bottom, kotlin.jvm.functions.Function1<? super android.graphics.Canvas,kotlin.Unit> block);
+ method public static inline void withClip(android.graphics.Canvas, float left, float top, float right, float bottom, kotlin.jvm.functions.Function1<? super android.graphics.Canvas,kotlin.Unit> block);
+ method public static inline void withClip(android.graphics.Canvas, android.graphics.Path clipPath, kotlin.jvm.functions.Function1<? super android.graphics.Canvas,kotlin.Unit> block);
+ method public static inline void withMatrix(android.graphics.Canvas, optional android.graphics.Matrix matrix, kotlin.jvm.functions.Function1<? super android.graphics.Canvas,kotlin.Unit> block);
+ method public static inline void withRotation(android.graphics.Canvas, optional float degrees, optional float pivotX, optional float pivotY, kotlin.jvm.functions.Function1<? super android.graphics.Canvas,kotlin.Unit> block);
+ method public static inline void withSave(android.graphics.Canvas, kotlin.jvm.functions.Function1<? super android.graphics.Canvas,kotlin.Unit> block);
+ method public static inline void withScale(android.graphics.Canvas, optional float x, optional float y, optional float pivotX, optional float pivotY, kotlin.jvm.functions.Function1<? super android.graphics.Canvas,kotlin.Unit> block);
+ method public static inline void withSkew(android.graphics.Canvas, optional float x, optional float y, kotlin.jvm.functions.Function1<? super android.graphics.Canvas,kotlin.Unit> block);
+ method public static inline void withTranslation(android.graphics.Canvas, optional float x, optional float y, kotlin.jvm.functions.Function1<? super android.graphics.Canvas,kotlin.Unit> block);
+ }
+
+ public final class ColorKt {
+ method @RequiresApi(26) public static inline operator float component1(android.graphics.Color);
+ method public static inline operator int component1(@ColorInt int);
+ method @RequiresApi(26) public static inline operator float component1(@ColorLong long);
+ method @RequiresApi(26) public static inline operator float component2(android.graphics.Color);
+ method public static inline operator int component2(@ColorInt int);
+ method @RequiresApi(26) public static inline operator float component2(@ColorLong long);
+ method @RequiresApi(26) public static inline operator float component3(android.graphics.Color);
+ method public static inline operator int component3(@ColorInt int);
+ method @RequiresApi(26) public static inline operator float component3(@ColorLong long);
+ method @RequiresApi(26) public static inline operator float component4(android.graphics.Color);
+ method public static inline operator int component4(@ColorInt int);
+ method @RequiresApi(26) public static inline operator float component4(@ColorLong long);
+ method @ColorLong @RequiresApi(26) public static inline infix long convertTo(@ColorInt int, android.graphics.ColorSpace.Named colorSpace);
+ method @ColorLong @RequiresApi(26) public static inline infix long convertTo(@ColorInt int, android.graphics.ColorSpace colorSpace);
+ method @ColorLong @RequiresApi(26) public static inline infix long convertTo(@ColorLong long, android.graphics.ColorSpace.Named colorSpace);
+ method @ColorLong @RequiresApi(26) public static inline infix long convertTo(@ColorLong long, android.graphics.ColorSpace colorSpace);
+ method @RequiresApi(26) public static inline infix android.graphics.Color convertTo(android.graphics.Color, android.graphics.ColorSpace.Named colorSpace);
+ method @RequiresApi(26) public static inline infix android.graphics.Color convertTo(android.graphics.Color, android.graphics.ColorSpace colorSpace);
+ method public static inline int getAlpha(@ColorInt int);
+ method @RequiresApi(26) public static inline float getAlpha(@ColorLong long);
+ method public static inline int getBlue(@ColorInt int);
+ method @RequiresApi(26) public static inline float getBlue(@ColorLong long);
+ method @RequiresApi(26) public static inline android.graphics.ColorSpace getColorSpace(@ColorLong long);
+ method public static inline int getGreen(@ColorInt int);
+ method @RequiresApi(26) public static inline float getGreen(@ColorLong long);
+ method @RequiresApi(26) public static inline float getLuminance(@ColorInt int);
+ method @RequiresApi(26) public static inline float getLuminance(@ColorLong long);
+ method public static inline int getRed(@ColorInt int);
+ method @RequiresApi(26) public static inline float getRed(@ColorLong long);
+ method @RequiresApi(26) public static inline boolean isSrgb(@ColorLong long);
+ method @RequiresApi(26) public static inline boolean isWideGamut(@ColorLong long);
+ method @RequiresApi(26) public static operator android.graphics.Color plus(android.graphics.Color, android.graphics.Color c);
+ method @RequiresApi(26) public static inline android.graphics.Color toColor(@ColorInt int);
+ method @RequiresApi(26) public static inline android.graphics.Color toColor(@ColorLong long);
+ method @ColorInt @RequiresApi(26) public static inline int toColorInt(@ColorLong long);
+ method @ColorInt public static inline int toColorInt(String);
+ method @ColorLong @RequiresApi(26) public static inline long toColorLong(@ColorInt int);
+ }
+
+ public final class ImageDecoderKt {
+ method @RequiresApi(28) public static inline android.graphics.Bitmap decodeBitmap(android.graphics.ImageDecoder.Source, kotlin.jvm.functions.Function3<? super android.graphics.ImageDecoder,? super android.graphics.ImageDecoder.ImageInfo,? super android.graphics.ImageDecoder.Source,kotlin.Unit> action);
+ method @RequiresApi(28) public static inline android.graphics.drawable.Drawable decodeDrawable(android.graphics.ImageDecoder.Source, kotlin.jvm.functions.Function3<? super android.graphics.ImageDecoder,? super android.graphics.ImageDecoder.ImageInfo,? super android.graphics.ImageDecoder.Source,kotlin.Unit> action);
+ }
+
+ public final class MatrixKt {
+ method public static android.graphics.Matrix rotationMatrix(float degrees, optional float px, optional float py);
+ method public static android.graphics.Matrix scaleMatrix(optional float sx, optional float sy);
+ method public static inline operator android.graphics.Matrix times(android.graphics.Matrix, android.graphics.Matrix m);
+ method public static android.graphics.Matrix translationMatrix(optional float tx, optional float ty);
+ method public static inline float[] values(android.graphics.Matrix);
+ }
+
+ public final class PaintKt {
+ method public static inline boolean setBlendMode(android.graphics.Paint, androidx.core.graphics.BlendModeCompat? blendModeCompat);
+ }
+
+ public final class PathKt {
+ method @RequiresApi(19) public static inline infix android.graphics.Path and(android.graphics.Path, android.graphics.Path p);
+ method @RequiresApi(26) public static Iterable<androidx.core.graphics.PathSegment> flatten(android.graphics.Path, optional float error);
+ method @RequiresApi(19) public static inline operator android.graphics.Path minus(android.graphics.Path, android.graphics.Path p);
+ method @RequiresApi(19) public static inline infix android.graphics.Path or(android.graphics.Path, android.graphics.Path p);
+ method @RequiresApi(19) public static inline operator android.graphics.Path plus(android.graphics.Path, android.graphics.Path p);
+ method @RequiresApi(19) public static inline infix android.graphics.Path xor(android.graphics.Path, android.graphics.Path p);
+ }
+
+ public final class PictureKt {
+ method public static inline android.graphics.Picture record(android.graphics.Picture, int width, int height, kotlin.jvm.functions.Function1<? super android.graphics.Canvas,kotlin.Unit> block);
+ }
+
+ public final class PointKt {
+ method public static inline operator int component1(android.graphics.Point);
+ method public static inline operator float component1(android.graphics.PointF);
+ method public static inline operator int component2(android.graphics.Point);
+ method public static inline operator float component2(android.graphics.PointF);
+ method public static inline operator android.graphics.Point div(android.graphics.Point, float scalar);
+ method public static inline operator android.graphics.PointF div(android.graphics.PointF, float scalar);
+ method public static inline operator android.graphics.Point minus(android.graphics.Point, android.graphics.Point p);
+ method public static inline operator android.graphics.PointF minus(android.graphics.PointF, android.graphics.PointF p);
+ method public static inline operator android.graphics.Point minus(android.graphics.Point, int xy);
+ method public static inline operator android.graphics.PointF minus(android.graphics.PointF, float xy);
+ method public static inline operator android.graphics.Point plus(android.graphics.Point, android.graphics.Point p);
+ method public static inline operator android.graphics.PointF plus(android.graphics.PointF, android.graphics.PointF p);
+ method public static inline operator android.graphics.Point plus(android.graphics.Point, int xy);
+ method public static inline operator android.graphics.PointF plus(android.graphics.PointF, float xy);
+ method public static inline operator android.graphics.Point times(android.graphics.Point, float scalar);
+ method public static inline operator android.graphics.PointF times(android.graphics.PointF, float scalar);
+ method public static inline android.graphics.Point toPoint(android.graphics.PointF);
+ method public static inline android.graphics.PointF toPointF(android.graphics.Point);
+ method public static inline operator android.graphics.Point unaryMinus(android.graphics.Point);
+ method public static inline operator android.graphics.PointF unaryMinus(android.graphics.PointF);
+ }
+
+ public final class PorterDuffKt {
+ method public static inline android.graphics.PorterDuffColorFilter toColorFilter(android.graphics.PorterDuff.Mode, int color);
+ method public static inline android.graphics.PorterDuffXfermode toXfermode(android.graphics.PorterDuff.Mode);
+ }
+
+ public final class RectKt {
+ method public static inline infix android.graphics.Rect and(android.graphics.Rect, android.graphics.Rect r);
+ method public static inline infix android.graphics.RectF and(android.graphics.RectF, android.graphics.RectF r);
+ method public static inline operator int component1(android.graphics.Rect);
+ method public static inline operator float component1(android.graphics.RectF);
+ method public static inline operator int component2(android.graphics.Rect);
+ method public static inline operator float component2(android.graphics.RectF);
+ method public static inline operator int component3(android.graphics.Rect);
+ method public static inline operator float component3(android.graphics.RectF);
+ method public static inline operator int component4(android.graphics.Rect);
+ method public static inline operator float component4(android.graphics.RectF);
+ method public static inline operator boolean contains(android.graphics.Rect, android.graphics.Point p);
+ method public static inline operator boolean contains(android.graphics.RectF, android.graphics.PointF p);
+ method public static inline operator android.graphics.Region minus(android.graphics.Rect, android.graphics.Rect r);
+ method public static inline operator android.graphics.Region minus(android.graphics.RectF, android.graphics.RectF r);
+ method public static inline operator android.graphics.Rect minus(android.graphics.Rect, int xy);
+ method public static inline operator android.graphics.RectF minus(android.graphics.RectF, float xy);
+ method public static inline operator android.graphics.Rect minus(android.graphics.Rect, android.graphics.Point xy);
+ method public static inline operator android.graphics.RectF minus(android.graphics.RectF, android.graphics.PointF xy);
+ method public static inline infix android.graphics.Rect or(android.graphics.Rect, android.graphics.Rect r);
+ method public static inline infix android.graphics.RectF or(android.graphics.RectF, android.graphics.RectF r);
+ method public static inline operator android.graphics.Rect plus(android.graphics.Rect, android.graphics.Rect r);
+ method public static inline operator android.graphics.RectF plus(android.graphics.RectF, android.graphics.RectF r);
+ method public static inline operator android.graphics.Rect plus(android.graphics.Rect, int xy);
+ method public static inline operator android.graphics.RectF plus(android.graphics.RectF, float xy);
+ method public static inline operator android.graphics.Rect plus(android.graphics.Rect, android.graphics.Point xy);
+ method public static inline operator android.graphics.RectF plus(android.graphics.RectF, android.graphics.PointF xy);
+ method public static inline operator android.graphics.Rect times(android.graphics.Rect, int factor);
+ method public static inline operator android.graphics.RectF times(android.graphics.RectF, int factor);
+ method public static inline operator android.graphics.RectF times(android.graphics.RectF, float factor);
+ method public static inline android.graphics.Rect toRect(android.graphics.RectF);
+ method public static inline android.graphics.RectF toRectF(android.graphics.Rect);
+ method public static inline android.graphics.Region toRegion(android.graphics.Rect);
+ method public static inline android.graphics.Region toRegion(android.graphics.RectF);
+ method public static inline android.graphics.RectF transform(android.graphics.RectF, android.graphics.Matrix m);
+ method public static inline infix android.graphics.Region xor(android.graphics.Rect, android.graphics.Rect r);
+ method public static inline infix android.graphics.Region xor(android.graphics.RectF, android.graphics.RectF r);
+ }
+
+ public final class RegionKt {
+ method public static inline infix android.graphics.Region and(android.graphics.Region, android.graphics.Rect r);
+ method public static inline infix android.graphics.Region and(android.graphics.Region, android.graphics.Region r);
+ method public static inline operator boolean contains(android.graphics.Region, android.graphics.Point p);
+ method public static inline void forEach(android.graphics.Region, kotlin.jvm.functions.Function1<? super android.graphics.Rect,kotlin.Unit> action);
+ method public static operator java.util.Iterator<android.graphics.Rect> iterator(android.graphics.Region);
+ method public static inline operator android.graphics.Region minus(android.graphics.Region, android.graphics.Rect r);
+ method public static inline operator android.graphics.Region minus(android.graphics.Region, android.graphics.Region r);
+ method public static inline operator android.graphics.Region not(android.graphics.Region);
+ method public static inline infix android.graphics.Region or(android.graphics.Region, android.graphics.Rect r);
+ method public static inline infix android.graphics.Region or(android.graphics.Region, android.graphics.Region r);
+ method public static inline operator android.graphics.Region plus(android.graphics.Region, android.graphics.Rect r);
+ method public static inline operator android.graphics.Region plus(android.graphics.Region, android.graphics.Region r);
+ method public static inline operator android.graphics.Region unaryMinus(android.graphics.Region);
+ method public static inline infix android.graphics.Region xor(android.graphics.Region, android.graphics.Rect r);
+ method public static inline infix android.graphics.Region xor(android.graphics.Region, android.graphics.Region r);
+ }
+
+ public final class ShaderKt {
+ method public static inline void transform(android.graphics.Shader, kotlin.jvm.functions.Function1<? super android.graphics.Matrix,kotlin.Unit> block);
+ }
+
+}
+
+package androidx.core.graphics.drawable {
+
+ public final class BitmapDrawableKt {
+ method public static inline android.graphics.drawable.BitmapDrawable toDrawable(android.graphics.Bitmap, android.content.res.Resources resources);
+ }
+
+ public final class ColorDrawableKt {
+ method public static inline android.graphics.drawable.ColorDrawable toDrawable(@ColorInt int);
+ method @RequiresApi(26) public static inline android.graphics.drawable.ColorDrawable toDrawable(android.graphics.Color);
+ }
+
+ public final class DrawableKt {
+ method public static android.graphics.Bitmap toBitmap(android.graphics.drawable.Drawable, optional @Px int width, optional @Px int height, optional android.graphics.Bitmap.Config? config);
+ method public static android.graphics.Bitmap? toBitmapOrNull(android.graphics.drawable.Drawable, optional @Px int width, optional @Px int height, optional android.graphics.Bitmap.Config? config);
+ method public static void updateBounds(android.graphics.drawable.Drawable, optional @Px int left, optional @Px int top, optional @Px int right, optional @Px int bottom);
+ }
+
+ public final class IconKt {
+ method @RequiresApi(26) public static inline android.graphics.drawable.Icon toAdaptiveIcon(android.graphics.Bitmap);
+ method @RequiresApi(26) public static inline android.graphics.drawable.Icon toIcon(android.graphics.Bitmap);
+ method @RequiresApi(26) public static inline android.graphics.drawable.Icon toIcon(android.net.Uri);
+ method @RequiresApi(26) public static inline android.graphics.drawable.Icon toIcon(byte[]);
+ }
+
+}
+
+package androidx.core.location {
+
+ public final class LocationKt {
+ method public static inline operator double component1(android.location.Location);
+ method public static inline operator double component2(android.location.Location);
+ }
+
+}
+
+package androidx.core.net {
+
+ public final class UriKt {
+ method public static java.io.File toFile(android.net.Uri);
+ method public static inline android.net.Uri toUri(String);
+ method public static inline android.net.Uri toUri(java.io.File);
+ }
+
+}
+
+package androidx.core.os {
+
+ public final class BundleKt {
+ method public static android.os.Bundle bundleOf(kotlin.Pair<java.lang.String,?>... pairs);
+ method public static android.os.Bundle bundleOf();
+ }
+
+ public final class HandlerKt {
+ method public static inline Runnable postAtTime(android.os.Handler, long uptimeMillis, optional Object? token, kotlin.jvm.functions.Function0<kotlin.Unit> action);
+ method public static inline Runnable postDelayed(android.os.Handler, long delayInMillis, optional Object? token, kotlin.jvm.functions.Function0<kotlin.Unit> action);
+ }
+
+ @RequiresApi(31) public final class OutcomeReceiverKt {
+ method @RequiresApi(31) public static <R, E extends java.lang.Throwable> android.os.OutcomeReceiver<R,E> asOutcomeReceiver(kotlin.coroutines.Continuation<? super R>);
+ }
+
+ public final class PersistableBundleKt {
+ method @RequiresApi(21) public static android.os.PersistableBundle persistableBundleOf(kotlin.Pair<java.lang.String,?>... pairs);
+ method @RequiresApi(21) public static android.os.PersistableBundle persistableBundleOf();
+ method @RequiresApi(21) public static android.os.PersistableBundle toPersistableBundle(java.util.Map<java.lang.String,?>);
+ }
+
+ public final class TraceKt {
+ method @Deprecated public static inline <T> T! trace(String sectionName, kotlin.jvm.functions.Function0<? extends T> block);
+ }
+
+}
+
+package androidx.core.text {
+
+ public final class CharSequenceKt {
+ method public static inline boolean isDigitsOnly(CharSequence);
+ method public static inline int trimmedLength(CharSequence);
+ }
+
+ public final class HtmlKt {
+ method public static inline android.text.Spanned parseAsHtml(String, optional int flags, optional android.text.Html.ImageGetter? imageGetter, optional android.text.Html.TagHandler? tagHandler);
+ method public static inline String toHtml(android.text.Spanned, optional int option);
+ }
+
+ public final class LocaleKt {
+ method @RequiresApi(17) public static inline int getLayoutDirection(java.util.Locale);
+ }
+
+ public final class SpannableStringBuilderKt {
+ method public static inline android.text.SpannableStringBuilder backgroundColor(android.text.SpannableStringBuilder, @ColorInt int color, kotlin.jvm.functions.Function1<? super android.text.SpannableStringBuilder,kotlin.Unit> builderAction);
+ method public static inline android.text.SpannableStringBuilder bold(android.text.SpannableStringBuilder, kotlin.jvm.functions.Function1<? super android.text.SpannableStringBuilder,kotlin.Unit> builderAction);
+ method public static inline android.text.SpannedString buildSpannedString(kotlin.jvm.functions.Function1<? super android.text.SpannableStringBuilder,kotlin.Unit> builderAction);
+ method public static inline android.text.SpannableStringBuilder color(android.text.SpannableStringBuilder, @ColorInt int color, kotlin.jvm.functions.Function1<? super android.text.SpannableStringBuilder,kotlin.Unit> builderAction);
+ method public static inline android.text.SpannableStringBuilder inSpans(android.text.SpannableStringBuilder, Object![] spans, kotlin.jvm.functions.Function1<? super android.text.SpannableStringBuilder,kotlin.Unit> builderAction);
+ method public static inline android.text.SpannableStringBuilder inSpans(android.text.SpannableStringBuilder, Object span, kotlin.jvm.functions.Function1<? super android.text.SpannableStringBuilder,kotlin.Unit> builderAction);
+ method public static inline android.text.SpannableStringBuilder italic(android.text.SpannableStringBuilder, kotlin.jvm.functions.Function1<? super android.text.SpannableStringBuilder,kotlin.Unit> builderAction);
+ method public static inline android.text.SpannableStringBuilder scale(android.text.SpannableStringBuilder, float proportion, kotlin.jvm.functions.Function1<? super android.text.SpannableStringBuilder,kotlin.Unit> builderAction);
+ method public static inline android.text.SpannableStringBuilder strikeThrough(android.text.SpannableStringBuilder, kotlin.jvm.functions.Function1<? super android.text.SpannableStringBuilder,kotlin.Unit> builderAction);
+ method public static inline android.text.SpannableStringBuilder subscript(android.text.SpannableStringBuilder, kotlin.jvm.functions.Function1<? super android.text.SpannableStringBuilder,kotlin.Unit> builderAction);
+ method public static inline android.text.SpannableStringBuilder superscript(android.text.SpannableStringBuilder, kotlin.jvm.functions.Function1<? super android.text.SpannableStringBuilder,kotlin.Unit> builderAction);
+ method public static inline android.text.SpannableStringBuilder underline(android.text.SpannableStringBuilder, kotlin.jvm.functions.Function1<? super android.text.SpannableStringBuilder,kotlin.Unit> builderAction);
+ }
+
+ public final class SpannableStringKt {
+ method public static inline void clearSpans(android.text.Spannable);
+ method public static inline operator void set(android.text.Spannable, int start, int end, Object span);
+ method public static inline operator void set(android.text.Spannable, kotlin.ranges.IntRange range, Object span);
+ method public static inline android.text.Spannable toSpannable(CharSequence);
+ }
+
+ public final class SpannedStringKt {
+ method public static inline <reified T> T![] getSpans(android.text.Spanned, optional int start, optional int end);
+ method public static inline android.text.Spanned toSpanned(CharSequence);
+ }
+
+ public final class StringKt {
+ method public static inline String htmlEncode(String);
+ }
+
+}
+
+package androidx.core.transition {
+
+ public final class TransitionKt {
+ method @RequiresApi(19) public static inline android.transition.Transition.TransitionListener addListener(android.transition.Transition, optional kotlin.jvm.functions.Function1<? super android.transition.Transition,kotlin.Unit> onEnd, optional kotlin.jvm.functions.Function1<? super android.transition.Transition,kotlin.Unit> onStart, optional kotlin.jvm.functions.Function1<? super android.transition.Transition,kotlin.Unit> onCancel, optional kotlin.jvm.functions.Function1<? super android.transition.Transition,kotlin.Unit> onResume, optional kotlin.jvm.functions.Function1<? super android.transition.Transition,kotlin.Unit> onPause);
+ method @RequiresApi(19) public static inline android.transition.Transition.TransitionListener doOnCancel(android.transition.Transition, kotlin.jvm.functions.Function1<? super android.transition.Transition,kotlin.Unit> action);
+ method @RequiresApi(19) public static inline android.transition.Transition.TransitionListener doOnEnd(android.transition.Transition, kotlin.jvm.functions.Function1<? super android.transition.Transition,kotlin.Unit> action);
+ method @RequiresApi(19) public static inline android.transition.Transition.TransitionListener doOnPause(android.transition.Transition, kotlin.jvm.functions.Function1<? super android.transition.Transition,kotlin.Unit> action);
+ method @RequiresApi(19) public static inline android.transition.Transition.TransitionListener doOnResume(android.transition.Transition, kotlin.jvm.functions.Function1<? super android.transition.Transition,kotlin.Unit> action);
+ method @RequiresApi(19) public static inline android.transition.Transition.TransitionListener doOnStart(android.transition.Transition, kotlin.jvm.functions.Function1<? super android.transition.Transition,kotlin.Unit> action);
+ }
+
+}
+
+package androidx.core.util {
+
+ public final class AndroidXConsumerKt {
+ method public static <T> androidx.core.util.Consumer<T> asAndroidXConsumer(kotlin.coroutines.Continuation<? super T>);
+ }
+
+ public final class AtomicFileKt {
+ method @RequiresApi(17) public static inline byte[] readBytes(android.util.AtomicFile);
+ method @RequiresApi(17) public static String readText(android.util.AtomicFile, optional java.nio.charset.Charset charset);
+ method @RequiresApi(17) public static inline void tryWrite(android.util.AtomicFile, kotlin.jvm.functions.Function1<? super java.io.FileOutputStream,kotlin.Unit> block);
+ method @RequiresApi(17) public static void writeBytes(android.util.AtomicFile, byte[] array);
+ method @RequiresApi(17) public static void writeText(android.util.AtomicFile, String text, optional java.nio.charset.Charset charset);
+ }
+
+ @RequiresApi(24) public final class ConsumerKt {
+ method @RequiresApi(24) public static <T> java.util.function.Consumer<T> asConsumer(kotlin.coroutines.Continuation<? super T>);
+ }
+
+ public final class HalfKt {
+ method @RequiresApi(26) public static inline android.util.Half toHalf(@HalfFloat short);
+ method @RequiresApi(26) public static inline android.util.Half toHalf(float);
+ method @RequiresApi(26) public static inline android.util.Half toHalf(double);
+ method @RequiresApi(26) public static inline android.util.Half toHalf(String);
+ }
+
+ public final class LongSparseArrayKt {
+ method @RequiresApi(16) public static inline operator <T> boolean contains(android.util.LongSparseArray<T>, long key);
+ method @RequiresApi(16) public static inline <T> boolean containsKey(android.util.LongSparseArray<T>, long key);
+ method @RequiresApi(16) public static inline <T> boolean containsValue(android.util.LongSparseArray<T>, T? value);
+ method @RequiresApi(16) public static inline <T> void forEach(android.util.LongSparseArray<T>, kotlin.jvm.functions.Function2<? super java.lang.Long,? super T,kotlin.Unit> action);
+ method @RequiresApi(16) public static inline <T> T! getOrDefault(android.util.LongSparseArray<T>, long key, T? defaultValue);
+ method @RequiresApi(16) public static inline <T> T! getOrElse(android.util.LongSparseArray<T>, long key, kotlin.jvm.functions.Function0<? extends T> defaultValue);
+ method @RequiresApi(16) public static inline <T> int getSize(android.util.LongSparseArray<T>);
+ method @RequiresApi(16) public static inline <T> boolean isEmpty(android.util.LongSparseArray<T>);
+ method @RequiresApi(16) public static inline <T> boolean isNotEmpty(android.util.LongSparseArray<T>);
+ method @RequiresApi(16) public static <T> kotlin.collections.LongIterator keyIterator(android.util.LongSparseArray<T>);
+ method @RequiresApi(16) public static operator <T> android.util.LongSparseArray<T> plus(android.util.LongSparseArray<T>, android.util.LongSparseArray<T> other);
+ method @RequiresApi(16) public static <T> void putAll(android.util.LongSparseArray<T>, android.util.LongSparseArray<T> other);
+ method @RequiresApi(16) public static <T> boolean remove(android.util.LongSparseArray<T>, long key, T? value);
+ method @RequiresApi(16) public static inline operator <T> void set(android.util.LongSparseArray<T>, long key, T? value);
+ method @RequiresApi(16) public static <T> java.util.Iterator<T> valueIterator(android.util.LongSparseArray<T>);
+ }
+
+ public final class LruCacheKt {
+ method public static inline <K, V> android.util.LruCache<K,V> lruCache(int maxSize, optional kotlin.jvm.functions.Function2<? super K,? super V,java.lang.Integer> sizeOf, optional kotlin.jvm.functions.Function1<? super K,? extends V> create, optional kotlin.jvm.functions.Function4<? super java.lang.Boolean,? super K,? super V,? super V,kotlin.Unit> onEntryRemoved);
+ }
+
+ public final class PairKt {
+ method public static inline operator <F, S> F! component1(androidx.core.util.Pair<F,S>);
+ method public static inline operator <F, S> F! component1(android.util.Pair<F,S>);
+ method public static inline operator <F, S> S! component2(androidx.core.util.Pair<F,S>);
+ method public static inline operator <F, S> S! component2(android.util.Pair<F,S>);
+ method public static inline <F, S> android.util.Pair<F,S> toAndroidPair(kotlin.Pair<? extends F,? extends S>);
+ method public static inline <F, S> androidx.core.util.Pair<F,S> toAndroidXPair(kotlin.Pair<? extends F,? extends S>);
+ method public static inline <F, S> kotlin.Pair<F,S> toKotlinPair(androidx.core.util.Pair<F,S>);
+ method public static inline <F, S> kotlin.Pair<F,S> toKotlinPair(android.util.Pair<F,S>);
+ }
+
+ public final class RangeKt {
+ method @RequiresApi(21) public static inline infix <T extends java.lang.Comparable<? super T>> android.util.Range<T> and(android.util.Range<T>, android.util.Range<T> other);
+ method @RequiresApi(21) public static inline operator <T extends java.lang.Comparable<? super T>> android.util.Range<T> plus(android.util.Range<T>, T value);
+ method @RequiresApi(21) public static inline operator <T extends java.lang.Comparable<? super T>> android.util.Range<T> plus(android.util.Range<T>, android.util.Range<T> other);
+ method @RequiresApi(21) public static inline infix <T extends java.lang.Comparable<? super T>> android.util.Range<T> rangeTo(T, T that);
+ method @RequiresApi(21) public static <T extends java.lang.Comparable<? super T>> kotlin.ranges.ClosedRange<T> toClosedRange(android.util.Range<T>);
+ method @RequiresApi(21) public static <T extends java.lang.Comparable<? super T>> android.util.Range<T> toRange(kotlin.ranges.ClosedRange<T>);
+ }
+
+ public final class RunnableKt {
+ method public static Runnable asRunnable(kotlin.coroutines.Continuation<? super kotlin.Unit>);
+ }
+
+ public final class SizeKt {
+ method @RequiresApi(21) public static inline operator int component1(android.util.Size);
+ method @RequiresApi(21) public static inline operator float component1(android.util.SizeF);
+ method public static inline operator float component1(androidx.core.util.SizeFCompat);
+ method @RequiresApi(21) public static inline operator int component2(android.util.Size);
+ method @RequiresApi(21) public static inline operator float component2(android.util.SizeF);
+ method public static inline operator float component2(androidx.core.util.SizeFCompat);
+ }
+
+ public final class SparseArrayKt {
+ method public static inline operator <T> boolean contains(android.util.SparseArray<T>, int key);
+ method public static inline <T> boolean containsKey(android.util.SparseArray<T>, int key);
+ method public static inline <T> boolean containsValue(android.util.SparseArray<T>, T? value);
+ method public static inline <T> void forEach(android.util.SparseArray<T>, kotlin.jvm.functions.Function2<? super java.lang.Integer,? super T,kotlin.Unit> action);
+ method public static inline <T> T! getOrDefault(android.util.SparseArray<T>, int key, T? defaultValue);
+ method public static inline <T> T! getOrElse(android.util.SparseArray<T>, int key, kotlin.jvm.functions.Function0<? extends T> defaultValue);
+ method public static inline <T> int getSize(android.util.SparseArray<T>);
+ method public static inline <T> boolean isEmpty(android.util.SparseArray<T>);
+ method public static inline <T> boolean isNotEmpty(android.util.SparseArray<T>);
+ method public static <T> kotlin.collections.IntIterator keyIterator(android.util.SparseArray<T>);
+ method public static operator <T> android.util.SparseArray<T> plus(android.util.SparseArray<T>, android.util.SparseArray<T> other);
+ method public static <T> void putAll(android.util.SparseArray<T>, android.util.SparseArray<T> other);
+ method public static <T> boolean remove(android.util.SparseArray<T>, int key, T? value);
+ method public static inline operator <T> void set(android.util.SparseArray<T>, int key, T? value);
+ method public static <T> java.util.Iterator<T> valueIterator(android.util.SparseArray<T>);
+ }
+
+ public final class SparseBooleanArrayKt {
+ method public static inline operator boolean contains(android.util.SparseBooleanArray, int key);
+ method public static inline boolean containsKey(android.util.SparseBooleanArray, int key);
+ method public static inline boolean containsValue(android.util.SparseBooleanArray, boolean value);
+ method public static inline void forEach(android.util.SparseBooleanArray, kotlin.jvm.functions.Function2<? super java.lang.Integer,? super java.lang.Boolean,kotlin.Unit> action);
+ method public static inline boolean getOrDefault(android.util.SparseBooleanArray, int key, boolean defaultValue);
+ method public static inline boolean getOrElse(android.util.SparseBooleanArray, int key, kotlin.jvm.functions.Function0<java.lang.Boolean> defaultValue);
+ method public static inline int getSize(android.util.SparseBooleanArray);
+ method public static inline boolean isEmpty(android.util.SparseBooleanArray);
+ method public static inline boolean isNotEmpty(android.util.SparseBooleanArray);
+ method public static kotlin.collections.IntIterator keyIterator(android.util.SparseBooleanArray);
+ method public static operator android.util.SparseBooleanArray plus(android.util.SparseBooleanArray, android.util.SparseBooleanArray other);
+ method public static void putAll(android.util.SparseBooleanArray, android.util.SparseBooleanArray other);
+ method public static boolean remove(android.util.SparseBooleanArray, int key, boolean value);
+ method public static inline operator void set(android.util.SparseBooleanArray, int key, boolean value);
+ method public static kotlin.collections.BooleanIterator valueIterator(android.util.SparseBooleanArray);
+ }
+
+ public final class SparseIntArrayKt {
+ method public static inline operator boolean contains(android.util.SparseIntArray, int key);
+ method public static inline boolean containsKey(android.util.SparseIntArray, int key);
+ method public static inline boolean containsValue(android.util.SparseIntArray, int value);
+ method public static inline void forEach(android.util.SparseIntArray, kotlin.jvm.functions.Function2<? super java.lang.Integer,? super java.lang.Integer,kotlin.Unit> action);
+ method public static inline int getOrDefault(android.util.SparseIntArray, int key, int defaultValue);
+ method public static inline int getOrElse(android.util.SparseIntArray, int key, kotlin.jvm.functions.Function0<java.lang.Integer> defaultValue);
+ method public static inline int getSize(android.util.SparseIntArray);
+ method public static inline boolean isEmpty(android.util.SparseIntArray);
+ method public static inline boolean isNotEmpty(android.util.SparseIntArray);
+ method public static kotlin.collections.IntIterator keyIterator(android.util.SparseIntArray);
+ method public static operator android.util.SparseIntArray plus(android.util.SparseIntArray, android.util.SparseIntArray other);
+ method public static void putAll(android.util.SparseIntArray, android.util.SparseIntArray other);
+ method public static boolean remove(android.util.SparseIntArray, int key, int value);
+ method public static inline operator void set(android.util.SparseIntArray, int key, int value);
+ method public static kotlin.collections.IntIterator valueIterator(android.util.SparseIntArray);
+ }
+
+ public final class SparseLongArrayKt {
+ method @RequiresApi(18) public static inline operator boolean contains(android.util.SparseLongArray, int key);
+ method @RequiresApi(18) public static inline boolean containsKey(android.util.SparseLongArray, int key);
+ method @RequiresApi(18) public static inline boolean containsValue(android.util.SparseLongArray, long value);
+ method @RequiresApi(18) public static inline void forEach(android.util.SparseLongArray, kotlin.jvm.functions.Function2<? super java.lang.Integer,? super java.lang.Long,kotlin.Unit> action);
+ method @RequiresApi(18) public static inline long getOrDefault(android.util.SparseLongArray, int key, long defaultValue);
+ method @RequiresApi(18) public static inline long getOrElse(android.util.SparseLongArray, int key, kotlin.jvm.functions.Function0<java.lang.Long> defaultValue);
+ method @RequiresApi(18) public static inline int getSize(android.util.SparseLongArray);
+ method @RequiresApi(18) public static inline boolean isEmpty(android.util.SparseLongArray);
+ method @RequiresApi(18) public static inline boolean isNotEmpty(android.util.SparseLongArray);
+ method @RequiresApi(18) public static kotlin.collections.IntIterator keyIterator(android.util.SparseLongArray);
+ method @RequiresApi(18) public static operator android.util.SparseLongArray plus(android.util.SparseLongArray, android.util.SparseLongArray other);
+ method @RequiresApi(18) public static void putAll(android.util.SparseLongArray, android.util.SparseLongArray other);
+ method @RequiresApi(18) public static boolean remove(android.util.SparseLongArray, int key, long value);
+ method @RequiresApi(18) public static inline operator void set(android.util.SparseLongArray, int key, long value);
+ method @RequiresApi(18) public static kotlin.collections.LongIterator valueIterator(android.util.SparseLongArray);
+ }
+
+}
+
+package androidx.core.view {
+
+ public final class MenuKt {
+ method public static operator boolean contains(android.view.Menu, android.view.MenuItem item);
+ method public static inline void forEach(android.view.Menu, kotlin.jvm.functions.Function1<? super android.view.MenuItem,kotlin.Unit> action);
+ method public static inline void forEachIndexed(android.view.Menu, kotlin.jvm.functions.Function2<? super java.lang.Integer,? super android.view.MenuItem,kotlin.Unit> action);
+ method public static inline operator android.view.MenuItem get(android.view.Menu, int index);
+ method public static kotlin.sequences.Sequence<android.view.MenuItem> getChildren(android.view.Menu);
+ method public static inline int getSize(android.view.Menu);
+ method public static inline boolean isEmpty(android.view.Menu);
+ method public static inline boolean isNotEmpty(android.view.Menu);
+ method public static operator java.util.Iterator<android.view.MenuItem> iterator(android.view.Menu);
+ method public static inline operator void minusAssign(android.view.Menu, android.view.MenuItem item);
+ method public static inline void removeItemAt(android.view.Menu, int index);
+ }
+
+ public final class ViewGroupKt {
+ method public static inline operator boolean contains(android.view.ViewGroup, android.view.View view);
+ method public static inline void forEach(android.view.ViewGroup, kotlin.jvm.functions.Function1<? super android.view.View,kotlin.Unit> action);
+ method public static inline void forEachIndexed(android.view.ViewGroup, kotlin.jvm.functions.Function2<? super java.lang.Integer,? super android.view.View,kotlin.Unit> action);
+ method public static operator android.view.View get(android.view.ViewGroup, int index);
+ method public static kotlin.sequences.Sequence<android.view.View> getChildren(android.view.ViewGroup);
+ method public static kotlin.sequences.Sequence<android.view.View> getDescendants(android.view.ViewGroup);
+ method public static inline kotlin.ranges.IntRange getIndices(android.view.ViewGroup);
+ method public static inline int getSize(android.view.ViewGroup);
+ method public static inline boolean isEmpty(android.view.ViewGroup);
+ method public static inline boolean isNotEmpty(android.view.ViewGroup);
+ method public static operator java.util.Iterator<android.view.View> iterator(android.view.ViewGroup);
+ method public static inline operator void minusAssign(android.view.ViewGroup, android.view.View view);
+ method public static inline operator void plusAssign(android.view.ViewGroup, android.view.View view);
+ method public static inline void setMargins(android.view.ViewGroup.MarginLayoutParams, @Px int size);
+ method public static inline void updateMargins(android.view.ViewGroup.MarginLayoutParams, optional @Px int left, optional @Px int top, optional @Px int right, optional @Px int bottom);
+ method @RequiresApi(17) public static inline void updateMarginsRelative(android.view.ViewGroup.MarginLayoutParams, optional @Px int start, optional @Px int top, optional @Px int end, optional @Px int bottom);
+ }
+
+ public final class ViewKt {
+ method public static inline void doOnAttach(android.view.View, kotlin.jvm.functions.Function1<? super android.view.View,kotlin.Unit> action);
+ method public static inline void doOnDetach(android.view.View, kotlin.jvm.functions.Function1<? super android.view.View,kotlin.Unit> action);
+ method public static inline void doOnLayout(android.view.View, kotlin.jvm.functions.Function1<? super android.view.View,kotlin.Unit> action);
+ method public static inline void doOnNextLayout(android.view.View, kotlin.jvm.functions.Function1<? super android.view.View,kotlin.Unit> action);
+ method public static inline androidx.core.view.OneShotPreDrawListener doOnPreDraw(android.view.View, kotlin.jvm.functions.Function1<? super android.view.View,kotlin.Unit> action);
+ method public static android.graphics.Bitmap drawToBitmap(android.view.View, optional android.graphics.Bitmap.Config config);
+ method public static kotlin.sequences.Sequence<android.view.View> getAllViews(android.view.View);
+ method public static kotlin.sequences.Sequence<android.view.ViewParent> getAncestors(android.view.View);
+ method public static inline int getMarginBottom(android.view.View);
+ method public static inline int getMarginEnd(android.view.View);
+ method public static inline int getMarginLeft(android.view.View);
+ method public static inline int getMarginRight(android.view.View);
+ method public static inline int getMarginStart(android.view.View);
+ method public static inline int getMarginTop(android.view.View);
+ method public static inline boolean isGone(android.view.View);
+ method public static inline boolean isInvisible(android.view.View);
+ method public static inline boolean isVisible(android.view.View);
+ method public static inline Runnable postDelayed(android.view.View, long delayInMillis, kotlin.jvm.functions.Function0<kotlin.Unit> action);
+ method @RequiresApi(16) public static Runnable postOnAnimationDelayed(android.view.View, long delayInMillis, kotlin.jvm.functions.Function0<kotlin.Unit> action);
+ method public static inline void setGone(android.view.View, boolean);
+ method public static inline void setInvisible(android.view.View, boolean);
+ method public static inline void setPadding(android.view.View, @Px int size);
+ method public static inline void setVisible(android.view.View, boolean);
+ method public static inline void updateLayoutParams(android.view.View, kotlin.jvm.functions.Function1<? super android.view.ViewGroup.LayoutParams,kotlin.Unit> block);
+ method public static inline <reified T extends android.view.ViewGroup.LayoutParams> void updateLayoutParams(android.view.View, kotlin.jvm.functions.Function1<? super T,? extends kotlin.Unit> block);
+ method public static inline void updatePadding(android.view.View, optional @Px int left, optional @Px int top, optional @Px int right, optional @Px int bottom);
+ method @RequiresApi(17) public static inline void updatePaddingRelative(android.view.View, optional @Px int start, optional @Px int top, optional @Px int end, optional @Px int bottom);
+ }
+
+}
+
+package androidx.core.widget {
+
+ public final class TextViewKt {
+ method public static inline android.text.TextWatcher addTextChangedListener(android.widget.TextView, optional kotlin.jvm.functions.Function4<? super java.lang.CharSequence,? super java.lang.Integer,? super java.lang.Integer,? super java.lang.Integer,kotlin.Unit> beforeTextChanged, optional kotlin.jvm.functions.Function4<? super java.lang.CharSequence,? super java.lang.Integer,? super java.lang.Integer,? super java.lang.Integer,kotlin.Unit> onTextChanged, optional kotlin.jvm.functions.Function1<? super android.text.Editable,kotlin.Unit> afterTextChanged);
+ method public static inline android.text.TextWatcher doAfterTextChanged(android.widget.TextView, kotlin.jvm.functions.Function1<? super android.text.Editable,kotlin.Unit> action);
+ method public static inline android.text.TextWatcher doBeforeTextChanged(android.widget.TextView, kotlin.jvm.functions.Function4<? super java.lang.CharSequence,? super java.lang.Integer,? super java.lang.Integer,? super java.lang.Integer,kotlin.Unit> action);
+ method public static inline android.text.TextWatcher doOnTextChanged(android.widget.TextView, kotlin.jvm.functions.Function4<? super java.lang.CharSequence,? super java.lang.Integer,? super java.lang.Integer,? super java.lang.Integer,kotlin.Unit> action);
+ }
+
+}
+
diff --git a/webkit/webkit/api/res-1.6.0-beta02.txt b/core/core-ktx/api/res-1.10.0-beta01.txt
similarity index 100%
copy from webkit/webkit/api/res-1.6.0-beta02.txt
copy to core/core-ktx/api/res-1.10.0-beta01.txt
diff --git a/core/core-ktx/api/restricted_1.10.0-beta01.txt b/core/core-ktx/api/restricted_1.10.0-beta01.txt
new file mode 100644
index 0000000..801b56b
--- /dev/null
+++ b/core/core-ktx/api/restricted_1.10.0-beta01.txt
@@ -0,0 +1,634 @@
+// Signature format: 4.0
+package androidx.core.animation {
+
+ public final class AnimatorKt {
+ method public static inline android.animation.Animator.AnimatorListener addListener(android.animation.Animator, optional kotlin.jvm.functions.Function1<? super android.animation.Animator,kotlin.Unit> onEnd, optional kotlin.jvm.functions.Function1<? super android.animation.Animator,kotlin.Unit> onStart, optional kotlin.jvm.functions.Function1<? super android.animation.Animator,kotlin.Unit> onCancel, optional kotlin.jvm.functions.Function1<? super android.animation.Animator,kotlin.Unit> onRepeat);
+ method @RequiresApi(19) public static android.animation.Animator.AnimatorPauseListener addPauseListener(android.animation.Animator, optional kotlin.jvm.functions.Function1<? super android.animation.Animator,kotlin.Unit> onResume, optional kotlin.jvm.functions.Function1<? super android.animation.Animator,kotlin.Unit> onPause);
+ method public static inline android.animation.Animator.AnimatorListener doOnCancel(android.animation.Animator, kotlin.jvm.functions.Function1<? super android.animation.Animator,kotlin.Unit> action);
+ method public static inline android.animation.Animator.AnimatorListener doOnEnd(android.animation.Animator, kotlin.jvm.functions.Function1<? super android.animation.Animator,kotlin.Unit> action);
+ method @RequiresApi(19) public static android.animation.Animator.AnimatorPauseListener doOnPause(android.animation.Animator, kotlin.jvm.functions.Function1<? super android.animation.Animator,kotlin.Unit> action);
+ method public static inline android.animation.Animator.AnimatorListener doOnRepeat(android.animation.Animator, kotlin.jvm.functions.Function1<? super android.animation.Animator,kotlin.Unit> action);
+ method @RequiresApi(19) public static android.animation.Animator.AnimatorPauseListener doOnResume(android.animation.Animator, kotlin.jvm.functions.Function1<? super android.animation.Animator,kotlin.Unit> action);
+ method public static inline android.animation.Animator.AnimatorListener doOnStart(android.animation.Animator, kotlin.jvm.functions.Function1<? super android.animation.Animator,kotlin.Unit> action);
+ }
+
+}
+
+package androidx.core.content {
+
+ public final class ContentValuesKt {
+ method public static android.content.ContentValues contentValuesOf(kotlin.Pair<java.lang.String,?>... pairs);
+ }
+
+ public final class ContextKt {
+ method public static inline <reified T> T! getSystemService(android.content.Context);
+ method public static inline void withStyledAttributes(android.content.Context, optional android.util.AttributeSet? set, int[] attrs, optional @AttrRes int defStyleAttr, optional @StyleRes int defStyleRes, kotlin.jvm.functions.Function1<? super android.content.res.TypedArray,kotlin.Unit> block);
+ method public static inline void withStyledAttributes(android.content.Context, @StyleRes int resourceId, int[] attrs, kotlin.jvm.functions.Function1<? super android.content.res.TypedArray,kotlin.Unit> block);
+ }
+
+ public final class SharedPreferencesKt {
+ method public static inline void edit(android.content.SharedPreferences, optional boolean commit, kotlin.jvm.functions.Function1<? super android.content.SharedPreferences.Editor,kotlin.Unit> action);
+ }
+
+}
+
+package androidx.core.content.res {
+
+ public final class TypedArrayKt {
+ method public static boolean getBooleanOrThrow(android.content.res.TypedArray, @StyleableRes int index);
+ method @ColorInt public static int getColorOrThrow(android.content.res.TypedArray, @StyleableRes int index);
+ method public static android.content.res.ColorStateList getColorStateListOrThrow(android.content.res.TypedArray, @StyleableRes int index);
+ method public static float getDimensionOrThrow(android.content.res.TypedArray, @StyleableRes int index);
+ method @Dimension public static int getDimensionPixelOffsetOrThrow(android.content.res.TypedArray, @StyleableRes int index);
+ method @Dimension public static int getDimensionPixelSizeOrThrow(android.content.res.TypedArray, @StyleableRes int index);
+ method public static android.graphics.drawable.Drawable getDrawableOrThrow(android.content.res.TypedArray, @StyleableRes int index);
+ method public static float getFloatOrThrow(android.content.res.TypedArray, @StyleableRes int index);
+ method @RequiresApi(26) public static android.graphics.Typeface getFontOrThrow(android.content.res.TypedArray, @StyleableRes int index);
+ method public static int getIntOrThrow(android.content.res.TypedArray, @StyleableRes int index);
+ method public static int getIntegerOrThrow(android.content.res.TypedArray, @StyleableRes int index);
+ method @AnyRes public static int getResourceIdOrThrow(android.content.res.TypedArray, @StyleableRes int index);
+ method public static String getStringOrThrow(android.content.res.TypedArray, @StyleableRes int index);
+ method public static CharSequence![] getTextArrayOrThrow(android.content.res.TypedArray, @StyleableRes int index);
+ method public static CharSequence getTextOrThrow(android.content.res.TypedArray, @StyleableRes int index);
+ method public static inline <R> R! use(android.content.res.TypedArray, kotlin.jvm.functions.Function1<? super android.content.res.TypedArray,? extends R> block);
+ }
+
+}
+
+package androidx.core.database {
+
+ public final class CursorKt {
+ method public static inline byte[]? getBlobOrNull(android.database.Cursor, int index);
+ method public static inline Double? getDoubleOrNull(android.database.Cursor, int index);
+ method public static inline Float? getFloatOrNull(android.database.Cursor, int index);
+ method public static inline Integer? getIntOrNull(android.database.Cursor, int index);
+ method public static inline Long? getLongOrNull(android.database.Cursor, int index);
+ method public static inline Short? getShortOrNull(android.database.Cursor, int index);
+ method public static inline String? getStringOrNull(android.database.Cursor, int index);
+ }
+
+}
+
+package androidx.core.database.sqlite {
+
+ public final class SQLiteDatabaseKt {
+ method public static inline <T> T! transaction(android.database.sqlite.SQLiteDatabase, optional boolean exclusive, kotlin.jvm.functions.Function1<? super android.database.sqlite.SQLiteDatabase,? extends T> body);
+ }
+
+}
+
+package androidx.core.graphics {
+
+ public final class BitmapKt {
+ method public static inline android.graphics.Bitmap applyCanvas(android.graphics.Bitmap, kotlin.jvm.functions.Function1<? super android.graphics.Canvas,kotlin.Unit> block);
+ method public static inline operator boolean contains(android.graphics.Bitmap, android.graphics.Point p);
+ method public static inline operator boolean contains(android.graphics.Bitmap, android.graphics.PointF p);
+ method public static inline android.graphics.Bitmap createBitmap(int width, int height, optional android.graphics.Bitmap.Config config);
+ method @RequiresApi(26) public static inline android.graphics.Bitmap createBitmap(int width, int height, optional android.graphics.Bitmap.Config config, optional boolean hasAlpha, optional android.graphics.ColorSpace colorSpace);
+ method public static inline operator int get(android.graphics.Bitmap, int x, int y);
+ method public static inline android.graphics.Bitmap scale(android.graphics.Bitmap, int width, int height, optional boolean filter);
+ method public static inline operator void set(android.graphics.Bitmap, int x, int y, @ColorInt int color);
+ }
+
+ public final class CanvasKt {
+ method public static inline void withClip(android.graphics.Canvas, android.graphics.Rect clipRect, kotlin.jvm.functions.Function1<? super android.graphics.Canvas,kotlin.Unit> block);
+ method public static inline void withClip(android.graphics.Canvas, android.graphics.RectF clipRect, kotlin.jvm.functions.Function1<? super android.graphics.Canvas,kotlin.Unit> block);
+ method public static inline void withClip(android.graphics.Canvas, int left, int top, int right, int bottom, kotlin.jvm.functions.Function1<? super android.graphics.Canvas,kotlin.Unit> block);
+ method public static inline void withClip(android.graphics.Canvas, float left, float top, float right, float bottom, kotlin.jvm.functions.Function1<? super android.graphics.Canvas,kotlin.Unit> block);
+ method public static inline void withClip(android.graphics.Canvas, android.graphics.Path clipPath, kotlin.jvm.functions.Function1<? super android.graphics.Canvas,kotlin.Unit> block);
+ method public static inline void withMatrix(android.graphics.Canvas, optional android.graphics.Matrix matrix, kotlin.jvm.functions.Function1<? super android.graphics.Canvas,kotlin.Unit> block);
+ method public static inline void withRotation(android.graphics.Canvas, optional float degrees, optional float pivotX, optional float pivotY, kotlin.jvm.functions.Function1<? super android.graphics.Canvas,kotlin.Unit> block);
+ method public static inline void withSave(android.graphics.Canvas, kotlin.jvm.functions.Function1<? super android.graphics.Canvas,kotlin.Unit> block);
+ method public static inline void withScale(android.graphics.Canvas, optional float x, optional float y, optional float pivotX, optional float pivotY, kotlin.jvm.functions.Function1<? super android.graphics.Canvas,kotlin.Unit> block);
+ method public static inline void withSkew(android.graphics.Canvas, optional float x, optional float y, kotlin.jvm.functions.Function1<? super android.graphics.Canvas,kotlin.Unit> block);
+ method public static inline void withTranslation(android.graphics.Canvas, optional float x, optional float y, kotlin.jvm.functions.Function1<? super android.graphics.Canvas,kotlin.Unit> block);
+ }
+
+ public final class ColorKt {
+ method @RequiresApi(26) public static inline operator float component1(android.graphics.Color);
+ method public static inline operator int component1(@ColorInt int);
+ method @RequiresApi(26) public static inline operator float component1(@ColorLong long);
+ method @RequiresApi(26) public static inline operator float component2(android.graphics.Color);
+ method public static inline operator int component2(@ColorInt int);
+ method @RequiresApi(26) public static inline operator float component2(@ColorLong long);
+ method @RequiresApi(26) public static inline operator float component3(android.graphics.Color);
+ method public static inline operator int component3(@ColorInt int);
+ method @RequiresApi(26) public static inline operator float component3(@ColorLong long);
+ method @RequiresApi(26) public static inline operator float component4(android.graphics.Color);
+ method public static inline operator int component4(@ColorInt int);
+ method @RequiresApi(26) public static inline operator float component4(@ColorLong long);
+ method @ColorLong @RequiresApi(26) public static inline infix long convertTo(@ColorInt int, android.graphics.ColorSpace.Named colorSpace);
+ method @ColorLong @RequiresApi(26) public static inline infix long convertTo(@ColorInt int, android.graphics.ColorSpace colorSpace);
+ method @ColorLong @RequiresApi(26) public static inline infix long convertTo(@ColorLong long, android.graphics.ColorSpace.Named colorSpace);
+ method @ColorLong @RequiresApi(26) public static inline infix long convertTo(@ColorLong long, android.graphics.ColorSpace colorSpace);
+ method @RequiresApi(26) public static inline infix android.graphics.Color convertTo(android.graphics.Color, android.graphics.ColorSpace.Named colorSpace);
+ method @RequiresApi(26) public static inline infix android.graphics.Color convertTo(android.graphics.Color, android.graphics.ColorSpace colorSpace);
+ method public static inline int getAlpha(@ColorInt int);
+ method @RequiresApi(26) public static inline float getAlpha(@ColorLong long);
+ method public static inline int getBlue(@ColorInt int);
+ method @RequiresApi(26) public static inline float getBlue(@ColorLong long);
+ method @RequiresApi(26) public static inline android.graphics.ColorSpace getColorSpace(@ColorLong long);
+ method public static inline int getGreen(@ColorInt int);
+ method @RequiresApi(26) public static inline float getGreen(@ColorLong long);
+ method @RequiresApi(26) public static inline float getLuminance(@ColorInt int);
+ method @RequiresApi(26) public static inline float getLuminance(@ColorLong long);
+ method public static inline int getRed(@ColorInt int);
+ method @RequiresApi(26) public static inline float getRed(@ColorLong long);
+ method @RequiresApi(26) public static inline boolean isSrgb(@ColorLong long);
+ method @RequiresApi(26) public static inline boolean isWideGamut(@ColorLong long);
+ method @RequiresApi(26) public static operator android.graphics.Color plus(android.graphics.Color, android.graphics.Color c);
+ method @RequiresApi(26) public static inline android.graphics.Color toColor(@ColorInt int);
+ method @RequiresApi(26) public static inline android.graphics.Color toColor(@ColorLong long);
+ method @ColorInt @RequiresApi(26) public static inline int toColorInt(@ColorLong long);
+ method @ColorInt public static inline int toColorInt(String);
+ method @ColorLong @RequiresApi(26) public static inline long toColorLong(@ColorInt int);
+ }
+
+ public final class ImageDecoderKt {
+ method @RequiresApi(28) public static inline android.graphics.Bitmap decodeBitmap(android.graphics.ImageDecoder.Source, kotlin.jvm.functions.Function3<? super android.graphics.ImageDecoder,? super android.graphics.ImageDecoder.ImageInfo,? super android.graphics.ImageDecoder.Source,kotlin.Unit> action);
+ method @RequiresApi(28) public static inline android.graphics.drawable.Drawable decodeDrawable(android.graphics.ImageDecoder.Source, kotlin.jvm.functions.Function3<? super android.graphics.ImageDecoder,? super android.graphics.ImageDecoder.ImageInfo,? super android.graphics.ImageDecoder.Source,kotlin.Unit> action);
+ }
+
+ public final class MatrixKt {
+ method public static android.graphics.Matrix rotationMatrix(float degrees, optional float px, optional float py);
+ method public static android.graphics.Matrix scaleMatrix(optional float sx, optional float sy);
+ method public static inline operator android.graphics.Matrix times(android.graphics.Matrix, android.graphics.Matrix m);
+ method public static android.graphics.Matrix translationMatrix(optional float tx, optional float ty);
+ method public static inline float[] values(android.graphics.Matrix);
+ }
+
+ public final class PaintKt {
+ method public static inline boolean setBlendMode(android.graphics.Paint, androidx.core.graphics.BlendModeCompat? blendModeCompat);
+ }
+
+ public final class PathKt {
+ method @RequiresApi(19) public static inline infix android.graphics.Path and(android.graphics.Path, android.graphics.Path p);
+ method @RequiresApi(26) public static Iterable<androidx.core.graphics.PathSegment> flatten(android.graphics.Path, optional float error);
+ method @RequiresApi(19) public static inline operator android.graphics.Path minus(android.graphics.Path, android.graphics.Path p);
+ method @RequiresApi(19) public static inline infix android.graphics.Path or(android.graphics.Path, android.graphics.Path p);
+ method @RequiresApi(19) public static inline operator android.graphics.Path plus(android.graphics.Path, android.graphics.Path p);
+ method @RequiresApi(19) public static inline infix android.graphics.Path xor(android.graphics.Path, android.graphics.Path p);
+ }
+
+ public final class PictureKt {
+ method public static inline android.graphics.Picture record(android.graphics.Picture, int width, int height, kotlin.jvm.functions.Function1<? super android.graphics.Canvas,kotlin.Unit> block);
+ }
+
+ public final class PointKt {
+ method public static inline operator int component1(android.graphics.Point);
+ method public static inline operator float component1(android.graphics.PointF);
+ method public static inline operator int component2(android.graphics.Point);
+ method public static inline operator float component2(android.graphics.PointF);
+ method public static inline operator android.graphics.Point div(android.graphics.Point, float scalar);
+ method public static inline operator android.graphics.PointF div(android.graphics.PointF, float scalar);
+ method public static inline operator android.graphics.Point minus(android.graphics.Point, android.graphics.Point p);
+ method public static inline operator android.graphics.PointF minus(android.graphics.PointF, android.graphics.PointF p);
+ method public static inline operator android.graphics.Point minus(android.graphics.Point, int xy);
+ method public static inline operator android.graphics.PointF minus(android.graphics.PointF, float xy);
+ method public static inline operator android.graphics.Point plus(android.graphics.Point, android.graphics.Point p);
+ method public static inline operator android.graphics.PointF plus(android.graphics.PointF, android.graphics.PointF p);
+ method public static inline operator android.graphics.Point plus(android.graphics.Point, int xy);
+ method public static inline operator android.graphics.PointF plus(android.graphics.PointF, float xy);
+ method public static inline operator android.graphics.Point times(android.graphics.Point, float scalar);
+ method public static inline operator android.graphics.PointF times(android.graphics.PointF, float scalar);
+ method public static inline android.graphics.Point toPoint(android.graphics.PointF);
+ method public static inline android.graphics.PointF toPointF(android.graphics.Point);
+ method public static inline operator android.graphics.Point unaryMinus(android.graphics.Point);
+ method public static inline operator android.graphics.PointF unaryMinus(android.graphics.PointF);
+ }
+
+ public final class PorterDuffKt {
+ method public static inline android.graphics.PorterDuffColorFilter toColorFilter(android.graphics.PorterDuff.Mode, int color);
+ method public static inline android.graphics.PorterDuffXfermode toXfermode(android.graphics.PorterDuff.Mode);
+ }
+
+ public final class RectKt {
+ method public static inline infix android.graphics.Rect and(android.graphics.Rect, android.graphics.Rect r);
+ method public static inline infix android.graphics.RectF and(android.graphics.RectF, android.graphics.RectF r);
+ method public static inline operator int component1(android.graphics.Rect);
+ method public static inline operator float component1(android.graphics.RectF);
+ method public static inline operator int component2(android.graphics.Rect);
+ method public static inline operator float component2(android.graphics.RectF);
+ method public static inline operator int component3(android.graphics.Rect);
+ method public static inline operator float component3(android.graphics.RectF);
+ method public static inline operator int component4(android.graphics.Rect);
+ method public static inline operator float component4(android.graphics.RectF);
+ method public static inline operator boolean contains(android.graphics.Rect, android.graphics.Point p);
+ method public static inline operator boolean contains(android.graphics.RectF, android.graphics.PointF p);
+ method public static inline operator android.graphics.Region minus(android.graphics.Rect, android.graphics.Rect r);
+ method public static inline operator android.graphics.Region minus(android.graphics.RectF, android.graphics.RectF r);
+ method public static inline operator android.graphics.Rect minus(android.graphics.Rect, int xy);
+ method public static inline operator android.graphics.RectF minus(android.graphics.RectF, float xy);
+ method public static inline operator android.graphics.Rect minus(android.graphics.Rect, android.graphics.Point xy);
+ method public static inline operator android.graphics.RectF minus(android.graphics.RectF, android.graphics.PointF xy);
+ method public static inline infix android.graphics.Rect or(android.graphics.Rect, android.graphics.Rect r);
+ method public static inline infix android.graphics.RectF or(android.graphics.RectF, android.graphics.RectF r);
+ method public static inline operator android.graphics.Rect plus(android.graphics.Rect, android.graphics.Rect r);
+ method public static inline operator android.graphics.RectF plus(android.graphics.RectF, android.graphics.RectF r);
+ method public static inline operator android.graphics.Rect plus(android.graphics.Rect, int xy);
+ method public static inline operator android.graphics.RectF plus(android.graphics.RectF, float xy);
+ method public static inline operator android.graphics.Rect plus(android.graphics.Rect, android.graphics.Point xy);
+ method public static inline operator android.graphics.RectF plus(android.graphics.RectF, android.graphics.PointF xy);
+ method public static inline operator android.graphics.Rect times(android.graphics.Rect, int factor);
+ method public static inline operator android.graphics.RectF times(android.graphics.RectF, int factor);
+ method public static inline operator android.graphics.RectF times(android.graphics.RectF, float factor);
+ method public static inline android.graphics.Rect toRect(android.graphics.RectF);
+ method public static inline android.graphics.RectF toRectF(android.graphics.Rect);
+ method public static inline android.graphics.Region toRegion(android.graphics.Rect);
+ method public static inline android.graphics.Region toRegion(android.graphics.RectF);
+ method public static inline android.graphics.RectF transform(android.graphics.RectF, android.graphics.Matrix m);
+ method public static inline infix android.graphics.Region xor(android.graphics.Rect, android.graphics.Rect r);
+ method public static inline infix android.graphics.Region xor(android.graphics.RectF, android.graphics.RectF r);
+ }
+
+ public final class RegionKt {
+ method public static inline infix android.graphics.Region and(android.graphics.Region, android.graphics.Rect r);
+ method public static inline infix android.graphics.Region and(android.graphics.Region, android.graphics.Region r);
+ method public static inline operator boolean contains(android.graphics.Region, android.graphics.Point p);
+ method public static inline void forEach(android.graphics.Region, kotlin.jvm.functions.Function1<? super android.graphics.Rect,kotlin.Unit> action);
+ method public static operator java.util.Iterator<android.graphics.Rect> iterator(android.graphics.Region);
+ method public static inline operator android.graphics.Region minus(android.graphics.Region, android.graphics.Rect r);
+ method public static inline operator android.graphics.Region minus(android.graphics.Region, android.graphics.Region r);
+ method public static inline operator android.graphics.Region not(android.graphics.Region);
+ method public static inline infix android.graphics.Region or(android.graphics.Region, android.graphics.Rect r);
+ method public static inline infix android.graphics.Region or(android.graphics.Region, android.graphics.Region r);
+ method public static inline operator android.graphics.Region plus(android.graphics.Region, android.graphics.Rect r);
+ method public static inline operator android.graphics.Region plus(android.graphics.Region, android.graphics.Region r);
+ method public static inline operator android.graphics.Region unaryMinus(android.graphics.Region);
+ method public static inline infix android.graphics.Region xor(android.graphics.Region, android.graphics.Rect r);
+ method public static inline infix android.graphics.Region xor(android.graphics.Region, android.graphics.Region r);
+ }
+
+ public final class ShaderKt {
+ method public static inline void transform(android.graphics.Shader, kotlin.jvm.functions.Function1<? super android.graphics.Matrix,kotlin.Unit> block);
+ }
+
+}
+
+package androidx.core.graphics.drawable {
+
+ public final class BitmapDrawableKt {
+ method public static inline android.graphics.drawable.BitmapDrawable toDrawable(android.graphics.Bitmap, android.content.res.Resources resources);
+ }
+
+ public final class ColorDrawableKt {
+ method public static inline android.graphics.drawable.ColorDrawable toDrawable(@ColorInt int);
+ method @RequiresApi(26) public static inline android.graphics.drawable.ColorDrawable toDrawable(android.graphics.Color);
+ }
+
+ public final class DrawableKt {
+ method public static android.graphics.Bitmap toBitmap(android.graphics.drawable.Drawable, optional @Px int width, optional @Px int height, optional android.graphics.Bitmap.Config? config);
+ method public static android.graphics.Bitmap? toBitmapOrNull(android.graphics.drawable.Drawable, optional @Px int width, optional @Px int height, optional android.graphics.Bitmap.Config? config);
+ method public static void updateBounds(android.graphics.drawable.Drawable, optional @Px int left, optional @Px int top, optional @Px int right, optional @Px int bottom);
+ }
+
+ public final class IconKt {
+ method @RequiresApi(26) public static inline android.graphics.drawable.Icon toAdaptiveIcon(android.graphics.Bitmap);
+ method @RequiresApi(26) public static inline android.graphics.drawable.Icon toIcon(android.graphics.Bitmap);
+ method @RequiresApi(26) public static inline android.graphics.drawable.Icon toIcon(android.net.Uri);
+ method @RequiresApi(26) public static inline android.graphics.drawable.Icon toIcon(byte[]);
+ }
+
+}
+
+package androidx.core.location {
+
+ public final class LocationKt {
+ method public static inline operator double component1(android.location.Location);
+ method public static inline operator double component2(android.location.Location);
+ }
+
+}
+
+package androidx.core.net {
+
+ public final class UriKt {
+ method public static java.io.File toFile(android.net.Uri);
+ method public static inline android.net.Uri toUri(String);
+ method public static inline android.net.Uri toUri(java.io.File);
+ }
+
+}
+
+package androidx.core.os {
+
+ public final class BundleKt {
+ method public static android.os.Bundle bundleOf(kotlin.Pair<java.lang.String,?>... pairs);
+ method public static android.os.Bundle bundleOf();
+ }
+
+ public final class HandlerKt {
+ method public static inline Runnable postAtTime(android.os.Handler, long uptimeMillis, optional Object? token, kotlin.jvm.functions.Function0<kotlin.Unit> action);
+ method public static inline Runnable postDelayed(android.os.Handler, long delayInMillis, optional Object? token, kotlin.jvm.functions.Function0<kotlin.Unit> action);
+ }
+
+ @RequiresApi(31) public final class OutcomeReceiverKt {
+ method @RequiresApi(31) public static <R, E extends java.lang.Throwable> android.os.OutcomeReceiver<R,E> asOutcomeReceiver(kotlin.coroutines.Continuation<? super R>);
+ }
+
+ public final class PersistableBundleKt {
+ method @RequiresApi(21) public static android.os.PersistableBundle persistableBundleOf(kotlin.Pair<java.lang.String,?>... pairs);
+ method @RequiresApi(21) public static android.os.PersistableBundle persistableBundleOf();
+ method @RequiresApi(21) public static android.os.PersistableBundle toPersistableBundle(java.util.Map<java.lang.String,?>);
+ }
+
+ public final class TraceKt {
+ method @Deprecated public static inline <T> T! trace(String sectionName, kotlin.jvm.functions.Function0<? extends T> block);
+ }
+
+}
+
+package androidx.core.text {
+
+ public final class CharSequenceKt {
+ method public static inline boolean isDigitsOnly(CharSequence);
+ method public static inline int trimmedLength(CharSequence);
+ }
+
+ public final class HtmlKt {
+ method public static inline android.text.Spanned parseAsHtml(String, optional int flags, optional android.text.Html.ImageGetter? imageGetter, optional android.text.Html.TagHandler? tagHandler);
+ method public static inline String toHtml(android.text.Spanned, optional int option);
+ }
+
+ public final class LocaleKt {
+ method @RequiresApi(17) public static inline int getLayoutDirection(java.util.Locale);
+ }
+
+ public final class SpannableStringBuilderKt {
+ method public static inline android.text.SpannableStringBuilder backgroundColor(android.text.SpannableStringBuilder, @ColorInt int color, kotlin.jvm.functions.Function1<? super android.text.SpannableStringBuilder,kotlin.Unit> builderAction);
+ method public static inline android.text.SpannableStringBuilder bold(android.text.SpannableStringBuilder, kotlin.jvm.functions.Function1<? super android.text.SpannableStringBuilder,kotlin.Unit> builderAction);
+ method public static inline android.text.SpannedString buildSpannedString(kotlin.jvm.functions.Function1<? super android.text.SpannableStringBuilder,kotlin.Unit> builderAction);
+ method public static inline android.text.SpannableStringBuilder color(android.text.SpannableStringBuilder, @ColorInt int color, kotlin.jvm.functions.Function1<? super android.text.SpannableStringBuilder,kotlin.Unit> builderAction);
+ method public static inline android.text.SpannableStringBuilder inSpans(android.text.SpannableStringBuilder, Object![] spans, kotlin.jvm.functions.Function1<? super android.text.SpannableStringBuilder,kotlin.Unit> builderAction);
+ method public static inline android.text.SpannableStringBuilder inSpans(android.text.SpannableStringBuilder, Object span, kotlin.jvm.functions.Function1<? super android.text.SpannableStringBuilder,kotlin.Unit> builderAction);
+ method public static inline android.text.SpannableStringBuilder italic(android.text.SpannableStringBuilder, kotlin.jvm.functions.Function1<? super android.text.SpannableStringBuilder,kotlin.Unit> builderAction);
+ method public static inline android.text.SpannableStringBuilder scale(android.text.SpannableStringBuilder, float proportion, kotlin.jvm.functions.Function1<? super android.text.SpannableStringBuilder,kotlin.Unit> builderAction);
+ method public static inline android.text.SpannableStringBuilder strikeThrough(android.text.SpannableStringBuilder, kotlin.jvm.functions.Function1<? super android.text.SpannableStringBuilder,kotlin.Unit> builderAction);
+ method public static inline android.text.SpannableStringBuilder subscript(android.text.SpannableStringBuilder, kotlin.jvm.functions.Function1<? super android.text.SpannableStringBuilder,kotlin.Unit> builderAction);
+ method public static inline android.text.SpannableStringBuilder superscript(android.text.SpannableStringBuilder, kotlin.jvm.functions.Function1<? super android.text.SpannableStringBuilder,kotlin.Unit> builderAction);
+ method public static inline android.text.SpannableStringBuilder underline(android.text.SpannableStringBuilder, kotlin.jvm.functions.Function1<? super android.text.SpannableStringBuilder,kotlin.Unit> builderAction);
+ }
+
+ public final class SpannableStringKt {
+ method public static inline void clearSpans(android.text.Spannable);
+ method public static inline operator void set(android.text.Spannable, int start, int end, Object span);
+ method public static inline operator void set(android.text.Spannable, kotlin.ranges.IntRange range, Object span);
+ method public static inline android.text.Spannable toSpannable(CharSequence);
+ }
+
+ public final class SpannedStringKt {
+ method public static inline <reified T> T![] getSpans(android.text.Spanned, optional int start, optional int end);
+ method public static inline android.text.Spanned toSpanned(CharSequence);
+ }
+
+ public final class StringKt {
+ method public static inline String htmlEncode(String);
+ }
+
+}
+
+package androidx.core.transition {
+
+ public final class TransitionKt {
+ method @RequiresApi(19) public static inline android.transition.Transition.TransitionListener addListener(android.transition.Transition, optional kotlin.jvm.functions.Function1<? super android.transition.Transition,kotlin.Unit> onEnd, optional kotlin.jvm.functions.Function1<? super android.transition.Transition,kotlin.Unit> onStart, optional kotlin.jvm.functions.Function1<? super android.transition.Transition,kotlin.Unit> onCancel, optional kotlin.jvm.functions.Function1<? super android.transition.Transition,kotlin.Unit> onResume, optional kotlin.jvm.functions.Function1<? super android.transition.Transition,kotlin.Unit> onPause);
+ method @RequiresApi(19) public static inline android.transition.Transition.TransitionListener doOnCancel(android.transition.Transition, kotlin.jvm.functions.Function1<? super android.transition.Transition,kotlin.Unit> action);
+ method @RequiresApi(19) public static inline android.transition.Transition.TransitionListener doOnEnd(android.transition.Transition, kotlin.jvm.functions.Function1<? super android.transition.Transition,kotlin.Unit> action);
+ method @RequiresApi(19) public static inline android.transition.Transition.TransitionListener doOnPause(android.transition.Transition, kotlin.jvm.functions.Function1<? super android.transition.Transition,kotlin.Unit> action);
+ method @RequiresApi(19) public static inline android.transition.Transition.TransitionListener doOnResume(android.transition.Transition, kotlin.jvm.functions.Function1<? super android.transition.Transition,kotlin.Unit> action);
+ method @RequiresApi(19) public static inline android.transition.Transition.TransitionListener doOnStart(android.transition.Transition, kotlin.jvm.functions.Function1<? super android.transition.Transition,kotlin.Unit> action);
+ }
+
+}
+
+package androidx.core.util {
+
+ public final class AndroidXConsumerKt {
+ method public static <T> androidx.core.util.Consumer<T> asAndroidXConsumer(kotlin.coroutines.Continuation<? super T>);
+ }
+
+ public final class AtomicFileKt {
+ method @RequiresApi(17) public static inline byte[] readBytes(android.util.AtomicFile);
+ method @RequiresApi(17) public static String readText(android.util.AtomicFile, optional java.nio.charset.Charset charset);
+ method @RequiresApi(17) public static inline void tryWrite(android.util.AtomicFile, kotlin.jvm.functions.Function1<? super java.io.FileOutputStream,kotlin.Unit> block);
+ method @RequiresApi(17) public static void writeBytes(android.util.AtomicFile, byte[] array);
+ method @RequiresApi(17) public static void writeText(android.util.AtomicFile, String text, optional java.nio.charset.Charset charset);
+ }
+
+ @RequiresApi(24) public final class ConsumerKt {
+ method @RequiresApi(24) public static <T> java.util.function.Consumer<T> asConsumer(kotlin.coroutines.Continuation<? super T>);
+ }
+
+ public final class HalfKt {
+ method @RequiresApi(26) public static inline android.util.Half toHalf(@HalfFloat short);
+ method @RequiresApi(26) public static inline android.util.Half toHalf(float);
+ method @RequiresApi(26) public static inline android.util.Half toHalf(double);
+ method @RequiresApi(26) public static inline android.util.Half toHalf(String);
+ }
+
+ public final class LongSparseArrayKt {
+ method @RequiresApi(16) public static inline operator <T> boolean contains(android.util.LongSparseArray<T>, long key);
+ method @RequiresApi(16) public static inline <T> boolean containsKey(android.util.LongSparseArray<T>, long key);
+ method @RequiresApi(16) public static inline <T> boolean containsValue(android.util.LongSparseArray<T>, T? value);
+ method @RequiresApi(16) public static inline <T> void forEach(android.util.LongSparseArray<T>, kotlin.jvm.functions.Function2<? super java.lang.Long,? super T,kotlin.Unit> action);
+ method @RequiresApi(16) public static inline <T> T! getOrDefault(android.util.LongSparseArray<T>, long key, T? defaultValue);
+ method @RequiresApi(16) public static inline <T> T! getOrElse(android.util.LongSparseArray<T>, long key, kotlin.jvm.functions.Function0<? extends T> defaultValue);
+ method @RequiresApi(16) public static inline <T> int getSize(android.util.LongSparseArray<T>);
+ method @RequiresApi(16) public static inline <T> boolean isEmpty(android.util.LongSparseArray<T>);
+ method @RequiresApi(16) public static inline <T> boolean isNotEmpty(android.util.LongSparseArray<T>);
+ method @RequiresApi(16) public static <T> kotlin.collections.LongIterator keyIterator(android.util.LongSparseArray<T>);
+ method @RequiresApi(16) public static operator <T> android.util.LongSparseArray<T> plus(android.util.LongSparseArray<T>, android.util.LongSparseArray<T> other);
+ method @RequiresApi(16) public static <T> void putAll(android.util.LongSparseArray<T>, android.util.LongSparseArray<T> other);
+ method @RequiresApi(16) public static <T> boolean remove(android.util.LongSparseArray<T>, long key, T? value);
+ method @RequiresApi(16) public static inline operator <T> void set(android.util.LongSparseArray<T>, long key, T? value);
+ method @RequiresApi(16) public static <T> java.util.Iterator<T> valueIterator(android.util.LongSparseArray<T>);
+ }
+
+ public final class LruCacheKt {
+ method public static inline <K, V> android.util.LruCache<K,V> lruCache(int maxSize, optional kotlin.jvm.functions.Function2<? super K,? super V,java.lang.Integer> sizeOf, optional kotlin.jvm.functions.Function1<? super K,? extends V> create, optional kotlin.jvm.functions.Function4<? super java.lang.Boolean,? super K,? super V,? super V,kotlin.Unit> onEntryRemoved);
+ }
+
+ public final class PairKt {
+ method public static inline operator <F, S> F! component1(androidx.core.util.Pair<F,S>);
+ method public static inline operator <F, S> F! component1(android.util.Pair<F,S>);
+ method public static inline operator <F, S> S! component2(androidx.core.util.Pair<F,S>);
+ method public static inline operator <F, S> S! component2(android.util.Pair<F,S>);
+ method public static inline <F, S> android.util.Pair<F,S> toAndroidPair(kotlin.Pair<? extends F,? extends S>);
+ method public static inline <F, S> androidx.core.util.Pair<F,S> toAndroidXPair(kotlin.Pair<? extends F,? extends S>);
+ method public static inline <F, S> kotlin.Pair<F,S> toKotlinPair(androidx.core.util.Pair<F,S>);
+ method public static inline <F, S> kotlin.Pair<F,S> toKotlinPair(android.util.Pair<F,S>);
+ }
+
+ public final class RangeKt {
+ method @RequiresApi(21) public static inline infix <T extends java.lang.Comparable<? super T>> android.util.Range<T> and(android.util.Range<T>, android.util.Range<T> other);
+ method @RequiresApi(21) public static inline operator <T extends java.lang.Comparable<? super T>> android.util.Range<T> plus(android.util.Range<T>, T value);
+ method @RequiresApi(21) public static inline operator <T extends java.lang.Comparable<? super T>> android.util.Range<T> plus(android.util.Range<T>, android.util.Range<T> other);
+ method @RequiresApi(21) public static inline infix <T extends java.lang.Comparable<? super T>> android.util.Range<T> rangeTo(T, T that);
+ method @RequiresApi(21) public static <T extends java.lang.Comparable<? super T>> kotlin.ranges.ClosedRange<T> toClosedRange(android.util.Range<T>);
+ method @RequiresApi(21) public static <T extends java.lang.Comparable<? super T>> android.util.Range<T> toRange(kotlin.ranges.ClosedRange<T>);
+ }
+
+ public final class RunnableKt {
+ method public static Runnable asRunnable(kotlin.coroutines.Continuation<? super kotlin.Unit>);
+ }
+
+ public final class SizeKt {
+ method @RequiresApi(21) public static inline operator int component1(android.util.Size);
+ method @RequiresApi(21) public static inline operator float component1(android.util.SizeF);
+ method public static inline operator float component1(androidx.core.util.SizeFCompat);
+ method @RequiresApi(21) public static inline operator int component2(android.util.Size);
+ method @RequiresApi(21) public static inline operator float component2(android.util.SizeF);
+ method public static inline operator float component2(androidx.core.util.SizeFCompat);
+ }
+
+ public final class SparseArrayKt {
+ method public static inline operator <T> boolean contains(android.util.SparseArray<T>, int key);
+ method public static inline <T> boolean containsKey(android.util.SparseArray<T>, int key);
+ method public static inline <T> boolean containsValue(android.util.SparseArray<T>, T? value);
+ method public static inline <T> void forEach(android.util.SparseArray<T>, kotlin.jvm.functions.Function2<? super java.lang.Integer,? super T,kotlin.Unit> action);
+ method public static inline <T> T! getOrDefault(android.util.SparseArray<T>, int key, T? defaultValue);
+ method public static inline <T> T! getOrElse(android.util.SparseArray<T>, int key, kotlin.jvm.functions.Function0<? extends T> defaultValue);
+ method public static inline <T> int getSize(android.util.SparseArray<T>);
+ method public static inline <T> boolean isEmpty(android.util.SparseArray<T>);
+ method public static inline <T> boolean isNotEmpty(android.util.SparseArray<T>);
+ method public static <T> kotlin.collections.IntIterator keyIterator(android.util.SparseArray<T>);
+ method public static operator <T> android.util.SparseArray<T> plus(android.util.SparseArray<T>, android.util.SparseArray<T> other);
+ method public static <T> void putAll(android.util.SparseArray<T>, android.util.SparseArray<T> other);
+ method public static <T> boolean remove(android.util.SparseArray<T>, int key, T? value);
+ method public static inline operator <T> void set(android.util.SparseArray<T>, int key, T? value);
+ method public static <T> java.util.Iterator<T> valueIterator(android.util.SparseArray<T>);
+ }
+
+ public final class SparseBooleanArrayKt {
+ method public static inline operator boolean contains(android.util.SparseBooleanArray, int key);
+ method public static inline boolean containsKey(android.util.SparseBooleanArray, int key);
+ method public static inline boolean containsValue(android.util.SparseBooleanArray, boolean value);
+ method public static inline void forEach(android.util.SparseBooleanArray, kotlin.jvm.functions.Function2<? super java.lang.Integer,? super java.lang.Boolean,kotlin.Unit> action);
+ method public static inline boolean getOrDefault(android.util.SparseBooleanArray, int key, boolean defaultValue);
+ method public static inline boolean getOrElse(android.util.SparseBooleanArray, int key, kotlin.jvm.functions.Function0<java.lang.Boolean> defaultValue);
+ method public static inline int getSize(android.util.SparseBooleanArray);
+ method public static inline boolean isEmpty(android.util.SparseBooleanArray);
+ method public static inline boolean isNotEmpty(android.util.SparseBooleanArray);
+ method public static kotlin.collections.IntIterator keyIterator(android.util.SparseBooleanArray);
+ method public static operator android.util.SparseBooleanArray plus(android.util.SparseBooleanArray, android.util.SparseBooleanArray other);
+ method public static void putAll(android.util.SparseBooleanArray, android.util.SparseBooleanArray other);
+ method public static boolean remove(android.util.SparseBooleanArray, int key, boolean value);
+ method public static inline operator void set(android.util.SparseBooleanArray, int key, boolean value);
+ method public static kotlin.collections.BooleanIterator valueIterator(android.util.SparseBooleanArray);
+ }
+
+ public final class SparseIntArrayKt {
+ method public static inline operator boolean contains(android.util.SparseIntArray, int key);
+ method public static inline boolean containsKey(android.util.SparseIntArray, int key);
+ method public static inline boolean containsValue(android.util.SparseIntArray, int value);
+ method public static inline void forEach(android.util.SparseIntArray, kotlin.jvm.functions.Function2<? super java.lang.Integer,? super java.lang.Integer,kotlin.Unit> action);
+ method public static inline int getOrDefault(android.util.SparseIntArray, int key, int defaultValue);
+ method public static inline int getOrElse(android.util.SparseIntArray, int key, kotlin.jvm.functions.Function0<java.lang.Integer> defaultValue);
+ method public static inline int getSize(android.util.SparseIntArray);
+ method public static inline boolean isEmpty(android.util.SparseIntArray);
+ method public static inline boolean isNotEmpty(android.util.SparseIntArray);
+ method public static kotlin.collections.IntIterator keyIterator(android.util.SparseIntArray);
+ method public static operator android.util.SparseIntArray plus(android.util.SparseIntArray, android.util.SparseIntArray other);
+ method public static void putAll(android.util.SparseIntArray, android.util.SparseIntArray other);
+ method public static boolean remove(android.util.SparseIntArray, int key, int value);
+ method public static inline operator void set(android.util.SparseIntArray, int key, int value);
+ method public static kotlin.collections.IntIterator valueIterator(android.util.SparseIntArray);
+ }
+
+ public final class SparseLongArrayKt {
+ method @RequiresApi(18) public static inline operator boolean contains(android.util.SparseLongArray, int key);
+ method @RequiresApi(18) public static inline boolean containsKey(android.util.SparseLongArray, int key);
+ method @RequiresApi(18) public static inline boolean containsValue(android.util.SparseLongArray, long value);
+ method @RequiresApi(18) public static inline void forEach(android.util.SparseLongArray, kotlin.jvm.functions.Function2<? super java.lang.Integer,? super java.lang.Long,kotlin.Unit> action);
+ method @RequiresApi(18) public static inline long getOrDefault(android.util.SparseLongArray, int key, long defaultValue);
+ method @RequiresApi(18) public static inline long getOrElse(android.util.SparseLongArray, int key, kotlin.jvm.functions.Function0<java.lang.Long> defaultValue);
+ method @RequiresApi(18) public static inline int getSize(android.util.SparseLongArray);
+ method @RequiresApi(18) public static inline boolean isEmpty(android.util.SparseLongArray);
+ method @RequiresApi(18) public static inline boolean isNotEmpty(android.util.SparseLongArray);
+ method @RequiresApi(18) public static kotlin.collections.IntIterator keyIterator(android.util.SparseLongArray);
+ method @RequiresApi(18) public static operator android.util.SparseLongArray plus(android.util.SparseLongArray, android.util.SparseLongArray other);
+ method @RequiresApi(18) public static void putAll(android.util.SparseLongArray, android.util.SparseLongArray other);
+ method @RequiresApi(18) public static boolean remove(android.util.SparseLongArray, int key, long value);
+ method @RequiresApi(18) public static inline operator void set(android.util.SparseLongArray, int key, long value);
+ method @RequiresApi(18) public static kotlin.collections.LongIterator valueIterator(android.util.SparseLongArray);
+ }
+
+}
+
+package androidx.core.view {
+
+ public final class MenuKt {
+ method public static operator boolean contains(android.view.Menu, android.view.MenuItem item);
+ method public static inline void forEach(android.view.Menu, kotlin.jvm.functions.Function1<? super android.view.MenuItem,kotlin.Unit> action);
+ method public static inline void forEachIndexed(android.view.Menu, kotlin.jvm.functions.Function2<? super java.lang.Integer,? super android.view.MenuItem,kotlin.Unit> action);
+ method public static inline operator android.view.MenuItem get(android.view.Menu, int index);
+ method public static kotlin.sequences.Sequence<android.view.MenuItem> getChildren(android.view.Menu);
+ method public static inline int getSize(android.view.Menu);
+ method public static inline boolean isEmpty(android.view.Menu);
+ method public static inline boolean isNotEmpty(android.view.Menu);
+ method public static operator java.util.Iterator<android.view.MenuItem> iterator(android.view.Menu);
+ method public static inline operator void minusAssign(android.view.Menu, android.view.MenuItem item);
+ method public static inline void removeItemAt(android.view.Menu, int index);
+ }
+
+ public final class ViewGroupKt {
+ method public static inline operator boolean contains(android.view.ViewGroup, android.view.View view);
+ method public static inline void forEach(android.view.ViewGroup, kotlin.jvm.functions.Function1<? super android.view.View,kotlin.Unit> action);
+ method public static inline void forEachIndexed(android.view.ViewGroup, kotlin.jvm.functions.Function2<? super java.lang.Integer,? super android.view.View,kotlin.Unit> action);
+ method public static operator android.view.View get(android.view.ViewGroup, int index);
+ method public static kotlin.sequences.Sequence<android.view.View> getChildren(android.view.ViewGroup);
+ method public static kotlin.sequences.Sequence<android.view.View> getDescendants(android.view.ViewGroup);
+ method public static inline kotlin.ranges.IntRange getIndices(android.view.ViewGroup);
+ method public static inline int getSize(android.view.ViewGroup);
+ method public static inline boolean isEmpty(android.view.ViewGroup);
+ method public static inline boolean isNotEmpty(android.view.ViewGroup);
+ method public static operator java.util.Iterator<android.view.View> iterator(android.view.ViewGroup);
+ method public static inline operator void minusAssign(android.view.ViewGroup, android.view.View view);
+ method public static inline operator void plusAssign(android.view.ViewGroup, android.view.View view);
+ method public static inline void setMargins(android.view.ViewGroup.MarginLayoutParams, @Px int size);
+ method public static inline void updateMargins(android.view.ViewGroup.MarginLayoutParams, optional @Px int left, optional @Px int top, optional @Px int right, optional @Px int bottom);
+ method @RequiresApi(17) public static inline void updateMarginsRelative(android.view.ViewGroup.MarginLayoutParams, optional @Px int start, optional @Px int top, optional @Px int end, optional @Px int bottom);
+ }
+
+ public final class ViewKt {
+ method public static inline void doOnAttach(android.view.View, kotlin.jvm.functions.Function1<? super android.view.View,kotlin.Unit> action);
+ method public static inline void doOnDetach(android.view.View, kotlin.jvm.functions.Function1<? super android.view.View,kotlin.Unit> action);
+ method public static inline void doOnLayout(android.view.View, kotlin.jvm.functions.Function1<? super android.view.View,kotlin.Unit> action);
+ method public static inline void doOnNextLayout(android.view.View, kotlin.jvm.functions.Function1<? super android.view.View,kotlin.Unit> action);
+ method public static inline androidx.core.view.OneShotPreDrawListener doOnPreDraw(android.view.View, kotlin.jvm.functions.Function1<? super android.view.View,kotlin.Unit> action);
+ method public static android.graphics.Bitmap drawToBitmap(android.view.View, optional android.graphics.Bitmap.Config config);
+ method public static kotlin.sequences.Sequence<android.view.View> getAllViews(android.view.View);
+ method public static kotlin.sequences.Sequence<android.view.ViewParent> getAncestors(android.view.View);
+ method public static inline int getMarginBottom(android.view.View);
+ method public static inline int getMarginEnd(android.view.View);
+ method public static inline int getMarginLeft(android.view.View);
+ method public static inline int getMarginRight(android.view.View);
+ method public static inline int getMarginStart(android.view.View);
+ method public static inline int getMarginTop(android.view.View);
+ method public static inline boolean isGone(android.view.View);
+ method public static inline boolean isInvisible(android.view.View);
+ method public static inline boolean isVisible(android.view.View);
+ method public static inline Runnable postDelayed(android.view.View, long delayInMillis, kotlin.jvm.functions.Function0<kotlin.Unit> action);
+ method @RequiresApi(16) public static Runnable postOnAnimationDelayed(android.view.View, long delayInMillis, kotlin.jvm.functions.Function0<kotlin.Unit> action);
+ method public static inline void setGone(android.view.View, boolean);
+ method public static inline void setInvisible(android.view.View, boolean);
+ method public static inline void setPadding(android.view.View, @Px int size);
+ method public static inline void setVisible(android.view.View, boolean);
+ method public static inline void updateLayoutParams(android.view.View, kotlin.jvm.functions.Function1<? super android.view.ViewGroup.LayoutParams,kotlin.Unit> block);
+ method public static inline <reified T extends android.view.ViewGroup.LayoutParams> void updateLayoutParams(android.view.View, kotlin.jvm.functions.Function1<? super T,? extends kotlin.Unit> block);
+ method public static inline void updatePadding(android.view.View, optional @Px int left, optional @Px int top, optional @Px int right, optional @Px int bottom);
+ method @RequiresApi(17) public static inline void updatePaddingRelative(android.view.View, optional @Px int start, optional @Px int top, optional @Px int end, optional @Px int bottom);
+ }
+
+}
+
+package androidx.core.widget {
+
+ public final class TextViewKt {
+ method public static inline android.text.TextWatcher addTextChangedListener(android.widget.TextView, optional kotlin.jvm.functions.Function4<? super java.lang.CharSequence,? super java.lang.Integer,? super java.lang.Integer,? super java.lang.Integer,kotlin.Unit> beforeTextChanged, optional kotlin.jvm.functions.Function4<? super java.lang.CharSequence,? super java.lang.Integer,? super java.lang.Integer,? super java.lang.Integer,kotlin.Unit> onTextChanged, optional kotlin.jvm.functions.Function1<? super android.text.Editable,kotlin.Unit> afterTextChanged);
+ method public static inline android.text.TextWatcher doAfterTextChanged(android.widget.TextView, kotlin.jvm.functions.Function1<? super android.text.Editable,kotlin.Unit> action);
+ method public static inline android.text.TextWatcher doBeforeTextChanged(android.widget.TextView, kotlin.jvm.functions.Function4<? super java.lang.CharSequence,? super java.lang.Integer,? super java.lang.Integer,? super java.lang.Integer,kotlin.Unit> action);
+ method public static inline android.text.TextWatcher doOnTextChanged(android.widget.TextView, kotlin.jvm.functions.Function4<? super java.lang.CharSequence,? super java.lang.Integer,? super java.lang.Integer,? super java.lang.Integer,kotlin.Unit> action);
+ }
+
+}
+
diff --git a/core/core-ktx/src/main/java/androidx/core/os/OutcomeReceiver.kt b/core/core-ktx/src/main/java/androidx/core/os/OutcomeReceiver.kt
index 74052a3..d6698aa 100644
--- a/core/core-ktx/src/main/java/androidx/core/os/OutcomeReceiver.kt
+++ b/core/core-ktx/src/main/java/androidx/core/os/OutcomeReceiver.kt
@@ -61,7 +61,7 @@
private class ContinuationOutcomeReceiver<R, E : Throwable>(
private val continuation: Continuation<R>
) : OutcomeReceiver<R, E>, AtomicBoolean(false) {
- override fun onResult(result: R & Any) {
+ override fun onResult(result: R) {
// Do not attempt to resume more than once, even if the caller of the returned
// OutcomeReceiver is buggy and tries anyway.
if (compareAndSet(false, true)) {
diff --git a/core/core-telecom/OWNERS b/core/core-telecom/OWNERS
new file mode 100644
index 0000000..7de7eb4
--- /dev/null
+++ b/core/core-telecom/OWNERS
@@ -0,0 +1,9 @@
+# Bug component: 151185
+breadley@google.com
+tgunn@google.com
+xiaotonj@google.com
+chinmayd@google.com
+tjstuart@google.com
+rgreenwalt@google.com
+pmadapurmath@google.com
+grantmenke@google.com
diff --git a/core/core-telecom/api/current.txt b/core/core-telecom/api/current.txt
new file mode 100644
index 0000000..e6f50d0
--- /dev/null
+++ b/core/core-telecom/api/current.txt
@@ -0,0 +1 @@
+// Signature format: 4.0
diff --git a/core/core-telecom/api/public_plus_experimental_current.txt b/core/core-telecom/api/public_plus_experimental_current.txt
new file mode 100644
index 0000000..e6f50d0
--- /dev/null
+++ b/core/core-telecom/api/public_plus_experimental_current.txt
@@ -0,0 +1 @@
+// Signature format: 4.0
diff --git a/webkit/webkit/api/res-1.6.0-beta02.txt b/core/core-telecom/api/res-current.txt
similarity index 100%
copy from webkit/webkit/api/res-1.6.0-beta02.txt
copy to core/core-telecom/api/res-current.txt
diff --git a/core/core-telecom/api/restricted_current.txt b/core/core-telecom/api/restricted_current.txt
new file mode 100644
index 0000000..e6f50d0
--- /dev/null
+++ b/core/core-telecom/api/restricted_current.txt
@@ -0,0 +1 @@
+// Signature format: 4.0
diff --git a/core/core-telecom/build.gradle b/core/core-telecom/build.gradle
new file mode 100644
index 0000000..6f3ef0c
--- /dev/null
+++ b/core/core-telecom/build.gradle
@@ -0,0 +1,40 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import androidx.build.LibraryType
+
+plugins {
+ id("AndroidXPlugin")
+ id("com.android.library")
+ id("org.jetbrains.kotlin.android")
+}
+
+dependencies {
+ api(libs.kotlinStdlib)
+ // Add dependencies here
+}
+
+android {
+ namespace "androidx.core.telecom"
+}
+
+androidx {
+ name = "androidx.core:core-telecom"
+ type = LibraryType.PUBLISHED_LIBRARY
+ mavenVersion = LibraryVersions.CORE_TELECOM
+ inceptionYear = "2023"
+ description = "Integrate VoIP calls with the Telecom framework."
+}
diff --git a/core/core-telecom/src/main/java/androidx/core/androidx-core-core-telecom-documentation.md b/core/core-telecom/src/main/java/androidx/core/androidx-core-core-telecom-documentation.md
new file mode 100644
index 0000000..bfb5ecc
--- /dev/null
+++ b/core/core-telecom/src/main/java/androidx/core/androidx-core-core-telecom-documentation.md
@@ -0,0 +1,7 @@
+# Module root
+
+<GROUPID> <ARTIFACTID>
+
+# Package androidx.core.telecom
+
+TODO: Document
diff --git a/core/core/api/1.10.0-beta01.txt b/core/core/api/1.10.0-beta01.txt
new file mode 100644
index 0000000..5033a53
--- /dev/null
+++ b/core/core/api/1.10.0-beta01.txt
@@ -0,0 +1,3929 @@
+// Signature format: 4.0
+package androidx.core.accessibilityservice {
+
+ public final class AccessibilityServiceInfoCompat {
+ method public static String capabilityToString(int);
+ method public static String feedbackTypeToString(int);
+ method public static String? flagToString(int);
+ method public static int getCapabilities(android.accessibilityservice.AccessibilityServiceInfo);
+ method public static String? loadDescription(android.accessibilityservice.AccessibilityServiceInfo, android.content.pm.PackageManager);
+ field public static final int CAPABILITY_CAN_FILTER_KEY_EVENTS = 8; // 0x8
+ field public static final int CAPABILITY_CAN_REQUEST_ENHANCED_WEB_ACCESSIBILITY = 4; // 0x4
+ field public static final int CAPABILITY_CAN_REQUEST_TOUCH_EXPLORATION = 2; // 0x2
+ field public static final int CAPABILITY_CAN_RETRIEVE_WINDOW_CONTENT = 1; // 0x1
+ field public static final int FEEDBACK_ALL_MASK = -1; // 0xffffffff
+ field public static final int FEEDBACK_BRAILLE = 32; // 0x20
+ field public static final int FLAG_INCLUDE_NOT_IMPORTANT_VIEWS = 2; // 0x2
+ field public static final int FLAG_REPORT_VIEW_IDS = 16; // 0x10
+ field public static final int FLAG_REQUEST_ENHANCED_WEB_ACCESSIBILITY = 8; // 0x8
+ field public static final int FLAG_REQUEST_FILTER_KEY_EVENTS = 32; // 0x20
+ field public static final int FLAG_REQUEST_TOUCH_EXPLORATION_MODE = 4; // 0x4
+ }
+
+}
+
+package androidx.core.app {
+
+ public class ActivityCompat extends androidx.core.content.ContextCompat {
+ ctor protected ActivityCompat();
+ method public static void finishAffinity(android.app.Activity);
+ method public static void finishAfterTransition(android.app.Activity);
+ method public static android.net.Uri? getReferrer(android.app.Activity);
+ method @Deprecated public static boolean invalidateOptionsMenu(android.app.Activity!);
+ method public static boolean isLaunchedFromBubble(android.app.Activity);
+ method public static void postponeEnterTransition(android.app.Activity);
+ method public static void recreate(android.app.Activity);
+ method public static androidx.core.view.DragAndDropPermissionsCompat? requestDragAndDropPermissions(android.app.Activity, android.view.DragEvent);
+ method public static void requestPermissions(android.app.Activity, String![], @IntRange(from=0) int);
+ method public static <T extends android.view.View> T requireViewById(android.app.Activity, @IdRes int);
+ method public static void setEnterSharedElementCallback(android.app.Activity, androidx.core.app.SharedElementCallback?);
+ method public static void setExitSharedElementCallback(android.app.Activity, androidx.core.app.SharedElementCallback?);
+ method public static void setLocusContext(android.app.Activity, androidx.core.content.LocusIdCompat?, android.os.Bundle?);
+ method public static void setPermissionCompatDelegate(androidx.core.app.ActivityCompat.PermissionCompatDelegate?);
+ method public static boolean shouldShowRequestPermissionRationale(android.app.Activity, String);
+ method public static void startActivityForResult(android.app.Activity, android.content.Intent, int, android.os.Bundle?);
+ method public static void startIntentSenderForResult(android.app.Activity, android.content.IntentSender, int, android.content.Intent?, int, int, int, android.os.Bundle?) throws android.content.IntentSender.SendIntentException;
+ method public static void startPostponedEnterTransition(android.app.Activity);
+ }
+
+ public static interface ActivityCompat.OnRequestPermissionsResultCallback {
+ method public void onRequestPermissionsResult(int, String![], int[]);
+ }
+
+ public static interface ActivityCompat.PermissionCompatDelegate {
+ method public boolean onActivityResult(android.app.Activity, @IntRange(from=0) int, int, android.content.Intent?);
+ method public boolean requestPermissions(android.app.Activity, String![], @IntRange(from=0) int);
+ }
+
+ public final class ActivityManagerCompat {
+ method public static boolean isLowRamDevice(android.app.ActivityManager);
+ }
+
+ public class ActivityOptionsCompat {
+ ctor protected ActivityOptionsCompat();
+ method public android.graphics.Rect? getLaunchBounds();
+ method public static androidx.core.app.ActivityOptionsCompat makeBasic();
+ method public static androidx.core.app.ActivityOptionsCompat makeClipRevealAnimation(android.view.View, int, int, int, int);
+ method public static androidx.core.app.ActivityOptionsCompat makeCustomAnimation(android.content.Context, int, int);
+ method public static androidx.core.app.ActivityOptionsCompat makeScaleUpAnimation(android.view.View, int, int, int, int);
+ method public static androidx.core.app.ActivityOptionsCompat makeSceneTransitionAnimation(android.app.Activity, android.view.View, String);
+ method public static androidx.core.app.ActivityOptionsCompat makeSceneTransitionAnimation(android.app.Activity, androidx.core.util.Pair<android.view.View!,java.lang.String!>!...);
+ method public static androidx.core.app.ActivityOptionsCompat makeTaskLaunchBehind();
+ method public static androidx.core.app.ActivityOptionsCompat makeThumbnailScaleUpAnimation(android.view.View, android.graphics.Bitmap, int, int);
+ method public void requestUsageTimeReport(android.app.PendingIntent);
+ method public androidx.core.app.ActivityOptionsCompat setLaunchBounds(android.graphics.Rect?);
+ method public android.os.Bundle? toBundle();
+ method public void update(androidx.core.app.ActivityOptionsCompat);
+ field public static final String EXTRA_USAGE_TIME_REPORT = "android.activity.usage_time";
+ field public static final String EXTRA_USAGE_TIME_REPORT_PACKAGES = "android.usage_time_packages";
+ }
+
+ public final class AlarmManagerCompat {
+ method public static void setAlarmClock(android.app.AlarmManager, long, android.app.PendingIntent, android.app.PendingIntent);
+ method public static void setAndAllowWhileIdle(android.app.AlarmManager, int, long, android.app.PendingIntent);
+ method public static void setExact(android.app.AlarmManager, int, long, android.app.PendingIntent);
+ method public static void setExactAndAllowWhileIdle(android.app.AlarmManager, int, long, android.app.PendingIntent);
+ }
+
+ @RequiresApi(28) public class AppComponentFactory extends android.app.AppComponentFactory {
+ ctor public AppComponentFactory();
+ method public final android.app.Activity instantiateActivity(ClassLoader, String, android.content.Intent?) throws java.lang.ClassNotFoundException, java.lang.IllegalAccessException, java.lang.InstantiationException;
+ method public android.app.Activity instantiateActivityCompat(ClassLoader, String, android.content.Intent?) throws java.lang.ClassNotFoundException, java.lang.IllegalAccessException, java.lang.InstantiationException;
+ method public final android.app.Application instantiateApplication(ClassLoader, String) throws java.lang.ClassNotFoundException, java.lang.IllegalAccessException, java.lang.InstantiationException;
+ method public android.app.Application instantiateApplicationCompat(ClassLoader, String) throws java.lang.ClassNotFoundException, java.lang.IllegalAccessException, java.lang.InstantiationException;
+ method public final android.content.ContentProvider instantiateProvider(ClassLoader, String) throws java.lang.ClassNotFoundException, java.lang.IllegalAccessException, java.lang.InstantiationException;
+ method public android.content.ContentProvider instantiateProviderCompat(ClassLoader, String) throws java.lang.ClassNotFoundException, java.lang.IllegalAccessException, java.lang.InstantiationException;
+ method public final android.content.BroadcastReceiver instantiateReceiver(ClassLoader, String, android.content.Intent?) throws java.lang.ClassNotFoundException, java.lang.IllegalAccessException, java.lang.InstantiationException;
+ method public android.content.BroadcastReceiver instantiateReceiverCompat(ClassLoader, String, android.content.Intent?) throws java.lang.ClassNotFoundException, java.lang.IllegalAccessException, java.lang.InstantiationException;
+ method public final android.app.Service instantiateService(ClassLoader, String, android.content.Intent?) throws java.lang.ClassNotFoundException, java.lang.IllegalAccessException, java.lang.InstantiationException;
+ method public android.app.Service instantiateServiceCompat(ClassLoader, String, android.content.Intent?) throws java.lang.ClassNotFoundException, java.lang.IllegalAccessException, java.lang.InstantiationException;
+ }
+
+ public class AppLaunchChecker {
+ ctor @Deprecated public AppLaunchChecker();
+ method public static boolean hasStartedFromLauncher(android.content.Context);
+ method public static void onActivityCreate(android.app.Activity);
+ }
+
+ public final class AppOpsManagerCompat {
+ method public static int checkOrNoteProxyOp(android.content.Context, int, String, String);
+ method public static int noteOp(android.content.Context, String, int, String);
+ method public static int noteOpNoThrow(android.content.Context, String, int, String);
+ method public static int noteProxyOp(android.content.Context, String, String);
+ method public static int noteProxyOpNoThrow(android.content.Context, String, String);
+ method public static String? permissionToOp(String);
+ field public static final int MODE_ALLOWED = 0; // 0x0
+ field public static final int MODE_DEFAULT = 3; // 0x3
+ field public static final int MODE_ERRORED = 2; // 0x2
+ field public static final int MODE_IGNORED = 1; // 0x1
+ }
+
+ public final class BundleCompat {
+ method public static android.os.IBinder? getBinder(android.os.Bundle, String?);
+ method public static void putBinder(android.os.Bundle, String?, android.os.IBinder?);
+ }
+
+ public class DialogCompat {
+ method public static android.view.View requireViewById(android.app.Dialog, int);
+ }
+
+ public class FrameMetricsAggregator {
+ ctor public FrameMetricsAggregator();
+ ctor public FrameMetricsAggregator(int);
+ method public void add(android.app.Activity);
+ method public android.util.SparseIntArray![]? getMetrics();
+ method public android.util.SparseIntArray![]? remove(android.app.Activity);
+ method public android.util.SparseIntArray![]? reset();
+ method public android.util.SparseIntArray![]? stop();
+ field public static final int ANIMATION_DURATION = 256; // 0x100
+ field public static final int ANIMATION_INDEX = 8; // 0x8
+ field public static final int COMMAND_DURATION = 32; // 0x20
+ field public static final int COMMAND_INDEX = 5; // 0x5
+ field public static final int DELAY_DURATION = 128; // 0x80
+ field public static final int DELAY_INDEX = 7; // 0x7
+ field public static final int DRAW_DURATION = 8; // 0x8
+ field public static final int DRAW_INDEX = 3; // 0x3
+ field public static final int EVERY_DURATION = 511; // 0x1ff
+ field public static final int INPUT_DURATION = 2; // 0x2
+ field public static final int INPUT_INDEX = 1; // 0x1
+ field public static final int LAYOUT_MEASURE_DURATION = 4; // 0x4
+ field public static final int LAYOUT_MEASURE_INDEX = 2; // 0x2
+ field public static final int SWAP_DURATION = 64; // 0x40
+ field public static final int SWAP_INDEX = 6; // 0x6
+ field public static final int SYNC_DURATION = 16; // 0x10
+ field public static final int SYNC_INDEX = 4; // 0x4
+ field public static final int TOTAL_DURATION = 1; // 0x1
+ field public static final int TOTAL_INDEX = 0; // 0x0
+ }
+
+ @Deprecated public abstract class JobIntentService extends android.app.Service {
+ ctor @Deprecated public JobIntentService();
+ method @Deprecated public static void enqueueWork(android.content.Context, Class<?>, int, android.content.Intent);
+ method @Deprecated public static void enqueueWork(android.content.Context, android.content.ComponentName, int, android.content.Intent);
+ method @Deprecated public boolean isStopped();
+ method @Deprecated public android.os.IBinder! onBind(android.content.Intent);
+ method @Deprecated protected abstract void onHandleWork(android.content.Intent);
+ method @Deprecated public boolean onStopCurrentWork();
+ method @Deprecated public void setInterruptIfStopped(boolean);
+ }
+
+ public final class LocaleManagerCompat {
+ method @AnyThread public static androidx.core.os.LocaleListCompat getSystemLocales(android.content.Context);
+ }
+
+ public final class MultiWindowModeChangedInfo {
+ ctor public MultiWindowModeChangedInfo(boolean);
+ ctor @RequiresApi(26) public MultiWindowModeChangedInfo(boolean, android.content.res.Configuration);
+ method @RequiresApi(26) public android.content.res.Configuration getNewConfig();
+ method public boolean isInMultiWindowMode();
+ }
+
+ public final class NavUtils {
+ method public static android.content.Intent? getParentActivityIntent(android.app.Activity);
+ method public static android.content.Intent? getParentActivityIntent(android.content.Context, Class<?>) throws android.content.pm.PackageManager.NameNotFoundException;
+ method public static android.content.Intent? getParentActivityIntent(android.content.Context, android.content.ComponentName) throws android.content.pm.PackageManager.NameNotFoundException;
+ method public static String? getParentActivityName(android.app.Activity);
+ method public static String? getParentActivityName(android.content.Context, android.content.ComponentName) throws android.content.pm.PackageManager.NameNotFoundException;
+ method public static void navigateUpFromSameTask(android.app.Activity);
+ method public static void navigateUpTo(android.app.Activity, android.content.Intent);
+ method public static boolean shouldUpRecreateTask(android.app.Activity, android.content.Intent);
+ field public static final String PARENT_ACTIVITY = "android.support.PARENT_ACTIVITY";
+ }
+
+ public class NotificationChannelCompat {
+ method public boolean canBubble();
+ method public boolean canBypassDnd();
+ method public boolean canShowBadge();
+ method public android.media.AudioAttributes? getAudioAttributes();
+ method public String? getConversationId();
+ method public String? getDescription();
+ method public String? getGroup();
+ method public String getId();
+ method public int getImportance();
+ method public int getLightColor();
+ method public int getLockscreenVisibility();
+ method public CharSequence? getName();
+ method public String? getParentChannelId();
+ method public android.net.Uri? getSound();
+ method public long[]? getVibrationPattern();
+ method public boolean isImportantConversation();
+ method public boolean shouldShowLights();
+ method public boolean shouldVibrate();
+ method public androidx.core.app.NotificationChannelCompat.Builder toBuilder();
+ field public static final String DEFAULT_CHANNEL_ID = "miscellaneous";
+ }
+
+ public static class NotificationChannelCompat.Builder {
+ ctor public NotificationChannelCompat.Builder(String, int);
+ method public androidx.core.app.NotificationChannelCompat build();
+ method public androidx.core.app.NotificationChannelCompat.Builder setConversationId(String, String);
+ method public androidx.core.app.NotificationChannelCompat.Builder setDescription(String?);
+ method public androidx.core.app.NotificationChannelCompat.Builder setGroup(String?);
+ method public androidx.core.app.NotificationChannelCompat.Builder setImportance(int);
+ method public androidx.core.app.NotificationChannelCompat.Builder setLightColor(int);
+ method public androidx.core.app.NotificationChannelCompat.Builder setLightsEnabled(boolean);
+ method public androidx.core.app.NotificationChannelCompat.Builder setName(CharSequence?);
+ method public androidx.core.app.NotificationChannelCompat.Builder setShowBadge(boolean);
+ method public androidx.core.app.NotificationChannelCompat.Builder setSound(android.net.Uri?, android.media.AudioAttributes?);
+ method public androidx.core.app.NotificationChannelCompat.Builder setVibrationEnabled(boolean);
+ method public androidx.core.app.NotificationChannelCompat.Builder setVibrationPattern(long[]?);
+ }
+
+ public class NotificationChannelGroupCompat {
+ method public java.util.List<androidx.core.app.NotificationChannelCompat!> getChannels();
+ method public String? getDescription();
+ method public String getId();
+ method public CharSequence? getName();
+ method public boolean isBlocked();
+ method public androidx.core.app.NotificationChannelGroupCompat.Builder toBuilder();
+ }
+
+ public static class NotificationChannelGroupCompat.Builder {
+ ctor public NotificationChannelGroupCompat.Builder(String);
+ method public androidx.core.app.NotificationChannelGroupCompat build();
+ method public androidx.core.app.NotificationChannelGroupCompat.Builder setDescription(String?);
+ method public androidx.core.app.NotificationChannelGroupCompat.Builder setName(CharSequence?);
+ }
+
+ public class NotificationCompat {
+ ctor @Deprecated public NotificationCompat();
+ method public static androidx.core.app.NotificationCompat.Action? getAction(android.app.Notification, int);
+ method public static int getActionCount(android.app.Notification);
+ method public static boolean getAllowSystemGeneratedContextualActions(android.app.Notification);
+ method public static boolean getAutoCancel(android.app.Notification);
+ method public static int getBadgeIconType(android.app.Notification);
+ method public static androidx.core.app.NotificationCompat.BubbleMetadata? getBubbleMetadata(android.app.Notification);
+ method public static String? getCategory(android.app.Notification);
+ method public static String? getChannelId(android.app.Notification);
+ method public static int getColor(android.app.Notification);
+ method @RequiresApi(19) public static CharSequence? getContentInfo(android.app.Notification);
+ method @RequiresApi(19) public static CharSequence? getContentText(android.app.Notification);
+ method @RequiresApi(19) public static CharSequence? getContentTitle(android.app.Notification);
+ method public static android.os.Bundle? getExtras(android.app.Notification);
+ method public static String? getGroup(android.app.Notification);
+ method public static int getGroupAlertBehavior(android.app.Notification);
+ method @RequiresApi(21) public static java.util.List<androidx.core.app.NotificationCompat.Action!> getInvisibleActions(android.app.Notification);
+ method public static boolean getLocalOnly(android.app.Notification);
+ method public static androidx.core.content.LocusIdCompat? getLocusId(android.app.Notification);
+ method public static boolean getOngoing(android.app.Notification);
+ method public static boolean getOnlyAlertOnce(android.app.Notification);
+ method public static java.util.List<androidx.core.app.Person!> getPeople(android.app.Notification);
+ method public static android.app.Notification? getPublicVersion(android.app.Notification);
+ method public static CharSequence? getSettingsText(android.app.Notification);
+ method public static String? getShortcutId(android.app.Notification);
+ method @RequiresApi(19) public static boolean getShowWhen(android.app.Notification);
+ method public static String? getSortKey(android.app.Notification);
+ method @RequiresApi(19) public static CharSequence? getSubText(android.app.Notification);
+ method public static long getTimeoutAfter(android.app.Notification);
+ method @RequiresApi(19) public static boolean getUsesChronometer(android.app.Notification);
+ method public static int getVisibility(android.app.Notification);
+ method public static boolean isGroupSummary(android.app.Notification);
+ field public static final int BADGE_ICON_LARGE = 2; // 0x2
+ field public static final int BADGE_ICON_NONE = 0; // 0x0
+ field public static final int BADGE_ICON_SMALL = 1; // 0x1
+ field public static final String CATEGORY_ALARM = "alarm";
+ field public static final String CATEGORY_CALL = "call";
+ field public static final String CATEGORY_EMAIL = "email";
+ field public static final String CATEGORY_ERROR = "err";
+ field public static final String CATEGORY_EVENT = "event";
+ field public static final String CATEGORY_LOCATION_SHARING = "location_sharing";
+ field public static final String CATEGORY_MESSAGE = "msg";
+ field public static final String CATEGORY_MISSED_CALL = "missed_call";
+ field public static final String CATEGORY_NAVIGATION = "navigation";
+ field public static final String CATEGORY_PROGRESS = "progress";
+ field public static final String CATEGORY_PROMO = "promo";
+ field public static final String CATEGORY_RECOMMENDATION = "recommendation";
+ field public static final String CATEGORY_REMINDER = "reminder";
+ field public static final String CATEGORY_SERVICE = "service";
+ field public static final String CATEGORY_SOCIAL = "social";
+ field public static final String CATEGORY_STATUS = "status";
+ field public static final String CATEGORY_STOPWATCH = "stopwatch";
+ field public static final String CATEGORY_SYSTEM = "sys";
+ field public static final String CATEGORY_TRANSPORT = "transport";
+ field public static final String CATEGORY_WORKOUT = "workout";
+ field @ColorInt public static final int COLOR_DEFAULT = 0; // 0x0
+ field public static final int DEFAULT_ALL = -1; // 0xffffffff
+ field public static final int DEFAULT_LIGHTS = 4; // 0x4
+ field public static final int DEFAULT_SOUND = 1; // 0x1
+ field public static final int DEFAULT_VIBRATE = 2; // 0x2
+ field public static final String EXTRA_ANSWER_COLOR = "android.answerColor";
+ field public static final String EXTRA_ANSWER_INTENT = "android.answerIntent";
+ field public static final String EXTRA_AUDIO_CONTENTS_URI = "android.audioContents";
+ field public static final String EXTRA_BACKGROUND_IMAGE_URI = "android.backgroundImageUri";
+ field public static final String EXTRA_BIG_TEXT = "android.bigText";
+ field public static final String EXTRA_CALL_IS_VIDEO = "android.callIsVideo";
+ field public static final String EXTRA_CALL_PERSON = "android.callPerson";
+ field public static final String EXTRA_CALL_PERSON_COMPAT = "android.callPersonCompat";
+ field public static final String EXTRA_CALL_TYPE = "android.callType";
+ field public static final String EXTRA_CHANNEL_GROUP_ID = "android.intent.extra.CHANNEL_GROUP_ID";
+ field public static final String EXTRA_CHANNEL_ID = "android.intent.extra.CHANNEL_ID";
+ field public static final String EXTRA_CHRONOMETER_COUNT_DOWN = "android.chronometerCountDown";
+ field public static final String EXTRA_COLORIZED = "android.colorized";
+ field public static final String EXTRA_COMPACT_ACTIONS = "android.compactActions";
+ field public static final String EXTRA_COMPAT_TEMPLATE = "androidx.core.app.extra.COMPAT_TEMPLATE";
+ field public static final String EXTRA_CONVERSATION_TITLE = "android.conversationTitle";
+ field public static final String EXTRA_DECLINE_COLOR = "android.declineColor";
+ field public static final String EXTRA_DECLINE_INTENT = "android.declineIntent";
+ field public static final String EXTRA_HANG_UP_INTENT = "android.hangUpIntent";
+ field public static final String EXTRA_HIDDEN_CONVERSATION_TITLE = "android.hiddenConversationTitle";
+ field public static final String EXTRA_HISTORIC_MESSAGES = "android.messages.historic";
+ field public static final String EXTRA_INFO_TEXT = "android.infoText";
+ field public static final String EXTRA_IS_GROUP_CONVERSATION = "android.isGroupConversation";
+ field public static final String EXTRA_LARGE_ICON = "android.largeIcon";
+ field public static final String EXTRA_LARGE_ICON_BIG = "android.largeIcon.big";
+ field public static final String EXTRA_MEDIA_SESSION = "android.mediaSession";
+ field public static final String EXTRA_MESSAGES = "android.messages";
+ field public static final String EXTRA_MESSAGING_STYLE_USER = "android.messagingStyleUser";
+ field public static final String EXTRA_NOTIFICATION_ID = "android.intent.extra.NOTIFICATION_ID";
+ field public static final String EXTRA_NOTIFICATION_TAG = "android.intent.extra.NOTIFICATION_TAG";
+ field @Deprecated public static final String EXTRA_PEOPLE = "android.people";
+ field public static final String EXTRA_PEOPLE_LIST = "android.people.list";
+ field public static final String EXTRA_PICTURE = "android.picture";
+ field public static final String EXTRA_PICTURE_CONTENT_DESCRIPTION = "android.pictureContentDescription";
+ field public static final String EXTRA_PICTURE_ICON = "android.pictureIcon";
+ field public static final String EXTRA_PROGRESS = "android.progress";
+ field public static final String EXTRA_PROGRESS_INDETERMINATE = "android.progressIndeterminate";
+ field public static final String EXTRA_PROGRESS_MAX = "android.progressMax";
+ field public static final String EXTRA_REMOTE_INPUT_HISTORY = "android.remoteInputHistory";
+ field public static final String EXTRA_SELF_DISPLAY_NAME = "android.selfDisplayName";
+ field public static final String EXTRA_SHOW_BIG_PICTURE_WHEN_COLLAPSED = "android.showBigPictureWhenCollapsed";
+ field public static final String EXTRA_SHOW_CHRONOMETER = "android.showChronometer";
+ field public static final String EXTRA_SHOW_WHEN = "android.showWhen";
+ field public static final String EXTRA_SMALL_ICON = "android.icon";
+ field public static final String EXTRA_SUB_TEXT = "android.subText";
+ field public static final String EXTRA_SUMMARY_TEXT = "android.summaryText";
+ field public static final String EXTRA_TEMPLATE = "android.template";
+ field public static final String EXTRA_TEXT = "android.text";
+ field public static final String EXTRA_TEXT_LINES = "android.textLines";
+ field public static final String EXTRA_TITLE = "android.title";
+ field public static final String EXTRA_TITLE_BIG = "android.title.big";
+ field public static final String EXTRA_VERIFICATION_ICON = "android.verificationIcon";
+ field public static final String EXTRA_VERIFICATION_ICON_COMPAT = "android.verificationIconCompat";
+ field public static final String EXTRA_VERIFICATION_TEXT = "android.verificationText";
+ field public static final int FLAG_AUTO_CANCEL = 16; // 0x10
+ field public static final int FLAG_BUBBLE = 4096; // 0x1000
+ field public static final int FLAG_FOREGROUND_SERVICE = 64; // 0x40
+ field public static final int FLAG_GROUP_SUMMARY = 512; // 0x200
+ field @Deprecated public static final int FLAG_HIGH_PRIORITY = 128; // 0x80
+ field public static final int FLAG_INSISTENT = 4; // 0x4
+ field public static final int FLAG_LOCAL_ONLY = 256; // 0x100
+ field public static final int FLAG_NO_CLEAR = 32; // 0x20
+ field public static final int FLAG_ONGOING_EVENT = 2; // 0x2
+ field public static final int FLAG_ONLY_ALERT_ONCE = 8; // 0x8
+ field public static final int FLAG_SHOW_LIGHTS = 1; // 0x1
+ field public static final int FOREGROUND_SERVICE_DEFAULT = 0; // 0x0
+ field public static final int FOREGROUND_SERVICE_DEFERRED = 2; // 0x2
+ field public static final int FOREGROUND_SERVICE_IMMEDIATE = 1; // 0x1
+ field public static final int GROUP_ALERT_ALL = 0; // 0x0
+ field public static final int GROUP_ALERT_CHILDREN = 2; // 0x2
+ field public static final int GROUP_ALERT_SUMMARY = 1; // 0x1
+ field public static final String GROUP_KEY_SILENT = "silent";
+ field public static final String INTENT_CATEGORY_NOTIFICATION_PREFERENCES = "android.intent.category.NOTIFICATION_PREFERENCES";
+ field public static final int PRIORITY_DEFAULT = 0; // 0x0
+ field public static final int PRIORITY_HIGH = 1; // 0x1
+ field public static final int PRIORITY_LOW = -1; // 0xffffffff
+ field public static final int PRIORITY_MAX = 2; // 0x2
+ field public static final int PRIORITY_MIN = -2; // 0xfffffffe
+ field public static final int STREAM_DEFAULT = -1; // 0xffffffff
+ field public static final int VISIBILITY_PRIVATE = 0; // 0x0
+ field public static final int VISIBILITY_PUBLIC = 1; // 0x1
+ field public static final int VISIBILITY_SECRET = -1; // 0xffffffff
+ }
+
+ public static class NotificationCompat.Action {
+ ctor public NotificationCompat.Action(int, CharSequence?, android.app.PendingIntent?);
+ ctor public NotificationCompat.Action(androidx.core.graphics.drawable.IconCompat?, CharSequence?, android.app.PendingIntent?);
+ method public android.app.PendingIntent? getActionIntent();
+ method public boolean getAllowGeneratedReplies();
+ method public androidx.core.app.RemoteInput![]? getDataOnlyRemoteInputs();
+ method public android.os.Bundle getExtras();
+ method @Deprecated public int getIcon();
+ method public androidx.core.graphics.drawable.IconCompat? getIconCompat();
+ method public androidx.core.app.RemoteInput![]? getRemoteInputs();
+ method @androidx.core.app.NotificationCompat.Action.SemanticAction public int getSemanticAction();
+ method public boolean getShowsUserInterface();
+ method public CharSequence? getTitle();
+ method public boolean isAuthenticationRequired();
+ method public boolean isContextual();
+ field public static final int SEMANTIC_ACTION_ARCHIVE = 5; // 0x5
+ field public static final int SEMANTIC_ACTION_CALL = 10; // 0xa
+ field public static final int SEMANTIC_ACTION_DELETE = 4; // 0x4
+ field public static final int SEMANTIC_ACTION_MARK_AS_READ = 2; // 0x2
+ field public static final int SEMANTIC_ACTION_MARK_AS_UNREAD = 3; // 0x3
+ field public static final int SEMANTIC_ACTION_MUTE = 6; // 0x6
+ field public static final int SEMANTIC_ACTION_NONE = 0; // 0x0
+ field public static final int SEMANTIC_ACTION_REPLY = 1; // 0x1
+ field public static final int SEMANTIC_ACTION_THUMBS_DOWN = 9; // 0x9
+ field public static final int SEMANTIC_ACTION_THUMBS_UP = 8; // 0x8
+ field public static final int SEMANTIC_ACTION_UNMUTE = 7; // 0x7
+ field public android.app.PendingIntent? actionIntent;
+ field @Deprecated public int icon;
+ field public CharSequence! title;
+ }
+
+ public static final class NotificationCompat.Action.Builder {
+ ctor public NotificationCompat.Action.Builder(androidx.core.graphics.drawable.IconCompat?, CharSequence?, android.app.PendingIntent?);
+ ctor public NotificationCompat.Action.Builder(int, CharSequence?, android.app.PendingIntent?);
+ ctor public NotificationCompat.Action.Builder(androidx.core.app.NotificationCompat.Action);
+ method public androidx.core.app.NotificationCompat.Action.Builder addExtras(android.os.Bundle?);
+ method public androidx.core.app.NotificationCompat.Action.Builder addRemoteInput(androidx.core.app.RemoteInput?);
+ method public androidx.core.app.NotificationCompat.Action build();
+ method public androidx.core.app.NotificationCompat.Action.Builder extend(androidx.core.app.NotificationCompat.Action.Extender);
+ method public android.os.Bundle getExtras();
+ method public androidx.core.app.NotificationCompat.Action.Builder setAllowGeneratedReplies(boolean);
+ method public androidx.core.app.NotificationCompat.Action.Builder setAuthenticationRequired(boolean);
+ method public androidx.core.app.NotificationCompat.Action.Builder setContextual(boolean);
+ method public androidx.core.app.NotificationCompat.Action.Builder setSemanticAction(@androidx.core.app.NotificationCompat.Action.SemanticAction int);
+ method public androidx.core.app.NotificationCompat.Action.Builder setShowsUserInterface(boolean);
+ }
+
+ public static interface NotificationCompat.Action.Extender {
+ method public androidx.core.app.NotificationCompat.Action.Builder extend(androidx.core.app.NotificationCompat.Action.Builder);
+ }
+
+ @IntDef({androidx.core.app.NotificationCompat.Action.SEMANTIC_ACTION_NONE, androidx.core.app.NotificationCompat.Action.SEMANTIC_ACTION_REPLY, androidx.core.app.NotificationCompat.Action.SEMANTIC_ACTION_MARK_AS_READ, androidx.core.app.NotificationCompat.Action.SEMANTIC_ACTION_MARK_AS_UNREAD, androidx.core.app.NotificationCompat.Action.SEMANTIC_ACTION_DELETE, androidx.core.app.NotificationCompat.Action.SEMANTIC_ACTION_ARCHIVE, androidx.core.app.NotificationCompat.Action.SEMANTIC_ACTION_MUTE, androidx.core.app.NotificationCompat.Action.SEMANTIC_ACTION_UNMUTE, androidx.core.app.NotificationCompat.Action.SEMANTIC_ACTION_THUMBS_UP, androidx.core.app.NotificationCompat.Action.SEMANTIC_ACTION_THUMBS_DOWN, androidx.core.app.NotificationCompat.Action.SEMANTIC_ACTION_CALL}) @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.SOURCE) public static @interface NotificationCompat.Action.SemanticAction {
+ }
+
+ public static final class NotificationCompat.Action.WearableExtender implements androidx.core.app.NotificationCompat.Action.Extender {
+ ctor public NotificationCompat.Action.WearableExtender();
+ ctor public NotificationCompat.Action.WearableExtender(androidx.core.app.NotificationCompat.Action);
+ method public androidx.core.app.NotificationCompat.Action.WearableExtender clone();
+ method public androidx.core.app.NotificationCompat.Action.Builder extend(androidx.core.app.NotificationCompat.Action.Builder);
+ method @Deprecated public CharSequence? getCancelLabel();
+ method @Deprecated public CharSequence? getConfirmLabel();
+ method public boolean getHintDisplayActionInline();
+ method public boolean getHintLaunchesActivity();
+ method @Deprecated public CharSequence? getInProgressLabel();
+ method public boolean isAvailableOffline();
+ method public androidx.core.app.NotificationCompat.Action.WearableExtender setAvailableOffline(boolean);
+ method @Deprecated public androidx.core.app.NotificationCompat.Action.WearableExtender setCancelLabel(CharSequence?);
+ method @Deprecated public androidx.core.app.NotificationCompat.Action.WearableExtender setConfirmLabel(CharSequence?);
+ method public androidx.core.app.NotificationCompat.Action.WearableExtender setHintDisplayActionInline(boolean);
+ method public androidx.core.app.NotificationCompat.Action.WearableExtender setHintLaunchesActivity(boolean);
+ method @Deprecated public androidx.core.app.NotificationCompat.Action.WearableExtender setInProgressLabel(CharSequence?);
+ }
+
+ public static class NotificationCompat.BigPictureStyle extends androidx.core.app.NotificationCompat.Style {
+ ctor public NotificationCompat.BigPictureStyle();
+ ctor public NotificationCompat.BigPictureStyle(androidx.core.app.NotificationCompat.Builder?);
+ method public androidx.core.app.NotificationCompat.BigPictureStyle bigLargeIcon(android.graphics.Bitmap?);
+ method @RequiresApi(23) public androidx.core.app.NotificationCompat.BigPictureStyle bigLargeIcon(android.graphics.drawable.Icon?);
+ method public androidx.core.app.NotificationCompat.BigPictureStyle bigPicture(android.graphics.Bitmap?);
+ method @RequiresApi(31) public androidx.core.app.NotificationCompat.BigPictureStyle bigPicture(android.graphics.drawable.Icon?);
+ method public androidx.core.app.NotificationCompat.BigPictureStyle setBigContentTitle(CharSequence?);
+ method @RequiresApi(31) public androidx.core.app.NotificationCompat.BigPictureStyle setContentDescription(CharSequence?);
+ method public androidx.core.app.NotificationCompat.BigPictureStyle setSummaryText(CharSequence?);
+ method @RequiresApi(31) public androidx.core.app.NotificationCompat.BigPictureStyle showBigPictureWhenCollapsed(boolean);
+ }
+
+ public static class NotificationCompat.BigTextStyle extends androidx.core.app.NotificationCompat.Style {
+ ctor public NotificationCompat.BigTextStyle();
+ ctor public NotificationCompat.BigTextStyle(androidx.core.app.NotificationCompat.Builder?);
+ method public androidx.core.app.NotificationCompat.BigTextStyle bigText(CharSequence?);
+ method public androidx.core.app.NotificationCompat.BigTextStyle setBigContentTitle(CharSequence?);
+ method public androidx.core.app.NotificationCompat.BigTextStyle setSummaryText(CharSequence?);
+ }
+
+ public static final class NotificationCompat.BubbleMetadata {
+ method public static androidx.core.app.NotificationCompat.BubbleMetadata? fromPlatform(android.app.Notification.BubbleMetadata?);
+ method public boolean getAutoExpandBubble();
+ method public android.app.PendingIntent? getDeleteIntent();
+ method @Dimension(unit=androidx.annotation.Dimension.DP) public int getDesiredHeight();
+ method @DimenRes public int getDesiredHeightResId();
+ method public androidx.core.graphics.drawable.IconCompat? getIcon();
+ method public android.app.PendingIntent? getIntent();
+ method public String? getShortcutId();
+ method public boolean isNotificationSuppressed();
+ method public static android.app.Notification.BubbleMetadata? toPlatform(androidx.core.app.NotificationCompat.BubbleMetadata?);
+ }
+
+ public static final class NotificationCompat.BubbleMetadata.Builder {
+ ctor @Deprecated public NotificationCompat.BubbleMetadata.Builder();
+ ctor @RequiresApi(30) public NotificationCompat.BubbleMetadata.Builder(String);
+ ctor public NotificationCompat.BubbleMetadata.Builder(android.app.PendingIntent, androidx.core.graphics.drawable.IconCompat);
+ method public androidx.core.app.NotificationCompat.BubbleMetadata build();
+ method public androidx.core.app.NotificationCompat.BubbleMetadata.Builder setAutoExpandBubble(boolean);
+ method public androidx.core.app.NotificationCompat.BubbleMetadata.Builder setDeleteIntent(android.app.PendingIntent?);
+ method public androidx.core.app.NotificationCompat.BubbleMetadata.Builder setDesiredHeight(@Dimension(unit=androidx.annotation.Dimension.DP) int);
+ method public androidx.core.app.NotificationCompat.BubbleMetadata.Builder setDesiredHeightResId(@DimenRes int);
+ method public androidx.core.app.NotificationCompat.BubbleMetadata.Builder setIcon(androidx.core.graphics.drawable.IconCompat);
+ method public androidx.core.app.NotificationCompat.BubbleMetadata.Builder setIntent(android.app.PendingIntent);
+ method public androidx.core.app.NotificationCompat.BubbleMetadata.Builder setSuppressNotification(boolean);
+ }
+
+ public static class NotificationCompat.Builder {
+ ctor @RequiresApi(19) public NotificationCompat.Builder(android.content.Context, android.app.Notification);
+ ctor public NotificationCompat.Builder(android.content.Context, String);
+ ctor @Deprecated public NotificationCompat.Builder(android.content.Context);
+ method public androidx.core.app.NotificationCompat.Builder addAction(int, CharSequence?, android.app.PendingIntent?);
+ method public androidx.core.app.NotificationCompat.Builder addAction(androidx.core.app.NotificationCompat.Action?);
+ method public androidx.core.app.NotificationCompat.Builder addExtras(android.os.Bundle?);
+ method @RequiresApi(21) public androidx.core.app.NotificationCompat.Builder addInvisibleAction(int, CharSequence?, android.app.PendingIntent?);
+ method @RequiresApi(21) public androidx.core.app.NotificationCompat.Builder addInvisibleAction(androidx.core.app.NotificationCompat.Action?);
+ method @Deprecated public androidx.core.app.NotificationCompat.Builder addPerson(String?);
+ method public androidx.core.app.NotificationCompat.Builder addPerson(androidx.core.app.Person?);
+ method public android.app.Notification build();
+ method public androidx.core.app.NotificationCompat.Builder clearActions();
+ method public androidx.core.app.NotificationCompat.Builder clearInvisibleActions();
+ method public androidx.core.app.NotificationCompat.Builder clearPeople();
+ method public android.widget.RemoteViews? createBigContentView();
+ method public android.widget.RemoteViews? createContentView();
+ method public android.widget.RemoteViews? createHeadsUpContentView();
+ method public androidx.core.app.NotificationCompat.Builder extend(androidx.core.app.NotificationCompat.Extender);
+ method public android.os.Bundle getExtras();
+ method @Deprecated public android.app.Notification getNotification();
+ method protected static CharSequence? limitCharSequenceLength(CharSequence?);
+ method public androidx.core.app.NotificationCompat.Builder setAllowSystemGeneratedContextualActions(boolean);
+ method public androidx.core.app.NotificationCompat.Builder setAutoCancel(boolean);
+ method public androidx.core.app.NotificationCompat.Builder setBadgeIconType(int);
+ method public androidx.core.app.NotificationCompat.Builder setBubbleMetadata(androidx.core.app.NotificationCompat.BubbleMetadata?);
+ method public androidx.core.app.NotificationCompat.Builder setCategory(String?);
+ method public androidx.core.app.NotificationCompat.Builder setChannelId(String);
+ method @RequiresApi(24) public androidx.core.app.NotificationCompat.Builder setChronometerCountDown(boolean);
+ method public androidx.core.app.NotificationCompat.Builder setColor(@ColorInt int);
+ method public androidx.core.app.NotificationCompat.Builder setColorized(boolean);
+ method public androidx.core.app.NotificationCompat.Builder setContent(android.widget.RemoteViews?);
+ method public androidx.core.app.NotificationCompat.Builder setContentInfo(CharSequence?);
+ method public androidx.core.app.NotificationCompat.Builder setContentIntent(android.app.PendingIntent?);
+ method public androidx.core.app.NotificationCompat.Builder setContentText(CharSequence?);
+ method public androidx.core.app.NotificationCompat.Builder setContentTitle(CharSequence?);
+ method public androidx.core.app.NotificationCompat.Builder setCustomBigContentView(android.widget.RemoteViews?);
+ method public androidx.core.app.NotificationCompat.Builder setCustomContentView(android.widget.RemoteViews?);
+ method public androidx.core.app.NotificationCompat.Builder setCustomHeadsUpContentView(android.widget.RemoteViews?);
+ method public androidx.core.app.NotificationCompat.Builder setDefaults(int);
+ method public androidx.core.app.NotificationCompat.Builder setDeleteIntent(android.app.PendingIntent?);
+ method public androidx.core.app.NotificationCompat.Builder setExtras(android.os.Bundle?);
+ method public androidx.core.app.NotificationCompat.Builder setForegroundServiceBehavior(int);
+ method public androidx.core.app.NotificationCompat.Builder setFullScreenIntent(android.app.PendingIntent?, boolean);
+ method public androidx.core.app.NotificationCompat.Builder setGroup(String?);
+ method public androidx.core.app.NotificationCompat.Builder setGroupAlertBehavior(int);
+ method public androidx.core.app.NotificationCompat.Builder setGroupSummary(boolean);
+ method public androidx.core.app.NotificationCompat.Builder setLargeIcon(android.graphics.Bitmap?);
+ method public androidx.core.app.NotificationCompat.Builder setLights(@ColorInt int, int, int);
+ method public androidx.core.app.NotificationCompat.Builder setLocalOnly(boolean);
+ method public androidx.core.app.NotificationCompat.Builder setLocusId(androidx.core.content.LocusIdCompat?);
+ method @Deprecated public androidx.core.app.NotificationCompat.Builder setNotificationSilent();
+ method public androidx.core.app.NotificationCompat.Builder setNumber(int);
+ method public androidx.core.app.NotificationCompat.Builder setOngoing(boolean);
+ method public androidx.core.app.NotificationCompat.Builder setOnlyAlertOnce(boolean);
+ method public androidx.core.app.NotificationCompat.Builder setPriority(int);
+ method public androidx.core.app.NotificationCompat.Builder setProgress(int, int, boolean);
+ method public androidx.core.app.NotificationCompat.Builder setPublicVersion(android.app.Notification?);
+ method public androidx.core.app.NotificationCompat.Builder setRemoteInputHistory(CharSequence![]?);
+ method public androidx.core.app.NotificationCompat.Builder setSettingsText(CharSequence?);
+ method public androidx.core.app.NotificationCompat.Builder setShortcutId(String?);
+ method public androidx.core.app.NotificationCompat.Builder setShortcutInfo(androidx.core.content.pm.ShortcutInfoCompat?);
+ method public androidx.core.app.NotificationCompat.Builder setShowWhen(boolean);
+ method public androidx.core.app.NotificationCompat.Builder setSilent(boolean);
+ method @RequiresApi(23) public androidx.core.app.NotificationCompat.Builder setSmallIcon(androidx.core.graphics.drawable.IconCompat);
+ method public androidx.core.app.NotificationCompat.Builder setSmallIcon(int);
+ method public androidx.core.app.NotificationCompat.Builder setSmallIcon(int, int);
+ method public androidx.core.app.NotificationCompat.Builder setSortKey(String?);
+ method public androidx.core.app.NotificationCompat.Builder setSound(android.net.Uri?);
+ method public androidx.core.app.NotificationCompat.Builder setSound(android.net.Uri?, int);
+ method public androidx.core.app.NotificationCompat.Builder setStyle(androidx.core.app.NotificationCompat.Style?);
+ method public androidx.core.app.NotificationCompat.Builder setSubText(CharSequence?);
+ method public androidx.core.app.NotificationCompat.Builder setTicker(CharSequence?);
+ method @Deprecated public androidx.core.app.NotificationCompat.Builder setTicker(CharSequence?, android.widget.RemoteViews?);
+ method public androidx.core.app.NotificationCompat.Builder setTimeoutAfter(long);
+ method public androidx.core.app.NotificationCompat.Builder setUsesChronometer(boolean);
+ method public androidx.core.app.NotificationCompat.Builder setVibrate(long[]?);
+ method public androidx.core.app.NotificationCompat.Builder setVisibility(int);
+ method public androidx.core.app.NotificationCompat.Builder setWhen(long);
+ field @Deprecated public java.util.ArrayList<java.lang.String!>! mPeople;
+ }
+
+ public static class NotificationCompat.CallStyle extends androidx.core.app.NotificationCompat.Style {
+ ctor public NotificationCompat.CallStyle();
+ ctor public NotificationCompat.CallStyle(androidx.core.app.NotificationCompat.Builder?);
+ method public static androidx.core.app.NotificationCompat.CallStyle forIncomingCall(androidx.core.app.Person, android.app.PendingIntent, android.app.PendingIntent);
+ method public static androidx.core.app.NotificationCompat.CallStyle forOngoingCall(androidx.core.app.Person, android.app.PendingIntent);
+ method public static androidx.core.app.NotificationCompat.CallStyle forScreeningCall(androidx.core.app.Person, android.app.PendingIntent, android.app.PendingIntent);
+ method public androidx.core.app.NotificationCompat.CallStyle setAnswerButtonColorHint(@ColorInt int);
+ method public androidx.core.app.NotificationCompat.CallStyle setDeclineButtonColorHint(@ColorInt int);
+ method public androidx.core.app.NotificationCompat.CallStyle setIsVideo(boolean);
+ method @RequiresApi(23) public androidx.core.app.NotificationCompat.CallStyle setVerificationIcon(android.graphics.drawable.Icon?);
+ method public androidx.core.app.NotificationCompat.CallStyle setVerificationIcon(android.graphics.Bitmap?);
+ method public androidx.core.app.NotificationCompat.CallStyle setVerificationText(CharSequence?);
+ field public static final int CALL_TYPE_INCOMING = 1; // 0x1
+ field public static final int CALL_TYPE_ONGOING = 2; // 0x2
+ field public static final int CALL_TYPE_SCREENING = 3; // 0x3
+ field public static final int CALL_TYPE_UNKNOWN = 0; // 0x0
+ }
+
+ public static final class NotificationCompat.CarExtender implements androidx.core.app.NotificationCompat.Extender {
+ ctor public NotificationCompat.CarExtender();
+ ctor public NotificationCompat.CarExtender(android.app.Notification);
+ method public androidx.core.app.NotificationCompat.Builder extend(androidx.core.app.NotificationCompat.Builder);
+ method @ColorInt public int getColor();
+ method public android.graphics.Bitmap? getLargeIcon();
+ method @Deprecated public androidx.core.app.NotificationCompat.CarExtender.UnreadConversation? getUnreadConversation();
+ method public androidx.core.app.NotificationCompat.CarExtender setColor(@ColorInt int);
+ method public androidx.core.app.NotificationCompat.CarExtender setLargeIcon(android.graphics.Bitmap?);
+ method @Deprecated public androidx.core.app.NotificationCompat.CarExtender setUnreadConversation(androidx.core.app.NotificationCompat.CarExtender.UnreadConversation?);
+ }
+
+ @Deprecated public static class NotificationCompat.CarExtender.UnreadConversation {
+ method @Deprecated public long getLatestTimestamp();
+ method @Deprecated public String![]? getMessages();
+ method @Deprecated public String? getParticipant();
+ method @Deprecated public String![]? getParticipants();
+ method @Deprecated public android.app.PendingIntent? getReadPendingIntent();
+ method @Deprecated public androidx.core.app.RemoteInput? getRemoteInput();
+ method @Deprecated public android.app.PendingIntent? getReplyPendingIntent();
+ }
+
+ @Deprecated public static class NotificationCompat.CarExtender.UnreadConversation.Builder {
+ ctor @Deprecated public NotificationCompat.CarExtender.UnreadConversation.Builder(String);
+ method @Deprecated public androidx.core.app.NotificationCompat.CarExtender.UnreadConversation.Builder addMessage(String?);
+ method @Deprecated public androidx.core.app.NotificationCompat.CarExtender.UnreadConversation build();
+ method @Deprecated public androidx.core.app.NotificationCompat.CarExtender.UnreadConversation.Builder setLatestTimestamp(long);
+ method @Deprecated public androidx.core.app.NotificationCompat.CarExtender.UnreadConversation.Builder setReadPendingIntent(android.app.PendingIntent?);
+ method @Deprecated public androidx.core.app.NotificationCompat.CarExtender.UnreadConversation.Builder setReplyAction(android.app.PendingIntent?, androidx.core.app.RemoteInput?);
+ }
+
+ public static class NotificationCompat.DecoratedCustomViewStyle extends androidx.core.app.NotificationCompat.Style {
+ ctor public NotificationCompat.DecoratedCustomViewStyle();
+ }
+
+ public static interface NotificationCompat.Extender {
+ method public androidx.core.app.NotificationCompat.Builder extend(androidx.core.app.NotificationCompat.Builder);
+ }
+
+ public static class NotificationCompat.InboxStyle extends androidx.core.app.NotificationCompat.Style {
+ ctor public NotificationCompat.InboxStyle();
+ ctor public NotificationCompat.InboxStyle(androidx.core.app.NotificationCompat.Builder?);
+ method public androidx.core.app.NotificationCompat.InboxStyle addLine(CharSequence?);
+ method public androidx.core.app.NotificationCompat.InboxStyle setBigContentTitle(CharSequence?);
+ method public androidx.core.app.NotificationCompat.InboxStyle setSummaryText(CharSequence?);
+ }
+
+ public static class NotificationCompat.MessagingStyle extends androidx.core.app.NotificationCompat.Style {
+ ctor @Deprecated public NotificationCompat.MessagingStyle(CharSequence);
+ ctor public NotificationCompat.MessagingStyle(androidx.core.app.Person);
+ method public void addCompatExtras(android.os.Bundle);
+ method public androidx.core.app.NotificationCompat.MessagingStyle addHistoricMessage(androidx.core.app.NotificationCompat.MessagingStyle.Message?);
+ method @Deprecated public androidx.core.app.NotificationCompat.MessagingStyle addMessage(CharSequence?, long, CharSequence?);
+ method public androidx.core.app.NotificationCompat.MessagingStyle addMessage(CharSequence?, long, androidx.core.app.Person?);
+ method public androidx.core.app.NotificationCompat.MessagingStyle addMessage(androidx.core.app.NotificationCompat.MessagingStyle.Message?);
+ method public static androidx.core.app.NotificationCompat.MessagingStyle? extractMessagingStyleFromNotification(android.app.Notification);
+ method public CharSequence? getConversationTitle();
+ method public java.util.List<androidx.core.app.NotificationCompat.MessagingStyle.Message!> getHistoricMessages();
+ method public java.util.List<androidx.core.app.NotificationCompat.MessagingStyle.Message!> getMessages();
+ method public androidx.core.app.Person getUser();
+ method @Deprecated public CharSequence? getUserDisplayName();
+ method public boolean isGroupConversation();
+ method public androidx.core.app.NotificationCompat.MessagingStyle setConversationTitle(CharSequence?);
+ method public androidx.core.app.NotificationCompat.MessagingStyle setGroupConversation(boolean);
+ field public static final int MAXIMUM_RETAINED_MESSAGES = 25; // 0x19
+ }
+
+ public static final class NotificationCompat.MessagingStyle.Message {
+ ctor public NotificationCompat.MessagingStyle.Message(CharSequence?, long, androidx.core.app.Person?);
+ ctor @Deprecated public NotificationCompat.MessagingStyle.Message(CharSequence?, long, CharSequence?);
+ method public String? getDataMimeType();
+ method public android.net.Uri? getDataUri();
+ method public android.os.Bundle getExtras();
+ method public androidx.core.app.Person? getPerson();
+ method @Deprecated public CharSequence? getSender();
+ method public CharSequence? getText();
+ method public long getTimestamp();
+ method public androidx.core.app.NotificationCompat.MessagingStyle.Message setData(String?, android.net.Uri?);
+ }
+
+ public abstract static class NotificationCompat.Style {
+ ctor public NotificationCompat.Style();
+ method public android.app.Notification? build();
+ method public void setBuilder(androidx.core.app.NotificationCompat.Builder?);
+ }
+
+ public static final class NotificationCompat.WearableExtender implements androidx.core.app.NotificationCompat.Extender {
+ ctor public NotificationCompat.WearableExtender();
+ ctor public NotificationCompat.WearableExtender(android.app.Notification);
+ method public androidx.core.app.NotificationCompat.WearableExtender addAction(androidx.core.app.NotificationCompat.Action);
+ method public androidx.core.app.NotificationCompat.WearableExtender addActions(java.util.List<androidx.core.app.NotificationCompat.Action!>);
+ method @Deprecated public androidx.core.app.NotificationCompat.WearableExtender addPage(android.app.Notification);
+ method @Deprecated public androidx.core.app.NotificationCompat.WearableExtender addPages(java.util.List<android.app.Notification!>);
+ method public androidx.core.app.NotificationCompat.WearableExtender clearActions();
+ method @Deprecated public androidx.core.app.NotificationCompat.WearableExtender clearPages();
+ method public androidx.core.app.NotificationCompat.WearableExtender clone();
+ method public androidx.core.app.NotificationCompat.Builder extend(androidx.core.app.NotificationCompat.Builder);
+ method public java.util.List<androidx.core.app.NotificationCompat.Action!> getActions();
+ method @Deprecated public android.graphics.Bitmap? getBackground();
+ method public String? getBridgeTag();
+ method public int getContentAction();
+ method @Deprecated public int getContentIcon();
+ method @Deprecated public int getContentIconGravity();
+ method public boolean getContentIntentAvailableOffline();
+ method @Deprecated public int getCustomContentHeight();
+ method @Deprecated public int getCustomSizePreset();
+ method public String? getDismissalId();
+ method @Deprecated public android.app.PendingIntent? getDisplayIntent();
+ method @Deprecated public int getGravity();
+ method @Deprecated public boolean getHintAmbientBigPicture();
+ method @Deprecated public boolean getHintAvoidBackgroundClipping();
+ method public boolean getHintContentIntentLaunchesActivity();
+ method @Deprecated public boolean getHintHideIcon();
+ method @Deprecated public int getHintScreenTimeout();
+ method @Deprecated public boolean getHintShowBackgroundOnly();
+ method @Deprecated public java.util.List<android.app.Notification!> getPages();
+ method public boolean getStartScrollBottom();
+ method @Deprecated public androidx.core.app.NotificationCompat.WearableExtender setBackground(android.graphics.Bitmap?);
+ method public androidx.core.app.NotificationCompat.WearableExtender setBridgeTag(String?);
+ method public androidx.core.app.NotificationCompat.WearableExtender setContentAction(int);
+ method @Deprecated public androidx.core.app.NotificationCompat.WearableExtender setContentIcon(int);
+ method @Deprecated public androidx.core.app.NotificationCompat.WearableExtender setContentIconGravity(int);
+ method public androidx.core.app.NotificationCompat.WearableExtender setContentIntentAvailableOffline(boolean);
+ method @Deprecated public androidx.core.app.NotificationCompat.WearableExtender setCustomContentHeight(int);
+ method @Deprecated public androidx.core.app.NotificationCompat.WearableExtender setCustomSizePreset(int);
+ method public androidx.core.app.NotificationCompat.WearableExtender setDismissalId(String?);
+ method @Deprecated public androidx.core.app.NotificationCompat.WearableExtender setDisplayIntent(android.app.PendingIntent?);
+ method @Deprecated public androidx.core.app.NotificationCompat.WearableExtender setGravity(int);
+ method @Deprecated public androidx.core.app.NotificationCompat.WearableExtender setHintAmbientBigPicture(boolean);
+ method @Deprecated public androidx.core.app.NotificationCompat.WearableExtender setHintAvoidBackgroundClipping(boolean);
+ method public androidx.core.app.NotificationCompat.WearableExtender setHintContentIntentLaunchesActivity(boolean);
+ method @Deprecated public androidx.core.app.NotificationCompat.WearableExtender setHintHideIcon(boolean);
+ method @Deprecated public androidx.core.app.NotificationCompat.WearableExtender setHintScreenTimeout(int);
+ method @Deprecated public androidx.core.app.NotificationCompat.WearableExtender setHintShowBackgroundOnly(boolean);
+ method public androidx.core.app.NotificationCompat.WearableExtender setStartScrollBottom(boolean);
+ field @Deprecated public static final int SCREEN_TIMEOUT_LONG = -1; // 0xffffffff
+ field @Deprecated public static final int SCREEN_TIMEOUT_SHORT = 0; // 0x0
+ field @Deprecated public static final int SIZE_DEFAULT = 0; // 0x0
+ field @Deprecated public static final int SIZE_FULL_SCREEN = 5; // 0x5
+ field @Deprecated public static final int SIZE_LARGE = 4; // 0x4
+ field @Deprecated public static final int SIZE_MEDIUM = 3; // 0x3
+ field @Deprecated public static final int SIZE_SMALL = 2; // 0x2
+ field @Deprecated public static final int SIZE_XSMALL = 1; // 0x1
+ field public static final int UNSET_ACTION_INDEX = -1; // 0xffffffff
+ }
+
+ public final class NotificationCompatExtras {
+ field public static final String EXTRA_ACTION_EXTRAS = "android.support.actionExtras";
+ field public static final String EXTRA_GROUP_KEY = "android.support.groupKey";
+ field public static final String EXTRA_GROUP_SUMMARY = "android.support.isGroupSummary";
+ field public static final String EXTRA_LOCAL_ONLY = "android.support.localOnly";
+ field public static final String EXTRA_REMOTE_INPUTS = "android.support.remoteInputs";
+ field public static final String EXTRA_SORT_KEY = "android.support.sortKey";
+ }
+
+ public abstract class NotificationCompatSideChannelService extends android.app.Service {
+ ctor public NotificationCompatSideChannelService();
+ method public abstract void cancel(String!, int, String!);
+ method public abstract void cancelAll(String!);
+ method public abstract void notify(String!, int, String!, android.app.Notification!);
+ method public android.os.IBinder! onBind(android.content.Intent!);
+ }
+
+ public final class NotificationManagerCompat {
+ method public boolean areNotificationsEnabled();
+ method public void cancel(int);
+ method public void cancel(String?, int);
+ method public void cancelAll();
+ method public void createNotificationChannel(android.app.NotificationChannel);
+ method public void createNotificationChannel(androidx.core.app.NotificationChannelCompat);
+ method public void createNotificationChannelGroup(android.app.NotificationChannelGroup);
+ method public void createNotificationChannelGroup(androidx.core.app.NotificationChannelGroupCompat);
+ method public void createNotificationChannelGroups(java.util.List<android.app.NotificationChannelGroup!>);
+ method public void createNotificationChannelGroupsCompat(java.util.List<androidx.core.app.NotificationChannelGroupCompat!>);
+ method public void createNotificationChannels(java.util.List<android.app.NotificationChannel!>);
+ method public void createNotificationChannelsCompat(java.util.List<androidx.core.app.NotificationChannelCompat!>);
+ method public void deleteNotificationChannel(String);
+ method public void deleteNotificationChannelGroup(String);
+ method public void deleteUnlistedNotificationChannels(java.util.Collection<java.lang.String!>);
+ method public static androidx.core.app.NotificationManagerCompat from(android.content.Context);
+ method public static java.util.Set<java.lang.String!> getEnabledListenerPackages(android.content.Context);
+ method public int getImportance();
+ method public android.app.NotificationChannel? getNotificationChannel(String);
+ method public android.app.NotificationChannel? getNotificationChannel(String, String);
+ method public androidx.core.app.NotificationChannelCompat? getNotificationChannelCompat(String);
+ method public androidx.core.app.NotificationChannelCompat? getNotificationChannelCompat(String, String);
+ method public android.app.NotificationChannelGroup? getNotificationChannelGroup(String);
+ method public androidx.core.app.NotificationChannelGroupCompat? getNotificationChannelGroupCompat(String);
+ method public java.util.List<android.app.NotificationChannelGroup!> getNotificationChannelGroups();
+ method public java.util.List<androidx.core.app.NotificationChannelGroupCompat!> getNotificationChannelGroupsCompat();
+ method public java.util.List<android.app.NotificationChannel!> getNotificationChannels();
+ method public java.util.List<androidx.core.app.NotificationChannelCompat!> getNotificationChannelsCompat();
+ method @RequiresPermission(android.Manifest.permission.POST_NOTIFICATIONS) public void notify(int, android.app.Notification);
+ method @RequiresPermission(android.Manifest.permission.POST_NOTIFICATIONS) public void notify(String?, int, android.app.Notification);
+ field public static final String ACTION_BIND_SIDE_CHANNEL = "android.support.BIND_NOTIFICATION_SIDE_CHANNEL";
+ field public static final String EXTRA_USE_SIDE_CHANNEL = "android.support.useSideChannel";
+ field public static final int IMPORTANCE_DEFAULT = 3; // 0x3
+ field public static final int IMPORTANCE_HIGH = 4; // 0x4
+ field public static final int IMPORTANCE_LOW = 2; // 0x2
+ field public static final int IMPORTANCE_MAX = 5; // 0x5
+ field public static final int IMPORTANCE_MIN = 1; // 0x1
+ field public static final int IMPORTANCE_NONE = 0; // 0x0
+ field public static final int IMPORTANCE_UNSPECIFIED = -1000; // 0xfffffc18
+ }
+
+ public interface OnMultiWindowModeChangedProvider {
+ method public void addOnMultiWindowModeChangedListener(androidx.core.util.Consumer<androidx.core.app.MultiWindowModeChangedInfo!>);
+ method public void removeOnMultiWindowModeChangedListener(androidx.core.util.Consumer<androidx.core.app.MultiWindowModeChangedInfo!>);
+ }
+
+ public interface OnNewIntentProvider {
+ method public void addOnNewIntentListener(androidx.core.util.Consumer<android.content.Intent!>);
+ method public void removeOnNewIntentListener(androidx.core.util.Consumer<android.content.Intent!>);
+ }
+
+ public interface OnPictureInPictureModeChangedProvider {
+ method public void addOnPictureInPictureModeChangedListener(androidx.core.util.Consumer<androidx.core.app.PictureInPictureModeChangedInfo!>);
+ method public void removeOnPictureInPictureModeChangedListener(androidx.core.util.Consumer<androidx.core.app.PictureInPictureModeChangedInfo!>);
+ }
+
+ public final class PendingIntentCompat {
+ method public static android.app.PendingIntent getActivities(android.content.Context, int, android.content.Intent![], int, android.os.Bundle, boolean);
+ method public static android.app.PendingIntent getActivities(android.content.Context, int, android.content.Intent![], int, boolean);
+ method public static android.app.PendingIntent getActivity(android.content.Context, int, android.content.Intent, int, boolean);
+ method public static android.app.PendingIntent getActivity(android.content.Context, int, android.content.Intent, int, android.os.Bundle, boolean);
+ method public static android.app.PendingIntent getBroadcast(android.content.Context, int, android.content.Intent, int, boolean);
+ method @RequiresApi(26) public static android.app.PendingIntent getForegroundService(android.content.Context, int, android.content.Intent, int, boolean);
+ method public static android.app.PendingIntent getService(android.content.Context, int, android.content.Intent, int, boolean);
+ }
+
+ public class Person {
+ method public static androidx.core.app.Person fromBundle(android.os.Bundle);
+ method public androidx.core.graphics.drawable.IconCompat? getIcon();
+ method public String? getKey();
+ method public CharSequence? getName();
+ method public String? getUri();
+ method public boolean isBot();
+ method public boolean isImportant();
+ method public androidx.core.app.Person.Builder toBuilder();
+ method public android.os.Bundle toBundle();
+ }
+
+ public static class Person.Builder {
+ ctor public Person.Builder();
+ method public androidx.core.app.Person build();
+ method public androidx.core.app.Person.Builder setBot(boolean);
+ method public androidx.core.app.Person.Builder setIcon(androidx.core.graphics.drawable.IconCompat?);
+ method public androidx.core.app.Person.Builder setImportant(boolean);
+ method public androidx.core.app.Person.Builder setKey(String?);
+ method public androidx.core.app.Person.Builder setName(CharSequence?);
+ method public androidx.core.app.Person.Builder setUri(String?);
+ }
+
+ public final class PictureInPictureModeChangedInfo {
+ ctor public PictureInPictureModeChangedInfo(boolean);
+ ctor @RequiresApi(26) public PictureInPictureModeChangedInfo(boolean, android.content.res.Configuration);
+ method @RequiresApi(26) public android.content.res.Configuration getNewConfig();
+ method public boolean isInPictureInPictureMode();
+ }
+
+ public final class RemoteActionCompat implements androidx.versionedparcelable.VersionedParcelable {
+ ctor public RemoteActionCompat(androidx.core.graphics.drawable.IconCompat, CharSequence, CharSequence, android.app.PendingIntent);
+ ctor public RemoteActionCompat(androidx.core.app.RemoteActionCompat);
+ method @RequiresApi(26) public static androidx.core.app.RemoteActionCompat createFromRemoteAction(android.app.RemoteAction);
+ method public android.app.PendingIntent getActionIntent();
+ method public CharSequence getContentDescription();
+ method public androidx.core.graphics.drawable.IconCompat getIcon();
+ method public CharSequence getTitle();
+ method public boolean isEnabled();
+ method public void setEnabled(boolean);
+ method public void setShouldShowIcon(boolean);
+ method public boolean shouldShowIcon();
+ method @RequiresApi(26) public android.app.RemoteAction toRemoteAction();
+ }
+
+ public final class RemoteInput {
+ method public static void addDataResultToIntent(androidx.core.app.RemoteInput, android.content.Intent, java.util.Map<java.lang.String!,android.net.Uri!>);
+ method public static void addResultsToIntent(androidx.core.app.RemoteInput![], android.content.Intent, android.os.Bundle);
+ method public boolean getAllowFreeFormInput();
+ method public java.util.Set<java.lang.String!>? getAllowedDataTypes();
+ method public CharSequence![]? getChoices();
+ method public static java.util.Map<java.lang.String!,android.net.Uri!>? getDataResultsFromIntent(android.content.Intent, String);
+ method public int getEditChoicesBeforeSending();
+ method public android.os.Bundle getExtras();
+ method public CharSequence? getLabel();
+ method public String getResultKey();
+ method public static android.os.Bundle? getResultsFromIntent(android.content.Intent);
+ method public static int getResultsSource(android.content.Intent);
+ method public boolean isDataOnly();
+ method public static void setResultsSource(android.content.Intent, int);
+ field public static final int EDIT_CHOICES_BEFORE_SENDING_AUTO = 0; // 0x0
+ field public static final int EDIT_CHOICES_BEFORE_SENDING_DISABLED = 1; // 0x1
+ field public static final int EDIT_CHOICES_BEFORE_SENDING_ENABLED = 2; // 0x2
+ field public static final String EXTRA_RESULTS_DATA = "android.remoteinput.resultsData";
+ field public static final String RESULTS_CLIP_LABEL = "android.remoteinput.results";
+ field public static final int SOURCE_CHOICE = 1; // 0x1
+ field public static final int SOURCE_FREE_FORM_INPUT = 0; // 0x0
+ }
+
+ public static final class RemoteInput.Builder {
+ ctor public RemoteInput.Builder(String);
+ method public androidx.core.app.RemoteInput.Builder addExtras(android.os.Bundle);
+ method public androidx.core.app.RemoteInput build();
+ method public android.os.Bundle getExtras();
+ method public androidx.core.app.RemoteInput.Builder setAllowDataType(String, boolean);
+ method public androidx.core.app.RemoteInput.Builder setAllowFreeFormInput(boolean);
+ method public androidx.core.app.RemoteInput.Builder setChoices(CharSequence![]?);
+ method public androidx.core.app.RemoteInput.Builder setEditChoicesBeforeSending(int);
+ method public androidx.core.app.RemoteInput.Builder setLabel(CharSequence?);
+ }
+
+ public final class ServiceCompat {
+ method public static void stopForeground(android.app.Service, int);
+ field public static final int START_STICKY = 1; // 0x1
+ field public static final int STOP_FOREGROUND_DETACH = 2; // 0x2
+ field public static final int STOP_FOREGROUND_REMOVE = 1; // 0x1
+ }
+
+ public final class ShareCompat {
+ method @Deprecated public static void configureMenuItem(android.view.MenuItem, androidx.core.app.ShareCompat.IntentBuilder);
+ method @Deprecated public static void configureMenuItem(android.view.Menu, @IdRes int, androidx.core.app.ShareCompat.IntentBuilder);
+ method public static android.content.ComponentName? getCallingActivity(android.app.Activity);
+ method public static String? getCallingPackage(android.app.Activity);
+ field public static final String EXTRA_CALLING_ACTIVITY = "androidx.core.app.EXTRA_CALLING_ACTIVITY";
+ field public static final String EXTRA_CALLING_ACTIVITY_INTEROP = "android.support.v4.app.EXTRA_CALLING_ACTIVITY";
+ field public static final String EXTRA_CALLING_PACKAGE = "androidx.core.app.EXTRA_CALLING_PACKAGE";
+ field public static final String EXTRA_CALLING_PACKAGE_INTEROP = "android.support.v4.app.EXTRA_CALLING_PACKAGE";
+ }
+
+ public static class ShareCompat.IntentBuilder {
+ ctor public ShareCompat.IntentBuilder(android.content.Context);
+ method public androidx.core.app.ShareCompat.IntentBuilder addEmailBcc(String);
+ method public androidx.core.app.ShareCompat.IntentBuilder addEmailBcc(String![]);
+ method public androidx.core.app.ShareCompat.IntentBuilder addEmailCc(String);
+ method public androidx.core.app.ShareCompat.IntentBuilder addEmailCc(String![]);
+ method public androidx.core.app.ShareCompat.IntentBuilder addEmailTo(String);
+ method public androidx.core.app.ShareCompat.IntentBuilder addEmailTo(String![]);
+ method public androidx.core.app.ShareCompat.IntentBuilder addStream(android.net.Uri);
+ method public android.content.Intent createChooserIntent();
+ method @Deprecated public static androidx.core.app.ShareCompat.IntentBuilder from(android.app.Activity);
+ method public android.content.Intent getIntent();
+ method public androidx.core.app.ShareCompat.IntentBuilder setChooserTitle(CharSequence?);
+ method public androidx.core.app.ShareCompat.IntentBuilder setChooserTitle(@StringRes int);
+ method public androidx.core.app.ShareCompat.IntentBuilder setEmailBcc(String![]?);
+ method public androidx.core.app.ShareCompat.IntentBuilder setEmailCc(String![]?);
+ method public androidx.core.app.ShareCompat.IntentBuilder setEmailTo(String![]?);
+ method public androidx.core.app.ShareCompat.IntentBuilder setHtmlText(String?);
+ method public androidx.core.app.ShareCompat.IntentBuilder setStream(android.net.Uri?);
+ method public androidx.core.app.ShareCompat.IntentBuilder setSubject(String?);
+ method public androidx.core.app.ShareCompat.IntentBuilder setText(CharSequence?);
+ method public androidx.core.app.ShareCompat.IntentBuilder setType(String?);
+ method public void startChooser();
+ }
+
+ public static class ShareCompat.IntentReader {
+ ctor public ShareCompat.IntentReader(android.app.Activity);
+ ctor public ShareCompat.IntentReader(android.content.Context, android.content.Intent);
+ method @Deprecated public static androidx.core.app.ShareCompat.IntentReader from(android.app.Activity);
+ method public android.content.ComponentName? getCallingActivity();
+ method public android.graphics.drawable.Drawable? getCallingActivityIcon();
+ method public android.graphics.drawable.Drawable? getCallingApplicationIcon();
+ method public CharSequence? getCallingApplicationLabel();
+ method public String? getCallingPackage();
+ method public String![]? getEmailBcc();
+ method public String![]? getEmailCc();
+ method public String![]? getEmailTo();
+ method public String? getHtmlText();
+ method public android.net.Uri? getStream();
+ method public android.net.Uri? getStream(int);
+ method public int getStreamCount();
+ method public String? getSubject();
+ method public CharSequence? getText();
+ method public String? getType();
+ method public boolean isMultipleShare();
+ method public boolean isShareIntent();
+ method public boolean isSingleShare();
+ }
+
+ public abstract class SharedElementCallback {
+ ctor public SharedElementCallback();
+ method public android.os.Parcelable! onCaptureSharedElementSnapshot(android.view.View!, android.graphics.Matrix!, android.graphics.RectF!);
+ method public android.view.View! onCreateSnapshotView(android.content.Context!, android.os.Parcelable!);
+ method public void onMapSharedElements(java.util.List<java.lang.String!>!, java.util.Map<java.lang.String!,android.view.View!>!);
+ method public void onRejectSharedElements(java.util.List<android.view.View!>!);
+ method public void onSharedElementEnd(java.util.List<java.lang.String!>!, java.util.List<android.view.View!>!, java.util.List<android.view.View!>!);
+ method public void onSharedElementStart(java.util.List<java.lang.String!>!, java.util.List<android.view.View!>!, java.util.List<android.view.View!>!);
+ method public void onSharedElementsArrived(java.util.List<java.lang.String!>!, java.util.List<android.view.View!>!, androidx.core.app.SharedElementCallback.OnSharedElementsReadyListener!);
+ }
+
+ public static interface SharedElementCallback.OnSharedElementsReadyListener {
+ method public void onSharedElementsReady();
+ }
+
+ public final class TaskStackBuilder implements java.lang.Iterable<android.content.Intent> {
+ method public androidx.core.app.TaskStackBuilder addNextIntent(android.content.Intent);
+ method public androidx.core.app.TaskStackBuilder addNextIntentWithParentStack(android.content.Intent);
+ method public androidx.core.app.TaskStackBuilder addParentStack(android.app.Activity);
+ method public androidx.core.app.TaskStackBuilder addParentStack(Class<?>);
+ method public androidx.core.app.TaskStackBuilder addParentStack(android.content.ComponentName);
+ method public static androidx.core.app.TaskStackBuilder create(android.content.Context);
+ method public android.content.Intent? editIntentAt(int);
+ method @Deprecated public static androidx.core.app.TaskStackBuilder! from(android.content.Context!);
+ method @Deprecated public android.content.Intent! getIntent(int);
+ method public int getIntentCount();
+ method public android.content.Intent![] getIntents();
+ method public android.app.PendingIntent? getPendingIntent(int, int);
+ method public android.app.PendingIntent? getPendingIntent(int, int, android.os.Bundle?);
+ method @Deprecated public java.util.Iterator<android.content.Intent!> iterator();
+ method public void startActivities();
+ method public void startActivities(android.os.Bundle?);
+ }
+
+ public static interface TaskStackBuilder.SupportParentable {
+ method public android.content.Intent? getSupportParentActivityIntent();
+ }
+
+}
+
+package androidx.core.content {
+
+ public final class ContentProviderCompat {
+ method public static android.content.Context requireContext(android.content.ContentProvider);
+ }
+
+ public final class ContentResolverCompat {
+ method public static android.database.Cursor? query(android.content.ContentResolver, android.net.Uri, String![]?, String?, String![]?, String?, androidx.core.os.CancellationSignal?);
+ }
+
+ public class ContextCompat {
+ ctor protected ContextCompat();
+ method public static int checkSelfPermission(android.content.Context, String);
+ method public static android.content.Context? createDeviceProtectedStorageContext(android.content.Context);
+ method public static String? getAttributionTag(android.content.Context);
+ method public static java.io.File getCodeCacheDir(android.content.Context);
+ method @ColorInt public static int getColor(android.content.Context, @ColorRes int);
+ method public static android.content.res.ColorStateList? getColorStateList(android.content.Context, @ColorRes int);
+ method public static java.io.File? getDataDir(android.content.Context);
+ method public static android.graphics.drawable.Drawable? getDrawable(android.content.Context, @DrawableRes int);
+ method public static java.io.File![] getExternalCacheDirs(android.content.Context);
+ method public static java.io.File![] getExternalFilesDirs(android.content.Context, String?);
+ method public static java.util.concurrent.Executor getMainExecutor(android.content.Context);
+ method public static java.io.File? getNoBackupFilesDir(android.content.Context);
+ method public static java.io.File![] getObbDirs(android.content.Context);
+ method public static <T> T? getSystemService(android.content.Context, Class<T!>);
+ method public static String? getSystemServiceName(android.content.Context, Class<?>);
+ method public static boolean isDeviceProtectedStorage(android.content.Context);
+ method public static android.content.Intent? registerReceiver(android.content.Context, android.content.BroadcastReceiver?, android.content.IntentFilter, int);
+ method public static android.content.Intent? registerReceiver(android.content.Context, android.content.BroadcastReceiver?, android.content.IntentFilter, String?, android.os.Handler?, int);
+ method public static boolean startActivities(android.content.Context, android.content.Intent![]);
+ method public static boolean startActivities(android.content.Context, android.content.Intent![], android.os.Bundle?);
+ method public static void startActivity(android.content.Context, android.content.Intent, android.os.Bundle?);
+ method public static void startForegroundService(android.content.Context, android.content.Intent);
+ field public static final int RECEIVER_EXPORTED = 2; // 0x2
+ field public static final int RECEIVER_NOT_EXPORTED = 4; // 0x4
+ field public static final int RECEIVER_VISIBLE_TO_INSTANT_APPS = 1; // 0x1
+ }
+
+ public class FileProvider extends android.content.ContentProvider {
+ ctor public FileProvider();
+ ctor protected FileProvider(@XmlRes int);
+ method public int delete(android.net.Uri, String?, String![]?);
+ method public String? getType(android.net.Uri);
+ method public static android.net.Uri! getUriForFile(android.content.Context, String, java.io.File);
+ method public static android.net.Uri getUriForFile(android.content.Context, String, java.io.File, String);
+ method public android.net.Uri! insert(android.net.Uri, android.content.ContentValues);
+ method public boolean onCreate();
+ method public android.database.Cursor query(android.net.Uri, String![]?, String?, String![]?, String?);
+ method public int update(android.net.Uri, android.content.ContentValues, String?, String![]?);
+ }
+
+ public final class IntentCompat {
+ method public static android.content.Intent createManageUnusedAppRestrictionsIntent(android.content.Context, String);
+ method public static android.os.Parcelable![]? getParcelableArrayExtra(android.content.Intent, String?, Class<? extends android.os.Parcelable>);
+ method public static <T> java.util.ArrayList<T!>? getParcelableArrayListExtra(android.content.Intent, String?, Class<? extends T>);
+ method public static <T> T? getParcelableExtra(android.content.Intent, String?, Class<T!>);
+ method public static android.content.Intent makeMainSelectorActivity(String, String);
+ field public static final String ACTION_CREATE_REMINDER = "android.intent.action.CREATE_REMINDER";
+ field public static final String CATEGORY_LEANBACK_LAUNCHER = "android.intent.category.LEANBACK_LAUNCHER";
+ field public static final String EXTRA_HTML_TEXT = "android.intent.extra.HTML_TEXT";
+ field public static final String EXTRA_START_PLAYBACK = "android.intent.extra.START_PLAYBACK";
+ field public static final String EXTRA_TIME = "android.intent.extra.TIME";
+ }
+
+ public class IntentSanitizer {
+ method public android.content.Intent sanitize(android.content.Intent, androidx.core.util.Consumer<java.lang.String!>);
+ method public android.content.Intent sanitizeByFiltering(android.content.Intent);
+ method public android.content.Intent sanitizeByThrowing(android.content.Intent);
+ }
+
+ public static final class IntentSanitizer.Builder {
+ ctor public IntentSanitizer.Builder();
+ method public androidx.core.content.IntentSanitizer.Builder allowAction(String);
+ method public androidx.core.content.IntentSanitizer.Builder allowAction(androidx.core.util.Predicate<java.lang.String!>);
+ method public androidx.core.content.IntentSanitizer.Builder allowAnyComponent();
+ method public androidx.core.content.IntentSanitizer.Builder allowCategory(String);
+ method public androidx.core.content.IntentSanitizer.Builder allowCategory(androidx.core.util.Predicate<java.lang.String!>);
+ method public androidx.core.content.IntentSanitizer.Builder allowClipData(androidx.core.util.Predicate<android.content.ClipData!>);
+ method public androidx.core.content.IntentSanitizer.Builder allowClipDataText();
+ method public androidx.core.content.IntentSanitizer.Builder allowClipDataUri(androidx.core.util.Predicate<android.net.Uri!>);
+ method public androidx.core.content.IntentSanitizer.Builder allowClipDataUriWithAuthority(String);
+ method public androidx.core.content.IntentSanitizer.Builder allowComponent(android.content.ComponentName);
+ method public androidx.core.content.IntentSanitizer.Builder allowComponent(androidx.core.util.Predicate<android.content.ComponentName!>);
+ method public androidx.core.content.IntentSanitizer.Builder allowComponentWithPackage(String);
+ method public androidx.core.content.IntentSanitizer.Builder allowData(androidx.core.util.Predicate<android.net.Uri!>);
+ method public androidx.core.content.IntentSanitizer.Builder allowDataWithAuthority(String);
+ method public androidx.core.content.IntentSanitizer.Builder allowExtra(String, Class<?>);
+ method public <T> androidx.core.content.IntentSanitizer.Builder allowExtra(String, Class<T!>, androidx.core.util.Predicate<T!>);
+ method public androidx.core.content.IntentSanitizer.Builder allowExtra(String, androidx.core.util.Predicate<java.lang.Object!>);
+ method public androidx.core.content.IntentSanitizer.Builder allowExtraOutput(String);
+ method public androidx.core.content.IntentSanitizer.Builder allowExtraOutput(androidx.core.util.Predicate<android.net.Uri!>);
+ method public androidx.core.content.IntentSanitizer.Builder allowExtraStream(androidx.core.util.Predicate<android.net.Uri!>);
+ method public androidx.core.content.IntentSanitizer.Builder allowExtraStreamUriWithAuthority(String);
+ method public androidx.core.content.IntentSanitizer.Builder allowFlags(int);
+ method public androidx.core.content.IntentSanitizer.Builder allowHistoryStackFlags();
+ method public androidx.core.content.IntentSanitizer.Builder allowIdentifier();
+ method public androidx.core.content.IntentSanitizer.Builder allowPackage(String);
+ method public androidx.core.content.IntentSanitizer.Builder allowPackage(androidx.core.util.Predicate<java.lang.String!>);
+ method public androidx.core.content.IntentSanitizer.Builder allowReceiverFlags();
+ method public androidx.core.content.IntentSanitizer.Builder allowSelector();
+ method public androidx.core.content.IntentSanitizer.Builder allowSourceBounds();
+ method public androidx.core.content.IntentSanitizer.Builder allowType(String);
+ method public androidx.core.content.IntentSanitizer.Builder allowType(androidx.core.util.Predicate<java.lang.String!>);
+ method public androidx.core.content.IntentSanitizer build();
+ }
+
+ public final class LocusIdCompat {
+ ctor public LocusIdCompat(String);
+ method public String getId();
+ method @RequiresApi(29) public android.content.LocusId toLocusId();
+ method @RequiresApi(29) public static androidx.core.content.LocusIdCompat toLocusIdCompat(android.content.LocusId);
+ }
+
+ public final class MimeTypeFilter {
+ method public static boolean matches(String?, String);
+ method public static String? matches(String?, String![]);
+ method public static String? matches(String![]?, String);
+ method public static String![] matchesMany(String![]?, String);
+ }
+
+ public interface OnConfigurationChangedProvider {
+ method public void addOnConfigurationChangedListener(androidx.core.util.Consumer<android.content.res.Configuration!>);
+ method public void removeOnConfigurationChangedListener(androidx.core.util.Consumer<android.content.res.Configuration!>);
+ }
+
+ public interface OnTrimMemoryProvider {
+ method public void addOnTrimMemoryListener(androidx.core.util.Consumer<java.lang.Integer!>);
+ method public void removeOnTrimMemoryListener(androidx.core.util.Consumer<java.lang.Integer!>);
+ }
+
+ public final class PackageManagerCompat {
+ method public static com.google.common.util.concurrent.ListenableFuture<java.lang.Integer!> getUnusedAppRestrictionsStatus(android.content.Context);
+ field public static final String ACTION_PERMISSION_REVOCATION_SETTINGS = "android.intent.action.AUTO_REVOKE_PERMISSIONS";
+ }
+
+ public final class PermissionChecker {
+ method public static int checkCallingOrSelfPermission(android.content.Context, String);
+ method public static int checkCallingPermission(android.content.Context, String, String?);
+ method public static int checkPermission(android.content.Context, String, int, int, String?);
+ method public static int checkSelfPermission(android.content.Context, String);
+ field public static final int PERMISSION_DENIED = -1; // 0xffffffff
+ field public static final int PERMISSION_DENIED_APP_OP = -2; // 0xfffffffe
+ field public static final int PERMISSION_GRANTED = 0; // 0x0
+ }
+
+ @Deprecated public final class SharedPreferencesCompat {
+ }
+
+ @Deprecated public static final class SharedPreferencesCompat.EditorCompat {
+ method @Deprecated public void apply(android.content.SharedPreferences.Editor);
+ method @Deprecated public static androidx.core.content.SharedPreferencesCompat.EditorCompat! getInstance();
+ }
+
+ public class UnusedAppRestrictionsBackportCallback {
+ method public void onResult(boolean, boolean) throws android.os.RemoteException;
+ }
+
+ public abstract class UnusedAppRestrictionsBackportService extends android.app.Service {
+ ctor public UnusedAppRestrictionsBackportService();
+ method protected abstract void isPermissionRevocationEnabled(androidx.core.content.UnusedAppRestrictionsBackportCallback);
+ method public android.os.IBinder? onBind(android.content.Intent?);
+ field public static final String ACTION_UNUSED_APP_RESTRICTIONS_BACKPORT_CONNECTION = "android.support.unusedapprestrictions.action.CustomUnusedAppRestrictionsBackportService";
+ }
+
+ public final class UnusedAppRestrictionsConstants {
+ field public static final int API_30 = 4; // 0x4
+ field public static final int API_30_BACKPORT = 3; // 0x3
+ field public static final int API_31 = 5; // 0x5
+ field public static final int DISABLED = 2; // 0x2
+ field public static final int ERROR = 0; // 0x0
+ field public static final int FEATURE_NOT_AVAILABLE = 1; // 0x1
+ }
+
+ public class UriMatcherCompat {
+ method public static androidx.core.util.Predicate<android.net.Uri!> asPredicate(android.content.UriMatcher);
+ }
+
+}
+
+package androidx.core.content.pm {
+
+ @Deprecated public final class ActivityInfoCompat {
+ field @Deprecated public static final int CONFIG_UI_MODE = 512; // 0x200
+ }
+
+ public final class PackageInfoCompat {
+ method public static long getLongVersionCode(android.content.pm.PackageInfo);
+ method public static java.util.List<android.content.pm.Signature!> getSignatures(android.content.pm.PackageManager, String) throws android.content.pm.PackageManager.NameNotFoundException;
+ method public static boolean hasSignatures(android.content.pm.PackageManager, String, @Size(min=1) java.util.Map<byte[]!,java.lang.Integer!>, boolean) throws android.content.pm.PackageManager.NameNotFoundException;
+ }
+
+ public final class PermissionInfoCompat {
+ method public static int getProtection(android.content.pm.PermissionInfo);
+ method public static int getProtectionFlags(android.content.pm.PermissionInfo);
+ }
+
+ public class ShortcutInfoCompat {
+ method public android.content.ComponentName? getActivity();
+ method public java.util.Set<java.lang.String!>? getCategories();
+ method public CharSequence? getDisabledMessage();
+ method public int getDisabledReason();
+ method public int getExcludedFromSurfaces();
+ method public android.os.PersistableBundle? getExtras();
+ method public String getId();
+ method public android.content.Intent getIntent();
+ method public android.content.Intent![] getIntents();
+ method public long getLastChangedTimestamp();
+ method public androidx.core.content.LocusIdCompat? getLocusId();
+ method public CharSequence? getLongLabel();
+ method public String getPackage();
+ method public int getRank();
+ method public CharSequence getShortLabel();
+ method public android.os.UserHandle? getUserHandle();
+ method public boolean hasKeyFieldsOnly();
+ method public boolean isCached();
+ method public boolean isDeclaredInManifest();
+ method public boolean isDynamic();
+ method public boolean isEnabled();
+ method public boolean isExcludedFromSurfaces(int);
+ method public boolean isImmutable();
+ method public boolean isPinned();
+ method @RequiresApi(25) public android.content.pm.ShortcutInfo! toShortcutInfo();
+ field public static final int SURFACE_LAUNCHER = 1; // 0x1
+ }
+
+ public static class ShortcutInfoCompat.Builder {
+ ctor public ShortcutInfoCompat.Builder(android.content.Context, String);
+ method public androidx.core.content.pm.ShortcutInfoCompat.Builder addCapabilityBinding(String);
+ method public androidx.core.content.pm.ShortcutInfoCompat.Builder addCapabilityBinding(String, String, java.util.List<java.lang.String!>);
+ method public androidx.core.content.pm.ShortcutInfoCompat build();
+ method public androidx.core.content.pm.ShortcutInfoCompat.Builder setActivity(android.content.ComponentName);
+ method public androidx.core.content.pm.ShortcutInfoCompat.Builder setAlwaysBadged();
+ method public androidx.core.content.pm.ShortcutInfoCompat.Builder setCategories(java.util.Set<java.lang.String!>);
+ method public androidx.core.content.pm.ShortcutInfoCompat.Builder setDisabledMessage(CharSequence);
+ method public androidx.core.content.pm.ShortcutInfoCompat.Builder setExcludedFromSurfaces(int);
+ method public androidx.core.content.pm.ShortcutInfoCompat.Builder setExtras(android.os.PersistableBundle);
+ method public androidx.core.content.pm.ShortcutInfoCompat.Builder setIcon(androidx.core.graphics.drawable.IconCompat!);
+ method public androidx.core.content.pm.ShortcutInfoCompat.Builder setIntent(android.content.Intent);
+ method public androidx.core.content.pm.ShortcutInfoCompat.Builder setIntents(android.content.Intent![]);
+ method public androidx.core.content.pm.ShortcutInfoCompat.Builder setIsConversation();
+ method public androidx.core.content.pm.ShortcutInfoCompat.Builder setLocusId(androidx.core.content.LocusIdCompat?);
+ method public androidx.core.content.pm.ShortcutInfoCompat.Builder setLongLabel(CharSequence);
+ method @Deprecated public androidx.core.content.pm.ShortcutInfoCompat.Builder setLongLived();
+ method public androidx.core.content.pm.ShortcutInfoCompat.Builder setLongLived(boolean);
+ method public androidx.core.content.pm.ShortcutInfoCompat.Builder setPerson(androidx.core.app.Person);
+ method public androidx.core.content.pm.ShortcutInfoCompat.Builder setPersons(androidx.core.app.Person![]);
+ method public androidx.core.content.pm.ShortcutInfoCompat.Builder setRank(int);
+ method public androidx.core.content.pm.ShortcutInfoCompat.Builder setShortLabel(CharSequence);
+ method public androidx.core.content.pm.ShortcutInfoCompat.Builder setSliceUri(android.net.Uri);
+ }
+
+ public class ShortcutManagerCompat {
+ method public static boolean addDynamicShortcuts(android.content.Context, java.util.List<androidx.core.content.pm.ShortcutInfoCompat!>);
+ method public static android.content.Intent createShortcutResultIntent(android.content.Context, androidx.core.content.pm.ShortcutInfoCompat);
+ method public static void disableShortcuts(android.content.Context, java.util.List<java.lang.String!>, CharSequence?);
+ method public static void enableShortcuts(android.content.Context, java.util.List<androidx.core.content.pm.ShortcutInfoCompat!>);
+ method public static java.util.List<androidx.core.content.pm.ShortcutInfoCompat!> getDynamicShortcuts(android.content.Context);
+ method public static int getIconMaxHeight(android.content.Context);
+ method public static int getIconMaxWidth(android.content.Context);
+ method public static int getMaxShortcutCountPerActivity(android.content.Context);
+ method public static java.util.List<androidx.core.content.pm.ShortcutInfoCompat!> getShortcuts(android.content.Context, int);
+ method public static boolean isRateLimitingActive(android.content.Context);
+ method public static boolean isRequestPinShortcutSupported(android.content.Context);
+ method public static boolean pushDynamicShortcut(android.content.Context, androidx.core.content.pm.ShortcutInfoCompat);
+ method public static void removeAllDynamicShortcuts(android.content.Context);
+ method public static void removeDynamicShortcuts(android.content.Context, java.util.List<java.lang.String!>);
+ method public static void removeLongLivedShortcuts(android.content.Context, java.util.List<java.lang.String!>);
+ method public static void reportShortcutUsed(android.content.Context, String);
+ method public static boolean requestPinShortcut(android.content.Context, androidx.core.content.pm.ShortcutInfoCompat, android.content.IntentSender?);
+ method public static boolean setDynamicShortcuts(android.content.Context, java.util.List<androidx.core.content.pm.ShortcutInfoCompat!>);
+ method public static boolean updateShortcuts(android.content.Context, java.util.List<androidx.core.content.pm.ShortcutInfoCompat!>);
+ field public static final String EXTRA_SHORTCUT_ID = "android.intent.extra.shortcut.ID";
+ field public static final int FLAG_MATCH_CACHED = 8; // 0x8
+ field public static final int FLAG_MATCH_DYNAMIC = 2; // 0x2
+ field public static final int FLAG_MATCH_MANIFEST = 1; // 0x1
+ field public static final int FLAG_MATCH_PINNED = 4; // 0x4
+ }
+
+}
+
+package androidx.core.content.res {
+
+ public final class ConfigurationHelper {
+ method public static int getDensityDpi(android.content.res.Resources);
+ }
+
+ public final class ResourcesCompat {
+ method public static void clearCachesForTheme(android.content.res.Resources.Theme);
+ method public static android.graphics.Typeface? getCachedFont(android.content.Context, @FontRes int) throws android.content.res.Resources.NotFoundException;
+ method @ColorInt public static int getColor(android.content.res.Resources, @ColorRes int, android.content.res.Resources.Theme?) throws android.content.res.Resources.NotFoundException;
+ method public static android.content.res.ColorStateList? getColorStateList(android.content.res.Resources, @ColorRes int, android.content.res.Resources.Theme?) throws android.content.res.Resources.NotFoundException;
+ method public static android.graphics.drawable.Drawable? getDrawable(android.content.res.Resources, @DrawableRes int, android.content.res.Resources.Theme?) throws android.content.res.Resources.NotFoundException;
+ method public static android.graphics.drawable.Drawable? getDrawableForDensity(android.content.res.Resources, @DrawableRes int, int, android.content.res.Resources.Theme?) throws android.content.res.Resources.NotFoundException;
+ method public static float getFloat(android.content.res.Resources, @DimenRes int);
+ method public static android.graphics.Typeface? getFont(android.content.Context, @FontRes int) throws android.content.res.Resources.NotFoundException;
+ method public static void getFont(android.content.Context, @FontRes int, androidx.core.content.res.ResourcesCompat.FontCallback, android.os.Handler?) throws android.content.res.Resources.NotFoundException;
+ field @AnyRes public static final int ID_NULL = 0; // 0x0
+ }
+
+ public abstract static class ResourcesCompat.FontCallback {
+ ctor public ResourcesCompat.FontCallback();
+ method public abstract void onFontRetrievalFailed(int);
+ method public abstract void onFontRetrieved(android.graphics.Typeface);
+ }
+
+ public static final class ResourcesCompat.ThemeCompat {
+ method public static void rebase(android.content.res.Resources.Theme);
+ }
+
+}
+
+package androidx.core.database {
+
+ public final class CursorWindowCompat {
+ method public static android.database.CursorWindow create(String?, long);
+ }
+
+ @Deprecated public final class DatabaseUtilsCompat {
+ method @Deprecated public static String![]! appendSelectionArgs(String![]!, String![]!);
+ method @Deprecated public static String! concatenateWhere(String!, String!);
+ }
+
+}
+
+package androidx.core.database.sqlite {
+
+ public final class SQLiteCursorCompat {
+ method public static void setFillWindowForwardOnly(android.database.sqlite.SQLiteCursor, boolean);
+ }
+
+}
+
+package androidx.core.graphics {
+
+ public final class BitmapCompat {
+ method public static android.graphics.Bitmap createScaledBitmap(android.graphics.Bitmap, int, int, android.graphics.Rect?, boolean);
+ method public static int getAllocationByteCount(android.graphics.Bitmap);
+ method public static boolean hasMipMap(android.graphics.Bitmap);
+ method public static void setHasMipMap(android.graphics.Bitmap, boolean);
+ }
+
+ public class BlendModeColorFilterCompat {
+ method public static android.graphics.ColorFilter? createBlendModeColorFilterCompat(int, androidx.core.graphics.BlendModeCompat);
+ }
+
+ public enum BlendModeCompat {
+ enum_constant public static final androidx.core.graphics.BlendModeCompat CLEAR;
+ enum_constant @RequiresApi(android.os.Build.VERSION_CODES.Q) public static final androidx.core.graphics.BlendModeCompat COLOR;
+ enum_constant @RequiresApi(android.os.Build.VERSION_CODES.Q) public static final androidx.core.graphics.BlendModeCompat COLOR_BURN;
+ enum_constant @RequiresApi(android.os.Build.VERSION_CODES.Q) public static final androidx.core.graphics.BlendModeCompat COLOR_DODGE;
+ enum_constant public static final androidx.core.graphics.BlendModeCompat DARKEN;
+ enum_constant @RequiresApi(android.os.Build.VERSION_CODES.Q) public static final androidx.core.graphics.BlendModeCompat DIFFERENCE;
+ enum_constant public static final androidx.core.graphics.BlendModeCompat DST;
+ enum_constant public static final androidx.core.graphics.BlendModeCompat DST_ATOP;
+ enum_constant public static final androidx.core.graphics.BlendModeCompat DST_IN;
+ enum_constant public static final androidx.core.graphics.BlendModeCompat DST_OUT;
+ enum_constant public static final androidx.core.graphics.BlendModeCompat DST_OVER;
+ enum_constant @RequiresApi(android.os.Build.VERSION_CODES.Q) public static final androidx.core.graphics.BlendModeCompat EXCLUSION;
+ enum_constant @RequiresApi(android.os.Build.VERSION_CODES.Q) public static final androidx.core.graphics.BlendModeCompat HARD_LIGHT;
+ enum_constant @RequiresApi(android.os.Build.VERSION_CODES.Q) public static final androidx.core.graphics.BlendModeCompat HUE;
+ enum_constant public static final androidx.core.graphics.BlendModeCompat LIGHTEN;
+ enum_constant @RequiresApi(android.os.Build.VERSION_CODES.Q) public static final androidx.core.graphics.BlendModeCompat LUMINOSITY;
+ enum_constant public static final androidx.core.graphics.BlendModeCompat MODULATE;
+ enum_constant @RequiresApi(android.os.Build.VERSION_CODES.Q) public static final androidx.core.graphics.BlendModeCompat MULTIPLY;
+ enum_constant public static final androidx.core.graphics.BlendModeCompat OVERLAY;
+ enum_constant public static final androidx.core.graphics.BlendModeCompat PLUS;
+ enum_constant @RequiresApi(android.os.Build.VERSION_CODES.Q) public static final androidx.core.graphics.BlendModeCompat SATURATION;
+ enum_constant public static final androidx.core.graphics.BlendModeCompat SCREEN;
+ enum_constant @RequiresApi(android.os.Build.VERSION_CODES.Q) public static final androidx.core.graphics.BlendModeCompat SOFT_LIGHT;
+ enum_constant public static final androidx.core.graphics.BlendModeCompat SRC;
+ enum_constant public static final androidx.core.graphics.BlendModeCompat SRC_ATOP;
+ enum_constant public static final androidx.core.graphics.BlendModeCompat SRC_IN;
+ enum_constant public static final androidx.core.graphics.BlendModeCompat SRC_OUT;
+ enum_constant public static final androidx.core.graphics.BlendModeCompat SRC_OVER;
+ enum_constant public static final androidx.core.graphics.BlendModeCompat XOR;
+ }
+
+ public final class ColorUtils {
+ method @ColorInt public static int HSLToColor(float[]);
+ method @ColorInt public static int LABToColor(@FloatRange(from=0.0f, to=100) double, @FloatRange(from=0xffffff80, to=127) double, @FloatRange(from=0xffffff80, to=127) double);
+ method public static void LABToXYZ(@FloatRange(from=0.0f, to=100) double, @FloatRange(from=0xffffff80, to=127) double, @FloatRange(from=0xffffff80, to=127) double, double[]);
+ method public static void RGBToHSL(@IntRange(from=0, to=255) int, @IntRange(from=0, to=255) int, @IntRange(from=0, to=255) int, float[]);
+ method public static void RGBToLAB(@IntRange(from=0, to=255) int, @IntRange(from=0, to=255) int, @IntRange(from=0, to=255) int, double[]);
+ method public static void RGBToXYZ(@IntRange(from=0, to=255) int, @IntRange(from=0, to=255) int, @IntRange(from=0, to=255) int, double[]);
+ method @ColorInt public static int XYZToColor(@FloatRange(from=0.0f, to=95.047) double, @FloatRange(from=0.0f, to=0x64) double, @FloatRange(from=0.0f, to=108.883) double);
+ method public static void XYZToLAB(@FloatRange(from=0.0f, to=95.047) double, @FloatRange(from=0.0f, to=0x64) double, @FloatRange(from=0.0f, to=108.883) double, double[]);
+ method @ColorInt public static int blendARGB(@ColorInt int, @ColorInt int, @FloatRange(from=0.0, to=1.0) float);
+ method public static void blendHSL(float[], float[], @FloatRange(from=0.0, to=1.0) float, float[]);
+ method public static void blendLAB(double[], double[], @FloatRange(from=0.0, to=1.0) double, double[]);
+ method public static double calculateContrast(@ColorInt int, @ColorInt int);
+ method @FloatRange(from=0.0, to=1.0) public static double calculateLuminance(@ColorInt int);
+ method public static int calculateMinimumAlpha(@ColorInt int, @ColorInt int, float);
+ method public static void colorToHSL(@ColorInt int, float[]);
+ method public static void colorToLAB(@ColorInt int, double[]);
+ method public static void colorToXYZ(@ColorInt int, double[]);
+ method public static int compositeColors(@ColorInt int, @ColorInt int);
+ method @RequiresApi(26) public static android.graphics.Color compositeColors(android.graphics.Color, android.graphics.Color);
+ method public static double distanceEuclidean(double[], double[]);
+ method @ColorInt public static int setAlphaComponent(@ColorInt int, @IntRange(from=0, to=255) int);
+ }
+
+ public final class Insets {
+ method public static androidx.core.graphics.Insets add(androidx.core.graphics.Insets, androidx.core.graphics.Insets);
+ method public static androidx.core.graphics.Insets max(androidx.core.graphics.Insets, androidx.core.graphics.Insets);
+ method public static androidx.core.graphics.Insets min(androidx.core.graphics.Insets, androidx.core.graphics.Insets);
+ method public static androidx.core.graphics.Insets of(int, int, int, int);
+ method public static androidx.core.graphics.Insets of(android.graphics.Rect);
+ method public static androidx.core.graphics.Insets subtract(androidx.core.graphics.Insets, androidx.core.graphics.Insets);
+ method @RequiresApi(api=29) public static androidx.core.graphics.Insets toCompatInsets(android.graphics.Insets);
+ method @RequiresApi(29) public android.graphics.Insets toPlatformInsets();
+ field public static final androidx.core.graphics.Insets NONE;
+ field public final int bottom;
+ field public final int left;
+ field public final int right;
+ field public final int top;
+ }
+
+ public final class PaintCompat {
+ method public static boolean hasGlyph(android.graphics.Paint, String);
+ method public static boolean setBlendMode(android.graphics.Paint, androidx.core.graphics.BlendModeCompat?);
+ }
+
+ public final class PathSegment {
+ ctor public PathSegment(android.graphics.PointF, float, android.graphics.PointF, float);
+ method public android.graphics.PointF getEnd();
+ method public float getEndFraction();
+ method public android.graphics.PointF getStart();
+ method public float getStartFraction();
+ }
+
+ public final class PathUtils {
+ method @RequiresApi(26) public static java.util.Collection<androidx.core.graphics.PathSegment!> flatten(android.graphics.Path);
+ method @RequiresApi(26) public static java.util.Collection<androidx.core.graphics.PathSegment!> flatten(android.graphics.Path, @FloatRange(from=0) float);
+ }
+
+ public class TypefaceCompat {
+ method public static android.graphics.Typeface create(android.content.Context, android.graphics.Typeface?, int);
+ method public static android.graphics.Typeface create(android.content.Context, android.graphics.Typeface?, @IntRange(from=1, to=1000) int, boolean);
+ }
+
+}
+
+package androidx.core.graphics.drawable {
+
+ public final class DrawableCompat {
+ method public static void applyTheme(android.graphics.drawable.Drawable, android.content.res.Resources.Theme);
+ method public static boolean canApplyTheme(android.graphics.drawable.Drawable);
+ method public static void clearColorFilter(android.graphics.drawable.Drawable);
+ method public static int getAlpha(android.graphics.drawable.Drawable);
+ method public static android.graphics.ColorFilter? getColorFilter(android.graphics.drawable.Drawable);
+ method public static int getLayoutDirection(android.graphics.drawable.Drawable);
+ method public static void inflate(android.graphics.drawable.Drawable, android.content.res.Resources, org.xmlpull.v1.XmlPullParser, android.util.AttributeSet, android.content.res.Resources.Theme?) throws java.io.IOException, org.xmlpull.v1.XmlPullParserException;
+ method public static boolean isAutoMirrored(android.graphics.drawable.Drawable);
+ method @Deprecated public static void jumpToCurrentState(android.graphics.drawable.Drawable);
+ method public static void setAutoMirrored(android.graphics.drawable.Drawable, boolean);
+ method public static void setHotspot(android.graphics.drawable.Drawable, float, float);
+ method public static void setHotspotBounds(android.graphics.drawable.Drawable, int, int, int, int);
+ method public static boolean setLayoutDirection(android.graphics.drawable.Drawable, int);
+ method public static void setTint(android.graphics.drawable.Drawable, @ColorInt int);
+ method public static void setTintList(android.graphics.drawable.Drawable, android.content.res.ColorStateList?);
+ method public static void setTintMode(android.graphics.drawable.Drawable, android.graphics.PorterDuff.Mode?);
+ method public static <T extends android.graphics.drawable.Drawable> T! unwrap(android.graphics.drawable.Drawable);
+ method public static android.graphics.drawable.Drawable wrap(android.graphics.drawable.Drawable);
+ }
+
+ public class IconCompat implements androidx.versionedparcelable.VersionedParcelable {
+ method public static androidx.core.graphics.drawable.IconCompat? createFromBundle(android.os.Bundle);
+ method @RequiresApi(23) public static androidx.core.graphics.drawable.IconCompat? createFromIcon(android.content.Context, android.graphics.drawable.Icon);
+ method public static androidx.core.graphics.drawable.IconCompat createWithAdaptiveBitmap(android.graphics.Bitmap);
+ method public static androidx.core.graphics.drawable.IconCompat createWithAdaptiveBitmapContentUri(String);
+ method public static androidx.core.graphics.drawable.IconCompat createWithAdaptiveBitmapContentUri(android.net.Uri);
+ method public static androidx.core.graphics.drawable.IconCompat createWithBitmap(android.graphics.Bitmap);
+ method public static androidx.core.graphics.drawable.IconCompat createWithContentUri(String);
+ method public static androidx.core.graphics.drawable.IconCompat createWithContentUri(android.net.Uri);
+ method public static androidx.core.graphics.drawable.IconCompat createWithData(byte[], int, int);
+ method public static androidx.core.graphics.drawable.IconCompat createWithResource(android.content.Context, @DrawableRes int);
+ method @DrawableRes public int getResId();
+ method public String getResPackage();
+ method public int getType();
+ method public android.net.Uri getUri();
+ method public android.graphics.drawable.Drawable? loadDrawable(android.content.Context);
+ method public void onPostParceling();
+ method public void onPreParceling(boolean);
+ method public androidx.core.graphics.drawable.IconCompat setTint(@ColorInt int);
+ method public androidx.core.graphics.drawable.IconCompat setTintList(android.content.res.ColorStateList?);
+ method public androidx.core.graphics.drawable.IconCompat setTintMode(android.graphics.PorterDuff.Mode?);
+ method public android.os.Bundle toBundle();
+ method @Deprecated @RequiresApi(23) public android.graphics.drawable.Icon toIcon();
+ method @RequiresApi(23) public android.graphics.drawable.Icon toIcon(android.content.Context?);
+ field public static final int TYPE_ADAPTIVE_BITMAP = 5; // 0x5
+ field public static final int TYPE_BITMAP = 1; // 0x1
+ field public static final int TYPE_DATA = 3; // 0x3
+ field public static final int TYPE_RESOURCE = 2; // 0x2
+ field public static final int TYPE_UNKNOWN = -1; // 0xffffffff
+ field public static final int TYPE_URI = 4; // 0x4
+ field public static final int TYPE_URI_ADAPTIVE_BITMAP = 6; // 0x6
+ }
+
+ public abstract class RoundedBitmapDrawable extends android.graphics.drawable.Drawable {
+ method public void draw(android.graphics.Canvas);
+ method public final android.graphics.Bitmap? getBitmap();
+ method public float getCornerRadius();
+ method public int getGravity();
+ method public int getOpacity();
+ method public final android.graphics.Paint getPaint();
+ method public boolean hasAntiAlias();
+ method public boolean hasMipMap();
+ method public boolean isCircular();
+ method public void setAlpha(int);
+ method public void setAntiAlias(boolean);
+ method public void setCircular(boolean);
+ method public void setColorFilter(android.graphics.ColorFilter!);
+ method public void setCornerRadius(float);
+ method public void setDither(boolean);
+ method public void setGravity(int);
+ method public void setMipMap(boolean);
+ method public void setTargetDensity(android.graphics.Canvas);
+ method public void setTargetDensity(android.util.DisplayMetrics);
+ method public void setTargetDensity(int);
+ }
+
+ public final class RoundedBitmapDrawableFactory {
+ method public static androidx.core.graphics.drawable.RoundedBitmapDrawable create(android.content.res.Resources, android.graphics.Bitmap?);
+ method public static androidx.core.graphics.drawable.RoundedBitmapDrawable create(android.content.res.Resources, String);
+ method public static androidx.core.graphics.drawable.RoundedBitmapDrawable create(android.content.res.Resources, java.io.InputStream);
+ }
+
+}
+
+package androidx.core.hardware.display {
+
+ public final class DisplayManagerCompat {
+ method public android.view.Display? getDisplay(int);
+ method public android.view.Display![] getDisplays();
+ method public android.view.Display![] getDisplays(String?);
+ method public static androidx.core.hardware.display.DisplayManagerCompat getInstance(android.content.Context);
+ field public static final String DISPLAY_CATEGORY_PRESENTATION = "android.hardware.display.category.PRESENTATION";
+ }
+
+}
+
+package androidx.core.hardware.fingerprint {
+
+ @Deprecated public class FingerprintManagerCompat {
+ method @Deprecated @RequiresPermission(android.Manifest.permission.USE_FINGERPRINT) public void authenticate(androidx.core.hardware.fingerprint.FingerprintManagerCompat.CryptoObject?, int, androidx.core.os.CancellationSignal?, androidx.core.hardware.fingerprint.FingerprintManagerCompat.AuthenticationCallback, android.os.Handler?);
+ method @Deprecated public static androidx.core.hardware.fingerprint.FingerprintManagerCompat from(android.content.Context);
+ method @Deprecated @RequiresPermission(android.Manifest.permission.USE_FINGERPRINT) public boolean hasEnrolledFingerprints();
+ method @Deprecated @RequiresPermission(android.Manifest.permission.USE_FINGERPRINT) public boolean isHardwareDetected();
+ }
+
+ @Deprecated public abstract static class FingerprintManagerCompat.AuthenticationCallback {
+ ctor @Deprecated public FingerprintManagerCompat.AuthenticationCallback();
+ method @Deprecated public void onAuthenticationError(int, CharSequence!);
+ method @Deprecated public void onAuthenticationFailed();
+ method @Deprecated public void onAuthenticationHelp(int, CharSequence!);
+ method @Deprecated public void onAuthenticationSucceeded(androidx.core.hardware.fingerprint.FingerprintManagerCompat.AuthenticationResult!);
+ }
+
+ @Deprecated public static final class FingerprintManagerCompat.AuthenticationResult {
+ ctor @Deprecated public FingerprintManagerCompat.AuthenticationResult(androidx.core.hardware.fingerprint.FingerprintManagerCompat.CryptoObject!);
+ method @Deprecated public androidx.core.hardware.fingerprint.FingerprintManagerCompat.CryptoObject! getCryptoObject();
+ }
+
+ @Deprecated public static class FingerprintManagerCompat.CryptoObject {
+ ctor @Deprecated public FingerprintManagerCompat.CryptoObject(java.security.Signature);
+ ctor @Deprecated public FingerprintManagerCompat.CryptoObject(javax.crypto.Cipher);
+ ctor @Deprecated public FingerprintManagerCompat.CryptoObject(javax.crypto.Mac);
+ method @Deprecated public javax.crypto.Cipher? getCipher();
+ method @Deprecated public javax.crypto.Mac? getMac();
+ method @Deprecated public java.security.Signature? getSignature();
+ }
+
+}
+
+package androidx.core.location {
+
+ public abstract class GnssStatusCompat {
+ method @FloatRange(from=0, to=360) public abstract float getAzimuthDegrees(@IntRange(from=0) int);
+ method @FloatRange(from=0, to=63) public abstract float getBasebandCn0DbHz(@IntRange(from=0) int);
+ method @FloatRange(from=0) public abstract float getCarrierFrequencyHz(@IntRange(from=0) int);
+ method @FloatRange(from=0, to=63) public abstract float getCn0DbHz(@IntRange(from=0) int);
+ method public abstract int getConstellationType(@IntRange(from=0) int);
+ method @FloatRange(from=0xffffffa6, to=90) public abstract float getElevationDegrees(@IntRange(from=0) int);
+ method @IntRange(from=0) public abstract int getSatelliteCount();
+ method @IntRange(from=1, to=200) public abstract int getSvid(@IntRange(from=0) int);
+ method public abstract boolean hasAlmanacData(@IntRange(from=0) int);
+ method public abstract boolean hasBasebandCn0DbHz(@IntRange(from=0) int);
+ method public abstract boolean hasCarrierFrequencyHz(@IntRange(from=0) int);
+ method public abstract boolean hasEphemerisData(@IntRange(from=0) int);
+ method public abstract boolean usedInFix(@IntRange(from=0) int);
+ method @RequiresApi(android.os.Build.VERSION_CODES.N) public static androidx.core.location.GnssStatusCompat wrap(android.location.GnssStatus);
+ method public static androidx.core.location.GnssStatusCompat wrap(android.location.GpsStatus);
+ field public static final int CONSTELLATION_BEIDOU = 5; // 0x5
+ field public static final int CONSTELLATION_GALILEO = 6; // 0x6
+ field public static final int CONSTELLATION_GLONASS = 3; // 0x3
+ field public static final int CONSTELLATION_GPS = 1; // 0x1
+ field public static final int CONSTELLATION_IRNSS = 7; // 0x7
+ field public static final int CONSTELLATION_QZSS = 4; // 0x4
+ field public static final int CONSTELLATION_SBAS = 2; // 0x2
+ field public static final int CONSTELLATION_UNKNOWN = 0; // 0x0
+ }
+
+ public abstract static class GnssStatusCompat.Callback {
+ ctor public GnssStatusCompat.Callback();
+ method public void onFirstFix(@IntRange(from=0) int);
+ method public void onSatelliteStatusChanged(androidx.core.location.GnssStatusCompat);
+ method public void onStarted();
+ method public void onStopped();
+ }
+
+ public final class LocationCompat {
+ method public static float getBearingAccuracyDegrees(android.location.Location);
+ method public static long getElapsedRealtimeMillis(android.location.Location);
+ method public static long getElapsedRealtimeNanos(android.location.Location);
+ method @FloatRange(from=0.0) public static float getMslAltitudeAccuracyMeters(android.location.Location);
+ method public static double getMslAltitudeMeters(android.location.Location);
+ method public static float getSpeedAccuracyMetersPerSecond(android.location.Location);
+ method public static float getVerticalAccuracyMeters(android.location.Location);
+ method public static boolean hasBearingAccuracy(android.location.Location);
+ method public static boolean hasMslAltitude(android.location.Location);
+ method public static boolean hasMslAltitudeAccuracy(android.location.Location);
+ method public static boolean hasSpeedAccuracy(android.location.Location);
+ method public static boolean hasVerticalAccuracy(android.location.Location);
+ method public static boolean isMock(android.location.Location);
+ method public static void removeMslAltitude(android.location.Location);
+ method public static void removeMslAltitudeAccuracy(android.location.Location);
+ method public static void setBearingAccuracyDegrees(android.location.Location, float);
+ method public static void setMock(android.location.Location, boolean);
+ method public static void setMslAltitudeAccuracyMeters(android.location.Location, @FloatRange(from=0.0) float);
+ method public static void setMslAltitudeMeters(android.location.Location, double);
+ method public static void setSpeedAccuracyMetersPerSecond(android.location.Location, float);
+ method public static void setVerticalAccuracyMeters(android.location.Location, float);
+ field public static final String EXTRA_BEARING_ACCURACY = "bearingAccuracy";
+ field public static final String EXTRA_IS_MOCK = "mockLocation";
+ field public static final String EXTRA_MSL_ALTITUDE = "androidx.core.location.extra.MSL_ALTITUDE";
+ field public static final String EXTRA_MSL_ALTITUDE_ACCURACY = "androidx.core.location.extra.MSL_ALTITUDE_ACCURACY";
+ field public static final String EXTRA_SPEED_ACCURACY = "speedAccuracy";
+ field public static final String EXTRA_VERTICAL_ACCURACY = "verticalAccuracy";
+ }
+
+ public interface LocationListenerCompat extends android.location.LocationListener {
+ method public default void onStatusChanged(String, int, android.os.Bundle?);
+ }
+
+ public final class LocationManagerCompat {
+ method @RequiresPermission(anyOf={android.Manifest.permission.ACCESS_COARSE_LOCATION, android.Manifest.permission.ACCESS_FINE_LOCATION}) public static void getCurrentLocation(android.location.LocationManager, String, androidx.core.os.CancellationSignal?, java.util.concurrent.Executor, androidx.core.util.Consumer<android.location.Location!>);
+ method public static String? getGnssHardwareModelName(android.location.LocationManager);
+ method public static int getGnssYearOfHardware(android.location.LocationManager);
+ method public static boolean hasProvider(android.location.LocationManager, String);
+ method public static boolean isLocationEnabled(android.location.LocationManager);
+ method @RequiresApi(android.os.Build.VERSION_CODES.N) @RequiresPermission(android.Manifest.permission.ACCESS_FINE_LOCATION) public static boolean registerGnssMeasurementsCallback(android.location.LocationManager, android.location.GnssMeasurementsEvent.Callback, android.os.Handler);
+ method @RequiresApi(android.os.Build.VERSION_CODES.R) @RequiresPermission(android.Manifest.permission.ACCESS_FINE_LOCATION) public static boolean registerGnssMeasurementsCallback(android.location.LocationManager, java.util.concurrent.Executor, android.location.GnssMeasurementsEvent.Callback);
+ method @RequiresPermission(android.Manifest.permission.ACCESS_FINE_LOCATION) public static boolean registerGnssStatusCallback(android.location.LocationManager, androidx.core.location.GnssStatusCompat.Callback, android.os.Handler);
+ method @RequiresPermission(android.Manifest.permission.ACCESS_FINE_LOCATION) public static boolean registerGnssStatusCallback(android.location.LocationManager, java.util.concurrent.Executor, androidx.core.location.GnssStatusCompat.Callback);
+ method @RequiresPermission(anyOf={android.Manifest.permission.ACCESS_COARSE_LOCATION, android.Manifest.permission.ACCESS_FINE_LOCATION}) public static void removeUpdates(android.location.LocationManager, androidx.core.location.LocationListenerCompat);
+ method @RequiresPermission(anyOf={android.Manifest.permission.ACCESS_COARSE_LOCATION, android.Manifest.permission.ACCESS_FINE_LOCATION}) public static void requestLocationUpdates(android.location.LocationManager, String, androidx.core.location.LocationRequestCompat, 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 @RequiresApi(android.os.Build.VERSION_CODES.N) public static void unregisterGnssMeasurementsCallback(android.location.LocationManager, android.location.GnssMeasurementsEvent.Callback);
+ method public static void unregisterGnssStatusCallback(android.location.LocationManager, androidx.core.location.GnssStatusCompat.Callback);
+ }
+
+ public final class LocationRequestCompat {
+ method @IntRange(from=1) public long getDurationMillis();
+ method @IntRange(from=0) public long getIntervalMillis();
+ method @IntRange(from=0) public long getMaxUpdateDelayMillis();
+ method @IntRange(from=1, to=java.lang.Integer.MAX_VALUE) public int getMaxUpdates();
+ method @FloatRange(from=0, to=java.lang.Float.MAX_VALUE) public float getMinUpdateDistanceMeters();
+ method @IntRange(from=0) public long getMinUpdateIntervalMillis();
+ method public int getQuality();
+ method @RequiresApi(31) public android.location.LocationRequest toLocationRequest();
+ method @RequiresApi(19) public android.location.LocationRequest? toLocationRequest(String);
+ field public static final long PASSIVE_INTERVAL = 9223372036854775807L; // 0x7fffffffffffffffL
+ field public static final int QUALITY_BALANCED_POWER_ACCURACY = 102; // 0x66
+ field public static final int QUALITY_HIGH_ACCURACY = 100; // 0x64
+ field public static final int QUALITY_LOW_POWER = 104; // 0x68
+ }
+
+ public static final class LocationRequestCompat.Builder {
+ ctor public LocationRequestCompat.Builder(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 {
+
+ public class MathUtils {
+ method public static int addExact(int, int);
+ method public static long addExact(long, long);
+ method public static float clamp(float, float, float);
+ method public static double clamp(double, double, double);
+ method public static int clamp(int, int, int);
+ method public static long clamp(long, long, long);
+ method public static int decrementExact(int);
+ method public static long decrementExact(long);
+ method public static int incrementExact(int);
+ method public static long incrementExact(long);
+ method public static int multiplyExact(int, int);
+ method public static long multiplyExact(long, long);
+ method public static int negateExact(int);
+ method public static long negateExact(long);
+ method public static int subtractExact(int, int);
+ method public static long subtractExact(long, long);
+ method public static int toIntExact(long);
+ }
+
+}
+
+package androidx.core.net {
+
+ public final class ConnectivityManagerCompat {
+ method @RequiresPermission(android.Manifest.permission.ACCESS_NETWORK_STATE) public static android.net.NetworkInfo? getNetworkInfoFromBroadcast(android.net.ConnectivityManager, android.content.Intent);
+ method public static int getRestrictBackgroundStatus(android.net.ConnectivityManager);
+ method @RequiresPermission(android.Manifest.permission.ACCESS_NETWORK_STATE) public static boolean isActiveNetworkMetered(android.net.ConnectivityManager);
+ field public static final int RESTRICT_BACKGROUND_STATUS_DISABLED = 1; // 0x1
+ field public static final int RESTRICT_BACKGROUND_STATUS_ENABLED = 3; // 0x3
+ field public static final int RESTRICT_BACKGROUND_STATUS_WHITELISTED = 2; // 0x2
+ }
+
+ public final class MailTo {
+ method public String? getBcc();
+ method public String? getBody();
+ method public String? getCc();
+ method public java.util.Map<java.lang.String!,java.lang.String!>? getHeaders();
+ method public String? getSubject();
+ method public String? getTo();
+ method public static boolean isMailTo(String?);
+ method public static boolean isMailTo(android.net.Uri?);
+ method public static androidx.core.net.MailTo parse(String) throws androidx.core.net.ParseException;
+ method public static androidx.core.net.MailTo parse(android.net.Uri) throws androidx.core.net.ParseException;
+ field public static final String MAILTO_SCHEME = "mailto:";
+ }
+
+ public class ParseException extends java.lang.RuntimeException {
+ field public final String response;
+ }
+
+ public final class TrafficStatsCompat {
+ method @Deprecated public static void clearThreadStatsTag();
+ method @Deprecated public static int getThreadStatsTag();
+ method @Deprecated public static void incrementOperationCount(int);
+ method @Deprecated public static void incrementOperationCount(int, int);
+ method @Deprecated public static void setThreadStatsTag(int);
+ method public static void tagDatagramSocket(java.net.DatagramSocket) throws java.net.SocketException;
+ method @Deprecated public static void tagSocket(java.net.Socket!) throws java.net.SocketException;
+ method public static void untagDatagramSocket(java.net.DatagramSocket) throws java.net.SocketException;
+ method @Deprecated public static void untagSocket(java.net.Socket!) throws java.net.SocketException;
+ }
+
+ public final class UriCompat {
+ method public static String toSafeString(android.net.Uri);
+ }
+
+}
+
+package androidx.core.os {
+
+ public class BuildCompat {
+ method @Deprecated @ChecksSdkIntAtLeast(api=android.os.Build.VERSION_CODES.N) public static boolean isAtLeastN();
+ method @Deprecated @ChecksSdkIntAtLeast(api=android.os.Build.VERSION_CODES.N_MR1) public static boolean isAtLeastNMR1();
+ method @Deprecated @ChecksSdkIntAtLeast(api=android.os.Build.VERSION_CODES.O) public static boolean isAtLeastO();
+ method @Deprecated @ChecksSdkIntAtLeast(api=android.os.Build.VERSION_CODES.O_MR1) public static boolean isAtLeastOMR1();
+ method @Deprecated @ChecksSdkIntAtLeast(api=android.os.Build.VERSION_CODES.P) public static boolean isAtLeastP();
+ method @Deprecated @ChecksSdkIntAtLeast(api=android.os.Build.VERSION_CODES.Q) public static boolean isAtLeastQ();
+ method @Deprecated @ChecksSdkIntAtLeast(api=android.os.Build.VERSION_CODES.R) public static boolean isAtLeastR();
+ method @Deprecated @ChecksSdkIntAtLeast(api=31, codename="S") public static boolean isAtLeastS();
+ field @ChecksSdkIntAtLeast(extension=android.os.ext.SdkExtensions.AD_SERVICES) public static final int AD_SERVICES_EXTENSION_INT;
+ field @ChecksSdkIntAtLeast(extension=android.os.Build.VERSION_CODES.R) public static final int R_EXTENSION_INT;
+ field @ChecksSdkIntAtLeast(extension=android.os.Build.VERSION_CODES.S) public static final int S_EXTENSION_INT;
+ field @ChecksSdkIntAtLeast(extension=android.os.Build.VERSION_CODES.TIRAMISU) public static final int T_EXTENSION_INT;
+ }
+
+ public final class BundleCompat {
+ method public static <T> T? getParcelable(android.os.Bundle, String?, Class<T!>);
+ method public static android.os.Parcelable![]? getParcelableArray(android.os.Bundle, String?, Class<? extends android.os.Parcelable>);
+ method public static <T> java.util.ArrayList<T!>? getParcelableArrayList(android.os.Bundle, String?, Class<? extends T>);
+ method public static <T> android.util.SparseArray<T!>? getSparseParcelableArray(android.os.Bundle, String?, Class<? extends T>);
+ }
+
+ public final class CancellationSignal {
+ ctor public CancellationSignal();
+ method public void cancel();
+ method public Object? getCancellationSignalObject();
+ method public boolean isCanceled();
+ method public void setOnCancelListener(androidx.core.os.CancellationSignal.OnCancelListener?);
+ method public void throwIfCanceled();
+ }
+
+ public static interface CancellationSignal.OnCancelListener {
+ method public void onCancel();
+ }
+
+ public final class ConfigurationCompat {
+ method public static androidx.core.os.LocaleListCompat getLocales(android.content.res.Configuration);
+ }
+
+ public final class EnvironmentCompat {
+ method public static String getStorageState(java.io.File);
+ field public static final String MEDIA_UNKNOWN = "unknown";
+ }
+
+ public final class ExecutorCompat {
+ method public static java.util.concurrent.Executor create(android.os.Handler);
+ }
+
+ public final class HandlerCompat {
+ method public static android.os.Handler createAsync(android.os.Looper);
+ method public static android.os.Handler createAsync(android.os.Looper, android.os.Handler.Callback);
+ method @RequiresApi(16) public static boolean hasCallbacks(android.os.Handler, Runnable);
+ method public static boolean postDelayed(android.os.Handler, Runnable, Object?, long);
+ }
+
+ public final class LocaleListCompat {
+ method public static androidx.core.os.LocaleListCompat create(java.util.Locale!...);
+ method public static androidx.core.os.LocaleListCompat forLanguageTags(String?);
+ method public java.util.Locale? get(int);
+ method @Size(min=1) public static androidx.core.os.LocaleListCompat getAdjustedDefault();
+ method @Size(min=1) public static androidx.core.os.LocaleListCompat getDefault();
+ method public static androidx.core.os.LocaleListCompat getEmptyLocaleList();
+ method public java.util.Locale? getFirstMatch(String![]);
+ method @IntRange(from=0xffffffff) public int indexOf(java.util.Locale?);
+ method public boolean isEmpty();
+ method @RequiresApi(21) public static boolean matchesLanguageAndScript(java.util.Locale, java.util.Locale);
+ method @IntRange(from=0) public int size();
+ method public String toLanguageTags();
+ method public Object? unwrap();
+ method @Deprecated @RequiresApi(24) public static androidx.core.os.LocaleListCompat! wrap(Object!);
+ method @RequiresApi(24) public static androidx.core.os.LocaleListCompat wrap(android.os.LocaleList);
+ }
+
+ public final class MessageCompat {
+ method public static boolean isAsynchronous(android.os.Message);
+ method public static void setAsynchronous(android.os.Message, boolean);
+ }
+
+ public class OperationCanceledException extends java.lang.RuntimeException {
+ ctor public OperationCanceledException();
+ ctor public OperationCanceledException(String?);
+ }
+
+ public final class ParcelCompat {
+ method public static <T> Object![]? readArray(android.os.Parcel, ClassLoader?, Class<T!>);
+ method public static <T> java.util.ArrayList<T!>? readArrayList(android.os.Parcel, ClassLoader?, Class<? extends T>);
+ method public static boolean readBoolean(android.os.Parcel);
+ method public static <K, V> java.util.HashMap<K!,V!>? readHashMap(android.os.Parcel, ClassLoader?, Class<? extends K>, Class<? extends V>);
+ method public static <T> void readList(android.os.Parcel, java.util.List<? super T>, ClassLoader?, Class<T!>);
+ method public static <K, V> void readMap(android.os.Parcel, java.util.Map<? super K,? super V>, ClassLoader?, Class<K!>, Class<V!>);
+ method public static <T extends android.os.Parcelable> T? readParcelable(android.os.Parcel, ClassLoader?, Class<T!>);
+ method @Deprecated public static <T> T![]? readParcelableArray(android.os.Parcel, ClassLoader?, Class<T!>);
+ method public static <T> android.os.Parcelable![]? readParcelableArrayTyped(android.os.Parcel, ClassLoader?, Class<T!>);
+ method @RequiresApi(30) public static <T> android.os.Parcelable.Creator<T!>? readParcelableCreator(android.os.Parcel, ClassLoader?, Class<T!>);
+ method @RequiresApi(api=android.os.Build.VERSION_CODES.Q) public static <T> java.util.List<T!> readParcelableList(android.os.Parcel, java.util.List<T!>, ClassLoader?, Class<T!>);
+ method public static <T extends java.io.Serializable> T? readSerializable(android.os.Parcel, ClassLoader?, Class<T!>);
+ method public static <T> android.util.SparseArray<T!>? readSparseArray(android.os.Parcel, ClassLoader?, Class<? extends T>);
+ method public static void writeBoolean(android.os.Parcel, boolean);
+ }
+
+ @Deprecated public final class ParcelableCompat {
+ method @Deprecated public static <T> android.os.Parcelable.Creator<T!>! newCreator(androidx.core.os.ParcelableCompatCreatorCallbacks<T!>!);
+ }
+
+ @Deprecated public interface ParcelableCompatCreatorCallbacks<T> {
+ method @Deprecated public T! createFromParcel(android.os.Parcel!, ClassLoader!);
+ method @Deprecated public T![]! newArray(int);
+ }
+
+ public final class ProcessCompat {
+ method public static boolean isApplicationUid(int);
+ }
+
+ @Deprecated public final class TraceCompat {
+ method @Deprecated public static void beginAsyncSection(String, int);
+ method @Deprecated public static void beginSection(String);
+ method @Deprecated public static void endAsyncSection(String, int);
+ method @Deprecated public static void endSection();
+ method @Deprecated public static boolean isEnabled();
+ method @Deprecated public static void setCounter(String, int);
+ }
+
+ @RequiresApi(17) public class UserHandleCompat {
+ method public static android.os.UserHandle getUserHandleForUid(int);
+ }
+
+ public class UserManagerCompat {
+ method public static boolean isUserUnlocked(android.content.Context);
+ }
+
+}
+
+package androidx.core.provider {
+
+ public final class DocumentsContractCompat {
+ method public static android.net.Uri? buildChildDocumentsUri(String, String?);
+ method public static android.net.Uri? buildChildDocumentsUriUsingTree(android.net.Uri, String);
+ method public static android.net.Uri? buildDocumentUri(String, String);
+ method public static android.net.Uri? buildDocumentUriUsingTree(android.net.Uri, String);
+ method public static android.net.Uri? buildTreeDocumentUri(String, String);
+ method public static android.net.Uri? createDocument(android.content.ContentResolver, android.net.Uri, String, String) throws java.io.FileNotFoundException;
+ method public static String? getDocumentId(android.net.Uri);
+ method public static String? getTreeDocumentId(android.net.Uri);
+ method public static boolean isDocumentUri(android.content.Context, android.net.Uri?);
+ method public static boolean isTreeUri(android.net.Uri);
+ method public static boolean removeDocument(android.content.ContentResolver, android.net.Uri, android.net.Uri) throws java.io.FileNotFoundException;
+ method public static android.net.Uri? renameDocument(android.content.ContentResolver, android.net.Uri, String) throws java.io.FileNotFoundException;
+ }
+
+ public static final class DocumentsContractCompat.DocumentCompat {
+ field public static final int FLAG_VIRTUAL_DOCUMENT = 512; // 0x200
+ }
+
+ public final class FontRequest {
+ ctor public FontRequest(String, String, String, java.util.List<java.util.List<byte[]!>!>);
+ ctor public FontRequest(String, String, String, @ArrayRes int);
+ method public java.util.List<java.util.List<byte[]!>!>? getCertificates();
+ method @ArrayRes public int getCertificatesArrayResId();
+ method public String getProviderAuthority();
+ method public String getProviderPackage();
+ method public String getQuery();
+ }
+
+ public class FontsContractCompat {
+ method public static android.graphics.Typeface? buildTypeface(android.content.Context, android.os.CancellationSignal?, androidx.core.provider.FontsContractCompat.FontInfo![]);
+ method public static androidx.core.provider.FontsContractCompat.FontFamilyResult fetchFonts(android.content.Context, android.os.CancellationSignal?, androidx.core.provider.FontRequest) throws android.content.pm.PackageManager.NameNotFoundException;
+ method public static void requestFont(android.content.Context, androidx.core.provider.FontRequest, androidx.core.provider.FontsContractCompat.FontRequestCallback, android.os.Handler);
+ }
+
+ public static final class FontsContractCompat.Columns implements android.provider.BaseColumns {
+ ctor public FontsContractCompat.Columns();
+ field public static final String FILE_ID = "file_id";
+ field public static final String ITALIC = "font_italic";
+ field public static final String RESULT_CODE = "result_code";
+ field public static final int RESULT_CODE_FONT_NOT_FOUND = 1; // 0x1
+ field public static final int RESULT_CODE_FONT_UNAVAILABLE = 2; // 0x2
+ field public static final int RESULT_CODE_MALFORMED_QUERY = 3; // 0x3
+ field public static final int RESULT_CODE_OK = 0; // 0x0
+ field public static final String TTC_INDEX = "font_ttc_index";
+ field public static final String VARIATION_SETTINGS = "font_variation_settings";
+ field public static final String WEIGHT = "font_weight";
+ }
+
+ public static class FontsContractCompat.FontFamilyResult {
+ method public androidx.core.provider.FontsContractCompat.FontInfo![]! getFonts();
+ method public int getStatusCode();
+ field public static final int STATUS_OK = 0; // 0x0
+ field public static final int STATUS_UNEXPECTED_DATA_PROVIDED = 2; // 0x2
+ field public static final int STATUS_WRONG_CERTIFICATES = 1; // 0x1
+ }
+
+ public static class FontsContractCompat.FontInfo {
+ method public int getResultCode();
+ method @IntRange(from=0) public int getTtcIndex();
+ method public android.net.Uri getUri();
+ method @IntRange(from=1, to=1000) public int getWeight();
+ method public boolean isItalic();
+ }
+
+ public static class FontsContractCompat.FontRequestCallback {
+ ctor public FontsContractCompat.FontRequestCallback();
+ method public void onTypefaceRequestFailed(int);
+ method public void onTypefaceRetrieved(android.graphics.Typeface!);
+ field public static final int FAIL_REASON_FONT_LOAD_ERROR = -3; // 0xfffffffd
+ field public static final int FAIL_REASON_FONT_NOT_FOUND = 1; // 0x1
+ field public static final int FAIL_REASON_FONT_UNAVAILABLE = 2; // 0x2
+ field public static final int FAIL_REASON_MALFORMED_QUERY = 3; // 0x3
+ field public static final int FAIL_REASON_PROVIDER_NOT_FOUND = -1; // 0xffffffff
+ field public static final int FAIL_REASON_SECURITY_VIOLATION = -4; // 0xfffffffc
+ field public static final int FAIL_REASON_WRONG_CERTIFICATES = -2; // 0xfffffffe
+ }
+
+}
+
+package androidx.core.telephony {
+
+ @RequiresApi(22) public class SubscriptionManagerCompat {
+ method public static int getSlotIndex(int);
+ }
+
+ public class TelephonyManagerCompat {
+ method @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE) public static String? getImei(android.telephony.TelephonyManager);
+ method public static int getSubscriptionId(android.telephony.TelephonyManager);
+ }
+
+}
+
+package androidx.core.telephony.mbms {
+
+ public final class MbmsHelper {
+ method public static CharSequence? getBestNameForService(android.content.Context, android.telephony.mbms.ServiceInfo);
+ }
+
+}
+
+package androidx.core.text {
+
+ public final class BidiFormatter {
+ method public static androidx.core.text.BidiFormatter! getInstance();
+ method public static androidx.core.text.BidiFormatter! getInstance(boolean);
+ method public static androidx.core.text.BidiFormatter! getInstance(java.util.Locale!);
+ method public boolean getStereoReset();
+ method public boolean isRtl(String!);
+ method public boolean isRtl(CharSequence!);
+ method public boolean isRtlContext();
+ method public String! unicodeWrap(String!, androidx.core.text.TextDirectionHeuristicCompat!, boolean);
+ method public CharSequence! unicodeWrap(CharSequence!, androidx.core.text.TextDirectionHeuristicCompat!, boolean);
+ method public String! unicodeWrap(String!, androidx.core.text.TextDirectionHeuristicCompat!);
+ method public CharSequence! unicodeWrap(CharSequence!, androidx.core.text.TextDirectionHeuristicCompat!);
+ method public String! unicodeWrap(String!, boolean);
+ method public CharSequence! unicodeWrap(CharSequence!, boolean);
+ method public String! unicodeWrap(String!);
+ method public CharSequence! unicodeWrap(CharSequence!);
+ }
+
+ public static final class BidiFormatter.Builder {
+ ctor public BidiFormatter.Builder();
+ ctor public BidiFormatter.Builder(boolean);
+ ctor public BidiFormatter.Builder(java.util.Locale!);
+ method public androidx.core.text.BidiFormatter! build();
+ method public androidx.core.text.BidiFormatter.Builder! setTextDirectionHeuristic(androidx.core.text.TextDirectionHeuristicCompat!);
+ method public androidx.core.text.BidiFormatter.Builder! stereoReset(boolean);
+ }
+
+ public final class HtmlCompat {
+ method public static android.text.Spanned fromHtml(String, int);
+ method public static android.text.Spanned fromHtml(String, int, android.text.Html.ImageGetter?, android.text.Html.TagHandler?);
+ method public static String toHtml(android.text.Spanned, int);
+ field public static final int FROM_HTML_MODE_COMPACT = 63; // 0x3f
+ field public static final int FROM_HTML_MODE_LEGACY = 0; // 0x0
+ field public static final int FROM_HTML_OPTION_USE_CSS_COLORS = 256; // 0x100
+ field public static final int FROM_HTML_SEPARATOR_LINE_BREAK_BLOCKQUOTE = 32; // 0x20
+ field public static final int FROM_HTML_SEPARATOR_LINE_BREAK_DIV = 16; // 0x10
+ field public static final int FROM_HTML_SEPARATOR_LINE_BREAK_HEADING = 2; // 0x2
+ field public static final int FROM_HTML_SEPARATOR_LINE_BREAK_LIST = 8; // 0x8
+ field public static final int FROM_HTML_SEPARATOR_LINE_BREAK_LIST_ITEM = 4; // 0x4
+ field public static final int FROM_HTML_SEPARATOR_LINE_BREAK_PARAGRAPH = 1; // 0x1
+ field public static final int TO_HTML_PARAGRAPH_LINES_CONSECUTIVE = 0; // 0x0
+ field public static final int TO_HTML_PARAGRAPH_LINES_INDIVIDUAL = 1; // 0x1
+ }
+
+ public final class ICUCompat {
+ method public static String? maximizeAndGetScript(java.util.Locale);
+ }
+
+ public class PrecomputedTextCompat implements android.text.Spannable {
+ method public char charAt(int);
+ method public static androidx.core.text.PrecomputedTextCompat! create(CharSequence, androidx.core.text.PrecomputedTextCompat.Params);
+ method @IntRange(from=0) public int getParagraphCount();
+ method @IntRange(from=0) public int getParagraphEnd(@IntRange(from=0) int);
+ method @IntRange(from=0) public int getParagraphStart(@IntRange(from=0) int);
+ method public androidx.core.text.PrecomputedTextCompat.Params getParams();
+ method public int getSpanEnd(Object!);
+ method public int getSpanFlags(Object!);
+ method public int getSpanStart(Object!);
+ method public <T> T![]! getSpans(int, int, Class<T!>!);
+ method @UiThread public static java.util.concurrent.Future<androidx.core.text.PrecomputedTextCompat!>! getTextFuture(CharSequence, androidx.core.text.PrecomputedTextCompat.Params, java.util.concurrent.Executor?);
+ method public int length();
+ method public int nextSpanTransition(int, int, Class!);
+ method public void removeSpan(Object!);
+ method public void setSpan(Object!, int, int, int);
+ method public CharSequence! subSequence(int, int);
+ }
+
+ public static final class PrecomputedTextCompat.Params {
+ ctor @RequiresApi(28) public PrecomputedTextCompat.Params(android.text.PrecomputedText.Params);
+ method @RequiresApi(23) public int getBreakStrategy();
+ method @RequiresApi(23) public int getHyphenationFrequency();
+ method @RequiresApi(18) public android.text.TextDirectionHeuristic? getTextDirection();
+ method public android.text.TextPaint getTextPaint();
+ }
+
+ public static class PrecomputedTextCompat.Params.Builder {
+ ctor public PrecomputedTextCompat.Params.Builder(android.text.TextPaint);
+ method public androidx.core.text.PrecomputedTextCompat.Params build();
+ method @RequiresApi(23) public androidx.core.text.PrecomputedTextCompat.Params.Builder! setBreakStrategy(int);
+ method @RequiresApi(23) public androidx.core.text.PrecomputedTextCompat.Params.Builder! setHyphenationFrequency(int);
+ method @RequiresApi(18) public androidx.core.text.PrecomputedTextCompat.Params.Builder! setTextDirection(android.text.TextDirectionHeuristic);
+ }
+
+ public interface TextDirectionHeuristicCompat {
+ method public boolean isRtl(char[]!, int, int);
+ method public boolean isRtl(CharSequence!, int, int);
+ }
+
+ public final class TextDirectionHeuristicsCompat {
+ field public static final androidx.core.text.TextDirectionHeuristicCompat! ANYRTL_LTR;
+ field public static final androidx.core.text.TextDirectionHeuristicCompat! FIRSTSTRONG_LTR;
+ field public static final androidx.core.text.TextDirectionHeuristicCompat! FIRSTSTRONG_RTL;
+ field public static final androidx.core.text.TextDirectionHeuristicCompat! LOCALE;
+ field public static final androidx.core.text.TextDirectionHeuristicCompat! LTR;
+ field public static final androidx.core.text.TextDirectionHeuristicCompat! RTL;
+ }
+
+ public final class TextUtilsCompat {
+ method public static int getLayoutDirectionFromLocale(java.util.Locale?);
+ method public static String htmlEncode(String);
+ }
+
+}
+
+package androidx.core.text.util {
+
+ public final class LinkifyCompat {
+ method public static boolean addLinks(android.text.Spannable, int);
+ method public static boolean addLinks(android.widget.TextView, int);
+ method public static void addLinks(android.widget.TextView, java.util.regex.Pattern, String?);
+ method public static void addLinks(android.widget.TextView, java.util.regex.Pattern, String?, android.text.util.Linkify.MatchFilter?, android.text.util.Linkify.TransformFilter?);
+ method public static void addLinks(android.widget.TextView, java.util.regex.Pattern, String?, String![]?, android.text.util.Linkify.MatchFilter?, android.text.util.Linkify.TransformFilter?);
+ method public static boolean addLinks(android.text.Spannable, java.util.regex.Pattern, String?);
+ method public static boolean addLinks(android.text.Spannable, java.util.regex.Pattern, String?, android.text.util.Linkify.MatchFilter?, android.text.util.Linkify.TransformFilter?);
+ method public static boolean addLinks(android.text.Spannable, java.util.regex.Pattern, String?, String![]?, android.text.util.Linkify.MatchFilter?, android.text.util.Linkify.TransformFilter?);
+ }
+
+}
+
+package androidx.core.util {
+
+ public class AtomicFile {
+ ctor public AtomicFile(java.io.File);
+ method public void delete();
+ method public void failWrite(java.io.FileOutputStream?);
+ method public void finishWrite(java.io.FileOutputStream?);
+ method public java.io.File getBaseFile();
+ method public java.io.FileInputStream openRead() throws java.io.FileNotFoundException;
+ method public byte[] readFully() throws java.io.IOException;
+ method public java.io.FileOutputStream startWrite() throws java.io.IOException;
+ }
+
+ public interface Consumer<T> {
+ method public void accept(T!);
+ }
+
+ public class ObjectsCompat {
+ method public static boolean equals(Object?, Object?);
+ method public static int hash(java.lang.Object!...);
+ method public static int hashCode(Object?);
+ method public static <T> T requireNonNull(T?);
+ method public static <T> T requireNonNull(T?, String);
+ method public static String? toString(Object?, String?);
+ }
+
+ public class Pair<F, S> {
+ ctor public Pair(F!, S!);
+ method public static <A, B> androidx.core.util.Pair<A!,B!> create(A!, B!);
+ field public final F! first;
+ field public final S! second;
+ }
+
+ public final class PatternsCompat {
+ field public static final java.util.regex.Pattern DOMAIN_NAME;
+ field public static final java.util.regex.Pattern EMAIL_ADDRESS;
+ field public static final java.util.regex.Pattern IP_ADDRESS;
+ field public static final java.util.regex.Pattern WEB_URL;
+ }
+
+ public final class Pools {
+ }
+
+ public static interface Pools.Pool<T> {
+ method public T? acquire();
+ method public boolean release(T);
+ }
+
+ public static class Pools.SimplePool<T> implements androidx.core.util.Pools.Pool<T> {
+ ctor public Pools.SimplePool(int);
+ method public T! acquire();
+ method public boolean release(T);
+ }
+
+ public static class Pools.SynchronizedPool<T> extends androidx.core.util.Pools.SimplePool<T> {
+ ctor public Pools.SynchronizedPool(int);
+ }
+
+ public interface Predicate<T> {
+ method public default androidx.core.util.Predicate<T!>! and(androidx.core.util.Predicate<? super T>!);
+ method public static <T> androidx.core.util.Predicate<T!>! isEqual(Object!);
+ method public default androidx.core.util.Predicate<T!>! negate();
+ method public static <T> androidx.core.util.Predicate<T!>! not(androidx.core.util.Predicate<? super T>!);
+ method public default androidx.core.util.Predicate<T!>! or(androidx.core.util.Predicate<? super T>!);
+ method public boolean test(T!);
+ }
+
+ public final class SizeFCompat {
+ ctor public SizeFCompat(float, float);
+ method public float getHeight();
+ method public float getWidth();
+ method @RequiresApi(21) public android.util.SizeF toSizeF();
+ method @RequiresApi(21) public static androidx.core.util.SizeFCompat toSizeFCompat(android.util.SizeF);
+ }
+
+ public interface Supplier<T> {
+ method public T! get();
+ }
+
+}
+
+package androidx.core.view {
+
+ public class AccessibilityDelegateCompat {
+ ctor public AccessibilityDelegateCompat();
+ method public boolean dispatchPopulateAccessibilityEvent(android.view.View, android.view.accessibility.AccessibilityEvent);
+ method public androidx.core.view.accessibility.AccessibilityNodeProviderCompat? getAccessibilityNodeProvider(android.view.View);
+ method public void onInitializeAccessibilityEvent(android.view.View, android.view.accessibility.AccessibilityEvent);
+ method public void onInitializeAccessibilityNodeInfo(android.view.View, androidx.core.view.accessibility.AccessibilityNodeInfoCompat);
+ method public void onPopulateAccessibilityEvent(android.view.View, android.view.accessibility.AccessibilityEvent);
+ method public boolean onRequestSendAccessibilityEvent(android.view.ViewGroup, android.view.View, android.view.accessibility.AccessibilityEvent);
+ method public boolean performAccessibilityAction(android.view.View, int, android.os.Bundle?);
+ method public void sendAccessibilityEvent(android.view.View, int);
+ method public void sendAccessibilityEventUnchecked(android.view.View, android.view.accessibility.AccessibilityEvent);
+ }
+
+ public abstract class ActionProvider {
+ ctor public ActionProvider(android.content.Context);
+ method public android.content.Context getContext();
+ method public boolean hasSubMenu();
+ method public boolean isVisible();
+ method public abstract android.view.View onCreateActionView();
+ method public android.view.View onCreateActionView(android.view.MenuItem);
+ method public boolean onPerformDefaultAction();
+ method public void onPrepareSubMenu(android.view.SubMenu);
+ method public boolean overridesItemVisibility();
+ method public void refreshVisibility();
+ method public void setVisibilityListener(androidx.core.view.ActionProvider.VisibilityListener?);
+ }
+
+ public static interface ActionProvider.VisibilityListener {
+ method public void onActionProviderVisibilityChanged(boolean);
+ }
+
+ public final class ContentInfoCompat {
+ method public android.content.ClipData getClip();
+ method public android.os.Bundle? getExtras();
+ method public int getFlags();
+ method public android.net.Uri? getLinkUri();
+ method public int getSource();
+ method 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 {
+ ctor public ContentInfoCompat.Builder(androidx.core.view.ContentInfoCompat);
+ ctor public ContentInfoCompat.Builder(android.content.ClipData, int);
+ method public androidx.core.view.ContentInfoCompat build();
+ method public androidx.core.view.ContentInfoCompat.Builder setClip(android.content.ClipData);
+ method public androidx.core.view.ContentInfoCompat.Builder setExtras(android.os.Bundle?);
+ method public androidx.core.view.ContentInfoCompat.Builder setFlags(int);
+ method public androidx.core.view.ContentInfoCompat.Builder setLinkUri(android.net.Uri?);
+ method public androidx.core.view.ContentInfoCompat.Builder setSource(int);
+ }
+
+ public final class DisplayCompat {
+ method public static androidx.core.view.DisplayCompat.ModeCompat getMode(android.content.Context, android.view.Display);
+ method public static androidx.core.view.DisplayCompat.ModeCompat![] getSupportedModes(android.content.Context, android.view.Display);
+ }
+
+ public static final class DisplayCompat.ModeCompat {
+ method public int getPhysicalHeight();
+ method public int getPhysicalWidth();
+ method @Deprecated public boolean isNative();
+ method @RequiresApi(android.os.Build.VERSION_CODES.M) public android.view.Display.Mode? toMode();
+ }
+
+ public final class DisplayCutoutCompat {
+ ctor public DisplayCutoutCompat(android.graphics.Rect?, java.util.List<android.graphics.Rect!>?);
+ ctor public DisplayCutoutCompat(androidx.core.graphics.Insets, android.graphics.Rect?, android.graphics.Rect?, android.graphics.Rect?, android.graphics.Rect?, androidx.core.graphics.Insets);
+ method public java.util.List<android.graphics.Rect!> getBoundingRects();
+ method public int getSafeInsetBottom();
+ method public int getSafeInsetLeft();
+ method public int getSafeInsetRight();
+ method public int getSafeInsetTop();
+ method public androidx.core.graphics.Insets getWaterfallInsets();
+ }
+
+ public final class DragAndDropPermissionsCompat {
+ method public void release();
+ }
+
+ public class DragStartHelper {
+ ctor public DragStartHelper(android.view.View, androidx.core.view.DragStartHelper.OnDragStartListener);
+ method public void attach();
+ method public void detach();
+ method public void getTouchPosition(android.graphics.Point);
+ method public boolean onLongClick(android.view.View);
+ method public boolean onTouch(android.view.View, android.view.MotionEvent);
+ }
+
+ public static interface DragStartHelper.OnDragStartListener {
+ method public boolean onDragStart(android.view.View, androidx.core.view.DragStartHelper);
+ }
+
+ public final class GestureDetectorCompat {
+ ctor public GestureDetectorCompat(android.content.Context, android.view.GestureDetector.OnGestureListener);
+ ctor public GestureDetectorCompat(android.content.Context, android.view.GestureDetector.OnGestureListener, android.os.Handler?);
+ method public boolean isLongpressEnabled();
+ method public boolean onTouchEvent(android.view.MotionEvent);
+ method public void setIsLongpressEnabled(boolean);
+ method public void setOnDoubleTapListener(android.view.GestureDetector.OnDoubleTapListener?);
+ }
+
+ public final class GravityCompat {
+ method public static void apply(int, int, int, android.graphics.Rect, android.graphics.Rect, int);
+ method public static void apply(int, int, int, android.graphics.Rect, int, int, android.graphics.Rect, int);
+ method public static void applyDisplay(int, android.graphics.Rect, android.graphics.Rect, int);
+ method public static int getAbsoluteGravity(int, int);
+ field public static final int END = 8388613; // 0x800005
+ field public static final int RELATIVE_HORIZONTAL_GRAVITY_MASK = 8388615; // 0x800007
+ field public static final int RELATIVE_LAYOUT_DIRECTION = 8388608; // 0x800000
+ field public static final int START = 8388611; // 0x800003
+ }
+
+ public final class InputDeviceCompat {
+ field public static final int SOURCE_ANY = -256; // 0xffffff00
+ field public static final int SOURCE_CLASS_BUTTON = 1; // 0x1
+ field public static final int SOURCE_CLASS_JOYSTICK = 16; // 0x10
+ field public static final int SOURCE_CLASS_MASK = 255; // 0xff
+ field public static final int SOURCE_CLASS_NONE = 0; // 0x0
+ field public static final int SOURCE_CLASS_POINTER = 2; // 0x2
+ field public static final int SOURCE_CLASS_POSITION = 8; // 0x8
+ field public static final int SOURCE_CLASS_TRACKBALL = 4; // 0x4
+ field public static final int SOURCE_DPAD = 513; // 0x201
+ field public static final int SOURCE_GAMEPAD = 1025; // 0x401
+ field public static final int SOURCE_HDMI = 33554433; // 0x2000001
+ field public static final int SOURCE_JOYSTICK = 16777232; // 0x1000010
+ field public static final int SOURCE_KEYBOARD = 257; // 0x101
+ field public static final int SOURCE_MOUSE = 8194; // 0x2002
+ field public static final int SOURCE_ROTARY_ENCODER = 4194304; // 0x400000
+ field public static final int SOURCE_STYLUS = 16386; // 0x4002
+ field public static final int SOURCE_TOUCHPAD = 1048584; // 0x100008
+ field public static final int SOURCE_TOUCHSCREEN = 4098; // 0x1002
+ field public static final int SOURCE_TOUCH_NAVIGATION = 2097152; // 0x200000
+ field public static final int SOURCE_TRACKBALL = 65540; // 0x10004
+ field public static final int SOURCE_UNKNOWN = 0; // 0x0
+ }
+
+ public final class LayoutInflaterCompat {
+ method @Deprecated public static androidx.core.view.LayoutInflaterFactory! getFactory(android.view.LayoutInflater!);
+ method @Deprecated public static void setFactory(android.view.LayoutInflater, androidx.core.view.LayoutInflaterFactory);
+ method public static void setFactory2(android.view.LayoutInflater, android.view.LayoutInflater.Factory2);
+ }
+
+ @Deprecated public interface LayoutInflaterFactory {
+ method @Deprecated public android.view.View! onCreateView(android.view.View!, String!, android.content.Context!, android.util.AttributeSet!);
+ }
+
+ public final class MarginLayoutParamsCompat {
+ method public static int getLayoutDirection(android.view.ViewGroup.MarginLayoutParams);
+ method public static int getMarginEnd(android.view.ViewGroup.MarginLayoutParams);
+ method public static int getMarginStart(android.view.ViewGroup.MarginLayoutParams);
+ method public static boolean isMarginRelative(android.view.ViewGroup.MarginLayoutParams);
+ method public static void resolveLayoutDirection(android.view.ViewGroup.MarginLayoutParams, int);
+ method public static void setLayoutDirection(android.view.ViewGroup.MarginLayoutParams, int);
+ method public static void setMarginEnd(android.view.ViewGroup.MarginLayoutParams, int);
+ method public static void setMarginStart(android.view.ViewGroup.MarginLayoutParams, int);
+ }
+
+ public final class MenuCompat {
+ method public static void setGroupDividerEnabled(android.view.Menu, boolean);
+ method @Deprecated public static void setShowAsAction(android.view.MenuItem!, int);
+ }
+
+ public interface MenuHost {
+ method public void addMenuProvider(androidx.core.view.MenuProvider);
+ method public void addMenuProvider(androidx.core.view.MenuProvider, androidx.lifecycle.LifecycleOwner);
+ method public void addMenuProvider(androidx.core.view.MenuProvider, androidx.lifecycle.LifecycleOwner, androidx.lifecycle.Lifecycle.State);
+ method public void invalidateMenu();
+ method public void removeMenuProvider(androidx.core.view.MenuProvider);
+ }
+
+ public class MenuHostHelper {
+ ctor public MenuHostHelper(Runnable);
+ method public void addMenuProvider(androidx.core.view.MenuProvider);
+ method public void addMenuProvider(androidx.core.view.MenuProvider, androidx.lifecycle.LifecycleOwner);
+ method public void addMenuProvider(androidx.core.view.MenuProvider, androidx.lifecycle.LifecycleOwner, androidx.lifecycle.Lifecycle.State);
+ method public void onCreateMenu(android.view.Menu, android.view.MenuInflater);
+ method public void onMenuClosed(android.view.Menu);
+ method public boolean onMenuItemSelected(android.view.MenuItem);
+ method public void onPrepareMenu(android.view.Menu);
+ method public void removeMenuProvider(androidx.core.view.MenuProvider);
+ }
+
+ public final class MenuItemCompat {
+ method @Deprecated public static boolean collapseActionView(android.view.MenuItem!);
+ method @Deprecated public static boolean expandActionView(android.view.MenuItem!);
+ method public static androidx.core.view.ActionProvider? getActionProvider(android.view.MenuItem);
+ method @Deprecated public static android.view.View! getActionView(android.view.MenuItem!);
+ method public static int getAlphabeticModifiers(android.view.MenuItem);
+ method public static CharSequence? getContentDescription(android.view.MenuItem);
+ method public static android.content.res.ColorStateList? getIconTintList(android.view.MenuItem);
+ method public static android.graphics.PorterDuff.Mode? getIconTintMode(android.view.MenuItem);
+ method public static int getNumericModifiers(android.view.MenuItem);
+ method public static CharSequence? getTooltipText(android.view.MenuItem);
+ method @Deprecated public static boolean isActionViewExpanded(android.view.MenuItem!);
+ method public static android.view.MenuItem? setActionProvider(android.view.MenuItem, androidx.core.view.ActionProvider?);
+ method @Deprecated public static android.view.MenuItem! setActionView(android.view.MenuItem!, android.view.View!);
+ method @Deprecated public static android.view.MenuItem! setActionView(android.view.MenuItem!, int);
+ method public static void setAlphabeticShortcut(android.view.MenuItem, char, int);
+ method public static void setContentDescription(android.view.MenuItem, CharSequence?);
+ method public static void setIconTintList(android.view.MenuItem, android.content.res.ColorStateList?);
+ method public static void setIconTintMode(android.view.MenuItem, android.graphics.PorterDuff.Mode?);
+ method public static void setNumericShortcut(android.view.MenuItem, char, int);
+ method @Deprecated public static android.view.MenuItem! setOnActionExpandListener(android.view.MenuItem!, androidx.core.view.MenuItemCompat.OnActionExpandListener!);
+ method public static void setShortcut(android.view.MenuItem, char, char, int, int);
+ method @Deprecated public static void setShowAsAction(android.view.MenuItem!, int);
+ method public static void setTooltipText(android.view.MenuItem, CharSequence?);
+ field @Deprecated public static final int SHOW_AS_ACTION_ALWAYS = 2; // 0x2
+ field @Deprecated public static final int SHOW_AS_ACTION_COLLAPSE_ACTION_VIEW = 8; // 0x8
+ field @Deprecated public static final int SHOW_AS_ACTION_IF_ROOM = 1; // 0x1
+ field @Deprecated public static final int SHOW_AS_ACTION_NEVER = 0; // 0x0
+ field @Deprecated public static final int SHOW_AS_ACTION_WITH_TEXT = 4; // 0x4
+ }
+
+ @Deprecated public static interface MenuItemCompat.OnActionExpandListener {
+ method @Deprecated public boolean onMenuItemActionCollapse(android.view.MenuItem!);
+ method @Deprecated public boolean onMenuItemActionExpand(android.view.MenuItem!);
+ }
+
+ public interface MenuProvider {
+ method public void onCreateMenu(android.view.Menu, android.view.MenuInflater);
+ method public default void onMenuClosed(android.view.Menu);
+ method public boolean onMenuItemSelected(android.view.MenuItem);
+ method public default void onPrepareMenu(android.view.Menu);
+ }
+
+ public final class MotionEventCompat {
+ method @Deprecated public static int findPointerIndex(android.view.MotionEvent!, int);
+ method @Deprecated public static int getActionIndex(android.view.MotionEvent!);
+ method @Deprecated public static int getActionMasked(android.view.MotionEvent!);
+ method @Deprecated public static float getAxisValue(android.view.MotionEvent!, int);
+ method @Deprecated public static float getAxisValue(android.view.MotionEvent!, int, int);
+ method @Deprecated public static int getButtonState(android.view.MotionEvent!);
+ method @Deprecated public static int getPointerCount(android.view.MotionEvent!);
+ method @Deprecated public static int getPointerId(android.view.MotionEvent!, int);
+ method @Deprecated public static int getSource(android.view.MotionEvent!);
+ method @Deprecated public static float getX(android.view.MotionEvent!, int);
+ method @Deprecated public static float getY(android.view.MotionEvent!, int);
+ method public static boolean isFromSource(android.view.MotionEvent, int);
+ field @Deprecated public static final int ACTION_HOVER_ENTER = 9; // 0x9
+ field @Deprecated public static final int ACTION_HOVER_EXIT = 10; // 0xa
+ field @Deprecated public static final int ACTION_HOVER_MOVE = 7; // 0x7
+ field @Deprecated public static final int ACTION_MASK = 255; // 0xff
+ field @Deprecated public static final int ACTION_POINTER_DOWN = 5; // 0x5
+ field @Deprecated public static final int ACTION_POINTER_INDEX_MASK = 65280; // 0xff00
+ field @Deprecated public static final int ACTION_POINTER_INDEX_SHIFT = 8; // 0x8
+ field @Deprecated public static final int ACTION_POINTER_UP = 6; // 0x6
+ field @Deprecated public static final int ACTION_SCROLL = 8; // 0x8
+ field @Deprecated public static final int AXIS_BRAKE = 23; // 0x17
+ field @Deprecated public static final int AXIS_DISTANCE = 24; // 0x18
+ field @Deprecated public static final int AXIS_GAS = 22; // 0x16
+ field @Deprecated public static final int AXIS_GENERIC_1 = 32; // 0x20
+ field @Deprecated public static final int AXIS_GENERIC_10 = 41; // 0x29
+ field @Deprecated public static final int AXIS_GENERIC_11 = 42; // 0x2a
+ field @Deprecated public static final int AXIS_GENERIC_12 = 43; // 0x2b
+ field @Deprecated public static final int AXIS_GENERIC_13 = 44; // 0x2c
+ field @Deprecated public static final int AXIS_GENERIC_14 = 45; // 0x2d
+ field @Deprecated public static final int AXIS_GENERIC_15 = 46; // 0x2e
+ field @Deprecated public static final int AXIS_GENERIC_16 = 47; // 0x2f
+ field @Deprecated public static final int AXIS_GENERIC_2 = 33; // 0x21
+ field @Deprecated public static final int AXIS_GENERIC_3 = 34; // 0x22
+ field @Deprecated public static final int AXIS_GENERIC_4 = 35; // 0x23
+ field @Deprecated public static final int AXIS_GENERIC_5 = 36; // 0x24
+ field @Deprecated public static final int AXIS_GENERIC_6 = 37; // 0x25
+ field @Deprecated public static final int AXIS_GENERIC_7 = 38; // 0x26
+ field @Deprecated public static final int AXIS_GENERIC_8 = 39; // 0x27
+ field @Deprecated public static final int AXIS_GENERIC_9 = 40; // 0x28
+ field @Deprecated public static final int AXIS_HAT_X = 15; // 0xf
+ field @Deprecated public static final int AXIS_HAT_Y = 16; // 0x10
+ field @Deprecated public static final int AXIS_HSCROLL = 10; // 0xa
+ field @Deprecated public static final int AXIS_LTRIGGER = 17; // 0x11
+ field @Deprecated public static final int AXIS_ORIENTATION = 8; // 0x8
+ field @Deprecated public static final int AXIS_PRESSURE = 2; // 0x2
+ field public static final int AXIS_RELATIVE_X = 27; // 0x1b
+ field public static final int AXIS_RELATIVE_Y = 28; // 0x1c
+ field @Deprecated public static final int AXIS_RTRIGGER = 18; // 0x12
+ field @Deprecated public static final int AXIS_RUDDER = 20; // 0x14
+ field @Deprecated public static final int AXIS_RX = 12; // 0xc
+ field @Deprecated public static final int AXIS_RY = 13; // 0xd
+ field @Deprecated public static final int AXIS_RZ = 14; // 0xe
+ field public static final int AXIS_SCROLL = 26; // 0x1a
+ field @Deprecated public static final int AXIS_SIZE = 3; // 0x3
+ field @Deprecated public static final int AXIS_THROTTLE = 19; // 0x13
+ field @Deprecated public static final int AXIS_TILT = 25; // 0x19
+ field @Deprecated public static final int AXIS_TOOL_MAJOR = 6; // 0x6
+ field @Deprecated public static final int AXIS_TOOL_MINOR = 7; // 0x7
+ field @Deprecated public static final int AXIS_TOUCH_MAJOR = 4; // 0x4
+ field @Deprecated public static final int AXIS_TOUCH_MINOR = 5; // 0x5
+ field @Deprecated public static final int AXIS_VSCROLL = 9; // 0x9
+ field @Deprecated public static final int AXIS_WHEEL = 21; // 0x15
+ field @Deprecated public static final int AXIS_X = 0; // 0x0
+ field @Deprecated public static final int AXIS_Y = 1; // 0x1
+ field @Deprecated public static final int AXIS_Z = 11; // 0xb
+ field @Deprecated public static final int BUTTON_PRIMARY = 1; // 0x1
+ }
+
+ public interface NestedScrollingChild {
+ method public boolean dispatchNestedFling(float, float, boolean);
+ method public boolean dispatchNestedPreFling(float, float);
+ method public boolean dispatchNestedPreScroll(int, int, int[]?, int[]?);
+ method public boolean dispatchNestedScroll(int, int, int, int, int[]?);
+ method public boolean hasNestedScrollingParent();
+ method public boolean isNestedScrollingEnabled();
+ method public void setNestedScrollingEnabled(boolean);
+ method public boolean startNestedScroll(int);
+ method public void stopNestedScroll();
+ }
+
+ public interface NestedScrollingChild2 extends androidx.core.view.NestedScrollingChild {
+ method public boolean dispatchNestedPreScroll(int, int, int[]?, int[]?, int);
+ method public boolean dispatchNestedScroll(int, int, int, int, int[]?, int);
+ method public boolean hasNestedScrollingParent(int);
+ method public boolean startNestedScroll(int, int);
+ method public void stopNestedScroll(int);
+ }
+
+ public interface NestedScrollingChild3 extends androidx.core.view.NestedScrollingChild2 {
+ method public void dispatchNestedScroll(int, int, int, int, int[]?, int, int[]);
+ }
+
+ public class NestedScrollingChildHelper {
+ ctor public NestedScrollingChildHelper(android.view.View);
+ method public boolean dispatchNestedFling(float, float, boolean);
+ method public boolean dispatchNestedPreFling(float, float);
+ method public boolean dispatchNestedPreScroll(int, int, int[]?, int[]?);
+ method public boolean dispatchNestedPreScroll(int, int, int[]?, int[]?, int);
+ method public boolean dispatchNestedScroll(int, int, int, int, int[]?);
+ method public boolean dispatchNestedScroll(int, int, int, int, int[]?, int);
+ method public void dispatchNestedScroll(int, int, int, int, int[]?, int, int[]?);
+ method public boolean hasNestedScrollingParent();
+ method public boolean hasNestedScrollingParent(int);
+ method public boolean isNestedScrollingEnabled();
+ method public void onDetachedFromWindow();
+ method public void onStopNestedScroll(android.view.View);
+ method public void setNestedScrollingEnabled(boolean);
+ method public boolean startNestedScroll(int);
+ method public boolean startNestedScroll(int, int);
+ method public void stopNestedScroll();
+ method public void stopNestedScroll(int);
+ }
+
+ public interface NestedScrollingParent {
+ method public int getNestedScrollAxes();
+ method public boolean onNestedFling(android.view.View, float, float, boolean);
+ method public boolean onNestedPreFling(android.view.View, float, float);
+ method public void onNestedPreScroll(android.view.View, int, int, int[]);
+ method public void onNestedScroll(android.view.View, int, int, int, int);
+ method public void onNestedScrollAccepted(android.view.View, android.view.View, int);
+ method public boolean onStartNestedScroll(android.view.View, android.view.View, int);
+ method public void onStopNestedScroll(android.view.View);
+ }
+
+ public interface NestedScrollingParent2 extends androidx.core.view.NestedScrollingParent {
+ method public void onNestedPreScroll(android.view.View, int, int, int[], int);
+ method public void onNestedScroll(android.view.View, int, int, int, int, int);
+ method public void onNestedScrollAccepted(android.view.View, android.view.View, int, int);
+ method public boolean onStartNestedScroll(android.view.View, android.view.View, int, int);
+ method public void onStopNestedScroll(android.view.View, int);
+ }
+
+ public interface NestedScrollingParent3 extends androidx.core.view.NestedScrollingParent2 {
+ method public void onNestedScroll(android.view.View, int, int, int, int, int, int[]);
+ }
+
+ public class NestedScrollingParentHelper {
+ ctor public NestedScrollingParentHelper(android.view.ViewGroup);
+ method public int getNestedScrollAxes();
+ method public void onNestedScrollAccepted(android.view.View, android.view.View, int);
+ method public void onNestedScrollAccepted(android.view.View, android.view.View, int, int);
+ method public void onStopNestedScroll(android.view.View);
+ method public void onStopNestedScroll(android.view.View, int);
+ }
+
+ public interface OnApplyWindowInsetsListener {
+ method public androidx.core.view.WindowInsetsCompat onApplyWindowInsets(android.view.View, androidx.core.view.WindowInsetsCompat);
+ }
+
+ public interface OnReceiveContentListener {
+ method public androidx.core.view.ContentInfoCompat? onReceiveContent(android.view.View, androidx.core.view.ContentInfoCompat);
+ }
+
+ public interface OnReceiveContentViewBehavior {
+ method public androidx.core.view.ContentInfoCompat? onReceiveContent(androidx.core.view.ContentInfoCompat);
+ }
+
+ public final class OneShotPreDrawListener implements android.view.View.OnAttachStateChangeListener android.view.ViewTreeObserver.OnPreDrawListener {
+ method public static androidx.core.view.OneShotPreDrawListener add(android.view.View, Runnable);
+ method public boolean onPreDraw();
+ method public void onViewAttachedToWindow(android.view.View);
+ method public void onViewDetachedFromWindow(android.view.View);
+ method public void removeListener();
+ }
+
+ public final class PointerIconCompat {
+ method public static androidx.core.view.PointerIconCompat create(android.graphics.Bitmap, float, float);
+ method public static androidx.core.view.PointerIconCompat getSystemIcon(android.content.Context, int);
+ method public static androidx.core.view.PointerIconCompat load(android.content.res.Resources, int);
+ field public static final int TYPE_ALIAS = 1010; // 0x3f2
+ field public static final int TYPE_ALL_SCROLL = 1013; // 0x3f5
+ field public static final int TYPE_ARROW = 1000; // 0x3e8
+ field public static final int TYPE_CELL = 1006; // 0x3ee
+ field public static final int TYPE_CONTEXT_MENU = 1001; // 0x3e9
+ field public static final int TYPE_COPY = 1011; // 0x3f3
+ field public static final int TYPE_CROSSHAIR = 1007; // 0x3ef
+ field public static final int TYPE_DEFAULT = 1000; // 0x3e8
+ field public static final int TYPE_GRAB = 1020; // 0x3fc
+ field public static final int TYPE_GRABBING = 1021; // 0x3fd
+ field public static final int TYPE_HAND = 1002; // 0x3ea
+ field public static final int TYPE_HELP = 1003; // 0x3eb
+ field public static final int TYPE_HORIZONTAL_DOUBLE_ARROW = 1014; // 0x3f6
+ field public static final int TYPE_NO_DROP = 1012; // 0x3f4
+ field public static final int TYPE_NULL = 0; // 0x0
+ field public static final int TYPE_TEXT = 1008; // 0x3f0
+ field public static final int TYPE_TOP_LEFT_DIAGONAL_DOUBLE_ARROW = 1017; // 0x3f9
+ field public static final int TYPE_TOP_RIGHT_DIAGONAL_DOUBLE_ARROW = 1016; // 0x3f8
+ field public static final int TYPE_VERTICAL_DOUBLE_ARROW = 1015; // 0x3f7
+ field public static final int TYPE_VERTICAL_TEXT = 1009; // 0x3f1
+ field public static final int TYPE_WAIT = 1004; // 0x3ec
+ field public static final int TYPE_ZOOM_IN = 1018; // 0x3fa
+ field public static final int TYPE_ZOOM_OUT = 1019; // 0x3fb
+ }
+
+ public final class ScaleGestureDetectorCompat {
+ method @Deprecated public static boolean isQuickScaleEnabled(Object!);
+ method public static boolean isQuickScaleEnabled(android.view.ScaleGestureDetector);
+ method @Deprecated public static void setQuickScaleEnabled(Object!, boolean);
+ method public static void setQuickScaleEnabled(android.view.ScaleGestureDetector, boolean);
+ }
+
+ public interface ScrollingView {
+ method public int computeHorizontalScrollExtent();
+ method public int computeHorizontalScrollOffset();
+ method public int computeHorizontalScrollRange();
+ method public int computeVerticalScrollExtent();
+ method public int computeVerticalScrollOffset();
+ method public int computeVerticalScrollRange();
+ }
+
+ public interface TintableBackgroundView {
+ method public android.content.res.ColorStateList? getSupportBackgroundTintList();
+ method public android.graphics.PorterDuff.Mode? getSupportBackgroundTintMode();
+ method public void setSupportBackgroundTintList(android.content.res.ColorStateList?);
+ method public void setSupportBackgroundTintMode(android.graphics.PorterDuff.Mode?);
+ }
+
+ @Deprecated public final class VelocityTrackerCompat {
+ method @Deprecated public static float getXVelocity(android.view.VelocityTracker!, int);
+ method @Deprecated public static float getYVelocity(android.view.VelocityTracker!, int);
+ }
+
+ public class ViewCompat {
+ ctor @Deprecated protected ViewCompat();
+ method public static int addAccessibilityAction(android.view.View, CharSequence, androidx.core.view.accessibility.AccessibilityViewCommand);
+ method public static void addKeyboardNavigationClusters(android.view.View, java.util.Collection<android.view.View!>, int);
+ method public static void addOnUnhandledKeyEventListener(android.view.View, androidx.core.view.ViewCompat.OnUnhandledKeyEventListenerCompat);
+ method public static androidx.core.view.ViewPropertyAnimatorCompat animate(android.view.View);
+ method @Deprecated public static boolean canScrollHorizontally(android.view.View!, int);
+ method @Deprecated public static boolean canScrollVertically(android.view.View!, int);
+ method public static void cancelDragAndDrop(android.view.View);
+ method @Deprecated public static int combineMeasuredStates(int, int);
+ method public static androidx.core.view.WindowInsetsCompat computeSystemWindowInsets(android.view.View, androidx.core.view.WindowInsetsCompat, android.graphics.Rect);
+ method public static androidx.core.view.WindowInsetsCompat dispatchApplyWindowInsets(android.view.View, androidx.core.view.WindowInsetsCompat);
+ method public static void dispatchFinishTemporaryDetach(android.view.View);
+ method public static boolean dispatchNestedFling(android.view.View, float, float, boolean);
+ method public static boolean dispatchNestedPreFling(android.view.View, float, float);
+ method public static boolean dispatchNestedPreScroll(android.view.View, int, int, int[]?, int[]?);
+ method public static boolean dispatchNestedPreScroll(android.view.View, int, int, int[]?, int[]?, int);
+ method public static boolean dispatchNestedScroll(android.view.View, int, int, int, int, int[]?);
+ method public static void dispatchNestedScroll(android.view.View, int, int, int, int, int[]?, int, int[]);
+ method public static boolean dispatchNestedScroll(android.view.View, int, int, int, int, int[]?, int);
+ method public static void dispatchStartTemporaryDetach(android.view.View);
+ method public static void enableAccessibleClickableSpanSupport(android.view.View);
+ method public static int generateViewId();
+ method public static androidx.core.view.AccessibilityDelegateCompat? getAccessibilityDelegate(android.view.View);
+ method public static int getAccessibilityLiveRegion(android.view.View);
+ method public static androidx.core.view.accessibility.AccessibilityNodeProviderCompat? getAccessibilityNodeProvider(android.view.View);
+ method @UiThread public static CharSequence? getAccessibilityPaneTitle(android.view.View);
+ method @Deprecated public static float getAlpha(android.view.View!);
+ method public static android.content.res.ColorStateList? getBackgroundTintList(android.view.View);
+ method public static android.graphics.PorterDuff.Mode? getBackgroundTintMode(android.view.View);
+ method public static android.graphics.Rect? getClipBounds(android.view.View);
+ method public static android.view.Display? getDisplay(android.view.View);
+ method public static float getElevation(android.view.View);
+ method public static boolean getFitsSystemWindows(android.view.View);
+ method public static int getImportantForAccessibility(android.view.View);
+ method public static int getImportantForAutofill(android.view.View);
+ method public static int getLabelFor(android.view.View);
+ method @Deprecated public static int getLayerType(android.view.View!);
+ method public static int getLayoutDirection(android.view.View);
+ method @Deprecated public static android.graphics.Matrix? getMatrix(android.view.View!);
+ method @Deprecated public static int getMeasuredHeightAndState(android.view.View!);
+ method @Deprecated public static int getMeasuredState(android.view.View!);
+ method @Deprecated public static int getMeasuredWidthAndState(android.view.View!);
+ method public static int getMinimumHeight(android.view.View);
+ method public static int getMinimumWidth(android.view.View);
+ method public static int getNextClusterForwardId(android.view.View);
+ method public static String![]? getOnReceiveContentMimeTypes(android.view.View);
+ method @Deprecated public static int getOverScrollMode(android.view.View!);
+ method @Px public static int getPaddingEnd(android.view.View);
+ method @Px public static int getPaddingStart(android.view.View);
+ method public static android.view.ViewParent? getParentForAccessibility(android.view.View);
+ method @Deprecated public static float getPivotX(android.view.View!);
+ method @Deprecated public static float getPivotY(android.view.View!);
+ method public static androidx.core.view.WindowInsetsCompat? getRootWindowInsets(android.view.View);
+ method @Deprecated public static float getRotation(android.view.View!);
+ method @Deprecated public static float getRotationX(android.view.View!);
+ method @Deprecated public static float getRotationY(android.view.View!);
+ method @Deprecated public static float getScaleX(android.view.View!);
+ method @Deprecated public static float getScaleY(android.view.View!);
+ method public static int getScrollIndicators(android.view.View);
+ method @UiThread public static CharSequence? getStateDescription(android.view.View);
+ method public static java.util.List<android.graphics.Rect!> getSystemGestureExclusionRects(android.view.View);
+ method public static String? getTransitionName(android.view.View);
+ method @Deprecated public static float getTranslationX(android.view.View!);
+ method @Deprecated public static float getTranslationY(android.view.View!);
+ method public static float getTranslationZ(android.view.View);
+ method @Deprecated public static androidx.core.view.WindowInsetsControllerCompat? getWindowInsetsController(android.view.View);
+ method @Deprecated public static int getWindowSystemUiVisibility(android.view.View);
+ method @Deprecated public static float getX(android.view.View!);
+ method @Deprecated public static float getY(android.view.View!);
+ method public static float getZ(android.view.View);
+ method public static boolean hasAccessibilityDelegate(android.view.View);
+ method public static boolean hasExplicitFocusable(android.view.View);
+ method public static boolean hasNestedScrollingParent(android.view.View);
+ method public static boolean hasNestedScrollingParent(android.view.View, int);
+ method public static boolean hasOnClickListeners(android.view.View);
+ method public static boolean hasOverlappingRendering(android.view.View);
+ method public static boolean hasTransientState(android.view.View);
+ method @UiThread public static boolean isAccessibilityHeading(android.view.View);
+ method public static boolean isAttachedToWindow(android.view.View);
+ method public static boolean isFocusedByDefault(android.view.View);
+ method public static boolean isImportantForAccessibility(android.view.View);
+ method public static boolean isImportantForAutofill(android.view.View);
+ method public static boolean isInLayout(android.view.View);
+ method public static boolean isKeyboardNavigationCluster(android.view.View);
+ method public static boolean isLaidOut(android.view.View);
+ method public static boolean isLayoutDirectionResolved(android.view.View);
+ method public static boolean isNestedScrollingEnabled(android.view.View);
+ method @Deprecated public static boolean isOpaque(android.view.View!);
+ method public static boolean isPaddingRelative(android.view.View);
+ method @UiThread public static boolean isScreenReaderFocusable(android.view.View);
+ method @Deprecated public static void jumpDrawablesToCurrentState(android.view.View!);
+ method public static android.view.View? keyboardNavigationClusterSearch(android.view.View, android.view.View?, int);
+ method public static void offsetLeftAndRight(android.view.View, int);
+ method public static void offsetTopAndBottom(android.view.View, int);
+ method public static androidx.core.view.WindowInsetsCompat onApplyWindowInsets(android.view.View, androidx.core.view.WindowInsetsCompat);
+ method @Deprecated public static void onInitializeAccessibilityEvent(android.view.View!, android.view.accessibility.AccessibilityEvent!);
+ method public static void onInitializeAccessibilityNodeInfo(android.view.View, androidx.core.view.accessibility.AccessibilityNodeInfoCompat);
+ method @Deprecated public static void onPopulateAccessibilityEvent(android.view.View!, android.view.accessibility.AccessibilityEvent!);
+ method public static boolean performAccessibilityAction(android.view.View, int, android.os.Bundle?);
+ method public static androidx.core.view.ContentInfoCompat? performReceiveContent(android.view.View, androidx.core.view.ContentInfoCompat);
+ method public static void postInvalidateOnAnimation(android.view.View);
+ method public static void postInvalidateOnAnimation(android.view.View, int, int, int, int);
+ method public static void postOnAnimation(android.view.View, Runnable);
+ method public static void postOnAnimationDelayed(android.view.View, Runnable, long);
+ method public static void removeAccessibilityAction(android.view.View, int);
+ method public static void removeOnUnhandledKeyEventListener(android.view.View, androidx.core.view.ViewCompat.OnUnhandledKeyEventListenerCompat);
+ method public static void replaceAccessibilityAction(android.view.View, androidx.core.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat, CharSequence?, androidx.core.view.accessibility.AccessibilityViewCommand?);
+ method public static void requestApplyInsets(android.view.View);
+ method public static <T extends android.view.View> T requireViewById(android.view.View, @IdRes int);
+ method @Deprecated public static int resolveSizeAndState(int, int, int);
+ method public static boolean restoreDefaultFocus(android.view.View);
+ method public static void saveAttributeDataForStyleable(android.view.View, android.content.Context, int[], android.util.AttributeSet?, android.content.res.TypedArray, int, int);
+ method public static void setAccessibilityDelegate(android.view.View, androidx.core.view.AccessibilityDelegateCompat?);
+ method @UiThread public static void setAccessibilityHeading(android.view.View, boolean);
+ method public static void setAccessibilityLiveRegion(android.view.View, int);
+ method @UiThread public static void setAccessibilityPaneTitle(android.view.View, CharSequence?);
+ method @Deprecated public static void setActivated(android.view.View!, boolean);
+ method @Deprecated public static void setAlpha(android.view.View!, @FloatRange(from=0.0, to=1.0) float);
+ method public static void setAutofillHints(android.view.View, java.lang.String!...);
+ method public static void setBackground(android.view.View, android.graphics.drawable.Drawable?);
+ method public static void setBackgroundTintList(android.view.View, android.content.res.ColorStateList?);
+ method public static void setBackgroundTintMode(android.view.View, android.graphics.PorterDuff.Mode?);
+ method @Deprecated public static void setChildrenDrawingOrderEnabled(android.view.ViewGroup!, boolean);
+ method public static void setClipBounds(android.view.View, android.graphics.Rect?);
+ method public static void setElevation(android.view.View, float);
+ method @Deprecated public static void setFitsSystemWindows(android.view.View!, boolean);
+ method public static void setFocusedByDefault(android.view.View, boolean);
+ method public static void setHasTransientState(android.view.View, boolean);
+ method @UiThread public static void setImportantForAccessibility(android.view.View, int);
+ method public static void setImportantForAutofill(android.view.View, int);
+ method public static void setKeyboardNavigationCluster(android.view.View, boolean);
+ method public static void setLabelFor(android.view.View, @IdRes int);
+ method public static void setLayerPaint(android.view.View, android.graphics.Paint?);
+ method @Deprecated public static void setLayerType(android.view.View!, int, android.graphics.Paint!);
+ method public static void setLayoutDirection(android.view.View, int);
+ method public static void setNestedScrollingEnabled(android.view.View, boolean);
+ method public static void setNextClusterForwardId(android.view.View, int);
+ method public static void setOnApplyWindowInsetsListener(android.view.View, androidx.core.view.OnApplyWindowInsetsListener?);
+ method public static void setOnReceiveContentListener(android.view.View, String![]?, androidx.core.view.OnReceiveContentListener?);
+ method @Deprecated public static void setOverScrollMode(android.view.View!, int);
+ method public static void setPaddingRelative(android.view.View, @Px int, @Px int, @Px int, @Px int);
+ method @Deprecated public static void setPivotX(android.view.View!, float);
+ method @Deprecated public static void setPivotY(android.view.View!, float);
+ method public static void setPointerIcon(android.view.View, androidx.core.view.PointerIconCompat?);
+ method @Deprecated public static void setRotation(android.view.View!, float);
+ method @Deprecated public static void setRotationX(android.view.View!, float);
+ method @Deprecated public static void setRotationY(android.view.View!, float);
+ method @Deprecated public static void setSaveFromParentEnabled(android.view.View!, boolean);
+ method @Deprecated public static void setScaleX(android.view.View!, float);
+ method @Deprecated public static void setScaleY(android.view.View!, float);
+ method @UiThread public static void setScreenReaderFocusable(android.view.View, boolean);
+ method public static void setScrollIndicators(android.view.View, int);
+ method public static void setScrollIndicators(android.view.View, int, int);
+ method @UiThread public static void setStateDescription(android.view.View, CharSequence?);
+ method public static void setSystemGestureExclusionRects(android.view.View, java.util.List<android.graphics.Rect!>);
+ method public static void setTooltipText(android.view.View, CharSequence?);
+ method public static void setTransitionName(android.view.View, String?);
+ method @Deprecated public static void setTranslationX(android.view.View!, float);
+ method @Deprecated public static void setTranslationY(android.view.View!, float);
+ method public static void setTranslationZ(android.view.View, float);
+ method public static void setWindowInsetsAnimationCallback(android.view.View, androidx.core.view.WindowInsetsAnimationCompat.Callback?);
+ method @Deprecated public static void setX(android.view.View!, float);
+ method @Deprecated public static void setY(android.view.View!, float);
+ method public static void setZ(android.view.View, float);
+ method public static boolean startDragAndDrop(android.view.View, android.content.ClipData?, android.view.View.DragShadowBuilder, Object?, int);
+ method public static boolean startNestedScroll(android.view.View, int);
+ method public static boolean startNestedScroll(android.view.View, int, int);
+ method public static void stopNestedScroll(android.view.View);
+ method public static void stopNestedScroll(android.view.View, int);
+ method public static void updateDragShadow(android.view.View, android.view.View.DragShadowBuilder);
+ field public static final int ACCESSIBILITY_LIVE_REGION_ASSERTIVE = 2; // 0x2
+ field public static final int ACCESSIBILITY_LIVE_REGION_NONE = 0; // 0x0
+ field public static final int ACCESSIBILITY_LIVE_REGION_POLITE = 1; // 0x1
+ field public static final int IMPORTANT_FOR_ACCESSIBILITY_AUTO = 0; // 0x0
+ field public static final int IMPORTANT_FOR_ACCESSIBILITY_NO = 2; // 0x2
+ field public static final int IMPORTANT_FOR_ACCESSIBILITY_NO_HIDE_DESCENDANTS = 4; // 0x4
+ field public static final int IMPORTANT_FOR_ACCESSIBILITY_YES = 1; // 0x1
+ field @Deprecated public static final int LAYER_TYPE_HARDWARE = 2; // 0x2
+ field @Deprecated public static final int LAYER_TYPE_NONE = 0; // 0x0
+ field @Deprecated public static final int LAYER_TYPE_SOFTWARE = 1; // 0x1
+ field public static final int LAYOUT_DIRECTION_INHERIT = 2; // 0x2
+ field public static final int LAYOUT_DIRECTION_LOCALE = 3; // 0x3
+ field public static final int LAYOUT_DIRECTION_LTR = 0; // 0x0
+ field public static final int LAYOUT_DIRECTION_RTL = 1; // 0x1
+ field @Deprecated public static final int MEASURED_HEIGHT_STATE_SHIFT = 16; // 0x10
+ field @Deprecated public static final int MEASURED_SIZE_MASK = 16777215; // 0xffffff
+ field @Deprecated public static final int MEASURED_STATE_MASK = -16777216; // 0xff000000
+ field @Deprecated public static final int MEASURED_STATE_TOO_SMALL = 16777216; // 0x1000000
+ field @Deprecated public static final int OVER_SCROLL_ALWAYS = 0; // 0x0
+ field @Deprecated public static final int OVER_SCROLL_IF_CONTENT_SCROLLS = 1; // 0x1
+ field @Deprecated public static final int OVER_SCROLL_NEVER = 2; // 0x2
+ field public static final int SCROLL_AXIS_HORIZONTAL = 1; // 0x1
+ field public static final int SCROLL_AXIS_NONE = 0; // 0x0
+ field public static final int SCROLL_AXIS_VERTICAL = 2; // 0x2
+ field public static final int SCROLL_INDICATOR_BOTTOM = 2; // 0x2
+ field public static final int SCROLL_INDICATOR_END = 32; // 0x20
+ field public static final int SCROLL_INDICATOR_LEFT = 4; // 0x4
+ field public static final int SCROLL_INDICATOR_RIGHT = 8; // 0x8
+ field public static final int SCROLL_INDICATOR_START = 16; // 0x10
+ field public static final int SCROLL_INDICATOR_TOP = 1; // 0x1
+ field public static final int TYPE_NON_TOUCH = 1; // 0x1
+ field public static final int TYPE_TOUCH = 0; // 0x0
+ }
+
+ public static interface ViewCompat.OnUnhandledKeyEventListenerCompat {
+ method public boolean onUnhandledKeyEvent(android.view.View, android.view.KeyEvent);
+ }
+
+ public final class ViewConfigurationCompat {
+ method public static float getScaledHorizontalScrollFactor(android.view.ViewConfiguration, android.content.Context);
+ method public static int getScaledHoverSlop(android.view.ViewConfiguration);
+ method @Deprecated public static int getScaledPagingTouchSlop(android.view.ViewConfiguration!);
+ method public static float getScaledVerticalScrollFactor(android.view.ViewConfiguration, android.content.Context);
+ method @Deprecated public static boolean hasPermanentMenuKey(android.view.ViewConfiguration!);
+ method public static boolean shouldShowMenuShortcutsWhenKeyboardPresent(android.view.ViewConfiguration, android.content.Context);
+ }
+
+ public final class ViewGroupCompat {
+ method public static int getLayoutMode(android.view.ViewGroup);
+ method public static int getNestedScrollAxes(android.view.ViewGroup);
+ method public static boolean isTransitionGroup(android.view.ViewGroup);
+ method @Deprecated public static boolean onRequestSendAccessibilityEvent(android.view.ViewGroup!, android.view.View!, android.view.accessibility.AccessibilityEvent!);
+ method public static void setLayoutMode(android.view.ViewGroup, int);
+ method @Deprecated public static void setMotionEventSplittingEnabled(android.view.ViewGroup!, boolean);
+ method public static void setTransitionGroup(android.view.ViewGroup, boolean);
+ field public static final int LAYOUT_MODE_CLIP_BOUNDS = 0; // 0x0
+ field public static final int LAYOUT_MODE_OPTICAL_BOUNDS = 1; // 0x1
+ }
+
+ public final class ViewParentCompat {
+ method public static void notifySubtreeAccessibilityStateChanged(android.view.ViewParent, android.view.View, android.view.View, int);
+ method public static boolean onNestedFling(android.view.ViewParent, android.view.View, float, float, boolean);
+ method public static boolean onNestedPreFling(android.view.ViewParent, android.view.View, float, float);
+ method public static void onNestedPreScroll(android.view.ViewParent, android.view.View, int, int, int[]);
+ method public static void onNestedPreScroll(android.view.ViewParent, android.view.View, int, int, int[], int);
+ method public static void onNestedScroll(android.view.ViewParent, android.view.View, int, int, int, int);
+ method public static void onNestedScroll(android.view.ViewParent, android.view.View, int, int, int, int, int);
+ method public static void onNestedScroll(android.view.ViewParent, android.view.View, int, int, int, int, int, int[]);
+ method public static void onNestedScrollAccepted(android.view.ViewParent, android.view.View, android.view.View, int);
+ method public static void onNestedScrollAccepted(android.view.ViewParent, android.view.View, android.view.View, int, int);
+ method public static boolean onStartNestedScroll(android.view.ViewParent, android.view.View, android.view.View, int);
+ method public static boolean onStartNestedScroll(android.view.ViewParent, android.view.View, android.view.View, int, int);
+ method public static void onStopNestedScroll(android.view.ViewParent, android.view.View);
+ method public static void onStopNestedScroll(android.view.ViewParent, android.view.View, int);
+ method @Deprecated public static boolean requestSendAccessibilityEvent(android.view.ViewParent!, android.view.View!, android.view.accessibility.AccessibilityEvent!);
+ }
+
+ public final class ViewPropertyAnimatorCompat {
+ method public androidx.core.view.ViewPropertyAnimatorCompat alpha(float);
+ method public androidx.core.view.ViewPropertyAnimatorCompat alphaBy(float);
+ method public void cancel();
+ method public long getDuration();
+ method public android.view.animation.Interpolator? getInterpolator();
+ method public long getStartDelay();
+ method public androidx.core.view.ViewPropertyAnimatorCompat rotation(float);
+ method public androidx.core.view.ViewPropertyAnimatorCompat rotationBy(float);
+ method public androidx.core.view.ViewPropertyAnimatorCompat rotationX(float);
+ method public androidx.core.view.ViewPropertyAnimatorCompat rotationXBy(float);
+ method public androidx.core.view.ViewPropertyAnimatorCompat rotationY(float);
+ method public androidx.core.view.ViewPropertyAnimatorCompat rotationYBy(float);
+ method public androidx.core.view.ViewPropertyAnimatorCompat scaleX(float);
+ method public androidx.core.view.ViewPropertyAnimatorCompat scaleXBy(float);
+ method public androidx.core.view.ViewPropertyAnimatorCompat scaleY(float);
+ method public androidx.core.view.ViewPropertyAnimatorCompat scaleYBy(float);
+ method public androidx.core.view.ViewPropertyAnimatorCompat setDuration(long);
+ method public androidx.core.view.ViewPropertyAnimatorCompat setInterpolator(android.view.animation.Interpolator?);
+ method public androidx.core.view.ViewPropertyAnimatorCompat setListener(androidx.core.view.ViewPropertyAnimatorListener?);
+ method public androidx.core.view.ViewPropertyAnimatorCompat setStartDelay(long);
+ method public androidx.core.view.ViewPropertyAnimatorCompat setUpdateListener(androidx.core.view.ViewPropertyAnimatorUpdateListener?);
+ method public void start();
+ method public androidx.core.view.ViewPropertyAnimatorCompat translationX(float);
+ method public androidx.core.view.ViewPropertyAnimatorCompat translationXBy(float);
+ method public androidx.core.view.ViewPropertyAnimatorCompat translationY(float);
+ method public androidx.core.view.ViewPropertyAnimatorCompat translationYBy(float);
+ method public androidx.core.view.ViewPropertyAnimatorCompat translationZ(float);
+ method public androidx.core.view.ViewPropertyAnimatorCompat translationZBy(float);
+ method public androidx.core.view.ViewPropertyAnimatorCompat withEndAction(Runnable);
+ method public androidx.core.view.ViewPropertyAnimatorCompat withLayer();
+ method public androidx.core.view.ViewPropertyAnimatorCompat withStartAction(Runnable);
+ method public androidx.core.view.ViewPropertyAnimatorCompat x(float);
+ method public androidx.core.view.ViewPropertyAnimatorCompat xBy(float);
+ method public androidx.core.view.ViewPropertyAnimatorCompat y(float);
+ method public androidx.core.view.ViewPropertyAnimatorCompat yBy(float);
+ method public androidx.core.view.ViewPropertyAnimatorCompat z(float);
+ method public androidx.core.view.ViewPropertyAnimatorCompat zBy(float);
+ }
+
+ public interface ViewPropertyAnimatorListener {
+ method public void onAnimationCancel(android.view.View);
+ method public void onAnimationEnd(android.view.View);
+ method public void onAnimationStart(android.view.View);
+ }
+
+ public class ViewPropertyAnimatorListenerAdapter implements androidx.core.view.ViewPropertyAnimatorListener {
+ ctor public ViewPropertyAnimatorListenerAdapter();
+ method public void onAnimationCancel(android.view.View);
+ method public void onAnimationEnd(android.view.View);
+ method public void onAnimationStart(android.view.View);
+ }
+
+ public interface ViewPropertyAnimatorUpdateListener {
+ method public void onAnimationUpdate(android.view.View);
+ }
+
+ public final class WindowCompat {
+ method public static androidx.core.view.WindowInsetsControllerCompat getInsetsController(android.view.Window, android.view.View);
+ method public static <T extends android.view.View> T requireViewById(android.view.Window, @IdRes int);
+ method public static void setDecorFitsSystemWindows(android.view.Window, boolean);
+ field public static final int FEATURE_ACTION_BAR = 8; // 0x8
+ field public static final int FEATURE_ACTION_BAR_OVERLAY = 9; // 0x9
+ field public static final int FEATURE_ACTION_MODE_OVERLAY = 10; // 0xa
+ }
+
+ public final class WindowInsetsAnimationCompat {
+ ctor public WindowInsetsAnimationCompat(int, android.view.animation.Interpolator?, long);
+ method @FloatRange(from=0.0f, to=1.0f) public float getAlpha();
+ method public long getDurationMillis();
+ method @FloatRange(from=0.0f, to=1.0f) public float getFraction();
+ method public float getInterpolatedFraction();
+ method public android.view.animation.Interpolator? getInterpolator();
+ method public int getTypeMask();
+ method public void setAlpha(@FloatRange(from=0.0f, to=1.0f) float);
+ method public void setFraction(@FloatRange(from=0.0f, to=1.0f) float);
+ }
+
+ public static final class WindowInsetsAnimationCompat.BoundsCompat {
+ ctor public WindowInsetsAnimationCompat.BoundsCompat(androidx.core.graphics.Insets, androidx.core.graphics.Insets);
+ method public androidx.core.graphics.Insets getLowerBound();
+ method public androidx.core.graphics.Insets getUpperBound();
+ method public androidx.core.view.WindowInsetsAnimationCompat.BoundsCompat inset(androidx.core.graphics.Insets);
+ method @RequiresApi(30) public android.view.WindowInsetsAnimation.Bounds toBounds();
+ method @RequiresApi(30) public static androidx.core.view.WindowInsetsAnimationCompat.BoundsCompat toBoundsCompat(android.view.WindowInsetsAnimation.Bounds);
+ }
+
+ public abstract static class WindowInsetsAnimationCompat.Callback {
+ ctor public WindowInsetsAnimationCompat.Callback(int);
+ method public final int getDispatchMode();
+ method public void onEnd(androidx.core.view.WindowInsetsAnimationCompat);
+ method public void onPrepare(androidx.core.view.WindowInsetsAnimationCompat);
+ method public abstract androidx.core.view.WindowInsetsCompat onProgress(androidx.core.view.WindowInsetsCompat, java.util.List<androidx.core.view.WindowInsetsAnimationCompat!>);
+ method public androidx.core.view.WindowInsetsAnimationCompat.BoundsCompat onStart(androidx.core.view.WindowInsetsAnimationCompat, androidx.core.view.WindowInsetsAnimationCompat.BoundsCompat);
+ field public static final int DISPATCH_MODE_CONTINUE_ON_SUBTREE = 1; // 0x1
+ field public static final int DISPATCH_MODE_STOP = 0; // 0x0
+ }
+
+ public interface WindowInsetsAnimationControlListenerCompat {
+ method public void onCancelled(androidx.core.view.WindowInsetsAnimationControllerCompat?);
+ method public void onFinished(androidx.core.view.WindowInsetsAnimationControllerCompat);
+ method public void onReady(androidx.core.view.WindowInsetsAnimationControllerCompat, int);
+ }
+
+ public final class WindowInsetsAnimationControllerCompat {
+ method public void finish(boolean);
+ method public float getCurrentAlpha();
+ method @FloatRange(from=0.0f, to=1.0f) public float getCurrentFraction();
+ method public androidx.core.graphics.Insets getCurrentInsets();
+ method public androidx.core.graphics.Insets getHiddenStateInsets();
+ method public androidx.core.graphics.Insets getShownStateInsets();
+ method public int getTypes();
+ method public boolean isCancelled();
+ method public boolean isFinished();
+ method public boolean isReady();
+ method public void setInsetsAndAlpha(androidx.core.graphics.Insets?, @FloatRange(from=0.0f, to=1.0f) float, @FloatRange(from=0.0f, to=1.0f) float);
+ }
+
+ public class WindowInsetsCompat {
+ ctor public WindowInsetsCompat(androidx.core.view.WindowInsetsCompat?);
+ method @Deprecated public androidx.core.view.WindowInsetsCompat consumeDisplayCutout();
+ method @Deprecated public androidx.core.view.WindowInsetsCompat consumeStableInsets();
+ method @Deprecated public androidx.core.view.WindowInsetsCompat consumeSystemWindowInsets();
+ method public androidx.core.view.DisplayCutoutCompat? getDisplayCutout();
+ method public androidx.core.graphics.Insets getInsets(int);
+ method public androidx.core.graphics.Insets getInsetsIgnoringVisibility(int);
+ method @Deprecated public androidx.core.graphics.Insets getMandatorySystemGestureInsets();
+ method @Deprecated public int getStableInsetBottom();
+ method @Deprecated public int getStableInsetLeft();
+ method @Deprecated public int getStableInsetRight();
+ method @Deprecated public int getStableInsetTop();
+ method @Deprecated public androidx.core.graphics.Insets getStableInsets();
+ method @Deprecated public androidx.core.graphics.Insets getSystemGestureInsets();
+ method @Deprecated public int getSystemWindowInsetBottom();
+ method @Deprecated public int getSystemWindowInsetLeft();
+ method @Deprecated public int getSystemWindowInsetRight();
+ method @Deprecated public int getSystemWindowInsetTop();
+ method @Deprecated public androidx.core.graphics.Insets getSystemWindowInsets();
+ method @Deprecated public androidx.core.graphics.Insets getTappableElementInsets();
+ method public boolean hasInsets();
+ method @Deprecated public boolean hasStableInsets();
+ method @Deprecated public boolean hasSystemWindowInsets();
+ method public androidx.core.view.WindowInsetsCompat inset(androidx.core.graphics.Insets);
+ method public androidx.core.view.WindowInsetsCompat inset(@IntRange(from=0) int, @IntRange(from=0) int, @IntRange(from=0) int, @IntRange(from=0) int);
+ method public boolean isConsumed();
+ method public boolean isRound();
+ method public boolean isVisible(int);
+ method @Deprecated public androidx.core.view.WindowInsetsCompat replaceSystemWindowInsets(int, int, int, int);
+ method @Deprecated public androidx.core.view.WindowInsetsCompat replaceSystemWindowInsets(android.graphics.Rect);
+ method @RequiresApi(20) public android.view.WindowInsets? toWindowInsets();
+ method @RequiresApi(20) public static androidx.core.view.WindowInsetsCompat toWindowInsetsCompat(android.view.WindowInsets);
+ method @RequiresApi(20) public static androidx.core.view.WindowInsetsCompat toWindowInsetsCompat(android.view.WindowInsets, android.view.View?);
+ field public static final androidx.core.view.WindowInsetsCompat CONSUMED;
+ }
+
+ public static final class WindowInsetsCompat.Builder {
+ ctor public WindowInsetsCompat.Builder();
+ ctor public WindowInsetsCompat.Builder(androidx.core.view.WindowInsetsCompat);
+ method public androidx.core.view.WindowInsetsCompat build();
+ method public androidx.core.view.WindowInsetsCompat.Builder setDisplayCutout(androidx.core.view.DisplayCutoutCompat?);
+ method public androidx.core.view.WindowInsetsCompat.Builder setInsets(int, androidx.core.graphics.Insets);
+ method public androidx.core.view.WindowInsetsCompat.Builder setInsetsIgnoringVisibility(int, androidx.core.graphics.Insets);
+ method @Deprecated public androidx.core.view.WindowInsetsCompat.Builder setMandatorySystemGestureInsets(androidx.core.graphics.Insets);
+ method @Deprecated public androidx.core.view.WindowInsetsCompat.Builder setStableInsets(androidx.core.graphics.Insets);
+ method @Deprecated public androidx.core.view.WindowInsetsCompat.Builder setSystemGestureInsets(androidx.core.graphics.Insets);
+ method @Deprecated public androidx.core.view.WindowInsetsCompat.Builder setSystemWindowInsets(androidx.core.graphics.Insets);
+ method @Deprecated public androidx.core.view.WindowInsetsCompat.Builder setTappableElementInsets(androidx.core.graphics.Insets);
+ method public androidx.core.view.WindowInsetsCompat.Builder setVisible(int, boolean);
+ }
+
+ public static final class WindowInsetsCompat.Type {
+ method public static int captionBar();
+ method public static int displayCutout();
+ method public static int ime();
+ method public static int mandatorySystemGestures();
+ method public static int navigationBars();
+ method public static int statusBars();
+ method public static int systemBars();
+ method public static int systemGestures();
+ method public static int tappableElement();
+ }
+
+ public final class WindowInsetsControllerCompat {
+ ctor public WindowInsetsControllerCompat(android.view.Window, android.view.View);
+ method public void addOnControllableInsetsChangedListener(androidx.core.view.WindowInsetsControllerCompat.OnControllableInsetsChangedListener);
+ method public void controlWindowInsetsAnimation(int, long, android.view.animation.Interpolator?, android.os.CancellationSignal?, androidx.core.view.WindowInsetsAnimationControlListenerCompat);
+ method public int getSystemBarsBehavior();
+ method public void hide(int);
+ method public boolean isAppearanceLightNavigationBars();
+ method public boolean isAppearanceLightStatusBars();
+ method public void removeOnControllableInsetsChangedListener(androidx.core.view.WindowInsetsControllerCompat.OnControllableInsetsChangedListener);
+ method public void setAppearanceLightNavigationBars(boolean);
+ method public void setAppearanceLightStatusBars(boolean);
+ method public void setSystemBarsBehavior(int);
+ method public void show(int);
+ method @Deprecated @RequiresApi(30) public static androidx.core.view.WindowInsetsControllerCompat toWindowInsetsControllerCompat(android.view.WindowInsetsController);
+ field public static final int BEHAVIOR_DEFAULT = 1; // 0x1
+ field @Deprecated public static final int BEHAVIOR_SHOW_BARS_BY_SWIPE = 1; // 0x1
+ field @Deprecated public static final int BEHAVIOR_SHOW_BARS_BY_TOUCH = 0; // 0x0
+ field public static final int BEHAVIOR_SHOW_TRANSIENT_BARS_BY_SWIPE = 2; // 0x2
+ }
+
+ public static interface WindowInsetsControllerCompat.OnControllableInsetsChangedListener {
+ method public void onControllableInsetsChanged(androidx.core.view.WindowInsetsControllerCompat, int);
+ }
+
+}
+
+package androidx.core.view.accessibility {
+
+ public final class AccessibilityClickableSpanCompat extends android.text.style.ClickableSpan {
+ method public void onClick(android.view.View);
+ }
+
+ public final class AccessibilityEventCompat {
+ method @Deprecated public static void appendRecord(android.view.accessibility.AccessibilityEvent!, androidx.core.view.accessibility.AccessibilityRecordCompat!);
+ method @Deprecated public static androidx.core.view.accessibility.AccessibilityRecordCompat! asRecord(android.view.accessibility.AccessibilityEvent!);
+ method public static int getAction(android.view.accessibility.AccessibilityEvent);
+ method public static int getContentChangeTypes(android.view.accessibility.AccessibilityEvent);
+ method public static int getMovementGranularity(android.view.accessibility.AccessibilityEvent);
+ method @Deprecated public static androidx.core.view.accessibility.AccessibilityRecordCompat! getRecord(android.view.accessibility.AccessibilityEvent!, int);
+ method @Deprecated public static int getRecordCount(android.view.accessibility.AccessibilityEvent!);
+ method public static void setAction(android.view.accessibility.AccessibilityEvent, int);
+ method public static void setContentChangeTypes(android.view.accessibility.AccessibilityEvent, int);
+ method public static void setMovementGranularity(android.view.accessibility.AccessibilityEvent, int);
+ field public static final int CONTENT_CHANGE_TYPE_CONTENT_DESCRIPTION = 4; // 0x4
+ field public static final int CONTENT_CHANGE_TYPE_DRAG_CANCELLED = 512; // 0x200
+ field public static final int CONTENT_CHANGE_TYPE_DRAG_DROPPED = 256; // 0x100
+ field public static final int CONTENT_CHANGE_TYPE_DRAG_STARTED = 128; // 0x80
+ field public static final int CONTENT_CHANGE_TYPE_PANE_APPEARED = 16; // 0x10
+ field public static final int CONTENT_CHANGE_TYPE_PANE_DISAPPEARED = 32; // 0x20
+ field public static final int CONTENT_CHANGE_TYPE_PANE_TITLE = 8; // 0x8
+ field public static final int CONTENT_CHANGE_TYPE_STATE_DESCRIPTION = 64; // 0x40
+ field public static final int CONTENT_CHANGE_TYPE_SUBTREE = 1; // 0x1
+ field public static final int CONTENT_CHANGE_TYPE_TEXT = 2; // 0x2
+ field public static final int CONTENT_CHANGE_TYPE_UNDEFINED = 0; // 0x0
+ field public static final int TYPES_ALL_MASK = -1; // 0xffffffff
+ field public static final int TYPE_ANNOUNCEMENT = 16384; // 0x4000
+ field public static final int TYPE_ASSIST_READING_CONTEXT = 16777216; // 0x1000000
+ field public static final int TYPE_GESTURE_DETECTION_END = 524288; // 0x80000
+ field public static final int TYPE_GESTURE_DETECTION_START = 262144; // 0x40000
+ field @Deprecated public static final int TYPE_TOUCH_EXPLORATION_GESTURE_END = 1024; // 0x400
+ field @Deprecated public static final int TYPE_TOUCH_EXPLORATION_GESTURE_START = 512; // 0x200
+ field public static final int TYPE_TOUCH_INTERACTION_END = 2097152; // 0x200000
+ field public static final int TYPE_TOUCH_INTERACTION_START = 1048576; // 0x100000
+ field public static final int TYPE_VIEW_ACCESSIBILITY_FOCUSED = 32768; // 0x8000
+ field public static final int TYPE_VIEW_ACCESSIBILITY_FOCUS_CLEARED = 65536; // 0x10000
+ field public static final int TYPE_VIEW_CONTEXT_CLICKED = 8388608; // 0x800000
+ field @Deprecated public static final int TYPE_VIEW_HOVER_ENTER = 128; // 0x80
+ field @Deprecated public static final int TYPE_VIEW_HOVER_EXIT = 256; // 0x100
+ field @Deprecated public static final int TYPE_VIEW_SCROLLED = 4096; // 0x1000
+ field @Deprecated public static final int TYPE_VIEW_TEXT_SELECTION_CHANGED = 8192; // 0x2000
+ field public static final int TYPE_VIEW_TEXT_TRAVERSED_AT_MOVEMENT_GRANULARITY = 131072; // 0x20000
+ field public static final int TYPE_WINDOWS_CHANGED = 4194304; // 0x400000
+ field @Deprecated public static final int TYPE_WINDOW_CONTENT_CHANGED = 2048; // 0x800
+ }
+
+ public final class AccessibilityManagerCompat {
+ method @Deprecated public static boolean addAccessibilityStateChangeListener(android.view.accessibility.AccessibilityManager!, androidx.core.view.accessibility.AccessibilityManagerCompat.AccessibilityStateChangeListener!);
+ method public static boolean addTouchExplorationStateChangeListener(android.view.accessibility.AccessibilityManager, androidx.core.view.accessibility.AccessibilityManagerCompat.TouchExplorationStateChangeListener);
+ method @Deprecated public static java.util.List<android.accessibilityservice.AccessibilityServiceInfo!>! getEnabledAccessibilityServiceList(android.view.accessibility.AccessibilityManager!, int);
+ method @Deprecated public static java.util.List<android.accessibilityservice.AccessibilityServiceInfo!>! getInstalledAccessibilityServiceList(android.view.accessibility.AccessibilityManager!);
+ method @Deprecated public static boolean isTouchExplorationEnabled(android.view.accessibility.AccessibilityManager!);
+ method @Deprecated public static boolean removeAccessibilityStateChangeListener(android.view.accessibility.AccessibilityManager!, androidx.core.view.accessibility.AccessibilityManagerCompat.AccessibilityStateChangeListener!);
+ method public static boolean removeTouchExplorationStateChangeListener(android.view.accessibility.AccessibilityManager, androidx.core.view.accessibility.AccessibilityManagerCompat.TouchExplorationStateChangeListener);
+ }
+
+ @Deprecated public static interface AccessibilityManagerCompat.AccessibilityStateChangeListener {
+ method @Deprecated public void onAccessibilityStateChanged(boolean);
+ }
+
+ @Deprecated public abstract static class AccessibilityManagerCompat.AccessibilityStateChangeListenerCompat implements androidx.core.view.accessibility.AccessibilityManagerCompat.AccessibilityStateChangeListener {
+ ctor @Deprecated public AccessibilityManagerCompat.AccessibilityStateChangeListenerCompat();
+ }
+
+ public static interface AccessibilityManagerCompat.TouchExplorationStateChangeListener {
+ method public void onTouchExplorationStateChanged(boolean);
+ }
+
+ public class AccessibilityNodeInfoCompat {
+ ctor @Deprecated public AccessibilityNodeInfoCompat(Object!);
+ method public void addAction(int);
+ method public void addAction(androidx.core.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat!);
+ method public void addChild(android.view.View!);
+ method public void addChild(android.view.View!, int);
+ method public boolean canOpenPopup();
+ method public java.util.List<androidx.core.view.accessibility.AccessibilityNodeInfoCompat!>! findAccessibilityNodeInfosByText(String!);
+ method public java.util.List<androidx.core.view.accessibility.AccessibilityNodeInfoCompat!>! findAccessibilityNodeInfosByViewId(String!);
+ method public androidx.core.view.accessibility.AccessibilityNodeInfoCompat! findFocus(int);
+ method public androidx.core.view.accessibility.AccessibilityNodeInfoCompat! focusSearch(int);
+ method public java.util.List<androidx.core.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat!>! getActionList();
+ method @Deprecated public int getActions();
+ method public java.util.List<java.lang.String!> getAvailableExtraData();
+ method @Deprecated public void getBoundsInParent(android.graphics.Rect!);
+ method public void getBoundsInScreen(android.graphics.Rect!);
+ method public androidx.core.view.accessibility.AccessibilityNodeInfoCompat! getChild(int);
+ method public int getChildCount();
+ method public CharSequence! getClassName();
+ method public androidx.core.view.accessibility.AccessibilityNodeInfoCompat.CollectionInfoCompat! getCollectionInfo();
+ method public androidx.core.view.accessibility.AccessibilityNodeInfoCompat.CollectionItemInfoCompat! getCollectionItemInfo();
+ method public CharSequence! getContentDescription();
+ method public int getDrawingOrder();
+ method public CharSequence! getError();
+ method public android.view.accessibility.AccessibilityNodeInfo.ExtraRenderingInfo? getExtraRenderingInfo();
+ method public android.os.Bundle! getExtras();
+ method public CharSequence? getHintText();
+ method @Deprecated public Object! getInfo();
+ method public int getInputType();
+ method public androidx.core.view.accessibility.AccessibilityNodeInfoCompat! getLabelFor();
+ method public androidx.core.view.accessibility.AccessibilityNodeInfoCompat! getLabeledBy();
+ method public int getLiveRegion();
+ method public int getMaxTextLength();
+ method public int getMinMillisBetweenContentChanges();
+ method public int getMovementGranularities();
+ method public CharSequence! getPackageName();
+ method public CharSequence? getPaneTitle();
+ method public androidx.core.view.accessibility.AccessibilityNodeInfoCompat! getParent();
+ method public androidx.core.view.accessibility.AccessibilityNodeInfoCompat.RangeInfoCompat! getRangeInfo();
+ method public CharSequence? getRoleDescription();
+ method public CharSequence? getStateDescription();
+ method public CharSequence! getText();
+ method public int getTextSelectionEnd();
+ method public int getTextSelectionStart();
+ method public CharSequence? getTooltipText();
+ method public androidx.core.view.accessibility.AccessibilityNodeInfoCompat.TouchDelegateInfoCompat? getTouchDelegateInfo();
+ method public androidx.core.view.accessibility.AccessibilityNodeInfoCompat! getTraversalAfter();
+ method public androidx.core.view.accessibility.AccessibilityNodeInfoCompat! getTraversalBefore();
+ method public String? getUniqueId();
+ method public String! getViewIdResourceName();
+ method public androidx.core.view.accessibility.AccessibilityWindowInfoCompat! getWindow();
+ method public int getWindowId();
+ method public boolean hasRequestInitialAccessibilityFocus();
+ method public boolean isAccessibilityFocused();
+ method public boolean isCheckable();
+ method public boolean isChecked();
+ method public boolean isClickable();
+ method public boolean isContentInvalid();
+ method public boolean isContextClickable();
+ method public boolean isDismissable();
+ method public boolean isEditable();
+ method public boolean isEnabled();
+ method public boolean isFocusable();
+ method public boolean isFocused();
+ method public boolean isHeading();
+ method public boolean isImportantForAccessibility();
+ method public boolean isLongClickable();
+ method public boolean isMultiLine();
+ method public boolean isPassword();
+ method public boolean isScreenReaderFocusable();
+ method public boolean isScrollable();
+ method public boolean isSelected();
+ method public boolean isShowingHintText();
+ method public boolean isTextEntryKey();
+ method public boolean isTextSelectable();
+ method public boolean isVisibleToUser();
+ method public static androidx.core.view.accessibility.AccessibilityNodeInfoCompat! obtain(android.view.View!);
+ method public static androidx.core.view.accessibility.AccessibilityNodeInfoCompat! obtain(android.view.View!, int);
+ method public static androidx.core.view.accessibility.AccessibilityNodeInfoCompat! obtain();
+ method public static androidx.core.view.accessibility.AccessibilityNodeInfoCompat! obtain(androidx.core.view.accessibility.AccessibilityNodeInfoCompat!);
+ method public boolean performAction(int);
+ method public boolean performAction(int, android.os.Bundle!);
+ method @Deprecated public void recycle();
+ method public boolean refresh();
+ method public boolean removeAction(androidx.core.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat!);
+ method public boolean removeChild(android.view.View!);
+ method public boolean removeChild(android.view.View!, int);
+ method public void setAccessibilityFocused(boolean);
+ method public void setAvailableExtraData(java.util.List<java.lang.String!>);
+ method @Deprecated public void setBoundsInParent(android.graphics.Rect!);
+ method public void setBoundsInScreen(android.graphics.Rect!);
+ method public void setCanOpenPopup(boolean);
+ method public void setCheckable(boolean);
+ method public void setChecked(boolean);
+ method public void setClassName(CharSequence!);
+ method public void setClickable(boolean);
+ method public void setCollectionInfo(Object!);
+ method public void setCollectionItemInfo(Object!);
+ method public void setContentDescription(CharSequence!);
+ method public void setContentInvalid(boolean);
+ method public void setContextClickable(boolean);
+ method public void setDismissable(boolean);
+ method public void setDrawingOrder(int);
+ method public void setEditable(boolean);
+ method public void setEnabled(boolean);
+ method public void setError(CharSequence!);
+ method public void setFocusable(boolean);
+ method public void setFocused(boolean);
+ method public void setHeading(boolean);
+ method public void setHintText(CharSequence?);
+ method public void setImportantForAccessibility(boolean);
+ method public void setInputType(int);
+ method public void setLabelFor(android.view.View!);
+ method public void setLabelFor(android.view.View!, int);
+ method public void setLabeledBy(android.view.View!);
+ method public void setLabeledBy(android.view.View!, int);
+ method public void setLiveRegion(int);
+ method public void setLongClickable(boolean);
+ method public void setMaxTextLength(int);
+ method public void setMinMillisBetweenContentChanges(int);
+ method public void setMovementGranularities(int);
+ method public void setMultiLine(boolean);
+ method public void setPackageName(CharSequence!);
+ method public void setPaneTitle(CharSequence?);
+ method public void setParent(android.view.View!);
+ method public void setParent(android.view.View!, int);
+ method public void setPassword(boolean);
+ method public void setRangeInfo(androidx.core.view.accessibility.AccessibilityNodeInfoCompat.RangeInfoCompat!);
+ method public void setRequestInitialAccessibilityFocus(boolean);
+ method public void setRoleDescription(CharSequence?);
+ method public void setScreenReaderFocusable(boolean);
+ method public void setScrollable(boolean);
+ method public void setSelected(boolean);
+ method public void setShowingHintText(boolean);
+ method public void setSource(android.view.View!);
+ method public void setSource(android.view.View!, int);
+ method public void setStateDescription(CharSequence?);
+ method public void setText(CharSequence!);
+ method public void setTextEntryKey(boolean);
+ method public void setTextSelectable(boolean);
+ method public void setTextSelection(int, int);
+ method public void setTooltipText(CharSequence?);
+ method public void setTouchDelegateInfo(androidx.core.view.accessibility.AccessibilityNodeInfoCompat.TouchDelegateInfoCompat);
+ method public void setTraversalAfter(android.view.View!);
+ method public void setTraversalAfter(android.view.View!, int);
+ method public void setTraversalBefore(android.view.View!);
+ method public void setTraversalBefore(android.view.View!, int);
+ method public void setUniqueId(String?);
+ method public void setViewIdResourceName(String!);
+ method public void setVisibleToUser(boolean);
+ method public android.view.accessibility.AccessibilityNodeInfo! unwrap();
+ method public static androidx.core.view.accessibility.AccessibilityNodeInfoCompat! wrap(android.view.accessibility.AccessibilityNodeInfo);
+ field public static final int ACTION_ACCESSIBILITY_FOCUS = 64; // 0x40
+ field public static final String ACTION_ARGUMENT_COLUMN_INT = "android.view.accessibility.action.ARGUMENT_COLUMN_INT";
+ field public static final String ACTION_ARGUMENT_EXTEND_SELECTION_BOOLEAN = "ACTION_ARGUMENT_EXTEND_SELECTION_BOOLEAN";
+ field public static final String ACTION_ARGUMENT_HTML_ELEMENT_STRING = "ACTION_ARGUMENT_HTML_ELEMENT_STRING";
+ field public static final String ACTION_ARGUMENT_MOVEMENT_GRANULARITY_INT = "ACTION_ARGUMENT_MOVEMENT_GRANULARITY_INT";
+ field public static final String ACTION_ARGUMENT_MOVE_WINDOW_X = "ACTION_ARGUMENT_MOVE_WINDOW_X";
+ field public static final String ACTION_ARGUMENT_MOVE_WINDOW_Y = "ACTION_ARGUMENT_MOVE_WINDOW_Y";
+ field public static final String ACTION_ARGUMENT_PRESS_AND_HOLD_DURATION_MILLIS_INT = "android.view.accessibility.action.ARGUMENT_PRESS_AND_HOLD_DURATION_MILLIS_INT";
+ field public static final String ACTION_ARGUMENT_PROGRESS_VALUE = "android.view.accessibility.action.ARGUMENT_PROGRESS_VALUE";
+ field public static final String ACTION_ARGUMENT_ROW_INT = "android.view.accessibility.action.ARGUMENT_ROW_INT";
+ field public static final String ACTION_ARGUMENT_SELECTION_END_INT = "ACTION_ARGUMENT_SELECTION_END_INT";
+ field public static final String ACTION_ARGUMENT_SELECTION_START_INT = "ACTION_ARGUMENT_SELECTION_START_INT";
+ field public static final String ACTION_ARGUMENT_SET_TEXT_CHARSEQUENCE = "ACTION_ARGUMENT_SET_TEXT_CHARSEQUENCE";
+ field public static final int ACTION_CLEAR_ACCESSIBILITY_FOCUS = 128; // 0x80
+ field public static final int ACTION_CLEAR_FOCUS = 2; // 0x2
+ field public static final int ACTION_CLEAR_SELECTION = 8; // 0x8
+ field public static final int ACTION_CLICK = 16; // 0x10
+ field public static final int ACTION_COLLAPSE = 524288; // 0x80000
+ field public static final int ACTION_COPY = 16384; // 0x4000
+ field public static final int ACTION_CUT = 65536; // 0x10000
+ field public static final int ACTION_DISMISS = 1048576; // 0x100000
+ field public static final int ACTION_EXPAND = 262144; // 0x40000
+ field public static final int ACTION_FOCUS = 1; // 0x1
+ field public static final int ACTION_LONG_CLICK = 32; // 0x20
+ field public static final int ACTION_NEXT_AT_MOVEMENT_GRANULARITY = 256; // 0x100
+ field public static final int ACTION_NEXT_HTML_ELEMENT = 1024; // 0x400
+ field public static final int ACTION_PASTE = 32768; // 0x8000
+ field public static final int ACTION_PREVIOUS_AT_MOVEMENT_GRANULARITY = 512; // 0x200
+ field public static final int ACTION_PREVIOUS_HTML_ELEMENT = 2048; // 0x800
+ field public static final int ACTION_SCROLL_BACKWARD = 8192; // 0x2000
+ field public static final int ACTION_SCROLL_FORWARD = 4096; // 0x1000
+ field public static final int ACTION_SELECT = 4; // 0x4
+ field public static final int ACTION_SET_SELECTION = 131072; // 0x20000
+ field public static final int ACTION_SET_TEXT = 2097152; // 0x200000
+ field public static final String EXTRA_DATA_TEXT_CHARACTER_LOCATION_ARG_LENGTH = "android.core.view.accessibility.extra.DATA_TEXT_CHARACTER_LOCATION_ARG_LENGTH";
+ field public static final int EXTRA_DATA_TEXT_CHARACTER_LOCATION_ARG_MAX_LENGTH = 20000; // 0x4e20
+ field public static final String EXTRA_DATA_TEXT_CHARACTER_LOCATION_ARG_START_INDEX = "android.core.view.accessibility.extra.DATA_TEXT_CHARACTER_LOCATION_ARG_START_INDEX";
+ field public static final String EXTRA_DATA_TEXT_CHARACTER_LOCATION_KEY = "android.core.view.accessibility.extra.DATA_TEXT_CHARACTER_LOCATION_KEY";
+ field public static final int FOCUS_ACCESSIBILITY = 2; // 0x2
+ field public static final int FOCUS_INPUT = 1; // 0x1
+ field public static final int MOVEMENT_GRANULARITY_CHARACTER = 1; // 0x1
+ field public static final int MOVEMENT_GRANULARITY_LINE = 4; // 0x4
+ field public static final int MOVEMENT_GRANULARITY_PAGE = 16; // 0x10
+ field public static final int MOVEMENT_GRANULARITY_PARAGRAPH = 8; // 0x8
+ field public static final int MOVEMENT_GRANULARITY_WORD = 2; // 0x2
+ }
+
+ public static class AccessibilityNodeInfoCompat.AccessibilityActionCompat {
+ ctor public AccessibilityNodeInfoCompat.AccessibilityActionCompat(int, CharSequence!);
+ method public int getId();
+ method public CharSequence! getLabel();
+ field public static final androidx.core.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat! ACTION_ACCESSIBILITY_FOCUS;
+ field public static final androidx.core.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat! ACTION_CLEAR_ACCESSIBILITY_FOCUS;
+ field public static final androidx.core.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat! ACTION_CLEAR_FOCUS;
+ field public static final androidx.core.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat! ACTION_CLEAR_SELECTION;
+ field public static final androidx.core.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat! ACTION_CLICK;
+ field public static final androidx.core.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat! ACTION_COLLAPSE;
+ field public static final androidx.core.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat! ACTION_CONTEXT_CLICK;
+ field public static final androidx.core.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat! ACTION_COPY;
+ field public static final androidx.core.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat! ACTION_CUT;
+ field public static final androidx.core.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat! ACTION_DISMISS;
+ field public static final androidx.core.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat ACTION_DRAG_CANCEL;
+ field public static final androidx.core.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat ACTION_DRAG_DROP;
+ field public static final androidx.core.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat ACTION_DRAG_START;
+ field public static final androidx.core.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat! ACTION_EXPAND;
+ field public static final androidx.core.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat! ACTION_FOCUS;
+ field public static final androidx.core.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat! ACTION_HIDE_TOOLTIP;
+ field public static final androidx.core.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat ACTION_IME_ENTER;
+ field public static final androidx.core.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat! ACTION_LONG_CLICK;
+ field public static final androidx.core.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat! ACTION_MOVE_WINDOW;
+ field public static final androidx.core.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat! ACTION_NEXT_AT_MOVEMENT_GRANULARITY;
+ field public static final androidx.core.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat! ACTION_NEXT_HTML_ELEMENT;
+ field public static final androidx.core.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat ACTION_PAGE_DOWN;
+ field public static final androidx.core.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat ACTION_PAGE_LEFT;
+ field public static final androidx.core.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat ACTION_PAGE_RIGHT;
+ field public static final androidx.core.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat ACTION_PAGE_UP;
+ field public static final androidx.core.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat! ACTION_PASTE;
+ field public static final androidx.core.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat ACTION_PRESS_AND_HOLD;
+ field public static final androidx.core.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat! ACTION_PREVIOUS_AT_MOVEMENT_GRANULARITY;
+ field public static final androidx.core.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat! ACTION_PREVIOUS_HTML_ELEMENT;
+ field public static final androidx.core.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat! ACTION_SCROLL_BACKWARD;
+ field public static final androidx.core.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat! ACTION_SCROLL_DOWN;
+ field public static final androidx.core.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat! ACTION_SCROLL_FORWARD;
+ field public static final androidx.core.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat! ACTION_SCROLL_LEFT;
+ field public static final androidx.core.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat! ACTION_SCROLL_RIGHT;
+ field public static final androidx.core.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat! ACTION_SCROLL_TO_POSITION;
+ field public static final androidx.core.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat! ACTION_SCROLL_UP;
+ field public static final androidx.core.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat! ACTION_SELECT;
+ field public static final androidx.core.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat! ACTION_SET_PROGRESS;
+ field public static final androidx.core.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat! ACTION_SET_SELECTION;
+ field public static final androidx.core.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat! ACTION_SET_TEXT;
+ field public static final androidx.core.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat! ACTION_SHOW_ON_SCREEN;
+ field public static final androidx.core.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat ACTION_SHOW_TEXT_SUGGESTIONS;
+ field public static final androidx.core.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat! ACTION_SHOW_TOOLTIP;
+ }
+
+ public static class AccessibilityNodeInfoCompat.CollectionInfoCompat {
+ method public int getColumnCount();
+ method public int getRowCount();
+ method public int getSelectionMode();
+ method public boolean isHierarchical();
+ method public static androidx.core.view.accessibility.AccessibilityNodeInfoCompat.CollectionInfoCompat! obtain(int, int, boolean, int);
+ method public static androidx.core.view.accessibility.AccessibilityNodeInfoCompat.CollectionInfoCompat! obtain(int, int, boolean);
+ field public static final int SELECTION_MODE_MULTIPLE = 2; // 0x2
+ field public static final int SELECTION_MODE_NONE = 0; // 0x0
+ field public static final int SELECTION_MODE_SINGLE = 1; // 0x1
+ }
+
+ public static class AccessibilityNodeInfoCompat.CollectionItemInfoCompat {
+ method public int getColumnIndex();
+ method public int getColumnSpan();
+ method public int getRowIndex();
+ method public int getRowSpan();
+ method @Deprecated public boolean isHeading();
+ method public boolean isSelected();
+ method public static androidx.core.view.accessibility.AccessibilityNodeInfoCompat.CollectionItemInfoCompat! obtain(int, int, int, int, boolean, boolean);
+ method public static androidx.core.view.accessibility.AccessibilityNodeInfoCompat.CollectionItemInfoCompat! obtain(int, int, int, int, boolean);
+ }
+
+ public static class AccessibilityNodeInfoCompat.RangeInfoCompat {
+ method public float getCurrent();
+ method public float getMax();
+ method public float getMin();
+ method public int getType();
+ method public static androidx.core.view.accessibility.AccessibilityNodeInfoCompat.RangeInfoCompat! obtain(int, float, float, float);
+ field public static final int RANGE_TYPE_FLOAT = 1; // 0x1
+ field public static final int RANGE_TYPE_INT = 0; // 0x0
+ field public static final int RANGE_TYPE_PERCENT = 2; // 0x2
+ }
+
+ public static final class AccessibilityNodeInfoCompat.TouchDelegateInfoCompat {
+ ctor public AccessibilityNodeInfoCompat.TouchDelegateInfoCompat(java.util.Map<android.graphics.Region!,android.view.View!>);
+ method public android.graphics.Region? getRegionAt(@IntRange(from=0) int);
+ method @IntRange(from=0) public int getRegionCount();
+ method public androidx.core.view.accessibility.AccessibilityNodeInfoCompat? getTargetForRegion(android.graphics.Region);
+ }
+
+ public class AccessibilityNodeProviderCompat {
+ ctor public AccessibilityNodeProviderCompat();
+ ctor public AccessibilityNodeProviderCompat(Object?);
+ method public void addExtraDataToAccessibilityNodeInfo(int, androidx.core.view.accessibility.AccessibilityNodeInfoCompat, String, android.os.Bundle?);
+ method public androidx.core.view.accessibility.AccessibilityNodeInfoCompat? createAccessibilityNodeInfo(int);
+ method public java.util.List<androidx.core.view.accessibility.AccessibilityNodeInfoCompat!>? findAccessibilityNodeInfosByText(String, int);
+ method public androidx.core.view.accessibility.AccessibilityNodeInfoCompat? findFocus(int);
+ method public Object? getProvider();
+ method public boolean performAction(int, int, android.os.Bundle?);
+ field public static final int HOST_VIEW_ID = -1; // 0xffffffff
+ }
+
+ public class AccessibilityRecordCompat {
+ ctor @Deprecated public AccessibilityRecordCompat(Object!);
+ method @Deprecated public boolean equals(Object?);
+ method @Deprecated public int getAddedCount();
+ method @Deprecated public CharSequence! getBeforeText();
+ method @Deprecated public CharSequence! getClassName();
+ method @Deprecated public CharSequence! getContentDescription();
+ method @Deprecated public int getCurrentItemIndex();
+ method @Deprecated public int getFromIndex();
+ method @Deprecated public Object! getImpl();
+ method @Deprecated public int getItemCount();
+ method @Deprecated public int getMaxScrollX();
+ method public static int getMaxScrollX(android.view.accessibility.AccessibilityRecord);
+ method @Deprecated public int getMaxScrollY();
+ method public static int getMaxScrollY(android.view.accessibility.AccessibilityRecord);
+ method @Deprecated public android.os.Parcelable! getParcelableData();
+ method @Deprecated public int getRemovedCount();
+ method @Deprecated public int getScrollX();
+ method @Deprecated public int getScrollY();
+ method @Deprecated public androidx.core.view.accessibility.AccessibilityNodeInfoCompat! getSource();
+ method @Deprecated public java.util.List<java.lang.CharSequence!>! getText();
+ method @Deprecated public int getToIndex();
+ method @Deprecated public int getWindowId();
+ method @Deprecated public int hashCode();
+ method @Deprecated public boolean isChecked();
+ method @Deprecated public boolean isEnabled();
+ method @Deprecated public boolean isFullScreen();
+ method @Deprecated public boolean isPassword();
+ method @Deprecated public boolean isScrollable();
+ method @Deprecated public static androidx.core.view.accessibility.AccessibilityRecordCompat! obtain(androidx.core.view.accessibility.AccessibilityRecordCompat!);
+ method @Deprecated public static androidx.core.view.accessibility.AccessibilityRecordCompat! obtain();
+ method @Deprecated public void recycle();
+ method @Deprecated public void setAddedCount(int);
+ method @Deprecated public void setBeforeText(CharSequence!);
+ method @Deprecated public void setChecked(boolean);
+ method @Deprecated public void setClassName(CharSequence!);
+ method @Deprecated public void setContentDescription(CharSequence!);
+ method @Deprecated public void setCurrentItemIndex(int);
+ method @Deprecated public void setEnabled(boolean);
+ method @Deprecated public void setFromIndex(int);
+ method @Deprecated public void setFullScreen(boolean);
+ method @Deprecated public void setItemCount(int);
+ method @Deprecated public void setMaxScrollX(int);
+ method public static void setMaxScrollX(android.view.accessibility.AccessibilityRecord, int);
+ method @Deprecated public void setMaxScrollY(int);
+ method public static void setMaxScrollY(android.view.accessibility.AccessibilityRecord, int);
+ method @Deprecated public void setParcelableData(android.os.Parcelable!);
+ method @Deprecated public void setPassword(boolean);
+ method @Deprecated public void setRemovedCount(int);
+ method @Deprecated public void setScrollX(int);
+ method @Deprecated public void setScrollY(int);
+ method @Deprecated public void setScrollable(boolean);
+ method @Deprecated public void setSource(android.view.View!);
+ method @Deprecated public void setSource(android.view.View!, int);
+ method public static void setSource(android.view.accessibility.AccessibilityRecord, android.view.View?, int);
+ method @Deprecated public void setToIndex(int);
+ }
+
+ public interface AccessibilityViewCommand {
+ method public boolean perform(android.view.View, androidx.core.view.accessibility.AccessibilityViewCommand.CommandArguments?);
+ }
+
+ public abstract static class AccessibilityViewCommand.CommandArguments {
+ ctor public AccessibilityViewCommand.CommandArguments();
+ }
+
+ public static final class AccessibilityViewCommand.MoveAtGranularityArguments extends androidx.core.view.accessibility.AccessibilityViewCommand.CommandArguments {
+ ctor public AccessibilityViewCommand.MoveAtGranularityArguments();
+ method public boolean getExtendSelection();
+ method public int getGranularity();
+ }
+
+ public static final class AccessibilityViewCommand.MoveHtmlArguments extends androidx.core.view.accessibility.AccessibilityViewCommand.CommandArguments {
+ ctor public AccessibilityViewCommand.MoveHtmlArguments();
+ method public String? getHTMLElement();
+ }
+
+ public static final class AccessibilityViewCommand.MoveWindowArguments extends androidx.core.view.accessibility.AccessibilityViewCommand.CommandArguments {
+ ctor public AccessibilityViewCommand.MoveWindowArguments();
+ method public int getX();
+ method public int getY();
+ }
+
+ public static final class AccessibilityViewCommand.ScrollToPositionArguments extends androidx.core.view.accessibility.AccessibilityViewCommand.CommandArguments {
+ ctor public AccessibilityViewCommand.ScrollToPositionArguments();
+ method public int getColumn();
+ method public int getRow();
+ }
+
+ public static final class AccessibilityViewCommand.SetProgressArguments extends androidx.core.view.accessibility.AccessibilityViewCommand.CommandArguments {
+ ctor public AccessibilityViewCommand.SetProgressArguments();
+ method public float getProgress();
+ }
+
+ public static final class AccessibilityViewCommand.SetSelectionArguments extends androidx.core.view.accessibility.AccessibilityViewCommand.CommandArguments {
+ ctor public AccessibilityViewCommand.SetSelectionArguments();
+ method public int getEnd();
+ method public int getStart();
+ }
+
+ public static final class AccessibilityViewCommand.SetTextArguments extends androidx.core.view.accessibility.AccessibilityViewCommand.CommandArguments {
+ ctor public AccessibilityViewCommand.SetTextArguments();
+ method public CharSequence? getText();
+ }
+
+ public class AccessibilityWindowInfoCompat {
+ method public androidx.core.view.accessibility.AccessibilityNodeInfoCompat? getAnchor();
+ method public void getBoundsInScreen(android.graphics.Rect);
+ method public androidx.core.view.accessibility.AccessibilityWindowInfoCompat? getChild(int);
+ method public int getChildCount();
+ method public int getDisplayId();
+ method public int getId();
+ method public int getLayer();
+ method public androidx.core.view.accessibility.AccessibilityWindowInfoCompat? getParent();
+ method public void getRegionInScreen(android.graphics.Region);
+ method public androidx.core.view.accessibility.AccessibilityNodeInfoCompat? getRoot();
+ method public CharSequence? getTitle();
+ method public int getType();
+ method public boolean isAccessibilityFocused();
+ method public boolean isActive();
+ method public boolean isFocused();
+ method public boolean isInPictureInPictureMode();
+ method public static androidx.core.view.accessibility.AccessibilityWindowInfoCompat? obtain();
+ method public static androidx.core.view.accessibility.AccessibilityWindowInfoCompat? obtain(androidx.core.view.accessibility.AccessibilityWindowInfoCompat?);
+ method @Deprecated public void recycle();
+ method public android.view.accessibility.AccessibilityWindowInfo? unwrap();
+ field public static final int TYPE_ACCESSIBILITY_OVERLAY = 4; // 0x4
+ field public static final int TYPE_APPLICATION = 1; // 0x1
+ field public static final int TYPE_INPUT_METHOD = 2; // 0x2
+ field public static final int TYPE_SPLIT_SCREEN_DIVIDER = 5; // 0x5
+ field public static final int TYPE_SYSTEM = 3; // 0x3
+ }
+
+}
+
+package androidx.core.view.animation {
+
+ public final class PathInterpolatorCompat {
+ method public static android.view.animation.Interpolator create(android.graphics.Path);
+ method public static android.view.animation.Interpolator create(float, float);
+ method public static android.view.animation.Interpolator create(float, float, float, float);
+ }
+
+}
+
+package androidx.core.view.inputmethod {
+
+ public final class EditorInfoCompat {
+ ctor @Deprecated public EditorInfoCompat();
+ method public static String![] getContentMimeTypes(android.view.inputmethod.EditorInfo);
+ method public static CharSequence? getInitialSelectedText(android.view.inputmethod.EditorInfo, int);
+ method public static CharSequence? getInitialTextAfterCursor(android.view.inputmethod.EditorInfo, int, int);
+ method public static CharSequence? getInitialTextBeforeCursor(android.view.inputmethod.EditorInfo, int, int);
+ method public static void setContentMimeTypes(android.view.inputmethod.EditorInfo, String![]?);
+ method public static void setInitialSurroundingSubText(android.view.inputmethod.EditorInfo, CharSequence, int);
+ method public static void setInitialSurroundingText(android.view.inputmethod.EditorInfo, CharSequence);
+ field public static final int IME_FLAG_FORCE_ASCII = -2147483648; // 0x80000000
+ field public static final int IME_FLAG_NO_PERSONALIZED_LEARNING = 16777216; // 0x1000000
+ }
+
+ public final class InputConnectionCompat {
+ ctor @Deprecated public InputConnectionCompat();
+ method public static boolean commitContent(android.view.inputmethod.InputConnection, android.view.inputmethod.EditorInfo, androidx.core.view.inputmethod.InputContentInfoCompat, int, android.os.Bundle?);
+ method @Deprecated public static android.view.inputmethod.InputConnection createWrapper(android.view.inputmethod.InputConnection, android.view.inputmethod.EditorInfo, androidx.core.view.inputmethod.InputConnectionCompat.OnCommitContentListener);
+ method public static android.view.inputmethod.InputConnection createWrapper(android.view.View, android.view.inputmethod.InputConnection, android.view.inputmethod.EditorInfo);
+ field public static final int INPUT_CONTENT_GRANT_READ_URI_PERMISSION = 1; // 0x1
+ }
+
+ public static interface InputConnectionCompat.OnCommitContentListener {
+ method public boolean onCommitContent(androidx.core.view.inputmethod.InputContentInfoCompat, int, android.os.Bundle?);
+ }
+
+ public final class InputContentInfoCompat {
+ ctor public InputContentInfoCompat(android.net.Uri, android.content.ClipDescription, android.net.Uri?);
+ method public android.net.Uri getContentUri();
+ method public android.content.ClipDescription getDescription();
+ method public android.net.Uri? getLinkUri();
+ method public void releasePermission();
+ method public void requestPermission();
+ method public Object? unwrap();
+ method public static androidx.core.view.inputmethod.InputContentInfoCompat? wrap(Object?);
+ }
+
+}
+
+package androidx.core.widget {
+
+ public abstract class AutoScrollHelper implements android.view.View.OnTouchListener {
+ ctor public AutoScrollHelper(android.view.View);
+ method public abstract boolean canTargetScrollHorizontally(int);
+ method public abstract boolean canTargetScrollVertically(int);
+ method public boolean isEnabled();
+ method public boolean isExclusive();
+ method public boolean onTouch(android.view.View!, android.view.MotionEvent!);
+ method public abstract void scrollTargetBy(int, int);
+ method public androidx.core.widget.AutoScrollHelper setActivationDelay(int);
+ method public androidx.core.widget.AutoScrollHelper setEdgeType(int);
+ method public androidx.core.widget.AutoScrollHelper! setEnabled(boolean);
+ method public androidx.core.widget.AutoScrollHelper! setExclusive(boolean);
+ method public androidx.core.widget.AutoScrollHelper setMaximumEdges(float, float);
+ method public androidx.core.widget.AutoScrollHelper setMaximumVelocity(float, float);
+ method public androidx.core.widget.AutoScrollHelper setMinimumVelocity(float, float);
+ method public androidx.core.widget.AutoScrollHelper setRampDownDuration(int);
+ method public androidx.core.widget.AutoScrollHelper setRampUpDuration(int);
+ method public androidx.core.widget.AutoScrollHelper setRelativeEdges(float, float);
+ method public androidx.core.widget.AutoScrollHelper setRelativeVelocity(float, float);
+ field public static final int EDGE_TYPE_INSIDE = 0; // 0x0
+ field public static final int EDGE_TYPE_INSIDE_EXTEND = 1; // 0x1
+ field public static final int EDGE_TYPE_OUTSIDE = 2; // 0x2
+ field public static final float NO_MAX = 3.4028235E38f;
+ field public static final float NO_MIN = 0.0f;
+ field public static final float RELATIVE_UNSPECIFIED = 0.0f;
+ }
+
+ public final class CheckedTextViewCompat {
+ method public static android.graphics.drawable.Drawable? getCheckMarkDrawable(android.widget.CheckedTextView);
+ method public static android.content.res.ColorStateList? getCheckMarkTintList(android.widget.CheckedTextView);
+ method public static android.graphics.PorterDuff.Mode? getCheckMarkTintMode(android.widget.CheckedTextView);
+ method public static void setCheckMarkTintList(android.widget.CheckedTextView, android.content.res.ColorStateList?);
+ method public static void setCheckMarkTintMode(android.widget.CheckedTextView, android.graphics.PorterDuff.Mode?);
+ }
+
+ public final class CompoundButtonCompat {
+ method public static android.graphics.drawable.Drawable? getButtonDrawable(android.widget.CompoundButton);
+ method public static android.content.res.ColorStateList? getButtonTintList(android.widget.CompoundButton);
+ method public static android.graphics.PorterDuff.Mode? getButtonTintMode(android.widget.CompoundButton);
+ method public static void setButtonTintList(android.widget.CompoundButton, android.content.res.ColorStateList?);
+ method public static void setButtonTintMode(android.widget.CompoundButton, android.graphics.PorterDuff.Mode?);
+ }
+
+ public class ContentLoadingProgressBar extends android.widget.ProgressBar {
+ ctor public ContentLoadingProgressBar(android.content.Context);
+ ctor public ContentLoadingProgressBar(android.content.Context, android.util.AttributeSet?);
+ method public void hide();
+ method public void onAttachedToWindow();
+ method public void onDetachedFromWindow();
+ method public void show();
+ }
+
+ public final class EdgeEffectCompat {
+ ctor @Deprecated public EdgeEffectCompat(android.content.Context!);
+ method public static android.widget.EdgeEffect create(android.content.Context, android.util.AttributeSet?);
+ method @Deprecated public boolean draw(android.graphics.Canvas!);
+ method @Deprecated public void finish();
+ method public static float getDistance(android.widget.EdgeEffect);
+ method @Deprecated public boolean isFinished();
+ method @Deprecated public boolean onAbsorb(int);
+ method @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);
+ }
+
+ public class ImageViewCompat {
+ method public static android.content.res.ColorStateList? getImageTintList(android.widget.ImageView);
+ method public static android.graphics.PorterDuff.Mode? getImageTintMode(android.widget.ImageView);
+ method public static void setImageTintList(android.widget.ImageView, android.content.res.ColorStateList?);
+ method public static void setImageTintMode(android.widget.ImageView, android.graphics.PorterDuff.Mode?);
+ }
+
+ public final class ListPopupWindowCompat {
+ method @Deprecated public static android.view.View.OnTouchListener! createDragToOpenListener(Object!, android.view.View!);
+ method public static android.view.View.OnTouchListener? createDragToOpenListener(android.widget.ListPopupWindow, android.view.View);
+ }
+
+ public class ListViewAutoScrollHelper extends androidx.core.widget.AutoScrollHelper {
+ ctor public ListViewAutoScrollHelper(android.widget.ListView);
+ method public boolean canTargetScrollHorizontally(int);
+ method public boolean canTargetScrollVertically(int);
+ method public void scrollTargetBy(int, int);
+ }
+
+ public final class ListViewCompat {
+ method public static boolean canScrollList(android.widget.ListView, int);
+ method public static void scrollListBy(android.widget.ListView, int);
+ }
+
+ public class NestedScrollView extends android.widget.FrameLayout implements androidx.core.view.NestedScrollingChild3 androidx.core.view.NestedScrollingParent3 androidx.core.view.ScrollingView {
+ ctor public NestedScrollView(android.content.Context);
+ ctor public NestedScrollView(android.content.Context, android.util.AttributeSet?);
+ ctor public NestedScrollView(android.content.Context, android.util.AttributeSet?, int);
+ method public boolean arrowScroll(int);
+ method @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) public int computeHorizontalScrollExtent();
+ method @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) public int computeHorizontalScrollOffset();
+ method @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) public int computeHorizontalScrollRange();
+ method protected int computeScrollDeltaToGetChildRectOnScreen(android.graphics.Rect!);
+ method @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) public int computeVerticalScrollExtent();
+ method @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) public int computeVerticalScrollOffset();
+ method @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) public int computeVerticalScrollRange();
+ method public boolean dispatchNestedPreScroll(int, int, int[]?, int[]?, int);
+ method public void dispatchNestedScroll(int, int, int, int, int[]?, int, int[]);
+ method public boolean dispatchNestedScroll(int, int, int, int, int[]?, int);
+ method public boolean executeKeyEvent(android.view.KeyEvent);
+ method public void fling(int);
+ method public boolean fullScroll(int);
+ method public int getMaxScrollAmount();
+ method public boolean hasNestedScrollingParent(int);
+ method public boolean isFillViewport();
+ method public boolean isSmoothScrollingEnabled();
+ method public void onAttachedToWindow();
+ method public void onNestedPreScroll(android.view.View, int, int, int[], int);
+ method public void onNestedScroll(android.view.View, int, int, int, int, int, int[]);
+ method public void onNestedScroll(android.view.View, int, int, int, int, int);
+ method public void onNestedScrollAccepted(android.view.View, android.view.View, int, int);
+ method public boolean onStartNestedScroll(android.view.View, android.view.View, int, int);
+ method public void onStopNestedScroll(android.view.View, int);
+ method public boolean pageScroll(int);
+ method public void setFillViewport(boolean);
+ method public void setOnScrollChangeListener(androidx.core.widget.NestedScrollView.OnScrollChangeListener?);
+ method public void setSmoothScrollingEnabled(boolean);
+ method public final void smoothScrollBy(int, int);
+ method public final void smoothScrollBy(int, int, int);
+ method public final void smoothScrollTo(int, int);
+ method public final void smoothScrollTo(int, int, int);
+ method public boolean startNestedScroll(int, int);
+ method public void stopNestedScroll(int);
+ }
+
+ public static interface NestedScrollView.OnScrollChangeListener {
+ method public void onScrollChange(androidx.core.widget.NestedScrollView, int, int, int, int);
+ }
+
+ public final class PopupMenuCompat {
+ method public static android.view.View.OnTouchListener? getDragToOpenListener(Object);
+ }
+
+ public final class PopupWindowCompat {
+ method public static boolean getOverlapAnchor(android.widget.PopupWindow);
+ method public static int getWindowLayoutType(android.widget.PopupWindow);
+ method public static void setOverlapAnchor(android.widget.PopupWindow, boolean);
+ method public static void setWindowLayoutType(android.widget.PopupWindow, int);
+ method public static void showAsDropDown(android.widget.PopupWindow, android.view.View, int, int, int);
+ }
+
+ @Deprecated public final class ScrollerCompat {
+ method @Deprecated public void abortAnimation();
+ method @Deprecated public boolean computeScrollOffset();
+ method @Deprecated public static androidx.core.widget.ScrollerCompat! create(android.content.Context!);
+ method @Deprecated public static androidx.core.widget.ScrollerCompat! create(android.content.Context!, android.view.animation.Interpolator!);
+ method @Deprecated public void fling(int, int, int, int, int, int, int, int);
+ method @Deprecated public void fling(int, int, int, int, int, int, int, int, int, int);
+ method @Deprecated public float getCurrVelocity();
+ method @Deprecated public int getCurrX();
+ method @Deprecated public int getCurrY();
+ method @Deprecated public int getFinalX();
+ method @Deprecated public int getFinalY();
+ method @Deprecated public boolean isFinished();
+ method @Deprecated public boolean isOverScrolled();
+ method @Deprecated public void notifyHorizontalEdgeReached(int, int, int);
+ method @Deprecated public void notifyVerticalEdgeReached(int, int, int);
+ method @Deprecated public boolean springBack(int, int, int, int, int, int);
+ method @Deprecated public void startScroll(int, int, int, int);
+ method @Deprecated public void startScroll(int, int, int, int, int);
+ }
+
+ public final class TextViewCompat {
+ method public static int getAutoSizeMaxTextSize(android.widget.TextView);
+ method public static int getAutoSizeMinTextSize(android.widget.TextView);
+ method public static int getAutoSizeStepGranularity(android.widget.TextView);
+ method public static int[] getAutoSizeTextAvailableSizes(android.widget.TextView);
+ method public static int getAutoSizeTextType(android.widget.TextView);
+ method public static android.content.res.ColorStateList? getCompoundDrawableTintList(android.widget.TextView);
+ method public static android.graphics.PorterDuff.Mode? getCompoundDrawableTintMode(android.widget.TextView);
+ method public static android.graphics.drawable.Drawable![] getCompoundDrawablesRelative(android.widget.TextView);
+ method public static int getFirstBaselineToTopHeight(android.widget.TextView);
+ method public static int getLastBaselineToBottomHeight(android.widget.TextView);
+ method public static int getMaxLines(android.widget.TextView);
+ method public static int getMinLines(android.widget.TextView);
+ method public static androidx.core.text.PrecomputedTextCompat.Params getTextMetricsParams(android.widget.TextView);
+ method public static void setAutoSizeTextTypeUniformWithConfiguration(android.widget.TextView, int, int, int, int) throws java.lang.IllegalArgumentException;
+ method public static void setAutoSizeTextTypeUniformWithPresetSizes(android.widget.TextView, int[], int) throws java.lang.IllegalArgumentException;
+ method public static void setAutoSizeTextTypeWithDefaults(android.widget.TextView, int);
+ method public static void setCompoundDrawableTintList(android.widget.TextView, android.content.res.ColorStateList?);
+ method public static void setCompoundDrawableTintMode(android.widget.TextView, android.graphics.PorterDuff.Mode?);
+ method public static void setCompoundDrawablesRelative(android.widget.TextView, android.graphics.drawable.Drawable?, android.graphics.drawable.Drawable?, android.graphics.drawable.Drawable?, android.graphics.drawable.Drawable?);
+ method public static void setCompoundDrawablesRelativeWithIntrinsicBounds(android.widget.TextView, android.graphics.drawable.Drawable?, android.graphics.drawable.Drawable?, android.graphics.drawable.Drawable?, android.graphics.drawable.Drawable?);
+ method public static void setCompoundDrawablesRelativeWithIntrinsicBounds(android.widget.TextView, @DrawableRes int, @DrawableRes int, @DrawableRes int, @DrawableRes int);
+ method public static void setCustomSelectionActionModeCallback(android.widget.TextView, android.view.ActionMode.Callback);
+ method public static void setFirstBaselineToTopHeight(android.widget.TextView, @IntRange(from=0) @Px int);
+ method public static void setLastBaselineToBottomHeight(android.widget.TextView, @IntRange(from=0) @Px int);
+ method public static void setLineHeight(android.widget.TextView, @IntRange(from=0) @Px int);
+ method public static void setPrecomputedText(android.widget.TextView, androidx.core.text.PrecomputedTextCompat);
+ method public static void setTextAppearance(android.widget.TextView, @StyleRes int);
+ method public static void setTextMetricsParams(android.widget.TextView, androidx.core.text.PrecomputedTextCompat.Params);
+ field public static final int AUTO_SIZE_TEXT_TYPE_NONE = 0; // 0x0
+ field public static final int AUTO_SIZE_TEXT_TYPE_UNIFORM = 1; // 0x1
+ }
+
+ public interface TintableCompoundButton {
+ method public android.content.res.ColorStateList? getSupportButtonTintList();
+ method public android.graphics.PorterDuff.Mode? getSupportButtonTintMode();
+ method public void setSupportButtonTintList(android.content.res.ColorStateList?);
+ method public void setSupportButtonTintMode(android.graphics.PorterDuff.Mode?);
+ }
+
+ public interface TintableCompoundDrawablesView {
+ method public android.content.res.ColorStateList? getSupportCompoundDrawablesTintList();
+ method public android.graphics.PorterDuff.Mode? getSupportCompoundDrawablesTintMode();
+ method public void setSupportCompoundDrawablesTintList(android.content.res.ColorStateList?);
+ method public void setSupportCompoundDrawablesTintMode(android.graphics.PorterDuff.Mode?);
+ }
+
+}
+
diff --git a/core/core/api/current.txt b/core/core/api/current.txt
index 5033a53..c1e6a7e 100644
--- a/core/core/api/current.txt
+++ b/core/core/api/current.txt
@@ -2010,6 +2010,26 @@
}
+package androidx.core.service.quicksettings {
+
+ public class PendingIntentActivityWrapper {
+ ctor public PendingIntentActivityWrapper(android.content.Context, int, android.content.Intent, int, boolean);
+ ctor public PendingIntentActivityWrapper(android.content.Context, int, android.content.Intent, int, android.os.Bundle?, boolean);
+ method public android.content.Context getContext();
+ method public int getFlags();
+ method public android.content.Intent getIntent();
+ method public android.os.Bundle getOptions();
+ method public android.app.PendingIntent? getPendingIntent();
+ method public int getRequestCode();
+ method public boolean isMutable();
+ }
+
+ public class TileServiceCompat {
+ method public static void startActivityAndCollapse(android.service.quicksettings.TileService, androidx.core.service.quicksettings.PendingIntentActivityWrapper);
+ }
+
+}
+
package androidx.core.telephony {
@RequiresApi(22) public class SubscriptionManagerCompat {
@@ -2150,6 +2170,66 @@
method public static boolean addLinks(android.text.Spannable, java.util.regex.Pattern, String?, String![]?, android.text.util.Linkify.MatchFilter?, android.text.util.Linkify.TransformFilter?);
}
+ public final class LocalePreferences {
+ method @RequiresApi(android.os.Build.VERSION_CODES.TIRAMISU) public static String getCalendarType();
+ method @RequiresApi(android.os.Build.VERSION_CODES.TIRAMISU) public static String getCalendarType(java.util.Locale);
+ method @RequiresApi(android.os.Build.VERSION_CODES.TIRAMISU) public static String getCalendarType(boolean);
+ method @RequiresApi(android.os.Build.VERSION_CODES.TIRAMISU) public static String getCalendarType(java.util.Locale, boolean);
+ method @RequiresApi(android.os.Build.VERSION_CODES.TIRAMISU) public static String getFirstDayOfWeek();
+ method @RequiresApi(android.os.Build.VERSION_CODES.TIRAMISU) public static String getFirstDayOfWeek(java.util.Locale);
+ method @RequiresApi(android.os.Build.VERSION_CODES.TIRAMISU) public static String getFirstDayOfWeek(boolean);
+ method @RequiresApi(android.os.Build.VERSION_CODES.TIRAMISU) public static String getFirstDayOfWeek(java.util.Locale, boolean);
+ method @RequiresApi(android.os.Build.VERSION_CODES.TIRAMISU) public static String getHourCycle();
+ method @RequiresApi(android.os.Build.VERSION_CODES.TIRAMISU) public static String getHourCycle(java.util.Locale);
+ method @RequiresApi(android.os.Build.VERSION_CODES.TIRAMISU) public static String getHourCycle(boolean);
+ method @RequiresApi(android.os.Build.VERSION_CODES.TIRAMISU) public static String getHourCycle(java.util.Locale, boolean);
+ method @RequiresApi(android.os.Build.VERSION_CODES.TIRAMISU) public static String getTemperatureUnit();
+ method @RequiresApi(android.os.Build.VERSION_CODES.TIRAMISU) public static String getTemperatureUnit(java.util.Locale);
+ method @RequiresApi(android.os.Build.VERSION_CODES.TIRAMISU) public static String getTemperatureUnit(boolean);
+ method @RequiresApi(android.os.Build.VERSION_CODES.TIRAMISU) public static String getTemperatureUnit(java.util.Locale, boolean);
+ }
+
+ public static class LocalePreferences.CalendarType {
+ field public static final String CHINESE = "chinese";
+ field public static final String DANGI = "dangi";
+ field public static final String DEFAULT = "";
+ field public static final String GREGORIAN = "gregorian";
+ field public static final String HEBREW = "hebrew";
+ field public static final String INDIAN = "indian";
+ field public static final String ISLAMIC = "islamic";
+ field public static final String ISLAMIC_CIVIL = "islamic-civil";
+ field public static final String ISLAMIC_RGSA = "islamic-rgsa";
+ field public static final String ISLAMIC_TBLA = "islamic-tbla";
+ field public static final String ISLAMIC_UMALQURA = "islamic-umalqura";
+ field public static final String PERSIAN = "persian";
+ }
+
+ public static class LocalePreferences.FirstDayOfWeek {
+ field public static final String DEFAULT = "";
+ field public static final String FRIDAY = "fri";
+ field public static final String MONDAY = "mon";
+ field public static final String SATURDAY = "sat";
+ field public static final String SUNDAY = "sun";
+ field public static final String THURSDAY = "thu";
+ field public static final String TUESDAY = "tue";
+ field public static final String WEDNESDAY = "wed";
+ }
+
+ public static class LocalePreferences.HourCycle {
+ field public static final String DEFAULT = "";
+ field public static final String H11 = "h11";
+ field public static final String H12 = "h12";
+ field public static final String H23 = "h23";
+ field public static final String H24 = "h24";
+ }
+
+ public static class LocalePreferences.TemperatureUnit {
+ field public static final String CELSIUS = "celsius";
+ field public static final String DEFAULT = "";
+ field public static final String FAHRENHEIT = "fahrenheit";
+ field public static final String KELVIN = "kelvin";
+ }
+
}
package androidx.core.util {
@@ -2231,6 +2311,14 @@
method public T! get();
}
+ public class TypedValueCompat {
+ method public static float deriveDimension(int, float, android.util.DisplayMetrics);
+ method public static float dpToPx(float, android.util.DisplayMetrics);
+ method public static float pxToDp(float, android.util.DisplayMetrics);
+ method public static float pxToSp(float, android.util.DisplayMetrics);
+ method public static float spToPx(float, android.util.DisplayMetrics);
+ }
+
}
package androidx.core.view {
@@ -2688,9 +2776,12 @@
method public void setSupportBackgroundTintMode(android.graphics.PorterDuff.Mode?);
}
- @Deprecated public final class VelocityTrackerCompat {
+ public final class VelocityTrackerCompat {
+ method public static float getAxisVelocity(android.view.VelocityTracker, int);
+ method public static float getAxisVelocity(android.view.VelocityTracker, int, int);
method @Deprecated public static float getXVelocity(android.view.VelocityTracker!, int);
method @Deprecated public static float getYVelocity(android.view.VelocityTracker!, int);
+ method public static boolean isAxisSupported(android.view.VelocityTracker, int);
}
public class ViewCompat {
@@ -3627,6 +3718,7 @@
}
public class AccessibilityWindowInfoCompat {
+ ctor public AccessibilityWindowInfoCompat();
method public androidx.core.view.accessibility.AccessibilityNodeInfoCompat? getAnchor();
method public void getBoundsInScreen(android.graphics.Rect);
method public androidx.core.view.accessibility.AccessibilityWindowInfoCompat? getChild(int);
diff --git a/core/core/api/public_plus_experimental_1.10.0-beta01.txt b/core/core/api/public_plus_experimental_1.10.0-beta01.txt
new file mode 100644
index 0000000..2b431b6
--- /dev/null
+++ b/core/core/api/public_plus_experimental_1.10.0-beta01.txt
@@ -0,0 +1,3935 @@
+// Signature format: 4.0
+package androidx.core.accessibilityservice {
+
+ public final class AccessibilityServiceInfoCompat {
+ method public static String capabilityToString(int);
+ method public static String feedbackTypeToString(int);
+ method public static String? flagToString(int);
+ method public static int getCapabilities(android.accessibilityservice.AccessibilityServiceInfo);
+ method public static String? loadDescription(android.accessibilityservice.AccessibilityServiceInfo, android.content.pm.PackageManager);
+ field public static final int CAPABILITY_CAN_FILTER_KEY_EVENTS = 8; // 0x8
+ field public static final int CAPABILITY_CAN_REQUEST_ENHANCED_WEB_ACCESSIBILITY = 4; // 0x4
+ field public static final int CAPABILITY_CAN_REQUEST_TOUCH_EXPLORATION = 2; // 0x2
+ field public static final int CAPABILITY_CAN_RETRIEVE_WINDOW_CONTENT = 1; // 0x1
+ field public static final int FEEDBACK_ALL_MASK = -1; // 0xffffffff
+ field public static final int FEEDBACK_BRAILLE = 32; // 0x20
+ field public static final int FLAG_INCLUDE_NOT_IMPORTANT_VIEWS = 2; // 0x2
+ field public static final int FLAG_REPORT_VIEW_IDS = 16; // 0x10
+ field public static final int FLAG_REQUEST_ENHANCED_WEB_ACCESSIBILITY = 8; // 0x8
+ field public static final int FLAG_REQUEST_FILTER_KEY_EVENTS = 32; // 0x20
+ field public static final int FLAG_REQUEST_TOUCH_EXPLORATION_MODE = 4; // 0x4
+ }
+
+}
+
+package androidx.core.app {
+
+ public class ActivityCompat extends androidx.core.content.ContextCompat {
+ ctor protected ActivityCompat();
+ method public static void finishAffinity(android.app.Activity);
+ method public static void finishAfterTransition(android.app.Activity);
+ method public static android.net.Uri? getReferrer(android.app.Activity);
+ method @Deprecated public static boolean invalidateOptionsMenu(android.app.Activity!);
+ method public static boolean isLaunchedFromBubble(android.app.Activity);
+ method public static void postponeEnterTransition(android.app.Activity);
+ method public static void recreate(android.app.Activity);
+ method public static androidx.core.view.DragAndDropPermissionsCompat? requestDragAndDropPermissions(android.app.Activity, android.view.DragEvent);
+ method public static void requestPermissions(android.app.Activity, String![], @IntRange(from=0) int);
+ method public static <T extends android.view.View> T requireViewById(android.app.Activity, @IdRes int);
+ method public static void setEnterSharedElementCallback(android.app.Activity, androidx.core.app.SharedElementCallback?);
+ method public static void setExitSharedElementCallback(android.app.Activity, androidx.core.app.SharedElementCallback?);
+ method public static void setLocusContext(android.app.Activity, androidx.core.content.LocusIdCompat?, android.os.Bundle?);
+ method public static void setPermissionCompatDelegate(androidx.core.app.ActivityCompat.PermissionCompatDelegate?);
+ method public static boolean shouldShowRequestPermissionRationale(android.app.Activity, String);
+ method public static void startActivityForResult(android.app.Activity, android.content.Intent, int, android.os.Bundle?);
+ method public static void startIntentSenderForResult(android.app.Activity, android.content.IntentSender, int, android.content.Intent?, int, int, int, android.os.Bundle?) throws android.content.IntentSender.SendIntentException;
+ method public static void startPostponedEnterTransition(android.app.Activity);
+ }
+
+ public static interface ActivityCompat.OnRequestPermissionsResultCallback {
+ method public void onRequestPermissionsResult(int, String![], int[]);
+ }
+
+ public static interface ActivityCompat.PermissionCompatDelegate {
+ method public boolean onActivityResult(android.app.Activity, @IntRange(from=0) int, int, android.content.Intent?);
+ method public boolean requestPermissions(android.app.Activity, String![], @IntRange(from=0) int);
+ }
+
+ public final class ActivityManagerCompat {
+ method public static boolean isLowRamDevice(android.app.ActivityManager);
+ }
+
+ public class ActivityOptionsCompat {
+ ctor protected ActivityOptionsCompat();
+ method public android.graphics.Rect? getLaunchBounds();
+ method public static androidx.core.app.ActivityOptionsCompat makeBasic();
+ method public static androidx.core.app.ActivityOptionsCompat makeClipRevealAnimation(android.view.View, int, int, int, int);
+ method public static androidx.core.app.ActivityOptionsCompat makeCustomAnimation(android.content.Context, int, int);
+ method public static androidx.core.app.ActivityOptionsCompat makeScaleUpAnimation(android.view.View, int, int, int, int);
+ method public static androidx.core.app.ActivityOptionsCompat makeSceneTransitionAnimation(android.app.Activity, android.view.View, String);
+ method public static androidx.core.app.ActivityOptionsCompat makeSceneTransitionAnimation(android.app.Activity, androidx.core.util.Pair<android.view.View!,java.lang.String!>!...);
+ method public static androidx.core.app.ActivityOptionsCompat makeTaskLaunchBehind();
+ method public static androidx.core.app.ActivityOptionsCompat makeThumbnailScaleUpAnimation(android.view.View, android.graphics.Bitmap, int, int);
+ method public void requestUsageTimeReport(android.app.PendingIntent);
+ method public androidx.core.app.ActivityOptionsCompat setLaunchBounds(android.graphics.Rect?);
+ method public android.os.Bundle? toBundle();
+ method public void update(androidx.core.app.ActivityOptionsCompat);
+ field public static final String EXTRA_USAGE_TIME_REPORT = "android.activity.usage_time";
+ field public static final String EXTRA_USAGE_TIME_REPORT_PACKAGES = "android.usage_time_packages";
+ }
+
+ public final class AlarmManagerCompat {
+ method public static void setAlarmClock(android.app.AlarmManager, long, android.app.PendingIntent, android.app.PendingIntent);
+ method public static void setAndAllowWhileIdle(android.app.AlarmManager, int, long, android.app.PendingIntent);
+ method public static void setExact(android.app.AlarmManager, int, long, android.app.PendingIntent);
+ method public static void setExactAndAllowWhileIdle(android.app.AlarmManager, int, long, android.app.PendingIntent);
+ }
+
+ @RequiresApi(28) public class AppComponentFactory extends android.app.AppComponentFactory {
+ ctor public AppComponentFactory();
+ method public final android.app.Activity instantiateActivity(ClassLoader, String, android.content.Intent?) throws java.lang.ClassNotFoundException, java.lang.IllegalAccessException, java.lang.InstantiationException;
+ method public android.app.Activity instantiateActivityCompat(ClassLoader, String, android.content.Intent?) throws java.lang.ClassNotFoundException, java.lang.IllegalAccessException, java.lang.InstantiationException;
+ method public final android.app.Application instantiateApplication(ClassLoader, String) throws java.lang.ClassNotFoundException, java.lang.IllegalAccessException, java.lang.InstantiationException;
+ method public android.app.Application instantiateApplicationCompat(ClassLoader, String) throws java.lang.ClassNotFoundException, java.lang.IllegalAccessException, java.lang.InstantiationException;
+ method public final android.content.ContentProvider instantiateProvider(ClassLoader, String) throws java.lang.ClassNotFoundException, java.lang.IllegalAccessException, java.lang.InstantiationException;
+ method public android.content.ContentProvider instantiateProviderCompat(ClassLoader, String) throws java.lang.ClassNotFoundException, java.lang.IllegalAccessException, java.lang.InstantiationException;
+ method public final android.content.BroadcastReceiver instantiateReceiver(ClassLoader, String, android.content.Intent?) throws java.lang.ClassNotFoundException, java.lang.IllegalAccessException, java.lang.InstantiationException;
+ method public android.content.BroadcastReceiver instantiateReceiverCompat(ClassLoader, String, android.content.Intent?) throws java.lang.ClassNotFoundException, java.lang.IllegalAccessException, java.lang.InstantiationException;
+ method public final android.app.Service instantiateService(ClassLoader, String, android.content.Intent?) throws java.lang.ClassNotFoundException, java.lang.IllegalAccessException, java.lang.InstantiationException;
+ method public android.app.Service instantiateServiceCompat(ClassLoader, String, android.content.Intent?) throws java.lang.ClassNotFoundException, java.lang.IllegalAccessException, java.lang.InstantiationException;
+ }
+
+ public class AppLaunchChecker {
+ ctor @Deprecated public AppLaunchChecker();
+ method public static boolean hasStartedFromLauncher(android.content.Context);
+ method public static void onActivityCreate(android.app.Activity);
+ }
+
+ public final class AppOpsManagerCompat {
+ method public static int checkOrNoteProxyOp(android.content.Context, int, String, String);
+ method public static int noteOp(android.content.Context, String, int, String);
+ method public static int noteOpNoThrow(android.content.Context, String, int, String);
+ method public static int noteProxyOp(android.content.Context, String, String);
+ method public static int noteProxyOpNoThrow(android.content.Context, String, String);
+ method public static String? permissionToOp(String);
+ field public static final int MODE_ALLOWED = 0; // 0x0
+ field public static final int MODE_DEFAULT = 3; // 0x3
+ field public static final int MODE_ERRORED = 2; // 0x2
+ field public static final int MODE_IGNORED = 1; // 0x1
+ }
+
+ public final class BundleCompat {
+ method public static android.os.IBinder? getBinder(android.os.Bundle, String?);
+ method public static void putBinder(android.os.Bundle, String?, android.os.IBinder?);
+ }
+
+ public class DialogCompat {
+ method public static android.view.View requireViewById(android.app.Dialog, int);
+ }
+
+ public class FrameMetricsAggregator {
+ ctor public FrameMetricsAggregator();
+ ctor public FrameMetricsAggregator(int);
+ method public void add(android.app.Activity);
+ method public android.util.SparseIntArray![]? getMetrics();
+ method public android.util.SparseIntArray![]? remove(android.app.Activity);
+ method public android.util.SparseIntArray![]? reset();
+ method public android.util.SparseIntArray![]? stop();
+ field public static final int ANIMATION_DURATION = 256; // 0x100
+ field public static final int ANIMATION_INDEX = 8; // 0x8
+ field public static final int COMMAND_DURATION = 32; // 0x20
+ field public static final int COMMAND_INDEX = 5; // 0x5
+ field public static final int DELAY_DURATION = 128; // 0x80
+ field public static final int DELAY_INDEX = 7; // 0x7
+ field public static final int DRAW_DURATION = 8; // 0x8
+ field public static final int DRAW_INDEX = 3; // 0x3
+ field public static final int EVERY_DURATION = 511; // 0x1ff
+ field public static final int INPUT_DURATION = 2; // 0x2
+ field public static final int INPUT_INDEX = 1; // 0x1
+ field public static final int LAYOUT_MEASURE_DURATION = 4; // 0x4
+ field public static final int LAYOUT_MEASURE_INDEX = 2; // 0x2
+ field public static final int SWAP_DURATION = 64; // 0x40
+ field public static final int SWAP_INDEX = 6; // 0x6
+ field public static final int SYNC_DURATION = 16; // 0x10
+ field public static final int SYNC_INDEX = 4; // 0x4
+ field public static final int TOTAL_DURATION = 1; // 0x1
+ field public static final int TOTAL_INDEX = 0; // 0x0
+ }
+
+ @Deprecated public abstract class JobIntentService extends android.app.Service {
+ ctor @Deprecated public JobIntentService();
+ method @Deprecated public static void enqueueWork(android.content.Context, Class<?>, int, android.content.Intent);
+ method @Deprecated public static void enqueueWork(android.content.Context, android.content.ComponentName, int, android.content.Intent);
+ method @Deprecated public boolean isStopped();
+ method @Deprecated public android.os.IBinder! onBind(android.content.Intent);
+ method @Deprecated protected abstract void onHandleWork(android.content.Intent);
+ method @Deprecated public boolean onStopCurrentWork();
+ method @Deprecated public void setInterruptIfStopped(boolean);
+ }
+
+ public final class LocaleManagerCompat {
+ method @AnyThread public static androidx.core.os.LocaleListCompat getSystemLocales(android.content.Context);
+ }
+
+ public final class MultiWindowModeChangedInfo {
+ ctor public MultiWindowModeChangedInfo(boolean);
+ ctor @RequiresApi(26) public MultiWindowModeChangedInfo(boolean, android.content.res.Configuration);
+ method @RequiresApi(26) public android.content.res.Configuration getNewConfig();
+ method public boolean isInMultiWindowMode();
+ }
+
+ public final class NavUtils {
+ method public static android.content.Intent? getParentActivityIntent(android.app.Activity);
+ method public static android.content.Intent? getParentActivityIntent(android.content.Context, Class<?>) throws android.content.pm.PackageManager.NameNotFoundException;
+ method public static android.content.Intent? getParentActivityIntent(android.content.Context, android.content.ComponentName) throws android.content.pm.PackageManager.NameNotFoundException;
+ method public static String? getParentActivityName(android.app.Activity);
+ method public static String? getParentActivityName(android.content.Context, android.content.ComponentName) throws android.content.pm.PackageManager.NameNotFoundException;
+ method public static void navigateUpFromSameTask(android.app.Activity);
+ method public static void navigateUpTo(android.app.Activity, android.content.Intent);
+ method public static boolean shouldUpRecreateTask(android.app.Activity, android.content.Intent);
+ field public static final String PARENT_ACTIVITY = "android.support.PARENT_ACTIVITY";
+ }
+
+ public class NotificationChannelCompat {
+ method public boolean canBubble();
+ method public boolean canBypassDnd();
+ method public boolean canShowBadge();
+ method public android.media.AudioAttributes? getAudioAttributes();
+ method public String? getConversationId();
+ method public String? getDescription();
+ method public String? getGroup();
+ method public String getId();
+ method public int getImportance();
+ method public int getLightColor();
+ method public int getLockscreenVisibility();
+ method public CharSequence? getName();
+ method public String? getParentChannelId();
+ method public android.net.Uri? getSound();
+ method public long[]? getVibrationPattern();
+ method public boolean isImportantConversation();
+ method public boolean shouldShowLights();
+ method public boolean shouldVibrate();
+ method public androidx.core.app.NotificationChannelCompat.Builder toBuilder();
+ field public static final String DEFAULT_CHANNEL_ID = "miscellaneous";
+ }
+
+ public static class NotificationChannelCompat.Builder {
+ ctor public NotificationChannelCompat.Builder(String, int);
+ method public androidx.core.app.NotificationChannelCompat build();
+ method public androidx.core.app.NotificationChannelCompat.Builder setConversationId(String, String);
+ method public androidx.core.app.NotificationChannelCompat.Builder setDescription(String?);
+ method public androidx.core.app.NotificationChannelCompat.Builder setGroup(String?);
+ method public androidx.core.app.NotificationChannelCompat.Builder setImportance(int);
+ method public androidx.core.app.NotificationChannelCompat.Builder setLightColor(int);
+ method public androidx.core.app.NotificationChannelCompat.Builder setLightsEnabled(boolean);
+ method public androidx.core.app.NotificationChannelCompat.Builder setName(CharSequence?);
+ method public androidx.core.app.NotificationChannelCompat.Builder setShowBadge(boolean);
+ method public androidx.core.app.NotificationChannelCompat.Builder setSound(android.net.Uri?, android.media.AudioAttributes?);
+ method public androidx.core.app.NotificationChannelCompat.Builder setVibrationEnabled(boolean);
+ method public androidx.core.app.NotificationChannelCompat.Builder setVibrationPattern(long[]?);
+ }
+
+ public class NotificationChannelGroupCompat {
+ method public java.util.List<androidx.core.app.NotificationChannelCompat!> getChannels();
+ method public String? getDescription();
+ method public String getId();
+ method public CharSequence? getName();
+ method public boolean isBlocked();
+ method public androidx.core.app.NotificationChannelGroupCompat.Builder toBuilder();
+ }
+
+ public static class NotificationChannelGroupCompat.Builder {
+ ctor public NotificationChannelGroupCompat.Builder(String);
+ method public androidx.core.app.NotificationChannelGroupCompat build();
+ method public androidx.core.app.NotificationChannelGroupCompat.Builder setDescription(String?);
+ method public androidx.core.app.NotificationChannelGroupCompat.Builder setName(CharSequence?);
+ }
+
+ public class NotificationCompat {
+ ctor @Deprecated public NotificationCompat();
+ method public static androidx.core.app.NotificationCompat.Action? getAction(android.app.Notification, int);
+ method public static int getActionCount(android.app.Notification);
+ method public static boolean getAllowSystemGeneratedContextualActions(android.app.Notification);
+ method public static boolean getAutoCancel(android.app.Notification);
+ method public static int getBadgeIconType(android.app.Notification);
+ method public static androidx.core.app.NotificationCompat.BubbleMetadata? getBubbleMetadata(android.app.Notification);
+ method public static String? getCategory(android.app.Notification);
+ method public static String? getChannelId(android.app.Notification);
+ method public static int getColor(android.app.Notification);
+ method @RequiresApi(19) public static CharSequence? getContentInfo(android.app.Notification);
+ method @RequiresApi(19) public static CharSequence? getContentText(android.app.Notification);
+ method @RequiresApi(19) public static CharSequence? getContentTitle(android.app.Notification);
+ method public static android.os.Bundle? getExtras(android.app.Notification);
+ method public static String? getGroup(android.app.Notification);
+ method public static int getGroupAlertBehavior(android.app.Notification);
+ method @RequiresApi(21) public static java.util.List<androidx.core.app.NotificationCompat.Action!> getInvisibleActions(android.app.Notification);
+ method public static boolean getLocalOnly(android.app.Notification);
+ method public static androidx.core.content.LocusIdCompat? getLocusId(android.app.Notification);
+ method public static boolean getOngoing(android.app.Notification);
+ method public static boolean getOnlyAlertOnce(android.app.Notification);
+ method public static java.util.List<androidx.core.app.Person!> getPeople(android.app.Notification);
+ method public static android.app.Notification? getPublicVersion(android.app.Notification);
+ method public static CharSequence? getSettingsText(android.app.Notification);
+ method public static String? getShortcutId(android.app.Notification);
+ method @RequiresApi(19) public static boolean getShowWhen(android.app.Notification);
+ method public static String? getSortKey(android.app.Notification);
+ method @RequiresApi(19) public static CharSequence? getSubText(android.app.Notification);
+ method public static long getTimeoutAfter(android.app.Notification);
+ method @RequiresApi(19) public static boolean getUsesChronometer(android.app.Notification);
+ method public static int getVisibility(android.app.Notification);
+ method public static boolean isGroupSummary(android.app.Notification);
+ field public static final int BADGE_ICON_LARGE = 2; // 0x2
+ field public static final int BADGE_ICON_NONE = 0; // 0x0
+ field public static final int BADGE_ICON_SMALL = 1; // 0x1
+ field public static final String CATEGORY_ALARM = "alarm";
+ field public static final String CATEGORY_CALL = "call";
+ field public static final String CATEGORY_EMAIL = "email";
+ field public static final String CATEGORY_ERROR = "err";
+ field public static final String CATEGORY_EVENT = "event";
+ field public static final String CATEGORY_LOCATION_SHARING = "location_sharing";
+ field public static final String CATEGORY_MESSAGE = "msg";
+ field public static final String CATEGORY_MISSED_CALL = "missed_call";
+ field public static final String CATEGORY_NAVIGATION = "navigation";
+ field public static final String CATEGORY_PROGRESS = "progress";
+ field public static final String CATEGORY_PROMO = "promo";
+ field public static final String CATEGORY_RECOMMENDATION = "recommendation";
+ field public static final String CATEGORY_REMINDER = "reminder";
+ field public static final String CATEGORY_SERVICE = "service";
+ field public static final String CATEGORY_SOCIAL = "social";
+ field public static final String CATEGORY_STATUS = "status";
+ field public static final String CATEGORY_STOPWATCH = "stopwatch";
+ field public static final String CATEGORY_SYSTEM = "sys";
+ field public static final String CATEGORY_TRANSPORT = "transport";
+ field public static final String CATEGORY_WORKOUT = "workout";
+ field @ColorInt public static final int COLOR_DEFAULT = 0; // 0x0
+ field public static final int DEFAULT_ALL = -1; // 0xffffffff
+ field public static final int DEFAULT_LIGHTS = 4; // 0x4
+ field public static final int DEFAULT_SOUND = 1; // 0x1
+ field public static final int DEFAULT_VIBRATE = 2; // 0x2
+ field public static final String EXTRA_ANSWER_COLOR = "android.answerColor";
+ field public static final String EXTRA_ANSWER_INTENT = "android.answerIntent";
+ field public static final String EXTRA_AUDIO_CONTENTS_URI = "android.audioContents";
+ field public static final String EXTRA_BACKGROUND_IMAGE_URI = "android.backgroundImageUri";
+ field public static final String EXTRA_BIG_TEXT = "android.bigText";
+ field public static final String EXTRA_CALL_IS_VIDEO = "android.callIsVideo";
+ field public static final String EXTRA_CALL_PERSON = "android.callPerson";
+ field public static final String EXTRA_CALL_PERSON_COMPAT = "android.callPersonCompat";
+ field public static final String EXTRA_CALL_TYPE = "android.callType";
+ field public static final String EXTRA_CHANNEL_GROUP_ID = "android.intent.extra.CHANNEL_GROUP_ID";
+ field public static final String EXTRA_CHANNEL_ID = "android.intent.extra.CHANNEL_ID";
+ field public static final String EXTRA_CHRONOMETER_COUNT_DOWN = "android.chronometerCountDown";
+ field public static final String EXTRA_COLORIZED = "android.colorized";
+ field public static final String EXTRA_COMPACT_ACTIONS = "android.compactActions";
+ field public static final String EXTRA_COMPAT_TEMPLATE = "androidx.core.app.extra.COMPAT_TEMPLATE";
+ field public static final String EXTRA_CONVERSATION_TITLE = "android.conversationTitle";
+ field public static final String EXTRA_DECLINE_COLOR = "android.declineColor";
+ field public static final String EXTRA_DECLINE_INTENT = "android.declineIntent";
+ field public static final String EXTRA_HANG_UP_INTENT = "android.hangUpIntent";
+ field public static final String EXTRA_HIDDEN_CONVERSATION_TITLE = "android.hiddenConversationTitle";
+ field public static final String EXTRA_HISTORIC_MESSAGES = "android.messages.historic";
+ field public static final String EXTRA_INFO_TEXT = "android.infoText";
+ field public static final String EXTRA_IS_GROUP_CONVERSATION = "android.isGroupConversation";
+ field public static final String EXTRA_LARGE_ICON = "android.largeIcon";
+ field public static final String EXTRA_LARGE_ICON_BIG = "android.largeIcon.big";
+ field public static final String EXTRA_MEDIA_SESSION = "android.mediaSession";
+ field public static final String EXTRA_MESSAGES = "android.messages";
+ field public static final String EXTRA_MESSAGING_STYLE_USER = "android.messagingStyleUser";
+ field public static final String EXTRA_NOTIFICATION_ID = "android.intent.extra.NOTIFICATION_ID";
+ field public static final String EXTRA_NOTIFICATION_TAG = "android.intent.extra.NOTIFICATION_TAG";
+ field @Deprecated public static final String EXTRA_PEOPLE = "android.people";
+ field public static final String EXTRA_PEOPLE_LIST = "android.people.list";
+ field public static final String EXTRA_PICTURE = "android.picture";
+ field public static final String EXTRA_PICTURE_CONTENT_DESCRIPTION = "android.pictureContentDescription";
+ field public static final String EXTRA_PICTURE_ICON = "android.pictureIcon";
+ field public static final String EXTRA_PROGRESS = "android.progress";
+ field public static final String EXTRA_PROGRESS_INDETERMINATE = "android.progressIndeterminate";
+ field public static final String EXTRA_PROGRESS_MAX = "android.progressMax";
+ field public static final String EXTRA_REMOTE_INPUT_HISTORY = "android.remoteInputHistory";
+ field public static final String EXTRA_SELF_DISPLAY_NAME = "android.selfDisplayName";
+ field public static final String EXTRA_SHOW_BIG_PICTURE_WHEN_COLLAPSED = "android.showBigPictureWhenCollapsed";
+ field public static final String EXTRA_SHOW_CHRONOMETER = "android.showChronometer";
+ field public static final String EXTRA_SHOW_WHEN = "android.showWhen";
+ field public static final String EXTRA_SMALL_ICON = "android.icon";
+ field public static final String EXTRA_SUB_TEXT = "android.subText";
+ field public static final String EXTRA_SUMMARY_TEXT = "android.summaryText";
+ field public static final String EXTRA_TEMPLATE = "android.template";
+ field public static final String EXTRA_TEXT = "android.text";
+ field public static final String EXTRA_TEXT_LINES = "android.textLines";
+ field public static final String EXTRA_TITLE = "android.title";
+ field public static final String EXTRA_TITLE_BIG = "android.title.big";
+ field public static final String EXTRA_VERIFICATION_ICON = "android.verificationIcon";
+ field public static final String EXTRA_VERIFICATION_ICON_COMPAT = "android.verificationIconCompat";
+ field public static final String EXTRA_VERIFICATION_TEXT = "android.verificationText";
+ field public static final int FLAG_AUTO_CANCEL = 16; // 0x10
+ field public static final int FLAG_BUBBLE = 4096; // 0x1000
+ field public static final int FLAG_FOREGROUND_SERVICE = 64; // 0x40
+ field public static final int FLAG_GROUP_SUMMARY = 512; // 0x200
+ field @Deprecated public static final int FLAG_HIGH_PRIORITY = 128; // 0x80
+ field public static final int FLAG_INSISTENT = 4; // 0x4
+ field public static final int FLAG_LOCAL_ONLY = 256; // 0x100
+ field public static final int FLAG_NO_CLEAR = 32; // 0x20
+ field public static final int FLAG_ONGOING_EVENT = 2; // 0x2
+ field public static final int FLAG_ONLY_ALERT_ONCE = 8; // 0x8
+ field public static final int FLAG_SHOW_LIGHTS = 1; // 0x1
+ field public static final int FOREGROUND_SERVICE_DEFAULT = 0; // 0x0
+ field public static final int FOREGROUND_SERVICE_DEFERRED = 2; // 0x2
+ field public static final int FOREGROUND_SERVICE_IMMEDIATE = 1; // 0x1
+ field public static final int GROUP_ALERT_ALL = 0; // 0x0
+ field public static final int GROUP_ALERT_CHILDREN = 2; // 0x2
+ field public static final int GROUP_ALERT_SUMMARY = 1; // 0x1
+ field public static final String GROUP_KEY_SILENT = "silent";
+ field public static final String INTENT_CATEGORY_NOTIFICATION_PREFERENCES = "android.intent.category.NOTIFICATION_PREFERENCES";
+ field public static final int PRIORITY_DEFAULT = 0; // 0x0
+ field public static final int PRIORITY_HIGH = 1; // 0x1
+ field public static final int PRIORITY_LOW = -1; // 0xffffffff
+ field public static final int PRIORITY_MAX = 2; // 0x2
+ field public static final int PRIORITY_MIN = -2; // 0xfffffffe
+ field public static final int STREAM_DEFAULT = -1; // 0xffffffff
+ field public static final int VISIBILITY_PRIVATE = 0; // 0x0
+ field public static final int VISIBILITY_PUBLIC = 1; // 0x1
+ field public static final int VISIBILITY_SECRET = -1; // 0xffffffff
+ }
+
+ public static class NotificationCompat.Action {
+ ctor public NotificationCompat.Action(int, CharSequence?, android.app.PendingIntent?);
+ ctor public NotificationCompat.Action(androidx.core.graphics.drawable.IconCompat?, CharSequence?, android.app.PendingIntent?);
+ method public android.app.PendingIntent? getActionIntent();
+ method public boolean getAllowGeneratedReplies();
+ method public androidx.core.app.RemoteInput![]? getDataOnlyRemoteInputs();
+ method public android.os.Bundle getExtras();
+ method @Deprecated public int getIcon();
+ method public androidx.core.graphics.drawable.IconCompat? getIconCompat();
+ method public androidx.core.app.RemoteInput![]? getRemoteInputs();
+ method @androidx.core.app.NotificationCompat.Action.SemanticAction public int getSemanticAction();
+ method public boolean getShowsUserInterface();
+ method public CharSequence? getTitle();
+ method public boolean isAuthenticationRequired();
+ method public boolean isContextual();
+ field public static final int SEMANTIC_ACTION_ARCHIVE = 5; // 0x5
+ field public static final int SEMANTIC_ACTION_CALL = 10; // 0xa
+ field public static final int SEMANTIC_ACTION_DELETE = 4; // 0x4
+ field public static final int SEMANTIC_ACTION_MARK_AS_READ = 2; // 0x2
+ field public static final int SEMANTIC_ACTION_MARK_AS_UNREAD = 3; // 0x3
+ field public static final int SEMANTIC_ACTION_MUTE = 6; // 0x6
+ field public static final int SEMANTIC_ACTION_NONE = 0; // 0x0
+ field public static final int SEMANTIC_ACTION_REPLY = 1; // 0x1
+ field public static final int SEMANTIC_ACTION_THUMBS_DOWN = 9; // 0x9
+ field public static final int SEMANTIC_ACTION_THUMBS_UP = 8; // 0x8
+ field public static final int SEMANTIC_ACTION_UNMUTE = 7; // 0x7
+ field public android.app.PendingIntent? actionIntent;
+ field @Deprecated public int icon;
+ field public CharSequence! title;
+ }
+
+ public static final class NotificationCompat.Action.Builder {
+ ctor public NotificationCompat.Action.Builder(androidx.core.graphics.drawable.IconCompat?, CharSequence?, android.app.PendingIntent?);
+ ctor public NotificationCompat.Action.Builder(int, CharSequence?, android.app.PendingIntent?);
+ ctor public NotificationCompat.Action.Builder(androidx.core.app.NotificationCompat.Action);
+ method public androidx.core.app.NotificationCompat.Action.Builder addExtras(android.os.Bundle?);
+ method public androidx.core.app.NotificationCompat.Action.Builder addRemoteInput(androidx.core.app.RemoteInput?);
+ method public androidx.core.app.NotificationCompat.Action build();
+ method public androidx.core.app.NotificationCompat.Action.Builder extend(androidx.core.app.NotificationCompat.Action.Extender);
+ method public android.os.Bundle getExtras();
+ method public androidx.core.app.NotificationCompat.Action.Builder setAllowGeneratedReplies(boolean);
+ method public androidx.core.app.NotificationCompat.Action.Builder setAuthenticationRequired(boolean);
+ method public androidx.core.app.NotificationCompat.Action.Builder setContextual(boolean);
+ method public androidx.core.app.NotificationCompat.Action.Builder setSemanticAction(@androidx.core.app.NotificationCompat.Action.SemanticAction int);
+ method public androidx.core.app.NotificationCompat.Action.Builder setShowsUserInterface(boolean);
+ }
+
+ public static interface NotificationCompat.Action.Extender {
+ method public androidx.core.app.NotificationCompat.Action.Builder extend(androidx.core.app.NotificationCompat.Action.Builder);
+ }
+
+ @IntDef({androidx.core.app.NotificationCompat.Action.SEMANTIC_ACTION_NONE, androidx.core.app.NotificationCompat.Action.SEMANTIC_ACTION_REPLY, androidx.core.app.NotificationCompat.Action.SEMANTIC_ACTION_MARK_AS_READ, androidx.core.app.NotificationCompat.Action.SEMANTIC_ACTION_MARK_AS_UNREAD, androidx.core.app.NotificationCompat.Action.SEMANTIC_ACTION_DELETE, androidx.core.app.NotificationCompat.Action.SEMANTIC_ACTION_ARCHIVE, androidx.core.app.NotificationCompat.Action.SEMANTIC_ACTION_MUTE, androidx.core.app.NotificationCompat.Action.SEMANTIC_ACTION_UNMUTE, androidx.core.app.NotificationCompat.Action.SEMANTIC_ACTION_THUMBS_UP, androidx.core.app.NotificationCompat.Action.SEMANTIC_ACTION_THUMBS_DOWN, androidx.core.app.NotificationCompat.Action.SEMANTIC_ACTION_CALL}) @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.SOURCE) public static @interface NotificationCompat.Action.SemanticAction {
+ }
+
+ public static final class NotificationCompat.Action.WearableExtender implements androidx.core.app.NotificationCompat.Action.Extender {
+ ctor public NotificationCompat.Action.WearableExtender();
+ ctor public NotificationCompat.Action.WearableExtender(androidx.core.app.NotificationCompat.Action);
+ method public androidx.core.app.NotificationCompat.Action.WearableExtender clone();
+ method public androidx.core.app.NotificationCompat.Action.Builder extend(androidx.core.app.NotificationCompat.Action.Builder);
+ method @Deprecated public CharSequence? getCancelLabel();
+ method @Deprecated public CharSequence? getConfirmLabel();
+ method public boolean getHintDisplayActionInline();
+ method public boolean getHintLaunchesActivity();
+ method @Deprecated public CharSequence? getInProgressLabel();
+ method public boolean isAvailableOffline();
+ method public androidx.core.app.NotificationCompat.Action.WearableExtender setAvailableOffline(boolean);
+ method @Deprecated public androidx.core.app.NotificationCompat.Action.WearableExtender setCancelLabel(CharSequence?);
+ method @Deprecated public androidx.core.app.NotificationCompat.Action.WearableExtender setConfirmLabel(CharSequence?);
+ method public androidx.core.app.NotificationCompat.Action.WearableExtender setHintDisplayActionInline(boolean);
+ method public androidx.core.app.NotificationCompat.Action.WearableExtender setHintLaunchesActivity(boolean);
+ method @Deprecated public androidx.core.app.NotificationCompat.Action.WearableExtender setInProgressLabel(CharSequence?);
+ }
+
+ public static class NotificationCompat.BigPictureStyle extends androidx.core.app.NotificationCompat.Style {
+ ctor public NotificationCompat.BigPictureStyle();
+ ctor public NotificationCompat.BigPictureStyle(androidx.core.app.NotificationCompat.Builder?);
+ method public androidx.core.app.NotificationCompat.BigPictureStyle bigLargeIcon(android.graphics.Bitmap?);
+ method @RequiresApi(23) public androidx.core.app.NotificationCompat.BigPictureStyle bigLargeIcon(android.graphics.drawable.Icon?);
+ method public androidx.core.app.NotificationCompat.BigPictureStyle bigPicture(android.graphics.Bitmap?);
+ method @RequiresApi(31) public androidx.core.app.NotificationCompat.BigPictureStyle bigPicture(android.graphics.drawable.Icon?);
+ method public androidx.core.app.NotificationCompat.BigPictureStyle setBigContentTitle(CharSequence?);
+ method @RequiresApi(31) public androidx.core.app.NotificationCompat.BigPictureStyle setContentDescription(CharSequence?);
+ method public androidx.core.app.NotificationCompat.BigPictureStyle setSummaryText(CharSequence?);
+ method @RequiresApi(31) public androidx.core.app.NotificationCompat.BigPictureStyle showBigPictureWhenCollapsed(boolean);
+ }
+
+ public static class NotificationCompat.BigTextStyle extends androidx.core.app.NotificationCompat.Style {
+ ctor public NotificationCompat.BigTextStyle();
+ ctor public NotificationCompat.BigTextStyle(androidx.core.app.NotificationCompat.Builder?);
+ method public androidx.core.app.NotificationCompat.BigTextStyle bigText(CharSequence?);
+ method public androidx.core.app.NotificationCompat.BigTextStyle setBigContentTitle(CharSequence?);
+ method public androidx.core.app.NotificationCompat.BigTextStyle setSummaryText(CharSequence?);
+ }
+
+ public static final class NotificationCompat.BubbleMetadata {
+ method public static androidx.core.app.NotificationCompat.BubbleMetadata? fromPlatform(android.app.Notification.BubbleMetadata?);
+ method public boolean getAutoExpandBubble();
+ method public android.app.PendingIntent? getDeleteIntent();
+ method @Dimension(unit=androidx.annotation.Dimension.DP) public int getDesiredHeight();
+ method @DimenRes public int getDesiredHeightResId();
+ method public androidx.core.graphics.drawable.IconCompat? getIcon();
+ method public android.app.PendingIntent? getIntent();
+ method public String? getShortcutId();
+ method public boolean isNotificationSuppressed();
+ method public static android.app.Notification.BubbleMetadata? toPlatform(androidx.core.app.NotificationCompat.BubbleMetadata?);
+ }
+
+ public static final class NotificationCompat.BubbleMetadata.Builder {
+ ctor @Deprecated public NotificationCompat.BubbleMetadata.Builder();
+ ctor @RequiresApi(30) public NotificationCompat.BubbleMetadata.Builder(String);
+ ctor public NotificationCompat.BubbleMetadata.Builder(android.app.PendingIntent, androidx.core.graphics.drawable.IconCompat);
+ method public androidx.core.app.NotificationCompat.BubbleMetadata build();
+ method public androidx.core.app.NotificationCompat.BubbleMetadata.Builder setAutoExpandBubble(boolean);
+ method public androidx.core.app.NotificationCompat.BubbleMetadata.Builder setDeleteIntent(android.app.PendingIntent?);
+ method public androidx.core.app.NotificationCompat.BubbleMetadata.Builder setDesiredHeight(@Dimension(unit=androidx.annotation.Dimension.DP) int);
+ method public androidx.core.app.NotificationCompat.BubbleMetadata.Builder setDesiredHeightResId(@DimenRes int);
+ method public androidx.core.app.NotificationCompat.BubbleMetadata.Builder setIcon(androidx.core.graphics.drawable.IconCompat);
+ method public androidx.core.app.NotificationCompat.BubbleMetadata.Builder setIntent(android.app.PendingIntent);
+ method public androidx.core.app.NotificationCompat.BubbleMetadata.Builder setSuppressNotification(boolean);
+ }
+
+ public static class NotificationCompat.Builder {
+ ctor @RequiresApi(19) public NotificationCompat.Builder(android.content.Context, android.app.Notification);
+ ctor public NotificationCompat.Builder(android.content.Context, String);
+ ctor @Deprecated public NotificationCompat.Builder(android.content.Context);
+ method public androidx.core.app.NotificationCompat.Builder addAction(int, CharSequence?, android.app.PendingIntent?);
+ method public androidx.core.app.NotificationCompat.Builder addAction(androidx.core.app.NotificationCompat.Action?);
+ method public androidx.core.app.NotificationCompat.Builder addExtras(android.os.Bundle?);
+ method @RequiresApi(21) public androidx.core.app.NotificationCompat.Builder addInvisibleAction(int, CharSequence?, android.app.PendingIntent?);
+ method @RequiresApi(21) public androidx.core.app.NotificationCompat.Builder addInvisibleAction(androidx.core.app.NotificationCompat.Action?);
+ method @Deprecated public androidx.core.app.NotificationCompat.Builder addPerson(String?);
+ method public androidx.core.app.NotificationCompat.Builder addPerson(androidx.core.app.Person?);
+ method public android.app.Notification build();
+ method public androidx.core.app.NotificationCompat.Builder clearActions();
+ method public androidx.core.app.NotificationCompat.Builder clearInvisibleActions();
+ method public androidx.core.app.NotificationCompat.Builder clearPeople();
+ method public android.widget.RemoteViews? createBigContentView();
+ method public android.widget.RemoteViews? createContentView();
+ method public android.widget.RemoteViews? createHeadsUpContentView();
+ method public androidx.core.app.NotificationCompat.Builder extend(androidx.core.app.NotificationCompat.Extender);
+ method public android.os.Bundle getExtras();
+ method @Deprecated public android.app.Notification getNotification();
+ method protected static CharSequence? limitCharSequenceLength(CharSequence?);
+ method public androidx.core.app.NotificationCompat.Builder setAllowSystemGeneratedContextualActions(boolean);
+ method public androidx.core.app.NotificationCompat.Builder setAutoCancel(boolean);
+ method public androidx.core.app.NotificationCompat.Builder setBadgeIconType(int);
+ method public androidx.core.app.NotificationCompat.Builder setBubbleMetadata(androidx.core.app.NotificationCompat.BubbleMetadata?);
+ method public androidx.core.app.NotificationCompat.Builder setCategory(String?);
+ method public androidx.core.app.NotificationCompat.Builder setChannelId(String);
+ method @RequiresApi(24) public androidx.core.app.NotificationCompat.Builder setChronometerCountDown(boolean);
+ method public androidx.core.app.NotificationCompat.Builder setColor(@ColorInt int);
+ method public androidx.core.app.NotificationCompat.Builder setColorized(boolean);
+ method public androidx.core.app.NotificationCompat.Builder setContent(android.widget.RemoteViews?);
+ method public androidx.core.app.NotificationCompat.Builder setContentInfo(CharSequence?);
+ method public androidx.core.app.NotificationCompat.Builder setContentIntent(android.app.PendingIntent?);
+ method public androidx.core.app.NotificationCompat.Builder setContentText(CharSequence?);
+ method public androidx.core.app.NotificationCompat.Builder setContentTitle(CharSequence?);
+ method public androidx.core.app.NotificationCompat.Builder setCustomBigContentView(android.widget.RemoteViews?);
+ method public androidx.core.app.NotificationCompat.Builder setCustomContentView(android.widget.RemoteViews?);
+ method public androidx.core.app.NotificationCompat.Builder setCustomHeadsUpContentView(android.widget.RemoteViews?);
+ method public androidx.core.app.NotificationCompat.Builder setDefaults(int);
+ method public androidx.core.app.NotificationCompat.Builder setDeleteIntent(android.app.PendingIntent?);
+ method public androidx.core.app.NotificationCompat.Builder setExtras(android.os.Bundle?);
+ method public androidx.core.app.NotificationCompat.Builder setForegroundServiceBehavior(int);
+ method public androidx.core.app.NotificationCompat.Builder setFullScreenIntent(android.app.PendingIntent?, boolean);
+ method public androidx.core.app.NotificationCompat.Builder setGroup(String?);
+ method public androidx.core.app.NotificationCompat.Builder setGroupAlertBehavior(int);
+ method public androidx.core.app.NotificationCompat.Builder setGroupSummary(boolean);
+ method public androidx.core.app.NotificationCompat.Builder setLargeIcon(android.graphics.Bitmap?);
+ method public androidx.core.app.NotificationCompat.Builder setLights(@ColorInt int, int, int);
+ method public androidx.core.app.NotificationCompat.Builder setLocalOnly(boolean);
+ method public androidx.core.app.NotificationCompat.Builder setLocusId(androidx.core.content.LocusIdCompat?);
+ method @Deprecated public androidx.core.app.NotificationCompat.Builder setNotificationSilent();
+ method public androidx.core.app.NotificationCompat.Builder setNumber(int);
+ method public androidx.core.app.NotificationCompat.Builder setOngoing(boolean);
+ method public androidx.core.app.NotificationCompat.Builder setOnlyAlertOnce(boolean);
+ method public androidx.core.app.NotificationCompat.Builder setPriority(int);
+ method public androidx.core.app.NotificationCompat.Builder setProgress(int, int, boolean);
+ method public androidx.core.app.NotificationCompat.Builder setPublicVersion(android.app.Notification?);
+ method public androidx.core.app.NotificationCompat.Builder setRemoteInputHistory(CharSequence![]?);
+ method public androidx.core.app.NotificationCompat.Builder setSettingsText(CharSequence?);
+ method public androidx.core.app.NotificationCompat.Builder setShortcutId(String?);
+ method public androidx.core.app.NotificationCompat.Builder setShortcutInfo(androidx.core.content.pm.ShortcutInfoCompat?);
+ method public androidx.core.app.NotificationCompat.Builder setShowWhen(boolean);
+ method public androidx.core.app.NotificationCompat.Builder setSilent(boolean);
+ method @RequiresApi(23) public androidx.core.app.NotificationCompat.Builder setSmallIcon(androidx.core.graphics.drawable.IconCompat);
+ method public androidx.core.app.NotificationCompat.Builder setSmallIcon(int);
+ method public androidx.core.app.NotificationCompat.Builder setSmallIcon(int, int);
+ method public androidx.core.app.NotificationCompat.Builder setSortKey(String?);
+ method public androidx.core.app.NotificationCompat.Builder setSound(android.net.Uri?);
+ method public androidx.core.app.NotificationCompat.Builder setSound(android.net.Uri?, int);
+ method public androidx.core.app.NotificationCompat.Builder setStyle(androidx.core.app.NotificationCompat.Style?);
+ method public androidx.core.app.NotificationCompat.Builder setSubText(CharSequence?);
+ method public androidx.core.app.NotificationCompat.Builder setTicker(CharSequence?);
+ method @Deprecated public androidx.core.app.NotificationCompat.Builder setTicker(CharSequence?, android.widget.RemoteViews?);
+ method public androidx.core.app.NotificationCompat.Builder setTimeoutAfter(long);
+ method public androidx.core.app.NotificationCompat.Builder setUsesChronometer(boolean);
+ method public androidx.core.app.NotificationCompat.Builder setVibrate(long[]?);
+ method public androidx.core.app.NotificationCompat.Builder setVisibility(int);
+ method public androidx.core.app.NotificationCompat.Builder setWhen(long);
+ field @Deprecated public java.util.ArrayList<java.lang.String!>! mPeople;
+ }
+
+ public static class NotificationCompat.CallStyle extends androidx.core.app.NotificationCompat.Style {
+ ctor public NotificationCompat.CallStyle();
+ ctor public NotificationCompat.CallStyle(androidx.core.app.NotificationCompat.Builder?);
+ method public static androidx.core.app.NotificationCompat.CallStyle forIncomingCall(androidx.core.app.Person, android.app.PendingIntent, android.app.PendingIntent);
+ method public static androidx.core.app.NotificationCompat.CallStyle forOngoingCall(androidx.core.app.Person, android.app.PendingIntent);
+ method public static androidx.core.app.NotificationCompat.CallStyle forScreeningCall(androidx.core.app.Person, android.app.PendingIntent, android.app.PendingIntent);
+ method public androidx.core.app.NotificationCompat.CallStyle setAnswerButtonColorHint(@ColorInt int);
+ method public androidx.core.app.NotificationCompat.CallStyle setDeclineButtonColorHint(@ColorInt int);
+ method public androidx.core.app.NotificationCompat.CallStyle setIsVideo(boolean);
+ method @RequiresApi(23) public androidx.core.app.NotificationCompat.CallStyle setVerificationIcon(android.graphics.drawable.Icon?);
+ method public androidx.core.app.NotificationCompat.CallStyle setVerificationIcon(android.graphics.Bitmap?);
+ method public androidx.core.app.NotificationCompat.CallStyle setVerificationText(CharSequence?);
+ field public static final int CALL_TYPE_INCOMING = 1; // 0x1
+ field public static final int CALL_TYPE_ONGOING = 2; // 0x2
+ field public static final int CALL_TYPE_SCREENING = 3; // 0x3
+ field public static final int CALL_TYPE_UNKNOWN = 0; // 0x0
+ }
+
+ public static final class NotificationCompat.CarExtender implements androidx.core.app.NotificationCompat.Extender {
+ ctor public NotificationCompat.CarExtender();
+ ctor public NotificationCompat.CarExtender(android.app.Notification);
+ method public androidx.core.app.NotificationCompat.Builder extend(androidx.core.app.NotificationCompat.Builder);
+ method @ColorInt public int getColor();
+ method public android.graphics.Bitmap? getLargeIcon();
+ method @Deprecated public androidx.core.app.NotificationCompat.CarExtender.UnreadConversation? getUnreadConversation();
+ method public androidx.core.app.NotificationCompat.CarExtender setColor(@ColorInt int);
+ method public androidx.core.app.NotificationCompat.CarExtender setLargeIcon(android.graphics.Bitmap?);
+ method @Deprecated public androidx.core.app.NotificationCompat.CarExtender setUnreadConversation(androidx.core.app.NotificationCompat.CarExtender.UnreadConversation?);
+ }
+
+ @Deprecated public static class NotificationCompat.CarExtender.UnreadConversation {
+ method @Deprecated public long getLatestTimestamp();
+ method @Deprecated public String![]? getMessages();
+ method @Deprecated public String? getParticipant();
+ method @Deprecated public String![]? getParticipants();
+ method @Deprecated public android.app.PendingIntent? getReadPendingIntent();
+ method @Deprecated public androidx.core.app.RemoteInput? getRemoteInput();
+ method @Deprecated public android.app.PendingIntent? getReplyPendingIntent();
+ }
+
+ @Deprecated public static class NotificationCompat.CarExtender.UnreadConversation.Builder {
+ ctor @Deprecated public NotificationCompat.CarExtender.UnreadConversation.Builder(String);
+ method @Deprecated public androidx.core.app.NotificationCompat.CarExtender.UnreadConversation.Builder addMessage(String?);
+ method @Deprecated public androidx.core.app.NotificationCompat.CarExtender.UnreadConversation build();
+ method @Deprecated public androidx.core.app.NotificationCompat.CarExtender.UnreadConversation.Builder setLatestTimestamp(long);
+ method @Deprecated public androidx.core.app.NotificationCompat.CarExtender.UnreadConversation.Builder setReadPendingIntent(android.app.PendingIntent?);
+ method @Deprecated public androidx.core.app.NotificationCompat.CarExtender.UnreadConversation.Builder setReplyAction(android.app.PendingIntent?, androidx.core.app.RemoteInput?);
+ }
+
+ public static class NotificationCompat.DecoratedCustomViewStyle extends androidx.core.app.NotificationCompat.Style {
+ ctor public NotificationCompat.DecoratedCustomViewStyle();
+ }
+
+ public static interface NotificationCompat.Extender {
+ method public androidx.core.app.NotificationCompat.Builder extend(androidx.core.app.NotificationCompat.Builder);
+ }
+
+ public static class NotificationCompat.InboxStyle extends androidx.core.app.NotificationCompat.Style {
+ ctor public NotificationCompat.InboxStyle();
+ ctor public NotificationCompat.InboxStyle(androidx.core.app.NotificationCompat.Builder?);
+ method public androidx.core.app.NotificationCompat.InboxStyle addLine(CharSequence?);
+ method public androidx.core.app.NotificationCompat.InboxStyle setBigContentTitle(CharSequence?);
+ method public androidx.core.app.NotificationCompat.InboxStyle setSummaryText(CharSequence?);
+ }
+
+ public static class NotificationCompat.MessagingStyle extends androidx.core.app.NotificationCompat.Style {
+ ctor @Deprecated public NotificationCompat.MessagingStyle(CharSequence);
+ ctor public NotificationCompat.MessagingStyle(androidx.core.app.Person);
+ method public void addCompatExtras(android.os.Bundle);
+ method public androidx.core.app.NotificationCompat.MessagingStyle addHistoricMessage(androidx.core.app.NotificationCompat.MessagingStyle.Message?);
+ method @Deprecated public androidx.core.app.NotificationCompat.MessagingStyle addMessage(CharSequence?, long, CharSequence?);
+ method public androidx.core.app.NotificationCompat.MessagingStyle addMessage(CharSequence?, long, androidx.core.app.Person?);
+ method public androidx.core.app.NotificationCompat.MessagingStyle addMessage(androidx.core.app.NotificationCompat.MessagingStyle.Message?);
+ method public static androidx.core.app.NotificationCompat.MessagingStyle? extractMessagingStyleFromNotification(android.app.Notification);
+ method public CharSequence? getConversationTitle();
+ method public java.util.List<androidx.core.app.NotificationCompat.MessagingStyle.Message!> getHistoricMessages();
+ method public java.util.List<androidx.core.app.NotificationCompat.MessagingStyle.Message!> getMessages();
+ method public androidx.core.app.Person getUser();
+ method @Deprecated public CharSequence? getUserDisplayName();
+ method public boolean isGroupConversation();
+ method public androidx.core.app.NotificationCompat.MessagingStyle setConversationTitle(CharSequence?);
+ method public androidx.core.app.NotificationCompat.MessagingStyle setGroupConversation(boolean);
+ field public static final int MAXIMUM_RETAINED_MESSAGES = 25; // 0x19
+ }
+
+ public static final class NotificationCompat.MessagingStyle.Message {
+ ctor public NotificationCompat.MessagingStyle.Message(CharSequence?, long, androidx.core.app.Person?);
+ ctor @Deprecated public NotificationCompat.MessagingStyle.Message(CharSequence?, long, CharSequence?);
+ method public String? getDataMimeType();
+ method public android.net.Uri? getDataUri();
+ method public android.os.Bundle getExtras();
+ method public androidx.core.app.Person? getPerson();
+ method @Deprecated public CharSequence? getSender();
+ method public CharSequence? getText();
+ method public long getTimestamp();
+ method public androidx.core.app.NotificationCompat.MessagingStyle.Message setData(String?, android.net.Uri?);
+ }
+
+ public abstract static class NotificationCompat.Style {
+ ctor public NotificationCompat.Style();
+ method public android.app.Notification? build();
+ method public void setBuilder(androidx.core.app.NotificationCompat.Builder?);
+ }
+
+ public static final class NotificationCompat.WearableExtender implements androidx.core.app.NotificationCompat.Extender {
+ ctor public NotificationCompat.WearableExtender();
+ ctor public NotificationCompat.WearableExtender(android.app.Notification);
+ method public androidx.core.app.NotificationCompat.WearableExtender addAction(androidx.core.app.NotificationCompat.Action);
+ method public androidx.core.app.NotificationCompat.WearableExtender addActions(java.util.List<androidx.core.app.NotificationCompat.Action!>);
+ method @Deprecated public androidx.core.app.NotificationCompat.WearableExtender addPage(android.app.Notification);
+ method @Deprecated public androidx.core.app.NotificationCompat.WearableExtender addPages(java.util.List<android.app.Notification!>);
+ method public androidx.core.app.NotificationCompat.WearableExtender clearActions();
+ method @Deprecated public androidx.core.app.NotificationCompat.WearableExtender clearPages();
+ method public androidx.core.app.NotificationCompat.WearableExtender clone();
+ method public androidx.core.app.NotificationCompat.Builder extend(androidx.core.app.NotificationCompat.Builder);
+ method public java.util.List<androidx.core.app.NotificationCompat.Action!> getActions();
+ method @Deprecated public android.graphics.Bitmap? getBackground();
+ method public String? getBridgeTag();
+ method public int getContentAction();
+ method @Deprecated public int getContentIcon();
+ method @Deprecated public int getContentIconGravity();
+ method public boolean getContentIntentAvailableOffline();
+ method @Deprecated public int getCustomContentHeight();
+ method @Deprecated public int getCustomSizePreset();
+ method public String? getDismissalId();
+ method @Deprecated public android.app.PendingIntent? getDisplayIntent();
+ method @Deprecated public int getGravity();
+ method @Deprecated public boolean getHintAmbientBigPicture();
+ method @Deprecated public boolean getHintAvoidBackgroundClipping();
+ method public boolean getHintContentIntentLaunchesActivity();
+ method @Deprecated public boolean getHintHideIcon();
+ method @Deprecated public int getHintScreenTimeout();
+ method @Deprecated public boolean getHintShowBackgroundOnly();
+ method @Deprecated public java.util.List<android.app.Notification!> getPages();
+ method public boolean getStartScrollBottom();
+ method @Deprecated public androidx.core.app.NotificationCompat.WearableExtender setBackground(android.graphics.Bitmap?);
+ method public androidx.core.app.NotificationCompat.WearableExtender setBridgeTag(String?);
+ method public androidx.core.app.NotificationCompat.WearableExtender setContentAction(int);
+ method @Deprecated public androidx.core.app.NotificationCompat.WearableExtender setContentIcon(int);
+ method @Deprecated public androidx.core.app.NotificationCompat.WearableExtender setContentIconGravity(int);
+ method public androidx.core.app.NotificationCompat.WearableExtender setContentIntentAvailableOffline(boolean);
+ method @Deprecated public androidx.core.app.NotificationCompat.WearableExtender setCustomContentHeight(int);
+ method @Deprecated public androidx.core.app.NotificationCompat.WearableExtender setCustomSizePreset(int);
+ method public androidx.core.app.NotificationCompat.WearableExtender setDismissalId(String?);
+ method @Deprecated public androidx.core.app.NotificationCompat.WearableExtender setDisplayIntent(android.app.PendingIntent?);
+ method @Deprecated public androidx.core.app.NotificationCompat.WearableExtender setGravity(int);
+ method @Deprecated public androidx.core.app.NotificationCompat.WearableExtender setHintAmbientBigPicture(boolean);
+ method @Deprecated public androidx.core.app.NotificationCompat.WearableExtender setHintAvoidBackgroundClipping(boolean);
+ method public androidx.core.app.NotificationCompat.WearableExtender setHintContentIntentLaunchesActivity(boolean);
+ method @Deprecated public androidx.core.app.NotificationCompat.WearableExtender setHintHideIcon(boolean);
+ method @Deprecated public androidx.core.app.NotificationCompat.WearableExtender setHintScreenTimeout(int);
+ method @Deprecated public androidx.core.app.NotificationCompat.WearableExtender setHintShowBackgroundOnly(boolean);
+ method public androidx.core.app.NotificationCompat.WearableExtender setStartScrollBottom(boolean);
+ field @Deprecated public static final int SCREEN_TIMEOUT_LONG = -1; // 0xffffffff
+ field @Deprecated public static final int SCREEN_TIMEOUT_SHORT = 0; // 0x0
+ field @Deprecated public static final int SIZE_DEFAULT = 0; // 0x0
+ field @Deprecated public static final int SIZE_FULL_SCREEN = 5; // 0x5
+ field @Deprecated public static final int SIZE_LARGE = 4; // 0x4
+ field @Deprecated public static final int SIZE_MEDIUM = 3; // 0x3
+ field @Deprecated public static final int SIZE_SMALL = 2; // 0x2
+ field @Deprecated public static final int SIZE_XSMALL = 1; // 0x1
+ field public static final int UNSET_ACTION_INDEX = -1; // 0xffffffff
+ }
+
+ public final class NotificationCompatExtras {
+ field public static final String EXTRA_ACTION_EXTRAS = "android.support.actionExtras";
+ field public static final String EXTRA_GROUP_KEY = "android.support.groupKey";
+ field public static final String EXTRA_GROUP_SUMMARY = "android.support.isGroupSummary";
+ field public static final String EXTRA_LOCAL_ONLY = "android.support.localOnly";
+ field public static final String EXTRA_REMOTE_INPUTS = "android.support.remoteInputs";
+ field public static final String EXTRA_SORT_KEY = "android.support.sortKey";
+ }
+
+ public abstract class NotificationCompatSideChannelService extends android.app.Service {
+ ctor public NotificationCompatSideChannelService();
+ method public abstract void cancel(String!, int, String!);
+ method public abstract void cancelAll(String!);
+ method public abstract void notify(String!, int, String!, android.app.Notification!);
+ method public android.os.IBinder! onBind(android.content.Intent!);
+ }
+
+ public final class NotificationManagerCompat {
+ method public boolean areNotificationsEnabled();
+ method public void cancel(int);
+ method public void cancel(String?, int);
+ method public void cancelAll();
+ method public void createNotificationChannel(android.app.NotificationChannel);
+ method public void createNotificationChannel(androidx.core.app.NotificationChannelCompat);
+ method public void createNotificationChannelGroup(android.app.NotificationChannelGroup);
+ method public void createNotificationChannelGroup(androidx.core.app.NotificationChannelGroupCompat);
+ method public void createNotificationChannelGroups(java.util.List<android.app.NotificationChannelGroup!>);
+ method public void createNotificationChannelGroupsCompat(java.util.List<androidx.core.app.NotificationChannelGroupCompat!>);
+ method public void createNotificationChannels(java.util.List<android.app.NotificationChannel!>);
+ method public void createNotificationChannelsCompat(java.util.List<androidx.core.app.NotificationChannelCompat!>);
+ method public void deleteNotificationChannel(String);
+ method public void deleteNotificationChannelGroup(String);
+ method public void deleteUnlistedNotificationChannels(java.util.Collection<java.lang.String!>);
+ method public static androidx.core.app.NotificationManagerCompat from(android.content.Context);
+ method public static java.util.Set<java.lang.String!> getEnabledListenerPackages(android.content.Context);
+ method public int getImportance();
+ method public android.app.NotificationChannel? getNotificationChannel(String);
+ method public android.app.NotificationChannel? getNotificationChannel(String, String);
+ method public androidx.core.app.NotificationChannelCompat? getNotificationChannelCompat(String);
+ method public androidx.core.app.NotificationChannelCompat? getNotificationChannelCompat(String, String);
+ method public android.app.NotificationChannelGroup? getNotificationChannelGroup(String);
+ method public androidx.core.app.NotificationChannelGroupCompat? getNotificationChannelGroupCompat(String);
+ method public java.util.List<android.app.NotificationChannelGroup!> getNotificationChannelGroups();
+ method public java.util.List<androidx.core.app.NotificationChannelGroupCompat!> getNotificationChannelGroupsCompat();
+ method public java.util.List<android.app.NotificationChannel!> getNotificationChannels();
+ method public java.util.List<androidx.core.app.NotificationChannelCompat!> getNotificationChannelsCompat();
+ method @RequiresPermission(android.Manifest.permission.POST_NOTIFICATIONS) public void notify(int, android.app.Notification);
+ method @RequiresPermission(android.Manifest.permission.POST_NOTIFICATIONS) public void notify(String?, int, android.app.Notification);
+ field public static final String ACTION_BIND_SIDE_CHANNEL = "android.support.BIND_NOTIFICATION_SIDE_CHANNEL";
+ field public static final String EXTRA_USE_SIDE_CHANNEL = "android.support.useSideChannel";
+ field public static final int IMPORTANCE_DEFAULT = 3; // 0x3
+ field public static final int IMPORTANCE_HIGH = 4; // 0x4
+ field public static final int IMPORTANCE_LOW = 2; // 0x2
+ field public static final int IMPORTANCE_MAX = 5; // 0x5
+ field public static final int IMPORTANCE_MIN = 1; // 0x1
+ field public static final int IMPORTANCE_NONE = 0; // 0x0
+ field public static final int IMPORTANCE_UNSPECIFIED = -1000; // 0xfffffc18
+ }
+
+ public interface OnMultiWindowModeChangedProvider {
+ method public void addOnMultiWindowModeChangedListener(androidx.core.util.Consumer<androidx.core.app.MultiWindowModeChangedInfo!>);
+ method public void removeOnMultiWindowModeChangedListener(androidx.core.util.Consumer<androidx.core.app.MultiWindowModeChangedInfo!>);
+ }
+
+ public interface OnNewIntentProvider {
+ method public void addOnNewIntentListener(androidx.core.util.Consumer<android.content.Intent!>);
+ method public void removeOnNewIntentListener(androidx.core.util.Consumer<android.content.Intent!>);
+ }
+
+ public interface OnPictureInPictureModeChangedProvider {
+ method public void addOnPictureInPictureModeChangedListener(androidx.core.util.Consumer<androidx.core.app.PictureInPictureModeChangedInfo!>);
+ method public void removeOnPictureInPictureModeChangedListener(androidx.core.util.Consumer<androidx.core.app.PictureInPictureModeChangedInfo!>);
+ }
+
+ public final class PendingIntentCompat {
+ method public static android.app.PendingIntent getActivities(android.content.Context, int, android.content.Intent![], int, android.os.Bundle, boolean);
+ method public static android.app.PendingIntent getActivities(android.content.Context, int, android.content.Intent![], int, boolean);
+ method public static android.app.PendingIntent getActivity(android.content.Context, int, android.content.Intent, int, boolean);
+ method public static android.app.PendingIntent getActivity(android.content.Context, int, android.content.Intent, int, android.os.Bundle, boolean);
+ method public static android.app.PendingIntent getBroadcast(android.content.Context, int, android.content.Intent, int, boolean);
+ method @RequiresApi(26) public static android.app.PendingIntent getForegroundService(android.content.Context, int, android.content.Intent, int, boolean);
+ method public static android.app.PendingIntent getService(android.content.Context, int, android.content.Intent, int, boolean);
+ }
+
+ public class Person {
+ method public static androidx.core.app.Person fromBundle(android.os.Bundle);
+ method public androidx.core.graphics.drawable.IconCompat? getIcon();
+ method public String? getKey();
+ method public CharSequence? getName();
+ method public String? getUri();
+ method public boolean isBot();
+ method public boolean isImportant();
+ method public androidx.core.app.Person.Builder toBuilder();
+ method public android.os.Bundle toBundle();
+ }
+
+ public static class Person.Builder {
+ ctor public Person.Builder();
+ method public androidx.core.app.Person build();
+ method public androidx.core.app.Person.Builder setBot(boolean);
+ method public androidx.core.app.Person.Builder setIcon(androidx.core.graphics.drawable.IconCompat?);
+ method public androidx.core.app.Person.Builder setImportant(boolean);
+ method public androidx.core.app.Person.Builder setKey(String?);
+ method public androidx.core.app.Person.Builder setName(CharSequence?);
+ method public androidx.core.app.Person.Builder setUri(String?);
+ }
+
+ public final class PictureInPictureModeChangedInfo {
+ ctor public PictureInPictureModeChangedInfo(boolean);
+ ctor @RequiresApi(26) public PictureInPictureModeChangedInfo(boolean, android.content.res.Configuration);
+ method @RequiresApi(26) public android.content.res.Configuration getNewConfig();
+ method public boolean isInPictureInPictureMode();
+ }
+
+ public final class RemoteActionCompat implements androidx.versionedparcelable.VersionedParcelable {
+ ctor public RemoteActionCompat(androidx.core.graphics.drawable.IconCompat, CharSequence, CharSequence, android.app.PendingIntent);
+ ctor public RemoteActionCompat(androidx.core.app.RemoteActionCompat);
+ method @RequiresApi(26) public static androidx.core.app.RemoteActionCompat createFromRemoteAction(android.app.RemoteAction);
+ method public android.app.PendingIntent getActionIntent();
+ method public CharSequence getContentDescription();
+ method public androidx.core.graphics.drawable.IconCompat getIcon();
+ method public CharSequence getTitle();
+ method public boolean isEnabled();
+ method public void setEnabled(boolean);
+ method public void setShouldShowIcon(boolean);
+ method public boolean shouldShowIcon();
+ method @RequiresApi(26) public android.app.RemoteAction toRemoteAction();
+ }
+
+ public final class RemoteInput {
+ method public static void addDataResultToIntent(androidx.core.app.RemoteInput, android.content.Intent, java.util.Map<java.lang.String!,android.net.Uri!>);
+ method public static void addResultsToIntent(androidx.core.app.RemoteInput![], android.content.Intent, android.os.Bundle);
+ method public boolean getAllowFreeFormInput();
+ method public java.util.Set<java.lang.String!>? getAllowedDataTypes();
+ method public CharSequence![]? getChoices();
+ method public static java.util.Map<java.lang.String!,android.net.Uri!>? getDataResultsFromIntent(android.content.Intent, String);
+ method public int getEditChoicesBeforeSending();
+ method public android.os.Bundle getExtras();
+ method public CharSequence? getLabel();
+ method public String getResultKey();
+ method public static android.os.Bundle? getResultsFromIntent(android.content.Intent);
+ method public static int getResultsSource(android.content.Intent);
+ method public boolean isDataOnly();
+ method public static void setResultsSource(android.content.Intent, int);
+ field public static final int EDIT_CHOICES_BEFORE_SENDING_AUTO = 0; // 0x0
+ field public static final int EDIT_CHOICES_BEFORE_SENDING_DISABLED = 1; // 0x1
+ field public static final int EDIT_CHOICES_BEFORE_SENDING_ENABLED = 2; // 0x2
+ field public static final String EXTRA_RESULTS_DATA = "android.remoteinput.resultsData";
+ field public static final String RESULTS_CLIP_LABEL = "android.remoteinput.results";
+ field public static final int SOURCE_CHOICE = 1; // 0x1
+ field public static final int SOURCE_FREE_FORM_INPUT = 0; // 0x0
+ }
+
+ public static final class RemoteInput.Builder {
+ ctor public RemoteInput.Builder(String);
+ method public androidx.core.app.RemoteInput.Builder addExtras(android.os.Bundle);
+ method public androidx.core.app.RemoteInput build();
+ method public android.os.Bundle getExtras();
+ method public androidx.core.app.RemoteInput.Builder setAllowDataType(String, boolean);
+ method public androidx.core.app.RemoteInput.Builder setAllowFreeFormInput(boolean);
+ method public androidx.core.app.RemoteInput.Builder setChoices(CharSequence![]?);
+ method public androidx.core.app.RemoteInput.Builder setEditChoicesBeforeSending(int);
+ method public androidx.core.app.RemoteInput.Builder setLabel(CharSequence?);
+ }
+
+ public final class ServiceCompat {
+ method public static void stopForeground(android.app.Service, int);
+ field public static final int START_STICKY = 1; // 0x1
+ field public static final int STOP_FOREGROUND_DETACH = 2; // 0x2
+ field public static final int STOP_FOREGROUND_REMOVE = 1; // 0x1
+ }
+
+ public final class ShareCompat {
+ method @Deprecated public static void configureMenuItem(android.view.MenuItem, androidx.core.app.ShareCompat.IntentBuilder);
+ method @Deprecated public static void configureMenuItem(android.view.Menu, @IdRes int, androidx.core.app.ShareCompat.IntentBuilder);
+ method public static android.content.ComponentName? getCallingActivity(android.app.Activity);
+ method public static String? getCallingPackage(android.app.Activity);
+ field public static final String EXTRA_CALLING_ACTIVITY = "androidx.core.app.EXTRA_CALLING_ACTIVITY";
+ field public static final String EXTRA_CALLING_ACTIVITY_INTEROP = "android.support.v4.app.EXTRA_CALLING_ACTIVITY";
+ field public static final String EXTRA_CALLING_PACKAGE = "androidx.core.app.EXTRA_CALLING_PACKAGE";
+ field public static final String EXTRA_CALLING_PACKAGE_INTEROP = "android.support.v4.app.EXTRA_CALLING_PACKAGE";
+ }
+
+ public static class ShareCompat.IntentBuilder {
+ ctor public ShareCompat.IntentBuilder(android.content.Context);
+ method public androidx.core.app.ShareCompat.IntentBuilder addEmailBcc(String);
+ method public androidx.core.app.ShareCompat.IntentBuilder addEmailBcc(String![]);
+ method public androidx.core.app.ShareCompat.IntentBuilder addEmailCc(String);
+ method public androidx.core.app.ShareCompat.IntentBuilder addEmailCc(String![]);
+ method public androidx.core.app.ShareCompat.IntentBuilder addEmailTo(String);
+ method public androidx.core.app.ShareCompat.IntentBuilder addEmailTo(String![]);
+ method public androidx.core.app.ShareCompat.IntentBuilder addStream(android.net.Uri);
+ method public android.content.Intent createChooserIntent();
+ method @Deprecated public static androidx.core.app.ShareCompat.IntentBuilder from(android.app.Activity);
+ method public android.content.Intent getIntent();
+ method public androidx.core.app.ShareCompat.IntentBuilder setChooserTitle(CharSequence?);
+ method public androidx.core.app.ShareCompat.IntentBuilder setChooserTitle(@StringRes int);
+ method public androidx.core.app.ShareCompat.IntentBuilder setEmailBcc(String![]?);
+ method public androidx.core.app.ShareCompat.IntentBuilder setEmailCc(String![]?);
+ method public androidx.core.app.ShareCompat.IntentBuilder setEmailTo(String![]?);
+ method public androidx.core.app.ShareCompat.IntentBuilder setHtmlText(String?);
+ method public androidx.core.app.ShareCompat.IntentBuilder setStream(android.net.Uri?);
+ method public androidx.core.app.ShareCompat.IntentBuilder setSubject(String?);
+ method public androidx.core.app.ShareCompat.IntentBuilder setText(CharSequence?);
+ method public androidx.core.app.ShareCompat.IntentBuilder setType(String?);
+ method public void startChooser();
+ }
+
+ public static class ShareCompat.IntentReader {
+ ctor public ShareCompat.IntentReader(android.app.Activity);
+ ctor public ShareCompat.IntentReader(android.content.Context, android.content.Intent);
+ method @Deprecated public static androidx.core.app.ShareCompat.IntentReader from(android.app.Activity);
+ method public android.content.ComponentName? getCallingActivity();
+ method public android.graphics.drawable.Drawable? getCallingActivityIcon();
+ method public android.graphics.drawable.Drawable? getCallingApplicationIcon();
+ method public CharSequence? getCallingApplicationLabel();
+ method public String? getCallingPackage();
+ method public String![]? getEmailBcc();
+ method public String![]? getEmailCc();
+ method public String![]? getEmailTo();
+ method public String? getHtmlText();
+ method public android.net.Uri? getStream();
+ method public android.net.Uri? getStream(int);
+ method public int getStreamCount();
+ method public String? getSubject();
+ method public CharSequence? getText();
+ method public String? getType();
+ method public boolean isMultipleShare();
+ method public boolean isShareIntent();
+ method public boolean isSingleShare();
+ }
+
+ public abstract class SharedElementCallback {
+ ctor public SharedElementCallback();
+ method public android.os.Parcelable! onCaptureSharedElementSnapshot(android.view.View!, android.graphics.Matrix!, android.graphics.RectF!);
+ method public android.view.View! onCreateSnapshotView(android.content.Context!, android.os.Parcelable!);
+ method public void onMapSharedElements(java.util.List<java.lang.String!>!, java.util.Map<java.lang.String!,android.view.View!>!);
+ method public void onRejectSharedElements(java.util.List<android.view.View!>!);
+ method public void onSharedElementEnd(java.util.List<java.lang.String!>!, java.util.List<android.view.View!>!, java.util.List<android.view.View!>!);
+ method public void onSharedElementStart(java.util.List<java.lang.String!>!, java.util.List<android.view.View!>!, java.util.List<android.view.View!>!);
+ method public void onSharedElementsArrived(java.util.List<java.lang.String!>!, java.util.List<android.view.View!>!, androidx.core.app.SharedElementCallback.OnSharedElementsReadyListener!);
+ }
+
+ public static interface SharedElementCallback.OnSharedElementsReadyListener {
+ method public void onSharedElementsReady();
+ }
+
+ public final class TaskStackBuilder implements java.lang.Iterable<android.content.Intent> {
+ method public androidx.core.app.TaskStackBuilder addNextIntent(android.content.Intent);
+ method public androidx.core.app.TaskStackBuilder addNextIntentWithParentStack(android.content.Intent);
+ method public androidx.core.app.TaskStackBuilder addParentStack(android.app.Activity);
+ method public androidx.core.app.TaskStackBuilder addParentStack(Class<?>);
+ method public androidx.core.app.TaskStackBuilder addParentStack(android.content.ComponentName);
+ method public static androidx.core.app.TaskStackBuilder create(android.content.Context);
+ method public android.content.Intent? editIntentAt(int);
+ method @Deprecated public static androidx.core.app.TaskStackBuilder! from(android.content.Context!);
+ method @Deprecated public android.content.Intent! getIntent(int);
+ method public int getIntentCount();
+ method public android.content.Intent![] getIntents();
+ method public android.app.PendingIntent? getPendingIntent(int, int);
+ method public android.app.PendingIntent? getPendingIntent(int, int, android.os.Bundle?);
+ method @Deprecated public java.util.Iterator<android.content.Intent!> iterator();
+ method public void startActivities();
+ method public void startActivities(android.os.Bundle?);
+ }
+
+ public static interface TaskStackBuilder.SupportParentable {
+ method public android.content.Intent? getSupportParentActivityIntent();
+ }
+
+}
+
+package androidx.core.content {
+
+ public final class ContentProviderCompat {
+ method public static android.content.Context requireContext(android.content.ContentProvider);
+ }
+
+ public final class ContentResolverCompat {
+ method public static android.database.Cursor? query(android.content.ContentResolver, android.net.Uri, String![]?, String?, String![]?, String?, androidx.core.os.CancellationSignal?);
+ }
+
+ public class ContextCompat {
+ ctor protected ContextCompat();
+ method public static int checkSelfPermission(android.content.Context, String);
+ method public static android.content.Context? createDeviceProtectedStorageContext(android.content.Context);
+ method public static String? getAttributionTag(android.content.Context);
+ method public static java.io.File getCodeCacheDir(android.content.Context);
+ method @ColorInt public static int getColor(android.content.Context, @ColorRes int);
+ method public static android.content.res.ColorStateList? getColorStateList(android.content.Context, @ColorRes int);
+ method public static java.io.File? getDataDir(android.content.Context);
+ method public static android.graphics.drawable.Drawable? getDrawable(android.content.Context, @DrawableRes int);
+ method public static java.io.File![] getExternalCacheDirs(android.content.Context);
+ method public static java.io.File![] getExternalFilesDirs(android.content.Context, String?);
+ method public static java.util.concurrent.Executor getMainExecutor(android.content.Context);
+ method public static java.io.File? getNoBackupFilesDir(android.content.Context);
+ method public static java.io.File![] getObbDirs(android.content.Context);
+ method public static <T> T? getSystemService(android.content.Context, Class<T!>);
+ method public static String? getSystemServiceName(android.content.Context, Class<?>);
+ method public static boolean isDeviceProtectedStorage(android.content.Context);
+ method public static android.content.Intent? registerReceiver(android.content.Context, android.content.BroadcastReceiver?, android.content.IntentFilter, int);
+ method public static android.content.Intent? registerReceiver(android.content.Context, android.content.BroadcastReceiver?, android.content.IntentFilter, String?, android.os.Handler?, int);
+ method public static boolean startActivities(android.content.Context, android.content.Intent![]);
+ method public static boolean startActivities(android.content.Context, android.content.Intent![], android.os.Bundle?);
+ method public static void startActivity(android.content.Context, android.content.Intent, android.os.Bundle?);
+ method public static void startForegroundService(android.content.Context, android.content.Intent);
+ field public static final int RECEIVER_EXPORTED = 2; // 0x2
+ field public static final int RECEIVER_NOT_EXPORTED = 4; // 0x4
+ field public static final int RECEIVER_VISIBLE_TO_INSTANT_APPS = 1; // 0x1
+ }
+
+ public class FileProvider extends android.content.ContentProvider {
+ ctor public FileProvider();
+ ctor protected FileProvider(@XmlRes int);
+ method public int delete(android.net.Uri, String?, String![]?);
+ method public String? getType(android.net.Uri);
+ method public static android.net.Uri! getUriForFile(android.content.Context, String, java.io.File);
+ method public static android.net.Uri getUriForFile(android.content.Context, String, java.io.File, String);
+ method public android.net.Uri! insert(android.net.Uri, android.content.ContentValues);
+ method public boolean onCreate();
+ method public android.database.Cursor query(android.net.Uri, String![]?, String?, String![]?, String?);
+ method public int update(android.net.Uri, android.content.ContentValues, String?, String![]?);
+ }
+
+ public final class IntentCompat {
+ method public static android.content.Intent createManageUnusedAppRestrictionsIntent(android.content.Context, String);
+ method public static android.os.Parcelable![]? getParcelableArrayExtra(android.content.Intent, String?, Class<? extends android.os.Parcelable>);
+ method public static <T> java.util.ArrayList<T!>? getParcelableArrayListExtra(android.content.Intent, String?, Class<? extends T>);
+ method public static <T> T? getParcelableExtra(android.content.Intent, String?, Class<T!>);
+ method public static android.content.Intent makeMainSelectorActivity(String, String);
+ field public static final String ACTION_CREATE_REMINDER = "android.intent.action.CREATE_REMINDER";
+ field public static final String CATEGORY_LEANBACK_LAUNCHER = "android.intent.category.LEANBACK_LAUNCHER";
+ field public static final String EXTRA_HTML_TEXT = "android.intent.extra.HTML_TEXT";
+ field public static final String EXTRA_START_PLAYBACK = "android.intent.extra.START_PLAYBACK";
+ field public static final String EXTRA_TIME = "android.intent.extra.TIME";
+ }
+
+ public class IntentSanitizer {
+ method public android.content.Intent sanitize(android.content.Intent, androidx.core.util.Consumer<java.lang.String!>);
+ method public android.content.Intent sanitizeByFiltering(android.content.Intent);
+ method public android.content.Intent sanitizeByThrowing(android.content.Intent);
+ }
+
+ public static final class IntentSanitizer.Builder {
+ ctor public IntentSanitizer.Builder();
+ method public androidx.core.content.IntentSanitizer.Builder allowAction(String);
+ method public androidx.core.content.IntentSanitizer.Builder allowAction(androidx.core.util.Predicate<java.lang.String!>);
+ method public androidx.core.content.IntentSanitizer.Builder allowAnyComponent();
+ method public androidx.core.content.IntentSanitizer.Builder allowCategory(String);
+ method public androidx.core.content.IntentSanitizer.Builder allowCategory(androidx.core.util.Predicate<java.lang.String!>);
+ method public androidx.core.content.IntentSanitizer.Builder allowClipData(androidx.core.util.Predicate<android.content.ClipData!>);
+ method public androidx.core.content.IntentSanitizer.Builder allowClipDataText();
+ method public androidx.core.content.IntentSanitizer.Builder allowClipDataUri(androidx.core.util.Predicate<android.net.Uri!>);
+ method public androidx.core.content.IntentSanitizer.Builder allowClipDataUriWithAuthority(String);
+ method public androidx.core.content.IntentSanitizer.Builder allowComponent(android.content.ComponentName);
+ method public androidx.core.content.IntentSanitizer.Builder allowComponent(androidx.core.util.Predicate<android.content.ComponentName!>);
+ method public androidx.core.content.IntentSanitizer.Builder allowComponentWithPackage(String);
+ method public androidx.core.content.IntentSanitizer.Builder allowData(androidx.core.util.Predicate<android.net.Uri!>);
+ method public androidx.core.content.IntentSanitizer.Builder allowDataWithAuthority(String);
+ method public androidx.core.content.IntentSanitizer.Builder allowExtra(String, Class<?>);
+ method public <T> androidx.core.content.IntentSanitizer.Builder allowExtra(String, Class<T!>, androidx.core.util.Predicate<T!>);
+ method public androidx.core.content.IntentSanitizer.Builder allowExtra(String, androidx.core.util.Predicate<java.lang.Object!>);
+ method public androidx.core.content.IntentSanitizer.Builder allowExtraOutput(String);
+ method public androidx.core.content.IntentSanitizer.Builder allowExtraOutput(androidx.core.util.Predicate<android.net.Uri!>);
+ method public androidx.core.content.IntentSanitizer.Builder allowExtraStream(androidx.core.util.Predicate<android.net.Uri!>);
+ method public androidx.core.content.IntentSanitizer.Builder allowExtraStreamUriWithAuthority(String);
+ method public androidx.core.content.IntentSanitizer.Builder allowFlags(int);
+ method public androidx.core.content.IntentSanitizer.Builder allowHistoryStackFlags();
+ method public androidx.core.content.IntentSanitizer.Builder allowIdentifier();
+ method public androidx.core.content.IntentSanitizer.Builder allowPackage(String);
+ method public androidx.core.content.IntentSanitizer.Builder allowPackage(androidx.core.util.Predicate<java.lang.String!>);
+ method public androidx.core.content.IntentSanitizer.Builder allowReceiverFlags();
+ method public androidx.core.content.IntentSanitizer.Builder allowSelector();
+ method public androidx.core.content.IntentSanitizer.Builder allowSourceBounds();
+ method public androidx.core.content.IntentSanitizer.Builder allowType(String);
+ method public androidx.core.content.IntentSanitizer.Builder allowType(androidx.core.util.Predicate<java.lang.String!>);
+ method public androidx.core.content.IntentSanitizer build();
+ }
+
+ public final class LocusIdCompat {
+ ctor public LocusIdCompat(String);
+ method public String getId();
+ method @RequiresApi(29) public android.content.LocusId toLocusId();
+ method @RequiresApi(29) public static androidx.core.content.LocusIdCompat toLocusIdCompat(android.content.LocusId);
+ }
+
+ public final class MimeTypeFilter {
+ method public static boolean matches(String?, String);
+ method public static String? matches(String?, String![]);
+ method public static String? matches(String![]?, String);
+ method public static String![] matchesMany(String![]?, String);
+ }
+
+ public interface OnConfigurationChangedProvider {
+ method public void addOnConfigurationChangedListener(androidx.core.util.Consumer<android.content.res.Configuration!>);
+ method public void removeOnConfigurationChangedListener(androidx.core.util.Consumer<android.content.res.Configuration!>);
+ }
+
+ public interface OnTrimMemoryProvider {
+ method public void addOnTrimMemoryListener(androidx.core.util.Consumer<java.lang.Integer!>);
+ method public void removeOnTrimMemoryListener(androidx.core.util.Consumer<java.lang.Integer!>);
+ }
+
+ public final class PackageManagerCompat {
+ method public static com.google.common.util.concurrent.ListenableFuture<java.lang.Integer!> getUnusedAppRestrictionsStatus(android.content.Context);
+ field public static final String ACTION_PERMISSION_REVOCATION_SETTINGS = "android.intent.action.AUTO_REVOKE_PERMISSIONS";
+ }
+
+ public final class PermissionChecker {
+ method public static int checkCallingOrSelfPermission(android.content.Context, String);
+ method public static int checkCallingPermission(android.content.Context, String, String?);
+ method public static int checkPermission(android.content.Context, String, int, int, String?);
+ method public static int checkSelfPermission(android.content.Context, String);
+ field public static final int PERMISSION_DENIED = -1; // 0xffffffff
+ field public static final int PERMISSION_DENIED_APP_OP = -2; // 0xfffffffe
+ field public static final int PERMISSION_GRANTED = 0; // 0x0
+ }
+
+ @Deprecated public final class SharedPreferencesCompat {
+ }
+
+ @Deprecated public static final class SharedPreferencesCompat.EditorCompat {
+ method @Deprecated public void apply(android.content.SharedPreferences.Editor);
+ method @Deprecated public static androidx.core.content.SharedPreferencesCompat.EditorCompat! getInstance();
+ }
+
+ public class UnusedAppRestrictionsBackportCallback {
+ method public void onResult(boolean, boolean) throws android.os.RemoteException;
+ }
+
+ public abstract class UnusedAppRestrictionsBackportService extends android.app.Service {
+ ctor public UnusedAppRestrictionsBackportService();
+ method protected abstract void isPermissionRevocationEnabled(androidx.core.content.UnusedAppRestrictionsBackportCallback);
+ method public android.os.IBinder? onBind(android.content.Intent?);
+ field public static final String ACTION_UNUSED_APP_RESTRICTIONS_BACKPORT_CONNECTION = "android.support.unusedapprestrictions.action.CustomUnusedAppRestrictionsBackportService";
+ }
+
+ public final class UnusedAppRestrictionsConstants {
+ field public static final int API_30 = 4; // 0x4
+ field public static final int API_30_BACKPORT = 3; // 0x3
+ field public static final int API_31 = 5; // 0x5
+ field public static final int DISABLED = 2; // 0x2
+ field public static final int ERROR = 0; // 0x0
+ field public static final int FEATURE_NOT_AVAILABLE = 1; // 0x1
+ }
+
+ public class UriMatcherCompat {
+ method public static androidx.core.util.Predicate<android.net.Uri!> asPredicate(android.content.UriMatcher);
+ }
+
+}
+
+package androidx.core.content.pm {
+
+ @Deprecated public final class ActivityInfoCompat {
+ field @Deprecated public static final int CONFIG_UI_MODE = 512; // 0x200
+ }
+
+ public final class PackageInfoCompat {
+ method public static long getLongVersionCode(android.content.pm.PackageInfo);
+ method public static java.util.List<android.content.pm.Signature!> getSignatures(android.content.pm.PackageManager, String) throws android.content.pm.PackageManager.NameNotFoundException;
+ method public static boolean hasSignatures(android.content.pm.PackageManager, String, @Size(min=1) java.util.Map<byte[]!,java.lang.Integer!>, boolean) throws android.content.pm.PackageManager.NameNotFoundException;
+ }
+
+ public final class PermissionInfoCompat {
+ method public static int getProtection(android.content.pm.PermissionInfo);
+ method public static int getProtectionFlags(android.content.pm.PermissionInfo);
+ }
+
+ public class ShortcutInfoCompat {
+ method public android.content.ComponentName? getActivity();
+ method public java.util.Set<java.lang.String!>? getCategories();
+ method public CharSequence? getDisabledMessage();
+ method public int getDisabledReason();
+ method public int getExcludedFromSurfaces();
+ method public android.os.PersistableBundle? getExtras();
+ method public String getId();
+ method public android.content.Intent getIntent();
+ method public android.content.Intent![] getIntents();
+ method public long getLastChangedTimestamp();
+ method public androidx.core.content.LocusIdCompat? getLocusId();
+ method public CharSequence? getLongLabel();
+ method public String getPackage();
+ method public int getRank();
+ method public CharSequence getShortLabel();
+ method public android.os.UserHandle? getUserHandle();
+ method public boolean hasKeyFieldsOnly();
+ method public boolean isCached();
+ method public boolean isDeclaredInManifest();
+ method public boolean isDynamic();
+ method public boolean isEnabled();
+ method public boolean isExcludedFromSurfaces(int);
+ method public boolean isImmutable();
+ method public boolean isPinned();
+ method @RequiresApi(25) public android.content.pm.ShortcutInfo! toShortcutInfo();
+ field public static final int SURFACE_LAUNCHER = 1; // 0x1
+ }
+
+ public static class ShortcutInfoCompat.Builder {
+ ctor public ShortcutInfoCompat.Builder(android.content.Context, String);
+ method public androidx.core.content.pm.ShortcutInfoCompat.Builder addCapabilityBinding(String);
+ method public androidx.core.content.pm.ShortcutInfoCompat.Builder addCapabilityBinding(String, String, java.util.List<java.lang.String!>);
+ method public androidx.core.content.pm.ShortcutInfoCompat build();
+ method public androidx.core.content.pm.ShortcutInfoCompat.Builder setActivity(android.content.ComponentName);
+ method public androidx.core.content.pm.ShortcutInfoCompat.Builder setAlwaysBadged();
+ method public androidx.core.content.pm.ShortcutInfoCompat.Builder setCategories(java.util.Set<java.lang.String!>);
+ method public androidx.core.content.pm.ShortcutInfoCompat.Builder setDisabledMessage(CharSequence);
+ method public androidx.core.content.pm.ShortcutInfoCompat.Builder setExcludedFromSurfaces(int);
+ method public androidx.core.content.pm.ShortcutInfoCompat.Builder setExtras(android.os.PersistableBundle);
+ method public androidx.core.content.pm.ShortcutInfoCompat.Builder setIcon(androidx.core.graphics.drawable.IconCompat!);
+ method public androidx.core.content.pm.ShortcutInfoCompat.Builder setIntent(android.content.Intent);
+ method public androidx.core.content.pm.ShortcutInfoCompat.Builder setIntents(android.content.Intent![]);
+ method public androidx.core.content.pm.ShortcutInfoCompat.Builder setIsConversation();
+ method public androidx.core.content.pm.ShortcutInfoCompat.Builder setLocusId(androidx.core.content.LocusIdCompat?);
+ method public androidx.core.content.pm.ShortcutInfoCompat.Builder setLongLabel(CharSequence);
+ method @Deprecated public androidx.core.content.pm.ShortcutInfoCompat.Builder setLongLived();
+ method public androidx.core.content.pm.ShortcutInfoCompat.Builder setLongLived(boolean);
+ method public androidx.core.content.pm.ShortcutInfoCompat.Builder setPerson(androidx.core.app.Person);
+ method public androidx.core.content.pm.ShortcutInfoCompat.Builder setPersons(androidx.core.app.Person![]);
+ method public androidx.core.content.pm.ShortcutInfoCompat.Builder setRank(int);
+ method public androidx.core.content.pm.ShortcutInfoCompat.Builder setShortLabel(CharSequence);
+ method public androidx.core.content.pm.ShortcutInfoCompat.Builder setSliceUri(android.net.Uri);
+ }
+
+ public class ShortcutManagerCompat {
+ method public static boolean addDynamicShortcuts(android.content.Context, java.util.List<androidx.core.content.pm.ShortcutInfoCompat!>);
+ method public static android.content.Intent createShortcutResultIntent(android.content.Context, androidx.core.content.pm.ShortcutInfoCompat);
+ method public static void disableShortcuts(android.content.Context, java.util.List<java.lang.String!>, CharSequence?);
+ method public static void enableShortcuts(android.content.Context, java.util.List<androidx.core.content.pm.ShortcutInfoCompat!>);
+ method public static java.util.List<androidx.core.content.pm.ShortcutInfoCompat!> getDynamicShortcuts(android.content.Context);
+ method public static int getIconMaxHeight(android.content.Context);
+ method public static int getIconMaxWidth(android.content.Context);
+ method public static int getMaxShortcutCountPerActivity(android.content.Context);
+ method public static java.util.List<androidx.core.content.pm.ShortcutInfoCompat!> getShortcuts(android.content.Context, int);
+ method public static boolean isRateLimitingActive(android.content.Context);
+ method public static boolean isRequestPinShortcutSupported(android.content.Context);
+ method public static boolean pushDynamicShortcut(android.content.Context, androidx.core.content.pm.ShortcutInfoCompat);
+ method public static void removeAllDynamicShortcuts(android.content.Context);
+ method public static void removeDynamicShortcuts(android.content.Context, java.util.List<java.lang.String!>);
+ method public static void removeLongLivedShortcuts(android.content.Context, java.util.List<java.lang.String!>);
+ method public static void reportShortcutUsed(android.content.Context, String);
+ method public static boolean requestPinShortcut(android.content.Context, androidx.core.content.pm.ShortcutInfoCompat, android.content.IntentSender?);
+ method public static boolean setDynamicShortcuts(android.content.Context, java.util.List<androidx.core.content.pm.ShortcutInfoCompat!>);
+ method public static boolean updateShortcuts(android.content.Context, java.util.List<androidx.core.content.pm.ShortcutInfoCompat!>);
+ field public static final String EXTRA_SHORTCUT_ID = "android.intent.extra.shortcut.ID";
+ field public static final int FLAG_MATCH_CACHED = 8; // 0x8
+ field public static final int FLAG_MATCH_DYNAMIC = 2; // 0x2
+ field public static final int FLAG_MATCH_MANIFEST = 1; // 0x1
+ field public static final int FLAG_MATCH_PINNED = 4; // 0x4
+ }
+
+}
+
+package androidx.core.content.res {
+
+ public final class ConfigurationHelper {
+ method public static int getDensityDpi(android.content.res.Resources);
+ }
+
+ public final class ResourcesCompat {
+ method public static void clearCachesForTheme(android.content.res.Resources.Theme);
+ method public static android.graphics.Typeface? getCachedFont(android.content.Context, @FontRes int) throws android.content.res.Resources.NotFoundException;
+ method @ColorInt public static int getColor(android.content.res.Resources, @ColorRes int, android.content.res.Resources.Theme?) throws android.content.res.Resources.NotFoundException;
+ method public static android.content.res.ColorStateList? getColorStateList(android.content.res.Resources, @ColorRes int, android.content.res.Resources.Theme?) throws android.content.res.Resources.NotFoundException;
+ method public static android.graphics.drawable.Drawable? getDrawable(android.content.res.Resources, @DrawableRes int, android.content.res.Resources.Theme?) throws android.content.res.Resources.NotFoundException;
+ method public static android.graphics.drawable.Drawable? getDrawableForDensity(android.content.res.Resources, @DrawableRes int, int, android.content.res.Resources.Theme?) throws android.content.res.Resources.NotFoundException;
+ method public static float getFloat(android.content.res.Resources, @DimenRes int);
+ method public static android.graphics.Typeface? getFont(android.content.Context, @FontRes int) throws android.content.res.Resources.NotFoundException;
+ method public static void getFont(android.content.Context, @FontRes int, androidx.core.content.res.ResourcesCompat.FontCallback, android.os.Handler?) throws android.content.res.Resources.NotFoundException;
+ field @AnyRes public static final int ID_NULL = 0; // 0x0
+ }
+
+ public abstract static class ResourcesCompat.FontCallback {
+ ctor public ResourcesCompat.FontCallback();
+ method public abstract void onFontRetrievalFailed(int);
+ method public abstract void onFontRetrieved(android.graphics.Typeface);
+ }
+
+ public static final class ResourcesCompat.ThemeCompat {
+ method public static void rebase(android.content.res.Resources.Theme);
+ }
+
+}
+
+package androidx.core.database {
+
+ public final class CursorWindowCompat {
+ method public static android.database.CursorWindow create(String?, long);
+ }
+
+ @Deprecated public final class DatabaseUtilsCompat {
+ method @Deprecated public static String![]! appendSelectionArgs(String![]!, String![]!);
+ method @Deprecated public static String! concatenateWhere(String!, String!);
+ }
+
+}
+
+package androidx.core.database.sqlite {
+
+ public final class SQLiteCursorCompat {
+ method public static void setFillWindowForwardOnly(android.database.sqlite.SQLiteCursor, boolean);
+ }
+
+}
+
+package androidx.core.graphics {
+
+ public final class BitmapCompat {
+ method public static android.graphics.Bitmap createScaledBitmap(android.graphics.Bitmap, int, int, android.graphics.Rect?, boolean);
+ method public static int getAllocationByteCount(android.graphics.Bitmap);
+ method public static boolean hasMipMap(android.graphics.Bitmap);
+ method public static void setHasMipMap(android.graphics.Bitmap, boolean);
+ }
+
+ public class BlendModeColorFilterCompat {
+ method public static android.graphics.ColorFilter? createBlendModeColorFilterCompat(int, androidx.core.graphics.BlendModeCompat);
+ }
+
+ public enum BlendModeCompat {
+ enum_constant public static final androidx.core.graphics.BlendModeCompat CLEAR;
+ enum_constant @RequiresApi(android.os.Build.VERSION_CODES.Q) public static final androidx.core.graphics.BlendModeCompat COLOR;
+ enum_constant @RequiresApi(android.os.Build.VERSION_CODES.Q) public static final androidx.core.graphics.BlendModeCompat COLOR_BURN;
+ enum_constant @RequiresApi(android.os.Build.VERSION_CODES.Q) public static final androidx.core.graphics.BlendModeCompat COLOR_DODGE;
+ enum_constant public static final androidx.core.graphics.BlendModeCompat DARKEN;
+ enum_constant @RequiresApi(android.os.Build.VERSION_CODES.Q) public static final androidx.core.graphics.BlendModeCompat DIFFERENCE;
+ enum_constant public static final androidx.core.graphics.BlendModeCompat DST;
+ enum_constant public static final androidx.core.graphics.BlendModeCompat DST_ATOP;
+ enum_constant public static final androidx.core.graphics.BlendModeCompat DST_IN;
+ enum_constant public static final androidx.core.graphics.BlendModeCompat DST_OUT;
+ enum_constant public static final androidx.core.graphics.BlendModeCompat DST_OVER;
+ enum_constant @RequiresApi(android.os.Build.VERSION_CODES.Q) public static final androidx.core.graphics.BlendModeCompat EXCLUSION;
+ enum_constant @RequiresApi(android.os.Build.VERSION_CODES.Q) public static final androidx.core.graphics.BlendModeCompat HARD_LIGHT;
+ enum_constant @RequiresApi(android.os.Build.VERSION_CODES.Q) public static final androidx.core.graphics.BlendModeCompat HUE;
+ enum_constant public static final androidx.core.graphics.BlendModeCompat LIGHTEN;
+ enum_constant @RequiresApi(android.os.Build.VERSION_CODES.Q) public static final androidx.core.graphics.BlendModeCompat LUMINOSITY;
+ enum_constant public static final androidx.core.graphics.BlendModeCompat MODULATE;
+ enum_constant @RequiresApi(android.os.Build.VERSION_CODES.Q) public static final androidx.core.graphics.BlendModeCompat MULTIPLY;
+ enum_constant public static final androidx.core.graphics.BlendModeCompat OVERLAY;
+ enum_constant public static final androidx.core.graphics.BlendModeCompat PLUS;
+ enum_constant @RequiresApi(android.os.Build.VERSION_CODES.Q) public static final androidx.core.graphics.BlendModeCompat SATURATION;
+ enum_constant public static final androidx.core.graphics.BlendModeCompat SCREEN;
+ enum_constant @RequiresApi(android.os.Build.VERSION_CODES.Q) public static final androidx.core.graphics.BlendModeCompat SOFT_LIGHT;
+ enum_constant public static final androidx.core.graphics.BlendModeCompat SRC;
+ enum_constant public static final androidx.core.graphics.BlendModeCompat SRC_ATOP;
+ enum_constant public static final androidx.core.graphics.BlendModeCompat SRC_IN;
+ enum_constant public static final androidx.core.graphics.BlendModeCompat SRC_OUT;
+ enum_constant public static final androidx.core.graphics.BlendModeCompat SRC_OVER;
+ enum_constant public static final androidx.core.graphics.BlendModeCompat XOR;
+ }
+
+ public final class ColorUtils {
+ method @ColorInt public static int HSLToColor(float[]);
+ method @ColorInt public static int LABToColor(@FloatRange(from=0.0f, to=100) double, @FloatRange(from=0xffffff80, to=127) double, @FloatRange(from=0xffffff80, to=127) double);
+ method public static void LABToXYZ(@FloatRange(from=0.0f, to=100) double, @FloatRange(from=0xffffff80, to=127) double, @FloatRange(from=0xffffff80, to=127) double, double[]);
+ method public static void RGBToHSL(@IntRange(from=0, to=255) int, @IntRange(from=0, to=255) int, @IntRange(from=0, to=255) int, float[]);
+ method public static void RGBToLAB(@IntRange(from=0, to=255) int, @IntRange(from=0, to=255) int, @IntRange(from=0, to=255) int, double[]);
+ method public static void RGBToXYZ(@IntRange(from=0, to=255) int, @IntRange(from=0, to=255) int, @IntRange(from=0, to=255) int, double[]);
+ method @ColorInt public static int XYZToColor(@FloatRange(from=0.0f, to=95.047) double, @FloatRange(from=0.0f, to=0x64) double, @FloatRange(from=0.0f, to=108.883) double);
+ method public static void XYZToLAB(@FloatRange(from=0.0f, to=95.047) double, @FloatRange(from=0.0f, to=0x64) double, @FloatRange(from=0.0f, to=108.883) double, double[]);
+ method @ColorInt public static int blendARGB(@ColorInt int, @ColorInt int, @FloatRange(from=0.0, to=1.0) float);
+ method public static void blendHSL(float[], float[], @FloatRange(from=0.0, to=1.0) float, float[]);
+ method public static void blendLAB(double[], double[], @FloatRange(from=0.0, to=1.0) double, double[]);
+ method public static double calculateContrast(@ColorInt int, @ColorInt int);
+ method @FloatRange(from=0.0, to=1.0) public static double calculateLuminance(@ColorInt int);
+ method public static int calculateMinimumAlpha(@ColorInt int, @ColorInt int, float);
+ method public static void colorToHSL(@ColorInt int, float[]);
+ method public static void colorToLAB(@ColorInt int, double[]);
+ method public static void colorToXYZ(@ColorInt int, double[]);
+ method public static int compositeColors(@ColorInt int, @ColorInt int);
+ method @RequiresApi(26) public static android.graphics.Color compositeColors(android.graphics.Color, android.graphics.Color);
+ method public static double distanceEuclidean(double[], double[]);
+ method @ColorInt public static int setAlphaComponent(@ColorInt int, @IntRange(from=0, to=255) int);
+ }
+
+ public final class Insets {
+ method public static androidx.core.graphics.Insets add(androidx.core.graphics.Insets, androidx.core.graphics.Insets);
+ method public static androidx.core.graphics.Insets max(androidx.core.graphics.Insets, androidx.core.graphics.Insets);
+ method public static androidx.core.graphics.Insets min(androidx.core.graphics.Insets, androidx.core.graphics.Insets);
+ method public static androidx.core.graphics.Insets of(int, int, int, int);
+ method public static androidx.core.graphics.Insets of(android.graphics.Rect);
+ method public static androidx.core.graphics.Insets subtract(androidx.core.graphics.Insets, androidx.core.graphics.Insets);
+ method @RequiresApi(api=29) public static androidx.core.graphics.Insets toCompatInsets(android.graphics.Insets);
+ method @RequiresApi(29) public android.graphics.Insets toPlatformInsets();
+ field public static final androidx.core.graphics.Insets NONE;
+ field public final int bottom;
+ field public final int left;
+ field public final int right;
+ field public final int top;
+ }
+
+ public final class PaintCompat {
+ method public static boolean hasGlyph(android.graphics.Paint, String);
+ method public static boolean setBlendMode(android.graphics.Paint, androidx.core.graphics.BlendModeCompat?);
+ }
+
+ public final class PathSegment {
+ ctor public PathSegment(android.graphics.PointF, float, android.graphics.PointF, float);
+ method public android.graphics.PointF getEnd();
+ method public float getEndFraction();
+ method public android.graphics.PointF getStart();
+ method public float getStartFraction();
+ }
+
+ public final class PathUtils {
+ method @RequiresApi(26) public static java.util.Collection<androidx.core.graphics.PathSegment!> flatten(android.graphics.Path);
+ method @RequiresApi(26) public static java.util.Collection<androidx.core.graphics.PathSegment!> flatten(android.graphics.Path, @FloatRange(from=0) float);
+ }
+
+ public class TypefaceCompat {
+ method public static android.graphics.Typeface create(android.content.Context, android.graphics.Typeface?, int);
+ method public static android.graphics.Typeface create(android.content.Context, android.graphics.Typeface?, @IntRange(from=1, to=1000) int, boolean);
+ }
+
+}
+
+package androidx.core.graphics.drawable {
+
+ public final class DrawableCompat {
+ method public static void applyTheme(android.graphics.drawable.Drawable, android.content.res.Resources.Theme);
+ method public static boolean canApplyTheme(android.graphics.drawable.Drawable);
+ method public static void clearColorFilter(android.graphics.drawable.Drawable);
+ method public static int getAlpha(android.graphics.drawable.Drawable);
+ method public static android.graphics.ColorFilter? getColorFilter(android.graphics.drawable.Drawable);
+ method public static int getLayoutDirection(android.graphics.drawable.Drawable);
+ method public static void inflate(android.graphics.drawable.Drawable, android.content.res.Resources, org.xmlpull.v1.XmlPullParser, android.util.AttributeSet, android.content.res.Resources.Theme?) throws java.io.IOException, org.xmlpull.v1.XmlPullParserException;
+ method public static boolean isAutoMirrored(android.graphics.drawable.Drawable);
+ method @Deprecated public static void jumpToCurrentState(android.graphics.drawable.Drawable);
+ method public static void setAutoMirrored(android.graphics.drawable.Drawable, boolean);
+ method public static void setHotspot(android.graphics.drawable.Drawable, float, float);
+ method public static void setHotspotBounds(android.graphics.drawable.Drawable, int, int, int, int);
+ method public static boolean setLayoutDirection(android.graphics.drawable.Drawable, int);
+ method public static void setTint(android.graphics.drawable.Drawable, @ColorInt int);
+ method public static void setTintList(android.graphics.drawable.Drawable, android.content.res.ColorStateList?);
+ method public static void setTintMode(android.graphics.drawable.Drawable, android.graphics.PorterDuff.Mode?);
+ method public static <T extends android.graphics.drawable.Drawable> T! unwrap(android.graphics.drawable.Drawable);
+ method public static android.graphics.drawable.Drawable wrap(android.graphics.drawable.Drawable);
+ }
+
+ public class IconCompat implements androidx.versionedparcelable.VersionedParcelable {
+ method public static androidx.core.graphics.drawable.IconCompat? createFromBundle(android.os.Bundle);
+ method @RequiresApi(23) public static androidx.core.graphics.drawable.IconCompat? createFromIcon(android.content.Context, android.graphics.drawable.Icon);
+ method public static androidx.core.graphics.drawable.IconCompat createWithAdaptiveBitmap(android.graphics.Bitmap);
+ method public static androidx.core.graphics.drawable.IconCompat createWithAdaptiveBitmapContentUri(String);
+ method public static androidx.core.graphics.drawable.IconCompat createWithAdaptiveBitmapContentUri(android.net.Uri);
+ method public static androidx.core.graphics.drawable.IconCompat createWithBitmap(android.graphics.Bitmap);
+ method public static androidx.core.graphics.drawable.IconCompat createWithContentUri(String);
+ method public static androidx.core.graphics.drawable.IconCompat createWithContentUri(android.net.Uri);
+ method public static androidx.core.graphics.drawable.IconCompat createWithData(byte[], int, int);
+ method public static androidx.core.graphics.drawable.IconCompat createWithResource(android.content.Context, @DrawableRes int);
+ method @DrawableRes public int getResId();
+ method public String getResPackage();
+ method public int getType();
+ method public android.net.Uri getUri();
+ method public android.graphics.drawable.Drawable? loadDrawable(android.content.Context);
+ method public void onPostParceling();
+ method public void onPreParceling(boolean);
+ method public androidx.core.graphics.drawable.IconCompat setTint(@ColorInt int);
+ method public androidx.core.graphics.drawable.IconCompat setTintList(android.content.res.ColorStateList?);
+ method public androidx.core.graphics.drawable.IconCompat setTintMode(android.graphics.PorterDuff.Mode?);
+ method public android.os.Bundle toBundle();
+ method @Deprecated @RequiresApi(23) public android.graphics.drawable.Icon toIcon();
+ method @RequiresApi(23) public android.graphics.drawable.Icon toIcon(android.content.Context?);
+ field public static final int TYPE_ADAPTIVE_BITMAP = 5; // 0x5
+ field public static final int TYPE_BITMAP = 1; // 0x1
+ field public static final int TYPE_DATA = 3; // 0x3
+ field public static final int TYPE_RESOURCE = 2; // 0x2
+ field public static final int TYPE_UNKNOWN = -1; // 0xffffffff
+ field public static final int TYPE_URI = 4; // 0x4
+ field public static final int TYPE_URI_ADAPTIVE_BITMAP = 6; // 0x6
+ }
+
+ public abstract class RoundedBitmapDrawable extends android.graphics.drawable.Drawable {
+ method public void draw(android.graphics.Canvas);
+ method public final android.graphics.Bitmap? getBitmap();
+ method public float getCornerRadius();
+ method public int getGravity();
+ method public int getOpacity();
+ method public final android.graphics.Paint getPaint();
+ method public boolean hasAntiAlias();
+ method public boolean hasMipMap();
+ method public boolean isCircular();
+ method public void setAlpha(int);
+ method public void setAntiAlias(boolean);
+ method public void setCircular(boolean);
+ method public void setColorFilter(android.graphics.ColorFilter!);
+ method public void setCornerRadius(float);
+ method public void setDither(boolean);
+ method public void setGravity(int);
+ method public void setMipMap(boolean);
+ method public void setTargetDensity(android.graphics.Canvas);
+ method public void setTargetDensity(android.util.DisplayMetrics);
+ method public void setTargetDensity(int);
+ }
+
+ public final class RoundedBitmapDrawableFactory {
+ method public static androidx.core.graphics.drawable.RoundedBitmapDrawable create(android.content.res.Resources, android.graphics.Bitmap?);
+ method public static androidx.core.graphics.drawable.RoundedBitmapDrawable create(android.content.res.Resources, String);
+ method public static androidx.core.graphics.drawable.RoundedBitmapDrawable create(android.content.res.Resources, java.io.InputStream);
+ }
+
+}
+
+package androidx.core.hardware.display {
+
+ public final class DisplayManagerCompat {
+ method public android.view.Display? getDisplay(int);
+ method public android.view.Display![] getDisplays();
+ method public android.view.Display![] getDisplays(String?);
+ method public static androidx.core.hardware.display.DisplayManagerCompat getInstance(android.content.Context);
+ field public static final String DISPLAY_CATEGORY_PRESENTATION = "android.hardware.display.category.PRESENTATION";
+ }
+
+}
+
+package androidx.core.hardware.fingerprint {
+
+ @Deprecated public class FingerprintManagerCompat {
+ method @Deprecated @RequiresPermission(android.Manifest.permission.USE_FINGERPRINT) public void authenticate(androidx.core.hardware.fingerprint.FingerprintManagerCompat.CryptoObject?, int, androidx.core.os.CancellationSignal?, androidx.core.hardware.fingerprint.FingerprintManagerCompat.AuthenticationCallback, android.os.Handler?);
+ method @Deprecated public static androidx.core.hardware.fingerprint.FingerprintManagerCompat from(android.content.Context);
+ method @Deprecated @RequiresPermission(android.Manifest.permission.USE_FINGERPRINT) public boolean hasEnrolledFingerprints();
+ method @Deprecated @RequiresPermission(android.Manifest.permission.USE_FINGERPRINT) public boolean isHardwareDetected();
+ }
+
+ @Deprecated public abstract static class FingerprintManagerCompat.AuthenticationCallback {
+ ctor @Deprecated public FingerprintManagerCompat.AuthenticationCallback();
+ method @Deprecated public void onAuthenticationError(int, CharSequence!);
+ method @Deprecated public void onAuthenticationFailed();
+ method @Deprecated public void onAuthenticationHelp(int, CharSequence!);
+ method @Deprecated public void onAuthenticationSucceeded(androidx.core.hardware.fingerprint.FingerprintManagerCompat.AuthenticationResult!);
+ }
+
+ @Deprecated public static final class FingerprintManagerCompat.AuthenticationResult {
+ ctor @Deprecated public FingerprintManagerCompat.AuthenticationResult(androidx.core.hardware.fingerprint.FingerprintManagerCompat.CryptoObject!);
+ method @Deprecated public androidx.core.hardware.fingerprint.FingerprintManagerCompat.CryptoObject! getCryptoObject();
+ }
+
+ @Deprecated public static class FingerprintManagerCompat.CryptoObject {
+ ctor @Deprecated public FingerprintManagerCompat.CryptoObject(java.security.Signature);
+ ctor @Deprecated public FingerprintManagerCompat.CryptoObject(javax.crypto.Cipher);
+ ctor @Deprecated public FingerprintManagerCompat.CryptoObject(javax.crypto.Mac);
+ method @Deprecated public javax.crypto.Cipher? getCipher();
+ method @Deprecated public javax.crypto.Mac? getMac();
+ method @Deprecated public java.security.Signature? getSignature();
+ }
+
+}
+
+package androidx.core.location {
+
+ public abstract class GnssStatusCompat {
+ method @FloatRange(from=0, to=360) public abstract float getAzimuthDegrees(@IntRange(from=0) int);
+ method @FloatRange(from=0, to=63) public abstract float getBasebandCn0DbHz(@IntRange(from=0) int);
+ method @FloatRange(from=0) public abstract float getCarrierFrequencyHz(@IntRange(from=0) int);
+ method @FloatRange(from=0, to=63) public abstract float getCn0DbHz(@IntRange(from=0) int);
+ method public abstract int getConstellationType(@IntRange(from=0) int);
+ method @FloatRange(from=0xffffffa6, to=90) public abstract float getElevationDegrees(@IntRange(from=0) int);
+ method @IntRange(from=0) public abstract int getSatelliteCount();
+ method @IntRange(from=1, to=200) public abstract int getSvid(@IntRange(from=0) int);
+ method public abstract boolean hasAlmanacData(@IntRange(from=0) int);
+ method public abstract boolean hasBasebandCn0DbHz(@IntRange(from=0) int);
+ method public abstract boolean hasCarrierFrequencyHz(@IntRange(from=0) int);
+ method public abstract boolean hasEphemerisData(@IntRange(from=0) int);
+ method public abstract boolean usedInFix(@IntRange(from=0) int);
+ method @RequiresApi(android.os.Build.VERSION_CODES.N) public static androidx.core.location.GnssStatusCompat wrap(android.location.GnssStatus);
+ method public static androidx.core.location.GnssStatusCompat wrap(android.location.GpsStatus);
+ field public static final int CONSTELLATION_BEIDOU = 5; // 0x5
+ field public static final int CONSTELLATION_GALILEO = 6; // 0x6
+ field public static final int CONSTELLATION_GLONASS = 3; // 0x3
+ field public static final int CONSTELLATION_GPS = 1; // 0x1
+ field public static final int CONSTELLATION_IRNSS = 7; // 0x7
+ field public static final int CONSTELLATION_QZSS = 4; // 0x4
+ field public static final int CONSTELLATION_SBAS = 2; // 0x2
+ field public static final int CONSTELLATION_UNKNOWN = 0; // 0x0
+ }
+
+ public abstract static class GnssStatusCompat.Callback {
+ ctor public GnssStatusCompat.Callback();
+ method public void onFirstFix(@IntRange(from=0) int);
+ method public void onSatelliteStatusChanged(androidx.core.location.GnssStatusCompat);
+ method public void onStarted();
+ method public void onStopped();
+ }
+
+ public final class LocationCompat {
+ method public static float getBearingAccuracyDegrees(android.location.Location);
+ method public static long getElapsedRealtimeMillis(android.location.Location);
+ method public static long getElapsedRealtimeNanos(android.location.Location);
+ method @FloatRange(from=0.0) public static float getMslAltitudeAccuracyMeters(android.location.Location);
+ method public static double getMslAltitudeMeters(android.location.Location);
+ method public static float getSpeedAccuracyMetersPerSecond(android.location.Location);
+ method public static float getVerticalAccuracyMeters(android.location.Location);
+ method public static boolean hasBearingAccuracy(android.location.Location);
+ method public static boolean hasMslAltitude(android.location.Location);
+ method public static boolean hasMslAltitudeAccuracy(android.location.Location);
+ method public static boolean hasSpeedAccuracy(android.location.Location);
+ method public static boolean hasVerticalAccuracy(android.location.Location);
+ method public static boolean isMock(android.location.Location);
+ method public static void removeMslAltitude(android.location.Location);
+ method public static void removeMslAltitudeAccuracy(android.location.Location);
+ method public static void setBearingAccuracyDegrees(android.location.Location, float);
+ method public static void setMock(android.location.Location, boolean);
+ method public static void setMslAltitudeAccuracyMeters(android.location.Location, @FloatRange(from=0.0) float);
+ method public static void setMslAltitudeMeters(android.location.Location, double);
+ method public static void setSpeedAccuracyMetersPerSecond(android.location.Location, float);
+ method public static void setVerticalAccuracyMeters(android.location.Location, float);
+ field public static final String EXTRA_BEARING_ACCURACY = "bearingAccuracy";
+ field public static final String EXTRA_IS_MOCK = "mockLocation";
+ field public static final String EXTRA_MSL_ALTITUDE = "androidx.core.location.extra.MSL_ALTITUDE";
+ field public static final String EXTRA_MSL_ALTITUDE_ACCURACY = "androidx.core.location.extra.MSL_ALTITUDE_ACCURACY";
+ field public static final String EXTRA_SPEED_ACCURACY = "speedAccuracy";
+ field public static final String EXTRA_VERTICAL_ACCURACY = "verticalAccuracy";
+ }
+
+ public interface LocationListenerCompat extends android.location.LocationListener {
+ method public default void onStatusChanged(String, int, android.os.Bundle?);
+ }
+
+ public final class LocationManagerCompat {
+ method @RequiresPermission(anyOf={android.Manifest.permission.ACCESS_COARSE_LOCATION, android.Manifest.permission.ACCESS_FINE_LOCATION}) public static void getCurrentLocation(android.location.LocationManager, String, androidx.core.os.CancellationSignal?, java.util.concurrent.Executor, androidx.core.util.Consumer<android.location.Location!>);
+ method public static String? getGnssHardwareModelName(android.location.LocationManager);
+ method public static int getGnssYearOfHardware(android.location.LocationManager);
+ method public static boolean hasProvider(android.location.LocationManager, String);
+ method public static boolean isLocationEnabled(android.location.LocationManager);
+ method @RequiresApi(android.os.Build.VERSION_CODES.N) @RequiresPermission(android.Manifest.permission.ACCESS_FINE_LOCATION) public static boolean registerGnssMeasurementsCallback(android.location.LocationManager, android.location.GnssMeasurementsEvent.Callback, android.os.Handler);
+ method @RequiresApi(android.os.Build.VERSION_CODES.R) @RequiresPermission(android.Manifest.permission.ACCESS_FINE_LOCATION) public static boolean registerGnssMeasurementsCallback(android.location.LocationManager, java.util.concurrent.Executor, android.location.GnssMeasurementsEvent.Callback);
+ method @RequiresPermission(android.Manifest.permission.ACCESS_FINE_LOCATION) public static boolean registerGnssStatusCallback(android.location.LocationManager, androidx.core.location.GnssStatusCompat.Callback, android.os.Handler);
+ method @RequiresPermission(android.Manifest.permission.ACCESS_FINE_LOCATION) public static boolean registerGnssStatusCallback(android.location.LocationManager, java.util.concurrent.Executor, androidx.core.location.GnssStatusCompat.Callback);
+ method @RequiresPermission(anyOf={android.Manifest.permission.ACCESS_COARSE_LOCATION, android.Manifest.permission.ACCESS_FINE_LOCATION}) public static void removeUpdates(android.location.LocationManager, androidx.core.location.LocationListenerCompat);
+ method @RequiresPermission(anyOf={android.Manifest.permission.ACCESS_COARSE_LOCATION, android.Manifest.permission.ACCESS_FINE_LOCATION}) public static void requestLocationUpdates(android.location.LocationManager, String, androidx.core.location.LocationRequestCompat, 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 @RequiresApi(android.os.Build.VERSION_CODES.N) public static void unregisterGnssMeasurementsCallback(android.location.LocationManager, android.location.GnssMeasurementsEvent.Callback);
+ method public static void unregisterGnssStatusCallback(android.location.LocationManager, androidx.core.location.GnssStatusCompat.Callback);
+ }
+
+ public final class LocationRequestCompat {
+ method @IntRange(from=1) public long getDurationMillis();
+ method @IntRange(from=0) public long getIntervalMillis();
+ method @IntRange(from=0) public long getMaxUpdateDelayMillis();
+ method @IntRange(from=1, to=java.lang.Integer.MAX_VALUE) public int getMaxUpdates();
+ method @FloatRange(from=0, to=java.lang.Float.MAX_VALUE) public float getMinUpdateDistanceMeters();
+ method @IntRange(from=0) public long getMinUpdateIntervalMillis();
+ method public int getQuality();
+ method @RequiresApi(31) public android.location.LocationRequest toLocationRequest();
+ method @RequiresApi(19) public android.location.LocationRequest? toLocationRequest(String);
+ field public static final long PASSIVE_INTERVAL = 9223372036854775807L; // 0x7fffffffffffffffL
+ field public static final int QUALITY_BALANCED_POWER_ACCURACY = 102; // 0x66
+ field public static final int QUALITY_HIGH_ACCURACY = 100; // 0x64
+ field public static final int QUALITY_LOW_POWER = 104; // 0x68
+ }
+
+ public static final class LocationRequestCompat.Builder {
+ ctor public LocationRequestCompat.Builder(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 {
+
+ public class MathUtils {
+ method public static int addExact(int, int);
+ method public static long addExact(long, long);
+ method public static float clamp(float, float, float);
+ method public static double clamp(double, double, double);
+ method public static int clamp(int, int, int);
+ method public static long clamp(long, long, long);
+ method public static int decrementExact(int);
+ method public static long decrementExact(long);
+ method public static int incrementExact(int);
+ method public static long incrementExact(long);
+ method public static int multiplyExact(int, int);
+ method public static long multiplyExact(long, long);
+ method public static int negateExact(int);
+ method public static long negateExact(long);
+ method public static int subtractExact(int, int);
+ method public static long subtractExact(long, long);
+ method public static int toIntExact(long);
+ }
+
+}
+
+package androidx.core.net {
+
+ public final class ConnectivityManagerCompat {
+ method @RequiresPermission(android.Manifest.permission.ACCESS_NETWORK_STATE) public static android.net.NetworkInfo? getNetworkInfoFromBroadcast(android.net.ConnectivityManager, android.content.Intent);
+ method public static int getRestrictBackgroundStatus(android.net.ConnectivityManager);
+ method @RequiresPermission(android.Manifest.permission.ACCESS_NETWORK_STATE) public static boolean isActiveNetworkMetered(android.net.ConnectivityManager);
+ field public static final int RESTRICT_BACKGROUND_STATUS_DISABLED = 1; // 0x1
+ field public static final int RESTRICT_BACKGROUND_STATUS_ENABLED = 3; // 0x3
+ field public static final int RESTRICT_BACKGROUND_STATUS_WHITELISTED = 2; // 0x2
+ }
+
+ public final class MailTo {
+ method public String? getBcc();
+ method public String? getBody();
+ method public String? getCc();
+ method public java.util.Map<java.lang.String!,java.lang.String!>? getHeaders();
+ method public String? getSubject();
+ method public String? getTo();
+ method public static boolean isMailTo(String?);
+ method public static boolean isMailTo(android.net.Uri?);
+ method public static androidx.core.net.MailTo parse(String) throws androidx.core.net.ParseException;
+ method public static androidx.core.net.MailTo parse(android.net.Uri) throws androidx.core.net.ParseException;
+ field public static final String MAILTO_SCHEME = "mailto:";
+ }
+
+ public class ParseException extends java.lang.RuntimeException {
+ field public final String response;
+ }
+
+ public final class TrafficStatsCompat {
+ method @Deprecated public static void clearThreadStatsTag();
+ method @Deprecated public static int getThreadStatsTag();
+ method @Deprecated public static void incrementOperationCount(int);
+ method @Deprecated public static void incrementOperationCount(int, int);
+ method @Deprecated public static void setThreadStatsTag(int);
+ method public static void tagDatagramSocket(java.net.DatagramSocket) throws java.net.SocketException;
+ method @Deprecated public static void tagSocket(java.net.Socket!) throws java.net.SocketException;
+ method public static void untagDatagramSocket(java.net.DatagramSocket) throws java.net.SocketException;
+ method @Deprecated public static void untagSocket(java.net.Socket!) throws java.net.SocketException;
+ }
+
+ public final class UriCompat {
+ method public static String toSafeString(android.net.Uri);
+ }
+
+}
+
+package androidx.core.os {
+
+ public class BuildCompat {
+ method @Deprecated @ChecksSdkIntAtLeast(api=android.os.Build.VERSION_CODES.N) public static boolean isAtLeastN();
+ method @Deprecated @ChecksSdkIntAtLeast(api=android.os.Build.VERSION_CODES.N_MR1) public static boolean isAtLeastNMR1();
+ method @Deprecated @ChecksSdkIntAtLeast(api=android.os.Build.VERSION_CODES.O) public static boolean isAtLeastO();
+ method @Deprecated @ChecksSdkIntAtLeast(api=android.os.Build.VERSION_CODES.O_MR1) public static boolean isAtLeastOMR1();
+ method @Deprecated @ChecksSdkIntAtLeast(api=android.os.Build.VERSION_CODES.P) public static boolean isAtLeastP();
+ method @Deprecated @ChecksSdkIntAtLeast(api=android.os.Build.VERSION_CODES.Q) public static boolean isAtLeastQ();
+ method @Deprecated @ChecksSdkIntAtLeast(api=android.os.Build.VERSION_CODES.R) public static boolean isAtLeastR();
+ method @Deprecated @ChecksSdkIntAtLeast(api=31, codename="S") public static boolean isAtLeastS();
+ method @Deprecated @ChecksSdkIntAtLeast(api=32, codename="Sv2") @androidx.core.os.BuildCompat.PrereleaseSdkCheck public static boolean isAtLeastSv2();
+ method @ChecksSdkIntAtLeast(api=33, codename="Tiramisu") @androidx.core.os.BuildCompat.PrereleaseSdkCheck public static boolean isAtLeastT();
+ method @ChecksSdkIntAtLeast(codename="UpsideDownCake") @androidx.core.os.BuildCompat.PrereleaseSdkCheck public static boolean isAtLeastU();
+ field @ChecksSdkIntAtLeast(extension=android.os.ext.SdkExtensions.AD_SERVICES) public static final int AD_SERVICES_EXTENSION_INT;
+ field @ChecksSdkIntAtLeast(extension=android.os.Build.VERSION_CODES.R) public static final int R_EXTENSION_INT;
+ field @ChecksSdkIntAtLeast(extension=android.os.Build.VERSION_CODES.S) public static final int S_EXTENSION_INT;
+ field @ChecksSdkIntAtLeast(extension=android.os.Build.VERSION_CODES.TIRAMISU) public static final int T_EXTENSION_INT;
+ }
+
+ @RequiresOptIn @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.CLASS) public static @interface BuildCompat.PrereleaseSdkCheck {
+ }
+
+ public final class BundleCompat {
+ method public static <T> T? getParcelable(android.os.Bundle, String?, Class<T!>);
+ method public static android.os.Parcelable![]? getParcelableArray(android.os.Bundle, String?, Class<? extends android.os.Parcelable>);
+ method public static <T> java.util.ArrayList<T!>? getParcelableArrayList(android.os.Bundle, String?, Class<? extends T>);
+ method public static <T> android.util.SparseArray<T!>? getSparseParcelableArray(android.os.Bundle, String?, Class<? extends T>);
+ }
+
+ public final class CancellationSignal {
+ ctor public CancellationSignal();
+ method public void cancel();
+ method public Object? getCancellationSignalObject();
+ method public boolean isCanceled();
+ method public void setOnCancelListener(androidx.core.os.CancellationSignal.OnCancelListener?);
+ method public void throwIfCanceled();
+ }
+
+ public static interface CancellationSignal.OnCancelListener {
+ method public void onCancel();
+ }
+
+ public final class ConfigurationCompat {
+ method public static androidx.core.os.LocaleListCompat getLocales(android.content.res.Configuration);
+ }
+
+ public final class EnvironmentCompat {
+ method public static String getStorageState(java.io.File);
+ field public static final String MEDIA_UNKNOWN = "unknown";
+ }
+
+ public final class ExecutorCompat {
+ method public static java.util.concurrent.Executor create(android.os.Handler);
+ }
+
+ public final class HandlerCompat {
+ method public static android.os.Handler createAsync(android.os.Looper);
+ method public static android.os.Handler createAsync(android.os.Looper, android.os.Handler.Callback);
+ method @RequiresApi(16) public static boolean hasCallbacks(android.os.Handler, Runnable);
+ method public static boolean postDelayed(android.os.Handler, Runnable, Object?, long);
+ }
+
+ public final class LocaleListCompat {
+ method public static androidx.core.os.LocaleListCompat create(java.util.Locale!...);
+ method public static androidx.core.os.LocaleListCompat forLanguageTags(String?);
+ method public java.util.Locale? get(int);
+ method @Size(min=1) public static androidx.core.os.LocaleListCompat getAdjustedDefault();
+ method @Size(min=1) public static androidx.core.os.LocaleListCompat getDefault();
+ method public static androidx.core.os.LocaleListCompat getEmptyLocaleList();
+ method public java.util.Locale? getFirstMatch(String![]);
+ method @IntRange(from=0xffffffff) public int indexOf(java.util.Locale?);
+ method public boolean isEmpty();
+ method @RequiresApi(21) public static boolean matchesLanguageAndScript(java.util.Locale, java.util.Locale);
+ method @IntRange(from=0) public int size();
+ method public String toLanguageTags();
+ method public Object? unwrap();
+ method @Deprecated @RequiresApi(24) public static androidx.core.os.LocaleListCompat! wrap(Object!);
+ method @RequiresApi(24) public static androidx.core.os.LocaleListCompat wrap(android.os.LocaleList);
+ }
+
+ public final class MessageCompat {
+ method public static boolean isAsynchronous(android.os.Message);
+ method public static void setAsynchronous(android.os.Message, boolean);
+ }
+
+ public class OperationCanceledException extends java.lang.RuntimeException {
+ ctor public OperationCanceledException();
+ ctor public OperationCanceledException(String?);
+ }
+
+ public final class ParcelCompat {
+ method public static <T> Object![]? readArray(android.os.Parcel, ClassLoader?, Class<T!>);
+ method public static <T> java.util.ArrayList<T!>? readArrayList(android.os.Parcel, ClassLoader?, Class<? extends T>);
+ method public static boolean readBoolean(android.os.Parcel);
+ method public static <K, V> java.util.HashMap<K!,V!>? readHashMap(android.os.Parcel, ClassLoader?, Class<? extends K>, Class<? extends V>);
+ method public static <T> void readList(android.os.Parcel, java.util.List<? super T>, ClassLoader?, Class<T!>);
+ method public static <K, V> void readMap(android.os.Parcel, java.util.Map<? super K,? super V>, ClassLoader?, Class<K!>, Class<V!>);
+ method public static <T extends android.os.Parcelable> T? readParcelable(android.os.Parcel, ClassLoader?, Class<T!>);
+ method @Deprecated public static <T> T![]? readParcelableArray(android.os.Parcel, ClassLoader?, Class<T!>);
+ method public static <T> android.os.Parcelable![]? readParcelableArrayTyped(android.os.Parcel, ClassLoader?, Class<T!>);
+ method @RequiresApi(30) public static <T> android.os.Parcelable.Creator<T!>? readParcelableCreator(android.os.Parcel, ClassLoader?, Class<T!>);
+ method @RequiresApi(api=android.os.Build.VERSION_CODES.Q) public static <T> java.util.List<T!> readParcelableList(android.os.Parcel, java.util.List<T!>, ClassLoader?, Class<T!>);
+ method public static <T extends java.io.Serializable> T? readSerializable(android.os.Parcel, ClassLoader?, Class<T!>);
+ method public static <T> android.util.SparseArray<T!>? readSparseArray(android.os.Parcel, ClassLoader?, Class<? extends T>);
+ method public static void writeBoolean(android.os.Parcel, boolean);
+ }
+
+ @Deprecated public final class ParcelableCompat {
+ method @Deprecated public static <T> android.os.Parcelable.Creator<T!>! newCreator(androidx.core.os.ParcelableCompatCreatorCallbacks<T!>!);
+ }
+
+ @Deprecated public interface ParcelableCompatCreatorCallbacks<T> {
+ method @Deprecated public T! createFromParcel(android.os.Parcel!, ClassLoader!);
+ method @Deprecated public T![]! newArray(int);
+ }
+
+ public final class ProcessCompat {
+ method public static boolean isApplicationUid(int);
+ }
+
+ @Deprecated public final class TraceCompat {
+ method @Deprecated public static void beginAsyncSection(String, int);
+ method @Deprecated public static void beginSection(String);
+ method @Deprecated public static void endAsyncSection(String, int);
+ method @Deprecated public static void endSection();
+ method @Deprecated public static boolean isEnabled();
+ method @Deprecated public static void setCounter(String, int);
+ }
+
+ @RequiresApi(17) public class UserHandleCompat {
+ method public static android.os.UserHandle getUserHandleForUid(int);
+ }
+
+ public class UserManagerCompat {
+ method public static boolean isUserUnlocked(android.content.Context);
+ }
+
+}
+
+package androidx.core.provider {
+
+ public final class DocumentsContractCompat {
+ method public static android.net.Uri? buildChildDocumentsUri(String, String?);
+ method public static android.net.Uri? buildChildDocumentsUriUsingTree(android.net.Uri, String);
+ method public static android.net.Uri? buildDocumentUri(String, String);
+ method public static android.net.Uri? buildDocumentUriUsingTree(android.net.Uri, String);
+ method public static android.net.Uri? buildTreeDocumentUri(String, String);
+ method public static android.net.Uri? createDocument(android.content.ContentResolver, android.net.Uri, String, String) throws java.io.FileNotFoundException;
+ method public static String? getDocumentId(android.net.Uri);
+ method public static String? getTreeDocumentId(android.net.Uri);
+ method public static boolean isDocumentUri(android.content.Context, android.net.Uri?);
+ method public static boolean isTreeUri(android.net.Uri);
+ method public static boolean removeDocument(android.content.ContentResolver, android.net.Uri, android.net.Uri) throws java.io.FileNotFoundException;
+ method public static android.net.Uri? renameDocument(android.content.ContentResolver, android.net.Uri, String) throws java.io.FileNotFoundException;
+ }
+
+ public static final class DocumentsContractCompat.DocumentCompat {
+ field public static final int FLAG_VIRTUAL_DOCUMENT = 512; // 0x200
+ }
+
+ public final class FontRequest {
+ ctor public FontRequest(String, String, String, java.util.List<java.util.List<byte[]!>!>);
+ ctor public FontRequest(String, String, String, @ArrayRes int);
+ method public java.util.List<java.util.List<byte[]!>!>? getCertificates();
+ method @ArrayRes public int getCertificatesArrayResId();
+ method public String getProviderAuthority();
+ method public String getProviderPackage();
+ method public String getQuery();
+ }
+
+ public class FontsContractCompat {
+ method public static android.graphics.Typeface? buildTypeface(android.content.Context, android.os.CancellationSignal?, androidx.core.provider.FontsContractCompat.FontInfo![]);
+ method public static androidx.core.provider.FontsContractCompat.FontFamilyResult fetchFonts(android.content.Context, android.os.CancellationSignal?, androidx.core.provider.FontRequest) throws android.content.pm.PackageManager.NameNotFoundException;
+ method public static void requestFont(android.content.Context, androidx.core.provider.FontRequest, androidx.core.provider.FontsContractCompat.FontRequestCallback, android.os.Handler);
+ }
+
+ public static final class FontsContractCompat.Columns implements android.provider.BaseColumns {
+ ctor public FontsContractCompat.Columns();
+ field public static final String FILE_ID = "file_id";
+ field public static final String ITALIC = "font_italic";
+ field public static final String RESULT_CODE = "result_code";
+ field public static final int RESULT_CODE_FONT_NOT_FOUND = 1; // 0x1
+ field public static final int RESULT_CODE_FONT_UNAVAILABLE = 2; // 0x2
+ field public static final int RESULT_CODE_MALFORMED_QUERY = 3; // 0x3
+ field public static final int RESULT_CODE_OK = 0; // 0x0
+ field public static final String TTC_INDEX = "font_ttc_index";
+ field public static final String VARIATION_SETTINGS = "font_variation_settings";
+ field public static final String WEIGHT = "font_weight";
+ }
+
+ public static class FontsContractCompat.FontFamilyResult {
+ method public androidx.core.provider.FontsContractCompat.FontInfo![]! getFonts();
+ method public int getStatusCode();
+ field public static final int STATUS_OK = 0; // 0x0
+ field public static final int STATUS_UNEXPECTED_DATA_PROVIDED = 2; // 0x2
+ field public static final int STATUS_WRONG_CERTIFICATES = 1; // 0x1
+ }
+
+ public static class FontsContractCompat.FontInfo {
+ method public int getResultCode();
+ method @IntRange(from=0) public int getTtcIndex();
+ method public android.net.Uri getUri();
+ method @IntRange(from=1, to=1000) public int getWeight();
+ method public boolean isItalic();
+ }
+
+ public static class FontsContractCompat.FontRequestCallback {
+ ctor public FontsContractCompat.FontRequestCallback();
+ method public void onTypefaceRequestFailed(int);
+ method public void onTypefaceRetrieved(android.graphics.Typeface!);
+ field public static final int FAIL_REASON_FONT_LOAD_ERROR = -3; // 0xfffffffd
+ field public static final int FAIL_REASON_FONT_NOT_FOUND = 1; // 0x1
+ field public static final int FAIL_REASON_FONT_UNAVAILABLE = 2; // 0x2
+ field public static final int FAIL_REASON_MALFORMED_QUERY = 3; // 0x3
+ field public static final int FAIL_REASON_PROVIDER_NOT_FOUND = -1; // 0xffffffff
+ field public static final int FAIL_REASON_SECURITY_VIOLATION = -4; // 0xfffffffc
+ field public static final int FAIL_REASON_WRONG_CERTIFICATES = -2; // 0xfffffffe
+ }
+
+}
+
+package androidx.core.telephony {
+
+ @RequiresApi(22) public class SubscriptionManagerCompat {
+ method public static int getSlotIndex(int);
+ }
+
+ public class TelephonyManagerCompat {
+ method @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE) public static String? getImei(android.telephony.TelephonyManager);
+ method public static int getSubscriptionId(android.telephony.TelephonyManager);
+ }
+
+}
+
+package androidx.core.telephony.mbms {
+
+ public final class MbmsHelper {
+ method public static CharSequence? getBestNameForService(android.content.Context, android.telephony.mbms.ServiceInfo);
+ }
+
+}
+
+package androidx.core.text {
+
+ public final class BidiFormatter {
+ method public static androidx.core.text.BidiFormatter! getInstance();
+ method public static androidx.core.text.BidiFormatter! getInstance(boolean);
+ method public static androidx.core.text.BidiFormatter! getInstance(java.util.Locale!);
+ method public boolean getStereoReset();
+ method public boolean isRtl(String!);
+ method public boolean isRtl(CharSequence!);
+ method public boolean isRtlContext();
+ method public String! unicodeWrap(String!, androidx.core.text.TextDirectionHeuristicCompat!, boolean);
+ method public CharSequence! unicodeWrap(CharSequence!, androidx.core.text.TextDirectionHeuristicCompat!, boolean);
+ method public String! unicodeWrap(String!, androidx.core.text.TextDirectionHeuristicCompat!);
+ method public CharSequence! unicodeWrap(CharSequence!, androidx.core.text.TextDirectionHeuristicCompat!);
+ method public String! unicodeWrap(String!, boolean);
+ method public CharSequence! unicodeWrap(CharSequence!, boolean);
+ method public String! unicodeWrap(String!);
+ method public CharSequence! unicodeWrap(CharSequence!);
+ }
+
+ public static final class BidiFormatter.Builder {
+ ctor public BidiFormatter.Builder();
+ ctor public BidiFormatter.Builder(boolean);
+ ctor public BidiFormatter.Builder(java.util.Locale!);
+ method public androidx.core.text.BidiFormatter! build();
+ method public androidx.core.text.BidiFormatter.Builder! setTextDirectionHeuristic(androidx.core.text.TextDirectionHeuristicCompat!);
+ method public androidx.core.text.BidiFormatter.Builder! stereoReset(boolean);
+ }
+
+ public final class HtmlCompat {
+ method public static android.text.Spanned fromHtml(String, int);
+ method public static android.text.Spanned fromHtml(String, int, android.text.Html.ImageGetter?, android.text.Html.TagHandler?);
+ method public static String toHtml(android.text.Spanned, int);
+ field public static final int FROM_HTML_MODE_COMPACT = 63; // 0x3f
+ field public static final int FROM_HTML_MODE_LEGACY = 0; // 0x0
+ field public static final int FROM_HTML_OPTION_USE_CSS_COLORS = 256; // 0x100
+ field public static final int FROM_HTML_SEPARATOR_LINE_BREAK_BLOCKQUOTE = 32; // 0x20
+ field public static final int FROM_HTML_SEPARATOR_LINE_BREAK_DIV = 16; // 0x10
+ field public static final int FROM_HTML_SEPARATOR_LINE_BREAK_HEADING = 2; // 0x2
+ field public static final int FROM_HTML_SEPARATOR_LINE_BREAK_LIST = 8; // 0x8
+ field public static final int FROM_HTML_SEPARATOR_LINE_BREAK_LIST_ITEM = 4; // 0x4
+ field public static final int FROM_HTML_SEPARATOR_LINE_BREAK_PARAGRAPH = 1; // 0x1
+ field public static final int TO_HTML_PARAGRAPH_LINES_CONSECUTIVE = 0; // 0x0
+ field public static final int TO_HTML_PARAGRAPH_LINES_INDIVIDUAL = 1; // 0x1
+ }
+
+ public final class ICUCompat {
+ method public static String? maximizeAndGetScript(java.util.Locale);
+ }
+
+ public class PrecomputedTextCompat implements android.text.Spannable {
+ method public char charAt(int);
+ method public static androidx.core.text.PrecomputedTextCompat! create(CharSequence, androidx.core.text.PrecomputedTextCompat.Params);
+ method @IntRange(from=0) public int getParagraphCount();
+ method @IntRange(from=0) public int getParagraphEnd(@IntRange(from=0) int);
+ method @IntRange(from=0) public int getParagraphStart(@IntRange(from=0) int);
+ method public androidx.core.text.PrecomputedTextCompat.Params getParams();
+ method public int getSpanEnd(Object!);
+ method public int getSpanFlags(Object!);
+ method public int getSpanStart(Object!);
+ method public <T> T![]! getSpans(int, int, Class<T!>!);
+ method @UiThread public static java.util.concurrent.Future<androidx.core.text.PrecomputedTextCompat!>! getTextFuture(CharSequence, androidx.core.text.PrecomputedTextCompat.Params, java.util.concurrent.Executor?);
+ method public int length();
+ method public int nextSpanTransition(int, int, Class!);
+ method public void removeSpan(Object!);
+ method public void setSpan(Object!, int, int, int);
+ method public CharSequence! subSequence(int, int);
+ }
+
+ public static final class PrecomputedTextCompat.Params {
+ ctor @RequiresApi(28) public PrecomputedTextCompat.Params(android.text.PrecomputedText.Params);
+ method @RequiresApi(23) public int getBreakStrategy();
+ method @RequiresApi(23) public int getHyphenationFrequency();
+ method @RequiresApi(18) public android.text.TextDirectionHeuristic? getTextDirection();
+ method public android.text.TextPaint getTextPaint();
+ }
+
+ public static class PrecomputedTextCompat.Params.Builder {
+ ctor public PrecomputedTextCompat.Params.Builder(android.text.TextPaint);
+ method public androidx.core.text.PrecomputedTextCompat.Params build();
+ method @RequiresApi(23) public androidx.core.text.PrecomputedTextCompat.Params.Builder! setBreakStrategy(int);
+ method @RequiresApi(23) public androidx.core.text.PrecomputedTextCompat.Params.Builder! setHyphenationFrequency(int);
+ method @RequiresApi(18) public androidx.core.text.PrecomputedTextCompat.Params.Builder! setTextDirection(android.text.TextDirectionHeuristic);
+ }
+
+ public interface TextDirectionHeuristicCompat {
+ method public boolean isRtl(char[]!, int, int);
+ method public boolean isRtl(CharSequence!, int, int);
+ }
+
+ public final class TextDirectionHeuristicsCompat {
+ field public static final androidx.core.text.TextDirectionHeuristicCompat! ANYRTL_LTR;
+ field public static final androidx.core.text.TextDirectionHeuristicCompat! FIRSTSTRONG_LTR;
+ field public static final androidx.core.text.TextDirectionHeuristicCompat! FIRSTSTRONG_RTL;
+ field public static final androidx.core.text.TextDirectionHeuristicCompat! LOCALE;
+ field public static final androidx.core.text.TextDirectionHeuristicCompat! LTR;
+ field public static final androidx.core.text.TextDirectionHeuristicCompat! RTL;
+ }
+
+ public final class TextUtilsCompat {
+ method public static int getLayoutDirectionFromLocale(java.util.Locale?);
+ method public static String htmlEncode(String);
+ }
+
+}
+
+package androidx.core.text.util {
+
+ public final class LinkifyCompat {
+ method public static boolean addLinks(android.text.Spannable, int);
+ method public static boolean addLinks(android.widget.TextView, int);
+ method public static void addLinks(android.widget.TextView, java.util.regex.Pattern, String?);
+ method public static void addLinks(android.widget.TextView, java.util.regex.Pattern, String?, android.text.util.Linkify.MatchFilter?, android.text.util.Linkify.TransformFilter?);
+ method public static void addLinks(android.widget.TextView, java.util.regex.Pattern, String?, String![]?, android.text.util.Linkify.MatchFilter?, android.text.util.Linkify.TransformFilter?);
+ method public static boolean addLinks(android.text.Spannable, java.util.regex.Pattern, String?);
+ method public static boolean addLinks(android.text.Spannable, java.util.regex.Pattern, String?, android.text.util.Linkify.MatchFilter?, android.text.util.Linkify.TransformFilter?);
+ method public static boolean addLinks(android.text.Spannable, java.util.regex.Pattern, String?, String![]?, android.text.util.Linkify.MatchFilter?, android.text.util.Linkify.TransformFilter?);
+ }
+
+}
+
+package androidx.core.util {
+
+ public class AtomicFile {
+ ctor public AtomicFile(java.io.File);
+ method public void delete();
+ method public void failWrite(java.io.FileOutputStream?);
+ method public void finishWrite(java.io.FileOutputStream?);
+ method public java.io.File getBaseFile();
+ method public java.io.FileInputStream openRead() throws java.io.FileNotFoundException;
+ method public byte[] readFully() throws java.io.IOException;
+ method public java.io.FileOutputStream startWrite() throws java.io.IOException;
+ }
+
+ public interface Consumer<T> {
+ method public void accept(T!);
+ }
+
+ public class ObjectsCompat {
+ method public static boolean equals(Object?, Object?);
+ method public static int hash(java.lang.Object!...);
+ method public static int hashCode(Object?);
+ method public static <T> T requireNonNull(T?);
+ method public static <T> T requireNonNull(T?, String);
+ method public static String? toString(Object?, String?);
+ }
+
+ public class Pair<F, S> {
+ ctor public Pair(F!, S!);
+ method public static <A, B> androidx.core.util.Pair<A!,B!> create(A!, B!);
+ field public final F! first;
+ field public final S! second;
+ }
+
+ public final class PatternsCompat {
+ field public static final java.util.regex.Pattern DOMAIN_NAME;
+ field public static final java.util.regex.Pattern EMAIL_ADDRESS;
+ field public static final java.util.regex.Pattern IP_ADDRESS;
+ field public static final java.util.regex.Pattern WEB_URL;
+ }
+
+ public final class Pools {
+ }
+
+ public static interface Pools.Pool<T> {
+ method public T? acquire();
+ method public boolean release(T);
+ }
+
+ public static class Pools.SimplePool<T> implements androidx.core.util.Pools.Pool<T> {
+ ctor public Pools.SimplePool(int);
+ method public T! acquire();
+ method public boolean release(T);
+ }
+
+ public static class Pools.SynchronizedPool<T> extends androidx.core.util.Pools.SimplePool<T> {
+ ctor public Pools.SynchronizedPool(int);
+ }
+
+ public interface Predicate<T> {
+ method public default androidx.core.util.Predicate<T!>! and(androidx.core.util.Predicate<? super T>!);
+ method public static <T> androidx.core.util.Predicate<T!>! isEqual(Object!);
+ method public default androidx.core.util.Predicate<T!>! negate();
+ method public static <T> androidx.core.util.Predicate<T!>! not(androidx.core.util.Predicate<? super T>!);
+ method public default androidx.core.util.Predicate<T!>! or(androidx.core.util.Predicate<? super T>!);
+ method public boolean test(T!);
+ }
+
+ public final class SizeFCompat {
+ ctor public SizeFCompat(float, float);
+ method public float getHeight();
+ method public float getWidth();
+ method @RequiresApi(21) public android.util.SizeF toSizeF();
+ method @RequiresApi(21) public static androidx.core.util.SizeFCompat toSizeFCompat(android.util.SizeF);
+ }
+
+ public interface Supplier<T> {
+ method public T! get();
+ }
+
+}
+
+package androidx.core.view {
+
+ public class AccessibilityDelegateCompat {
+ ctor public AccessibilityDelegateCompat();
+ method public boolean dispatchPopulateAccessibilityEvent(android.view.View, android.view.accessibility.AccessibilityEvent);
+ method public androidx.core.view.accessibility.AccessibilityNodeProviderCompat? getAccessibilityNodeProvider(android.view.View);
+ method public void onInitializeAccessibilityEvent(android.view.View, android.view.accessibility.AccessibilityEvent);
+ method public void onInitializeAccessibilityNodeInfo(android.view.View, androidx.core.view.accessibility.AccessibilityNodeInfoCompat);
+ method public void onPopulateAccessibilityEvent(android.view.View, android.view.accessibility.AccessibilityEvent);
+ method public boolean onRequestSendAccessibilityEvent(android.view.ViewGroup, android.view.View, android.view.accessibility.AccessibilityEvent);
+ method public boolean performAccessibilityAction(android.view.View, int, android.os.Bundle?);
+ method public void sendAccessibilityEvent(android.view.View, int);
+ method public void sendAccessibilityEventUnchecked(android.view.View, android.view.accessibility.AccessibilityEvent);
+ }
+
+ public abstract class ActionProvider {
+ ctor public ActionProvider(android.content.Context);
+ method public android.content.Context getContext();
+ method public boolean hasSubMenu();
+ method public boolean isVisible();
+ method public abstract android.view.View onCreateActionView();
+ method public android.view.View onCreateActionView(android.view.MenuItem);
+ method public boolean onPerformDefaultAction();
+ method public void onPrepareSubMenu(android.view.SubMenu);
+ method public boolean overridesItemVisibility();
+ method public void refreshVisibility();
+ method public void setVisibilityListener(androidx.core.view.ActionProvider.VisibilityListener?);
+ }
+
+ public static interface ActionProvider.VisibilityListener {
+ method public void onActionProviderVisibilityChanged(boolean);
+ }
+
+ public final class ContentInfoCompat {
+ method public android.content.ClipData getClip();
+ method public android.os.Bundle? getExtras();
+ method public int getFlags();
+ method public android.net.Uri? getLinkUri();
+ method public int getSource();
+ method 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 {
+ ctor public ContentInfoCompat.Builder(androidx.core.view.ContentInfoCompat);
+ ctor public ContentInfoCompat.Builder(android.content.ClipData, int);
+ method public androidx.core.view.ContentInfoCompat build();
+ method public androidx.core.view.ContentInfoCompat.Builder setClip(android.content.ClipData);
+ method public androidx.core.view.ContentInfoCompat.Builder setExtras(android.os.Bundle?);
+ method public androidx.core.view.ContentInfoCompat.Builder setFlags(int);
+ method public androidx.core.view.ContentInfoCompat.Builder setLinkUri(android.net.Uri?);
+ method public androidx.core.view.ContentInfoCompat.Builder setSource(int);
+ }
+
+ public final class DisplayCompat {
+ method public static androidx.core.view.DisplayCompat.ModeCompat getMode(android.content.Context, android.view.Display);
+ method public static androidx.core.view.DisplayCompat.ModeCompat![] getSupportedModes(android.content.Context, android.view.Display);
+ }
+
+ public static final class DisplayCompat.ModeCompat {
+ method public int getPhysicalHeight();
+ method public int getPhysicalWidth();
+ method @Deprecated public boolean isNative();
+ method @RequiresApi(android.os.Build.VERSION_CODES.M) public android.view.Display.Mode? toMode();
+ }
+
+ public final class DisplayCutoutCompat {
+ ctor public DisplayCutoutCompat(android.graphics.Rect?, java.util.List<android.graphics.Rect!>?);
+ ctor public DisplayCutoutCompat(androidx.core.graphics.Insets, android.graphics.Rect?, android.graphics.Rect?, android.graphics.Rect?, android.graphics.Rect?, androidx.core.graphics.Insets);
+ method public java.util.List<android.graphics.Rect!> getBoundingRects();
+ method public int getSafeInsetBottom();
+ method public int getSafeInsetLeft();
+ method public int getSafeInsetRight();
+ method public int getSafeInsetTop();
+ method public androidx.core.graphics.Insets getWaterfallInsets();
+ }
+
+ public final class DragAndDropPermissionsCompat {
+ method public void release();
+ }
+
+ public class DragStartHelper {
+ ctor public DragStartHelper(android.view.View, androidx.core.view.DragStartHelper.OnDragStartListener);
+ method public void attach();
+ method public void detach();
+ method public void getTouchPosition(android.graphics.Point);
+ method public boolean onLongClick(android.view.View);
+ method public boolean onTouch(android.view.View, android.view.MotionEvent);
+ }
+
+ public static interface DragStartHelper.OnDragStartListener {
+ method public boolean onDragStart(android.view.View, androidx.core.view.DragStartHelper);
+ }
+
+ public final class GestureDetectorCompat {
+ ctor public GestureDetectorCompat(android.content.Context, android.view.GestureDetector.OnGestureListener);
+ ctor public GestureDetectorCompat(android.content.Context, android.view.GestureDetector.OnGestureListener, android.os.Handler?);
+ method public boolean isLongpressEnabled();
+ method public boolean onTouchEvent(android.view.MotionEvent);
+ method public void setIsLongpressEnabled(boolean);
+ method public void setOnDoubleTapListener(android.view.GestureDetector.OnDoubleTapListener?);
+ }
+
+ public final class GravityCompat {
+ method public static void apply(int, int, int, android.graphics.Rect, android.graphics.Rect, int);
+ method public static void apply(int, int, int, android.graphics.Rect, int, int, android.graphics.Rect, int);
+ method public static void applyDisplay(int, android.graphics.Rect, android.graphics.Rect, int);
+ method public static int getAbsoluteGravity(int, int);
+ field public static final int END = 8388613; // 0x800005
+ field public static final int RELATIVE_HORIZONTAL_GRAVITY_MASK = 8388615; // 0x800007
+ field public static final int RELATIVE_LAYOUT_DIRECTION = 8388608; // 0x800000
+ field public static final int START = 8388611; // 0x800003
+ }
+
+ public final class InputDeviceCompat {
+ field public static final int SOURCE_ANY = -256; // 0xffffff00
+ field public static final int SOURCE_CLASS_BUTTON = 1; // 0x1
+ field public static final int SOURCE_CLASS_JOYSTICK = 16; // 0x10
+ field public static final int SOURCE_CLASS_MASK = 255; // 0xff
+ field public static final int SOURCE_CLASS_NONE = 0; // 0x0
+ field public static final int SOURCE_CLASS_POINTER = 2; // 0x2
+ field public static final int SOURCE_CLASS_POSITION = 8; // 0x8
+ field public static final int SOURCE_CLASS_TRACKBALL = 4; // 0x4
+ field public static final int SOURCE_DPAD = 513; // 0x201
+ field public static final int SOURCE_GAMEPAD = 1025; // 0x401
+ field public static final int SOURCE_HDMI = 33554433; // 0x2000001
+ field public static final int SOURCE_JOYSTICK = 16777232; // 0x1000010
+ field public static final int SOURCE_KEYBOARD = 257; // 0x101
+ field public static final int SOURCE_MOUSE = 8194; // 0x2002
+ field public static final int SOURCE_ROTARY_ENCODER = 4194304; // 0x400000
+ field public static final int SOURCE_STYLUS = 16386; // 0x4002
+ field public static final int SOURCE_TOUCHPAD = 1048584; // 0x100008
+ field public static final int SOURCE_TOUCHSCREEN = 4098; // 0x1002
+ field public static final int SOURCE_TOUCH_NAVIGATION = 2097152; // 0x200000
+ field public static final int SOURCE_TRACKBALL = 65540; // 0x10004
+ field public static final int SOURCE_UNKNOWN = 0; // 0x0
+ }
+
+ public final class LayoutInflaterCompat {
+ method @Deprecated public static androidx.core.view.LayoutInflaterFactory! getFactory(android.view.LayoutInflater!);
+ method @Deprecated public static void setFactory(android.view.LayoutInflater, androidx.core.view.LayoutInflaterFactory);
+ method public static void setFactory2(android.view.LayoutInflater, android.view.LayoutInflater.Factory2);
+ }
+
+ @Deprecated public interface LayoutInflaterFactory {
+ method @Deprecated public android.view.View! onCreateView(android.view.View!, String!, android.content.Context!, android.util.AttributeSet!);
+ }
+
+ public final class MarginLayoutParamsCompat {
+ method public static int getLayoutDirection(android.view.ViewGroup.MarginLayoutParams);
+ method public static int getMarginEnd(android.view.ViewGroup.MarginLayoutParams);
+ method public static int getMarginStart(android.view.ViewGroup.MarginLayoutParams);
+ method public static boolean isMarginRelative(android.view.ViewGroup.MarginLayoutParams);
+ method public static void resolveLayoutDirection(android.view.ViewGroup.MarginLayoutParams, int);
+ method public static void setLayoutDirection(android.view.ViewGroup.MarginLayoutParams, int);
+ method public static void setMarginEnd(android.view.ViewGroup.MarginLayoutParams, int);
+ method public static void setMarginStart(android.view.ViewGroup.MarginLayoutParams, int);
+ }
+
+ public final class MenuCompat {
+ method public static void setGroupDividerEnabled(android.view.Menu, boolean);
+ method @Deprecated public static void setShowAsAction(android.view.MenuItem!, int);
+ }
+
+ public interface MenuHost {
+ method public void addMenuProvider(androidx.core.view.MenuProvider);
+ method public void addMenuProvider(androidx.core.view.MenuProvider, androidx.lifecycle.LifecycleOwner);
+ method public void addMenuProvider(androidx.core.view.MenuProvider, androidx.lifecycle.LifecycleOwner, androidx.lifecycle.Lifecycle.State);
+ method public void invalidateMenu();
+ method public void removeMenuProvider(androidx.core.view.MenuProvider);
+ }
+
+ public class MenuHostHelper {
+ ctor public MenuHostHelper(Runnable);
+ method public void addMenuProvider(androidx.core.view.MenuProvider);
+ method public void addMenuProvider(androidx.core.view.MenuProvider, androidx.lifecycle.LifecycleOwner);
+ method public void addMenuProvider(androidx.core.view.MenuProvider, androidx.lifecycle.LifecycleOwner, androidx.lifecycle.Lifecycle.State);
+ method public void onCreateMenu(android.view.Menu, android.view.MenuInflater);
+ method public void onMenuClosed(android.view.Menu);
+ method public boolean onMenuItemSelected(android.view.MenuItem);
+ method public void onPrepareMenu(android.view.Menu);
+ method public void removeMenuProvider(androidx.core.view.MenuProvider);
+ }
+
+ public final class MenuItemCompat {
+ method @Deprecated public static boolean collapseActionView(android.view.MenuItem!);
+ method @Deprecated public static boolean expandActionView(android.view.MenuItem!);
+ method public static androidx.core.view.ActionProvider? getActionProvider(android.view.MenuItem);
+ method @Deprecated public static android.view.View! getActionView(android.view.MenuItem!);
+ method public static int getAlphabeticModifiers(android.view.MenuItem);
+ method public static CharSequence? getContentDescription(android.view.MenuItem);
+ method public static android.content.res.ColorStateList? getIconTintList(android.view.MenuItem);
+ method public static android.graphics.PorterDuff.Mode? getIconTintMode(android.view.MenuItem);
+ method public static int getNumericModifiers(android.view.MenuItem);
+ method public static CharSequence? getTooltipText(android.view.MenuItem);
+ method @Deprecated public static boolean isActionViewExpanded(android.view.MenuItem!);
+ method public static android.view.MenuItem? setActionProvider(android.view.MenuItem, androidx.core.view.ActionProvider?);
+ method @Deprecated public static android.view.MenuItem! setActionView(android.view.MenuItem!, android.view.View!);
+ method @Deprecated public static android.view.MenuItem! setActionView(android.view.MenuItem!, int);
+ method public static void setAlphabeticShortcut(android.view.MenuItem, char, int);
+ method public static void setContentDescription(android.view.MenuItem, CharSequence?);
+ method public static void setIconTintList(android.view.MenuItem, android.content.res.ColorStateList?);
+ method public static void setIconTintMode(android.view.MenuItem, android.graphics.PorterDuff.Mode?);
+ method public static void setNumericShortcut(android.view.MenuItem, char, int);
+ method @Deprecated public static android.view.MenuItem! setOnActionExpandListener(android.view.MenuItem!, androidx.core.view.MenuItemCompat.OnActionExpandListener!);
+ method public static void setShortcut(android.view.MenuItem, char, char, int, int);
+ method @Deprecated public static void setShowAsAction(android.view.MenuItem!, int);
+ method public static void setTooltipText(android.view.MenuItem, CharSequence?);
+ field @Deprecated public static final int SHOW_AS_ACTION_ALWAYS = 2; // 0x2
+ field @Deprecated public static final int SHOW_AS_ACTION_COLLAPSE_ACTION_VIEW = 8; // 0x8
+ field @Deprecated public static final int SHOW_AS_ACTION_IF_ROOM = 1; // 0x1
+ field @Deprecated public static final int SHOW_AS_ACTION_NEVER = 0; // 0x0
+ field @Deprecated public static final int SHOW_AS_ACTION_WITH_TEXT = 4; // 0x4
+ }
+
+ @Deprecated public static interface MenuItemCompat.OnActionExpandListener {
+ method @Deprecated public boolean onMenuItemActionCollapse(android.view.MenuItem!);
+ method @Deprecated public boolean onMenuItemActionExpand(android.view.MenuItem!);
+ }
+
+ public interface MenuProvider {
+ method public void onCreateMenu(android.view.Menu, android.view.MenuInflater);
+ method public default void onMenuClosed(android.view.Menu);
+ method public boolean onMenuItemSelected(android.view.MenuItem);
+ method public default void onPrepareMenu(android.view.Menu);
+ }
+
+ public final class MotionEventCompat {
+ method @Deprecated public static int findPointerIndex(android.view.MotionEvent!, int);
+ method @Deprecated public static int getActionIndex(android.view.MotionEvent!);
+ method @Deprecated public static int getActionMasked(android.view.MotionEvent!);
+ method @Deprecated public static float getAxisValue(android.view.MotionEvent!, int);
+ method @Deprecated public static float getAxisValue(android.view.MotionEvent!, int, int);
+ method @Deprecated public static int getButtonState(android.view.MotionEvent!);
+ method @Deprecated public static int getPointerCount(android.view.MotionEvent!);
+ method @Deprecated public static int getPointerId(android.view.MotionEvent!, int);
+ method @Deprecated public static int getSource(android.view.MotionEvent!);
+ method @Deprecated public static float getX(android.view.MotionEvent!, int);
+ method @Deprecated public static float getY(android.view.MotionEvent!, int);
+ method public static boolean isFromSource(android.view.MotionEvent, int);
+ field @Deprecated public static final int ACTION_HOVER_ENTER = 9; // 0x9
+ field @Deprecated public static final int ACTION_HOVER_EXIT = 10; // 0xa
+ field @Deprecated public static final int ACTION_HOVER_MOVE = 7; // 0x7
+ field @Deprecated public static final int ACTION_MASK = 255; // 0xff
+ field @Deprecated public static final int ACTION_POINTER_DOWN = 5; // 0x5
+ field @Deprecated public static final int ACTION_POINTER_INDEX_MASK = 65280; // 0xff00
+ field @Deprecated public static final int ACTION_POINTER_INDEX_SHIFT = 8; // 0x8
+ field @Deprecated public static final int ACTION_POINTER_UP = 6; // 0x6
+ field @Deprecated public static final int ACTION_SCROLL = 8; // 0x8
+ field @Deprecated public static final int AXIS_BRAKE = 23; // 0x17
+ field @Deprecated public static final int AXIS_DISTANCE = 24; // 0x18
+ field @Deprecated public static final int AXIS_GAS = 22; // 0x16
+ field @Deprecated public static final int AXIS_GENERIC_1 = 32; // 0x20
+ field @Deprecated public static final int AXIS_GENERIC_10 = 41; // 0x29
+ field @Deprecated public static final int AXIS_GENERIC_11 = 42; // 0x2a
+ field @Deprecated public static final int AXIS_GENERIC_12 = 43; // 0x2b
+ field @Deprecated public static final int AXIS_GENERIC_13 = 44; // 0x2c
+ field @Deprecated public static final int AXIS_GENERIC_14 = 45; // 0x2d
+ field @Deprecated public static final int AXIS_GENERIC_15 = 46; // 0x2e
+ field @Deprecated public static final int AXIS_GENERIC_16 = 47; // 0x2f
+ field @Deprecated public static final int AXIS_GENERIC_2 = 33; // 0x21
+ field @Deprecated public static final int AXIS_GENERIC_3 = 34; // 0x22
+ field @Deprecated public static final int AXIS_GENERIC_4 = 35; // 0x23
+ field @Deprecated public static final int AXIS_GENERIC_5 = 36; // 0x24
+ field @Deprecated public static final int AXIS_GENERIC_6 = 37; // 0x25
+ field @Deprecated public static final int AXIS_GENERIC_7 = 38; // 0x26
+ field @Deprecated public static final int AXIS_GENERIC_8 = 39; // 0x27
+ field @Deprecated public static final int AXIS_GENERIC_9 = 40; // 0x28
+ field @Deprecated public static final int AXIS_HAT_X = 15; // 0xf
+ field @Deprecated public static final int AXIS_HAT_Y = 16; // 0x10
+ field @Deprecated public static final int AXIS_HSCROLL = 10; // 0xa
+ field @Deprecated public static final int AXIS_LTRIGGER = 17; // 0x11
+ field @Deprecated public static final int AXIS_ORIENTATION = 8; // 0x8
+ field @Deprecated public static final int AXIS_PRESSURE = 2; // 0x2
+ field public static final int AXIS_RELATIVE_X = 27; // 0x1b
+ field public static final int AXIS_RELATIVE_Y = 28; // 0x1c
+ field @Deprecated public static final int AXIS_RTRIGGER = 18; // 0x12
+ field @Deprecated public static final int AXIS_RUDDER = 20; // 0x14
+ field @Deprecated public static final int AXIS_RX = 12; // 0xc
+ field @Deprecated public static final int AXIS_RY = 13; // 0xd
+ field @Deprecated public static final int AXIS_RZ = 14; // 0xe
+ field public static final int AXIS_SCROLL = 26; // 0x1a
+ field @Deprecated public static final int AXIS_SIZE = 3; // 0x3
+ field @Deprecated public static final int AXIS_THROTTLE = 19; // 0x13
+ field @Deprecated public static final int AXIS_TILT = 25; // 0x19
+ field @Deprecated public static final int AXIS_TOOL_MAJOR = 6; // 0x6
+ field @Deprecated public static final int AXIS_TOOL_MINOR = 7; // 0x7
+ field @Deprecated public static final int AXIS_TOUCH_MAJOR = 4; // 0x4
+ field @Deprecated public static final int AXIS_TOUCH_MINOR = 5; // 0x5
+ field @Deprecated public static final int AXIS_VSCROLL = 9; // 0x9
+ field @Deprecated public static final int AXIS_WHEEL = 21; // 0x15
+ field @Deprecated public static final int AXIS_X = 0; // 0x0
+ field @Deprecated public static final int AXIS_Y = 1; // 0x1
+ field @Deprecated public static final int AXIS_Z = 11; // 0xb
+ field @Deprecated public static final int BUTTON_PRIMARY = 1; // 0x1
+ }
+
+ public interface NestedScrollingChild {
+ method public boolean dispatchNestedFling(float, float, boolean);
+ method public boolean dispatchNestedPreFling(float, float);
+ method public boolean dispatchNestedPreScroll(int, int, int[]?, int[]?);
+ method public boolean dispatchNestedScroll(int, int, int, int, int[]?);
+ method public boolean hasNestedScrollingParent();
+ method public boolean isNestedScrollingEnabled();
+ method public void setNestedScrollingEnabled(boolean);
+ method public boolean startNestedScroll(int);
+ method public void stopNestedScroll();
+ }
+
+ public interface NestedScrollingChild2 extends androidx.core.view.NestedScrollingChild {
+ method public boolean dispatchNestedPreScroll(int, int, int[]?, int[]?, int);
+ method public boolean dispatchNestedScroll(int, int, int, int, int[]?, int);
+ method public boolean hasNestedScrollingParent(int);
+ method public boolean startNestedScroll(int, int);
+ method public void stopNestedScroll(int);
+ }
+
+ public interface NestedScrollingChild3 extends androidx.core.view.NestedScrollingChild2 {
+ method public void dispatchNestedScroll(int, int, int, int, int[]?, int, int[]);
+ }
+
+ public class NestedScrollingChildHelper {
+ ctor public NestedScrollingChildHelper(android.view.View);
+ method public boolean dispatchNestedFling(float, float, boolean);
+ method public boolean dispatchNestedPreFling(float, float);
+ method public boolean dispatchNestedPreScroll(int, int, int[]?, int[]?);
+ method public boolean dispatchNestedPreScroll(int, int, int[]?, int[]?, int);
+ method public boolean dispatchNestedScroll(int, int, int, int, int[]?);
+ method public boolean dispatchNestedScroll(int, int, int, int, int[]?, int);
+ method public void dispatchNestedScroll(int, int, int, int, int[]?, int, int[]?);
+ method public boolean hasNestedScrollingParent();
+ method public boolean hasNestedScrollingParent(int);
+ method public boolean isNestedScrollingEnabled();
+ method public void onDetachedFromWindow();
+ method public void onStopNestedScroll(android.view.View);
+ method public void setNestedScrollingEnabled(boolean);
+ method public boolean startNestedScroll(int);
+ method public boolean startNestedScroll(int, int);
+ method public void stopNestedScroll();
+ method public void stopNestedScroll(int);
+ }
+
+ public interface NestedScrollingParent {
+ method public int getNestedScrollAxes();
+ method public boolean onNestedFling(android.view.View, float, float, boolean);
+ method public boolean onNestedPreFling(android.view.View, float, float);
+ method public void onNestedPreScroll(android.view.View, int, int, int[]);
+ method public void onNestedScroll(android.view.View, int, int, int, int);
+ method public void onNestedScrollAccepted(android.view.View, android.view.View, int);
+ method public boolean onStartNestedScroll(android.view.View, android.view.View, int);
+ method public void onStopNestedScroll(android.view.View);
+ }
+
+ public interface NestedScrollingParent2 extends androidx.core.view.NestedScrollingParent {
+ method public void onNestedPreScroll(android.view.View, int, int, int[], int);
+ method public void onNestedScroll(android.view.View, int, int, int, int, int);
+ method public void onNestedScrollAccepted(android.view.View, android.view.View, int, int);
+ method public boolean onStartNestedScroll(android.view.View, android.view.View, int, int);
+ method public void onStopNestedScroll(android.view.View, int);
+ }
+
+ public interface NestedScrollingParent3 extends androidx.core.view.NestedScrollingParent2 {
+ method public void onNestedScroll(android.view.View, int, int, int, int, int, int[]);
+ }
+
+ public class NestedScrollingParentHelper {
+ ctor public NestedScrollingParentHelper(android.view.ViewGroup);
+ method public int getNestedScrollAxes();
+ method public void onNestedScrollAccepted(android.view.View, android.view.View, int);
+ method public void onNestedScrollAccepted(android.view.View, android.view.View, int, int);
+ method public void onStopNestedScroll(android.view.View);
+ method public void onStopNestedScroll(android.view.View, int);
+ }
+
+ public interface OnApplyWindowInsetsListener {
+ method public androidx.core.view.WindowInsetsCompat onApplyWindowInsets(android.view.View, androidx.core.view.WindowInsetsCompat);
+ }
+
+ public interface OnReceiveContentListener {
+ method public androidx.core.view.ContentInfoCompat? onReceiveContent(android.view.View, androidx.core.view.ContentInfoCompat);
+ }
+
+ public interface OnReceiveContentViewBehavior {
+ method public androidx.core.view.ContentInfoCompat? onReceiveContent(androidx.core.view.ContentInfoCompat);
+ }
+
+ public final class OneShotPreDrawListener implements android.view.View.OnAttachStateChangeListener android.view.ViewTreeObserver.OnPreDrawListener {
+ method public static androidx.core.view.OneShotPreDrawListener add(android.view.View, Runnable);
+ method public boolean onPreDraw();
+ method public void onViewAttachedToWindow(android.view.View);
+ method public void onViewDetachedFromWindow(android.view.View);
+ method public void removeListener();
+ }
+
+ public final class PointerIconCompat {
+ method public static androidx.core.view.PointerIconCompat create(android.graphics.Bitmap, float, float);
+ method public static androidx.core.view.PointerIconCompat getSystemIcon(android.content.Context, int);
+ method public static androidx.core.view.PointerIconCompat load(android.content.res.Resources, int);
+ field public static final int TYPE_ALIAS = 1010; // 0x3f2
+ field public static final int TYPE_ALL_SCROLL = 1013; // 0x3f5
+ field public static final int TYPE_ARROW = 1000; // 0x3e8
+ field public static final int TYPE_CELL = 1006; // 0x3ee
+ field public static final int TYPE_CONTEXT_MENU = 1001; // 0x3e9
+ field public static final int TYPE_COPY = 1011; // 0x3f3
+ field public static final int TYPE_CROSSHAIR = 1007; // 0x3ef
+ field public static final int TYPE_DEFAULT = 1000; // 0x3e8
+ field public static final int TYPE_GRAB = 1020; // 0x3fc
+ field public static final int TYPE_GRABBING = 1021; // 0x3fd
+ field public static final int TYPE_HAND = 1002; // 0x3ea
+ field public static final int TYPE_HELP = 1003; // 0x3eb
+ field public static final int TYPE_HORIZONTAL_DOUBLE_ARROW = 1014; // 0x3f6
+ field public static final int TYPE_NO_DROP = 1012; // 0x3f4
+ field public static final int TYPE_NULL = 0; // 0x0
+ field public static final int TYPE_TEXT = 1008; // 0x3f0
+ field public static final int TYPE_TOP_LEFT_DIAGONAL_DOUBLE_ARROW = 1017; // 0x3f9
+ field public static final int TYPE_TOP_RIGHT_DIAGONAL_DOUBLE_ARROW = 1016; // 0x3f8
+ field public static final int TYPE_VERTICAL_DOUBLE_ARROW = 1015; // 0x3f7
+ field public static final int TYPE_VERTICAL_TEXT = 1009; // 0x3f1
+ field public static final int TYPE_WAIT = 1004; // 0x3ec
+ field public static final int TYPE_ZOOM_IN = 1018; // 0x3fa
+ field public static final int TYPE_ZOOM_OUT = 1019; // 0x3fb
+ }
+
+ public final class ScaleGestureDetectorCompat {
+ method @Deprecated public static boolean isQuickScaleEnabled(Object!);
+ method public static boolean isQuickScaleEnabled(android.view.ScaleGestureDetector);
+ method @Deprecated public static void setQuickScaleEnabled(Object!, boolean);
+ method public static void setQuickScaleEnabled(android.view.ScaleGestureDetector, boolean);
+ }
+
+ public interface ScrollingView {
+ method public int computeHorizontalScrollExtent();
+ method public int computeHorizontalScrollOffset();
+ method public int computeHorizontalScrollRange();
+ method public int computeVerticalScrollExtent();
+ method public int computeVerticalScrollOffset();
+ method public int computeVerticalScrollRange();
+ }
+
+ public interface TintableBackgroundView {
+ method public android.content.res.ColorStateList? getSupportBackgroundTintList();
+ method public android.graphics.PorterDuff.Mode? getSupportBackgroundTintMode();
+ method public void setSupportBackgroundTintList(android.content.res.ColorStateList?);
+ method public void setSupportBackgroundTintMode(android.graphics.PorterDuff.Mode?);
+ }
+
+ @Deprecated public final class VelocityTrackerCompat {
+ method @Deprecated public static float getXVelocity(android.view.VelocityTracker!, int);
+ method @Deprecated public static float getYVelocity(android.view.VelocityTracker!, int);
+ }
+
+ public class ViewCompat {
+ ctor @Deprecated protected ViewCompat();
+ method public static int addAccessibilityAction(android.view.View, CharSequence, androidx.core.view.accessibility.AccessibilityViewCommand);
+ method public static void addKeyboardNavigationClusters(android.view.View, java.util.Collection<android.view.View!>, int);
+ method public static void addOnUnhandledKeyEventListener(android.view.View, androidx.core.view.ViewCompat.OnUnhandledKeyEventListenerCompat);
+ method public static androidx.core.view.ViewPropertyAnimatorCompat animate(android.view.View);
+ method @Deprecated public static boolean canScrollHorizontally(android.view.View!, int);
+ method @Deprecated public static boolean canScrollVertically(android.view.View!, int);
+ method public static void cancelDragAndDrop(android.view.View);
+ method @Deprecated public static int combineMeasuredStates(int, int);
+ method public static androidx.core.view.WindowInsetsCompat computeSystemWindowInsets(android.view.View, androidx.core.view.WindowInsetsCompat, android.graphics.Rect);
+ method public static androidx.core.view.WindowInsetsCompat dispatchApplyWindowInsets(android.view.View, androidx.core.view.WindowInsetsCompat);
+ method public static void dispatchFinishTemporaryDetach(android.view.View);
+ method public static boolean dispatchNestedFling(android.view.View, float, float, boolean);
+ method public static boolean dispatchNestedPreFling(android.view.View, float, float);
+ method public static boolean dispatchNestedPreScroll(android.view.View, int, int, int[]?, int[]?);
+ method public static boolean dispatchNestedPreScroll(android.view.View, int, int, int[]?, int[]?, int);
+ method public static boolean dispatchNestedScroll(android.view.View, int, int, int, int, int[]?);
+ method public static void dispatchNestedScroll(android.view.View, int, int, int, int, int[]?, int, int[]);
+ method public static boolean dispatchNestedScroll(android.view.View, int, int, int, int, int[]?, int);
+ method public static void dispatchStartTemporaryDetach(android.view.View);
+ method public static void enableAccessibleClickableSpanSupport(android.view.View);
+ method public static int generateViewId();
+ method public static androidx.core.view.AccessibilityDelegateCompat? getAccessibilityDelegate(android.view.View);
+ method public static int getAccessibilityLiveRegion(android.view.View);
+ method public static androidx.core.view.accessibility.AccessibilityNodeProviderCompat? getAccessibilityNodeProvider(android.view.View);
+ method @UiThread public static CharSequence? getAccessibilityPaneTitle(android.view.View);
+ method @Deprecated public static float getAlpha(android.view.View!);
+ method public static android.content.res.ColorStateList? getBackgroundTintList(android.view.View);
+ method public static android.graphics.PorterDuff.Mode? getBackgroundTintMode(android.view.View);
+ method public static android.graphics.Rect? getClipBounds(android.view.View);
+ method public static android.view.Display? getDisplay(android.view.View);
+ method public static float getElevation(android.view.View);
+ method public static boolean getFitsSystemWindows(android.view.View);
+ method public static int getImportantForAccessibility(android.view.View);
+ method public static int getImportantForAutofill(android.view.View);
+ method public static int getLabelFor(android.view.View);
+ method @Deprecated public static int getLayerType(android.view.View!);
+ method public static int getLayoutDirection(android.view.View);
+ method @Deprecated public static android.graphics.Matrix? getMatrix(android.view.View!);
+ method @Deprecated public static int getMeasuredHeightAndState(android.view.View!);
+ method @Deprecated public static int getMeasuredState(android.view.View!);
+ method @Deprecated public static int getMeasuredWidthAndState(android.view.View!);
+ method public static int getMinimumHeight(android.view.View);
+ method public static int getMinimumWidth(android.view.View);
+ method public static int getNextClusterForwardId(android.view.View);
+ method public static String![]? getOnReceiveContentMimeTypes(android.view.View);
+ method @Deprecated public static int getOverScrollMode(android.view.View!);
+ method @Px public static int getPaddingEnd(android.view.View);
+ method @Px public static int getPaddingStart(android.view.View);
+ method public static android.view.ViewParent? getParentForAccessibility(android.view.View);
+ method @Deprecated public static float getPivotX(android.view.View!);
+ method @Deprecated public static float getPivotY(android.view.View!);
+ method public static androidx.core.view.WindowInsetsCompat? getRootWindowInsets(android.view.View);
+ method @Deprecated public static float getRotation(android.view.View!);
+ method @Deprecated public static float getRotationX(android.view.View!);
+ method @Deprecated public static float getRotationY(android.view.View!);
+ method @Deprecated public static float getScaleX(android.view.View!);
+ method @Deprecated public static float getScaleY(android.view.View!);
+ method public static int getScrollIndicators(android.view.View);
+ method @UiThread public static CharSequence? getStateDescription(android.view.View);
+ method public static java.util.List<android.graphics.Rect!> getSystemGestureExclusionRects(android.view.View);
+ method public static String? getTransitionName(android.view.View);
+ method @Deprecated public static float getTranslationX(android.view.View!);
+ method @Deprecated public static float getTranslationY(android.view.View!);
+ method public static float getTranslationZ(android.view.View);
+ method @Deprecated public static androidx.core.view.WindowInsetsControllerCompat? getWindowInsetsController(android.view.View);
+ method @Deprecated public static int getWindowSystemUiVisibility(android.view.View);
+ method @Deprecated public static float getX(android.view.View!);
+ method @Deprecated public static float getY(android.view.View!);
+ method public static float getZ(android.view.View);
+ method public static boolean hasAccessibilityDelegate(android.view.View);
+ method public static boolean hasExplicitFocusable(android.view.View);
+ method public static boolean hasNestedScrollingParent(android.view.View);
+ method public static boolean hasNestedScrollingParent(android.view.View, int);
+ method public static boolean hasOnClickListeners(android.view.View);
+ method public static boolean hasOverlappingRendering(android.view.View);
+ method public static boolean hasTransientState(android.view.View);
+ method @UiThread public static boolean isAccessibilityHeading(android.view.View);
+ method public static boolean isAttachedToWindow(android.view.View);
+ method public static boolean isFocusedByDefault(android.view.View);
+ method public static boolean isImportantForAccessibility(android.view.View);
+ method public static boolean isImportantForAutofill(android.view.View);
+ method public static boolean isInLayout(android.view.View);
+ method public static boolean isKeyboardNavigationCluster(android.view.View);
+ method public static boolean isLaidOut(android.view.View);
+ method public static boolean isLayoutDirectionResolved(android.view.View);
+ method public static boolean isNestedScrollingEnabled(android.view.View);
+ method @Deprecated public static boolean isOpaque(android.view.View!);
+ method public static boolean isPaddingRelative(android.view.View);
+ method @UiThread public static boolean isScreenReaderFocusable(android.view.View);
+ method @Deprecated public static void jumpDrawablesToCurrentState(android.view.View!);
+ method public static android.view.View? keyboardNavigationClusterSearch(android.view.View, android.view.View?, int);
+ method public static void offsetLeftAndRight(android.view.View, int);
+ method public static void offsetTopAndBottom(android.view.View, int);
+ method public static androidx.core.view.WindowInsetsCompat onApplyWindowInsets(android.view.View, androidx.core.view.WindowInsetsCompat);
+ method @Deprecated public static void onInitializeAccessibilityEvent(android.view.View!, android.view.accessibility.AccessibilityEvent!);
+ method public static void onInitializeAccessibilityNodeInfo(android.view.View, androidx.core.view.accessibility.AccessibilityNodeInfoCompat);
+ method @Deprecated public static void onPopulateAccessibilityEvent(android.view.View!, android.view.accessibility.AccessibilityEvent!);
+ method public static boolean performAccessibilityAction(android.view.View, int, android.os.Bundle?);
+ method public static androidx.core.view.ContentInfoCompat? performReceiveContent(android.view.View, androidx.core.view.ContentInfoCompat);
+ method public static void postInvalidateOnAnimation(android.view.View);
+ method public static void postInvalidateOnAnimation(android.view.View, int, int, int, int);
+ method public static void postOnAnimation(android.view.View, Runnable);
+ method public static void postOnAnimationDelayed(android.view.View, Runnable, long);
+ method public static void removeAccessibilityAction(android.view.View, int);
+ method public static void removeOnUnhandledKeyEventListener(android.view.View, androidx.core.view.ViewCompat.OnUnhandledKeyEventListenerCompat);
+ method public static void replaceAccessibilityAction(android.view.View, androidx.core.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat, CharSequence?, androidx.core.view.accessibility.AccessibilityViewCommand?);
+ method public static void requestApplyInsets(android.view.View);
+ method public static <T extends android.view.View> T requireViewById(android.view.View, @IdRes int);
+ method @Deprecated public static int resolveSizeAndState(int, int, int);
+ method public static boolean restoreDefaultFocus(android.view.View);
+ method public static void saveAttributeDataForStyleable(android.view.View, android.content.Context, int[], android.util.AttributeSet?, android.content.res.TypedArray, int, int);
+ method public static void setAccessibilityDelegate(android.view.View, androidx.core.view.AccessibilityDelegateCompat?);
+ method @UiThread public static void setAccessibilityHeading(android.view.View, boolean);
+ method public static void setAccessibilityLiveRegion(android.view.View, int);
+ method @UiThread public static void setAccessibilityPaneTitle(android.view.View, CharSequence?);
+ method @Deprecated public static void setActivated(android.view.View!, boolean);
+ method @Deprecated public static void setAlpha(android.view.View!, @FloatRange(from=0.0, to=1.0) float);
+ method public static void setAutofillHints(android.view.View, java.lang.String!...);
+ method public static void setBackground(android.view.View, android.graphics.drawable.Drawable?);
+ method public static void setBackgroundTintList(android.view.View, android.content.res.ColorStateList?);
+ method public static void setBackgroundTintMode(android.view.View, android.graphics.PorterDuff.Mode?);
+ method @Deprecated public static void setChildrenDrawingOrderEnabled(android.view.ViewGroup!, boolean);
+ method public static void setClipBounds(android.view.View, android.graphics.Rect?);
+ method public static void setElevation(android.view.View, float);
+ method @Deprecated public static void setFitsSystemWindows(android.view.View!, boolean);
+ method public static void setFocusedByDefault(android.view.View, boolean);
+ method public static void setHasTransientState(android.view.View, boolean);
+ method @UiThread public static void setImportantForAccessibility(android.view.View, int);
+ method public static void setImportantForAutofill(android.view.View, int);
+ method public static void setKeyboardNavigationCluster(android.view.View, boolean);
+ method public static void setLabelFor(android.view.View, @IdRes int);
+ method public static void setLayerPaint(android.view.View, android.graphics.Paint?);
+ method @Deprecated public static void setLayerType(android.view.View!, int, android.graphics.Paint!);
+ method public static void setLayoutDirection(android.view.View, int);
+ method public static void setNestedScrollingEnabled(android.view.View, boolean);
+ method public static void setNextClusterForwardId(android.view.View, int);
+ method public static void setOnApplyWindowInsetsListener(android.view.View, androidx.core.view.OnApplyWindowInsetsListener?);
+ method public static void setOnReceiveContentListener(android.view.View, String![]?, androidx.core.view.OnReceiveContentListener?);
+ method @Deprecated public static void setOverScrollMode(android.view.View!, int);
+ method public static void setPaddingRelative(android.view.View, @Px int, @Px int, @Px int, @Px int);
+ method @Deprecated public static void setPivotX(android.view.View!, float);
+ method @Deprecated public static void setPivotY(android.view.View!, float);
+ method public static void setPointerIcon(android.view.View, androidx.core.view.PointerIconCompat?);
+ method @Deprecated public static void setRotation(android.view.View!, float);
+ method @Deprecated public static void setRotationX(android.view.View!, float);
+ method @Deprecated public static void setRotationY(android.view.View!, float);
+ method @Deprecated public static void setSaveFromParentEnabled(android.view.View!, boolean);
+ method @Deprecated public static void setScaleX(android.view.View!, float);
+ method @Deprecated public static void setScaleY(android.view.View!, float);
+ method @UiThread public static void setScreenReaderFocusable(android.view.View, boolean);
+ method public static void setScrollIndicators(android.view.View, int);
+ method public static void setScrollIndicators(android.view.View, int, int);
+ method @UiThread public static void setStateDescription(android.view.View, CharSequence?);
+ method public static void setSystemGestureExclusionRects(android.view.View, java.util.List<android.graphics.Rect!>);
+ method public static void setTooltipText(android.view.View, CharSequence?);
+ method public static void setTransitionName(android.view.View, String?);
+ method @Deprecated public static void setTranslationX(android.view.View!, float);
+ method @Deprecated public static void setTranslationY(android.view.View!, float);
+ method public static void setTranslationZ(android.view.View, float);
+ method public static void setWindowInsetsAnimationCallback(android.view.View, androidx.core.view.WindowInsetsAnimationCompat.Callback?);
+ method @Deprecated public static void setX(android.view.View!, float);
+ method @Deprecated public static void setY(android.view.View!, float);
+ method public static void setZ(android.view.View, float);
+ method public static boolean startDragAndDrop(android.view.View, android.content.ClipData?, android.view.View.DragShadowBuilder, Object?, int);
+ method public static boolean startNestedScroll(android.view.View, int);
+ method public static boolean startNestedScroll(android.view.View, int, int);
+ method public static void stopNestedScroll(android.view.View);
+ method public static void stopNestedScroll(android.view.View, int);
+ method public static void updateDragShadow(android.view.View, android.view.View.DragShadowBuilder);
+ field public static final int ACCESSIBILITY_LIVE_REGION_ASSERTIVE = 2; // 0x2
+ field public static final int ACCESSIBILITY_LIVE_REGION_NONE = 0; // 0x0
+ field public static final int ACCESSIBILITY_LIVE_REGION_POLITE = 1; // 0x1
+ field public static final int IMPORTANT_FOR_ACCESSIBILITY_AUTO = 0; // 0x0
+ field public static final int IMPORTANT_FOR_ACCESSIBILITY_NO = 2; // 0x2
+ field public static final int IMPORTANT_FOR_ACCESSIBILITY_NO_HIDE_DESCENDANTS = 4; // 0x4
+ field public static final int IMPORTANT_FOR_ACCESSIBILITY_YES = 1; // 0x1
+ field @Deprecated public static final int LAYER_TYPE_HARDWARE = 2; // 0x2
+ field @Deprecated public static final int LAYER_TYPE_NONE = 0; // 0x0
+ field @Deprecated public static final int LAYER_TYPE_SOFTWARE = 1; // 0x1
+ field public static final int LAYOUT_DIRECTION_INHERIT = 2; // 0x2
+ field public static final int LAYOUT_DIRECTION_LOCALE = 3; // 0x3
+ field public static final int LAYOUT_DIRECTION_LTR = 0; // 0x0
+ field public static final int LAYOUT_DIRECTION_RTL = 1; // 0x1
+ field @Deprecated public static final int MEASURED_HEIGHT_STATE_SHIFT = 16; // 0x10
+ field @Deprecated public static final int MEASURED_SIZE_MASK = 16777215; // 0xffffff
+ field @Deprecated public static final int MEASURED_STATE_MASK = -16777216; // 0xff000000
+ field @Deprecated public static final int MEASURED_STATE_TOO_SMALL = 16777216; // 0x1000000
+ field @Deprecated public static final int OVER_SCROLL_ALWAYS = 0; // 0x0
+ field @Deprecated public static final int OVER_SCROLL_IF_CONTENT_SCROLLS = 1; // 0x1
+ field @Deprecated public static final int OVER_SCROLL_NEVER = 2; // 0x2
+ field public static final int SCROLL_AXIS_HORIZONTAL = 1; // 0x1
+ field public static final int SCROLL_AXIS_NONE = 0; // 0x0
+ field public static final int SCROLL_AXIS_VERTICAL = 2; // 0x2
+ field public static final int SCROLL_INDICATOR_BOTTOM = 2; // 0x2
+ field public static final int SCROLL_INDICATOR_END = 32; // 0x20
+ field public static final int SCROLL_INDICATOR_LEFT = 4; // 0x4
+ field public static final int SCROLL_INDICATOR_RIGHT = 8; // 0x8
+ field public static final int SCROLL_INDICATOR_START = 16; // 0x10
+ field public static final int SCROLL_INDICATOR_TOP = 1; // 0x1
+ field public static final int TYPE_NON_TOUCH = 1; // 0x1
+ field public static final int TYPE_TOUCH = 0; // 0x0
+ }
+
+ public static interface ViewCompat.OnUnhandledKeyEventListenerCompat {
+ method public boolean onUnhandledKeyEvent(android.view.View, android.view.KeyEvent);
+ }
+
+ public final class ViewConfigurationCompat {
+ method public static float getScaledHorizontalScrollFactor(android.view.ViewConfiguration, android.content.Context);
+ method public static int getScaledHoverSlop(android.view.ViewConfiguration);
+ method @Deprecated public static int getScaledPagingTouchSlop(android.view.ViewConfiguration!);
+ method public static float getScaledVerticalScrollFactor(android.view.ViewConfiguration, android.content.Context);
+ method @Deprecated public static boolean hasPermanentMenuKey(android.view.ViewConfiguration!);
+ method public static boolean shouldShowMenuShortcutsWhenKeyboardPresent(android.view.ViewConfiguration, android.content.Context);
+ }
+
+ public final class ViewGroupCompat {
+ method public static int getLayoutMode(android.view.ViewGroup);
+ method public static int getNestedScrollAxes(android.view.ViewGroup);
+ method public static boolean isTransitionGroup(android.view.ViewGroup);
+ method @Deprecated public static boolean onRequestSendAccessibilityEvent(android.view.ViewGroup!, android.view.View!, android.view.accessibility.AccessibilityEvent!);
+ method public static void setLayoutMode(android.view.ViewGroup, int);
+ method @Deprecated public static void setMotionEventSplittingEnabled(android.view.ViewGroup!, boolean);
+ method public static void setTransitionGroup(android.view.ViewGroup, boolean);
+ field public static final int LAYOUT_MODE_CLIP_BOUNDS = 0; // 0x0
+ field public static final int LAYOUT_MODE_OPTICAL_BOUNDS = 1; // 0x1
+ }
+
+ public final class ViewParentCompat {
+ method public static void notifySubtreeAccessibilityStateChanged(android.view.ViewParent, android.view.View, android.view.View, int);
+ method public static boolean onNestedFling(android.view.ViewParent, android.view.View, float, float, boolean);
+ method public static boolean onNestedPreFling(android.view.ViewParent, android.view.View, float, float);
+ method public static void onNestedPreScroll(android.view.ViewParent, android.view.View, int, int, int[]);
+ method public static void onNestedPreScroll(android.view.ViewParent, android.view.View, int, int, int[], int);
+ method public static void onNestedScroll(android.view.ViewParent, android.view.View, int, int, int, int);
+ method public static void onNestedScroll(android.view.ViewParent, android.view.View, int, int, int, int, int);
+ method public static void onNestedScroll(android.view.ViewParent, android.view.View, int, int, int, int, int, int[]);
+ method public static void onNestedScrollAccepted(android.view.ViewParent, android.view.View, android.view.View, int);
+ method public static void onNestedScrollAccepted(android.view.ViewParent, android.view.View, android.view.View, int, int);
+ method public static boolean onStartNestedScroll(android.view.ViewParent, android.view.View, android.view.View, int);
+ method public static boolean onStartNestedScroll(android.view.ViewParent, android.view.View, android.view.View, int, int);
+ method public static void onStopNestedScroll(android.view.ViewParent, android.view.View);
+ method public static void onStopNestedScroll(android.view.ViewParent, android.view.View, int);
+ method @Deprecated public static boolean requestSendAccessibilityEvent(android.view.ViewParent!, android.view.View!, android.view.accessibility.AccessibilityEvent!);
+ }
+
+ public final class ViewPropertyAnimatorCompat {
+ method public androidx.core.view.ViewPropertyAnimatorCompat alpha(float);
+ method public androidx.core.view.ViewPropertyAnimatorCompat alphaBy(float);
+ method public void cancel();
+ method public long getDuration();
+ method public android.view.animation.Interpolator? getInterpolator();
+ method public long getStartDelay();
+ method public androidx.core.view.ViewPropertyAnimatorCompat rotation(float);
+ method public androidx.core.view.ViewPropertyAnimatorCompat rotationBy(float);
+ method public androidx.core.view.ViewPropertyAnimatorCompat rotationX(float);
+ method public androidx.core.view.ViewPropertyAnimatorCompat rotationXBy(float);
+ method public androidx.core.view.ViewPropertyAnimatorCompat rotationY(float);
+ method public androidx.core.view.ViewPropertyAnimatorCompat rotationYBy(float);
+ method public androidx.core.view.ViewPropertyAnimatorCompat scaleX(float);
+ method public androidx.core.view.ViewPropertyAnimatorCompat scaleXBy(float);
+ method public androidx.core.view.ViewPropertyAnimatorCompat scaleY(float);
+ method public androidx.core.view.ViewPropertyAnimatorCompat scaleYBy(float);
+ method public androidx.core.view.ViewPropertyAnimatorCompat setDuration(long);
+ method public androidx.core.view.ViewPropertyAnimatorCompat setInterpolator(android.view.animation.Interpolator?);
+ method public androidx.core.view.ViewPropertyAnimatorCompat setListener(androidx.core.view.ViewPropertyAnimatorListener?);
+ method public androidx.core.view.ViewPropertyAnimatorCompat setStartDelay(long);
+ method public androidx.core.view.ViewPropertyAnimatorCompat setUpdateListener(androidx.core.view.ViewPropertyAnimatorUpdateListener?);
+ method public void start();
+ method public androidx.core.view.ViewPropertyAnimatorCompat translationX(float);
+ method public androidx.core.view.ViewPropertyAnimatorCompat translationXBy(float);
+ method public androidx.core.view.ViewPropertyAnimatorCompat translationY(float);
+ method public androidx.core.view.ViewPropertyAnimatorCompat translationYBy(float);
+ method public androidx.core.view.ViewPropertyAnimatorCompat translationZ(float);
+ method public androidx.core.view.ViewPropertyAnimatorCompat translationZBy(float);
+ method public androidx.core.view.ViewPropertyAnimatorCompat withEndAction(Runnable);
+ method public androidx.core.view.ViewPropertyAnimatorCompat withLayer();
+ method public androidx.core.view.ViewPropertyAnimatorCompat withStartAction(Runnable);
+ method public androidx.core.view.ViewPropertyAnimatorCompat x(float);
+ method public androidx.core.view.ViewPropertyAnimatorCompat xBy(float);
+ method public androidx.core.view.ViewPropertyAnimatorCompat y(float);
+ method public androidx.core.view.ViewPropertyAnimatorCompat yBy(float);
+ method public androidx.core.view.ViewPropertyAnimatorCompat z(float);
+ method public androidx.core.view.ViewPropertyAnimatorCompat zBy(float);
+ }
+
+ public interface ViewPropertyAnimatorListener {
+ method public void onAnimationCancel(android.view.View);
+ method public void onAnimationEnd(android.view.View);
+ method public void onAnimationStart(android.view.View);
+ }
+
+ public class ViewPropertyAnimatorListenerAdapter implements androidx.core.view.ViewPropertyAnimatorListener {
+ ctor public ViewPropertyAnimatorListenerAdapter();
+ method public void onAnimationCancel(android.view.View);
+ method public void onAnimationEnd(android.view.View);
+ method public void onAnimationStart(android.view.View);
+ }
+
+ public interface ViewPropertyAnimatorUpdateListener {
+ method public void onAnimationUpdate(android.view.View);
+ }
+
+ public final class WindowCompat {
+ method public static androidx.core.view.WindowInsetsControllerCompat getInsetsController(android.view.Window, android.view.View);
+ method public static <T extends android.view.View> T requireViewById(android.view.Window, @IdRes int);
+ method public static void setDecorFitsSystemWindows(android.view.Window, boolean);
+ field public static final int FEATURE_ACTION_BAR = 8; // 0x8
+ field public static final int FEATURE_ACTION_BAR_OVERLAY = 9; // 0x9
+ field public static final int FEATURE_ACTION_MODE_OVERLAY = 10; // 0xa
+ }
+
+ public final class WindowInsetsAnimationCompat {
+ ctor public WindowInsetsAnimationCompat(int, android.view.animation.Interpolator?, long);
+ method @FloatRange(from=0.0f, to=1.0f) public float getAlpha();
+ method public long getDurationMillis();
+ method @FloatRange(from=0.0f, to=1.0f) public float getFraction();
+ method public float getInterpolatedFraction();
+ method public android.view.animation.Interpolator? getInterpolator();
+ method public int getTypeMask();
+ method public void setAlpha(@FloatRange(from=0.0f, to=1.0f) float);
+ method public void setFraction(@FloatRange(from=0.0f, to=1.0f) float);
+ }
+
+ public static final class WindowInsetsAnimationCompat.BoundsCompat {
+ ctor public WindowInsetsAnimationCompat.BoundsCompat(androidx.core.graphics.Insets, androidx.core.graphics.Insets);
+ method public androidx.core.graphics.Insets getLowerBound();
+ method public androidx.core.graphics.Insets getUpperBound();
+ method public androidx.core.view.WindowInsetsAnimationCompat.BoundsCompat inset(androidx.core.graphics.Insets);
+ method @RequiresApi(30) public android.view.WindowInsetsAnimation.Bounds toBounds();
+ method @RequiresApi(30) public static androidx.core.view.WindowInsetsAnimationCompat.BoundsCompat toBoundsCompat(android.view.WindowInsetsAnimation.Bounds);
+ }
+
+ public abstract static class WindowInsetsAnimationCompat.Callback {
+ ctor public WindowInsetsAnimationCompat.Callback(int);
+ method public final int getDispatchMode();
+ method public void onEnd(androidx.core.view.WindowInsetsAnimationCompat);
+ method public void onPrepare(androidx.core.view.WindowInsetsAnimationCompat);
+ method public abstract androidx.core.view.WindowInsetsCompat onProgress(androidx.core.view.WindowInsetsCompat, java.util.List<androidx.core.view.WindowInsetsAnimationCompat!>);
+ method public androidx.core.view.WindowInsetsAnimationCompat.BoundsCompat onStart(androidx.core.view.WindowInsetsAnimationCompat, androidx.core.view.WindowInsetsAnimationCompat.BoundsCompat);
+ field public static final int DISPATCH_MODE_CONTINUE_ON_SUBTREE = 1; // 0x1
+ field public static final int DISPATCH_MODE_STOP = 0; // 0x0
+ }
+
+ public interface WindowInsetsAnimationControlListenerCompat {
+ method public void onCancelled(androidx.core.view.WindowInsetsAnimationControllerCompat?);
+ method public void onFinished(androidx.core.view.WindowInsetsAnimationControllerCompat);
+ method public void onReady(androidx.core.view.WindowInsetsAnimationControllerCompat, int);
+ }
+
+ public final class WindowInsetsAnimationControllerCompat {
+ method public void finish(boolean);
+ method public float getCurrentAlpha();
+ method @FloatRange(from=0.0f, to=1.0f) public float getCurrentFraction();
+ method public androidx.core.graphics.Insets getCurrentInsets();
+ method public androidx.core.graphics.Insets getHiddenStateInsets();
+ method public androidx.core.graphics.Insets getShownStateInsets();
+ method public int getTypes();
+ method public boolean isCancelled();
+ method public boolean isFinished();
+ method public boolean isReady();
+ method public void setInsetsAndAlpha(androidx.core.graphics.Insets?, @FloatRange(from=0.0f, to=1.0f) float, @FloatRange(from=0.0f, to=1.0f) float);
+ }
+
+ public class WindowInsetsCompat {
+ ctor public WindowInsetsCompat(androidx.core.view.WindowInsetsCompat?);
+ method @Deprecated public androidx.core.view.WindowInsetsCompat consumeDisplayCutout();
+ method @Deprecated public androidx.core.view.WindowInsetsCompat consumeStableInsets();
+ method @Deprecated public androidx.core.view.WindowInsetsCompat consumeSystemWindowInsets();
+ method public androidx.core.view.DisplayCutoutCompat? getDisplayCutout();
+ method public androidx.core.graphics.Insets getInsets(int);
+ method public androidx.core.graphics.Insets getInsetsIgnoringVisibility(int);
+ method @Deprecated public androidx.core.graphics.Insets getMandatorySystemGestureInsets();
+ method @Deprecated public int getStableInsetBottom();
+ method @Deprecated public int getStableInsetLeft();
+ method @Deprecated public int getStableInsetRight();
+ method @Deprecated public int getStableInsetTop();
+ method @Deprecated public androidx.core.graphics.Insets getStableInsets();
+ method @Deprecated public androidx.core.graphics.Insets getSystemGestureInsets();
+ method @Deprecated public int getSystemWindowInsetBottom();
+ method @Deprecated public int getSystemWindowInsetLeft();
+ method @Deprecated public int getSystemWindowInsetRight();
+ method @Deprecated public int getSystemWindowInsetTop();
+ method @Deprecated public androidx.core.graphics.Insets getSystemWindowInsets();
+ method @Deprecated public androidx.core.graphics.Insets getTappableElementInsets();
+ method public boolean hasInsets();
+ method @Deprecated public boolean hasStableInsets();
+ method @Deprecated public boolean hasSystemWindowInsets();
+ method public androidx.core.view.WindowInsetsCompat inset(androidx.core.graphics.Insets);
+ method public androidx.core.view.WindowInsetsCompat inset(@IntRange(from=0) int, @IntRange(from=0) int, @IntRange(from=0) int, @IntRange(from=0) int);
+ method public boolean isConsumed();
+ method public boolean isRound();
+ method public boolean isVisible(int);
+ method @Deprecated public androidx.core.view.WindowInsetsCompat replaceSystemWindowInsets(int, int, int, int);
+ method @Deprecated public androidx.core.view.WindowInsetsCompat replaceSystemWindowInsets(android.graphics.Rect);
+ method @RequiresApi(20) public android.view.WindowInsets? toWindowInsets();
+ method @RequiresApi(20) public static androidx.core.view.WindowInsetsCompat toWindowInsetsCompat(android.view.WindowInsets);
+ method @RequiresApi(20) public static androidx.core.view.WindowInsetsCompat toWindowInsetsCompat(android.view.WindowInsets, android.view.View?);
+ field public static final androidx.core.view.WindowInsetsCompat CONSUMED;
+ }
+
+ public static final class WindowInsetsCompat.Builder {
+ ctor public WindowInsetsCompat.Builder();
+ ctor public WindowInsetsCompat.Builder(androidx.core.view.WindowInsetsCompat);
+ method public androidx.core.view.WindowInsetsCompat build();
+ method public androidx.core.view.WindowInsetsCompat.Builder setDisplayCutout(androidx.core.view.DisplayCutoutCompat?);
+ method public androidx.core.view.WindowInsetsCompat.Builder setInsets(int, androidx.core.graphics.Insets);
+ method public androidx.core.view.WindowInsetsCompat.Builder setInsetsIgnoringVisibility(int, androidx.core.graphics.Insets);
+ method @Deprecated public androidx.core.view.WindowInsetsCompat.Builder setMandatorySystemGestureInsets(androidx.core.graphics.Insets);
+ method @Deprecated public androidx.core.view.WindowInsetsCompat.Builder setStableInsets(androidx.core.graphics.Insets);
+ method @Deprecated public androidx.core.view.WindowInsetsCompat.Builder setSystemGestureInsets(androidx.core.graphics.Insets);
+ method @Deprecated public androidx.core.view.WindowInsetsCompat.Builder setSystemWindowInsets(androidx.core.graphics.Insets);
+ method @Deprecated public androidx.core.view.WindowInsetsCompat.Builder setTappableElementInsets(androidx.core.graphics.Insets);
+ method public androidx.core.view.WindowInsetsCompat.Builder setVisible(int, boolean);
+ }
+
+ public static final class WindowInsetsCompat.Type {
+ method public static int captionBar();
+ method public static int displayCutout();
+ method public static int ime();
+ method public static int mandatorySystemGestures();
+ method public static int navigationBars();
+ method public static int statusBars();
+ method public static int systemBars();
+ method public static int systemGestures();
+ method public static int tappableElement();
+ }
+
+ public final class WindowInsetsControllerCompat {
+ ctor public WindowInsetsControllerCompat(android.view.Window, android.view.View);
+ method public void addOnControllableInsetsChangedListener(androidx.core.view.WindowInsetsControllerCompat.OnControllableInsetsChangedListener);
+ method public void controlWindowInsetsAnimation(int, long, android.view.animation.Interpolator?, android.os.CancellationSignal?, androidx.core.view.WindowInsetsAnimationControlListenerCompat);
+ method public int getSystemBarsBehavior();
+ method public void hide(int);
+ method public boolean isAppearanceLightNavigationBars();
+ method public boolean isAppearanceLightStatusBars();
+ method public void removeOnControllableInsetsChangedListener(androidx.core.view.WindowInsetsControllerCompat.OnControllableInsetsChangedListener);
+ method public void setAppearanceLightNavigationBars(boolean);
+ method public void setAppearanceLightStatusBars(boolean);
+ method public void setSystemBarsBehavior(int);
+ method public void show(int);
+ method @Deprecated @RequiresApi(30) public static androidx.core.view.WindowInsetsControllerCompat toWindowInsetsControllerCompat(android.view.WindowInsetsController);
+ field public static final int BEHAVIOR_DEFAULT = 1; // 0x1
+ field @Deprecated public static final int BEHAVIOR_SHOW_BARS_BY_SWIPE = 1; // 0x1
+ field @Deprecated public static final int BEHAVIOR_SHOW_BARS_BY_TOUCH = 0; // 0x0
+ field public static final int BEHAVIOR_SHOW_TRANSIENT_BARS_BY_SWIPE = 2; // 0x2
+ }
+
+ public static interface WindowInsetsControllerCompat.OnControllableInsetsChangedListener {
+ method public void onControllableInsetsChanged(androidx.core.view.WindowInsetsControllerCompat, int);
+ }
+
+}
+
+package androidx.core.view.accessibility {
+
+ public final class AccessibilityClickableSpanCompat extends android.text.style.ClickableSpan {
+ method public void onClick(android.view.View);
+ }
+
+ public final class AccessibilityEventCompat {
+ method @Deprecated public static void appendRecord(android.view.accessibility.AccessibilityEvent!, androidx.core.view.accessibility.AccessibilityRecordCompat!);
+ method @Deprecated public static androidx.core.view.accessibility.AccessibilityRecordCompat! asRecord(android.view.accessibility.AccessibilityEvent!);
+ method public static int getAction(android.view.accessibility.AccessibilityEvent);
+ method public static int getContentChangeTypes(android.view.accessibility.AccessibilityEvent);
+ method public static int getMovementGranularity(android.view.accessibility.AccessibilityEvent);
+ method @Deprecated public static androidx.core.view.accessibility.AccessibilityRecordCompat! getRecord(android.view.accessibility.AccessibilityEvent!, int);
+ method @Deprecated public static int getRecordCount(android.view.accessibility.AccessibilityEvent!);
+ method public static void setAction(android.view.accessibility.AccessibilityEvent, int);
+ method public static void setContentChangeTypes(android.view.accessibility.AccessibilityEvent, int);
+ method public static void setMovementGranularity(android.view.accessibility.AccessibilityEvent, int);
+ field public static final int CONTENT_CHANGE_TYPE_CONTENT_DESCRIPTION = 4; // 0x4
+ field public static final int CONTENT_CHANGE_TYPE_DRAG_CANCELLED = 512; // 0x200
+ field public static final int CONTENT_CHANGE_TYPE_DRAG_DROPPED = 256; // 0x100
+ field public static final int CONTENT_CHANGE_TYPE_DRAG_STARTED = 128; // 0x80
+ field public static final int CONTENT_CHANGE_TYPE_PANE_APPEARED = 16; // 0x10
+ field public static final int CONTENT_CHANGE_TYPE_PANE_DISAPPEARED = 32; // 0x20
+ field public static final int CONTENT_CHANGE_TYPE_PANE_TITLE = 8; // 0x8
+ field public static final int CONTENT_CHANGE_TYPE_STATE_DESCRIPTION = 64; // 0x40
+ field public static final int CONTENT_CHANGE_TYPE_SUBTREE = 1; // 0x1
+ field public static final int CONTENT_CHANGE_TYPE_TEXT = 2; // 0x2
+ field public static final int CONTENT_CHANGE_TYPE_UNDEFINED = 0; // 0x0
+ field public static final int TYPES_ALL_MASK = -1; // 0xffffffff
+ field public static final int TYPE_ANNOUNCEMENT = 16384; // 0x4000
+ field public static final int TYPE_ASSIST_READING_CONTEXT = 16777216; // 0x1000000
+ field public static final int TYPE_GESTURE_DETECTION_END = 524288; // 0x80000
+ field public static final int TYPE_GESTURE_DETECTION_START = 262144; // 0x40000
+ field @Deprecated public static final int TYPE_TOUCH_EXPLORATION_GESTURE_END = 1024; // 0x400
+ field @Deprecated public static final int TYPE_TOUCH_EXPLORATION_GESTURE_START = 512; // 0x200
+ field public static final int TYPE_TOUCH_INTERACTION_END = 2097152; // 0x200000
+ field public static final int TYPE_TOUCH_INTERACTION_START = 1048576; // 0x100000
+ field public static final int TYPE_VIEW_ACCESSIBILITY_FOCUSED = 32768; // 0x8000
+ field public static final int TYPE_VIEW_ACCESSIBILITY_FOCUS_CLEARED = 65536; // 0x10000
+ field public static final int TYPE_VIEW_CONTEXT_CLICKED = 8388608; // 0x800000
+ field @Deprecated public static final int TYPE_VIEW_HOVER_ENTER = 128; // 0x80
+ field @Deprecated public static final int TYPE_VIEW_HOVER_EXIT = 256; // 0x100
+ field @Deprecated public static final int TYPE_VIEW_SCROLLED = 4096; // 0x1000
+ field @Deprecated public static final int TYPE_VIEW_TEXT_SELECTION_CHANGED = 8192; // 0x2000
+ field public static final int TYPE_VIEW_TEXT_TRAVERSED_AT_MOVEMENT_GRANULARITY = 131072; // 0x20000
+ field public static final int TYPE_WINDOWS_CHANGED = 4194304; // 0x400000
+ field @Deprecated public static final int TYPE_WINDOW_CONTENT_CHANGED = 2048; // 0x800
+ }
+
+ public final class AccessibilityManagerCompat {
+ method @Deprecated public static boolean addAccessibilityStateChangeListener(android.view.accessibility.AccessibilityManager!, androidx.core.view.accessibility.AccessibilityManagerCompat.AccessibilityStateChangeListener!);
+ method public static boolean addTouchExplorationStateChangeListener(android.view.accessibility.AccessibilityManager, androidx.core.view.accessibility.AccessibilityManagerCompat.TouchExplorationStateChangeListener);
+ method @Deprecated public static java.util.List<android.accessibilityservice.AccessibilityServiceInfo!>! getEnabledAccessibilityServiceList(android.view.accessibility.AccessibilityManager!, int);
+ method @Deprecated public static java.util.List<android.accessibilityservice.AccessibilityServiceInfo!>! getInstalledAccessibilityServiceList(android.view.accessibility.AccessibilityManager!);
+ method @Deprecated public static boolean isTouchExplorationEnabled(android.view.accessibility.AccessibilityManager!);
+ method @Deprecated public static boolean removeAccessibilityStateChangeListener(android.view.accessibility.AccessibilityManager!, androidx.core.view.accessibility.AccessibilityManagerCompat.AccessibilityStateChangeListener!);
+ method public static boolean removeTouchExplorationStateChangeListener(android.view.accessibility.AccessibilityManager, androidx.core.view.accessibility.AccessibilityManagerCompat.TouchExplorationStateChangeListener);
+ }
+
+ @Deprecated public static interface AccessibilityManagerCompat.AccessibilityStateChangeListener {
+ method @Deprecated public void onAccessibilityStateChanged(boolean);
+ }
+
+ @Deprecated public abstract static class AccessibilityManagerCompat.AccessibilityStateChangeListenerCompat implements androidx.core.view.accessibility.AccessibilityManagerCompat.AccessibilityStateChangeListener {
+ ctor @Deprecated public AccessibilityManagerCompat.AccessibilityStateChangeListenerCompat();
+ }
+
+ public static interface AccessibilityManagerCompat.TouchExplorationStateChangeListener {
+ method public void onTouchExplorationStateChanged(boolean);
+ }
+
+ public class AccessibilityNodeInfoCompat {
+ ctor @Deprecated public AccessibilityNodeInfoCompat(Object!);
+ method public void addAction(int);
+ method public void addAction(androidx.core.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat!);
+ method public void addChild(android.view.View!);
+ method public void addChild(android.view.View!, int);
+ method public boolean canOpenPopup();
+ method public java.util.List<androidx.core.view.accessibility.AccessibilityNodeInfoCompat!>! findAccessibilityNodeInfosByText(String!);
+ method public java.util.List<androidx.core.view.accessibility.AccessibilityNodeInfoCompat!>! findAccessibilityNodeInfosByViewId(String!);
+ method public androidx.core.view.accessibility.AccessibilityNodeInfoCompat! findFocus(int);
+ method public androidx.core.view.accessibility.AccessibilityNodeInfoCompat! focusSearch(int);
+ method public java.util.List<androidx.core.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat!>! getActionList();
+ method @Deprecated public int getActions();
+ method public java.util.List<java.lang.String!> getAvailableExtraData();
+ method @Deprecated public void getBoundsInParent(android.graphics.Rect!);
+ method public void getBoundsInScreen(android.graphics.Rect!);
+ method public androidx.core.view.accessibility.AccessibilityNodeInfoCompat! getChild(int);
+ method public int getChildCount();
+ method public CharSequence! getClassName();
+ method public androidx.core.view.accessibility.AccessibilityNodeInfoCompat.CollectionInfoCompat! getCollectionInfo();
+ method public androidx.core.view.accessibility.AccessibilityNodeInfoCompat.CollectionItemInfoCompat! getCollectionItemInfo();
+ method public CharSequence! getContentDescription();
+ method public int getDrawingOrder();
+ method public CharSequence! getError();
+ method public android.view.accessibility.AccessibilityNodeInfo.ExtraRenderingInfo? getExtraRenderingInfo();
+ method public android.os.Bundle! getExtras();
+ method public CharSequence? getHintText();
+ method @Deprecated public Object! getInfo();
+ method public int getInputType();
+ method public androidx.core.view.accessibility.AccessibilityNodeInfoCompat! getLabelFor();
+ method public androidx.core.view.accessibility.AccessibilityNodeInfoCompat! getLabeledBy();
+ method public int getLiveRegion();
+ method public int getMaxTextLength();
+ method public int getMinMillisBetweenContentChanges();
+ method public int getMovementGranularities();
+ method public CharSequence! getPackageName();
+ method public CharSequence? getPaneTitle();
+ method public androidx.core.view.accessibility.AccessibilityNodeInfoCompat! getParent();
+ method public androidx.core.view.accessibility.AccessibilityNodeInfoCompat.RangeInfoCompat! getRangeInfo();
+ method public CharSequence? getRoleDescription();
+ method public CharSequence? getStateDescription();
+ method public CharSequence! getText();
+ method public int getTextSelectionEnd();
+ method public int getTextSelectionStart();
+ method public CharSequence? getTooltipText();
+ method public androidx.core.view.accessibility.AccessibilityNodeInfoCompat.TouchDelegateInfoCompat? getTouchDelegateInfo();
+ method public androidx.core.view.accessibility.AccessibilityNodeInfoCompat! getTraversalAfter();
+ method public androidx.core.view.accessibility.AccessibilityNodeInfoCompat! getTraversalBefore();
+ method public String? getUniqueId();
+ method public String! getViewIdResourceName();
+ method public androidx.core.view.accessibility.AccessibilityWindowInfoCompat! getWindow();
+ method public int getWindowId();
+ method public boolean hasRequestInitialAccessibilityFocus();
+ method public boolean isAccessibilityFocused();
+ method public boolean isCheckable();
+ method public boolean isChecked();
+ method public boolean isClickable();
+ method public boolean isContentInvalid();
+ method public boolean isContextClickable();
+ method public boolean isDismissable();
+ method public boolean isEditable();
+ method public boolean isEnabled();
+ method public boolean isFocusable();
+ method public boolean isFocused();
+ method public boolean isHeading();
+ method public boolean isImportantForAccessibility();
+ method public boolean isLongClickable();
+ method public boolean isMultiLine();
+ method public boolean isPassword();
+ method public boolean isScreenReaderFocusable();
+ method public boolean isScrollable();
+ method public boolean isSelected();
+ method public boolean isShowingHintText();
+ method public boolean isTextEntryKey();
+ method public boolean isTextSelectable();
+ method public boolean isVisibleToUser();
+ method public static androidx.core.view.accessibility.AccessibilityNodeInfoCompat! obtain(android.view.View!);
+ method public static androidx.core.view.accessibility.AccessibilityNodeInfoCompat! obtain(android.view.View!, int);
+ method public static androidx.core.view.accessibility.AccessibilityNodeInfoCompat! obtain();
+ method public static androidx.core.view.accessibility.AccessibilityNodeInfoCompat! obtain(androidx.core.view.accessibility.AccessibilityNodeInfoCompat!);
+ method public boolean performAction(int);
+ method public boolean performAction(int, android.os.Bundle!);
+ method @Deprecated public void recycle();
+ method public boolean refresh();
+ method public boolean removeAction(androidx.core.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat!);
+ method public boolean removeChild(android.view.View!);
+ method public boolean removeChild(android.view.View!, int);
+ method public void setAccessibilityFocused(boolean);
+ method public void setAvailableExtraData(java.util.List<java.lang.String!>);
+ method @Deprecated public void setBoundsInParent(android.graphics.Rect!);
+ method public void setBoundsInScreen(android.graphics.Rect!);
+ method public void setCanOpenPopup(boolean);
+ method public void setCheckable(boolean);
+ method public void setChecked(boolean);
+ method public void setClassName(CharSequence!);
+ method public void setClickable(boolean);
+ method public void setCollectionInfo(Object!);
+ method public void setCollectionItemInfo(Object!);
+ method public void setContentDescription(CharSequence!);
+ method public void setContentInvalid(boolean);
+ method public void setContextClickable(boolean);
+ method public void setDismissable(boolean);
+ method public void setDrawingOrder(int);
+ method public void setEditable(boolean);
+ method public void setEnabled(boolean);
+ method public void setError(CharSequence!);
+ method public void setFocusable(boolean);
+ method public void setFocused(boolean);
+ method public void setHeading(boolean);
+ method public void setHintText(CharSequence?);
+ method public void setImportantForAccessibility(boolean);
+ method public void setInputType(int);
+ method public void setLabelFor(android.view.View!);
+ method public void setLabelFor(android.view.View!, int);
+ method public void setLabeledBy(android.view.View!);
+ method public void setLabeledBy(android.view.View!, int);
+ method public void setLiveRegion(int);
+ method public void setLongClickable(boolean);
+ method public void setMaxTextLength(int);
+ method public void setMinMillisBetweenContentChanges(int);
+ method public void setMovementGranularities(int);
+ method public void setMultiLine(boolean);
+ method public void setPackageName(CharSequence!);
+ method public void setPaneTitle(CharSequence?);
+ method public void setParent(android.view.View!);
+ method public void setParent(android.view.View!, int);
+ method public void setPassword(boolean);
+ method public void setRangeInfo(androidx.core.view.accessibility.AccessibilityNodeInfoCompat.RangeInfoCompat!);
+ method public void setRequestInitialAccessibilityFocus(boolean);
+ method public void setRoleDescription(CharSequence?);
+ method public void setScreenReaderFocusable(boolean);
+ method public void setScrollable(boolean);
+ method public void setSelected(boolean);
+ method public void setShowingHintText(boolean);
+ method public void setSource(android.view.View!);
+ method public void setSource(android.view.View!, int);
+ method public void setStateDescription(CharSequence?);
+ method public void setText(CharSequence!);
+ method public void setTextEntryKey(boolean);
+ method public void setTextSelectable(boolean);
+ method public void setTextSelection(int, int);
+ method public void setTooltipText(CharSequence?);
+ method public void setTouchDelegateInfo(androidx.core.view.accessibility.AccessibilityNodeInfoCompat.TouchDelegateInfoCompat);
+ method public void setTraversalAfter(android.view.View!);
+ method public void setTraversalAfter(android.view.View!, int);
+ method public void setTraversalBefore(android.view.View!);
+ method public void setTraversalBefore(android.view.View!, int);
+ method public void setUniqueId(String?);
+ method public void setViewIdResourceName(String!);
+ method public void setVisibleToUser(boolean);
+ method public android.view.accessibility.AccessibilityNodeInfo! unwrap();
+ method public static androidx.core.view.accessibility.AccessibilityNodeInfoCompat! wrap(android.view.accessibility.AccessibilityNodeInfo);
+ field public static final int ACTION_ACCESSIBILITY_FOCUS = 64; // 0x40
+ field public static final String ACTION_ARGUMENT_COLUMN_INT = "android.view.accessibility.action.ARGUMENT_COLUMN_INT";
+ field public static final String ACTION_ARGUMENT_EXTEND_SELECTION_BOOLEAN = "ACTION_ARGUMENT_EXTEND_SELECTION_BOOLEAN";
+ field public static final String ACTION_ARGUMENT_HTML_ELEMENT_STRING = "ACTION_ARGUMENT_HTML_ELEMENT_STRING";
+ field public static final String ACTION_ARGUMENT_MOVEMENT_GRANULARITY_INT = "ACTION_ARGUMENT_MOVEMENT_GRANULARITY_INT";
+ field public static final String ACTION_ARGUMENT_MOVE_WINDOW_X = "ACTION_ARGUMENT_MOVE_WINDOW_X";
+ field public static final String ACTION_ARGUMENT_MOVE_WINDOW_Y = "ACTION_ARGUMENT_MOVE_WINDOW_Y";
+ field public static final String ACTION_ARGUMENT_PRESS_AND_HOLD_DURATION_MILLIS_INT = "android.view.accessibility.action.ARGUMENT_PRESS_AND_HOLD_DURATION_MILLIS_INT";
+ field public static final String ACTION_ARGUMENT_PROGRESS_VALUE = "android.view.accessibility.action.ARGUMENT_PROGRESS_VALUE";
+ field public static final String ACTION_ARGUMENT_ROW_INT = "android.view.accessibility.action.ARGUMENT_ROW_INT";
+ field public static final String ACTION_ARGUMENT_SELECTION_END_INT = "ACTION_ARGUMENT_SELECTION_END_INT";
+ field public static final String ACTION_ARGUMENT_SELECTION_START_INT = "ACTION_ARGUMENT_SELECTION_START_INT";
+ field public static final String ACTION_ARGUMENT_SET_TEXT_CHARSEQUENCE = "ACTION_ARGUMENT_SET_TEXT_CHARSEQUENCE";
+ field public static final int ACTION_CLEAR_ACCESSIBILITY_FOCUS = 128; // 0x80
+ field public static final int ACTION_CLEAR_FOCUS = 2; // 0x2
+ field public static final int ACTION_CLEAR_SELECTION = 8; // 0x8
+ field public static final int ACTION_CLICK = 16; // 0x10
+ field public static final int ACTION_COLLAPSE = 524288; // 0x80000
+ field public static final int ACTION_COPY = 16384; // 0x4000
+ field public static final int ACTION_CUT = 65536; // 0x10000
+ field public static final int ACTION_DISMISS = 1048576; // 0x100000
+ field public static final int ACTION_EXPAND = 262144; // 0x40000
+ field public static final int ACTION_FOCUS = 1; // 0x1
+ field public static final int ACTION_LONG_CLICK = 32; // 0x20
+ field public static final int ACTION_NEXT_AT_MOVEMENT_GRANULARITY = 256; // 0x100
+ field public static final int ACTION_NEXT_HTML_ELEMENT = 1024; // 0x400
+ field public static final int ACTION_PASTE = 32768; // 0x8000
+ field public static final int ACTION_PREVIOUS_AT_MOVEMENT_GRANULARITY = 512; // 0x200
+ field public static final int ACTION_PREVIOUS_HTML_ELEMENT = 2048; // 0x800
+ field public static final int ACTION_SCROLL_BACKWARD = 8192; // 0x2000
+ field public static final int ACTION_SCROLL_FORWARD = 4096; // 0x1000
+ field public static final int ACTION_SELECT = 4; // 0x4
+ field public static final int ACTION_SET_SELECTION = 131072; // 0x20000
+ field public static final int ACTION_SET_TEXT = 2097152; // 0x200000
+ field public static final String EXTRA_DATA_TEXT_CHARACTER_LOCATION_ARG_LENGTH = "android.core.view.accessibility.extra.DATA_TEXT_CHARACTER_LOCATION_ARG_LENGTH";
+ field public static final int EXTRA_DATA_TEXT_CHARACTER_LOCATION_ARG_MAX_LENGTH = 20000; // 0x4e20
+ field public static final String EXTRA_DATA_TEXT_CHARACTER_LOCATION_ARG_START_INDEX = "android.core.view.accessibility.extra.DATA_TEXT_CHARACTER_LOCATION_ARG_START_INDEX";
+ field public static final String EXTRA_DATA_TEXT_CHARACTER_LOCATION_KEY = "android.core.view.accessibility.extra.DATA_TEXT_CHARACTER_LOCATION_KEY";
+ field public static final int FOCUS_ACCESSIBILITY = 2; // 0x2
+ field public static final int FOCUS_INPUT = 1; // 0x1
+ field public static final int MOVEMENT_GRANULARITY_CHARACTER = 1; // 0x1
+ field public static final int MOVEMENT_GRANULARITY_LINE = 4; // 0x4
+ field public static final int MOVEMENT_GRANULARITY_PAGE = 16; // 0x10
+ field public static final int MOVEMENT_GRANULARITY_PARAGRAPH = 8; // 0x8
+ field public static final int MOVEMENT_GRANULARITY_WORD = 2; // 0x2
+ }
+
+ public static class AccessibilityNodeInfoCompat.AccessibilityActionCompat {
+ ctor public AccessibilityNodeInfoCompat.AccessibilityActionCompat(int, CharSequence!);
+ method public int getId();
+ method public CharSequence! getLabel();
+ field public static final androidx.core.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat! ACTION_ACCESSIBILITY_FOCUS;
+ field public static final androidx.core.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat! ACTION_CLEAR_ACCESSIBILITY_FOCUS;
+ field public static final androidx.core.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat! ACTION_CLEAR_FOCUS;
+ field public static final androidx.core.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat! ACTION_CLEAR_SELECTION;
+ field public static final androidx.core.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat! ACTION_CLICK;
+ field public static final androidx.core.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat! ACTION_COLLAPSE;
+ field public static final androidx.core.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat! ACTION_CONTEXT_CLICK;
+ field public static final androidx.core.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat! ACTION_COPY;
+ field public static final androidx.core.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat! ACTION_CUT;
+ field public static final androidx.core.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat! ACTION_DISMISS;
+ field public static final androidx.core.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat ACTION_DRAG_CANCEL;
+ field public static final androidx.core.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat ACTION_DRAG_DROP;
+ field public static final androidx.core.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat ACTION_DRAG_START;
+ field public static final androidx.core.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat! ACTION_EXPAND;
+ field public static final androidx.core.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat! ACTION_FOCUS;
+ field public static final androidx.core.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat! ACTION_HIDE_TOOLTIP;
+ field public static final androidx.core.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat ACTION_IME_ENTER;
+ field public static final androidx.core.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat! ACTION_LONG_CLICK;
+ field public static final androidx.core.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat! ACTION_MOVE_WINDOW;
+ field public static final androidx.core.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat! ACTION_NEXT_AT_MOVEMENT_GRANULARITY;
+ field public static final androidx.core.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat! ACTION_NEXT_HTML_ELEMENT;
+ field public static final androidx.core.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat ACTION_PAGE_DOWN;
+ field public static final androidx.core.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat ACTION_PAGE_LEFT;
+ field public static final androidx.core.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat ACTION_PAGE_RIGHT;
+ field public static final androidx.core.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat ACTION_PAGE_UP;
+ field public static final androidx.core.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat! ACTION_PASTE;
+ field public static final androidx.core.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat ACTION_PRESS_AND_HOLD;
+ field public static final androidx.core.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat! ACTION_PREVIOUS_AT_MOVEMENT_GRANULARITY;
+ field public static final androidx.core.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat! ACTION_PREVIOUS_HTML_ELEMENT;
+ field public static final androidx.core.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat! ACTION_SCROLL_BACKWARD;
+ field public static final androidx.core.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat! ACTION_SCROLL_DOWN;
+ field public static final androidx.core.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat! ACTION_SCROLL_FORWARD;
+ field public static final androidx.core.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat! ACTION_SCROLL_LEFT;
+ field public static final androidx.core.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat! ACTION_SCROLL_RIGHT;
+ field public static final androidx.core.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat! ACTION_SCROLL_TO_POSITION;
+ field public static final androidx.core.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat! ACTION_SCROLL_UP;
+ field public static final androidx.core.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat! ACTION_SELECT;
+ field public static final androidx.core.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat! ACTION_SET_PROGRESS;
+ field public static final androidx.core.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat! ACTION_SET_SELECTION;
+ field public static final androidx.core.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat! ACTION_SET_TEXT;
+ field public static final androidx.core.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat! ACTION_SHOW_ON_SCREEN;
+ field public static final androidx.core.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat ACTION_SHOW_TEXT_SUGGESTIONS;
+ field public static final androidx.core.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat! ACTION_SHOW_TOOLTIP;
+ }
+
+ public static class AccessibilityNodeInfoCompat.CollectionInfoCompat {
+ method public int getColumnCount();
+ method public int getRowCount();
+ method public int getSelectionMode();
+ method public boolean isHierarchical();
+ method public static androidx.core.view.accessibility.AccessibilityNodeInfoCompat.CollectionInfoCompat! obtain(int, int, boolean, int);
+ method public static androidx.core.view.accessibility.AccessibilityNodeInfoCompat.CollectionInfoCompat! obtain(int, int, boolean);
+ field public static final int SELECTION_MODE_MULTIPLE = 2; // 0x2
+ field public static final int SELECTION_MODE_NONE = 0; // 0x0
+ field public static final int SELECTION_MODE_SINGLE = 1; // 0x1
+ }
+
+ public static class AccessibilityNodeInfoCompat.CollectionItemInfoCompat {
+ method public int getColumnIndex();
+ method public int getColumnSpan();
+ method public int getRowIndex();
+ method public int getRowSpan();
+ method @Deprecated public boolean isHeading();
+ method public boolean isSelected();
+ method public static androidx.core.view.accessibility.AccessibilityNodeInfoCompat.CollectionItemInfoCompat! obtain(int, int, int, int, boolean, boolean);
+ method public static androidx.core.view.accessibility.AccessibilityNodeInfoCompat.CollectionItemInfoCompat! obtain(int, int, int, int, boolean);
+ }
+
+ public static class AccessibilityNodeInfoCompat.RangeInfoCompat {
+ method public float getCurrent();
+ method public float getMax();
+ method public float getMin();
+ method public int getType();
+ method public static androidx.core.view.accessibility.AccessibilityNodeInfoCompat.RangeInfoCompat! obtain(int, float, float, float);
+ field public static final int RANGE_TYPE_FLOAT = 1; // 0x1
+ field public static final int RANGE_TYPE_INT = 0; // 0x0
+ field public static final int RANGE_TYPE_PERCENT = 2; // 0x2
+ }
+
+ public static final class AccessibilityNodeInfoCompat.TouchDelegateInfoCompat {
+ ctor public AccessibilityNodeInfoCompat.TouchDelegateInfoCompat(java.util.Map<android.graphics.Region!,android.view.View!>);
+ method public android.graphics.Region? getRegionAt(@IntRange(from=0) int);
+ method @IntRange(from=0) public int getRegionCount();
+ method public androidx.core.view.accessibility.AccessibilityNodeInfoCompat? getTargetForRegion(android.graphics.Region);
+ }
+
+ public class AccessibilityNodeProviderCompat {
+ ctor public AccessibilityNodeProviderCompat();
+ ctor public AccessibilityNodeProviderCompat(Object?);
+ method public void addExtraDataToAccessibilityNodeInfo(int, androidx.core.view.accessibility.AccessibilityNodeInfoCompat, String, android.os.Bundle?);
+ method public androidx.core.view.accessibility.AccessibilityNodeInfoCompat? createAccessibilityNodeInfo(int);
+ method public java.util.List<androidx.core.view.accessibility.AccessibilityNodeInfoCompat!>? findAccessibilityNodeInfosByText(String, int);
+ method public androidx.core.view.accessibility.AccessibilityNodeInfoCompat? findFocus(int);
+ method public Object? getProvider();
+ method public boolean performAction(int, int, android.os.Bundle?);
+ field public static final int HOST_VIEW_ID = -1; // 0xffffffff
+ }
+
+ public class AccessibilityRecordCompat {
+ ctor @Deprecated public AccessibilityRecordCompat(Object!);
+ method @Deprecated public boolean equals(Object?);
+ method @Deprecated public int getAddedCount();
+ method @Deprecated public CharSequence! getBeforeText();
+ method @Deprecated public CharSequence! getClassName();
+ method @Deprecated public CharSequence! getContentDescription();
+ method @Deprecated public int getCurrentItemIndex();
+ method @Deprecated public int getFromIndex();
+ method @Deprecated public Object! getImpl();
+ method @Deprecated public int getItemCount();
+ method @Deprecated public int getMaxScrollX();
+ method public static int getMaxScrollX(android.view.accessibility.AccessibilityRecord);
+ method @Deprecated public int getMaxScrollY();
+ method public static int getMaxScrollY(android.view.accessibility.AccessibilityRecord);
+ method @Deprecated public android.os.Parcelable! getParcelableData();
+ method @Deprecated public int getRemovedCount();
+ method @Deprecated public int getScrollX();
+ method @Deprecated public int getScrollY();
+ method @Deprecated public androidx.core.view.accessibility.AccessibilityNodeInfoCompat! getSource();
+ method @Deprecated public java.util.List<java.lang.CharSequence!>! getText();
+ method @Deprecated public int getToIndex();
+ method @Deprecated public int getWindowId();
+ method @Deprecated public int hashCode();
+ method @Deprecated public boolean isChecked();
+ method @Deprecated public boolean isEnabled();
+ method @Deprecated public boolean isFullScreen();
+ method @Deprecated public boolean isPassword();
+ method @Deprecated public boolean isScrollable();
+ method @Deprecated public static androidx.core.view.accessibility.AccessibilityRecordCompat! obtain(androidx.core.view.accessibility.AccessibilityRecordCompat!);
+ method @Deprecated public static androidx.core.view.accessibility.AccessibilityRecordCompat! obtain();
+ method @Deprecated public void recycle();
+ method @Deprecated public void setAddedCount(int);
+ method @Deprecated public void setBeforeText(CharSequence!);
+ method @Deprecated public void setChecked(boolean);
+ method @Deprecated public void setClassName(CharSequence!);
+ method @Deprecated public void setContentDescription(CharSequence!);
+ method @Deprecated public void setCurrentItemIndex(int);
+ method @Deprecated public void setEnabled(boolean);
+ method @Deprecated public void setFromIndex(int);
+ method @Deprecated public void setFullScreen(boolean);
+ method @Deprecated public void setItemCount(int);
+ method @Deprecated public void setMaxScrollX(int);
+ method public static void setMaxScrollX(android.view.accessibility.AccessibilityRecord, int);
+ method @Deprecated public void setMaxScrollY(int);
+ method public static void setMaxScrollY(android.view.accessibility.AccessibilityRecord, int);
+ method @Deprecated public void setParcelableData(android.os.Parcelable!);
+ method @Deprecated public void setPassword(boolean);
+ method @Deprecated public void setRemovedCount(int);
+ method @Deprecated public void setScrollX(int);
+ method @Deprecated public void setScrollY(int);
+ method @Deprecated public void setScrollable(boolean);
+ method @Deprecated public void setSource(android.view.View!);
+ method @Deprecated public void setSource(android.view.View!, int);
+ method public static void setSource(android.view.accessibility.AccessibilityRecord, android.view.View?, int);
+ method @Deprecated public void setToIndex(int);
+ }
+
+ public interface AccessibilityViewCommand {
+ method public boolean perform(android.view.View, androidx.core.view.accessibility.AccessibilityViewCommand.CommandArguments?);
+ }
+
+ public abstract static class AccessibilityViewCommand.CommandArguments {
+ ctor public AccessibilityViewCommand.CommandArguments();
+ }
+
+ public static final class AccessibilityViewCommand.MoveAtGranularityArguments extends androidx.core.view.accessibility.AccessibilityViewCommand.CommandArguments {
+ ctor public AccessibilityViewCommand.MoveAtGranularityArguments();
+ method public boolean getExtendSelection();
+ method public int getGranularity();
+ }
+
+ public static final class AccessibilityViewCommand.MoveHtmlArguments extends androidx.core.view.accessibility.AccessibilityViewCommand.CommandArguments {
+ ctor public AccessibilityViewCommand.MoveHtmlArguments();
+ method public String? getHTMLElement();
+ }
+
+ public static final class AccessibilityViewCommand.MoveWindowArguments extends androidx.core.view.accessibility.AccessibilityViewCommand.CommandArguments {
+ ctor public AccessibilityViewCommand.MoveWindowArguments();
+ method public int getX();
+ method public int getY();
+ }
+
+ public static final class AccessibilityViewCommand.ScrollToPositionArguments extends androidx.core.view.accessibility.AccessibilityViewCommand.CommandArguments {
+ ctor public AccessibilityViewCommand.ScrollToPositionArguments();
+ method public int getColumn();
+ method public int getRow();
+ }
+
+ public static final class AccessibilityViewCommand.SetProgressArguments extends androidx.core.view.accessibility.AccessibilityViewCommand.CommandArguments {
+ ctor public AccessibilityViewCommand.SetProgressArguments();
+ method public float getProgress();
+ }
+
+ public static final class AccessibilityViewCommand.SetSelectionArguments extends androidx.core.view.accessibility.AccessibilityViewCommand.CommandArguments {
+ ctor public AccessibilityViewCommand.SetSelectionArguments();
+ method public int getEnd();
+ method public int getStart();
+ }
+
+ public static final class AccessibilityViewCommand.SetTextArguments extends androidx.core.view.accessibility.AccessibilityViewCommand.CommandArguments {
+ ctor public AccessibilityViewCommand.SetTextArguments();
+ method public CharSequence? getText();
+ }
+
+ public class AccessibilityWindowInfoCompat {
+ method public androidx.core.view.accessibility.AccessibilityNodeInfoCompat? getAnchor();
+ method public void getBoundsInScreen(android.graphics.Rect);
+ method public androidx.core.view.accessibility.AccessibilityWindowInfoCompat? getChild(int);
+ method public int getChildCount();
+ method public int getDisplayId();
+ method public int getId();
+ method public int getLayer();
+ method public androidx.core.view.accessibility.AccessibilityWindowInfoCompat? getParent();
+ method public void getRegionInScreen(android.graphics.Region);
+ method public androidx.core.view.accessibility.AccessibilityNodeInfoCompat? getRoot();
+ method public CharSequence? getTitle();
+ method public int getType();
+ method public boolean isAccessibilityFocused();
+ method public boolean isActive();
+ method public boolean isFocused();
+ method public boolean isInPictureInPictureMode();
+ method public static androidx.core.view.accessibility.AccessibilityWindowInfoCompat? obtain();
+ method public static androidx.core.view.accessibility.AccessibilityWindowInfoCompat? obtain(androidx.core.view.accessibility.AccessibilityWindowInfoCompat?);
+ method @Deprecated public void recycle();
+ method public android.view.accessibility.AccessibilityWindowInfo? unwrap();
+ field public static final int TYPE_ACCESSIBILITY_OVERLAY = 4; // 0x4
+ field public static final int TYPE_APPLICATION = 1; // 0x1
+ field public static final int TYPE_INPUT_METHOD = 2; // 0x2
+ field public static final int TYPE_SPLIT_SCREEN_DIVIDER = 5; // 0x5
+ field public static final int TYPE_SYSTEM = 3; // 0x3
+ }
+
+}
+
+package androidx.core.view.animation {
+
+ public final class PathInterpolatorCompat {
+ method public static android.view.animation.Interpolator create(android.graphics.Path);
+ method public static android.view.animation.Interpolator create(float, float);
+ method public static android.view.animation.Interpolator create(float, float, float, float);
+ }
+
+}
+
+package androidx.core.view.inputmethod {
+
+ public final class EditorInfoCompat {
+ ctor @Deprecated public EditorInfoCompat();
+ method public static String![] getContentMimeTypes(android.view.inputmethod.EditorInfo);
+ method public static CharSequence? getInitialSelectedText(android.view.inputmethod.EditorInfo, int);
+ method public static CharSequence? getInitialTextAfterCursor(android.view.inputmethod.EditorInfo, int, int);
+ method public static CharSequence? getInitialTextBeforeCursor(android.view.inputmethod.EditorInfo, int, int);
+ method public static void setContentMimeTypes(android.view.inputmethod.EditorInfo, String![]?);
+ method public static void setInitialSurroundingSubText(android.view.inputmethod.EditorInfo, CharSequence, int);
+ method public static void setInitialSurroundingText(android.view.inputmethod.EditorInfo, CharSequence);
+ field public static final int IME_FLAG_FORCE_ASCII = -2147483648; // 0x80000000
+ field public static final int IME_FLAG_NO_PERSONALIZED_LEARNING = 16777216; // 0x1000000
+ }
+
+ public final class InputConnectionCompat {
+ ctor @Deprecated public InputConnectionCompat();
+ method public static boolean commitContent(android.view.inputmethod.InputConnection, android.view.inputmethod.EditorInfo, androidx.core.view.inputmethod.InputContentInfoCompat, int, android.os.Bundle?);
+ method @Deprecated public static android.view.inputmethod.InputConnection createWrapper(android.view.inputmethod.InputConnection, android.view.inputmethod.EditorInfo, androidx.core.view.inputmethod.InputConnectionCompat.OnCommitContentListener);
+ method public static android.view.inputmethod.InputConnection createWrapper(android.view.View, android.view.inputmethod.InputConnection, android.view.inputmethod.EditorInfo);
+ field public static final int INPUT_CONTENT_GRANT_READ_URI_PERMISSION = 1; // 0x1
+ }
+
+ public static interface InputConnectionCompat.OnCommitContentListener {
+ method public boolean onCommitContent(androidx.core.view.inputmethod.InputContentInfoCompat, int, android.os.Bundle?);
+ }
+
+ public final class InputContentInfoCompat {
+ ctor public InputContentInfoCompat(android.net.Uri, android.content.ClipDescription, android.net.Uri?);
+ method public android.net.Uri getContentUri();
+ method public android.content.ClipDescription getDescription();
+ method public android.net.Uri? getLinkUri();
+ method public void releasePermission();
+ method public void requestPermission();
+ method public Object? unwrap();
+ method public static androidx.core.view.inputmethod.InputContentInfoCompat? wrap(Object?);
+ }
+
+}
+
+package androidx.core.widget {
+
+ public abstract class AutoScrollHelper implements android.view.View.OnTouchListener {
+ ctor public AutoScrollHelper(android.view.View);
+ method public abstract boolean canTargetScrollHorizontally(int);
+ method public abstract boolean canTargetScrollVertically(int);
+ method public boolean isEnabled();
+ method public boolean isExclusive();
+ method public boolean onTouch(android.view.View!, android.view.MotionEvent!);
+ method public abstract void scrollTargetBy(int, int);
+ method public androidx.core.widget.AutoScrollHelper setActivationDelay(int);
+ method public androidx.core.widget.AutoScrollHelper setEdgeType(int);
+ method public androidx.core.widget.AutoScrollHelper! setEnabled(boolean);
+ method public androidx.core.widget.AutoScrollHelper! setExclusive(boolean);
+ method public androidx.core.widget.AutoScrollHelper setMaximumEdges(float, float);
+ method public androidx.core.widget.AutoScrollHelper setMaximumVelocity(float, float);
+ method public androidx.core.widget.AutoScrollHelper setMinimumVelocity(float, float);
+ method public androidx.core.widget.AutoScrollHelper setRampDownDuration(int);
+ method public androidx.core.widget.AutoScrollHelper setRampUpDuration(int);
+ method public androidx.core.widget.AutoScrollHelper setRelativeEdges(float, float);
+ method public androidx.core.widget.AutoScrollHelper setRelativeVelocity(float, float);
+ field public static final int EDGE_TYPE_INSIDE = 0; // 0x0
+ field public static final int EDGE_TYPE_INSIDE_EXTEND = 1; // 0x1
+ field public static final int EDGE_TYPE_OUTSIDE = 2; // 0x2
+ field public static final float NO_MAX = 3.4028235E38f;
+ field public static final float NO_MIN = 0.0f;
+ field public static final float RELATIVE_UNSPECIFIED = 0.0f;
+ }
+
+ public final class CheckedTextViewCompat {
+ method public static android.graphics.drawable.Drawable? getCheckMarkDrawable(android.widget.CheckedTextView);
+ method public static android.content.res.ColorStateList? getCheckMarkTintList(android.widget.CheckedTextView);
+ method public static android.graphics.PorterDuff.Mode? getCheckMarkTintMode(android.widget.CheckedTextView);
+ method public static void setCheckMarkTintList(android.widget.CheckedTextView, android.content.res.ColorStateList?);
+ method public static void setCheckMarkTintMode(android.widget.CheckedTextView, android.graphics.PorterDuff.Mode?);
+ }
+
+ public final class CompoundButtonCompat {
+ method public static android.graphics.drawable.Drawable? getButtonDrawable(android.widget.CompoundButton);
+ method public static android.content.res.ColorStateList? getButtonTintList(android.widget.CompoundButton);
+ method public static android.graphics.PorterDuff.Mode? getButtonTintMode(android.widget.CompoundButton);
+ method public static void setButtonTintList(android.widget.CompoundButton, android.content.res.ColorStateList?);
+ method public static void setButtonTintMode(android.widget.CompoundButton, android.graphics.PorterDuff.Mode?);
+ }
+
+ public class ContentLoadingProgressBar extends android.widget.ProgressBar {
+ ctor public ContentLoadingProgressBar(android.content.Context);
+ ctor public ContentLoadingProgressBar(android.content.Context, android.util.AttributeSet?);
+ method public void hide();
+ method public void onAttachedToWindow();
+ method public void onDetachedFromWindow();
+ method public void show();
+ }
+
+ public final class EdgeEffectCompat {
+ ctor @Deprecated public EdgeEffectCompat(android.content.Context!);
+ method public static android.widget.EdgeEffect create(android.content.Context, android.util.AttributeSet?);
+ method @Deprecated public boolean draw(android.graphics.Canvas!);
+ method @Deprecated public void finish();
+ method public static float getDistance(android.widget.EdgeEffect);
+ method @Deprecated public boolean isFinished();
+ method @Deprecated public boolean onAbsorb(int);
+ method @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);
+ }
+
+ public class ImageViewCompat {
+ method public static android.content.res.ColorStateList? getImageTintList(android.widget.ImageView);
+ method public static android.graphics.PorterDuff.Mode? getImageTintMode(android.widget.ImageView);
+ method public static void setImageTintList(android.widget.ImageView, android.content.res.ColorStateList?);
+ method public static void setImageTintMode(android.widget.ImageView, android.graphics.PorterDuff.Mode?);
+ }
+
+ public final class ListPopupWindowCompat {
+ method @Deprecated public static android.view.View.OnTouchListener! createDragToOpenListener(Object!, android.view.View!);
+ method public static android.view.View.OnTouchListener? createDragToOpenListener(android.widget.ListPopupWindow, android.view.View);
+ }
+
+ public class ListViewAutoScrollHelper extends androidx.core.widget.AutoScrollHelper {
+ ctor public ListViewAutoScrollHelper(android.widget.ListView);
+ method public boolean canTargetScrollHorizontally(int);
+ method public boolean canTargetScrollVertically(int);
+ method public void scrollTargetBy(int, int);
+ }
+
+ public final class ListViewCompat {
+ method public static boolean canScrollList(android.widget.ListView, int);
+ method public static void scrollListBy(android.widget.ListView, int);
+ }
+
+ public class NestedScrollView extends android.widget.FrameLayout implements androidx.core.view.NestedScrollingChild3 androidx.core.view.NestedScrollingParent3 androidx.core.view.ScrollingView {
+ ctor public NestedScrollView(android.content.Context);
+ ctor public NestedScrollView(android.content.Context, android.util.AttributeSet?);
+ ctor public NestedScrollView(android.content.Context, android.util.AttributeSet?, int);
+ method public boolean arrowScroll(int);
+ method @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) public int computeHorizontalScrollExtent();
+ method @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) public int computeHorizontalScrollOffset();
+ method @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) public int computeHorizontalScrollRange();
+ method protected int computeScrollDeltaToGetChildRectOnScreen(android.graphics.Rect!);
+ method @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) public int computeVerticalScrollExtent();
+ method @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) public int computeVerticalScrollOffset();
+ method @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) public int computeVerticalScrollRange();
+ method public boolean dispatchNestedPreScroll(int, int, int[]?, int[]?, int);
+ method public void dispatchNestedScroll(int, int, int, int, int[]?, int, int[]);
+ method public boolean dispatchNestedScroll(int, int, int, int, int[]?, int);
+ method public boolean executeKeyEvent(android.view.KeyEvent);
+ method public void fling(int);
+ method public boolean fullScroll(int);
+ method public int getMaxScrollAmount();
+ method public boolean hasNestedScrollingParent(int);
+ method public boolean isFillViewport();
+ method public boolean isSmoothScrollingEnabled();
+ method public void onAttachedToWindow();
+ method public void onNestedPreScroll(android.view.View, int, int, int[], int);
+ method public void onNestedScroll(android.view.View, int, int, int, int, int, int[]);
+ method public void onNestedScroll(android.view.View, int, int, int, int, int);
+ method public void onNestedScrollAccepted(android.view.View, android.view.View, int, int);
+ method public boolean onStartNestedScroll(android.view.View, android.view.View, int, int);
+ method public void onStopNestedScroll(android.view.View, int);
+ method public boolean pageScroll(int);
+ method public void setFillViewport(boolean);
+ method public void setOnScrollChangeListener(androidx.core.widget.NestedScrollView.OnScrollChangeListener?);
+ method public void setSmoothScrollingEnabled(boolean);
+ method public final void smoothScrollBy(int, int);
+ method public final void smoothScrollBy(int, int, int);
+ method public final void smoothScrollTo(int, int);
+ method public final void smoothScrollTo(int, int, int);
+ method public boolean startNestedScroll(int, int);
+ method public void stopNestedScroll(int);
+ }
+
+ public static interface NestedScrollView.OnScrollChangeListener {
+ method public void onScrollChange(androidx.core.widget.NestedScrollView, int, int, int, int);
+ }
+
+ public final class PopupMenuCompat {
+ method public static android.view.View.OnTouchListener? getDragToOpenListener(Object);
+ }
+
+ public final class PopupWindowCompat {
+ method public static boolean getOverlapAnchor(android.widget.PopupWindow);
+ method public static int getWindowLayoutType(android.widget.PopupWindow);
+ method public static void setOverlapAnchor(android.widget.PopupWindow, boolean);
+ method public static void setWindowLayoutType(android.widget.PopupWindow, int);
+ method public static void showAsDropDown(android.widget.PopupWindow, android.view.View, int, int, int);
+ }
+
+ @Deprecated public final class ScrollerCompat {
+ method @Deprecated public void abortAnimation();
+ method @Deprecated public boolean computeScrollOffset();
+ method @Deprecated public static androidx.core.widget.ScrollerCompat! create(android.content.Context!);
+ method @Deprecated public static androidx.core.widget.ScrollerCompat! create(android.content.Context!, android.view.animation.Interpolator!);
+ method @Deprecated public void fling(int, int, int, int, int, int, int, int);
+ method @Deprecated public void fling(int, int, int, int, int, int, int, int, int, int);
+ method @Deprecated public float getCurrVelocity();
+ method @Deprecated public int getCurrX();
+ method @Deprecated public int getCurrY();
+ method @Deprecated public int getFinalX();
+ method @Deprecated public int getFinalY();
+ method @Deprecated public boolean isFinished();
+ method @Deprecated public boolean isOverScrolled();
+ method @Deprecated public void notifyHorizontalEdgeReached(int, int, int);
+ method @Deprecated public void notifyVerticalEdgeReached(int, int, int);
+ method @Deprecated public boolean springBack(int, int, int, int, int, int);
+ method @Deprecated public void startScroll(int, int, int, int);
+ method @Deprecated public void startScroll(int, int, int, int, int);
+ }
+
+ public final class TextViewCompat {
+ method public static int getAutoSizeMaxTextSize(android.widget.TextView);
+ method public static int getAutoSizeMinTextSize(android.widget.TextView);
+ method public static int getAutoSizeStepGranularity(android.widget.TextView);
+ method public static int[] getAutoSizeTextAvailableSizes(android.widget.TextView);
+ method public static int getAutoSizeTextType(android.widget.TextView);
+ method public static android.content.res.ColorStateList? getCompoundDrawableTintList(android.widget.TextView);
+ method public static android.graphics.PorterDuff.Mode? getCompoundDrawableTintMode(android.widget.TextView);
+ method public static android.graphics.drawable.Drawable![] getCompoundDrawablesRelative(android.widget.TextView);
+ method public static int getFirstBaselineToTopHeight(android.widget.TextView);
+ method public static int getLastBaselineToBottomHeight(android.widget.TextView);
+ method public static int getMaxLines(android.widget.TextView);
+ method public static int getMinLines(android.widget.TextView);
+ method public static androidx.core.text.PrecomputedTextCompat.Params getTextMetricsParams(android.widget.TextView);
+ method public static void setAutoSizeTextTypeUniformWithConfiguration(android.widget.TextView, int, int, int, int) throws java.lang.IllegalArgumentException;
+ method public static void setAutoSizeTextTypeUniformWithPresetSizes(android.widget.TextView, int[], int) throws java.lang.IllegalArgumentException;
+ method public static void setAutoSizeTextTypeWithDefaults(android.widget.TextView, int);
+ method public static void setCompoundDrawableTintList(android.widget.TextView, android.content.res.ColorStateList?);
+ method public static void setCompoundDrawableTintMode(android.widget.TextView, android.graphics.PorterDuff.Mode?);
+ method public static void setCompoundDrawablesRelative(android.widget.TextView, android.graphics.drawable.Drawable?, android.graphics.drawable.Drawable?, android.graphics.drawable.Drawable?, android.graphics.drawable.Drawable?);
+ method public static void setCompoundDrawablesRelativeWithIntrinsicBounds(android.widget.TextView, android.graphics.drawable.Drawable?, android.graphics.drawable.Drawable?, android.graphics.drawable.Drawable?, android.graphics.drawable.Drawable?);
+ method public static void setCompoundDrawablesRelativeWithIntrinsicBounds(android.widget.TextView, @DrawableRes int, @DrawableRes int, @DrawableRes int, @DrawableRes int);
+ method public static void setCustomSelectionActionModeCallback(android.widget.TextView, android.view.ActionMode.Callback);
+ method public static void setFirstBaselineToTopHeight(android.widget.TextView, @IntRange(from=0) @Px int);
+ method public static void setLastBaselineToBottomHeight(android.widget.TextView, @IntRange(from=0) @Px int);
+ method public static void setLineHeight(android.widget.TextView, @IntRange(from=0) @Px int);
+ method public static void setPrecomputedText(android.widget.TextView, androidx.core.text.PrecomputedTextCompat);
+ method public static void setTextAppearance(android.widget.TextView, @StyleRes int);
+ method public static void setTextMetricsParams(android.widget.TextView, androidx.core.text.PrecomputedTextCompat.Params);
+ field public static final int AUTO_SIZE_TEXT_TYPE_NONE = 0; // 0x0
+ field public static final int AUTO_SIZE_TEXT_TYPE_UNIFORM = 1; // 0x1
+ }
+
+ public interface TintableCompoundButton {
+ method public android.content.res.ColorStateList? getSupportButtonTintList();
+ method public android.graphics.PorterDuff.Mode? getSupportButtonTintMode();
+ method public void setSupportButtonTintList(android.content.res.ColorStateList?);
+ method public void setSupportButtonTintMode(android.graphics.PorterDuff.Mode?);
+ }
+
+ public interface TintableCompoundDrawablesView {
+ method public android.content.res.ColorStateList? getSupportCompoundDrawablesTintList();
+ method public android.graphics.PorterDuff.Mode? getSupportCompoundDrawablesTintMode();
+ method public void setSupportCompoundDrawablesTintList(android.content.res.ColorStateList?);
+ method public void setSupportCompoundDrawablesTintMode(android.graphics.PorterDuff.Mode?);
+ }
+
+}
+
diff --git a/core/core/api/public_plus_experimental_current.txt b/core/core/api/public_plus_experimental_current.txt
index 2b431b6..3238e35 100644
--- a/core/core/api/public_plus_experimental_current.txt
+++ b/core/core/api/public_plus_experimental_current.txt
@@ -2016,6 +2016,26 @@
}
+package androidx.core.service.quicksettings {
+
+ public class PendingIntentActivityWrapper {
+ ctor public PendingIntentActivityWrapper(android.content.Context, int, android.content.Intent, int, boolean);
+ ctor public PendingIntentActivityWrapper(android.content.Context, int, android.content.Intent, int, android.os.Bundle?, boolean);
+ method public android.content.Context getContext();
+ method public int getFlags();
+ method public android.content.Intent getIntent();
+ method public android.os.Bundle getOptions();
+ method public android.app.PendingIntent? getPendingIntent();
+ method public int getRequestCode();
+ method public boolean isMutable();
+ }
+
+ public class TileServiceCompat {
+ method public static void startActivityAndCollapse(android.service.quicksettings.TileService, androidx.core.service.quicksettings.PendingIntentActivityWrapper);
+ }
+
+}
+
package androidx.core.telephony {
@RequiresApi(22) public class SubscriptionManagerCompat {
@@ -2156,6 +2176,66 @@
method public static boolean addLinks(android.text.Spannable, java.util.regex.Pattern, String?, String![]?, android.text.util.Linkify.MatchFilter?, android.text.util.Linkify.TransformFilter?);
}
+ public final class LocalePreferences {
+ method @RequiresApi(android.os.Build.VERSION_CODES.TIRAMISU) public static String getCalendarType();
+ method @RequiresApi(android.os.Build.VERSION_CODES.TIRAMISU) public static String getCalendarType(java.util.Locale);
+ method @RequiresApi(android.os.Build.VERSION_CODES.TIRAMISU) public static String getCalendarType(boolean);
+ method @RequiresApi(android.os.Build.VERSION_CODES.TIRAMISU) public static String getCalendarType(java.util.Locale, boolean);
+ method @RequiresApi(android.os.Build.VERSION_CODES.TIRAMISU) public static String getFirstDayOfWeek();
+ method @RequiresApi(android.os.Build.VERSION_CODES.TIRAMISU) public static String getFirstDayOfWeek(java.util.Locale);
+ method @RequiresApi(android.os.Build.VERSION_CODES.TIRAMISU) public static String getFirstDayOfWeek(boolean);
+ method @RequiresApi(android.os.Build.VERSION_CODES.TIRAMISU) public static String getFirstDayOfWeek(java.util.Locale, boolean);
+ method @RequiresApi(android.os.Build.VERSION_CODES.TIRAMISU) public static String getHourCycle();
+ method @RequiresApi(android.os.Build.VERSION_CODES.TIRAMISU) public static String getHourCycle(java.util.Locale);
+ method @RequiresApi(android.os.Build.VERSION_CODES.TIRAMISU) public static String getHourCycle(boolean);
+ method @RequiresApi(android.os.Build.VERSION_CODES.TIRAMISU) public static String getHourCycle(java.util.Locale, boolean);
+ method @RequiresApi(android.os.Build.VERSION_CODES.TIRAMISU) public static String getTemperatureUnit();
+ method @RequiresApi(android.os.Build.VERSION_CODES.TIRAMISU) public static String getTemperatureUnit(java.util.Locale);
+ method @RequiresApi(android.os.Build.VERSION_CODES.TIRAMISU) public static String getTemperatureUnit(boolean);
+ method @RequiresApi(android.os.Build.VERSION_CODES.TIRAMISU) public static String getTemperatureUnit(java.util.Locale, boolean);
+ }
+
+ public static class LocalePreferences.CalendarType {
+ field public static final String CHINESE = "chinese";
+ field public static final String DANGI = "dangi";
+ field public static final String DEFAULT = "";
+ field public static final String GREGORIAN = "gregorian";
+ field public static final String HEBREW = "hebrew";
+ field public static final String INDIAN = "indian";
+ field public static final String ISLAMIC = "islamic";
+ field public static final String ISLAMIC_CIVIL = "islamic-civil";
+ field public static final String ISLAMIC_RGSA = "islamic-rgsa";
+ field public static final String ISLAMIC_TBLA = "islamic-tbla";
+ field public static final String ISLAMIC_UMALQURA = "islamic-umalqura";
+ field public static final String PERSIAN = "persian";
+ }
+
+ public static class LocalePreferences.FirstDayOfWeek {
+ field public static final String DEFAULT = "";
+ field public static final String FRIDAY = "fri";
+ field public static final String MONDAY = "mon";
+ field public static final String SATURDAY = "sat";
+ field public static final String SUNDAY = "sun";
+ field public static final String THURSDAY = "thu";
+ field public static final String TUESDAY = "tue";
+ field public static final String WEDNESDAY = "wed";
+ }
+
+ public static class LocalePreferences.HourCycle {
+ field public static final String DEFAULT = "";
+ field public static final String H11 = "h11";
+ field public static final String H12 = "h12";
+ field public static final String H23 = "h23";
+ field public static final String H24 = "h24";
+ }
+
+ public static class LocalePreferences.TemperatureUnit {
+ field public static final String CELSIUS = "celsius";
+ field public static final String DEFAULT = "";
+ field public static final String FAHRENHEIT = "fahrenheit";
+ field public static final String KELVIN = "kelvin";
+ }
+
}
package androidx.core.util {
@@ -2237,6 +2317,14 @@
method public T! get();
}
+ public class TypedValueCompat {
+ method public static float deriveDimension(int, float, android.util.DisplayMetrics);
+ method public static float dpToPx(float, android.util.DisplayMetrics);
+ method public static float pxToDp(float, android.util.DisplayMetrics);
+ method public static float pxToSp(float, android.util.DisplayMetrics);
+ method public static float spToPx(float, android.util.DisplayMetrics);
+ }
+
}
package androidx.core.view {
@@ -2694,9 +2782,12 @@
method public void setSupportBackgroundTintMode(android.graphics.PorterDuff.Mode?);
}
- @Deprecated public final class VelocityTrackerCompat {
+ public final class VelocityTrackerCompat {
+ method public static float getAxisVelocity(android.view.VelocityTracker, int);
+ method public static float getAxisVelocity(android.view.VelocityTracker, int, int);
method @Deprecated public static float getXVelocity(android.view.VelocityTracker!, int);
method @Deprecated public static float getYVelocity(android.view.VelocityTracker!, int);
+ method public static boolean isAxisSupported(android.view.VelocityTracker, int);
}
public class ViewCompat {
@@ -3633,6 +3724,7 @@
}
public class AccessibilityWindowInfoCompat {
+ ctor public AccessibilityWindowInfoCompat();
method public androidx.core.view.accessibility.AccessibilityNodeInfoCompat? getAnchor();
method public void getBoundsInScreen(android.graphics.Rect);
method public androidx.core.view.accessibility.AccessibilityWindowInfoCompat? getChild(int);
diff --git a/core/core/api/res-1.10.0-beta01.txt b/core/core/api/res-1.10.0-beta01.txt
new file mode 100644
index 0000000..dd913d3
--- /dev/null
+++ b/core/core/api/res-1.10.0-beta01.txt
@@ -0,0 +1,21 @@
+attr alpha
+attr font
+attr fontProviderAuthority
+attr fontProviderCerts
+attr fontProviderFetchStrategy
+attr fontProviderFetchTimeout
+attr fontProviderPackage
+attr fontProviderQuery
+attr fontProviderSystemFontFamily
+attr fontStyle
+attr fontVariationSettings
+attr fontWeight
+attr lStar
+attr queryPatterns
+attr shortcutMatchRequired
+attr ttcIndex
+style TextAppearance_Compat_Notification
+style TextAppearance_Compat_Notification_Info
+style TextAppearance_Compat_Notification_Line2
+style TextAppearance_Compat_Notification_Time
+style TextAppearance_Compat_Notification_Title
diff --git a/core/core/api/restricted_1.10.0-beta01.txt b/core/core/api/restricted_1.10.0-beta01.txt
new file mode 100644
index 0000000..9556806
--- /dev/null
+++ b/core/core/api/restricted_1.10.0-beta01.txt
@@ -0,0 +1,4438 @@
+// Signature format: 4.0
+package android.support.v4.os {
+
+ @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) public class ResultReceiver implements android.os.Parcelable {
+ ctor public ResultReceiver(android.os.Handler!);
+ method public int describeContents();
+ method protected void onReceiveResult(int, android.os.Bundle!);
+ method public void send(int, android.os.Bundle!);
+ method public void writeToParcel(android.os.Parcel, int);
+ field public static final android.os.Parcelable.Creator<android.support.v4.os.ResultReceiver!>! CREATOR;
+ }
+
+}
+
+package androidx.core.accessibilityservice {
+
+ public final class AccessibilityServiceInfoCompat {
+ method public static String capabilityToString(int);
+ method public static String feedbackTypeToString(int);
+ method public static String? flagToString(int);
+ method public static int getCapabilities(android.accessibilityservice.AccessibilityServiceInfo);
+ method public static String? loadDescription(android.accessibilityservice.AccessibilityServiceInfo, android.content.pm.PackageManager);
+ field public static final int CAPABILITY_CAN_FILTER_KEY_EVENTS = 8; // 0x8
+ field public static final int CAPABILITY_CAN_REQUEST_ENHANCED_WEB_ACCESSIBILITY = 4; // 0x4
+ field public static final int CAPABILITY_CAN_REQUEST_TOUCH_EXPLORATION = 2; // 0x2
+ field public static final int CAPABILITY_CAN_RETRIEVE_WINDOW_CONTENT = 1; // 0x1
+ field public static final int FEEDBACK_ALL_MASK = -1; // 0xffffffff
+ field public static final int FEEDBACK_BRAILLE = 32; // 0x20
+ field public static final int FLAG_INCLUDE_NOT_IMPORTANT_VIEWS = 2; // 0x2
+ field public static final int FLAG_REPORT_VIEW_IDS = 16; // 0x10
+ field public static final int FLAG_REQUEST_ENHANCED_WEB_ACCESSIBILITY = 8; // 0x8
+ field public static final int FLAG_REQUEST_FILTER_KEY_EVENTS = 32; // 0x20
+ field public static final int FLAG_REQUEST_TOUCH_EXPLORATION_MODE = 4; // 0x4
+ }
+
+}
+
+package androidx.core.app {
+
+ public class ActivityCompat extends androidx.core.content.ContextCompat {
+ ctor protected ActivityCompat();
+ method public static void finishAffinity(android.app.Activity);
+ method public static void finishAfterTransition(android.app.Activity);
+ method @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) public static androidx.core.app.ActivityCompat.PermissionCompatDelegate? getPermissionCompatDelegate();
+ method public static android.net.Uri? getReferrer(android.app.Activity);
+ method @Deprecated public static boolean invalidateOptionsMenu(android.app.Activity!);
+ method public static boolean isLaunchedFromBubble(android.app.Activity);
+ method public static void postponeEnterTransition(android.app.Activity);
+ method public static void recreate(android.app.Activity);
+ method public static androidx.core.view.DragAndDropPermissionsCompat? requestDragAndDropPermissions(android.app.Activity, android.view.DragEvent);
+ method public static void requestPermissions(android.app.Activity, String![], @IntRange(from=0) int);
+ method public static <T extends android.view.View> T requireViewById(android.app.Activity, @IdRes int);
+ method public static void setEnterSharedElementCallback(android.app.Activity, androidx.core.app.SharedElementCallback?);
+ method public static void setExitSharedElementCallback(android.app.Activity, androidx.core.app.SharedElementCallback?);
+ method public static void setLocusContext(android.app.Activity, androidx.core.content.LocusIdCompat?, android.os.Bundle?);
+ method public static void setPermissionCompatDelegate(androidx.core.app.ActivityCompat.PermissionCompatDelegate?);
+ method public static boolean shouldShowRequestPermissionRationale(android.app.Activity, String);
+ method public static void startActivityForResult(android.app.Activity, android.content.Intent, int, android.os.Bundle?);
+ method public static void startIntentSenderForResult(android.app.Activity, android.content.IntentSender, int, android.content.Intent?, int, int, int, android.os.Bundle?) throws android.content.IntentSender.SendIntentException;
+ method public static void startPostponedEnterTransition(android.app.Activity);
+ }
+
+ public static interface ActivityCompat.OnRequestPermissionsResultCallback {
+ method public void onRequestPermissionsResult(int, String![], int[]);
+ }
+
+ public static interface ActivityCompat.PermissionCompatDelegate {
+ method public boolean onActivityResult(android.app.Activity, @IntRange(from=0) int, int, android.content.Intent?);
+ method public boolean requestPermissions(android.app.Activity, String![], @IntRange(from=0) int);
+ }
+
+ @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) public static interface ActivityCompat.RequestPermissionsRequestCodeValidator {
+ method public void validateRequestPermissionsRequestCode(int);
+ }
+
+ public final class ActivityManagerCompat {
+ method public static boolean isLowRamDevice(android.app.ActivityManager);
+ }
+
+ public class ActivityOptionsCompat {
+ ctor protected ActivityOptionsCompat();
+ method public android.graphics.Rect? getLaunchBounds();
+ method public static androidx.core.app.ActivityOptionsCompat makeBasic();
+ method public static androidx.core.app.ActivityOptionsCompat makeClipRevealAnimation(android.view.View, int, int, int, int);
+ method public static androidx.core.app.ActivityOptionsCompat makeCustomAnimation(android.content.Context, int, int);
+ method public static androidx.core.app.ActivityOptionsCompat makeScaleUpAnimation(android.view.View, int, int, int, int);
+ method public static androidx.core.app.ActivityOptionsCompat makeSceneTransitionAnimation(android.app.Activity, android.view.View, String);
+ method public static androidx.core.app.ActivityOptionsCompat makeSceneTransitionAnimation(android.app.Activity, androidx.core.util.Pair<android.view.View!,java.lang.String!>!...);
+ method public static androidx.core.app.ActivityOptionsCompat makeTaskLaunchBehind();
+ method public static androidx.core.app.ActivityOptionsCompat makeThumbnailScaleUpAnimation(android.view.View, android.graphics.Bitmap, int, int);
+ method public void requestUsageTimeReport(android.app.PendingIntent);
+ method public androidx.core.app.ActivityOptionsCompat setLaunchBounds(android.graphics.Rect?);
+ method public android.os.Bundle? toBundle();
+ method public void update(androidx.core.app.ActivityOptionsCompat);
+ field public static final String EXTRA_USAGE_TIME_REPORT = "android.activity.usage_time";
+ field public static final String EXTRA_USAGE_TIME_REPORT_PACKAGES = "android.usage_time_packages";
+ }
+
+ public final class AlarmManagerCompat {
+ method public static void setAlarmClock(android.app.AlarmManager, long, android.app.PendingIntent, android.app.PendingIntent);
+ method public static void setAndAllowWhileIdle(android.app.AlarmManager, int, long, android.app.PendingIntent);
+ method public static void setExact(android.app.AlarmManager, int, long, android.app.PendingIntent);
+ method public static void setExactAndAllowWhileIdle(android.app.AlarmManager, int, long, android.app.PendingIntent);
+ }
+
+ @RequiresApi(28) public class AppComponentFactory extends android.app.AppComponentFactory {
+ ctor public AppComponentFactory();
+ method public final android.app.Activity instantiateActivity(ClassLoader, String, android.content.Intent?) throws java.lang.ClassNotFoundException, java.lang.IllegalAccessException, java.lang.InstantiationException;
+ method public android.app.Activity instantiateActivityCompat(ClassLoader, String, android.content.Intent?) throws java.lang.ClassNotFoundException, java.lang.IllegalAccessException, java.lang.InstantiationException;
+ method public final android.app.Application instantiateApplication(ClassLoader, String) throws java.lang.ClassNotFoundException, java.lang.IllegalAccessException, java.lang.InstantiationException;
+ method public android.app.Application instantiateApplicationCompat(ClassLoader, String) throws java.lang.ClassNotFoundException, java.lang.IllegalAccessException, java.lang.InstantiationException;
+ method public final android.content.ContentProvider instantiateProvider(ClassLoader, String) throws java.lang.ClassNotFoundException, java.lang.IllegalAccessException, java.lang.InstantiationException;
+ method public android.content.ContentProvider instantiateProviderCompat(ClassLoader, String) throws java.lang.ClassNotFoundException, java.lang.IllegalAccessException, java.lang.InstantiationException;
+ method public final android.content.BroadcastReceiver instantiateReceiver(ClassLoader, String, android.content.Intent?) throws java.lang.ClassNotFoundException, java.lang.IllegalAccessException, java.lang.InstantiationException;
+ method public android.content.BroadcastReceiver instantiateReceiverCompat(ClassLoader, String, android.content.Intent?) throws java.lang.ClassNotFoundException, java.lang.IllegalAccessException, java.lang.InstantiationException;
+ method public final android.app.Service instantiateService(ClassLoader, String, android.content.Intent?) throws java.lang.ClassNotFoundException, java.lang.IllegalAccessException, java.lang.InstantiationException;
+ method public android.app.Service instantiateServiceCompat(ClassLoader, String, android.content.Intent?) throws java.lang.ClassNotFoundException, java.lang.IllegalAccessException, java.lang.InstantiationException;
+ }
+
+ public class AppLaunchChecker {
+ ctor @Deprecated public AppLaunchChecker();
+ method public static boolean hasStartedFromLauncher(android.content.Context);
+ method public static void onActivityCreate(android.app.Activity);
+ }
+
+ public final class AppOpsManagerCompat {
+ method public static int checkOrNoteProxyOp(android.content.Context, int, String, String);
+ method public static int noteOp(android.content.Context, String, int, String);
+ method public static int noteOpNoThrow(android.content.Context, String, int, String);
+ method public static int noteProxyOp(android.content.Context, String, String);
+ method public static int noteProxyOpNoThrow(android.content.Context, String, String);
+ method public static String? permissionToOp(String);
+ field public static final int MODE_ALLOWED = 0; // 0x0
+ field public static final int MODE_DEFAULT = 3; // 0x3
+ field public static final int MODE_ERRORED = 2; // 0x2
+ field public static final int MODE_IGNORED = 1; // 0x1
+ }
+
+ public final class BundleCompat {
+ method public static android.os.IBinder? getBinder(android.os.Bundle, String?);
+ method public static void putBinder(android.os.Bundle, String?, android.os.IBinder?);
+ }
+
+ @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) public class ComponentActivity extends android.app.Activity implements androidx.core.view.KeyEventDispatcher.Component androidx.lifecycle.LifecycleOwner {
+ ctor public ComponentActivity();
+ method @Deprecated @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) public <T extends androidx.core.app.ComponentActivity.ExtraData> T! getExtraData(Class<T!>!);
+ method public androidx.lifecycle.Lifecycle getLifecycle();
+ method @Deprecated @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) public void putExtraData(androidx.core.app.ComponentActivity.ExtraData!);
+ method protected final boolean shouldDumpInternalState(String![]?);
+ method @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) public boolean superDispatchKeyEvent(android.view.KeyEvent);
+ }
+
+ @Deprecated @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) public static class ComponentActivity.ExtraData {
+ ctor @Deprecated public ComponentActivity.ExtraData();
+ }
+
+ @RequiresApi(api=28) @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) public class CoreComponentFactory extends android.app.AppComponentFactory {
+ ctor public CoreComponentFactory();
+ }
+
+ @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) public static interface CoreComponentFactory.CompatWrapped {
+ method public Object! getWrapper();
+ }
+
+ public class DialogCompat {
+ method public static android.view.View requireViewById(android.app.Dialog, int);
+ }
+
+ public class FrameMetricsAggregator {
+ ctor public FrameMetricsAggregator();
+ ctor public FrameMetricsAggregator(@androidx.core.app.FrameMetricsAggregator.MetricType int);
+ method public void add(android.app.Activity);
+ method public android.util.SparseIntArray![]? getMetrics();
+ method public android.util.SparseIntArray![]? remove(android.app.Activity);
+ method public android.util.SparseIntArray![]? reset();
+ method public android.util.SparseIntArray![]? stop();
+ field public static final int ANIMATION_DURATION = 256; // 0x100
+ field public static final int ANIMATION_INDEX = 8; // 0x8
+ field public static final int COMMAND_DURATION = 32; // 0x20
+ field public static final int COMMAND_INDEX = 5; // 0x5
+ field public static final int DELAY_DURATION = 128; // 0x80
+ field public static final int DELAY_INDEX = 7; // 0x7
+ field public static final int DRAW_DURATION = 8; // 0x8
+ field public static final int DRAW_INDEX = 3; // 0x3
+ field public static final int EVERY_DURATION = 511; // 0x1ff
+ field public static final int INPUT_DURATION = 2; // 0x2
+ field public static final int INPUT_INDEX = 1; // 0x1
+ field public static final int LAYOUT_MEASURE_DURATION = 4; // 0x4
+ field public static final int LAYOUT_MEASURE_INDEX = 2; // 0x2
+ field public static final int SWAP_DURATION = 64; // 0x40
+ field public static final int SWAP_INDEX = 6; // 0x6
+ field public static final int SYNC_DURATION = 16; // 0x10
+ field public static final int SYNC_INDEX = 4; // 0x4
+ field public static final int TOTAL_DURATION = 1; // 0x1
+ field public static final int TOTAL_INDEX = 0; // 0x0
+ }
+
+ @IntDef(flag=true, value={androidx.core.app.FrameMetricsAggregator.TOTAL_DURATION, androidx.core.app.FrameMetricsAggregator.INPUT_DURATION, androidx.core.app.FrameMetricsAggregator.LAYOUT_MEASURE_DURATION, androidx.core.app.FrameMetricsAggregator.DRAW_DURATION, androidx.core.app.FrameMetricsAggregator.SYNC_DURATION, androidx.core.app.FrameMetricsAggregator.COMMAND_DURATION, androidx.core.app.FrameMetricsAggregator.SWAP_DURATION, androidx.core.app.FrameMetricsAggregator.DELAY_DURATION, androidx.core.app.FrameMetricsAggregator.ANIMATION_DURATION, androidx.core.app.FrameMetricsAggregator.EVERY_DURATION}) @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.SOURCE) public static @interface FrameMetricsAggregator.MetricType {
+ }
+
+ @Deprecated public abstract class JobIntentService extends android.app.Service {
+ ctor @Deprecated public JobIntentService();
+ method @Deprecated public static void enqueueWork(android.content.Context, Class<?>, int, android.content.Intent);
+ method @Deprecated public static void enqueueWork(android.content.Context, android.content.ComponentName, int, android.content.Intent);
+ method @Deprecated public boolean isStopped();
+ method @Deprecated public android.os.IBinder! onBind(android.content.Intent);
+ method @Deprecated protected abstract void onHandleWork(android.content.Intent);
+ method @Deprecated public boolean onStopCurrentWork();
+ method @Deprecated public void setInterruptIfStopped(boolean);
+ }
+
+ public final class LocaleManagerCompat {
+ method @AnyThread public static androidx.core.os.LocaleListCompat getSystemLocales(android.content.Context);
+ }
+
+ public final class MultiWindowModeChangedInfo {
+ ctor public MultiWindowModeChangedInfo(boolean);
+ ctor @RequiresApi(26) public MultiWindowModeChangedInfo(boolean, android.content.res.Configuration);
+ method @RequiresApi(26) public android.content.res.Configuration getNewConfig();
+ method public boolean isInMultiWindowMode();
+ }
+
+ public final class NavUtils {
+ method public static android.content.Intent? getParentActivityIntent(android.app.Activity);
+ method public static android.content.Intent? getParentActivityIntent(android.content.Context, Class<?>) throws android.content.pm.PackageManager.NameNotFoundException;
+ method public static android.content.Intent? getParentActivityIntent(android.content.Context, android.content.ComponentName) throws android.content.pm.PackageManager.NameNotFoundException;
+ method public static String? getParentActivityName(android.app.Activity);
+ method public static String? getParentActivityName(android.content.Context, android.content.ComponentName) throws android.content.pm.PackageManager.NameNotFoundException;
+ method public static void navigateUpFromSameTask(android.app.Activity);
+ method public static void navigateUpTo(android.app.Activity, android.content.Intent);
+ method public static boolean shouldUpRecreateTask(android.app.Activity, android.content.Intent);
+ field public static final String PARENT_ACTIVITY = "android.support.PARENT_ACTIVITY";
+ }
+
+ @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) public interface NotificationBuilderWithBuilderAccessor {
+ method public android.app.Notification.Builder! getBuilder();
+ }
+
+ public class NotificationChannelCompat {
+ method public boolean canBubble();
+ method public boolean canBypassDnd();
+ method public boolean canShowBadge();
+ method public android.media.AudioAttributes? getAudioAttributes();
+ method public String? getConversationId();
+ method public String? getDescription();
+ method public String? getGroup();
+ method public String getId();
+ method public int getImportance();
+ method public int getLightColor();
+ method @androidx.core.app.NotificationCompat.NotificationVisibility public int getLockscreenVisibility();
+ method public CharSequence? getName();
+ method public String? getParentChannelId();
+ method public android.net.Uri? getSound();
+ method public long[]? getVibrationPattern();
+ method public boolean isImportantConversation();
+ method public boolean shouldShowLights();
+ method public boolean shouldVibrate();
+ method public androidx.core.app.NotificationChannelCompat.Builder toBuilder();
+ field public static final String DEFAULT_CHANNEL_ID = "miscellaneous";
+ }
+
+ public static class NotificationChannelCompat.Builder {
+ ctor public NotificationChannelCompat.Builder(String, int);
+ method public androidx.core.app.NotificationChannelCompat build();
+ method public androidx.core.app.NotificationChannelCompat.Builder setConversationId(String, String);
+ method public androidx.core.app.NotificationChannelCompat.Builder setDescription(String?);
+ method public androidx.core.app.NotificationChannelCompat.Builder setGroup(String?);
+ method public androidx.core.app.NotificationChannelCompat.Builder setImportance(int);
+ method public androidx.core.app.NotificationChannelCompat.Builder setLightColor(int);
+ method public androidx.core.app.NotificationChannelCompat.Builder setLightsEnabled(boolean);
+ method public androidx.core.app.NotificationChannelCompat.Builder setName(CharSequence?);
+ method public androidx.core.app.NotificationChannelCompat.Builder setShowBadge(boolean);
+ method public androidx.core.app.NotificationChannelCompat.Builder setSound(android.net.Uri?, android.media.AudioAttributes?);
+ method public androidx.core.app.NotificationChannelCompat.Builder setVibrationEnabled(boolean);
+ method public androidx.core.app.NotificationChannelCompat.Builder setVibrationPattern(long[]?);
+ }
+
+ public class NotificationChannelGroupCompat {
+ method public java.util.List<androidx.core.app.NotificationChannelCompat!> getChannels();
+ method public String? getDescription();
+ method public String getId();
+ method public CharSequence? getName();
+ method public boolean isBlocked();
+ method public androidx.core.app.NotificationChannelGroupCompat.Builder toBuilder();
+ }
+
+ public static class NotificationChannelGroupCompat.Builder {
+ ctor public NotificationChannelGroupCompat.Builder(String);
+ method public androidx.core.app.NotificationChannelGroupCompat build();
+ method public androidx.core.app.NotificationChannelGroupCompat.Builder setDescription(String?);
+ method public androidx.core.app.NotificationChannelGroupCompat.Builder setName(CharSequence?);
+ }
+
+ public class NotificationCompat {
+ ctor @Deprecated public NotificationCompat();
+ method public static androidx.core.app.NotificationCompat.Action? getAction(android.app.Notification, int);
+ method public static int getActionCount(android.app.Notification);
+ method public static boolean getAllowSystemGeneratedContextualActions(android.app.Notification);
+ method public static boolean getAutoCancel(android.app.Notification);
+ method public static int getBadgeIconType(android.app.Notification);
+ method public static androidx.core.app.NotificationCompat.BubbleMetadata? getBubbleMetadata(android.app.Notification);
+ method public static String? getCategory(android.app.Notification);
+ method public static String? getChannelId(android.app.Notification);
+ method public static int getColor(android.app.Notification);
+ method @RequiresApi(19) public static CharSequence? getContentInfo(android.app.Notification);
+ method @RequiresApi(19) public static CharSequence? getContentText(android.app.Notification);
+ method @RequiresApi(19) public static CharSequence? getContentTitle(android.app.Notification);
+ method public static android.os.Bundle? getExtras(android.app.Notification);
+ method public static String? getGroup(android.app.Notification);
+ method @androidx.core.app.NotificationCompat.GroupAlertBehavior public static int getGroupAlertBehavior(android.app.Notification);
+ method @RequiresApi(21) public static java.util.List<androidx.core.app.NotificationCompat.Action!> getInvisibleActions(android.app.Notification);
+ method public static boolean getLocalOnly(android.app.Notification);
+ method public static androidx.core.content.LocusIdCompat? getLocusId(android.app.Notification);
+ method public static boolean getOngoing(android.app.Notification);
+ method public static boolean getOnlyAlertOnce(android.app.Notification);
+ method public static java.util.List<androidx.core.app.Person!> getPeople(android.app.Notification);
+ method public static android.app.Notification? getPublicVersion(android.app.Notification);
+ method public static CharSequence? getSettingsText(android.app.Notification);
+ method public static String? getShortcutId(android.app.Notification);
+ method @RequiresApi(19) public static boolean getShowWhen(android.app.Notification);
+ method public static String? getSortKey(android.app.Notification);
+ method @RequiresApi(19) public static CharSequence? getSubText(android.app.Notification);
+ method public static long getTimeoutAfter(android.app.Notification);
+ method @RequiresApi(19) public static boolean getUsesChronometer(android.app.Notification);
+ method @androidx.core.app.NotificationCompat.NotificationVisibility public static int getVisibility(android.app.Notification);
+ method public static boolean isGroupSummary(android.app.Notification);
+ field public static final int BADGE_ICON_LARGE = 2; // 0x2
+ field public static final int BADGE_ICON_NONE = 0; // 0x0
+ field public static final int BADGE_ICON_SMALL = 1; // 0x1
+ field public static final String CATEGORY_ALARM = "alarm";
+ field public static final String CATEGORY_CALL = "call";
+ field public static final String CATEGORY_EMAIL = "email";
+ field public static final String CATEGORY_ERROR = "err";
+ field public static final String CATEGORY_EVENT = "event";
+ field public static final String CATEGORY_LOCATION_SHARING = "location_sharing";
+ field public static final String CATEGORY_MESSAGE = "msg";
+ field public static final String CATEGORY_MISSED_CALL = "missed_call";
+ field public static final String CATEGORY_NAVIGATION = "navigation";
+ field public static final String CATEGORY_PROGRESS = "progress";
+ field public static final String CATEGORY_PROMO = "promo";
+ field public static final String CATEGORY_RECOMMENDATION = "recommendation";
+ field public static final String CATEGORY_REMINDER = "reminder";
+ field public static final String CATEGORY_SERVICE = "service";
+ field public static final String CATEGORY_SOCIAL = "social";
+ field public static final String CATEGORY_STATUS = "status";
+ field public static final String CATEGORY_STOPWATCH = "stopwatch";
+ field public static final String CATEGORY_SYSTEM = "sys";
+ field public static final String CATEGORY_TRANSPORT = "transport";
+ field public static final String CATEGORY_WORKOUT = "workout";
+ field @ColorInt public static final int COLOR_DEFAULT = 0; // 0x0
+ field public static final int DEFAULT_ALL = -1; // 0xffffffff
+ field public static final int DEFAULT_LIGHTS = 4; // 0x4
+ field public static final int DEFAULT_SOUND = 1; // 0x1
+ field public static final int DEFAULT_VIBRATE = 2; // 0x2
+ field public static final String EXTRA_ANSWER_COLOR = "android.answerColor";
+ field public static final String EXTRA_ANSWER_INTENT = "android.answerIntent";
+ field public static final String EXTRA_AUDIO_CONTENTS_URI = "android.audioContents";
+ field public static final String EXTRA_BACKGROUND_IMAGE_URI = "android.backgroundImageUri";
+ field public static final String EXTRA_BIG_TEXT = "android.bigText";
+ field public static final String EXTRA_CALL_IS_VIDEO = "android.callIsVideo";
+ field public static final String EXTRA_CALL_PERSON = "android.callPerson";
+ field public static final String EXTRA_CALL_PERSON_COMPAT = "android.callPersonCompat";
+ field public static final String EXTRA_CALL_TYPE = "android.callType";
+ field public static final String EXTRA_CHANNEL_GROUP_ID = "android.intent.extra.CHANNEL_GROUP_ID";
+ field public static final String EXTRA_CHANNEL_ID = "android.intent.extra.CHANNEL_ID";
+ field public static final String EXTRA_CHRONOMETER_COUNT_DOWN = "android.chronometerCountDown";
+ field public static final String EXTRA_COLORIZED = "android.colorized";
+ field public static final String EXTRA_COMPACT_ACTIONS = "android.compactActions";
+ field public static final String EXTRA_COMPAT_TEMPLATE = "androidx.core.app.extra.COMPAT_TEMPLATE";
+ field public static final String EXTRA_CONVERSATION_TITLE = "android.conversationTitle";
+ field public static final String EXTRA_DECLINE_COLOR = "android.declineColor";
+ field public static final String EXTRA_DECLINE_INTENT = "android.declineIntent";
+ field public static final String EXTRA_HANG_UP_INTENT = "android.hangUpIntent";
+ field public static final String EXTRA_HIDDEN_CONVERSATION_TITLE = "android.hiddenConversationTitle";
+ field public static final String EXTRA_HISTORIC_MESSAGES = "android.messages.historic";
+ field public static final String EXTRA_INFO_TEXT = "android.infoText";
+ field public static final String EXTRA_IS_GROUP_CONVERSATION = "android.isGroupConversation";
+ field public static final String EXTRA_LARGE_ICON = "android.largeIcon";
+ field public static final String EXTRA_LARGE_ICON_BIG = "android.largeIcon.big";
+ field public static final String EXTRA_MEDIA_SESSION = "android.mediaSession";
+ field public static final String EXTRA_MESSAGES = "android.messages";
+ field public static final String EXTRA_MESSAGING_STYLE_USER = "android.messagingStyleUser";
+ field public static final String EXTRA_NOTIFICATION_ID = "android.intent.extra.NOTIFICATION_ID";
+ field public static final String EXTRA_NOTIFICATION_TAG = "android.intent.extra.NOTIFICATION_TAG";
+ field @Deprecated public static final String EXTRA_PEOPLE = "android.people";
+ field public static final String EXTRA_PEOPLE_LIST = "android.people.list";
+ field public static final String EXTRA_PICTURE = "android.picture";
+ field public static final String EXTRA_PICTURE_CONTENT_DESCRIPTION = "android.pictureContentDescription";
+ field public static final String EXTRA_PICTURE_ICON = "android.pictureIcon";
+ field public static final String EXTRA_PROGRESS = "android.progress";
+ field public static final String EXTRA_PROGRESS_INDETERMINATE = "android.progressIndeterminate";
+ field public static final String EXTRA_PROGRESS_MAX = "android.progressMax";
+ field public static final String EXTRA_REMOTE_INPUT_HISTORY = "android.remoteInputHistory";
+ field public static final String EXTRA_SELF_DISPLAY_NAME = "android.selfDisplayName";
+ field public static final String EXTRA_SHOW_BIG_PICTURE_WHEN_COLLAPSED = "android.showBigPictureWhenCollapsed";
+ field public static final String EXTRA_SHOW_CHRONOMETER = "android.showChronometer";
+ field public static final String EXTRA_SHOW_WHEN = "android.showWhen";
+ field public static final String EXTRA_SMALL_ICON = "android.icon";
+ field public static final String EXTRA_SUB_TEXT = "android.subText";
+ field public static final String EXTRA_SUMMARY_TEXT = "android.summaryText";
+ field public static final String EXTRA_TEMPLATE = "android.template";
+ field public static final String EXTRA_TEXT = "android.text";
+ field public static final String EXTRA_TEXT_LINES = "android.textLines";
+ field public static final String EXTRA_TITLE = "android.title";
+ field public static final String EXTRA_TITLE_BIG = "android.title.big";
+ field public static final String EXTRA_VERIFICATION_ICON = "android.verificationIcon";
+ field public static final String EXTRA_VERIFICATION_ICON_COMPAT = "android.verificationIconCompat";
+ field public static final String EXTRA_VERIFICATION_TEXT = "android.verificationText";
+ field public static final int FLAG_AUTO_CANCEL = 16; // 0x10
+ field public static final int FLAG_BUBBLE = 4096; // 0x1000
+ field public static final int FLAG_FOREGROUND_SERVICE = 64; // 0x40
+ field public static final int FLAG_GROUP_SUMMARY = 512; // 0x200
+ field @Deprecated public static final int FLAG_HIGH_PRIORITY = 128; // 0x80
+ field public static final int FLAG_INSISTENT = 4; // 0x4
+ field public static final int FLAG_LOCAL_ONLY = 256; // 0x100
+ field public static final int FLAG_NO_CLEAR = 32; // 0x20
+ field public static final int FLAG_ONGOING_EVENT = 2; // 0x2
+ field public static final int FLAG_ONLY_ALERT_ONCE = 8; // 0x8
+ field public static final int FLAG_SHOW_LIGHTS = 1; // 0x1
+ field public static final int FOREGROUND_SERVICE_DEFAULT = 0; // 0x0
+ field public static final int FOREGROUND_SERVICE_DEFERRED = 2; // 0x2
+ field public static final int FOREGROUND_SERVICE_IMMEDIATE = 1; // 0x1
+ field public static final int GROUP_ALERT_ALL = 0; // 0x0
+ field public static final int GROUP_ALERT_CHILDREN = 2; // 0x2
+ field public static final int GROUP_ALERT_SUMMARY = 1; // 0x1
+ field public static final String GROUP_KEY_SILENT = "silent";
+ field public static final String INTENT_CATEGORY_NOTIFICATION_PREFERENCES = "android.intent.category.NOTIFICATION_PREFERENCES";
+ field @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) public static final int MAX_ACTION_BUTTONS = 3; // 0x3
+ field public static final int PRIORITY_DEFAULT = 0; // 0x0
+ field public static final int PRIORITY_HIGH = 1; // 0x1
+ field public static final int PRIORITY_LOW = -1; // 0xffffffff
+ field public static final int PRIORITY_MAX = 2; // 0x2
+ field public static final int PRIORITY_MIN = -2; // 0xfffffffe
+ field public static final int STREAM_DEFAULT = -1; // 0xffffffff
+ field public static final int VISIBILITY_PRIVATE = 0; // 0x0
+ field public static final int VISIBILITY_PUBLIC = 1; // 0x1
+ field public static final int VISIBILITY_SECRET = -1; // 0xffffffff
+ }
+
+ public static class NotificationCompat.Action {
+ ctor public NotificationCompat.Action(int, CharSequence?, android.app.PendingIntent?);
+ ctor public NotificationCompat.Action(androidx.core.graphics.drawable.IconCompat?, CharSequence?, android.app.PendingIntent?);
+ method public android.app.PendingIntent? getActionIntent();
+ method public boolean getAllowGeneratedReplies();
+ method public androidx.core.app.RemoteInput![]? getDataOnlyRemoteInputs();
+ method public android.os.Bundle getExtras();
+ method @Deprecated public int getIcon();
+ method public androidx.core.graphics.drawable.IconCompat? getIconCompat();
+ method public androidx.core.app.RemoteInput![]? getRemoteInputs();
+ method @androidx.core.app.NotificationCompat.Action.SemanticAction public int getSemanticAction();
+ method public boolean getShowsUserInterface();
+ method public CharSequence? getTitle();
+ method public boolean isAuthenticationRequired();
+ method public boolean isContextual();
+ field public static final int SEMANTIC_ACTION_ARCHIVE = 5; // 0x5
+ field public static final int SEMANTIC_ACTION_CALL = 10; // 0xa
+ field public static final int SEMANTIC_ACTION_DELETE = 4; // 0x4
+ field public static final int SEMANTIC_ACTION_MARK_AS_READ = 2; // 0x2
+ field public static final int SEMANTIC_ACTION_MARK_AS_UNREAD = 3; // 0x3
+ field public static final int SEMANTIC_ACTION_MUTE = 6; // 0x6
+ field public static final int SEMANTIC_ACTION_NONE = 0; // 0x0
+ field public static final int SEMANTIC_ACTION_REPLY = 1; // 0x1
+ field public static final int SEMANTIC_ACTION_THUMBS_DOWN = 9; // 0x9
+ field public static final int SEMANTIC_ACTION_THUMBS_UP = 8; // 0x8
+ field public static final int SEMANTIC_ACTION_UNMUTE = 7; // 0x7
+ field public android.app.PendingIntent? actionIntent;
+ field @Deprecated public int icon;
+ field public CharSequence! title;
+ }
+
+ public static final class NotificationCompat.Action.Builder {
+ ctor public NotificationCompat.Action.Builder(androidx.core.graphics.drawable.IconCompat?, CharSequence?, android.app.PendingIntent?);
+ ctor public NotificationCompat.Action.Builder(int, CharSequence?, android.app.PendingIntent?);
+ ctor public NotificationCompat.Action.Builder(androidx.core.app.NotificationCompat.Action);
+ method public androidx.core.app.NotificationCompat.Action.Builder addExtras(android.os.Bundle?);
+ method public androidx.core.app.NotificationCompat.Action.Builder addRemoteInput(androidx.core.app.RemoteInput?);
+ method public androidx.core.app.NotificationCompat.Action build();
+ method public androidx.core.app.NotificationCompat.Action.Builder extend(androidx.core.app.NotificationCompat.Action.Extender);
+ method @RequiresApi(19) @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) public static androidx.core.app.NotificationCompat.Action.Builder fromAndroidAction(android.app.Notification.Action);
+ method public android.os.Bundle getExtras();
+ method public androidx.core.app.NotificationCompat.Action.Builder setAllowGeneratedReplies(boolean);
+ method public androidx.core.app.NotificationCompat.Action.Builder setAuthenticationRequired(boolean);
+ method public androidx.core.app.NotificationCompat.Action.Builder setContextual(boolean);
+ method public androidx.core.app.NotificationCompat.Action.Builder setSemanticAction(@androidx.core.app.NotificationCompat.Action.SemanticAction int);
+ method public androidx.core.app.NotificationCompat.Action.Builder setShowsUserInterface(boolean);
+ }
+
+ public static interface NotificationCompat.Action.Extender {
+ method public androidx.core.app.NotificationCompat.Action.Builder extend(androidx.core.app.NotificationCompat.Action.Builder);
+ }
+
+ @IntDef({androidx.core.app.NotificationCompat.Action.SEMANTIC_ACTION_NONE, androidx.core.app.NotificationCompat.Action.SEMANTIC_ACTION_REPLY, androidx.core.app.NotificationCompat.Action.SEMANTIC_ACTION_MARK_AS_READ, androidx.core.app.NotificationCompat.Action.SEMANTIC_ACTION_MARK_AS_UNREAD, androidx.core.app.NotificationCompat.Action.SEMANTIC_ACTION_DELETE, androidx.core.app.NotificationCompat.Action.SEMANTIC_ACTION_ARCHIVE, androidx.core.app.NotificationCompat.Action.SEMANTIC_ACTION_MUTE, androidx.core.app.NotificationCompat.Action.SEMANTIC_ACTION_UNMUTE, androidx.core.app.NotificationCompat.Action.SEMANTIC_ACTION_THUMBS_UP, androidx.core.app.NotificationCompat.Action.SEMANTIC_ACTION_THUMBS_DOWN, androidx.core.app.NotificationCompat.Action.SEMANTIC_ACTION_CALL}) @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.SOURCE) public static @interface NotificationCompat.Action.SemanticAction {
+ }
+
+ public static final class NotificationCompat.Action.WearableExtender implements androidx.core.app.NotificationCompat.Action.Extender {
+ ctor public NotificationCompat.Action.WearableExtender();
+ ctor public NotificationCompat.Action.WearableExtender(androidx.core.app.NotificationCompat.Action);
+ method public androidx.core.app.NotificationCompat.Action.WearableExtender clone();
+ method public androidx.core.app.NotificationCompat.Action.Builder extend(androidx.core.app.NotificationCompat.Action.Builder);
+ method @Deprecated public CharSequence? getCancelLabel();
+ method @Deprecated public CharSequence? getConfirmLabel();
+ method public boolean getHintDisplayActionInline();
+ method public boolean getHintLaunchesActivity();
+ method @Deprecated public CharSequence? getInProgressLabel();
+ method public boolean isAvailableOffline();
+ method public androidx.core.app.NotificationCompat.Action.WearableExtender setAvailableOffline(boolean);
+ method @Deprecated public androidx.core.app.NotificationCompat.Action.WearableExtender setCancelLabel(CharSequence?);
+ method @Deprecated public androidx.core.app.NotificationCompat.Action.WearableExtender setConfirmLabel(CharSequence?);
+ method public androidx.core.app.NotificationCompat.Action.WearableExtender setHintDisplayActionInline(boolean);
+ method public androidx.core.app.NotificationCompat.Action.WearableExtender setHintLaunchesActivity(boolean);
+ method @Deprecated public androidx.core.app.NotificationCompat.Action.WearableExtender setInProgressLabel(CharSequence?);
+ }
+
+ @IntDef({androidx.core.app.NotificationCompat.BADGE_ICON_NONE, androidx.core.app.NotificationCompat.BADGE_ICON_SMALL, androidx.core.app.NotificationCompat.BADGE_ICON_LARGE}) @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.SOURCE) public static @interface NotificationCompat.BadgeIconType {
+ }
+
+ public static class NotificationCompat.BigPictureStyle extends androidx.core.app.NotificationCompat.Style {
+ ctor public NotificationCompat.BigPictureStyle();
+ ctor public NotificationCompat.BigPictureStyle(androidx.core.app.NotificationCompat.Builder?);
+ method public androidx.core.app.NotificationCompat.BigPictureStyle bigLargeIcon(android.graphics.Bitmap?);
+ method @RequiresApi(23) public androidx.core.app.NotificationCompat.BigPictureStyle bigLargeIcon(android.graphics.drawable.Icon?);
+ method public androidx.core.app.NotificationCompat.BigPictureStyle bigPicture(android.graphics.Bitmap?);
+ method @RequiresApi(31) public androidx.core.app.NotificationCompat.BigPictureStyle bigPicture(android.graphics.drawable.Icon?);
+ method @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) public static androidx.core.graphics.drawable.IconCompat? getPictureIcon(android.os.Bundle?);
+ method public androidx.core.app.NotificationCompat.BigPictureStyle setBigContentTitle(CharSequence?);
+ method @RequiresApi(31) public androidx.core.app.NotificationCompat.BigPictureStyle setContentDescription(CharSequence?);
+ method public androidx.core.app.NotificationCompat.BigPictureStyle setSummaryText(CharSequence?);
+ method @RequiresApi(31) public androidx.core.app.NotificationCompat.BigPictureStyle showBigPictureWhenCollapsed(boolean);
+ }
+
+ public static class NotificationCompat.BigTextStyle extends androidx.core.app.NotificationCompat.Style {
+ ctor public NotificationCompat.BigTextStyle();
+ ctor public NotificationCompat.BigTextStyle(androidx.core.app.NotificationCompat.Builder?);
+ method public androidx.core.app.NotificationCompat.BigTextStyle bigText(CharSequence?);
+ method public androidx.core.app.NotificationCompat.BigTextStyle setBigContentTitle(CharSequence?);
+ method public androidx.core.app.NotificationCompat.BigTextStyle setSummaryText(CharSequence?);
+ }
+
+ public static final class NotificationCompat.BubbleMetadata {
+ method public static androidx.core.app.NotificationCompat.BubbleMetadata? fromPlatform(android.app.Notification.BubbleMetadata?);
+ method public boolean getAutoExpandBubble();
+ method public android.app.PendingIntent? getDeleteIntent();
+ method @Dimension(unit=androidx.annotation.Dimension.DP) public int getDesiredHeight();
+ method @DimenRes public int getDesiredHeightResId();
+ method public androidx.core.graphics.drawable.IconCompat? getIcon();
+ method public android.app.PendingIntent? getIntent();
+ method public String? getShortcutId();
+ method public boolean isNotificationSuppressed();
+ method @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) public void setFlags(int);
+ method public static android.app.Notification.BubbleMetadata? toPlatform(androidx.core.app.NotificationCompat.BubbleMetadata?);
+ }
+
+ public static final class NotificationCompat.BubbleMetadata.Builder {
+ ctor @Deprecated public NotificationCompat.BubbleMetadata.Builder();
+ ctor @RequiresApi(30) public NotificationCompat.BubbleMetadata.Builder(String);
+ ctor public NotificationCompat.BubbleMetadata.Builder(android.app.PendingIntent, androidx.core.graphics.drawable.IconCompat);
+ method public androidx.core.app.NotificationCompat.BubbleMetadata build();
+ method public androidx.core.app.NotificationCompat.BubbleMetadata.Builder setAutoExpandBubble(boolean);
+ method public androidx.core.app.NotificationCompat.BubbleMetadata.Builder setDeleteIntent(android.app.PendingIntent?);
+ method public androidx.core.app.NotificationCompat.BubbleMetadata.Builder setDesiredHeight(@Dimension(unit=androidx.annotation.Dimension.DP) int);
+ method public androidx.core.app.NotificationCompat.BubbleMetadata.Builder setDesiredHeightResId(@DimenRes int);
+ method public androidx.core.app.NotificationCompat.BubbleMetadata.Builder setIcon(androidx.core.graphics.drawable.IconCompat);
+ method public androidx.core.app.NotificationCompat.BubbleMetadata.Builder setIntent(android.app.PendingIntent);
+ method public androidx.core.app.NotificationCompat.BubbleMetadata.Builder setSuppressNotification(boolean);
+ }
+
+ public static class NotificationCompat.Builder {
+ ctor @RequiresApi(19) public NotificationCompat.Builder(android.content.Context, android.app.Notification);
+ ctor public NotificationCompat.Builder(android.content.Context, String);
+ ctor @Deprecated public NotificationCompat.Builder(android.content.Context);
+ method public androidx.core.app.NotificationCompat.Builder addAction(int, CharSequence?, android.app.PendingIntent?);
+ method public androidx.core.app.NotificationCompat.Builder addAction(androidx.core.app.NotificationCompat.Action?);
+ method public androidx.core.app.NotificationCompat.Builder addExtras(android.os.Bundle?);
+ method @RequiresApi(21) public androidx.core.app.NotificationCompat.Builder addInvisibleAction(int, CharSequence?, android.app.PendingIntent?);
+ method @RequiresApi(21) public androidx.core.app.NotificationCompat.Builder addInvisibleAction(androidx.core.app.NotificationCompat.Action?);
+ method @Deprecated public androidx.core.app.NotificationCompat.Builder addPerson(String?);
+ method public androidx.core.app.NotificationCompat.Builder addPerson(androidx.core.app.Person?);
+ method public android.app.Notification build();
+ method public androidx.core.app.NotificationCompat.Builder clearActions();
+ method public androidx.core.app.NotificationCompat.Builder clearInvisibleActions();
+ method public androidx.core.app.NotificationCompat.Builder clearPeople();
+ method public android.widget.RemoteViews? createBigContentView();
+ method public android.widget.RemoteViews? createContentView();
+ method public android.widget.RemoteViews? createHeadsUpContentView();
+ method public androidx.core.app.NotificationCompat.Builder extend(androidx.core.app.NotificationCompat.Extender);
+ method @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) public android.widget.RemoteViews! getBigContentView();
+ method @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) public androidx.core.app.NotificationCompat.BubbleMetadata? getBubbleMetadata();
+ method @ColorInt @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) public int getColor();
+ method @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) public android.widget.RemoteViews! getContentView();
+ method public android.os.Bundle getExtras();
+ method @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) public int getForegroundServiceBehavior();
+ method @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) public android.widget.RemoteViews! getHeadsUpContentView();
+ method @Deprecated public android.app.Notification getNotification();
+ method @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) public int getPriority();
+ method @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) public long getWhenIfShowing();
+ method protected static CharSequence? limitCharSequenceLength(CharSequence?);
+ method public androidx.core.app.NotificationCompat.Builder setAllowSystemGeneratedContextualActions(boolean);
+ method public androidx.core.app.NotificationCompat.Builder setAutoCancel(boolean);
+ method public androidx.core.app.NotificationCompat.Builder setBadgeIconType(@androidx.core.app.NotificationCompat.BadgeIconType int);
+ method public androidx.core.app.NotificationCompat.Builder setBubbleMetadata(androidx.core.app.NotificationCompat.BubbleMetadata?);
+ method public androidx.core.app.NotificationCompat.Builder setCategory(String?);
+ method public androidx.core.app.NotificationCompat.Builder setChannelId(String);
+ method @RequiresApi(24) public androidx.core.app.NotificationCompat.Builder setChronometerCountDown(boolean);
+ method public androidx.core.app.NotificationCompat.Builder setColor(@ColorInt int);
+ method public androidx.core.app.NotificationCompat.Builder setColorized(boolean);
+ method public androidx.core.app.NotificationCompat.Builder setContent(android.widget.RemoteViews?);
+ method public androidx.core.app.NotificationCompat.Builder setContentInfo(CharSequence?);
+ method public androidx.core.app.NotificationCompat.Builder setContentIntent(android.app.PendingIntent?);
+ method public androidx.core.app.NotificationCompat.Builder setContentText(CharSequence?);
+ method public androidx.core.app.NotificationCompat.Builder setContentTitle(CharSequence?);
+ method public androidx.core.app.NotificationCompat.Builder setCustomBigContentView(android.widget.RemoteViews?);
+ method public androidx.core.app.NotificationCompat.Builder setCustomContentView(android.widget.RemoteViews?);
+ method public androidx.core.app.NotificationCompat.Builder setCustomHeadsUpContentView(android.widget.RemoteViews?);
+ method public androidx.core.app.NotificationCompat.Builder setDefaults(int);
+ method public androidx.core.app.NotificationCompat.Builder setDeleteIntent(android.app.PendingIntent?);
+ method public androidx.core.app.NotificationCompat.Builder setExtras(android.os.Bundle?);
+ method public androidx.core.app.NotificationCompat.Builder setForegroundServiceBehavior(@androidx.core.app.NotificationCompat.ServiceNotificationBehavior int);
+ method public androidx.core.app.NotificationCompat.Builder setFullScreenIntent(android.app.PendingIntent?, boolean);
+ method public androidx.core.app.NotificationCompat.Builder setGroup(String?);
+ method public androidx.core.app.NotificationCompat.Builder setGroupAlertBehavior(@androidx.core.app.NotificationCompat.GroupAlertBehavior int);
+ method public androidx.core.app.NotificationCompat.Builder setGroupSummary(boolean);
+ method public androidx.core.app.NotificationCompat.Builder setLargeIcon(android.graphics.Bitmap?);
+ method public androidx.core.app.NotificationCompat.Builder setLights(@ColorInt int, int, int);
+ method public androidx.core.app.NotificationCompat.Builder setLocalOnly(boolean);
+ method public androidx.core.app.NotificationCompat.Builder setLocusId(androidx.core.content.LocusIdCompat?);
+ method @Deprecated public androidx.core.app.NotificationCompat.Builder setNotificationSilent();
+ method public androidx.core.app.NotificationCompat.Builder setNumber(int);
+ method public androidx.core.app.NotificationCompat.Builder setOngoing(boolean);
+ method public androidx.core.app.NotificationCompat.Builder setOnlyAlertOnce(boolean);
+ method public androidx.core.app.NotificationCompat.Builder setPriority(int);
+ method public androidx.core.app.NotificationCompat.Builder setProgress(int, int, boolean);
+ method public androidx.core.app.NotificationCompat.Builder setPublicVersion(android.app.Notification?);
+ method public androidx.core.app.NotificationCompat.Builder setRemoteInputHistory(CharSequence![]?);
+ method public androidx.core.app.NotificationCompat.Builder setSettingsText(CharSequence?);
+ method public androidx.core.app.NotificationCompat.Builder setShortcutId(String?);
+ method public androidx.core.app.NotificationCompat.Builder setShortcutInfo(androidx.core.content.pm.ShortcutInfoCompat?);
+ method public androidx.core.app.NotificationCompat.Builder setShowWhen(boolean);
+ method public androidx.core.app.NotificationCompat.Builder setSilent(boolean);
+ method @RequiresApi(23) public androidx.core.app.NotificationCompat.Builder setSmallIcon(androidx.core.graphics.drawable.IconCompat);
+ method public androidx.core.app.NotificationCompat.Builder setSmallIcon(int);
+ method public androidx.core.app.NotificationCompat.Builder setSmallIcon(int, int);
+ method public androidx.core.app.NotificationCompat.Builder setSortKey(String?);
+ method public androidx.core.app.NotificationCompat.Builder setSound(android.net.Uri?);
+ method public androidx.core.app.NotificationCompat.Builder setSound(android.net.Uri?, @androidx.core.app.NotificationCompat.StreamType int);
+ method public androidx.core.app.NotificationCompat.Builder setStyle(androidx.core.app.NotificationCompat.Style?);
+ method public androidx.core.app.NotificationCompat.Builder setSubText(CharSequence?);
+ method public androidx.core.app.NotificationCompat.Builder setTicker(CharSequence?);
+ method @Deprecated public androidx.core.app.NotificationCompat.Builder setTicker(CharSequence?, android.widget.RemoteViews?);
+ method public androidx.core.app.NotificationCompat.Builder setTimeoutAfter(long);
+ method public androidx.core.app.NotificationCompat.Builder setUsesChronometer(boolean);
+ method public androidx.core.app.NotificationCompat.Builder setVibrate(long[]?);
+ method public androidx.core.app.NotificationCompat.Builder setVisibility(@androidx.core.app.NotificationCompat.NotificationVisibility int);
+ method public androidx.core.app.NotificationCompat.Builder setWhen(long);
+ field @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) public java.util.ArrayList<androidx.core.app.NotificationCompat.Action!>! mActions;
+ field @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) public android.content.Context! mContext;
+ field @Deprecated public java.util.ArrayList<java.lang.String!>! mPeople;
+ field @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) public java.util.ArrayList<androidx.core.app.Person!> mPersonList;
+ }
+
+ public static class NotificationCompat.CallStyle extends androidx.core.app.NotificationCompat.Style {
+ ctor public NotificationCompat.CallStyle();
+ ctor public NotificationCompat.CallStyle(androidx.core.app.NotificationCompat.Builder?);
+ method public static androidx.core.app.NotificationCompat.CallStyle forIncomingCall(androidx.core.app.Person, android.app.PendingIntent, android.app.PendingIntent);
+ method public static androidx.core.app.NotificationCompat.CallStyle forOngoingCall(androidx.core.app.Person, android.app.PendingIntent);
+ method public static androidx.core.app.NotificationCompat.CallStyle forScreeningCall(androidx.core.app.Person, android.app.PendingIntent, android.app.PendingIntent);
+ method @RequiresApi(20) @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) public java.util.ArrayList<androidx.core.app.NotificationCompat.Action!> getActionsListWithSystemActions();
+ method public androidx.core.app.NotificationCompat.CallStyle setAnswerButtonColorHint(@ColorInt int);
+ method public androidx.core.app.NotificationCompat.CallStyle setDeclineButtonColorHint(@ColorInt int);
+ method public androidx.core.app.NotificationCompat.CallStyle setIsVideo(boolean);
+ method @RequiresApi(23) public androidx.core.app.NotificationCompat.CallStyle setVerificationIcon(android.graphics.drawable.Icon?);
+ method public androidx.core.app.NotificationCompat.CallStyle setVerificationIcon(android.graphics.Bitmap?);
+ method public androidx.core.app.NotificationCompat.CallStyle setVerificationText(CharSequence?);
+ field public static final int CALL_TYPE_INCOMING = 1; // 0x1
+ field public static final int CALL_TYPE_ONGOING = 2; // 0x2
+ field public static final int CALL_TYPE_SCREENING = 3; // 0x3
+ field public static final int CALL_TYPE_UNKNOWN = 0; // 0x0
+ }
+
+ @IntDef({androidx.core.app.NotificationCompat.CallStyle.CALL_TYPE_UNKNOWN, androidx.core.app.NotificationCompat.CallStyle.CALL_TYPE_INCOMING, androidx.core.app.NotificationCompat.CallStyle.CALL_TYPE_ONGOING, androidx.core.app.NotificationCompat.CallStyle.CALL_TYPE_SCREENING}) @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.SOURCE) public static @interface NotificationCompat.CallStyle.CallType {
+ }
+
+ public static final class NotificationCompat.CarExtender implements androidx.core.app.NotificationCompat.Extender {
+ ctor public NotificationCompat.CarExtender();
+ ctor public NotificationCompat.CarExtender(android.app.Notification);
+ method public androidx.core.app.NotificationCompat.Builder extend(androidx.core.app.NotificationCompat.Builder);
+ method @ColorInt public int getColor();
+ method public android.graphics.Bitmap? getLargeIcon();
+ method @Deprecated public androidx.core.app.NotificationCompat.CarExtender.UnreadConversation? getUnreadConversation();
+ method public androidx.core.app.NotificationCompat.CarExtender setColor(@ColorInt int);
+ method public androidx.core.app.NotificationCompat.CarExtender setLargeIcon(android.graphics.Bitmap?);
+ method @Deprecated public androidx.core.app.NotificationCompat.CarExtender setUnreadConversation(androidx.core.app.NotificationCompat.CarExtender.UnreadConversation?);
+ }
+
+ @Deprecated public static class NotificationCompat.CarExtender.UnreadConversation {
+ method @Deprecated public long getLatestTimestamp();
+ method @Deprecated public String![]? getMessages();
+ method @Deprecated public String? getParticipant();
+ method @Deprecated public String![]? getParticipants();
+ method @Deprecated public android.app.PendingIntent? getReadPendingIntent();
+ method @Deprecated public androidx.core.app.RemoteInput? getRemoteInput();
+ method @Deprecated public android.app.PendingIntent? getReplyPendingIntent();
+ }
+
+ @Deprecated public static class NotificationCompat.CarExtender.UnreadConversation.Builder {
+ ctor @Deprecated public NotificationCompat.CarExtender.UnreadConversation.Builder(String);
+ method @Deprecated public androidx.core.app.NotificationCompat.CarExtender.UnreadConversation.Builder addMessage(String?);
+ method @Deprecated public androidx.core.app.NotificationCompat.CarExtender.UnreadConversation build();
+ method @Deprecated public androidx.core.app.NotificationCompat.CarExtender.UnreadConversation.Builder setLatestTimestamp(long);
+ method @Deprecated public androidx.core.app.NotificationCompat.CarExtender.UnreadConversation.Builder setReadPendingIntent(android.app.PendingIntent?);
+ method @Deprecated public androidx.core.app.NotificationCompat.CarExtender.UnreadConversation.Builder setReplyAction(android.app.PendingIntent?, androidx.core.app.RemoteInput?);
+ }
+
+ public static class NotificationCompat.DecoratedCustomViewStyle extends androidx.core.app.NotificationCompat.Style {
+ ctor public NotificationCompat.DecoratedCustomViewStyle();
+ }
+
+ public static interface NotificationCompat.Extender {
+ method public androidx.core.app.NotificationCompat.Builder extend(androidx.core.app.NotificationCompat.Builder);
+ }
+
+ @IntDef({androidx.core.app.NotificationCompat.GROUP_ALERT_ALL, androidx.core.app.NotificationCompat.GROUP_ALERT_SUMMARY, androidx.core.app.NotificationCompat.GROUP_ALERT_CHILDREN}) @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.SOURCE) public static @interface NotificationCompat.GroupAlertBehavior {
+ }
+
+ public static class NotificationCompat.InboxStyle extends androidx.core.app.NotificationCompat.Style {
+ ctor public NotificationCompat.InboxStyle();
+ ctor public NotificationCompat.InboxStyle(androidx.core.app.NotificationCompat.Builder?);
+ method public androidx.core.app.NotificationCompat.InboxStyle addLine(CharSequence?);
+ method public androidx.core.app.NotificationCompat.InboxStyle setBigContentTitle(CharSequence?);
+ method public androidx.core.app.NotificationCompat.InboxStyle setSummaryText(CharSequence?);
+ }
+
+ public static class NotificationCompat.MessagingStyle extends androidx.core.app.NotificationCompat.Style {
+ ctor @Deprecated public NotificationCompat.MessagingStyle(CharSequence);
+ ctor public NotificationCompat.MessagingStyle(androidx.core.app.Person);
+ method public androidx.core.app.NotificationCompat.MessagingStyle addHistoricMessage(androidx.core.app.NotificationCompat.MessagingStyle.Message?);
+ method @Deprecated public androidx.core.app.NotificationCompat.MessagingStyle addMessage(CharSequence?, long, CharSequence?);
+ method public androidx.core.app.NotificationCompat.MessagingStyle addMessage(CharSequence?, long, androidx.core.app.Person?);
+ method public androidx.core.app.NotificationCompat.MessagingStyle addMessage(androidx.core.app.NotificationCompat.MessagingStyle.Message?);
+ method public static androidx.core.app.NotificationCompat.MessagingStyle? extractMessagingStyleFromNotification(android.app.Notification);
+ method public CharSequence? getConversationTitle();
+ method public java.util.List<androidx.core.app.NotificationCompat.MessagingStyle.Message!> getHistoricMessages();
+ method public java.util.List<androidx.core.app.NotificationCompat.MessagingStyle.Message!> getMessages();
+ method public androidx.core.app.Person getUser();
+ method @Deprecated public CharSequence? getUserDisplayName();
+ method public boolean isGroupConversation();
+ method public androidx.core.app.NotificationCompat.MessagingStyle setConversationTitle(CharSequence?);
+ method public androidx.core.app.NotificationCompat.MessagingStyle setGroupConversation(boolean);
+ field public static final int MAXIMUM_RETAINED_MESSAGES = 25; // 0x19
+ }
+
+ public static final class NotificationCompat.MessagingStyle.Message {
+ ctor public NotificationCompat.MessagingStyle.Message(CharSequence?, long, androidx.core.app.Person?);
+ ctor @Deprecated public NotificationCompat.MessagingStyle.Message(CharSequence?, long, CharSequence?);
+ method public String? getDataMimeType();
+ method public android.net.Uri? getDataUri();
+ method public android.os.Bundle getExtras();
+ method public androidx.core.app.Person? getPerson();
+ method @Deprecated public CharSequence? getSender();
+ method public CharSequence? getText();
+ method public long getTimestamp();
+ method public androidx.core.app.NotificationCompat.MessagingStyle.Message setData(String?, android.net.Uri?);
+ }
+
+ @IntDef({androidx.core.app.NotificationCompat.VISIBILITY_PUBLIC, androidx.core.app.NotificationCompat.VISIBILITY_PRIVATE, androidx.core.app.NotificationCompat.VISIBILITY_SECRET}) @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.SOURCE) public static @interface NotificationCompat.NotificationVisibility {
+ }
+
+ @IntDef({androidx.core.app.NotificationCompat.FOREGROUND_SERVICE_DEFAULT, androidx.core.app.NotificationCompat.FOREGROUND_SERVICE_IMMEDIATE, androidx.core.app.NotificationCompat.FOREGROUND_SERVICE_DEFERRED}) @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.SOURCE) public static @interface NotificationCompat.ServiceNotificationBehavior {
+ }
+
+ @IntDef({android.media.AudioManager.STREAM_VOICE_CALL, android.media.AudioManager.STREAM_SYSTEM, android.media.AudioManager.STREAM_RING, android.media.AudioManager.STREAM_MUSIC, android.media.AudioManager.STREAM_ALARM, android.media.AudioManager.STREAM_NOTIFICATION, android.media.AudioManager.STREAM_DTMF, android.media.AudioManager.STREAM_ACCESSIBILITY}) @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.SOURCE) public static @interface NotificationCompat.StreamType {
+ }
+
+ public abstract static class NotificationCompat.Style {
+ ctor public NotificationCompat.Style();
+ method @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) public void addCompatExtras(android.os.Bundle);
+ method @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) public void apply(androidx.core.app.NotificationBuilderWithBuilderAccessor!);
+ method @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) public android.widget.RemoteViews applyStandardTemplate(boolean, int, boolean);
+ method public android.app.Notification? build();
+ method @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) public void buildIntoRemoteViews(android.widget.RemoteViews!, android.widget.RemoteViews!);
+ method @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) protected void clearCompatExtraKeys(android.os.Bundle);
+ method @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) public android.graphics.Bitmap! createColoredBitmap(int, int);
+ method @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) public boolean displayCustomViewInline();
+ method @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) public static androidx.core.app.NotificationCompat.Style? extractStyleFromNotification(android.app.Notification);
+ method @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) protected String? getClassName();
+ method @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) public android.widget.RemoteViews! makeBigContentView(androidx.core.app.NotificationBuilderWithBuilderAccessor!);
+ method @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) public android.widget.RemoteViews! makeContentView(androidx.core.app.NotificationBuilderWithBuilderAccessor!);
+ method @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) public android.widget.RemoteViews! makeHeadsUpContentView(androidx.core.app.NotificationBuilderWithBuilderAccessor!);
+ method @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) protected void restoreFromCompatExtras(android.os.Bundle);
+ method public void setBuilder(androidx.core.app.NotificationCompat.Builder?);
+ field @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) protected androidx.core.app.NotificationCompat.Builder! mBuilder;
+ }
+
+ public static final class NotificationCompat.WearableExtender implements androidx.core.app.NotificationCompat.Extender {
+ ctor public NotificationCompat.WearableExtender();
+ ctor public NotificationCompat.WearableExtender(android.app.Notification);
+ method public androidx.core.app.NotificationCompat.WearableExtender addAction(androidx.core.app.NotificationCompat.Action);
+ method public androidx.core.app.NotificationCompat.WearableExtender addActions(java.util.List<androidx.core.app.NotificationCompat.Action!>);
+ method @Deprecated public androidx.core.app.NotificationCompat.WearableExtender addPage(android.app.Notification);
+ method @Deprecated public androidx.core.app.NotificationCompat.WearableExtender addPages(java.util.List<android.app.Notification!>);
+ method public androidx.core.app.NotificationCompat.WearableExtender clearActions();
+ method @Deprecated public androidx.core.app.NotificationCompat.WearableExtender clearPages();
+ method public androidx.core.app.NotificationCompat.WearableExtender clone();
+ method public androidx.core.app.NotificationCompat.Builder extend(androidx.core.app.NotificationCompat.Builder);
+ method public java.util.List<androidx.core.app.NotificationCompat.Action!> getActions();
+ method @Deprecated public android.graphics.Bitmap? getBackground();
+ method public String? getBridgeTag();
+ method public int getContentAction();
+ method @Deprecated public int getContentIcon();
+ method @Deprecated public int getContentIconGravity();
+ method public boolean getContentIntentAvailableOffline();
+ method @Deprecated public int getCustomContentHeight();
+ method @Deprecated public int getCustomSizePreset();
+ method public String? getDismissalId();
+ method @Deprecated public android.app.PendingIntent? getDisplayIntent();
+ method @Deprecated public int getGravity();
+ method @Deprecated public boolean getHintAmbientBigPicture();
+ method @Deprecated public boolean getHintAvoidBackgroundClipping();
+ method public boolean getHintContentIntentLaunchesActivity();
+ method @Deprecated public boolean getHintHideIcon();
+ method @Deprecated public int getHintScreenTimeout();
+ method @Deprecated public boolean getHintShowBackgroundOnly();
+ method @Deprecated public java.util.List<android.app.Notification!> getPages();
+ method public boolean getStartScrollBottom();
+ method @Deprecated public androidx.core.app.NotificationCompat.WearableExtender setBackground(android.graphics.Bitmap?);
+ method public androidx.core.app.NotificationCompat.WearableExtender setBridgeTag(String?);
+ method public androidx.core.app.NotificationCompat.WearableExtender setContentAction(int);
+ method @Deprecated public androidx.core.app.NotificationCompat.WearableExtender setContentIcon(int);
+ method @Deprecated public androidx.core.app.NotificationCompat.WearableExtender setContentIconGravity(int);
+ method public androidx.core.app.NotificationCompat.WearableExtender setContentIntentAvailableOffline(boolean);
+ method @Deprecated public androidx.core.app.NotificationCompat.WearableExtender setCustomContentHeight(int);
+ method @Deprecated public androidx.core.app.NotificationCompat.WearableExtender setCustomSizePreset(int);
+ method public androidx.core.app.NotificationCompat.WearableExtender setDismissalId(String?);
+ method @Deprecated public androidx.core.app.NotificationCompat.WearableExtender setDisplayIntent(android.app.PendingIntent?);
+ method @Deprecated public androidx.core.app.NotificationCompat.WearableExtender setGravity(int);
+ method @Deprecated public androidx.core.app.NotificationCompat.WearableExtender setHintAmbientBigPicture(boolean);
+ method @Deprecated public androidx.core.app.NotificationCompat.WearableExtender setHintAvoidBackgroundClipping(boolean);
+ method public androidx.core.app.NotificationCompat.WearableExtender setHintContentIntentLaunchesActivity(boolean);
+ method @Deprecated public androidx.core.app.NotificationCompat.WearableExtender setHintHideIcon(boolean);
+ method @Deprecated public androidx.core.app.NotificationCompat.WearableExtender setHintScreenTimeout(int);
+ method @Deprecated public androidx.core.app.NotificationCompat.WearableExtender setHintShowBackgroundOnly(boolean);
+ method public androidx.core.app.NotificationCompat.WearableExtender setStartScrollBottom(boolean);
+ field @Deprecated public static final int SCREEN_TIMEOUT_LONG = -1; // 0xffffffff
+ field @Deprecated public static final int SCREEN_TIMEOUT_SHORT = 0; // 0x0
+ field @Deprecated public static final int SIZE_DEFAULT = 0; // 0x0
+ field @Deprecated public static final int SIZE_FULL_SCREEN = 5; // 0x5
+ field @Deprecated public static final int SIZE_LARGE = 4; // 0x4
+ field @Deprecated public static final int SIZE_MEDIUM = 3; // 0x3
+ field @Deprecated public static final int SIZE_SMALL = 2; // 0x2
+ field @Deprecated public static final int SIZE_XSMALL = 1; // 0x1
+ field public static final int UNSET_ACTION_INDEX = -1; // 0xffffffff
+ }
+
+ public final class NotificationCompatExtras {
+ field public static final String EXTRA_ACTION_EXTRAS = "android.support.actionExtras";
+ field public static final String EXTRA_GROUP_KEY = "android.support.groupKey";
+ field public static final String EXTRA_GROUP_SUMMARY = "android.support.isGroupSummary";
+ field public static final String EXTRA_LOCAL_ONLY = "android.support.localOnly";
+ field public static final String EXTRA_REMOTE_INPUTS = "android.support.remoteInputs";
+ field public static final String EXTRA_SORT_KEY = "android.support.sortKey";
+ }
+
+ public abstract class NotificationCompatSideChannelService extends android.app.Service {
+ ctor public NotificationCompatSideChannelService();
+ method public abstract void cancel(String!, int, String!);
+ method public abstract void cancelAll(String!);
+ method public abstract void notify(String!, int, String!, android.app.Notification!);
+ method public android.os.IBinder! onBind(android.content.Intent!);
+ }
+
+ public final class NotificationManagerCompat {
+ method public boolean areNotificationsEnabled();
+ method public void cancel(int);
+ method public void cancel(String?, int);
+ method public void cancelAll();
+ method public void createNotificationChannel(android.app.NotificationChannel);
+ method public void createNotificationChannel(androidx.core.app.NotificationChannelCompat);
+ method public void createNotificationChannelGroup(android.app.NotificationChannelGroup);
+ method public void createNotificationChannelGroup(androidx.core.app.NotificationChannelGroupCompat);
+ method public void createNotificationChannelGroups(java.util.List<android.app.NotificationChannelGroup!>);
+ method public void createNotificationChannelGroupsCompat(java.util.List<androidx.core.app.NotificationChannelGroupCompat!>);
+ method public void createNotificationChannels(java.util.List<android.app.NotificationChannel!>);
+ method public void createNotificationChannelsCompat(java.util.List<androidx.core.app.NotificationChannelCompat!>);
+ method public void deleteNotificationChannel(String);
+ method public void deleteNotificationChannelGroup(String);
+ method public void deleteUnlistedNotificationChannels(java.util.Collection<java.lang.String!>);
+ method public static androidx.core.app.NotificationManagerCompat from(android.content.Context);
+ method public static java.util.Set<java.lang.String!> getEnabledListenerPackages(android.content.Context);
+ method public int getImportance();
+ method public android.app.NotificationChannel? getNotificationChannel(String);
+ method public android.app.NotificationChannel? getNotificationChannel(String, String);
+ method public androidx.core.app.NotificationChannelCompat? getNotificationChannelCompat(String);
+ method public androidx.core.app.NotificationChannelCompat? getNotificationChannelCompat(String, String);
+ method public android.app.NotificationChannelGroup? getNotificationChannelGroup(String);
+ method public androidx.core.app.NotificationChannelGroupCompat? getNotificationChannelGroupCompat(String);
+ method public java.util.List<android.app.NotificationChannelGroup!> getNotificationChannelGroups();
+ method public java.util.List<androidx.core.app.NotificationChannelGroupCompat!> getNotificationChannelGroupsCompat();
+ method public java.util.List<android.app.NotificationChannel!> getNotificationChannels();
+ method public java.util.List<androidx.core.app.NotificationChannelCompat!> getNotificationChannelsCompat();
+ method @RequiresPermission(android.Manifest.permission.POST_NOTIFICATIONS) public void notify(int, android.app.Notification);
+ method @RequiresPermission(android.Manifest.permission.POST_NOTIFICATIONS) public void notify(String?, int, android.app.Notification);
+ field public static final String ACTION_BIND_SIDE_CHANNEL = "android.support.BIND_NOTIFICATION_SIDE_CHANNEL";
+ field public static final String EXTRA_USE_SIDE_CHANNEL = "android.support.useSideChannel";
+ field public static final int IMPORTANCE_DEFAULT = 3; // 0x3
+ field public static final int IMPORTANCE_HIGH = 4; // 0x4
+ field public static final int IMPORTANCE_LOW = 2; // 0x2
+ field public static final int IMPORTANCE_MAX = 5; // 0x5
+ field public static final int IMPORTANCE_MIN = 1; // 0x1
+ field public static final int IMPORTANCE_NONE = 0; // 0x0
+ field public static final int IMPORTANCE_UNSPECIFIED = -1000; // 0xfffffc18
+ }
+
+ public interface OnMultiWindowModeChangedProvider {
+ method public void addOnMultiWindowModeChangedListener(androidx.core.util.Consumer<androidx.core.app.MultiWindowModeChangedInfo!>);
+ method public void removeOnMultiWindowModeChangedListener(androidx.core.util.Consumer<androidx.core.app.MultiWindowModeChangedInfo!>);
+ }
+
+ public interface OnNewIntentProvider {
+ method public void addOnNewIntentListener(androidx.core.util.Consumer<android.content.Intent!>);
+ method public void removeOnNewIntentListener(androidx.core.util.Consumer<android.content.Intent!>);
+ }
+
+ public interface OnPictureInPictureModeChangedProvider {
+ method public void addOnPictureInPictureModeChangedListener(androidx.core.util.Consumer<androidx.core.app.PictureInPictureModeChangedInfo!>);
+ method public void removeOnPictureInPictureModeChangedListener(androidx.core.util.Consumer<androidx.core.app.PictureInPictureModeChangedInfo!>);
+ }
+
+ public final class PendingIntentCompat {
+ method public static android.app.PendingIntent getActivities(android.content.Context, int, android.content.Intent![], int, android.os.Bundle, boolean);
+ method public static android.app.PendingIntent getActivities(android.content.Context, int, android.content.Intent![], int, boolean);
+ method public static android.app.PendingIntent getActivity(android.content.Context, int, android.content.Intent, int, boolean);
+ method public static android.app.PendingIntent getActivity(android.content.Context, int, android.content.Intent, int, android.os.Bundle, boolean);
+ method public static android.app.PendingIntent getBroadcast(android.content.Context, int, android.content.Intent, int, boolean);
+ method @RequiresApi(26) public static android.app.PendingIntent getForegroundService(android.content.Context, int, android.content.Intent, int, boolean);
+ method public static android.app.PendingIntent getService(android.content.Context, int, android.content.Intent, int, boolean);
+ }
+
+ public class Person {
+ method @RequiresApi(28) @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) public static androidx.core.app.Person fromAndroidPerson(android.app.Person);
+ method public static androidx.core.app.Person fromBundle(android.os.Bundle);
+ method @RequiresApi(22) @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) public static androidx.core.app.Person fromPersistableBundle(android.os.PersistableBundle);
+ method public androidx.core.graphics.drawable.IconCompat? getIcon();
+ method public String? getKey();
+ method public CharSequence? getName();
+ method public String? getUri();
+ method public boolean isBot();
+ method public boolean isImportant();
+ method @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) public String resolveToLegacyUri();
+ method @RequiresApi(28) @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) public android.app.Person toAndroidPerson();
+ method public androidx.core.app.Person.Builder toBuilder();
+ method public android.os.Bundle toBundle();
+ method @RequiresApi(22) @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) public android.os.PersistableBundle toPersistableBundle();
+ }
+
+ public static class Person.Builder {
+ ctor public Person.Builder();
+ method public androidx.core.app.Person build();
+ method public androidx.core.app.Person.Builder setBot(boolean);
+ method public androidx.core.app.Person.Builder setIcon(androidx.core.graphics.drawable.IconCompat?);
+ method public androidx.core.app.Person.Builder setImportant(boolean);
+ method public androidx.core.app.Person.Builder setKey(String?);
+ method public androidx.core.app.Person.Builder setName(CharSequence?);
+ method public androidx.core.app.Person.Builder setUri(String?);
+ }
+
+ public final class PictureInPictureModeChangedInfo {
+ ctor public PictureInPictureModeChangedInfo(boolean);
+ ctor @RequiresApi(26) public PictureInPictureModeChangedInfo(boolean, android.content.res.Configuration);
+ method @RequiresApi(26) public android.content.res.Configuration getNewConfig();
+ method public boolean isInPictureInPictureMode();
+ }
+
+ @androidx.versionedparcelable.VersionedParcelize(jetifyAs="android.support.v4.app.RemoteActionCompat") public final class RemoteActionCompat implements androidx.versionedparcelable.VersionedParcelable {
+ ctor public RemoteActionCompat(androidx.core.graphics.drawable.IconCompat, CharSequence, CharSequence, android.app.PendingIntent);
+ ctor @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP) public RemoteActionCompat();
+ ctor public RemoteActionCompat(androidx.core.app.RemoteActionCompat);
+ method @RequiresApi(26) public static androidx.core.app.RemoteActionCompat createFromRemoteAction(android.app.RemoteAction);
+ method public android.app.PendingIntent getActionIntent();
+ method public CharSequence getContentDescription();
+ method public androidx.core.graphics.drawable.IconCompat getIcon();
+ method public CharSequence getTitle();
+ method public boolean isEnabled();
+ method public void setEnabled(boolean);
+ method public void setShouldShowIcon(boolean);
+ method public boolean shouldShowIcon();
+ method @RequiresApi(26) public android.app.RemoteAction toRemoteAction();
+ field @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP) @androidx.versionedparcelable.ParcelField(4) public android.app.PendingIntent mActionIntent;
+ field @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP) @androidx.versionedparcelable.ParcelField(3) public CharSequence mContentDescription;
+ field @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP) @androidx.versionedparcelable.ParcelField(5) public boolean mEnabled;
+ field @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP) @androidx.versionedparcelable.ParcelField(1) public androidx.core.graphics.drawable.IconCompat mIcon;
+ field @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP) @androidx.versionedparcelable.ParcelField(6) public boolean mShouldShowIcon;
+ field @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP) @androidx.versionedparcelable.ParcelField(2) public CharSequence mTitle;
+ }
+
+ public final class RemoteInput {
+ method public static void addDataResultToIntent(androidx.core.app.RemoteInput, android.content.Intent, java.util.Map<java.lang.String!,android.net.Uri!>);
+ method public static void addResultsToIntent(androidx.core.app.RemoteInput![], android.content.Intent, android.os.Bundle);
+ method public boolean getAllowFreeFormInput();
+ method public java.util.Set<java.lang.String!>? getAllowedDataTypes();
+ method public CharSequence![]? getChoices();
+ method public static java.util.Map<java.lang.String!,android.net.Uri!>? getDataResultsFromIntent(android.content.Intent, String);
+ method @androidx.core.app.RemoteInput.EditChoicesBeforeSending public int getEditChoicesBeforeSending();
+ method public android.os.Bundle getExtras();
+ method public CharSequence? getLabel();
+ method public String getResultKey();
+ method public static android.os.Bundle? getResultsFromIntent(android.content.Intent);
+ method @androidx.core.app.RemoteInput.Source public static int getResultsSource(android.content.Intent);
+ method public boolean isDataOnly();
+ method public static void setResultsSource(android.content.Intent, @androidx.core.app.RemoteInput.Source int);
+ field public static final int EDIT_CHOICES_BEFORE_SENDING_AUTO = 0; // 0x0
+ field public static final int EDIT_CHOICES_BEFORE_SENDING_DISABLED = 1; // 0x1
+ field public static final int EDIT_CHOICES_BEFORE_SENDING_ENABLED = 2; // 0x2
+ field public static final String EXTRA_RESULTS_DATA = "android.remoteinput.resultsData";
+ field public static final String RESULTS_CLIP_LABEL = "android.remoteinput.results";
+ field public static final int SOURCE_CHOICE = 1; // 0x1
+ field public static final int SOURCE_FREE_FORM_INPUT = 0; // 0x0
+ }
+
+ public static final class RemoteInput.Builder {
+ ctor public RemoteInput.Builder(String);
+ method public androidx.core.app.RemoteInput.Builder addExtras(android.os.Bundle);
+ method public androidx.core.app.RemoteInput build();
+ method public android.os.Bundle getExtras();
+ method public androidx.core.app.RemoteInput.Builder setAllowDataType(String, boolean);
+ method public androidx.core.app.RemoteInput.Builder setAllowFreeFormInput(boolean);
+ method public androidx.core.app.RemoteInput.Builder setChoices(CharSequence![]?);
+ method public androidx.core.app.RemoteInput.Builder setEditChoicesBeforeSending(@androidx.core.app.RemoteInput.EditChoicesBeforeSending int);
+ method public androidx.core.app.RemoteInput.Builder setLabel(CharSequence?);
+ }
+
+ @IntDef({androidx.core.app.RemoteInput.EDIT_CHOICES_BEFORE_SENDING_AUTO, androidx.core.app.RemoteInput.EDIT_CHOICES_BEFORE_SENDING_DISABLED, androidx.core.app.RemoteInput.EDIT_CHOICES_BEFORE_SENDING_ENABLED}) @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.SOURCE) public static @interface RemoteInput.EditChoicesBeforeSending {
+ }
+
+ @IntDef({androidx.core.app.RemoteInput.SOURCE_FREE_FORM_INPUT, androidx.core.app.RemoteInput.SOURCE_CHOICE}) @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.SOURCE) public static @interface RemoteInput.Source {
+ }
+
+ public final class ServiceCompat {
+ method public static void stopForeground(android.app.Service, @androidx.core.app.ServiceCompat.StopForegroundFlags int);
+ field public static final int START_STICKY = 1; // 0x1
+ field public static final int STOP_FOREGROUND_DETACH = 2; // 0x2
+ field public static final int STOP_FOREGROUND_REMOVE = 1; // 0x1
+ }
+
+ @IntDef(flag=true, value={androidx.core.app.ServiceCompat.STOP_FOREGROUND_REMOVE, androidx.core.app.ServiceCompat.STOP_FOREGROUND_DETACH}) @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.SOURCE) public static @interface ServiceCompat.StopForegroundFlags {
+ }
+
+ public final class ShareCompat {
+ method @Deprecated public static void configureMenuItem(android.view.MenuItem, androidx.core.app.ShareCompat.IntentBuilder);
+ method @Deprecated public static void configureMenuItem(android.view.Menu, @IdRes int, androidx.core.app.ShareCompat.IntentBuilder);
+ method public static android.content.ComponentName? getCallingActivity(android.app.Activity);
+ method public static String? getCallingPackage(android.app.Activity);
+ field public static final String EXTRA_CALLING_ACTIVITY = "androidx.core.app.EXTRA_CALLING_ACTIVITY";
+ field public static final String EXTRA_CALLING_ACTIVITY_INTEROP = "android.support.v4.app.EXTRA_CALLING_ACTIVITY";
+ field public static final String EXTRA_CALLING_PACKAGE = "androidx.core.app.EXTRA_CALLING_PACKAGE";
+ field public static final String EXTRA_CALLING_PACKAGE_INTEROP = "android.support.v4.app.EXTRA_CALLING_PACKAGE";
+ }
+
+ public static class ShareCompat.IntentBuilder {
+ ctor public ShareCompat.IntentBuilder(android.content.Context);
+ method public androidx.core.app.ShareCompat.IntentBuilder addEmailBcc(String);
+ method public androidx.core.app.ShareCompat.IntentBuilder addEmailBcc(String![]);
+ method public androidx.core.app.ShareCompat.IntentBuilder addEmailCc(String);
+ method public androidx.core.app.ShareCompat.IntentBuilder addEmailCc(String![]);
+ method public androidx.core.app.ShareCompat.IntentBuilder addEmailTo(String);
+ method public androidx.core.app.ShareCompat.IntentBuilder addEmailTo(String![]);
+ method public androidx.core.app.ShareCompat.IntentBuilder addStream(android.net.Uri);
+ method public android.content.Intent createChooserIntent();
+ method @Deprecated public static androidx.core.app.ShareCompat.IntentBuilder from(android.app.Activity);
+ method public android.content.Intent getIntent();
+ method public androidx.core.app.ShareCompat.IntentBuilder setChooserTitle(CharSequence?);
+ method public androidx.core.app.ShareCompat.IntentBuilder setChooserTitle(@StringRes int);
+ method public androidx.core.app.ShareCompat.IntentBuilder setEmailBcc(String![]?);
+ method public androidx.core.app.ShareCompat.IntentBuilder setEmailCc(String![]?);
+ method public androidx.core.app.ShareCompat.IntentBuilder setEmailTo(String![]?);
+ method public androidx.core.app.ShareCompat.IntentBuilder setHtmlText(String?);
+ method public androidx.core.app.ShareCompat.IntentBuilder setStream(android.net.Uri?);
+ method public androidx.core.app.ShareCompat.IntentBuilder setSubject(String?);
+ method public androidx.core.app.ShareCompat.IntentBuilder setText(CharSequence?);
+ method public androidx.core.app.ShareCompat.IntentBuilder setType(String?);
+ method public void startChooser();
+ }
+
+ public static class ShareCompat.IntentReader {
+ ctor public ShareCompat.IntentReader(android.app.Activity);
+ ctor public ShareCompat.IntentReader(android.content.Context, android.content.Intent);
+ method @Deprecated public static androidx.core.app.ShareCompat.IntentReader from(android.app.Activity);
+ method public android.content.ComponentName? getCallingActivity();
+ method public android.graphics.drawable.Drawable? getCallingActivityIcon();
+ method public android.graphics.drawable.Drawable? getCallingApplicationIcon();
+ method public CharSequence? getCallingApplicationLabel();
+ method public String? getCallingPackage();
+ method public String![]? getEmailBcc();
+ method public String![]? getEmailCc();
+ method public String![]? getEmailTo();
+ method public String? getHtmlText();
+ method public android.net.Uri? getStream();
+ method public android.net.Uri? getStream(int);
+ method public int getStreamCount();
+ method public String? getSubject();
+ method public CharSequence? getText();
+ method public String? getType();
+ method public boolean isMultipleShare();
+ method public boolean isShareIntent();
+ method public boolean isSingleShare();
+ }
+
+ public abstract class SharedElementCallback {
+ ctor public SharedElementCallback();
+ method public android.os.Parcelable! onCaptureSharedElementSnapshot(android.view.View!, android.graphics.Matrix!, android.graphics.RectF!);
+ method public android.view.View! onCreateSnapshotView(android.content.Context!, android.os.Parcelable!);
+ method public void onMapSharedElements(java.util.List<java.lang.String!>!, java.util.Map<java.lang.String!,android.view.View!>!);
+ method public void onRejectSharedElements(java.util.List<android.view.View!>!);
+ method public void onSharedElementEnd(java.util.List<java.lang.String!>!, java.util.List<android.view.View!>!, java.util.List<android.view.View!>!);
+ method public void onSharedElementStart(java.util.List<java.lang.String!>!, java.util.List<android.view.View!>!, java.util.List<android.view.View!>!);
+ method public void onSharedElementsArrived(java.util.List<java.lang.String!>!, java.util.List<android.view.View!>!, androidx.core.app.SharedElementCallback.OnSharedElementsReadyListener!);
+ }
+
+ public static interface SharedElementCallback.OnSharedElementsReadyListener {
+ method public void onSharedElementsReady();
+ }
+
+ public final class TaskStackBuilder implements java.lang.Iterable<android.content.Intent> {
+ method public androidx.core.app.TaskStackBuilder addNextIntent(android.content.Intent);
+ method public androidx.core.app.TaskStackBuilder addNextIntentWithParentStack(android.content.Intent);
+ method public androidx.core.app.TaskStackBuilder addParentStack(android.app.Activity);
+ method public androidx.core.app.TaskStackBuilder addParentStack(Class<?>);
+ method public androidx.core.app.TaskStackBuilder addParentStack(android.content.ComponentName);
+ method public static androidx.core.app.TaskStackBuilder create(android.content.Context);
+ method public android.content.Intent? editIntentAt(int);
+ method @Deprecated public static androidx.core.app.TaskStackBuilder! from(android.content.Context!);
+ method @Deprecated public android.content.Intent! getIntent(int);
+ method public int getIntentCount();
+ method public android.content.Intent![] getIntents();
+ method public android.app.PendingIntent? getPendingIntent(int, int);
+ method public android.app.PendingIntent? getPendingIntent(int, int, android.os.Bundle?);
+ method @Deprecated public java.util.Iterator<android.content.Intent!> iterator();
+ method public void startActivities();
+ method public void startActivities(android.os.Bundle?);
+ }
+
+ public static interface TaskStackBuilder.SupportParentable {
+ method public android.content.Intent? getSupportParentActivityIntent();
+ }
+
+}
+
+package androidx.core.content {
+
+ public final class ContentProviderCompat {
+ method public static android.content.Context requireContext(android.content.ContentProvider);
+ }
+
+ public final class ContentResolverCompat {
+ method public static android.database.Cursor? query(android.content.ContentResolver, android.net.Uri, String![]?, String?, String![]?, String?, androidx.core.os.CancellationSignal?);
+ }
+
+ public class ContextCompat {
+ ctor protected ContextCompat();
+ method public static int checkSelfPermission(android.content.Context, String);
+ method public static android.content.Context? createDeviceProtectedStorageContext(android.content.Context);
+ method public static String? getAttributionTag(android.content.Context);
+ method public static java.io.File getCodeCacheDir(android.content.Context);
+ method @ColorInt public static int getColor(android.content.Context, @ColorRes int);
+ method public static android.content.res.ColorStateList? getColorStateList(android.content.Context, @ColorRes int);
+ method public static java.io.File? getDataDir(android.content.Context);
+ method public static android.graphics.drawable.Drawable? getDrawable(android.content.Context, @DrawableRes int);
+ method public static java.io.File![] getExternalCacheDirs(android.content.Context);
+ method public static java.io.File![] getExternalFilesDirs(android.content.Context, String?);
+ method public static java.util.concurrent.Executor getMainExecutor(android.content.Context);
+ method public static java.io.File? getNoBackupFilesDir(android.content.Context);
+ method public static java.io.File![] getObbDirs(android.content.Context);
+ method public static <T> T? getSystemService(android.content.Context, Class<T!>);
+ method public static String? getSystemServiceName(android.content.Context, Class<?>);
+ method public static boolean isDeviceProtectedStorage(android.content.Context);
+ method public static android.content.Intent? registerReceiver(android.content.Context, android.content.BroadcastReceiver?, android.content.IntentFilter, int);
+ method public static android.content.Intent? registerReceiver(android.content.Context, android.content.BroadcastReceiver?, android.content.IntentFilter, String?, android.os.Handler?, int);
+ method public static boolean startActivities(android.content.Context, android.content.Intent![]);
+ method public static boolean startActivities(android.content.Context, android.content.Intent![], android.os.Bundle?);
+ method public static void startActivity(android.content.Context, android.content.Intent, android.os.Bundle?);
+ method public static void startForegroundService(android.content.Context, android.content.Intent);
+ field public static final int RECEIVER_EXPORTED = 2; // 0x2
+ field public static final int RECEIVER_NOT_EXPORTED = 4; // 0x4
+ field public static final int RECEIVER_VISIBLE_TO_INSTANT_APPS = 1; // 0x1
+ }
+
+ public class FileProvider extends android.content.ContentProvider {
+ ctor public FileProvider();
+ ctor protected FileProvider(@XmlRes int);
+ method public int delete(android.net.Uri, String?, String![]?);
+ method public String? getType(android.net.Uri);
+ method public static android.net.Uri! getUriForFile(android.content.Context, String, java.io.File);
+ method public static android.net.Uri getUriForFile(android.content.Context, String, java.io.File, String);
+ method public android.net.Uri! insert(android.net.Uri, android.content.ContentValues);
+ method public boolean onCreate();
+ method public android.database.Cursor query(android.net.Uri, String![]?, String?, String![]?, String?);
+ method public int update(android.net.Uri, android.content.ContentValues, String?, String![]?);
+ }
+
+ public final class IntentCompat {
+ method public static android.content.Intent createManageUnusedAppRestrictionsIntent(android.content.Context, String);
+ method public static android.os.Parcelable![]? getParcelableArrayExtra(android.content.Intent, String?, Class<? extends android.os.Parcelable>);
+ method public static <T> java.util.ArrayList<T!>? getParcelableArrayListExtra(android.content.Intent, String?, Class<? extends T>);
+ method public static <T> T? getParcelableExtra(android.content.Intent, String?, Class<T!>);
+ method public static android.content.Intent makeMainSelectorActivity(String, String);
+ field public static final String ACTION_CREATE_REMINDER = "android.intent.action.CREATE_REMINDER";
+ field public static final String CATEGORY_LEANBACK_LAUNCHER = "android.intent.category.LEANBACK_LAUNCHER";
+ field public static final String EXTRA_HTML_TEXT = "android.intent.extra.HTML_TEXT";
+ field public static final String EXTRA_START_PLAYBACK = "android.intent.extra.START_PLAYBACK";
+ field public static final String EXTRA_TIME = "android.intent.extra.TIME";
+ }
+
+ public class IntentSanitizer {
+ method public android.content.Intent sanitize(android.content.Intent, androidx.core.util.Consumer<java.lang.String!>);
+ method public android.content.Intent sanitizeByFiltering(android.content.Intent);
+ method public android.content.Intent sanitizeByThrowing(android.content.Intent);
+ }
+
+ public static final class IntentSanitizer.Builder {
+ ctor public IntentSanitizer.Builder();
+ method public androidx.core.content.IntentSanitizer.Builder allowAction(String);
+ method public androidx.core.content.IntentSanitizer.Builder allowAction(androidx.core.util.Predicate<java.lang.String!>);
+ method public androidx.core.content.IntentSanitizer.Builder allowAnyComponent();
+ method public androidx.core.content.IntentSanitizer.Builder allowCategory(String);
+ method public androidx.core.content.IntentSanitizer.Builder allowCategory(androidx.core.util.Predicate<java.lang.String!>);
+ method public androidx.core.content.IntentSanitizer.Builder allowClipData(androidx.core.util.Predicate<android.content.ClipData!>);
+ method public androidx.core.content.IntentSanitizer.Builder allowClipDataText();
+ method public androidx.core.content.IntentSanitizer.Builder allowClipDataUri(androidx.core.util.Predicate<android.net.Uri!>);
+ method public androidx.core.content.IntentSanitizer.Builder allowClipDataUriWithAuthority(String);
+ method public androidx.core.content.IntentSanitizer.Builder allowComponent(android.content.ComponentName);
+ method public androidx.core.content.IntentSanitizer.Builder allowComponent(androidx.core.util.Predicate<android.content.ComponentName!>);
+ method public androidx.core.content.IntentSanitizer.Builder allowComponentWithPackage(String);
+ method public androidx.core.content.IntentSanitizer.Builder allowData(androidx.core.util.Predicate<android.net.Uri!>);
+ method public androidx.core.content.IntentSanitizer.Builder allowDataWithAuthority(String);
+ method public androidx.core.content.IntentSanitizer.Builder allowExtra(String, Class<?>);
+ method public <T> androidx.core.content.IntentSanitizer.Builder allowExtra(String, Class<T!>, androidx.core.util.Predicate<T!>);
+ method public androidx.core.content.IntentSanitizer.Builder allowExtra(String, androidx.core.util.Predicate<java.lang.Object!>);
+ method public androidx.core.content.IntentSanitizer.Builder allowExtraOutput(String);
+ method public androidx.core.content.IntentSanitizer.Builder allowExtraOutput(androidx.core.util.Predicate<android.net.Uri!>);
+ method public androidx.core.content.IntentSanitizer.Builder allowExtraStream(androidx.core.util.Predicate<android.net.Uri!>);
+ method public androidx.core.content.IntentSanitizer.Builder allowExtraStreamUriWithAuthority(String);
+ method public androidx.core.content.IntentSanitizer.Builder allowFlags(int);
+ method public androidx.core.content.IntentSanitizer.Builder allowHistoryStackFlags();
+ method public androidx.core.content.IntentSanitizer.Builder allowIdentifier();
+ method public androidx.core.content.IntentSanitizer.Builder allowPackage(String);
+ method public androidx.core.content.IntentSanitizer.Builder allowPackage(androidx.core.util.Predicate<java.lang.String!>);
+ method public androidx.core.content.IntentSanitizer.Builder allowReceiverFlags();
+ method public androidx.core.content.IntentSanitizer.Builder allowSelector();
+ method public androidx.core.content.IntentSanitizer.Builder allowSourceBounds();
+ method public androidx.core.content.IntentSanitizer.Builder allowType(String);
+ method public androidx.core.content.IntentSanitizer.Builder allowType(androidx.core.util.Predicate<java.lang.String!>);
+ method public androidx.core.content.IntentSanitizer build();
+ }
+
+ public final class LocusIdCompat {
+ ctor public LocusIdCompat(String);
+ method public String getId();
+ method @RequiresApi(29) public android.content.LocusId toLocusId();
+ method @RequiresApi(29) public static androidx.core.content.LocusIdCompat toLocusIdCompat(android.content.LocusId);
+ }
+
+ public final class MimeTypeFilter {
+ method public static boolean matches(String?, String);
+ method public static String? matches(String?, String![]);
+ method public static String? matches(String![]?, String);
+ method public static String![] matchesMany(String![]?, String);
+ }
+
+ public interface OnConfigurationChangedProvider {
+ method public void addOnConfigurationChangedListener(androidx.core.util.Consumer<android.content.res.Configuration!>);
+ method public void removeOnConfigurationChangedListener(androidx.core.util.Consumer<android.content.res.Configuration!>);
+ }
+
+ public interface OnTrimMemoryProvider {
+ method public void addOnTrimMemoryListener(androidx.core.util.Consumer<java.lang.Integer!>);
+ method public void removeOnTrimMemoryListener(androidx.core.util.Consumer<java.lang.Integer!>);
+ }
+
+ public final class PackageManagerCompat {
+ method public static com.google.common.util.concurrent.ListenableFuture<java.lang.Integer!> getUnusedAppRestrictionsStatus(android.content.Context);
+ field public static final String ACTION_PERMISSION_REVOCATION_SETTINGS = "android.intent.action.AUTO_REVOKE_PERMISSIONS";
+ }
+
+ public final class PermissionChecker {
+ method @androidx.core.content.PermissionChecker.PermissionResult public static int checkCallingOrSelfPermission(android.content.Context, String);
+ method @androidx.core.content.PermissionChecker.PermissionResult public static int checkCallingPermission(android.content.Context, String, String?);
+ method @androidx.core.content.PermissionChecker.PermissionResult public static int checkPermission(android.content.Context, String, int, int, String?);
+ method @androidx.core.content.PermissionChecker.PermissionResult public static int checkSelfPermission(android.content.Context, String);
+ field public static final int PERMISSION_DENIED = -1; // 0xffffffff
+ field public static final int PERMISSION_DENIED_APP_OP = -2; // 0xfffffffe
+ field public static final int PERMISSION_GRANTED = 0; // 0x0
+ }
+
+ @IntDef({androidx.core.content.PermissionChecker.PERMISSION_GRANTED, androidx.core.content.PermissionChecker.PERMISSION_DENIED, androidx.core.content.PermissionChecker.PERMISSION_DENIED_APP_OP}) @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.SOURCE) public static @interface PermissionChecker.PermissionResult {
+ }
+
+ @Deprecated public final class SharedPreferencesCompat {
+ }
+
+ @Deprecated public static final class SharedPreferencesCompat.EditorCompat {
+ method @Deprecated public void apply(android.content.SharedPreferences.Editor);
+ method @Deprecated public static androidx.core.content.SharedPreferencesCompat.EditorCompat! getInstance();
+ }
+
+ public class UnusedAppRestrictionsBackportCallback {
+ method public void onResult(boolean, boolean) throws android.os.RemoteException;
+ }
+
+ public abstract class UnusedAppRestrictionsBackportService extends android.app.Service {
+ ctor public UnusedAppRestrictionsBackportService();
+ method protected abstract void isPermissionRevocationEnabled(androidx.core.content.UnusedAppRestrictionsBackportCallback);
+ method public android.os.IBinder? onBind(android.content.Intent?);
+ field public static final String ACTION_UNUSED_APP_RESTRICTIONS_BACKPORT_CONNECTION = "android.support.unusedapprestrictions.action.CustomUnusedAppRestrictionsBackportService";
+ }
+
+ public final class UnusedAppRestrictionsConstants {
+ field public static final int API_30 = 4; // 0x4
+ field public static final int API_30_BACKPORT = 3; // 0x3
+ field public static final int API_31 = 5; // 0x5
+ field public static final int DISABLED = 2; // 0x2
+ field public static final int ERROR = 0; // 0x0
+ field public static final int FEATURE_NOT_AVAILABLE = 1; // 0x1
+ }
+
+ public class UriMatcherCompat {
+ method public static androidx.core.util.Predicate<android.net.Uri!> asPredicate(android.content.UriMatcher);
+ }
+
+}
+
+package androidx.core.content.pm {
+
+ @Deprecated public final class ActivityInfoCompat {
+ field @Deprecated public static final int CONFIG_UI_MODE = 512; // 0x200
+ }
+
+ public final class PackageInfoCompat {
+ method public static long getLongVersionCode(android.content.pm.PackageInfo);
+ method public static java.util.List<android.content.pm.Signature!> getSignatures(android.content.pm.PackageManager, String) throws android.content.pm.PackageManager.NameNotFoundException;
+ method public static boolean hasSignatures(android.content.pm.PackageManager, String, @Size(min=1) java.util.Map<byte[]!,java.lang.Integer!>, boolean) throws android.content.pm.PackageManager.NameNotFoundException;
+ }
+
+ public final class PermissionInfoCompat {
+ method public static int getProtection(android.content.pm.PermissionInfo);
+ method public static int getProtectionFlags(android.content.pm.PermissionInfo);
+ }
+
+ @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) public abstract class ShortcutInfoChangeListener {
+ ctor public ShortcutInfoChangeListener();
+ method @AnyThread public void onAllShortcutsRemoved();
+ method @AnyThread public void onShortcutAdded(java.util.List<androidx.core.content.pm.ShortcutInfoCompat!>);
+ method @AnyThread public void onShortcutRemoved(java.util.List<java.lang.String!>);
+ method @AnyThread public void onShortcutUpdated(java.util.List<androidx.core.content.pm.ShortcutInfoCompat!>);
+ method @AnyThread public void onShortcutUsageReported(java.util.List<java.lang.String!>);
+ }
+
+ public class ShortcutInfoCompat {
+ method public android.content.ComponentName? getActivity();
+ method public java.util.Set<java.lang.String!>? getCategories();
+ method public CharSequence? getDisabledMessage();
+ method public int getDisabledReason();
+ method @androidx.core.content.pm.ShortcutInfoCompat.Surface public int getExcludedFromSurfaces();
+ method public android.os.PersistableBundle? getExtras();
+ method @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) public androidx.core.graphics.drawable.IconCompat! getIcon();
+ method public String getId();
+ method public android.content.Intent getIntent();
+ method public android.content.Intent![] getIntents();
+ method public long getLastChangedTimestamp();
+ method public androidx.core.content.LocusIdCompat? getLocusId();
+ method public CharSequence? getLongLabel();
+ method public String getPackage();
+ method public int getRank();
+ method public CharSequence getShortLabel();
+ method @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) public android.os.Bundle? getTransientExtras();
+ method public android.os.UserHandle? getUserHandle();
+ method public boolean hasKeyFieldsOnly();
+ method public boolean isCached();
+ method public boolean isDeclaredInManifest();
+ method public boolean isDynamic();
+ method public boolean isEnabled();
+ method public boolean isExcludedFromSurfaces(@androidx.core.content.pm.ShortcutInfoCompat.Surface int);
+ method public boolean isImmutable();
+ method public boolean isPinned();
+ method @RequiresApi(25) public android.content.pm.ShortcutInfo! toShortcutInfo();
+ field public static final int SURFACE_LAUNCHER = 1; // 0x1
+ }
+
+ public static class ShortcutInfoCompat.Builder {
+ ctor public ShortcutInfoCompat.Builder(android.content.Context, String);
+ ctor @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) public ShortcutInfoCompat.Builder(androidx.core.content.pm.ShortcutInfoCompat);
+ ctor @RequiresApi(25) @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) public ShortcutInfoCompat.Builder(android.content.Context, android.content.pm.ShortcutInfo);
+ method public androidx.core.content.pm.ShortcutInfoCompat.Builder addCapabilityBinding(String);
+ method public androidx.core.content.pm.ShortcutInfoCompat.Builder addCapabilityBinding(String, String, java.util.List<java.lang.String!>);
+ method public androidx.core.content.pm.ShortcutInfoCompat build();
+ method public androidx.core.content.pm.ShortcutInfoCompat.Builder setActivity(android.content.ComponentName);
+ method public androidx.core.content.pm.ShortcutInfoCompat.Builder setAlwaysBadged();
+ method public androidx.core.content.pm.ShortcutInfoCompat.Builder setCategories(java.util.Set<java.lang.String!>);
+ method public androidx.core.content.pm.ShortcutInfoCompat.Builder setDisabledMessage(CharSequence);
+ method public androidx.core.content.pm.ShortcutInfoCompat.Builder setExcludedFromSurfaces(int);
+ method public androidx.core.content.pm.ShortcutInfoCompat.Builder setExtras(android.os.PersistableBundle);
+ method public androidx.core.content.pm.ShortcutInfoCompat.Builder setIcon(androidx.core.graphics.drawable.IconCompat!);
+ method public androidx.core.content.pm.ShortcutInfoCompat.Builder setIntent(android.content.Intent);
+ method public androidx.core.content.pm.ShortcutInfoCompat.Builder setIntents(android.content.Intent![]);
+ method public androidx.core.content.pm.ShortcutInfoCompat.Builder setIsConversation();
+ method public androidx.core.content.pm.ShortcutInfoCompat.Builder setLocusId(androidx.core.content.LocusIdCompat?);
+ method public androidx.core.content.pm.ShortcutInfoCompat.Builder setLongLabel(CharSequence);
+ method @Deprecated public androidx.core.content.pm.ShortcutInfoCompat.Builder setLongLived();
+ method public androidx.core.content.pm.ShortcutInfoCompat.Builder setLongLived(boolean);
+ method public androidx.core.content.pm.ShortcutInfoCompat.Builder setPerson(androidx.core.app.Person);
+ method public androidx.core.content.pm.ShortcutInfoCompat.Builder setPersons(androidx.core.app.Person![]);
+ method public androidx.core.content.pm.ShortcutInfoCompat.Builder setRank(int);
+ method public androidx.core.content.pm.ShortcutInfoCompat.Builder setShortLabel(CharSequence);
+ method public androidx.core.content.pm.ShortcutInfoCompat.Builder setSliceUri(android.net.Uri);
+ method @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) public androidx.core.content.pm.ShortcutInfoCompat.Builder setTransientExtras(android.os.Bundle);
+ }
+
+ @IntDef(flag=true, value={androidx.core.content.pm.ShortcutInfoCompat.SURFACE_LAUNCHER}) @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.SOURCE) public static @interface ShortcutInfoCompat.Surface {
+ }
+
+ @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) public abstract class ShortcutInfoCompatSaver<T> {
+ ctor public ShortcutInfoCompatSaver();
+ method @AnyThread public abstract T! addShortcuts(java.util.List<androidx.core.content.pm.ShortcutInfoCompat!>!);
+ method @WorkerThread public java.util.List<androidx.core.content.pm.ShortcutInfoCompat!>! getShortcuts() throws java.lang.Exception;
+ method @AnyThread public abstract T! removeAllShortcuts();
+ method @AnyThread public abstract T! removeShortcuts(java.util.List<java.lang.String!>!);
+ }
+
+ public class ShortcutManagerCompat {
+ method public static boolean addDynamicShortcuts(android.content.Context, java.util.List<androidx.core.content.pm.ShortcutInfoCompat!>);
+ method public static android.content.Intent createShortcutResultIntent(android.content.Context, androidx.core.content.pm.ShortcutInfoCompat);
+ method public static void disableShortcuts(android.content.Context, java.util.List<java.lang.String!>, CharSequence?);
+ method public static void enableShortcuts(android.content.Context, java.util.List<androidx.core.content.pm.ShortcutInfoCompat!>);
+ method public static java.util.List<androidx.core.content.pm.ShortcutInfoCompat!> getDynamicShortcuts(android.content.Context);
+ method public static int getIconMaxHeight(android.content.Context);
+ method public static int getIconMaxWidth(android.content.Context);
+ method public static int getMaxShortcutCountPerActivity(android.content.Context);
+ method public static java.util.List<androidx.core.content.pm.ShortcutInfoCompat!> getShortcuts(android.content.Context, @androidx.core.content.pm.ShortcutManagerCompat.ShortcutMatchFlags int);
+ method public static boolean isRateLimitingActive(android.content.Context);
+ method public static boolean isRequestPinShortcutSupported(android.content.Context);
+ method public static boolean pushDynamicShortcut(android.content.Context, androidx.core.content.pm.ShortcutInfoCompat);
+ method public static void removeAllDynamicShortcuts(android.content.Context);
+ method public static void removeDynamicShortcuts(android.content.Context, java.util.List<java.lang.String!>);
+ method public static void removeLongLivedShortcuts(android.content.Context, java.util.List<java.lang.String!>);
+ method public static void reportShortcutUsed(android.content.Context, String);
+ method public static boolean requestPinShortcut(android.content.Context, androidx.core.content.pm.ShortcutInfoCompat, android.content.IntentSender?);
+ method public static boolean setDynamicShortcuts(android.content.Context, java.util.List<androidx.core.content.pm.ShortcutInfoCompat!>);
+ method public static boolean updateShortcuts(android.content.Context, java.util.List<androidx.core.content.pm.ShortcutInfoCompat!>);
+ field public static final String EXTRA_SHORTCUT_ID = "android.intent.extra.shortcut.ID";
+ field public static final int FLAG_MATCH_CACHED = 8; // 0x8
+ field public static final int FLAG_MATCH_DYNAMIC = 2; // 0x2
+ field public static final int FLAG_MATCH_MANIFEST = 1; // 0x1
+ field public static final int FLAG_MATCH_PINNED = 4; // 0x4
+ }
+
+ @IntDef(flag=true, value={androidx.core.content.pm.ShortcutManagerCompat.FLAG_MATCH_MANIFEST, androidx.core.content.pm.ShortcutManagerCompat.FLAG_MATCH_DYNAMIC, androidx.core.content.pm.ShortcutManagerCompat.FLAG_MATCH_PINNED, androidx.core.content.pm.ShortcutManagerCompat.FLAG_MATCH_CACHED}) @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.SOURCE) public static @interface ShortcutManagerCompat.ShortcutMatchFlags {
+ }
+
+ @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP) public class ShortcutXmlParser {
+ method @WorkerThread public static java.util.List<java.lang.String!> getShortcutIds(android.content.Context);
+ method @VisibleForTesting public static java.util.List<java.lang.String!> parseShortcutIds(org.xmlpull.v1.XmlPullParser) throws java.io.IOException, org.xmlpull.v1.XmlPullParserException;
+ }
+
+}
+
+package androidx.core.content.res {
+
+ @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) public final class ColorStateListInflaterCompat {
+ method public static android.content.res.ColorStateList createFromXml(android.content.res.Resources, org.xmlpull.v1.XmlPullParser, android.content.res.Resources.Theme?) throws java.io.IOException, org.xmlpull.v1.XmlPullParserException;
+ method public static android.content.res.ColorStateList createFromXmlInner(android.content.res.Resources, org.xmlpull.v1.XmlPullParser, android.util.AttributeSet, android.content.res.Resources.Theme?) throws java.io.IOException, org.xmlpull.v1.XmlPullParserException;
+ method public static android.content.res.ColorStateList? inflate(android.content.res.Resources, @XmlRes int, android.content.res.Resources.Theme?);
+ }
+
+ @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) public final class ComplexColorCompat {
+ method @ColorInt public int getColor();
+ method public android.graphics.Shader? getShader();
+ method public static androidx.core.content.res.ComplexColorCompat? inflate(android.content.res.Resources, @ColorRes int, android.content.res.Resources.Theme?);
+ method public boolean isGradient();
+ method public boolean isStateful();
+ method public boolean onStateChanged(int[]!);
+ method public void setColor(@ColorInt int);
+ method public boolean willDraw();
+ }
+
+ public final class ConfigurationHelper {
+ method public static int getDensityDpi(android.content.res.Resources);
+ }
+
+ @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) public class FontResourcesParserCompat {
+ method public static androidx.core.content.res.FontResourcesParserCompat.FamilyResourceEntry? parse(org.xmlpull.v1.XmlPullParser, android.content.res.Resources) throws java.io.IOException, org.xmlpull.v1.XmlPullParserException;
+ method public static java.util.List<java.util.List<byte[]!>!> readCerts(android.content.res.Resources, @ArrayRes int);
+ field public static final int FETCH_STRATEGY_ASYNC = 1; // 0x1
+ field public static final int FETCH_STRATEGY_BLOCKING = 0; // 0x0
+ field public static final int INFINITE_TIMEOUT_VALUE = -1; // 0xffffffff
+ }
+
+ public static interface FontResourcesParserCompat.FamilyResourceEntry {
+ }
+
+ @IntDef({androidx.core.content.res.FontResourcesParserCompat.FETCH_STRATEGY_BLOCKING, androidx.core.content.res.FontResourcesParserCompat.FETCH_STRATEGY_ASYNC}) @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.SOURCE) public static @interface FontResourcesParserCompat.FetchStrategy {
+ }
+
+ public static final class FontResourcesParserCompat.FontFamilyFilesResourceEntry implements androidx.core.content.res.FontResourcesParserCompat.FamilyResourceEntry {
+ ctor public FontResourcesParserCompat.FontFamilyFilesResourceEntry(androidx.core.content.res.FontResourcesParserCompat.FontFileResourceEntry![]);
+ method public androidx.core.content.res.FontResourcesParserCompat.FontFileResourceEntry![] getEntries();
+ }
+
+ public static final class FontResourcesParserCompat.FontFileResourceEntry {
+ ctor public FontResourcesParserCompat.FontFileResourceEntry(String, int, boolean, String?, int, int);
+ method public String getFileName();
+ method public int getResourceId();
+ method public int getTtcIndex();
+ method public String? getVariationSettings();
+ method public int getWeight();
+ method public boolean isItalic();
+ }
+
+ public static final class FontResourcesParserCompat.ProviderResourceEntry implements androidx.core.content.res.FontResourcesParserCompat.FamilyResourceEntry {
+ ctor public FontResourcesParserCompat.ProviderResourceEntry(androidx.core.provider.FontRequest, @androidx.core.content.res.FontResourcesParserCompat.FetchStrategy int, int);
+ method @androidx.core.content.res.FontResourcesParserCompat.FetchStrategy public int getFetchStrategy();
+ method public androidx.core.provider.FontRequest getRequest();
+ method public int getTimeout();
+ }
+
+ public final class ResourcesCompat {
+ method public static void clearCachesForTheme(android.content.res.Resources.Theme);
+ method public static android.graphics.Typeface? getCachedFont(android.content.Context, @FontRes int) throws android.content.res.Resources.NotFoundException;
+ method @ColorInt public static int getColor(android.content.res.Resources, @ColorRes int, android.content.res.Resources.Theme?) throws android.content.res.Resources.NotFoundException;
+ method public static android.content.res.ColorStateList? getColorStateList(android.content.res.Resources, @ColorRes int, android.content.res.Resources.Theme?) throws android.content.res.Resources.NotFoundException;
+ method public static android.graphics.drawable.Drawable? getDrawable(android.content.res.Resources, @DrawableRes int, android.content.res.Resources.Theme?) throws android.content.res.Resources.NotFoundException;
+ method public static android.graphics.drawable.Drawable? getDrawableForDensity(android.content.res.Resources, @DrawableRes int, int, android.content.res.Resources.Theme?) throws android.content.res.Resources.NotFoundException;
+ method public static float getFloat(android.content.res.Resources, @DimenRes int);
+ method public static android.graphics.Typeface? getFont(android.content.Context, @FontRes int) throws android.content.res.Resources.NotFoundException;
+ method public static void getFont(android.content.Context, @FontRes int, androidx.core.content.res.ResourcesCompat.FontCallback, android.os.Handler?) throws android.content.res.Resources.NotFoundException;
+ method @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) public static android.graphics.Typeface? getFont(android.content.Context, @FontRes int, android.util.TypedValue, int, androidx.core.content.res.ResourcesCompat.FontCallback?) throws android.content.res.Resources.NotFoundException;
+ field @AnyRes public static final int ID_NULL = 0; // 0x0
+ }
+
+ public abstract static class ResourcesCompat.FontCallback {
+ ctor public ResourcesCompat.FontCallback();
+ method @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) public final void callbackFailAsync(@androidx.core.provider.FontsContractCompat.FontRequestCallback.FontRequestFailReason int, android.os.Handler?);
+ method @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) public final void callbackSuccessAsync(android.graphics.Typeface, android.os.Handler?);
+ method public abstract void onFontRetrievalFailed(@androidx.core.provider.FontsContractCompat.FontRequestCallback.FontRequestFailReason int);
+ method public abstract void onFontRetrieved(android.graphics.Typeface);
+ }
+
+ public static final class ResourcesCompat.ThemeCompat {
+ method public static void rebase(android.content.res.Resources.Theme);
+ }
+
+ @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) public class TypedArrayUtils {
+ method public static int getAttr(android.content.Context, int, int);
+ method public static boolean getBoolean(android.content.res.TypedArray, @StyleableRes int, @StyleableRes int, boolean);
+ method public static android.graphics.drawable.Drawable? getDrawable(android.content.res.TypedArray, @StyleableRes int, @StyleableRes int);
+ method public static int getInt(android.content.res.TypedArray, @StyleableRes int, @StyleableRes int, int);
+ method public static boolean getNamedBoolean(android.content.res.TypedArray, org.xmlpull.v1.XmlPullParser, String, @StyleableRes int, boolean);
+ method @ColorInt public static int getNamedColor(android.content.res.TypedArray, org.xmlpull.v1.XmlPullParser, String, @StyleableRes int, @ColorInt int);
+ method public static android.content.res.ColorStateList? getNamedColorStateList(android.content.res.TypedArray, org.xmlpull.v1.XmlPullParser, android.content.res.Resources.Theme?, String, @StyleableRes int);
+ method public static androidx.core.content.res.ComplexColorCompat! getNamedComplexColor(android.content.res.TypedArray, org.xmlpull.v1.XmlPullParser, android.content.res.Resources.Theme?, String, @StyleableRes int, @ColorInt int);
+ method public static float getNamedFloat(android.content.res.TypedArray, org.xmlpull.v1.XmlPullParser, String, @StyleableRes int, float);
+ method public static int getNamedInt(android.content.res.TypedArray, org.xmlpull.v1.XmlPullParser, String, @StyleableRes int, int);
+ method @AnyRes public static int getNamedResourceId(android.content.res.TypedArray, org.xmlpull.v1.XmlPullParser, String, @StyleableRes int, @AnyRes int);
+ method public static String? getNamedString(android.content.res.TypedArray, org.xmlpull.v1.XmlPullParser, String, @StyleableRes int);
+ method @AnyRes public static int getResourceId(android.content.res.TypedArray, @StyleableRes int, @StyleableRes int, @AnyRes int);
+ method public static String? getString(android.content.res.TypedArray, @StyleableRes int, @StyleableRes int);
+ method public static CharSequence? getText(android.content.res.TypedArray, @StyleableRes int, @StyleableRes int);
+ method public static CharSequence![]? getTextArray(android.content.res.TypedArray, @StyleableRes int, @StyleableRes int);
+ method public static boolean hasAttribute(org.xmlpull.v1.XmlPullParser, String);
+ method public static android.content.res.TypedArray obtainAttributes(android.content.res.Resources, android.content.res.Resources.Theme?, android.util.AttributeSet, int[]);
+ method public static android.util.TypedValue? peekNamedValue(android.content.res.TypedArray, org.xmlpull.v1.XmlPullParser, String, int);
+ }
+
+}
+
+package androidx.core.database {
+
+ public final class CursorWindowCompat {
+ method public static android.database.CursorWindow create(String?, long);
+ }
+
+ @Deprecated public final class DatabaseUtilsCompat {
+ method @Deprecated public static String![]! appendSelectionArgs(String![]!, String![]!);
+ method @Deprecated public static String! concatenateWhere(String!, String!);
+ }
+
+}
+
+package androidx.core.database.sqlite {
+
+ public final class SQLiteCursorCompat {
+ method public static void setFillWindowForwardOnly(android.database.sqlite.SQLiteCursor, boolean);
+ }
+
+}
+
+package androidx.core.graphics {
+
+ public final class BitmapCompat {
+ method public static android.graphics.Bitmap createScaledBitmap(android.graphics.Bitmap, int, int, android.graphics.Rect?, boolean);
+ method public static int getAllocationByteCount(android.graphics.Bitmap);
+ method public static boolean hasMipMap(android.graphics.Bitmap);
+ method public static void setHasMipMap(android.graphics.Bitmap, boolean);
+ }
+
+ public class BlendModeColorFilterCompat {
+ method public static android.graphics.ColorFilter? createBlendModeColorFilterCompat(int, androidx.core.graphics.BlendModeCompat);
+ }
+
+ public enum BlendModeCompat {
+ enum_constant public static final androidx.core.graphics.BlendModeCompat CLEAR;
+ enum_constant @RequiresApi(android.os.Build.VERSION_CODES.Q) public static final androidx.core.graphics.BlendModeCompat COLOR;
+ enum_constant @RequiresApi(android.os.Build.VERSION_CODES.Q) public static final androidx.core.graphics.BlendModeCompat COLOR_BURN;
+ enum_constant @RequiresApi(android.os.Build.VERSION_CODES.Q) public static final androidx.core.graphics.BlendModeCompat COLOR_DODGE;
+ enum_constant public static final androidx.core.graphics.BlendModeCompat DARKEN;
+ enum_constant @RequiresApi(android.os.Build.VERSION_CODES.Q) public static final androidx.core.graphics.BlendModeCompat DIFFERENCE;
+ enum_constant public static final androidx.core.graphics.BlendModeCompat DST;
+ enum_constant public static final androidx.core.graphics.BlendModeCompat DST_ATOP;
+ enum_constant public static final androidx.core.graphics.BlendModeCompat DST_IN;
+ enum_constant public static final androidx.core.graphics.BlendModeCompat DST_OUT;
+ enum_constant public static final androidx.core.graphics.BlendModeCompat DST_OVER;
+ enum_constant @RequiresApi(android.os.Build.VERSION_CODES.Q) public static final androidx.core.graphics.BlendModeCompat EXCLUSION;
+ enum_constant @RequiresApi(android.os.Build.VERSION_CODES.Q) public static final androidx.core.graphics.BlendModeCompat HARD_LIGHT;
+ enum_constant @RequiresApi(android.os.Build.VERSION_CODES.Q) public static final androidx.core.graphics.BlendModeCompat HUE;
+ enum_constant public static final androidx.core.graphics.BlendModeCompat LIGHTEN;
+ enum_constant @RequiresApi(android.os.Build.VERSION_CODES.Q) public static final androidx.core.graphics.BlendModeCompat LUMINOSITY;
+ enum_constant public static final androidx.core.graphics.BlendModeCompat MODULATE;
+ enum_constant @RequiresApi(android.os.Build.VERSION_CODES.Q) public static final androidx.core.graphics.BlendModeCompat MULTIPLY;
+ enum_constant public static final androidx.core.graphics.BlendModeCompat OVERLAY;
+ enum_constant public static final androidx.core.graphics.BlendModeCompat PLUS;
+ enum_constant @RequiresApi(android.os.Build.VERSION_CODES.Q) public static final androidx.core.graphics.BlendModeCompat SATURATION;
+ enum_constant public static final androidx.core.graphics.BlendModeCompat SCREEN;
+ enum_constant @RequiresApi(android.os.Build.VERSION_CODES.Q) public static final androidx.core.graphics.BlendModeCompat SOFT_LIGHT;
+ enum_constant public static final androidx.core.graphics.BlendModeCompat SRC;
+ enum_constant public static final androidx.core.graphics.BlendModeCompat SRC_ATOP;
+ enum_constant public static final androidx.core.graphics.BlendModeCompat SRC_IN;
+ enum_constant public static final androidx.core.graphics.BlendModeCompat SRC_OUT;
+ enum_constant public static final androidx.core.graphics.BlendModeCompat SRC_OVER;
+ enum_constant public static final androidx.core.graphics.BlendModeCompat XOR;
+ }
+
+ public final class ColorUtils {
+ method @ColorInt public static int HSLToColor(float[]);
+ method @ColorInt public static int LABToColor(@FloatRange(from=0.0f, to=100) double, @FloatRange(from=0xffffff80, to=127) double, @FloatRange(from=0xffffff80, to=127) double);
+ method public static void LABToXYZ(@FloatRange(from=0.0f, to=100) double, @FloatRange(from=0xffffff80, to=127) double, @FloatRange(from=0xffffff80, to=127) double, double[]);
+ method public static void RGBToHSL(@IntRange(from=0, to=255) int, @IntRange(from=0, to=255) int, @IntRange(from=0, to=255) int, float[]);
+ method public static void RGBToLAB(@IntRange(from=0, to=255) int, @IntRange(from=0, to=255) int, @IntRange(from=0, to=255) int, double[]);
+ method public static void RGBToXYZ(@IntRange(from=0, to=255) int, @IntRange(from=0, to=255) int, @IntRange(from=0, to=255) int, double[]);
+ method @ColorInt public static int XYZToColor(@FloatRange(from=0.0f, to=95.047) double, @FloatRange(from=0.0f, to=0x64) double, @FloatRange(from=0.0f, to=108.883) double);
+ method public static void XYZToLAB(@FloatRange(from=0.0f, to=95.047) double, @FloatRange(from=0.0f, to=0x64) double, @FloatRange(from=0.0f, to=108.883) double, double[]);
+ method @ColorInt public static int blendARGB(@ColorInt int, @ColorInt int, @FloatRange(from=0.0, to=1.0) float);
+ method public static void blendHSL(float[], float[], @FloatRange(from=0.0, to=1.0) float, float[]);
+ method public static void blendLAB(double[], double[], @FloatRange(from=0.0, to=1.0) double, double[]);
+ method public static double calculateContrast(@ColorInt int, @ColorInt int);
+ method @FloatRange(from=0.0, to=1.0) public static double calculateLuminance(@ColorInt int);
+ method public static int calculateMinimumAlpha(@ColorInt int, @ColorInt int, float);
+ method public static void colorToHSL(@ColorInt int, float[]);
+ method public static void colorToLAB(@ColorInt int, double[]);
+ method public static void colorToXYZ(@ColorInt int, double[]);
+ method public static int compositeColors(@ColorInt int, @ColorInt int);
+ method @RequiresApi(26) public static android.graphics.Color compositeColors(android.graphics.Color, android.graphics.Color);
+ method public static double distanceEuclidean(double[], double[]);
+ method @ColorInt public static int setAlphaComponent(@ColorInt int, @IntRange(from=0, to=255) int);
+ }
+
+ public final class Insets {
+ method public static androidx.core.graphics.Insets add(androidx.core.graphics.Insets, androidx.core.graphics.Insets);
+ method public static androidx.core.graphics.Insets max(androidx.core.graphics.Insets, androidx.core.graphics.Insets);
+ method public static androidx.core.graphics.Insets min(androidx.core.graphics.Insets, androidx.core.graphics.Insets);
+ method public static androidx.core.graphics.Insets of(int, int, int, int);
+ method public static androidx.core.graphics.Insets of(android.graphics.Rect);
+ method public static androidx.core.graphics.Insets subtract(androidx.core.graphics.Insets, androidx.core.graphics.Insets);
+ method @RequiresApi(api=29) public static androidx.core.graphics.Insets toCompatInsets(android.graphics.Insets);
+ method @RequiresApi(29) public android.graphics.Insets toPlatformInsets();
+ method @Deprecated @RequiresApi(api=29) @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) public static androidx.core.graphics.Insets wrap(android.graphics.Insets);
+ field public static final androidx.core.graphics.Insets NONE;
+ field public final int bottom;
+ field public final int left;
+ field public final int right;
+ field public final int top;
+ }
+
+ public final class PaintCompat {
+ method public static boolean hasGlyph(android.graphics.Paint, String);
+ method public static boolean setBlendMode(android.graphics.Paint, androidx.core.graphics.BlendModeCompat?);
+ }
+
+ public final class PathSegment {
+ ctor public PathSegment(android.graphics.PointF, float, android.graphics.PointF, float);
+ method public android.graphics.PointF getEnd();
+ method public float getEndFraction();
+ method public android.graphics.PointF getStart();
+ method public float getStartFraction();
+ }
+
+ public final class PathUtils {
+ method @RequiresApi(26) public static java.util.Collection<androidx.core.graphics.PathSegment!> flatten(android.graphics.Path);
+ method @RequiresApi(26) public static java.util.Collection<androidx.core.graphics.PathSegment!> flatten(android.graphics.Path, @FloatRange(from=0) float);
+ }
+
+ public class TypefaceCompat {
+ method @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) @VisibleForTesting public static void clearCache();
+ method public static android.graphics.Typeface create(android.content.Context, android.graphics.Typeface?, int);
+ method public static android.graphics.Typeface create(android.content.Context, android.graphics.Typeface?, @IntRange(from=1, to=1000) int, boolean);
+ method @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) public static android.graphics.Typeface? createFromFontInfo(android.content.Context, android.os.CancellationSignal?, androidx.core.provider.FontsContractCompat.FontInfo![], int);
+ method @Deprecated @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) public static android.graphics.Typeface? createFromResourcesFamilyXml(android.content.Context, androidx.core.content.res.FontResourcesParserCompat.FamilyResourceEntry, android.content.res.Resources, int, int, androidx.core.content.res.ResourcesCompat.FontCallback?, android.os.Handler?, boolean);
+ method @Deprecated @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) public static android.graphics.Typeface? createFromResourcesFontFile(android.content.Context, android.content.res.Resources, int, String!, int);
+ method @Deprecated @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) public static android.graphics.Typeface? findFromCache(android.content.res.Resources, int, int);
+ }
+
+ @RequiresApi(26) @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) public class TypefaceCompatApi26Impl {
+ ctor public TypefaceCompatApi26Impl();
+ method protected android.graphics.Typeface? createFromFamiliesWithDefault(Object!);
+ method public android.graphics.Typeface? createFromFontFamilyFilesResourceEntry(android.content.Context!, androidx.core.content.res.FontResourcesParserCompat.FontFamilyFilesResourceEntry!, android.content.res.Resources!, int);
+ method public android.graphics.Typeface? createFromFontInfo(android.content.Context!, android.os.CancellationSignal?, androidx.core.provider.FontsContractCompat.FontInfo![], int);
+ method public android.graphics.Typeface? createFromResourcesFontFile(android.content.Context!, android.content.res.Resources!, int, String!, int);
+ method protected java.lang.reflect.Method! obtainAbortCreationMethod(Class<?>!) throws java.lang.NoSuchMethodException;
+ method protected java.lang.reflect.Method! obtainAddFontFromAssetManagerMethod(Class<?>!) throws java.lang.NoSuchMethodException;
+ method protected java.lang.reflect.Method! obtainAddFontFromBufferMethod(Class<?>!) throws java.lang.NoSuchMethodException;
+ method protected java.lang.reflect.Method! obtainCreateFromFamiliesWithDefaultMethod(Class<?>!) throws java.lang.NoSuchMethodException;
+ method protected Class<?>! obtainFontFamily() throws java.lang.ClassNotFoundException;
+ method protected java.lang.reflect.Constructor<?>! obtainFontFamilyCtor(Class<?>!) throws java.lang.NoSuchMethodException;
+ method protected java.lang.reflect.Method! obtainFreezeMethod(Class<?>!) throws java.lang.NoSuchMethodException;
+ field protected final java.lang.reflect.Method! mAbortCreation;
+ field protected final java.lang.reflect.Method! mAddFontFromAssetManager;
+ field protected final java.lang.reflect.Method! mAddFontFromBuffer;
+ field protected final java.lang.reflect.Method! mCreateFromFamiliesWithDefault;
+ field protected final Class<?>! mFontFamily;
+ field protected final java.lang.reflect.Constructor<?>! mFontFamilyCtor;
+ field protected final java.lang.reflect.Method! mFreeze;
+ }
+
+ @RequiresApi(28) @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) public class TypefaceCompatApi28Impl extends androidx.core.graphics.TypefaceCompatApi26Impl {
+ ctor public TypefaceCompatApi28Impl();
+ }
+
+ @RequiresApi(29) @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP) public class TypefaceCompatApi29Impl {
+ ctor public TypefaceCompatApi29Impl();
+ method public android.graphics.Typeface? createFromFontFamilyFilesResourceEntry(android.content.Context!, androidx.core.content.res.FontResourcesParserCompat.FontFamilyFilesResourceEntry!, android.content.res.Resources!, int);
+ method public android.graphics.Typeface? createFromFontInfo(android.content.Context!, android.os.CancellationSignal?, androidx.core.provider.FontsContractCompat.FontInfo![], int);
+ method protected android.graphics.Typeface! createFromInputStream(android.content.Context!, java.io.InputStream!);
+ method public android.graphics.Typeface? createFromResourcesFontFile(android.content.Context!, android.content.res.Resources!, int, String!, int);
+ method protected androidx.core.provider.FontsContractCompat.FontInfo! findBestInfo(androidx.core.provider.FontsContractCompat.FontInfo![]!, int);
+ }
+
+ @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) public class TypefaceCompatUtil {
+ method public static void closeQuietly(java.io.Closeable?);
+ method @RequiresApi(19) public static java.nio.ByteBuffer? copyToDirectBuffer(android.content.Context, android.content.res.Resources, int);
+ method public static boolean copyToFile(java.io.File, java.io.InputStream);
+ method public static boolean copyToFile(java.io.File, android.content.res.Resources, int);
+ method public static java.io.File? getTempFile(android.content.Context);
+ method @RequiresApi(19) public static java.nio.ByteBuffer? mmap(android.content.Context, android.os.CancellationSignal?, android.net.Uri);
+ }
+
+}
+
+package androidx.core.graphics.drawable {
+
+ public final class DrawableCompat {
+ method public static void applyTheme(android.graphics.drawable.Drawable, android.content.res.Resources.Theme);
+ method public static boolean canApplyTheme(android.graphics.drawable.Drawable);
+ method public static void clearColorFilter(android.graphics.drawable.Drawable);
+ method public static int getAlpha(android.graphics.drawable.Drawable);
+ method public static android.graphics.ColorFilter? getColorFilter(android.graphics.drawable.Drawable);
+ method public static int getLayoutDirection(android.graphics.drawable.Drawable);
+ method public static void inflate(android.graphics.drawable.Drawable, android.content.res.Resources, org.xmlpull.v1.XmlPullParser, android.util.AttributeSet, android.content.res.Resources.Theme?) throws java.io.IOException, org.xmlpull.v1.XmlPullParserException;
+ method public static boolean isAutoMirrored(android.graphics.drawable.Drawable);
+ method @Deprecated public static void jumpToCurrentState(android.graphics.drawable.Drawable);
+ method public static void setAutoMirrored(android.graphics.drawable.Drawable, boolean);
+ method public static void setHotspot(android.graphics.drawable.Drawable, float, float);
+ method public static void setHotspotBounds(android.graphics.drawable.Drawable, int, int, int, int);
+ method public static boolean setLayoutDirection(android.graphics.drawable.Drawable, int);
+ method public static void setTint(android.graphics.drawable.Drawable, @ColorInt int);
+ method public static void setTintList(android.graphics.drawable.Drawable, android.content.res.ColorStateList?);
+ method public static void setTintMode(android.graphics.drawable.Drawable, android.graphics.PorterDuff.Mode?);
+ method public static <T extends android.graphics.drawable.Drawable> T! unwrap(android.graphics.drawable.Drawable);
+ method public static android.graphics.drawable.Drawable wrap(android.graphics.drawable.Drawable);
+ }
+
+ @androidx.versionedparcelable.VersionedParcelize(allowSerialization=true, ignoreParcelables=true, isCustom=true, jetifyAs="android.support.v4.graphics.drawable.IconCompat") public class IconCompat extends androidx.versionedparcelable.CustomVersionedParcelable {
+ method @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) public void addToShortcutIntent(android.content.Intent, android.graphics.drawable.Drawable?, android.content.Context);
+ method @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) public void checkResource(android.content.Context);
+ method public static androidx.core.graphics.drawable.IconCompat? createFromBundle(android.os.Bundle);
+ method @RequiresApi(23) public static androidx.core.graphics.drawable.IconCompat? createFromIcon(android.content.Context, android.graphics.drawable.Icon);
+ method @RequiresApi(23) @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) public static androidx.core.graphics.drawable.IconCompat? createFromIcon(android.graphics.drawable.Icon);
+ method @RequiresApi(23) @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) public static androidx.core.graphics.drawable.IconCompat? createFromIconOrNullIfZeroResId(android.graphics.drawable.Icon);
+ method public static androidx.core.graphics.drawable.IconCompat createWithAdaptiveBitmap(android.graphics.Bitmap);
+ method public static androidx.core.graphics.drawable.IconCompat createWithAdaptiveBitmapContentUri(String);
+ method public static androidx.core.graphics.drawable.IconCompat createWithAdaptiveBitmapContentUri(android.net.Uri);
+ method public static androidx.core.graphics.drawable.IconCompat createWithBitmap(android.graphics.Bitmap);
+ method public static androidx.core.graphics.drawable.IconCompat createWithContentUri(String);
+ method public static androidx.core.graphics.drawable.IconCompat createWithContentUri(android.net.Uri);
+ method public static androidx.core.graphics.drawable.IconCompat createWithData(byte[], int, int);
+ method public static androidx.core.graphics.drawable.IconCompat createWithResource(android.content.Context, @DrawableRes int);
+ method @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) public static androidx.core.graphics.drawable.IconCompat createWithResource(android.content.res.Resources?, String, @DrawableRes int);
+ method @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) public android.graphics.Bitmap? getBitmap();
+ method @DrawableRes public int getResId();
+ method public String getResPackage();
+ method public int getType();
+ method public android.net.Uri getUri();
+ method @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP) public java.io.InputStream? getUriInputStream(android.content.Context);
+ method public android.graphics.drawable.Drawable? loadDrawable(android.content.Context);
+ method public androidx.core.graphics.drawable.IconCompat setTint(@ColorInt int);
+ method public androidx.core.graphics.drawable.IconCompat setTintList(android.content.res.ColorStateList?);
+ method public androidx.core.graphics.drawable.IconCompat setTintMode(android.graphics.PorterDuff.Mode?);
+ method public android.os.Bundle toBundle();
+ method @Deprecated @RequiresApi(23) public android.graphics.drawable.Icon toIcon();
+ method @RequiresApi(23) public android.graphics.drawable.Icon toIcon(android.content.Context?);
+ field public static final int TYPE_ADAPTIVE_BITMAP = 5; // 0x5
+ field public static final int TYPE_BITMAP = 1; // 0x1
+ field public static final int TYPE_DATA = 3; // 0x3
+ field public static final int TYPE_RESOURCE = 2; // 0x2
+ field public static final int TYPE_UNKNOWN = -1; // 0xffffffff
+ field public static final int TYPE_URI = 4; // 0x4
+ field public static final int TYPE_URI_ADAPTIVE_BITMAP = 6; // 0x6
+ field @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) @androidx.versionedparcelable.ParcelField(value=1, defaultValue="androidx.core.graphics.drawable.IconCompat.TYPE_UNKNOWN") public int mType;
+ }
+
+ public abstract class RoundedBitmapDrawable extends android.graphics.drawable.Drawable {
+ method public void draw(android.graphics.Canvas);
+ method public final android.graphics.Bitmap? getBitmap();
+ method public float getCornerRadius();
+ method public int getGravity();
+ method public int getOpacity();
+ method public final android.graphics.Paint getPaint();
+ method public boolean hasAntiAlias();
+ method public boolean hasMipMap();
+ method public boolean isCircular();
+ method public void setAlpha(int);
+ method public void setAntiAlias(boolean);
+ method public void setCircular(boolean);
+ method public void setColorFilter(android.graphics.ColorFilter!);
+ method public void setCornerRadius(float);
+ method public void setDither(boolean);
+ method public void setGravity(int);
+ method public void setMipMap(boolean);
+ method public void setTargetDensity(android.graphics.Canvas);
+ method public void setTargetDensity(android.util.DisplayMetrics);
+ method public void setTargetDensity(int);
+ }
+
+ public final class RoundedBitmapDrawableFactory {
+ method public static androidx.core.graphics.drawable.RoundedBitmapDrawable create(android.content.res.Resources, android.graphics.Bitmap?);
+ method public static androidx.core.graphics.drawable.RoundedBitmapDrawable create(android.content.res.Resources, String);
+ method public static androidx.core.graphics.drawable.RoundedBitmapDrawable create(android.content.res.Resources, java.io.InputStream);
+ }
+
+ @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) public interface TintAwareDrawable {
+ method public void setTint(@ColorInt int);
+ method public void setTintList(android.content.res.ColorStateList!);
+ method public void setTintMode(android.graphics.PorterDuff.Mode!);
+ }
+
+ @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) public interface WrappedDrawable {
+ method public android.graphics.drawable.Drawable! getWrappedDrawable();
+ method public void setWrappedDrawable(android.graphics.drawable.Drawable!);
+ }
+
+}
+
+package androidx.core.hardware.display {
+
+ public final class DisplayManagerCompat {
+ method public android.view.Display? getDisplay(int);
+ method public android.view.Display![] getDisplays();
+ method public android.view.Display![] getDisplays(String?);
+ method public static androidx.core.hardware.display.DisplayManagerCompat getInstance(android.content.Context);
+ field public static final String DISPLAY_CATEGORY_PRESENTATION = "android.hardware.display.category.PRESENTATION";
+ }
+
+}
+
+package androidx.core.hardware.fingerprint {
+
+ @Deprecated public class FingerprintManagerCompat {
+ method @Deprecated @RequiresPermission(android.Manifest.permission.USE_FINGERPRINT) public void authenticate(androidx.core.hardware.fingerprint.FingerprintManagerCompat.CryptoObject?, int, androidx.core.os.CancellationSignal?, androidx.core.hardware.fingerprint.FingerprintManagerCompat.AuthenticationCallback, android.os.Handler?);
+ method @Deprecated public static androidx.core.hardware.fingerprint.FingerprintManagerCompat from(android.content.Context);
+ method @Deprecated @RequiresPermission(android.Manifest.permission.USE_FINGERPRINT) public boolean hasEnrolledFingerprints();
+ method @Deprecated @RequiresPermission(android.Manifest.permission.USE_FINGERPRINT) public boolean isHardwareDetected();
+ }
+
+ @Deprecated public abstract static class FingerprintManagerCompat.AuthenticationCallback {
+ ctor @Deprecated public FingerprintManagerCompat.AuthenticationCallback();
+ method @Deprecated public void onAuthenticationError(int, CharSequence!);
+ method @Deprecated public void onAuthenticationFailed();
+ method @Deprecated public void onAuthenticationHelp(int, CharSequence!);
+ method @Deprecated public void onAuthenticationSucceeded(androidx.core.hardware.fingerprint.FingerprintManagerCompat.AuthenticationResult!);
+ }
+
+ @Deprecated public static final class FingerprintManagerCompat.AuthenticationResult {
+ ctor @Deprecated public FingerprintManagerCompat.AuthenticationResult(androidx.core.hardware.fingerprint.FingerprintManagerCompat.CryptoObject!);
+ method @Deprecated public androidx.core.hardware.fingerprint.FingerprintManagerCompat.CryptoObject! getCryptoObject();
+ }
+
+ @Deprecated public static class FingerprintManagerCompat.CryptoObject {
+ ctor @Deprecated public FingerprintManagerCompat.CryptoObject(java.security.Signature);
+ ctor @Deprecated public FingerprintManagerCompat.CryptoObject(javax.crypto.Cipher);
+ ctor @Deprecated public FingerprintManagerCompat.CryptoObject(javax.crypto.Mac);
+ method @Deprecated public javax.crypto.Cipher? getCipher();
+ method @Deprecated public javax.crypto.Mac? getMac();
+ method @Deprecated public java.security.Signature? getSignature();
+ }
+
+}
+
+package androidx.core.internal.view {
+
+ @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) public interface SupportMenu extends android.view.Menu {
+ method public void setGroupDividerEnabled(boolean);
+ field public static final int CATEGORY_MASK = -65536; // 0xffff0000
+ field public static final int CATEGORY_SHIFT = 16; // 0x10
+ field public static final int FLAG_KEEP_OPEN_ON_SUBMENU_OPENED = 4; // 0x4
+ field public static final int SUPPORTED_MODIFIERS_MASK = 69647; // 0x1100f
+ field public static final int USER_MASK = 65535; // 0xffff
+ field public static final int USER_SHIFT = 0; // 0x0
+ }
+
+ @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) public interface SupportMenuItem extends android.view.MenuItem {
+ method public int getAlphabeticModifiers();
+ method public CharSequence? getContentDescription();
+ method public android.content.res.ColorStateList? getIconTintList();
+ method public android.graphics.PorterDuff.Mode? getIconTintMode();
+ method public int getNumericModifiers();
+ method public androidx.core.view.ActionProvider? getSupportActionProvider();
+ method public CharSequence? getTooltipText();
+ method public boolean requiresActionButton();
+ method public boolean requiresOverflow();
+ method public android.view.MenuItem setAlphabeticShortcut(char, int);
+ method public androidx.core.internal.view.SupportMenuItem setContentDescription(CharSequence?);
+ method public android.view.MenuItem setIconTintList(android.content.res.ColorStateList?);
+ method public android.view.MenuItem setIconTintMode(android.graphics.PorterDuff.Mode?);
+ method public android.view.MenuItem setNumericShortcut(char, int);
+ method public android.view.MenuItem setShortcut(char, char, int, int);
+ method public androidx.core.internal.view.SupportMenuItem setSupportActionProvider(androidx.core.view.ActionProvider?);
+ method public androidx.core.internal.view.SupportMenuItem setTooltipText(CharSequence?);
+ field public static final int SHOW_AS_ACTION_ALWAYS = 2; // 0x2
+ field public static final int SHOW_AS_ACTION_COLLAPSE_ACTION_VIEW = 8; // 0x8
+ field public static final int SHOW_AS_ACTION_IF_ROOM = 1; // 0x1
+ field public static final int SHOW_AS_ACTION_NEVER = 0; // 0x0
+ field public static final int SHOW_AS_ACTION_WITH_TEXT = 4; // 0x4
+ }
+
+ @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) public interface SupportSubMenu extends androidx.core.internal.view.SupportMenu android.view.SubMenu {
+ }
+
+}
+
+package androidx.core.location {
+
+ public abstract class GnssStatusCompat {
+ method @FloatRange(from=0, to=360) public abstract float getAzimuthDegrees(@IntRange(from=0) int);
+ method @FloatRange(from=0, to=63) public abstract float getBasebandCn0DbHz(@IntRange(from=0) int);
+ method @FloatRange(from=0) public abstract float getCarrierFrequencyHz(@IntRange(from=0) int);
+ method @FloatRange(from=0, to=63) public abstract float getCn0DbHz(@IntRange(from=0) int);
+ method public abstract int getConstellationType(@IntRange(from=0) int);
+ method @FloatRange(from=0xffffffa6, to=90) public abstract float getElevationDegrees(@IntRange(from=0) int);
+ method @IntRange(from=0) public abstract int getSatelliteCount();
+ method @IntRange(from=1, to=200) public abstract int getSvid(@IntRange(from=0) int);
+ method public abstract boolean hasAlmanacData(@IntRange(from=0) int);
+ method public abstract boolean hasBasebandCn0DbHz(@IntRange(from=0) int);
+ method public abstract boolean hasCarrierFrequencyHz(@IntRange(from=0) int);
+ method public abstract boolean hasEphemerisData(@IntRange(from=0) int);
+ method public abstract boolean usedInFix(@IntRange(from=0) int);
+ method @RequiresApi(android.os.Build.VERSION_CODES.N) public static androidx.core.location.GnssStatusCompat wrap(android.location.GnssStatus);
+ method public static androidx.core.location.GnssStatusCompat wrap(android.location.GpsStatus);
+ field public static final int CONSTELLATION_BEIDOU = 5; // 0x5
+ field public static final int CONSTELLATION_GALILEO = 6; // 0x6
+ field public static final int CONSTELLATION_GLONASS = 3; // 0x3
+ field public static final int CONSTELLATION_GPS = 1; // 0x1
+ field public static final int CONSTELLATION_IRNSS = 7; // 0x7
+ field public static final int CONSTELLATION_QZSS = 4; // 0x4
+ field public static final int CONSTELLATION_SBAS = 2; // 0x2
+ field public static final int CONSTELLATION_UNKNOWN = 0; // 0x0
+ }
+
+ public abstract static class GnssStatusCompat.Callback {
+ ctor public GnssStatusCompat.Callback();
+ method public void onFirstFix(@IntRange(from=0) int);
+ method public void onSatelliteStatusChanged(androidx.core.location.GnssStatusCompat);
+ method public void onStarted();
+ method public void onStopped();
+ }
+
+ public final class LocationCompat {
+ method public static float getBearingAccuracyDegrees(android.location.Location);
+ method public static long getElapsedRealtimeMillis(android.location.Location);
+ method public static long getElapsedRealtimeNanos(android.location.Location);
+ method @FloatRange(from=0.0) public static float getMslAltitudeAccuracyMeters(android.location.Location);
+ method public static double getMslAltitudeMeters(android.location.Location);
+ method public static float getSpeedAccuracyMetersPerSecond(android.location.Location);
+ method public static float getVerticalAccuracyMeters(android.location.Location);
+ method public static boolean hasBearingAccuracy(android.location.Location);
+ method public static boolean hasMslAltitude(android.location.Location);
+ method public static boolean hasMslAltitudeAccuracy(android.location.Location);
+ method public static boolean hasSpeedAccuracy(android.location.Location);
+ method public static boolean hasVerticalAccuracy(android.location.Location);
+ method public static boolean isMock(android.location.Location);
+ method public static void removeMslAltitude(android.location.Location);
+ method public static void removeMslAltitudeAccuracy(android.location.Location);
+ method public static void setBearingAccuracyDegrees(android.location.Location, float);
+ method public static void setMock(android.location.Location, boolean);
+ method public static void setMslAltitudeAccuracyMeters(android.location.Location, @FloatRange(from=0.0) float);
+ method public static void setMslAltitudeMeters(android.location.Location, double);
+ method public static void setSpeedAccuracyMetersPerSecond(android.location.Location, float);
+ method public static void setVerticalAccuracyMeters(android.location.Location, float);
+ field public static final String EXTRA_BEARING_ACCURACY = "bearingAccuracy";
+ field public static final String EXTRA_IS_MOCK = "mockLocation";
+ field public static final String EXTRA_MSL_ALTITUDE = "androidx.core.location.extra.MSL_ALTITUDE";
+ field public static final String EXTRA_MSL_ALTITUDE_ACCURACY = "androidx.core.location.extra.MSL_ALTITUDE_ACCURACY";
+ field public static final String EXTRA_SPEED_ACCURACY = "speedAccuracy";
+ field public static final String EXTRA_VERTICAL_ACCURACY = "verticalAccuracy";
+ }
+
+ public interface LocationListenerCompat extends android.location.LocationListener {
+ method public default void onStatusChanged(String, int, android.os.Bundle?);
+ }
+
+ public final class LocationManagerCompat {
+ method @RequiresPermission(anyOf={android.Manifest.permission.ACCESS_COARSE_LOCATION, android.Manifest.permission.ACCESS_FINE_LOCATION}) public static void getCurrentLocation(android.location.LocationManager, String, androidx.core.os.CancellationSignal?, java.util.concurrent.Executor, androidx.core.util.Consumer<android.location.Location!>);
+ method public static String? getGnssHardwareModelName(android.location.LocationManager);
+ method public static int getGnssYearOfHardware(android.location.LocationManager);
+ method public static boolean hasProvider(android.location.LocationManager, String);
+ method public static boolean isLocationEnabled(android.location.LocationManager);
+ method @RequiresApi(android.os.Build.VERSION_CODES.N) @RequiresPermission(android.Manifest.permission.ACCESS_FINE_LOCATION) public static boolean registerGnssMeasurementsCallback(android.location.LocationManager, android.location.GnssMeasurementsEvent.Callback, android.os.Handler);
+ method @RequiresApi(android.os.Build.VERSION_CODES.R) @RequiresPermission(android.Manifest.permission.ACCESS_FINE_LOCATION) public static boolean registerGnssMeasurementsCallback(android.location.LocationManager, java.util.concurrent.Executor, android.location.GnssMeasurementsEvent.Callback);
+ method @RequiresPermission(android.Manifest.permission.ACCESS_FINE_LOCATION) public static boolean registerGnssStatusCallback(android.location.LocationManager, androidx.core.location.GnssStatusCompat.Callback, android.os.Handler);
+ method @RequiresPermission(android.Manifest.permission.ACCESS_FINE_LOCATION) public static boolean registerGnssStatusCallback(android.location.LocationManager, java.util.concurrent.Executor, androidx.core.location.GnssStatusCompat.Callback);
+ method @RequiresPermission(anyOf={android.Manifest.permission.ACCESS_COARSE_LOCATION, android.Manifest.permission.ACCESS_FINE_LOCATION}) public static void removeUpdates(android.location.LocationManager, androidx.core.location.LocationListenerCompat);
+ method @RequiresPermission(anyOf={android.Manifest.permission.ACCESS_COARSE_LOCATION, android.Manifest.permission.ACCESS_FINE_LOCATION}) public static void requestLocationUpdates(android.location.LocationManager, String, androidx.core.location.LocationRequestCompat, 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 @RequiresApi(android.os.Build.VERSION_CODES.N) public static void unregisterGnssMeasurementsCallback(android.location.LocationManager, android.location.GnssMeasurementsEvent.Callback);
+ method public static void unregisterGnssStatusCallback(android.location.LocationManager, androidx.core.location.GnssStatusCompat.Callback);
+ }
+
+ public final class LocationRequestCompat {
+ method @IntRange(from=1) public long getDurationMillis();
+ method @IntRange(from=0) public long getIntervalMillis();
+ method @IntRange(from=0) public long getMaxUpdateDelayMillis();
+ method @IntRange(from=1, to=java.lang.Integer.MAX_VALUE) public int getMaxUpdates();
+ method @FloatRange(from=0, to=java.lang.Float.MAX_VALUE) public float getMinUpdateDistanceMeters();
+ method @IntRange(from=0) public long getMinUpdateIntervalMillis();
+ method public int getQuality();
+ method @RequiresApi(31) public android.location.LocationRequest toLocationRequest();
+ method @RequiresApi(19) public android.location.LocationRequest? toLocationRequest(String);
+ field public static final long PASSIVE_INTERVAL = 9223372036854775807L; // 0x7fffffffffffffffL
+ field public static final int QUALITY_BALANCED_POWER_ACCURACY = 102; // 0x66
+ field public static final int QUALITY_HIGH_ACCURACY = 100; // 0x64
+ field public static final int QUALITY_LOW_POWER = 104; // 0x68
+ }
+
+ public static final class LocationRequestCompat.Builder {
+ ctor public LocationRequestCompat.Builder(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 {
+
+ public class MathUtils {
+ method public static int addExact(int, int);
+ method public static long addExact(long, long);
+ method public static float clamp(float, float, float);
+ method public static double clamp(double, double, double);
+ method public static int clamp(int, int, int);
+ method public static long clamp(long, long, long);
+ method public static int decrementExact(int);
+ method public static long decrementExact(long);
+ method public static int incrementExact(int);
+ method public static long incrementExact(long);
+ method public static int multiplyExact(int, int);
+ method public static long multiplyExact(long, long);
+ method public static int negateExact(int);
+ method public static long negateExact(long);
+ method public static int subtractExact(int, int);
+ method public static long subtractExact(long, long);
+ method public static int toIntExact(long);
+ }
+
+}
+
+package androidx.core.net {
+
+ public final class ConnectivityManagerCompat {
+ method @RequiresPermission(android.Manifest.permission.ACCESS_NETWORK_STATE) public static android.net.NetworkInfo? getNetworkInfoFromBroadcast(android.net.ConnectivityManager, android.content.Intent);
+ method @androidx.core.net.ConnectivityManagerCompat.RestrictBackgroundStatus public static int getRestrictBackgroundStatus(android.net.ConnectivityManager);
+ method @RequiresPermission(android.Manifest.permission.ACCESS_NETWORK_STATE) public static boolean isActiveNetworkMetered(android.net.ConnectivityManager);
+ field public static final int RESTRICT_BACKGROUND_STATUS_DISABLED = 1; // 0x1
+ field public static final int RESTRICT_BACKGROUND_STATUS_ENABLED = 3; // 0x3
+ field public static final int RESTRICT_BACKGROUND_STATUS_WHITELISTED = 2; // 0x2
+ }
+
+ @IntDef({androidx.core.net.ConnectivityManagerCompat.RESTRICT_BACKGROUND_STATUS_DISABLED, androidx.core.net.ConnectivityManagerCompat.RESTRICT_BACKGROUND_STATUS_WHITELISTED, androidx.core.net.ConnectivityManagerCompat.RESTRICT_BACKGROUND_STATUS_ENABLED}) @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.SOURCE) public static @interface ConnectivityManagerCompat.RestrictBackgroundStatus {
+ }
+
+ public final class MailTo {
+ method public String? getBcc();
+ method public String? getBody();
+ method public String? getCc();
+ method public java.util.Map<java.lang.String!,java.lang.String!>? getHeaders();
+ method public String? getSubject();
+ method public String? getTo();
+ method public static boolean isMailTo(String?);
+ method public static boolean isMailTo(android.net.Uri?);
+ method public static androidx.core.net.MailTo parse(String) throws androidx.core.net.ParseException;
+ method public static androidx.core.net.MailTo parse(android.net.Uri) throws androidx.core.net.ParseException;
+ field public static final String MAILTO_SCHEME = "mailto:";
+ }
+
+ public class ParseException extends java.lang.RuntimeException {
+ field public final String response;
+ }
+
+ public final class TrafficStatsCompat {
+ method @Deprecated public static void clearThreadStatsTag();
+ method @Deprecated public static int getThreadStatsTag();
+ method @Deprecated public static void incrementOperationCount(int);
+ method @Deprecated public static void incrementOperationCount(int, int);
+ method @Deprecated public static void setThreadStatsTag(int);
+ method public static void tagDatagramSocket(java.net.DatagramSocket) throws java.net.SocketException;
+ method @Deprecated public static void tagSocket(java.net.Socket!) throws java.net.SocketException;
+ method public static void untagDatagramSocket(java.net.DatagramSocket) throws java.net.SocketException;
+ method @Deprecated public static void untagSocket(java.net.Socket!) throws java.net.SocketException;
+ }
+
+ public final class UriCompat {
+ method public static String toSafeString(android.net.Uri);
+ }
+
+}
+
+package androidx.core.os {
+
+ public class BuildCompat {
+ method @Deprecated @ChecksSdkIntAtLeast(api=android.os.Build.VERSION_CODES.N) public static boolean isAtLeastN();
+ method @Deprecated @ChecksSdkIntAtLeast(api=android.os.Build.VERSION_CODES.N_MR1) public static boolean isAtLeastNMR1();
+ method @Deprecated @ChecksSdkIntAtLeast(api=android.os.Build.VERSION_CODES.O) public static boolean isAtLeastO();
+ method @Deprecated @ChecksSdkIntAtLeast(api=android.os.Build.VERSION_CODES.O_MR1) public static boolean isAtLeastOMR1();
+ method @Deprecated @ChecksSdkIntAtLeast(api=android.os.Build.VERSION_CODES.P) public static boolean isAtLeastP();
+ method @Deprecated @ChecksSdkIntAtLeast(api=android.os.Build.VERSION_CODES.Q) public static boolean isAtLeastQ();
+ method @Deprecated @ChecksSdkIntAtLeast(api=android.os.Build.VERSION_CODES.R) public static boolean isAtLeastR();
+ method @Deprecated @ChecksSdkIntAtLeast(api=31, codename="S") public static boolean isAtLeastS();
+ field @ChecksSdkIntAtLeast(extension=android.os.ext.SdkExtensions.AD_SERVICES) public static final int AD_SERVICES_EXTENSION_INT;
+ field @ChecksSdkIntAtLeast(extension=android.os.Build.VERSION_CODES.R) public static final int R_EXTENSION_INT;
+ field @ChecksSdkIntAtLeast(extension=android.os.Build.VERSION_CODES.S) public static final int S_EXTENSION_INT;
+ field @ChecksSdkIntAtLeast(extension=android.os.Build.VERSION_CODES.TIRAMISU) public static final int T_EXTENSION_INT;
+ }
+
+ public final class BundleCompat {
+ method public static <T> T? getParcelable(android.os.Bundle, String?, Class<T!>);
+ method public static android.os.Parcelable![]? getParcelableArray(android.os.Bundle, String?, Class<? extends android.os.Parcelable>);
+ method public static <T> java.util.ArrayList<T!>? getParcelableArrayList(android.os.Bundle, String?, Class<? extends T>);
+ method public static <T> android.util.SparseArray<T!>? getSparseParcelableArray(android.os.Bundle, String?, Class<? extends T>);
+ }
+
+ public final class CancellationSignal {
+ ctor public CancellationSignal();
+ method public void cancel();
+ method public Object? getCancellationSignalObject();
+ method public boolean isCanceled();
+ method public void setOnCancelListener(androidx.core.os.CancellationSignal.OnCancelListener?);
+ method public void throwIfCanceled();
+ }
+
+ public static interface CancellationSignal.OnCancelListener {
+ method public void onCancel();
+ }
+
+ public final class ConfigurationCompat {
+ method public static androidx.core.os.LocaleListCompat getLocales(android.content.res.Configuration);
+ }
+
+ public final class EnvironmentCompat {
+ method public static String getStorageState(java.io.File);
+ field public static final String MEDIA_UNKNOWN = "unknown";
+ }
+
+ public final class ExecutorCompat {
+ method public static java.util.concurrent.Executor create(android.os.Handler);
+ }
+
+ public final class HandlerCompat {
+ method public static android.os.Handler createAsync(android.os.Looper);
+ method public static android.os.Handler createAsync(android.os.Looper, android.os.Handler.Callback);
+ method @RequiresApi(16) public static boolean hasCallbacks(android.os.Handler, Runnable);
+ method public static boolean postDelayed(android.os.Handler, Runnable, Object?, long);
+ }
+
+ public final class LocaleListCompat {
+ method public static androidx.core.os.LocaleListCompat create(java.util.Locale!...);
+ method public static androidx.core.os.LocaleListCompat forLanguageTags(String?);
+ method public java.util.Locale? get(int);
+ method @Size(min=1) public static androidx.core.os.LocaleListCompat getAdjustedDefault();
+ method @Size(min=1) public static androidx.core.os.LocaleListCompat getDefault();
+ method public static androidx.core.os.LocaleListCompat getEmptyLocaleList();
+ method public java.util.Locale? getFirstMatch(String![]);
+ method @IntRange(from=0xffffffff) public int indexOf(java.util.Locale?);
+ method public boolean isEmpty();
+ method @RequiresApi(21) public static boolean matchesLanguageAndScript(java.util.Locale, java.util.Locale);
+ method @IntRange(from=0) public int size();
+ method public String toLanguageTags();
+ method public Object? unwrap();
+ method @Deprecated @RequiresApi(24) public static androidx.core.os.LocaleListCompat! wrap(Object!);
+ method @RequiresApi(24) public static androidx.core.os.LocaleListCompat wrap(android.os.LocaleList);
+ }
+
+ public final class MessageCompat {
+ method public static boolean isAsynchronous(android.os.Message);
+ method public static void setAsynchronous(android.os.Message, boolean);
+ }
+
+ public class OperationCanceledException extends java.lang.RuntimeException {
+ ctor public OperationCanceledException();
+ ctor public OperationCanceledException(String?);
+ }
+
+ public final class ParcelCompat {
+ method public static <T> Object![]? readArray(android.os.Parcel, ClassLoader?, Class<T!>);
+ method public static <T> java.util.ArrayList<T!>? readArrayList(android.os.Parcel, ClassLoader?, Class<? extends T>);
+ method public static boolean readBoolean(android.os.Parcel);
+ method public static <K, V> java.util.HashMap<K!,V!>? readHashMap(android.os.Parcel, ClassLoader?, Class<? extends K>, Class<? extends V>);
+ method public static <T> void readList(android.os.Parcel, java.util.List<? super T>, ClassLoader?, Class<T!>);
+ method public static <K, V> void readMap(android.os.Parcel, java.util.Map<? super K,? super V>, ClassLoader?, Class<K!>, Class<V!>);
+ method public static <T extends android.os.Parcelable> T? readParcelable(android.os.Parcel, ClassLoader?, Class<T!>);
+ method @Deprecated public static <T> T![]? readParcelableArray(android.os.Parcel, ClassLoader?, Class<T!>);
+ method public static <T> android.os.Parcelable![]? readParcelableArrayTyped(android.os.Parcel, ClassLoader?, Class<T!>);
+ method @RequiresApi(30) public static <T> android.os.Parcelable.Creator<T!>? readParcelableCreator(android.os.Parcel, ClassLoader?, Class<T!>);
+ method @RequiresApi(api=android.os.Build.VERSION_CODES.Q) public static <T> java.util.List<T!> readParcelableList(android.os.Parcel, java.util.List<T!>, ClassLoader?, Class<T!>);
+ method public static <T extends java.io.Serializable> T? readSerializable(android.os.Parcel, ClassLoader?, Class<T!>);
+ method public static <T> android.util.SparseArray<T!>? readSparseArray(android.os.Parcel, ClassLoader?, Class<? extends T>);
+ method public static void writeBoolean(android.os.Parcel, boolean);
+ }
+
+ @Deprecated public final class ParcelableCompat {
+ method @Deprecated public static <T> android.os.Parcelable.Creator<T!>! newCreator(androidx.core.os.ParcelableCompatCreatorCallbacks<T!>!);
+ }
+
+ @Deprecated public interface ParcelableCompatCreatorCallbacks<T> {
+ method @Deprecated public T! createFromParcel(android.os.Parcel!, ClassLoader!);
+ method @Deprecated public T![]! newArray(int);
+ }
+
+ public final class ProcessCompat {
+ method public static boolean isApplicationUid(int);
+ }
+
+ @Deprecated public final class TraceCompat {
+ method @Deprecated public static void beginAsyncSection(String, int);
+ method @Deprecated public static void beginSection(String);
+ method @Deprecated public static void endAsyncSection(String, int);
+ method @Deprecated public static void endSection();
+ method @Deprecated public static boolean isEnabled();
+ method @Deprecated public static void setCounter(String, int);
+ }
+
+ @RequiresApi(17) public class UserHandleCompat {
+ method public static android.os.UserHandle getUserHandleForUid(int);
+ }
+
+ public class UserManagerCompat {
+ method public static boolean isUserUnlocked(android.content.Context);
+ }
+
+}
+
+package androidx.core.provider {
+
+ public final class DocumentsContractCompat {
+ method public static android.net.Uri? buildChildDocumentsUri(String, String?);
+ method public static android.net.Uri? buildChildDocumentsUriUsingTree(android.net.Uri, String);
+ method public static android.net.Uri? buildDocumentUri(String, String);
+ method public static android.net.Uri? buildDocumentUriUsingTree(android.net.Uri, String);
+ method public static android.net.Uri? buildTreeDocumentUri(String, String);
+ method public static android.net.Uri? createDocument(android.content.ContentResolver, android.net.Uri, String, String) throws java.io.FileNotFoundException;
+ method public static String? getDocumentId(android.net.Uri);
+ method public static String? getTreeDocumentId(android.net.Uri);
+ method public static boolean isDocumentUri(android.content.Context, android.net.Uri?);
+ method public static boolean isTreeUri(android.net.Uri);
+ method public static boolean removeDocument(android.content.ContentResolver, android.net.Uri, android.net.Uri) throws java.io.FileNotFoundException;
+ method public static android.net.Uri? renameDocument(android.content.ContentResolver, android.net.Uri, String) throws java.io.FileNotFoundException;
+ }
+
+ public static final class DocumentsContractCompat.DocumentCompat {
+ field public static final int FLAG_VIRTUAL_DOCUMENT = 512; // 0x200
+ }
+
+ public final class FontRequest {
+ ctor public FontRequest(String, String, String, java.util.List<java.util.List<byte[]!>!>);
+ ctor public FontRequest(String, String, String, @ArrayRes int);
+ method public java.util.List<java.util.List<byte[]!>!>? getCertificates();
+ method @ArrayRes public int getCertificatesArrayResId();
+ method @Deprecated @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) public String! getIdentifier();
+ method public String getProviderAuthority();
+ method public String getProviderPackage();
+ method public String getQuery();
+ }
+
+ public class FontsContractCompat {
+ method public static android.graphics.Typeface? buildTypeface(android.content.Context, android.os.CancellationSignal?, androidx.core.provider.FontsContractCompat.FontInfo![]);
+ method public static androidx.core.provider.FontsContractCompat.FontFamilyResult fetchFonts(android.content.Context, android.os.CancellationSignal?, androidx.core.provider.FontRequest) throws android.content.pm.PackageManager.NameNotFoundException;
+ method @Deprecated @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) public static android.graphics.Typeface! getFontSync(android.content.Context!, androidx.core.provider.FontRequest!, androidx.core.content.res.ResourcesCompat.FontCallback?, android.os.Handler?, boolean, int, int);
+ method @Deprecated @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) @VisibleForTesting public static android.content.pm.ProviderInfo? getProvider(android.content.pm.PackageManager, androidx.core.provider.FontRequest, android.content.res.Resources?) throws android.content.pm.PackageManager.NameNotFoundException;
+ method @Deprecated @RequiresApi(19) @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) public static java.util.Map<android.net.Uri!,java.nio.ByteBuffer!>! prepareFontData(android.content.Context!, androidx.core.provider.FontsContractCompat.FontInfo![]!, android.os.CancellationSignal!);
+ method public static void requestFont(android.content.Context, androidx.core.provider.FontRequest, androidx.core.provider.FontsContractCompat.FontRequestCallback, android.os.Handler);
+ method @Deprecated @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) public static void resetCache();
+ field @Deprecated @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) public static final String PARCEL_FONT_RESULTS = "font_results";
+ }
+
+ public static final class FontsContractCompat.Columns implements android.provider.BaseColumns {
+ ctor public FontsContractCompat.Columns();
+ field public static final String FILE_ID = "file_id";
+ field public static final String ITALIC = "font_italic";
+ field public static final String RESULT_CODE = "result_code";
+ field public static final int RESULT_CODE_FONT_NOT_FOUND = 1; // 0x1
+ field public static final int RESULT_CODE_FONT_UNAVAILABLE = 2; // 0x2
+ field public static final int RESULT_CODE_MALFORMED_QUERY = 3; // 0x3
+ field public static final int RESULT_CODE_OK = 0; // 0x0
+ field public static final String TTC_INDEX = "font_ttc_index";
+ field public static final String VARIATION_SETTINGS = "font_variation_settings";
+ field public static final String WEIGHT = "font_weight";
+ }
+
+ public static class FontsContractCompat.FontFamilyResult {
+ ctor @Deprecated @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) public FontsContractCompat.FontFamilyResult(int, androidx.core.provider.FontsContractCompat.FontInfo![]?);
+ method public androidx.core.provider.FontsContractCompat.FontInfo![]! getFonts();
+ method public int getStatusCode();
+ field public static final int STATUS_OK = 0; // 0x0
+ field public static final int STATUS_UNEXPECTED_DATA_PROVIDED = 2; // 0x2
+ field public static final int STATUS_WRONG_CERTIFICATES = 1; // 0x1
+ }
+
+ public static class FontsContractCompat.FontInfo {
+ ctor @Deprecated @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) public FontsContractCompat.FontInfo(android.net.Uri, @IntRange(from=0) int, @IntRange(from=1, to=1000) int, boolean, int);
+ method public int getResultCode();
+ method @IntRange(from=0) public int getTtcIndex();
+ method public android.net.Uri getUri();
+ method @IntRange(from=1, to=1000) public int getWeight();
+ method public boolean isItalic();
+ }
+
+ public static class FontsContractCompat.FontRequestCallback {
+ ctor public FontsContractCompat.FontRequestCallback();
+ method public void onTypefaceRequestFailed(@androidx.core.provider.FontsContractCompat.FontRequestCallback.FontRequestFailReason int);
+ method public void onTypefaceRetrieved(android.graphics.Typeface!);
+ field public static final int FAIL_REASON_FONT_LOAD_ERROR = -3; // 0xfffffffd
+ field public static final int FAIL_REASON_FONT_NOT_FOUND = 1; // 0x1
+ field public static final int FAIL_REASON_FONT_UNAVAILABLE = 2; // 0x2
+ field public static final int FAIL_REASON_MALFORMED_QUERY = 3; // 0x3
+ field public static final int FAIL_REASON_PROVIDER_NOT_FOUND = -1; // 0xffffffff
+ field public static final int FAIL_REASON_SECURITY_VIOLATION = -4; // 0xfffffffc
+ field public static final int FAIL_REASON_WRONG_CERTIFICATES = -2; // 0xfffffffe
+ field @Deprecated @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) public static final int RESULT_OK = 0; // 0x0
+ }
+
+ @IntDef({androidx.core.provider.FontsContractCompat.FontRequestCallback.FAIL_REASON_PROVIDER_NOT_FOUND, androidx.core.provider.FontsContractCompat.FontRequestCallback.FAIL_REASON_FONT_LOAD_ERROR, androidx.core.provider.FontsContractCompat.FontRequestCallback.FAIL_REASON_FONT_NOT_FOUND, androidx.core.provider.FontsContractCompat.FontRequestCallback.FAIL_REASON_FONT_UNAVAILABLE, androidx.core.provider.FontsContractCompat.FontRequestCallback.FAIL_REASON_MALFORMED_QUERY, androidx.core.provider.FontsContractCompat.FontRequestCallback.FAIL_REASON_WRONG_CERTIFICATES, androidx.core.provider.FontsContractCompat.FontRequestCallback.FAIL_REASON_SECURITY_VIOLATION, androidx.core.provider.FontsContractCompat.FontRequestCallback.RESULT_OK}) @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.SOURCE) public static @interface FontsContractCompat.FontRequestCallback.FontRequestFailReason {
+ }
+
+ @Deprecated @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) public class SelfDestructiveThread {
+ ctor @Deprecated public SelfDestructiveThread(String!, int, int);
+ method @Deprecated @VisibleForTesting public int getGeneration();
+ method @Deprecated @VisibleForTesting public boolean isRunning();
+ method @Deprecated public <T> void postAndReply(java.util.concurrent.Callable<T!>!, androidx.core.provider.SelfDestructiveThread.ReplyCallback<T!>!);
+ method @Deprecated public <T> T! postAndWait(java.util.concurrent.Callable<T!>!, int) throws java.lang.InterruptedException;
+ }
+
+ @Deprecated public static interface SelfDestructiveThread.ReplyCallback<T> {
+ method @Deprecated public void onReply(T!);
+ }
+
+}
+
+package androidx.core.telephony {
+
+ @RequiresApi(22) public class SubscriptionManagerCompat {
+ method public static int getSlotIndex(int);
+ }
+
+ public class TelephonyManagerCompat {
+ method @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE) public static String? getImei(android.telephony.TelephonyManager);
+ method public static int getSubscriptionId(android.telephony.TelephonyManager);
+ }
+
+}
+
+package androidx.core.telephony.mbms {
+
+ public final class MbmsHelper {
+ method public static CharSequence? getBestNameForService(android.content.Context, android.telephony.mbms.ServiceInfo);
+ }
+
+}
+
+package androidx.core.text {
+
+ public final class BidiFormatter {
+ method public static androidx.core.text.BidiFormatter! getInstance();
+ method public static androidx.core.text.BidiFormatter! getInstance(boolean);
+ method public static androidx.core.text.BidiFormatter! getInstance(java.util.Locale!);
+ method public boolean getStereoReset();
+ method public boolean isRtl(String!);
+ method public boolean isRtl(CharSequence!);
+ method public boolean isRtlContext();
+ method public String! unicodeWrap(String!, androidx.core.text.TextDirectionHeuristicCompat!, boolean);
+ method public CharSequence! unicodeWrap(CharSequence!, androidx.core.text.TextDirectionHeuristicCompat!, boolean);
+ method public String! unicodeWrap(String!, androidx.core.text.TextDirectionHeuristicCompat!);
+ method public CharSequence! unicodeWrap(CharSequence!, androidx.core.text.TextDirectionHeuristicCompat!);
+ method public String! unicodeWrap(String!, boolean);
+ method public CharSequence! unicodeWrap(CharSequence!, boolean);
+ method public String! unicodeWrap(String!);
+ method public CharSequence! unicodeWrap(CharSequence!);
+ }
+
+ public static final class BidiFormatter.Builder {
+ ctor public BidiFormatter.Builder();
+ ctor public BidiFormatter.Builder(boolean);
+ ctor public BidiFormatter.Builder(java.util.Locale!);
+ method public androidx.core.text.BidiFormatter! build();
+ method public androidx.core.text.BidiFormatter.Builder! setTextDirectionHeuristic(androidx.core.text.TextDirectionHeuristicCompat!);
+ method public androidx.core.text.BidiFormatter.Builder! stereoReset(boolean);
+ }
+
+ public final class HtmlCompat {
+ method public static android.text.Spanned fromHtml(String, int);
+ method public static android.text.Spanned fromHtml(String, int, android.text.Html.ImageGetter?, android.text.Html.TagHandler?);
+ method public static String toHtml(android.text.Spanned, int);
+ field public static final int FROM_HTML_MODE_COMPACT = 63; // 0x3f
+ field public static final int FROM_HTML_MODE_LEGACY = 0; // 0x0
+ field public static final int FROM_HTML_OPTION_USE_CSS_COLORS = 256; // 0x100
+ field public static final int FROM_HTML_SEPARATOR_LINE_BREAK_BLOCKQUOTE = 32; // 0x20
+ field public static final int FROM_HTML_SEPARATOR_LINE_BREAK_DIV = 16; // 0x10
+ field public static final int FROM_HTML_SEPARATOR_LINE_BREAK_HEADING = 2; // 0x2
+ field public static final int FROM_HTML_SEPARATOR_LINE_BREAK_LIST = 8; // 0x8
+ field public static final int FROM_HTML_SEPARATOR_LINE_BREAK_LIST_ITEM = 4; // 0x4
+ field public static final int FROM_HTML_SEPARATOR_LINE_BREAK_PARAGRAPH = 1; // 0x1
+ field public static final int TO_HTML_PARAGRAPH_LINES_CONSECUTIVE = 0; // 0x0
+ field public static final int TO_HTML_PARAGRAPH_LINES_INDIVIDUAL = 1; // 0x1
+ }
+
+ public final class ICUCompat {
+ method public static String? maximizeAndGetScript(java.util.Locale);
+ }
+
+ public class PrecomputedTextCompat implements android.text.Spannable {
+ method public char charAt(int);
+ method public static androidx.core.text.PrecomputedTextCompat! create(CharSequence, androidx.core.text.PrecomputedTextCompat.Params);
+ method @IntRange(from=0) public int getParagraphCount();
+ method @IntRange(from=0) public int getParagraphEnd(@IntRange(from=0) int);
+ method @IntRange(from=0) public int getParagraphStart(@IntRange(from=0) int);
+ method public androidx.core.text.PrecomputedTextCompat.Params getParams();
+ method @RequiresApi(28) @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) public android.text.PrecomputedText? getPrecomputedText();
+ method public int getSpanEnd(Object!);
+ method public int getSpanFlags(Object!);
+ method public int getSpanStart(Object!);
+ method public <T> T![]! getSpans(int, int, Class<T!>!);
+ method @UiThread public static java.util.concurrent.Future<androidx.core.text.PrecomputedTextCompat!>! getTextFuture(CharSequence, androidx.core.text.PrecomputedTextCompat.Params, java.util.concurrent.Executor?);
+ method public int length();
+ method public int nextSpanTransition(int, int, Class!);
+ method public void removeSpan(Object!);
+ method public void setSpan(Object!, int, int, int);
+ method public CharSequence! subSequence(int, int);
+ }
+
+ public static final class PrecomputedTextCompat.Params {
+ ctor @RequiresApi(28) public PrecomputedTextCompat.Params(android.text.PrecomputedText.Params);
+ method @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) public boolean equalsWithoutTextDirection(androidx.core.text.PrecomputedTextCompat.Params);
+ method @RequiresApi(23) public int getBreakStrategy();
+ method @RequiresApi(23) public int getHyphenationFrequency();
+ method @RequiresApi(18) public android.text.TextDirectionHeuristic? getTextDirection();
+ method public android.text.TextPaint getTextPaint();
+ }
+
+ public static class PrecomputedTextCompat.Params.Builder {
+ ctor public PrecomputedTextCompat.Params.Builder(android.text.TextPaint);
+ method public androidx.core.text.PrecomputedTextCompat.Params build();
+ method @RequiresApi(23) public androidx.core.text.PrecomputedTextCompat.Params.Builder! setBreakStrategy(int);
+ method @RequiresApi(23) public androidx.core.text.PrecomputedTextCompat.Params.Builder! setHyphenationFrequency(int);
+ method @RequiresApi(18) public androidx.core.text.PrecomputedTextCompat.Params.Builder! setTextDirection(android.text.TextDirectionHeuristic);
+ }
+
+ public interface TextDirectionHeuristicCompat {
+ method public boolean isRtl(char[]!, int, int);
+ method public boolean isRtl(CharSequence!, int, int);
+ }
+
+ public final class TextDirectionHeuristicsCompat {
+ field public static final androidx.core.text.TextDirectionHeuristicCompat! ANYRTL_LTR;
+ field public static final androidx.core.text.TextDirectionHeuristicCompat! FIRSTSTRONG_LTR;
+ field public static final androidx.core.text.TextDirectionHeuristicCompat! FIRSTSTRONG_RTL;
+ field public static final androidx.core.text.TextDirectionHeuristicCompat! LOCALE;
+ field public static final androidx.core.text.TextDirectionHeuristicCompat! LTR;
+ field public static final androidx.core.text.TextDirectionHeuristicCompat! RTL;
+ }
+
+ public final class TextUtilsCompat {
+ method public static int getLayoutDirectionFromLocale(java.util.Locale?);
+ method public static String htmlEncode(String);
+ }
+
+}
+
+package androidx.core.text.util {
+
+ public final class LinkifyCompat {
+ method public static boolean addLinks(android.text.Spannable, @androidx.core.text.util.LinkifyCompat.LinkifyMask int);
+ method public static boolean addLinks(android.widget.TextView, @androidx.core.text.util.LinkifyCompat.LinkifyMask int);
+ method public static void addLinks(android.widget.TextView, java.util.regex.Pattern, String?);
+ method public static void addLinks(android.widget.TextView, java.util.regex.Pattern, String?, android.text.util.Linkify.MatchFilter?, android.text.util.Linkify.TransformFilter?);
+ method public static void addLinks(android.widget.TextView, java.util.regex.Pattern, String?, String![]?, android.text.util.Linkify.MatchFilter?, android.text.util.Linkify.TransformFilter?);
+ method public static boolean addLinks(android.text.Spannable, java.util.regex.Pattern, String?);
+ method public static boolean addLinks(android.text.Spannable, java.util.regex.Pattern, String?, android.text.util.Linkify.MatchFilter?, android.text.util.Linkify.TransformFilter?);
+ method public static boolean addLinks(android.text.Spannable, java.util.regex.Pattern, String?, String![]?, android.text.util.Linkify.MatchFilter?, android.text.util.Linkify.TransformFilter?);
+ }
+
+ @IntDef(flag=true, value={android.text.util.Linkify.WEB_URLS, android.text.util.Linkify.EMAIL_ADDRESSES, android.text.util.Linkify.PHONE_NUMBERS, android.text.util.Linkify.MAP_ADDRESSES, android.text.util.Linkify.ALL}) @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.SOURCE) public static @interface LinkifyCompat.LinkifyMask {
+ }
+
+}
+
+package androidx.core.util {
+
+ public class AtomicFile {
+ ctor public AtomicFile(java.io.File);
+ method public void delete();
+ method public void failWrite(java.io.FileOutputStream?);
+ method public void finishWrite(java.io.FileOutputStream?);
+ method public java.io.File getBaseFile();
+ method public java.io.FileInputStream openRead() throws java.io.FileNotFoundException;
+ method public byte[] readFully() throws java.io.IOException;
+ method public java.io.FileOutputStream startWrite() throws java.io.IOException;
+ }
+
+ public interface Consumer<T> {
+ method public void accept(T!);
+ }
+
+ @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) public class DebugUtils {
+ method public static void buildShortClassTag(Object!, StringBuilder!);
+ }
+
+ @Deprecated @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) public class LogWriter extends java.io.Writer {
+ ctor @Deprecated public LogWriter(String!);
+ method @Deprecated public void close();
+ method @Deprecated public void flush();
+ method @Deprecated public void write(char[]!, int, int);
+ }
+
+ public class ObjectsCompat {
+ method public static boolean equals(Object?, Object?);
+ method public static int hash(java.lang.Object!...);
+ method public static int hashCode(Object?);
+ method public static <T> T requireNonNull(T?);
+ method public static <T> T requireNonNull(T?, String);
+ method public static String? toString(Object?, String?);
+ }
+
+ public class Pair<F, S> {
+ ctor public Pair(F!, S!);
+ method public static <A, B> androidx.core.util.Pair<A!,B!> create(A!, B!);
+ field public final F! first;
+ field public final S! second;
+ }
+
+ public final class PatternsCompat {
+ field @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) public static final java.util.regex.Pattern AUTOLINK_EMAIL_ADDRESS;
+ field @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) public static final java.util.regex.Pattern AUTOLINK_WEB_URL;
+ field public static final java.util.regex.Pattern DOMAIN_NAME;
+ field public static final java.util.regex.Pattern EMAIL_ADDRESS;
+ field public static final java.util.regex.Pattern IP_ADDRESS;
+ field public static final java.util.regex.Pattern WEB_URL;
+ }
+
+ public final class Pools {
+ }
+
+ public static interface Pools.Pool<T> {
+ method public T? acquire();
+ method public boolean release(T);
+ }
+
+ public static class Pools.SimplePool<T> implements androidx.core.util.Pools.Pool<T> {
+ ctor public Pools.SimplePool(int);
+ method public T! acquire();
+ method public boolean release(T);
+ }
+
+ public static class Pools.SynchronizedPool<T> extends androidx.core.util.Pools.SimplePool<T> {
+ ctor public Pools.SynchronizedPool(int);
+ }
+
+ @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) public final class Preconditions {
+ method public static void checkArgument(boolean);
+ method public static void checkArgument(boolean, Object);
+ method public static void checkArgument(boolean, String, java.lang.Object!...);
+ method public static float checkArgumentFinite(float, String);
+ method public static 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);
+ method public static <T> T checkNotNull(T?);
+ method public static <T> T checkNotNull(T?, Object);
+ method public static void checkState(boolean, String?);
+ method public static void checkState(boolean);
+ method public static <T extends java.lang.CharSequence> T checkStringNotEmpty(T?);
+ method public static <T extends java.lang.CharSequence> T checkStringNotEmpty(T?, Object);
+ method public static <T extends java.lang.CharSequence> T checkStringNotEmpty(T?, String, java.lang.Object!...);
+ }
+
+ public interface Predicate<T> {
+ method public default androidx.core.util.Predicate<T!>! and(androidx.core.util.Predicate<? super T>!);
+ method public static <T> androidx.core.util.Predicate<T!>! isEqual(Object!);
+ method public default androidx.core.util.Predicate<T!>! negate();
+ method public static <T> androidx.core.util.Predicate<T!>! not(androidx.core.util.Predicate<? super T>!);
+ method public default androidx.core.util.Predicate<T!>! or(androidx.core.util.Predicate<? super T>!);
+ method public boolean test(T!);
+ }
+
+ public final class SizeFCompat {
+ ctor public SizeFCompat(float, float);
+ method public float getHeight();
+ method public float getWidth();
+ method @RequiresApi(21) public android.util.SizeF toSizeF();
+ method @RequiresApi(21) public static androidx.core.util.SizeFCompat toSizeFCompat(android.util.SizeF);
+ }
+
+ public interface Supplier<T> {
+ method public T! get();
+ }
+
+ @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) public final class TimeUtils {
+ method @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) public static void formatDuration(long, StringBuilder!);
+ method @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) public static void formatDuration(long, java.io.PrintWriter!, int);
+ method @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) public static void formatDuration(long, java.io.PrintWriter!);
+ method @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) public static void formatDuration(long, long, java.io.PrintWriter!);
+ field @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) public static final int HUNDRED_DAY_FIELD_LEN = 19; // 0x13
+ }
+
+}
+
+package androidx.core.view {
+
+ public class AccessibilityDelegateCompat {
+ ctor public AccessibilityDelegateCompat();
+ ctor @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) public AccessibilityDelegateCompat(android.view.View.AccessibilityDelegate);
+ method public boolean dispatchPopulateAccessibilityEvent(android.view.View, android.view.accessibility.AccessibilityEvent);
+ method public androidx.core.view.accessibility.AccessibilityNodeProviderCompat? getAccessibilityNodeProvider(android.view.View);
+ method public void onInitializeAccessibilityEvent(android.view.View, android.view.accessibility.AccessibilityEvent);
+ method public void onInitializeAccessibilityNodeInfo(android.view.View, androidx.core.view.accessibility.AccessibilityNodeInfoCompat);
+ method public void onPopulateAccessibilityEvent(android.view.View, android.view.accessibility.AccessibilityEvent);
+ method public boolean onRequestSendAccessibilityEvent(android.view.ViewGroup, android.view.View, android.view.accessibility.AccessibilityEvent);
+ method public boolean performAccessibilityAction(android.view.View, int, android.os.Bundle?);
+ method public void sendAccessibilityEvent(android.view.View, int);
+ method public void sendAccessibilityEventUnchecked(android.view.View, android.view.accessibility.AccessibilityEvent);
+ }
+
+ public abstract class ActionProvider {
+ ctor public ActionProvider(android.content.Context);
+ method public android.content.Context getContext();
+ method public boolean hasSubMenu();
+ method public boolean isVisible();
+ method public abstract android.view.View onCreateActionView();
+ method public android.view.View onCreateActionView(android.view.MenuItem);
+ method public boolean onPerformDefaultAction();
+ method public void onPrepareSubMenu(android.view.SubMenu);
+ method public boolean overridesItemVisibility();
+ method public void refreshVisibility();
+ method @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) public void reset();
+ method @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) public void setSubUiVisibilityListener(androidx.core.view.ActionProvider.SubUiVisibilityListener?);
+ method public void setVisibilityListener(androidx.core.view.ActionProvider.VisibilityListener?);
+ method @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) public void subUiVisibilityChanged(boolean);
+ }
+
+ @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) public static interface ActionProvider.SubUiVisibilityListener {
+ method public void onSubUiVisibilityChanged(boolean);
+ }
+
+ public static interface ActionProvider.VisibilityListener {
+ method public void onActionProviderVisibilityChanged(boolean);
+ }
+
+ public final class ContentInfoCompat {
+ method public android.content.ClipData getClip();
+ method public android.os.Bundle? getExtras();
+ method @androidx.core.view.ContentInfoCompat.Flags public int getFlags();
+ method public android.net.Uri? getLinkUri();
+ method @androidx.core.view.ContentInfoCompat.Source public int getSource();
+ method 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 {
+ ctor public ContentInfoCompat.Builder(androidx.core.view.ContentInfoCompat);
+ ctor public ContentInfoCompat.Builder(android.content.ClipData, @androidx.core.view.ContentInfoCompat.Source int);
+ method public androidx.core.view.ContentInfoCompat build();
+ method public androidx.core.view.ContentInfoCompat.Builder setClip(android.content.ClipData);
+ method public androidx.core.view.ContentInfoCompat.Builder setExtras(android.os.Bundle?);
+ method public androidx.core.view.ContentInfoCompat.Builder setFlags(@androidx.core.view.ContentInfoCompat.Flags int);
+ method public androidx.core.view.ContentInfoCompat.Builder setLinkUri(android.net.Uri?);
+ method public androidx.core.view.ContentInfoCompat.Builder setSource(@androidx.core.view.ContentInfoCompat.Source int);
+ }
+
+ @IntDef(flag=true, value={androidx.core.view.ContentInfoCompat.FLAG_CONVERT_TO_PLAIN_TEXT}) @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.SOURCE) public static @interface ContentInfoCompat.Flags {
+ }
+
+ @IntDef({androidx.core.view.ContentInfoCompat.SOURCE_APP, androidx.core.view.ContentInfoCompat.SOURCE_CLIPBOARD, androidx.core.view.ContentInfoCompat.SOURCE_INPUT_METHOD, androidx.core.view.ContentInfoCompat.SOURCE_DRAG_AND_DROP, androidx.core.view.ContentInfoCompat.SOURCE_AUTOFILL, androidx.core.view.ContentInfoCompat.SOURCE_PROCESS_TEXT}) @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.SOURCE) public static @interface ContentInfoCompat.Source {
+ }
+
+ public final class DisplayCompat {
+ method public static androidx.core.view.DisplayCompat.ModeCompat getMode(android.content.Context, android.view.Display);
+ method public static androidx.core.view.DisplayCompat.ModeCompat![] getSupportedModes(android.content.Context, android.view.Display);
+ }
+
+ public static final class DisplayCompat.ModeCompat {
+ method public int getPhysicalHeight();
+ method public int getPhysicalWidth();
+ method @Deprecated public boolean isNative();
+ method @RequiresApi(android.os.Build.VERSION_CODES.M) public android.view.Display.Mode? toMode();
+ }
+
+ public final class DisplayCutoutCompat {
+ ctor public DisplayCutoutCompat(android.graphics.Rect?, java.util.List<android.graphics.Rect!>?);
+ ctor public DisplayCutoutCompat(androidx.core.graphics.Insets, android.graphics.Rect?, android.graphics.Rect?, android.graphics.Rect?, android.graphics.Rect?, androidx.core.graphics.Insets);
+ method public java.util.List<android.graphics.Rect!> getBoundingRects();
+ method public int getSafeInsetBottom();
+ method public int getSafeInsetLeft();
+ method public int getSafeInsetRight();
+ method public int getSafeInsetTop();
+ method public androidx.core.graphics.Insets getWaterfallInsets();
+ }
+
+ public final class DragAndDropPermissionsCompat {
+ method public void release();
+ method @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) public static androidx.core.view.DragAndDropPermissionsCompat? request(android.app.Activity, android.view.DragEvent);
+ }
+
+ public class DragStartHelper {
+ ctor public DragStartHelper(android.view.View, androidx.core.view.DragStartHelper.OnDragStartListener);
+ method public void attach();
+ method public void detach();
+ method public void getTouchPosition(android.graphics.Point);
+ method public boolean onLongClick(android.view.View);
+ method public boolean onTouch(android.view.View, android.view.MotionEvent);
+ }
+
+ public static interface DragStartHelper.OnDragStartListener {
+ method public boolean onDragStart(android.view.View, androidx.core.view.DragStartHelper);
+ }
+
+ public final class GestureDetectorCompat {
+ ctor public GestureDetectorCompat(android.content.Context, android.view.GestureDetector.OnGestureListener);
+ ctor public GestureDetectorCompat(android.content.Context, android.view.GestureDetector.OnGestureListener, android.os.Handler?);
+ method public boolean isLongpressEnabled();
+ method public boolean onTouchEvent(android.view.MotionEvent);
+ method public void setIsLongpressEnabled(boolean);
+ method public void setOnDoubleTapListener(android.view.GestureDetector.OnDoubleTapListener?);
+ }
+
+ public final class GravityCompat {
+ method public static void apply(int, int, int, android.graphics.Rect, android.graphics.Rect, int);
+ method public static void apply(int, int, int, android.graphics.Rect, int, int, android.graphics.Rect, int);
+ method public static void applyDisplay(int, android.graphics.Rect, android.graphics.Rect, int);
+ method public static int getAbsoluteGravity(int, int);
+ field public static final int END = 8388613; // 0x800005
+ field public static final int RELATIVE_HORIZONTAL_GRAVITY_MASK = 8388615; // 0x800007
+ field public static final int RELATIVE_LAYOUT_DIRECTION = 8388608; // 0x800000
+ field public static final int START = 8388611; // 0x800003
+ }
+
+ public final class InputDeviceCompat {
+ field public static final int SOURCE_ANY = -256; // 0xffffff00
+ field public static final int SOURCE_CLASS_BUTTON = 1; // 0x1
+ field public static final int SOURCE_CLASS_JOYSTICK = 16; // 0x10
+ field public static final int SOURCE_CLASS_MASK = 255; // 0xff
+ field public static final int SOURCE_CLASS_NONE = 0; // 0x0
+ field public static final int SOURCE_CLASS_POINTER = 2; // 0x2
+ field public static final int SOURCE_CLASS_POSITION = 8; // 0x8
+ field public static final int SOURCE_CLASS_TRACKBALL = 4; // 0x4
+ field public static final int SOURCE_DPAD = 513; // 0x201
+ field public static final int SOURCE_GAMEPAD = 1025; // 0x401
+ field public static final int SOURCE_HDMI = 33554433; // 0x2000001
+ field public static final int SOURCE_JOYSTICK = 16777232; // 0x1000010
+ field public static final int SOURCE_KEYBOARD = 257; // 0x101
+ field public static final int SOURCE_MOUSE = 8194; // 0x2002
+ field public static final int SOURCE_ROTARY_ENCODER = 4194304; // 0x400000
+ field public static final int SOURCE_STYLUS = 16386; // 0x4002
+ field public static final int SOURCE_TOUCHPAD = 1048584; // 0x100008
+ field public static final int SOURCE_TOUCHSCREEN = 4098; // 0x1002
+ field public static final int SOURCE_TOUCH_NAVIGATION = 2097152; // 0x200000
+ field public static final int SOURCE_TRACKBALL = 65540; // 0x10004
+ field public static final int SOURCE_UNKNOWN = 0; // 0x0
+ }
+
+ @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) public class KeyEventDispatcher {
+ method public static boolean dispatchBeforeHierarchy(android.view.View, android.view.KeyEvent);
+ method public static boolean dispatchKeyEvent(androidx.core.view.KeyEventDispatcher.Component, android.view.View?, android.view.Window.Callback?, android.view.KeyEvent);
+ }
+
+ public static interface KeyEventDispatcher.Component {
+ method public boolean superDispatchKeyEvent(android.view.KeyEvent);
+ }
+
+ public final class LayoutInflaterCompat {
+ method @Deprecated public static androidx.core.view.LayoutInflaterFactory! getFactory(android.view.LayoutInflater!);
+ method @Deprecated public static void setFactory(android.view.LayoutInflater, androidx.core.view.LayoutInflaterFactory);
+ method public static void setFactory2(android.view.LayoutInflater, android.view.LayoutInflater.Factory2);
+ }
+
+ @Deprecated public interface LayoutInflaterFactory {
+ method @Deprecated public android.view.View! onCreateView(android.view.View!, String!, android.content.Context!, android.util.AttributeSet!);
+ }
+
+ public final class MarginLayoutParamsCompat {
+ method public static int getLayoutDirection(android.view.ViewGroup.MarginLayoutParams);
+ method public static int getMarginEnd(android.view.ViewGroup.MarginLayoutParams);
+ method public static int getMarginStart(android.view.ViewGroup.MarginLayoutParams);
+ method public static boolean isMarginRelative(android.view.ViewGroup.MarginLayoutParams);
+ method public static void resolveLayoutDirection(android.view.ViewGroup.MarginLayoutParams, int);
+ method public static void setLayoutDirection(android.view.ViewGroup.MarginLayoutParams, int);
+ method public static void setMarginEnd(android.view.ViewGroup.MarginLayoutParams, int);
+ method public static void setMarginStart(android.view.ViewGroup.MarginLayoutParams, int);
+ }
+
+ public final class MenuCompat {
+ method public static void setGroupDividerEnabled(android.view.Menu, boolean);
+ method @Deprecated public static void setShowAsAction(android.view.MenuItem!, int);
+ }
+
+ public interface MenuHost {
+ method public void addMenuProvider(androidx.core.view.MenuProvider);
+ method public void addMenuProvider(androidx.core.view.MenuProvider, androidx.lifecycle.LifecycleOwner);
+ method public void addMenuProvider(androidx.core.view.MenuProvider, androidx.lifecycle.LifecycleOwner, androidx.lifecycle.Lifecycle.State);
+ method public void invalidateMenu();
+ method public void removeMenuProvider(androidx.core.view.MenuProvider);
+ }
+
+ public class MenuHostHelper {
+ ctor public MenuHostHelper(Runnable);
+ method public void addMenuProvider(androidx.core.view.MenuProvider);
+ method public void addMenuProvider(androidx.core.view.MenuProvider, androidx.lifecycle.LifecycleOwner);
+ method public void addMenuProvider(androidx.core.view.MenuProvider, androidx.lifecycle.LifecycleOwner, androidx.lifecycle.Lifecycle.State);
+ method public void onCreateMenu(android.view.Menu, android.view.MenuInflater);
+ method public void onMenuClosed(android.view.Menu);
+ method public boolean onMenuItemSelected(android.view.MenuItem);
+ method public void onPrepareMenu(android.view.Menu);
+ method public void removeMenuProvider(androidx.core.view.MenuProvider);
+ }
+
+ public final class MenuItemCompat {
+ method @Deprecated public static boolean collapseActionView(android.view.MenuItem!);
+ method @Deprecated public static boolean expandActionView(android.view.MenuItem!);
+ method public static androidx.core.view.ActionProvider? getActionProvider(android.view.MenuItem);
+ method @Deprecated public static android.view.View! getActionView(android.view.MenuItem!);
+ method public static int getAlphabeticModifiers(android.view.MenuItem);
+ method public static CharSequence? getContentDescription(android.view.MenuItem);
+ method public static android.content.res.ColorStateList? getIconTintList(android.view.MenuItem);
+ method public static android.graphics.PorterDuff.Mode? getIconTintMode(android.view.MenuItem);
+ method public static int getNumericModifiers(android.view.MenuItem);
+ method public static CharSequence? getTooltipText(android.view.MenuItem);
+ method @Deprecated public static boolean isActionViewExpanded(android.view.MenuItem!);
+ method public static android.view.MenuItem? setActionProvider(android.view.MenuItem, androidx.core.view.ActionProvider?);
+ method @Deprecated public static android.view.MenuItem! setActionView(android.view.MenuItem!, android.view.View!);
+ method @Deprecated public static android.view.MenuItem! setActionView(android.view.MenuItem!, int);
+ method public static void setAlphabeticShortcut(android.view.MenuItem, char, int);
+ method public static void setContentDescription(android.view.MenuItem, CharSequence?);
+ method public static void setIconTintList(android.view.MenuItem, android.content.res.ColorStateList?);
+ method public static void setIconTintMode(android.view.MenuItem, android.graphics.PorterDuff.Mode?);
+ method public static void setNumericShortcut(android.view.MenuItem, char, int);
+ method @Deprecated public static android.view.MenuItem! setOnActionExpandListener(android.view.MenuItem!, androidx.core.view.MenuItemCompat.OnActionExpandListener!);
+ method public static void setShortcut(android.view.MenuItem, char, char, int, int);
+ method @Deprecated public static void setShowAsAction(android.view.MenuItem!, int);
+ method public static void setTooltipText(android.view.MenuItem, CharSequence?);
+ field @Deprecated public static final int SHOW_AS_ACTION_ALWAYS = 2; // 0x2
+ field @Deprecated public static final int SHOW_AS_ACTION_COLLAPSE_ACTION_VIEW = 8; // 0x8
+ field @Deprecated public static final int SHOW_AS_ACTION_IF_ROOM = 1; // 0x1
+ field @Deprecated public static final int SHOW_AS_ACTION_NEVER = 0; // 0x0
+ field @Deprecated public static final int SHOW_AS_ACTION_WITH_TEXT = 4; // 0x4
+ }
+
+ @Deprecated public static interface MenuItemCompat.OnActionExpandListener {
+ method @Deprecated public boolean onMenuItemActionCollapse(android.view.MenuItem!);
+ method @Deprecated public boolean onMenuItemActionExpand(android.view.MenuItem!);
+ }
+
+ public interface MenuProvider {
+ method public void onCreateMenu(android.view.Menu, android.view.MenuInflater);
+ method public default void onMenuClosed(android.view.Menu);
+ method public boolean onMenuItemSelected(android.view.MenuItem);
+ method public default void onPrepareMenu(android.view.Menu);
+ }
+
+ public final class MotionEventCompat {
+ method @Deprecated public static int findPointerIndex(android.view.MotionEvent!, int);
+ method @Deprecated public static int getActionIndex(android.view.MotionEvent!);
+ method @Deprecated public static int getActionMasked(android.view.MotionEvent!);
+ method @Deprecated public static float getAxisValue(android.view.MotionEvent!, int);
+ method @Deprecated public static float getAxisValue(android.view.MotionEvent!, int, int);
+ method @Deprecated public static int getButtonState(android.view.MotionEvent!);
+ method @Deprecated public static int getPointerCount(android.view.MotionEvent!);
+ method @Deprecated public static int getPointerId(android.view.MotionEvent!, int);
+ method @Deprecated public static int getSource(android.view.MotionEvent!);
+ method @Deprecated public static float getX(android.view.MotionEvent!, int);
+ method @Deprecated public static float getY(android.view.MotionEvent!, int);
+ method public static boolean isFromSource(android.view.MotionEvent, int);
+ field @Deprecated public static final int ACTION_HOVER_ENTER = 9; // 0x9
+ field @Deprecated public static final int ACTION_HOVER_EXIT = 10; // 0xa
+ field @Deprecated public static final int ACTION_HOVER_MOVE = 7; // 0x7
+ field @Deprecated public static final int ACTION_MASK = 255; // 0xff
+ field @Deprecated public static final int ACTION_POINTER_DOWN = 5; // 0x5
+ field @Deprecated public static final int ACTION_POINTER_INDEX_MASK = 65280; // 0xff00
+ field @Deprecated public static final int ACTION_POINTER_INDEX_SHIFT = 8; // 0x8
+ field @Deprecated public static final int ACTION_POINTER_UP = 6; // 0x6
+ field @Deprecated public static final int ACTION_SCROLL = 8; // 0x8
+ field @Deprecated public static final int AXIS_BRAKE = 23; // 0x17
+ field @Deprecated public static final int AXIS_DISTANCE = 24; // 0x18
+ field @Deprecated public static final int AXIS_GAS = 22; // 0x16
+ field @Deprecated public static final int AXIS_GENERIC_1 = 32; // 0x20
+ field @Deprecated public static final int AXIS_GENERIC_10 = 41; // 0x29
+ field @Deprecated public static final int AXIS_GENERIC_11 = 42; // 0x2a
+ field @Deprecated public static final int AXIS_GENERIC_12 = 43; // 0x2b
+ field @Deprecated public static final int AXIS_GENERIC_13 = 44; // 0x2c
+ field @Deprecated public static final int AXIS_GENERIC_14 = 45; // 0x2d
+ field @Deprecated public static final int AXIS_GENERIC_15 = 46; // 0x2e
+ field @Deprecated public static final int AXIS_GENERIC_16 = 47; // 0x2f
+ field @Deprecated public static final int AXIS_GENERIC_2 = 33; // 0x21
+ field @Deprecated public static final int AXIS_GENERIC_3 = 34; // 0x22
+ field @Deprecated public static final int AXIS_GENERIC_4 = 35; // 0x23
+ field @Deprecated public static final int AXIS_GENERIC_5 = 36; // 0x24
+ field @Deprecated public static final int AXIS_GENERIC_6 = 37; // 0x25
+ field @Deprecated public static final int AXIS_GENERIC_7 = 38; // 0x26
+ field @Deprecated public static final int AXIS_GENERIC_8 = 39; // 0x27
+ field @Deprecated public static final int AXIS_GENERIC_9 = 40; // 0x28
+ field @Deprecated public static final int AXIS_HAT_X = 15; // 0xf
+ field @Deprecated public static final int AXIS_HAT_Y = 16; // 0x10
+ field @Deprecated public static final int AXIS_HSCROLL = 10; // 0xa
+ field @Deprecated public static final int AXIS_LTRIGGER = 17; // 0x11
+ field @Deprecated public static final int AXIS_ORIENTATION = 8; // 0x8
+ field @Deprecated public static final int AXIS_PRESSURE = 2; // 0x2
+ field public static final int AXIS_RELATIVE_X = 27; // 0x1b
+ field public static final int AXIS_RELATIVE_Y = 28; // 0x1c
+ field @Deprecated public static final int AXIS_RTRIGGER = 18; // 0x12
+ field @Deprecated public static final int AXIS_RUDDER = 20; // 0x14
+ field @Deprecated public static final int AXIS_RX = 12; // 0xc
+ field @Deprecated public static final int AXIS_RY = 13; // 0xd
+ field @Deprecated public static final int AXIS_RZ = 14; // 0xe
+ field public static final int AXIS_SCROLL = 26; // 0x1a
+ field @Deprecated public static final int AXIS_SIZE = 3; // 0x3
+ field @Deprecated public static final int AXIS_THROTTLE = 19; // 0x13
+ field @Deprecated public static final int AXIS_TILT = 25; // 0x19
+ field @Deprecated public static final int AXIS_TOOL_MAJOR = 6; // 0x6
+ field @Deprecated public static final int AXIS_TOOL_MINOR = 7; // 0x7
+ field @Deprecated public static final int AXIS_TOUCH_MAJOR = 4; // 0x4
+ field @Deprecated public static final int AXIS_TOUCH_MINOR = 5; // 0x5
+ field @Deprecated public static final int AXIS_VSCROLL = 9; // 0x9
+ field @Deprecated public static final int AXIS_WHEEL = 21; // 0x15
+ field @Deprecated public static final int AXIS_X = 0; // 0x0
+ field @Deprecated public static final int AXIS_Y = 1; // 0x1
+ field @Deprecated public static final int AXIS_Z = 11; // 0xb
+ field @Deprecated public static final int BUTTON_PRIMARY = 1; // 0x1
+ }
+
+ public interface NestedScrollingChild {
+ method public boolean dispatchNestedFling(float, float, boolean);
+ method public boolean dispatchNestedPreFling(float, float);
+ method public boolean dispatchNestedPreScroll(int, int, int[]?, int[]?);
+ method public boolean dispatchNestedScroll(int, int, int, int, int[]?);
+ method public boolean hasNestedScrollingParent();
+ method public boolean isNestedScrollingEnabled();
+ method public void setNestedScrollingEnabled(boolean);
+ method public boolean startNestedScroll(@androidx.core.view.ViewCompat.ScrollAxis int);
+ method public void stopNestedScroll();
+ }
+
+ public interface NestedScrollingChild2 extends androidx.core.view.NestedScrollingChild {
+ method public boolean dispatchNestedPreScroll(int, int, int[]?, int[]?, @androidx.core.view.ViewCompat.NestedScrollType int);
+ method public boolean dispatchNestedScroll(int, int, int, int, int[]?, @androidx.core.view.ViewCompat.NestedScrollType int);
+ method public boolean hasNestedScrollingParent(@androidx.core.view.ViewCompat.NestedScrollType int);
+ method public boolean startNestedScroll(@androidx.core.view.ViewCompat.ScrollAxis int, @androidx.core.view.ViewCompat.NestedScrollType int);
+ method public void stopNestedScroll(@androidx.core.view.ViewCompat.NestedScrollType int);
+ }
+
+ public interface NestedScrollingChild3 extends androidx.core.view.NestedScrollingChild2 {
+ method public void dispatchNestedScroll(int, int, int, int, int[]?, @androidx.core.view.ViewCompat.NestedScrollType int, int[]);
+ }
+
+ public class NestedScrollingChildHelper {
+ ctor public NestedScrollingChildHelper(android.view.View);
+ method public boolean dispatchNestedFling(float, float, boolean);
+ method public boolean dispatchNestedPreFling(float, float);
+ method public boolean dispatchNestedPreScroll(int, int, int[]?, int[]?);
+ method public boolean dispatchNestedPreScroll(int, int, int[]?, int[]?, @androidx.core.view.ViewCompat.NestedScrollType int);
+ method public boolean dispatchNestedScroll(int, int, int, int, int[]?);
+ method public boolean dispatchNestedScroll(int, int, int, int, int[]?, @androidx.core.view.ViewCompat.NestedScrollType int);
+ method public void dispatchNestedScroll(int, int, int, int, int[]?, @androidx.core.view.ViewCompat.NestedScrollType int, int[]?);
+ method public boolean hasNestedScrollingParent();
+ method public boolean hasNestedScrollingParent(@androidx.core.view.ViewCompat.NestedScrollType int);
+ method public boolean isNestedScrollingEnabled();
+ method public void onDetachedFromWindow();
+ method public void onStopNestedScroll(android.view.View);
+ method public void setNestedScrollingEnabled(boolean);
+ method public boolean startNestedScroll(@androidx.core.view.ViewCompat.ScrollAxis int);
+ method public boolean startNestedScroll(@androidx.core.view.ViewCompat.ScrollAxis int, @androidx.core.view.ViewCompat.NestedScrollType int);
+ method public void stopNestedScroll();
+ method public void stopNestedScroll(@androidx.core.view.ViewCompat.NestedScrollType int);
+ }
+
+ public interface NestedScrollingParent {
+ method @androidx.core.view.ViewCompat.ScrollAxis public int getNestedScrollAxes();
+ method public boolean onNestedFling(android.view.View, float, float, boolean);
+ method public boolean onNestedPreFling(android.view.View, float, float);
+ method public void onNestedPreScroll(android.view.View, int, int, int[]);
+ method public void onNestedScroll(android.view.View, int, int, int, int);
+ method public void onNestedScrollAccepted(android.view.View, android.view.View, @androidx.core.view.ViewCompat.ScrollAxis int);
+ method public boolean onStartNestedScroll(android.view.View, android.view.View, @androidx.core.view.ViewCompat.ScrollAxis int);
+ method public void onStopNestedScroll(android.view.View);
+ }
+
+ public interface NestedScrollingParent2 extends androidx.core.view.NestedScrollingParent {
+ method public void onNestedPreScroll(android.view.View, int, int, int[], @androidx.core.view.ViewCompat.NestedScrollType int);
+ method public void onNestedScroll(android.view.View, int, int, int, int, @androidx.core.view.ViewCompat.NestedScrollType int);
+ method public void onNestedScrollAccepted(android.view.View, android.view.View, @androidx.core.view.ViewCompat.ScrollAxis int, @androidx.core.view.ViewCompat.NestedScrollType int);
+ method public boolean onStartNestedScroll(android.view.View, android.view.View, @androidx.core.view.ViewCompat.ScrollAxis int, @androidx.core.view.ViewCompat.NestedScrollType int);
+ method public void onStopNestedScroll(android.view.View, @androidx.core.view.ViewCompat.NestedScrollType int);
+ }
+
+ public interface NestedScrollingParent3 extends androidx.core.view.NestedScrollingParent2 {
+ method public void onNestedScroll(android.view.View, int, int, int, int, @androidx.core.view.ViewCompat.NestedScrollType int, int[]);
+ }
+
+ public class NestedScrollingParentHelper {
+ ctor public NestedScrollingParentHelper(android.view.ViewGroup);
+ method @androidx.core.view.ViewCompat.ScrollAxis public int getNestedScrollAxes();
+ method public void onNestedScrollAccepted(android.view.View, android.view.View, @androidx.core.view.ViewCompat.ScrollAxis int);
+ method public void onNestedScrollAccepted(android.view.View, android.view.View, @androidx.core.view.ViewCompat.ScrollAxis int, @androidx.core.view.ViewCompat.NestedScrollType int);
+ method public void onStopNestedScroll(android.view.View);
+ method public void onStopNestedScroll(android.view.View, @androidx.core.view.ViewCompat.NestedScrollType int);
+ }
+
+ public interface OnApplyWindowInsetsListener {
+ method public androidx.core.view.WindowInsetsCompat onApplyWindowInsets(android.view.View, androidx.core.view.WindowInsetsCompat);
+ }
+
+ public interface OnReceiveContentListener {
+ method public androidx.core.view.ContentInfoCompat? onReceiveContent(android.view.View, androidx.core.view.ContentInfoCompat);
+ }
+
+ public interface OnReceiveContentViewBehavior {
+ method public androidx.core.view.ContentInfoCompat? onReceiveContent(androidx.core.view.ContentInfoCompat);
+ }
+
+ public final class OneShotPreDrawListener implements android.view.View.OnAttachStateChangeListener android.view.ViewTreeObserver.OnPreDrawListener {
+ method public static androidx.core.view.OneShotPreDrawListener add(android.view.View, Runnable);
+ method public boolean onPreDraw();
+ method public void onViewAttachedToWindow(android.view.View);
+ method public void onViewDetachedFromWindow(android.view.View);
+ method public void removeListener();
+ }
+
+ public final class PointerIconCompat {
+ method public static androidx.core.view.PointerIconCompat create(android.graphics.Bitmap, float, float);
+ method @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) public Object? getPointerIcon();
+ method public static androidx.core.view.PointerIconCompat getSystemIcon(android.content.Context, int);
+ method public static androidx.core.view.PointerIconCompat load(android.content.res.Resources, int);
+ field public static final int TYPE_ALIAS = 1010; // 0x3f2
+ field public static final int TYPE_ALL_SCROLL = 1013; // 0x3f5
+ field public static final int TYPE_ARROW = 1000; // 0x3e8
+ field public static final int TYPE_CELL = 1006; // 0x3ee
+ field public static final int TYPE_CONTEXT_MENU = 1001; // 0x3e9
+ field public static final int TYPE_COPY = 1011; // 0x3f3
+ field public static final int TYPE_CROSSHAIR = 1007; // 0x3ef
+ field public static final int TYPE_DEFAULT = 1000; // 0x3e8
+ field public static final int TYPE_GRAB = 1020; // 0x3fc
+ field public static final int TYPE_GRABBING = 1021; // 0x3fd
+ field public static final int TYPE_HAND = 1002; // 0x3ea
+ field public static final int TYPE_HELP = 1003; // 0x3eb
+ field public static final int TYPE_HORIZONTAL_DOUBLE_ARROW = 1014; // 0x3f6
+ field public static final int TYPE_NO_DROP = 1012; // 0x3f4
+ field public static final int TYPE_NULL = 0; // 0x0
+ field public static final int TYPE_TEXT = 1008; // 0x3f0
+ field public static final int TYPE_TOP_LEFT_DIAGONAL_DOUBLE_ARROW = 1017; // 0x3f9
+ field public static final int TYPE_TOP_RIGHT_DIAGONAL_DOUBLE_ARROW = 1016; // 0x3f8
+ field public static final int TYPE_VERTICAL_DOUBLE_ARROW = 1015; // 0x3f7
+ field public static final int TYPE_VERTICAL_TEXT = 1009; // 0x3f1
+ field public static final int TYPE_WAIT = 1004; // 0x3ec
+ field public static final int TYPE_ZOOM_IN = 1018; // 0x3fa
+ field public static final int TYPE_ZOOM_OUT = 1019; // 0x3fb
+ }
+
+ public final class ScaleGestureDetectorCompat {
+ method @Deprecated public static boolean isQuickScaleEnabled(Object!);
+ method public static boolean isQuickScaleEnabled(android.view.ScaleGestureDetector);
+ method @Deprecated public static void setQuickScaleEnabled(Object!, boolean);
+ method public static void setQuickScaleEnabled(android.view.ScaleGestureDetector, boolean);
+ }
+
+ public interface ScrollingView {
+ method public int computeHorizontalScrollExtent();
+ method public int computeHorizontalScrollOffset();
+ method public int computeHorizontalScrollRange();
+ method public int computeVerticalScrollExtent();
+ method public int computeVerticalScrollOffset();
+ method public int computeVerticalScrollRange();
+ }
+
+ public interface TintableBackgroundView {
+ method public android.content.res.ColorStateList? getSupportBackgroundTintList();
+ method public android.graphics.PorterDuff.Mode? getSupportBackgroundTintMode();
+ method public void setSupportBackgroundTintList(android.content.res.ColorStateList?);
+ method public void setSupportBackgroundTintMode(android.graphics.PorterDuff.Mode?);
+ }
+
+ @Deprecated public final class VelocityTrackerCompat {
+ method @Deprecated public static float getXVelocity(android.view.VelocityTracker!, int);
+ method @Deprecated public static float getYVelocity(android.view.VelocityTracker!, int);
+ }
+
+ public class ViewCompat {
+ ctor @Deprecated protected ViewCompat();
+ method public static int addAccessibilityAction(android.view.View, CharSequence, androidx.core.view.accessibility.AccessibilityViewCommand);
+ method public static void addKeyboardNavigationClusters(android.view.View, java.util.Collection<android.view.View!>, int);
+ method public static void addOnUnhandledKeyEventListener(android.view.View, androidx.core.view.ViewCompat.OnUnhandledKeyEventListenerCompat);
+ method public static androidx.core.view.ViewPropertyAnimatorCompat animate(android.view.View);
+ method @Deprecated public static boolean canScrollHorizontally(android.view.View!, int);
+ method @Deprecated public static boolean canScrollVertically(android.view.View!, int);
+ method public static void cancelDragAndDrop(android.view.View);
+ method @Deprecated public static int combineMeasuredStates(int, int);
+ method public static androidx.core.view.WindowInsetsCompat computeSystemWindowInsets(android.view.View, androidx.core.view.WindowInsetsCompat, android.graphics.Rect);
+ method public static androidx.core.view.WindowInsetsCompat dispatchApplyWindowInsets(android.view.View, androidx.core.view.WindowInsetsCompat);
+ method public static void dispatchFinishTemporaryDetach(android.view.View);
+ method public static boolean dispatchNestedFling(android.view.View, float, float, boolean);
+ method public static boolean dispatchNestedPreFling(android.view.View, float, float);
+ method public static boolean dispatchNestedPreScroll(android.view.View, int, int, int[]?, int[]?);
+ method public static boolean dispatchNestedPreScroll(android.view.View, int, int, int[]?, int[]?, @androidx.core.view.ViewCompat.NestedScrollType int);
+ method public static boolean dispatchNestedScroll(android.view.View, int, int, int, int, int[]?);
+ method public static void dispatchNestedScroll(android.view.View, int, int, int, int, int[]?, @androidx.core.view.ViewCompat.NestedScrollType int, int[]);
+ method public static boolean dispatchNestedScroll(android.view.View, int, int, int, int, int[]?, @androidx.core.view.ViewCompat.NestedScrollType int);
+ method public static void dispatchStartTemporaryDetach(android.view.View);
+ method public static void enableAccessibleClickableSpanSupport(android.view.View);
+ method public static int generateViewId();
+ method public static androidx.core.view.AccessibilityDelegateCompat? getAccessibilityDelegate(android.view.View);
+ method public static int getAccessibilityLiveRegion(android.view.View);
+ method public static androidx.core.view.accessibility.AccessibilityNodeProviderCompat? getAccessibilityNodeProvider(android.view.View);
+ method @UiThread public static CharSequence? getAccessibilityPaneTitle(android.view.View);
+ method @Deprecated public static float getAlpha(android.view.View!);
+ method public static android.content.res.ColorStateList? getBackgroundTintList(android.view.View);
+ method public static android.graphics.PorterDuff.Mode? getBackgroundTintMode(android.view.View);
+ method public static android.graphics.Rect? getClipBounds(android.view.View);
+ method public static android.view.Display? getDisplay(android.view.View);
+ method public static float getElevation(android.view.View);
+ method public static boolean getFitsSystemWindows(android.view.View);
+ method public static int getImportantForAccessibility(android.view.View);
+ method public static int getImportantForAutofill(android.view.View);
+ method public static int getLabelFor(android.view.View);
+ method @Deprecated public static int getLayerType(android.view.View!);
+ method public static int getLayoutDirection(android.view.View);
+ method @Deprecated public static android.graphics.Matrix? getMatrix(android.view.View!);
+ method @Deprecated public static int getMeasuredHeightAndState(android.view.View!);
+ method @Deprecated public static int getMeasuredState(android.view.View!);
+ method @Deprecated public static int getMeasuredWidthAndState(android.view.View!);
+ method public static int getMinimumHeight(android.view.View);
+ method public static int getMinimumWidth(android.view.View);
+ method public static int getNextClusterForwardId(android.view.View);
+ method public static String![]? getOnReceiveContentMimeTypes(android.view.View);
+ method @Deprecated public static int getOverScrollMode(android.view.View!);
+ method @Px public static int getPaddingEnd(android.view.View);
+ method @Px public static int getPaddingStart(android.view.View);
+ method public static android.view.ViewParent? getParentForAccessibility(android.view.View);
+ method @Deprecated public static float getPivotX(android.view.View!);
+ method @Deprecated public static float getPivotY(android.view.View!);
+ method public static androidx.core.view.WindowInsetsCompat? getRootWindowInsets(android.view.View);
+ method @Deprecated public static float getRotation(android.view.View!);
+ method @Deprecated public static float getRotationX(android.view.View!);
+ method @Deprecated public static float getRotationY(android.view.View!);
+ method @Deprecated public static float getScaleX(android.view.View!);
+ method @Deprecated public static float getScaleY(android.view.View!);
+ method public static int getScrollIndicators(android.view.View);
+ method @UiThread public static CharSequence? getStateDescription(android.view.View);
+ method public static java.util.List<android.graphics.Rect!> getSystemGestureExclusionRects(android.view.View);
+ method public static String? getTransitionName(android.view.View);
+ method @Deprecated public static float getTranslationX(android.view.View!);
+ method @Deprecated public static float getTranslationY(android.view.View!);
+ method public static float getTranslationZ(android.view.View);
+ method @Deprecated public static androidx.core.view.WindowInsetsControllerCompat? getWindowInsetsController(android.view.View);
+ method @Deprecated public static int getWindowSystemUiVisibility(android.view.View);
+ method @Deprecated public static float getX(android.view.View!);
+ method @Deprecated public static float getY(android.view.View!);
+ method public static float getZ(android.view.View);
+ method public static boolean hasAccessibilityDelegate(android.view.View);
+ method public static boolean hasExplicitFocusable(android.view.View);
+ method public static boolean hasNestedScrollingParent(android.view.View);
+ method public static boolean hasNestedScrollingParent(android.view.View, @androidx.core.view.ViewCompat.NestedScrollType int);
+ method public static boolean hasOnClickListeners(android.view.View);
+ method public static boolean hasOverlappingRendering(android.view.View);
+ method public static boolean hasTransientState(android.view.View);
+ method @UiThread public static boolean isAccessibilityHeading(android.view.View);
+ method public static boolean isAttachedToWindow(android.view.View);
+ method public static boolean isFocusedByDefault(android.view.View);
+ method public static boolean isImportantForAccessibility(android.view.View);
+ method public static boolean isImportantForAutofill(android.view.View);
+ method public static boolean isInLayout(android.view.View);
+ method public static boolean isKeyboardNavigationCluster(android.view.View);
+ method public static boolean isLaidOut(android.view.View);
+ method public static boolean isLayoutDirectionResolved(android.view.View);
+ method public static boolean isNestedScrollingEnabled(android.view.View);
+ method @Deprecated public static boolean isOpaque(android.view.View!);
+ method public static boolean isPaddingRelative(android.view.View);
+ method @UiThread public static boolean isScreenReaderFocusable(android.view.View);
+ method @Deprecated public static void jumpDrawablesToCurrentState(android.view.View!);
+ method public static android.view.View? keyboardNavigationClusterSearch(android.view.View, android.view.View?, @androidx.core.view.ViewCompat.FocusDirection int);
+ method public static void offsetLeftAndRight(android.view.View, int);
+ method public static void offsetTopAndBottom(android.view.View, int);
+ method public static androidx.core.view.WindowInsetsCompat onApplyWindowInsets(android.view.View, androidx.core.view.WindowInsetsCompat);
+ method @Deprecated public static void onInitializeAccessibilityEvent(android.view.View!, android.view.accessibility.AccessibilityEvent!);
+ method public static void onInitializeAccessibilityNodeInfo(android.view.View, androidx.core.view.accessibility.AccessibilityNodeInfoCompat);
+ method @Deprecated public static void onPopulateAccessibilityEvent(android.view.View!, android.view.accessibility.AccessibilityEvent!);
+ method public static boolean performAccessibilityAction(android.view.View, int, android.os.Bundle?);
+ method public static androidx.core.view.ContentInfoCompat? performReceiveContent(android.view.View, androidx.core.view.ContentInfoCompat);
+ method public static void postInvalidateOnAnimation(android.view.View);
+ method public static void postInvalidateOnAnimation(android.view.View, int, int, int, int);
+ method public static void postOnAnimation(android.view.View, Runnable);
+ method public static void postOnAnimationDelayed(android.view.View, Runnable, long);
+ method public static void removeAccessibilityAction(android.view.View, int);
+ method public static void removeOnUnhandledKeyEventListener(android.view.View, androidx.core.view.ViewCompat.OnUnhandledKeyEventListenerCompat);
+ method public static void replaceAccessibilityAction(android.view.View, androidx.core.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat, CharSequence?, androidx.core.view.accessibility.AccessibilityViewCommand?);
+ method public static void requestApplyInsets(android.view.View);
+ method public static <T extends android.view.View> T requireViewById(android.view.View, @IdRes int);
+ method @Deprecated public static int resolveSizeAndState(int, int, int);
+ method public static boolean restoreDefaultFocus(android.view.View);
+ method public static void saveAttributeDataForStyleable(android.view.View, android.content.Context, int[], android.util.AttributeSet?, android.content.res.TypedArray, int, int);
+ method public static void setAccessibilityDelegate(android.view.View, androidx.core.view.AccessibilityDelegateCompat?);
+ method @UiThread public static void setAccessibilityHeading(android.view.View, boolean);
+ method public static void setAccessibilityLiveRegion(android.view.View, int);
+ method @UiThread public static void setAccessibilityPaneTitle(android.view.View, CharSequence?);
+ method @Deprecated public static void setActivated(android.view.View!, boolean);
+ method @Deprecated public static void setAlpha(android.view.View!, @FloatRange(from=0.0, to=1.0) float);
+ method public static void setAutofillHints(android.view.View, java.lang.String!...);
+ method public static void setBackground(android.view.View, android.graphics.drawable.Drawable?);
+ method public static void setBackgroundTintList(android.view.View, android.content.res.ColorStateList?);
+ method public static void setBackgroundTintMode(android.view.View, android.graphics.PorterDuff.Mode?);
+ method @Deprecated public static void setChildrenDrawingOrderEnabled(android.view.ViewGroup!, boolean);
+ method public static void setClipBounds(android.view.View, android.graphics.Rect?);
+ method public static void setElevation(android.view.View, float);
+ method @Deprecated public static void setFitsSystemWindows(android.view.View!, boolean);
+ method public static void setFocusedByDefault(android.view.View, boolean);
+ method public static void setHasTransientState(android.view.View, boolean);
+ method @UiThread public static void setImportantForAccessibility(android.view.View, int);
+ method public static void setImportantForAutofill(android.view.View, int);
+ method public static void setKeyboardNavigationCluster(android.view.View, boolean);
+ method public static void setLabelFor(android.view.View, @IdRes int);
+ method public static void setLayerPaint(android.view.View, android.graphics.Paint?);
+ method @Deprecated public static void setLayerType(android.view.View!, int, android.graphics.Paint!);
+ method public static void setLayoutDirection(android.view.View, int);
+ method public static void setNestedScrollingEnabled(android.view.View, boolean);
+ method public static void setNextClusterForwardId(android.view.View, int);
+ method public static void setOnApplyWindowInsetsListener(android.view.View, androidx.core.view.OnApplyWindowInsetsListener?);
+ method public static void setOnReceiveContentListener(android.view.View, String![]?, androidx.core.view.OnReceiveContentListener?);
+ method @Deprecated public static void setOverScrollMode(android.view.View!, int);
+ method public static void setPaddingRelative(android.view.View, @Px int, @Px int, @Px int, @Px int);
+ method @Deprecated public static void setPivotX(android.view.View!, float);
+ method @Deprecated public static void setPivotY(android.view.View!, float);
+ method public static void setPointerIcon(android.view.View, androidx.core.view.PointerIconCompat?);
+ method @Deprecated public static void setRotation(android.view.View!, float);
+ method @Deprecated public static void setRotationX(android.view.View!, float);
+ method @Deprecated public static void setRotationY(android.view.View!, float);
+ method @Deprecated public static void setSaveFromParentEnabled(android.view.View!, boolean);
+ method @Deprecated public static void setScaleX(android.view.View!, float);
+ method @Deprecated public static void setScaleY(android.view.View!, float);
+ method @UiThread public static void setScreenReaderFocusable(android.view.View, boolean);
+ method public static void setScrollIndicators(android.view.View, @androidx.core.view.ViewCompat.ScrollIndicators int);
+ method public static void setScrollIndicators(android.view.View, @androidx.core.view.ViewCompat.ScrollIndicators int, @androidx.core.view.ViewCompat.ScrollIndicators int);
+ method @UiThread public static void setStateDescription(android.view.View, CharSequence?);
+ method public static void setSystemGestureExclusionRects(android.view.View, java.util.List<android.graphics.Rect!>);
+ method public static void setTooltipText(android.view.View, CharSequence?);
+ method public static void setTransitionName(android.view.View, String?);
+ method @Deprecated public static void setTranslationX(android.view.View!, float);
+ method @Deprecated public static void setTranslationY(android.view.View!, float);
+ method public static void setTranslationZ(android.view.View, float);
+ method public static void setWindowInsetsAnimationCallback(android.view.View, androidx.core.view.WindowInsetsAnimationCompat.Callback?);
+ method @Deprecated public static void setX(android.view.View!, float);
+ method @Deprecated public static void setY(android.view.View!, float);
+ method public static void setZ(android.view.View, float);
+ method public static boolean startDragAndDrop(android.view.View, android.content.ClipData?, android.view.View.DragShadowBuilder, Object?, int);
+ method public static boolean startNestedScroll(android.view.View, @androidx.core.view.ViewCompat.ScrollAxis int);
+ method public static boolean startNestedScroll(android.view.View, @androidx.core.view.ViewCompat.ScrollAxis int, @androidx.core.view.ViewCompat.NestedScrollType int);
+ method public static void stopNestedScroll(android.view.View);
+ method public static void stopNestedScroll(android.view.View, @androidx.core.view.ViewCompat.NestedScrollType int);
+ method public static void updateDragShadow(android.view.View, android.view.View.DragShadowBuilder);
+ field public static final int ACCESSIBILITY_LIVE_REGION_ASSERTIVE = 2; // 0x2
+ field public static final int ACCESSIBILITY_LIVE_REGION_NONE = 0; // 0x0
+ field public static final int ACCESSIBILITY_LIVE_REGION_POLITE = 1; // 0x1
+ field public static final int IMPORTANT_FOR_ACCESSIBILITY_AUTO = 0; // 0x0
+ field public static final int IMPORTANT_FOR_ACCESSIBILITY_NO = 2; // 0x2
+ field public static final int IMPORTANT_FOR_ACCESSIBILITY_NO_HIDE_DESCENDANTS = 4; // 0x4
+ field public static final int IMPORTANT_FOR_ACCESSIBILITY_YES = 1; // 0x1
+ field @Deprecated public static final int LAYER_TYPE_HARDWARE = 2; // 0x2
+ field @Deprecated public static final int LAYER_TYPE_NONE = 0; // 0x0
+ field @Deprecated public static final int LAYER_TYPE_SOFTWARE = 1; // 0x1
+ field public static final int LAYOUT_DIRECTION_INHERIT = 2; // 0x2
+ field public static final int LAYOUT_DIRECTION_LOCALE = 3; // 0x3
+ field public static final int LAYOUT_DIRECTION_LTR = 0; // 0x0
+ field public static final int LAYOUT_DIRECTION_RTL = 1; // 0x1
+ field @Deprecated public static final int MEASURED_HEIGHT_STATE_SHIFT = 16; // 0x10
+ field @Deprecated public static final int MEASURED_SIZE_MASK = 16777215; // 0xffffff
+ field @Deprecated public static final int MEASURED_STATE_MASK = -16777216; // 0xff000000
+ field @Deprecated public static final int MEASURED_STATE_TOO_SMALL = 16777216; // 0x1000000
+ field @Deprecated public static final int OVER_SCROLL_ALWAYS = 0; // 0x0
+ field @Deprecated public static final int OVER_SCROLL_IF_CONTENT_SCROLLS = 1; // 0x1
+ field @Deprecated public static final int OVER_SCROLL_NEVER = 2; // 0x2
+ field public static final int SCROLL_AXIS_HORIZONTAL = 1; // 0x1
+ field public static final int SCROLL_AXIS_NONE = 0; // 0x0
+ field public static final int SCROLL_AXIS_VERTICAL = 2; // 0x2
+ field public static final int SCROLL_INDICATOR_BOTTOM = 2; // 0x2
+ field public static final int SCROLL_INDICATOR_END = 32; // 0x20
+ field public static final int SCROLL_INDICATOR_LEFT = 4; // 0x4
+ field public static final int SCROLL_INDICATOR_RIGHT = 8; // 0x8
+ field public static final int SCROLL_INDICATOR_START = 16; // 0x10
+ field public static final int SCROLL_INDICATOR_TOP = 1; // 0x1
+ field public static final int TYPE_NON_TOUCH = 1; // 0x1
+ field public static final int TYPE_TOUCH = 0; // 0x0
+ }
+
+ @IntDef({android.view.View.FOCUS_LEFT, android.view.View.FOCUS_UP, android.view.View.FOCUS_RIGHT, android.view.View.FOCUS_DOWN, android.view.View.FOCUS_FORWARD, android.view.View.FOCUS_BACKWARD}) @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.SOURCE) public static @interface ViewCompat.FocusDirection {
+ }
+
+ @IntDef({android.view.View.FOCUS_LEFT, android.view.View.FOCUS_UP, android.view.View.FOCUS_RIGHT, android.view.View.FOCUS_DOWN}) @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.SOURCE) public static @interface ViewCompat.FocusRealDirection {
+ }
+
+ @IntDef({android.view.View.FOCUS_FORWARD, android.view.View.FOCUS_BACKWARD}) @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.SOURCE) public static @interface ViewCompat.FocusRelativeDirection {
+ }
+
+ @IntDef({androidx.core.view.ViewCompat.TYPE_TOUCH, androidx.core.view.ViewCompat.TYPE_NON_TOUCH}) @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.SOURCE) public static @interface ViewCompat.NestedScrollType {
+ }
+
+ public static interface ViewCompat.OnUnhandledKeyEventListenerCompat {
+ method public boolean onUnhandledKeyEvent(android.view.View, android.view.KeyEvent);
+ }
+
+ @IntDef(value={androidx.core.view.ViewCompat.SCROLL_AXIS_NONE, androidx.core.view.ViewCompat.SCROLL_AXIS_HORIZONTAL, androidx.core.view.ViewCompat.SCROLL_AXIS_VERTICAL}, flag=true) @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.SOURCE) public static @interface ViewCompat.ScrollAxis {
+ }
+
+ @IntDef(flag=true, value={androidx.core.view.ViewCompat.SCROLL_INDICATOR_TOP, androidx.core.view.ViewCompat.SCROLL_INDICATOR_BOTTOM, androidx.core.view.ViewCompat.SCROLL_INDICATOR_LEFT, androidx.core.view.ViewCompat.SCROLL_INDICATOR_RIGHT, androidx.core.view.ViewCompat.SCROLL_INDICATOR_START, androidx.core.view.ViewCompat.SCROLL_INDICATOR_END}) @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.SOURCE) public static @interface ViewCompat.ScrollIndicators {
+ }
+
+ public final class ViewConfigurationCompat {
+ method public static float getScaledHorizontalScrollFactor(android.view.ViewConfiguration, android.content.Context);
+ method public static int getScaledHoverSlop(android.view.ViewConfiguration);
+ method @Deprecated public static int getScaledPagingTouchSlop(android.view.ViewConfiguration!);
+ method public static float getScaledVerticalScrollFactor(android.view.ViewConfiguration, android.content.Context);
+ method @Deprecated public static boolean hasPermanentMenuKey(android.view.ViewConfiguration!);
+ method public static boolean shouldShowMenuShortcutsWhenKeyboardPresent(android.view.ViewConfiguration, android.content.Context);
+ }
+
+ public final class ViewGroupCompat {
+ method public static int getLayoutMode(android.view.ViewGroup);
+ method @androidx.core.view.ViewCompat.ScrollAxis public static int getNestedScrollAxes(android.view.ViewGroup);
+ method public static boolean isTransitionGroup(android.view.ViewGroup);
+ method @Deprecated public static boolean onRequestSendAccessibilityEvent(android.view.ViewGroup!, android.view.View!, android.view.accessibility.AccessibilityEvent!);
+ method public static void setLayoutMode(android.view.ViewGroup, int);
+ method @Deprecated public static void setMotionEventSplittingEnabled(android.view.ViewGroup!, boolean);
+ method public static void setTransitionGroup(android.view.ViewGroup, boolean);
+ field public static final int LAYOUT_MODE_CLIP_BOUNDS = 0; // 0x0
+ field public static final int LAYOUT_MODE_OPTICAL_BOUNDS = 1; // 0x1
+ }
+
+ public final class ViewParentCompat {
+ method public static void notifySubtreeAccessibilityStateChanged(android.view.ViewParent, android.view.View, android.view.View, int);
+ method public static boolean onNestedFling(android.view.ViewParent, android.view.View, float, float, boolean);
+ method public static boolean onNestedPreFling(android.view.ViewParent, android.view.View, float, float);
+ method public static void onNestedPreScroll(android.view.ViewParent, android.view.View, int, int, int[]);
+ method public static void onNestedPreScroll(android.view.ViewParent, android.view.View, int, int, int[], int);
+ method public static void onNestedScroll(android.view.ViewParent, android.view.View, int, int, int, int);
+ method public static void onNestedScroll(android.view.ViewParent, android.view.View, int, int, int, int, int);
+ method public static void onNestedScroll(android.view.ViewParent, android.view.View, int, int, int, int, int, int[]);
+ method public static void onNestedScrollAccepted(android.view.ViewParent, android.view.View, android.view.View, int);
+ method public static void onNestedScrollAccepted(android.view.ViewParent, android.view.View, android.view.View, int, int);
+ method public static boolean onStartNestedScroll(android.view.ViewParent, android.view.View, android.view.View, int);
+ method public static boolean onStartNestedScroll(android.view.ViewParent, android.view.View, android.view.View, int, int);
+ method public static void onStopNestedScroll(android.view.ViewParent, android.view.View);
+ method public static void onStopNestedScroll(android.view.ViewParent, android.view.View, int);
+ method @Deprecated public static boolean requestSendAccessibilityEvent(android.view.ViewParent!, android.view.View!, android.view.accessibility.AccessibilityEvent!);
+ }
+
+ public final class ViewPropertyAnimatorCompat {
+ method public androidx.core.view.ViewPropertyAnimatorCompat alpha(float);
+ method public androidx.core.view.ViewPropertyAnimatorCompat alphaBy(float);
+ method public void cancel();
+ method public long getDuration();
+ method public android.view.animation.Interpolator? getInterpolator();
+ method public long getStartDelay();
+ method public androidx.core.view.ViewPropertyAnimatorCompat rotation(float);
+ method public androidx.core.view.ViewPropertyAnimatorCompat rotationBy(float);
+ method public androidx.core.view.ViewPropertyAnimatorCompat rotationX(float);
+ method public androidx.core.view.ViewPropertyAnimatorCompat rotationXBy(float);
+ method public androidx.core.view.ViewPropertyAnimatorCompat rotationY(float);
+ method public androidx.core.view.ViewPropertyAnimatorCompat rotationYBy(float);
+ method public androidx.core.view.ViewPropertyAnimatorCompat scaleX(float);
+ method public androidx.core.view.ViewPropertyAnimatorCompat scaleXBy(float);
+ method public androidx.core.view.ViewPropertyAnimatorCompat scaleY(float);
+ method public androidx.core.view.ViewPropertyAnimatorCompat scaleYBy(float);
+ method public androidx.core.view.ViewPropertyAnimatorCompat setDuration(long);
+ method public androidx.core.view.ViewPropertyAnimatorCompat setInterpolator(android.view.animation.Interpolator?);
+ method public androidx.core.view.ViewPropertyAnimatorCompat setListener(androidx.core.view.ViewPropertyAnimatorListener?);
+ method public androidx.core.view.ViewPropertyAnimatorCompat setStartDelay(long);
+ method public androidx.core.view.ViewPropertyAnimatorCompat setUpdateListener(androidx.core.view.ViewPropertyAnimatorUpdateListener?);
+ method public void start();
+ method public androidx.core.view.ViewPropertyAnimatorCompat translationX(float);
+ method public androidx.core.view.ViewPropertyAnimatorCompat translationXBy(float);
+ method public androidx.core.view.ViewPropertyAnimatorCompat translationY(float);
+ method public androidx.core.view.ViewPropertyAnimatorCompat translationYBy(float);
+ method public androidx.core.view.ViewPropertyAnimatorCompat translationZ(float);
+ method public androidx.core.view.ViewPropertyAnimatorCompat translationZBy(float);
+ method public androidx.core.view.ViewPropertyAnimatorCompat withEndAction(Runnable);
+ method public androidx.core.view.ViewPropertyAnimatorCompat withLayer();
+ method public androidx.core.view.ViewPropertyAnimatorCompat withStartAction(Runnable);
+ method public androidx.core.view.ViewPropertyAnimatorCompat x(float);
+ method public androidx.core.view.ViewPropertyAnimatorCompat xBy(float);
+ method public androidx.core.view.ViewPropertyAnimatorCompat y(float);
+ method public androidx.core.view.ViewPropertyAnimatorCompat yBy(float);
+ method public androidx.core.view.ViewPropertyAnimatorCompat z(float);
+ method public androidx.core.view.ViewPropertyAnimatorCompat zBy(float);
+ }
+
+ public interface ViewPropertyAnimatorListener {
+ method public void onAnimationCancel(android.view.View);
+ method public void onAnimationEnd(android.view.View);
+ method public void onAnimationStart(android.view.View);
+ }
+
+ public class ViewPropertyAnimatorListenerAdapter implements androidx.core.view.ViewPropertyAnimatorListener {
+ ctor public ViewPropertyAnimatorListenerAdapter();
+ method public void onAnimationCancel(android.view.View);
+ method public void onAnimationEnd(android.view.View);
+ method public void onAnimationStart(android.view.View);
+ }
+
+ public interface ViewPropertyAnimatorUpdateListener {
+ method public void onAnimationUpdate(android.view.View);
+ }
+
+ public final class WindowCompat {
+ method public static androidx.core.view.WindowInsetsControllerCompat getInsetsController(android.view.Window, android.view.View);
+ method public static <T extends android.view.View> T requireViewById(android.view.Window, @IdRes int);
+ method public static void setDecorFitsSystemWindows(android.view.Window, boolean);
+ field public static final int FEATURE_ACTION_BAR = 8; // 0x8
+ field public static final int FEATURE_ACTION_BAR_OVERLAY = 9; // 0x9
+ field public static final int FEATURE_ACTION_MODE_OVERLAY = 10; // 0xa
+ }
+
+ public final class WindowInsetsAnimationCompat {
+ ctor public WindowInsetsAnimationCompat(@androidx.core.view.WindowInsetsCompat.Type.InsetsType int, android.view.animation.Interpolator?, long);
+ method @FloatRange(from=0.0f, to=1.0f) public float getAlpha();
+ method public long getDurationMillis();
+ method @FloatRange(from=0.0f, to=1.0f) public float getFraction();
+ method public float getInterpolatedFraction();
+ method public android.view.animation.Interpolator? getInterpolator();
+ method @androidx.core.view.WindowInsetsCompat.Type.InsetsType public int getTypeMask();
+ method public void setAlpha(@FloatRange(from=0.0f, to=1.0f) float);
+ method public void setFraction(@FloatRange(from=0.0f, to=1.0f) float);
+ }
+
+ public static final class WindowInsetsAnimationCompat.BoundsCompat {
+ ctor public WindowInsetsAnimationCompat.BoundsCompat(androidx.core.graphics.Insets, androidx.core.graphics.Insets);
+ method public androidx.core.graphics.Insets getLowerBound();
+ method public androidx.core.graphics.Insets getUpperBound();
+ method public androidx.core.view.WindowInsetsAnimationCompat.BoundsCompat inset(androidx.core.graphics.Insets);
+ method @RequiresApi(30) public android.view.WindowInsetsAnimation.Bounds toBounds();
+ method @RequiresApi(30) public static androidx.core.view.WindowInsetsAnimationCompat.BoundsCompat toBoundsCompat(android.view.WindowInsetsAnimation.Bounds);
+ }
+
+ public abstract static class WindowInsetsAnimationCompat.Callback {
+ ctor public WindowInsetsAnimationCompat.Callback(@androidx.core.view.WindowInsetsAnimationCompat.Callback.DispatchMode int);
+ method @androidx.core.view.WindowInsetsAnimationCompat.Callback.DispatchMode public final int getDispatchMode();
+ method public void onEnd(androidx.core.view.WindowInsetsAnimationCompat);
+ method public void onPrepare(androidx.core.view.WindowInsetsAnimationCompat);
+ method public abstract androidx.core.view.WindowInsetsCompat onProgress(androidx.core.view.WindowInsetsCompat, java.util.List<androidx.core.view.WindowInsetsAnimationCompat!>);
+ method public androidx.core.view.WindowInsetsAnimationCompat.BoundsCompat onStart(androidx.core.view.WindowInsetsAnimationCompat, androidx.core.view.WindowInsetsAnimationCompat.BoundsCompat);
+ field public static final int DISPATCH_MODE_CONTINUE_ON_SUBTREE = 1; // 0x1
+ field public static final int DISPATCH_MODE_STOP = 0; // 0x0
+ }
+
+ @IntDef({androidx.core.view.WindowInsetsAnimationCompat.Callback.DISPATCH_MODE_STOP, androidx.core.view.WindowInsetsAnimationCompat.Callback.DISPATCH_MODE_CONTINUE_ON_SUBTREE}) @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP) @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.SOURCE) public static @interface WindowInsetsAnimationCompat.Callback.DispatchMode {
+ }
+
+ public interface WindowInsetsAnimationControlListenerCompat {
+ method public void onCancelled(androidx.core.view.WindowInsetsAnimationControllerCompat?);
+ method public void onFinished(androidx.core.view.WindowInsetsAnimationControllerCompat);
+ method public void onReady(androidx.core.view.WindowInsetsAnimationControllerCompat, @androidx.core.view.WindowInsetsCompat.Type.InsetsType int);
+ }
+
+ public final class WindowInsetsAnimationControllerCompat {
+ method public void finish(boolean);
+ method public float getCurrentAlpha();
+ method @FloatRange(from=0.0f, to=1.0f) public float getCurrentFraction();
+ method public androidx.core.graphics.Insets getCurrentInsets();
+ method public androidx.core.graphics.Insets getHiddenStateInsets();
+ method public androidx.core.graphics.Insets getShownStateInsets();
+ method @androidx.core.view.WindowInsetsCompat.Type.InsetsType public int getTypes();
+ method public boolean isCancelled();
+ method public boolean isFinished();
+ method public boolean isReady();
+ method public void setInsetsAndAlpha(androidx.core.graphics.Insets?, @FloatRange(from=0.0f, to=1.0f) float, @FloatRange(from=0.0f, to=1.0f) float);
+ }
+
+ public class WindowInsetsCompat {
+ ctor public WindowInsetsCompat(androidx.core.view.WindowInsetsCompat?);
+ method @Deprecated public androidx.core.view.WindowInsetsCompat consumeDisplayCutout();
+ method @Deprecated public androidx.core.view.WindowInsetsCompat consumeStableInsets();
+ method @Deprecated public androidx.core.view.WindowInsetsCompat consumeSystemWindowInsets();
+ method public androidx.core.view.DisplayCutoutCompat? getDisplayCutout();
+ method public androidx.core.graphics.Insets getInsets(@androidx.core.view.WindowInsetsCompat.Type.InsetsType int);
+ method public androidx.core.graphics.Insets getInsetsIgnoringVisibility(@androidx.core.view.WindowInsetsCompat.Type.InsetsType int);
+ method @Deprecated public androidx.core.graphics.Insets getMandatorySystemGestureInsets();
+ method @Deprecated public int getStableInsetBottom();
+ method @Deprecated public int getStableInsetLeft();
+ method @Deprecated public int getStableInsetRight();
+ method @Deprecated public int getStableInsetTop();
+ method @Deprecated public androidx.core.graphics.Insets getStableInsets();
+ method @Deprecated public androidx.core.graphics.Insets getSystemGestureInsets();
+ method @Deprecated public int getSystemWindowInsetBottom();
+ method @Deprecated public int getSystemWindowInsetLeft();
+ method @Deprecated public int getSystemWindowInsetRight();
+ method @Deprecated public int getSystemWindowInsetTop();
+ method @Deprecated public androidx.core.graphics.Insets getSystemWindowInsets();
+ method @Deprecated public androidx.core.graphics.Insets getTappableElementInsets();
+ method public boolean hasInsets();
+ method @Deprecated public boolean hasStableInsets();
+ method @Deprecated public boolean hasSystemWindowInsets();
+ method public androidx.core.view.WindowInsetsCompat inset(androidx.core.graphics.Insets);
+ method public androidx.core.view.WindowInsetsCompat inset(@IntRange(from=0) int, @IntRange(from=0) int, @IntRange(from=0) int, @IntRange(from=0) int);
+ method public boolean isConsumed();
+ method public boolean isRound();
+ method public boolean isVisible(@androidx.core.view.WindowInsetsCompat.Type.InsetsType int);
+ method @Deprecated public androidx.core.view.WindowInsetsCompat replaceSystemWindowInsets(int, int, int, int);
+ method @Deprecated public androidx.core.view.WindowInsetsCompat replaceSystemWindowInsets(android.graphics.Rect);
+ method @RequiresApi(20) public android.view.WindowInsets? toWindowInsets();
+ method @RequiresApi(20) public static androidx.core.view.WindowInsetsCompat toWindowInsetsCompat(android.view.WindowInsets);
+ method @RequiresApi(20) public static androidx.core.view.WindowInsetsCompat toWindowInsetsCompat(android.view.WindowInsets, android.view.View?);
+ field public static final androidx.core.view.WindowInsetsCompat CONSUMED;
+ }
+
+ public static final class WindowInsetsCompat.Builder {
+ ctor public WindowInsetsCompat.Builder();
+ ctor public WindowInsetsCompat.Builder(androidx.core.view.WindowInsetsCompat);
+ method public androidx.core.view.WindowInsetsCompat build();
+ method public androidx.core.view.WindowInsetsCompat.Builder setDisplayCutout(androidx.core.view.DisplayCutoutCompat?);
+ method public androidx.core.view.WindowInsetsCompat.Builder setInsets(@androidx.core.view.WindowInsetsCompat.Type.InsetsType int, androidx.core.graphics.Insets);
+ method public androidx.core.view.WindowInsetsCompat.Builder setInsetsIgnoringVisibility(@androidx.core.view.WindowInsetsCompat.Type.InsetsType int, androidx.core.graphics.Insets);
+ method @Deprecated public androidx.core.view.WindowInsetsCompat.Builder setMandatorySystemGestureInsets(androidx.core.graphics.Insets);
+ method @Deprecated public androidx.core.view.WindowInsetsCompat.Builder setStableInsets(androidx.core.graphics.Insets);
+ method @Deprecated public androidx.core.view.WindowInsetsCompat.Builder setSystemGestureInsets(androidx.core.graphics.Insets);
+ method @Deprecated public androidx.core.view.WindowInsetsCompat.Builder setSystemWindowInsets(androidx.core.graphics.Insets);
+ method @Deprecated public androidx.core.view.WindowInsetsCompat.Builder setTappableElementInsets(androidx.core.graphics.Insets);
+ method public androidx.core.view.WindowInsetsCompat.Builder setVisible(@androidx.core.view.WindowInsetsCompat.Type.InsetsType int, boolean);
+ }
+
+ public static final class WindowInsetsCompat.Type {
+ method @androidx.core.view.WindowInsetsCompat.Type.InsetsType public static int captionBar();
+ method @androidx.core.view.WindowInsetsCompat.Type.InsetsType public static int displayCutout();
+ method @androidx.core.view.WindowInsetsCompat.Type.InsetsType public static int ime();
+ method @androidx.core.view.WindowInsetsCompat.Type.InsetsType public static int mandatorySystemGestures();
+ method @androidx.core.view.WindowInsetsCompat.Type.InsetsType public static int navigationBars();
+ method @androidx.core.view.WindowInsetsCompat.Type.InsetsType public static int statusBars();
+ method @androidx.core.view.WindowInsetsCompat.Type.InsetsType public static int systemBars();
+ method @androidx.core.view.WindowInsetsCompat.Type.InsetsType public static int systemGestures();
+ method @androidx.core.view.WindowInsetsCompat.Type.InsetsType public static int tappableElement();
+ }
+
+ @IntDef(flag=true, value={0x1, 0x2, 0x4, 0x8, 0x100, 0x10, 0x20, 0x40, 0x80}) @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP) @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.SOURCE) public static @interface WindowInsetsCompat.Type.InsetsType {
+ }
+
+ public final class WindowInsetsControllerCompat {
+ ctor public WindowInsetsControllerCompat(android.view.Window, android.view.View);
+ method public void addOnControllableInsetsChangedListener(androidx.core.view.WindowInsetsControllerCompat.OnControllableInsetsChangedListener);
+ method public void controlWindowInsetsAnimation(@androidx.core.view.WindowInsetsCompat.Type.InsetsType int, long, android.view.animation.Interpolator?, android.os.CancellationSignal?, androidx.core.view.WindowInsetsAnimationControlListenerCompat);
+ method public int getSystemBarsBehavior();
+ method public void hide(@androidx.core.view.WindowInsetsCompat.Type.InsetsType int);
+ method public boolean isAppearanceLightNavigationBars();
+ method public boolean isAppearanceLightStatusBars();
+ method public void removeOnControllableInsetsChangedListener(androidx.core.view.WindowInsetsControllerCompat.OnControllableInsetsChangedListener);
+ method public void setAppearanceLightNavigationBars(boolean);
+ method public void setAppearanceLightStatusBars(boolean);
+ method public void setSystemBarsBehavior(int);
+ method public void show(@androidx.core.view.WindowInsetsCompat.Type.InsetsType int);
+ method @Deprecated @RequiresApi(30) public static androidx.core.view.WindowInsetsControllerCompat toWindowInsetsControllerCompat(android.view.WindowInsetsController);
+ field public static final int BEHAVIOR_DEFAULT = 1; // 0x1
+ field @Deprecated public static final int BEHAVIOR_SHOW_BARS_BY_SWIPE = 1; // 0x1
+ field @Deprecated public static final int BEHAVIOR_SHOW_BARS_BY_TOUCH = 0; // 0x0
+ field public static final int BEHAVIOR_SHOW_TRANSIENT_BARS_BY_SWIPE = 2; // 0x2
+ }
+
+ public static interface WindowInsetsControllerCompat.OnControllableInsetsChangedListener {
+ method public void onControllableInsetsChanged(androidx.core.view.WindowInsetsControllerCompat, @androidx.core.view.WindowInsetsCompat.Type.InsetsType int);
+ }
+
+}
+
+package androidx.core.view.accessibility {
+
+ public final class AccessibilityClickableSpanCompat extends android.text.style.ClickableSpan {
+ ctor @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) public AccessibilityClickableSpanCompat(int, androidx.core.view.accessibility.AccessibilityNodeInfoCompat, int);
+ method public void onClick(android.view.View);
+ field @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) public static final String SPAN_ID = "ACCESSIBILITY_CLICKABLE_SPAN_ID";
+ }
+
+ public final class AccessibilityEventCompat {
+ method @Deprecated public static void appendRecord(android.view.accessibility.AccessibilityEvent!, androidx.core.view.accessibility.AccessibilityRecordCompat!);
+ method @Deprecated public static androidx.core.view.accessibility.AccessibilityRecordCompat! asRecord(android.view.accessibility.AccessibilityEvent!);
+ method public static int getAction(android.view.accessibility.AccessibilityEvent);
+ method @androidx.core.view.accessibility.AccessibilityEventCompat.ContentChangeType public static int getContentChangeTypes(android.view.accessibility.AccessibilityEvent);
+ method public static int getMovementGranularity(android.view.accessibility.AccessibilityEvent);
+ method @Deprecated public static androidx.core.view.accessibility.AccessibilityRecordCompat! getRecord(android.view.accessibility.AccessibilityEvent!, int);
+ method @Deprecated public static int getRecordCount(android.view.accessibility.AccessibilityEvent!);
+ method public static void setAction(android.view.accessibility.AccessibilityEvent, int);
+ method public static void setContentChangeTypes(android.view.accessibility.AccessibilityEvent, @androidx.core.view.accessibility.AccessibilityEventCompat.ContentChangeType int);
+ method public static void setMovementGranularity(android.view.accessibility.AccessibilityEvent, int);
+ field public static final int CONTENT_CHANGE_TYPE_CONTENT_DESCRIPTION = 4; // 0x4
+ field public static final int CONTENT_CHANGE_TYPE_DRAG_CANCELLED = 512; // 0x200
+ field public static final int CONTENT_CHANGE_TYPE_DRAG_DROPPED = 256; // 0x100
+ field public static final int CONTENT_CHANGE_TYPE_DRAG_STARTED = 128; // 0x80
+ field public static final int CONTENT_CHANGE_TYPE_PANE_APPEARED = 16; // 0x10
+ field public static final int CONTENT_CHANGE_TYPE_PANE_DISAPPEARED = 32; // 0x20
+ field public static final int CONTENT_CHANGE_TYPE_PANE_TITLE = 8; // 0x8
+ field public static final int CONTENT_CHANGE_TYPE_STATE_DESCRIPTION = 64; // 0x40
+ field public static final int CONTENT_CHANGE_TYPE_SUBTREE = 1; // 0x1
+ field public static final int CONTENT_CHANGE_TYPE_TEXT = 2; // 0x2
+ field public static final int CONTENT_CHANGE_TYPE_UNDEFINED = 0; // 0x0
+ field public static final int TYPES_ALL_MASK = -1; // 0xffffffff
+ field public static final int TYPE_ANNOUNCEMENT = 16384; // 0x4000
+ field public static final int TYPE_ASSIST_READING_CONTEXT = 16777216; // 0x1000000
+ field public static final int TYPE_GESTURE_DETECTION_END = 524288; // 0x80000
+ field public static final int TYPE_GESTURE_DETECTION_START = 262144; // 0x40000
+ field @Deprecated public static final int TYPE_TOUCH_EXPLORATION_GESTURE_END = 1024; // 0x400
+ field @Deprecated public static final int TYPE_TOUCH_EXPLORATION_GESTURE_START = 512; // 0x200
+ field public static final int TYPE_TOUCH_INTERACTION_END = 2097152; // 0x200000
+ field public static final int TYPE_TOUCH_INTERACTION_START = 1048576; // 0x100000
+ field public static final int TYPE_VIEW_ACCESSIBILITY_FOCUSED = 32768; // 0x8000
+ field public static final int TYPE_VIEW_ACCESSIBILITY_FOCUS_CLEARED = 65536; // 0x10000
+ field public static final int TYPE_VIEW_CONTEXT_CLICKED = 8388608; // 0x800000
+ field @Deprecated public static final int TYPE_VIEW_HOVER_ENTER = 128; // 0x80
+ field @Deprecated public static final int TYPE_VIEW_HOVER_EXIT = 256; // 0x100
+ field @Deprecated public static final int TYPE_VIEW_SCROLLED = 4096; // 0x1000
+ field @Deprecated public static final int TYPE_VIEW_TEXT_SELECTION_CHANGED = 8192; // 0x2000
+ field public static final int TYPE_VIEW_TEXT_TRAVERSED_AT_MOVEMENT_GRANULARITY = 131072; // 0x20000
+ field public static final int TYPE_WINDOWS_CHANGED = 4194304; // 0x400000
+ field @Deprecated public static final int TYPE_WINDOW_CONTENT_CHANGED = 2048; // 0x800
+ }
+
+ @IntDef(flag=true, value={androidx.core.view.accessibility.AccessibilityEventCompat.CONTENT_CHANGE_TYPE_CONTENT_DESCRIPTION, androidx.core.view.accessibility.AccessibilityEventCompat.CONTENT_CHANGE_TYPE_STATE_DESCRIPTION, androidx.core.view.accessibility.AccessibilityEventCompat.CONTENT_CHANGE_TYPE_SUBTREE, androidx.core.view.accessibility.AccessibilityEventCompat.CONTENT_CHANGE_TYPE_TEXT, androidx.core.view.accessibility.AccessibilityEventCompat.CONTENT_CHANGE_TYPE_UNDEFINED, androidx.core.view.accessibility.AccessibilityEventCompat.CONTENT_CHANGE_TYPE_DRAG_STARTED, androidx.core.view.accessibility.AccessibilityEventCompat.CONTENT_CHANGE_TYPE_DRAG_DROPPED, androidx.core.view.accessibility.AccessibilityEventCompat.CONTENT_CHANGE_TYPE_DRAG_CANCELLED}) @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.SOURCE) public static @interface AccessibilityEventCompat.ContentChangeType {
+ }
+
+ public final class AccessibilityManagerCompat {
+ method @Deprecated public static boolean addAccessibilityStateChangeListener(android.view.accessibility.AccessibilityManager!, androidx.core.view.accessibility.AccessibilityManagerCompat.AccessibilityStateChangeListener!);
+ method public static boolean addTouchExplorationStateChangeListener(android.view.accessibility.AccessibilityManager, androidx.core.view.accessibility.AccessibilityManagerCompat.TouchExplorationStateChangeListener);
+ method @Deprecated public static java.util.List<android.accessibilityservice.AccessibilityServiceInfo!>! getEnabledAccessibilityServiceList(android.view.accessibility.AccessibilityManager!, int);
+ method @Deprecated public static java.util.List<android.accessibilityservice.AccessibilityServiceInfo!>! getInstalledAccessibilityServiceList(android.view.accessibility.AccessibilityManager!);
+ method @Deprecated public static boolean isTouchExplorationEnabled(android.view.accessibility.AccessibilityManager!);
+ method @Deprecated public static boolean removeAccessibilityStateChangeListener(android.view.accessibility.AccessibilityManager!, androidx.core.view.accessibility.AccessibilityManagerCompat.AccessibilityStateChangeListener!);
+ method public static boolean removeTouchExplorationStateChangeListener(android.view.accessibility.AccessibilityManager, androidx.core.view.accessibility.AccessibilityManagerCompat.TouchExplorationStateChangeListener);
+ }
+
+ @Deprecated public static interface AccessibilityManagerCompat.AccessibilityStateChangeListener {
+ method @Deprecated public void onAccessibilityStateChanged(boolean);
+ }
+
+ @Deprecated public abstract static class AccessibilityManagerCompat.AccessibilityStateChangeListenerCompat implements androidx.core.view.accessibility.AccessibilityManagerCompat.AccessibilityStateChangeListener {
+ ctor @Deprecated public AccessibilityManagerCompat.AccessibilityStateChangeListenerCompat();
+ }
+
+ public static interface AccessibilityManagerCompat.TouchExplorationStateChangeListener {
+ method public void onTouchExplorationStateChanged(boolean);
+ }
+
+ public class AccessibilityNodeInfoCompat {
+ ctor @Deprecated public AccessibilityNodeInfoCompat(Object!);
+ method public void addAction(int);
+ method public void addAction(androidx.core.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat!);
+ method public void addChild(android.view.View!);
+ method public void addChild(android.view.View!, int);
+ method @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) public void addSpansToExtras(CharSequence!, android.view.View!);
+ method public boolean canOpenPopup();
+ method public java.util.List<androidx.core.view.accessibility.AccessibilityNodeInfoCompat!>! findAccessibilityNodeInfosByText(String!);
+ method public java.util.List<androidx.core.view.accessibility.AccessibilityNodeInfoCompat!>! findAccessibilityNodeInfosByViewId(String!);
+ method public androidx.core.view.accessibility.AccessibilityNodeInfoCompat! findFocus(int);
+ method public androidx.core.view.accessibility.AccessibilityNodeInfoCompat! focusSearch(int);
+ method public java.util.List<androidx.core.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat!>! getActionList();
+ method @Deprecated public int getActions();
+ method public java.util.List<java.lang.String!> getAvailableExtraData();
+ method @Deprecated public void getBoundsInParent(android.graphics.Rect!);
+ method public void getBoundsInScreen(android.graphics.Rect!);
+ method public androidx.core.view.accessibility.AccessibilityNodeInfoCompat! getChild(int);
+ method public int getChildCount();
+ method public CharSequence! getClassName();
+ method @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) public static android.text.style.ClickableSpan![]! getClickableSpans(CharSequence!);
+ method public androidx.core.view.accessibility.AccessibilityNodeInfoCompat.CollectionInfoCompat! getCollectionInfo();
+ method public androidx.core.view.accessibility.AccessibilityNodeInfoCompat.CollectionItemInfoCompat! getCollectionItemInfo();
+ method public CharSequence! getContentDescription();
+ method public int getDrawingOrder();
+ method public CharSequence! getError();
+ method public android.view.accessibility.AccessibilityNodeInfo.ExtraRenderingInfo? getExtraRenderingInfo();
+ method public android.os.Bundle! getExtras();
+ method public CharSequence? getHintText();
+ method @Deprecated public Object! getInfo();
+ method public int getInputType();
+ method public androidx.core.view.accessibility.AccessibilityNodeInfoCompat! getLabelFor();
+ method public androidx.core.view.accessibility.AccessibilityNodeInfoCompat! getLabeledBy();
+ method public int getLiveRegion();
+ method public int getMaxTextLength();
+ method public int getMinMillisBetweenContentChanges();
+ method public int getMovementGranularities();
+ method public CharSequence! getPackageName();
+ method public CharSequence? getPaneTitle();
+ method public androidx.core.view.accessibility.AccessibilityNodeInfoCompat! getParent();
+ method public androidx.core.view.accessibility.AccessibilityNodeInfoCompat.RangeInfoCompat! getRangeInfo();
+ method public CharSequence? getRoleDescription();
+ method public CharSequence? getStateDescription();
+ method public CharSequence! getText();
+ method public int getTextSelectionEnd();
+ method public int getTextSelectionStart();
+ method public CharSequence? getTooltipText();
+ method public androidx.core.view.accessibility.AccessibilityNodeInfoCompat.TouchDelegateInfoCompat? getTouchDelegateInfo();
+ method public androidx.core.view.accessibility.AccessibilityNodeInfoCompat! getTraversalAfter();
+ method public androidx.core.view.accessibility.AccessibilityNodeInfoCompat! getTraversalBefore();
+ method public String? getUniqueId();
+ method public String! getViewIdResourceName();
+ method public androidx.core.view.accessibility.AccessibilityWindowInfoCompat! getWindow();
+ method public int getWindowId();
+ method public boolean hasRequestInitialAccessibilityFocus();
+ method public boolean isAccessibilityFocused();
+ method public boolean isCheckable();
+ method public boolean isChecked();
+ method public boolean isClickable();
+ method public boolean isContentInvalid();
+ method public boolean isContextClickable();
+ method public boolean isDismissable();
+ method public boolean isEditable();
+ method public boolean isEnabled();
+ method public boolean isFocusable();
+ method public boolean isFocused();
+ method public boolean isHeading();
+ method public boolean isImportantForAccessibility();
+ method public boolean isLongClickable();
+ method public boolean isMultiLine();
+ method public boolean isPassword();
+ method public boolean isScreenReaderFocusable();
+ method public boolean isScrollable();
+ method public boolean isSelected();
+ method public boolean isShowingHintText();
+ method public boolean isTextEntryKey();
+ method public boolean isTextSelectable();
+ method public boolean isVisibleToUser();
+ method public static androidx.core.view.accessibility.AccessibilityNodeInfoCompat! obtain(android.view.View!);
+ method public static androidx.core.view.accessibility.AccessibilityNodeInfoCompat! obtain(android.view.View!, int);
+ method public static androidx.core.view.accessibility.AccessibilityNodeInfoCompat! obtain();
+ method public static androidx.core.view.accessibility.AccessibilityNodeInfoCompat! obtain(androidx.core.view.accessibility.AccessibilityNodeInfoCompat!);
+ method public boolean performAction(int);
+ method public boolean performAction(int, android.os.Bundle!);
+ method @Deprecated public void recycle();
+ method public boolean refresh();
+ method public boolean removeAction(androidx.core.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat!);
+ method public boolean removeChild(android.view.View!);
+ method public boolean removeChild(android.view.View!, int);
+ method public void setAccessibilityFocused(boolean);
+ method public void setAvailableExtraData(java.util.List<java.lang.String!>);
+ method @Deprecated public void setBoundsInParent(android.graphics.Rect!);
+ method public void setBoundsInScreen(android.graphics.Rect!);
+ method public void setCanOpenPopup(boolean);
+ method public void setCheckable(boolean);
+ method public void setChecked(boolean);
+ method public void setClassName(CharSequence!);
+ method public void setClickable(boolean);
+ method public void setCollectionInfo(Object!);
+ method public void setCollectionItemInfo(Object!);
+ method public void setContentDescription(CharSequence!);
+ method public void setContentInvalid(boolean);
+ method public void setContextClickable(boolean);
+ method public void setDismissable(boolean);
+ method public void setDrawingOrder(int);
+ method public void setEditable(boolean);
+ method public void setEnabled(boolean);
+ method public void setError(CharSequence!);
+ method public void setFocusable(boolean);
+ method public void setFocused(boolean);
+ method public void setHeading(boolean);
+ method public void setHintText(CharSequence?);
+ method public void setImportantForAccessibility(boolean);
+ method public void setInputType(int);
+ method public void setLabelFor(android.view.View!);
+ method public void setLabelFor(android.view.View!, int);
+ method public void setLabeledBy(android.view.View!);
+ method public void setLabeledBy(android.view.View!, int);
+ method public void setLiveRegion(int);
+ method public void setLongClickable(boolean);
+ method public void setMaxTextLength(int);
+ method public void setMinMillisBetweenContentChanges(int);
+ method public void setMovementGranularities(int);
+ method public void setMultiLine(boolean);
+ method public void setPackageName(CharSequence!);
+ method public void setPaneTitle(CharSequence?);
+ method public void setParent(android.view.View!);
+ method public void setParent(android.view.View!, int);
+ method public void setPassword(boolean);
+ method public void setRangeInfo(androidx.core.view.accessibility.AccessibilityNodeInfoCompat.RangeInfoCompat!);
+ method public void setRequestInitialAccessibilityFocus(boolean);
+ method public void setRoleDescription(CharSequence?);
+ method public void setScreenReaderFocusable(boolean);
+ method public void setScrollable(boolean);
+ method public void setSelected(boolean);
+ method public void setShowingHintText(boolean);
+ method public void setSource(android.view.View!);
+ method public void setSource(android.view.View!, int);
+ method public void setStateDescription(CharSequence?);
+ method public void setText(CharSequence!);
+ method public void setTextEntryKey(boolean);
+ method public void setTextSelectable(boolean);
+ method public void setTextSelection(int, int);
+ method public void setTooltipText(CharSequence?);
+ method public void setTouchDelegateInfo(androidx.core.view.accessibility.AccessibilityNodeInfoCompat.TouchDelegateInfoCompat);
+ method public void setTraversalAfter(android.view.View!);
+ method public void setTraversalAfter(android.view.View!, int);
+ method public void setTraversalBefore(android.view.View!);
+ method public void setTraversalBefore(android.view.View!, int);
+ method public void setUniqueId(String?);
+ method public void setViewIdResourceName(String!);
+ method public void setVisibleToUser(boolean);
+ method public android.view.accessibility.AccessibilityNodeInfo! unwrap();
+ method public static androidx.core.view.accessibility.AccessibilityNodeInfoCompat! wrap(android.view.accessibility.AccessibilityNodeInfo);
+ field public static final int ACTION_ACCESSIBILITY_FOCUS = 64; // 0x40
+ field public static final String ACTION_ARGUMENT_COLUMN_INT = "android.view.accessibility.action.ARGUMENT_COLUMN_INT";
+ field public static final String ACTION_ARGUMENT_EXTEND_SELECTION_BOOLEAN = "ACTION_ARGUMENT_EXTEND_SELECTION_BOOLEAN";
+ field public static final String ACTION_ARGUMENT_HTML_ELEMENT_STRING = "ACTION_ARGUMENT_HTML_ELEMENT_STRING";
+ field public static final String ACTION_ARGUMENT_MOVEMENT_GRANULARITY_INT = "ACTION_ARGUMENT_MOVEMENT_GRANULARITY_INT";
+ field public static final String ACTION_ARGUMENT_MOVE_WINDOW_X = "ACTION_ARGUMENT_MOVE_WINDOW_X";
+ field public static final String ACTION_ARGUMENT_MOVE_WINDOW_Y = "ACTION_ARGUMENT_MOVE_WINDOW_Y";
+ field public static final String ACTION_ARGUMENT_PRESS_AND_HOLD_DURATION_MILLIS_INT = "android.view.accessibility.action.ARGUMENT_PRESS_AND_HOLD_DURATION_MILLIS_INT";
+ field public static final String ACTION_ARGUMENT_PROGRESS_VALUE = "android.view.accessibility.action.ARGUMENT_PROGRESS_VALUE";
+ field public static final String ACTION_ARGUMENT_ROW_INT = "android.view.accessibility.action.ARGUMENT_ROW_INT";
+ field public static final String ACTION_ARGUMENT_SELECTION_END_INT = "ACTION_ARGUMENT_SELECTION_END_INT";
+ field public static final String ACTION_ARGUMENT_SELECTION_START_INT = "ACTION_ARGUMENT_SELECTION_START_INT";
+ field public static final String ACTION_ARGUMENT_SET_TEXT_CHARSEQUENCE = "ACTION_ARGUMENT_SET_TEXT_CHARSEQUENCE";
+ field public static final int ACTION_CLEAR_ACCESSIBILITY_FOCUS = 128; // 0x80
+ field public static final int ACTION_CLEAR_FOCUS = 2; // 0x2
+ field public static final int ACTION_CLEAR_SELECTION = 8; // 0x8
+ field public static final int ACTION_CLICK = 16; // 0x10
+ field public static final int ACTION_COLLAPSE = 524288; // 0x80000
+ field public static final int ACTION_COPY = 16384; // 0x4000
+ field public static final int ACTION_CUT = 65536; // 0x10000
+ field public static final int ACTION_DISMISS = 1048576; // 0x100000
+ field public static final int ACTION_EXPAND = 262144; // 0x40000
+ field public static final int ACTION_FOCUS = 1; // 0x1
+ field public static final int ACTION_LONG_CLICK = 32; // 0x20
+ field public static final int ACTION_NEXT_AT_MOVEMENT_GRANULARITY = 256; // 0x100
+ field public static final int ACTION_NEXT_HTML_ELEMENT = 1024; // 0x400
+ field public static final int ACTION_PASTE = 32768; // 0x8000
+ field public static final int ACTION_PREVIOUS_AT_MOVEMENT_GRANULARITY = 512; // 0x200
+ field public static final int ACTION_PREVIOUS_HTML_ELEMENT = 2048; // 0x800
+ field public static final int ACTION_SCROLL_BACKWARD = 8192; // 0x2000
+ field public static final int ACTION_SCROLL_FORWARD = 4096; // 0x1000
+ field public static final int ACTION_SELECT = 4; // 0x4
+ field public static final int ACTION_SET_SELECTION = 131072; // 0x20000
+ field public static final int ACTION_SET_TEXT = 2097152; // 0x200000
+ field public static final String EXTRA_DATA_TEXT_CHARACTER_LOCATION_ARG_LENGTH = "android.core.view.accessibility.extra.DATA_TEXT_CHARACTER_LOCATION_ARG_LENGTH";
+ field public static final int EXTRA_DATA_TEXT_CHARACTER_LOCATION_ARG_MAX_LENGTH = 20000; // 0x4e20
+ field public static final String EXTRA_DATA_TEXT_CHARACTER_LOCATION_ARG_START_INDEX = "android.core.view.accessibility.extra.DATA_TEXT_CHARACTER_LOCATION_ARG_START_INDEX";
+ field public static final String EXTRA_DATA_TEXT_CHARACTER_LOCATION_KEY = "android.core.view.accessibility.extra.DATA_TEXT_CHARACTER_LOCATION_KEY";
+ field public static final int FOCUS_ACCESSIBILITY = 2; // 0x2
+ field public static final int FOCUS_INPUT = 1; // 0x1
+ field public static final int MOVEMENT_GRANULARITY_CHARACTER = 1; // 0x1
+ field public static final int MOVEMENT_GRANULARITY_LINE = 4; // 0x4
+ field public static final int MOVEMENT_GRANULARITY_PAGE = 16; // 0x10
+ field public static final int MOVEMENT_GRANULARITY_PARAGRAPH = 8; // 0x8
+ field public static final int MOVEMENT_GRANULARITY_WORD = 2; // 0x2
+ field @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) public int mParentVirtualDescendantId;
+ }
+
+ public static class AccessibilityNodeInfoCompat.AccessibilityActionCompat {
+ ctor public AccessibilityNodeInfoCompat.AccessibilityActionCompat(int, CharSequence!);
+ ctor @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) public AccessibilityNodeInfoCompat.AccessibilityActionCompat(int, CharSequence!, androidx.core.view.accessibility.AccessibilityViewCommand!);
+ method @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) public androidx.core.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat! createReplacementAction(CharSequence!, androidx.core.view.accessibility.AccessibilityViewCommand!);
+ method public int getId();
+ method public CharSequence! getLabel();
+ method @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) public boolean perform(android.view.View!, android.os.Bundle!);
+ field public static final androidx.core.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat! ACTION_ACCESSIBILITY_FOCUS;
+ field public static final androidx.core.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat! ACTION_CLEAR_ACCESSIBILITY_FOCUS;
+ field public static final androidx.core.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat! ACTION_CLEAR_FOCUS;
+ field public static final androidx.core.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat! ACTION_CLEAR_SELECTION;
+ field public static final androidx.core.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat! ACTION_CLICK;
+ field public static final androidx.core.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat! ACTION_COLLAPSE;
+ field public static final androidx.core.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat! ACTION_CONTEXT_CLICK;
+ field public static final androidx.core.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat! ACTION_COPY;
+ field public static final androidx.core.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat! ACTION_CUT;
+ field public static final androidx.core.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat! ACTION_DISMISS;
+ field public static final androidx.core.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat ACTION_DRAG_CANCEL;
+ field public static final androidx.core.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat ACTION_DRAG_DROP;
+ field public static final androidx.core.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat ACTION_DRAG_START;
+ field public static final androidx.core.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat! ACTION_EXPAND;
+ field public static final androidx.core.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat! ACTION_FOCUS;
+ field public static final androidx.core.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat! ACTION_HIDE_TOOLTIP;
+ field public static final androidx.core.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat ACTION_IME_ENTER;
+ field public static final androidx.core.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat! ACTION_LONG_CLICK;
+ field public static final androidx.core.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat! ACTION_MOVE_WINDOW;
+ field public static final androidx.core.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat! ACTION_NEXT_AT_MOVEMENT_GRANULARITY;
+ field public static final androidx.core.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat! ACTION_NEXT_HTML_ELEMENT;
+ field public static final androidx.core.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat ACTION_PAGE_DOWN;
+ field public static final androidx.core.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat ACTION_PAGE_LEFT;
+ field public static final androidx.core.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat ACTION_PAGE_RIGHT;
+ field public static final androidx.core.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat ACTION_PAGE_UP;
+ field public static final androidx.core.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat! ACTION_PASTE;
+ field public static final androidx.core.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat ACTION_PRESS_AND_HOLD;
+ field public static final androidx.core.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat! ACTION_PREVIOUS_AT_MOVEMENT_GRANULARITY;
+ field public static final androidx.core.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat! ACTION_PREVIOUS_HTML_ELEMENT;
+ field public static final androidx.core.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat! ACTION_SCROLL_BACKWARD;
+ field public static final androidx.core.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat! ACTION_SCROLL_DOWN;
+ field public static final androidx.core.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat! ACTION_SCROLL_FORWARD;
+ field public static final androidx.core.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat! ACTION_SCROLL_LEFT;
+ field public static final androidx.core.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat! ACTION_SCROLL_RIGHT;
+ field public static final androidx.core.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat! ACTION_SCROLL_TO_POSITION;
+ field public static final androidx.core.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat! ACTION_SCROLL_UP;
+ field public static final androidx.core.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat! ACTION_SELECT;
+ field public static final androidx.core.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat! ACTION_SET_PROGRESS;
+ field public static final androidx.core.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat! ACTION_SET_SELECTION;
+ field public static final androidx.core.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat! ACTION_SET_TEXT;
+ field public static final androidx.core.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat! ACTION_SHOW_ON_SCREEN;
+ field public static final androidx.core.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat ACTION_SHOW_TEXT_SUGGESTIONS;
+ field public static final androidx.core.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat! ACTION_SHOW_TOOLTIP;
+ field @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) protected final androidx.core.view.accessibility.AccessibilityViewCommand! mCommand;
+ }
+
+ public static class AccessibilityNodeInfoCompat.CollectionInfoCompat {
+ method public int getColumnCount();
+ method public int getRowCount();
+ method public int getSelectionMode();
+ method public boolean isHierarchical();
+ method public static androidx.core.view.accessibility.AccessibilityNodeInfoCompat.CollectionInfoCompat! obtain(int, int, boolean, int);
+ method public static androidx.core.view.accessibility.AccessibilityNodeInfoCompat.CollectionInfoCompat! obtain(int, int, boolean);
+ field public static final int SELECTION_MODE_MULTIPLE = 2; // 0x2
+ field public static final int SELECTION_MODE_NONE = 0; // 0x0
+ field public static final int SELECTION_MODE_SINGLE = 1; // 0x1
+ }
+
+ public static class AccessibilityNodeInfoCompat.CollectionItemInfoCompat {
+ method public int getColumnIndex();
+ method public int getColumnSpan();
+ method public int getRowIndex();
+ method public int getRowSpan();
+ method @Deprecated public boolean isHeading();
+ method public boolean isSelected();
+ method public static androidx.core.view.accessibility.AccessibilityNodeInfoCompat.CollectionItemInfoCompat! obtain(int, int, int, int, boolean, boolean);
+ method public static androidx.core.view.accessibility.AccessibilityNodeInfoCompat.CollectionItemInfoCompat! obtain(int, int, int, int, boolean);
+ }
+
+ public static class AccessibilityNodeInfoCompat.RangeInfoCompat {
+ method public float getCurrent();
+ method public float getMax();
+ method public float getMin();
+ method public int getType();
+ method public static androidx.core.view.accessibility.AccessibilityNodeInfoCompat.RangeInfoCompat! obtain(int, float, float, float);
+ field public static final int RANGE_TYPE_FLOAT = 1; // 0x1
+ field public static final int RANGE_TYPE_INT = 0; // 0x0
+ field public static final int RANGE_TYPE_PERCENT = 2; // 0x2
+ }
+
+ public static final class AccessibilityNodeInfoCompat.TouchDelegateInfoCompat {
+ ctor public AccessibilityNodeInfoCompat.TouchDelegateInfoCompat(java.util.Map<android.graphics.Region!,android.view.View!>);
+ method public android.graphics.Region? getRegionAt(@IntRange(from=0) int);
+ method @IntRange(from=0) public int getRegionCount();
+ method public androidx.core.view.accessibility.AccessibilityNodeInfoCompat? getTargetForRegion(android.graphics.Region);
+ }
+
+ public class AccessibilityNodeProviderCompat {
+ ctor public AccessibilityNodeProviderCompat();
+ ctor public AccessibilityNodeProviderCompat(Object?);
+ method public void addExtraDataToAccessibilityNodeInfo(int, androidx.core.view.accessibility.AccessibilityNodeInfoCompat, String, android.os.Bundle?);
+ method public androidx.core.view.accessibility.AccessibilityNodeInfoCompat? createAccessibilityNodeInfo(int);
+ method public java.util.List<androidx.core.view.accessibility.AccessibilityNodeInfoCompat!>? findAccessibilityNodeInfosByText(String, int);
+ method public androidx.core.view.accessibility.AccessibilityNodeInfoCompat? findFocus(int);
+ method public Object? getProvider();
+ method public boolean performAction(int, int, android.os.Bundle?);
+ field public static final int HOST_VIEW_ID = -1; // 0xffffffff
+ }
+
+ public class AccessibilityRecordCompat {
+ ctor @Deprecated public AccessibilityRecordCompat(Object!);
+ method @Deprecated public boolean equals(Object?);
+ method @Deprecated public int getAddedCount();
+ method @Deprecated public CharSequence! getBeforeText();
+ method @Deprecated public CharSequence! getClassName();
+ method @Deprecated public CharSequence! getContentDescription();
+ method @Deprecated public int getCurrentItemIndex();
+ method @Deprecated public int getFromIndex();
+ method @Deprecated public Object! getImpl();
+ method @Deprecated public int getItemCount();
+ method @Deprecated public int getMaxScrollX();
+ method public static int getMaxScrollX(android.view.accessibility.AccessibilityRecord);
+ method @Deprecated public int getMaxScrollY();
+ method public static int getMaxScrollY(android.view.accessibility.AccessibilityRecord);
+ method @Deprecated public android.os.Parcelable! getParcelableData();
+ method @Deprecated public int getRemovedCount();
+ method @Deprecated public int getScrollX();
+ method @Deprecated public int getScrollY();
+ method @Deprecated public androidx.core.view.accessibility.AccessibilityNodeInfoCompat! getSource();
+ method @Deprecated public java.util.List<java.lang.CharSequence!>! getText();
+ method @Deprecated public int getToIndex();
+ method @Deprecated public int getWindowId();
+ method @Deprecated public int hashCode();
+ method @Deprecated public boolean isChecked();
+ method @Deprecated public boolean isEnabled();
+ method @Deprecated public boolean isFullScreen();
+ method @Deprecated public boolean isPassword();
+ method @Deprecated public boolean isScrollable();
+ method @Deprecated public static androidx.core.view.accessibility.AccessibilityRecordCompat! obtain(androidx.core.view.accessibility.AccessibilityRecordCompat!);
+ method @Deprecated public static androidx.core.view.accessibility.AccessibilityRecordCompat! obtain();
+ method @Deprecated public void recycle();
+ method @Deprecated public void setAddedCount(int);
+ method @Deprecated public void setBeforeText(CharSequence!);
+ method @Deprecated public void setChecked(boolean);
+ method @Deprecated public void setClassName(CharSequence!);
+ method @Deprecated public void setContentDescription(CharSequence!);
+ method @Deprecated public void setCurrentItemIndex(int);
+ method @Deprecated public void setEnabled(boolean);
+ method @Deprecated public void setFromIndex(int);
+ method @Deprecated public void setFullScreen(boolean);
+ method @Deprecated public void setItemCount(int);
+ method @Deprecated public void setMaxScrollX(int);
+ method public static void setMaxScrollX(android.view.accessibility.AccessibilityRecord, int);
+ method @Deprecated public void setMaxScrollY(int);
+ method public static void setMaxScrollY(android.view.accessibility.AccessibilityRecord, int);
+ method @Deprecated public void setParcelableData(android.os.Parcelable!);
+ method @Deprecated public void setPassword(boolean);
+ method @Deprecated public void setRemovedCount(int);
+ method @Deprecated public void setScrollX(int);
+ method @Deprecated public void setScrollY(int);
+ method @Deprecated public void setScrollable(boolean);
+ method @Deprecated public void setSource(android.view.View!);
+ method @Deprecated public void setSource(android.view.View!, int);
+ method public static void setSource(android.view.accessibility.AccessibilityRecord, android.view.View?, int);
+ method @Deprecated public void setToIndex(int);
+ }
+
+ public interface AccessibilityViewCommand {
+ method public boolean perform(android.view.View, androidx.core.view.accessibility.AccessibilityViewCommand.CommandArguments?);
+ }
+
+ public abstract static class AccessibilityViewCommand.CommandArguments {
+ ctor public AccessibilityViewCommand.CommandArguments();
+ method @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) public void setBundle(android.os.Bundle?);
+ }
+
+ public static final class AccessibilityViewCommand.MoveAtGranularityArguments extends androidx.core.view.accessibility.AccessibilityViewCommand.CommandArguments {
+ ctor public AccessibilityViewCommand.MoveAtGranularityArguments();
+ method public boolean getExtendSelection();
+ method public int getGranularity();
+ }
+
+ public static final class AccessibilityViewCommand.MoveHtmlArguments extends androidx.core.view.accessibility.AccessibilityViewCommand.CommandArguments {
+ ctor public AccessibilityViewCommand.MoveHtmlArguments();
+ method public String? getHTMLElement();
+ }
+
+ public static final class AccessibilityViewCommand.MoveWindowArguments extends androidx.core.view.accessibility.AccessibilityViewCommand.CommandArguments {
+ ctor public AccessibilityViewCommand.MoveWindowArguments();
+ method public int getX();
+ method public int getY();
+ }
+
+ public static final class AccessibilityViewCommand.ScrollToPositionArguments extends androidx.core.view.accessibility.AccessibilityViewCommand.CommandArguments {
+ ctor public AccessibilityViewCommand.ScrollToPositionArguments();
+ method public int getColumn();
+ method public int getRow();
+ }
+
+ public static final class AccessibilityViewCommand.SetProgressArguments extends androidx.core.view.accessibility.AccessibilityViewCommand.CommandArguments {
+ ctor public AccessibilityViewCommand.SetProgressArguments();
+ method public float getProgress();
+ }
+
+ public static final class AccessibilityViewCommand.SetSelectionArguments extends androidx.core.view.accessibility.AccessibilityViewCommand.CommandArguments {
+ ctor public AccessibilityViewCommand.SetSelectionArguments();
+ method public int getEnd();
+ method public int getStart();
+ }
+
+ public static final class AccessibilityViewCommand.SetTextArguments extends androidx.core.view.accessibility.AccessibilityViewCommand.CommandArguments {
+ ctor public AccessibilityViewCommand.SetTextArguments();
+ method public CharSequence? getText();
+ }
+
+ public class AccessibilityWindowInfoCompat {
+ method public androidx.core.view.accessibility.AccessibilityNodeInfoCompat? getAnchor();
+ method public void getBoundsInScreen(android.graphics.Rect);
+ method public androidx.core.view.accessibility.AccessibilityWindowInfoCompat? getChild(int);
+ method public int getChildCount();
+ method public int getDisplayId();
+ method public int getId();
+ method public int getLayer();
+ method public androidx.core.view.accessibility.AccessibilityWindowInfoCompat? getParent();
+ method public void getRegionInScreen(android.graphics.Region);
+ method public androidx.core.view.accessibility.AccessibilityNodeInfoCompat? getRoot();
+ method public CharSequence? getTitle();
+ method public int getType();
+ method public boolean isAccessibilityFocused();
+ method public boolean isActive();
+ method public boolean isFocused();
+ method public boolean isInPictureInPictureMode();
+ method public static androidx.core.view.accessibility.AccessibilityWindowInfoCompat? obtain();
+ method public static androidx.core.view.accessibility.AccessibilityWindowInfoCompat? obtain(androidx.core.view.accessibility.AccessibilityWindowInfoCompat?);
+ method @Deprecated public void recycle();
+ method public android.view.accessibility.AccessibilityWindowInfo? unwrap();
+ field public static final int TYPE_ACCESSIBILITY_OVERLAY = 4; // 0x4
+ field public static final int TYPE_APPLICATION = 1; // 0x1
+ field public static final int TYPE_INPUT_METHOD = 2; // 0x2
+ field public static final int TYPE_SPLIT_SCREEN_DIVIDER = 5; // 0x5
+ field public static final int TYPE_SYSTEM = 3; // 0x3
+ }
+
+}
+
+package androidx.core.view.animation {
+
+ public final class PathInterpolatorCompat {
+ method public static android.view.animation.Interpolator create(android.graphics.Path);
+ method public static android.view.animation.Interpolator create(float, float);
+ method public static android.view.animation.Interpolator create(float, float, float, float);
+ }
+
+}
+
+package androidx.core.view.inputmethod {
+
+ public final class EditorInfoCompat {
+ ctor @Deprecated public EditorInfoCompat();
+ method public static String![] getContentMimeTypes(android.view.inputmethod.EditorInfo);
+ method public static CharSequence? getInitialSelectedText(android.view.inputmethod.EditorInfo, int);
+ method public static CharSequence? getInitialTextAfterCursor(android.view.inputmethod.EditorInfo, int, int);
+ method public static CharSequence? getInitialTextBeforeCursor(android.view.inputmethod.EditorInfo, int, int);
+ method public static void setContentMimeTypes(android.view.inputmethod.EditorInfo, String![]?);
+ method public static void setInitialSurroundingSubText(android.view.inputmethod.EditorInfo, CharSequence, int);
+ method public static void setInitialSurroundingText(android.view.inputmethod.EditorInfo, CharSequence);
+ field public static final int IME_FLAG_FORCE_ASCII = -2147483648; // 0x80000000
+ field public static final int IME_FLAG_NO_PERSONALIZED_LEARNING = 16777216; // 0x1000000
+ }
+
+ public final class InputConnectionCompat {
+ ctor @Deprecated public InputConnectionCompat();
+ method public static boolean commitContent(android.view.inputmethod.InputConnection, android.view.inputmethod.EditorInfo, androidx.core.view.inputmethod.InputContentInfoCompat, int, android.os.Bundle?);
+ method @Deprecated public static android.view.inputmethod.InputConnection createWrapper(android.view.inputmethod.InputConnection, android.view.inputmethod.EditorInfo, androidx.core.view.inputmethod.InputConnectionCompat.OnCommitContentListener);
+ method public static android.view.inputmethod.InputConnection createWrapper(android.view.View, android.view.inputmethod.InputConnection, android.view.inputmethod.EditorInfo);
+ field public static final int INPUT_CONTENT_GRANT_READ_URI_PERMISSION = 1; // 0x1
+ }
+
+ public static interface InputConnectionCompat.OnCommitContentListener {
+ method public boolean onCommitContent(androidx.core.view.inputmethod.InputContentInfoCompat, int, android.os.Bundle?);
+ }
+
+ public final class InputContentInfoCompat {
+ ctor public InputContentInfoCompat(android.net.Uri, android.content.ClipDescription, android.net.Uri?);
+ method public android.net.Uri getContentUri();
+ method public android.content.ClipDescription getDescription();
+ method public android.net.Uri? getLinkUri();
+ method public void releasePermission();
+ method public void requestPermission();
+ method public Object? unwrap();
+ method public static androidx.core.view.inputmethod.InputContentInfoCompat? wrap(Object?);
+ }
+
+}
+
+package androidx.core.widget {
+
+ public abstract class AutoScrollHelper implements android.view.View.OnTouchListener {
+ ctor public AutoScrollHelper(android.view.View);
+ method public abstract boolean canTargetScrollHorizontally(int);
+ method public abstract boolean canTargetScrollVertically(int);
+ method public boolean isEnabled();
+ method public boolean isExclusive();
+ method public boolean onTouch(android.view.View!, android.view.MotionEvent!);
+ method public abstract void scrollTargetBy(int, int);
+ method public androidx.core.widget.AutoScrollHelper setActivationDelay(int);
+ method public androidx.core.widget.AutoScrollHelper setEdgeType(int);
+ method public androidx.core.widget.AutoScrollHelper! setEnabled(boolean);
+ method public androidx.core.widget.AutoScrollHelper! setExclusive(boolean);
+ method public androidx.core.widget.AutoScrollHelper setMaximumEdges(float, float);
+ method public androidx.core.widget.AutoScrollHelper setMaximumVelocity(float, float);
+ method public androidx.core.widget.AutoScrollHelper setMinimumVelocity(float, float);
+ method public androidx.core.widget.AutoScrollHelper setRampDownDuration(int);
+ method public androidx.core.widget.AutoScrollHelper setRampUpDuration(int);
+ method public androidx.core.widget.AutoScrollHelper setRelativeEdges(float, float);
+ method public androidx.core.widget.AutoScrollHelper setRelativeVelocity(float, float);
+ field public static final int EDGE_TYPE_INSIDE = 0; // 0x0
+ field public static final int EDGE_TYPE_INSIDE_EXTEND = 1; // 0x1
+ field public static final int EDGE_TYPE_OUTSIDE = 2; // 0x2
+ field public static final float NO_MAX = 3.4028235E38f;
+ field public static final float NO_MIN = 0.0f;
+ field public static final float RELATIVE_UNSPECIFIED = 0.0f;
+ }
+
+ @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) public interface AutoSizeableTextView {
+ method public int getAutoSizeMaxTextSize();
+ method public int getAutoSizeMinTextSize();
+ method public int getAutoSizeStepGranularity();
+ method public int[]! getAutoSizeTextAvailableSizes();
+ method @androidx.core.widget.TextViewCompat.AutoSizeTextType public int getAutoSizeTextType();
+ method public void setAutoSizeTextTypeUniformWithConfiguration(int, int, int, int) throws java.lang.IllegalArgumentException;
+ method public void setAutoSizeTextTypeUniformWithPresetSizes(int[], int) throws java.lang.IllegalArgumentException;
+ method public void setAutoSizeTextTypeWithDefaults(@androidx.core.widget.TextViewCompat.AutoSizeTextType int);
+ field @Deprecated @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) public static final boolean PLATFORM_SUPPORTS_AUTOSIZE;
+ }
+
+ public final class CheckedTextViewCompat {
+ method public static android.graphics.drawable.Drawable? getCheckMarkDrawable(android.widget.CheckedTextView);
+ method public static android.content.res.ColorStateList? getCheckMarkTintList(android.widget.CheckedTextView);
+ method public static android.graphics.PorterDuff.Mode? getCheckMarkTintMode(android.widget.CheckedTextView);
+ method public static void setCheckMarkTintList(android.widget.CheckedTextView, android.content.res.ColorStateList?);
+ method public static void setCheckMarkTintMode(android.widget.CheckedTextView, android.graphics.PorterDuff.Mode?);
+ }
+
+ public final class CompoundButtonCompat {
+ method public static android.graphics.drawable.Drawable? getButtonDrawable(android.widget.CompoundButton);
+ method public static android.content.res.ColorStateList? getButtonTintList(android.widget.CompoundButton);
+ method public static android.graphics.PorterDuff.Mode? getButtonTintMode(android.widget.CompoundButton);
+ method public static void setButtonTintList(android.widget.CompoundButton, android.content.res.ColorStateList?);
+ method public static void setButtonTintMode(android.widget.CompoundButton, android.graphics.PorterDuff.Mode?);
+ }
+
+ public class ContentLoadingProgressBar extends android.widget.ProgressBar {
+ ctor public ContentLoadingProgressBar(android.content.Context);
+ ctor public ContentLoadingProgressBar(android.content.Context, android.util.AttributeSet?);
+ method public void hide();
+ method public void onAttachedToWindow();
+ method public void onDetachedFromWindow();
+ method public void show();
+ }
+
+ public final class EdgeEffectCompat {
+ ctor @Deprecated public EdgeEffectCompat(android.content.Context!);
+ method public static android.widget.EdgeEffect create(android.content.Context, android.util.AttributeSet?);
+ method @Deprecated public boolean draw(android.graphics.Canvas!);
+ method @Deprecated public void finish();
+ method public static float getDistance(android.widget.EdgeEffect);
+ method @Deprecated public boolean isFinished();
+ method @Deprecated public boolean onAbsorb(int);
+ method @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);
+ }
+
+ public class ImageViewCompat {
+ method public static android.content.res.ColorStateList? getImageTintList(android.widget.ImageView);
+ method public static android.graphics.PorterDuff.Mode? getImageTintMode(android.widget.ImageView);
+ method public static void setImageTintList(android.widget.ImageView, android.content.res.ColorStateList?);
+ method public static void setImageTintMode(android.widget.ImageView, android.graphics.PorterDuff.Mode?);
+ }
+
+ public final class ListPopupWindowCompat {
+ method @Deprecated public static android.view.View.OnTouchListener! createDragToOpenListener(Object!, android.view.View!);
+ method public static android.view.View.OnTouchListener? createDragToOpenListener(android.widget.ListPopupWindow, android.view.View);
+ }
+
+ public class ListViewAutoScrollHelper extends androidx.core.widget.AutoScrollHelper {
+ ctor public ListViewAutoScrollHelper(android.widget.ListView);
+ method public boolean canTargetScrollHorizontally(int);
+ method public boolean canTargetScrollVertically(int);
+ method public void scrollTargetBy(int, int);
+ }
+
+ public final class ListViewCompat {
+ method public static boolean canScrollList(android.widget.ListView, int);
+ method public static void scrollListBy(android.widget.ListView, int);
+ }
+
+ public class NestedScrollView extends android.widget.FrameLayout implements androidx.core.view.NestedScrollingChild3 androidx.core.view.NestedScrollingParent3 androidx.core.view.ScrollingView {
+ ctor public NestedScrollView(android.content.Context);
+ ctor public NestedScrollView(android.content.Context, android.util.AttributeSet?);
+ ctor public NestedScrollView(android.content.Context, android.util.AttributeSet?, int);
+ method public boolean arrowScroll(int);
+ method @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) public int computeHorizontalScrollExtent();
+ method @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) public int computeHorizontalScrollOffset();
+ method @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) public int computeHorizontalScrollRange();
+ method protected int computeScrollDeltaToGetChildRectOnScreen(android.graphics.Rect!);
+ method @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) public int computeVerticalScrollExtent();
+ method @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) public int computeVerticalScrollOffset();
+ method @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) public int computeVerticalScrollRange();
+ method public boolean dispatchNestedPreScroll(int, int, int[]?, int[]?, int);
+ method public void dispatchNestedScroll(int, int, int, int, int[]?, int, int[]);
+ method public boolean dispatchNestedScroll(int, int, int, int, int[]?, int);
+ method public boolean executeKeyEvent(android.view.KeyEvent);
+ method public void fling(int);
+ method public boolean fullScroll(int);
+ method public int getMaxScrollAmount();
+ method public boolean hasNestedScrollingParent(int);
+ method public boolean isFillViewport();
+ method public boolean isSmoothScrollingEnabled();
+ method public void onAttachedToWindow();
+ method public void onNestedPreScroll(android.view.View, int, int, int[], int);
+ method public void onNestedScroll(android.view.View, int, int, int, int, int, int[]);
+ method public void onNestedScroll(android.view.View, int, int, int, int, int);
+ method public void onNestedScrollAccepted(android.view.View, android.view.View, int, int);
+ method public boolean onStartNestedScroll(android.view.View, android.view.View, int, int);
+ method public void onStopNestedScroll(android.view.View, int);
+ method public boolean pageScroll(int);
+ method public void setFillViewport(boolean);
+ method public void setOnScrollChangeListener(androidx.core.widget.NestedScrollView.OnScrollChangeListener?);
+ method public void setSmoothScrollingEnabled(boolean);
+ method public final void smoothScrollBy(int, int);
+ method public final void smoothScrollBy(int, int, int);
+ method public final void smoothScrollTo(int, int);
+ method public final void smoothScrollTo(int, int, int);
+ method public boolean startNestedScroll(int, int);
+ method public void stopNestedScroll(int);
+ }
+
+ public static interface NestedScrollView.OnScrollChangeListener {
+ method public void onScrollChange(androidx.core.widget.NestedScrollView, int, int, int, int);
+ }
+
+ public final class PopupMenuCompat {
+ method public static android.view.View.OnTouchListener? getDragToOpenListener(Object);
+ }
+
+ public final class PopupWindowCompat {
+ method public static boolean getOverlapAnchor(android.widget.PopupWindow);
+ method public static int getWindowLayoutType(android.widget.PopupWindow);
+ method public static void setOverlapAnchor(android.widget.PopupWindow, boolean);
+ method public static void setWindowLayoutType(android.widget.PopupWindow, int);
+ method public static void showAsDropDown(android.widget.PopupWindow, android.view.View, int, int, int);
+ }
+
+ @Deprecated public final class ScrollerCompat {
+ method @Deprecated public void abortAnimation();
+ method @Deprecated public boolean computeScrollOffset();
+ method @Deprecated public static androidx.core.widget.ScrollerCompat! create(android.content.Context!);
+ method @Deprecated public static androidx.core.widget.ScrollerCompat! create(android.content.Context!, android.view.animation.Interpolator!);
+ method @Deprecated public void fling(int, int, int, int, int, int, int, int);
+ method @Deprecated public void fling(int, int, int, int, int, int, int, int, int, int);
+ method @Deprecated public float getCurrVelocity();
+ method @Deprecated public int getCurrX();
+ method @Deprecated public int getCurrY();
+ method @Deprecated public int getFinalX();
+ method @Deprecated public int getFinalY();
+ method @Deprecated public boolean isFinished();
+ method @Deprecated public boolean isOverScrolled();
+ method @Deprecated public void notifyHorizontalEdgeReached(int, int, int);
+ method @Deprecated public void notifyVerticalEdgeReached(int, int, int);
+ method @Deprecated public boolean springBack(int, int, int, int, int, int);
+ method @Deprecated public void startScroll(int, int, int, int);
+ method @Deprecated public void startScroll(int, int, int, int, int);
+ }
+
+ public final class TextViewCompat {
+ method public static int getAutoSizeMaxTextSize(android.widget.TextView);
+ method public static int getAutoSizeMinTextSize(android.widget.TextView);
+ method public static int getAutoSizeStepGranularity(android.widget.TextView);
+ method public static int[] getAutoSizeTextAvailableSizes(android.widget.TextView);
+ method public static int getAutoSizeTextType(android.widget.TextView);
+ method public static android.content.res.ColorStateList? getCompoundDrawableTintList(android.widget.TextView);
+ method public static android.graphics.PorterDuff.Mode? getCompoundDrawableTintMode(android.widget.TextView);
+ method public static android.graphics.drawable.Drawable![] getCompoundDrawablesRelative(android.widget.TextView);
+ method public static int getFirstBaselineToTopHeight(android.widget.TextView);
+ method public static int getLastBaselineToBottomHeight(android.widget.TextView);
+ method public static int getMaxLines(android.widget.TextView);
+ method public static int getMinLines(android.widget.TextView);
+ method public static androidx.core.text.PrecomputedTextCompat.Params getTextMetricsParams(android.widget.TextView);
+ method public static void setAutoSizeTextTypeUniformWithConfiguration(android.widget.TextView, int, int, int, int) throws java.lang.IllegalArgumentException;
+ method public static void setAutoSizeTextTypeUniformWithPresetSizes(android.widget.TextView, int[], int) throws java.lang.IllegalArgumentException;
+ method public static void setAutoSizeTextTypeWithDefaults(android.widget.TextView, int);
+ method public static void setCompoundDrawableTintList(android.widget.TextView, android.content.res.ColorStateList?);
+ method public static void setCompoundDrawableTintMode(android.widget.TextView, android.graphics.PorterDuff.Mode?);
+ method public static void setCompoundDrawablesRelative(android.widget.TextView, android.graphics.drawable.Drawable?, android.graphics.drawable.Drawable?, android.graphics.drawable.Drawable?, android.graphics.drawable.Drawable?);
+ method public static void setCompoundDrawablesRelativeWithIntrinsicBounds(android.widget.TextView, android.graphics.drawable.Drawable?, android.graphics.drawable.Drawable?, android.graphics.drawable.Drawable?, android.graphics.drawable.Drawable?);
+ method public static void setCompoundDrawablesRelativeWithIntrinsicBounds(android.widget.TextView, @DrawableRes int, @DrawableRes int, @DrawableRes int, @DrawableRes int);
+ method public static void setCustomSelectionActionModeCallback(android.widget.TextView, android.view.ActionMode.Callback);
+ method public static void setFirstBaselineToTopHeight(android.widget.TextView, @IntRange(from=0) @Px int);
+ method public static void setLastBaselineToBottomHeight(android.widget.TextView, @IntRange(from=0) @Px int);
+ method public static void setLineHeight(android.widget.TextView, @IntRange(from=0) @Px int);
+ method public static void setPrecomputedText(android.widget.TextView, androidx.core.text.PrecomputedTextCompat);
+ method public static void setTextAppearance(android.widget.TextView, @StyleRes int);
+ method public static void setTextMetricsParams(android.widget.TextView, androidx.core.text.PrecomputedTextCompat.Params);
+ method @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) public static android.view.ActionMode.Callback? unwrapCustomSelectionActionModeCallback(android.view.ActionMode.Callback?);
+ method @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) public static android.view.ActionMode.Callback? wrapCustomSelectionActionModeCallback(android.widget.TextView, android.view.ActionMode.Callback?);
+ field public static final int AUTO_SIZE_TEXT_TYPE_NONE = 0; // 0x0
+ field public static final int AUTO_SIZE_TEXT_TYPE_UNIFORM = 1; // 0x1
+ }
+
+ @IntDef({androidx.core.widget.TextViewCompat.AUTO_SIZE_TEXT_TYPE_NONE, androidx.core.widget.TextViewCompat.AUTO_SIZE_TEXT_TYPE_UNIFORM}) @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.SOURCE) public static @interface TextViewCompat.AutoSizeTextType {
+ }
+
+ @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) public final class TextViewOnReceiveContentListener implements androidx.core.view.OnReceiveContentListener {
+ ctor public TextViewOnReceiveContentListener();
+ method public androidx.core.view.ContentInfoCompat? onReceiveContent(android.view.View, androidx.core.view.ContentInfoCompat);
+ }
+
+ @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) public interface TintableCheckedTextView {
+ method public android.content.res.ColorStateList? getSupportCheckMarkTintList();
+ method public android.graphics.PorterDuff.Mode? getSupportCheckMarkTintMode();
+ method public void setSupportCheckMarkTintList(android.content.res.ColorStateList?);
+ method public void setSupportCheckMarkTintMode(android.graphics.PorterDuff.Mode?);
+ }
+
+ public interface TintableCompoundButton {
+ method public android.content.res.ColorStateList? getSupportButtonTintList();
+ method public android.graphics.PorterDuff.Mode? getSupportButtonTintMode();
+ method public void setSupportButtonTintList(android.content.res.ColorStateList?);
+ method public void setSupportButtonTintMode(android.graphics.PorterDuff.Mode?);
+ }
+
+ public interface TintableCompoundDrawablesView {
+ method public android.content.res.ColorStateList? getSupportCompoundDrawablesTintList();
+ method public android.graphics.PorterDuff.Mode? getSupportCompoundDrawablesTintMode();
+ method public void setSupportCompoundDrawablesTintList(android.content.res.ColorStateList?);
+ method public void setSupportCompoundDrawablesTintMode(android.graphics.PorterDuff.Mode?);
+ }
+
+ @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) public interface TintableImageSourceView {
+ method public android.content.res.ColorStateList? getSupportImageTintList();
+ method public android.graphics.PorterDuff.Mode? getSupportImageTintMode();
+ method public void setSupportImageTintList(android.content.res.ColorStateList?);
+ method public void setSupportImageTintMode(android.graphics.PorterDuff.Mode?);
+ }
+
+}
+
diff --git a/core/core/api/restricted_current.txt b/core/core/api/restricted_current.txt
index 9556806..0f48602 100644
--- a/core/core/api/restricted_current.txt
+++ b/core/core/api/restricted_current.txt
@@ -2374,6 +2374,26 @@
}
+package androidx.core.service.quicksettings {
+
+ public class PendingIntentActivityWrapper {
+ ctor public PendingIntentActivityWrapper(android.content.Context, int, android.content.Intent, int, boolean);
+ ctor public PendingIntentActivityWrapper(android.content.Context, int, android.content.Intent, int, android.os.Bundle?, boolean);
+ method public android.content.Context getContext();
+ method public int getFlags();
+ method public android.content.Intent getIntent();
+ method public android.os.Bundle getOptions();
+ method public android.app.PendingIntent? getPendingIntent();
+ method public int getRequestCode();
+ method public boolean isMutable();
+ }
+
+ public class TileServiceCompat {
+ method public static void startActivityAndCollapse(android.service.quicksettings.TileService, androidx.core.service.quicksettings.PendingIntentActivityWrapper);
+ }
+
+}
+
package androidx.core.telephony {
@RequiresApi(22) public class SubscriptionManagerCompat {
@@ -2519,6 +2539,66 @@
@IntDef(flag=true, value={android.text.util.Linkify.WEB_URLS, android.text.util.Linkify.EMAIL_ADDRESSES, android.text.util.Linkify.PHONE_NUMBERS, android.text.util.Linkify.MAP_ADDRESSES, android.text.util.Linkify.ALL}) @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.SOURCE) public static @interface LinkifyCompat.LinkifyMask {
}
+ public final class LocalePreferences {
+ method @RequiresApi(android.os.Build.VERSION_CODES.TIRAMISU) public static String getCalendarType();
+ method @RequiresApi(android.os.Build.VERSION_CODES.TIRAMISU) public static String getCalendarType(java.util.Locale);
+ method @RequiresApi(android.os.Build.VERSION_CODES.TIRAMISU) public static String getCalendarType(boolean);
+ method @RequiresApi(android.os.Build.VERSION_CODES.TIRAMISU) public static String getCalendarType(java.util.Locale, boolean);
+ method @RequiresApi(android.os.Build.VERSION_CODES.TIRAMISU) public static String getFirstDayOfWeek();
+ method @RequiresApi(android.os.Build.VERSION_CODES.TIRAMISU) public static String getFirstDayOfWeek(java.util.Locale);
+ method @RequiresApi(android.os.Build.VERSION_CODES.TIRAMISU) public static String getFirstDayOfWeek(boolean);
+ method @RequiresApi(android.os.Build.VERSION_CODES.TIRAMISU) public static String getFirstDayOfWeek(java.util.Locale, boolean);
+ method @RequiresApi(android.os.Build.VERSION_CODES.TIRAMISU) public static String getHourCycle();
+ method @RequiresApi(android.os.Build.VERSION_CODES.TIRAMISU) public static String getHourCycle(java.util.Locale);
+ method @RequiresApi(android.os.Build.VERSION_CODES.TIRAMISU) public static String getHourCycle(boolean);
+ method @RequiresApi(android.os.Build.VERSION_CODES.TIRAMISU) public static String getHourCycle(java.util.Locale, boolean);
+ method @RequiresApi(android.os.Build.VERSION_CODES.TIRAMISU) public static String getTemperatureUnit();
+ method @RequiresApi(android.os.Build.VERSION_CODES.TIRAMISU) public static String getTemperatureUnit(java.util.Locale);
+ method @RequiresApi(android.os.Build.VERSION_CODES.TIRAMISU) public static String getTemperatureUnit(boolean);
+ method @RequiresApi(android.os.Build.VERSION_CODES.TIRAMISU) public static String getTemperatureUnit(java.util.Locale, boolean);
+ }
+
+ public static class LocalePreferences.CalendarType {
+ field public static final String CHINESE = "chinese";
+ field public static final String DANGI = "dangi";
+ field public static final String DEFAULT = "";
+ field public static final String GREGORIAN = "gregorian";
+ field public static final String HEBREW = "hebrew";
+ field public static final String INDIAN = "indian";
+ field public static final String ISLAMIC = "islamic";
+ field public static final String ISLAMIC_CIVIL = "islamic-civil";
+ field public static final String ISLAMIC_RGSA = "islamic-rgsa";
+ field public static final String ISLAMIC_TBLA = "islamic-tbla";
+ field public static final String ISLAMIC_UMALQURA = "islamic-umalqura";
+ field public static final String PERSIAN = "persian";
+ }
+
+ public static class LocalePreferences.FirstDayOfWeek {
+ field public static final String DEFAULT = "";
+ field public static final String FRIDAY = "fri";
+ field public static final String MONDAY = "mon";
+ field public static final String SATURDAY = "sat";
+ field public static final String SUNDAY = "sun";
+ field public static final String THURSDAY = "thu";
+ field public static final String TUESDAY = "tue";
+ field public static final String WEDNESDAY = "wed";
+ }
+
+ public static class LocalePreferences.HourCycle {
+ field public static final String DEFAULT = "";
+ field public static final String H11 = "h11";
+ field public static final String H12 = "h12";
+ field public static final String H23 = "h23";
+ field public static final String H24 = "h24";
+ }
+
+ public static class LocalePreferences.TemperatureUnit {
+ field public static final String CELSIUS = "celsius";
+ field public static final String DEFAULT = "";
+ field public static final String FAHRENHEIT = "fahrenheit";
+ field public static final String KELVIN = "kelvin";
+ }
+
}
package androidx.core.util {
@@ -2642,6 +2722,14 @@
field @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) public static final int HUNDRED_DAY_FIELD_LEN = 19; // 0x13
}
+ public class TypedValueCompat {
+ method public static float deriveDimension(int, float, android.util.DisplayMetrics);
+ method public static float dpToPx(float, android.util.DisplayMetrics);
+ method public static float pxToDp(float, android.util.DisplayMetrics);
+ method public static float pxToSp(float, android.util.DisplayMetrics);
+ method public static float spToPx(float, android.util.DisplayMetrics);
+ }
+
}
package androidx.core.view {
@@ -3124,9 +3212,15 @@
method public void setSupportBackgroundTintMode(android.graphics.PorterDuff.Mode?);
}
- @Deprecated public final class VelocityTrackerCompat {
+ public final class VelocityTrackerCompat {
+ method public static float getAxisVelocity(android.view.VelocityTracker, @androidx.core.view.VelocityTrackerCompat.VelocityTrackableMotionEventAxis int);
+ method public static float getAxisVelocity(android.view.VelocityTracker, @androidx.core.view.VelocityTrackerCompat.VelocityTrackableMotionEventAxis int, int);
method @Deprecated public static float getXVelocity(android.view.VelocityTracker!, int);
method @Deprecated public static float getYVelocity(android.view.VelocityTracker!, int);
+ method public static boolean isAxisSupported(android.view.VelocityTracker, @androidx.core.view.VelocityTrackerCompat.VelocityTrackableMotionEventAxis int);
+ }
+
+ @IntDef({android.view.MotionEvent.AXIS_X, android.view.MotionEvent.AXIS_Y, android.view.MotionEvent.AXIS_SCROLL}) @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.SOURCE) public static @interface VelocityTrackerCompat.VelocityTrackableMotionEventAxis {
}
public class ViewCompat {
@@ -4100,6 +4194,7 @@
}
public class AccessibilityWindowInfoCompat {
+ ctor public AccessibilityWindowInfoCompat();
method public androidx.core.view.accessibility.AccessibilityNodeInfoCompat? getAnchor();
method public void getBoundsInScreen(android.graphics.Rect);
method public androidx.core.view.accessibility.AccessibilityWindowInfoCompat? getChild(int);
diff --git a/core/core/lint-baseline.xml b/core/core/lint-baseline.xml
index 2949272..ca1c7c0 100644
--- a/core/core/lint-baseline.xml
+++ b/core/core/lint-baseline.xml
@@ -713,6 +713,15 @@
</issue>
<issue
+ id="Range"
+ message="Value must be ≥ 1 and ≤ 200 but `getSvid` can be 206"
+ errorLine1=" return mWrapped.getSvid(satelliteIndex);"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="src/main/java/androidx/core/location/GnssStatusWrapper.java"/>
+ </issue>
+
+ <issue
id="WrongConstant"
message="Must be one of: Callback.DISPATCH_MODE_STOP, Callback.DISPATCH_MODE_CONTINUE_ON_SUBTREE"
errorLine1=" super(compat.getDispatchMode());"
diff --git a/core/core/src/androidTest/java/androidx/core/content/ContextCompatTest.java b/core/core/src/androidTest/java/androidx/core/content/ContextCompatTest.java
index 85db291..9629356 100644
--- a/core/core/src/androidTest/java/androidx/core/content/ContextCompatTest.java
+++ b/core/core/src/androidTest/java/androidx/core/content/ContextCompatTest.java
@@ -86,6 +86,7 @@
import android.app.KeyguardManager;
import android.app.NotificationManager;
import android.app.SearchManager;
+import android.app.UiAutomation;
import android.app.UiModeManager;
import android.app.WallpaperManager;
import android.app.admin.DevicePolicyManager;
@@ -517,11 +518,15 @@
@Test
@SdkSuppress(minSdkVersion = 29, maxSdkVersion = 32)
public void testRegisterReceiverPermissionNotGrantedApi26() {
- InstrumentationRegistry
- .getInstrumentation().getUiAutomation().adoptShellPermissionIdentity();
- assertThrows(RuntimeException.class,
- () -> ContextCompat.registerReceiver(mContext,
- mTestReceiver, mTestFilter, ContextCompat.RECEIVER_NOT_EXPORTED));
+ UiAutomation uiAutomation = InstrumentationRegistry.getInstrumentation().getUiAutomation();
+ uiAutomation.adoptShellPermissionIdentity();
+ try {
+ assertThrows(RuntimeException.class,
+ () -> ContextCompat.registerReceiver(mContext,
+ mTestReceiver, mTestFilter, ContextCompat.RECEIVER_NOT_EXPORTED));
+ } finally {
+ uiAutomation.dropShellPermissionIdentity();
+ }
}
@Test
diff --git a/core/core/src/androidTest/java/androidx/core/service/quicksettings/TileServiceCompatTest.java b/core/core/src/androidTest/java/androidx/core/service/quicksettings/TileServiceCompatTest.java
new file mode 100644
index 0000000..a78f703
--- /dev/null
+++ b/core/core/src/androidTest/java/androidx/core/service/quicksettings/TileServiceCompatTest.java
@@ -0,0 +1,88 @@
+/*
+ * Copyright 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.core.service.quicksettings;
+
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.verify;
+
+import android.app.PendingIntent;
+import android.content.Context;
+import android.content.Intent;
+import android.os.Bundle;
+import android.service.quicksettings.TileService;
+
+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.After;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+/**
+ * Unit test for {@link TileServiceCompat}.
+ */
+@RunWith(AndroidJUnit4.class)
+@SmallTest
+public class TileServiceCompatTest {
+
+ private final Context mContext = ApplicationProvider.getApplicationContext();
+
+ @After
+ public void tearDown() {
+ TileServiceCompat.clearTileServiceWrapper();
+ }
+
+ @SdkSuppress(minSdkVersion = 34)
+ @Test
+ public void startActivityAndCollapse_usesPendingIntent() {
+ TileServiceCompat.TileServiceWrapper tileServiceWrapper =
+ mock(TileServiceCompat.TileServiceWrapper.class);
+ TileService tileService = mock(TileService.class);
+ int requestCode = 7465;
+ Intent intent = new Intent();
+ Bundle options = new Bundle();
+ PendingIntentActivityWrapper wrapper = new PendingIntentActivityWrapper(mContext,
+ requestCode, intent, PendingIntent.FLAG_UPDATE_CURRENT, options, /* isMutable = */
+ true);
+ TileServiceCompat.setTileServiceWrapper(tileServiceWrapper);
+
+ TileServiceCompat.startActivityAndCollapse(tileService, wrapper);
+
+ verify(tileServiceWrapper).startActivityAndCollapse(wrapper.getPendingIntent());
+ }
+
+ @SdkSuppress(minSdkVersion = 24, maxSdkVersion = 33)
+ @Test
+ public void startActivityAndCollapse_usesIntent() {
+ TileServiceCompat.TileServiceWrapper tileServiceWrapper =
+ mock(TileServiceCompat.TileServiceWrapper.class);
+ TileService tileService = mock(TileService.class);
+ int requestCode = 7465;
+ Intent intent = new Intent();
+ Bundle options = new Bundle();
+ PendingIntentActivityWrapper wrapper = new PendingIntentActivityWrapper(mContext,
+ requestCode, intent, PendingIntent.FLAG_UPDATE_CURRENT, options, /* isMutable = */
+ true);
+ TileServiceCompat.setTileServiceWrapper(tileServiceWrapper);
+
+ TileServiceCompat.startActivityAndCollapse(tileService, wrapper);
+
+ verify(tileServiceWrapper).startActivityAndCollapse(intent);
+ }
+}
diff --git a/core/core/src/androidTest/java/androidx/core/text/util/LocalePreferencesTest.java b/core/core/src/androidTest/java/androidx/core/text/util/LocalePreferencesTest.java
new file mode 100644
index 0000000..c59ae1f
--- /dev/null
+++ b/core/core/src/androidTest/java/androidx/core/text/util/LocalePreferencesTest.java
@@ -0,0 +1,337 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.core.text.util;
+
+import static org.junit.Assert.assertEquals;
+
+import android.os.Build.VERSION_CODES;
+
+import androidx.test.ext.junit.runners.AndroidJUnit4;
+import androidx.test.filters.SdkSuppress;
+import androidx.test.filters.SmallTest;
+
+import org.junit.After;
+import org.junit.BeforeClass;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.util.Locale;
+
+@SmallTest
+@SdkSuppress(minSdkVersion = VERSION_CODES.TIRAMISU)
+@RunWith(AndroidJUnit4.class)
+public class LocalePreferencesTest {
+ private static Locale sLocale;
+
+ @BeforeClass
+ public static void setUpClass() throws Exception {
+ sLocale = Locale.getDefault(Locale.Category.FORMAT);
+ }
+
+ @After
+ public void tearDown() {
+ Locale.setDefault(sLocale);
+ }
+
+ // Hour cycle
+ @Test
+ public void getHourCycle_hasSubTags_resultIsH24() throws Exception {
+ Locale.setDefault(Locale.forLanguageTag("en-US-u-ca-chinese-hc-h24-mu-celsius-fw-wed"));
+
+ String result = LocalePreferences.getHourCycle();
+
+ assertEquals(LocalePreferences.HourCycle.H24, result);
+ }
+
+ @Test
+ public void getHourCycle_hasSubTagsWithoutHourCycleTag_resultIsH12() throws Exception {
+ Locale.setDefault(Locale.forLanguageTag("en-US-u-ca-chinese-mu-celsius-fw-wed"));
+
+ String result = LocalePreferences.getHourCycle();
+
+ assertEquals(LocalePreferences.HourCycle.H12, result);
+ }
+
+ @Test
+ public void getHourCycle_hasSubTagsAndDisableResolved_resultIsH24() throws Exception {
+ Locale.setDefault(Locale.forLanguageTag("en-US-u-ca-chinese-hc-h24-mu-celsius-fw-wed"));
+
+ String result = LocalePreferences.getHourCycle(false);
+
+ assertEquals(LocalePreferences.HourCycle.H24, result);
+ }
+
+ @Test
+ public void getHourCycle_hasSubTagsWithoutHourCycleTagAndDisableResolved_resultIsEmpty()
+ throws Exception {
+ Locale.setDefault(Locale.forLanguageTag("en-US-u-ca-chinese-mu-celsius-fw-wed"));
+
+ String result = LocalePreferences.getHourCycle(false);
+
+ assertEquals(LocalePreferences.HourCycle.DEFAULT, result);
+ }
+
+ @Test
+ public void getHourCycle_inputLocaleWithHourCycleTag_resultIsH12() throws Exception {
+ String result = LocalePreferences.getHourCycle(Locale.forLanguageTag("en-US-u-hc-h12"));
+
+ assertEquals(LocalePreferences.HourCycle.H12, result);
+ }
+
+ @Test
+ public void getHourCycle_inputLocaleWithoutHourCycleTag_resultIsH12() throws Exception {
+ String result = LocalePreferences.getHourCycle(Locale.forLanguageTag("en-US"));
+
+ assertEquals(LocalePreferences.HourCycle.H12, result);
+ }
+
+ @Test
+ public void getHourCycle_inputH23Locale_resultIsH23() throws Exception {
+ String result = LocalePreferences.getHourCycle(Locale.forLanguageTag("fr-FR"));
+
+ assertEquals(LocalePreferences.HourCycle.H23, result);
+ }
+
+ @Test
+ public void getHourCycle_inputH23LocaleWithHourCycleTag_resultIsH12() throws Exception {
+ String result = LocalePreferences.getHourCycle(Locale.forLanguageTag("fr-FR-u-hc-h12"));
+
+ assertEquals(LocalePreferences.HourCycle.H12, result);
+ }
+
+ @Test
+ public void getHourCycle_inputLocaleWithoutHourCycleTagAndDisableResolved_resultIsEmpty()
+ throws Exception {
+ String result = LocalePreferences.getHourCycle(Locale.forLanguageTag("en-US"), false);
+
+ assertEquals(LocalePreferences.HourCycle.DEFAULT, result);
+ }
+
+ @Test
+ public void getHourCycle_compareHasResolvedValueIsTrueAndWithoutResolvedValue_sameResult()
+ throws Exception {
+ Locale.setDefault(Locale.forLanguageTag("zh-TW-u-ca-chinese-hc-h24-mu-celsius-fw-wed"));
+
+ // Has Hour Cycle subtag
+ String resultWithoutResolvedValue = LocalePreferences.getHourCycle();
+ String resultResolvedIsTrue = LocalePreferences.getHourCycle(true);
+ assertEquals(resultWithoutResolvedValue, resultResolvedIsTrue);
+
+ // Does not have HourCycle subtag
+ Locale.setDefault(Locale.forLanguageTag("zh-TW-u-ca-chinese-mu-celsius-fw-wed"));
+
+ resultWithoutResolvedValue = LocalePreferences.getHourCycle();
+ resultResolvedIsTrue = LocalePreferences.getHourCycle(true);
+ assertEquals(resultWithoutResolvedValue, resultResolvedIsTrue);
+ }
+
+ // Calendar
+ @Test
+ public void getCalendarType_hasSubTags_resultIsChinese() throws Exception {
+ Locale.setDefault(Locale.forLanguageTag("en-US-u-ca-chinese-hc-h24-mu-celsius-fw-wed"));
+
+ String result = LocalePreferences.getCalendarType();
+
+ assertEquals(LocalePreferences.CalendarType.CHINESE, result);
+ }
+
+ @Test
+ public void getCalendarType_hasSubTagsWithoutCalendarTag_resultIsGregorian() throws Exception {
+ Locale.setDefault(Locale.forLanguageTag("en-US-u-hc-h24-mu-celsius-fw-wed"));
+
+ String result = LocalePreferences.getCalendarType();
+
+ assertEquals(LocalePreferences.CalendarType.GREGORIAN, result);
+ }
+
+ @Test
+ public void getCalendarType_hasSubTagsAndDisableResolved_resultIsChinese() throws Exception {
+ Locale.setDefault(Locale.forLanguageTag("en-US-u-ca-chinese-hc-h24-mu-celsius-fw-wed"));
+
+ String result = LocalePreferences.getCalendarType(false);
+
+ assertEquals(LocalePreferences.CalendarType.CHINESE, result);
+ }
+
+ @Test
+ public void getCalendarType_hasSubTagsWithoutCalendarTagAndDisableResolved_resultIsEmpty()
+ throws Exception {
+ Locale.setDefault(Locale.forLanguageTag("en-US-u-mu-celsius-fw-wed"));
+
+ String result = LocalePreferences.getCalendarType(false);
+
+ assertEquals(LocalePreferences.CalendarType.DEFAULT, result);
+ }
+
+ @Test
+ public void getCalendarType_inputLocaleWithCalendarTag_resultIsChinese() throws Exception {
+ String result =
+ LocalePreferences.getCalendarType(Locale.forLanguageTag("en-US-u-ca-chinese"));
+
+ assertEquals(LocalePreferences.CalendarType.CHINESE, result);
+ }
+
+ @Test
+ public void getCalendarType_inputLocaleWithoutCalendarTag_resultIsGregorian() throws Exception {
+ String result = LocalePreferences.getCalendarType(Locale.forLanguageTag("en-US"));
+
+ assertEquals(LocalePreferences.CalendarType.GREGORIAN, result);
+ }
+
+ @Test
+ public void getCalendarType_inputLocaleWithoutCalendarTagAndDisableResolved_resultIsEmpty()
+ throws Exception {
+ String result = LocalePreferences.getCalendarType(Locale.forLanguageTag("en-US"), false);
+
+ assertEquals(LocalePreferences.CalendarType.DEFAULT, result);
+ }
+
+ // Temperature unit
+ @Test
+ public void getTemperatureUnit_hasSubTags_resultIsCelsius() throws Exception {
+ Locale.setDefault(Locale.forLanguageTag("en-US-u-ca-chinese-hc-h24-mu-celsius-fw-wed"));
+
+ String result = LocalePreferences.getTemperatureUnit();
+
+ assertEquals(LocalePreferences.TemperatureUnit.CELSIUS, result);
+ }
+
+ @Test
+ public void getTemperatureUnit_hasSubTagsWithoutUnitTag_resultIsFahrenheit() throws Exception {
+ Locale.setDefault(Locale.forLanguageTag("en-US-u-hc-h24-fw-wed"));
+
+ String result = LocalePreferences.getTemperatureUnit();
+
+ assertEquals(LocalePreferences.TemperatureUnit.FAHRENHEIT, result);
+ }
+
+ @Test
+ public void getTemperatureUnit_hasSubTagsAndDisableResolved_resultIsCelsius() throws Exception {
+ Locale.setDefault(Locale.forLanguageTag("en-US-u-ca-chinese-hc-h24-mu-celsius-fw-wed"));
+
+ String result = LocalePreferences.getTemperatureUnit(false);
+
+ assertEquals(LocalePreferences.TemperatureUnit.CELSIUS, result);
+ }
+
+ @Test
+ public void getTemperatureUnit_hasSubTagsAndDisableResolved_resultIsFahrenheit()
+ throws Exception {
+ Locale.setDefault(Locale.forLanguageTag("zh-TW-u-ca-chinese-hc-h24-mu-fahrenhe-fw-wed"));
+
+ String result = LocalePreferences.getTemperatureUnit(false);
+
+ assertEquals(LocalePreferences.TemperatureUnit.FAHRENHEIT, result);
+ }
+
+ @Test
+ public void getTemperatureUnit_hasSubTagsWithoutUnitTagAndDisableResolved_resultIsEmpty()
+ throws Exception {
+ Locale.setDefault(Locale.forLanguageTag("en-US-u-fw-wed"));
+
+ String result = LocalePreferences.getTemperatureUnit(false);
+
+ assertEquals(LocalePreferences.TemperatureUnit.DEFAULT, result);
+ }
+
+ @Test
+ public void getTemperatureUnit_inputLocaleWithUnitTag_resultIsCelsius() throws Exception {
+ String result = LocalePreferences
+ .getTemperatureUnit(Locale.forLanguageTag("en-US-u-mu-celsius"));
+
+ assertEquals(LocalePreferences.TemperatureUnit.CELSIUS, result);
+ }
+
+ @Test
+ public void getTemperatureUnit_inputLocaleWithoutUnitTag_resultIsFahrenheit() throws Exception {
+ String result = LocalePreferences.getTemperatureUnit(Locale.forLanguageTag("en-US"));
+
+ assertEquals(LocalePreferences.TemperatureUnit.FAHRENHEIT, result);
+ }
+
+ @Test
+ public void getTemperatureUnit_inputLocaleWithoutUnitTagAndDisableResolved_resultIsEmpty()
+ throws Exception {
+ String result = LocalePreferences
+ .getTemperatureUnit(Locale.forLanguageTag("en-US"), false);
+
+ assertEquals(LocalePreferences.TemperatureUnit.DEFAULT, result);
+ }
+
+ // First day of week
+ @Test
+ public void getFirstDayOfWeek_hasSubTags_resultIsCelsius() throws Exception {
+ Locale.setDefault(Locale.forLanguageTag("en-US-u-ca-chinese-hc-h24-mu-celsius-fw-wed"));
+
+ String result = LocalePreferences.getFirstDayOfWeek();
+
+ assertEquals(LocalePreferences.FirstDayOfWeek.WEDNESDAY, result);
+ }
+
+ @Test
+ public void getFirstDayOfWeek_hasSubTagsWithoutFwTag_resultIsSun() throws Exception {
+ Locale.setDefault(Locale.forLanguageTag("en-US-u-hc-h24"));
+
+ String result = LocalePreferences.getFirstDayOfWeek();
+
+ assertEquals(LocalePreferences.FirstDayOfWeek.SUNDAY, result);
+
+ }
+
+ @Test
+ public void getFirstDayOfWeek_hasSubTagsAndDisableResolved_resultIsWed() throws Exception {
+ Locale.setDefault(Locale.forLanguageTag("en-US-u-ca-chinese-hc-h24-mu-celsius-fw-wed"));
+
+ String result = LocalePreferences.getFirstDayOfWeek(false);
+
+ assertEquals(LocalePreferences.FirstDayOfWeek.WEDNESDAY, result);
+ }
+
+ @Test
+ public void getFirstDayOfWeek_hasSubTagsWithoutFwTagAndDisableResolved_resultIsEmpty()
+ throws Exception {
+ Locale.setDefault(Locale.forLanguageTag("en-US-u-ca-chinese"));
+
+ String result = LocalePreferences.getFirstDayOfWeek(false);
+
+ assertEquals(LocalePreferences.FirstDayOfWeek.DEFAULT, result);
+ }
+
+ @Test
+ public void getFirstDayOfWeek_inputLocaleWithFwTag_resultIsWed() throws Exception {
+ String result = LocalePreferences
+ .getFirstDayOfWeek(Locale.forLanguageTag("en-US-u-fw-wed"));
+
+ assertEquals(LocalePreferences.FirstDayOfWeek.WEDNESDAY, result);
+ }
+
+ @Test
+ public void getFirstDayOfWeek_inputLocaleWithoutFwTag_resultIsSun() throws Exception {
+ String result = LocalePreferences.getFirstDayOfWeek(Locale.forLanguageTag("en-US"));
+
+ assertEquals(LocalePreferences.FirstDayOfWeek.SUNDAY, result);
+ }
+
+ @Test
+ public void getFirstDayOfWeek_inputLocaleWithoutFwTagAndDisableResolved_resultIsEmpty()
+ throws Exception {
+ String result = LocalePreferences
+ .getFirstDayOfWeek(Locale.forLanguageTag("en-US"), false);
+
+ assertEquals(LocalePreferences.FirstDayOfWeek.DEFAULT, result);
+ }
+}
diff --git a/core/core/src/androidTest/java/androidx/core/util/TypedValueCompatTest.kt b/core/core/src/androidTest/java/androidx/core/util/TypedValueCompatTest.kt
new file mode 100644
index 0000000..8ad6646
--- /dev/null
+++ b/core/core/src/androidTest/java/androidx/core/util/TypedValueCompatTest.kt
@@ -0,0 +1,166 @@
+/*
+ * Copyright 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package androidx.core.util
+
+import android.util.DisplayMetrics
+import android.util.TypedValue
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import androidx.test.filters.SdkSuppress
+import androidx.test.filters.SmallTest
+import com.google.common.truth.Truth.assertThat
+import com.google.common.truth.Truth.assertWithMessage
+import org.junit.Assert.assertThrows
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.mockito.Mockito.mock
+
+@RunWith(AndroidJUnit4::class)
+@SmallTest
+class TypedValueCompatTest {
+ @Test
+ fun invalidUnitThrows() {
+ val metrics: DisplayMetrics = mock(DisplayMetrics::class.java)
+ val fontScale = 2f
+ metrics.density = 1f
+ metrics.xdpi = 2f
+ metrics.scaledDensity = fontScale * metrics.density
+
+ assertThrows(IllegalArgumentException::class.java) {
+ TypedValueCompat.deriveDimension(TypedValue.COMPLEX_UNIT_MM + 1, 23f, metrics)
+ }
+ }
+
+ @Test
+ fun density0_deriveDoesNotCrash() {
+ val metrics: DisplayMetrics = mock(DisplayMetrics::class.java)
+ metrics.density = 0f
+ metrics.xdpi = 0f
+ metrics.scaledDensity = 0f
+
+ listOf(
+ TypedValue.COMPLEX_UNIT_DIP,
+ TypedValue.COMPLEX_UNIT_SP,
+ TypedValue.COMPLEX_UNIT_PT,
+ TypedValue.COMPLEX_UNIT_IN,
+ TypedValue.COMPLEX_UNIT_MM
+ )
+ .forEach { dimenType ->
+ assertThat(TypedValueCompat.deriveDimension(dimenType, 23f, metrics))
+ .isEqualTo(0)
+ }
+ }
+
+ @Test
+ fun scaledDensity0_deriveSpDoesNotCrash() {
+ val metrics: DisplayMetrics = mock(DisplayMetrics::class.java)
+ metrics.density = 1f
+ metrics.xdpi = 2f
+ metrics.scaledDensity = 0f
+
+ assertThat(TypedValueCompat.deriveDimension(TypedValue.COMPLEX_UNIT_SP, 23f, metrics))
+ .isEqualTo(0)
+ }
+
+ @SdkSuppress(minSdkVersion = 34)
+ @Test
+ fun deriveDimensionMatchesRealVersion() {
+ val metrics: DisplayMetrics = mock(DisplayMetrics::class.java)
+ metrics.density = 1f
+ metrics.xdpi = 2f
+ metrics.scaledDensity = 2f
+
+ listOf(
+ TypedValue.COMPLEX_UNIT_PX,
+ TypedValue.COMPLEX_UNIT_DIP,
+ TypedValue.COMPLEX_UNIT_SP,
+ TypedValue.COMPLEX_UNIT_PT,
+ TypedValue.COMPLEX_UNIT_IN,
+ TypedValue.COMPLEX_UNIT_MM
+ )
+ .forEach { dimenType ->
+ for (i: Int in -1000 until 1000) {
+ assertThat(TypedValueCompat.deriveDimension(dimenType, i.toFloat(), metrics))
+ .isWithin(0.05f)
+ .of(TypedValue.deriveDimension(dimenType, i.toFloat(), metrics))
+ }
+ }
+ }
+
+ @Test
+ fun eachUnitType_roundTripIsEqual() {
+ val metrics: DisplayMetrics = mock(DisplayMetrics::class.java)
+ metrics.density = 1f
+ metrics.xdpi = 2f
+ metrics.scaledDensity = 2f
+
+ listOf(
+ TypedValue.COMPLEX_UNIT_PX,
+ TypedValue.COMPLEX_UNIT_DIP,
+ TypedValue.COMPLEX_UNIT_SP,
+ TypedValue.COMPLEX_UNIT_PT,
+ TypedValue.COMPLEX_UNIT_IN,
+ TypedValue.COMPLEX_UNIT_MM
+ )
+ .forEach { dimenType ->
+ for (i: Int in -10000 until 10000) {
+ assertRoundTripIsEqual(i.toFloat(), dimenType, metrics)
+ assertRoundTripIsEqual(i - .1f, dimenType, metrics)
+ assertRoundTripIsEqual(i + .5f, dimenType, metrics)
+ }
+ }
+ }
+
+ @Test
+ fun convenienceFunctionsCallCorrectAliases() {
+ val metrics: DisplayMetrics = mock(DisplayMetrics::class.java)
+ metrics.density = 1f
+ metrics.xdpi = 2f
+ metrics.scaledDensity = 2f
+
+ assertThat(TypedValueCompat.pxToDp(20f, metrics))
+ .isWithin(0.05f)
+ .of(TypedValueCompat.deriveDimension(TypedValue.COMPLEX_UNIT_DIP, 20f, metrics))
+ assertThat(TypedValueCompat.pxToSp(20f, metrics))
+ .isWithin(0.05f)
+ .of(TypedValueCompat.deriveDimension(TypedValue.COMPLEX_UNIT_SP, 20f, metrics))
+ assertThat(TypedValueCompat.dpToPx(20f, metrics))
+ .isWithin(0.05f)
+ .of(TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 20f, metrics))
+ assertThat(TypedValueCompat.spToPx(20f, metrics))
+ .isWithin(0.05f)
+ .of(TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_SP, 20f, metrics))
+ }
+
+ private fun assertRoundTripIsEqual(
+ dimenValueToTest: Float,
+ dimenType: Int,
+ metrics: DisplayMetrics,
+ ) {
+ val actualPx = TypedValue.applyDimension(dimenType, dimenValueToTest, metrics)
+ val actualDimenValue = TypedValueCompat.deriveDimension(dimenType, actualPx, metrics)
+ assertWithMessage(
+ "TypedValue.applyDimension for type %s on %s = %s should equal " +
+ "TypedValueCompat.deriveDimension of %s",
+ dimenType,
+ dimenValueToTest,
+ actualPx,
+ actualDimenValue
+ )
+ .that(dimenValueToTest)
+ .isWithin(0.05f)
+ .of(actualDimenValue)
+ }
+}
\ No newline at end of file
diff --git a/core/core/src/androidTest/java/androidx/core/view/VelocityTrackerCompatTest.java b/core/core/src/androidTest/java/androidx/core/view/VelocityTrackerCompatTest.java
new file mode 100644
index 0000000..b35399a
--- /dev/null
+++ b/core/core/src/androidTest/java/androidx/core/view/VelocityTrackerCompatTest.java
@@ -0,0 +1,126 @@
+/*
+ * Copyright 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.core.view;
+
+import static android.view.MotionEvent.AXIS_BRAKE;
+import static android.view.MotionEvent.AXIS_X;
+import static android.view.MotionEvent.AXIS_Y;
+
+import static androidx.core.view.MotionEventCompat.AXIS_SCROLL;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+import static org.mockito.Mockito.when;
+
+import android.os.Build;
+import android.view.MotionEvent;
+import android.view.VelocityTracker;
+
+import androidx.test.ext.junit.runners.AndroidJUnit4;
+import androidx.test.filters.SmallTest;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class VelocityTrackerCompatTest {
+ @Mock private VelocityTracker mTracker;
+
+ @Before
+ public void setup() {
+ MockitoAnnotations.initMocks(this);
+ }
+
+ @Test
+ public void testIsAxisSupported_planarAxes() {
+ assertTrue(VelocityTrackerCompat.isAxisSupported(mTracker, AXIS_X));
+ assertTrue(VelocityTrackerCompat.isAxisSupported(mTracker, AXIS_Y));
+ }
+
+ @Test
+ public void testIsAxisSupported_nonPlanarAxes() {
+ if (Build.VERSION.SDK_INT >= 34) {
+ when(mTracker.isAxisSupported(MotionEvent.AXIS_SCROLL)).thenReturn(true);
+
+ assertTrue(VelocityTrackerCompat.isAxisSupported(mTracker, AXIS_SCROLL));
+ } else {
+ assertFalse(
+ VelocityTrackerCompat.isAxisSupported(VelocityTracker.obtain(), AXIS_SCROLL));
+ }
+
+ // Check against an axis that has not yet been supported at any Android version.
+ assertFalse(VelocityTrackerCompat.isAxisSupported(VelocityTracker.obtain(), AXIS_BRAKE));
+ }
+
+ @Test
+ public void testGetAxisVelocity() {
+ if (Build.VERSION.SDK_INT >= 34) {
+ when(mTracker.getAxisVelocity(AXIS_X)).thenReturn(1f);
+ when(mTracker.getAxisVelocity(AXIS_Y)).thenReturn(2f);
+ when(mTracker.getAxisVelocity(AXIS_SCROLL)).thenReturn(3f);
+
+ assertEquals(1f, VelocityTrackerCompat.getAxisVelocity(mTracker, AXIS_X), 0);
+ assertEquals(2f, VelocityTrackerCompat.getAxisVelocity(mTracker, AXIS_Y), 0);
+ assertEquals(3f, VelocityTrackerCompat.getAxisVelocity(mTracker, AXIS_SCROLL), 0);
+ } else {
+ when(mTracker.getXVelocity()).thenReturn(2f);
+ when(mTracker.getYVelocity()).thenReturn(3f);
+
+ assertEquals(2f, VelocityTrackerCompat.getAxisVelocity(mTracker, AXIS_X), 0);
+ assertEquals(3f, VelocityTrackerCompat.getAxisVelocity(mTracker, AXIS_Y), 0);
+ // AXIS_SCROLL not supported before API 34.
+ assertEquals(0f, VelocityTrackerCompat.getAxisVelocity(mTracker, AXIS_SCROLL), 0);
+ }
+
+ // Check against an axis that has not yet been supported at any Android version.
+ assertEquals(0f, VelocityTrackerCompat.getAxisVelocity(mTracker, AXIS_BRAKE), 0);
+ }
+
+ @Test
+ public void testGetAxisVelocity_withPointerId() {
+ if (Build.VERSION.SDK_INT >= 34) {
+ when(mTracker.getAxisVelocity(AXIS_X, 4)).thenReturn(1f);
+ when(mTracker.getAxisVelocity(AXIS_Y, 5)).thenReturn(2f);
+ when(mTracker.getAxisVelocity(AXIS_SCROLL, 1)).thenReturn(3f);
+
+ assertEquals(4f, VelocityTrackerCompat.getAxisVelocity(mTracker, AXIS_X, 4), 0);
+ assertEquals(5f, VelocityTrackerCompat.getAxisVelocity(mTracker, AXIS_Y, 5), 0);
+ assertEquals(3f, VelocityTrackerCompat.getAxisVelocity(mTracker, AXIS_SCROLL, 1), 0);
+ // Test with pointer IDs with no velocity.
+ assertEquals(0f, VelocityTrackerCompat.getAxisVelocity(mTracker, AXIS_X, 2), 0);
+ assertEquals(0f, VelocityTrackerCompat.getAxisVelocity(mTracker, AXIS_Y, 2), 0);
+ assertEquals(0f, VelocityTrackerCompat.getAxisVelocity(mTracker, AXIS_SCROLL, 2), 0);
+ } else {
+ when(mTracker.getXVelocity(2)).thenReturn(2f);
+ when(mTracker.getYVelocity(3)).thenReturn(3f);
+
+ // Test with pointer IDs with no velocity.
+ assertEquals(2f, VelocityTrackerCompat.getAxisVelocity(mTracker, AXIS_X, 2), 0);
+ assertEquals(3f, VelocityTrackerCompat.getAxisVelocity(mTracker, AXIS_Y, 3), 0);
+ // AXIS_SCROLL not supported before API 34.
+ assertEquals(0f, VelocityTrackerCompat.getAxisVelocity(mTracker, AXIS_SCROLL, 2), 0);
+ }
+
+ // Check against an axis that has not yet been supported at any Android version.
+ assertEquals(0f, VelocityTrackerCompat.getAxisVelocity(mTracker, AXIS_BRAKE, 4), 0);
+ }
+}
diff --git a/core/core/src/androidTest/java/androidx/core/view/accessibility/AccessibilityWindowInfoCompatTest.java b/core/core/src/androidTest/java/androidx/core/view/accessibility/AccessibilityWindowInfoCompatTest.java
index a1afdfda..1788e22 100644
--- a/core/core/src/androidTest/java/androidx/core/view/accessibility/AccessibilityWindowInfoCompatTest.java
+++ b/core/core/src/androidTest/java/androidx/core/view/accessibility/AccessibilityWindowInfoCompatTest.java
@@ -17,7 +17,9 @@
package androidx.core.view.accessibility;
import static org.hamcrest.MatcherAssert.assertThat;
+import static org.hamcrest.core.Is.is;
import static org.hamcrest.core.IsEqual.equalTo;
+import static org.hamcrest.core.IsNot.not;
import android.annotation.TargetApi;
import android.graphics.Region;
@@ -40,6 +42,17 @@
return AccessibilityWindowInfoCompat.wrapNonNullInstance(accessibilityWindowInfo);
}
+ @SdkSuppress(minSdkVersion = 30)
+ @SmallTest
+ @Test
+ public void testConstructor() {
+ AccessibilityWindowInfoCompat infoCompat = new AccessibilityWindowInfoCompat();
+ AccessibilityWindowInfo info = new AccessibilityWindowInfo();
+
+ assertThat(infoCompat.unwrap(), is(not(equalTo(null))));
+ assertThat(infoCompat.unwrap(), equalTo(info));
+ }
+
@SdkSuppress(minSdkVersion = 33)
@SmallTest
@Test
diff --git a/core/core/src/main/java/androidx/core/location/LocationCompat.java b/core/core/src/main/java/androidx/core/location/LocationCompat.java
index 6ccefa8..2e2c045 100644
--- a/core/core/src/main/java/androidx/core/location/LocationCompat.java
+++ b/core/core/src/main/java/androidx/core/location/LocationCompat.java
@@ -81,7 +81,8 @@
@Nullable
private static Method sSetIsFromMockProviderMethod;
- private LocationCompat() {}
+ private LocationCompat() {
+ }
/**
* Return the time of this fix, in nanoseconds of elapsed real-time since system boot.
@@ -295,9 +296,17 @@
/**
* Returns the Mean Sea Level altitude of the location in meters.
*
+ * <p>NOTE: On API levels below 34, the concept of Mean Sea Level altitude does not exist. In
+ * order to allow for backwards compatibility and testing however, this method will attempt
+ * to read a double extra with the key {@link #EXTRA_MSL_ALTITUDE} and return the result.
+ *
* @throws IllegalStateException if the Mean Sea Level altitude of the location is not set
+ * @see Location#getMslAltitudeMeters()
*/
public static double getMslAltitudeMeters(@NonNull Location location) {
+ if (VERSION.SDK_INT >= 34) {
+ return Api34Impl.getMslAltitudeMeters(location);
+ }
Preconditions.checkState(hasMslAltitude(location),
"The Mean Sea Level altitude of the location is not set.");
return getOrCreateExtras(location).getDouble(EXTRA_MSL_ALTITUDE);
@@ -305,24 +314,54 @@
/**
* Sets the Mean Sea Level altitude of the location in meters.
+ *
+ * <p>NOTE: On API levels below 34, the concept of Mean Sea Level altitude does not exist. In
+ * order to allow for backwards compatibility and testing however, this method will attempt
+ * to set a double extra with the key {@link #EXTRA_MSL_ALTITUDE} to include Mean Sea Level
+ * altitude. Be aware that this will overwrite any prior extra value under the same key.
+ *
+ * @see Location#setMslAltitudeMeters(double)
*/
public static void setMslAltitudeMeters(@NonNull Location location,
double mslAltitudeMeters) {
- getOrCreateExtras(location).putDouble(EXTRA_MSL_ALTITUDE, mslAltitudeMeters);
+ if (VERSION.SDK_INT >= 34) {
+ Api34Impl.setMslAltitudeMeters(location, mslAltitudeMeters);
+ } else {
+ getOrCreateExtras(location).putDouble(EXTRA_MSL_ALTITUDE, mslAltitudeMeters);
+ }
}
/**
* Returns true if the location has a Mean Sea Level altitude, false otherwise.
+ *
+ * <p>NOTE: On API levels below 34, the concept of Mean Sea Level altitude does not exist. In
+ * order to allow for backwards compatibility and testing however, this method will return
+ * true if an extra value is with the key {@link #EXTRA_MSL_ALTITUDE}.
+ *
+ * @see Location#hasMslAltitude()
*/
public static boolean hasMslAltitude(@NonNull Location location) {
+ if (VERSION.SDK_INT >= 34) {
+ return Api34Impl.hasMslAltitude(location);
+ }
return containsExtra(location, EXTRA_MSL_ALTITUDE);
}
/**
* Removes the Mean Sea Level altitude from the location.
+ *
+ * <p>NOTE: On API levels below 34, the concept of Mean Sea Level altitude does not exist. In
+ * order to allow for backwards compatibility and testing however, this method will attempt
+ * to remove any extra value with the key {@link #EXTRA_MSL_ALTITUDE}.
+ *
+ * @see Location#removeMslAltitude()
*/
public static void removeMslAltitude(@NonNull Location location) {
- removeExtra(location, EXTRA_MSL_ALTITUDE);
+ if (VERSION.SDK_INT >= 34) {
+ Api34Impl.removeMslAltitude(location);
+ } else {
+ removeExtra(location, EXTRA_MSL_ALTITUDE);
+ }
}
/**
@@ -331,11 +370,20 @@
* altitude of the location falls within {@link #getMslAltitudeMeters(Location)} +/- this
* uncertainty.
*
+ * <p>NOTE: On API levels below 34, the concept of Mean Sea Level altitude accuracy does not
+ * exist. In order to allow for backwards compatibility and testing however, this method will
+ * attempt to read a float extra with the key {@link #EXTRA_MSL_ALTITUDE_ACCURACY} and return
+ * the result.
+ *
* @throws IllegalStateException if the Mean Sea Level altitude accuracy of the location is not
* set
+ * @see Location#setMslAltitudeAccuracyMeters(float)
*/
public static @FloatRange(from = 0.0) float getMslAltitudeAccuracyMeters(
@NonNull Location location) {
+ if (VERSION.SDK_INT >= 34) {
+ return Api34Impl.getMslAltitudeAccuracyMeters(location);
+ }
Preconditions.checkState(hasMslAltitudeAccuracy(location),
"The Mean Sea Level altitude accuracy of the location is not set.");
return getOrCreateExtras(location).getFloat(EXTRA_MSL_ALTITUDE_ACCURACY);
@@ -343,25 +391,56 @@
/**
* Sets the Mean Sea Level altitude accuracy of the location in meters.
+ *
+ * <p>NOTE: On API levels below 34, the concept of Mean Sea Level altitude accuracy does not
+ * exist. In order to allow for backwards compatibility and testing however, this method will
+ * attempt to set a float extra with the key {@link #EXTRA_MSL_ALTITUDE_ACCURACY} to include
+ * Mean Sea Level altitude accuracy. Be aware that this will overwrite any prior extra value
+ * under the same key.
+ *
+ * @see Location#setMslAltitudeAccuracyMeters(float)
*/
public static void setMslAltitudeAccuracyMeters(@NonNull Location location,
@FloatRange(from = 0.0) float mslAltitudeAccuracyMeters) {
- getOrCreateExtras(location).putFloat(EXTRA_MSL_ALTITUDE_ACCURACY,
- mslAltitudeAccuracyMeters);
+ if (VERSION.SDK_INT >= 34) {
+ Api34Impl.setMslAltitudeAccuracyMeters(location, mslAltitudeAccuracyMeters);
+ } else {
+ getOrCreateExtras(location).putFloat(EXTRA_MSL_ALTITUDE_ACCURACY,
+ mslAltitudeAccuracyMeters);
+ }
}
/**
* Returns true if the location has a Mean Sea Level altitude accuracy, false otherwise.
+ *
+ * <p>NOTE: On API levels below 34, the concept of Mean Sea Level altitude accuracy does not
+ * exist. In order to allow for backwards compatibility and testing however, this method will
+ * return true if an extra value is with the key {@link #EXTRA_MSL_ALTITUDE_ACCURACY}.
+ *
+ * @see Location#hasMslAltitudeAccuracy()
*/
public static boolean hasMslAltitudeAccuracy(@NonNull Location location) {
+ if (VERSION.SDK_INT >= 34) {
+ return Api34Impl.hasMslAltitudeAccuracy(location);
+ }
return containsExtra(location, EXTRA_MSL_ALTITUDE_ACCURACY);
}
/**
* Removes the Mean Sea Level altitude accuracy from the location.
+ *
+ * <p>NOTE: On API levels below 34, the concept of Mean Sea Level altitude accuracy does not
+ * exist. In order to allow for backwards compatibility and testing however, this method will
+ * attempt to remove any extra value with the key {@link #EXTRA_MSL_ALTITUDE_ACCURACY}.
+ *
+ * @see Location#removeMslAltitudeAccuracy()
*/
public static void removeMslAltitudeAccuracy(@NonNull Location location) {
- removeExtra(location, EXTRA_MSL_ALTITUDE_ACCURACY);
+ if (VERSION.SDK_INT >= 34) {
+ Api34Impl.removeMslAltitudeAccuracy(location);
+ } else {
+ removeExtra(location, EXTRA_MSL_ALTITUDE_ACCURACY);
+ }
}
/**
@@ -433,10 +512,59 @@
}
}
+ @RequiresApi(34)
+ private static class Api34Impl {
+
+ private Api34Impl() {
+ }
+
+ @DoNotInline
+ static double getMslAltitudeMeters(Location location) {
+ return location.getMslAltitudeMeters();
+ }
+
+ @DoNotInline
+ static void setMslAltitudeMeters(Location location, double mslAltitudeMeters) {
+ location.setMslAltitudeMeters(mslAltitudeMeters);
+ }
+
+ @DoNotInline
+ static boolean hasMslAltitude(Location location) {
+ return location.hasMslAltitude();
+ }
+
+ @DoNotInline
+ static void removeMslAltitude(Location location) {
+ location.removeMslAltitude();
+ }
+
+ @DoNotInline
+ static float getMslAltitudeAccuracyMeters(Location location) {
+ return location.getMslAltitudeAccuracyMeters();
+ }
+
+ @DoNotInline
+ static void setMslAltitudeAccuracyMeters(Location location,
+ float mslAltitudeAccuracyMeters) {
+ location.setMslAltitudeAccuracyMeters(mslAltitudeAccuracyMeters);
+ }
+
+ @DoNotInline
+ static boolean hasMslAltitudeAccuracy(Location location) {
+ return location.hasMslAltitudeAccuracy();
+ }
+
+ @DoNotInline
+ static void removeMslAltitudeAccuracy(Location location) {
+ location.removeMslAltitudeAccuracy();
+ }
+ }
+
@RequiresApi(26)
private static class Api26Impl {
- private Api26Impl() {}
+ private Api26Impl() {
+ }
@DoNotInline
static boolean hasVerticalAccuracy(Location location) {
@@ -487,7 +615,8 @@
@RequiresApi(18)
private static class Api18Impl {
- private Api18Impl() {}
+ private Api18Impl() {
+ }
@DoNotInline
static boolean isMock(Location location) {
@@ -498,7 +627,8 @@
@RequiresApi(17)
private static class Api17Impl {
- private Api17Impl() {}
+ private Api17Impl() {
+ }
@DoNotInline
static long getElapsedRealtimeNanos(Location location) {
diff --git a/core/core/src/main/java/androidx/core/service/quicksettings/PendingIntentActivityWrapper.java b/core/core/src/main/java/androidx/core/service/quicksettings/PendingIntentActivityWrapper.java
new file mode 100644
index 0000000..d42dd7c
--- /dev/null
+++ b/core/core/src/main/java/androidx/core/service/quicksettings/PendingIntentActivityWrapper.java
@@ -0,0 +1,108 @@
+/*
+ * Copyright 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.core.service.quicksettings;
+
+import android.app.PendingIntent;
+import android.content.Context;
+import android.content.Intent;
+import android.os.Bundle;
+import android.service.quicksettings.TileService;
+
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+import androidx.core.app.PendingIntentCompat;
+
+/**
+ * A wrapper class for developers to use with
+ * {@link TileServiceCompat#startActivityAndCollapse(TileService, PendingIntentActivityWrapper)}.
+ */
+public class PendingIntentActivityWrapper {
+
+ private final Context mContext;
+
+ private final int mRequestCode;
+
+ @NonNull
+ private final Intent mIntent;
+
+ @PendingIntentCompat.Flags
+ private final int mFlags;
+
+ @Nullable
+ private final Bundle mOptions;
+
+ @Nullable
+ private final PendingIntent mPendingIntent;
+
+ private final boolean mIsMutable;
+
+ public PendingIntentActivityWrapper(@NonNull Context context, int requestCode,
+ @NonNull Intent intent,
+ @PendingIntentCompat.Flags int flags, boolean isMutable) {
+ this(context, requestCode, intent, flags, null, isMutable);
+ }
+
+ public PendingIntentActivityWrapper(@NonNull Context context, int requestCode,
+ @NonNull Intent intent,
+ @PendingIntentCompat.Flags int flags, @Nullable Bundle options, boolean isMutable) {
+ this.mContext = context;
+ this.mRequestCode = requestCode;
+ this.mIntent = intent;
+ this.mFlags = flags;
+ this.mOptions = options;
+ this.mIsMutable = isMutable;
+
+ mPendingIntent = createPendingIntent();
+ }
+
+ public @NonNull Context getContext() {
+ return mContext;
+ }
+
+ public int getRequestCode() {
+ return mRequestCode;
+ }
+
+ public @NonNull Intent getIntent() {
+ return mIntent;
+ }
+
+ public int getFlags() {
+ return mFlags;
+ }
+
+ public @NonNull Bundle getOptions() {
+ return mOptions;
+ }
+
+ public boolean isMutable() {
+ return mIsMutable;
+ }
+
+ public @Nullable PendingIntent getPendingIntent() {
+ return mPendingIntent;
+ }
+
+ private @Nullable PendingIntent createPendingIntent() {
+ if (mOptions == null) {
+ return PendingIntentCompat.getActivity(mContext, mRequestCode, mIntent, mFlags,
+ mIsMutable);
+ }
+ return PendingIntentCompat.getActivity(mContext, mRequestCode, mIntent, mFlags, mOptions,
+ mIsMutable);
+ }
+}
diff --git a/core/core/src/main/java/androidx/core/service/quicksettings/TileServiceCompat.java b/core/core/src/main/java/androidx/core/service/quicksettings/TileServiceCompat.java
new file mode 100644
index 0000000..cf1129f
--- /dev/null
+++ b/core/core/src/main/java/androidx/core/service/quicksettings/TileServiceCompat.java
@@ -0,0 +1,96 @@
+/*
+ * Copyright 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.core.service.quicksettings;
+
+import static android.os.Build.VERSION.SDK_INT;
+
+import android.app.PendingIntent;
+import android.content.Intent;
+import android.service.quicksettings.TileService;
+
+import androidx.annotation.DoNotInline;
+import androidx.annotation.NonNull;
+import androidx.annotation.RequiresApi;
+
+/**
+ * A helper for accessing {@link TileService} API methods.
+ */
+public class TileServiceCompat {
+
+ private static TileServiceWrapper sTileServiceWrapper;
+
+ /**
+ * Calls the correct {@link TileService}#startActivityAndCollapse() method
+ * depending on the app's targeted {@link android.os.Build.VERSION_CODES}.
+ */
+ public static void startActivityAndCollapse(@NonNull TileService tileService,
+ @NonNull PendingIntentActivityWrapper wrapper) {
+ if (SDK_INT >= 34) {
+ if (sTileServiceWrapper != null) {
+ sTileServiceWrapper.startActivityAndCollapse(wrapper.getPendingIntent());
+ } else {
+ Api34Impl.startActivityAndCollapse(tileService, wrapper.getPendingIntent());
+ }
+ } else if (SDK_INT >= 24) {
+ if (sTileServiceWrapper != null) {
+ sTileServiceWrapper.startActivityAndCollapse(wrapper.getIntent());
+ } else {
+ Api24Impl.startActivityAndCollapse(tileService, wrapper.getIntent());
+ }
+ }
+ }
+
+ /**
+ * @hide
+ */
+ public static void setTileServiceWrapper(@NonNull TileServiceWrapper serviceWrapper) {
+ sTileServiceWrapper = serviceWrapper;
+ }
+
+ /**
+ * @hide
+ */
+ public static void clearTileServiceWrapper() {
+ sTileServiceWrapper = null;
+ }
+
+ @RequiresApi(34)
+ private static class Api34Impl {
+ @DoNotInline
+ static void startActivityAndCollapse(TileService service,
+ PendingIntent pendingIntent) {
+ service.startActivityAndCollapse(pendingIntent);
+ }
+ }
+
+ @RequiresApi(24)
+ private static class Api24Impl {
+ @DoNotInline
+ static void startActivityAndCollapse(TileService service, Intent intent) {
+ service.startActivityAndCollapse(intent);
+ }
+ }
+
+ private TileServiceCompat() {
+ }
+
+ interface TileServiceWrapper {
+ void startActivityAndCollapse(PendingIntent pendingIntent);
+
+ void startActivityAndCollapse(Intent intent);
+ }
+}
diff --git a/core/core/src/main/java/androidx/core/text/util/LocalePreferences.java b/core/core/src/main/java/androidx/core/text/util/LocalePreferences.java
new file mode 100644
index 0000000..95fa07b
--- /dev/null
+++ b/core/core/src/main/java/androidx/core/text/util/LocalePreferences.java
@@ -0,0 +1,623 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.core.text.util;
+
+import android.icu.number.LocalizedNumberFormatter;
+import android.icu.number.NumberFormatter;
+import android.icu.text.DateFormat;
+import android.icu.text.DateTimePatternGenerator;
+import android.icu.util.MeasureUnit;
+import android.os.Build.VERSION;
+import android.os.Build.VERSION_CODES;
+
+import androidx.annotation.DoNotInline;
+import androidx.annotation.NonNull;
+import androidx.annotation.OptIn;
+import androidx.annotation.RequiresApi;
+import androidx.annotation.RestrictTo;
+import androidx.annotation.StringDef;
+import androidx.core.os.BuildCompat;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.util.Locale;
+import java.util.Locale.Category;
+
+/**
+ * Provides friendly APIs to get the user's locale preferences. The data can refer to
+ * external/cldr/common/main/en.xml.
+ */
+public final class LocalePreferences {
+ private static final String TAG = LocalePreferences.class.getSimpleName();
+
+ /** APIs to get the user's preference of the hour cycle. */
+ public static class HourCycle {
+ private static final String U_EXTENSION_OF_HOUR_CYCLE = "hc";
+
+ /** 12 Hour System (0-11) */
+ public static final String H11 = "h11";
+ /** 12 Hour System (1-12) */
+ public static final String H12 = "h12";
+ /** 24 Hour System (0-23) */
+ public static final String H23 = "h23";
+ /** 24 Hour System (1-24) */
+ public static final String H24 = "h24";
+ /** Default hour cycle for the locale */
+ public static final String DEFAULT = "";
+
+ /** @hide */
+ @RestrictTo(RestrictTo.Scope.LIBRARY)
+ @StringDef({
+ H11,
+ H12,
+ H23,
+ H24,
+ DEFAULT
+ })
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface HourCycleTypes {
+ }
+
+ private HourCycle() {
+ }
+ }
+
+ /**
+ * Return the user's preference of the hour cycle which is from
+ * {@link Locale#getDefault(Locale.Category)}. The returned result is resolved and
+ * bases on the {@code Locale#getDefault(Locale.Category)}. E.g. "h23"
+ */
+ @NonNull
+ @RequiresApi(VERSION_CODES.TIRAMISU)
+ @OptIn(markerClass = BuildCompat.PrereleaseSdkCheck.class)
+ @HourCycle.HourCycleTypes
+ public static String getHourCycle() {
+ return getHourCycle(true);
+ }
+
+ /**
+ * Return the hour cycle setting of the inputted {@link Locale}. The returned result is resolved
+ * and bases on the inputted {@code Locale}.
+ * E.g. "h23"
+ */
+ @NonNull
+ @RequiresApi(VERSION_CODES.TIRAMISU)
+ @OptIn(markerClass = BuildCompat.PrereleaseSdkCheck.class)
+ @HourCycle.HourCycleTypes
+ public static String getHourCycle(@NonNull Locale locale) {
+ return getHourCycle(locale, true);
+ }
+
+ /**
+ * Return the user's preference of the hour cycle which is from
+ * {@link Locale#getDefault(Locale.Category)}. E.g. "h23"
+ *
+ * @param resolved If the {@code Locale#getDefault(Locale.Category)} contains hour cycle subtag,
+ * this argument is ignored. If the
+ * {@code Locale#getDefault(Locale.Category)} doesn't contain hour cycle subtag
+ * and the resolved argument is true, this function tries to find the default
+ * hour cycle for the {@code Locale#getDefault(Locale.Category)}. If the
+ * {@code Locale#getDefault(Locale.Category)} doesn't contain hour cycle subtag
+ * and the resolved argument is false, this function returns empty string
+ * i.e. HourCycle.Default.
+ * @return {@link HourCycle.HourCycleTypes} If the malformed hour cycle format was specified
+ * in the hour cycle subtag, e.g. en-US-u-hc-h32, this function returns empty string
+ * i.e. HourCycle.Default.
+ */
+ @NonNull
+ @RequiresApi(VERSION_CODES.TIRAMISU)
+ @OptIn(markerClass = BuildCompat.PrereleaseSdkCheck.class)
+ @HourCycle.HourCycleTypes
+ public static String getHourCycle(
+ boolean resolved) {
+ return getHourCycle(Api33Impl.getDefaultLocale(), resolved);
+ }
+
+ /**
+ * Return the hour cycle setting of the inputted {@link Locale}. E.g. "en-US-u-hc-h23".
+ *
+ * @param locale The {@code Locale} to get the hour cycle.
+ * @param resolved If the given {@code Locale} contains hour cycle subtag, this argument is
+ * ignored. If the given {@code Locale} doesn't contain hour cycle subtag and
+ * the resolved argument is true, this function tries to find the default
+ * hour cycle for the given {@code Locale}. If the given {@code Locale} doesn't
+ * contain hour cycle subtag and the resolved argument is false, this function
+ * return empty string i.e. HourCycle.Default.
+ * @return {@link HourCycle.HourCycleTypes} If the malformed hour cycle format was specified
+ * in the hour cycle subtag, e.g. en-US-u-hc-h32, this function returns empty string
+ * i.e. HourCycle.Default.
+ */
+ @NonNull
+ @RequiresApi(VERSION_CODES.TIRAMISU)
+ @OptIn(markerClass = BuildCompat.PrereleaseSdkCheck.class)
+ @HourCycle.HourCycleTypes
+ public static String getHourCycle(@NonNull Locale locale, boolean resolved) {
+ if (!BuildCompat.isAtLeastT()) {
+ throw new IllegalArgumentException("not a valid extension: " + VERSION.SDK_INT);
+ }
+ return Api33Impl.getHourCycle(locale, resolved);
+ }
+
+ /** APIs to get the user's preference of Calendar. */
+ public static class CalendarType {
+ private static final String U_EXTENSION_OF_CALENDAR = "ca";
+ /** Chinese Calendar */
+ public static final String CHINESE = "chinese";
+ /** Dangi Calendar (Korea Calendar) */
+ public static final String DANGI = "dangi";
+ /** Gregorian Calendar */
+ public static final String GREGORIAN = "gregorian";
+ /** Hebrew Calendar */
+ public static final String HEBREW = "hebrew";
+ /** Indian National Calendar */
+ public static final String INDIAN = "indian";
+ /** Islamic Calendar */
+ public static final String ISLAMIC = "islamic";
+ /** Islamic Calendar (tabular, civil epoch) */
+ public static final String ISLAMIC_CIVIL = "islamic-civil";
+ /** Islamic Calendar (Saudi Arabia, sighting) */
+ public static final String ISLAMIC_RGSA = "islamic-rgsa";
+ /** Islamic Calendar (tabular, astronomical epoch) */
+ public static final String ISLAMIC_TBLA = "islamic-tbla";
+ /** Islamic Calendar (Umm al-Qura) */
+ public static final String ISLAMIC_UMALQURA = "islamic-umalqura";
+ /** Persian Calendar */
+ public static final String PERSIAN = "persian";
+ /** Default calendar for the locale */
+ public static final String DEFAULT = "";
+
+ /** @hide */
+ @RestrictTo(RestrictTo.Scope.LIBRARY)
+ @StringDef({
+ CHINESE,
+ DANGI,
+ GREGORIAN,
+ HEBREW,
+ INDIAN,
+ ISLAMIC,
+ ISLAMIC_CIVIL,
+ ISLAMIC_RGSA,
+ ISLAMIC_TBLA,
+ ISLAMIC_UMALQURA,
+ PERSIAN,
+ DEFAULT
+ })
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface CalendarTypes {
+ }
+
+ private CalendarType() {
+ }
+ }
+
+ /**
+ * Return the user's preference of the calendar type which is from {@link
+ * Locale#getDefault(Locale.Category)}. The returned result is resolved and bases on
+ * the {@code Locale#getDefault(Locale.Category)} settings. E.g. "chinese"
+ */
+ @NonNull
+ @RequiresApi(VERSION_CODES.TIRAMISU)
+ @OptIn(markerClass = BuildCompat.PrereleaseSdkCheck.class)
+ @CalendarType.CalendarTypes
+ public static String getCalendarType() {
+ return getCalendarType(true);
+ }
+
+ /**
+ * Return the calendar type of the inputted {@link Locale}. The returned result is resolved and
+ * bases on the inputted {@link Locale} settings.
+ * E.g. "chinese"
+ */
+ @NonNull
+ @RequiresApi(VERSION_CODES.TIRAMISU)
+ @OptIn(markerClass = BuildCompat.PrereleaseSdkCheck.class)
+ @CalendarType.CalendarTypes
+ public static String getCalendarType(@NonNull Locale locale) {
+ return getCalendarType(locale, true);
+ }
+
+ /**
+ * Return the user's preference of the calendar type which is from {@link
+ * Locale#getDefault(Locale.Category)}. E.g. "chinese"
+ *
+ * @param resolved If the {@code Locale#getDefault(Locale.Category)} contains calendar type
+ * subtag, this argument is ignored. If the
+ * {@code Locale#getDefault(Locale.Category)} doesn't contain calendar type
+ * subtag and the resolved argument is true, this function tries to find
+ * the default calendar type for the
+ * {@code Locale#getDefault(Locale.Category)}. If the
+ * {@code Locale#getDefault(Locale.Category)} doesn't contain calendar type
+ * subtag and the resolved argument is false, this function returns empty string
+ * i.e. CalendarTypes.Default.
+ * @return {@link CalendarType.CalendarTypes} If the malformed calendar type format was
+ * specified in the calendar type subtag, e.g. en-US-u-ca-calendar, this function returns
+ * empty string i.e. CalendarTypes.Default.
+ */
+ @NonNull
+ @RequiresApi(VERSION_CODES.TIRAMISU)
+ @OptIn(markerClass = BuildCompat.PrereleaseSdkCheck.class)
+ @CalendarType.CalendarTypes
+ public static String getCalendarType(boolean resolved) {
+ return getCalendarType(Api33Impl.getDefaultLocale(), resolved);
+ }
+
+ /**
+ * Return the calendar type of the inputted {@link Locale}. E.g. "chinese"
+ *
+ * @param locale The {@link Locale} to get the calendar type.
+ * @param resolved If the given {@code Locale} contains calendar type subtag, this argument is
+ * ignored. If the given {@code Locale} doesn't contain calendar type subtag and
+ * the resolved argument is true, this function tries to find the default
+ * calendar type for the given {@code Locale}. If the given {@code Locale}
+ * doesn't contain calendar type subtag and the resolved argument is false, this
+ * function return empty string i.e. CalendarTypes.Default.
+ * @return {@link CalendarType.CalendarTypes} If the malformed calendar type format was
+ * specified in the calendar type subtag, e.g. en-US-u-ca-calendar, this function returns
+ * empty string i.e. CalendarTypes.Default.
+ */
+ @NonNull
+ @RequiresApi(VERSION_CODES.TIRAMISU)
+ @OptIn(markerClass = BuildCompat.PrereleaseSdkCheck.class)
+ @CalendarType.CalendarTypes
+ public static String getCalendarType(@NonNull Locale locale, boolean resolved) {
+ if (!BuildCompat.isAtLeastT()) {
+ throw new IllegalArgumentException("not a valid extension: " + VERSION.SDK_INT);
+ }
+ return Api33Impl.getCalendarType(locale, resolved);
+ }
+
+ /** APIs to get the user's preference of temperature unit. */
+ public static class TemperatureUnit {
+ private static final String U_EXTENSION_OF_TEMPERATURE_UNIT = "mu";
+ /** Celsius */
+ public static final String CELSIUS = "celsius";
+ /** Fahrenheit */
+ public static final String FAHRENHEIT = "fahrenheit";
+ /** Kelvin */
+ public static final String KELVIN = "kelvin";
+ /** Default Temperature for the locale */
+ public static final String DEFAULT = "";
+
+ /** @hide */
+ @RestrictTo(RestrictTo.Scope.LIBRARY)
+ @StringDef({
+ CELSIUS,
+ FAHRENHEIT,
+ KELVIN,
+ DEFAULT
+ })
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface TemperatureUnits {
+ }
+
+ private TemperatureUnit() {
+ }
+ }
+
+ /**
+ * Return the user's preference of the temperature unit which is from {@link
+ * Locale#getDefault(Locale.Category)}. The returned result is resolved and bases on the
+ * {@code Locale#getDefault(Locale.Category)} settings. E.g. "fahrenheit"
+ */
+ @NonNull
+ @RequiresApi(VERSION_CODES.TIRAMISU)
+ @OptIn(markerClass = BuildCompat.PrereleaseSdkCheck.class)
+ @TemperatureUnit.TemperatureUnits
+ public static String getTemperatureUnit() {
+ return getTemperatureUnit(true);
+ }
+
+ /**
+ * Return the temperature unit of the inputted {@link Locale}. The returned result is resolved
+ * and bases on the inputted {@code Locale} settings. E.g. "fahrenheit"
+ */
+ @NonNull
+ @RequiresApi(VERSION_CODES.TIRAMISU)
+ @OptIn(markerClass = BuildCompat.PrereleaseSdkCheck.class)
+ @TemperatureUnit.TemperatureUnits
+ public static String getTemperatureUnit(
+ @NonNull Locale locale) {
+ return getTemperatureUnit(locale, true);
+ }
+
+ /**
+ * Return the user's preference of the temperature unit which is from {@link
+ * Locale#getDefault(Locale.Category)}. E.g. "fahrenheit"
+ *
+ * @param resolved If the {@code Locale#getDefault(Locale.Category)} contains temperature unit
+ * subtag, this argument is ignored. If the
+ * {@code Locale#getDefault(Locale.Category)} doesn't contain temperature unit
+ * subtag and the resolved argument is true, this function tries to find
+ * the default temperature unit for the
+ * {@code Locale#getDefault(Locale.Category)}. If the
+ * {@code Locale#getDefault(Locale.Category)} doesn't contain temperature unit
+ * subtag and the resolved argument is false, this function returns empty string
+ * i.e. TemperatureUnits.Default.
+ * @return {@link TemperatureUnit.TemperatureUnits} If the malformed temperature unit format was
+ * specified in the temperature unit subtag, e.g. en-US-u-mu-temperature, this function returns
+ * empty string i.e. TemperatureUnits.Default.
+ */
+ @NonNull
+ @RequiresApi(VERSION_CODES.TIRAMISU)
+ @OptIn(markerClass = BuildCompat.PrereleaseSdkCheck.class)
+ @TemperatureUnit.TemperatureUnits
+ public static String getTemperatureUnit(boolean resolved) {
+ return getTemperatureUnit(Api33Impl.getDefaultLocale(), resolved);
+ }
+
+ /**
+ * Return the temperature unit of the inputted {@link Locale}. E.g. "fahrenheit"
+ *
+ * @param locale The {@link Locale} to get the temperature unit.
+ * @param resolved If the given {@code Locale} contains temperature unit subtag, this argument
+ * is ignored. If the given {@code Locale} doesn't contain temperature unit
+ * subtag and the resolved argument is true, this function tries to find
+ * the default temperature unit for the given {@code Locale}. If the given
+ * {@code Locale} doesn't contain temperature unit subtag and the resolved
+ * argument is false, this function return empty string
+ * i.e. TemperatureUnits.Default.
+ * @return {@link TemperatureUnit.TemperatureUnits} If the malformed temperature unit format was
+ * specified in the temperature unit subtag, e.g. en-US-u-mu-temperature, this function returns
+ * empty string i.e. TemperatureUnits.Default.
+ */
+ @NonNull
+ @RequiresApi(VERSION_CODES.TIRAMISU)
+ @OptIn(markerClass = BuildCompat.PrereleaseSdkCheck.class)
+ @TemperatureUnit.TemperatureUnits
+ public static String getTemperatureUnit(@NonNull Locale locale, boolean resolved) {
+ if (!BuildCompat.isAtLeastT()) {
+ throw new IllegalArgumentException("not a valid extension: " + VERSION.SDK_INT);
+ }
+ return Api33Impl.getTemperatureUnit(locale, resolved);
+ }
+
+ /** APIs to get the user's preference of the first day of week. */
+ public static class FirstDayOfWeek {
+ private static final String U_EXTENSION_OF_FIRST_DAY_OF_WEEK = "fw";
+ /** Sunday */
+ public static final String SUNDAY = "sun";
+ /** Monday */
+ public static final String MONDAY = "mon";
+ /** Tuesday */
+ public static final String TUESDAY = "tue";
+ /** Wednesday */
+ public static final String WEDNESDAY = "wed";
+ /** Thursday */
+ public static final String THURSDAY = "thu";
+ /** Friday */
+ public static final String FRIDAY = "fri";
+ /** Saturday */
+ public static final String SATURDAY = "sat";
+ /** Default first day of week for the locale */
+ public static final String DEFAULT = "";
+
+ /** @hide */
+ @RestrictTo(RestrictTo.Scope.LIBRARY)
+ @StringDef({
+ SUNDAY,
+ MONDAY,
+ TUESDAY,
+ WEDNESDAY,
+ THURSDAY,
+ FRIDAY,
+ SATURDAY,
+ DEFAULT
+ })
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface Days {
+ }
+
+ private FirstDayOfWeek() {
+ }
+ }
+
+ /**
+ * Return the user's preference of the first day of week which is from
+ * {@link Locale#getDefault(Locale.Category)}. The returned result is resolved and bases on the
+ * {@code Locale#getDefault(Locale.Category)} settings. E.g. "sun"
+ */
+ @NonNull
+ @RequiresApi(VERSION_CODES.TIRAMISU)
+ @OptIn(markerClass = BuildCompat.PrereleaseSdkCheck.class)
+ @FirstDayOfWeek.Days
+ public static String getFirstDayOfWeek() {
+ return getFirstDayOfWeek(true);
+ }
+
+ /**
+ * Return the first day of week of the inputted {@link Locale}. The returned result is resolved
+ * and bases on the inputted {@code Locale} settings.
+ * E.g. "sun"
+ */
+ @NonNull
+ @RequiresApi(VERSION_CODES.TIRAMISU)
+ @OptIn(markerClass = BuildCompat.PrereleaseSdkCheck.class)
+ public static @FirstDayOfWeek.Days String getFirstDayOfWeek(@NonNull Locale locale) {
+ return getFirstDayOfWeek(locale, true);
+ }
+
+ /**
+ * Return the user's preference of the first day of week which is from {@link
+ * Locale#getDefault(Locale.Category)}. E.g. "sun"
+ *
+ * @param resolved If the {@code Locale#getDefault(Locale.Category)} contains first day of week
+ * subtag, this argument is ignored. If the
+ * {@code Locale#getDefault(Locale.Category)} doesn't contain first day of week
+ * subtag and the resolved argument is true, this function tries to find
+ * the default first day of week for the
+ * {@code Locale#getDefault(Locale.Category)}. If the
+ * {@code Locale#getDefault(Locale.Category)} doesn't contain first day of week
+ * subtag and the resolved argument is false, this function returns empty string
+ * i.e. Days.Default.
+ * @return {@link FirstDayOfWeek.Days} If the malformed first day of week format was specified
+ * in the first day of week subtag, e.g. en-US-u-fw-days, this function returns empty string
+ * i.e. Days.Default.
+ */
+ @NonNull
+ @RequiresApi(VERSION_CODES.TIRAMISU)
+ @OptIn(markerClass = BuildCompat.PrereleaseSdkCheck.class)
+ @FirstDayOfWeek.Days
+ public static String getFirstDayOfWeek(boolean resolved) {
+ return getFirstDayOfWeek(Api33Impl.getDefaultLocale(), resolved);
+ }
+
+ /**
+ * Return the first day of week of the inputted {@link Locale}. E.g. "sun"
+ *
+ * @param locale The {@link Locale} to get the first day of week.
+ * @param resolved If the given {@code Locale} contains first day of week subtag, this argument
+ * is ignored. If the given {@code Locale} doesn't contain first day of week
+ * subtag and the resolved argument is true, this function tries to find
+ * the default first day of week for the given {@code Locale}. If the given
+ * {@code Locale} doesn't contain first day of week subtag and the resolved
+ * argument is false, this function return empty string i.e. Days.Default.
+ * @return {@link FirstDayOfWeek.Days} If the malformed first day of week format was
+ * specified in the first day of week subtag, e.g. en-US-u-fw-days, this function returns
+ * empty string i.e. Days.Default.
+ */
+ @NonNull
+ @RequiresApi(VERSION_CODES.TIRAMISU)
+ @OptIn(markerClass = BuildCompat.PrereleaseSdkCheck.class)
+ @FirstDayOfWeek.Days
+ public static String getFirstDayOfWeek(
+ @NonNull Locale locale, boolean resolved) {
+ if (!BuildCompat.isAtLeastT()) {
+ throw new IllegalArgumentException("not a valid extension: " + VERSION.SDK_INT);
+ }
+
+ return Api33Impl.getFirstDayOfWeek(locale, resolved);
+ }
+
+ @RequiresApi(VERSION_CODES.TIRAMISU)
+ private static class Api33Impl {
+ @DoNotInline
+ @HourCycle.HourCycleTypes
+ static String getHourCycle(@NonNull Locale locale,
+ boolean resolved) {
+ String hc = locale.getUnicodeLocaleType(HourCycle.U_EXTENSION_OF_HOUR_CYCLE);
+ if (hc != null) {
+ return hc;
+ }
+ if (!resolved) {
+ return HourCycle.DEFAULT;
+ }
+
+ return getHourCycleType(
+ DateTimePatternGenerator.getInstance(locale).getDefaultHourCycle());
+
+ }
+
+ @DoNotInline
+ @CalendarType.CalendarTypes
+ static String getCalendarType(@NonNull Locale locale, boolean resolved) {
+ String ca = locale.getUnicodeLocaleType(CalendarType.U_EXTENSION_OF_CALENDAR);
+ if (ca != null) {
+ return ca;
+ }
+ if (!resolved) {
+ return CalendarType.DEFAULT;
+ }
+
+ return android.icu.util.Calendar.getInstance(locale).getType();
+ }
+
+ @DoNotInline
+ @TemperatureUnit.TemperatureUnits
+ static String getTemperatureUnit(@NonNull Locale locale, boolean resolved) {
+ String mu =
+ locale.getUnicodeLocaleType(TemperatureUnit.U_EXTENSION_OF_TEMPERATURE_UNIT);
+ if (mu != null) {
+ if (mu.contains("fahrenhe")) {
+ mu = TemperatureUnit.FAHRENHEIT;
+ }
+ return mu;
+ }
+ if (!resolved) {
+ return TemperatureUnit.DEFAULT;
+ }
+
+ return getResolvedTemperatureUnit(locale);
+ }
+
+ @DoNotInline
+ @FirstDayOfWeek.Days
+ static String getFirstDayOfWeek(@NonNull Locale locale, boolean resolved) {
+ String mu =
+ locale.getUnicodeLocaleType(FirstDayOfWeek.U_EXTENSION_OF_FIRST_DAY_OF_WEEK);
+ if (mu != null) {
+ return mu;
+ }
+ if (!resolved) {
+ return FirstDayOfWeek.DEFAULT;
+ }
+ // TODO(b/262294472) Use {@code android.icu.util.Calendar} instead of
+ // {@code java.util.Calendar}.
+ return getStringOfFirstDayOfWeek(
+ java.util.Calendar.getInstance(locale).getFirstDayOfWeek());
+ }
+
+ @DoNotInline
+ static Locale getDefaultLocale() {
+ return Locale.getDefault(Category.FORMAT);
+ }
+
+ private static String getStringOfFirstDayOfWeek(int fw) {
+ String[] arrDays = {
+ FirstDayOfWeek.SUNDAY,
+ FirstDayOfWeek.MONDAY,
+ FirstDayOfWeek.TUESDAY,
+ FirstDayOfWeek.WEDNESDAY,
+ FirstDayOfWeek.THURSDAY,
+ FirstDayOfWeek.FRIDAY,
+ FirstDayOfWeek.SATURDAY};
+
+ return fw >= 1 && fw <= 7 ? arrDays[fw - 1] : FirstDayOfWeek.DEFAULT;
+ }
+
+ @HourCycle.HourCycleTypes
+ private static String getHourCycleType(
+ DateFormat.HourCycle hourCycle) {
+ switch (hourCycle) {
+ case HOUR_CYCLE_11:
+ return HourCycle.H11;
+ case HOUR_CYCLE_12:
+ return HourCycle.H12;
+ case HOUR_CYCLE_23:
+ return HourCycle.H23;
+ case HOUR_CYCLE_24:
+ return HourCycle.H24;
+ default:
+ return HourCycle.DEFAULT;
+ }
+ }
+
+ @TemperatureUnit.TemperatureUnits
+ private static String getResolvedTemperatureUnit(@NonNull Locale locale) {
+ LocalizedNumberFormatter nf = NumberFormatter.with()
+ .usage("temperature")
+ .unit(MeasureUnit.CELSIUS)
+ .locale(locale);
+ return nf.format(1).getOutputUnit().getIdentifier();
+ }
+
+ private Api33Impl() {
+ }
+ }
+
+ private LocalePreferences() {
+ }
+}
diff --git a/core/core/src/main/java/androidx/core/util/TypedValueCompat.java b/core/core/src/main/java/androidx/core/util/TypedValueCompat.java
new file mode 100644
index 0000000..49f3bab
--- /dev/null
+++ b/core/core/src/main/java/androidx/core/util/TypedValueCompat.java
@@ -0,0 +1,176 @@
+/*
+ * Copyright 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.core.util;
+
+import static android.util.TypedValue.COMPLEX_UNIT_DIP;
+import static android.util.TypedValue.COMPLEX_UNIT_IN;
+import static android.util.TypedValue.COMPLEX_UNIT_MM;
+import static android.util.TypedValue.COMPLEX_UNIT_PT;
+import static android.util.TypedValue.COMPLEX_UNIT_PX;
+import static android.util.TypedValue.COMPLEX_UNIT_SP;
+
+import android.os.Build;
+import android.util.DisplayMetrics;
+import android.util.TypedValue;
+
+import androidx.annotation.DoNotInline;
+import androidx.annotation.NonNull;
+import androidx.annotation.RequiresApi;
+
+/**
+ * Container for a dynamically typed data value. Primarily used with
+ * {@link android.content.res.Resources} for holding resource values.
+ *
+ * <p>Used to convert between dimension values like DP and SP to pixels, and vice versa.
+ */
+public class TypedValueCompat {
+ private static final float INCHES_PER_PT = (1.0f / 72);
+ private static final float INCHES_PER_MM = (1.0f / 25.4f);
+
+ private TypedValueCompat() {}
+
+ /**
+ * Converts a pixel value to the given dimension, e.g. PX to DP.
+ *
+ * <p>This is the inverse of {@link TypedValue#applyDimension(int, float, DisplayMetrics)}
+ *
+ * @param unitToConvertTo The unit to convert to.
+ * @param pixelValue The raw pixels value to convert from.
+ * @param metrics Current display metrics to use in the conversion --
+ * supplies display density and scaling information.
+ *
+ * @return A dimension value equivalent to the given number of pixels
+ * @throws IllegalArgumentException if unitToConvertTo is not valid.
+ */
+ public static float deriveDimension(
+ int unitToConvertTo,
+ float pixelValue,
+ @NonNull DisplayMetrics metrics) {
+ if (Build.VERSION.SDK_INT >= 34) {
+ return Api34Impl.deriveDimension(unitToConvertTo, pixelValue, metrics);
+ }
+
+ switch (unitToConvertTo) {
+ case COMPLEX_UNIT_PX:
+ return pixelValue;
+ case COMPLEX_UNIT_DIP: {
+ // Avoid divide-by-zero, and return 0 since that's what the inverse function will do
+ if (metrics.density == 0) {
+ return 0;
+ }
+ return pixelValue / metrics.density;
+ }
+ case COMPLEX_UNIT_SP:
+ // Versions earlier than U don't get the fancy non-linear scaling
+ if (metrics.scaledDensity == 0) {
+ return 0;
+ }
+ return pixelValue / metrics.scaledDensity;
+ case COMPLEX_UNIT_PT: {
+ if (metrics.xdpi == 0) {
+ return 0;
+ }
+ return pixelValue / metrics.xdpi / INCHES_PER_PT;
+ }
+ case COMPLEX_UNIT_IN: {
+ if (metrics.xdpi == 0) {
+ return 0;
+ }
+ return pixelValue / metrics.xdpi;
+ }
+ case COMPLEX_UNIT_MM: {
+ if (metrics.xdpi == 0) {
+ return 0;
+ }
+ return pixelValue / metrics.xdpi / INCHES_PER_MM;
+ }
+ default:
+ throw new IllegalArgumentException("Invalid unitToConvertTo " + unitToConvertTo);
+ }
+ }
+
+ /**
+ * Converts a density-independent pixels (DP) value to pixels
+ *
+ * <p>This is a convenience function for
+ * {@link TypedValue#applyDimension(int, float, DisplayMetrics)}
+ *
+ * @param dpValue The value in DP to convert from.
+ * @param metrics Current display metrics to use in the conversion --
+ * supplies display density and scaling information.
+ *
+ * @return A raw pixel value
+ */
+ public static float dpToPx(float dpValue, @NonNull DisplayMetrics metrics) {
+ return TypedValue.applyDimension(COMPLEX_UNIT_DIP, dpValue, metrics);
+ }
+
+ /**
+ * Converts a pixel value to density-independent pixels (DP)
+ *
+ * <p>This is a convenience function for {@link #deriveDimension(int, float, DisplayMetrics)}
+ *
+ * @param pixelValue The raw pixels value to convert from.
+ * @param metrics Current display metrics to use in the conversion --
+ * supplies display density and scaling information.
+ *
+ * @return A dimension value (in DP) representing the given number of pixels.
+ */
+ public static float pxToDp(float pixelValue, @NonNull DisplayMetrics metrics) {
+ return deriveDimension(COMPLEX_UNIT_DIP, pixelValue, metrics);
+ }
+
+ /**
+ * Converts a scaled pixels (SP) value to pixels
+ *
+ * <p>This is a convenience function for
+ * {@link TypedValue#applyDimension(int, float, DisplayMetrics)}
+ *
+ * @param spValue The value in SP to convert from.
+ * @param metrics Current display metrics to use in the conversion --
+ * supplies display density and scaling information.
+ *
+ * @return A raw pixel value
+ */
+ public static float spToPx(float spValue, @NonNull DisplayMetrics metrics) {
+ return TypedValue.applyDimension(COMPLEX_UNIT_SP, spValue, metrics);
+ }
+
+ /**
+ * Converts a pixel value to scaled pixels (SP)
+ *
+ * <p>This is a convenience function for {@link #deriveDimension(int, float, DisplayMetrics)}
+ *
+ * @param pixelValue The raw pixels value to convert from.
+ * @param metrics Current display metrics to use in the conversion --
+ * supplies display density and scaling information.
+ *
+ * @return A dimension value (in SP) representing the given number of pixels.
+ */
+ public static float pxToSp(float pixelValue, @NonNull DisplayMetrics metrics) {
+ return deriveDimension(COMPLEX_UNIT_SP, pixelValue, metrics);
+ }
+
+ @RequiresApi(34)
+ private static class Api34Impl {
+ @DoNotInline
+ public static float deriveDimension(int unitToConvertTo, float pixelValue,
+ DisplayMetrics metrics) {
+ return TypedValue.deriveDimension(unitToConvertTo, pixelValue, metrics);
+ }
+ }
+}
diff --git a/core/core/src/main/java/androidx/core/view/VelocityTrackerCompat.java b/core/core/src/main/java/androidx/core/view/VelocityTrackerCompat.java
index a0d31d1..688e887f 100644
--- a/core/core/src/main/java/androidx/core/view/VelocityTrackerCompat.java
+++ b/core/core/src/main/java/androidx/core/view/VelocityTrackerCompat.java
@@ -16,18 +16,36 @@
package androidx.core.view;
+import static androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX;
+
+import static java.lang.annotation.RetentionPolicy.SOURCE;
+
+import android.os.Build;
+import android.view.MotionEvent;
import android.view.VelocityTracker;
-/**
- * Helper for accessing features in {@link VelocityTracker}.
- *
- * @deprecated Use {@link VelocityTracker} directly.
- */
-@Deprecated
+import androidx.annotation.DoNotInline;
+import androidx.annotation.IntDef;
+import androidx.annotation.NonNull;
+import androidx.annotation.RequiresApi;
+import androidx.annotation.RestrictTo;
+
+import java.lang.annotation.Retention;
+
+/** Helper for accessing features in {@link VelocityTracker}. */
public final class VelocityTrackerCompat {
+ /** @hide */
+ @RestrictTo(LIBRARY_GROUP_PREFIX)
+ @Retention(SOURCE)
+ @IntDef(value = {
+ MotionEvent.AXIS_X,
+ MotionEvent.AXIS_Y,
+ MotionEvent.AXIS_SCROLL
+ })
+ public @interface VelocityTrackableMotionEventAxis {}
/**
* Call {@link VelocityTracker#getXVelocity(int)}.
- * If running on a pre-{@link android.os.Build.VERSION_CODES#HONEYCOMB} device,
+ * If running on a pre-{@link Build.VERSION_CODES#HONEYCOMB} device,
* returns {@link VelocityTracker#getXVelocity()}.
*
* @deprecated Use {@link VelocityTracker#getXVelocity(int)} directly.
@@ -39,7 +57,7 @@
/**
* Call {@link VelocityTracker#getYVelocity(int)}.
- * If running on a pre-{@link android.os.Build.VERSION_CODES#HONEYCOMB} device,
+ * If running on a pre-{@link Build.VERSION_CODES#HONEYCOMB} device,
* returns {@link VelocityTracker#getYVelocity()}.
*
* @deprecated Use {@link VelocityTracker#getYVelocity(int)} directly.
@@ -49,5 +67,119 @@
return tracker.getYVelocity(pointerId);
}
+ /**
+ * Checks whether a given velocity-trackable {@link MotionEvent} axis is supported for velocity
+ * tracking by this {@link VelocityTracker} instance (refer to
+ * {@link #getAxisVelocity(VelocityTracker, int, int)} for a list of potentially
+ * velocity-trackable axes).
+ *
+ * <p>Note that the value returned from this method will stay the same for a given instance, so
+ * a single check for axis support is enough per a {@link VelocityTracker} instance.
+ *
+ * @param tracker The {@link VelocityTracker} for which to check axis support.
+ * @param axis The axis to check for velocity support.
+ * @return {@code true} if {@code axis} is supported for velocity tracking, or {@code false}
+ * otherwise.
+ * @see #getAxisVelocity(VelocityTracker, int, int)
+ * @see #getAxisVelocity(VelocityTracker, int)
+ */
+ public static boolean isAxisSupported(@NonNull VelocityTracker tracker,
+ @VelocityTrackableMotionEventAxis int axis) {
+ if (Build.VERSION.SDK_INT >= 34) {
+ return Api34Impl.isAxisSupported(tracker, axis);
+ }
+ return axis == MotionEvent.AXIS_X || axis == MotionEvent.AXIS_Y;
+ }
+
+ /**
+ * Equivalent to calling {@link #getAxisVelocity(VelocityTracker, int, int)} for {@code axis}
+ * and the active pointer.
+ *
+ * @param tracker The {@link VelocityTracker} from which to get axis velocity.
+ * @param axis Which axis' velocity to return.
+ * @return The previously computed velocity for {@code axis} for the active pointer if
+ * {@code axis} is supported for velocity tracking, or 0 if velocity tracking is not
+ * supported for the axis.
+ * @see #isAxisSupported(VelocityTracker, int)
+ * @see #getAxisVelocity(VelocityTracker, int, int)
+ */
+ public static float getAxisVelocity(@NonNull VelocityTracker tracker,
+ @VelocityTrackableMotionEventAxis int axis) {
+ if (Build.VERSION.SDK_INT >= 34) {
+ return Api34Impl.getAxisVelocity(tracker, axis);
+ }
+ if (axis == MotionEvent.AXIS_X) {
+ return tracker.getXVelocity();
+ }
+ if (axis == MotionEvent.AXIS_Y) {
+ return tracker.getYVelocity();
+ }
+ return 0;
+ }
+
+ /**
+ * Retrieve the last computed velocity for a given motion axis. You must first call
+ * {@link VelocityTracker#computeCurrentVelocity(int)} or
+ * {@link VelocityTracker#computeCurrentVelocity(int, float)} before calling this function.
+ *
+ * <p>In addition to {@link MotionEvent#AXIS_X} and {@link MotionEvent#AXIS_Y} which have been
+ * supported since the introduction of this class, the following axes can be candidates for this
+ * method:
+ * <ul>
+ * <li> {@link MotionEvent#AXIS_SCROLL}: supported starting
+ * {@link Build.VERSION_CODES#UPSIDE_DOWN_CAKE}
+ * </ul>
+ *
+ * <p>Before accessing velocities of an axis using this method, check that your
+ * {@link VelocityTracker} instance supports the axis by using
+ * {@link #isAxisSupported(VelocityTracker, int)}.
+ *
+ * @param tracker The {@link VelocityTracker} from which to get axis velocity.
+ * @param axis Which axis' velocity to return.
+ * @param pointerId Which pointer's velocity to return.
+ * @return The previously computed velocity for {@code axis} for pointer ID of {@code id} if
+ * {@code axis} is supported for velocity tracking, or 0 if velocity tracking is not
+ * supported for the axis.
+ * @see #isAxisSupported(VelocityTracker, int)
+ */
+ public static float getAxisVelocity(
+ @NonNull VelocityTracker tracker,
+ @VelocityTrackableMotionEventAxis int axis,
+ int pointerId) {
+ if (Build.VERSION.SDK_INT >= 34) {
+ return Api34Impl.getAxisVelocity(tracker, axis, pointerId);
+ }
+ if (axis == MotionEvent.AXIS_X) {
+ return tracker.getXVelocity(pointerId);
+ }
+ if (axis == MotionEvent.AXIS_Y) {
+ return tracker.getYVelocity(pointerId);
+ }
+ return 0;
+
+ }
+
+ @RequiresApi(34)
+ private static class Api34Impl {
+ private Api34Impl() {
+ // This class is not instantiable.
+ }
+
+ @DoNotInline
+ static boolean isAxisSupported(VelocityTracker velocityTracker, int axis) {
+ return velocityTracker.isAxisSupported(axis);
+ }
+
+ @DoNotInline
+ static float getAxisVelocity(VelocityTracker velocityTracker, int axis, int id) {
+ return velocityTracker.getAxisVelocity(axis, id);
+ }
+
+ @DoNotInline
+ static float getAxisVelocity(VelocityTracker velocityTracker, int axis) {
+ return velocityTracker.getAxisVelocity(axis);
+ }
+ }
+
private VelocityTrackerCompat() {}
}
diff --git a/core/core/src/main/java/androidx/core/view/accessibility/AccessibilityWindowInfoCompat.java b/core/core/src/main/java/androidx/core/view/accessibility/AccessibilityWindowInfoCompat.java
index 511d9b8..91586a5 100644
--- a/core/core/src/main/java/androidx/core/view/accessibility/AccessibilityWindowInfoCompat.java
+++ b/core/core/src/main/java/androidx/core/view/accessibility/AccessibilityWindowInfoCompat.java
@@ -87,6 +87,25 @@
return null;
}
+ /**
+ * Creates a new AccessibilityWindowInfoCompat.
+ * <p>
+ * Compatibility:
+ * <ul>
+ * <li>Api < 30: Will not wrap an
+ * {@link android.view.accessibility.AccessibilityWindowInfo} instance.</li>
+ * </ul>
+ * </p>
+ *
+ */
+ public AccessibilityWindowInfoCompat() {
+ if (SDK_INT >= 30) {
+ mInfo = Api30Impl.instantiateAccessibilityWindowInfo();
+ } else {
+ mInfo = null;
+ }
+ }
+
private AccessibilityWindowInfoCompat(Object info) {
mInfo = info;
}
@@ -541,6 +560,18 @@
}
}
+ @RequiresApi(30)
+ private static class Api30Impl {
+ private Api30Impl() {
+ // This class is non instantiable.
+ }
+
+ @DoNotInline
+ static AccessibilityWindowInfo instantiateAccessibilityWindowInfo() {
+ return new AccessibilityWindowInfo();
+ }
+ }
+
@RequiresApi(33)
private static class Api33Impl {
private Api33Impl() {
diff --git a/credentials/credentials/api/current.txt b/credentials/credentials/api/current.txt
index 423cdee..00689a8 100644
--- a/credentials/credentials/api/current.txt
+++ b/credentials/credentials/api/current.txt
@@ -448,3 +448,302 @@
}
+package androidx.credentials.provider {
+
+ @RequiresApi(34) public final class Action extends android.service.credentials.Action {
+ ctor public Action(CharSequence title, android.app.PendingIntent pendingIntent, optional CharSequence? subtitle);
+ method public android.app.PendingIntent getPendingIntent();
+ method public CharSequence? getSubtitle();
+ method public CharSequence getTitle();
+ property public final android.app.PendingIntent pendingIntent;
+ property public final CharSequence? subtitle;
+ property public final CharSequence title;
+ field public static final android.os.Parcelable.Creator<androidx.credentials.provider.Action> CREATOR;
+ field public static final androidx.credentials.provider.Action.Companion Companion;
+ }
+
+ public static final class Action.Builder {
+ ctor public Action.Builder(CharSequence title, android.app.PendingIntent pendingIntent);
+ method public androidx.credentials.provider.Action build();
+ method public androidx.credentials.provider.Action.Builder setSubtitle(CharSequence? subtitle);
+ }
+
+ public static final class Action.Companion {
+ }
+
+ @RequiresApi(34) public final class AuthenticationAction extends android.service.credentials.Action {
+ ctor public AuthenticationAction(android.app.PendingIntent pendingIntent);
+ method public android.app.PendingIntent getPendingIntent();
+ property public final android.app.PendingIntent pendingIntent;
+ field public static final android.os.Parcelable.Creator<androidx.credentials.provider.AuthenticationAction> CREATOR;
+ field public static final androidx.credentials.provider.AuthenticationAction.Companion Companion;
+ }
+
+ public static final class AuthenticationAction.Companion {
+ }
+
+ @RequiresApi(34) public final class BeginCreatePasswordCredentialRequest extends android.service.credentials.BeginCreateCredentialRequest {
+ field public static final android.os.Parcelable.Creator<androidx.credentials.provider.BeginCreatePasswordCredentialRequest> CREATOR;
+ field public static final androidx.credentials.provider.BeginCreatePasswordCredentialRequest.Companion Companion;
+ }
+
+ public static final class BeginCreatePasswordCredentialRequest.Companion {
+ }
+
+ @RequiresApi(34) public final class BeginCreatePublicKeyCredentialRequest extends android.service.credentials.BeginCreateCredentialRequest {
+ method public String getJson();
+ property public final String json;
+ field public static final android.os.Parcelable.Creator<androidx.credentials.provider.BeginCreatePublicKeyCredentialRequest> CREATOR;
+ field public static final androidx.credentials.provider.BeginCreatePublicKeyCredentialRequest.Companion Companion;
+ }
+
+ public static final class BeginCreatePublicKeyCredentialRequest.Companion {
+ }
+
+ @RequiresApi(34) public final class BeginCreatePublicKeyCredentialRequestPrivileged extends android.service.credentials.BeginCreateCredentialRequest {
+ method public String getClientDataHash();
+ method public String getJson();
+ method public String getRelyingParty();
+ property public final String clientDataHash;
+ property public final String json;
+ property public final String relyingParty;
+ field public static final android.os.Parcelable.Creator<androidx.credentials.provider.BeginCreatePublicKeyCredentialRequestPrivileged> CREATOR;
+ field public static final androidx.credentials.provider.BeginCreatePublicKeyCredentialRequestPrivileged.Companion Companion;
+ }
+
+ public static final class BeginCreatePublicKeyCredentialRequestPrivileged.Companion {
+ }
+
+ @RequiresApi(34) public final class BeginGetPasswordOption extends android.service.credentials.BeginGetCredentialOption {
+ field public static final android.os.Parcelable.Creator<androidx.credentials.provider.BeginGetPasswordOption> CREATOR;
+ field public static final androidx.credentials.provider.BeginGetPasswordOption.Companion Companion;
+ }
+
+ public static final class BeginGetPasswordOption.Companion {
+ }
+
+ @RequiresApi(34) public final class BeginGetPublicKeyCredentialOption extends android.service.credentials.BeginGetCredentialOption {
+ method public String getRequestJson();
+ property public final String requestJson;
+ field public static final android.os.Parcelable.Creator<androidx.credentials.provider.BeginGetPublicKeyCredentialOption> CREATOR;
+ field public static final androidx.credentials.provider.BeginGetPublicKeyCredentialOption.Companion Companion;
+ }
+
+ public static final class BeginGetPublicKeyCredentialOption.Companion {
+ }
+
+ @RequiresApi(34) public final class BeginGetPublicKeyCredentialOptionPrivileged extends android.service.credentials.BeginGetCredentialOption {
+ method public String getClientDataHash();
+ method public String getRelyingParty();
+ method public String getRequestJson();
+ property public final String clientDataHash;
+ property public final String relyingParty;
+ property public final String requestJson;
+ field public static final android.os.Parcelable.Creator<androidx.credentials.provider.BeginGetPublicKeyCredentialOptionPrivileged> CREATOR;
+ field public static final androidx.credentials.provider.BeginGetPublicKeyCredentialOptionPrivileged.Companion Companion;
+ }
+
+ public static final class BeginGetPublicKeyCredentialOptionPrivileged.Companion {
+ }
+
+ @RequiresApi(34) public final class CreateEntry extends android.service.credentials.CreateEntry {
+ ctor public CreateEntry(CharSequence accountName, android.app.PendingIntent pendingIntent, optional CharSequence? description, optional java.time.Instant? lastUsedTime, optional android.graphics.drawable.Icon? icon, optional Integer? passwordCredentialCount, optional Integer? publicKeyCredentialCount, optional Integer? totalCredentialCount);
+ method public CharSequence getAccountName();
+ method public CharSequence? getDescription();
+ method public android.graphics.drawable.Icon? getIcon();
+ method public java.time.Instant? getLastUsedTime();
+ method public Integer? getPasswordCredentialCount();
+ method public android.app.PendingIntent getPendingIntent();
+ method public Integer? getPublicKeyCredentialCount();
+ method public Integer? getTotalCredentialCount();
+ property public final CharSequence accountName;
+ property public final CharSequence? description;
+ property public final android.graphics.drawable.Icon? icon;
+ property public final java.time.Instant? lastUsedTime;
+ property public final android.app.PendingIntent pendingIntent;
+ field public static final android.os.Parcelable.Creator<androidx.credentials.provider.CreateEntry> CREATOR;
+ field public static final androidx.credentials.provider.CreateEntry.Companion Companion;
+ }
+
+ public static final class CreateEntry.Builder {
+ ctor public CreateEntry.Builder(CharSequence accountName, android.app.PendingIntent pendingIntent);
+ method public androidx.credentials.provider.CreateEntry build();
+ method public androidx.credentials.provider.CreateEntry.Builder setDescription(CharSequence? description);
+ method public androidx.credentials.provider.CreateEntry.Builder setIcon(android.graphics.drawable.Icon? icon);
+ method public androidx.credentials.provider.CreateEntry.Builder setLastUsedTime(java.time.Instant? lastUsedTime);
+ method public androidx.credentials.provider.CreateEntry.Builder setPasswordCredentialCount(int count);
+ method public androidx.credentials.provider.CreateEntry.Builder setPublicKeyCredentialCount(int count);
+ method public androidx.credentials.provider.CreateEntry.Builder setTotalCredentialCount(int count);
+ }
+
+ public static final class CreateEntry.Companion {
+ }
+
+ @RequiresApi(34) public abstract class CredentialProviderService extends android.service.credentials.CredentialProviderService {
+ ctor public CredentialProviderService();
+ method public final void onBeginCreateCredential(android.service.credentials.BeginCreateCredentialRequest request, android.os.CancellationSignal cancellationSignal, android.os.OutcomeReceiver<android.service.credentials.BeginCreateCredentialResponse,android.credentials.CreateCredentialException> callback);
+ method public abstract void onBeginCreateCredentialRequest(android.service.credentials.BeginCreateCredentialRequest request, android.os.CancellationSignal cancellationSignal, android.os.OutcomeReceiver<android.service.credentials.BeginCreateCredentialResponse,androidx.credentials.exceptions.CreateCredentialException> callback);
+ method public final void onBeginGetCredential(android.service.credentials.BeginGetCredentialRequest request, android.os.CancellationSignal cancellationSignal, android.os.OutcomeReceiver<android.service.credentials.BeginGetCredentialResponse,android.credentials.GetCredentialException> callback);
+ method public abstract void onBeginGetCredentialRequest(android.service.credentials.BeginGetCredentialRequest request, android.os.CancellationSignal cancellationSignal, android.os.OutcomeReceiver<android.service.credentials.BeginGetCredentialResponse,androidx.credentials.exceptions.GetCredentialException> callback);
+ method public final void onClearCredentialState(android.service.credentials.ClearCredentialStateRequest request, android.os.CancellationSignal cancellationSignal, android.os.OutcomeReceiver<java.lang.Void,android.credentials.ClearCredentialStateException> callback);
+ method public abstract void onClearCredentialStateRequest(android.service.credentials.ClearCredentialStateRequest request, android.os.CancellationSignal cancellationSignal, android.os.OutcomeReceiver<java.lang.Void,androidx.credentials.exceptions.ClearCredentialException> callback);
+ }
+
+ @RequiresApi(34) public final class CustomCredentialEntry extends android.service.credentials.CredentialEntry {
+ ctor public CustomCredentialEntry(android.content.Context context, CharSequence title, android.app.PendingIntent pendingIntent, android.service.credentials.BeginGetCredentialOption beginGetCredentialOption, optional CharSequence? subtitle, optional CharSequence? typeDisplayName, optional java.time.Instant? lastUsedTime, optional android.graphics.drawable.Icon? icon, optional boolean isAutoSelectAllowed);
+ method public android.graphics.drawable.Icon? getIcon();
+ method public java.time.Instant? getLastUsedTime();
+ method public android.app.PendingIntent getPendingIntent();
+ method public CharSequence? getSubtitle();
+ method public CharSequence getTitle();
+ method public CharSequence? getTypeDisplayName();
+ method public boolean isAutoSelectAllowed();
+ property public final android.graphics.drawable.Icon? icon;
+ property public final boolean isAutoSelectAllowed;
+ property public final java.time.Instant? lastUsedTime;
+ property public final android.app.PendingIntent pendingIntent;
+ property public final CharSequence? subtitle;
+ property public final CharSequence title;
+ property public final CharSequence? typeDisplayName;
+ field public static final android.os.Parcelable.Creator<androidx.credentials.provider.CustomCredentialEntry> CREATOR;
+ field public static final androidx.credentials.provider.CustomCredentialEntry.Companion Companion;
+ }
+
+ public static final class CustomCredentialEntry.Builder {
+ ctor public CustomCredentialEntry.Builder(android.content.Context context, String type, CharSequence title, android.app.PendingIntent pendingIntent, android.service.credentials.BeginGetCredentialOption beginGetCredentialOption);
+ method public androidx.credentials.provider.CustomCredentialEntry build();
+ method public androidx.credentials.provider.CustomCredentialEntry.Builder setAutoSelectAllowed(boolean autoSelectAllowed);
+ method public androidx.credentials.provider.CustomCredentialEntry.Builder setIcon(android.graphics.drawable.Icon? icon);
+ method public androidx.credentials.provider.CustomCredentialEntry.Builder setLastUsedTime(java.time.Instant? lastUsedTime);
+ method public androidx.credentials.provider.CustomCredentialEntry.Builder setSubtitle(CharSequence? subtitle);
+ method public androidx.credentials.provider.CustomCredentialEntry.Builder setTypeDisplayName(CharSequence? typeDisplayName);
+ }
+
+ @RequiresApi(34) public static final class CustomCredentialEntry.Companion {
+ }
+
+ @RequiresApi(34) public final class PasswordCredentialEntry extends android.service.credentials.CredentialEntry {
+ ctor public PasswordCredentialEntry(android.content.Context context, CharSequence username, android.app.PendingIntent pendingIntent, androidx.credentials.provider.BeginGetPasswordOption beginGetPasswordOption, optional CharSequence? displayName, optional java.time.Instant? lastUsedTime, optional android.graphics.drawable.Icon? icon);
+ method public CharSequence? getDisplayName();
+ method public android.graphics.drawable.Icon? getIcon();
+ method public java.time.Instant? getLastUsedTime();
+ method public android.app.PendingIntent getPendingIntent();
+ method public CharSequence getTypeDisplayName();
+ method public CharSequence getUsername();
+ method public boolean isAutoSelectAllowed();
+ property public final CharSequence? displayName;
+ property public final android.graphics.drawable.Icon? icon;
+ property public final boolean isAutoSelectAllowed;
+ property public final java.time.Instant? lastUsedTime;
+ property public final android.app.PendingIntent pendingIntent;
+ property public final CharSequence typeDisplayName;
+ property public final CharSequence username;
+ field public static final androidx.credentials.provider.PasswordCredentialEntry.CREATOR CREATOR;
+ field public static final android.os.Parcelable.Creator<androidx.credentials.provider.PasswordCredentialEntry> CREATOR$1;
+ }
+
+ public static final class PasswordCredentialEntry.Builder {
+ ctor public PasswordCredentialEntry.Builder(android.content.Context context, CharSequence username, android.app.PendingIntent pendingIntent, androidx.credentials.provider.BeginGetPasswordOption beginGetPasswordOption);
+ method public androidx.credentials.provider.PasswordCredentialEntry build();
+ method public androidx.credentials.provider.PasswordCredentialEntry.Builder setDisplayName(CharSequence? displayName);
+ method public androidx.credentials.provider.PasswordCredentialEntry.Builder setIcon(android.graphics.drawable.Icon? icon);
+ method public androidx.credentials.provider.PasswordCredentialEntry.Builder setLastUsedTime(java.time.Instant? lastUsedTime);
+ }
+
+ public static final class PasswordCredentialEntry.CREATOR {
+ }
+
+ @RequiresApi(34) public final class PendingIntentHandler {
+ ctor public PendingIntentHandler();
+ method public static android.service.credentials.BeginGetCredentialRequest? retrieveBeginGetCredentialRequest(android.content.Intent intent);
+ method public static androidx.credentials.provider.ProviderCreateCredentialRequest? retrieveProviderCreateCredentialRequest(android.content.Intent intent);
+ method public static androidx.credentials.provider.ProviderGetCredentialRequest? retrieveProviderGetCredentialRequest(android.content.Intent intent);
+ method public static void setBeginGetCredentialResponse(android.content.Intent intent, android.service.credentials.BeginGetCredentialResponse response);
+ method public static void setCreateCredentialException(android.content.Intent intent, androidx.credentials.exceptions.CreateCredentialException exception);
+ method public static void setCreateCredentialResponse(android.content.Intent intent, androidx.credentials.CreateCredentialResponse response);
+ method public static void setGetCredentialException(android.content.Intent intent, androidx.credentials.exceptions.GetCredentialException exception);
+ method public static void setGetCredentialResponse(android.content.Intent intent, androidx.credentials.GetCredentialResponse response);
+ field public static final androidx.credentials.provider.PendingIntentHandler.Companion Companion;
+ }
+
+ public static final class PendingIntentHandler.Companion {
+ method public android.service.credentials.BeginGetCredentialRequest? retrieveBeginGetCredentialRequest(android.content.Intent intent);
+ method public androidx.credentials.provider.ProviderCreateCredentialRequest? retrieveProviderCreateCredentialRequest(android.content.Intent intent);
+ method public androidx.credentials.provider.ProviderGetCredentialRequest? retrieveProviderGetCredentialRequest(android.content.Intent intent);
+ method public void setBeginGetCredentialResponse(android.content.Intent intent, android.service.credentials.BeginGetCredentialResponse response);
+ method public void setCreateCredentialException(android.content.Intent intent, androidx.credentials.exceptions.CreateCredentialException exception);
+ method public void setCreateCredentialResponse(android.content.Intent intent, androidx.credentials.CreateCredentialResponse response);
+ method public void setGetCredentialException(android.content.Intent intent, androidx.credentials.exceptions.GetCredentialException exception);
+ method public void setGetCredentialResponse(android.content.Intent intent, androidx.credentials.GetCredentialResponse response);
+ }
+
+ @RequiresApi(34) public final class ProviderCreateCredentialRequest {
+ method public android.service.credentials.CallingAppInfo getCallingAppInfo();
+ method public androidx.credentials.CreateCredentialRequest getCallingRequest();
+ property public final android.service.credentials.CallingAppInfo callingAppInfo;
+ property public final androidx.credentials.CreateCredentialRequest callingRequest;
+ }
+
+ @RequiresApi(34) public final class ProviderGetCredentialRequest {
+ method public android.service.credentials.CallingAppInfo getCallingAppInfo();
+ method public androidx.credentials.CredentialOption getCredentialOption();
+ property public final android.service.credentials.CallingAppInfo callingAppInfo;
+ property public final androidx.credentials.CredentialOption credentialOption;
+ }
+
+ @RequiresApi(34) public final class PublicKeyCredentialEntry extends android.service.credentials.CredentialEntry {
+ ctor public PublicKeyCredentialEntry(android.content.Context context, CharSequence username, android.app.PendingIntent pendingIntent, androidx.credentials.provider.BeginGetPublicKeyCredentialOption beginGetPublicKeyCredentialOption, optional CharSequence? displayName, optional java.time.Instant? lastUsedTime, optional android.graphics.drawable.Icon? icon, optional boolean isAutoSelectAllowed);
+ method public CharSequence? getDisplayName();
+ method public android.graphics.drawable.Icon? getIcon();
+ method public java.time.Instant? getLastUsedTime();
+ method public android.app.PendingIntent getPendingIntent();
+ method public CharSequence getTypeDisplayName();
+ method public CharSequence getUsername();
+ method public boolean isAutoSelectAllowed();
+ property public final CharSequence? displayName;
+ property public final android.graphics.drawable.Icon? icon;
+ property public final boolean isAutoSelectAllowed;
+ property public final java.time.Instant? lastUsedTime;
+ property public final android.app.PendingIntent pendingIntent;
+ property public final CharSequence typeDisplayName;
+ property public final CharSequence username;
+ field public static final androidx.credentials.provider.PublicKeyCredentialEntry.CREATOR CREATOR;
+ field public static final android.os.Parcelable.Creator<androidx.credentials.provider.PublicKeyCredentialEntry> CREATOR$1;
+ }
+
+ public static final class PublicKeyCredentialEntry.Builder {
+ ctor public PublicKeyCredentialEntry.Builder(android.content.Context context, CharSequence username, android.app.PendingIntent pendingIntent, androidx.credentials.provider.BeginGetPublicKeyCredentialOption beginGetPublicKeyCredentialOption);
+ method public androidx.credentials.provider.PublicKeyCredentialEntry build();
+ method public androidx.credentials.provider.PublicKeyCredentialEntry.Builder setAutoSelectAllowed(boolean autoSelectAllowed);
+ method public androidx.credentials.provider.PublicKeyCredentialEntry.Builder setDisplayName(CharSequence? displayName);
+ method public androidx.credentials.provider.PublicKeyCredentialEntry.Builder setIcon(android.graphics.drawable.Icon? icon);
+ method public androidx.credentials.provider.PublicKeyCredentialEntry.Builder setLastUsedTime(java.time.Instant? lastUsedTime);
+ }
+
+ public static final class PublicKeyCredentialEntry.CREATOR {
+ }
+
+ @RequiresApi(34) public final class RemoteCreateEntry extends android.service.credentials.CreateEntry {
+ ctor public RemoteCreateEntry(android.app.PendingIntent pendingIntent);
+ method public android.app.PendingIntent getPendingIntent();
+ property public final android.app.PendingIntent pendingIntent;
+ field public static final android.os.Parcelable.Creator<androidx.credentials.provider.RemoteCreateEntry> CREATOR;
+ field public static final androidx.credentials.provider.RemoteCreateEntry.Companion Companion;
+ }
+
+ public static final class RemoteCreateEntry.Companion {
+ }
+
+ @RequiresApi(34) public final class RemoteCredentialEntry extends android.service.credentials.CredentialEntry {
+ ctor public RemoteCredentialEntry(android.app.PendingIntent pendingIntent, androidx.credentials.provider.BeginGetPublicKeyCredentialOption beginGetPublicKeyCredentialOption);
+ method public android.app.PendingIntent getPendingIntent();
+ property public final android.app.PendingIntent pendingIntent;
+ field public static final androidx.credentials.provider.RemoteCredentialEntry.CREATOR CREATOR;
+ field public static final android.os.Parcelable.Creator<androidx.credentials.provider.RemoteCredentialEntry> CREATOR$1;
+ }
+
+ public static final class RemoteCredentialEntry.CREATOR {
+ }
+
+}
+
diff --git a/credentials/credentials/api/public_plus_experimental_current.txt b/credentials/credentials/api/public_plus_experimental_current.txt
index 423cdee..00689a8 100644
--- a/credentials/credentials/api/public_plus_experimental_current.txt
+++ b/credentials/credentials/api/public_plus_experimental_current.txt
@@ -448,3 +448,302 @@
}
+package androidx.credentials.provider {
+
+ @RequiresApi(34) public final class Action extends android.service.credentials.Action {
+ ctor public Action(CharSequence title, android.app.PendingIntent pendingIntent, optional CharSequence? subtitle);
+ method public android.app.PendingIntent getPendingIntent();
+ method public CharSequence? getSubtitle();
+ method public CharSequence getTitle();
+ property public final android.app.PendingIntent pendingIntent;
+ property public final CharSequence? subtitle;
+ property public final CharSequence title;
+ field public static final android.os.Parcelable.Creator<androidx.credentials.provider.Action> CREATOR;
+ field public static final androidx.credentials.provider.Action.Companion Companion;
+ }
+
+ public static final class Action.Builder {
+ ctor public Action.Builder(CharSequence title, android.app.PendingIntent pendingIntent);
+ method public androidx.credentials.provider.Action build();
+ method public androidx.credentials.provider.Action.Builder setSubtitle(CharSequence? subtitle);
+ }
+
+ public static final class Action.Companion {
+ }
+
+ @RequiresApi(34) public final class AuthenticationAction extends android.service.credentials.Action {
+ ctor public AuthenticationAction(android.app.PendingIntent pendingIntent);
+ method public android.app.PendingIntent getPendingIntent();
+ property public final android.app.PendingIntent pendingIntent;
+ field public static final android.os.Parcelable.Creator<androidx.credentials.provider.AuthenticationAction> CREATOR;
+ field public static final androidx.credentials.provider.AuthenticationAction.Companion Companion;
+ }
+
+ public static final class AuthenticationAction.Companion {
+ }
+
+ @RequiresApi(34) public final class BeginCreatePasswordCredentialRequest extends android.service.credentials.BeginCreateCredentialRequest {
+ field public static final android.os.Parcelable.Creator<androidx.credentials.provider.BeginCreatePasswordCredentialRequest> CREATOR;
+ field public static final androidx.credentials.provider.BeginCreatePasswordCredentialRequest.Companion Companion;
+ }
+
+ public static final class BeginCreatePasswordCredentialRequest.Companion {
+ }
+
+ @RequiresApi(34) public final class BeginCreatePublicKeyCredentialRequest extends android.service.credentials.BeginCreateCredentialRequest {
+ method public String getJson();
+ property public final String json;
+ field public static final android.os.Parcelable.Creator<androidx.credentials.provider.BeginCreatePublicKeyCredentialRequest> CREATOR;
+ field public static final androidx.credentials.provider.BeginCreatePublicKeyCredentialRequest.Companion Companion;
+ }
+
+ public static final class BeginCreatePublicKeyCredentialRequest.Companion {
+ }
+
+ @RequiresApi(34) public final class BeginCreatePublicKeyCredentialRequestPrivileged extends android.service.credentials.BeginCreateCredentialRequest {
+ method public String getClientDataHash();
+ method public String getJson();
+ method public String getRelyingParty();
+ property public final String clientDataHash;
+ property public final String json;
+ property public final String relyingParty;
+ field public static final android.os.Parcelable.Creator<androidx.credentials.provider.BeginCreatePublicKeyCredentialRequestPrivileged> CREATOR;
+ field public static final androidx.credentials.provider.BeginCreatePublicKeyCredentialRequestPrivileged.Companion Companion;
+ }
+
+ public static final class BeginCreatePublicKeyCredentialRequestPrivileged.Companion {
+ }
+
+ @RequiresApi(34) public final class BeginGetPasswordOption extends android.service.credentials.BeginGetCredentialOption {
+ field public static final android.os.Parcelable.Creator<androidx.credentials.provider.BeginGetPasswordOption> CREATOR;
+ field public static final androidx.credentials.provider.BeginGetPasswordOption.Companion Companion;
+ }
+
+ public static final class BeginGetPasswordOption.Companion {
+ }
+
+ @RequiresApi(34) public final class BeginGetPublicKeyCredentialOption extends android.service.credentials.BeginGetCredentialOption {
+ method public String getRequestJson();
+ property public final String requestJson;
+ field public static final android.os.Parcelable.Creator<androidx.credentials.provider.BeginGetPublicKeyCredentialOption> CREATOR;
+ field public static final androidx.credentials.provider.BeginGetPublicKeyCredentialOption.Companion Companion;
+ }
+
+ public static final class BeginGetPublicKeyCredentialOption.Companion {
+ }
+
+ @RequiresApi(34) public final class BeginGetPublicKeyCredentialOptionPrivileged extends android.service.credentials.BeginGetCredentialOption {
+ method public String getClientDataHash();
+ method public String getRelyingParty();
+ method public String getRequestJson();
+ property public final String clientDataHash;
+ property public final String relyingParty;
+ property public final String requestJson;
+ field public static final android.os.Parcelable.Creator<androidx.credentials.provider.BeginGetPublicKeyCredentialOptionPrivileged> CREATOR;
+ field public static final androidx.credentials.provider.BeginGetPublicKeyCredentialOptionPrivileged.Companion Companion;
+ }
+
+ public static final class BeginGetPublicKeyCredentialOptionPrivileged.Companion {
+ }
+
+ @RequiresApi(34) public final class CreateEntry extends android.service.credentials.CreateEntry {
+ ctor public CreateEntry(CharSequence accountName, android.app.PendingIntent pendingIntent, optional CharSequence? description, optional java.time.Instant? lastUsedTime, optional android.graphics.drawable.Icon? icon, optional Integer? passwordCredentialCount, optional Integer? publicKeyCredentialCount, optional Integer? totalCredentialCount);
+ method public CharSequence getAccountName();
+ method public CharSequence? getDescription();
+ method public android.graphics.drawable.Icon? getIcon();
+ method public java.time.Instant? getLastUsedTime();
+ method public Integer? getPasswordCredentialCount();
+ method public android.app.PendingIntent getPendingIntent();
+ method public Integer? getPublicKeyCredentialCount();
+ method public Integer? getTotalCredentialCount();
+ property public final CharSequence accountName;
+ property public final CharSequence? description;
+ property public final android.graphics.drawable.Icon? icon;
+ property public final java.time.Instant? lastUsedTime;
+ property public final android.app.PendingIntent pendingIntent;
+ field public static final android.os.Parcelable.Creator<androidx.credentials.provider.CreateEntry> CREATOR;
+ field public static final androidx.credentials.provider.CreateEntry.Companion Companion;
+ }
+
+ public static final class CreateEntry.Builder {
+ ctor public CreateEntry.Builder(CharSequence accountName, android.app.PendingIntent pendingIntent);
+ method public androidx.credentials.provider.CreateEntry build();
+ method public androidx.credentials.provider.CreateEntry.Builder setDescription(CharSequence? description);
+ method public androidx.credentials.provider.CreateEntry.Builder setIcon(android.graphics.drawable.Icon? icon);
+ method public androidx.credentials.provider.CreateEntry.Builder setLastUsedTime(java.time.Instant? lastUsedTime);
+ method public androidx.credentials.provider.CreateEntry.Builder setPasswordCredentialCount(int count);
+ method public androidx.credentials.provider.CreateEntry.Builder setPublicKeyCredentialCount(int count);
+ method public androidx.credentials.provider.CreateEntry.Builder setTotalCredentialCount(int count);
+ }
+
+ public static final class CreateEntry.Companion {
+ }
+
+ @RequiresApi(34) public abstract class CredentialProviderService extends android.service.credentials.CredentialProviderService {
+ ctor public CredentialProviderService();
+ method public final void onBeginCreateCredential(android.service.credentials.BeginCreateCredentialRequest request, android.os.CancellationSignal cancellationSignal, android.os.OutcomeReceiver<android.service.credentials.BeginCreateCredentialResponse,android.credentials.CreateCredentialException> callback);
+ method public abstract void onBeginCreateCredentialRequest(android.service.credentials.BeginCreateCredentialRequest request, android.os.CancellationSignal cancellationSignal, android.os.OutcomeReceiver<android.service.credentials.BeginCreateCredentialResponse,androidx.credentials.exceptions.CreateCredentialException> callback);
+ method public final void onBeginGetCredential(android.service.credentials.BeginGetCredentialRequest request, android.os.CancellationSignal cancellationSignal, android.os.OutcomeReceiver<android.service.credentials.BeginGetCredentialResponse,android.credentials.GetCredentialException> callback);
+ method public abstract void onBeginGetCredentialRequest(android.service.credentials.BeginGetCredentialRequest request, android.os.CancellationSignal cancellationSignal, android.os.OutcomeReceiver<android.service.credentials.BeginGetCredentialResponse,androidx.credentials.exceptions.GetCredentialException> callback);
+ method public final void onClearCredentialState(android.service.credentials.ClearCredentialStateRequest request, android.os.CancellationSignal cancellationSignal, android.os.OutcomeReceiver<java.lang.Void,android.credentials.ClearCredentialStateException> callback);
+ method public abstract void onClearCredentialStateRequest(android.service.credentials.ClearCredentialStateRequest request, android.os.CancellationSignal cancellationSignal, android.os.OutcomeReceiver<java.lang.Void,androidx.credentials.exceptions.ClearCredentialException> callback);
+ }
+
+ @RequiresApi(34) public final class CustomCredentialEntry extends android.service.credentials.CredentialEntry {
+ ctor public CustomCredentialEntry(android.content.Context context, CharSequence title, android.app.PendingIntent pendingIntent, android.service.credentials.BeginGetCredentialOption beginGetCredentialOption, optional CharSequence? subtitle, optional CharSequence? typeDisplayName, optional java.time.Instant? lastUsedTime, optional android.graphics.drawable.Icon? icon, optional boolean isAutoSelectAllowed);
+ method public android.graphics.drawable.Icon? getIcon();
+ method public java.time.Instant? getLastUsedTime();
+ method public android.app.PendingIntent getPendingIntent();
+ method public CharSequence? getSubtitle();
+ method public CharSequence getTitle();
+ method public CharSequence? getTypeDisplayName();
+ method public boolean isAutoSelectAllowed();
+ property public final android.graphics.drawable.Icon? icon;
+ property public final boolean isAutoSelectAllowed;
+ property public final java.time.Instant? lastUsedTime;
+ property public final android.app.PendingIntent pendingIntent;
+ property public final CharSequence? subtitle;
+ property public final CharSequence title;
+ property public final CharSequence? typeDisplayName;
+ field public static final android.os.Parcelable.Creator<androidx.credentials.provider.CustomCredentialEntry> CREATOR;
+ field public static final androidx.credentials.provider.CustomCredentialEntry.Companion Companion;
+ }
+
+ public static final class CustomCredentialEntry.Builder {
+ ctor public CustomCredentialEntry.Builder(android.content.Context context, String type, CharSequence title, android.app.PendingIntent pendingIntent, android.service.credentials.BeginGetCredentialOption beginGetCredentialOption);
+ method public androidx.credentials.provider.CustomCredentialEntry build();
+ method public androidx.credentials.provider.CustomCredentialEntry.Builder setAutoSelectAllowed(boolean autoSelectAllowed);
+ method public androidx.credentials.provider.CustomCredentialEntry.Builder setIcon(android.graphics.drawable.Icon? icon);
+ method public androidx.credentials.provider.CustomCredentialEntry.Builder setLastUsedTime(java.time.Instant? lastUsedTime);
+ method public androidx.credentials.provider.CustomCredentialEntry.Builder setSubtitle(CharSequence? subtitle);
+ method public androidx.credentials.provider.CustomCredentialEntry.Builder setTypeDisplayName(CharSequence? typeDisplayName);
+ }
+
+ @RequiresApi(34) public static final class CustomCredentialEntry.Companion {
+ }
+
+ @RequiresApi(34) public final class PasswordCredentialEntry extends android.service.credentials.CredentialEntry {
+ ctor public PasswordCredentialEntry(android.content.Context context, CharSequence username, android.app.PendingIntent pendingIntent, androidx.credentials.provider.BeginGetPasswordOption beginGetPasswordOption, optional CharSequence? displayName, optional java.time.Instant? lastUsedTime, optional android.graphics.drawable.Icon? icon);
+ method public CharSequence? getDisplayName();
+ method public android.graphics.drawable.Icon? getIcon();
+ method public java.time.Instant? getLastUsedTime();
+ method public android.app.PendingIntent getPendingIntent();
+ method public CharSequence getTypeDisplayName();
+ method public CharSequence getUsername();
+ method public boolean isAutoSelectAllowed();
+ property public final CharSequence? displayName;
+ property public final android.graphics.drawable.Icon? icon;
+ property public final boolean isAutoSelectAllowed;
+ property public final java.time.Instant? lastUsedTime;
+ property public final android.app.PendingIntent pendingIntent;
+ property public final CharSequence typeDisplayName;
+ property public final CharSequence username;
+ field public static final androidx.credentials.provider.PasswordCredentialEntry.CREATOR CREATOR;
+ field public static final android.os.Parcelable.Creator<androidx.credentials.provider.PasswordCredentialEntry> CREATOR$1;
+ }
+
+ public static final class PasswordCredentialEntry.Builder {
+ ctor public PasswordCredentialEntry.Builder(android.content.Context context, CharSequence username, android.app.PendingIntent pendingIntent, androidx.credentials.provider.BeginGetPasswordOption beginGetPasswordOption);
+ method public androidx.credentials.provider.PasswordCredentialEntry build();
+ method public androidx.credentials.provider.PasswordCredentialEntry.Builder setDisplayName(CharSequence? displayName);
+ method public androidx.credentials.provider.PasswordCredentialEntry.Builder setIcon(android.graphics.drawable.Icon? icon);
+ method public androidx.credentials.provider.PasswordCredentialEntry.Builder setLastUsedTime(java.time.Instant? lastUsedTime);
+ }
+
+ public static final class PasswordCredentialEntry.CREATOR {
+ }
+
+ @RequiresApi(34) public final class PendingIntentHandler {
+ ctor public PendingIntentHandler();
+ method public static android.service.credentials.BeginGetCredentialRequest? retrieveBeginGetCredentialRequest(android.content.Intent intent);
+ method public static androidx.credentials.provider.ProviderCreateCredentialRequest? retrieveProviderCreateCredentialRequest(android.content.Intent intent);
+ method public static androidx.credentials.provider.ProviderGetCredentialRequest? retrieveProviderGetCredentialRequest(android.content.Intent intent);
+ method public static void setBeginGetCredentialResponse(android.content.Intent intent, android.service.credentials.BeginGetCredentialResponse response);
+ method public static void setCreateCredentialException(android.content.Intent intent, androidx.credentials.exceptions.CreateCredentialException exception);
+ method public static void setCreateCredentialResponse(android.content.Intent intent, androidx.credentials.CreateCredentialResponse response);
+ method public static void setGetCredentialException(android.content.Intent intent, androidx.credentials.exceptions.GetCredentialException exception);
+ method public static void setGetCredentialResponse(android.content.Intent intent, androidx.credentials.GetCredentialResponse response);
+ field public static final androidx.credentials.provider.PendingIntentHandler.Companion Companion;
+ }
+
+ public static final class PendingIntentHandler.Companion {
+ method public android.service.credentials.BeginGetCredentialRequest? retrieveBeginGetCredentialRequest(android.content.Intent intent);
+ method public androidx.credentials.provider.ProviderCreateCredentialRequest? retrieveProviderCreateCredentialRequest(android.content.Intent intent);
+ method public androidx.credentials.provider.ProviderGetCredentialRequest? retrieveProviderGetCredentialRequest(android.content.Intent intent);
+ method public void setBeginGetCredentialResponse(android.content.Intent intent, android.service.credentials.BeginGetCredentialResponse response);
+ method public void setCreateCredentialException(android.content.Intent intent, androidx.credentials.exceptions.CreateCredentialException exception);
+ method public void setCreateCredentialResponse(android.content.Intent intent, androidx.credentials.CreateCredentialResponse response);
+ method public void setGetCredentialException(android.content.Intent intent, androidx.credentials.exceptions.GetCredentialException exception);
+ method public void setGetCredentialResponse(android.content.Intent intent, androidx.credentials.GetCredentialResponse response);
+ }
+
+ @RequiresApi(34) public final class ProviderCreateCredentialRequest {
+ method public android.service.credentials.CallingAppInfo getCallingAppInfo();
+ method public androidx.credentials.CreateCredentialRequest getCallingRequest();
+ property public final android.service.credentials.CallingAppInfo callingAppInfo;
+ property public final androidx.credentials.CreateCredentialRequest callingRequest;
+ }
+
+ @RequiresApi(34) public final class ProviderGetCredentialRequest {
+ method public android.service.credentials.CallingAppInfo getCallingAppInfo();
+ method public androidx.credentials.CredentialOption getCredentialOption();
+ property public final android.service.credentials.CallingAppInfo callingAppInfo;
+ property public final androidx.credentials.CredentialOption credentialOption;
+ }
+
+ @RequiresApi(34) public final class PublicKeyCredentialEntry extends android.service.credentials.CredentialEntry {
+ ctor public PublicKeyCredentialEntry(android.content.Context context, CharSequence username, android.app.PendingIntent pendingIntent, androidx.credentials.provider.BeginGetPublicKeyCredentialOption beginGetPublicKeyCredentialOption, optional CharSequence? displayName, optional java.time.Instant? lastUsedTime, optional android.graphics.drawable.Icon? icon, optional boolean isAutoSelectAllowed);
+ method public CharSequence? getDisplayName();
+ method public android.graphics.drawable.Icon? getIcon();
+ method public java.time.Instant? getLastUsedTime();
+ method public android.app.PendingIntent getPendingIntent();
+ method public CharSequence getTypeDisplayName();
+ method public CharSequence getUsername();
+ method public boolean isAutoSelectAllowed();
+ property public final CharSequence? displayName;
+ property public final android.graphics.drawable.Icon? icon;
+ property public final boolean isAutoSelectAllowed;
+ property public final java.time.Instant? lastUsedTime;
+ property public final android.app.PendingIntent pendingIntent;
+ property public final CharSequence typeDisplayName;
+ property public final CharSequence username;
+ field public static final androidx.credentials.provider.PublicKeyCredentialEntry.CREATOR CREATOR;
+ field public static final android.os.Parcelable.Creator<androidx.credentials.provider.PublicKeyCredentialEntry> CREATOR$1;
+ }
+
+ public static final class PublicKeyCredentialEntry.Builder {
+ ctor public PublicKeyCredentialEntry.Builder(android.content.Context context, CharSequence username, android.app.PendingIntent pendingIntent, androidx.credentials.provider.BeginGetPublicKeyCredentialOption beginGetPublicKeyCredentialOption);
+ method public androidx.credentials.provider.PublicKeyCredentialEntry build();
+ method public androidx.credentials.provider.PublicKeyCredentialEntry.Builder setAutoSelectAllowed(boolean autoSelectAllowed);
+ method public androidx.credentials.provider.PublicKeyCredentialEntry.Builder setDisplayName(CharSequence? displayName);
+ method public androidx.credentials.provider.PublicKeyCredentialEntry.Builder setIcon(android.graphics.drawable.Icon? icon);
+ method public androidx.credentials.provider.PublicKeyCredentialEntry.Builder setLastUsedTime(java.time.Instant? lastUsedTime);
+ }
+
+ public static final class PublicKeyCredentialEntry.CREATOR {
+ }
+
+ @RequiresApi(34) public final class RemoteCreateEntry extends android.service.credentials.CreateEntry {
+ ctor public RemoteCreateEntry(android.app.PendingIntent pendingIntent);
+ method public android.app.PendingIntent getPendingIntent();
+ property public final android.app.PendingIntent pendingIntent;
+ field public static final android.os.Parcelable.Creator<androidx.credentials.provider.RemoteCreateEntry> CREATOR;
+ field public static final androidx.credentials.provider.RemoteCreateEntry.Companion Companion;
+ }
+
+ public static final class RemoteCreateEntry.Companion {
+ }
+
+ @RequiresApi(34) public final class RemoteCredentialEntry extends android.service.credentials.CredentialEntry {
+ ctor public RemoteCredentialEntry(android.app.PendingIntent pendingIntent, androidx.credentials.provider.BeginGetPublicKeyCredentialOption beginGetPublicKeyCredentialOption);
+ method public android.app.PendingIntent getPendingIntent();
+ property public final android.app.PendingIntent pendingIntent;
+ field public static final androidx.credentials.provider.RemoteCredentialEntry.CREATOR CREATOR;
+ field public static final android.os.Parcelable.Creator<androidx.credentials.provider.RemoteCredentialEntry> CREATOR$1;
+ }
+
+ public static final class RemoteCredentialEntry.CREATOR {
+ }
+
+}
+
diff --git a/credentials/credentials/api/restricted_current.txt b/credentials/credentials/api/restricted_current.txt
index 423cdee..00689a8 100644
--- a/credentials/credentials/api/restricted_current.txt
+++ b/credentials/credentials/api/restricted_current.txt
@@ -448,3 +448,302 @@
}
+package androidx.credentials.provider {
+
+ @RequiresApi(34) public final class Action extends android.service.credentials.Action {
+ ctor public Action(CharSequence title, android.app.PendingIntent pendingIntent, optional CharSequence? subtitle);
+ method public android.app.PendingIntent getPendingIntent();
+ method public CharSequence? getSubtitle();
+ method public CharSequence getTitle();
+ property public final android.app.PendingIntent pendingIntent;
+ property public final CharSequence? subtitle;
+ property public final CharSequence title;
+ field public static final android.os.Parcelable.Creator<androidx.credentials.provider.Action> CREATOR;
+ field public static final androidx.credentials.provider.Action.Companion Companion;
+ }
+
+ public static final class Action.Builder {
+ ctor public Action.Builder(CharSequence title, android.app.PendingIntent pendingIntent);
+ method public androidx.credentials.provider.Action build();
+ method public androidx.credentials.provider.Action.Builder setSubtitle(CharSequence? subtitle);
+ }
+
+ public static final class Action.Companion {
+ }
+
+ @RequiresApi(34) public final class AuthenticationAction extends android.service.credentials.Action {
+ ctor public AuthenticationAction(android.app.PendingIntent pendingIntent);
+ method public android.app.PendingIntent getPendingIntent();
+ property public final android.app.PendingIntent pendingIntent;
+ field public static final android.os.Parcelable.Creator<androidx.credentials.provider.AuthenticationAction> CREATOR;
+ field public static final androidx.credentials.provider.AuthenticationAction.Companion Companion;
+ }
+
+ public static final class AuthenticationAction.Companion {
+ }
+
+ @RequiresApi(34) public final class BeginCreatePasswordCredentialRequest extends android.service.credentials.BeginCreateCredentialRequest {
+ field public static final android.os.Parcelable.Creator<androidx.credentials.provider.BeginCreatePasswordCredentialRequest> CREATOR;
+ field public static final androidx.credentials.provider.BeginCreatePasswordCredentialRequest.Companion Companion;
+ }
+
+ public static final class BeginCreatePasswordCredentialRequest.Companion {
+ }
+
+ @RequiresApi(34) public final class BeginCreatePublicKeyCredentialRequest extends android.service.credentials.BeginCreateCredentialRequest {
+ method public String getJson();
+ property public final String json;
+ field public static final android.os.Parcelable.Creator<androidx.credentials.provider.BeginCreatePublicKeyCredentialRequest> CREATOR;
+ field public static final androidx.credentials.provider.BeginCreatePublicKeyCredentialRequest.Companion Companion;
+ }
+
+ public static final class BeginCreatePublicKeyCredentialRequest.Companion {
+ }
+
+ @RequiresApi(34) public final class BeginCreatePublicKeyCredentialRequestPrivileged extends android.service.credentials.BeginCreateCredentialRequest {
+ method public String getClientDataHash();
+ method public String getJson();
+ method public String getRelyingParty();
+ property public final String clientDataHash;
+ property public final String json;
+ property public final String relyingParty;
+ field public static final android.os.Parcelable.Creator<androidx.credentials.provider.BeginCreatePublicKeyCredentialRequestPrivileged> CREATOR;
+ field public static final androidx.credentials.provider.BeginCreatePublicKeyCredentialRequestPrivileged.Companion Companion;
+ }
+
+ public static final class BeginCreatePublicKeyCredentialRequestPrivileged.Companion {
+ }
+
+ @RequiresApi(34) public final class BeginGetPasswordOption extends android.service.credentials.BeginGetCredentialOption {
+ field public static final android.os.Parcelable.Creator<androidx.credentials.provider.BeginGetPasswordOption> CREATOR;
+ field public static final androidx.credentials.provider.BeginGetPasswordOption.Companion Companion;
+ }
+
+ public static final class BeginGetPasswordOption.Companion {
+ }
+
+ @RequiresApi(34) public final class BeginGetPublicKeyCredentialOption extends android.service.credentials.BeginGetCredentialOption {
+ method public String getRequestJson();
+ property public final String requestJson;
+ field public static final android.os.Parcelable.Creator<androidx.credentials.provider.BeginGetPublicKeyCredentialOption> CREATOR;
+ field public static final androidx.credentials.provider.BeginGetPublicKeyCredentialOption.Companion Companion;
+ }
+
+ public static final class BeginGetPublicKeyCredentialOption.Companion {
+ }
+
+ @RequiresApi(34) public final class BeginGetPublicKeyCredentialOptionPrivileged extends android.service.credentials.BeginGetCredentialOption {
+ method public String getClientDataHash();
+ method public String getRelyingParty();
+ method public String getRequestJson();
+ property public final String clientDataHash;
+ property public final String relyingParty;
+ property public final String requestJson;
+ field public static final android.os.Parcelable.Creator<androidx.credentials.provider.BeginGetPublicKeyCredentialOptionPrivileged> CREATOR;
+ field public static final androidx.credentials.provider.BeginGetPublicKeyCredentialOptionPrivileged.Companion Companion;
+ }
+
+ public static final class BeginGetPublicKeyCredentialOptionPrivileged.Companion {
+ }
+
+ @RequiresApi(34) public final class CreateEntry extends android.service.credentials.CreateEntry {
+ ctor public CreateEntry(CharSequence accountName, android.app.PendingIntent pendingIntent, optional CharSequence? description, optional java.time.Instant? lastUsedTime, optional android.graphics.drawable.Icon? icon, optional Integer? passwordCredentialCount, optional Integer? publicKeyCredentialCount, optional Integer? totalCredentialCount);
+ method public CharSequence getAccountName();
+ method public CharSequence? getDescription();
+ method public android.graphics.drawable.Icon? getIcon();
+ method public java.time.Instant? getLastUsedTime();
+ method public Integer? getPasswordCredentialCount();
+ method public android.app.PendingIntent getPendingIntent();
+ method public Integer? getPublicKeyCredentialCount();
+ method public Integer? getTotalCredentialCount();
+ property public final CharSequence accountName;
+ property public final CharSequence? description;
+ property public final android.graphics.drawable.Icon? icon;
+ property public final java.time.Instant? lastUsedTime;
+ property public final android.app.PendingIntent pendingIntent;
+ field public static final android.os.Parcelable.Creator<androidx.credentials.provider.CreateEntry> CREATOR;
+ field public static final androidx.credentials.provider.CreateEntry.Companion Companion;
+ }
+
+ public static final class CreateEntry.Builder {
+ ctor public CreateEntry.Builder(CharSequence accountName, android.app.PendingIntent pendingIntent);
+ method public androidx.credentials.provider.CreateEntry build();
+ method public androidx.credentials.provider.CreateEntry.Builder setDescription(CharSequence? description);
+ method public androidx.credentials.provider.CreateEntry.Builder setIcon(android.graphics.drawable.Icon? icon);
+ method public androidx.credentials.provider.CreateEntry.Builder setLastUsedTime(java.time.Instant? lastUsedTime);
+ method public androidx.credentials.provider.CreateEntry.Builder setPasswordCredentialCount(int count);
+ method public androidx.credentials.provider.CreateEntry.Builder setPublicKeyCredentialCount(int count);
+ method public androidx.credentials.provider.CreateEntry.Builder setTotalCredentialCount(int count);
+ }
+
+ public static final class CreateEntry.Companion {
+ }
+
+ @RequiresApi(34) public abstract class CredentialProviderService extends android.service.credentials.CredentialProviderService {
+ ctor public CredentialProviderService();
+ method public final void onBeginCreateCredential(android.service.credentials.BeginCreateCredentialRequest request, android.os.CancellationSignal cancellationSignal, android.os.OutcomeReceiver<android.service.credentials.BeginCreateCredentialResponse,android.credentials.CreateCredentialException> callback);
+ method public abstract void onBeginCreateCredentialRequest(android.service.credentials.BeginCreateCredentialRequest request, android.os.CancellationSignal cancellationSignal, android.os.OutcomeReceiver<android.service.credentials.BeginCreateCredentialResponse,androidx.credentials.exceptions.CreateCredentialException> callback);
+ method public final void onBeginGetCredential(android.service.credentials.BeginGetCredentialRequest request, android.os.CancellationSignal cancellationSignal, android.os.OutcomeReceiver<android.service.credentials.BeginGetCredentialResponse,android.credentials.GetCredentialException> callback);
+ method public abstract void onBeginGetCredentialRequest(android.service.credentials.BeginGetCredentialRequest request, android.os.CancellationSignal cancellationSignal, android.os.OutcomeReceiver<android.service.credentials.BeginGetCredentialResponse,androidx.credentials.exceptions.GetCredentialException> callback);
+ method public final void onClearCredentialState(android.service.credentials.ClearCredentialStateRequest request, android.os.CancellationSignal cancellationSignal, android.os.OutcomeReceiver<java.lang.Void,android.credentials.ClearCredentialStateException> callback);
+ method public abstract void onClearCredentialStateRequest(android.service.credentials.ClearCredentialStateRequest request, android.os.CancellationSignal cancellationSignal, android.os.OutcomeReceiver<java.lang.Void,androidx.credentials.exceptions.ClearCredentialException> callback);
+ }
+
+ @RequiresApi(34) public final class CustomCredentialEntry extends android.service.credentials.CredentialEntry {
+ ctor public CustomCredentialEntry(android.content.Context context, CharSequence title, android.app.PendingIntent pendingIntent, android.service.credentials.BeginGetCredentialOption beginGetCredentialOption, optional CharSequence? subtitle, optional CharSequence? typeDisplayName, optional java.time.Instant? lastUsedTime, optional android.graphics.drawable.Icon? icon, optional boolean isAutoSelectAllowed);
+ method public android.graphics.drawable.Icon? getIcon();
+ method public java.time.Instant? getLastUsedTime();
+ method public android.app.PendingIntent getPendingIntent();
+ method public CharSequence? getSubtitle();
+ method public CharSequence getTitle();
+ method public CharSequence? getTypeDisplayName();
+ method public boolean isAutoSelectAllowed();
+ property public final android.graphics.drawable.Icon? icon;
+ property public final boolean isAutoSelectAllowed;
+ property public final java.time.Instant? lastUsedTime;
+ property public final android.app.PendingIntent pendingIntent;
+ property public final CharSequence? subtitle;
+ property public final CharSequence title;
+ property public final CharSequence? typeDisplayName;
+ field public static final android.os.Parcelable.Creator<androidx.credentials.provider.CustomCredentialEntry> CREATOR;
+ field public static final androidx.credentials.provider.CustomCredentialEntry.Companion Companion;
+ }
+
+ public static final class CustomCredentialEntry.Builder {
+ ctor public CustomCredentialEntry.Builder(android.content.Context context, String type, CharSequence title, android.app.PendingIntent pendingIntent, android.service.credentials.BeginGetCredentialOption beginGetCredentialOption);
+ method public androidx.credentials.provider.CustomCredentialEntry build();
+ method public androidx.credentials.provider.CustomCredentialEntry.Builder setAutoSelectAllowed(boolean autoSelectAllowed);
+ method public androidx.credentials.provider.CustomCredentialEntry.Builder setIcon(android.graphics.drawable.Icon? icon);
+ method public androidx.credentials.provider.CustomCredentialEntry.Builder setLastUsedTime(java.time.Instant? lastUsedTime);
+ method public androidx.credentials.provider.CustomCredentialEntry.Builder setSubtitle(CharSequence? subtitle);
+ method public androidx.credentials.provider.CustomCredentialEntry.Builder setTypeDisplayName(CharSequence? typeDisplayName);
+ }
+
+ @RequiresApi(34) public static final class CustomCredentialEntry.Companion {
+ }
+
+ @RequiresApi(34) public final class PasswordCredentialEntry extends android.service.credentials.CredentialEntry {
+ ctor public PasswordCredentialEntry(android.content.Context context, CharSequence username, android.app.PendingIntent pendingIntent, androidx.credentials.provider.BeginGetPasswordOption beginGetPasswordOption, optional CharSequence? displayName, optional java.time.Instant? lastUsedTime, optional android.graphics.drawable.Icon? icon);
+ method public CharSequence? getDisplayName();
+ method public android.graphics.drawable.Icon? getIcon();
+ method public java.time.Instant? getLastUsedTime();
+ method public android.app.PendingIntent getPendingIntent();
+ method public CharSequence getTypeDisplayName();
+ method public CharSequence getUsername();
+ method public boolean isAutoSelectAllowed();
+ property public final CharSequence? displayName;
+ property public final android.graphics.drawable.Icon? icon;
+ property public final boolean isAutoSelectAllowed;
+ property public final java.time.Instant? lastUsedTime;
+ property public final android.app.PendingIntent pendingIntent;
+ property public final CharSequence typeDisplayName;
+ property public final CharSequence username;
+ field public static final androidx.credentials.provider.PasswordCredentialEntry.CREATOR CREATOR;
+ field public static final android.os.Parcelable.Creator<androidx.credentials.provider.PasswordCredentialEntry> CREATOR$1;
+ }
+
+ public static final class PasswordCredentialEntry.Builder {
+ ctor public PasswordCredentialEntry.Builder(android.content.Context context, CharSequence username, android.app.PendingIntent pendingIntent, androidx.credentials.provider.BeginGetPasswordOption beginGetPasswordOption);
+ method public androidx.credentials.provider.PasswordCredentialEntry build();
+ method public androidx.credentials.provider.PasswordCredentialEntry.Builder setDisplayName(CharSequence? displayName);
+ method public androidx.credentials.provider.PasswordCredentialEntry.Builder setIcon(android.graphics.drawable.Icon? icon);
+ method public androidx.credentials.provider.PasswordCredentialEntry.Builder setLastUsedTime(java.time.Instant? lastUsedTime);
+ }
+
+ public static final class PasswordCredentialEntry.CREATOR {
+ }
+
+ @RequiresApi(34) public final class PendingIntentHandler {
+ ctor public PendingIntentHandler();
+ method public static android.service.credentials.BeginGetCredentialRequest? retrieveBeginGetCredentialRequest(android.content.Intent intent);
+ method public static androidx.credentials.provider.ProviderCreateCredentialRequest? retrieveProviderCreateCredentialRequest(android.content.Intent intent);
+ method public static androidx.credentials.provider.ProviderGetCredentialRequest? retrieveProviderGetCredentialRequest(android.content.Intent intent);
+ method public static void setBeginGetCredentialResponse(android.content.Intent intent, android.service.credentials.BeginGetCredentialResponse response);
+ method public static void setCreateCredentialException(android.content.Intent intent, androidx.credentials.exceptions.CreateCredentialException exception);
+ method public static void setCreateCredentialResponse(android.content.Intent intent, androidx.credentials.CreateCredentialResponse response);
+ method public static void setGetCredentialException(android.content.Intent intent, androidx.credentials.exceptions.GetCredentialException exception);
+ method public static void setGetCredentialResponse(android.content.Intent intent, androidx.credentials.GetCredentialResponse response);
+ field public static final androidx.credentials.provider.PendingIntentHandler.Companion Companion;
+ }
+
+ public static final class PendingIntentHandler.Companion {
+ method public android.service.credentials.BeginGetCredentialRequest? retrieveBeginGetCredentialRequest(android.content.Intent intent);
+ method public androidx.credentials.provider.ProviderCreateCredentialRequest? retrieveProviderCreateCredentialRequest(android.content.Intent intent);
+ method public androidx.credentials.provider.ProviderGetCredentialRequest? retrieveProviderGetCredentialRequest(android.content.Intent intent);
+ method public void setBeginGetCredentialResponse(android.content.Intent intent, android.service.credentials.BeginGetCredentialResponse response);
+ method public void setCreateCredentialException(android.content.Intent intent, androidx.credentials.exceptions.CreateCredentialException exception);
+ method public void setCreateCredentialResponse(android.content.Intent intent, androidx.credentials.CreateCredentialResponse response);
+ method public void setGetCredentialException(android.content.Intent intent, androidx.credentials.exceptions.GetCredentialException exception);
+ method public void setGetCredentialResponse(android.content.Intent intent, androidx.credentials.GetCredentialResponse response);
+ }
+
+ @RequiresApi(34) public final class ProviderCreateCredentialRequest {
+ method public android.service.credentials.CallingAppInfo getCallingAppInfo();
+ method public androidx.credentials.CreateCredentialRequest getCallingRequest();
+ property public final android.service.credentials.CallingAppInfo callingAppInfo;
+ property public final androidx.credentials.CreateCredentialRequest callingRequest;
+ }
+
+ @RequiresApi(34) public final class ProviderGetCredentialRequest {
+ method public android.service.credentials.CallingAppInfo getCallingAppInfo();
+ method public androidx.credentials.CredentialOption getCredentialOption();
+ property public final android.service.credentials.CallingAppInfo callingAppInfo;
+ property public final androidx.credentials.CredentialOption credentialOption;
+ }
+
+ @RequiresApi(34) public final class PublicKeyCredentialEntry extends android.service.credentials.CredentialEntry {
+ ctor public PublicKeyCredentialEntry(android.content.Context context, CharSequence username, android.app.PendingIntent pendingIntent, androidx.credentials.provider.BeginGetPublicKeyCredentialOption beginGetPublicKeyCredentialOption, optional CharSequence? displayName, optional java.time.Instant? lastUsedTime, optional android.graphics.drawable.Icon? icon, optional boolean isAutoSelectAllowed);
+ method public CharSequence? getDisplayName();
+ method public android.graphics.drawable.Icon? getIcon();
+ method public java.time.Instant? getLastUsedTime();
+ method public android.app.PendingIntent getPendingIntent();
+ method public CharSequence getTypeDisplayName();
+ method public CharSequence getUsername();
+ method public boolean isAutoSelectAllowed();
+ property public final CharSequence? displayName;
+ property public final android.graphics.drawable.Icon? icon;
+ property public final boolean isAutoSelectAllowed;
+ property public final java.time.Instant? lastUsedTime;
+ property public final android.app.PendingIntent pendingIntent;
+ property public final CharSequence typeDisplayName;
+ property public final CharSequence username;
+ field public static final androidx.credentials.provider.PublicKeyCredentialEntry.CREATOR CREATOR;
+ field public static final android.os.Parcelable.Creator<androidx.credentials.provider.PublicKeyCredentialEntry> CREATOR$1;
+ }
+
+ public static final class PublicKeyCredentialEntry.Builder {
+ ctor public PublicKeyCredentialEntry.Builder(android.content.Context context, CharSequence username, android.app.PendingIntent pendingIntent, androidx.credentials.provider.BeginGetPublicKeyCredentialOption beginGetPublicKeyCredentialOption);
+ method public androidx.credentials.provider.PublicKeyCredentialEntry build();
+ method public androidx.credentials.provider.PublicKeyCredentialEntry.Builder setAutoSelectAllowed(boolean autoSelectAllowed);
+ method public androidx.credentials.provider.PublicKeyCredentialEntry.Builder setDisplayName(CharSequence? displayName);
+ method public androidx.credentials.provider.PublicKeyCredentialEntry.Builder setIcon(android.graphics.drawable.Icon? icon);
+ method public androidx.credentials.provider.PublicKeyCredentialEntry.Builder setLastUsedTime(java.time.Instant? lastUsedTime);
+ }
+
+ public static final class PublicKeyCredentialEntry.CREATOR {
+ }
+
+ @RequiresApi(34) public final class RemoteCreateEntry extends android.service.credentials.CreateEntry {
+ ctor public RemoteCreateEntry(android.app.PendingIntent pendingIntent);
+ method public android.app.PendingIntent getPendingIntent();
+ property public final android.app.PendingIntent pendingIntent;
+ field public static final android.os.Parcelable.Creator<androidx.credentials.provider.RemoteCreateEntry> CREATOR;
+ field public static final androidx.credentials.provider.RemoteCreateEntry.Companion Companion;
+ }
+
+ public static final class RemoteCreateEntry.Companion {
+ }
+
+ @RequiresApi(34) public final class RemoteCredentialEntry extends android.service.credentials.CredentialEntry {
+ ctor public RemoteCredentialEntry(android.app.PendingIntent pendingIntent, androidx.credentials.provider.BeginGetPublicKeyCredentialOption beginGetPublicKeyCredentialOption);
+ method public android.app.PendingIntent getPendingIntent();
+ property public final android.app.PendingIntent pendingIntent;
+ field public static final androidx.credentials.provider.RemoteCredentialEntry.CREATOR CREATOR;
+ field public static final android.os.Parcelable.Creator<androidx.credentials.provider.RemoteCredentialEntry> CREATOR$1;
+ }
+
+ public static final class RemoteCredentialEntry.CREATOR {
+ }
+
+}
+
diff --git a/credentials/credentials/build.gradle b/credentials/credentials/build.gradle
index 0c8c3fb..b8262a0 100644
--- a/credentials/credentials/build.gradle
+++ b/credentials/credentials/build.gradle
@@ -26,6 +26,7 @@
api("androidx.annotation:annotation:1.5.0")
api(libs.kotlinStdlib)
implementation(libs.kotlinCoroutinesCore)
+ implementation("androidx.core:core:1.8.0")
androidTestImplementation("androidx.activity:activity:1.2.0")
androidTestImplementation(libs.junit)
diff --git a/credentials/credentials/src/androidTest/java/androidx/credentials/CredentialManagerJavaTest.java b/credentials/credentials/src/androidTest/java/androidx/credentials/CredentialManagerJavaTest.java
index 85246a1..794c953 100644
--- a/credentials/credentials/src/androidTest/java/androidx/credentials/CredentialManagerJavaTest.java
+++ b/credentials/credentials/src/androidTest/java/androidx/credentials/CredentialManagerJavaTest.java
@@ -29,8 +29,10 @@
import androidx.credentials.exceptions.ClearCredentialProviderConfigurationException;
import androidx.credentials.exceptions.CreateCredentialException;
import androidx.credentials.exceptions.CreateCredentialProviderConfigurationException;
+import androidx.credentials.exceptions.CreateCredentialUnknownException;
import androidx.credentials.exceptions.GetCredentialException;
import androidx.credentials.exceptions.GetCredentialProviderConfigurationException;
+import androidx.credentials.exceptions.GetCredentialUnknownException;
import androidx.test.core.app.ActivityScenario;
import androidx.test.ext.junit.runners.AndroidJUnit4;
import androidx.test.filters.SmallTest;
@@ -86,8 +88,13 @@
});
latch.await(100L, TimeUnit.MILLISECONDS);
- assertThat(loadedResult.get().getClass()).isEqualTo(
- CreateCredentialProviderConfigurationException.class);
+ if (!isPostFrameworkApiLevel()) {
+ assertThat(loadedResult.get().getClass()).isEqualTo(
+ CreateCredentialProviderConfigurationException.class);
+ } else {
+ assertThat(loadedResult.get().getClass()).isEqualTo(
+ CreateCredentialUnknownException.class);
+ }
// TODO("Add manifest tests and possibly further separate these tests by API Level
// - maybe a rule perhaps?")
}
@@ -121,8 +128,13 @@
});
latch.await(100L, TimeUnit.MILLISECONDS);
- assertThat(loadedResult.get().getClass()).isEqualTo(
- GetCredentialProviderConfigurationException.class);
+ if (!isPostFrameworkApiLevel()) {
+ assertThat(loadedResult.get().getClass()).isEqualTo(
+ GetCredentialProviderConfigurationException.class);
+ } else {
+ assertThat(loadedResult.get().getClass()).isEqualTo(
+ GetCredentialUnknownException.class);
+ }
// TODO("Add manifest tests and possibly further separate these tests - maybe a rule
// perhaps?")
}
diff --git a/credentials/credentials/src/androidTest/java/androidx/credentials/CredentialManagerTest.kt b/credentials/credentials/src/androidTest/java/androidx/credentials/CredentialManagerTest.kt
index 162d6df..a27ae72 100644
--- a/credentials/credentials/src/androidTest/java/androidx/credentials/CredentialManagerTest.kt
+++ b/credentials/credentials/src/androidTest/java/androidx/credentials/CredentialManagerTest.kt
@@ -22,8 +22,10 @@
import androidx.credentials.exceptions.ClearCredentialProviderConfigurationException
import androidx.credentials.exceptions.CreateCredentialException
import androidx.credentials.exceptions.CreateCredentialProviderConfigurationException
+import androidx.credentials.exceptions.CreateCredentialUnknownException
import androidx.credentials.exceptions.GetCredentialException
import androidx.credentials.exceptions.GetCredentialProviderConfigurationException
+import androidx.credentials.exceptions.GetCredentialUnknownException
import androidx.test.core.app.ActivityScenario
import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
@@ -81,6 +83,10 @@
assertThrows<GetCredentialProviderConfigurationException> {
credentialManager.getCredential(request, Activity())
}
+ } else {
+ assertThrows<GetCredentialUnknownException> {
+ credentialManager.getCredential(request, Activity())
+ }
}
// TODO("Add manifest tests and possibly further separate these tests by API Level
// - maybe a rule perhaps?")
@@ -132,6 +138,10 @@
assertThat(loadedResult.get().javaClass).isEqualTo(
CreateCredentialProviderConfigurationException::class.java
)
+ } else {
+ assertThat(loadedResult.get().javaClass).isEqualTo(
+ CreateCredentialUnknownException::class.java
+ )
}
// TODO("Add manifest tests and possibly further separate these tests by API Level
// - maybe a rule perhaps?")
@@ -167,6 +177,10 @@
assertThat(loadedResult.get().javaClass).isEqualTo(
GetCredentialProviderConfigurationException::class.java
)
+ } else {
+ assertThat(loadedResult.get().javaClass).isEqualTo(
+ GetCredentialUnknownException::class.java
+ )
}
// TODO("Add manifest tests and possibly further separate these tests - maybe a rule
// perhaps?")
diff --git a/credentials/credentials/src/main/java/androidx/credentials/CredentialProviderFactory.kt b/credentials/credentials/src/main/java/androidx/credentials/CredentialProviderFactory.kt
index 6dcd0f2..1622a63 100644
--- a/credentials/credentials/src/main/java/androidx/credentials/CredentialProviderFactory.kt
+++ b/credentials/credentials/src/main/java/androidx/credentials/CredentialProviderFactory.kt
@@ -20,6 +20,8 @@
import android.content.pm.PackageManager
import android.os.Build
import android.util.Log
+import androidx.annotation.OptIn
+import androidx.core.os.BuildCompat
/**
* Factory that returns the credential provider to be used by Credential Manager.
@@ -41,12 +43,14 @@
* the app. Developer must not add more than one provider library.
* Post-U, providers will be registered with the framework, and enabled by the user.
*/
+ @OptIn(markerClass = [BuildCompat.PrereleaseSdkCheck::class])
fun getBestAvailableProvider(context: Context): CredentialProvider? {
- if (Build.VERSION.SDK_INT <= MAX_CRED_MAN_PRE_FRAMEWORK_API_LEVEL) {
+ if (BuildCompat.isAtLeastU()) {
+ return CredentialProviderFrameworkImpl(context)
+ } else if (Build.VERSION.SDK_INT <= MAX_CRED_MAN_PRE_FRAMEWORK_API_LEVEL) {
return tryCreatePreUOemProvider(context)
} else {
- // TODO("Implement")
- throw UnsupportedOperationException("Post-U not supported yet")
+ return null
}
}
diff --git a/credentials/credentials/src/main/java/androidx/credentials/CredentialProviderFrameworkImpl.kt b/credentials/credentials/src/main/java/androidx/credentials/CredentialProviderFrameworkImpl.kt
new file mode 100644
index 0000000..c32a19e
--- /dev/null
+++ b/credentials/credentials/src/main/java/androidx/credentials/CredentialProviderFrameworkImpl.kt
@@ -0,0 +1,241 @@
+/*
+ * Copyright 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.credentials
+
+import android.app.Activity
+import android.content.Context
+import android.credentials.CredentialManager
+import android.os.Bundle
+import android.os.CancellationSignal
+import android.os.OutcomeReceiver
+import android.util.Log
+import androidx.annotation.RequiresApi
+import androidx.credentials.exceptions.ClearCredentialException
+import androidx.credentials.exceptions.ClearCredentialUnknownException
+import androidx.credentials.exceptions.CreateCredentialCancellationException
+import androidx.credentials.exceptions.CreateCredentialException
+import androidx.credentials.exceptions.CreateCredentialInterruptedException
+import androidx.credentials.exceptions.CreateCredentialUnknownException
+import androidx.credentials.exceptions.GetCredentialCancellationException
+import androidx.credentials.exceptions.GetCredentialException
+import androidx.credentials.exceptions.GetCredentialInterruptedException
+import androidx.credentials.exceptions.GetCredentialUnknownException
+import androidx.credentials.exceptions.NoCredentialException
+import androidx.credentials.internal.FrameworkImplHelper
+import java.util.concurrent.Executor
+import java.util.concurrent.Executors
+
+/**
+ * Framework credential provider implementation that allows credential
+ * manager requests to be routed to the framework.
+ *
+ * @hide
+ */
+@RequiresApi(34)
+class CredentialProviderFrameworkImpl(context: Context) : CredentialProvider {
+ private val credentialManager: CredentialManager? =
+ context.getSystemService(Context.CREDENTIAL_SERVICE) as CredentialManager?
+
+ override fun onGetCredential(
+ request: GetCredentialRequest,
+ activity: Activity,
+ cancellationSignal: CancellationSignal?,
+ executor: Executor,
+ callback: CredentialManagerCallback<GetCredentialResponse, GetCredentialException>
+ ) {
+ Log.i(TAG, "In CredentialProviderFrameworkImpl onGetCredential")
+ if (isCredmanDisabled { -> callback.onError(GetCredentialUnknownException(
+ "Your device doesn't support credential manager")) }) return
+
+ val outcome = object : OutcomeReceiver<
+ android.credentials.GetCredentialResponse, android.credentials.GetCredentialException> {
+ override fun onResult(response: android.credentials.GetCredentialResponse) {
+ Log.i(TAG, "GetCredentialResponse returned from framework")
+ callback.onResult(convertGetResponseToJetpackClass(response))
+ }
+
+ override fun onError(error: android.credentials.GetCredentialException) {
+ Log.i(TAG, "GetCredentialResponse error returned from framework")
+ callback.onError(convertToJetpackGetException(error))
+ }
+ }
+
+ credentialManager!!.getCredential(
+ convertGetRequestToFrameworkClass(request),
+ activity,
+ cancellationSignal,
+ Executors.newSingleThreadExecutor(),
+ outcome
+ )
+ }
+
+ private fun isCredmanDisabled(handleNullCredMan: () -> Unit): Boolean {
+ if (credentialManager == null) {
+ handleNullCredMan()
+ return true
+ }
+ return false
+ }
+
+ override fun onCreateCredential(
+ request: CreateCredentialRequest,
+ activity: Activity,
+ cancellationSignal: CancellationSignal?,
+ executor: Executor,
+ callback: CredentialManagerCallback<CreateCredentialResponse, CreateCredentialException>
+ ) {
+ Log.i(TAG, "In CredentialProviderFrameworkImpl onCreateCredential")
+ if (isCredmanDisabled { -> callback.onError(CreateCredentialUnknownException(
+ "Your device doesn't support credential manager")) }) return
+ val outcome = object : OutcomeReceiver<
+ android.credentials.CreateCredentialResponse,
+ android.credentials.CreateCredentialException> {
+ override fun onResult(response: android.credentials.CreateCredentialResponse) {
+ Log.i(TAG, "Create Result returned from framework: ")
+ callback.onResult(
+ CreateCredentialResponse.createFrom(
+ request.type, response.data
+ )
+ )
+ }
+
+ override fun onError(error: android.credentials.CreateCredentialException) {
+ Log.i(TAG, "CreateCredentialResponse error returned from framework")
+ callback.onError(convertToJetpackCreateException(error))
+ }
+ }
+
+ credentialManager!!.createCredential(
+ android.credentials.CreateCredentialRequest(
+ request.type,
+ FrameworkImplHelper.getFinalCreateCredentialData(request, activity),
+ request.candidateQueryData,
+ request.isSystemProviderRequired
+ ),
+ activity,
+ cancellationSignal,
+ Executors.newSingleThreadExecutor(),
+ outcome
+ )
+ }
+
+ private fun convertGetRequestToFrameworkClass(request: GetCredentialRequest):
+ android.credentials.GetCredentialRequest {
+ val builder = android.credentials.GetCredentialRequest.Builder(Bundle())
+ request.credentialOptions.forEach {
+ builder.addCredentialOption(
+ android.credentials.CredentialOption(
+ it.type, it.requestData, it.candidateQueryData, it.isSystemProviderRequired
+ )
+ )
+ }
+ return builder.build()
+ }
+
+ private fun createFrameworkClearCredentialRequest():
+ android.credentials.ClearCredentialStateRequest {
+ return android.credentials.ClearCredentialStateRequest(Bundle())
+ }
+ internal fun convertToJetpackGetException(error: android.credentials.GetCredentialException):
+ GetCredentialException {
+ return when (error.type) {
+ // TODO ("Change to NoCred exception when ready")
+ android.credentials.GetCredentialException.TYPE_NO_CREDENTIAL ->
+ NoCredentialException(error.message)
+
+ android.credentials.GetCredentialException.TYPE_USER_CANCELED ->
+ GetCredentialCancellationException(error.message)
+
+ android.credentials.GetCredentialException.TYPE_INTERRUPTED ->
+ GetCredentialInterruptedException(error.message)
+
+ else -> GetCredentialUnknownException(error.message)
+ }
+ }
+
+ internal fun convertToJetpackCreateException(
+ error: android.credentials.CreateCredentialException
+ ): CreateCredentialException {
+ return when (error.type) {
+ // TODO ("Change to NoCred exception when ready")
+ android.credentials.CreateCredentialException.TYPE_NO_CREATE_OPTIONS ->
+ CreateCredentialUnknownException(error.message)
+
+ android.credentials.CreateCredentialException.TYPE_USER_CANCELED ->
+ CreateCredentialCancellationException(error.message)
+
+ android.credentials.CreateCredentialException.TYPE_INTERRUPTED ->
+ CreateCredentialInterruptedException(error.message)
+
+ else -> CreateCredentialUnknownException(error.message)
+ }
+ }
+
+ internal fun convertGetResponseToJetpackClass(
+ response: android.credentials.GetCredentialResponse
+ ): GetCredentialResponse {
+ val credential = response.credential
+ return GetCredentialResponse(
+ Credential.createFrom(
+ credential.type, credential.data
+ )
+ )
+ }
+
+ override fun isAvailableOnDevice(): Boolean {
+ // TODO("Base it on API level check")
+ return true
+ }
+
+ override fun onClearCredential(
+ request: ClearCredentialStateRequest,
+ cancellationSignal: CancellationSignal?,
+ executor: Executor,
+ callback: CredentialManagerCallback<Void?, ClearCredentialException>
+ ) {
+ Log.i(TAG, "In CredentialProviderFrameworkImpl onClearCredential")
+
+ if (isCredmanDisabled { -> callback.onError(ClearCredentialUnknownException(
+ "Your device doesn't support credential manager")) }) return
+
+ val outcome = object : OutcomeReceiver<Void,
+ android.credentials.ClearCredentialStateException> {
+ override fun onResult(response: Void) {
+ Log.i(TAG, "Clear result returned from framework: ")
+ callback.onResult(response)
+ }
+
+ override fun onError(error: android.credentials.ClearCredentialStateException) {
+ Log.i(TAG, "ClearCredentialStateException error returned from framework")
+ // TODO("Covert to the appropriate exception")
+ callback.onError(ClearCredentialUnknownException())
+ }
+ }
+
+ credentialManager!!.clearCredentialState(
+ createFrameworkClearCredentialRequest(),
+ cancellationSignal,
+ Executors.newSingleThreadExecutor(),
+ outcome
+ )
+ }
+
+ /** @hide */
+ companion object {
+ private const val TAG = "CredManProvService"
+ }
+}
\ No newline at end of file
diff --git a/credentials/credentials/src/main/java/androidx/credentials/provider/Action.kt b/credentials/credentials/src/main/java/androidx/credentials/provider/Action.kt
new file mode 100644
index 0000000..bb46238
--- /dev/null
+++ b/credentials/credentials/src/main/java/androidx/credentials/provider/Action.kt
@@ -0,0 +1,185 @@
+/*
+ * Copyright 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package androidx.credentials.provider
+
+import android.annotation.SuppressLint
+import android.app.PendingIntent
+import android.app.slice.Slice
+import android.app.slice.SliceSpec
+import android.net.Uri
+import android.os.Parcel
+import android.os.Parcelable
+import android.util.Log
+import androidx.annotation.NonNull
+import androidx.annotation.RequiresApi
+import androidx.annotation.VisibleForTesting
+import java.util.Collections
+
+/**
+ * An actionable entry that is returned as part of the
+ * [android.service.credentials.BeginGetCredentialResponse], and then shown on the user selector.
+ * When selected, the associated [PendingIntent] is invoked to launch a provider controlled
+ * activity.
+ *
+ * Examples of [Action] entries include and entry that it titled 'Open App', and navigates
+ * to the home page of the credential provider app, or an entry that is titled 'Manage Credentials'
+ * and navigates to a particular page that lists all credentials.
+ *
+ * @property title the title of the entry
+ * @property pendingIntent the [PendingIntent] that will be invoked when the user selects this entry
+ * @property subtitle the optional subtitle that is displayed on the entry
+ *
+ * @see android.service.credentials.CredentialsResponseContent for usage.
+ *
+ * @throws IllegalArgumentException If [title] is empty
+ * @throws NullPointerException If [title] or [pendingIntent] is null
+ */
+@RequiresApi(34)
+class Action constructor(
+ val title: CharSequence,
+ val pendingIntent: PendingIntent,
+ val subtitle: CharSequence? = null,
+ ) : android.service.credentials.Action(
+ toSlice(title, subtitle, pendingIntent)) {
+
+ init {
+ require(title.isNotEmpty()) { "title must not be empty" }
+ }
+
+ override fun describeContents(): Int {
+ return 0
+ }
+
+ override fun writeToParcel(@NonNull dest: Parcel, flags: Int) {
+ super.writeToParcel(dest, flags)
+ }
+
+ /**
+ * A builder for [Action]
+ *
+ * @param title the title of this action entry
+ * @param pendingIntent the [PendingIntent] that will be fired when the user selects
+ * this action entry
+ */
+ class Builder constructor(
+ private val title: CharSequence,
+ private val pendingIntent: PendingIntent
+ ) {
+ private var subtitle: CharSequence? = null
+
+ /** Sets a sub title to be shown on the UI with this entry */
+ fun setSubtitle(subtitle: CharSequence?): Builder {
+ this.subtitle = subtitle
+ return this
+ }
+
+ /**
+ * Builds an instance of [Action]
+ *
+ * @throws IllegalArgumentException If [title] is empty
+ */
+ fun build(): Action {
+ return Action(title, pendingIntent, subtitle)
+ }
+ }
+
+ @Suppress("AcronymName")
+ companion object {
+ private const val TAG = "Action"
+ private const val SLICE_SPEC_REVISION = 0
+ private const val SLICE_SPEC_TYPE = "Action"
+
+ @VisibleForTesting(otherwise = VisibleForTesting.PRIVATE)
+ internal const val SLICE_HINT_TITLE =
+ "androidx.credentials.provider.action.HINT_ACTION_TITLE"
+ @VisibleForTesting(otherwise = VisibleForTesting.PRIVATE)
+ internal const val SLICE_HINT_SUBTITLE =
+ "androidx.credentials.provider.action.HINT_ACTION_SUBTEXT"
+ @VisibleForTesting(otherwise = VisibleForTesting.PRIVATE)
+ internal const val SLICE_HINT_PENDING_INTENT =
+ "androidx.credentials.provider.action.SLICE_HINT_PENDING_INTENT"
+
+ @JvmStatic
+ internal fun toSlice(
+ title: CharSequence,
+ subtitle: CharSequence?,
+ pendingIntent: PendingIntent
+ ): Slice {
+ val sliceBuilder = Slice.Builder(Uri.EMPTY, SliceSpec(
+ SLICE_SPEC_TYPE, SLICE_SPEC_REVISION))
+ .addText(title, /*subType=*/null,
+ listOf(SLICE_HINT_TITLE))
+ .addText(subtitle, /*subType=*/null,
+ listOf(SLICE_HINT_SUBTITLE))
+ sliceBuilder.addAction(pendingIntent,
+ Slice.Builder(sliceBuilder)
+ .addHints(Collections.singletonList(SLICE_HINT_PENDING_INTENT))
+ .build(),
+ /*subType=*/null)
+ return sliceBuilder.build()
+ }
+
+ /**
+ * Returns an instance of [Action] derived from a [Slice] object.
+ *
+ * @param slice the [Slice] object constructed through [toSlice]
+ *
+ * @hide
+ */
+ @SuppressLint("WrongConstant") // custom conversion between jetpack and framework
+ @JvmStatic
+ fun fromSlice(slice: Slice): Action? {
+ var title: CharSequence = ""
+ var subtitle: CharSequence? = null
+ var pendingIntent: PendingIntent? = null
+
+ slice.items.forEach {
+ if (it.hasHint(SLICE_HINT_TITLE)) {
+ title = it.text
+ } else if (it.hasHint(SLICE_HINT_SUBTITLE)) {
+ subtitle = it.text
+ } else if (it.hasHint(SLICE_HINT_PENDING_INTENT)) {
+ pendingIntent = it.action
+ }
+ }
+
+ return try {
+ Action(title, pendingIntent!!, subtitle)
+ } catch (e: Exception) {
+ Log.i(TAG, "fromSlice failed with: " + e.message)
+ null
+ }
+ }
+
+ @JvmField val CREATOR: Parcelable.Creator<Action> = object :
+ Parcelable.Creator<Action> {
+ /**
+ * This will not be used in any of the credMan flows as Action is constructed
+ * in the jetpack library and sent to the framework. UI app will receive the
+ * slice and use [fromSlice] to get back the object.
+ */
+ override fun createFromParcel(p0: Parcel?): Action? {
+ val action = android.service.credentials.Action.CREATOR.createFromParcel(p0)
+ return fromSlice(action.slice)
+ }
+
+ @Suppress("ArrayReturn")
+ override fun newArray(size: Int): Array<Action?> {
+ return arrayOfNulls<Action>(size)
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/credentials/credentials/src/main/java/androidx/credentials/provider/AuthenticationAction.kt b/credentials/credentials/src/main/java/androidx/credentials/provider/AuthenticationAction.kt
new file mode 100644
index 0000000..63402bd
--- /dev/null
+++ b/credentials/credentials/src/main/java/androidx/credentials/provider/AuthenticationAction.kt
@@ -0,0 +1,127 @@
+/*
+ * Copyright 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package androidx.credentials.provider
+import android.annotation.SuppressLint
+import android.app.PendingIntent
+import android.app.slice.Slice
+import android.app.slice.SliceSpec
+import android.net.Uri
+import android.os.Parcel
+import android.os.Parcelable
+import android.util.Log
+import androidx.annotation.NonNull
+import androidx.annotation.RequiresApi
+import androidx.annotation.VisibleForTesting
+import java.util.Collections
+
+/**
+ * An entry on the selector, denoting that the provider service is locked and authentication
+ * is needed to proceed.
+ *
+ * Providers should set this entry when the provider app is locked, and no credentials can
+ * be returned.
+ * Providers must set the [PendingIntent] that leads to their unlock activity. When the user
+ * selects this entry, the corresponding [PendingIntent] is fired and the unlock activity is
+ * invoked. Once the provider authentication flow is complete, providers must set
+ * the [android.service.credentials.CredentialsResponseContent] containing the unlocked credential
+ * entries, through the [PendingIntentHandler.setBeginGetCredentialResponse] method, before
+ * finishing the activity.
+ * If providers fail to set the [android.service.credentials.CredentialsResponseContent], the
+ * system will assume that there are no credentials available and the this entry will be removed
+ * from the selector.
+ *
+ * @property pendingIntent the [PendingIntent] to be invoked if the user selects
+ * this authentication entry on the UI.
+ *
+ * @see android.service.credentials.BeginGetCredentialResponse
+ * for usage details.
+ *
+ * @throws NullPointerException If the [pendingIntent] is null
+ */
+@RequiresApi(34)
+class AuthenticationAction constructor(
+ val pendingIntent: PendingIntent,
+) : android.service.credentials.Action(
+ toSlice(pendingIntent)) {
+
+ override fun describeContents(): Int {
+ return 0
+ }
+
+ override fun writeToParcel(@NonNull dest: Parcel, flags: Int) {
+ super.writeToParcel(dest, flags)
+ }
+ @Suppress("AcronymName")
+ companion object {
+ private const val TAG = "AuthenticationAction"
+ private const val SLICE_SPEC_REVISION = 0
+ private const val SLICE_SPEC_TYPE = "AuthenticationAction"
+ @VisibleForTesting(otherwise = VisibleForTesting.PRIVATE)
+ internal const val SLICE_HINT_PENDING_INTENT =
+ "androidx.credentials.provider.authenticationAction.SLICE_HINT_PENDING_INTENT"
+
+ /** @hide **/
+ @JvmStatic
+ fun toSlice(pendingIntent: PendingIntent): Slice {
+ val sliceBuilder = Slice.Builder(Uri.EMPTY, SliceSpec(SLICE_SPEC_TYPE,
+ SLICE_SPEC_REVISION))
+ sliceBuilder.addAction(pendingIntent,
+ Slice.Builder(sliceBuilder)
+ .addHints(Collections.singletonList(SLICE_HINT_PENDING_INTENT))
+ .build(),
+ /*subType=*/null)
+ return sliceBuilder.build()
+ }
+
+ /**
+ * Returns an instance of [AuthenticationAction] derived from a [Slice] object.
+ *
+ * @param slice the [Slice] object that contains the information required for
+ * constructing an instance of this class.
+ *
+ * @hide
+ */
+ @SuppressLint("WrongConstant") // custom conversion between jetpack and framework
+ @JvmStatic
+ fun fromSlice(slice: Slice): AuthenticationAction? {
+ slice.items.forEach {
+ if (it.hasHint(SLICE_HINT_PENDING_INTENT)) {
+ return try {
+ AuthenticationAction(it.action)
+ } catch (e: Exception) {
+ Log.i(TAG, "fromSlice failed with: " + e.message)
+ null
+ }
+ }
+ }
+ return null
+ }
+
+ @JvmField val CREATOR: Parcelable.Creator<AuthenticationAction> = object :
+ Parcelable.Creator<AuthenticationAction> {
+ override fun createFromParcel(p0: Parcel?): AuthenticationAction? {
+ val authAction =
+ android.service.credentials.Action.CREATOR.createFromParcel(p0)
+ return fromSlice(authAction.slice)
+ }
+
+ @Suppress("ArrayReturn")
+ override fun newArray(size: Int): Array<AuthenticationAction?> {
+ return arrayOfNulls(size)
+ }
+ }
+ }
+}
diff --git a/credentials/credentials/src/main/java/androidx/credentials/provider/BeginCreatePasswordCredentialRequest.kt b/credentials/credentials/src/main/java/androidx/credentials/provider/BeginCreatePasswordCredentialRequest.kt
new file mode 100644
index 0000000..ce9e7a3
--- /dev/null
+++ b/credentials/credentials/src/main/java/androidx/credentials/provider/BeginCreatePasswordCredentialRequest.kt
@@ -0,0 +1,99 @@
+/*
+ * Copyright 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.credentials.provider
+
+import android.app.PendingIntent
+import android.content.Intent
+import android.os.Bundle
+import android.os.Parcel
+import android.os.Parcelable
+import android.service.credentials.BeginCreateCredentialRequest
+import android.service.credentials.CallingAppInfo
+import androidx.annotation.NonNull
+import androidx.annotation.RequiresApi
+import androidx.credentials.CreatePasswordRequest
+import androidx.credentials.PasswordCredential
+import androidx.credentials.internal.FrameworkClassParsingException
+
+/**
+ * Request to begin saving a password credential, received by the provider with a
+ * CredentialProviderBaseService.onBeginCreateCredentialRequest call.
+ *
+ * This request will not contain all parameters needed to store the password. Provider must
+ * use the initial parameters to determine if the password can be stored, and return
+ * a list of [CreateEntry], denoting the accounts/groups where the password can be stored.
+ * When user selects one of the returned [CreateEntry], the corresponding [PendingIntent] set on
+ * the [CreateEntry] will be fired. The [Intent] invoked through the [PendingIntent] will contain the
+ * complete [CreatePasswordRequest]. This request will contain all required parameters to
+ * actually store the password.
+ *
+ * @see BeginCreateCredentialRequest
+ */
+@RequiresApi(34)
+class BeginCreatePasswordCredentialRequest internal constructor(
+ callingAppInfo: CallingAppInfo?
+) : BeginCreateCredentialRequest(
+ PasswordCredential.TYPE_PASSWORD_CREDENTIAL,
+ toCandidateDataBundle(),
+ callingAppInfo,
+ ) {
+ override fun describeContents(): Int {
+ return 0
+ }
+
+ override fun writeToParcel(@NonNull dest: Parcel, flags: Int) {
+ super.writeToParcel(dest, flags)
+ }
+
+ @Suppress("AcronymName")
+ companion object {
+
+ // No credential data should be sent during the query phase.
+ /** @hide **/
+ @JvmStatic
+ internal fun toCandidateDataBundle(): Bundle {
+ return Bundle()
+ }
+
+ /** @hide **/
+ @JvmStatic
+ @Suppress("UNUSED_PARAMETER")
+ internal fun createFrom(data: Bundle, callingAppInfo: CallingAppInfo?):
+ BeginCreatePasswordCredentialRequest {
+ try {
+ return BeginCreatePasswordCredentialRequest(
+ callingAppInfo
+ )
+ } catch (e: Exception) {
+ throw FrameworkClassParsingException()
+ }
+ }
+
+ @JvmField val CREATOR: Parcelable.Creator<BeginCreatePasswordCredentialRequest> =
+ object : Parcelable.Creator<BeginCreatePasswordCredentialRequest> {
+ override fun createFromParcel(p0: Parcel?): BeginCreatePasswordCredentialRequest {
+ val baseRequest = BeginCreateCredentialRequest.CREATOR.createFromParcel(p0)
+ return createFrom(baseRequest.data, baseRequest.callingAppInfo)
+ }
+
+ @Suppress("ArrayReturn")
+ override fun newArray(size: Int): Array<BeginCreatePasswordCredentialRequest?> {
+ return arrayOfNulls(size)
+ }
+ }
+ }
+}
diff --git a/credentials/credentials/src/main/java/androidx/credentials/provider/BeginCreatePublicKeyCredentialRequest.kt b/credentials/credentials/src/main/java/androidx/credentials/provider/BeginCreatePublicKeyCredentialRequest.kt
new file mode 100644
index 0000000..c3b04db
--- /dev/null
+++ b/credentials/credentials/src/main/java/androidx/credentials/provider/BeginCreatePublicKeyCredentialRequest.kt
@@ -0,0 +1,121 @@
+/*
+ * Copyright 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.credentials.provider
+
+import android.app.PendingIntent
+import android.content.Intent
+import android.os.Bundle
+import android.os.Parcel
+import android.os.Parcelable
+import android.service.credentials.BeginCreateCredentialRequest
+import android.service.credentials.CallingAppInfo
+import androidx.annotation.NonNull
+import androidx.annotation.RequiresApi
+import androidx.credentials.CreatePublicKeyCredentialRequest
+import androidx.credentials.CreatePublicKeyCredentialRequest.Companion.BUNDLE_KEY_REQUEST_JSON
+import androidx.credentials.PublicKeyCredential
+import androidx.credentials.internal.FrameworkClassParsingException
+
+/**
+ * Request to begin registering a public key credential.
+ *
+ * This request will not contain all parameters needed to create the public key. Provider must
+ * use the initial parameters to determine if the public key can be registered, and return
+ * a list of [CreateEntry], denoting the accounts/groups where the public key can be registered.
+ * When user selects one of the returned [CreateEntry], the corresponding [PendingIntent] set on
+ * the [CreateEntry] will be fired. The [Intent] invoked through the [PendingIntent] will contain
+ * the complete [CreatePublicKeyCredentialRequest]. This request will contain all required
+ * parameters to actually register a public key.
+ *
+ * @property json the request json to be used for registering the public key credential
+ *
+ * @see BeginCreateCredentialRequest
+ */
+@RequiresApi(34)
+class BeginCreatePublicKeyCredentialRequest internal constructor(
+ val json: String,
+ callingAppInfo: CallingAppInfo?,
+) : BeginCreateCredentialRequest(
+ PublicKeyCredential.TYPE_PUBLIC_KEY_CREDENTIAL,
+ // TODO ("Use custom version of toCandidateData in this class")
+ toCandidateDataBundle(
+ json,
+ /*preferImmediatelyAvailableCredentials=*/false
+ ),
+ callingAppInfo
+) {
+ init {
+ require(json.isNotEmpty()) { "json must not be empty" }
+ }
+
+ override fun describeContents(): Int {
+ return 0
+ }
+
+ override fun writeToParcel(@NonNull dest: Parcel, flags: Int) {
+ super.writeToParcel(dest, flags)
+ }
+
+ @Suppress("AcronymName")
+ companion object {
+ /** @hide */
+ @JvmStatic
+ internal fun toCandidateDataBundle(
+ requestJson: String,
+ preferImmediatelyAvailableCredentials: Boolean
+ ): Bundle {
+ val bundle = Bundle()
+ bundle.putString(
+ PublicKeyCredential.BUNDLE_KEY_SUBTYPE,
+ CreatePublicKeyCredentialRequest
+ .BUNDLE_VALUE_SUBTYPE_CREATE_PUBLIC_KEY_CREDENTIAL_REQUEST
+ )
+ bundle.putString(BUNDLE_KEY_REQUEST_JSON, requestJson)
+ bundle.putBoolean(
+ CreatePublicKeyCredentialRequest
+ .BUNDLE_KEY_PREFER_IMMEDIATELY_AVAILABLE_CREDENTIALS,
+ preferImmediatelyAvailableCredentials
+ )
+ return bundle
+ }
+
+ /** @hide */
+ @JvmStatic
+ internal fun createFrom(data: Bundle, callingAppInfo: CallingAppInfo?):
+ BeginCreatePublicKeyCredentialRequest {
+ try {
+ val requestJson = data.getString(BUNDLE_KEY_REQUEST_JSON)
+ return BeginCreatePublicKeyCredentialRequest(requestJson!!, callingAppInfo)
+ } catch (e: Exception) {
+ throw FrameworkClassParsingException()
+ }
+ }
+
+ @JvmField val CREATOR: Parcelable.Creator<BeginCreatePublicKeyCredentialRequest> = object :
+ Parcelable.Creator<BeginCreatePublicKeyCredentialRequest> {
+ override fun createFromParcel(p0: Parcel?): BeginCreatePublicKeyCredentialRequest {
+ val baseRequest = BeginCreateCredentialRequest.CREATOR.createFromParcel(p0)
+ return createFrom(baseRequest.data, baseRequest.callingAppInfo)
+ }
+
+ @Suppress("ArrayReturn")
+ override fun newArray(size: Int): Array<BeginCreatePublicKeyCredentialRequest?> {
+ return arrayOfNulls(size)
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/credentials/credentials/src/main/java/androidx/credentials/provider/BeginCreatePublicKeyCredentialRequestPrivileged.kt b/credentials/credentials/src/main/java/androidx/credentials/provider/BeginCreatePublicKeyCredentialRequestPrivileged.kt
new file mode 100644
index 0000000..27ed933
--- /dev/null
+++ b/credentials/credentials/src/main/java/androidx/credentials/provider/BeginCreatePublicKeyCredentialRequestPrivileged.kt
@@ -0,0 +1,114 @@
+/*
+ * Copyright 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.credentials.provider
+
+import android.app.PendingIntent
+import android.content.Intent
+import android.os.Bundle
+import android.os.Parcel
+import android.os.Parcelable
+import android.service.credentials.BeginCreateCredentialRequest
+import android.service.credentials.CallingAppInfo
+import androidx.annotation.NonNull
+import androidx.annotation.RequiresApi
+import androidx.credentials.CreatePublicKeyCredentialRequestPrivileged
+import androidx.credentials.CreatePublicKeyCredentialRequestPrivileged.Companion.BUNDLE_KEY_CLIENT_DATA_HASH
+import androidx.credentials.CreatePublicKeyCredentialRequestPrivileged.Companion.BUNDLE_KEY_RELYING_PARTY
+import androidx.credentials.CreatePublicKeyCredentialRequestPrivileged.Companion.toCredentialDataBundle
+import androidx.credentials.PublicKeyCredential
+import androidx.credentials.internal.FrameworkClassParsingException
+
+/**
+ * Request to begin registering a public key credential, coming from a privileged source that
+ * can call on behalf of another relying party.
+ *
+ * This request will not contain all parameters needed to create the public key. Provider must
+ * use the initial parameters to determine if the public key can be registered, and return
+ * a list of [CreateEntry], denoting the accounts/groups where the public key can be registered.
+ * When user selects one of the returned [CreateEntry], the corresponding [PendingIntent] set on
+ * the [CreateEntry] will be fired. The [Intent] invoked through the [PendingIntent] will contain
+ * the complete [CreatePublicKeyCredentialRequestPrivileged]. This request will contain all
+ * required parameters to actually register a public key.
+ *
+ * @property json the request json to be used for registering the public key credential
+ *
+ * @see BeginCreateCredentialRequest
+ */
+@RequiresApi(34)
+class BeginCreatePublicKeyCredentialRequestPrivileged internal constructor(
+ val json: String,
+ val relyingParty: String,
+ val clientDataHash: String,
+ callingAppInfo: CallingAppInfo?,
+) : BeginCreateCredentialRequest(
+ PublicKeyCredential.TYPE_PUBLIC_KEY_CREDENTIAL,
+ toCredentialDataBundle(json, relyingParty, clientDataHash,
+ /*preferImmediatelyAvailableCredentials=*/ false),
+ callingAppInfo
+) {
+ init {
+ require(json.isNotEmpty()) { "json must not be empty" }
+ }
+
+ override fun describeContents(): Int {
+ return 0
+ }
+
+ override fun writeToParcel(@NonNull dest: Parcel, flags: Int) {
+ super.writeToParcel(dest, flags)
+ }
+
+ @Suppress("AcronymName")
+ companion object {
+
+ /** @hide */
+ @JvmStatic
+ internal fun createFrom(data: Bundle, callingAppInfo: CallingAppInfo?):
+ BeginCreatePublicKeyCredentialRequestPrivileged {
+ try {
+ val requestJson = data.getString(CreatePublicKeyCredentialRequestPrivileged
+ .BUNDLE_KEY_REQUEST_JSON)
+ val rp = data.getString(BUNDLE_KEY_RELYING_PARTY)
+ val clientDataHash = data.getString(BUNDLE_KEY_CLIENT_DATA_HASH)
+ return BeginCreatePublicKeyCredentialRequestPrivileged(
+ requestJson!!,
+ rp!!,
+ clientDataHash!!,
+ callingAppInfo
+ )
+ } catch (e: Exception) {
+ throw FrameworkClassParsingException()
+ }
+ }
+
+ @JvmField val CREATOR:
+ Parcelable.Creator<BeginCreatePublicKeyCredentialRequestPrivileged> = object :
+ Parcelable.Creator<BeginCreatePublicKeyCredentialRequestPrivileged> {
+ override fun createFromParcel(p0: Parcel?):
+ BeginCreatePublicKeyCredentialRequestPrivileged {
+ val baseRequest = BeginCreateCredentialRequest.CREATOR.createFromParcel(p0)
+ return createFrom(baseRequest.data, baseRequest.callingAppInfo)
+ }
+
+ @Suppress("ArrayReturn")
+ override fun newArray(size: Int):
+ Array<BeginCreatePublicKeyCredentialRequestPrivileged?> {
+ return arrayOfNulls(size)
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/credentials/credentials/src/main/java/androidx/credentials/provider/BeginGetPasswordOption.kt b/credentials/credentials/src/main/java/androidx/credentials/provider/BeginGetPasswordOption.kt
new file mode 100644
index 0000000..bba0632
--- /dev/null
+++ b/credentials/credentials/src/main/java/androidx/credentials/provider/BeginGetPasswordOption.kt
@@ -0,0 +1,74 @@
+/*
+ * Copyright 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.credentials.provider
+
+import android.os.Bundle
+import android.os.Parcel
+import android.os.Parcelable
+import android.service.credentials.BeginGetCredentialOption
+import android.service.credentials.BeginGetCredentialResponse
+import androidx.annotation.NonNull
+import androidx.annotation.RequiresApi
+import androidx.credentials.PasswordCredential
+
+/**
+ * A request to a password provider to begin the flow of retrieving the user's saved passwords.
+ *
+ * Providers must use the parameters in this option to retrieve the corresponding credentials'
+ * metadata, and then return them in the form of a list of [PasswordCredentialEntry]
+ * set on the [BeginGetCredentialResponse].
+ */
+@RequiresApi(34)
+class BeginGetPasswordOption internal constructor(
+ candidateQueryData: Bundle,
+ id: String
+) : BeginGetCredentialOption(
+ id,
+ PasswordCredential.TYPE_PASSWORD_CREDENTIAL,
+ candidateQueryData
+) {
+
+ override fun describeContents(): Int {
+ return 0
+ }
+
+ override fun writeToParcel(@NonNull dest: Parcel, flags: Int) {
+ super.writeToParcel(dest, flags)
+ }
+
+ @Suppress("AcronymName")
+ companion object {
+ /** @hide */
+ @JvmStatic
+ internal fun createFrom(data: Bundle, id: String): BeginGetPasswordOption {
+ return BeginGetPasswordOption(data, id)
+ }
+
+ @JvmField val CREATOR: Parcelable.Creator<BeginGetPasswordOption> = object :
+ Parcelable.Creator<BeginGetPasswordOption> {
+ override fun createFromParcel(p0: Parcel?): BeginGetPasswordOption {
+ val baseOption = BeginGetCredentialOption.CREATOR.createFromParcel(p0)
+ return createFrom(baseOption.candidateQueryData, baseOption.id)
+ }
+
+ @Suppress("ArrayReturn")
+ override fun newArray(size: Int): Array<BeginGetPasswordOption?> {
+ return arrayOfNulls(size)
+ }
+ }
+ }
+}
diff --git a/credentials/credentials/src/main/java/androidx/credentials/provider/BeginGetPublicKeyCredentialOption.kt b/credentials/credentials/src/main/java/androidx/credentials/provider/BeginGetPublicKeyCredentialOption.kt
new file mode 100644
index 0000000..bb8c5ab
--- /dev/null
+++ b/credentials/credentials/src/main/java/androidx/credentials/provider/BeginGetPublicKeyCredentialOption.kt
@@ -0,0 +1,87 @@
+/*
+ * Copyright 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.credentials.provider
+
+import android.os.Bundle
+import android.os.Parcel
+import android.os.Parcelable
+import android.service.credentials.BeginGetCredentialOption
+import androidx.annotation.NonNull
+import androidx.annotation.RequiresApi
+import androidx.credentials.GetPublicKeyCredentialOption
+import androidx.credentials.PublicKeyCredential
+import androidx.credentials.internal.FrameworkClassParsingException
+
+/**
+ * A request to begin the flow of getting passkeys from the user's public key credential provider.
+ *
+ * @property requestJson the privileged request in JSON format in the standard webauthn web json
+ * shown [here](https://w3c.github.io/webauthn/#dictdef-publickeycredentialrequestoptionsjson)
+ *
+ * @throws NullPointerException If [requestJson] is null
+ * @throws IllegalArgumentException If [requestJson] is empty
+ */
+@RequiresApi(34)
+class BeginGetPublicKeyCredentialOption internal constructor(
+ candidateQueryData: Bundle,
+ id: String,
+ val requestJson: String,
+) : BeginGetCredentialOption(
+ id,
+ PublicKeyCredential.TYPE_PUBLIC_KEY_CREDENTIAL,
+ candidateQueryData
+) {
+ init {
+ require(requestJson.isNotEmpty()) { "requestJson must not be empty" }
+ }
+
+ override fun describeContents(): Int {
+ return 0
+ }
+
+ override fun writeToParcel(@NonNull dest: Parcel, flags: Int) {
+ super.writeToParcel(dest, flags)
+ }
+
+ @Suppress("AcronymName")
+ companion object {
+ /** @hide */
+ @JvmStatic
+ internal fun createFrom(data: Bundle, id: String): BeginGetPublicKeyCredentialOption {
+ try {
+ val requestJson = data.getString(
+ GetPublicKeyCredentialOption.BUNDLE_KEY_REQUEST_JSON)
+ return BeginGetPublicKeyCredentialOption(data, id, requestJson!!)
+ } catch (e: Exception) {
+ throw FrameworkClassParsingException()
+ }
+ }
+
+ @JvmField val CREATOR: Parcelable.Creator<BeginGetPublicKeyCredentialOption> = object :
+ Parcelable.Creator<BeginGetPublicKeyCredentialOption> {
+ override fun createFromParcel(p0: Parcel?): BeginGetPublicKeyCredentialOption {
+ val baseOption = BeginGetCredentialOption.CREATOR.createFromParcel(p0)
+ return createFrom(baseOption.candidateQueryData, baseOption.id)
+ }
+
+ @Suppress("ArrayReturn")
+ override fun newArray(size: Int): Array<BeginGetPublicKeyCredentialOption?> {
+ return arrayOfNulls(size)
+ }
+ }
+ }
+}
diff --git a/credentials/credentials/src/main/java/androidx/credentials/provider/BeginGetPublicKeyCredentialOptionPrivileged.kt b/credentials/credentials/src/main/java/androidx/credentials/provider/BeginGetPublicKeyCredentialOptionPrivileged.kt
new file mode 100644
index 0000000..1bc264b
--- /dev/null
+++ b/credentials/credentials/src/main/java/androidx/credentials/provider/BeginGetPublicKeyCredentialOptionPrivileged.kt
@@ -0,0 +1,113 @@
+/*
+ * Copyright 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.credentials.provider
+
+import android.os.Bundle
+import android.os.Parcel
+import android.os.Parcelable
+import android.service.credentials.BeginGetCredentialOption
+import androidx.annotation.NonNull
+import androidx.annotation.RequiresApi
+import androidx.credentials.GetPublicKeyCredentialOptionPrivileged
+import androidx.credentials.PublicKeyCredential
+import androidx.credentials.internal.FrameworkClassParsingException
+
+/**
+ * A privileged request to get passkeys from the user's public key credential provider. The caller
+ * can modify the RP. Only callers with privileged permission (e.g. user's public browser or caBLE)
+ * can use this. These permissions will be introduced in an upcoming release.
+ * TODO("Add specific permission info/annotation")
+ *
+ * @property requestJson the privileged request in JSON format in the standard webauthn web json
+ * shown [here](https://w3c.github.io/webauthn/#dictdef-publickeycredentialrequestoptionsjson).
+ * @property relyingParty the expected true RP ID which will override the one in the [requestJson],
+ * where relyingParty is defined [here](https://w3c.github.io/webauthn/#rp-id) in more detail
+ * @property clientDataHash a hash that is used to verify the [relyingParty] Identity
+ *
+ * @throws NullPointerException If any of [requestJson], [relyingParty], or [clientDataHash]
+ * is null
+ * @throws IllegalArgumentException If any of [requestJson], [relyingParty], or [clientDataHash]
+ * is empty
+ */
+@RequiresApi(34)
+class BeginGetPublicKeyCredentialOptionPrivileged internal constructor(
+ candidateQueryData: Bundle,
+ id: String,
+ val requestJson: String,
+ val relyingParty: String,
+ val clientDataHash: String,
+) : BeginGetCredentialOption(
+ id,
+ PublicKeyCredential.TYPE_PUBLIC_KEY_CREDENTIAL,
+ candidateQueryData
+) {
+
+ init {
+ require(requestJson.isNotEmpty()) { "requestJson must not be empty" }
+ require(relyingParty.isNotEmpty()) { "rp must not be empty" }
+ require(clientDataHash.isNotEmpty()) { "clientDataHash must not be empty" }
+ }
+
+ override fun describeContents(): Int {
+ return 0
+ }
+
+ override fun writeToParcel(@NonNull dest: Parcel, flags: Int) {
+ super.writeToParcel(dest, flags)
+ }
+
+ @Suppress("AcronymName")
+ companion object {
+
+ /** @hide */
+ @JvmStatic
+ internal fun createFrom(data: Bundle, id: String):
+ BeginGetPublicKeyCredentialOptionPrivileged {
+ try {
+ val requestJson = data.getString(
+ GetPublicKeyCredentialOptionPrivileged.BUNDLE_KEY_REQUEST_JSON)
+ val rp = data.getString(
+ GetPublicKeyCredentialOptionPrivileged.BUNDLE_KEY_RELYING_PARTY)
+ val clientDataHash = data.getString(
+ GetPublicKeyCredentialOptionPrivileged.BUNDLE_KEY_CLIENT_DATA_HASH)
+ return BeginGetPublicKeyCredentialOptionPrivileged(
+ data,
+ id,
+ requestJson!!,
+ rp!!,
+ clientDataHash!!
+ )
+ } catch (e: Exception) {
+ throw FrameworkClassParsingException()
+ }
+ }
+
+ @JvmField val CREATOR: Parcelable.Creator<BeginGetPublicKeyCredentialOptionPrivileged> =
+ object : Parcelable.Creator<BeginGetPublicKeyCredentialOptionPrivileged> {
+ override fun createFromParcel(p0: Parcel?):
+ BeginGetPublicKeyCredentialOptionPrivileged {
+ val baseOption = BeginGetCredentialOption.CREATOR.createFromParcel(p0)
+ return createFrom(baseOption.candidateQueryData, baseOption.id)
+ }
+
+ @Suppress("ArrayReturn")
+ override fun newArray(size: Int): Array<BeginGetPublicKeyCredentialOptionPrivileged?> {
+ return arrayOfNulls(size)
+ }
+ }
+ }
+}
diff --git a/credentials/credentials/src/main/java/androidx/credentials/provider/CreateEntry.kt b/credentials/credentials/src/main/java/androidx/credentials/provider/CreateEntry.kt
new file mode 100644
index 0000000..b75ac8c
--- /dev/null
+++ b/credentials/credentials/src/main/java/androidx/credentials/provider/CreateEntry.kt
@@ -0,0 +1,419 @@
+/*
+ * Copyright 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package androidx.credentials.provider
+
+import android.annotation.SuppressLint
+import android.app.PendingIntent
+import android.app.slice.Slice
+import android.app.slice.SliceSpec
+import android.graphics.drawable.Icon
+import android.net.Uri
+import android.os.Bundle
+import android.os.Parcel
+import android.os.Parcelable
+import android.util.Log
+import androidx.annotation.NonNull
+import androidx.annotation.RequiresApi
+import androidx.annotation.VisibleForTesting
+import androidx.credentials.CredentialManager
+import androidx.credentials.PasswordCredential
+import androidx.credentials.PublicKeyCredential
+import java.time.Instant
+import java.util.Collections
+
+/**
+ * An entry to be shown on the selector during a create flow initiated when an app calls
+ * [CredentialManager.createCredential]
+ *
+ * A [CreateEntry] points to a location such as an account, or a group where the credential can be
+ * registered. When user selects this entry, the corresponding [PendingIntent] is fired, and the
+ * credential creation can be completed.
+ *
+ * @throws IllegalArgumentException If [accountName] is empty
+ */
+@RequiresApi(34)
+class CreateEntry internal constructor(
+ val accountName: CharSequence,
+ val pendingIntent: PendingIntent,
+ val icon: Icon?,
+ val description: CharSequence?,
+ val lastUsedTime: Instant?,
+ private val credentialCountInformationMap: MutableMap<String, Int?>
+ ) : android.service.credentials.CreateEntry(
+ toSlice(
+ accountName,
+ icon,
+ description,
+ lastUsedTime,
+ credentialCountInformationMap,
+ pendingIntent)
+) {
+
+ /**
+ * Creates an entry to be displayed on the selector during create flows.
+ *
+ * @param accountName the name of the account where the credential will be saved
+ * @param pendingIntent the [PendingIntent] that will get invoked when user selects this entry
+ * @param description the description shown on UI about where the credential is stored
+ * @param icon the icon to be displayed with this entry on the UI
+ * @param lastUsedTime the last time the account underlying this entry was used by the user
+ * @param passwordCredentialCount the no. of password credentials saved by the provider
+ * @param publicKeyCredentialCount the no. of public key credentials saved by the provider
+ * @param totalCredentialCount the total no. of credentials saved by the provider
+ *
+ * @throws IllegalArgumentException If [accountName] is empty
+ * @throws NullPointerException If [accountName] or [pendingIntent] is null
+ */
+ constructor(
+ accountName: CharSequence,
+ pendingIntent: PendingIntent,
+ description: CharSequence? = null,
+ lastUsedTime: Instant? = null,
+ icon: Icon? = null,
+ @Suppress("AutoBoxing")
+ passwordCredentialCount: Int? = null,
+ @Suppress("AutoBoxing")
+ publicKeyCredentialCount: Int? = null,
+ @Suppress("AutoBoxing")
+ totalCredentialCount: Int? = null
+ ) : this(
+ accountName,
+ pendingIntent,
+ icon,
+ description,
+ lastUsedTime,
+ mutableMapOf(
+ PasswordCredential.TYPE_PASSWORD_CREDENTIAL to passwordCredentialCount,
+ PublicKeyCredential.TYPE_PUBLIC_KEY_CREDENTIAL to publicKeyCredentialCount,
+ TYPE_TOTAL_CREDENTIAL to totalCredentialCount
+ )
+ )
+
+ init {
+ require(accountName.isNotEmpty()) { "accountName must not be empty" }
+ }
+
+ /** Returns the no. of password type credentials that the provider with this entry has. */
+ @Suppress("AutoBoxing")
+ fun getPasswordCredentialCount(): Int? {
+ return credentialCountInformationMap[PasswordCredential.TYPE_PASSWORD_CREDENTIAL]
+ }
+
+ /** Returns the no. of public key type credentials that the provider with this entry has. */
+ @Suppress("AutoBoxing")
+ fun getPublicKeyCredentialCount(): Int? {
+ return credentialCountInformationMap[PublicKeyCredential.TYPE_PUBLIC_KEY_CREDENTIAL]
+ }
+
+ /** Returns the no. of total credentials that the provider with this entry has.
+ *
+ * This total count is not necessarily equal to the sum of [getPasswordCredentialCount]
+ * and [getPublicKeyCredentialCount].
+ *
+ */
+ @Suppress("AutoBoxing")
+ fun getTotalCredentialCount(): Int? {
+ return credentialCountInformationMap[TYPE_TOTAL_CREDENTIAL]
+ }
+
+ override fun describeContents(): Int {
+ return 0
+ }
+
+ override fun writeToParcel(@NonNull dest: Parcel, flags: Int) {
+ super.writeToParcel(dest, flags)
+ }
+
+ /**
+ * A builder for [CreateEntry]
+ *
+ * @param accountName the name of the account where the credential will be registered
+ * @param pendingIntent the [PendingIntent] that will be fired when the user selects
+ * this entry
+ */
+ class Builder constructor(
+ private val accountName: CharSequence,
+ private val pendingIntent: PendingIntent
+ ) {
+
+ private var credentialCountInformationMap: MutableMap<String, Int?> =
+ mutableMapOf()
+ private var icon: Icon? = null
+ private var description: CharSequence? = null
+ private var lastUsedTime: Instant? = null
+ private var passwordCredentialCount: Int? = null
+ private var publicKeyCredentialCount: Int? = null
+ private var totalCredentialCount: Int? = null
+
+ /** Sets the password credential count, denoting how many credentials of type
+ * [PasswordCredential.TYPE_PASSWORD_CREDENTIAL] does the provider have stored.
+ *
+ * This information will be displayed on the [CreateEntry] to help the user
+ * make a choice.
+ */
+ fun setPasswordCredentialCount(count: Int): Builder {
+ passwordCredentialCount = count
+ credentialCountInformationMap[PasswordCredential.TYPE_PASSWORD_CREDENTIAL] = count
+ return this
+ }
+
+ /** Sets the password credential count, denoting how many credentials of type
+ * [PublicKeyCredential.TYPE_PUBLIC_KEY_CREDENTIAL] does the provider have stored.
+ *
+ * This information will be displayed on the [CreateEntry] to help the user
+ * make a choice.
+ */
+ fun setPublicKeyCredentialCount(count: Int): Builder {
+ publicKeyCredentialCount = count
+ credentialCountInformationMap[PublicKeyCredential.TYPE_PUBLIC_KEY_CREDENTIAL] = count
+ return this
+ }
+
+ /** Sets the total credential count, denoting how many credentials in total
+ * does the provider have stored.
+ *
+ * This total count no. does not need to be a total of the counts set through
+ * [setPasswordCredentialCount] and [setPublicKeyCredentialCount].
+ *
+ * This information will be displayed on the [CreateEntry] to help the user
+ * make a choice.
+ */
+ fun setTotalCredentialCount(count: Int): Builder {
+ totalCredentialCount = count
+ credentialCountInformationMap[TYPE_TOTAL_CREDENTIAL] = count
+ return this
+ }
+
+ /** Sets an icon to be displayed with the entry on the UI */
+ fun setIcon(icon: Icon?): Builder {
+ this.icon = icon
+ return this
+ }
+
+ /**
+ * Sets a description to be displayed on the UI at the time of credential creation.
+ *
+ * Typically this description should contain information informing the user of the
+ * credential being created, and where it is being stored. Providers are free
+ * to phrase this however they see fit.
+ *
+ * @throws IllegalArgumentException if [description] is longer than 150 characters.
+ */
+ fun setDescription(description: CharSequence?): Builder {
+ if (description?.length != null && description.length > DESCRIPTION_MAX_CHAR_LIMIT) {
+ throw IllegalArgumentException("Description must follow a limit of 150 characters.")
+ }
+ this.description = description
+ return this
+ }
+
+ /** Sets the last time this account was used */
+ fun setLastUsedTime(lastUsedTime: Instant?): Builder {
+ this.lastUsedTime = lastUsedTime
+ return this
+ }
+
+ /**
+ * Builds an instance of [CreateEntry]
+ *
+ * @throws IllegalArgumentException If [accountName] is empty
+ */
+ fun build(): CreateEntry {
+ return CreateEntry(
+ accountName, pendingIntent, icon, description, lastUsedTime,
+ credentialCountInformationMap
+ )
+ }
+ }
+
+ @Suppress("AcronymName")
+ companion object {
+ private const val TAG = "CreateEntry"
+ private const val DESCRIPTION_MAX_CHAR_LIMIT = 150
+ @VisibleForTesting(otherwise = VisibleForTesting.PRIVATE)
+ internal const val TYPE_TOTAL_CREDENTIAL = "TOTAL_CREDENTIAL_COUNT_TYPE"
+ @VisibleForTesting(otherwise = VisibleForTesting.PRIVATE)
+ internal const val SLICE_HINT_ACCOUNT_NAME =
+ "androidx.credentials.provider.createEntry.SLICE_HINT_USER_PROVIDER_ACCOUNT_NAME"
+ @VisibleForTesting(otherwise = VisibleForTesting.PRIVATE)
+ internal const val SLICE_HINT_NOTE =
+ "androidx.credentials.provider.createEntry.SLICE_HINT_NOTE"
+
+ @VisibleForTesting(otherwise = VisibleForTesting.PRIVATE)
+ internal const val SLICE_HINT_ICON =
+ "androidx.credentials.provider.createEntry.SLICE_HINT_PROFILE_ICON"
+
+ @VisibleForTesting(otherwise = VisibleForTesting.PRIVATE)
+ internal const val SLICE_HINT_CREDENTIAL_COUNT_INFORMATION =
+ "androidx.credentials.provider.createEntry.SLICE_HINT_CREDENTIAL_COUNT_INFORMATION"
+
+ @VisibleForTesting(otherwise = VisibleForTesting.PRIVATE)
+ internal const val SLICE_HINT_LAST_USED_TIME_MILLIS =
+ "androidx.credentials.provider.createEntry.SLICE_HINT_LAST_USED_TIME_MILLIS"
+
+ @VisibleForTesting(otherwise = VisibleForTesting.PRIVATE)
+ internal const val SLICE_HINT_PENDING_INTENT =
+ "androidx.credentials.provider.createEntry.SLICE_HINT_PENDING_INTENT"
+
+ /** @hide **/
+ @JvmStatic
+ fun toSlice(
+ accountName: CharSequence,
+ icon: Icon?,
+ description: CharSequence?,
+ lastUsedTime: Instant?,
+ credentialCountInformationMap: Map<String, Int?>,
+ pendingIntent: PendingIntent
+ ): Slice {
+ // TODO("Use the right type and revision")
+ val sliceBuilder = Slice.Builder(Uri.EMPTY, SliceSpec("type", 1))
+ sliceBuilder.addText(
+ accountName, /*subType=*/null,
+ listOf(SLICE_HINT_ACCOUNT_NAME)
+ )
+ if (lastUsedTime != null) {
+ sliceBuilder.addLong(
+ lastUsedTime.toEpochMilli(), /*subType=*/null, listOf(
+ SLICE_HINT_LAST_USED_TIME_MILLIS))
+ }
+ if (description != null) {
+ sliceBuilder.addText(description, null,
+ listOf(SLICE_HINT_NOTE))
+ }
+ if (icon != null) {
+ sliceBuilder.addIcon(
+ icon, /*subType=*/null,
+ listOf(SLICE_HINT_ICON)
+ )
+ }
+ val credentialCountBundle = convertCredentialCountInfoToBundle(
+ credentialCountInformationMap
+ )
+ if (credentialCountBundle != null) {
+ sliceBuilder.addBundle(
+ convertCredentialCountInfoToBundle(
+ credentialCountInformationMap
+ ), null, listOf(
+ SLICE_HINT_CREDENTIAL_COUNT_INFORMATION
+ )
+ )
+ }
+ sliceBuilder.addAction(
+ pendingIntent,
+ Slice.Builder(sliceBuilder)
+ .addHints(Collections.singletonList(SLICE_HINT_PENDING_INTENT))
+ .build(),
+ /*subType=*/null
+ )
+ return sliceBuilder.build()
+ }
+
+ /**
+ * Returns an instance of [CreateEntry] derived from a [Slice] object.
+ *
+ * @param slice the [Slice] object constructed through [toSlice]
+ *
+ * @hide
+ */
+ @SuppressLint("WrongConstant") // custom conversion between jetpack and framework
+ @JvmStatic
+ fun fromSlice(slice: Slice): CreateEntry? {
+ // TODO("Put the right spec and version value")
+ var accountName: CharSequence? = null
+ var icon: Icon? = null
+ var pendingIntent: PendingIntent? = null
+ var credentialCountInfo: MutableMap<String, Int?> = mutableMapOf()
+ var description: CharSequence? = null
+ var lastUsedTime: Instant? = null
+ slice.items.forEach {
+ if (it.hasHint(SLICE_HINT_ACCOUNT_NAME)) {
+ accountName = it.text
+ } else if (it.hasHint(SLICE_HINT_ICON)) {
+ icon = it.icon
+ } else if (it.hasHint(SLICE_HINT_PENDING_INTENT)) {
+ pendingIntent = it.action
+ } else if (it.hasHint(SLICE_HINT_CREDENTIAL_COUNT_INFORMATION)) {
+ credentialCountInfo = convertBundleToCredentialCountInfo(it.bundle)
+ as MutableMap<String, Int?>
+ } else if (it.hasHint(SLICE_HINT_LAST_USED_TIME_MILLIS)) {
+ lastUsedTime = Instant.ofEpochMilli(it.long)
+ } else if (it.hasHint(SLICE_HINT_NOTE)) {
+ description = it.text
+ }
+ }
+ return try {
+ CreateEntry(
+ accountName!!, pendingIntent!!, icon, description,
+ lastUsedTime, credentialCountInfo
+ )
+ } catch (e: Exception) {
+ Log.i(TAG, "fromSlice failed with: " + e.message)
+ null
+ }
+ }
+
+ /** @hide **/
+ @JvmStatic
+ internal fun convertBundleToCredentialCountInfo(bundle: Bundle?):
+ Map<String, Int?> {
+ val credentialCountMap = HashMap<String, Int?>()
+ if (bundle == null) {
+ return credentialCountMap
+ }
+ bundle.keySet().forEach {
+ try {
+ credentialCountMap[it] = bundle.getInt(it)
+ } catch (e: Exception) {
+ Log.i(TAG, "Issue unpacking credential count info bundle: " + e.message)
+ }
+ }
+ return credentialCountMap
+ }
+
+ /** @hide **/
+ @JvmStatic
+ internal fun convertCredentialCountInfoToBundle(
+ credentialCountInformationMap: Map<String, Int?>
+ ): Bundle? {
+ var foundCredentialCount = false
+ val bundle = Bundle()
+ credentialCountInformationMap.forEach {
+ if (it.value != null) {
+ bundle.putInt(it.key, it.value!!)
+ foundCredentialCount = true
+ }
+ }
+ if (!foundCredentialCount) {
+ return null
+ }
+ return bundle
+ }
+
+ @JvmField val CREATOR: Parcelable.Creator<CreateEntry> =
+ object : Parcelable.Creator<CreateEntry> {
+ override fun createFromParcel(p0: Parcel?): CreateEntry? {
+ val createEntry = android.service.credentials.CreateEntry
+ .CREATOR.createFromParcel(p0)
+ return fromSlice(createEntry.slice)
+ }
+
+ @Suppress("ArrayReturn")
+ override fun newArray(size: Int): Array<CreateEntry?> {
+ return arrayOfNulls(size)
+ }
+ }
+ }
+ }
diff --git a/credentials/credentials/src/main/java/androidx/credentials/provider/CredentialProviderService.kt b/credentials/credentials/src/main/java/androidx/credentials/provider/CredentialProviderService.kt
new file mode 100644
index 0000000..6aef8fd
--- /dev/null
+++ b/credentials/credentials/src/main/java/androidx/credentials/provider/CredentialProviderService.kt
@@ -0,0 +1,295 @@
+/*
+ * Copyright 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.credentials.provider
+
+import android.credentials.ClearCredentialStateException
+import android.credentials.GetCredentialException
+import android.os.CancellationSignal
+import android.os.OutcomeReceiver
+import android.service.credentials.BeginCreateCredentialRequest
+import android.service.credentials.BeginCreateCredentialResponse
+import android.service.credentials.BeginGetCredentialRequest
+import android.service.credentials.BeginGetCredentialResponse
+import android.service.credentials.ClearCredentialStateRequest
+import android.service.credentials.CredentialProviderService
+import android.util.Log
+import androidx.annotation.RequiresApi
+import androidx.credentials.exceptions.ClearCredentialException
+import androidx.credentials.exceptions.CreateCredentialException
+import androidx.credentials.provider.utils.BeginCreateCredentialUtil
+import android.app.PendingIntent
+import android.service.credentials.CredentialEntry
+import android.app.Activity
+import androidx.credentials.provider.utils.BeginGetCredentialUtil
+
+/**
+ * A [CredentialProviderService] is a service used to save and retrieve credentials for a given
+ * user, upon the request of a client app that typically uses these credentials for sign-in flows.
+ *
+ * The credential retrieval and creation/saving is mediated by the Android System that
+ * aggregates credentials from multiple credential provider services, and presents them to
+ * the user in the form of a selector UI for credential selections/account selections/
+ * confirmations etc.
+ *
+ * A [CredentialProviderService] is only bound to the Android System for the span
+ * of a [androidx.credentials.CredentialManager] get/create API call. The service is bound only
+ * if :
+ * 1. The service requires the [android.Manifest.permission.BIND_CREDENTIAL_PROVIDER_SERVICE]
+ * permission.
+ * 2. The user has enabled this service as a credential provider from the
+ * settings.
+ *
+ * ## Basic Usage
+ * The basic Credential Manager flow is as such:
+ * - Client app calls one of the APIs exposed in [androidx.credentials.CredentialManager].
+ * - Android system propagates the developer's request to providers that have been
+ * enabled by the user, and can support the [androidx.credentials.Credential] type
+ * specified in the request. We call this the **query phase** of provider communication.
+ * Developer may specify a different set of request parameters to be sent to the provider
+ * during this phase.
+ * - In this query phase, providers, in most cases, will respond with a list of
+ * [CredentialEntry], and an optional list of [Action] entries (for the get flow), and a list
+ * of [CreateEntry] (for the create flow). No actual credentials will be returned in this phase.
+ * - Provider responses are aggregated and presented to the user in the form of a selector UI.
+ * - User selects an entry on the selector.
+ * - Android System invokes the [PendingIntent] associated with this entry, that belongs to the
+ * corresponding provider. We call this the **final phase** of provider communication. The
+ * [PendingIntent] contains the complete request originally created by the developer.
+ * - Provider finishes the [Activity] invoked by the [PendingIntent] by setting the result
+ * as the activity is finished.
+ * - Android System sends back the result to the client app.
+ *
+ * The flow described above minimizes the amount of time a service is bound to the system.
+ * Calls to the service are considered stateless. If a service wishes to maintain state
+ * between the calls, it must do its own state management.
+ * Note: The service's process might be killed by the Android System when unbound, for cases
+ * such as low memory on the device.
+ *
+ * ## Service Registration
+ * In order for Credential Manager to propagate requests to a given provider service, the provider
+ * must:
+ * - Extend this class and implement the abstract methods.
+ * - Declare the [CredentialProviderService.SERVICE_INTERFACE] intent as handled by the service.
+ * - Require the [android.Manifest.permission.BIND_CREDENTIAL_PROVIDER_SERVICE] permission.
+ * - Declare capabilities that the provider supports. Capabilities are essentially credential types
+ * that the provider can handle. Capabilities must be added to the metadata of the service against
+ * [CredentialProviderService.CAPABILITY_META_DATA_KEY].
+ */
+@RequiresApi(34)
+abstract class CredentialProviderService : CredentialProviderService() {
+
+ /** @hide **/
+ final override fun onBeginGetCredential(
+ request: BeginGetCredentialRequest,
+ cancellationSignal: CancellationSignal,
+ callback: OutcomeReceiver<BeginGetCredentialResponse, GetCredentialException>
+ ) {
+ val structuredRequest = BeginGetCredentialUtil.convertToStructuredRequest(request)
+ val outcome = object : OutcomeReceiver<BeginGetCredentialResponse,
+ androidx.credentials.exceptions.GetCredentialException> {
+ override fun onResult(response: BeginGetCredentialResponse?) {
+ Log.i(TAG, "onGetCredentials response returned from provider " +
+ "to jetpack library")
+ callback.onResult(response)
+ }
+
+ override fun onError(error: androidx.credentials.exceptions.GetCredentialException) {
+ super.onError(error)
+ Log.i(TAG, "onGetCredentials error returned from provider " +
+ "to jetpack library")
+ // TODO("Change error code to provider error when ready on framework")
+ callback.onError(GetCredentialException(error.type, error.message))
+ }
+ }
+ this.onBeginGetCredentialRequest(structuredRequest, cancellationSignal, outcome)
+ }
+
+ /** @hide **/
+ final override fun onBeginCreateCredential(
+ request: BeginCreateCredentialRequest,
+ cancellationSignal: CancellationSignal,
+ callback: OutcomeReceiver<BeginCreateCredentialResponse,
+ android.credentials.CreateCredentialException>
+ ) {
+ val outcome = object : OutcomeReceiver<
+ BeginCreateCredentialResponse, CreateCredentialException> {
+ override fun onResult(response: BeginCreateCredentialResponse?) {
+ Log.i(
+ TAG, "onCreateCredential result returned from provider to jetpack " +
+ "library with credential entries size: " + response?.createEntries?.size)
+ callback.onResult(response)
+ }
+ override fun onError(error: CreateCredentialException) {
+ Log.i(
+ TAG, "onCreateCredential result returned from provider to jetpack")
+ super.onError(error)
+ // TODO("Change error code to provider error when ready on framework")
+ callback.onError(android.credentials.CreateCredentialException(
+ error.type, error.message))
+ }
+ }
+ onBeginCreateCredentialRequest(
+ BeginCreateCredentialUtil.convertToStructuredRequest(request),
+ cancellationSignal, outcome)
+ }
+
+ final override fun onClearCredentialState(
+ request: ClearCredentialStateRequest,
+ cancellationSignal: CancellationSignal,
+ callback: OutcomeReceiver<Void, ClearCredentialStateException>
+ ) {
+ val outcome = object : OutcomeReceiver<Void, ClearCredentialException> {
+ override fun onResult(response: Void) {
+ Log.i(
+ TAG, "onClearCredentialState result returned from provider to jetpack ")
+ callback.onResult(response)
+ }
+ override fun onError(error: ClearCredentialException) {
+ Log.i(
+ TAG, "onClearCredentialState result returned from provider to jetpack")
+ super.onError(error)
+ // TODO("Change error code to provider error when ready on framework")
+ callback.onError(ClearCredentialStateException(error.type, error.message))
+ }
+ }
+ onClearCredentialStateRequest(request, cancellationSignal, outcome)
+ }
+
+ /**
+ * Called by the Android System in response to a client app calling
+ * [androidx.credentials.CredentialManager.clearCredentialState]. A client app typically
+ * calls this API on instances like sign-out when the intention is that the providers clear
+ * any state that they may have maintained for the given user.
+ *
+ * You should invoked this api after your user signs out of your app to notify all credential
+ * providers that any stored credential session for the given app should be cleared.
+ *
+ * An example scenario of a state that is maintained and is expected to be cleared on this
+ * call, is when an active credential session is being stored to limit sign-in options
+ * in the result of subsequent get-request calls. When a user explicitly signs out of the app,
+ * the next time, the client app may want their users to see all options and hence will call
+ * this API first to make sure credential providers can clear the state maintained previously.
+ *
+ * @param [request] the [androidx.credentials.ClearCredentialStateRequest] to handle
+ * @param cancellationSignal signal for observing cancellation requests. The system will
+ * use this to notify you that the result is no longer needed and you should stop
+ * handling it in order to save your resources
+ * @param callback the callback object to be used to notify the response or error
+ */
+ abstract fun onClearCredentialStateRequest(
+ request: ClearCredentialStateRequest,
+ cancellationSignal: CancellationSignal,
+ callback: OutcomeReceiver<Void,
+ ClearCredentialException>
+ )
+
+ /**
+ * Called by the Android System in response to a client app calling
+ * [androidx.credentials.CredentialManager.getCredential], to get a credential
+ * sourced from a credential provider installed on the device.
+ *
+ * Credential provider services must extend this method in order to handle a
+ * [BeginGetCredentialRequest] request. Once processed, the service must call one of the
+ * [callback] methods to notify the result of the request.
+ *
+ * This API call is referred to as the **query phase** of the original get request from
+ * the client app. In this phase, provider must go over all the
+ * [android.service.credentials.BeginGetCredentialOption], and add corresponding a
+ * [CredentialEntry] to the [BeginGetCredentialResponse]. Each [CredentialEntry] should
+ * contain meta-data to be shown on the selector UI. In addition, each [CredentialEntry]
+ * must contain a [PendingIntent].
+ * Optionally, providers can also add [Action] entries for any non-credential related actions
+ * that they want to offer to the users e.g. opening app, managing credentials etc.
+ *
+ * When user selects one of the [CredentialEntry], **final phase** of the original client's
+ * get-request flow starts. The Android System attached the complete
+ * [androidx.credentials.provider.ProviderGetCredentialRequest] to an intent extra of the
+ * activity that is started by the pending intent. The request must be retrieved through
+ * [PendingIntentHandler.retrieveProviderGetCredentialRequest]. This final request
+ * will only contain a single [androidx.credentials.CredentialOption] that contains the
+ * parameters of the credential the user has requested. The provider service must retrieve this
+ * credential and return through [PendingIntentHandler.setGetCredentialResponse].
+ *
+ * **Handling locked provider apps**
+ * If the provider app is locked, and the provider cannot provide any meta-data based
+ * [CredentialEntry], provider must set an [AuthenticationAction] on the
+ * [BeginGetCredentialResponse]. The [PendingIntent] set on this entry must lead the user
+ * to an >unlock activity. Once unlocked, the provider must retrieve all credentials,
+ * and set the list of [CredentialEntry] and the list of optional [Action] as a result
+ * of the >unlock activity through [PendingIntentHandler.setBeginGetCredentialResponse].
+ *
+ * @see CredentialEntry for how an entry representing a credential must be built
+ * @see Action for how a non-credential related action should be built
+ * @see AuthenticationAction for how an entry that navigates the user to an unlock flow
+ * can be built
+ *
+ * @param [request] the [ProviderGetCredentialRequest] to handle
+ * See [BeginGetCredentialResponse] for the response to be returned
+ * @param cancellationSignal signal for observing cancellation requests. The system will
+ * use this to notify you that the result is no longer needed and you should stop
+ * handling it in order to save your resources
+ * @param callback the callback object to be used to notify the response or error
+ */
+ abstract fun onBeginGetCredentialRequest(
+ request: BeginGetCredentialRequest,
+ cancellationSignal: CancellationSignal,
+ callback: OutcomeReceiver<BeginGetCredentialResponse,
+ androidx.credentials.exceptions.GetCredentialException>
+ )
+
+ /**
+ * Called by the Android System in response to a client app calling
+ * [androidx.credentials.CredentialManager.createCredential], to create/save a credential
+ * with a credential provider installed on the device.
+ *
+ * Credential provider services must extend this method in order to handle a
+ * [BeginCreateCredentialRequest] request. Once processed, the service must call one of the
+ * [callback] methods to notify the result of the request.
+ *
+ * This API call is referred to as the **query phase** of the original create request from
+ * the client app. In this phase, provider must process the request parameters in the
+ * [BeginCreateCredentialRequest] and return a list of [CreateEntry] whereby every
+ * entry represents an account/group where the user will be storing the credential. Each
+ * [CreateEntry] must contain a [PendingIntent] that will lead the user to an activity
+ * in the credential provider's app that will complete the actual credential creation.
+ *
+ * When user selects one of the [CreateEntry], the associated [PendingIntent] will be invoked
+ * and the provider will receive the complete request as part of the extras in the resulting
+ * activity. Provider must retrieve the request through
+ * [PendingIntentHandler.retrieveProviderCreateCredentialRequest].
+ * Once the activity is complete, and the credential is created, provider must set back the
+ * response through [PendingIntentHandler.setCreateCredentialResponse].
+ *
+ * @param [request] the [BeginCreateCredentialRequest] to handle
+ * See [BeginCreateCredentialResponse] for the response to be returned
+ * @param cancellationSignal signal for observing cancellation requests. The system will
+ * use this to notify you that the result is no longer needed and you should stop
+ * handling it in order to save your resources
+ * @param callback the callback object to be used to notify the response or error
+ */
+ abstract fun onBeginCreateCredentialRequest(
+ request: BeginCreateCredentialRequest,
+ cancellationSignal: CancellationSignal,
+ callback: OutcomeReceiver<BeginCreateCredentialResponse,
+ CreateCredentialException>
+ )
+
+ /** @hide **/
+ companion object {
+ private const val TAG = "BaseService"
+ }
+}
diff --git a/credentials/credentials/src/main/java/androidx/credentials/provider/CustomCredentialEntry.kt b/credentials/credentials/src/main/java/androidx/credentials/provider/CustomCredentialEntry.kt
new file mode 100644
index 0000000..e34663b
--- /dev/null
+++ b/credentials/credentials/src/main/java/androidx/credentials/provider/CustomCredentialEntry.kt
@@ -0,0 +1,365 @@
+/*
+ * Copyright 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package androidx.credentials.provider
+
+import android.annotation.SuppressLint
+import android.app.PendingIntent
+import android.app.slice.Slice
+import android.app.slice.SliceSpec
+import android.content.Context
+import android.graphics.drawable.Icon
+import android.net.Uri
+import android.os.Bundle
+import android.os.Parcel
+import android.os.Parcelable
+import android.service.credentials.BeginGetCredentialOption
+import android.util.Log
+import androidx.annotation.NonNull
+import androidx.annotation.RequiresApi
+import androidx.annotation.VisibleForTesting
+import androidx.credentials.R
+import java.time.Instant
+import java.util.Collections
+
+/**
+ * Custom credential entry for a custom credential tyoe that is displayed on the account
+ * selector UI.
+ *
+ * Each entry corresponds to an account that can provide a credential.
+ *
+ * @property title the title shown with this entry on the selector UI
+ * @property subtitle the subTitle shown with this entry on the selector UI
+ * @property lastUsedTime the last used time the credential underlying this entry was
+ * used by the user
+ * @property icon the icon to be displayed with this entry on the selector UI
+ * @property pendingIntent the [PendingIntent] to be invoked when this entry
+ * is selected by the user
+ * @property typeDisplayName the friendly name to be displayed on the UI for
+ * the type of the credential
+ * @property isAutoSelectAllowed whether this entry is allowed to be auto
+ * selected if it is the only one on the UI. Note that setting this value
+ * to true does not guarantee this behavior. The developer must also set this
+ * to true, and the framework must determine that only one entry is present
+ */
+@RequiresApi(34)
+class CustomCredentialEntry internal constructor(
+ type: String,
+ val title: CharSequence,
+ val pendingIntent: PendingIntent,
+ @get:Suppress("AutoBoxing")
+ val isAutoSelectAllowed: Boolean,
+ val subtitle: CharSequence?,
+ val typeDisplayName: CharSequence?,
+ val icon: Icon?,
+ val lastUsedTime: Instant?,
+ beginGetCredentialOption: BeginGetCredentialOption
+ ) : android.service.credentials.CredentialEntry(
+ beginGetCredentialOption,
+ toSlice(
+ type,
+ title,
+ subtitle,
+ pendingIntent,
+ typeDisplayName,
+ lastUsedTime,
+ icon,
+ isAutoSelectAllowed,
+ beginGetCredentialOption
+ )
+) {
+ init {
+ require(type.isNotEmpty()) { "type must not be empty" }
+ require(title.isNotEmpty()) { "title must not be empty" }
+ }
+ constructor(
+ context: Context,
+ title: CharSequence,
+ pendingIntent: PendingIntent,
+ beginGetCredentialOption: BeginGetCredentialOption,
+ subtitle: CharSequence? = null,
+ typeDisplayName: CharSequence? = null,
+ lastUsedTime: Instant? = null,
+ icon: Icon? = Icon.createWithResource(context, R.drawable.ic_other_sign_in),
+ @Suppress("AutoBoxing")
+ isAutoSelectAllowed: Boolean = false
+ ) : this(
+ beginGetCredentialOption.type,
+ title,
+ pendingIntent,
+ isAutoSelectAllowed,
+ subtitle,
+ typeDisplayName,
+ icon,
+ lastUsedTime,
+ beginGetCredentialOption
+ )
+
+ override fun describeContents(): Int {
+ return 0
+ }
+
+ override fun writeToParcel(@NonNull dest: Parcel, flags: Int) {
+ super.writeToParcel(dest, flags)
+ }
+
+ @Suppress("AcronymName")
+ @RequiresApi(34)
+ companion object {
+ private const val TAG = "CredentialEntry"
+ @VisibleForTesting(otherwise = VisibleForTesting.PRIVATE)
+ internal const val SLICE_HINT_TYPE_DISPLAY_NAME =
+ "androidx.credentials.provider.credentialEntry.SLICE_HINT_TYPE_DISPLAY_NAME"
+ @VisibleForTesting(otherwise = VisibleForTesting.PRIVATE)
+ internal const val SLICE_HINT_TITLE =
+ "androidx.credentials.provider.credentialEntry.SLICE_HINT_USER_NAME"
+ @VisibleForTesting(otherwise = VisibleForTesting.PRIVATE)
+ internal const val SLICE_HINT_SUBTITLE =
+ "androidx.credentials.provider.credentialEntry.SLICE_HINT_CREDENTIAL_TYPE_DISPLAY_NAME"
+ @VisibleForTesting(otherwise = VisibleForTesting.PRIVATE)
+ internal const val SLICE_HINT_LAST_USED_TIME_MILLIS =
+ "androidx.credentials.provider.credentialEntry.SLICE_HINT_LAST_USED_TIME_MILLIS"
+ @VisibleForTesting(otherwise = VisibleForTesting.PRIVATE)
+ internal const val SLICE_HINT_ICON =
+ "androidx.credentials.provider.credentialEntry.SLICE_HINT_PROFILE_ICON"
+ @VisibleForTesting(otherwise = VisibleForTesting.PRIVATE)
+ internal const val SLICE_HINT_PENDING_INTENT =
+ "androidx.credentials.provider.credentialEntry.SLICE_HINT_PENDING_INTENT"
+ @VisibleForTesting(otherwise = VisibleForTesting.PRIVATE)
+ internal const val SLICE_HINT_AUTO_ALLOWED =
+ "androidx.credentials.provider.credentialEntry.SLICE_HINT_AUTO_ALLOWED"
+ @VisibleForTesting(otherwise = VisibleForTesting.PRIVATE)
+ internal const val SLICE_HINT_OPTION_BUNDLE =
+ "androidx.credentials.provider.credentialEntry.SLICE_HINT_OPTION_BUNDLE"
+ @VisibleForTesting(otherwise = VisibleForTesting.PRIVATE)
+ internal const val SLICE_HINT_OPTION_ID =
+ "androidx.credentials.provider.credentialEntry.SLICE_HINT_OPTION_ID"
+
+ @VisibleForTesting(otherwise = VisibleForTesting.PRIVATE)
+ internal const val AUTO_SELECT_TRUE_STRING = "true"
+ @VisibleForTesting(otherwise = VisibleForTesting.PRIVATE)
+ internal const val AUTO_SELECT_FALSE_STRING = "false"
+
+ /** @hide */
+ @JvmStatic
+ internal fun toSlice(
+ type: String,
+ title: CharSequence,
+ subtitle: CharSequence?,
+ pendingIntent: PendingIntent,
+ typeDisplayName: CharSequence?,
+ lastUsedTime: Instant?,
+ icon: Icon?,
+ isAutoSelectAllowed: Boolean?,
+ beginGetCredentialOption: BeginGetCredentialOption
+ ): Slice {
+ // TODO("Put the right revision value")
+ val autoSelectAllowed = if (isAutoSelectAllowed == true) {
+ AUTO_SELECT_TRUE_STRING
+ } else {
+ AUTO_SELECT_FALSE_STRING
+ }
+ val sliceBuilder = Slice.Builder(Uri.EMPTY, SliceSpec(
+ type, 1))
+ .addText(typeDisplayName, /*subType=*/null,
+ listOf(SLICE_HINT_TYPE_DISPLAY_NAME))
+ .addText(title, /*subType=*/null,
+ listOf(SLICE_HINT_TITLE))
+ .addText(subtitle, /*subType=*/null,
+ listOf(SLICE_HINT_SUBTITLE))
+ .addText(autoSelectAllowed, /*subType=*/null,
+ listOf(SLICE_HINT_AUTO_ALLOWED))
+ .addBundle(beginGetCredentialOption.candidateQueryData,
+ /*subType=*/null,
+ listOf(SLICE_HINT_OPTION_BUNDLE))
+ .addText(
+ beginGetCredentialOption.id,
+ /*subType=*/null,
+ listOf(SLICE_HINT_OPTION_ID)
+ )
+
+ if (lastUsedTime != null) {
+ sliceBuilder.addLong(lastUsedTime.toEpochMilli(),
+ /*subType=*/null,
+ listOf(SLICE_HINT_LAST_USED_TIME_MILLIS))
+ }
+ if (icon != null) {
+ sliceBuilder.addIcon(icon, /*subType=*/null,
+ listOf(SLICE_HINT_ICON))
+ }
+ sliceBuilder.addAction(pendingIntent,
+ Slice.Builder(sliceBuilder)
+ .addHints(Collections.singletonList(SLICE_HINT_PENDING_INTENT))
+ .build(),
+ /*subType=*/null)
+ return sliceBuilder.build()
+ }
+
+ /**
+ * Returns an instance of [CustomCredentialEntry] derived from a [Slice] object.
+ *
+ * @param slice the [Slice] object constructed through [toSlice]
+ *
+ * @hide
+ */
+ @SuppressLint("WrongConstant") // custom conversion between jetpack and framework
+ @JvmStatic
+ fun fromSlice(slice: Slice): CustomCredentialEntry? {
+ val type: String = slice.spec!!.type
+ var typeDisplayName: CharSequence? = null
+ var title: CharSequence? = null
+ var subtitle: CharSequence? = null
+ var icon: Icon? = null
+ var pendingIntent: PendingIntent? = null
+ var lastUsedTime: Instant? = null
+ var autoSelectAllowed = false
+ var beginGetCredentialOptionBundle: Bundle? = null
+ var beginGetCredentialOptionId: CharSequence? = null
+
+ slice.items.forEach {
+ if (it.hasHint(SLICE_HINT_TYPE_DISPLAY_NAME)) {
+ typeDisplayName = it.text
+ } else if (it.hasHint(SLICE_HINT_TITLE)) {
+ title = it.text
+ } else if (it.hasHint(SLICE_HINT_SUBTITLE)) {
+ subtitle = it.text
+ } else if (it.hasHint(SLICE_HINT_ICON)) {
+ icon = it.icon
+ } else if (it.hasHint(SLICE_HINT_PENDING_INTENT)) {
+ pendingIntent = it.action
+ } else if (it.hasHint(SLICE_HINT_OPTION_BUNDLE)) {
+ beginGetCredentialOptionBundle = it.bundle
+ } else if (it.hasHint(SLICE_HINT_OPTION_ID)) {
+ beginGetCredentialOptionId = it.text
+ } else if (it.hasHint(SLICE_HINT_LAST_USED_TIME_MILLIS)) {
+ lastUsedTime = Instant.ofEpochMilli(it.long)
+ } else if (it.hasHint(SLICE_HINT_AUTO_ALLOWED)) {
+ val autoSelectValue = it.text
+ if (autoSelectValue == AUTO_SELECT_TRUE_STRING) {
+ autoSelectAllowed = true
+ }
+ }
+ }
+
+ return try {
+ CustomCredentialEntry(
+ type,
+ title!!,
+ pendingIntent!!,
+ autoSelectAllowed,
+ subtitle,
+ typeDisplayName,
+ icon!!,
+ lastUsedTime,
+ BeginGetCredentialOption(
+ beginGetCredentialOptionId!!.toString(),
+ type,
+ beginGetCredentialOptionBundle!!
+ )
+ )
+ } catch (e: Exception) {
+ Log.i(TAG, "fromSlice failed with: " + e.message)
+ null
+ }
+ }
+
+ @JvmField val CREATOR: Parcelable.Creator<CustomCredentialEntry> = object :
+ Parcelable.Creator<CustomCredentialEntry> {
+ override fun createFromParcel(p0: Parcel?): CustomCredentialEntry? {
+ val baseEntry =
+ android.service.credentials.CredentialEntry.CREATOR.createFromParcel(p0)
+ return fromSlice(baseEntry.slice)
+ }
+
+ @Suppress("ArrayReturn")
+ override fun newArray(size: Int): Array<CustomCredentialEntry?> {
+ return arrayOfNulls(size)
+ }
+ }
+ }
+
+ /** Builder for [CustomCredentialEntry] */
+ class Builder(
+ private val context: Context,
+ private val type: String,
+ private val title: CharSequence,
+ private val pendingIntent: PendingIntent,
+ private val beginGetCredentialOption: BeginGetCredentialOption
+ ) {
+ private var subtitle: CharSequence? = null
+ private var lastUsedTime: Instant? = null
+ private var typeDisplayName: CharSequence? = null
+ private var icon: Icon? = null
+ private var autoSelectAllowed = false
+
+ /** Sets a displayName to be shown on the UI with this entry. */
+ fun setSubtitle(subtitle: CharSequence?): Builder {
+ this.subtitle = subtitle
+ return this
+ }
+
+ /** Sets the display name of this credential type, to be shown on the UI with this entry. */
+ fun setTypeDisplayName(typeDisplayName: CharSequence?): Builder {
+ this.typeDisplayName = typeDisplayName
+ return this
+ }
+
+ /**
+ * Sets the icon to be show on the UI.
+ * If no icon is set, a default icon representing a custom credential will be set.
+ */
+ fun setIcon(icon: Icon?): Builder {
+ this.icon = icon
+ return this
+ }
+
+ /**
+ * Sets whether the entry should be auto-selected.
+ * The value is false by default
+ */
+ @Suppress("MissingGetterMatchingBuilder")
+ fun setAutoSelectAllowed(autoSelectAllowed: Boolean): Builder {
+ this.autoSelectAllowed = autoSelectAllowed
+ return this
+ }
+
+ /**
+ * Sets the last used time of this account. This information will be used to sort the
+ * entries on the selector.
+ */
+ fun setLastUsedTime(lastUsedTime: Instant?): Builder {
+ this.lastUsedTime = lastUsedTime
+ return this
+ }
+
+ /** Builds an instance of [CustomCredentialEntry] */
+ fun build(): CustomCredentialEntry {
+ if (icon == null) {
+ icon = Icon.createWithResource(context, R.drawable.ic_other_sign_in)
+ }
+ return CustomCredentialEntry(
+ type,
+ title,
+ pendingIntent,
+ autoSelectAllowed,
+ subtitle,
+ typeDisplayName,
+ icon!!,
+ lastUsedTime,
+ beginGetCredentialOption
+ )
+ }
+ }
+}
diff --git a/credentials/credentials/src/main/java/androidx/credentials/provider/PasswordCredentialEntry.kt b/credentials/credentials/src/main/java/androidx/credentials/provider/PasswordCredentialEntry.kt
new file mode 100644
index 0000000..69ef526
--- /dev/null
+++ b/credentials/credentials/src/main/java/androidx/credentials/provider/PasswordCredentialEntry.kt
@@ -0,0 +1,368 @@
+/*
+ * Copyright 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.credentials.provider
+
+import android.annotation.SuppressLint
+import android.app.PendingIntent
+import android.app.slice.Slice
+import android.app.slice.SliceSpec
+import android.content.Context
+import android.graphics.drawable.Icon
+import android.net.Uri
+import android.os.Bundle
+import android.os.Parcel
+import android.os.Parcelable
+import android.service.credentials.CredentialEntry
+import android.util.Log
+import androidx.annotation.NonNull
+import androidx.annotation.RequiresApi
+import androidx.annotation.VisibleForTesting
+import androidx.credentials.PasswordCredential
+import androidx.credentials.R
+import java.time.Instant
+import java.util.Collections
+
+/**
+ * A password credential entry that is displayed on the account selector UI. This
+ * entry denotes that a credential of type [PasswordCredential.TYPE_PASSWORD_CREDENTIAL]
+ * is available for the user to select.
+ *
+ * Once this entry is selected, the corresponding [pendingIntent] will be invoked. The provider
+ * can then show any activity they wish to. Before finishing the activity, provider must
+ * set the final [androidx.credentials.GetCredentialResponse] through the
+ * [PendingIntentHandler.setGetCredentialResponse] helper API.
+ *
+ * @property username the username of the account holding the password credential
+ * @property displayName the displayName of the account holding the password credential
+ * @property lastUsedTime the last used time of this entry
+ * @property icon the icon to be displayed with this entry on the selector
+ * @property pendingIntent the [PendingIntent] to be invoked when user selects
+ * this entry
+ * @property isAutoSelectAllowed whether this entry is allowed to be auto
+ * selected if it is the only one on the UI. Note that setting this value
+ * to true does not guarantee this behavior. The developer must also set this
+ * to true, and the framework must determine that this is the only entry available for the user.
+ *
+ * @throws IllegalArgumentException if [username] is empty
+ *
+ * @see CustomCredentialEntry
+ */
+@RequiresApi(34)
+class PasswordCredentialEntry internal constructor(
+ val username: CharSequence,
+ val displayName: CharSequence?,
+ val typeDisplayName: CharSequence,
+ val pendingIntent: PendingIntent,
+ val lastUsedTime: Instant?,
+ val icon: Icon?,
+ val isAutoSelectAllowed: Boolean,
+ beginGetPasswordOption: BeginGetPasswordOption
+ ) : CredentialEntry(
+ beginGetPasswordOption,
+ toSlice(
+ PasswordCredential.TYPE_PASSWORD_CREDENTIAL,
+ username,
+ displayName,
+ pendingIntent,
+ typeDisplayName,
+ lastUsedTime,
+ icon,
+ isAutoSelectAllowed,
+ beginGetPasswordOption
+ )
+) {
+ init {
+ require(username.isNotEmpty()) { "username must not be empty" }
+ }
+ constructor(
+ context: Context,
+ username: CharSequence,
+ pendingIntent: PendingIntent,
+ beginGetPasswordOption: BeginGetPasswordOption,
+ displayName: CharSequence? = null,
+ lastUsedTime: Instant? = null,
+ icon: Icon? = Icon.createWithResource(context, R.drawable.ic_password),
+ ) : this(
+ username,
+ displayName,
+ typeDisplayName = context.getString(
+ R.string.android_credentials_TYPE_PASSWORD_CREDENTIAL),
+ pendingIntent,
+ lastUsedTime,
+ icon,
+ isAutoSelectAllowed = false,
+ beginGetPasswordOption,
+ )
+
+ override fun describeContents(): Int {
+ return 0
+ }
+
+ override fun writeToParcel(@NonNull dest: Parcel, flags: Int) {
+ super.writeToParcel(dest, flags)
+ }
+
+ @Suppress("AcronymName")
+ companion object CREATOR {
+ private const val TAG = "PasswordCredentialEntry"
+
+ @VisibleForTesting(otherwise = VisibleForTesting.PRIVATE)
+ internal const val SLICE_HINT_TYPE_DISPLAY_NAME =
+ "androidx.credentials.provider.credentialEntry.SLICE_HINT_TYPE_DISPLAY_NAME"
+
+ @VisibleForTesting(otherwise = VisibleForTesting.PRIVATE)
+ internal const val SLICE_HINT_TITLE =
+ "androidx.credentials.provider.credentialEntry.SLICE_HINT_USER_NAME"
+
+ @VisibleForTesting(otherwise = VisibleForTesting.PRIVATE)
+ internal const val SLICE_HINT_SUBTITLE =
+ "androidx.credentials.provider.credentialEntry.SLICE_HINT_CREDENTIAL_TYPE_DISPLAY_NAME"
+
+ @VisibleForTesting(otherwise = VisibleForTesting.PRIVATE)
+ internal const val SLICE_HINT_LAST_USED_TIME_MILLIS =
+ "androidx.credentials.provider.credentialEntry.SLICE_HINT_LAST_USED_TIME_MILLIS"
+
+ @VisibleForTesting(otherwise = VisibleForTesting.PRIVATE)
+ internal const val SLICE_HINT_ICON =
+ "androidx.credentials.provider.credentialEntry.SLICE_HINT_PROFILE_ICON"
+
+ @VisibleForTesting(otherwise = VisibleForTesting.PRIVATE)
+ internal const val SLICE_HINT_PENDING_INTENT =
+ "androidx.credentials.provider.credentialEntry.SLICE_HINT_PENDING_INTENT"
+
+ @VisibleForTesting(otherwise = VisibleForTesting.PRIVATE)
+ internal const val SLICE_HINT_OPTION_BUNDLE =
+ "androidx.credentials.provider.credentialEntry.SLICE_HINT_OPTION_BUNDLE"
+
+ @VisibleForTesting(otherwise = VisibleForTesting.PRIVATE)
+ internal const val SLICE_HINT_OPTION_ID =
+ "androidx.credentials.provider.credentialEntry.SLICE_HINT_OPTION_ID"
+
+ @VisibleForTesting(otherwise = VisibleForTesting.PRIVATE)
+ internal const val SLICE_HINT_AUTO_ALLOWED =
+ "androidx.credentials.provider.credentialEntry.SLICE_HINT_AUTO_ALLOWED"
+
+ @VisibleForTesting(otherwise = VisibleForTesting.PRIVATE)
+ internal const val AUTO_SELECT_TRUE_STRING = "true"
+
+ @VisibleForTesting(otherwise = VisibleForTesting.PRIVATE)
+ internal const val AUTO_SELECT_FALSE_STRING = "false"
+
+ /** @hide */
+ @JvmStatic
+ internal fun toSlice(
+ type: String,
+ title: CharSequence,
+ subTitle: CharSequence?,
+ pendingIntent: PendingIntent,
+ typeDisplayName: CharSequence?,
+ lastUsedTime: Instant?,
+ icon: Icon?,
+ isAutoSelectAllowed: Boolean,
+ beginGetPasswordCredentialOption: BeginGetPasswordOption
+ ): Slice {
+ // TODO("Put the right revision value")
+ val autoSelectAllowed = if (isAutoSelectAllowed) {
+ AUTO_SELECT_TRUE_STRING
+ } else {
+ AUTO_SELECT_FALSE_STRING
+ }
+ val sliceBuilder = Slice.Builder(
+ Uri.EMPTY, SliceSpec(
+ type, 1
+ )
+ )
+ .addText(
+ typeDisplayName, /*subType=*/null,
+ listOf(SLICE_HINT_TYPE_DISPLAY_NAME)
+ )
+ .addText(
+ title, /*subType=*/null,
+ listOf(SLICE_HINT_TITLE)
+ )
+ .addText(
+ subTitle, /*subType=*/null,
+ listOf(SLICE_HINT_SUBTITLE)
+ )
+ .addText(
+ autoSelectAllowed, /*subType=*/null,
+ listOf(SLICE_HINT_AUTO_ALLOWED)
+ )
+ .addBundle(
+ beginGetPasswordCredentialOption.candidateQueryData,
+ /*subType=*/null,
+ listOf(SLICE_HINT_OPTION_BUNDLE)
+ )
+ .addText(
+ beginGetPasswordCredentialOption.id,
+ /*subType=*/null,
+ listOf(SLICE_HINT_OPTION_ID)
+ )
+ if (lastUsedTime != null) {
+ sliceBuilder.addLong(
+ lastUsedTime.toEpochMilli(),
+ /*subType=*/null,
+ listOf(SLICE_HINT_LAST_USED_TIME_MILLIS)
+ )
+ }
+ if (icon != null) {
+ sliceBuilder.addIcon(
+ icon, /*subType=*/null,
+ listOf(SLICE_HINT_ICON)
+ )
+ }
+ sliceBuilder.addAction(
+ pendingIntent,
+ Slice.Builder(sliceBuilder)
+ .addHints(Collections.singletonList(SLICE_HINT_PENDING_INTENT))
+ .build(),
+ /*subType=*/null
+ )
+ return sliceBuilder.build()
+ }
+
+ /**
+ * Returns an instance of [CustomCredentialEntry] derived from a [Slice] object.
+ *
+ * @param slice the [Slice] object constructed through [toSlice]
+ *
+ * @hide
+ */
+ @SuppressLint("WrongConstant") // custom conversion between jetpack and framework
+ @JvmStatic
+ fun fromSlice(slice: Slice): PasswordCredentialEntry? {
+ var typeDisplayName: CharSequence? = null
+ var title: CharSequence? = null
+ var subTitle: CharSequence? = null
+ var icon: Icon? = null
+ var pendingIntent: PendingIntent? = null
+ var lastUsedTime: Instant? = null
+ var autoSelectAllowed = false
+ var beginGetPasswordOptionBundle: Bundle? = null
+ var beginGetPasswordOptionId: CharSequence? = null
+
+ slice.items.forEach {
+ if (it.hasHint(SLICE_HINT_TYPE_DISPLAY_NAME)) {
+ typeDisplayName = it.text
+ } else if (it.hasHint(SLICE_HINT_TITLE)) {
+ title = it.text
+ } else if (it.hasHint(SLICE_HINT_SUBTITLE)) {
+ subTitle = it.text
+ } else if (it.hasHint(SLICE_HINT_ICON)) {
+ icon = it.icon
+ } else if (it.hasHint(SLICE_HINT_PENDING_INTENT)) {
+ pendingIntent = it.action
+ } else if (it.hasHint(SLICE_HINT_OPTION_ID)) {
+ beginGetPasswordOptionId = it.text
+ } else if (it.hasHint(SLICE_HINT_OPTION_BUNDLE)) {
+ beginGetPasswordOptionBundle = it.bundle
+ } else if (it.hasHint(SLICE_HINT_LAST_USED_TIME_MILLIS)) {
+ lastUsedTime = Instant.ofEpochMilli(it.long)
+ } else if (it.hasHint(SLICE_HINT_AUTO_ALLOWED)) {
+ val autoSelectValue = it.text
+ if (autoSelectValue == AUTO_SELECT_TRUE_STRING) {
+ autoSelectAllowed = true
+ }
+ }
+ }
+
+ return try {
+ PasswordCredentialEntry(
+ title!!,
+ subTitle,
+ typeDisplayName!!,
+ pendingIntent!!,
+ lastUsedTime,
+ icon!!,
+ autoSelectAllowed,
+ BeginGetPasswordOption.createFrom(
+ beginGetPasswordOptionBundle!!,
+ beginGetPasswordOptionId!!.toString()
+ )
+ )
+ } catch (e: Exception) {
+ Log.i(TAG, "fromSlice failed with: " + e.message)
+ null
+ }
+ }
+
+ @JvmField val CREATOR: Parcelable.Creator<PasswordCredentialEntry> = object :
+ Parcelable.Creator<PasswordCredentialEntry> {
+ override fun createFromParcel(p0: Parcel?): PasswordCredentialEntry? {
+ val credentialEntry = CredentialEntry.CREATOR.createFromParcel(p0)
+ return fromSlice(credentialEntry.slice)
+ }
+
+ @Suppress("ArrayReturn")
+ override fun newArray(size: Int): Array<PasswordCredentialEntry?> {
+ return arrayOfNulls(size)
+ }
+ }
+ }
+ /** Builder for [PasswordCredentialEntry] */
+ class Builder(
+ private val context: Context,
+ private val username: CharSequence,
+ private val pendingIntent: PendingIntent,
+ private val beginGetPasswordOption: BeginGetPasswordOption
+ ) {
+ private var displayName: CharSequence? = null
+ private var lastUsedTime: Instant? = null
+ private var icon: Icon? = null
+ private var autoSelectAllowed = false
+
+ /** Sets a displayName to be shown on the UI with this entry */
+ fun setDisplayName(displayName: CharSequence?): Builder {
+ this.displayName = displayName
+ return this
+ }
+
+ /** Sets the icon to be shown on the UI with this entry */
+ fun setIcon(icon: Icon?): Builder {
+ this.icon = icon
+ return this
+ }
+
+ /**
+ * Sets the last used time of this account. This information will be used to sort the
+ * entries on the selector.
+ */
+ fun setLastUsedTime(lastUsedTime: Instant?): Builder {
+ this.lastUsedTime = lastUsedTime
+ return this
+ }
+
+ /** Builds an instance of [PasswordCredentialEntry] */
+ fun build(): PasswordCredentialEntry {
+ if (icon == null) {
+ icon = Icon.createWithResource(context, R.drawable.ic_password)
+ }
+ val typeDisplayName = context.getString(
+ R.string.android_credentials_TYPE_PASSWORD_CREDENTIAL)
+ return PasswordCredentialEntry(
+ username,
+ displayName,
+ typeDisplayName,
+ pendingIntent,
+ lastUsedTime,
+ icon!!,
+ autoSelectAllowed,
+ beginGetPasswordOption
+ )
+ }
+ }
+}
diff --git a/credentials/credentials/src/main/java/androidx/credentials/provider/PendingIntentHandler.kt b/credentials/credentials/src/main/java/androidx/credentials/provider/PendingIntentHandler.kt
new file mode 100644
index 0000000..e44c659
--- /dev/null
+++ b/credentials/credentials/src/main/java/androidx/credentials/provider/PendingIntentHandler.kt
@@ -0,0 +1,246 @@
+/*
+ * Copyright 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.credentials.provider
+
+import android.app.PendingIntent
+import android.content.Intent
+import android.credentials.CreateCredentialResponse
+import android.service.credentials.BeginGetCredentialRequest
+import android.service.credentials.CreateCredentialRequest
+import android.service.credentials.CredentialProviderService
+import android.util.Log
+import android.service.credentials.CredentialEntry
+import android.service.credentials.BeginGetCredentialResponse
+import android.service.credentials.BeginCreateCredentialResponse
+import androidx.annotation.RequiresApi
+import androidx.credentials.GetCredentialResponse
+import android.app.Activity
+import androidx.credentials.exceptions.CreateCredentialException
+import androidx.credentials.exceptions.GetCredentialException
+import androidx.credentials.provider.utils.BeginGetCredentialUtil
+
+/**
+ * PendingIntentHandler to be used by credential providers to extract requests from
+ * [PendingIntent] invoked when a given [CreateEntry], or a [CustomCredentialEntry]
+ * is selected by the user.
+ *
+ * This handler can also be used to set [android.credentials.CreateCredentialResponse] and
+ * [android.credentials.GetCredentialResponse] on the result of the activity
+ * invoked by the [PendingIntent]
+ */
+@RequiresApi(34)
+class PendingIntentHandler {
+ companion object {
+ private const val TAG = "PendingIntentHandler"
+
+ /**
+ * Extracts the [ProviderCreateCredentialRequest] from the provider's
+ * [PendingIntent] invoked by the Android system.
+ *
+ * @param intent the intent associated with the [Activity] invoked through the
+ * [PendingIntent]
+ *
+ * @throws NullPointerException If [intent] is null
+ */
+ @JvmStatic
+ fun retrieveProviderCreateCredentialRequest(intent: Intent):
+ ProviderCreateCredentialRequest? {
+ val frameworkReq: CreateCredentialRequest? =
+ intent.getParcelableExtra(
+ CredentialProviderService
+ .EXTRA_CREATE_CREDENTIAL_REQUEST, CreateCredentialRequest::class.java
+ )
+ if (frameworkReq == null) {
+ Log.i(TAG, "Request not found in pendingIntent")
+ return frameworkReq
+ }
+ return ProviderCreateCredentialRequest(
+ androidx.credentials.CreateCredentialRequest
+ .createFrom(
+ frameworkReq.type,
+ frameworkReq.data,
+ frameworkReq.data,
+ requireSystemProvider = false) ?: return null,
+ frameworkReq.callingAppInfo)
+ }
+
+ /**
+ * Extracts the [BeginGetCredentialRequest] from the provider's
+ * [PendingIntent] invoked by the Android system when the user
+ * selects an [AuthenticationAction].
+ *
+ * @param intent the intent associated with the [Activity] invoked through the
+ * [PendingIntent]
+ *
+ * @throws NullPointerException If [intent] is null
+ */
+ @JvmStatic
+ fun retrieveBeginGetCredentialRequest(intent: Intent): BeginGetCredentialRequest? {
+ val request = intent.getParcelableExtra(
+ "android.service.credentials.extra.BEGIN_GET_CREDENTIAL_REQUEST",
+ BeginGetCredentialRequest::class.java
+ )
+ return request?.let { BeginGetCredentialUtil.convertToStructuredRequest(it) }
+ }
+
+ /**
+ * Sets the [CreateCredentialResponse] on the result of the
+ * activity invoked by the [PendingIntent] set on a
+ * [CreateEntry].
+ *
+ * @param intent the intent to be set on the result of the [Activity] invoked through the
+ * [PendingIntent]
+ * @param response the response to be set as an extra on the [intent]
+ *
+ * @throws NullPointerException If [intent], or [response] is null
+ */
+ @JvmStatic
+ fun setCreateCredentialResponse(
+ intent: Intent,
+ response: androidx.credentials.CreateCredentialResponse
+ ) {
+ intent.putExtra(
+ CredentialProviderService.EXTRA_CREATE_CREDENTIAL_RESPONSE,
+ CreateCredentialResponse(response.data))
+ }
+
+ /**
+ * Extracts the [ProviderGetCredentialRequest] from the provider's
+ * [PendingIntent] invoked by the Android system, when the user selects a
+ * [CredentialEntry].
+ *
+ * @param intent the intent associated with the [Activity] invoked through the
+ * [PendingIntent]
+ *
+ * @throws NullPointerException If [intent] is null
+ */
+ @JvmStatic
+ fun retrieveProviderGetCredentialRequest(intent: Intent):
+ ProviderGetCredentialRequest? {
+ val frameworkReq = intent.getParcelableExtra(
+ CredentialProviderService.EXTRA_GET_CREDENTIAL_REQUEST,
+ android.service.credentials.GetCredentialRequest::class.java
+ )
+ if (frameworkReq == null) {
+ Log.i(TAG, "Get request from framework is null")
+ return null
+ }
+ return ProviderGetCredentialRequest.createFrom(frameworkReq)
+ }
+
+ /**
+ * Sets the [android.credentials.GetCredentialResponse] on the result of the
+ * activity invoked by the [PendingIntent], set on a [CreateEntry].
+ *
+ * @param intent the intent to be set on the result of the [Activity] invoked through the
+ * [PendingIntent]
+ * @param response the response to be set as an extra on the [intent]
+ *
+ * @throws NullPointerException If [intent], or [response] is null
+ */
+ @JvmStatic
+ fun setGetCredentialResponse(
+ intent: Intent,
+ response: GetCredentialResponse
+ ) {
+ intent.putExtra(
+ CredentialProviderService.EXTRA_GET_CREDENTIAL_RESPONSE,
+ android.credentials.GetCredentialResponse(
+ android.credentials.Credential(response.credential.type,
+ response.credential.data))
+ )
+ }
+
+ /**
+ * Sets the [android.service.credentials.BeginGetCredentialResponse] on the result of the
+ * activity invoked by the [PendingIntent], set on an [AuthenticationAction].
+ *
+ * @param intent the intent to be set on the result of the [Activity] invoked through the
+ * [PendingIntent]
+ * @param response the response to be set as an extra on the [intent]
+ *
+ * @throws NullPointerException If [intent], or [response] is null
+ */
+ @JvmStatic
+ fun setBeginGetCredentialResponse(
+ intent: Intent,
+ response: BeginGetCredentialResponse
+ ) {
+ intent.putExtra(
+ CredentialProviderService.EXTRA_BEGIN_GET_CREDENTIAL_RESPONSE,
+ response
+ )
+ }
+
+ /**
+ * Sets the [androidx.credentials.exceptions.GetCredentialException] if an error is
+ * encountered during the final phase of the get credential flow.
+ *
+ * A credential provider service returns a list of [CredentialEntry] as part of
+ * the [BeginGetCredentialResponse] to the query phase of the get-credential flow.
+ * If the user selects one of these entries, the corresponding [PendingIntent]
+ * is fired and the provider's activity is invoked.
+ * If there is an error encountered during the lifetime of that activity, the provider
+ * must use this API to set an exception before finishing this activity.
+ *
+ * @param intent the intent to be set on the result of the [Activity] invoked through the
+ * [PendingIntent]
+ * @param exception the exception to be set as an extra to the [intent]
+ *
+ * @throws NullPointerException If [intent], or [exception] is null
+ */
+ @JvmStatic
+ fun setGetCredentialException(
+ intent: Intent,
+ exception: GetCredentialException
+ ) {
+ intent.putExtra(
+ CredentialProviderService.EXTRA_GET_CREDENTIAL_EXCEPTION,
+ android.credentials.GetCredentialException(exception.type, exception.message)
+ )
+ }
+
+ /**
+ * Sets the [androidx.credentials.exceptions.CreateCredentialException] if an error is
+ * encountered during the final phase of the create credential flow.
+ *
+ * A credential provider service returns a list of [CreateEntry] as part of
+ * the [BeginCreateCredentialResponse] to the query phase of the get-credential flow.
+ *
+ * If the user selects one of these entries, the corresponding [PendingIntent]
+ * is fired and the provider's activity is invoked. If there is an error encountered
+ * during the lifetime of that activity, the provider must use this API to set
+ * an exception before finishing the activity.
+ *
+ * @param intent the intent to be set on the result of the [Activity] invoked through the
+ * [PendingIntent]
+ * @param exception the exception to be set as an extra to the [intent]
+ *
+ * @throws NullPointerException If [intent], or [exception] is null
+ */
+ @JvmStatic
+ fun setCreateCredentialException(
+ intent: Intent,
+ exception: CreateCredentialException
+ ) {
+ intent.putExtra(
+ CredentialProviderService.EXTRA_CREATE_CREDENTIAL_EXCEPTION,
+ android.credentials.CreateCredentialException(exception.type, exception.message)
+ )
+ }
+ }
+}
diff --git a/credentials/credentials/src/main/java/androidx/credentials/provider/ProviderCreateCredentialRequest.kt b/credentials/credentials/src/main/java/androidx/credentials/provider/ProviderCreateCredentialRequest.kt
new file mode 100644
index 0000000..9f77325
--- /dev/null
+++ b/credentials/credentials/src/main/java/androidx/credentials/provider/ProviderCreateCredentialRequest.kt
@@ -0,0 +1,42 @@
+/*
+ * Copyright 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.credentials.provider
+
+import android.service.credentials.CallingAppInfo
+import androidx.annotation.RequiresApi
+import androidx.credentials.CreateCredentialRequest
+
+/**
+ * Final request received by the provider after the user has selected a given [CreateEntry]
+ * on the UI.
+ *
+ * This request contains the actual request coming from the calling app,
+ * and the application information associated with the calling app.
+ *
+ * @property callingRequest the complete [CreateCredentialRequest] coming from
+ * the calling app that is requesting for credential creation
+ * @property callingAppInfo information pertaining to the calling app making
+ * the request
+ *
+ * @throws NullPointerException If [callingRequest] is null
+ * @throws NullPointerException If [callingAppInfo] is null
+ */
+@RequiresApi(34)
+class ProviderCreateCredentialRequest internal constructor(
+ val callingRequest: CreateCredentialRequest,
+ val callingAppInfo: CallingAppInfo
+)
\ No newline at end of file
diff --git a/credentials/credentials/src/main/java/androidx/credentials/provider/ProviderGetCredentialRequest.kt b/credentials/credentials/src/main/java/androidx/credentials/provider/ProviderGetCredentialRequest.kt
new file mode 100644
index 0000000..eebe8ad
--- /dev/null
+++ b/credentials/credentials/src/main/java/androidx/credentials/provider/ProviderGetCredentialRequest.kt
@@ -0,0 +1,57 @@
+/*
+ * Copyright 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package androidx.credentials.provider
+
+import android.app.PendingIntent
+import android.service.credentials.CallingAppInfo
+import androidx.annotation.RequiresApi
+import androidx.credentials.CredentialOption
+
+/**
+ * Request received by the provider after the query phase of the get flow is complete i.e. the user
+ * was presented with a list of credentials, and the user has now made a selection from the list of
+ * [android.service.credentials.CredentialEntry] presented on the selector UI.
+ *
+ * This request will be added to the intent extras of the activity invoked by the [PendingIntent]
+ * set on the [android.service.credentials.CredentialEntry] that the user selected. The request
+ * must be extracted using the [PendingIntentHandler.retrieveProviderGetCredentialRequest] helper
+ * API.
+ *
+ * @property credentialOption the credential retrieval parameters
+ * @property callingAppInfo information pertaining to the calling application
+ */
+@RequiresApi(34)
+class ProviderGetCredentialRequest internal constructor(
+ val credentialOption: CredentialOption,
+ val callingAppInfo: CallingAppInfo
+ ) {
+
+ /** @hide */
+ companion object {
+ internal fun createFrom(request: android.service.credentials.GetCredentialRequest):
+ ProviderGetCredentialRequest {
+ val option = CredentialOption.createFrom(
+ request.credentialOption.type,
+ request.credentialOption.candidateQueryData,
+ request.credentialOption.credentialRetrievalData,
+ request.credentialOption.isSystemProviderRequired
+ )
+ return ProviderGetCredentialRequest(
+ option,
+ request.callingAppInfo)
+ }
+ }
+}
diff --git a/credentials/credentials/src/main/java/androidx/credentials/provider/PublicKeyCredentialEntry.kt b/credentials/credentials/src/main/java/androidx/credentials/provider/PublicKeyCredentialEntry.kt
new file mode 100644
index 0000000..8ec4ed5
--- /dev/null
+++ b/credentials/credentials/src/main/java/androidx/credentials/provider/PublicKeyCredentialEntry.kt
@@ -0,0 +1,357 @@
+/*
+ * Copyright 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.credentials.provider
+
+import android.annotation.SuppressLint
+import android.app.PendingIntent
+import android.app.slice.Slice
+import android.app.slice.SliceSpec
+import android.content.Context
+import android.graphics.drawable.Icon
+import android.net.Uri
+import android.os.Bundle
+import android.os.Parcel
+import android.os.Parcelable
+import android.service.credentials.CredentialEntry
+import android.util.Log
+import androidx.annotation.NonNull
+import androidx.annotation.RequiresApi
+import androidx.annotation.VisibleForTesting
+import androidx.credentials.PublicKeyCredential
+import androidx.credentials.R
+import java.time.Instant
+import java.util.Collections
+
+/**
+ * A public key credential entry that is displayed on the account selector UI. This
+ * entry denotes that a credential of type [PublicKeyCredential.TYPE_PUBLIC_KEY_CREDENTIAL]
+ * is available for the user to select.
+ *
+ * Once this entry is selected, the corresponding [pendingIntent] will be invoked. The provider
+ * can then show any activity they wish to. Before finishing the activity, provider must
+ * set the final [androidx.credentials.GetCredentialResponse] through the
+ * [PendingIntentHandler.setGetCredentialResponse] helper API.
+ *
+ * @property username the username of the account holding the public key credential
+ * @property displayName the displayName of the account holding the public key credential
+ * @property lastUsedTime the last used time of this entry
+ * @property icon the icon to be displayed with this entry on the selector
+ * @param pendingIntent the [PendingIntent] to be invoked when the user
+ * selects this entry
+ * @property isAutoSelectAllowed whether this entry is allowed to be auto
+ * selected if it is the only one on the UI. Note that setting this value
+ * to true does not guarantee this behavior. The developer must also set this
+ * to true, and the framework must determine that it is safe to auto select.
+ *
+ * @throws IllegalArgumentException if [username] is empty
+ */
+@RequiresApi(34)
+class PublicKeyCredentialEntry internal constructor(
+ val username: CharSequence,
+ val displayName: CharSequence?,
+ val typeDisplayName: CharSequence,
+ val pendingIntent: PendingIntent,
+ val icon: Icon?,
+ val lastUsedTime: Instant?,
+ val isAutoSelectAllowed: Boolean,
+ beginGetPublicKeyCredentialOption: BeginGetPublicKeyCredentialOption,
+ ) : CredentialEntry(
+ beginGetPublicKeyCredentialOption,
+ toSlice(
+ PublicKeyCredential.TYPE_PUBLIC_KEY_CREDENTIAL,
+ username,
+ displayName,
+ pendingIntent,
+ typeDisplayName,
+ lastUsedTime,
+ icon,
+ isAutoSelectAllowed,
+ beginGetPublicKeyCredentialOption
+ )
+) {
+
+ init {
+ require(username.isNotEmpty()) { "username must not be empty" }
+ require(typeDisplayName.isNotEmpty()) { "typeDisplayName must not be empty" }
+ }
+
+ constructor(
+ context: Context,
+ username: CharSequence,
+ pendingIntent: PendingIntent,
+ beginGetPublicKeyCredentialOption: BeginGetPublicKeyCredentialOption,
+ displayName: CharSequence? = null,
+ lastUsedTime: Instant? = null,
+ icon: Icon? = Icon.createWithResource(context, R.drawable.ic_passkey),
+ isAutoSelectAllowed: Boolean = false,
+ ) : this(
+ username,
+ displayName,
+ context.getString(
+ R.string.androidx_credentials_TYPE_PUBLIC_KEY_CREDENTIAL),
+ pendingIntent,
+ icon,
+ lastUsedTime,
+ isAutoSelectAllowed,
+ beginGetPublicKeyCredentialOption
+ )
+
+ override fun describeContents(): Int {
+ return 0
+ }
+
+ override fun writeToParcel(@NonNull dest: Parcel, flags: Int) {
+ super.writeToParcel(dest, flags)
+ }
+
+ @Suppress("AcronymName")
+ companion object CREATOR {
+
+ private const val TAG = "PublicKeyCredEntry"
+ @VisibleForTesting(otherwise = VisibleForTesting.PRIVATE)
+ internal const val SLICE_HINT_TYPE_DISPLAY_NAME =
+ "androidx.credentials.provider.credentialEntry.SLICE_HINT_TYPE_DISPLAY_NAME"
+ @VisibleForTesting(otherwise = VisibleForTesting.PRIVATE)
+ internal const val SLICE_HINT_TITLE =
+ "androidx.credentials.provider.credentialEntry.SLICE_HINT_USER_NAME"
+ @VisibleForTesting(otherwise = VisibleForTesting.PRIVATE)
+ internal const val SLICE_HINT_SUBTITLE =
+ "androidx.credentials.provider.credentialEntry.SLICE_HINT_CREDENTIAL_TYPE_DISPLAY_NAME"
+ @VisibleForTesting(otherwise = VisibleForTesting.PRIVATE)
+ internal const val SLICE_HINT_LAST_USED_TIME_MILLIS =
+ "androidx.credentials.provider.credentialEntry.SLICE_HINT_LAST_USED_TIME_MILLIS"
+ @VisibleForTesting(otherwise = VisibleForTesting.PRIVATE)
+ internal const val SLICE_HINT_ICON =
+ "androidx.credentials.provider.credentialEntry.SLICE_HINT_PROFILE_ICON"
+ @VisibleForTesting(otherwise = VisibleForTesting.PRIVATE)
+ internal const val SLICE_HINT_PENDING_INTENT =
+ "androidx.credentials.provider.credentialEntry.SLICE_HINT_PENDING_INTENT"
+ @VisibleForTesting(otherwise = VisibleForTesting.PRIVATE)
+ internal const val SLICE_HINT_AUTO_ALLOWED =
+ "androidx.credentials.provider.credentialEntry.SLICE_HINT_AUTO_ALLOWED"
+ @VisibleForTesting(otherwise = VisibleForTesting.PRIVATE)
+ internal const val SLICE_HINT_OPTION_BUNDLE =
+ "androidx.credentials.provider.credentialEntry.SLICE_HINT_OPTION_BUNDLE"
+ @VisibleForTesting(otherwise = VisibleForTesting.PRIVATE)
+ internal const val SLICE_HINT_OPTION_ID =
+ "androidx.credentials.provider.credentialEntry.SLICE_HINT_OPTION_ID"
+ @VisibleForTesting(otherwise = VisibleForTesting.PRIVATE)
+ internal const val AUTO_SELECT_TRUE_STRING = "true"
+ @VisibleForTesting(otherwise = VisibleForTesting.PRIVATE)
+ internal const val AUTO_SELECT_FALSE_STRING = "false"
+
+ /** @hide */
+ @JvmStatic
+ internal fun toSlice(
+ type: String,
+ title: CharSequence,
+ subTitle: CharSequence?,
+ pendingIntent: PendingIntent,
+ typeDisplayName: CharSequence?,
+ lastUsedTime: Instant?,
+ icon: Icon?,
+ isAutoSelectAllowed: Boolean,
+ beginGetPublicKeyCredentialOption: BeginGetPublicKeyCredentialOption
+ ): Slice {
+ // TODO("Put the right revision value")
+ val autoSelectAllowed = if (isAutoSelectAllowed) {
+ AUTO_SELECT_TRUE_STRING
+ } else {
+ AUTO_SELECT_FALSE_STRING
+ }
+ val sliceBuilder = Slice.Builder(
+ Uri.EMPTY, SliceSpec(
+ type, 1)
+ )
+ .addText(typeDisplayName, /*subType=*/null,
+ listOf(SLICE_HINT_TYPE_DISPLAY_NAME))
+ .addText(title, /*subType=*/null,
+ listOf(SLICE_HINT_TITLE))
+ .addText(subTitle, /*subType=*/null,
+ listOf(SLICE_HINT_SUBTITLE))
+ .addText(autoSelectAllowed, /*subType=*/null,
+ listOf(SLICE_HINT_AUTO_ALLOWED))
+ .addBundle(beginGetPublicKeyCredentialOption.candidateQueryData,
+ /*subType=*/null,
+ listOf(SLICE_HINT_OPTION_BUNDLE))
+ .addText(
+ beginGetPublicKeyCredentialOption.id,
+ /*subType=*/null,
+ listOf(SLICE_HINT_OPTION_ID)
+ )
+ if (lastUsedTime != null) {
+ sliceBuilder.addLong(lastUsedTime.toEpochMilli(),
+ /*subType=*/null,
+ listOf(SLICE_HINT_LAST_USED_TIME_MILLIS))
+ }
+ if (icon != null) {
+ sliceBuilder.addIcon(icon, /*subType=*/null,
+ listOf(SLICE_HINT_ICON))
+ }
+ sliceBuilder.addAction(pendingIntent,
+ Slice.Builder(sliceBuilder)
+ .addHints(Collections.singletonList(SLICE_HINT_PENDING_INTENT))
+ .build(),
+ /*subType=*/null)
+ return sliceBuilder.build()
+ }
+
+ /**
+ * Returns an instance of [CustomCredentialEntry] derived from a [Slice] object.
+ *
+ * @param slice the [Slice] object constructed through [toSlice]
+ *
+ * @hide
+ */
+ @SuppressLint("WrongConstant") // custom conversion between jetpack and framework
+ @JvmStatic
+ fun fromSlice(slice: Slice): PublicKeyCredentialEntry? {
+ var typeDisplayName: CharSequence? = null
+ var title: CharSequence? = null
+ var subTitle: CharSequence? = null
+ var icon: Icon? = null
+ var pendingIntent: PendingIntent? = null
+ var lastUsedTime: Instant? = null
+ var autoSelectAllowed = false
+ var beginGetPublicKeyCredentialOptionBundle: Bundle? = null
+ var beginGetPublicKeyCredentialOptionId: CharSequence? = null
+
+ slice.items.forEach {
+ if (it.hasHint(SLICE_HINT_TYPE_DISPLAY_NAME)) {
+ typeDisplayName = it.text
+ } else if (it.hasHint(SLICE_HINT_TITLE)) {
+ title = it.text
+ } else if (it.hasHint(SLICE_HINT_SUBTITLE)) {
+ subTitle = it.text
+ } else if (it.hasHint(SLICE_HINT_ICON)) {
+ icon = it.icon
+ } else if (it.hasHint(SLICE_HINT_PENDING_INTENT)) {
+ pendingIntent = it.action
+ } else if (it.hasHint(SLICE_HINT_OPTION_BUNDLE)) {
+ beginGetPublicKeyCredentialOptionBundle = it.bundle
+ } else if (it.hasHint(SLICE_HINT_OPTION_ID)) {
+ beginGetPublicKeyCredentialOptionId = it.text
+ } else if (it.hasHint(SLICE_HINT_LAST_USED_TIME_MILLIS)) {
+ lastUsedTime = Instant.ofEpochMilli(it.long)
+ } else if (it.hasHint(SLICE_HINT_AUTO_ALLOWED)) {
+ val autoSelectValue = it.text
+ if (autoSelectValue == AUTO_SELECT_TRUE_STRING) {
+ autoSelectAllowed = true
+ }
+ }
+ }
+
+ return try {
+ PublicKeyCredentialEntry(
+ title!!,
+ subTitle,
+ typeDisplayName!!,
+ pendingIntent!!,
+ icon!!,
+ lastUsedTime,
+ autoSelectAllowed,
+ BeginGetPublicKeyCredentialOption.createFrom(
+ beginGetPublicKeyCredentialOptionBundle!!,
+ beginGetPublicKeyCredentialOptionId!!.toString()
+ )
+ )
+ } catch (e: Exception) {
+ Log.i(TAG, "fromSlice failed with: " + e.message)
+ null
+ }
+ }
+
+ @JvmField val CREATOR: Parcelable.Creator<PublicKeyCredentialEntry> = object :
+ Parcelable.Creator<PublicKeyCredentialEntry> {
+ override fun createFromParcel(p0: Parcel?): PublicKeyCredentialEntry? {
+ val credentialEntry = CredentialEntry.CREATOR.createFromParcel(p0)
+ return fromSlice(credentialEntry.slice)
+ }
+
+ @Suppress("ArrayReturn")
+ override fun newArray(size: Int): Array<PublicKeyCredentialEntry?> {
+ return arrayOfNulls(size)
+ }
+ }
+ }
+
+ /**
+ * Builder for [PublicKeyCredentialEntry]
+ */
+ class Builder(
+ private val context: Context,
+ private val username: CharSequence,
+ private val pendingIntent: PendingIntent,
+ private val beginGetPublicKeyCredentialOption: BeginGetPublicKeyCredentialOption
+ ) {
+ private var displayName: CharSequence? = null
+ private var lastUsedTime: Instant? = null
+ private var icon: Icon? = null
+ private var autoSelectAllowed: Boolean = false
+
+ /** Sets a displayName to be shown on the UI with this entry */
+ fun setDisplayName(displayName: CharSequence?): Builder {
+ this.displayName = displayName
+ return this
+ }
+
+ /** Sets the icon to be shown on the UI with this entry */
+ fun setIcon(icon: Icon?): Builder {
+ this.icon = icon
+ return this
+ }
+
+ /**
+ * Sets whether the entry should be auto-selected.
+ * The value is false by default
+ */
+ @Suppress("MissingGetterMatchingBuilder")
+ fun setAutoSelectAllowed(autoSelectAllowed: Boolean): Builder {
+ this.autoSelectAllowed = autoSelectAllowed
+ return this
+ }
+
+ /**
+ * Sets the last used time of this account
+ *
+ * This information will be used to sort the entries on the selector.
+ */
+ fun setLastUsedTime(lastUsedTime: Instant?): Builder {
+ this.lastUsedTime = lastUsedTime
+ return this
+ }
+
+ /** Builds an instance of [PublicKeyCredentialEntry] */
+ fun build(): PublicKeyCredentialEntry {
+ if (icon == null) {
+ icon = Icon.createWithResource(context, R.drawable.ic_passkey)
+ }
+ val typeDisplayName = context.getString(
+ R.string.androidx_credentials_TYPE_PUBLIC_KEY_CREDENTIAL)
+ return PublicKeyCredentialEntry(
+ username,
+ displayName,
+ typeDisplayName,
+ pendingIntent,
+ icon!!,
+ lastUsedTime,
+ autoSelectAllowed,
+ beginGetPublicKeyCredentialOption
+ )
+ }
+ }
+}
diff --git a/credentials/credentials/src/main/java/androidx/credentials/provider/RemoteCreateEntry.kt b/credentials/credentials/src/main/java/androidx/credentials/provider/RemoteCreateEntry.kt
new file mode 100644
index 0000000..33ff311
--- /dev/null
+++ b/credentials/credentials/src/main/java/androidx/credentials/provider/RemoteCreateEntry.kt
@@ -0,0 +1,124 @@
+/*
+ * Copyright 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package androidx.credentials.provider
+
+import android.annotation.SuppressLint
+import android.app.PendingIntent
+import android.app.slice.Slice
+import android.app.slice.SliceSpec
+import android.net.Uri
+import android.os.Parcel
+import android.os.Parcelable
+import android.util.Log
+import androidx.annotation.NonNull
+import androidx.annotation.RequiresApi
+import androidx.annotation.VisibleForTesting
+import androidx.credentials.CredentialManager
+import java.util.Collections
+
+/**
+ * An entry to be shown on the selector during a create flow initiated when an app calls
+ * [CredentialManager.createCredential].
+ *
+ * A [RemoteCreateEntry] implies that the credential will be created on
+ * a different device.
+ * When the user selects this entry, the corresponding [PendingIntent] is fired,
+ * and the credential creation can be completed.
+ *
+ * @property pendingIntent the [PendingIntent] to be fired when this
+ * [RemoteCreateEntry] is selected
+ *
+ * @throws NullPointerException If [pendingIntent] is empty
+ */
+@RequiresApi(34)
+class RemoteCreateEntry constructor(
+ val pendingIntent: PendingIntent,
+ ) : android.service.credentials.CreateEntry(
+ toSlice(pendingIntent)
+) {
+
+ override fun describeContents(): Int {
+ return 0
+ }
+
+ override fun writeToParcel(@NonNull dest: Parcel, flags: Int) {
+ super.writeToParcel(dest, flags)
+ }
+
+ @Suppress("AcronymName")
+ companion object {
+ private const val TAG = "RemoteCreateEntry"
+ @VisibleForTesting(otherwise = VisibleForTesting.PRIVATE)
+ internal const val SLICE_HINT_PENDING_INTENT =
+ "androidx.credentials.provider.createEntry.SLICE_HINT_PENDING_INTENT"
+
+ /** @hide **/
+ @JvmStatic
+ fun toSlice(
+ pendingIntent: PendingIntent
+ ): Slice {
+ // TODO("Use the right type and revision")
+ val sliceBuilder = Slice.Builder(Uri.EMPTY, SliceSpec("type", 1))
+ sliceBuilder.addAction(
+ pendingIntent,
+ Slice.Builder(sliceBuilder)
+ .addHints(Collections.singletonList(SLICE_HINT_PENDING_INTENT))
+ .build(),
+ /*subType=*/null
+ )
+ return sliceBuilder.build()
+ }
+
+ /**
+ * Returns an instance of [RemoteCreateEntry] derived from a [Slice] object.
+ *
+ * @param slice the [Slice] object constructed through [toSlice]
+ *
+ * @hide
+ */
+ @SuppressLint("WrongConstant") // custom conversion between jetpack and framework
+ @JvmStatic
+ fun fromSlice(slice: Slice): RemoteCreateEntry? {
+ // TODO("Put the right spec and version value")
+ var pendingIntent: PendingIntent? = null
+ slice.items.forEach {
+ if (it.hasHint(SLICE_HINT_PENDING_INTENT)) {
+ pendingIntent = it.action
+ }
+ }
+ return try {
+ RemoteCreateEntry(pendingIntent!!)
+ } catch (e: Exception) {
+ Log.i(TAG, "fromSlice failed with: " + e.message)
+ null
+ }
+ }
+
+ @JvmField val CREATOR: Parcelable.Creator<RemoteCreateEntry> =
+ object : Parcelable.Creator<RemoteCreateEntry> {
+ override fun createFromParcel(p0: Parcel?): RemoteCreateEntry? {
+ val createEntry = android.service.credentials.CreateEntry
+ .CREATOR.createFromParcel(p0)
+ return fromSlice(createEntry.slice)
+ }
+
+ @Suppress("ArrayReturn")
+ override fun newArray(size: Int): Array<RemoteCreateEntry?> {
+ return arrayOfNulls(size)
+ }
+ }
+ }
+ }
diff --git a/credentials/credentials/src/main/java/androidx/credentials/provider/RemoteCredentialEntry.kt b/credentials/credentials/src/main/java/androidx/credentials/provider/RemoteCredentialEntry.kt
new file mode 100644
index 0000000..730a6c6
--- /dev/null
+++ b/credentials/credentials/src/main/java/androidx/credentials/provider/RemoteCredentialEntry.kt
@@ -0,0 +1,149 @@
+/*
+ * Copyright 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package androidx.credentials.provider
+
+import android.annotation.SuppressLint
+import android.app.PendingIntent
+import android.app.slice.Slice
+import android.app.slice.SliceSpec
+import android.net.Uri
+import android.os.Bundle
+import android.os.Parcel
+import android.os.Parcelable
+import android.util.Log
+import androidx.annotation.NonNull
+import androidx.annotation.RequiresApi
+import androidx.annotation.VisibleForTesting
+import androidx.credentials.PublicKeyCredential
+import java.util.Collections
+
+/**
+ * An entry on the selector, denoting that the credential will be retrieved from a remote device.
+ * A public key credential entry that is displayed on the account selector UI.
+ *
+ * Once this entry is selected, the corresponding [pendingIntent] will be invoked. The provider
+ * can then show any activity they wish to. Before finishing the activity, provider must
+ * set the final [androidx.credentials.GetCredentialResponse] through the
+ * [PendingIntentHandler.setGetCredentialResponse] helper API.
+ *
+ * @property pendingIntent the [PendingIntent] to be invoked when the user selects
+ * this entry
+ *
+ * See [android.service.credentials.BeginGetCredentialResponse] for usage details.
+ */
+@RequiresApi(34)
+class RemoteCredentialEntry constructor(
+ val pendingIntent: PendingIntent,
+ beginGetPublicKeyCredentialOption: BeginGetPublicKeyCredentialOption
+ ) : android.service.credentials.CredentialEntry(
+ beginGetPublicKeyCredentialOption,
+ toSlice(PublicKeyCredential.TYPE_PUBLIC_KEY_CREDENTIAL, pendingIntent,
+ beginGetPublicKeyCredentialOption)
+ ) {
+
+ override fun describeContents(): Int {
+ return 0
+ }
+
+ override fun writeToParcel(@NonNull dest: Parcel, flags: Int) {
+ super.writeToParcel(dest, flags)
+ }
+ @Suppress("AcronymName")
+ companion object CREATOR {
+ private const val TAG = "RemoteEntry"
+
+ @VisibleForTesting(otherwise = VisibleForTesting.PRIVATE)
+ internal const val SLICE_HINT_PENDING_INTENT =
+ "androidx.credentials.provider.remoteEntry.SLICE_HINT_PENDING_INTENT"
+ @VisibleForTesting(otherwise = VisibleForTesting.PRIVATE)
+ internal const val SLICE_HINT_OPTION_BUNDLE =
+ "androidx.credentials.provider.remoteEntry.SLICE_HINT_OPTION_BUNDLE"
+ @VisibleForTesting(otherwise = VisibleForTesting.PRIVATE)
+ internal const val SLICE_HINT_OPTION_ID =
+ "androidx.credentials.provider.remoteEntry.SLICE_HINT_OPTION_ID"
+
+ /** @hide */
+ @JvmStatic
+ internal fun toSlice(
+ type: String,
+ pendingIntent: PendingIntent,
+ beginGetPublicKeyCredentialOption: BeginGetPublicKeyCredentialOption
+ ): Slice {
+ // TODO("Put the right spec and version value")
+ val sliceBuilder = Slice.Builder(Uri.EMPTY, SliceSpec(type, 1))
+ sliceBuilder.addAction(pendingIntent,
+ Slice.Builder(sliceBuilder)
+ .addHints(Collections.singletonList(SLICE_HINT_PENDING_INTENT))
+ .build(), /*subType=*/null)
+ .addBundle(beginGetPublicKeyCredentialOption.candidateQueryData,
+ /*subType=*/null,
+ listOf(SLICE_HINT_OPTION_BUNDLE))
+ .addText(beginGetPublicKeyCredentialOption.id,
+ /*subType=*/null,
+ listOf(SLICE_HINT_OPTION_ID))
+ return sliceBuilder.build()
+ }
+
+ /**
+ * Returns an instance of [RemoteCredentialEntry] derived from a [Slice] object.
+ *
+ * @param slice the [Slice] object constructed through [toSlice]
+ *
+ * @hide
+ */
+ @SuppressLint("WrongConstant") // custom conversion between jetpack and framework
+ @JvmStatic
+ fun fromSlice(slice: Slice): RemoteCredentialEntry? {
+ var beginGetPublicKeyCredentialOptionBundle: Bundle? = null
+ var beginGetPublicKeyCredentialOptionId: CharSequence? = null
+ var pendingIntent: PendingIntent? = null
+ slice.items.forEach {
+ if (it.hasHint(SLICE_HINT_PENDING_INTENT)) {
+ pendingIntent = it.action
+ } else if (it.hasHint(SLICE_HINT_OPTION_BUNDLE)) {
+ beginGetPublicKeyCredentialOptionBundle = it.bundle
+ } else if (it.hasHint(SLICE_HINT_OPTION_ID)) {
+ beginGetPublicKeyCredentialOptionId = it.text
+ }
+ }
+ return try {
+ RemoteCredentialEntry(pendingIntent!!,
+ BeginGetPublicKeyCredentialOption.createFrom(
+ beginGetPublicKeyCredentialOptionBundle!!,
+ beginGetPublicKeyCredentialOptionId!!.toString()
+ )
+ )
+ } catch (e: Exception) {
+ Log.i(TAG, "fromSlice failed with: " + e.message)
+ null
+ }
+ }
+
+ @JvmField val CREATOR: Parcelable.Creator<RemoteCredentialEntry> = object :
+ Parcelable.Creator<RemoteCredentialEntry> {
+ override fun createFromParcel(p0: Parcel?): RemoteCredentialEntry? {
+ val baseEntry =
+ android.service.credentials.CredentialEntry.CREATOR.createFromParcel(p0)
+ return fromSlice(baseEntry.slice)
+ }
+
+ @Suppress("ArrayReturn")
+ override fun newArray(size: Int): Array<RemoteCredentialEntry?> {
+ return arrayOfNulls(size)
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/credentials/credentials/src/main/java/androidx/credentials/provider/utils/BeginCreateCredentialUtil.kt b/credentials/credentials/src/main/java/androidx/credentials/provider/utils/BeginCreateCredentialUtil.kt
new file mode 100644
index 0000000..4e55912
--- /dev/null
+++ b/credentials/credentials/src/main/java/androidx/credentials/provider/utils/BeginCreateCredentialUtil.kt
@@ -0,0 +1,68 @@
+/*
+ * Copyright 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.credentials.provider.utils
+
+import android.service.credentials.BeginCreateCredentialRequest
+import androidx.annotation.RequiresApi
+import androidx.credentials.CreatePublicKeyCredentialRequest
+import androidx.credentials.CreatePublicKeyCredentialRequestPrivileged
+import androidx.credentials.PasswordCredential
+import androidx.credentials.PublicKeyCredential
+import androidx.credentials.internal.FrameworkClassParsingException
+import androidx.credentials.provider.BeginCreatePasswordCredentialRequest
+import androidx.credentials.provider.BeginCreatePublicKeyCredentialRequest
+import androidx.credentials.provider.BeginCreatePublicKeyCredentialRequestPrivileged
+
+/**
+ * @hide
+ */
+@RequiresApi(34)
+class BeginCreateCredentialUtil {
+ companion object {
+ @JvmStatic
+ internal fun convertToStructuredRequest(request: BeginCreateCredentialRequest):
+ BeginCreateCredentialRequest {
+ return try {
+ when (request.type) {
+ PasswordCredential.TYPE_PASSWORD_CREDENTIAL -> {
+ BeginCreatePasswordCredentialRequest.createFrom(
+ request.data, request.callingAppInfo)
+ }
+ PublicKeyCredential.TYPE_PUBLIC_KEY_CREDENTIAL -> {
+ when (request.data.getString(PublicKeyCredential.BUNDLE_KEY_SUBTYPE)) {
+ CreatePublicKeyCredentialRequest
+ .BUNDLE_VALUE_SUBTYPE_CREATE_PUBLIC_KEY_CREDENTIAL_REQUEST ->
+ BeginCreatePublicKeyCredentialRequest.createFrom(
+ request.data, request.callingAppInfo)
+ CreatePublicKeyCredentialRequestPrivileged
+ .BUNDLE_VALUE_SUBTYPE_CREATE_PUBLIC_KEY_CREDENTIAL_REQUEST_PRIV ->
+ BeginCreatePublicKeyCredentialRequestPrivileged.createFrom(
+ request.data, request.callingAppInfo)
+ else -> throw FrameworkClassParsingException()
+ }
+ }
+ else -> {
+ BeginCreateCredentialRequest(request.type, request.data,
+ request.callingAppInfo)
+ }
+ }
+ } catch (e: FrameworkClassParsingException) {
+ BeginCreateCredentialRequest(request.type, request.data, request.callingAppInfo)
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/credentials/credentials/src/main/java/androidx/credentials/provider/utils/BeginGetCredentialUtil.kt b/credentials/credentials/src/main/java/androidx/credentials/provider/utils/BeginGetCredentialUtil.kt
new file mode 100644
index 0000000..723e876
--- /dev/null
+++ b/credentials/credentials/src/main/java/androidx/credentials/provider/utils/BeginGetCredentialUtil.kt
@@ -0,0 +1,89 @@
+/*
+ * Copyright 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.credentials.provider.utils
+
+import android.os.Bundle
+import android.service.credentials.BeginGetCredentialOption
+import android.service.credentials.BeginGetCredentialRequest
+import androidx.annotation.RequiresApi
+import androidx.credentials.GetPublicKeyCredentialOption
+import androidx.credentials.GetPublicKeyCredentialOptionPrivileged
+import androidx.credentials.PasswordCredential
+import androidx.credentials.PublicKeyCredential
+import androidx.credentials.provider.BeginGetPasswordOption
+import androidx.credentials.provider.BeginGetPublicKeyCredentialOption
+import androidx.credentials.provider.BeginGetPublicKeyCredentialOptionPrivileged
+
+/**
+ * @hide
+ */
+@RequiresApi(34)
+class BeginGetCredentialUtil {
+ companion object {
+ @JvmStatic
+ internal fun convertToStructuredRequest(request: BeginGetCredentialRequest):
+ BeginGetCredentialRequest {
+ val beginGetCredentialOptions: MutableList<BeginGetCredentialOption> =
+ mutableListOf()
+ request.beginGetCredentialOptions.forEach {
+ beginGetCredentialOptions.add(convertRequestOption(
+ it.type,
+ it.candidateQueryData, it.id)
+ )
+ }
+ return BeginGetCredentialRequest.Builder()
+ .setCallingAppInfo(request.callingAppInfo)
+ .setBeginGetCredentialOptions(beginGetCredentialOptions)
+ .build()
+ }
+ @JvmStatic
+ internal fun convertRequestOption(
+ type: String,
+ candidateQueryData: Bundle,
+ id: String
+ ):
+ BeginGetCredentialOption {
+ return when (type) {
+ PasswordCredential.TYPE_PASSWORD_CREDENTIAL -> {
+ BeginGetPasswordOption(candidateQueryData, id)
+ }
+ PublicKeyCredential.TYPE_PUBLIC_KEY_CREDENTIAL -> {
+ when (candidateQueryData.getString(
+ PublicKeyCredential.BUNDLE_KEY_SUBTYPE
+ )) {
+ GetPublicKeyCredentialOption
+ .BUNDLE_VALUE_SUBTYPE_GET_PUBLIC_KEY_CREDENTIAL_OPTION -> {
+ BeginGetPublicKeyCredentialOption.createFrom(candidateQueryData, id)
+ }
+ GetPublicKeyCredentialOptionPrivileged
+ .BUNDLE_VALUE_SUBTYPE_GET_PUBLIC_KEY_CREDENTIAL_OPTION_PRIVILEGED
+ -> {
+ BeginGetPublicKeyCredentialOptionPrivileged
+ .createFrom(candidateQueryData, id)
+ }
+ else -> {
+ BeginGetCredentialOption(id, type, candidateQueryData)
+ }
+ }
+ }
+ else -> {
+ BeginGetCredentialOption(id, type, candidateQueryData)
+ }
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/development/build_log_simplifier/messages.ignore b/development/build_log_simplifier/messages.ignore
index 86c3857..beb1c23 100644
--- a/development/build_log_simplifier/messages.ignore
+++ b/development/build_log_simplifier/messages.ignore
@@ -829,4 +829,8 @@
# > Configure project :internal-testutils-ktx
WARNING:The option setting 'android\.r8\.maxWorkers=[0-9]+' is experimental\.
# Building XCFrameworks (b/260140834) and iOS benchmark invocation
-.*xcodebuild.*
\ No newline at end of file
+.*xcodebuild.*
+Observed package id 'platforms;android-33-ext4' in inconsistent location.*
+.*xcodebuild.*
+# > Task :core:core:compileDebugAndroidTestKotlin
+w: file://\$SUPPORT/core/core/src/androidTest/java/androidx/core/util/TypedValueCompatTest\.kt:[0-9]+:[0-9]+ 'scaledDensity: Float' is deprecated\. Deprecated in Java
\ No newline at end of file
diff --git a/development/studio/idea.properties b/development/studio/idea.properties
index f352237..3cabbbf 100644
--- a/development/studio/idea.properties
+++ b/development/studio/idea.properties
@@ -5,12 +5,12 @@
#---------------------------------------------------------------------
# Uncomment this option if you want to customize path to IDE config folder. Make sure you're using forward slashes.
#---------------------------------------------------------------------
-idea.config.path=${user.home}/.AndroidStudioAndroidX/config
+idea.config.path=${user.home}/.AndroidStudioAndroidXPlatform/config
#---------------------------------------------------------------------
# Uncomment this option if you want to customize path to IDE system folder. Make sure you're using forward slashes.
#---------------------------------------------------------------------
-idea.system.path=${user.home}/.AndroidStudioAndroidX/system
+idea.system.path=${user.home}/.AndroidStudioAndroidXPlatform/system
#---------------------------------------------------------------------
# Uncomment this option if you want to customize path to user installed plugins folder. Make sure you're using forward slashes.
diff --git a/docs-public/build.gradle b/docs-public/build.gradle
index 36bbd84..8112d1f 100644
--- a/docs-public/build.gradle
+++ b/docs-public/build.gradle
@@ -245,6 +245,10 @@
docs("androidx.preference:preference:1.2.0")
docs("androidx.preference:preference-ktx:1.2.0")
docs("androidx.print:print:1.1.0-beta01")
+ docs("androidx.privacysandbox.ads:ads-adservices:1.0.0-alpha01")
+ docs("androidx.privacysandbox.ads:ads-adservices-java:1.0.0-alpha01")
+ docs("androidx.privacysandbox.sdkruntime:sdkruntime-client:1.0.0-alpha01")
+ docs("androidx.privacysandbox.sdkruntime:sdkruntime-core:1.0.0-alpha01")
docs("androidx.privacysandbox.tools:tools:1.0.0-alpha02")
docs("androidx.privacysandbox.tools:tools-apigenerator:1.0.0-alpha02")
docs("androidx.privacysandbox.tools:tools-apipackager:1.0.0-alpha02")
diff --git a/docs-tip-of-tree/build.gradle b/docs-tip-of-tree/build.gradle
index b3fc1a1..9dd217a 100644
--- a/docs-tip-of-tree/build.gradle
+++ b/docs-tip-of-tree/build.gradle
@@ -128,6 +128,7 @@
docs(project(":core:core-remoteviews"))
docs(project(":core:core-splashscreen"))
docs(project(":core:core-role"))
+ docs(project(":core:core-telecom"))
docs(project(":core:uwb:uwb"))
docs(project(":core:uwb:uwb-rxjava3"))
docs(project(":credentials:credentials"))
@@ -171,6 +172,7 @@
docs(project(":glance:glance-wear-tiles"))
docs(project(":graphics:filters:filters"))
docs(project(":graphics:graphics-core"))
+ docs(project(":graphics:graphics-path"))
docs(project(":graphics:graphics-shapes"))
docs(project(":gridlayout:gridlayout"))
docs(project(":health:connect:connect-client"))
@@ -358,12 +360,12 @@
docs(project(":wear:watchface:watchface-style"))
docs(project(":webkit:webkit"))
docs(project(":window:window"))
+ samples(project(":window:window-samples"))
docs(project(":window:window-core"))
docs(project(":window:window-java"))
docs(project(":window:window-rxjava2"))
docs(project(":window:window-rxjava3"))
stubs(project(":window:sidecar:sidecar"))
- samples(project(":window:window-samples:"))
stubs(project(":window:extensions:extensions"))
stubs(project(":window:extensions:core:core"))
docs(project(":window:window-testing"))
diff --git a/drawerlayout/drawerlayout/api/api_lint.ignore b/drawerlayout/drawerlayout/api/api_lint.ignore
index be4e831..69b398e 100644
--- a/drawerlayout/drawerlayout/api/api_lint.ignore
+++ b/drawerlayout/drawerlayout/api/api_lint.ignore
@@ -3,12 +3,6 @@
Parameter type is concrete collection (`java.util.ArrayList`); must be higher-level interface
-InvalidNullabilityOverride: androidx.drawerlayout.widget.DrawerLayout#drawChild(android.graphics.Canvas, android.view.View, long) parameter #0:
- Invalid nullability on parameter `canvas` in method `drawChild`. Parameters of overrides cannot be NonNull if the super parameter is unannotated.
-InvalidNullabilityOverride: androidx.drawerlayout.widget.DrawerLayout#onDraw(android.graphics.Canvas) parameter #0:
- Invalid nullability on parameter `c` in method `onDraw`. Parameters of overrides cannot be NonNull if the super parameter is unannotated.
-
-
ListenerInterface: androidx.drawerlayout.widget.DrawerLayout.SimpleDrawerListener:
Listeners should be an interface, or otherwise renamed Callback: SimpleDrawerListener
@@ -23,6 +17,8 @@
Missing nullability on parameter `p` in method `checkLayoutParams`
MissingNullability: androidx.drawerlayout.widget.DrawerLayout#dispatchGenericMotionEvent(android.view.MotionEvent) parameter #0:
Missing nullability on parameter `event` in method `dispatchGenericMotionEvent`
+MissingNullability: androidx.drawerlayout.widget.DrawerLayout#drawChild(android.graphics.Canvas, android.view.View, long) parameter #0:
+ Missing nullability on parameter `canvas` in method `drawChild`
MissingNullability: androidx.drawerlayout.widget.DrawerLayout#drawChild(android.graphics.Canvas, android.view.View, long) parameter #1:
Missing nullability on parameter `child` in method `drawChild`
MissingNullability: androidx.drawerlayout.widget.DrawerLayout#generateDefaultLayoutParams():
@@ -35,6 +31,8 @@
Missing nullability on method `generateLayoutParams` return
MissingNullability: androidx.drawerlayout.widget.DrawerLayout#generateLayoutParams(android.view.ViewGroup.LayoutParams) parameter #0:
Missing nullability on parameter `p` in method `generateLayoutParams`
+MissingNullability: androidx.drawerlayout.widget.DrawerLayout#onDraw(android.graphics.Canvas) parameter #0:
+ Missing nullability on parameter `c` in method `onDraw`
MissingNullability: androidx.drawerlayout.widget.DrawerLayout#onInterceptTouchEvent(android.view.MotionEvent) parameter #0:
Missing nullability on parameter `ev` in method `onInterceptTouchEvent`
MissingNullability: androidx.drawerlayout.widget.DrawerLayout#onKeyDown(int, android.view.KeyEvent) parameter #1:
diff --git a/emoji2/emoji2-emojipicker/src/main/java/androidx/emoji2/emojipicker/PopupViewHelper.kt b/emoji2/emoji2-emojipicker/src/main/java/androidx/emoji2/emojipicker/PopupViewHelper.kt
index 8038e48..9548eeb 100644
--- a/emoji2/emoji2-emojipicker/src/main/java/androidx/emoji2/emojipicker/PopupViewHelper.kt
+++ b/emoji2/emoji2-emojipicker/src/main/java/androidx/emoji2/emojipicker/PopupViewHelper.kt
@@ -167,9 +167,9 @@
private val radius = resources.getDimension(R.dimen.emoji_picker_skin_tone_circle_radius)
var paint: Paint? = null
- override fun draw(canvas: Canvas?) {
+ override fun draw(canvas: Canvas) {
super.draw(canvas)
- canvas?.apply {
+ canvas.apply {
paint?.let { drawCircle(width / 2f, height / 2f, radius, it) }
}
}
diff --git a/gradle.properties b/gradle.properties
index c10ff1a..f23a0e4 100644
--- a/gradle.properties
+++ b/gradle.properties
@@ -25,10 +25,10 @@
android.experimental.lint.missingBaselineIsEmptyBaseline=true
# Don't generate versioned API files
-androidx.writeVersionedApiFiles=true
+androidx.writeVersionedApiFiles=false
-# Do restrict compileSdkPreview usage
-androidx.allowCustomCompileSdk=false
+# Don't restrict compileSdkPreview usage
+androidx.allowCustomCompileSdk=true
# Don't warn about needing to update AGP
android.suppressUnsupportedCompileSdk=Tiramisu,33
diff --git a/graphics/OWNERS b/graphics/OWNERS
index 9ba9c32..db046a2 100644
--- a/graphics/OWNERS
+++ b/graphics/OWNERS
@@ -1,4 +1,5 @@
# Bug component: 1137062
sumir@google.com
jreck@google.com
-njawad@google.com
+xxayedawgxx@google.com
+njawad@google.com
\ No newline at end of file
diff --git a/graphics/graphics-path/api/current.txt b/graphics/graphics-path/api/current.txt
new file mode 100644
index 0000000..1b2faa6
--- /dev/null
+++ b/graphics/graphics-path/api/current.txt
@@ -0,0 +1,33 @@
+// Signature format: 4.0
+package androidx.graphics.path {
+
+ public final class PathSegment {
+ method public android.graphics.PointF![] getPoints();
+ method public androidx.graphics.path.PathSegment.Type getType();
+ method public float getWeight();
+ property public final android.graphics.PointF![] points;
+ property public final androidx.graphics.path.PathSegment.Type type;
+ property public final float weight;
+ }
+
+ public enum PathSegment.Type {
+ method public static androidx.graphics.path.PathSegment.Type valueOf(String name) throws java.lang.IllegalArgumentException;
+ method public static androidx.graphics.path.PathSegment.Type[] values();
+ enum_constant public static final androidx.graphics.path.PathSegment.Type Close;
+ enum_constant public static final androidx.graphics.path.PathSegment.Type Conic;
+ enum_constant public static final androidx.graphics.path.PathSegment.Type Cubic;
+ enum_constant public static final androidx.graphics.path.PathSegment.Type Done;
+ enum_constant public static final androidx.graphics.path.PathSegment.Type Line;
+ enum_constant public static final androidx.graphics.path.PathSegment.Type Move;
+ enum_constant public static final androidx.graphics.path.PathSegment.Type Quadratic;
+ }
+
+ public final class PathSegmentUtilities {
+ method public static androidx.graphics.path.PathSegment getCloseSegment();
+ method public static androidx.graphics.path.PathSegment getDoneSegment();
+ property public static final androidx.graphics.path.PathSegment CloseSegment;
+ property public static final androidx.graphics.path.PathSegment DoneSegment;
+ }
+
+}
+
diff --git a/graphics/graphics-path/api/public_plus_experimental_current.txt b/graphics/graphics-path/api/public_plus_experimental_current.txt
new file mode 100644
index 0000000..9be3390
--- /dev/null
+++ b/graphics/graphics-path/api/public_plus_experimental_current.txt
@@ -0,0 +1,61 @@
+// Signature format: 4.0
+package androidx.graphics.path {
+
+ @androidx.core.os.BuildCompat.PrereleaseSdkCheck public final class PathIterator implements java.util.Iterator<androidx.graphics.path.PathSegment> kotlin.jvm.internal.markers.KMappedMarker {
+ ctor public PathIterator(android.graphics.Path path, optional androidx.graphics.path.PathIterator.ConicEvaluation conicEvaluation, optional float tolerance);
+ method public int calculateSize(optional boolean includeConvertedConics);
+ method public androidx.graphics.path.PathIterator.ConicEvaluation getConicEvaluation();
+ method public android.graphics.Path getPath();
+ method public float getTolerance();
+ method public boolean hasNext();
+ method public androidx.graphics.path.PathSegment.Type next(float[] points, optional int offset);
+ method public androidx.graphics.path.PathSegment.Type next(float[] points);
+ method public androidx.graphics.path.PathSegment next();
+ method public androidx.graphics.path.PathSegment.Type peek();
+ property public final androidx.graphics.path.PathIterator.ConicEvaluation conicEvaluation;
+ property public final android.graphics.Path path;
+ property public final float tolerance;
+ }
+
+ public enum PathIterator.ConicEvaluation {
+ method public static androidx.graphics.path.PathIterator.ConicEvaluation valueOf(String name) throws java.lang.IllegalArgumentException;
+ method public static androidx.graphics.path.PathIterator.ConicEvaluation[] values();
+ enum_constant public static final androidx.graphics.path.PathIterator.ConicEvaluation AsConic;
+ enum_constant public static final androidx.graphics.path.PathIterator.ConicEvaluation AsQuadratics;
+ }
+
+ public final class PathSegment {
+ method public android.graphics.PointF![] getPoints();
+ method public androidx.graphics.path.PathSegment.Type getType();
+ method public float getWeight();
+ property public final android.graphics.PointF![] points;
+ property public final androidx.graphics.path.PathSegment.Type type;
+ property public final float weight;
+ }
+
+ public enum PathSegment.Type {
+ method public static androidx.graphics.path.PathSegment.Type valueOf(String name) throws java.lang.IllegalArgumentException;
+ method public static androidx.graphics.path.PathSegment.Type[] values();
+ enum_constant public static final androidx.graphics.path.PathSegment.Type Close;
+ enum_constant public static final androidx.graphics.path.PathSegment.Type Conic;
+ enum_constant public static final androidx.graphics.path.PathSegment.Type Cubic;
+ enum_constant public static final androidx.graphics.path.PathSegment.Type Done;
+ enum_constant public static final androidx.graphics.path.PathSegment.Type Line;
+ enum_constant public static final androidx.graphics.path.PathSegment.Type Move;
+ enum_constant public static final androidx.graphics.path.PathSegment.Type Quadratic;
+ }
+
+ public final class PathSegmentUtilities {
+ method public static androidx.graphics.path.PathSegment getCloseSegment();
+ method public static androidx.graphics.path.PathSegment getDoneSegment();
+ property public static final androidx.graphics.path.PathSegment CloseSegment;
+ property public static final androidx.graphics.path.PathSegment DoneSegment;
+ }
+
+ public final class PathUtilities {
+ method @androidx.core.os.BuildCompat.PrereleaseSdkCheck public static operator androidx.graphics.path.PathIterator iterator(android.graphics.Path);
+ method @androidx.core.os.BuildCompat.PrereleaseSdkCheck public static androidx.graphics.path.PathIterator iterator(android.graphics.Path, androidx.graphics.path.PathIterator.ConicEvaluation conicEvaluation, optional float tolerance);
+ }
+
+}
+
diff --git a/webkit/webkit/api/res-1.6.0-beta02.txt b/graphics/graphics-path/api/res-current.txt
similarity index 100%
copy from webkit/webkit/api/res-1.6.0-beta02.txt
copy to graphics/graphics-path/api/res-current.txt
diff --git a/graphics/graphics-path/api/restricted_current.txt b/graphics/graphics-path/api/restricted_current.txt
new file mode 100644
index 0000000..1b2faa6
--- /dev/null
+++ b/graphics/graphics-path/api/restricted_current.txt
@@ -0,0 +1,33 @@
+// Signature format: 4.0
+package androidx.graphics.path {
+
+ public final class PathSegment {
+ method public android.graphics.PointF![] getPoints();
+ method public androidx.graphics.path.PathSegment.Type getType();
+ method public float getWeight();
+ property public final android.graphics.PointF![] points;
+ property public final androidx.graphics.path.PathSegment.Type type;
+ property public final float weight;
+ }
+
+ public enum PathSegment.Type {
+ method public static androidx.graphics.path.PathSegment.Type valueOf(String name) throws java.lang.IllegalArgumentException;
+ method public static androidx.graphics.path.PathSegment.Type[] values();
+ enum_constant public static final androidx.graphics.path.PathSegment.Type Close;
+ enum_constant public static final androidx.graphics.path.PathSegment.Type Conic;
+ enum_constant public static final androidx.graphics.path.PathSegment.Type Cubic;
+ enum_constant public static final androidx.graphics.path.PathSegment.Type Done;
+ enum_constant public static final androidx.graphics.path.PathSegment.Type Line;
+ enum_constant public static final androidx.graphics.path.PathSegment.Type Move;
+ enum_constant public static final androidx.graphics.path.PathSegment.Type Quadratic;
+ }
+
+ public final class PathSegmentUtilities {
+ method public static androidx.graphics.path.PathSegment getCloseSegment();
+ method public static androidx.graphics.path.PathSegment getDoneSegment();
+ property public static final androidx.graphics.path.PathSegment CloseSegment;
+ property public static final androidx.graphics.path.PathSegment DoneSegment;
+ }
+
+}
+
diff --git a/graphics/graphics-path/build.gradle b/graphics/graphics-path/build.gradle
new file mode 100644
index 0000000..ddf300a
--- /dev/null
+++ b/graphics/graphics-path/build.gradle
@@ -0,0 +1,87 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import androidx.build.LibraryType
+
+plugins {
+ id("AndroidXPlugin")
+ id("com.android.library")
+ id("kotlin-android")
+}
+
+dependencies {
+ api(libs.kotlinStdlib)
+ androidTestImplementation(project(':appcompat:appcompat'))
+
+ implementation(project(':appcompat:appcompat'))
+ implementation('androidx.core:core:1.5.0-beta01')
+
+ androidTestImplementation("androidx.annotation:annotation:1.4.0")
+ androidTestImplementation("androidx.core:core-ktx:1.8.0")
+ androidTestImplementation("androidx.test:core:1.4.0@aar")
+ androidTestImplementation(libs.testExtJunit)
+ androidTestImplementation(libs.testCore)
+ androidTestImplementation(libs.testRunner)
+ androidTestImplementation(libs.testRules)
+ androidTestImplementation(libs.truth)
+}
+
+android {
+ namespace "androidx.graphics.path"
+
+ defaultConfig {
+ minSdkVersion 21 // Limited to 21+ due to native changes before that release
+ externalNativeBuild {
+ cmake {
+ cppFlags.addAll(
+ [
+ "-std=c++17",
+ "-Wno-unused-command-line-argument",
+ "-Wl,--hash-style=both", // Required to support API levels below 23
+ "-fno-stack-protector",
+ "-fno-exceptions",
+ "-fno-unwind-tables",
+ "-fno-asynchronous-unwind-tables",
+ "-fno-rtti",
+ "-ffast-math",
+ "-ffp-contract=fast",
+ "-fvisibility-inlines-hidden",
+ "-fvisibility=hidden",
+ "-fomit-frame-pointer",
+ "-ffunction-sections",
+ "-fdata-sections",
+ "-Wl,--gc-sections",
+ "-Wl,-Bsymbolic-functions",
+ ])
+ }
+ }
+ }
+
+ externalNativeBuild {
+ cmake {
+ path file('src/main/cpp/CMakeLists.txt')
+ version libs.versions.cmake.get()
+ }
+ }
+
+}
+
+androidx {
+ name = "Android Graphics Path"
+ type = LibraryType.PUBLISHED_LIBRARY
+ inceptionYear = "2022"
+ description = "Query segment data for android.graphics.Path objects"
+}
diff --git a/graphics/graphics-path/src/androidTest/java/androidx/graphics/path/PathIteratorTest.kt b/graphics/graphics-path/src/androidTest/java/androidx/graphics/path/PathIteratorTest.kt
new file mode 100644
index 0000000..5a58802
--- /dev/null
+++ b/graphics/graphics-path/src/androidTest/java/androidx/graphics/path/PathIteratorTest.kt
@@ -0,0 +1,544 @@
+/*
+ * Copyright 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.graphics.path
+
+import android.graphics.Bitmap
+import android.graphics.Color
+import android.graphics.Paint
+import android.graphics.Path
+import android.graphics.PointF
+import android.graphics.RectF
+import android.os.Build
+import androidx.core.graphics.applyCanvas
+import androidx.core.graphics.createBitmap
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import androidx.test.filters.SmallTest
+import kotlin.math.abs
+import org.junit.Assert.assertEquals
+import org.junit.Assert.assertTrue
+import org.junit.Assert.fail
+import org.junit.Test
+import org.junit.runner.RunWith
+
+private fun assertPointsEquals(p1: PointF, p2: PointF) {
+ assertEquals(p1.x, p2.x, 1e-6f)
+ assertEquals(p1.y, p2.y, 1e-6f)
+}
+
+private fun assertPointsEquals(p1: FloatArray, offset: Int, p2: PointF) {
+ assertEquals(p1[0 + offset * 2], p2.x, 1e-6f)
+ assertEquals(p1[1 + offset * 2], p2.y, 1e-6f)
+}
+
+private fun compareBitmaps(b1: Bitmap, b2: Bitmap) {
+ val epsilon: Int
+ if (Build.VERSION.SDK_INT != 23) {
+ epsilon = 1
+ } else {
+ // There is more AA variability between conics and cubics on API 23, leading
+ // to failures on relatively small visual differences. Increase the error
+ // value for just this release to avoid erroneous bitmap comparison failures.
+ epsilon = 32
+ }
+
+ assertEquals(b1.width, b2.width)
+ assertEquals(b1.height, b2.height)
+
+ val p1 = IntArray(b1.width * b1.height)
+ b1.getPixels(p1, 0, b1.width, 0, 0, b1.width, b1.height)
+
+ val p2 = IntArray(b2.width * b2.height)
+ b2.getPixels(p2, 0, b2.width, 0, 0, b2.width, b2.height)
+
+ for (x in 0 until b1.width) {
+ for (y in 0 until b2.width) {
+ val index = y * b1.width + x
+
+ val c1 = p1[index]
+ val c2 = p2[index]
+
+ assertTrue(abs(Color.red(c1) - Color.red(c2)) <= epsilon)
+ assertTrue(abs(Color.green(c1) - Color.green(c2)) <= epsilon)
+ assertTrue(abs(Color.blue(c1) - Color.blue(c2)) <= epsilon)
+ }
+ }
+}
+
+@SmallTest
+@RunWith(AndroidJUnit4::class)
+class PathIteratorTest {
+ @Test
+ fun emptyIterator() {
+ val path = Path()
+
+ val iterator = path.iterator()
+ // TODO: un-comment the hasNext() check when the platform has the behavior change
+ // which ignores final DONE ops in the value for hasNext()
+ // assertFalse(iterator.hasNext())
+ val firstSegment = iterator.next()
+ assertEquals(PathSegment.Type.Done, firstSegment.type)
+
+ var count = 0
+ for (segment in path) {
+ // TODO: remove condition check and just increment count when platform change
+ // is checked in which will not iterate when DONE is the only op left
+ if (segment.type != PathSegment.Type.Done) {
+ // Shouldn't get here; count should remain 0
+ count++
+ }
+ }
+
+ assertEquals(0, count)
+ }
+
+ @Test
+ fun emptyPeek() {
+ val path = Path()
+ val iterator = path.iterator()
+ assertEquals(PathSegment.Type.Done, iterator.peek())
+ }
+
+ @Test
+ fun nonEmptyIterator() {
+ val path = Path().apply {
+ moveTo(1.0f, 1.0f)
+ lineTo(2.0f, 2.0f)
+ close()
+ }
+
+ val iterator = path.iterator()
+ assertTrue(iterator.hasNext())
+
+ val types = arrayOf(
+ PathSegment.Type.Move,
+ PathSegment.Type.Line,
+ PathSegment.Type.Close,
+ PathSegment.Type.Done
+ )
+ val points = arrayOf(
+ PointF(1.0f, 1.0f),
+ PointF(2.0f, 2.0f)
+ )
+
+ var count = 0
+ for (segment in path) {
+ assertEquals(types[count], segment.type)
+ when (segment.type) {
+ PathSegment.Type.Move -> {
+ assertEquals(points[count], segment.points[0])
+ }
+ PathSegment.Type.Line -> {
+ assertEquals(points[count - 1], segment.points[0])
+ assertEquals(points[count], segment.points[1])
+ }
+ else -> { }
+ }
+ // TODO: remove condition and just auto-increment count when platform change is
+ // checked in which ignores DONE during iteration
+ if (segment.type != PathSegment.Type.Done) count++
+ }
+
+ assertEquals(3, count)
+ }
+
+ @Test
+ fun peek() {
+ val path = Path().apply {
+ moveTo(1.0f, 1.0f)
+ lineTo(2.0f, 2.0f)
+ close()
+ }
+
+ val iterator = path.iterator()
+ assertEquals(PathSegment.Type.Move, iterator.peek())
+ }
+
+ @Test
+ fun peekBeyond() {
+ val path = Path()
+ assertEquals(PathSegment.Type.Done, path.iterator().peek())
+
+ path.apply {
+ moveTo(1.0f, 1.0f)
+ lineTo(2.0f, 2.0f)
+ close()
+ }
+
+ val iterator = path.iterator()
+ while (iterator.hasNext()) iterator.next()
+ assertEquals(PathSegment.Type.Done, iterator.peek())
+ }
+
+ @Test
+ fun iteratorStyles() {
+ val path = Path().apply {
+ moveTo(1.0f, 1.0f)
+ lineTo(2.0f, 2.0f)
+ cubicTo(3.0f, 3.0f, 4.0f, 4.0f, 5.0f, 5.0f)
+ quadTo(7.0f, 7.0f, 8.0f, 8.0f)
+ moveTo(10.0f, 10.0f)
+ // addRoundRect() will generate conic curves on certain API levels
+ addRoundRect(RectF(12.0f, 12.0f, 36.0f, 36.0f), 8.0f, 8.0f, Path.Direction.CW)
+ close()
+ }
+
+ iteratorStylesImpl(path, PathIterator.ConicEvaluation.AsConic)
+ iteratorStylesImpl(path, PathIterator.ConicEvaluation.AsQuadratics)
+ }
+
+ private fun iteratorStylesImpl(path: Path, conicEvaluation: PathIterator.ConicEvaluation) {
+ val iterator1 = path.iterator(conicEvaluation)
+ val iterator2 = path.iterator(conicEvaluation)
+ val iterator3 = path.iterator(conicEvaluation)
+
+ val points = FloatArray(8)
+ val points2 = FloatArray(16)
+
+ while (iterator1.hasNext() || iterator2.hasNext() || iterator3.hasNext()) {
+ val segment = iterator1.next()
+ val type = iterator2.next(points)
+ val type2 = iterator3.next(points2, 8)
+
+ assertEquals(type, segment.type)
+ assertEquals(type2, segment.type)
+
+ when (type) {
+ PathSegment.Type.Move -> {
+ assertPointsEquals(points, 0, segment.points[0])
+ assertPointsEquals(points2, 4, segment.points[0])
+ }
+
+ PathSegment.Type.Line -> {
+ assertPointsEquals(points, 0, segment.points[0])
+ assertPointsEquals(points, 1, segment.points[1])
+ assertPointsEquals(points2, 4, segment.points[0])
+ assertPointsEquals(points2, 5, segment.points[1])
+ }
+
+ PathSegment.Type.Quadratic -> {
+ assertPointsEquals(points, 0, segment.points[0])
+ assertPointsEquals(points, 1, segment.points[1])
+ assertPointsEquals(points, 2, segment.points[2])
+ assertPointsEquals(points2, 4, segment.points[0])
+ assertPointsEquals(points2, 5, segment.points[1])
+ assertPointsEquals(points2, 6, segment.points[2])
+ }
+
+ PathSegment.Type.Conic -> {
+ assertPointsEquals(points, 0, segment.points[0])
+ assertPointsEquals(points, 1, segment.points[1])
+ assertPointsEquals(points, 2, segment.points[2])
+ // Weight is stored after all of the points
+ assertEquals(points[6], segment.weight)
+
+ assertPointsEquals(points2, 4, segment.points[0])
+ assertPointsEquals(points2, 5, segment.points[1])
+ assertPointsEquals(points2, 6, segment.points[2])
+ // Weight is stored after all of the points
+ assertEquals(points2[14], segment.weight)
+ }
+
+ PathSegment.Type.Cubic -> {
+ assertPointsEquals(points, 0, segment.points[0])
+ assertPointsEquals(points, 1, segment.points[1])
+ assertPointsEquals(points, 2, segment.points[2])
+ assertPointsEquals(points, 3, segment.points[3])
+
+ assertPointsEquals(points2, 4, segment.points[0])
+ assertPointsEquals(points2, 5, segment.points[1])
+ assertPointsEquals(points2, 6, segment.points[2])
+ assertPointsEquals(points2, 7, segment.points[3])
+ }
+
+ PathSegment.Type.Close -> {}
+ PathSegment.Type.Done -> {}
+ }
+ }
+ }
+
+ @Test
+ fun done() {
+ val path = Path().apply {
+ close()
+ }
+
+ val segment = path.iterator().next()
+
+ assertEquals(PathSegment.Type.Done, segment.type)
+ assertEquals(0, segment.points.size)
+ assertEquals(0.0f, segment.weight)
+ }
+
+ @Test
+ fun close() {
+ val path = Path().apply {
+ lineTo(10.0f, 12.0f)
+ close()
+ }
+
+ val iterator = path.iterator()
+ // Swallow the move
+ iterator.next()
+ // Swallow the line
+ iterator.next()
+
+ val segment = iterator.next()
+
+ assertEquals(PathSegment.Type.Close, segment.type)
+ assertEquals(0, segment.points.size)
+ assertEquals(0.0f, segment.weight)
+ }
+
+ @Test
+ fun moveTo() {
+ val path = Path().apply {
+ moveTo(10.0f, 12.0f)
+ }
+
+ val segment = path.iterator().next()
+
+ assertEquals(PathSegment.Type.Move, segment.type)
+ assertEquals(1, segment.points.size)
+ assertPointsEquals(PointF(10.0f, 12.0f), segment.points[0])
+ assertEquals(0.0f, segment.weight)
+ }
+
+ @Test
+ fun lineTo() {
+ val path = Path().apply {
+ moveTo(4.0f, 6.0f)
+ lineTo(10.0f, 12.0f)
+ }
+
+ val iterator = path.iterator()
+ // Swallow the move
+ iterator.next()
+
+ val segment = iterator.next()
+
+ assertEquals(PathSegment.Type.Line, segment.type)
+ assertEquals(2, segment.points.size)
+ assertPointsEquals(PointF(4.0f, 6.0f), segment.points[0])
+ assertPointsEquals(PointF(10.0f, 12.0f), segment.points[1])
+ assertEquals(0.0f, segment.weight)
+ }
+
+ @Test
+ fun quadraticTo() {
+ val path = Path().apply {
+ moveTo(4.0f, 6.0f)
+ quadTo(10.0f, 12.0f, 20.0f, 24.0f)
+ }
+
+ val iterator = path.iterator()
+ // Swallow the move
+ iterator.next()
+
+ val segment = iterator.next()
+
+ assertEquals(PathSegment.Type.Quadratic, segment.type)
+ assertEquals(3, segment.points.size)
+ assertPointsEquals(PointF(4.0f, 6.0f), segment.points[0])
+ assertPointsEquals(PointF(10.0f, 12.0f), segment.points[1])
+ assertPointsEquals(PointF(20.0f, 24.0f), segment.points[2])
+ assertEquals(0.0f, segment.weight)
+ }
+
+ @Test
+ fun cubicTo() {
+ val path = Path().apply {
+ moveTo(4.0f, 6.0f)
+ cubicTo(10.0f, 12.0f, 20.0f, 24.0f, 30.0f, 36.0f)
+ }
+
+ val iterator = path.iterator()
+ // Swallow the move
+ iterator.next()
+
+ val segment = iterator.next()
+
+ assertEquals(PathSegment.Type.Cubic, segment.type)
+ assertEquals(4, segment.points.size)
+ assertPointsEquals(PointF(4.0f, 6.0f), segment.points[0])
+ assertPointsEquals(PointF(10.0f, 12.0f), segment.points[1])
+ assertPointsEquals(PointF(20.0f, 24.0f), segment.points[2])
+ assertPointsEquals(PointF(30.0f, 36.0f), segment.points[3])
+ assertEquals(0.0f, segment.weight)
+ }
+
+ @Test
+ fun conicTo() {
+ if (Build.VERSION.SDK_INT >= 25) {
+ val path = Path().apply {
+ addRoundRect(RectF(12.0f, 12.0f, 24.0f, 24.0f), 8.0f, 8.0f, Path.Direction.CW)
+ }
+
+ val iterator = path.iterator(PathIterator.ConicEvaluation.AsConic)
+ // Swallow the move
+ iterator.next()
+
+ val segment = iterator.next()
+
+ assertEquals(PathSegment.Type.Conic, segment.type)
+ assertEquals(3, segment.points.size)
+
+ assertPointsEquals(PointF(12.0f, 18.0f), segment.points[0])
+ assertPointsEquals(PointF(12.0f, 12.0f), segment.points[1])
+ assertPointsEquals(PointF(18.0f, 12.0f), segment.points[2])
+ assertEquals(0.70710677f, segment.weight)
+ }
+ }
+
+ @Test
+ fun conicAsQuadratics() {
+ val path = Path().apply {
+ addRoundRect(RectF(12.0f, 12.0f, 24.0f, 24.0f), 8.0f, 8.0f, Path.Direction.CW)
+ }
+
+ for (segment in path) {
+ if (segment.type == PathSegment.Type.Conic) fail("Found conic, none expected: $segment")
+ }
+ }
+
+ @Test
+ fun convertedConics() {
+ val path1 = Path().apply {
+ addRoundRect(RectF(12.0f, 12.0f, 64.0f, 64.0f), 12.0f, 12.0f, Path.Direction.CW)
+ }
+
+ val path2 = Path()
+ for (segment in path1) {
+ when (segment.type) {
+ PathSegment.Type.Move -> path2.moveTo(segment.points[0].x, segment.points[0].y)
+ PathSegment.Type.Line -> path2.lineTo(segment.points[1].x, segment.points[1].y)
+ PathSegment.Type.Quadratic -> path2.quadTo(
+ segment.points[1].x, segment.points[1].y,
+ segment.points[2].x, segment.points[2].y
+ )
+ PathSegment.Type.Conic -> fail("Unexpected conic! $segment")
+ PathSegment.Type.Cubic -> path2.cubicTo(
+ segment.points[1].x, segment.points[1].y,
+ segment.points[2].x, segment.points[2].y,
+ segment.points[3].x, segment.points[3].y
+ )
+ PathSegment.Type.Close -> path2.close()
+ PathSegment.Type.Done -> { }
+ }
+ }
+
+ // Now with smaller error tolerance
+ val path3 = Path()
+ for (segment in path1.iterator(
+ conicEvaluation = PathIterator.ConicEvaluation.AsQuadratics,
+ .001f
+ )) {
+ when (segment.type) {
+ PathSegment.Type.Move -> path3.moveTo(segment.points[0].x, segment.points[0].y)
+ PathSegment.Type.Line -> path3.lineTo(segment.points[1].x, segment.points[1].y)
+ PathSegment.Type.Quadratic -> path3.quadTo(
+ segment.points[1].x, segment.points[1].y,
+ segment.points[2].x, segment.points[2].y
+ )
+ PathSegment.Type.Conic -> fail("Unexpected conic! $segment")
+ PathSegment.Type.Cubic -> path3.cubicTo(
+ segment.points[1].x, segment.points[1].y,
+ segment.points[2].x, segment.points[2].y,
+ segment.points[3].x, segment.points[3].y
+ )
+ PathSegment.Type.Close -> path3.close()
+ PathSegment.Type.Done -> { }
+ }
+ }
+
+ val b1 = createBitmap(76, 76).applyCanvas {
+ drawARGB(255, 255, 255, 255)
+ drawPath(path1, Paint().apply {
+ color = argb(1.0f, 0.0f, 0.0f, 1.0f)
+ strokeWidth = 2.0f
+ isAntiAlias = true
+ style = Paint.Style.STROKE
+ })
+ }
+
+ val b2 = createBitmap(76, 76).applyCanvas {
+ drawARGB(255, 255, 255, 255)
+ drawPath(path2, Paint().apply {
+ color = argb(1.0f, 0.0f, 0.0f, 1.0f)
+ strokeWidth = 2.0f
+ isAntiAlias = true
+ style = Paint.Style.STROKE
+ })
+ }
+
+ compareBitmaps(b1, b2)
+ // Note: b1-vs-b3 is not a valid comparison; default Skia rendering does not use an
+ // error tolerance that low. The test for fine-precision in path3 was just to
+ // ensure that the system could handle the extra data and operations required
+ }
+
+ @Test
+ fun sizes() {
+ val path = Path()
+ var iterator: PathIterator = path.iterator()
+
+ if (iterator.calculateSize() > 0) {
+ assertEquals(PathSegment.Type.Done, iterator.peek())
+ }
+ // TODO: replace above check with below assertEquals after platform change is checked
+ // in which returns a size of zero when there the only op in the path is DONE
+ // assertEquals(0, iterator.size())
+
+ path.addRoundRect(RectF(12.0f, 12.0f, 64.0f, 64.0f), 8.0f, 8.0f,
+ Path.Direction.CW)
+
+ // Skia converted
+ if (Build.VERSION.SDK_INT > 22) {
+ // Preserve conics and count
+ iterator = path.iterator(PathIterator.ConicEvaluation.AsConic)
+ assert(iterator.calculateSize() == 10 || iterator.calculateSize() == 11)
+ // TODO: replace assert() above with assertEquals below once platform change exists
+ // which does not count final DONE in the size
+ // assertEquals(10, iterator.size())
+ assertEquals(iterator.calculateSize(true), iterator.calculateSize())
+ }
+
+ // Convert conics and count
+ iterator = path.iterator(PathIterator.ConicEvaluation.AsQuadratics)
+ if (Build.VERSION.SDK_INT > 22) {
+ // simple size, not including conic conversion
+ assert(iterator.calculateSize(false) == 10 || iterator.calculateSize(false) == 11)
+ // TODO: replace assert() above with assertEquals below once platform change exists
+ // which does not count final DONE in the size
+ // assertEquals(10, iterator.size(false))
+ } else {
+ // round rects pre-API22 used line/quad/quad for each corner
+ assertEquals(14, iterator.calculateSize())
+ }
+ // now get the size with converted conics
+ val size = iterator.calculateSize()
+ assert(size == 14 || size == 15)
+ // TODO: replace assert() above with assertEquals below once platform change exists
+ // which does not count final DONE in the size
+ // assertEquals(14, iterator.size())
+ }
+}
+
+fun argb(alpha: Float, red: Float, green: Float, blue: Float) =
+ ((alpha * 255.0f + 0.5f).toInt() shl 24) or
+ ((red * 255.0f + 0.5f).toInt() shl 16) or
+ ((green * 255.0f + 0.5f).toInt() shl 8) or
+ (blue * 255.0f + 0.5f).toInt()
diff --git a/graphics/graphics-path/src/main/androidx/graphics/androidx-graphics-graphics-path-documentation.md b/graphics/graphics-path/src/main/androidx/graphics/androidx-graphics-graphics-path-documentation.md
new file mode 100644
index 0000000..6c44750
--- /dev/null
+++ b/graphics/graphics-path/src/main/androidx/graphics/androidx-graphics-graphics-path-documentation.md
@@ -0,0 +1,117 @@
+# Package androidx.graphics.paths
+
+Androidx Graphics Path is an Android library that provides new functionalities around the
+[Path](https://developer.android.com/reference/android/graphics/Path) API. Specifically, it
+allows paths to be queried for the segment data they contain,
+
+The library is compatible with API 21+.
+
+## Iterating over a Path
+
+With Pathway you can easily iterate over a `Path` object to inspect its segments
+(curves or commands):
+
+```kotlin
+val path = Path().apply {
+ // Build path content
+}
+
+for (segment in path) {
+ val type = segment.type // The type of segment (move, cubic, quadratic, line, close, etc.)
+ val points = segment.points // The points describing the segment geometry
+}
+```
+
+This type of iteration is easy to use but may create an allocation per segment iterated over.
+If you must avoid allocations, Pathway provides a lower-level API to do so:
+
+```kotlin
+val path = Path().apply {
+ // Build path content
+}
+
+val iterator = path.iterator
+val points = FloatArray(8)
+
+while (iterator.hasNext()) {
+ val type = iterator.next(points) // The type of segment
+ // Read the segment geometry from the points array depending on the type
+}
+
+```
+
+### Path segments
+
+Each segment in a `Path` can be of one of the following types:
+
+#### Move
+
+Move command. The path segment contains 1 point indicating the move destination.
+The weight is set 0.0f and not meaningful.
+
+#### Line
+
+Line curve. The path segment contains 2 points indicating the two extremities of
+the line. The weight is set 0.0f and not meaningful.
+
+#### Quadratic
+
+Quadratic curve. The path segment contains 3 points in the following order:
+- Start point
+- Control point
+- End point
+
+The weight is set 0.0f and not meaningful.
+
+#### Conic
+
+Conic curve. The path segment contains 3 points in the following order:
+- Start point
+- Control point
+- End point
+
+The curve is weighted by the `PathSegment.weight` property.
+
+Conic curves are automatically converted to quadratic curves by default, see
+[Handling conic segments](#handling-conic-segments) below for more information.
+
+#### Cubic
+
+Cubic curve. The path segment contains 4 points in the following order:
+- Start point
+- First control point
+- Second control point
+- End point
+
+The weight is set to 0.0f and is not meaningful.
+
+#### Close
+
+Close command. Close the current contour by joining the last point added to the
+path with the first point of the current contour. The segment does not contain
+any point. The weight is set 0.0f and not meaningful.
+
+#### Done
+
+Done command. This optional command indicates that no further segment will be
+found in the path. It typically indicates the end of an iteration over a path
+and can be ignored.
+
+## Handling conic segments
+
+In some API levels, paths may contain conic curves (weighted quadratics) but the
+`Path` API does not offer a way to add conics to a `Path` object. To work around
+this, Pathway automatically converts conics into several quadratics by default.
+
+The conic to quadratic conversion is an approximation controlled by a tolerance
+threshold, set by default to 0.25f (sub-pixel). If you want to preserve conics
+or control the tolerance, you can use the following APIs:
+
+```kotlin
+// Preserve conics
+val iterator = path.iterator(PathIterator.ConicEvaluation.AsConic)
+
+// Control the tolerance of the conic to quadratic conversion
+val iterator = path.iterator(PathIterator.ConicEvaluation.AsQuadratics, 2.0f)
+
+```
diff --git a/graphics/graphics-path/src/main/cpp/CMakeLists.txt b/graphics/graphics-path/src/main/cpp/CMakeLists.txt
new file mode 100644
index 0000000..e77704f
--- /dev/null
+++ b/graphics/graphics-path/src/main/cpp/CMakeLists.txt
@@ -0,0 +1,20 @@
+cmake_minimum_required(VERSION 3.18.1)
+project("androidx.graphics.path")
+
+add_library(
+ androidx.graphics.path
+ SHARED
+ Conic.cpp
+ PathIterator.cpp
+ pathway.cpp
+)
+
+find_library(
+ log-lib
+ log
+)
+
+target_link_libraries(
+ androidx.graphics.path
+ ${log-lib}
+)
diff --git a/graphics/graphics-path/src/main/cpp/Conic.cpp b/graphics/graphics-path/src/main/cpp/Conic.cpp
new file mode 100644
index 0000000..a6d15b6
--- /dev/null
+++ b/graphics/graphics-path/src/main/cpp/Conic.cpp
@@ -0,0 +1,170 @@
+/*
+ * Copyright 2022 The Android Open Source Project
+ * Copyright (C) 2006 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "Conic.h"
+
+#include "scalar.h"
+
+#include "math/vec2.h"
+
+#include <cmath>
+#include <cstring>
+
+using namespace filament::math;
+
+constexpr int kMaxConicToQuadCount = 5;
+
+constexpr bool isFinite(const Point points[], int count) noexcept {
+ return isFinite(&points[0].x, count << 1);
+}
+
+constexpr bool isFinite(const Point& point) noexcept {
+ float a = 0.0f;
+ a *= point.x;
+ a *= point.y;
+ return a == 0.0f;
+}
+
+constexpr Point toPoint(const float2& v) noexcept {
+ return { .x = v.x, .y = v.y };
+}
+
+constexpr float2 fromPoint(const Point& v) noexcept {
+ return float2{v.x, v.y};
+}
+
+int conicToQuadratics(
+ const Point conicPoints[3], Point *quadraticPoints, int bufferSize,
+ float weight, float tolerance
+) noexcept {
+ Conic conic(conicPoints[0], conicPoints[1], conicPoints[2], weight);
+
+ int count = conic.computeQuadraticCount(tolerance);
+ int quadraticCount = 1 << count;
+ if (quadraticCount > bufferSize) {
+ // Buffer not large enough; return necessary size to resize and try again
+ return quadraticCount;
+ }
+ quadraticCount = conic.splitIntoQuadratics(quadraticPoints, count);
+
+ return quadraticCount;
+}
+
+int Conic::computeQuadraticCount(float tolerance) const noexcept {
+ if (tolerance <= 0.0f || !isFinite(tolerance) || !isFinite(points, 3)) return 0;
+
+ float a = weight - 1.0f;
+ float k = a / (4.0f * (2.0f + a));
+ float x = k * (points[0].x - 2.0f * points[1].x + points[2].x);
+ float y = k * (points[0].y - 2.0f * points[1].y + points[2].y);
+
+ float error = std::sqrtf(x * x + y * y);
+ int count = 0;
+ for ( ; count < kMaxConicToQuadCount; count++) {
+ if (error <= tolerance) break;
+ error *= 0.25f;
+ }
+
+ return count;
+}
+
+static Point* subdivide(const Conic& src, Point pts[], int level) {
+ if (level == 0) {
+ memcpy(pts, &src.points[1], 2 * sizeof(Point));
+ return pts + 2;
+ } else {
+ Conic dst[2];
+ src.split(dst);
+ const float startY = src.points[0].y;
+ const float endY = src.points[2].y;
+ if (between(startY, src.points[1].y, endY)) {
+ float midY = dst[0].points[2].y;
+ if (!between(startY, midY, endY)) {
+ float closerY = tabs(midY - startY) < tabs(midY - endY) ? startY : endY;
+ dst[0].points[2].y = dst[1].points[0].y = closerY;
+ }
+ if (!between(startY, dst[0].points[1].y, dst[0].points[2].y)) {
+ dst[0].points[1].y = startY;
+ }
+ if (!between(dst[1].points[0].y, dst[1].points[1].y, endY)) {
+ dst[1].points[1].y = endY;
+ }
+ }
+ --level;
+ pts = subdivide(dst[0], pts, level);
+ return subdivide(dst[1], pts, level);
+ }
+}
+
+void Conic::split(Conic* __restrict__ dst) const noexcept {
+ float2 scale{1.0f / (1.0f + weight)};
+ float newW = std::sqrtf(0.5f + weight * 0.5f);
+
+ float2 p0 = fromPoint(points[0]);
+ float2 p1 = fromPoint(points[1]);
+ float2 p2 = fromPoint(points[2]);
+ float2 ww(weight);
+
+ float2 wp1 = ww * p1;
+ float2 m = (p0 + (wp1 + wp1) + p2) * scale * float2(0.5f);
+ Point pt = toPoint(m);
+ if (!isFinite(pt)) {
+ double w_d = weight;
+ double w_2 = w_d * 2.0;
+ double scale_half = 1.0 / (1.0 + w_d) * 0.5;
+ pt.x = float((points[0].x + w_2 * points[1].x + points[2].x) * scale_half);
+ pt.y = float((points[0].y + w_2 * points[1].y + points[2].y) * scale_half);
+ }
+ dst[0].points[0] = points[0];
+ dst[0].points[1] = toPoint((p0 + wp1) * scale);
+ dst[0].points[2] = dst[1].points[0] = pt;
+ dst[1].points[1] = toPoint((wp1 + p2) * scale);
+ dst[1].points[2] = points[2];
+
+ dst[0].weight = dst[1].weight = newW;
+}
+
+int Conic::splitIntoQuadratics(Point dstPoints[], int count) const noexcept {
+ *dstPoints = points[0];
+
+ if (count >= kMaxConicToQuadCount) {
+ Conic dst[2];
+ split(dst);
+
+ if (equals(dst[0].points[1], dst[0].points[2]) &&
+ equals(dst[1].points[0], dst[1].points[1])) {
+ dstPoints[1] = dstPoints[2] = dstPoints[3] = dst[0].points[1];
+ dstPoints[4] = dst[1].points[2];
+ count = 1;
+ goto commonFinitePointCheck;
+ }
+ }
+
+ subdivide(*this, dstPoints + 1, count);
+
+commonFinitePointCheck:
+ const int quadCount = 1 << count;
+ const int pointCount = 2 * quadCount + 1;
+
+ if (!isFinite(dstPoints, pointCount)) {
+ for (int i = 1; i < pointCount - 1; ++i) {
+ dstPoints[i] = points[1];
+ }
+ }
+
+ return quadCount;
+}
\ No newline at end of file
diff --git a/graphics/graphics-path/src/main/cpp/Conic.h b/graphics/graphics-path/src/main/cpp/Conic.h
new file mode 100644
index 0000000..548fea2
--- /dev/null
+++ b/graphics/graphics-path/src/main/cpp/Conic.h
@@ -0,0 +1,57 @@
+/*
+ * Copyright 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef PATH_CONIC_H
+#define PATH_CONIC_H
+
+#include "Path.h"
+
+#include <vector>
+
+constexpr int kDefaultQuadraticCount = 8;
+
+int conicToQuadratics(
+ const Point conicPoints[3], Point *quadraticPoints, int bufferSize,
+ float weight, float tolerance
+) noexcept;
+
+class ConicConverter {
+public:
+ ConicConverter() noexcept { }
+
+private:
+ std::vector<Point> mStorage{1 + 2 * kDefaultQuadraticCount};
+};
+
+struct Conic {
+ Conic() noexcept { }
+
+ Conic(Point p0, Point p1, Point p2, float weight) noexcept {
+ points[0] = p0;
+ points[1] = p1;
+ points[2] = p2;
+ this->weight = weight;
+ }
+
+ void split(Conic* __restrict__ dst) const noexcept;
+ int computeQuadraticCount(float tolerance) const noexcept;
+ int splitIntoQuadratics(Point dstPoints[], int count) const noexcept;
+
+ Point points[3];
+ float weight;
+};
+
+#endif //PATH_CONIC_H
diff --git a/graphics/graphics-path/src/main/cpp/Path.h b/graphics/graphics-path/src/main/cpp/Path.h
new file mode 100644
index 0000000..f25d708
--- /dev/null
+++ b/graphics/graphics-path/src/main/cpp/Path.h
@@ -0,0 +1,122 @@
+/*
+ * Copyright 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef PATH_PATH_H
+#define PATH_PATH_H
+
+#include <stdint.h>
+
+// The following structures declare the minimum we need + a marker (generationId) to
+// validate the data during debugging. There may be more fields in the Skia structures
+// but we just ignore them for now. Some fields declared in older API levels (isFinite
+// for instance) may not show up in the declarations for newer API levels if the field
+// still exist but was moved after the data we need.
+
+enum class Verb : uint8_t {
+ Move,
+ Line,
+ Quadratic,
+ Conic,
+ Cubic,
+ Close,
+ Done
+};
+
+struct Point {
+ float x;
+ float y;
+};
+
+struct PathRef21 {
+ __unused intptr_t pointer; // Virtual tables
+ __unused int32_t refCount;
+ __unused float left;
+ __unused float top;
+ __unused float right;
+ __unused float bottom;
+ __unused uint8_t segmentMask; // Some of the unused fields are in a different order in 22/23
+ __unused uint8_t boundsIsDirty;
+ __unused uint8_t isFinite;
+ __unused uint8_t isOval;
+ Point* points;
+ Verb* verbs;
+ int verbCount;
+ __unused int pointCount;
+ __unused size_t freeSpace;
+ float* conicWeights;
+ __unused int conicWeightsReserve;
+ __unused int conicWeightsCount;
+ __unused uint32_t generationId;
+};
+
+struct PathRef24 {
+ __unused intptr_t pointer;
+ __unused int32_t refCount;
+ __unused float left;
+ __unused float top;
+ __unused float right;
+ __unused float bottom;
+ Point* points;
+ Verb* verbs;
+ int verbCount;
+ __unused int pointCount;
+ __unused size_t freeSpace;
+ float* conicWeights;
+ __unused int conicWeightsReserve;
+ __unused int conicWeightsCount;
+ __unused uint32_t generationId;
+};
+
+struct PathRef26 {
+ __unused int32_t refCount;
+ __unused float left;
+ __unused float top;
+ __unused float right;
+ __unused float bottom;
+ Point* points;
+ Verb* verbs;
+ int verbCount;
+ __unused int pointCount;
+ __unused size_t freeSpace;
+ float* conicWeights;
+ __unused int conicWeightsReserve;
+ __unused int conicWeightsCount;
+ __unused uint32_t generationId;
+};
+
+struct PathRef30 {
+ __unused int32_t refCount;
+ __unused float left;
+ __unused float top;
+ __unused float right;
+ __unused float bottom;
+ Point* points;
+ __unused int pointReserve;
+ __unused int pointCount;
+ Verb* verbs;
+ __unused int verbReserve;
+ int verbCount;
+ float* conicWeights;
+ __unused int conicWeightsReserve;
+ __unused int conicWeightsCount;
+ __unused uint32_t generationId;
+};
+
+struct Path {
+ PathRef21* pathRef;
+};
+
+#endif //PATH_PATH_H
diff --git a/graphics/graphics-path/src/main/cpp/PathIterator.cpp b/graphics/graphics-path/src/main/cpp/PathIterator.cpp
new file mode 100644
index 0000000..a77e251
--- /dev/null
+++ b/graphics/graphics-path/src/main/cpp/PathIterator.cpp
@@ -0,0 +1,100 @@
+/*
+ * Copyright 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "PathIterator.h"
+
+int PathIterator::count() noexcept {
+ int count = 0;
+ const Verb* verbs = mVerbs;
+ const Point* points = mPoints;
+ const float* conicWeights = mConicWeights;
+
+ for (int i = 0; i < mCount; i++) {
+ Verb verb = *(mDirection == VerbDirection::Forward ? verbs++ : --verbs);
+ switch (verb) {
+ case Verb::Move:
+ case Verb::Line:
+ points += 1;
+ count++;
+ break;
+ case Verb::Quadratic:
+ points += 2;
+ count++;
+ break;
+ case Verb::Conic:
+ points += 2;
+ count++;
+ break;
+ case Verb::Cubic:
+ points += 3;
+ count++;
+ break;
+ case Verb::Close:
+ case Verb::Done:
+ count++;
+ break;
+ }
+ }
+
+ return count;
+}
+
+Verb PathIterator::next(Point points[4]) noexcept {
+ if (mIndex <= 0) {
+ return Verb::Done;
+ }
+ mIndex--;
+
+ Verb verb = *(mDirection == VerbDirection::Forward ? mVerbs++ : --mVerbs);
+ switch (verb) {
+ case Verb::Move:
+ points[0] = mPoints[0];
+ mPoints += 1;
+ break;
+ case Verb::Line:
+ points[0] = mPoints[-1];
+ points[1] = mPoints[0];
+ mPoints += 1;
+ break;
+ case Verb::Quadratic:
+ points[0] = mPoints[-1];
+ points[1] = mPoints[0];
+ points[2] = mPoints[1];
+ mPoints += 2;
+ break;
+ case Verb::Conic:
+ points[0] = mPoints[-1];
+ points[1] = mPoints[0];
+ points[2] = mPoints[1];
+ points[3].x = *mConicWeights;
+ points[3].y = *mConicWeights;
+ mConicWeights++;
+ mPoints += 2;
+ break;
+ case Verb::Cubic:
+ points[0] = mPoints[-1];
+ points[1] = mPoints[0];
+ points[2] = mPoints[1];
+ points[3] = mPoints[2];
+ mPoints += 3;
+ break;
+ case Verb::Close:
+ case Verb::Done:
+ break;
+ }
+
+ return verb;
+}
diff --git a/graphics/graphics-path/src/main/cpp/PathIterator.h b/graphics/graphics-path/src/main/cpp/PathIterator.h
new file mode 100644
index 0000000..f814863
--- /dev/null
+++ b/graphics/graphics-path/src/main/cpp/PathIterator.h
@@ -0,0 +1,68 @@
+/*
+ * Copyright 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef PATH_PATH_ITERATOR_H
+#define PATH_PATH_ITERATOR_H
+
+#include "Path.h"
+#include "Conic.h"
+
+class PathIterator {
+public:
+ enum class VerbDirection : uint8_t {
+ Forward, // API >=30
+ Backward // API < 30
+ };
+
+ PathIterator(
+ Point* points,
+ Verb* verbs,
+ float* conicWeights,
+ int count,
+ VerbDirection direction
+ ) noexcept
+ : mPoints(points),
+ mVerbs(verbs),
+ mConicWeights(conicWeights),
+ mIndex(count),
+ mCount(count),
+ mDirection(direction) {
+ }
+
+ int rawCount() const noexcept { return mCount; }
+
+ int count() noexcept;
+
+ bool hasNext() const noexcept { return mIndex > 0; }
+
+ Verb peek() const noexcept {
+ auto verbs = mDirection == VerbDirection::Forward ? mVerbs : mVerbs - 1;
+ return mIndex > 0 ? *verbs : Verb::Done;
+ }
+
+ Verb next(Point points[4]) noexcept;
+
+private:
+ const Point* mPoints;
+ const Verb* mVerbs;
+ const float* mConicWeights;
+ int mIndex;
+ const int mCount;
+ const VerbDirection mDirection;
+ ConicConverter mConverter;
+};
+
+#endif //PATH_PATH_ITERATOR_H
diff --git a/graphics/graphics-path/src/main/cpp/math/TVecHelpers.h b/graphics/graphics-path/src/main/cpp/math/TVecHelpers.h
new file mode 100644
index 0000000..be00ebd
--- /dev/null
+++ b/graphics/graphics-path/src/main/cpp/math/TVecHelpers.h
@@ -0,0 +1,629 @@
+/*
+ * Copyright 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef TNT_MATH_TVECHELPERS_H
+#define TNT_MATH_TVECHELPERS_H
+
+#include "compiler.h"
+
+#include <cmath> // for std:: namespace
+
+#include <math.h>
+#include <stdint.h>
+#include <sys/types.h>
+
+namespace filament {
+namespace math {
+namespace details {
+// -------------------------------------------------------------------------------------
+
+template<typename U>
+inline constexpr U min(U a, U b) noexcept {
+ return a < b ? a : b;
+}
+
+template<typename U>
+inline constexpr U max(U a, U b) noexcept {
+ return a > b ? a : b;
+}
+
+template<typename T, typename U>
+struct arithmetic_result {
+ using type = decltype(std::declval<T>() + std::declval<U>());
+};
+
+template<typename T, typename U>
+using arithmetic_result_t = typename arithmetic_result<T, U>::type;
+
+template<typename A, typename B = int, typename C = int, typename D = int>
+using enable_if_arithmetic_t = std::enable_if_t<
+ is_arithmetic<A>::value &&
+ is_arithmetic<B>::value &&
+ is_arithmetic<C>::value &&
+ is_arithmetic<D>::value>;
+
+/*
+ * No user serviceable parts here.
+ *
+ * Don't use this file directly, instead include math/vec{2|3|4}.h
+ */
+
+/*
+ * TVec{Add|Product}Operators implements basic arithmetic and basic compound assignments
+ * operators on a vector of type BASE<T>.
+ *
+ * BASE only needs to implement operator[] and size().
+ * By simply inheriting from TVec{Add|Product}Operators<BASE, T> BASE will automatically
+ * get all the functionality here.
+ */
+
+template<template<typename T> class VECTOR, typename T>
+class TVecAddOperators {
+public:
+ /* compound assignment from a another vector of the same size but different
+ * element type.
+ */
+ template<typename U>
+ constexpr VECTOR<T>& operator+=(const VECTOR<U>& v) {
+ VECTOR<T>& lhs = static_cast<VECTOR<T>&>(*this);
+ for (size_t i = 0; i < lhs.size(); i++) {
+ lhs[i] += v[i];
+ }
+ return lhs;
+ }
+
+ template<typename U, typename = enable_if_arithmetic_t<U>>
+ constexpr VECTOR<T>& operator+=(U v) {
+ return operator+=(VECTOR<U>(v));
+ }
+
+ template<typename U>
+ constexpr VECTOR<T>& operator-=(const VECTOR<U>& v) {
+ VECTOR<T>& lhs = static_cast<VECTOR<T>&>(*this);
+ for (size_t i = 0; i < lhs.size(); i++) {
+ lhs[i] -= v[i];
+ }
+ return lhs;
+ }
+
+ template<typename U, typename = enable_if_arithmetic_t<U>>
+ constexpr VECTOR<T>& operator-=(U v) {
+ return operator-=(VECTOR<U>(v));
+ }
+
+private:
+ /*
+ * NOTE: the functions below ARE NOT member methods. They are friend functions
+ * with they definition inlined with their declaration. This makes these
+ * template functions available to the compiler when (and only when) this class
+ * is instantiated, at which point they're only templated on the 2nd parameter
+ * (the first one, BASE<T> being known).
+ */
+
+ template<typename U>
+ friend inline constexpr
+ VECTOR<arithmetic_result_t<T, U>> MATH_PURE operator+(const VECTOR<T>& lv, const VECTOR<U>& rv)
+ {
+ VECTOR<arithmetic_result_t<T, U>> res(lv);
+ res += rv;
+ return res;
+ }
+
+ template<typename U, typename = enable_if_arithmetic_t<U>>
+ friend inline constexpr
+ VECTOR<arithmetic_result_t<T, U>> MATH_PURE operator+(const VECTOR<T>& lv, U rv) {
+ return lv + VECTOR<U>(rv);
+ }
+
+ template<typename U, typename = enable_if_arithmetic_t<U>>
+ friend inline constexpr
+ VECTOR<arithmetic_result_t<T, U>> MATH_PURE operator+(U lv, const VECTOR<T>& rv) {
+ return VECTOR<U>(lv) + rv;
+ }
+
+ template<typename U>
+ friend inline constexpr
+ VECTOR<arithmetic_result_t<T, U>> MATH_PURE operator-(const VECTOR<T>& lv, const VECTOR<U>& rv)
+ {
+ VECTOR<arithmetic_result_t<T, U>> res(lv);
+ res -= rv;
+ return res;
+ }
+
+ template<typename U, typename = enable_if_arithmetic_t<U>>
+ friend inline constexpr
+ VECTOR<arithmetic_result_t<T, U>> MATH_PURE operator-(const VECTOR<T>& lv, U rv) {
+ return lv - VECTOR<U>(rv);
+ }
+
+ template<typename U, typename = enable_if_arithmetic_t<U>>
+ friend inline constexpr
+ VECTOR<arithmetic_result_t<T, U>> MATH_PURE operator-(U lv, const VECTOR<T>& rv) {
+ return VECTOR<U>(lv) - rv;
+ }
+};
+
+template<template<typename T> class VECTOR, typename T>
+class TVecProductOperators {
+public:
+ /* compound assignment from a another vector of the same size but different
+ * element type.
+ */
+ template<typename U>
+ constexpr VECTOR<T>& operator*=(const VECTOR<U>& v) {
+ VECTOR<T>& lhs = static_cast<VECTOR<T>&>(*this);
+ for (size_t i = 0; i < lhs.size(); i++) {
+ lhs[i] *= v[i];
+ }
+ return lhs;
+ }
+
+ template<typename U, typename = enable_if_arithmetic_t<U>>
+ constexpr VECTOR<T>& operator*=(U v) {
+ return operator*=(VECTOR<U>(v));
+ }
+
+ template<typename U>
+ constexpr VECTOR<T>& operator/=(const VECTOR<U>& v) {
+ VECTOR<T>& lhs = static_cast<VECTOR<T>&>(*this);
+ for (size_t i = 0; i < lhs.size(); i++) {
+ lhs[i] /= v[i];
+ }
+ return lhs;
+ }
+
+ template<typename U, typename = enable_if_arithmetic_t<U>>
+ constexpr VECTOR<T>& operator/=(U v) {
+ return operator/=(VECTOR<U>(v));
+ }
+
+private:
+ /*
+ * NOTE: the functions below ARE NOT member methods. They are friend functions
+ * with they definition inlined with their declaration. This makes these
+ * template functions available to the compiler when (and only when) this class
+ * is instantiated, at which point they're only templated on the 2nd parameter
+ * (the first one, BASE<T> being known).
+ */
+
+ template<typename U>
+ friend inline constexpr
+ VECTOR<arithmetic_result_t<T, U>> MATH_PURE operator*(const VECTOR<T>& lv, const VECTOR<U>& rv)
+ {
+ VECTOR<arithmetic_result_t<T, U>> res(lv);
+ res *= rv;
+ return res;
+ }
+
+ template<typename U, typename = enable_if_arithmetic_t<U>>
+ friend inline constexpr
+ VECTOR<arithmetic_result_t<T, U>> MATH_PURE operator*(const VECTOR<T>& lv, U rv) {
+ return lv * VECTOR<U>(rv);
+ }
+
+ template<typename U, typename = enable_if_arithmetic_t<U>>
+ friend inline constexpr
+ VECTOR<arithmetic_result_t<T, U>> MATH_PURE operator*(U lv, const VECTOR<T>& rv) {
+ return VECTOR<U>(lv) * rv;
+ }
+
+ template<typename U>
+ friend inline constexpr
+ VECTOR<arithmetic_result_t<T, U>> MATH_PURE operator/(const VECTOR<T>& lv, const VECTOR<U>& rv)
+ {
+ VECTOR<arithmetic_result_t<T, U>> res(lv);
+ res /= rv;
+ return res;
+ }
+
+ template<typename U, typename = enable_if_arithmetic_t<U>>
+ friend inline constexpr
+ VECTOR<arithmetic_result_t<T, U>> MATH_PURE operator/(const VECTOR<T>& lv, U rv) {
+ return lv / VECTOR<U>(rv);
+ }
+
+ template<typename U, typename = enable_if_arithmetic_t<U>>
+ friend inline constexpr
+ VECTOR<arithmetic_result_t<T, U>> MATH_PURE operator/(U lv, const VECTOR<T>& rv) {
+ return VECTOR<U>(lv) / rv;
+ }
+};
+
+/*
+ * TVecUnaryOperators implements unary operators on a vector of type BASE<T>.
+ *
+ * BASE only needs to implement operator[] and size().
+ * By simply inheriting from TVecUnaryOperators<BASE, T> BASE will automatically
+ * get all the functionality here.
+ *
+ * These operators are implemented as friend functions of TVecUnaryOperators<BASE, T>
+ */
+template<template<typename T> class VECTOR, typename T>
+class TVecUnaryOperators {
+public:
+ constexpr VECTOR<T> operator-() const {
+ VECTOR<T> r{};
+ VECTOR<T> const& rv(static_cast<VECTOR<T> const&>(*this));
+ for (size_t i = 0; i < r.size(); i++) {
+ r[i] = -rv[i];
+ }
+ return r;
+ }
+};
+
+/*
+ * TVecComparisonOperators implements relational/comparison operators
+ * on a vector of type BASE<T>.
+ *
+ * BASE only needs to implement operator[] and size().
+ * By simply inheriting from TVecComparisonOperators<BASE, T> BASE will automatically
+ * get all the functionality here.
+ */
+template<template<typename T> class VECTOR, typename T>
+class TVecComparisonOperators {
+private:
+ /*
+ * NOTE: the functions below ARE NOT member methods. They are friend functions
+ * with they definition inlined with their declaration. This makes these
+ * template functions available to the compiler when (and only when) this class
+ * is instantiated, at which point they're only templated on the 2nd parameter
+ * (the first one, BASE<T> being known).
+ */
+ template<typename U>
+ friend inline constexpr
+ bool MATH_PURE operator==(const VECTOR<T>& lv, const VECTOR<U>& rv) {
+ // w/ inlining we end-up with many branches that will pollute the BPU cache
+ MATH_NOUNROLL
+ for (size_t i = 0; i < lv.size(); i++) {
+ if (lv[i] != rv[i]) {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ template<typename U>
+ friend inline constexpr
+ bool MATH_PURE operator!=(const VECTOR<T>& lv, const VECTOR<U>& rv) {
+ return !operator==(lv, rv);
+ }
+
+ template<typename U>
+ friend inline constexpr
+ VECTOR<bool> MATH_PURE equal(const VECTOR<T>& lv, const VECTOR<U>& rv) {
+ VECTOR<bool> r{};
+ for (size_t i = 0; i < lv.size(); i++) {
+ r[i] = lv[i] == rv[i];
+ }
+ return r;
+ }
+
+ template<typename U>
+ friend inline constexpr
+ VECTOR<bool> MATH_PURE notEqual(const VECTOR<T>& lv, const VECTOR<U>& rv) {
+ VECTOR<bool> r{};
+ for (size_t i = 0; i < lv.size(); i++) {
+ r[i] = lv[i] != rv[i];
+ }
+ return r;
+ }
+
+ template<typename U>
+ friend inline constexpr
+ VECTOR<bool> MATH_PURE lessThan(const VECTOR<T>& lv, const VECTOR<U>& rv) {
+ VECTOR<bool> r{};
+ for (size_t i = 0; i < lv.size(); i++) {
+ r[i] = lv[i] < rv[i];
+ }
+ return r;
+ }
+
+ template<typename U>
+ friend inline constexpr
+ VECTOR<bool> MATH_PURE lessThanEqual(const VECTOR<T>& lv, const VECTOR<U>& rv) {
+ VECTOR<bool> r{};
+ for (size_t i = 0; i < lv.size(); i++) {
+ r[i] = lv[i] <= rv[i];
+ }
+ return r;
+ }
+
+ template<typename U>
+ friend inline constexpr
+ VECTOR<bool> MATH_PURE greaterThan(const VECTOR<T>& lv, const VECTOR<U>& rv) {
+ VECTOR<bool> r;
+ for (size_t i = 0; i < lv.size(); i++) {
+ r[i] = lv[i] > rv[i];
+ }
+ return r;
+ }
+
+ template<typename U>
+ friend inline
+ VECTOR<bool> MATH_PURE greaterThanEqual(const VECTOR<T>& lv, const VECTOR<U>& rv) {
+ VECTOR<bool> r{};
+ for (size_t i = 0; i < lv.size(); i++) {
+ r[i] = lv[i] >= rv[i];
+ }
+ return r;
+ }
+};
+
+/*
+ * TVecFunctions implements functions on a vector of type BASE<T>.
+ *
+ * BASE only needs to implement operator[] and size().
+ * By simply inheriting from TVecFunctions<BASE, T> BASE will automatically
+ * get all the functionality here.
+ */
+template<template<typename T> class VECTOR, typename T>
+class TVecFunctions {
+private:
+ /*
+ * NOTE: the functions below ARE NOT member methods. They are friend functions
+ * with they definition inlined with their declaration. This makes these
+ * template functions available to the compiler when (and only when) this class
+ * is instantiated, at which point they're only templated on the 2nd parameter
+ * (the first one, BASE<T> being known).
+ */
+ template<typename U>
+ friend constexpr inline
+ arithmetic_result_t<T, U> MATH_PURE dot(const VECTOR<T>& lv, const VECTOR<U>& rv) {
+ arithmetic_result_t<T, U> r{};
+ for (size_t i = 0; i < lv.size(); i++) {
+ r += lv[i] * rv[i];
+ }
+ return r;
+ }
+
+ friend inline T MATH_PURE norm(const VECTOR<T>& lv) {
+ return std::sqrt(dot(lv, lv));
+ }
+
+ friend inline T MATH_PURE length(const VECTOR<T>& lv) {
+ return norm(lv);
+ }
+
+ friend inline constexpr T MATH_PURE norm2(const VECTOR<T>& lv) {
+ return dot(lv, lv);
+ }
+
+ friend inline constexpr T MATH_PURE length2(const VECTOR<T>& lv) {
+ return norm2(lv);
+ }
+
+ template<typename U>
+ friend inline constexpr
+ arithmetic_result_t<T, U> MATH_PURE distance(const VECTOR<T>& lv, const VECTOR<U>& rv) {
+ return length(rv - lv);
+ }
+
+ template<typename U>
+ friend inline constexpr
+ arithmetic_result_t<T, U> MATH_PURE distance2(const VECTOR<T>& lv, const VECTOR<U>& rv) {
+ return length2(rv - lv);
+ }
+
+ friend inline VECTOR<T> MATH_PURE normalize(const VECTOR<T>& lv) {
+ return lv * (T(1) / length(lv));
+ }
+
+ friend inline VECTOR<T> MATH_PURE rcp(VECTOR<T> v) {
+ return T(1) / v;
+ }
+
+ friend inline constexpr VECTOR<T> MATH_PURE abs(VECTOR<T> v) {
+ for (size_t i = 0; i < v.size(); i++) {
+ v[i] = v[i] < 0 ? -v[i] : v[i];
+ }
+ return v;
+ }
+
+ friend inline VECTOR<T> MATH_PURE floor(VECTOR<T> v) {
+ for (size_t i = 0; i < v.size(); i++) {
+ v[i] = std::floor(v[i]);
+ }
+ return v;
+ }
+
+ friend inline VECTOR<T> MATH_PURE ceil(VECTOR<T> v) {
+ for (size_t i = 0; i < v.size(); i++) {
+ v[i] = std::ceil(v[i]);
+ }
+ return v;
+ }
+
+ friend inline VECTOR<T> MATH_PURE round(VECTOR<T> v) {
+ for (size_t i = 0; i < v.size(); i++) {
+ v[i] = std::round(v[i]);
+ }
+ return v;
+ }
+
+ friend inline VECTOR<T> MATH_PURE inversesqrt(VECTOR<T> v) {
+ for (size_t i = 0; i < v.size(); i++) {
+ v[i] = T(1) / std::sqrt(v[i]);
+ }
+ return v;
+ }
+
+ friend inline VECTOR<T> MATH_PURE sqrt(VECTOR<T> v) {
+ for (size_t i = 0; i < v.size(); i++) {
+ v[i] = std::sqrt(v[i]);
+ }
+ return v;
+ }
+
+ friend inline VECTOR<T> MATH_PURE cbrt(VECTOR<T> v) {
+ for (size_t i = 0; i < v.size(); i++) {
+ v[i] = std::cbrt(v[i]);
+ }
+ return v;
+ }
+
+ friend inline VECTOR<T> MATH_PURE exp(VECTOR<T> v) {
+ for (size_t i = 0; i < v.size(); i++) {
+ v[i] = std::exp(v[i]);
+ }
+ return v;
+ }
+
+ friend inline VECTOR<T> MATH_PURE pow(VECTOR<T> v, T p) {
+ for (size_t i = 0; i < v.size(); i++) {
+ v[i] = std::pow(v[i], p);
+ }
+ return v;
+ }
+
+ friend inline VECTOR<T> MATH_PURE pow(T v, VECTOR<T> p) {
+ for (size_t i = 0; i < p.size(); i++) {
+ p[i] = std::pow(v, p[i]);
+ }
+ return p;
+ }
+
+ friend inline VECTOR<T> MATH_PURE pow(VECTOR<T> v, VECTOR<T> p) {
+ for (size_t i = 0; i < v.size(); i++) {
+ v[i] = std::pow(v[i], p[i]);
+ }
+ return v;
+ }
+
+ friend inline VECTOR<T> MATH_PURE log(VECTOR<T> v) {
+ for (size_t i = 0; i < v.size(); i++) {
+ v[i] = std::log(v[i]);
+ }
+ return v;
+ }
+
+ friend inline VECTOR<T> MATH_PURE log10(VECTOR<T> v) {
+ for (size_t i = 0; i < v.size(); i++) {
+ v[i] = std::log10(v[i]);
+ }
+ return v;
+ }
+
+ friend inline VECTOR<T> MATH_PURE log2(VECTOR<T> v) {
+ for (size_t i = 0; i < v.size(); i++) {
+ v[i] = std::log2(v[i]);
+ }
+ return v;
+ }
+
+ friend inline constexpr VECTOR<T> MATH_PURE saturate(const VECTOR<T>& lv) {
+ return clamp(lv, T(0), T(1));
+ }
+
+ friend inline constexpr VECTOR<T> MATH_PURE clamp(VECTOR<T> v, T min, T max) {
+ for (size_t i = 0; i < v.size(); i++) {
+ v[i] = details::min(max, details::max(min, v[i]));
+ }
+ return v;
+ }
+
+ friend inline constexpr VECTOR<T> MATH_PURE clamp(VECTOR<T> v, VECTOR<T> min, VECTOR<T> max) {
+ for (size_t i = 0; i < v.size(); i++) {
+ v[i] = details::min(max[i], details::max(min[i], v[i]));
+ }
+ return v;
+ }
+
+ friend inline constexpr VECTOR<T> MATH_PURE fma(const VECTOR<T>& lv, const VECTOR<T>& rv,
+ VECTOR<T> a) {
+ for (size_t i = 0; i < lv.size(); i++) {
+ a[i] += (lv[i] * rv[i]);
+ }
+ return a;
+ }
+
+ friend inline constexpr VECTOR<T> MATH_PURE min(const VECTOR<T>& u, VECTOR<T> v) {
+ for (size_t i = 0; i < v.size(); i++) {
+ v[i] = details::min(u[i], v[i]);
+ }
+ return v;
+ }
+
+ friend inline constexpr VECTOR<T> MATH_PURE max(const VECTOR<T>& u, VECTOR<T> v) {
+ for (size_t i = 0; i < v.size(); i++) {
+ v[i] = details::max(u[i], v[i]);
+ }
+ return v;
+ }
+
+ friend inline constexpr T MATH_PURE max(const VECTOR<T>& v) {
+ T r(v[0]);
+ for (size_t i = 1; i < v.size(); i++) {
+ r = max(r, v[i]);
+ }
+ return r;
+ }
+
+ friend inline constexpr T MATH_PURE min(const VECTOR<T>& v) {
+ T r(v[0]);
+ for (size_t i = 1; i < v.size(); i++) {
+ r = min(r, v[i]);
+ }
+ return r;
+ }
+
+ friend inline constexpr VECTOR<T> MATH_PURE mix(const VECTOR<T>& u, VECTOR<T> v, T a) {
+ for (size_t i = 0; i < v.size(); i++) {
+ v[i] = u[i] * (T(1) - a) + v[i] * a;
+ }
+ return v;
+ }
+
+ friend inline constexpr VECTOR<T> MATH_PURE smoothstep(T edge0, T edge1, VECTOR<T> v) {
+ VECTOR<T> t = saturate((v - edge0) / (edge1 - edge0));
+ return t * t * (T(3) - T(2) * t);
+ }
+
+ friend inline constexpr VECTOR<T> MATH_PURE step(T edge, VECTOR<T> v) {
+ for (size_t i = 0; i < v.size(); i++) {
+ v[i] = v[i] < edge ? T(0) : T(1);
+ }
+ return v;
+ }
+
+ friend inline constexpr VECTOR<T> MATH_PURE step(VECTOR<T> edge, VECTOR<T> v) {
+ for (size_t i = 0; i < v.size(); i++) {
+ v[i] = v[i] < edge[i] ? T(0) : T(1);
+ }
+ return v;
+ }
+
+ friend inline constexpr bool MATH_PURE any(const VECTOR<T>& v) {
+ for (size_t i = 0; i < v.size(); i++) {
+ if (v[i] != T(0)) return true;
+ }
+ return false;
+ }
+
+ friend inline constexpr bool MATH_PURE all(const VECTOR<T>& v) {
+ bool result = true;
+ for (size_t i = 0; i < v.size(); i++) {
+ result &= (v[i] != T(0));
+ }
+ return result;
+ }
+};
+
+// -------------------------------------------------------------------------------------
+} // namespace details
+} // namespace math
+} // namespace filament
+
+#endif // TNT_MATH_TVECHELPERS_H
diff --git a/graphics/graphics-path/src/main/cpp/math/compiler.h b/graphics/graphics-path/src/main/cpp/math/compiler.h
new file mode 100644
index 0000000..d6e18aa
--- /dev/null
+++ b/graphics/graphics-path/src/main/cpp/math/compiler.h
@@ -0,0 +1,128 @@
+/*
+ * 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.
+ */
+
+#ifndef PATH_MATH_COMPILER_H
+#define PATH_MATH_COMPILER_H
+
+#include <type_traits>
+
+#if defined (WIN32)
+
+#ifdef max
+#undef max
+#endif
+
+#ifdef min
+#undef min
+#endif
+
+#ifdef far
+#undef far
+#endif
+
+#ifdef near
+#undef near
+#endif
+
+#endif
+
+// compatibility with non-clang compilers...
+#ifndef __has_attribute
+#define __has_attribute(x) 0
+#endif
+#ifndef __has_builtin
+#define __has_builtin(x) 0
+#endif
+
+#if __has_builtin(__builtin_expect)
+# ifdef __cplusplus
+# define MATH_LIKELY( exp ) (__builtin_expect( !!(exp), true ))
+# define MATH_UNLIKELY( exp ) (__builtin_expect( !!(exp), false ))
+# else
+# define MATH_LIKELY( exp ) (__builtin_expect( !!(exp), 1 ))
+# define MATH_UNLIKELY( exp ) (__builtin_expect( !!(exp), 0 ))
+# endif
+#else
+# define MATH_LIKELY( exp ) (exp)
+# define MATH_UNLIKELY( exp ) (exp)
+#endif
+
+#if __has_attribute(unused)
+# define MATH_UNUSED __attribute__((unused))
+#else
+# define MATH_UNUSED
+#endif
+
+#if __has_attribute(pure)
+# define MATH_PURE __attribute__((pure))
+#else
+# define MATH_PURE
+#endif
+
+#ifdef _MSC_VER
+# define MATH_EMPTY_BASES __declspec(empty_bases)
+
+// MSVC does not support loop unrolling hints
+# define MATH_NOUNROLL
+
+// Sadly, MSVC does not support __builtin_constant_p
+# ifndef MAKE_CONSTEXPR
+# define MAKE_CONSTEXPR(e) (e)
+# endif
+
+// About value initialization, the C++ standard says:
+// if T is a class type with a default constructor that is neither user-provided nor deleted
+// (that is, it may be a class with an implicitly-defined or defaulted default constructor),
+// the object is zero-initialized and then it is default-initialized
+// if it has a non-trivial default constructor;
+// Unfortunately, MSVC always calls the default constructor, even if it is trivial, which
+// breaks constexpr-ness. To workaround this, we're always zero-initializing TVecN<>
+# define MATH_CONSTEXPR_INIT {}
+# define MATH_DEFAULT_CTOR {}
+# define MATH_DEFAULT_CTOR_CONSTEXPR constexpr
+# define CONSTEXPR_IF_NOT_MSVC // when declared constexpr, msvc fails with
+ // "failure was caused by cast of object of dynamic type"
+
+#else // _MSC_VER
+
+# define MATH_EMPTY_BASES
+// C++11 allows pragmas to be specified as part of defines using the _Pragma syntax.
+# define MATH_NOUNROLL _Pragma("nounroll")
+
+# ifndef MAKE_CONSTEXPR
+# define MAKE_CONSTEXPR(e) __builtin_constant_p(e) ? (e) : (e)
+# endif
+
+# define MATH_CONSTEXPR_INIT
+# define MATH_DEFAULT_CTOR = default;
+# define MATH_DEFAULT_CTOR_CONSTEXPR
+# define CONSTEXPR_IF_NOT_MSVC constexpr
+
+#endif // _MSC_VER
+
+namespace filament::math {
+
+// MSVC 2019 16.4 doesn't seem to like it when we specialize std::is_arithmetic for
+// filament::math::half, so we're forced to create our own is_arithmetic here and specialize it
+// inside of half.h.
+template<typename T>
+struct is_arithmetic : std::integral_constant<bool,
+ std::is_integral<T>::value || std::is_floating_point<T>::value> {
+};
+
+} // filament::math
+
+#endif // PATH_MATH_COMPILER_H
diff --git a/graphics/graphics-path/src/main/cpp/math/vec2.h b/graphics/graphics-path/src/main/cpp/math/vec2.h
new file mode 100644
index 0000000..3228b09
--- /dev/null
+++ b/graphics/graphics-path/src/main/cpp/math/vec2.h
@@ -0,0 +1,112 @@
+/*
+ * Copyright 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef TNT_MATH_VEC2_H
+#define TNT_MATH_VEC2_H
+
+#include "TVecHelpers.h"
+
+#include <type_traits>
+
+#include <assert.h>
+#include <stdint.h>
+#include <sys/types.h>
+
+namespace filament {
+namespace math {
+// -------------------------------------------------------------------------------------
+
+namespace details {
+
+template<typename T>
+class MATH_EMPTY_BASES TVec2 :
+ public TVecProductOperators<TVec2, T>,
+ public TVecAddOperators<TVec2, T>,
+ public TVecUnaryOperators<TVec2, T>,
+ public TVecComparisonOperators<TVec2, T>,
+ public TVecFunctions<TVec2, T> {
+public:
+ typedef T value_type;
+ typedef T& reference;
+ typedef T const& const_reference;
+ typedef size_t size_type;
+ static constexpr size_t SIZE = 2;
+
+ union {
+ T v[SIZE] MATH_CONSTEXPR_INIT;
+ struct { T x, y; };
+ struct { T s, t; };
+ struct { T r, g; };
+ };
+
+ inline constexpr size_type size() const { return SIZE; }
+
+ // array access
+ inline constexpr T const& operator[](size_t i) const noexcept {
+ assert(i < SIZE);
+ return v[i];
+ }
+
+ inline constexpr T& operator[](size_t i) noexcept {
+ assert(i < SIZE);
+ return v[i];
+ }
+
+ // constructors
+
+ // default constructor
+ MATH_DEFAULT_CTOR_CONSTEXPR TVec2() MATH_DEFAULT_CTOR
+
+ // handles implicit conversion to a tvec4. must not be explicit.
+ template<typename A, typename = enable_if_arithmetic_t<A>>
+ constexpr TVec2(A v) noexcept : v{ T(v), T(v) } {}
+
+ template<typename A, typename B, typename = enable_if_arithmetic_t<A, B>>
+ constexpr TVec2(A x, B y) noexcept : v{ T(x), T(y) } {}
+
+ template<typename A, typename = enable_if_arithmetic_t<A>>
+ constexpr TVec2(const TVec2<A>& v) noexcept : v{ T(v[0]), T(v[1]) } {}
+
+ // cross product works only on vectors of size 2 or 3
+ template<typename U>
+ friend inline constexpr
+ arithmetic_result_t<T, U> cross(const TVec2& u, const TVec2<U>& v) noexcept {
+ return u[0] * v[1] - u[1] * v[0];
+ }
+};
+
+} // namespace details
+
+// ----------------------------------------------------------------------------------------
+
+template<typename T, typename = details::enable_if_arithmetic_t<T>>
+using vec2 = details::TVec2<T>;
+
+using double2 = vec2<double>;
+using float2 = vec2<float>;
+using int2 = vec2<int32_t>;
+using uint2 = vec2<uint32_t>;
+using short2 = vec2<int16_t>;
+using ushort2 = vec2<uint16_t>;
+using byte2 = vec2<int8_t>;
+using ubyte2 = vec2<uint8_t>;
+using bool2 = vec2<bool>;
+
+// ----------------------------------------------------------------------------------------
+} // namespace math
+} // namespace filament
+
+#endif // TNT_MATH_VEC2_H
diff --git a/graphics/graphics-path/src/main/cpp/pathway.cpp b/graphics/graphics-path/src/main/cpp/pathway.cpp
new file mode 100644
index 0000000..9997387
--- /dev/null
+++ b/graphics/graphics-path/src/main/cpp/pathway.cpp
@@ -0,0 +1,229 @@
+/*
+ * Copyright 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "PathIterator.h"
+
+#include <jni.h>
+
+#include <sys/system_properties.h>
+
+#include <mutex>
+
+#define JNI_CLASS_NAME "androidx/graphics/path/PathIteratorPreApi34Impl"
+#define JNI_CLASS_NAME_CONVERTER "androidx/graphics/path/ConicConverter"
+
+#if !defined(NDEBUG)
+#include <android/log.h>
+#define ANDROID_LOG_TAG "PathIterator"
+#define LOGD(...) __android_log_print(ANDROID_LOG_DEBUG, ANDROID_LOG_TAG, __VA_ARGS__)
+#endif
+
+struct {
+ jclass jniClass;
+ jfieldID nativePath;
+} sPath{};
+
+uint32_t sApiLevel = 0;
+std::once_flag sApiLevelOnceFlag;
+
+static uint32_t api_level() {
+ std::call_once(sApiLevelOnceFlag, []() {
+ char sdkVersion[PROP_VALUE_MAX];
+ __system_property_get("ro.build.version.sdk", sdkVersion);
+ sApiLevel = atoi(sdkVersion); // NOLINT(cert-err34-c)
+ });
+ return sApiLevel;
+}
+
+static jlong createPathIterator(JNIEnv* env, jobject,
+ jobject path_, jint conicEvaluation_, jfloat tolerance_) {
+
+ auto nativePath = static_cast<intptr_t>(env->GetLongField(path_, sPath.nativePath));
+ auto* path = reinterpret_cast<Path*>(nativePath);
+
+ Point* points;
+ Verb* verbs;
+ float* conicWeights;
+ int count;
+ PathIterator::VerbDirection direction;
+
+ const uint32_t apiLevel = api_level();
+ if (apiLevel >= 30) {
+ auto* ref = reinterpret_cast<PathRef30*>(path->pathRef);
+ points = ref->points;
+ verbs = ref->verbs;
+ conicWeights = ref->conicWeights;
+ count = ref->verbCount;
+ direction = PathIterator::VerbDirection::Forward;
+ } else if (apiLevel >= 26) {
+ auto* ref = reinterpret_cast<PathRef26*>(path->pathRef);
+ points = ref->points;
+ verbs = ref->verbs;
+ conicWeights = ref->conicWeights;
+ count = ref->verbCount;
+ direction = PathIterator::VerbDirection::Backward;
+ } else if (apiLevel >= 24) {
+ auto* ref = reinterpret_cast<PathRef24*>(path->pathRef);
+ points = ref->points;
+ verbs = ref->verbs;
+ conicWeights = ref->conicWeights;
+ count = ref->verbCount;
+ direction = PathIterator::VerbDirection::Backward;
+ } else {
+ auto* ref = path->pathRef;
+ points = ref->points;
+ verbs = ref->verbs;
+ conicWeights = ref->conicWeights;
+ count = ref->verbCount;
+ direction = PathIterator::VerbDirection::Backward;
+ }
+
+ return jlong(new PathIterator(points, verbs, conicWeights, count, direction));
+}
+
+static void destroyPathIterator(JNIEnv*, jobject, jlong pathIterator_) {
+ delete reinterpret_cast<PathIterator*>(pathIterator_);
+}
+
+static jboolean pathIteratorHasNext(JNIEnv*, jobject, jlong pathIterator_) {
+ return reinterpret_cast<PathIterator*>(pathIterator_)->hasNext();
+}
+
+static jint conicToQuadraticsWrapper(JNIEnv* env, jobject,
+ jfloatArray conicPoints, jfloatArray quadraticPoints,
+ jfloat weight, jfloat tolerance, jint offset) {
+ float *conicData1 = env->GetFloatArrayElements(conicPoints, JNI_FALSE);
+ float *quadData1 = env->GetFloatArrayElements(quadraticPoints, JNI_FALSE);
+ int quadDataSize = env->GetArrayLength(quadraticPoints);
+
+ int count = conicToQuadratics(reinterpret_cast<Point *>(conicData1 + offset),
+ reinterpret_cast<Point *>(quadData1),
+ env->GetArrayLength(quadraticPoints),
+ weight, tolerance);
+
+ env->ReleaseFloatArrayElements(conicPoints, conicData1, 0);
+ env->ReleaseFloatArrayElements(quadraticPoints, quadData1, 0);
+
+ return count;
+}
+
+static jint pathIteratorNext(JNIEnv* env, jobject,
+ jlong pathIterator_, jfloatArray points_, jint offset_) {
+ auto pathIterator = reinterpret_cast<PathIterator*>(pathIterator_);
+ Point pointsData[4];
+ Verb verb = pathIterator->next(pointsData);
+
+ if (verb != Verb::Done && verb != Verb::Close) {
+ auto* floatsData = reinterpret_cast<jfloat*>(pointsData);
+ env->SetFloatArrayRegion(points_, offset_, 8, floatsData);
+ }
+
+ return static_cast<jint>(verb);
+}
+
+static jint pathIteratorPeek(JNIEnv*, jobject, jlong pathIterator_) {
+ return static_cast<jint>(reinterpret_cast<PathIterator *>(pathIterator_)->peek());
+}
+
+static jint pathIteratorRawSize(JNIEnv*, jobject, jlong pathIterator_) {
+ return static_cast<jint>(reinterpret_cast<PathIterator *>(pathIterator_)->rawCount());
+}
+
+static jint pathIteratorSize(JNIEnv*, jobject, jlong pathIterator_) {
+ return static_cast<jint>(reinterpret_cast<PathIterator *>(pathIterator_)->count());
+}
+
+JNIEXPORT jint JNI_OnLoad(JavaVM* vm, void*) {
+ JNIEnv* env;
+ if (vm->GetEnv(reinterpret_cast<void**>(&env), JNI_VERSION_1_6) != JNI_OK) {
+ return -1;
+ }
+
+ sPath.jniClass = env->FindClass("android/graphics/Path");
+ if (sPath.jniClass == nullptr) return JNI_ERR;
+
+ sPath.nativePath = env->GetFieldID(sPath.jniClass, "mNativePath", "J");
+ if (sPath.nativePath == nullptr) return JNI_ERR;
+
+ {
+ jclass pathsClass = env->FindClass(JNI_CLASS_NAME);
+ if (pathsClass == nullptr) return JNI_ERR;
+
+ static const JNINativeMethod methods[] = {
+ {
+ (char*) "createInternalPathIterator",
+ (char*) "(Landroid/graphics/Path;IF)J",
+ reinterpret_cast<void*>(createPathIterator)
+ },
+ {
+ (char*) "destroyInternalPathIterator",
+ (char*) "(J)V",
+ reinterpret_cast<void*>(destroyPathIterator)
+ },
+ {
+ (char*) "internalPathIteratorHasNext",
+ (char*) "(J)Z",
+ reinterpret_cast<void*>(pathIteratorHasNext)
+ },
+ {
+ (char*) "internalPathIteratorNext",
+ (char*) "(J[FI)I",
+ reinterpret_cast<void*>(pathIteratorNext)
+ },
+ {
+ (char*) "internalPathIteratorPeek",
+ (char*) "(J)I",
+ reinterpret_cast<void*>(pathIteratorPeek)
+ },
+ {
+ (char*) "internalPathIteratorRawSize",
+ (char*) "(J)I",
+ reinterpret_cast<void*>(pathIteratorRawSize)
+ },
+ {
+ (char*) "internalPathIteratorSize",
+ (char*) "(J)I",
+ reinterpret_cast<void*>(pathIteratorSize)
+ },
+ };
+
+ int result = env->RegisterNatives(
+ pathsClass, methods, sizeof(methods) / sizeof(JNINativeMethod)
+ );
+ if (result != JNI_OK) return result;
+
+ env->DeleteLocalRef(pathsClass);
+
+ jclass converterClass = env->FindClass(JNI_CLASS_NAME_CONVERTER);
+ if (converterClass == nullptr) return JNI_ERR;
+ static const JNINativeMethod methods2[] = {
+ {
+ (char *) "internalConicToQuadratics",
+ (char *) "([F[FFFI)I",
+ reinterpret_cast<void *>(conicToQuadraticsWrapper)
+ },
+ };
+
+ result = env->RegisterNatives(
+ converterClass, methods2, sizeof(methods2) / sizeof(JNINativeMethod)
+ );
+ if (result != JNI_OK) return result;
+
+ env->DeleteLocalRef(converterClass);
+ }
+
+ return JNI_VERSION_1_6;
+}
diff --git a/graphics/graphics-path/src/main/cpp/scalar.h b/graphics/graphics-path/src/main/cpp/scalar.h
new file mode 100644
index 0000000..0342d13
--- /dev/null
+++ b/graphics/graphics-path/src/main/cpp/scalar.h
@@ -0,0 +1,71 @@
+/*
+ * Copyright 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef PATH_SCALAR_H
+#define PATH_SCALAR_H
+
+union floatIntUnion {
+ float value;
+ int32_t signBitInt;
+};
+
+static inline int32_t float2Bits(float x) noexcept {
+ floatIntUnion data; // NOLINT(cppcoreguidelines-pro-type-member-init)
+ data.value = x;
+ return data.signBitInt;
+}
+
+constexpr bool isFloatFinite(int32_t bits) noexcept {
+ constexpr int32_t kFloatBitsExponentMask = 0x7F800000;
+ return (bits & kFloatBitsExponentMask) != kFloatBitsExponentMask;
+}
+
+static inline bool isFinite(float v) noexcept {
+ return isFloatFinite(float2Bits(v));
+}
+
+#pragma clang diagnostic push
+#pragma ide diagnostic ignored "cppcoreguidelines-narrowing-conversions"
+static bool canNormalize(float dx, float dy) noexcept {
+ return (isFinite(dx) && isFinite(dy)) && (dx || dy);
+}
+#pragma clang diagnostic pop
+
+static bool equals(const Point& p1, const Point& p2) noexcept {
+ return !canNormalize(p1.x - p2.x, p1.y - p2.y);
+}
+
+constexpr bool isFinite(const float array[], int count) noexcept {
+ float prod = 0.0f;
+ for (int i = 0; i < count; i++) {
+ prod *= array[i];
+ }
+ return prod == 0.0f;
+}
+
+template<typename T>
+constexpr T tabs(T value) noexcept {
+ if (value < 0) {
+ value = -value;
+ }
+ return value;
+}
+
+constexpr bool between(float a, float b, float c) noexcept {
+ return (a - b) * (c - b) <= 0.0f;
+}
+
+#endif //PATH_SCALAR_H
diff --git a/graphics/graphics-path/src/main/java/androidx/graphics/path/ConicConverter.kt b/graphics/graphics-path/src/main/java/androidx/graphics/path/ConicConverter.kt
new file mode 100644
index 0000000..445bd47
--- /dev/null
+++ b/graphics/graphics-path/src/main/java/androidx/graphics/path/ConicConverter.kt
@@ -0,0 +1,102 @@
+/*
+ * Copyright 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.graphics.path
+
+import android.util.Log
+
+/**
+ * This class converts a given Conic object to the equivalent set of Quadratic objects.
+ * It stores all quadratics from a conversion in the call to [convert], but returns only
+ * one at a time, from nextQuadratic(), storing the rest for later retrieval (since a
+ * PathIterator only retrieves one object at a time).
+ *
+ * This object is stateful, using quadraticCount, currentQuadratic, and quadraticData
+ * to send back the next quadratic when requested, in [nextQuadratic].
+ */
+internal class ConicConverter() {
+
+ private val LOG_TAG = "ConicConverter"
+ private val DEBUG = false
+
+ /**
+ * The total number of quadratics currently stored in the converter
+ */
+ var quadraticCount: Int = 0
+ private set
+
+ /**
+ * The index of the current Quadratic; this is the next quadratic to be returned
+ * in the call to nextQuadratic().
+ */
+ var currentQuadratic = 0
+
+ /**
+ * Storage for all quadratics for a particular conic. Set to reasonable
+ * default size, will need to resize if we ever get a return count larger
+ * than the current size.
+ * Initial size holds up to 5 quadratics: 2 floats/point, 3 points/quadratic
+ * where all quadratics overlap in one point except the ends.
+ */
+ private var quadraticData = FloatArray(1)
+
+ /**
+ * This function stores the next converted quadratic in the given points array,
+ * returning true if this happened, false if there was no quadratic to be returned.
+ */
+ fun nextQuadratic(points: FloatArray, offset: Int = 0): Boolean {
+ if (currentQuadratic < quadraticCount) {
+ val index = currentQuadratic * 2 * 2
+ points[0 + offset] = quadraticData[index]
+ points[1 + offset] = quadraticData[index + 1]
+ points[2 + offset] = quadraticData[index + 2]
+ points[3 + offset] = quadraticData[index + 3]
+ points[4 + offset] = quadraticData[index + 4]
+ points[5 + offset] = quadraticData[index + 5]
+ currentQuadratic++
+ return true
+ }
+ return false
+ }
+
+ /**
+ * Converts the conic in [points] to a series of quadratics, which will all be stored
+ */
+ fun convert(points: FloatArray, weight: Float, tolerance: Float, offset: Int = 0) {
+ quadraticCount = internalConicToQuadratics(points, quadraticData, weight, tolerance, offset)
+ if (quadraticCount > quadraticData.size) {
+ if (DEBUG) Log.d(LOG_TAG, "Resizing quadraticData buffer to $quadraticCount")
+ quadraticData = FloatArray(quadraticCount * 4 * 2)
+ quadraticCount = internalConicToQuadratics(points, quadraticData, weight, tolerance,
+ offset)
+ }
+ currentQuadratic = 0
+ if (DEBUG) Log.d("ConicConverter", "internalConicToQuadratics returned " + quadraticCount)
+ }
+
+ /**
+ * The actual conversion from conic to quadratic data happens in native code, in the library
+ * loaded elsewhere. This JNI function wraps that native functionality.
+ */
+ @Suppress("KotlinJniMissingFunction")
+ private external fun internalConicToQuadratics(
+ conicPoints: FloatArray,
+ quadraticPoints: FloatArray,
+ weight: Float,
+ tolerance: Float,
+ offset: Int
+ ): Int
+}
\ No newline at end of file
diff --git a/graphics/graphics-path/src/main/java/androidx/graphics/path/PathIterator.kt b/graphics/graphics-path/src/main/java/androidx/graphics/path/PathIterator.kt
new file mode 100644
index 0000000..6567419
--- /dev/null
+++ b/graphics/graphics-path/src/main/java/androidx/graphics/path/PathIterator.kt
@@ -0,0 +1,146 @@
+/*
+ * Copyright 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+@file:JvmName("PathUtilities")
+package androidx.graphics.path
+
+import android.graphics.Path
+import androidx.core.os.BuildCompat
+import androidx.core.os.BuildCompat.PrereleaseSdkCheck
+
+/**
+ * A path iterator can be used to iterate over all the [segments][PathSegment] that make up
+ * a path. Those segments may in turn define multiple contours inside the path. Conic segments
+ * are by default evaluated as approximated quadratic segments. To preserve conic segments as
+ * conics, set [conicEvaluation] to [AsConic][ConicEvaluation.AsConic]. The error of the
+ * approximation is controlled by [tolerance].
+ *
+ * [PathIterator] objects are created implicitly through a given [Path] object; to create a
+ * [PathIterator], call one of the two [Path.iterator] extension functions.
+ */
+@Suppress("NotCloseable", "IllegalExperimentalApiUsage")
+@PrereleaseSdkCheck
+class PathIterator constructor(
+ val path: Path,
+ val conicEvaluation: ConicEvaluation = ConicEvaluation.AsQuadratics,
+ val tolerance: Float = 0.25f
+) : Iterator<PathSegment> {
+
+ internal val implementation: PathIteratorImpl
+ init {
+ implementation =
+ when {
+ // TODO: replace isAtLeastU() check with below or similar when U is released
+ // Build.VERSION.SDK_INT >= 34 -> {
+ BuildCompat.isAtLeastU() -> {
+ PathIteratorApi34Impl(path, conicEvaluation, tolerance)
+ }
+ else -> {
+ PathIteratorPreApi34Impl(path, conicEvaluation, tolerance)
+ }
+ }
+ }
+
+ enum class ConicEvaluation {
+ /**
+ * Conic segments are returned as conic segments.
+ */
+ AsConic,
+
+ /**
+ * Conic segments are returned as quadratic approximations. The quality of the
+ * approximation is defined by a tolerance value.
+ */
+ AsQuadratics
+ }
+
+ /**
+ * Returns the number of verbs present in this iterator, i.e. the number of calls to
+ * [next] required to complete the iteration.
+ *
+ * By default, [calculateSize] returns the true number of operations in the iterator. Deriving
+ * this result requires converting any conics to quadratics, if [conicEvaluation] is
+ * set to [ConicEvaluation.AsQuadratics], which takes extra processing time. Set
+ * [includeConvertedConics] to false if an approximate size, not including conic
+ * conversion, is sufficient.
+ *
+ * @param includeConvertedConics The returned size includes any required conic conversions.
+ * Default is true, so it will return the exact size, at the cost of iterating through
+ * all elements and converting any conics as appropriate. Set to false to save on processing,
+ * at the cost of a less exact result.
+ */
+ fun calculateSize(includeConvertedConics: Boolean = true) =
+ implementation.calculateSize(includeConvertedConics)
+
+ /**
+ * Returns `true` if the iteration has more elements.
+ */
+ override fun hasNext(): Boolean = implementation.hasNext()
+
+ /**
+ * Returns the type of the current segment in the iteration, or [Done][PathSegment.Type.Done]
+ * if the iteration is finished.
+ */
+ fun peek() = implementation.peek()
+
+ /**
+ * Returns the [type][PathSegment.Type] of the next [path segment][PathSegment] in the iteration
+ * and fills [points] with the points specific to the segment type. Each pair of floats in
+ * the [points] array represents a point for the given segment. The number of pairs of floats
+ * depends on the [PathSegment.Type]:
+ * - [Move][PathSegment.Type.Move]: 1 pair (indices 0 to 1)
+ * - [Move][PathSegment.Type.Line]: 2 pairs (indices 0 to 3)
+ * - [Move][PathSegment.Type.Quadratic]: 3 pairs (indices 0 to 5)
+ * - [Move][PathSegment.Type.Conic]: 4 pairs (indices 0 to 7), the last pair contains the
+ * [weight][PathSegment.weight] twice
+ * - [Move][PathSegment.Type.Cubic]: 4 pairs (indices 0 to 7)
+ * - [Close][PathSegment.Type.Close]: 0 pair
+ * - [Done][PathSegment.Type.Done]: 0 pair
+ * This method does not allocate any memory.
+ *
+ * @param points A [FloatArray] large enough to hold 8 floats starting at [offset],
+ * throws an [IllegalStateException] otherwise.
+ * @param offset Offset in [points] where to store the result
+ */
+ @JvmOverloads
+ fun next(points: FloatArray, offset: Int = 0): PathSegment.Type =
+ implementation.next(points, offset)
+
+ /**
+ * Returns the next [path segment][PathSegment] in the iteration, or [DoneSegment] if
+ * the iteration is finished. To save on allocations, use the alternative [next] function, which
+ * takes a [FloatArray].
+ */
+ override fun next(): PathSegment = implementation.next()
+}
+
+/**
+ * Creates a new [PathIterator] for this [path][android.graphics.Path] that evaluates
+ * conics as quadratics. To preserve conics, use the [Path.iterator] function that takes a
+ * [PathIterator.ConicEvaluation] parameter.
+ */
+@Suppress("IllegalExperimentalApiUsage")
+@PrereleaseSdkCheck
+operator fun Path.iterator() = PathIterator(this)
+
+/**
+ * Creates a new [PathIterator] for this [path][android.graphics.Path]. To preserve conics as
+ * conics (not convert them to quadratics), set [conicEvaluation] to
+ * [PathIterator.ConicEvaluation.AsConic].
+ */
+@Suppress("IllegalExperimentalApiUsage")
+@PrereleaseSdkCheck
+fun Path.iterator(conicEvaluation: PathIterator.ConicEvaluation, tolerance: Float = 0.25f) =
+ PathIterator(this, conicEvaluation, tolerance)
diff --git a/graphics/graphics-path/src/main/java/androidx/graphics/path/PathIteratorImpl.kt b/graphics/graphics-path/src/main/java/androidx/graphics/path/PathIteratorImpl.kt
new file mode 100644
index 0000000..65fa2c1
--- /dev/null
+++ b/graphics/graphics-path/src/main/java/androidx/graphics/path/PathIteratorImpl.kt
@@ -0,0 +1,341 @@
+/*
+ * Copyright 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.graphics.path
+
+import android.graphics.Path
+import android.graphics.PathIterator as PlatformPathIterator
+import android.graphics.PointF
+import androidx.annotation.RequiresApi
+import androidx.core.os.BuildCompat
+import androidx.graphics.path.PathIterator.ConicEvaluation
+
+/**
+ * Base class for API-version-specific PathIterator implementation classes. All functionality
+ * is implemented in the subclasses except for [next], which relies on shared native code
+ * to perform conic conversion.
+ */
+@Suppress("IllegalExperimentalApiUsage")
+@BuildCompat.PrereleaseSdkCheck
+internal abstract class PathIteratorImpl(
+ val path: Path,
+ val conicEvaluation: ConicEvaluation = ConicEvaluation.AsQuadratics,
+ val tolerance: Float = 0.25f
+) {
+ /**
+ * An iterator's ConicConverter converts from a conic to a series of
+ * quadratics. It keeps track of the resulting quadratics and iterates through
+ * them on ensuing calls to next(). The converter is only ever called if
+ * [conicEvaluation] is set to [ConicEvaluation.AsQuadratics].
+ */
+ var conicConverter = ConicConverter()
+
+ /**
+ * pointsData is used internally when the no-arg variant of next() is called,
+ * to avoid allocating a new array every time.
+ */
+ val pointsData = FloatArray(8)
+
+ private companion object {
+ init {
+ /**
+ * The native library is used mainly for pre-API34, but we also rely
+ * on the conic conversion code in API34+, thus it is initialized here.
+ */
+ System.loadLibrary("androidx.graphics.path")
+ }
+ }
+
+ abstract fun calculateSize(includeConvertedConics: Boolean): Int
+
+ abstract fun hasNext(): Boolean
+ abstract fun peek(): PathSegment.Type
+
+ /**
+ * The core functionality of [next] is in API-specific subclasses. But we implement [next]
+ * at this level to share the same conic conversion implementation across all versions.
+ * This happens by calling [nextImpl] to get the next segment from the subclasses, then
+ * calling the shared [ConicConverter] code when appropriate to get and return the
+ * converted segments.
+ */
+ abstract fun nextImpl(points: FloatArray, offset: Int = 0): PathSegment.Type
+
+ fun next(points: FloatArray, offset: Int = 0): PathSegment.Type {
+ check(points.size - offset >= 8) { "The points array must contain at least 8 floats" }
+ // First check to see if we are currently iterating through converted conics
+ if (conicConverter.currentQuadratic < conicConverter.quadraticCount
+ ) {
+ conicConverter.nextQuadratic(points, offset)
+ return (pathSegmentTypes[PathSegment.Type.Quadratic.ordinal])
+ } else {
+ val typeValue = nextImpl(points, offset)
+ if (typeValue == PathSegment.Type.Conic &&
+ conicEvaluation == ConicEvaluation.AsQuadratics
+ ) {
+ with(conicConverter) {
+ convert(points, points[6 + offset], tolerance, offset)
+ if (quadraticCount > 0) {
+ nextQuadratic(points, offset)
+ }
+ }
+ return PathSegment.Type.Quadratic
+ }
+ return typeValue
+ }
+ }
+
+ fun next(): PathSegment {
+ val type = next(pointsData, 0)
+ if (type == PathSegment.Type.Done) return DoneSegment
+ if (type == PathSegment.Type.Close) return CloseSegment
+ val weight = if (type == PathSegment.Type.Conic) pointsData[6] else 0.0f
+ return PathSegment(type, floatsToPoints(pointsData, type), weight)
+ }
+
+ /**
+ * Utility function to convert a FloatArray to an array of PointF objects, where
+ * every two Floats in the FloatArray correspond to a single PointF in the resulting
+ * point array. The FloatArray is used internally to process a next() call, the
+ * array of points is used to create a PathSegment from the operation.
+ */
+ private fun floatsToPoints(pointsData: FloatArray, type: PathSegment.Type): Array<PointF> {
+ val points = when (type) {
+ PathSegment.Type.Move -> {
+ arrayOf(PointF(pointsData[0], pointsData[1]))
+ }
+
+ PathSegment.Type.Line -> {
+ arrayOf(
+ PointF(pointsData[0], pointsData[1]),
+ PointF(pointsData[2], pointsData[3])
+ )
+ }
+
+ PathSegment.Type.Quadratic,
+ PathSegment.Type.Conic -> {
+ arrayOf(
+ PointF(pointsData[0], pointsData[1]),
+ PointF(pointsData[2], pointsData[3]),
+ PointF(pointsData[4], pointsData[5])
+ )
+ }
+
+ PathSegment.Type.Cubic -> {
+ arrayOf(
+ PointF(pointsData[0], pointsData[1]),
+ PointF(pointsData[2], pointsData[3]),
+ PointF(pointsData[4], pointsData[5]),
+ PointF(pointsData[6], pointsData[7])
+ )
+ }
+ // This should not happen because of the early returns above
+ else -> emptyArray()
+ }
+ return points
+ }
+}
+
+/**
+ * In API level 34, we can use new platform functionality for most of what PathIterator does.
+ * The exceptions are conic conversion (which is handled in the base impl class) and
+ * [calculateSize], which is implemented here.
+ */
+@RequiresApi(34)
+@Suppress("IllegalExperimentalApiUsage")
+@BuildCompat.PrereleaseSdkCheck
+internal class PathIteratorApi34Impl(
+ path: Path,
+ conicEvaluation: ConicEvaluation = ConicEvaluation.AsQuadratics,
+ tolerance: Float = 0.25f
+) : PathIteratorImpl(path, conicEvaluation, tolerance) {
+
+ /**
+ * The platform iterator handles most of what we need for iterating. We hold an instance
+ * of that object in this class.
+ */
+ private val platformIterator: PlatformPathIterator
+
+ init {
+ platformIterator = path.pathIterator
+ }
+
+ /**
+ * The platform does not expose a calculateSize() method, so we implement our own. In the
+ * simplest case, this is done by simply iterating through all segments until done. However, if
+ * the caller requested the true size (including any conic conversion) and if there are any
+ * conics in the path segments, then there is more work to do since we have to convert and count
+ * those segments as well.
+ */
+ override fun calculateSize(includeConvertedConics: Boolean): Int {
+ val convertConics = includeConvertedConics &&
+ conicEvaluation == ConicEvaluation.AsQuadratics
+ var numVerbs = 0
+ val tempIterator = path.pathIterator
+ val tempFloats = FloatArray(8)
+ while (tempIterator.hasNext()) {
+ val type = tempIterator.next(tempFloats, 0)
+ if (type == PlatformPathIterator.VERB_CONIC && convertConics) {
+ with(conicConverter) {
+ convert(tempFloats, tempFloats[6], tolerance)
+ numVerbs += quadraticCount
+ }
+ } else {
+ numVerbs++
+ }
+ }
+ return numVerbs
+ }
+
+ /**
+ * [nextImpl] is called by [next] in the base class to do the work of actually getting the
+ * next segment, for which we defer to the platform iterator.
+ */
+ override fun nextImpl(points: FloatArray, offset: Int): PathSegment.Type {
+ return platformToAndroidXSegmentType(platformIterator.next(points, offset))
+ }
+
+ override fun hasNext(): Boolean {
+ return platformIterator.hasNext()
+ }
+
+ override fun peek(): PathSegment.Type {
+ val platformType = platformIterator.peek()
+ return platformToAndroidXSegmentType(platformType)
+ }
+
+ /**
+ * Callers need the AndroidX segment types, so we must convert from the platform types.
+ */
+ private fun platformToAndroidXSegmentType(platformType: Int): PathSegment.Type {
+ return when (platformType) {
+ PlatformPathIterator.VERB_CLOSE -> PathSegment.Type.Close
+ PlatformPathIterator.VERB_CONIC -> PathSegment.Type.Conic
+ PlatformPathIterator.VERB_CUBIC -> PathSegment.Type.Cubic
+ PlatformPathIterator.VERB_DONE -> PathSegment.Type.Done
+ PlatformPathIterator.VERB_LINE -> PathSegment.Type.Line
+ PlatformPathIterator.VERB_MOVE -> PathSegment.Type.Move
+ PlatformPathIterator.VERB_QUAD -> PathSegment.Type.Quadratic
+ else -> {
+ throw IllegalArgumentException("Unknown path segment type $platformType")
+ }
+ }
+ }
+}
+
+/**
+ * Most of the functionality for pre-34 iteration is handled in the native code. The only
+ * exception, similar to the API34 implementation, is the calculateSize(). There is a size()
+ * function in native code which is very quick (it simply tracks the number of verbs in the native
+ * structure). But if the caller wants conic conversion, then we need to iterate through
+ * and convert appropriately, counting as we iterate.
+ */
+@Suppress("IllegalExperimentalApiUsage")
+@BuildCompat.PrereleaseSdkCheck
+internal class PathIteratorPreApi34Impl(
+ path: Path,
+ conicEvaluation: ConicEvaluation = ConicEvaluation.AsQuadratics,
+ tolerance: Float = 0.25f
+) : PathIteratorImpl(path, conicEvaluation, tolerance) {
+
+ @Suppress("KotlinJniMissingFunction")
+ private external fun createInternalPathIterator(
+ path: Path,
+ conicEvaluation: Int,
+ tolerance: Float
+ ): Long
+
+ @Suppress("KotlinJniMissingFunction")
+ private external fun destroyInternalPathIterator(internalPathIterator: Long)
+
+ @Suppress("KotlinJniMissingFunction")
+ private external fun internalPathIteratorHasNext(internalPathIterator: Long): Boolean
+
+ @Suppress("KotlinJniMissingFunction")
+ private external fun internalPathIteratorNext(
+ internalPathIterator: Long,
+ points: FloatArray,
+ offset: Int
+ ): Int
+
+ @Suppress("KotlinJniMissingFunction")
+ private external fun internalPathIteratorPeek(internalPathIterator: Long): Int
+
+ @Suppress("KotlinJniMissingFunction")
+ private external fun internalPathIteratorRawSize(internalPathIterator: Long): Int
+
+ @Suppress("KotlinJniMissingFunction")
+ private external fun internalPathIteratorSize(internalPathIterator: Long): Int
+ /**
+ * Defines the type of evaluation to apply to conic segments during iteration.
+ */
+
+ private val internalPathIterator =
+ createInternalPathIterator(path, ConicEvaluation.AsConic.ordinal, tolerance)
+
+ /**
+ * Returns the number of verbs present in this iterator's path. If [includeConvertedConics]
+ * property is false and the path has any conic elements, the returned size might be smaller
+ * than the number of calls to [next] required to fully iterate over the path. An accurate
+ * size can be computed by setting the parameter to true instead, at a performance cost.
+ * Including converted conics requires iterating through the entire path, including converting
+ * any conics along the way, to calculate the true size.
+ */
+ override fun calculateSize(includeConvertedConics: Boolean): Int {
+ var numVerbs = 0
+ if (!includeConvertedConics || conicEvaluation == ConicEvaluation.AsConic) {
+ numVerbs = internalPathIteratorSize(internalPathIterator)
+ } else {
+ val tempIterator =
+ createInternalPathIterator(path, ConicEvaluation.AsConic.ordinal, tolerance)
+ val tempFloats = FloatArray(8)
+ while (internalPathIteratorHasNext(tempIterator)) {
+ val segment = internalPathIteratorNext(tempIterator, tempFloats, 0)
+ when (pathSegmentTypes[segment]) {
+ PathSegment.Type.Conic -> {
+ conicConverter.convert(tempFloats, tempFloats[7], tolerance)
+ numVerbs += conicConverter.quadraticCount
+ }
+ else -> numVerbs++
+ }
+ }
+ }
+ return numVerbs
+ }
+
+ /**
+ * Returns `true` if the iteration has more elements.
+ */
+ override fun hasNext(): Boolean = internalPathIteratorHasNext(internalPathIterator)
+
+ /**
+ * Returns the type of the current segment in the iteration, or [Done][PathSegment.Type.Done]
+ * if the iteration is finished.
+ */
+ override fun peek() = pathSegmentTypes[internalPathIteratorPeek(internalPathIterator)]
+
+ /**
+ * This is where the actual work happens to get the next segment in the path, which happens
+ * in native code. This function is called by [next] in the base class, which then converts
+ * the resulting segment from conics to quadratics as necessary.
+ */
+ override fun nextImpl(points: FloatArray, offset: Int): PathSegment.Type {
+ return pathSegmentTypes[internalPathIteratorNext(internalPathIterator, points, offset)]
+ }
+
+ protected fun finalize() {
+ destroyInternalPathIterator(internalPathIterator)
+ }
+}
\ No newline at end of file
diff --git a/graphics/graphics-path/src/main/java/androidx/graphics/path/PathSegment.kt b/graphics/graphics-path/src/main/java/androidx/graphics/path/PathSegment.kt
new file mode 100644
index 0000000..863d6d0
--- /dev/null
+++ b/graphics/graphics-path/src/main/java/androidx/graphics/path/PathSegment.kt
@@ -0,0 +1,143 @@
+/*
+ * Copyright 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+@file:JvmName("PathSegmentUtilities")
+package androidx.graphics.path
+
+import android.graphics.PointF
+
+/**
+ * A path segment represents a curve (line, cubic, quadratic or conic) or a command inside
+ * a fully formed [path][android.graphics.Path] object.
+ *
+ * A segment is identified by a [type][PathSegment.Type] which in turns defines how many
+ * [points] are available (from 0 to 3) and whether the [weight] is meaningful. Please refer
+ * to the documentation of each [type][PathSegment.Type] for more information.
+ *
+ * A segment with the [Move][Type.Move] or [Close][Type.Close] is usually represented by
+ * the singletons [DoneSegment] and [CloseSegment] respectively.
+ *
+ * @property type The type that identifies this segment and defines the number of points.
+ * @property points An array of points describing this segment, whose size depends on [type].
+ * @property weight Conic weight, only valid if [type] is [Type.Conic].
+ */
+class PathSegment internal constructor(
+ val type: Type,
+ @get:Suppress("ArrayReturn") val points: Array<PointF>,
+ val weight: Float
+) {
+
+ /**
+ * Type of a given segment in a [path][android.graphics.Path], either a command
+ * ([Type.Move], [Type.Close], [Type.Done]) or a curve ([Type.Line], [Type.Cubic],
+ * [Type.Quadratic], [Type.Conic]).
+ */
+ enum class Type {
+ /**
+ * Move command, the path segment contains 1 point indicating the move destination.
+ * The weight is set 0.0f and not meaningful.
+ */
+ Move,
+ /**
+ * Line curve, the path segment contains 2 points indicating the two extremities of
+ * the line. The weight is set 0.0f and not meaningful.
+ */
+ Line,
+ /**
+ * Quadratic curve, the path segment contains 3 points in the following order:
+ * - Start point
+ * - Control point
+ * - End point
+ *
+ * The weight is set 0.0f and not meaningful.
+ */
+ Quadratic,
+ /**
+ * Conic curve, the path segment contains 3 points in the following order:
+ * - Start point
+ * - Control point
+ * - End point
+ *
+ * The curve is weighted by the [weight][PathSegment.weight] property.
+ */
+ Conic,
+ /**
+ * Cubic curve, the path segment contains 4 points in the following order:
+ * - Start point
+ * - First control point
+ * - Second control point
+ * - End point
+ *
+ * The weight is set 0.0f and not meaningful.
+ */
+ Cubic,
+ /**
+ * Close command, close the current contour by joining the last point added to the
+ * path with the first point of the current contour. The segment does not contain
+ * any point. The weight is set 0.0f and not meaningful.
+ */
+ Close,
+ /**
+ * Done command, which indicates that no further segment will be
+ * found in the path. It typically indicates the end of an iteration over a path
+ * and can be ignored.
+ */
+ Done
+ }
+
+ override fun equals(other: Any?): Boolean {
+ if (this === other) return true
+ if (javaClass != other?.javaClass) return false
+
+ other as PathSegment
+
+ if (type != other.type) return false
+ if (!points.contentEquals(other.points)) return false
+ if (weight != other.weight) return false
+
+ return true
+ }
+
+ override fun hashCode(): Int {
+ var result = type.hashCode()
+ result = 31 * result + points.contentHashCode()
+ result = 31 * result + weight.hashCode()
+ return result
+ }
+
+ override fun toString(): String {
+ return "PathSegment(type=$type, points=${points.contentToString()}, weight=$weight)"
+ }
+}
+
+/**
+ * A [PathSegment] containing the [Done][PathSegment.Type.Done] command.
+ * This static object exists to avoid allocating a new segment when returning a
+ * [Done][PathSegment.Type.Done] result from [PathIterator.next].
+ */
+val DoneSegment = PathSegment(PathSegment.Type.Done, emptyArray(), 0.0f)
+
+/**
+ * A [PathSegment] containing the [Close][PathSegment.Type.Close] command.
+ * This static object exists to avoid allocating a new segment when returning a
+ * [Close][PathSegment.Type.Close] result from [PathIterator.next].
+ */
+val CloseSegment = PathSegment(PathSegment.Type.Close, emptyArray(), 0.0f)
+
+/**
+ * Cache of [PathSegment.Type] values to avoid internal allocation on each use.
+ */
+internal val pathSegmentTypes = PathSegment.Type.values()
\ No newline at end of file
diff --git a/health/connect/connect-client/build.gradle b/health/connect/connect-client/build.gradle
index 8a8757a..d346b3d 100644
--- a/health/connect/connect-client/build.gradle
+++ b/health/connect/connect-client/build.gradle
@@ -43,6 +43,7 @@
implementation(libs.guavaAndroid)
implementation(libs.kotlinCoroutinesAndroid)
implementation(libs.kotlinCoroutinesGuava)
+ implementation("androidx.core:core-ktx:1.8.0")
testImplementation(libs.testCore)
testImplementation(libs.testRunner)
@@ -58,6 +59,13 @@
testImplementation(libs.espressoIntents)
testImplementation(libs.kotlinReflect)
+ androidTestImplementation(libs.testExtJunit)
+ androidTestImplementation(libs.kotlinCoroutinesTest)
+ androidTestImplementation(libs.kotlinReflect)
+ androidTestImplementation(libs.kotlinTest)
+ androidTestImplementation(libs.junit)
+ androidTestImplementation(libs.truth)
+
samples(project(":health:connect:connect-client-samples"))
}
diff --git a/health/connect/connect-client/src/androidTest/AndroidManifest.xml b/health/connect/connect-client/src/androidTest/AndroidManifest.xml
index 4d68dc2..34efdec 100644
--- a/health/connect/connect-client/src/androidTest/AndroidManifest.xml
+++ b/health/connect/connect-client/src/androidTest/AndroidManifest.xml
@@ -15,5 +15,96 @@
limitations under the License.
-->
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
+ <!-- Read permissions for ACTIVITY. -->
+ <uses-permission android:name="android.permission.health.READ_ACTIVE_CALORIES_BURNED"/>
+ <uses-permission android:name="android.permission.health.READ_DISTANCE"/>
+ <uses-permission android:name="android.permission.health.READ_ELEVATION_GAINED"/>
+ <uses-permission android:name="android.permission.health.READ_EXERCISE"/>
+ <uses-permission android:name="android.permission.health.READ_FLOORS_CLIMBED"/>
+ <uses-permission android:name="android.permission.health.READ_STEPS"/>
+ <uses-permission android:name="android.permission.health.READ_TOTAL_CALORIES_BURNED"/>
+ <uses-permission android:name="android.permission.health.READ_VO2_MAX"/>
+ <uses-permission android:name="android.permission.health.READ_WHEELCHAIR_PUSHES"/>
+ <uses-permission android:name="android.permission.health.READ_POWER"/>
+ <uses-permission android:name="android.permission.health.READ_SPEED"/>
+ <!-- Read permissions for BODY_MEASUREMENTS. -->
+ <uses-permission android:name="android.permission.health.READ_BASAL_METABOLIC_RATE"/>
+ <uses-permission android:name="android.permission.health.READ_BODY_FAT"/>
+ <uses-permission android:name="android.permission.health.READ_BODY_WATER_MASS"/>
+ <uses-permission android:name="android.permission.health.READ_BONE_MASS"/>
+ <uses-permission android:name="android.permission.health.READ_HEIGHT"/>
+ <uses-permission android:name="android.permission.health.READ_LEAN_BODY_MASS"/>
+ <uses-permission android:name="android.permission.health.READ_WEIGHT"/>
+
+ <!-- Read permissions for CYCLE_TRACKING. -->
+ <uses-permission android:name="android.permission.health.READ_CERVICAL_MUCUS"/>
+ <uses-permission android:name="android.permission.health.READ_MENSTRUATION"/>
+ <uses-permission android:name="android.permission.health.READ_OVULATION_TEST"/>
+ <uses-permission android:name="android.permission.health.READ_SEXUAL_ACTIVITY"/>
+
+ <!-- Read permissions for NUTRITION. -->
+ <uses-permission android:name="android.permission.health.READ_HYDRATION"/>
+ <uses-permission android:name="android.permission.health.READ_NUTRITION"/>
+
+ <!-- Read permissions for SLEEP. -->
+ <uses-permission android:name="android.permission.health.READ_SLEEP"/>
+
+ <!-- Read permissions for VITALS. -->
+ <uses-permission android:name="android.permission.health.READ_BASAL_BODY_TEMPERATURE"/>
+ <uses-permission android:name="android.permission.health.READ_BLOOD_GLUCOSE"/>
+ <uses-permission android:name="android.permission.health.READ_BLOOD_PRESSURE"/>
+ <uses-permission android:name="android.permission.health.READ_BODY_TEMPERATURE"/>
+ <uses-permission android:name="android.permission.health.READ_HEART_RATE"/>
+ <uses-permission android:name="android.permission.health.READ_HEART_RATE_VARIABILITY"/>
+ <uses-permission android:name="android.permission.health.READ_OXYGEN_SATURATION"/>
+ <uses-permission android:name="android.permission.health.READ_RESPIRATORY_RATE"/>
+ <uses-permission android:name="android.permission.health.READ_RESTING_HEART_RATE"/>
+
+ <!-- Write permissions for ACTIVITY. -->
+ <uses-permission android:name="android.permission.health.WRITE_ACTIVE_CALORIES_BURNED"/>
+ <uses-permission android:name="android.permission.health.WRITE_DISTANCE"/>
+ <uses-permission android:name="android.permission.health.WRITE_ELEVATION_GAINED"/>
+ <uses-permission android:name="android.permission.health.WRITE_EXERCISE"/>
+ <uses-permission android:name="android.permission.health.WRITE_FLOORS_CLIMBED"/>
+ <uses-permission android:name="android.permission.health.WRITE_STEPS"/>
+ <uses-permission android:name="android.permission.health.WRITE_TOTAL_CALORIES_BURNED"/>
+ <uses-permission android:name="android.permission.health.WRITE_VO2_MAX"/>
+ <uses-permission android:name="android.permission.health.WRITE_WHEELCHAIR_PUSHES"/>
+ <uses-permission android:name="android.permission.health.WRITE_POWER"/>
+ <uses-permission android:name="android.permission.health.WRITE_SPEED"/>
+
+ <!-- Write permissions for BODY_MEASUREMENTS. -->
+ <uses-permission android:name="android.permission.health.WRITE_BASAL_METABOLIC_RATE"/>
+ <uses-permission android:name="android.permission.health.WRITE_BODY_FAT"/>
+ <uses-permission android:name="android.permission.health.WRITE_BODY_WATER_MASS"/>
+ <uses-permission android:name="android.permission.health.WRITE_BONE_MASS"/>
+ <uses-permission android:name="android.permission.health.WRITE_HEIGHT"/>
+ <uses-permission android:name="android.permission.health.WRITE_LEAN_BODY_MASS"/>
+ <uses-permission android:name="android.permission.health.WRITE_WEIGHT"/>
+
+ <!-- Write permissions for CYCLE_TRACKING. -->
+ <uses-permission android:name="android.permission.health.WRITE_CERVICAL_MUCUS"/>
+ <uses-permission android:name="android.permission.health.WRITE_INTERMENSTRUAL_BLEEDING"/>
+ <uses-permission android:name="android.permission.health.WRITE_MENSTRUATION"/>
+ <uses-permission android:name="android.permission.health.WRITE_OVULATION_TEST"/>
+ <uses-permission android:name="android.permission.health.WRITE_SEXUAL_ACTIVITY"/>
+
+ <!-- Write permissions for NUTRITION. -->
+ <uses-permission android:name="android.permission.health.WRITE_HYDRATION"/>
+ <uses-permission android:name="android.permission.health.WRITE_NUTRITION"/>
+
+ <!-- Write permissions for SLEEP. -->
+ <uses-permission android:name="android.permission.health.WRITE_SLEEP"/>
+
+ <!-- Write permissions for VITALS. -->
+ <uses-permission android:name="android.permission.health.WRITE_BASAL_BODY_TEMPERATURE"/>
+ <uses-permission android:name="android.permission.health.WRITE_BLOOD_GLUCOSE"/>
+ <uses-permission android:name="android.permission.health.WRITE_BLOOD_PRESSURE"/>
+ <uses-permission android:name="android.permission.health.WRITE_BODY_TEMPERATURE"/>
+ <uses-permission android:name="android.permission.health.WRITE_HEART_RATE"/>
+ <uses-permission android:name="android.permission.health.WRITE_HEART_RATE_VARIABILITY"/>
+ <uses-permission android:name="android.permission.health.WRITE_OXYGEN_SATURATION"/>
+ <uses-permission android:name="android.permission.health.WRITE_RESPIRATORY_RATE"/>
+ <uses-permission android:name="android.permission.health.WRITE_RESTING_HEART_RATE"/>
</manifest>
diff --git a/health/connect/connect-client/src/androidTest/java/androidx/health/connect/client/ClassFinder.kt b/health/connect/connect-client/src/androidTest/java/androidx/health/connect/client/ClassFinder.kt
new file mode 100644
index 0000000..5539e49
--- /dev/null
+++ b/health/connect/connect-client/src/androidTest/java/androidx/health/connect/client/ClassFinder.kt
@@ -0,0 +1,81 @@
+/*
+ * Copyright 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.health.connect.client
+
+import androidx.health.connect.client.records.Record
+import java.io.File
+import java.net.URL
+import java.util.zip.ZipEntry
+import java.util.zip.ZipInputStream
+import kotlin.reflect.KClass
+
+@Suppress("UNCHECKED_CAST")
+val RECORD_CLASSES: List<KClass<out Record>> by lazy {
+ findClasses("androidx.health.connect.client.records")
+ .filterNot { it.java.isInterface }
+ .filter { it.simpleName.orEmpty().endsWith("Record") }
+ .map { it as KClass<out Record> }
+}
+
+fun findClasses(packageName: String): Set<KClass<*>> {
+ val resources =
+ requireNotNull(Thread.currentThread().contextClassLoader)
+ .getResources(packageName.replace('.', '/'))
+
+ return buildSet {
+ while (resources.hasMoreElements()) {
+ val classNames = findClasses(resources.nextElement().file, packageName)
+ for (className in classNames) {
+ add(Class.forName(className).kotlin)
+ }
+ }
+ }
+}
+
+private fun findClasses(directory: String, packageName: String): Set<String> = buildSet {
+ if (directory.startsWith("file:") && ('!' in directory)) {
+ addAll(unzipClasses(path = directory, packageName = packageName))
+ }
+
+ for (file in File(directory).takeIf(File::exists)?.listFiles() ?: emptyArray()) {
+ if (file.isDirectory) {
+ addAll(findClasses(file.absolutePath, "$packageName.${file.name}"))
+ } else if (file.name.endsWith(".class")) {
+ add("$packageName.${file.name.dropLast(6)}")
+ }
+ }
+}
+
+private fun unzipClasses(path: String, packageName: String): Set<String> =
+ ZipInputStream(URL(path.substringBefore('!')).openStream()).use { zip ->
+ buildSet {
+ while (true) {
+ val entry = zip.nextEntry ?: break
+ val className = entry.formatClassName()
+ if ((className != null) && className.startsWith(packageName)) {
+ add(className)
+ }
+ }
+ }
+ }
+
+private fun ZipEntry.formatClassName(): String? =
+ name
+ .takeIf { it.endsWith(".class") }
+ ?.replace("[$].*".toRegex(), "")
+ ?.replace("[.]class".toRegex(), "")
+ ?.replace('/', '.')
diff --git a/health/connect/connect-client/src/androidTest/java/androidx/health/connect/client/impl/HealthConnectClientUpsideDownImplTest.kt b/health/connect/connect-client/src/androidTest/java/androidx/health/connect/client/impl/HealthConnectClientUpsideDownImplTest.kt
new file mode 100644
index 0000000..373952a
--- /dev/null
+++ b/health/connect/connect-client/src/androidTest/java/androidx/health/connect/client/impl/HealthConnectClientUpsideDownImplTest.kt
@@ -0,0 +1,529 @@
+/*
+ * Copyright 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.health.connect.client.impl
+
+import android.annotation.TargetApi
+import android.content.Context
+import android.content.pm.PackageManager
+import android.os.Build
+import android.os.RemoteException
+import androidx.health.connect.client.HealthConnectClient
+import androidx.health.connect.client.changes.DeletionChange
+import androidx.health.connect.client.changes.UpsertionChange
+import androidx.health.connect.client.permission.HealthPermission.Companion.PERMISSION_PREFIX
+import androidx.health.connect.client.records.HeartRateRecord
+import androidx.health.connect.client.records.NutritionRecord
+import androidx.health.connect.client.records.StepsRecord
+import androidx.health.connect.client.records.WheelchairPushesRecord
+import androidx.health.connect.client.records.metadata.Metadata
+import androidx.health.connect.client.request.AggregateGroupByDurationRequest
+import androidx.health.connect.client.request.AggregateGroupByPeriodRequest
+import androidx.health.connect.client.request.AggregateRequest
+import androidx.health.connect.client.request.ChangesTokenRequest
+import androidx.health.connect.client.request.ReadRecordsRequest
+import androidx.health.connect.client.time.TimeRangeFilter
+import androidx.health.connect.client.units.Energy
+import androidx.health.connect.client.units.Mass
+import androidx.test.core.app.ApplicationProvider
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import androidx.test.filters.MediumTest
+import androidx.test.filters.SdkSuppress
+import androidx.test.rule.GrantPermissionRule
+import com.google.common.truth.Truth.assertThat
+import java.time.Duration
+import java.time.Instant
+import java.time.LocalDateTime
+import java.time.Period
+import java.time.ZoneOffset
+import kotlin.test.assertFailsWith
+import kotlinx.coroutines.test.runTest
+import org.junit.After
+import org.junit.Before
+import org.junit.Ignore
+import org.junit.Rule
+import org.junit.Test
+import org.junit.runner.RunWith
+
+@RunWith(AndroidJUnit4::class)
+@OptIn(kotlinx.coroutines.ExperimentalCoroutinesApi::class)
+@MediumTest
+@TargetApi(Build.VERSION_CODES.UPSIDE_DOWN_CAKE)
+// Comment the SDK suppress to run on emulators lower than U.
+@SdkSuppress(minSdkVersion = Build.VERSION_CODES.UPSIDE_DOWN_CAKE, codeName = "UpsideDownCake")
+class HealthConnectClientUpsideDownImplTest {
+
+ private val context: Context = ApplicationProvider.getApplicationContext()
+ private val allHealthPermissions =
+ context.packageManager
+ .getPackageInfo(
+ context.packageName,
+ PackageManager.PackageInfoFlags.of(PackageManager.GET_PERMISSIONS.toLong())
+ )
+ .requestedPermissions
+ .filter { it.startsWith(PERMISSION_PREFIX) }
+ .toTypedArray()
+
+ // Grant every permission as deletion by id checks for every permission
+ @get:Rule
+ val grantPermissionRule: GrantPermissionRule = GrantPermissionRule.grant(*allHealthPermissions)
+
+ private lateinit var healthConnectClient: HealthConnectClient
+
+ @Before
+ fun setUp() {
+ healthConnectClient = HealthConnectClientUpsideDownImpl(context)
+ }
+
+ @After
+ fun tearDown() = runTest {
+ healthConnectClient.deleteRecords(StepsRecord::class, TimeRangeFilter.none())
+ healthConnectClient.deleteRecords(HeartRateRecord::class, TimeRangeFilter.none())
+ healthConnectClient.deleteRecords(NutritionRecord::class, TimeRangeFilter.none())
+ }
+
+ @Test
+ fun insertRecords() = runTest {
+ val response =
+ healthConnectClient.insertRecords(
+ listOf(
+ StepsRecord(
+ count = 10,
+ startTime = Instant.ofEpochMilli(1234L),
+ startZoneOffset = null,
+ endTime = Instant.ofEpochMilli(5678L),
+ endZoneOffset = null
+ )
+ )
+ )
+ assertThat(response.recordIdsList).hasSize(1)
+ }
+
+ @Test
+ fun deleteRecords_byId() = runTest {
+ val recordIds =
+ healthConnectClient
+ .insertRecords(
+ listOf(
+ StepsRecord(
+ count = 10,
+ startTime = Instant.ofEpochMilli(1234L),
+ startZoneOffset = null,
+ endTime = Instant.ofEpochMilli(5678L),
+ endZoneOffset = null
+ ),
+ StepsRecord(
+ count = 15,
+ startTime = Instant.ofEpochMilli(12340L),
+ startZoneOffset = null,
+ endTime = Instant.ofEpochMilli(56780L),
+ endZoneOffset = null
+ ),
+ StepsRecord(
+ count = 20,
+ startTime = Instant.ofEpochMilli(123400L),
+ startZoneOffset = null,
+ endTime = Instant.ofEpochMilli(567800L),
+ endZoneOffset = null,
+ metadata = Metadata(clientRecordId = "clientId")
+ ),
+ )
+ )
+ .recordIdsList
+
+ val initialRecords =
+ healthConnectClient
+ .readRecords(ReadRecordsRequest(StepsRecord::class, TimeRangeFilter.none()))
+ .records
+
+ healthConnectClient.deleteRecords(
+ StepsRecord::class,
+ listOf(recordIds[1]),
+ listOf("clientId")
+ )
+
+ assertThat(
+ healthConnectClient
+ .readRecords(ReadRecordsRequest(StepsRecord::class, TimeRangeFilter.none()))
+ .records
+ )
+ .containsExactly(initialRecords[0])
+ }
+
+ // TODO(b/264253708): remove @Ignore from this test case once bug is resolved
+ @Test
+ @Ignore("Blocked while investigating b/264253708")
+ fun deleteRecords_byTimeRange() = runTest {
+ healthConnectClient
+ .insertRecords(
+ listOf(
+ StepsRecord(
+ count = 100,
+ startTime = Instant.ofEpochMilli(1_234L),
+ startZoneOffset = ZoneOffset.UTC,
+ endTime = Instant.ofEpochMilli(5_678L),
+ endZoneOffset = ZoneOffset.UTC
+ ),
+ StepsRecord(
+ count = 150,
+ startTime = Instant.ofEpochMilli(12_340L),
+ startZoneOffset = ZoneOffset.UTC,
+ endTime = Instant.ofEpochMilli(56_780L),
+ endZoneOffset = ZoneOffset.UTC
+ ),
+ )
+ )
+ .recordIdsList
+
+ val initialRecords =
+ healthConnectClient
+ .readRecords(ReadRecordsRequest(StepsRecord::class, TimeRangeFilter.none()))
+ .records
+
+ healthConnectClient.deleteRecords(
+ StepsRecord::class,
+ TimeRangeFilter.before(Instant.ofEpochMilli(10_000L))
+ )
+
+ assertThat(
+ healthConnectClient
+ .readRecords(ReadRecordsRequest(StepsRecord::class, TimeRangeFilter.none()))
+ .records
+ )
+ .containsExactly(initialRecords[1])
+ }
+
+ @Test
+ fun updateRecords() = runTest {
+ val id =
+ healthConnectClient
+ .insertRecords(
+ listOf(
+ StepsRecord(
+ count = 10,
+ startTime = Instant.ofEpochMilli(1234L),
+ startZoneOffset = null,
+ endTime = Instant.ofEpochMilli(5678L),
+ endZoneOffset = null
+ )
+ )
+ )
+ .recordIdsList[0]
+
+ val insertedRecord = healthConnectClient.readRecord(StepsRecord::class, id).record
+
+ healthConnectClient.updateRecords(
+ listOf(
+ StepsRecord(
+ count = 5,
+ startTime = Instant.ofEpochMilli(1234L),
+ startZoneOffset = null,
+ endTime = Instant.ofEpochMilli(5678L),
+ endZoneOffset = null,
+ metadata = Metadata(id, insertedRecord.metadata.dataOrigin)
+ )
+ )
+ )
+
+ val updatedRecord = healthConnectClient.readRecord(StepsRecord::class, id).record
+
+ assertThat(updatedRecord.count).isEqualTo(5L)
+ }
+
+ @Test
+ fun readRecord_withId() = runTest {
+ val insertResponse =
+ healthConnectClient.insertRecords(
+ listOf(
+ StepsRecord(
+ count = 10,
+ startTime = Instant.ofEpochMilli(1234L),
+ startZoneOffset = ZoneOffset.UTC,
+ endTime = Instant.ofEpochMilli(5678L),
+ endZoneOffset = ZoneOffset.UTC
+ )
+ )
+ )
+
+ val readResponse =
+ healthConnectClient.readRecord(StepsRecord::class, insertResponse.recordIdsList[0])
+
+ with(readResponse.record) {
+ assertThat(count).isEqualTo(10)
+ assertThat(startTime).isEqualTo(Instant.ofEpochMilli(1234L))
+ assertThat(startZoneOffset).isEqualTo(ZoneOffset.UTC)
+ assertThat(endTime).isEqualTo(Instant.ofEpochMilli(5678L))
+ assertThat(endZoneOffset).isEqualTo(ZoneOffset.UTC)
+ }
+ }
+
+ @Test
+ fun readRecords_withFilters() = runTest {
+ healthConnectClient.insertRecords(
+ listOf(
+ StepsRecord(
+ count = 10,
+ startTime = Instant.ofEpochMilli(1234L),
+ startZoneOffset = ZoneOffset.UTC,
+ endTime = Instant.ofEpochMilli(5678L),
+ endZoneOffset = ZoneOffset.UTC
+ ),
+ StepsRecord(
+ count = 5,
+ startTime = Instant.ofEpochMilli(12340L),
+ startZoneOffset = ZoneOffset.UTC,
+ endTime = Instant.ofEpochMilli(56780L),
+ endZoneOffset = ZoneOffset.UTC
+ ),
+ )
+ )
+
+ val readResponse =
+ healthConnectClient.readRecords(
+ ReadRecordsRequest(
+ StepsRecord::class,
+ TimeRangeFilter.after(Instant.ofEpochMilli(10_000L))
+ )
+ )
+
+ assertThat(readResponse.records[0].count).isEqualTo(5)
+ }
+
+ @Test
+ fun readRecord_noRecords_throwRemoteException() = runTest {
+ assertFailsWith<RemoteException> { healthConnectClient.readRecord(StepsRecord::class, "1") }
+ }
+
+ @Test
+ fun aggregateRecords() = runTest {
+ healthConnectClient.insertRecords(
+ listOf(
+ StepsRecord(
+ count = 10,
+ startTime = Instant.ofEpochMilli(1234L),
+ startZoneOffset = ZoneOffset.UTC,
+ endTime = Instant.ofEpochMilli(5678L),
+ endZoneOffset = ZoneOffset.UTC
+ ),
+ StepsRecord(
+ count = 5,
+ startTime = Instant.ofEpochMilli(12340L),
+ startZoneOffset = ZoneOffset.UTC,
+ endTime = Instant.ofEpochMilli(56780L),
+ endZoneOffset = ZoneOffset.UTC
+ ),
+ HeartRateRecord(
+ startTime = Instant.ofEpochMilli(1234L),
+ startZoneOffset = ZoneOffset.UTC,
+ endTime = Instant.ofEpochMilli(5678L),
+ endZoneOffset = ZoneOffset.UTC,
+ samples =
+ listOf(
+ HeartRateRecord.Sample(Instant.ofEpochMilli(1234L), 57L),
+ HeartRateRecord.Sample(Instant.ofEpochMilli(1235L), 120L)
+ )
+ ),
+ HeartRateRecord(
+ startTime = Instant.ofEpochMilli(12340L),
+ startZoneOffset = ZoneOffset.UTC,
+ endTime = Instant.ofEpochMilli(56780L),
+ endZoneOffset = ZoneOffset.UTC,
+ samples =
+ listOf(
+ HeartRateRecord.Sample(Instant.ofEpochMilli(12340L), 47L),
+ HeartRateRecord.Sample(Instant.ofEpochMilli(12350L), 48L)
+ )
+ ),
+ NutritionRecord(
+ startTime = Instant.ofEpochMilli(1234L),
+ startZoneOffset = ZoneOffset.UTC,
+ endTime = Instant.ofEpochMilli(5678L),
+ endZoneOffset = ZoneOffset.UTC,
+ energy = Energy.kilocalories(200.0)
+ )
+ )
+ )
+
+ val aggregateResponse =
+ healthConnectClient.aggregate(
+ AggregateRequest(
+ setOf(
+ StepsRecord.COUNT_TOTAL,
+ HeartRateRecord.BPM_MIN,
+ HeartRateRecord.BPM_MAX,
+ NutritionRecord.ENERGY_TOTAL,
+ NutritionRecord.CAFFEINE_TOTAL,
+ WheelchairPushesRecord.COUNT_TOTAL,
+ ),
+ TimeRangeFilter.none()
+ )
+ )
+
+ with(aggregateResponse) {
+ assertThat(this[StepsRecord.COUNT_TOTAL]).isEqualTo(15L)
+ assertThat(this[HeartRateRecord.BPM_MIN]).isEqualTo(47L)
+ assertThat(this[HeartRateRecord.BPM_MAX]).isEqualTo(120L)
+ assertThat(this[NutritionRecord.ENERGY_TOTAL]).isEqualTo(Energy.kilocalories(200.0))
+ assertThat(this[NutritionRecord.CAFFEINE_TOTAL]).isEqualTo(Mass.grams(0.0))
+
+ assertThat(contains(WheelchairPushesRecord.COUNT_TOTAL)).isFalse()
+ }
+ }
+
+ @Test
+ fun aggregateRecordsGroupByDuration() = runTest {
+ healthConnectClient.insertRecords(
+ listOf(
+ StepsRecord(
+ count = 1,
+ startTime = Instant.ofEpochMilli(1200L),
+ startZoneOffset = ZoneOffset.UTC,
+ endTime = Instant.ofEpochMilli(1240L),
+ endZoneOffset = ZoneOffset.UTC
+ ),
+ StepsRecord(
+ count = 2,
+ startTime = Instant.ofEpochMilli(1300L),
+ startZoneOffset = ZoneOffset.UTC,
+ endTime = Instant.ofEpochMilli(1500L),
+ endZoneOffset = ZoneOffset.UTC
+ ),
+ StepsRecord(
+ count = 5,
+ startTime = Instant.ofEpochMilli(2400L),
+ startZoneOffset = ZoneOffset.UTC,
+ endTime = Instant.ofEpochMilli(3500L),
+ endZoneOffset = ZoneOffset.UTC
+ )
+ )
+ )
+
+ val aggregateResponse =
+ healthConnectClient.aggregateGroupByDuration(
+ AggregateGroupByDurationRequest(
+ setOf(StepsRecord.COUNT_TOTAL),
+ TimeRangeFilter.between(
+ Instant.ofEpochMilli(1000L),
+ Instant.ofEpochMilli(3000L)
+ ),
+ Duration.ofMillis(1000),
+ setOf()
+ )
+ )
+
+ with(aggregateResponse) {
+ assertThat(this).hasSize(2)
+ assertThat(this[0].result[StepsRecord.COUNT_TOTAL]).isEqualTo(3)
+ assertThat(this[1].result[StepsRecord.COUNT_TOTAL]).isEqualTo(5)
+ }
+ }
+
+ @Test
+ @Ignore("Blocked as period response from platform has a bug with inverted start/end timestamps")
+ fun aggregateRecordsGroupByPeriod() = runTest {
+ healthConnectClient.insertRecords(
+ listOf(
+ StepsRecord(
+ count = 100,
+ startTime = LocalDateTime.of(2018, 10, 11, 7, 10).toInstant(ZoneOffset.UTC),
+ startZoneOffset = ZoneOffset.UTC,
+ endTime = LocalDateTime.of(2018, 10, 11, 7, 15).toInstant(ZoneOffset.UTC),
+ endZoneOffset = ZoneOffset.UTC
+ ),
+ StepsRecord(
+ count = 200,
+ startTime = LocalDateTime.of(2018, 10, 11, 10, 10).toInstant(ZoneOffset.UTC),
+ startZoneOffset = ZoneOffset.UTC,
+ endTime = LocalDateTime.of(2018, 10, 11, 11, 0).toInstant(ZoneOffset.UTC),
+ endZoneOffset = ZoneOffset.UTC
+ ),
+ StepsRecord(
+ count = 50,
+ startTime = LocalDateTime.of(2018, 10, 13, 7, 10).toInstant(ZoneOffset.UTC),
+ startZoneOffset = ZoneOffset.UTC,
+ endTime = LocalDateTime.of(2018, 10, 13, 8, 10).toInstant(ZoneOffset.UTC),
+ endZoneOffset = ZoneOffset.UTC
+ )
+ )
+ )
+
+ val aggregateResponse =
+ healthConnectClient.aggregateGroupByPeriod(
+ AggregateGroupByPeriodRequest(
+ setOf(StepsRecord.COUNT_TOTAL),
+ TimeRangeFilter.between(
+ LocalDateTime.of(2018, 10, 11, 6, 10).toInstant(ZoneOffset.UTC),
+ LocalDateTime.of(2018, 10, 12, 7, 15).toInstant(ZoneOffset.UTC),
+ ),
+ timeRangeSlicer = Period.ofDays(1)
+ )
+ )
+
+ with(aggregateResponse) {
+ assertThat(this).hasSize(2)
+ assertThat(this[0].result[StepsRecord.COUNT_TOTAL]).isEqualTo(300)
+ assertThat(this[1].result[StepsRecord.COUNT_TOTAL]).isEqualTo(0)
+ }
+ }
+
+ @Test
+ fun getChangesToken() = runTest {
+ val token =
+ healthConnectClient.getChangesToken(
+ ChangesTokenRequest(setOf(StepsRecord::class), setOf())
+ )
+ assertThat(token).isNotEmpty()
+ }
+
+ @Test
+ fun getChanges() = runTest {
+ val token =
+ healthConnectClient.getChangesToken(
+ ChangesTokenRequest(setOf(StepsRecord::class), setOf())
+ )
+
+ val insertedRecordId =
+ healthConnectClient
+ .insertRecords(
+ listOf(
+ StepsRecord(
+ count = 10,
+ startTime = Instant.ofEpochMilli(1234L),
+ startZoneOffset = ZoneOffset.UTC,
+ endTime = Instant.ofEpochMilli(5678L),
+ endZoneOffset = ZoneOffset.UTC
+ )
+ )
+ )
+ .recordIdsList[0]
+
+ val record = healthConnectClient.readRecord(StepsRecord::class, insertedRecordId).record
+
+ assertThat(healthConnectClient.getChanges(token).changes)
+ .containsExactly(UpsertionChange(record))
+
+ healthConnectClient.deleteRecords(StepsRecord::class, TimeRangeFilter.none())
+
+ assertThat(healthConnectClient.getChanges(token).changes)
+ .containsExactly(DeletionChange(insertedRecordId))
+ }
+
+ @Test
+ fun getGrantedPermissions() = runTest {
+ assertThat(healthConnectClient.permissionController.getGrantedPermissions())
+ .containsExactlyElementsIn(allHealthPermissions)
+ }
+}
diff --git a/health/connect/connect-client/src/androidTest/java/androidx/health/connect/client/impl/PermissionControllerUpsideDownTest.kt b/health/connect/connect-client/src/androidTest/java/androidx/health/connect/client/impl/PermissionControllerUpsideDownTest.kt
new file mode 100644
index 0000000..290d3ec
--- /dev/null
+++ b/health/connect/connect-client/src/androidTest/java/androidx/health/connect/client/impl/PermissionControllerUpsideDownTest.kt
@@ -0,0 +1,68 @@
+/*
+ * Copyright 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.health.connect.client.impl
+
+import android.annotation.TargetApi
+import android.health.connect.HealthPermissions
+import android.os.Build
+import androidx.health.connect.client.PermissionController
+import androidx.health.connect.client.impl.platform.time.SystemDefaultTimeSource
+import androidx.health.connect.client.permission.HealthPermission.Companion.PERMISSION_PREFIX
+import androidx.test.core.app.ApplicationProvider
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import androidx.test.filters.MediumTest
+import androidx.test.filters.SdkSuppress
+import androidx.test.rule.GrantPermissionRule
+import com.google.common.truth.Truth.assertThat
+import kotlinx.coroutines.test.runTest
+import org.junit.Rule
+import org.junit.Test
+import org.junit.runner.RunWith
+
+@RunWith(AndroidJUnit4::class)
+@OptIn(kotlinx.coroutines.ExperimentalCoroutinesApi::class)
+@MediumTest
+@TargetApi(Build.VERSION_CODES.UPSIDE_DOWN_CAKE)
+// Comment the SDK suppress to run on emulators lower than U.
+@SdkSuppress(minSdkVersion = Build.VERSION_CODES.UPSIDE_DOWN_CAKE, codeName = "UpsideDownCake")
+class PermissionControllerUpsideDownTest {
+
+ @get:Rule
+ val grantPermissionRule: GrantPermissionRule =
+ GrantPermissionRule.grant(HealthPermissions.WRITE_STEPS, HealthPermissions.READ_DISTANCE)
+
+ @Test
+ fun getGrantedPermissions() = runTest {
+ val permissionController: PermissionController =
+ HealthConnectClientUpsideDownImpl(ApplicationProvider.getApplicationContext())
+ assertThat(permissionController.getGrantedPermissions())
+ .containsExactly(HealthPermissions.WRITE_STEPS, HealthPermissions.READ_DISTANCE)
+ }
+
+ @Test
+ fun revokeAllPermissions_revokesHealthPermissions() = runTest {
+ val revokedPermissions: MutableList<String> = mutableListOf()
+ val permissionController: PermissionController =
+ HealthConnectClientUpsideDownImpl(
+ ApplicationProvider.getApplicationContext(), SystemDefaultTimeSource) {
+ permissionsToRevoke ->
+ revokedPermissions.addAll(permissionsToRevoke)
+ }
+ permissionController.revokeAllPermissions()
+ assertThat(revokedPermissions.all { it.startsWith(PERMISSION_PREFIX) }).isTrue()
+ }
+}
diff --git a/health/connect/connect-client/src/androidTest/java/androidx/health/connect/client/impl/platform/records/RecordsConvertersTest.kt b/health/connect/connect-client/src/androidTest/java/androidx/health/connect/client/impl/platform/records/RecordsConvertersTest.kt
new file mode 100644
index 0000000..abf5d49
--- /dev/null
+++ b/health/connect/connect-client/src/androidTest/java/androidx/health/connect/client/impl/platform/records/RecordsConvertersTest.kt
@@ -0,0 +1,287 @@
+/*
+ * Copyright 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.health.connect.client.impl.platform.records
+
+import android.annotation.TargetApi
+import android.health.connect.datatypes.DataOrigin as PlatformDataOrigin
+import android.health.connect.datatypes.Device as PlatformDevice
+import android.health.connect.datatypes.HeartRateRecord as PlatformHeartRateRecord
+import android.health.connect.datatypes.Metadata as PlatformMetadata
+import android.health.connect.datatypes.NutritionRecord as PlatformNutritionRecord
+import android.health.connect.datatypes.StepsRecord as PlatformStepsRecord
+import android.health.connect.datatypes.units.Energy as PlatformEnergy
+import android.health.connect.datatypes.units.Mass as PlatformMass
+import android.os.Build
+import androidx.health.connect.client.RECORD_CLASSES
+import androidx.health.connect.client.records.HeartRateRecord
+import androidx.health.connect.client.records.NutritionRecord
+import androidx.health.connect.client.records.StepsRecord
+import androidx.health.connect.client.records.metadata.DataOrigin
+import androidx.health.connect.client.records.metadata.Device
+import androidx.health.connect.client.records.metadata.Metadata
+import androidx.health.connect.client.units.Energy
+import androidx.health.connect.client.units.Mass
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import androidx.test.filters.SdkSuppress
+import androidx.test.filters.SmallTest
+import com.google.common.truth.Correspondence
+import com.google.common.truth.Truth.assertThat
+import java.time.Instant
+import java.time.ZoneOffset
+import org.junit.Test
+import org.junit.runner.RunWith
+
+@RunWith(AndroidJUnit4::class)
+@OptIn(kotlinx.coroutines.ExperimentalCoroutinesApi::class)
+@SmallTest
+@TargetApi(Build.VERSION_CODES.UPSIDE_DOWN_CAKE)
+// Comment the SDK suppress to run on emulators lower than U.
+@SdkSuppress(minSdkVersion = Build.VERSION_CODES.UPSIDE_DOWN_CAKE, codeName = "UpsideDownCake")
+class RecordsConvertersTest {
+
+ @Test
+ fun toPlatformRecordClass_supportsAllRecordTypes() {
+ RECORD_CLASSES.forEach {
+ assertThat(it.toPlatformRecordClass()).isNotNull()
+ }
+ }
+
+ @Test
+ fun stepsRecordClass_convertToPlatform() {
+ val stepsSdkClass = StepsRecord::class
+ val stepsPlatformClass = PlatformStepsRecord::class.java
+
+ assertThat(stepsSdkClass.toPlatformRecordClass()).isEqualTo(stepsPlatformClass)
+ }
+
+ @Test
+ fun stepsRecord_convertToPlatform() {
+ val steps =
+ StepsRecord(
+ count = 100,
+ startTime = Instant.ofEpochMilli(1234L),
+ startZoneOffset = ZoneOffset.UTC,
+ endTime = Instant.ofEpochMilli(56780L),
+ endZoneOffset = ZoneOffset.UTC,
+ metadata = Metadata(id = "someId"))
+
+ val platformSteps = steps.toPlatformRecord() as PlatformStepsRecord
+
+ with(platformSteps) {
+ assertThat(count).isEqualTo(100)
+ assertThat(startTime).isEqualTo(Instant.ofEpochMilli(1234L))
+ assertThat(startZoneOffset).isEqualTo(ZoneOffset.UTC)
+ assertThat(endTime).isEqualTo(Instant.ofEpochMilli(56780L))
+ assertThat(endZoneOffset).isEqualTo(ZoneOffset.UTC)
+ assertThat(metadata.id).isEqualTo("someId")
+ }
+ }
+
+ @Test
+ fun heartRateRecord_convertToPlatform() {
+ val heartRate =
+ HeartRateRecord(
+ startTime = Instant.ofEpochMilli(1234L),
+ startZoneOffset = ZoneOffset.UTC,
+ endTime = Instant.ofEpochMilli(5678L),
+ endZoneOffset = ZoneOffset.UTC,
+ samples =
+ listOf(
+ HeartRateRecord.Sample(Instant.ofEpochMilli(1234L), 55L),
+ HeartRateRecord.Sample(Instant.ofEpochMilli(5678L), 57L)),
+ metadata = Metadata(id = "an id"))
+
+ val platformHeartRate = heartRate.toPlatformRecord() as PlatformHeartRateRecord
+
+ with(platformHeartRate) {
+ assertThat(startTime).isEqualTo(Instant.ofEpochMilli(1234L))
+ assertThat(startZoneOffset).isEqualTo(ZoneOffset.UTC)
+ assertThat(endTime).isEqualTo(Instant.ofEpochMilli(5678L))
+ assertThat(endZoneOffset).isEqualTo(ZoneOffset.UTC)
+ assertThat(samples)
+ .comparingElementsUsing(
+ Correspondence.from<
+ PlatformHeartRateRecord.HeartRateSample,
+ PlatformHeartRateRecord.HeartRateSample>(
+ { actual, expected ->
+ actual!!.beatsPerMinute == expected!!.beatsPerMinute &&
+ actual.time == expected.time
+ },
+ "has same BPM and same time as"))
+ .containsExactly(
+ PlatformHeartRateRecord.HeartRateSample(55L, Instant.ofEpochMilli(1234L)),
+ PlatformHeartRateRecord.HeartRateSample(57L, Instant.ofEpochMilli(5678L)))
+ assertThat(metadata.id).isEqualTo("an id")
+ }
+ }
+
+ @Test
+ fun nutritionRecord_convertToPlatform() {
+ val nutrition =
+ NutritionRecord(
+ startTime = Instant.ofEpochMilli(1234L),
+ startZoneOffset = ZoneOffset.UTC,
+ endTime = Instant.ofEpochMilli(5678L),
+ endZoneOffset = ZoneOffset.UTC,
+ caffeine = Mass.grams(20.0),
+ energy = Energy.joules(300.0),
+ metadata = Metadata(id = "another id"))
+
+ val platformNutrition = nutrition.toPlatformRecord() as PlatformNutritionRecord
+ val tolerance = 1.0e-9
+
+ with(platformNutrition) {
+ assertThat(startTime).isEqualTo(Instant.ofEpochMilli(1234L))
+ assertThat(startZoneOffset).isEqualTo(ZoneOffset.UTC)
+ assertThat(endTime).isEqualTo(Instant.ofEpochMilli(5678L))
+ assertThat(endZoneOffset).isEqualTo(ZoneOffset.UTC)
+ assertThat(caffeine!!.inKilograms)
+ .isWithin(tolerance)
+ .of(PlatformMass.fromKilograms(0.02).inKilograms)
+ assertThat(energy!!.inJoules)
+ .isWithin(tolerance)
+ .of(PlatformEnergy.fromJoules(300.0).inJoules)
+ assertThat(metadata.id).isEqualTo("another id")
+ }
+ }
+
+ @Test
+ fun metadata_convertToPlatform() {
+ val metadata =
+ Metadata(
+ id = "someId",
+ dataOrigin = DataOrigin("origin package name"),
+ lastModifiedTime = Instant.ofEpochMilli(6666L),
+ clientRecordId = "clientId",
+ clientRecordVersion = 2L,
+ device =
+ Device(
+ manufacturer = "Awesome-watches",
+ model = "AwesomeOne",
+ type = Device.TYPE_WATCH))
+
+ with(metadata.toPlatformMetadata()) {
+ assertThat(id).isEqualTo("someId")
+ assertThat(dataOrigin)
+ .isEqualTo(
+ PlatformDataOrigin.Builder().setPackageName("origin package name").build())
+ assertThat(clientRecordId).isEqualTo("clientId")
+ assertThat(clientRecordVersion).isEqualTo(2L)
+ assertThat(device)
+ .isEqualTo(
+ PlatformDevice.Builder()
+ .setManufacturer("Awesome-watches")
+ .setModel("AwesomeOne")
+ .setType(PlatformDevice.DEVICE_TYPE_WATCH)
+ .build())
+ }
+ }
+
+ @Test
+ fun metadata_convertToPlatform_noDevice() {
+ val metadata =
+ Metadata(
+ id = "someId",
+ dataOrigin = DataOrigin("origin package name"),
+ lastModifiedTime = Instant.ofEpochMilli(6666L),
+ clientRecordId = "clientId",
+ clientRecordVersion = 2L)
+
+ with(metadata.toPlatformMetadata()) {
+ assertThat(id).isEqualTo("someId")
+ assertThat(dataOrigin)
+ .isEqualTo(
+ PlatformDataOrigin.Builder().setPackageName("origin package name").build())
+ assertThat(clientRecordId).isEqualTo("clientId")
+ assertThat(clientRecordVersion).isEqualTo(2L)
+ assertThat(device).isEqualTo(PlatformDevice.Builder().build())
+ }
+ }
+
+ @Test
+ fun metadata_convertToSdk() {
+ val metadata =
+ PlatformMetadata.Builder()
+ .apply {
+ setId("someId")
+ setDataOrigin(
+ PlatformDataOrigin.Builder().setPackageName("origin package name").build())
+ setLastModifiedTime(Instant.ofEpochMilli(6666L))
+ setClientRecordId("clientId")
+ setClientRecordVersion(2L)
+ setDevice(
+ PlatformDevice.Builder()
+ .setManufacturer("AwesomeTech")
+ .setModel("AwesomeTwo")
+ .setType(PlatformDevice.DEVICE_TYPE_WATCH)
+ .build())
+ }
+ .build()
+
+ with(metadata.toSdkMetadata()) {
+ assertThat(id).isEqualTo("someId")
+ assertThat(dataOrigin).isEqualTo(DataOrigin("origin package name"))
+ assertThat(lastModifiedTime).isEqualTo(Instant.ofEpochMilli(6666L))
+ assertThat(clientRecordId).isEqualTo("clientId")
+ assertThat(clientRecordVersion).isEqualTo(2L)
+ assertThat(device)
+ .isEqualTo(
+ Device(
+ manufacturer = "AwesomeTech",
+ model = "AwesomeTwo",
+ type = Device.TYPE_WATCH))
+ }
+ }
+
+ @Test
+ fun stepsRecord_convertToSdk() {
+ val steps =
+ PlatformStepsRecord.Builder(
+ PlatformMetadata.Builder()
+ .apply {
+ setDevice(
+ PlatformDevice.Builder()
+ .setType(PlatformDevice.DEVICE_TYPE_WATCH)
+ .build())
+ setClientRecordVersion(123L)
+ setDataOrigin(
+ PlatformDataOrigin.Builder()
+ .setPackageName("com.packageName")
+ .build())
+ setLastModifiedTime(Instant.ofEpochMilli(9999L))
+ }
+ .build(),
+ Instant.ofEpochMilli(5678L),
+ Instant.ofEpochMilli(90120L),
+ 200)
+ .build()
+
+ val sdkSteps = steps.toSdkRecord() as StepsRecord
+
+ with(sdkSteps) {
+ assertThat(count).isEqualTo(200)
+ assertThat(startTime).isEqualTo(Instant.ofEpochMilli(5678L))
+ assertThat(endTime).isEqualTo(Instant.ofEpochMilli(90120L))
+
+ with(metadata) {
+ assertThat(device).isEqualTo(Device(type = Device.TYPE_WATCH))
+ assertThat(clientRecordVersion).isEqualTo(123L)
+ assertThat(dataOrigin).isEqualTo(DataOrigin("com.packageName"))
+ }
+ }
+ }
+}
diff --git a/health/connect/connect-client/src/androidTest/java/androidx/health/connect/client/impl/platform/records/RequestConvertersTest.kt b/health/connect/connect-client/src/androidTest/java/androidx/health/connect/client/impl/platform/records/RequestConvertersTest.kt
new file mode 100644
index 0000000..a4bcbe7
--- /dev/null
+++ b/health/connect/connect-client/src/androidTest/java/androidx/health/connect/client/impl/platform/records/RequestConvertersTest.kt
@@ -0,0 +1,206 @@
+/*
+ * Copyright 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.health.connect.client.impl.platform.records
+
+import android.annotation.TargetApi
+import android.health.connect.datatypes.DataOrigin as PlatformDataOrigin
+import android.health.connect.datatypes.HeartRateRecord as PlatformHeartRateRecord
+import android.health.connect.datatypes.NutritionRecord as PlatformNutritionRecord
+import android.health.connect.datatypes.StepsRecord as PlatformStepsRecord
+import android.health.connect.datatypes.WheelchairPushesRecord as PlatformWheelchairPushesRecord
+import android.health.connect.TimeInstantRangeFilter
+import android.os.Build
+import androidx.health.connect.client.impl.platform.time.FakeTimeSource
+import androidx.health.connect.client.impl.platform.time.SystemDefaultTimeSource
+import androidx.health.connect.client.records.HeartRateRecord
+import androidx.health.connect.client.records.NutritionRecord
+import androidx.health.connect.client.records.StepsRecord
+import androidx.health.connect.client.records.WheelchairPushesRecord
+import androidx.health.connect.client.records.metadata.DataOrigin
+import androidx.health.connect.client.request.AggregateGroupByDurationRequest
+import androidx.health.connect.client.request.AggregateGroupByPeriodRequest
+import androidx.health.connect.client.request.AggregateRequest
+import androidx.health.connect.client.request.ChangesTokenRequest
+import androidx.health.connect.client.request.ReadRecordsRequest
+import androidx.health.connect.client.time.TimeRangeFilter
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import androidx.test.filters.SdkSuppress
+import androidx.test.filters.SmallTest
+import com.google.common.truth.Truth.assertThat
+import java.time.Duration
+import java.time.Instant
+import java.time.Period
+import org.junit.Test
+import org.junit.runner.RunWith
+
+@RunWith(AndroidJUnit4::class)
+@OptIn(kotlinx.coroutines.ExperimentalCoroutinesApi::class)
+@SmallTest
+@TargetApi(Build.VERSION_CODES.UPSIDE_DOWN_CAKE)
+// Comment the SDK suppress to run on emulators lower than U.
+@SdkSuppress(minSdkVersion = Build.VERSION_CODES.UPSIDE_DOWN_CAKE, codeName = "UpsideDownCake")
+class RequestConvertersTest {
+
+ @Test
+ fun readRecordsRequest_fromSdkToPlatform() {
+ val sdkRequest =
+ ReadRecordsRequest(
+ StepsRecord::class,
+ TimeRangeFilter.between(Instant.ofEpochMilli(123L), Instant.ofEpochMilli(456L)),
+ setOf(DataOrigin("package1"), DataOrigin("package2")))
+
+ with(sdkRequest.toPlatformRequest(SystemDefaultTimeSource)) {
+ assertThat(recordType).isAssignableTo(PlatformStepsRecord::class.java)
+ assertThat(dataOrigins)
+ .containsExactly(
+ PlatformDataOrigin.Builder().setPackageName("package1").build(),
+ PlatformDataOrigin.Builder().setPackageName("package2").build())
+ }
+ }
+
+ @Test
+ fun timeRangeFilter_fromSdkToPlatform() {
+ val sdkFilter =
+ TimeRangeFilter.between(Instant.ofEpochMilli(123L), Instant.ofEpochMilli(456L))
+
+ with(sdkFilter.toPlatformTimeRangeFilter(SystemDefaultTimeSource)) {
+ assertThat(startTime).isEqualTo(Instant.ofEpochMilli(123L))
+ assertThat(endTime).isEqualTo(Instant.ofEpochMilli(456L))
+ }
+ }
+
+ @Test
+ fun timeRangeFilter_fromSdkToPlatform_none() {
+ val timeSource = FakeTimeSource()
+ timeSource.now = Instant.ofEpochMilli(123L)
+
+ val sdkFilter = TimeRangeFilter.none()
+
+ with(sdkFilter.toPlatformTimeRangeFilter(timeSource)) {
+ assertThat(startTime).isEqualTo(Instant.EPOCH)
+ assertThat(endTime).isEqualTo(Instant.ofEpochMilli(123L))
+ }
+ }
+
+ @Test
+ fun changesTokenRequest_fromSdkToPlatform() {
+ val sdkRequest =
+ ChangesTokenRequest(
+ setOf(StepsRecord::class, HeartRateRecord::class),
+ setOf(DataOrigin("package1"), DataOrigin("package2")))
+
+ with(sdkRequest.toPlatformRequest()) {
+ assertThat(recordTypes)
+ .containsExactly(
+ PlatformStepsRecord::class.java, PlatformHeartRateRecord::class.java)
+ assertThat(dataOriginFilters)
+ .containsExactly(
+ PlatformDataOrigin.Builder().setPackageName("package1").build(),
+ PlatformDataOrigin.Builder().setPackageName("package2").build())
+ }
+ }
+
+ @Test
+ fun aggregateRequest_fromSdkToPlatform() {
+ val sdkRequest =
+ AggregateRequest(
+ setOf(StepsRecord.COUNT_TOTAL, NutritionRecord.CAFFEINE_TOTAL),
+ TimeRangeFilter.between(Instant.ofEpochMilli(123L), Instant.ofEpochMilli(456L)),
+ setOf(DataOrigin("package1")))
+
+ with(sdkRequest.toPlatformRequest(SystemDefaultTimeSource)) {
+ with(timeRangeFilter as TimeInstantRangeFilter) {
+ assertThat(startTime).isEqualTo(Instant.ofEpochMilli(123L))
+ assertThat(endTime).isEqualTo(Instant.ofEpochMilli(456L))
+ }
+ assertThat(aggregationTypes)
+ .containsExactly(
+ PlatformStepsRecord.STEPS_COUNT_TOTAL, PlatformNutritionRecord.CAFFEINE_TOTAL)
+ assertThat(dataOriginsFilters)
+ .containsExactly(PlatformDataOrigin.Builder().setPackageName("package1").build())
+ }
+ }
+
+ @Test
+ fun aggregateGroupByDurationRequest_fromSdkToPlatform() {
+ val sdkRequest =
+ AggregateGroupByDurationRequest(
+ setOf(NutritionRecord.ENERGY_TOTAL),
+ TimeRangeFilter.between(Instant.ofEpochMilli(123L), Instant.ofEpochMilli(456L)),
+ Duration.ofDays(1),
+ setOf(DataOrigin("package1"), DataOrigin("package2")))
+
+ with(sdkRequest.toPlatformRequest(SystemDefaultTimeSource)) {
+ with(timeRangeFilter as TimeInstantRangeFilter) {
+ assertThat(startTime).isEqualTo(Instant.ofEpochMilli(123L))
+ assertThat(endTime).isEqualTo(Instant.ofEpochMilli(456L))
+ }
+ assertThat(aggregationTypes).containsExactly(PlatformNutritionRecord.ENERGY_TOTAL)
+ assertThat(dataOriginsFilters)
+ .containsExactly(
+ PlatformDataOrigin.Builder().setPackageName("package1").build(),
+ PlatformDataOrigin.Builder().setPackageName("package2").build())
+ }
+ }
+
+ @Test
+ fun aggregateGroupByPeriodRequest_fromSdkToPlatform() {
+ val sdkRequest =
+ AggregateGroupByPeriodRequest(
+ setOf(HeartRateRecord.BPM_MAX, HeartRateRecord.BPM_MIN, HeartRateRecord.BPM_AVG),
+ TimeRangeFilter.between(Instant.ofEpochMilli(123L), Instant.ofEpochMilli(456L)),
+ Period.ofDays(1),
+ setOf(DataOrigin("package1"), DataOrigin("package2"), DataOrigin("package3")))
+
+ with(sdkRequest.toPlatformRequest(SystemDefaultTimeSource)) {
+ with(timeRangeFilter as TimeInstantRangeFilter) {
+ assertThat(startTime).isEqualTo(Instant.ofEpochMilli(123L))
+ assertThat(endTime).isEqualTo(Instant.ofEpochMilli(456L))
+ }
+ assertThat(aggregationTypes)
+ .containsExactly(
+ PlatformHeartRateRecord.BPM_MAX,
+ PlatformHeartRateRecord.BPM_MIN,
+ PlatformHeartRateRecord.BPM_AVG)
+ assertThat(dataOriginsFilters)
+ .containsExactly(
+ PlatformDataOrigin.Builder().setPackageName("package1").build(),
+ PlatformDataOrigin.Builder().setPackageName("package2").build(),
+ PlatformDataOrigin.Builder().setPackageName("package3").build())
+ }
+ }
+
+ @Test
+ fun aggregateMetric_fromSdkToPlatformAggregationType() {
+ assertThat(WheelchairPushesRecord.COUNT_TOTAL.toAggregationType())
+ .isEqualTo(PlatformWheelchairPushesRecord.WHEEL_CHAIR_PUSHES_COUNT_TOTAL)
+ assertThat(NutritionRecord.ENERGY_TOTAL.toAggregationType())
+ .isEqualTo(PlatformNutritionRecord.ENERGY_TOTAL)
+ }
+
+ @Test
+ fun aggregateMetric_isLongAggregationType() {
+ assertThat(WheelchairPushesRecord.COUNT_TOTAL.isLongAggregationType()).isTrue()
+ assertThat(NutritionRecord.ENERGY_TOTAL.isLongAggregationType()).isFalse()
+ }
+
+ @Test
+ fun aggregateMetric_isDoubleAggregationType() {
+ assertThat(NutritionRecord.ENERGY_TOTAL.isDoubleAggregationType()).isTrue()
+ assertThat(WheelchairPushesRecord.COUNT_TOTAL.isDoubleAggregationType()).isFalse()
+ }
+}
diff --git a/health/connect/connect-client/src/androidTest/java/androidx/health/connect/client/impl/platform/time/FakeTimeSource.kt b/health/connect/connect-client/src/androidTest/java/androidx/health/connect/client/impl/platform/time/FakeTimeSource.kt
new file mode 100644
index 0000000..270eaf4
--- /dev/null
+++ b/health/connect/connect-client/src/androidTest/java/androidx/health/connect/client/impl/platform/time/FakeTimeSource.kt
@@ -0,0 +1,26 @@
+/*
+ * Copyright 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.health.connect.client.impl.platform.time
+
+import android.os.Build
+import androidx.annotation.RequiresApi
+import java.time.Instant
+
+@RequiresApi(api = Build.VERSION_CODES.UPSIDE_DOWN_CAKE)
+class FakeTimeSource : TimeSource {
+ override lateinit var now: Instant
+}
\ No newline at end of file
diff --git a/health/connect/connect-client/src/main/java/androidx/health/connect/client/PermissionController.kt b/health/connect/connect-client/src/main/java/androidx/health/connect/client/PermissionController.kt
index 1be95806..bff2c17 100644
--- a/health/connect/connect-client/src/main/java/androidx/health/connect/client/PermissionController.kt
+++ b/health/connect/connect-client/src/main/java/androidx/health/connect/client/PermissionController.kt
@@ -15,10 +15,13 @@
*/
package androidx.health.connect.client
+import android.os.Build.VERSION
+import android.os.Build.VERSION_CODES
import androidx.activity.result.contract.ActivityResultContract
import androidx.health.connect.client.HealthConnectClient.Companion.DEFAULT_PROVIDER_PACKAGE_NAME
import androidx.health.connect.client.permission.HealthDataRequestPermissionsInternal
import androidx.health.connect.client.permission.HealthPermission
+import androidx.health.connect.client.permission.platform.HealthDataRequestPermissionsUpsideDownCake
@JvmDefaultWithCompatibility
/** Interface for operations related to permissions. */
@@ -58,7 +61,12 @@
fun createRequestPermissionResultContract(
providerPackageName: String = DEFAULT_PROVIDER_PACKAGE_NAME
): ActivityResultContract<Set<String>, Set<String>> {
- return HealthDataRequestPermissionsInternal(providerPackageName = providerPackageName)
+ if (VERSION.SDK_INT < VERSION_CODES.UPSIDE_DOWN_CAKE) {
+ return HealthDataRequestPermissionsInternal(
+ providerPackageName = providerPackageName
+ )
+ }
+ return HealthDataRequestPermissionsUpsideDownCake()
}
}
}
diff --git a/health/connect/connect-client/src/main/java/androidx/health/connect/client/impl/HealthConnectClientUpsideDownImpl.kt b/health/connect/connect-client/src/main/java/androidx/health/connect/client/impl/HealthConnectClientUpsideDownImpl.kt
new file mode 100644
index 0000000..04721f2
--- /dev/null
+++ b/health/connect/connect-client/src/main/java/androidx/health/connect/client/impl/HealthConnectClientUpsideDownImpl.kt
@@ -0,0 +1,330 @@
+/*
+ * Copyright 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.health.connect.client.impl
+
+import android.content.Context
+import android.content.pm.PackageInfo.REQUESTED_PERMISSION_GRANTED
+import android.content.pm.PackageManager.GET_PERMISSIONS
+import android.content.pm.PackageManager.PackageInfoFlags
+import android.health.connect.ChangeLogsRequest
+import android.health.connect.HealthConnectException
+import android.health.connect.HealthConnectManager
+import android.health.connect.ReadRecordsRequestUsingIds
+import android.health.connect.RecordIdFilter
+import android.os.Build
+import android.os.RemoteException
+import androidx.annotation.RequiresApi
+import androidx.annotation.VisibleForTesting
+import androidx.core.os.asOutcomeReceiver
+import androidx.health.connect.client.HealthConnectClient
+import androidx.health.connect.client.PermissionController
+import androidx.health.connect.client.aggregate.AggregationResult
+import androidx.health.connect.client.aggregate.AggregationResultGroupedByDuration
+import androidx.health.connect.client.aggregate.AggregationResultGroupedByPeriod
+import androidx.health.connect.client.changes.DeletionChange
+import androidx.health.connect.client.changes.UpsertionChange
+import androidx.health.connect.client.impl.platform.records.toPlatformRecord
+import androidx.health.connect.client.impl.platform.records.toPlatformRecordClass
+import androidx.health.connect.client.impl.platform.records.toPlatformRequest
+import androidx.health.connect.client.impl.platform.records.toPlatformTimeRangeFilter
+import androidx.health.connect.client.impl.platform.records.toSdkRecord
+import androidx.health.connect.client.impl.platform.records.toSdkResponse
+import androidx.health.connect.client.impl.platform.response.toKtResponse
+import androidx.health.connect.client.impl.platform.time.SystemDefaultTimeSource
+import androidx.health.connect.client.impl.platform.time.TimeSource
+import androidx.health.connect.client.impl.platform.toKtException
+import androidx.health.connect.client.permission.HealthPermission.Companion.PERMISSION_PREFIX
+import androidx.health.connect.client.records.Record
+import androidx.health.connect.client.request.AggregateGroupByDurationRequest
+import androidx.health.connect.client.request.AggregateGroupByPeriodRequest
+import androidx.health.connect.client.request.AggregateRequest
+import androidx.health.connect.client.request.ChangesTokenRequest
+import androidx.health.connect.client.request.ReadRecordsRequest
+import androidx.health.connect.client.response.ChangesResponse
+import androidx.health.connect.client.response.InsertRecordsResponse
+import androidx.health.connect.client.response.ReadRecordResponse
+import androidx.health.connect.client.response.ReadRecordsResponse
+import androidx.health.connect.client.time.TimeRangeFilter
+import kotlin.reflect.KClass
+import kotlinx.coroutines.suspendCancellableCoroutine
+
+/**
+ * Implements the [HealthConnectClient] with APIs in UpsideDownCake.
+ *
+ * @suppress
+ */
+@RequiresApi(api = Build.VERSION_CODES.UPSIDE_DOWN_CAKE)
+class HealthConnectClientUpsideDownImpl : HealthConnectClient, PermissionController {
+
+ private val context: Context
+ private val timeSource: TimeSource
+ private val healthConnectManager: HealthConnectManager
+ private val revokePermissionsFunction: (Collection<String>) -> Unit
+
+ constructor(
+ context: Context
+ ) : this(context, SystemDefaultTimeSource, context::revokeSelfPermissionsOnKill)
+
+ @VisibleForTesting
+ internal constructor(
+ context: Context,
+ timeSource: TimeSource,
+ revokePermissionsFunction: (Collection<String>) -> Unit
+ ) {
+ this.context = context
+ this.timeSource = timeSource
+ this.healthConnectManager =
+ context.getSystemService(Context.HEALTHCONNECT_SERVICE) as HealthConnectManager
+ this.revokePermissionsFunction = revokePermissionsFunction
+ }
+
+ override val permissionController: PermissionController
+ get() = this
+
+ override suspend fun insertRecords(records: List<Record>): InsertRecordsResponse {
+ val response = wrapPlatformException {
+ suspendCancellableCoroutine { continuation ->
+ healthConnectManager.insertRecords(
+ records.map { it.toPlatformRecord() },
+ Runnable::run,
+ continuation.asOutcomeReceiver()
+ )
+ }
+ }
+ return response.toKtResponse()
+ }
+
+ override suspend fun updateRecords(records: List<Record>) {
+ wrapPlatformException {
+ suspendCancellableCoroutine { continuation ->
+ healthConnectManager.updateRecords(
+ records.map { it.toPlatformRecord() },
+ Runnable::run,
+ continuation.asOutcomeReceiver()
+ )
+ }
+ }
+ }
+
+ override suspend fun deleteRecords(
+ recordType: KClass<out Record>,
+ recordIdsList: List<String>,
+ clientRecordIdsList: List<String>
+ ) {
+ wrapPlatformException {
+ suspendCancellableCoroutine { continuation ->
+ healthConnectManager.deleteRecords(
+ buildList {
+ recordIdsList.forEach {
+ add(RecordIdFilter.fromId(recordType.toPlatformRecordClass(), it))
+ }
+ clientRecordIdsList.forEach {
+ add(
+ RecordIdFilter.fromClientRecordId(
+ recordType.toPlatformRecordClass(),
+ it
+ )
+ )
+ }
+ },
+ Runnable::run,
+ continuation.asOutcomeReceiver()
+ )
+ }
+ }
+ }
+
+ override suspend fun deleteRecords(
+ recordType: KClass<out Record>,
+ timeRangeFilter: TimeRangeFilter
+ ) {
+ wrapPlatformException {
+ suspendCancellableCoroutine { continuation ->
+ healthConnectManager.deleteRecords(
+ recordType.toPlatformRecordClass(),
+ timeRangeFilter.toPlatformTimeRangeFilter(timeSource),
+ Runnable::run,
+ continuation.asOutcomeReceiver()
+ )
+ }
+ }
+ }
+
+ @Suppress("UNCHECKED_CAST") // Safe to cast as the type should match
+ override suspend fun <T : Record> readRecord(
+ recordType: KClass<T>,
+ recordId: String
+ ): ReadRecordResponse<T> {
+ val response = wrapPlatformException {
+ suspendCancellableCoroutine { continuation ->
+ healthConnectManager.readRecords(
+ ReadRecordsRequestUsingIds.Builder(recordType.toPlatformRecordClass())
+ .addId(recordId)
+ .build(),
+ Runnable::run,
+ continuation.asOutcomeReceiver()
+ )
+ }
+ }
+ if (response.records.isEmpty()) {
+ throw RemoteException("No records")
+ }
+ return ReadRecordResponse(response.records[0].toSdkRecord() as T)
+ }
+
+ @Suppress("UNCHECKED_CAST") // Safe to cast as the type should match
+ override suspend fun <T : Record> readRecords(
+ request: ReadRecordsRequest<T>
+ ): ReadRecordsResponse<T> {
+ val response = wrapPlatformException {
+ suspendCancellableCoroutine { continuation ->
+ healthConnectManager.readRecords(
+ request.toPlatformRequest(timeSource),
+ Runnable::run,
+ continuation.asOutcomeReceiver()
+ )
+ }
+ }
+ // TODO(b/262573513): pass page token
+ return ReadRecordsResponse(response.records.map { it.toSdkRecord() as T }, null)
+ }
+
+ override suspend fun aggregate(request: AggregateRequest): AggregationResult {
+ return wrapPlatformException {
+ suspendCancellableCoroutine { continuation ->
+ healthConnectManager.aggregate(
+ request.toPlatformRequest(timeSource),
+ Runnable::run,
+ continuation.asOutcomeReceiver()
+ )
+ }
+ }
+ .toSdkResponse(request.metrics)
+ }
+
+ override suspend fun aggregateGroupByDuration(
+ request: AggregateGroupByDurationRequest
+ ): List<AggregationResultGroupedByDuration> {
+ return wrapPlatformException {
+ suspendCancellableCoroutine { continuation ->
+ healthConnectManager.aggregateGroupByDuration(
+ request.toPlatformRequest(timeSource),
+ request.timeRangeSlicer,
+ Runnable::run,
+ continuation.asOutcomeReceiver()
+ )
+ }
+ }
+ .map { it.toSdkResponse(request.metrics) }
+ }
+
+ override suspend fun aggregateGroupByPeriod(
+ request: AggregateGroupByPeriodRequest
+ ): List<AggregationResultGroupedByPeriod> {
+ return wrapPlatformException {
+ suspendCancellableCoroutine { continuation ->
+ healthConnectManager.aggregateGroupByPeriod(
+ request.toPlatformRequest(timeSource),
+ request.timeRangeSlicer,
+ Runnable::run,
+ continuation.asOutcomeReceiver()
+ )
+ }
+ }
+ .map { it.toSdkResponse(request.metrics) }
+ }
+
+ override suspend fun getChangesToken(request: ChangesTokenRequest): String {
+ return wrapPlatformException {
+ suspendCancellableCoroutine { continuation ->
+ healthConnectManager.getChangeLogToken(
+ request.toPlatformRequest(),
+ Runnable::run,
+ continuation.asOutcomeReceiver()
+ )
+ }
+ }
+ .token
+ }
+
+ override suspend fun registerForDataNotifications(
+ notificationIntentAction: String,
+ recordTypes: Iterable<KClass<out Record>>
+ ) {
+ throw UnsupportedOperationException("Method not supported yet")
+ }
+
+ override suspend fun unregisterFromDataNotifications(notificationIntentAction: String) {
+ throw UnsupportedOperationException("Method not supported yet")
+ }
+
+ override suspend fun getChanges(changesToken: String): ChangesResponse {
+ val response = wrapPlatformException {
+ suspendCancellableCoroutine { continuation ->
+ healthConnectManager.getChangeLogs(
+ ChangeLogsRequest.Builder(changesToken).build(),
+ Runnable::run,
+ continuation.asOutcomeReceiver()
+ )
+ }
+ }
+ // TODO(b/263472286) revisit changesTokenExpired field in the constructor
+ return ChangesResponse(
+ buildList {
+ response.upsertedRecords.forEach { add(UpsertionChange(it.toSdkRecord())) }
+ response.deletedLogs.forEach { add(DeletionChange(it.deletedRecordId)) }
+ },
+ response.nextChangesToken,
+ response.hasMorePages(),
+ changesTokenExpired = true
+ )
+ }
+
+ override suspend fun getGrantedPermissions(): Set<String> {
+ context.packageManager
+ .getPackageInfo(context.packageName, PackageInfoFlags.of(GET_PERMISSIONS.toLong()))
+ .let {
+ return buildSet {
+ for (i in it.requestedPermissions.indices) {
+ if (
+ it.requestedPermissions[i].startsWith(PERMISSION_PREFIX) &&
+ it.requestedPermissionsFlags[i] and REQUESTED_PERMISSION_GRANTED > 0
+ ) {
+ add(it.requestedPermissions[i])
+ }
+ }
+ }
+ }
+ }
+
+ override suspend fun revokeAllPermissions() {
+ val allHealthPermissions =
+ context.packageManager
+ .getPackageInfo(context.packageName, PackageInfoFlags.of(GET_PERMISSIONS.toLong()))
+ .requestedPermissions
+ .filter { it.startsWith(PERMISSION_PREFIX) }
+ revokePermissionsFunction(allHealthPermissions)
+ }
+
+ private suspend fun <T> wrapPlatformException(function: suspend () -> T): T {
+ return try {
+ function()
+ } catch (e: HealthConnectException) {
+ throw e.toKtException()
+ }
+ }
+}
diff --git a/health/connect/connect-client/src/main/java/androidx/health/connect/client/impl/platform/ExceptionConverter.kt b/health/connect/connect-client/src/main/java/androidx/health/connect/client/impl/platform/ExceptionConverter.kt
new file mode 100644
index 0000000..624ef1c
--- /dev/null
+++ b/health/connect/connect-client/src/main/java/androidx/health/connect/client/impl/platform/ExceptionConverter.kt
@@ -0,0 +1,38 @@
+/*
+ * Copyright 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+@file:RequiresApi(api = Build.VERSION_CODES.UPSIDE_DOWN_CAKE)
+
+package androidx.health.connect.client.impl.platform
+
+import android.health.connect.HealthConnectException
+import android.os.Build
+import android.os.RemoteException
+import androidx.annotation.RequiresApi
+import java.io.IOException
+import java.lang.IllegalArgumentException
+import java.lang.IllegalStateException
+
+/** Converts exception returned by the platform to one of standard exception class hierarchy. */
+internal fun HealthConnectException.toKtException(): Exception {
+ return when (errorCode) {
+ HealthConnectException.ERROR_IO -> IOException(message)
+ HealthConnectException.ERROR_REMOTE -> RemoteException(message)
+ HealthConnectException.ERROR_SECURITY -> SecurityException(message)
+ HealthConnectException.ERROR_INVALID_ARGUMENT -> IllegalArgumentException(message)
+ else -> IllegalStateException(message)
+ }
+}
diff --git a/appsearch/appsearch/src/main/java/androidx/appsearch/observer/AppSearchObserverCallback.java b/health/connect/connect-client/src/main/java/androidx/health/connect/client/impl/platform/package-info.java
similarity index 62%
rename from appsearch/appsearch/src/main/java/androidx/appsearch/observer/AppSearchObserverCallback.java
rename to health/connect/connect-client/src/main/java/androidx/health/connect/client/impl/platform/package-info.java
index c01917e..dc32f56 100644
--- a/appsearch/appsearch/src/main/java/androidx/appsearch/observer/AppSearchObserverCallback.java
+++ b/health/connect/connect-client/src/main/java/androidx/health/connect/client/impl/platform/package-info.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2021 The Android Open Source Project
+ * Copyright (C) 2022 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -14,15 +14,12 @@
* limitations under the License.
*/
-package androidx.appsearch.observer;
-
-import androidx.annotation.RestrictTo;
-
/**
- * @deprecated use {@link ObserverCallback} instead.
+ * Helps with conversions to the platform record and API objects.
+ *
* @hide
*/
-// TODO(b/209734214): Remove this after dogfooders and devices have migrated away from this class.
-@Deprecated
-@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
-public interface AppSearchObserverCallback extends ObserverCallback {}
+@RestrictTo(RestrictTo.Scope.LIBRARY)
+package androidx.health.connect.client.impl.platform;
+
+import androidx.annotation.RestrictTo;
diff --git a/health/connect/connect-client/src/main/java/androidx/health/connect/client/impl/platform/records/RecordMappings.kt b/health/connect/connect-client/src/main/java/androidx/health/connect/client/impl/platform/records/RecordMappings.kt
new file mode 100644
index 0000000..b92c6b7
--- /dev/null
+++ b/health/connect/connect-client/src/main/java/androidx/health/connect/client/impl/platform/records/RecordMappings.kt
@@ -0,0 +1,149 @@
+/*
+ * Copyright 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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:RestrictTo(RestrictTo.Scope.LIBRARY)
+@file:RequiresApi(api = Build.VERSION_CODES.UPSIDE_DOWN_CAKE)
+
+package androidx.health.connect.client.impl.platform.records
+
+import android.health.connect.datatypes.ActiveCaloriesBurnedRecord as PlatformActiveCaloriesBurnedRecord
+import android.health.connect.datatypes.BasalBodyTemperatureRecord as PlatformBasalBodyTemperatureRecord
+import android.health.connect.datatypes.BasalMetabolicRateRecord as PlatformBasalMetabolicRateRecord
+import android.health.connect.datatypes.BloodGlucoseRecord as PlatformBloodGlucoseRecord
+import android.health.connect.datatypes.BloodPressureRecord as PlatformBloodPressureRecord
+import android.health.connect.datatypes.BodyFatRecord as PlatformBodyFatRecord
+import android.health.connect.datatypes.BodyTemperatureRecord as PlatformBodyTemperatureRecord
+import android.health.connect.datatypes.BodyWaterMassRecord as PlatformBodyWaterMassRecord
+import android.health.connect.datatypes.BoneMassRecord as PlatformBoneMassRecord
+import android.health.connect.datatypes.CervicalMucusRecord as PlatformCervicalMucusRecord
+import android.health.connect.datatypes.CyclingPedalingCadenceRecord as PlatformCyclingPedalingCadenceRecord
+import android.health.connect.datatypes.DistanceRecord as PlatformDistanceRecord
+import android.health.connect.datatypes.ElevationGainedRecord as PlatformElevationGainedRecord
+import android.health.connect.datatypes.ExerciseSessionRecord as PlatformExerciseSessionRecord
+import android.health.connect.datatypes.FloorsClimbedRecord as PlatformFloorsClimbedRecord
+import android.health.connect.datatypes.HeartRateRecord as PlatformHeartRateRecord
+import android.health.connect.datatypes.HeartRateVariabilityRmssdRecord as PlatformHeartRateVariabilityRmssdRecord
+import android.health.connect.datatypes.HeightRecord as PlatformHeightRecord
+import android.health.connect.datatypes.HydrationRecord as PlatformHydrationRecord
+import android.health.connect.datatypes.IntermenstrualBleedingRecord as PlatformIntermenstrualBleedingRecord
+import android.health.connect.datatypes.IntervalRecord as PlatformIntervalRecord
+import android.health.connect.datatypes.LeanBodyMassRecord as PlatformLeanBodyMassRecord
+import android.health.connect.datatypes.MenstruationFlowRecord as PlatformMenstruationFlowRecord
+import android.health.connect.datatypes.MenstruationPeriodRecord as PlatformMenstruationPeriodRecord
+import android.health.connect.datatypes.NutritionRecord as PlatformNutritionRecord
+import android.health.connect.datatypes.OvulationTestRecord as PlatformOvulationTestRecord
+import android.health.connect.datatypes.OxygenSaturationRecord as PlatformOxygenSaturationRecord
+import android.health.connect.datatypes.PowerRecord as PlatformPowerRecord
+import android.health.connect.datatypes.Record as PlatformRecord
+import android.health.connect.datatypes.RespiratoryRateRecord as PlatformRespiratoryRateRecord
+import android.health.connect.datatypes.RestingHeartRateRecord as PlatformRestingHeartRateRecord
+import android.health.connect.datatypes.SexualActivityRecord as PlatformSexualActivityRecord
+import android.health.connect.datatypes.SleepSessionRecord as PlatformSleepSessionRecord
+import android.health.connect.datatypes.SpeedRecord as PlatformSpeedRecord
+import android.health.connect.datatypes.StepsCadenceRecord as PlatformStepsCadenceRecord
+import android.health.connect.datatypes.StepsRecord as PlatformStepsRecord
+import android.health.connect.datatypes.TotalCaloriesBurnedRecord as PlatformTotalCaloriesBurnedRecord
+import android.health.connect.datatypes.Vo2MaxRecord as PlatformVo2MaxRecord
+import android.health.connect.datatypes.WeightRecord as PlatformWeightRecord
+import android.health.connect.datatypes.WheelchairPushesRecord as PlatformWheelchairPushesRecord
+import android.os.Build
+import androidx.annotation.RequiresApi
+import androidx.annotation.RestrictTo
+import androidx.health.connect.client.records.ActiveCaloriesBurnedRecord
+import androidx.health.connect.client.records.BasalBodyTemperatureRecord
+import androidx.health.connect.client.records.BasalMetabolicRateRecord
+import androidx.health.connect.client.records.BloodGlucoseRecord
+import androidx.health.connect.client.records.BloodPressureRecord
+import androidx.health.connect.client.records.BodyFatRecord
+import androidx.health.connect.client.records.BodyTemperatureRecord
+import androidx.health.connect.client.records.BodyWaterMassRecord
+import androidx.health.connect.client.records.BoneMassRecord
+import androidx.health.connect.client.records.CervicalMucusRecord
+import androidx.health.connect.client.records.CyclingPedalingCadenceRecord
+import androidx.health.connect.client.records.DistanceRecord
+import androidx.health.connect.client.records.ElevationGainedRecord
+import androidx.health.connect.client.records.ExerciseSessionRecord
+import androidx.health.connect.client.records.FloorsClimbedRecord
+import androidx.health.connect.client.records.HeartRateRecord
+import androidx.health.connect.client.records.HeartRateVariabilityRmssdRecord
+import androidx.health.connect.client.records.HeightRecord
+import androidx.health.connect.client.records.HydrationRecord
+import androidx.health.connect.client.records.IntermenstrualBleedingRecord
+import androidx.health.connect.client.records.IntervalRecord
+import androidx.health.connect.client.records.LeanBodyMassRecord
+import androidx.health.connect.client.records.MenstruationFlowRecord
+import androidx.health.connect.client.records.MenstruationPeriodRecord
+import androidx.health.connect.client.records.NutritionRecord
+import androidx.health.connect.client.records.OvulationTestRecord
+import androidx.health.connect.client.records.OxygenSaturationRecord
+import androidx.health.connect.client.records.PowerRecord
+import androidx.health.connect.client.records.Record
+import androidx.health.connect.client.records.RespiratoryRateRecord
+import androidx.health.connect.client.records.RestingHeartRateRecord
+import androidx.health.connect.client.records.SexualActivityRecord
+import androidx.health.connect.client.records.SleepSessionRecord
+import androidx.health.connect.client.records.SpeedRecord
+import androidx.health.connect.client.records.StepsCadenceRecord
+import androidx.health.connect.client.records.StepsRecord
+import androidx.health.connect.client.records.TotalCaloriesBurnedRecord
+import androidx.health.connect.client.records.Vo2MaxRecord
+import androidx.health.connect.client.records.WeightRecord
+import androidx.health.connect.client.records.WheelchairPushesRecord
+import kotlin.reflect.KClass
+
+internal val SDK_TO_PLATFORM_RECORD_CLASS: Map<KClass<out Record>, Class<out PlatformRecord>> =
+ mapOf(
+ ActiveCaloriesBurnedRecord::class to PlatformActiveCaloriesBurnedRecord::class.java,
+ BasalBodyTemperatureRecord::class to PlatformBasalBodyTemperatureRecord::class.java,
+ BasalMetabolicRateRecord::class to PlatformBasalMetabolicRateRecord::class.java,
+ BloodGlucoseRecord::class to PlatformBloodGlucoseRecord::class.java,
+ BloodPressureRecord::class to PlatformBloodPressureRecord::class.java,
+ BodyFatRecord::class to PlatformBodyFatRecord::class.java,
+ BodyTemperatureRecord::class to PlatformBodyTemperatureRecord::class.java,
+ BodyWaterMassRecord::class to PlatformBodyWaterMassRecord::class.java,
+ BoneMassRecord::class to PlatformBoneMassRecord::class.java,
+ CervicalMucusRecord::class to PlatformCervicalMucusRecord::class.java,
+ CyclingPedalingCadenceRecord::class to PlatformCyclingPedalingCadenceRecord::class.java,
+ DistanceRecord::class to PlatformDistanceRecord::class.java,
+ ElevationGainedRecord::class to PlatformElevationGainedRecord::class.java,
+ ExerciseSessionRecord::class to PlatformExerciseSessionRecord::class.java,
+ FloorsClimbedRecord::class to PlatformFloorsClimbedRecord::class.java,
+ HeartRateRecord::class to PlatformHeartRateRecord::class.java,
+ HeartRateVariabilityRmssdRecord::class to
+ PlatformHeartRateVariabilityRmssdRecord::class.java,
+ HeightRecord::class to PlatformHeightRecord::class.java,
+ HydrationRecord::class to PlatformHydrationRecord::class.java,
+ IntermenstrualBleedingRecord::class to PlatformIntermenstrualBleedingRecord::class.java,
+ IntervalRecord::class to PlatformIntervalRecord::class.java,
+ LeanBodyMassRecord::class to PlatformLeanBodyMassRecord::class.java,
+ MenstruationFlowRecord::class to PlatformMenstruationFlowRecord::class.java,
+ MenstruationPeriodRecord::class to PlatformMenstruationPeriodRecord::class.java,
+ NutritionRecord::class to PlatformNutritionRecord::class.java,
+ OvulationTestRecord::class to PlatformOvulationTestRecord::class.java,
+ OxygenSaturationRecord::class to PlatformOxygenSaturationRecord::class.java,
+ PowerRecord::class to PlatformPowerRecord::class.java,
+ RespiratoryRateRecord::class to PlatformRespiratoryRateRecord::class.java,
+ RestingHeartRateRecord::class to PlatformRestingHeartRateRecord::class.java,
+ SexualActivityRecord::class to PlatformSexualActivityRecord::class.java,
+ SleepSessionRecord::class to PlatformSleepSessionRecord::class.java,
+ SpeedRecord::class to PlatformSpeedRecord::class.java,
+ StepsCadenceRecord::class to PlatformStepsCadenceRecord::class.java,
+ StepsRecord::class to PlatformStepsRecord::class.java,
+ TotalCaloriesBurnedRecord::class to PlatformTotalCaloriesBurnedRecord::class.java,
+ Vo2MaxRecord::class to PlatformVo2MaxRecord::class.java,
+ WeightRecord::class to PlatformWeightRecord::class.java,
+ WheelchairPushesRecord::class to PlatformWheelchairPushesRecord::class.java,
+ )
diff --git a/health/connect/connect-client/src/main/java/androidx/health/connect/client/impl/platform/records/RecordsConverters.kt b/health/connect/connect-client/src/main/java/androidx/health/connect/client/impl/platform/records/RecordsConverters.kt
new file mode 100644
index 0000000..020fce4
--- /dev/null
+++ b/health/connect/connect-client/src/main/java/androidx/health/connect/client/impl/platform/records/RecordsConverters.kt
@@ -0,0 +1,153 @@
+/*
+ * Copyright 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+@file:RestrictTo(RestrictTo.Scope.LIBRARY)
+@file:RequiresApi(api = Build.VERSION_CODES.UPSIDE_DOWN_CAKE)
+
+package androidx.health.connect.client.impl.platform.records
+
+import android.health.connect.datatypes.DataOrigin as PlatformDataOrigin
+import android.health.connect.datatypes.Device as PlatformDevice
+import android.health.connect.datatypes.HeartRateRecord as PlatformHeartRateRecord
+import android.health.connect.datatypes.Metadata as PlatformMetadata
+import android.health.connect.datatypes.NutritionRecord as PlatformNutritionRecord
+import android.health.connect.datatypes.Record as PlatformRecord
+import android.health.connect.datatypes.StepsRecord as PlatformStepsRecord
+import android.health.connect.datatypes.units.Energy as PlatformEnergy
+import android.health.connect.datatypes.units.Mass as PlatformMass
+import android.os.Build
+import androidx.annotation.RequiresApi
+import androidx.annotation.RestrictTo
+import androidx.annotation.VisibleForTesting
+import androidx.health.connect.client.records.HeartRateRecord
+import androidx.health.connect.client.records.NutritionRecord
+import androidx.health.connect.client.records.Record
+import androidx.health.connect.client.records.StepsRecord
+import androidx.health.connect.client.records.metadata.DataOrigin
+import androidx.health.connect.client.records.metadata.Device
+import androidx.health.connect.client.records.metadata.Metadata
+import androidx.health.connect.client.units.Energy
+import androidx.health.connect.client.units.Mass
+import kotlin.reflect.KClass
+
+fun KClass<out Record>.toPlatformRecordClass(): Class<out PlatformRecord> {
+ return SDK_TO_PLATFORM_RECORD_CLASS[this]
+ ?: throw IllegalArgumentException("Unsupported record type $this")
+}
+
+fun Record.toPlatformRecord(): PlatformRecord {
+ return when (this) {
+ is StepsRecord ->
+ PlatformStepsRecord.Builder(metadata.toPlatformMetadata(), startTime, endTime, count)
+ .apply {
+ startZoneOffset?.let { setStartZoneOffset(it) }
+ endZoneOffset?.let { setEndZoneOffset(it) }
+ }
+ .build()
+ is HeartRateRecord ->
+ PlatformHeartRateRecord.Builder(
+ metadata.toPlatformMetadata(),
+ startTime,
+ endTime,
+ samples.map { it.toPlatformHeartRateSample() })
+ .apply {
+ startZoneOffset?.let { setStartZoneOffset(it) }
+ endZoneOffset?.let { setEndZoneOffset(it) }
+ }
+ .build()
+ is NutritionRecord ->
+ PlatformNutritionRecord.Builder(metadata.toPlatformMetadata(), startTime, endTime)
+ .apply {
+ startZoneOffset?.let { setStartZoneOffset(it) }
+ endZoneOffset?.let { setEndZoneOffset(it) }
+ caffeine?.let { setCaffeine(it.toPlatformMass()) }
+ energy?.let { setEnergy(it.toPlatformEnergy()) }
+ }
+ .build()
+ else -> throw IllegalArgumentException("Unsupported record $this")
+ }
+}
+
+private fun Mass.toPlatformMass(): PlatformMass {
+ return PlatformMass.fromKilograms(inKilograms)
+}
+
+private fun Energy.toPlatformEnergy(): PlatformEnergy {
+ return PlatformEnergy.fromJoules(inJoules)
+}
+
+private fun HeartRateRecord.Sample.toPlatformHeartRateSample():
+ PlatformHeartRateRecord.HeartRateSample {
+ return PlatformHeartRateRecord.HeartRateSample(beatsPerMinute, time)
+}
+
+fun PlatformRecord.toSdkRecord(): Record {
+ return when (this) {
+ is PlatformStepsRecord ->
+ StepsRecord(
+ startTime, startZoneOffset, endTime, endZoneOffset, count, metadata.toSdkMetadata())
+ else -> throw IllegalArgumentException("Unsupported record $this")
+ }
+}
+
+@VisibleForTesting
+internal fun Metadata.toPlatformMetadata(): PlatformMetadata {
+ return PlatformMetadata.Builder()
+ .apply {
+ device?.toPlatformDevice()?.let { setDevice(it) }
+ setLastModifiedTime(lastModifiedTime)
+ setId(id)
+ setDataOrigin(dataOrigin.toPlatformDataOrigin())
+ setClientRecordId(clientRecordId)
+ setClientRecordVersion(clientRecordVersion)
+ }
+ .build()
+}
+
+@VisibleForTesting
+internal fun PlatformMetadata.toSdkMetadata(): Metadata {
+ return Metadata(
+ id,
+ dataOrigin.toSdkDataOrigin(),
+ lastModifiedTime,
+ clientRecordId,
+ clientRecordVersion,
+ device.toSdkDevice())
+}
+
+private fun Device.toPlatformDevice(): PlatformDevice {
+ @Suppress("WrongConstant") // Platform intdef and jetpack intdef match in value.
+ return PlatformDevice.Builder()
+ .apply {
+ setType(type)
+ manufacturer?.let { setManufacturer(it) }
+ model?.let { setModel(it) }
+ }
+ .build()
+}
+
+private fun PlatformDevice.toSdkDevice(): Device {
+ @Suppress("WrongConstant") // Platform intdef and jetpack intdef match in value.
+ return Device(manufacturer, model, type)
+}
+
+internal fun DataOrigin.toPlatformDataOrigin(): PlatformDataOrigin {
+ return PlatformDataOrigin.Builder().apply { setPackageName(packageName) }.build()
+}
+
+private fun PlatformDataOrigin.toSdkDataOrigin(): DataOrigin {
+ return DataOrigin(packageName)
+}
diff --git a/health/connect/connect-client/src/main/java/androidx/health/connect/client/impl/platform/records/RequestConverters.kt b/health/connect/connect-client/src/main/java/androidx/health/connect/client/impl/platform/records/RequestConverters.kt
new file mode 100644
index 0000000..fc8fb08
--- /dev/null
+++ b/health/connect/connect-client/src/main/java/androidx/health/connect/client/impl/platform/records/RequestConverters.kt
@@ -0,0 +1,269 @@
+/*
+ * Copyright 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+@file:RestrictTo(RestrictTo.Scope.LIBRARY)
+@file:RequiresApi(api = Build.VERSION_CODES.UPSIDE_DOWN_CAKE)
+
+package androidx.health.connect.client.impl.platform.records
+
+import android.health.connect.AggregateRecordsRequest
+import android.health.connect.ChangeLogTokenRequest
+import android.health.connect.ReadRecordsRequestUsingFilters
+import android.health.connect.TimeInstantRangeFilter
+import android.health.connect.datatypes.ActiveCaloriesBurnedRecord as PlatformActiveCaloriesBurnedRecord
+import android.health.connect.datatypes.AggregationType
+import android.health.connect.datatypes.BasalMetabolicRateRecord as PlatformBasalMetabolicRateRecord
+import android.health.connect.datatypes.DistanceRecord as PlatformDistanceRecord
+import android.health.connect.datatypes.ElevationGainedRecord as PlatformElevationGainedRecord
+import android.health.connect.datatypes.FloorsClimbedRecord as PlatformFloorsClimbedRecord
+import android.health.connect.datatypes.HeartRateRecord as PlatformHeartRateRecord
+import android.health.connect.datatypes.HeightRecord as PlatformHeightRecord
+import android.health.connect.datatypes.HydrationRecord as PlatformHydrationRecord
+import android.health.connect.datatypes.NutritionRecord as PlatformNutritionRecord
+import android.health.connect.datatypes.PowerRecord as PlatformPowerRecord
+import android.health.connect.datatypes.Record as PlatformRecord
+import android.health.connect.datatypes.RestingHeartRateRecord as PlatformRestingHeartRateRecord
+import android.health.connect.datatypes.StepsRecord as PlatformStepsRecord
+import android.health.connect.datatypes.TotalCaloriesBurnedRecord as PlatformTotalCaloriesBurnedRecord
+import android.health.connect.datatypes.WeightRecord as PlatformWeightRecord
+import android.health.connect.datatypes.WheelchairPushesRecord as PlatformWheelchairPushesRecord
+import android.os.Build
+import androidx.annotation.RequiresApi
+import androidx.annotation.RestrictTo
+import androidx.health.connect.client.aggregate.AggregateMetric
+import androidx.health.connect.client.impl.platform.time.TimeSource
+import androidx.health.connect.client.records.ActiveCaloriesBurnedRecord
+import androidx.health.connect.client.records.BasalMetabolicRateRecord
+import androidx.health.connect.client.records.DistanceRecord
+import androidx.health.connect.client.records.ElevationGainedRecord
+import androidx.health.connect.client.records.FloorsClimbedRecord
+import androidx.health.connect.client.records.HeartRateRecord
+import androidx.health.connect.client.records.HeightRecord
+import androidx.health.connect.client.records.HydrationRecord
+import androidx.health.connect.client.records.NutritionRecord
+import androidx.health.connect.client.records.PowerRecord
+import androidx.health.connect.client.records.Record
+import androidx.health.connect.client.records.RestingHeartRateRecord
+import androidx.health.connect.client.records.StepsRecord
+import androidx.health.connect.client.records.TotalCaloriesBurnedRecord
+import androidx.health.connect.client.records.WeightRecord
+import androidx.health.connect.client.records.WheelchairPushesRecord
+import androidx.health.connect.client.request.AggregateGroupByDurationRequest
+import androidx.health.connect.client.request.AggregateGroupByPeriodRequest
+import androidx.health.connect.client.request.AggregateRequest
+import androidx.health.connect.client.request.ChangesTokenRequest
+import androidx.health.connect.client.request.ReadRecordsRequest
+import androidx.health.connect.client.time.TimeRangeFilter
+import java.time.Instant
+
+// TODO(b/268327085): Is casting the map values necessary?
+// TODO(b/268326895): Add PlatformRestingHeartRateCord.BPM_AV
+@Suppress("UNCHECKED_CAST")
+private val LONG_AGGREGATION_METRIC_TYPE_MAP: Map<AggregateMetric<Any>, AggregationType<Any>> =
+ mapOf(
+ HeartRateRecord.BPM_MIN to PlatformHeartRateRecord.BPM_MIN as AggregationType<Any>,
+ HeartRateRecord.BPM_MAX to PlatformHeartRateRecord.BPM_MAX as AggregationType<Any>,
+ HeartRateRecord.BPM_AVG to PlatformHeartRateRecord.BPM_AVG as AggregationType<Any>,
+ HeartRateRecord.MEASUREMENTS_COUNT to
+ PlatformHeartRateRecord.HEART_MEASUREMENTS_COUNT as AggregationType<Any>,
+ RestingHeartRateRecord.BPM_MIN to
+ PlatformRestingHeartRateRecord.BPM_MIN as AggregationType<Any>,
+ RestingHeartRateRecord.BPM_MAX to
+ PlatformRestingHeartRateRecord.BPM_MAX as AggregationType<Any>,
+ StepsRecord.COUNT_TOTAL to PlatformStepsRecord.STEPS_COUNT_TOTAL as AggregationType<Any>,
+ WheelchairPushesRecord.COUNT_TOTAL to
+ PlatformWheelchairPushesRecord.WHEEL_CHAIR_PUSHES_COUNT_TOTAL as AggregationType<Any>,
+ )
+
+@Suppress("UNCHECKED_CAST")
+private val DOUBLE_AGGREGATION_METRIC_TYPE_MAP: Map<AggregateMetric<Any>, AggregationType<Any>> =
+ mapOf(
+ ActiveCaloriesBurnedRecord.ACTIVE_CALORIES_TOTAL to
+ PlatformActiveCaloriesBurnedRecord.ACTIVE_CALORIES_TOTAL as AggregationType<Any>,
+ BasalMetabolicRateRecord.BASAL_CALORIES_TOTAL to
+ PlatformBasalMetabolicRateRecord.BASAL_CALORIES_TOTAL as AggregationType<Any>,
+ DistanceRecord.DISTANCE_TOTAL to
+ PlatformDistanceRecord.DISTANCE_TOTAL as AggregationType<Any>,
+ ElevationGainedRecord.ELEVATION_GAINED_TOTAL to
+ PlatformElevationGainedRecord.ELEVATION_GAINED_TOTAL as AggregationType<Any>,
+ FloorsClimbedRecord.FLOORS_CLIMBED_TOTAL to
+ PlatformFloorsClimbedRecord.FLOORS_CLIMBED_TOTAL as AggregationType<Any>,
+ HeightRecord.HEIGHT_AVG to PlatformHeightRecord.HEIGHT_AVG as AggregationType<Any>,
+ HeightRecord.HEIGHT_MIN to PlatformHeightRecord.HEIGHT_MIN as AggregationType<Any>,
+ HeightRecord.HEIGHT_MAX to PlatformHeightRecord.HEIGHT_MAX as AggregationType<Any>,
+ HydrationRecord.VOLUME_TOTAL to
+ PlatformHydrationRecord.VOLUME_TOTAL as AggregationType<Any>,
+ NutritionRecord.BIOTIN_TOTAL to
+ PlatformNutritionRecord.BIOTIN_TOTAL as AggregationType<Any>,
+ NutritionRecord.CAFFEINE_TOTAL to
+ PlatformNutritionRecord.CAFFEINE_TOTAL as AggregationType<Any>,
+ NutritionRecord.CALCIUM_TOTAL to
+ PlatformNutritionRecord.CALCIUM_TOTAL as AggregationType<Any>,
+ NutritionRecord.CHLORIDE_TOTAL to
+ PlatformNutritionRecord.CHLORIDE_TOTAL as AggregationType<Any>,
+ NutritionRecord.CHOLESTEROL_TOTAL to
+ PlatformNutritionRecord.CHOLESTEROL_TOTAL as AggregationType<Any>,
+ NutritionRecord.CHROMIUM_TOTAL to
+ PlatformNutritionRecord.CHROMIUM_TOTAL as AggregationType<Any>,
+ NutritionRecord.COPPER_TOTAL to
+ PlatformNutritionRecord.COPPER_TOTAL as AggregationType<Any>,
+ NutritionRecord.DIETARY_FIBER_TOTAL to
+ PlatformNutritionRecord.DIETARY_FIBER_TOTAL as AggregationType<Any>,
+ NutritionRecord.ENERGY_TOTAL to
+ PlatformNutritionRecord.ENERGY_TOTAL as AggregationType<Any>,
+ NutritionRecord.ENERGY_FROM_FAT_TOTAL to
+ PlatformNutritionRecord.ENERGY_FROM_FAT_TOTAL as AggregationType<Any>,
+ NutritionRecord.FOLATE_TOTAL to
+ PlatformNutritionRecord.FOLATE_TOTAL as AggregationType<Any>,
+ NutritionRecord.FOLIC_ACID_TOTAL to
+ PlatformNutritionRecord.FOLIC_ACID_TOTAL as AggregationType<Any>,
+ NutritionRecord.IODINE_TOTAL to
+ PlatformNutritionRecord.IODINE_TOTAL as AggregationType<Any>,
+ NutritionRecord.IRON_TOTAL to PlatformNutritionRecord.IRON_TOTAL as AggregationType<Any>,
+ NutritionRecord.MAGNESIUM_TOTAL to
+ PlatformNutritionRecord.MAGNESIUM_TOTAL as AggregationType<Any>,
+ NutritionRecord.MANGANESE_TOTAL to
+ PlatformNutritionRecord.MANGANESE_TOTAL as AggregationType<Any>,
+ NutritionRecord.MOLYBDENUM_TOTAL to
+ PlatformNutritionRecord.MOLYBDENUM_TOTAL as AggregationType<Any>,
+ NutritionRecord.MONOUNSATURATED_FAT_TOTAL to
+ PlatformNutritionRecord.MONOUNSATURATED_FAT_TOTAL as AggregationType<Any>,
+ NutritionRecord.NIACIN_TOTAL to
+ PlatformNutritionRecord.NIACIN_TOTAL as AggregationType<Any>,
+ NutritionRecord.PANTOTHENIC_ACID_TOTAL to
+ PlatformNutritionRecord.PANTOTHENIC_ACID_TOTAL as AggregationType<Any>,
+ NutritionRecord.PHOSPHORUS_TOTAL to
+ PlatformNutritionRecord.PHOSPHORUS_TOTAL as AggregationType<Any>,
+ NutritionRecord.POLYUNSATURATED_FAT_TOTAL to
+ PlatformNutritionRecord.POLYUNSATURATED_FAT_TOTAL as AggregationType<Any>,
+ NutritionRecord.POTASSIUM_TOTAL to
+ PlatformNutritionRecord.POTASSIUM_TOTAL as AggregationType<Any>,
+ NutritionRecord.PROTEIN_TOTAL to
+ PlatformNutritionRecord.PROTEIN_TOTAL as AggregationType<Any>,
+ NutritionRecord.RIBOFLAVIN_TOTAL to
+ PlatformNutritionRecord.RIBOFLAVIN_TOTAL as AggregationType<Any>,
+ NutritionRecord.SATURATED_FAT_TOTAL to
+ PlatformNutritionRecord.SATURATED_FAT_TOTAL as AggregationType<Any>,
+ NutritionRecord.SELENIUM_TOTAL to
+ PlatformNutritionRecord.SELENIUM_TOTAL as AggregationType<Any>,
+ NutritionRecord.SODIUM_TOTAL to
+ PlatformNutritionRecord.SODIUM_TOTAL as AggregationType<Any>,
+ NutritionRecord.SUGAR_TOTAL to PlatformNutritionRecord.SUGAR_TOTAL as AggregationType<Any>,
+ NutritionRecord.THIAMIN_TOTAL to
+ PlatformNutritionRecord.THIAMIN_TOTAL as AggregationType<Any>,
+ NutritionRecord.TOTAL_CARBOHYDRATE_TOTAL to
+ PlatformNutritionRecord.TOTAL_CARBOHYDRATE_TOTAL as AggregationType<Any>,
+ NutritionRecord.TOTAL_FAT_TOTAL to
+ PlatformNutritionRecord.TOTAL_FAT_TOTAL as AggregationType<Any>,
+ NutritionRecord.UNSATURATED_FAT_TOTAL to
+ PlatformNutritionRecord.UNSATURATED_FAT_TOTAL as AggregationType<Any>,
+ NutritionRecord.VITAMIN_A_TOTAL to
+ PlatformNutritionRecord.VITAMIN_A_TOTAL as AggregationType<Any>,
+ NutritionRecord.VITAMIN_B12_TOTAL to
+ PlatformNutritionRecord.VITAMIN_B12_TOTAL as AggregationType<Any>,
+ NutritionRecord.VITAMIN_B6_TOTAL to
+ PlatformNutritionRecord.VITAMIN_B6_TOTAL as AggregationType<Any>,
+ NutritionRecord.VITAMIN_C_TOTAL to
+ PlatformNutritionRecord.VITAMIN_C_TOTAL as AggregationType<Any>,
+ NutritionRecord.VITAMIN_D_TOTAL to
+ PlatformNutritionRecord.VITAMIN_D_TOTAL as AggregationType<Any>,
+ NutritionRecord.VITAMIN_E_TOTAL to
+ PlatformNutritionRecord.VITAMIN_E_TOTAL as AggregationType<Any>,
+ NutritionRecord.VITAMIN_K_TOTAL to
+ PlatformNutritionRecord.VITAMIN_K_TOTAL as AggregationType<Any>,
+ NutritionRecord.ZINC_TOTAL to PlatformNutritionRecord.ZINC_TOTAL as AggregationType<Any>,
+ PowerRecord.POWER_AVG to PlatformPowerRecord.POWER_AVG as AggregationType<Any>,
+ PowerRecord.POWER_MAX to PlatformPowerRecord.POWER_MAX as AggregationType<Any>,
+ PowerRecord.POWER_MIN to PlatformPowerRecord.POWER_MIN as AggregationType<Any>,
+ TotalCaloriesBurnedRecord.ENERGY_TOTAL to
+ PlatformTotalCaloriesBurnedRecord.ENERGY_TOTAL as AggregationType<Any>,
+ WeightRecord.WEIGHT_AVG to PlatformWeightRecord.WEIGHT_AVG as AggregationType<Any>,
+ WeightRecord.WEIGHT_MIN to PlatformWeightRecord.WEIGHT_MIN as AggregationType<Any>,
+ WeightRecord.WEIGHT_MAX to PlatformWeightRecord.WEIGHT_MAX as AggregationType<Any>,
+ )
+
+fun ReadRecordsRequest<out Record>.toPlatformRequest(
+ timeSource: TimeSource
+): ReadRecordsRequestUsingFilters<out PlatformRecord> {
+ return ReadRecordsRequestUsingFilters.Builder(recordType.toPlatformRecordClass())
+ .setTimeRangeFilter(timeRangeFilter.toPlatformTimeRangeFilter(timeSource))
+ .apply { dataOriginFilter.forEach { addDataOrigins(it.toPlatformDataOrigin()) } }
+ .build()
+}
+
+fun TimeRangeFilter.toPlatformTimeRangeFilter(timeSource: TimeSource): TimeInstantRangeFilter {
+ // TODO(b/262571990): pass nullable Instant start/end
+ // TODO(b/262571990): pass nullable LocalDateTime start/end
+ return TimeInstantRangeFilter.Builder()
+ .setStartTime(startTime ?: Instant.EPOCH)
+ .setEndTime(endTime ?: timeSource.now)
+ .build()
+}
+
+fun ChangesTokenRequest.toPlatformRequest(): ChangeLogTokenRequest {
+ return ChangeLogTokenRequest.Builder()
+ .apply {
+ dataOriginFilters.forEach { addDataOriginFilter(it.toPlatformDataOrigin()) }
+ recordTypes.forEach { addRecordType(it.toPlatformRecordClass()) }
+ }
+ .build()
+}
+
+fun AggregateRequest.toPlatformRequest(timeSource: TimeSource): AggregateRecordsRequest<Any> {
+ return AggregateRecordsRequest.Builder<Any>(
+ timeRangeFilter.toPlatformTimeRangeFilter(timeSource))
+ .apply {
+ dataOriginFilter.forEach { addDataOriginsFilter(it.toPlatformDataOrigin()) }
+ metrics.forEach { addAggregationType(it.toAggregationType()) }
+ }
+ .build()
+}
+
+fun AggregateGroupByDurationRequest.toPlatformRequest(
+ timeSource: TimeSource
+): AggregateRecordsRequest<Any> {
+ return AggregateRecordsRequest.Builder<Any>(
+ timeRangeFilter.toPlatformTimeRangeFilter(timeSource))
+ .apply {
+ dataOriginFilter.forEach { addDataOriginsFilter(it.toPlatformDataOrigin()) }
+ metrics.forEach { addAggregationType(it.toAggregationType()) }
+ }
+ .build()
+}
+
+fun AggregateGroupByPeriodRequest.toPlatformRequest(
+ timeSource: TimeSource
+): AggregateRecordsRequest<Any> {
+ return AggregateRecordsRequest.Builder<Any>(
+ timeRangeFilter.toPlatformTimeRangeFilter(timeSource))
+ .apply {
+ dataOriginFilter.forEach { addDataOriginsFilter(it.toPlatformDataOrigin()) }
+ metrics.forEach { addAggregationType(it.toAggregationType()) }
+ }
+ .build()
+}
+
+fun AggregateMetric<Any>.toAggregationType(): AggregationType<Any> {
+ return LONG_AGGREGATION_METRIC_TYPE_MAP[this]
+ ?: DOUBLE_AGGREGATION_METRIC_TYPE_MAP[this]
+ ?: throw IllegalArgumentException("Unsupported aggregation type $metricKey")
+}
+
+fun AggregateMetric<Any>.isLongAggregationType() =
+ LONG_AGGREGATION_METRIC_TYPE_MAP.containsKey(this)
+
+fun AggregateMetric<Any>.isDoubleAggregationType() =
+ DOUBLE_AGGREGATION_METRIC_TYPE_MAP.containsKey(this)
diff --git a/health/connect/connect-client/src/main/java/androidx/health/connect/client/impl/platform/records/ResponseConverters.kt b/health/connect/connect-client/src/main/java/androidx/health/connect/client/impl/platform/records/ResponseConverters.kt
new file mode 100644
index 0000000..13f6a05
--- /dev/null
+++ b/health/connect/connect-client/src/main/java/androidx/health/connect/client/impl/platform/records/ResponseConverters.kt
@@ -0,0 +1,96 @@
+/*
+ * Copyright 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+@file:RestrictTo(RestrictTo.Scope.LIBRARY)
+@file:RequiresApi(api = Build.VERSION_CODES.UPSIDE_DOWN_CAKE)
+
+package androidx.health.connect.client.impl.platform.records
+
+import android.health.connect.AggregateRecordsGroupedByDurationResponse
+import android.health.connect.AggregateRecordsGroupedByPeriodResponse
+import android.health.connect.AggregateRecordsResponse
+import android.health.connect.datatypes.AggregationType
+import android.health.connect.datatypes.NutritionRecord
+import android.health.connect.datatypes.units.Energy as PlatformEnergy
+import android.health.connect.datatypes.units.Mass
+import android.os.Build
+import androidx.annotation.RequiresApi
+import androidx.annotation.RestrictTo
+import androidx.health.connect.client.aggregate.AggregateMetric
+import androidx.health.connect.client.aggregate.AggregationResult
+import androidx.health.connect.client.aggregate.AggregationResultGroupedByDuration
+import androidx.health.connect.client.aggregate.AggregationResultGroupedByPeriod
+import androidx.health.connect.client.units.Energy
+import java.time.ZoneOffset
+
+private val DOUBLE_AGGREGATION_TYPE_CONVERTERS: Map<AggregationType<out Any>, (Any) -> Double> =
+ mapOf(
+ NutritionRecord.CAFFEINE_TOTAL to { (it as Mass).inKilograms },
+ NutritionRecord.ENERGY_TOTAL to
+ {
+ Energy.joules((it as PlatformEnergy).inJoules).inKilocalories
+ })
+
+fun AggregateRecordsResponse<Any>.toSdkResponse(metrics: Set<AggregateMetric<Any>>) =
+ buildAggregationResult(metrics, ::get)
+
+fun AggregateRecordsGroupedByDurationResponse<Any>.toSdkResponse(
+ metrics: Set<AggregateMetric<Any>>
+) =
+ AggregationResultGroupedByDuration(
+ buildAggregationResult(metrics, ::get),
+ startTime,
+ endTime,
+ getZoneOffset(metrics.first().toAggregationType())
+ ?: ZoneOffset.systemDefault().rules.getOffset(startTime))
+
+fun AggregateRecordsGroupedByPeriodResponse<Any>.toSdkResponse(metrics: Set<AggregateMetric<Any>>) =
+ AggregationResultGroupedByPeriod(buildAggregationResult(metrics, ::get), startTime, endTime)
+
+private fun buildAggregationResult(
+ metrics: Set<AggregateMetric<Any>>,
+ aggregationValueGetter: (AggregationType<Any>) -> Any?
+): AggregationResult {
+ val metricValueMap = buildMap {
+ metrics.forEach { metric ->
+ aggregationValueGetter(metric.toAggregationType())?.also { this[metric] = it }
+ }
+ }
+ return AggregationResult(
+ getLongMetricValues(metricValueMap), getDoubleMetricValues(metricValueMap), setOf())
+}
+
+private fun getLongMetricValues(metricValueMap: Map<AggregateMetric<Any>, Any>): Map<String, Long> {
+ return buildMap {
+ metricValueMap
+ .filterKeys { it.isLongAggregationType() }
+ .forEach { this[it.key.metricKey] = it.value as Long }
+ }
+}
+
+private fun getDoubleMetricValues(
+ metricValueMap: Map<AggregateMetric<Any>, Any>
+): Map<String, Double> {
+ return buildMap {
+ metricValueMap
+ .filterKeys { it.isDoubleAggregationType() }
+ .forEach {
+ DOUBLE_AGGREGATION_TYPE_CONVERTERS[it.key.toAggregationType()]?.also { convert ->
+ this[it.key.metricKey] = convert(it.value)
+ }
+ }
+ }
+}
diff --git a/appsearch/appsearch/src/main/java/androidx/appsearch/observer/AppSearchObserverCallback.java b/health/connect/connect-client/src/main/java/androidx/health/connect/client/impl/platform/records/package-info.java
similarity index 62%
copy from appsearch/appsearch/src/main/java/androidx/appsearch/observer/AppSearchObserverCallback.java
copy to health/connect/connect-client/src/main/java/androidx/health/connect/client/impl/platform/records/package-info.java
index c01917e..c5b8a8e 100644
--- a/appsearch/appsearch/src/main/java/androidx/appsearch/observer/AppSearchObserverCallback.java
+++ b/health/connect/connect-client/src/main/java/androidx/health/connect/client/impl/platform/records/package-info.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2021 The Android Open Source Project
+ * Copyright (C) 2022 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -14,15 +14,12 @@
* limitations under the License.
*/
-package androidx.appsearch.observer;
-
-import androidx.annotation.RestrictTo;
-
/**
- * @deprecated use {@link ObserverCallback} instead.
+ * Helps with conversions to the platform record and API objects.
+ *
* @hide
*/
-// TODO(b/209734214): Remove this after dogfooders and devices have migrated away from this class.
-@Deprecated
-@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
-public interface AppSearchObserverCallback extends ObserverCallback {}
+@RestrictTo(RestrictTo.Scope.LIBRARY)
+package androidx.health.connect.client.impl.platform.records;
+
+import androidx.annotation.RestrictTo;
diff --git a/health/connect/connect-client/src/main/java/androidx/health/connect/client/impl/platform/response/InsertRecordsResponseConverter.kt b/health/connect/connect-client/src/main/java/androidx/health/connect/client/impl/platform/response/InsertRecordsResponseConverter.kt
new file mode 100644
index 0000000..6aba317
--- /dev/null
+++ b/health/connect/connect-client/src/main/java/androidx/health/connect/client/impl/platform/response/InsertRecordsResponseConverter.kt
@@ -0,0 +1,30 @@
+/*
+ * Copyright 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+@file:RequiresApi(api = Build.VERSION_CODES.UPSIDE_DOWN_CAKE)
+
+package androidx.health.connect.client.impl.platform.response
+
+import android.health.connect.InsertRecordsResponse
+import android.os.Build
+import androidx.annotation.RequiresApi
+
+internal fun InsertRecordsResponse.toKtResponse():
+ androidx.health.connect.client.response.InsertRecordsResponse {
+ return androidx.health.connect.client.response.InsertRecordsResponse(
+ recordIdsList = records.map { record -> record.metadata.id }
+ )
+}
diff --git a/appsearch/appsearch/src/main/java/androidx/appsearch/observer/AppSearchObserverCallback.java b/health/connect/connect-client/src/main/java/androidx/health/connect/client/impl/platform/response/package-info.java
similarity index 62%
copy from appsearch/appsearch/src/main/java/androidx/appsearch/observer/AppSearchObserverCallback.java
copy to health/connect/connect-client/src/main/java/androidx/health/connect/client/impl/platform/response/package-info.java
index c01917e..f8b9cb7 100644
--- a/appsearch/appsearch/src/main/java/androidx/appsearch/observer/AppSearchObserverCallback.java
+++ b/health/connect/connect-client/src/main/java/androidx/health/connect/client/impl/platform/response/package-info.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2021 The Android Open Source Project
+ * Copyright (C) 2022 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -14,15 +14,12 @@
* limitations under the License.
*/
-package androidx.appsearch.observer;
-
-import androidx.annotation.RestrictTo;
-
/**
- * @deprecated use {@link ObserverCallback} instead.
+ * Helps with conversions to the platform record and API objects.
+ *
* @hide
*/
-// TODO(b/209734214): Remove this after dogfooders and devices have migrated away from this class.
-@Deprecated
-@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
-public interface AppSearchObserverCallback extends ObserverCallback {}
+@RestrictTo(RestrictTo.Scope.LIBRARY)
+package androidx.health.connect.client.impl.platform.response;
+
+import androidx.annotation.RestrictTo;
diff --git a/health/connect/connect-client/src/main/java/androidx/health/connect/client/impl/platform/time/TimeSource.kt b/health/connect/connect-client/src/main/java/androidx/health/connect/client/impl/platform/time/TimeSource.kt
new file mode 100644
index 0000000..b0385c6
--- /dev/null
+++ b/health/connect/connect-client/src/main/java/androidx/health/connect/client/impl/platform/time/TimeSource.kt
@@ -0,0 +1,34 @@
+/*
+ * Copyright 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+@file:RestrictTo(RestrictTo.Scope.LIBRARY)
+@file:RequiresApi(api = Build.VERSION_CODES.UPSIDE_DOWN_CAKE)
+
+package androidx.health.connect.client.impl.platform.time
+
+import android.os.Build
+import androidx.annotation.RequiresApi
+import androidx.annotation.RestrictTo
+import java.time.Instant
+
+interface TimeSource {
+ val now: Instant
+}
+
+object SystemDefaultTimeSource : TimeSource {
+ override val now: Instant
+ get() = Instant.now()
+}
\ No newline at end of file
diff --git a/health/connect/connect-client/src/main/java/androidx/health/connect/client/permission/HealthPermission.kt b/health/connect/connect-client/src/main/java/androidx/health/connect/client/permission/HealthPermission.kt
index 463f45f..bc0ac62 100644
--- a/health/connect/connect-client/src/main/java/androidx/health/connect/client/permission/HealthPermission.kt
+++ b/health/connect/connect-client/src/main/java/androidx/health/connect/client/permission/HealthPermission.kt
@@ -129,137 +129,127 @@
return WRITE_PERMISSION_PREFIX + RECORD_TYPE_TO_PERMISSION.getOrDefault(recordType, "")
}
+ internal const val PERMISSION_PREFIX = "android.permission.health."
+
// Read permissions for ACTIVITY.
internal const val READ_ACTIVE_CALORIES_BURNED =
- "android.permission.health.READ_ACTIVE_CALORIES_BURNED"
- internal const val READ_DISTANCE = "android.permission.health.READ_DISTANCE"
- internal const val READ_ELEVATION_GAINED = "android.permission.health.READ_ELEVATION_GAINED"
- internal const val READ_EXERCISE = "android.permission.health.READ_EXERCISE"
- internal const val READ_FLOORS_CLIMBED = "android.permission.health.READ_FLOORS_CLIMBED"
- internal const val READ_STEPS = "android.permission.health.READ_STEPS"
+ PERMISSION_PREFIX + "READ_ACTIVE_CALORIES_BURNED"
+ internal const val READ_DISTANCE = PERMISSION_PREFIX + "READ_DISTANCE"
+ internal const val READ_ELEVATION_GAINED = PERMISSION_PREFIX + "READ_ELEVATION_GAINED"
+ internal const val READ_EXERCISE = PERMISSION_PREFIX + "READ_EXERCISE"
+ internal const val READ_FLOORS_CLIMBED = PERMISSION_PREFIX + "READ_FLOORS_CLIMBED"
+ internal const val READ_STEPS = PERMISSION_PREFIX + "READ_STEPS"
internal const val READ_TOTAL_CALORIES_BURNED =
- "android.permission.health.READ_TOTAL_CALORIES_BURNED"
- internal const val READ_VO2_MAX = "android.permission.health.READ_VO2_MAX"
- internal const val READ_WHEELCHAIR_PUSHES =
- "android.permission.health.READ_WHEELCHAIR_PUSHES"
- internal const val READ_POWER = "android.permission.health.READ_POWER"
- internal const val READ_SPEED = "android.permission.health.READ_SPEED"
+ PERMISSION_PREFIX + "READ_TOTAL_CALORIES_BURNED"
+ internal const val READ_VO2_MAX = PERMISSION_PREFIX + "READ_VO2_MAX"
+ internal const val READ_WHEELCHAIR_PUSHES = PERMISSION_PREFIX + "READ_WHEELCHAIR_PUSHES"
+ internal const val READ_POWER = PERMISSION_PREFIX + "READ_POWER"
+ internal const val READ_SPEED = PERMISSION_PREFIX + "READ_SPEED"
// Read permissions for BODY_MEASUREMENTS.
internal const val READ_BASAL_METABOLIC_RATE =
- "android.permission.health.READ_BASAL_METABOLIC_RATE"
- internal const val READ_BODY_FAT = "android.permission.health.READ_BODY_FAT"
- internal const val READ_BODY_WATER_MASS = "android.permission.health.READ_BODY_WATER_MASS"
- internal const val READ_BONE_MASS = "android.permission.health.READ_BONE_MASS"
- internal const val READ_HEIGHT = "android.permission.health.READ_HEIGHT"
+ PERMISSION_PREFIX + "READ_BASAL_METABOLIC_RATE"
+ internal const val READ_BODY_FAT = PERMISSION_PREFIX + "READ_BODY_FAT"
+ internal const val READ_BODY_WATER_MASS = PERMISSION_PREFIX + "READ_BODY_WATER_MASS"
+ internal const val READ_BONE_MASS = PERMISSION_PREFIX + "READ_BONE_MASS"
+ internal const val READ_HEIGHT = PERMISSION_PREFIX + "READ_HEIGHT"
@RestrictTo(RestrictTo.Scope.LIBRARY)
- internal const val READ_HIP_CIRCUMFERENCE =
- "android.permission.health.READ_HIP_CIRCUMFERENCE"
- internal const val READ_LEAN_BODY_MASS = "android.permission.health.READ_LEAN_BODY_MASS"
+ internal const val READ_HIP_CIRCUMFERENCE = PERMISSION_PREFIX + "READ_HIP_CIRCUMFERENCE"
+ internal const val READ_LEAN_BODY_MASS = PERMISSION_PREFIX + "READ_LEAN_BODY_MASS"
@RestrictTo(RestrictTo.Scope.LIBRARY)
- internal const val READ_WAIST_CIRCUMFERENCE =
- "android.permission.health.READ_WAIST_CIRCUMFERENCE"
- internal const val READ_WEIGHT = "android.permission.health.READ_WEIGHT"
+ internal const val READ_WAIST_CIRCUMFERENCE = PERMISSION_PREFIX + "READ_WAIST_CIRCUMFERENCE"
+ internal const val READ_WEIGHT = PERMISSION_PREFIX + "READ_WEIGHT"
// Read permissions for CYCLE_TRACKING.
- internal const val READ_CERVICAL_MUCUS = "android.permission.health.READ_CERVICAL_MUCUS"
+ internal const val READ_CERVICAL_MUCUS = PERMISSION_PREFIX + "READ_CERVICAL_MUCUS"
@RestrictTo(RestrictTo.Scope.LIBRARY)
internal const val READ_INTERMENSTRUAL_BLEEDING =
- "android.permission.health.READ_INTERMENSTRUAL_BLEEDING"
- internal const val READ_MENSTRUATION = "android.permission.health.READ_MENSTRUATION"
- internal const val READ_OVULATION_TEST = "android.permission.health.READ_OVULATION_TEST"
- internal const val READ_SEXUAL_ACTIVITY = "android.permission.health.READ_SEXUAL_ACTIVITY"
+ PERMISSION_PREFIX + "READ_INTERMENSTRUAL_BLEEDING"
+ internal const val READ_MENSTRUATION = PERMISSION_PREFIX + "READ_MENSTRUATION"
+ internal const val READ_OVULATION_TEST = PERMISSION_PREFIX + "READ_OVULATION_TEST"
+ internal const val READ_SEXUAL_ACTIVITY = PERMISSION_PREFIX + "READ_SEXUAL_ACTIVITY"
// Read permissions for NUTRITION.
- internal const val READ_HYDRATION = "android.permission.health.READ_HYDRATION"
- internal const val READ_NUTRITION = "android.permission.health.READ_NUTRITION"
+ internal const val READ_HYDRATION = PERMISSION_PREFIX + "READ_HYDRATION"
+ internal const val READ_NUTRITION = PERMISSION_PREFIX + "READ_NUTRITION"
// Read permissions for SLEEP.
- internal const val READ_SLEEP = "android.permission.health.READ_SLEEP"
+ internal const val READ_SLEEP = PERMISSION_PREFIX + "READ_SLEEP"
// Read permissions for VITALS.
internal const val READ_BASAL_BODY_TEMPERATURE =
- "android.permission.health.READ_BASAL_BODY_TEMPERATURE"
- internal const val READ_BLOOD_GLUCOSE = "android.permission.health.READ_BLOOD_GLUCOSE"
- internal const val READ_BLOOD_PRESSURE = "android.permission.health.READ_BLOOD_PRESSURE"
- internal const val READ_BODY_TEMPERATURE = "android.permission.health.READ_BODY_TEMPERATURE"
- internal const val READ_HEART_RATE = "android.permission.health.READ_HEART_RATE"
+ PERMISSION_PREFIX + "READ_BASAL_BODY_TEMPERATURE"
+ internal const val READ_BLOOD_GLUCOSE = PERMISSION_PREFIX + "READ_BLOOD_GLUCOSE"
+ internal const val READ_BLOOD_PRESSURE = PERMISSION_PREFIX + "READ_BLOOD_PRESSURE"
+ internal const val READ_BODY_TEMPERATURE = PERMISSION_PREFIX + "READ_BODY_TEMPERATURE"
+ internal const val READ_HEART_RATE = PERMISSION_PREFIX + "READ_HEART_RATE"
internal const val READ_HEART_RATE_VARIABILITY =
- "android.permission.health.READ_HEART_RATE_VARIABILITY"
- internal const val READ_OXYGEN_SATURATION =
- "android.permission.health.READ_OXYGEN_SATURATION"
- internal const val READ_RESPIRATORY_RATE = "android.permission.health.READ_RESPIRATORY_RATE"
- internal const val READ_RESTING_HEART_RATE =
- "android.permission.health.READ_RESTING_HEART_RATE"
+ PERMISSION_PREFIX + "READ_HEART_RATE_VARIABILITY"
+ internal const val READ_OXYGEN_SATURATION = PERMISSION_PREFIX + "READ_OXYGEN_SATURATION"
+ internal const val READ_RESPIRATORY_RATE = PERMISSION_PREFIX + "READ_RESPIRATORY_RATE"
+ internal const val READ_RESTING_HEART_RATE = PERMISSION_PREFIX + "READ_RESTING_HEART_RATE"
// Write permissions for ACTIVITY.
internal const val WRITE_ACTIVE_CALORIES_BURNED =
- "android.permission.health.WRITE_ACTIVE_CALORIES_BURNED"
- internal const val WRITE_DISTANCE = "android.permission.health.WRITE_DISTANCE"
- internal const val WRITE_ELEVATION_GAINED =
- "android.permission.health.WRITE_ELEVATION_GAINED"
- internal const val WRITE_EXERCISE = "android.permission.health.WRITE_EXERCISE"
- internal const val WRITE_FLOORS_CLIMBED = "android.permission.health.WRITE_FLOORS_CLIMBED"
- internal const val WRITE_STEPS = "android.permission.health.WRITE_STEPS"
+ PERMISSION_PREFIX + "WRITE_ACTIVE_CALORIES_BURNED"
+ internal const val WRITE_DISTANCE = PERMISSION_PREFIX + "WRITE_DISTANCE"
+ internal const val WRITE_ELEVATION_GAINED = PERMISSION_PREFIX + "WRITE_ELEVATION_GAINED"
+ internal const val WRITE_EXERCISE = PERMISSION_PREFIX + "WRITE_EXERCISE"
+ internal const val WRITE_FLOORS_CLIMBED = PERMISSION_PREFIX + "WRITE_FLOORS_CLIMBED"
+ internal const val WRITE_STEPS = PERMISSION_PREFIX + "WRITE_STEPS"
internal const val WRITE_TOTAL_CALORIES_BURNED =
- "android.permission.health.WRITE_TOTAL_CALORIES_BURNED"
- internal const val WRITE_VO2_MAX = "android.permission.health.WRITE_VO2_MAX"
- internal const val WRITE_WHEELCHAIR_PUSHES =
- "android.permission.health.WRITE_WHEELCHAIR_PUSHES"
- internal const val WRITE_POWER = "android.permission.health.WRITE_POWER"
- internal const val WRITE_SPEED = "android.permission.health.WRITE_SPEED"
+ PERMISSION_PREFIX + "WRITE_TOTAL_CALORIES_BURNED"
+ internal const val WRITE_VO2_MAX = PERMISSION_PREFIX + "WRITE_VO2_MAX"
+ internal const val WRITE_WHEELCHAIR_PUSHES = PERMISSION_PREFIX + "WRITE_WHEELCHAIR_PUSHES"
+ internal const val WRITE_POWER = PERMISSION_PREFIX + "WRITE_POWER"
+ internal const val WRITE_SPEED = PERMISSION_PREFIX + "WRITE_SPEED"
// Write permissions for BODY_MEASUREMENTS.
internal const val WRITE_BASAL_METABOLIC_RATE =
- "android.permission.health.WRITE_BASAL_METABOLIC_RATE"
- internal const val WRITE_BODY_FAT = "android.permission.health.WRITE_BODY_FAT"
- internal const val WRITE_BODY_WATER_MASS = "android.permission.health.WRITE_BODY_WATER_MASS"
- internal const val WRITE_BONE_MASS = "android.permission.health.WRITE_BONE_MASS"
- internal const val WRITE_HEIGHT = "android.permission.health.WRITE_HEIGHT"
+ PERMISSION_PREFIX + "WRITE_BASAL_METABOLIC_RATE"
+ internal const val WRITE_BODY_FAT = PERMISSION_PREFIX + "WRITE_BODY_FAT"
+ internal const val WRITE_BODY_WATER_MASS = PERMISSION_PREFIX + "WRITE_BODY_WATER_MASS"
+ internal const val WRITE_BONE_MASS = PERMISSION_PREFIX + "WRITE_BONE_MASS"
+ internal const val WRITE_HEIGHT = PERMISSION_PREFIX + "WRITE_HEIGHT"
@RestrictTo(RestrictTo.Scope.LIBRARY)
- internal const val WRITE_HIP_CIRCUMFERENCE =
- "android.permission.health.WRITE_HIP_CIRCUMFERENCE"
- internal const val WRITE_LEAN_BODY_MASS = "android.permission.health.WRITE_LEAN_BODY_MASS"
+ internal const val WRITE_HIP_CIRCUMFERENCE = PERMISSION_PREFIX + "WRITE_HIP_CIRCUMFERENCE"
+ internal const val WRITE_LEAN_BODY_MASS = PERMISSION_PREFIX + "WRITE_LEAN_BODY_MASS"
@RestrictTo(RestrictTo.Scope.LIBRARY)
internal const val WRITE_WAIST_CIRCUMFERENCE =
- "android.permission.health.WRITE_WAIST_CIRCUMFERENCE"
- internal const val WRITE_WEIGHT = "android.permission.health.WRITE_WEIGHT"
+ PERMISSION_PREFIX + "WRITE_WAIST_CIRCUMFERENCE"
+ internal const val WRITE_WEIGHT = PERMISSION_PREFIX + "WRITE_WEIGHT"
// Write permissions for CYCLE_TRACKING.
- internal const val WRITE_CERVICAL_MUCUS = "android.permission.health.WRITE_CERVICAL_MUCUS"
+ internal const val WRITE_CERVICAL_MUCUS = PERMISSION_PREFIX + "WRITE_CERVICAL_MUCUS"
@RestrictTo(RestrictTo.Scope.LIBRARY)
internal const val WRITE_INTERMENSTRUAL_BLEEDING =
- "android.permission.health.WRITE_INTERMENSTRUAL_BLEEDING"
- internal const val WRITE_MENSTRUATION = "android.permission.health.WRITE_MENSTRUATION"
- internal const val WRITE_OVULATION_TEST = "android.permission.health.WRITE_OVULATION_TEST"
- internal const val WRITE_SEXUAL_ACTIVITY = "android.permission.health.WRITE_SEXUAL_ACTIVITY"
+ PERMISSION_PREFIX + "WRITE_INTERMENSTRUAL_BLEEDING"
+ internal const val WRITE_MENSTRUATION = PERMISSION_PREFIX + "WRITE_MENSTRUATION"
+ internal const val WRITE_OVULATION_TEST = PERMISSION_PREFIX + "WRITE_OVULATION_TEST"
+ internal const val WRITE_SEXUAL_ACTIVITY = PERMISSION_PREFIX + "WRITE_SEXUAL_ACTIVITY"
// Write permissions for NUTRITION.
- internal const val WRITE_HYDRATION = "android.permission.health.WRITE_HYDRATION"
- internal const val WRITE_NUTRITION = "android.permission.health.WRITE_NUTRITION"
+ internal const val WRITE_HYDRATION = PERMISSION_PREFIX + "WRITE_HYDRATION"
+ internal const val WRITE_NUTRITION = PERMISSION_PREFIX + "WRITE_NUTRITION"
// Write permissions for SLEEP.
- internal const val WRITE_SLEEP = "android.permission.health.WRITE_SLEEP"
+ internal const val WRITE_SLEEP = PERMISSION_PREFIX + "WRITE_SLEEP"
// Write permissions for VITALS.
internal const val WRITE_BASAL_BODY_TEMPERATURE =
- "android.permission.health.WRITE_BASAL_BODY_TEMPERATURE"
- internal const val WRITE_BLOOD_GLUCOSE = "android.permission.health.WRITE_BLOOD_GLUCOSE"
- internal const val WRITE_BLOOD_PRESSURE = "android.permission.health.WRITE_BLOOD_PRESSURE"
- internal const val WRITE_BODY_TEMPERATURE =
- "android.permission.health.WRITE_BODY_TEMPERATURE"
- internal const val WRITE_HEART_RATE = "android.permission.health.WRITE_HEART_RATE"
+ PERMISSION_PREFIX + "WRITE_BASAL_BODY_TEMPERATURE"
+ internal const val WRITE_BLOOD_GLUCOSE = PERMISSION_PREFIX + "WRITE_BLOOD_GLUCOSE"
+ internal const val WRITE_BLOOD_PRESSURE = PERMISSION_PREFIX + "WRITE_BLOOD_PRESSURE"
+ internal const val WRITE_BODY_TEMPERATURE = PERMISSION_PREFIX + "WRITE_BODY_TEMPERATURE"
+ internal const val WRITE_HEART_RATE = PERMISSION_PREFIX + "WRITE_HEART_RATE"
internal const val WRITE_HEART_RATE_VARIABILITY =
- "android.permission.health.WRITE_HEART_RATE_VARIABILITY"
- internal const val WRITE_OXYGEN_SATURATION =
- "android.permission.health.WRITE_OXYGEN_SATURATION"
- internal const val WRITE_RESPIRATORY_RATE =
- "android.permission.health.WRITE_RESPIRATORY_RATE"
- internal const val WRITE_RESTING_HEART_RATE =
- "android.permission.health.WRITE_RESTING_HEART_RATE"
+ PERMISSION_PREFIX + "WRITE_HEART_RATE_VARIABILITY"
+ internal const val WRITE_OXYGEN_SATURATION = PERMISSION_PREFIX + "WRITE_OXYGEN_SATURATION"
+ internal const val WRITE_RESPIRATORY_RATE = PERMISSION_PREFIX + "WRITE_RESPIRATORY_RATE"
+ internal const val WRITE_RESTING_HEART_RATE = PERMISSION_PREFIX + "WRITE_RESTING_HEART_RATE"
- internal const val READ_PERMISSION_PREFIX = "android.permission.health.READ_"
- internal const val WRITE_PERMISSION_PREFIX = "android.permission.health.WRITE_"
+ internal const val READ_PERMISSION_PREFIX = PERMISSION_PREFIX + "READ_"
+ internal const val WRITE_PERMISSION_PREFIX = PERMISSION_PREFIX + "WRITE_"
internal val RECORD_TYPE_TO_PERMISSION =
mapOf<KClass<out Record>, String>(
diff --git a/health/connect/connect-client/src/main/java/androidx/health/connect/client/permission/platform/HealthDataRequestPermissionsUpsideDownCake.kt b/health/connect/connect-client/src/main/java/androidx/health/connect/client/permission/platform/HealthDataRequestPermissionsUpsideDownCake.kt
new file mode 100644
index 0000000..e6994c5
--- /dev/null
+++ b/health/connect/connect-client/src/main/java/androidx/health/connect/client/permission/platform/HealthDataRequestPermissionsUpsideDownCake.kt
@@ -0,0 +1,53 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package androidx.health.connect.client.permission.platform
+
+import android.content.Context
+import android.content.Intent
+import androidx.activity.result.contract.ActivityResultContract
+import androidx.activity.result.contract.ActivityResultContracts.RequestMultiplePermissions
+import androidx.annotation.RestrictTo
+import androidx.health.connect.client.permission.HealthPermission.Companion.PERMISSION_PREFIX
+
+/**
+ * An [ActivityResultContract] to request Health Connect system permissions.
+ *
+ * @see androidx.activity.ComponentActivity.registerForActivityResult
+ */
+@RestrictTo(RestrictTo.Scope.LIBRARY)
+internal class HealthDataRequestPermissionsUpsideDownCake :
+ ActivityResultContract<Set<String>, Set<String>>() {
+
+ private val requestPermissions = RequestMultiplePermissions()
+
+ override fun createIntent(context: Context, input: Set<String>): Intent {
+ require(input.all { it.startsWith(PERMISSION_PREFIX) }) {
+ "Unsupported health connect permission"
+ }
+ return requestPermissions.createIntent(context, input.toTypedArray())
+ }
+
+ override fun parseResult(resultCode: Int, intent: Intent?): Set<String> =
+ requestPermissions.parseResult(resultCode, intent).filterValues { it }.keys
+
+ override fun getSynchronousResult(
+ context: Context,
+ input: Set<String>,
+ ): SynchronousResult<Set<String>>? =
+ requestPermissions.getSynchronousResult(context, input.toTypedArray())?.let { result ->
+ SynchronousResult(result.value.filterValues { it }.keys)
+ }
+}
diff --git a/health/connect/connect-client/src/test/java/androidx/health/connect/client/PermissionControllerTest.kt b/health/connect/connect-client/src/test/java/androidx/health/connect/client/PermissionControllerTest.kt
index f0d031bc..038429be 100644
--- a/health/connect/connect-client/src/test/java/androidx/health/connect/client/PermissionControllerTest.kt
+++ b/health/connect/connect-client/src/test/java/androidx/health/connect/client/PermissionControllerTest.kt
@@ -17,13 +17,16 @@
package androidx.health.connect.client
import android.content.Context
+import android.os.Build.VERSION_CODES
+import androidx.activity.result.contract.ActivityResultContracts.RequestMultiplePermissions
import androidx.health.connect.client.permission.HealthPermission
import androidx.test.core.app.ApplicationProvider
import androidx.test.ext.junit.runners.AndroidJUnit4
-import com.google.common.truth.Truth
+import com.google.common.truth.Truth.assertThat
import org.junit.Before
import org.junit.Test
import org.junit.runner.RunWith
+import org.robolectric.annotation.Config
private const val PROVIDER_PACKAGE_NAME = "com.example.fake.provider"
@@ -38,7 +41,7 @@
}
@Test
- fun createIntentTest_permissionStrings() {
+ fun createIntent_permissionStrings() {
val requestPermissionContract =
PermissionController.createRequestPermissionResultContract(PROVIDER_PACKAGE_NAME)
val intent =
@@ -47,7 +50,25 @@
setOf(HealthPermission.READ_ACTIVE_CALORIES_BURNED)
)
- Truth.assertThat(intent.action).isEqualTo("androidx.health.ACTION_REQUEST_PERMISSIONS")
- Truth.assertThat(intent.`package`).isEqualTo(PROVIDER_PACKAGE_NAME)
+ assertThat(intent.action).isEqualTo("androidx.health.ACTION_REQUEST_PERMISSIONS")
+ assertThat(intent.`package`).isEqualTo(PROVIDER_PACKAGE_NAME)
+ }
+
+ @Test
+ @Config(minSdk = VERSION_CODES.UPSIDE_DOWN_CAKE)
+ fun createIntent_UpsideDownCake() {
+ val requestPermissionContract =
+ PermissionController.createRequestPermissionResultContract(PROVIDER_PACKAGE_NAME)
+ val intent =
+ requestPermissionContract.createIntent(
+ context,
+ setOf(HealthPermission.WRITE_STEPS, HealthPermission.READ_DISTANCE)
+ )
+
+ assertThat(intent.action).isEqualTo(RequestMultiplePermissions.ACTION_REQUEST_PERMISSIONS)
+ assertThat(intent.getStringArrayExtra(RequestMultiplePermissions.EXTRA_PERMISSIONS))
+ .asList()
+ .containsExactly(HealthPermission.WRITE_STEPS, HealthPermission.READ_DISTANCE)
+ assertThat(intent.`package`).isNull()
}
}
diff --git a/health/connect/connect-client/src/test/java/androidx/health/connect/client/permission/platform/HealthDataRequestPermissionsUpsideDownCakeTest.kt b/health/connect/connect-client/src/test/java/androidx/health/connect/client/permission/platform/HealthDataRequestPermissionsUpsideDownCakeTest.kt
new file mode 100644
index 0000000..2bbd4f4
--- /dev/null
+++ b/health/connect/connect-client/src/test/java/androidx/health/connect/client/permission/platform/HealthDataRequestPermissionsUpsideDownCakeTest.kt
@@ -0,0 +1,90 @@
+/*
+ * Copyright 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.health.connect.client.permission.platform
+
+import android.app.Activity
+import android.content.Context
+import android.content.Intent
+import android.content.pm.PackageManager
+import androidx.activity.result.contract.ActivityResultContracts.RequestMultiplePermissions
+import androidx.health.connect.client.permission.HealthPermission
+import androidx.test.core.app.ApplicationProvider
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import com.google.common.truth.Truth.assertThat
+import kotlin.test.assertFailsWith
+import org.junit.Before
+import org.junit.Test
+import org.junit.runner.RunWith
+
+@RunWith(AndroidJUnit4::class)
+class HealthDataRequestPermissionsUpsideDownCakeTest {
+
+ private lateinit var context: Context
+
+ @Before
+ fun setUp() {
+ context = ApplicationProvider.getApplicationContext()
+ }
+
+ @Test
+ fun createIntent() {
+ val requestPermissionContract = HealthDataRequestPermissionsUpsideDownCake()
+ val intent =
+ requestPermissionContract.createIntent(
+ context, setOf(HealthPermission.READ_STEPS, HealthPermission.WRITE_DISTANCE))
+
+ assertThat(intent.action).isEqualTo(RequestMultiplePermissions.ACTION_REQUEST_PERMISSIONS)
+ assertThat(intent.getStringArrayExtra(RequestMultiplePermissions.EXTRA_PERMISSIONS))
+ .asList()
+ .containsExactly(HealthPermission.READ_STEPS, HealthPermission.WRITE_DISTANCE)
+ }
+
+ @Test
+ fun createIntent_nonHealthPermission_throwsIAE() {
+ val requestPermissionContract = HealthDataRequestPermissionsUpsideDownCake()
+ assertFailsWith<IllegalArgumentException> {
+ requestPermissionContract.createIntent(
+ context, setOf(HealthPermission.READ_STEPS, "NON_HEALTH_PERMISSION"))
+ }
+ }
+
+ @Test
+ fun parseIntent() {
+ val requestPermissionContract = HealthDataRequestPermissionsUpsideDownCake()
+
+ val intent = Intent()
+ intent.putExtra(
+ RequestMultiplePermissions.EXTRA_PERMISSIONS,
+ arrayOf(
+ HealthPermission.READ_STEPS,
+ HealthPermission.WRITE_STEPS,
+ HealthPermission.WRITE_DISTANCE,
+ HealthPermission.READ_HEART_RATE))
+ intent.putExtra(
+ RequestMultiplePermissions.EXTRA_PERMISSION_GRANT_RESULTS,
+ intArrayOf(
+ PackageManager.PERMISSION_GRANTED,
+ PackageManager.PERMISSION_DENIED,
+ PackageManager.PERMISSION_GRANTED,
+ PackageManager.PERMISSION_DENIED))
+
+ val result = requestPermissionContract.parseResult(Activity.RESULT_OK, intent)
+
+ assertThat(result)
+ .containsExactly(HealthPermission.READ_STEPS, HealthPermission.WRITE_DISTANCE)
+ }
+}
diff --git a/heifwriter/heifwriter/api/api_lint.ignore b/heifwriter/heifwriter/api/api_lint.ignore
index a93261a..d3c7e43 100644
--- a/heifwriter/heifwriter/api/api_lint.ignore
+++ b/heifwriter/heifwriter/api/api_lint.ignore
@@ -1,42 +1,24 @@
// Baseline format: 1.0
+GenericException: androidx.heifwriter.AvifWriter#stop(long):
+ Methods must not throw generic exceptions (`java.lang.Exception`)
GenericException: androidx.heifwriter.HeifWriter#stop(long):
Methods must not throw generic exceptions (`java.lang.Exception`)
-MissingGetterMatchingBuilder: androidx.heifwriter.HeifWriter.Builder#setGridEnabled(boolean):
- androidx.heifwriter.HeifWriter does not declare a `isGridEnabled()` method matching method androidx.heifwriter.HeifWriter.Builder.setGridEnabled(boolean)
-MissingGetterMatchingBuilder: androidx.heifwriter.HeifWriter.Builder#setHandler(android.os.Handler):
- androidx.heifwriter.HeifWriter does not declare a `getHandler()` method matching method androidx.heifwriter.HeifWriter.Builder.setHandler(android.os.Handler)
-MissingGetterMatchingBuilder: androidx.heifwriter.HeifWriter.Builder#setMaxImages(int):
- androidx.heifwriter.HeifWriter does not declare a `getMaxImages()` method matching method androidx.heifwriter.HeifWriter.Builder.setMaxImages(int)
-MissingGetterMatchingBuilder: androidx.heifwriter.HeifWriter.Builder#setPrimaryIndex(int):
- androidx.heifwriter.HeifWriter does not declare a `getPrimaryIndex()` method matching method androidx.heifwriter.HeifWriter.Builder.setPrimaryIndex(int)
-MissingGetterMatchingBuilder: androidx.heifwriter.HeifWriter.Builder#setQuality(int):
- androidx.heifwriter.HeifWriter does not declare a `getQuality()` method matching method androidx.heifwriter.HeifWriter.Builder.setQuality(int)
-MissingGetterMatchingBuilder: androidx.heifwriter.HeifWriter.Builder#setRotation(int):
- androidx.heifwriter.HeifWriter does not declare a `getRotation()` method matching method androidx.heifwriter.HeifWriter.Builder.setRotation(int)
-
-
-MissingNullability: androidx.heifwriter.HeifWriter.Builder#build():
- Missing nullability on method `build` return
-MissingNullability: androidx.heifwriter.HeifWriter.Builder#setGridEnabled(boolean):
- Missing nullability on method `setGridEnabled` return
-MissingNullability: androidx.heifwriter.HeifWriter.Builder#setHandler(android.os.Handler):
- Missing nullability on method `setHandler` return
-MissingNullability: androidx.heifwriter.HeifWriter.Builder#setMaxImages(int):
- Missing nullability on method `setMaxImages` return
-MissingNullability: androidx.heifwriter.HeifWriter.Builder#setPrimaryIndex(int):
- Missing nullability on method `setPrimaryIndex` return
-MissingNullability: androidx.heifwriter.HeifWriter.Builder#setQuality(int):
- Missing nullability on method `setQuality` return
-MissingNullability: androidx.heifwriter.HeifWriter.Builder#setRotation(int):
- Missing nullability on method `setRotation` return
-
-
+UseParcelFileDescriptor: androidx.heifwriter.AvifWriter.Builder#Builder(java.io.FileDescriptor, int, int, int) parameter #0:
+ Must use ParcelFileDescriptor instead of FileDescriptor in parameter fd in androidx.heifwriter.AvifWriter.Builder(java.io.FileDescriptor fd, int width, int height, int inputMode)
UseParcelFileDescriptor: androidx.heifwriter.HeifWriter.Builder#Builder(java.io.FileDescriptor, int, int, int) parameter #0:
Must use ParcelFileDescriptor instead of FileDescriptor in parameter fd in androidx.heifwriter.HeifWriter.Builder(java.io.FileDescriptor fd, int width, int height, int inputMode)
+VisiblySynchronized: androidx.heifwriter.AvifWriter#addBitmap(android.graphics.Bitmap):
+ Internal locks must not be exposed (synchronizing on this or class is still externally observable): method androidx.heifwriter.AvifWriter.addBitmap(android.graphics.Bitmap)
+VisiblySynchronized: androidx.heifwriter.AvifWriter#addYuvBuffer(int, byte[]):
+ Internal locks must not be exposed (synchronizing on this or class is still externally observable): method androidx.heifwriter.AvifWriter.addYuvBuffer(int,byte[])
+VisiblySynchronized: androidx.heifwriter.AvifWriter#setInputEndOfStreamTimestamp(long):
+ Internal locks must not be exposed (synchronizing on this or class is still externally observable): method androidx.heifwriter.AvifWriter.setInputEndOfStreamTimestamp(long)
+VisiblySynchronized: androidx.heifwriter.AvifWriter#stop(long):
+ Internal locks must not be exposed (synchronizing on this or class is still externally observable): method androidx.heifwriter.AvifWriter.stop(long)
VisiblySynchronized: androidx.heifwriter.HeifWriter#addBitmap(android.graphics.Bitmap):
Internal locks must not be exposed (synchronizing on this or class is still externally observable): method androidx.heifwriter.HeifWriter.addBitmap(android.graphics.Bitmap)
VisiblySynchronized: androidx.heifwriter.HeifWriter#addYuvBuffer(int, byte[]):
diff --git a/heifwriter/heifwriter/api/current.txt b/heifwriter/heifwriter/api/current.txt
index 8a45d85..90c95a4 100644
--- a/heifwriter/heifwriter/api/current.txt
+++ b/heifwriter/heifwriter/api/current.txt
@@ -1,30 +1,71 @@
// Signature format: 4.0
package androidx.heifwriter {
+ public final class AvifWriter implements java.lang.AutoCloseable {
+ method public void addBitmap(android.graphics.Bitmap);
+ method public void addExifData(int, byte[], int, int);
+ method public void addYuvBuffer(int, byte[]);
+ method public void close();
+ method public android.os.Handler? getHandler();
+ method public android.view.Surface getInputSurface();
+ method public int getMaxImages();
+ method public int getPrimaryIndex();
+ method public int getQuality();
+ method public int getRotation();
+ method public boolean isGridEnabled();
+ method public boolean isHighBitDepthEnabled();
+ method public void setInputEndOfStreamTimestamp(@IntRange(from=0) long);
+ method public void start();
+ method public void stop(@IntRange(from=0) long) throws java.lang.Exception;
+ field public static final int INPUT_MODE_BITMAP = 2; // 0x2
+ field public static final int INPUT_MODE_BUFFER = 0; // 0x0
+ field public static final int INPUT_MODE_SURFACE = 1; // 0x1
+ }
+
+ public static final class AvifWriter.Builder {
+ ctor public AvifWriter.Builder(String, @IntRange(from=1) int, @IntRange(from=1) int, int);
+ ctor public AvifWriter.Builder(java.io.FileDescriptor, @IntRange(from=1) int, @IntRange(from=1) int, int);
+ method public androidx.heifwriter.AvifWriter build() throws java.io.IOException;
+ method public androidx.heifwriter.AvifWriter.Builder setGridEnabled(boolean);
+ method public androidx.heifwriter.AvifWriter.Builder setHandler(android.os.Handler?);
+ method public androidx.heifwriter.AvifWriter.Builder setHighBitDepthEnabled(boolean);
+ method public androidx.heifwriter.AvifWriter.Builder setMaxImages(@IntRange(from=1) int);
+ method public androidx.heifwriter.AvifWriter.Builder setPrimaryIndex(@IntRange(from=0) int);
+ method public androidx.heifwriter.AvifWriter.Builder setQuality(@IntRange(from=0, to=100) int);
+ method public androidx.heifwriter.AvifWriter.Builder setRotation(@IntRange(from=0) int);
+ }
+
public final class HeifWriter implements java.lang.AutoCloseable {
method public void addBitmap(android.graphics.Bitmap);
method public void addExifData(int, byte[], int, int);
method public void addYuvBuffer(int, byte[]);
method public void close();
+ method public android.os.Handler? getHandler();
method public android.view.Surface getInputSurface();
- method public void setInputEndOfStreamTimestamp(long);
+ method public int getMaxImages();
+ method public int getPrimaryIndex();
+ method public int getQuality();
+ method public int getRotation();
+ method public boolean isGridEnabled();
+ method public boolean isHighBitDepthEnabled();
+ method public void setInputEndOfStreamTimestamp(@IntRange(from=0) long);
method public void start();
- method public void stop(long) throws java.lang.Exception;
+ method public void stop(@IntRange(from=0) long) throws java.lang.Exception;
field public static final int INPUT_MODE_BITMAP = 2; // 0x2
field public static final int INPUT_MODE_BUFFER = 0; // 0x0
field public static final int INPUT_MODE_SURFACE = 1; // 0x1
}
public static final class HeifWriter.Builder {
- ctor public HeifWriter.Builder(String, int, int, int);
- ctor public HeifWriter.Builder(java.io.FileDescriptor, int, int, int);
- method public androidx.heifwriter.HeifWriter! build() throws java.io.IOException;
- method public androidx.heifwriter.HeifWriter.Builder! setGridEnabled(boolean);
- method public androidx.heifwriter.HeifWriter.Builder! setHandler(android.os.Handler?);
- method public androidx.heifwriter.HeifWriter.Builder! setMaxImages(int);
- method public androidx.heifwriter.HeifWriter.Builder! setPrimaryIndex(int);
- method public androidx.heifwriter.HeifWriter.Builder! setQuality(int);
- method public androidx.heifwriter.HeifWriter.Builder! setRotation(int);
+ ctor public HeifWriter.Builder(String, @IntRange(from=1) int, @IntRange(from=1) int, int);
+ ctor public HeifWriter.Builder(java.io.FileDescriptor, @IntRange(from=1) int, @IntRange(from=1) int, int);
+ method public androidx.heifwriter.HeifWriter build() throws java.io.IOException;
+ method public androidx.heifwriter.HeifWriter.Builder setGridEnabled(boolean);
+ method public androidx.heifwriter.HeifWriter.Builder setHandler(android.os.Handler?);
+ method public androidx.heifwriter.HeifWriter.Builder setMaxImages(@IntRange(from=1) int);
+ method public androidx.heifwriter.HeifWriter.Builder setPrimaryIndex(@IntRange(from=0) int);
+ method public androidx.heifwriter.HeifWriter.Builder setQuality(@IntRange(from=0, to=100) int);
+ method public androidx.heifwriter.HeifWriter.Builder setRotation(@IntRange(from=0) int);
}
}
diff --git a/heifwriter/heifwriter/api/public_plus_experimental_current.txt b/heifwriter/heifwriter/api/public_plus_experimental_current.txt
index 8a45d85..90c95a4 100644
--- a/heifwriter/heifwriter/api/public_plus_experimental_current.txt
+++ b/heifwriter/heifwriter/api/public_plus_experimental_current.txt
@@ -1,30 +1,71 @@
// Signature format: 4.0
package androidx.heifwriter {
+ public final class AvifWriter implements java.lang.AutoCloseable {
+ method public void addBitmap(android.graphics.Bitmap);
+ method public void addExifData(int, byte[], int, int);
+ method public void addYuvBuffer(int, byte[]);
+ method public void close();
+ method public android.os.Handler? getHandler();
+ method public android.view.Surface getInputSurface();
+ method public int getMaxImages();
+ method public int getPrimaryIndex();
+ method public int getQuality();
+ method public int getRotation();
+ method public boolean isGridEnabled();
+ method public boolean isHighBitDepthEnabled();
+ method public void setInputEndOfStreamTimestamp(@IntRange(from=0) long);
+ method public void start();
+ method public void stop(@IntRange(from=0) long) throws java.lang.Exception;
+ field public static final int INPUT_MODE_BITMAP = 2; // 0x2
+ field public static final int INPUT_MODE_BUFFER = 0; // 0x0
+ field public static final int INPUT_MODE_SURFACE = 1; // 0x1
+ }
+
+ public static final class AvifWriter.Builder {
+ ctor public AvifWriter.Builder(String, @IntRange(from=1) int, @IntRange(from=1) int, int);
+ ctor public AvifWriter.Builder(java.io.FileDescriptor, @IntRange(from=1) int, @IntRange(from=1) int, int);
+ method public androidx.heifwriter.AvifWriter build() throws java.io.IOException;
+ method public androidx.heifwriter.AvifWriter.Builder setGridEnabled(boolean);
+ method public androidx.heifwriter.AvifWriter.Builder setHandler(android.os.Handler?);
+ method public androidx.heifwriter.AvifWriter.Builder setHighBitDepthEnabled(boolean);
+ method public androidx.heifwriter.AvifWriter.Builder setMaxImages(@IntRange(from=1) int);
+ method public androidx.heifwriter.AvifWriter.Builder setPrimaryIndex(@IntRange(from=0) int);
+ method public androidx.heifwriter.AvifWriter.Builder setQuality(@IntRange(from=0, to=100) int);
+ method public androidx.heifwriter.AvifWriter.Builder setRotation(@IntRange(from=0) int);
+ }
+
public final class HeifWriter implements java.lang.AutoCloseable {
method public void addBitmap(android.graphics.Bitmap);
method public void addExifData(int, byte[], int, int);
method public void addYuvBuffer(int, byte[]);
method public void close();
+ method public android.os.Handler? getHandler();
method public android.view.Surface getInputSurface();
- method public void setInputEndOfStreamTimestamp(long);
+ method public int getMaxImages();
+ method public int getPrimaryIndex();
+ method public int getQuality();
+ method public int getRotation();
+ method public boolean isGridEnabled();
+ method public boolean isHighBitDepthEnabled();
+ method public void setInputEndOfStreamTimestamp(@IntRange(from=0) long);
method public void start();
- method public void stop(long) throws java.lang.Exception;
+ method public void stop(@IntRange(from=0) long) throws java.lang.Exception;
field public static final int INPUT_MODE_BITMAP = 2; // 0x2
field public static final int INPUT_MODE_BUFFER = 0; // 0x0
field public static final int INPUT_MODE_SURFACE = 1; // 0x1
}
public static final class HeifWriter.Builder {
- ctor public HeifWriter.Builder(String, int, int, int);
- ctor public HeifWriter.Builder(java.io.FileDescriptor, int, int, int);
- method public androidx.heifwriter.HeifWriter! build() throws java.io.IOException;
- method public androidx.heifwriter.HeifWriter.Builder! setGridEnabled(boolean);
- method public androidx.heifwriter.HeifWriter.Builder! setHandler(android.os.Handler?);
- method public androidx.heifwriter.HeifWriter.Builder! setMaxImages(int);
- method public androidx.heifwriter.HeifWriter.Builder! setPrimaryIndex(int);
- method public androidx.heifwriter.HeifWriter.Builder! setQuality(int);
- method public androidx.heifwriter.HeifWriter.Builder! setRotation(int);
+ ctor public HeifWriter.Builder(String, @IntRange(from=1) int, @IntRange(from=1) int, int);
+ ctor public HeifWriter.Builder(java.io.FileDescriptor, @IntRange(from=1) int, @IntRange(from=1) int, int);
+ method public androidx.heifwriter.HeifWriter build() throws java.io.IOException;
+ method public androidx.heifwriter.HeifWriter.Builder setGridEnabled(boolean);
+ method public androidx.heifwriter.HeifWriter.Builder setHandler(android.os.Handler?);
+ method public androidx.heifwriter.HeifWriter.Builder setMaxImages(@IntRange(from=1) int);
+ method public androidx.heifwriter.HeifWriter.Builder setPrimaryIndex(@IntRange(from=0) int);
+ method public androidx.heifwriter.HeifWriter.Builder setQuality(@IntRange(from=0, to=100) int);
+ method public androidx.heifwriter.HeifWriter.Builder setRotation(@IntRange(from=0) int);
}
}
diff --git a/heifwriter/heifwriter/api/restricted_current.txt b/heifwriter/heifwriter/api/restricted_current.txt
index 8a45d85..90c95a4 100644
--- a/heifwriter/heifwriter/api/restricted_current.txt
+++ b/heifwriter/heifwriter/api/restricted_current.txt
@@ -1,30 +1,71 @@
// Signature format: 4.0
package androidx.heifwriter {
+ public final class AvifWriter implements java.lang.AutoCloseable {
+ method public void addBitmap(android.graphics.Bitmap);
+ method public void addExifData(int, byte[], int, int);
+ method public void addYuvBuffer(int, byte[]);
+ method public void close();
+ method public android.os.Handler? getHandler();
+ method public android.view.Surface getInputSurface();
+ method public int getMaxImages();
+ method public int getPrimaryIndex();
+ method public int getQuality();
+ method public int getRotation();
+ method public boolean isGridEnabled();
+ method public boolean isHighBitDepthEnabled();
+ method public void setInputEndOfStreamTimestamp(@IntRange(from=0) long);
+ method public void start();
+ method public void stop(@IntRange(from=0) long) throws java.lang.Exception;
+ field public static final int INPUT_MODE_BITMAP = 2; // 0x2
+ field public static final int INPUT_MODE_BUFFER = 0; // 0x0
+ field public static final int INPUT_MODE_SURFACE = 1; // 0x1
+ }
+
+ public static final class AvifWriter.Builder {
+ ctor public AvifWriter.Builder(String, @IntRange(from=1) int, @IntRange(from=1) int, int);
+ ctor public AvifWriter.Builder(java.io.FileDescriptor, @IntRange(from=1) int, @IntRange(from=1) int, int);
+ method public androidx.heifwriter.AvifWriter build() throws java.io.IOException;
+ method public androidx.heifwriter.AvifWriter.Builder setGridEnabled(boolean);
+ method public androidx.heifwriter.AvifWriter.Builder setHandler(android.os.Handler?);
+ method public androidx.heifwriter.AvifWriter.Builder setHighBitDepthEnabled(boolean);
+ method public androidx.heifwriter.AvifWriter.Builder setMaxImages(@IntRange(from=1) int);
+ method public androidx.heifwriter.AvifWriter.Builder setPrimaryIndex(@IntRange(from=0) int);
+ method public androidx.heifwriter.AvifWriter.Builder setQuality(@IntRange(from=0, to=100) int);
+ method public androidx.heifwriter.AvifWriter.Builder setRotation(@IntRange(from=0) int);
+ }
+
public final class HeifWriter implements java.lang.AutoCloseable {
method public void addBitmap(android.graphics.Bitmap);
method public void addExifData(int, byte[], int, int);
method public void addYuvBuffer(int, byte[]);
method public void close();
+ method public android.os.Handler? getHandler();
method public android.view.Surface getInputSurface();
- method public void setInputEndOfStreamTimestamp(long);
+ method public int getMaxImages();
+ method public int getPrimaryIndex();
+ method public int getQuality();
+ method public int getRotation();
+ method public boolean isGridEnabled();
+ method public boolean isHighBitDepthEnabled();
+ method public void setInputEndOfStreamTimestamp(@IntRange(from=0) long);
method public void start();
- method public void stop(long) throws java.lang.Exception;
+ method public void stop(@IntRange(from=0) long) throws java.lang.Exception;
field public static final int INPUT_MODE_BITMAP = 2; // 0x2
field public static final int INPUT_MODE_BUFFER = 0; // 0x0
field public static final int INPUT_MODE_SURFACE = 1; // 0x1
}
public static final class HeifWriter.Builder {
- ctor public HeifWriter.Builder(String, int, int, int);
- ctor public HeifWriter.Builder(java.io.FileDescriptor, int, int, int);
- method public androidx.heifwriter.HeifWriter! build() throws java.io.IOException;
- method public androidx.heifwriter.HeifWriter.Builder! setGridEnabled(boolean);
- method public androidx.heifwriter.HeifWriter.Builder! setHandler(android.os.Handler?);
- method public androidx.heifwriter.HeifWriter.Builder! setMaxImages(int);
- method public androidx.heifwriter.HeifWriter.Builder! setPrimaryIndex(int);
- method public androidx.heifwriter.HeifWriter.Builder! setQuality(int);
- method public androidx.heifwriter.HeifWriter.Builder! setRotation(int);
+ ctor public HeifWriter.Builder(String, @IntRange(from=1) int, @IntRange(from=1) int, int);
+ ctor public HeifWriter.Builder(java.io.FileDescriptor, @IntRange(from=1) int, @IntRange(from=1) int, int);
+ method public androidx.heifwriter.HeifWriter build() throws java.io.IOException;
+ method public androidx.heifwriter.HeifWriter.Builder setGridEnabled(boolean);
+ method public androidx.heifwriter.HeifWriter.Builder setHandler(android.os.Handler?);
+ method public androidx.heifwriter.HeifWriter.Builder setMaxImages(@IntRange(from=1) int);
+ method public androidx.heifwriter.HeifWriter.Builder setPrimaryIndex(@IntRange(from=0) int);
+ method public androidx.heifwriter.HeifWriter.Builder setQuality(@IntRange(from=0, to=100) int);
+ method public androidx.heifwriter.HeifWriter.Builder setRotation(@IntRange(from=0) int);
}
}
diff --git a/heifwriter/heifwriter/lint-baseline.xml b/heifwriter/heifwriter/lint-baseline.xml
index 3a578ac..b2f2806 100644
--- a/heifwriter/heifwriter/lint-baseline.xml
+++ b/heifwriter/heifwriter/lint-baseline.xml
@@ -7,7 +7,7 @@
errorLine1=" synchronized void updateInputEOSTime(long timestampNs) {"
errorLine2=" ^">
<location
- file="src/main/java/androidx/heifwriter/HeifEncoder.java"/>
+ file="src/main/java/androidx/heifwriter/EncoderBase.java"/>
</issue>
<issue
@@ -16,7 +16,7 @@
errorLine1=" synchronized boolean updateLastInputAndEncoderTime(long inputTimeNs, long encoderTimeUs) {"
errorLine2=" ^">
<location
- file="src/main/java/androidx/heifwriter/HeifEncoder.java"/>
+ file="src/main/java/androidx/heifwriter/EncoderBase.java"/>
</issue>
<issue
@@ -25,7 +25,7 @@
errorLine1=" synchronized void updateLastOutputTime(long outputTimeUs) {"
errorLine2=" ^">
<location
- file="src/main/java/androidx/heifwriter/HeifEncoder.java"/>
+ file="src/main/java/androidx/heifwriter/EncoderBase.java"/>
</issue>
<issue
@@ -34,7 +34,7 @@
errorLine1=" synchronized void waitForResult(long timeoutMs) throws Exception {"
errorLine2=" ^">
<location
- file="src/main/java/androidx/heifwriter/HeifWriter.java"/>
+ file="src/main/java/androidx/heifwriter/WriterBase.java"/>
</issue>
<issue
@@ -43,7 +43,7 @@
errorLine1=" synchronized void signalResult(@Nullable Exception e) {"
errorLine2=" ^">
<location
- file="src/main/java/androidx/heifwriter/HeifWriter.java"/>
+ file="src/main/java/androidx/heifwriter/WriterBase.java"/>
</issue>
<issue
@@ -121,6 +121,24 @@
<issue
id="UnknownNullness"
message="Unknown nullability; explicitly declare as `@Nullable` or `@NonNull` to improve Kotlin interoperability; see https://developer.android.com/kotlin/interop#nullability_annotations"
+ errorLine1=" protected static String findHevcFallback() {"
+ errorLine2=" ~~~~~~~">
+ <location
+ file="src/main/java/androidx/heifwriter/HeifEncoder.java"/>
+ </issue>
+
+ <issue
+ id="UnknownNullness"
+ message="Unknown nullability; explicitly declare as `@Nullable` or `@NonNull` to improve Kotlin interoperability; see https://developer.android.com/kotlin/interop#nullability_annotations"
+ errorLine1=" protected static String findAv1Fallback() {"
+ errorLine2=" ~~~~~~~">
+ <location
+ file="src/main/java/androidx/heifwriter/AvifEncoder.java"/>
+ </issue>
+
+ <issue
+ id="UnknownNullness"
+ message="Unknown nullability; explicitly declare as `@Nullable` or `@NonNull` to improve Kotlin interoperability; see https://developer.android.com/kotlin/interop#nullability_annotations"
errorLine1=" public Builder setRotation(int rotation) {"
errorLine2=" ~~~~~~~">
<location
@@ -184,6 +202,69 @@
<issue
id="UnknownNullness"
message="Unknown nullability; explicitly declare as `@Nullable` or `@NonNull` to improve Kotlin interoperability; see https://developer.android.com/kotlin/interop#nullability_annotations"
+ errorLine1=" public Builder setRotation(int rotation) {"
+ errorLine2=" ~~~~~~~">
+ <location
+ file="src/main/java/androidx/heifwriter/AvifWriter.java"/>
+ </issue>
+
+ <issue
+ id="UnknownNullness"
+ message="Unknown nullability; explicitly declare as `@Nullable` or `@NonNull` to improve Kotlin interoperability; see https://developer.android.com/kotlin/interop#nullability_annotations"
+ errorLine1=" public Builder setGridEnabled(boolean gridEnabled) {"
+ errorLine2=" ~~~~~~~">
+ <location
+ file="src/main/java/androidx/heifwriter/AvifWriter.java"/>
+ </issue>
+
+ <issue
+ id="UnknownNullness"
+ message="Unknown nullability; explicitly declare as `@Nullable` or `@NonNull` to improve Kotlin interoperability; see https://developer.android.com/kotlin/interop#nullability_annotations"
+ errorLine1=" public Builder setQuality(int quality) {"
+ errorLine2=" ~~~~~~~">
+ <location
+ file="src/main/java/androidx/heifwriter/AvifWriter.java"/>
+ </issue>
+
+ <issue
+ id="UnknownNullness"
+ message="Unknown nullability; explicitly declare as `@Nullable` or `@NonNull` to improve Kotlin interoperability; see https://developer.android.com/kotlin/interop#nullability_annotations"
+ errorLine1=" public Builder setMaxImages(int maxImages) {"
+ errorLine2=" ~~~~~~~">
+ <location
+ file="src/main/java/androidx/heifwriter/AvifWriter.java"/>
+ </issue>
+
+ <issue
+ id="UnknownNullness"
+ message="Unknown nullability; explicitly declare as `@Nullable` or `@NonNull` to improve Kotlin interoperability; see https://developer.android.com/kotlin/interop#nullability_annotations"
+ errorLine1=" public Builder setPrimaryIndex(int primaryIndex) {"
+ errorLine2=" ~~~~~~~">
+ <location
+ file="src/main/java/androidx/heifwriter/AvifWriter.java"/>
+ </issue>
+
+ <issue
+ id="UnknownNullness"
+ message="Unknown nullability; explicitly declare as `@Nullable` or `@NonNull` to improve Kotlin interoperability; see https://developer.android.com/kotlin/interop#nullability_annotations"
+ errorLine1=" public Builder setHandler(@Nullable Handler handler) {"
+ errorLine2=" ~~~~~~~">
+ <location
+ file="src/main/java/androidx/heifwriter/AvifWriter.java"/>
+ </issue>
+
+ <issue
+ id="UnknownNullness"
+ message="Unknown nullability; explicitly declare as `@Nullable` or `@NonNull` to improve Kotlin interoperability; see https://developer.android.com/kotlin/interop#nullability_annotations"
+ errorLine1=" public HeifWriter build() throws IOException {"
+ errorLine2=" ~~~~~~~~~~">
+ <location
+ file="src/main/java/androidx/heifwriter/AvifWriter.java"/>
+ </issue>
+
+ <issue
+ id="UnknownNullness"
+ message="Unknown nullability; explicitly declare as `@Nullable` or `@NonNull` to improve Kotlin interoperability; see https://developer.android.com/kotlin/interop#nullability_annotations"
errorLine1=" public void loadTexture(int texId, Bitmap bitmap) {"
errorLine2=" ~~~~~~">
<location
diff --git a/heifwriter/heifwriter/src/androidTest/java/androidx/heifwriter/AvifWriterTest.java b/heifwriter/heifwriter/src/androidTest/java/androidx/heifwriter/AvifWriterTest.java
new file mode 100644
index 0000000..5aadb65
--- /dev/null
+++ b/heifwriter/heifwriter/src/androidTest/java/androidx/heifwriter/AvifWriterTest.java
@@ -0,0 +1,425 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.heifwriter;
+
+import static androidx.heifwriter.AvifWriter.INPUT_MODE_BITMAP;
+import static androidx.heifwriter.AvifWriter.INPUT_MODE_BUFFER;
+import static androidx.heifwriter.AvifWriter.INPUT_MODE_SURFACE;
+import static androidx.test.core.app.ApplicationProvider.getApplicationContext;
+
+import android.Manifest;
+import android.graphics.Bitmap;
+import android.graphics.ImageFormat;
+import android.media.MediaFormat;
+import android.os.Handler;
+import android.os.HandlerThread;
+import android.os.Process;
+import android.util.Log;
+
+import androidx.heifwriter.test.R;
+import androidx.test.ext.junit.runners.AndroidJUnit4;
+import androidx.test.filters.FlakyTest;
+import androidx.test.filters.LargeTest;
+import androidx.test.filters.SdkSuppress;
+import androidx.test.filters.SmallTest;
+import androidx.test.rule.GrantPermissionRule;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+
+/**
+ * Test {@link AvifWriter}.
+ */
+@RunWith(AndroidJUnit4.class)
+@FlakyTest
+public class AvifWriterTest extends TestBase {
+ private static final String TAG = AvifWriterTest.class.getSimpleName();
+
+ @Rule
+ public GrantPermissionRule mRuntimePermissionRule1 =
+ GrantPermissionRule.grant(Manifest.permission.READ_EXTERNAL_STORAGE);
+
+ @Rule
+ public GrantPermissionRule mRuntimePermissionRule =
+ GrantPermissionRule.grant(Manifest.permission.WRITE_EXTERNAL_STORAGE);
+
+ private static final boolean DEBUG = true;
+ private static final boolean DUMP_YUV_INPUT = false;
+
+ private static final String AVIFWRITER_INPUT = "heifwriter_input.heic";
+ private static final int[] IMAGE_RESOURCES = new int[] {
+ R.raw.heifwriter_input
+ };
+ private static final String[] IMAGE_FILENAMES = new String[] {
+ AVIFWRITER_INPUT
+ };
+ private static final String OUTPUT_FILENAME = "output.avif";
+
+ private EglWindowSurface mInputEglSurface;
+ private Handler mHandler;
+ private int mInputIndex;
+
+ @Before
+ public void setUp() throws Exception {
+ for (int i = 0; i < IMAGE_RESOURCES.length; ++i) {
+ String outputPath = new File(getApplicationContext().getExternalFilesDir(null),
+ IMAGE_FILENAMES[i]).getAbsolutePath();
+
+ InputStream inputStream = null;
+ FileOutputStream outputStream = null;
+ try {
+ inputStream = getApplicationContext()
+ .getResources().openRawResource(IMAGE_RESOURCES[i]);
+ outputStream = new FileOutputStream(outputPath);
+ copy(inputStream, outputStream);
+ } finally {
+ closeQuietly(inputStream);
+ closeQuietly(outputStream);
+ }
+ }
+
+ HandlerThread handlerThread = new HandlerThread(
+ "AvifEncoderThread", Process.THREAD_PRIORITY_FOREGROUND);
+ handlerThread.start();
+ mHandler = new Handler(handlerThread.getLooper());
+ }
+
+ @After
+ public void tearDown() throws Exception {
+ for (int i = 0; i < IMAGE_RESOURCES.length; ++i) {
+ String imageFilePath = new File(getApplicationContext().getExternalFilesDir(null),
+ IMAGE_FILENAMES[i]).getAbsolutePath();
+ File imageFile = new File(imageFilePath);
+ if (imageFile.exists()) {
+ imageFile.delete();
+ }
+ }
+ }
+
+ @Test
+ @LargeTest
+ public void testInputBuffer_NoGrid_NoHandler() throws Throwable {
+ if (shouldSkip()) return;
+
+ TestConfig.Builder builder =
+ new TestConfig.Builder(INPUT_MODE_BUFFER, false, false, OUTPUT_FILENAME);
+ doTestForVariousNumberImages(builder);
+ }
+
+ @Test
+ @LargeTest
+ public void testInputBuffer_Grid_NoHandler() throws Throwable {
+ if (shouldSkip()) return;
+
+ TestConfig.Builder builder =
+ new TestConfig.Builder(INPUT_MODE_BUFFER, true, false, OUTPUT_FILENAME);
+ doTestForVariousNumberImages(builder);
+ }
+
+ @Test
+ @LargeTest
+ public void testInputBuffer_NoGrid_Handler() throws Throwable {
+ if (shouldSkip()) return;
+
+ TestConfig.Builder builder =
+ new TestConfig.Builder(INPUT_MODE_BUFFER, false, true, OUTPUT_FILENAME);
+ doTestForVariousNumberImages(builder);
+ }
+
+ @Test
+ @LargeTest
+ public void testInputBuffer_Grid_Handler() throws Throwable {
+ if (shouldSkip()) return;
+
+ TestConfig.Builder builder =
+ new TestConfig.Builder(INPUT_MODE_BUFFER, true, true, OUTPUT_FILENAME);
+ doTestForVariousNumberImages(builder);
+ }
+
+ @SdkSuppress(maxSdkVersion = 29) // b/192261638
+ @Test
+ @LargeTest
+ public void testInputSurface_NoGrid_NoHandler() throws Throwable {
+ if (shouldSkip()) return;
+
+ TestConfig.Builder builder =
+ new TestConfig.Builder(INPUT_MODE_SURFACE, false, false, OUTPUT_FILENAME);
+ doTestForVariousNumberImages(builder);
+ }
+ //
+ @SdkSuppress(maxSdkVersion = 29) // b/192261638
+ @Test
+ @LargeTest
+ public void testInputSurface_Grid_NoHandler() throws Throwable {
+ if (shouldSkip()) return;
+
+ TestConfig.Builder builder =
+ new TestConfig.Builder(INPUT_MODE_SURFACE, true, false, OUTPUT_FILENAME);
+ doTestForVariousNumberImages(builder);
+ }
+
+ @SdkSuppress(maxSdkVersion = 29) // b/192261638
+ @Test
+ @LargeTest
+ public void testInputSurface_NoGrid_Handler() throws Throwable {
+ if (shouldSkip()) return;
+
+ TestConfig.Builder builder =
+ new TestConfig.Builder(INPUT_MODE_SURFACE, false, true, OUTPUT_FILENAME);
+ doTestForVariousNumberImages(builder);
+ }
+
+ @SdkSuppress(maxSdkVersion = 29) // b/192261638
+ @Test
+ @LargeTest
+ public void testInputSurface_Grid_Handler() throws Throwable {
+ if (shouldSkip()) return;
+
+ TestConfig.Builder builder =
+ new TestConfig.Builder(INPUT_MODE_SURFACE, true, true, OUTPUT_FILENAME);
+ doTestForVariousNumberImages(builder);
+ }
+
+
+ @Test
+ @LargeTest
+ public void testInputBitmap_NoGrid_NoHandler() throws Throwable {
+ if (shouldSkip()) return;
+
+ TestConfig.Builder builder =
+ new TestConfig.Builder(INPUT_MODE_BITMAP, false, false, OUTPUT_FILENAME);
+ for (int i = 0; i < IMAGE_RESOURCES.length; ++i) {
+ String inputPath = new File(getApplicationContext().getExternalFilesDir(null),
+ IMAGE_FILENAMES[i]).getAbsolutePath();
+ doTestForVariousNumberImages(builder.setInputPath(inputPath));
+ }
+ }
+
+ @SdkSuppress(maxSdkVersion = 29) // b/192261638
+ @Test
+ @LargeTest
+ public void testInputBitmap_Grid_NoHandler() throws Throwable {
+ if (shouldSkip()) return;
+
+ TestConfig.Builder builder =
+ new TestConfig.Builder(INPUT_MODE_BITMAP, true, false, OUTPUT_FILENAME);
+ for (int i = 0; i < IMAGE_RESOURCES.length; ++i) {
+ String inputPath = new File(getApplicationContext().getExternalFilesDir(null),
+ IMAGE_FILENAMES[i]).getAbsolutePath();
+ doTestForVariousNumberImages(builder.setInputPath(inputPath));
+ }
+ }
+
+ @SdkSuppress(maxSdkVersion = 29) // b/192261638
+ @Test
+ @LargeTest
+ public void testInputBitmap_NoGrid_Handler() throws Throwable {
+ if (shouldSkip()) return;
+
+ TestConfig.Builder builder =
+ new TestConfig.Builder(INPUT_MODE_BITMAP, false, true, OUTPUT_FILENAME);
+ for (int i = 0; i < IMAGE_RESOURCES.length; ++i) {
+ String inputPath = new File(getApplicationContext().getExternalFilesDir(null),
+ IMAGE_FILENAMES[i]).getAbsolutePath();
+ doTestForVariousNumberImages(builder.setInputPath(inputPath));
+ }
+ }
+
+ @SdkSuppress(maxSdkVersion = 29) // b/192261638
+ @Test
+ @LargeTest
+ public void testInputBitmap_Grid_Handler() throws Throwable {
+ if (shouldSkip()) return;
+
+ TestConfig.Builder builder =
+ new TestConfig.Builder(INPUT_MODE_BITMAP, true, true, OUTPUT_FILENAME);
+ for (int i = 0; i < IMAGE_RESOURCES.length; ++i) {
+ String inputPath = new File(getApplicationContext().getExternalFilesDir(null),
+ IMAGE_FILENAMES[i]).getAbsolutePath();
+ doTestForVariousNumberImages(builder.setInputPath(inputPath));
+ }
+ }
+
+ @SdkSuppress(maxSdkVersion = 29) // b/192261638
+ @Test
+ @SmallTest
+ public void testCloseWithoutStart() throws Throwable {
+ if (shouldSkip()) return;
+
+ final String outputPath = new File(getApplicationContext().getExternalFilesDir(null),
+ OUTPUT_FILENAME).getAbsolutePath();
+ AvifWriter avifWriter = new AvifWriter.Builder(
+ outputPath, 1920, 1080, INPUT_MODE_SURFACE)
+ .setGridEnabled(true)
+ .setMaxImages(4)
+ .setQuality(90)
+ .setPrimaryIndex(0)
+ .setHandler(mHandler)
+ .build();
+
+ avifWriter.close();
+ }
+
+ private void drawFrame(int width, int height) {
+ mInputEglSurface.makeCurrent();
+ generateSurfaceFrame(mInputIndex, width, height);
+ mInputEglSurface.setPresentationTime(1000 * computePresentationTime(mInputIndex));
+ mInputEglSurface.swapBuffers();
+ mInputIndex++;
+ }
+
+ private void doTestForVariousNumberImages(TestConfig.Builder builder) throws Exception {
+ builder.setNumImages(4);
+ doTest(builder.setRotation(270).build());
+ doTest(builder.setRotation(180).build());
+ doTest(builder.setRotation(90).build());
+ doTest(builder.setRotation(0).build());
+ doTest(builder.setNumImages(1).build());
+ doTest(builder.setNumImages(8).build());
+ }
+
+ private boolean shouldSkip() {
+ return !hasEncoderForMime(MediaFormat.MIMETYPE_VIDEO_AV1);
+ }
+
+ private static byte[] mYuvData;
+ private void doTest(final TestConfig config) throws Exception {
+ final int width = config.mWidth;
+ final int height = config.mHeight;
+ final int actualNumImages = config.mActualNumImages;
+
+ mInputIndex = 0;
+ AvifWriter avifWriter = null;
+ FileInputStream inputStream = null;
+ FileOutputStream outputStream = null;
+ try {
+ if (DEBUG)
+ Log.d(TAG, "started: " + config);
+
+ avifWriter = new AvifWriter.Builder(
+ new File(getApplicationContext().getExternalFilesDir(null),
+ OUTPUT_FILENAME).getAbsolutePath(), width, height, config.mInputMode)
+ .setRotation(config.mRotation)
+ .setGridEnabled(config.mUseGrid)
+ .setMaxImages(config.mMaxNumImages)
+ .setQuality(config.mQuality)
+ .setPrimaryIndex(config.mMaxNumImages - 1)
+ .setHandler(config.mUseHandler ? mHandler : null)
+ .build();
+
+ if (config.mInputMode == INPUT_MODE_SURFACE) {
+ mInputEglSurface = new EglWindowSurface(avifWriter.getInputSurface());
+ }
+
+ avifWriter.start();
+
+ if (config.mInputMode == INPUT_MODE_BUFFER) {
+ if (mYuvData == null || mYuvData.length != width * height * 3 / 2) {
+ mYuvData = new byte[width * height * 3 / 2];
+ }
+
+ if (config.mInputPath != null) {
+ inputStream = new FileInputStream(config.mInputPath);
+ }
+
+ if (DUMP_YUV_INPUT) {
+ File outputFile = new File("/sdcard/input.yuv");
+ outputFile.createNewFile();
+ outputStream = new FileOutputStream(outputFile);
+ }
+
+ for (int i = 0; i < actualNumImages; i++) {
+ if (DEBUG)
+ Log.d(TAG, "fillYuvBuffer: " + i);
+ fillYuvBuffer(i, mYuvData, width, height, inputStream);
+ if (DUMP_YUV_INPUT) {
+ Log.d(TAG, "@@@ dumping input YUV");
+ outputStream.write(mYuvData);
+ }
+ avifWriter.addYuvBuffer(ImageFormat.YUV_420_888, mYuvData);
+ }
+ } else if (config.mInputMode == INPUT_MODE_SURFACE) {
+ // The input surface is a surface texture using single buffer mode, draws will be
+ // blocked until onFrameAvailable is done with the buffer, which is dependant on
+ // how fast MediaCodec processes them, which is further dependent on how fast the
+ // MediaCodec callbacks are handled. We can't put draws on the same looper that
+ // handles MediaCodec callback, it will cause deadlock.
+ for (int i = 0; i < actualNumImages; i++) {
+ if (DEBUG)
+ Log.d(TAG, "drawFrame: " + i);
+ drawFrame(width, height);
+ }
+ avifWriter.setInputEndOfStreamTimestamp(
+ 1000 * computePresentationTime(actualNumImages - 1));
+ } else if (config.mInputMode == INPUT_MODE_BITMAP) {
+ Bitmap[] bitmaps = config.mBitmaps;
+ for (int i = 0; i < Math.min(bitmaps.length, actualNumImages); i++) {
+ if (DEBUG)
+ Log.d(TAG, "addBitmap: " + i);
+ avifWriter.addBitmap(bitmaps[i]);
+ bitmaps[i].recycle();
+ }
+ }
+
+ avifWriter.stop(10000);
+ // The test sets the primary index to the last image.
+ // However, if we're testing early abort, the last image will not be
+ // present and the muxer is supposed to set it to 0 by default.
+ int expectedPrimary = config.mMaxNumImages - 1;
+ int expectedImageCount = config.mMaxNumImages;
+ if (actualNumImages < config.mMaxNumImages) {
+ expectedPrimary = 0;
+ expectedImageCount = actualNumImages;
+ }
+ verifyResult(config.mOutputPath, width, height, config.mRotation,
+ expectedImageCount, expectedPrimary, config.mUseGrid,
+ config.mInputMode == INPUT_MODE_SURFACE);
+ if (DEBUG)
+ Log.d(TAG, "finished: PASS");
+ } finally {
+ try {
+ if (outputStream != null) {
+ outputStream.close();
+ }
+ if (inputStream != null) {
+ inputStream.close();
+ }
+ } catch (IOException e) {
+ }
+
+ if (avifWriter != null) {
+ avifWriter.close();
+ avifWriter = null;
+ }
+ if (mInputEglSurface != null) {
+ // This also releases the surface from encoder.
+ mInputEglSurface.release();
+ mInputEglSurface = null;
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/heifwriter/heifwriter/src/androidTest/java/androidx/heifwriter/HeifWriterTest.java b/heifwriter/heifwriter/src/androidTest/java/androidx/heifwriter/HeifWriterTest.java
index b8e3752..f1f65ab 100644
--- a/heifwriter/heifwriter/src/androidTest/java/androidx/heifwriter/HeifWriterTest.java
+++ b/heifwriter/heifwriter/src/androidTest/java/androidx/heifwriter/HeifWriterTest.java
@@ -21,28 +21,15 @@
import static androidx.heifwriter.HeifWriter.INPUT_MODE_SURFACE;
import static androidx.test.core.app.ApplicationProvider.getApplicationContext;
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertTrue;
-
import android.Manifest;
import android.graphics.Bitmap;
-import android.graphics.BitmapFactory;
-import android.graphics.Color;
import android.graphics.ImageFormat;
-import android.graphics.Rect;
-import android.media.MediaCodecInfo;
-import android.media.MediaCodecList;
-import android.media.MediaExtractor;
import android.media.MediaFormat;
-import android.media.MediaMetadataRetriever;
-import android.opengl.GLES20;
import android.os.Handler;
import android.os.HandlerThread;
import android.os.Process;
import android.util.Log;
-import androidx.annotation.NonNull;
-import androidx.annotation.Nullable;
import androidx.heifwriter.test.R;
import androidx.test.ext.junit.runners.AndroidJUnit4;
import androidx.test.filters.FlakyTest;
@@ -58,62 +45,38 @@
import org.junit.Test;
import org.junit.runner.RunWith;
-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.io.OutputStream;
-import java.util.Arrays;
/**
* Test {@link HeifWriter}.
*/
@RunWith(AndroidJUnit4.class)
@FlakyTest
-public class HeifWriterTest {
+public class HeifWriterTest extends TestBase {
private static final String TAG = HeifWriterTest.class.getSimpleName();
- private static final MediaCodecList sMCL = new MediaCodecList(MediaCodecList.REGULAR_CODECS);
-
@Rule
public GrantPermissionRule mRuntimePermissionRule1 =
- GrantPermissionRule.grant(Manifest.permission.READ_EXTERNAL_STORAGE);
+ GrantPermissionRule.grant(Manifest.permission.READ_EXTERNAL_STORAGE);
@Rule
public GrantPermissionRule mRuntimePermissionRule =
- GrantPermissionRule.grant(Manifest.permission.WRITE_EXTERNAL_STORAGE);
+ GrantPermissionRule.grant(Manifest.permission.WRITE_EXTERNAL_STORAGE);
- private static final boolean DEBUG = false;
+ private static final boolean DEBUG = true;
private static final boolean DUMP_YUV_INPUT = false;
- private static final byte[][] TEST_YUV_COLORS = {
- {(byte) 255, (byte) 0, (byte) 0},
- {(byte) 255, (byte) 0, (byte) 255},
- {(byte) 255, (byte) 255, (byte) 255},
- {(byte) 255, (byte) 255, (byte) 0},
- };
- private static final Color COLOR_BLOCK =
- Color.valueOf(1.0f, 1.0f, 1.0f);
- private static final Color[] COLOR_BARS = {
- Color.valueOf(0.0f, 0.0f, 0.0f),
- Color.valueOf(0.0f, 0.0f, 0.64f),
- Color.valueOf(0.0f, 0.64f, 0.0f),
- Color.valueOf(0.0f, 0.64f, 0.64f),
- Color.valueOf(0.64f, 0.0f, 0.0f),
- Color.valueOf(0.64f, 0.0f, 0.64f),
- Color.valueOf(0.64f, 0.64f, 0.0f),
- };
- private static final float MAX_DELTA = 0.025f;
- private static final int BORDER_WIDTH = 16;
-
private static final String HEIFWRITER_INPUT = "heifwriter_input.heic";
private static final int[] IMAGE_RESOURCES = new int[] {
- R.raw.heifwriter_input
+ R.raw.heifwriter_input
};
private static final String[] IMAGE_FILENAMES = new String[] {
- HEIFWRITER_INPUT
+ HEIFWRITER_INPUT
};
private static final String OUTPUT_FILENAME = "output.heic";
@@ -125,13 +88,13 @@
public void setUp() throws Exception {
for (int i = 0; i < IMAGE_RESOURCES.length; ++i) {
String outputPath = new File(getApplicationContext().getExternalFilesDir(null),
- IMAGE_FILENAMES[i]).getAbsolutePath();
+ IMAGE_FILENAMES[i]).getAbsolutePath();
InputStream inputStream = null;
FileOutputStream outputStream = null;
try {
inputStream = getApplicationContext()
- .getResources().openRawResource(IMAGE_RESOURCES[i]);
+ .getResources().openRawResource(IMAGE_RESOURCES[i]);
outputStream = new FileOutputStream(outputPath);
copy(inputStream, outputStream);
} finally {
@@ -141,7 +104,7 @@
}
HandlerThread handlerThread = new HandlerThread(
- "HeifEncoderThread", Process.THREAD_PRIORITY_FOREGROUND);
+ "HeifEncoderThread", Process.THREAD_PRIORITY_FOREGROUND);
handlerThread.start();
mHandler = new Handler(handlerThread.getLooper());
}
@@ -150,7 +113,7 @@
public void tearDown() throws Exception {
for (int i = 0; i < IMAGE_RESOURCES.length; ++i) {
String imageFilePath = new File(getApplicationContext().getExternalFilesDir(null),
- IMAGE_FILENAMES[i]).getAbsolutePath();
+ IMAGE_FILENAMES[i]).getAbsolutePath();
File imageFile = new File(imageFilePath);
if (imageFile.exists()) {
imageFile.delete();
@@ -164,7 +127,8 @@
public void testInputBuffer_NoGrid_NoHandler() throws Throwable {
if (shouldSkip()) return;
- TestConfig.Builder builder = new TestConfig.Builder(INPUT_MODE_BUFFER, false, false);
+ TestConfig.Builder builder =
+ new TestConfig.Builder(INPUT_MODE_BUFFER, false, false, OUTPUT_FILENAME);
doTestForVariousNumberImages(builder);
}
@@ -174,7 +138,8 @@
public void testInputBuffer_Grid_NoHandler() throws Throwable {
if (shouldSkip()) return;
- TestConfig.Builder builder = new TestConfig.Builder(INPUT_MODE_BUFFER, true, false);
+ TestConfig.Builder builder =
+ new TestConfig.Builder(INPUT_MODE_BUFFER, true, false, OUTPUT_FILENAME);
doTestForVariousNumberImages(builder);
}
@@ -184,7 +149,8 @@
public void testInputBuffer_NoGrid_Handler() throws Throwable {
if (shouldSkip()) return;
- TestConfig.Builder builder = new TestConfig.Builder(INPUT_MODE_BUFFER, false, true);
+ TestConfig.Builder builder =
+ new TestConfig.Builder(INPUT_MODE_BUFFER, false, true, OUTPUT_FILENAME);
doTestForVariousNumberImages(builder);
}
@@ -194,7 +160,8 @@
public void testInputBuffer_Grid_Handler() throws Throwable {
if (shouldSkip()) return;
- TestConfig.Builder builder = new TestConfig.Builder(INPUT_MODE_BUFFER, true, true);
+ TestConfig.Builder builder =
+ new TestConfig.Builder(INPUT_MODE_BUFFER, true, true, OUTPUT_FILENAME);
doTestForVariousNumberImages(builder);
}
@@ -204,17 +171,19 @@
public void testInputSurface_NoGrid_NoHandler() throws Throwable {
if (shouldSkip()) return;
- TestConfig.Builder builder = new TestConfig.Builder(INPUT_MODE_SURFACE, false, false);
+ TestConfig.Builder builder =
+ new TestConfig.Builder(INPUT_MODE_SURFACE, false, false, OUTPUT_FILENAME);
doTestForVariousNumberImages(builder);
}
-
+ //
@SdkSuppress(maxSdkVersion = 29) // b/192261638
@Test
@LargeTest
public void testInputSurface_Grid_NoHandler() throws Throwable {
if (shouldSkip()) return;
- TestConfig.Builder builder = new TestConfig.Builder(INPUT_MODE_SURFACE, true, false);
+ TestConfig.Builder builder =
+ new TestConfig.Builder(INPUT_MODE_SURFACE, true, false, OUTPUT_FILENAME);
doTestForVariousNumberImages(builder);
}
@@ -224,7 +193,8 @@
public void testInputSurface_NoGrid_Handler() throws Throwable {
if (shouldSkip()) return;
- TestConfig.Builder builder = new TestConfig.Builder(INPUT_MODE_SURFACE, false, true);
+ TestConfig.Builder builder =
+ new TestConfig.Builder(INPUT_MODE_SURFACE, false, true, OUTPUT_FILENAME);
doTestForVariousNumberImages(builder);
}
@@ -234,20 +204,23 @@
public void testInputSurface_Grid_Handler() throws Throwable {
if (shouldSkip()) return;
- TestConfig.Builder builder = new TestConfig.Builder(INPUT_MODE_SURFACE, true, true);
+ TestConfig.Builder builder =
+ new TestConfig.Builder(INPUT_MODE_SURFACE, true, true, OUTPUT_FILENAME);
doTestForVariousNumberImages(builder);
}
+
@SdkSuppress(maxSdkVersion = 29) // b/192261638
@Test
@LargeTest
public void testInputBitmap_NoGrid_NoHandler() throws Throwable {
if (shouldSkip()) return;
- TestConfig.Builder builder = new TestConfig.Builder(INPUT_MODE_BITMAP, false, false);
+ TestConfig.Builder builder =
+ new TestConfig.Builder(INPUT_MODE_BITMAP, false, false, OUTPUT_FILENAME);
for (int i = 0; i < IMAGE_RESOURCES.length; ++i) {
String inputPath = new File(getApplicationContext().getExternalFilesDir(null),
- IMAGE_FILENAMES[i]).getAbsolutePath();
+ IMAGE_FILENAMES[i]).getAbsolutePath();
doTestForVariousNumberImages(builder.setInputPath(inputPath));
}
}
@@ -258,10 +231,11 @@
public void testInputBitmap_Grid_NoHandler() throws Throwable {
if (shouldSkip()) return;
- TestConfig.Builder builder = new TestConfig.Builder(INPUT_MODE_BITMAP, true, false);
+ TestConfig.Builder builder =
+ new TestConfig.Builder(INPUT_MODE_BITMAP, true, false, OUTPUT_FILENAME);
for (int i = 0; i < IMAGE_RESOURCES.length; ++i) {
String inputPath = new File(getApplicationContext().getExternalFilesDir(null),
- IMAGE_FILENAMES[i]).getAbsolutePath();
+ IMAGE_FILENAMES[i]).getAbsolutePath();
doTestForVariousNumberImages(builder.setInputPath(inputPath));
}
}
@@ -272,10 +246,11 @@
public void testInputBitmap_NoGrid_Handler() throws Throwable {
if (shouldSkip()) return;
- TestConfig.Builder builder = new TestConfig.Builder(INPUT_MODE_BITMAP, false, true);
+ TestConfig.Builder builder =
+ new TestConfig.Builder(INPUT_MODE_BITMAP, false, true, OUTPUT_FILENAME);
for (int i = 0; i < IMAGE_RESOURCES.length; ++i) {
String inputPath = new File(getApplicationContext().getExternalFilesDir(null),
- IMAGE_FILENAMES[i]).getAbsolutePath();
+ IMAGE_FILENAMES[i]).getAbsolutePath();
doTestForVariousNumberImages(builder.setInputPath(inputPath));
}
}
@@ -286,10 +261,11 @@
public void testInputBitmap_Grid_Handler() throws Throwable {
if (shouldSkip()) return;
- TestConfig.Builder builder = new TestConfig.Builder(INPUT_MODE_BITMAP, true, true);
+ TestConfig.Builder builder =
+ new TestConfig.Builder(INPUT_MODE_BITMAP, true, true, OUTPUT_FILENAME);
for (int i = 0; i < IMAGE_RESOURCES.length; ++i) {
String inputPath = new File(getApplicationContext().getExternalFilesDir(null),
- IMAGE_FILENAMES[i]).getAbsolutePath();
+ IMAGE_FILENAMES[i]).getAbsolutePath();
doTestForVariousNumberImages(builder.setInputPath(inputPath));
}
}
@@ -301,19 +277,27 @@
if (shouldSkip()) return;
final String outputPath = new File(getApplicationContext().getExternalFilesDir(null),
- OUTPUT_FILENAME).getAbsolutePath();
+ OUTPUT_FILENAME).getAbsolutePath();
HeifWriter heifWriter = new HeifWriter.Builder(
- outputPath, 1920, 1080, INPUT_MODE_SURFACE)
- .setGridEnabled(true)
- .setMaxImages(4)
- .setQuality(90)
- .setPrimaryIndex(0)
- .setHandler(mHandler)
- .build();
+ outputPath, 1920, 1080, INPUT_MODE_SURFACE)
+ .setGridEnabled(true)
+ .setMaxImages(4)
+ .setQuality(90)
+ .setPrimaryIndex(0)
+ .setHandler(mHandler)
+ .build();
heifWriter.close();
}
+ private void drawFrame(int width, int height) {
+ mInputEglSurface.makeCurrent();
+ generateSurfaceFrame(mInputIndex, width, height);
+ mInputEglSurface.setPresentationTime(1000 * computePresentationTime(mInputIndex));
+ mInputEglSurface.swapBuffers();
+ mInputIndex++;
+ }
+
private void doTestForVariousNumberImages(TestConfig.Builder builder) throws Exception {
builder.setNumImages(4);
doTest(builder.setRotation(270).build());
@@ -324,186 +308,11 @@
doTest(builder.setNumImages(8).build());
}
- private void closeQuietly(Closeable closeable) {
- if (closeable != null) {
- try {
- closeable.close();
- } catch (RuntimeException rethrown) {
- throw rethrown;
- } catch (Exception ignored) {
- }
- }
- }
-
- private int copy(InputStream in, OutputStream out) throws IOException {
- int total = 0;
- byte[] buffer = new byte[8192];
- int c;
- while ((c = in.read(buffer)) != -1) {
- total += c;
- out.write(buffer, 0, c);
- }
- return total;
- }
-
private boolean shouldSkip() {
return !hasEncoderForMime(MediaFormat.MIMETYPE_VIDEO_HEVC)
&& !hasEncoderForMime(MediaFormat.MIMETYPE_IMAGE_ANDROID_HEIC);
}
- private boolean hasEncoderForMime(String mime) {
- for (MediaCodecInfo info : sMCL.getCodecInfos()) {
- if (info.isEncoder()) {
- for (String type : info.getSupportedTypes()) {
- if (type.equalsIgnoreCase(mime)) {
- Log.i(TAG, "found codec " + info.getName() + " for mime " + mime);
- return true;
- }
- }
- }
- }
- return false;
- }
-
- private static class TestConfig {
- final int mInputMode;
- final boolean mUseGrid;
- final boolean mUseHandler;
- final int mMaxNumImages;
- final int mActualNumImages;
- final int mWidth;
- final int mHeight;
- final int mRotation;
- final int mQuality;
- final String mInputPath;
- final String mOutputPath;
- final Bitmap[] mBitmaps;
-
- TestConfig(int inputMode, boolean useGrid, boolean useHandler,
- int maxNumImages, int actualNumImages, int width, int height,
- int rotation, int quality,
- String inputPath, String outputPath, Bitmap[] bitmaps) {
- mInputMode = inputMode;
- mUseGrid = useGrid;
- mUseHandler = useHandler;
- mMaxNumImages = maxNumImages;
- mActualNumImages = actualNumImages;
- mWidth = width;
- mHeight = height;
- mRotation = rotation;
- mQuality = quality;
- mInputPath = inputPath;
- mOutputPath = outputPath;
- mBitmaps = bitmaps;
- }
-
- static class Builder {
- final int mInputMode;
- final boolean mUseGrid;
- final boolean mUseHandler;
- int mMaxNumImages;
- int mNumImages;
- int mWidth;
- int mHeight;
- int mRotation;
- final int mQuality;
- String mInputPath;
- final String mOutputPath;
- Bitmap[] mBitmaps;
- boolean mNumImagesSetExplicitly;
-
-
- Builder(int inputMode, boolean useGrids, boolean useHandler) {
- mInputMode = inputMode;
- mUseGrid = useGrids;
- mUseHandler = useHandler;
- mMaxNumImages = mNumImages = 4;
- mWidth = 1920;
- mHeight = 1080;
- mRotation = 0;
- mQuality = 100;
- mOutputPath = new File(getApplicationContext().getExternalFilesDir(null),
- OUTPUT_FILENAME).getAbsolutePath();
- }
-
- Builder setInputPath(String inputPath) {
- mInputPath = (mInputMode == INPUT_MODE_BITMAP) ? inputPath : null;
- return this;
- }
-
- Builder setNumImages(int numImages) {
- mNumImagesSetExplicitly = true;
- mNumImages = numImages;
- return this;
- }
-
- Builder setRotation(int rotation) {
- mRotation = rotation;
- return this;
- }
-
- private void loadBitmapInputs() {
- if (mInputMode != INPUT_MODE_BITMAP) {
- return;
- }
- MediaMetadataRetriever retriever = new MediaMetadataRetriever();
- retriever.setDataSource(mInputPath);
- String hasImage = retriever.extractMetadata(
- MediaMetadataRetriever.METADATA_KEY_HAS_IMAGE);
- if (!"yes".equals(hasImage)) {
- throw new IllegalArgumentException("no bitmap found!");
- }
- mMaxNumImages = Math.min(mMaxNumImages, Integer.parseInt(retriever.extractMetadata(
- MediaMetadataRetriever.METADATA_KEY_IMAGE_COUNT)));
- if (!mNumImagesSetExplicitly) {
- mNumImages = mMaxNumImages;
- }
- mBitmaps = new Bitmap[mMaxNumImages];
- for (int i = 0; i < mBitmaps.length; i++) {
- mBitmaps[i] = retriever.getImageAtIndex(i);
- }
- mWidth = mBitmaps[0].getWidth();
- mHeight = mBitmaps[0].getHeight();
- try {
- retriever.release();
- } catch (IOException e) {
- // Nothing we can do about it.
- }
- }
-
- private void cleanupStaleOutputs() {
- File outputFile = new File(mOutputPath);
- if (outputFile.exists()) {
- outputFile.delete();
- }
- }
-
- TestConfig build() {
- cleanupStaleOutputs();
- loadBitmapInputs();
-
- return new TestConfig(mInputMode, mUseGrid, mUseHandler, mMaxNumImages, mNumImages,
- mWidth, mHeight, mRotation, mQuality, mInputPath, mOutputPath, mBitmaps);
- }
- }
-
- @Override
- public String toString() {
- return "TestConfig"
- + ": mInputMode " + mInputMode
- + ", mUseGrid " + mUseGrid
- + ", mUseHandler " + mUseHandler
- + ", mMaxNumImages " + mMaxNumImages
- + ", mNumImages " + mActualNumImages
- + ", mWidth " + mWidth
- + ", mHeight " + mHeight
- + ", mRotation " + mRotation
- + ", mQuality " + mQuality
- + ", mInputPath " + mInputPath
- + ", mOutputPath " + mOutputPath;
- }
- }
-
private static byte[] mYuvData;
private void doTest(final TestConfig config) throws Exception {
final int width = config.mWidth;
@@ -515,17 +324,19 @@
FileInputStream inputStream = null;
FileOutputStream outputStream = null;
try {
- if (DEBUG) Log.d(TAG, "started: " + config);
+ if (DEBUG)
+ Log.d(TAG, "started: " + config);
heifWriter = new HeifWriter.Builder(
- config.mOutputPath, width, height, config.mInputMode)
- .setRotation(config.mRotation)
- .setGridEnabled(config.mUseGrid)
- .setMaxImages(config.mMaxNumImages)
- .setQuality(config.mQuality)
- .setPrimaryIndex(config.mMaxNumImages - 1)
- .setHandler(config.mUseHandler ? mHandler : null)
- .build();
+ new File(getApplicationContext().getExternalFilesDir(null),
+ OUTPUT_FILENAME).getAbsolutePath(), width, height, config.mInputMode)
+ .setRotation(config.mRotation)
+ .setGridEnabled(config.mUseGrid)
+ .setMaxImages(config.mMaxNumImages)
+ .setQuality(config.mQuality)
+ .setPrimaryIndex(config.mMaxNumImages - 1)
+ .setHandler(config.mUseHandler ? mHandler : null)
+ .build();
if (config.mInputMode == INPUT_MODE_SURFACE) {
mInputEglSurface = new EglWindowSurface(heifWriter.getInputSurface());
@@ -549,7 +360,8 @@
}
for (int i = 0; i < actualNumImages; i++) {
- if (DEBUG) Log.d(TAG, "fillYuvBuffer: " + i);
+ if (DEBUG)
+ Log.d(TAG, "fillYuvBuffer: " + i);
fillYuvBuffer(i, mYuvData, width, height, inputStream);
if (DUMP_YUV_INPUT) {
Log.d(TAG, "@@@ dumping input YUV");
@@ -564,15 +376,17 @@
// MediaCodec callbacks are handled. We can't put draws on the same looper that
// handles MediaCodec callback, it will cause deadlock.
for (int i = 0; i < actualNumImages; i++) {
- if (DEBUG) Log.d(TAG, "drawFrame: " + i);
+ if (DEBUG)
+ Log.d(TAG, "drawFrame: " + i);
drawFrame(width, height);
}
heifWriter.setInputEndOfStreamTimestamp(
- 1000 * computePresentationTime(actualNumImages - 1));
+ 1000 * computePresentationTime(actualNumImages - 1));
} else if (config.mInputMode == INPUT_MODE_BITMAP) {
Bitmap[] bitmaps = config.mBitmaps;
for (int i = 0; i < Math.min(bitmaps.length, actualNumImages); i++) {
- if (DEBUG) Log.d(TAG, "addBitmap: " + i);
+ if (DEBUG)
+ Log.d(TAG, "addBitmap: " + i);
heifWriter.addBitmap(bitmaps[i]);
bitmaps[i].recycle();
}
@@ -589,9 +403,10 @@
expectedImageCount = actualNumImages;
}
verifyResult(config.mOutputPath, width, height, config.mRotation,
- expectedImageCount, expectedPrimary, config.mUseGrid,
- config.mInputMode == INPUT_MODE_SURFACE);
- if (DEBUG) Log.d(TAG, "finished: PASS");
+ expectedImageCount, expectedPrimary, config.mUseGrid,
+ config.mInputMode == INPUT_MODE_SURFACE);
+ if (DEBUG)
+ Log.d(TAG, "finished: PASS");
} finally {
try {
if (outputStream != null) {
@@ -600,7 +415,8 @@
if (inputStream != null) {
inputStream.close();
}
- } catch (IOException e) {}
+ } catch (IOException e) {
+ }
if (heifWriter != null) {
heifWriter.close();
@@ -613,139 +429,4 @@
}
}
}
-
- private long computePresentationTime(int frameIndex) {
- return 132 + (long)frameIndex * 1000000;
- }
-
- private void fillYuvBuffer(int frameIndex, @NonNull byte[] data, int width, int height,
- @Nullable FileInputStream inputStream) throws IOException {
- if (inputStream != null) {
- inputStream.read(data);
- } else {
- byte[] color = TEST_YUV_COLORS[frameIndex % TEST_YUV_COLORS.length];
- int sizeY = width * height;
- Arrays.fill(data, 0, sizeY, color[0]);
- Arrays.fill(data, sizeY, sizeY * 5 / 4, color[1]);
- Arrays.fill(data, sizeY * 5 / 4, sizeY * 3 / 2, color[2]);
- }
- }
-
- private void drawFrame(int width, int height) {
- mInputEglSurface.makeCurrent();
- generateSurfaceFrame(mInputIndex, width, height);
- mInputEglSurface.setPresentationTime(1000 * computePresentationTime(mInputIndex));
- mInputEglSurface.swapBuffers();
- mInputIndex++;
- }
-
- private static Rect getColorBarRect(int index, int width, int height) {
- int barWidth = (width - BORDER_WIDTH * 2) / COLOR_BARS.length;
- return new Rect(BORDER_WIDTH + barWidth * index, BORDER_WIDTH,
- BORDER_WIDTH + barWidth * (index + 1), height - BORDER_WIDTH);
- }
-
- private static Rect getColorBlockRect(int index, int width, int height) {
- int blockCenterX = (width / 5) * (index % 4 + 1);
- return new Rect(blockCenterX - width / 10, height / 6,
- blockCenterX + width / 10, height / 3);
- }
-
- private void generateSurfaceFrame(int frameIndex, int width, int height) {
- GLES20.glViewport(0, 0, width, height);
- GLES20.glDisable(GLES20.GL_SCISSOR_TEST);
- GLES20.glClearColor(1.0f, 0.0f, 0.0f, 1.0f);
- GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT);
- GLES20.glEnable(GLES20.GL_SCISSOR_TEST);
-
- for (int i = 0; i < COLOR_BARS.length; i++) {
- Rect r = getColorBarRect(i, width, height);
-
- GLES20.glScissor(r.left, r.top, r.width(), r.height());
- final Color color = COLOR_BARS[i];
- GLES20.glClearColor(color.red(), color.green(), color.blue(), 1.0f);
- GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT);
- }
-
- Rect r = getColorBlockRect(frameIndex, width, height);
- GLES20.glScissor(r.left, r.top, r.width(), r.height());
- GLES20.glClearColor(0.5f, 0.5f, 0.5f, 1.0f);
- GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT);
- r.inset(BORDER_WIDTH, BORDER_WIDTH);
- GLES20.glScissor(r.left, r.top, r.width(), r.height());
- GLES20.glClearColor(COLOR_BLOCK.red(), COLOR_BLOCK.green(), COLOR_BLOCK.blue(), 1.0f);
- GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT);
- }
-
- /**
- * Determines if two color values are approximately equal.
- */
- private static boolean approxEquals(Color expected, Color actual) {
- return (Math.abs(expected.red() - actual.red()) <= MAX_DELTA)
- && (Math.abs(expected.green() - actual.green()) <= MAX_DELTA)
- && (Math.abs(expected.blue() - actual.blue()) <= MAX_DELTA);
- }
-
- private void verifyResult(
- String filename, int width, int height, int rotation,
- int imageCount, int primary, boolean useGrid, boolean checkColor)
- throws Exception {
- MediaMetadataRetriever retriever = new MediaMetadataRetriever();
- retriever.setDataSource(filename);
- String hasImage = retriever.extractMetadata(MediaMetadataRetriever.METADATA_KEY_HAS_IMAGE);
- if (!"yes".equals(hasImage)) {
- throw new Exception("No images found in file " + filename);
- }
- assertEquals("Wrong width", width,
- Integer.parseInt(retriever.extractMetadata(
- MediaMetadataRetriever.METADATA_KEY_IMAGE_WIDTH)));
- assertEquals("Wrong height", height,
- Integer.parseInt(retriever.extractMetadata(
- MediaMetadataRetriever.METADATA_KEY_IMAGE_HEIGHT)));
- assertEquals("Wrong rotation", rotation,
- Integer.parseInt(retriever.extractMetadata(
- MediaMetadataRetriever.METADATA_KEY_IMAGE_ROTATION)));
- assertEquals("Wrong image count", imageCount,
- Integer.parseInt(retriever.extractMetadata(
- MediaMetadataRetriever.METADATA_KEY_IMAGE_COUNT)));
- assertEquals("Wrong primary index", primary,
- Integer.parseInt(retriever.extractMetadata(
- MediaMetadataRetriever.METADATA_KEY_IMAGE_PRIMARY)));
- try {
- retriever.release();
- } catch (IOException e) {
- // Nothing we can do about it.
- }
-
- if (useGrid) {
- MediaExtractor extractor = new MediaExtractor();
- extractor.setDataSource(filename);
- MediaFormat format = extractor.getTrackFormat(0);
- int tileWidth = format.getInteger(MediaFormat.KEY_TILE_WIDTH);
- int tileHeight = format.getInteger(MediaFormat.KEY_TILE_HEIGHT);
- int gridRows = format.getInteger(MediaFormat.KEY_GRID_ROWS);
- int gridCols = format.getInteger(MediaFormat.KEY_GRID_COLUMNS);
- assertTrue("Wrong tile width or grid cols",
- ((width + tileWidth - 1) / tileWidth) == gridCols);
- assertTrue("Wrong tile height or grid rows",
- ((height + tileHeight - 1) / tileHeight) == gridRows);
- extractor.release();
- }
-
- if (checkColor) {
- Bitmap bitmap = BitmapFactory.decodeFile(filename);
-
- for (int i = 0; i < COLOR_BARS.length; i++) {
- Rect r = getColorBarRect(i, width, height);
- assertTrue("Color bar " + i + " doesn't match", approxEquals(COLOR_BARS[i],
- Color.valueOf(bitmap.getPixel(r.centerX(), r.centerY()))));
- }
-
- Rect r = getColorBlockRect(primary, width, height);
- assertTrue("Color block doesn't match", approxEquals(COLOR_BLOCK,
- Color.valueOf(bitmap.getPixel(r.centerX(), height - r.centerY()))));
-
- bitmap.recycle();
- }
- }
-}
+}
\ No newline at end of file
diff --git a/heifwriter/heifwriter/src/androidTest/java/androidx/heifwriter/TestBase.java b/heifwriter/heifwriter/src/androidTest/java/androidx/heifwriter/TestBase.java
new file mode 100644
index 0000000..83938e4
--- /dev/null
+++ b/heifwriter/heifwriter/src/androidTest/java/androidx/heifwriter/TestBase.java
@@ -0,0 +1,377 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package androidx.heifwriter;
+
+import static androidx.heifwriter.HeifWriter.INPUT_MODE_BITMAP;
+import static androidx.test.core.app.ApplicationProvider.getApplicationContext;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+
+import android.graphics.Bitmap;
+import android.graphics.BitmapFactory;
+import android.graphics.Color;
+import android.graphics.Rect;
+import android.media.MediaCodecInfo;
+import android.media.MediaCodecList;
+import android.media.MediaExtractor;
+import android.media.MediaFormat;
+import android.media.MediaMetadataRetriever;
+import android.opengl.GLES20;
+import android.util.Log;
+
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+
+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.io.OutputStream;
+import java.util.Arrays;
+
+/**
+ * Base class holding common utilities for {@link HeifWriterTest} and {@link AvifWriterTest}.
+ */
+public class TestBase {
+ private static final String TAG = HeifWriterTest.class.getSimpleName();
+
+ private static final MediaCodecList sMCL = new MediaCodecList(MediaCodecList.REGULAR_CODECS);
+
+ private static final byte[][] TEST_YUV_COLORS = {
+ {(byte) 255, (byte) 0, (byte) 0},
+ {(byte) 255, (byte) 0, (byte) 255},
+ {(byte) 255, (byte) 255, (byte) 255},
+ {(byte) 255, (byte) 255, (byte) 0},
+ };
+ private static final Color COLOR_BLOCK =
+ Color.valueOf(1.0f, 1.0f, 1.0f);
+ private static final Color[] COLOR_BARS = {
+ Color.valueOf(0.0f, 0.0f, 0.0f),
+ Color.valueOf(0.0f, 0.0f, 0.64f),
+ Color.valueOf(0.0f, 0.64f, 0.0f),
+ Color.valueOf(0.0f, 0.64f, 0.64f),
+ Color.valueOf(0.64f, 0.0f, 0.0f),
+ Color.valueOf(0.64f, 0.0f, 0.64f),
+ Color.valueOf(0.64f, 0.64f, 0.0f),
+ };
+ private static final float MAX_DELTA = 0.025f;
+ private static final int BORDER_WIDTH = 16;
+
+ protected long computePresentationTime(int frameIndex) {
+ return 132 + (long)frameIndex * 1000000;
+ }
+
+ protected void fillYuvBuffer(int frameIndex, @NonNull byte[] data, int width, int height,
+ @Nullable FileInputStream inputStream) throws IOException {
+ if (inputStream != null) {
+ inputStream.read(data);
+ } else {
+ byte[] color = TEST_YUV_COLORS[frameIndex % TEST_YUV_COLORS.length];
+ int sizeY = width * height;
+ Arrays.fill(data, 0, sizeY, color[0]);
+ Arrays.fill(data, sizeY, sizeY * 5 / 4, color[1]);
+ Arrays.fill(data, sizeY * 5 / 4, sizeY * 3 / 2, color[2]);
+ }
+ }
+
+ protected static Rect getColorBarRect(int index, int width, int height) {
+ int barWidth = (width - BORDER_WIDTH * 2) / COLOR_BARS.length;
+ return new Rect(BORDER_WIDTH + barWidth * index, BORDER_WIDTH,
+ BORDER_WIDTH + barWidth * (index + 1), height - BORDER_WIDTH);
+ }
+
+ protected static Rect getColorBlockRect(int index, int width, int height) {
+ int blockCenterX = (width / 5) * (index % 4 + 1);
+ return new Rect(blockCenterX - width / 10, height / 6,
+ blockCenterX + width / 10, height / 3);
+ }
+
+ protected void generateSurfaceFrame(int frameIndex, int width, int height) {
+ GLES20.glViewport(0, 0, width, height);
+ GLES20.glDisable(GLES20.GL_SCISSOR_TEST);
+ GLES20.glClearColor(1.0f, 0.0f, 0.0f, 1.0f);
+ GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT);
+ GLES20.glEnable(GLES20.GL_SCISSOR_TEST);
+
+ for (int i = 0; i < COLOR_BARS.length; i++) {
+ Rect r = getColorBarRect(i, width, height);
+
+ GLES20.glScissor(r.left, r.top, r.width(), r.height());
+ final Color color = COLOR_BARS[i];
+ GLES20.glClearColor(color.red(), color.green(), color.blue(), 1.0f);
+ GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT);
+ }
+
+ Rect r = getColorBlockRect(frameIndex, width, height);
+ GLES20.glScissor(r.left, r.top, r.width(), r.height());
+ GLES20.glClearColor(0.5f, 0.5f, 0.5f, 1.0f);
+ GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT);
+ r.inset(BORDER_WIDTH, BORDER_WIDTH);
+ GLES20.glScissor(r.left, r.top, r.width(), r.height());
+ GLES20.glClearColor(COLOR_BLOCK.red(), COLOR_BLOCK.green(), COLOR_BLOCK.blue(), 1.0f);
+ GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT);
+ }
+
+ /**
+ * Determines if two color values are approximately equal.
+ */
+ protected static boolean approxEquals(Color expected, Color actual) {
+ return (Math.abs(expected.red() - actual.red()) <= MAX_DELTA)
+ && (Math.abs(expected.green() - actual.green()) <= MAX_DELTA)
+ && (Math.abs(expected.blue() - actual.blue()) <= MAX_DELTA);
+ }
+
+ protected void verifyResult(
+ String filename, int width, int height, int rotation,
+ int imageCount, int primary, boolean useGrid, boolean checkColor)
+ throws Exception {
+ MediaMetadataRetriever retriever = new MediaMetadataRetriever();
+ retriever.setDataSource(filename);
+ String hasImage = retriever.extractMetadata(MediaMetadataRetriever.METADATA_KEY_HAS_IMAGE);
+ if (!"yes".equals(hasImage)) {
+ throw new Exception("No images found in file " + filename);
+ }
+ assertEquals("Wrong width", width,
+ Integer.parseInt(retriever.extractMetadata(
+ MediaMetadataRetriever.METADATA_KEY_IMAGE_WIDTH)));
+ assertEquals("Wrong height", height,
+ Integer.parseInt(retriever.extractMetadata(
+ MediaMetadataRetriever.METADATA_KEY_IMAGE_HEIGHT)));
+ assertEquals("Wrong rotation", rotation,
+ Integer.parseInt(retriever.extractMetadata(
+ MediaMetadataRetriever.METADATA_KEY_IMAGE_ROTATION)));
+ assertEquals("Wrong image count", imageCount,
+ Integer.parseInt(retriever.extractMetadata(
+ MediaMetadataRetriever.METADATA_KEY_IMAGE_COUNT)));
+ assertEquals("Wrong primary index", primary,
+ Integer.parseInt(retriever.extractMetadata(
+ MediaMetadataRetriever.METADATA_KEY_IMAGE_PRIMARY)));
+ try {
+ retriever.release();
+ } catch (IOException e) {
+ // Nothing we can do about it.
+ }
+
+ if (useGrid) {
+ MediaExtractor extractor = new MediaExtractor();
+ extractor.setDataSource(filename);
+ MediaFormat format = extractor.getTrackFormat(0);
+ int tileWidth = format.getInteger(MediaFormat.KEY_TILE_WIDTH);
+ int tileHeight = format.getInteger(MediaFormat.KEY_TILE_HEIGHT);
+ int gridRows = format.getInteger(MediaFormat.KEY_GRID_ROWS);
+ int gridCols = format.getInteger(MediaFormat.KEY_GRID_COLUMNS);
+ assertTrue("Wrong tile width or grid cols",
+ ((width + tileWidth - 1) / tileWidth) == gridCols);
+ assertTrue("Wrong tile height or grid rows",
+ ((height + tileHeight - 1) / tileHeight) == gridRows);
+ extractor.release();
+ }
+
+ if (checkColor) {
+ Bitmap bitmap = BitmapFactory.decodeFile(filename);
+
+ for (int i = 0; i < COLOR_BARS.length; i++) {
+ Rect r = getColorBarRect(i, width, height);
+ assertTrue("Color bar " + i + " doesn't match", approxEquals(COLOR_BARS[i],
+ Color.valueOf(bitmap.getPixel(r.centerX(), r.centerY()))));
+ }
+
+ Rect r = getColorBlockRect(primary, width, height);
+ assertTrue("Color block doesn't match", approxEquals(COLOR_BLOCK,
+ Color.valueOf(bitmap.getPixel(r.centerX(), height - r.centerY()))));
+
+ bitmap.recycle();
+ }
+ }
+
+ protected void closeQuietly(Closeable closeable) {
+ if (closeable != null) {
+ try {
+ closeable.close();
+ } catch (RuntimeException rethrown) {
+ throw rethrown;
+ } catch (Exception ignored) {
+ }
+ }
+ }
+
+ protected int copy(InputStream in, OutputStream out) throws IOException {
+ int total = 0;
+ byte[] buffer = new byte[8192];
+ int c;
+ while ((c = in.read(buffer)) != -1) {
+ total += c;
+ out.write(buffer, 0, c);
+ }
+ return total;
+ }
+
+ protected boolean hasEncoderForMime(String mime) {
+ for (MediaCodecInfo info : sMCL.getCodecInfos()) {
+ if (info.isEncoder()) {
+ for (String type : info.getSupportedTypes()) {
+ if (type.equalsIgnoreCase(mime)) {
+ Log.i(TAG, "found codec " + info.getName() + " for mime " + mime);
+ return true;
+ }
+ }
+ }
+ }
+ return false;
+ }
+
+ protected static class TestConfig {
+ final int mInputMode;
+ final boolean mUseGrid;
+ final boolean mUseHandler;
+ final int mMaxNumImages;
+ final int mActualNumImages;
+ final int mWidth;
+ final int mHeight;
+ final int mRotation;
+ final int mQuality;
+ final String mInputPath;
+ final String mOutputPath;
+ final Bitmap[] mBitmaps;
+
+ TestConfig(int inputMode, boolean useGrid, boolean useHandler,
+ int maxNumImages, int actualNumImages, int width, int height,
+ int rotation, int quality,
+ String inputPath, String outputPath, Bitmap[] bitmaps) {
+ mInputMode = inputMode;
+ mUseGrid = useGrid;
+ mUseHandler = useHandler;
+ mMaxNumImages = maxNumImages;
+ mActualNumImages = actualNumImages;
+ mWidth = width;
+ mHeight = height;
+ mRotation = rotation;
+ mQuality = quality;
+ mInputPath = inputPath;
+ mOutputPath = outputPath;
+ mBitmaps = bitmaps;
+ }
+
+ static class Builder {
+ final int mInputMode;
+ final boolean mUseGrid;
+ final boolean mUseHandler;
+ int mMaxNumImages;
+ int mNumImages;
+ int mWidth;
+ int mHeight;
+ int mRotation;
+ final int mQuality;
+ String mInputPath;
+ final String mOutputPath;
+ Bitmap[] mBitmaps;
+ boolean mNumImagesSetExplicitly;
+
+
+ Builder(int inputMode, boolean useGrids, boolean useHandler, String outputFileName) {
+ mInputMode = inputMode;
+ mUseGrid = useGrids;
+ mUseHandler = useHandler;
+ mMaxNumImages = mNumImages = 4;
+ mWidth = 1920;
+ mHeight = 1080;
+ mRotation = 0;
+ mQuality = 100;
+ mOutputPath = new File(getApplicationContext().getExternalFilesDir(null),
+ outputFileName).getAbsolutePath();
+ }
+
+ Builder setInputPath(String inputPath) {
+ mInputPath = (mInputMode == INPUT_MODE_BITMAP) ? inputPath : null;
+ return this;
+ }
+
+ Builder setNumImages(int numImages) {
+ mNumImagesSetExplicitly = true;
+ mNumImages = numImages;
+ return this;
+ }
+
+ Builder setRotation(int rotation) {
+ mRotation = rotation;
+ return this;
+ }
+
+ private void loadBitmapInputs() {
+ if (mInputMode != INPUT_MODE_BITMAP) {
+ return;
+ }
+ MediaMetadataRetriever retriever = new MediaMetadataRetriever();
+ retriever.setDataSource(mInputPath);
+ String hasImage = retriever.extractMetadata(
+ MediaMetadataRetriever.METADATA_KEY_HAS_IMAGE);
+ if (!"yes".equals(hasImage)) {
+ throw new IllegalArgumentException("no bitmap found!");
+ }
+ mMaxNumImages = Math.min(mMaxNumImages, Integer.parseInt(retriever.extractMetadata(
+ MediaMetadataRetriever.METADATA_KEY_IMAGE_COUNT)));
+ if (!mNumImagesSetExplicitly) {
+ mNumImages = mMaxNumImages;
+ }
+ mBitmaps = new Bitmap[mMaxNumImages];
+ for (int i = 0; i < mBitmaps.length; i++) {
+ mBitmaps[i] = retriever.getImageAtIndex(i);
+ }
+ mWidth = mBitmaps[0].getWidth();
+ mHeight = mBitmaps[0].getHeight();
+ try {
+ retriever.release();
+ } catch (IOException e) {
+ // Nothing we can do about it.
+ }
+ }
+
+ private void cleanupStaleOutputs() {
+ File outputFile = new File(mOutputPath);
+ if (outputFile.exists()) {
+ outputFile.delete();
+ }
+ }
+
+ TestConfig build() {
+ cleanupStaleOutputs();
+ loadBitmapInputs();
+
+ return new TestConfig(mInputMode, mUseGrid, mUseHandler, mMaxNumImages, mNumImages,
+ mWidth, mHeight, mRotation, mQuality, mInputPath, mOutputPath, mBitmaps);
+ }
+ }
+
+ @Override
+ public String toString() {
+ return "TestConfig"
+ + ": mInputMode " + mInputMode
+ + ", mUseGrid " + mUseGrid
+ + ", mUseHandler " + mUseHandler
+ + ", mMaxNumImages " + mMaxNumImages
+ + ", mNumImages " + mActualNumImages
+ + ", mWidth " + mWidth
+ + ", mHeight " + mHeight
+ + ", mRotation " + mRotation
+ + ", mQuality " + mQuality
+ + ", mInputPath " + mInputPath
+ + ", mOutputPath " + mOutputPath;
+ }
+ }
+}
\ No newline at end of file
diff --git a/heifwriter/heifwriter/src/main/java/androidx/heifwriter/AvifEncoder.java b/heifwriter/heifwriter/src/main/java/androidx/heifwriter/AvifEncoder.java
new file mode 100644
index 0000000..561e0b2
--- /dev/null
+++ b/heifwriter/heifwriter/src/main/java/androidx/heifwriter/AvifEncoder.java
@@ -0,0 +1,144 @@
+/*
+ * Copyright 2022 Google Inc. All rights reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.heifwriter;
+
+import android.media.MediaCodec;
+import android.media.MediaCodecInfo;
+import android.media.MediaCodecInfo.CodecCapabilities;
+import android.media.MediaCodecList;
+import android.media.MediaFormat;
+import android.os.Handler;
+import android.os.HandlerThread;
+import android.util.Log;
+import android.util.Range;
+
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+
+import java.io.IOException;
+
+/**
+ * This class encodes images into HEIF-compatible samples using AV1 encoder.
+ *
+ * It currently supports three input modes: {@link #INPUT_MODE_BUFFER},
+ * {@link #INPUT_MODE_SURFACE}, or {@link #INPUT_MODE_BITMAP}.
+ *
+ * The output format and samples are sent back in {@link
+ * Callback#onOutputFormatChanged(HeifEncoder, MediaFormat)} and {@link
+ * Callback#onDrainOutputBuffer(HeifEncoder, ByteBuffer)}. If the client
+ * requests to use grid, each tile will be sent back individually.
+ *
+ * HeifEncoder is made a separate class from {@link HeifWriter}, as some more
+ * advanced use cases might want to build solutions on top of the HeifEncoder directly.
+ * (eg. mux still images and video tracks into a single container).
+ *
+ * @hide
+ */
+public final class AvifEncoder extends EncoderBase {
+ private static final String TAG = "AvifEncoder";
+ private static final boolean DEBUG = false;
+
+ protected static final int GRID_WIDTH = 512;
+ protected static final int GRID_HEIGHT = 512;
+ protected static final double MAX_COMPRESS_RATIO = 0.25f;
+
+ private static final MediaCodecList sMCL =
+ new MediaCodecList(MediaCodecList.REGULAR_CODECS);
+
+ /**
+ * Configure the avif encoding session. Should only be called once.
+ *
+ * @param width Width of the image.
+ * @param height Height of the image.
+ * @param useGrid Whether to encode image into tiles. If enabled, tile size will be
+ * automatically chosen.
+ * @param quality A number between 0 and 100 (inclusive), with 100 indicating the best quality
+ * supported by this implementation (which often results in larger file size).
+ * @param inputMode The input type of this encoding session.
+ * @param handler If not null, client will receive all callbacks on the handler's looper.
+ * Otherwise, client will receive callbacks on a looper created by us.
+ * @param cb The callback to receive various messages from the avif encoder.
+ */
+ public AvifEncoder(int width, int height, boolean useGrid,
+ int quality, @InputMode int inputMode,
+ @Nullable Handler handler, @NonNull Callback cb,
+ boolean useBitDepth10) throws IOException {
+ super("AVIF", width, height, useGrid, quality, inputMode, handler, cb, useBitDepth10);
+ mEncoder.setCallback(new Av1EncoderCallback(), mHandler);
+ finishSettingUpEncoder(useBitDepth10);
+ }
+
+ protected static String findAv1Fallback() {
+ String av1 = null; // first AV1 encoder
+ for (MediaCodecInfo info : sMCL.getCodecInfos()) {
+ if (!info.isEncoder()) {
+ continue;
+ }
+ MediaCodecInfo.CodecCapabilities caps = null;
+ try {
+ caps = info.getCapabilitiesForType(MediaFormat.MIMETYPE_VIDEO_AV1);
+ } catch (IllegalArgumentException e) { // mime is not supported
+ continue;
+ }
+ if (!caps.getVideoCapabilities().isSizeSupported(GRID_WIDTH, GRID_HEIGHT)) {
+ continue;
+ }
+ if (caps.getEncoderCapabilities().isBitrateModeSupported(
+ MediaCodecInfo.EncoderCapabilities.BITRATE_MODE_CQ)) {
+ // Encoder that supports CQ mode is preferred over others,
+ // return the first encoder that supports CQ mode.
+ // (No need to check if it's hw based, it's already listed in
+ // order of preference.)
+ return info.getName();
+ }
+ if (av1 == null) {
+ av1 = info.getName();
+ }
+ }
+ // If no encoders support CQ, return the first AV1 encoder.
+ return av1;
+ }
+
+ /**
+ * MediaCodec callback for AV1 encoding.
+ */
+ @SuppressWarnings("WeakerAccess") /* synthetic access */
+ protected class Av1EncoderCallback extends EncoderCallback {
+ @Override
+ public void onOutputFormatChanged(MediaCodec codec, MediaFormat format) {
+ if (codec != mEncoder) return;
+
+ if (DEBUG) Log.d(TAG, "onOutputFormatChanged: " + format);
+
+ // TODO(b/252835975) replace "image/avif" with MIMETYPE_IMAGE_AVIF.
+ if (!format.getString(MediaFormat.KEY_MIME).equals("image/avif")) {
+ format.setString(MediaFormat.KEY_MIME, "image/avif");
+ format.setInteger(MediaFormat.KEY_WIDTH, mWidth);
+ format.setInteger(MediaFormat.KEY_HEIGHT, mHeight);
+
+ if (mUseGrid) {
+ format.setInteger(MediaFormat.KEY_TILE_WIDTH, mGridWidth);
+ format.setInteger(MediaFormat.KEY_TILE_HEIGHT, mGridHeight);
+ format.setInteger(MediaFormat.KEY_GRID_ROWS, mGridRows);
+ format.setInteger(MediaFormat.KEY_GRID_COLUMNS, mGridCols);
+ }
+ }
+
+ mCallback.onOutputFormatChanged(AvifEncoder.this, format);
+ }
+ }
+}
\ No newline at end of file
diff --git a/heifwriter/heifwriter/src/main/java/androidx/heifwriter/AvifWriter.java b/heifwriter/heifwriter/src/main/java/androidx/heifwriter/AvifWriter.java
new file mode 100644
index 0000000..706f9dfd
--- /dev/null
+++ b/heifwriter/heifwriter/src/main/java/androidx/heifwriter/AvifWriter.java
@@ -0,0 +1,330 @@
+/*
+ * Copyright 2022 Google Inc. All rights reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.heifwriter;
+
+import static android.media.MediaMuxer.OutputFormat.MUXER_OUTPUT_HEIF;
+
+import android.annotation.SuppressLint;
+import android.graphics.Bitmap;
+import android.media.MediaCodec;
+import android.media.MediaFormat;
+import android.media.MediaMuxer;
+import android.os.Handler;
+import android.os.HandlerThread;
+import android.os.Looper;
+import android.os.Process;
+import android.util.Log;
+import android.util.Pair;
+import android.view.Surface;
+
+import androidx.annotation.IntDef;
+import androidx.annotation.IntRange;
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+
+import java.io.FileDescriptor;
+import java.io.IOException;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.nio.ByteBuffer;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.concurrent.TimeoutException;
+import java.util.concurrent.atomic.AtomicBoolean;
+
+/**
+ * This class writes one or more still images (of the same dimensions) into
+ * an AVIF file.
+ *
+ * It currently supports three input modes: {@link #INPUT_MODE_BUFFER},
+ * {@link #INPUT_MODE_SURFACE}, or {@link #INPUT_MODE_BITMAP}.
+ *
+ * The general sequence (in pseudo-code) to write a avif file using this class is as follows:
+ *
+ * 1) Construct the writer:
+ * AvifWriter avifwriter = new AvifWriter(...);
+ *
+ * 2) If using surface input mode, obtain the input surface:
+ * Surface surface = avifwriter.getInputSurface();
+ *
+ * 3) Call start:
+ * avifwriter.start();
+ *
+ * 4) Depending on the chosen input mode, add one or more images using one of these methods:
+ * avifwriter.addYuvBuffer(...); Or
+ * avifwriter.addBitmap(...); Or
+ * render to the previously obtained surface
+ *
+ * 5) Call stop:
+ * avifwriter.stop(...);
+ *
+ * 6) Close the writer:
+ * avifwriter.close();
+ *
+ * Please refer to the documentations on individual methods for the exact usage.
+ */
+@SuppressWarnings("HiddenSuperclass")
+public final class AvifWriter extends WriterBase {
+
+ private static final String TAG = "AvifWriter";
+ private static final boolean DEBUG = false;
+
+ /**
+ * The input mode where the client adds input buffers with YUV data.
+ *
+ * @see #addYuvBuffer(int, byte[])
+ */
+ public static final int INPUT_MODE_BUFFER = WriterBase.INPUT_MODE_BUFFER;
+
+ /**
+ * The input mode where the client renders the images to an input Surface created by the writer.
+ *
+ * The input surface operates in single buffer mode. As a result, for use case where camera
+ * directly outputs to the input surface, this mode will not work because camera framework
+ * requires multiple buffers to operate in a pipeline fashion.
+ *
+ * @see #getInputSurface()
+ */
+ public static final int INPUT_MODE_SURFACE = WriterBase.INPUT_MODE_SURFACE;
+
+ /**
+ * The input mode where the client adds bitmaps.
+ *
+ * @see #addBitmap(Bitmap)
+ */
+ public static final int INPUT_MODE_BITMAP = WriterBase.INPUT_MODE_BITMAP;
+
+ /**
+ * @hide
+ */
+ @IntDef({
+ INPUT_MODE_BUFFER, INPUT_MODE_SURFACE, INPUT_MODE_BITMAP,
+ })
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface InputMode {
+
+ }
+
+ /**
+ * Builder class for constructing a AvifWriter object from specified parameters.
+ */
+ public static final class Builder {
+ private final String mPath;
+ private final FileDescriptor mFd;
+ private final int mWidth;
+ private final int mHeight;
+ private final @InputMode int mInputMode;
+ private boolean mGridEnabled = true;
+ private int mQuality = 100;
+ private int mMaxImages = 1;
+ private int mPrimaryIndex = 0;
+ private int mRotation = 0;
+ private Handler mHandler;
+ private boolean mHighBitDepthEnabled = false;
+
+ /**
+ * Construct a Builder with output specified by its path.
+ *
+ * @param path Path of the file to be written.
+ * @param width Width of the image in number of pixels.
+ * @param height Height of the image in number of pixels.
+ * @param inputMode Input mode for this writer, must be one of {@link #INPUT_MODE_BUFFER},
+ * {@link #INPUT_MODE_SURFACE}, or {@link #INPUT_MODE_BITMAP}.
+ */
+ public Builder(@NonNull String path,
+ @IntRange(from = 1) int width,
+ @IntRange(from = 1) int height,
+ @InputMode int inputMode) {
+ this(path, null, width, height, inputMode);
+ }
+
+ /**
+ * Construct a Builder with output specified by its file descriptor.
+ *
+ * @param fd File descriptor of the file to be written.
+ * @param width Width of the image in number of pixels.
+ * @param height Height of the image in number of pixels.
+ * @param inputMode Input mode for this writer, must be one of {@link #INPUT_MODE_BUFFER},
+ * {@link #INPUT_MODE_SURFACE}, or {@link #INPUT_MODE_BITMAP}.
+ */
+ public Builder(@NonNull FileDescriptor fd,
+ @IntRange(from = 1) int width,
+ @IntRange(from = 1) int height,
+ @InputMode int inputMode) {
+ this(null, fd, width, height, inputMode);
+ }
+
+ private Builder(String path, FileDescriptor fd,
+ @IntRange(from = 1) int width,
+ @IntRange(from = 1) int height,
+ @InputMode int inputMode) {
+ mPath = path;
+ mFd = fd;
+ mWidth = width;
+ mHeight = height;
+ mInputMode = inputMode;
+ }
+
+ /**
+ * Set the image rotation in degrees.
+ *
+ * @param rotation Rotation angle in degrees (clockwise) of the image, must be 0, 90,
+ * 180 or 270. Default is 0.
+ * @return this Builder object.
+ */
+ public @NonNull Builder setRotation(@IntRange(from = 0) int rotation) {
+ if (rotation != 0 && rotation != 90 && rotation != 180 && rotation != 270) {
+ throw new IllegalArgumentException("Invalid rotation angle: " + rotation);
+ }
+ mRotation = rotation;
+ return this;
+ }
+
+ /**
+ * Set whether to enable grid option.
+ *
+ * @param gridEnabled Whether to enable grid option. If enabled, the tile size will be
+ * automatically chosen. Default is to enable.
+ * @return this Builder object.
+ */
+ public @NonNull Builder setGridEnabled(boolean gridEnabled) {
+ mGridEnabled = gridEnabled;
+ return this;
+ }
+
+ /**
+ * Set the quality for encoding images.
+ *
+ * @param quality A number between 0 and 100 (inclusive), with 100 indicating the best
+ * quality supported by this implementation. Default is 100.
+ * @return this Builder object.
+ */
+ public @NonNull Builder setQuality(@IntRange(from = 0, to = 100) int quality) {
+ if (quality < 0 || quality > 100) {
+ throw new IllegalArgumentException("Invalid quality: " + quality);
+ }
+ mQuality = quality;
+ return this;
+ }
+
+ /**
+ * Set the maximum number of images to write.
+ *
+ * @param maxImages Max number of images to write. Frames exceeding this number will not be
+ * written to file. The writing can be stopped earlier before this number
+ * of images are written by {@link #stop(long)}, except for the input mode
+ * of {@link #INPUT_MODE_SURFACE}, where the EOS timestamp must be
+ * specified (via {@link #setInputEndOfStreamTimestamp(long)} and reached.
+ * Default is 1.
+ * @return this Builder object.
+ */
+ public @NonNull Builder setMaxImages(@IntRange(from = 1) int maxImages) {
+ if (maxImages <= 0) {
+ throw new IllegalArgumentException("Invalid maxImage: " + maxImages);
+ }
+ mMaxImages = maxImages;
+ return this;
+ }
+
+ /**
+ * Set the primary image index.
+ *
+ * @param primaryIndex Index of the image that should be marked as primary, must be within
+ * range [0, maxImages - 1] inclusive. Default is 0.
+ * @return this Builder object.
+ */
+ public @NonNull Builder setPrimaryIndex(@IntRange(from = 0) int primaryIndex) {
+ mPrimaryIndex = primaryIndex;
+ return this;
+ }
+
+ /**
+ * Provide a handler for the AvifWriter to use.
+ *
+ * @param handler If not null, client will receive all callbacks on the handler's looper.
+ * Otherwise, client will receive callbacks on a looper created by the
+ * writer. Default is null.
+ * @return this Builder object.
+ */
+ public @NonNull Builder setHandler(@Nullable Handler handler) {
+ mHandler = handler;
+ return this;
+ }
+
+ /**
+ * Provide a setting for the AvifWriter to use high bit-depth or not.
+ *
+ * @param highBitDepthEnabled Whether to enable high bit-depth mode. Default is false, if
+ * true, AvifWriter will encode with high bit-depth.
+ * @return this Builder object.
+ */
+ public @NonNull Builder setHighBitDepthEnabled(boolean highBitDepthEnabled) {
+ mHighBitDepthEnabled = highBitDepthEnabled;
+ return this;
+ }
+
+ /**
+ * Build a AvifWriter object.
+ *
+ * @return a AvifWriter object built according to the specifications.
+ * @throws IOException if failed to create the writer, possibly due to failure to create
+ * {@link android.media.MediaMuxer} or {@link android.media.MediaCodec}.
+ */
+ public @NonNull AvifWriter build() throws IOException {
+ return new AvifWriter(mPath, mFd, mWidth, mHeight, mRotation, mGridEnabled, mQuality,
+ mMaxImages, mPrimaryIndex, mInputMode, mHandler, mHighBitDepthEnabled);
+ }
+ }
+
+ @SuppressLint("WrongConstant")
+ @SuppressWarnings("WeakerAccess") /* synthetic access */
+ AvifWriter(@NonNull String path,
+ @NonNull FileDescriptor fd,
+ int width,
+ int height,
+ int rotation,
+ boolean gridEnabled,
+ int quality,
+ int maxImages,
+ int primaryIndex,
+ @InputMode int inputMode,
+ @Nullable Handler handler,
+ boolean highBitDepthEnabled) throws IOException {
+ super(rotation, inputMode, maxImages, primaryIndex, gridEnabled, quality,
+ handler, highBitDepthEnabled);
+
+ if (DEBUG) {
+ Log.d(TAG, "width: " + width
+ + ", height: " + height
+ + ", rotation: " + rotation
+ + ", gridEnabled: " + gridEnabled
+ + ", quality: " + quality
+ + ", maxImages: " + maxImages
+ + ", primaryIndex: " + primaryIndex
+ + ", inputMode: " + inputMode);
+ }
+
+ // set to 1 initially, and wait for output format to know for sure
+ mNumTiles = 1;
+
+ mMuxer = (path != null) ? new MediaMuxer(path, MUXER_OUTPUT_HEIF)
+ : new MediaMuxer(fd, MUXER_OUTPUT_HEIF);
+
+ mEncoder = new AvifEncoder(width, height, gridEnabled, quality,
+ mInputMode, mHandler, new WriterCallback(), highBitDepthEnabled);
+ }
+}
\ No newline at end of file
diff --git a/heifwriter/heifwriter/src/main/java/androidx/heifwriter/EglWindowSurface.java b/heifwriter/heifwriter/src/main/java/androidx/heifwriter/EglWindowSurface.java
index 35d34d4..c69e002 100644
--- a/heifwriter/heifwriter/src/main/java/androidx/heifwriter/EglWindowSurface.java
+++ b/heifwriter/heifwriter/src/main/java/androidx/heifwriter/EglWindowSurface.java
@@ -25,6 +25,8 @@
import android.util.Log;
import android.view.Surface;
+import androidx.annotation.NonNull;
+
import java.util.Objects;
/**
@@ -52,18 +54,22 @@
* Creates an EglWindowSurface from a Surface.
*/
public EglWindowSurface(Surface surface) {
+ this(surface, false);
+ }
+
+ public EglWindowSurface(Surface surface, boolean useHighBitDepth) {
if (surface == null) {
throw new NullPointerException();
}
mSurface = surface;
- eglSetup();
+ eglSetup(useHighBitDepth);
}
/**
* Prepares EGL. We want a GLES 2.0 context and a surface that supports recording.
*/
- private void eglSetup() {
+ private void eglSetup(boolean useHighBitDepth) {
mEGLDisplay = EGL14.eglGetDisplay(EGL14.EGL_DEFAULT_DISPLAY);
if (Objects.equals(mEGLDisplay, EGL14.EGL_NO_DISPLAY)) {
throw new RuntimeException("unable to get EGL14 display");
@@ -76,27 +82,31 @@
// Configure EGL for recordable and OpenGL ES 2.0. We want enough RGB bits
// to minimize artifacts from possible YUV conversion.
- int[] attribList = {
- EGL14.EGL_RED_SIZE, 8,
- EGL14.EGL_GREEN_SIZE, 8,
- EGL14.EGL_BLUE_SIZE, 8,
- EGL14.EGL_RENDERABLE_TYPE, EGL14.EGL_OPENGL_ES2_BIT,
- EGLExt.EGL_RECORDABLE_ANDROID, 1,
- EGL14.EGL_NONE
+ int eglColorSize = useHighBitDepth ? 10: 8;
+ int eglAlphaSize = useHighBitDepth ? 2: 0;
+ int recordable = useHighBitDepth ? 0: 1;
+ int[] configAttribList = {
+ EGL14.EGL_RED_SIZE, eglColorSize,
+ EGL14.EGL_GREEN_SIZE, eglColorSize,
+ EGL14.EGL_BLUE_SIZE, eglColorSize,
+ EGL14.EGL_ALPHA_SIZE, eglAlphaSize,
+ EGL14.EGL_RENDERABLE_TYPE, EGL14.EGL_OPENGL_ES2_BIT,
+ EGLExt.EGL_RECORDABLE_ANDROID, recordable,
+ EGL14.EGL_NONE
};
int[] numConfigs = new int[1];
- if (!EGL14.eglChooseConfig(mEGLDisplay, attribList, 0, mConfigs, 0, mConfigs.length,
- numConfigs, 0)) {
+ if (!EGL14.eglChooseConfig(mEGLDisplay, configAttribList, 0, mConfigs, 0, mConfigs.length,
+ numConfigs, 0)) {
throw new RuntimeException("unable to find RGB888+recordable ES2 EGL config");
}
// Configure context for OpenGL ES 2.0.
- int[] attrib_list = {
- EGL14.EGL_CONTEXT_CLIENT_VERSION, 2,
- EGL14.EGL_NONE
+ int[] contextAttribList = {
+ EGL14.EGL_CONTEXT_CLIENT_VERSION, 2,
+ EGL14.EGL_NONE
};
mEGLContext = EGL14.eglCreateContext(mEGLDisplay, mConfigs[0], EGL14.EGL_NO_CONTEXT,
- attrib_list, 0);
+ contextAttribList, 0);
checkEglError("eglCreateContext");
if (mEGLContext == null) {
throw new RuntimeException("null context");
@@ -188,7 +198,7 @@
/**
* Returns the Surface that the MediaCodec receives buffers from.
*/
- public Surface getSurface() {
+ public @NonNull Surface getSurface() {
return mSurface;
}
diff --git a/heifwriter/heifwriter/src/main/java/androidx/heifwriter/EncoderBase.java b/heifwriter/heifwriter/src/main/java/androidx/heifwriter/EncoderBase.java
new file mode 100644
index 0000000..5a30454
--- /dev/null
+++ b/heifwriter/heifwriter/src/main/java/androidx/heifwriter/EncoderBase.java
@@ -0,0 +1,1058 @@
+/*
+ * Copyright 2022 Google Inc. All rights reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.heifwriter;
+
+import android.graphics.Bitmap;
+import android.graphics.ImageFormat;
+import android.graphics.Rect;
+import android.graphics.SurfaceTexture;
+import android.media.Image;
+import android.media.MediaCodec;
+import android.media.MediaCodec.BufferInfo;
+import android.media.MediaCodec.CodecException;
+import android.media.MediaCodecInfo;
+import android.media.MediaCodecInfo.CodecCapabilities;
+import android.media.MediaCodecList;
+import android.media.MediaFormat;
+import android.opengl.GLES20;
+import android.os.Handler;
+import android.os.HandlerThread;
+import android.os.Looper;
+import android.os.Process;
+import android.util.Log;
+import android.util.Range;
+import android.view.Surface;
+
+import androidx.annotation.IntDef;
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+
+import java.io.IOException;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.nio.ByteBuffer;
+import java.util.ArrayList;
+import java.util.concurrent.atomic.AtomicBoolean;
+
+/**
+ * This class holds common utilities for {@link HeifEncoder} and {@link AvifEncoder}, and
+ * calls media framework and encodes images into HEIF- or AVIF- compatible samples using
+ * HEVC or AV1 encoder.
+ *
+ * It currently supports three input modes: {@link #INPUT_MODE_BUFFER},
+ * {@link #INPUT_MODE_SURFACE}, or {@link #INPUT_MODE_BITMAP}.
+ *
+ * Callback#onOutputFormatChanged(MediaCodec, MediaFormat)} and {@link
+ * Callback#onDrainOutputBuffer(MediaCodec, ByteBuffer)}. If the client
+ * requests to use grid, each tile will be sent back individually.
+ *
+ *
+ * * HeifEncoder is made a separate class from {@link HeifWriter}, as some more
+ * * advanced use cases might want to build solutions on top of the HeifEncoder directly.
+ * * (eg. mux still images and video tracks into a single container).
+ *
+ *
+ * @hide
+ */
+public class EncoderBase implements AutoCloseable,
+ SurfaceTexture.OnFrameAvailableListener {
+ private static final String TAG = "EncoderBase";
+ private static final boolean DEBUG = false;
+
+ private String MIME;
+ private int GRID_WIDTH;
+ private int GRID_HEIGHT;
+ private double MAX_COMPRESS_RATIO;
+ private int INPUT_BUFFER_POOL_SIZE = 2;
+
+ @SuppressWarnings("WeakerAccess") /* synthetic access */
+ MediaCodec mEncoder;
+ @SuppressWarnings("WeakerAccess") /* synthetic access */
+ final MediaFormat mCodecFormat;
+ @SuppressWarnings("WeakerAccess") /* synthetic access */
+ protected final Callback mCallback;
+ private final HandlerThread mHandlerThread;
+ @SuppressWarnings("WeakerAccess") /* synthetic access */
+ final Handler mHandler;
+ private final @InputMode int mInputMode;
+ private final boolean mUseBitDepth10;
+
+ @SuppressWarnings("WeakerAccess") /* synthetic access */
+ final int mWidth;
+ @SuppressWarnings("WeakerAccess") /* synthetic access */
+ protected final int mHeight;
+ @SuppressWarnings("WeakerAccess") /* synthetic access */
+ protected final int mGridWidth;
+ @SuppressWarnings("WeakerAccess") /* synthetic access */
+ protected final int mGridHeight;
+ @SuppressWarnings("WeakerAccess") /* synthetic access */
+ protected final int mGridRows;
+ @SuppressWarnings("WeakerAccess") /* synthetic access */
+ protected final int mGridCols;
+ private final int mNumTiles;
+ @SuppressWarnings("WeakerAccess") /* synthetic access */
+ final boolean mUseGrid;
+
+ private int mInputIndex;
+ @SuppressWarnings("WeakerAccess") /* synthetic access */
+ boolean mInputEOS;
+ private final Rect mSrcRect;
+ private final Rect mDstRect;
+ private ByteBuffer mCurrentBuffer;
+ private final ArrayList<ByteBuffer> mEmptyBuffers = new ArrayList<>();
+ private final ArrayList<ByteBuffer> mFilledBuffers = new ArrayList<>();
+ @SuppressWarnings("WeakerAccess") /* synthetic access */
+ final ArrayList<Integer> mCodecInputBuffers = new ArrayList<>();
+ private final boolean mCopyTiles;
+
+ // Helper for tracking EOS when surface is used
+ @SuppressWarnings("WeakerAccess") /* synthetic access */
+ SurfaceEOSTracker mEOSTracker;
+
+ // Below variables are to handle GL copy from client's surface
+ // to encoder surface when tiles are used.
+ private SurfaceTexture mInputTexture;
+ private Surface mInputSurface;
+ private Surface mEncoderSurface;
+ private EglWindowSurface mEncoderEglSurface;
+ private EglRectBlt mRectBlt;
+ private int mTextureId;
+ private final float[] mTmpMatrix = new float[16];
+ private final AtomicBoolean mStopping = new AtomicBoolean(false);
+
+ public static final int INPUT_MODE_BUFFER = HeifWriter.INPUT_MODE_BUFFER;
+ public static final int INPUT_MODE_SURFACE = HeifWriter.INPUT_MODE_SURFACE;
+ public static final int INPUT_MODE_BITMAP = HeifWriter.INPUT_MODE_BITMAP;
+ @IntDef({
+ INPUT_MODE_BUFFER,
+ INPUT_MODE_SURFACE,
+ INPUT_MODE_BITMAP,
+ })
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface InputMode {}
+
+ public static abstract class Callback {
+ /**
+ * Called when the output format has changed.
+ *
+ * @param encoder The EncoderBase object.
+ * @param format The new output format.
+ */
+ public abstract void onOutputFormatChanged(
+ @NonNull EncoderBase encoder, @NonNull MediaFormat format);
+
+ /**
+ * Called when an output buffer becomes available.
+ *
+ * @param encoder The EncoderBase object.
+ * @param byteBuffer the available output buffer.
+ */
+ public abstract void onDrainOutputBuffer(
+ @NonNull EncoderBase encoder, @NonNull ByteBuffer byteBuffer);
+
+ /**
+ * Called when encoding reached the end of stream without error.
+ *
+ * @param encoder The EncoderBase object.
+ */
+ public abstract void onComplete(@NonNull EncoderBase encoder);
+
+ /**
+ * Called when encoding hits an error.
+ *
+ * @param encoder The EncoderBase object.
+ * @param e The exception that the codec reported.
+ */
+ public abstract void onError(@NonNull EncoderBase encoder, @NonNull CodecException e);
+ }
+
+ /**
+ * Configure the encoder. Should only be called once.
+ *
+ * @param mimeType mime type. Currently it supports "HEIC" and "AVIF".
+ * @param width Width of the image.
+ * @param height Height of the image.
+ * @param useGrid Whether to encode image into tiles. If enabled, tile size will be
+ * automatically chosen.
+ * @param quality A number between 0 and 100 (inclusive), with 100 indicating the best quality
+ * supported by this implementation (which often results in larger file size).
+ * @param inputMode The input type of this encoding session.
+ * @param handler If not null, client will receive all callbacks on the handler's looper.
+ * Otherwise, client will receive callbacks on a looper created by us.
+ * @param cb The callback to receive various messages from the heif encoder.
+ */
+ protected EncoderBase(@NonNull String mimeType, int width, int height, boolean useGrid,
+ int quality, @InputMode int inputMode,
+ @Nullable Handler handler, @NonNull Callback cb,
+ boolean useBitDepth10) throws IOException {
+ if (DEBUG)
+ Log.d(TAG, "width: " + width + ", height: " + height +
+ ", useGrid: " + useGrid + ", quality: " + quality +
+ ", inputMode: " + inputMode +
+ ", useBitDepth10: " + String.valueOf(useBitDepth10));
+
+ if (width < 0 || height < 0 || quality < 0 || quality > 100) {
+ throw new IllegalArgumentException("invalid encoder inputs");
+ }
+
+ switch (mimeType) {
+ case "HEIC":
+ MIME = mimeType;
+ GRID_WIDTH = HeifEncoder.GRID_WIDTH;
+ GRID_HEIGHT = HeifEncoder.GRID_HEIGHT;
+ MAX_COMPRESS_RATIO = HeifEncoder.MAX_COMPRESS_RATIO;
+ break;
+ case "AVIF":
+ MIME = mimeType;
+ GRID_WIDTH = AvifEncoder.GRID_WIDTH;
+ GRID_HEIGHT = AvifEncoder.GRID_HEIGHT;
+ MAX_COMPRESS_RATIO = AvifEncoder.MAX_COMPRESS_RATIO;
+ break;
+ default:
+ Log.e(TAG, "Not supported mime type: " + mimeType);
+ }
+
+ boolean useHeicEncoder = false;
+ MediaCodecInfo.CodecCapabilities caps = null;
+ switch (MIME) {
+ case "HEIC":
+ try {
+ mEncoder = MediaCodec.createEncoderByType(
+ MediaFormat.MIMETYPE_IMAGE_ANDROID_HEIC);
+ caps = mEncoder.getCodecInfo().getCapabilitiesForType(
+ MediaFormat.MIMETYPE_IMAGE_ANDROID_HEIC);
+ // If the HEIC encoder can't support the size, fall back to HEVC encoder.
+ if (!caps.getVideoCapabilities().isSizeSupported(width, height)) {
+ mEncoder.release();
+ mEncoder = null;
+ throw new Exception();
+ }
+ useHeicEncoder = true;
+ } catch (Exception e) {
+ mEncoder = MediaCodec.createByCodecName(HeifEncoder.findHevcFallback());
+ caps = mEncoder.getCodecInfo()
+ .getCapabilitiesForType(MediaFormat.MIMETYPE_VIDEO_HEVC);
+ // Disable grid if the image is too small
+ useGrid &= (width > GRID_WIDTH || height > GRID_HEIGHT);
+ // Always enable grid if the size is too large for the HEVC encoder
+ useGrid |= !caps.getVideoCapabilities().isSizeSupported(width, height);
+ }
+ break;
+ case "AVIF":
+ mEncoder = MediaCodec.createByCodecName(AvifEncoder.findAv1Fallback());
+ caps = mEncoder.getCodecInfo()
+ .getCapabilitiesForType(MediaFormat.MIMETYPE_VIDEO_AV1);
+ // Disable grid if the image is too small
+ useGrid &= (width > GRID_WIDTH || height > GRID_HEIGHT);
+ // Always enable grid if the size is too large for the AV1 encoder
+ useGrid |= !caps.getVideoCapabilities().isSizeSupported(width, height);
+ break;
+ default:
+ Log.e(TAG, "Not supported mime type: " + MIME);
+ }
+
+ mInputMode = inputMode;
+ mUseBitDepth10 = useBitDepth10;
+ mCallback = cb;
+
+ Looper looper = (handler != null) ? handler.getLooper() : null;
+ if (looper == null) {
+ mHandlerThread = new HandlerThread("HeifEncoderThread",
+ Process.THREAD_PRIORITY_FOREGROUND);
+ mHandlerThread.start();
+ looper = mHandlerThread.getLooper();
+ } else {
+ mHandlerThread = null;
+ }
+ mHandler = new Handler(looper);
+ boolean useSurfaceInternally =
+ (inputMode == INPUT_MODE_SURFACE) || (inputMode == INPUT_MODE_BITMAP);
+ int colorFormat = useSurfaceInternally ? CodecCapabilities.COLOR_FormatSurface :
+ (useBitDepth10 ? CodecCapabilities.COLOR_FormatYUVP010 :
+ CodecCapabilities.COLOR_FormatYUV420Flexible);
+ mCopyTiles = (useGrid && !useHeicEncoder) || (inputMode == INPUT_MODE_BITMAP);
+
+ mWidth = width;
+ mHeight = height;
+ mUseGrid = useGrid;
+
+ int gridWidth, gridHeight, gridRows, gridCols;
+
+ if (useGrid) {
+ gridWidth = GRID_WIDTH;
+ gridHeight = GRID_HEIGHT;
+ gridRows = (height + GRID_HEIGHT - 1) / GRID_HEIGHT;
+ gridCols = (width + GRID_WIDTH - 1) / GRID_WIDTH;
+ } else {
+ gridWidth = mWidth;
+ gridHeight = mHeight;
+ gridRows = 1;
+ gridCols = 1;
+ }
+
+ MediaFormat codecFormat;
+ if (useHeicEncoder) {
+ codecFormat = MediaFormat.createVideoFormat(
+ MediaFormat.MIMETYPE_IMAGE_ANDROID_HEIC, mWidth, mHeight);
+ } else {
+ codecFormat = MediaFormat.createVideoFormat(
+ MediaFormat.MIMETYPE_VIDEO_HEVC, gridWidth, gridHeight);
+ }
+
+ if (useGrid) {
+ codecFormat.setInteger(MediaFormat.KEY_TILE_WIDTH, gridWidth);
+ codecFormat.setInteger(MediaFormat.KEY_TILE_HEIGHT, gridHeight);
+ codecFormat.setInteger(MediaFormat.KEY_GRID_COLUMNS, gridCols);
+ codecFormat.setInteger(MediaFormat.KEY_GRID_ROWS, gridRows);
+ }
+
+ if (useHeicEncoder) {
+ mGridWidth = width;
+ mGridHeight = height;
+ mGridRows = 1;
+ mGridCols = 1;
+ } else {
+ mGridWidth = gridWidth;
+ mGridHeight = gridHeight;
+ mGridRows = gridRows;
+ mGridCols = gridCols;
+ }
+ mNumTiles = mGridRows * mGridCols;
+
+ codecFormat.setInteger(MediaFormat.KEY_I_FRAME_INTERVAL, 0);
+ codecFormat.setInteger(MediaFormat.KEY_COLOR_FORMAT, colorFormat);
+ codecFormat.setInteger(MediaFormat.KEY_FRAME_RATE, mNumTiles);
+
+ // When we're doing tiles, set the operating rate higher as the size
+ // is small, otherwise set to the normal 30fps.
+ if (mNumTiles > 1) {
+ codecFormat.setInteger(MediaFormat.KEY_OPERATING_RATE, 120);
+ } else {
+ codecFormat.setInteger(MediaFormat.KEY_OPERATING_RATE, 30);
+ }
+
+ if (useSurfaceInternally && !mCopyTiles) {
+ // Use fixed PTS gap and disable backward frame drop
+ Log.d(TAG, "Setting fixed pts gap");
+ codecFormat.setLong(MediaFormat.KEY_MAX_PTS_GAP_TO_ENCODER, -1000000);
+ }
+
+ MediaCodecInfo.EncoderCapabilities encoderCaps = caps.getEncoderCapabilities();
+
+ if (encoderCaps.isBitrateModeSupported(
+ MediaCodecInfo.EncoderCapabilities.BITRATE_MODE_CQ)) {
+ Log.d(TAG, "Setting bitrate mode to constant quality");
+ Range<Integer> qualityRange = encoderCaps.getQualityRange();
+ Log.d(TAG, "Quality range: " + qualityRange);
+ codecFormat.setInteger(MediaFormat.KEY_BITRATE_MODE,
+ MediaCodecInfo.EncoderCapabilities.BITRATE_MODE_CQ);
+ codecFormat.setInteger(MediaFormat.KEY_QUALITY, (int) (qualityRange.getLower() +
+ (qualityRange.getUpper() - qualityRange.getLower()) * quality / 100.0));
+ } else {
+ if (encoderCaps.isBitrateModeSupported(
+ MediaCodecInfo.EncoderCapabilities.BITRATE_MODE_CBR)) {
+ Log.d(TAG, "Setting bitrate mode to constant bitrate");
+ codecFormat.setInteger(MediaFormat.KEY_BITRATE_MODE,
+ MediaCodecInfo.EncoderCapabilities.BITRATE_MODE_CBR);
+ } else { // assume VBR
+ Log.d(TAG, "Setting bitrate mode to variable bitrate");
+ codecFormat.setInteger(MediaFormat.KEY_BITRATE_MODE,
+ MediaCodecInfo.EncoderCapabilities.BITRATE_MODE_VBR);
+ }
+ // Calculate the bitrate based on image dimension, max compression ratio and quality.
+ // Note that we set the frame rate to the number of tiles, so the bitrate would be the
+ // intended bits for one image.
+ int bitrate = caps.getVideoCapabilities().getBitrateRange().clamp(
+ (int) (width * height * 1.5 * 8 * MAX_COMPRESS_RATIO * quality / 100.0f));
+ codecFormat.setInteger(MediaFormat.KEY_BIT_RATE, bitrate);
+ }
+
+ mCodecFormat = codecFormat;
+
+ mDstRect = new Rect(0, 0, mGridWidth, mGridHeight);
+ mSrcRect = new Rect();
+ }
+
+ /**
+ * Finish setting up the encoder.
+ * Call MediaCodec.configure() method so that mEncoder enters configured stage, then add input
+ * surface or add input buffers if needed.
+ *
+ * Note: this method must be called after the constructor.
+ */
+ protected void finishSettingUpEncoder(boolean useBitDepth10) {
+ boolean useSurfaceInternally =
+ (mInputMode == INPUT_MODE_SURFACE) || (mInputMode == INPUT_MODE_BITMAP);
+
+ mEncoder.configure(mCodecFormat, null, null, MediaCodec.CONFIGURE_FLAG_ENCODE);
+
+ if (useSurfaceInternally) {
+ mEncoderSurface = mEncoder.createInputSurface();
+
+ mEOSTracker = new SurfaceEOSTracker(mCopyTiles);
+
+ if (mCopyTiles) {
+ mEncoderEglSurface = new EglWindowSurface(mEncoderSurface, useBitDepth10);
+ mEncoderEglSurface.makeCurrent();
+
+ mRectBlt = new EglRectBlt(
+ new Texture2dProgram((mInputMode == INPUT_MODE_BITMAP)
+ ? Texture2dProgram.TEXTURE_2D
+ : Texture2dProgram.TEXTURE_EXT),
+ mWidth, mHeight);
+
+ mTextureId = mRectBlt.createTextureObject();
+
+ if (mInputMode == INPUT_MODE_SURFACE) {
+ // use single buffer mode to block on input
+ mInputTexture = new SurfaceTexture(mTextureId, true);
+ mInputTexture.setOnFrameAvailableListener(this);
+ mInputTexture.setDefaultBufferSize(mWidth, mHeight);
+ mInputSurface = new Surface(mInputTexture);
+ }
+
+ // make uncurrent since onFrameAvailable could be called on arbituray thread.
+ // making the context current on a different thread will cause error.
+ mEncoderEglSurface.makeUnCurrent();
+ } else {
+ mInputSurface = mEncoderSurface;
+ }
+ } else {
+ for (int i = 0; i < INPUT_BUFFER_POOL_SIZE; i++) {
+ int bufferSize = mUseBitDepth10 ? mWidth * mHeight * 3 : mWidth * mHeight * 3 / 2;
+ mEmptyBuffers.add(ByteBuffer.allocateDirect(bufferSize));
+ }
+ }
+ }
+
+ /**
+ * Copies from source frame to encoder inputs using GL. The source could be either
+ * client's input surface, or the input bitmap loaded to texture.
+ */
+ private void copyTilesGL() {
+ GLES20.glViewport(0, 0, mGridWidth, mGridHeight);
+
+ for (int row = 0; row < mGridRows; row++) {
+ for (int col = 0; col < mGridCols; col++) {
+ int left = col * mGridWidth;
+ int top = row * mGridHeight;
+ mSrcRect.set(left, top, left + mGridWidth, top + mGridHeight);
+ try {
+ mRectBlt.copyRect(mTextureId, Texture2dProgram.V_FLIP_MATRIX, mSrcRect);
+ } catch (RuntimeException e) {
+ // EGL copy could throw if the encoder input surface is no longer valid
+ // after encoder is released. This is not an error because we're already
+ // stopping (either after EOS is received or requested by client).
+ if (mStopping.get()) {
+ return;
+ }
+ throw e;
+ }
+ mEncoderEglSurface.setPresentationTime(
+ 1000 * computePresentationTime(mInputIndex++));
+ mEncoderEglSurface.swapBuffers();
+ }
+ }
+ }
+
+ @Override
+ public void onFrameAvailable(SurfaceTexture surfaceTexture) {
+ synchronized (this) {
+ if (mEncoderEglSurface == null) {
+ return;
+ }
+
+ mEncoderEglSurface.makeCurrent();
+
+ surfaceTexture.updateTexImage();
+ surfaceTexture.getTransformMatrix(mTmpMatrix);
+
+ long timestampNs = surfaceTexture.getTimestamp();
+
+ if (DEBUG) Log.d(TAG, "onFrameAvailable: timestampUs " + (timestampNs / 1000));
+
+ boolean takeFrame = mEOSTracker.updateLastInputAndEncoderTime(timestampNs,
+ computePresentationTime(mInputIndex + mNumTiles - 1));
+
+ if (takeFrame) {
+ copyTilesGL();
+ }
+
+ surfaceTexture.releaseTexImage();
+
+ // make uncurrent since the onFrameAvailable could be called on arbituray thread.
+ // making the context current on a different thread will cause error.
+ mEncoderEglSurface.makeUnCurrent();
+ }
+ }
+
+ /**
+ * Start the encoding process.
+ */
+ public void start() {
+ mEncoder.start();
+ }
+
+ /**
+ * Add one YUV buffer to be encoded. This might block if the encoder can't process the input
+ * buffers fast enough.
+ *
+ * After the call returns, the client can reuse the data array.
+ *
+ * @param format The YUV format as defined in {@link android.graphics.ImageFormat}, currently
+ * only support YUV_420_888.
+ *
+ * @param data byte array containing the YUV data. If the format has more than one planes,
+ * they must be concatenated.
+ */
+ public void addYuvBuffer(int format, @NonNull byte[] data) {
+ if (mInputMode != INPUT_MODE_BUFFER) {
+ throw new IllegalStateException(
+ "addYuvBuffer is only allowed in buffer input mode");
+ }
+ if ((mUseBitDepth10 && format != ImageFormat.YCBCR_P010)
+ || (!mUseBitDepth10 && format != ImageFormat.YUV_420_888)) {
+ throw new IllegalStateException("Wrong color format.");
+ }
+ if (data == null
+ || (mUseBitDepth10 && data.length != mWidth * mHeight * 3)
+ || (!mUseBitDepth10 && data.length != mWidth * mHeight * 3 / 2)) {
+ throw new IllegalArgumentException("invalid data");
+ }
+ addYuvBufferInternal(data);
+ }
+
+ /**
+ * Retrieves the input surface for encoding.
+ *
+ * Will only return valid value if configured to use surface input.
+ */
+ public @NonNull Surface getInputSurface() {
+ if (mInputMode != INPUT_MODE_SURFACE) {
+ throw new IllegalStateException(
+ "getInputSurface is only allowed in surface input mode");
+ }
+ return mInputSurface;
+ }
+
+ /**
+ * Sets the timestamp (in nano seconds) of the last input frame to encode. Frames with
+ * timestamps larger than the specified value will not be encoded. However, if a frame
+ * already started encoding when this is set, all tiles within that frame will be encoded.
+ *
+ * This method only applies when surface is used.
+ */
+ public void setEndOfInputStreamTimestamp(long timestampNs) {
+ if (mInputMode != INPUT_MODE_SURFACE) {
+ throw new IllegalStateException(
+ "setEndOfInputStreamTimestamp is only allowed in surface input mode");
+ }
+ if (mEOSTracker != null) {
+ mEOSTracker.updateInputEOSTime(timestampNs);
+ }
+ }
+
+ /**
+ * Adds one bitmap to be encoded.
+ */
+ public void addBitmap(@NonNull Bitmap bitmap) {
+ if (mInputMode != INPUT_MODE_BITMAP) {
+ throw new IllegalStateException("addBitmap is only allowed in bitmap input mode");
+ }
+
+ boolean takeFrame = mEOSTracker.updateLastInputAndEncoderTime(
+ computePresentationTime(mInputIndex) * 1000,
+ computePresentationTime(mInputIndex + mNumTiles - 1));
+
+ if (!takeFrame) return;
+
+ synchronized (this) {
+ if (mEncoderEglSurface == null) {
+ return;
+ }
+
+ mEncoderEglSurface.makeCurrent();
+
+ mRectBlt.loadTexture(mTextureId, bitmap);
+
+ copyTilesGL();
+
+ // make uncurrent since the onFrameAvailable could be called on arbituray thread.
+ // making the context current on a different thread will cause error.
+ mEncoderEglSurface.makeUnCurrent();
+ }
+ }
+
+ /**
+ * Sends input EOS to the encoder. Result will be notified asynchronously via
+ * {@link Callback#onComplete(EncoderBase)} if encoder reaches EOS without error, or
+ * {@link Callback#onError(EncoderBase, CodecException)} otherwise.
+ */
+ public void stopAsync() {
+ if (mInputMode == INPUT_MODE_BITMAP) {
+ // here we simply set the EOS timestamp to 0, so that the cut off will be the last
+ // bitmap ever added.
+ mEOSTracker.updateInputEOSTime(0);
+ } else if (mInputMode == INPUT_MODE_BUFFER) {
+ addYuvBufferInternal(null);
+ }
+ }
+
+ /**
+ * Generates the presentation time for input frame N, in microseconds.
+ * The timestamp advances 1 sec for every whole frame.
+ */
+ private long computePresentationTime(int frameIndex) {
+ return 132 + (long)frameIndex * 1000000 / mNumTiles;
+ }
+
+ /**
+ * Obtains one empty input buffer and copies the data into it. Before input
+ * EOS is sent, this would block until the data is copied. After input EOS
+ * is sent, this would return immediately.
+ */
+ private void addYuvBufferInternal(@Nullable byte[] data) {
+ ByteBuffer buffer = acquireEmptyBuffer();
+ if (buffer == null) {
+ return;
+ }
+ buffer.clear();
+ if (data != null) {
+ buffer.put(data);
+ }
+ buffer.flip();
+ synchronized (mFilledBuffers) {
+ mFilledBuffers.add(buffer);
+ }
+ mHandler.post(new Runnable() {
+ @Override
+ public void run() {
+ maybeCopyOneTileYUV();
+ }
+ });
+ }
+
+ /**
+ * Routine to copy one tile if we have both input and codec buffer available.
+ *
+ * Must be called on the handler looper that also handles the MediaCodec callback.
+ */
+ @SuppressWarnings("WeakerAccess") /* synthetic access */
+ void maybeCopyOneTileYUV() {
+ ByteBuffer currentBuffer;
+ while ((currentBuffer = getCurrentBuffer()) != null && !mCodecInputBuffers.isEmpty()) {
+ int index = mCodecInputBuffers.remove(0);
+
+ // 0-length input means EOS.
+ boolean inputEOS = (mInputIndex % mNumTiles == 0) && (currentBuffer.remaining() == 0);
+
+ if (!inputEOS) {
+ Image image = mEncoder.getInputImage(index);
+ int left = mGridWidth * (mInputIndex % mGridCols);
+ int top = mGridHeight * (mInputIndex / mGridCols % mGridRows);
+ mSrcRect.set(left, top, left + mGridWidth, top + mGridHeight);
+ copyOneTileYUV(currentBuffer, image, mWidth, mHeight, mSrcRect, mDstRect,
+ mUseBitDepth10);
+ }
+
+ mEncoder.queueInputBuffer(index, 0,
+ inputEOS ? 0 : mEncoder.getInputBuffer(index).capacity(),
+ computePresentationTime(mInputIndex++),
+ inputEOS ? MediaCodec.BUFFER_FLAG_END_OF_STREAM : 0);
+
+ if (inputEOS || mInputIndex % mNumTiles == 0) {
+ returnEmptyBufferAndNotify(inputEOS);
+ }
+ }
+ }
+
+ /**
+ * Copies from a rect from src buffer to dst image.
+ * TOOD: This will be replaced by JNI.
+ */
+ private static void copyOneTileYUV(ByteBuffer srcBuffer, Image dstImage,
+ int srcWidth, int srcHeight, Rect srcRect, Rect dstRect, boolean useBitDepth10) {
+ if (srcRect.width() != dstRect.width() || srcRect.height() != dstRect.height()) {
+ throw new IllegalArgumentException("src and dst rect size are different!");
+ }
+ if (srcWidth % 2 != 0 || srcHeight % 2 != 0 ||
+ srcRect.left % 2 != 0 || srcRect.top % 2 != 0 ||
+ srcRect.right % 2 != 0 || srcRect.bottom % 2 != 0 ||
+ dstRect.left % 2 != 0 || dstRect.top % 2 != 0 ||
+ dstRect.right % 2 != 0 || dstRect.bottom % 2 != 0) {
+ throw new IllegalArgumentException("src or dst are not aligned!");
+ }
+
+ Image.Plane[] planes = dstImage.getPlanes();
+ if (useBitDepth10) {
+ for (int n = 0; n < planes.length; n++) {
+ ByteBuffer dstBuffer = planes[n].getBuffer();
+ int colStride = planes[n].getPixelStride();
+ int copyWidth = Math.min(srcRect.width(), srcWidth - srcRect.left);
+ int copyHeight = Math.min(srcRect.height(), srcHeight - srcRect.top);
+ int srcPlanePos = 0, div = 1;
+ if (n > 0) {
+ div = 2;
+ srcPlanePos = srcWidth * srcHeight;
+ }
+ for (int i = 0; i < copyHeight / div; i++) {
+ srcBuffer.position(srcPlanePos +
+ (i + srcRect.top / div) * srcWidth + srcRect.left / div);
+ dstBuffer.position((i + dstRect.top / div) * planes[n].getRowStride()
+ + dstRect.left * colStride / div);
+
+ for (int j = 0; j < copyWidth; j++) {
+ dstBuffer.put(srcBuffer.get());
+ if (colStride > 1 && j != copyWidth - 1) {
+ dstBuffer.position(dstBuffer.position() + colStride - 1);
+ }
+ }
+ }
+ }
+ } else {
+ for (int n = 0; n < planes.length; n++) {
+ ByteBuffer dstBuffer = planes[n].getBuffer();
+ int colStride = planes[n].getPixelStride();
+ int copyWidth = Math.min(srcRect.width(), srcWidth - srcRect.left);
+ int copyHeight = Math.min(srcRect.height(), srcHeight - srcRect.top);
+ int srcPlanePos = 0, div = 1;
+ if (n > 0) {
+ div = 2;
+ srcPlanePos = srcWidth * srcHeight * (n + 3) / 4;
+ }
+ for (int i = 0; i < copyHeight / div; i++) {
+ srcBuffer.position(srcPlanePos +
+ (i + srcRect.top / div) * srcWidth / div + srcRect.left / div);
+ dstBuffer.position((i + dstRect.top / div) * planes[n].getRowStride()
+ + dstRect.left * colStride / div);
+
+ for (int j = 0; j < copyWidth / div; j++) {
+ dstBuffer.put(srcBuffer.get());
+ if (colStride > 1 && j != copyWidth / div - 1) {
+ dstBuffer.position(dstBuffer.position() + colStride - 1);
+ }
+ }
+ }
+ }
+ }
+ }
+
+ private ByteBuffer acquireEmptyBuffer() {
+ synchronized (mEmptyBuffers) {
+ // wait for an empty input buffer first
+ while (!mInputEOS && mEmptyBuffers.isEmpty()) {
+ try {
+ mEmptyBuffers.wait();
+ } catch (InterruptedException e) {}
+ }
+
+ // if already EOS, return null to stop further encoding.
+ return mInputEOS ? null : mEmptyBuffers.remove(0);
+ }
+ }
+
+ /**
+ * Routine to get the current input buffer to copy from.
+ * Only called on callback handler thread.
+ */
+ private ByteBuffer getCurrentBuffer() {
+ if (!mInputEOS && mCurrentBuffer == null) {
+ synchronized (mFilledBuffers) {
+ mCurrentBuffer = mFilledBuffers.isEmpty() ?
+ null : mFilledBuffers.remove(0);
+ }
+ }
+ return mInputEOS ? null : mCurrentBuffer;
+ }
+
+ /**
+ * Routine to put the consumed input buffer back into the empty buffer pool.
+ * Only called on callback handler thread.
+ */
+ private void returnEmptyBufferAndNotify(boolean inputEOS) {
+ synchronized (mEmptyBuffers) {
+ mInputEOS |= inputEOS;
+ mEmptyBuffers.add(mCurrentBuffer);
+ mEmptyBuffers.notifyAll();
+ }
+ mCurrentBuffer = null;
+ }
+
+ /**
+ * Routine to release all resources. Must be run on the same looper that
+ * handles the MediaCodec callbacks.
+ */
+ @SuppressWarnings("WeakerAccess") /* synthetic access */
+ void stopInternal() {
+ if (DEBUG) Log.d(TAG, "stopInternal");
+
+ // set stopping, so that the tile copy would bail out
+ // if it hits failure after this point.
+ mStopping.set(true);
+
+ // after start, mEncoder is only accessed on handler, so no need to sync.
+ try {
+ if (mEncoder != null) {
+ mEncoder.stop();
+ mEncoder.release();
+ }
+ } catch (Exception e) {
+ } finally {
+ mEncoder = null;
+ }
+
+ // unblock the addBuffer() if we're tearing down before EOS is sent.
+ synchronized (mEmptyBuffers) {
+ mInputEOS = true;
+ mEmptyBuffers.notifyAll();
+ }
+
+ // Clean up surface and Egl related refs. This lock must come after encoder
+ // release. When we're closing, we insert stopInternal() at the front of queue
+ // so that the shutdown can be processed promptly, this means there might be
+ // some output available requests queued after this. As the tile copies trying
+ // to finish the current frame, there is a chance is might get stuck because
+ // those outputs were not returned. Shutting down the encoder will make break
+ // the tile copier out of that.
+ synchronized(this) {
+ try {
+ if (mRectBlt != null) {
+ mRectBlt.release(false);
+ }
+ } catch (Exception e) {
+ } finally {
+ mRectBlt = null;
+ }
+
+ try {
+ if (mEncoderEglSurface != null) {
+ // Note that this frees mEncoderSurface too. If mEncoderEglSurface is not
+ // there, client is responsible to release the input surface it got from us,
+ // we don't release mEncoderSurface here.
+ mEncoderEglSurface.release();
+ }
+ } catch (Exception e) {
+ } finally {
+ mEncoderEglSurface = null;
+ }
+
+ try {
+ if (mInputTexture != null) {
+ mInputTexture.release();
+ }
+ } catch (Exception e) {
+ } finally {
+ mInputTexture = null;
+ }
+ }
+ }
+
+ /**
+ * This class handles EOS for surface or bitmap inputs.
+ *
+ * When encoding from surface or bitmap, we can't call
+ * {@link MediaCodec#signalEndOfInputStream()} immediately after input is drawn, since this
+ * could drop all pending frames in the buffer queue. When there are tiles, this could leave
+ * us a partially encoded image.
+ *
+ * So here we track the EOS status by timestamps, and only signal EOS to the encoder
+ * when we collected all images we need.
+ *
+ * Since this is updated from multiple threads ({@link #setEndOfInputStreamTimestamp(long)},
+ * {@link EncoderCallback#onOutputBufferAvailable(MediaCodec, int, BufferInfo)},
+ * {@link #addBitmap(Bitmap)} and {@link #onFrameAvailable(SurfaceTexture)}), it must be fully
+ * synchronized.
+ *
+ * Note that when buffer input is used, the EOS flag is set in
+ * {@link EncoderCallback#onInputBufferAvailable(MediaCodec, int)} and this class is not used.
+ */
+ private class SurfaceEOSTracker {
+ private static final boolean DEBUG_EOS = false;
+
+ final boolean mCopyTiles;
+ long mInputEOSTimeNs = -1;
+ long mLastInputTimeNs = -1;
+ long mEncoderEOSTimeUs = -1;
+ long mLastEncoderTimeUs = -1;
+ long mLastOutputTimeUs = -1;
+ boolean mSignaled;
+
+ SurfaceEOSTracker(boolean copyTiles) {
+ mCopyTiles = copyTiles;
+ }
+
+ synchronized void updateInputEOSTime(long timestampNs) {
+ if (DEBUG_EOS) Log.d(TAG, "updateInputEOSTime: " + timestampNs);
+
+ if (mCopyTiles) {
+ if (mInputEOSTimeNs < 0) {
+ mInputEOSTimeNs = timestampNs;
+ }
+ } else {
+ if (mEncoderEOSTimeUs < 0) {
+ mEncoderEOSTimeUs = timestampNs / 1000;
+ }
+ }
+ updateEOSLocked();
+ }
+
+ synchronized boolean updateLastInputAndEncoderTime(long inputTimeNs, long encoderTimeUs) {
+ if (DEBUG_EOS) Log.d(TAG,
+ "updateLastInputAndEncoderTime: " + inputTimeNs + ", " + encoderTimeUs);
+
+ boolean shouldTakeFrame = mInputEOSTimeNs < 0 || inputTimeNs <= mInputEOSTimeNs;
+ if (shouldTakeFrame) {
+ mLastEncoderTimeUs = encoderTimeUs;
+ }
+ mLastInputTimeNs = inputTimeNs;
+ updateEOSLocked();
+ return shouldTakeFrame;
+ }
+
+ synchronized void updateLastOutputTime(long outputTimeUs) {
+ if (DEBUG_EOS) Log.d(TAG, "updateLastOutputTime: " + outputTimeUs);
+
+ mLastOutputTimeUs = outputTimeUs;
+ updateEOSLocked();
+ }
+
+ private void updateEOSLocked() {
+ if (mSignaled) {
+ return;
+ }
+ if (mEncoderEOSTimeUs < 0) {
+ if (mInputEOSTimeNs >= 0 && mLastInputTimeNs >= mInputEOSTimeNs) {
+ if (mLastEncoderTimeUs < 0) {
+ doSignalEOSLocked();
+ return;
+ }
+ // mEncoderEOSTimeUs tracks the timestamp of the last output buffer we
+ // will wait for. When that buffer arrives, encoder will be signalled EOS.
+ mEncoderEOSTimeUs = mLastEncoderTimeUs;
+ if (DEBUG_EOS) Log.d(TAG,
+ "updateEOSLocked: mEncoderEOSTimeUs " + mEncoderEOSTimeUs);
+ }
+ }
+ if (mEncoderEOSTimeUs >= 0 && mEncoderEOSTimeUs <= mLastOutputTimeUs) {
+ doSignalEOSLocked();
+ }
+ }
+
+ private void doSignalEOSLocked() {
+ if (DEBUG_EOS) Log.d(TAG, "doSignalEOSLocked");
+
+ mHandler.post(new Runnable() {
+ @Override public void run() {
+ if (mEncoder != null) {
+ mEncoder.signalEndOfInputStream();
+ }
+ }
+ });
+
+ mSignaled = true;
+ }
+ }
+
+
+ /**
+ * MediaCodec callback for HEVC/AV1 encoding.
+ */
+ @SuppressWarnings("WeakerAccess") /* synthetic access */
+ abstract class EncoderCallback extends MediaCodec.Callback {
+ private boolean mOutputEOS;
+
+ @Override
+ public void onInputBufferAvailable(MediaCodec codec, int index) {
+ if (codec != mEncoder || mInputEOS) return;
+
+ if (DEBUG) Log.d(TAG, "onInputBufferAvailable: " + index);
+ mCodecInputBuffers.add(index);
+ maybeCopyOneTileYUV();
+ }
+
+ @Override
+ public void onOutputBufferAvailable(MediaCodec codec, int index, BufferInfo info) {
+ if (codec != mEncoder || mOutputEOS) return;
+
+ if (DEBUG) {
+ Log.d(TAG, "onOutputBufferAvailable: " + index
+ + ", time " + info.presentationTimeUs
+ + ", size " + info.size
+ + ", flags " + info.flags);
+ }
+
+ if ((info.size > 0) && ((info.flags & MediaCodec.BUFFER_FLAG_CODEC_CONFIG) == 0)) {
+ ByteBuffer outputBuffer = codec.getOutputBuffer(index);
+
+ // reset position as addBuffer() modifies it
+ outputBuffer.position(info.offset);
+ outputBuffer.limit(info.offset + info.size);
+
+ if (mEOSTracker != null) {
+ mEOSTracker.updateLastOutputTime(info.presentationTimeUs);
+ }
+
+ mCallback.onDrainOutputBuffer(EncoderBase.this, outputBuffer);
+ }
+
+ mOutputEOS |= ((info.flags & MediaCodec.BUFFER_FLAG_END_OF_STREAM) != 0);
+
+ codec.releaseOutputBuffer(index, false);
+
+ if (mOutputEOS) {
+ stopAndNotify(null);
+ }
+ }
+
+ @Override
+ public void onError(MediaCodec codec, CodecException e) {
+ if (codec != mEncoder) return;
+
+ Log.e(TAG, "onError: " + e);
+ stopAndNotify(e);
+ }
+
+ private void stopAndNotify(@Nullable CodecException e) {
+ stopInternal();
+ if (e == null) {
+ mCallback.onComplete(EncoderBase.this);
+ } else {
+ mCallback.onError(EncoderBase.this, e);
+ }
+ }
+ }
+
+ @Override
+ public void close() {
+ // unblock the addBuffer() if we're tearing down before EOS is sent.
+ synchronized (mEmptyBuffers) {
+ mInputEOS = true;
+ mEmptyBuffers.notifyAll();
+ }
+
+ mHandler.postAtFrontOfQueue(new Runnable() {
+ @Override
+ public void run() {
+ try {
+ stopInternal();
+ } catch (Exception e) {
+ // We don't want to crash when closing.
+ }
+ }
+ });
+ }
+}
\ No newline at end of file
diff --git a/heifwriter/heifwriter/src/main/java/androidx/heifwriter/HeifEncoder.java b/heifwriter/heifwriter/src/main/java/androidx/heifwriter/HeifEncoder.java
index 5e08a73..6ab3111 100644
--- a/heifwriter/heifwriter/src/main/java/androidx/heifwriter/HeifEncoder.java
+++ b/heifwriter/heifwriter/src/main/java/androidx/heifwriter/HeifEncoder.java
@@ -16,36 +16,20 @@
package androidx.heifwriter;
-import android.graphics.Bitmap;
-import android.graphics.Rect;
-import android.graphics.SurfaceTexture;
-import android.media.Image;
import android.media.MediaCodec;
-import android.media.MediaCodec.BufferInfo;
-import android.media.MediaCodec.CodecException;
import android.media.MediaCodecInfo;
import android.media.MediaCodecInfo.CodecCapabilities;
import android.media.MediaCodecList;
import android.media.MediaFormat;
-import android.opengl.GLES20;
import android.os.Handler;
import android.os.HandlerThread;
-import android.os.Looper;
-import android.os.Process;
import android.util.Log;
import android.util.Range;
-import android.view.Surface;
-import androidx.annotation.IntDef;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import java.io.IOException;
-import java.lang.annotation.Retention;
-import java.lang.annotation.RetentionPolicy;
-import java.nio.ByteBuffer;
-import java.util.ArrayList;
-import java.util.concurrent.atomic.AtomicBoolean;
/**
* This class encodes images into HEIF-compatible samples using HEVC encoder.
@@ -64,115 +48,16 @@
*
* @hide
*/
-public final class HeifEncoder implements AutoCloseable,
- SurfaceTexture.OnFrameAvailableListener {
+public final class HeifEncoder extends EncoderBase {
private static final String TAG = "HeifEncoder";
private static final boolean DEBUG = false;
- private static final int GRID_WIDTH = 512;
- private static final int GRID_HEIGHT = 512;
- private static final double MAX_COMPRESS_RATIO = 0.25f;
- private static final int INPUT_BUFFER_POOL_SIZE = 2;
+ protected static final int GRID_WIDTH = 512;
+ protected static final int GRID_HEIGHT = 512;
+ protected static final double MAX_COMPRESS_RATIO = 0.25f;
private static final MediaCodecList sMCL =
- new MediaCodecList(MediaCodecList.REGULAR_CODECS);
-
- @SuppressWarnings("WeakerAccess") /* synthetic access */
- MediaCodec mEncoder;
- @SuppressWarnings("WeakerAccess") /* synthetic access */
- final Callback mCallback;
- private final HandlerThread mHandlerThread;
- @SuppressWarnings("WeakerAccess") /* synthetic access */
- final Handler mHandler;
- private final @InputMode int mInputMode;
-
- @SuppressWarnings("WeakerAccess") /* synthetic access */
- final int mWidth;
- @SuppressWarnings("WeakerAccess") /* synthetic access */
- final int mHeight;
- @SuppressWarnings("WeakerAccess") /* synthetic access */
- final int mGridWidth;
- @SuppressWarnings("WeakerAccess") /* synthetic access */
- final int mGridHeight;
- @SuppressWarnings("WeakerAccess") /* synthetic access */
- final int mGridRows;
- @SuppressWarnings("WeakerAccess") /* synthetic access */
- final int mGridCols;
- private final int mNumTiles;
- @SuppressWarnings("WeakerAccess") /* synthetic access */
- final boolean mUseGrid;
-
- private int mInputIndex;
- @SuppressWarnings("WeakerAccess") /* synthetic access */
- boolean mInputEOS;
- private final Rect mSrcRect;
- private final Rect mDstRect;
- private ByteBuffer mCurrentBuffer;
- private final ArrayList<ByteBuffer> mEmptyBuffers = new ArrayList<>();
- private final ArrayList<ByteBuffer> mFilledBuffers = new ArrayList<>();
- @SuppressWarnings("WeakerAccess") /* synthetic access */
- final ArrayList<Integer> mCodecInputBuffers = new ArrayList<>();
-
- // Helper for tracking EOS when surface is used
- @SuppressWarnings("WeakerAccess") /* synthetic access */
- SurfaceEOSTracker mEOSTracker;
-
- // Below variables are to handle GL copy from client's surface
- // to encoder surface when tiles are used.
- private SurfaceTexture mInputTexture;
- private Surface mInputSurface;
- private Surface mEncoderSurface;
- private EglWindowSurface mEncoderEglSurface;
- private EglRectBlt mRectBlt;
- private int mTextureId;
- private final float[] mTmpMatrix = new float[16];
- private final AtomicBoolean mStopping = new AtomicBoolean(false);
-
- public static final int INPUT_MODE_BUFFER = HeifWriter.INPUT_MODE_BUFFER;
- public static final int INPUT_MODE_SURFACE = HeifWriter.INPUT_MODE_SURFACE;
- public static final int INPUT_MODE_BITMAP = HeifWriter.INPUT_MODE_BITMAP;
- @IntDef({
- INPUT_MODE_BUFFER,
- INPUT_MODE_SURFACE,
- INPUT_MODE_BITMAP,
- })
- @Retention(RetentionPolicy.SOURCE)
- public @interface InputMode {}
-
- public static abstract class Callback {
- /**
- * Called when the output format has changed.
- *
- * @param encoder The HeifEncoder object.
- * @param format The new output format.
- */
- public abstract void onOutputFormatChanged(
- @NonNull HeifEncoder encoder, @NonNull MediaFormat format);
-
- /**
- * Called when an output buffer becomes available.
- *
- * @param encoder The HeifEncoder object.
- * @param byteBuffer the available output buffer.
- */
- public abstract void onDrainOutputBuffer(
- @NonNull HeifEncoder encoder, @NonNull ByteBuffer byteBuffer);
-
- /**
- * Called when encoding reached the end of stream without error.
- *
- * @param encoder The HeifEncoder object.
- */
- public abstract void onComplete(@NonNull HeifEncoder encoder);
-
- /**
- * Called when encoding hits an error.
- *
- * @param encoder The HeifEncoder object.
- * @param e The exception that the codec reported.
- */
- public abstract void onError(@NonNull HeifEncoder encoder, @NonNull CodecException e);
- }
+ new MediaCodecList(MediaCodecList.REGULAR_CODECS);
/**
* Configure the heif encoding session. Should only be called once.
@@ -189,198 +74,15 @@
* @param cb The callback to receive various messages from the heif encoder.
*/
public HeifEncoder(int width, int height, boolean useGrid,
- int quality, @InputMode int inputMode,
- @Nullable Handler handler, @NonNull Callback cb) throws IOException {
- if (DEBUG) Log.d(TAG, "width: " + width + ", height: " + height +
- ", useGrid: " + useGrid + ", quality: " + quality + ", inputMode: " + inputMode);
-
- if (width < 0 || height < 0 || quality < 0 || quality > 100) {
- throw new IllegalArgumentException("invalid encoder inputs");
- }
-
- // Disable grid if the image is too small
- useGrid &= (width > GRID_WIDTH || height > GRID_HEIGHT);
-
- boolean useHeicEncoder = false;
- MediaCodecInfo.CodecCapabilities caps = null;
- try {
- mEncoder = MediaCodec.createEncoderByType(MediaFormat.MIMETYPE_IMAGE_ANDROID_HEIC);
- caps = mEncoder.getCodecInfo().getCapabilitiesForType(
- MediaFormat.MIMETYPE_IMAGE_ANDROID_HEIC);
- // If the HEIC encoder can't support the size, fall back to HEVC encoder.
- if (!caps.getVideoCapabilities().isSizeSupported(width, height)) {
- mEncoder.release();
- mEncoder = null;
- throw new Exception();
- }
- useHeicEncoder = true;
- } catch (Exception e) {
- mEncoder = MediaCodec.createByCodecName(findHevcFallback());
- caps = mEncoder.getCodecInfo().getCapabilitiesForType(MediaFormat.MIMETYPE_VIDEO_HEVC);
- // Always enable grid if the size is too large for the HEVC encoder
- useGrid |= !caps.getVideoCapabilities().isSizeSupported(width, height);
- }
-
- mInputMode = inputMode;
-
- mCallback = cb;
-
- Looper looper = (handler != null) ? handler.getLooper() : null;
- if (looper == null) {
- mHandlerThread = new HandlerThread("HeifEncoderThread",
- Process.THREAD_PRIORITY_FOREGROUND);
- mHandlerThread.start();
- looper = mHandlerThread.getLooper();
- } else {
- mHandlerThread = null;
- }
- mHandler = new Handler(looper);
- boolean useSurfaceInternally =
- (inputMode == INPUT_MODE_SURFACE) || (inputMode == INPUT_MODE_BITMAP);
- int colorFormat = useSurfaceInternally ? CodecCapabilities.COLOR_FormatSurface :
- CodecCapabilities.COLOR_FormatYUV420Flexible;
- boolean copyTiles = (useGrid && !useHeicEncoder) || (inputMode == INPUT_MODE_BITMAP);
-
- mWidth = width;
- mHeight = height;
- mUseGrid = useGrid;
-
- int gridWidth, gridHeight, gridRows, gridCols;
-
- if (useGrid) {
- gridWidth = GRID_WIDTH;
- gridHeight = GRID_HEIGHT;
- gridRows = (height + GRID_HEIGHT - 1) / GRID_HEIGHT;
- gridCols = (width + GRID_WIDTH - 1) / GRID_WIDTH;
- } else {
- gridWidth = mWidth;
- gridHeight = mHeight;
- gridRows = 1;
- gridCols = 1;
- }
-
- MediaFormat codecFormat;
- if (useHeicEncoder) {
- codecFormat = MediaFormat.createVideoFormat(
- MediaFormat.MIMETYPE_IMAGE_ANDROID_HEIC, mWidth, mHeight);
- } else {
- codecFormat = MediaFormat.createVideoFormat(
- MediaFormat.MIMETYPE_VIDEO_HEVC, gridWidth, gridHeight);
- }
-
- if (useGrid) {
- codecFormat.setInteger(MediaFormat.KEY_TILE_WIDTH, gridWidth);
- codecFormat.setInteger(MediaFormat.KEY_TILE_HEIGHT, gridHeight);
- codecFormat.setInteger(MediaFormat.KEY_GRID_COLUMNS, gridCols);
- codecFormat.setInteger(MediaFormat.KEY_GRID_ROWS, gridRows);
- }
-
- if (useHeicEncoder) {
- mGridWidth = width;
- mGridHeight = height;
- mGridRows = 1;
- mGridCols = 1;
- } else {
- mGridWidth = gridWidth;
- mGridHeight = gridHeight;
- mGridRows = gridRows;
- mGridCols = gridCols;
- }
- mNumTiles = mGridRows * mGridCols;
-
- codecFormat.setInteger(MediaFormat.KEY_I_FRAME_INTERVAL, 0);
- codecFormat.setInteger(MediaFormat.KEY_COLOR_FORMAT, colorFormat);
- codecFormat.setInteger(MediaFormat.KEY_FRAME_RATE, mNumTiles);
-
- // When we're doing tiles, set the operating rate higher as the size
- // is small, otherwise set to the normal 30fps.
- if (mNumTiles > 1) {
- codecFormat.setInteger(MediaFormat.KEY_OPERATING_RATE, 120);
- } else {
- codecFormat.setInteger(MediaFormat.KEY_OPERATING_RATE, 30);
- }
-
- if (useSurfaceInternally && !copyTiles) {
- // Use fixed PTS gap and disable backward frame drop
- Log.d(TAG, "Setting fixed pts gap");
- codecFormat.setLong(MediaFormat.KEY_MAX_PTS_GAP_TO_ENCODER, -1000000);
- }
-
- MediaCodecInfo.EncoderCapabilities encoderCaps = caps.getEncoderCapabilities();
-
- if (encoderCaps.isBitrateModeSupported(
- MediaCodecInfo.EncoderCapabilities.BITRATE_MODE_CQ)) {
- Log.d(TAG, "Setting bitrate mode to constant quality");
- Range<Integer> qualityRange = encoderCaps.getQualityRange();
- Log.d(TAG, "Quality range: " + qualityRange);
- codecFormat.setInteger(MediaFormat.KEY_BITRATE_MODE,
- MediaCodecInfo.EncoderCapabilities.BITRATE_MODE_CQ);
- codecFormat.setInteger(MediaFormat.KEY_QUALITY, (int) (qualityRange.getLower() +
- (qualityRange.getUpper() - qualityRange.getLower()) * quality / 100.0));
- } else {
- if (encoderCaps.isBitrateModeSupported(
- MediaCodecInfo.EncoderCapabilities.BITRATE_MODE_CBR)) {
- Log.d(TAG, "Setting bitrate mode to constant bitrate");
- codecFormat.setInteger(MediaFormat.KEY_BITRATE_MODE,
- MediaCodecInfo.EncoderCapabilities.BITRATE_MODE_CBR);
- } else { // assume VBR
- Log.d(TAG, "Setting bitrate mode to variable bitrate");
- codecFormat.setInteger(MediaFormat.KEY_BITRATE_MODE,
- MediaCodecInfo.EncoderCapabilities.BITRATE_MODE_VBR);
- }
- // Calculate the bitrate based on image dimension, max compression ratio and quality.
- // Note that we set the frame rate to the number of tiles, so the bitrate would be the
- // intended bits for one image.
- int bitrate = caps.getVideoCapabilities().getBitrateRange().clamp(
- (int) (width * height * 1.5 * 8 * MAX_COMPRESS_RATIO * quality / 100.0f));
- codecFormat.setInteger(MediaFormat.KEY_BIT_RATE, bitrate);
- }
-
- mEncoder.setCallback(new EncoderCallback(), mHandler);
- mEncoder.configure(codecFormat, null, null, MediaCodec.CONFIGURE_FLAG_ENCODE);
-
- if (useSurfaceInternally) {
- mEncoderSurface = mEncoder.createInputSurface();
-
- mEOSTracker = new SurfaceEOSTracker(copyTiles);
-
- if (copyTiles) {
- mEncoderEglSurface = new EglWindowSurface(mEncoderSurface);
- mEncoderEglSurface.makeCurrent();
-
- mRectBlt = new EglRectBlt(
- new Texture2dProgram((inputMode == INPUT_MODE_BITMAP)
- ? Texture2dProgram.TEXTURE_2D
- : Texture2dProgram.TEXTURE_EXT),
- mWidth, mHeight);
-
- mTextureId = mRectBlt.createTextureObject();
-
- if (inputMode == INPUT_MODE_SURFACE) {
- // use single buffer mode to block on input
- mInputTexture = new SurfaceTexture(mTextureId, true);
- mInputTexture.setOnFrameAvailableListener(this);
- mInputTexture.setDefaultBufferSize(mWidth, mHeight);
- mInputSurface = new Surface(mInputTexture);
- }
-
- // make uncurrent since onFrameAvailable could be called on arbituray thread.
- // making the context current on a different thread will cause error.
- mEncoderEglSurface.makeUnCurrent();
- } else {
- mInputSurface = mEncoderSurface;
- }
- } else {
- for (int i = 0; i < INPUT_BUFFER_POOL_SIZE; i++) {
- mEmptyBuffers.add(ByteBuffer.allocateDirect(mWidth * mHeight * 3 / 2));
- }
- }
-
- mDstRect = new Rect(0, 0, mGridWidth, mGridHeight);
- mSrcRect = new Rect();
+ int quality, @InputMode int inputMode,
+ @Nullable Handler handler, @NonNull Callback cb) throws IOException {
+ super("HEIC", width, height, useGrid, quality, inputMode, handler, cb,
+ /* useBitDepth10 */ false);
+ mEncoder.setCallback(new HevcEncoderCallback(), mHandler);
+ finishSettingUpEncoder(/* useBitDepth10 */ false);
}
- private String findHevcFallback() {
+ protected static String findHevcFallback() {
String hevc = null; // first HEVC encoder
for (MediaCodecInfo info : sMCL.getCodecInfos()) {
if (!info.isEncoder()) {
@@ -396,7 +98,7 @@
continue;
}
if (caps.getEncoderCapabilities().isBitrateModeSupported(
- MediaCodecInfo.EncoderCapabilities.BITRATE_MODE_CQ)) {
+ MediaCodecInfo.EncoderCapabilities.BITRATE_MODE_CQ)) {
// Encoder that supports CQ mode is preferred over others,
// return the first encoder that supports CQ mode.
// (No need to check if it's hw based, it's already listed in
@@ -410,508 +112,12 @@
// If no encoders support CQ, return the first HEVC encoder.
return hevc;
}
- /**
- * Copies from source frame to encoder inputs using GL. The source could be either
- * client's input surface, or the input bitmap loaded to texture.
- */
- private void copyTilesGL() {
- GLES20.glViewport(0, 0, mGridWidth, mGridHeight);
-
- for (int row = 0; row < mGridRows; row++) {
- for (int col = 0; col < mGridCols; col++) {
- int left = col * mGridWidth;
- int top = row * mGridHeight;
- mSrcRect.set(left, top, left + mGridWidth, top + mGridHeight);
- try {
- mRectBlt.copyRect(mTextureId, Texture2dProgram.V_FLIP_MATRIX, mSrcRect);
- } catch (RuntimeException e) {
- // EGL copy could throw if the encoder input surface is no longer valid
- // after encoder is released. This is not an error because we're already
- // stopping (either after EOS is received or requested by client).
- if (mStopping.get()) {
- return;
- }
- throw e;
- }
- mEncoderEglSurface.setPresentationTime(
- 1000 * computePresentationTime(mInputIndex++));
- mEncoderEglSurface.swapBuffers();
- }
- }
- }
-
- @Override
- public void onFrameAvailable(SurfaceTexture surfaceTexture) {
- synchronized (this) {
- if (mEncoderEglSurface == null) {
- return;
- }
-
- mEncoderEglSurface.makeCurrent();
-
- surfaceTexture.updateTexImage();
- surfaceTexture.getTransformMatrix(mTmpMatrix);
-
- long timestampNs = surfaceTexture.getTimestamp();
-
- if (DEBUG) Log.d(TAG, "onFrameAvailable: timestampUs " + (timestampNs / 1000));
-
- boolean takeFrame = mEOSTracker.updateLastInputAndEncoderTime(timestampNs,
- computePresentationTime(mInputIndex + mNumTiles - 1));
-
- if (takeFrame) {
- copyTilesGL();
- }
-
- surfaceTexture.releaseTexImage();
-
- // make uncurrent since the onFrameAvailable could be called on arbituray thread.
- // making the context current on a different thread will cause error.
- mEncoderEglSurface.makeUnCurrent();
- }
- }
-
- /**
- * Start the encoding process.
- */
- public void start() {
- mEncoder.start();
- }
-
- /**
- * Add one YUV buffer to be encoded. This might block if the encoder can't process the input
- * buffers fast enough.
- *
- * After the call returns, the client can reuse the data array.
- *
- * @param format The YUV format as defined in {@link android.graphics.ImageFormat}, currently
- * only support YUV_420_888.
- *
- * @param data byte array containing the YUV data. If the format has more than one planes,
- * they must be concatenated.
- */
- public void addYuvBuffer(int format, @NonNull byte[] data) {
- if (mInputMode != INPUT_MODE_BUFFER) {
- throw new IllegalStateException(
- "addYuvBuffer is only allowed in buffer input mode");
- }
- if (data == null || data.length != mWidth * mHeight * 3 / 2) {
- throw new IllegalArgumentException("invalid data");
- }
- addYuvBufferInternal(data);
- }
-
- /**
- * Retrieves the input surface for encoding.
- *
- * Will only return valid value if configured to use surface input.
- */
- public @NonNull Surface getInputSurface() {
- if (mInputMode != INPUT_MODE_SURFACE) {
- throw new IllegalStateException(
- "getInputSurface is only allowed in surface input mode");
- }
- return mInputSurface;
- }
-
- /**
- * Sets the timestamp (in nano seconds) of the last input frame to encode. Frames with
- * timestamps larger than the specified value will not be encoded. However, if a frame
- * already started encoding when this is set, all tiles within that frame will be encoded.
- *
- * This method only applies when surface is used.
- */
- public void setEndOfInputStreamTimestamp(long timestampNs) {
- if (mInputMode != INPUT_MODE_SURFACE) {
- throw new IllegalStateException(
- "setEndOfInputStreamTimestamp is only allowed in surface input mode");
- }
- if (mEOSTracker != null) {
- mEOSTracker.updateInputEOSTime(timestampNs);
- }
- }
-
- /**
- * Adds one bitmap to be encoded.
- */
- public void addBitmap(@NonNull Bitmap bitmap) {
- if (mInputMode != INPUT_MODE_BITMAP) {
- throw new IllegalStateException("addBitmap is only allowed in bitmap input mode");
- }
-
- boolean takeFrame = mEOSTracker.updateLastInputAndEncoderTime(
- computePresentationTime(mInputIndex) * 1000,
- computePresentationTime(mInputIndex + mNumTiles - 1));
-
- if (!takeFrame) return;
-
- synchronized (this) {
- if (mEncoderEglSurface == null) {
- return;
- }
-
- mEncoderEglSurface.makeCurrent();
-
- mRectBlt.loadTexture(mTextureId, bitmap);
-
- copyTilesGL();
-
- // make uncurrent since the onFrameAvailable could be called on arbituray thread.
- // making the context current on a different thread will cause error.
- mEncoderEglSurface.makeUnCurrent();
- }
- }
-
- /**
- * Sends input EOS to the encoder. Result will be notified asynchronously via
- * {@link Callback#onComplete(HeifEncoder)} if encoder reaches EOS without error, or
- * {@link Callback#onError(HeifEncoder, CodecException)} otherwise.
- */
- public void stopAsync() {
- if (mInputMode == INPUT_MODE_BITMAP) {
- // here we simply set the EOS timestamp to 0, so that the cut off will be the last
- // bitmap ever added.
- mEOSTracker.updateInputEOSTime(0);
- } else if (mInputMode == INPUT_MODE_BUFFER) {
- addYuvBufferInternal(null);
- }
- }
-
- /**
- * Generates the presentation time for input frame N, in microseconds.
- * The timestamp advances 1 sec for every whole frame.
- */
- private long computePresentationTime(int frameIndex) {
- return 132 + (long)frameIndex * 1000000 / mNumTiles;
- }
-
- /**
- * Obtains one empty input buffer and copies the data into it. Before input
- * EOS is sent, this would block until the data is copied. After input EOS
- * is sent, this would return immediately.
- */
- private void addYuvBufferInternal(@Nullable byte[] data) {
- ByteBuffer buffer = acquireEmptyBuffer();
- if (buffer == null) {
- return;
- }
- buffer.clear();
- if (data != null) {
- buffer.put(data);
- }
- buffer.flip();
- synchronized (mFilledBuffers) {
- mFilledBuffers.add(buffer);
- }
- mHandler.post(new Runnable() {
- @Override
- public void run() {
- maybeCopyOneTileYUV();
- }
- });
- }
-
- /**
- * Routine to copy one tile if we have both input and codec buffer available.
- *
- * Must be called on the handler looper that also handles the MediaCodec callback.
- */
- @SuppressWarnings("WeakerAccess") /* synthetic access */
- void maybeCopyOneTileYUV() {
- ByteBuffer currentBuffer;
- while ((currentBuffer = getCurrentBuffer()) != null && !mCodecInputBuffers.isEmpty()) {
- int index = mCodecInputBuffers.remove(0);
-
- // 0-length input means EOS.
- boolean inputEOS = (mInputIndex % mNumTiles == 0) && (currentBuffer.remaining() == 0);
-
- if (!inputEOS) {
- Image image = mEncoder.getInputImage(index);
- int left = mGridWidth * (mInputIndex % mGridCols);
- int top = mGridHeight * (mInputIndex / mGridCols % mGridRows);
- mSrcRect.set(left, top, left + mGridWidth, top + mGridHeight);
- copyOneTileYUV(currentBuffer, image, mWidth, mHeight, mSrcRect, mDstRect);
- }
-
- mEncoder.queueInputBuffer(index, 0,
- inputEOS ? 0 : mEncoder.getInputBuffer(index).capacity(),
- computePresentationTime(mInputIndex++),
- inputEOS ? MediaCodec.BUFFER_FLAG_END_OF_STREAM : 0);
-
- if (inputEOS || mInputIndex % mNumTiles == 0) {
- returnEmptyBufferAndNotify(inputEOS);
- }
- }
- }
-
- /**
- * Copies from a rect from src buffer to dst image.
- * TOOD: This will be replaced by JNI.
- */
- private static void copyOneTileYUV(
- ByteBuffer srcBuffer, Image dstImage,
- int srcWidth, int srcHeight,
- Rect srcRect, Rect dstRect) {
- if (srcRect.width() != dstRect.width() || srcRect.height() != dstRect.height()) {
- throw new IllegalArgumentException("src and dst rect size are different!");
- }
- if (srcWidth % 2 != 0 || srcHeight % 2 != 0 ||
- srcRect.left % 2 != 0 || srcRect.top % 2 != 0 ||
- srcRect.right % 2 != 0 || srcRect.bottom % 2 != 0 ||
- dstRect.left % 2 != 0 || dstRect.top % 2 != 0 ||
- dstRect.right % 2 != 0 || dstRect.bottom % 2 != 0) {
- throw new IllegalArgumentException("src or dst are not aligned!");
- }
-
- Image.Plane[] planes = dstImage.getPlanes();
- for (int n = 0; n < planes.length; n++) {
- ByteBuffer dstBuffer = planes[n].getBuffer();
- int colStride = planes[n].getPixelStride();
- int copyWidth = Math.min(srcRect.width(), srcWidth - srcRect.left);
- int copyHeight = Math.min(srcRect.height(), srcHeight - srcRect.top);
- int srcPlanePos = 0, div = 1;
- if (n > 0) {
- div = 2;
- srcPlanePos = srcWidth * srcHeight * (n + 3) / 4;
- }
- for (int i = 0; i < copyHeight / div; i++) {
- srcBuffer.position(srcPlanePos +
- (i + srcRect.top / div) * srcWidth / div + srcRect.left / div);
- dstBuffer.position((i + dstRect.top / div) * planes[n].getRowStride()
- + dstRect.left * colStride / div);
-
- for (int j = 0; j < copyWidth / div; j++) {
- dstBuffer.put(srcBuffer.get());
- if (colStride > 1 && j != copyWidth / div - 1) {
- dstBuffer.position(dstBuffer.position() + colStride - 1);
- }
- }
- }
- }
- }
-
- private ByteBuffer acquireEmptyBuffer() {
- synchronized (mEmptyBuffers) {
- // wait for an empty input buffer first
- while (!mInputEOS && mEmptyBuffers.isEmpty()) {
- try {
- mEmptyBuffers.wait();
- } catch (InterruptedException e) {}
- }
-
- // if already EOS, return null to stop further encoding.
- return mInputEOS ? null : mEmptyBuffers.remove(0);
- }
- }
-
- /**
- * Routine to get the current input buffer to copy from.
- * Only called on callback handler thread.
- */
- private ByteBuffer getCurrentBuffer() {
- if (!mInputEOS && mCurrentBuffer == null) {
- synchronized (mFilledBuffers) {
- mCurrentBuffer = mFilledBuffers.isEmpty() ?
- null : mFilledBuffers.remove(0);
- }
- }
- return mInputEOS ? null : mCurrentBuffer;
- }
-
- /**
- * Routine to put the consumed input buffer back into the empty buffer pool.
- * Only called on callback handler thread.
- */
- private void returnEmptyBufferAndNotify(boolean inputEOS) {
- synchronized (mEmptyBuffers) {
- mInputEOS |= inputEOS;
- mEmptyBuffers.add(mCurrentBuffer);
- mEmptyBuffers.notifyAll();
- }
- mCurrentBuffer = null;
- }
-
- /**
- * Routine to release all resources. Must be run on the same looper that
- * handles the MediaCodec callbacks.
- */
- @SuppressWarnings("WeakerAccess") /* synthetic access */
- void stopInternal() {
- if (DEBUG) Log.d(TAG, "stopInternal");
-
- // set stopping, so that the tile copy would bail out
- // if it hits failure after this point.
- mStopping.set(true);
-
- // after start, mEncoder is only accessed on handler, so no need to sync.
- try {
- if (mEncoder != null) {
- mEncoder.stop();
- mEncoder.release();
- }
- } catch (Exception e) {
- } finally {
- mEncoder = null;
- }
-
- // unblock the addBuffer() if we're tearing down before EOS is sent.
- synchronized (mEmptyBuffers) {
- mInputEOS = true;
- mEmptyBuffers.notifyAll();
- }
-
- // Clean up surface and Egl related refs. This lock must come after encoder
- // release. When we're closing, we insert stopInternal() at the front of queue
- // so that the shutdown can be processed promptly, this means there might be
- // some output available requests queued after this. As the tile copies trying
- // to finish the current frame, there is a chance is might get stuck because
- // those outputs were not returned. Shutting down the encoder will make break
- // the tile copier out of that.
- synchronized(this) {
- try {
- if (mRectBlt != null) {
- mRectBlt.release(false);
- }
- } catch (Exception e) {
- } finally {
- mRectBlt = null;
- }
-
- try {
- if (mEncoderEglSurface != null) {
- // Note that this frees mEncoderSurface too. If mEncoderEglSurface is not
- // there, client is responsible to release the input surface it got from us,
- // we don't release mEncoderSurface here.
- mEncoderEglSurface.release();
- }
- } catch (Exception e) {
- } finally {
- mEncoderEglSurface = null;
- }
-
- try {
- if (mInputTexture != null) {
- mInputTexture.release();
- }
- } catch (Exception e) {
- } finally {
- mInputTexture = null;
- }
- }
- }
-
- /**
- * This class handles EOS for surface or bitmap inputs.
- *
- * When encoding from surface or bitmap, we can't call {@link MediaCodec#signalEndOfInputStream()}
- * immediately after input is drawn, since this could drop all pending frames in the
- * buffer queue. When there are tiles, this could leave us a partially encoded image.
- *
- * So here we track the EOS status by timestamps, and only signal EOS to the encoder
- * when we collected all images we need.
- *
- * Since this is updated from multiple threads ({@link #setEndOfInputStreamTimestamp(long)},
- * {@link EncoderCallback#onOutputBufferAvailable(MediaCodec, int, BufferInfo)},
- * {@link #addBitmap(Bitmap)} and {@link #onFrameAvailable(SurfaceTexture)}), it must be fully
- * synchronized.
- *
- * Note that when buffer input is used, the EOS flag is set in
- * {@link EncoderCallback#onInputBufferAvailable(MediaCodec, int)} and this class is not used.
- */
- private class SurfaceEOSTracker {
- private static final boolean DEBUG_EOS = false;
-
- final boolean mCopyTiles;
- long mInputEOSTimeNs = -1;
- long mLastInputTimeNs = -1;
- long mEncoderEOSTimeUs = -1;
- long mLastEncoderTimeUs = -1;
- long mLastOutputTimeUs = -1;
- boolean mSignaled;
-
- SurfaceEOSTracker(boolean copyTiles) {
- mCopyTiles = copyTiles;
- }
-
- synchronized void updateInputEOSTime(long timestampNs) {
- if (DEBUG_EOS) Log.d(TAG, "updateInputEOSTime: " + timestampNs);
-
- if (mCopyTiles) {
- if (mInputEOSTimeNs < 0) {
- mInputEOSTimeNs = timestampNs;
- }
- } else {
- if (mEncoderEOSTimeUs < 0) {
- mEncoderEOSTimeUs = timestampNs / 1000;
- }
- }
- updateEOSLocked();
- }
-
- synchronized boolean updateLastInputAndEncoderTime(long inputTimeNs, long encoderTimeUs) {
- if (DEBUG_EOS) Log.d(TAG,
- "updateLastInputAndEncoderTime: " + inputTimeNs + ", " + encoderTimeUs);
-
- boolean shouldTakeFrame = mInputEOSTimeNs < 0 || inputTimeNs <= mInputEOSTimeNs;
- if (shouldTakeFrame) {
- mLastEncoderTimeUs = encoderTimeUs;
- }
- mLastInputTimeNs = inputTimeNs;
- updateEOSLocked();
- return shouldTakeFrame;
- }
-
- synchronized void updateLastOutputTime(long outputTimeUs) {
- if (DEBUG_EOS) Log.d(TAG, "updateLastOutputTime: " + outputTimeUs);
-
- mLastOutputTimeUs = outputTimeUs;
- updateEOSLocked();
- }
-
- private void updateEOSLocked() {
- if (mSignaled) {
- return;
- }
- if (mEncoderEOSTimeUs < 0) {
- if (mInputEOSTimeNs >= 0 && mLastInputTimeNs >= mInputEOSTimeNs) {
- if (mLastEncoderTimeUs < 0) {
- doSignalEOSLocked();
- return;
- }
- // mEncoderEOSTimeUs tracks the timestamp of the last output buffer we
- // will wait for. When that buffer arrives, encoder will be signalled EOS.
- mEncoderEOSTimeUs = mLastEncoderTimeUs;
- if (DEBUG_EOS) Log.d(TAG,
- "updateEOSLocked: mEncoderEOSTimeUs " + mEncoderEOSTimeUs);
- }
- }
- if (mEncoderEOSTimeUs >= 0 && mEncoderEOSTimeUs <= mLastOutputTimeUs) {
- doSignalEOSLocked();
- }
- }
-
- private void doSignalEOSLocked() {
- if (DEBUG_EOS) Log.d(TAG, "doSignalEOSLocked");
-
- mHandler.post(new Runnable() {
- @Override public void run() {
- if (mEncoder != null) {
- mEncoder.signalEndOfInputStream();
- }
- }
- });
-
- mSignaled = true;
- }
- }
/**
* MediaCodec callback for HEVC encoding.
*/
@SuppressWarnings("WeakerAccess") /* synthetic access */
- class EncoderCallback extends MediaCodec.Callback {
- private boolean mOutputEOS;
-
+ protected class HevcEncoderCallback extends EncoderCallback {
@Override
public void onOutputFormatChanged(MediaCodec codec, MediaFormat format) {
if (codec != mEncoder) return;
@@ -919,7 +125,7 @@
if (DEBUG) Log.d(TAG, "onOutputFormatChanged: " + format);
if (!MediaFormat.MIMETYPE_IMAGE_ANDROID_HEIC.equals(
- format.getString(MediaFormat.KEY_MIME))) {
+ format.getString(MediaFormat.KEY_MIME))) {
format.setString(MediaFormat.KEY_MIME, MediaFormat.MIMETYPE_IMAGE_ANDROID_HEIC);
format.setInteger(MediaFormat.KEY_WIDTH, mWidth);
format.setInteger(MediaFormat.KEY_HEIGHT, mHeight);
@@ -934,85 +140,5 @@
mCallback.onOutputFormatChanged(HeifEncoder.this, format);
}
-
- @Override
- public void onInputBufferAvailable(MediaCodec codec, int index) {
- if (codec != mEncoder || mInputEOS) return;
-
- if (DEBUG) Log.d(TAG, "onInputBufferAvailable: " + index);
- mCodecInputBuffers.add(index);
- maybeCopyOneTileYUV();
- }
-
- @Override
- public void onOutputBufferAvailable(MediaCodec codec, int index, BufferInfo info) {
- if (codec != mEncoder || mOutputEOS) return;
-
- if (DEBUG) {
- Log.d(TAG, "onOutputBufferAvailable: " + index
- + ", time " + info.presentationTimeUs
- + ", size " + info.size
- + ", flags " + info.flags);
- }
-
- if ((info.size > 0) && ((info.flags & MediaCodec.BUFFER_FLAG_CODEC_CONFIG) == 0)) {
- ByteBuffer outputBuffer = codec.getOutputBuffer(index);
-
- // reset position as addBuffer() modifies it
- outputBuffer.position(info.offset);
- outputBuffer.limit(info.offset + info.size);
-
- if (mEOSTracker != null) {
- mEOSTracker.updateLastOutputTime(info.presentationTimeUs);
- }
-
- mCallback.onDrainOutputBuffer(HeifEncoder.this, outputBuffer);
- }
-
- mOutputEOS |= ((info.flags & MediaCodec.BUFFER_FLAG_END_OF_STREAM) != 0);
-
- codec.releaseOutputBuffer(index, false);
-
- if (mOutputEOS) {
- stopAndNotify(null);
- }
- }
-
- @Override
- public void onError(MediaCodec codec, CodecException e) {
- if (codec != mEncoder) return;
-
- Log.e(TAG, "onError: " + e);
- stopAndNotify(e);
- }
-
- private void stopAndNotify(@Nullable CodecException e) {
- stopInternal();
- if (e == null) {
- mCallback.onComplete(HeifEncoder.this);
- } else {
- mCallback.onError(HeifEncoder.this, e);
- }
- }
}
-
- @Override
- public void close() {
- // unblock the addBuffer() if we're tearing down before EOS is sent.
- synchronized (mEmptyBuffers) {
- mInputEOS = true;
- mEmptyBuffers.notifyAll();
- }
-
- mHandler.postAtFrontOfQueue(new Runnable() {
- @Override
- public void run() {
- try {
- stopInternal();
- } catch (Exception e) {
- // We don't want to crash when closing.
- }
- }
- });
- }
-}
+}
\ No newline at end of file
diff --git a/heifwriter/heifwriter/src/main/java/androidx/heifwriter/HeifWriter.java b/heifwriter/heifwriter/src/main/java/androidx/heifwriter/HeifWriter.java
index 978654a..878b1ac 100644
--- a/heifwriter/heifwriter/src/main/java/androidx/heifwriter/HeifWriter.java
+++ b/heifwriter/heifwriter/src/main/java/androidx/heifwriter/HeifWriter.java
@@ -32,6 +32,7 @@
import android.view.Surface;
import androidx.annotation.IntDef;
+import androidx.annotation.IntRange;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
@@ -77,42 +78,17 @@
*
* <p>Please refer to the documentations on individual methods for the exact usage.
*/
-public final class HeifWriter implements AutoCloseable {
+@SuppressWarnings("HiddenSuperclass")
+public final class HeifWriter extends WriterBase {
private static final String TAG = "HeifWriter";
private static final boolean DEBUG = false;
- private static final int MUXER_DATA_FLAG = 16;
-
- private final @InputMode int mInputMode;
- private final HandlerThread mHandlerThread;
- private final Handler mHandler;
- @SuppressWarnings("WeakerAccess") /* synthetic access */
- int mNumTiles;
- @SuppressWarnings("WeakerAccess") /* synthetic access */
- final int mRotation;
- @SuppressWarnings("WeakerAccess") /* synthetic access */
- final int mMaxImages;
- @SuppressWarnings("WeakerAccess") /* synthetic access */
- final int mPrimaryIndex;
- @SuppressWarnings("WeakerAccess") /* synthetic access */
- final ResultWaiter mResultWaiter = new ResultWaiter();
- @SuppressWarnings("WeakerAccess") /* synthetic access */
- MediaMuxer mMuxer;
- private HeifEncoder mHeifEncoder;
- final AtomicBoolean mMuxerStarted = new AtomicBoolean(false);
- @SuppressWarnings("WeakerAccess") /* synthetic access */
- int[] mTrackIndexArray;
- @SuppressWarnings("WeakerAccess") /* synthetic access */
- int mOutputIndex;
- private boolean mStarted;
-
- private final List<Pair<Integer, ByteBuffer>> mExifList = new ArrayList<>();
/**
* The input mode where the client adds input buffers with YUV data.
*
* @see #addYuvBuffer(int, byte[])
*/
- public static final int INPUT_MODE_BUFFER = 0;
+ public static final int INPUT_MODE_BUFFER = WriterBase.INPUT_MODE_BUFFER;
/**
* The input mode where the client renders the images to an input Surface
@@ -125,18 +101,18 @@
*
* @see #getInputSurface()
*/
- public static final int INPUT_MODE_SURFACE = 1;
+ public static final int INPUT_MODE_SURFACE = WriterBase.INPUT_MODE_SURFACE;
/**
* The input mode where the client adds bitmaps.
*
* @see #addBitmap(Bitmap)
*/
- public static final int INPUT_MODE_BITMAP = 2;
+ public static final int INPUT_MODE_BITMAP = WriterBase.INPUT_MODE_BITMAP;
/** @hide */
@IntDef({
- INPUT_MODE_BUFFER, INPUT_MODE_SURFACE, INPUT_MODE_BITMAP,
+ INPUT_MODE_BUFFER, INPUT_MODE_SURFACE, INPUT_MODE_BITMAP,
})
@Retention(RetentionPolicy.SOURCE)
public @interface InputMode {}
@@ -161,13 +137,15 @@
* Construct a Builder with output specified by its path.
*
* @param path Path of the file to be written.
- * @param width Width of the image.
- * @param height Height of the image.
+ * @param width Width of the image in number of pixels.
+ * @param height Height of the image in number of pixels.
* @param inputMode Input mode for this writer, must be one of {@link #INPUT_MODE_BUFFER},
* {@link #INPUT_MODE_SURFACE}, or {@link #INPUT_MODE_BITMAP}.
*/
public Builder(@NonNull String path,
- int width, int height, @InputMode int inputMode) {
+ @IntRange(from = 1) int width,
+ @IntRange(from = 1) int height,
+ @InputMode int inputMode) {
this(path, null, width, height, inputMode);
}
@@ -175,21 +153,22 @@
* Construct a Builder with output specified by its file descriptor.
*
* @param fd File descriptor of the file to be written.
- * @param width Width of the image.
- * @param height Height of the image.
+ * @param width Width of the image in number of pixels.
+ * @param height Height of the image in number of pixels.
* @param inputMode Input mode for this writer, must be one of {@link #INPUT_MODE_BUFFER},
* {@link #INPUT_MODE_SURFACE}, or {@link #INPUT_MODE_BITMAP}.
*/
public Builder(@NonNull FileDescriptor fd,
- int width, int height, @InputMode int inputMode) {
+ @IntRange(from = 1) int width,
+ @IntRange(from = 1) int height,
+ @InputMode int inputMode) {
this(null, fd, width, height, inputMode);
}
private Builder(String path, FileDescriptor fd,
- int width, int height, @InputMode int inputMode) {
- if (width <= 0 || height <= 0) {
- throw new IllegalArgumentException("Invalid image size: " + width + "x" + height);
- }
+ @IntRange(from = 1) int width,
+ @IntRange(from = 1) int height,
+ @InputMode int inputMode) {
mPath = path;
mFd = fd;
mWidth = width;
@@ -200,11 +179,11 @@
/**
* Set the image rotation in degrees.
*
- * @param rotation Rotation angle (clockwise) of the image, must be 0, 90, 180 or 270.
- * Default is 0.
+ * @param rotation Rotation angle in degrees (clockwise) of the image, must be 0, 90,
+ * 180 or 270. Default is 0.
* @return this Builder object.
*/
- public Builder setRotation(int rotation) {
+ public @NonNull Builder setRotation(@IntRange(from = 0) int rotation) {
if (rotation != 0 && rotation != 90 && rotation != 180 && rotation != 270) {
throw new IllegalArgumentException("Invalid rotation angle: " + rotation);
}
@@ -219,7 +198,7 @@
* automatically chosen. Default is to enable.
* @return this Builder object.
*/
- public Builder setGridEnabled(boolean gridEnabled) {
+ public @NonNull Builder setGridEnabled(boolean gridEnabled) {
mGridEnabled = gridEnabled;
return this;
}
@@ -231,7 +210,7 @@
* quality supported by this implementation. Default is 100.
* @return this Builder object.
*/
- public Builder setQuality(int quality) {
+ public @NonNull Builder setQuality(@IntRange(from = 0, to = 100) int quality) {
if (quality < 0 || quality > 100) {
throw new IllegalArgumentException("Invalid quality: " + quality);
}
@@ -250,7 +229,7 @@
* Default is 1.
* @return this Builder object.
*/
- public Builder setMaxImages(int maxImages) {
+ public @NonNull Builder setMaxImages(@IntRange(from = 1) int maxImages) {
if (maxImages <= 0) {
throw new IllegalArgumentException("Invalid maxImage: " + maxImages);
}
@@ -265,10 +244,7 @@
* range [0, maxImages - 1] inclusive. Default is 0.
* @return this Builder object.
*/
- public Builder setPrimaryIndex(int primaryIndex) {
- if (primaryIndex < 0) {
- throw new IllegalArgumentException("Invalid primaryIndex: " + primaryIndex);
- }
+ public @NonNull Builder setPrimaryIndex(@IntRange(from = 0) int primaryIndex) {
mPrimaryIndex = primaryIndex;
return this;
}
@@ -281,7 +257,7 @@
* writer. Default is null.
* @return this Builder object.
*/
- public Builder setHandler(@Nullable Handler handler) {
+ public @NonNull Builder setHandler(@Nullable Handler handler) {
mHandler = handler;
return this;
}
@@ -293,428 +269,46 @@
* @throws IOException if failed to create the writer, possibly due to failure to create
* {@link android.media.MediaMuxer} or {@link android.media.MediaCodec}.
*/
- public HeifWriter build() throws IOException {
+ public @NonNull HeifWriter build() throws IOException {
return new HeifWriter(mPath, mFd, mWidth, mHeight, mRotation, mGridEnabled, mQuality,
- mMaxImages, mPrimaryIndex, mInputMode, mHandler);
+ mMaxImages, mPrimaryIndex, mInputMode, mHandler);
}
}
@SuppressLint("WrongConstant")
@SuppressWarnings("WeakerAccess") /* synthetic access */
HeifWriter(@NonNull String path,
- @NonNull FileDescriptor fd,
- int width,
- int height,
- int rotation,
- boolean gridEnabled,
- int quality,
- int maxImages,
- int primaryIndex,
- @InputMode int inputMode,
- @Nullable Handler handler) throws IOException {
- if (primaryIndex >= maxImages) {
- throw new IllegalArgumentException(
- "Invalid maxImages (" + maxImages + ") or primaryIndex (" + primaryIndex + ")");
- }
+ @NonNull FileDescriptor fd,
+ int width,
+ int height,
+ int rotation,
+ boolean gridEnabled,
+ int quality,
+ int maxImages,
+ int primaryIndex,
+ @InputMode int inputMode,
+ @Nullable Handler handler) throws IOException {
+ super(rotation, inputMode, maxImages, primaryIndex, gridEnabled, quality,
+ handler, /* highBitDepthEnabled */ false);
if (DEBUG) {
Log.d(TAG, "width: " + width
- + ", height: " + height
- + ", rotation: " + rotation
- + ", gridEnabled: " + gridEnabled
- + ", quality: " + quality
- + ", maxImages: " + maxImages
- + ", primaryIndex: " + primaryIndex
- + ", inputMode: " + inputMode);
+ + ", height: " + height
+ + ", rotation: " + rotation
+ + ", gridEnabled: " + gridEnabled
+ + ", quality: " + quality
+ + ", maxImages: " + maxImages
+ + ", primaryIndex: " + primaryIndex
+ + ", inputMode: " + inputMode);
}
// set to 1 initially, and wait for output format to know for sure
mNumTiles = 1;
- mRotation = rotation;
- mInputMode = inputMode;
- mMaxImages = maxImages;
- mPrimaryIndex = primaryIndex;
-
- Looper looper = (handler != null) ? handler.getLooper() : null;
- if (looper == null) {
- mHandlerThread = new HandlerThread("HeifEncoderThread",
- Process.THREAD_PRIORITY_FOREGROUND);
- mHandlerThread.start();
- looper = mHandlerThread.getLooper();
- } else {
- mHandlerThread = null;
- }
- mHandler = new Handler(looper);
-
mMuxer = (path != null) ? new MediaMuxer(path, MUXER_OUTPUT_HEIF)
- : new MediaMuxer(fd, MUXER_OUTPUT_HEIF);
+ : new MediaMuxer(fd, MUXER_OUTPUT_HEIF);
- mHeifEncoder = new HeifEncoder(width, height, gridEnabled, quality,
- mInputMode, mHandler, new HeifCallback());
+ mEncoder = new HeifEncoder(width, height, gridEnabled, quality,
+ mInputMode, mHandler, new WriterCallback());
}
-
- /**
- * Start the heif writer. Can only be called once.
- *
- * @throws IllegalStateException if called more than once.
- */
- public void start() {
- checkStarted(false);
- mStarted = true;
- mHeifEncoder.start();
- }
-
- /**
- * Add one YUV buffer to the heif file.
- *
- * @param format The YUV format as defined in {@link android.graphics.ImageFormat}, currently
- * only support YUV_420_888.
- *
- * @param data byte array containing the YUV data. If the format has more than one planes,
- * they must be concatenated.
- *
- * @throws IllegalStateException if not started or not configured to use buffer input.
- */
- public void addYuvBuffer(int format, @NonNull byte[] data) {
- checkStartedAndMode(INPUT_MODE_BUFFER);
- synchronized (this) {
- if (mHeifEncoder != null) {
- mHeifEncoder.addYuvBuffer(format, data);
- }
- }
- }
-
- /**
- * Retrieves the input surface for encoding.
- *
- * @return the input surface if configured to use surface input.
- *
- * @throws IllegalStateException if called after start or not configured to use surface input.
- */
- public @NonNull Surface getInputSurface() {
- checkStarted(false);
- checkMode(INPUT_MODE_SURFACE);
- return mHeifEncoder.getInputSurface();
- }
-
- /**
- * Set the timestamp (in nano seconds) of the last input frame to encode.
- *
- * This call is only valid for surface input. Client can use this to stop the heif writer
- * earlier before the maximum number of images are written. If not called, the writer will
- * only stop when the maximum number of images are written.
- *
- * @param timestampNs timestamp (in nano seconds) of the last frame that will be written to the
- * heif file. Frames with timestamps larger than the specified value will not
- * be written. However, if a frame already started encoding when this is set,
- * all tiles within that frame will be encoded.
- *
- * @throws IllegalStateException if not started or not configured to use surface input.
- */
- public void setInputEndOfStreamTimestamp(long timestampNs) {
- checkStartedAndMode(INPUT_MODE_SURFACE);
- synchronized (this) {
- if (mHeifEncoder != null) {
- mHeifEncoder.setEndOfInputStreamTimestamp(timestampNs);
- }
- }
- }
-
- /**
- * Add one bitmap to the heif file.
- *
- * @param bitmap the bitmap to be added to the file.
- * @throws IllegalStateException if not started or not configured to use bitmap input.
- */
- public void addBitmap(@NonNull Bitmap bitmap) {
- checkStartedAndMode(INPUT_MODE_BITMAP);
- synchronized (this) {
- if (mHeifEncoder != null) {
- mHeifEncoder.addBitmap(bitmap);
- }
- }
- }
-
- /**
- * Add Exif data for the specified image. The data must be a valid Exif data block,
- * starting with "Exif\0\0" followed by the TIFF header (See JEITA CP-3451C Section 4.5.2.)
- *
- * @param imageIndex index of the image, must be a valid index for the max number of image
- * specified by {@link Builder#setMaxImages(int)}.
- * @param exifData byte buffer containing a Exif data block.
- * @param offset offset of the Exif data block within exifData.
- * @param length length of the Exif data block.
- */
- public void addExifData(int imageIndex, @NonNull byte[] exifData, int offset, int length) {
- checkStarted(true);
-
- ByteBuffer buffer = ByteBuffer.allocateDirect(length);
- buffer.put(exifData, offset, length);
- buffer.flip();
- // Put it in a queue, as we might not be able to process it at this time.
- synchronized (mExifList) {
- mExifList.add(new Pair<Integer, ByteBuffer>(imageIndex, buffer));
- }
- processExifData();
- }
-
- @SuppressLint("WrongConstant")
- @SuppressWarnings("WeakerAccess") /* synthetic access */
- void processExifData() {
- if (!mMuxerStarted.get()) {
- return;
- }
-
- while (true) {
- Pair<Integer, ByteBuffer> entry;
- synchronized (mExifList) {
- if (mExifList.isEmpty()) {
- return;
- }
- entry = mExifList.remove(0);
- }
- MediaCodec.BufferInfo info = new MediaCodec.BufferInfo();
- info.set(entry.second.position(), entry.second.remaining(), 0, MUXER_DATA_FLAG);
- mMuxer.writeSampleData(mTrackIndexArray[entry.first], entry.second, info);
- }
- }
-
- /**
- * Stop the heif writer synchronously. Throws exception if the writer didn't finish writing
- * successfully. Upon a success return:
- *
- * - For buffer and bitmap inputs, all images sent before stop will be written.
- *
- * - For surface input, images with timestamp on or before that specified in
- * {@link #setInputEndOfStreamTimestamp(long)} will be written. In case where
- * {@link #setInputEndOfStreamTimestamp(long)} was never called, stop will block
- * until maximum number of images are received.
- *
- * @param timeoutMs Maximum time (in microsec) to wait for the writer to complete, with zero
- * indicating waiting indefinitely.
- * @see #setInputEndOfStreamTimestamp(long)
- * @throws Exception if encountered error, in which case the output file may not be valid. In
- * particular, {@link TimeoutException} is thrown when timed out, and {@link
- * MediaCodec.CodecException} is thrown when encountered codec error.
- */
- public void stop(long timeoutMs) throws Exception {
- checkStarted(true);
- synchronized (this) {
- if (mHeifEncoder != null) {
- mHeifEncoder.stopAsync();
- }
- }
- mResultWaiter.waitForResult(timeoutMs);
- processExifData();
- closeInternal();
- }
-
- private void checkStarted(boolean requiredStarted) {
- if (mStarted != requiredStarted) {
- throw new IllegalStateException("Already started");
- }
- }
-
- private void checkMode(@InputMode int requiredMode) {
- if (mInputMode != requiredMode) {
- throw new IllegalStateException("Not valid in input mode " + mInputMode);
- }
- }
-
- private void checkStartedAndMode(@InputMode int requiredMode) {
- checkStarted(true);
- checkMode(requiredMode);
- }
-
- /**
- * Routine to stop and release writer, must be called on the same looper
- * that receives heif encoder callbacks.
- */
- @SuppressWarnings("WeakerAccess") /* synthetic access */
- void closeInternal() {
- if (DEBUG) Log.d(TAG, "closeInternal");
- // We don't want to crash when closing, catch all exceptions.
- try {
- // Muxer could throw exceptions if stop is called without samples.
- // Don't crash in that case.
- if (mMuxer != null) {
- mMuxer.stop();
- mMuxer.release();
- }
- } catch (Exception e) {
- } finally {
- mMuxer = null;
- }
- try {
- if (mHeifEncoder != null) {
- mHeifEncoder.close();
- }
- } catch (Exception e) {
- } finally {
- synchronized (this) {
- mHeifEncoder = null;
- }
- }
- }
-
- /**
- * Callback from the heif encoder.
- */
- @SuppressWarnings("WeakerAccess") /* synthetic access */
- class HeifCallback extends HeifEncoder.Callback {
- private boolean mEncoderStopped;
- /**
- * Upon receiving output format from the encoder, add the requested number of
- * image tracks to the muxer and start the muxer.
- */
- @Override
- public void onOutputFormatChanged(
- @NonNull HeifEncoder encoder, @NonNull MediaFormat format) {
- if (mEncoderStopped) return;
-
- if (DEBUG) {
- Log.d(TAG, "onOutputFormatChanged: " + format);
- }
- if (mTrackIndexArray != null) {
- stopAndNotify(new IllegalStateException(
- "Output format changed after muxer started"));
- return;
- }
-
- try {
- int gridRows = format.getInteger(MediaFormat.KEY_GRID_ROWS);
- int gridCols = format.getInteger(MediaFormat.KEY_GRID_COLUMNS);
- mNumTiles = gridRows * gridCols;
- } catch (NullPointerException | ClassCastException e) {
- mNumTiles = 1;
- }
-
- // add mMaxImages image tracks of the same format
- mTrackIndexArray = new int[mMaxImages];
-
- // set rotation angle
- if (mRotation > 0) {
- Log.d(TAG, "setting rotation: " + mRotation);
- mMuxer.setOrientationHint(mRotation);
- }
- for (int i = 0; i < mTrackIndexArray.length; i++) {
- // mark primary
- format.setInteger(MediaFormat.KEY_IS_DEFAULT, (i == mPrimaryIndex) ? 1 : 0);
- mTrackIndexArray[i] = mMuxer.addTrack(format);
- }
- mMuxer.start();
- mMuxerStarted.set(true);
- processExifData();
- }
-
- /**
- * Upon receiving an output buffer from the encoder (which is one image when
- * grid is not used, or one tile if grid is used), add that sample to the muxer.
- */
- @Override
- public void onDrainOutputBuffer(
- @NonNull HeifEncoder encoder, @NonNull ByteBuffer byteBuffer) {
- if (mEncoderStopped) return;
-
- if (DEBUG) {
- Log.d(TAG, "onDrainOutputBuffer: " + mOutputIndex);
- }
- if (mTrackIndexArray == null) {
- stopAndNotify(new IllegalStateException(
- "Output buffer received before format info"));
- return;
- }
-
- if (mOutputIndex < mMaxImages * mNumTiles) {
- MediaCodec.BufferInfo info = new MediaCodec.BufferInfo();
- info.set(byteBuffer.position(), byteBuffer.remaining(), 0, 0);
- mMuxer.writeSampleData(
- mTrackIndexArray[mOutputIndex / mNumTiles], byteBuffer, info);
- }
-
- mOutputIndex++;
-
- // post EOS if reached max number of images allowed.
- if (mOutputIndex == mMaxImages * mNumTiles) {
- stopAndNotify(null);
- }
- }
-
- @Override
- public void onComplete(@NonNull HeifEncoder encoder) {
- stopAndNotify(null);
- }
-
- @Override
- public void onError(@NonNull HeifEncoder encoder, @NonNull MediaCodec.CodecException e) {
- stopAndNotify(e);
- }
-
- private void stopAndNotify(@Nullable Exception error) {
- if (mEncoderStopped) return;
-
- mEncoderStopped = true;
- mResultWaiter.signalResult(error);
- }
- }
-
- @SuppressWarnings("WeakerAccess") /* synthetic access */
- static class ResultWaiter {
- private boolean mDone;
- private Exception mException;
-
- synchronized void waitForResult(long timeoutMs) throws Exception {
- if (timeoutMs < 0) {
- throw new IllegalArgumentException("timeoutMs is negative");
- }
- if (timeoutMs == 0) {
- while (!mDone) {
- try {
- wait();
- } catch (InterruptedException ex) {}
- }
- } else {
- final long startTimeMs = System.currentTimeMillis();
- long remainingWaitTimeMs = timeoutMs;
- // avoid early termination by "spurious" wakeup.
- while (!mDone && remainingWaitTimeMs > 0) {
- try {
- wait(remainingWaitTimeMs);
- } catch (InterruptedException ex) {}
- remainingWaitTimeMs -= (System.currentTimeMillis() - startTimeMs);
- }
- }
- if (!mDone) {
- mDone = true;
- mException = new TimeoutException("timed out waiting for result");
- }
- if (mException != null) {
- throw mException;
- }
- }
-
- synchronized void signalResult(@Nullable Exception e) {
- if (!mDone) {
- mDone = true;
- mException = e;
- notifyAll();
- }
- }
- }
-
- @Override
- public void close() {
- mHandler.postAtFrontOfQueue(new Runnable() {
- @Override
- public void run() {
- try {
- closeInternal();
- } catch (Exception e) {
- // If the client called stop() properly, any errors would have been
- // reported there. We don't want to crash when closing.
- }
- }
- });
- }
-}
+}
\ No newline at end of file
diff --git a/heifwriter/heifwriter/src/main/java/androidx/heifwriter/WriterBase.java b/heifwriter/heifwriter/src/main/java/androidx/heifwriter/WriterBase.java
new file mode 100644
index 0000000..7f283edf
--- /dev/null
+++ b/heifwriter/heifwriter/src/main/java/androidx/heifwriter/WriterBase.java
@@ -0,0 +1,572 @@
+/*
+ * Copyright 2022 Google Inc. All rights reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.heifwriter;
+
+import static android.media.MediaMuxer.OutputFormat.MUXER_OUTPUT_HEIF;
+
+import android.annotation.SuppressLint;
+import android.graphics.Bitmap;
+import android.media.MediaCodec;
+import android.media.MediaFormat;
+import android.media.MediaMuxer;
+import android.os.Handler;
+import android.os.HandlerThread;
+import android.os.Looper;
+import android.os.Process;
+import android.util.Log;
+import android.util.Pair;
+import android.view.Surface;
+
+import androidx.annotation.IntDef;
+import androidx.annotation.IntRange;
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+
+import java.io.FileDescriptor;
+import java.io.IOException;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.nio.ByteBuffer;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.concurrent.TimeoutException;
+import java.util.concurrent.atomic.AtomicBoolean;
+
+/**
+ * This class holds common utliities for {@link HeifWriter} and {@link AvifWriter}.
+ *
+ * @hide
+ */
+public class WriterBase implements AutoCloseable {
+ private static final String TAG = "WriterBase";
+ private static final boolean DEBUG = false;
+ private static final int MUXER_DATA_FLAG = 16;
+
+ /**
+ * The input mode where the client adds input buffers with YUV data.
+ *
+ * @see #addYuvBuffer(int, byte[])
+ */
+ protected static final int INPUT_MODE_BUFFER = 0;
+
+ /**
+ * The input mode where the client renders the images to an input Surface
+ * created by the writer.
+ *
+ * The input surface operates in single buffer mode. As a result, for use case
+ * where camera directly outputs to the input surface, this mode will not work
+ * because camera framework requires multiple buffers to operate in a pipeline
+ * fashion.
+ *
+ * @see #getInputSurface()
+ */
+ protected static final int INPUT_MODE_SURFACE = 1;
+
+ /**
+ * The input mode where the client adds bitmaps.
+ *
+ * @see #addBitmap(Bitmap)
+ */
+ protected static final int INPUT_MODE_BITMAP = 2;
+
+ /** @hide */
+ @IntDef({
+ INPUT_MODE_BUFFER, INPUT_MODE_SURFACE, INPUT_MODE_BITMAP,
+ })
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface InputMode {}
+
+ protected final @InputMode int mInputMode;
+ protected final boolean mHighBitDepthEnabled;
+ protected final HandlerThread mHandlerThread;
+ protected final Handler mHandler;
+ @SuppressWarnings("WeakerAccess") /* synthetic access */
+ protected int mNumTiles;
+ @SuppressWarnings("WeakerAccess") /* synthetic access */
+ protected final int mRotation;
+ @SuppressWarnings("WeakerAccess") /* synthetic access */
+ protected final int mMaxImages;
+ @SuppressWarnings("WeakerAccess") /* synthetic access */
+ protected final int mPrimaryIndex;
+ @SuppressWarnings("WeakerAccess") /* synthetic access */
+ final ResultWaiter mResultWaiter = new ResultWaiter();
+ @SuppressWarnings("WeakerAccess") /* synthetic access */
+ @NonNull protected MediaMuxer mMuxer;
+ @NonNull protected EncoderBase mEncoder;
+ final AtomicBoolean mMuxerStarted = new AtomicBoolean(false);
+ @SuppressWarnings("WeakerAccess") /* synthetic access */
+ int[] mTrackIndexArray;
+ @SuppressWarnings("WeakerAccess") /* synthetic access */
+ int mOutputIndex;
+ @SuppressWarnings("WeakerAccess") /* synthetic access */
+ boolean mGridEnabled;
+ @SuppressWarnings("WeakerAccess") /* synthetic access */
+ int mQuality;
+ private boolean mStarted;
+
+ private final List<Pair<Integer, ByteBuffer>> mExifList = new ArrayList<>();
+
+ protected WriterBase(int rotation,
+ @InputMode int inputMode,
+ int maxImages,
+ int primaryIndex,
+ boolean gridEnabled,
+ int quality,
+ @Nullable Handler handler,
+ boolean highBitDepthEnabled) throws IOException {
+ if (primaryIndex >= maxImages) {
+ throw new IllegalArgumentException(
+ "Invalid maxImages (" + maxImages + ") or primaryIndex (" + primaryIndex + ")");
+ }
+
+ mRotation = rotation;
+ mInputMode = inputMode;
+ mMaxImages = maxImages;
+ mPrimaryIndex = primaryIndex;
+ mGridEnabled = gridEnabled;
+ mQuality = quality;
+ mHighBitDepthEnabled = highBitDepthEnabled;
+
+ Looper looper = (handler != null) ? handler.getLooper() : null;
+ if (looper == null) {
+ mHandlerThread = new HandlerThread("HeifEncoderThread",
+ Process.THREAD_PRIORITY_FOREGROUND);
+ mHandlerThread.start();
+ looper = mHandlerThread.getLooper();
+ } else {
+ mHandlerThread = null;
+ }
+ mHandler = new Handler(looper);
+ }
+
+ /**
+ * Start the heif writer. Can only be called once.
+ *
+ * @throws IllegalStateException if called more than once.
+ */
+ public void start() {
+ checkStarted(false);
+ mStarted = true;
+ mEncoder.start();
+ }
+
+ /**
+ * Add one YUV buffer to the heif file.
+ *
+ * @param format The YUV format as defined in {@link android.graphics.ImageFormat}, currently
+ * only support YUV_420_888.
+ *
+ * @param data byte array containing the YUV data. If the format has more than one planes,
+ * they must be concatenated.
+ *
+ * @throws IllegalStateException if not started or not configured to use buffer input.
+ */
+ public void addYuvBuffer(int format, @NonNull byte[] data) {
+ checkStartedAndMode(INPUT_MODE_BUFFER);
+ synchronized (this) {
+ if (mEncoder != null) {
+ mEncoder.addYuvBuffer(format, data);
+ }
+ }
+ }
+
+ /**
+ * Retrieves the input surface for encoding.
+ *
+ * @return the input surface if configured to use surface input.
+ *
+ * @throws IllegalStateException if called after start or not configured to use surface input.
+ */
+ public @NonNull Surface getInputSurface() {
+ checkStarted(false);
+ checkMode(INPUT_MODE_SURFACE);
+ return mEncoder.getInputSurface();
+ }
+
+ /**
+ * Set the timestamp (in nano seconds) of the last input frame to encode.
+ *
+ * This call is only valid for surface input. Client can use this to stop the heif writer
+ * earlier before the maximum number of images are written. If not called, the writer will
+ * only stop when the maximum number of images are written.
+ *
+ * @param timestampNs timestamp (in nano seconds) of the last frame that will be written to the
+ * heif file. Frames with timestamps larger than the specified value will not
+ * be written. However, if a frame already started encoding when this is set,
+ * all tiles within that frame will be encoded.
+ *
+ * @throws IllegalStateException if not started or not configured to use surface input.
+ */
+ public void setInputEndOfStreamTimestamp(@IntRange(from = 0) long timestampNs) {
+ checkStartedAndMode(INPUT_MODE_SURFACE);
+ synchronized (this) {
+ if (mEncoder != null) {
+ mEncoder.setEndOfInputStreamTimestamp(timestampNs);
+ }
+ }
+ }
+
+ /**
+ * Add one bitmap to the heif file.
+ *
+ * @param bitmap the bitmap to be added to the file.
+ * @throws IllegalStateException if not started or not configured to use bitmap input.
+ */
+ public void addBitmap(@NonNull Bitmap bitmap) {
+ checkStartedAndMode(INPUT_MODE_BITMAP);
+ synchronized (this) {
+ if (mEncoder != null) {
+ mEncoder.addBitmap(bitmap);
+ }
+ }
+ }
+
+ /**
+ * Add Exif data for the specified image. The data must be a valid Exif data block,
+ * starting with "Exif\0\0" followed by the TIFF header (See JEITA CP-3451C Section 4.5.2.)
+ *
+ * @param imageIndex index of the image, must be a valid index for the max number of image
+ * specified by {@link Builder#setMaxImages(int)}.
+ * @param exifData byte buffer containing a Exif data block.
+ * @param offset offset of the Exif data block within exifData.
+ * @param length length of the Exif data block.
+ */
+ public void addExifData(int imageIndex, @NonNull byte[] exifData, int offset, int length) {
+ checkStarted(true);
+
+ ByteBuffer buffer = ByteBuffer.allocateDirect(length);
+ buffer.put(exifData, offset, length);
+ buffer.flip();
+ // Put it in a queue, as we might not be able to process it at this time.
+ synchronized (mExifList) {
+ mExifList.add(new Pair<Integer, ByteBuffer>(imageIndex, buffer));
+ }
+ processExifData();
+ }
+
+ @SuppressLint("WrongConstant")
+ @SuppressWarnings("WeakerAccess") /* synthetic access */
+ void processExifData() {
+ if (!mMuxerStarted.get()) {
+ return;
+ }
+
+ while (true) {
+ Pair<Integer, ByteBuffer> entry;
+ synchronized (mExifList) {
+ if (mExifList.isEmpty()) {
+ return;
+ }
+ entry = mExifList.remove(0);
+ }
+ MediaCodec.BufferInfo info = new MediaCodec.BufferInfo();
+ info.set(entry.second.position(), entry.second.remaining(), 0, MUXER_DATA_FLAG);
+ mMuxer.writeSampleData(mTrackIndexArray[entry.first], entry.second, info);
+ }
+ }
+
+ /**
+ * Stop the heif writer synchronously. Throws exception if the writer didn't finish writing
+ * successfully. Upon a success return:
+ *
+ * - For buffer and bitmap inputs, all images sent before stop will be written.
+ *
+ * - For surface input, images with timestamp on or before that specified in
+ * {@link #setInputEndOfStreamTimestamp(long)} will be written. In case where
+ * {@link #setInputEndOfStreamTimestamp(long)} was never called, stop will block
+ * until maximum number of images are received.
+ *
+ * @param timeoutMs Maximum time (in microsec) to wait for the writer to complete, with zero
+ * indicating waiting indefinitely.
+ * @see #setInputEndOfStreamTimestamp(long)
+ * @throws Exception if encountered error, in which case the output file may not be valid. In
+ * particular, {@link TimeoutException} is thrown when timed out, and {@link
+ * MediaCodec.CodecException} is thrown when encountered codec error.
+ */
+ public void stop(@IntRange(from = 0) long timeoutMs) throws Exception {
+ checkStarted(true);
+ synchronized (this) {
+ if (mEncoder != null) {
+ mEncoder.stopAsync();
+ }
+ }
+ mResultWaiter.waitForResult(timeoutMs);
+ processExifData();
+ closeInternal();
+ }
+
+ private void checkStarted(boolean requiredStarted) {
+ if (mStarted != requiredStarted) {
+ throw new IllegalStateException("Already started");
+ }
+ }
+
+ private void checkMode(@InputMode int requiredMode) {
+ if (mInputMode != requiredMode) {
+ throw new IllegalStateException("Not valid in input mode " + mInputMode);
+ }
+ }
+
+ private void checkStartedAndMode(@InputMode int requiredMode) {
+ checkStarted(true);
+ checkMode(requiredMode);
+ }
+
+ /**
+ * Routine to stop and release writer, must be called on the same looper
+ * that receives heif encoder callbacks.
+ */
+ @SuppressWarnings("WeakerAccess") /* synthetic access */
+ void closeInternal() {
+ if (DEBUG) Log.d(TAG, "closeInternal");
+ // We don't want to crash when closing, catch all exceptions.
+ try {
+ // Muxer could throw exceptions if stop is called without samples.
+ // Don't crash in that case.
+ if (mMuxer != null) {
+ mMuxer.stop();
+ mMuxer.release();
+ }
+ } catch (Exception e) {
+ } finally {
+ mMuxer = null;
+ }
+ try {
+ if (mEncoder != null) {
+ mEncoder.close();
+ }
+ } catch (Exception e) {
+ } finally {
+ synchronized (this) {
+ mEncoder = null;
+ }
+ }
+ }
+
+ /**
+ * Callback from the encoder.
+ */
+ @SuppressWarnings("WeakerAccess") /* synthetic access */
+ protected class WriterCallback extends EncoderBase.Callback {
+ private boolean mEncoderStopped;
+ /**
+ * Upon receiving output format from the encoder, add the requested number of
+ * image tracks to the muxer and start the muxer.
+ */
+ @Override
+ public void onOutputFormatChanged(
+ @NonNull EncoderBase encoder, @NonNull MediaFormat format) {
+ if (mEncoderStopped) return;
+
+ if (DEBUG) {
+ Log.d(TAG, "onOutputFormatChanged: " + format);
+ }
+ if (mTrackIndexArray != null) {
+ stopAndNotify(new IllegalStateException(
+ "Output format changed after muxer started"));
+ return;
+ }
+
+ try {
+ int gridRows = format.getInteger(MediaFormat.KEY_GRID_ROWS);
+ int gridCols = format.getInteger(MediaFormat.KEY_GRID_COLUMNS);
+ mNumTiles = gridRows * gridCols;
+ } catch (NullPointerException | ClassCastException e) {
+ mNumTiles = 1;
+ }
+
+ // add mMaxImages image tracks of the same format
+ mTrackIndexArray = new int[mMaxImages];
+
+ // set rotation angle
+ if (mRotation > 0) {
+ Log.d(TAG, "setting rotation: " + mRotation);
+ mMuxer.setOrientationHint(mRotation);
+ }
+ for (int i = 0; i < mTrackIndexArray.length; i++) {
+ // mark primary
+ format.setInteger(MediaFormat.KEY_IS_DEFAULT, (i == mPrimaryIndex) ? 1 : 0);
+ mTrackIndexArray[i] = mMuxer.addTrack(format);
+ }
+ mMuxer.start();
+ mMuxerStarted.set(true);
+ processExifData();
+ }
+
+ /**
+ * Upon receiving an output buffer from the encoder (which is one image when
+ * grid is not used, or one tile if grid is used), add that sample to the muxer.
+ */
+ @Override
+ public void onDrainOutputBuffer(
+ @NonNull EncoderBase encoder, @NonNull ByteBuffer byteBuffer) {
+ if (mEncoderStopped) return;
+
+ if (DEBUG) {
+ Log.d(TAG, "onDrainOutputBuffer: " + mOutputIndex);
+ }
+ if (mTrackIndexArray == null) {
+ stopAndNotify(new IllegalStateException(
+ "Output buffer received before format info"));
+ return;
+ }
+
+ if (mOutputIndex < mMaxImages * mNumTiles) {
+ MediaCodec.BufferInfo info = new MediaCodec.BufferInfo();
+ info.set(byteBuffer.position(), byteBuffer.remaining(), 0, 0);
+ mMuxer.writeSampleData(
+ mTrackIndexArray[mOutputIndex / mNumTiles], byteBuffer, info);
+ }
+
+ mOutputIndex++;
+
+ // post EOS if reached max number of images allowed.
+ if (mOutputIndex == mMaxImages * mNumTiles) {
+ stopAndNotify(null);
+ }
+ }
+
+ @Override
+ public void onComplete(@NonNull EncoderBase encoder) {
+ stopAndNotify(null);
+ }
+
+ @Override
+ public void onError(@NonNull EncoderBase encoder, @NonNull MediaCodec.CodecException e) {
+ stopAndNotify(e);
+ }
+
+ private void stopAndNotify(@Nullable Exception error) {
+ if (mEncoderStopped) return;
+
+ mEncoderStopped = true;
+ mResultWaiter.signalResult(error);
+ }
+ }
+
+ @SuppressWarnings("WeakerAccess") /* synthetic access */
+ static class ResultWaiter {
+ private boolean mDone;
+ private Exception mException;
+
+ synchronized void waitForResult(long timeoutMs) throws Exception {
+ if (timeoutMs < 0) {
+ throw new IllegalArgumentException("timeoutMs is negative");
+ }
+ if (timeoutMs == 0) {
+ while (!mDone) {
+ try {
+ wait();
+ } catch (InterruptedException ex) {}
+ }
+ } else {
+ final long startTimeMs = System.currentTimeMillis();
+ long remainingWaitTimeMs = timeoutMs;
+ // avoid early termination by "spurious" wakeup.
+ while (!mDone && remainingWaitTimeMs > 0) {
+ try {
+ wait(remainingWaitTimeMs);
+ } catch (InterruptedException ex) {}
+ remainingWaitTimeMs -= (System.currentTimeMillis() - startTimeMs);
+ }
+ }
+ if (!mDone) {
+ mDone = true;
+ mException = new TimeoutException("timed out waiting for result");
+ }
+ if (mException != null) {
+ throw mException;
+ }
+ }
+
+ synchronized void signalResult(@Nullable Exception e) {
+ if (!mDone) {
+ mDone = true;
+ mException = e;
+ notifyAll();
+ }
+ }
+ }
+
+ @Override
+ public void close() {
+ mHandler.postAtFrontOfQueue(new Runnable() {
+ @Override
+ public void run() {
+ try {
+ closeInternal();
+ } catch (Exception e) {
+ // If the client called stop() properly, any errors would have been
+ // reported there. We don't want to crash when closing.
+ }
+ }
+ });
+ }
+
+ /*
+ * Gets rotation.
+ */
+ public int getRotation() {
+ return mRotation;
+ }
+
+ /*
+ * Returns true if grid is enabled.
+ */
+ public boolean isGridEnabled() {
+ return mGridEnabled;
+ }
+
+ /*
+ * Gets configured quality.
+ */
+ public int getQuality() {
+ return mQuality;
+ }
+
+ /*
+ * Gets number of maximum images.
+ */
+ public int getMaxImages() {
+ return mMaxImages;
+ }
+
+ /*
+ * Gets index of the primary image.
+ */
+ public int getPrimaryIndex() {
+ return mPrimaryIndex;
+ }
+
+ /*
+ * Gets handler.
+ *
+ * The result is the same as clients' input from setHandler() method.
+ * If not null, client will receive all callbacks on the handler's looper.
+ * Otherwise, client will receive callbacks on the current looper.
+ */
+ public @Nullable Handler getHandler() {
+ return mHandler;
+ }
+
+ /*
+ * Returns true if high bit-depth is enabled.
+ */
+ public boolean isHighBitDepthEnabled() {
+ return mHighBitDepthEnabled;
+ }
+}
\ No newline at end of file
diff --git a/leanback/leanback/api/api_lint.ignore b/leanback/leanback/api/api_lint.ignore
index a72d2ae..a568a48 100644
--- a/leanback/leanback/api/api_lint.ignore
+++ b/leanback/leanback/api/api_lint.ignore
@@ -147,8 +147,6 @@
Invalid nullability on parameter `view` in method `onViewCreated`. Parameters of overrides cannot be NonNull if the super parameter is unannotated.
InvalidNullabilityOverride: androidx.leanback.widget.GuidedActionEditText#onTouchEvent(android.view.MotionEvent) parameter #0:
Invalid nullability on parameter `event` in method `onTouchEvent`. Parameters of overrides cannot be NonNull if the super parameter is unannotated.
-InvalidNullabilityOverride: androidx.leanback.widget.ShadowOverlayContainer#draw(android.graphics.Canvas) parameter #0:
- Invalid nullability on parameter `canvas` in method `draw`. Parameters of overrides cannot be NonNull if the super parameter is unannotated.
KotlinOperator: androidx.leanback.widget.ObjectAdapter#get(int):
@@ -1135,6 +1133,8 @@
Missing nullability on field `TOP_FRACTION` in class `class androidx.leanback.graphics.CompositeDrawable.ChildDrawable`
MissingNullability: androidx.leanback.graphics.FitWidthBitmapDrawable#PROPERTY_VERTICAL_OFFSET:
Missing nullability on field `PROPERTY_VERTICAL_OFFSET` in class `class androidx.leanback.graphics.FitWidthBitmapDrawable`
+MissingNullability: androidx.leanback.graphics.FitWidthBitmapDrawable#draw(android.graphics.Canvas) parameter #0:
+ Missing nullability on parameter `canvas` in method `draw`
MissingNullability: androidx.leanback.graphics.FitWidthBitmapDrawable#getBitmap():
Missing nullability on method `getBitmap` return
MissingNullability: androidx.leanback.graphics.FitWidthBitmapDrawable#getConstantState():
@@ -2189,6 +2189,8 @@
Missing nullability on parameter `context` in method `ShadowOverlayContainer`
MissingNullability: androidx.leanback.widget.ShadowOverlayContainer#ShadowOverlayContainer(android.content.Context, android.util.AttributeSet, int) parameter #1:
Missing nullability on parameter `attrs` in method `ShadowOverlayContainer`
+MissingNullability: androidx.leanback.widget.ShadowOverlayContainer#draw(android.graphics.Canvas) parameter #0:
+ Missing nullability on parameter `canvas` in method `draw`
MissingNullability: androidx.leanback.widget.ShadowOverlayContainer#getWrappedView():
Missing nullability on method `getWrappedView` return
MissingNullability: androidx.leanback.widget.ShadowOverlayContainer#prepareParentForShadow(android.view.ViewGroup) parameter #0:
diff --git a/libraryversions.toml b/libraryversions.toml
index 85674b8..1a45ca9 100644
--- a/libraryversions.toml
+++ b/libraryversions.toml
@@ -1,5 +1,5 @@
[versions]
-ACTIVITY = "1.7.0-beta02"
+ACTIVITY = "1.8.0-alpha02"
ADS_IDENTIFIER = "1.0.0-alpha05"
ANNOTATION = "1.7.0-alpha01"
ANNOTATION_KMP = "1.6.0-dev01"
@@ -31,7 +31,7 @@
CONSTRAINTLAYOUT_CORE = "1.1.0-alpha08"
CONTENTPAGER = "1.1.0-alpha01"
COORDINATORLAYOUT = "1.3.0-alpha01"
-CORE = "1.10.0-alpha03"
+CORE = "1.12.0-alpha01"
CORE_ANIMATION = "1.0.0-beta02"
CORE_ANIMATION_TESTING = "1.0.0-beta01"
CORE_APPDIGEST = "1.0.0-alpha01"
@@ -42,8 +42,9 @@
CORE_REMOTEVIEWS = "1.0.0-beta04"
CORE_ROLE = "1.2.0-alpha01"
CORE_SPLASHSCREEN = "1.1.0-alpha01"
+CORE_TELECOM = "1.0.0-alpha01"
CORE_UWB = "1.0.0-alpha05"
-CREDENTIALS = "1.0.0-alpha03"
+CREDENTIALS = "1.2.0-alpha01"
CURSORADAPTER = "1.1.0-alpha01"
CUSTOMVIEW = "1.2.0-alpha03"
CUSTOMVIEW_POOLINGCONTAINER = "1.1.0-alpha01"
@@ -82,12 +83,12 @@
LEANBACK_TAB = "1.1.0-beta01"
LEGACY = "1.1.0-alpha01"
LIBYUV = "0.1.0-dev01"
-LIFECYCLE = "2.6.0-beta01"
+LIFECYCLE = "2.6.0-beta02"
LIFECYCLE_EXTENSIONS = "2.2.0"
LOADER = "1.2.0-alpha01"
MEDIA = "1.7.0-alpha02"
MEDIA2 = "1.3.0-alpha01"
-MEDIAROUTER = "1.4.0-beta02"
+MEDIAROUTER = "1.6.0-alpha01"
METRICS = "1.0.0-alpha04"
NAVIGATION = "2.6.0-alpha06"
PAGING = "3.2.0-alpha05"
diff --git a/lifecycle/lifecycle-common-java8/api/2.6.0-beta02.txt b/lifecycle/lifecycle-common-java8/api/2.6.0-beta02.txt
new file mode 100644
index 0000000..e6f50d0
--- /dev/null
+++ b/lifecycle/lifecycle-common-java8/api/2.6.0-beta02.txt
@@ -0,0 +1 @@
+// Signature format: 4.0
diff --git a/lifecycle/lifecycle-common-java8/api/public_plus_experimental_2.6.0-beta02.txt b/lifecycle/lifecycle-common-java8/api/public_plus_experimental_2.6.0-beta02.txt
new file mode 100644
index 0000000..e6f50d0
--- /dev/null
+++ b/lifecycle/lifecycle-common-java8/api/public_plus_experimental_2.6.0-beta02.txt
@@ -0,0 +1 @@
+// Signature format: 4.0
diff --git a/lifecycle/lifecycle-common-java8/api/restricted_2.6.0-beta02.txt b/lifecycle/lifecycle-common-java8/api/restricted_2.6.0-beta02.txt
new file mode 100644
index 0000000..e6f50d0
--- /dev/null
+++ b/lifecycle/lifecycle-common-java8/api/restricted_2.6.0-beta02.txt
@@ -0,0 +1 @@
+// Signature format: 4.0
diff --git a/lifecycle/lifecycle-common/api/2.6.0-beta02.txt b/lifecycle/lifecycle-common/api/2.6.0-beta02.txt
new file mode 100644
index 0000000..f3dc4c9
--- /dev/null
+++ b/lifecycle/lifecycle-common/api/2.6.0-beta02.txt
@@ -0,0 +1,99 @@
+// Signature format: 4.0
+package androidx.lifecycle {
+
+ public interface DefaultLifecycleObserver extends androidx.lifecycle.LifecycleObserver {
+ method public default void onCreate(androidx.lifecycle.LifecycleOwner owner);
+ method public default void onDestroy(androidx.lifecycle.LifecycleOwner owner);
+ method public default void onPause(androidx.lifecycle.LifecycleOwner owner);
+ method public default void onResume(androidx.lifecycle.LifecycleOwner owner);
+ method public default void onStart(androidx.lifecycle.LifecycleOwner owner);
+ method public default void onStop(androidx.lifecycle.LifecycleOwner owner);
+ }
+
+ public abstract class Lifecycle {
+ ctor public Lifecycle();
+ method @MainThread public abstract void addObserver(androidx.lifecycle.LifecycleObserver observer);
+ method @MainThread public abstract androidx.lifecycle.Lifecycle.State getCurrentState();
+ method @MainThread public abstract void removeObserver(androidx.lifecycle.LifecycleObserver observer);
+ property @MainThread public abstract androidx.lifecycle.Lifecycle.State currentState;
+ }
+
+ public enum Lifecycle.Event {
+ method public static final androidx.lifecycle.Lifecycle.Event? downFrom(androidx.lifecycle.Lifecycle.State state);
+ method public static final androidx.lifecycle.Lifecycle.Event? downTo(androidx.lifecycle.Lifecycle.State state);
+ method public final androidx.lifecycle.Lifecycle.State getTargetState();
+ method public static final androidx.lifecycle.Lifecycle.Event? upFrom(androidx.lifecycle.Lifecycle.State state);
+ method public static final androidx.lifecycle.Lifecycle.Event? upTo(androidx.lifecycle.Lifecycle.State state);
+ method public static androidx.lifecycle.Lifecycle.Event valueOf(String name) throws java.lang.IllegalArgumentException;
+ method public static androidx.lifecycle.Lifecycle.Event[] values();
+ property public final androidx.lifecycle.Lifecycle.State targetState;
+ enum_constant public static final androidx.lifecycle.Lifecycle.Event ON_ANY;
+ enum_constant public static final androidx.lifecycle.Lifecycle.Event ON_CREATE;
+ enum_constant public static final androidx.lifecycle.Lifecycle.Event ON_DESTROY;
+ enum_constant public static final androidx.lifecycle.Lifecycle.Event ON_PAUSE;
+ enum_constant public static final androidx.lifecycle.Lifecycle.Event ON_RESUME;
+ enum_constant public static final androidx.lifecycle.Lifecycle.Event ON_START;
+ enum_constant public static final androidx.lifecycle.Lifecycle.Event ON_STOP;
+ field public static final androidx.lifecycle.Lifecycle.Event.Companion Companion;
+ }
+
+ public static final class Lifecycle.Event.Companion {
+ method public androidx.lifecycle.Lifecycle.Event? downFrom(androidx.lifecycle.Lifecycle.State state);
+ method public androidx.lifecycle.Lifecycle.Event? downTo(androidx.lifecycle.Lifecycle.State state);
+ method public androidx.lifecycle.Lifecycle.Event? upFrom(androidx.lifecycle.Lifecycle.State state);
+ method public androidx.lifecycle.Lifecycle.Event? upTo(androidx.lifecycle.Lifecycle.State state);
+ }
+
+ public enum Lifecycle.State {
+ method public final boolean isAtLeast(androidx.lifecycle.Lifecycle.State state);
+ method public static androidx.lifecycle.Lifecycle.State valueOf(String name) throws java.lang.IllegalArgumentException;
+ method public static androidx.lifecycle.Lifecycle.State[] values();
+ enum_constant public static final androidx.lifecycle.Lifecycle.State CREATED;
+ enum_constant public static final androidx.lifecycle.Lifecycle.State DESTROYED;
+ enum_constant public static final androidx.lifecycle.Lifecycle.State INITIALIZED;
+ enum_constant public static final androidx.lifecycle.Lifecycle.State RESUMED;
+ enum_constant public static final androidx.lifecycle.Lifecycle.State STARTED;
+ }
+
+ public abstract class LifecycleCoroutineScope implements kotlinx.coroutines.CoroutineScope {
+ method @Deprecated public final kotlinx.coroutines.Job launchWhenCreated(kotlin.jvm.functions.Function2<? super kotlinx.coroutines.CoroutineScope,? super kotlin.coroutines.Continuation<? super kotlin.Unit>,?> block);
+ method @Deprecated public final kotlinx.coroutines.Job launchWhenResumed(kotlin.jvm.functions.Function2<? super kotlinx.coroutines.CoroutineScope,? super kotlin.coroutines.Continuation<? super kotlin.Unit>,?> block);
+ method @Deprecated public final kotlinx.coroutines.Job launchWhenStarted(kotlin.jvm.functions.Function2<? super kotlinx.coroutines.CoroutineScope,? super kotlin.coroutines.Continuation<? super kotlin.Unit>,?> block);
+ }
+
+ public fun interface LifecycleEventObserver extends androidx.lifecycle.LifecycleObserver {
+ method public void onStateChanged(androidx.lifecycle.LifecycleOwner source, androidx.lifecycle.Lifecycle.Event event);
+ }
+
+ public final class LifecycleKt {
+ method public static androidx.lifecycle.LifecycleCoroutineScope getCoroutineScope(androidx.lifecycle.Lifecycle);
+ }
+
+ public interface LifecycleObserver {
+ }
+
+ public interface LifecycleOwner {
+ method public androidx.lifecycle.Lifecycle getLifecycle();
+ property public abstract androidx.lifecycle.Lifecycle lifecycle;
+ }
+
+ public final class LifecycleOwnerKt {
+ method public static androidx.lifecycle.LifecycleCoroutineScope getLifecycleScope(androidx.lifecycle.LifecycleOwner);
+ }
+
+ @Deprecated @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.RUNTIME) @java.lang.annotation.Target(java.lang.annotation.ElementType.METHOD) public @interface OnLifecycleEvent {
+ method @Deprecated public abstract androidx.lifecycle.Lifecycle.Event! value();
+ }
+
+ public final class PausingDispatcherKt {
+ method @Deprecated public static suspend <T> Object? whenCreated(androidx.lifecycle.LifecycleOwner, kotlin.jvm.functions.Function2<? super kotlinx.coroutines.CoroutineScope,? super kotlin.coroutines.Continuation<? super T>,?> block, kotlin.coroutines.Continuation<? super T>);
+ method @Deprecated public static suspend <T> Object? whenCreated(androidx.lifecycle.Lifecycle, kotlin.jvm.functions.Function2<? super kotlinx.coroutines.CoroutineScope,? super kotlin.coroutines.Continuation<? super T>,?> block, kotlin.coroutines.Continuation<? super T>);
+ method @Deprecated public static suspend <T> Object? whenResumed(androidx.lifecycle.LifecycleOwner, kotlin.jvm.functions.Function2<? super kotlinx.coroutines.CoroutineScope,? super kotlin.coroutines.Continuation<? super T>,?> block, kotlin.coroutines.Continuation<? super T>);
+ method @Deprecated public static suspend <T> Object? whenResumed(androidx.lifecycle.Lifecycle, kotlin.jvm.functions.Function2<? super kotlinx.coroutines.CoroutineScope,? super kotlin.coroutines.Continuation<? super T>,?> block, kotlin.coroutines.Continuation<? super T>);
+ method @Deprecated public static suspend <T> Object? whenStarted(androidx.lifecycle.LifecycleOwner, kotlin.jvm.functions.Function2<? super kotlinx.coroutines.CoroutineScope,? super kotlin.coroutines.Continuation<? super T>,?> block, kotlin.coroutines.Continuation<? super T>);
+ method @Deprecated public static suspend <T> Object? whenStarted(androidx.lifecycle.Lifecycle, kotlin.jvm.functions.Function2<? super kotlinx.coroutines.CoroutineScope,? super kotlin.coroutines.Continuation<? super T>,?> block, kotlin.coroutines.Continuation<? super T>);
+ method @Deprecated public static suspend <T> Object? whenStateAtLeast(androidx.lifecycle.Lifecycle, androidx.lifecycle.Lifecycle.State minState, kotlin.jvm.functions.Function2<? super kotlinx.coroutines.CoroutineScope,? super kotlin.coroutines.Continuation<? super T>,?> block, kotlin.coroutines.Continuation<? super T>);
+ }
+
+}
+
diff --git a/lifecycle/lifecycle-common/api/public_plus_experimental_2.6.0-beta02.txt b/lifecycle/lifecycle-common/api/public_plus_experimental_2.6.0-beta02.txt
new file mode 100644
index 0000000..f3dc4c9
--- /dev/null
+++ b/lifecycle/lifecycle-common/api/public_plus_experimental_2.6.0-beta02.txt
@@ -0,0 +1,99 @@
+// Signature format: 4.0
+package androidx.lifecycle {
+
+ public interface DefaultLifecycleObserver extends androidx.lifecycle.LifecycleObserver {
+ method public default void onCreate(androidx.lifecycle.LifecycleOwner owner);
+ method public default void onDestroy(androidx.lifecycle.LifecycleOwner owner);
+ method public default void onPause(androidx.lifecycle.LifecycleOwner owner);
+ method public default void onResume(androidx.lifecycle.LifecycleOwner owner);
+ method public default void onStart(androidx.lifecycle.LifecycleOwner owner);
+ method public default void onStop(androidx.lifecycle.LifecycleOwner owner);
+ }
+
+ public abstract class Lifecycle {
+ ctor public Lifecycle();
+ method @MainThread public abstract void addObserver(androidx.lifecycle.LifecycleObserver observer);
+ method @MainThread public abstract androidx.lifecycle.Lifecycle.State getCurrentState();
+ method @MainThread public abstract void removeObserver(androidx.lifecycle.LifecycleObserver observer);
+ property @MainThread public abstract androidx.lifecycle.Lifecycle.State currentState;
+ }
+
+ public enum Lifecycle.Event {
+ method public static final androidx.lifecycle.Lifecycle.Event? downFrom(androidx.lifecycle.Lifecycle.State state);
+ method public static final androidx.lifecycle.Lifecycle.Event? downTo(androidx.lifecycle.Lifecycle.State state);
+ method public final androidx.lifecycle.Lifecycle.State getTargetState();
+ method public static final androidx.lifecycle.Lifecycle.Event? upFrom(androidx.lifecycle.Lifecycle.State state);
+ method public static final androidx.lifecycle.Lifecycle.Event? upTo(androidx.lifecycle.Lifecycle.State state);
+ method public static androidx.lifecycle.Lifecycle.Event valueOf(String name) throws java.lang.IllegalArgumentException;
+ method public static androidx.lifecycle.Lifecycle.Event[] values();
+ property public final androidx.lifecycle.Lifecycle.State targetState;
+ enum_constant public static final androidx.lifecycle.Lifecycle.Event ON_ANY;
+ enum_constant public static final androidx.lifecycle.Lifecycle.Event ON_CREATE;
+ enum_constant public static final androidx.lifecycle.Lifecycle.Event ON_DESTROY;
+ enum_constant public static final androidx.lifecycle.Lifecycle.Event ON_PAUSE;
+ enum_constant public static final androidx.lifecycle.Lifecycle.Event ON_RESUME;
+ enum_constant public static final androidx.lifecycle.Lifecycle.Event ON_START;
+ enum_constant public static final androidx.lifecycle.Lifecycle.Event ON_STOP;
+ field public static final androidx.lifecycle.Lifecycle.Event.Companion Companion;
+ }
+
+ public static final class Lifecycle.Event.Companion {
+ method public androidx.lifecycle.Lifecycle.Event? downFrom(androidx.lifecycle.Lifecycle.State state);
+ method public androidx.lifecycle.Lifecycle.Event? downTo(androidx.lifecycle.Lifecycle.State state);
+ method public androidx.lifecycle.Lifecycle.Event? upFrom(androidx.lifecycle.Lifecycle.State state);
+ method public androidx.lifecycle.Lifecycle.Event? upTo(androidx.lifecycle.Lifecycle.State state);
+ }
+
+ public enum Lifecycle.State {
+ method public final boolean isAtLeast(androidx.lifecycle.Lifecycle.State state);
+ method public static androidx.lifecycle.Lifecycle.State valueOf(String name) throws java.lang.IllegalArgumentException;
+ method public static androidx.lifecycle.Lifecycle.State[] values();
+ enum_constant public static final androidx.lifecycle.Lifecycle.State CREATED;
+ enum_constant public static final androidx.lifecycle.Lifecycle.State DESTROYED;
+ enum_constant public static final androidx.lifecycle.Lifecycle.State INITIALIZED;
+ enum_constant public static final androidx.lifecycle.Lifecycle.State RESUMED;
+ enum_constant public static final androidx.lifecycle.Lifecycle.State STARTED;
+ }
+
+ public abstract class LifecycleCoroutineScope implements kotlinx.coroutines.CoroutineScope {
+ method @Deprecated public final kotlinx.coroutines.Job launchWhenCreated(kotlin.jvm.functions.Function2<? super kotlinx.coroutines.CoroutineScope,? super kotlin.coroutines.Continuation<? super kotlin.Unit>,?> block);
+ method @Deprecated public final kotlinx.coroutines.Job launchWhenResumed(kotlin.jvm.functions.Function2<? super kotlinx.coroutines.CoroutineScope,? super kotlin.coroutines.Continuation<? super kotlin.Unit>,?> block);
+ method @Deprecated public final kotlinx.coroutines.Job launchWhenStarted(kotlin.jvm.functions.Function2<? super kotlinx.coroutines.CoroutineScope,? super kotlin.coroutines.Continuation<? super kotlin.Unit>,?> block);
+ }
+
+ public fun interface LifecycleEventObserver extends androidx.lifecycle.LifecycleObserver {
+ method public void onStateChanged(androidx.lifecycle.LifecycleOwner source, androidx.lifecycle.Lifecycle.Event event);
+ }
+
+ public final class LifecycleKt {
+ method public static androidx.lifecycle.LifecycleCoroutineScope getCoroutineScope(androidx.lifecycle.Lifecycle);
+ }
+
+ public interface LifecycleObserver {
+ }
+
+ public interface LifecycleOwner {
+ method public androidx.lifecycle.Lifecycle getLifecycle();
+ property public abstract androidx.lifecycle.Lifecycle lifecycle;
+ }
+
+ public final class LifecycleOwnerKt {
+ method public static androidx.lifecycle.LifecycleCoroutineScope getLifecycleScope(androidx.lifecycle.LifecycleOwner);
+ }
+
+ @Deprecated @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.RUNTIME) @java.lang.annotation.Target(java.lang.annotation.ElementType.METHOD) public @interface OnLifecycleEvent {
+ method @Deprecated public abstract androidx.lifecycle.Lifecycle.Event! value();
+ }
+
+ public final class PausingDispatcherKt {
+ method @Deprecated public static suspend <T> Object? whenCreated(androidx.lifecycle.LifecycleOwner, kotlin.jvm.functions.Function2<? super kotlinx.coroutines.CoroutineScope,? super kotlin.coroutines.Continuation<? super T>,?> block, kotlin.coroutines.Continuation<? super T>);
+ method @Deprecated public static suspend <T> Object? whenCreated(androidx.lifecycle.Lifecycle, kotlin.jvm.functions.Function2<? super kotlinx.coroutines.CoroutineScope,? super kotlin.coroutines.Continuation<? super T>,?> block, kotlin.coroutines.Continuation<? super T>);
+ method @Deprecated public static suspend <T> Object? whenResumed(androidx.lifecycle.LifecycleOwner, kotlin.jvm.functions.Function2<? super kotlinx.coroutines.CoroutineScope,? super kotlin.coroutines.Continuation<? super T>,?> block, kotlin.coroutines.Continuation<? super T>);
+ method @Deprecated public static suspend <T> Object? whenResumed(androidx.lifecycle.Lifecycle, kotlin.jvm.functions.Function2<? super kotlinx.coroutines.CoroutineScope,? super kotlin.coroutines.Continuation<? super T>,?> block, kotlin.coroutines.Continuation<? super T>);
+ method @Deprecated public static suspend <T> Object? whenStarted(androidx.lifecycle.LifecycleOwner, kotlin.jvm.functions.Function2<? super kotlinx.coroutines.CoroutineScope,? super kotlin.coroutines.Continuation<? super T>,?> block, kotlin.coroutines.Continuation<? super T>);
+ method @Deprecated public static suspend <T> Object? whenStarted(androidx.lifecycle.Lifecycle, kotlin.jvm.functions.Function2<? super kotlinx.coroutines.CoroutineScope,? super kotlin.coroutines.Continuation<? super T>,?> block, kotlin.coroutines.Continuation<? super T>);
+ method @Deprecated public static suspend <T> Object? whenStateAtLeast(androidx.lifecycle.Lifecycle, androidx.lifecycle.Lifecycle.State minState, kotlin.jvm.functions.Function2<? super kotlinx.coroutines.CoroutineScope,? super kotlin.coroutines.Continuation<? super T>,?> block, kotlin.coroutines.Continuation<? super T>);
+ }
+
+}
+
diff --git a/lifecycle/lifecycle-common/api/restricted_2.6.0-beta02.txt b/lifecycle/lifecycle-common/api/restricted_2.6.0-beta02.txt
new file mode 100644
index 0000000..05b2709
--- /dev/null
+++ b/lifecycle/lifecycle-common/api/restricted_2.6.0-beta02.txt
@@ -0,0 +1,116 @@
+// Signature format: 4.0
+package androidx.lifecycle {
+
+ public interface DefaultLifecycleObserver extends androidx.lifecycle.LifecycleObserver {
+ method public default void onCreate(androidx.lifecycle.LifecycleOwner owner);
+ method public default void onDestroy(androidx.lifecycle.LifecycleOwner owner);
+ method public default void onPause(androidx.lifecycle.LifecycleOwner owner);
+ method public default void onResume(androidx.lifecycle.LifecycleOwner owner);
+ method public default void onStart(androidx.lifecycle.LifecycleOwner owner);
+ method public default void onStop(androidx.lifecycle.LifecycleOwner owner);
+ }
+
+ @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) public interface GeneratedAdapter {
+ method public void callMethods(androidx.lifecycle.LifecycleOwner source, androidx.lifecycle.Lifecycle.Event event, boolean onAny, androidx.lifecycle.MethodCallsLogger? logger);
+ }
+
+ @Deprecated @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) public interface GenericLifecycleObserver extends androidx.lifecycle.LifecycleEventObserver {
+ }
+
+ public abstract class Lifecycle {
+ ctor public Lifecycle();
+ method @MainThread public abstract void addObserver(androidx.lifecycle.LifecycleObserver observer);
+ method @MainThread public abstract androidx.lifecycle.Lifecycle.State getCurrentState();
+ method @MainThread public abstract void removeObserver(androidx.lifecycle.LifecycleObserver observer);
+ property @MainThread public abstract androidx.lifecycle.Lifecycle.State currentState;
+ }
+
+ public enum Lifecycle.Event {
+ method public static final androidx.lifecycle.Lifecycle.Event? downFrom(androidx.lifecycle.Lifecycle.State state);
+ method public static final androidx.lifecycle.Lifecycle.Event? downTo(androidx.lifecycle.Lifecycle.State state);
+ method public final androidx.lifecycle.Lifecycle.State getTargetState();
+ method public static final androidx.lifecycle.Lifecycle.Event? upFrom(androidx.lifecycle.Lifecycle.State state);
+ method public static final androidx.lifecycle.Lifecycle.Event? upTo(androidx.lifecycle.Lifecycle.State state);
+ method public static androidx.lifecycle.Lifecycle.Event valueOf(String name) throws java.lang.IllegalArgumentException;
+ method public static androidx.lifecycle.Lifecycle.Event[] values();
+ property public final androidx.lifecycle.Lifecycle.State targetState;
+ enum_constant public static final androidx.lifecycle.Lifecycle.Event ON_ANY;
+ enum_constant public static final androidx.lifecycle.Lifecycle.Event ON_CREATE;
+ enum_constant public static final androidx.lifecycle.Lifecycle.Event ON_DESTROY;
+ enum_constant public static final androidx.lifecycle.Lifecycle.Event ON_PAUSE;
+ enum_constant public static final androidx.lifecycle.Lifecycle.Event ON_RESUME;
+ enum_constant public static final androidx.lifecycle.Lifecycle.Event ON_START;
+ enum_constant public static final androidx.lifecycle.Lifecycle.Event ON_STOP;
+ field public static final androidx.lifecycle.Lifecycle.Event.Companion Companion;
+ }
+
+ public static final class Lifecycle.Event.Companion {
+ method public androidx.lifecycle.Lifecycle.Event? downFrom(androidx.lifecycle.Lifecycle.State state);
+ method public androidx.lifecycle.Lifecycle.Event? downTo(androidx.lifecycle.Lifecycle.State state);
+ method public androidx.lifecycle.Lifecycle.Event? upFrom(androidx.lifecycle.Lifecycle.State state);
+ method public androidx.lifecycle.Lifecycle.Event? upTo(androidx.lifecycle.Lifecycle.State state);
+ }
+
+ public enum Lifecycle.State {
+ method public final boolean isAtLeast(androidx.lifecycle.Lifecycle.State state);
+ method public static androidx.lifecycle.Lifecycle.State valueOf(String name) throws java.lang.IllegalArgumentException;
+ method public static androidx.lifecycle.Lifecycle.State[] values();
+ enum_constant public static final androidx.lifecycle.Lifecycle.State CREATED;
+ enum_constant public static final androidx.lifecycle.Lifecycle.State DESTROYED;
+ enum_constant public static final androidx.lifecycle.Lifecycle.State INITIALIZED;
+ enum_constant public static final androidx.lifecycle.Lifecycle.State RESUMED;
+ enum_constant public static final androidx.lifecycle.Lifecycle.State STARTED;
+ }
+
+ public abstract class LifecycleCoroutineScope implements kotlinx.coroutines.CoroutineScope {
+ method @Deprecated public final kotlinx.coroutines.Job launchWhenCreated(kotlin.jvm.functions.Function2<? super kotlinx.coroutines.CoroutineScope,? super kotlin.coroutines.Continuation<? super kotlin.Unit>,?> block);
+ method @Deprecated public final kotlinx.coroutines.Job launchWhenResumed(kotlin.jvm.functions.Function2<? super kotlinx.coroutines.CoroutineScope,? super kotlin.coroutines.Continuation<? super kotlin.Unit>,?> block);
+ method @Deprecated public final kotlinx.coroutines.Job launchWhenStarted(kotlin.jvm.functions.Function2<? super kotlinx.coroutines.CoroutineScope,? super kotlin.coroutines.Continuation<? super kotlin.Unit>,?> block);
+ }
+
+ public fun interface LifecycleEventObserver extends androidx.lifecycle.LifecycleObserver {
+ method public void onStateChanged(androidx.lifecycle.LifecycleOwner source, androidx.lifecycle.Lifecycle.Event event);
+ }
+
+ public final class LifecycleKt {
+ method public static androidx.lifecycle.LifecycleCoroutineScope getCoroutineScope(androidx.lifecycle.Lifecycle);
+ }
+
+ public interface LifecycleObserver {
+ }
+
+ public interface LifecycleOwner {
+ method public androidx.lifecycle.Lifecycle getLifecycle();
+ property public abstract androidx.lifecycle.Lifecycle lifecycle;
+ }
+
+ public final class LifecycleOwnerKt {
+ method public static androidx.lifecycle.LifecycleCoroutineScope getLifecycleScope(androidx.lifecycle.LifecycleOwner);
+ }
+
+ @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) public final class Lifecycling {
+ method public static String getAdapterName(String className);
+ method public static androidx.lifecycle.LifecycleEventObserver lifecycleEventObserver(Object object);
+ }
+
+ @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) public class MethodCallsLogger {
+ ctor public MethodCallsLogger();
+ method @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) public boolean approveCall(String name, int type);
+ }
+
+ @Deprecated @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.RUNTIME) @java.lang.annotation.Target(java.lang.annotation.ElementType.METHOD) public @interface OnLifecycleEvent {
+ method @Deprecated public abstract androidx.lifecycle.Lifecycle.Event! value();
+ }
+
+ public final class PausingDispatcherKt {
+ method @Deprecated public static suspend <T> Object? whenCreated(androidx.lifecycle.LifecycleOwner, kotlin.jvm.functions.Function2<? super kotlinx.coroutines.CoroutineScope,? super kotlin.coroutines.Continuation<? super T>,?> block, kotlin.coroutines.Continuation<? super T>);
+ method @Deprecated public static suspend <T> Object? whenCreated(androidx.lifecycle.Lifecycle, kotlin.jvm.functions.Function2<? super kotlinx.coroutines.CoroutineScope,? super kotlin.coroutines.Continuation<? super T>,?> block, kotlin.coroutines.Continuation<? super T>);
+ method @Deprecated public static suspend <T> Object? whenResumed(androidx.lifecycle.LifecycleOwner, kotlin.jvm.functions.Function2<? super kotlinx.coroutines.CoroutineScope,? super kotlin.coroutines.Continuation<? super T>,?> block, kotlin.coroutines.Continuation<? super T>);
+ method @Deprecated public static suspend <T> Object? whenResumed(androidx.lifecycle.Lifecycle, kotlin.jvm.functions.Function2<? super kotlinx.coroutines.CoroutineScope,? super kotlin.coroutines.Continuation<? super T>,?> block, kotlin.coroutines.Continuation<? super T>);
+ method @Deprecated public static suspend <T> Object? whenStarted(androidx.lifecycle.LifecycleOwner, kotlin.jvm.functions.Function2<? super kotlinx.coroutines.CoroutineScope,? super kotlin.coroutines.Continuation<? super T>,?> block, kotlin.coroutines.Continuation<? super T>);
+ method @Deprecated public static suspend <T> Object? whenStarted(androidx.lifecycle.Lifecycle, kotlin.jvm.functions.Function2<? super kotlinx.coroutines.CoroutineScope,? super kotlin.coroutines.Continuation<? super T>,?> block, kotlin.coroutines.Continuation<? super T>);
+ method @Deprecated public static suspend <T> Object? whenStateAtLeast(androidx.lifecycle.Lifecycle, androidx.lifecycle.Lifecycle.State minState, kotlin.jvm.functions.Function2<? super kotlinx.coroutines.CoroutineScope,? super kotlin.coroutines.Continuation<? super T>,?> block, kotlin.coroutines.Continuation<? super T>);
+ }
+
+}
+
diff --git a/lifecycle/lifecycle-extensions/api/2.6.0-beta02.txt b/lifecycle/lifecycle-extensions/api/2.6.0-beta02.txt
new file mode 100644
index 0000000..88798d8
--- /dev/null
+++ b/lifecycle/lifecycle-extensions/api/2.6.0-beta02.txt
@@ -0,0 +1,22 @@
+// Signature format: 4.0
+package androidx.lifecycle {
+
+ @Deprecated public class ViewModelProviders {
+ ctor @Deprecated public ViewModelProviders();
+ method @Deprecated @MainThread public static androidx.lifecycle.ViewModelProvider of(androidx.fragment.app.Fragment);
+ method @Deprecated @MainThread public static androidx.lifecycle.ViewModelProvider of(androidx.fragment.app.FragmentActivity);
+ method @Deprecated @MainThread public static androidx.lifecycle.ViewModelProvider of(androidx.fragment.app.Fragment, androidx.lifecycle.ViewModelProvider.Factory?);
+ method @Deprecated @MainThread public static androidx.lifecycle.ViewModelProvider of(androidx.fragment.app.FragmentActivity, androidx.lifecycle.ViewModelProvider.Factory?);
+ }
+
+ @Deprecated public static class ViewModelProviders.DefaultFactory extends androidx.lifecycle.ViewModelProvider.AndroidViewModelFactory {
+ ctor @Deprecated public ViewModelProviders.DefaultFactory(android.app.Application);
+ }
+
+ @Deprecated public class ViewModelStores {
+ method @Deprecated @MainThread public static androidx.lifecycle.ViewModelStore of(androidx.fragment.app.FragmentActivity);
+ method @Deprecated @MainThread public static androidx.lifecycle.ViewModelStore of(androidx.fragment.app.Fragment);
+ }
+
+}
+
diff --git a/lifecycle/lifecycle-extensions/api/public_plus_experimental_2.6.0-beta02.txt b/lifecycle/lifecycle-extensions/api/public_plus_experimental_2.6.0-beta02.txt
new file mode 100644
index 0000000..88798d8
--- /dev/null
+++ b/lifecycle/lifecycle-extensions/api/public_plus_experimental_2.6.0-beta02.txt
@@ -0,0 +1,22 @@
+// Signature format: 4.0
+package androidx.lifecycle {
+
+ @Deprecated public class ViewModelProviders {
+ ctor @Deprecated public ViewModelProviders();
+ method @Deprecated @MainThread public static androidx.lifecycle.ViewModelProvider of(androidx.fragment.app.Fragment);
+ method @Deprecated @MainThread public static androidx.lifecycle.ViewModelProvider of(androidx.fragment.app.FragmentActivity);
+ method @Deprecated @MainThread public static androidx.lifecycle.ViewModelProvider of(androidx.fragment.app.Fragment, androidx.lifecycle.ViewModelProvider.Factory?);
+ method @Deprecated @MainThread public static androidx.lifecycle.ViewModelProvider of(androidx.fragment.app.FragmentActivity, androidx.lifecycle.ViewModelProvider.Factory?);
+ }
+
+ @Deprecated public static class ViewModelProviders.DefaultFactory extends androidx.lifecycle.ViewModelProvider.AndroidViewModelFactory {
+ ctor @Deprecated public ViewModelProviders.DefaultFactory(android.app.Application);
+ }
+
+ @Deprecated public class ViewModelStores {
+ method @Deprecated @MainThread public static androidx.lifecycle.ViewModelStore of(androidx.fragment.app.FragmentActivity);
+ method @Deprecated @MainThread public static androidx.lifecycle.ViewModelStore of(androidx.fragment.app.Fragment);
+ }
+
+}
+
diff --git a/webkit/webkit/api/res-1.6.0-beta02.txt b/lifecycle/lifecycle-extensions/api/res-2.6.0-beta02.txt
similarity index 100%
rename from webkit/webkit/api/res-1.6.0-beta02.txt
rename to lifecycle/lifecycle-extensions/api/res-2.6.0-beta02.txt
diff --git a/lifecycle/lifecycle-extensions/api/restricted_2.6.0-beta02.txt b/lifecycle/lifecycle-extensions/api/restricted_2.6.0-beta02.txt
new file mode 100644
index 0000000..88798d8
--- /dev/null
+++ b/lifecycle/lifecycle-extensions/api/restricted_2.6.0-beta02.txt
@@ -0,0 +1,22 @@
+// Signature format: 4.0
+package androidx.lifecycle {
+
+ @Deprecated public class ViewModelProviders {
+ ctor @Deprecated public ViewModelProviders();
+ method @Deprecated @MainThread public static androidx.lifecycle.ViewModelProvider of(androidx.fragment.app.Fragment);
+ method @Deprecated @MainThread public static androidx.lifecycle.ViewModelProvider of(androidx.fragment.app.FragmentActivity);
+ method @Deprecated @MainThread public static androidx.lifecycle.ViewModelProvider of(androidx.fragment.app.Fragment, androidx.lifecycle.ViewModelProvider.Factory?);
+ method @Deprecated @MainThread public static androidx.lifecycle.ViewModelProvider of(androidx.fragment.app.FragmentActivity, androidx.lifecycle.ViewModelProvider.Factory?);
+ }
+
+ @Deprecated public static class ViewModelProviders.DefaultFactory extends androidx.lifecycle.ViewModelProvider.AndroidViewModelFactory {
+ ctor @Deprecated public ViewModelProviders.DefaultFactory(android.app.Application);
+ }
+
+ @Deprecated public class ViewModelStores {
+ method @Deprecated @MainThread public static androidx.lifecycle.ViewModelStore of(androidx.fragment.app.FragmentActivity);
+ method @Deprecated @MainThread public static androidx.lifecycle.ViewModelStore of(androidx.fragment.app.Fragment);
+ }
+
+}
+
diff --git a/lifecycle/lifecycle-livedata-core-ktx/api/2.6.0-beta02.txt b/lifecycle/lifecycle-livedata-core-ktx/api/2.6.0-beta02.txt
new file mode 100644
index 0000000..daac648
--- /dev/null
+++ b/lifecycle/lifecycle-livedata-core-ktx/api/2.6.0-beta02.txt
@@ -0,0 +1,9 @@
+// Signature format: 4.0
+package androidx.lifecycle {
+
+ public final class LiveDataKt {
+ method @Deprecated @MainThread public static inline <T> androidx.lifecycle.Observer<T> observe(androidx.lifecycle.LiveData<T>, androidx.lifecycle.LifecycleOwner owner, kotlin.jvm.functions.Function1<? super T,kotlin.Unit> onChanged);
+ }
+
+}
+
diff --git a/lifecycle/lifecycle-livedata-core-ktx/api/public_plus_experimental_2.6.0-beta02.txt b/lifecycle/lifecycle-livedata-core-ktx/api/public_plus_experimental_2.6.0-beta02.txt
new file mode 100644
index 0000000..daac648
--- /dev/null
+++ b/lifecycle/lifecycle-livedata-core-ktx/api/public_plus_experimental_2.6.0-beta02.txt
@@ -0,0 +1,9 @@
+// Signature format: 4.0
+package androidx.lifecycle {
+
+ public final class LiveDataKt {
+ method @Deprecated @MainThread public static inline <T> androidx.lifecycle.Observer<T> observe(androidx.lifecycle.LiveData<T>, androidx.lifecycle.LifecycleOwner owner, kotlin.jvm.functions.Function1<? super T,kotlin.Unit> onChanged);
+ }
+
+}
+
diff --git a/webkit/webkit/api/res-1.6.0-beta02.txt b/lifecycle/lifecycle-livedata-core-ktx/api/res-2.6.0-beta02.txt
similarity index 100%
copy from webkit/webkit/api/res-1.6.0-beta02.txt
copy to lifecycle/lifecycle-livedata-core-ktx/api/res-2.6.0-beta02.txt
diff --git a/lifecycle/lifecycle-livedata-core-ktx/api/restricted_2.6.0-beta02.txt b/lifecycle/lifecycle-livedata-core-ktx/api/restricted_2.6.0-beta02.txt
new file mode 100644
index 0000000..daac648
--- /dev/null
+++ b/lifecycle/lifecycle-livedata-core-ktx/api/restricted_2.6.0-beta02.txt
@@ -0,0 +1,9 @@
+// Signature format: 4.0
+package androidx.lifecycle {
+
+ public final class LiveDataKt {
+ method @Deprecated @MainThread public static inline <T> androidx.lifecycle.Observer<T> observe(androidx.lifecycle.LiveData<T>, androidx.lifecycle.LifecycleOwner owner, kotlin.jvm.functions.Function1<? super T,kotlin.Unit> onChanged);
+ }
+
+}
+
diff --git a/lifecycle/lifecycle-livedata-core/api/2.6.0-beta02.txt b/lifecycle/lifecycle-livedata-core/api/2.6.0-beta02.txt
new file mode 100644
index 0000000..f528b4e
--- /dev/null
+++ b/lifecycle/lifecycle-livedata-core/api/2.6.0-beta02.txt
@@ -0,0 +1,33 @@
+// Signature format: 4.0
+package androidx.lifecycle {
+
+ public abstract class LiveData<T> {
+ ctor public LiveData(T!);
+ ctor public LiveData();
+ method public T? getValue();
+ method public boolean hasActiveObservers();
+ method public boolean hasObservers();
+ method public boolean isInitialized();
+ method @MainThread public void observe(androidx.lifecycle.LifecycleOwner, androidx.lifecycle.Observer<? super T>);
+ method @MainThread public void observeForever(androidx.lifecycle.Observer<? super T>);
+ method protected void onActive();
+ method protected void onInactive();
+ method protected void postValue(T!);
+ method @MainThread public void removeObserver(androidx.lifecycle.Observer<? super T>);
+ method @MainThread public void removeObservers(androidx.lifecycle.LifecycleOwner);
+ method @MainThread protected void setValue(T!);
+ }
+
+ public class MutableLiveData<T> extends androidx.lifecycle.LiveData<T> {
+ ctor public MutableLiveData(T!);
+ ctor public MutableLiveData();
+ method public void postValue(T!);
+ method public void setValue(T!);
+ }
+
+ public fun interface Observer<T> {
+ method public void onChanged(T? value);
+ }
+
+}
+
diff --git a/lifecycle/lifecycle-livedata-core/api/public_plus_experimental_2.6.0-beta02.txt b/lifecycle/lifecycle-livedata-core/api/public_plus_experimental_2.6.0-beta02.txt
new file mode 100644
index 0000000..f528b4e
--- /dev/null
+++ b/lifecycle/lifecycle-livedata-core/api/public_plus_experimental_2.6.0-beta02.txt
@@ -0,0 +1,33 @@
+// Signature format: 4.0
+package androidx.lifecycle {
+
+ public abstract class LiveData<T> {
+ ctor public LiveData(T!);
+ ctor public LiveData();
+ method public T? getValue();
+ method public boolean hasActiveObservers();
+ method public boolean hasObservers();
+ method public boolean isInitialized();
+ method @MainThread public void observe(androidx.lifecycle.LifecycleOwner, androidx.lifecycle.Observer<? super T>);
+ method @MainThread public void observeForever(androidx.lifecycle.Observer<? super T>);
+ method protected void onActive();
+ method protected void onInactive();
+ method protected void postValue(T!);
+ method @MainThread public void removeObserver(androidx.lifecycle.Observer<? super T>);
+ method @MainThread public void removeObservers(androidx.lifecycle.LifecycleOwner);
+ method @MainThread protected void setValue(T!);
+ }
+
+ public class MutableLiveData<T> extends androidx.lifecycle.LiveData<T> {
+ ctor public MutableLiveData(T!);
+ ctor public MutableLiveData();
+ method public void postValue(T!);
+ method public void setValue(T!);
+ }
+
+ public fun interface Observer<T> {
+ method public void onChanged(T? value);
+ }
+
+}
+
diff --git a/webkit/webkit/api/res-1.6.0-beta02.txt b/lifecycle/lifecycle-livedata-core/api/res-2.6.0-beta02.txt
similarity index 100%
copy from webkit/webkit/api/res-1.6.0-beta02.txt
copy to lifecycle/lifecycle-livedata-core/api/res-2.6.0-beta02.txt
diff --git a/lifecycle/lifecycle-livedata-core/api/restricted_2.6.0-beta02.txt b/lifecycle/lifecycle-livedata-core/api/restricted_2.6.0-beta02.txt
new file mode 100644
index 0000000..f528b4e
--- /dev/null
+++ b/lifecycle/lifecycle-livedata-core/api/restricted_2.6.0-beta02.txt
@@ -0,0 +1,33 @@
+// Signature format: 4.0
+package androidx.lifecycle {
+
+ public abstract class LiveData<T> {
+ ctor public LiveData(T!);
+ ctor public LiveData();
+ method public T? getValue();
+ method public boolean hasActiveObservers();
+ method public boolean hasObservers();
+ method public boolean isInitialized();
+ method @MainThread public void observe(androidx.lifecycle.LifecycleOwner, androidx.lifecycle.Observer<? super T>);
+ method @MainThread public void observeForever(androidx.lifecycle.Observer<? super T>);
+ method protected void onActive();
+ method protected void onInactive();
+ method protected void postValue(T!);
+ method @MainThread public void removeObserver(androidx.lifecycle.Observer<? super T>);
+ method @MainThread public void removeObservers(androidx.lifecycle.LifecycleOwner);
+ method @MainThread protected void setValue(T!);
+ }
+
+ public class MutableLiveData<T> extends androidx.lifecycle.LiveData<T> {
+ ctor public MutableLiveData(T!);
+ ctor public MutableLiveData();
+ method public void postValue(T!);
+ method public void setValue(T!);
+ }
+
+ public fun interface Observer<T> {
+ method public void onChanged(T? value);
+ }
+
+}
+
diff --git a/lifecycle/lifecycle-livedata-ktx/api/2.6.0-beta02.txt b/lifecycle/lifecycle-livedata-ktx/api/2.6.0-beta02.txt
new file mode 100644
index 0000000..bae0928
--- /dev/null
+++ b/lifecycle/lifecycle-livedata-ktx/api/2.6.0-beta02.txt
@@ -0,0 +1,25 @@
+// Signature format: 4.0
+package androidx.lifecycle {
+
+ public final class CoroutineLiveDataKt {
+ method public static <T> androidx.lifecycle.LiveData<T> liveData(optional kotlin.coroutines.CoroutineContext context, optional long timeoutInMs, kotlin.jvm.functions.Function2<? super androidx.lifecycle.LiveDataScope<T>,? super kotlin.coroutines.Continuation<? super kotlin.Unit>,?> block);
+ method @RequiresApi(android.os.Build.VERSION_CODES.O) public static <T> androidx.lifecycle.LiveData<T> liveData(optional kotlin.coroutines.CoroutineContext context, java.time.Duration timeout, kotlin.jvm.functions.Function2<? super androidx.lifecycle.LiveDataScope<T>,? super kotlin.coroutines.Continuation<? super kotlin.Unit>,?> block);
+ }
+
+ public final class FlowLiveDataConversions {
+ method public static <T> kotlinx.coroutines.flow.Flow<T> asFlow(androidx.lifecycle.LiveData<T>);
+ method public static <T> androidx.lifecycle.LiveData<T> asLiveData(kotlinx.coroutines.flow.Flow<? extends T>, optional kotlin.coroutines.CoroutineContext context, optional long timeoutInMs);
+ method public static <T> androidx.lifecycle.LiveData<T> asLiveData(kotlinx.coroutines.flow.Flow<? extends T>, optional kotlin.coroutines.CoroutineContext context);
+ method public static <T> androidx.lifecycle.LiveData<T> asLiveData(kotlinx.coroutines.flow.Flow<? extends T>);
+ method @RequiresApi(android.os.Build.VERSION_CODES.O) public static <T> androidx.lifecycle.LiveData<T> asLiveData(kotlinx.coroutines.flow.Flow<? extends T>, optional kotlin.coroutines.CoroutineContext context, java.time.Duration timeout);
+ }
+
+ public interface LiveDataScope<T> {
+ method public suspend Object? emit(T? value, kotlin.coroutines.Continuation<? super kotlin.Unit>);
+ method public suspend Object? emitSource(androidx.lifecycle.LiveData<T> source, kotlin.coroutines.Continuation<? super kotlinx.coroutines.DisposableHandle>);
+ method public T? getLatestValue();
+ property public abstract T? latestValue;
+ }
+
+}
+
diff --git a/lifecycle/lifecycle-livedata-ktx/api/public_plus_experimental_2.6.0-beta02.txt b/lifecycle/lifecycle-livedata-ktx/api/public_plus_experimental_2.6.0-beta02.txt
new file mode 100644
index 0000000..bae0928
--- /dev/null
+++ b/lifecycle/lifecycle-livedata-ktx/api/public_plus_experimental_2.6.0-beta02.txt
@@ -0,0 +1,25 @@
+// Signature format: 4.0
+package androidx.lifecycle {
+
+ public final class CoroutineLiveDataKt {
+ method public static <T> androidx.lifecycle.LiveData<T> liveData(optional kotlin.coroutines.CoroutineContext context, optional long timeoutInMs, kotlin.jvm.functions.Function2<? super androidx.lifecycle.LiveDataScope<T>,? super kotlin.coroutines.Continuation<? super kotlin.Unit>,?> block);
+ method @RequiresApi(android.os.Build.VERSION_CODES.O) public static <T> androidx.lifecycle.LiveData<T> liveData(optional kotlin.coroutines.CoroutineContext context, java.time.Duration timeout, kotlin.jvm.functions.Function2<? super androidx.lifecycle.LiveDataScope<T>,? super kotlin.coroutines.Continuation<? super kotlin.Unit>,?> block);
+ }
+
+ public final class FlowLiveDataConversions {
+ method public static <T> kotlinx.coroutines.flow.Flow<T> asFlow(androidx.lifecycle.LiveData<T>);
+ method public static <T> androidx.lifecycle.LiveData<T> asLiveData(kotlinx.coroutines.flow.Flow<? extends T>, optional kotlin.coroutines.CoroutineContext context, optional long timeoutInMs);
+ method public static <T> androidx.lifecycle.LiveData<T> asLiveData(kotlinx.coroutines.flow.Flow<? extends T>, optional kotlin.coroutines.CoroutineContext context);
+ method public static <T> androidx.lifecycle.LiveData<T> asLiveData(kotlinx.coroutines.flow.Flow<? extends T>);
+ method @RequiresApi(android.os.Build.VERSION_CODES.O) public static <T> androidx.lifecycle.LiveData<T> asLiveData(kotlinx.coroutines.flow.Flow<? extends T>, optional kotlin.coroutines.CoroutineContext context, java.time.Duration timeout);
+ }
+
+ public interface LiveDataScope<T> {
+ method public suspend Object? emit(T? value, kotlin.coroutines.Continuation<? super kotlin.Unit>);
+ method public suspend Object? emitSource(androidx.lifecycle.LiveData<T> source, kotlin.coroutines.Continuation<? super kotlinx.coroutines.DisposableHandle>);
+ method public T? getLatestValue();
+ property public abstract T? latestValue;
+ }
+
+}
+
diff --git a/webkit/webkit/api/res-1.6.0-beta02.txt b/lifecycle/lifecycle-livedata-ktx/api/res-2.6.0-beta02.txt
similarity index 100%
copy from webkit/webkit/api/res-1.6.0-beta02.txt
copy to lifecycle/lifecycle-livedata-ktx/api/res-2.6.0-beta02.txt
diff --git a/lifecycle/lifecycle-livedata-ktx/api/restricted_2.6.0-beta02.txt b/lifecycle/lifecycle-livedata-ktx/api/restricted_2.6.0-beta02.txt
new file mode 100644
index 0000000..bae0928
--- /dev/null
+++ b/lifecycle/lifecycle-livedata-ktx/api/restricted_2.6.0-beta02.txt
@@ -0,0 +1,25 @@
+// Signature format: 4.0
+package androidx.lifecycle {
+
+ public final class CoroutineLiveDataKt {
+ method public static <T> androidx.lifecycle.LiveData<T> liveData(optional kotlin.coroutines.CoroutineContext context, optional long timeoutInMs, kotlin.jvm.functions.Function2<? super androidx.lifecycle.LiveDataScope<T>,? super kotlin.coroutines.Continuation<? super kotlin.Unit>,?> block);
+ method @RequiresApi(android.os.Build.VERSION_CODES.O) public static <T> androidx.lifecycle.LiveData<T> liveData(optional kotlin.coroutines.CoroutineContext context, java.time.Duration timeout, kotlin.jvm.functions.Function2<? super androidx.lifecycle.LiveDataScope<T>,? super kotlin.coroutines.Continuation<? super kotlin.Unit>,?> block);
+ }
+
+ public final class FlowLiveDataConversions {
+ method public static <T> kotlinx.coroutines.flow.Flow<T> asFlow(androidx.lifecycle.LiveData<T>);
+ method public static <T> androidx.lifecycle.LiveData<T> asLiveData(kotlinx.coroutines.flow.Flow<? extends T>, optional kotlin.coroutines.CoroutineContext context, optional long timeoutInMs);
+ method public static <T> androidx.lifecycle.LiveData<T> asLiveData(kotlinx.coroutines.flow.Flow<? extends T>, optional kotlin.coroutines.CoroutineContext context);
+ method public static <T> androidx.lifecycle.LiveData<T> asLiveData(kotlinx.coroutines.flow.Flow<? extends T>);
+ method @RequiresApi(android.os.Build.VERSION_CODES.O) public static <T> androidx.lifecycle.LiveData<T> asLiveData(kotlinx.coroutines.flow.Flow<? extends T>, optional kotlin.coroutines.CoroutineContext context, java.time.Duration timeout);
+ }
+
+ public interface LiveDataScope<T> {
+ method public suspend Object? emit(T? value, kotlin.coroutines.Continuation<? super kotlin.Unit>);
+ method public suspend Object? emitSource(androidx.lifecycle.LiveData<T> source, kotlin.coroutines.Continuation<? super kotlinx.coroutines.DisposableHandle>);
+ method public T? getLatestValue();
+ property public abstract T? latestValue;
+ }
+
+}
+
diff --git a/lifecycle/lifecycle-livedata/api/2.6.0-beta02.txt b/lifecycle/lifecycle-livedata/api/2.6.0-beta02.txt
new file mode 100644
index 0000000..9b1bf6c
--- /dev/null
+++ b/lifecycle/lifecycle-livedata/api/2.6.0-beta02.txt
@@ -0,0 +1,20 @@
+// Signature format: 4.0
+package androidx.lifecycle {
+
+ public class MediatorLiveData<T> extends androidx.lifecycle.MutableLiveData<T> {
+ ctor public MediatorLiveData();
+ ctor public MediatorLiveData(T!);
+ method @MainThread public <S> void addSource(androidx.lifecycle.LiveData<S!>, androidx.lifecycle.Observer<? super S>);
+ method @MainThread public <S> void removeSource(androidx.lifecycle.LiveData<S!>);
+ }
+
+ public final class Transformations {
+ method @CheckResult @MainThread public static <X> androidx.lifecycle.LiveData<X> distinctUntilChanged(androidx.lifecycle.LiveData<X>);
+ method @CheckResult @MainThread public static <X, Y> androidx.lifecycle.LiveData<Y> map(androidx.lifecycle.LiveData<X>, kotlin.jvm.functions.Function1<X,Y> transform);
+ method @Deprecated @CheckResult @MainThread public static <X, Y> androidx.lifecycle.LiveData<Y> map(androidx.lifecycle.LiveData<X>, androidx.arch.core.util.Function<X,Y> mapFunction);
+ method @CheckResult @MainThread public static <X, Y> androidx.lifecycle.LiveData<Y> switchMap(androidx.lifecycle.LiveData<X>, kotlin.jvm.functions.Function1<X,androidx.lifecycle.LiveData<Y>> transform);
+ method @Deprecated @CheckResult @MainThread public static <X, Y> androidx.lifecycle.LiveData<Y> switchMap(androidx.lifecycle.LiveData<X>, androidx.arch.core.util.Function<X,androidx.lifecycle.LiveData<Y>> switchMapFunction);
+ }
+
+}
+
diff --git a/lifecycle/lifecycle-livedata/api/public_plus_experimental_2.6.0-beta02.txt b/lifecycle/lifecycle-livedata/api/public_plus_experimental_2.6.0-beta02.txt
new file mode 100644
index 0000000..9b1bf6c
--- /dev/null
+++ b/lifecycle/lifecycle-livedata/api/public_plus_experimental_2.6.0-beta02.txt
@@ -0,0 +1,20 @@
+// Signature format: 4.0
+package androidx.lifecycle {
+
+ public class MediatorLiveData<T> extends androidx.lifecycle.MutableLiveData<T> {
+ ctor public MediatorLiveData();
+ ctor public MediatorLiveData(T!);
+ method @MainThread public <S> void addSource(androidx.lifecycle.LiveData<S!>, androidx.lifecycle.Observer<? super S>);
+ method @MainThread public <S> void removeSource(androidx.lifecycle.LiveData<S!>);
+ }
+
+ public final class Transformations {
+ method @CheckResult @MainThread public static <X> androidx.lifecycle.LiveData<X> distinctUntilChanged(androidx.lifecycle.LiveData<X>);
+ method @CheckResult @MainThread public static <X, Y> androidx.lifecycle.LiveData<Y> map(androidx.lifecycle.LiveData<X>, kotlin.jvm.functions.Function1<X,Y> transform);
+ method @Deprecated @CheckResult @MainThread public static <X, Y> androidx.lifecycle.LiveData<Y> map(androidx.lifecycle.LiveData<X>, androidx.arch.core.util.Function<X,Y> mapFunction);
+ method @CheckResult @MainThread public static <X, Y> androidx.lifecycle.LiveData<Y> switchMap(androidx.lifecycle.LiveData<X>, kotlin.jvm.functions.Function1<X,androidx.lifecycle.LiveData<Y>> transform);
+ method @Deprecated @CheckResult @MainThread public static <X, Y> androidx.lifecycle.LiveData<Y> switchMap(androidx.lifecycle.LiveData<X>, androidx.arch.core.util.Function<X,androidx.lifecycle.LiveData<Y>> switchMapFunction);
+ }
+
+}
+
diff --git a/webkit/webkit/api/res-1.6.0-beta02.txt b/lifecycle/lifecycle-livedata/api/res-2.6.0-beta02.txt
similarity index 100%
copy from webkit/webkit/api/res-1.6.0-beta02.txt
copy to lifecycle/lifecycle-livedata/api/res-2.6.0-beta02.txt
diff --git a/lifecycle/lifecycle-livedata/api/restricted_2.6.0-beta02.txt b/lifecycle/lifecycle-livedata/api/restricted_2.6.0-beta02.txt
new file mode 100644
index 0000000..bb61b39
--- /dev/null
+++ b/lifecycle/lifecycle-livedata/api/restricted_2.6.0-beta02.txt
@@ -0,0 +1,29 @@
+// Signature format: 4.0
+package androidx.lifecycle {
+
+ @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) public abstract class ComputableLiveData<T> {
+ ctor public ComputableLiveData(optional java.util.concurrent.Executor executor);
+ ctor public ComputableLiveData();
+ method @WorkerThread protected abstract T! compute();
+ method public androidx.lifecycle.LiveData<T> getLiveData();
+ method public void invalidate();
+ property public androidx.lifecycle.LiveData<T> liveData;
+ }
+
+ public class MediatorLiveData<T> extends androidx.lifecycle.MutableLiveData<T> {
+ ctor public MediatorLiveData();
+ ctor public MediatorLiveData(T!);
+ method @MainThread public <S> void addSource(androidx.lifecycle.LiveData<S!>, androidx.lifecycle.Observer<? super S>);
+ method @MainThread public <S> void removeSource(androidx.lifecycle.LiveData<S!>);
+ }
+
+ public final class Transformations {
+ method @CheckResult @MainThread public static <X> androidx.lifecycle.LiveData<X> distinctUntilChanged(androidx.lifecycle.LiveData<X>);
+ method @CheckResult @MainThread public static <X, Y> androidx.lifecycle.LiveData<Y> map(androidx.lifecycle.LiveData<X>, kotlin.jvm.functions.Function1<X,Y> transform);
+ method @Deprecated @CheckResult @MainThread public static <X, Y> androidx.lifecycle.LiveData<Y> map(androidx.lifecycle.LiveData<X>, androidx.arch.core.util.Function<X,Y> mapFunction);
+ method @CheckResult @MainThread public static <X, Y> androidx.lifecycle.LiveData<Y> switchMap(androidx.lifecycle.LiveData<X>, kotlin.jvm.functions.Function1<X,androidx.lifecycle.LiveData<Y>> transform);
+ method @Deprecated @CheckResult @MainThread public static <X, Y> androidx.lifecycle.LiveData<Y> switchMap(androidx.lifecycle.LiveData<X>, androidx.arch.core.util.Function<X,androidx.lifecycle.LiveData<Y>> switchMapFunction);
+ }
+
+}
+
diff --git a/lifecycle/lifecycle-process/api/2.6.0-beta02.txt b/lifecycle/lifecycle-process/api/2.6.0-beta02.txt
new file mode 100644
index 0000000..891c9c6
--- /dev/null
+++ b/lifecycle/lifecycle-process/api/2.6.0-beta02.txt
@@ -0,0 +1,22 @@
+// Signature format: 4.0
+package androidx.lifecycle {
+
+ public final class ProcessLifecycleInitializer implements androidx.startup.Initializer<androidx.lifecycle.LifecycleOwner> {
+ ctor public ProcessLifecycleInitializer();
+ method public androidx.lifecycle.LifecycleOwner create(android.content.Context context);
+ method public java.util.List<java.lang.Class<? extends androidx.startup.Initializer<?>>> dependencies();
+ }
+
+ public final class ProcessLifecycleOwner implements androidx.lifecycle.LifecycleOwner {
+ method public static androidx.lifecycle.LifecycleOwner get();
+ method public androidx.lifecycle.Lifecycle getLifecycle();
+ property public androidx.lifecycle.Lifecycle lifecycle;
+ field public static final androidx.lifecycle.ProcessLifecycleOwner.Companion Companion;
+ }
+
+ public static final class ProcessLifecycleOwner.Companion {
+ method public androidx.lifecycle.LifecycleOwner get();
+ }
+
+}
+
diff --git a/lifecycle/lifecycle-process/api/public_plus_experimental_2.6.0-beta02.txt b/lifecycle/lifecycle-process/api/public_plus_experimental_2.6.0-beta02.txt
new file mode 100644
index 0000000..891c9c6
--- /dev/null
+++ b/lifecycle/lifecycle-process/api/public_plus_experimental_2.6.0-beta02.txt
@@ -0,0 +1,22 @@
+// Signature format: 4.0
+package androidx.lifecycle {
+
+ public final class ProcessLifecycleInitializer implements androidx.startup.Initializer<androidx.lifecycle.LifecycleOwner> {
+ ctor public ProcessLifecycleInitializer();
+ method public androidx.lifecycle.LifecycleOwner create(android.content.Context context);
+ method public java.util.List<java.lang.Class<? extends androidx.startup.Initializer<?>>> dependencies();
+ }
+
+ public final class ProcessLifecycleOwner implements androidx.lifecycle.LifecycleOwner {
+ method public static androidx.lifecycle.LifecycleOwner get();
+ method public androidx.lifecycle.Lifecycle getLifecycle();
+ property public androidx.lifecycle.Lifecycle lifecycle;
+ field public static final androidx.lifecycle.ProcessLifecycleOwner.Companion Companion;
+ }
+
+ public static final class ProcessLifecycleOwner.Companion {
+ method public androidx.lifecycle.LifecycleOwner get();
+ }
+
+}
+
diff --git a/webkit/webkit/api/res-1.6.0-beta02.txt b/lifecycle/lifecycle-process/api/res-2.6.0-beta02.txt
similarity index 100%
copy from webkit/webkit/api/res-1.6.0-beta02.txt
copy to lifecycle/lifecycle-process/api/res-2.6.0-beta02.txt
diff --git a/lifecycle/lifecycle-process/api/restricted_2.6.0-beta02.txt b/lifecycle/lifecycle-process/api/restricted_2.6.0-beta02.txt
new file mode 100644
index 0000000..891c9c6
--- /dev/null
+++ b/lifecycle/lifecycle-process/api/restricted_2.6.0-beta02.txt
@@ -0,0 +1,22 @@
+// Signature format: 4.0
+package androidx.lifecycle {
+
+ public final class ProcessLifecycleInitializer implements androidx.startup.Initializer<androidx.lifecycle.LifecycleOwner> {
+ ctor public ProcessLifecycleInitializer();
+ method public androidx.lifecycle.LifecycleOwner create(android.content.Context context);
+ method public java.util.List<java.lang.Class<? extends androidx.startup.Initializer<?>>> dependencies();
+ }
+
+ public final class ProcessLifecycleOwner implements androidx.lifecycle.LifecycleOwner {
+ method public static androidx.lifecycle.LifecycleOwner get();
+ method public androidx.lifecycle.Lifecycle getLifecycle();
+ property public androidx.lifecycle.Lifecycle lifecycle;
+ field public static final androidx.lifecycle.ProcessLifecycleOwner.Companion Companion;
+ }
+
+ public static final class ProcessLifecycleOwner.Companion {
+ method public androidx.lifecycle.LifecycleOwner get();
+ }
+
+}
+
diff --git a/lifecycle/lifecycle-reactivestreams-ktx/api/2.6.0-beta02.txt b/lifecycle/lifecycle-reactivestreams-ktx/api/2.6.0-beta02.txt
new file mode 100644
index 0000000..e6f50d0
--- /dev/null
+++ b/lifecycle/lifecycle-reactivestreams-ktx/api/2.6.0-beta02.txt
@@ -0,0 +1 @@
+// Signature format: 4.0
diff --git a/lifecycle/lifecycle-reactivestreams-ktx/api/public_plus_experimental_2.6.0-beta02.txt b/lifecycle/lifecycle-reactivestreams-ktx/api/public_plus_experimental_2.6.0-beta02.txt
new file mode 100644
index 0000000..e6f50d0
--- /dev/null
+++ b/lifecycle/lifecycle-reactivestreams-ktx/api/public_plus_experimental_2.6.0-beta02.txt
@@ -0,0 +1 @@
+// Signature format: 4.0
diff --git a/webkit/webkit/api/res-1.6.0-beta02.txt b/lifecycle/lifecycle-reactivestreams-ktx/api/res-2.6.0-beta02.txt
similarity index 100%
copy from webkit/webkit/api/res-1.6.0-beta02.txt
copy to lifecycle/lifecycle-reactivestreams-ktx/api/res-2.6.0-beta02.txt
diff --git a/lifecycle/lifecycle-reactivestreams-ktx/api/restricted_2.6.0-beta02.txt b/lifecycle/lifecycle-reactivestreams-ktx/api/restricted_2.6.0-beta02.txt
new file mode 100644
index 0000000..e6f50d0
--- /dev/null
+++ b/lifecycle/lifecycle-reactivestreams-ktx/api/restricted_2.6.0-beta02.txt
@@ -0,0 +1 @@
+// Signature format: 4.0
diff --git a/lifecycle/lifecycle-reactivestreams/api/2.6.0-beta02.txt b/lifecycle/lifecycle-reactivestreams/api/2.6.0-beta02.txt
new file mode 100644
index 0000000..138dd3e
--- /dev/null
+++ b/lifecycle/lifecycle-reactivestreams/api/2.6.0-beta02.txt
@@ -0,0 +1,11 @@
+// Signature format: 4.0
+package androidx.lifecycle {
+
+ public final class LiveDataReactiveStreams {
+ method public static <T> androidx.lifecycle.LiveData<T> fromPublisher(org.reactivestreams.Publisher<T>);
+ method public static <T> org.reactivestreams.Publisher<T> toPublisher(androidx.lifecycle.LifecycleOwner lifecycle, androidx.lifecycle.LiveData<T> liveData);
+ method public static <T> org.reactivestreams.Publisher<T> toPublisher(androidx.lifecycle.LiveData<T>, androidx.lifecycle.LifecycleOwner lifecycle);
+ }
+
+}
+
diff --git a/lifecycle/lifecycle-reactivestreams/api/public_plus_experimental_2.6.0-beta02.txt b/lifecycle/lifecycle-reactivestreams/api/public_plus_experimental_2.6.0-beta02.txt
new file mode 100644
index 0000000..138dd3e
--- /dev/null
+++ b/lifecycle/lifecycle-reactivestreams/api/public_plus_experimental_2.6.0-beta02.txt
@@ -0,0 +1,11 @@
+// Signature format: 4.0
+package androidx.lifecycle {
+
+ public final class LiveDataReactiveStreams {
+ method public static <T> androidx.lifecycle.LiveData<T> fromPublisher(org.reactivestreams.Publisher<T>);
+ method public static <T> org.reactivestreams.Publisher<T> toPublisher(androidx.lifecycle.LifecycleOwner lifecycle, androidx.lifecycle.LiveData<T> liveData);
+ method public static <T> org.reactivestreams.Publisher<T> toPublisher(androidx.lifecycle.LiveData<T>, androidx.lifecycle.LifecycleOwner lifecycle);
+ }
+
+}
+
diff --git a/webkit/webkit/api/res-1.6.0-beta02.txt b/lifecycle/lifecycle-reactivestreams/api/res-2.6.0-beta02.txt
similarity index 100%
copy from webkit/webkit/api/res-1.6.0-beta02.txt
copy to lifecycle/lifecycle-reactivestreams/api/res-2.6.0-beta02.txt
diff --git a/lifecycle/lifecycle-reactivestreams/api/restricted_2.6.0-beta02.txt b/lifecycle/lifecycle-reactivestreams/api/restricted_2.6.0-beta02.txt
new file mode 100644
index 0000000..138dd3e
--- /dev/null
+++ b/lifecycle/lifecycle-reactivestreams/api/restricted_2.6.0-beta02.txt
@@ -0,0 +1,11 @@
+// Signature format: 4.0
+package androidx.lifecycle {
+
+ public final class LiveDataReactiveStreams {
+ method public static <T> androidx.lifecycle.LiveData<T> fromPublisher(org.reactivestreams.Publisher<T>);
+ method public static <T> org.reactivestreams.Publisher<T> toPublisher(androidx.lifecycle.LifecycleOwner lifecycle, androidx.lifecycle.LiveData<T> liveData);
+ method public static <T> org.reactivestreams.Publisher<T> toPublisher(androidx.lifecycle.LiveData<T>, androidx.lifecycle.LifecycleOwner lifecycle);
+ }
+
+}
+
diff --git a/lifecycle/lifecycle-runtime-compose/api/2.6.0-beta02.txt b/lifecycle/lifecycle-runtime-compose/api/2.6.0-beta02.txt
new file mode 100644
index 0000000..c80fa83
--- /dev/null
+++ b/lifecycle/lifecycle-runtime-compose/api/2.6.0-beta02.txt
@@ -0,0 +1,12 @@
+// Signature format: 4.0
+package androidx.lifecycle.compose {
+
+ public final class FlowExtKt {
+ method @androidx.compose.runtime.Composable public static <T> androidx.compose.runtime.State<T> collectAsStateWithLifecycle(kotlinx.coroutines.flow.StateFlow<? extends T>, optional androidx.lifecycle.LifecycleOwner lifecycleOwner, optional androidx.lifecycle.Lifecycle.State minActiveState, optional kotlin.coroutines.CoroutineContext context);
+ method @androidx.compose.runtime.Composable public static <T> androidx.compose.runtime.State<T> collectAsStateWithLifecycle(kotlinx.coroutines.flow.StateFlow<? extends T>, androidx.lifecycle.Lifecycle lifecycle, optional androidx.lifecycle.Lifecycle.State minActiveState, optional kotlin.coroutines.CoroutineContext context);
+ method @androidx.compose.runtime.Composable public static <T> androidx.compose.runtime.State<T> collectAsStateWithLifecycle(kotlinx.coroutines.flow.Flow<? extends T>, T? initialValue, optional androidx.lifecycle.LifecycleOwner lifecycleOwner, optional androidx.lifecycle.Lifecycle.State minActiveState, optional kotlin.coroutines.CoroutineContext context);
+ method @androidx.compose.runtime.Composable public static <T> androidx.compose.runtime.State<T> collectAsStateWithLifecycle(kotlinx.coroutines.flow.Flow<? extends T>, T? initialValue, androidx.lifecycle.Lifecycle lifecycle, optional androidx.lifecycle.Lifecycle.State minActiveState, optional kotlin.coroutines.CoroutineContext context);
+ }
+
+}
+
diff --git a/lifecycle/lifecycle-runtime-compose/api/public_plus_experimental_2.6.0-beta02.txt b/lifecycle/lifecycle-runtime-compose/api/public_plus_experimental_2.6.0-beta02.txt
new file mode 100644
index 0000000..c80fa83
--- /dev/null
+++ b/lifecycle/lifecycle-runtime-compose/api/public_plus_experimental_2.6.0-beta02.txt
@@ -0,0 +1,12 @@
+// Signature format: 4.0
+package androidx.lifecycle.compose {
+
+ public final class FlowExtKt {
+ method @androidx.compose.runtime.Composable public static <T> androidx.compose.runtime.State<T> collectAsStateWithLifecycle(kotlinx.coroutines.flow.StateFlow<? extends T>, optional androidx.lifecycle.LifecycleOwner lifecycleOwner, optional androidx.lifecycle.Lifecycle.State minActiveState, optional kotlin.coroutines.CoroutineContext context);
+ method @androidx.compose.runtime.Composable public static <T> androidx.compose.runtime.State<T> collectAsStateWithLifecycle(kotlinx.coroutines.flow.StateFlow<? extends T>, androidx.lifecycle.Lifecycle lifecycle, optional androidx.lifecycle.Lifecycle.State minActiveState, optional kotlin.coroutines.CoroutineContext context);
+ method @androidx.compose.runtime.Composable public static <T> androidx.compose.runtime.State<T> collectAsStateWithLifecycle(kotlinx.coroutines.flow.Flow<? extends T>, T? initialValue, optional androidx.lifecycle.LifecycleOwner lifecycleOwner, optional androidx.lifecycle.Lifecycle.State minActiveState, optional kotlin.coroutines.CoroutineContext context);
+ method @androidx.compose.runtime.Composable public static <T> androidx.compose.runtime.State<T> collectAsStateWithLifecycle(kotlinx.coroutines.flow.Flow<? extends T>, T? initialValue, androidx.lifecycle.Lifecycle lifecycle, optional androidx.lifecycle.Lifecycle.State minActiveState, optional kotlin.coroutines.CoroutineContext context);
+ }
+
+}
+
diff --git a/webkit/webkit/api/res-1.6.0-beta02.txt b/lifecycle/lifecycle-runtime-compose/api/res-2.6.0-beta02.txt
similarity index 100%
copy from webkit/webkit/api/res-1.6.0-beta02.txt
copy to lifecycle/lifecycle-runtime-compose/api/res-2.6.0-beta02.txt
diff --git a/lifecycle/lifecycle-runtime-compose/api/restricted_2.6.0-beta02.txt b/lifecycle/lifecycle-runtime-compose/api/restricted_2.6.0-beta02.txt
new file mode 100644
index 0000000..c80fa83
--- /dev/null
+++ b/lifecycle/lifecycle-runtime-compose/api/restricted_2.6.0-beta02.txt
@@ -0,0 +1,12 @@
+// Signature format: 4.0
+package androidx.lifecycle.compose {
+
+ public final class FlowExtKt {
+ method @androidx.compose.runtime.Composable public static <T> androidx.compose.runtime.State<T> collectAsStateWithLifecycle(kotlinx.coroutines.flow.StateFlow<? extends T>, optional androidx.lifecycle.LifecycleOwner lifecycleOwner, optional androidx.lifecycle.Lifecycle.State minActiveState, optional kotlin.coroutines.CoroutineContext context);
+ method @androidx.compose.runtime.Composable public static <T> androidx.compose.runtime.State<T> collectAsStateWithLifecycle(kotlinx.coroutines.flow.StateFlow<? extends T>, androidx.lifecycle.Lifecycle lifecycle, optional androidx.lifecycle.Lifecycle.State minActiveState, optional kotlin.coroutines.CoroutineContext context);
+ method @androidx.compose.runtime.Composable public static <T> androidx.compose.runtime.State<T> collectAsStateWithLifecycle(kotlinx.coroutines.flow.Flow<? extends T>, T? initialValue, optional androidx.lifecycle.LifecycleOwner lifecycleOwner, optional androidx.lifecycle.Lifecycle.State minActiveState, optional kotlin.coroutines.CoroutineContext context);
+ method @androidx.compose.runtime.Composable public static <T> androidx.compose.runtime.State<T> collectAsStateWithLifecycle(kotlinx.coroutines.flow.Flow<? extends T>, T? initialValue, androidx.lifecycle.Lifecycle lifecycle, optional androidx.lifecycle.Lifecycle.State minActiveState, optional kotlin.coroutines.CoroutineContext context);
+ }
+
+}
+
diff --git a/lifecycle/lifecycle-runtime-ktx/api/2.6.0-beta02.txt b/lifecycle/lifecycle-runtime-ktx/api/2.6.0-beta02.txt
new file mode 100644
index 0000000..2ee0d85
--- /dev/null
+++ b/lifecycle/lifecycle-runtime-ktx/api/2.6.0-beta02.txt
@@ -0,0 +1,33 @@
+// Signature format: 4.0
+package androidx.lifecycle {
+
+ public final class FlowExtKt {
+ method public static <T> kotlinx.coroutines.flow.Flow<T> flowWithLifecycle(kotlinx.coroutines.flow.Flow<? extends T>, androidx.lifecycle.Lifecycle lifecycle, optional androidx.lifecycle.Lifecycle.State minActiveState);
+ }
+
+ public final class LifecycleDestroyedException extends java.util.concurrent.CancellationException {
+ ctor public LifecycleDestroyedException();
+ }
+
+ public final class RepeatOnLifecycleKt {
+ method public static suspend Object? repeatOnLifecycle(androidx.lifecycle.Lifecycle, androidx.lifecycle.Lifecycle.State state, kotlin.jvm.functions.Function2<? super kotlinx.coroutines.CoroutineScope,? super kotlin.coroutines.Continuation<? super kotlin.Unit>,?> block, kotlin.coroutines.Continuation<? super kotlin.Unit>);
+ method public static suspend Object? repeatOnLifecycle(androidx.lifecycle.LifecycleOwner, androidx.lifecycle.Lifecycle.State state, kotlin.jvm.functions.Function2<? super kotlinx.coroutines.CoroutineScope,? super kotlin.coroutines.Continuation<? super kotlin.Unit>,?> block, kotlin.coroutines.Continuation<? super kotlin.Unit>);
+ }
+
+ public final class ViewKt {
+ method @Deprecated public static androidx.lifecycle.LifecycleOwner? findViewTreeLifecycleOwner(android.view.View);
+ }
+
+ public final class WithLifecycleStateKt {
+ method public static suspend inline <R> Object? withCreated(androidx.lifecycle.Lifecycle, kotlin.jvm.functions.Function0<? extends R> block, kotlin.coroutines.Continuation<? super R>);
+ method public static suspend inline <R> Object? withCreated(androidx.lifecycle.LifecycleOwner, kotlin.jvm.functions.Function0<? extends R> block, kotlin.coroutines.Continuation<? super R>);
+ method public static suspend inline <R> Object? withResumed(androidx.lifecycle.Lifecycle, kotlin.jvm.functions.Function0<? extends R> block, kotlin.coroutines.Continuation<? super R>);
+ method public static suspend inline <R> Object? withResumed(androidx.lifecycle.LifecycleOwner, kotlin.jvm.functions.Function0<? extends R> block, kotlin.coroutines.Continuation<? super R>);
+ method public static suspend inline <R> Object? withStarted(androidx.lifecycle.Lifecycle, kotlin.jvm.functions.Function0<? extends R> block, kotlin.coroutines.Continuation<? super R>);
+ method public static suspend inline <R> Object? withStarted(androidx.lifecycle.LifecycleOwner, kotlin.jvm.functions.Function0<? extends R> block, kotlin.coroutines.Continuation<? super R>);
+ method public static suspend inline <R> Object? withStateAtLeast(androidx.lifecycle.Lifecycle, androidx.lifecycle.Lifecycle.State state, kotlin.jvm.functions.Function0<? extends R> block, kotlin.coroutines.Continuation<? super R>);
+ method public static suspend inline <R> Object? withStateAtLeast(androidx.lifecycle.LifecycleOwner, androidx.lifecycle.Lifecycle.State state, kotlin.jvm.functions.Function0<? extends R> block, kotlin.coroutines.Continuation<? super R>);
+ }
+
+}
+
diff --git a/lifecycle/lifecycle-runtime-ktx/api/public_plus_experimental_2.6.0-beta02.txt b/lifecycle/lifecycle-runtime-ktx/api/public_plus_experimental_2.6.0-beta02.txt
new file mode 100644
index 0000000..2ee0d85
--- /dev/null
+++ b/lifecycle/lifecycle-runtime-ktx/api/public_plus_experimental_2.6.0-beta02.txt
@@ -0,0 +1,33 @@
+// Signature format: 4.0
+package androidx.lifecycle {
+
+ public final class FlowExtKt {
+ method public static <T> kotlinx.coroutines.flow.Flow<T> flowWithLifecycle(kotlinx.coroutines.flow.Flow<? extends T>, androidx.lifecycle.Lifecycle lifecycle, optional androidx.lifecycle.Lifecycle.State minActiveState);
+ }
+
+ public final class LifecycleDestroyedException extends java.util.concurrent.CancellationException {
+ ctor public LifecycleDestroyedException();
+ }
+
+ public final class RepeatOnLifecycleKt {
+ method public static suspend Object? repeatOnLifecycle(androidx.lifecycle.Lifecycle, androidx.lifecycle.Lifecycle.State state, kotlin.jvm.functions.Function2<? super kotlinx.coroutines.CoroutineScope,? super kotlin.coroutines.Continuation<? super kotlin.Unit>,?> block, kotlin.coroutines.Continuation<? super kotlin.Unit>);
+ method public static suspend Object? repeatOnLifecycle(androidx.lifecycle.LifecycleOwner, androidx.lifecycle.Lifecycle.State state, kotlin.jvm.functions.Function2<? super kotlinx.coroutines.CoroutineScope,? super kotlin.coroutines.Continuation<? super kotlin.Unit>,?> block, kotlin.coroutines.Continuation<? super kotlin.Unit>);
+ }
+
+ public final class ViewKt {
+ method @Deprecated public static androidx.lifecycle.LifecycleOwner? findViewTreeLifecycleOwner(android.view.View);
+ }
+
+ public final class WithLifecycleStateKt {
+ method public static suspend inline <R> Object? withCreated(androidx.lifecycle.Lifecycle, kotlin.jvm.functions.Function0<? extends R> block, kotlin.coroutines.Continuation<? super R>);
+ method public static suspend inline <R> Object? withCreated(androidx.lifecycle.LifecycleOwner, kotlin.jvm.functions.Function0<? extends R> block, kotlin.coroutines.Continuation<? super R>);
+ method public static suspend inline <R> Object? withResumed(androidx.lifecycle.Lifecycle, kotlin.jvm.functions.Function0<? extends R> block, kotlin.coroutines.Continuation<? super R>);
+ method public static suspend inline <R> Object? withResumed(androidx.lifecycle.LifecycleOwner, kotlin.jvm.functions.Function0<? extends R> block, kotlin.coroutines.Continuation<? super R>);
+ method public static suspend inline <R> Object? withStarted(androidx.lifecycle.Lifecycle, kotlin.jvm.functions.Function0<? extends R> block, kotlin.coroutines.Continuation<? super R>);
+ method public static suspend inline <R> Object? withStarted(androidx.lifecycle.LifecycleOwner, kotlin.jvm.functions.Function0<? extends R> block, kotlin.coroutines.Continuation<? super R>);
+ method public static suspend inline <R> Object? withStateAtLeast(androidx.lifecycle.Lifecycle, androidx.lifecycle.Lifecycle.State state, kotlin.jvm.functions.Function0<? extends R> block, kotlin.coroutines.Continuation<? super R>);
+ method public static suspend inline <R> Object? withStateAtLeast(androidx.lifecycle.LifecycleOwner, androidx.lifecycle.Lifecycle.State state, kotlin.jvm.functions.Function0<? extends R> block, kotlin.coroutines.Continuation<? super R>);
+ }
+
+}
+
diff --git a/webkit/webkit/api/res-1.6.0-beta02.txt b/lifecycle/lifecycle-runtime-ktx/api/res-2.6.0-beta02.txt
similarity index 100%
copy from webkit/webkit/api/res-1.6.0-beta02.txt
copy to lifecycle/lifecycle-runtime-ktx/api/res-2.6.0-beta02.txt
diff --git a/lifecycle/lifecycle-runtime-ktx/api/restricted_2.6.0-beta02.txt b/lifecycle/lifecycle-runtime-ktx/api/restricted_2.6.0-beta02.txt
new file mode 100644
index 0000000..a998f6e
--- /dev/null
+++ b/lifecycle/lifecycle-runtime-ktx/api/restricted_2.6.0-beta02.txt
@@ -0,0 +1,35 @@
+// Signature format: 4.0
+package androidx.lifecycle {
+
+ public final class FlowExtKt {
+ method public static <T> kotlinx.coroutines.flow.Flow<T> flowWithLifecycle(kotlinx.coroutines.flow.Flow<? extends T>, androidx.lifecycle.Lifecycle lifecycle, optional androidx.lifecycle.Lifecycle.State minActiveState);
+ }
+
+ public final class LifecycleDestroyedException extends java.util.concurrent.CancellationException {
+ ctor public LifecycleDestroyedException();
+ }
+
+ public final class RepeatOnLifecycleKt {
+ method public static suspend Object? repeatOnLifecycle(androidx.lifecycle.Lifecycle, androidx.lifecycle.Lifecycle.State state, kotlin.jvm.functions.Function2<? super kotlinx.coroutines.CoroutineScope,? super kotlin.coroutines.Continuation<? super kotlin.Unit>,?> block, kotlin.coroutines.Continuation<? super kotlin.Unit>);
+ method public static suspend Object? repeatOnLifecycle(androidx.lifecycle.LifecycleOwner, androidx.lifecycle.Lifecycle.State state, kotlin.jvm.functions.Function2<? super kotlinx.coroutines.CoroutineScope,? super kotlin.coroutines.Continuation<? super kotlin.Unit>,?> block, kotlin.coroutines.Continuation<? super kotlin.Unit>);
+ }
+
+ public final class ViewKt {
+ method @Deprecated public static androidx.lifecycle.LifecycleOwner? findViewTreeLifecycleOwner(android.view.View);
+ }
+
+ public final class WithLifecycleStateKt {
+ method @kotlin.PublishedApi internal static suspend <R> Object? suspendWithStateAtLeastUnchecked(androidx.lifecycle.Lifecycle, androidx.lifecycle.Lifecycle.State state, boolean dispatchNeeded, kotlinx.coroutines.CoroutineDispatcher lifecycleDispatcher, kotlin.jvm.functions.Function0<? extends R> block, kotlin.coroutines.Continuation<? super R>);
+ method public static suspend inline <R> Object? withCreated(androidx.lifecycle.Lifecycle, kotlin.jvm.functions.Function0<? extends R> block, kotlin.coroutines.Continuation<? super R>);
+ method public static suspend inline <R> Object? withCreated(androidx.lifecycle.LifecycleOwner, kotlin.jvm.functions.Function0<? extends R> block, kotlin.coroutines.Continuation<? super R>);
+ method public static suspend inline <R> Object? withResumed(androidx.lifecycle.Lifecycle, kotlin.jvm.functions.Function0<? extends R> block, kotlin.coroutines.Continuation<? super R>);
+ method public static suspend inline <R> Object? withResumed(androidx.lifecycle.LifecycleOwner, kotlin.jvm.functions.Function0<? extends R> block, kotlin.coroutines.Continuation<? super R>);
+ method public static suspend inline <R> Object? withStarted(androidx.lifecycle.Lifecycle, kotlin.jvm.functions.Function0<? extends R> block, kotlin.coroutines.Continuation<? super R>);
+ method public static suspend inline <R> Object? withStarted(androidx.lifecycle.LifecycleOwner, kotlin.jvm.functions.Function0<? extends R> block, kotlin.coroutines.Continuation<? super R>);
+ method public static suspend inline <R> Object? withStateAtLeast(androidx.lifecycle.Lifecycle, androidx.lifecycle.Lifecycle.State state, kotlin.jvm.functions.Function0<? extends R> block, kotlin.coroutines.Continuation<? super R>);
+ method public static suspend inline <R> Object? withStateAtLeast(androidx.lifecycle.LifecycleOwner, androidx.lifecycle.Lifecycle.State state, kotlin.jvm.functions.Function0<? extends R> block, kotlin.coroutines.Continuation<? super R>);
+ method @kotlin.PublishedApi internal static suspend inline <R> Object? withStateAtLeastUnchecked(androidx.lifecycle.Lifecycle, androidx.lifecycle.Lifecycle.State state, kotlin.jvm.functions.Function0<? extends R> block, kotlin.coroutines.Continuation<? super R>);
+ }
+
+}
+
diff --git a/lifecycle/lifecycle-runtime-testing/api/2.6.0-beta02.txt b/lifecycle/lifecycle-runtime-testing/api/2.6.0-beta02.txt
new file mode 100644
index 0000000..47a819e
--- /dev/null
+++ b/lifecycle/lifecycle-runtime-testing/api/2.6.0-beta02.txt
@@ -0,0 +1,19 @@
+// Signature format: 4.0
+package androidx.lifecycle.testing {
+
+ public final class TestLifecycleOwner implements androidx.lifecycle.LifecycleOwner {
+ ctor public TestLifecycleOwner(optional androidx.lifecycle.Lifecycle.State initialState, optional kotlinx.coroutines.CoroutineDispatcher coroutineDispatcher);
+ ctor public TestLifecycleOwner(optional androidx.lifecycle.Lifecycle.State initialState);
+ ctor public TestLifecycleOwner();
+ method public androidx.lifecycle.Lifecycle.State getCurrentState();
+ method public androidx.lifecycle.LifecycleRegistry getLifecycle();
+ method public int getObserverCount();
+ method public void handleLifecycleEvent(androidx.lifecycle.Lifecycle.Event event);
+ method public void setCurrentState(androidx.lifecycle.Lifecycle.State);
+ property public final androidx.lifecycle.Lifecycle.State currentState;
+ property public androidx.lifecycle.LifecycleRegistry lifecycle;
+ property public final int observerCount;
+ }
+
+}
+
diff --git a/lifecycle/lifecycle-runtime-testing/api/public_plus_experimental_2.6.0-beta02.txt b/lifecycle/lifecycle-runtime-testing/api/public_plus_experimental_2.6.0-beta02.txt
new file mode 100644
index 0000000..47a819e
--- /dev/null
+++ b/lifecycle/lifecycle-runtime-testing/api/public_plus_experimental_2.6.0-beta02.txt
@@ -0,0 +1,19 @@
+// Signature format: 4.0
+package androidx.lifecycle.testing {
+
+ public final class TestLifecycleOwner implements androidx.lifecycle.LifecycleOwner {
+ ctor public TestLifecycleOwner(optional androidx.lifecycle.Lifecycle.State initialState, optional kotlinx.coroutines.CoroutineDispatcher coroutineDispatcher);
+ ctor public TestLifecycleOwner(optional androidx.lifecycle.Lifecycle.State initialState);
+ ctor public TestLifecycleOwner();
+ method public androidx.lifecycle.Lifecycle.State getCurrentState();
+ method public androidx.lifecycle.LifecycleRegistry getLifecycle();
+ method public int getObserverCount();
+ method public void handleLifecycleEvent(androidx.lifecycle.Lifecycle.Event event);
+ method public void setCurrentState(androidx.lifecycle.Lifecycle.State);
+ property public final androidx.lifecycle.Lifecycle.State currentState;
+ property public androidx.lifecycle.LifecycleRegistry lifecycle;
+ property public final int observerCount;
+ }
+
+}
+
diff --git a/webkit/webkit/api/res-1.6.0-beta02.txt b/lifecycle/lifecycle-runtime-testing/api/res-2.6.0-beta02.txt
similarity index 100%
copy from webkit/webkit/api/res-1.6.0-beta02.txt
copy to lifecycle/lifecycle-runtime-testing/api/res-2.6.0-beta02.txt
diff --git a/lifecycle/lifecycle-runtime-testing/api/restricted_2.6.0-beta02.txt b/lifecycle/lifecycle-runtime-testing/api/restricted_2.6.0-beta02.txt
new file mode 100644
index 0000000..47a819e
--- /dev/null
+++ b/lifecycle/lifecycle-runtime-testing/api/restricted_2.6.0-beta02.txt
@@ -0,0 +1,19 @@
+// Signature format: 4.0
+package androidx.lifecycle.testing {
+
+ public final class TestLifecycleOwner implements androidx.lifecycle.LifecycleOwner {
+ ctor public TestLifecycleOwner(optional androidx.lifecycle.Lifecycle.State initialState, optional kotlinx.coroutines.CoroutineDispatcher coroutineDispatcher);
+ ctor public TestLifecycleOwner(optional androidx.lifecycle.Lifecycle.State initialState);
+ ctor public TestLifecycleOwner();
+ method public androidx.lifecycle.Lifecycle.State getCurrentState();
+ method public androidx.lifecycle.LifecycleRegistry getLifecycle();
+ method public int getObserverCount();
+ method public void handleLifecycleEvent(androidx.lifecycle.Lifecycle.Event event);
+ method public void setCurrentState(androidx.lifecycle.Lifecycle.State);
+ property public final androidx.lifecycle.Lifecycle.State currentState;
+ property public androidx.lifecycle.LifecycleRegistry lifecycle;
+ property public final int observerCount;
+ }
+
+}
+
diff --git a/lifecycle/lifecycle-runtime/api/2.6.0-beta02.txt b/lifecycle/lifecycle-runtime/api/2.6.0-beta02.txt
new file mode 100644
index 0000000..e72bd60
--- /dev/null
+++ b/lifecycle/lifecycle-runtime/api/2.6.0-beta02.txt
@@ -0,0 +1,33 @@
+// Signature format: 4.0
+package androidx.lifecycle {
+
+ public class LifecycleRegistry extends androidx.lifecycle.Lifecycle {
+ ctor public LifecycleRegistry(androidx.lifecycle.LifecycleOwner provider);
+ method public void addObserver(androidx.lifecycle.LifecycleObserver observer);
+ method @VisibleForTesting public static final androidx.lifecycle.LifecycleRegistry createUnsafe(androidx.lifecycle.LifecycleOwner owner);
+ method public androidx.lifecycle.Lifecycle.State getCurrentState();
+ method public int getObserverCount();
+ method public void handleLifecycleEvent(androidx.lifecycle.Lifecycle.Event event);
+ method @Deprecated @MainThread public void markState(androidx.lifecycle.Lifecycle.State state);
+ method public void removeObserver(androidx.lifecycle.LifecycleObserver observer);
+ method public void setCurrentState(androidx.lifecycle.Lifecycle.State);
+ property public androidx.lifecycle.Lifecycle.State currentState;
+ property public int observerCount;
+ field public static final androidx.lifecycle.LifecycleRegistry.Companion Companion;
+ }
+
+ public static final class LifecycleRegistry.Companion {
+ method @VisibleForTesting public androidx.lifecycle.LifecycleRegistry createUnsafe(androidx.lifecycle.LifecycleOwner owner);
+ }
+
+ @Deprecated public interface LifecycleRegistryOwner extends androidx.lifecycle.LifecycleOwner {
+ method @Deprecated public androidx.lifecycle.LifecycleRegistry getLifecycle();
+ }
+
+ public final class ViewTreeLifecycleOwner {
+ method public static androidx.lifecycle.LifecycleOwner? get(android.view.View);
+ method public static void set(android.view.View, androidx.lifecycle.LifecycleOwner? lifecycleOwner);
+ }
+
+}
+
diff --git a/lifecycle/lifecycle-runtime/api/public_plus_experimental_2.6.0-beta02.txt b/lifecycle/lifecycle-runtime/api/public_plus_experimental_2.6.0-beta02.txt
new file mode 100644
index 0000000..e72bd60
--- /dev/null
+++ b/lifecycle/lifecycle-runtime/api/public_plus_experimental_2.6.0-beta02.txt
@@ -0,0 +1,33 @@
+// Signature format: 4.0
+package androidx.lifecycle {
+
+ public class LifecycleRegistry extends androidx.lifecycle.Lifecycle {
+ ctor public LifecycleRegistry(androidx.lifecycle.LifecycleOwner provider);
+ method public void addObserver(androidx.lifecycle.LifecycleObserver observer);
+ method @VisibleForTesting public static final androidx.lifecycle.LifecycleRegistry createUnsafe(androidx.lifecycle.LifecycleOwner owner);
+ method public androidx.lifecycle.Lifecycle.State getCurrentState();
+ method public int getObserverCount();
+ method public void handleLifecycleEvent(androidx.lifecycle.Lifecycle.Event event);
+ method @Deprecated @MainThread public void markState(androidx.lifecycle.Lifecycle.State state);
+ method public void removeObserver(androidx.lifecycle.LifecycleObserver observer);
+ method public void setCurrentState(androidx.lifecycle.Lifecycle.State);
+ property public androidx.lifecycle.Lifecycle.State currentState;
+ property public int observerCount;
+ field public static final androidx.lifecycle.LifecycleRegistry.Companion Companion;
+ }
+
+ public static final class LifecycleRegistry.Companion {
+ method @VisibleForTesting public androidx.lifecycle.LifecycleRegistry createUnsafe(androidx.lifecycle.LifecycleOwner owner);
+ }
+
+ @Deprecated public interface LifecycleRegistryOwner extends androidx.lifecycle.LifecycleOwner {
+ method @Deprecated public androidx.lifecycle.LifecycleRegistry getLifecycle();
+ }
+
+ public final class ViewTreeLifecycleOwner {
+ method public static androidx.lifecycle.LifecycleOwner? get(android.view.View);
+ method public static void set(android.view.View, androidx.lifecycle.LifecycleOwner? lifecycleOwner);
+ }
+
+}
+
diff --git a/webkit/webkit/api/res-1.6.0-beta02.txt b/lifecycle/lifecycle-runtime/api/res-2.6.0-beta02.txt
similarity index 100%
copy from webkit/webkit/api/res-1.6.0-beta02.txt
copy to lifecycle/lifecycle-runtime/api/res-2.6.0-beta02.txt
diff --git a/lifecycle/lifecycle-runtime/api/restricted_2.6.0-beta02.txt b/lifecycle/lifecycle-runtime/api/restricted_2.6.0-beta02.txt
new file mode 100644
index 0000000..704cdb4
--- /dev/null
+++ b/lifecycle/lifecycle-runtime/api/restricted_2.6.0-beta02.txt
@@ -0,0 +1,58 @@
+// Signature format: 4.0
+package androidx.lifecycle {
+
+ public class LifecycleRegistry extends androidx.lifecycle.Lifecycle {
+ ctor public LifecycleRegistry(androidx.lifecycle.LifecycleOwner provider);
+ method public void addObserver(androidx.lifecycle.LifecycleObserver observer);
+ method @VisibleForTesting public static final androidx.lifecycle.LifecycleRegistry createUnsafe(androidx.lifecycle.LifecycleOwner owner);
+ method public androidx.lifecycle.Lifecycle.State getCurrentState();
+ method public int getObserverCount();
+ method public void handleLifecycleEvent(androidx.lifecycle.Lifecycle.Event event);
+ method @Deprecated @MainThread public void markState(androidx.lifecycle.Lifecycle.State state);
+ method public void removeObserver(androidx.lifecycle.LifecycleObserver observer);
+ method public void setCurrentState(androidx.lifecycle.Lifecycle.State);
+ property public androidx.lifecycle.Lifecycle.State currentState;
+ property public int observerCount;
+ field public static final androidx.lifecycle.LifecycleRegistry.Companion Companion;
+ }
+
+ public static final class LifecycleRegistry.Companion {
+ method @VisibleForTesting public androidx.lifecycle.LifecycleRegistry createUnsafe(androidx.lifecycle.LifecycleOwner owner);
+ }
+
+ @Deprecated public interface LifecycleRegistryOwner extends androidx.lifecycle.LifecycleOwner {
+ method @Deprecated public androidx.lifecycle.LifecycleRegistry getLifecycle();
+ }
+
+ @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) public class ReportFragment extends android.app.Fragment {
+ ctor public ReportFragment();
+ method public static final androidx.lifecycle.ReportFragment get(android.app.Activity);
+ method public static final void injectIfNeededIn(android.app.Activity activity);
+ method public void onActivityCreated(android.os.Bundle? savedInstanceState);
+ method public void onDestroy();
+ method public void onPause();
+ method public void onResume();
+ method public void onStart();
+ method public void onStop();
+ method public final void setProcessListener(androidx.lifecycle.ReportFragment.ActivityInitializationListener? processListener);
+ field public static final androidx.lifecycle.ReportFragment.Companion Companion;
+ }
+
+ public static interface ReportFragment.ActivityInitializationListener {
+ method public void onCreate();
+ method public void onResume();
+ method public void onStart();
+ }
+
+ public static final class ReportFragment.Companion {
+ method public androidx.lifecycle.ReportFragment get(android.app.Activity);
+ method public void injectIfNeededIn(android.app.Activity activity);
+ }
+
+ public final class ViewTreeLifecycleOwner {
+ method public static androidx.lifecycle.LifecycleOwner? get(android.view.View);
+ method public static void set(android.view.View, androidx.lifecycle.LifecycleOwner? lifecycleOwner);
+ }
+
+}
+
diff --git a/lifecycle/lifecycle-service/api/2.6.0-beta02.txt b/lifecycle/lifecycle-service/api/2.6.0-beta02.txt
new file mode 100644
index 0000000..bebcd93
--- /dev/null
+++ b/lifecycle/lifecycle-service/api/2.6.0-beta02.txt
@@ -0,0 +1,22 @@
+// Signature format: 4.0
+package androidx.lifecycle {
+
+ public class LifecycleService extends android.app.Service implements androidx.lifecycle.LifecycleOwner {
+ ctor public LifecycleService();
+ method public androidx.lifecycle.Lifecycle getLifecycle();
+ method @CallSuper public android.os.IBinder? onBind(android.content.Intent intent);
+ property public androidx.lifecycle.Lifecycle lifecycle;
+ }
+
+ public class ServiceLifecycleDispatcher {
+ ctor public ServiceLifecycleDispatcher(androidx.lifecycle.LifecycleOwner provider);
+ method public androidx.lifecycle.Lifecycle getLifecycle();
+ method public void onServicePreSuperOnBind();
+ method public void onServicePreSuperOnCreate();
+ method public void onServicePreSuperOnDestroy();
+ method public void onServicePreSuperOnStart();
+ property public androidx.lifecycle.Lifecycle lifecycle;
+ }
+
+}
+
diff --git a/lifecycle/lifecycle-service/api/public_plus_experimental_2.6.0-beta02.txt b/lifecycle/lifecycle-service/api/public_plus_experimental_2.6.0-beta02.txt
new file mode 100644
index 0000000..bebcd93
--- /dev/null
+++ b/lifecycle/lifecycle-service/api/public_plus_experimental_2.6.0-beta02.txt
@@ -0,0 +1,22 @@
+// Signature format: 4.0
+package androidx.lifecycle {
+
+ public class LifecycleService extends android.app.Service implements androidx.lifecycle.LifecycleOwner {
+ ctor public LifecycleService();
+ method public androidx.lifecycle.Lifecycle getLifecycle();
+ method @CallSuper public android.os.IBinder? onBind(android.content.Intent intent);
+ property public androidx.lifecycle.Lifecycle lifecycle;
+ }
+
+ public class ServiceLifecycleDispatcher {
+ ctor public ServiceLifecycleDispatcher(androidx.lifecycle.LifecycleOwner provider);
+ method public androidx.lifecycle.Lifecycle getLifecycle();
+ method public void onServicePreSuperOnBind();
+ method public void onServicePreSuperOnCreate();
+ method public void onServicePreSuperOnDestroy();
+ method public void onServicePreSuperOnStart();
+ property public androidx.lifecycle.Lifecycle lifecycle;
+ }
+
+}
+
diff --git a/webkit/webkit/api/res-1.6.0-beta02.txt b/lifecycle/lifecycle-service/api/res-2.6.0-beta02.txt
similarity index 100%
copy from webkit/webkit/api/res-1.6.0-beta02.txt
copy to lifecycle/lifecycle-service/api/res-2.6.0-beta02.txt
diff --git a/lifecycle/lifecycle-service/api/restricted_2.6.0-beta02.txt b/lifecycle/lifecycle-service/api/restricted_2.6.0-beta02.txt
new file mode 100644
index 0000000..bebcd93
--- /dev/null
+++ b/lifecycle/lifecycle-service/api/restricted_2.6.0-beta02.txt
@@ -0,0 +1,22 @@
+// Signature format: 4.0
+package androidx.lifecycle {
+
+ public class LifecycleService extends android.app.Service implements androidx.lifecycle.LifecycleOwner {
+ ctor public LifecycleService();
+ method public androidx.lifecycle.Lifecycle getLifecycle();
+ method @CallSuper public android.os.IBinder? onBind(android.content.Intent intent);
+ property public androidx.lifecycle.Lifecycle lifecycle;
+ }
+
+ public class ServiceLifecycleDispatcher {
+ ctor public ServiceLifecycleDispatcher(androidx.lifecycle.LifecycleOwner provider);
+ method public androidx.lifecycle.Lifecycle getLifecycle();
+ method public void onServicePreSuperOnBind();
+ method public void onServicePreSuperOnCreate();
+ method public void onServicePreSuperOnDestroy();
+ method public void onServicePreSuperOnStart();
+ property public androidx.lifecycle.Lifecycle lifecycle;
+ }
+
+}
+
diff --git a/lifecycle/lifecycle-viewmodel-compose/api/2.6.0-beta02.txt b/lifecycle/lifecycle-viewmodel-compose/api/2.6.0-beta02.txt
new file mode 100644
index 0000000..05b6910
--- /dev/null
+++ b/lifecycle/lifecycle-viewmodel-compose/api/2.6.0-beta02.txt
@@ -0,0 +1,23 @@
+// Signature format: 4.0
+package androidx.lifecycle.viewmodel.compose {
+
+ public final class LocalViewModelStoreOwner {
+ method @androidx.compose.runtime.Composable public androidx.lifecycle.ViewModelStoreOwner? getCurrent();
+ method public infix androidx.compose.runtime.ProvidedValue<androidx.lifecycle.ViewModelStoreOwner> provides(androidx.lifecycle.ViewModelStoreOwner viewModelStoreOwner);
+ property @androidx.compose.runtime.Composable public final androidx.lifecycle.ViewModelStoreOwner? current;
+ field public static final androidx.lifecycle.viewmodel.compose.LocalViewModelStoreOwner INSTANCE;
+ }
+
+ public final class SavedStateHandleSaverKt {
+ }
+
+ public final class ViewModelKt {
+ method @androidx.compose.runtime.Composable public static <VM extends androidx.lifecycle.ViewModel> VM viewModel(Class<VM> modelClass, optional androidx.lifecycle.ViewModelStoreOwner viewModelStoreOwner, optional String? key, optional androidx.lifecycle.ViewModelProvider.Factory? factory, optional androidx.lifecycle.viewmodel.CreationExtras extras);
+ method @Deprecated @androidx.compose.runtime.Composable public static inline <reified VM extends androidx.lifecycle.ViewModel> VM viewModel(optional androidx.lifecycle.ViewModelStoreOwner viewModelStoreOwner, optional String? key, optional androidx.lifecycle.ViewModelProvider.Factory? factory);
+ method @androidx.compose.runtime.Composable public static inline <reified VM extends androidx.lifecycle.ViewModel> VM viewModel(optional androidx.lifecycle.ViewModelStoreOwner viewModelStoreOwner, optional String? key, optional androidx.lifecycle.ViewModelProvider.Factory? factory, optional androidx.lifecycle.viewmodel.CreationExtras extras);
+ method @Deprecated @androidx.compose.runtime.Composable public static <VM extends androidx.lifecycle.ViewModel> VM viewModel(Class<VM> modelClass, optional androidx.lifecycle.ViewModelStoreOwner viewModelStoreOwner, optional String? key, optional androidx.lifecycle.ViewModelProvider.Factory? factory);
+ method @androidx.compose.runtime.Composable public static inline <reified VM extends androidx.lifecycle.ViewModel> VM viewModel(optional androidx.lifecycle.ViewModelStoreOwner viewModelStoreOwner, optional String? key, kotlin.jvm.functions.Function1<? super androidx.lifecycle.viewmodel.CreationExtras,? extends VM> initializer);
+ }
+
+}
+
diff --git a/lifecycle/lifecycle-viewmodel-compose/api/public_plus_experimental_2.6.0-beta02.txt b/lifecycle/lifecycle-viewmodel-compose/api/public_plus_experimental_2.6.0-beta02.txt
new file mode 100644
index 0000000..188b922
--- /dev/null
+++ b/lifecycle/lifecycle-viewmodel-compose/api/public_plus_experimental_2.6.0-beta02.txt
@@ -0,0 +1,30 @@
+// Signature format: 4.0
+package androidx.lifecycle.viewmodel.compose {
+
+ public final class LocalViewModelStoreOwner {
+ method @androidx.compose.runtime.Composable public androidx.lifecycle.ViewModelStoreOwner? getCurrent();
+ method public infix androidx.compose.runtime.ProvidedValue<androidx.lifecycle.ViewModelStoreOwner> provides(androidx.lifecycle.ViewModelStoreOwner viewModelStoreOwner);
+ property @androidx.compose.runtime.Composable public final androidx.lifecycle.ViewModelStoreOwner? current;
+ field public static final androidx.lifecycle.viewmodel.compose.LocalViewModelStoreOwner INSTANCE;
+ }
+
+ @kotlin.RequiresOptIn(level=kotlin.RequiresOptIn.Level.WARNING) @kotlin.annotation.Retention(kotlin.annotation.AnnotationRetention.RUNTIME) @kotlin.annotation.Target(allowedTargets=kotlin.annotation.AnnotationTarget.FUNCTION) public @interface SavedStateHandleSaveableApi {
+ }
+
+ public final class SavedStateHandleSaverKt {
+ method @androidx.lifecycle.viewmodel.compose.SavedStateHandleSaveableApi public static <T> T saveable(androidx.lifecycle.SavedStateHandle, String key, optional androidx.compose.runtime.saveable.Saver<T,?> saver, kotlin.jvm.functions.Function0<? extends T> init);
+ method @androidx.lifecycle.viewmodel.compose.SavedStateHandleSaveableApi public static <T> androidx.compose.runtime.MutableState<T> saveable(androidx.lifecycle.SavedStateHandle, String key, androidx.compose.runtime.saveable.Saver<T,?> stateSaver, kotlin.jvm.functions.Function0<? extends androidx.compose.runtime.MutableState<T>> init);
+ method @androidx.lifecycle.viewmodel.compose.SavedStateHandleSaveableApi public static <T> kotlin.properties.PropertyDelegateProvider<java.lang.Object,kotlin.properties.ReadOnlyProperty<java.lang.Object,T>> saveable(androidx.lifecycle.SavedStateHandle, optional androidx.compose.runtime.saveable.Saver<T,?> saver, kotlin.jvm.functions.Function0<? extends T> init);
+ method @androidx.lifecycle.viewmodel.compose.SavedStateHandleSaveableApi public static <T, M extends androidx.compose.runtime.MutableState<T>> kotlin.properties.PropertyDelegateProvider<java.lang.Object,kotlin.properties.ReadWriteProperty<java.lang.Object,T>> saveableMutableState(androidx.lifecycle.SavedStateHandle, optional androidx.compose.runtime.saveable.Saver<T,?> stateSaver, kotlin.jvm.functions.Function0<? extends M> init);
+ }
+
+ public final class ViewModelKt {
+ method @androidx.compose.runtime.Composable public static <VM extends androidx.lifecycle.ViewModel> VM viewModel(Class<VM> modelClass, optional androidx.lifecycle.ViewModelStoreOwner viewModelStoreOwner, optional String? key, optional androidx.lifecycle.ViewModelProvider.Factory? factory, optional androidx.lifecycle.viewmodel.CreationExtras extras);
+ method @Deprecated @androidx.compose.runtime.Composable public static inline <reified VM extends androidx.lifecycle.ViewModel> VM viewModel(optional androidx.lifecycle.ViewModelStoreOwner viewModelStoreOwner, optional String? key, optional androidx.lifecycle.ViewModelProvider.Factory? factory);
+ method @androidx.compose.runtime.Composable public static inline <reified VM extends androidx.lifecycle.ViewModel> VM viewModel(optional androidx.lifecycle.ViewModelStoreOwner viewModelStoreOwner, optional String? key, optional androidx.lifecycle.ViewModelProvider.Factory? factory, optional androidx.lifecycle.viewmodel.CreationExtras extras);
+ method @Deprecated @androidx.compose.runtime.Composable public static <VM extends androidx.lifecycle.ViewModel> VM viewModel(Class<VM> modelClass, optional androidx.lifecycle.ViewModelStoreOwner viewModelStoreOwner, optional String? key, optional androidx.lifecycle.ViewModelProvider.Factory? factory);
+ method @androidx.compose.runtime.Composable public static inline <reified VM extends androidx.lifecycle.ViewModel> VM viewModel(optional androidx.lifecycle.ViewModelStoreOwner viewModelStoreOwner, optional String? key, kotlin.jvm.functions.Function1<? super androidx.lifecycle.viewmodel.CreationExtras,? extends VM> initializer);
+ }
+
+}
+
diff --git a/webkit/webkit/api/res-1.6.0-beta02.txt b/lifecycle/lifecycle-viewmodel-compose/api/res-2.6.0-beta02.txt
similarity index 100%
copy from webkit/webkit/api/res-1.6.0-beta02.txt
copy to lifecycle/lifecycle-viewmodel-compose/api/res-2.6.0-beta02.txt
diff --git a/lifecycle/lifecycle-viewmodel-compose/api/restricted_2.6.0-beta02.txt b/lifecycle/lifecycle-viewmodel-compose/api/restricted_2.6.0-beta02.txt
new file mode 100644
index 0000000..05b6910
--- /dev/null
+++ b/lifecycle/lifecycle-viewmodel-compose/api/restricted_2.6.0-beta02.txt
@@ -0,0 +1,23 @@
+// Signature format: 4.0
+package androidx.lifecycle.viewmodel.compose {
+
+ public final class LocalViewModelStoreOwner {
+ method @androidx.compose.runtime.Composable public androidx.lifecycle.ViewModelStoreOwner? getCurrent();
+ method public infix androidx.compose.runtime.ProvidedValue<androidx.lifecycle.ViewModelStoreOwner> provides(androidx.lifecycle.ViewModelStoreOwner viewModelStoreOwner);
+ property @androidx.compose.runtime.Composable public final androidx.lifecycle.ViewModelStoreOwner? current;
+ field public static final androidx.lifecycle.viewmodel.compose.LocalViewModelStoreOwner INSTANCE;
+ }
+
+ public final class SavedStateHandleSaverKt {
+ }
+
+ public final class ViewModelKt {
+ method @androidx.compose.runtime.Composable public static <VM extends androidx.lifecycle.ViewModel> VM viewModel(Class<VM> modelClass, optional androidx.lifecycle.ViewModelStoreOwner viewModelStoreOwner, optional String? key, optional androidx.lifecycle.ViewModelProvider.Factory? factory, optional androidx.lifecycle.viewmodel.CreationExtras extras);
+ method @Deprecated @androidx.compose.runtime.Composable public static inline <reified VM extends androidx.lifecycle.ViewModel> VM viewModel(optional androidx.lifecycle.ViewModelStoreOwner viewModelStoreOwner, optional String? key, optional androidx.lifecycle.ViewModelProvider.Factory? factory);
+ method @androidx.compose.runtime.Composable public static inline <reified VM extends androidx.lifecycle.ViewModel> VM viewModel(optional androidx.lifecycle.ViewModelStoreOwner viewModelStoreOwner, optional String? key, optional androidx.lifecycle.ViewModelProvider.Factory? factory, optional androidx.lifecycle.viewmodel.CreationExtras extras);
+ method @Deprecated @androidx.compose.runtime.Composable public static <VM extends androidx.lifecycle.ViewModel> VM viewModel(Class<VM> modelClass, optional androidx.lifecycle.ViewModelStoreOwner viewModelStoreOwner, optional String? key, optional androidx.lifecycle.ViewModelProvider.Factory? factory);
+ method @androidx.compose.runtime.Composable public static inline <reified VM extends androidx.lifecycle.ViewModel> VM viewModel(optional androidx.lifecycle.ViewModelStoreOwner viewModelStoreOwner, optional String? key, kotlin.jvm.functions.Function1<? super androidx.lifecycle.viewmodel.CreationExtras,? extends VM> initializer);
+ }
+
+}
+
diff --git a/lifecycle/lifecycle-viewmodel-ktx/api/2.6.0-beta02.txt b/lifecycle/lifecycle-viewmodel-ktx/api/2.6.0-beta02.txt
new file mode 100644
index 0000000..1d1d247
--- /dev/null
+++ b/lifecycle/lifecycle-viewmodel-ktx/api/2.6.0-beta02.txt
@@ -0,0 +1,9 @@
+// Signature format: 4.0
+package androidx.lifecycle {
+
+ public final class ViewModelKt {
+ method public static kotlinx.coroutines.CoroutineScope getViewModelScope(androidx.lifecycle.ViewModel);
+ }
+
+}
+
diff --git a/lifecycle/lifecycle-viewmodel-ktx/api/public_plus_experimental_2.6.0-beta02.txt b/lifecycle/lifecycle-viewmodel-ktx/api/public_plus_experimental_2.6.0-beta02.txt
new file mode 100644
index 0000000..1d1d247
--- /dev/null
+++ b/lifecycle/lifecycle-viewmodel-ktx/api/public_plus_experimental_2.6.0-beta02.txt
@@ -0,0 +1,9 @@
+// Signature format: 4.0
+package androidx.lifecycle {
+
+ public final class ViewModelKt {
+ method public static kotlinx.coroutines.CoroutineScope getViewModelScope(androidx.lifecycle.ViewModel);
+ }
+
+}
+
diff --git a/webkit/webkit/api/res-1.6.0-beta02.txt b/lifecycle/lifecycle-viewmodel-ktx/api/res-2.6.0-beta02.txt
similarity index 100%
copy from webkit/webkit/api/res-1.6.0-beta02.txt
copy to lifecycle/lifecycle-viewmodel-ktx/api/res-2.6.0-beta02.txt
diff --git a/lifecycle/lifecycle-viewmodel-ktx/api/restricted_2.6.0-beta02.txt b/lifecycle/lifecycle-viewmodel-ktx/api/restricted_2.6.0-beta02.txt
new file mode 100644
index 0000000..1d1d247
--- /dev/null
+++ b/lifecycle/lifecycle-viewmodel-ktx/api/restricted_2.6.0-beta02.txt
@@ -0,0 +1,9 @@
+// Signature format: 4.0
+package androidx.lifecycle {
+
+ public final class ViewModelKt {
+ method public static kotlinx.coroutines.CoroutineScope getViewModelScope(androidx.lifecycle.ViewModel);
+ }
+
+}
+
diff --git a/lifecycle/lifecycle-viewmodel-savedstate/api/2.6.0-beta02.txt b/lifecycle/lifecycle-viewmodel-savedstate/api/2.6.0-beta02.txt
new file mode 100644
index 0000000..c030c8a
--- /dev/null
+++ b/lifecycle/lifecycle-viewmodel-savedstate/api/2.6.0-beta02.txt
@@ -0,0 +1,45 @@
+// Signature format: 4.0
+package androidx.lifecycle {
+
+ public abstract class AbstractSavedStateViewModelFactory implements androidx.lifecycle.ViewModelProvider.Factory {
+ ctor public AbstractSavedStateViewModelFactory();
+ ctor public AbstractSavedStateViewModelFactory(androidx.savedstate.SavedStateRegistryOwner owner, android.os.Bundle? defaultArgs);
+ method protected abstract <T extends androidx.lifecycle.ViewModel> T create(String key, Class<T> modelClass, androidx.lifecycle.SavedStateHandle handle);
+ }
+
+ public final class SavedStateHandle {
+ ctor public SavedStateHandle(java.util.Map<java.lang.String,?> initialState);
+ ctor public SavedStateHandle();
+ method @MainThread public void clearSavedStateProvider(String key);
+ method @MainThread public operator boolean contains(String key);
+ method @MainThread public operator <T> T? get(String key);
+ method @MainThread public <T> androidx.lifecycle.MutableLiveData<T> getLiveData(String key);
+ method @MainThread public <T> androidx.lifecycle.MutableLiveData<T> getLiveData(String key, T? initialValue);
+ method @MainThread public <T> kotlinx.coroutines.flow.StateFlow<T> getStateFlow(String key, T? initialValue);
+ method @MainThread public java.util.Set<java.lang.String> keys();
+ method @MainThread public <T> T? remove(String key);
+ method @MainThread public operator <T> void set(String key, T? value);
+ method @MainThread public void setSavedStateProvider(String key, androidx.savedstate.SavedStateRegistry.SavedStateProvider provider);
+ field public static final androidx.lifecycle.SavedStateHandle.Companion Companion;
+ }
+
+ public static final class SavedStateHandle.Companion {
+ }
+
+ public final class SavedStateHandleSupport {
+ method @MainThread public static androidx.lifecycle.SavedStateHandle createSavedStateHandle(androidx.lifecycle.viewmodel.CreationExtras);
+ method @MainThread public static <T extends androidx.savedstate.SavedStateRegistryOwner & androidx.lifecycle.ViewModelStoreOwner> void enableSavedStateHandles(T);
+ field public static final androidx.lifecycle.viewmodel.CreationExtras.Key<android.os.Bundle> DEFAULT_ARGS_KEY;
+ field public static final androidx.lifecycle.viewmodel.CreationExtras.Key<androidx.savedstate.SavedStateRegistryOwner> SAVED_STATE_REGISTRY_OWNER_KEY;
+ field public static final androidx.lifecycle.viewmodel.CreationExtras.Key<androidx.lifecycle.ViewModelStoreOwner> VIEW_MODEL_STORE_OWNER_KEY;
+ }
+
+ public final class SavedStateViewModelFactory implements androidx.lifecycle.ViewModelProvider.Factory {
+ ctor public SavedStateViewModelFactory();
+ ctor public SavedStateViewModelFactory(android.app.Application? application, androidx.savedstate.SavedStateRegistryOwner owner);
+ ctor public SavedStateViewModelFactory(android.app.Application? application, androidx.savedstate.SavedStateRegistryOwner owner, android.os.Bundle? defaultArgs);
+ method public <T extends androidx.lifecycle.ViewModel> T create(String key, Class<T> modelClass);
+ }
+
+}
+
diff --git a/lifecycle/lifecycle-viewmodel-savedstate/api/public_plus_experimental_2.6.0-beta02.txt b/lifecycle/lifecycle-viewmodel-savedstate/api/public_plus_experimental_2.6.0-beta02.txt
new file mode 100644
index 0000000..c030c8a
--- /dev/null
+++ b/lifecycle/lifecycle-viewmodel-savedstate/api/public_plus_experimental_2.6.0-beta02.txt
@@ -0,0 +1,45 @@
+// Signature format: 4.0
+package androidx.lifecycle {
+
+ public abstract class AbstractSavedStateViewModelFactory implements androidx.lifecycle.ViewModelProvider.Factory {
+ ctor public AbstractSavedStateViewModelFactory();
+ ctor public AbstractSavedStateViewModelFactory(androidx.savedstate.SavedStateRegistryOwner owner, android.os.Bundle? defaultArgs);
+ method protected abstract <T extends androidx.lifecycle.ViewModel> T create(String key, Class<T> modelClass, androidx.lifecycle.SavedStateHandle handle);
+ }
+
+ public final class SavedStateHandle {
+ ctor public SavedStateHandle(java.util.Map<java.lang.String,?> initialState);
+ ctor public SavedStateHandle();
+ method @MainThread public void clearSavedStateProvider(String key);
+ method @MainThread public operator boolean contains(String key);
+ method @MainThread public operator <T> T? get(String key);
+ method @MainThread public <T> androidx.lifecycle.MutableLiveData<T> getLiveData(String key);
+ method @MainThread public <T> androidx.lifecycle.MutableLiveData<T> getLiveData(String key, T? initialValue);
+ method @MainThread public <T> kotlinx.coroutines.flow.StateFlow<T> getStateFlow(String key, T? initialValue);
+ method @MainThread public java.util.Set<java.lang.String> keys();
+ method @MainThread public <T> T? remove(String key);
+ method @MainThread public operator <T> void set(String key, T? value);
+ method @MainThread public void setSavedStateProvider(String key, androidx.savedstate.SavedStateRegistry.SavedStateProvider provider);
+ field public static final androidx.lifecycle.SavedStateHandle.Companion Companion;
+ }
+
+ public static final class SavedStateHandle.Companion {
+ }
+
+ public final class SavedStateHandleSupport {
+ method @MainThread public static androidx.lifecycle.SavedStateHandle createSavedStateHandle(androidx.lifecycle.viewmodel.CreationExtras);
+ method @MainThread public static <T extends androidx.savedstate.SavedStateRegistryOwner & androidx.lifecycle.ViewModelStoreOwner> void enableSavedStateHandles(T);
+ field public static final androidx.lifecycle.viewmodel.CreationExtras.Key<android.os.Bundle> DEFAULT_ARGS_KEY;
+ field public static final androidx.lifecycle.viewmodel.CreationExtras.Key<androidx.savedstate.SavedStateRegistryOwner> SAVED_STATE_REGISTRY_OWNER_KEY;
+ field public static final androidx.lifecycle.viewmodel.CreationExtras.Key<androidx.lifecycle.ViewModelStoreOwner> VIEW_MODEL_STORE_OWNER_KEY;
+ }
+
+ public final class SavedStateViewModelFactory implements androidx.lifecycle.ViewModelProvider.Factory {
+ ctor public SavedStateViewModelFactory();
+ ctor public SavedStateViewModelFactory(android.app.Application? application, androidx.savedstate.SavedStateRegistryOwner owner);
+ ctor public SavedStateViewModelFactory(android.app.Application? application, androidx.savedstate.SavedStateRegistryOwner owner, android.os.Bundle? defaultArgs);
+ method public <T extends androidx.lifecycle.ViewModel> T create(String key, Class<T> modelClass);
+ }
+
+}
+
diff --git a/webkit/webkit/api/res-1.6.0-beta02.txt b/lifecycle/lifecycle-viewmodel-savedstate/api/res-2.6.0-beta02.txt
similarity index 100%
copy from webkit/webkit/api/res-1.6.0-beta02.txt
copy to lifecycle/lifecycle-viewmodel-savedstate/api/res-2.6.0-beta02.txt
diff --git a/lifecycle/lifecycle-viewmodel-savedstate/api/restricted_2.6.0-beta02.txt b/lifecycle/lifecycle-viewmodel-savedstate/api/restricted_2.6.0-beta02.txt
new file mode 100644
index 0000000..c030c8a
--- /dev/null
+++ b/lifecycle/lifecycle-viewmodel-savedstate/api/restricted_2.6.0-beta02.txt
@@ -0,0 +1,45 @@
+// Signature format: 4.0
+package androidx.lifecycle {
+
+ public abstract class AbstractSavedStateViewModelFactory implements androidx.lifecycle.ViewModelProvider.Factory {
+ ctor public AbstractSavedStateViewModelFactory();
+ ctor public AbstractSavedStateViewModelFactory(androidx.savedstate.SavedStateRegistryOwner owner, android.os.Bundle? defaultArgs);
+ method protected abstract <T extends androidx.lifecycle.ViewModel> T create(String key, Class<T> modelClass, androidx.lifecycle.SavedStateHandle handle);
+ }
+
+ public final class SavedStateHandle {
+ ctor public SavedStateHandle(java.util.Map<java.lang.String,?> initialState);
+ ctor public SavedStateHandle();
+ method @MainThread public void clearSavedStateProvider(String key);
+ method @MainThread public operator boolean contains(String key);
+ method @MainThread public operator <T> T? get(String key);
+ method @MainThread public <T> androidx.lifecycle.MutableLiveData<T> getLiveData(String key);
+ method @MainThread public <T> androidx.lifecycle.MutableLiveData<T> getLiveData(String key, T? initialValue);
+ method @MainThread public <T> kotlinx.coroutines.flow.StateFlow<T> getStateFlow(String key, T? initialValue);
+ method @MainThread public java.util.Set<java.lang.String> keys();
+ method @MainThread public <T> T? remove(String key);
+ method @MainThread public operator <T> void set(String key, T? value);
+ method @MainThread public void setSavedStateProvider(String key, androidx.savedstate.SavedStateRegistry.SavedStateProvider provider);
+ field public static final androidx.lifecycle.SavedStateHandle.Companion Companion;
+ }
+
+ public static final class SavedStateHandle.Companion {
+ }
+
+ public final class SavedStateHandleSupport {
+ method @MainThread public static androidx.lifecycle.SavedStateHandle createSavedStateHandle(androidx.lifecycle.viewmodel.CreationExtras);
+ method @MainThread public static <T extends androidx.savedstate.SavedStateRegistryOwner & androidx.lifecycle.ViewModelStoreOwner> void enableSavedStateHandles(T);
+ field public static final androidx.lifecycle.viewmodel.CreationExtras.Key<android.os.Bundle> DEFAULT_ARGS_KEY;
+ field public static final androidx.lifecycle.viewmodel.CreationExtras.Key<androidx.savedstate.SavedStateRegistryOwner> SAVED_STATE_REGISTRY_OWNER_KEY;
+ field public static final androidx.lifecycle.viewmodel.CreationExtras.Key<androidx.lifecycle.ViewModelStoreOwner> VIEW_MODEL_STORE_OWNER_KEY;
+ }
+
+ public final class SavedStateViewModelFactory implements androidx.lifecycle.ViewModelProvider.Factory {
+ ctor public SavedStateViewModelFactory();
+ ctor public SavedStateViewModelFactory(android.app.Application? application, androidx.savedstate.SavedStateRegistryOwner owner);
+ ctor public SavedStateViewModelFactory(android.app.Application? application, androidx.savedstate.SavedStateRegistryOwner owner, android.os.Bundle? defaultArgs);
+ method public <T extends androidx.lifecycle.ViewModel> T create(String key, Class<T> modelClass);
+ }
+
+}
+
diff --git a/lifecycle/lifecycle-viewmodel/api/2.6.0-beta02.txt b/lifecycle/lifecycle-viewmodel/api/2.6.0-beta02.txt
new file mode 100644
index 0000000..f8457f6
--- /dev/null
+++ b/lifecycle/lifecycle-viewmodel/api/2.6.0-beta02.txt
@@ -0,0 +1,136 @@
+// Signature format: 4.0
+package androidx.lifecycle {
+
+ public class AndroidViewModel extends androidx.lifecycle.ViewModel {
+ ctor public AndroidViewModel(android.app.Application application);
+ method public <T extends android.app.Application> T getApplication();
+ }
+
+ public interface HasDefaultViewModelProviderFactory {
+ method public default androidx.lifecycle.viewmodel.CreationExtras getDefaultViewModelCreationExtras();
+ method public androidx.lifecycle.ViewModelProvider.Factory getDefaultViewModelProviderFactory();
+ property public default androidx.lifecycle.viewmodel.CreationExtras defaultViewModelCreationExtras;
+ property public abstract androidx.lifecycle.ViewModelProvider.Factory defaultViewModelProviderFactory;
+ }
+
+ public abstract class ViewModel {
+ ctor public ViewModel();
+ ctor public ViewModel(java.io.Closeable!...);
+ method public void addCloseable(java.io.Closeable);
+ 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, optional kotlin.jvm.functions.Function0<? extends androidx.lifecycle.viewmodel.CreationExtras> extrasProducer);
+ 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, optional androidx.lifecycle.viewmodel.CreationExtras defaultCreationExtras);
+ ctor public ViewModelProvider(androidx.lifecycle.ViewModelStore store, androidx.lifecycle.ViewModelProvider.Factory factory);
+ ctor public ViewModelProvider(androidx.lifecycle.ViewModelStoreOwner owner);
+ ctor public ViewModelProvider(androidx.lifecycle.ViewModelStoreOwner owner, androidx.lifecycle.ViewModelProvider.Factory factory);
+ method @MainThread public operator <T extends androidx.lifecycle.ViewModel> T get(Class<T> modelClass);
+ method @MainThread public operator <T extends androidx.lifecycle.ViewModel> T get(String key, Class<T> modelClass);
+ }
+
+ public static class ViewModelProvider.AndroidViewModelFactory extends androidx.lifecycle.ViewModelProvider.NewInstanceFactory {
+ ctor public ViewModelProvider.AndroidViewModelFactory();
+ ctor public ViewModelProvider.AndroidViewModelFactory(android.app.Application application);
+ method public static final androidx.lifecycle.ViewModelProvider.AndroidViewModelFactory getInstance(android.app.Application application);
+ field public static final androidx.lifecycle.viewmodel.CreationExtras.Key<android.app.Application> APPLICATION_KEY;
+ field public static final androidx.lifecycle.ViewModelProvider.AndroidViewModelFactory.Companion Companion;
+ }
+
+ public static final class ViewModelProvider.AndroidViewModelFactory.Companion {
+ method public androidx.lifecycle.ViewModelProvider.AndroidViewModelFactory getInstance(android.app.Application application);
+ }
+
+ public static interface ViewModelProvider.Factory {
+ method public default <T extends androidx.lifecycle.ViewModel> T create(Class<T> modelClass);
+ method public default <T extends androidx.lifecycle.ViewModel> T create(Class<T> modelClass, androidx.lifecycle.viewmodel.CreationExtras extras);
+ method public default static androidx.lifecycle.ViewModelProvider.Factory from(androidx.lifecycle.viewmodel.ViewModelInitializer<?>... initializers);
+ field public static final androidx.lifecycle.ViewModelProvider.Factory.Companion Companion;
+ }
+
+ public static final class ViewModelProvider.Factory.Companion {
+ method public androidx.lifecycle.ViewModelProvider.Factory from(androidx.lifecycle.viewmodel.ViewModelInitializer<?>... initializers);
+ }
+
+ public static class ViewModelProvider.NewInstanceFactory implements androidx.lifecycle.ViewModelProvider.Factory {
+ ctor public ViewModelProvider.NewInstanceFactory();
+ field public static final androidx.lifecycle.ViewModelProvider.NewInstanceFactory.Companion Companion;
+ field public static final androidx.lifecycle.viewmodel.CreationExtras.Key<java.lang.String> VIEW_MODEL_KEY;
+ }
+
+ public static final class ViewModelProvider.NewInstanceFactory.Companion {
+ }
+
+ public final class ViewModelProviderGetKt {
+ 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();
+ }
+
+ public interface ViewModelStoreOwner {
+ method public androidx.lifecycle.ViewModelStore getViewModelStore();
+ property public abstract androidx.lifecycle.ViewModelStore viewModelStore;
+ }
+
+ public final class ViewTreeViewModelKt {
+ method @Deprecated public static androidx.lifecycle.ViewModelStoreOwner? findViewTreeViewModelStoreOwner(android.view.View view);
+ }
+
+ public final class ViewTreeViewModelStoreOwner {
+ method public static androidx.lifecycle.ViewModelStoreOwner? get(android.view.View);
+ method public static void set(android.view.View, androidx.lifecycle.ViewModelStoreOwner? viewModelStoreOwner);
+ }
+
+}
+
+package androidx.lifecycle.viewmodel {
+
+ public abstract class CreationExtras {
+ method public abstract operator <T> T? get(androidx.lifecycle.viewmodel.CreationExtras.Key<T> key);
+ }
+
+ public static final class CreationExtras.Empty extends androidx.lifecycle.viewmodel.CreationExtras {
+ method public <T> T? get(androidx.lifecycle.viewmodel.CreationExtras.Key<T> key);
+ field public static final androidx.lifecycle.viewmodel.CreationExtras.Empty INSTANCE;
+ }
+
+ public static interface CreationExtras.Key<T> {
+ }
+
+ @androidx.lifecycle.viewmodel.ViewModelFactoryDsl public final class InitializerViewModelFactoryBuilder {
+ ctor public InitializerViewModelFactoryBuilder();
+ method public <T extends androidx.lifecycle.ViewModel> void addInitializer(kotlin.reflect.KClass<T> clazz, kotlin.jvm.functions.Function1<? super androidx.lifecycle.viewmodel.CreationExtras,? extends T> initializer);
+ method public androidx.lifecycle.ViewModelProvider.Factory build();
+ }
+
+ public final class InitializerViewModelFactoryKt {
+ method public static inline <reified VM extends androidx.lifecycle.ViewModel> void initializer(androidx.lifecycle.viewmodel.InitializerViewModelFactoryBuilder, kotlin.jvm.functions.Function1<? super androidx.lifecycle.viewmodel.CreationExtras,? extends VM> initializer);
+ method public static inline androidx.lifecycle.ViewModelProvider.Factory viewModelFactory(kotlin.jvm.functions.Function1<? super androidx.lifecycle.viewmodel.InitializerViewModelFactoryBuilder,kotlin.Unit> builder);
+ }
+
+ public final class MutableCreationExtras extends androidx.lifecycle.viewmodel.CreationExtras {
+ ctor public MutableCreationExtras(optional androidx.lifecycle.viewmodel.CreationExtras initialExtras);
+ method public <T> T? get(androidx.lifecycle.viewmodel.CreationExtras.Key<T> key);
+ method public operator <T> void set(androidx.lifecycle.viewmodel.CreationExtras.Key<T> key, T? t);
+ }
+
+ @kotlin.DslMarker public @interface ViewModelFactoryDsl {
+ }
+
+ public final class ViewModelInitializer<T extends androidx.lifecycle.ViewModel> {
+ ctor public ViewModelInitializer(Class<T> clazz, kotlin.jvm.functions.Function1<? super androidx.lifecycle.viewmodel.CreationExtras,? extends T> initializer);
+ }
+
+}
+
diff --git a/lifecycle/lifecycle-viewmodel/api/public_plus_experimental_2.6.0-beta02.txt b/lifecycle/lifecycle-viewmodel/api/public_plus_experimental_2.6.0-beta02.txt
new file mode 100644
index 0000000..f8457f6
--- /dev/null
+++ b/lifecycle/lifecycle-viewmodel/api/public_plus_experimental_2.6.0-beta02.txt
@@ -0,0 +1,136 @@
+// Signature format: 4.0
+package androidx.lifecycle {
+
+ public class AndroidViewModel extends androidx.lifecycle.ViewModel {
+ ctor public AndroidViewModel(android.app.Application application);
+ method public <T extends android.app.Application> T getApplication();
+ }
+
+ public interface HasDefaultViewModelProviderFactory {
+ method public default androidx.lifecycle.viewmodel.CreationExtras getDefaultViewModelCreationExtras();
+ method public androidx.lifecycle.ViewModelProvider.Factory getDefaultViewModelProviderFactory();
+ property public default androidx.lifecycle.viewmodel.CreationExtras defaultViewModelCreationExtras;
+ property public abstract androidx.lifecycle.ViewModelProvider.Factory defaultViewModelProviderFactory;
+ }
+
+ public abstract class ViewModel {
+ ctor public ViewModel();
+ ctor public ViewModel(java.io.Closeable!...);
+ method public void addCloseable(java.io.Closeable);
+ 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, optional kotlin.jvm.functions.Function0<? extends androidx.lifecycle.viewmodel.CreationExtras> extrasProducer);
+ 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, optional androidx.lifecycle.viewmodel.CreationExtras defaultCreationExtras);
+ ctor public ViewModelProvider(androidx.lifecycle.ViewModelStore store, androidx.lifecycle.ViewModelProvider.Factory factory);
+ ctor public ViewModelProvider(androidx.lifecycle.ViewModelStoreOwner owner);
+ ctor public ViewModelProvider(androidx.lifecycle.ViewModelStoreOwner owner, androidx.lifecycle.ViewModelProvider.Factory factory);
+ method @MainThread public operator <T extends androidx.lifecycle.ViewModel> T get(Class<T> modelClass);
+ method @MainThread public operator <T extends androidx.lifecycle.ViewModel> T get(String key, Class<T> modelClass);
+ }
+
+ public static class ViewModelProvider.AndroidViewModelFactory extends androidx.lifecycle.ViewModelProvider.NewInstanceFactory {
+ ctor public ViewModelProvider.AndroidViewModelFactory();
+ ctor public ViewModelProvider.AndroidViewModelFactory(android.app.Application application);
+ method public static final androidx.lifecycle.ViewModelProvider.AndroidViewModelFactory getInstance(android.app.Application application);
+ field public static final androidx.lifecycle.viewmodel.CreationExtras.Key<android.app.Application> APPLICATION_KEY;
+ field public static final androidx.lifecycle.ViewModelProvider.AndroidViewModelFactory.Companion Companion;
+ }
+
+ public static final class ViewModelProvider.AndroidViewModelFactory.Companion {
+ method public androidx.lifecycle.ViewModelProvider.AndroidViewModelFactory getInstance(android.app.Application application);
+ }
+
+ public static interface ViewModelProvider.Factory {
+ method public default <T extends androidx.lifecycle.ViewModel> T create(Class<T> modelClass);
+ method public default <T extends androidx.lifecycle.ViewModel> T create(Class<T> modelClass, androidx.lifecycle.viewmodel.CreationExtras extras);
+ method public default static androidx.lifecycle.ViewModelProvider.Factory from(androidx.lifecycle.viewmodel.ViewModelInitializer<?>... initializers);
+ field public static final androidx.lifecycle.ViewModelProvider.Factory.Companion Companion;
+ }
+
+ public static final class ViewModelProvider.Factory.Companion {
+ method public androidx.lifecycle.ViewModelProvider.Factory from(androidx.lifecycle.viewmodel.ViewModelInitializer<?>... initializers);
+ }
+
+ public static class ViewModelProvider.NewInstanceFactory implements androidx.lifecycle.ViewModelProvider.Factory {
+ ctor public ViewModelProvider.NewInstanceFactory();
+ field public static final androidx.lifecycle.ViewModelProvider.NewInstanceFactory.Companion Companion;
+ field public static final androidx.lifecycle.viewmodel.CreationExtras.Key<java.lang.String> VIEW_MODEL_KEY;
+ }
+
+ public static final class ViewModelProvider.NewInstanceFactory.Companion {
+ }
+
+ public final class ViewModelProviderGetKt {
+ 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();
+ }
+
+ public interface ViewModelStoreOwner {
+ method public androidx.lifecycle.ViewModelStore getViewModelStore();
+ property public abstract androidx.lifecycle.ViewModelStore viewModelStore;
+ }
+
+ public final class ViewTreeViewModelKt {
+ method @Deprecated public static androidx.lifecycle.ViewModelStoreOwner? findViewTreeViewModelStoreOwner(android.view.View view);
+ }
+
+ public final class ViewTreeViewModelStoreOwner {
+ method public static androidx.lifecycle.ViewModelStoreOwner? get(android.view.View);
+ method public static void set(android.view.View, androidx.lifecycle.ViewModelStoreOwner? viewModelStoreOwner);
+ }
+
+}
+
+package androidx.lifecycle.viewmodel {
+
+ public abstract class CreationExtras {
+ method public abstract operator <T> T? get(androidx.lifecycle.viewmodel.CreationExtras.Key<T> key);
+ }
+
+ public static final class CreationExtras.Empty extends androidx.lifecycle.viewmodel.CreationExtras {
+ method public <T> T? get(androidx.lifecycle.viewmodel.CreationExtras.Key<T> key);
+ field public static final androidx.lifecycle.viewmodel.CreationExtras.Empty INSTANCE;
+ }
+
+ public static interface CreationExtras.Key<T> {
+ }
+
+ @androidx.lifecycle.viewmodel.ViewModelFactoryDsl public final class InitializerViewModelFactoryBuilder {
+ ctor public InitializerViewModelFactoryBuilder();
+ method public <T extends androidx.lifecycle.ViewModel> void addInitializer(kotlin.reflect.KClass<T> clazz, kotlin.jvm.functions.Function1<? super androidx.lifecycle.viewmodel.CreationExtras,? extends T> initializer);
+ method public androidx.lifecycle.ViewModelProvider.Factory build();
+ }
+
+ public final class InitializerViewModelFactoryKt {
+ method public static inline <reified VM extends androidx.lifecycle.ViewModel> void initializer(androidx.lifecycle.viewmodel.InitializerViewModelFactoryBuilder, kotlin.jvm.functions.Function1<? super androidx.lifecycle.viewmodel.CreationExtras,? extends VM> initializer);
+ method public static inline androidx.lifecycle.ViewModelProvider.Factory viewModelFactory(kotlin.jvm.functions.Function1<? super androidx.lifecycle.viewmodel.InitializerViewModelFactoryBuilder,kotlin.Unit> builder);
+ }
+
+ public final class MutableCreationExtras extends androidx.lifecycle.viewmodel.CreationExtras {
+ ctor public MutableCreationExtras(optional androidx.lifecycle.viewmodel.CreationExtras initialExtras);
+ method public <T> T? get(androidx.lifecycle.viewmodel.CreationExtras.Key<T> key);
+ method public operator <T> void set(androidx.lifecycle.viewmodel.CreationExtras.Key<T> key, T? t);
+ }
+
+ @kotlin.DslMarker public @interface ViewModelFactoryDsl {
+ }
+
+ public final class ViewModelInitializer<T extends androidx.lifecycle.ViewModel> {
+ ctor public ViewModelInitializer(Class<T> clazz, kotlin.jvm.functions.Function1<? super androidx.lifecycle.viewmodel.CreationExtras,? extends T> initializer);
+ }
+
+}
+
diff --git a/webkit/webkit/api/res-1.6.0-beta02.txt b/lifecycle/lifecycle-viewmodel/api/res-2.6.0-beta02.txt
similarity index 100%
copy from webkit/webkit/api/res-1.6.0-beta02.txt
copy to lifecycle/lifecycle-viewmodel/api/res-2.6.0-beta02.txt
diff --git a/lifecycle/lifecycle-viewmodel/api/restricted_2.6.0-beta02.txt b/lifecycle/lifecycle-viewmodel/api/restricted_2.6.0-beta02.txt
new file mode 100644
index 0000000..f8457f6
--- /dev/null
+++ b/lifecycle/lifecycle-viewmodel/api/restricted_2.6.0-beta02.txt
@@ -0,0 +1,136 @@
+// Signature format: 4.0
+package androidx.lifecycle {
+
+ public class AndroidViewModel extends androidx.lifecycle.ViewModel {
+ ctor public AndroidViewModel(android.app.Application application);
+ method public <T extends android.app.Application> T getApplication();
+ }
+
+ public interface HasDefaultViewModelProviderFactory {
+ method public default androidx.lifecycle.viewmodel.CreationExtras getDefaultViewModelCreationExtras();
+ method public androidx.lifecycle.ViewModelProvider.Factory getDefaultViewModelProviderFactory();
+ property public default androidx.lifecycle.viewmodel.CreationExtras defaultViewModelCreationExtras;
+ property public abstract androidx.lifecycle.ViewModelProvider.Factory defaultViewModelProviderFactory;
+ }
+
+ public abstract class ViewModel {
+ ctor public ViewModel();
+ ctor public ViewModel(java.io.Closeable!...);
+ method public void addCloseable(java.io.Closeable);
+ 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, optional kotlin.jvm.functions.Function0<? extends androidx.lifecycle.viewmodel.CreationExtras> extrasProducer);
+ 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, optional androidx.lifecycle.viewmodel.CreationExtras defaultCreationExtras);
+ ctor public ViewModelProvider(androidx.lifecycle.ViewModelStore store, androidx.lifecycle.ViewModelProvider.Factory factory);
+ ctor public ViewModelProvider(androidx.lifecycle.ViewModelStoreOwner owner);
+ ctor public ViewModelProvider(androidx.lifecycle.ViewModelStoreOwner owner, androidx.lifecycle.ViewModelProvider.Factory factory);
+ method @MainThread public operator <T extends androidx.lifecycle.ViewModel> T get(Class<T> modelClass);
+ method @MainThread public operator <T extends androidx.lifecycle.ViewModel> T get(String key, Class<T> modelClass);
+ }
+
+ public static class ViewModelProvider.AndroidViewModelFactory extends androidx.lifecycle.ViewModelProvider.NewInstanceFactory {
+ ctor public ViewModelProvider.AndroidViewModelFactory();
+ ctor public ViewModelProvider.AndroidViewModelFactory(android.app.Application application);
+ method public static final androidx.lifecycle.ViewModelProvider.AndroidViewModelFactory getInstance(android.app.Application application);
+ field public static final androidx.lifecycle.viewmodel.CreationExtras.Key<android.app.Application> APPLICATION_KEY;
+ field public static final androidx.lifecycle.ViewModelProvider.AndroidViewModelFactory.Companion Companion;
+ }
+
+ public static final class ViewModelProvider.AndroidViewModelFactory.Companion {
+ method public androidx.lifecycle.ViewModelProvider.AndroidViewModelFactory getInstance(android.app.Application application);
+ }
+
+ public static interface ViewModelProvider.Factory {
+ method public default <T extends androidx.lifecycle.ViewModel> T create(Class<T> modelClass);
+ method public default <T extends androidx.lifecycle.ViewModel> T create(Class<T> modelClass, androidx.lifecycle.viewmodel.CreationExtras extras);
+ method public default static androidx.lifecycle.ViewModelProvider.Factory from(androidx.lifecycle.viewmodel.ViewModelInitializer<?>... initializers);
+ field public static final androidx.lifecycle.ViewModelProvider.Factory.Companion Companion;
+ }
+
+ public static final class ViewModelProvider.Factory.Companion {
+ method public androidx.lifecycle.ViewModelProvider.Factory from(androidx.lifecycle.viewmodel.ViewModelInitializer<?>... initializers);
+ }
+
+ public static class ViewModelProvider.NewInstanceFactory implements androidx.lifecycle.ViewModelProvider.Factory {
+ ctor public ViewModelProvider.NewInstanceFactory();
+ field public static final androidx.lifecycle.ViewModelProvider.NewInstanceFactory.Companion Companion;
+ field public static final androidx.lifecycle.viewmodel.CreationExtras.Key<java.lang.String> VIEW_MODEL_KEY;
+ }
+
+ public static final class ViewModelProvider.NewInstanceFactory.Companion {
+ }
+
+ public final class ViewModelProviderGetKt {
+ 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();
+ }
+
+ public interface ViewModelStoreOwner {
+ method public androidx.lifecycle.ViewModelStore getViewModelStore();
+ property public abstract androidx.lifecycle.ViewModelStore viewModelStore;
+ }
+
+ public final class ViewTreeViewModelKt {
+ method @Deprecated public static androidx.lifecycle.ViewModelStoreOwner? findViewTreeViewModelStoreOwner(android.view.View view);
+ }
+
+ public final class ViewTreeViewModelStoreOwner {
+ method public static androidx.lifecycle.ViewModelStoreOwner? get(android.view.View);
+ method public static void set(android.view.View, androidx.lifecycle.ViewModelStoreOwner? viewModelStoreOwner);
+ }
+
+}
+
+package androidx.lifecycle.viewmodel {
+
+ public abstract class CreationExtras {
+ method public abstract operator <T> T? get(androidx.lifecycle.viewmodel.CreationExtras.Key<T> key);
+ }
+
+ public static final class CreationExtras.Empty extends androidx.lifecycle.viewmodel.CreationExtras {
+ method public <T> T? get(androidx.lifecycle.viewmodel.CreationExtras.Key<T> key);
+ field public static final androidx.lifecycle.viewmodel.CreationExtras.Empty INSTANCE;
+ }
+
+ public static interface CreationExtras.Key<T> {
+ }
+
+ @androidx.lifecycle.viewmodel.ViewModelFactoryDsl public final class InitializerViewModelFactoryBuilder {
+ ctor public InitializerViewModelFactoryBuilder();
+ method public <T extends androidx.lifecycle.ViewModel> void addInitializer(kotlin.reflect.KClass<T> clazz, kotlin.jvm.functions.Function1<? super androidx.lifecycle.viewmodel.CreationExtras,? extends T> initializer);
+ method public androidx.lifecycle.ViewModelProvider.Factory build();
+ }
+
+ public final class InitializerViewModelFactoryKt {
+ method public static inline <reified VM extends androidx.lifecycle.ViewModel> void initializer(androidx.lifecycle.viewmodel.InitializerViewModelFactoryBuilder, kotlin.jvm.functions.Function1<? super androidx.lifecycle.viewmodel.CreationExtras,? extends VM> initializer);
+ method public static inline androidx.lifecycle.ViewModelProvider.Factory viewModelFactory(kotlin.jvm.functions.Function1<? super androidx.lifecycle.viewmodel.InitializerViewModelFactoryBuilder,kotlin.Unit> builder);
+ }
+
+ public final class MutableCreationExtras extends androidx.lifecycle.viewmodel.CreationExtras {
+ ctor public MutableCreationExtras(optional androidx.lifecycle.viewmodel.CreationExtras initialExtras);
+ method public <T> T? get(androidx.lifecycle.viewmodel.CreationExtras.Key<T> key);
+ method public operator <T> void set(androidx.lifecycle.viewmodel.CreationExtras.Key<T> key, T? t);
+ }
+
+ @kotlin.DslMarker public @interface ViewModelFactoryDsl {
+ }
+
+ public final class ViewModelInitializer<T extends androidx.lifecycle.ViewModel> {
+ ctor public ViewModelInitializer(Class<T> clazz, kotlin.jvm.functions.Function1<? super androidx.lifecycle.viewmodel.CreationExtras,? extends T> initializer);
+ }
+
+}
+
diff --git a/mediarouter/mediarouter/api/current.txt b/mediarouter/mediarouter/api/current.txt
index b1cf094..e1077a5 100644
--- a/mediarouter/mediarouter/api/current.txt
+++ b/mediarouter/mediarouter/api/current.txt
@@ -172,6 +172,7 @@
method public static androidx.mediarouter.media.MediaRouteDescriptor? fromBundle(android.os.Bundle?);
method public int getConnectionState();
method public java.util.List<android.content.IntentFilter!> getControlFilters();
+ method public java.util.Set<java.lang.String!> getDeduplicationIds();
method public String? getDescription();
method public int getDeviceType();
method public android.os.Bundle? getExtras();
@@ -201,6 +202,7 @@
method public androidx.mediarouter.media.MediaRouteDescriptor.Builder setCanDisconnect(boolean);
method @Deprecated public androidx.mediarouter.media.MediaRouteDescriptor.Builder setConnecting(boolean);
method public androidx.mediarouter.media.MediaRouteDescriptor.Builder setConnectionState(int);
+ method public androidx.mediarouter.media.MediaRouteDescriptor.Builder setDeduplicationIds(java.util.Set<java.lang.String!>);
method public androidx.mediarouter.media.MediaRouteDescriptor.Builder setDescription(String?);
method public androidx.mediarouter.media.MediaRouteDescriptor.Builder setDeviceType(int);
method public androidx.mediarouter.media.MediaRouteDescriptor.Builder setEnabled(boolean);
diff --git a/mediarouter/mediarouter/api/public_plus_experimental_current.txt b/mediarouter/mediarouter/api/public_plus_experimental_current.txt
index b1cf094..e1077a5 100644
--- a/mediarouter/mediarouter/api/public_plus_experimental_current.txt
+++ b/mediarouter/mediarouter/api/public_plus_experimental_current.txt
@@ -172,6 +172,7 @@
method public static androidx.mediarouter.media.MediaRouteDescriptor? fromBundle(android.os.Bundle?);
method public int getConnectionState();
method public java.util.List<android.content.IntentFilter!> getControlFilters();
+ method public java.util.Set<java.lang.String!> getDeduplicationIds();
method public String? getDescription();
method public int getDeviceType();
method public android.os.Bundle? getExtras();
@@ -201,6 +202,7 @@
method public androidx.mediarouter.media.MediaRouteDescriptor.Builder setCanDisconnect(boolean);
method @Deprecated public androidx.mediarouter.media.MediaRouteDescriptor.Builder setConnecting(boolean);
method public androidx.mediarouter.media.MediaRouteDescriptor.Builder setConnectionState(int);
+ method public androidx.mediarouter.media.MediaRouteDescriptor.Builder setDeduplicationIds(java.util.Set<java.lang.String!>);
method public androidx.mediarouter.media.MediaRouteDescriptor.Builder setDescription(String?);
method public androidx.mediarouter.media.MediaRouteDescriptor.Builder setDeviceType(int);
method public androidx.mediarouter.media.MediaRouteDescriptor.Builder setEnabled(boolean);
diff --git a/mediarouter/mediarouter/api/restricted_current.txt b/mediarouter/mediarouter/api/restricted_current.txt
index b1cf094..e1077a5 100644
--- a/mediarouter/mediarouter/api/restricted_current.txt
+++ b/mediarouter/mediarouter/api/restricted_current.txt
@@ -172,6 +172,7 @@
method public static androidx.mediarouter.media.MediaRouteDescriptor? fromBundle(android.os.Bundle?);
method public int getConnectionState();
method public java.util.List<android.content.IntentFilter!> getControlFilters();
+ method public java.util.Set<java.lang.String!> getDeduplicationIds();
method public String? getDescription();
method public int getDeviceType();
method public android.os.Bundle? getExtras();
@@ -201,6 +202,7 @@
method public androidx.mediarouter.media.MediaRouteDescriptor.Builder setCanDisconnect(boolean);
method @Deprecated public androidx.mediarouter.media.MediaRouteDescriptor.Builder setConnecting(boolean);
method public androidx.mediarouter.media.MediaRouteDescriptor.Builder setConnectionState(int);
+ method public androidx.mediarouter.media.MediaRouteDescriptor.Builder setDeduplicationIds(java.util.Set<java.lang.String!>);
method public androidx.mediarouter.media.MediaRouteDescriptor.Builder setDescription(String?);
method public androidx.mediarouter.media.MediaRouteDescriptor.Builder setDeviceType(int);
method public androidx.mediarouter.media.MediaRouteDescriptor.Builder setEnabled(boolean);
diff --git a/mediarouter/mediarouter/build.gradle b/mediarouter/mediarouter/build.gradle
index fcaf016..e9e3b8d 100644
--- a/mediarouter/mediarouter/build.gradle
+++ b/mediarouter/mediarouter/build.gradle
@@ -25,11 +25,12 @@
api("androidx.media:media:1.4.1")
api(libs.guavaListenableFuture)
- implementation("androidx.core:core:1.6.0")
+ implementation("androidx.core:core:1.8.0")
implementation("androidx.appcompat:appcompat:1.1.0")
implementation("androidx.palette:palette:1.0.0")
implementation("androidx.recyclerview:recyclerview:1.1.0")
implementation("androidx.appcompat:appcompat-resources:1.2.0")
+ implementation "androidx.annotation:annotation-experimental:1.3.0"
testImplementation(libs.junit)
testImplementation(libs.testCore)
diff --git a/mediarouter/mediarouter/src/androidTest/java/androidx/mediarouter/media/MediaRouter2UtilsTest.java b/mediarouter/mediarouter/src/androidTest/java/androidx/mediarouter/media/MediaRouter2UtilsTest.java
index ae769ed..5c524fd 100644
--- a/mediarouter/mediarouter/src/androidTest/java/androidx/mediarouter/media/MediaRouter2UtilsTest.java
+++ b/mediarouter/mediarouter/src/androidTest/java/androidx/mediarouter/media/MediaRouter2UtilsTest.java
@@ -16,11 +16,17 @@
package androidx.mediarouter.media;
+import static androidx.mediarouter.media.MediaRouter2Utils.KEY_CONTROL_FILTERS;
+import static androidx.mediarouter.media.MediaRouter2Utils.KEY_DEVICE_TYPE;
+import static androidx.mediarouter.media.MediaRouter2Utils.KEY_EXTRAS;
+
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertTrue;
import android.media.MediaRoute2Info;
import android.os.Build;
+import android.os.Bundle;
import androidx.test.ext.junit.runners.AndroidJUnit4;
import androidx.test.filters.SdkSuppress;
@@ -29,6 +35,9 @@
import org.junit.Test;
import org.junit.runner.RunWith;
+import java.util.ArrayList;
+import java.util.HashSet;
+
/** Test for {@link MediaRouter2Utils}. */
@SmallTest
@SdkSuppress(minSdkVersion = Build.VERSION_CODES.R)
@@ -60,4 +69,45 @@
.build();
assertNull(MediaRouter2Utils.toFwkMediaRoute2Info(descriptorWithEmptyName));
}
+
+ @SdkSuppress(minSdkVersion = Build.VERSION_CODES.UPSIDE_DOWN_CAKE, codeName = "UpsideDownCake")
+ @Test
+ public void toFwkMediaRoute2Info_withDeduplicationIds() {
+ HashSet<String> dedupIds = new HashSet<>();
+ dedupIds.add("dedup_id1");
+ dedupIds.add("dedup_id2");
+ MediaRouteDescriptor descriptor =
+ new MediaRouteDescriptor.Builder(
+ FAKE_MEDIA_ROUTE_DESCRIPTOR_ID, FAKE_MEDIA_ROUTE_DESCRIPTOR_NAME)
+ .setDeduplicationIds(dedupIds)
+ .build();
+ assertTrue(
+ MediaRouter2Utils.toFwkMediaRoute2Info(descriptor)
+ .getDeduplicationIds()
+ .equals(dedupIds));
+ }
+
+ @SdkSuppress(minSdkVersion = Build.VERSION_CODES.UPSIDE_DOWN_CAKE, codeName = "UpsideDownCake")
+ @Test
+ public void toMediaRouteDescriptor_withDeduplicationIds() {
+ HashSet<String> dedupIds = new HashSet<>();
+ dedupIds.add("dedup_id1");
+ dedupIds.add("dedup_id2");
+ // Extras needed to make toMediaRouteDescriptor not return null.
+ Bundle extras = new Bundle();
+ extras.putBundle(KEY_EXTRAS, new Bundle());
+ extras.putInt(KEY_DEVICE_TYPE, MediaRouter.RouteInfo.DEVICE_TYPE_UNKNOWN);
+ extras.putParcelableArrayList(KEY_CONTROL_FILTERS, new ArrayList<>());
+ MediaRoute2Info routeInfo =
+ new MediaRoute2Info.Builder(
+ FAKE_MEDIA_ROUTE_DESCRIPTOR_ID, FAKE_MEDIA_ROUTE_DESCRIPTOR_NAME)
+ .addFeature(MediaRoute2Info.FEATURE_REMOTE_PLAYBACK)
+ .setDeduplicationIds(dedupIds)
+ .setExtras(extras)
+ .build();
+ assertTrue(
+ MediaRouter2Utils.toMediaRouteDescriptor(routeInfo)
+ .getDeduplicationIds()
+ .equals(dedupIds));
+ }
}
diff --git a/mediarouter/mediarouter/src/main/java/androidx/mediarouter/media/MediaRoute2Provider.java b/mediarouter/mediarouter/src/main/java/androidx/mediarouter/media/MediaRoute2Provider.java
index e77626e..73a1ddd 100644
--- a/mediarouter/mediarouter/src/main/java/androidx/mediarouter/media/MediaRoute2Provider.java
+++ b/mediarouter/mediarouter/src/main/java/androidx/mediarouter/media/MediaRoute2Provider.java
@@ -46,7 +46,9 @@
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
+import androidx.annotation.OptIn;
import androidx.annotation.RequiresApi;
+import androidx.core.os.BuildCompat;
import androidx.mediarouter.R;
import androidx.mediarouter.media.MediaRouteProvider.DynamicGroupRouteController.DynamicRouteDescriptor;
import androidx.mediarouter.media.MediaRouter.ControlRequestCallback;
@@ -72,7 +74,7 @@
final Callback mCallback;
final Map<MediaRouter2.RoutingController, GroupRouteController> mControllerMap =
new ArrayMap<>();
- private final MediaRouter2.RouteCallback mRouteCallback = new RouteCallback();
+ private final MediaRouter2.RouteCallback mRouteCallback;
private final MediaRouter2.TransferCallback mTransferCallback = new TransferCallback();
private final MediaRouter2.ControllerCallback mControllerCallback = new ControllerCallback();
private final Handler mHandler;
@@ -81,6 +83,8 @@
private List<MediaRoute2Info> mRoutes = new ArrayList<>();
private Map<String, String> mRouteIdToOriginalRouteIdMap = new ArrayMap<>();
+ @OptIn(markerClass = androidx.core.os.BuildCompat.PrereleaseSdkCheck.class)
+ @SuppressWarnings({"SyntheticAccessor"})
MediaRoute2Provider(@NonNull Context context, @NonNull Callback callback) {
super(context);
mMediaRouter2 = MediaRouter2.getInstance(context);
@@ -88,6 +92,12 @@
mHandler = new Handler(Looper.getMainLooper());
mHandlerExecutor = mHandler::post;
+
+ if (BuildCompat.isAtLeastU()) {
+ mRouteCallback = new RouteCallbackUpsideDownCake();
+ } else {
+ mRouteCallback = new RouteCallback();
+ }
}
@Override
@@ -380,6 +390,14 @@
}
}
+ private class RouteCallbackUpsideDownCake extends MediaRouter2.RouteCallback {
+
+ @Override
+ public void onRoutesUpdated(@NonNull List<MediaRoute2Info> routes) {
+ refreshRoutes();
+ }
+ }
+
private class TransferCallback extends MediaRouter2.TransferCallback {
TransferCallback() {}
diff --git a/mediarouter/mediarouter/src/main/java/androidx/mediarouter/media/MediaRouteDescriptor.java b/mediarouter/mediarouter/src/main/java/androidx/mediarouter/media/MediaRouteDescriptor.java
index 314a72f..bc16e9f 100644
--- a/mediarouter/mediarouter/src/main/java/androidx/mediarouter/media/MediaRouteDescriptor.java
+++ b/mediarouter/mediarouter/src/main/java/androidx/mediarouter/media/MediaRouteDescriptor.java
@@ -31,7 +31,9 @@
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
+import java.util.HashSet;
import java.util.List;
+import java.util.Set;
/**
* Describes the properties of a route.
@@ -65,6 +67,7 @@
static final String KEY_SETTINGS_INTENT = "settingsIntent";
static final String KEY_MIN_CLIENT_VERSION = "minClientVersion";
static final String KEY_MAX_CLIENT_VERSION = "maxClientVersion";
+ static final String KEY_DEDUPLICATION_IDS = "deduplicationIds";
final Bundle mBundle;
List<String> mGroupMemberIds;
@@ -299,6 +302,20 @@
}
/**
+ * Gets the route's deduplication ids.
+ *
+ * <p>Two routes are considered to come from the same receiver device if any of their respective
+ * deduplication ids match.
+ */
+ @NonNull
+ public Set<String> getDeduplicationIds() {
+ ArrayList<String> deduplicationIds = mBundle.getStringArrayList(KEY_DEDUPLICATION_IDS);
+ return deduplicationIds != null
+ ? Collections.unmodifiableSet(new HashSet<>(deduplicationIds))
+ : Collections.emptySet();
+ }
+
+ /**
* Gets the route's presentation display id, or -1 if none.
*/
public int getPresentationDisplayId() {
@@ -767,6 +784,21 @@
}
/**
+ * Sets the route's deduplication ids.
+ *
+ * <p>Two routes are considered to come from the same receiver device if any of their
+ * respective deduplication ids match.
+ *
+ * @param deduplicationIds A set of strings that uniquely identify the receiver device that
+ * backs this route.
+ */
+ @NonNull
+ public Builder setDeduplicationIds(@NonNull Set<String> deduplicationIds) {
+ mBundle.putStringArrayList(KEY_DEDUPLICATION_IDS, new ArrayList<>(deduplicationIds));
+ return this;
+ }
+
+ /**
* Sets the route's presentation display id, or -1 if none.
*/
@NonNull
diff --git a/mediarouter/mediarouter/src/main/java/androidx/mediarouter/media/MediaRouter2Utils.java b/mediarouter/mediarouter/src/main/java/androidx/mediarouter/media/MediaRouter2Utils.java
index 5514799..8ac3e5b 100644
--- a/mediarouter/mediarouter/src/main/java/androidx/mediarouter/media/MediaRouter2Utils.java
+++ b/mediarouter/mediarouter/src/main/java/androidx/mediarouter/media/MediaRouter2Utils.java
@@ -35,9 +35,12 @@
import android.text.TextUtils;
import android.util.ArraySet;
+import androidx.annotation.DoNotInline;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
+import androidx.annotation.OptIn;
import androidx.annotation.RequiresApi;
+import androidx.core.os.BuildCompat;
import java.util.ArrayList;
import java.util.Collection;
@@ -65,6 +68,7 @@
private MediaRouter2Utils() {}
+ @OptIn(markerClass = androidx.core.os.BuildCompat.PrereleaseSdkCheck.class)
@Nullable
public static MediaRoute2Info toFwkMediaRoute2Info(@Nullable MediaRouteDescriptor descriptor) {
if (descriptor == null) {
@@ -88,6 +92,10 @@
//.setClientPackageName(clientMap.get(device.getDeviceId()))
;
+ if (BuildCompat.isAtLeastU()) {
+ Api34Impl.setDeduplicationIds(builder, descriptor.getDeduplicationIds());
+ }
+
switch (descriptor.getDeviceType()) {
case DEVICE_TYPE_TV:
builder.addFeature(FEATURE_REMOTE_VIDEO_PLAYBACK);
@@ -118,6 +126,7 @@
return builder.build();
}
+ @OptIn(markerClass = androidx.core.os.BuildCompat.PrereleaseSdkCheck.class)
@Nullable
public static MediaRouteDescriptor toMediaRouteDescriptor(
@Nullable MediaRoute2Info fwkMediaRoute2Info) {
@@ -135,6 +144,10 @@
.setEnabled(true)
.setCanDisconnect(false);
+ if (BuildCompat.isAtLeastU()) {
+ builder.setDeduplicationIds(Api34Impl.getDeduplicationIds(fwkMediaRoute2Info));
+ }
+
CharSequence description = fwkMediaRoute2Info.getDescription();
if (description != null) {
builder.setDescription(description.toString());
@@ -276,4 +289,19 @@
}
return routeFeature;
}
+
+ @RequiresApi(api = 34)
+ private static final class Api34Impl {
+
+ @DoNotInline
+ public static void setDeduplicationIds(
+ MediaRoute2Info.Builder builder, Set<String> deduplicationIds) {
+ builder.setDeduplicationIds(deduplicationIds);
+ }
+
+ @DoNotInline
+ public static Set<String> getDeduplicationIds(MediaRoute2Info fwkMediaRoute2Info) {
+ return fwkMediaRoute2Info.getDeduplicationIds();
+ }
+ }
}
diff --git a/privacysandbox/ads/ads-adservices-java/src/androidTest/java/androidx/privacysandbox/ads/adservices/java/endtoend/TestUtil.java b/privacysandbox/ads/ads-adservices-java/src/androidTest/java/androidx/privacysandbox/ads/adservices/java/endtoend/TestUtil.java
index 8d5d99a..5502ef7 100644
--- a/privacysandbox/ads/ads-adservices-java/src/androidTest/java/androidx/privacysandbox/ads/adservices/java/endtoend/TestUtil.java
+++ b/privacysandbox/ads/ads-adservices-java/src/androidTest/java/androidx/privacysandbox/ads/adservices/java/endtoend/TestUtil.java
@@ -104,6 +104,14 @@
}
}
+ public void overrideAppSetIdKillSwitch(boolean override) {
+ if (override) {
+ runShellCommand("setprop debug.adservices.appsetid_kill_switch " + false);
+ } else {
+ runShellCommand("setprop debug.adservices.appsetid_kill_switch " + null);
+ }
+ }
+
// Override measurement related kill switch to ignore the effect of actual PH values.
// If isOverride = true, override measurement related kill switch to OFF to allow adservices
// If isOverride = false, override measurement related kill switch to meaningless value so that
diff --git a/privacysandbox/ads/ads-adservices-java/src/androidTest/java/androidx/privacysandbox/ads/adservices/java/endtoend/appsetid/AppSetIdManagerTest.java b/privacysandbox/ads/ads-adservices-java/src/androidTest/java/androidx/privacysandbox/ads/adservices/java/endtoend/appsetid/AppSetIdManagerTest.java
new file mode 100644
index 0000000..88973750
--- /dev/null
+++ b/privacysandbox/ads/ads-adservices-java/src/androidTest/java/androidx/privacysandbox/ads/adservices/java/endtoend/appsetid/AppSetIdManagerTest.java
@@ -0,0 +1,66 @@
+/*
+ * Copyright 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.privacysandbox.ads.adservices.java.endtoend.appsetid;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import androidx.privacysandbox.ads.adservices.appsetid.AppSetId;
+import androidx.privacysandbox.ads.adservices.internal.AdServicesInfo;
+import androidx.privacysandbox.ads.adservices.java.appsetid.AppSetIdManagerFutures;
+import androidx.privacysandbox.ads.adservices.java.endtoend.TestUtil;
+import androidx.test.core.app.ApplicationProvider;
+import androidx.test.platform.app.InstrumentationRegistry;
+
+import org.junit.After;
+import org.junit.Assume;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+
+@RunWith(JUnit4.class)
+// TODO: Consider refactoring so that we're not duplicating code.
+public class AppSetIdManagerTest {
+ private static final String TAG = "AppSetIdManagerTest";
+ TestUtil mTestUtil = new TestUtil(InstrumentationRegistry.getInstrumentation(), TAG);
+
+ @Before
+ public void setup() throws Exception {
+ mTestUtil.overrideAppSetIdKillSwitch(true);
+ mTestUtil.overrideKillSwitches(true);
+ mTestUtil.overrideAllowlists(true);
+ }
+
+ @After
+ public void teardown() {
+ mTestUtil.overrideAppSetIdKillSwitch(false);
+ mTestUtil.overrideKillSwitches(false);
+ mTestUtil.overrideAllowlists(false);
+ }
+
+ @Test
+ public void testAppSetId() throws Exception {
+ // Skip the test if SDK extension 4 is not present.
+ Assume.assumeTrue(AdServicesInfo.INSTANCE.version() >= 4);
+
+ AppSetIdManagerFutures appSetIdManager =
+ AppSetIdManagerFutures.from(ApplicationProvider.getApplicationContext());
+ AppSetId appSetId = appSetIdManager.getAppSetIdAsync().get();
+ assertThat(appSetId.getId()).isNotEmpty();
+ assertThat(appSetId.getScope()).isNotNull();
+ }
+}
diff --git a/privacysandbox/sdkruntime/sdkruntime-client/api/current.txt b/privacysandbox/sdkruntime/sdkruntime-client/api/current.txt
index e6f50d0..5044aaf 100644
--- a/privacysandbox/sdkruntime/sdkruntime-client/api/current.txt
+++ b/privacysandbox/sdkruntime/sdkruntime-client/api/current.txt
@@ -1 +1,16 @@
// Signature format: 4.0
+package androidx.privacysandbox.sdkruntime.client {
+
+ public final class SdkSandboxManagerCompat {
+ method public static androidx.privacysandbox.sdkruntime.client.SdkSandboxManagerCompat from(android.content.Context context);
+ method public java.util.List<androidx.privacysandbox.sdkruntime.core.SandboxedSdkCompat> getSandboxedSdks();
+ method @kotlin.jvm.Throws(exceptionClasses=LoadSdkCompatException::class) public suspend Object? loadSdk(String sdkName, android.os.Bundle params, kotlin.coroutines.Continuation<? super androidx.privacysandbox.sdkruntime.core.SandboxedSdkCompat>) throws androidx.privacysandbox.sdkruntime.core.LoadSdkCompatException;
+ field public static final androidx.privacysandbox.sdkruntime.client.SdkSandboxManagerCompat.Companion Companion;
+ }
+
+ public static final class SdkSandboxManagerCompat.Companion {
+ method public androidx.privacysandbox.sdkruntime.client.SdkSandboxManagerCompat from(android.content.Context context);
+ }
+
+}
+
diff --git a/privacysandbox/sdkruntime/sdkruntime-client/api/public_plus_experimental_current.txt b/privacysandbox/sdkruntime/sdkruntime-client/api/public_plus_experimental_current.txt
index e6f50d0..5044aaf 100644
--- a/privacysandbox/sdkruntime/sdkruntime-client/api/public_plus_experimental_current.txt
+++ b/privacysandbox/sdkruntime/sdkruntime-client/api/public_plus_experimental_current.txt
@@ -1 +1,16 @@
// Signature format: 4.0
+package androidx.privacysandbox.sdkruntime.client {
+
+ public final class SdkSandboxManagerCompat {
+ method public static androidx.privacysandbox.sdkruntime.client.SdkSandboxManagerCompat from(android.content.Context context);
+ method public java.util.List<androidx.privacysandbox.sdkruntime.core.SandboxedSdkCompat> getSandboxedSdks();
+ method @kotlin.jvm.Throws(exceptionClasses=LoadSdkCompatException::class) public suspend Object? loadSdk(String sdkName, android.os.Bundle params, kotlin.coroutines.Continuation<? super androidx.privacysandbox.sdkruntime.core.SandboxedSdkCompat>) throws androidx.privacysandbox.sdkruntime.core.LoadSdkCompatException;
+ field public static final androidx.privacysandbox.sdkruntime.client.SdkSandboxManagerCompat.Companion Companion;
+ }
+
+ public static final class SdkSandboxManagerCompat.Companion {
+ method public androidx.privacysandbox.sdkruntime.client.SdkSandboxManagerCompat from(android.content.Context context);
+ }
+
+}
+
diff --git a/privacysandbox/sdkruntime/sdkruntime-client/api/restricted_current.txt b/privacysandbox/sdkruntime/sdkruntime-client/api/restricted_current.txt
index e6f50d0..5044aaf 100644
--- a/privacysandbox/sdkruntime/sdkruntime-client/api/restricted_current.txt
+++ b/privacysandbox/sdkruntime/sdkruntime-client/api/restricted_current.txt
@@ -1 +1,16 @@
// Signature format: 4.0
+package androidx.privacysandbox.sdkruntime.client {
+
+ public final class SdkSandboxManagerCompat {
+ method public static androidx.privacysandbox.sdkruntime.client.SdkSandboxManagerCompat from(android.content.Context context);
+ method public java.util.List<androidx.privacysandbox.sdkruntime.core.SandboxedSdkCompat> getSandboxedSdks();
+ method @kotlin.jvm.Throws(exceptionClasses=LoadSdkCompatException::class) public suspend Object? loadSdk(String sdkName, android.os.Bundle params, kotlin.coroutines.Continuation<? super androidx.privacysandbox.sdkruntime.core.SandboxedSdkCompat>) throws androidx.privacysandbox.sdkruntime.core.LoadSdkCompatException;
+ field public static final androidx.privacysandbox.sdkruntime.client.SdkSandboxManagerCompat.Companion Companion;
+ }
+
+ public static final class SdkSandboxManagerCompat.Companion {
+ method public androidx.privacysandbox.sdkruntime.client.SdkSandboxManagerCompat from(android.content.Context context);
+ }
+
+}
+
diff --git a/privacysandbox/sdkruntime/sdkruntime-client/build.gradle b/privacysandbox/sdkruntime/sdkruntime-client/build.gradle
index 4ce9b50..ad4f80a 100644
--- a/privacysandbox/sdkruntime/sdkruntime-client/build.gradle
+++ b/privacysandbox/sdkruntime/sdkruntime-client/build.gradle
@@ -24,9 +24,38 @@
dependencies {
api(libs.kotlinStdlib)
+ api(libs.kotlinCoroutinesCore)
+ implementation("androidx.core:core-ktx:1.8.0")
+
+ api project(path: ':privacysandbox:sdkruntime:sdkruntime-core')
+
+ implementation("androidx.core:core:1.8.0")
+
+ testImplementation(libs.junit)
+ testImplementation(libs.truth)
+ testImplementation project(":room:room-compiler-processing-testing")
+
+ // TODO(b/249982004): cleanup dependencies
+ androidTestImplementation(libs.testCore)
+ androidTestImplementation(libs.testExtJunit)
+ androidTestImplementation(libs.testRunner)
+ androidTestImplementation(libs.testRules)
+ androidTestImplementation(libs.truth)
+ androidTestImplementation(libs.junit)
+ androidTestImplementation(project(":internal-testutils-truth")) // for assertThrows
+
+ androidTestImplementation(libs.mockitoCore, excludes.bytebuddy) // DexMaker has it"s own MockMaker
+ androidTestImplementation(libs.dexmakerMockitoInline, excludes.bytebuddy) // DexMaker has it"s own MockMaker
}
android {
+ sourceSets {
+ androidTest {
+ assets {
+ srcDirs += "src/androidTest/assets"
+ }
+ }
+ }
namespace "androidx.privacysandbox.sdkruntime.client"
}
diff --git a/privacysandbox/sdkruntime/sdkruntime-client/src/androidTest/AndroidManifest.xml b/privacysandbox/sdkruntime/sdkruntime-client/src/androidTest/AndroidManifest.xml
new file mode 100644
index 0000000..3e3ea90
--- /dev/null
+++ b/privacysandbox/sdkruntime/sdkruntime-client/src/androidTest/AndroidManifest.xml
@@ -0,0 +1,17 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright 2022 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<manifest xmlns:android="http://schemas.android.com/apk/res/android">
+</manifest>
\ No newline at end of file
diff --git a/privacysandbox/sdkruntime/sdkruntime-client/src/androidTest/assets/RuntimeEnabledSdkTable.xml b/privacysandbox/sdkruntime/sdkruntime-client/src/androidTest/assets/RuntimeEnabledSdkTable.xml
new file mode 100644
index 0000000..d589762
--- /dev/null
+++ b/privacysandbox/sdkruntime/sdkruntime-client/src/androidTest/assets/RuntimeEnabledSdkTable.xml
@@ -0,0 +1,25 @@
+<!--
+ Copyright 2022 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+<runtime-enabled-sdk-table>
+ <runtime-enabled-sdk>
+ <compat-config-path>RuntimeEnabledSdks/V1/CompatSdkConfig.xml</compat-config-path>
+ <package-name>androidx.privacysandbox.sdkruntime.test.v1</package-name>
+ </runtime-enabled-sdk>
+ <runtime-enabled-sdk>
+ <compat-config-path>RuntimeEnabledSdks/InvalidEntryPointSdkConfig.xml</compat-config-path>
+ <package-name>androidx.privacysandbox.sdkruntime.test.invalidEntryPoint</package-name>
+ </runtime-enabled-sdk>
+</runtime-enabled-sdk-table>
\ No newline at end of file
diff --git a/privacysandbox/sdkruntime/sdkruntime-client/src/androidTest/assets/RuntimeEnabledSdks/InvalidEntryPointSdkConfig.xml b/privacysandbox/sdkruntime/sdkruntime-client/src/androidTest/assets/RuntimeEnabledSdks/InvalidEntryPointSdkConfig.xml
new file mode 100644
index 0000000..d28649c
--- /dev/null
+++ b/privacysandbox/sdkruntime/sdkruntime-client/src/androidTest/assets/RuntimeEnabledSdks/InvalidEntryPointSdkConfig.xml
@@ -0,0 +1,19 @@
+<!--
+ Copyright 2022 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+<compat-config>
+ <compat-entrypoint>InvalidEntryPoint</compat-entrypoint>
+ <dex-path>RuntimeEnabledSdks/V1/classes.dex</dex-path>
+</compat-config>
\ No newline at end of file
diff --git a/privacysandbox/sdkruntime/sdkruntime-client/src/androidTest/assets/RuntimeEnabledSdks/RPackage.dex b/privacysandbox/sdkruntime/sdkruntime-client/src/androidTest/assets/RuntimeEnabledSdks/RPackage.dex
new file mode 100644
index 0000000..d4862a1
--- /dev/null
+++ b/privacysandbox/sdkruntime/sdkruntime-client/src/androidTest/assets/RuntimeEnabledSdks/RPackage.dex
Binary files differ
diff --git a/privacysandbox/sdkruntime/sdkruntime-client/src/androidTest/assets/RuntimeEnabledSdks/RPackage.md b/privacysandbox/sdkruntime/sdkruntime-client/src/androidTest/assets/RuntimeEnabledSdks/RPackage.md
new file mode 100644
index 0000000..5c1e2a0
--- /dev/null
+++ b/privacysandbox/sdkruntime/sdkruntime-client/src/androidTest/assets/RuntimeEnabledSdks/RPackage.md
@@ -0,0 +1,8 @@
+RPackage class for testing SDK resource remapping.
+
+RPackage.dex built from:
+
+1) androidx.privacysandbox.sdkruntime.test.RPackage
+ public class RPackage {
+ public static int packageId = 0;
+ }
\ No newline at end of file
diff --git a/privacysandbox/sdkruntime/sdkruntime-client/src/androidTest/assets/RuntimeEnabledSdks/V1/CompatSdkCode.md b/privacysandbox/sdkruntime/sdkruntime-client/src/androidTest/assets/RuntimeEnabledSdks/V1/CompatSdkCode.md
new file mode 100644
index 0000000..a2f1cbf
--- /dev/null
+++ b/privacysandbox/sdkruntime/sdkruntime-client/src/androidTest/assets/RuntimeEnabledSdks/V1/CompatSdkCode.md
@@ -0,0 +1,125 @@
+Test sdk that was built with V1 library.
+
+DO NOT RECOMPILE WITH ANY CHANGES TO LIBRARY CLASSES.
+Main purpose of that provider is to test that old core versions could be loaded by new client.
+
+classes.dex built from:
+
+1) androidx.privacysandbox.sdkruntime.core.Versions
+@Keep
+object Versions {
+
+ const val API_VERSION = 1
+
+ @JvmField
+ var CLIENT_VERSION = -1
+
+ @JvmStatic
+ fun handShake(clientVersion: Int): Int {
+ CLIENT_VERSION = clientVersion
+ return API_VERSION
+ }
+}
+
+2) androidx.privacysandbox.sdkruntime.core.SandboxedSdkProviderCompat
+abstract class SandboxedSdkProviderCompat {
+ var context: Context? = null
+ private set
+
+ fun attachContext(context: Context) {
+ check(this.context == null) { "Context already set" }
+ this.context = context
+ }
+
+ @Throws(LoadSdkCompatException::class)
+ abstract fun onLoadSdk(params: Bundle): SandboxedSdkCompat
+
+ open fun beforeUnloadSdk() {}
+
+ abstract fun getView(
+ windowContext: Context,
+ params: Bundle,
+ width: Int,
+ height: Int
+ ): View
+}
+
+3) androidx.privacysandbox.sdkruntime.core.SandboxedSdkCompat
+sealed class SandboxedSdkCompat {
+
+ abstract fun getInterface(): IBinder?
+
+ private class CompatImpl(private val mInterface: IBinder) : SandboxedSdkCompat() {
+ override fun getInterface(): IBinder? {
+ return mInterface
+ }
+ }
+
+ companion object {
+ @JvmStatic
+ fun create(binder: IBinder): SandboxedSdkCompat {
+ return CompatImpl(binder)
+ }
+ }
+}
+
+4) androidx.privacysandbox.sdkruntime.core.LoadSdkCompatException
+class LoadSdkCompatException : Exception {
+
+ val loadSdkErrorCode: Int
+
+ val extraInformation: Bundle
+
+ @JvmOverloads
+ constructor(
+ loadSdkErrorCode: Int,
+ message: String?,
+ cause: Throwable?,
+ extraInformation: Bundle = Bundle()
+ ) : super(message, cause) {
+ this.loadSdkErrorCode = loadSdkErrorCode
+ this.extraInformation = extraInformation
+ }
+
+ constructor(
+ cause: Throwable,
+ extraInfo: Bundle
+ ) : this(LOAD_SDK_SDK_DEFINED_ERROR, "", cause, extraInfo)
+
+ companion object {
+ const val LOAD_SDK_SDK_DEFINED_ERROR = 102
+ }
+}
+
+5) androidx.privacysandbox.sdkruntime.test.v1.CompatProvider
+class CompatProvider : SandboxedSdkProviderCompat() {
+
+ @JvmField
+ val onLoadSdkBinder = Binder()
+
+ @JvmField
+ var lastOnLoadSdkParams: Bundle? = null
+
+ @JvmField
+ var isBeforeUnloadSdkCalled = false
+
+ @Throws(LoadSdkCompatException::class)
+ override fun onLoadSdk(params: Bundle): SandboxedSdkCompat {
+ lastOnLoadSdkParams = params
+ if (params.getBoolean("needFail", false)) {
+ throw LoadSdkCompatException(RuntimeException(), params)
+ }
+ return SandboxedSdkCompat.create(onLoadSdkBinder)
+ }
+
+ override fun beforeUnloadSdk() {
+ isBeforeUnloadSdkCalled = true
+ }
+
+ override fun getView(
+ windowContext: Context, params: Bundle, width: Int,
+ height: Int
+ ): View {
+ return View(windowContext)
+ }
+}
\ No newline at end of file
diff --git a/privacysandbox/sdkruntime/sdkruntime-client/src/androidTest/assets/RuntimeEnabledSdks/V1/CompatSdkConfig.xml b/privacysandbox/sdkruntime/sdkruntime-client/src/androidTest/assets/RuntimeEnabledSdks/V1/CompatSdkConfig.xml
new file mode 100644
index 0000000..dfeca90
--- /dev/null
+++ b/privacysandbox/sdkruntime/sdkruntime-client/src/androidTest/assets/RuntimeEnabledSdks/V1/CompatSdkConfig.xml
@@ -0,0 +1,20 @@
+<!--
+ Copyright 2022 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+<compat-config>
+ <compat-entrypoint>androidx.privacysandbox.sdkruntime.test.v1.CompatProvider</compat-entrypoint>
+ <dex-path>RuntimeEnabledSdks/V1/classes.dex</dex-path>
+ <java-resources-root-path>RuntimeEnabledSdks/V1/javaresources</java-resources-root-path>
+</compat-config>
\ No newline at end of file
diff --git a/privacysandbox/sdkruntime/sdkruntime-client/src/androidTest/assets/RuntimeEnabledSdks/V1/classes.dex b/privacysandbox/sdkruntime/sdkruntime-client/src/androidTest/assets/RuntimeEnabledSdks/V1/classes.dex
new file mode 100644
index 0000000..a6da7e9
--- /dev/null
+++ b/privacysandbox/sdkruntime/sdkruntime-client/src/androidTest/assets/RuntimeEnabledSdks/V1/classes.dex
Binary files differ
diff --git a/privacysandbox/sdkruntime/sdkruntime-client/src/androidTest/assets/RuntimeEnabledSdks/V1/javaresources/test.txt b/privacysandbox/sdkruntime/sdkruntime-client/src/androidTest/assets/RuntimeEnabledSdks/V1/javaresources/test.txt
new file mode 100644
index 0000000..30d74d2
--- /dev/null
+++ b/privacysandbox/sdkruntime/sdkruntime-client/src/androidTest/assets/RuntimeEnabledSdks/V1/javaresources/test.txt
@@ -0,0 +1 @@
+test
\ No newline at end of file
diff --git a/privacysandbox/sdkruntime/sdkruntime-client/src/androidTest/java/androidx/privacysandbox/sdkruntime/client/SdkSandboxManagerCompatSandboxedTest.kt b/privacysandbox/sdkruntime/sdkruntime-client/src/androidTest/java/androidx/privacysandbox/sdkruntime/client/SdkSandboxManagerCompatSandboxedTest.kt
new file mode 100644
index 0000000..94b694b
--- /dev/null
+++ b/privacysandbox/sdkruntime/sdkruntime-client/src/androidTest/java/androidx/privacysandbox/sdkruntime/client/SdkSandboxManagerCompatSandboxedTest.kt
@@ -0,0 +1,227 @@
+/*
+ * Copyright 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.privacysandbox.sdkruntime.client
+
+import android.annotation.SuppressLint
+import android.app.sdksandbox.LoadSdkException
+import android.app.sdksandbox.SandboxedSdk
+import android.app.sdksandbox.SdkSandboxManager
+import android.content.Context
+import android.os.Binder
+import android.os.Build
+import android.os.Bundle
+import android.os.OutcomeReceiver
+import android.os.ext.SdkExtensions.AD_SERVICES
+import androidx.annotation.RequiresExtension
+import androidx.privacysandbox.sdkruntime.core.AdServicesInfo
+import androidx.privacysandbox.sdkruntime.core.LoadSdkCompatException
+import androidx.test.core.app.ApplicationProvider
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import androidx.test.filters.SdkSuppress
+import androidx.test.filters.SmallTest
+import com.google.common.truth.Truth.assertThat
+import kotlinx.coroutines.runBlocking
+import org.junit.Assert.assertThrows
+import org.junit.Assume.assumeFalse
+import org.junit.Assume.assumeTrue
+import org.junit.Before
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.mockito.ArgumentMatchers.any
+import org.mockito.ArgumentMatchers.eq
+import org.mockito.Mockito
+import org.mockito.Mockito.doAnswer
+import org.mockito.Mockito.verify
+import org.mockito.Mockito.verifyZeroInteractions
+import org.mockito.Mockito.`when`
+import org.mockito.invocation.InvocationOnMock
+
+@SmallTest
+@RunWith(AndroidJUnit4::class)
+// TODO(b/249982507) Test should be rewritten to use real SDK in sandbox instead of mocking manager
+// TODO(b/249981547) Remove suppress after updating to new lint version (b/262251309)
+@SuppressLint("NewApi")
+// TODO(b/262577044) Remove RequiresExtension after extensions support in @SdkSuppress
+@RequiresExtension(extension = AD_SERVICES, version = 4)
+@SdkSuppress(minSdkVersion = Build.VERSION_CODES.TIRAMISU)
+class SdkSandboxManagerCompatSandboxedTest {
+
+ private lateinit var mContext: Context
+
+ @Before
+ fun setUp() {
+ assumeTrue("Requires Sandbox API available", isSandboxApiAvailable())
+ mContext = Mockito.spy(ApplicationProvider.getApplicationContext<Context>())
+ }
+
+ @Test
+ fun loadSdk_whenNoLocalSdkExistsAndSandboxAvailable_delegateToPlatformLoadSdk() {
+ val sdkSandboxManager = mockSandboxManager(mContext)
+ setupLoadSdkAnswer(sdkSandboxManager, SandboxedSdk(Binder()))
+
+ val managerCompat = SdkSandboxManagerCompat.from(mContext)
+ val sdkName = "test"
+ val params = Bundle()
+
+ runBlocking {
+ managerCompat.loadSdk(sdkName, params)
+ }
+
+ verify(sdkSandboxManager).loadSdk(
+ eq(sdkName),
+ eq(params),
+ any(),
+ any()
+ )
+ }
+
+ @Test
+ fun loadSdk_whenNoLocalSdkExistsAndSandboxAvailable_returnResultFromPlatformLoadSdk() {
+ val sdkSandboxManager = mockSandboxManager(mContext)
+
+ val sandboxedSdk = SandboxedSdk(Binder())
+ setupLoadSdkAnswer(sdkSandboxManager, sandboxedSdk)
+
+ val managerCompat = SdkSandboxManagerCompat.from(mContext)
+
+ val result = runBlocking {
+ managerCompat.loadSdk("test", Bundle())
+ }
+
+ assertThat(result.getInterface()).isEqualTo(sandboxedSdk.getInterface())
+ }
+
+ @Test
+ fun loadSdk_whenNoLocalSdkExistsAndSandboxAvailable_rethrowsExceptionFromPlatformLoadSdk() {
+ val sdkSandboxManager = mockSandboxManager(mContext)
+
+ val loadSdkException = LoadSdkException(
+ RuntimeException(),
+ Bundle()
+ )
+ setupLoadSdkAnswer(sdkSandboxManager, loadSdkException)
+
+ val managerCompat = SdkSandboxManagerCompat.from(mContext)
+
+ val result = assertThrows(LoadSdkCompatException::class.java) {
+ runBlocking {
+ managerCompat.loadSdk("test", Bundle())
+ }
+ }
+
+ assertThat(result.cause).isEqualTo(loadSdkException.cause)
+ assertThat(result.extraInformation).isEqualTo(loadSdkException.extraInformation)
+ assertThat(result.loadSdkErrorCode).isEqualTo(loadSdkException.loadSdkErrorCode)
+ }
+
+ @Test
+ fun getSandboxedSdks_whenLoadedSdkListNotAvailable_dontDelegateToSandbox() {
+ assumeFalse("Requires getSandboxedSdks API not available", isSdkListAvailable())
+
+ val sdkSandboxManager = mockSandboxManager(mContext)
+ val managerCompat = SdkSandboxManagerCompat.from(mContext)
+
+ managerCompat.getSandboxedSdks()
+
+ verifyZeroInteractions(sdkSandboxManager)
+ }
+
+ @Test
+ fun getSandboxedSdks_whenLoadedSdkListNotAvailable_returnsEmptyList() {
+ assumeFalse("Requires getSandboxedSdks API not available", isSdkListAvailable())
+
+ // SdkSandboxManagerCompat.from require SandboxManager available for AdServices version >= 4
+ mockSandboxManager(mContext)
+ val managerCompat = SdkSandboxManagerCompat.from(mContext)
+
+ val sandboxedSdks = managerCompat.getSandboxedSdks()
+
+ assertThat(sandboxedSdks).isEmpty()
+ }
+
+ @Test
+ // TODO(b/265295473) Update version check after AdServices V5 finalisation.
+ @SdkSuppress(minSdkVersion = 34, codeName = "UpsideDownCake")
+ fun getSandboxedSdks_whenLoadedSdkListAvailable_returnResultFromPlatformGetSandboxedSdks() {
+ assumeTrue("Requires getSandboxedSdks API available", isSdkListAvailable())
+
+ val sdkSandboxManager = mockSandboxManager(mContext)
+ val sandboxedSdk = SandboxedSdk(Binder())
+ `when`(sdkSandboxManager.sandboxedSdks)
+ .thenReturn(listOf(sandboxedSdk))
+ val managerCompat = SdkSandboxManagerCompat.from(mContext)
+
+ val sandboxedSdks = managerCompat.getSandboxedSdks()
+ assertThat(sandboxedSdks).hasSize(1)
+ val result = sandboxedSdks[0]
+
+ assertThat(result.getInterface())
+ .isEqualTo(sandboxedSdk.getInterface())
+ }
+
+ companion object SandboxApi {
+
+ private fun isSandboxApiAvailable() =
+ AdServicesInfo.version() >= 4
+
+ private fun isSdkListAvailable() =
+ AdServicesInfo.isAtLeastV5()
+
+ private fun mockSandboxManager(spyContext: Context): SdkSandboxManager {
+ val sdkSandboxManager = Mockito.mock(SdkSandboxManager::class.java)
+ `when`(spyContext.getSystemService(SdkSandboxManager::class.java))
+ .thenReturn(sdkSandboxManager)
+ return sdkSandboxManager
+ }
+
+ private fun setupLoadSdkAnswer(
+ sdkSandboxManager: SdkSandboxManager,
+ sandboxedSdk: SandboxedSdk
+ ) {
+ val answer = { args: InvocationOnMock ->
+ val receiver = args.getArgument<OutcomeReceiver<SandboxedSdk, LoadSdkException>>(3)
+ receiver.onResult(sandboxedSdk)
+ null
+ }
+ doAnswer(answer)
+ .`when`(sdkSandboxManager).loadSdk(
+ any(),
+ any(),
+ any(),
+ any()
+ )
+ }
+
+ private fun setupLoadSdkAnswer(
+ sdkSandboxManager: SdkSandboxManager,
+ loadSdkException: LoadSdkException
+ ) {
+ val answer = { args: InvocationOnMock ->
+ val receiver = args.getArgument<OutcomeReceiver<SandboxedSdk, LoadSdkException>>(3)
+ receiver.onError(loadSdkException)
+ null
+ }
+ doAnswer(answer)
+ .`when`(sdkSandboxManager).loadSdk(
+ any(),
+ any(),
+ any(),
+ any()
+ )
+ }
+ }
+}
\ No newline at end of file
diff --git a/privacysandbox/sdkruntime/sdkruntime-client/src/androidTest/java/androidx/privacysandbox/sdkruntime/client/SdkSandboxManagerCompatTest.kt b/privacysandbox/sdkruntime/sdkruntime-client/src/androidTest/java/androidx/privacysandbox/sdkruntime/client/SdkSandboxManagerCompatTest.kt
new file mode 100644
index 0000000..e799baf
--- /dev/null
+++ b/privacysandbox/sdkruntime/sdkruntime-client/src/androidTest/java/androidx/privacysandbox/sdkruntime/client/SdkSandboxManagerCompatTest.kt
@@ -0,0 +1,182 @@
+/*
+ * Copyright 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package androidx.privacysandbox.sdkruntime.client
+
+import android.content.Context
+import android.content.ContextWrapper
+import android.os.Build
+import android.os.Bundle
+import androidx.privacysandbox.sdkruntime.core.AdServicesInfo
+import androidx.privacysandbox.sdkruntime.core.LoadSdkCompatException
+import androidx.privacysandbox.sdkruntime.core.LoadSdkCompatException.Companion.LOAD_SDK_INTERNAL_ERROR
+import androidx.privacysandbox.sdkruntime.core.LoadSdkCompatException.Companion.LOAD_SDK_SDK_DEFINED_ERROR
+import androidx.test.core.app.ApplicationProvider
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import androidx.test.filters.SdkSuppress
+import androidx.test.filters.SmallTest
+import com.google.common.truth.Truth.assertThat
+import kotlinx.coroutines.runBlocking
+import org.junit.Assert.assertThrows
+import org.junit.Assume.assumeTrue
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.mockito.Mockito
+import org.mockito.Mockito.any
+import org.mockito.Mockito.spy
+import org.mockito.Mockito.verify
+
+@SmallTest
+@RunWith(AndroidJUnit4::class)
+class SdkSandboxManagerCompatTest {
+
+ @Test
+ fun from_whenCalledOnSameContext_returnSameManager() {
+ val context = ApplicationProvider.getApplicationContext<Context>()
+
+ val managerCompat = SdkSandboxManagerCompat.from(context)
+ val managerCompat2 = SdkSandboxManagerCompat.from(context)
+
+ assertThat(managerCompat2).isSameInstanceAs(managerCompat)
+ }
+
+ @Test
+ fun from_whenCalledOnDifferentContext_returnDifferentManager() {
+ val context = ApplicationProvider.getApplicationContext<Context>()
+ val context2 = ContextWrapper(context)
+
+ val managerCompat = SdkSandboxManagerCompat.from(context)
+ val managerCompat2 = SdkSandboxManagerCompat.from(context2)
+
+ assertThat(managerCompat2).isNotSameInstanceAs(managerCompat)
+ }
+
+ @Test
+ // TODO(b/249982507) DexmakerMockitoInline requires P+. Rewrite to support P-
+ @SdkSuppress(minSdkVersion = Build.VERSION_CODES.P)
+ fun loadSdk_whenNoLocalSdkExistsAndSandboxNotAvailable_dontDelegateToSandbox() {
+ // TODO(b/262577044) Replace with @SdkSuppress after supporting maxExtensionVersion
+ assumeTrue("Requires Sandbox API not available", isSandboxApiNotAvailable())
+
+ val context = spy(ApplicationProvider.getApplicationContext<Context>())
+ val managerCompat = SdkSandboxManagerCompat.from(context)
+
+ assertThrows(LoadSdkCompatException::class.java) {
+ runBlocking {
+ managerCompat.loadSdk("sdk-not-exists", Bundle())
+ }
+ }
+
+ verify(context, Mockito.never()).getSystemService(any())
+ }
+
+ @Test
+ fun loadSdk_whenNoLocalSdkExistsAndSandboxNotAvailable_throwsSdkNotFoundException() {
+ // TODO(b/262577044) Replace with @SdkSuppress after supporting maxExtensionVersion
+ assumeTrue("Requires Sandbox API not available", isSandboxApiNotAvailable())
+
+ val context = ApplicationProvider.getApplicationContext<Context>()
+ val managerCompat = SdkSandboxManagerCompat.from(context)
+
+ val result = assertThrows(LoadSdkCompatException::class.java) {
+ runBlocking {
+ managerCompat.loadSdk("sdk-not-exists", Bundle())
+ }
+ }
+
+ assertThat(result.loadSdkErrorCode)
+ .isEqualTo(LoadSdkCompatException.LOAD_SDK_NOT_FOUND)
+ }
+
+ @Test
+ fun loadSdk_whenLocalSdkExists_returnResultFromCompatLoadSdk() {
+ val context = ApplicationProvider.getApplicationContext<Context>()
+ val managerCompat = SdkSandboxManagerCompat.from(context)
+
+ val result = runBlocking {
+ managerCompat.loadSdk("androidx.privacysandbox.sdkruntime.test.v1", Bundle())
+ }
+
+ assertThat(result.getInterface()!!.javaClass.classLoader)
+ .isNotSameInstanceAs(managerCompat.javaClass.classLoader)
+ }
+
+ @Test
+ fun loadSdk_whenLocalSdkExists_rethrowsExceptionFromCompatLoadSdk() {
+ val context = ApplicationProvider.getApplicationContext<Context>()
+ val managerCompat = SdkSandboxManagerCompat.from(context)
+
+ val params = Bundle()
+ params.putBoolean("needFail", true)
+
+ val result = assertThrows(LoadSdkCompatException::class.java) {
+ runBlocking {
+ managerCompat.loadSdk("androidx.privacysandbox.sdkruntime.test.v1", params)
+ }
+ }
+
+ assertThat(result.extraInformation).isEqualTo(params)
+ assertThat(result.loadSdkErrorCode).isEqualTo(LOAD_SDK_SDK_DEFINED_ERROR)
+ }
+
+ @Test
+ fun loadSdk_whenLocalSdkFailedToLoad_throwsInternalErrorException() {
+ val context = ApplicationProvider.getApplicationContext<Context>()
+ val managerCompat = SdkSandboxManagerCompat.from(context)
+
+ val result = assertThrows(LoadSdkCompatException::class.java) {
+ runBlocking {
+ managerCompat.loadSdk(
+ sdkName = "androidx.privacysandbox.sdkruntime.test.invalidEntryPoint",
+ params = Bundle()
+ )
+ }
+ }
+
+ assertThat(result.loadSdkErrorCode).isEqualTo(LOAD_SDK_INTERNAL_ERROR)
+ assertThat(result.message).isEqualTo("Failed to instantiate local SDK")
+ }
+
+ @Test
+ // TODO(b/249982507) DexmakerMockitoInline requires P+. Rewrite to support P-
+ @SdkSuppress(minSdkVersion = Build.VERSION_CODES.P)
+ fun getSandboxedSdks_whenSandboxNotAvailable_dontDelegateToSandbox() {
+ // TODO(b/262577044) Replace with @SdkSuppress after supporting maxExtensionVersion
+ assumeTrue("Requires Sandbox API not available", isSandboxApiNotAvailable())
+
+ val context = spy(ApplicationProvider.getApplicationContext<Context>())
+ val managerCompat = SdkSandboxManagerCompat.from(context)
+
+ managerCompat.getSandboxedSdks()
+
+ verify(context, Mockito.never()).getSystemService(any())
+ }
+
+ @Test
+ fun getSandboxedSdks_whenSandboxNotAvailable_returnsEmptyList() {
+ // TODO(b/262577044) Replace with @SdkSuppress after supporting maxExtensionVersion
+ assumeTrue("Requires Sandbox API not available", isSandboxApiNotAvailable())
+
+ val context = ApplicationProvider.getApplicationContext<Context>()
+ val managerCompat = SdkSandboxManagerCompat.from(context)
+
+ val sandboxedSdks = managerCompat.getSandboxedSdks()
+
+ assertThat(sandboxedSdks).isEmpty()
+ }
+
+ private fun isSandboxApiNotAvailable() =
+ AdServicesInfo.version() < 4
+}
\ No newline at end of file
diff --git a/privacysandbox/sdkruntime/sdkruntime-client/src/androidTest/java/androidx/privacysandbox/sdkruntime/client/config/LocalSdkConfigParserTest.kt b/privacysandbox/sdkruntime/sdkruntime-client/src/androidTest/java/androidx/privacysandbox/sdkruntime/client/config/LocalSdkConfigParserTest.kt
new file mode 100644
index 0000000..541d137
--- /dev/null
+++ b/privacysandbox/sdkruntime/sdkruntime-client/src/androidTest/java/androidx/privacysandbox/sdkruntime/client/config/LocalSdkConfigParserTest.kt
@@ -0,0 +1,247 @@
+/*
+ * Copyright 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package androidx.privacysandbox.sdkruntime.client.config
+
+import androidx.privacysandbox.sdkruntime.client.config.LocalSdkConfigParser.Companion.parse
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import androidx.test.filters.SmallTest
+import androidx.testutils.assertThrows
+import com.google.common.truth.Truth.assertThat
+import java.io.ByteArrayInputStream
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.xmlpull.v1.XmlPullParserException
+
+@SmallTest
+@RunWith(AndroidJUnit4::class)
+class LocalSdkConfigParserTest {
+
+ @Test
+ fun parse_skipUnknownTagsAndReturnParsedResult() {
+ val xml = """
+ <compat-config>
+ <compat-entrypoint>compat.sdk.provider</compat-entrypoint>
+ <unknown-tag>new parameter from future library version</unknown-tag>
+ <dex-path>1.dex</dex-path>
+ <future-version-tag>
+ <unknown-tag>new inner tag</unknown-tag>
+ </future-version-tag>
+ <dex-path>2.dex</dex-path>
+ <java-resources-root-path>javaResPath/</java-resources-root-path>
+ <resource-id-remapping>
+ <unknown-tag>new remapping tag</unknown-tag>
+ <r-package-class>com.test.sdk.RPackage</r-package-class>
+ <resources-package-id>42</resources-package-id>
+ </resource-id-remapping>
+ </compat-config>
+ """.trimIndent()
+
+ val result = tryParse(xml, packageName = "com.test.sdk.package")
+
+ assertThat(result)
+ .isEqualTo(
+ LocalSdkConfig(
+ packageName = "com.test.sdk.package",
+ dexPaths = listOf("1.dex", "2.dex"),
+ entryPoint = "compat.sdk.provider",
+ javaResourcesRoot = "javaResPath/",
+ resourceRemapping = ResourceRemappingConfig(
+ rPackageClassName = "com.test.sdk.RPackage",
+ packageId = 42
+ )
+ )
+ )
+ }
+
+ @Test
+ fun parse_whenOnlyMandatoryElements_returnParsedResult() {
+ val xml = """
+ <compat-config>
+ <compat-entrypoint>compat.sdk.provider</compat-entrypoint>
+ <dex-path>1.dex</dex-path>
+ </compat-config>
+ """.trimIndent()
+
+ val result = tryParse(xml, packageName = "com.test.sdk.package")
+
+ assertThat(result)
+ .isEqualTo(
+ LocalSdkConfig(
+ packageName = "com.test.sdk.package",
+ dexPaths = listOf("1.dex"),
+ entryPoint = "compat.sdk.provider",
+ javaResourcesRoot = null,
+ resourceRemapping = null
+ )
+ )
+ }
+
+ @Test
+ fun parse_whenNoEntryPoint_throwsException() {
+ assertParsingFailWithReason(
+ xml = """
+ <compat-config>
+ <dex-path>1.dex</dex-path>
+ </compat-config>
+ """.trimIndent(),
+ reason = "No compat-entrypoint tag found"
+ )
+ }
+
+ @Test
+ fun parse_whenDuplicateEntryPoint_throwsException() {
+ assertParsingFailWithReason(
+ xml = """
+ <compat-config>
+ <compat-entrypoint>compat.sdk.provider</compat-entrypoint>
+ <compat-entrypoint>compat.sdk.provider2</compat-entrypoint>
+ <dex-path>1.dex</dex-path>
+ </compat-config>
+ """.trimIndent(),
+ reason = "Duplicate compat-entrypoint tag found"
+ )
+ }
+
+ @Test
+ fun parse_whenNoDexPath_throwsException() {
+ assertParsingFailWithReason(
+ xml = """
+ <compat-config>
+ <compat-entrypoint>compat.sdk.provider</compat-entrypoint>
+ </compat-config>
+ """.trimIndent(),
+ reason = "No dex-path tags found"
+ )
+ }
+
+ @Test
+ fun parse_whenDuplicateJavaResourceRoot_throwsException() {
+ assertParsingFailWithReason(
+ xml = """
+ <compat-config>
+ <compat-entrypoint>compat.sdk.provider</compat-entrypoint>
+ <dex-path>1.dex</dex-path>
+ <java-resources-root-path>path1/</java-resources-root-path>
+ <java-resources-root-path>path2/</java-resources-root-path>
+ </compat-config>
+ """.trimIndent(),
+ reason = "Duplicate java-resources-root-path tag found"
+ )
+ }
+
+ @Test
+ fun parse_whenDuplicateResourceRemapping_throwsException() {
+ assertParsingFailWithReason(
+ xml = """
+ <compat-config>
+ <compat-entrypoint>compat.sdk.provider</compat-entrypoint>
+ <dex-path>1.dex</dex-path>
+ <resource-id-remapping>
+ <r-package-class>com.test.sdk.RPackage</r-package-class>
+ <resources-package-id>42</resources-package-id>
+ </resource-id-remapping>
+ <resource-id-remapping>
+ <r-package-class>com.test.sdk.RPackage</r-package-class>
+ <resources-package-id>42</resources-package-id>
+ </resource-id-remapping>
+ </compat-config>
+ """.trimIndent(),
+ reason = "Duplicate resource-id-remapping tag found"
+ )
+ }
+
+ @Test
+ fun parse_whenNoClassInResourceRemapping_throwsException() {
+ assertParsingFailWithReason(
+ xml = """
+ <compat-config>
+ <compat-entrypoint>compat.sdk.provider</compat-entrypoint>
+ <dex-path>1.dex</dex-path>
+ <resource-id-remapping>
+ <resources-package-id>42</resources-package-id>
+ </resource-id-remapping>
+ </compat-config>
+ """.trimIndent(),
+ reason = "No r-package-class tag found"
+ )
+ }
+
+ @Test
+ fun parse_whenDuplicateClassInResourceRemapping_throwsException() {
+ assertParsingFailWithReason(
+ xml = """
+ <compat-config>
+ <compat-entrypoint>compat.sdk.provider</compat-entrypoint>
+ <dex-path>1.dex</dex-path>
+ <resource-id-remapping>
+ <r-package-class>com.test.sdk.RPackage</r-package-class>
+ <r-package-class>com.test.sdk.RPackage</r-package-class>
+ <resources-package-id>42</resources-package-id>
+ </resource-id-remapping>
+ </compat-config>
+ """.trimIndent(),
+ reason = "Duplicate r-package-class tag found"
+ )
+ }
+
+ @Test
+ fun parse_whenNoPackageIdInResourceRemapping_throwsException() {
+ assertParsingFailWithReason(
+ xml = """
+ <compat-config>
+ <compat-entrypoint>compat.sdk.provider</compat-entrypoint>
+ <dex-path>1.dex</dex-path>
+ <resource-id-remapping>
+ <r-package-class>com.test.sdk.RPackage</r-package-class>
+ </resource-id-remapping>
+ </compat-config>
+ """.trimIndent(),
+ reason = "No resources-package-id tag found"
+ )
+ }
+
+ @Test
+ fun parse_whenDuplicatePackageIdInResourceRemapping_throwsException() {
+ assertParsingFailWithReason(
+ xml = """
+ <compat-config>
+ <compat-entrypoint>compat.sdk.provider</compat-entrypoint>
+ <dex-path>1.dex</dex-path>
+ <resource-id-remapping>
+ <r-package-class>com.test.sdk.RPackage</r-package-class>
+ <resources-package-id>42</resources-package-id>
+ <resources-package-id>42</resources-package-id>
+ </resource-id-remapping>
+ </compat-config>
+ """.trimIndent(),
+ reason = "Duplicate resources-package-id tag found"
+ )
+ }
+
+ private fun assertParsingFailWithReason(xml: String, reason: String) {
+ assertThrows<XmlPullParserException> {
+ tryParse(xml)
+ }.hasMessageThat().isEqualTo(
+ reason
+ )
+ }
+
+ private fun tryParse(xml: String, packageName: String = "sdkPackageName"): LocalSdkConfig {
+ ByteArrayInputStream(xml.toByteArray()).use { inputStream ->
+ return parse(inputStream, packageName)
+ }
+ }
+}
\ No newline at end of file
diff --git a/privacysandbox/sdkruntime/sdkruntime-client/src/androidTest/java/androidx/privacysandbox/sdkruntime/client/config/LocalSdkConfigsHolderTest.kt b/privacysandbox/sdkruntime/sdkruntime-client/src/androidTest/java/androidx/privacysandbox/sdkruntime/client/config/LocalSdkConfigsHolderTest.kt
new file mode 100644
index 0000000..0b51558
--- /dev/null
+++ b/privacysandbox/sdkruntime/sdkruntime-client/src/androidTest/java/androidx/privacysandbox/sdkruntime/client/config/LocalSdkConfigsHolderTest.kt
@@ -0,0 +1,70 @@
+/*
+ * Copyright 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package androidx.privacysandbox.sdkruntime.client.config
+
+import androidx.test.core.app.ApplicationProvider
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import androidx.test.filters.SmallTest
+import com.google.common.truth.Truth.assertThat
+import org.junit.Test
+import org.junit.runner.RunWith
+
+@SmallTest
+@RunWith(AndroidJUnit4::class)
+class LocalSdkConfigsHolderTest {
+
+ @Test
+ fun load_whenSdkTableNotExists_doesNotThrowException() {
+ val configHolder = LocalSdkConfigsHolder.load(
+ ApplicationProvider.getApplicationContext(),
+ sdkTableAssetName = "not-exists"
+ )
+ val result = configHolder.getSdkConfig("sdk")
+ assertThat(result).isNull()
+ }
+
+ @Test
+ fun getSdkConfig_whenSdkExists_returnSdkInfo() {
+ val configHolder = LocalSdkConfigsHolder.load(
+ ApplicationProvider.getApplicationContext()
+ )
+
+ val result = configHolder.getSdkConfig(
+ "androidx.privacysandbox.sdkruntime.test.v1"
+ )
+
+ assertThat(result)
+ .isEqualTo(
+ LocalSdkConfig(
+ packageName = "androidx.privacysandbox.sdkruntime.test.v1",
+ dexPaths = listOf("RuntimeEnabledSdks/V1/classes.dex"),
+ entryPoint = "androidx.privacysandbox.sdkruntime.test.v1.CompatProvider",
+ javaResourcesRoot = "RuntimeEnabledSdks/V1/javaresources"
+ )
+ )
+ }
+
+ @Test
+ fun getSdkConfig_whenSdkNotExists_returnNull() {
+ val configHolder = LocalSdkConfigsHolder.load(
+ ApplicationProvider.getApplicationContext()
+ )
+
+ val result = configHolder.getSdkConfig("not-exists")
+
+ assertThat(result).isNull()
+ }
+}
\ No newline at end of file
diff --git a/privacysandbox/sdkruntime/sdkruntime-client/src/androidTest/java/androidx/privacysandbox/sdkruntime/client/config/SdkTableConfigParserTest.kt b/privacysandbox/sdkruntime/sdkruntime-client/src/androidTest/java/androidx/privacysandbox/sdkruntime/client/config/SdkTableConfigParserTest.kt
new file mode 100644
index 0000000..e646377
--- /dev/null
+++ b/privacysandbox/sdkruntime/sdkruntime-client/src/androidTest/java/androidx/privacysandbox/sdkruntime/client/config/SdkTableConfigParserTest.kt
@@ -0,0 +1,173 @@
+/*
+ * Copyright 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package androidx.privacysandbox.sdkruntime.client.config
+
+import androidx.privacysandbox.sdkruntime.client.config.SdkTableConfigParser.Companion.parse
+import androidx.privacysandbox.sdkruntime.client.config.SdkTableConfigParser.SdkTableEntry
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import androidx.test.filters.SmallTest
+import androidx.testutils.assertThrows
+import com.google.common.truth.Truth.assertThat
+import java.io.ByteArrayInputStream
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.xmlpull.v1.XmlPullParserException
+
+@SmallTest
+@RunWith(AndroidJUnit4::class)
+class SdkTableConfigParserTest {
+
+ @Test
+ fun parse_skipUnknownTagsAndReturnSetWithSdkTableEntries() {
+ val xml = """
+ <runtime-enabled-sdk-table>
+ <runtime-enabled-sdk>
+ <package-name>sdk1</package-name>
+ <unknown-tag>new parameter from future library version</unknown-tag>
+ <compat-config-path>config1.xml</compat-config-path>
+ </runtime-enabled-sdk>
+ <future-version-runtime-enabled-sdk>
+ <unknown-tag>new sdk type without old tags</unknown-tag>
+ </future-version-runtime-enabled-sdk>
+ <runtime-enabled-sdk>
+ <unknown-tag2>new parameter from future library version</unknown-tag2>
+ <package-name>sdk2</package-name>
+ <compat-config-path>config2.xml</compat-config-path>
+ </runtime-enabled-sdk>
+ </runtime-enabled-sdk-table>
+ """.trimIndent()
+
+ val result = tryParse(xml)
+
+ assertThat(result)
+ .containsExactly(
+ SdkTableEntry("sdk1", "config1.xml"),
+ SdkTableEntry("sdk2", "config2.xml")
+ )
+ }
+
+ @Test
+ fun parse_whenEmptyTable_returnsEmptyMap() {
+ val xml = """
+ <runtime-enabled-sdk-table>
+ </runtime-enabled-sdk-table>
+ """.trimIndent()
+
+ val result = tryParse(xml)
+
+ assertThat(result).isEmpty()
+ }
+
+ @Test
+ fun parse_whenNoPackageName_throwsException() {
+ val xml = """
+ <runtime-enabled-sdk-table>
+ <runtime-enabled-sdk>
+ <compat-config-path>config1.xml</compat-config-path>
+ </runtime-enabled-sdk>
+ </runtime-enabled-sdk-table>
+ """.trimIndent()
+
+ assertThrows<XmlPullParserException> {
+ tryParse(xml)
+ }.hasMessageThat().isEqualTo(
+ "No package-name tag found"
+ )
+ }
+
+ @Test
+ fun parse_whenMultiplePackageNames_throwsException() {
+ val xml = """
+ <runtime-enabled-sdk-table>
+ <runtime-enabled-sdk>
+ <package-name>sdk1</package-name>
+ <package-name>sdk2</package-name>
+ <compat-config-path>config1.xml</compat-config-path>
+ </runtime-enabled-sdk>
+ </runtime-enabled-sdk-table>
+ """.trimIndent()
+
+ assertThrows<XmlPullParserException> {
+ tryParse(xml)
+ }.hasMessageThat().isEqualTo(
+ "Duplicate package-name tag found"
+ )
+ }
+
+ @Test
+ fun parse_whenNoConfigPath_throwsException() {
+ val xml = """
+ <runtime-enabled-sdk-table>
+ <runtime-enabled-sdk>
+ <package-name>sdk1</package-name>
+ </runtime-enabled-sdk>
+ </runtime-enabled-sdk-table>
+ """.trimIndent()
+
+ assertThrows<XmlPullParserException> {
+ tryParse(xml)
+ }.hasMessageThat().isEqualTo(
+ "No compat-config-path tag found"
+ )
+ }
+
+ @Test
+ fun parse_whenMultipleConfigPaths_throwsException() {
+ val xml = """
+ <runtime-enabled-sdk-table>
+ <runtime-enabled-sdk>
+ <package-name>sdk1</package-name>
+ <compat-config-path>config1.xml</compat-config-path>
+ <compat-config-path>config2.xml</compat-config-path>
+ </runtime-enabled-sdk>
+ </runtime-enabled-sdk-table>
+ """.trimIndent()
+
+ assertThrows<XmlPullParserException> {
+ tryParse(xml)
+ }.hasMessageThat().isEqualTo(
+ "Duplicate compat-config-path tag found"
+ )
+ }
+
+ @Test
+ fun parse_whenDuplicatePackageName_throwsException() {
+ val xml = """
+ <runtime-enabled-sdk-table>
+ <runtime-enabled-sdk>
+ <package-name>sdk1</package-name>
+ <compat-config-path>config1.xml</compat-config-path>
+ </runtime-enabled-sdk>
+ <runtime-enabled-sdk>
+ <package-name>sdk1</package-name>
+ <compat-config-path>config2.xml</compat-config-path>
+ </runtime-enabled-sdk>
+ </runtime-enabled-sdk-table>
+ """.trimIndent()
+
+ assertThrows<XmlPullParserException> {
+ tryParse(xml)
+ }.hasMessageThat().isEqualTo(
+ "Duplicate entry for sdk1 found"
+ )
+ }
+
+ private fun tryParse(xml: String): Set<SdkTableEntry> {
+ ByteArrayInputStream(xml.toByteArray()).use { inputStream ->
+ return parse(inputStream)
+ }
+ }
+}
\ No newline at end of file
diff --git a/privacysandbox/sdkruntime/sdkruntime-client/src/androidTest/java/androidx/privacysandbox/sdkruntime/client/loader/FileClassLoaderFactoryTest.kt b/privacysandbox/sdkruntime/sdkruntime-client/src/androidTest/java/androidx/privacysandbox/sdkruntime/client/loader/FileClassLoaderFactoryTest.kt
new file mode 100644
index 0000000..31fee55
--- /dev/null
+++ b/privacysandbox/sdkruntime/sdkruntime-client/src/androidTest/java/androidx/privacysandbox/sdkruntime/client/loader/FileClassLoaderFactoryTest.kt
@@ -0,0 +1,145 @@
+/*
+ * Copyright 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.privacysandbox.sdkruntime.client.loader
+
+import android.content.Context
+import androidx.privacysandbox.sdkruntime.client.config.LocalSdkConfig
+import androidx.privacysandbox.sdkruntime.client.loader.storage.LocalSdkStorage
+import androidx.privacysandbox.sdkruntime.client.loader.storage.LocalSdkDexFiles
+import androidx.privacysandbox.sdkruntime.client.loader.storage.TestLocalSdkStorage
+import androidx.test.core.app.ApplicationProvider
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import androidx.test.filters.SmallTest
+import com.google.common.truth.Truth.assertThat
+import java.io.File
+import org.junit.Before
+import org.junit.Test
+import org.junit.runner.RunWith
+
+@SmallTest
+@RunWith(AndroidJUnit4::class)
+class FileClassLoaderFactoryTest {
+
+ private lateinit var testSdkConfig: LocalSdkConfig
+
+ @Before
+ fun setUp() {
+ testSdkConfig = LocalSdkConfig(
+ packageName = "androidx.privacysandbox.sdkruntime.test.v1",
+ dexPaths = listOf(
+ "RuntimeEnabledSdks/V1/classes.dex",
+ ),
+ entryPoint = "androidx.privacysandbox.sdkruntime.test.v1.CompatProvider",
+ )
+ }
+
+ @Test
+ fun createClassLoaderFor_whenSdkStorageReturnFiles_returnClassloaderAndNotDelegateToFallback() {
+ val sdkDexFiles = extractTestSdkDexFiles()
+ val fallback = TestFallbackFactory()
+
+ val fileClassLoaderFactory = FileClassLoaderFactory(
+ StubSdkStorage(result = sdkDexFiles),
+ fallback
+ )
+
+ val classLoader = fileClassLoaderFactory.createClassLoaderFor(
+ testSdkConfig,
+ javaClass.classLoader!!.parent!!
+ )
+
+ val loadedEntryPointClass = classLoader.loadClass(testSdkConfig.entryPoint)
+ assertThat(loadedEntryPointClass.classLoader).isEqualTo(classLoader)
+
+ assertThat(fallback.loadSdkCalled).isFalse()
+ }
+
+ @Test
+ fun createClassLoaderFor_whenSdkStorageReturnNull_delegateToFallback() {
+ val fallback = TestFallbackFactory(testSdkConfig, javaClass.classLoader!!.parent)
+ val fileClassLoaderFactory = FileClassLoaderFactory(
+ StubSdkStorage(result = null),
+ fallback
+ )
+
+ fileClassLoaderFactory.createClassLoaderFor(
+ testSdkConfig,
+ javaClass.classLoader!!.parent!!
+ )
+
+ assertThat(fallback.loadSdkCalled).isTrue()
+ }
+
+ @Test
+ fun createClassLoaderFor_whenSdkStorageThrows_delegateToFallback() {
+ val fallback = TestFallbackFactory(testSdkConfig, javaClass.classLoader!!.parent)
+ val fileClassLoaderFactory = FileClassLoaderFactory(
+ ThrowingSdkStorage(exception = Exception("Something wrong")),
+ fallback
+ )
+
+ fileClassLoaderFactory.createClassLoaderFor(
+ testSdkConfig,
+ javaClass.classLoader!!.parent!!
+ )
+
+ assertThat(fallback.loadSdkCalled).isTrue()
+ }
+
+ private class StubSdkStorage(
+ private val result: LocalSdkDexFiles?
+ ) : LocalSdkStorage {
+ override fun dexFilesFor(sdkConfig: LocalSdkConfig) = result
+ }
+
+ private class ThrowingSdkStorage(
+ private val exception: Exception
+ ) : LocalSdkStorage {
+ override fun dexFilesFor(sdkConfig: LocalSdkConfig): LocalSdkDexFiles? {
+ throw exception
+ }
+ }
+
+ private class TestFallbackFactory(
+ private val expectedSdkConfig: LocalSdkConfig? = null,
+ private val expectedParent: ClassLoader? = null,
+ ) : SdkLoader.ClassLoaderFactory {
+
+ var loadSdkCalled: Boolean = false
+
+ override fun createClassLoaderFor(
+ sdkConfig: LocalSdkConfig,
+ parent: ClassLoader
+ ): ClassLoader {
+ assertThat(sdkConfig).isEqualTo(expectedSdkConfig)
+ assertThat(parent).isEqualTo(expectedParent)
+ loadSdkCalled = true
+ return parent
+ }
+ }
+
+ private fun extractTestSdkDexFiles(): LocalSdkDexFiles {
+ val context = ApplicationProvider.getApplicationContext<Context>()
+
+ val testStorage = TestLocalSdkStorage(
+ context,
+ rootFolder = File(context.cacheDir, "FileClassLoaderFactoryTest")
+ )
+
+ return testStorage.dexFilesFor(testSdkConfig)
+ }
+}
\ No newline at end of file
diff --git a/privacysandbox/sdkruntime/sdkruntime-client/src/androidTest/java/androidx/privacysandbox/sdkruntime/client/loader/InMemorySdkClassLoaderFactoryTest.kt b/privacysandbox/sdkruntime/sdkruntime-client/src/androidTest/java/androidx/privacysandbox/sdkruntime/client/loader/InMemorySdkClassLoaderFactoryTest.kt
new file mode 100644
index 0000000..93aec37
--- /dev/null
+++ b/privacysandbox/sdkruntime/sdkruntime-client/src/androidTest/java/androidx/privacysandbox/sdkruntime/client/loader/InMemorySdkClassLoaderFactoryTest.kt
@@ -0,0 +1,78 @@
+/*
+ * Copyright 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package androidx.privacysandbox.sdkruntime.client.loader
+
+import android.os.Build
+import androidx.privacysandbox.sdkruntime.client.config.LocalSdkConfig
+import androidx.privacysandbox.sdkruntime.core.LoadSdkCompatException
+import androidx.test.core.app.ApplicationProvider
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import androidx.test.filters.SdkSuppress
+import androidx.test.filters.SmallTest
+import com.google.common.truth.Truth.assertThat
+import org.junit.Assert.assertThrows
+import org.junit.Before
+import org.junit.Test
+import org.junit.runner.RunWith
+
+@SmallTest
+@RunWith(AndroidJUnit4::class)
+class InMemorySdkClassLoaderFactoryTest {
+
+ private lateinit var factoryUnderTest: InMemorySdkClassLoaderFactory
+ private lateinit var testSdkInfo: LocalSdkConfig
+
+ @Before
+ fun setUp() {
+ factoryUnderTest = InMemorySdkClassLoaderFactory.create(
+ ApplicationProvider.getApplicationContext()
+ )
+ testSdkInfo = LocalSdkConfig(
+ packageName = "androidx.privacysandbox.sdkruntime.test.v1",
+ dexPaths = listOf("RuntimeEnabledSdks/V1/classes.dex"),
+ entryPoint = "androidx.privacysandbox.sdkruntime.test.v1.CompatProvider",
+ javaResourcesRoot = "RuntimeEnabledSdks/V1/"
+ )
+ }
+
+ @Test
+ @SdkSuppress(minSdkVersion = Build.VERSION_CODES.O_MR1)
+ fun createClassLoaderFor_whenApi27_returnClassloader() {
+ val classLoader = factoryUnderTest.createClassLoaderFor(
+ testSdkInfo,
+ javaClass.classLoader!!
+ )
+ val loadedEntryPointClass = classLoader.loadClass(testSdkInfo.entryPoint)
+ assertThat(loadedEntryPointClass.classLoader).isEqualTo(classLoader)
+ }
+
+ @Test
+ @SdkSuppress(maxSdkVersion = Build.VERSION_CODES.O)
+ fun createClassLoaderFor_whenApiPre27_throwsSandboxDisabledException() {
+ val ex = assertThrows(LoadSdkCompatException::class.java) {
+ factoryUnderTest.createClassLoaderFor(
+ testSdkInfo,
+ javaClass.classLoader!!
+ )
+ }
+
+ assertThat(ex.loadSdkErrorCode)
+ .isEqualTo(LoadSdkCompatException.LOAD_SDK_SDK_SANDBOX_DISABLED)
+ assertThat(ex)
+ .hasMessageThat()
+ .isEqualTo("Can't use InMemoryDexClassLoader")
+ }
+}
\ No newline at end of file
diff --git a/privacysandbox/sdkruntime/sdkruntime-client/src/androidTest/java/androidx/privacysandbox/sdkruntime/client/loader/JavaResourcesLoadingClassLoaderFactoryTest.kt b/privacysandbox/sdkruntime/sdkruntime-client/src/androidTest/java/androidx/privacysandbox/sdkruntime/client/loader/JavaResourcesLoadingClassLoaderFactoryTest.kt
new file mode 100644
index 0000000..3da2c8b
--- /dev/null
+++ b/privacysandbox/sdkruntime/sdkruntime-client/src/androidTest/java/androidx/privacysandbox/sdkruntime/client/loader/JavaResourcesLoadingClassLoaderFactoryTest.kt
@@ -0,0 +1,114 @@
+/*
+ * Copyright 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.privacysandbox.sdkruntime.client.loader
+
+import androidx.privacysandbox.sdkruntime.client.config.LocalSdkConfig
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import androidx.test.filters.SmallTest
+import com.google.common.truth.Truth.assertThat
+import org.junit.Before
+import org.junit.Test
+import org.junit.runner.RunWith
+
+@SmallTest
+@RunWith(AndroidJUnit4::class)
+class JavaResourcesLoadingClassLoaderFactoryTest {
+
+ private lateinit var appClassloader: ClassLoader
+ private lateinit var factoryUnderTest: JavaResourcesLoadingClassLoaderFactory
+ private lateinit var testSdkConfig: LocalSdkConfig
+
+ @Before
+ fun setUp() {
+ appClassloader = javaClass.classLoader!!
+ factoryUnderTest = JavaResourcesLoadingClassLoaderFactory(
+ appClassloader,
+ codeClassLoaderFactory = object : SdkLoader.ClassLoaderFactory {
+ override fun createClassLoaderFor(sdkConfig: LocalSdkConfig, parent: ClassLoader) =
+ parent
+ }
+ )
+ testSdkConfig = LocalSdkConfig(
+ packageName = "androidx.privacysandbox.sdkruntime.test.v1",
+ dexPaths = listOf("RuntimeEnabledSdks/V1/classes.dex"),
+ entryPoint = "androidx.privacysandbox.sdkruntime.test.v1.CompatProvider",
+ javaResourcesRoot = "RuntimeEnabledSdks/V1/javaresources"
+ )
+ }
+
+ @Test
+ fun getResource_delegateToAppClassloaderWithPrefix() {
+ val classLoader = factoryUnderTest.createClassLoaderFor(
+ testSdkConfig,
+ appClassloader.parent!!
+ )
+ val resource = classLoader.getResource("test.txt")
+
+ val appResource = appClassloader.getResource(
+ "assets/RuntimeEnabledSdks/V1/javaresources/test.txt"
+ )
+ assertThat(resource).isNotNull()
+ assertThat(resource).isEqualTo(appResource)
+ }
+
+ @Test
+ fun getResource_whenAppResource_returnNull() {
+ val classLoader = factoryUnderTest.createClassLoaderFor(
+ testSdkConfig,
+ appClassloader.parent!!
+ )
+
+ val resource = classLoader.getResource("assets/RuntimeEnabledSdkTable.xml")
+ val appResource = appClassloader.getResource("assets/RuntimeEnabledSdkTable.xml")
+
+ assertThat(appResource).isNotNull()
+ assertThat(resource).isNull()
+ }
+
+ @Test
+ fun getResources_delegateToAppClassloaderWithPrefix() {
+ val classLoader = factoryUnderTest.createClassLoaderFor(
+ testSdkConfig,
+ appClassloader.parent!!
+ )
+
+ val resources = classLoader
+ .getResources("test.txt")
+ .toList()
+ assertThat(resources.isEmpty()).isFalse()
+
+ val appResources = appClassloader
+ .getResources("assets/RuntimeEnabledSdks/V1/javaresources/test.txt")
+ .toList()
+
+ assertThat(appResources).isEqualTo(resources)
+ }
+
+ @Test
+ fun getResources_whenAppResource_returnEmpty() {
+ val classLoader = factoryUnderTest.createClassLoaderFor(
+ testSdkConfig,
+ appClassloader.parent!!
+ )
+
+ val resources = classLoader.getResources("assets/RuntimeEnabledSdkTable.xml")
+ val appResources = appClassloader.getResources("assets/RuntimeEnabledSdkTable.xml")
+
+ assertThat(appResources.hasMoreElements()).isTrue()
+ assertThat(resources.hasMoreElements()).isFalse()
+ }
+}
\ No newline at end of file
diff --git a/privacysandbox/sdkruntime/sdkruntime-client/src/androidTest/java/androidx/privacysandbox/sdkruntime/client/loader/LocalSdkTest.kt b/privacysandbox/sdkruntime/sdkruntime-client/src/androidTest/java/androidx/privacysandbox/sdkruntime/client/loader/LocalSdkTest.kt
new file mode 100644
index 0000000..37635f0
--- /dev/null
+++ b/privacysandbox/sdkruntime/sdkruntime-client/src/androidTest/java/androidx/privacysandbox/sdkruntime/client/loader/LocalSdkTest.kt
@@ -0,0 +1,237 @@
+/*
+ * Copyright 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package androidx.privacysandbox.sdkruntime.client.loader
+
+import android.content.Context
+import android.os.Binder
+import android.os.Bundle
+import android.view.View
+import androidx.privacysandbox.sdkruntime.client.config.LocalSdkConfig
+import androidx.privacysandbox.sdkruntime.client.loader.impl.SandboxedSdkContextCompat
+import androidx.privacysandbox.sdkruntime.client.loader.storage.TestLocalSdkStorage
+import androidx.privacysandbox.sdkruntime.client.loader.storage.toClassPathString
+import androidx.privacysandbox.sdkruntime.core.LoadSdkCompatException
+import androidx.privacysandbox.sdkruntime.core.SandboxedSdkCompat
+import androidx.privacysandbox.sdkruntime.core.SandboxedSdkProviderCompat
+import androidx.privacysandbox.sdkruntime.core.Versions
+import androidx.test.core.app.ApplicationProvider
+import androidx.test.filters.SmallTest
+import com.google.common.truth.Truth.assertThat
+import dalvik.system.BaseDexClassLoader
+import java.io.File
+import org.junit.Assert.assertThrows
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.junit.runners.Parameterized
+
+@SmallTest
+@RunWith(Parameterized::class)
+internal class LocalSdkTest(
+ @Suppress("unused") private val sdkPath: String,
+ @Suppress("unused") private val sdkVersion: Int,
+ private val loadedSdk: LocalSdk
+) {
+
+ @Test
+ fun loadSdk_attachCorrectContext() {
+ val sdkContext = loadedSdk.extractSdkContext()
+ assertThat(sdkContext.javaClass.name)
+ .isEqualTo(SandboxedSdkContextCompat::class.java.name)
+ }
+
+ @Test
+ fun onLoadSdk_callOnLoadSdkAndReturnResult() {
+ val params = Bundle()
+
+ val sandboxedSdkCompat = loadedSdk.onLoadSdk(params)
+
+ val expectedBinder = loadedSdk.extractSdkProviderFieldValue<Binder>(
+ fieldName = "onLoadSdkBinder",
+ )
+ assertThat(sandboxedSdkCompat.getInterface()).isEqualTo(expectedBinder)
+
+ val lastParams = loadedSdk.extractSdkProviderFieldValue<Bundle>(
+ fieldName = "lastOnLoadSdkParams",
+ )
+ assertThat(lastParams).isEqualTo(params)
+ }
+
+ @Test
+ fun onLoadSdk_callOnLoadSdkAndThrowException() {
+ val params = Bundle()
+ params.putBoolean("needFail", true)
+
+ val ex = assertThrows(LoadSdkCompatException::class.java) {
+ loadedSdk.onLoadSdk(params)
+ }
+
+ assertThat(ex.extraInformation).isEqualTo(params)
+ }
+
+ @Test
+ fun beforeUnloadSdk_callBeforeUnloadSdk() {
+ loadedSdk.beforeUnloadSdk()
+
+ val isBeforeUnloadSdkCalled = loadedSdk.extractSdkProviderFieldValue<Boolean>(
+ fieldName = "isBeforeUnloadSdkCalled"
+ )
+
+ assertThat(isBeforeUnloadSdkCalled).isTrue()
+ }
+
+ class CurrentVersionProviderLoadTest : SandboxedSdkProviderCompat() {
+ @JvmField
+ val onLoadSdkBinder = Binder()
+
+ @JvmField
+ var lastOnLoadSdkParams: Bundle? = null
+
+ @JvmField
+ var isBeforeUnloadSdkCalled = false
+
+ @Throws(LoadSdkCompatException::class)
+ override fun onLoadSdk(params: Bundle): SandboxedSdkCompat {
+ lastOnLoadSdkParams = params
+ if (params.getBoolean("needFail", false)) {
+ throw LoadSdkCompatException(RuntimeException(), params)
+ }
+ return SandboxedSdkCompat(onLoadSdkBinder)
+ }
+
+ override fun beforeUnloadSdk() {
+ isBeforeUnloadSdkCalled = true
+ }
+
+ override fun getView(
+ windowContext: Context,
+ params: Bundle,
+ width: Int,
+ height: Int
+ ): View {
+ return View(windowContext)
+ }
+ }
+
+ internal class TestClassLoaderFactory(
+ private val testStorage: TestLocalSdkStorage
+ ) : SdkLoader.ClassLoaderFactory {
+ override fun createClassLoaderFor(
+ sdkConfig: LocalSdkConfig,
+ parent: ClassLoader
+ ): ClassLoader {
+ val sdkDexFiles = testStorage.dexFilesFor(sdkConfig)
+
+ val optimizedDirectory = File(sdkDexFiles.files[0].parentFile, "DexOpt")
+ if (!optimizedDirectory.exists()) {
+ optimizedDirectory.mkdirs()
+ }
+
+ return BaseDexClassLoader(
+ sdkDexFiles.toClassPathString(),
+ optimizedDirectory,
+ /* librarySearchPath = */ null,
+ parent
+ )
+ }
+ }
+
+ internal class TestSdkInfo internal constructor(
+ val apiVersion: Int,
+ dexPath: String,
+ sdkProviderClass: String
+ ) {
+ val localSdkConfig = LocalSdkConfig(
+ packageName = "test.$apiVersion.$sdkProviderClass",
+ dexPaths = listOf(dexPath),
+ entryPoint = sdkProviderClass
+ )
+ }
+
+ companion object {
+ private val SDKS = arrayOf(
+ TestSdkInfo(
+ 1,
+ "RuntimeEnabledSdks/V1/classes.dex",
+ "androidx.privacysandbox.sdkruntime.test.v1.CompatProvider"
+ )
+ )
+
+ @Parameterized.Parameters(name = "sdk: {0}, version: {1}")
+ @JvmStatic
+ fun params(): List<Array<Any>> = buildList {
+ assertThat(SDKS.size).isEqualTo(Versions.API_VERSION)
+
+ val assetsSdkLoader = createAssetsSdkLoader()
+ for (i in SDKS.indices) {
+ val sdk = SDKS[i]
+ assertThat(sdk.apiVersion).isEqualTo(i + 1)
+
+ val loadedSdk = assetsSdkLoader.loadSdk(sdk.localSdkConfig)
+ assertThat(loadedSdk.extractApiVersion())
+ .isEqualTo(sdk.apiVersion)
+
+ add(
+ arrayOf(
+ sdk.localSdkConfig.dexPaths[0],
+ sdk.apiVersion,
+ loadedSdk
+ )
+ )
+ }
+
+ // add SDK loaded from test sources
+ add(
+ arrayOf(
+ "BuiltFromSource",
+ Versions.API_VERSION,
+ loadTestSdkFromSource(),
+ )
+ )
+ }
+
+ private fun loadTestSdkFromSource(): LocalSdk {
+ val sdkLoader = SdkLoader(
+ object : SdkLoader.ClassLoaderFactory {
+ override fun createClassLoaderFor(
+ sdkConfig: LocalSdkConfig,
+ parent: ClassLoader
+ ): ClassLoader = javaClass.classLoader!!
+ },
+ ApplicationProvider.getApplicationContext()
+ )
+
+ return sdkLoader.loadSdk(
+ LocalSdkConfig(
+ packageName = "test.CurrentVersionProviderLoadTest",
+ dexPaths = emptyList(),
+ entryPoint = CurrentVersionProviderLoadTest::class.java.name
+ )
+ )
+ }
+
+ private fun createAssetsSdkLoader(): SdkLoader {
+ val context = ApplicationProvider.getApplicationContext<Context>()
+ val testStorage = TestLocalSdkStorage(
+ context,
+ rootFolder = File(context.cacheDir, "LocalSdkTest")
+ )
+ return SdkLoader(
+ TestClassLoaderFactory(testStorage),
+ context
+ )
+ }
+ }
+}
\ No newline at end of file
diff --git a/privacysandbox/sdkruntime/sdkruntime-client/src/androidTest/java/androidx/privacysandbox/sdkruntime/client/loader/LocalSdkTestUtils.kt b/privacysandbox/sdkruntime/sdkruntime-client/src/androidTest/java/androidx/privacysandbox/sdkruntime/client/loader/LocalSdkTestUtils.kt
new file mode 100644
index 0000000..0cfa817
--- /dev/null
+++ b/privacysandbox/sdkruntime/sdkruntime-client/src/androidTest/java/androidx/privacysandbox/sdkruntime/client/loader/LocalSdkTestUtils.kt
@@ -0,0 +1,72 @@
+/*
+ * Copyright 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.privacysandbox.sdkruntime.client.loader
+
+import android.content.Context
+import androidx.privacysandbox.sdkruntime.core.Versions
+import androidx.privacysandbox.sdkruntime.core.SandboxedSdkProviderCompat
+import kotlin.reflect.cast
+
+/**
+ * Extract value of [Versions.API_VERSION] from loaded SDK.
+ */
+internal fun LocalSdk.extractApiVersion(): Int =
+ extractVersionValue("API_VERSION")
+
+/**
+ * Extract value of [Versions.CLIENT_VERSION] from loaded SDK.
+ */
+internal fun LocalSdk.extractClientVersion(): Int =
+ extractVersionValue("CLIENT_VERSION")
+
+/**
+ * Extract [SandboxedSdkProviderCompat.context] from loaded SDK.
+ */
+internal fun LocalSdk.extractSdkContext(): Context {
+ val getContextMethod = sdkProvider
+ .javaClass
+ .getMethod("getContext")
+
+ val rawContext = getContextMethod.invoke(sdkProvider)
+
+ return Context::class.cast(rawContext)
+}
+
+/**
+ * Extract field value from [SandboxedSdkProviderCompat]
+ */
+internal inline fun <reified T> LocalSdk.extractSdkProviderFieldValue(fieldName: String): T {
+ return sdkProvider
+ .javaClass
+ .getField(fieldName)
+ .get(sdkProvider)!! as T
+}
+
+/**
+ * Extract classloader that was used for loading of [SandboxedSdkProviderCompat].
+ */
+internal fun LocalSdk.extractSdkProviderClassloader(): ClassLoader =
+ sdkProvider.javaClass.classLoader!!
+
+private fun LocalSdk.extractVersionValue(versionFieldName: String): Int {
+ val versionsClass = Class.forName(
+ Versions::class.java.name,
+ false,
+ extractSdkProviderClassloader()
+ )
+ return versionsClass.getDeclaredField(versionFieldName).get(null) as Int
+}
\ No newline at end of file
diff --git a/privacysandbox/sdkruntime/sdkruntime-client/src/androidTest/java/androidx/privacysandbox/sdkruntime/client/loader/SandboxedSdkContextCompatTest.kt b/privacysandbox/sdkruntime/sdkruntime-client/src/androidTest/java/androidx/privacysandbox/sdkruntime/client/loader/SandboxedSdkContextCompatTest.kt
new file mode 100644
index 0000000..11c62973
--- /dev/null
+++ b/privacysandbox/sdkruntime/sdkruntime-client/src/androidTest/java/androidx/privacysandbox/sdkruntime/client/loader/SandboxedSdkContextCompatTest.kt
@@ -0,0 +1,41 @@
+/*
+ * Copyright 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package androidx.privacysandbox.sdkruntime.client.loader
+
+import androidx.privacysandbox.sdkruntime.client.loader.impl.SandboxedSdkContextCompat
+import androidx.test.core.app.ApplicationProvider
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import androidx.test.filters.SmallTest
+import com.google.common.truth.Truth.assertThat
+import org.junit.Test
+import org.junit.runner.RunWith
+
+@SmallTest
+@RunWith(AndroidJUnit4::class)
+class SandboxedSdkContextCompatTest {
+
+ @Test
+ fun getClassloader_returnSdkClassloader() {
+ val sdkClassLoader = javaClass.classLoader!!.parent!!
+
+ val sdkContextCompat = SandboxedSdkContextCompat(
+ ApplicationProvider.getApplicationContext(),
+ sdkClassLoader
+ )
+ assertThat(sdkContextCompat.classLoader)
+ .isEqualTo(sdkClassLoader)
+ }
+}
\ No newline at end of file
diff --git a/privacysandbox/sdkruntime/sdkruntime-client/src/androidTest/java/androidx/privacysandbox/sdkruntime/client/loader/SdkLoaderTest.kt b/privacysandbox/sdkruntime/sdkruntime-client/src/androidTest/java/androidx/privacysandbox/sdkruntime/client/loader/SdkLoaderTest.kt
new file mode 100644
index 0000000..2c2b15d
--- /dev/null
+++ b/privacysandbox/sdkruntime/sdkruntime-client/src/androidTest/java/androidx/privacysandbox/sdkruntime/client/loader/SdkLoaderTest.kt
@@ -0,0 +1,142 @@
+/*
+ * Copyright 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package androidx.privacysandbox.sdkruntime.client.loader
+
+import android.content.Context
+import android.os.Build
+import androidx.privacysandbox.sdkruntime.client.config.LocalSdkConfig
+import androidx.privacysandbox.sdkruntime.client.config.ResourceRemappingConfig
+import androidx.privacysandbox.sdkruntime.core.LoadSdkCompatException
+import androidx.privacysandbox.sdkruntime.core.Versions
+import androidx.test.core.app.ApplicationProvider
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import androidx.test.filters.SdkSuppress
+import androidx.test.filters.SmallTest
+import androidx.testutils.assertThrows
+import com.google.common.truth.Truth.assertThat
+import java.io.File
+import org.junit.Before
+import org.junit.Test
+import org.junit.runner.RunWith
+
+@SmallTest
+@RunWith(AndroidJUnit4::class)
+class SdkLoaderTest {
+
+ private lateinit var sdkLoader: SdkLoader
+
+ private lateinit var testSdkConfig: LocalSdkConfig
+
+ @Before
+ fun setUp() {
+ val context = ApplicationProvider.getApplicationContext<Context>()
+ sdkLoader = SdkLoader.create(
+ context
+ )
+ testSdkConfig = LocalSdkConfig(
+ packageName = "androidx.privacysandbox.sdkruntime.test.v1",
+ dexPaths = listOf(
+ "RuntimeEnabledSdks/V1/classes.dex",
+ "RuntimeEnabledSdks/RPackage.dex"
+ ),
+ entryPoint = "androidx.privacysandbox.sdkruntime.test.v1.CompatProvider",
+ javaResourcesRoot = "RuntimeEnabledSdks/V1/javaresources",
+ resourceRemapping = ResourceRemappingConfig(
+ rPackageClassName = "androidx.privacysandbox.sdkruntime.test.RPackage",
+ packageId = 42
+ )
+ )
+
+ // Clean extracted SDKs between tests
+ File(context.cacheDir, "RuntimeEnabledSdk").deleteRecursively()
+ }
+
+ @Test
+ fun loadSdk_callVersionsHandShake() {
+ val loadedSdk = sdkLoader.loadSdk(testSdkConfig)
+
+ assertThat(loadedSdk.extractClientVersion())
+ .isEqualTo(Versions.API_VERSION)
+ }
+
+ @Test
+ fun testContextClassloader() {
+ val loadedSdk = sdkLoader.loadSdk(testSdkConfig)
+
+ val classLoader = loadedSdk.extractSdkProviderClassloader()
+ val sdkContext = loadedSdk.extractSdkContext()
+
+ assertThat(sdkContext.classLoader)
+ .isSameInstanceAs(classLoader)
+ }
+
+ @Test
+ fun testJavaResources() {
+ val loadedSdk = sdkLoader.loadSdk(testSdkConfig)
+
+ val classLoader = loadedSdk.extractSdkProviderClassloader()
+ val content = classLoader.getResourceAsStream("test.txt").use { inputStream ->
+ inputStream.bufferedReader().readLine()
+ }
+
+ assertThat(content)
+ .isEqualTo("test")
+ }
+
+ @Test
+ fun testRPackageUpdate() {
+ val loadedSdk = sdkLoader.loadSdk(testSdkConfig)
+
+ val classLoader = loadedSdk.extractSdkProviderClassloader()
+
+ val rPackageClass =
+ classLoader.loadClass("androidx.privacysandbox.sdkruntime.test.RPackage")
+
+ val packageIdField = rPackageClass.getDeclaredField("packageId")
+ val value = packageIdField.get(null)
+
+ assertThat(value).isEqualTo(42)
+ }
+
+ @Test
+ @SdkSuppress(maxSdkVersion = Build.VERSION_CODES.O)
+ fun testLowSpace_failPreApi27() {
+ val context = ApplicationProvider.getApplicationContext<Context>()
+ val sdkLoaderWithLowSpaceMode = SdkLoader.create(
+ context,
+ lowSpaceThreshold = Long.MAX_VALUE
+ )
+
+ assertThrows(LoadSdkCompatException::class.java) {
+ sdkLoaderWithLowSpaceMode.loadSdk(testSdkConfig)
+ }.hasMessageThat().isEqualTo("Can't use InMemoryDexClassLoader")
+ }
+
+ @Test
+ @SdkSuppress(minSdkVersion = Build.VERSION_CODES.O_MR1)
+ fun testLowSpace_notFailApi27() {
+ val sdkLoaderWithLowSpaceMode = SdkLoader.create(
+ ApplicationProvider.getApplicationContext(),
+ lowSpaceThreshold = Long.MAX_VALUE
+ )
+
+ val loadedSdk = sdkLoaderWithLowSpaceMode.loadSdk(testSdkConfig)
+ val classLoader = loadedSdk.extractSdkProviderClassloader()
+
+ val entryPointClass = classLoader.loadClass(testSdkConfig.entryPoint)
+ assertThat(entryPointClass).isNotNull()
+ }
+}
\ No newline at end of file
diff --git a/privacysandbox/sdkruntime/sdkruntime-client/src/androidTest/java/androidx/privacysandbox/sdkruntime/client/loader/storage/CachedLocalSdkStorageTest.kt b/privacysandbox/sdkruntime/sdkruntime-client/src/androidTest/java/androidx/privacysandbox/sdkruntime/client/loader/storage/CachedLocalSdkStorageTest.kt
new file mode 100644
index 0000000..428c85f
--- /dev/null
+++ b/privacysandbox/sdkruntime/sdkruntime-client/src/androidTest/java/androidx/privacysandbox/sdkruntime/client/loader/storage/CachedLocalSdkStorageTest.kt
@@ -0,0 +1,192 @@
+/*
+ * Copyright 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.privacysandbox.sdkruntime.client.loader.storage
+
+import android.content.Context
+import android.os.Environment
+import android.os.StatFs
+import androidx.privacysandbox.sdkruntime.client.config.LocalSdkConfig
+import androidx.test.core.app.ApplicationProvider
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import androidx.test.filters.SmallTest
+import androidx.testutils.assertThrows
+import com.google.common.truth.Truth.assertThat
+import java.io.File
+import java.io.FileNotFoundException
+import java.io.InputStream
+import org.junit.Before
+import org.junit.Test
+import org.junit.runner.RunWith
+
+@SmallTest
+@RunWith(AndroidJUnit4::class)
+class CachedLocalSdkStorageTest {
+
+ private lateinit var context: Context
+
+ private lateinit var storageUnderTest: CachedLocalSdkStorage
+
+ private lateinit var testSdkConfig: LocalSdkConfig
+
+ private lateinit var sdkFolder: File
+
+ @Before
+ fun setUp() {
+ context = ApplicationProvider.getApplicationContext()
+
+ storageUnderTest = CachedLocalSdkStorage.create(
+ context,
+ lowSpaceThreshold = disabledLowSpaceModeThreshold()
+ )
+
+ testSdkConfig = LocalSdkConfig(
+ packageName = "androidx.privacysandbox.sdkruntime.test.v1",
+ dexPaths = listOf(
+ "RuntimeEnabledSdks/V1/classes.dex",
+ "RuntimeEnabledSdks/RPackage.dex"
+ ),
+ entryPoint = "androidx.privacysandbox.sdkruntime.test.v1.CompatProvider",
+ )
+
+ sdkFolder = LocalSdkFolderProvider
+ .create(context)
+ .dexFolderFor(testSdkConfig)
+
+ // Clean up between tests
+ sdkFolder.deleteRecursively()
+ sdkFolder.deleteOnExit()
+ }
+
+ @Test
+ fun dexFilesFor_extractSdkDexFilesAndMakeThemReadOnly() {
+ val dexFiles = storageUnderTest.dexFilesFor(testSdkConfig)
+ assertThat(dexFiles).isNotNull()
+ val dexList = dexFiles!!.files
+
+ assertThat(dexList.size).isEqualTo(testSdkConfig.dexPaths.size)
+ for (index in testSdkConfig.dexPaths.indices) {
+ assertAssetExtractedToReadOnlyFile(testSdkConfig.dexPaths[index], dexList[index])
+ }
+ }
+
+ @Test
+ fun dexFilesFor_whenAlreadyExtracted_returnExistingFilesWithoutModification() {
+ val firstResult = storageUnderTest.dexFilesFor(testSdkConfig)!!.files
+ val lastModifiedBefore = firstResult[0].lastModified()
+
+ // Wait some time to check that no new files will be created (same lastModified)
+ Thread.sleep(100)
+
+ val secondResult = storageUnderTest.dexFilesFor(testSdkConfig)!!.files
+ val lastModifiedAfter = secondResult[0].lastModified()
+
+ assertThat(secondResult).isEqualTo(firstResult)
+ assertThat(lastModifiedAfter).isEqualTo(lastModifiedBefore)
+ }
+
+ @Test
+ fun dexFilesFor_whenFileMissing_extractOnlyThisFile() {
+ val firstResult = storageUnderTest.dexFilesFor(testSdkConfig)!!.files
+ val fileToDelete = firstResult[0]
+ val fileToKeep = firstResult[1]
+
+ fileToDelete.delete()
+ val fileToKeepLastModified = fileToKeep.lastModified()
+
+ // Wait some time to check that existing file will not be modified (same lastModified)
+ Thread.sleep(100)
+
+ val secondResult = storageUnderTest.dexFilesFor(testSdkConfig)!!.files
+ val extractedFile = secondResult[0]
+ val notModifiedFile = secondResult[1]
+
+ assertThat(secondResult).isEqualTo(firstResult)
+ assertAssetExtractedToReadOnlyFile(testSdkConfig.dexPaths[0], extractedFile)
+ assertThat(notModifiedFile.lastModified()).isEqualTo(fileToKeepLastModified)
+ }
+
+ @Test
+ fun dexFilesFor_whenLowSpaceAndNoExtractedFiles_returnNull() {
+ val storageWithLowSpaceEnabled = CachedLocalSdkStorage.create(
+ context,
+ lowSpaceThreshold = enabledLowSpaceModeThreshold()
+ )
+ val result = storageWithLowSpaceEnabled.dexFilesFor(testSdkConfig)
+ assertThat(result).isNull()
+ }
+
+ @Test
+ fun dexFilesFor_whenLowSpaceAndFilesExtractedBefore_returnExistingFiles() {
+ val extractedFiles = storageUnderTest.dexFilesFor(testSdkConfig)
+ assertThat(extractedFiles).isNotNull()
+
+ val storageWithLowSpaceEnabled = CachedLocalSdkStorage.create(
+ context,
+ lowSpaceThreshold = enabledLowSpaceModeThreshold()
+ )
+ val result = storageWithLowSpaceEnabled.dexFilesFor(testSdkConfig)
+ assertThat(result).isEqualTo(extractedFiles)
+ }
+
+ @Test
+ fun dexFilesFor_whenFailedToExtract_deleteFolderAndThrowException() {
+ val invalidConfig = LocalSdkConfig(
+ packageName = "storage.test.invalid.dexPath",
+ dexPaths = listOf("NOT_EXISTS"),
+ entryPoint = "EntryPoint"
+ )
+
+ val rootFolder = LocalSdkFolderProvider
+ .create(context)
+ .dexFolderFor(invalidConfig)
+
+ val fileToDelete = File(rootFolder, "toDelete")
+ fileToDelete.createNewFile()
+ assertThat(fileToDelete.exists()).isTrue()
+
+ assertThrows<FileNotFoundException> {
+ storageUnderTest.dexFilesFor(invalidConfig)
+ }.hasMessageThat().contains("NOT_EXISTS")
+
+ assertThat(fileToDelete.exists()).isFalse()
+ }
+
+ private fun assertAssetExtractedToReadOnlyFile(assetPath: String, outputFile: File) {
+ assertThat(outputFile.exists()).isTrue()
+ assertThat(outputFile.parentFile).isEqualTo(sdkFolder)
+ assertThat(outputFile.canWrite()).isFalse()
+
+ val assetContent = context.assets.open(assetPath).use(InputStream::readBytes)
+ val fileContent = outputFile.inputStream().use(InputStream::readBytes)
+ assertThat(fileContent).isEqualTo(assetContent)
+ }
+
+ private fun enabledLowSpaceModeThreshold(): Long =
+ availableBytes() + 10_000_000
+
+ private fun disabledLowSpaceModeThreshold(): Long =
+ availableBytes() - 10_000_000
+
+ @Suppress("DEPRECATION")
+ private fun availableBytes(): Long {
+ val path = Environment.getDataDirectory()
+ val stat = StatFs(path.path)
+ val blockSize = stat.blockSize.toLong()
+ val availableBlocks = stat.availableBlocks.toLong()
+ return availableBlocks * blockSize
+ }
+}
\ No newline at end of file
diff --git a/privacysandbox/sdkruntime/sdkruntime-client/src/androidTest/java/androidx/privacysandbox/sdkruntime/client/loader/storage/LocalSdkFolderProviderTest.kt b/privacysandbox/sdkruntime/sdkruntime-client/src/androidTest/java/androidx/privacysandbox/sdkruntime/client/loader/storage/LocalSdkFolderProviderTest.kt
new file mode 100644
index 0000000..8e06bf7
--- /dev/null
+++ b/privacysandbox/sdkruntime/sdkruntime-client/src/androidTest/java/androidx/privacysandbox/sdkruntime/client/loader/storage/LocalSdkFolderProviderTest.kt
@@ -0,0 +1,186 @@
+/*
+ * Copyright 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.privacysandbox.sdkruntime.client.loader.storage
+
+import android.content.Context
+import androidx.privacysandbox.sdkruntime.client.config.LocalSdkConfig
+import androidx.test.core.app.ApplicationProvider
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import androidx.test.filters.SmallTest
+import com.google.common.truth.Truth.assertThat
+import java.io.DataInputStream
+import java.io.DataOutputStream
+import java.io.File
+import org.junit.Before
+import org.junit.Test
+import org.junit.runner.RunWith
+
+@SmallTest
+@RunWith(AndroidJUnit4::class)
+class LocalSdkFolderProviderTest {
+
+ private lateinit var context: Context
+
+ private lateinit var sdkRootFolder: File
+ private lateinit var versionFile: File
+
+ private var appLastUpdateTime = 0L
+
+ @Before
+ fun setUp() {
+ context = ApplicationProvider.getApplicationContext()
+
+ sdkRootFolder = File(context.cacheDir, "RuntimeEnabledSdk")
+ versionFile = File(sdkRootFolder, "Folder.version")
+
+ @Suppress("DEPRECATION")
+ appLastUpdateTime =
+ context.packageManager.getPackageInfo(context.packageName, 0).lastUpdateTime
+
+ sdkRootFolder.deleteRecursively()
+ }
+
+ @Test
+ fun create_whenNoSdkRootFolder_createSdkRootFolderAndVersionFile() {
+ LocalSdkFolderProvider.create(context)
+
+ assertThat(sdkRootFolder.exists()).isTrue()
+ val version = readVersionFromFile()
+ assertThat(version).isEqualTo(appLastUpdateTime)
+ }
+
+ @Test
+ fun create_whenVersionNotChanged_doNotRemoveContents() {
+ // Initial create
+ LocalSdkFolderProvider.create(context)
+ val fileToKeep = File(sdkRootFolder, "file")
+ fileToKeep.createNewFile()
+
+ LocalSdkFolderProvider.create(context)
+
+ assertThat(fileToKeep.exists()).isTrue()
+ }
+
+ @Test
+ fun create_whenVersionChanged_deleteSdkRootFolderContentAndCreateVersionFile() {
+ val fileToDelete = createFileToDeleteInSdkRootFolder()
+ createVersionFile {
+ it.writeLong(42)
+ }
+
+ LocalSdkFolderProvider.create(context)
+
+ assertThat(fileToDelete.exists()).isFalse()
+ val version = readVersionFromFile()
+ assertThat(version).isEqualTo(appLastUpdateTime)
+ }
+
+ @Test
+ fun create_whenNoVersionFile_deleteSdkRootFolderContentAndCreateVersionFile() {
+ val fileToDelete = createFileToDeleteInSdkRootFolder()
+
+ LocalSdkFolderProvider.create(context)
+
+ assertThat(sdkRootFolder.exists()).isTrue()
+ assertThat(fileToDelete.exists()).isFalse()
+
+ val version = readVersionFromFile()
+ assertThat(version).isEqualTo(appLastUpdateTime)
+ }
+
+ @Test
+ fun create_whenInvalidVersionFile_deleteSdkRootFolderContentAndCreateVersionFile() {
+ val fileToDelete = createFileToDeleteInSdkRootFolder()
+ createVersionFile {
+ // Version is long type, byte is not enough
+ it.writeByte(1)
+ }
+
+ LocalSdkFolderProvider.create(context)
+
+ assertThat(fileToDelete.exists()).isFalse()
+ val version = readVersionFromFile()
+ assertThat(version).isEqualTo(appLastUpdateTime)
+ }
+
+ @Test
+ fun dexFolderFor_returnPathToSdkDexFolder() {
+ val sdkFolderProvider = LocalSdkFolderProvider.create(context)
+ val dexFolder = sdkFolderProvider.dexFolderFor(
+ LocalSdkConfig(
+ packageName = "com.test.sdk.package",
+ dexPaths = listOf("1.dex", "2.dex"),
+ entryPoint = "compat.sdk.provider",
+ )
+ )
+ assertThat(dexFolder.exists()).isTrue()
+ assertThat(dexFolder).isEqualTo(
+ File(sdkRootFolder, "com.test.sdk.package")
+ )
+ }
+
+ @Test
+ fun dexFolderFor_doNotRemoveExistingFiles() {
+ val sdkFolderProvider = LocalSdkFolderProvider.create(context)
+
+ val sdkConfig = LocalSdkConfig(
+ packageName = "com.test.sdk.package",
+ dexPaths = listOf("1.dex", "2.dex"),
+ entryPoint = "compat.sdk.provider",
+ )
+
+ val dexFolder = sdkFolderProvider.dexFolderFor(sdkConfig)
+
+ val fileToKeep = File(dexFolder, "testFile")
+ fileToKeep.createNewFile()
+
+ val dexFolder2 = sdkFolderProvider.dexFolderFor(sdkConfig)
+ assertThat(dexFolder).isEqualTo(dexFolder2)
+
+ assertThat(fileToKeep.exists()).isTrue()
+ }
+
+ private fun createFileToDeleteInSdkRootFolder(): File {
+ val folder = File(sdkRootFolder, "folder")
+ folder.mkdirs()
+ val file = File(folder, "file")
+ file.createNewFile()
+ file.setReadOnly()
+ assertThat(file.exists()).isTrue()
+ return file
+ }
+
+ private fun readVersionFromFile(): Long {
+ return versionFile.inputStream().use { inputStream ->
+ DataInputStream(inputStream).use { dataStream ->
+ dataStream.readLong()
+ }
+ }
+ }
+
+ private fun createVersionFile(versionWriter: (DataOutputStream) -> Unit) {
+ if (!sdkRootFolder.exists()) {
+ sdkRootFolder.mkdirs()
+ }
+ versionFile.createNewFile()
+ versionFile.outputStream().use { outputStream ->
+ DataOutputStream(outputStream).use { dataStream ->
+ versionWriter(dataStream)
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/privacysandbox/sdkruntime/sdkruntime-client/src/androidTest/java/androidx/privacysandbox/sdkruntime/client/loader/storage/TestLocalSdkStorage.kt b/privacysandbox/sdkruntime/sdkruntime-client/src/androidTest/java/androidx/privacysandbox/sdkruntime/client/loader/storage/TestLocalSdkStorage.kt
new file mode 100644
index 0000000..22cf607
--- /dev/null
+++ b/privacysandbox/sdkruntime/sdkruntime-client/src/androidTest/java/androidx/privacysandbox/sdkruntime/client/loader/storage/TestLocalSdkStorage.kt
@@ -0,0 +1,51 @@
+/*
+ * Copyright 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.privacysandbox.sdkruntime.client.loader.storage
+
+import android.content.Context
+import androidx.privacysandbox.sdkruntime.client.config.LocalSdkConfig
+import java.io.File
+
+/**
+ * Extract SDK DEX files in [rootFolder] / <packageName>.
+ */
+internal class TestLocalSdkStorage(
+ private val context: Context,
+ private val rootFolder: File
+) : LocalSdkStorage {
+ override fun dexFilesFor(sdkConfig: LocalSdkConfig): LocalSdkDexFiles {
+ val outputFolder = File(rootFolder, sdkConfig.packageName)
+ outputFolder.deleteRecursively()
+ outputFolder.mkdirs()
+
+ val fileList = buildList {
+ for (index in sdkConfig.dexPaths.indices) {
+ val dexFile = File(outputFolder, "$index.dex")
+ dexFile.createNewFile()
+ context.assets.open(sdkConfig.dexPaths[index]).use { inputStream ->
+ dexFile.outputStream().use { outputStream ->
+ inputStream.copyTo(outputStream)
+ }
+ }
+ dexFile.setReadOnly()
+ add(dexFile)
+ }
+ }
+
+ return LocalSdkDexFiles(fileList)
+ }
+}
\ No newline at end of file
diff --git a/privacysandbox/sdkruntime/sdkruntime-client/src/main/java/androidx/privacysandbox/sdkruntime/client/SdkSandboxManagerCompat.kt b/privacysandbox/sdkruntime/sdkruntime-client/src/main/java/androidx/privacysandbox/sdkruntime/client/SdkSandboxManagerCompat.kt
new file mode 100644
index 0000000..f0dddb0
--- /dev/null
+++ b/privacysandbox/sdkruntime/sdkruntime-client/src/main/java/androidx/privacysandbox/sdkruntime/client/SdkSandboxManagerCompat.kt
@@ -0,0 +1,251 @@
+/*
+ * Copyright 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package androidx.privacysandbox.sdkruntime.client
+
+import android.annotation.SuppressLint
+import android.app.sdksandbox.LoadSdkException
+import android.app.sdksandbox.SandboxedSdk
+import android.app.sdksandbox.SdkSandboxManager
+import android.content.Context
+import android.os.Bundle
+import android.os.ext.SdkExtensions.AD_SERVICES
+import androidx.annotation.DoNotInline
+import androidx.annotation.RequiresApi
+import androidx.annotation.RequiresExtension
+import androidx.core.os.asOutcomeReceiver
+import androidx.privacysandbox.sdkruntime.client.config.LocalSdkConfigsHolder
+import androidx.privacysandbox.sdkruntime.client.loader.LocalSdk
+import androidx.privacysandbox.sdkruntime.client.loader.SdkLoader
+import androidx.privacysandbox.sdkruntime.core.AdServicesInfo
+import androidx.privacysandbox.sdkruntime.core.LoadSdkCompatException
+import androidx.privacysandbox.sdkruntime.core.LoadSdkCompatException.Companion.LOAD_SDK_ALREADY_LOADED
+import androidx.privacysandbox.sdkruntime.core.LoadSdkCompatException.Companion.LOAD_SDK_NOT_FOUND
+import androidx.privacysandbox.sdkruntime.core.LoadSdkCompatException.Companion.toLoadCompatSdkException
+import androidx.privacysandbox.sdkruntime.core.SandboxedSdkCompat
+import java.util.WeakHashMap
+import kotlinx.coroutines.suspendCancellableCoroutine
+
+/**
+ * Compat version of [SdkSandboxManager].
+ *
+ * Provides APIs to load [androidx.privacysandbox.sdkruntime.core.SandboxedSdkProviderCompat]
+ * into SDK sandbox process or locally, and then interact with them.
+ *
+ * SdkSandbox process is a java process running in a separate uid range. Each app has its own
+ * SDK sandbox process.
+ *
+ * First app needs to declare SDKs it depends on in it's AndroidManifest.xml
+ * using <uses-sdk-library> tag. App can only load SDKs it depends on into the
+ * SDK sandbox process.
+ *
+ * For loading SDKs locally App need to bundle and declare local SDKs in
+ * assets/RuntimeEnabledSdkTable.xml with following format:
+ *
+ * <runtime-enabled-sdk-table>
+ * <runtime-enabled-sdk>
+ * <package-name>com.sdk1</package-name>
+ * <compat-config-path>assets/RuntimeEnabledSdk-com.sdk1/CompatSdkConfig.xml</compat-config-path>
+ * </runtime-enabled-sdk>
+ * <runtime-enabled-sdk>
+ * <package-name>com.sdk2</package-name>
+ * <compat-config-path>assets/RuntimeEnabledSdk-com.sdk2/CompatSdkConfig.xml</compat-config-path>
+ * </runtime-enabled-sdk>
+ * </runtime-enabled-sdk-table>
+ *
+ * Each local SDK should have config with following format:
+ *
+ * <compat-config>
+ * <dex-path>RuntimeEnabledSdk-sdk.package.name/dex/classes.dex</dex-path>
+ * <dex-path>RuntimeEnabledSdk-sdk.package.name/dex/classes2.dex</dex-path>
+ * <java-resources-root-path>RuntimeEnabledSdk-sdk.package.name/res</java-resources-root-path>
+ * <compat-entrypoint>com.sdk.EntryPointClass</compat-entrypoint>
+ * <resource-id-remapping>
+ * <r-package-class>com.test.sdk.RPackage</r-package-class>
+ * <resources-package-id>123</resources-package-id>
+ * </resource-id-remapping>
+ * </compat-config>
+ *
+ * @see [SdkSandboxManager]
+ */
+class SdkSandboxManagerCompat private constructor(
+ private val platformApi: PlatformApi,
+ private val configHolder: LocalSdkConfigsHolder,
+ private val sdkLoader: SdkLoader
+) {
+
+ private val localLoadedSdks = HashMap<String, LocalSdk>()
+
+ /**
+ * Load SDK in a SDK sandbox java process or locally.
+ *
+ * App should already declare SDKs it depends on in its AndroidManifest using
+ * <use-sdk-library> tag. App can only load SDKs it depends on into the SDK Sandbox process.
+ *
+ * When client application loads the first SDK, a new SdkSandbox process will be
+ * created, otherwise other SDKs will be loaded into the same sandbox which already created for
+ * the client application.
+ *
+ * Alternatively App could bundle and declare local SDKs dependencies in
+ * assets/RuntimeEnabledSdkTable.xml to load SDKs locally.
+ *
+ * This API may only be called while the caller is running in the foreground. Calls from the
+ * background will result in a [LoadSdkCompatException] being thrown.
+ *
+ * @param sdkName name of the SDK to be loaded.
+ * @param params additional parameters to be passed to the SDK in the form of a [Bundle]
+ * as agreed between the client and the SDK.
+ * @return [SandboxedSdkCompat] from SDK on a successful run.
+ * @throws [LoadSdkCompatException] on fail.
+ *
+ * @see [SdkSandboxManager.loadSdk]
+ */
+ @Throws(LoadSdkCompatException::class)
+ suspend fun loadSdk(
+ sdkName: String,
+ params: Bundle
+ ): SandboxedSdkCompat {
+ if (localLoadedSdks.containsKey(sdkName)) {
+ throw LoadSdkCompatException(LOAD_SDK_ALREADY_LOADED, "$sdkName already loaded")
+ }
+
+ val sdkConfig = configHolder.getSdkConfig(sdkName)
+ if (sdkConfig != null) {
+ val sdkHolder = sdkLoader.loadSdk(sdkConfig)
+ val sandboxedSdkCompat = sdkHolder.onLoadSdk(params)
+ localLoadedSdks.put(sdkName, sdkHolder)
+ return sandboxedSdkCompat
+ }
+
+ return platformApi.loadSdk(sdkName, params)
+ }
+
+ /**
+ * Fetches information about Sdks that are loaded in the sandbox or locally.
+ *
+ * @return List of [SandboxedSdkCompat] containing all currently loaded sdks
+ *
+ * @see [SdkSandboxManager.getSandboxedSdks]
+ */
+ fun getSandboxedSdks(): List<SandboxedSdkCompat> = platformApi.getSandboxedSdks()
+
+ private interface PlatformApi {
+ @DoNotInline
+ suspend fun loadSdk(sdkName: String, params: Bundle): SandboxedSdkCompat
+
+ @DoNotInline
+ fun getSandboxedSdks(): List<SandboxedSdkCompat> = emptyList()
+ }
+
+ // TODO(b/249981547) Remove suppress after updating to new lint version (b/262251309)
+ @SuppressLint("NewApi", "ClassVerificationFailure")
+ @RequiresExtension(extension = AD_SERVICES, version = 4)
+ private open class ApiAdServicesV4Impl(context: Context) : PlatformApi {
+ protected val sdkSandboxManager = context.getSystemService(
+ SdkSandboxManager::class.java
+ )
+
+ @DoNotInline
+ override suspend fun loadSdk(
+ sdkName: String,
+ params: Bundle
+ ): SandboxedSdkCompat {
+ try {
+ val sandboxedSdk = loadSdkInternal(sdkName, params)
+ return SandboxedSdkCompat(sandboxedSdk)
+ } catch (ex: LoadSdkException) {
+ throw toLoadCompatSdkException(ex)
+ }
+ }
+
+ private suspend fun loadSdkInternal(
+ sdkName: String,
+ params: Bundle
+ ): SandboxedSdk {
+ return suspendCancellableCoroutine { continuation ->
+ sdkSandboxManager.loadSdk(
+ sdkName,
+ params,
+ Runnable::run,
+ continuation.asOutcomeReceiver()
+ )
+ }
+ }
+ }
+
+ // TODO(b/265295473): Replace @RequiresApi with correct @RequiresExtension
+ @RequiresApi(34)
+ @SuppressLint("NewApi") // b/24998154
+ private class ApiAdServicesV5Impl(
+ context: Context
+ ) : ApiAdServicesV4Impl(context) {
+ @DoNotInline
+ override fun getSandboxedSdks(): List<SandboxedSdkCompat> {
+ return sdkSandboxManager
+ .sandboxedSdks
+ .map { platformSdk -> SandboxedSdkCompat(platformSdk) }
+ }
+ }
+
+ private class FailImpl : PlatformApi {
+ @DoNotInline
+ override suspend fun loadSdk(
+ sdkName: String,
+ params: Bundle
+ ): SandboxedSdkCompat {
+ throw LoadSdkCompatException(LOAD_SDK_NOT_FOUND, "$sdkName not bundled with app")
+ }
+ }
+
+ companion object {
+
+ private val sInstances = WeakHashMap<Context, SdkSandboxManagerCompat>()
+
+ /**
+ * Creates [SdkSandboxManagerCompat].
+ *
+ * @param context Application context
+ *
+ * @return SdkSandboxManagerCompat object.
+ */
+ @JvmStatic
+ fun from(context: Context): SdkSandboxManagerCompat {
+ synchronized(sInstances) {
+ var instance = sInstances[context]
+ if (instance == null) {
+ val configHolder = LocalSdkConfigsHolder.load(context)
+ val sdkLoader = SdkLoader.create(context)
+ val platformApi = PlatformApiFactory.create(context)
+ instance = SdkSandboxManagerCompat(platformApi, configHolder, sdkLoader)
+ sInstances[context] = instance
+ }
+ return instance
+ }
+ }
+ }
+
+ private object PlatformApiFactory {
+ @SuppressLint("NewApi") // b/24998154
+ fun create(context: Context): PlatformApi {
+ return if (AdServicesInfo.isAtLeastV5()) {
+ ApiAdServicesV5Impl(context)
+ } else if (AdServicesInfo.version() >= 4) {
+ ApiAdServicesV4Impl(context)
+ } else {
+ FailImpl()
+ }
+ }
+ }
+}
diff --git a/privacysandbox/sdkruntime/sdkruntime-client/src/main/androidx/privacysandbox/sdkruntime/androidx-privacysandbox-sdkruntime-sdkruntime-client-documentation.md b/privacysandbox/sdkruntime/sdkruntime-client/src/main/java/androidx/privacysandbox/sdkruntime/client/androidx-privacysandbox-sdkruntime-sdkruntime-client-documentation.md
similarity index 100%
rename from privacysandbox/sdkruntime/sdkruntime-client/src/main/androidx/privacysandbox/sdkruntime/androidx-privacysandbox-sdkruntime-sdkruntime-client-documentation.md
rename to privacysandbox/sdkruntime/sdkruntime-client/src/main/java/androidx/privacysandbox/sdkruntime/client/androidx-privacysandbox-sdkruntime-sdkruntime-client-documentation.md
diff --git a/privacysandbox/sdkruntime/sdkruntime-client/src/main/java/androidx/privacysandbox/sdkruntime/client/config/LocalSdkConfig.kt b/privacysandbox/sdkruntime/sdkruntime-client/src/main/java/androidx/privacysandbox/sdkruntime/client/config/LocalSdkConfig.kt
new file mode 100644
index 0000000..081acf5
--- /dev/null
+++ b/privacysandbox/sdkruntime/sdkruntime-client/src/main/java/androidx/privacysandbox/sdkruntime/client/config/LocalSdkConfig.kt
@@ -0,0 +1,33 @@
+/*
+ * Copyright 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package androidx.privacysandbox.sdkruntime.client.config
+
+/**
+ * Information required for loading SDK bundled with App.
+ *
+ */
+internal data class LocalSdkConfig(
+ val packageName: String,
+ val dexPaths: List<String>,
+ val entryPoint: String,
+ val javaResourcesRoot: String? = null,
+ val resourceRemapping: ResourceRemappingConfig? = null
+)
+
+internal data class ResourceRemappingConfig(
+ val rPackageClassName: String,
+ val packageId: Int
+)
\ No newline at end of file
diff --git a/privacysandbox/sdkruntime/sdkruntime-client/src/main/java/androidx/privacysandbox/sdkruntime/client/config/LocalSdkConfigParser.kt b/privacysandbox/sdkruntime/sdkruntime-client/src/main/java/androidx/privacysandbox/sdkruntime/client/config/LocalSdkConfigParser.kt
new file mode 100644
index 0000000..b9f10c2
--- /dev/null
+++ b/privacysandbox/sdkruntime/sdkruntime-client/src/main/java/androidx/privacysandbox/sdkruntime/client/config/LocalSdkConfigParser.kt
@@ -0,0 +1,180 @@
+/*
+ * Copyright 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package androidx.privacysandbox.sdkruntime.client.config
+
+import android.util.Xml
+import java.io.InputStream
+import org.xmlpull.v1.XmlPullParser
+import org.xmlpull.v1.XmlPullParser.END_TAG
+import org.xmlpull.v1.XmlPullParser.START_TAG
+import org.xmlpull.v1.XmlPullParserException
+
+/**
+ * Parser for SDK config.
+ *
+ * The expected XML structure is:
+ * <compat-config>
+ * <dex-path>RuntimeEnabledSdk-sdk.package.name/dex/classes.dex</dex-path>
+ * <dex-path>RuntimeEnabledSdk-sdk.package.name/dex/classes2.dex</dex-path>
+ * <java-resources-root-path>RuntimeEnabledSdk-sdk.package.name/res</java-resources-root-path>
+ * <compat-entrypoint>com.sdk.EntryPointClass</compat-entrypoint>
+ * <resource-id-remapping>
+ * <r-package-class>com.test.sdk.RPackage</r-package-class>
+ * <resources-package-id>123</resources-package-id>
+ * </resource-id-remapping>
+ * </compat-config>
+ */
+internal class LocalSdkConfigParser private constructor(
+ private val xmlParser: XmlPullParser
+) {
+
+ private fun readConfig(packageName: String): LocalSdkConfig {
+ xmlParser.require(XmlPullParser.START_DOCUMENT, NAMESPACE, null)
+ xmlParser.nextTag()
+
+ val dexPaths = mutableListOf<String>()
+ var javaResourcesRoot: String? = null
+ var entryPoint: String? = null
+ var resourceRemapping: ResourceRemappingConfig? = null
+
+ xmlParser.require(START_TAG, NAMESPACE, CONFIG_ELEMENT_NAME)
+ while (xmlParser.next() != END_TAG) {
+ if (xmlParser.eventType != START_TAG) {
+ continue
+ }
+ when (xmlParser.name) {
+ DEX_PATH_ELEMENT_NAME -> {
+ val dexPath = xmlParser.nextText()
+ dexPaths.add(dexPath)
+ }
+
+ RESOURCE_ROOT_ELEMENT_NAME -> {
+ if (javaResourcesRoot != null) {
+ throw XmlPullParserException(
+ "Duplicate $RESOURCE_ROOT_ELEMENT_NAME tag found"
+ )
+ }
+ javaResourcesRoot = xmlParser.nextText()
+ }
+
+ ENTRYPOINT_ELEMENT_NAME -> {
+ if (entryPoint != null) {
+ throw XmlPullParserException(
+ "Duplicate $ENTRYPOINT_ELEMENT_NAME tag found"
+ )
+ }
+ entryPoint = xmlParser.nextText()
+ }
+
+ RESOURCE_REMAPPING_ENTRY_ELEMENT_NAME -> {
+ if (resourceRemapping != null) {
+ throw XmlPullParserException(
+ "Duplicate $RESOURCE_REMAPPING_ENTRY_ELEMENT_NAME tag found"
+ )
+ }
+ resourceRemapping = readResourceRemappingConfig()
+ }
+
+ else -> xmlParser.skipCurrentTag()
+ }
+ }
+ xmlParser.require(END_TAG, NAMESPACE, CONFIG_ELEMENT_NAME)
+
+ if (entryPoint == null) {
+ throw XmlPullParserException("No $ENTRYPOINT_ELEMENT_NAME tag found")
+ }
+ if (dexPaths.isEmpty()) {
+ throw XmlPullParserException("No $DEX_PATH_ELEMENT_NAME tags found")
+ }
+
+ return LocalSdkConfig(
+ packageName,
+ dexPaths,
+ entryPoint,
+ javaResourcesRoot,
+ resourceRemapping
+ )
+ }
+
+ private fun readResourceRemappingConfig(): ResourceRemappingConfig {
+ var rPackageClassName: String? = null
+ var packageId: Int? = null
+
+ xmlParser.require(START_TAG, NAMESPACE, RESOURCE_REMAPPING_ENTRY_ELEMENT_NAME)
+ while (xmlParser.next() != END_TAG) {
+ if (xmlParser.eventType != START_TAG) {
+ continue
+ }
+ when (xmlParser.name) {
+ RESOURCE_REMAPPING_CLASS_ELEMENT_NAME -> {
+ if (rPackageClassName != null) {
+ throw XmlPullParserException(
+ "Duplicate $RESOURCE_REMAPPING_CLASS_ELEMENT_NAME tag found"
+ )
+ }
+ rPackageClassName = xmlParser.nextText()
+ }
+
+ RESOURCE_REMAPPING_ID_ELEMENT_NAME -> {
+ if (packageId != null) {
+ throw XmlPullParserException(
+ "Duplicate $RESOURCE_REMAPPING_ID_ELEMENT_NAME tag found"
+ )
+ }
+ packageId = xmlParser.nextText().toInt()
+ }
+
+ else -> xmlParser.skipCurrentTag()
+ }
+ }
+ xmlParser.require(END_TAG, NAMESPACE, RESOURCE_REMAPPING_ENTRY_ELEMENT_NAME)
+
+ if (rPackageClassName == null) {
+ throw XmlPullParserException(
+ "No $RESOURCE_REMAPPING_CLASS_ELEMENT_NAME tag found"
+ )
+ }
+ if (packageId == null) {
+ throw XmlPullParserException(
+ "No $RESOURCE_REMAPPING_ID_ELEMENT_NAME tag found"
+ )
+ }
+
+ return ResourceRemappingConfig(rPackageClassName, packageId)
+ }
+
+ companion object {
+ private val NAMESPACE: String? = null // We don't use namespaces
+ private const val CONFIG_ELEMENT_NAME = "compat-config"
+ private const val DEX_PATH_ELEMENT_NAME = "dex-path"
+ private const val RESOURCE_ROOT_ELEMENT_NAME = "java-resources-root-path"
+ private const val ENTRYPOINT_ELEMENT_NAME = "compat-entrypoint"
+ private const val RESOURCE_REMAPPING_ENTRY_ELEMENT_NAME = "resource-id-remapping"
+ private const val RESOURCE_REMAPPING_CLASS_ELEMENT_NAME = "r-package-class"
+ private const val RESOURCE_REMAPPING_ID_ELEMENT_NAME = "resources-package-id"
+
+ fun parse(inputStream: InputStream, packageName: String): LocalSdkConfig {
+ val parser = Xml.newPullParser()
+ try {
+ parser.setFeature(XmlPullParser.FEATURE_PROCESS_NAMESPACES, false)
+ parser.setInput(inputStream, null)
+ return LocalSdkConfigParser(parser).readConfig(packageName)
+ } finally {
+ parser.setInput(null)
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/privacysandbox/sdkruntime/sdkruntime-client/src/main/java/androidx/privacysandbox/sdkruntime/client/config/LocalSdkConfigsHolder.kt b/privacysandbox/sdkruntime/sdkruntime-client/src/main/java/androidx/privacysandbox/sdkruntime/client/config/LocalSdkConfigsHolder.kt
new file mode 100644
index 0000000..4232878
--- /dev/null
+++ b/privacysandbox/sdkruntime/sdkruntime-client/src/main/java/androidx/privacysandbox/sdkruntime/client/config/LocalSdkConfigsHolder.kt
@@ -0,0 +1,70 @@
+/*
+ * Copyright 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package androidx.privacysandbox.sdkruntime.client.config
+
+import android.content.Context
+import androidx.annotation.RestrictTo
+import java.io.FileNotFoundException
+
+/**
+ * Holds information about all SDKs bundled with App.
+ *
+ * @suppress
+ */
+@RestrictTo(RestrictTo.Scope.LIBRARY)
+internal class LocalSdkConfigsHolder private constructor(
+ private val configs: Map<String, LocalSdkConfig>
+) {
+
+ fun getSdkConfig(sdkName: String): LocalSdkConfig? {
+ return configs[sdkName]
+ }
+
+ companion object {
+ private const val SDK_TABLE_ASSET_NAME = "RuntimeEnabledSdkTable.xml"
+
+ fun load(
+ context: Context,
+ sdkTableAssetName: String = SDK_TABLE_ASSET_NAME
+ ): LocalSdkConfigsHolder {
+ val sdkTable = loadSdkTable(context, sdkTableAssetName)
+
+ val data = buildMap {
+ for ((packageName, configPath) in sdkTable) {
+ context.assets.open(configPath).use { sdkConfigAsset ->
+ val sdkInfo = LocalSdkConfigParser.parse(sdkConfigAsset, packageName)
+ put(packageName, sdkInfo)
+ }
+ }
+ }
+
+ return LocalSdkConfigsHolder(data)
+ }
+
+ private fun loadSdkTable(
+ context: Context,
+ sdkTableAssetName: String
+ ): Set<SdkTableConfigParser.SdkTableEntry> {
+ try {
+ context.assets.open(sdkTableAssetName).use { sdkTableAsset ->
+ return SdkTableConfigParser.parse(sdkTableAsset)
+ }
+ } catch (ignored: FileNotFoundException) {
+ return emptySet()
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/privacysandbox/sdkruntime/sdkruntime-client/src/main/java/androidx/privacysandbox/sdkruntime/client/config/SdkTableConfigParser.kt b/privacysandbox/sdkruntime/sdkruntime-client/src/main/java/androidx/privacysandbox/sdkruntime/client/config/SdkTableConfigParser.kt
new file mode 100644
index 0000000..eea19cc
--- /dev/null
+++ b/privacysandbox/sdkruntime/sdkruntime-client/src/main/java/androidx/privacysandbox/sdkruntime/client/config/SdkTableConfigParser.kt
@@ -0,0 +1,146 @@
+/*
+ * Copyright 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package androidx.privacysandbox.sdkruntime.client.config
+
+import android.util.Xml
+import androidx.annotation.RestrictTo
+import java.io.InputStream
+import org.xmlpull.v1.XmlPullParser
+import org.xmlpull.v1.XmlPullParser.END_TAG
+import org.xmlpull.v1.XmlPullParser.START_TAG
+import org.xmlpull.v1.XmlPullParserException
+
+/**
+ * Parser for config with paths to compat SDK configs for each SDK that bundled with app.
+ *
+ * The expected XML structure is:
+ * <runtime-enabled-sdk-table>
+ * <runtime-enabled-sdk>
+ * <package-name>com.sdk1</package-name>
+ * <compat-config-path>assets/RuntimeEnabledSdk-com.sdk1/CompatSdkConfig.xml</compat-config-path>
+ * </runtime-enabled-sdk>
+ * <runtime-enabled-sdk>
+ * <package-name>com.sdk2</package-name>
+ * <compat-config-path>assets/RuntimeEnabledSdk-com.sdk2/CompatSdkConfig.xml</compat-config-path>
+ * </runtime-enabled-sdk>
+ * </runtime-enabled-sdk-table>
+ *
+ * @suppress
+ */
+@RestrictTo(RestrictTo.Scope.LIBRARY)
+internal class SdkTableConfigParser private constructor(
+ private val xmlParser: XmlPullParser
+) {
+
+ private fun readSdkTable(): Set<SdkTableEntry> {
+ xmlParser.require(XmlPullParser.START_DOCUMENT, NAMESPACE, null)
+ xmlParser.nextTag()
+
+ val packages = mutableSetOf<String>()
+
+ return buildSet {
+ xmlParser.require(START_TAG, NAMESPACE, SDK_TABLE_ELEMENT_NAME)
+ while (xmlParser.next() != END_TAG) {
+ if (xmlParser.eventType != START_TAG) {
+ continue
+ }
+ if (xmlParser.name == SDK_ENTRY_ELEMENT_NAME) {
+ val entry = readSdkEntry()
+ if (!packages.add(entry.packageName)) {
+ throw XmlPullParserException(
+ "Duplicate entry for ${entry.packageName} found"
+ )
+ }
+ add(entry)
+ } else {
+ xmlParser.skipCurrentTag()
+ }
+ }
+ xmlParser.require(END_TAG, NAMESPACE, SDK_TABLE_ELEMENT_NAME)
+ }
+ }
+
+ private fun readSdkEntry(): SdkTableEntry {
+ var packageName: String? = null
+ var configPath: String? = null
+
+ xmlParser.require(START_TAG, NAMESPACE, SDK_ENTRY_ELEMENT_NAME)
+ while (xmlParser.next() != END_TAG) {
+ if (xmlParser.eventType != START_TAG) {
+ continue
+ }
+ when (xmlParser.name) {
+ SDK_PACKAGE_NAME_ELEMENT_NAME -> {
+ if (packageName != null) {
+ throw XmlPullParserException(
+ "Duplicate $SDK_PACKAGE_NAME_ELEMENT_NAME tag found"
+ )
+ }
+ packageName = xmlParser.nextText()
+ }
+
+ COMPAT_CONFIG_PATH_ELEMENT_NAME -> {
+ if (configPath != null) {
+ throw XmlPullParserException(
+ "Duplicate $COMPAT_CONFIG_PATH_ELEMENT_NAME tag found"
+ )
+ }
+ configPath = xmlParser.nextText()
+ }
+
+ else -> xmlParser.skipCurrentTag()
+ }
+ }
+ xmlParser.require(END_TAG, NAMESPACE, SDK_ENTRY_ELEMENT_NAME)
+
+ if (packageName == null) {
+ throw XmlPullParserException(
+ "No $SDK_PACKAGE_NAME_ELEMENT_NAME tag found"
+ )
+ }
+ if (configPath == null) {
+ throw XmlPullParserException(
+ "No $COMPAT_CONFIG_PATH_ELEMENT_NAME tag found"
+ )
+ }
+
+ return SdkTableEntry(packageName, configPath)
+ }
+
+ internal data class SdkTableEntry(
+ val packageName: String,
+ val compatConfigPath: String,
+ )
+
+ companion object {
+ private val NAMESPACE: String? = null // We don't use namespaces
+ private const val SDK_TABLE_ELEMENT_NAME = "runtime-enabled-sdk-table"
+ private const val SDK_ENTRY_ELEMENT_NAME = "runtime-enabled-sdk"
+ private const val SDK_PACKAGE_NAME_ELEMENT_NAME = "package-name"
+ private const val COMPAT_CONFIG_PATH_ELEMENT_NAME = "compat-config-path"
+
+ fun parse(inputStream: InputStream): Set<SdkTableEntry> {
+ val parser = Xml.newPullParser()
+ try {
+ parser.setFeature(XmlPullParser.FEATURE_PROCESS_NAMESPACES, false)
+ parser.setInput(inputStream, null)
+ return SdkTableConfigParser(parser).readSdkTable()
+ } finally {
+ parser.setInput(null)
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/privacysandbox/sdkruntime/sdkruntime-client/src/main/java/androidx/privacysandbox/sdkruntime/client/config/XmlUtils.kt b/privacysandbox/sdkruntime/sdkruntime-client/src/main/java/androidx/privacysandbox/sdkruntime/client/config/XmlUtils.kt
new file mode 100644
index 0000000..6a91815
--- /dev/null
+++ b/privacysandbox/sdkruntime/sdkruntime-client/src/main/java/androidx/privacysandbox/sdkruntime/client/config/XmlUtils.kt
@@ -0,0 +1,40 @@
+/*
+ * Copyright 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+@file:RestrictTo(RestrictTo.Scope.LIBRARY)
+
+package androidx.privacysandbox.sdkruntime.client.config
+
+import androidx.annotation.RestrictTo
+import org.xmlpull.v1.XmlPullParser
+import org.xmlpull.v1.XmlPullParser.END_TAG
+import org.xmlpull.v1.XmlPullParser.START_TAG
+
+/**
+ * Skip current tag (including inner tags)
+ *
+ * @suppress
+ */
+internal fun XmlPullParser.skipCurrentTag() {
+ require(START_TAG, null, null)
+ var depth = 1
+ while (depth != 0) {
+ when (next()) {
+ END_TAG -> depth--
+ START_TAG -> depth++
+ }
+ }
+}
diff --git a/privacysandbox/sdkruntime/sdkruntime-client/src/main/java/androidx/privacysandbox/sdkruntime/client/loader/FileClassLoaderFactory.kt b/privacysandbox/sdkruntime/sdkruntime-client/src/main/java/androidx/privacysandbox/sdkruntime/client/loader/FileClassLoaderFactory.kt
new file mode 100644
index 0000000..e6d8eb6
--- /dev/null
+++ b/privacysandbox/sdkruntime/sdkruntime-client/src/main/java/androidx/privacysandbox/sdkruntime/client/loader/FileClassLoaderFactory.kt
@@ -0,0 +1,86 @@
+/*
+ * Copyright 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.privacysandbox.sdkruntime.client.loader
+
+import android.util.Log
+import androidx.privacysandbox.sdkruntime.client.config.LocalSdkConfig
+import androidx.privacysandbox.sdkruntime.client.loader.storage.LocalSdkStorage
+import androidx.privacysandbox.sdkruntime.client.loader.storage.toClassPathString
+import dalvik.system.BaseDexClassLoader
+import java.io.File
+
+/**
+ * Loading SDK using BaseDexClassLoader.
+ * Using [LocalSdkStorage] to get SDK DEX files,
+ * if no files available - delegating to fallback.
+ */
+internal class FileClassLoaderFactory(
+ private val localSdkStorage: LocalSdkStorage,
+ private val fallback: SdkLoader.ClassLoaderFactory,
+) : SdkLoader.ClassLoaderFactory {
+
+ override fun createClassLoaderFor(
+ sdkConfig: LocalSdkConfig,
+ parent: ClassLoader
+ ): ClassLoader {
+ return tryCreateBaseDexClassLoaderFor(sdkConfig, parent)
+ ?: fallback.createClassLoaderFor(
+ sdkConfig,
+ parent
+ )
+ }
+
+ private fun tryCreateBaseDexClassLoaderFor(
+ sdkConfig: LocalSdkConfig,
+ parent: ClassLoader
+ ): ClassLoader? {
+ try {
+ val dexFiles = localSdkStorage.dexFilesFor(sdkConfig)
+ if (dexFiles == null) {
+ Log.w(
+ LOG_TAG,
+ "Can't use BaseDexClassLoader for ${sdkConfig.packageName} - no dexFiles"
+ )
+ return null
+ }
+
+ val optimizedDirectory = File(dexFiles.files[0].parentFile, "DexOpt")
+ if (!optimizedDirectory.exists()) {
+ optimizedDirectory.mkdirs()
+ }
+
+ return BaseDexClassLoader(
+ dexFiles.toClassPathString(),
+ optimizedDirectory,
+ /* librarySearchPath = */ null,
+ parent
+ )
+ } catch (ex: Exception) {
+ Log.e(
+ LOG_TAG,
+ "Failed to use BaseDexClassLoader for ${sdkConfig.packageName} - exception",
+ ex
+ )
+ return null
+ }
+ }
+
+ companion object {
+ const val LOG_TAG =
+ "FileClassLoaderFactory"
+ }
+}
\ No newline at end of file
diff --git a/privacysandbox/sdkruntime/sdkruntime-client/src/main/java/androidx/privacysandbox/sdkruntime/client/loader/InMemorySdkClassLoaderFactory.kt b/privacysandbox/sdkruntime/sdkruntime-client/src/main/java/androidx/privacysandbox/sdkruntime/client/loader/InMemorySdkClassLoaderFactory.kt
new file mode 100644
index 0000000..2fa4a55
--- /dev/null
+++ b/privacysandbox/sdkruntime/sdkruntime-client/src/main/java/androidx/privacysandbox/sdkruntime/client/loader/InMemorySdkClassLoaderFactory.kt
@@ -0,0 +1,87 @@
+/*
+ * Copyright 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package androidx.privacysandbox.sdkruntime.client.loader
+
+import android.content.Context
+import android.content.res.AssetManager
+import android.os.Build
+import androidx.annotation.DoNotInline
+import androidx.annotation.RequiresApi
+import androidx.privacysandbox.sdkruntime.client.config.LocalSdkConfig
+import androidx.privacysandbox.sdkruntime.core.LoadSdkCompatException
+import dalvik.system.InMemoryDexClassLoader
+import java.nio.ByteBuffer
+import java.nio.channels.Channels
+
+/**
+ * Loading SDK in memory on API 27+
+ */
+internal abstract class InMemorySdkClassLoaderFactory : SdkLoader.ClassLoaderFactory {
+
+ @RequiresApi(Build.VERSION_CODES.O_MR1)
+ internal class InMemoryImpl(
+ private val assetManager: AssetManager
+ ) : InMemorySdkClassLoaderFactory() {
+
+ @DoNotInline
+ override fun createClassLoaderFor(
+ sdkConfig: LocalSdkConfig,
+ parent: ClassLoader
+ ): ClassLoader {
+ try {
+ val buffers = arrayOfNulls<ByteBuffer>(sdkConfig.dexPaths.size)
+ for (i in sdkConfig.dexPaths.indices) {
+ assetManager.open(sdkConfig.dexPaths[i]).use { inputStream ->
+ val byteBuffer = ByteBuffer.allocate(inputStream.available())
+ Channels.newChannel(inputStream).read(byteBuffer)
+ byteBuffer.flip()
+ buffers[i] = byteBuffer
+ }
+ }
+ return InMemoryDexClassLoader(buffers, parent)
+ } catch (ex: Exception) {
+ throw LoadSdkCompatException(
+ LoadSdkCompatException.LOAD_SDK_INTERNAL_ERROR,
+ "Failed to instantiate classloader",
+ ex
+ )
+ }
+ }
+ }
+
+ internal class FailImpl : InMemorySdkClassLoaderFactory() {
+ @DoNotInline
+ override fun createClassLoaderFor(
+ sdkConfig: LocalSdkConfig,
+ parent: ClassLoader
+ ): ClassLoader {
+ throw LoadSdkCompatException(
+ LoadSdkCompatException.LOAD_SDK_SDK_SANDBOX_DISABLED,
+ "Can't use InMemoryDexClassLoader"
+ )
+ }
+ }
+
+ companion object {
+ fun create(context: Context): InMemorySdkClassLoaderFactory {
+ return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O_MR1) {
+ InMemoryImpl(context.assets)
+ } else {
+ FailImpl()
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/privacysandbox/sdkruntime/sdkruntime-client/src/main/java/androidx/privacysandbox/sdkruntime/client/loader/JavaResourcesLoadingClassLoaderFactory.kt b/privacysandbox/sdkruntime/sdkruntime-client/src/main/java/androidx/privacysandbox/sdkruntime/client/loader/JavaResourcesLoadingClassLoaderFactory.kt
new file mode 100644
index 0000000..b669af8
--- /dev/null
+++ b/privacysandbox/sdkruntime/sdkruntime-client/src/main/java/androidx/privacysandbox/sdkruntime/client/loader/JavaResourcesLoadingClassLoaderFactory.kt
@@ -0,0 +1,85 @@
+/*
+ * Copyright 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package androidx.privacysandbox.sdkruntime.client.loader
+
+import androidx.privacysandbox.sdkruntime.client.config.LocalSdkConfig
+import java.io.File
+import java.io.IOException
+import java.net.URL
+import java.util.Enumeration
+
+/**
+ * Delegate java resources related calls to app classloader.
+ *
+ * Classloaders normally delegate calls to parent classloader first, that's why this factory
+ * creates classloader that will work with java resources and pass it as parent to
+ * [codeClassLoaderFactory] thus overrides java resources for all classes loaded down the line.
+ *
+ * Add [LocalSdkConfig.javaResourcesRoot] as prefix to resource names before delegating calls,
+ * thus allowing isolating java resources for different local sdks.
+ */
+internal class JavaResourcesLoadingClassLoaderFactory(
+ private val appClassloader: ClassLoader,
+ private val codeClassLoaderFactory: SdkLoader.ClassLoaderFactory
+) : SdkLoader.ClassLoaderFactory {
+ override fun createClassLoaderFor(
+ sdkConfig: LocalSdkConfig,
+ parent: ClassLoader
+ ): ClassLoader {
+ val javaResourcesLoadingClassLoader = createJavaResourcesLoadingClassLoader(
+ sdkConfig,
+ parent
+ )
+ return codeClassLoaderFactory.createClassLoaderFor(
+ sdkConfig,
+ parent = javaResourcesLoadingClassLoader
+ )
+ }
+
+ private fun createJavaResourcesLoadingClassLoader(
+ sdkConfig: LocalSdkConfig,
+ parent: ClassLoader
+ ): ClassLoader {
+ return if (sdkConfig.javaResourcesRoot == null) {
+ parent
+ } else {
+ JavaResourcesLoadingClassLoader(
+ parent,
+ appClassloader,
+ File(ASSETS_DIR, sdkConfig.javaResourcesRoot)
+ )
+ }
+ }
+
+ private class JavaResourcesLoadingClassLoader constructor(
+ parent: ClassLoader,
+ private val appClassloader: ClassLoader,
+ private val javaResourcePrefix: File
+ ) : ClassLoader(parent) {
+ override fun findResource(name: String): URL? {
+ return appClassloader.getResource(File(javaResourcePrefix, name).path)
+ }
+
+ @Throws(IOException::class)
+ override fun findResources(name: String): Enumeration<URL> {
+ return appClassloader.getResources(File(javaResourcePrefix, name).path)
+ }
+ }
+
+ companion object {
+ const val ASSETS_DIR = "assets/"
+ }
+}
\ No newline at end of file
diff --git a/privacysandbox/sdkruntime/sdkruntime-client/src/main/java/androidx/privacysandbox/sdkruntime/client/loader/LocalSdk.kt b/privacysandbox/sdkruntime/sdkruntime-client/src/main/java/androidx/privacysandbox/sdkruntime/client/loader/LocalSdk.kt
new file mode 100644
index 0000000..0867e6e
--- /dev/null
+++ b/privacysandbox/sdkruntime/sdkruntime-client/src/main/java/androidx/privacysandbox/sdkruntime/client/loader/LocalSdk.kt
@@ -0,0 +1,37 @@
+/*
+ * Copyright 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package androidx.privacysandbox.sdkruntime.client.loader
+
+import android.os.Bundle
+import androidx.annotation.RestrictTo
+import androidx.privacysandbox.sdkruntime.core.SandboxedSdkCompat
+import org.jetbrains.annotations.TestOnly
+
+/**
+ * Provides interface for interaction with locally loaded SDK.
+ * Handle different protocol versions inside.
+ *
+ * @suppress
+ */
+@RestrictTo(RestrictTo.Scope.LIBRARY)
+internal abstract class LocalSdk protected constructor(
+ @get:TestOnly val sdkProvider: Any
+) {
+
+ abstract fun onLoadSdk(params: Bundle): SandboxedSdkCompat
+
+ abstract fun beforeUnloadSdk()
+}
\ No newline at end of file
diff --git a/privacysandbox/sdkruntime/sdkruntime-client/src/main/java/androidx/privacysandbox/sdkruntime/client/loader/ResourceRemapping.kt b/privacysandbox/sdkruntime/sdkruntime-client/src/main/java/androidx/privacysandbox/sdkruntime/client/loader/ResourceRemapping.kt
new file mode 100644
index 0000000..711d7b1
--- /dev/null
+++ b/privacysandbox/sdkruntime/sdkruntime-client/src/main/java/androidx/privacysandbox/sdkruntime/client/loader/ResourceRemapping.kt
@@ -0,0 +1,48 @@
+/*
+ * Copyright 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.privacysandbox.sdkruntime.client.loader
+
+import androidx.privacysandbox.sdkruntime.client.config.ResourceRemappingConfig
+
+/**
+ * Update RPackage.packageId for supporting Android Resource remapping for SDK.
+ * Each resource has id calculated as id = RPackage.packageId + index.
+ * Updating packageId effectively shifting all SDK resource ids in resource table.
+ * IMPORTANT: ResourceRemapping should happen before ANY interactions with R.class
+ */
+internal object ResourceRemapping {
+
+ private const val PACKAGE_ID_FIELD_NAME = "packageId"
+
+ fun apply(
+ sdkClassLoader: ClassLoader,
+ remappingConfig: ResourceRemappingConfig?
+ ) {
+ if (remappingConfig == null)
+ return
+
+ val rPackageClass = Class.forName(
+ remappingConfig.rPackageClassName,
+ /* initialize = */ false,
+ sdkClassLoader
+ )
+
+ val field = rPackageClass.getDeclaredField(PACKAGE_ID_FIELD_NAME)
+
+ field.setInt(null, remappingConfig.packageId)
+ }
+}
\ No newline at end of file
diff --git a/privacysandbox/sdkruntime/sdkruntime-client/src/main/java/androidx/privacysandbox/sdkruntime/client/loader/SdkLoader.kt b/privacysandbox/sdkruntime/sdkruntime-client/src/main/java/androidx/privacysandbox/sdkruntime/client/loader/SdkLoader.kt
new file mode 100644
index 0000000..89e3457
--- /dev/null
+++ b/privacysandbox/sdkruntime/sdkruntime-client/src/main/java/androidx/privacysandbox/sdkruntime/client/loader/SdkLoader.kt
@@ -0,0 +1,115 @@
+/*
+ * Copyright 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package androidx.privacysandbox.sdkruntime.client.loader
+
+import android.content.Context
+import androidx.privacysandbox.sdkruntime.client.config.LocalSdkConfig
+import androidx.privacysandbox.sdkruntime.client.loader.impl.SdkV1
+import androidx.privacysandbox.sdkruntime.client.loader.storage.CachedLocalSdkStorage
+import androidx.privacysandbox.sdkruntime.core.LoadSdkCompatException
+
+/**
+ * Load SDK bundled with App.
+ */
+internal class SdkLoader internal constructor(
+ private val classLoaderFactory: ClassLoaderFactory,
+ private val appContext: Context
+) {
+
+ internal interface ClassLoaderFactory {
+ fun createClassLoaderFor(sdkConfig: LocalSdkConfig, parent: ClassLoader): ClassLoader
+ }
+
+ /**
+ * Loading SDK in separate classloader:
+ * 1. Create classloader for sdk;
+ * 2. Performing handshake to determine api version;
+ * 3. (optional) Update RPackage.packageId to support Android Resource remapping for SDK
+ * 4. Select [LocalSdk] implementation that could work with that api version.
+ *
+ * @param sdkConfig sdk to load
+ * @return LocalSdk implementation for loaded SDK
+ */
+ fun loadSdk(sdkConfig: LocalSdkConfig): LocalSdk {
+ val classLoader = classLoaderFactory.createClassLoaderFor(
+ sdkConfig,
+ getParentClassLoader()
+ )
+ return createLocalSdk(classLoader, sdkConfig)
+ }
+
+ private fun getParentClassLoader(): ClassLoader = appContext.classLoader.parent!!
+
+ private fun createLocalSdk(classLoader: ClassLoader, sdkConfig: LocalSdkConfig): LocalSdk {
+ try {
+ val apiVersion = VersionHandshake.perform(classLoader)
+ ResourceRemapping.apply(classLoader, sdkConfig.resourceRemapping)
+ if (apiVersion >= 1) {
+ return SdkV1.create(classLoader, sdkConfig.entryPoint, appContext)
+ }
+ } catch (ex: Exception) {
+ throw LoadSdkCompatException(
+ LoadSdkCompatException.LOAD_SDK_INTERNAL_ERROR,
+ "Failed to instantiate local SDK",
+ ex
+ )
+ }
+
+ throw LoadSdkCompatException(
+ LoadSdkCompatException.LOAD_SDK_NOT_FOUND,
+ "Incorrect Api version"
+ )
+ }
+
+ companion object {
+ /**
+ * Build chain of [ClassLoaderFactory] that could load SDKs with their resources.
+ * Order is important because classloaders normally delegate calls to parent classloader
+ * first:
+ * 1. [JavaResourcesLoadingClassLoaderFactory] - to provide java resources to classes
+ * loaded by child classloaders;
+ * 2a. [FileClassLoaderFactory] - first trying to use factory that extracting SDK Dex
+ * to storage and load it using [dalvik.system.BaseDexClassLoader].
+ * Supports all platform versions (Api14+, minSdkVersion for library).
+ * 2b. [InMemorySdkClassLoaderFactory] - fallback for low available space. Trying to load
+ * SDK in-memory using [dalvik.system.InMemoryDexClassLoader].
+ * Supports Api27+ only, fails SDK loading on non-supported platform versions.
+ *
+ * @param context App context
+ * @param lowSpaceThreshold Minimal available space in bytes required to proceed with
+ * extracting SDK Dex files.
+ *
+ * @return SdkLoader that could load SDKs with their resources.
+ */
+ fun create(
+ context: Context,
+ lowSpaceThreshold: Long = 100 * 1024 * 1024
+ ): SdkLoader {
+ val cachedLocalSdkStorage = CachedLocalSdkStorage.create(
+ context,
+ lowSpaceThreshold
+ )
+ val classLoaderFactory = JavaResourcesLoadingClassLoaderFactory(
+ context.classLoader,
+ codeClassLoaderFactory = FileClassLoaderFactory(
+ cachedLocalSdkStorage,
+ fallback = InMemorySdkClassLoaderFactory.create(context)
+ )
+ )
+ return SdkLoader(classLoaderFactory, context)
+ }
+ }
+}
\ No newline at end of file
diff --git a/privacysandbox/sdkruntime/sdkruntime-client/src/main/java/androidx/privacysandbox/sdkruntime/client/loader/VersionHandshake.kt b/privacysandbox/sdkruntime/sdkruntime-client/src/main/java/androidx/privacysandbox/sdkruntime/client/loader/VersionHandshake.kt
new file mode 100644
index 0000000..21a6a17
--- /dev/null
+++ b/privacysandbox/sdkruntime/sdkruntime-client/src/main/java/androidx/privacysandbox/sdkruntime/client/loader/VersionHandshake.kt
@@ -0,0 +1,39 @@
+/*
+ * Copyright 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package androidx.privacysandbox.sdkruntime.client.loader
+
+import android.annotation.SuppressLint
+import androidx.annotation.RestrictTo
+import androidx.privacysandbox.sdkruntime.core.Versions
+
+/**
+ * Performing version handshake.
+ *
+ * @suppress
+ */
+@RestrictTo(RestrictTo.Scope.LIBRARY)
+internal object VersionHandshake {
+ @SuppressLint("BanUncheckedReflection") // calling method on Versions class
+ fun perform(classLoader: ClassLoader?): Int {
+ val versionsClass = Class.forName(
+ Versions::class.java.name,
+ false,
+ classLoader
+ )
+ val handShakeMethod = versionsClass.getMethod("handShake", Int::class.javaPrimitiveType)
+ return handShakeMethod.invoke(null, Versions.API_VERSION) as Int
+ }
+}
\ No newline at end of file
diff --git a/privacysandbox/sdkruntime/sdkruntime-client/src/main/java/androidx/privacysandbox/sdkruntime/client/loader/impl/SandboxedSdkContextCompat.kt b/privacysandbox/sdkruntime/sdkruntime-client/src/main/java/androidx/privacysandbox/sdkruntime/client/loader/impl/SandboxedSdkContextCompat.kt
new file mode 100644
index 0000000..4a9fd3b
--- /dev/null
+++ b/privacysandbox/sdkruntime/sdkruntime-client/src/main/java/androidx/privacysandbox/sdkruntime/client/loader/impl/SandboxedSdkContextCompat.kt
@@ -0,0 +1,35 @@
+/*
+ * Copyright 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package androidx.privacysandbox.sdkruntime.client.loader.impl
+
+import android.content.Context
+import android.content.ContextWrapper
+import androidx.annotation.RestrictTo
+
+/**
+ * Refers to the context of the SDK loaded locally.
+ *
+ * @suppress
+ */
+@RestrictTo(RestrictTo.Scope.LIBRARY)
+internal class SandboxedSdkContextCompat(
+ base: Context,
+ private val classLoader: ClassLoader?
+) : ContextWrapper(base) {
+ override fun getClassLoader(): ClassLoader? {
+ return classLoader
+ }
+}
\ No newline at end of file
diff --git a/privacysandbox/sdkruntime/sdkruntime-client/src/main/java/androidx/privacysandbox/sdkruntime/client/loader/impl/SdkV1.kt b/privacysandbox/sdkruntime/sdkruntime-client/src/main/java/androidx/privacysandbox/sdkruntime/client/loader/impl/SdkV1.kt
new file mode 100644
index 0000000..9602b3cd
--- /dev/null
+++ b/privacysandbox/sdkruntime/sdkruntime-client/src/main/java/androidx/privacysandbox/sdkruntime/client/loader/impl/SdkV1.kt
@@ -0,0 +1,174 @@
+/*
+ * Copyright 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package androidx.privacysandbox.sdkruntime.client.loader.impl
+
+import android.annotation.SuppressLint
+import android.content.Context
+import android.os.Bundle
+import android.os.IBinder
+import androidx.annotation.RestrictTo
+import androidx.privacysandbox.sdkruntime.client.loader.LocalSdk
+import androidx.privacysandbox.sdkruntime.core.LoadSdkCompatException
+import androidx.privacysandbox.sdkruntime.core.SandboxedSdkCompat
+import java.lang.reflect.InvocationTargetException
+import java.lang.reflect.Method
+
+/**
+ * Provides interface for interaction with locally loaded SDK with ApiVersion 1.
+ *
+ * @suppress
+ */
+@RestrictTo(RestrictTo.Scope.LIBRARY)
+internal class SdkV1 private constructor(
+ sdkProvider: Any,
+
+ private val onLoadSdkMethod: Method,
+ private val beforeUnloadSdkMethod: Method,
+
+ private val sandboxedSdkCompatBuilder: SandboxedSdkCompatBuilderV1,
+ private val loadSdkCompatExceptionBuilder: LoadSdkCompatExceptionBuilderV1
+) : LocalSdk(sdkProvider) {
+
+ @SuppressLint("BanUncheckedReflection") // using reflection on library classes
+ override fun onLoadSdk(params: Bundle): SandboxedSdkCompat {
+ try {
+ val rawResult = onLoadSdkMethod.invoke(sdkProvider, params)
+ return sandboxedSdkCompatBuilder.build(rawResult!!)
+ } catch (e: InvocationTargetException) {
+ throw loadSdkCompatExceptionBuilder.tryRebuildCompatException(e.targetException)
+ } catch (ex: Exception) {
+ throw LoadSdkCompatException(
+ LoadSdkCompatException.LOAD_SDK_INTERNAL_ERROR,
+ "Failed during onLoadSdk call",
+ ex
+ )
+ }
+ }
+
+ @SuppressLint("BanUncheckedReflection") // using reflection on library classes
+ override fun beforeUnloadSdk() {
+ beforeUnloadSdkMethod.invoke(sdkProvider)
+ }
+
+ internal class SandboxedSdkCompatBuilderV1 private constructor(
+ private val getInterfaceMethod: Method
+ ) {
+
+ @SuppressLint("BanUncheckedReflection") // calling method on SandboxedSdkCompat class
+ fun build(rawObject: Any): SandboxedSdkCompat {
+ val binder = getInterfaceMethod.invoke(rawObject) as IBinder
+ return SandboxedSdkCompat(binder)
+ }
+
+ companion object {
+
+ fun create(classLoader: ClassLoader?): SandboxedSdkCompatBuilderV1 {
+ val sandboxedSdkCompatClass = Class.forName(
+ SandboxedSdkCompat::class.java.name,
+ /* initialize = */ false,
+ classLoader
+ )
+ val getInterfaceMethod = sandboxedSdkCompatClass.getMethod("getInterface")
+ return SandboxedSdkCompatBuilderV1(getInterfaceMethod)
+ }
+ }
+ }
+
+ internal class LoadSdkCompatExceptionBuilderV1 private constructor(
+ private val getLoadSdkErrorCodeMethod: Method,
+ private val getExtraInformationMethod: Method
+ ) {
+ @SuppressLint("BanUncheckedReflection") // calling method on LoadSdkCompatException class
+ fun tryRebuildCompatException(rawException: Throwable): Throwable {
+ if (rawException.javaClass.name != LoadSdkCompatException::class.java.name) {
+ return rawException
+ }
+
+ return try {
+ val loadSdkErrorCode = getLoadSdkErrorCodeMethod.invoke(rawException) as Int
+ val extraInformation = getExtraInformationMethod.invoke(rawException) as Bundle
+ LoadSdkCompatException(
+ loadSdkErrorCode,
+ rawException.message,
+ rawException.cause,
+ extraInformation
+ )
+ } catch (ex: Throwable) {
+ // failed to rebuild, just wrap original
+ LoadSdkCompatException(
+ LoadSdkCompatException.LOAD_SDK_INTERNAL_ERROR,
+ "Failed to rebuild exception with error ${ex.message}",
+ rawException
+ )
+ }
+ }
+
+ companion object {
+ fun create(classLoader: ClassLoader?): LoadSdkCompatExceptionBuilderV1 {
+ val loadSdkCompatExceptionClass = Class.forName(
+ LoadSdkCompatException::class.java.name,
+ /* initialize = */ false,
+ classLoader
+ )
+ val getLoadSdkErrorCodeMethod = loadSdkCompatExceptionClass.getMethod(
+ "getLoadSdkErrorCode"
+ )
+ val getExtraInformationMethod = loadSdkCompatExceptionClass.getMethod(
+ "getExtraInformation"
+ )
+ return LoadSdkCompatExceptionBuilderV1(
+ getLoadSdkErrorCodeMethod,
+ getExtraInformationMethod
+ )
+ }
+ }
+ }
+
+ companion object {
+
+ @SuppressLint("BanUncheckedReflection") // calling method of SandboxedSdkProviderCompat
+ fun create(
+ classLoader: ClassLoader?,
+ sdkProviderClassName: String,
+ appContext: Context
+ ): SdkV1 {
+ val sdkProviderClass = Class.forName(
+ sdkProviderClassName,
+ /* initialize = */ false,
+ classLoader
+ )
+ val attachContextMethod =
+ sdkProviderClass.getMethod("attachContext", Context::class.java)
+ val onLoadSdkMethod = sdkProviderClass.getMethod("onLoadSdk", Bundle::class.java)
+ val beforeUnloadSdkMethod = sdkProviderClass.getMethod("beforeUnloadSdk")
+ val sandboxedSdkCompatBuilder = SandboxedSdkCompatBuilderV1.create(classLoader)
+ val loadSdkCompatExceptionBuilder =
+ LoadSdkCompatExceptionBuilderV1.create(classLoader)
+
+ val sdkProvider = sdkProviderClass.getConstructor().newInstance()
+ val sandboxedSdkContextCompat = SandboxedSdkContextCompat(appContext, classLoader)
+ attachContextMethod.invoke(sdkProvider, sandboxedSdkContextCompat)
+
+ return SdkV1(
+ sdkProvider,
+ onLoadSdkMethod,
+ beforeUnloadSdkMethod,
+ sandboxedSdkCompatBuilder,
+ loadSdkCompatExceptionBuilder
+ )
+ }
+ }
+}
\ No newline at end of file
diff --git a/privacysandbox/sdkruntime/sdkruntime-client/src/main/java/androidx/privacysandbox/sdkruntime/client/loader/storage/CachedLocalSdkStorage.kt b/privacysandbox/sdkruntime/sdkruntime-client/src/main/java/androidx/privacysandbox/sdkruntime/client/loader/storage/CachedLocalSdkStorage.kt
new file mode 100644
index 0000000..82251fc
--- /dev/null
+++ b/privacysandbox/sdkruntime/sdkruntime-client/src/main/java/androidx/privacysandbox/sdkruntime/client/loader/storage/CachedLocalSdkStorage.kt
@@ -0,0 +1,148 @@
+/*
+ * Copyright 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.privacysandbox.sdkruntime.client.loader.storage
+
+import android.content.Context
+import android.os.Build
+import android.os.Build.VERSION_CODES.JELLY_BEAN_MR2
+import android.os.Environment
+import android.os.StatFs
+import android.util.Log
+import androidx.annotation.DoNotInline
+import androidx.annotation.RequiresApi
+import androidx.privacysandbox.sdkruntime.client.config.LocalSdkConfig
+import java.io.File
+
+/**
+ * Caching implementation of [LocalSdkStorage].
+ *
+ * Extract SDK DEX files into folder provided by [LocalSdkFolderProvider].
+ * Not extracting new files if available space lower than lowSpaceThreshold.
+ * Return result only if all files successfully extracted.
+ */
+internal class CachedLocalSdkStorage private constructor(
+ private val context: Context,
+ private val rootFolderProvider: LocalSdkFolderProvider,
+ private val lowSpaceThreshold: Long
+) : LocalSdkStorage {
+
+ /**
+ * Return SDK DEX files from folder provided by [LocalSdkFolderProvider].
+ * Extract missing files from assets if available space bigger than lowSpaceThreshold.
+ *
+ * @param sdkConfig sdk config
+ * @return [LocalSdkDexFiles] if all SDK DEX files available in SDK folder
+ * or null if something missing and couldn't be extracted because of
+ * available space lower than lowSpaceThreshold
+ */
+ override fun dexFilesFor(sdkConfig: LocalSdkConfig): LocalSdkDexFiles? {
+ val disableExtracting = availableBytes() < lowSpaceThreshold
+ val targetFolder = rootFolderProvider.dexFolderFor(sdkConfig)
+
+ try {
+ val files = buildList {
+ for (index in sdkConfig.dexPaths.indices) {
+ val assetName = sdkConfig.dexPaths[index]
+ val outputFileName = "$index.dex"
+ val outputDexFile = File(targetFolder, outputFileName)
+
+ if (!outputDexFile.exists()) {
+ if (disableExtracting) {
+ Log.i(LOG_TAG, "Can't extract $assetName because of low space")
+ return null
+ }
+ extractAssetToFile(assetName, outputDexFile)
+ }
+
+ add(outputDexFile)
+ }
+ }
+ return LocalSdkDexFiles(files)
+ } catch (ex: Exception) {
+ Log.e(
+ LOG_TAG,
+ "Failed to extract ${sdkConfig.packageName}, deleting $targetFolder.",
+ ex
+ )
+
+ if (!targetFolder.deleteRecursively()) {
+ Log.e(
+ LOG_TAG,
+ "Failed to delete $targetFolder during cleanup.",
+ ex
+ )
+ }
+
+ throw ex
+ }
+ }
+
+ private fun extractAssetToFile(
+ assetName: String,
+ outputFile: File,
+ ) {
+ outputFile.createNewFile()
+ context.assets.open(assetName).use { fromStream ->
+ outputFile.outputStream().use { toStream ->
+ fromStream.copyTo(toStream)
+ }
+ }
+ outputFile.setReadOnly()
+ }
+
+ private fun availableBytes(): Long {
+ val dataDirectory = Environment.getDataDirectory()
+ val statFs = StatFs(dataDirectory.path)
+ if (Build.VERSION.SDK_INT >= JELLY_BEAN_MR2) {
+ return Api18Impl.availableBytes(statFs)
+ }
+
+ @Suppress("DEPRECATION")
+ val blockSize = statFs.blockSize.toLong()
+
+ @Suppress("DEPRECATION")
+ val availableBlocks = statFs.availableBlocks.toLong()
+
+ return availableBlocks * blockSize
+ }
+
+ @RequiresApi(JELLY_BEAN_MR2)
+ private object Api18Impl {
+ @DoNotInline
+ fun availableBytes(statFs: StatFs) = statFs.availableBytes
+ }
+
+ companion object {
+
+ const val LOG_TAG = "CachedLocalSdkStorage"
+
+ /**
+ * Create CachedLocalSdkStorage.
+ *
+ * @param context Application context
+ * @param lowSpaceThreshold Minimal available space in bytes required to proceed with
+ * extracting new SDK Dex files.
+ */
+ fun create(
+ context: Context,
+ lowSpaceThreshold: Long
+ ): CachedLocalSdkStorage {
+ val localSdkFolderProvider = LocalSdkFolderProvider.create(context)
+ return CachedLocalSdkStorage(context, localSdkFolderProvider, lowSpaceThreshold)
+ }
+ }
+}
\ No newline at end of file
diff --git a/privacysandbox/sdkruntime/sdkruntime-client/src/main/java/androidx/privacysandbox/sdkruntime/client/loader/storage/LocalSdkDexFiles.kt b/privacysandbox/sdkruntime/sdkruntime-client/src/main/java/androidx/privacysandbox/sdkruntime/client/loader/storage/LocalSdkDexFiles.kt
new file mode 100644
index 0000000..6cf8035
--- /dev/null
+++ b/privacysandbox/sdkruntime/sdkruntime-client/src/main/java/androidx/privacysandbox/sdkruntime/client/loader/storage/LocalSdkDexFiles.kt
@@ -0,0 +1,35 @@
+/*
+ * Copyright 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+@file:RestrictTo(RestrictTo.Scope.LIBRARY)
+
+package androidx.privacysandbox.sdkruntime.client.loader.storage
+
+import androidx.annotation.RestrictTo
+import java.io.File
+
+/**
+ * Represent SDK Dex files extracted to device storage.
+ */
+internal data class LocalSdkDexFiles(
+ val files: List<File>
+)
+
+/**
+ * Convert [LocalSdkDexFiles] to ClassPath string.
+ */
+internal fun LocalSdkDexFiles.toClassPathString() =
+ files.joinToString(separator = File.pathSeparator, transform = File::getPath)
diff --git a/privacysandbox/sdkruntime/sdkruntime-client/src/main/java/androidx/privacysandbox/sdkruntime/client/loader/storage/LocalSdkFolderProvider.kt b/privacysandbox/sdkruntime/sdkruntime-client/src/main/java/androidx/privacysandbox/sdkruntime/client/loader/storage/LocalSdkFolderProvider.kt
new file mode 100644
index 0000000..72aaffb
--- /dev/null
+++ b/privacysandbox/sdkruntime/sdkruntime-client/src/main/java/androidx/privacysandbox/sdkruntime/client/loader/storage/LocalSdkFolderProvider.kt
@@ -0,0 +1,128 @@
+/*
+ * Copyright 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.privacysandbox.sdkruntime.client.loader.storage
+
+import android.content.Context
+import android.content.pm.PackageManager
+import android.os.Build
+import android.os.Build.VERSION_CODES.TIRAMISU
+import androidx.annotation.DoNotInline
+import androidx.annotation.RequiresApi
+import androidx.privacysandbox.sdkruntime.client.config.LocalSdkConfig
+import java.io.DataInputStream
+import java.io.DataOutputStream
+import java.io.File
+
+/**
+ * Create folders for Local SDKs in ([Context.getCacheDir] / RuntimeEnabledSdk / <packageName>)
+ *
+ * Store Application update time ([android.content.pm.PackageInfo.lastUpdateTime]) in
+ * ([Context.getCacheDir] / RuntimeEnabledSdk / Folder.version) file.
+ * Remove SDK Folders if Application was updated after folders were created.
+ */
+internal class LocalSdkFolderProvider private constructor(
+ private val sdkRootFolder: File
+) {
+
+ /**
+ * Return folder on storage that should be used for storing SDK DEX files.
+ */
+ fun dexFolderFor(sdkConfig: LocalSdkConfig): File {
+ val sdkDexFolder = File(sdkRootFolder, sdkConfig.packageName)
+ if (!sdkDexFolder.exists()) {
+ sdkDexFolder.mkdirs()
+ }
+ return sdkDexFolder
+ }
+
+ companion object {
+
+ private const val SDK_ROOT_FOLDER = "RuntimeEnabledSdk"
+ private const val VERSION_FILE_NAME = "Folder.version"
+
+ /**
+ * Create LocalSdkFolderProvider.
+ *
+ * Check if current root folder created in same app installation
+ * and remove folder content if not.
+ */
+ fun create(context: Context): LocalSdkFolderProvider {
+ val sdkRootFolder = createSdkRootFolder(context)
+ return LocalSdkFolderProvider(sdkRootFolder)
+ }
+
+ private fun createSdkRootFolder(context: Context): File {
+ val rootFolder = File(context.cacheDir, SDK_ROOT_FOLDER)
+ val versionFile = File(rootFolder, VERSION_FILE_NAME)
+
+ val sdkRootFolderVersion = readVersion(versionFile)
+ val lastUpdateTime = appLastUpdateTime(context)
+
+ if (lastUpdateTime != sdkRootFolderVersion) {
+ if (rootFolder.exists()) {
+ rootFolder.deleteRecursively()
+ }
+ rootFolder.mkdirs()
+ versionFile.createNewFile()
+
+ versionFile.outputStream().use { outputStream ->
+ DataOutputStream(outputStream).use { dataStream ->
+ dataStream.writeLong(lastUpdateTime)
+ }
+ }
+ }
+
+ return rootFolder
+ }
+
+ private fun appLastUpdateTime(context: Context): Long {
+ if (Build.VERSION.SDK_INT >= TIRAMISU) {
+ return Api33Impl.getLastUpdateTime(context)
+ }
+
+ @Suppress("DEPRECATION")
+ val packageInfo = context.packageManager.getPackageInfo(context.packageName, 0)
+ return packageInfo.lastUpdateTime
+ }
+
+ private fun readVersion(versionFile: File): Long? {
+ if (!versionFile.exists()) {
+ return null
+ }
+ try {
+ versionFile.inputStream().use { inputStream ->
+ DataInputStream(inputStream).use { dataStream ->
+ return dataStream.readLong()
+ }
+ }
+ } catch (e: Exception) {
+ // Failed to parse or IOException, treat as no version file exists.
+ return null
+ }
+ }
+ }
+
+ @RequiresApi(TIRAMISU)
+ private object Api33Impl {
+ @DoNotInline
+ fun getLastUpdateTime(context: Context): Long =
+ context.packageManager.getPackageInfo(
+ context.packageName,
+ PackageManager.PackageInfoFlags.of(0)
+ ).lastUpdateTime
+ }
+}
\ No newline at end of file
diff --git a/privacysandbox/sdkruntime/sdkruntime-client/src/main/java/androidx/privacysandbox/sdkruntime/client/loader/storage/LocalSdkStorage.kt b/privacysandbox/sdkruntime/sdkruntime-client/src/main/java/androidx/privacysandbox/sdkruntime/client/loader/storage/LocalSdkStorage.kt
new file mode 100644
index 0000000..66fdab7
--- /dev/null
+++ b/privacysandbox/sdkruntime/sdkruntime-client/src/main/java/androidx/privacysandbox/sdkruntime/client/loader/storage/LocalSdkStorage.kt
@@ -0,0 +1,32 @@
+/*
+ * Copyright 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.privacysandbox.sdkruntime.client.loader.storage
+
+import androidx.privacysandbox.sdkruntime.client.config.LocalSdkConfig
+
+/**
+ * Provides interface for getting SDK related files.
+ */
+internal interface LocalSdkStorage {
+ /**
+ * Get [LocalSdkDexFiles] for bundled SDK.
+ *
+ * @param sdkConfig sdk config
+ * @return [LocalSdkDexFiles] if DEX files available or null if not.
+ */
+ fun dexFilesFor(sdkConfig: LocalSdkConfig): LocalSdkDexFiles?
+}
\ No newline at end of file
diff --git a/privacysandbox/sdkruntime/sdkruntime-client/src/test/java/androidx/privacysandbox/sdkruntime/client/loader/ResourceRemappingTest.kt b/privacysandbox/sdkruntime/sdkruntime-client/src/test/java/androidx/privacysandbox/sdkruntime/client/loader/ResourceRemappingTest.kt
new file mode 100644
index 0000000..cb17a81
--- /dev/null
+++ b/privacysandbox/sdkruntime/sdkruntime-client/src/test/java/androidx/privacysandbox/sdkruntime/client/loader/ResourceRemappingTest.kt
@@ -0,0 +1,149 @@
+/*
+ * Copyright 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.privacysandbox.sdkruntime.client.loader
+
+import androidx.privacysandbox.sdkruntime.client.config.ResourceRemappingConfig
+import androidx.room.compiler.processing.util.Source
+import androidx.room.compiler.processing.util.compiler.TestCompilationArguments
+import androidx.room.compiler.processing.util.compiler.compile
+import com.google.common.truth.Truth.assertThat
+import java.net.URLClassLoader
+import kotlin.reflect.KClass
+import org.junit.Assert.assertThrows
+import org.junit.Rule
+import org.junit.Test
+import org.junit.rules.TemporaryFolder
+import org.junit.runner.RunWith
+import org.junit.runners.JUnit4
+
+@RunWith(JUnit4::class)
+class ResourceRemappingTest {
+
+ @field:Rule
+ @JvmField
+ val temporaryFolder = TemporaryFolder()
+
+ @Test
+ fun apply_whenNonNullConfig_updatePackageId() {
+ val classLoader = compileAndLoad(
+ Source.java(
+ "RPackage", """
+ public class RPackage {
+ public static int packageId = 0;
+ }
+ """
+ )
+ )
+
+ ResourceRemapping.apply(
+ classLoader,
+ ResourceRemappingConfig(
+ rPackageClassName = "RPackage",
+ packageId = 42
+ )
+ )
+
+ val rPackageClass = classLoader.loadClass("RPackage")
+ val packageIdField = rPackageClass.getDeclaredField("packageId")
+ val value = packageIdField.getInt(null)
+
+ assertThat(value).isEqualTo(42)
+ }
+
+ @Test
+ fun apply_whenNullConfig_doesntThrow() {
+ val classLoader = compileAndLoad(
+ Source.java(
+ "AnotherClass", """
+ public class AnotherClass {
+ }
+ """
+ )
+ )
+
+ ResourceRemapping.apply(
+ classLoader,
+ remappingConfig = null
+ )
+ }
+
+ @Test
+ fun apply_whenNoRPackageClass_throwsClassNotFoundException() {
+ val source = Source.java(
+ "AnotherClass", """
+ public class AnotherClass {
+ }
+ """
+ )
+
+ val config = ResourceRemappingConfig(
+ rPackageClassName = "RPackage",
+ packageId = 42
+ )
+
+ assertThrows(ClassNotFoundException::class, source, config)
+ }
+
+ @Test
+ fun apply_whenNoPackageIdField_throwsNoSuchFieldException() {
+ val source = Source.java(
+ "RPackage", """
+ public class RPackage {
+ }
+ """
+ )
+
+ val config = ResourceRemappingConfig(
+ rPackageClassName = "RPackage",
+ packageId = 42
+ )
+
+ assertThrows(NoSuchFieldException::class, source, config)
+ }
+
+ private fun assertThrows(
+ expectedThrowable: KClass<out Exception>,
+ source: Source,
+ config: ResourceRemappingConfig
+ ) {
+ val classLoader = compileAndLoad(source)
+ assertThrows(expectedThrowable.java) {
+ ResourceRemapping.apply(
+ classLoader,
+ config
+ )
+ }
+ }
+
+ private fun compileAndLoad(source: Source): ClassLoader {
+ val compilationResult = compile(
+ temporaryFolder.root,
+ TestCompilationArguments(
+ sources = listOf(source),
+ )
+ )
+
+ assertThat(compilationResult.success).isTrue()
+
+ return URLClassLoader.newInstance(
+ compilationResult.outputClasspath.map {
+ it.toURI().toURL()
+ }.toTypedArray(),
+ /* parent = */ null
+ )
+ }
+}
\ No newline at end of file
diff --git a/privacysandbox/sdkruntime/sdkruntime-core/api/current.txt b/privacysandbox/sdkruntime/sdkruntime-core/api/current.txt
index e6f50d0..ffefc096 100644
--- a/privacysandbox/sdkruntime/sdkruntime-core/api/current.txt
+++ b/privacysandbox/sdkruntime/sdkruntime-core/api/current.txt
@@ -1 +1,73 @@
// Signature format: 4.0
+package androidx.privacysandbox.sdkruntime.core {
+
+ public final class LoadSdkCompatException extends java.lang.Exception {
+ ctor public LoadSdkCompatException(Throwable cause, android.os.Bundle extraInfo);
+ method public android.os.Bundle getExtraInformation();
+ method public int getLoadSdkErrorCode();
+ property public final android.os.Bundle extraInformation;
+ property public final int loadSdkErrorCode;
+ field public static final androidx.privacysandbox.sdkruntime.core.LoadSdkCompatException.Companion Companion;
+ field public static final int LOAD_SDK_ALREADY_LOADED = 101; // 0x65
+ field public static final int LOAD_SDK_INTERNAL_ERROR = 500; // 0x1f4
+ field public static final int LOAD_SDK_NOT_FOUND = 100; // 0x64
+ field public static final int LOAD_SDK_SDK_DEFINED_ERROR = 102; // 0x66
+ field public static final int LOAD_SDK_SDK_SANDBOX_DISABLED = 103; // 0x67
+ field public static final int SDK_SANDBOX_PROCESS_NOT_AVAILABLE = 503; // 0x1f7
+ }
+
+ public static final class LoadSdkCompatException.Companion {
+ }
+
+ public final class SandboxedSdkCompat {
+ ctor public SandboxedSdkCompat(android.os.IBinder sdkInterface);
+ method public static androidx.privacysandbox.sdkruntime.core.SandboxedSdkCompat create(android.os.IBinder binder);
+ method public android.os.IBinder? getInterface();
+ method public androidx.privacysandbox.sdkruntime.core.SandboxedSdkInfo? getSdkInfo();
+ field public static final androidx.privacysandbox.sdkruntime.core.SandboxedSdkCompat.Companion Companion;
+ }
+
+ public static final class SandboxedSdkCompat.Companion {
+ method public androidx.privacysandbox.sdkruntime.core.SandboxedSdkCompat create(android.os.IBinder binder);
+ }
+
+ public final class SandboxedSdkInfo {
+ ctor public SandboxedSdkInfo(String name, long version);
+ method public String getName();
+ method public long getVersion();
+ property public final String name;
+ property public final long version;
+ }
+
+ @RequiresExtension(extension=android.os.ext.SdkExtensions.AD_SERVICES, version=4) public final class SandboxedSdkProviderAdapter extends android.app.sdksandbox.SandboxedSdkProvider {
+ ctor public SandboxedSdkProviderAdapter();
+ method public android.view.View getView(android.content.Context windowContext, android.os.Bundle params, int width, int height);
+ method @kotlin.jvm.Throws(exceptionClasses=LoadSdkException::class) public android.app.sdksandbox.SandboxedSdk onLoadSdk(android.os.Bundle params) throws android.app.sdksandbox.LoadSdkException;
+ }
+
+ public abstract class SandboxedSdkProviderCompat {
+ ctor public SandboxedSdkProviderCompat();
+ method public final void attachContext(android.content.Context context);
+ method public void beforeUnloadSdk();
+ method public final android.content.Context? getContext();
+ method public abstract android.view.View getView(android.content.Context windowContext, android.os.Bundle params, int width, int height);
+ method @kotlin.jvm.Throws(exceptionClasses=LoadSdkCompatException::class) public abstract androidx.privacysandbox.sdkruntime.core.SandboxedSdkCompat onLoadSdk(android.os.Bundle params) throws androidx.privacysandbox.sdkruntime.core.LoadSdkCompatException;
+ property public final android.content.Context? context;
+ }
+
+}
+
+package androidx.privacysandbox.sdkruntime.core.controller {
+
+ public final class SdkSandboxControllerCompat {
+ method public static androidx.privacysandbox.sdkruntime.core.controller.SdkSandboxControllerCompat from(android.content.Context context);
+ method public java.util.List<androidx.privacysandbox.sdkruntime.core.SandboxedSdkCompat> getSandboxedSdks();
+ field public static final androidx.privacysandbox.sdkruntime.core.controller.SdkSandboxControllerCompat.Companion Companion;
+ }
+
+ public static final class SdkSandboxControllerCompat.Companion {
+ method public androidx.privacysandbox.sdkruntime.core.controller.SdkSandboxControllerCompat from(android.content.Context context);
+ }
+
+}
+
diff --git a/privacysandbox/sdkruntime/sdkruntime-core/api/public_plus_experimental_current.txt b/privacysandbox/sdkruntime/sdkruntime-core/api/public_plus_experimental_current.txt
index e6f50d0..ffefc096 100644
--- a/privacysandbox/sdkruntime/sdkruntime-core/api/public_plus_experimental_current.txt
+++ b/privacysandbox/sdkruntime/sdkruntime-core/api/public_plus_experimental_current.txt
@@ -1 +1,73 @@
// Signature format: 4.0
+package androidx.privacysandbox.sdkruntime.core {
+
+ public final class LoadSdkCompatException extends java.lang.Exception {
+ ctor public LoadSdkCompatException(Throwable cause, android.os.Bundle extraInfo);
+ method public android.os.Bundle getExtraInformation();
+ method public int getLoadSdkErrorCode();
+ property public final android.os.Bundle extraInformation;
+ property public final int loadSdkErrorCode;
+ field public static final androidx.privacysandbox.sdkruntime.core.LoadSdkCompatException.Companion Companion;
+ field public static final int LOAD_SDK_ALREADY_LOADED = 101; // 0x65
+ field public static final int LOAD_SDK_INTERNAL_ERROR = 500; // 0x1f4
+ field public static final int LOAD_SDK_NOT_FOUND = 100; // 0x64
+ field public static final int LOAD_SDK_SDK_DEFINED_ERROR = 102; // 0x66
+ field public static final int LOAD_SDK_SDK_SANDBOX_DISABLED = 103; // 0x67
+ field public static final int SDK_SANDBOX_PROCESS_NOT_AVAILABLE = 503; // 0x1f7
+ }
+
+ public static final class LoadSdkCompatException.Companion {
+ }
+
+ public final class SandboxedSdkCompat {
+ ctor public SandboxedSdkCompat(android.os.IBinder sdkInterface);
+ method public static androidx.privacysandbox.sdkruntime.core.SandboxedSdkCompat create(android.os.IBinder binder);
+ method public android.os.IBinder? getInterface();
+ method public androidx.privacysandbox.sdkruntime.core.SandboxedSdkInfo? getSdkInfo();
+ field public static final androidx.privacysandbox.sdkruntime.core.SandboxedSdkCompat.Companion Companion;
+ }
+
+ public static final class SandboxedSdkCompat.Companion {
+ method public androidx.privacysandbox.sdkruntime.core.SandboxedSdkCompat create(android.os.IBinder binder);
+ }
+
+ public final class SandboxedSdkInfo {
+ ctor public SandboxedSdkInfo(String name, long version);
+ method public String getName();
+ method public long getVersion();
+ property public final String name;
+ property public final long version;
+ }
+
+ @RequiresExtension(extension=android.os.ext.SdkExtensions.AD_SERVICES, version=4) public final class SandboxedSdkProviderAdapter extends android.app.sdksandbox.SandboxedSdkProvider {
+ ctor public SandboxedSdkProviderAdapter();
+ method public android.view.View getView(android.content.Context windowContext, android.os.Bundle params, int width, int height);
+ method @kotlin.jvm.Throws(exceptionClasses=LoadSdkException::class) public android.app.sdksandbox.SandboxedSdk onLoadSdk(android.os.Bundle params) throws android.app.sdksandbox.LoadSdkException;
+ }
+
+ public abstract class SandboxedSdkProviderCompat {
+ ctor public SandboxedSdkProviderCompat();
+ method public final void attachContext(android.content.Context context);
+ method public void beforeUnloadSdk();
+ method public final android.content.Context? getContext();
+ method public abstract android.view.View getView(android.content.Context windowContext, android.os.Bundle params, int width, int height);
+ method @kotlin.jvm.Throws(exceptionClasses=LoadSdkCompatException::class) public abstract androidx.privacysandbox.sdkruntime.core.SandboxedSdkCompat onLoadSdk(android.os.Bundle params) throws androidx.privacysandbox.sdkruntime.core.LoadSdkCompatException;
+ property public final android.content.Context? context;
+ }
+
+}
+
+package androidx.privacysandbox.sdkruntime.core.controller {
+
+ public final class SdkSandboxControllerCompat {
+ method public static androidx.privacysandbox.sdkruntime.core.controller.SdkSandboxControllerCompat from(android.content.Context context);
+ method public java.util.List<androidx.privacysandbox.sdkruntime.core.SandboxedSdkCompat> getSandboxedSdks();
+ field public static final androidx.privacysandbox.sdkruntime.core.controller.SdkSandboxControllerCompat.Companion Companion;
+ }
+
+ public static final class SdkSandboxControllerCompat.Companion {
+ method public androidx.privacysandbox.sdkruntime.core.controller.SdkSandboxControllerCompat from(android.content.Context context);
+ }
+
+}
+
diff --git a/privacysandbox/sdkruntime/sdkruntime-core/api/restricted_current.txt b/privacysandbox/sdkruntime/sdkruntime-core/api/restricted_current.txt
index e6f50d0..ffefc096 100644
--- a/privacysandbox/sdkruntime/sdkruntime-core/api/restricted_current.txt
+++ b/privacysandbox/sdkruntime/sdkruntime-core/api/restricted_current.txt
@@ -1 +1,73 @@
// Signature format: 4.0
+package androidx.privacysandbox.sdkruntime.core {
+
+ public final class LoadSdkCompatException extends java.lang.Exception {
+ ctor public LoadSdkCompatException(Throwable cause, android.os.Bundle extraInfo);
+ method public android.os.Bundle getExtraInformation();
+ method public int getLoadSdkErrorCode();
+ property public final android.os.Bundle extraInformation;
+ property public final int loadSdkErrorCode;
+ field public static final androidx.privacysandbox.sdkruntime.core.LoadSdkCompatException.Companion Companion;
+ field public static final int LOAD_SDK_ALREADY_LOADED = 101; // 0x65
+ field public static final int LOAD_SDK_INTERNAL_ERROR = 500; // 0x1f4
+ field public static final int LOAD_SDK_NOT_FOUND = 100; // 0x64
+ field public static final int LOAD_SDK_SDK_DEFINED_ERROR = 102; // 0x66
+ field public static final int LOAD_SDK_SDK_SANDBOX_DISABLED = 103; // 0x67
+ field public static final int SDK_SANDBOX_PROCESS_NOT_AVAILABLE = 503; // 0x1f7
+ }
+
+ public static final class LoadSdkCompatException.Companion {
+ }
+
+ public final class SandboxedSdkCompat {
+ ctor public SandboxedSdkCompat(android.os.IBinder sdkInterface);
+ method public static androidx.privacysandbox.sdkruntime.core.SandboxedSdkCompat create(android.os.IBinder binder);
+ method public android.os.IBinder? getInterface();
+ method public androidx.privacysandbox.sdkruntime.core.SandboxedSdkInfo? getSdkInfo();
+ field public static final androidx.privacysandbox.sdkruntime.core.SandboxedSdkCompat.Companion Companion;
+ }
+
+ public static final class SandboxedSdkCompat.Companion {
+ method public androidx.privacysandbox.sdkruntime.core.SandboxedSdkCompat create(android.os.IBinder binder);
+ }
+
+ public final class SandboxedSdkInfo {
+ ctor public SandboxedSdkInfo(String name, long version);
+ method public String getName();
+ method public long getVersion();
+ property public final String name;
+ property public final long version;
+ }
+
+ @RequiresExtension(extension=android.os.ext.SdkExtensions.AD_SERVICES, version=4) public final class SandboxedSdkProviderAdapter extends android.app.sdksandbox.SandboxedSdkProvider {
+ ctor public SandboxedSdkProviderAdapter();
+ method public android.view.View getView(android.content.Context windowContext, android.os.Bundle params, int width, int height);
+ method @kotlin.jvm.Throws(exceptionClasses=LoadSdkException::class) public android.app.sdksandbox.SandboxedSdk onLoadSdk(android.os.Bundle params) throws android.app.sdksandbox.LoadSdkException;
+ }
+
+ public abstract class SandboxedSdkProviderCompat {
+ ctor public SandboxedSdkProviderCompat();
+ method public final void attachContext(android.content.Context context);
+ method public void beforeUnloadSdk();
+ method public final android.content.Context? getContext();
+ method public abstract android.view.View getView(android.content.Context windowContext, android.os.Bundle params, int width, int height);
+ method @kotlin.jvm.Throws(exceptionClasses=LoadSdkCompatException::class) public abstract androidx.privacysandbox.sdkruntime.core.SandboxedSdkCompat onLoadSdk(android.os.Bundle params) throws androidx.privacysandbox.sdkruntime.core.LoadSdkCompatException;
+ property public final android.content.Context? context;
+ }
+
+}
+
+package androidx.privacysandbox.sdkruntime.core.controller {
+
+ public final class SdkSandboxControllerCompat {
+ method public static androidx.privacysandbox.sdkruntime.core.controller.SdkSandboxControllerCompat from(android.content.Context context);
+ method public java.util.List<androidx.privacysandbox.sdkruntime.core.SandboxedSdkCompat> getSandboxedSdks();
+ field public static final androidx.privacysandbox.sdkruntime.core.controller.SdkSandboxControllerCompat.Companion Companion;
+ }
+
+ public static final class SdkSandboxControllerCompat.Companion {
+ method public androidx.privacysandbox.sdkruntime.core.controller.SdkSandboxControllerCompat from(android.content.Context context);
+ }
+
+}
+
diff --git a/privacysandbox/sdkruntime/sdkruntime-core/build.gradle b/privacysandbox/sdkruntime/sdkruntime-core/build.gradle
index bbd8542..4d44983 100644
--- a/privacysandbox/sdkruntime/sdkruntime-core/build.gradle
+++ b/privacysandbox/sdkruntime/sdkruntime-core/build.gradle
@@ -24,9 +24,28 @@
dependencies {
api(libs.kotlinStdlib)
+ api(projectOrArtifact(":annotation:annotation"))
+
+ implementation("androidx.core:core:1.8.0")
+
+ // TODO(b/249982004): cleanup dependencies
+ androidTestImplementation(libs.testCore)
+ androidTestImplementation(libs.testExtJunit)
+ androidTestImplementation(libs.testRunner)
+ androidTestImplementation(libs.testRules)
+ androidTestImplementation(libs.truth)
+ androidTestImplementation(libs.junit)
+
+ androidTestImplementation(libs.mockitoCore, excludes.bytebuddy) // DexMaker has it"s own MockMaker
+ androidTestImplementation(libs.dexmakerMockitoInline, excludes.bytebuddy) // DexMaker has it"s own MockMaker
}
android {
+ lintOptions {
+ // All components could be loaded from another app via client library
+ disable("BanKeepAnnotation")
+ }
+
namespace "androidx.privacysandbox.sdkruntime.core"
}
diff --git a/privacysandbox/sdkruntime/sdkruntime-core/src/androidTest/AndroidManifest.xml b/privacysandbox/sdkruntime/sdkruntime-core/src/androidTest/AndroidManifest.xml
new file mode 100644
index 0000000..3f2e804
--- /dev/null
+++ b/privacysandbox/sdkruntime/sdkruntime-core/src/androidTest/AndroidManifest.xml
@@ -0,0 +1,18 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright 2022 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+<manifest xmlns:android="http://schemas.android.com/apk/res/android">
+</manifest>
\ No newline at end of file
diff --git a/privacysandbox/sdkruntime/sdkruntime-core/src/androidTest/assets/SandboxedSdkProviderCompatClassName.txt b/privacysandbox/sdkruntime/sdkruntime-core/src/androidTest/assets/SandboxedSdkProviderCompatClassName.txt
new file mode 100644
index 0000000..3d062e4
--- /dev/null
+++ b/privacysandbox/sdkruntime/sdkruntime-core/src/androidTest/assets/SandboxedSdkProviderCompatClassName.txt
@@ -0,0 +1 @@
+androidx.privacysandbox.sdkruntime.core.SandboxedSdkProviderAdapterTest$TestOnLoadReturnResultSdkProvider
\ No newline at end of file
diff --git a/privacysandbox/sdkruntime/sdkruntime-core/src/androidTest/java/androidx/privacysandbox/sdkruntime/core/LoadSdkCompatExceptionTest.kt b/privacysandbox/sdkruntime/sdkruntime-core/src/androidTest/java/androidx/privacysandbox/sdkruntime/core/LoadSdkCompatExceptionTest.kt
new file mode 100644
index 0000000..9235febc
--- /dev/null
+++ b/privacysandbox/sdkruntime/sdkruntime-core/src/androidTest/java/androidx/privacysandbox/sdkruntime/core/LoadSdkCompatExceptionTest.kt
@@ -0,0 +1,81 @@
+/*
+ * Copyright 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package androidx.privacysandbox.sdkruntime.core
+
+import android.annotation.SuppressLint
+import android.app.sdksandbox.LoadSdkException
+import android.os.Build.VERSION_CODES.TIRAMISU
+import android.os.Bundle
+import android.os.ext.SdkExtensions.AD_SERVICES
+import androidx.annotation.RequiresExtension
+import androidx.privacysandbox.sdkruntime.core.LoadSdkCompatException.Companion.toLoadCompatSdkException
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import androidx.test.filters.SdkSuppress
+import androidx.test.filters.SmallTest
+import com.google.common.truth.Truth.assertThat
+import org.junit.Assume.assumeTrue
+import org.junit.Before
+import org.junit.Test
+import org.junit.runner.RunWith
+
+@SmallTest
+@RunWith(AndroidJUnit4::class)
+// TODO(b/249981547) Remove suppress after updating to new lint version (b/262251309)
+@SuppressLint("NewApi")
+// TODO(b/262577044) Remove RequiresExtension after extensions support in @SdkSuppress
+@RequiresExtension(extension = AD_SERVICES, version = 4)
+@SdkSuppress(minSdkVersion = TIRAMISU)
+class LoadSdkCompatExceptionTest {
+
+ @Before
+ fun setUp() {
+ assumeTrue("Requires Sandbox API available", isSandboxApiAvailable())
+ }
+
+ @Test
+ fun toLoadSdkException_returnLoadSdkException() {
+ val loadSdkCompatException = LoadSdkCompatException(RuntimeException(), Bundle())
+
+ val loadSdkException = loadSdkCompatException.toLoadSdkException()
+
+ assertThat(loadSdkException.cause)
+ .isSameInstanceAs(loadSdkCompatException.cause)
+ assertThat(loadSdkException.extraInformation)
+ .isSameInstanceAs(loadSdkCompatException.extraInformation)
+ assertThat(loadSdkException.loadSdkErrorCode)
+ .isEqualTo(loadSdkCompatException.loadSdkErrorCode)
+ }
+
+ @Test
+ fun toLoadCompatSdkException_returnLoadCompatSdkException() {
+ val loadSdkException = LoadSdkException(
+ RuntimeException(),
+ Bundle()
+ )
+
+ val loadCompatSdkException = toLoadCompatSdkException(loadSdkException)
+
+ assertThat(loadCompatSdkException.cause)
+ .isSameInstanceAs(loadSdkException.cause)
+ assertThat(loadCompatSdkException.extraInformation)
+ .isSameInstanceAs(loadSdkException.extraInformation)
+ assertThat(loadCompatSdkException.loadSdkErrorCode)
+ .isEqualTo(loadSdkException.loadSdkErrorCode)
+ }
+
+ private fun isSandboxApiAvailable() =
+ AdServicesInfo.version() >= 4
+}
\ No newline at end of file
diff --git a/privacysandbox/sdkruntime/sdkruntime-core/src/androidTest/java/androidx/privacysandbox/sdkruntime/core/SandboxedSdkCompatTest.kt b/privacysandbox/sdkruntime/sdkruntime-core/src/androidTest/java/androidx/privacysandbox/sdkruntime/core/SandboxedSdkCompatTest.kt
new file mode 100644
index 0000000..2f8a0dc
--- /dev/null
+++ b/privacysandbox/sdkruntime/sdkruntime-core/src/androidTest/java/androidx/privacysandbox/sdkruntime/core/SandboxedSdkCompatTest.kt
@@ -0,0 +1,177 @@
+/*
+ * Copyright 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package androidx.privacysandbox.sdkruntime.core
+
+import android.annotation.SuppressLint
+import android.app.sdksandbox.SandboxedSdk
+import android.content.pm.SharedLibraryInfo
+import android.os.Binder
+import android.os.Build.VERSION_CODES.TIRAMISU
+import android.os.ext.SdkExtensions
+import androidx.annotation.RequiresApi
+import androidx.annotation.RequiresExtension
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import androidx.test.filters.SdkSuppress
+import androidx.test.filters.SmallTest
+import com.google.common.truth.Truth.assertThat
+import org.junit.Assume.assumeFalse
+import org.junit.Assume.assumeTrue
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.mockito.Mockito
+import org.mockito.Mockito.doReturn
+import org.mockito.Mockito.spy
+import org.mockito.Mockito.`when`
+
+@SmallTest
+@RunWith(AndroidJUnit4::class)
+class SandboxedSdkCompatTest {
+
+ @Test
+ fun getInterface_returnsBinderPassedToCreate() {
+ val binder = Binder()
+
+ val sandboxedSdkCompat = SandboxedSdkCompat(binder)
+
+ assertThat(sandboxedSdkCompat.getInterface())
+ .isSameInstanceAs(binder)
+ }
+
+ @Test
+ // TODO(b/249981547) Remove suppress after updating to new lint version (b/262251309)
+ @SuppressLint("NewApi")
+ // TODO(b/262577044) Remove RequiresExtension after extensions support in @SdkSuppress
+ @RequiresExtension(extension = SdkExtensions.AD_SERVICES, version = 4)
+ @SdkSuppress(minSdkVersion = TIRAMISU)
+ fun toSandboxedSdk_whenCreatedFromBinder_returnsSandboxedSdkWithSameBinder() {
+ assumeTrue("Requires Sandbox API available", isSandboxApiAvailable())
+
+ val binder = Binder()
+
+ val toSandboxedSdkResult = SandboxedSdkCompat(binder).toSandboxedSdk()
+
+ assertThat(toSandboxedSdkResult.getInterface())
+ .isSameInstanceAs(binder)
+ }
+
+ @Test
+ // TODO(b/249981547) Remove suppress after updating to new lint version (b/262251309)
+ @SuppressLint("NewApi")
+ // TODO(b/262577044) Remove RequiresExtension after extensions support in @SdkSuppress
+ @RequiresExtension(extension = SdkExtensions.AD_SERVICES, version = 4)
+ @SdkSuppress(minSdkVersion = TIRAMISU)
+ fun toSandboxedSdk_whenCreatedFromSandboxedSdk_returnsSameSandboxedSdk() {
+ assumeTrue("Requires Sandbox API available", isSandboxApiAvailable())
+
+ val binder = Binder()
+ val sandboxedSdk = SandboxedSdk(binder)
+
+ val toSandboxedSdkResult = SandboxedSdkCompat(sandboxedSdk).toSandboxedSdk()
+
+ assertThat(toSandboxedSdkResult)
+ .isSameInstanceAs(sandboxedSdk)
+ }
+
+ @Test
+ fun getSdkInfo_whenCreatedFromBinder_returnsNull() {
+ val binder = Binder()
+ val sandboxedSdkCompat = SandboxedSdkCompat(binder)
+
+ assertThat(sandboxedSdkCompat.getSdkInfo()).isNull()
+ }
+
+ @Test
+ // TODO(b/249981547) Remove suppress after updating to new lint version (b/262251309)
+ @SuppressLint("NewApi")
+ // TODO(b/262577044) Remove RequiresExtension after extensions support in @SdkSuppress
+ @RequiresExtension(extension = SdkExtensions.AD_SERVICES, version = 4)
+ @SdkSuppress(minSdkVersion = TIRAMISU)
+ fun getSdkInfo_whenCreatedFromSandboxedSdkAndNoSharedLibraryInfo_returnsNull() {
+ assumeTrue("Requires Sandbox API available", isSandboxApiAvailable())
+ assumeFalse(
+ "Requires SharedLibraryInfo not available",
+ isSharedLibraryInfoAvailable()
+ )
+
+ val binder = Binder()
+ val sandboxedSdk = SandboxedSdk(binder)
+ val sandboxedSdkCompat = SandboxedSdkCompat(sandboxedSdk)
+
+ assertThat(sandboxedSdkCompat.getSdkInfo()).isNull()
+ }
+
+ @Test
+ // TODO(b/265295473) Update version check after AdServices V5 finalisation.
+ @SdkSuppress(minSdkVersion = 34, codeName = "UpsideDownCake")
+ @SuppressLint("NewApi") // b/24998154
+ fun getSdkInfo_whenCreatedFromSandboxedSdkAndSharedLibraryInfoAvailable_returnsSdkInfo() {
+ assumeTrue("Requires Sandbox API available", isSandboxApiAvailable())
+ assumeTrue(
+ "Requires SharedLibraryInfo available",
+ isSharedLibraryInfoAvailable()
+ )
+
+ val sdkName = "sdkName"
+ val sdkVersion = 1L
+ val sharedLibraryInfo = ApiAdServicesV5.mockSharedLibraryInfo(sdkName, sdkVersion)
+ val sandboxedSdk = ApiAdServicesV5.mockSandboxedSdkWithSharedLibraryInfo(sharedLibraryInfo)
+
+ val sandboxedSdkCompat = SandboxedSdkCompat(sandboxedSdk)
+ val sdkInfo = sandboxedSdkCompat.getSdkInfo()
+
+ assertThat(sdkInfo).isEqualTo(
+ SandboxedSdkInfo(
+ sdkName,
+ sdkVersion
+ )
+ )
+ }
+
+ private object ApiAdServicesV5 {
+ @Suppress("SameParameterValue")
+ @RequiresApi(28)
+ fun mockSharedLibraryInfo(
+ sdkName: String,
+ sdkVersion: Long
+ ): SharedLibraryInfo {
+ // No public constructor for SharedLibraryInfo available.
+ val sharedLibraryInfo = Mockito.mock(SharedLibraryInfo::class.java)
+ `when`(sharedLibraryInfo.name).thenReturn(sdkName)
+ `when`(sharedLibraryInfo.longVersion).thenReturn(sdkVersion)
+ return sharedLibraryInfo
+ }
+
+ @Suppress("SameParameterValue")
+ @RequiresApi(34)
+ @SuppressLint("NewApi") // b/24998154
+ fun mockSandboxedSdkWithSharedLibraryInfo(
+ sharedLibraryInfo: SharedLibraryInfo
+ ): SandboxedSdk {
+ val binder = Binder()
+ val sandboxedSdk = SandboxedSdk(binder)
+ val sandboxedSdkSpy = spy(sandboxedSdk)
+ // Platform uses attachSharedLibraryInfo (hidden) to set sharedLibraryInfo.
+ doReturn(sharedLibraryInfo).`when`(sandboxedSdkSpy).sharedLibraryInfo
+ return sandboxedSdkSpy
+ }
+ }
+
+ private fun isSandboxApiAvailable() =
+ AdServicesInfo.version() >= 4
+
+ private fun isSharedLibraryInfoAvailable() =
+ AdServicesInfo.isAtLeastV5()
+}
diff --git a/privacysandbox/sdkruntime/sdkruntime-core/src/androidTest/java/androidx/privacysandbox/sdkruntime/core/SandboxedSdkProviderAdapterTest.kt b/privacysandbox/sdkruntime/sdkruntime-core/src/androidTest/java/androidx/privacysandbox/sdkruntime/core/SandboxedSdkProviderAdapterTest.kt
new file mode 100644
index 0000000..db9b56b
--- /dev/null
+++ b/privacysandbox/sdkruntime/sdkruntime-core/src/androidTest/java/androidx/privacysandbox/sdkruntime/core/SandboxedSdkProviderAdapterTest.kt
@@ -0,0 +1,263 @@
+/*
+ * Copyright 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package androidx.privacysandbox.sdkruntime.core
+
+import android.annotation.SuppressLint
+import android.app.sdksandbox.LoadSdkException
+import android.content.Context
+import android.os.Binder
+import android.os.Build.VERSION_CODES.TIRAMISU
+import android.os.Bundle
+import android.os.ext.SdkExtensions.AD_SERVICES
+import android.view.View
+import androidx.annotation.RequiresExtension
+import androidx.test.core.app.ApplicationProvider
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import androidx.test.filters.SdkSuppress
+import androidx.test.filters.SmallTest
+import com.google.common.truth.Truth.assertThat
+import kotlin.reflect.KClass
+import org.junit.Assert.assertThrows
+import org.junit.Assume.assumeTrue
+import org.junit.Before
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.mockito.Mockito.mock
+
+@SmallTest
+@RunWith(AndroidJUnit4::class)
+// TODO(b/249981547) Remove suppress after updating to new lint version (b/262251309)
+@SuppressLint("NewApi")
+// TODO(b/262577044) Remove RequiresExtension after extensions support in @SdkSuppress
+@RequiresExtension(extension = AD_SERVICES, version = 4)
+@SdkSuppress(minSdkVersion = TIRAMISU)
+class SandboxedSdkProviderAdapterTest {
+
+ private lateinit var context: Context
+
+ @Before
+ fun setUp() {
+ assumeTrue("Requires Sandbox API available", isSandboxApiAvailable())
+ context = ApplicationProvider.getApplicationContext()
+ }
+
+ @Test
+ fun testAdapterGetCompatClassNameFromAsset() {
+ val expectedClassName = context.assets
+ .open("SandboxedSdkProviderCompatClassName.txt")
+ .use { inputStream ->
+ inputStream.bufferedReader().readLine()
+ }
+
+ val adapter = SandboxedSdkProviderAdapter()
+ adapter.attachContext(context)
+
+ adapter.onLoadSdk(Bundle())
+
+ val delegate = adapter.extractDelegate<SandboxedSdkProviderCompat>()
+ assertThat(delegate.javaClass.name)
+ .isEqualTo(expectedClassName)
+ }
+
+ @Test
+ fun onLoadSdk_shouldInstantiateDelegateAndAttachContext() {
+ val adapter = createAdapterFor(TestOnLoadReturnResultSdkProvider::class)
+
+ adapter.onLoadSdk(Bundle())
+
+ val delegate = adapter.extractDelegate<TestOnLoadReturnResultSdkProvider>()
+ assertThat(delegate.context)
+ .isSameInstanceAs(context)
+ }
+
+ @Test
+ fun onLoadSdk_shouldDelegateToCompatClassAndReturnResult() {
+ val adapter = createAdapterFor(TestOnLoadReturnResultSdkProvider::class)
+ val params = Bundle()
+
+ val result = adapter.onLoadSdk(params)
+
+ val delegate = adapter.extractDelegate<TestOnLoadReturnResultSdkProvider>()
+ assertThat(delegate.mLastOnLoadSdkBundle)
+ .isSameInstanceAs(params)
+ assertThat(result.getInterface())
+ .isEqualTo(delegate.mResult.getInterface())
+ }
+
+ @Test
+ fun loadSdk_shouldRethrowExceptionFromCompatClass() {
+ val adapter = createAdapterFor(TestOnLoadThrowSdkProvider::class)
+
+ val ex = assertThrows(LoadSdkException::class.java) {
+ adapter.onLoadSdk(Bundle())
+ }
+
+ val delegate = adapter.extractDelegate<TestOnLoadThrowSdkProvider>()
+ assertThat(ex.cause)
+ .isSameInstanceAs(delegate.mError.cause)
+ assertThat(ex.extraInformation)
+ .isSameInstanceAs(delegate.mError.extraInformation)
+ }
+
+ @Test
+ fun loadSdk_shouldThrowIfCompatClassNotExists() {
+ val adapter = createAdapterFor("NOTEXISTS")
+
+ assertThrows(ClassNotFoundException::class.java) {
+ adapter.onLoadSdk(Bundle())
+ }
+ }
+
+ @Test
+ fun beforeUnloadSdk_shouldDelegateToCompatProvider() {
+ val adapter = createAdapterFor(TestOnBeforeUnloadDelegateSdkProvider::class)
+
+ adapter.beforeUnloadSdk()
+
+ val delegate = adapter.extractDelegate<TestOnBeforeUnloadDelegateSdkProvider>()
+ assertThat(delegate.mBeforeUnloadSdkCalled)
+ .isTrue()
+ }
+
+ @Test
+ fun getView_shouldDelegateToCompatProviderAndReturnResult() {
+ val adapter = createAdapterFor(TestGetViewSdkProvider::class)
+ val windowContext = mock(Context::class.java)
+ val params = Bundle()
+ val width = 1
+ val height = 2
+
+ val result = adapter.getView(windowContext, params, width, height)
+
+ val delegate = adapter.extractDelegate<TestGetViewSdkProvider>()
+ assertThat(result)
+ .isSameInstanceAs(delegate.mView)
+ assertThat(delegate.mLastWindowContext)
+ .isSameInstanceAs(windowContext)
+ assertThat(delegate.mLastParams)
+ .isSameInstanceAs(params)
+ assertThat(delegate.mLastWidth)
+ .isSameInstanceAs(width)
+ assertThat(delegate.mLastHeigh)
+ .isSameInstanceAs(height)
+ }
+
+ private fun createAdapterFor(
+ clazz: KClass<out SandboxedSdkProviderCompat>
+ ): SandboxedSdkProviderAdapter = createAdapterFor(clazz.java.name)
+
+ private fun createAdapterFor(delegateClassName: String): SandboxedSdkProviderAdapter {
+ val adapter = SandboxedSdkProviderAdapter(
+ object : SandboxedSdkProviderAdapter.CompatClassNameProvider {
+ override fun getCompatProviderClassName(context: Context): String {
+ return delegateClassName
+ }
+ })
+ adapter.attachContext(context)
+ return adapter
+ }
+
+ private inline fun <reified T : SandboxedSdkProviderCompat>
+ SandboxedSdkProviderAdapter.extractDelegate(): T = delegate as T
+
+ class TestOnLoadReturnResultSdkProvider : SandboxedSdkProviderCompat() {
+ var mResult = SandboxedSdkCompat(Binder())
+ var mLastOnLoadSdkBundle: Bundle? = null
+
+ override fun onLoadSdk(params: Bundle): SandboxedSdkCompat {
+ mLastOnLoadSdkBundle = params
+ return mResult
+ }
+
+ override fun getView(
+ windowContext: Context,
+ params: Bundle,
+ width: Int,
+ height: Int
+ ): View {
+ throw RuntimeException("Not implemented")
+ }
+ }
+
+ class TestOnLoadThrowSdkProvider : SandboxedSdkProviderCompat() {
+ var mError = LoadSdkCompatException(RuntimeException(), Bundle())
+
+ @Throws(LoadSdkCompatException::class)
+ override fun onLoadSdk(params: Bundle): SandboxedSdkCompat {
+ throw mError
+ }
+
+ override fun getView(
+ windowContext: Context,
+ params: Bundle,
+ width: Int,
+ height: Int
+ ): View {
+ throw RuntimeException("Stub!")
+ }
+ }
+
+ class TestOnBeforeUnloadDelegateSdkProvider : SandboxedSdkProviderCompat() {
+ var mBeforeUnloadSdkCalled = false
+
+ override fun onLoadSdk(params: Bundle): SandboxedSdkCompat {
+ throw RuntimeException("Not implemented")
+ }
+
+ override fun beforeUnloadSdk() {
+ mBeforeUnloadSdkCalled = true
+ }
+
+ override fun getView(
+ windowContext: Context,
+ params: Bundle,
+ width: Int,
+ height: Int
+ ): View {
+ throw RuntimeException("Not implemented")
+ }
+ }
+
+ class TestGetViewSdkProvider : SandboxedSdkProviderCompat() {
+ val mView: View = mock(View::class.java)
+
+ var mLastWindowContext: Context? = null
+ var mLastParams: Bundle? = null
+ var mLastWidth = 0
+ var mLastHeigh = 0
+
+ override fun onLoadSdk(params: Bundle): SandboxedSdkCompat {
+ throw RuntimeException("Not implemented")
+ }
+
+ override fun getView(
+ windowContext: Context,
+ params: Bundle,
+ width: Int,
+ height: Int
+ ): View {
+ mLastWindowContext = windowContext
+ mLastParams = params
+ mLastWidth = width
+ mLastHeigh = height
+
+ return mView
+ }
+ }
+
+ private fun isSandboxApiAvailable() =
+ AdServicesInfo.version() >= 4
+}
\ No newline at end of file
diff --git a/privacysandbox/sdkruntime/sdkruntime-core/src/androidTest/java/androidx/privacysandbox/sdkruntime/core/controller/SdkSandboxControllerCompatLocalTest.kt b/privacysandbox/sdkruntime/sdkruntime-core/src/androidTest/java/androidx/privacysandbox/sdkruntime/core/controller/SdkSandboxControllerCompatLocalTest.kt
new file mode 100644
index 0000000..3616736
--- /dev/null
+++ b/privacysandbox/sdkruntime/sdkruntime-core/src/androidTest/java/androidx/privacysandbox/sdkruntime/core/controller/SdkSandboxControllerCompatLocalTest.kt
@@ -0,0 +1,79 @@
+/*
+ * Copyright 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.privacysandbox.sdkruntime.core.controller
+
+import android.content.Context
+import android.os.Binder
+import androidx.privacysandbox.sdkruntime.core.SandboxedSdkCompat
+import androidx.privacysandbox.sdkruntime.core.Versions
+import androidx.test.core.app.ApplicationProvider
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import androidx.test.filters.SmallTest
+import com.google.common.truth.Truth.assertThat
+import org.junit.After
+import org.junit.Before
+import org.junit.Test
+import org.junit.runner.RunWith
+
+@SmallTest
+@RunWith(AndroidJUnit4::class)
+class SdkSandboxControllerCompatLocalTest {
+
+ private lateinit var context: Context
+
+ @Before
+ fun setUp() {
+ // Emulate loading via client lib
+ Versions.handShake(Versions.API_VERSION)
+
+ context = ApplicationProvider.getApplicationContext()
+ }
+
+ @After
+ fun tearDown() {
+ // Reset version back to avoid failing non-compat tests
+ Versions.resetClientVersion()
+ SdkSandboxControllerCompat.resetLocalImpl()
+ }
+
+ @Test
+ fun getSandboxedSdks_withoutLocalImpl_returnsEmptyList() {
+ val controllerCompat = SdkSandboxControllerCompat.from(context)
+ val sandboxedSdks = controllerCompat.getSandboxedSdks()
+ assertThat(sandboxedSdks).isEmpty()
+ }
+
+ @Test
+ fun getSandboxedSdks_withLocalImpl_returnsListFromLocalImpl() {
+ val expectedResult = listOf(SandboxedSdkCompat(Binder()))
+ SdkSandboxControllerCompat.injectLocalImpl(
+ StubImpl(
+ sandboxedSdks = expectedResult
+ )
+ )
+
+ val controllerCompat = SdkSandboxControllerCompat.from(context)
+ val sandboxedSdks = controllerCompat.getSandboxedSdks()
+ assertThat(sandboxedSdks).isEqualTo(expectedResult)
+ }
+
+ private class StubImpl(
+ private val sandboxedSdks: List<SandboxedSdkCompat> = emptyList()
+ ) : SdkSandboxControllerCompat.SandboxControllerImpl {
+ override fun getSandboxedSdks() = sandboxedSdks
+ }
+}
\ No newline at end of file
diff --git a/privacysandbox/sdkruntime/sdkruntime-core/src/androidTest/java/androidx/privacysandbox/sdkruntime/core/controller/SdkSandboxControllerCompatSandboxedTest.kt b/privacysandbox/sdkruntime/sdkruntime-core/src/androidTest/java/androidx/privacysandbox/sdkruntime/core/controller/SdkSandboxControllerCompatSandboxedTest.kt
new file mode 100644
index 0000000..620246c
--- /dev/null
+++ b/privacysandbox/sdkruntime/sdkruntime-core/src/androidTest/java/androidx/privacysandbox/sdkruntime/core/controller/SdkSandboxControllerCompatSandboxedTest.kt
@@ -0,0 +1,101 @@
+/*
+ * Copyright 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.privacysandbox.sdkruntime.core.controller
+
+import android.annotation.SuppressLint
+import android.app.sdksandbox.SandboxedSdk
+import android.app.sdksandbox.sdkprovider.SdkSandboxController
+import android.content.Context
+import android.os.Binder
+import android.os.Build
+import androidx.privacysandbox.sdkruntime.core.AdServicesInfo
+import androidx.test.core.app.ApplicationProvider
+import androidx.test.filters.SdkSuppress
+import com.google.common.truth.Truth.assertThat
+import org.junit.Assume.assumeFalse
+import org.junit.Assume.assumeTrue
+import org.junit.Test
+import org.mockito.Mockito.doReturn
+import org.mockito.Mockito.mock
+import org.mockito.Mockito.spy
+import org.mockito.Mockito.verifyZeroInteractions
+import org.mockito.Mockito.`when`
+
+// TODO(b/249982507) Rewrite test to use real SDK in sandbox instead of mocking controller
+@SdkSuppress(minSdkVersion = Build.VERSION_CODES.TIRAMISU)
+class SdkSandboxControllerCompatSandboxedTest {
+
+ @Test
+ fun getSandboxedSdks_whenApiNotAvailable_notDelegateToSandbox() {
+ assumeFalse(
+ "Requires SandboxController API not available",
+ isSandboxControllerAvailable()
+ )
+
+ val context = spy(ApplicationProvider.getApplicationContext<Context>())
+ val controllerCompat = SdkSandboxControllerCompat.from(context)
+
+ controllerCompat.getSandboxedSdks()
+
+ verifyZeroInteractions(context)
+ }
+
+ @Test
+ fun getSandboxedSdks_whenApiNotAvailable_returnsEmptyList() {
+ assumeFalse(
+ "Requires SandboxController API not available",
+ isSandboxControllerAvailable()
+ )
+
+ val context = ApplicationProvider.getApplicationContext<Context>()
+ val controllerCompat = SdkSandboxControllerCompat.from(context)
+
+ val sandboxedSdks = controllerCompat.getSandboxedSdks()
+
+ assertThat(sandboxedSdks).isEmpty()
+ }
+
+ @Test
+ // TODO(b/265295473) Update version check after AdServices V5 finalisation.
+ @SdkSuppress(minSdkVersion = 34, codeName = "UpsideDownCake")
+ @SuppressLint("NewApi") // b/249981547
+ fun getSandboxedSdks_whenApiAvailable_returnsListFromPlatformApi() {
+ assumeTrue(
+ "Requires SandboxController API available",
+ isSandboxControllerAvailable()
+ )
+
+ val context = spy(ApplicationProvider.getApplicationContext<Context>())
+ val sdkSandboxController = mock(SdkSandboxController::class.java)
+ doReturn(sdkSandboxController)
+ .`when`(context).getSystemService(SdkSandboxController::class.java)
+
+ val sandboxedSdk = SandboxedSdk(Binder())
+ `when`(sdkSandboxController.sandboxedSdks)
+ .thenReturn(listOf(sandboxedSdk))
+
+ val controllerCompat = SdkSandboxControllerCompat.from(context)
+ val sandboxedSdks = controllerCompat.getSandboxedSdks()
+ assertThat(sandboxedSdks).hasSize(1)
+ val result = sandboxedSdks[0]
+
+ assertThat(result.getInterface()).isEqualTo(sandboxedSdk.getInterface())
+ }
+
+ private fun isSandboxControllerAvailable() =
+ AdServicesInfo.isAtLeastV5()
+}
diff --git a/privacysandbox/sdkruntime/sdkruntime-core/src/main/java/androidx/privacysandbox/sdkruntime/core/AdServicesInfo.kt b/privacysandbox/sdkruntime/sdkruntime-core/src/main/java/androidx/privacysandbox/sdkruntime/core/AdServicesInfo.kt
new file mode 100644
index 0000000..de9f490
--- /dev/null
+++ b/privacysandbox/sdkruntime/sdkruntime-core/src/main/java/androidx/privacysandbox/sdkruntime/core/AdServicesInfo.kt
@@ -0,0 +1,60 @@
+/*
+ * Copyright 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.privacysandbox.sdkruntime.core
+
+import android.os.Build
+import android.os.ext.SdkExtensions
+import androidx.annotation.ChecksSdkIntAtLeast
+import androidx.annotation.DoNotInline
+import androidx.annotation.RequiresApi
+import androidx.annotation.RestrictTo
+import androidx.core.os.BuildCompat
+
+/**
+ * Temporary replacement for BuildCompat.AD_SERVICES_EXTENSION_INT.
+ * TODO(b/249981547) Replace with AD_SERVICES_EXTENSION_INT after new core library release
+ *
+ * @suppress
+ */
+@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
+object AdServicesInfo {
+
+ fun version(): Int {
+ return if (Build.VERSION.SDK_INT >= 30) {
+ Extensions30Impl.getAdServicesVersion()
+ } else {
+ 0
+ }
+ }
+
+ @androidx.annotation.OptIn(markerClass = [BuildCompat.PrereleaseSdkCheck::class])
+ @ChecksSdkIntAtLeast(codename = "UpsideDownCake")
+ fun isAtLeastV5(): Boolean {
+ // Can't use only version check until SDK rollout (see b/260334264).
+ // Using only isAtLeastU() is correct, but make testing of V4 functionality complicated.
+ // Combination of 2 checks allows to test V4/V5 using different U builds.
+ // TODO (b/265295473): Remove BuildCompat.isAtLeastU() after SDK finalisation.
+ return BuildCompat.isAtLeastU() && version() >= 5
+ }
+
+ @RequiresApi(30)
+ private object Extensions30Impl {
+ @DoNotInline
+ fun getAdServicesVersion() =
+ SdkExtensions.getExtensionVersion(SdkExtensions.AD_SERVICES)
+ }
+}
\ No newline at end of file
diff --git a/privacysandbox/sdkruntime/sdkruntime-core/src/main/java/androidx/privacysandbox/sdkruntime/core/LoadSdkCompatException.kt b/privacysandbox/sdkruntime/sdkruntime-core/src/main/java/androidx/privacysandbox/sdkruntime/core/LoadSdkCompatException.kt
new file mode 100644
index 0000000..b1851c4
--- /dev/null
+++ b/privacysandbox/sdkruntime/sdkruntime-core/src/main/java/androidx/privacysandbox/sdkruntime/core/LoadSdkCompatException.kt
@@ -0,0 +1,227 @@
+/*
+ * Copyright 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package androidx.privacysandbox.sdkruntime.core
+
+import android.annotation.SuppressLint
+import android.app.sdksandbox.LoadSdkException
+import android.os.Bundle
+import android.os.ext.SdkExtensions.AD_SERVICES
+import androidx.annotation.DoNotInline
+import androidx.annotation.IntDef
+import androidx.annotation.RequiresExtension
+import androidx.annotation.RestrictTo
+import androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP
+
+/**
+ * Compat alternative for [LoadSdkException].
+ * Thrown from [SandboxedSdkProviderCompat.onLoadSdk].
+ *
+ * @see [LoadSdkException]
+ */
+class LoadSdkCompatException : Exception {
+
+ /**
+ * Result code this exception was constructed with.
+ *
+ * @see [LoadSdkException.getLoadSdkErrorCode]
+ */
+ @field:LoadSdkErrorCode
+ @get:LoadSdkErrorCode
+ val loadSdkErrorCode: Int
+
+ /**
+ * Extra error information this exception was constructed with.
+ *
+ * @see [LoadSdkException.getExtraInformation]
+ */
+ val extraInformation: Bundle
+
+ /**
+ * Initializes a LoadSdkCompatException with a result code, a message, a cause and extra
+ * information.
+ *
+ * @param loadSdkErrorCode The result code.
+ * @param message The detailed message.
+ * @param cause The cause of the exception. A null value is permitted, and indicates that the
+ * cause is nonexistent or unknown.
+ * @param extraInformation Extra error information. This is empty if there is no such information.
+ * @suppress
+ */
+ @RestrictTo(LIBRARY_GROUP)
+ @JvmOverloads
+ constructor(
+ @LoadSdkErrorCode loadSdkErrorCode: Int,
+ message: String?,
+ cause: Throwable?,
+ extraInformation: Bundle = Bundle()
+ ) : super(message, cause) {
+ this.loadSdkErrorCode = loadSdkErrorCode
+ this.extraInformation = extraInformation
+ }
+
+ /**
+ * Initializes a LoadSdkCompatException with a result code and a message
+ *
+ * @param loadSdkErrorCode The result code.
+ * @param message The detailed message.
+ * @suppress
+ */
+ @RestrictTo(LIBRARY_GROUP)
+ constructor(
+ @LoadSdkErrorCode loadSdkErrorCode: Int,
+ message: String?
+ ) : this(loadSdkErrorCode, message, cause = null)
+
+ /**
+ * Initializes a LoadSdkCompatException with a Throwable and a Bundle.
+ *
+ * @param cause The cause of the exception.
+ * @param extraInfo Extra error information. This is empty if there is no such information.
+ */
+ constructor(
+ cause: Throwable,
+ extraInfo: Bundle
+ ) : this(LOAD_SDK_SDK_DEFINED_ERROR, "", cause, extraInfo)
+
+ /** @suppress */
+ @IntDef(
+ SDK_SANDBOX_PROCESS_NOT_AVAILABLE,
+ LOAD_SDK_NOT_FOUND,
+ LOAD_SDK_ALREADY_LOADED,
+ LOAD_SDK_SDK_DEFINED_ERROR,
+ LOAD_SDK_SDK_SANDBOX_DISABLED,
+ LOAD_SDK_INTERNAL_ERROR,
+ )
+ @RestrictTo(RestrictTo.Scope.LIBRARY)
+ @Retention(AnnotationRetention.SOURCE)
+ annotation class LoadSdkErrorCode
+
+ /**
+ * Create platform [LoadSdkException] from compat exception.
+ *
+ * @return Platform exception.
+ */
+ @RequiresExtension(extension = AD_SERVICES, version = 4)
+ internal fun toLoadSdkException(): LoadSdkException {
+ return ApiAdServicesV4Impl.toLoadSdkException(this)
+ }
+
+ // TODO(b/249981547) Remove suppress after updating to new lint version (b/262251309)
+ @SuppressLint("NewApi", "ClassVerificationFailure")
+ @RequiresExtension(extension = AD_SERVICES, version = 4)
+ private object ApiAdServicesV4Impl {
+
+ @DoNotInline
+ fun toLoadSdkException(ex: LoadSdkCompatException): LoadSdkException {
+ return LoadSdkException(
+ ex.cause!!,
+ ex.extraInformation
+ )
+ }
+
+ @DoNotInline
+ fun toLoadCompatSdkException(ex: LoadSdkException): LoadSdkCompatException {
+ return LoadSdkCompatException(
+ toLoadSdkErrorCodeCompat(ex.loadSdkErrorCode),
+ ex.message,
+ ex.cause,
+ ex.extraInformation
+ )
+ }
+
+ @LoadSdkErrorCode
+ private fun toLoadSdkErrorCodeCompat(
+ value: Int
+ ): Int {
+ return value // TODO(b/249982002): Validate and convert
+ }
+ }
+
+ companion object {
+
+ /**
+ * Sdk sandbox process is not available.
+ *
+ * This indicates that the sdk sandbox process is not available, either because it has died,
+ * disconnected or was not created in the first place.
+ *
+ * @see [android.app.sdksandbox.SdkSandboxManager.SDK_SANDBOX_PROCESS_NOT_AVAILABLE]
+ */
+ const val SDK_SANDBOX_PROCESS_NOT_AVAILABLE = 503
+
+ /**
+ * SDK not found.
+ *
+ * This indicates that client application tried to load a non-existing SDK.
+ *
+ * @see [android.app.sdksandbox.SdkSandboxManager.LOAD_SDK_NOT_FOUND]
+ */
+ const val LOAD_SDK_NOT_FOUND = 100
+
+ /**
+ * SDK is already loaded.
+ *
+ * This indicates that client application tried to reload the same SDK after being
+ * successfully loaded.
+ *
+ * @see [android.app.sdksandbox.SdkSandboxManager.LOAD_SDK_ALREADY_LOADED]
+ */
+ const val LOAD_SDK_ALREADY_LOADED = 101
+
+ /**
+ * SDK error after being loaded.
+ *
+ * This indicates that the SDK encountered an error during post-load initialization. The
+ * details of this can be obtained from the Bundle returned in [LoadSdkCompatException].
+ *
+ * @see [android.app.sdksandbox.SdkSandboxManager.LOAD_SDK_SDK_DEFINED_ERROR]
+ */
+ const val LOAD_SDK_SDK_DEFINED_ERROR = 102
+
+ /**
+ * SDK sandbox is disabled.
+ *
+ * This indicates that the SDK sandbox is disabled. Any subsequent attempts to load SDKs in
+ * this boot will also fail.
+ *
+ * @see [android.app.sdksandbox.SdkSandboxManager.LOAD_SDK_SDK_SANDBOX_DISABLED]
+ */
+ const val LOAD_SDK_SDK_SANDBOX_DISABLED = 103
+
+ /**
+ * Internal error while loading SDK.
+ *
+ * This indicates a generic internal error happened while applying the call from
+ * client application.
+ *
+ * @see [android.app.sdksandbox.SdkSandboxManager.LOAD_SDK_INTERNAL_ERROR]
+ */
+ const val LOAD_SDK_INTERNAL_ERROR = 500
+
+ /**
+ * Create compat exception from platform [LoadSdkException].
+ *
+ * @param ex Platform exception
+ * @return Compat exception.
+ * @suppress
+ */
+ @RequiresExtension(extension = AD_SERVICES, version = 4)
+ @RestrictTo(LIBRARY_GROUP)
+ fun toLoadCompatSdkException(ex: LoadSdkException): LoadSdkCompatException {
+ return ApiAdServicesV4Impl.toLoadCompatSdkException(ex)
+ }
+ }
+}
\ No newline at end of file
diff --git a/privacysandbox/sdkruntime/sdkruntime-core/src/main/java/androidx/privacysandbox/sdkruntime/core/SandboxedSdkCompat.kt b/privacysandbox/sdkruntime/sdkruntime-core/src/main/java/androidx/privacysandbox/sdkruntime/core/SandboxedSdkCompat.kt
new file mode 100644
index 0000000..3a4c057
--- /dev/null
+++ b/privacysandbox/sdkruntime/sdkruntime-core/src/main/java/androidx/privacysandbox/sdkruntime/core/SandboxedSdkCompat.kt
@@ -0,0 +1,188 @@
+/*
+ * Copyright 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package androidx.privacysandbox.sdkruntime.core
+
+import android.annotation.SuppressLint
+import android.app.sdksandbox.SandboxedSdk
+import android.os.IBinder
+import android.os.ext.SdkExtensions.AD_SERVICES
+import androidx.annotation.DoNotInline
+import androidx.annotation.RequiresApi
+import androidx.annotation.RequiresExtension
+import androidx.annotation.RestrictTo
+import androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP
+
+/**
+ * Compat wrapper for [SandboxedSdk].
+ * Represents an SDK loaded in the sandbox process or locally.
+ * An application should use this object to obtain an interface to the SDK through [getInterface].
+ *
+ * The SDK should create it when [SandboxedSdkProviderCompat.onLoadSdk] is called, and drop all
+ * references to it when [SandboxedSdkProviderCompat.beforeUnloadSdk] is called. Additionally, the
+ * SDK should fail calls made to the [IBinder] returned from [getInterface] after
+ * [SandboxedSdkProviderCompat.beforeUnloadSdk] has been called.
+ *
+ * @see [SandboxedSdk]
+ *
+ */
+class SandboxedSdkCompat private constructor(
+ private val sdkImpl: SandboxedSdkImpl
+) {
+
+ /**
+ * Creates SandboxedSdkCompat from SDK Binder object.
+ *
+ * @param sdkInterface The SDK's interface. This will be the entrypoint into the sandboxed SDK
+ * for the application. The SDK should keep this valid until it's loaded in the sandbox, and
+ * start failing calls to this interface once it has been unloaded
+ *
+ * This interface can later be retrieved using [getInterface].
+ *
+ * @see [SandboxedSdk]
+ */
+ constructor(sdkInterface: IBinder) : this(CompatImpl(sdkInterface))
+
+ /**
+ * Creates SandboxedSdkCompat wrapper around existing [SandboxedSdk] object.
+ *
+ * @param sandboxedSdk SandboxedSdk object. All calls will be delegated to that object.
+ * @suppress
+ */
+ @RequiresExtension(extension = AD_SERVICES, version = 4)
+ @RestrictTo(LIBRARY_GROUP)
+ constructor(sandboxedSdk: SandboxedSdk) : this(
+ SdkImplFactory.createSdkImpl(sandboxedSdk)
+ )
+
+ /**
+ * Returns the interface to the loaded SDK.
+ * A null interface is returned if the Binder has since
+ * become unavailable, in response to the SDK being unloaded.
+ *
+ * @return [IBinder] object for loaded SDK.
+ *
+ * @see [SandboxedSdk.getInterface]
+ */
+ fun getInterface() = sdkImpl.getInterface()
+
+ /**
+ * Returns information about loaded SDK.
+ *
+ * @return [SandboxedSdkInfo] object for loaded SDK or null if no information available.
+ *
+ * @see [SandboxedSdk.getSharedLibraryInfo]
+ */
+ fun getSdkInfo(): SandboxedSdkInfo? = sdkImpl.getSdkInfo()
+
+ /**
+ * Create [SandboxedSdk] from compat object.
+ *
+ * @return Platform SandboxedSdk
+ */
+ @RequiresExtension(extension = AD_SERVICES, version = 4)
+ internal fun toSandboxedSdk() = sdkImpl.toSandboxedSdk()
+
+ internal interface SandboxedSdkImpl {
+ fun getInterface(): IBinder?
+
+ fun getSdkInfo(): SandboxedSdkInfo?
+
+ @RequiresExtension(extension = AD_SERVICES, version = 4)
+ @DoNotInline
+ fun toSandboxedSdk(): SandboxedSdk
+ }
+
+ // TODO(b/249981547) Remove suppress after updating to new lint version (b/262251309)
+ @SuppressLint("NewApi", "ClassVerificationFailure")
+ @RequiresExtension(extension = AD_SERVICES, version = 4)
+ private open class ApiAdServicesV4Impl(
+ protected val sandboxedSdk: SandboxedSdk
+ ) : SandboxedSdkImpl {
+
+ @DoNotInline
+ override fun getInterface(): IBinder? {
+ return sandboxedSdk.getInterface()
+ }
+
+ override fun getSdkInfo(): SandboxedSdkInfo? = null
+
+ @DoNotInline
+ override fun toSandboxedSdk(): SandboxedSdk {
+ return sandboxedSdk
+ }
+
+ companion object {
+ @DoNotInline
+ fun createSandboxedSdk(sdkInterface: IBinder): SandboxedSdk {
+ return SandboxedSdk(sdkInterface)
+ }
+ }
+ }
+
+ // TODO(b/265295473): Replace @RequiresApi with correct @RequiresExtension
+ @RequiresApi(34)
+ @SuppressLint("NewApi") // b/249981547
+ private class ApiAdServicesV5Impl(
+ sandboxedSdk: SandboxedSdk
+ ) : ApiAdServicesV4Impl(sandboxedSdk) {
+
+ override fun getSdkInfo(): SandboxedSdkInfo {
+ val sharedLibraryInfo = sandboxedSdk.sharedLibraryInfo
+ return SandboxedSdkInfo(
+ name = sharedLibraryInfo.name,
+ version = sharedLibraryInfo.longVersion,
+ )
+ }
+ }
+
+ private object SdkImplFactory {
+ @SuppressLint("NewApi") // b/249981547
+ fun createSdkImpl(sandboxedSdk: SandboxedSdk): SandboxedSdkImpl {
+ return if (AdServicesInfo.isAtLeastV5()) {
+ ApiAdServicesV5Impl(sandboxedSdk)
+ } else {
+ ApiAdServicesV4Impl(sandboxedSdk)
+ }
+ }
+ }
+
+ private class CompatImpl(private val sdkInterface: IBinder) : SandboxedSdkImpl {
+
+ override fun getInterface(): IBinder {
+ // This will be null if the SDK has been unloaded and the IBinder originally provided
+ // is now a dead object.
+ return sdkInterface
+ }
+
+ override fun getSdkInfo(): SandboxedSdkInfo? = null
+
+ @RequiresExtension(extension = AD_SERVICES, version = 4)
+ override fun toSandboxedSdk(): SandboxedSdk {
+ // avoid class verifications errors
+ return ApiAdServicesV4Impl.createSandboxedSdk(sdkInterface)
+ }
+ }
+
+ companion object {
+ /**
+ * Deprecated and will be removed in next release.
+ * Use [SandboxedSdkCompat] constructor instead.
+ * TODO(b/261013990) Remove method after Shim generator migration and release
+ */
+ @JvmStatic
+ fun create(binder: IBinder): SandboxedSdkCompat = SandboxedSdkCompat(binder)
+ }
+}
diff --git a/privacysandbox/sdkruntime/sdkruntime-core/src/main/java/androidx/privacysandbox/sdkruntime/core/SandboxedSdkInfo.kt b/privacysandbox/sdkruntime/sdkruntime-core/src/main/java/androidx/privacysandbox/sdkruntime/core/SandboxedSdkInfo.kt
new file mode 100644
index 0000000..b2caca8
--- /dev/null
+++ b/privacysandbox/sdkruntime/sdkruntime-core/src/main/java/androidx/privacysandbox/sdkruntime/core/SandboxedSdkInfo.kt
@@ -0,0 +1,53 @@
+/*
+ * Copyright 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.privacysandbox.sdkruntime.core
+
+/**
+ * Information about runtime enabled SDK.
+ * Could represent SDK loaded in sandbox or locally loaded SDK.
+ */
+class SandboxedSdkInfo(
+ /**
+ * Sdk Name.
+ * This is a value of `android:name` attribute <sdk-library> tag of SDK Manifest.
+ */
+ val name: String,
+ /**
+ * Sdk Version.
+ * This is a value of `android:versionMajor` attribute <sdk-library> tag of SDK Manifest.
+ */
+ val version: Long
+) {
+
+ override fun equals(other: Any?): Boolean {
+ if (this === other) return true
+ if (javaClass != other?.javaClass) return false
+
+ other as SandboxedSdkInfo
+
+ if (name != other.name) return false
+ if (version != other.version) return false
+
+ return true
+ }
+
+ override fun hashCode(): Int {
+ var result = name.hashCode()
+ result = 31 * result + version.hashCode()
+ return result
+ }
+}
\ No newline at end of file
diff --git a/privacysandbox/sdkruntime/sdkruntime-core/src/main/java/androidx/privacysandbox/sdkruntime/core/SandboxedSdkProviderAdapter.kt b/privacysandbox/sdkruntime/sdkruntime-core/src/main/java/androidx/privacysandbox/sdkruntime/core/SandboxedSdkProviderAdapter.kt
new file mode 100644
index 0000000..d0af98f
--- /dev/null
+++ b/privacysandbox/sdkruntime/sdkruntime-core/src/main/java/androidx/privacysandbox/sdkruntime/core/SandboxedSdkProviderAdapter.kt
@@ -0,0 +1,95 @@
+/*
+ * Copyright 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package androidx.privacysandbox.sdkruntime.core
+
+import android.annotation.SuppressLint
+import android.app.sdksandbox.LoadSdkException
+import android.app.sdksandbox.SandboxedSdk
+import android.app.sdksandbox.SandboxedSdkProvider
+import android.content.Context
+import android.os.Bundle
+import android.os.ext.SdkExtensions.AD_SERVICES
+import android.view.View
+import androidx.annotation.RequiresExtension
+
+/**
+ * Implementation of platform [SandboxedSdkProvider] that delegate to [SandboxedSdkProviderCompat]
+ * Gets compat class name from asset "SandboxedSdkProviderCompatClassName.txt"
+ *
+ */
+// TODO(b/249981547) Remove suppress after updating to new lint version (b/262251309)
+@SuppressLint("NewApi", "ClassVerificationFailure", "Override")
+@RequiresExtension(extension = AD_SERVICES, version = 4)
+class SandboxedSdkProviderAdapter internal constructor(
+ private val classNameProvider: CompatClassNameProvider
+) : SandboxedSdkProvider() {
+
+ /**
+ * Provides classname of [SandboxedSdkProviderCompat] implementation.
+ */
+ internal interface CompatClassNameProvider {
+ fun getCompatProviderClassName(context: Context): String
+ }
+
+ constructor () : this(DefaultClassNameProvider())
+
+ internal val delegate: SandboxedSdkProviderCompat by lazy {
+ val currentContext = context!!
+ val compatSdkProviderClassName =
+ classNameProvider.getCompatProviderClassName(currentContext)
+ val clz = Class.forName(compatSdkProviderClassName)
+ val newDelegate = clz.getConstructor().newInstance() as SandboxedSdkProviderCompat
+ newDelegate.attachContext(currentContext)
+ newDelegate
+ }
+
+ @Throws(LoadSdkException::class)
+ override fun onLoadSdk(params: Bundle): SandboxedSdk {
+ return try {
+ delegate.onLoadSdk(params).toSandboxedSdk()
+ } catch (e: LoadSdkCompatException) {
+ throw e.toLoadSdkException()
+ }
+ }
+
+ override fun beforeUnloadSdk() {
+ delegate.beforeUnloadSdk()
+ }
+
+ override fun getView(
+ windowContext: Context,
+ params: Bundle,
+ width: Int,
+ height: Int
+ ): View {
+ return delegate.getView(windowContext, params, width, height)
+ }
+
+ private class DefaultClassNameProvider : CompatClassNameProvider {
+ override fun getCompatProviderClassName(context: Context): String {
+ // TODO(b/257966930) Read classname from SDK manifest property
+ return context.assets.open(COMPAT_SDK_PROVIDER_CLASS_ASSET_NAME)
+ .use { inputStream ->
+ inputStream.bufferedReader().readLine()
+ }
+ }
+ }
+
+ private companion object {
+ private const val COMPAT_SDK_PROVIDER_CLASS_ASSET_NAME =
+ "SandboxedSdkProviderCompatClassName.txt"
+ }
+}
\ No newline at end of file
diff --git a/privacysandbox/sdkruntime/sdkruntime-core/src/main/java/androidx/privacysandbox/sdkruntime/core/SandboxedSdkProviderCompat.kt b/privacysandbox/sdkruntime/sdkruntime-core/src/main/java/androidx/privacysandbox/sdkruntime/core/SandboxedSdkProviderCompat.kt
new file mode 100644
index 0000000..8882d6f
--- /dev/null
+++ b/privacysandbox/sdkruntime/sdkruntime-core/src/main/java/androidx/privacysandbox/sdkruntime/core/SandboxedSdkProviderCompat.kt
@@ -0,0 +1,106 @@
+/*
+ * Copyright 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package androidx.privacysandbox.sdkruntime.core
+
+import android.content.Context
+import android.os.Bundle
+import android.view.View
+
+/**
+ * Compat version of [android.app.sdksandbox.SandboxedSdkProvider].
+ *
+ * Encapsulates API which SDK sandbox can use to interact with SDKs loaded into it.
+ *
+ * SDK has to implement this abstract class to generate an entry point for SDK sandbox to be able
+ * to call it through.
+ *
+ * @see [android.app.sdksandbox.SandboxedSdkProvider]
+ */
+abstract class SandboxedSdkProviderCompat {
+ /**
+ * Context previously set through [SandboxedSdkProviderCompat.attachContext].
+ * This will return null if no context has been previously set.
+ */
+ var context: Context? = null
+ private set
+
+ /**
+ * Sets the SDK [Context] which can then be received using [SandboxedSdkProviderCompat.context]
+ *
+ * This is called before [SandboxedSdkProviderCompat.onLoadSdk] is invoked.
+ * No operations requiring a [Context] should be performed before then, as
+ * [SandboxedSdkProviderCompat.context] will return null until this method has been called.
+ *
+ * @throws IllegalStateException if a base context has already been set.
+ *
+ * @param context The new base context.
+ *
+ * @see [android.app.sdksandbox.SandboxedSdkProvider.attachContext]
+ */
+ fun attachContext(context: Context) {
+ check(this.context == null) { "Context already set" }
+ this.context = context
+ }
+
+ /**
+ * Does the work needed for the SDK to start handling requests.
+ *
+ * This function is called by the SDK sandbox after it loads the SDK.
+ *
+ * SDK should do any work to be ready to handle upcoming requests. It should not do any
+ * long-running tasks here, like I/O and network calls. Doing so can prevent the SDK from
+ * receiving requests from the client. Additionally, it should not do initialization that
+ * depends on other SDKs being loaded into the SDK sandbox.
+ *
+ * The SDK should not do any operations requiring a [Context] object before this method
+ * has been called.
+ *
+ * @param params list of params passed from the client when it loads the SDK. This can be empty.
+ * @return Returns a [SandboxedSdkCompat], passed back to the client. The IBinder used to create
+ * the [SandboxedSdkCompat] object will be used by the client to call into the SDK.
+ *
+ * @throws LoadSdkCompatException if initialization failed.
+ *
+ * @see [android.app.sdksandbox.SandboxedSdkProvider.onLoadSdk]
+ */
+ @Throws(LoadSdkCompatException::class)
+ abstract fun onLoadSdk(params: Bundle): SandboxedSdkCompat
+
+ /**
+ * Does the work needed for the SDK to free its resources before being unloaded.
+ *
+ * This function is called by the SDK sandbox manager before it unloads the SDK. The SDK
+ * should fail any invocations on the Binder previously returned to the client through
+ * [SandboxedSdkCompat.getInterface]
+ *
+ * The SDK should not do any long-running tasks here, like I/O and network calls.
+ *
+ * @see [android.app.sdksandbox.SandboxedSdkProvider.beforeUnloadSdk]
+ */
+ open fun beforeUnloadSdk() {}
+
+ /**
+ * Requests a view to be remotely rendered to the client app process.
+ *
+ * @see [android.app.sdksandbox.SandboxedSdkProvider.getView]
+ */
+ abstract fun getView(
+ windowContext: Context,
+ params: Bundle,
+ width: Int,
+ height: Int
+ ): View
+}
\ No newline at end of file
diff --git a/privacysandbox/sdkruntime/sdkruntime-core/src/main/java/androidx/privacysandbox/sdkruntime/core/Versions.kt b/privacysandbox/sdkruntime/sdkruntime-core/src/main/java/androidx/privacysandbox/sdkruntime/core/Versions.kt
new file mode 100644
index 0000000..e7235c5
--- /dev/null
+++ b/privacysandbox/sdkruntime/sdkruntime-core/src/main/java/androidx/privacysandbox/sdkruntime/core/Versions.kt
@@ -0,0 +1,49 @@
+/*
+ * Copyright 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.privacysandbox.sdkruntime.core
+
+import androidx.annotation.Keep
+import androidx.annotation.RestrictTo
+import org.jetbrains.annotations.TestOnly
+
+/**
+ * Store internal API version (for Client-Core communication).
+ * Methods invoked via reflection.
+ *
+ * @suppress
+ */
+@Suppress("unused")
+@Keep
+@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
+object Versions {
+
+ const val API_VERSION = 1
+
+ @JvmField
+ var CLIENT_VERSION: Int? = null
+
+ @JvmStatic
+ fun handShake(clientVersion: Int): Int {
+ CLIENT_VERSION = clientVersion
+ return API_VERSION
+ }
+
+ @TestOnly
+ internal fun resetClientVersion() {
+ CLIENT_VERSION = null
+ }
+}
\ No newline at end of file
diff --git a/privacysandbox/sdkruntime/sdkruntime-core/src/main/androidx/privacysandbox/sdkruntime/androidx-privacysandbox-sdkruntime-sdkruntime-core-documentation.md b/privacysandbox/sdkruntime/sdkruntime-core/src/main/java/androidx/privacysandbox/sdkruntime/core/androidx-privacysandbox-sdkruntime-sdkruntime-core-documentation.md
similarity index 100%
rename from privacysandbox/sdkruntime/sdkruntime-core/src/main/androidx/privacysandbox/sdkruntime/androidx-privacysandbox-sdkruntime-sdkruntime-core-documentation.md
rename to privacysandbox/sdkruntime/sdkruntime-core/src/main/java/androidx/privacysandbox/sdkruntime/core/androidx-privacysandbox-sdkruntime-sdkruntime-core-documentation.md
diff --git a/privacysandbox/sdkruntime/sdkruntime-core/src/main/java/androidx/privacysandbox/sdkruntime/core/controller/SdkSandboxControllerCompat.kt b/privacysandbox/sdkruntime/sdkruntime-core/src/main/java/androidx/privacysandbox/sdkruntime/core/controller/SdkSandboxControllerCompat.kt
new file mode 100644
index 0000000..a32af23
--- /dev/null
+++ b/privacysandbox/sdkruntime/sdkruntime-core/src/main/java/androidx/privacysandbox/sdkruntime/core/controller/SdkSandboxControllerCompat.kt
@@ -0,0 +1,114 @@
+/*
+ * Copyright 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.privacysandbox.sdkruntime.core.controller
+
+import android.content.Context
+import androidx.annotation.Keep
+import androidx.annotation.RestrictTo
+import androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP
+import androidx.privacysandbox.sdkruntime.core.AdServicesInfo
+import androidx.privacysandbox.sdkruntime.core.SandboxedSdkCompat
+import androidx.privacysandbox.sdkruntime.core.SandboxedSdkProviderCompat
+import androidx.privacysandbox.sdkruntime.core.Versions
+import androidx.privacysandbox.sdkruntime.core.controller.impl.NoOpImpl
+import androidx.privacysandbox.sdkruntime.core.controller.impl.PlatformImpl
+import org.jetbrains.annotations.TestOnly
+
+/**
+ * Compat version of [android.app.sdksandbox.sdkprovider.SdkSandboxController].
+ *
+ * Controller that is used by SDK loaded in the sandbox or locally to access information provided
+ * by the sandbox environment.
+ *
+ * It enables the SDK to communicate with other SDKS and know about the state of the sdks that are
+ * currently loaded.
+ *
+ * An instance can be obtained using [SdkSandboxControllerCompat.from].
+ * The [Context] can be obtained using [SandboxedSdkProviderCompat.context].
+ *
+ * @see [android.app.sdksandbox.sdkprovider.SdkSandboxController]
+ */
+class SdkSandboxControllerCompat internal constructor(
+ private val controllerImpl: SandboxControllerImpl
+) {
+
+ /**
+ * Fetches information about Sdks that are loaded in the sandbox or locally.
+ *
+ * @return List of [SandboxedSdkCompat] containing all currently loaded sdks
+ *
+ * @see [android.app.sdksandbox.sdkprovider.SdkSandboxController.getSandboxedSdks]
+ */
+ fun getSandboxedSdks(): List<SandboxedSdkCompat> =
+ controllerImpl.getSandboxedSdks()
+
+ /** @suppress */
+ @RestrictTo(LIBRARY_GROUP)
+ interface SandboxControllerImpl {
+ fun getSandboxedSdks(): List<SandboxedSdkCompat>
+ }
+
+ companion object {
+
+ private var localImpl: SandboxControllerImpl? = null
+
+ /**
+ * Creates [SdkSandboxControllerCompat].
+ *
+ * @param context SDK context
+ *
+ * @return SdkSandboxControllerCompat object.
+ */
+ @JvmStatic
+ fun from(context: Context): SdkSandboxControllerCompat {
+ val loadedLocally = Versions.CLIENT_VERSION != null
+ if (loadedLocally) {
+ val implFromClient = localImpl
+ if (implFromClient != null) {
+ return SdkSandboxControllerCompat(implFromClient)
+ }
+ return SdkSandboxControllerCompat(NoOpImpl())
+ }
+
+ if (AdServicesInfo.isAtLeastV5()) {
+ return SdkSandboxControllerCompat(PlatformImpl.from(context))
+ }
+
+ return SdkSandboxControllerCompat(NoOpImpl())
+ }
+
+ /**
+ * Inject implementation from client library.
+ * Implementation will be used only if loaded locally.
+ * This method will be called from client side via reflection during loading SDK.
+ *
+ * @suppress
+ */
+ @JvmStatic
+ @Keep
+ @RestrictTo(LIBRARY_GROUP)
+ fun injectLocalImpl(impl: SandboxControllerImpl) {
+ check(localImpl == null) { "Local implementation already injected" }
+ localImpl = impl
+ }
+
+ @TestOnly
+ internal fun resetLocalImpl() {
+ localImpl = null
+ }
+ }
+}
\ No newline at end of file
diff --git a/privacysandbox/sdkruntime/sdkruntime-core/src/main/java/androidx/privacysandbox/sdkruntime/core/controller/impl/NoOpImpl.kt b/privacysandbox/sdkruntime/sdkruntime-core/src/main/java/androidx/privacysandbox/sdkruntime/core/controller/impl/NoOpImpl.kt
new file mode 100644
index 0000000..cc0bfa3
--- /dev/null
+++ b/privacysandbox/sdkruntime/sdkruntime-core/src/main/java/androidx/privacysandbox/sdkruntime/core/controller/impl/NoOpImpl.kt
@@ -0,0 +1,27 @@
+/*
+ * Copyright 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.privacysandbox.sdkruntime.core.controller.impl
+
+import androidx.privacysandbox.sdkruntime.core.SandboxedSdkCompat
+import androidx.privacysandbox.sdkruntime.core.controller.SdkSandboxControllerCompat
+
+/**
+ * NoOp implementation for cases when [SdkSandboxControllerCompat] not supported.
+ */
+internal class NoOpImpl : SdkSandboxControllerCompat.SandboxControllerImpl {
+ override fun getSandboxedSdks(): List<SandboxedSdkCompat> = emptyList()
+}
\ No newline at end of file
diff --git a/privacysandbox/sdkruntime/sdkruntime-core/src/main/java/androidx/privacysandbox/sdkruntime/core/controller/impl/PlatformImpl.kt b/privacysandbox/sdkruntime/sdkruntime-core/src/main/java/androidx/privacysandbox/sdkruntime/core/controller/impl/PlatformImpl.kt
new file mode 100644
index 0000000..63d670a
--- /dev/null
+++ b/privacysandbox/sdkruntime/sdkruntime-core/src/main/java/androidx/privacysandbox/sdkruntime/core/controller/impl/PlatformImpl.kt
@@ -0,0 +1,49 @@
+/*
+ * Copyright 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.privacysandbox.sdkruntime.core.controller.impl
+
+import android.annotation.SuppressLint
+import android.app.sdksandbox.sdkprovider.SdkSandboxController
+import android.content.Context
+import androidx.annotation.RequiresApi
+import androidx.privacysandbox.sdkruntime.core.SandboxedSdkCompat
+import androidx.privacysandbox.sdkruntime.core.controller.SdkSandboxControllerCompat
+
+/**
+ * Implementation that delegates to platform [SdkSandboxController].
+ */
+// TODO(b/265295473): Replace @RequiresApi with correct @RequiresExtension
+@RequiresApi(34)
+internal class PlatformImpl(
+ private val controller: SdkSandboxController
+) : SdkSandboxControllerCompat.SandboxControllerImpl {
+
+ @SuppressLint("NewApi") // b/249981547
+ override fun getSandboxedSdks(): List<SandboxedSdkCompat> {
+ return controller
+ .sandboxedSdks
+ .map { platformSdk -> SandboxedSdkCompat(platformSdk) }
+ }
+
+ companion object {
+ @SuppressLint("NewApi") // b/249981547
+ fun from(context: Context): PlatformImpl {
+ val sdkSandboxController = context.getSystemService(SdkSandboxController::class.java)
+ return PlatformImpl(sdkSandboxController)
+ }
+ }
+}
diff --git a/recyclerview/recyclerview/api/api_lint.ignore b/recyclerview/recyclerview/api/api_lint.ignore
index ee7fa16..463599f 100644
--- a/recyclerview/recyclerview/api/api_lint.ignore
+++ b/recyclerview/recyclerview/api/api_lint.ignore
@@ -161,12 +161,6 @@
Internal field mLayoutManager must not be exposed
-InvalidNullabilityOverride: androidx.recyclerview.widget.RecyclerView#draw(android.graphics.Canvas) parameter #0:
- Invalid nullability on parameter `c` in method `draw`. Parameters of overrides cannot be NonNull if the super parameter is unannotated.
-InvalidNullabilityOverride: androidx.recyclerview.widget.RecyclerView#drawChild(android.graphics.Canvas, android.view.View, long) parameter #0:
- Invalid nullability on parameter `canvas` in method `drawChild`. Parameters of overrides cannot be NonNull if the super parameter is unannotated.
-InvalidNullabilityOverride: androidx.recyclerview.widget.RecyclerView#onDraw(android.graphics.Canvas) parameter #0:
- Invalid nullability on parameter `c` in method `onDraw`. Parameters of overrides cannot be NonNull if the super parameter is unannotated.
InvalidNullabilityOverride: androidx.recyclerview.widget.RecyclerViewAccessibilityDelegate.ItemDelegate#dispatchPopulateAccessibilityEvent(android.view.View, android.view.accessibility.AccessibilityEvent) parameter #0:
Invalid nullability on parameter `host` in method `dispatchPopulateAccessibilityEvent`. Parameters of overrides cannot be NonNull if the super parameter is unannotated.
InvalidNullabilityOverride: androidx.recyclerview.widget.RecyclerViewAccessibilityDelegate.ItemDelegate#dispatchPopulateAccessibilityEvent(android.view.View, android.view.accessibility.AccessibilityEvent) parameter #1:
@@ -551,6 +545,10 @@
Missing nullability on parameter `container` in method `dispatchRestoreInstanceState`
MissingNullability: androidx.recyclerview.widget.RecyclerView#dispatchSaveInstanceState(android.util.SparseArray<android.os.Parcelable>) parameter #0:
Missing nullability on parameter `container` in method `dispatchSaveInstanceState`
+MissingNullability: androidx.recyclerview.widget.RecyclerView#draw(android.graphics.Canvas) parameter #0:
+ Missing nullability on parameter `c` in method `draw`
+MissingNullability: androidx.recyclerview.widget.RecyclerView#drawChild(android.graphics.Canvas, android.view.View, long) parameter #0:
+ Missing nullability on parameter `canvas` in method `drawChild`
MissingNullability: androidx.recyclerview.widget.RecyclerView#drawChild(android.graphics.Canvas, android.view.View, long) parameter #1:
Missing nullability on parameter `child` in method `drawChild`
MissingNullability: androidx.recyclerview.widget.RecyclerView#findViewHolderForItemId(long):
@@ -573,6 +571,8 @@
Missing nullability on method `getAccessibilityClassName` return
MissingNullability: androidx.recyclerview.widget.RecyclerView#getChildViewHolder(android.view.View):
Missing nullability on method `getChildViewHolder` return
+MissingNullability: androidx.recyclerview.widget.RecyclerView#onDraw(android.graphics.Canvas) parameter #0:
+ Missing nullability on parameter `c` in method `onDraw`
MissingNullability: androidx.recyclerview.widget.RecyclerView#onGenericMotionEvent(android.view.MotionEvent) parameter #0:
Missing nullability on parameter `event` in method `onGenericMotionEvent`
MissingNullability: androidx.recyclerview.widget.RecyclerView#onInterceptTouchEvent(android.view.MotionEvent) parameter #0:
diff --git a/samples/MediaRoutingDemo/src/main/AndroidManifest.xml b/samples/MediaRoutingDemo/src/main/AndroidManifest.xml
index b56a49f..66bfc2c 100644
--- a/samples/MediaRoutingDemo/src/main/AndroidManifest.xml
+++ b/samples/MediaRoutingDemo/src/main/AndroidManifest.xml
@@ -64,6 +64,17 @@
</intent-filter>
</activity>
+ <activity
+ android:name=".activities.RouteListingPreferenceActivity"
+ android:configChanges="orientation|screenSize"
+ android:exported="false"
+ android:label="Route Listing Preference">
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN" />
+ <category android:name="com.example.androidx.SAMPLE_CODE" />
+ </intent-filter>
+ </activity>
+
<receiver android:name="androidx.mediarouter.media.MediaTransferReceiver"
android:exported="true" />
diff --git a/samples/MediaRoutingDemo/src/main/java/com/example/androidx/mediarouting/RoutesManager.java b/samples/MediaRoutingDemo/src/main/java/com/example/androidx/mediarouting/RoutesManager.java
index 7e69d77..f48ae8a 100644
--- a/samples/MediaRoutingDemo/src/main/java/com/example/androidx/mediarouting/RoutesManager.java
+++ b/samples/MediaRoutingDemo/src/main/java/com/example/androidx/mediarouting/RoutesManager.java
@@ -23,20 +23,31 @@
import static com.example.androidx.mediarouting.data.RouteItem.PlaybackType.REMOTE;
import static com.example.androidx.mediarouting.data.RouteItem.VolumeHandling.VARIABLE;
+import android.annotation.SuppressLint;
import android.content.Context;
import android.content.res.Resources;
+import android.media.MediaRouter2;
+import android.media.RouteListingPreference;
+import androidx.annotation.IntDef;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
+import androidx.annotation.OptIn;
+import androidx.annotation.RequiresApi;
+import androidx.core.os.BuildCompat;
import androidx.mediarouter.media.MediaRouter;
import androidx.mediarouter.media.MediaRouterParams;
import com.example.androidx.mediarouting.data.RouteItem;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
import java.util.ArrayList;
+import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
+import java.util.stream.Collectors;
/** Holds the data needed to control the provider for the routes dynamically. */
public final class RoutesManager {
@@ -51,12 +62,19 @@
private final Map<String, RouteItem> mRouteItems;
private boolean mDynamicRoutingEnabled;
private DialogType mDialogType;
+ private final MediaRouter2 mPlatformMediaRouter2;
+ private boolean mRouteListingPreferenceEnabled;
+ private boolean mRouteListingSystemOrderingPreferred;
+ private List<RouteListingPreferenceItem> mRouteListingPreferenceItems;
+ @SuppressLint({"NewApi", "ClassVerificationFailure"})
private RoutesManager(Context context) {
mContext = context;
mDynamicRoutingEnabled = true;
mDialogType = DialogType.OUTPUT_SWITCHER;
mRouteItems = new HashMap<>();
+ mRouteListingPreferenceItems = Collections.emptyList();
+ mPlatformMediaRouter2 = MediaRouter2.getInstance(context);
initTestRoutes();
}
@@ -113,6 +131,85 @@
mRouteItems.put(routeItem.getId(), routeItem);
}
+ /**
+ * Returns whether route listing preference is enabled.
+ *
+ * @see #setRouteListingPreferenceEnabled
+ */
+ public boolean isRouteListingPreferenceEnabled() {
+ return mRouteListingPreferenceEnabled;
+ }
+
+ /**
+ * Sets whether the use of route listing preference is enabled or not.
+ *
+ * <p>If route listing preference is enabled, the route listing preference configuration for
+ * this app is maintained following the item list provided via {@link
+ * #setRouteListingPreferenceItems}. Otherwise, if route listing preference is disabled, the
+ * route listing preference for this app is set to null.
+ *
+ * @throws UnsupportedOperationException If called on a device running API 33 or older.
+ */
+ @OptIn(markerClass = BuildCompat.PrereleaseSdkCheck.class)
+ public void setRouteListingPreferenceEnabled(boolean routeListingPreferenceEnabled) {
+ if (BuildCompat.isAtLeastU()) {
+ mRouteListingPreferenceEnabled = routeListingPreferenceEnabled;
+ updatePlatformListingPreference();
+ } else {
+ throw new UnsupportedOperationException("RouteListingPreference requires Android U+.");
+ }
+ }
+
+ /** Returns whether the system ordering for route listing is preferred. */
+ public boolean getRouteListingSystemOrderingPreferred() {
+ return mRouteListingSystemOrderingPreferred;
+ }
+
+ /**
+ * Sets whether to prefer the system ordering for route listing.
+ *
+ * <p>True means that the ordering for route listing is the one in the {@link #getRouteItems()}
+ * list. If false, the ordering of said list is ignored, and the system uses its builtin
+ * ordering for the items.
+ */
+ @OptIn(markerClass = BuildCompat.PrereleaseSdkCheck.class)
+ public void setRouteListingSystemOrderingPreferred(
+ boolean routeListingSystemOrderringPreferred) {
+ if (BuildCompat.isAtLeastU()) {
+ mRouteListingSystemOrderingPreferred = routeListingSystemOrderringPreferred;
+ updatePlatformListingPreference();
+ } else {
+ throw new UnsupportedOperationException("RouteListingPreference requires Android U+.");
+ }
+ }
+
+ /**
+ * The current list of route listing preference items, as set via {@link
+ * #setRouteListingPreferenceItems}.
+ */
+ @NonNull
+ public List<RouteListingPreferenceItem> getRouteListingPreferenceItems() {
+ return mRouteListingPreferenceItems;
+ }
+
+ /**
+ * Sets the route listing preference items.
+ *
+ * @see #setRouteListingPreferenceEnabled
+ * @throws UnsupportedOperationException If called on a device running API 33 or older.
+ */
+ @OptIn(markerClass = BuildCompat.PrereleaseSdkCheck.class)
+ public void setRouteListingPreferenceItems(
+ @NonNull List<RouteListingPreferenceItem> preference) {
+ if (BuildCompat.isAtLeastU()) {
+ mRouteListingPreferenceItems =
+ Collections.unmodifiableList(new ArrayList<>(preference));
+ updatePlatformListingPreference();
+ } else {
+ throw new UnsupportedOperationException("RouteListingPreference requires Android U+.");
+ }
+ }
+
/** Changes the media router dialog type with the type stored in {@link RoutesManager} */
public void reloadDialogType() {
MediaRouter mediaRouter = MediaRouter.getInstance(mContext.getApplicationContext());
@@ -197,9 +294,97 @@
mRouteItems.put(r4.getId(), r4);
}
+ @RequiresApi(api = 34)
+ private void updatePlatformListingPreference() {
+ Api34Impl.updatePlatformRouteListingPreference(
+ mPlatformMediaRouter2,
+ mRouteListingPreferenceEnabled,
+ mRouteListingSystemOrderingPreferred,
+ mRouteListingPreferenceItems);
+ }
+
public enum DialogType {
DEFAULT,
DYNAMIC_GROUP,
OUTPUT_SWITCHER
}
+
+ /** An item corresponding to a route in the route listing preference of this app. */
+ public static final class RouteListingPreferenceItem {
+
+ @Retention(RetentionPolicy.SOURCE)
+ @IntDef(
+ flag = true,
+ value = {FLAG_ONGOING_SESSION, FLAG_ONGOING_SESSION_MANAGED, FLAG_SUGGESTED})
+ public @interface Flags {}
+
+ // TODO(b/266561322): Replace literals with constant references. We need to use their values
+ // directly because AndroidX still depends on an old SDK, where the new one has changed the
+ // values of the flags.
+ public static final int FLAG_ONGOING_SESSION = 1;
+
+ public static final int FLAG_ONGOING_SESSION_MANAGED = 1 << 1;
+
+ public static final int FLAG_SUGGESTED = 1 << 2;
+
+ @NonNull public final String mRouteId;
+ @NonNull public final String mRouteName;
+ public final int mFlags;
+ // TODO(b/266561322): Add subtext, deep-link-to-app, and others.
+
+ public RouteListingPreferenceItem(
+ @NonNull String routeId, @NonNull String routeName, int flags) {
+ mRouteId = routeId;
+ mRouteName = routeName;
+ mFlags = flags;
+ }
+
+ /** Returns a copy of this instance with the provided {@link #mFlags}. */
+ @NonNull
+ public RouteListingPreferenceItem copyWithFlags(@Flags int flags) {
+ return new RouteListingPreferenceItem(mRouteId, mRouteName, flags);
+ }
+
+ /** Returns the name of the corresponding route. */
+ @Override
+ @NonNull
+ public String toString() {
+ return mRouteName;
+ }
+ }
+
+ @RequiresApi(34)
+ private static class Api34Impl {
+
+ // TODO(b/266561322): Update the media router listing preference once the AndroidX api is
+ // in place.
+ private static void updatePlatformRouteListingPreference(
+ MediaRouter2 platformRouter,
+ boolean routeListingPreferenceEnabled,
+ boolean routeListingSystemOrderingPreferred,
+ List<RouteListingPreferenceItem> items) {
+ if (routeListingPreferenceEnabled) {
+ List<RouteListingPreference.Item> platformItems =
+ items.stream()
+ .map(
+ it ->
+ new RouteListingPreference.Item.Builder(it.mRouteId)
+ .setFlags(it.mFlags)
+ .build())
+ .collect(Collectors.toList());
+ RouteListingPreference routeListingPreference =
+ new RouteListingPreference.Builder()
+ .setUseSystemOrdering(routeListingSystemOrderingPreferred)
+ .setItems(platformItems)
+ .build();
+ platformRouter.setRouteListingPreference(routeListingPreference);
+ } else {
+ platformRouter.setRouteListingPreference(null);
+ }
+ }
+
+ private Api34Impl() {
+ // This class is not instantiable.
+ }
+ }
}
diff --git a/samples/MediaRoutingDemo/src/main/java/com/example/androidx/mediarouting/activities/RouteListingPreferenceActivity.java b/samples/MediaRoutingDemo/src/main/java/com/example/androidx/mediarouting/activities/RouteListingPreferenceActivity.java
new file mode 100644
index 0000000..493f8bb
--- /dev/null
+++ b/samples/MediaRoutingDemo/src/main/java/com/example/androidx/mediarouting/activities/RouteListingPreferenceActivity.java
@@ -0,0 +1,335 @@
+/*
+ * Copyright 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.example.androidx.mediarouting.activities;
+
+import static com.example.androidx.mediarouting.RoutesManager.RouteListingPreferenceItem.FLAG_ONGOING_SESSION;
+import static com.example.androidx.mediarouting.RoutesManager.RouteListingPreferenceItem.FLAG_ONGOING_SESSION_MANAGED;
+import static com.example.androidx.mediarouting.RoutesManager.RouteListingPreferenceItem.FLAG_SUGGESTED;
+
+import android.annotation.SuppressLint;
+import android.media.MediaRoute2Info;
+import android.media.MediaRouter2;
+import android.os.Build;
+import android.os.Bundle;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.ArrayAdapter;
+import android.widget.CheckBox;
+import android.widget.Spinner;
+import android.widget.Switch;
+import android.widget.TextView;
+import android.widget.Toast;
+
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+import androidx.annotation.OptIn;
+import androidx.appcompat.app.AlertDialog;
+import androidx.appcompat.app.AppCompatActivity;
+import androidx.core.os.BuildCompat;
+import androidx.recyclerview.widget.ItemTouchHelper;
+import androidx.recyclerview.widget.LinearLayoutManager;
+import androidx.recyclerview.widget.RecyclerView;
+
+import com.example.androidx.mediarouting.R;
+import com.example.androidx.mediarouting.RoutesManager;
+import com.google.android.material.floatingactionbutton.FloatingActionButton;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+import java.util.Set;
+import java.util.stream.Collectors;
+
+/** Allows the user to manage the route listing preference of this app. */
+public class RouteListingPreferenceActivity extends AppCompatActivity {
+
+ private RoutesManager mRoutesManager;
+ private RecyclerView mRouteListingPreferenceRecyclerView;
+
+ @OptIn(markerClass = BuildCompat.PrereleaseSdkCheck.class)
+ @Override
+ protected void onCreate(@Nullable Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+
+ if (!BuildCompat.isAtLeastU()) {
+ Toast.makeText(
+ /* context= */ this,
+ "Route Listing Preference requires Android U+",
+ Toast.LENGTH_LONG)
+ .show();
+ finish();
+ return;
+ }
+
+ setContentView(R.layout.activity_route_listing_preference);
+
+ mRoutesManager = RoutesManager.getInstance(/* context= */ this);
+
+ Switch preferSystemOrderingSwitch = findViewById(R.id.prefer_system_ordering_switch);
+ preferSystemOrderingSwitch.setChecked(
+ mRoutesManager.getRouteListingSystemOrderingPreferred());
+ preferSystemOrderingSwitch.setOnCheckedChangeListener(
+ (unusedButton, isChecked) -> {
+ mRoutesManager.setRouteListingSystemOrderingPreferred(isChecked);
+ });
+ preferSystemOrderingSwitch.setEnabled(mRoutesManager.isRouteListingPreferenceEnabled());
+
+ Switch enableRouteListingPreferenceSwitch =
+ findViewById(R.id.enable_route_listing_preference_switch);
+ enableRouteListingPreferenceSwitch.setChecked(
+ mRoutesManager.isRouteListingPreferenceEnabled());
+ enableRouteListingPreferenceSwitch.setOnCheckedChangeListener(
+ (unusedButton, isChecked) -> {
+ mRoutesManager.setRouteListingPreferenceEnabled(isChecked);
+ preferSystemOrderingSwitch.setEnabled(isChecked);
+ });
+
+ mRouteListingPreferenceRecyclerView =
+ findViewById(R.id.route_listing_preference_recycler_view);
+ new ItemTouchHelper(new RecyclerViewCallback())
+ .attachToRecyclerView(mRouteListingPreferenceRecyclerView);
+ mRouteListingPreferenceRecyclerView.setLayoutManager(
+ new LinearLayoutManager(/* context= */ this));
+ mRouteListingPreferenceRecyclerView.setHasFixedSize(true);
+ mRouteListingPreferenceRecyclerView.setAdapter(
+ new RouteListingPreferenceRecyclerViewAdapter());
+
+ FloatingActionButton newRouteButton =
+ findViewById(R.id.new_route_listing_preference_item_button);
+ newRouteButton.setOnClickListener(
+ view ->
+ setUpRouteListingPreferenceItemEditionDialog(
+ mRoutesManager.getRouteListingPreferenceItems().size()));
+ }
+
+ // This method won't run before U due to checks in onCreate().
+ @SuppressLint({"NewApi", "ClassVerificationFailure"})
+ private void setUpRouteListingPreferenceItemEditionDialog(int itemPositionInList) {
+ List<RoutesManager.RouteListingPreferenceItem> routeListingPreference =
+ mRoutesManager.getRouteListingPreferenceItems();
+ List<MediaRoute2Info> routesWithNoAssociatedListingPreferenceItem =
+ getRoutesWithNoAssociatedListingPreferenceItem();
+ if (itemPositionInList == routeListingPreference.size()
+ && routesWithNoAssociatedListingPreferenceItem.isEmpty()) {
+ Toast.makeText(/* context= */ this, "No (more) routes available", Toast.LENGTH_LONG)
+ .show();
+ return;
+ }
+ View dialogView =
+ getLayoutInflater()
+ .inflate(R.layout.route_listing_preference_item_dialog, /* root= */ null);
+
+ Spinner routeSpinner = dialogView.findViewById(R.id.rlp_item_dialog_route_name_spinner);
+ List<RoutesManager.RouteListingPreferenceItem> spinnerEntries = new ArrayList<>();
+
+ CheckBox ongoingSessionCheckBox =
+ dialogView.findViewById(R.id.rlp_item_dialog_ongoing_session_checkbox);
+ CheckBox sessionManagedCheckBox =
+ dialogView.findViewById(R.id.rlp_item_dialog_session_managed_checkbox);
+ CheckBox suggestedRouteCheckBox =
+ dialogView.findViewById(R.id.rlp_item_dialog_suggested_checkbox);
+
+ if (itemPositionInList < routeListingPreference.size()) {
+ RoutesManager.RouteListingPreferenceItem itemToEdit =
+ routeListingPreference.get(itemPositionInList);
+ spinnerEntries.add(itemToEdit);
+ ongoingSessionCheckBox.setChecked((itemToEdit.mFlags & FLAG_ONGOING_SESSION) != 0);
+ sessionManagedCheckBox.setChecked(
+ (itemToEdit.mFlags & FLAG_ONGOING_SESSION_MANAGED) != 0);
+ suggestedRouteCheckBox.setChecked((itemToEdit.mFlags & FLAG_SUGGESTED) != 0);
+ }
+ for (MediaRoute2Info mediaRoute2Info : routesWithNoAssociatedListingPreferenceItem) {
+ spinnerEntries.add(
+ new RoutesManager.RouteListingPreferenceItem(
+ mediaRoute2Info.getId(),
+ String.valueOf(mediaRoute2Info.getName()),
+ /* flags= */ 0));
+ }
+ routeSpinner.setAdapter(
+ new ArrayAdapter<>(
+ /* context= */ this, android.R.layout.simple_spinner_item, spinnerEntries));
+
+ AlertDialog editRlpItemDialog =
+ new AlertDialog.Builder(this)
+ .setView(dialogView)
+ .setPositiveButton(
+ "Accept",
+ (unusedDialog, unusedWhich) -> {
+ RoutesManager.RouteListingPreferenceItem item =
+ (RoutesManager.RouteListingPreferenceItem)
+ routeSpinner.getSelectedItem();
+ int flags = 0;
+ flags |=
+ ongoingSessionCheckBox.isChecked()
+ ? FLAG_ONGOING_SESSION
+ : 0;
+ flags |=
+ sessionManagedCheckBox.isChecked()
+ ? FLAG_ONGOING_SESSION_MANAGED
+ : 0;
+ flags |=
+ suggestedRouteCheckBox.isChecked() ? FLAG_SUGGESTED : 0;
+ onEditRlpItemDialogAccepted(
+ item.copyWithFlags(flags), itemPositionInList);
+ })
+ .setNegativeButton("Dismiss", (unusedDialog, unusedWhich) -> {})
+ .create();
+
+ editRlpItemDialog.show();
+ }
+
+ private void onEditRlpItemDialogAccepted(
+ RoutesManager.RouteListingPreferenceItem routeListingPreferenceItem,
+ int itemPositionInList) {
+ ArrayList<RoutesManager.RouteListingPreferenceItem> newRouteListingPreference =
+ new ArrayList<>(mRoutesManager.getRouteListingPreferenceItems());
+ RecyclerView.Adapter<?> adapter = mRouteListingPreferenceRecyclerView.getAdapter();
+ if (itemPositionInList < newRouteListingPreference.size()) {
+ newRouteListingPreference.set(itemPositionInList, routeListingPreferenceItem);
+ adapter.notifyItemChanged(itemPositionInList);
+ } else {
+ newRouteListingPreference.add(routeListingPreferenceItem);
+ adapter.notifyItemInserted(itemPositionInList);
+ }
+ mRoutesManager.setRouteListingPreferenceItems(newRouteListingPreference);
+ }
+
+ // This method won't run before U due to checks in onCreate().
+ @SuppressLint({"NewApi", "ClassVerificationFailure"})
+ @NonNull
+ private List<MediaRoute2Info> getRoutesWithNoAssociatedListingPreferenceItem() {
+ if (Build.VERSION.SDK_INT < Build.VERSION_CODES.R) {
+ return Collections.emptyList();
+ }
+ Set<String> routesWithAssociatedRouteListingPreferenceItem =
+ mRoutesManager.getRouteListingPreferenceItems().stream()
+ .map(item -> item.mRouteId)
+ .collect(Collectors.toSet());
+ List<MediaRoute2Info> availableRoutes =
+ MediaRouter2.getInstance(/* context= */ this).getRoutes();
+ return availableRoutes.stream()
+ .filter(
+ route ->
+ !routesWithAssociatedRouteListingPreferenceItem.contains(
+ route.getId()))
+ .collect(Collectors.toList());
+ }
+
+ private class RecyclerViewCallback extends ItemTouchHelper.SimpleCallback {
+
+ private static final int INDEX_UNSET = -1;
+
+ private int mDraggingFromPosition;
+ private int mDraggingToPosition;
+
+ private RecyclerViewCallback() {
+ super(
+ ItemTouchHelper.UP | ItemTouchHelper.DOWN,
+ ItemTouchHelper.START | ItemTouchHelper.END);
+ mDraggingFromPosition = INDEX_UNSET;
+ mDraggingToPosition = INDEX_UNSET;
+ }
+
+ @Override
+ public boolean onMove(
+ @NonNull RecyclerView recyclerView,
+ @NonNull RecyclerView.ViewHolder origin,
+ @NonNull RecyclerView.ViewHolder target) {
+ int fromPosition = origin.getBindingAdapterPosition();
+ int toPosition = target.getBindingAdapterPosition();
+ if (mDraggingFromPosition == INDEX_UNSET) {
+ // A drag has started, but we wait for the clearView() call to update the route
+ // listing preference.
+ mDraggingFromPosition = fromPosition;
+ }
+ mDraggingToPosition = toPosition;
+ recyclerView.getAdapter().notifyItemMoved(fromPosition, toPosition);
+ return false;
+ }
+
+ @Override
+ public void onSwiped(@NonNull RecyclerView.ViewHolder viewHolder, int direction) {
+ ArrayList<RoutesManager.RouteListingPreferenceItem> newRouteListingPreference =
+ new ArrayList<>(mRoutesManager.getRouteListingPreferenceItems());
+ int itemPosition = viewHolder.getBindingAdapterPosition();
+ newRouteListingPreference.remove(itemPosition);
+ mRoutesManager.setRouteListingPreferenceItems(newRouteListingPreference);
+ viewHolder.getBindingAdapter().notifyItemRemoved(itemPosition);
+ }
+
+ @Override
+ public void clearView(
+ @NonNull RecyclerView recyclerView, @NonNull RecyclerView.ViewHolder viewHolder) {
+ super.clearView(recyclerView, viewHolder);
+ if (mDraggingFromPosition != INDEX_UNSET) {
+ ArrayList<RoutesManager.RouteListingPreferenceItem> newRouteListingPreference =
+ new ArrayList<>(mRoutesManager.getRouteListingPreferenceItems());
+ newRouteListingPreference.add(
+ mDraggingToPosition,
+ newRouteListingPreference.remove(mDraggingFromPosition));
+ }
+ mDraggingFromPosition = INDEX_UNSET;
+ mDraggingToPosition = INDEX_UNSET;
+ }
+ }
+
+ private class RouteListingPreferenceRecyclerViewAdapter
+ extends RecyclerView.Adapter<RecyclerViewItemViewHolder> {
+ @NonNull
+ @Override
+ public RecyclerViewItemViewHolder onCreateViewHolder(
+ @NonNull ViewGroup parent, int viewType) {
+ TextView textView =
+ (TextView)
+ LayoutInflater.from(parent.getContext())
+ .inflate(
+ android.R.layout.simple_list_item_1,
+ parent,
+ /* attachToRoot= */ false);
+ return new RecyclerViewItemViewHolder(textView);
+ }
+
+ @Override
+ public void onBindViewHolder(@NonNull RecyclerViewItemViewHolder holder, int position) {
+ holder.mTextView.setText(
+ mRoutesManager.getRouteListingPreferenceItems().get(position).mRouteName);
+ }
+
+ @Override
+ public int getItemCount() {
+ return mRoutesManager.getRouteListingPreferenceItems().size();
+ }
+ }
+
+ private class RecyclerViewItemViewHolder extends RecyclerView.ViewHolder
+ implements View.OnClickListener {
+
+ public final TextView mTextView;
+
+ private RecyclerViewItemViewHolder(TextView textView) {
+ super(textView);
+ mTextView = textView;
+ textView.setOnClickListener(this);
+ }
+
+ @Override
+ public void onClick(View view) {
+ setUpRouteListingPreferenceItemEditionDialog(getBindingAdapterPosition());
+ }
+ }
+}
diff --git a/samples/MediaRoutingDemo/src/main/java/com/example/androidx/mediarouting/activities/SettingsActivity.java b/samples/MediaRoutingDemo/src/main/java/com/example/androidx/mediarouting/activities/SettingsActivity.java
index aae3bd1..6efb10a 100644
--- a/samples/MediaRoutingDemo/src/main/java/com/example/androidx/mediarouting/activities/SettingsActivity.java
+++ b/samples/MediaRoutingDemo/src/main/java/com/example/androidx/mediarouting/activities/SettingsActivity.java
@@ -26,6 +26,7 @@
import android.view.View;
import android.widget.AdapterView;
import android.widget.ArrayAdapter;
+import android.widget.Button;
import android.widget.Spinner;
import android.widget.Switch;
@@ -91,6 +92,13 @@
}
};
+ Button goToRouteListingPreferenceButton =
+ findViewById(R.id.go_to_route_listing_preference_button);
+ goToRouteListingPreferenceButton.setOnClickListener(
+ unusedView -> {
+ startActivity(new Intent(this, RouteListingPreferenceActivity.class));
+ });
+
RecyclerView routeList = findViewById(R.id.routes_recycler_view);
routeList.setLayoutManager(new LinearLayoutManager(/* context= */ this));
mRoutesAdapter = new RoutesAdapter(mRoutesManager.getRouteItems(), routeItemListener);
diff --git a/samples/MediaRoutingDemo/src/main/res/layout/activity_route_listing_preference.xml b/samples/MediaRoutingDemo/src/main/res/layout/activity_route_listing_preference.xml
new file mode 100644
index 0000000..b932051
--- /dev/null
+++ b/samples/MediaRoutingDemo/src/main/res/layout/activity_route_listing_preference.xml
@@ -0,0 +1,97 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2023 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+
+
+<LinearLayout
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:app="http://schemas.android.com/apk/res-auto"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:orientation="vertical">
+
+ <RelativeLayout
+ android:layout_width="match_parent"
+ android:layout_height="50dp"
+ android:layout_margin="12dp"
+ android:padding="4dp">
+
+ <TextView
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_alignParentLeft="true"
+ android:layout_alignParentStart="true"
+ android:layout_centerVertical="true"
+ android:gravity="center"
+ android:text="Enable Route Listing Preference" />
+
+ <Switch
+ android:id="@+id/enable_route_listing_preference_switch"
+ android:layout_width="wrap_content"
+ android:layout_height="match_parent"
+ android:layout_alignParentEnd="true"
+ android:layout_alignParentRight="true"
+ android:layout_centerVertical="true" />
+
+ </RelativeLayout>
+
+ <RelativeLayout
+ android:layout_width="match_parent"
+ android:layout_height="50dp"
+ android:layout_margin="12dp"
+ android:padding="4dp">
+
+ <TextView
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_alignParentLeft="true"
+ android:layout_alignParentStart="true"
+ android:layout_centerVertical="true"
+ android:gravity="center"
+ android:text="Prefer system ordering" />
+
+ <Switch
+ android:id="@+id/prefer_system_ordering_switch"
+ android:layout_width="wrap_content"
+ android:layout_height="match_parent"
+ android:layout_alignParentEnd="true"
+ android:layout_alignParentRight="true"
+ android:layout_centerVertical="true" />
+
+ </RelativeLayout>
+
+ <RelativeLayout
+ android:layout_width="match_parent"
+ android:layout_height="match_parent">
+
+ <androidx.recyclerview.widget.RecyclerView
+ android:id="@+id/route_listing_preference_recycler_view"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:layout_weight="1" />
+
+ <com.google.android.material.floatingactionbutton.FloatingActionButton
+ android:id="@+id/new_route_listing_preference_item_button"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_alignParentBottom="true"
+ android:layout_alignParentEnd="true"
+ android:layout_alignParentRight="true"
+ android:layout_margin="20dp"
+ android:padding="0dp"
+ app:srcCompat="@drawable/ic_add" />
+
+ </RelativeLayout>
+</LinearLayout>
diff --git a/samples/MediaRoutingDemo/src/main/res/layout/activity_settings.xml b/samples/MediaRoutingDemo/src/main/res/layout/activity_settings.xml
index 8432164..d421ef3 100644
--- a/samples/MediaRoutingDemo/src/main/res/layout/activity_settings.xml
+++ b/samples/MediaRoutingDemo/src/main/res/layout/activity_settings.xml
@@ -23,6 +23,12 @@
android:layout_height="wrap_content"
android:orientation="vertical">
+ <Button
+ android:id="@+id/go_to_route_listing_preference_button"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:text="Route listing preference"/>
+
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="50dp"
diff --git a/samples/MediaRoutingDemo/src/main/res/layout/route_listing_preference_item_dialog.xml b/samples/MediaRoutingDemo/src/main/res/layout/route_listing_preference_item_dialog.xml
new file mode 100644
index 0000000..9033216
--- /dev/null
+++ b/samples/MediaRoutingDemo/src/main/res/layout/route_listing_preference_item_dialog.xml
@@ -0,0 +1,118 @@
+<?xml version="1.0" encoding="utf-8"?><!--
+ Copyright 2023 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:orientation="vertical"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent">
+
+ <LinearLayout
+ android:layout_width="match_parent"
+ android:layout_height="50dp"
+ android:layout_margin="12dp"
+ android:padding="4dp">
+
+ <TextView
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_alignParentLeft="true"
+ android:layout_alignParentStart="true"
+ android:layout_centerVertical="true"
+ android:gravity="center"
+ android:text="Route name" />
+
+ <Spinner
+ android:id="@+id/rlp_item_dialog_route_name_spinner"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:layout_alignParentEnd="true"
+ android:layout_alignParentRight="true"
+ android:layout_centerVertical="true" />
+ </LinearLayout>
+
+ <RelativeLayout
+ android:layout_width="match_parent"
+ android:layout_height="50dp"
+ android:layout_margin="12dp"
+ android:padding="4dp">
+
+ <TextView
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_alignParentLeft="true"
+ android:layout_alignParentStart="true"
+ android:layout_centerVertical="true"
+ android:gravity="center"
+ android:text="Ongoing session" />
+
+ <CheckBox
+ android:id="@+id/rlp_item_dialog_ongoing_session_checkbox"
+ android:layout_width="wrap_content"
+ android:layout_height="match_parent"
+ android:layout_alignParentEnd="true"
+ android:layout_alignParentRight="true"
+ android:layout_centerVertical="true" />
+ </RelativeLayout>
+
+ <RelativeLayout
+ android:layout_width="match_parent"
+ android:layout_height="50dp"
+ android:layout_margin="12dp"
+ android:padding="4dp">
+
+ <TextView
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_alignParentLeft="true"
+ android:layout_alignParentStart="true"
+ android:layout_centerVertical="true"
+ android:gravity="center"
+ android:text="Ongoing session managed" />
+
+ <CheckBox
+ android:id="@+id/rlp_item_dialog_session_managed_checkbox"
+ android:layout_width="wrap_content"
+ android:layout_height="match_parent"
+ android:layout_alignParentEnd="true"
+ android:layout_alignParentRight="true"
+ android:layout_centerVertical="true" />
+ </RelativeLayout>
+
+ <RelativeLayout
+ android:layout_width="match_parent"
+ android:layout_height="50dp"
+ android:layout_margin="12dp"
+ android:padding="4dp">
+
+ <TextView
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_alignParentLeft="true"
+ android:layout_alignParentStart="true"
+ android:layout_centerVertical="true"
+ android:gravity="center"
+ android:text="Suggested route" />
+
+ <CheckBox
+ android:id="@+id/rlp_item_dialog_suggested_checkbox"
+ android:layout_width="wrap_content"
+ android:layout_height="match_parent"
+ android:layout_alignParentEnd="true"
+ android:layout_alignParentRight="true"
+ android:layout_centerVertical="true" />
+ </RelativeLayout>
+
+</LinearLayout>
\ No newline at end of file
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 855f060..096366c 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
@@ -249,6 +249,7 @@
return builder.build();
}
+ @SuppressWarnings("deprecation")
@Override
public void setAvailableAuthenticationKeys(int keyCount, int maxUsesPerKey) {
mCredential.setAvailableAuthenticationKeys(keyCount, maxUsesPerKey);
@@ -271,6 +272,7 @@
}
}
+ @SuppressWarnings("deprecation")
@Override
public @NonNull
int[] getAuthenticationDataUsageCount() {
diff --git a/settings.gradle b/settings.gradle
index c405219..800f0dc 100644
--- a/settings.gradle
+++ b/settings.gradle
@@ -92,9 +92,9 @@
value("androidx.projects", getRequestedProjectSubsetName() ?: "Unset")
value("androidx.useMaxDepVersions", providers.gradleProperty("androidx.useMaxDepVersions").isPresent().toString())
- // Publish scan for androidx-main
- publishAlways()
- publishIfAuthenticated()
+ // Do not publish scan for androidx-platform-dev
+ // publishAlways()
+ // publishIfAuthenticated()
}
}
@@ -621,6 +621,7 @@
includeProject(":core:core-splashscreen:core-splashscreen-samples", "core/core-splashscreen/samples", [BuildType.MAIN])
includeProject(":core:core-graphics-integration-tests:core-graphics-integration-tests", "core/core-graphics-integration-tests/testapp", [BuildType.MAIN])
includeProject(":core:core-role", [BuildType.MAIN])
+includeProject(":core:core-telecom", [BuildType.MAIN])
includeProject(":core:uwb:uwb", [BuildType.MAIN])
includeProject(":core:uwb:uwb-rxjava3", [BuildType.MAIN])
includeProject(":credentials:credentials", [BuildType.MAIN])
@@ -692,9 +693,10 @@
includeProject(":glance:glance-wear-tiles", [BuildType.GLANCE])
includeProject(":glance:glance-wear-tiles-preview", [BuildType.GLANCE])
includeProject(":graphics:filters:filters", [BuildType.MAIN])
+includeProject(":graphics:graphics-path", [BuildType.MAIN])
includeProject(":graphics:graphics-core", [BuildType.MAIN])
+includeProject(":graphics:graphics-shapes", [BuildType.MAIN, BuildType.COMPOSE])
includeProject(":graphics:integration-tests:testapp", [BuildType.MAIN])
-includeProject(":graphics:graphics-shapes", [BuildType.MAIN])
includeProject(":gridlayout:gridlayout", [BuildType.MAIN])
includeProject(":health:connect:connect-client", [BuildType.MAIN])
includeProject(":health:connect:connect-client-proto", [BuildType.MAIN])
@@ -985,20 +987,20 @@
includeProject(":wear:watchface:watchface-style-old-api-test-stub", "wear/watchface/watchface-style/old-api-test-stub", [BuildType.MAIN, BuildType.WEAR])
includeProject(":webkit:integration-tests:testapp", [BuildType.MAIN])
includeProject(":webkit:webkit", [BuildType.MAIN])
-includeProject(":window:window", [BuildType.MAIN, BuildType.COMPOSE, BuildType.FLAN, BuildType.CAMERA])
-includeProject(":window:window-samples", "window/window/samples", [BuildType.MAIN, BuildType.COMPOSE, BuildType.FLAN, BuildType.CAMERA])
-includeProject(":window:extensions:extensions", [BuildType.MAIN, BuildType.COMPOSE, BuildType.FLAN, BuildType.CAMERA])
-includeProject(":window:extensions:core:core", [BuildType.MAIN, BuildType.COMPOSE, BuildType.FLAN, BuildType.CAMERA])
-includeProject(":window:integration-tests:configuration-change-tests", [BuildType.MAIN])
-includeProject(":window:sidecar:sidecar", [BuildType.MAIN, BuildType.COMPOSE, BuildType.FLAN, BuildType.CAMERA])
-includeProject(":window:window-java", [BuildType.MAIN, BuildType.COMPOSE, BuildType.FLAN, BuildType.CAMERA])
-includeProject(":window:window-core", [BuildType.MAIN, BuildType.COMPOSE, BuildType.FLAN, BuildType.CAMERA])
-includeProject(":window:window-rxjava2", [BuildType.MAIN])
-includeProject(":window:window-rxjava3", [BuildType.MAIN])
-includeProject(":window:window-demos:demo", [BuildType.MAIN, BuildType.COMPOSE, BuildType.FLAN, BuildType.CAMERA])
-includeProject(":window:window-demos:demo-common", [BuildType.MAIN, BuildType.COMPOSE, BuildType.FLAN, BuildType.CAMERA])
-includeProject(":window:window-demos:demo-second-app", [BuildType.MAIN, BuildType.COMPOSE, BuildType.FLAN, BuildType.CAMERA])
-includeProject(":window:window-testing", [BuildType.MAIN, BuildType.COMPOSE, BuildType.FLAN, BuildType.CAMERA])
+includeProject(":window:window", [BuildType.MAIN, BuildType.COMPOSE, BuildType.FLAN, BuildType.CAMERA, BuildType.WINDOW])
+includeProject(":window:window-samples", "window/window/samples", [BuildType.MAIN, BuildType.COMPOSE, BuildType.FLAN, BuildType.CAMERA, BuildType.WINDOW])
+includeProject(":window:extensions:extensions", [BuildType.MAIN, BuildType.COMPOSE, BuildType.FLAN, BuildType.CAMERA, BuildType.WINDOW])
+includeProject(":window:extensions:core:core", [BuildType.MAIN, BuildType.COMPOSE, BuildType.FLAN, BuildType.CAMERA, BuildType.WINDOW])
+includeProject(":window:integration-tests:configuration-change-tests", [BuildType.MAIN, BuildType.WINDOW])
+includeProject(":window:sidecar:sidecar", [BuildType.MAIN, BuildType.COMPOSE, BuildType.FLAN, BuildType.CAMERA, BuildType.WINDOW])
+includeProject(":window:window-java", [BuildType.MAIN, BuildType.COMPOSE, BuildType.FLAN, BuildType.CAMERA, BuildType.WINDOW])
+includeProject(":window:window-core", [BuildType.MAIN, BuildType.COMPOSE, BuildType.FLAN, BuildType.CAMERA, BuildType.WINDOW])
+includeProject(":window:window-rxjava2", [BuildType.MAIN, BuildType.WINDOW])
+includeProject(":window:window-rxjava3", [BuildType.MAIN, BuildType.WINDOW])
+includeProject(":window:window-demos:demo", [BuildType.MAIN, BuildType.COMPOSE, BuildType.FLAN, BuildType.CAMERA, BuildType.WINDOW])
+includeProject(":window:window-demos:demo-common", [BuildType.MAIN, BuildType.COMPOSE, BuildType.FLAN, BuildType.CAMERA, BuildType.WINDOW])
+includeProject(":window:window-demos:demo-second-app", [BuildType.MAIN, BuildType.COMPOSE, BuildType.FLAN, BuildType.CAMERA, BuildType.WINDOW])
+includeProject(":window:window-testing", [BuildType.MAIN, BuildType.COMPOSE, BuildType.FLAN, BuildType.CAMERA, BuildType.WINDOW])
includeProject(":work:integration-tests:testapp", [BuildType.MAIN])
includeProject(":work:work-benchmark", [BuildType.MAIN])
includeProject(":work:work-gcm", [BuildType.MAIN])
diff --git a/slidingpanelayout/slidingpanelayout/api/api_lint.ignore b/slidingpanelayout/slidingpanelayout/api/api_lint.ignore
index e495753..a288bd0 100644
--- a/slidingpanelayout/slidingpanelayout/api/api_lint.ignore
+++ b/slidingpanelayout/slidingpanelayout/api/api_lint.ignore
@@ -1,10 +1,6 @@
// Baseline format: 1.0
InvalidNullabilityOverride: androidx.slidingpanelayout.widget.SlidingPaneLayout#addView(android.view.View, int, android.view.ViewGroup.LayoutParams) parameter #0:
Invalid nullability on parameter `child` in method `addView`. Parameters of overrides cannot be NonNull if the super parameter is unannotated.
-InvalidNullabilityOverride: androidx.slidingpanelayout.widget.SlidingPaneLayout#draw(android.graphics.Canvas) parameter #0:
- Invalid nullability on parameter `c` in method `draw`. Parameters of overrides cannot be NonNull if the super parameter is unannotated.
-InvalidNullabilityOverride: androidx.slidingpanelayout.widget.SlidingPaneLayout#drawChild(android.graphics.Canvas, android.view.View, long) parameter #0:
- Invalid nullability on parameter `canvas` in method `drawChild`. Parameters of overrides cannot be NonNull if the super parameter is unannotated.
InvalidNullabilityOverride: androidx.slidingpanelayout.widget.SlidingPaneLayout#removeView(android.view.View) parameter #0:
Invalid nullability on parameter `view` in method `removeView`. Parameters of overrides cannot be NonNull if the super parameter is unannotated.
@@ -15,6 +11,10 @@
MissingNullability: androidx.slidingpanelayout.widget.SlidingPaneLayout#checkLayoutParams(android.view.ViewGroup.LayoutParams) parameter #0:
Missing nullability on parameter `p` in method `checkLayoutParams`
+MissingNullability: androidx.slidingpanelayout.widget.SlidingPaneLayout#draw(android.graphics.Canvas) parameter #0:
+ Missing nullability on parameter `c` in method `draw`
+MissingNullability: androidx.slidingpanelayout.widget.SlidingPaneLayout#drawChild(android.graphics.Canvas, android.view.View, long) parameter #0:
+ Missing nullability on parameter `canvas` in method `drawChild`
MissingNullability: androidx.slidingpanelayout.widget.SlidingPaneLayout#drawChild(android.graphics.Canvas, android.view.View, long) parameter #1:
Missing nullability on parameter `child` in method `drawChild`
MissingNullability: androidx.slidingpanelayout.widget.SlidingPaneLayout#generateDefaultLayoutParams():
diff --git a/swiperefreshlayout/swiperefreshlayout/api/api_lint.ignore b/swiperefreshlayout/swiperefreshlayout/api/api_lint.ignore
index 6038f08..25a9da5 100644
--- a/swiperefreshlayout/swiperefreshlayout/api/api_lint.ignore
+++ b/swiperefreshlayout/swiperefreshlayout/api/api_lint.ignore
@@ -13,6 +13,8 @@
Internal field mOriginalOffsetTop must not be exposed
+MissingNullability: androidx.swiperefreshlayout.widget.CircularProgressDrawable#draw(android.graphics.Canvas) parameter #0:
+ Missing nullability on parameter `canvas` in method `draw`
MissingNullability: androidx.swiperefreshlayout.widget.CircularProgressDrawable#setColorFilter(android.graphics.ColorFilter) parameter #0:
Missing nullability on parameter `colorFilter` in method `setColorFilter`
MissingNullability: androidx.swiperefreshlayout.widget.SwipeRefreshLayout#onInterceptTouchEvent(android.view.MotionEvent) parameter #0:
diff --git a/viewpager/viewpager/api/api_lint.ignore b/viewpager/viewpager/api/api_lint.ignore
index 1c07b48..908ecb2 100644
--- a/viewpager/viewpager/api/api_lint.ignore
+++ b/viewpager/viewpager/api/api_lint.ignore
@@ -9,18 +9,12 @@
Symmetric method for `setDrawFullUnderline` must be named `isDrawFullUnderline`; was `getDrawFullUnderline`
-InvalidNullabilityOverride: androidx.viewpager.widget.PagerTabStrip#onDraw(android.graphics.Canvas) parameter #0:
- Invalid nullability on parameter `canvas` in method `onDraw`. Parameters of overrides cannot be NonNull if the super parameter is unannotated.
-InvalidNullabilityOverride: androidx.viewpager.widget.ViewPager#draw(android.graphics.Canvas) parameter #0:
- Invalid nullability on parameter `canvas` in method `draw`. Parameters of overrides cannot be NonNull if the super parameter is unannotated.
-InvalidNullabilityOverride: androidx.viewpager.widget.ViewPager#onDraw(android.graphics.Canvas) parameter #0:
- Invalid nullability on parameter `canvas` in method `onDraw`. Parameters of overrides cannot be NonNull if the super parameter is unannotated.
-
-
ListenerInterface: androidx.viewpager.widget.ViewPager.SimpleOnPageChangeListener:
Listeners should be an interface, or otherwise renamed Callback: SimpleOnPageChangeListener
+MissingNullability: androidx.viewpager.widget.PagerTabStrip#onDraw(android.graphics.Canvas) parameter #0:
+ Missing nullability on parameter `canvas` in method `onDraw`
MissingNullability: androidx.viewpager.widget.PagerTabStrip#onTouchEvent(android.view.MotionEvent) parameter #0:
Missing nullability on parameter `ev` in method `onTouchEvent`
MissingNullability: androidx.viewpager.widget.PagerTabStrip#setBackgroundDrawable(android.graphics.drawable.Drawable) parameter #0:
@@ -39,6 +33,8 @@
Missing nullability on parameter `event` in method `dispatchKeyEvent`
MissingNullability: androidx.viewpager.widget.ViewPager#dispatchPopulateAccessibilityEvent(android.view.accessibility.AccessibilityEvent) parameter #0:
Missing nullability on parameter `event` in method `dispatchPopulateAccessibilityEvent`
+MissingNullability: androidx.viewpager.widget.ViewPager#draw(android.graphics.Canvas) parameter #0:
+ Missing nullability on parameter `canvas` in method `draw`
MissingNullability: androidx.viewpager.widget.ViewPager#generateDefaultLayoutParams():
Missing nullability on method `generateDefaultLayoutParams` return
MissingNullability: androidx.viewpager.widget.ViewPager#generateLayoutParams(android.util.AttributeSet):
@@ -49,6 +45,8 @@
Missing nullability on method `generateLayoutParams` return
MissingNullability: androidx.viewpager.widget.ViewPager#generateLayoutParams(android.view.ViewGroup.LayoutParams) parameter #0:
Missing nullability on parameter `p` in method `generateLayoutParams`
+MissingNullability: androidx.viewpager.widget.ViewPager#onDraw(android.graphics.Canvas) parameter #0:
+ Missing nullability on parameter `canvas` in method `onDraw`
MissingNullability: androidx.viewpager.widget.ViewPager#onInterceptTouchEvent(android.view.MotionEvent) parameter #0:
Missing nullability on parameter `ev` in method `onInterceptTouchEvent`
MissingNullability: androidx.viewpager.widget.ViewPager#onRequestFocusInDescendants(int, android.graphics.Rect) parameter #1:
diff --git a/wear/tiles/tiles-material/src/androidTest/java/androidx/wear/tiles/material/MaterialGoldenXLTest.java b/wear/tiles/tiles-material/src/androidTest/java/androidx/wear/tiles/material/MaterialGoldenXLTest.java
index f42d628..6ad6f38 100644
--- a/wear/tiles/tiles-material/src/androidTest/java/androidx/wear/tiles/material/MaterialGoldenXLTest.java
+++ b/wear/tiles/tiles-material/src/androidTest/java/androidx/wear/tiles/material/MaterialGoldenXLTest.java
@@ -73,6 +73,8 @@
}
@Parameterized.Parameters(name = "{0}")
+ // TODO(b/267744228): Remove the warning suppression.
+ @SuppressWarnings("deprecation")
public static Collection<Object[]> data() {
Context context = InstrumentationRegistry.getInstrumentation().getTargetContext();
DisplayMetrics currentDisplayMetrics = new DisplayMetrics();
diff --git a/wear/tiles/tiles-material/src/androidTest/java/androidx/wear/tiles/material/layouts/LayoutsGoldenXLTest.java b/wear/tiles/tiles-material/src/androidTest/java/androidx/wear/tiles/material/layouts/LayoutsGoldenXLTest.java
index 41ee4be..4f5ece5 100644
--- a/wear/tiles/tiles-material/src/androidTest/java/androidx/wear/tiles/material/layouts/LayoutsGoldenXLTest.java
+++ b/wear/tiles/tiles-material/src/androidTest/java/androidx/wear/tiles/material/layouts/LayoutsGoldenXLTest.java
@@ -73,6 +73,8 @@
}
@Parameterized.Parameters(name = "{0}")
+ // TODO(b/267744228): Remove the warning suppression.
+ @SuppressWarnings("deprecation")
public static Collection<Object[]> data() {
Context context = InstrumentationRegistry.getInstrumentation().getTargetContext();
DisplayMetrics currentDisplayMetrics = new DisplayMetrics();
diff --git a/wear/tiles/tiles-material/src/main/java/androidx/wear/tiles/material/Typography.java b/wear/tiles/tiles-material/src/main/java/androidx/wear/tiles/material/Typography.java
index 8941e70..70451b3 100644
--- a/wear/tiles/tiles-material/src/main/java/androidx/wear/tiles/material/Typography.java
+++ b/wear/tiles/tiles-material/src/main/java/androidx/wear/tiles/material/Typography.java
@@ -189,6 +189,8 @@
// and convert it to SP which is needed to be passed in as a font size. However, we will pass an
// SP object to it, because the default style is defined in it, but for the case when the font
// size on device in 1, so the DP is equal to SP.
+ // TODO(b/267744228): Remove the warning suppression.
+ @SuppressWarnings("deprecation")
private static SpProp dpToSp(@NonNull Context context, @Dimension(unit = DP) float valueDp) {
DisplayMetrics metrics = context.getResources().getDisplayMetrics();
float scaledSp = (valueDp / metrics.scaledDensity) * metrics.density;
diff --git a/webkit/webkit/api/1.6.0-beta02.txt b/webkit/webkit/api/1.6.0-beta02.txt
deleted file mode 100644
index faf13cb..0000000
--- a/webkit/webkit/api/1.6.0-beta02.txt
+++ /dev/null
@@ -1,300 +0,0 @@
-// Signature format: 4.0
-package androidx.webkit {
-
- public class CookieManagerCompat {
- method @RequiresFeature(name=androidx.webkit.WebViewFeature.GET_COOKIE_INFO, enforcement="androidx.webkit.WebViewFeature#isFeatureSupported") public static java.util.List<java.lang.String!> getCookieInfo(android.webkit.CookieManager, String);
- }
-
- public abstract class JavaScriptReplyProxy {
- method @RequiresFeature(name=androidx.webkit.WebViewFeature.WEB_MESSAGE_LISTENER, enforcement="androidx.webkit.WebViewFeature#isFeatureSupported") public abstract void postMessage(String);
- }
-
- public class ProcessGlobalConfig {
- ctor public ProcessGlobalConfig();
- method public static void apply(androidx.webkit.ProcessGlobalConfig);
- method @RequiresFeature(name=androidx.webkit.WebViewFeature.STARTUP_FEATURE_SET_DATA_DIRECTORY_SUFFIX, enforcement="androidx.webkit.WebViewFeature#isConfigFeatureSupported(String, Context)") public androidx.webkit.ProcessGlobalConfig setDataDirectorySuffix(android.content.Context, String);
- }
-
- public final class ProxyConfig {
- method public java.util.List<java.lang.String!> getBypassRules();
- method public java.util.List<androidx.webkit.ProxyConfig.ProxyRule!> getProxyRules();
- method public boolean isReverseBypassEnabled();
- field public static final String MATCH_ALL_SCHEMES = "*";
- field public static final String MATCH_HTTP = "http";
- field public static final String MATCH_HTTPS = "https";
- }
-
- public static final class ProxyConfig.Builder {
- ctor public ProxyConfig.Builder();
- ctor public ProxyConfig.Builder(androidx.webkit.ProxyConfig);
- method public androidx.webkit.ProxyConfig.Builder addBypassRule(String);
- method public androidx.webkit.ProxyConfig.Builder addDirect(String);
- method public androidx.webkit.ProxyConfig.Builder addDirect();
- method public androidx.webkit.ProxyConfig.Builder addProxyRule(String);
- method public androidx.webkit.ProxyConfig.Builder addProxyRule(String, String);
- method public androidx.webkit.ProxyConfig build();
- method public androidx.webkit.ProxyConfig.Builder bypassSimpleHostnames();
- method public androidx.webkit.ProxyConfig.Builder removeImplicitRules();
- method @RequiresFeature(name=androidx.webkit.WebViewFeature.PROXY_OVERRIDE_REVERSE_BYPASS, enforcement="androidx.webkit.WebViewFeature#isFeatureSupported") public androidx.webkit.ProxyConfig.Builder setReverseBypassEnabled(boolean);
- }
-
- public static final class ProxyConfig.ProxyRule {
- method public String getSchemeFilter();
- method public String getUrl();
- }
-
- public abstract class ProxyController {
- method public abstract void clearProxyOverride(java.util.concurrent.Executor, Runnable);
- method @RequiresFeature(name=androidx.webkit.WebViewFeature.PROXY_OVERRIDE, enforcement="androidx.webkit.WebViewFeature#isFeatureSupported") public static androidx.webkit.ProxyController getInstance();
- method public abstract void setProxyOverride(androidx.webkit.ProxyConfig, java.util.concurrent.Executor, Runnable);
- }
-
- public abstract class SafeBrowsingResponseCompat {
- method @RequiresFeature(name=androidx.webkit.WebViewFeature.SAFE_BROWSING_RESPONSE_BACK_TO_SAFETY, enforcement="androidx.webkit.WebViewFeature#isFeatureSupported") public abstract void backToSafety(boolean);
- method @RequiresFeature(name=androidx.webkit.WebViewFeature.SAFE_BROWSING_RESPONSE_PROCEED, enforcement="androidx.webkit.WebViewFeature#isFeatureSupported") public abstract void proceed(boolean);
- method @RequiresFeature(name=androidx.webkit.WebViewFeature.SAFE_BROWSING_RESPONSE_SHOW_INTERSTITIAL, enforcement="androidx.webkit.WebViewFeature#isFeatureSupported") public abstract void showInterstitial(boolean);
- }
-
- public abstract class ServiceWorkerClientCompat {
- ctor public ServiceWorkerClientCompat();
- method @WorkerThread public abstract android.webkit.WebResourceResponse? shouldInterceptRequest(android.webkit.WebResourceRequest);
- }
-
- public abstract class ServiceWorkerControllerCompat {
- method @RequiresFeature(name=androidx.webkit.WebViewFeature.SERVICE_WORKER_BASIC_USAGE, enforcement="androidx.webkit.WebViewFeature#isFeatureSupported") public static androidx.webkit.ServiceWorkerControllerCompat getInstance();
- method public abstract androidx.webkit.ServiceWorkerWebSettingsCompat getServiceWorkerWebSettings();
- method public abstract void setServiceWorkerClient(androidx.webkit.ServiceWorkerClientCompat?);
- }
-
- public abstract class ServiceWorkerWebSettingsCompat {
- method @RequiresFeature(name=androidx.webkit.WebViewFeature.SERVICE_WORKER_CONTENT_ACCESS, enforcement="androidx.webkit.WebViewFeature#isFeatureSupported") public abstract boolean getAllowContentAccess();
- method @RequiresFeature(name=androidx.webkit.WebViewFeature.SERVICE_WORKER_FILE_ACCESS, enforcement="androidx.webkit.WebViewFeature#isFeatureSupported") public abstract boolean getAllowFileAccess();
- method @RequiresFeature(name=androidx.webkit.WebViewFeature.SERVICE_WORKER_BLOCK_NETWORK_LOADS, enforcement="androidx.webkit.WebViewFeature#isFeatureSupported") public abstract boolean getBlockNetworkLoads();
- method @RequiresFeature(name=androidx.webkit.WebViewFeature.SERVICE_WORKER_CACHE_MODE, enforcement="androidx.webkit.WebViewFeature#isFeatureSupported") public abstract int getCacheMode();
- method @RequiresFeature(name="REQUESTED_WITH_HEADER_ALLOW_LIST", enforcement="androidx.webkit.WebViewFeature#isFeatureSupported") public abstract java.util.Set<java.lang.String!> getRequestedWithHeaderOriginAllowList();
- method @RequiresFeature(name=androidx.webkit.WebViewFeature.SERVICE_WORKER_CONTENT_ACCESS, enforcement="androidx.webkit.WebViewFeature#isFeatureSupported") public abstract void setAllowContentAccess(boolean);
- method @RequiresFeature(name=androidx.webkit.WebViewFeature.SERVICE_WORKER_FILE_ACCESS, enforcement="androidx.webkit.WebViewFeature#isFeatureSupported") public abstract void setAllowFileAccess(boolean);
- method @RequiresFeature(name=androidx.webkit.WebViewFeature.SERVICE_WORKER_BLOCK_NETWORK_LOADS, enforcement="androidx.webkit.WebViewFeature#isFeatureSupported") public abstract void setBlockNetworkLoads(boolean);
- method @RequiresFeature(name=androidx.webkit.WebViewFeature.SERVICE_WORKER_CACHE_MODE, enforcement="androidx.webkit.WebViewFeature#isFeatureSupported") public abstract void setCacheMode(int);
- method @RequiresFeature(name="REQUESTED_WITH_HEADER_ALLOW_LIST", enforcement="androidx.webkit.WebViewFeature#isFeatureSupported") public abstract void setRequestedWithHeaderOriginAllowList(java.util.Set<java.lang.String!>);
- }
-
- public class TracingConfig {
- method public java.util.List<java.lang.String!> getCustomIncludedCategories();
- method public int getPredefinedCategories();
- method public int getTracingMode();
- field public static final int CATEGORIES_ALL = 1; // 0x1
- field public static final int CATEGORIES_ANDROID_WEBVIEW = 2; // 0x2
- field public static final int CATEGORIES_FRAME_VIEWER = 64; // 0x40
- field public static final int CATEGORIES_INPUT_LATENCY = 8; // 0x8
- field public static final int CATEGORIES_JAVASCRIPT_AND_RENDERING = 32; // 0x20
- field public static final int CATEGORIES_NONE = 0; // 0x0
- field public static final int CATEGORIES_RENDERING = 16; // 0x10
- field public static final int CATEGORIES_WEB_DEVELOPER = 4; // 0x4
- field public static final int RECORD_CONTINUOUSLY = 1; // 0x1
- field public static final int RECORD_UNTIL_FULL = 0; // 0x0
- }
-
- public static class TracingConfig.Builder {
- ctor public TracingConfig.Builder();
- method public androidx.webkit.TracingConfig.Builder addCategories(int...);
- method public androidx.webkit.TracingConfig.Builder addCategories(java.lang.String!...);
- method public androidx.webkit.TracingConfig.Builder addCategories(java.util.Collection<java.lang.String!>);
- method public androidx.webkit.TracingConfig build();
- method public androidx.webkit.TracingConfig.Builder setTracingMode(int);
- }
-
- public abstract class TracingController {
- method @RequiresFeature(name=androidx.webkit.WebViewFeature.TRACING_CONTROLLER_BASIC_USAGE, enforcement="androidx.webkit.WebViewFeature#isFeatureSupported") public static androidx.webkit.TracingController getInstance();
- method public abstract boolean isTracing();
- method public abstract void start(androidx.webkit.TracingConfig);
- method public abstract boolean stop(java.io.OutputStream?, java.util.concurrent.Executor);
- }
-
- public class WebMessageCompat {
- ctor public WebMessageCompat(String?);
- ctor public WebMessageCompat(String?, androidx.webkit.WebMessagePortCompat![]?);
- method public String? getData();
- method public androidx.webkit.WebMessagePortCompat![]? getPorts();
- }
-
- public abstract class WebMessagePortCompat {
- method @RequiresFeature(name=androidx.webkit.WebViewFeature.WEB_MESSAGE_PORT_CLOSE, enforcement="androidx.webkit.WebViewFeature#isFeatureSupported") public abstract void close();
- method @RequiresFeature(name=androidx.webkit.WebViewFeature.WEB_MESSAGE_PORT_POST_MESSAGE, enforcement="androidx.webkit.WebViewFeature#isFeatureSupported") public abstract void postMessage(androidx.webkit.WebMessageCompat);
- method @RequiresFeature(name=androidx.webkit.WebViewFeature.WEB_MESSAGE_PORT_SET_MESSAGE_CALLBACK, enforcement="androidx.webkit.WebViewFeature#isFeatureSupported") public abstract void setWebMessageCallback(androidx.webkit.WebMessagePortCompat.WebMessageCallbackCompat);
- method @RequiresFeature(name=androidx.webkit.WebViewFeature.WEB_MESSAGE_PORT_SET_MESSAGE_CALLBACK, enforcement="androidx.webkit.WebViewFeature#isFeatureSupported") public abstract void setWebMessageCallback(android.os.Handler?, androidx.webkit.WebMessagePortCompat.WebMessageCallbackCompat);
- }
-
- public abstract static class WebMessagePortCompat.WebMessageCallbackCompat {
- ctor public WebMessagePortCompat.WebMessageCallbackCompat();
- method public void onMessage(androidx.webkit.WebMessagePortCompat, androidx.webkit.WebMessageCompat?);
- }
-
- public abstract class WebResourceErrorCompat {
- method @RequiresFeature(name=androidx.webkit.WebViewFeature.WEB_RESOURCE_ERROR_GET_DESCRIPTION, enforcement="androidx.webkit.WebViewFeature#isFeatureSupported") public abstract CharSequence getDescription();
- method @RequiresFeature(name=androidx.webkit.WebViewFeature.WEB_RESOURCE_ERROR_GET_CODE, enforcement="androidx.webkit.WebViewFeature#isFeatureSupported") public abstract int getErrorCode();
- }
-
- public class WebResourceRequestCompat {
- method @RequiresFeature(name=androidx.webkit.WebViewFeature.WEB_RESOURCE_REQUEST_IS_REDIRECT, enforcement="androidx.webkit.WebViewFeature#isFeatureSupported") public static boolean isRedirect(android.webkit.WebResourceRequest);
- }
-
- public class WebSettingsCompat {
- method @RequiresFeature(name=androidx.webkit.WebViewFeature.DISABLED_ACTION_MODE_MENU_ITEMS, enforcement="androidx.webkit.WebViewFeature#isFeatureSupported") public static int getDisabledActionModeMenuItems(android.webkit.WebSettings);
- method @RequiresFeature(name=androidx.webkit.WebViewFeature.ENTERPRISE_AUTHENTICATION_APP_LINK_POLICY, enforcement="androidx.webkit.WebViewFeature#isFeatureSupported") public static boolean getEnterpriseAuthenticationAppLinkPolicyEnabled(android.webkit.WebSettings);
- method @Deprecated @RequiresFeature(name=androidx.webkit.WebViewFeature.FORCE_DARK, enforcement="androidx.webkit.WebViewFeature#isFeatureSupported") public static int getForceDark(android.webkit.WebSettings);
- method @Deprecated @RequiresFeature(name=androidx.webkit.WebViewFeature.FORCE_DARK_STRATEGY, enforcement="androidx.webkit.WebViewFeature#isFeatureSupported") public static int getForceDarkStrategy(android.webkit.WebSettings);
- method @RequiresFeature(name=androidx.webkit.WebViewFeature.OFF_SCREEN_PRERASTER, enforcement="androidx.webkit.WebViewFeature#isFeatureSupported") public static boolean getOffscreenPreRaster(android.webkit.WebSettings);
- method @RequiresFeature(name="REQUESTED_WITH_HEADER_ALLOW_LIST", enforcement="androidx.webkit.WebViewFeature#isFeatureSupported") public static java.util.Set<java.lang.String!> getRequestedWithHeaderOriginAllowList(android.webkit.WebSettings);
- method @RequiresFeature(name=androidx.webkit.WebViewFeature.SAFE_BROWSING_ENABLE, enforcement="androidx.webkit.WebViewFeature#isFeatureSupported") public static boolean getSafeBrowsingEnabled(android.webkit.WebSettings);
- method @RequiresFeature(name=androidx.webkit.WebViewFeature.ALGORITHMIC_DARKENING, enforcement="androidx.webkit.WebViewFeature#isFeatureSupported") public static boolean isAlgorithmicDarkeningAllowed(android.webkit.WebSettings);
- method @RequiresFeature(name=androidx.webkit.WebViewFeature.ALGORITHMIC_DARKENING, enforcement="androidx.webkit.WebViewFeature#isFeatureSupported") public static void setAlgorithmicDarkeningAllowed(android.webkit.WebSettings, boolean);
- method @RequiresFeature(name=androidx.webkit.WebViewFeature.DISABLED_ACTION_MODE_MENU_ITEMS, enforcement="androidx.webkit.WebViewFeature#isFeatureSupported") public static void setDisabledActionModeMenuItems(android.webkit.WebSettings, int);
- method @RequiresFeature(name=androidx.webkit.WebViewFeature.ENTERPRISE_AUTHENTICATION_APP_LINK_POLICY, enforcement="androidx.webkit.WebViewFeature#isFeatureSupported") public static void setEnterpriseAuthenticationAppLinkPolicyEnabled(android.webkit.WebSettings, boolean);
- method @Deprecated @RequiresFeature(name=androidx.webkit.WebViewFeature.FORCE_DARK, enforcement="androidx.webkit.WebViewFeature#isFeatureSupported") public static void setForceDark(android.webkit.WebSettings, int);
- method @Deprecated @RequiresFeature(name=androidx.webkit.WebViewFeature.FORCE_DARK_STRATEGY, enforcement="androidx.webkit.WebViewFeature#isFeatureSupported") public static void setForceDarkStrategy(android.webkit.WebSettings, int);
- method @RequiresFeature(name=androidx.webkit.WebViewFeature.OFF_SCREEN_PRERASTER, enforcement="androidx.webkit.WebViewFeature#isFeatureSupported") public static void setOffscreenPreRaster(android.webkit.WebSettings, boolean);
- method @RequiresFeature(name="REQUESTED_WITH_HEADER_ALLOW_LIST", enforcement="androidx.webkit.WebViewFeature#isFeatureSupported") public static void setRequestedWithHeaderOriginAllowList(android.webkit.WebSettings, java.util.Set<java.lang.String!>);
- method @RequiresFeature(name=androidx.webkit.WebViewFeature.SAFE_BROWSING_ENABLE, enforcement="androidx.webkit.WebViewFeature#isFeatureSupported") public static void setSafeBrowsingEnabled(android.webkit.WebSettings, boolean);
- field @Deprecated public static final int DARK_STRATEGY_PREFER_WEB_THEME_OVER_USER_AGENT_DARKENING = 2; // 0x2
- field @Deprecated public static final int DARK_STRATEGY_USER_AGENT_DARKENING_ONLY = 0; // 0x0
- field @Deprecated public static final int DARK_STRATEGY_WEB_THEME_DARKENING_ONLY = 1; // 0x1
- field @Deprecated public static final int FORCE_DARK_AUTO = 1; // 0x1
- field @Deprecated public static final int FORCE_DARK_OFF = 0; // 0x0
- field @Deprecated public static final int FORCE_DARK_ON = 2; // 0x2
- }
-
- public final class WebViewAssetLoader {
- method @WorkerThread public android.webkit.WebResourceResponse? shouldInterceptRequest(android.net.Uri);
- field public static final String DEFAULT_DOMAIN = "appassets.androidplatform.net";
- }
-
- public static final class WebViewAssetLoader.AssetsPathHandler implements androidx.webkit.WebViewAssetLoader.PathHandler {
- ctor public WebViewAssetLoader.AssetsPathHandler(android.content.Context);
- method @WorkerThread public android.webkit.WebResourceResponse? handle(String);
- }
-
- public static final class WebViewAssetLoader.Builder {
- ctor public WebViewAssetLoader.Builder();
- method public androidx.webkit.WebViewAssetLoader.Builder addPathHandler(String, androidx.webkit.WebViewAssetLoader.PathHandler);
- method public androidx.webkit.WebViewAssetLoader build();
- method public androidx.webkit.WebViewAssetLoader.Builder setDomain(String);
- method public androidx.webkit.WebViewAssetLoader.Builder setHttpAllowed(boolean);
- }
-
- public static final class WebViewAssetLoader.InternalStoragePathHandler implements androidx.webkit.WebViewAssetLoader.PathHandler {
- ctor public WebViewAssetLoader.InternalStoragePathHandler(android.content.Context, java.io.File);
- method @WorkerThread public android.webkit.WebResourceResponse handle(String);
- }
-
- public static interface WebViewAssetLoader.PathHandler {
- method @WorkerThread public android.webkit.WebResourceResponse? handle(String);
- }
-
- public static final class WebViewAssetLoader.ResourcesPathHandler implements androidx.webkit.WebViewAssetLoader.PathHandler {
- ctor public WebViewAssetLoader.ResourcesPathHandler(android.content.Context);
- method @WorkerThread public android.webkit.WebResourceResponse? handle(String);
- }
-
- public class WebViewClientCompat extends android.webkit.WebViewClient {
- ctor public WebViewClientCompat();
- method @RequiresApi(23) public final void onReceivedError(android.webkit.WebView, android.webkit.WebResourceRequest, android.webkit.WebResourceError);
- method @RequiresApi(21) @UiThread public void onReceivedError(android.webkit.WebView, android.webkit.WebResourceRequest, androidx.webkit.WebResourceErrorCompat);
- method @RequiresApi(27) public final void onSafeBrowsingHit(android.webkit.WebView, android.webkit.WebResourceRequest, int, android.webkit.SafeBrowsingResponse);
- method @UiThread public void onSafeBrowsingHit(android.webkit.WebView, android.webkit.WebResourceRequest, int, androidx.webkit.SafeBrowsingResponseCompat);
- }
-
- public class WebViewCompat {
- method @RequiresFeature(name=androidx.webkit.WebViewFeature.WEB_MESSAGE_LISTENER, enforcement="androidx.webkit.WebViewFeature#isFeatureSupported") public static void addWebMessageListener(android.webkit.WebView, String, java.util.Set<java.lang.String!>, androidx.webkit.WebViewCompat.WebMessageListener);
- method @RequiresFeature(name=androidx.webkit.WebViewFeature.CREATE_WEB_MESSAGE_CHANNEL, enforcement="androidx.webkit.WebViewFeature#isFeatureSupported") public static androidx.webkit.WebMessagePortCompat![] createWebMessageChannel(android.webkit.WebView);
- method public static android.content.pm.PackageInfo? getCurrentWebViewPackage(android.content.Context);
- method @RequiresFeature(name=androidx.webkit.WebViewFeature.SAFE_BROWSING_PRIVACY_POLICY_URL, enforcement="androidx.webkit.WebViewFeature#isFeatureSupported") public static android.net.Uri getSafeBrowsingPrivacyPolicyUrl();
- method @RequiresFeature(name=androidx.webkit.WebViewFeature.GET_VARIATIONS_HEADER, enforcement="androidx.webkit.WebViewFeature#isFeatureSupported") public static String getVariationsHeader();
- method @RequiresFeature(name=androidx.webkit.WebViewFeature.GET_WEB_CHROME_CLIENT, enforcement="androidx.webkit.WebViewFeature#isFeatureSupported") public static android.webkit.WebChromeClient? getWebChromeClient(android.webkit.WebView);
- method @RequiresFeature(name=androidx.webkit.WebViewFeature.GET_WEB_VIEW_CLIENT, enforcement="androidx.webkit.WebViewFeature#isFeatureSupported") public static android.webkit.WebViewClient getWebViewClient(android.webkit.WebView);
- method @RequiresFeature(name=androidx.webkit.WebViewFeature.GET_WEB_VIEW_RENDERER, enforcement="androidx.webkit.WebViewFeature#isFeatureSupported") public static androidx.webkit.WebViewRenderProcess? getWebViewRenderProcess(android.webkit.WebView);
- method @RequiresFeature(name=androidx.webkit.WebViewFeature.WEB_VIEW_RENDERER_CLIENT_BASIC_USAGE, enforcement="androidx.webkit.WebViewFeature#isFeatureSupported") public static androidx.webkit.WebViewRenderProcessClient? getWebViewRenderProcessClient(android.webkit.WebView);
- method @RequiresFeature(name=androidx.webkit.WebViewFeature.MULTI_PROCESS, enforcement="androidx.webkit.WebViewFeature#isFeatureSupported") public static boolean isMultiProcessEnabled();
- method @RequiresFeature(name=androidx.webkit.WebViewFeature.VISUAL_STATE_CALLBACK, enforcement="androidx.webkit.WebViewFeature#isFeatureSupported") public static void postVisualStateCallback(android.webkit.WebView, long, androidx.webkit.WebViewCompat.VisualStateCallback);
- method @RequiresFeature(name=androidx.webkit.WebViewFeature.POST_WEB_MESSAGE, enforcement="androidx.webkit.WebViewFeature#isFeatureSupported") public static void postWebMessage(android.webkit.WebView, androidx.webkit.WebMessageCompat, android.net.Uri);
- method @RequiresFeature(name=androidx.webkit.WebViewFeature.WEB_MESSAGE_LISTENER, enforcement="androidx.webkit.WebViewFeature#isFeatureSupported") public static void removeWebMessageListener(android.webkit.WebView, String);
- method @RequiresFeature(name=androidx.webkit.WebViewFeature.SAFE_BROWSING_ALLOWLIST, enforcement="androidx.webkit.WebViewFeature#isFeatureSupported") public static void setSafeBrowsingAllowlist(java.util.Set<java.lang.String!>, android.webkit.ValueCallback<java.lang.Boolean!>?);
- method @Deprecated @RequiresFeature(name=androidx.webkit.WebViewFeature.SAFE_BROWSING_WHITELIST, enforcement="androidx.webkit.WebViewFeature#isFeatureSupported") public static void setSafeBrowsingWhitelist(java.util.List<java.lang.String!>, android.webkit.ValueCallback<java.lang.Boolean!>?);
- method @RequiresFeature(name=androidx.webkit.WebViewFeature.WEB_VIEW_RENDERER_CLIENT_BASIC_USAGE, enforcement="androidx.webkit.WebViewFeature#isFeatureSupported") public static void setWebViewRenderProcessClient(android.webkit.WebView, java.util.concurrent.Executor, androidx.webkit.WebViewRenderProcessClient);
- method @RequiresFeature(name=androidx.webkit.WebViewFeature.WEB_VIEW_RENDERER_CLIENT_BASIC_USAGE, enforcement="androidx.webkit.WebViewFeature#isFeatureSupported") public static void setWebViewRenderProcessClient(android.webkit.WebView, androidx.webkit.WebViewRenderProcessClient?);
- method @RequiresFeature(name=androidx.webkit.WebViewFeature.START_SAFE_BROWSING, enforcement="androidx.webkit.WebViewFeature#isFeatureSupported") public static void startSafeBrowsing(android.content.Context, android.webkit.ValueCallback<java.lang.Boolean!>?);
- }
-
- public static interface WebViewCompat.VisualStateCallback {
- method @UiThread public void onComplete(long);
- }
-
- public static interface WebViewCompat.WebMessageListener {
- method @UiThread public void onPostMessage(android.webkit.WebView, androidx.webkit.WebMessageCompat, android.net.Uri, boolean, androidx.webkit.JavaScriptReplyProxy);
- }
-
- public class WebViewFeature {
- method public static boolean isFeatureSupported(String);
- method public static boolean isStartupFeatureSupported(android.content.Context, String);
- field public static final String ALGORITHMIC_DARKENING = "ALGORITHMIC_DARKENING";
- field public static final String CREATE_WEB_MESSAGE_CHANNEL = "CREATE_WEB_MESSAGE_CHANNEL";
- field public static final String DISABLED_ACTION_MODE_MENU_ITEMS = "DISABLED_ACTION_MODE_MENU_ITEMS";
- field public static final String ENTERPRISE_AUTHENTICATION_APP_LINK_POLICY = "ENTERPRISE_AUTHENTICATION_APP_LINK_POLICY";
- field public static final String FORCE_DARK = "FORCE_DARK";
- field public static final String FORCE_DARK_STRATEGY = "FORCE_DARK_STRATEGY";
- field public static final String GET_COOKIE_INFO = "GET_COOKIE_INFO";
- field public static final String GET_VARIATIONS_HEADER = "GET_VARIATIONS_HEADER";
- field public static final String GET_WEB_CHROME_CLIENT = "GET_WEB_CHROME_CLIENT";
- field public static final String GET_WEB_VIEW_CLIENT = "GET_WEB_VIEW_CLIENT";
- field public static final String GET_WEB_VIEW_RENDERER = "GET_WEB_VIEW_RENDERER";
- field public static final String MULTI_PROCESS = "MULTI_PROCESS";
- field public static final String OFF_SCREEN_PRERASTER = "OFF_SCREEN_PRERASTER";
- field public static final String POST_WEB_MESSAGE = "POST_WEB_MESSAGE";
- field public static final String PROXY_OVERRIDE = "PROXY_OVERRIDE";
- field public static final String PROXY_OVERRIDE_REVERSE_BYPASS = "PROXY_OVERRIDE_REVERSE_BYPASS";
- field public static final String RECEIVE_HTTP_ERROR = "RECEIVE_HTTP_ERROR";
- field public static final String RECEIVE_WEB_RESOURCE_ERROR = "RECEIVE_WEB_RESOURCE_ERROR";
- field public static final String SAFE_BROWSING_ALLOWLIST = "SAFE_BROWSING_ALLOWLIST";
- field public static final String SAFE_BROWSING_ENABLE = "SAFE_BROWSING_ENABLE";
- field public static final String SAFE_BROWSING_HIT = "SAFE_BROWSING_HIT";
- field public static final String SAFE_BROWSING_PRIVACY_POLICY_URL = "SAFE_BROWSING_PRIVACY_POLICY_URL";
- field public static final String SAFE_BROWSING_RESPONSE_BACK_TO_SAFETY = "SAFE_BROWSING_RESPONSE_BACK_TO_SAFETY";
- field public static final String SAFE_BROWSING_RESPONSE_PROCEED = "SAFE_BROWSING_RESPONSE_PROCEED";
- field public static final String SAFE_BROWSING_RESPONSE_SHOW_INTERSTITIAL = "SAFE_BROWSING_RESPONSE_SHOW_INTERSTITIAL";
- field @Deprecated public static final String SAFE_BROWSING_WHITELIST = "SAFE_BROWSING_WHITELIST";
- field public static final String SERVICE_WORKER_BASIC_USAGE = "SERVICE_WORKER_BASIC_USAGE";
- field public static final String SERVICE_WORKER_BLOCK_NETWORK_LOADS = "SERVICE_WORKER_BLOCK_NETWORK_LOADS";
- field public static final String SERVICE_WORKER_CACHE_MODE = "SERVICE_WORKER_CACHE_MODE";
- field public static final String SERVICE_WORKER_CONTENT_ACCESS = "SERVICE_WORKER_CONTENT_ACCESS";
- field public static final String SERVICE_WORKER_FILE_ACCESS = "SERVICE_WORKER_FILE_ACCESS";
- field public static final String SERVICE_WORKER_SHOULD_INTERCEPT_REQUEST = "SERVICE_WORKER_SHOULD_INTERCEPT_REQUEST";
- field public static final String SHOULD_OVERRIDE_WITH_REDIRECTS = "SHOULD_OVERRIDE_WITH_REDIRECTS";
- field public static final String STARTUP_FEATURE_SET_DATA_DIRECTORY_SUFFIX = "STARTUP_FEATURE_SET_DATA_DIRECTORY_SUFFIX";
- field public static final String START_SAFE_BROWSING = "START_SAFE_BROWSING";
- field public static final String TRACING_CONTROLLER_BASIC_USAGE = "TRACING_CONTROLLER_BASIC_USAGE";
- field public static final String VISUAL_STATE_CALLBACK = "VISUAL_STATE_CALLBACK";
- field public static final String WEB_MESSAGE_CALLBACK_ON_MESSAGE = "WEB_MESSAGE_CALLBACK_ON_MESSAGE";
- field public static final String WEB_MESSAGE_LISTENER = "WEB_MESSAGE_LISTENER";
- field public static final String WEB_MESSAGE_PORT_CLOSE = "WEB_MESSAGE_PORT_CLOSE";
- field public static final String WEB_MESSAGE_PORT_POST_MESSAGE = "WEB_MESSAGE_PORT_POST_MESSAGE";
- field public static final String WEB_MESSAGE_PORT_SET_MESSAGE_CALLBACK = "WEB_MESSAGE_PORT_SET_MESSAGE_CALLBACK";
- field public static final String WEB_RESOURCE_ERROR_GET_CODE = "WEB_RESOURCE_ERROR_GET_CODE";
- field public static final String WEB_RESOURCE_ERROR_GET_DESCRIPTION = "WEB_RESOURCE_ERROR_GET_DESCRIPTION";
- field public static final String WEB_RESOURCE_REQUEST_IS_REDIRECT = "WEB_RESOURCE_REQUEST_IS_REDIRECT";
- field public static final String WEB_VIEW_RENDERER_CLIENT_BASIC_USAGE = "WEB_VIEW_RENDERER_CLIENT_BASIC_USAGE";
- field public static final String WEB_VIEW_RENDERER_TERMINATE = "WEB_VIEW_RENDERER_TERMINATE";
- }
-
- public abstract class WebViewRenderProcess {
- ctor public WebViewRenderProcess();
- method public abstract boolean terminate();
- }
-
- public abstract class WebViewRenderProcessClient {
- ctor public WebViewRenderProcessClient();
- method public abstract void onRenderProcessResponsive(android.webkit.WebView, androidx.webkit.WebViewRenderProcess?);
- method public abstract void onRenderProcessUnresponsive(android.webkit.WebView, androidx.webkit.WebViewRenderProcess?);
- }
-
-}
-
diff --git a/webkit/webkit/api/public_plus_experimental_1.6.0-beta02.txt b/webkit/webkit/api/public_plus_experimental_1.6.0-beta02.txt
deleted file mode 100644
index faf13cb..0000000
--- a/webkit/webkit/api/public_plus_experimental_1.6.0-beta02.txt
+++ /dev/null
@@ -1,300 +0,0 @@
-// Signature format: 4.0
-package androidx.webkit {
-
- public class CookieManagerCompat {
- method @RequiresFeature(name=androidx.webkit.WebViewFeature.GET_COOKIE_INFO, enforcement="androidx.webkit.WebViewFeature#isFeatureSupported") public static java.util.List<java.lang.String!> getCookieInfo(android.webkit.CookieManager, String);
- }
-
- public abstract class JavaScriptReplyProxy {
- method @RequiresFeature(name=androidx.webkit.WebViewFeature.WEB_MESSAGE_LISTENER, enforcement="androidx.webkit.WebViewFeature#isFeatureSupported") public abstract void postMessage(String);
- }
-
- public class ProcessGlobalConfig {
- ctor public ProcessGlobalConfig();
- method public static void apply(androidx.webkit.ProcessGlobalConfig);
- method @RequiresFeature(name=androidx.webkit.WebViewFeature.STARTUP_FEATURE_SET_DATA_DIRECTORY_SUFFIX, enforcement="androidx.webkit.WebViewFeature#isConfigFeatureSupported(String, Context)") public androidx.webkit.ProcessGlobalConfig setDataDirectorySuffix(android.content.Context, String);
- }
-
- public final class ProxyConfig {
- method public java.util.List<java.lang.String!> getBypassRules();
- method public java.util.List<androidx.webkit.ProxyConfig.ProxyRule!> getProxyRules();
- method public boolean isReverseBypassEnabled();
- field public static final String MATCH_ALL_SCHEMES = "*";
- field public static final String MATCH_HTTP = "http";
- field public static final String MATCH_HTTPS = "https";
- }
-
- public static final class ProxyConfig.Builder {
- ctor public ProxyConfig.Builder();
- ctor public ProxyConfig.Builder(androidx.webkit.ProxyConfig);
- method public androidx.webkit.ProxyConfig.Builder addBypassRule(String);
- method public androidx.webkit.ProxyConfig.Builder addDirect(String);
- method public androidx.webkit.ProxyConfig.Builder addDirect();
- method public androidx.webkit.ProxyConfig.Builder addProxyRule(String);
- method public androidx.webkit.ProxyConfig.Builder addProxyRule(String, String);
- method public androidx.webkit.ProxyConfig build();
- method public androidx.webkit.ProxyConfig.Builder bypassSimpleHostnames();
- method public androidx.webkit.ProxyConfig.Builder removeImplicitRules();
- method @RequiresFeature(name=androidx.webkit.WebViewFeature.PROXY_OVERRIDE_REVERSE_BYPASS, enforcement="androidx.webkit.WebViewFeature#isFeatureSupported") public androidx.webkit.ProxyConfig.Builder setReverseBypassEnabled(boolean);
- }
-
- public static final class ProxyConfig.ProxyRule {
- method public String getSchemeFilter();
- method public String getUrl();
- }
-
- public abstract class ProxyController {
- method public abstract void clearProxyOverride(java.util.concurrent.Executor, Runnable);
- method @RequiresFeature(name=androidx.webkit.WebViewFeature.PROXY_OVERRIDE, enforcement="androidx.webkit.WebViewFeature#isFeatureSupported") public static androidx.webkit.ProxyController getInstance();
- method public abstract void setProxyOverride(androidx.webkit.ProxyConfig, java.util.concurrent.Executor, Runnable);
- }
-
- public abstract class SafeBrowsingResponseCompat {
- method @RequiresFeature(name=androidx.webkit.WebViewFeature.SAFE_BROWSING_RESPONSE_BACK_TO_SAFETY, enforcement="androidx.webkit.WebViewFeature#isFeatureSupported") public abstract void backToSafety(boolean);
- method @RequiresFeature(name=androidx.webkit.WebViewFeature.SAFE_BROWSING_RESPONSE_PROCEED, enforcement="androidx.webkit.WebViewFeature#isFeatureSupported") public abstract void proceed(boolean);
- method @RequiresFeature(name=androidx.webkit.WebViewFeature.SAFE_BROWSING_RESPONSE_SHOW_INTERSTITIAL, enforcement="androidx.webkit.WebViewFeature#isFeatureSupported") public abstract void showInterstitial(boolean);
- }
-
- public abstract class ServiceWorkerClientCompat {
- ctor public ServiceWorkerClientCompat();
- method @WorkerThread public abstract android.webkit.WebResourceResponse? shouldInterceptRequest(android.webkit.WebResourceRequest);
- }
-
- public abstract class ServiceWorkerControllerCompat {
- method @RequiresFeature(name=androidx.webkit.WebViewFeature.SERVICE_WORKER_BASIC_USAGE, enforcement="androidx.webkit.WebViewFeature#isFeatureSupported") public static androidx.webkit.ServiceWorkerControllerCompat getInstance();
- method public abstract androidx.webkit.ServiceWorkerWebSettingsCompat getServiceWorkerWebSettings();
- method public abstract void setServiceWorkerClient(androidx.webkit.ServiceWorkerClientCompat?);
- }
-
- public abstract class ServiceWorkerWebSettingsCompat {
- method @RequiresFeature(name=androidx.webkit.WebViewFeature.SERVICE_WORKER_CONTENT_ACCESS, enforcement="androidx.webkit.WebViewFeature#isFeatureSupported") public abstract boolean getAllowContentAccess();
- method @RequiresFeature(name=androidx.webkit.WebViewFeature.SERVICE_WORKER_FILE_ACCESS, enforcement="androidx.webkit.WebViewFeature#isFeatureSupported") public abstract boolean getAllowFileAccess();
- method @RequiresFeature(name=androidx.webkit.WebViewFeature.SERVICE_WORKER_BLOCK_NETWORK_LOADS, enforcement="androidx.webkit.WebViewFeature#isFeatureSupported") public abstract boolean getBlockNetworkLoads();
- method @RequiresFeature(name=androidx.webkit.WebViewFeature.SERVICE_WORKER_CACHE_MODE, enforcement="androidx.webkit.WebViewFeature#isFeatureSupported") public abstract int getCacheMode();
- method @RequiresFeature(name="REQUESTED_WITH_HEADER_ALLOW_LIST", enforcement="androidx.webkit.WebViewFeature#isFeatureSupported") public abstract java.util.Set<java.lang.String!> getRequestedWithHeaderOriginAllowList();
- method @RequiresFeature(name=androidx.webkit.WebViewFeature.SERVICE_WORKER_CONTENT_ACCESS, enforcement="androidx.webkit.WebViewFeature#isFeatureSupported") public abstract void setAllowContentAccess(boolean);
- method @RequiresFeature(name=androidx.webkit.WebViewFeature.SERVICE_WORKER_FILE_ACCESS, enforcement="androidx.webkit.WebViewFeature#isFeatureSupported") public abstract void setAllowFileAccess(boolean);
- method @RequiresFeature(name=androidx.webkit.WebViewFeature.SERVICE_WORKER_BLOCK_NETWORK_LOADS, enforcement="androidx.webkit.WebViewFeature#isFeatureSupported") public abstract void setBlockNetworkLoads(boolean);
- method @RequiresFeature(name=androidx.webkit.WebViewFeature.SERVICE_WORKER_CACHE_MODE, enforcement="androidx.webkit.WebViewFeature#isFeatureSupported") public abstract void setCacheMode(int);
- method @RequiresFeature(name="REQUESTED_WITH_HEADER_ALLOW_LIST", enforcement="androidx.webkit.WebViewFeature#isFeatureSupported") public abstract void setRequestedWithHeaderOriginAllowList(java.util.Set<java.lang.String!>);
- }
-
- public class TracingConfig {
- method public java.util.List<java.lang.String!> getCustomIncludedCategories();
- method public int getPredefinedCategories();
- method public int getTracingMode();
- field public static final int CATEGORIES_ALL = 1; // 0x1
- field public static final int CATEGORIES_ANDROID_WEBVIEW = 2; // 0x2
- field public static final int CATEGORIES_FRAME_VIEWER = 64; // 0x40
- field public static final int CATEGORIES_INPUT_LATENCY = 8; // 0x8
- field public static final int CATEGORIES_JAVASCRIPT_AND_RENDERING = 32; // 0x20
- field public static final int CATEGORIES_NONE = 0; // 0x0
- field public static final int CATEGORIES_RENDERING = 16; // 0x10
- field public static final int CATEGORIES_WEB_DEVELOPER = 4; // 0x4
- field public static final int RECORD_CONTINUOUSLY = 1; // 0x1
- field public static final int RECORD_UNTIL_FULL = 0; // 0x0
- }
-
- public static class TracingConfig.Builder {
- ctor public TracingConfig.Builder();
- method public androidx.webkit.TracingConfig.Builder addCategories(int...);
- method public androidx.webkit.TracingConfig.Builder addCategories(java.lang.String!...);
- method public androidx.webkit.TracingConfig.Builder addCategories(java.util.Collection<java.lang.String!>);
- method public androidx.webkit.TracingConfig build();
- method public androidx.webkit.TracingConfig.Builder setTracingMode(int);
- }
-
- public abstract class TracingController {
- method @RequiresFeature(name=androidx.webkit.WebViewFeature.TRACING_CONTROLLER_BASIC_USAGE, enforcement="androidx.webkit.WebViewFeature#isFeatureSupported") public static androidx.webkit.TracingController getInstance();
- method public abstract boolean isTracing();
- method public abstract void start(androidx.webkit.TracingConfig);
- method public abstract boolean stop(java.io.OutputStream?, java.util.concurrent.Executor);
- }
-
- public class WebMessageCompat {
- ctor public WebMessageCompat(String?);
- ctor public WebMessageCompat(String?, androidx.webkit.WebMessagePortCompat![]?);
- method public String? getData();
- method public androidx.webkit.WebMessagePortCompat![]? getPorts();
- }
-
- public abstract class WebMessagePortCompat {
- method @RequiresFeature(name=androidx.webkit.WebViewFeature.WEB_MESSAGE_PORT_CLOSE, enforcement="androidx.webkit.WebViewFeature#isFeatureSupported") public abstract void close();
- method @RequiresFeature(name=androidx.webkit.WebViewFeature.WEB_MESSAGE_PORT_POST_MESSAGE, enforcement="androidx.webkit.WebViewFeature#isFeatureSupported") public abstract void postMessage(androidx.webkit.WebMessageCompat);
- method @RequiresFeature(name=androidx.webkit.WebViewFeature.WEB_MESSAGE_PORT_SET_MESSAGE_CALLBACK, enforcement="androidx.webkit.WebViewFeature#isFeatureSupported") public abstract void setWebMessageCallback(androidx.webkit.WebMessagePortCompat.WebMessageCallbackCompat);
- method @RequiresFeature(name=androidx.webkit.WebViewFeature.WEB_MESSAGE_PORT_SET_MESSAGE_CALLBACK, enforcement="androidx.webkit.WebViewFeature#isFeatureSupported") public abstract void setWebMessageCallback(android.os.Handler?, androidx.webkit.WebMessagePortCompat.WebMessageCallbackCompat);
- }
-
- public abstract static class WebMessagePortCompat.WebMessageCallbackCompat {
- ctor public WebMessagePortCompat.WebMessageCallbackCompat();
- method public void onMessage(androidx.webkit.WebMessagePortCompat, androidx.webkit.WebMessageCompat?);
- }
-
- public abstract class WebResourceErrorCompat {
- method @RequiresFeature(name=androidx.webkit.WebViewFeature.WEB_RESOURCE_ERROR_GET_DESCRIPTION, enforcement="androidx.webkit.WebViewFeature#isFeatureSupported") public abstract CharSequence getDescription();
- method @RequiresFeature(name=androidx.webkit.WebViewFeature.WEB_RESOURCE_ERROR_GET_CODE, enforcement="androidx.webkit.WebViewFeature#isFeatureSupported") public abstract int getErrorCode();
- }
-
- public class WebResourceRequestCompat {
- method @RequiresFeature(name=androidx.webkit.WebViewFeature.WEB_RESOURCE_REQUEST_IS_REDIRECT, enforcement="androidx.webkit.WebViewFeature#isFeatureSupported") public static boolean isRedirect(android.webkit.WebResourceRequest);
- }
-
- public class WebSettingsCompat {
- method @RequiresFeature(name=androidx.webkit.WebViewFeature.DISABLED_ACTION_MODE_MENU_ITEMS, enforcement="androidx.webkit.WebViewFeature#isFeatureSupported") public static int getDisabledActionModeMenuItems(android.webkit.WebSettings);
- method @RequiresFeature(name=androidx.webkit.WebViewFeature.ENTERPRISE_AUTHENTICATION_APP_LINK_POLICY, enforcement="androidx.webkit.WebViewFeature#isFeatureSupported") public static boolean getEnterpriseAuthenticationAppLinkPolicyEnabled(android.webkit.WebSettings);
- method @Deprecated @RequiresFeature(name=androidx.webkit.WebViewFeature.FORCE_DARK, enforcement="androidx.webkit.WebViewFeature#isFeatureSupported") public static int getForceDark(android.webkit.WebSettings);
- method @Deprecated @RequiresFeature(name=androidx.webkit.WebViewFeature.FORCE_DARK_STRATEGY, enforcement="androidx.webkit.WebViewFeature#isFeatureSupported") public static int getForceDarkStrategy(android.webkit.WebSettings);
- method @RequiresFeature(name=androidx.webkit.WebViewFeature.OFF_SCREEN_PRERASTER, enforcement="androidx.webkit.WebViewFeature#isFeatureSupported") public static boolean getOffscreenPreRaster(android.webkit.WebSettings);
- method @RequiresFeature(name="REQUESTED_WITH_HEADER_ALLOW_LIST", enforcement="androidx.webkit.WebViewFeature#isFeatureSupported") public static java.util.Set<java.lang.String!> getRequestedWithHeaderOriginAllowList(android.webkit.WebSettings);
- method @RequiresFeature(name=androidx.webkit.WebViewFeature.SAFE_BROWSING_ENABLE, enforcement="androidx.webkit.WebViewFeature#isFeatureSupported") public static boolean getSafeBrowsingEnabled(android.webkit.WebSettings);
- method @RequiresFeature(name=androidx.webkit.WebViewFeature.ALGORITHMIC_DARKENING, enforcement="androidx.webkit.WebViewFeature#isFeatureSupported") public static boolean isAlgorithmicDarkeningAllowed(android.webkit.WebSettings);
- method @RequiresFeature(name=androidx.webkit.WebViewFeature.ALGORITHMIC_DARKENING, enforcement="androidx.webkit.WebViewFeature#isFeatureSupported") public static void setAlgorithmicDarkeningAllowed(android.webkit.WebSettings, boolean);
- method @RequiresFeature(name=androidx.webkit.WebViewFeature.DISABLED_ACTION_MODE_MENU_ITEMS, enforcement="androidx.webkit.WebViewFeature#isFeatureSupported") public static void setDisabledActionModeMenuItems(android.webkit.WebSettings, int);
- method @RequiresFeature(name=androidx.webkit.WebViewFeature.ENTERPRISE_AUTHENTICATION_APP_LINK_POLICY, enforcement="androidx.webkit.WebViewFeature#isFeatureSupported") public static void setEnterpriseAuthenticationAppLinkPolicyEnabled(android.webkit.WebSettings, boolean);
- method @Deprecated @RequiresFeature(name=androidx.webkit.WebViewFeature.FORCE_DARK, enforcement="androidx.webkit.WebViewFeature#isFeatureSupported") public static void setForceDark(android.webkit.WebSettings, int);
- method @Deprecated @RequiresFeature(name=androidx.webkit.WebViewFeature.FORCE_DARK_STRATEGY, enforcement="androidx.webkit.WebViewFeature#isFeatureSupported") public static void setForceDarkStrategy(android.webkit.WebSettings, int);
- method @RequiresFeature(name=androidx.webkit.WebViewFeature.OFF_SCREEN_PRERASTER, enforcement="androidx.webkit.WebViewFeature#isFeatureSupported") public static void setOffscreenPreRaster(android.webkit.WebSettings, boolean);
- method @RequiresFeature(name="REQUESTED_WITH_HEADER_ALLOW_LIST", enforcement="androidx.webkit.WebViewFeature#isFeatureSupported") public static void setRequestedWithHeaderOriginAllowList(android.webkit.WebSettings, java.util.Set<java.lang.String!>);
- method @RequiresFeature(name=androidx.webkit.WebViewFeature.SAFE_BROWSING_ENABLE, enforcement="androidx.webkit.WebViewFeature#isFeatureSupported") public static void setSafeBrowsingEnabled(android.webkit.WebSettings, boolean);
- field @Deprecated public static final int DARK_STRATEGY_PREFER_WEB_THEME_OVER_USER_AGENT_DARKENING = 2; // 0x2
- field @Deprecated public static final int DARK_STRATEGY_USER_AGENT_DARKENING_ONLY = 0; // 0x0
- field @Deprecated public static final int DARK_STRATEGY_WEB_THEME_DARKENING_ONLY = 1; // 0x1
- field @Deprecated public static final int FORCE_DARK_AUTO = 1; // 0x1
- field @Deprecated public static final int FORCE_DARK_OFF = 0; // 0x0
- field @Deprecated public static final int FORCE_DARK_ON = 2; // 0x2
- }
-
- public final class WebViewAssetLoader {
- method @WorkerThread public android.webkit.WebResourceResponse? shouldInterceptRequest(android.net.Uri);
- field public static final String DEFAULT_DOMAIN = "appassets.androidplatform.net";
- }
-
- public static final class WebViewAssetLoader.AssetsPathHandler implements androidx.webkit.WebViewAssetLoader.PathHandler {
- ctor public WebViewAssetLoader.AssetsPathHandler(android.content.Context);
- method @WorkerThread public android.webkit.WebResourceResponse? handle(String);
- }
-
- public static final class WebViewAssetLoader.Builder {
- ctor public WebViewAssetLoader.Builder();
- method public androidx.webkit.WebViewAssetLoader.Builder addPathHandler(String, androidx.webkit.WebViewAssetLoader.PathHandler);
- method public androidx.webkit.WebViewAssetLoader build();
- method public androidx.webkit.WebViewAssetLoader.Builder setDomain(String);
- method public androidx.webkit.WebViewAssetLoader.Builder setHttpAllowed(boolean);
- }
-
- public static final class WebViewAssetLoader.InternalStoragePathHandler implements androidx.webkit.WebViewAssetLoader.PathHandler {
- ctor public WebViewAssetLoader.InternalStoragePathHandler(android.content.Context, java.io.File);
- method @WorkerThread public android.webkit.WebResourceResponse handle(String);
- }
-
- public static interface WebViewAssetLoader.PathHandler {
- method @WorkerThread public android.webkit.WebResourceResponse? handle(String);
- }
-
- public static final class WebViewAssetLoader.ResourcesPathHandler implements androidx.webkit.WebViewAssetLoader.PathHandler {
- ctor public WebViewAssetLoader.ResourcesPathHandler(android.content.Context);
- method @WorkerThread public android.webkit.WebResourceResponse? handle(String);
- }
-
- public class WebViewClientCompat extends android.webkit.WebViewClient {
- ctor public WebViewClientCompat();
- method @RequiresApi(23) public final void onReceivedError(android.webkit.WebView, android.webkit.WebResourceRequest, android.webkit.WebResourceError);
- method @RequiresApi(21) @UiThread public void onReceivedError(android.webkit.WebView, android.webkit.WebResourceRequest, androidx.webkit.WebResourceErrorCompat);
- method @RequiresApi(27) public final void onSafeBrowsingHit(android.webkit.WebView, android.webkit.WebResourceRequest, int, android.webkit.SafeBrowsingResponse);
- method @UiThread public void onSafeBrowsingHit(android.webkit.WebView, android.webkit.WebResourceRequest, int, androidx.webkit.SafeBrowsingResponseCompat);
- }
-
- public class WebViewCompat {
- method @RequiresFeature(name=androidx.webkit.WebViewFeature.WEB_MESSAGE_LISTENER, enforcement="androidx.webkit.WebViewFeature#isFeatureSupported") public static void addWebMessageListener(android.webkit.WebView, String, java.util.Set<java.lang.String!>, androidx.webkit.WebViewCompat.WebMessageListener);
- method @RequiresFeature(name=androidx.webkit.WebViewFeature.CREATE_WEB_MESSAGE_CHANNEL, enforcement="androidx.webkit.WebViewFeature#isFeatureSupported") public static androidx.webkit.WebMessagePortCompat![] createWebMessageChannel(android.webkit.WebView);
- method public static android.content.pm.PackageInfo? getCurrentWebViewPackage(android.content.Context);
- method @RequiresFeature(name=androidx.webkit.WebViewFeature.SAFE_BROWSING_PRIVACY_POLICY_URL, enforcement="androidx.webkit.WebViewFeature#isFeatureSupported") public static android.net.Uri getSafeBrowsingPrivacyPolicyUrl();
- method @RequiresFeature(name=androidx.webkit.WebViewFeature.GET_VARIATIONS_HEADER, enforcement="androidx.webkit.WebViewFeature#isFeatureSupported") public static String getVariationsHeader();
- method @RequiresFeature(name=androidx.webkit.WebViewFeature.GET_WEB_CHROME_CLIENT, enforcement="androidx.webkit.WebViewFeature#isFeatureSupported") public static android.webkit.WebChromeClient? getWebChromeClient(android.webkit.WebView);
- method @RequiresFeature(name=androidx.webkit.WebViewFeature.GET_WEB_VIEW_CLIENT, enforcement="androidx.webkit.WebViewFeature#isFeatureSupported") public static android.webkit.WebViewClient getWebViewClient(android.webkit.WebView);
- method @RequiresFeature(name=androidx.webkit.WebViewFeature.GET_WEB_VIEW_RENDERER, enforcement="androidx.webkit.WebViewFeature#isFeatureSupported") public static androidx.webkit.WebViewRenderProcess? getWebViewRenderProcess(android.webkit.WebView);
- method @RequiresFeature(name=androidx.webkit.WebViewFeature.WEB_VIEW_RENDERER_CLIENT_BASIC_USAGE, enforcement="androidx.webkit.WebViewFeature#isFeatureSupported") public static androidx.webkit.WebViewRenderProcessClient? getWebViewRenderProcessClient(android.webkit.WebView);
- method @RequiresFeature(name=androidx.webkit.WebViewFeature.MULTI_PROCESS, enforcement="androidx.webkit.WebViewFeature#isFeatureSupported") public static boolean isMultiProcessEnabled();
- method @RequiresFeature(name=androidx.webkit.WebViewFeature.VISUAL_STATE_CALLBACK, enforcement="androidx.webkit.WebViewFeature#isFeatureSupported") public static void postVisualStateCallback(android.webkit.WebView, long, androidx.webkit.WebViewCompat.VisualStateCallback);
- method @RequiresFeature(name=androidx.webkit.WebViewFeature.POST_WEB_MESSAGE, enforcement="androidx.webkit.WebViewFeature#isFeatureSupported") public static void postWebMessage(android.webkit.WebView, androidx.webkit.WebMessageCompat, android.net.Uri);
- method @RequiresFeature(name=androidx.webkit.WebViewFeature.WEB_MESSAGE_LISTENER, enforcement="androidx.webkit.WebViewFeature#isFeatureSupported") public static void removeWebMessageListener(android.webkit.WebView, String);
- method @RequiresFeature(name=androidx.webkit.WebViewFeature.SAFE_BROWSING_ALLOWLIST, enforcement="androidx.webkit.WebViewFeature#isFeatureSupported") public static void setSafeBrowsingAllowlist(java.util.Set<java.lang.String!>, android.webkit.ValueCallback<java.lang.Boolean!>?);
- method @Deprecated @RequiresFeature(name=androidx.webkit.WebViewFeature.SAFE_BROWSING_WHITELIST, enforcement="androidx.webkit.WebViewFeature#isFeatureSupported") public static void setSafeBrowsingWhitelist(java.util.List<java.lang.String!>, android.webkit.ValueCallback<java.lang.Boolean!>?);
- method @RequiresFeature(name=androidx.webkit.WebViewFeature.WEB_VIEW_RENDERER_CLIENT_BASIC_USAGE, enforcement="androidx.webkit.WebViewFeature#isFeatureSupported") public static void setWebViewRenderProcessClient(android.webkit.WebView, java.util.concurrent.Executor, androidx.webkit.WebViewRenderProcessClient);
- method @RequiresFeature(name=androidx.webkit.WebViewFeature.WEB_VIEW_RENDERER_CLIENT_BASIC_USAGE, enforcement="androidx.webkit.WebViewFeature#isFeatureSupported") public static void setWebViewRenderProcessClient(android.webkit.WebView, androidx.webkit.WebViewRenderProcessClient?);
- method @RequiresFeature(name=androidx.webkit.WebViewFeature.START_SAFE_BROWSING, enforcement="androidx.webkit.WebViewFeature#isFeatureSupported") public static void startSafeBrowsing(android.content.Context, android.webkit.ValueCallback<java.lang.Boolean!>?);
- }
-
- public static interface WebViewCompat.VisualStateCallback {
- method @UiThread public void onComplete(long);
- }
-
- public static interface WebViewCompat.WebMessageListener {
- method @UiThread public void onPostMessage(android.webkit.WebView, androidx.webkit.WebMessageCompat, android.net.Uri, boolean, androidx.webkit.JavaScriptReplyProxy);
- }
-
- public class WebViewFeature {
- method public static boolean isFeatureSupported(String);
- method public static boolean isStartupFeatureSupported(android.content.Context, String);
- field public static final String ALGORITHMIC_DARKENING = "ALGORITHMIC_DARKENING";
- field public static final String CREATE_WEB_MESSAGE_CHANNEL = "CREATE_WEB_MESSAGE_CHANNEL";
- field public static final String DISABLED_ACTION_MODE_MENU_ITEMS = "DISABLED_ACTION_MODE_MENU_ITEMS";
- field public static final String ENTERPRISE_AUTHENTICATION_APP_LINK_POLICY = "ENTERPRISE_AUTHENTICATION_APP_LINK_POLICY";
- field public static final String FORCE_DARK = "FORCE_DARK";
- field public static final String FORCE_DARK_STRATEGY = "FORCE_DARK_STRATEGY";
- field public static final String GET_COOKIE_INFO = "GET_COOKIE_INFO";
- field public static final String GET_VARIATIONS_HEADER = "GET_VARIATIONS_HEADER";
- field public static final String GET_WEB_CHROME_CLIENT = "GET_WEB_CHROME_CLIENT";
- field public static final String GET_WEB_VIEW_CLIENT = "GET_WEB_VIEW_CLIENT";
- field public static final String GET_WEB_VIEW_RENDERER = "GET_WEB_VIEW_RENDERER";
- field public static final String MULTI_PROCESS = "MULTI_PROCESS";
- field public static final String OFF_SCREEN_PRERASTER = "OFF_SCREEN_PRERASTER";
- field public static final String POST_WEB_MESSAGE = "POST_WEB_MESSAGE";
- field public static final String PROXY_OVERRIDE = "PROXY_OVERRIDE";
- field public static final String PROXY_OVERRIDE_REVERSE_BYPASS = "PROXY_OVERRIDE_REVERSE_BYPASS";
- field public static final String RECEIVE_HTTP_ERROR = "RECEIVE_HTTP_ERROR";
- field public static final String RECEIVE_WEB_RESOURCE_ERROR = "RECEIVE_WEB_RESOURCE_ERROR";
- field public static final String SAFE_BROWSING_ALLOWLIST = "SAFE_BROWSING_ALLOWLIST";
- field public static final String SAFE_BROWSING_ENABLE = "SAFE_BROWSING_ENABLE";
- field public static final String SAFE_BROWSING_HIT = "SAFE_BROWSING_HIT";
- field public static final String SAFE_BROWSING_PRIVACY_POLICY_URL = "SAFE_BROWSING_PRIVACY_POLICY_URL";
- field public static final String SAFE_BROWSING_RESPONSE_BACK_TO_SAFETY = "SAFE_BROWSING_RESPONSE_BACK_TO_SAFETY";
- field public static final String SAFE_BROWSING_RESPONSE_PROCEED = "SAFE_BROWSING_RESPONSE_PROCEED";
- field public static final String SAFE_BROWSING_RESPONSE_SHOW_INTERSTITIAL = "SAFE_BROWSING_RESPONSE_SHOW_INTERSTITIAL";
- field @Deprecated public static final String SAFE_BROWSING_WHITELIST = "SAFE_BROWSING_WHITELIST";
- field public static final String SERVICE_WORKER_BASIC_USAGE = "SERVICE_WORKER_BASIC_USAGE";
- field public static final String SERVICE_WORKER_BLOCK_NETWORK_LOADS = "SERVICE_WORKER_BLOCK_NETWORK_LOADS";
- field public static final String SERVICE_WORKER_CACHE_MODE = "SERVICE_WORKER_CACHE_MODE";
- field public static final String SERVICE_WORKER_CONTENT_ACCESS = "SERVICE_WORKER_CONTENT_ACCESS";
- field public static final String SERVICE_WORKER_FILE_ACCESS = "SERVICE_WORKER_FILE_ACCESS";
- field public static final String SERVICE_WORKER_SHOULD_INTERCEPT_REQUEST = "SERVICE_WORKER_SHOULD_INTERCEPT_REQUEST";
- field public static final String SHOULD_OVERRIDE_WITH_REDIRECTS = "SHOULD_OVERRIDE_WITH_REDIRECTS";
- field public static final String STARTUP_FEATURE_SET_DATA_DIRECTORY_SUFFIX = "STARTUP_FEATURE_SET_DATA_DIRECTORY_SUFFIX";
- field public static final String START_SAFE_BROWSING = "START_SAFE_BROWSING";
- field public static final String TRACING_CONTROLLER_BASIC_USAGE = "TRACING_CONTROLLER_BASIC_USAGE";
- field public static final String VISUAL_STATE_CALLBACK = "VISUAL_STATE_CALLBACK";
- field public static final String WEB_MESSAGE_CALLBACK_ON_MESSAGE = "WEB_MESSAGE_CALLBACK_ON_MESSAGE";
- field public static final String WEB_MESSAGE_LISTENER = "WEB_MESSAGE_LISTENER";
- field public static final String WEB_MESSAGE_PORT_CLOSE = "WEB_MESSAGE_PORT_CLOSE";
- field public static final String WEB_MESSAGE_PORT_POST_MESSAGE = "WEB_MESSAGE_PORT_POST_MESSAGE";
- field public static final String WEB_MESSAGE_PORT_SET_MESSAGE_CALLBACK = "WEB_MESSAGE_PORT_SET_MESSAGE_CALLBACK";
- field public static final String WEB_RESOURCE_ERROR_GET_CODE = "WEB_RESOURCE_ERROR_GET_CODE";
- field public static final String WEB_RESOURCE_ERROR_GET_DESCRIPTION = "WEB_RESOURCE_ERROR_GET_DESCRIPTION";
- field public static final String WEB_RESOURCE_REQUEST_IS_REDIRECT = "WEB_RESOURCE_REQUEST_IS_REDIRECT";
- field public static final String WEB_VIEW_RENDERER_CLIENT_BASIC_USAGE = "WEB_VIEW_RENDERER_CLIENT_BASIC_USAGE";
- field public static final String WEB_VIEW_RENDERER_TERMINATE = "WEB_VIEW_RENDERER_TERMINATE";
- }
-
- public abstract class WebViewRenderProcess {
- ctor public WebViewRenderProcess();
- method public abstract boolean terminate();
- }
-
- public abstract class WebViewRenderProcessClient {
- ctor public WebViewRenderProcessClient();
- method public abstract void onRenderProcessResponsive(android.webkit.WebView, androidx.webkit.WebViewRenderProcess?);
- method public abstract void onRenderProcessUnresponsive(android.webkit.WebView, androidx.webkit.WebViewRenderProcess?);
- }
-
-}
-
diff --git a/webkit/webkit/api/restricted_1.6.0-beta02.txt b/webkit/webkit/api/restricted_1.6.0-beta02.txt
deleted file mode 100644
index faf13cb..0000000
--- a/webkit/webkit/api/restricted_1.6.0-beta02.txt
+++ /dev/null
@@ -1,300 +0,0 @@
-// Signature format: 4.0
-package androidx.webkit {
-
- public class CookieManagerCompat {
- method @RequiresFeature(name=androidx.webkit.WebViewFeature.GET_COOKIE_INFO, enforcement="androidx.webkit.WebViewFeature#isFeatureSupported") public static java.util.List<java.lang.String!> getCookieInfo(android.webkit.CookieManager, String);
- }
-
- public abstract class JavaScriptReplyProxy {
- method @RequiresFeature(name=androidx.webkit.WebViewFeature.WEB_MESSAGE_LISTENER, enforcement="androidx.webkit.WebViewFeature#isFeatureSupported") public abstract void postMessage(String);
- }
-
- public class ProcessGlobalConfig {
- ctor public ProcessGlobalConfig();
- method public static void apply(androidx.webkit.ProcessGlobalConfig);
- method @RequiresFeature(name=androidx.webkit.WebViewFeature.STARTUP_FEATURE_SET_DATA_DIRECTORY_SUFFIX, enforcement="androidx.webkit.WebViewFeature#isConfigFeatureSupported(String, Context)") public androidx.webkit.ProcessGlobalConfig setDataDirectorySuffix(android.content.Context, String);
- }
-
- public final class ProxyConfig {
- method public java.util.List<java.lang.String!> getBypassRules();
- method public java.util.List<androidx.webkit.ProxyConfig.ProxyRule!> getProxyRules();
- method public boolean isReverseBypassEnabled();
- field public static final String MATCH_ALL_SCHEMES = "*";
- field public static final String MATCH_HTTP = "http";
- field public static final String MATCH_HTTPS = "https";
- }
-
- public static final class ProxyConfig.Builder {
- ctor public ProxyConfig.Builder();
- ctor public ProxyConfig.Builder(androidx.webkit.ProxyConfig);
- method public androidx.webkit.ProxyConfig.Builder addBypassRule(String);
- method public androidx.webkit.ProxyConfig.Builder addDirect(String);
- method public androidx.webkit.ProxyConfig.Builder addDirect();
- method public androidx.webkit.ProxyConfig.Builder addProxyRule(String);
- method public androidx.webkit.ProxyConfig.Builder addProxyRule(String, String);
- method public androidx.webkit.ProxyConfig build();
- method public androidx.webkit.ProxyConfig.Builder bypassSimpleHostnames();
- method public androidx.webkit.ProxyConfig.Builder removeImplicitRules();
- method @RequiresFeature(name=androidx.webkit.WebViewFeature.PROXY_OVERRIDE_REVERSE_BYPASS, enforcement="androidx.webkit.WebViewFeature#isFeatureSupported") public androidx.webkit.ProxyConfig.Builder setReverseBypassEnabled(boolean);
- }
-
- public static final class ProxyConfig.ProxyRule {
- method public String getSchemeFilter();
- method public String getUrl();
- }
-
- public abstract class ProxyController {
- method public abstract void clearProxyOverride(java.util.concurrent.Executor, Runnable);
- method @RequiresFeature(name=androidx.webkit.WebViewFeature.PROXY_OVERRIDE, enforcement="androidx.webkit.WebViewFeature#isFeatureSupported") public static androidx.webkit.ProxyController getInstance();
- method public abstract void setProxyOverride(androidx.webkit.ProxyConfig, java.util.concurrent.Executor, Runnable);
- }
-
- public abstract class SafeBrowsingResponseCompat {
- method @RequiresFeature(name=androidx.webkit.WebViewFeature.SAFE_BROWSING_RESPONSE_BACK_TO_SAFETY, enforcement="androidx.webkit.WebViewFeature#isFeatureSupported") public abstract void backToSafety(boolean);
- method @RequiresFeature(name=androidx.webkit.WebViewFeature.SAFE_BROWSING_RESPONSE_PROCEED, enforcement="androidx.webkit.WebViewFeature#isFeatureSupported") public abstract void proceed(boolean);
- method @RequiresFeature(name=androidx.webkit.WebViewFeature.SAFE_BROWSING_RESPONSE_SHOW_INTERSTITIAL, enforcement="androidx.webkit.WebViewFeature#isFeatureSupported") public abstract void showInterstitial(boolean);
- }
-
- public abstract class ServiceWorkerClientCompat {
- ctor public ServiceWorkerClientCompat();
- method @WorkerThread public abstract android.webkit.WebResourceResponse? shouldInterceptRequest(android.webkit.WebResourceRequest);
- }
-
- public abstract class ServiceWorkerControllerCompat {
- method @RequiresFeature(name=androidx.webkit.WebViewFeature.SERVICE_WORKER_BASIC_USAGE, enforcement="androidx.webkit.WebViewFeature#isFeatureSupported") public static androidx.webkit.ServiceWorkerControllerCompat getInstance();
- method public abstract androidx.webkit.ServiceWorkerWebSettingsCompat getServiceWorkerWebSettings();
- method public abstract void setServiceWorkerClient(androidx.webkit.ServiceWorkerClientCompat?);
- }
-
- public abstract class ServiceWorkerWebSettingsCompat {
- method @RequiresFeature(name=androidx.webkit.WebViewFeature.SERVICE_WORKER_CONTENT_ACCESS, enforcement="androidx.webkit.WebViewFeature#isFeatureSupported") public abstract boolean getAllowContentAccess();
- method @RequiresFeature(name=androidx.webkit.WebViewFeature.SERVICE_WORKER_FILE_ACCESS, enforcement="androidx.webkit.WebViewFeature#isFeatureSupported") public abstract boolean getAllowFileAccess();
- method @RequiresFeature(name=androidx.webkit.WebViewFeature.SERVICE_WORKER_BLOCK_NETWORK_LOADS, enforcement="androidx.webkit.WebViewFeature#isFeatureSupported") public abstract boolean getBlockNetworkLoads();
- method @RequiresFeature(name=androidx.webkit.WebViewFeature.SERVICE_WORKER_CACHE_MODE, enforcement="androidx.webkit.WebViewFeature#isFeatureSupported") public abstract int getCacheMode();
- method @RequiresFeature(name="REQUESTED_WITH_HEADER_ALLOW_LIST", enforcement="androidx.webkit.WebViewFeature#isFeatureSupported") public abstract java.util.Set<java.lang.String!> getRequestedWithHeaderOriginAllowList();
- method @RequiresFeature(name=androidx.webkit.WebViewFeature.SERVICE_WORKER_CONTENT_ACCESS, enforcement="androidx.webkit.WebViewFeature#isFeatureSupported") public abstract void setAllowContentAccess(boolean);
- method @RequiresFeature(name=androidx.webkit.WebViewFeature.SERVICE_WORKER_FILE_ACCESS, enforcement="androidx.webkit.WebViewFeature#isFeatureSupported") public abstract void setAllowFileAccess(boolean);
- method @RequiresFeature(name=androidx.webkit.WebViewFeature.SERVICE_WORKER_BLOCK_NETWORK_LOADS, enforcement="androidx.webkit.WebViewFeature#isFeatureSupported") public abstract void setBlockNetworkLoads(boolean);
- method @RequiresFeature(name=androidx.webkit.WebViewFeature.SERVICE_WORKER_CACHE_MODE, enforcement="androidx.webkit.WebViewFeature#isFeatureSupported") public abstract void setCacheMode(int);
- method @RequiresFeature(name="REQUESTED_WITH_HEADER_ALLOW_LIST", enforcement="androidx.webkit.WebViewFeature#isFeatureSupported") public abstract void setRequestedWithHeaderOriginAllowList(java.util.Set<java.lang.String!>);
- }
-
- public class TracingConfig {
- method public java.util.List<java.lang.String!> getCustomIncludedCategories();
- method public int getPredefinedCategories();
- method public int getTracingMode();
- field public static final int CATEGORIES_ALL = 1; // 0x1
- field public static final int CATEGORIES_ANDROID_WEBVIEW = 2; // 0x2
- field public static final int CATEGORIES_FRAME_VIEWER = 64; // 0x40
- field public static final int CATEGORIES_INPUT_LATENCY = 8; // 0x8
- field public static final int CATEGORIES_JAVASCRIPT_AND_RENDERING = 32; // 0x20
- field public static final int CATEGORIES_NONE = 0; // 0x0
- field public static final int CATEGORIES_RENDERING = 16; // 0x10
- field public static final int CATEGORIES_WEB_DEVELOPER = 4; // 0x4
- field public static final int RECORD_CONTINUOUSLY = 1; // 0x1
- field public static final int RECORD_UNTIL_FULL = 0; // 0x0
- }
-
- public static class TracingConfig.Builder {
- ctor public TracingConfig.Builder();
- method public androidx.webkit.TracingConfig.Builder addCategories(int...);
- method public androidx.webkit.TracingConfig.Builder addCategories(java.lang.String!...);
- method public androidx.webkit.TracingConfig.Builder addCategories(java.util.Collection<java.lang.String!>);
- method public androidx.webkit.TracingConfig build();
- method public androidx.webkit.TracingConfig.Builder setTracingMode(int);
- }
-
- public abstract class TracingController {
- method @RequiresFeature(name=androidx.webkit.WebViewFeature.TRACING_CONTROLLER_BASIC_USAGE, enforcement="androidx.webkit.WebViewFeature#isFeatureSupported") public static androidx.webkit.TracingController getInstance();
- method public abstract boolean isTracing();
- method public abstract void start(androidx.webkit.TracingConfig);
- method public abstract boolean stop(java.io.OutputStream?, java.util.concurrent.Executor);
- }
-
- public class WebMessageCompat {
- ctor public WebMessageCompat(String?);
- ctor public WebMessageCompat(String?, androidx.webkit.WebMessagePortCompat![]?);
- method public String? getData();
- method public androidx.webkit.WebMessagePortCompat![]? getPorts();
- }
-
- public abstract class WebMessagePortCompat {
- method @RequiresFeature(name=androidx.webkit.WebViewFeature.WEB_MESSAGE_PORT_CLOSE, enforcement="androidx.webkit.WebViewFeature#isFeatureSupported") public abstract void close();
- method @RequiresFeature(name=androidx.webkit.WebViewFeature.WEB_MESSAGE_PORT_POST_MESSAGE, enforcement="androidx.webkit.WebViewFeature#isFeatureSupported") public abstract void postMessage(androidx.webkit.WebMessageCompat);
- method @RequiresFeature(name=androidx.webkit.WebViewFeature.WEB_MESSAGE_PORT_SET_MESSAGE_CALLBACK, enforcement="androidx.webkit.WebViewFeature#isFeatureSupported") public abstract void setWebMessageCallback(androidx.webkit.WebMessagePortCompat.WebMessageCallbackCompat);
- method @RequiresFeature(name=androidx.webkit.WebViewFeature.WEB_MESSAGE_PORT_SET_MESSAGE_CALLBACK, enforcement="androidx.webkit.WebViewFeature#isFeatureSupported") public abstract void setWebMessageCallback(android.os.Handler?, androidx.webkit.WebMessagePortCompat.WebMessageCallbackCompat);
- }
-
- public abstract static class WebMessagePortCompat.WebMessageCallbackCompat {
- ctor public WebMessagePortCompat.WebMessageCallbackCompat();
- method public void onMessage(androidx.webkit.WebMessagePortCompat, androidx.webkit.WebMessageCompat?);
- }
-
- public abstract class WebResourceErrorCompat {
- method @RequiresFeature(name=androidx.webkit.WebViewFeature.WEB_RESOURCE_ERROR_GET_DESCRIPTION, enforcement="androidx.webkit.WebViewFeature#isFeatureSupported") public abstract CharSequence getDescription();
- method @RequiresFeature(name=androidx.webkit.WebViewFeature.WEB_RESOURCE_ERROR_GET_CODE, enforcement="androidx.webkit.WebViewFeature#isFeatureSupported") public abstract int getErrorCode();
- }
-
- public class WebResourceRequestCompat {
- method @RequiresFeature(name=androidx.webkit.WebViewFeature.WEB_RESOURCE_REQUEST_IS_REDIRECT, enforcement="androidx.webkit.WebViewFeature#isFeatureSupported") public static boolean isRedirect(android.webkit.WebResourceRequest);
- }
-
- public class WebSettingsCompat {
- method @RequiresFeature(name=androidx.webkit.WebViewFeature.DISABLED_ACTION_MODE_MENU_ITEMS, enforcement="androidx.webkit.WebViewFeature#isFeatureSupported") public static int getDisabledActionModeMenuItems(android.webkit.WebSettings);
- method @RequiresFeature(name=androidx.webkit.WebViewFeature.ENTERPRISE_AUTHENTICATION_APP_LINK_POLICY, enforcement="androidx.webkit.WebViewFeature#isFeatureSupported") public static boolean getEnterpriseAuthenticationAppLinkPolicyEnabled(android.webkit.WebSettings);
- method @Deprecated @RequiresFeature(name=androidx.webkit.WebViewFeature.FORCE_DARK, enforcement="androidx.webkit.WebViewFeature#isFeatureSupported") public static int getForceDark(android.webkit.WebSettings);
- method @Deprecated @RequiresFeature(name=androidx.webkit.WebViewFeature.FORCE_DARK_STRATEGY, enforcement="androidx.webkit.WebViewFeature#isFeatureSupported") public static int getForceDarkStrategy(android.webkit.WebSettings);
- method @RequiresFeature(name=androidx.webkit.WebViewFeature.OFF_SCREEN_PRERASTER, enforcement="androidx.webkit.WebViewFeature#isFeatureSupported") public static boolean getOffscreenPreRaster(android.webkit.WebSettings);
- method @RequiresFeature(name="REQUESTED_WITH_HEADER_ALLOW_LIST", enforcement="androidx.webkit.WebViewFeature#isFeatureSupported") public static java.util.Set<java.lang.String!> getRequestedWithHeaderOriginAllowList(android.webkit.WebSettings);
- method @RequiresFeature(name=androidx.webkit.WebViewFeature.SAFE_BROWSING_ENABLE, enforcement="androidx.webkit.WebViewFeature#isFeatureSupported") public static boolean getSafeBrowsingEnabled(android.webkit.WebSettings);
- method @RequiresFeature(name=androidx.webkit.WebViewFeature.ALGORITHMIC_DARKENING, enforcement="androidx.webkit.WebViewFeature#isFeatureSupported") public static boolean isAlgorithmicDarkeningAllowed(android.webkit.WebSettings);
- method @RequiresFeature(name=androidx.webkit.WebViewFeature.ALGORITHMIC_DARKENING, enforcement="androidx.webkit.WebViewFeature#isFeatureSupported") public static void setAlgorithmicDarkeningAllowed(android.webkit.WebSettings, boolean);
- method @RequiresFeature(name=androidx.webkit.WebViewFeature.DISABLED_ACTION_MODE_MENU_ITEMS, enforcement="androidx.webkit.WebViewFeature#isFeatureSupported") public static void setDisabledActionModeMenuItems(android.webkit.WebSettings, int);
- method @RequiresFeature(name=androidx.webkit.WebViewFeature.ENTERPRISE_AUTHENTICATION_APP_LINK_POLICY, enforcement="androidx.webkit.WebViewFeature#isFeatureSupported") public static void setEnterpriseAuthenticationAppLinkPolicyEnabled(android.webkit.WebSettings, boolean);
- method @Deprecated @RequiresFeature(name=androidx.webkit.WebViewFeature.FORCE_DARK, enforcement="androidx.webkit.WebViewFeature#isFeatureSupported") public static void setForceDark(android.webkit.WebSettings, int);
- method @Deprecated @RequiresFeature(name=androidx.webkit.WebViewFeature.FORCE_DARK_STRATEGY, enforcement="androidx.webkit.WebViewFeature#isFeatureSupported") public static void setForceDarkStrategy(android.webkit.WebSettings, int);
- method @RequiresFeature(name=androidx.webkit.WebViewFeature.OFF_SCREEN_PRERASTER, enforcement="androidx.webkit.WebViewFeature#isFeatureSupported") public static void setOffscreenPreRaster(android.webkit.WebSettings, boolean);
- method @RequiresFeature(name="REQUESTED_WITH_HEADER_ALLOW_LIST", enforcement="androidx.webkit.WebViewFeature#isFeatureSupported") public static void setRequestedWithHeaderOriginAllowList(android.webkit.WebSettings, java.util.Set<java.lang.String!>);
- method @RequiresFeature(name=androidx.webkit.WebViewFeature.SAFE_BROWSING_ENABLE, enforcement="androidx.webkit.WebViewFeature#isFeatureSupported") public static void setSafeBrowsingEnabled(android.webkit.WebSettings, boolean);
- field @Deprecated public static final int DARK_STRATEGY_PREFER_WEB_THEME_OVER_USER_AGENT_DARKENING = 2; // 0x2
- field @Deprecated public static final int DARK_STRATEGY_USER_AGENT_DARKENING_ONLY = 0; // 0x0
- field @Deprecated public static final int DARK_STRATEGY_WEB_THEME_DARKENING_ONLY = 1; // 0x1
- field @Deprecated public static final int FORCE_DARK_AUTO = 1; // 0x1
- field @Deprecated public static final int FORCE_DARK_OFF = 0; // 0x0
- field @Deprecated public static final int FORCE_DARK_ON = 2; // 0x2
- }
-
- public final class WebViewAssetLoader {
- method @WorkerThread public android.webkit.WebResourceResponse? shouldInterceptRequest(android.net.Uri);
- field public static final String DEFAULT_DOMAIN = "appassets.androidplatform.net";
- }
-
- public static final class WebViewAssetLoader.AssetsPathHandler implements androidx.webkit.WebViewAssetLoader.PathHandler {
- ctor public WebViewAssetLoader.AssetsPathHandler(android.content.Context);
- method @WorkerThread public android.webkit.WebResourceResponse? handle(String);
- }
-
- public static final class WebViewAssetLoader.Builder {
- ctor public WebViewAssetLoader.Builder();
- method public androidx.webkit.WebViewAssetLoader.Builder addPathHandler(String, androidx.webkit.WebViewAssetLoader.PathHandler);
- method public androidx.webkit.WebViewAssetLoader build();
- method public androidx.webkit.WebViewAssetLoader.Builder setDomain(String);
- method public androidx.webkit.WebViewAssetLoader.Builder setHttpAllowed(boolean);
- }
-
- public static final class WebViewAssetLoader.InternalStoragePathHandler implements androidx.webkit.WebViewAssetLoader.PathHandler {
- ctor public WebViewAssetLoader.InternalStoragePathHandler(android.content.Context, java.io.File);
- method @WorkerThread public android.webkit.WebResourceResponse handle(String);
- }
-
- public static interface WebViewAssetLoader.PathHandler {
- method @WorkerThread public android.webkit.WebResourceResponse? handle(String);
- }
-
- public static final class WebViewAssetLoader.ResourcesPathHandler implements androidx.webkit.WebViewAssetLoader.PathHandler {
- ctor public WebViewAssetLoader.ResourcesPathHandler(android.content.Context);
- method @WorkerThread public android.webkit.WebResourceResponse? handle(String);
- }
-
- public class WebViewClientCompat extends android.webkit.WebViewClient {
- ctor public WebViewClientCompat();
- method @RequiresApi(23) public final void onReceivedError(android.webkit.WebView, android.webkit.WebResourceRequest, android.webkit.WebResourceError);
- method @RequiresApi(21) @UiThread public void onReceivedError(android.webkit.WebView, android.webkit.WebResourceRequest, androidx.webkit.WebResourceErrorCompat);
- method @RequiresApi(27) public final void onSafeBrowsingHit(android.webkit.WebView, android.webkit.WebResourceRequest, int, android.webkit.SafeBrowsingResponse);
- method @UiThread public void onSafeBrowsingHit(android.webkit.WebView, android.webkit.WebResourceRequest, int, androidx.webkit.SafeBrowsingResponseCompat);
- }
-
- public class WebViewCompat {
- method @RequiresFeature(name=androidx.webkit.WebViewFeature.WEB_MESSAGE_LISTENER, enforcement="androidx.webkit.WebViewFeature#isFeatureSupported") public static void addWebMessageListener(android.webkit.WebView, String, java.util.Set<java.lang.String!>, androidx.webkit.WebViewCompat.WebMessageListener);
- method @RequiresFeature(name=androidx.webkit.WebViewFeature.CREATE_WEB_MESSAGE_CHANNEL, enforcement="androidx.webkit.WebViewFeature#isFeatureSupported") public static androidx.webkit.WebMessagePortCompat![] createWebMessageChannel(android.webkit.WebView);
- method public static android.content.pm.PackageInfo? getCurrentWebViewPackage(android.content.Context);
- method @RequiresFeature(name=androidx.webkit.WebViewFeature.SAFE_BROWSING_PRIVACY_POLICY_URL, enforcement="androidx.webkit.WebViewFeature#isFeatureSupported") public static android.net.Uri getSafeBrowsingPrivacyPolicyUrl();
- method @RequiresFeature(name=androidx.webkit.WebViewFeature.GET_VARIATIONS_HEADER, enforcement="androidx.webkit.WebViewFeature#isFeatureSupported") public static String getVariationsHeader();
- method @RequiresFeature(name=androidx.webkit.WebViewFeature.GET_WEB_CHROME_CLIENT, enforcement="androidx.webkit.WebViewFeature#isFeatureSupported") public static android.webkit.WebChromeClient? getWebChromeClient(android.webkit.WebView);
- method @RequiresFeature(name=androidx.webkit.WebViewFeature.GET_WEB_VIEW_CLIENT, enforcement="androidx.webkit.WebViewFeature#isFeatureSupported") public static android.webkit.WebViewClient getWebViewClient(android.webkit.WebView);
- method @RequiresFeature(name=androidx.webkit.WebViewFeature.GET_WEB_VIEW_RENDERER, enforcement="androidx.webkit.WebViewFeature#isFeatureSupported") public static androidx.webkit.WebViewRenderProcess? getWebViewRenderProcess(android.webkit.WebView);
- method @RequiresFeature(name=androidx.webkit.WebViewFeature.WEB_VIEW_RENDERER_CLIENT_BASIC_USAGE, enforcement="androidx.webkit.WebViewFeature#isFeatureSupported") public static androidx.webkit.WebViewRenderProcessClient? getWebViewRenderProcessClient(android.webkit.WebView);
- method @RequiresFeature(name=androidx.webkit.WebViewFeature.MULTI_PROCESS, enforcement="androidx.webkit.WebViewFeature#isFeatureSupported") public static boolean isMultiProcessEnabled();
- method @RequiresFeature(name=androidx.webkit.WebViewFeature.VISUAL_STATE_CALLBACK, enforcement="androidx.webkit.WebViewFeature#isFeatureSupported") public static void postVisualStateCallback(android.webkit.WebView, long, androidx.webkit.WebViewCompat.VisualStateCallback);
- method @RequiresFeature(name=androidx.webkit.WebViewFeature.POST_WEB_MESSAGE, enforcement="androidx.webkit.WebViewFeature#isFeatureSupported") public static void postWebMessage(android.webkit.WebView, androidx.webkit.WebMessageCompat, android.net.Uri);
- method @RequiresFeature(name=androidx.webkit.WebViewFeature.WEB_MESSAGE_LISTENER, enforcement="androidx.webkit.WebViewFeature#isFeatureSupported") public static void removeWebMessageListener(android.webkit.WebView, String);
- method @RequiresFeature(name=androidx.webkit.WebViewFeature.SAFE_BROWSING_ALLOWLIST, enforcement="androidx.webkit.WebViewFeature#isFeatureSupported") public static void setSafeBrowsingAllowlist(java.util.Set<java.lang.String!>, android.webkit.ValueCallback<java.lang.Boolean!>?);
- method @Deprecated @RequiresFeature(name=androidx.webkit.WebViewFeature.SAFE_BROWSING_WHITELIST, enforcement="androidx.webkit.WebViewFeature#isFeatureSupported") public static void setSafeBrowsingWhitelist(java.util.List<java.lang.String!>, android.webkit.ValueCallback<java.lang.Boolean!>?);
- method @RequiresFeature(name=androidx.webkit.WebViewFeature.WEB_VIEW_RENDERER_CLIENT_BASIC_USAGE, enforcement="androidx.webkit.WebViewFeature#isFeatureSupported") public static void setWebViewRenderProcessClient(android.webkit.WebView, java.util.concurrent.Executor, androidx.webkit.WebViewRenderProcessClient);
- method @RequiresFeature(name=androidx.webkit.WebViewFeature.WEB_VIEW_RENDERER_CLIENT_BASIC_USAGE, enforcement="androidx.webkit.WebViewFeature#isFeatureSupported") public static void setWebViewRenderProcessClient(android.webkit.WebView, androidx.webkit.WebViewRenderProcessClient?);
- method @RequiresFeature(name=androidx.webkit.WebViewFeature.START_SAFE_BROWSING, enforcement="androidx.webkit.WebViewFeature#isFeatureSupported") public static void startSafeBrowsing(android.content.Context, android.webkit.ValueCallback<java.lang.Boolean!>?);
- }
-
- public static interface WebViewCompat.VisualStateCallback {
- method @UiThread public void onComplete(long);
- }
-
- public static interface WebViewCompat.WebMessageListener {
- method @UiThread public void onPostMessage(android.webkit.WebView, androidx.webkit.WebMessageCompat, android.net.Uri, boolean, androidx.webkit.JavaScriptReplyProxy);
- }
-
- public class WebViewFeature {
- method public static boolean isFeatureSupported(String);
- method public static boolean isStartupFeatureSupported(android.content.Context, String);
- field public static final String ALGORITHMIC_DARKENING = "ALGORITHMIC_DARKENING";
- field public static final String CREATE_WEB_MESSAGE_CHANNEL = "CREATE_WEB_MESSAGE_CHANNEL";
- field public static final String DISABLED_ACTION_MODE_MENU_ITEMS = "DISABLED_ACTION_MODE_MENU_ITEMS";
- field public static final String ENTERPRISE_AUTHENTICATION_APP_LINK_POLICY = "ENTERPRISE_AUTHENTICATION_APP_LINK_POLICY";
- field public static final String FORCE_DARK = "FORCE_DARK";
- field public static final String FORCE_DARK_STRATEGY = "FORCE_DARK_STRATEGY";
- field public static final String GET_COOKIE_INFO = "GET_COOKIE_INFO";
- field public static final String GET_VARIATIONS_HEADER = "GET_VARIATIONS_HEADER";
- field public static final String GET_WEB_CHROME_CLIENT = "GET_WEB_CHROME_CLIENT";
- field public static final String GET_WEB_VIEW_CLIENT = "GET_WEB_VIEW_CLIENT";
- field public static final String GET_WEB_VIEW_RENDERER = "GET_WEB_VIEW_RENDERER";
- field public static final String MULTI_PROCESS = "MULTI_PROCESS";
- field public static final String OFF_SCREEN_PRERASTER = "OFF_SCREEN_PRERASTER";
- field public static final String POST_WEB_MESSAGE = "POST_WEB_MESSAGE";
- field public static final String PROXY_OVERRIDE = "PROXY_OVERRIDE";
- field public static final String PROXY_OVERRIDE_REVERSE_BYPASS = "PROXY_OVERRIDE_REVERSE_BYPASS";
- field public static final String RECEIVE_HTTP_ERROR = "RECEIVE_HTTP_ERROR";
- field public static final String RECEIVE_WEB_RESOURCE_ERROR = "RECEIVE_WEB_RESOURCE_ERROR";
- field public static final String SAFE_BROWSING_ALLOWLIST = "SAFE_BROWSING_ALLOWLIST";
- field public static final String SAFE_BROWSING_ENABLE = "SAFE_BROWSING_ENABLE";
- field public static final String SAFE_BROWSING_HIT = "SAFE_BROWSING_HIT";
- field public static final String SAFE_BROWSING_PRIVACY_POLICY_URL = "SAFE_BROWSING_PRIVACY_POLICY_URL";
- field public static final String SAFE_BROWSING_RESPONSE_BACK_TO_SAFETY = "SAFE_BROWSING_RESPONSE_BACK_TO_SAFETY";
- field public static final String SAFE_BROWSING_RESPONSE_PROCEED = "SAFE_BROWSING_RESPONSE_PROCEED";
- field public static final String SAFE_BROWSING_RESPONSE_SHOW_INTERSTITIAL = "SAFE_BROWSING_RESPONSE_SHOW_INTERSTITIAL";
- field @Deprecated public static final String SAFE_BROWSING_WHITELIST = "SAFE_BROWSING_WHITELIST";
- field public static final String SERVICE_WORKER_BASIC_USAGE = "SERVICE_WORKER_BASIC_USAGE";
- field public static final String SERVICE_WORKER_BLOCK_NETWORK_LOADS = "SERVICE_WORKER_BLOCK_NETWORK_LOADS";
- field public static final String SERVICE_WORKER_CACHE_MODE = "SERVICE_WORKER_CACHE_MODE";
- field public static final String SERVICE_WORKER_CONTENT_ACCESS = "SERVICE_WORKER_CONTENT_ACCESS";
- field public static final String SERVICE_WORKER_FILE_ACCESS = "SERVICE_WORKER_FILE_ACCESS";
- field public static final String SERVICE_WORKER_SHOULD_INTERCEPT_REQUEST = "SERVICE_WORKER_SHOULD_INTERCEPT_REQUEST";
- field public static final String SHOULD_OVERRIDE_WITH_REDIRECTS = "SHOULD_OVERRIDE_WITH_REDIRECTS";
- field public static final String STARTUP_FEATURE_SET_DATA_DIRECTORY_SUFFIX = "STARTUP_FEATURE_SET_DATA_DIRECTORY_SUFFIX";
- field public static final String START_SAFE_BROWSING = "START_SAFE_BROWSING";
- field public static final String TRACING_CONTROLLER_BASIC_USAGE = "TRACING_CONTROLLER_BASIC_USAGE";
- field public static final String VISUAL_STATE_CALLBACK = "VISUAL_STATE_CALLBACK";
- field public static final String WEB_MESSAGE_CALLBACK_ON_MESSAGE = "WEB_MESSAGE_CALLBACK_ON_MESSAGE";
- field public static final String WEB_MESSAGE_LISTENER = "WEB_MESSAGE_LISTENER";
- field public static final String WEB_MESSAGE_PORT_CLOSE = "WEB_MESSAGE_PORT_CLOSE";
- field public static final String WEB_MESSAGE_PORT_POST_MESSAGE = "WEB_MESSAGE_PORT_POST_MESSAGE";
- field public static final String WEB_MESSAGE_PORT_SET_MESSAGE_CALLBACK = "WEB_MESSAGE_PORT_SET_MESSAGE_CALLBACK";
- field public static final String WEB_RESOURCE_ERROR_GET_CODE = "WEB_RESOURCE_ERROR_GET_CODE";
- field public static final String WEB_RESOURCE_ERROR_GET_DESCRIPTION = "WEB_RESOURCE_ERROR_GET_DESCRIPTION";
- field public static final String WEB_RESOURCE_REQUEST_IS_REDIRECT = "WEB_RESOURCE_REQUEST_IS_REDIRECT";
- field public static final String WEB_VIEW_RENDERER_CLIENT_BASIC_USAGE = "WEB_VIEW_RENDERER_CLIENT_BASIC_USAGE";
- field public static final String WEB_VIEW_RENDERER_TERMINATE = "WEB_VIEW_RENDERER_TERMINATE";
- }
-
- public abstract class WebViewRenderProcess {
- ctor public WebViewRenderProcess();
- method public abstract boolean terminate();
- }
-
- public abstract class WebViewRenderProcessClient {
- ctor public WebViewRenderProcessClient();
- method public abstract void onRenderProcessResponsive(android.webkit.WebView, androidx.webkit.WebViewRenderProcess?);
- method public abstract void onRenderProcessUnresponsive(android.webkit.WebView, androidx.webkit.WebViewRenderProcess?);
- }
-
-}
-
diff --git a/window/extensions/extensions/api/current.txt b/window/extensions/extensions/api/current.txt
index f0c699b..7119193 100644
--- a/window/extensions/extensions/api/current.txt
+++ b/window/extensions/extensions/api/current.txt
@@ -4,6 +4,7 @@
public interface WindowExtensions {
method public default androidx.window.extensions.embedding.ActivityEmbeddingComponent? getActivityEmbeddingComponent();
method public default int getVendorApiLevel();
+ method public default androidx.window.extensions.area.WindowAreaComponent? getWindowAreaComponent();
method public androidx.window.extensions.layout.WindowLayoutComponent? getWindowLayoutComponent();
}
@@ -13,16 +14,53 @@
}
+package androidx.window.extensions.area {
+
+ public interface ExtensionWindowAreaPresentation {
+ method public android.content.Context getPresentationContext();
+ method public void setPresentationView(android.view.View);
+ }
+
+ public interface ExtensionWindowAreaStatus {
+ method public android.util.DisplayMetrics getWindowAreaDisplayMetrics();
+ method public int getWindowAreaStatus();
+ }
+
+ public interface WindowAreaComponent {
+ method public void addRearDisplayPresentationStatusListener(androidx.window.extensions.core.util.function.Consumer<androidx.window.extensions.area.ExtensionWindowAreaStatus!>);
+ method public void addRearDisplayStatusListener(androidx.window.extensions.core.util.function.Consumer<java.lang.Integer!>);
+ method public void endRearDisplayPresentationSession();
+ method public void endRearDisplaySession();
+ method public androidx.window.extensions.area.ExtensionWindowAreaPresentation? getRearDisplayPresentation();
+ method public void removeRearDisplayPresentationStatusListener(androidx.window.extensions.core.util.function.Consumer<androidx.window.extensions.area.ExtensionWindowAreaStatus!>);
+ method public void removeRearDisplayStatusListener(androidx.window.extensions.core.util.function.Consumer<java.lang.Integer!>);
+ method public void startRearDisplayPresentationSession(android.app.Activity, androidx.window.extensions.core.util.function.Consumer<java.lang.Integer!>);
+ method public void startRearDisplaySession(android.app.Activity, androidx.window.extensions.core.util.function.Consumer<java.lang.Integer!>);
+ field public static final int SESSION_STATE_ACTIVE = 1; // 0x1
+ field public static final int SESSION_STATE_INACTIVE = 0; // 0x0
+ field public static final int SESSION_STATE_INVISIBLE = 3; // 0x3
+ field public static final int SESSION_STATE_VISIBLE = 2; // 0x2
+ field public static final int STATUS_AVAILABLE = 2; // 0x2
+ field public static final int STATUS_UNAVAILABLE = 1; // 0x1
+ field public static final int STATUS_UNSUPPORTED = 0; // 0x0
+ }
+
+}
+
package androidx.window.extensions.embedding {
public interface ActivityEmbeddingComponent {
method public void clearSplitAttributesCalculator();
method public void clearSplitInfoCallback();
+ method public void finishActivityStacks(java.util.Set<android.os.IBinder!>);
+ method public void invalidateTopVisibleSplitAttributes();
method public boolean isActivityEmbedded(android.app.Activity);
method public void setEmbeddingRules(java.util.Set<androidx.window.extensions.embedding.EmbeddingRule!>);
+ method public android.app.ActivityOptions setLaunchingActivityStack(android.app.ActivityOptions, android.os.IBinder);
method public void setSplitAttributesCalculator(androidx.window.extensions.core.util.function.Function<androidx.window.extensions.embedding.SplitAttributesCalculatorParams!,androidx.window.extensions.embedding.SplitAttributes!>);
method @Deprecated public void setSplitInfoCallback(java.util.function.Consumer<java.util.List<androidx.window.extensions.embedding.SplitInfo!>!>);
method public default void setSplitInfoCallback(androidx.window.extensions.core.util.function.Consumer<java.util.List<androidx.window.extensions.embedding.SplitInfo!>!>);
+ method public void updateSplitAttributes(android.os.IBinder, androidx.window.extensions.embedding.SplitAttributes);
}
public class ActivityRule extends androidx.window.extensions.embedding.EmbeddingRule {
@@ -52,6 +90,7 @@
method @ColorInt public int getAnimationBackgroundColor();
method public int getLayoutDirection();
method public androidx.window.extensions.embedding.SplitAttributes.SplitType getSplitType();
+ field @ColorInt public static final int DEFAULT_ANIMATION_BACKGROUND_COLOR = 0; // 0x0
}
public static final class SplitAttributes.Builder {
@@ -102,6 +141,7 @@
method public androidx.window.extensions.embedding.ActivityStack getSecondaryActivityStack();
method public androidx.window.extensions.embedding.SplitAttributes getSplitAttributes();
method @Deprecated public float getSplitRatio();
+ method public android.os.IBinder getToken();
}
public class SplitPairRule extends androidx.window.extensions.embedding.SplitRule {
diff --git a/window/extensions/extensions/api/public_plus_experimental_current.txt b/window/extensions/extensions/api/public_plus_experimental_current.txt
index f0c699b..7119193 100644
--- a/window/extensions/extensions/api/public_plus_experimental_current.txt
+++ b/window/extensions/extensions/api/public_plus_experimental_current.txt
@@ -4,6 +4,7 @@
public interface WindowExtensions {
method public default androidx.window.extensions.embedding.ActivityEmbeddingComponent? getActivityEmbeddingComponent();
method public default int getVendorApiLevel();
+ method public default androidx.window.extensions.area.WindowAreaComponent? getWindowAreaComponent();
method public androidx.window.extensions.layout.WindowLayoutComponent? getWindowLayoutComponent();
}
@@ -13,16 +14,53 @@
}
+package androidx.window.extensions.area {
+
+ public interface ExtensionWindowAreaPresentation {
+ method public android.content.Context getPresentationContext();
+ method public void setPresentationView(android.view.View);
+ }
+
+ public interface ExtensionWindowAreaStatus {
+ method public android.util.DisplayMetrics getWindowAreaDisplayMetrics();
+ method public int getWindowAreaStatus();
+ }
+
+ public interface WindowAreaComponent {
+ method public void addRearDisplayPresentationStatusListener(androidx.window.extensions.core.util.function.Consumer<androidx.window.extensions.area.ExtensionWindowAreaStatus!>);
+ method public void addRearDisplayStatusListener(androidx.window.extensions.core.util.function.Consumer<java.lang.Integer!>);
+ method public void endRearDisplayPresentationSession();
+ method public void endRearDisplaySession();
+ method public androidx.window.extensions.area.ExtensionWindowAreaPresentation? getRearDisplayPresentation();
+ method public void removeRearDisplayPresentationStatusListener(androidx.window.extensions.core.util.function.Consumer<androidx.window.extensions.area.ExtensionWindowAreaStatus!>);
+ method public void removeRearDisplayStatusListener(androidx.window.extensions.core.util.function.Consumer<java.lang.Integer!>);
+ method public void startRearDisplayPresentationSession(android.app.Activity, androidx.window.extensions.core.util.function.Consumer<java.lang.Integer!>);
+ method public void startRearDisplaySession(android.app.Activity, androidx.window.extensions.core.util.function.Consumer<java.lang.Integer!>);
+ field public static final int SESSION_STATE_ACTIVE = 1; // 0x1
+ field public static final int SESSION_STATE_INACTIVE = 0; // 0x0
+ field public static final int SESSION_STATE_INVISIBLE = 3; // 0x3
+ field public static final int SESSION_STATE_VISIBLE = 2; // 0x2
+ field public static final int STATUS_AVAILABLE = 2; // 0x2
+ field public static final int STATUS_UNAVAILABLE = 1; // 0x1
+ field public static final int STATUS_UNSUPPORTED = 0; // 0x0
+ }
+
+}
+
package androidx.window.extensions.embedding {
public interface ActivityEmbeddingComponent {
method public void clearSplitAttributesCalculator();
method public void clearSplitInfoCallback();
+ method public void finishActivityStacks(java.util.Set<android.os.IBinder!>);
+ method public void invalidateTopVisibleSplitAttributes();
method public boolean isActivityEmbedded(android.app.Activity);
method public void setEmbeddingRules(java.util.Set<androidx.window.extensions.embedding.EmbeddingRule!>);
+ method public android.app.ActivityOptions setLaunchingActivityStack(android.app.ActivityOptions, android.os.IBinder);
method public void setSplitAttributesCalculator(androidx.window.extensions.core.util.function.Function<androidx.window.extensions.embedding.SplitAttributesCalculatorParams!,androidx.window.extensions.embedding.SplitAttributes!>);
method @Deprecated public void setSplitInfoCallback(java.util.function.Consumer<java.util.List<androidx.window.extensions.embedding.SplitInfo!>!>);
method public default void setSplitInfoCallback(androidx.window.extensions.core.util.function.Consumer<java.util.List<androidx.window.extensions.embedding.SplitInfo!>!>);
+ method public void updateSplitAttributes(android.os.IBinder, androidx.window.extensions.embedding.SplitAttributes);
}
public class ActivityRule extends androidx.window.extensions.embedding.EmbeddingRule {
@@ -52,6 +90,7 @@
method @ColorInt public int getAnimationBackgroundColor();
method public int getLayoutDirection();
method public androidx.window.extensions.embedding.SplitAttributes.SplitType getSplitType();
+ field @ColorInt public static final int DEFAULT_ANIMATION_BACKGROUND_COLOR = 0; // 0x0
}
public static final class SplitAttributes.Builder {
@@ -102,6 +141,7 @@
method public androidx.window.extensions.embedding.ActivityStack getSecondaryActivityStack();
method public androidx.window.extensions.embedding.SplitAttributes getSplitAttributes();
method @Deprecated public float getSplitRatio();
+ method public android.os.IBinder getToken();
}
public class SplitPairRule extends androidx.window.extensions.embedding.SplitRule {
diff --git a/window/extensions/extensions/api/restricted_current.txt b/window/extensions/extensions/api/restricted_current.txt
index f0c699b..7119193 100644
--- a/window/extensions/extensions/api/restricted_current.txt
+++ b/window/extensions/extensions/api/restricted_current.txt
@@ -4,6 +4,7 @@
public interface WindowExtensions {
method public default androidx.window.extensions.embedding.ActivityEmbeddingComponent? getActivityEmbeddingComponent();
method public default int getVendorApiLevel();
+ method public default androidx.window.extensions.area.WindowAreaComponent? getWindowAreaComponent();
method public androidx.window.extensions.layout.WindowLayoutComponent? getWindowLayoutComponent();
}
@@ -13,16 +14,53 @@
}
+package androidx.window.extensions.area {
+
+ public interface ExtensionWindowAreaPresentation {
+ method public android.content.Context getPresentationContext();
+ method public void setPresentationView(android.view.View);
+ }
+
+ public interface ExtensionWindowAreaStatus {
+ method public android.util.DisplayMetrics getWindowAreaDisplayMetrics();
+ method public int getWindowAreaStatus();
+ }
+
+ public interface WindowAreaComponent {
+ method public void addRearDisplayPresentationStatusListener(androidx.window.extensions.core.util.function.Consumer<androidx.window.extensions.area.ExtensionWindowAreaStatus!>);
+ method public void addRearDisplayStatusListener(androidx.window.extensions.core.util.function.Consumer<java.lang.Integer!>);
+ method public void endRearDisplayPresentationSession();
+ method public void endRearDisplaySession();
+ method public androidx.window.extensions.area.ExtensionWindowAreaPresentation? getRearDisplayPresentation();
+ method public void removeRearDisplayPresentationStatusListener(androidx.window.extensions.core.util.function.Consumer<androidx.window.extensions.area.ExtensionWindowAreaStatus!>);
+ method public void removeRearDisplayStatusListener(androidx.window.extensions.core.util.function.Consumer<java.lang.Integer!>);
+ method public void startRearDisplayPresentationSession(android.app.Activity, androidx.window.extensions.core.util.function.Consumer<java.lang.Integer!>);
+ method public void startRearDisplaySession(android.app.Activity, androidx.window.extensions.core.util.function.Consumer<java.lang.Integer!>);
+ field public static final int SESSION_STATE_ACTIVE = 1; // 0x1
+ field public static final int SESSION_STATE_INACTIVE = 0; // 0x0
+ field public static final int SESSION_STATE_INVISIBLE = 3; // 0x3
+ field public static final int SESSION_STATE_VISIBLE = 2; // 0x2
+ field public static final int STATUS_AVAILABLE = 2; // 0x2
+ field public static final int STATUS_UNAVAILABLE = 1; // 0x1
+ field public static final int STATUS_UNSUPPORTED = 0; // 0x0
+ }
+
+}
+
package androidx.window.extensions.embedding {
public interface ActivityEmbeddingComponent {
method public void clearSplitAttributesCalculator();
method public void clearSplitInfoCallback();
+ method public void finishActivityStacks(java.util.Set<android.os.IBinder!>);
+ method public void invalidateTopVisibleSplitAttributes();
method public boolean isActivityEmbedded(android.app.Activity);
method public void setEmbeddingRules(java.util.Set<androidx.window.extensions.embedding.EmbeddingRule!>);
+ method public android.app.ActivityOptions setLaunchingActivityStack(android.app.ActivityOptions, android.os.IBinder);
method public void setSplitAttributesCalculator(androidx.window.extensions.core.util.function.Function<androidx.window.extensions.embedding.SplitAttributesCalculatorParams!,androidx.window.extensions.embedding.SplitAttributes!>);
method @Deprecated public void setSplitInfoCallback(java.util.function.Consumer<java.util.List<androidx.window.extensions.embedding.SplitInfo!>!>);
method public default void setSplitInfoCallback(androidx.window.extensions.core.util.function.Consumer<java.util.List<androidx.window.extensions.embedding.SplitInfo!>!>);
+ method public void updateSplitAttributes(android.os.IBinder, androidx.window.extensions.embedding.SplitAttributes);
}
public class ActivityRule extends androidx.window.extensions.embedding.EmbeddingRule {
@@ -52,6 +90,7 @@
method @ColorInt public int getAnimationBackgroundColor();
method public int getLayoutDirection();
method public androidx.window.extensions.embedding.SplitAttributes.SplitType getSplitType();
+ field @ColorInt public static final int DEFAULT_ANIMATION_BACKGROUND_COLOR = 0; // 0x0
}
public static final class SplitAttributes.Builder {
@@ -102,6 +141,7 @@
method public androidx.window.extensions.embedding.ActivityStack getSecondaryActivityStack();
method public androidx.window.extensions.embedding.SplitAttributes getSplitAttributes();
method @Deprecated public float getSplitRatio();
+ method public android.os.IBinder getToken();
}
public class SplitPairRule extends androidx.window.extensions.embedding.SplitRule {
diff --git a/window/extensions/extensions/src/test/java/androidx/window/extensions/embedding/SplitAttributesTest.java b/window/extensions/extensions/src/androidTest/java/androidx/window/extensions/embedding/SplitAttributesTest.java
similarity index 93%
rename from window/extensions/extensions/src/test/java/androidx/window/extensions/embedding/SplitAttributesTest.java
rename to window/extensions/extensions/src/androidTest/java/androidx/window/extensions/embedding/SplitAttributesTest.java
index 76a1107..0bd4c63 100644
--- a/window/extensions/extensions/src/test/java/androidx/window/extensions/embedding/SplitAttributesTest.java
+++ b/window/extensions/extensions/src/androidTest/java/androidx/window/extensions/embedding/SplitAttributesTest.java
@@ -36,17 +36,17 @@
final SplitAttributes layout1 = new SplitAttributes.Builder()
.setSplitType(splitEqually())
.setLayoutDirection(LayoutDirection.LOCALE)
- .setAnimationBackgroundColor(0)
+ .setAnimationBackgroundColor(SplitAttributes.DEFAULT_ANIMATION_BACKGROUND_COLOR)
.build();
final SplitAttributes layout2 = new SplitAttributes.Builder()
.setSplitType(new SplitAttributes.SplitType.HingeSplitType(splitEqually()))
.setLayoutDirection(LayoutDirection.LOCALE)
- .setAnimationBackgroundColor(0)
+ .setAnimationBackgroundColor(SplitAttributes.DEFAULT_ANIMATION_BACKGROUND_COLOR)
.build();
final SplitAttributes layout3 = new SplitAttributes.Builder()
.setSplitType(new SplitAttributes.SplitType.HingeSplitType(splitEqually()))
.setLayoutDirection(LayoutDirection.TOP_TO_BOTTOM)
- .setAnimationBackgroundColor(0)
+ .setAnimationBackgroundColor(SplitAttributes.DEFAULT_ANIMATION_BACKGROUND_COLOR)
.build();
final SplitAttributes layout4 = new SplitAttributes.Builder()
.setSplitType(new SplitAttributes.SplitType.HingeSplitType(splitEqually()))
diff --git a/window/extensions/extensions/src/main/java/androidx/window/extensions/WindowExtensions.java b/window/extensions/extensions/src/main/java/androidx/window/extensions/WindowExtensions.java
index 97a1a86..447e5c1 100644
--- a/window/extensions/extensions/src/main/java/androidx/window/extensions/WindowExtensions.java
+++ b/window/extensions/extensions/src/main/java/androidx/window/extensions/WindowExtensions.java
@@ -18,11 +18,20 @@
import static androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP;
+import android.app.ActivityOptions;
+import android.os.IBinder;
+
import androidx.annotation.Nullable;
import androidx.annotation.RestrictTo;
+import androidx.window.extensions.area.WindowAreaComponent;
import androidx.window.extensions.embedding.ActivityEmbeddingComponent;
+import androidx.window.extensions.embedding.ActivityStack;
+import androidx.window.extensions.embedding.SplitAttributes;
+import androidx.window.extensions.embedding.SplitInfo;
import androidx.window.extensions.layout.WindowLayoutComponent;
+import java.util.Set;
+
/**
* A class to provide instances of different WindowManager Jetpack extension components. An OEM must
* implement all the availability methods to state which WindowManager Jetpack extension
@@ -55,12 +64,14 @@
* <li>{@link androidx.window.extensions.layout.FoldingFeature} APIs</li>
* <li>{@link androidx.window.extensions.layout.WindowLayoutInfo} APIs</li>
* <li>{@link androidx.window.extensions.layout.WindowLayoutComponent} APIs</li>
+ * <li>{@link androidx.window.extensions.area.WindowAreaComponent} APIs</li>
* </ul>
* </p>
* @hide
*/
@RestrictTo(LIBRARY_GROUP)
int VENDOR_API_LEVEL_1 = 1;
+
// TODO(b/241323716) Removed after we have annotation to check API level
/**
* A vendor API level constant. It helps to unify the format of documenting {@code @since}
@@ -77,6 +88,28 @@
@RestrictTo(LIBRARY_GROUP)
int VENDOR_API_LEVEL_2 = 2;
+ // TODO(b/241323716) Removed after we have annotation to check API level
+ /**
+ * A vendor API level constant. It helps to unify the format of documenting {@code @since}
+ * block.
+ * <p>
+ * The added APIs for Vendor API level 3 are:
+ * <ul>
+ * <li>{@link ActivityStack#getToken()}</li>
+ * <li>{@link SplitInfo#getToken()}</li>
+ * <li>{@link ActivityEmbeddingComponent#setLaunchingActivityStack(ActivityOptions,
+ * IBinder)}</li>
+ * <li>{@link ActivityEmbeddingComponent#invalidateTopVisibleSplitAttributes()}</li>
+ * <li>{@link ActivityEmbeddingComponent#updateSplitAttributes(IBinder, SplitAttributes)}
+ * </li>
+ * <li>{@link ActivityEmbeddingComponent#finishActivityStacks(Set)}</li>
+ * </ul>
+ * </p>
+ * @hide
+ */
+ @RestrictTo(LIBRARY_GROUP)
+ int VENDOR_API_LEVEL_3 = 3;
+
/**
* Returns the API level of the vendor library on the device. If the returned version is not
* supported by the WindowManager library, then some functions may not be available or replaced
@@ -109,4 +142,15 @@
default ActivityEmbeddingComponent getActivityEmbeddingComponent() {
return null;
}
+
+ /**
+ * Returns the OEM implementation of {@link WindowAreaComponent} if it is supported on
+ * the device, {@code null} otherwise. The implementation must match the API level reported in
+ * {@link WindowExtensions}.
+ * @return the OEM implementation of {@link WindowAreaComponent}
+ */
+ @Nullable
+ default WindowAreaComponent getWindowAreaComponent() {
+ return null;
+ }
}
diff --git a/window/extensions/extensions/src/main/java/androidx/window/extensions/area/ExtensionWindowAreaPresentation.java b/window/extensions/extensions/src/main/java/androidx/window/extensions/area/ExtensionWindowAreaPresentation.java
new file mode 100644
index 0000000..0ce24b8
--- /dev/null
+++ b/window/extensions/extensions/src/main/java/androidx/window/extensions/area/ExtensionWindowAreaPresentation.java
@@ -0,0 +1,44 @@
+/*
+ * Copyright 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.window.extensions.area;
+
+import android.content.Context;
+import android.view.View;
+
+import androidx.annotation.NonNull;
+
+/**
+ * An interface representing a container in an extension window area in which app content can be
+ * shown.
+ *
+ * Since {@link androidx.window.extensions.WindowExtensions#VENDOR_API_LEVEL_3}
+ * @see WindowAreaComponent#getRearDisplayPresentation()
+ */
+public interface ExtensionWindowAreaPresentation {
+
+ /**
+ * Returns the {@link Context} for the window that is being used
+ * to display the additional content provided from the application.
+ */
+ @NonNull
+ Context getPresentationContext();
+
+ /**
+ * Sets the {@link View} that the application wants to display in the extension window area.
+ */
+ void setPresentationView(@NonNull View view);
+}
diff --git a/window/extensions/extensions/src/main/java/androidx/window/extensions/area/ExtensionWindowAreaStatus.java b/window/extensions/extensions/src/main/java/androidx/window/extensions/area/ExtensionWindowAreaStatus.java
new file mode 100644
index 0000000..0dcd47f
--- /dev/null
+++ b/window/extensions/extensions/src/main/java/androidx/window/extensions/area/ExtensionWindowAreaStatus.java
@@ -0,0 +1,44 @@
+/*
+ * Copyright 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.window.extensions.area;
+
+import android.util.DisplayMetrics;
+
+import androidx.annotation.NonNull;
+
+/**
+ * Interface to provide information around the current status of a window area feature.
+ *
+ * Since {@link androidx.window.extensions.WindowExtensions#VENDOR_API_LEVEL_3}
+ * @see WindowAreaComponent#addRearDisplayPresentationStatusListener
+ */
+public interface ExtensionWindowAreaStatus {
+
+ /**
+ * Returns the {@link androidx.window.extensions.area.WindowAreaComponent.WindowAreaStatus}
+ * value that relates to the current status of a feature.
+ */
+ @WindowAreaComponent.WindowAreaStatus
+ int getWindowAreaStatus();
+
+ /**
+ * Returns the {@link DisplayMetrics} that corresponds to the window area that a feature
+ * interacts with. This is converted to size class information provided to developers.
+ */
+ @NonNull
+ DisplayMetrics getWindowAreaDisplayMetrics();
+}
diff --git a/window/extensions/extensions/src/main/java/androidx/window/extensions/area/WindowAreaComponent.java b/window/extensions/extensions/src/main/java/androidx/window/extensions/area/WindowAreaComponent.java
new file mode 100644
index 0000000..93d5397
--- /dev/null
+++ b/window/extensions/extensions/src/main/java/androidx/window/extensions/area/WindowAreaComponent.java
@@ -0,0 +1,315 @@
+/*
+ * Copyright 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.window.extensions.area;
+
+import android.annotation.SuppressLint;
+import android.app.Activity;
+import android.os.Build;
+import android.util.ArrayMap;
+
+import androidx.annotation.IntDef;
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+import androidx.annotation.RequiresApi;
+import androidx.annotation.RestrictTo;
+import androidx.window.extensions.WindowExtensions;
+import androidx.window.extensions.core.util.function.Consumer;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/**
+ * The interface definition that will be used by the WindowManager library to get custom
+ * OEM-provided behavior around moving windows between displays or display areas on a device.
+ *
+ * Currently the only behavior supported is RearDisplay Mode, where the window
+ * is moved to the display that faces the same direction as the rear camera.
+ *
+ * <p>This interface should be implemented by OEM and deployed to the target devices.
+ * @see WindowExtensions#getWindowLayoutComponent()
+ */
+public interface WindowAreaComponent {
+
+ /**
+ * WindowArea status constant to signify that the feature is
+ * unsupported on this device. Could be due to the device not supporting that
+ * specific feature.
+ */
+ int STATUS_UNSUPPORTED = 0;
+
+ /**
+ * WindowArea status constant to signify that the feature is
+ * currently unavailable but is supported on this device. This value could signify
+ * that the current device state does not support the specific feature or another
+ * process is currently enabled in that feature.
+ */
+ int STATUS_UNAVAILABLE = 1;
+
+ /**
+ * WindowArea status constant to signify that the feature is
+ * available to be entered or enabled.
+ */
+ int STATUS_AVAILABLE = 2;
+
+ /** @hide */
+ @RestrictTo(RestrictTo.Scope.LIBRARY)
+ @Retention(RetentionPolicy.SOURCE)
+ @Target({ElementType.TYPE_PARAMETER, ElementType.TYPE_USE})
+ @IntDef({
+ STATUS_UNSUPPORTED,
+ STATUS_UNAVAILABLE,
+ STATUS_AVAILABLE
+ })
+ @interface WindowAreaStatus {}
+
+ /**
+ * Session state constant to represent there being no active session
+ * currently in progress. Used by the library to call the correct callbacks if
+ * a session is ended.
+ */
+ int SESSION_STATE_INACTIVE = 0;
+
+ /**
+ * Session state constant to represent that there is an
+ * active session currently in progress. Used by the library to
+ * know when to return the session object to the developer when the
+ * session is created and active.
+ */
+ int SESSION_STATE_ACTIVE = 1;
+
+ /**
+ * Session state constant to represent that there is an
+ * active session currently in progress, and the content provided by the application
+ * is visible.
+ */
+ int SESSION_STATE_VISIBLE = 2;
+
+ /**
+ * Session state constant to represent that there is an
+ * active session currently in progress, but the content provided by the application
+ * is no longer visible.
+ */
+ int SESSION_STATE_INVISIBLE = 3;
+
+ /** @hide */
+ @RestrictTo(RestrictTo.Scope.LIBRARY)
+ @Retention(RetentionPolicy.SOURCE)
+ @Target({ElementType.TYPE_PARAMETER, ElementType.TYPE_USE})
+ @IntDef({
+ SESSION_STATE_ACTIVE,
+ SESSION_STATE_INACTIVE,
+ SESSION_STATE_VISIBLE,
+ SESSION_STATE_INVISIBLE
+ })
+ @interface WindowAreaSessionState {}
+
+ // TODO(b/264546746): Remove deprecated Window Extensions APIs after apps in g3 is updated to
+ // the latest library.
+ /** @hide */
+ @SuppressLint({"NewApi", "ClassVerificationFailure"})
+ @RestrictTo(RestrictTo.Scope.LIBRARY)
+ ArrayMap<java.util.function.Consumer<Integer>, Consumer<Integer>> JAVA_TO_EXTENSIONS_MAP =
+ new ArrayMap<>();
+
+ /**
+ * Adds a listener interested in receiving updates on the RearDisplayStatus
+ * of the device. Because this is being called from the OEM provided
+ * extensions, the library will post the result of the listener on the executor
+ * provided by the developer.
+ *
+ * The listener provided will receive values that
+ * correspond to the [WindowAreaStatus] value that aligns with the current status
+ * of the rear display.
+ * @param consumer interested in receiving updates to WindowAreaStatus.
+ * Since {@link WindowExtensions#VENDOR_API_LEVEL_2}
+ */
+ void addRearDisplayStatusListener(@NonNull Consumer<Integer> consumer);
+
+ // TODO(b/264546746): Remove deprecated Window Extensions APIs after apps in g3 is updated to
+ // the latest library.
+ /**
+ * @deprecated Use {@link #addRearDisplayStatusListener(Consumer)}.
+ *
+ * Since {@link WindowExtensions#VENDOR_API_LEVEL_2}
+ * @hide
+ */
+ @Deprecated
+ @SuppressLint("ClassVerificationFailure")
+ @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
+ @RequiresApi(api = Build.VERSION_CODES.N)
+ default void addRearDisplayStatusListener(
+ @NonNull java.util.function.Consumer<Integer> consumer) {
+ if (JAVA_TO_EXTENSIONS_MAP.containsKey(consumer)) {
+ return;
+ }
+ final Consumer<Integer> extensionsConsumer = consumer::accept;
+ JAVA_TO_EXTENSIONS_MAP.put(consumer, extensionsConsumer);
+ addRearDisplayStatusListener(extensionsConsumer);
+ }
+
+ /**
+ * Removes a listener no longer interested in receiving updates.
+ * @param consumer no longer interested in receiving updates to WindowAreaStatus
+ * Since {@link WindowExtensions#VENDOR_API_LEVEL_2}
+ */
+ void removeRearDisplayStatusListener(@NonNull Consumer<Integer> consumer);
+
+ // TODO(b/264546746): Remove deprecated Window Extensions APIs after apps in g3 is updated to
+ // the latest library.
+ /**
+ * @deprecated Use {@link #removeRearDisplayStatusListener(Consumer)}.
+ *
+ * Since {@link WindowExtensions#VENDOR_API_LEVEL_2}
+ * @hide
+ */
+ @Deprecated
+ @SuppressLint("ClassVerificationFailure")
+ @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
+ @RequiresApi(api = Build.VERSION_CODES.N)
+ default void removeRearDisplayStatusListener(
+ @NonNull java.util.function.Consumer<Integer> consumer) {
+ if (!JAVA_TO_EXTENSIONS_MAP.containsKey(consumer)) {
+ return;
+ }
+ final Consumer<Integer> extensionsConsumer = JAVA_TO_EXTENSIONS_MAP.remove(consumer);
+ removeRearDisplayStatusListener(extensionsConsumer);
+ }
+
+ /**
+ * Creates and starts a rear display session and sends state updates to the
+ * consumer provided. This consumer will receive a constant represented by
+ * [WindowAreaSessionState] to represent the state of the current rear display
+ * session. We will translate to a more friendly interface in the library.
+ *
+ * Because this is being called from the OEM provided extensions, the library
+ * will post the result of the listener on the executor provided by the developer.
+ *
+ * @param activity to allow that the OEM implementation will use as a base
+ * context and to identify the source display area of the request.
+ * The reference to the activity instance must not be stored in the OEM
+ * implementation to prevent memory leaks.
+ * @param consumer to provide updates to the client on the status of the session
+ * @throws UnsupportedOperationException if this method is called when RearDisplay
+ * mode is not available. This could be to an incompatible device state or when
+ * another process is currently in this mode.
+ * Since {@link WindowExtensions#VENDOR_API_LEVEL_2}
+ */
+ @SuppressWarnings("ExecutorRegistration") // Jetpack will post it on the app-provided executor.
+ void startRearDisplaySession(@NonNull Activity activity,
+ @NonNull Consumer<@WindowAreaSessionState Integer> consumer);
+
+ // TODO(b/264546746): Remove deprecated Window Extensions APIs after apps in g3 is updated to
+ // the latest library.
+ /**
+ * @deprecated Use {@link #startRearDisplaySession(Activity, Consumer)}.
+ *
+ * Since {@link WindowExtensions#VENDOR_API_LEVEL_2}
+ * @hide
+ */
+ @Deprecated
+ @SuppressLint("ClassVerificationFailure")
+ @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
+ @RequiresApi(api = Build.VERSION_CODES.N)
+ default void startRearDisplaySession(@NonNull Activity activity,
+ @NonNull java.util.function.Consumer<@WindowAreaSessionState Integer> consumer) {
+ final Consumer<Integer> extensionsConsumer = consumer::accept;
+ startRearDisplaySession(activity, extensionsConsumer);
+ }
+
+ /**
+ * Ends a RearDisplaySession and sends [STATE_INACTIVE] to the consumer
+ * provided in the {@code startRearDisplaySession} method. This method is only
+ * called through the {@code RearDisplaySession} provided to the developer.
+ * Since {@link WindowExtensions#VENDOR_API_LEVEL_2}
+ */
+ void endRearDisplaySession();
+
+ /**
+ * Adds a listener interested in receiving updates on the rear display presentation status
+ * of the device. Because this is being called from the OEM provided
+ * extensions, the library will post the result of the listener on the executor
+ * provided by the developer.
+ *
+ * The listener provided will receive {@link ExtensionWindowAreaStatus} values that
+ * correspond to the current status of the feature.
+ *
+ * @param consumer interested in receiving updates to {@link ExtensionWindowAreaStatus}.
+ * Since {@link WindowExtensions#VENDOR_API_LEVEL_3}
+ */
+ void addRearDisplayPresentationStatusListener(
+ @NonNull Consumer<ExtensionWindowAreaStatus> consumer);
+
+ /**
+ * Removes a listener no longer interested in receiving updates.
+ *
+ * @param consumer no longer interested in receiving updates to WindowAreaStatus
+ * Since {@link WindowExtensions#VENDOR_API_LEVEL_3}
+ */
+ void removeRearDisplayPresentationStatusListener(
+ @NonNull Consumer<ExtensionWindowAreaStatus> consumer);
+
+ /**
+ * Creates and starts a rear display presentation session and sends state updates to the
+ * consumer provided. This consumer will receive a constant represented by
+ * {@link WindowAreaSessionState} to represent the state of the current rear display
+ * session. We will translate to a more friendly interface in the library.
+ *
+ * Because this is being called from the OEM provided extensions, the library
+ * will post the result of the listener on the executor provided by the developer.
+ *
+ * Rear display presentation mode refers to a feature where an {@link Activity} can present
+ * additional content on a device with a second display that is facing the same direction
+ * as the rear camera (i.e. the cover display on a fold-in style device). The calling
+ * {@link Activity} stays on the user-facing display.
+ *
+ * @param activity that the OEM implementation will use as a base
+ * context and to identify the source display area of the request.
+ * The reference to the activity instance must not be stored in the OEM
+ * implementation to prevent memory leaks.
+ * @param consumer to provide updates to the client on the status of the session
+ * @throws UnsupportedOperationException if this method is called when rear display presentation
+ * mode is not available. This could be to an incompatible device state or when
+ * another process is currently in this mode.
+ * Since {@link WindowExtensions#VENDOR_API_LEVEL_3}
+ */
+ void startRearDisplayPresentationSession(@NonNull Activity activity,
+ @NonNull Consumer<@WindowAreaSessionState Integer> consumer);
+
+ /**
+ * Ends the current rear display presentation session and provides updates to the
+ * callback provided. When this is ended, the presented content from the calling
+ * {@link Activity} will also be removed from the rear facing display.
+ * Because this is being called from the OEM provided extensions, the result of the listener
+ * will be posted on the executor provided by the developer at the initial call site.
+ *
+ * Since {@link WindowExtensions#VENDOR_API_LEVEL_3}
+ */
+ void endRearDisplayPresentationSession();
+
+ /**
+ * Returns the {@link ExtensionWindowAreaPresentation} connected to the active
+ * rear display presentation session. If there is no session currently active, then it will
+ * return null.
+ *
+ * Since {@link WindowExtensions#VENDOR_API_LEVEL_3}
+ */
+ @Nullable
+ ExtensionWindowAreaPresentation getRearDisplayPresentation();
+
+}
diff --git a/window/extensions/extensions/src/main/java/androidx/window/extensions/embedding/ActivityEmbeddingComponent.java b/window/extensions/extensions/src/main/java/androidx/window/extensions/embedding/ActivityEmbeddingComponent.java
index bdca977..2a600af 100644
--- a/window/extensions/extensions/src/main/java/androidx/window/extensions/embedding/ActivityEmbeddingComponent.java
+++ b/window/extensions/extensions/src/main/java/androidx/window/extensions/embedding/ActivityEmbeddingComponent.java
@@ -17,9 +17,12 @@
package androidx.window.extensions.embedding;
import android.app.Activity;
+import android.app.ActivityOptions;
+import android.os.IBinder;
import android.view.WindowMetrics;
import androidx.annotation.NonNull;
+import androidx.annotation.RestrictTo;
import androidx.window.extensions.WindowExtensions;
import androidx.window.extensions.core.util.function.Consumer;
import androidx.window.extensions.core.util.function.Function;
@@ -117,6 +120,33 @@
void setSplitAttributesCalculator(
@NonNull Function<SplitAttributesCalculatorParams, SplitAttributes> calculator);
+ // TODO(b/264546746): Remove deprecated Window Extensions APIs after apps in g3 is updated to
+ // the latest library.
+ /**
+ * @deprecated Use {@link #setSplitAttributesCalculator(Function)}.
+ *
+ * Since {@link WindowExtensions#VENDOR_API_LEVEL_2}
+ * @hide
+ */
+ @Deprecated
+ @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
+ default void setSplitAttributesCalculator(@NonNull SplitAttributesCalculator calculator) {
+ final Function<SplitAttributesCalculatorParams, SplitAttributes> function =
+ params -> {
+ SplitAttributesCalculator.SplitAttributesCalculatorParams legacyParams =
+ new SplitAttributesCalculator.SplitAttributesCalculatorParams(
+ params.getParentWindowMetrics(),
+ params.getParentConfiguration(),
+ params.getDefaultSplitAttributes(),
+ params.areDefaultConstraintsSatisfied(),
+ params.getParentWindowLayoutInfo(),
+ params.getSplitRuleTag()
+ );
+ return calculator.computeSplitAttributesForParams(legacyParams);
+ };
+ setSplitAttributesCalculator(function);
+ }
+
/**
* Clears the previously callback set in {@link #setSplitAttributesCalculator(Function)}.
*
@@ -124,4 +154,48 @@
* Since {@link WindowExtensions#VENDOR_API_LEVEL_2}
*/
void clearSplitAttributesCalculator();
+
+ /**
+ * Sets the launching {@link ActivityStack} to the given {@link ActivityOptions}.
+ *
+ * @param options The {@link ActivityOptions} to be updated.
+ * @param token The {@link ActivityStack#getToken()} to represent the {@link ActivityStack}
+ * Since {@link WindowExtensions#VENDOR_API_LEVEL_3}
+ */
+ @NonNull
+ ActivityOptions setLaunchingActivityStack(@NonNull ActivityOptions options,
+ @NonNull IBinder token);
+
+ /**
+ * Finishes a set of {@link ActivityStack}s. When an {@link ActivityStack} that was in an active
+ * split is finished, the other {@link ActivityStack} in the same {@link SplitInfo} can be
+ * expanded to fill the parent task container.
+ *
+ * @param activityStackTokens The set of tokens of {@link ActivityStack}-s that is going to be
+ * finished.
+ * Since {@link WindowExtensions#VENDOR_API_LEVEL_3}
+ */
+ void finishActivityStacks(@NonNull Set<IBinder> activityStackTokens);
+
+ /**
+ * Triggers an update of the split attributes for the top split if there is one visible by
+ * making extensions invoke the split attributes calculator callback. This method can be used
+ * when a change to the split presentation originates from the application state change rather
+ * than driven by parent window changes or new activity starts. The call will be ignored if
+ * there is no visible split.
+ * @see #setSplitAttributesCalculator(Function)
+ * Since {@link WindowExtensions#VENDOR_API_LEVEL_3}
+ */
+ void invalidateTopVisibleSplitAttributes();
+
+ /**
+ * Updates the {@link SplitAttributes} of a split pair. This is an alternative to using
+ * a split attributes calculator callback, applicable when apps only need to update the
+ * splits in a few cases but rely on the default split attributes otherwise.
+ * @param splitInfoToken The identifier of the split pair to update.
+ * @param splitAttributes The {@link SplitAttributes} to apply to the split pair.
+ * Since {@link WindowExtensions#VENDOR_API_LEVEL_3}
+ */
+ void updateSplitAttributes(@NonNull IBinder splitInfoToken,
+ @NonNull SplitAttributes splitAttributes);
}
diff --git a/window/extensions/extensions/src/main/java/androidx/window/extensions/embedding/ActivityStack.java b/window/extensions/extensions/src/main/java/androidx/window/extensions/embedding/ActivityStack.java
index 857738d..e568666 100644
--- a/window/extensions/extensions/src/main/java/androidx/window/extensions/embedding/ActivityStack.java
+++ b/window/extensions/extensions/src/main/java/androidx/window/extensions/embedding/ActivityStack.java
@@ -17,8 +17,12 @@
package androidx.window.extensions.embedding;
import android.app.Activity;
+import android.os.Binder;
+import android.os.IBinder;
import androidx.annotation.NonNull;
+import androidx.annotation.RestrictTo;
+import androidx.window.extensions.WindowExtensions;
import java.util.ArrayList;
import java.util.List;
@@ -30,11 +34,17 @@
*/
public class ActivityStack {
+ /** Only used for compatibility with the deprecated constructor. */
+ private static final IBinder INVALID_ACTIVITY_STACK_TOKEN = new Binder();
+
@NonNull
private final List<Activity> mActivities;
private final boolean mIsEmpty;
+ @NonNull
+ private final IBinder mToken;
+
/**
* The {@code ActivityStack} constructor
*
@@ -42,11 +52,24 @@
* belongs to this {@code ActivityStack}
* @param isEmpty Indicates whether there's any {@link Activity} running in this
* {@code ActivityStack}
+ * @param token The token to identify this {@code ActivityStack}
+ * Since {@link WindowExtensions#VENDOR_API_LEVEL_3}
*/
- ActivityStack(@NonNull List<Activity> activities, boolean isEmpty) {
+ ActivityStack(@NonNull List<Activity> activities, boolean isEmpty, @NonNull IBinder token) {
Objects.requireNonNull(activities);
+ Objects.requireNonNull(token);
mActivities = new ArrayList<>(activities);
mIsEmpty = isEmpty;
+ mToken = token;
+ }
+
+ /**
+ * @deprecated Use the {@link WindowExtensions#VENDOR_API_LEVEL_3} version.
+ * Since {@link WindowExtensions#VENDOR_API_LEVEL_1}
+ */
+ @Deprecated
+ ActivityStack(@NonNull List<Activity> activities, boolean isEmpty) {
+ this(activities, isEmpty, INVALID_ACTIVITY_STACK_TOKEN);
}
/**
@@ -76,19 +99,31 @@
return mIsEmpty;
}
+ /**
+ * Returns a token uniquely identifying the container.
+ * Since {@link WindowExtensions#VENDOR_API_LEVEL_3}
+ */
+ @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
+ @NonNull
+ public IBinder getToken() {
+ return mToken;
+ }
+
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (!(o instanceof ActivityStack)) return false;
ActivityStack that = (ActivityStack) o;
return mActivities.equals(that.mActivities)
- && mIsEmpty == that.mIsEmpty;
+ && mIsEmpty == that.mIsEmpty
+ && mToken.equals(that.mToken);
}
@Override
public int hashCode() {
int result = (mIsEmpty ? 1 : 0);
result = result * 31 + mActivities.hashCode();
+ result = result * 31 + mToken.hashCode();
return result;
}
@@ -97,6 +132,7 @@
public String toString() {
return "ActivityStack{" + "mActivities=" + mActivities
+ ", mIsEmpty=" + mIsEmpty
+ + ", mToken=" + mToken
+ '}';
}
}
diff --git a/window/extensions/extensions/src/main/java/androidx/window/extensions/embedding/SplitAttributes.java b/window/extensions/extensions/src/main/java/androidx/window/extensions/embedding/SplitAttributes.java
index 59f8a02..e4f1e81 100644
--- a/window/extensions/extensions/src/main/java/androidx/window/extensions/embedding/SplitAttributes.java
+++ b/window/extensions/extensions/src/main/java/androidx/window/extensions/embedding/SplitAttributes.java
@@ -23,6 +23,7 @@
import static androidx.window.extensions.embedding.SplitAttributes.LayoutDirection.TOP_TO_BOTTOM;
import android.annotation.SuppressLint;
+import android.graphics.Color;
import androidx.annotation.ColorInt;
import androidx.annotation.FloatRange;
@@ -66,6 +67,19 @@
* Since {@link androidx.window.extensions.WindowExtensions#VENDOR_API_LEVEL_2}
*/
public class SplitAttributes {
+
+ /**
+ * The default value for animation background color, which means to use the current theme window
+ * background color.
+ *
+ * Only opaque color is supported, so {@code 0} is used as the default. Any other non-opaque
+ * color will be treated as the default.
+ *
+ * @see Builder#setAnimationBackgroundColor(int)
+ */
+ @ColorInt
+ public static final int DEFAULT_ANIMATION_BACKGROUND_COLOR = 0;
+
/**
* The type of window split, which defines the proportion of the parent
* window occupied by the primary and secondary activity containers.
@@ -413,6 +427,9 @@
* Gets the {@link ColorInt} to use for the background color during the
* animation of the split involving this {@code SplitAttributes} object.
*
+ * The default is {@link #DEFAULT_ANIMATION_BACKGROUND_COLOR}, which means
+ * to use the current theme window background color.
+ *
* @return The animation background {@code ColorInt}.
*/
@ColorInt
@@ -423,10 +440,9 @@
/**
* Builder for creating an instance of {@link SplitAttributes}.
*
- * The default split type is an equal split between primary and secondary
- * containers. The default layout direction is based on locale. The default
- * animation background color is 0, which specifies the theme window
- * background color.
+ * - The default split type is an equal split between primary and secondary containers.
+ * - The default layout direction is based on locale.
+ * - The default animation background color is to use the current theme window background color.
*/
public static final class Builder {
@NonNull
@@ -481,16 +497,23 @@
* animation of the split involving this {@code SplitAttributes} object
* if the animation requires a background.
*
- * The default value is 0, which specifies the theme window background
- * color.
+ * Only opaque color is supported.
+ *
+ * The default value is {@link #DEFAULT_ANIMATION_BACKGROUND_COLOR}, which
+ * means to use the current theme window background color. Any non-opaque
+ * animation color will be treated as
+ * {@link #DEFAULT_ANIMATION_BACKGROUND_COLOR}.
*
* @param color A packed color int of the form {@code AARRGGBB} for the
- * animation background color.
+ * animation background color.
* @return This {@code Builder}.
*/
@NonNull
public Builder setAnimationBackgroundColor(@ColorInt int color) {
- mAnimationBackgroundColor = color;
+ // Any non-opaque color will be treated as the default.
+ mAnimationBackgroundColor = Color.alpha(color) != 255
+ ? DEFAULT_ANIMATION_BACKGROUND_COLOR
+ : color;
return this;
}
diff --git a/window/extensions/extensions/src/main/java/androidx/window/extensions/embedding/SplitAttributesCalculator.java b/window/extensions/extensions/src/main/java/androidx/window/extensions/embedding/SplitAttributesCalculator.java
new file mode 100644
index 0000000..b06fefa
--- /dev/null
+++ b/window/extensions/extensions/src/main/java/androidx/window/extensions/embedding/SplitAttributesCalculator.java
@@ -0,0 +1,166 @@
+/*
+ * Copyright 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.window.extensions.embedding;
+
+import android.content.res.Configuration;
+import android.os.Build;
+import android.view.WindowMetrics;
+
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+import androidx.annotation.RequiresApi;
+import androidx.annotation.RestrictTo;
+import androidx.window.extensions.layout.WindowLayoutInfo;
+
+// TODO(b/264546746): Remove deprecated Window Extensions APIs after apps in g3 is updated to the
+// latest library.
+/**
+ * @deprecated Use {@link androidx.window.extensions.core.util.function.Function} instead unless
+ * {@link androidx.window.extensions.core.util.function.Function} cannot be used.
+ *
+ * @hide
+ */
+@Deprecated
+@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
+public interface SplitAttributesCalculator {
+ /** @deprecated See {@link SplitAttributesCalculator}. */
+ @Deprecated
+ @NonNull
+ SplitAttributes computeSplitAttributesForParams(
+ @NonNull SplitAttributesCalculatorParams params);
+
+ /**
+ * @deprecated Use
+ * {@link androidx.window.extensions.embedding.SplitAttributesCalculatorParams} unless
+ * {@link androidx.window.extensions.embedding.SplitAttributesCalculatorParams} cannot be used.
+ */
+ @Deprecated
+ class SplitAttributesCalculatorParams {
+ @NonNull
+ private final WindowMetrics mParentWindowMetrics;
+ @NonNull
+ private final Configuration mParentConfiguration;
+ @NonNull
+ private final WindowLayoutInfo mParentWindowLayoutInfo;
+ @NonNull
+ private final SplitAttributes mDefaultSplitAttributes;
+ private final boolean mIsDefaultMinSizeSatisfied;
+ @Nullable
+ private final String mSplitRuleTag;
+
+ /** Returns the parent container's {@link WindowMetrics} */
+ @NonNull
+ public WindowMetrics getParentWindowMetrics() {
+ return mParentWindowMetrics;
+ }
+
+ /** Returns the parent container's {@link Configuration} */
+ @NonNull
+ public Configuration getParentConfiguration() {
+ return new Configuration(mParentConfiguration);
+ }
+
+ /**
+ * Returns the {@link SplitRule#getDefaultSplitAttributes()}. It could be from
+ * {@link SplitRule} Builder APIs
+ * ({@link SplitPairRule.Builder#setDefaultSplitAttributes(SplitAttributes)} or
+ * {@link SplitPlaceholderRule.Builder#setDefaultSplitAttributes(SplitAttributes)}) or from
+ * the {@code splitRatio} and {@code splitLayoutDirection} attributes from static rule
+ * definitions.
+ */
+ @NonNull
+ public SplitAttributes getDefaultSplitAttributes() {
+ return mDefaultSplitAttributes;
+ }
+
+ /**
+ * Returns whether the {@link #getParentWindowMetrics()} satisfies the dimensions and aspect
+ * ratios requirements specified in the {@link androidx.window.embedding.SplitRule}, which
+ * are:
+ * - {@link androidx.window.embedding.SplitRule#minWidthDp}
+ * - {@link androidx.window.embedding.SplitRule#minHeightDp}
+ * - {@link androidx.window.embedding.SplitRule#minSmallestWidthDp}
+ * - {@link androidx.window.embedding.SplitRule#maxAspectRatioInPortrait}
+ * - {@link androidx.window.embedding.SplitRule#maxAspectRatioInLandscape}
+ */
+ public boolean isDefaultMinSizeSatisfied() {
+ return mIsDefaultMinSizeSatisfied;
+ }
+
+ /** Returns the parent container's {@link WindowLayoutInfo} */
+ @NonNull
+ public WindowLayoutInfo getParentWindowLayoutInfo() {
+ return mParentWindowLayoutInfo;
+ }
+
+ /**
+ * Returns {@link SplitRule#getTag()} to apply the {@link SplitAttributes} result if it was
+ * set.
+ */
+ @Nullable
+ public String getSplitRuleTag() {
+ return mSplitRuleTag;
+ }
+
+ SplitAttributesCalculatorParams(
+ @NonNull WindowMetrics parentWindowMetrics,
+ @NonNull Configuration parentConfiguration,
+ @NonNull SplitAttributes defaultSplitAttributes,
+ boolean isDefaultMinSizeSatisfied,
+ @NonNull WindowLayoutInfo parentWindowLayoutInfo,
+ @Nullable String splitRuleTag
+ ) {
+ mParentWindowMetrics = parentWindowMetrics;
+ mParentConfiguration = parentConfiguration;
+ mParentWindowLayoutInfo = parentWindowLayoutInfo;
+ mDefaultSplitAttributes = defaultSplitAttributes;
+ mIsDefaultMinSizeSatisfied = isDefaultMinSizeSatisfied;
+ mSplitRuleTag = splitRuleTag;
+ }
+
+ @NonNull
+ @Override
+ public String toString() {
+ return getClass().getSimpleName() + ":{"
+ + "windowMetrics=" + windowMetricsToString(mParentWindowMetrics)
+ + ", configuration=" + mParentConfiguration
+ + ", windowLayoutInfo=" + mParentWindowLayoutInfo
+ + ", defaultSplitAttributes=" + mDefaultSplitAttributes
+ + ", isDefaultMinSizeSatisfied=" + mIsDefaultMinSizeSatisfied
+ + ", tag=" + mSplitRuleTag + "}";
+ }
+
+ private static String windowMetricsToString(@NonNull WindowMetrics windowMetrics) {
+ // TODO(b/187712731): Use WindowMetrics#toString after it's implemented in U.
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
+ return Api30Impl.windowMetricsToString(
+ windowMetrics);
+ }
+ throw new UnsupportedOperationException("WindowMetrics didn't exist in R.");
+ }
+
+ @RequiresApi(30)
+ private static final class Api30Impl {
+ static String windowMetricsToString(@NonNull WindowMetrics windowMetrics) {
+ return WindowMetrics.class.getSimpleName() + ":{"
+ + "bounds=" + windowMetrics.getBounds()
+ + ", windowInsets=" + windowMetrics.getWindowInsets()
+ + "}";
+ }
+ }
+ }
+}
diff --git a/window/extensions/extensions/src/main/java/androidx/window/extensions/embedding/SplitInfo.java b/window/extensions/extensions/src/main/java/androidx/window/extensions/embedding/SplitInfo.java
index 717039b..bac42a4 100644
--- a/window/extensions/extensions/src/main/java/androidx/window/extensions/embedding/SplitInfo.java
+++ b/window/extensions/extensions/src/main/java/androidx/window/extensions/embedding/SplitInfo.java
@@ -16,6 +16,9 @@
package androidx.window.extensions.embedding;
+import android.os.Binder;
+import android.os.IBinder;
+
import androidx.annotation.NonNull;
import androidx.window.extensions.WindowExtensions;
import androidx.window.extensions.embedding.SplitAttributes.SplitType;
@@ -24,6 +27,10 @@
/** Describes a split of two containers with activities. */
public class SplitInfo {
+
+ /** Only used for compatibility with the deprecated constructor. */
+ private static final IBinder INVALID_SPLIT_INFO_TOKEN = new Binder();
+
@NonNull
private final ActivityStack mPrimaryActivityStack;
@NonNull
@@ -31,22 +38,42 @@
@NonNull
private final SplitAttributes mSplitAttributes;
+ @NonNull
+ private final IBinder mToken;
+
/**
- * The {@code SplitInfo} constructor.
+ * The {@code SplitInfo} constructor
*
- * @param primaryActivityStack The primary {@link ActivityStack}.
- * @param secondaryActivityStack The secondary {@link ActivityStack}.
- * @param splitAttributes The current {@link SplitAttributes} of this split pair.
+ * @param primaryActivityStack The primary {@link ActivityStack}
+ * @param secondaryActivityStack The secondary {@link ActivityStack}
+ * @param splitAttributes The current {@link SplitAttributes} of this split pair
+ * @param token The token to identify this split pair
+ * Since {@link WindowExtensions#VENDOR_API_LEVEL_3}
*/
SplitInfo(@NonNull ActivityStack primaryActivityStack,
@NonNull ActivityStack secondaryActivityStack,
- @NonNull SplitAttributes splitAttributes) {
+ @NonNull SplitAttributes splitAttributes,
+ @NonNull IBinder token) {
Objects.requireNonNull(primaryActivityStack);
Objects.requireNonNull(secondaryActivityStack);
Objects.requireNonNull(splitAttributes);
+ Objects.requireNonNull(token);
mPrimaryActivityStack = primaryActivityStack;
mSecondaryActivityStack = secondaryActivityStack;
mSplitAttributes = splitAttributes;
+ mToken = token;
+ }
+
+ /**
+ * @deprecated Use the {@link WindowExtensions#VENDOR_API_LEVEL_3} version.
+ * Since {@link WindowExtensions#VENDOR_API_LEVEL_1}
+ */
+ @Deprecated
+ SplitInfo(@NonNull ActivityStack primaryActivityStack,
+ @NonNull ActivityStack secondaryActivityStack,
+ @NonNull SplitAttributes splitAttributes) {
+ this(primaryActivityStack, secondaryActivityStack, splitAttributes,
+ INVALID_SPLIT_INFO_TOKEN);
}
@NonNull
@@ -83,6 +110,15 @@
return mSplitAttributes;
}
+ /**
+ * Returns a token uniquely identifying the container.
+ * Since {@link WindowExtensions#VENDOR_API_LEVEL_3}
+ */
+ @NonNull
+ public IBinder getToken() {
+ return mToken;
+ }
+
@Override
public boolean equals(Object o) {
if (this == o) return true;
@@ -90,7 +126,7 @@
SplitInfo that = (SplitInfo) o;
return mSplitAttributes.equals(that.mSplitAttributes) && mPrimaryActivityStack.equals(
that.mPrimaryActivityStack) && mSecondaryActivityStack.equals(
- that.mSecondaryActivityStack);
+ that.mSecondaryActivityStack) && mToken.equals(that.mToken);
}
@Override
@@ -98,6 +134,7 @@
int result = mPrimaryActivityStack.hashCode();
result = result * 31 + mSecondaryActivityStack.hashCode();
result = result * 31 + mSplitAttributes.hashCode();
+ result = result * 31 + mToken.hashCode();
return result;
}
@@ -108,6 +145,7 @@
+ "mPrimaryActivityStack=" + mPrimaryActivityStack
+ ", mSecondaryActivityStack=" + mSecondaryActivityStack
+ ", mSplitAttributes=" + mSplitAttributes
+ + ", mToken=" + mToken
+ '}';
}
}
diff --git a/window/extensions/extensions/src/main/java/androidx/window/extensions/layout/WindowLayoutComponent.java b/window/extensions/extensions/src/main/java/androidx/window/extensions/layout/WindowLayoutComponent.java
index 5573abb..9ed7d17 100644
--- a/window/extensions/extensions/src/main/java/androidx/window/extensions/layout/WindowLayoutComponent.java
+++ b/window/extensions/extensions/src/main/java/androidx/window/extensions/layout/WindowLayoutComponent.java
@@ -40,10 +40,11 @@
*/
public interface WindowLayoutComponent {
/**
- * @deprecated Use {@link #addWindowLayoutInfoListener(Context,Consumer)}
+ * @deprecated Use {@link #addWindowLayoutInfoListener(Context, Consumer)}
* starting with {@link WindowExtensions#VENDOR_API_LEVEL_2}. Only used if
* {@link #addWindowLayoutInfoListener(Context, Consumer)} can't be
* called on {@link WindowExtensions#VENDOR_API_LEVEL_1}.
+ * Since {@link WindowExtensions#VENDOR_API_LEVEL_1}
*/
@Deprecated
void addWindowLayoutInfoListener(@NonNull Activity activity,
@@ -54,6 +55,7 @@
* {@link WindowExtensions#VENDOR_API_LEVEL_2}. Only used if
* {@link #removeWindowLayoutInfoListener(Consumer)} can't be called on
* {@link WindowExtensions#VENDOR_API_LEVEL_1}.
+ * Since {@link WindowExtensions#VENDOR_API_LEVEL_1}
*/
@Deprecated
void removeWindowLayoutInfoListener(
@@ -61,7 +63,11 @@
// TODO(b/264546746): Remove addWindowLayoutInfoListener(Context, java.util.function.Consumer)
// after apps update to the latest WM Jetpack library.
- /** @deprecated Use {@link #addWindowLayoutInfoListener(Context, Consumer)} instead */
+
+ /**
+ * @deprecated Use {@link #addWindowLayoutInfoListener(Context, Consumer)} instead
+ * Since {@link WindowExtensions#VENDOR_API_LEVEL_2}
+ */
@SuppressWarnings("PairedRegistration")
// The paired method for unregistering is also removeWindowLayoutInfoListener.
@Deprecated
diff --git a/window/window-demos/demo/build.gradle b/window/window-demos/demo/build.gradle
index e579b7f..bc8df52 100644
--- a/window/window-demos/demo/build.gradle
+++ b/window/window-demos/demo/build.gradle
@@ -87,4 +87,4 @@
type = LibraryType.SAMPLES
inceptionYear = "2023"
description = "Samples for the WM Jetpack Library"
-}
\ No newline at end of file
+}
diff --git a/window/window-demos/demo/src/main/AndroidManifest.xml b/window/window-demos/demo/src/main/AndroidManifest.xml
index 36b547be..e78433e 100644
--- a/window/window-demos/demo/src/main/AndroidManifest.xml
+++ b/window/window-demos/demo/src/main/AndroidManifest.xml
@@ -58,6 +58,16 @@
android:exported="false"
android:configChanges="orientation|screenSize|screenLayout|screenSize"
android:label="@string/window_metrics"/>
+ <activity android:name=".RearDisplayActivityConfigChanges"
+ android:exported="true"
+ android:configChanges=
+ "orientation|screenLayout|screenSize|layoutDirection|smallestScreenSize"
+ android:label="@string/rear_display">
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN" />
+ <category android:name="android.intent.category.LAUNCHER" />
+ </intent-filter>
+ </activity>
<activity
android:name=".embedding.SplitActivityA"
android:exported="true"
diff --git a/window/window-demos/demo/src/main/java/androidx/window/demo/RearDisplayActivityConfigChanges.kt b/window/window-demos/demo/src/main/java/androidx/window/demo/RearDisplayActivityConfigChanges.kt
new file mode 100644
index 0000000..41c62be
--- /dev/null
+++ b/window/window-demos/demo/src/main/java/androidx/window/demo/RearDisplayActivityConfigChanges.kt
@@ -0,0 +1,136 @@
+/*
+ * Copyright 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR 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.demo
+
+import android.os.Bundle
+import androidx.appcompat.app.AppCompatActivity
+import androidx.core.content.ContextCompat
+import androidx.core.util.Consumer
+import androidx.window.area.WindowAreaController
+import androidx.window.area.WindowAreaSessionCallback
+import androidx.window.area.WindowAreaSession
+import androidx.window.area.WindowAreaStatus
+import androidx.window.core.ExperimentalWindowApi
+import androidx.window.java.area.WindowAreaControllerJavaAdapter
+import androidx.window.demo.databinding.ActivityRearDisplayBinding
+import androidx.window.demo.common.infolog.InfoLogAdapter
+import java.text.SimpleDateFormat
+import java.util.Date
+import java.util.Locale
+import java.util.concurrent.Executor
+
+/**
+ * Demo Activity that showcases listening for RearDisplay Status
+ * as well as enabling/disabling RearDisplay mode. This Activity
+ * implements [WindowAreaSessionCallback] for simplicity.
+ *
+ * This Activity overrides configuration changes for simplicity.
+ */
+@OptIn(ExperimentalWindowApi::class)
+class RearDisplayActivityConfigChanges : AppCompatActivity(), WindowAreaSessionCallback {
+
+ private lateinit var windowAreaController: WindowAreaControllerJavaAdapter
+ private var rearDisplaySession: WindowAreaSession? = null
+ private val infoLogAdapter = InfoLogAdapter()
+ private lateinit var binding: ActivityRearDisplayBinding
+ private lateinit var executor: Executor
+
+ private val rearDisplayStatusListener = Consumer<WindowAreaStatus> { status ->
+ infoLogAdapter.append(getCurrentTimeString(), status.toString())
+ infoLogAdapter.notifyDataSetChanged()
+ updateRearDisplayButton(status)
+ }
+
+ override fun onCreate(savedInstanceState: Bundle?) {
+ super.onCreate(savedInstanceState)
+ binding = ActivityRearDisplayBinding.inflate(layoutInflater)
+ setContentView(binding.root)
+
+ executor = ContextCompat.getMainExecutor(this)
+ windowAreaController = WindowAreaControllerJavaAdapter(WindowAreaController.getOrCreate())
+
+ binding.rearStatusRecyclerView.adapter = infoLogAdapter
+
+ binding.rearDisplayButton.setOnClickListener {
+ if (rearDisplaySession != null) {
+ rearDisplaySession?.close()
+ } else {
+ windowAreaController.startRearDisplayModeSession(
+ this,
+ executor,
+ this)
+ }
+ }
+ }
+
+ override fun onStart() {
+ super.onStart()
+ windowAreaController.addRearDisplayStatusListener(
+ executor,
+ rearDisplayStatusListener
+ )
+ }
+
+ override fun onStop() {
+ super.onStop()
+ windowAreaController.removeRearDisplayStatusListener(rearDisplayStatusListener)
+ }
+
+ override fun onSessionStarted(session: WindowAreaSession) {
+ rearDisplaySession = session
+ infoLogAdapter.append(getCurrentTimeString(), "RearDisplay Session has been started")
+ infoLogAdapter.notifyDataSetChanged()
+ }
+
+ override fun onSessionEnded() {
+ rearDisplaySession = null
+ infoLogAdapter.append(getCurrentTimeString(), "RearDisplay Session has ended")
+ infoLogAdapter.notifyDataSetChanged()
+ }
+
+ private fun updateRearDisplayButton(status: WindowAreaStatus) {
+ if (rearDisplaySession != null) {
+ binding.rearDisplayButton.isEnabled = true
+ binding.rearDisplayButton.text = "Disable RearDisplay Mode"
+ return
+ }
+ when (status) {
+ WindowAreaStatus.UNSUPPORTED -> {
+ binding.rearDisplayButton.isEnabled = false
+ binding.rearDisplayButton.text = "RearDisplay is not supported on this device"
+ }
+ WindowAreaStatus.UNAVAILABLE -> {
+ binding.rearDisplayButton.isEnabled = false
+ binding.rearDisplayButton.text = "RearDisplay is not currently available"
+ }
+ WindowAreaStatus.AVAILABLE -> {
+ binding.rearDisplayButton.isEnabled = true
+ binding.rearDisplayButton.text = "Enable RearDisplay Mode"
+ }
+ }
+ }
+
+ private fun getCurrentTimeString(): String {
+ val sdf = SimpleDateFormat("HH:mm:ss.SSS", Locale.getDefault())
+ val currentDate = sdf.format(Date())
+ return currentDate.toString()
+ }
+
+ private companion object {
+ private val TAG = RearDisplayActivityConfigChanges::class.java.simpleName
+ }
+}
\ No newline at end of file
diff --git a/window/window-demos/demo/src/main/java/androidx/window/demo/embedding/DemoActivityEmbeddingController.kt b/window/window-demos/demo/src/main/java/androidx/window/demo/embedding/DemoActivityEmbeddingController.kt
index 0d3771e..69542ac 100644
--- a/window/window-demos/demo/src/main/java/androidx/window/demo/embedding/DemoActivityEmbeddingController.kt
+++ b/window/window-demos/demo/src/main/java/androidx/window/demo/embedding/DemoActivityEmbeddingController.kt
@@ -16,8 +16,8 @@
package androidx.window.demo.embedding
-import androidx.annotation.ColorInt
import androidx.annotation.GuardedBy
+import androidx.window.embedding.SplitAttributes
import java.util.concurrent.locks.ReentrantLock
import kotlin.concurrent.withLock
@@ -27,16 +27,14 @@
private val lock = Object()
@GuardedBy("lock")
- @ColorInt
- private var _animationBackgroundColor = 0
+ private var _animationBackgroundColor = SplitAttributes.BackgroundColor.DEFAULT
/** Animation background color to use when the animation requires a background. */
- var animationBackgroundColor: Int
- @ColorInt
+ var animationBackgroundColor: SplitAttributes.BackgroundColor
get() = synchronized(lock) {
_animationBackgroundColor
}
- set(@ColorInt value) = synchronized(lock) {
+ set(value) = synchronized(lock) {
_animationBackgroundColor = value
}
diff --git a/window/window-demos/demo/src/main/java/androidx/window/demo/embedding/ExampleWindowInitializer.kt b/window/window-demos/demo/src/main/java/androidx/window/demo/embedding/ExampleWindowInitializer.kt
index 74adead..8665740 100644
--- a/window/window-demos/demo/src/main/java/androidx/window/demo/embedding/ExampleWindowInitializer.kt
+++ b/window/window-demos/demo/src/main/java/androidx/window/demo/embedding/ExampleWindowInitializer.kt
@@ -18,7 +18,6 @@
import android.content.Context
import androidx.startup.Initializer
-import androidx.window.core.ExperimentalWindowApi
import androidx.window.demo.R
import androidx.window.demo.embedding.SplitDeviceStateActivityBase.Companion.SUFFIX_AND_FULLSCREEN_IN_BOOK_MODE
import androidx.window.demo.embedding.SplitDeviceStateActivityBase.Companion.SUFFIX_AND_HORIZONTAL_LAYOUT_IN_TABLETOP
@@ -46,7 +45,6 @@
class ExampleWindowInitializer : Initializer<RuleController> {
private val mDemoActivityEmbeddingController = DemoActivityEmbeddingController.getInstance()
- @OptIn(ExperimentalWindowApi::class)
override fun create(context: Context): RuleController {
SplitController.getInstance(context).apply {
if (isSplitAttributesCalculatorSupported()) {
diff --git a/window/window-demos/demo/src/main/java/androidx/window/demo/embedding/SplitActivityBase.java b/window/window-demos/demo/src/main/java/androidx/window/demo/embedding/SplitActivityBase.java
index 59ca4ac..944916c 100644
--- a/window/window-demos/demo/src/main/java/androidx/window/demo/embedding/SplitActivityBase.java
+++ b/window/window-demos/demo/src/main/java/androidx/window/demo/embedding/SplitActivityBase.java
@@ -23,6 +23,7 @@
import static androidx.window.embedding.SplitRule.FinishBehavior.NEVER;
import android.app.Activity;
+import android.app.ActivityOptions;
import android.app.PendingIntent;
import android.content.ActivityNotFoundException;
import android.content.ComponentName;
@@ -41,6 +42,7 @@
import androidx.window.demo.databinding.ActivitySplitActivityLayoutBinding;
import androidx.window.embedding.ActivityEmbeddingController;
import androidx.window.embedding.ActivityFilter;
+import androidx.window.embedding.ActivityOptionsCompat;
import androidx.window.embedding.ActivityRule;
import androidx.window.embedding.EmbeddingRule;
import androidx.window.embedding.RuleController;
@@ -90,8 +92,23 @@
bStartIntent.putExtra(EXTRA_LAUNCH_C_TO_SIDE, true);
startActivity(bStartIntent);
});
- mViewBinding.launchE.setOnClickListener((View v) ->
- startActivity(new Intent(this, SplitActivityE.class)));
+ mViewBinding.launchE.setOnClickListener((View v) -> {
+ Bundle bundle = null;
+ if (mViewBinding.setLaunchingEInActivityStack.isChecked()) {
+ try {
+ final ActivityOptions options = ActivityOptionsCompat
+ .setLaunchingActivityStack(ActivityOptions.makeBasic(), this);
+ bundle = options.toBundle();
+ } catch (UnsupportedOperationException ex) {
+ Log.w(TAG, "#setLaunchingActivityStack is not supported", ex);
+ }
+ }
+ startActivity(new Intent(this, SplitActivityE.class), bundle);
+ });
+ if (!ActivityOptionsCompat.isSetLaunchingActivityStackSupported(
+ ActivityOptions.makeBasic())) {
+ mViewBinding.setLaunchingEInActivityStack.setEnabled(false);
+ }
mViewBinding.launchF.setOnClickListener((View v) ->
startActivity(new Intent(this, SplitActivityF.class)));
mViewBinding.launchFPendingIntent.setOnClickListener((View v) -> {
diff --git a/window/window-demos/demo/src/main/java/androidx/window/demo/embedding/SplitDeviceStateActivityBase.kt b/window/window-demos/demo/src/main/java/androidx/window/demo/embedding/SplitDeviceStateActivityBase.kt
index 5f686b2..b4aadf6 100644
--- a/window/window-demos/demo/src/main/java/androidx/window/demo/embedding/SplitDeviceStateActivityBase.kt
+++ b/window/window-demos/demo/src/main/java/androidx/window/demo/embedding/SplitDeviceStateActivityBase.kt
@@ -29,7 +29,6 @@
import androidx.appcompat.app.AppCompatActivity
import androidx.core.content.ContextCompat
import androidx.core.util.Consumer
-import androidx.window.core.ExperimentalWindowApi
import androidx.window.embedding.EmbeddingRule
import androidx.window.embedding.SplitAttributes
import androidx.window.embedding.SplitController
@@ -64,7 +63,6 @@
/** The last selected split rule id. */
private var lastCheckedRuleId = 0
- @OptIn(ExperimentalWindowApi::class)
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
viewBinding = ActivitySplitDeviceStateLayoutBinding.inflate(layoutInflater)
@@ -313,7 +311,6 @@
}
}
- @OptIn(ExperimentalWindowApi::class)
fun updateSplitAttributesText(newSplitInfos: List<SplitInfo>) {
var splitAttributes: SplitAttributes = SplitAttributes.Builder()
.setSplitType(SplitAttributes.SplitType.expandContainers())
@@ -410,12 +407,12 @@
const val SUFFIX_REVERSED = "_reversed"
const val SUFFIX_AND_HORIZONTAL_LAYOUT_IN_TABLETOP = "_and_horizontal_layout_in_tabletop"
const val SUFFIX_AND_FULLSCREEN_IN_BOOK_MODE = "_and_fullscreen_in_book_mode"
- val ANIMATION_BACKGROUND_COLORS_TEXT = arrayOf("BLACK", "BLUE", "GREEN", "YELLOW")
+ val ANIMATION_BACKGROUND_COLORS_TEXT = arrayOf("DEFAULT", "BLUE", "GREEN", "YELLOW")
val ANIMATION_BACKGROUND_COLORS_VALUE = arrayOf(
- Color.BLACK,
- Color.BLUE,
- Color.GREEN,
- Color.YELLOW
+ SplitAttributes.BackgroundColor.DEFAULT,
+ SplitAttributes.BackgroundColor.color(Color.BLUE),
+ SplitAttributes.BackgroundColor.color(Color.GREEN),
+ SplitAttributes.BackgroundColor.color(Color.YELLOW)
)
/**
diff --git a/window/window-java/api/public_plus_experimental_current.txt b/window/window-java/api/public_plus_experimental_current.txt
index 39c35ac..ded945be 100644
--- a/window/window-java/api/public_plus_experimental_current.txt
+++ b/window/window-java/api/public_plus_experimental_current.txt
@@ -1,4 +1,15 @@
// Signature format: 4.0
+package androidx.window.java.area {
+
+ @androidx.window.core.ExperimentalWindowApi public final class WindowAreaControllerJavaAdapter implements androidx.window.area.WindowAreaController {
+ ctor public WindowAreaControllerJavaAdapter(androidx.window.area.WindowAreaController controller);
+ method public void addRearDisplayStatusListener(java.util.concurrent.Executor executor, androidx.core.util.Consumer<androidx.window.area.WindowAreaStatus> consumer);
+ method public void removeRearDisplayStatusListener(androidx.core.util.Consumer<androidx.window.area.WindowAreaStatus> consumer);
+ method public void startRearDisplayModeSession(android.app.Activity activity, java.util.concurrent.Executor executor, androidx.window.area.WindowAreaSessionCallback windowAreaSessionCallback);
+ }
+
+}
+
package androidx.window.java.layout {
public final class WindowInfoTrackerCallbackAdapter implements androidx.window.layout.WindowInfoTracker {
diff --git a/window/window-java/src/main/java/androidx/window/java/area/WindowAreaControllerJavaAdapter.kt b/window/window-java/src/main/java/androidx/window/java/area/WindowAreaControllerJavaAdapter.kt
new file mode 100644
index 0000000..584445f
--- /dev/null
+++ b/window/window-java/src/main/java/androidx/window/java/area/WindowAreaControllerJavaAdapter.kt
@@ -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.window.java.area
+
+import android.app.Activity
+import androidx.core.util.Consumer
+import androidx.window.area.WindowAreaSessionCallback
+import androidx.window.area.WindowAreaStatus
+import androidx.window.area.WindowAreaController
+import androidx.window.core.ExperimentalWindowApi
+import kotlinx.coroutines.CoroutineScope
+import kotlinx.coroutines.Job
+import kotlinx.coroutines.asCoroutineDispatcher
+import kotlinx.coroutines.flow.collect
+import kotlinx.coroutines.launch
+import java.util.concurrent.Executor
+import java.util.concurrent.locks.ReentrantLock
+import kotlin.concurrent.withLock
+
+/**
+ * An adapted interface for [WindowAreaController] that provides the information and
+ * functionality around RearDisplay Mode via a callback shaped API.
+ */
+@ExperimentalWindowApi
+class WindowAreaControllerJavaAdapter(
+ private val controller: WindowAreaController
+) : WindowAreaController by controller {
+
+ /**
+ * A [ReentrantLock] to protect against concurrent access to [consumerToJobMap].
+ */
+ private val lock = ReentrantLock()
+ private val consumerToJobMap = mutableMapOf<Consumer<*>, Job>()
+
+ /**
+ * Registers a listener to consume [WindowAreaStatus] values defined as
+ * [WindowAreaStatus.UNSUPPORTED], [WindowAreaStatus.UNAVAILABLE], and
+ * [WindowAreaStatus.AVAILABLE]. The values provided through this listener should be used
+ * to determine if you are able to enable rear display Mode at that time. You can use these
+ * values to modify your UI to show/hide controls and determine when to enable features
+ * that use rear display Mode. You should only try and enter rear display mode when your
+ * [consumer] is provided a value of [WindowAreaStatus.AVAILABLE].
+ *
+ * The [consumer] will be provided an initial value on registration, as well as any change
+ * to the status as they occur. This could happen due to hardware device state changes, or if
+ * another process has enabled RearDisplay Mode.
+ *
+ * @see WindowAreaController.rearDisplayStatus
+ */
+ fun addRearDisplayStatusListener(
+ executor: Executor,
+ consumer: Consumer<WindowAreaStatus>
+ ) {
+ val statusFlow = controller.rearDisplayStatus()
+ lock.withLock {
+ if (consumerToJobMap[consumer] == null) {
+ val scope = CoroutineScope(executor.asCoroutineDispatcher())
+ consumerToJobMap[consumer] = scope.launch {
+ statusFlow.collect { consumer.accept(it) }
+ }
+ }
+ }
+ }
+
+ /**
+ * Removes a listener of [WindowAreaStatus] values
+ * @see WindowAreaController.rearDisplayStatus
+ */
+ fun removeRearDisplayStatusListener(consumer: Consumer<WindowAreaStatus>) {
+ lock.withLock {
+ consumerToJobMap[consumer]?.cancel()
+ consumerToJobMap.remove(consumer)
+ }
+ }
+
+ /**
+ * Starts a RearDisplay Mode session and provides updates through the
+ * [WindowAreaSessionCallback] provided. Due to the nature of moving your Activity to a
+ * different display, your Activity will likely go through a configuration change. Because of
+ * this, if your Activity does not override configuration changes, this method should be called
+ * from a component that outlives the Activity lifecycle such as a
+ * [androidx.lifecycle.ViewModel]. If your Activity does override
+ * configuration changes, it is safe to call this method inside your Activity.
+ *
+ * This method should only be called if you have received a [WindowAreaStatus.AVAILABLE]
+ * value from the listener provided through the [addRearDisplayStatusListener] method. If
+ * you try and enable RearDisplay mode without it being available, you will receive an
+ * [UnsupportedOperationException].
+ *
+ * The [windowAreaSessionCallback] provided will receive a call to
+ * [WindowAreaSessionCallback.onSessionStarted] after your Activity has been moved to the
+ * display corresponding to this mode. RearDisplay mode will stay active until the session
+ * provided through [WindowAreaSessionCallback.onSessionStarted] is closed, or there is a device
+ * state change that makes RearDisplay mode incompatible such as if the device is closed so the
+ * outer-display is no longer in line with the rear camera. When this occurs,
+ * [WindowAreaSessionCallback.onSessionEnded] is called to notify you the session has been
+ * ended.
+ *
+ * @see addRearDisplayStatusListener
+ * @throws UnsupportedOperationException if you try and start a RearDisplay session when
+ * your [WindowAreaController.rearDisplayStatus] does not return a value of
+ * [WindowAreaStatus.AVAILABLE]
+ */
+ fun startRearDisplayModeSession(
+ activity: Activity,
+ executor: Executor,
+ windowAreaSessionCallback: WindowAreaSessionCallback
+ ) {
+ controller.rearDisplayMode(activity, executor, windowAreaSessionCallback)
+ }
+}
\ No newline at end of file
diff --git a/window/window/api/api_lint.ignore b/window/window/api/api_lint.ignore
new file mode 100644
index 0000000..2c6dfc6
--- /dev/null
+++ b/window/window/api/api_lint.ignore
@@ -0,0 +1,3 @@
+// Baseline format: 1.0
+ContextFirst: androidx.window.embedding.ActivityOptionsCompat#setLaunchingActivityStack(android.app.ActivityOptions, android.content.Context, androidx.window.embedding.ActivityStack) parameter #1:
+ Context is distinct, so it must be the first argument (method `windowLayoutInfoFlowable`)
diff --git a/window/window/api/current.txt b/window/window/api/current.txt
index 2a716a3..cd4c848 100644
--- a/window/window/api/current.txt
+++ b/window/window/api/current.txt
@@ -84,19 +84,29 @@
}
public final class SplitAttributes {
- method public int getAnimationBackgroundColor();
+ method public androidx.window.embedding.SplitAttributes.BackgroundColor getAnimationBackgroundColor();
method public androidx.window.embedding.SplitAttributes.LayoutDirection getLayoutDirection();
method public androidx.window.embedding.SplitAttributes.SplitType getSplitType();
- property public final int animationBackgroundColor;
+ property public final androidx.window.embedding.SplitAttributes.BackgroundColor animationBackgroundColor;
property public final androidx.window.embedding.SplitAttributes.LayoutDirection layoutDirection;
property public final androidx.window.embedding.SplitAttributes.SplitType splitType;
field public static final androidx.window.embedding.SplitAttributes.Companion Companion;
}
+ public static final class SplitAttributes.BackgroundColor {
+ method public static androidx.window.embedding.SplitAttributes.BackgroundColor color(@ColorInt @IntRange(from=android.graphics.Color.BLACK.toLong(), to=android.graphics.Color.WHITE.toLong()) int color);
+ field public static final androidx.window.embedding.SplitAttributes.BackgroundColor.Companion Companion;
+ field public static final androidx.window.embedding.SplitAttributes.BackgroundColor DEFAULT;
+ }
+
+ public static final class SplitAttributes.BackgroundColor.Companion {
+ method public androidx.window.embedding.SplitAttributes.BackgroundColor color(@ColorInt @IntRange(from=android.graphics.Color.BLACK.toLong(), to=android.graphics.Color.WHITE.toLong()) int color);
+ }
+
public static final class SplitAttributes.Builder {
ctor public SplitAttributes.Builder();
method public androidx.window.embedding.SplitAttributes build();
- method public androidx.window.embedding.SplitAttributes.Builder setAnimationBackgroundColor(@ColorInt int color);
+ method public androidx.window.embedding.SplitAttributes.Builder setAnimationBackgroundColor(androidx.window.embedding.SplitAttributes.BackgroundColor color);
method public androidx.window.embedding.SplitAttributes.Builder setLayoutDirection(androidx.window.embedding.SplitAttributes.LayoutDirection layoutDirection);
method public androidx.window.embedding.SplitAttributes.Builder setSplitType(androidx.window.embedding.SplitAttributes.SplitType type);
}
@@ -161,9 +171,12 @@
public final class SplitController {
method public void addSplitListener(android.app.Activity activity, java.util.concurrent.Executor executor, androidx.core.util.Consumer<java.util.List<androidx.window.embedding.SplitInfo>> consumer);
+ method public void clearSplitAttributesCalculator();
method public static androidx.window.embedding.SplitController getInstance(android.content.Context context);
+ method public boolean isSplitAttributesCalculatorSupported();
method public boolean isSplitSupported();
method public void removeSplitListener(androidx.core.util.Consumer<java.util.List<androidx.window.embedding.SplitInfo>> consumer);
+ method public void setSplitAttributesCalculator(kotlin.jvm.functions.Function1<? super androidx.window.embedding.SplitAttributesCalculatorParams,androidx.window.embedding.SplitAttributes> calculator);
field public static final androidx.window.embedding.SplitController.Companion Companion;
}
diff --git a/window/window/api/public_plus_experimental_current.txt b/window/window/api/public_plus_experimental_current.txt
index 986a2d0..eefa40a 100644
--- a/window/window/api/public_plus_experimental_current.txt
+++ b/window/window/api/public_plus_experimental_current.txt
@@ -9,6 +9,38 @@
}
+package androidx.window.area {
+
+ @androidx.window.core.ExperimentalWindowApi public interface WindowAreaController {
+ method public default static androidx.window.area.WindowAreaController getOrCreate();
+ field public static final androidx.window.area.WindowAreaController.Companion Companion;
+ }
+
+ public static final class WindowAreaController.Companion {
+ method public androidx.window.area.WindowAreaController getOrCreate();
+ }
+
+ @androidx.window.core.ExperimentalWindowApi public interface WindowAreaSession {
+ method public void close();
+ }
+
+ @androidx.window.core.ExperimentalWindowApi public interface WindowAreaSessionCallback {
+ method public void onSessionEnded();
+ method public void onSessionStarted(androidx.window.area.WindowAreaSession session);
+ }
+
+ @androidx.window.core.ExperimentalWindowApi public final class WindowAreaStatus {
+ field public static final androidx.window.area.WindowAreaStatus AVAILABLE;
+ field public static final androidx.window.area.WindowAreaStatus.Companion Companion;
+ field public static final androidx.window.area.WindowAreaStatus UNAVAILABLE;
+ field public static final androidx.window.area.WindowAreaStatus UNSUPPORTED;
+ }
+
+ public static final class WindowAreaStatus.Companion {
+ }
+
+}
+
package androidx.window.core {
@kotlin.RequiresOptIn(level=kotlin.RequiresOptIn.Level.WARNING) @kotlin.annotation.MustBeDocumented @kotlin.annotation.Retention(kotlin.annotation.AnnotationRetention.BINARY) public @interface ExperimentalWindowApi {
@@ -19,8 +51,11 @@
package androidx.window.embedding {
public final class ActivityEmbeddingController {
+ method @androidx.window.core.ExperimentalWindowApi public void finishActivityStacks(java.util.Set<androidx.window.embedding.ActivityStack> activityStacks);
+ method @androidx.window.core.ExperimentalWindowApi public androidx.window.embedding.ActivityStack? getActivityStack(android.app.Activity activity);
method public static androidx.window.embedding.ActivityEmbeddingController getInstance(android.content.Context context);
method public boolean isActivityEmbedded(android.app.Activity activity);
+ method @androidx.window.core.ExperimentalWindowApi public boolean isFinishingActivityStacksSupported();
field public static final androidx.window.embedding.ActivityEmbeddingController.Companion Companion;
}
@@ -38,6 +73,12 @@
property public final String? intentAction;
}
+ public final class ActivityOptionsCompat {
+ method @androidx.window.core.ExperimentalWindowApi public static boolean isSetLaunchingActivityStackSupported(android.app.ActivityOptions);
+ method @androidx.window.core.ExperimentalWindowApi public static android.app.ActivityOptions setLaunchingActivityStack(android.app.ActivityOptions, android.content.Context context, androidx.window.embedding.ActivityStack activityStack);
+ method @androidx.window.core.ExperimentalWindowApi public static android.app.ActivityOptions setLaunchingActivityStack(android.app.ActivityOptions, android.app.Activity activity);
+ }
+
public final class ActivityRule extends androidx.window.embedding.EmbeddingRule {
method public boolean getAlwaysExpand();
method public java.util.Set<androidx.window.embedding.ActivityFilter> getFilters();
@@ -91,19 +132,29 @@
}
public final class SplitAttributes {
- method public int getAnimationBackgroundColor();
+ method public androidx.window.embedding.SplitAttributes.BackgroundColor getAnimationBackgroundColor();
method public androidx.window.embedding.SplitAttributes.LayoutDirection getLayoutDirection();
method public androidx.window.embedding.SplitAttributes.SplitType getSplitType();
- property public final int animationBackgroundColor;
+ property public final androidx.window.embedding.SplitAttributes.BackgroundColor animationBackgroundColor;
property public final androidx.window.embedding.SplitAttributes.LayoutDirection layoutDirection;
property public final androidx.window.embedding.SplitAttributes.SplitType splitType;
field public static final androidx.window.embedding.SplitAttributes.Companion Companion;
}
+ public static final class SplitAttributes.BackgroundColor {
+ method public static androidx.window.embedding.SplitAttributes.BackgroundColor color(@ColorInt @IntRange(from=android.graphics.Color.BLACK.toLong(), to=android.graphics.Color.WHITE.toLong()) int color);
+ field public static final androidx.window.embedding.SplitAttributes.BackgroundColor.Companion Companion;
+ field public static final androidx.window.embedding.SplitAttributes.BackgroundColor DEFAULT;
+ }
+
+ public static final class SplitAttributes.BackgroundColor.Companion {
+ method public androidx.window.embedding.SplitAttributes.BackgroundColor color(@ColorInt @IntRange(from=android.graphics.Color.BLACK.toLong(), to=android.graphics.Color.WHITE.toLong()) int color);
+ }
+
public static final class SplitAttributes.Builder {
ctor public SplitAttributes.Builder();
method public androidx.window.embedding.SplitAttributes build();
- method public androidx.window.embedding.SplitAttributes.Builder setAnimationBackgroundColor(@ColorInt int color);
+ method public androidx.window.embedding.SplitAttributes.Builder setAnimationBackgroundColor(androidx.window.embedding.SplitAttributes.BackgroundColor color);
method public androidx.window.embedding.SplitAttributes.Builder setLayoutDirection(androidx.window.embedding.SplitAttributes.LayoutDirection layoutDirection);
method public androidx.window.embedding.SplitAttributes.Builder setSplitType(androidx.window.embedding.SplitAttributes.SplitType type);
}
@@ -168,12 +219,16 @@
public final class SplitController {
method public void addSplitListener(android.app.Activity activity, java.util.concurrent.Executor executor, androidx.core.util.Consumer<java.util.List<androidx.window.embedding.SplitInfo>> consumer);
- method @androidx.window.core.ExperimentalWindowApi public void clearSplitAttributesCalculator();
+ method public void clearSplitAttributesCalculator();
method public static androidx.window.embedding.SplitController getInstance(android.content.Context context);
- method @androidx.window.core.ExperimentalWindowApi public boolean isSplitAttributesCalculatorSupported();
+ method @androidx.window.core.ExperimentalWindowApi public void invalidateTopVisibleSplitAttributes();
+ method @androidx.window.core.ExperimentalWindowApi public boolean isInvalidatingTopVisibleSplitAttributesSupported();
+ method public boolean isSplitAttributesCalculatorSupported();
method public boolean isSplitSupported();
+ method @androidx.window.core.ExperimentalWindowApi public boolean isUpdatingSplitAttributesSupported();
method public void removeSplitListener(androidx.core.util.Consumer<java.util.List<androidx.window.embedding.SplitInfo>> consumer);
- method @androidx.window.core.ExperimentalWindowApi public void setSplitAttributesCalculator(kotlin.jvm.functions.Function1<? super androidx.window.embedding.SplitAttributesCalculatorParams,androidx.window.embedding.SplitAttributes> calculator);
+ method public void setSplitAttributesCalculator(kotlin.jvm.functions.Function1<? super androidx.window.embedding.SplitAttributesCalculatorParams,androidx.window.embedding.SplitAttributes> calculator);
+ method @androidx.window.core.ExperimentalWindowApi public void updateSplitAttributes(androidx.window.embedding.SplitInfo splitInfo, androidx.window.embedding.SplitAttributes splitAttributes);
field public static final androidx.window.embedding.SplitController.Companion Companion;
}
diff --git a/window/window/api/restricted_current.txt b/window/window/api/restricted_current.txt
index 2a716a3..cd4c848 100644
--- a/window/window/api/restricted_current.txt
+++ b/window/window/api/restricted_current.txt
@@ -84,19 +84,29 @@
}
public final class SplitAttributes {
- method public int getAnimationBackgroundColor();
+ method public androidx.window.embedding.SplitAttributes.BackgroundColor getAnimationBackgroundColor();
method public androidx.window.embedding.SplitAttributes.LayoutDirection getLayoutDirection();
method public androidx.window.embedding.SplitAttributes.SplitType getSplitType();
- property public final int animationBackgroundColor;
+ property public final androidx.window.embedding.SplitAttributes.BackgroundColor animationBackgroundColor;
property public final androidx.window.embedding.SplitAttributes.LayoutDirection layoutDirection;
property public final androidx.window.embedding.SplitAttributes.SplitType splitType;
field public static final androidx.window.embedding.SplitAttributes.Companion Companion;
}
+ public static final class SplitAttributes.BackgroundColor {
+ method public static androidx.window.embedding.SplitAttributes.BackgroundColor color(@ColorInt @IntRange(from=android.graphics.Color.BLACK.toLong(), to=android.graphics.Color.WHITE.toLong()) int color);
+ field public static final androidx.window.embedding.SplitAttributes.BackgroundColor.Companion Companion;
+ field public static final androidx.window.embedding.SplitAttributes.BackgroundColor DEFAULT;
+ }
+
+ public static final class SplitAttributes.BackgroundColor.Companion {
+ method public androidx.window.embedding.SplitAttributes.BackgroundColor color(@ColorInt @IntRange(from=android.graphics.Color.BLACK.toLong(), to=android.graphics.Color.WHITE.toLong()) int color);
+ }
+
public static final class SplitAttributes.Builder {
ctor public SplitAttributes.Builder();
method public androidx.window.embedding.SplitAttributes build();
- method public androidx.window.embedding.SplitAttributes.Builder setAnimationBackgroundColor(@ColorInt int color);
+ method public androidx.window.embedding.SplitAttributes.Builder setAnimationBackgroundColor(androidx.window.embedding.SplitAttributes.BackgroundColor color);
method public androidx.window.embedding.SplitAttributes.Builder setLayoutDirection(androidx.window.embedding.SplitAttributes.LayoutDirection layoutDirection);
method public androidx.window.embedding.SplitAttributes.Builder setSplitType(androidx.window.embedding.SplitAttributes.SplitType type);
}
@@ -161,9 +171,12 @@
public final class SplitController {
method public void addSplitListener(android.app.Activity activity, java.util.concurrent.Executor executor, androidx.core.util.Consumer<java.util.List<androidx.window.embedding.SplitInfo>> consumer);
+ method public void clearSplitAttributesCalculator();
method public static androidx.window.embedding.SplitController getInstance(android.content.Context context);
+ method public boolean isSplitAttributesCalculatorSupported();
method public boolean isSplitSupported();
method public void removeSplitListener(androidx.core.util.Consumer<java.util.List<androidx.window.embedding.SplitInfo>> consumer);
+ method public void setSplitAttributesCalculator(kotlin.jvm.functions.Function1<? super androidx.window.embedding.SplitAttributesCalculatorParams,androidx.window.embedding.SplitAttributes> calculator);
field public static final androidx.window.embedding.SplitController.Companion Companion;
}
diff --git a/window/window/build.gradle b/window/window/build.gradle
index cdbbf0f..1880963 100644
--- a/window/window/build.gradle
+++ b/window/window/build.gradle
@@ -80,7 +80,6 @@
androidTestImplementation(compileOnly(project(":window:extensions:extensions")))
androidTestImplementation(compileOnly(project(":window:sidecar:sidecar")))
androidTestImplementation(implementation("androidx.window.extensions.core:core:1.0.0-alpha01"))
- samples(project(":window:window-samples"))
}
androidx {
diff --git a/window/window/samples/src/main/java/androidx.window.samples.embedding/FinishActivityStacksSamples.kt b/window/window/samples/src/main/java/androidx.window.samples.embedding/FinishActivityStacksSamples.kt
new file mode 100644
index 0000000..a4817c2
--- /dev/null
+++ b/window/window/samples/src/main/java/androidx.window.samples.embedding/FinishActivityStacksSamples.kt
@@ -0,0 +1,44 @@
+/*
+ * Copyright 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.window.samples.embedding
+
+import android.app.Activity
+import androidx.annotation.Sampled
+import androidx.window.core.ExperimentalWindowApi
+import androidx.window.embedding.ActivityEmbeddingController
+import androidx.window.embedding.SplitController
+
+@OptIn(ExperimentalWindowApi::class)
+@Sampled
+fun expandPrimaryContainer() {
+ SplitController.getInstance(primaryActivity).addSplitListener(
+ primaryActivity,
+ Runnable::run,
+ ) { splitInfoList ->
+ if (fullScreenEnabled) {
+ // Find all associated secondary ActivityStacks
+ val associatedSecondaryActivityStacks = splitInfoList
+ .mapTo(mutableSetOf()) { splitInfo -> splitInfo.secondaryActivityStack }
+ // Finish them all.
+ ActivityEmbeddingController.getInstance(primaryActivity)
+ .finishActivityStacks(associatedSecondaryActivityStacks)
+ }
+ }
+}
+
+val primaryActivity = Activity()
+var fullScreenEnabled = true
diff --git a/window/window/samples/src/main/java/androidx.window.samples.embedding/SplitAttributesCalculatorSamples.kt b/window/window/samples/src/main/java/androidx.window.samples.embedding/SplitAttributesCalculatorSamples.kt
index 8eebd5c..f201016 100644
--- a/window/window/samples/src/main/java/androidx.window.samples.embedding/SplitAttributesCalculatorSamples.kt
+++ b/window/window/samples/src/main/java/androidx.window.samples.embedding/SplitAttributesCalculatorSamples.kt
@@ -19,12 +19,10 @@
import android.app.Application
import android.graphics.Color
import androidx.annotation.Sampled
-import androidx.window.core.ExperimentalWindowApi
import androidx.window.embedding.SplitAttributes
import androidx.window.embedding.SplitController
import androidx.window.layout.FoldingFeature
-@OptIn(ExperimentalWindowApi::class)
@Sampled
fun splitAttributesCalculatorSample() {
SplitController.getInstance(context)
@@ -59,7 +57,7 @@
}
)
// Set the color to use when switching between vertical and horizontal
- .setAnimationBackgroundColor(Color.GRAY)
+ .setAnimationBackgroundColor(SplitAttributes.BackgroundColor.color(Color.GRAY))
.build()
}
return@setSplitAttributesCalculator if (
@@ -69,7 +67,7 @@
SplitAttributes.Builder()
.setSplitType(SplitAttributes.SplitType.splitEqually())
.setLayoutDirection(SplitAttributes.LayoutDirection.LOCALE)
- .setAnimationBackgroundColor(Color.GRAY)
+ .setAnimationBackgroundColor(SplitAttributes.BackgroundColor.color(Color.GRAY))
.build()
} else {
// Expand containers if the device is in portrait or the width is less than 600 dp.
@@ -80,7 +78,6 @@
}
}
-@OptIn(ExperimentalWindowApi::class)
@Sampled
fun splitWithOrientations() {
SplitController.getInstance(context)
@@ -93,13 +90,13 @@
builder
.setLayoutDirection(SplitAttributes.LayoutDirection.LOCALE)
// Set the color to use when switching between vertical and horizontal
- .setAnimationBackgroundColor(Color.GRAY)
+ .setAnimationBackgroundColor(SplitAttributes.BackgroundColor.color(Color.GRAY))
.build()
} else if (parentConfiguration.screenHeightDp >= 600) {
builder
.setLayoutDirection(SplitAttributes.LayoutDirection.TOP_TO_BOTTOM)
// Set the color to use when switching between vertical and horizontal
- .setAnimationBackgroundColor(Color.GRAY)
+ .setAnimationBackgroundColor(SplitAttributes.BackgroundColor.color(Color.GRAY))
.build()
} else {
// Fallback to expand the secondary container
@@ -110,7 +107,6 @@
}
}
-@OptIn(ExperimentalWindowApi::class)
@Sampled
fun expandContainersInPortrait() {
SplitController.getInstance(context)
diff --git a/window/window/src/androidTest/java/androidx/window/area/WindowAreaControllerImplTest.kt b/window/window/src/androidTest/java/androidx/window/area/WindowAreaControllerImplTest.kt
new file mode 100644
index 0000000..c553679
--- /dev/null
+++ b/window/window/src/androidTest/java/androidx/window/area/WindowAreaControllerImplTest.kt
@@ -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.window.area
+
+import android.annotation.TargetApi
+import android.app.Activity
+import android.content.pm.ActivityInfo
+import android.os.Build
+import androidx.annotation.RequiresApi
+import androidx.test.ext.junit.rules.ActivityScenarioRule
+import androidx.window.TestActivity
+import androidx.window.TestConsumer
+import androidx.window.core.ExperimentalWindowApi
+import androidx.window.extensions.area.ExtensionWindowAreaPresentation
+import androidx.window.extensions.area.ExtensionWindowAreaStatus
+import androidx.window.extensions.area.WindowAreaComponent
+import androidx.window.extensions.core.util.function.Consumer
+import kotlinx.coroutines.ExperimentalCoroutinesApi
+import kotlinx.coroutines.launch
+import org.junit.Assume.assumeTrue
+import org.junit.Rule
+import org.junit.Test
+import kotlin.test.assertFailsWith
+import kotlinx.coroutines.Job
+import kotlinx.coroutines.test.TestScope
+import kotlinx.coroutines.test.UnconfinedTestDispatcher
+import kotlinx.coroutines.test.runTest
+
+@OptIn(ExperimentalCoroutinesApi::class, ExperimentalWindowApi::class)
+class WindowAreaControllerImplTest {
+
+ @get:Rule
+ public val activityScenario: ActivityScenarioRule<TestActivity> =
+ ActivityScenarioRule(TestActivity::class.java)
+
+ private val testScope = TestScope(UnconfinedTestDispatcher())
+
+ @TargetApi(Build.VERSION_CODES.N)
+ @Test
+ public fun testRearDisplayStatus(): Unit = testScope.runTest {
+ assumeTrue(Build.VERSION.SDK_INT > Build.VERSION_CODES.N)
+ activityScenario.scenario.onActivity {
+ val extensionComponent = FakeWindowAreaComponent()
+ val repo = WindowAreaControllerImpl(extensionComponent)
+ val collector = TestConsumer<WindowAreaStatus>()
+ extensionComponent
+ .updateStatusListeners(WindowAreaComponent.STATUS_UNAVAILABLE)
+ testScope.launch(Job()) {
+ repo.rearDisplayStatus().collect(collector::accept)
+ }
+ collector.assertValue(WindowAreaStatus.UNAVAILABLE)
+ extensionComponent
+ .updateStatusListeners(WindowAreaComponent.STATUS_AVAILABLE)
+ collector.assertValues(
+ WindowAreaStatus.UNAVAILABLE,
+ WindowAreaStatus.AVAILABLE
+ )
+ }
+ }
+
+ @Test
+ public fun testRearDisplayStatusNullComponent(): Unit = testScope.runTest {
+ activityScenario.scenario.onActivity {
+ val repo = EmptyWindowAreaControllerImpl()
+ val collector = TestConsumer<WindowAreaStatus>()
+ testScope.launch(Job()) {
+ repo.rearDisplayStatus().collect(collector::accept)
+ }
+ collector.assertValue(WindowAreaStatus.UNSUPPORTED)
+ }
+ }
+
+ /**
+ * Tests the rear display mode flow works as expected. Tests the flow
+ * through WindowAreaControllerImpl with a fake extension. This fake extension
+ * changes the orientation of the activity to landscape when rear display mode is enabled
+ * and then returns it back to portrait when it's disabled.
+ */
+ @TargetApi(Build.VERSION_CODES.N)
+ @Test
+ public fun testRearDisplayMode(): Unit = testScope.runTest {
+ assumeTrue(Build.VERSION.SDK_INT > Build.VERSION_CODES.N)
+ val extensions = FakeWindowAreaComponent()
+ val repo = WindowAreaControllerImpl(extensions)
+ extensions.currentStatus = WindowAreaComponent.STATUS_AVAILABLE
+ val callback = TestWindowAreaSessionCallback()
+ activityScenario.scenario.onActivity { testActivity ->
+ testActivity.resetLayoutCounter()
+ testActivity.requestedOrientation = ActivityInfo.SCREEN_ORIENTATION_PORTRAIT
+ testActivity.waitForLayout()
+ }
+
+ activityScenario.scenario.onActivity { testActivity ->
+ assert(testActivity.requestedOrientation == ActivityInfo.SCREEN_ORIENTATION_PORTRAIT)
+ testActivity.resetLayoutCounter()
+ repo.rearDisplayMode(testActivity, Runnable::run, callback)
+ }
+
+ activityScenario.scenario.onActivity { testActivity ->
+ assert(testActivity.requestedOrientation == ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE)
+ assert(callback.currentSession != null)
+ testActivity.resetLayoutCounter()
+ callback.endSession()
+ }
+ activityScenario.scenario.onActivity { testActivity ->
+ assert(testActivity.requestedOrientation == ActivityInfo.SCREEN_ORIENTATION_PORTRAIT)
+ assert(callback.currentSession == null)
+ }
+ }
+
+ @TargetApi(Build.VERSION_CODES.N)
+ @Test
+ public fun testRearDisplayModeReturnsError(): Unit = testScope.runTest {
+ assumeTrue(Build.VERSION.SDK_INT > Build.VERSION_CODES.N)
+ val extensionComponent = FakeWindowAreaComponent()
+ extensionComponent.currentStatus = WindowAreaComponent.STATUS_UNAVAILABLE
+ val repo = WindowAreaControllerImpl(extensionComponent)
+ val callback = TestWindowAreaSessionCallback()
+ activityScenario.scenario.onActivity { testActivity ->
+ assertFailsWith(
+ exceptionClass = UnsupportedOperationException::class,
+ block = { repo.rearDisplayMode(testActivity, Runnable::run, callback) }
+ )
+ }
+ }
+
+ @TargetApi(Build.VERSION_CODES.N)
+ @Test
+ public fun testRearDisplayModeNullComponent(): Unit = testScope.runTest {
+ assumeTrue(Build.VERSION.SDK_INT > Build.VERSION_CODES.N)
+ val repo = EmptyWindowAreaControllerImpl()
+ val callback = TestWindowAreaSessionCallback()
+ activityScenario.scenario.onActivity { testActivity ->
+ assertFailsWith(
+ exceptionClass = UnsupportedOperationException::class,
+ block = { repo.rearDisplayMode(testActivity, Runnable::run, callback) }
+ )
+ }
+ }
+
+ private class FakeWindowAreaComponent : WindowAreaComponent {
+ val statusListeners = mutableListOf<Consumer<Int>>()
+ var currentStatus = WindowAreaComponent.STATUS_UNSUPPORTED
+ var testActivity: Activity? = null
+ var sessionConsumer: Consumer<Int>? = null
+
+ @RequiresApi(Build.VERSION_CODES.N)
+ override fun addRearDisplayStatusListener(consumer: Consumer<Int>) {
+ statusListeners.add(consumer)
+ consumer.accept(currentStatus)
+ }
+
+ override fun removeRearDisplayStatusListener(consumer: Consumer<Int>) {
+ statusListeners.remove(consumer)
+ }
+
+ override fun addRearDisplayPresentationStatusListener(
+ consumer: Consumer<ExtensionWindowAreaStatus>
+ ) {
+ return
+ }
+
+ override fun removeRearDisplayPresentationStatusListener(
+ consumer: Consumer<ExtensionWindowAreaStatus>
+ ) {
+ return
+ }
+
+ // Fake WindowAreaComponent will change the orientation of the activity to signal
+ // entering rear display mode, as well as ending the session
+ @RequiresApi(Build.VERSION_CODES.N)
+ override fun startRearDisplaySession(
+ activity: Activity,
+ rearDisplaySessionConsumer: Consumer<Int>
+ ) {
+ if (currentStatus != WindowAreaComponent.STATUS_AVAILABLE) {
+ throw WindowAreaController.REAR_DISPLAY_ERROR
+ }
+ testActivity = activity
+ sessionConsumer = rearDisplaySessionConsumer
+ testActivity!!.requestedOrientation = ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE
+ rearDisplaySessionConsumer.accept(WindowAreaComponent.SESSION_STATE_ACTIVE)
+ }
+
+ @RequiresApi(Build.VERSION_CODES.N)
+ override fun endRearDisplaySession() {
+ testActivity?.requestedOrientation = ActivityInfo.SCREEN_ORIENTATION_PORTRAIT
+ sessionConsumer?.accept(WindowAreaComponent.SESSION_STATE_INACTIVE)
+ }
+
+ override fun startRearDisplayPresentationSession(
+ activity: Activity,
+ consumer: Consumer<Int>
+ ) {
+ return
+ }
+
+ override fun endRearDisplayPresentationSession() {
+ return
+ }
+
+ override fun getRearDisplayPresentation(): ExtensionWindowAreaPresentation? {
+ return null
+ }
+
+ @RequiresApi(Build.VERSION_CODES.N)
+ fun updateStatusListeners(newStatus: Int) {
+ currentStatus = newStatus
+ for (consumer in statusListeners) {
+ consumer.accept(currentStatus)
+ }
+ }
+ }
+
+ private class TestWindowAreaSessionCallback : WindowAreaSessionCallback {
+
+ var currentSession: WindowAreaSession? = null
+ var error: Throwable? = null
+
+ override fun onSessionStarted(session: WindowAreaSession) {
+ currentSession = session
+ }
+
+ override fun onSessionEnded() {
+ currentSession = null
+ }
+
+ fun endSession() = currentSession?.close()
+ }
+}
\ No newline at end of file
diff --git a/window/window/src/androidTest/java/androidx/window/embedding/EmbeddingAdapterTest.kt b/window/window/src/androidTest/java/androidx/window/embedding/EmbeddingAdapterTest.kt
index f098cd6..867d6a6 100644
--- a/window/window/src/androidTest/java/androidx/window/embedding/EmbeddingAdapterTest.kt
+++ b/window/window/src/androidTest/java/androidx/window/embedding/EmbeddingAdapterTest.kt
@@ -21,9 +21,13 @@
import androidx.window.extensions.embedding.SplitInfo as OEMSplitInfo
import android.app.Activity
import android.graphics.Color
+import android.os.Binder
+import android.os.IBinder
import androidx.window.WindowTestUtils
import androidx.window.core.ExtensionsUtil
import androidx.window.core.PredicateAdapter
+import androidx.window.embedding.EmbeddingAdapter.Companion.INVALID_ACTIVITY_STACK_TOKEN
+import androidx.window.embedding.EmbeddingAdapter.Companion.INVALID_SPLIT_INFO_TOKEN
import androidx.window.embedding.SplitAttributes.SplitType
import androidx.window.extensions.WindowExtensions
import androidx.window.extensions.embedding.SplitAttributes.LayoutDirection.TOP_TO_BOTTOM
@@ -54,13 +58,14 @@
OEMSplitAttributes.Builder().build(),
)
val expectedSplitInfo = SplitInfo(
- ActivityStack(ArrayList(), isEmpty = true),
- ActivityStack(ArrayList(), isEmpty = true),
+ ActivityStack(ArrayList(), isEmpty = true, INVALID_ACTIVITY_STACK_TOKEN),
+ ActivityStack(ArrayList(), isEmpty = true, INVALID_ACTIVITY_STACK_TOKEN),
SplitAttributes.Builder()
.setSplitType(SplitType.splitEqually())
.setLayoutDirection(SplitAttributes.LayoutDirection.LOCALE)
- .setAnimationBackgroundColor(0)
- .build()
+ .setAnimationBackgroundColor(SplitAttributes.BackgroundColor.DEFAULT)
+ .build(),
+ INVALID_SPLIT_INFO_TOKEN,
)
assertEquals(listOf(expectedSplitInfo), adapter.translate(listOf(oemSplitInfo)))
}
@@ -77,12 +82,13 @@
.build(),
)
val expectedSplitInfo = SplitInfo(
- ActivityStack(ArrayList(), isEmpty = true),
- ActivityStack(ArrayList(), isEmpty = true),
+ ActivityStack(ArrayList(), isEmpty = true, INVALID_ACTIVITY_STACK_TOKEN),
+ ActivityStack(ArrayList(), isEmpty = true, INVALID_ACTIVITY_STACK_TOKEN),
SplitAttributes.Builder()
.setSplitType(SplitType.expandContainers())
.setLayoutDirection(SplitAttributes.LayoutDirection.LOCALE)
- .build()
+ .build(),
+ INVALID_SPLIT_INFO_TOKEN,
)
assertEquals(listOf(expectedSplitInfo), adapter.translate(listOf(oemSplitInfo)))
}
@@ -101,13 +107,14 @@
}
val expectedSplitInfo = SplitInfo(
- ActivityStack(ArrayList(), isEmpty = true),
- ActivityStack(ArrayList(), isEmpty = true),
+ ActivityStack(ArrayList(), isEmpty = true, INVALID_ACTIVITY_STACK_TOKEN),
+ ActivityStack(ArrayList(), isEmpty = true, INVALID_ACTIVITY_STACK_TOKEN),
SplitAttributes.Builder()
.setSplitType(SplitType.ratio(expectedSplitRatio))
// OEMSplitInfo with Vendor API level 1 doesn't provide layoutDirection.
.setLayoutDirection(SplitAttributes.LayoutDirection.LOCALE)
- .build()
+ .build(),
+ INVALID_SPLIT_INFO_TOKEN,
)
assertEquals(listOf(expectedSplitInfo), adapter.translate(listOf(oemSplitInfo)))
}
@@ -129,13 +136,45 @@
.build(),
)
val expectedSplitInfo = SplitInfo(
- ActivityStack(ArrayList(), isEmpty = true),
- ActivityStack(ArrayList(), isEmpty = true),
+ ActivityStack(ArrayList(), isEmpty = true, INVALID_ACTIVITY_STACK_TOKEN),
+ ActivityStack(ArrayList(), isEmpty = true, INVALID_ACTIVITY_STACK_TOKEN),
SplitAttributes.Builder()
.setSplitType(SplitType.splitByHinge(SplitType.ratio(0.3f)))
.setLayoutDirection(SplitAttributes.LayoutDirection.TOP_TO_BOTTOM)
+ .setAnimationBackgroundColor(SplitAttributes.BackgroundColor.color(Color.YELLOW))
+ .build(),
+ INVALID_SPLIT_INFO_TOKEN,
+ )
+ assertEquals(listOf(expectedSplitInfo), adapter.translate(listOf(oemSplitInfo)))
+ }
+
+ @Test
+ fun testTranslateSplitInfoWithApiLevel3() {
+ WindowTestUtils.assumeAtLeastVendorApiLevel(WindowExtensions.VENDOR_API_LEVEL_3)
+ val testStackToken = Binder()
+ val testSplitInfoToken = Binder()
+ val oemSplitInfo = createTestOEMSplitInfo(
+ createTestOEMActivityStack(ArrayList(), true, testStackToken),
+ createTestOEMActivityStack(ArrayList(), true, testStackToken),
+ OEMSplitAttributes.Builder()
+ .setSplitType(
+ OEMSplitAttributes.SplitType.HingeSplitType(
+ OEMSplitAttributes.SplitType.RatioSplitType(0.3f)
+ )
+ ).setLayoutDirection(TOP_TO_BOTTOM)
.setAnimationBackgroundColor(Color.YELLOW)
- .build()
+ .build(),
+ testSplitInfoToken,
+ )
+ val expectedSplitInfo = SplitInfo(
+ ActivityStack(ArrayList(), isEmpty = true, testStackToken),
+ ActivityStack(ArrayList(), isEmpty = true, testStackToken),
+ SplitAttributes.Builder()
+ .setSplitType(SplitType.splitByHinge(SplitType.ratio(0.3f)))
+ .setLayoutDirection(SplitAttributes.LayoutDirection.TOP_TO_BOTTOM)
+ .setAnimationBackgroundColor(SplitAttributes.BackgroundColor.color(Color.YELLOW))
+ .build(),
+ testSplitInfoToken,
)
assertEquals(listOf(expectedSplitInfo), adapter.translate(listOf(oemSplitInfo)))
}
@@ -143,7 +182,8 @@
private fun createTestOEMSplitInfo(
testPrimaryActivityStack: OEMActivityStack,
testSecondaryActivityStack: OEMActivityStack,
- testSplitAttributes: OEMSplitAttributes
+ testSplitAttributes: OEMSplitAttributes,
+ testToken: IBinder = INVALID_SPLIT_INFO_TOKEN,
): OEMSplitInfo {
return mock<OEMSplitInfo>().apply {
whenever(primaryActivityStack).thenReturn(testPrimaryActivityStack)
@@ -151,16 +191,23 @@
if (ExtensionsUtil.safeVendorApiLevel >= WindowExtensions.VENDOR_API_LEVEL_2) {
whenever(splitAttributes).thenReturn(testSplitAttributes)
}
+ if (ExtensionsUtil.safeVendorApiLevel >= WindowExtensions.VENDOR_API_LEVEL_3) {
+ whenever(token).thenReturn(testToken)
+ }
}
}
private fun createTestOEMActivityStack(
testActivities: List<Activity>,
- testIsEmpty: Boolean
+ testIsEmpty: Boolean,
+ testToken: IBinder = INVALID_ACTIVITY_STACK_TOKEN,
): OEMActivityStack {
return mock<OEMActivityStack>().apply {
whenever(activities).thenReturn(testActivities)
whenever(isEmpty).thenReturn(testIsEmpty)
+ if (ExtensionsUtil.safeVendorApiLevel >= WindowExtensions.VENDOR_API_LEVEL_3) {
+ whenever(token).thenReturn(testToken)
+ }
}
}
}
\ No newline at end of file
diff --git a/window/window/src/androidTest/java/androidx/window/embedding/EmbeddingRuleConstructionTests.kt b/window/window/src/androidTest/java/androidx/window/embedding/EmbeddingRuleConstructionTests.kt
index 62dcd3b..582d047 100644
--- a/window/window/src/androidTest/java/androidx/window/embedding/EmbeddingRuleConstructionTests.kt
+++ b/window/window/src/androidTest/java/androidx/window/embedding/EmbeddingRuleConstructionTests.kt
@@ -81,7 +81,7 @@
val expectedSplitLayout = SplitAttributes.Builder()
.setSplitType(SplitAttributes.SplitType.ratio(0.5f))
.setLayoutDirection(LOCALE)
- .setAnimationBackgroundColor(0)
+ .setAnimationBackgroundColor(SplitAttributes.BackgroundColor.DEFAULT)
.build()
assertNull(rule.tag)
assertEquals(SPLIT_MIN_DIMENSION_DP_DEFAULT, rule.minWidthDp)
@@ -133,7 +133,7 @@
val expectedSplitLayout = SplitAttributes.Builder()
.setSplitType(SplitAttributes.SplitType.ratio(0.3f))
.setLayoutDirection(TOP_TO_BOTTOM)
- .setAnimationBackgroundColor(Color.BLUE)
+ .setAnimationBackgroundColor(SplitAttributes.BackgroundColor.color(Color.BLUE))
.build()
assertEquals(TEST_TAG, rule.tag)
assertEquals(NEVER, rule.finishPrimaryWithSecondary)
@@ -154,7 +154,7 @@
val expectedSplitLayout = SplitAttributes.Builder()
.setSplitType(SplitAttributes.SplitType.ratio(0.5f))
.setLayoutDirection(LOCALE)
- .setAnimationBackgroundColor(0)
+ .setAnimationBackgroundColor(SplitAttributes.BackgroundColor.DEFAULT)
.build()
assertNull(rule.tag)
assertEquals(SPLIT_MIN_DIMENSION_DP_DEFAULT, rule.minWidthDp)
@@ -180,7 +180,7 @@
val expectedSplitLayout = SplitAttributes.Builder()
.setSplitType(SplitAttributes.SplitType.ratio(0.3f))
.setLayoutDirection(LEFT_TO_RIGHT)
- .setAnimationBackgroundColor(Color.GREEN)
+ .setAnimationBackgroundColor(SplitAttributes.BackgroundColor.color(Color.GREEN))
.build()
filters.add(
SplitPairFilter(
@@ -382,7 +382,7 @@
val expectedSplitLayout = SplitAttributes.Builder()
.setSplitType(SplitAttributes.SplitType.ratio(0.5f))
.setLayoutDirection(LOCALE)
- .setAnimationBackgroundColor(0)
+ .setAnimationBackgroundColor(SplitAttributes.BackgroundColor.DEFAULT)
.build()
assertNull(rule.tag)
assertEquals(SPLIT_MIN_DIMENSION_DP_DEFAULT, rule.minWidthDp)
@@ -437,7 +437,8 @@
val expectedSplitLayout = SplitAttributes.Builder()
.setSplitType(SplitAttributes.SplitType.ratio(0.3f))
.setLayoutDirection(BOTTOM_TO_TOP)
- .setAnimationBackgroundColor(application.resources.getColor(R.color.testColor, null))
+ .setAnimationBackgroundColor(SplitAttributes.BackgroundColor.color(
+ application.resources.getColor(R.color.testColor, null)))
.build()
assertEquals(TEST_TAG, rule.tag)
assertEquals(ALWAYS, rule.finishPrimaryWithPlaceholder)
@@ -465,7 +466,7 @@
val expectedSplitLayout = SplitAttributes.Builder()
.setSplitType(SplitAttributes.SplitType.ratio(0.5f))
.setLayoutDirection(LOCALE)
- .setAnimationBackgroundColor(0)
+ .setAnimationBackgroundColor(SplitAttributes.BackgroundColor.DEFAULT)
.build()
assertEquals(expectedSplitLayout, rule.defaultSplitAttributes)
assertTrue(rule.checkParentBounds(density, minValidWindowBounds()))
@@ -489,7 +490,7 @@
val expectedSplitLayout = SplitAttributes.Builder()
.setSplitType(SplitAttributes.SplitType.ratio(0.3f))
.setLayoutDirection(LEFT_TO_RIGHT)
- .setAnimationBackgroundColor(Color.GREEN)
+ .setAnimationBackgroundColor(SplitAttributes.BackgroundColor.color(Color.GREEN))
.build()
val rule = SplitPlaceholderRule.Builder(filters, intent)
.setMinWidthDp(123)
diff --git a/window/window/src/androidTest/java/androidx/window/embedding/SafeActivityEmbeddingComponentProviderTest.kt b/window/window/src/androidTest/java/androidx/window/embedding/SafeActivityEmbeddingComponentProviderTest.kt
new file mode 100644
index 0000000..3b93a9a
--- /dev/null
+++ b/window/window/src/androidTest/java/androidx/window/embedding/SafeActivityEmbeddingComponentProviderTest.kt
@@ -0,0 +1,79 @@
+/*
+ * Copyright 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR 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.embedding
+
+import android.util.Log
+import androidx.window.core.ConsumerAdapter
+import androidx.window.extensions.WindowExtensions
+import androidx.window.extensions.WindowExtensionsProvider
+import org.junit.Assert.assertNull
+import org.junit.Test
+
+/**
+ * An integration test to verify that if [WindowExtensionsProvider] is present then
+ * [SafeActivityEmbeddingComponentProvider.activityEmbeddingComponent] will return a value.
+ * This can fail if the implementation of window:extensions:extensions
+ * does not have the expected API.
+ */
+class SafeActivityEmbeddingComponentProviderTest {
+
+ /**
+ * Test that if [WindowExtensionsProvider] is available then
+ * use [SafeActivityEmbeddingComponentProvider.activityEmbeddingComponent] to validate.
+ * If [WindowExtensions.getActivityEmbeddingComponent] matches contract,
+ * return a non-null value.
+ * If it doesn't match, it will return a null.
+ *
+ * TODO(b/267708462) : add a more reliable test
+ */
+ @Test
+ fun activityEmbeddingComponentIsAvailable_ifProviderIsAvailable() {
+ val loader = SafeActivityEmbeddingComponentProviderTest::class.java.classLoader!!
+ val consumerAdapter = ConsumerAdapter(loader)
+ val windowExtensions: WindowExtensions = try {
+ WindowExtensionsProvider.getWindowExtensions()
+ } catch (e: UnsupportedOperationException) {
+ Log.d(TAG, "Device doesn't have WindowExtensions available")
+ return
+ }
+ val safeComponent = SafeActivityEmbeddingComponentProvider(
+ loader,
+ consumerAdapter,
+ windowExtensions
+ )
+ .activityEmbeddingComponent
+ try {
+ val actualComponent = windowExtensions.activityEmbeddingComponent
+ if (actualComponent == null) {
+ assertNull(safeComponent)
+ } else {
+ // TODO(b/267573854) : verify upon each api level
+ // TODO(b/267708462) : more reliable test for testing actual method matching
+ if (safeComponent == null) {
+ Log.d(TAG, "ActivityEmbeddingComponent on device doesn't match our constraints")
+ }
+ }
+ } catch (e: UnsupportedOperationException) {
+ // Invalid implementation of extensions
+ assertNull(safeComponent)
+ }
+ }
+
+ companion object {
+ private const val TAG = "SafeActivityEmbeddingComponentProviderTest"
+ }
+}
\ No newline at end of file
diff --git a/window/window/src/test/java/androidx/window/embedding/SplitAttributesTest.kt b/window/window/src/androidTest/java/androidx/window/embedding/SplitAttributesTest.kt
similarity index 92%
rename from window/window/src/test/java/androidx/window/embedding/SplitAttributesTest.kt
rename to window/window/src/androidTest/java/androidx/window/embedding/SplitAttributesTest.kt
index 96571cc..69c507d 100644
--- a/window/window/src/test/java/androidx/window/embedding/SplitAttributesTest.kt
+++ b/window/window/src/androidTest/java/androidx/window/embedding/SplitAttributesTest.kt
@@ -36,27 +36,27 @@
val attrs1 = SplitAttributes.Builder()
.setSplitType(SplitType.splitEqually())
.setLayoutDirection(LOCALE)
- .setAnimationBackgroundColor(0)
+ .setAnimationBackgroundColor(SplitAttributes.BackgroundColor.DEFAULT)
.build()
val attrs2 = SplitAttributes.Builder()
.setSplitType(SplitType.splitByHinge())
.setLayoutDirection(LOCALE)
- .setAnimationBackgroundColor(0)
+ .setAnimationBackgroundColor(SplitAttributes.BackgroundColor.DEFAULT)
.build()
val attrs3 = SplitAttributes.Builder()
.setSplitType(SplitType.splitByHinge())
.setLayoutDirection(TOP_TO_BOTTOM)
- .setAnimationBackgroundColor(0)
+ .setAnimationBackgroundColor(SplitAttributes.BackgroundColor.DEFAULT)
.build()
val attrs4 = SplitAttributes.Builder()
.setSplitType(SplitType.splitByHinge())
.setLayoutDirection(TOP_TO_BOTTOM)
- .setAnimationBackgroundColor(Color.GREEN)
+ .setAnimationBackgroundColor(SplitAttributes.BackgroundColor.color(Color.GREEN))
.build()
val attrs5 = SplitAttributes.Builder()
.setSplitType(SplitType.splitByHinge())
.setLayoutDirection(TOP_TO_BOTTOM)
- .setAnimationBackgroundColor(Color.GREEN)
+ .setAnimationBackgroundColor(SplitAttributes.BackgroundColor.color(Color.GREEN))
.build()
assertNotEquals(attrs1, attrs2)
diff --git a/window/window/src/androidTest/java/androidx/window/layout/SafeWindowLayoutComponentProviderTest.kt b/window/window/src/androidTest/java/androidx/window/layout/SafeWindowLayoutComponentProviderTest.kt
index 246e9a3..bc78a38 100644
--- a/window/window/src/androidTest/java/androidx/window/layout/SafeWindowLayoutComponentProviderTest.kt
+++ b/window/window/src/androidTest/java/androidx/window/layout/SafeWindowLayoutComponentProviderTest.kt
@@ -16,9 +16,9 @@
package androidx.window.layout
+import android.util.Log
import androidx.window.core.ConsumerAdapter
import androidx.window.extensions.WindowExtensionsProvider
-import org.junit.Assert.assertNotNull
import org.junit.Assert.assertNull
import org.junit.Test
@@ -46,11 +46,17 @@
if (actualComponent == null) {
assertNull(safeComponent)
} else {
- assertNotNull(safeComponent)
+ // TODO(b/267831038): verify upon each api level
+ // TODO(b/267708462): more reliable test for testing actual method matching
+ Log.d(TAG, "WindowLayoutComponent on device doesn't match our constraints")
}
} catch (e: UnsupportedOperationException) {
// Invalid implementation of extensions
assertNull(safeComponent)
}
}
+
+ companion object {
+ private const val TAG = "SafeWindowLayoutComponentProviderTest"
+ }
}
\ No newline at end of file
diff --git a/window/window/src/main/java/androidx/window/area/EmptyWindowAreaControllerImpl.kt b/window/window/src/main/java/androidx/window/area/EmptyWindowAreaControllerImpl.kt
new file mode 100644
index 0000000..996c7ad
--- /dev/null
+++ b/window/window/src/main/java/androidx/window/area/EmptyWindowAreaControllerImpl.kt
@@ -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.window.area
+
+import android.app.Activity
+import androidx.window.core.ExperimentalWindowApi
+import kotlinx.coroutines.flow.Flow
+import kotlinx.coroutines.flow.flowOf
+import java.util.concurrent.Executor
+
+/**
+ * Empty Implementation for devices that do not
+ * support the [WindowAreaController] functionality
+ */
+@ExperimentalWindowApi
+internal class EmptyWindowAreaControllerImpl : WindowAreaController {
+ override fun rearDisplayStatus(): Flow<WindowAreaStatus> {
+ return flowOf(WindowAreaStatus.UNSUPPORTED)
+ }
+
+ override fun rearDisplayMode(
+ activity: Activity,
+ executor: Executor,
+ windowAreaSessionCallback: WindowAreaSessionCallback
+ ) {
+ throw WindowAreaController.REAR_DISPLAY_ERROR
+ }
+}
\ No newline at end of file
diff --git a/appsearch/appsearch/src/main/java/androidx/appsearch/observer/AppSearchObserverCallback.java b/window/window/src/main/java/androidx/window/area/RearDisplaySessionImpl.kt
similarity index 61%
copy from appsearch/appsearch/src/main/java/androidx/appsearch/observer/AppSearchObserverCallback.java
copy to window/window/src/main/java/androidx/window/area/RearDisplaySessionImpl.kt
index c01917e..9a5bbd3 100644
--- a/appsearch/appsearch/src/main/java/androidx/appsearch/observer/AppSearchObserverCallback.java
+++ b/window/window/src/main/java/androidx/window/area/RearDisplaySessionImpl.kt
@@ -14,15 +14,17 @@
* limitations under the License.
*/
-package androidx.appsearch.observer;
+package androidx.window.area
-import androidx.annotation.RestrictTo;
+import androidx.window.core.ExperimentalWindowApi
+import androidx.window.extensions.area.WindowAreaComponent
-/**
- * @deprecated use {@link ObserverCallback} instead.
- * @hide
- */
-// TODO(b/209734214): Remove this after dogfooders and devices have migrated away from this class.
-@Deprecated
-@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
-public interface AppSearchObserverCallback extends ObserverCallback {}
+@ExperimentalWindowApi
+internal class RearDisplaySessionImpl(
+ private val windowAreaComponent: WindowAreaComponent
+) : WindowAreaSession {
+
+ override fun close() {
+ windowAreaComponent.endRearDisplaySession()
+ }
+}
diff --git a/window/window/src/main/java/androidx/window/area/WindowAreaController.kt b/window/window/src/main/java/androidx/window/area/WindowAreaController.kt
new file mode 100644
index 0000000..30ca792
--- /dev/null
+++ b/window/window/src/main/java/androidx/window/area/WindowAreaController.kt
@@ -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.window.area
+
+import android.app.Activity
+import android.os.Build
+import android.util.Log
+import androidx.annotation.RestrictTo
+import androidx.window.core.BuildConfig
+import androidx.window.core.ExperimentalWindowApi
+import androidx.window.core.VerificationMode
+import androidx.window.extensions.WindowExtensionsProvider
+import androidx.window.extensions.area.WindowAreaComponent
+import java.util.concurrent.Executor
+import kotlinx.coroutines.flow.Flow
+
+/**
+ * An interface to provide the information and behavior around moving windows between
+ * displays or display areas on a device.
+ */
+@ExperimentalWindowApi
+interface WindowAreaController {
+
+ /*
+ Marked with RestrictTo as we iterate and define the
+ Kotlin API we want to provide.
+ */
+ @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
+ public fun rearDisplayStatus(): Flow<WindowAreaStatus>
+
+ /*
+ Marked with RestrictTo as we iterate and define the
+ Kotlin API we want to provide.
+ */
+ @Throws(UnsupportedOperationException::class)
+ @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
+ public fun rearDisplayMode(
+ activity: Activity,
+ executor: Executor,
+ windowAreaSessionCallback: WindowAreaSessionCallback
+ )
+
+ public companion object {
+ internal val REAR_DISPLAY_ERROR =
+ UnsupportedOperationException("Rear Display mode cannot be enabled currently")
+
+ private val TAG = WindowAreaController::class.simpleName
+
+ private var decorator: WindowAreaControllerDecorator = EmptyDecorator
+
+ /**
+ * Provides an instance of [WindowAreaController].
+ */
+ @JvmName("getOrCreate")
+ @JvmStatic
+ public fun getOrCreate(): WindowAreaController {
+ var windowAreaComponentExtensions: WindowAreaComponent?
+ try {
+ windowAreaComponentExtensions = WindowExtensionsProvider
+ .getWindowExtensions()
+ .windowAreaComponent
+ } catch (t: Throwable) {
+ if (BuildConfig.verificationMode == VerificationMode.STRICT) {
+ Log.d(TAG, "Failed to load WindowExtensions")
+ }
+ windowAreaComponentExtensions = null
+ }
+ val controller =
+ if (Build.VERSION.SDK_INT < Build.VERSION_CODES.N ||
+ windowAreaComponentExtensions == null) {
+ EmptyWindowAreaControllerImpl()
+ } else {
+ WindowAreaControllerImpl(windowAreaComponentExtensions)
+ }
+ return decorator.decorate(controller)
+ }
+
+ @JvmStatic
+ @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
+ public fun overrideDecorator(overridingDecorator: WindowAreaControllerDecorator) {
+ decorator = overridingDecorator
+ }
+
+ @JvmStatic
+ @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
+ public fun reset() {
+ decorator = EmptyDecorator
+ }
+ }
+}
+
+/**
+ * Decorator that allows us to provide different functionality
+ * in our window-testing artifact.
+ */
+@ExperimentalWindowApi
+@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
+public interface WindowAreaControllerDecorator {
+ /**
+ * Returns an instance of [WindowAreaController] associated to the [Activity]
+ */
+ @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
+ public fun decorate(controller: WindowAreaController): WindowAreaController
+}
+
+@ExperimentalWindowApi
+private object EmptyDecorator : WindowAreaControllerDecorator {
+ override fun decorate(controller: WindowAreaController): WindowAreaController {
+ return controller
+ }
+}
diff --git a/window/window/src/main/java/androidx/window/area/WindowAreaControllerImpl.kt b/window/window/src/main/java/androidx/window/area/WindowAreaControllerImpl.kt
new file mode 100644
index 0000000..64e19eb
--- /dev/null
+++ b/window/window/src/main/java/androidx/window/area/WindowAreaControllerImpl.kt
@@ -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.window.area
+
+import android.app.Activity
+import android.os.Build
+import android.util.Log
+import androidx.annotation.RequiresApi
+import androidx.window.core.BuildConfig
+import androidx.window.core.ExperimentalWindowApi
+import androidx.window.core.VerificationMode
+import androidx.window.extensions.area.WindowAreaComponent
+import androidx.window.extensions.core.util.function.Consumer
+import java.util.concurrent.Executor
+import kotlinx.coroutines.channels.awaitClose
+import kotlinx.coroutines.flow.Flow
+import kotlinx.coroutines.flow.callbackFlow
+import kotlinx.coroutines.flow.distinctUntilChanged
+
+/**
+ * Implementation of WindowAreaController for devices
+ * that do implement the WindowAreaComponent on device.
+ *
+ * Requires [Build.VERSION_CODES.N] due to the use of [Consumer].
+ * Will not be created though on API levels lower than
+ * [Build.VERSION_CODES.S] as that's the min level of support for
+ * this functionality.
+ */
+@ExperimentalWindowApi
+@RequiresApi(Build.VERSION_CODES.N)
+internal class WindowAreaControllerImpl(
+ private val windowAreaComponent: WindowAreaComponent
+) : WindowAreaController {
+
+ private lateinit var rearDisplaySessionConsumer: Consumer<Int>
+ private var currentStatus: WindowAreaStatus? = null
+
+ override fun rearDisplayStatus(): Flow<WindowAreaStatus> {
+ return callbackFlow {
+ val listener = Consumer<Int> { status ->
+ currentStatus = WindowAreaStatus.translate(status)
+ channel.trySend(currentStatus ?: WindowAreaStatus.UNSUPPORTED)
+ }
+ windowAreaComponent.addRearDisplayStatusListener(listener)
+ awaitClose {
+ windowAreaComponent.removeRearDisplayStatusListener(listener)
+ }
+ }.distinctUntilChanged()
+ }
+
+ override fun rearDisplayMode(
+ activity: Activity,
+ executor: Executor,
+ windowAreaSessionCallback: WindowAreaSessionCallback
+ ) {
+ // If we already have a status value that is not [WindowAreaStatus.AVAILABLE]
+ // we should throw an exception quick to indicate they tried to enable
+ // RearDisplay mode when it was not available.
+ if (currentStatus != null && currentStatus != WindowAreaStatus.AVAILABLE) {
+ throw WindowAreaController.REAR_DISPLAY_ERROR
+ }
+ rearDisplaySessionConsumer =
+ RearDisplaySessionConsumer(windowAreaSessionCallback, windowAreaComponent)
+ windowAreaComponent.startRearDisplaySession(activity, rearDisplaySessionConsumer)
+ }
+
+ internal class RearDisplaySessionConsumer(
+ private val appCallback: WindowAreaSessionCallback,
+ private val extensionsComponent: WindowAreaComponent
+ ) : Consumer<Int> {
+
+ private var session: WindowAreaSession? = null
+
+ override fun accept(t: Int) {
+ when (t) {
+ WindowAreaComponent.SESSION_STATE_ACTIVE -> onSessionStarted()
+ WindowAreaComponent.SESSION_STATE_INACTIVE -> onSessionFinished()
+ else -> {
+ if (BuildConfig.verificationMode == VerificationMode.STRICT) {
+ Log.d(TAG, "Received an unknown session status value: $t")
+ }
+ onSessionFinished()
+ }
+ }
+ }
+
+ private fun onSessionStarted() {
+ session = RearDisplaySessionImpl(extensionsComponent)
+ session?.let { appCallback.onSessionStarted(it) }
+ }
+
+ private fun onSessionFinished() {
+ session = null
+ appCallback.onSessionEnded()
+ }
+ }
+
+ internal companion object {
+ private val TAG = WindowAreaControllerImpl::class.simpleName
+ /*
+ Chosen as 10 for a base default value. We shouldn't be receiving
+ many changes to window area status so this is enough capacity
+ to not end up blocking.
+ */
+ private const val BUFFER_CAPACITY = 10
+ }
+}
diff --git a/appsearch/appsearch/src/main/java/androidx/appsearch/observer/AppSearchObserverCallback.java b/window/window/src/main/java/androidx/window/area/WindowAreaSession.kt
similarity index 62%
copy from appsearch/appsearch/src/main/java/androidx/appsearch/observer/AppSearchObserverCallback.java
copy to window/window/src/main/java/androidx/window/area/WindowAreaSession.kt
index c01917e..6cdbd12 100644
--- a/appsearch/appsearch/src/main/java/androidx/appsearch/observer/AppSearchObserverCallback.java
+++ b/window/window/src/main/java/androidx/window/area/WindowAreaSession.kt
@@ -14,15 +14,16 @@
* limitations under the License.
*/
-package androidx.appsearch.observer;
+package androidx.window.area
-import androidx.annotation.RestrictTo;
+import androidx.window.core.ExperimentalWindowApi
/**
- * @deprecated use {@link ObserverCallback} instead.
- * @hide
+ * Session interface to represent a long-standing
+ * WindowArea mode or feature that provides a handle
+ * to close the session.
*/
-// TODO(b/209734214): Remove this after dogfooders and devices have migrated away from this class.
-@Deprecated
-@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
-public interface AppSearchObserverCallback extends ObserverCallback {}
+@ExperimentalWindowApi
+public interface WindowAreaSession {
+ fun close()
+}
\ No newline at end of file
diff --git a/appsearch/appsearch/src/main/java/androidx/appsearch/observer/AppSearchObserverCallback.java b/window/window/src/main/java/androidx/window/area/WindowAreaSessionCallback.kt
similarity index 61%
copy from appsearch/appsearch/src/main/java/androidx/appsearch/observer/AppSearchObserverCallback.java
copy to window/window/src/main/java/androidx/window/area/WindowAreaSessionCallback.kt
index c01917e..80842c4 100644
--- a/appsearch/appsearch/src/main/java/androidx/appsearch/observer/AppSearchObserverCallback.java
+++ b/window/window/src/main/java/androidx/window/area/WindowAreaSessionCallback.kt
@@ -14,15 +14,18 @@
* limitations under the License.
*/
-package androidx.appsearch.observer;
+package androidx.window.area
-import androidx.annotation.RestrictTo;
+import androidx.window.core.ExperimentalWindowApi
-/**
- * @deprecated use {@link ObserverCallback} instead.
- * @hide
+/** Callback to update the client on the WindowArea Session being
+ * started and ended.
+ * TODO(b/207720511) Move to window-java module when Kotlin API Finalized
*/
-// TODO(b/209734214): Remove this after dogfooders and devices have migrated away from this class.
-@Deprecated
-@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
-public interface AppSearchObserverCallback extends ObserverCallback {}
+@ExperimentalWindowApi
+interface WindowAreaSessionCallback {
+
+ fun onSessionStarted(session: WindowAreaSession)
+
+ fun onSessionEnded()
+}
\ No newline at end of file
diff --git a/window/window/src/main/java/androidx/window/area/WindowAreaStatus.kt b/window/window/src/main/java/androidx/window/area/WindowAreaStatus.kt
new file mode 100644
index 0000000..f60d8f5
--- /dev/null
+++ b/window/window/src/main/java/androidx/window/area/WindowAreaStatus.kt
@@ -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.window.area
+
+import androidx.window.core.ExperimentalWindowApi
+import androidx.window.extensions.area.WindowAreaComponent
+
+/**
+ * Represents a window area status.
+ */
+@ExperimentalWindowApi
+class WindowAreaStatus private constructor(private val mDescription: String) {
+ override fun toString(): String {
+ return mDescription
+ }
+
+ companion object {
+ /**
+ * Status representing that the WindowArea feature is not a supported
+ * feature on the device.
+ */
+ @JvmField
+ val UNSUPPORTED = WindowAreaStatus("UNSUPPORTED")
+
+ /**
+ * Status representing that the WindowArea feature is currently not available
+ * to be enabled. This could be due to another process has enabled it, or that the
+ * current device configuration doesn't allow it.
+ */
+ @JvmField
+ val UNAVAILABLE = WindowAreaStatus("UNAVAILABLE")
+
+ /**
+ * Status representing that the WindowArea feature is available to be enabled.
+ */
+ @JvmField
+ val AVAILABLE = WindowAreaStatus("AVAILABLE")
+
+ @JvmStatic
+ internal fun translate(status: Int): WindowAreaStatus {
+ return when (status) {
+ WindowAreaComponent.STATUS_AVAILABLE -> AVAILABLE
+ WindowAreaComponent.STATUS_UNAVAILABLE -> UNAVAILABLE
+ else -> UNSUPPORTED
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/window/window/src/main/java/androidx/window/embedding/ActivityEmbeddingController.kt b/window/window/src/main/java/androidx/window/embedding/ActivityEmbeddingController.kt
index 7a9574d..c202de0 100644
--- a/window/window/src/main/java/androidx/window/embedding/ActivityEmbeddingController.kt
+++ b/window/window/src/main/java/androidx/window/embedding/ActivityEmbeddingController.kt
@@ -17,7 +17,10 @@
package androidx.window.embedding
import android.app.Activity
+import android.app.ActivityOptions
import android.content.Context
+import android.os.IBinder
+import androidx.window.core.ExperimentalWindowApi
import java.util.concurrent.locks.ReentrantLock
import kotlin.concurrent.withLock
@@ -36,6 +39,68 @@
fun isActivityEmbedded(activity: Activity): Boolean =
embeddingBackend.isActivityEmbedded(activity)
+ /**
+ * Returns the [ActivityStack] that this [activity] is part of when it is being organized in the
+ * embedding container and associated with a [SplitInfo]. Returns `null` if there is no such
+ * [ActivityStack].
+ *
+ * @param activity The [Activity] to check.
+ * @return the [ActivityStack] that this [activity] is part of, or `null` if there is no such
+ * [ActivityStack].
+ */
+ @ExperimentalWindowApi
+ fun getActivityStack(activity: Activity): ActivityStack? =
+ embeddingBackend.getActivityStack(activity)
+
+ /**
+ * Sets the launching [ActivityStack] to the given [android.app.ActivityOptions].
+ *
+ * @param options The [android.app.ActivityOptions] to be updated.
+ * @param token The token of the [ActivityStack] to be set.
+ */
+ internal fun setLaunchingActivityStack(
+ options: ActivityOptions,
+ token: IBinder
+ ): ActivityOptions {
+ return embeddingBackend.setLaunchingActivityStack(options, token)
+ }
+
+ /**
+ * Finishes a set of [activityStacks][ActivityStack] from the lowest to the highest z-order
+ * regardless of the order of [ActivityStack] set.
+ *
+ * If the remaining [ActivityStack] from a split participates in other splits with other
+ * `activityStacks`, they might be showing instead. For example, if activityStack A splits with
+ * activityStack B and C, and activityStack C covers activityStack B, finishing activityStack C
+ * might make the split of activityStack A and B show.
+ *
+ * If all associated `activityStacks` of a [ActivityStack] are finished, the [ActivityStack]
+ * will be expanded to fill the parent task container. This is useful to expand the primary
+ * container as the sample linked below shows.
+ *
+ * **Note** that it's caller's responsibility to check whether this API is supported by calling
+ * [isFinishingActivityStacksSupported]. If not, an alternative approach to finishing all
+ * containers above a particular activity can be to launch it again with flag
+ * [android.content.Intent.FLAG_ACTIVITY_CLEAR_TOP].
+ *
+ * @param activityStacks The set of [ActivityStack] to be finished.
+ * @throws UnsupportedOperationException if this device doesn't support this API and
+ * [isFinishingActivityStacksSupported] returns `false`.
+ * @sample androidx.window.samples.embedding.expandPrimaryContainer
+ */
+ @ExperimentalWindowApi
+ fun finishActivityStacks(activityStacks: Set<ActivityStack>) =
+ embeddingBackend.finishActivityStacks(activityStacks)
+
+ /**
+ * Checks whether [finishActivityStacks] is supported.
+ *
+ * @return `true` if [finishActivityStacks] is supported on the device, `false` otherwise.
+ */
+ @ExperimentalWindowApi
+ fun isFinishingActivityStacksSupported(): Boolean =
+ embeddingBackend.isFinishActivityStacksSupported()
+
companion object {
@Volatile
private var globalInstance: ActivityEmbeddingController? = null
diff --git a/window/window/src/main/java/androidx/window/embedding/ActivityOptionsCompat.kt b/window/window/src/main/java/androidx/window/embedding/ActivityOptionsCompat.kt
new file mode 100644
index 0000000..7d4d122
--- /dev/null
+++ b/window/window/src/main/java/androidx/window/embedding/ActivityOptionsCompat.kt
@@ -0,0 +1,87 @@
+/*
+ * Copyright 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+@file:JvmName("ActivityOptionsCompat")
+
+package androidx.window.embedding
+
+import android.app.Activity
+import android.app.ActivityOptions
+import android.content.Context
+import androidx.window.core.ExperimentalWindowApi
+import androidx.window.core.ExtensionsUtil
+import androidx.window.extensions.WindowExtensions
+
+private const val TAG = "ActivityOptionsCompat"
+
+/**
+ * Sets the launching [ActivityStack] to the given [android.app.ActivityOptions].
+ *
+ * If the device doesn't support setting launching, [UnsupportedOperationException] will be thrown.
+ * @see isSetLaunchingActivityStackSupported
+ *
+ * @param context The [android.content.Context] that is going to be used for launching
+ * activity with this [android.app.ActivityOptions], which is usually be the [android.app.Activity]
+ * of the app that hosts the task.
+ * @param activityStack The target [ActivityStack] for launching.
+ * @throws UnsupportedOperationException if this device doesn't support this API.
+ */
+@ExperimentalWindowApi
+fun ActivityOptions.setLaunchingActivityStack(
+ context: Context,
+ activityStack: ActivityStack
+): ActivityOptions = let {
+ if (!isSetLaunchingActivityStackSupported()) {
+ throw UnsupportedOperationException("#setLaunchingActivityStack is not " +
+ "supported on the device.")
+ } else {
+ ActivityEmbeddingController.getInstance(context)
+ .setLaunchingActivityStack(this, activityStack.token)
+ }
+}
+
+/**
+ * Sets the launching [ActivityStack] to the [android.app.ActivityOptions] by the
+ * given [activity]. That is, the [ActivityStack] of the given [activity] is the
+ * [ActivityStack] used for launching.
+ *
+ * If the device doesn't support setting launching or no available [ActivityStack]
+ * can be found from the given [activity], [UnsupportedOperationException] will be thrown.
+ * @see isSetLaunchingActivityStackSupported
+ *
+ * @param activity The existing [android.app.Activity] on the target [ActivityStack].
+ * @throws UnsupportedOperationException if this device doesn't support this API or no
+ * available [ActivityStack] can be found.
+ */
+@ExperimentalWindowApi
+fun ActivityOptions.setLaunchingActivityStack(activity: Activity): ActivityOptions {
+ val activityStack =
+ ActivityEmbeddingController.getInstance(activity).getActivityStack(activity)
+ return if (activityStack != null) {
+ setLaunchingActivityStack(activity, activityStack)
+ } else {
+ throw UnsupportedOperationException("No available ActivityStack found. " +
+ "The given activity may not be embedded.")
+ }
+}
+
+/**
+ * Return `true` if the [setLaunchingActivityStack] APIs is supported and can be used
+ * to set the launching [ActivityStack]. Otherwise, return `false`.
+ */
+@ExperimentalWindowApi
+fun ActivityOptions.isSetLaunchingActivityStackSupported(): Boolean {
+ return ExtensionsUtil.safeVendorApiLevel >= WindowExtensions.VENDOR_API_LEVEL_3
+}
diff --git a/window/window/src/main/java/androidx/window/embedding/ActivityStack.kt b/window/window/src/main/java/androidx/window/embedding/ActivityStack.kt
index 310ce17..b120d25 100644
--- a/window/window/src/main/java/androidx/window/embedding/ActivityStack.kt
+++ b/window/window/src/main/java/androidx/window/embedding/ActivityStack.kt
@@ -16,6 +16,7 @@
package androidx.window.embedding
import android.app.Activity
+import android.os.IBinder
/**
* A container that holds a stack of activities, overlapping and bound to the same rectangle on the
@@ -38,7 +39,11 @@
* process(es), [activitiesInProcess] will return an empty list, but this method will return
* `false`.
*/
- val isEmpty: Boolean = false
+ val isEmpty: Boolean,
+ /**
+ * A token uniquely identifying this `ActivityStack`.
+ */
+ internal val token: IBinder,
) {
operator fun contains(activity: Activity): Boolean {
@@ -53,6 +58,7 @@
if (activitiesInProcess != other.activitiesInProcess) return false
if (isEmpty != other.isEmpty) return false
+ if (token != other.token) return false
return true
}
@@ -60,6 +66,7 @@
override fun hashCode(): Int {
var result = activitiesInProcess.hashCode()
result = 31 * result + isEmpty.hashCode()
+ result = 31 * result + token.hashCode()
return result
}
@@ -67,5 +74,6 @@
"ActivityStack{" +
"activitiesInProcess=$activitiesInProcess" +
", isEmpty=$isEmpty" +
+ ", token=$token" +
"}"
}
diff --git a/window/window/src/main/java/androidx/window/embedding/EmbeddingAdapter.kt b/window/window/src/main/java/androidx/window/embedding/EmbeddingAdapter.kt
index c38e4f3..d5bc366 100644
--- a/window/window/src/main/java/androidx/window/embedding/EmbeddingAdapter.kt
+++ b/window/window/src/main/java/androidx/window/embedding/EmbeddingAdapter.kt
@@ -32,6 +32,7 @@
import android.app.Activity
import android.content.Context
import android.content.Intent
+import android.os.Binder
import android.util.LayoutDirection
import android.view.WindowMetrics
import androidx.window.core.ExtensionsUtil
@@ -50,17 +51,6 @@
import androidx.window.extensions.embedding.SplitPairRule.FINISH_NEVER
import androidx.window.layout.WindowMetricsCalculator
import androidx.window.layout.adapter.extensions.ExtensionsWindowLayoutInfoAdapter
-import kotlin.Any
-import kotlin.Float
-import kotlin.IllegalArgumentException
-import kotlin.IllegalStateException
-import kotlin.Int
-import kotlin.Pair
-import kotlin.Suppress
-import kotlin.apply
-import kotlin.arrayOf
-import kotlin.let
-import kotlin.require
/**
* Adapter class that translates data classes between Extension and Jetpack interfaces.
@@ -86,13 +76,16 @@
SplitInfo(
ActivityStack(
primaryActivityStack.activities,
- primaryActivityStack.isEmpty
+ primaryActivityStack.isEmpty,
+ primaryActivityStack.token,
),
ActivityStack(
secondaryActivityStack.activities,
- secondaryActivityStack.isEmpty
+ secondaryActivityStack.isEmpty,
+ secondaryActivityStack.token,
),
- translate(splitInfo.splitAttributes)
+ translate(splitInfo.splitAttributes),
+ splitInfo.token,
)
}
}
@@ -113,7 +106,9 @@
)
}
)
- .setAnimationBackgroundColor(splitAttributes.animationBackgroundColor)
+ .setAnimationBackgroundColor(SplitAttributes.BackgroundColor.buildFromValue(
+ splitAttributes.animationBackgroundColor)
+ )
.build()
private fun translate(splitType: OEMSplitType): SplitType =
@@ -228,7 +223,7 @@
)
}
)
- .setAnimationBackgroundColor(splitAttributes.animationBackgroundColor)
+ .setAnimationBackgroundColor(splitAttributes.animationBackgroundColor.value)
.build()
}
@@ -343,18 +338,21 @@
val primaryActivityStack = splitInfo.primaryActivityStack
val primaryFragment = ActivityStack(
primaryActivityStack.activities,
- primaryActivityStack.isEmpty
+ primaryActivityStack.isEmpty,
+ INVALID_ACTIVITY_STACK_TOKEN,
)
val secondaryActivityStack = splitInfo.secondaryActivityStack
val secondaryFragment = ActivityStack(
secondaryActivityStack.activities,
- secondaryActivityStack.isEmpty
+ secondaryActivityStack.isEmpty,
+ INVALID_ACTIVITY_STACK_TOKEN,
)
return SplitInfo(
primaryFragment,
secondaryFragment,
- translate(splitInfo.splitAttributes)
+ translate(splitInfo.splitAttributes),
+ INVALID_SPLIT_INFO_TOKEN,
)
}
}
@@ -530,7 +528,8 @@
}
val primaryFragment = ActivityStack(
primaryActivityStack.activities,
- isPrimaryStackEmpty
+ isPrimaryStackEmpty,
+ INVALID_ACTIVITY_STACK_TOKEN,
)
val secondaryActivityStack = splitInfo.secondaryActivityStack
@@ -543,15 +542,30 @@
}
val secondaryFragment = ActivityStack(
secondaryActivityStack.activities,
- isSecondaryStackEmpty
+ isSecondaryStackEmpty,
+ INVALID_ACTIVITY_STACK_TOKEN,
)
val splitAttributes = getSplitAttributesCompat(splitInfo)
return SplitInfo(
primaryFragment,
secondaryFragment,
- splitAttributes
+ splitAttributes,
+ INVALID_SPLIT_INFO_TOKEN,
)
}
}
+
+ internal companion object {
+ /**
+ * The default token of [SplitInfo], which provides compatibility for device prior to
+ * [WindowExtensions.VENDOR_API_LEVEL_3]
+ */
+ val INVALID_SPLIT_INFO_TOKEN = Binder()
+ /**
+ * The default token of [ActivityStack], which provides compatibility for device prior to
+ * [WindowExtensions.VENDOR_API_LEVEL_3]
+ */
+ val INVALID_ACTIVITY_STACK_TOKEN = Binder()
+ }
}
diff --git a/window/window/src/main/java/androidx/window/embedding/EmbeddingBackend.kt b/window/window/src/main/java/androidx/window/embedding/EmbeddingBackend.kt
index 77ed5ef..ce76b0e 100644
--- a/window/window/src/main/java/androidx/window/embedding/EmbeddingBackend.kt
+++ b/window/window/src/main/java/androidx/window/embedding/EmbeddingBackend.kt
@@ -17,6 +17,8 @@
package androidx.window.embedding
import android.app.Activity
+import android.app.ActivityOptions
+import android.os.IBinder
import androidx.core.util.Consumer
import java.util.concurrent.Executor
@@ -51,4 +53,18 @@
fun clearSplitAttributesCalculator()
fun isSplitAttributesCalculatorSupported(): Boolean
+
+ fun getActivityStack(activity: Activity): ActivityStack?
+
+ fun setLaunchingActivityStack(options: ActivityOptions, token: IBinder): ActivityOptions
+
+ fun finishActivityStacks(activityStacks: Set<ActivityStack>)
+
+ fun isFinishActivityStacksSupported(): Boolean
+
+ fun invalidateTopVisibleSplitAttributes()
+
+ fun updateSplitAttributes(splitInfo: SplitInfo, splitAttributes: SplitAttributes)
+
+ fun areSplitAttributesUpdatesSupported(): Boolean
}
\ No newline at end of file
diff --git a/window/window/src/main/java/androidx/window/embedding/EmbeddingCompat.kt b/window/window/src/main/java/androidx/window/embedding/EmbeddingCompat.kt
index 4b13ef5..5cda758 100644
--- a/window/window/src/main/java/androidx/window/embedding/EmbeddingCompat.kt
+++ b/window/window/src/main/java/androidx/window/embedding/EmbeddingCompat.kt
@@ -18,12 +18,15 @@
import androidx.window.extensions.embedding.SplitInfo as OEMSplitInfo
import android.app.Activity
+import android.app.ActivityOptions
import android.content.Context
+import android.os.IBinder
import android.util.Log
import androidx.window.core.ConsumerAdapter
import androidx.window.core.ExtensionsUtil
import androidx.window.embedding.EmbeddingInterfaceCompat.EmbeddingCallbackInterface
import androidx.window.extensions.WindowExtensions.VENDOR_API_LEVEL_2
+import androidx.window.extensions.WindowExtensions.VENDOR_API_LEVEL_3
import androidx.window.extensions.WindowExtensionsProvider
import androidx.window.extensions.core.util.function.Consumer
import androidx.window.extensions.embedding.ActivityEmbeddingComponent
@@ -105,13 +108,63 @@
override fun isSplitAttributesCalculatorSupported(): Boolean =
ExtensionsUtil.safeVendorApiLevel >= VENDOR_API_LEVEL_2
+ override fun finishActivityStacks(activityStacks: Set<ActivityStack>) {
+ if (!isFinishActivityStacksSupported()) {
+ throw UnsupportedOperationException("#finishActivityStacks is not " +
+ "supported on the device.")
+ }
+ val stackTokens = activityStacks.mapTo(mutableSetOf()) { it.token }
+ embeddingExtension.finishActivityStacks(stackTokens)
+ }
+
+ override fun isFinishActivityStacksSupported(): Boolean =
+ ExtensionsUtil.safeVendorApiLevel >= VENDOR_API_LEVEL_3
+
+ override fun invalidateTopVisibleSplitAttributes() {
+ if (!areSplitAttributesUpdatesSupported()) {
+ throw UnsupportedOperationException("#invalidateTopVisibleSplitAttributes is not " +
+ "supported on the device.")
+ }
+ embeddingExtension.invalidateTopVisibleSplitAttributes()
+ }
+
+ override fun updateSplitAttributes(
+ splitInfo: SplitInfo,
+ splitAttributes: SplitAttributes
+ ) {
+ if (!areSplitAttributesUpdatesSupported()) {
+ throw UnsupportedOperationException("#updateSplitAttributes is not supported on the " +
+ "device.")
+ }
+ embeddingExtension.updateSplitAttributes(
+ splitInfo.token,
+ adapter.translateSplitAttributes(splitAttributes)
+ )
+ }
+
+ override fun areSplitAttributesUpdatesSupported(): Boolean =
+ ExtensionsUtil.safeVendorApiLevel >= VENDOR_API_LEVEL_3
+
+ override fun setLaunchingActivityStack(
+ options: ActivityOptions,
+ token: IBinder
+ ): ActivityOptions {
+ return embeddingExtension.setLaunchingActivityStack(options, token)
+ }
+
companion object {
const val DEBUG = true
private const val TAG = "EmbeddingCompat"
fun isEmbeddingAvailable(): Boolean {
return try {
- WindowExtensionsProvider.getWindowExtensions().activityEmbeddingComponent != null
+ EmbeddingCompat::class.java.classLoader?.let { loader ->
+ SafeActivityEmbeddingComponentProvider(
+ loader,
+ ConsumerAdapter(loader),
+ WindowExtensionsProvider.getWindowExtensions(),
+ ).activityEmbeddingComponent != null
+ } ?: false
} catch (e: NoClassDefFoundError) {
if (DEBUG) {
Log.d(TAG, "Embedding extension version not found")
@@ -127,17 +180,23 @@
fun embeddingComponent(): ActivityEmbeddingComponent {
return if (isEmbeddingAvailable()) {
- WindowExtensionsProvider.getWindowExtensions().activityEmbeddingComponent
- ?: Proxy.newProxyInstance(
- EmbeddingCompat::class.java.classLoader,
- arrayOf(ActivityEmbeddingComponent::class.java)
- ) { _, _, _ -> } as ActivityEmbeddingComponent
+ EmbeddingCompat::class.java.classLoader?.let { loader ->
+ SafeActivityEmbeddingComponentProvider(
+ loader,
+ ConsumerAdapter(loader),
+ WindowExtensionsProvider.getWindowExtensions(),
+ ).activityEmbeddingComponent
+ } ?: emptyActivityEmbeddingProxy()
} else {
- Proxy.newProxyInstance(
- EmbeddingCompat::class.java.classLoader,
- arrayOf(ActivityEmbeddingComponent::class.java)
- ) { _, _, _ -> } as ActivityEmbeddingComponent
+ emptyActivityEmbeddingProxy()
}
}
+
+ private fun emptyActivityEmbeddingProxy(): ActivityEmbeddingComponent {
+ return Proxy.newProxyInstance(
+ EmbeddingCompat::class.java.classLoader,
+ arrayOf(ActivityEmbeddingComponent::class.java)
+ ) { _, _, _ -> } as ActivityEmbeddingComponent
+ }
}
}
\ No newline at end of file
diff --git a/window/window/src/main/java/androidx/window/embedding/EmbeddingInterfaceCompat.kt b/window/window/src/main/java/androidx/window/embedding/EmbeddingInterfaceCompat.kt
index 8c74aec..26d8846 100644
--- a/window/window/src/main/java/androidx/window/embedding/EmbeddingInterfaceCompat.kt
+++ b/window/window/src/main/java/androidx/window/embedding/EmbeddingInterfaceCompat.kt
@@ -17,6 +17,8 @@
package androidx.window.embedding
import android.app.Activity
+import android.app.ActivityOptions
+import android.os.IBinder
import androidx.window.extensions.embedding.ActivityEmbeddingComponent
/**
@@ -42,4 +44,16 @@
fun clearSplitAttributesCalculator()
fun isSplitAttributesCalculatorSupported(): Boolean
+
+ fun setLaunchingActivityStack(options: ActivityOptions, token: IBinder): ActivityOptions
+
+ fun finishActivityStacks(activityStacks: Set<ActivityStack>)
+
+ fun isFinishActivityStacksSupported(): Boolean
+
+ fun invalidateTopVisibleSplitAttributes()
+
+ fun updateSplitAttributes(splitInfo: SplitInfo, splitAttributes: SplitAttributes)
+
+ fun areSplitAttributesUpdatesSupported(): Boolean
}
\ No newline at end of file
diff --git a/window/window/src/main/java/androidx/window/embedding/ExtensionEmbeddingBackend.kt b/window/window/src/main/java/androidx/window/embedding/ExtensionEmbeddingBackend.kt
index b9e2aa2..59a580b 100644
--- a/window/window/src/main/java/androidx/window/embedding/ExtensionEmbeddingBackend.kt
+++ b/window/window/src/main/java/androidx/window/embedding/ExtensionEmbeddingBackend.kt
@@ -17,7 +17,9 @@
package androidx.window.embedding
import android.app.Activity
+import android.app.ActivityOptions
import android.content.Context
+import android.os.IBinder
import android.util.Log
import androidx.annotation.GuardedBy
import androidx.annotation.VisibleForTesting
@@ -321,4 +323,48 @@
override fun isSplitAttributesCalculatorSupported(): Boolean =
embeddingExtension?.isSplitAttributesCalculatorSupported() ?: false
+
+ override fun getActivityStack(activity: Activity): ActivityStack? {
+ globalLock.withLock {
+ val lastInfo: List<SplitInfo> = splitInfoEmbeddingCallback.lastInfo ?: return null
+ for (info in lastInfo) {
+ if (activity !in info) {
+ continue
+ }
+ if (activity in info.primaryActivityStack) {
+ return info.primaryActivityStack
+ }
+ if (activity in info.secondaryActivityStack) {
+ return info.secondaryActivityStack
+ }
+ }
+ return null
+ }
+ }
+
+ override fun setLaunchingActivityStack(
+ options: ActivityOptions,
+ token: IBinder
+ ): ActivityOptions = embeddingExtension?.setLaunchingActivityStack(options, token) ?: options
+
+ override fun finishActivityStacks(activityStacks: Set<ActivityStack>) {
+ embeddingExtension?.finishActivityStacks(activityStacks)
+ }
+
+ override fun isFinishActivityStacksSupported(): Boolean =
+ embeddingExtension?.isFinishActivityStacksSupported() ?: false
+
+ override fun invalidateTopVisibleSplitAttributes() {
+ embeddingExtension?.invalidateTopVisibleSplitAttributes()
+ }
+
+ override fun updateSplitAttributes(
+ splitInfo: SplitInfo,
+ splitAttributes: SplitAttributes
+ ) {
+ embeddingExtension?.updateSplitAttributes(splitInfo, splitAttributes)
+ }
+
+ override fun areSplitAttributesUpdatesSupported(): Boolean =
+ embeddingExtension?.areSplitAttributesUpdatesSupported() ?: false
}
\ No newline at end of file
diff --git a/window/window/src/main/java/androidx/window/embedding/RuleParser.kt b/window/window/src/main/java/androidx/window/embedding/RuleParser.kt
index c3334c0..add2f25 100644
--- a/window/window/src/main/java/androidx/window/embedding/RuleParser.kt
+++ b/window/window/src/main/java/androidx/window/embedding/RuleParser.kt
@@ -176,7 +176,8 @@
val clearTop = typedArray.getBoolean(R.styleable.SplitPairRule_clearTop, false)
val animationBackgroundColor = typedArray.getColor(
R.styleable.SplitPairRule_animationBackgroundColor,
- 0)
+ SplitAttributes.BackgroundColor.DEFAULT.value
+ )
typedArray.recycle()
val defaultAttrs = SplitAttributes.Builder()
@@ -184,7 +185,9 @@
.setLayoutDirection(
SplitAttributes.LayoutDirection.getLayoutDirectionFromValue(layoutDir)
)
- .setAnimationBackgroundColor(animationBackgroundColor)
+ .setAnimationBackgroundColor(
+ SplitAttributes.BackgroundColor.buildFromValue(animationBackgroundColor)
+ )
.build()
SplitPairRule.Builder(emptySet())
@@ -258,7 +261,8 @@
)
val animationBackgroundColor = typedArray.getColor(
R.styleable.SplitPlaceholderRule_animationBackgroundColor,
- 0)
+ SplitAttributes.BackgroundColor.DEFAULT.value
+ )
typedArray.recycle()
val defaultAttrs = SplitAttributes.Builder()
@@ -266,7 +270,9 @@
.setLayoutDirection(
SplitAttributes.LayoutDirection.getLayoutDirectionFromValue(layoutDir)
)
- .setAnimationBackgroundColor(animationBackgroundColor)
+ .setAnimationBackgroundColor(
+ SplitAttributes.BackgroundColor.buildFromValue(animationBackgroundColor)
+ )
.build()
val packageName = context.applicationContext.packageName
val placeholderActivityClassName = buildClassName(
diff --git a/window/window/src/main/java/androidx/window/embedding/SafeActivityEmbeddingComponentProvider.kt b/window/window/src/main/java/androidx/window/embedding/SafeActivityEmbeddingComponentProvider.kt
new file mode 100644
index 0000000..44699d8
--- /dev/null
+++ b/window/window/src/main/java/androidx/window/embedding/SafeActivityEmbeddingComponentProvider.kt
@@ -0,0 +1,205 @@
+/*
+ * Copyright 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.window.embedding
+
+import android.app.Activity
+import androidx.window.core.ConsumerAdapter
+import androidx.window.core.ExtensionsUtil
+import androidx.window.extensions.WindowExtensions
+import androidx.window.extensions.core.util.function.Consumer
+import androidx.window.extensions.core.util.function.Function
+import androidx.window.extensions.embedding.ActivityEmbeddingComponent
+import androidx.window.reflection.ReflectionUtils.doesReturn
+import androidx.window.reflection.ReflectionUtils.isPublic
+import androidx.window.reflection.ReflectionUtils.validateReflection
+import androidx.window.reflection.WindowExtensionsConstants.ACTIVITY_EMBEDDING_COMPONENT_CLASS
+import androidx.window.reflection.WindowExtensionsConstants.WINDOW_EXTENSIONS_CLASS
+import androidx.window.reflection.WindowExtensionsConstants.WINDOW_EXTENSIONS_PROVIDER_CLASS
+
+/**
+ * Reflection Guard for [ActivityEmbeddingComponent].
+ * This will go through the [ActivityEmbeddingComponent]'s method by reflection and
+ * check each method's name and signature to see if the interface is what we required.
+ */
+internal class SafeActivityEmbeddingComponentProvider(
+ private val loader: ClassLoader,
+ private val consumerAdapter: ConsumerAdapter,
+ private val windowExtensions: WindowExtensions
+) {
+ val activityEmbeddingComponent: ActivityEmbeddingComponent?
+ get() {
+ return if (canUseActivityEmbeddingComponent()) {
+ try {
+ windowExtensions.activityEmbeddingComponent
+ } catch (e: UnsupportedOperationException) {
+ null
+ }
+ } else {
+ null
+ }
+ }
+
+ private fun canUseActivityEmbeddingComponent(): Boolean {
+ if (!isWindowExtensionsValid() || !isActivityEmbeddingComponentValid()) {
+ return false
+ }
+ // TODO(b/267573854) : update logic to fallback to lower version
+ // if higher version is not matched
+ return when (ExtensionsUtil.safeVendorApiLevel) {
+ 1 -> hasValidVendorApiLevel1()
+ in 2..Int.MAX_VALUE -> hasValidVendorApiLevel2()
+ // TODO(b/267956499) : add hasValidVendorApiLevel3
+ else -> false
+ }
+ }
+
+ /**
+ * [WindowExtensions.VENDOR_API_LEVEL_1] includes the following methods:
+ * - [ActivityEmbeddingComponent.setEmbeddingRules]
+ * - [ActivityEmbeddingComponent.isActivityEmbedded]
+ * - [ActivityEmbeddingComponent.setSplitInfoCallback] with [java.util.function.Consumer]
+ * and following classes: TODO(b/268583307) : add guard function for those classes
+ * - [androidx.window.extensions.embedding.ActivityRule]
+ * - [androidx.window.extensions.embedding.SplitPairRule]
+ * - [androidx.window.extensions.embedding.SplitPlaceholderRule]
+ * - [androidx.window.extensions.embedding.SplitInfo]
+ */
+ private fun hasValidVendorApiLevel1(): Boolean {
+ return isMethodSetEmbeddingRulesValid() &&
+ isMethodIsActivityEmbeddedValid() &&
+ isMethodSetSplitInfoCallbackJavaConsumerValid()
+ }
+
+ /**
+ * [WindowExtensions.VENDOR_API_LEVEL_2] includes the following methods
+ * - [ActivityEmbeddingComponent.setSplitInfoCallback] with [Consumer]
+ * - [ActivityEmbeddingComponent.clearSplitInfoCallback]
+ * - [ActivityEmbeddingComponent.setSplitAttributesCalculator]
+ * - [ActivityEmbeddingComponent.clearSplitAttributesCalculator]
+ * and following classes: TODO(b/268583307) : add guard function for those classes
+ * - [androidx.window.extensions.embedding.SplitAttributes]
+ */
+ private fun hasValidVendorApiLevel2(): Boolean {
+ return hasValidVendorApiLevel1() &&
+ isMethodSetSplitInfoCallbackWindowConsumerValid() &&
+ isMethodClearSplitInfoCallbackValid() &&
+ isMethodSplitAttributesCalculatorValid()
+ }
+
+ private fun isMethodSetEmbeddingRulesValid(): Boolean {
+ return validateReflection("ActivityEmbeddingComponent#setEmbeddingRules is not valid") {
+ val setEmbeddingRulesMethod = activityEmbeddingComponentClass.getMethod(
+ "setEmbeddingRules",
+ Set::class.java
+ )
+ setEmbeddingRulesMethod.isPublic
+ }
+ }
+
+ private fun isMethodIsActivityEmbeddedValid(): Boolean {
+ return validateReflection("ActivityEmbeddingComponent#isActivityEmbedded is not valid") {
+ val isActivityEmbeddedMethod = activityEmbeddingComponentClass.getMethod(
+ "isActivityEmbedded",
+ Activity::class.java
+ )
+ isActivityEmbeddedMethod.isPublic &&
+ isActivityEmbeddedMethod.doesReturn(Boolean::class.java)
+ }
+ }
+
+ private fun isMethodClearSplitInfoCallbackValid(): Boolean {
+ return validateReflection(
+ "ActivityEmbeddingComponent#clearSplitInfoCallback is not valid"
+ ) {
+ val clearSplitInfoCallbackMethod =
+ activityEmbeddingComponentClass.getMethod("clearSplitInfoCallback")
+ clearSplitInfoCallbackMethod.isPublic
+ }
+ }
+
+ private fun isMethodSplitAttributesCalculatorValid(): Boolean {
+ return validateReflection(
+ "ActivityEmbeddingComponent#setSplitAttributesCalculator is not valid"
+ ) {
+ val setSplitAttributesCalculatorMethod = activityEmbeddingComponentClass.getMethod(
+ "setSplitAttributesCalculator",
+ Function::class.java
+ )
+ val clearSplitAttributesCalculatorMethod =
+ activityEmbeddingComponentClass.getMethod("clearSplitAttributesCalculator")
+ setSplitAttributesCalculatorMethod.isPublic &&
+ clearSplitAttributesCalculatorMethod.isPublic
+ }
+ }
+
+ private fun isMethodSetSplitInfoCallbackJavaConsumerValid(): Boolean {
+ return validateReflection("ActivityEmbeddingComponent#setSplitInfoCallback is not valid") {
+ val consumerClass =
+ consumerAdapter.consumerClassOrNull() ?: return@validateReflection false
+ val setSplitInfoCallbackMethod =
+ activityEmbeddingComponentClass.getMethod("setSplitInfoCallback", consumerClass)
+ setSplitInfoCallbackMethod.isPublic
+ }
+ }
+
+ private fun isMethodSetSplitInfoCallbackWindowConsumerValid(): Boolean {
+ return validateReflection("ActivityEmbeddingComponent#setSplitInfoCallback is not valid") {
+ val setSplitInfoCallbackMethod = activityEmbeddingComponentClass.getMethod(
+ "setSplitInfoCallback",
+ Consumer::class.java
+ )
+ setSplitInfoCallbackMethod.isPublic
+ }
+ }
+
+ private fun isWindowExtensionsValid(): Boolean {
+ return validateReflection("WindowExtensionsProvider#getWindowExtensions is not valid") {
+ val providerClass = windowExtensionsProviderClass
+ val getWindowExtensionsMethod = providerClass.getDeclaredMethod("getWindowExtensions")
+ val windowExtensionsClass = windowExtensionsClass
+ getWindowExtensionsMethod.isPublic && getWindowExtensionsMethod.doesReturn(
+ windowExtensionsClass
+ )
+ }
+ }
+
+ private fun isActivityEmbeddingComponentValid(): Boolean {
+ return validateReflection("WindowExtensions#getActivityEmbeddingComponent is not valid") {
+ val extensionsClass = windowExtensionsClass
+ val getActivityEmbeddingComponentMethod =
+ extensionsClass.getMethod("getActivityEmbeddingComponent")
+ val activityEmbeddingComponentClass = activityEmbeddingComponentClass
+ getActivityEmbeddingComponentMethod.isPublic &&
+ getActivityEmbeddingComponentMethod.doesReturn(activityEmbeddingComponentClass)
+ }
+ }
+
+ private val windowExtensionsProviderClass: Class<*>
+ get() {
+ return loader.loadClass(WINDOW_EXTENSIONS_PROVIDER_CLASS)
+ }
+
+ private val windowExtensionsClass: Class<*>
+ get() {
+ return loader.loadClass(WINDOW_EXTENSIONS_CLASS)
+ }
+
+ private val activityEmbeddingComponentClass: Class<*>
+ get() {
+ return loader.loadClass(ACTIVITY_EMBEDDING_COMPONENT_CLASS)
+ }
+}
\ No newline at end of file
diff --git a/window/window/src/main/java/androidx/window/embedding/SplitAttributes.kt b/window/window/src/main/java/androidx/window/embedding/SplitAttributes.kt
index d83ce52..e79095a 100644
--- a/window/window/src/main/java/androidx/window/embedding/SplitAttributes.kt
+++ b/window/window/src/main/java/androidx/window/embedding/SplitAttributes.kt
@@ -17,14 +17,13 @@
package androidx.window.embedding
import android.annotation.SuppressLint
+import android.graphics.Color
import androidx.annotation.ColorInt
import androidx.annotation.FloatRange
import androidx.annotation.IntRange
import androidx.window.core.SpecificationComputer.Companion.startSpecification
import androidx.window.core.VerificationMode
-import androidx.window.embedding.SplitAttributes.LayoutDirection
import androidx.window.embedding.SplitAttributes.LayoutDirection.Companion.LOCALE
-import androidx.window.embedding.SplitAttributes.SplitType
import androidx.window.embedding.SplitAttributes.SplitType.Companion.splitEqually
/**
@@ -48,15 +47,16 @@
* - Setting `splitRatio`, `splitLayoutDirection`, and
* `animationBackgroundColor` attributes in `<SplitPairRule>` or
* `<SplitPlaceholderRule>` tags in an XML configuration file. The
- * attributes are parsed as [SplitType], [LayoutDirection], and [ColorInt],
- * respectively. Note that [SplitType.HingeSplitType] is not supported XML
- * format.
+ * attributes are parsed as [SplitType], [LayoutDirection], and
+ * [BackgroundColor], respectively. Note that [SplitType.HingeSplitType]
+ * is not supported XML format.
* - Using
* [SplitAttributesCalculator.computeSplitAttributesForParams] to customize
* the `SplitAttributes` for a given device and window state.
*
* @see SplitAttributes.SplitType
* @see SplitAttributes.LayoutDirection
+ * @see SplitAttributes.BackgroundColor
*/
class SplitAttributes internal constructor(
@@ -73,14 +73,16 @@
val layoutDirection: LayoutDirection = LOCALE,
/**
- * The [ColorInt] to use for the background color during the animation of
+ * The color to use for the background color during the animation of
* the split involving this `SplitAttributes` object if the animation
* requires a background.
*
- * The default is 0, which specifies the theme window background color.
+ * The default is to use the current theme window background color.
+ *
+ * @see BackgroundColor.color
+ * @see BackgroundColor.DEFAULT
*/
- @ColorInt
- val animationBackgroundColor: Int = 0
+ val animationBackgroundColor: BackgroundColor = BackgroundColor.DEFAULT
) {
/**
@@ -422,6 +424,85 @@
}
/**
+ * Background color to be used for window transition animations in a split if the animation
+ * requires a background.
+ *
+ * @see SplitAttributes.animationBackgroundColor
+ */
+ class BackgroundColor private constructor(
+
+ /**
+ * The description of this `BackgroundColor`.
+ */
+ private val description: String,
+
+ /**
+ * [ColorInt] to represent the color to use as the background color.
+ */
+ @ColorInt
+ internal val value: Int,
+ ) {
+ override fun toString() = "BackgroundColor($description)"
+
+ override fun equals(other: Any?): Boolean {
+ if (other === this) return true
+ if (other !is BackgroundColor) return false
+ return value == other.value && description == other.description
+ }
+
+ override fun hashCode() = description.hashCode() + 31 * value.hashCode()
+
+ /**
+ * Methods that create various [BackgroundColor].
+ */
+ companion object {
+
+ /**
+ * Creates a [BackgroundColor] to represent the given [color].
+ *
+ * Only opaque color is supported.
+ *
+ * @param color [ColorInt] of an opaque color.
+ * @return the [BackgroundColor] representing the [color].
+ *
+ * @see [DEFAULT] for the default value, which means to use the
+ * current theme window background color.
+ */
+ @JvmStatic
+ fun color(
+ @IntRange(from = Color.BLACK.toLong(), to = Color.WHITE.toLong())
+ @ColorInt
+ color: Int
+ ):
+ BackgroundColor {
+ require(Color.BLACK <= color && color <= Color.WHITE) {
+ "Background color must be opaque"
+ }
+ return BackgroundColor("color:${Integer.toHexString(color)}", color)
+ }
+
+ /**
+ * The special [BackgroundColor] to represent the default value,
+ * which means to use the current theme window background color.
+ */
+ @JvmField
+ val DEFAULT = BackgroundColor("DEFAULT", 0)
+
+ /**
+ * Returns a [BackgroundColor] with the given [value]
+ */
+ internal fun buildFromValue(@ColorInt value: Int): BackgroundColor {
+ return if (Color.alpha(value) != 255) {
+ // Treat any non-opaque color as the default.
+ DEFAULT
+ } else {
+ color(value)
+ }
+ }
+ }
+ }
+
+ /**
* Non-public properties and methods.
*/
companion object {
@@ -464,21 +545,21 @@
override fun toString(): String =
"${SplitAttributes::class.java.simpleName}:" +
"{splitType=$splitType, layoutDir=$layoutDirection," +
- " animationBackgroundColor=${Integer.toHexString(animationBackgroundColor)}"
+ " animationBackgroundColor=$animationBackgroundColor"
/**
* Builder for creating an instance of [SplitAttributes].
*
- * The default split type is an equal split between primary and secondary
- * containers. The default layout direction is based on locale. The default
- * animation background color is 0, which specifies the theme window
- * background color.
+ * - The default split type is an equal split between primary and secondary
+ * containers.
+ * - The default layout direction is based on locale.
+ * - The default animation background color is to use the current theme
+ * window background color.
*/
class Builder {
private var splitType: SplitType = splitEqually()
private var layoutDirection = LOCALE
- @ColorInt
- private var animationBackgroundColor = 0
+ private var animationBackgroundColor = BackgroundColor.DEFAULT
/**
* Sets the split type attribute.
@@ -507,20 +588,23 @@
apply { this.layoutDirection = layoutDirection }
/**
- * Sets the [ColorInt] to use for the background color during animation
+ * Sets the color to use for the background color during animation
* of the split involving this `SplitAttributes` object if the animation
- * requires a background.
+ * requires a background. Only opaque color is supported.
*
- * The default is 0, which specifies the theme window background color.
+ * The default is [BackgroundColor.DEFAULT], which means to use the
+ * current theme window background color.
*
- * @param color A packed color int of the form `AARRGGBB`, for the
- * animation background color.
+ * @param color The animation background color.
* @return This `Builder`.
*
- * @see SplitAttributes.animationBackgroundColor
+ * @see BackgroundColor.color
+ * @see BackgroundColor.DEFAULT
*/
- fun setAnimationBackgroundColor(@ColorInt color: Int): Builder =
- apply { this.animationBackgroundColor = color }
+ fun setAnimationBackgroundColor(color: BackgroundColor): Builder =
+ apply {
+ animationBackgroundColor = color
+ }
/**
* Builds a `SplitAttributes` instance with the attributes specified by
diff --git a/window/window/src/main/java/androidx/window/embedding/SplitController.kt b/window/window/src/main/java/androidx/window/embedding/SplitController.kt
index 9e061b5..5b4b113 100644
--- a/window/window/src/main/java/androidx/window/embedding/SplitController.kt
+++ b/window/window/src/main/java/androidx/window/embedding/SplitController.kt
@@ -157,7 +157,6 @@
* @throws UnsupportedOperationException if [isSplitAttributesCalculatorSupported] reports
* `false`
*/
- @ExperimentalWindowApi
fun setSplitAttributesCalculator(
calculator: (SplitAttributesCalculatorParams) -> SplitAttributes
) {
@@ -171,16 +170,82 @@
* @throws UnsupportedOperationException if [isSplitAttributesCalculatorSupported] reports
* `false`
*/
- @ExperimentalWindowApi
fun clearSplitAttributesCalculator() {
embeddingBackend.clearSplitAttributesCalculator()
}
/** Returns whether [setSplitAttributesCalculator] is supported or not. */
- @ExperimentalWindowApi
fun isSplitAttributesCalculatorSupported(): Boolean =
embeddingBackend.isSplitAttributesCalculatorSupported()
+ /**
+ * Triggers a [SplitAttributes] update callback for the current topmost and visible split layout
+ * if there is one. This method can be used when a change to the split presentation originates
+ * from an application state change. Changes that are driven by parent window changes or new
+ * activity starts invoke the callback provided in [setSplitAttributesCalculator] automatically
+ * without the need to call this function.
+ *
+ * The top [SplitInfo] is usually the last element of [SplitInfo] list which was received from
+ * the callback registered in [SplitController.addSplitListener].
+ *
+ * The call will be ignored if there is no visible split.
+ *
+ * @throws UnsupportedOperationException if the device doesn't support this API.
+ */
+ @ExperimentalWindowApi
+ fun invalidateTopVisibleSplitAttributes() =
+ embeddingBackend.invalidateTopVisibleSplitAttributes()
+
+ /**
+ * Checks whether [invalidateTopVisibleSplitAttributes] is supported on the device.
+ *
+ * Invoking these APIs if the feature is not supported would trigger an
+ * [UnsupportedOperationException].
+ * @return `true` if the runtime APIs to update [SplitAttributes] are supported and can be
+ * called safely, `false` otherwise.
+ */
+ @ExperimentalWindowApi
+ fun isInvalidatingTopVisibleSplitAttributesSupported(): Boolean =
+ embeddingBackend.areSplitAttributesUpdatesSupported()
+
+ /**
+ * Updates the [SplitAttributes] of a split pair. This is an alternative to using
+ * a split attributes calculator callback set in [setSplitAttributesCalculator], useful when
+ * apps only need to update the splits in a few cases proactively but rely on the default split
+ * attributes most of the time otherwise.
+ *
+ * The provided split attributes will be used instead of the associated
+ * [SplitRule.defaultSplitAttributes].
+ *
+ * **Note** that the split attributes may be updated if split attributes calculator callback is
+ * registered and invoked. If [setSplitAttributesCalculator] is used, the callback will still be
+ * applied to each [SplitInfo] when there's either:
+ * - A new Activity being launched.
+ * - A window or device state updates (e,g. due to screen rotation or folding state update).
+ *
+ * In most cases it is suggested to use [invalidateTopVisibleSplitAttributes] if
+ * [SplitAttributes] calculator callback is used.
+ *
+ * @param splitInfo the split pair to update
+ * @param splitAttributes the [SplitAttributes] to be applied
+ * @throws UnsupportedOperationException if this device doesn't support this API
+ */
+ @ExperimentalWindowApi
+ fun updateSplitAttributes(splitInfo: SplitInfo, splitAttributes: SplitAttributes) =
+ embeddingBackend.updateSplitAttributes(splitInfo, splitAttributes)
+
+ /**
+ * Checks whether [updateSplitAttributes] is supported on the device.
+ *
+ * Invoking these APIs if the feature is not supported would trigger an
+ * [UnsupportedOperationException].
+ * @return `true` if the runtime APIs to update [SplitAttributes] are supported and can be
+ * called safely, `false` otherwise.
+ */
+ @ExperimentalWindowApi
+ fun isUpdatingSplitAttributesSupported(): Boolean =
+ embeddingBackend.areSplitAttributesUpdatesSupported()
+
companion object {
@Volatile
private var globalInstance: SplitController? = null
diff --git a/window/window/src/main/java/androidx/window/embedding/SplitInfo.kt b/window/window/src/main/java/androidx/window/embedding/SplitInfo.kt
index fabb354..e6087fc 100644
--- a/window/window/src/main/java/androidx/window/embedding/SplitInfo.kt
+++ b/window/window/src/main/java/androidx/window/embedding/SplitInfo.kt
@@ -17,6 +17,7 @@
package androidx.window.embedding
import android.app.Activity
+import android.os.IBinder
/** Describes a split pair of two containers with activities. */
class SplitInfo internal constructor(
@@ -29,7 +30,11 @@
*/
val secondaryActivityStack: ActivityStack,
/** The [SplitAttributes] of this split pair. */
- val splitAttributes: SplitAttributes
+ val splitAttributes: SplitAttributes,
+ /**
+ * A token uniquely identifying this `SplitInfo`.
+ */
+ internal val token: IBinder,
) {
operator fun contains(activity: Activity): Boolean {
return primaryActivityStack.contains(activity) ||
@@ -43,6 +48,7 @@
if (primaryActivityStack != other.primaryActivityStack) return false
if (secondaryActivityStack != other.secondaryActivityStack) return false
if (splitAttributes != other.splitAttributes) return false
+ if (token != other.token) return false
return true
}
@@ -51,6 +57,7 @@
var result = primaryActivityStack.hashCode()
result = 31 * result + secondaryActivityStack.hashCode()
result = 31 * result + splitAttributes.hashCode()
+ result = 31 * result + token.hashCode()
return result
}
@@ -60,6 +67,7 @@
append("primaryActivityStack=$primaryActivityStack, ")
append("secondaryActivityStack=$secondaryActivityStack, ")
append("splitAttributes=$splitAttributes, ")
+ append("token=$token")
append("}")
}
}
diff --git a/window/window/src/main/java/androidx/window/embedding/SplitRule.kt b/window/window/src/main/java/androidx/window/embedding/SplitRule.kt
index c989e32..77fcdb6 100644
--- a/window/window/src/main/java/androidx/window/embedding/SplitRule.kt
+++ b/window/window/src/main/java/androidx/window/embedding/SplitRule.kt
@@ -239,7 +239,11 @@
}
val bounds = Api30Impl.getBounds(parentMetrics)
// TODO(b/265089843) replace with Build.VERSION.SDK_INT >= Build.VERSION_CODES.U
- val density = context.resources.displayMetrics.density
+ val density = if (BuildCompat.isAtLeastU()) {
+ Api34Impl.getDensity(parentMetrics)
+ } else {
+ context.resources.displayMetrics.density
+ }
return checkParentBounds(density, bounds)
}
@@ -288,6 +292,14 @@
}
}
+ @RequiresApi(34)
+ internal object Api34Impl {
+ @DoNotInline
+ fun getDensity(windowMetrics: WindowMetrics): Float {
+ return windowMetrics.density
+ }
+ }
+
override fun equals(other: Any?): Boolean {
if (this === other) return true
if (other !is SplitRule) return false
diff --git a/window/window/src/main/java/androidx/window/layout/SafeWindowLayoutComponentProvider.kt b/window/window/src/main/java/androidx/window/layout/SafeWindowLayoutComponentProvider.kt
index 6c9ec9d..fdc8c65 100644
--- a/window/window/src/main/java/androidx/window/layout/SafeWindowLayoutComponentProvider.kt
+++ b/window/window/src/main/java/androidx/window/layout/SafeWindowLayoutComponentProvider.kt
@@ -17,14 +17,29 @@
package androidx.window.layout
import android.app.Activity
+import android.content.Context
import android.graphics.Rect
import androidx.window.core.ConsumerAdapter
+import androidx.window.core.ExtensionsUtil
+import androidx.window.extensions.WindowExtensions
import androidx.window.extensions.WindowExtensionsProvider
+import androidx.window.extensions.core.util.function.Consumer
import androidx.window.extensions.layout.WindowLayoutComponent
-import java.lang.reflect.Method
-import java.lang.reflect.Modifier
-import kotlin.reflect.KClass
+import androidx.window.reflection.ReflectionUtils.doesReturn
+import androidx.window.reflection.ReflectionUtils.isPublic
+import androidx.window.reflection.ReflectionUtils.validateReflection
+import androidx.window.reflection.WindowExtensionsConstants.FOLDING_FEATURE_CLASS
+import androidx.window.reflection.WindowExtensionsConstants.JAVA_CONSUMER
+import androidx.window.reflection.WindowExtensionsConstants.WINDOW_CONSUMER
+import androidx.window.reflection.WindowExtensionsConstants.WINDOW_EXTENSIONS_CLASS
+import androidx.window.reflection.WindowExtensionsConstants.WINDOW_EXTENSIONS_PROVIDER_CLASS
+import androidx.window.reflection.WindowExtensionsConstants.WINDOW_LAYOUT_COMPONENT_CLASS
+/**
+ * Reflection Guard for [WindowLayoutComponent].
+ * This will go through the [WindowLayoutComponent]'s method by reflection and
+ * check each method's name and signature to see if the interface is what we required.
+ */
internal class SafeWindowLayoutComponentProvider(
private val loader: ClassLoader,
private val consumerAdapter: ConsumerAdapter
@@ -44,14 +59,47 @@
}
private fun canUseWindowLayoutComponent(): Boolean {
- return isWindowLayoutProviderValid() &&
- isWindowExtensionsValid() &&
- isWindowLayoutComponentValid() &&
- isFoldingFeatureValid()
+ if (!isWindowExtensionsValid() ||
+ !isWindowLayoutProviderValid() ||
+ !isFoldingFeatureValid()
+ ) {
+ return false
+ }
+ // TODO(b/267831038): can fallback to VendorApiLevel1 when level2 is not match
+ // but level 1 is matched
+ return when (ExtensionsUtil.safeVendorApiLevel) {
+ 1 -> hasValidVendorApiLevel1()
+ in 2..Int.MAX_VALUE -> hasValidVendorApiLevel2()
+ // TODO(b/267956499): add hasValidVendorApiLevel3
+ else -> false
+ }
}
- private fun isWindowLayoutProviderValid(): Boolean {
- return validate {
+ /**
+ * [WindowExtensions.VENDOR_API_LEVEL_1] includes the following methods
+ * - [WindowLayoutComponent.addWindowLayoutInfoListener] with [Activity] and
+ * [java.util.function.Consumer]
+ * - [WindowLayoutComponent.removeWindowLayoutInfoListener] with [java.util.function.Consumer]
+ */
+ private fun hasValidVendorApiLevel1(): Boolean {
+ return isMethodWindowLayoutInfoListenerJavaConsumerValid()
+ }
+
+ /**
+ * [WindowExtensions.VENDOR_API_LEVEL_2] includes the following methods
+ * - [WindowLayoutComponent.addWindowLayoutInfoListener] with [Context] and
+ * [java.util.function.Consumer]
+ * - [WindowLayoutComponent.addWindowLayoutInfoListener] with [Context] and [Consumer]
+ * - [WindowLayoutComponent.removeWindowLayoutInfoListener] with [Consumer]
+ */
+ private fun hasValidVendorApiLevel2(): Boolean {
+ return hasValidVendorApiLevel1() &&
+ isMethodWindowLayoutInfoListenerJavaConsumerUiContextValid() &&
+ isMethodWindowLayoutInfoListenerWindowConsumerValid()
+ }
+
+ private fun isWindowExtensionsValid(): Boolean {
+ return validateReflection("WindowExtensionsProvider#getWindowExtensions is not valid") {
val providerClass = windowExtensionsProviderClass
val getWindowExtensionsMethod = providerClass.getDeclaredMethod("getWindowExtensions")
val windowExtensionsClass = windowExtensionsClass
@@ -60,8 +108,8 @@
}
}
- private fun isWindowExtensionsValid(): Boolean {
- return validate {
+ private fun isWindowLayoutProviderValid(): Boolean {
+ return validateReflection("WindowExtensions#getWindowLayoutComponent is not valid") {
val extensionsClass = windowExtensionsClass
val getWindowLayoutComponentMethod =
extensionsClass.getMethod("getWindowLayoutComponent")
@@ -72,7 +120,7 @@
}
private fun isFoldingFeatureValid(): Boolean {
- return validate {
+ return validateReflection("FoldingFeature class is not valid") {
val foldingFeatureClass = foldingFeatureClass
val getBoundsMethod = foldingFeatureClass.getMethod("getBounds")
val getTypeMethod = foldingFeatureClass.getMethod("getType")
@@ -86,9 +134,13 @@
}
}
- private fun isWindowLayoutComponentValid(): Boolean {
- return validate {
- val consumerClass = consumerAdapter.consumerClassOrNull() ?: return@validate false
+ private fun isMethodWindowLayoutInfoListenerJavaConsumerValid(): Boolean {
+ return validateReflection(
+ "WindowLayoutComponent#addWindowLayoutInfoListener(" +
+ "${Activity::class.java.name}, $JAVA_CONSUMER) is not valid"
+ ) {
+ val consumerClass =
+ consumerAdapter.consumerClassOrNull() ?: return@validateReflection false
val windowLayoutComponent = windowLayoutComponentClass
val addListenerMethod = windowLayoutComponent
.getMethod(
@@ -102,46 +154,59 @@
}
}
- private fun validate(block: () -> Boolean): Boolean {
- return try {
- block()
- } catch (noClass: ClassNotFoundException) {
- false
- } catch (noMethod: NoSuchMethodException) {
- false
+ private fun isMethodWindowLayoutInfoListenerWindowConsumerValid(): Boolean {
+ return validateReflection(
+ "WindowLayoutComponent#addWindowLayoutInfoListener" +
+ "(${Context::class.java.name}, $WINDOW_CONSUMER) is not valid"
+ ) {
+ val windowLayoutComponent = windowLayoutComponentClass
+ val addListenerMethod = windowLayoutComponent
+ .getMethod(
+ "addWindowLayoutInfoListener",
+ Context::class.java,
+ Consumer::class.java
+ )
+ val removeListenerMethod = windowLayoutComponent
+ .getMethod("removeWindowLayoutInfoListener", Consumer::class.java)
+ addListenerMethod.isPublic && removeListenerMethod.isPublic
}
}
- private val Method.isPublic: Boolean
- get() {
- return Modifier.isPublic(modifiers)
+ private fun isMethodWindowLayoutInfoListenerJavaConsumerUiContextValid(): Boolean {
+ return validateReflection(
+ "WindowLayoutComponent#addWindowLayoutInfoListener" +
+ "(${Context::class.java.name}, $JAVA_CONSUMER) is not valid"
+ ) {
+ val consumerClass =
+ consumerAdapter.consumerClassOrNull() ?: return@validateReflection false
+ val windowLayoutComponent = windowLayoutComponentClass
+ val addListenerMethod = windowLayoutComponent
+ .getMethod(
+ "addWindowLayoutInfoListener",
+ Context::class.java,
+ consumerClass
+ )
+ addListenerMethod.isPublic
}
-
- private fun Method.doesReturn(clazz: KClass<*>): Boolean {
- return doesReturn(clazz.java)
- }
-
- private fun Method.doesReturn(clazz: Class<*>): Boolean {
- return returnType.equals(clazz)
}
private val windowExtensionsProviderClass: Class<*>
get() {
- return loader.loadClass("androidx.window.extensions.WindowExtensionsProvider")
+ return loader.loadClass(WINDOW_EXTENSIONS_PROVIDER_CLASS)
}
private val windowExtensionsClass: Class<*>
get() {
- return loader.loadClass("androidx.window.extensions.WindowExtensions")
+ return loader.loadClass(WINDOW_EXTENSIONS_CLASS)
}
private val foldingFeatureClass: Class<*>
get() {
- return loader.loadClass("androidx.window.extensions.layout.FoldingFeature")
+ return loader.loadClass(FOLDING_FEATURE_CLASS)
}
private val windowLayoutComponentClass: Class<*>
get() {
- return loader.loadClass("androidx.window.extensions.layout.WindowLayoutComponent")
+ return loader.loadClass(WINDOW_LAYOUT_COMPONENT_CLASS)
}
}
diff --git a/window/window/src/main/java/androidx/window/reflection/ReflectionUtils.kt b/window/window/src/main/java/androidx/window/reflection/ReflectionUtils.kt
new file mode 100644
index 0000000..52d92bd
--- /dev/null
+++ b/window/window/src/main/java/androidx/window/reflection/ReflectionUtils.kt
@@ -0,0 +1,72 @@
+/*
+ * Copyright 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.window.reflection
+
+import android.util.Log
+import java.lang.reflect.Method
+import java.lang.reflect.Modifier
+import kotlin.reflect.KClass
+
+/**
+ * Utility class used for reflection guard for WindowExtensions classes' validation
+ */
+internal object ReflectionUtils {
+
+ /**
+ * Validates the code block normally for reflection. If there are [ClassNotFoundException]
+ * or [NoSuchMethodException] thrown, validation will fail.
+ * Otherwise will return the validation result from the [block]
+ */
+ @JvmStatic
+ internal fun validateReflection(errorMessage: String? = null, block: () -> Boolean): Boolean {
+ return try {
+ val result = block()
+ if (!result && errorMessage != null) {
+ Log.e("ReflectionGuard", errorMessage)
+ }
+ result
+ } catch (noClass: ClassNotFoundException) {
+ Log.e("ReflectionGuard", "ClassNotFound: ${errorMessage.orEmpty()}")
+ false
+ } catch (noMethod: NoSuchMethodException) {
+ Log.e("ReflectionGuard", "NoSuchMethod: ${errorMessage.orEmpty()}")
+ false
+ }
+ }
+
+ /**
+ * Checks if a method has public modifier
+ */
+ internal val Method.isPublic: Boolean
+ get() {
+ return Modifier.isPublic(modifiers)
+ }
+
+ /**
+ * Checks if a method's return value is type of kotlin [clazz]
+ */
+ internal fun Method.doesReturn(clazz: KClass<*>): Boolean {
+ return doesReturn(clazz.java)
+ }
+
+ /**
+ * Checks if a method's return value is type of java [clazz]
+ */
+ internal fun Method.doesReturn(clazz: Class<*>): Boolean {
+ return returnType.equals(clazz)
+ }
+}
\ No newline at end of file
diff --git a/window/window/src/main/java/androidx/window/reflection/WindowExtensionsConstants.kt b/window/window/src/main/java/androidx/window/reflection/WindowExtensionsConstants.kt
new file mode 100644
index 0000000..341e019
--- /dev/null
+++ b/window/window/src/main/java/androidx/window/reflection/WindowExtensionsConstants.kt
@@ -0,0 +1,74 @@
+/*
+ * Copyright 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.window.reflection
+
+/**
+ * Constants for WindowExtensions
+ */
+internal object WindowExtensionsConstants {
+ /**
+ * Constant name for package [androidx.window.extensions]
+ */
+ private const val WINDOW_EXTENSIONS_PACKAGE_NAME = "androidx.window.extensions"
+
+ /**
+ * Constant name for class [androidx.window.extensions.WindowExtensionsProvider] used
+ * for reflection
+ */
+ internal const val WINDOW_EXTENSIONS_PROVIDER_CLASS =
+ "$WINDOW_EXTENSIONS_PACKAGE_NAME.WindowExtensionsProvider"
+
+ /**
+ * Constant name for class [androidx.window.extensions.WindowExtensions] used for reflection
+ */
+ internal const val WINDOW_EXTENSIONS_CLASS =
+ "$WINDOW_EXTENSIONS_PACKAGE_NAME.WindowExtensions"
+
+ /**
+ * Constant name for class [androidx.window.extensions.layout.FoldingFeature]
+ * used for reflection
+ */
+ internal const val FOLDING_FEATURE_CLASS =
+ "$WINDOW_EXTENSIONS_PACKAGE_NAME.layout.FoldingFeature"
+
+ /**
+ * Constant name for class [androidx.window.extensions.layout.WindowLayoutComponent]
+ * used for reflection
+ */
+ internal const val WINDOW_LAYOUT_COMPONENT_CLASS =
+ "$WINDOW_EXTENSIONS_PACKAGE_NAME.layout.WindowLayoutComponent"
+
+ /**
+ * Constant name for class [androidx.window.extensions.embedding.ActivityEmbeddingComponent]
+ * used for reflection
+ */
+ internal const val ACTIVITY_EMBEDDING_COMPONENT_CLASS =
+ "$WINDOW_EXTENSIONS_PACKAGE_NAME.embedding.ActivityEmbeddingComponent"
+
+ /**
+ * Constant name for class [androidx.window.extensions.core.util.function]
+ * used for reflection
+ */
+ internal const val WINDOW_CONSUMER =
+ "$WINDOW_EXTENSIONS_PACKAGE_NAME.core.util.function.Consumer"
+
+ /**
+ * Constant name for class [java.util.function.Consumer]
+ * used for reflection
+ */
+ internal const val JAVA_CONSUMER = "java.util.function.Consumer"
+}
diff --git a/window/window/src/main/res/values/attrs.xml b/window/window/src/main/res/values/attrs.xml
index 8ee9802..a2880ca 100644
--- a/window/window/src/main/res/values/attrs.xml
+++ b/window/window/src/main/res/values/attrs.xml
@@ -47,8 +47,9 @@
<attr name="tag" format="string" />
<!-- An attribute for Activity Embedding rules.
Background color of Activity Embedding window animation if the animation requires a
- background.
- The default is to use the theme's windowBackground. -->
+ background. Only opaque color is supported.
+ The default is to use the current theme's windowBackground. Any non-opaque color will be
+ treated the same as default. -->
<attr name="animationBackgroundColor" format="color" />
<!-- An attribute for Activity Embedding rules.
diff --git a/window/window/src/test/java/androidx/window/area/WindowAreaStatusUnitTest.kt b/window/window/src/test/java/androidx/window/area/WindowAreaStatusUnitTest.kt
new file mode 100644
index 0000000..04d3702
--- /dev/null
+++ b/window/window/src/test/java/androidx/window/area/WindowAreaStatusUnitTest.kt
@@ -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.window.area
+
+import androidx.window.core.ExperimentalWindowApi
+import androidx.window.extensions.area.WindowAreaComponent
+import org.junit.Test
+
+/**
+ * Unit tests for [WindowAreaStatus] that run on the JVM.
+ */
+@OptIn(ExperimentalWindowApi::class)
+class WindowAreaStatusUnitTest {
+
+ @Test
+ fun testWindowAreaStatusTranslateValueAvailable() {
+ val expected = WindowAreaStatus.AVAILABLE
+ val translateValue = WindowAreaStatus.translate(WindowAreaComponent.STATUS_AVAILABLE)
+ assert(expected == translateValue)
+ }
+
+ @Test
+ fun testWindowAreaStatusTranslateValueUnavailable() {
+ val expected = WindowAreaStatus.UNAVAILABLE
+ val translateValue = WindowAreaStatus.translate(WindowAreaComponent.STATUS_UNAVAILABLE)
+ assert(expected == translateValue)
+ }
+
+ @Test
+ fun testWindowAreaStatusTranslateValueUnsupported() {
+ val expected = WindowAreaStatus.UNSUPPORTED
+ val translateValue = WindowAreaStatus.translate(WindowAreaComponent.STATUS_UNSUPPORTED)
+ assert(expected == translateValue)
+ }
+}
\ No newline at end of file
diff --git a/window/window/src/test/java/androidx/window/embedding/ActivityStackTest.kt b/window/window/src/test/java/androidx/window/embedding/ActivityStackTest.kt
index b13af0c..1f84586 100644
--- a/window/window/src/test/java/androidx/window/embedding/ActivityStackTest.kt
+++ b/window/window/src/test/java/androidx/window/embedding/ActivityStackTest.kt
@@ -17,7 +17,9 @@
package androidx.window.embedding
import android.app.Activity
+import android.os.Binder
import org.junit.Assert.assertEquals
+import org.junit.Assert.assertNotEquals
import org.junit.Assert.assertTrue
import org.junit.Test
import org.mockito.kotlin.mock
@@ -27,7 +29,7 @@
@Test
fun testContainsActivity() {
val activity = mock<Activity>()
- val stack = ActivityStack(listOf(activity), isEmpty = false)
+ val stack = ActivityStack(listOf(activity), isEmpty = false, Binder())
assertTrue(activity in stack)
}
@@ -35,10 +37,17 @@
@Test
fun testEqualsImpliesHashCode() {
val activity = mock<Activity>()
- val first = ActivityStack(listOf(activity), isEmpty = false)
- val second = ActivityStack(listOf(activity), isEmpty = false)
+ val token = Binder()
+ val first = ActivityStack(listOf(activity), isEmpty = false, token)
+ val second = ActivityStack(listOf(activity), isEmpty = false, token)
assertEquals(first, second)
assertEquals(first.hashCode(), second.hashCode())
+
+ val anotherToken = Binder()
+ val third = ActivityStack(emptyList(), isEmpty = true, anotherToken)
+
+ assertNotEquals(first, third)
+ assertNotEquals(first.hashCode(), third.hashCode())
}
}
\ No newline at end of file
diff --git a/window/window/src/test/java/androidx/window/embedding/SplitInfoTest.kt b/window/window/src/test/java/androidx/window/embedding/SplitInfoTest.kt
index 07c0855..780bcf9 100644
--- a/window/window/src/test/java/androidx/window/embedding/SplitInfoTest.kt
+++ b/window/window/src/test/java/androidx/window/embedding/SplitInfoTest.kt
@@ -17,6 +17,9 @@
package androidx.window.embedding
import android.app.Activity
+import android.os.Binder
+import android.os.IBinder
+import androidx.window.embedding.EmbeddingAdapter.Companion.INVALID_ACTIVITY_STACK_TOKEN
import org.junit.Assert.assertEquals
import org.junit.Assert.assertTrue
import org.junit.Test
@@ -30,7 +33,8 @@
val firstStack = createTestActivityStack(listOf(activity))
val secondStack = createTestActivityStack(emptyList())
val attributes = SplitAttributes()
- val info = SplitInfo(firstStack, secondStack, attributes)
+ val token = Binder()
+ val info = SplitInfo(firstStack, secondStack, attributes, token)
assertTrue(info.contains(activity))
}
@@ -41,7 +45,8 @@
val firstStack = createTestActivityStack(emptyList())
val secondStack = createTestActivityStack(listOf(activity))
val attributes = SplitAttributes()
- val info = SplitInfo(firstStack, secondStack, attributes)
+ val token = Binder()
+ val info = SplitInfo(firstStack, secondStack, attributes, token)
assertTrue(info.contains(activity))
}
@@ -52,8 +57,9 @@
val firstStack = createTestActivityStack(emptyList())
val secondStack = createTestActivityStack(listOf(activity))
val attributes = SplitAttributes()
- val firstInfo = SplitInfo(firstStack, secondStack, attributes)
- val secondInfo = SplitInfo(firstStack, secondStack, attributes)
+ val token = Binder()
+ val firstInfo = SplitInfo(firstStack, secondStack, attributes, token)
+ val secondInfo = SplitInfo(firstStack, secondStack, attributes, token)
assertEquals(firstInfo, secondInfo)
assertEquals(firstInfo.hashCode(), secondInfo.hashCode())
@@ -62,5 +68,6 @@
private fun createTestActivityStack(
activitiesInProcess: List<Activity>,
isEmpty: Boolean = false,
- ): ActivityStack = ActivityStack(activitiesInProcess, isEmpty)
+ token: IBinder = INVALID_ACTIVITY_STACK_TOKEN,
+ ): ActivityStack = ActivityStack(activitiesInProcess, isEmpty, token)
}
\ No newline at end of file
diff --git a/window/window/src/test/java/androidx/window/reflection/ReflectionUtilsTest.kt b/window/window/src/test/java/androidx/window/reflection/ReflectionUtilsTest.kt
new file mode 100644
index 0000000..bdab6f7
--- /dev/null
+++ b/window/window/src/test/java/androidx/window/reflection/ReflectionUtilsTest.kt
@@ -0,0 +1,88 @@
+/*
+ * Copyright 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.window.reflection
+
+import androidx.window.reflection.ReflectionUtils.doesReturn
+import androidx.window.reflection.ReflectionUtils.isPublic
+import androidx.window.reflection.ReflectionUtils.validateReflection
+import org.junit.Assert.assertFalse
+import org.junit.Assert.assertTrue
+import org.junit.Before
+import org.junit.Test
+
+/**
+ * Unit test for reflection utilities
+ */
+class ReflectionUtilsTest {
+
+ private lateinit var classLoader: ClassLoader
+
+ @Before
+ fun setup() {
+ classLoader = this::class.java.classLoader!!
+ }
+
+ @Test
+ fun testValidateReflectionSuccess() {
+ val result = validateReflection {
+ true
+ }
+ assertTrue(result)
+ }
+
+ @Test
+ fun testValidateReflectionFail() {
+ val result = validateReflection {
+ classLoader.loadClass("SomeUnExistedClass.java")
+ true
+ }
+ assertFalse(result)
+ }
+
+ @Test
+ fun testMethodModifier() {
+ val result = validateReflection {
+ val testClass = this::class.java
+ val privateMethod = testClass.getDeclaredMethod("testMethod").isPublic
+ assertFalse(privateMethod)
+ val publicMethod = testClass.getDeclaredMethod("testMethodModifier").isPublic
+ assertTrue(publicMethod)
+ true
+ }
+ assertTrue(result)
+ }
+
+ @Test
+ fun testDoesReturn() {
+ val result = validateReflection {
+ val testClass = this::class.java
+ val privateMethod = testClass.getDeclaredMethod("testMethod")
+ assertTrue(privateMethod.doesReturn(Int::class.java))
+ assertTrue(privateMethod.doesReturn(Int::class))
+ assertFalse(privateMethod.doesReturn(Any::class.java))
+ assertFalse(privateMethod.doesReturn(Any::class))
+ true
+ }
+ assertTrue(result)
+ }
+
+ // method for testing
+ @Suppress("unused")
+ private fun testMethod(): Int {
+ return 0
+ }
+}
\ No newline at end of file