Merge "Handle privileged permission allowlist and isModule"
diff --git a/Android.bp b/Android.bp
index d031284..cfab18e 100644
--- a/Android.bp
+++ b/Android.bp
@@ -110,6 +110,7 @@
":android.security.maintenance-java-source",
":android.security.metrics-java-source",
":android.system.keystore2-V3-java-source",
+ ":android.hardware.cas-V1-java-source",
":credstore_aidl",
":dumpstate_aidl",
":framework_native_aidl",
@@ -200,6 +201,7 @@
"updatable-driver-protos",
"ota_metadata_proto_java",
"android.hidl.base-V1.0-java",
+ "android.hardware.cas-V1-java", // AIDL
"android.hardware.cas-V1.0-java",
"android.hardware.cas-V1.1-java",
"android.hardware.cas-V1.2-java",
@@ -692,3 +694,12 @@
"ProtoLibraries.bp",
"TestProtoLibraries.bp",
]
+
+java_api_contribution {
+ name: "api-stubs-docs-non-updatable-public-stubs",
+ api_surface: "public",
+ api_file: "core/api/current.txt",
+ visibility: [
+ "//build/orchestrator/apis",
+ ],
+}
diff --git a/StubLibraries.bp b/StubLibraries.bp
index 272b4f6..fc046fb 100644
--- a/StubLibraries.bp
+++ b/StubLibraries.bp
@@ -378,6 +378,67 @@
},
}
+java_library {
+ name: "android_stubs_private_jar",
+ defaults: ["android.jar_defaults"],
+ visibility: [
+ "//visibility:override",
+ "//visibility:private",
+ ],
+ static_libs: [
+ "stable.core.platform.api.stubs",
+ "core-lambda-stubs-for-system-modules",
+ "core-generated-annotation-stubs",
+ "framework",
+ "ext",
+ "framework-res-package-jar",
+ // The order of this matters, it has to be last to provide a
+ // package-private androidx.annotation.RecentlyNonNull without
+ // overriding the public android.annotation.Nullable in framework.jar
+ // with its own package-private android.annotation.Nullable.
+ "private-stub-annotations-jar",
+ ],
+}
+
+java_genrule {
+ name: "android_stubs_private_hjar",
+ visibility: ["//visibility:private"],
+ srcs: [":android_stubs_private_jar{.hjar}"],
+ out: ["android_stubs_private.jar"],
+ cmd: "cp $(in) $(out)",
+}
+
+java_library {
+ name: "android_stubs_private",
+ defaults: ["android_stubs_dists_default"],
+ visibility: ["//visibility:private"],
+ sdk_version: "none",
+ system_modules: "none",
+ static_libs: ["android_stubs_private_hjar"],
+ dist: {
+ dir: "apistubs/android/private",
+ },
+}
+
+java_genrule {
+ name: "android_stubs_private_framework_aidl",
+ visibility: ["//visibility:private"],
+ tools: ["sdkparcelables"],
+ srcs: [":android_stubs_private"],
+ out: ["framework.aidl"],
+ cmd: "rm -f $(genDir)/framework.aidl.merged && " +
+ "for i in $(in); do " +
+ " rm -f $(genDir)/framework.aidl.tmp && " +
+ " $(location sdkparcelables) $$i $(genDir)/framework.aidl.tmp && " +
+ " cat $(genDir)/framework.aidl.tmp >> $(genDir)/framework.aidl.merged; " +
+ "done && " +
+ "sort -u $(genDir)/framework.aidl.merged > $(out)",
+ dist: {
+ targets: ["sdk"],
+ dir: "apistubs/android/private",
+ },
+}
+
////////////////////////////////////////////////////////////////////////
// api-versions.xml generation, for public and system. This API database
// also contains the android.test.* APIs.
@@ -537,3 +598,12 @@
],
visibility: ["//visibility:public"],
}
+
+java_api_contribution {
+ name: "frameworks-base-core-api-module-lib-stubs",
+ api_surface: "module-lib",
+ api_file: "core/api/module-lib-current.txt",
+ visibility: [
+ "//build/orchestrator/apis",
+ ],
+}
diff --git a/apct-tests/perftests/packagemanager/AndroidManifest.xml b/apct-tests/perftests/packagemanager/AndroidManifest.xml
index 3b9431f..b4a34b8 100644
--- a/apct-tests/perftests/packagemanager/AndroidManifest.xml
+++ b/apct-tests/perftests/packagemanager/AndroidManifest.xml
@@ -26,6 +26,7 @@
<permission android:name="com.android.perftests.packagemanager.TestPermission" />
<uses-permission android:name="com.android.perftests.packagemanager.TestPermission" />
+ <uses-permission android:name="android.permission.GET_APP_METADATA" />
<queries>
<package android:name="com.android.perftests.appenumeration0" />
diff --git a/apct-tests/perftests/packagemanager/src/android/os/PackageManagerPerfTest.java b/apct-tests/perftests/packagemanager/src/android/os/PackageManagerPerfTest.java
index 673c6a3..4bcc8c4 100644
--- a/apct-tests/perftests/packagemanager/src/android/os/PackageManagerPerfTest.java
+++ b/apct-tests/perftests/packagemanager/src/android/os/PackageManagerPerfTest.java
@@ -19,10 +19,15 @@
import static libcore.junit.util.compat.CoreCompatChangeRule.DisableCompatChanges;
import static libcore.junit.util.compat.CoreCompatChangeRule.EnableCompatChanges;
+import static org.junit.Assert.assertEquals;
+
+import android.Manifest;
import android.compat.testing.PlatformCompatChangeRule;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
+import android.content.IntentSender;
+import android.content.pm.PackageInstaller;
import android.content.pm.PackageManager;
import android.perftests.utils.BenchmarkState;
import android.perftests.utils.PerfStatusReporter;
@@ -31,11 +36,19 @@
import androidx.test.filters.LargeTest;
import androidx.test.platform.app.InstrumentationRegistry;
+import com.android.compatibility.common.util.AdoptShellPermissionsRule;
+import com.android.cts.install.lib.Install;
+import com.android.cts.install.lib.InstallUtils;
+import com.android.cts.install.lib.LocalIntentSender;
+import com.android.cts.install.lib.TestApp;
+
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
+import java.io.IOException;
+
@RunWith(AndroidJUnit4.class)
@LargeTest
public class PackageManagerPerfTest {
@@ -46,6 +59,8 @@
private static final ComponentName TEST_ACTIVITY =
new ComponentName("com.android.perftests.packagemanager",
"android.perftests.utils.PerfTestActivity");
+ private static final String TEST_FIELD = "test";
+ private static final String TEST_VALUE = "value";
@Rule
public final PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
@@ -53,9 +68,39 @@
@Rule
public final PlatformCompatChangeRule mPlatformCompatChangeRule =
new PlatformCompatChangeRule();
+ @Rule
+ public AdoptShellPermissionsRule mAdoptShellPermissionsRule = new AdoptShellPermissionsRule(
+ InstrumentationRegistry.getInstrumentation().getUiAutomation(),
+ Manifest.permission.INSTALL_PACKAGES,
+ Manifest.permission.DELETE_PACKAGES);
+
+ final Context mContext = InstrumentationRegistry.getInstrumentation().getContext();
+ private PackageInstaller mPackageInstaller;
public PackageManagerPerfTest() throws PackageManager.NameNotFoundException {
- final Context context = InstrumentationRegistry.getInstrumentation().getContext();
+ mPackageInstaller = mContext.getPackageManager().getPackageInstaller();
+ }
+
+ private void installTestApp(TestApp testApp) throws IOException, InterruptedException {
+ Install install = Install.single(testApp);
+ final int expectedSessionId = install.createSession();
+ PackageInstaller.Session session =
+ InstallUtils.openPackageInstallerSession(expectedSessionId);
+ PersistableBundle bundle = new PersistableBundle();
+ bundle.putString(TEST_FIELD, TEST_VALUE);
+ session.setAppMetadata(bundle);
+ LocalIntentSender localIntentSender = new LocalIntentSender();
+ session.commit(localIntentSender.getIntentSender());
+ Intent intent = localIntentSender.getResult();
+ InstallUtils.assertStatusSuccess(intent);
+ }
+
+ private void uninstallTestApp(String packageName) throws InterruptedException {
+ LocalIntentSender localIntentSender = new LocalIntentSender();
+ IntentSender intentSender = localIntentSender.getIntentSender();
+ mPackageInstaller.uninstall(packageName, intentSender);
+ Intent intent = localIntentSender.getResult();
+ InstallUtils.assertStatusSuccess(intent);
}
@Before
@@ -65,6 +110,24 @@
}
@Test
+ public void testGetAppMetadata() throws Exception {
+ final BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ installTestApp(TestApp.A1);
+ final PackageManager pm =
+ InstrumentationRegistry.getInstrumentation().getTargetContext().getPackageManager();
+ final String packageName = TestApp.A1.getPackageName();
+
+ while (state.keepRunning()) {
+ PersistableBundle bundle = pm.getAppMetadata(packageName);
+ state.pauseTiming();
+ assertEquals(bundle.size(), 1);
+ assertEquals(bundle.getString(TEST_FIELD), TEST_VALUE);
+ state.resumeTiming();
+ }
+ uninstallTestApp(packageName);
+ }
+
+ @Test
@DisableCompatChanges(PackageManager.FILTER_APPLICATION_QUERY)
public void testCheckPermissionExists() {
final BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
diff --git a/apex/jobscheduler/framework/java/android/app/job/JobServiceEngine.java b/apex/jobscheduler/framework/java/android/app/job/JobServiceEngine.java
index 53e452f..697641e 100644
--- a/apex/jobscheduler/framework/java/android/app/job/JobServiceEngine.java
+++ b/apex/jobscheduler/framework/java/android/app/job/JobServiceEngine.java
@@ -418,11 +418,12 @@
/**
* Call in to engine to report data transfer progress.
*
- * @hide
* @see JobService#updateTransferredNetworkBytes(JobParameters, long, long)
+ * @see JobService#updateTransferredNetworkBytes(JobParameters, JobWorkItem, long, long)
*/
public void updateTransferredNetworkBytes(@NonNull JobParameters params,
- @Nullable JobWorkItem item, long downloadBytes, long uploadBytes) {
+ @Nullable JobWorkItem item,
+ @BytesLong long downloadBytes, @BytesLong long uploadBytes) {
if (params == null) {
throw new NullPointerException("params");
}
@@ -437,11 +438,11 @@
/**
* Call in to engine to report data transfer progress.
*
- * @hide
+ * @see JobService#updateEstimatedNetworkBytes(JobParameters, long, long)
* @see JobService#updateEstimatedNetworkBytes(JobParameters, JobWorkItem, long, long)
*/
public void updateEstimatedNetworkBytes(@NonNull JobParameters params,
- @NonNull JobWorkItem item,
+ @Nullable JobWorkItem item,
@BytesLong long downloadBytes, @BytesLong long uploadBytes) {
if (params == null) {
throw new NullPointerException("params");
@@ -457,7 +458,6 @@
/**
* Give JobScheduler a notification to tie to this job's lifecycle.
*
- * @hide
* @see JobService#setNotification(JobParameters, int, Notification, int)
*/
public void setNotification(@NonNull JobParameters params, int notificationId,
diff --git a/apex/jobscheduler/service/java/com/android/server/job/JobConcurrencyManager.java b/apex/jobscheduler/service/java/com/android/server/job/JobConcurrencyManager.java
index b806ef8..e0e0b4b 100644
--- a/apex/jobscheduler/service/java/com/android/server/job/JobConcurrencyManager.java
+++ b/apex/jobscheduler/service/java/com/android/server/job/JobConcurrencyManager.java
@@ -17,6 +17,7 @@
package com.android.server.job;
import static android.text.format.DateUtils.MINUTE_IN_MILLIS;
+import static android.util.DataUnit.GIGABYTES;
import static com.android.server.job.JobSchedulerService.RESTRICTED_INDEX;
import static com.android.server.job.JobSchedulerService.sElapsedRealtimeClock;
@@ -58,6 +59,7 @@
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.app.IBatteryStats;
import com.android.internal.app.procstats.ProcessStats;
+import com.android.internal.util.MemInfoReader;
import com.android.internal.util.StatLogger;
import com.android.server.JobSchedulerBackgroundThread;
import com.android.server.LocalServices;
@@ -85,11 +87,33 @@
private static final boolean DEBUG = JobSchedulerService.DEBUG;
/** The maximum number of concurrent jobs we'll aim to run at one time. */
- public static final int STANDARD_CONCURRENCY_LIMIT = 16;
+ @VisibleForTesting
+ static final int MAX_CONCURRENCY_LIMIT = 64;
/** The maximum number of objects we should retain in memory when not in use. */
- private static final int MAX_RETAINED_OBJECTS = (int) (1.5 * STANDARD_CONCURRENCY_LIMIT);
+ private static final int MAX_RETAINED_OBJECTS = (int) (1.5 * MAX_CONCURRENCY_LIMIT);
static final String CONFIG_KEY_PREFIX_CONCURRENCY = "concurrency_";
+ private static final String KEY_CONCURRENCY_LIMIT = CONFIG_KEY_PREFIX_CONCURRENCY + "limit";
+ @VisibleForTesting
+ static final int DEFAULT_CONCURRENCY_LIMIT;
+
+ static {
+ if (ActivityManager.isLowRamDeviceStatic()) {
+ DEFAULT_CONCURRENCY_LIMIT = 8;
+ } else {
+ final long ramBytes = new MemInfoReader().getTotalSize();
+ if (ramBytes <= GIGABYTES.toBytes(6)) {
+ DEFAULT_CONCURRENCY_LIMIT = 16;
+ } else if (ramBytes <= GIGABYTES.toBytes(8)) {
+ DEFAULT_CONCURRENCY_LIMIT = 20;
+ } else if (ramBytes <= GIGABYTES.toBytes(12)) {
+ DEFAULT_CONCURRENCY_LIMIT = 32;
+ } else {
+ DEFAULT_CONCURRENCY_LIMIT = 40;
+ }
+ }
+ }
+
private static final String KEY_SCREEN_OFF_ADJUSTMENT_DELAY_MS =
CONFIG_KEY_PREFIX_CONCURRENCY + "screen_off_adjustment_delay_ms";
private static final long DEFAULT_SCREEN_OFF_ADJUSTMENT_DELAY_MS = 30_000;
@@ -100,7 +124,7 @@
@VisibleForTesting
static final String KEY_PKG_CONCURRENCY_LIMIT_REGULAR =
CONFIG_KEY_PREFIX_CONCURRENCY + "pkg_concurrency_limit_regular";
- private static final int DEFAULT_PKG_CONCURRENCY_LIMIT_REGULAR = STANDARD_CONCURRENCY_LIMIT / 2;
+ private static final int DEFAULT_PKG_CONCURRENCY_LIMIT_REGULAR = DEFAULT_CONCURRENCY_LIMIT / 2;
@VisibleForTesting
static final String KEY_ENABLE_MAX_WAIT_TIME_BYPASS =
CONFIG_KEY_PREFIX_CONCURRENCY + "enable_max_wait_time_bypass";
@@ -209,84 +233,100 @@
private static final WorkConfigLimitsPerMemoryTrimLevel CONFIG_LIMITS_SCREEN_ON =
new WorkConfigLimitsPerMemoryTrimLevel(
- new WorkTypeConfig("screen_on_normal", 11,
+ new WorkTypeConfig("screen_on_normal", DEFAULT_CONCURRENCY_LIMIT,
+ /* defaultMaxTotal */ DEFAULT_CONCURRENCY_LIMIT * 3 / 4,
// defaultMin
- List.of(Pair.create(WORK_TYPE_TOP, 4), Pair.create(WORK_TYPE_FGS, 1),
- Pair.create(WORK_TYPE_EJ, 3), Pair.create(WORK_TYPE_BG, 2),
- Pair.create(WORK_TYPE_BGUSER_IMPORTANT, 1)),
+ List.of(Pair.create(WORK_TYPE_TOP, .4f),
+ Pair.create(WORK_TYPE_FGS, .2f),
+ Pair.create(WORK_TYPE_EJ, .2f), Pair.create(WORK_TYPE_BG, .1f),
+ Pair.create(WORK_TYPE_BGUSER_IMPORTANT, .1f)),
// defaultMax
- List.of(Pair.create(WORK_TYPE_BG, 6),
- Pair.create(WORK_TYPE_BGUSER_IMPORTANT, 2),
- Pair.create(WORK_TYPE_BGUSER, 3))
+ List.of(Pair.create(WORK_TYPE_BG, .5f),
+ Pair.create(WORK_TYPE_BGUSER_IMPORTANT, .25f),
+ Pair.create(WORK_TYPE_BGUSER, .2f))
),
- new WorkTypeConfig("screen_on_moderate", 9,
+ new WorkTypeConfig("screen_on_moderate", DEFAULT_CONCURRENCY_LIMIT,
+ /* defaultMaxTotal */ DEFAULT_CONCURRENCY_LIMIT / 2,
// defaultMin
- List.of(Pair.create(WORK_TYPE_TOP, 4), Pair.create(WORK_TYPE_FGS, 1),
- Pair.create(WORK_TYPE_EJ, 2), Pair.create(WORK_TYPE_BG, 1),
- Pair.create(WORK_TYPE_BGUSER_IMPORTANT, 1)),
+ List.of(Pair.create(WORK_TYPE_TOP, .4f),
+ Pair.create(WORK_TYPE_FGS, .1f),
+ Pair.create(WORK_TYPE_EJ, .1f), Pair.create(WORK_TYPE_BG, .1f),
+ Pair.create(WORK_TYPE_BGUSER_IMPORTANT, .1f)),
// defaultMax
- List.of(Pair.create(WORK_TYPE_BG, 4),
- Pair.create(WORK_TYPE_BGUSER_IMPORTANT, 1),
- Pair.create(WORK_TYPE_BGUSER, 1))
+ List.of(Pair.create(WORK_TYPE_BG, .4f),
+ Pair.create(WORK_TYPE_BGUSER_IMPORTANT, .1f),
+ Pair.create(WORK_TYPE_BGUSER, .1f))
),
- new WorkTypeConfig("screen_on_low", 6,
+ new WorkTypeConfig("screen_on_low", DEFAULT_CONCURRENCY_LIMIT,
+ /* defaultMaxTotal */ DEFAULT_CONCURRENCY_LIMIT * 4 / 10,
// defaultMin
- List.of(Pair.create(WORK_TYPE_TOP, 4), Pair.create(WORK_TYPE_FGS, 1),
- Pair.create(WORK_TYPE_EJ, 1)),
+ List.of(Pair.create(WORK_TYPE_TOP, 2.0f / 3),
+ Pair.create(WORK_TYPE_FGS, .1f),
+ Pair.create(WORK_TYPE_EJ, .1f)),
// defaultMax
- List.of(Pair.create(WORK_TYPE_BG, 2),
- Pair.create(WORK_TYPE_BGUSER_IMPORTANT, 1),
- Pair.create(WORK_TYPE_BGUSER, 1))
+ List.of(Pair.create(WORK_TYPE_BG, 1.0f / 3),
+ Pair.create(WORK_TYPE_BGUSER_IMPORTANT, 1.0f / 6),
+ Pair.create(WORK_TYPE_BGUSER, 1.0f / 6))
),
- new WorkTypeConfig("screen_on_critical", 6,
+ new WorkTypeConfig("screen_on_critical", DEFAULT_CONCURRENCY_LIMIT,
+ /* defaultMaxTotal */ DEFAULT_CONCURRENCY_LIMIT * 4 / 10,
// defaultMin
- List.of(Pair.create(WORK_TYPE_TOP, 4), Pair.create(WORK_TYPE_FGS, 1),
- Pair.create(WORK_TYPE_EJ, 1)),
+ List.of(Pair.create(WORK_TYPE_TOP, 2.0f / 3),
+ Pair.create(WORK_TYPE_FGS, .1f),
+ Pair.create(WORK_TYPE_EJ, .1f)),
// defaultMax
- List.of(Pair.create(WORK_TYPE_BG, 1),
- Pair.create(WORK_TYPE_BGUSER_IMPORTANT, 1),
- Pair.create(WORK_TYPE_BGUSER, 1))
+ List.of(Pair.create(WORK_TYPE_BG, 1.0f / 6),
+ Pair.create(WORK_TYPE_BGUSER_IMPORTANT, 1.0f / 6),
+ Pair.create(WORK_TYPE_BGUSER, 1.0f / 6))
)
);
private static final WorkConfigLimitsPerMemoryTrimLevel CONFIG_LIMITS_SCREEN_OFF =
new WorkConfigLimitsPerMemoryTrimLevel(
- new WorkTypeConfig("screen_off_normal", 16,
+ new WorkTypeConfig("screen_off_normal", DEFAULT_CONCURRENCY_LIMIT,
+ /* defaultMaxTotal */ DEFAULT_CONCURRENCY_LIMIT,
// defaultMin
- List.of(Pair.create(WORK_TYPE_TOP, 4), Pair.create(WORK_TYPE_FGS, 2),
- Pair.create(WORK_TYPE_EJ, 3), Pair.create(WORK_TYPE_BG, 2),
- Pair.create(WORK_TYPE_BGUSER_IMPORTANT, 1)),
+ List.of(Pair.create(WORK_TYPE_TOP, .3f),
+ Pair.create(WORK_TYPE_FGS, .2f),
+ Pair.create(WORK_TYPE_EJ, .3f), Pair.create(WORK_TYPE_BG, .2f),
+ Pair.create(WORK_TYPE_BGUSER_IMPORTANT, .1f)),
// defaultMax
- List.of(Pair.create(WORK_TYPE_BG, 10),
- Pair.create(WORK_TYPE_BGUSER_IMPORTANT, 2),
- Pair.create(WORK_TYPE_BGUSER, 3))
+ List.of(Pair.create(WORK_TYPE_BG, .6f),
+ Pair.create(WORK_TYPE_BGUSER_IMPORTANT, .2f),
+ Pair.create(WORK_TYPE_BGUSER, .2f))
),
- new WorkTypeConfig("screen_off_moderate", 14,
+ new WorkTypeConfig("screen_off_moderate", DEFAULT_CONCURRENCY_LIMIT,
+ /* defaultMaxTotal */ DEFAULT_CONCURRENCY_LIMIT * 9 / 10,
// defaultMin
- List.of(Pair.create(WORK_TYPE_TOP, 4), Pair.create(WORK_TYPE_FGS, 2),
- Pair.create(WORK_TYPE_EJ, 3), Pair.create(WORK_TYPE_BG, 2),
- Pair.create(WORK_TYPE_BGUSER_IMPORTANT, 1)),
+ List.of(Pair.create(WORK_TYPE_TOP, .3f),
+ Pair.create(WORK_TYPE_FGS, .2f),
+ Pair.create(WORK_TYPE_EJ, .3f), Pair.create(WORK_TYPE_BG, .2f),
+ Pair.create(WORK_TYPE_BGUSER_IMPORTANT, .1f)),
// defaultMax
- List.of(Pair.create(WORK_TYPE_BG, 7),
- Pair.create(WORK_TYPE_BGUSER_IMPORTANT, 1),
- Pair.create(WORK_TYPE_BGUSER, 1))
+ List.of(Pair.create(WORK_TYPE_BG, .5f),
+ Pair.create(WORK_TYPE_BGUSER_IMPORTANT, .1f),
+ Pair.create(WORK_TYPE_BGUSER, .1f))
),
- new WorkTypeConfig("screen_off_low", 9,
+ new WorkTypeConfig("screen_off_low", DEFAULT_CONCURRENCY_LIMIT,
+ /* defaultMaxTotal */ DEFAULT_CONCURRENCY_LIMIT * 6 / 10,
// defaultMin
- List.of(Pair.create(WORK_TYPE_TOP, 4), Pair.create(WORK_TYPE_FGS, 1),
- Pair.create(WORK_TYPE_EJ, 2), Pair.create(WORK_TYPE_BG, 1)),
+ List.of(Pair.create(WORK_TYPE_TOP, .4f),
+ Pair.create(WORK_TYPE_FGS, .1f),
+ Pair.create(WORK_TYPE_EJ, .2f), Pair.create(WORK_TYPE_BG, .1f)),
// defaultMax
- List.of(Pair.create(WORK_TYPE_BG, 3),
- Pair.create(WORK_TYPE_BGUSER_IMPORTANT, 1),
- Pair.create(WORK_TYPE_BGUSER, 1))
+ List.of(Pair.create(WORK_TYPE_BG, .25f),
+ Pair.create(WORK_TYPE_BGUSER_IMPORTANT, .1f),
+ Pair.create(WORK_TYPE_BGUSER, .1f))
),
- new WorkTypeConfig("screen_off_critical", 6,
+ new WorkTypeConfig("screen_off_critical", DEFAULT_CONCURRENCY_LIMIT,
+ /* defaultMaxTotal */ DEFAULT_CONCURRENCY_LIMIT * 4 / 10,
// defaultMin
- List.of(Pair.create(WORK_TYPE_TOP, 4), Pair.create(WORK_TYPE_FGS, 1),
- Pair.create(WORK_TYPE_EJ, 1)),
+ List.of(Pair.create(WORK_TYPE_TOP, .5f),
+ Pair.create(WORK_TYPE_FGS, .1f),
+ Pair.create(WORK_TYPE_EJ, .1f)),
// defaultMax
- List.of(Pair.create(WORK_TYPE_BG, 1),
- Pair.create(WORK_TYPE_BGUSER_IMPORTANT, 1),
- Pair.create(WORK_TYPE_BGUSER, 1))
+ List.of(Pair.create(WORK_TYPE_BG, .1f),
+ Pair.create(WORK_TYPE_BGUSER_IMPORTANT, .1f),
+ Pair.create(WORK_TYPE_BGUSER, .1f))
)
);
@@ -358,6 +398,12 @@
private long mScreenOffAdjustmentDelayMs = DEFAULT_SCREEN_OFF_ADJUSTMENT_DELAY_MS;
/**
+ * The maximum number of jobs we'll attempt to have running at one time. This may occasionally
+ * be exceeded based on other factors.
+ */
+ private int mSteadyStateConcurrencyLimit = DEFAULT_CONCURRENCY_LIMIT;
+
+ /**
* The maximum number of expedited jobs a single userId-package can have running simultaneously.
* TOP apps are not limited.
*/
@@ -451,7 +497,7 @@
void onThirdPartyAppsCanStart() {
final IBatteryStats batteryStats = IBatteryStats.Stub.asInterface(
ServiceManager.getService(BatteryStats.SERVICE_NAME));
- for (int i = 0; i < STANDARD_CONCURRENCY_LIMIT; i++) {
+ for (int i = 0; i < mSteadyStateConcurrencyLimit; ++i) {
mIdleContexts.add(
mInjector.createJobServiceContext(mService, this,
mNotificationCoordinator, batteryStats,
@@ -778,13 +824,14 @@
}
preferredUidOnly.sort(sDeterminationComparator);
stoppable.sort(sDeterminationComparator);
- for (int i = numRunningJobs; i < STANDARD_CONCURRENCY_LIMIT; ++i) {
+ for (int i = numRunningJobs; i < mSteadyStateConcurrencyLimit; ++i) {
final JobServiceContext jsc;
final int numIdleContexts = mIdleContexts.size();
if (numIdleContexts > 0) {
jsc = mIdleContexts.removeAt(numIdleContexts - 1);
} else {
- Slog.wtf(TAG, "Had fewer than " + STANDARD_CONCURRENCY_LIMIT + " in existence");
+ // This could happen if the config is changed at runtime.
+ Slog.w(TAG, "Had fewer than " + mSteadyStateConcurrencyLimit + " in existence");
jsc = createNewJobServiceContext();
}
@@ -850,7 +897,7 @@
ContextAssignment selectedContext = null;
final int allWorkTypes = getJobWorkTypes(nextPending);
final boolean pkgConcurrencyOkay = !isPkgConcurrencyLimitedLocked(nextPending);
- final boolean isInOverage = projectedRunningCount > STANDARD_CONCURRENCY_LIMIT;
+ final boolean isInOverage = projectedRunningCount > mSteadyStateConcurrencyLimit;
boolean startingJob = false;
if (idle.size() > 0) {
final int idx = idle.size() - 1;
@@ -1398,7 +1445,7 @@
noteConcurrency();
return;
}
- if (mActiveServices.size() >= STANDARD_CONCURRENCY_LIMIT) {
+ if (mActiveServices.size() >= mSteadyStateConcurrencyLimit) {
final boolean respectConcurrencyLimit;
if (!mMaxWaitTimeBypassEnabled) {
respectConcurrencyLimit = true;
@@ -1801,23 +1848,27 @@
DeviceConfig.Properties properties =
DeviceConfig.getProperties(DeviceConfig.NAMESPACE_JOB_SCHEDULER);
+ // Concurrency limit should be in the range [8, MAX_CONCURRENCY_LIMIT].
+ mSteadyStateConcurrencyLimit = Math.max(8, Math.min(MAX_CONCURRENCY_LIMIT,
+ properties.getInt(KEY_CONCURRENCY_LIMIT, DEFAULT_CONCURRENCY_LIMIT)));
+
mScreenOffAdjustmentDelayMs = properties.getLong(
KEY_SCREEN_OFF_ADJUSTMENT_DELAY_MS, DEFAULT_SCREEN_OFF_ADJUSTMENT_DELAY_MS);
- CONFIG_LIMITS_SCREEN_ON.normal.update(properties);
- CONFIG_LIMITS_SCREEN_ON.moderate.update(properties);
- CONFIG_LIMITS_SCREEN_ON.low.update(properties);
- CONFIG_LIMITS_SCREEN_ON.critical.update(properties);
+ CONFIG_LIMITS_SCREEN_ON.normal.update(properties, mSteadyStateConcurrencyLimit);
+ CONFIG_LIMITS_SCREEN_ON.moderate.update(properties, mSteadyStateConcurrencyLimit);
+ CONFIG_LIMITS_SCREEN_ON.low.update(properties, mSteadyStateConcurrencyLimit);
+ CONFIG_LIMITS_SCREEN_ON.critical.update(properties, mSteadyStateConcurrencyLimit);
- CONFIG_LIMITS_SCREEN_OFF.normal.update(properties);
- CONFIG_LIMITS_SCREEN_OFF.moderate.update(properties);
- CONFIG_LIMITS_SCREEN_OFF.low.update(properties);
- CONFIG_LIMITS_SCREEN_OFF.critical.update(properties);
+ CONFIG_LIMITS_SCREEN_OFF.normal.update(properties, mSteadyStateConcurrencyLimit);
+ CONFIG_LIMITS_SCREEN_OFF.moderate.update(properties, mSteadyStateConcurrencyLimit);
+ CONFIG_LIMITS_SCREEN_OFF.low.update(properties, mSteadyStateConcurrencyLimit);
+ CONFIG_LIMITS_SCREEN_OFF.critical.update(properties, mSteadyStateConcurrencyLimit);
- // Package concurrency limits must in the range [1, STANDARD_CONCURRENCY_LIMIT].
- mPkgConcurrencyLimitEj = Math.max(1, Math.min(STANDARD_CONCURRENCY_LIMIT,
+ // Package concurrency limits must in the range [1, mSteadyStateConcurrencyLimit].
+ mPkgConcurrencyLimitEj = Math.max(1, Math.min(mSteadyStateConcurrencyLimit,
properties.getInt(KEY_PKG_CONCURRENCY_LIMIT_EJ, DEFAULT_PKG_CONCURRENCY_LIMIT_EJ)));
- mPkgConcurrencyLimitRegular = Math.max(1, Math.min(STANDARD_CONCURRENCY_LIMIT,
+ mPkgConcurrencyLimitRegular = Math.max(1, Math.min(mSteadyStateConcurrencyLimit,
properties.getInt(
KEY_PKG_CONCURRENCY_LIMIT_REGULAR, DEFAULT_PKG_CONCURRENCY_LIMIT_REGULAR)));
@@ -1838,6 +1889,7 @@
try {
pw.println("Configuration:");
pw.increaseIndent();
+ pw.print(KEY_CONCURRENCY_LIMIT, mSteadyStateConcurrencyLimit).println();
pw.print(KEY_SCREEN_OFF_ADJUSTMENT_DELAY_MS, mScreenOffAdjustmentDelayMs).println();
pw.print(KEY_PKG_CONCURRENCY_LIMIT_EJ, mPkgConcurrencyLimitEj).println();
pw.print(KEY_PKG_CONCURRENCY_LIMIT_REGULAR, mPkgConcurrencyLimitRegular).println();
@@ -2041,130 +2093,181 @@
@VisibleForTesting
static class WorkTypeConfig {
- @VisibleForTesting
- static final String KEY_PREFIX_MAX = CONFIG_KEY_PREFIX_CONCURRENCY + "max_";
- @VisibleForTesting
- static final String KEY_PREFIX_MIN = CONFIG_KEY_PREFIX_CONCURRENCY + "min_";
+ private static final String KEY_PREFIX_MAX = CONFIG_KEY_PREFIX_CONCURRENCY + "max_";
+ private static final String KEY_PREFIX_MIN = CONFIG_KEY_PREFIX_CONCURRENCY + "min_";
@VisibleForTesting
static final String KEY_PREFIX_MAX_TOTAL = CONFIG_KEY_PREFIX_CONCURRENCY + "max_total_";
- private static final String KEY_PREFIX_MAX_TOP = CONFIG_KEY_PREFIX_CONCURRENCY + "max_top_";
- private static final String KEY_PREFIX_MAX_FGS = CONFIG_KEY_PREFIX_CONCURRENCY + "max_fgs_";
- private static final String KEY_PREFIX_MAX_EJ = CONFIG_KEY_PREFIX_CONCURRENCY + "max_ej_";
- private static final String KEY_PREFIX_MAX_BG = CONFIG_KEY_PREFIX_CONCURRENCY + "max_bg_";
- private static final String KEY_PREFIX_MAX_BGUSER =
- CONFIG_KEY_PREFIX_CONCURRENCY + "max_bguser_";
- private static final String KEY_PREFIX_MAX_BGUSER_IMPORTANT =
- CONFIG_KEY_PREFIX_CONCURRENCY + "max_bguser_important_";
- private static final String KEY_PREFIX_MIN_TOP = CONFIG_KEY_PREFIX_CONCURRENCY + "min_top_";
- private static final String KEY_PREFIX_MIN_FGS = CONFIG_KEY_PREFIX_CONCURRENCY + "min_fgs_";
- private static final String KEY_PREFIX_MIN_EJ = CONFIG_KEY_PREFIX_CONCURRENCY + "min_ej_";
- private static final String KEY_PREFIX_MIN_BG = CONFIG_KEY_PREFIX_CONCURRENCY + "min_bg_";
- private static final String KEY_PREFIX_MIN_BGUSER =
- CONFIG_KEY_PREFIX_CONCURRENCY + "min_bguser_";
- private static final String KEY_PREFIX_MIN_BGUSER_IMPORTANT =
- CONFIG_KEY_PREFIX_CONCURRENCY + "min_bguser_important_";
+ @VisibleForTesting
+ static final String KEY_PREFIX_MAX_RATIO = KEY_PREFIX_MAX + "ratio_";
+ private static final String KEY_PREFIX_MAX_RATIO_TOP = KEY_PREFIX_MAX_RATIO + "top_";
+ private static final String KEY_PREFIX_MAX_RATIO_FGS = KEY_PREFIX_MAX_RATIO + "fgs_";
+ private static final String KEY_PREFIX_MAX_RATIO_EJ = KEY_PREFIX_MAX_RATIO + "ej_";
+ private static final String KEY_PREFIX_MAX_RATIO_BG = KEY_PREFIX_MAX_RATIO + "bg_";
+ private static final String KEY_PREFIX_MAX_RATIO_BGUSER = KEY_PREFIX_MAX_RATIO + "bguser_";
+ private static final String KEY_PREFIX_MAX_RATIO_BGUSER_IMPORTANT =
+ KEY_PREFIX_MAX_RATIO + "bguser_important_";
+ @VisibleForTesting
+ static final String KEY_PREFIX_MIN_RATIO = KEY_PREFIX_MIN + "ratio_";
+ private static final String KEY_PREFIX_MIN_RATIO_TOP = KEY_PREFIX_MIN_RATIO + "top_";
+ private static final String KEY_PREFIX_MIN_RATIO_FGS = KEY_PREFIX_MIN_RATIO + "fgs_";
+ private static final String KEY_PREFIX_MIN_RATIO_EJ = KEY_PREFIX_MIN_RATIO + "ej_";
+ private static final String KEY_PREFIX_MIN_RATIO_BG = KEY_PREFIX_MIN_RATIO + "bg_";
+ private static final String KEY_PREFIX_MIN_RATIO_BGUSER = KEY_PREFIX_MIN_RATIO + "bguser_";
+ private static final String KEY_PREFIX_MIN_RATIO_BGUSER_IMPORTANT =
+ KEY_PREFIX_MIN_RATIO + "bguser_important_";
private final String mConfigIdentifier;
private int mMaxTotal;
private final SparseIntArray mMinReservedSlots = new SparseIntArray(NUM_WORK_TYPES);
private final SparseIntArray mMaxAllowedSlots = new SparseIntArray(NUM_WORK_TYPES);
private final int mDefaultMaxTotal;
- private final SparseIntArray mDefaultMinReservedSlots = new SparseIntArray(NUM_WORK_TYPES);
- private final SparseIntArray mDefaultMaxAllowedSlots = new SparseIntArray(NUM_WORK_TYPES);
+ // We use SparseIntArrays to store floats because there is currently no SparseFloatArray
+ // available, and it doesn't seem worth it to add such a data structure just for this
+ // use case. We don't use SparseDoubleArrays because DeviceConfig only supports floats and
+ // converting between floats and ints is more straightforward than floats and doubles.
+ private final SparseIntArray mDefaultMinReservedSlotsRatio =
+ new SparseIntArray(NUM_WORK_TYPES);
+ private final SparseIntArray mDefaultMaxAllowedSlotsRatio =
+ new SparseIntArray(NUM_WORK_TYPES);
- WorkTypeConfig(@NonNull String configIdentifier, int defaultMaxTotal,
- List<Pair<Integer, Integer>> defaultMin, List<Pair<Integer, Integer>> defaultMax) {
+ WorkTypeConfig(@NonNull String configIdentifier,
+ int steadyStateConcurrencyLimit, int defaultMaxTotal,
+ List<Pair<Integer, Float>> defaultMinRatio,
+ List<Pair<Integer, Float>> defaultMaxRatio) {
mConfigIdentifier = configIdentifier;
- mDefaultMaxTotal = mMaxTotal = Math.min(defaultMaxTotal, STANDARD_CONCURRENCY_LIMIT);
+ mDefaultMaxTotal = mMaxTotal = Math.min(defaultMaxTotal, steadyStateConcurrencyLimit);
int numReserved = 0;
- for (int i = defaultMin.size() - 1; i >= 0; --i) {
- mDefaultMinReservedSlots.put(defaultMin.get(i).first, defaultMin.get(i).second);
- numReserved += defaultMin.get(i).second;
+ for (int i = defaultMinRatio.size() - 1; i >= 0; --i) {
+ final float ratio = defaultMinRatio.get(i).second;
+ final int wt = defaultMinRatio.get(i).first;
+ if (ratio < 0 || 1 <= ratio) {
+ // 1 means to reserve everything. This shouldn't be allowed.
+ // We only create new configs on boot, so this should trigger during development
+ // (before the code gets checked in), so this makes sure the hard-coded defaults
+ // make sense. DeviceConfig values will be handled gracefully in update().
+ throw new IllegalArgumentException("Invalid default min ratio: wt=" + wt
+ + " minRatio=" + ratio);
+ }
+ mDefaultMinReservedSlotsRatio.put(wt, Float.floatToRawIntBits(ratio));
+ numReserved += mMaxTotal * ratio;
}
if (mDefaultMaxTotal < 0 || numReserved > mDefaultMaxTotal) {
// We only create new configs on boot, so this should trigger during development
// (before the code gets checked in), so this makes sure the hard-coded defaults
// make sense. DeviceConfig values will be handled gracefully in update().
throw new IllegalArgumentException("Invalid default config: t=" + defaultMaxTotal
- + " min=" + defaultMin + " max=" + defaultMax);
+ + " min=" + defaultMinRatio + " max=" + defaultMaxRatio);
}
- for (int i = defaultMax.size() - 1; i >= 0; --i) {
- mDefaultMaxAllowedSlots.put(defaultMax.get(i).first, defaultMax.get(i).second);
+ for (int i = defaultMaxRatio.size() - 1; i >= 0; --i) {
+ final float ratio = defaultMaxRatio.get(i).second;
+ final int wt = defaultMaxRatio.get(i).first;
+ final float minRatio =
+ Float.intBitsToFloat(mDefaultMinReservedSlotsRatio.get(wt, 0));
+ if (ratio < minRatio || ratio <= 0) {
+ // Max ratio shouldn't be <= 0 or less than minRatio.
+ throw new IllegalArgumentException("Invalid default config:"
+ + " t=" + defaultMaxTotal
+ + " min=" + defaultMinRatio + " max=" + defaultMaxRatio);
+ }
+ mDefaultMaxAllowedSlotsRatio.put(wt, Float.floatToRawIntBits(ratio));
}
update(new DeviceConfig.Properties.Builder(
- DeviceConfig.NAMESPACE_JOB_SCHEDULER).build());
+ DeviceConfig.NAMESPACE_JOB_SCHEDULER).build(), steadyStateConcurrencyLimit);
}
- void update(@NonNull DeviceConfig.Properties properties) {
- // Ensure total in the range [1, STANDARD_CONCURRENCY_LIMIT].
- mMaxTotal = Math.max(1, Math.min(STANDARD_CONCURRENCY_LIMIT,
+ void update(@NonNull DeviceConfig.Properties properties, int steadyStateConcurrencyLimit) {
+ // Ensure total in the range [1, mSteadyStateConcurrencyLimit].
+ mMaxTotal = Math.max(1, Math.min(steadyStateConcurrencyLimit,
properties.getInt(KEY_PREFIX_MAX_TOTAL + mConfigIdentifier, mDefaultMaxTotal)));
+ final int oneIntBits = Float.floatToIntBits(1);
+
mMaxAllowedSlots.clear();
// Ensure they're in the range [1, total].
- final int maxTop = Math.max(1, Math.min(mMaxTotal,
- properties.getInt(KEY_PREFIX_MAX_TOP + mConfigIdentifier,
- mDefaultMaxAllowedSlots.get(WORK_TYPE_TOP, mMaxTotal))));
+ final int maxTop = getMaxValue(properties,
+ KEY_PREFIX_MAX_RATIO_TOP + mConfigIdentifier, WORK_TYPE_TOP, oneIntBits);
mMaxAllowedSlots.put(WORK_TYPE_TOP, maxTop);
- final int maxFgs = Math.max(1, Math.min(mMaxTotal,
- properties.getInt(KEY_PREFIX_MAX_FGS + mConfigIdentifier,
- mDefaultMaxAllowedSlots.get(WORK_TYPE_FGS, mMaxTotal))));
+ final int maxFgs = getMaxValue(properties,
+ KEY_PREFIX_MAX_RATIO_FGS + mConfigIdentifier, WORK_TYPE_FGS, oneIntBits);
mMaxAllowedSlots.put(WORK_TYPE_FGS, maxFgs);
- final int maxEj = Math.max(1, Math.min(mMaxTotal,
- properties.getInt(KEY_PREFIX_MAX_EJ + mConfigIdentifier,
- mDefaultMaxAllowedSlots.get(WORK_TYPE_EJ, mMaxTotal))));
+ final int maxEj = getMaxValue(properties,
+ KEY_PREFIX_MAX_RATIO_EJ + mConfigIdentifier, WORK_TYPE_EJ, oneIntBits);
mMaxAllowedSlots.put(WORK_TYPE_EJ, maxEj);
- final int maxBg = Math.max(1, Math.min(mMaxTotal,
- properties.getInt(KEY_PREFIX_MAX_BG + mConfigIdentifier,
- mDefaultMaxAllowedSlots.get(WORK_TYPE_BG, mMaxTotal))));
+ final int maxBg = getMaxValue(properties,
+ KEY_PREFIX_MAX_RATIO_BG + mConfigIdentifier, WORK_TYPE_BG, oneIntBits);
mMaxAllowedSlots.put(WORK_TYPE_BG, maxBg);
- final int maxBgUserImp = Math.max(1, Math.min(mMaxTotal,
- properties.getInt(KEY_PREFIX_MAX_BGUSER_IMPORTANT + mConfigIdentifier,
- mDefaultMaxAllowedSlots.get(WORK_TYPE_BGUSER_IMPORTANT, mMaxTotal))));
+ final int maxBgUserImp = getMaxValue(properties,
+ KEY_PREFIX_MAX_RATIO_BGUSER_IMPORTANT + mConfigIdentifier,
+ WORK_TYPE_BGUSER_IMPORTANT, oneIntBits);
mMaxAllowedSlots.put(WORK_TYPE_BGUSER_IMPORTANT, maxBgUserImp);
- final int maxBgUser = Math.max(1, Math.min(mMaxTotal,
- properties.getInt(KEY_PREFIX_MAX_BGUSER + mConfigIdentifier,
- mDefaultMaxAllowedSlots.get(WORK_TYPE_BGUSER, mMaxTotal))));
+ final int maxBgUser = getMaxValue(properties,
+ KEY_PREFIX_MAX_RATIO_BGUSER + mConfigIdentifier, WORK_TYPE_BGUSER, oneIntBits);
mMaxAllowedSlots.put(WORK_TYPE_BGUSER, maxBgUser);
int remaining = mMaxTotal;
mMinReservedSlots.clear();
// Ensure top is in the range [1, min(maxTop, total)]
- final int minTop = Math.max(1, Math.min(Math.min(maxTop, mMaxTotal),
- properties.getInt(KEY_PREFIX_MIN_TOP + mConfigIdentifier,
- mDefaultMinReservedSlots.get(WORK_TYPE_TOP))));
+ final int minTop = getMinValue(properties,
+ KEY_PREFIX_MIN_RATIO_TOP + mConfigIdentifier, WORK_TYPE_TOP,
+ 1, Math.min(maxTop, mMaxTotal));
mMinReservedSlots.put(WORK_TYPE_TOP, minTop);
remaining -= minTop;
// Ensure fgs is in the range [0, min(maxFgs, remaining)]
- final int minFgs = Math.max(0, Math.min(Math.min(maxFgs, remaining),
- properties.getInt(KEY_PREFIX_MIN_FGS + mConfigIdentifier,
- mDefaultMinReservedSlots.get(WORK_TYPE_FGS))));
+ final int minFgs = getMinValue(properties,
+ KEY_PREFIX_MIN_RATIO_FGS + mConfigIdentifier, WORK_TYPE_FGS,
+ 0, Math.min(maxFgs, remaining));
mMinReservedSlots.put(WORK_TYPE_FGS, minFgs);
remaining -= minFgs;
// Ensure ej is in the range [0, min(maxEj, remaining)]
- final int minEj = Math.max(0, Math.min(Math.min(maxEj, remaining),
- properties.getInt(KEY_PREFIX_MIN_EJ + mConfigIdentifier,
- mDefaultMinReservedSlots.get(WORK_TYPE_EJ))));
+ final int minEj = getMinValue(properties,
+ KEY_PREFIX_MIN_RATIO_EJ + mConfigIdentifier, WORK_TYPE_EJ,
+ 0, Math.min(maxEj, remaining));
mMinReservedSlots.put(WORK_TYPE_EJ, minEj);
remaining -= minEj;
// Ensure bg is in the range [0, min(maxBg, remaining)]
- final int minBg = Math.max(0, Math.min(Math.min(maxBg, remaining),
- properties.getInt(KEY_PREFIX_MIN_BG + mConfigIdentifier,
- mDefaultMinReservedSlots.get(WORK_TYPE_BG))));
+ final int minBg = getMinValue(properties,
+ KEY_PREFIX_MIN_RATIO_BG + mConfigIdentifier, WORK_TYPE_BG,
+ 0, Math.min(maxBg, remaining));
mMinReservedSlots.put(WORK_TYPE_BG, minBg);
remaining -= minBg;
// Ensure bg user imp is in the range [0, min(maxBgUserImp, remaining)]
- final int minBgUserImp = Math.max(0, Math.min(Math.min(maxBgUserImp, remaining),
- properties.getInt(KEY_PREFIX_MIN_BGUSER_IMPORTANT + mConfigIdentifier,
- mDefaultMinReservedSlots.get(WORK_TYPE_BGUSER_IMPORTANT, 0))));
+ final int minBgUserImp = getMinValue(properties,
+ KEY_PREFIX_MIN_RATIO_BGUSER_IMPORTANT + mConfigIdentifier,
+ WORK_TYPE_BGUSER_IMPORTANT, 0, Math.min(maxBgUserImp, remaining));
mMinReservedSlots.put(WORK_TYPE_BGUSER_IMPORTANT, minBgUserImp);
+ remaining -= minBgUserImp;
// Ensure bg user is in the range [0, min(maxBgUser, remaining)]
- final int minBgUser = Math.max(0, Math.min(Math.min(maxBgUser, remaining),
- properties.getInt(KEY_PREFIX_MIN_BGUSER + mConfigIdentifier,
- mDefaultMinReservedSlots.get(WORK_TYPE_BGUSER, 0))));
+ final int minBgUser = getMinValue(properties,
+ KEY_PREFIX_MIN_RATIO_BGUSER + mConfigIdentifier, WORK_TYPE_BGUSER,
+ 0, Math.min(maxBgUser, remaining));
mMinReservedSlots.put(WORK_TYPE_BGUSER, minBgUser);
}
+ /**
+ * Return the calculated max value for the work type.
+ * @param defaultFloatInIntBits A {@code float} value in int bits representation (using
+ * {@link Float#floatToIntBits(float)}.
+ */
+ private int getMaxValue(@NonNull DeviceConfig.Properties properties, @NonNull String key,
+ int workType, int defaultFloatInIntBits) {
+ final float maxRatio = Math.min(1, properties.getFloat(key,
+ Float.intBitsToFloat(
+ mDefaultMaxAllowedSlotsRatio.get(workType, defaultFloatInIntBits))));
+ // Max values should be in the range [1, total].
+ return Math.max(1, (int) (mMaxTotal * maxRatio));
+ }
+
+ /**
+ * Return the calculated min value for the work type.
+ */
+ private int getMinValue(@NonNull DeviceConfig.Properties properties, @NonNull String key,
+ int workType, int lowerLimit, int upperLimit) {
+ final float minRatio = Math.min(1,
+ properties.getFloat(key,
+ Float.intBitsToFloat(mDefaultMinReservedSlotsRatio.get(workType))));
+ return Math.max(lowerLimit, Math.min(upperLimit, (int) (mMaxTotal * minRatio)));
+ }
+
int getMaxTotal() {
return mMaxTotal;
}
@@ -2179,29 +2282,37 @@
void dump(IndentingPrintWriter pw) {
pw.print(KEY_PREFIX_MAX_TOTAL + mConfigIdentifier, mMaxTotal).println();
- pw.print(KEY_PREFIX_MIN_TOP + mConfigIdentifier, mMinReservedSlots.get(WORK_TYPE_TOP))
+ pw.print(KEY_PREFIX_MIN_RATIO_TOP + mConfigIdentifier,
+ mMinReservedSlots.get(WORK_TYPE_TOP))
.println();
- pw.print(KEY_PREFIX_MAX_TOP + mConfigIdentifier, mMaxAllowedSlots.get(WORK_TYPE_TOP))
+ pw.print(KEY_PREFIX_MAX_RATIO_TOP + mConfigIdentifier,
+ mMaxAllowedSlots.get(WORK_TYPE_TOP))
.println();
- pw.print(KEY_PREFIX_MIN_FGS + mConfigIdentifier, mMinReservedSlots.get(WORK_TYPE_FGS))
+ pw.print(KEY_PREFIX_MIN_RATIO_FGS + mConfigIdentifier,
+ mMinReservedSlots.get(WORK_TYPE_FGS))
.println();
- pw.print(KEY_PREFIX_MAX_FGS + mConfigIdentifier, mMaxAllowedSlots.get(WORK_TYPE_FGS))
+ pw.print(KEY_PREFIX_MAX_RATIO_FGS + mConfigIdentifier,
+ mMaxAllowedSlots.get(WORK_TYPE_FGS))
.println();
- pw.print(KEY_PREFIX_MIN_EJ + mConfigIdentifier, mMinReservedSlots.get(WORK_TYPE_EJ))
+ pw.print(KEY_PREFIX_MIN_RATIO_EJ + mConfigIdentifier,
+ mMinReservedSlots.get(WORK_TYPE_EJ))
.println();
- pw.print(KEY_PREFIX_MAX_EJ + mConfigIdentifier, mMaxAllowedSlots.get(WORK_TYPE_EJ))
+ pw.print(KEY_PREFIX_MAX_RATIO_EJ + mConfigIdentifier,
+ mMaxAllowedSlots.get(WORK_TYPE_EJ))
.println();
- pw.print(KEY_PREFIX_MIN_BG + mConfigIdentifier, mMinReservedSlots.get(WORK_TYPE_BG))
+ pw.print(KEY_PREFIX_MIN_RATIO_BG + mConfigIdentifier,
+ mMinReservedSlots.get(WORK_TYPE_BG))
.println();
- pw.print(KEY_PREFIX_MAX_BG + mConfigIdentifier, mMaxAllowedSlots.get(WORK_TYPE_BG))
+ pw.print(KEY_PREFIX_MAX_RATIO_BG + mConfigIdentifier,
+ mMaxAllowedSlots.get(WORK_TYPE_BG))
.println();
- pw.print(KEY_PREFIX_MIN_BGUSER + mConfigIdentifier,
+ pw.print(KEY_PREFIX_MIN_RATIO_BGUSER + mConfigIdentifier,
mMinReservedSlots.get(WORK_TYPE_BGUSER_IMPORTANT)).println();
- pw.print(KEY_PREFIX_MAX_BGUSER + mConfigIdentifier,
+ pw.print(KEY_PREFIX_MAX_RATIO_BGUSER + mConfigIdentifier,
mMaxAllowedSlots.get(WORK_TYPE_BGUSER_IMPORTANT)).println();
- pw.print(KEY_PREFIX_MIN_BGUSER + mConfigIdentifier,
+ pw.print(KEY_PREFIX_MIN_RATIO_BGUSER + mConfigIdentifier,
mMinReservedSlots.get(WORK_TYPE_BGUSER)).println();
- pw.print(KEY_PREFIX_MAX_BGUSER + mConfigIdentifier,
+ pw.print(KEY_PREFIX_MAX_RATIO_BGUSER + mConfigIdentifier,
mMaxAllowedSlots.get(WORK_TYPE_BGUSER)).println();
}
}
diff --git a/apex/jobscheduler/service/java/com/android/server/job/JobServiceContext.java b/apex/jobscheduler/service/java/com/android/server/job/JobServiceContext.java
index ce7da86..b89337f 100644
--- a/apex/jobscheduler/service/java/com/android/server/job/JobServiceContext.java
+++ b/apex/jobscheduler/service/java/com/android/server/job/JobServiceContext.java
@@ -1193,7 +1193,7 @@
completedJob.isConstraintSatisfied(JobStatus.CONSTRAINT_CONTENT_TRIGGER));
if (Trace.isTagEnabled(Trace.TRACE_TAG_SYSTEM_SERVER)) {
Trace.asyncTraceForTrackEnd(Trace.TRACE_TAG_SYSTEM_SERVER, "JobScheduler",
- completedJob.getTag(), getId());
+ getId());
}
try {
mBatteryStats.noteJobFinish(mRunningJob.getBatteryName(), mRunningJob.getSourceUid(),
diff --git a/apex/jobscheduler/service/java/com/android/server/job/JobStore.java b/apex/jobscheduler/service/java/com/android/server/job/JobStore.java
index 53c56e7..9ec74e5 100644
--- a/apex/jobscheduler/service/java/com/android/server/job/JobStore.java
+++ b/apex/jobscheduler/service/java/com/android/server/job/JobStore.java
@@ -1033,10 +1033,10 @@
}
boolean needFileMigration = false;
long nowElapsed = sElapsedRealtimeClock.millis();
- for (File file : files) {
- final AtomicFile aFile = createJobFile(file);
- try (FileInputStream fis = aFile.openRead()) {
- synchronized (mLock) {
+ synchronized (mLock) {
+ for (File file : files) {
+ final AtomicFile aFile = createJobFile(file);
+ try (FileInputStream fis = aFile.openRead()) {
jobs = readJobMapImpl(fis, rtcGood, nowElapsed);
if (jobs != null) {
for (int i = 0; i < jobs.size(); i++) {
@@ -1054,33 +1054,35 @@
}
}
}
+ } catch (FileNotFoundException e) {
+ // mJobFileDirectory.listFiles() gave us this file...why can't we find it???
+ Slog.e(TAG, "Could not find jobs file: " + file.getName());
+ } catch (XmlPullParserException | IOException e) {
+ Slog.wtf(TAG, "Error in " + file.getName(), e);
+ } catch (Exception e) {
+ // Crashing at this point would result in a boot loop, so live with a
+ // generic Exception for system stability's sake.
+ Slog.wtf(TAG, "Unexpected exception", e);
}
- } catch (FileNotFoundException e) {
- // mJobFileDirectory.listFiles() gave us this file...why can't we find it???
- Slog.e(TAG, "Could not find jobs file: " + file.getName());
- } catch (XmlPullParserException | IOException e) {
- Slog.wtf(TAG, "Error in " + file.getName(), e);
- } catch (Exception e) {
- // Crashing at this point would result in a boot loop, so live with a general
- // Exception for system stability's sake.
- Slog.wtf(TAG, "Unexpected exception", e);
- }
- if (mUseSplitFiles) {
- if (!file.getName().startsWith(JOB_FILE_SPLIT_PREFIX)) {
- // We're supposed to be using the split file architecture, but we still have
- // the old job file around. Fully migrate and remove the old file.
+ if (mUseSplitFiles) {
+ if (!file.getName().startsWith(JOB_FILE_SPLIT_PREFIX)) {
+ // We're supposed to be using the split file architecture,
+ // but we still have
+ // the old job file around. Fully migrate and remove the old file.
+ needFileMigration = true;
+ }
+ } else if (file.getName().startsWith(JOB_FILE_SPLIT_PREFIX)) {
+ // We're supposed to be using the legacy single file architecture,
+ // but we still have some job split files around. Fully migrate
+ // and remove the split files.
needFileMigration = true;
}
- } else if (file.getName().startsWith(JOB_FILE_SPLIT_PREFIX)) {
- // We're supposed to be using the legacy single file architecture, but we still
- // have some job split files around. Fully migrate and remove the split files.
- needFileMigration = true;
}
- }
- if (mPersistInfo.countAllJobsLoaded < 0) { // Only set them once.
- mPersistInfo.countAllJobsLoaded = numJobs;
- mPersistInfo.countSystemServerJobsLoaded = numSystemJobs;
- mPersistInfo.countSystemSyncManagerJobsLoaded = numSyncJobs;
+ if (mPersistInfo.countAllJobsLoaded < 0) { // Only set them once.
+ mPersistInfo.countAllJobsLoaded = numJobs;
+ mPersistInfo.countSystemServerJobsLoaded = numSystemJobs;
+ mPersistInfo.countSystemSyncManagerJobsLoaded = numSyncJobs;
+ }
}
Slog.i(TAG, "Read " + numJobs + " jobs");
if (needFileMigration) {
diff --git a/core/api/current.txt b/core/api/current.txt
index dd3d6eb..0ad7d80 100644
--- a/core/api/current.txt
+++ b/core/api/current.txt
@@ -88,6 +88,7 @@
field public static final String DIAGNOSTIC = "android.permission.DIAGNOSTIC";
field public static final String DISABLE_KEYGUARD = "android.permission.DISABLE_KEYGUARD";
field public static final String DUMP = "android.permission.DUMP";
+ field public static final String ENFORCE_UPDATE_OWNERSHIP = "android.permission.ENFORCE_UPDATE_OWNERSHIP";
field public static final String EXPAND_STATUS_BAR = "android.permission.EXPAND_STATUS_BAR";
field public static final String FACTORY_TEST = "android.permission.FACTORY_TEST";
field public static final String FOREGROUND_SERVICE = "android.permission.FOREGROUND_SERVICE";
@@ -384,6 +385,7 @@
field public static final int allowTaskReparenting = 16843268; // 0x1010204
field public static final int allowUndo = 16843999; // 0x10104df
field public static final int allowUntrustedActivityEmbedding = 16844393; // 0x1010669
+ field public static final int allowUpdateOwnership;
field public static final int alpha = 16843551; // 0x101031f
field public static final int alphabeticModifiers = 16844110; // 0x101054e
field public static final int alphabeticShortcut = 16843235; // 0x10101e3
@@ -917,6 +919,7 @@
field public static final int isAlwaysSyncable = 16843571; // 0x1010333
field public static final int isAsciiCapable = 16843753; // 0x10103e9
field public static final int isAuxiliary = 16843647; // 0x101037f
+ field public static final int isCredential;
field public static final int isDefault = 16843297; // 0x1010221
field public static final int isFeatureSplit = 16844123; // 0x101055b
field public static final int isGame = 16843764; // 0x10103f4
@@ -5903,7 +5906,7 @@
ctor public LocaleConfig(@NonNull android.content.Context);
ctor public LocaleConfig(@NonNull android.os.LocaleList);
method public int describeContents();
- method @NonNull public static android.app.LocaleConfig fromResources(@NonNull android.content.Context);
+ method @NonNull public static android.app.LocaleConfig fromContextIgnoringOverride(@NonNull android.content.Context);
method public int getStatus();
method @Nullable public android.os.LocaleList getSupportedLocales();
method public void writeToParcel(@NonNull android.os.Parcel, int);
@@ -8640,6 +8643,9 @@
method public void jobFinished(android.app.job.JobParameters, boolean);
method public abstract boolean onStartJob(android.app.job.JobParameters);
method public abstract boolean onStopJob(android.app.job.JobParameters);
+ method public void setNotification(@NonNull android.app.job.JobParameters, int, @NonNull android.app.Notification, int);
+ method public void updateEstimatedNetworkBytes(@NonNull android.app.job.JobParameters, @Nullable android.app.job.JobWorkItem, long, long);
+ method public void updateTransferredNetworkBytes(@NonNull android.app.job.JobParameters, @Nullable android.app.job.JobWorkItem, long, long);
}
public final class JobWorkItem implements android.os.Parcelable {
@@ -9226,15 +9232,18 @@
}
public final class CompanionDeviceManager {
+ method @RequiresPermission("android.permission.MANAGE_COMPANION_DEVICES") public void addOnAssociationsChangedListener(@NonNull java.util.concurrent.Executor, @NonNull android.companion.CompanionDeviceManager.OnAssociationsChangedListener);
method @RequiresPermission(anyOf={android.Manifest.permission.REQUEST_COMPANION_PROFILE_WATCH, android.Manifest.permission.REQUEST_COMPANION_PROFILE_COMPUTER, android.Manifest.permission.REQUEST_COMPANION_PROFILE_APP_STREAMING, android.Manifest.permission.REQUEST_COMPANION_PROFILE_AUTOMOTIVE_PROJECTION}, conditional=true) public void associate(@NonNull android.companion.AssociationRequest, @NonNull android.companion.CompanionDeviceManager.Callback, @Nullable android.os.Handler);
method @RequiresPermission(anyOf={android.Manifest.permission.REQUEST_COMPANION_PROFILE_WATCH, android.Manifest.permission.REQUEST_COMPANION_PROFILE_COMPUTER, android.Manifest.permission.REQUEST_COMPANION_PROFILE_APP_STREAMING, android.Manifest.permission.REQUEST_COMPANION_PROFILE_AUTOMOTIVE_PROJECTION}, conditional=true) public void associate(@NonNull android.companion.AssociationRequest, @NonNull java.util.concurrent.Executor, @NonNull android.companion.CompanionDeviceManager.Callback);
method @Nullable public android.content.IntentSender buildAssociationCancellationIntent();
method @Nullable public android.content.IntentSender buildPermissionTransferUserConsentIntent(int) throws android.companion.DeviceNotAssociatedException;
method @Deprecated public void disassociate(@NonNull String);
method public void disassociate(int);
+ method @NonNull @RequiresPermission("android.permission.MANAGE_COMPANION_DEVICES") public java.util.List<android.companion.AssociationInfo> getAllAssociations();
method @Deprecated @NonNull public java.util.List<java.lang.String> getAssociations();
method @NonNull public java.util.List<android.companion.AssociationInfo> getMyAssociations();
method @Deprecated public boolean hasNotificationAccess(android.content.ComponentName);
+ method @RequiresPermission("android.permission.MANAGE_COMPANION_DEVICES") public void removeOnAssociationsChangedListener(@NonNull android.companion.CompanionDeviceManager.OnAssociationsChangedListener);
method public void requestNotificationAccess(android.content.ComponentName);
method @RequiresPermission(android.Manifest.permission.REQUEST_OBSERVE_COMPANION_DEVICE_PRESENCE) public void startObservingDevicePresence(@NonNull String) throws android.companion.DeviceNotAssociatedException;
method @RequiresPermission(android.Manifest.permission.REQUEST_OBSERVE_COMPANION_DEVICE_PRESENCE) public void stopObservingDevicePresence(@NonNull String) throws android.companion.DeviceNotAssociatedException;
@@ -9255,6 +9264,10 @@
method public abstract void onFailure(@Nullable CharSequence);
}
+ public static interface CompanionDeviceManager.OnAssociationsChangedListener {
+ method public void onAssociationsChanged(@NonNull java.util.List<android.companion.AssociationInfo>);
+ }
+
public abstract class CompanionDeviceService extends android.app.Service {
ctor public CompanionDeviceService();
method @Nullable public final android.os.IBinder onBind(@NonNull android.content.Intent);
@@ -11688,6 +11701,7 @@
method @Nullable public String getInstallingPackageName();
method @Nullable public String getOriginatingPackageName();
method public int getPackageSource();
+ method @Nullable public String getUpdateOwnerPackageName();
method public void writeToParcel(@NonNull android.os.Parcel, int);
field @NonNull public static final android.os.Parcelable.Creator<android.content.pm.InstallSourceInfo> CREATOR;
}
@@ -11870,6 +11884,7 @@
public class PackageInstaller {
method public void abandonSession(int);
method public void checkInstallConstraints(@NonNull java.util.List<java.lang.String>, @NonNull android.content.pm.PackageInstaller.InstallConstraints, @NonNull java.util.concurrent.Executor, @NonNull java.util.function.Consumer<android.content.pm.PackageInstaller.InstallConstraintsResult>);
+ method public void commitSessionAfterInstallConstraintsAreMet(int, @NonNull android.content.IntentSender, @NonNull android.content.pm.PackageInstaller.InstallConstraints, long);
method public int createSession(@NonNull android.content.pm.PackageInstaller.SessionParams) throws java.io.IOException;
method @Deprecated @Nullable public android.content.pm.PackageInstaller.SessionInfo getActiveStagedSession();
method @NonNull public java.util.List<android.content.pm.PackageInstaller.SessionInfo> getActiveStagedSessions();
@@ -11914,6 +11929,7 @@
field public static final int STATUS_FAILURE_INCOMPATIBLE = 7; // 0x7
field public static final int STATUS_FAILURE_INVALID = 4; // 0x4
field public static final int STATUS_FAILURE_STORAGE = 6; // 0x6
+ field public static final int STATUS_FAILURE_TIMEOUT = 8; // 0x8
field public static final int STATUS_PENDING_USER_ACTION = -1; // 0xffffffff
field public static final int STATUS_SUCCESS = 0; // 0x0
}
@@ -11978,6 +11994,7 @@
method public int getParentSessionId();
method public boolean isKeepApplicationEnabledSetting();
method public boolean isMultiPackage();
+ method public boolean isRequestUpdateOwnership();
method public boolean isStaged();
method @NonNull public java.io.InputStream openRead(@NonNull String) throws java.io.IOException;
method @NonNull public java.io.OutputStream openWrite(@NonNull String, long, long) throws java.io.IOException;
@@ -12033,6 +12050,7 @@
method public boolean isCommitted();
method public boolean isKeepApplicationEnabledSetting();
method public boolean isMultiPackage();
+ method public boolean isRequestUpdateOwnership();
method public boolean isSealed();
method public boolean isStaged();
method public boolean isStagedSessionActive();
@@ -12071,6 +12089,7 @@
method public void setOriginatingUri(@Nullable android.net.Uri);
method public void setPackageSource(int);
method public void setReferrerUri(@Nullable android.net.Uri);
+ method @RequiresPermission(android.Manifest.permission.ENFORCE_UPDATE_OWNERSHIP) public void setRequestUpdateOwnership(boolean);
method public void setRequireUserAction(int);
method public void setSize(long);
method public void setWhitelistedRestrictedPermissions(@Nullable java.util.Set<java.lang.String>);
@@ -12249,6 +12268,7 @@
method @NonNull public java.util.List<android.content.pm.PackageManager.Property> queryProviderProperty(@NonNull String);
method @NonNull public java.util.List<android.content.pm.PackageManager.Property> queryReceiverProperty(@NonNull String);
method @NonNull public java.util.List<android.content.pm.PackageManager.Property> queryServiceProperty(@NonNull String);
+ method public void relinquishUpdateOwnership(@NonNull String);
method @Deprecated public abstract void removePackageFromPreferred(@NonNull String);
method public abstract void removePermission(@NonNull String);
method @RequiresPermission(value="android.permission.WHITELIST_RESTRICTED_PERMISSIONS", conditional=true) public boolean removeWhitelistedRestrictedPermission(@NonNull String, @NonNull String, int);
@@ -12683,7 +12703,7 @@
field public static final int FLAG_USE_APP_ZYGOTE = 8; // 0x8
field @RequiresPermission(allOf={android.Manifest.permission.FOREGROUND_SERVICE_CAMERA}, anyOf={android.Manifest.permission.CAMERA}, conditional=true) public static final int FOREGROUND_SERVICE_TYPE_CAMERA = 64; // 0x40
field @RequiresPermission(allOf={android.Manifest.permission.FOREGROUND_SERVICE_CONNECTED_DEVICE}, anyOf={android.Manifest.permission.BLUETOOTH_CONNECT, android.Manifest.permission.CHANGE_NETWORK_STATE, android.Manifest.permission.CHANGE_WIFI_STATE, android.Manifest.permission.CHANGE_WIFI_MULTICAST_STATE, android.Manifest.permission.NFC, android.Manifest.permission.TRANSMIT_IR}, conditional=true) public static final int FOREGROUND_SERVICE_TYPE_CONNECTED_DEVICE = 16; // 0x10
- field @Deprecated @RequiresPermission(value=android.Manifest.permission.FOREGROUND_SERVICE_DATA_SYNC, conditional=true) public static final int FOREGROUND_SERVICE_TYPE_DATA_SYNC = 1; // 0x1
+ field @RequiresPermission(value=android.Manifest.permission.FOREGROUND_SERVICE_DATA_SYNC, conditional=true) public static final int FOREGROUND_SERVICE_TYPE_DATA_SYNC = 1; // 0x1
field @RequiresPermission(android.Manifest.permission.FOREGROUND_SERVICE_FILE_MANAGEMENT) public static final int FOREGROUND_SERVICE_TYPE_FILE_MANAGEMENT = 4096; // 0x1000
field @RequiresPermission(allOf={android.Manifest.permission.FOREGROUND_SERVICE_HEALTH}, anyOf={android.Manifest.permission.ACTIVITY_RECOGNITION, android.Manifest.permission.BODY_SENSORS, android.Manifest.permission.HIGH_SAMPLING_RATE_SENSORS}) public static final int FOREGROUND_SERVICE_TYPE_HEALTH = 256; // 0x100
field @RequiresPermission(allOf={android.Manifest.permission.FOREGROUND_SERVICE_LOCATION}, anyOf={android.Manifest.permission.ACCESS_COARSE_LOCATION, android.Manifest.permission.ACCESS_FINE_LOCATION}, conditional=true) public static final int FOREGROUND_SERVICE_TYPE_LOCATION = 8; // 0x8
@@ -13248,6 +13268,7 @@
ctor public ClearCredentialStateException(@NonNull String, @Nullable Throwable);
ctor public ClearCredentialStateException(@NonNull String);
method @NonNull public String getType();
+ field @NonNull public static final String TYPE_UNKNOWN = "android.credentials.ClearCredentialStateException.TYPE_UNKNOWN";
}
public final class ClearCredentialStateRequest implements android.os.Parcelable {
@@ -13264,7 +13285,10 @@
ctor public CreateCredentialException(@NonNull String, @Nullable Throwable);
ctor public CreateCredentialException(@NonNull String);
method @NonNull public String getType();
+ field @NonNull public static final String TYPE_INTERRUPTED = "android.credentials.CreateCredentialException.TYPE_INTERRUPTED";
field @NonNull public static final String TYPE_NO_CREDENTIAL = "android.credentials.CreateCredentialException.TYPE_NO_CREDENTIAL";
+ field @NonNull public static final String TYPE_UNKNOWN = "android.credentials.CreateCredentialException.TYPE_UNKNOWN";
+ field @NonNull public static final String TYPE_USER_CANCELED = "android.credentials.CreateCredentialException.TYPE_USER_CANCELED";
}
public final class CreateCredentialRequest implements android.os.Parcelable {
@@ -13308,7 +13332,10 @@
ctor public GetCredentialException(@NonNull String, @Nullable Throwable);
ctor public GetCredentialException(@NonNull String);
method @NonNull public String getType();
+ field @NonNull public static final String TYPE_INTERRUPTED = "android.credentials.GetCredentialException.TYPE_INTERRUPTED";
field @NonNull public static final String TYPE_NO_CREDENTIAL = "android.credentials.GetCredentialException.TYPE_NO_CREDENTIAL";
+ field @NonNull public static final String TYPE_UNKNOWN = "android.credentials.GetCredentialException.TYPE_UNKNOWN";
+ field @NonNull public static final String TYPE_USER_CANCELED = "android.credentials.GetCredentialException.TYPE_USER_CANCELED";
}
public final class GetCredentialOption implements android.os.Parcelable {
@@ -13339,9 +13366,8 @@
public final class GetCredentialResponse implements android.os.Parcelable {
ctor public GetCredentialResponse(@NonNull android.credentials.Credential);
- ctor public GetCredentialResponse();
method public int describeContents();
- method @Nullable public android.credentials.Credential getCredential();
+ method @NonNull public android.credentials.Credential getCredential();
method public void writeToParcel(@NonNull android.os.Parcel, int);
field @NonNull public static final android.os.Parcelable.Creator<android.credentials.GetCredentialResponse> CREATOR;
}
@@ -17715,8 +17741,8 @@
method public boolean flush(android.hardware.SensorEventListener);
method public static float getAltitude(float, float);
method public static void getAngleChange(float[], float[], float[]);
- method public android.hardware.Sensor getDefaultSensor(int);
- method public android.hardware.Sensor getDefaultSensor(int, boolean);
+ method @Nullable public android.hardware.Sensor getDefaultSensor(int);
+ method @Nullable public android.hardware.Sensor getDefaultSensor(int, boolean);
method public java.util.List<android.hardware.Sensor> getDynamicSensorList(int);
method public static float getInclination(float[]);
method public static float[] getOrientation(float[], float[]);
@@ -18203,7 +18229,7 @@
method public int capture(@NonNull android.hardware.camera2.CaptureRequest, @NonNull java.util.concurrent.Executor, @NonNull android.hardware.camera2.CameraExtensionSession.ExtensionCaptureCallback) throws android.hardware.camera2.CameraAccessException;
method public void close() throws android.hardware.camera2.CameraAccessException;
method @NonNull public android.hardware.camera2.CameraDevice getDevice();
- method @Nullable public android.util.Pair<java.lang.Long,java.lang.Long> getRealtimeStillCaptureLatency() throws android.hardware.camera2.CameraAccessException;
+ method @Nullable public android.hardware.camera2.CameraExtensionSession.StillCaptureLatency getRealtimeStillCaptureLatency() throws android.hardware.camera2.CameraAccessException;
method public int setRepeatingRequest(@NonNull android.hardware.camera2.CaptureRequest, @NonNull java.util.concurrent.Executor, @NonNull android.hardware.camera2.CameraExtensionSession.ExtensionCaptureCallback) throws android.hardware.camera2.CameraAccessException;
method public void stopRepeating() throws android.hardware.camera2.CameraAccessException;
}
@@ -18226,6 +18252,12 @@
method public abstract void onConfigured(@NonNull android.hardware.camera2.CameraExtensionSession);
}
+ public static final class CameraExtensionSession.StillCaptureLatency {
+ ctor public CameraExtensionSession.StillCaptureLatency(long, long);
+ method public long getCaptureLatency();
+ method public long getProcessingLatency();
+ }
+
public final class CameraManager {
method @NonNull public android.hardware.camera2.CameraCharacteristics getCameraCharacteristics(@NonNull String) throws android.hardware.camera2.CameraAccessException;
method @NonNull public android.hardware.camera2.CameraExtensionCharacteristics getCameraExtensionCharacteristics(@NonNull String) throws android.hardware.camera2.CameraAccessException;
@@ -21956,6 +21988,7 @@
field public static final int PLUGIN_STATUS_PHYSICAL_MODULE_CHANGED = 0; // 0x0
field public static final int PLUGIN_STATUS_SESSION_NUMBER_CHANGED = 1; // 0x1
field public static final int SCRAMBLING_MODE_AES128 = 9; // 0x9
+ field public static final int SCRAMBLING_MODE_AES_CBC = 14; // 0xe
field public static final int SCRAMBLING_MODE_AES_ECB = 10; // 0xa
field public static final int SCRAMBLING_MODE_AES_SCTE52 = 11; // 0xb
field public static final int SCRAMBLING_MODE_DVB_CISSA_V1 = 6; // 0x6
@@ -33194,6 +33227,7 @@
field public static final String DISALLOW_CONFIG_CELL_BROADCASTS = "no_config_cell_broadcasts";
field public static final String DISALLOW_CONFIG_CREDENTIALS = "no_config_credentials";
field public static final String DISALLOW_CONFIG_DATE_TIME = "no_config_date_time";
+ field public static final String DISALLOW_CONFIG_DEFAULT_APPS = "disallow_config_default_apps";
field public static final String DISALLOW_CONFIG_LOCALE = "no_config_locale";
field public static final String DISALLOW_CONFIG_LOCATION = "no_config_location";
field public static final String DISALLOW_CONFIG_MOBILE_NETWORKS = "no_config_mobile_networks";
@@ -36397,6 +36431,7 @@
field public static final String ACTION_PROCESS_WIFI_EASY_CONNECT_URI = "android.settings.PROCESS_WIFI_EASY_CONNECT_URI";
field public static final String ACTION_QUICK_ACCESS_WALLET_SETTINGS = "android.settings.QUICK_ACCESS_WALLET_SETTINGS";
field public static final String ACTION_QUICK_LAUNCH_SETTINGS = "android.settings.QUICK_LAUNCH_SETTINGS";
+ field public static final String ACTION_REGIONAL_PREFERENCES_SETTINGS = "android.settings.REGIONAL_PREFERENCES_SETTINGS";
field public static final String ACTION_REQUEST_IGNORE_BATTERY_OPTIMIZATIONS = "android.settings.REQUEST_IGNORE_BATTERY_OPTIMIZATIONS";
field public static final String ACTION_REQUEST_MANAGE_MEDIA = "android.settings.REQUEST_MANAGE_MEDIA";
field public static final String ACTION_REQUEST_SCHEDULE_EXACT_ALARM = "android.settings.REQUEST_SCHEDULE_EXACT_ALARM";
@@ -39919,6 +39954,7 @@
method @NonNull public final android.os.IBinder onBind(@NonNull android.content.Intent);
method public abstract void onClearCredentialState(@NonNull android.service.credentials.ClearCredentialStateRequest, @NonNull android.os.CancellationSignal, @NonNull android.os.OutcomeReceiver<java.lang.Void,android.credentials.ClearCredentialStateException>);
field public static final String CAPABILITY_META_DATA_KEY = "android.credentials.capabilities";
+ field public static final String EXTRA_BEGIN_GET_CREDENTIAL_REQUEST = "android.service.credentials.extra.BEGIN_GET_CREDENTIAL_REQUEST";
field public static final String EXTRA_CREATE_CREDENTIAL_EXCEPTION = "android.service.credentials.extra.CREATE_CREDENTIAL_EXCEPTION";
field public static final String EXTRA_CREATE_CREDENTIAL_REQUEST = "android.service.credentials.extra.CREATE_CREDENTIAL_REQUEST";
field public static final String EXTRA_CREATE_CREDENTIAL_RESPONSE = "android.service.credentials.extra.CREATE_CREDENTIAL_RESPONSE";
@@ -40437,7 +40473,7 @@
method public void onTileRemoved();
method public static final void requestListeningState(android.content.Context, android.content.ComponentName);
method public final void showDialog(android.app.Dialog);
- method public final void startActivityAndCollapse(android.content.Intent);
+ method @Deprecated public final void startActivityAndCollapse(android.content.Intent);
method public final void startActivityAndCollapse(@NonNull android.app.PendingIntent);
method public final void unlockAndRun(Runnable);
field public static final String ACTION_QS_TILE = "android.service.quicksettings.action.QS_TILE";
@@ -41306,6 +41342,7 @@
method public void disconnect(@NonNull android.telecom.DisconnectCause, @NonNull java.util.concurrent.Executor, @NonNull android.os.OutcomeReceiver<java.lang.Void,android.telecom.CallException>);
method @NonNull public android.os.ParcelUuid getCallId();
method public void rejectCall(@NonNull java.util.concurrent.Executor, @NonNull android.os.OutcomeReceiver<java.lang.Void,android.telecom.CallException>);
+ method public void requestCallEndpointChange(@NonNull android.telecom.CallEndpoint, @NonNull java.util.concurrent.Executor, @NonNull android.os.OutcomeReceiver<java.lang.Void,android.telecom.CallException>);
method public void setActive(@NonNull java.util.concurrent.Executor, @NonNull android.os.OutcomeReceiver<java.lang.Void,android.telecom.CallException>);
method public void setInactive(@NonNull java.util.concurrent.Executor, @NonNull android.os.OutcomeReceiver<java.lang.Void,android.telecom.CallException>);
method public void startCallStreaming(@NonNull java.util.concurrent.Executor, @NonNull android.os.OutcomeReceiver<java.lang.Void,android.telecom.CallException>);
@@ -41343,10 +41380,12 @@
public interface CallEventCallback {
method public void onAnswer(int, @NonNull java.util.function.Consumer<java.lang.Boolean>);
- method public void onCallAudioStateChanged(@NonNull android.telecom.CallAudioState);
+ method public void onAvailableCallEndpointsChanged(@NonNull java.util.List<android.telecom.CallEndpoint>);
+ method public void onCallEndpointChanged(@NonNull android.telecom.CallEndpoint);
method public void onCallStreamingFailed(int);
method public void onCallStreamingStarted(@NonNull java.util.function.Consumer<java.lang.Boolean>);
method public void onDisconnect(@NonNull java.util.function.Consumer<java.lang.Boolean>);
+ method public void onMuteStateChanged(boolean);
method public void onReject(@NonNull java.util.function.Consumer<java.lang.Boolean>);
method public void onSetActive(@NonNull java.util.function.Consumer<java.lang.Boolean>);
method public void onSetInactive(@NonNull java.util.function.Consumer<java.lang.Boolean>);
@@ -46612,8 +46651,8 @@
field public static final int DONE = -1; // 0xffffffff
}
- public static class SegmentFinder.DefaultSegmentFinder extends android.text.SegmentFinder {
- ctor public SegmentFinder.DefaultSegmentFinder(@NonNull int[]);
+ public static class SegmentFinder.PrescribedSegmentFinder extends android.text.SegmentFinder {
+ ctor public SegmentFinder.PrescribedSegmentFinder(@NonNull int[]);
method public int nextEndBoundary(@IntRange(from=0) int);
method public int nextStartBoundary(@IntRange(from=0) int);
method public int previousEndBoundary(@IntRange(from=0) int);
@@ -50536,6 +50575,8 @@
field public static final int AXIS_GENERIC_7 = 38; // 0x26
field public static final int AXIS_GENERIC_8 = 39; // 0x27
field public static final int AXIS_GENERIC_9 = 40; // 0x28
+ field public static final int AXIS_GESTURE_SCROLL_X_DISTANCE = 50; // 0x32
+ field public static final int AXIS_GESTURE_SCROLL_Y_DISTANCE = 51; // 0x33
field public static final int AXIS_GESTURE_X_OFFSET = 48; // 0x30
field public static final int AXIS_GESTURE_Y_OFFSET = 49; // 0x31
field public static final int AXIS_HAT_X = 15; // 0xf
@@ -51390,6 +51431,7 @@
method public boolean isAutoHandwritingEnabled();
method public boolean isClickable();
method public boolean isContextClickable();
+ method public boolean isCredential();
method public boolean isDirty();
method @Deprecated public boolean isDrawingCacheEnabled();
method public boolean isDuplicateParentStateEnabled();
@@ -51623,6 +51665,7 @@
method public void setImportantForAccessibility(int);
method public void setImportantForAutofill(int);
method public void setImportantForContentCapture(int);
+ method public void setIsCredential(boolean);
method public void setKeepScreenOn(boolean);
method public void setKeyboardNavigationCluster(boolean);
method public void setLabelFor(@IdRes int);
@@ -53763,6 +53806,7 @@
method public int getDisplayId();
method public int getId();
method public int getLayer();
+ method @NonNull public android.os.LocaleList getLocales();
method public android.view.accessibility.AccessibilityWindowInfo getParent();
method public void getRegionInScreen(@NonNull android.graphics.Region);
method public android.view.accessibility.AccessibilityNodeInfo getRoot();
@@ -54572,14 +54616,6 @@
public abstract class HandwritingGesture {
method @Nullable public final String getFallbackText();
- field public static final int GESTURE_TYPE_DELETE = 4; // 0x4
- field public static final int GESTURE_TYPE_DELETE_RANGE = 64; // 0x40
- field public static final int GESTURE_TYPE_INSERT = 2; // 0x2
- field public static final int GESTURE_TYPE_JOIN_OR_SPLIT = 16; // 0x10
- field public static final int GESTURE_TYPE_NONE = 0; // 0x0
- field public static final int GESTURE_TYPE_REMOVE_SPACE = 8; // 0x8
- field public static final int GESTURE_TYPE_SELECT = 1; // 0x1
- field public static final int GESTURE_TYPE_SELECT_RANGE = 32; // 0x20
field public static final int GRANULARITY_CHARACTER = 2; // 0x2
field public static final int GRANULARITY_WORD = 1; // 0x1
}
@@ -55079,15 +55115,15 @@
public final class TextBoundsInfo implements android.os.Parcelable {
method public int describeContents();
method @IntRange(from=0, to=125) public int getCharacterBidiLevel(int);
- method @NonNull public android.graphics.RectF getCharacterBounds(int);
+ method @NonNull public void getCharacterBounds(int, @NonNull android.graphics.RectF);
method public int getCharacterFlags(int);
- method public int getEnd();
+ method public int getEndIndex();
method @NonNull public android.text.SegmentFinder getGraphemeSegmentFinder();
method @NonNull public android.text.SegmentFinder getLineSegmentFinder();
- method @NonNull public android.graphics.Matrix getMatrix();
+ method @NonNull public void getMatrix(@NonNull android.graphics.Matrix);
method public int getOffsetForPosition(float, float);
method @Nullable public int[] getRangeForRect(@NonNull android.graphics.RectF, @NonNull android.text.SegmentFinder, @NonNull android.text.Layout.TextInclusionStrategy);
- method public int getStart();
+ method public int getStartIndex();
method @NonNull public android.text.SegmentFinder getWordSegmentFinder();
method public void writeToParcel(@NonNull android.os.Parcel, int);
field @NonNull public static final android.os.Parcelable.Creator<android.view.inputmethod.TextBoundsInfo> CREATOR;
@@ -55098,7 +55134,7 @@
}
public static final class TextBoundsInfo.Builder {
- ctor public TextBoundsInfo.Builder();
+ ctor public TextBoundsInfo.Builder(int, int);
method @NonNull public android.view.inputmethod.TextBoundsInfo build();
method @NonNull public android.view.inputmethod.TextBoundsInfo.Builder clear();
method @NonNull public android.view.inputmethod.TextBoundsInfo.Builder setCharacterBidiLevel(@NonNull int[]);
diff --git a/core/api/module-lib-current.txt b/core/api/module-lib-current.txt
index 447b113..55ef6de 100644
--- a/core/api/module-lib-current.txt
+++ b/core/api/module-lib-current.txt
@@ -82,6 +82,7 @@
}
public abstract class Context {
+ method @NonNull public android.content.Context createContextForSdkInSandbox(@NonNull android.content.pm.ApplicationInfo, int) throws android.content.pm.PackageManager.NameNotFoundException;
method @NonNull public android.os.IBinder getIApplicationThreadBinder();
method @NonNull public android.os.UserHandle getUser();
field public static final String PAC_PROXY_SERVICE = "pac_proxy";
@@ -171,6 +172,7 @@
method @RequiresPermission(android.Manifest.permission.BLUETOOTH_STACK) public void setHfpEnabled(boolean);
method @RequiresPermission(android.Manifest.permission.BLUETOOTH_STACK) public void setHfpSamplingRate(int);
method @RequiresPermission(android.Manifest.permission.BLUETOOTH_STACK) public void setHfpVolume(int);
+ method @RequiresPermission(android.Manifest.permission.BLUETOOTH_STACK) public void setLeAudioSuspended(boolean);
method public void setStreamVolumeForUid(int, int, int, @NonNull String, int, int, int);
field public static final int FLAG_FROM_KEY = 4096; // 0x1000
}
diff --git a/core/api/system-current.txt b/core/api/system-current.txt
index 1254560..85f8813 100644
--- a/core/api/system-current.txt
+++ b/core/api/system-current.txt
@@ -806,10 +806,12 @@
method @Nullable public android.content.IntentFilter getDeliveryGroupMatchingFilter();
method @Nullable public String getDeliveryGroupMatchingKey();
method public int getDeliveryGroupPolicy();
+ method public boolean isDeferUntilActive();
method public boolean isPendingIntentBackgroundActivityLaunchAllowed();
method public static android.app.BroadcastOptions makeBasic();
method @RequiresPermission(android.Manifest.permission.ACCESS_BROADCAST_RESPONSE_STATS) public void recordResponseEventWhileInBackground(@IntRange(from=0) long);
method @RequiresPermission(android.Manifest.permission.START_ACTIVITIES_FROM_BACKGROUND) public void setBackgroundActivityStartsAllowed(boolean);
+ method @NonNull public android.app.BroadcastOptions setDeferUntilActive(boolean);
method @NonNull public android.app.BroadcastOptions setDeliveryGroupMatchingFilter(@NonNull android.content.IntentFilter);
method @NonNull public android.app.BroadcastOptions setDeliveryGroupMatchingKey(@NonNull String, @NonNull String);
method @NonNull public android.app.BroadcastOptions setDeliveryGroupPolicy(int);
@@ -2973,18 +2975,11 @@
}
public final class CompanionDeviceManager {
- method @RequiresPermission("android.permission.MANAGE_COMPANION_DEVICES") public void addOnAssociationsChangedListener(@NonNull java.util.concurrent.Executor, @NonNull android.companion.CompanionDeviceManager.OnAssociationsChangedListener);
method @RequiresPermission(android.Manifest.permission.ASSOCIATE_COMPANION_DEVICES) public void associate(@NonNull String, @NonNull android.net.MacAddress, @NonNull byte[]);
method @RequiresPermission("android.permission.MANAGE_COMPANION_DEVICES") public boolean canPairWithoutPrompt(@NonNull String, @NonNull String, @NonNull android.os.UserHandle);
- method @NonNull @RequiresPermission("android.permission.MANAGE_COMPANION_DEVICES") public java.util.List<android.companion.AssociationInfo> getAllAssociations();
method @RequiresPermission("android.permission.MANAGE_COMPANION_DEVICES") public boolean isDeviceAssociatedForWifiConnection(@NonNull String, @NonNull android.net.MacAddress, @NonNull android.os.UserHandle);
method @RequiresPermission(android.Manifest.permission.REQUEST_COMPANION_SELF_MANAGED) public void notifyDeviceAppeared(int);
method @RequiresPermission(android.Manifest.permission.REQUEST_COMPANION_SELF_MANAGED) public void notifyDeviceDisappeared(int);
- method @RequiresPermission("android.permission.MANAGE_COMPANION_DEVICES") public void removeOnAssociationsChangedListener(@NonNull android.companion.CompanionDeviceManager.OnAssociationsChangedListener);
- }
-
- public static interface CompanionDeviceManager.OnAssociationsChangedListener {
- method public void onAssociationsChanged(@NonNull java.util.List<android.companion.AssociationInfo>);
}
}
@@ -3025,7 +3020,7 @@
method public int getDeviceId();
method @Nullable public android.companion.virtual.sensor.VirtualSensor getVirtualSensor(int, @NonNull String);
method public void launchPendingIntent(int, @NonNull android.app.PendingIntent, @NonNull java.util.concurrent.Executor, @NonNull java.util.function.IntConsumer);
- method @RequiresPermission(android.Manifest.permission.CREATE_VIRTUAL_DEVICE) public void registerIntentInterceptor(@NonNull java.util.concurrent.Executor, @NonNull android.content.IntentFilter, @NonNull android.companion.virtual.VirtualDeviceManager.IntentInterceptorCallback);
+ method @RequiresPermission(android.Manifest.permission.CREATE_VIRTUAL_DEVICE) public void registerIntentInterceptor(@NonNull android.content.IntentFilter, @NonNull java.util.concurrent.Executor, @NonNull android.companion.virtual.VirtualDeviceManager.IntentInterceptorCallback);
method public void removeActivityListener(@NonNull android.companion.virtual.VirtualDeviceManager.ActivityListener);
method @NonNull @RequiresPermission(android.Manifest.permission.CREATE_VIRTUAL_DEVICE) public void setShowPointerIcon(boolean);
method @RequiresPermission(android.Manifest.permission.CREATE_VIRTUAL_DEVICE) public void unregisterIntentInterceptor(@NonNull android.companion.virtual.VirtualDeviceManager.IntentInterceptorCallback);
@@ -3592,6 +3587,9 @@
field public static final int LOCATION_DATA_APP = 0; // 0x0
field public static final int LOCATION_MEDIA_DATA = 2; // 0x2
field public static final int LOCATION_MEDIA_OBB = 1; // 0x1
+ field public static final int REASON_CONFIRM_PACKAGE_CHANGE = 0; // 0x0
+ field public static final int REASON_OWNERSHIP_CHANGED = 1; // 0x1
+ field public static final int REASON_REMIND_OWNERSHIP = 2; // 0x2
}
public static class PackageInstaller.InstallInfo {
@@ -3621,6 +3619,7 @@
method public boolean getInstallAsFullApp(boolean);
method public boolean getInstallAsInstantApp(boolean);
method public boolean getInstallAsVirtualPreload();
+ method public int getPendingUserActionReason();
method public boolean getRequestDowngrade();
method public int getRollbackDataPolicy();
method @NonNull public java.util.Set<java.lang.String> getWhitelistedRestrictedPermissions();
@@ -5771,6 +5770,19 @@
package android.hardware.usb {
+ public final class DisplayPortAltModeInfo implements android.os.Parcelable {
+ method public int describeContents();
+ method public int getCableStatus();
+ method public int getNumberOfLanes();
+ method public int getPartnerSinkStatus();
+ method public void writeToParcel(@NonNull android.os.Parcel, int);
+ field @NonNull public static final android.os.Parcelable.Creator<android.hardware.usb.DisplayPortAltModeInfo> CREATOR;
+ field public static final int DISPLAYPORT_ALT_MODE_STATUS_CAPABLE = 2; // 0x2
+ field public static final int DISPLAYPORT_ALT_MODE_STATUS_ENABLED = 3; // 0x3
+ field public static final int DISPLAYPORT_ALT_MODE_STATUS_NOT_CAPABLE = 1; // 0x1
+ field public static final int DISPLAYPORT_ALT_MODE_STATUS_UNKNOWN = 0; // 0x0
+ }
+
public class UsbDeviceConnection {
method public boolean resetDevice();
}
@@ -5779,8 +5791,10 @@
method @RequiresPermission(android.Manifest.permission.MANAGE_USB) public long getCurrentFunctions();
method @NonNull @RequiresPermission(android.Manifest.permission.MANAGE_USB) public java.util.List<android.hardware.usb.UsbPort> getPorts();
method @RequiresPermission(android.Manifest.permission.MANAGE_USB) public void grantPermission(android.hardware.usb.UsbDevice, String);
+ method @RequiresPermission(android.Manifest.permission.MANAGE_USB) public boolean registerDisplayPortAltModeInfoListener(@NonNull java.util.concurrent.Executor, @NonNull android.hardware.usb.UsbManager.DisplayPortAltModeInfoListener);
method @RequiresPermission(android.Manifest.permission.MANAGE_USB) public void resetUsbGadget();
method @RequiresPermission(android.Manifest.permission.MANAGE_USB) public void setCurrentFunctions(long);
+ method @RequiresPermission(android.Manifest.permission.MANAGE_USB) public void unregisterDisplayPortAltModeInfoListener(@NonNull android.hardware.usb.UsbManager.DisplayPortAltModeInfoListener);
field @RequiresPermission(android.Manifest.permission.MANAGE_USB) public static final String ACTION_USB_ACCESSORY_HANDSHAKE = "android.hardware.usb.action.USB_ACCESSORY_HANDSHAKE";
field @RequiresPermission(android.Manifest.permission.MANAGE_USB) public static final String ACTION_USB_PORT_CHANGED = "android.hardware.usb.action.USB_PORT_CHANGED";
field @RequiresPermission(android.Manifest.permission.MANAGE_USB) public static final String ACTION_USB_PORT_COMPLIANCE_CHANGED = "android.hardware.usb.action.USB_PORT_COMPLIANCE_CHANGED";
@@ -5804,11 +5818,16 @@
field public static final String USB_FUNCTION_RNDIS = "rndis";
}
+ public static interface UsbManager.DisplayPortAltModeInfoListener {
+ method public void onDisplayPortAltModeInfoChanged(@NonNull String, @NonNull android.hardware.usb.DisplayPortAltModeInfo);
+ }
+
public final class UsbPort {
method @CheckResult @RequiresPermission(android.Manifest.permission.MANAGE_USB) public int enableLimitPowerTransfer(boolean);
method @CheckResult @RequiresPermission(android.Manifest.permission.MANAGE_USB) public int enableUsbData(boolean);
method @CheckResult @RequiresPermission(android.Manifest.permission.MANAGE_USB) public int enableUsbDataWhileDocked();
method @Nullable @RequiresPermission(android.Manifest.permission.MANAGE_USB) public android.hardware.usb.UsbPortStatus getStatus();
+ method public boolean isAltModeSupported(int);
method @CheckResult @RequiresPermission(android.Manifest.permission.MANAGE_USB) public void resetUsbPort(@NonNull java.util.concurrent.Executor, @NonNull java.util.function.Consumer<java.lang.Integer>);
method @RequiresPermission(android.Manifest.permission.MANAGE_USB) public void setRoles(int, int);
method @CheckResult @RequiresPermission(android.Manifest.permission.MANAGE_USB) public boolean supportsComplianceWarnings();
@@ -5828,6 +5847,7 @@
field public static final int ENABLE_USB_DATA_WHILE_DOCKED_ERROR_OTHER = 5; // 0x5
field public static final int ENABLE_USB_DATA_WHILE_DOCKED_ERROR_PORT_MISMATCH = 3; // 0x3
field public static final int ENABLE_USB_DATA_WHILE_DOCKED_SUCCESS = 0; // 0x0
+ field public static final int FLAG_ALT_MODE_TYPE_DISPLAYPORT = 1; // 0x1
field public static final int RESET_USB_PORT_ERROR_INTERNAL = 1; // 0x1
field public static final int RESET_USB_PORT_ERROR_NOT_SUPPORTED = 2; // 0x2
field public static final int RESET_USB_PORT_ERROR_OTHER = 4; // 0x4
@@ -5841,6 +5861,8 @@
method public int getCurrentDataRole();
method public int getCurrentMode();
method public int getCurrentPowerRole();
+ method @Nullable public android.hardware.usb.DisplayPortAltModeInfo getDisplayPortAltModeInfo();
+ method public int getPlugState();
method public int getPowerBrickConnectionStatus();
method public int getSupportedRoleCombinations();
method public int getUsbDataStatus();
@@ -5870,6 +5892,11 @@
field public static final int MODE_DFP = 2; // 0x2
field public static final int MODE_NONE = 0; // 0x0
field public static final int MODE_UFP = 1; // 0x1
+ field public static final int PLUG_STATE_PLUGGED_ORIENTATION_FLIPPED = 4; // 0x4
+ field public static final int PLUG_STATE_PLUGGED_ORIENTATION_NORMAL = 3; // 0x3
+ field public static final int PLUG_STATE_PLUGGED_ORIENTATION_UNKNOWN = 2; // 0x2
+ field public static final int PLUG_STATE_UNKNOWN = 0; // 0x0
+ field public static final int PLUG_STATE_UNPLUGGED = 1; // 0x1
field public static final int POWER_BRICK_STATUS_CONNECTED = 1; // 0x1
field public static final int POWER_BRICK_STATUS_DISCONNECTED = 2; // 0x2
field public static final int POWER_BRICK_STATUS_UNKNOWN = 0; // 0x0
@@ -10388,6 +10415,7 @@
field public static final String DISALLOW_RUN_IN_BACKGROUND = "no_run_in_background";
field public static final int REMOVE_RESULT_ALREADY_BEING_REMOVED = 2; // 0x2
field public static final int REMOVE_RESULT_DEFERRED = 1; // 0x1
+ field public static final int REMOVE_RESULT_ERROR_MAIN_USER_PERMANENT_ADMIN = -5; // 0xfffffffb
field public static final int REMOVE_RESULT_ERROR_SYSTEM_USER = -4; // 0xfffffffc
field public static final int REMOVE_RESULT_ERROR_UNKNOWN = -1; // 0xffffffff
field public static final int REMOVE_RESULT_ERROR_USER_NOT_FOUND = -3; // 0xfffffffd
@@ -10981,6 +11009,7 @@
field public static final String ACTION_NOTIFICATION_POLICY_ACCESS_DETAIL_SETTINGS = "android.settings.NOTIFICATION_POLICY_ACCESS_DETAIL_SETTINGS";
field public static final String ACTION_REQUEST_ENABLE_CONTENT_CAPTURE = "android.settings.REQUEST_ENABLE_CONTENT_CAPTURE";
field public static final String ACTION_SHOW_ADMIN_SUPPORT_DETAILS = "android.settings.SHOW_ADMIN_SUPPORT_DETAILS";
+ field public static final String ACTION_SHOW_RESTRICTED_SETTING_DIALOG = "android.settings.SHOW_RESTRICTED_SETTING_DIALOG";
field public static final String ACTION_TETHER_PROVISIONING_UI = "android.settings.TETHER_PROVISIONING_UI";
field public static final String ACTION_TETHER_SETTINGS = "android.settings.TETHER_SETTINGS";
field public static final String ACTION_TETHER_UNSUPPORTED_CARRIER_UI = "android.settings.TETHER_UNSUPPORTED_CARRIER_UI";
@@ -11739,6 +11768,7 @@
method public int onEraseSubscriptions(int, @android.telephony.euicc.EuiccCardManager.ResetOption int);
method public abstract android.service.euicc.GetDefaultDownloadableSubscriptionListResult onGetDefaultDownloadableSubscriptionList(int, boolean);
method public abstract android.service.euicc.GetDownloadableSubscriptionMetadataResult onGetDownloadableSubscriptionMetadata(int, android.telephony.euicc.DownloadableSubscription, boolean);
+ method @NonNull public android.service.euicc.GetDownloadableSubscriptionMetadataResult onGetDownloadableSubscriptionMetadata(int, int, @NonNull android.telephony.euicc.DownloadableSubscription, boolean);
method public abstract String onGetEid(int);
method @NonNull public abstract android.telephony.euicc.EuiccInfo onGetEuiccInfo(int);
method @NonNull public abstract android.service.euicc.GetEuiccProfileInfoListResult onGetEuiccProfileInfoList(int);
@@ -16501,6 +16531,7 @@
public abstract class AccessibilityDisplayProxy {
ctor public AccessibilityDisplayProxy(int, @NonNull java.util.concurrent.Executor, @NonNull java.util.List<android.accessibilityservice.AccessibilityServiceInfo>);
+ method @Nullable public android.view.accessibility.AccessibilityNodeInfo findFocus(int);
method public int getDisplayId();
method @NonNull public final java.util.List<android.accessibilityservice.AccessibilityServiceInfo> getInstalledAndEnabledServices();
method @NonNull public java.util.List<android.view.accessibility.AccessibilityWindowInfo> getWindows();
diff --git a/core/api/test-current.txt b/core/api/test-current.txt
index e3554a5..84ac868 100644
--- a/core/api/test-current.txt
+++ b/core/api/test-current.txt
@@ -1246,7 +1246,7 @@
public final class CameraManager {
method public String[] getCameraIdListNoLazy() throws android.hardware.camera2.CameraAccessException;
method @RequiresPermission(allOf={android.Manifest.permission.SYSTEM_CAMERA, android.Manifest.permission.CAMERA}) public void openCamera(@NonNull String, int, @NonNull java.util.concurrent.Executor, @NonNull android.hardware.camera2.CameraDevice.StateCallback) throws android.hardware.camera2.CameraAccessException;
- field public static final long OVERRIDE_FRONT_CAMERA_APP_COMPAT = 250678880L; // 0xef10e60L
+ field public static final long OVERRIDE_CAMERA_LANDSCAPE_TO_PORTRAIT = 250678880L; // 0xef10e60L
}
public abstract static class CameraManager.AvailabilityCallback {
@@ -3206,6 +3206,14 @@
package android.view.autofill {
+ public class AutofillFeatureFlags {
+ field public static final String DEVICE_CONFIG_AUTOFILL_COMPAT_MODE_ALLOWED_PACKAGES = "compat_mode_allowed_packages";
+ field public static final String DEVICE_CONFIG_AUTOFILL_CREDENTIAL_MANAGER_ENABLED = "autofill_credential_manager_enabled";
+ field public static final String DEVICE_CONFIG_AUTOFILL_CREDENTIAL_MANAGER_IGNORE_VIEWS = "autofill_credential_manager_ignore_views";
+ field public static final String DEVICE_CONFIG_AUTOFILL_DIALOG_ENABLED = "autofill_dialog_enabled";
+ field public static final String DEVICE_CONFIG_AUTOFILL_SMART_SUGGESTION_SUPPORTED_MODES = "smart_suggestion_supported_modes";
+ }
+
public final class AutofillId implements android.os.Parcelable {
ctor public AutofillId(int);
ctor public AutofillId(@NonNull android.view.autofill.AutofillId, int);
@@ -3217,9 +3225,6 @@
}
public final class AutofillManager {
- field public static final String DEVICE_CONFIG_AUTOFILL_COMPAT_MODE_ALLOWED_PACKAGES = "compat_mode_allowed_packages";
- field public static final String DEVICE_CONFIG_AUTOFILL_DIALOG_ENABLED = "autofill_dialog_enabled";
- field public static final String DEVICE_CONFIG_AUTOFILL_SMART_SUGGESTION_SUPPORTED_MODES = "smart_suggestion_supported_modes";
field public static final int FLAG_SMART_SUGGESTION_OFF = 0; // 0x0
field public static final int FLAG_SMART_SUGGESTION_SYSTEM = 1; // 0x1
field public static final int MAX_TEMP_AUGMENTED_SERVICE_DURATION_MS = 120000; // 0x1d4c0
@@ -3322,6 +3327,14 @@
public abstract class HandwritingGesture {
method public final int getGestureType();
+ field public static final int GESTURE_TYPE_DELETE = 4; // 0x4
+ field public static final int GESTURE_TYPE_DELETE_RANGE = 64; // 0x40
+ field public static final int GESTURE_TYPE_INSERT = 2; // 0x2
+ field public static final int GESTURE_TYPE_JOIN_OR_SPLIT = 16; // 0x10
+ field public static final int GESTURE_TYPE_NONE = 0; // 0x0
+ field public static final int GESTURE_TYPE_REMOVE_SPACE = 8; // 0x8
+ field public static final int GESTURE_TYPE_SELECT = 1; // 0x1
+ field public static final int GESTURE_TYPE_SELECT_RANGE = 32; // 0x20
}
public final class InlineSuggestion implements android.os.Parcelable {
@@ -3662,22 +3675,22 @@
public final class WindowContainerTransaction implements android.os.Parcelable {
ctor public WindowContainerTransaction();
+ method @NonNull public android.window.WindowContainerTransaction clearAdjacentTaskFragments(@NonNull android.os.IBinder);
method @NonNull public android.window.WindowContainerTransaction clearLaunchAdjacentFlagRoot(@NonNull android.window.WindowContainerToken);
method @NonNull public android.window.WindowContainerTransaction createTaskFragment(@NonNull android.window.TaskFragmentCreationParams);
- method @NonNull public android.window.WindowContainerTransaction deleteTaskFragment(@NonNull android.window.WindowContainerToken);
+ method @NonNull public android.window.WindowContainerTransaction deleteTaskFragment(@NonNull android.os.IBinder);
method public int describeContents();
method @NonNull public android.window.WindowContainerTransaction finishActivity(@NonNull android.os.IBinder);
method @NonNull public android.window.WindowContainerTransaction removeTask(@NonNull android.window.WindowContainerToken);
method @NonNull public android.window.WindowContainerTransaction reorder(@NonNull android.window.WindowContainerToken, boolean);
method @NonNull public android.window.WindowContainerTransaction reparent(@NonNull android.window.WindowContainerToken, @Nullable android.window.WindowContainerToken, boolean);
method @NonNull public android.window.WindowContainerTransaction reparentActivityToTaskFragment(@NonNull android.os.IBinder, @NonNull android.os.IBinder);
- method @NonNull public android.window.WindowContainerTransaction reparentChildren(@NonNull android.window.WindowContainerToken, @Nullable android.window.WindowContainerToken);
method @NonNull public android.window.WindowContainerTransaction reparentTasks(@Nullable android.window.WindowContainerToken, @Nullable android.window.WindowContainerToken, @Nullable int[], @Nullable int[], boolean);
method @NonNull public android.window.WindowContainerTransaction requestFocusOnTaskFragment(@NonNull android.os.IBinder);
method @NonNull public android.window.WindowContainerTransaction scheduleFinishEnterPip(@NonNull android.window.WindowContainerToken, @NonNull android.graphics.Rect);
method @NonNull public android.window.WindowContainerTransaction setActivityWindowingMode(@NonNull android.window.WindowContainerToken, int);
method @NonNull public android.window.WindowContainerTransaction setAdjacentRoots(@NonNull android.window.WindowContainerToken, @NonNull android.window.WindowContainerToken);
- method @NonNull public android.window.WindowContainerTransaction setAdjacentTaskFragments(@NonNull android.os.IBinder, @Nullable android.os.IBinder, @Nullable android.window.WindowContainerTransaction.TaskFragmentAdjacentParams);
+ method @NonNull public android.window.WindowContainerTransaction setAdjacentTaskFragments(@NonNull android.os.IBinder, @NonNull android.os.IBinder, @Nullable android.window.WindowContainerTransaction.TaskFragmentAdjacentParams);
method @NonNull public android.window.WindowContainerTransaction setAppBounds(@NonNull android.window.WindowContainerToken, @NonNull android.graphics.Rect);
method @NonNull public android.window.WindowContainerTransaction setBounds(@NonNull android.window.WindowContainerToken, @NonNull android.graphics.Rect);
method @NonNull public android.window.WindowContainerTransaction setBoundsChangeTransaction(@NonNull android.window.WindowContainerToken, @NonNull android.view.SurfaceControl.Transaction);
diff --git a/core/java/android/app/Activity.java b/core/java/android/app/Activity.java
index 32d88b2..c0239e8 100644
--- a/core/java/android/app/Activity.java
+++ b/core/java/android/app/Activity.java
@@ -9085,6 +9085,25 @@
state, sourceSpec, targetSpec, viewIds, uiTranslationSpec);
}
+ /**
+ * If set, any activity launch in the same task will be overridden to the locale of activity
+ * that started the task.
+ *
+ * <p>Currently, Android supports per app languages, and system apps are able to start
+ * activities of another package on the same task, which may cause users to set different
+ * languages in different apps and display two different languages in one app.</p>
+ *
+ * <p>The <a href="https://developer.android.com/guide/topics/large-screens/activity-embedding">
+ * activity embedding feature</a> will align the locale with root activity automatically, but
+ * it doesn't land on the phone yet. If activity embedding land on the phone in the future,
+ * please consider adapting activity embedding directly.</p>
+ *
+ * @hide
+ */
+ public void enableTaskLocaleOverride() {
+ ActivityClient.getInstance().enableTaskLocaleOverride(mToken);
+ }
+
class HostCallbacks extends FragmentHostCallback<Activity> {
public HostCallbacks() {
super(Activity.this /*activity*/);
diff --git a/core/java/android/app/ActivityClient.java b/core/java/android/app/ActivityClient.java
index 558dae5..aa868a7 100644
--- a/core/java/android/app/ActivityClient.java
+++ b/core/java/android/app/ActivityClient.java
@@ -563,6 +563,14 @@
}
}
+ void enableTaskLocaleOverride(IBinder token) {
+ try {
+ getActivityClientController().enableTaskLocaleOverride(token);
+ } catch (RemoteException e) {
+ e.rethrowFromSystemServer();
+ }
+ }
+
/**
* Shows or hides a Camera app compat toggle for stretched issues with the requested state.
*
diff --git a/core/java/android/app/ActivityManagerInternal.java b/core/java/android/app/ActivityManagerInternal.java
index 6826b67..3e21124 100644
--- a/core/java/android/app/ActivityManagerInternal.java
+++ b/core/java/android/app/ActivityManagerInternal.java
@@ -20,6 +20,8 @@
import android.annotation.NonNull;
import android.annotation.Nullable;
+import android.annotation.PermissionMethod;
+import android.annotation.PermissionName;
import android.annotation.UserIdInt;
import android.app.ActivityManager.ProcessCapability;
import android.app.ActivityManager.RestrictionLevel;
@@ -31,8 +33,6 @@
import android.content.pm.ActivityInfo;
import android.content.pm.ActivityPresentationInfo;
import android.content.pm.ApplicationInfo;
-import android.content.pm.PermissionMethod;
-import android.content.pm.PermissionName;
import android.content.pm.UserInfo;
import android.net.Uri;
import android.os.Bundle;
diff --git a/core/java/android/app/ActivityThread.java b/core/java/android/app/ActivityThread.java
index 86482c0..421ba7c 100644
--- a/core/java/android/app/ActivityThread.java
+++ b/core/java/android/app/ActivityThread.java
@@ -2640,7 +2640,7 @@
ClassLoader baseLoader, boolean securityViolation, boolean includeCode,
boolean registerPackage) {
return getPackageInfo(aInfo, compatInfo, baseLoader, securityViolation, includeCode,
- registerPackage, /*isSdkSandbox=*/false);
+ registerPackage, Process.isSdkSandbox());
}
private LoadedApk getPackageInfo(ApplicationInfo aInfo, CompatibilityInfo compatInfo,
@@ -4558,7 +4558,11 @@
service.attach(context, this, data.info.name, data.token, app,
ActivityManager.getService());
if (!service.isUiContext()) { // WindowProviderService is a UI Context.
- service.updateDeviceId(mLastReportedDeviceId);
+ VirtualDeviceManager vdm = context.getSystemService(VirtualDeviceManager.class);
+ if (mLastReportedDeviceId == VirtualDeviceManager.DEVICE_ID_DEFAULT
+ || vdm.isValidVirtualDeviceId(mLastReportedDeviceId)) {
+ service.updateDeviceId(mLastReportedDeviceId);
+ }
}
service.onCreate();
mServicesData.put(data.token, data);
diff --git a/core/java/android/app/ApplicationPackageManager.java b/core/java/android/app/ApplicationPackageManager.java
index a7a4b35..c11961e 100644
--- a/core/java/android/app/ApplicationPackageManager.java
+++ b/core/java/android/app/ApplicationPackageManager.java
@@ -3890,4 +3890,14 @@
return Settings.Global.getInt(mContext.getContentResolver(),
Settings.Global.SHOW_NEW_APP_INSTALLED_NOTIFICATION_ENABLED, 0) == 1;
}
+
+ @Override
+ public void relinquishUpdateOwnership(String targetPackage) {
+ Objects.requireNonNull(targetPackage);
+ try {
+ mPM.relinquishUpdateOwnership(targetPackage);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
}
diff --git a/core/java/android/app/BroadcastOptions.java b/core/java/android/app/BroadcastOptions.java
index e202760..5cf10d0 100644
--- a/core/java/android/app/BroadcastOptions.java
+++ b/core/java/android/app/BroadcastOptions.java
@@ -63,6 +63,7 @@
private long mRequireCompatChangeId = CHANGE_INVALID;
private boolean mRequireCompatChangeEnabled = true;
private boolean mIsAlarmBroadcast = false;
+ private boolean mIsDeferUntilActive = false;
private long mIdForResponseEvent;
private @Nullable IntentFilter mRemoveMatchingFilter;
private @DeliveryGroupPolicy int mDeliveryGroupPolicy;
@@ -201,6 +202,12 @@
"android:broadcast.removeMatchingFilter";
/**
+ * Corresponds to {@link #setDeferUntilActive(boolean)}.
+ */
+ private static final String KEY_DEFER_UNTIL_ACTIVE =
+ "android:broadcast.deferuntilactive";
+
+ /**
* Corresponds to {@link #setDeliveryGroupPolicy(int)}.
*/
private static final String KEY_DELIVERY_GROUP_POLICY =
@@ -320,6 +327,7 @@
BundleMerger.class);
mDeliveryGroupMatchingFilter = opts.getParcelable(KEY_DELIVERY_GROUP_MATCHING_FILTER,
IntentFilter.class);
+ mIsDeferUntilActive = opts.getBoolean(KEY_DEFER_UNTIL_ACTIVE, false);
}
/**
@@ -700,6 +708,41 @@
}
/**
+ * Sets whether the broadcast should not run until the process is in an active process state
+ * (ie, a process exists for the app and the app is not in a cached process state).
+ *
+ * Whether an app's process state is considered active is independent of its standby bucket.
+ *
+ * A broadcast that is deferred until the process is active will not execute until the process
+ * is brought to an active state by some other action, like a job, alarm, or service binding. As
+ * a result, the broadcast may be delayed indefinitely. This deferral only applies to runtime
+ * registered receivers of a broadcast. Any manifest receivers will run immediately, similar to
+ * how a manifest receiver would start a new process in order to run a broadcast receiver.
+ *
+ * Ordered broadcasts, alarm broadcasts, interactive broadcasts, and manifest broadcasts are
+ * never deferred.
+ *
+ * Unordered broadcasts and unordered broadcasts with completion callbacks may be
+ * deferred. Completion callbacks for broadcasts deferred until active are
+ * best-effort. Completion callbacks will run when all eligible processes have finished
+ * executing the broadcast. Processes in inactive process states that defer the broadcast are
+ * not considered eligible and may not execute the broadcast prior to the completion callback.
+ *
+ * @hide
+ */
+ @SystemApi
+ public @NonNull BroadcastOptions setDeferUntilActive(boolean shouldDefer) {
+ mIsDeferUntilActive = shouldDefer;
+ return this;
+ }
+
+ /** @hide */
+ @SystemApi
+ public boolean isDeferUntilActive() {
+ return mIsDeferUntilActive;
+ }
+
+ /**
* When enqueuing this broadcast, remove all pending broadcasts previously
* sent by this app which match the given filter.
* <p>
@@ -963,6 +1006,9 @@
if (mDeliveryGroupMatchingFilter != null) {
b.putParcelable(KEY_DELIVERY_GROUP_MATCHING_FILTER, mDeliveryGroupMatchingFilter);
}
+ if (mIsDeferUntilActive) {
+ b.putBoolean(KEY_DEFER_UNTIL_ACTIVE, mIsDeferUntilActive);
+ }
return b.isEmpty() ? null : b;
}
}
diff --git a/core/java/android/app/ContextImpl.java b/core/java/android/app/ContextImpl.java
index 240dbe1..b91fa35 100644
--- a/core/java/android/app/ContextImpl.java
+++ b/core/java/android/app/ContextImpl.java
@@ -26,9 +26,7 @@
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.UiContext;
-import android.companion.virtual.VirtualDevice;
import android.companion.virtual.VirtualDeviceManager;
-import android.companion.virtual.VirtualDeviceParams;
import android.compat.annotation.UnsupportedAppUsage;
import android.content.AttributionSource;
import android.content.AutofillOptions;
@@ -2584,6 +2582,22 @@
}
@Override
+ public Context createContextForSdkInSandbox(ApplicationInfo sdkInfo, int flags)
+ throws NameNotFoundException {
+ if (!Process.isSdkSandbox()) {
+ throw new SecurityException("API can only be called from SdkSandbox process");
+ }
+
+ ContextImpl ctx = (ContextImpl) createApplicationContext(sdkInfo, flags);
+
+ // Set sandbox app's context as the application context for sdk context
+ ctx.mPackageInfo.makeApplicationInner(/*forceDefaultAppClass=*/false,
+ /*instrumentation=*/null);
+
+ return ctx;
+ }
+
+ @Override
public Context createPackageContext(String packageName, int flags)
throws NameNotFoundException {
return createPackageContextAsUser(packageName, flags, mUser);
@@ -2742,9 +2756,12 @@
@Override
public @NonNull Context createDeviceContext(int deviceId) {
- if (!isValidDeviceId(deviceId)) {
- throw new IllegalArgumentException(
- "Not a valid ID of the default device or any virtual device: " + deviceId);
+ if (deviceId != VirtualDeviceManager.DEVICE_ID_DEFAULT) {
+ VirtualDeviceManager vdm = getSystemService(VirtualDeviceManager.class);
+ if (!vdm.isValidVirtualDeviceId(deviceId)) {
+ throw new IllegalArgumentException(
+ "Not a valid ID of the default device or any virtual device: " + deviceId);
+ }
}
ContextImpl context = new ContextImpl(this, mMainThread, mPackageInfo, mParams,
@@ -2757,31 +2774,6 @@
return context;
}
- /**
- * Checks whether the passed {@code deviceId} is valid or not.
- * {@link VirtualDeviceManager#DEVICE_ID_DEFAULT} is valid as it is the ID of the default
- * device when no additional virtual devices exist. If {@code deviceId} is the id of
- * a virtual device, it should correspond to a virtual device created by
- * {@link VirtualDeviceManager#createVirtualDevice(int, VirtualDeviceParams)}.
- */
- private boolean isValidDeviceId(int deviceId) {
- if (deviceId == VirtualDeviceManager.DEVICE_ID_DEFAULT) {
- return true;
- }
- if (deviceId > VirtualDeviceManager.DEVICE_ID_DEFAULT) {
- VirtualDeviceManager vdm = getSystemService(VirtualDeviceManager.class);
- if (vdm != null) {
- List<VirtualDevice> virtualDevices = vdm.getVirtualDevices();
- for (int i = 0; i < virtualDevices.size(); i++) {
- if (virtualDevices.get(i).getDeviceId() == deviceId) {
- return true;
- }
- }
- }
- }
- return false;
- }
-
@NonNull
@Override
public WindowContext createWindowContext(@WindowType int type,
@@ -3044,17 +3036,23 @@
@Override
public void updateDeviceId(int updatedDeviceId) {
- if (!isValidDeviceId(updatedDeviceId)) {
- throw new IllegalArgumentException(
- "Not a valid ID of the default device or any virtual device: "
- + updatedDeviceId);
+ if (updatedDeviceId != VirtualDeviceManager.DEVICE_ID_DEFAULT) {
+ VirtualDeviceManager vdm = getSystemService(VirtualDeviceManager.class);
+ if (!vdm.isValidVirtualDeviceId(updatedDeviceId)) {
+ throw new IllegalArgumentException(
+ "Not a valid ID of the default device or any virtual device: "
+ + updatedDeviceId);
+ }
}
if (mIsExplicitDeviceId) {
throw new UnsupportedOperationException(
"Cannot update device ID on a Context created with createDeviceContext()");
}
- mDeviceId = updatedDeviceId;
- notifyOnDeviceChangedListeners(updatedDeviceId);
+
+ if (mDeviceId != updatedDeviceId) {
+ mDeviceId = updatedDeviceId;
+ notifyOnDeviceChangedListeners(updatedDeviceId);
+ }
}
@Override
diff --git a/core/java/android/app/ForegroundServiceTypePolicy.java b/core/java/android/app/ForegroundServiceTypePolicy.java
index 877177c..f0c39ab 100644
--- a/core/java/android/app/ForegroundServiceTypePolicy.java
+++ b/core/java/android/app/ForegroundServiceTypePolicy.java
@@ -117,14 +117,10 @@
* The FGS type enforcement:
* deprecating the {@link android.content.pm.ServiceInfo#FOREGROUND_SERVICE_TYPE_DATA_SYNC}.
*
- * <p>Starting a FGS with this type from apps with targetSdkVersion
- * {@link android.os.Build.VERSION_CODES#UPSIDE_DOWN_CAKE} or later will
- * result in a warning in the log.</p>
- *
* @hide
*/
@ChangeId
- @EnabledAfter(targetSdkVersion = android.os.Build.VERSION_CODES.TIRAMISU)
+ @Disabled
@Overridable
public static final long FGS_TYPE_DATA_SYNC_DEPRECATION_CHANGE_ID = 255039210L;
@@ -132,13 +128,8 @@
* The FGS type enforcement:
* disabling the {@link android.content.pm.ServiceInfo#FOREGROUND_SERVICE_TYPE_DATA_SYNC}.
*
- * <p>Starting a FGS with this type from apps with targetSdkVersion
- * {@link android.os.Build.VERSION_CODES#UPSIDE_DOWN_CAKE} or later will
- * result in an exception.</p>
- *
* @hide
*/
- // TODO (b/254661666): Change to @EnabledSince(U) in next OS release
@ChangeId
@Disabled
@Overridable
diff --git a/core/java/android/app/IActivityClientController.aidl b/core/java/android/app/IActivityClientController.aidl
index ecea46a..03646c6 100644
--- a/core/java/android/app/IActivityClientController.aidl
+++ b/core/java/android/app/IActivityClientController.aidl
@@ -171,4 +171,10 @@
*/
oneway void requestCompatCameraControl(in IBinder token, boolean showControl,
boolean transformationApplied, in ICompatCameraControlCallback callback);
+
+ /**
+ * If set, any activity launch in the same task will be overridden to the locale of activity
+ * that started the task.
+ */
+ void enableTaskLocaleOverride(in IBinder token);
}
diff --git a/core/java/android/app/LocaleConfig.java b/core/java/android/app/LocaleConfig.java
index 50ba7db..69693fc 100644
--- a/core/java/android/app/LocaleConfig.java
+++ b/core/java/android/app/LocaleConfig.java
@@ -110,7 +110,7 @@
* @see Context#createPackageContext(String, int).
*/
@NonNull
- public static LocaleConfig fromResources(@NonNull Context context) {
+ public static LocaleConfig fromContextIgnoringOverride(@NonNull Context context) {
return new LocaleConfig(context, false);
}
diff --git a/core/java/android/app/OWNERS b/core/java/android/app/OWNERS
index f2eced3..20869e0 100644
--- a/core/java/android/app/OWNERS
+++ b/core/java/android/app/OWNERS
@@ -47,6 +47,9 @@
# AppOps
per-file *AppOp* = file:/core/java/android/permission/OWNERS
+# Backup and Restore
+per-file IBackupAgent.aidl = file:/services/backup/OWNERS
+
# LocaleManager
per-file *Locale* = file:/services/core/java/com/android/server/locales/OWNERS
diff --git a/core/java/android/app/PendingIntent.java b/core/java/android/app/PendingIntent.java
index 512b5e0..c58e627 100644
--- a/core/java/android/app/PendingIntent.java
+++ b/core/java/android/app/PendingIntent.java
@@ -879,6 +879,20 @@
}
/**
+ * Perform the operation associated with this PendingIntent, supplying additional
+ * options for the operation.
+ *
+ * @param options Additional options the caller would like to provide to modify the
+ * sending behavior. May be built from an {@link ActivityOptions} to apply to an
+ * activity start.
+ *
+ * @hide
+ */
+ public void send(Bundle options) throws CanceledException {
+ send(null, 0, null, null, null, null, options);
+ }
+
+ /**
* Perform the operation associated with this PendingIntent, allowing the
* caller to be notified when the send has completed.
*
diff --git a/core/java/android/app/Service.java b/core/java/android/app/Service.java
index ad27b33..e485397 100644
--- a/core/java/android/app/Service.java
+++ b/core/java/android/app/Service.java
@@ -1080,7 +1080,6 @@
if (mForegroundServiceTraceTitle != null) {
Trace.asyncTraceForTrackEnd(TRACE_TAG_ACTIVITY_MANAGER,
TRACE_TRACK_NAME_FOREGROUND_SERVICE,
- mForegroundServiceTraceTitle,
System.identityHashCode(this));
mForegroundServiceTraceTitle = null;
}
diff --git a/core/java/android/app/admin/DevicePolicyManager.java b/core/java/android/app/admin/DevicePolicyManager.java
index ad17e0d..1633073 100644
--- a/core/java/android/app/admin/DevicePolicyManager.java
+++ b/core/java/android/app/admin/DevicePolicyManager.java
@@ -2417,6 +2417,7 @@
* applied (cross profile intent filters updated). Only usesd for CTS tests.
* @hide
*/
+ @SuppressLint("ActionValue")
@TestApi
@SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
public static final String ACTION_DATA_SHARING_RESTRICTION_APPLIED =
@@ -2427,6 +2428,7 @@
* has been changed.
* @hide
*/
+ @SuppressLint("ActionValue")
@TestApi
@SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
public static final String ACTION_DEVICE_POLICY_CONSTANTS_CHANGED =
@@ -6979,6 +6981,8 @@
* {@link #ENCRYPTION_STATUS_UNSUPPORTED}, {@link #ENCRYPTION_STATUS_INACTIVE},
* {@link #ENCRYPTION_STATUS_ACTIVATING}, {@link #ENCRYPTION_STATUS_ACTIVE_DEFAULT_KEY},
* {@link #ENCRYPTION_STATUS_ACTIVE}, or {@link #ENCRYPTION_STATUS_ACTIVE_PER_USER}.
+ *
+ * @throws SecurityException if called on a parent instance.
*/
public int getStorageEncryptionStatus() {
throwIfParentInstance("getStorageEncryptionStatus");
diff --git a/core/java/android/app/admin/PolicyUpdatesReceiver.java b/core/java/android/app/admin/PolicyUpdatesReceiver.java
index 3ad3157..f7216e7 100644
--- a/core/java/android/app/admin/PolicyUpdatesReceiver.java
+++ b/core/java/android/app/admin/PolicyUpdatesReceiver.java
@@ -21,7 +21,6 @@
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.SdkConstant;
-import android.annotation.SuppressLint;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
@@ -109,8 +108,6 @@
public static final String ACTION_DEVICE_POLICY_CHANGED =
"android.app.admin.action.DEVICE_POLICY_CHANGED";
- // TODO(b/264510719): Remove once API linter is fixed
- @SuppressLint("ActionValue")
/**
* A string extra holding the package name the policy applies to, (see
* {@link PolicyUpdatesReceiver#onPolicyChanged} and
@@ -119,8 +116,6 @@
public static final String EXTRA_PACKAGE_NAME =
"android.app.admin.extra.PACKAGE_NAME";
- // TODO(b/264510719): Remove once API linter is fixed
- @SuppressLint("ActionValue")
/**
* A string extra holding the permission name the policy applies to, (see
* {@link PolicyUpdatesReceiver#onPolicyChanged} and
diff --git a/core/java/android/app/time/UnixEpochTime.java b/core/java/android/app/time/UnixEpochTime.java
index 61cbc5e..0b8f7ee 100644
--- a/core/java/android/app/time/UnixEpochTime.java
+++ b/core/java/android/app/time/UnixEpochTime.java
@@ -124,7 +124,7 @@
@Override
public String toString() {
return "UnixEpochTime{"
- + "mElapsedRealtimeTimeMillis=" + mElapsedRealtimeMillis
+ + "mElapsedRealtimeMillis=" + mElapsedRealtimeMillis
+ ", mUnixEpochTimeMillis=" + mUnixEpochTimeMillis
+ '}';
}
diff --git a/core/java/android/app/timedetector/TimeDetector.java b/core/java/android/app/timedetector/TimeDetector.java
index f95d6d3..50a7da1 100644
--- a/core/java/android/app/timedetector/TimeDetector.java
+++ b/core/java/android/app/timedetector/TimeDetector.java
@@ -73,6 +73,18 @@
String SHELL_COMMAND_SUGGEST_NETWORK_TIME = "suggest_network_time";
/**
+ * A shell command that prints the current network time information.
+ * @hide
+ */
+ String SHELL_COMMAND_GET_NETWORK_TIME = "get_network_time";
+
+ /**
+ * A shell command that clears the detector's network time information.
+ * @hide
+ */
+ String SHELL_COMMAND_CLEAR_NETWORK_TIME = "clear_network_time";
+
+ /**
* A shell command that injects a GNSS time suggestion.
* @hide
*/
diff --git a/core/java/android/companion/CompanionDeviceManager.java b/core/java/android/companion/CompanionDeviceManager.java
index 63f4bcf..d31124d 100644
--- a/core/java/android/companion/CompanionDeviceManager.java
+++ b/core/java/android/companion/CompanionDeviceManager.java
@@ -662,9 +662,7 @@
* @return the associations list
* @see #addOnAssociationsChangedListener(Executor, OnAssociationsChangedListener)
* @see #removeOnAssociationsChangedListener(OnAssociationsChangedListener)
- * @hide
*/
- @SystemApi
@UserHandleAware
@RequiresPermission(android.Manifest.permission.MANAGE_COMPANION_DEVICES)
public @NonNull List<AssociationInfo> getAllAssociations() {
@@ -678,10 +676,7 @@
/**
* Listener for any changes to {@link AssociationInfo}.
- *
- * @hide
*/
- @SystemApi
public interface OnAssociationsChangedListener {
/**
* Invoked when a change occurs to any of the associations for the user (including adding
@@ -696,9 +691,7 @@
* Register listener for any changes to {@link AssociationInfo}.
*
* @see #getAllAssociations()
- * @hide
*/
- @SystemApi
@UserHandleAware
@RequiresPermission(android.Manifest.permission.MANAGE_COMPANION_DEVICES)
public void addOnAssociationsChangedListener(
@@ -720,9 +713,7 @@
* Unregister listener for any changes to {@link AssociationInfo}.
*
* @see #getAllAssociations()
- * @hide
*/
- @SystemApi
@UserHandleAware
@RequiresPermission(android.Manifest.permission.MANAGE_COMPANION_DEVICES)
public void removeOnAssociationsChangedListener(
diff --git a/core/java/android/companion/virtual/IVirtualDeviceManager.aidl b/core/java/android/companion/virtual/IVirtualDeviceManager.aidl
index f0d23ac..e96a2c1 100644
--- a/core/java/android/companion/virtual/IVirtualDeviceManager.aidl
+++ b/core/java/android/companion/virtual/IVirtualDeviceManager.aidl
@@ -56,6 +56,14 @@
*/
int getDeviceIdForDisplayId(int displayId);
+ /**
+ * Checks whether the passed {@code deviceId} is a valid virtual device ID or not.
+ * {@link VirtualDeviceManager#DEVICE_ID_DEFAULT} is not valid as it is the ID of the default
+ * device which is not a virtual device. {@code deviceId} must correspond to a virtual device
+ * created by {@link VirtualDeviceManager#createVirtualDevice(int, VirtualDeviceParams)}.
+ */
+ boolean isValidVirtualDeviceId(int deviceId);
+
/**
* Returns the device policy for the given virtual device and policy type.
*/
diff --git a/core/java/android/companion/virtual/TEST_MAPPING b/core/java/android/companion/virtual/TEST_MAPPING
new file mode 100644
index 0000000..6a67b7f
--- /dev/null
+++ b/core/java/android/companion/virtual/TEST_MAPPING
@@ -0,0 +1,7 @@
+{
+ "imports": [
+ {
+ "path": "frameworks/base/services/companion/java/com/android/server/companion/virtual"
+ }
+ ]
+}
diff --git a/core/java/android/companion/virtual/VirtualDeviceManager.java b/core/java/android/companion/virtual/VirtualDeviceManager.java
index adf59fb..3bc1628 100644
--- a/core/java/android/companion/virtual/VirtualDeviceManager.java
+++ b/core/java/android/companion/virtual/VirtualDeviceManager.java
@@ -258,6 +258,26 @@
}
/**
+ * Checks whether the passed {@code deviceId} is a valid virtual device ID or not.
+ * {@link VirtualDeviceManager#DEVICE_ID_DEFAULT} is not valid as it is the ID of the default
+ * device which is not a virtual device. {@code deviceId} must correspond to a virtual device
+ * created by {@link VirtualDeviceManager#createVirtualDevice(int, VirtualDeviceParams)}.
+ *
+ * @hide
+ */
+ public boolean isValidVirtualDeviceId(int deviceId) {
+ if (mService == null) {
+ Log.w(TAG, "Failed to retrieve virtual devices; no virtual device manager service.");
+ return false;
+ }
+ try {
+ return mService.isValidVirtualDeviceId(deviceId);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
+ /**
* Returns device-specific audio session id for audio playback.
*
* @param deviceId - id of the virtual audio device
@@ -931,16 +951,16 @@
* when matching the provided IntentFilter and calls the callback with the intercepted
* intent.
*
- * @param executor The executor where the interceptor is executed on.
* @param interceptorFilter The filter to match intents intended for interception.
+ * @param executor The executor where the interceptor is executed on.
* @param interceptorCallback The callback called when an intent matching interceptorFilter
* is intercepted.
* @see #unregisterIntentInterceptor(IntentInterceptorCallback)
*/
@RequiresPermission(android.Manifest.permission.CREATE_VIRTUAL_DEVICE)
public void registerIntentInterceptor(
- @CallbackExecutor @NonNull Executor executor,
@NonNull IntentFilter interceptorFilter,
+ @CallbackExecutor @NonNull Executor executor,
@NonNull IntentInterceptorCallback interceptorCallback) {
Objects.requireNonNull(executor);
Objects.requireNonNull(interceptorFilter);
diff --git a/core/java/android/content/Context.java b/core/java/android/content/Context.java
index 12a2cae..c8d48c1 100644
--- a/core/java/android/content/Context.java
+++ b/core/java/android/content/Context.java
@@ -26,6 +26,8 @@
import android.annotation.IntDef;
import android.annotation.NonNull;
import android.annotation.Nullable;
+import android.annotation.PermissionMethod;
+import android.annotation.PermissionName;
import android.annotation.RequiresPermission;
import android.annotation.StringDef;
import android.annotation.StringRes;
@@ -53,8 +55,6 @@
import android.compat.annotation.UnsupportedAppUsage;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager;
-import android.content.pm.PermissionMethod;
-import android.content.pm.PermissionName;
import android.content.res.AssetManager;
import android.content.res.ColorStateList;
import android.content.res.Configuration;
@@ -408,7 +408,12 @@
* will cause the isolated service to be co-located in the same shared isolated process.
*
* Note that the shared isolated process is scoped to the calling app; once created, only
- * the calling app can bind additional isolated services into the shared process.
+ * the calling app can bind additional isolated services into the shared process. However,
+ * the services themselves can come from different APKs and therefore different vendors.
+ *
+ * Only services that set the {@link android.R.attr#allowSharedIsolatedProcess} attribute
+ * to {@code true} are allowed to be bound into a shared isolated process.
+ *
*/
public static final int BIND_SHARED_ISOLATED_PROCESS = 0x00002000;
@@ -6854,6 +6859,26 @@
@CreatePackageOptions int flags) throws PackageManager.NameNotFoundException;
/**
+ * Creates a context given an {@link android.content.pm.ApplicationInfo}.
+ *
+ * Context created is for an sdk library that is being loaded in sdk sandbox.
+ *
+ * @param sdkInfo information regarding the sdk library being loaded.
+ *
+ * @throws PackageManager.NameNotFoundException if there is no application with
+ * the given package name.
+ * @throws SecurityException if caller is not a SdkSandbox process.
+ *
+ * @hide
+ */
+ @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
+ @NonNull
+ public Context createContextForSdkInSandbox(@NonNull ApplicationInfo sdkInfo,
+ @CreatePackageOptions int flags) throws PackageManager.NameNotFoundException {
+ throw new RuntimeException("Not implemented. Must override in a subclass.");
+ }
+
+ /**
* Return a new Context object for the given split name. The new Context has a ClassLoader and
* Resources object that can access the split's and all of its dependencies' code/resources.
* Each call to this method returns a new instance of a Context object;
diff --git a/core/java/android/content/ContextWrapper.java b/core/java/android/content/ContextWrapper.java
index 0dc4adc..e65e91c 100644
--- a/core/java/android/content/ContextWrapper.java
+++ b/core/java/android/content/ContextWrapper.java
@@ -1073,6 +1073,15 @@
/** @hide */
@Override
+ @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
+ @NonNull
+ public Context createContextForSdkInSandbox(@NonNull ApplicationInfo sdkInfo, int flags)
+ throws PackageManager.NameNotFoundException {
+ return mBase.createContextForSdkInSandbox(sdkInfo, flags);
+ }
+
+ /** @hide */
+ @Override
public Context createContextForSplit(String splitName)
throws PackageManager.NameNotFoundException {
return mBase.createContextForSplit(splitName);
diff --git a/core/java/android/content/Intent.java b/core/java/android/content/Intent.java
index 7ee8f60..4318c39 100644
--- a/core/java/android/content/Intent.java
+++ b/core/java/android/content/Intent.java
@@ -11601,7 +11601,7 @@
private void toUriInner(StringBuilder uri, String scheme, String defAction,
String defPackage, int flags) {
if (scheme != null) {
- uri.append("scheme=").append(scheme).append(';');
+ uri.append("scheme=").append(Uri.encode(scheme)).append(';');
}
if (mAction != null && !mAction.equals(defAction)) {
uri.append("action=").append(Uri.encode(mAction)).append(';');
diff --git a/core/java/android/content/pm/ActivityInfo.java b/core/java/android/content/pm/ActivityInfo.java
index a9f55bc..8fd905e 100644
--- a/core/java/android/content/pm/ActivityInfo.java
+++ b/core/java/android/content/pm/ActivityInfo.java
@@ -1102,6 +1102,41 @@
public static final long ALWAYS_SANDBOX_DISPLAY_APIS = 185004937L; // buganizer id
/**
+ * This change id excludes the packages it is applied to from the camera compat force rotation
+ * treatment. See com.android.server.wm.DisplayRotationCompatPolicy for context.
+ * @hide
+ */
+ @ChangeId
+ @Overridable
+ @Disabled
+ public static final long OVERRIDE_CAMERA_COMPAT_DISABLE_FORCE_ROTATION =
+ 263959004L; // buganizer id
+
+ /**
+ * This change id excludes the packages it is applied to from activity refresh after camera
+ * compat force rotation treatment. See com.android.server.wm.DisplayRotationCompatPolicy for
+ * context.
+ * @hide
+ */
+ @ChangeId
+ @Overridable
+ @Disabled
+ public static final long OVERRIDE_CAMERA_COMPAT_DISABLE_REFRESH = 264304459L; // buganizer id
+
+ /**
+ * This change id makes the packages it is applied to do activity refresh after camera compat
+ * force rotation treatment using "resumed -> paused -> resumed" cycle rather than "resumed ->
+ * ... -> stopped -> ... -> resumed" cycle. See
+ * com.android.server.wm.DisplayRotationCompatPolicy for context.
+ * @hide
+ */
+ @ChangeId
+ @Overridable
+ @Disabled
+ public static final long OVERRIDE_CAMERA_COMPAT_ENABLE_REFRESH_VIA_PAUSE =
+ 264301586L; // buganizer id
+
+ /**
* This change id is the gatekeeper for all treatments that force a given min aspect ratio.
* Enabling this change will allow the following min aspect ratio treatments to be applied:
* OVERRIDE_MIN_ASPECT_RATIO_MEDIUM
diff --git a/core/java/android/content/pm/IPackageInstallerSession.aidl b/core/java/android/content/pm/IPackageInstallerSession.aidl
index 60a7b13..9dd9c0f 100644
--- a/core/java/android/content/pm/IPackageInstallerSession.aidl
+++ b/core/java/android/content/pm/IPackageInstallerSession.aidl
@@ -46,6 +46,8 @@
void commit(in IntentSender statusReceiver, boolean forTransferred);
void transfer(in String packageName);
void abandon();
+ void seal();
+ List<String> fetchPackageNames();
DataLoaderParamsParcel getDataLoaderParams();
void addFile(int location, String name, long lengthBytes, in byte[] metadata, in byte[] signature);
@@ -63,6 +65,7 @@
void requestUserPreapproval(in PackageInstaller.PreapprovalDetails details, in IntentSender statusReceiver);
boolean isKeepApplicationEnabledSetting();
+ boolean isRequestUpdateOwnership();
ParcelFileDescriptor getAppMetadataFd();
ParcelFileDescriptor openWriteAppMetadata();
diff --git a/core/java/android/content/pm/IPackageManager.aidl b/core/java/android/content/pm/IPackageManager.aidl
index 54ca1e5..0e37c87 100644
--- a/core/java/android/content/pm/IPackageManager.aidl
+++ b/core/java/android/content/pm/IPackageManager.aidl
@@ -214,6 +214,8 @@
@UnsupportedAppUsage
void setInstallerPackageName(in String targetPackage, in String installerPackageName);
+ void relinquishUpdateOwnership(in String targetPackage);
+
void setApplicationCategoryHint(String packageName, int categoryHint, String callerPackageName);
/** @deprecated rawr, don't call AIDL methods directly! */
diff --git a/core/java/android/content/pm/InstallSourceInfo.java b/core/java/android/content/pm/InstallSourceInfo.java
index 88f1a16..67123e8 100644
--- a/core/java/android/content/pm/InstallSourceInfo.java
+++ b/core/java/android/content/pm/InstallSourceInfo.java
@@ -35,6 +35,8 @@
@Nullable private final String mInstallingPackageName;
+ @Nullable private final String mUpdateOwnerPackageName;
+
@Nullable private final int mPackageSource;
/** @hide */
@@ -42,18 +44,20 @@
@Nullable SigningInfo initiatingPackageSigningInfo,
@Nullable String originatingPackageName, @Nullable String installingPackageName) {
this(initiatingPackageName, initiatingPackageSigningInfo, originatingPackageName,
- installingPackageName, PackageInstaller.PACKAGE_SOURCE_UNSPECIFIED);
+ installingPackageName, null /* updateOwnerPackageName */,
+ PackageInstaller.PACKAGE_SOURCE_UNSPECIFIED);
}
/** @hide */
public InstallSourceInfo(@Nullable String initiatingPackageName,
@Nullable SigningInfo initiatingPackageSigningInfo,
@Nullable String originatingPackageName, @Nullable String installingPackageName,
- int packageSource) {
+ @Nullable String updateOwnerPackageName, int packageSource) {
mInitiatingPackageName = initiatingPackageName;
mInitiatingPackageSigningInfo = initiatingPackageSigningInfo;
mOriginatingPackageName = originatingPackageName;
mInstallingPackageName = installingPackageName;
+ mUpdateOwnerPackageName = updateOwnerPackageName;
mPackageSource = packageSource;
}
@@ -69,6 +73,7 @@
dest.writeParcelable(mInitiatingPackageSigningInfo, flags);
dest.writeString(mOriginatingPackageName);
dest.writeString(mInstallingPackageName);
+ dest.writeString8(mUpdateOwnerPackageName);
dest.writeInt(mPackageSource);
}
@@ -77,6 +82,7 @@
mInitiatingPackageSigningInfo = source.readParcelable(SigningInfo.class.getClassLoader(), android.content.pm.SigningInfo.class);
mOriginatingPackageName = source.readString();
mInstallingPackageName = source.readString();
+ mUpdateOwnerPackageName = source.readString8();
mPackageSource = source.readInt();
}
@@ -137,6 +143,21 @@
}
/**
+ * The name of the package that is the update owner, or null if not available.
+ *
+ * This indicates the update ownership enforcement is enabled for this app,
+ * and which package is the update owner.
+ *
+ * Returns null if the update ownership enforcement is disabled for the app.
+ *
+ * @see PackageInstaller.SessionParams#setRequestUpdateOwnership
+ */
+ @Nullable
+ public String getUpdateOwnerPackageName() {
+ return mUpdateOwnerPackageName;
+ }
+
+ /**
* Information about the package source when installer installed this app.
*/
public @PackageInstaller.PackageSourceType int getPackageSource() {
diff --git a/core/java/android/content/pm/PackageInstaller.java b/core/java/android/content/pm/PackageInstaller.java
index 703a9252..df1340d 100644
--- a/core/java/android/content/pm/PackageInstaller.java
+++ b/core/java/android/content/pm/PackageInstaller.java
@@ -44,8 +44,11 @@
import android.annotation.SystemApi;
import android.annotation.TestApi;
import android.app.ActivityManager;
+import android.app.ActivityThread;
import android.app.AppGlobals;
import android.compat.annotation.UnsupportedAppUsage;
+import android.content.IIntentReceiver;
+import android.content.IIntentSender;
import android.content.Intent;
import android.content.IntentSender;
import android.content.pm.PackageManager.DeleteFlags;
@@ -59,9 +62,11 @@
import android.icu.util.ULocale;
import android.net.Uri;
import android.os.Build;
+import android.os.Bundle;
import android.os.FileBridge;
import android.os.Handler;
import android.os.HandlerExecutor;
+import android.os.IBinder;
import android.os.Parcel;
import android.os.ParcelFileDescriptor;
import android.os.Parcelable;
@@ -226,8 +231,8 @@
* {@link #STATUS_PENDING_USER_ACTION}, {@link #STATUS_SUCCESS},
* {@link #STATUS_FAILURE}, {@link #STATUS_FAILURE_ABORTED},
* {@link #STATUS_FAILURE_BLOCKED}, {@link #STATUS_FAILURE_CONFLICT},
- * {@link #STATUS_FAILURE_INCOMPATIBLE}, {@link #STATUS_FAILURE_INVALID}, or
- * {@link #STATUS_FAILURE_STORAGE}.
+ * {@link #STATUS_FAILURE_INCOMPATIBLE}, {@link #STATUS_FAILURE_INVALID},
+ * {@link #STATUS_FAILURE_STORAGE}, or {@link #STATUS_FAILURE_TIMEOUT}.
* <p>
* More information about a status may be available through additional
* extras; see the individual status documentation for details.
@@ -441,6 +446,13 @@
public static final int STATUS_FAILURE_INCOMPATIBLE = 7;
/**
+ * The operation failed because it didn't complete within the specified timeout.
+ *
+ * @see #EXTRA_STATUS_MESSAGE
+ */
+ public static final int STATUS_FAILURE_TIMEOUT = 8;
+
+ /**
* Default value, non-streaming installation session.
*
* @see #EXTRA_DATA_LOADER_TYPE
@@ -544,6 +556,46 @@
@Retention(RetentionPolicy.SOURCE)
@interface PackageSourceType{}
+ /**
+ * Indicate the user intervention is required when the installer attempts to commit the session.
+ * This is the default case.
+ *
+ * @hide
+ */
+ @SystemApi
+ public static final int REASON_CONFIRM_PACKAGE_CHANGE = 0;
+
+ /**
+ * Indicate the user intervention is required because the update ownership enforcement is
+ * enabled, and the update owner will change.
+ *
+ * @see PackageInstaller.SessionParams#setRequestUpdateOwnership
+ * @see InstallSourceInfo#getUpdateOwnerPackageName
+ * @hide
+ */
+ @SystemApi
+ public static final int REASON_OWNERSHIP_CHANGED = 1;
+
+ /**
+ * Indicate the user intervention is required because the update ownership enforcement is
+ * enabled, and remind the update owner will retain.
+ *
+ * @see PackageInstaller.SessionParams#setRequestUpdateOwnership
+ * @see InstallSourceInfo#getUpdateOwnerPackageName
+ * @hide
+ */
+ @SystemApi
+ public static final int REASON_REMIND_OWNERSHIP = 2;
+
+ /** @hide */
+ @IntDef(prefix = { "REASON_" }, value = {
+ REASON_CONFIRM_PACKAGE_CHANGE,
+ REASON_OWNERSHIP_CHANGED,
+ REASON_REMIND_OWNERSHIP,
+ })
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface UserActionReason {}
+
/** Default set of checksums - includes all available checksums.
* @see Session#requestChecksums */
private static final int DEFAULT_CHECKSUMS =
@@ -976,6 +1028,61 @@
}
/**
+ * Commit the session when all constraints are satisfied. This is a convenient method to
+ * combine {@link #waitForInstallConstraints(List, InstallConstraints, IntentSender, long)}
+ * and {@link Session#commit(IntentSender)}.
+ * <p>
+ * Once this method is called, the session is sealed and no additional mutations
+ * may be performed on the session. In the case of timeout, you may commit the
+ * session again using this method or {@link Session#commit(IntentSender)} for retries.
+ *
+ * @param statusReceiver Called when the state of the session changes. Intents
+ * sent to this receiver contain {@link #EXTRA_STATUS}.
+ * Refer to the individual status codes on how to handle them.
+ * @param constraints The requirements to satisfy before committing the session.
+ * @param timeoutMillis The maximum time to wait, in milliseconds until the
+ * constraints are satisfied. The caller will be notified via
+ * {@code statusReceiver} if timeout happens before commit.
+ */
+ public void commitSessionAfterInstallConstraintsAreMet(int sessionId,
+ @NonNull IntentSender statusReceiver, @NonNull InstallConstraints constraints,
+ @DurationMillisLong long timeoutMillis) {
+ try {
+ var session = mInstaller.openSession(sessionId);
+ session.seal();
+ var packageNames = session.fetchPackageNames();
+ var intentSender = new IntentSender((IIntentSender) new IIntentSender.Stub() {
+ @Override
+ public void send(int code, Intent intent, String resolvedType,
+ IBinder allowlistToken, IIntentReceiver finishedReceiver,
+ String requiredPermission, Bundle options) {
+ var result = intent.getParcelableExtra(
+ PackageInstaller.EXTRA_INSTALL_CONSTRAINTS_RESULT,
+ InstallConstraintsResult.class);
+ try {
+ if (result.isAllConstraintsSatisfied()) {
+ session.commit(statusReceiver, false);
+ } else {
+ // timeout
+ final Intent fillIn = new Intent();
+ fillIn.putExtra(PackageInstaller.EXTRA_SESSION_ID, sessionId);
+ fillIn.putExtra(PackageInstaller.EXTRA_STATUS, STATUS_FAILURE_TIMEOUT);
+ fillIn.putExtra(PackageInstaller.EXTRA_STATUS_MESSAGE,
+ "Install constraints not satisfied within timeout");
+ statusReceiver.sendIntent(
+ ActivityThread.currentApplication(), 0, fillIn, null, null);
+ }
+ } catch (Exception ignore) {
+ }
+ }
+ });
+ waitForInstallConstraints(packageNames, constraints, intentSender, timeoutMillis);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
+ /**
* Events for observing session lifecycle.
* <p>
* A typical session lifecycle looks like this:
@@ -1910,6 +2017,20 @@
throw e.rethrowFromSystemServer();
}
}
+
+ /**
+ * @return {@code true} if the installer requested the update ownership enforcement
+ * for the packages in this session.
+ *
+ * @see PackageInstaller.SessionParams#setRequestUpdateOwnership
+ */
+ public boolean isRequestUpdateOwnership() {
+ try {
+ return mSession.isRequestUpdateOwnership();
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
}
/**
@@ -2672,9 +2793,18 @@
* Android S ({@link android.os.Build.VERSION_CODES#S API 31})</li>
* </ul>
* </li>
- * <li>The installer is the {@link InstallSourceInfo#getInstallingPackageName()
- * installer of record} of an existing version of the app (in other words, this install
- * session is an app update) or the installer is updating itself.</li>
+ * <li>The installer is:
+ * <ul>
+ * <li>The {@link InstallSourceInfo#getUpdateOwnerPackageName() update owner}
+ * of an existing version of the app (in other words, this install session is
+ * an app update) if the update ownership enforcement is enabled.</li>
+ * <li>The {@link InstallSourceInfo#getInstallingPackageName() installer of
+ * record} of an existing version of the app (in other words, this install
+ * session is an app update) if the update ownership enforcement isn't
+ * enabled.</li>
+ * <li>Updating itself.</li>
+ * </ul>
+ * </li>>
* <li>The installer declares the
* {@link android.Manifest.permission#UPDATE_PACKAGES_WITHOUT_USER_ACTION
* UPDATE_PACKAGES_WITHOUT_USER_ACTION} permission.</li>
@@ -2713,6 +2843,30 @@
this.keepApplicationEnabledSetting = true;
}
+ /**
+ * Optionally indicate whether the package being installed needs the update ownership
+ * enforcement. Once the update ownership enforcement is enabled, the other installers
+ * will need the user action to update the package even if the installers have been
+ * granted the {@link android.Manifest.permission#INSTALL_PACKAGES INSTALL_PACKAGES}
+ * permission. Default to {@code false}.
+ *
+ * The update ownership enforcement can only be enabled on initial installation. Set
+ * this to {@code true} on package update indicates the installer package wants to be
+ * the update owner if the update ownership enforcement has enabled.
+ *
+ * Note: To enable the update ownership enforcement, the installer must have the
+ * {@link android.Manifest.permission#ENFORCE_UPDATE_OWNERSHIP ENFORCE_UPDATE_OWNERSHIP}
+ * permission.
+ */
+ @RequiresPermission(Manifest.permission.ENFORCE_UPDATE_OWNERSHIP)
+ public void setRequestUpdateOwnership(boolean enable) {
+ if (enable) {
+ this.installFlags |= PackageManager.INSTALL_REQUEST_UPDATE_OWNERSHIP;
+ } else {
+ this.installFlags &= ~PackageManager.INSTALL_REQUEST_UPDATE_OWNERSHIP;
+ }
+ }
+
/** {@hide} */
public void dump(IndentingPrintWriter pw) {
pw.printPair("mode", mode);
@@ -2987,6 +3141,9 @@
/** @hide */
public boolean keepApplicationEnabledSetting;
+ /** @hide */
+ public int pendingUserActionReason;
+
/** {@hide} */
@UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
public SessionInfo() {
@@ -3041,6 +3198,7 @@
installerUid = source.readInt();
packageSource = source.readInt();
keepApplicationEnabledSetting = source.readBoolean();
+ pendingUserActionReason = source.readInt();
}
/**
@@ -3585,6 +3743,25 @@
return isPreapprovalRequested;
}
+ /**
+ * @return {@code true} if the installer requested the update ownership enforcement
+ * for the packages in this session.
+ *
+ * @see PackageInstaller.SessionParams#setRequestUpdateOwnership
+ */
+ public boolean isRequestUpdateOwnership() {
+ return (installFlags & PackageManager.INSTALL_REQUEST_UPDATE_OWNERSHIP) != 0;
+ }
+
+ /**
+ * Return the reason for requiring the user action.
+ * @hide
+ */
+ @SystemApi
+ public @UserActionReason int getPendingUserActionReason() {
+ return pendingUserActionReason;
+ }
+
@Override
public int describeContents() {
return 0;
@@ -3635,6 +3812,7 @@
dest.writeInt(installerUid);
dest.writeInt(packageSource);
dest.writeBoolean(keepApplicationEnabledSetting);
+ dest.writeInt(pendingUserActionReason);
}
public static final Parcelable.Creator<SessionInfo>
diff --git a/core/java/android/content/pm/PackageManager.java b/core/java/android/content/pm/PackageManager.java
index 4ad657e..900454d 100644
--- a/core/java/android/content/pm/PackageManager.java
+++ b/core/java/android/content/pm/PackageManager.java
@@ -1355,6 +1355,7 @@
INSTALL_ENABLE_ROLLBACK,
INSTALL_ALLOW_DOWNGRADE,
INSTALL_STAGED,
+ INSTALL_REQUEST_UPDATE_OWNERSHIP,
})
@Retention(RetentionPolicy.SOURCE)
public @interface InstallFlags {}
@@ -1545,6 +1546,21 @@
*/
public static final int INSTALL_DISABLE_ALLOWED_APEX_UPDATE_CHECK = 0x00800000;
+ /**
+ * Flag parameter for {@link #installPackage} to bypass the low targer sdk version block
+ * for this install.
+ *
+ * @hide
+ */
+ public static final int INSTALL_BYPASS_LOW_TARGET_SDK_BLOCK = 0x01000000;
+
+ /**
+ * Flag parameter for {@link PackageInstaller.SessionParams} to indicate that the
+ * update ownership enforcement is requested.
+ * @hide
+ */
+ public static final int INSTALL_REQUEST_UPDATE_OWNERSHIP = 1 << 25;
+
/** @hide */
@IntDef(flag = true, value = {
DONT_KILL_APP,
@@ -2233,6 +2249,15 @@
*/
public static final int INSTALL_FAILED_PRE_APPROVAL_NOT_AVAILABLE = -129;
+ /**
+ * Installation return code: this is passed in the {@link PackageInstaller#EXTRA_LEGACY_STATUS}
+ * if the new package declares bad certificate digest for a shared library in the package
+ * manifest.
+ *
+ * @hide
+ */
+ public static final int INSTALL_FAILED_SHARED_LIBRARY_BAD_CERTIFICATE_DIGEST = -130;
+
/** @hide */
@IntDef(flag = true, prefix = { "DELETE_" }, value = {
DELETE_KEEP_DATA,
@@ -9681,6 +9706,8 @@
case INSTALL_FAILED_WRONG_INSTALLED_VERSION: return "INSTALL_FAILED_WRONG_INSTALLED_VERSION";
case INSTALL_FAILED_PROCESS_NOT_DEFINED: return "INSTALL_FAILED_PROCESS_NOT_DEFINED";
case INSTALL_FAILED_SESSION_INVALID: return "INSTALL_FAILED_SESSION_INVALID";
+ case INSTALL_FAILED_SHARED_LIBRARY_BAD_CERTIFICATE_DIGEST:
+ return "INSTALL_FAILED_SHARED_LIBRARY_BAD_CERTIFICATE_DIGEST";
default: return Integer.toString(status);
}
}
@@ -10850,4 +10877,16 @@
throw new UnsupportedOperationException(
"isShowNewAppInstalledNotificationEnabled not implemented in subclass");
}
+
+ /**
+ * Attempt to relinquish the update ownership of the given package. Only the current
+ * update owner of the given package can use this API or a SecurityException will be
+ * thrown.
+ *
+ * @param targetPackage The installed package whose update owner will be changed.
+ */
+ public void relinquishUpdateOwnership(@NonNull String targetPackage) {
+ throw new UnsupportedOperationException(
+ "relinquishUpdateOwnership not implemented in subclass");
+ }
}
diff --git a/core/java/android/content/pm/PermissionMethod.java b/core/java/android/content/pm/PermissionMethod.java
deleted file mode 100644
index 647c696..0000000
--- a/core/java/android/content/pm/PermissionMethod.java
+++ /dev/null
@@ -1,52 +0,0 @@
-/*
- * 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 android.content.pm;
-
-import static java.lang.annotation.ElementType.METHOD;
-import static java.lang.annotation.RetentionPolicy.CLASS;
-
-import java.lang.annotation.Retention;
-import java.lang.annotation.Target;
-
-/**
- * Documents that the subject method's job is to look
- * up whether the provided or calling uid/pid has the requested permission.
- *
- * <p>Methods should either return `void`, but potentially throw {@link SecurityException},
- * or return {@link android.content.pm.PackageManager.PermissionResult} `int`.
- *
- * @hide
- */
-@Retention(CLASS)
-@Target({METHOD})
-public @interface PermissionMethod {
- /**
- * Hard-coded list of permissions checked by this method
- */
- @PermissionName String[] value() default {};
- /**
- * If true, the check passes if the caller
- * has any ONE of the supplied permissions
- */
- boolean anyOf() default false;
- /**
- * Signifies that the permission check passes if
- * the calling process OR the current process has
- * the permission
- */
- boolean orSelf() default false;
-}
diff --git a/core/java/android/content/pm/PermissionName.java b/core/java/android/content/pm/PermissionName.java
deleted file mode 100644
index 719e13b..0000000
--- a/core/java/android/content/pm/PermissionName.java
+++ /dev/null
@@ -1,35 +0,0 @@
-/*
- * 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 android.content.pm;
-
-import static java.lang.annotation.ElementType.FIELD;
-import static java.lang.annotation.ElementType.LOCAL_VARIABLE;
-import static java.lang.annotation.ElementType.METHOD;
-import static java.lang.annotation.ElementType.PARAMETER;
-import static java.lang.annotation.RetentionPolicy.CLASS;
-
-import java.lang.annotation.Retention;
-import java.lang.annotation.Target;
-
-/**
- * Denotes that the annotated {@link String} represents a permission name.
- *
- * @hide
- */
-@Retention(CLASS)
-@Target({PARAMETER, METHOD, LOCAL_VARIABLE, FIELD})
-public @interface PermissionName {}
diff --git a/core/java/android/content/pm/ServiceInfo.java b/core/java/android/content/pm/ServiceInfo.java
index 4ade8a8..4e2acc0 100644
--- a/core/java/android/content/pm/ServiceInfo.java
+++ b/core/java/android/content/pm/ServiceInfo.java
@@ -133,20 +133,15 @@
* Data(photo, file, account) upload/download, backup/restore, import/export, fetch,
* transfer over network between device and cloud.
*
- * <p>Apps targeting API level {@link android.os.Build.VERSION_CODES#UPSIDE_DOWN_CAKE} and
- * later should NOT use this type:
- * calling {@link android.app.Service#startForeground(int, android.app.Notification, int)} with
- * this type on devices running {@link android.os.Build.VERSION_CODES#UPSIDE_DOWN_CAKE} is still
- * allowed, but calling it with this type on devices running future platform releases may get a
- * {@link android.app.InvalidForegroundServiceTypeException}.</p>
- *
- * @deprecated Use {@link android.app.job.JobInfo.Builder} data transfer APIs instead.
+ * <p class="note">
+ * Use the {@link android.app.job.JobInfo.Builder#setDataTransfer} API for data transfers
+ * that can be deferred until conditions are ideal for the app or device.
+ * </p>
*/
@RequiresPermission(
value = Manifest.permission.FOREGROUND_SERVICE_DATA_SYNC,
conditional = true
)
- @Deprecated
public static final int FOREGROUND_SERVICE_TYPE_DATA_SYNC = 1 << 0;
/**
diff --git a/core/java/android/content/pm/UserProperties.java b/core/java/android/content/pm/UserProperties.java
index 7f0f44b..51662af 100644
--- a/core/java/android/content/pm/UserProperties.java
+++ b/core/java/android/content/pm/UserProperties.java
@@ -50,6 +50,8 @@
"updateCrossProfileIntentFiltersOnOTA";
private static final String ATTR_CROSS_PROFILE_INTENT_FILTER_ACCESS_CONTROL =
"crossProfileIntentFilterAccessControl";
+ private static final String ATTR_CROSS_PROFILE_INTENT_RESOLUTION_STRATEGY =
+ "crossProfileIntentResolutionStrategy";
/** Index values of each property (to indicate whether they are present in this object). */
@IntDef(prefix = "INDEX_", value = {
@@ -59,7 +61,8 @@
INDEX_INHERIT_DEVICE_POLICY,
INDEX_USE_PARENTS_CONTACTS,
INDEX_UPDATE_CROSS_PROFILE_INTENT_FILTERS_ON_OTA,
- INDEX_CROSS_PROFILE_INTENT_FILTER_ACCESS_CONTROL
+ INDEX_CROSS_PROFILE_INTENT_FILTER_ACCESS_CONTROL,
+ INDEX_CROSS_PROFILE_INTENT_RESOLUTION_STRATEGY
})
@Retention(RetentionPolicy.SOURCE)
private @interface PropertyIndex {
@@ -71,6 +74,7 @@
private static final int INDEX_USE_PARENTS_CONTACTS = 4;
private static final int INDEX_UPDATE_CROSS_PROFILE_INTENT_FILTERS_ON_OTA = 5;
private static final int INDEX_CROSS_PROFILE_INTENT_FILTER_ACCESS_CONTROL = 6;
+ private static final int INDEX_CROSS_PROFILE_INTENT_RESOLUTION_STRATEGY = 7;
/** A bit set, mapping each PropertyIndex to whether it is present (1) or absent (0). */
private long mPropertiesPresent = 0;
@@ -219,6 +223,39 @@
public static final int CROSS_PROFILE_INTENT_FILTER_ACCESS_LEVEL_SYSTEM_ADD_ONLY = 20;
/**
+ * Possible values for cross profile intent resolution strategy.
+ *
+ * @hide
+ */
+ @IntDef(prefix = {"CROSS_PROFILE_INTENT_RESOLUTION_STRATEGY_"}, value = {
+ CROSS_PROFILE_INTENT_RESOLUTION_STRATEGY_DEFAULT,
+ CROSS_PROFILE_INTENT_RESOLUTION_STRATEGY_NO_FILTERING
+ })
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface CrossProfileIntentResolutionStrategy {
+ }
+
+ /**
+ * Signifies to use {@link DefaultCrossProfileResolver} strategy, which
+ * check if it needs to skip the initiating profile, resolves intent in target profile.
+ * {@link DefaultCrossProfileResolver} also filters the {@link ResolveInfo} after intent
+ * resolution based on their domain approval level
+ *
+ * @hide
+ */
+ public static final int CROSS_PROFILE_INTENT_RESOLUTION_STRATEGY_DEFAULT = 0;
+
+ /**
+ * Signifies that there is no need to filter {@link ResolveInfo} after cross profile intent
+ * resolution across. This strategy is for profile acting transparent to end-user and resolves
+ * all allowed intent without giving any profile priority.
+ *
+ * @hide
+ */
+ public static final int CROSS_PROFILE_INTENT_RESOLUTION_STRATEGY_NO_FILTERING = 1;
+
+
+ /**
* Creates a UserProperties (intended for the SystemServer) that stores a reference to the given
* default properties, which it uses for any property not subsequently set.
* @hide
@@ -255,6 +292,7 @@
setUpdateCrossProfileIntentFiltersOnOTA(orig.getUpdateCrossProfileIntentFiltersOnOTA());
setCrossProfileIntentFilterAccessControl(
orig.getCrossProfileIntentFilterAccessControl());
+ setCrossProfileIntentResolutionStrategy(orig.getCrossProfileIntentResolutionStrategy());
}
if (hasManagePermission) {
// Add items that require MANAGE_USERS or stronger.
@@ -466,6 +504,36 @@
}
private @CrossProfileIntentFilterAccessControlLevel int mCrossProfileIntentFilterAccessControl;
+ /**
+ * Returns the user's {@link CrossProfileIntentResolutionStrategy}. If not explicitly
+ * configured, default value is {@link #CROSS_PROFILE_INTENT_RESOLUTION_STRATEGY_DEFAULT}.
+ * @return user's {@link CrossProfileIntentResolutionStrategy}.
+ *
+ * @hide
+ */
+ public @CrossProfileIntentResolutionStrategy int getCrossProfileIntentResolutionStrategy() {
+ if (isPresent(INDEX_CROSS_PROFILE_INTENT_RESOLUTION_STRATEGY)) {
+ return mCrossProfileIntentResolutionStrategy;
+ }
+ if (mDefaultProperties != null) {
+ return mDefaultProperties.mCrossProfileIntentResolutionStrategy;
+ }
+ throw new SecurityException("You don't have permission to query "
+ + "crossProfileIntentResolutionStrategy");
+ }
+ /**
+ * Sets {@link CrossProfileIntentResolutionStrategy} for the user.
+ * @param val resolution strategy for user
+ * @hide
+ */
+ public void setCrossProfileIntentResolutionStrategy(
+ @CrossProfileIntentResolutionStrategy int val) {
+ this.mCrossProfileIntentResolutionStrategy = val;
+ setPresent(INDEX_CROSS_PROFILE_INTENT_RESOLUTION_STRATEGY);
+ }
+ private @CrossProfileIntentResolutionStrategy int mCrossProfileIntentResolutionStrategy;
+
+
@Override
public String toString() {
// Please print in increasing order of PropertyIndex.
@@ -480,6 +548,8 @@
+ getUpdateCrossProfileIntentFiltersOnOTA()
+ ", mCrossProfileIntentFilterAccessControl="
+ getCrossProfileIntentFilterAccessControl()
+ + ", mCrossProfileIntentResolutionStrategy="
+ + getCrossProfileIntentResolutionStrategy()
+ "}";
}
@@ -500,6 +570,8 @@
+ getUpdateCrossProfileIntentFiltersOnOTA());
pw.println(prefix + " mCrossProfileIntentFilterAccessControl="
+ getCrossProfileIntentFilterAccessControl());
+ pw.println(prefix + " mCrossProfileIntentResolutionStrategy="
+ + getCrossProfileIntentResolutionStrategy());
}
/**
@@ -554,6 +626,9 @@
case ATTR_CROSS_PROFILE_INTENT_FILTER_ACCESS_CONTROL:
setCrossProfileIntentFilterAccessControl(parser.getAttributeInt(i));
break;
+ case ATTR_CROSS_PROFILE_INTENT_RESOLUTION_STRATEGY:
+ setCrossProfileIntentResolutionStrategy(parser.getAttributeInt(i));
+ break;
default:
Slog.w(LOG_TAG, "Skipping unknown property " + attributeName);
}
@@ -597,6 +672,10 @@
serializer.attributeInt(null, ATTR_CROSS_PROFILE_INTENT_FILTER_ACCESS_CONTROL,
mCrossProfileIntentFilterAccessControl);
}
+ if (isPresent(INDEX_CROSS_PROFILE_INTENT_RESOLUTION_STRATEGY)) {
+ serializer.attributeInt(null, ATTR_CROSS_PROFILE_INTENT_RESOLUTION_STRATEGY,
+ mCrossProfileIntentResolutionStrategy);
+ }
}
// For use only with an object that has already had any permission-lacking fields stripped out.
@@ -610,6 +689,7 @@
dest.writeBoolean(mUseParentsContacts);
dest.writeBoolean(mUpdateCrossProfileIntentFiltersOnOTA);
dest.writeInt(mCrossProfileIntentFilterAccessControl);
+ dest.writeInt(mCrossProfileIntentResolutionStrategy);
}
/**
@@ -627,6 +707,7 @@
mUseParentsContacts = source.readBoolean();
mUpdateCrossProfileIntentFiltersOnOTA = source.readBoolean();
mCrossProfileIntentFilterAccessControl = source.readInt();
+ mCrossProfileIntentResolutionStrategy = source.readInt();
}
@Override
@@ -660,6 +741,8 @@
private @CrossProfileIntentFilterAccessControlLevel int
mCrossProfileIntentFilterAccessControl =
CROSS_PROFILE_INTENT_FILTER_ACCESS_LEVEL_ALL;
+ private @CrossProfileIntentResolutionStrategy int mCrossProfileIntentResolutionStrategy =
+ CROSS_PROFILE_INTENT_RESOLUTION_STRATEGY_DEFAULT;
public Builder setShowInLauncher(@ShowInLauncher int showInLauncher) {
mShowInLauncher = showInLauncher;
@@ -704,6 +787,13 @@
return this;
}
+ /** Sets the value for {@link #mCrossProfileIntentResolutionStrategy} */
+ public Builder setCrossProfileIntentResolutionStrategy(@CrossProfileIntentResolutionStrategy
+ int crossProfileIntentResolutionStrategy) {
+ mCrossProfileIntentResolutionStrategy = crossProfileIntentResolutionStrategy;
+ return this;
+ }
+
/** Builds a UserProperties object with *all* values populated. */
public UserProperties build() {
return new UserProperties(
@@ -713,7 +803,8 @@
mInheritDevicePolicy,
mUseParentsContacts,
mUpdateCrossProfileIntentFiltersOnOTA,
- mCrossProfileIntentFilterAccessControl);
+ mCrossProfileIntentFilterAccessControl,
+ mCrossProfileIntentResolutionStrategy);
}
} // end Builder
@@ -724,7 +815,8 @@
@ShowInSettings int showInSettings,
@InheritDevicePolicy int inheritDevicePolicy,
boolean useParentsContacts, boolean updateCrossProfileIntentFiltersOnOTA,
- @CrossProfileIntentFilterAccessControlLevel int crossProfileIntentFilterAccessControl) {
+ @CrossProfileIntentFilterAccessControlLevel int crossProfileIntentFilterAccessControl,
+ @CrossProfileIntentResolutionStrategy int crossProfileIntentResolutionStrategy) {
mDefaultProperties = null;
setShowInLauncher(showInLauncher);
@@ -734,5 +826,6 @@
setUseParentsContacts(useParentsContacts);
setUpdateCrossProfileIntentFiltersOnOTA(updateCrossProfileIntentFiltersOnOTA);
setCrossProfileIntentFilterAccessControl(crossProfileIntentFilterAccessControl);
+ setCrossProfileIntentResolutionStrategy(crossProfileIntentResolutionStrategy);
}
}
diff --git a/core/java/android/credentials/ClearCredentialStateException.java b/core/java/android/credentials/ClearCredentialStateException.java
index c518461..78fe203 100644
--- a/core/java/android/credentials/ClearCredentialStateException.java
+++ b/core/java/android/credentials/ClearCredentialStateException.java
@@ -31,6 +31,12 @@
* CancellationSignal, Executor, OutcomeReceiver)} operation.
*/
public class ClearCredentialStateException extends Exception {
+ /**
+ * The error type value for when the given operation failed due to an unknown reason.
+ */
+ @NonNull
+ public static final String TYPE_UNKNOWN =
+ "android.credentials.ClearCredentialStateException.TYPE_UNKNOWN";
@NonNull
private final String mType;
diff --git a/core/java/android/credentials/CreateCredentialException.java b/core/java/android/credentials/CreateCredentialException.java
index cb32690..fefa60a 100644
--- a/core/java/android/credentials/CreateCredentialException.java
+++ b/core/java/android/credentials/CreateCredentialException.java
@@ -33,6 +33,13 @@
*/
public class CreateCredentialException extends Exception {
/**
+ * The error type value for when the given operation failed due to an unknown reason.
+ */
+ @NonNull
+ public static final String TYPE_UNKNOWN =
+ "android.credentials.CreateCredentialException.TYPE_UNKNOWN";
+
+ /**
* The error type value for when no credential is available for the given {@link
* CredentialManager#executeCreateCredential(CreateCredentialRequest, Activity,
* CancellationSignal, Executor, OutcomeReceiver)} request.
@@ -40,6 +47,22 @@
@NonNull
public static final String TYPE_NO_CREDENTIAL =
"android.credentials.CreateCredentialException.TYPE_NO_CREDENTIAL";
+ /**
+ * The error type value for when the user intentionally cancelled the request.
+ *
+ * <p>This is a strong indicator that your app should refrain from making the same api call for
+ * a certain amount of time to provide a better user experience.
+ */
+ @NonNull
+ public static final String TYPE_USER_CANCELED =
+ "android.credentials.CreateCredentialException.TYPE_USER_CANCELED";
+ /**
+ * The error type value for when the given operation failed due to internal interruption.
+ * Retrying the same operation should fix the error.
+ */
+ @NonNull
+ public static final String TYPE_INTERRUPTED =
+ "android.credentials.CreateCredentialException.TYPE_INTERRUPTED";
@NonNull
private final String mType;
diff --git a/core/java/android/credentials/GetCredentialException.java b/core/java/android/credentials/GetCredentialException.java
index 5d6e4df..478afff 100644
--- a/core/java/android/credentials/GetCredentialException.java
+++ b/core/java/android/credentials/GetCredentialException.java
@@ -33,6 +33,13 @@
*/
public class GetCredentialException extends Exception {
/**
+ * The error type value for when the given operation failed due to an unknown reason.
+ */
+ @NonNull
+ public static final String TYPE_UNKNOWN =
+ "android.credentials.GetCredentialException.TYPE_UNKNOWN";
+
+ /**
* The error type value for when no credential is found available for the given {@link
* CredentialManager#executeGetCredential(GetCredentialRequest, Activity, CancellationSignal,
* Executor, OutcomeReceiver)} request.
@@ -40,6 +47,22 @@
@NonNull
public static final String TYPE_NO_CREDENTIAL =
"android.credentials.GetCredentialException.TYPE_NO_CREDENTIAL";
+ /**
+ * The error type value for when the user intentionally cancelled the request.
+ *
+ * <p>This is a strong indicator that your app should refrain from making the same api call for
+ * a certain amount of time to provide a better user experience.
+ */
+ @NonNull
+ public static final String TYPE_USER_CANCELED =
+ "android.credentials.GetCredentialException.TYPE_USER_CANCELED";
+ /**
+ * The error type value for when the given operation failed due to internal interruption.
+ * Retrying the same operation should fix the error.
+ */
+ @NonNull
+ public static final String TYPE_INTERRUPTED =
+ "android.credentials.GetCredentialException.TYPE_INTERRUPTED";
@NonNull
private final String mType;
diff --git a/core/java/android/credentials/GetCredentialResponse.java b/core/java/android/credentials/GetCredentialResponse.java
index 576da8b..4f8b026 100644
--- a/core/java/android/credentials/GetCredentialResponse.java
+++ b/core/java/android/credentials/GetCredentialResponse.java
@@ -19,7 +19,6 @@
import static java.util.Objects.requireNonNull;
import android.annotation.NonNull;
-import android.annotation.Nullable;
import android.os.Parcel;
import android.os.Parcelable;
@@ -33,14 +32,14 @@
/**
* The credential that can be used to authenticate the user.
*/
- @Nullable
+ @NonNull
private final Credential mCredential;
/**
* Returns the credential that can be used to authenticate the user, or {@code null} if no
* credential is available.
*/
- @Nullable
+ @NonNull
public Credential getCredential() {
return mCredential;
}
@@ -69,13 +68,6 @@
mCredential = requireNonNull(credential, "credential must not be null");
}
- /**
- * Constructs a {@link GetCredentialResponse}.
- */
- public GetCredentialResponse() {
- mCredential = null;
- }
-
private GetCredentialResponse(@NonNull Parcel in) {
Credential credential = in.readTypedObject(Credential.CREATOR);
mCredential = credential;
diff --git a/core/java/android/credentials/ui/Entry.java b/core/java/android/credentials/ui/Entry.java
index 9f2edae..37a5724 100644
--- a/core/java/android/credentials/ui/Entry.java
+++ b/core/java/android/credentials/ui/Entry.java
@@ -88,6 +88,7 @@
/** Constructor to be used for an entry that requires a pending intent to be invoked
* when clicked.
*/
+ // TODO: Remove this constructor as it is no longer used
public Entry(@NonNull String key, @NonNull String subkey, @NonNull Slice slice,
@NonNull PendingIntent pendingIntent, @NonNull Intent intent) {
this(key, subkey, slice);
diff --git a/core/java/android/hardware/Camera.java b/core/java/android/hardware/Camera.java
index c716f319..81d6ba9 100644
--- a/core/java/android/hardware/Camera.java
+++ b/core/java/android/hardware/Camera.java
@@ -24,7 +24,6 @@
import android.annotation.SdkConstant.SdkConstantType;
import android.app.ActivityThread;
import android.app.AppOpsManager;
-import android.app.compat.CompatChanges;
import android.compat.annotation.UnsupportedAppUsage;
import android.content.Context;
import android.graphics.ImageFormat;
@@ -42,7 +41,6 @@
import android.os.Process;
import android.os.RemoteException;
import android.os.ServiceManager;
-import android.os.SystemProperties;
import android.renderscript.Allocation;
import android.renderscript.Element;
import android.renderscript.RSIllegalArgumentException;
@@ -279,14 +277,6 @@
*/
public native static int getNumberOfCameras();
- private static final boolean sLandscapeToPortrait =
- SystemProperties.getBoolean(CameraManager.LANDSCAPE_TO_PORTRAIT_PROP, false);
-
- private static boolean shouldOverrideToPortrait() {
- return CompatChanges.isChangeEnabled(CameraManager.OVERRIDE_FRONT_CAMERA_APP_COMPAT)
- && sLandscapeToPortrait;
- }
-
/**
* Returns the information about a particular camera.
* If {@link #getNumberOfCameras()} returns N, the valid id is 0 to N-1.
@@ -296,7 +286,8 @@
* low-level failure).
*/
public static void getCameraInfo(int cameraId, CameraInfo cameraInfo) {
- boolean overrideToPortrait = shouldOverrideToPortrait();
+ boolean overrideToPortrait = CameraManager.shouldOverrideToPortrait(
+ ActivityThread.currentApplication().getApplicationContext());
_getCameraInfo(cameraId, overrideToPortrait, cameraInfo);
IBinder b = ServiceManager.getService(Context.AUDIO_SERVICE);
@@ -493,7 +484,8 @@
mEventHandler = null;
}
- boolean overrideToPortrait = shouldOverrideToPortrait();
+ boolean overrideToPortrait = CameraManager.shouldOverrideToPortrait(
+ ActivityThread.currentApplication().getApplicationContext());
return native_setup(new WeakReference<Camera>(this), cameraId,
ActivityThread.currentOpPackageName(), overrideToPortrait);
}
diff --git a/core/java/android/hardware/OverlayProperties.java b/core/java/android/hardware/OverlayProperties.java
index 1ce1361..8bfc2f7 100644
--- a/core/java/android/hardware/OverlayProperties.java
+++ b/core/java/android/hardware/OverlayProperties.java
@@ -59,6 +59,16 @@
}
/**
+ * @return True if the device can support mixed colorspaces, false otherwise.
+ */
+ public boolean supportMixedColorSpaces() {
+ if (mNativeObject == 0) {
+ return false;
+ }
+ return nSupportMixedColorSpaces(mNativeObject);
+ }
+
+ /**
* Release the local reference.
*/
public void release() {
@@ -106,6 +116,7 @@
private static native long nGetDestructor();
private static native boolean nSupportFp16ForHdr(long nativeObject);
+ private static native boolean nSupportMixedColorSpaces(long nativeObject);
private static native void nWriteOverlayPropertiesToParcel(long nativeObject, Parcel dest);
private static native long nReadOverlayPropertiesFromParcel(Parcel in);
}
diff --git a/core/java/android/hardware/SensorManager.java b/core/java/android/hardware/SensorManager.java
index dec424c..6d8c4a9 100644
--- a/core/java/android/hardware/SensorManager.java
+++ b/core/java/android/hardware/SensorManager.java
@@ -16,6 +16,7 @@
package android.hardware;
+import android.annotation.Nullable;
import android.annotation.SystemApi;
import android.annotation.SystemService;
import android.compat.annotation.UnsupportedAppUsage;
@@ -496,7 +497,7 @@
* @see #getSensorList(int)
* @see Sensor
*/
- public Sensor getDefaultSensor(int type) {
+ public @Nullable Sensor getDefaultSensor(int type) {
// TODO: need to be smarter, for now, just return the 1st sensor
List<Sensor> l = getSensorList(type);
boolean wakeUpSensor = false;
@@ -544,7 +545,7 @@
* and the application has the necessary permissions, or null otherwise.
* @see Sensor#isWakeUpSensor()
*/
- public Sensor getDefaultSensor(int type, boolean wakeUp) {
+ public @Nullable Sensor getDefaultSensor(int type, boolean wakeUp) {
List<Sensor> l = getSensorList(type);
for (Sensor sensor : l) {
if (sensor.isWakeUpSensor() == wakeUp) {
diff --git a/core/java/android/hardware/camera2/CameraExtensionSession.java b/core/java/android/hardware/camera2/CameraExtensionSession.java
index 1542d61..21fead9 100644
--- a/core/java/android/hardware/camera2/CameraExtensionSession.java
+++ b/core/java/android/hardware/camera2/CameraExtensionSession.java
@@ -19,10 +19,7 @@
import android.annotation.IntRange;
import android.annotation.NonNull;
import android.annotation.Nullable;
-import android.hardware.camera2.impl.PublicKey;
-import android.hardware.camera2.utils.TypeReference;
-import android.util.Pair;
-import android.util.Range;
+import android.hardware.camera2.utils.HashCodeHelpers;
import java.util.concurrent.Executor;
@@ -434,14 +431,66 @@
}
/**
- * Return the realtime still {@link #capture} latency.
+ * Realtime calculated still {@link #capture} latency.
*
- * <p>The pair will be in milliseconds with the first value indicating the capture latency from
- * the {@link ExtensionCaptureCallback#onCaptureStarted} until
- * {@link ExtensionCaptureCallback#onCaptureProcessStarted}
- * and the second value containing the estimated post-processing latency from
- * {@link ExtensionCaptureCallback#onCaptureProcessStarted} until the processed frame returns
- * to the client.</p>
+ * @see #getRealtimeStillCaptureLatency()
+ */
+ public final static class StillCaptureLatency {
+ private final long mCaptureLatency, mProcessingLatency;
+
+ public StillCaptureLatency(long captureLatency, long processingLatency) {
+ mCaptureLatency = captureLatency;
+ mProcessingLatency = processingLatency;
+ }
+ /**
+ * Return the capture latency from
+ * {@link ExtensionCaptureCallback#onCaptureStarted} until
+ * {@link ExtensionCaptureCallback#onCaptureProcessStarted}.
+ *
+ * @return The realtime capture latency in milliseconds.
+ */
+ public long getCaptureLatency() {
+ return mCaptureLatency;
+ }
+
+ /**
+ * Return the estimated post-processing latency from
+ * {@link ExtensionCaptureCallback#onCaptureProcessStarted} until the processed frame
+ * returns to the client.
+ *
+ * @return returns post-processing latency in milliseconds
+ */
+ public long getProcessingLatency() {
+ return mProcessingLatency;
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) return true;
+ if (o == null || getClass() != o.getClass()) return false;
+
+ StillCaptureLatency latency = (StillCaptureLatency) o;
+
+ if (mCaptureLatency != latency.mCaptureLatency) return false;
+ if (mProcessingLatency != latency.mProcessingLatency) return false;
+
+ return true;
+ }
+
+ @Override
+ public int hashCode() {
+ return HashCodeHelpers.hashCode(mCaptureLatency, mProcessingLatency);
+ }
+
+ @Override
+ public String toString() {
+ return "StillCaptureLatency(processingLatency:" + mProcessingLatency +
+ ", captureLatency: " + mCaptureLatency + ")";
+ }
+ }
+
+ /**
+ * Return the realtime still {@link #capture} latency.
*
* <p>The estimations will take into account the current environment conditions, the camera
* state and will include the time spent processing the multi-frame capture request along with
@@ -451,7 +500,7 @@
* or {@code null} if the estimation is not supported.
*/
@Nullable
- public Pair<Long, Long> getRealtimeStillCaptureLatency() throws CameraAccessException {
+ public StillCaptureLatency getRealtimeStillCaptureLatency() throws CameraAccessException {
throw new UnsupportedOperationException("Subclasses must override this method");
}
diff --git a/core/java/android/hardware/camera2/CameraManager.java b/core/java/android/hardware/camera2/CameraManager.java
index 5b6e288..e2dedd6 100644
--- a/core/java/android/hardware/camera2/CameraManager.java
+++ b/core/java/android/hardware/camera2/CameraManager.java
@@ -115,7 +115,14 @@
@Overridable
@EnabledSince(targetSdkVersion = android.os.Build.VERSION_CODES.BASE)
@TestApi
- public static final long OVERRIDE_FRONT_CAMERA_APP_COMPAT = 250678880L;
+ public static final long OVERRIDE_CAMERA_LANDSCAPE_TO_PORTRAIT = 250678880L;
+
+ /**
+ * Package-level opt in/out for the above.
+ * @hide
+ */
+ public static final String PROPERTY_COMPAT_OVERRIDE_LANDSCAPE_TO_PORTRAIT =
+ "android.camera.PROPERTY_COMPAT_OVERRIDE_LANDSCAPE_TO_PORTRAIT";
/**
* System property for allowing the above
@@ -607,7 +614,7 @@
try {
Size displaySize = getDisplaySize();
- boolean overrideToPortrait = shouldOverrideToPortrait();
+ boolean overrideToPortrait = shouldOverrideToPortrait(mContext);
CameraMetadataNative info = cameraService.getCameraCharacteristics(cameraId,
mContext.getApplicationInfo().targetSdkVersion, overrideToPortrait);
try {
@@ -727,7 +734,7 @@
"Camera service is currently unavailable");
}
- boolean overrideToPortrait = shouldOverrideToPortrait();
+ boolean overrideToPortrait = shouldOverrideToPortrait(mContext);
cameraUser = cameraService.connectDevice(callbacks, cameraId,
mContext.getOpPackageName(), mContext.getAttributionTag(), uid,
oomScoreOffset, mContext.getApplicationInfo().targetSdkVersion,
@@ -1159,9 +1166,26 @@
return CameraManagerGlobal.get().getTorchStrengthLevel(cameraId);
}
- private static boolean shouldOverrideToPortrait() {
- return CompatChanges.isChangeEnabled(OVERRIDE_FRONT_CAMERA_APP_COMPAT)
- && CameraManagerGlobal.sLandscapeToPortrait;
+ /**
+ * @hide
+ */
+ public static boolean shouldOverrideToPortrait(@Nullable Context context) {
+ if (!CameraManagerGlobal.sLandscapeToPortrait) {
+ return false;
+ }
+
+ if (context != null) {
+ PackageManager packageManager = context.getPackageManager();
+
+ try {
+ return packageManager.getProperty(context.getOpPackageName(),
+ PROPERTY_COMPAT_OVERRIDE_LANDSCAPE_TO_PORTRAIT).getBoolean();
+ } catch (PackageManager.NameNotFoundException e) {
+ // No such property
+ }
+ }
+
+ return CompatChanges.isChangeEnabled(OVERRIDE_CAMERA_LANDSCAPE_TO_PORTRAIT);
}
/**
@@ -2318,6 +2342,15 @@
final AvailabilityCallback callback = mCallbackMap.keyAt(i);
postSingleUpdate(callback, executor, id, null /*physicalId*/, status);
+
+ // Send the NOT_PRESENT state for unavailable physical cameras
+ if (isAvailable(status) && mUnavailablePhysicalDevices.containsKey(id)) {
+ ArrayList<String> unavailableIds = mUnavailablePhysicalDevices.get(id);
+ for (String unavailableId : unavailableIds) {
+ postSingleUpdate(callback, executor, id, unavailableId,
+ ICameraServiceListener.STATUS_NOT_PRESENT);
+ }
+ }
}
} // onStatusChangedLocked
diff --git a/core/java/android/hardware/camera2/impl/CameraAdvancedExtensionSessionImpl.java b/core/java/android/hardware/camera2/impl/CameraAdvancedExtensionSessionImpl.java
index 9437ea7..709fa60 100644
--- a/core/java/android/hardware/camera2/impl/CameraAdvancedExtensionSessionImpl.java
+++ b/core/java/android/hardware/camera2/impl/CameraAdvancedExtensionSessionImpl.java
@@ -361,7 +361,7 @@
}
@Override
- public Pair<Long, Long> getRealtimeStillCaptureLatency() throws CameraAccessException {
+ public StillCaptureLatency getRealtimeStillCaptureLatency() throws CameraAccessException {
synchronized (mInterfaceLock) {
if (!mInitialized) {
throw new IllegalStateException("Uninitialized component");
@@ -370,7 +370,7 @@
try {
LatencyPair latency = mSessionProcessor.getRealtimeCaptureLatency();
if (latency != null) {
- return new Pair<>(latency.first, latency.second);
+ return new StillCaptureLatency(latency.first, latency.second);
}
return null;
diff --git a/core/java/android/hardware/camera2/impl/CameraDeviceImpl.java b/core/java/android/hardware/camera2/impl/CameraDeviceImpl.java
index cc8de2b..cb1efe8 100644
--- a/core/java/android/hardware/camera2/impl/CameraDeviceImpl.java
+++ b/core/java/android/hardware/camera2/impl/CameraDeviceImpl.java
@@ -85,6 +85,7 @@
// TODO: guard every function with if (!mRemoteDevice) check (if it was closed)
private ICameraDeviceUserWrapper mRemoteDevice;
+ private boolean mRemoteDeviceInit = false;
// Lock to synchronize cross-thread access to device public interface
final Object mInterfaceLock = new Object(); // access from this class and Session only!
@@ -336,6 +337,8 @@
mDeviceExecutor.execute(mCallOnOpened);
mDeviceExecutor.execute(mCallOnUnconfigured);
+
+ mRemoteDeviceInit = true;
}
}
@@ -1752,8 +1755,8 @@
}
synchronized(mInterfaceLock) {
- if (mRemoteDevice == null) {
- return; // Camera already closed
+ if (mRemoteDevice == null && mRemoteDeviceInit) {
+ return; // Camera already closed, user is not interested in errors anymore.
}
// Redirect device callback to the offline session in case we are in the middle
diff --git a/core/java/android/hardware/camera2/impl/CameraExtensionSessionImpl.java b/core/java/android/hardware/camera2/impl/CameraExtensionSessionImpl.java
index ed48a6d..3f85d44 100644
--- a/core/java/android/hardware/camera2/impl/CameraExtensionSessionImpl.java
+++ b/core/java/android/hardware/camera2/impl/CameraExtensionSessionImpl.java
@@ -513,7 +513,7 @@
}
@Override
- public Pair<Long, Long> getRealtimeStillCaptureLatency() throws CameraAccessException {
+ public StillCaptureLatency getRealtimeStillCaptureLatency() throws CameraAccessException {
synchronized (mInterfaceLock) {
if (!mInitialized) {
throw new IllegalStateException("Uninitialized component");
@@ -522,7 +522,7 @@
try {
LatencyPair latency = mImageExtender.getRealtimeCaptureLatency();
if (latency != null) {
- return new Pair<>(latency.first, latency.second);
+ return new StillCaptureLatency(latency.first, latency.second);
}
return null;
diff --git a/core/java/android/hardware/camera2/impl/CameraMetadataNative.java b/core/java/android/hardware/camera2/impl/CameraMetadataNative.java
index 8d742b5..9640b0e 100644
--- a/core/java/android/hardware/camera2/impl/CameraMetadataNative.java
+++ b/core/java/android/hardware/camera2/impl/CameraMetadataNative.java
@@ -1037,6 +1037,19 @@
return fixedFaceRectangles;
}
+ private boolean setLensShadingMap(LensShadingMap lensShadingMap) {
+ if (lensShadingMap == null) {
+ return false;
+ }
+ float[] lsmArray = new float[lensShadingMap.getGainFactorCount()];
+ lensShadingMap.copyGainFactors(lsmArray, 0);
+ setBase(CaptureResult.STATISTICS_LENS_SHADING_MAP, lsmArray);
+
+ Size s = new Size(lensShadingMap.getRowCount(), lensShadingMap.getColumnCount());
+ setBase(CameraCharacteristics.LENS_INFO_SHADING_MAP_SIZE, s);
+ return true;
+ }
+
private LensShadingMap getLensShadingMap() {
float[] lsmArray = getBase(CaptureResult.STATISTICS_LENS_SHADING_MAP);
Size s = get(CameraCharacteristics.LENS_INFO_SHADING_MAP_SIZE);
@@ -1916,6 +1929,13 @@
metadata.setAERegions(value);
}
});
+ sSetCommandMap.put(CaptureResult.STATISTICS_LENS_SHADING_CORRECTION_MAP.getNativeKey(),
+ new SetCommand() {
+ @Override
+ public <T> void setValue(CameraMetadataNative metadata, T value) {
+ metadata.setLensShadingMap((LensShadingMap) value);
+ }
+ });
}
private boolean setAvailableFormats(int[] value) {
diff --git a/core/java/android/hardware/devicestate/DeviceStateManager.java b/core/java/android/hardware/devicestate/DeviceStateManager.java
index dba1a5e..6a667fe 100644
--- a/core/java/android/hardware/devicestate/DeviceStateManager.java
+++ b/core/java/android/hardware/devicestate/DeviceStateManager.java
@@ -251,6 +251,10 @@
@Nullable
private Boolean lastResult;
+ public FoldStateListener(Context context) {
+ this(context, folded -> {});
+ }
+
public FoldStateListener(Context context, Consumer<Boolean> listener) {
mFoldedDeviceStates = context.getResources().getIntArray(
com.android.internal.R.array.config_foldedDeviceStates);
@@ -266,5 +270,10 @@
mDelegate.accept(folded);
}
}
+
+ @Nullable
+ public Boolean getFolded() {
+ return lastResult;
+ }
}
}
diff --git a/core/java/android/hardware/face/IFaceService.aidl b/core/java/android/hardware/face/IFaceService.aidl
index 2bf187a..5fcc31e 100644
--- a/core/java/android/hardware/face/IFaceService.aidl
+++ b/core/java/android/hardware/face/IFaceService.aidl
@@ -43,7 +43,7 @@
byte[] dumpSensorServiceStateProto(int sensorId, boolean clearSchedulerBuffer);
// Retrieve static sensor properties for all face sensors
- @EnforcePermission("MANAGE_BIOMETRIC")
+ @EnforcePermission("USE_BIOMETRIC_INTERNAL")
List<FaceSensorPropertiesInternal> getSensorPropertiesInternal(String opPackageName);
// Retrieve static sensor properties for the specified sensor
diff --git a/core/java/android/hardware/fingerprint/FingerprintManager.java b/core/java/android/hardware/fingerprint/FingerprintManager.java
index a748b60..04a204a 100644
--- a/core/java/android/hardware/fingerprint/FingerprintManager.java
+++ b/core/java/android/hardware/fingerprint/FingerprintManager.java
@@ -464,6 +464,12 @@
* @param remaining The number of remaining steps
*/
public void onEnrollmentProgress(int remaining) { }
+
+ /**
+ * Called when a fingerprint image has been acquired.
+ * @param isAcquiredGood whether the fingerprint image was good.
+ */
+ public void onAcquired(boolean isAcquiredGood){ }
}
/**
@@ -1392,6 +1398,9 @@
if (mAuthenticationCallback != null) {
mAuthenticationCallback.onAuthenticationAcquired(acquireInfo);
}
+ if (mEnrollmentCallback != null) {
+ mEnrollmentCallback.onAcquired(acquireInfo == FINGERPRINT_ACQUIRED_GOOD);
+ }
final String msg = getAcquiredString(mContext, acquireInfo, vendorCode);
if (msg == null) {
return;
diff --git a/core/java/android/hardware/usb/DisplayPortAltModeInfo.aidl b/core/java/android/hardware/usb/DisplayPortAltModeInfo.aidl
new file mode 100644
index 0000000..14986d0
--- /dev/null
+++ b/core/java/android/hardware/usb/DisplayPortAltModeInfo.aidl
@@ -0,0 +1,19 @@
+/*
+ * 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 android.hardware.usb;
+
+parcelable DisplayPortAltModeInfo;
\ No newline at end of file
diff --git a/core/java/android/hardware/usb/DisplayPortAltModeInfo.java b/core/java/android/hardware/usb/DisplayPortAltModeInfo.java
new file mode 100644
index 0000000..febc643
--- /dev/null
+++ b/core/java/android/hardware/usb/DisplayPortAltModeInfo.java
@@ -0,0 +1,206 @@
+/*
+ * 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 android.hardware.usb;
+
+import android.Manifest;
+import android.annotation.CheckResult;
+import android.annotation.IntDef;
+import android.annotation.NonNull;
+import android.annotation.RequiresPermission;
+import android.annotation.SystemApi;
+import android.os.Parcel;
+import android.os.Parcelable;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.util.Objects;
+
+/**
+ * Holds information related to DisplayPort Alt Mode statuses
+ *
+ * @hide
+ */
+@SystemApi
+public final class DisplayPortAltModeInfo implements Parcelable {
+ private final @DisplayPortAltModeStatus int mPartnerSinkStatus;
+ private final @DisplayPortAltModeStatus int mCableStatus;
+ private final int mNumLanes;
+
+ /**
+ * Port Partners:
+ * The port partner status is currently unknown for one of the following reasons:
+ * <ul>
+ * <li> No port partner is connected to the device
+ * <li> The USB Power Delivery Discover Identity command has not been issued to the port
+ * partner via SOP messaging.
+ * </ul>
+ * <p>
+ * Cables:
+ * The cable’s capabilities are not yet known to the device, or no cable is plugged in.
+ */
+ public static final int DISPLAYPORT_ALT_MODE_STATUS_UNKNOWN = 0;
+
+ /**
+ * Port Partners:
+ * The current port partner does not list DisplayPort as one of its Alt Modes, or does not list
+ * the capability to act as a DisplayPort Source or Sink device, or a compatible configuration
+ * could not be established.
+ * <p>
+ * Cables:
+ * The cable/adapter’s capabilities do not list DisplayPort as one of its Alt Modes, or a
+ * compatible configuration could not be established.
+ */
+ public static final int DISPLAYPORT_ALT_MODE_STATUS_NOT_CAPABLE = 1;
+
+ /**
+ * Port Partners:
+ * The current port partner lists compatible DisplayPort capabilities with the device, however
+ * may not yet have entered DisplayPort Alt Mode or has configured its port for data
+ * transmission.
+ * <p>
+ * Cables:
+ * The Type-C cable/adapter’s capabilities have been discovered and list DisplayPort Alt Mode
+ * as one of its capabilities, however may not yet have entered DisplayPort Alt Mode or has been
+ * configured for data transmission.
+ */
+ public static final int DISPLAYPORT_ALT_MODE_STATUS_CAPABLE = 2;
+
+ /**
+ * Port Partners:
+ * The port partner and device are both configured for DisplayPort Alt Mode.
+ * <p>
+ * Cables:
+ * The Type-C cable/adapter is configured for DisplayPort Alt Mode.
+ */
+ public static final int DISPLAYPORT_ALT_MODE_STATUS_ENABLED = 3;
+
+ /** @hide */
+ @IntDef(prefix = { "DISPLAYPORT_ALT_MODE_STATUS_" }, value = {
+ DISPLAYPORT_ALT_MODE_STATUS_UNKNOWN,
+ DISPLAYPORT_ALT_MODE_STATUS_NOT_CAPABLE,
+ DISPLAYPORT_ALT_MODE_STATUS_CAPABLE,
+ DISPLAYPORT_ALT_MODE_STATUS_ENABLED,
+ })
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface DisplayPortAltModeStatus {}
+
+ /** @hide */
+ public DisplayPortAltModeInfo() {
+ mPartnerSinkStatus = DISPLAYPORT_ALT_MODE_STATUS_UNKNOWN;
+ mCableStatus = DISPLAYPORT_ALT_MODE_STATUS_UNKNOWN;
+ mNumLanes = 0;
+ }
+
+ /** @hide */
+ public DisplayPortAltModeInfo(int partnerSinkStatus, int cableStatus,
+ int numLanes) {
+ mPartnerSinkStatus = partnerSinkStatus;
+ mCableStatus = cableStatus;
+ mNumLanes = numLanes;
+ }
+
+ /**
+ * Returns the DisplayPort Alt Mode Status for a port partner acting as a sink.
+ *
+ * @return {@link #DISPLAYPORT_ALT_MODE_STATUS_UNKNOWN}
+ * or {@link #DISPLAYPORT_ALT_MODE_STATUS_NOT_CAPABLE}
+ * or {@link #DISPLAYPORT_ALT_MODE_STATUS_CAPABLE}
+ * or {@link #DISPLAYPORT_ALT_MODE_STATUS_ENABLED}
+ */
+ public @DisplayPortAltModeStatus int getPartnerSinkStatus() {
+ return mPartnerSinkStatus;
+ }
+
+ /**
+ * Returns the DisplayPort Alt Mode Status for the attached cable
+ *
+ * @return {@link #DISPLAYPORT_ALT_MODE_STATUS_UNKNOWN}
+ * or {@link #DISPLAYPORT_ALT_MODE_STATUS_NOT_CAPABLE}
+ * or {@link #DISPLAYPORT_ALT_MODE_STATUS_CAPABLE}
+ * or {@link #DISPLAYPORT_ALT_MODE_STATUS_ENABLED}
+ */
+ public @DisplayPortAltModeStatus int getCableStatus() {
+ return mCableStatus;
+ }
+
+ /**
+ * Returns the number of lanes used to transmit display data.
+ *
+ */
+ public int getNumberOfLanes() {
+ return mNumLanes;
+ }
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ @Override
+ public void writeToParcel(@NonNull Parcel dest, int flags) {
+ dest.writeInt(mPartnerSinkStatus);
+ dest.writeInt(mCableStatus);
+ dest.writeInt(mNumLanes);
+ }
+
+ @NonNull
+ @Override
+ public String toString() {
+ return "DisplayPortAltModeInfo{partnerSink="
+ + mPartnerSinkStatus
+ + " cable="
+ + mCableStatus
+ + " numLanes="
+ + mNumLanes
+ + "}";
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) {
+ return true;
+ }
+ if (!(o instanceof DisplayPortAltModeInfo)) {
+ return false;
+ }
+ DisplayPortAltModeInfo other = (DisplayPortAltModeInfo) o;
+ return this.mPartnerSinkStatus == other.mPartnerSinkStatus
+ && this.mCableStatus == other.mCableStatus
+ && this.mNumLanes == other.mNumLanes;
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(mPartnerSinkStatus, mCableStatus, mNumLanes);
+ }
+
+ public static final @NonNull Parcelable.Creator<DisplayPortAltModeInfo> CREATOR =
+ new Parcelable.Creator<DisplayPortAltModeInfo>() {
+ @Override
+ public DisplayPortAltModeInfo createFromParcel(Parcel in) {
+ int partnerSinkStatus = in.readInt();
+ int cableStatus = in.readInt();
+ int numLanes = in.readInt();
+ return new DisplayPortAltModeInfo(partnerSinkStatus, cableStatus, numLanes);
+ }
+
+ @Override
+ public DisplayPortAltModeInfo[] newArray(int size) {
+ return new DisplayPortAltModeInfo[size];
+ }
+ };
+}
diff --git a/core/java/android/hardware/usb/IDisplayPortAltModeInfoListener.aidl b/core/java/android/hardware/usb/IDisplayPortAltModeInfoListener.aidl
new file mode 100644
index 0000000..e93e0fb
--- /dev/null
+++ b/core/java/android/hardware/usb/IDisplayPortAltModeInfoListener.aidl
@@ -0,0 +1,27 @@
+/*
+ * 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 android.hardware.usb;
+
+import android.hardware.usb.DisplayPortAltModeInfo;
+
+/**
+ * @hide
+ */
+oneway interface IDisplayPortAltModeInfoListener {
+ void onDisplayPortAltModeInfoChanged(in String portId,
+ in DisplayPortAltModeInfo DisplayPortAltModeInfo);
+}
\ No newline at end of file
diff --git a/core/java/android/hardware/usb/IUsbManager.aidl b/core/java/android/hardware/usb/IUsbManager.aidl
index 248b5d0..21b00e3 100644
--- a/core/java/android/hardware/usb/IUsbManager.aidl
+++ b/core/java/android/hardware/usb/IUsbManager.aidl
@@ -18,6 +18,7 @@
import android.app.PendingIntent;
import android.content.ComponentName;
+import android.hardware.usb.IDisplayPortAltModeInfoListener;
import android.hardware.usb.IUsbOperationInternal;
import android.hardware.usb.UsbAccessory;
import android.hardware.usb.UsbDevice;
@@ -184,4 +185,15 @@
/* Sets USB device connection handler. */
void setUsbDeviceConnectionHandler(in ComponentName usbDeviceConnectionHandler);
+
+ /* Registers callback for Usb events */
+ @JavaPassthrough(annotation=
+ "@android.annotation.RequiresPermission(android.Manifest.permission.MANAGE_USB)")
+ boolean registerForDisplayPortEvents(IDisplayPortAltModeInfoListener listener);
+
+ /* Unregisters Usb event callback */
+ @JavaPassthrough(annotation=
+ "@android.annotation.RequiresPermission(android.Manifest.permission.MANAGE_USB)")
+ void unregisterForDisplayPortEvents(IDisplayPortAltModeInfoListener listener);
+
}
diff --git a/core/java/android/hardware/usb/ParcelableUsbPort.java b/core/java/android/hardware/usb/ParcelableUsbPort.java
index 7fc282c..eb6501a 100644
--- a/core/java/android/hardware/usb/ParcelableUsbPort.java
+++ b/core/java/android/hardware/usb/ParcelableUsbPort.java
@@ -35,12 +35,14 @@
private final boolean mSupportsEnableContaminantPresenceProtection;
private final boolean mSupportsEnableContaminantPresenceDetection;
private final boolean mSupportsComplianceWarnings;
+ private final int mSupportedAltModesMask;
private ParcelableUsbPort(@NonNull String id, int supportedModes,
int supportedContaminantProtectionModes,
boolean supportsEnableContaminantPresenceProtection,
boolean supportsEnableContaminantPresenceDetection,
- boolean supportsComplianceWarnings) {
+ boolean supportsComplianceWarnings,
+ int supportedAltModesMask) {
mId = id;
mSupportedModes = supportedModes;
mSupportedContaminantProtectionModes = supportedContaminantProtectionModes;
@@ -50,6 +52,7 @@
supportsEnableContaminantPresenceDetection;
mSupportsComplianceWarnings =
supportsComplianceWarnings;
+ mSupportedAltModesMask = supportedAltModesMask;
}
/**
@@ -64,7 +67,8 @@
port.getSupportedContaminantProtectionModes(),
port.supportsEnableContaminantPresenceProtection(),
port.supportsEnableContaminantPresenceDetection(),
- port.supportsComplianceWarnings());
+ port.supportsComplianceWarnings(),
+ port.getSupportedAltModesMask());
}
/**
@@ -78,7 +82,8 @@
return new UsbPort(usbManager, mId, mSupportedModes, mSupportedContaminantProtectionModes,
mSupportsEnableContaminantPresenceProtection,
mSupportsEnableContaminantPresenceDetection,
- mSupportsComplianceWarnings);
+ mSupportsComplianceWarnings,
+ mSupportedAltModesMask);
}
@Override
@@ -94,6 +99,7 @@
dest.writeBoolean(mSupportsEnableContaminantPresenceProtection);
dest.writeBoolean(mSupportsEnableContaminantPresenceDetection);
dest.writeBoolean(mSupportsComplianceWarnings);
+ dest.writeInt(mSupportedAltModesMask);
}
public static final @android.annotation.NonNull Creator<ParcelableUsbPort> CREATOR =
@@ -106,12 +112,14 @@
boolean supportsEnableContaminantPresenceProtection = in.readBoolean();
boolean supportsEnableContaminantPresenceDetection = in.readBoolean();
boolean supportsComplianceWarnings = in.readBoolean();
+ int supportedAltModesMask = in.readInt();
return new ParcelableUsbPort(id, supportedModes,
supportedContaminantProtectionModes,
supportsEnableContaminantPresenceProtection,
supportsEnableContaminantPresenceDetection,
- supportsComplianceWarnings);
+ supportsComplianceWarnings,
+ supportedAltModesMask);
}
@Override
diff --git a/core/java/android/hardware/usb/UsbManager.java b/core/java/android/hardware/usb/UsbManager.java
index 7a8117c..909d147 100644
--- a/core/java/android/hardware/usb/UsbManager.java
+++ b/core/java/android/hardware/usb/UsbManager.java
@@ -20,6 +20,7 @@
import static android.hardware.usb.UsbPortStatus.DATA_STATUS_DISABLED_FORCE;
import android.Manifest;
+import android.annotation.CallbackExecutor;
import android.annotation.IntDef;
import android.annotation.LongDef;
import android.annotation.NonNull;
@@ -44,16 +45,24 @@
import android.os.ParcelFileDescriptor;
import android.os.Process;
import android.os.RemoteException;
+import android.util.ArrayMap;
import android.util.Log;
+import android.util.Slog;
+
+import com.android.internal.annotations.GuardedBy;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
+import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.StringJoiner;
import java.util.concurrent.atomic.AtomicInteger;
+import java.util.concurrent.Executor;
+import java.util.function.BiConsumer;
+import java.util.function.Consumer;
/**
* This class allows you to access the state of USB and communicate with USB devices.
@@ -724,8 +733,60 @@
})
public @interface UsbHalVersion {}
+ /**
+ * Listener to register for when the {@link DisplayPortAltModeInfo} changes on a
+ * {@link UsbPort}.
+ *
+ * @hide
+ */
+ @SystemApi
+ public interface DisplayPortAltModeInfoListener {
+ /**
+ * Callback to be executed when the {@link DisplayPortAltModeInfo} changes on a
+ * {@link UsbPort}.
+ *
+ * @param portId String describing the {@link UsbPort} that was changed.
+ * @param info New {@link DisplayPortAltModeInfo} for the corresponding portId.
+ */
+ public void onDisplayPortAltModeInfoChanged(@NonNull String portId,
+ @NonNull DisplayPortAltModeInfo info);
+ }
+
+ /**
+ * Holds callback and executor data to be passed across UsbService.
+ */
+ private class DisplayPortAltModeInfoDispatchingListener extends
+ IDisplayPortAltModeInfoListener.Stub {
+
+ public void onDisplayPortAltModeInfoChanged(String portId,
+ DisplayPortAltModeInfo displayPortAltModeInfo) {
+ synchronized (mDisplayPortListenersLock) {
+ for (Map.Entry<DisplayPortAltModeInfoListener, Executor> entry :
+ mDisplayPortListeners.entrySet()) {
+ Executor executor = entry.getValue();
+ DisplayPortAltModeInfoListener callback = entry.getKey();
+ final long token = Binder.clearCallingIdentity();
+ try {
+ executor.execute(() -> callback.onDisplayPortAltModeInfoChanged(portId,
+ displayPortAltModeInfo));
+ } catch (Exception e) {
+ Slog.e(TAG, "Exception during onDisplayPortAltModeInfoChanged from "
+ + "executor: " + executor, e);
+ } finally {
+ Binder.restoreCallingIdentity(token);
+ }
+ }
+ }
+ }
+ }
+
private final Context mContext;
private final IUsbManager mService;
+ private final Object mDisplayPortListenersLock = new Object();
+ @GuardedBy("mDisplayPortListenersLock")
+ private ArrayMap<DisplayPortAltModeInfoListener, Executor> mDisplayPortListeners;
+ @GuardedBy("mDisplayPortListenersLock")
+ private DisplayPortAltModeInfoDispatchingListener mDisplayPortServiceListener;
/**
* @hide
@@ -1524,6 +1585,109 @@
}
}
+ @GuardedBy("mDisplayPortListenersLock")
+ @RequiresPermission(Manifest.permission.MANAGE_USB)
+ private boolean registerDisplayPortAltModeEventsIfNeededLocked() {
+ DisplayPortAltModeInfoDispatchingListener displayPortDispatchingListener =
+ new DisplayPortAltModeInfoDispatchingListener();
+ try {
+ if (mService.registerForDisplayPortEvents(displayPortDispatchingListener)) {
+ mDisplayPortServiceListener = displayPortDispatchingListener;
+ return true;
+ }
+ return false;
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
+ /**
+ * Registers the given listener to listen for DisplayPort Alt Mode changes.
+ * <p>
+ * If this method returns true, the caller should ensure to call
+ * {@link #unregisterDisplayPortAltModeListener} when it no longer requires updates.
+ *
+ * @param executor Executor on which to run the listener.
+ * @param listener DisplayPortAltModeInfoListener invoked on DisplayPortAltModeInfo
+ * changes. See {@link #DisplayPortAltModeInfoListener} for listener
+ * details.
+ *
+ * @return true on successful register, false on failed register due to listener already being
+ * registered or an internal error.
+ *
+ * @hide
+ */
+ @SystemApi
+ @RequiresPermission(Manifest.permission.MANAGE_USB)
+ public boolean registerDisplayPortAltModeInfoListener(
+ @NonNull @CallbackExecutor Executor executor,
+ @NonNull DisplayPortAltModeInfoListener listener) {
+ Objects.requireNonNull(executor, "registerDisplayPortAltModeInfoListener: "
+ + "executor must not be null.");
+ Objects.requireNonNull(listener, "registerDisplayPortAltModeInfoListener: "
+ + "listener must not be null.");
+
+ synchronized (mDisplayPortListenersLock) {
+ if (mDisplayPortListeners == null) {
+ mDisplayPortListeners = new ArrayMap<DisplayPortAltModeInfoListener,
+ Executor>();
+ }
+
+ if (mDisplayPortServiceListener == null) {
+ if (!registerDisplayPortAltModeEventsIfNeededLocked()) {
+ return false;
+ }
+ }
+ if (mDisplayPortListeners.containsKey(listener)) {
+ return false;
+ }
+
+ mDisplayPortListeners.put(listener, executor);
+ return true;
+ }
+ }
+
+ @GuardedBy("mDisplayPortListenersLock")
+ @RequiresPermission(Manifest.permission.MANAGE_USB)
+ private void unregisterDisplayPortAltModeEventsLocked() {
+ if (mDisplayPortServiceListener != null) {
+ try {
+ mService.unregisterForDisplayPortEvents(mDisplayPortServiceListener);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ } finally {
+ // If there was a RemoteException, the system server may have died,
+ // and this listener probably became unregistered, so clear it for re-registration.
+ mDisplayPortServiceListener = null;
+ }
+ }
+ }
+
+ /**
+ * Unregisters the given listener if it was previously passed to
+ * registerDisplayPortAltModeInfoListener.
+ *
+ * @param listener DisplayPortAltModeInfoListener used to register the listener
+ * in registerDisplayPortAltModeInfoListener.
+ *
+ * @hide
+ */
+ @SystemApi
+ @RequiresPermission(Manifest.permission.MANAGE_USB)
+ public void unregisterDisplayPortAltModeInfoListener(
+ @NonNull DisplayPortAltModeInfoListener listener) {
+ synchronized (mDisplayPortListenersLock) {
+ if (mDisplayPortListeners == null) {
+ return;
+ }
+ mDisplayPortListeners.remove(listener);
+ if (mDisplayPortListeners.isEmpty()) {
+ unregisterDisplayPortAltModeEventsLocked();
+ }
+ }
+ return;
+ }
+
/**
* Sets the component that will handle USB device connection.
* <p>
diff --git a/core/java/android/hardware/usb/UsbPort.java b/core/java/android/hardware/usb/UsbPort.java
index cdd67b7..73dcb36 100644
--- a/core/java/android/hardware/usb/UsbPort.java
+++ b/core/java/android/hardware/usb/UsbPort.java
@@ -52,6 +52,10 @@
import static android.hardware.usb.UsbPortStatus.COMPLIANCE_WARNING_BC_1_2;
import static android.hardware.usb.UsbPortStatus.COMPLIANCE_WARNING_MISSING_RP;
import static android.hardware.usb.UsbPortStatus.COMPLIANCE_WARNING_OTHER;
+import static android.hardware.usb.DisplayPortAltModeInfo.DISPLAYPORT_ALT_MODE_STATUS_UNKNOWN;
+import static android.hardware.usb.DisplayPortAltModeInfo.DISPLAYPORT_ALT_MODE_STATUS_NOT_CAPABLE;
+import static android.hardware.usb.DisplayPortAltModeInfo.DISPLAYPORT_ALT_MODE_STATUS_CAPABLE;
+import static android.hardware.usb.DisplayPortAltModeInfo.DISPLAYPORT_ALT_MODE_STATUS_ENABLED;
import android.Manifest;
import android.annotation.CallbackExecutor;
@@ -90,6 +94,7 @@
private final boolean mSupportsEnableContaminantPresenceProtection;
private final boolean mSupportsEnableContaminantPresenceDetection;
private final boolean mSupportsComplianceWarnings;
+ private final @AltModeType int mSupportedAltModes;
private static final int NUM_DATA_ROLES = Constants.PortDataRole.NUM_DATA_ROLES;
/**
@@ -252,6 +257,18 @@
@Retention(RetentionPolicy.SOURCE)
@interface EnableUsbDataWhileDockedStatus{}
+ /**
+ * Indicates that the Alt Mode being described is DisplayPort.
+ */
+ public static final int FLAG_ALT_MODE_TYPE_DISPLAYPORT = 1 << 0;
+
+ /** @hide */
+ @IntDef(prefix = { "FLAG_ALT_MODE_TYPE_" }, flag = true, value = {
+ FLAG_ALT_MODE_TYPE_DISPLAYPORT,
+ })
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface AltModeType {}
+
/** @hide */
public UsbPort(@NonNull UsbManager usbManager, @NonNull String id, int supportedModes,
int supportedContaminantProtectionModes,
@@ -260,7 +277,7 @@
this(usbManager, id, supportedModes, supportedContaminantProtectionModes,
supportsEnableContaminantPresenceProtection,
supportsEnableContaminantPresenceDetection,
- false);
+ false, 0);
}
/** @hide */
@@ -268,7 +285,8 @@
int supportedContaminantProtectionModes,
boolean supportsEnableContaminantPresenceProtection,
boolean supportsEnableContaminantPresenceDetection,
- boolean supportsComplianceWarnings) {
+ boolean supportsComplianceWarnings,
+ int supportedAltModes) {
Objects.requireNonNull(id);
Preconditions.checkFlagsArgument(supportedModes,
MODE_DFP | MODE_UFP | MODE_AUDIO_ACCESSORY | MODE_DEBUG_ACCESSORY);
@@ -282,6 +300,7 @@
mSupportsEnableContaminantPresenceDetection =
supportsEnableContaminantPresenceDetection;
mSupportsComplianceWarnings = supportsComplianceWarnings;
+ mSupportedAltModes = supportedAltModes;
}
/**
@@ -366,6 +385,27 @@
}
/**
+ * Returns all Alt Modes supported by the port.
+ *
+ * @hide
+ */
+ public @AltModeType int getSupportedAltModesMask() {
+ return mSupportedAltModes;
+ }
+
+ /**
+ * Returns whether all Alt Mode types in a given mask are supported
+ * by the port.
+ *
+ * @return true if all given Alt Modes are supported, false otherwise.
+ *
+ */
+ public boolean isAltModeSupported(@AltModeType int typeMask) {
+ return (mSupportedAltModes & typeMask) == typeMask;
+ }
+
+
+ /**
* Sets the desired role combination of the port.
* <p>
* The supported role combinations depend on what is connected to the port and may be
@@ -761,6 +801,22 @@
}
/** @hide */
+ public static String dpAltModeStatusToString(int dpAltModeStatus) {
+ switch (dpAltModeStatus) {
+ case DISPLAYPORT_ALT_MODE_STATUS_UNKNOWN:
+ return "Unknown";
+ case DISPLAYPORT_ALT_MODE_STATUS_NOT_CAPABLE:
+ return "Not Capable";
+ case DISPLAYPORT_ALT_MODE_STATUS_CAPABLE:
+ return "Capable";
+ case DISPLAYPORT_ALT_MODE_STATUS_ENABLED:
+ return "Enabled";
+ default:
+ return Integer.toString(dpAltModeStatus);
+ }
+ }
+
+ /** @hide */
public static void checkMode(int powerRole) {
Preconditions.checkArgumentInRange(powerRole, Constants.PortMode.NONE,
Constants.PortMode.NUM_MODES - 1, "portMode");
diff --git a/core/java/android/hardware/usb/UsbPortStatus.java b/core/java/android/hardware/usb/UsbPortStatus.java
index e61703d..8c13307 100644
--- a/core/java/android/hardware/usb/UsbPortStatus.java
+++ b/core/java/android/hardware/usb/UsbPortStatus.java
@@ -20,6 +20,7 @@
import android.annotation.CheckResult;
import android.annotation.IntDef;
import android.annotation.NonNull;
+import android.annotation.Nullable;
import android.annotation.RequiresPermission;
import android.annotation.SystemApi;
import android.os.Parcel;
@@ -27,6 +28,7 @@
import com.android.internal.annotations.Immutable;
+import java.lang.StringBuilder;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
@@ -49,6 +51,13 @@
private final @UsbDataStatus int mUsbDataStatus;
private final @PowerBrickConnectionStatus int mPowerBrickConnectionStatus;
private final @NonNull @ComplianceWarning int[] mComplianceWarnings;
+ private final @PlugState int mPlugState;
+ /**
+ * Holds the DisplayPort Alt Mode info for the Port. This field
+ * is null if the device does not support DisplayPort Alt Mode.
+ */
+ private final @Nullable DisplayPortAltModeInfo mDisplayPortAltModeInfo;
+
/**
* Power role: This USB port does not have a power role.
@@ -300,6 +309,35 @@
*/
public static final int COMPLIANCE_WARNING_MISSING_RP = 4;
+ /**
+ * Indicates that the Type-C plug orientation cannot be
+ * determined.
+ */
+ public static final int PLUG_STATE_UNKNOWN = 0;
+
+ /**
+ * Indicates no Type-C plug is inserted into the device.
+ */
+ public static final int PLUG_STATE_UNPLUGGED = 1;
+
+ /**
+ * Indicates a Type-C plug is inserted into the device, but
+ * the orientation cannot be determined.
+ */
+ public static final int PLUG_STATE_PLUGGED_ORIENTATION_UNKNOWN = 2;
+
+ /**
+ * Indicates that the connected plug uses its CC1
+ * pin to manage the Source-to-Sink connection.
+ */
+ public static final int PLUG_STATE_PLUGGED_ORIENTATION_NORMAL = 3;
+
+ /**
+ * Indicates that the connected plug uses its CC2
+ * pin to manage the Source-to-Sink connection.
+ */
+ public static final int PLUG_STATE_PLUGGED_ORIENTATION_FLIPPED = 4;
+
@IntDef(prefix = { "CONTAMINANT_DETECTION_" }, value = {
CONTAMINANT_DETECTION_NOT_SUPPORTED,
CONTAMINANT_DETECTION_DISABLED,
@@ -338,6 +376,16 @@
@Retention(RetentionPolicy.SOURCE)
@interface ComplianceWarning{}
+ @IntDef(prefix = { "PLUG_STATE_" }, value = {
+ PLUG_STATE_UNKNOWN,
+ PLUG_STATE_UNPLUGGED,
+ PLUG_STATE_PLUGGED_ORIENTATION_UNKNOWN,
+ PLUG_STATE_PLUGGED_ORIENTATION_NORMAL,
+ PLUG_STATE_PLUGGED_ORIENTATION_FLIPPED,
+ })
+ @Retention(RetentionPolicy.SOURCE)
+ @interface PlugState{}
+
/** @hide */
@IntDef(prefix = { "DATA_STATUS_" }, flag = true, value = {
DATA_STATUS_UNKNOWN,
@@ -348,7 +396,7 @@
DATA_STATUS_DISABLED_DOCK_HOST_MODE,
DATA_STATUS_DISABLED_DOCK_DEVICE_MODE,
DATA_STATUS_DISABLED_FORCE,
- DATA_STATUS_DISABLED_DEBUG
+ DATA_STATUS_DISABLED_DEBUG,
})
@Retention(RetentionPolicy.SOURCE)
@interface UsbDataStatus{}
@@ -368,7 +416,9 @@
int contaminantDetectionStatus, @UsbDataStatus int usbDataStatus,
boolean powerTransferLimited,
@PowerBrickConnectionStatus int powerBrickConnectionStatus,
- @NonNull @ComplianceWarning int[] complianceWarnings) {
+ @NonNull @ComplianceWarning int[] complianceWarnings,
+ int plugState,
+ @Nullable DisplayPortAltModeInfo displayPortAltModeInfo) {
mCurrentMode = currentMode;
mCurrentPowerRole = currentPowerRole;
mCurrentDataRole = currentDataRole;
@@ -393,6 +443,8 @@
mPowerTransferLimited = powerTransferLimited;
mPowerBrickConnectionStatus = powerBrickConnectionStatus;
mComplianceWarnings = complianceWarnings;
+ mPlugState = plugState;
+ mDisplayPortAltModeInfo = displayPortAltModeInfo;
}
/** @hide */
@@ -404,7 +456,7 @@
this(currentMode, currentPowerRole, currentDataRole, supportedRoleCombinations,
contaminantProtectionStatus, contaminantDetectionStatus,
usbDataStatus, powerTransferLimited, powerBrickConnectionStatus,
- new int[] {});
+ new int[] {}, PLUG_STATE_UNKNOWN, null);
}
/** @hide */
@@ -414,7 +466,7 @@
this(currentMode, currentPowerRole, currentDataRole, supportedRoleCombinations,
contaminantProtectionStatus, contaminantDetectionStatus,
DATA_STATUS_UNKNOWN, false, POWER_BRICK_STATUS_UNKNOWN,
- new int[] {});
+ new int[] {}, PLUG_STATE_UNKNOWN, null);
}
/**
@@ -547,10 +599,34 @@
return mComplianceWarnings;
}
+ /**
+ * Returns the orientation state of the attached cable/adapter.
+ *
+ * @return one of {@link #PLUG_STATE_UNKNOWN},
+ * {@link #PLUG_STATE_UNPLUGGED},
+ * {@link #PLUG_STATE_PLUGGED_ORIENTATION_UNKNOWN},
+ * {@link #PLUG_STATE_PLUGGED_ORIENTATION_NORMAL},
+ * {@link #PLUG_STATE_PLUGGED_ORIENTATION_FLIPPED},
+ */
+ public @PlugState int getPlugState() {
+ return mPlugState;
+ }
+
+ /**
+ * Returns the DisplayPortInfo of the USB Port, if applicable.
+ *
+ * @return an instance of type DisplayPortInfo
+ * or null if not applicable.
+ */
+ @Nullable
+ public DisplayPortAltModeInfo getDisplayPortAltModeInfo() {
+ return (mDisplayPortAltModeInfo == null) ? null : mDisplayPortAltModeInfo;
+ }
+
@NonNull
@Override
public String toString() {
- return "UsbPortStatus{connected=" + isConnected()
+ StringBuilder mString = new StringBuilder("UsbPortStatus{connected=" + isConnected()
+ ", currentMode=" + UsbPort.modeToString(mCurrentMode)
+ ", currentPowerRole=" + UsbPort.powerRoleToString(mCurrentPowerRole)
+ ", currentDataRole=" + UsbPort.dataRoleToString(mCurrentDataRole)
@@ -569,7 +645,12 @@
.powerBrickConnectionStatusToString(getPowerBrickConnectionStatus())
+ ", complianceWarnings="
+ UsbPort.complianceWarningsToString(getComplianceWarnings())
- + "}";
+ + ", plugState="
+ + getPlugState()
+ + ", displayPortAltModeInfo="
+ + mDisplayPortAltModeInfo
+ + "}");
+ return mString.toString();
}
@Override
@@ -589,6 +670,13 @@
dest.writeBoolean(mPowerTransferLimited);
dest.writeInt(mPowerBrickConnectionStatus);
dest.writeIntArray(mComplianceWarnings);
+ dest.writeInt(mPlugState);
+ if (mDisplayPortAltModeInfo == null) {
+ dest.writeBoolean(false);
+ } else {
+ dest.writeBoolean(true);
+ mDisplayPortAltModeInfo.writeToParcel(dest, 0);
+ }
}
public static final @NonNull Parcelable.Creator<UsbPortStatus> CREATOR =
@@ -605,11 +693,19 @@
boolean powerTransferLimited = in.readBoolean();
int powerBrickConnectionStatus = in.readInt();
@ComplianceWarning int[] complianceWarnings = in.createIntArray();
+ int plugState = in.readInt();
+ boolean supportsDisplayPortAltMode = in.readBoolean();
+ DisplayPortAltModeInfo displayPortAltModeInfo;
+ if (supportsDisplayPortAltMode) {
+ displayPortAltModeInfo = DisplayPortAltModeInfo.CREATOR.createFromParcel(in);
+ } else {
+ displayPortAltModeInfo = null;
+ }
return new UsbPortStatus(currentMode, currentPowerRole, currentDataRole,
supportedRoleCombinations, contaminantProtectionStatus,
contaminantDetectionStatus, usbDataStatus, powerTransferLimited,
powerBrickConnectionStatus,
- complianceWarnings);
+ complianceWarnings, plugState, displayPortAltModeInfo);
}
@Override
@@ -634,6 +730,8 @@
private @UsbDataStatus int mUsbDataStatus;
private @PowerBrickConnectionStatus int mPowerBrickConnectionStatus;
private @ComplianceWarning int[] mComplianceWarnings;
+ private @PlugState int mPlugState;
+ private @Nullable DisplayPortAltModeInfo mDisplayPortAltModeInfo;
public Builder() {
mCurrentMode = MODE_NONE;
@@ -644,6 +742,8 @@
mUsbDataStatus = DATA_STATUS_UNKNOWN;
mPowerBrickConnectionStatus = POWER_BRICK_STATUS_UNKNOWN;
mComplianceWarnings = new int[] {};
+ mPlugState = PLUG_STATE_UNKNOWN;
+ mDisplayPortAltModeInfo = null;
}
/**
@@ -742,6 +842,28 @@
return this;
}
+ /**
+ * Sets the plug orientation of {@link UsbPortStatus}
+ *
+ * @return Instance of {@link Builder}
+ */
+ @NonNull
+ public Builder setPlugState(int plugState) {
+ mPlugState = plugState;
+ return this;
+ }
+
+ /**
+ * Sets the plug orientation of {@link UsbPortStatus}
+ *
+ * @return Instance of {@link Builder}
+ */
+ @NonNull
+ public Builder setDisplayPortAltModeInfo(
+ @Nullable DisplayPortAltModeInfo displayPortAltModeInfo) {
+ mDisplayPortAltModeInfo = displayPortAltModeInfo;
+ return this;
+ }
/**
* Creates the {@link UsbPortStatus} object.
@@ -751,7 +873,8 @@
UsbPortStatus status = new UsbPortStatus(mCurrentMode, mCurrentPowerRole,
mCurrentDataRole, mSupportedRoleCombinations, mContaminantProtectionStatus,
mContaminantDetectionStatus, mUsbDataStatus, mPowerTransferLimited,
- mPowerBrickConnectionStatus, mComplianceWarnings);
+ mPowerBrickConnectionStatus, mComplianceWarnings,
+ mPlugState, mDisplayPortAltModeInfo);
return status;
}
};
diff --git a/core/java/android/inputmethodservice/IRemoteInputConnectionInvoker.java b/core/java/android/inputmethodservice/IRemoteInputConnectionInvoker.java
index 8759a6a..8e6f6dc 100644
--- a/core/java/android/inputmethodservice/IRemoteInputConnectionInvoker.java
+++ b/core/java/android/inputmethodservice/IRemoteInputConnectionInvoker.java
@@ -767,20 +767,20 @@
/**
* Invokes {@link IRemoteInputConnection#requestTextBoundsInfo(InputConnectionCommandHeader,
* RectF, ResultReceiver)}
- * @param rectF {@code rectF} parameter to be passed.
+ * @param bounds {@code rectF} parameter to be passed.
* @param executor {@code Executor} parameter to be passed.
* @param consumer {@code Consumer} parameter to be passed.
*/
@AnyThread
public void requestTextBoundsInfo(
- @NonNull RectF rectF, @NonNull @CallbackExecutor Executor executor,
+ @NonNull RectF bounds, @NonNull @CallbackExecutor Executor executor,
@NonNull Consumer<TextBoundsInfoResult> consumer) {
Objects.requireNonNull(executor);
Objects.requireNonNull(consumer);
final ResultReceiver resultReceiver = new TextBoundsInfoResultReceiver(executor, consumer);
try {
- mConnection.requestTextBoundsInfo(createHeader(), rectF, resultReceiver);
+ mConnection.requestTextBoundsInfo(createHeader(), bounds, resultReceiver);
} catch (RemoteException e) {
executor.execute(() -> consumer.accept(new TextBoundsInfoResult(CODE_CANCELLED)));
}
diff --git a/core/java/android/inputmethodservice/RemoteInputConnection.java b/core/java/android/inputmethodservice/RemoteInputConnection.java
index f93f9ab..ec26ace 100644
--- a/core/java/android/inputmethodservice/RemoteInputConnection.java
+++ b/core/java/android/inputmethodservice/RemoteInputConnection.java
@@ -476,9 +476,9 @@
@AnyThread
public void requestTextBoundsInfo(
- @NonNull RectF rectF, @NonNull @CallbackExecutor Executor executor,
+ @NonNull RectF bounds, @NonNull @CallbackExecutor Executor executor,
@NonNull Consumer<TextBoundsInfoResult> consumer) {
- mInvoker.requestTextBoundsInfo(rectF, executor, consumer);
+ mInvoker.requestTextBoundsInfo(bounds, executor, consumer);
}
@AnyThread
diff --git a/core/java/android/os/Binder.java b/core/java/android/os/Binder.java
index def0cbd..00676f3 100644
--- a/core/java/android/os/Binder.java
+++ b/core/java/android/os/Binder.java
@@ -358,16 +358,16 @@
* Return the Linux UID assigned to the process that sent the transaction
* currently being processed.
*
- * Logs WTF if the current thread is not currently
+ * Slog.wtf if the current thread is not currently
* executing an incoming transaction and the calling identity has not been
* explicitly set with {@link #clearCallingIdentity()}
*
* @hide
*/
- public static final int getCallingUidOrWtf() {
+ public static final int getCallingUidOrWtf(String message) {
if (!isDirectlyHandlingTransaction() && !hasExplicitIdentity()) {
- Log.wtfStack(TAG,
- "Thread is not in a binder transaction, "
+ Slog.wtf(TAG,
+ message + ": Thread is not in a binder transaction, "
+ "and the calling identity has not been "
+ "explicitly set with clearCallingIdentity");
}
diff --git a/core/java/android/os/Trace.java b/core/java/android/os/Trace.java
index cdde18a..adc73c8 100644
--- a/core/java/android/os/Trace.java
+++ b/core/java/android/os/Trace.java
@@ -395,19 +395,6 @@
}
/**
- * @deprecated use asyncTraceForTrackEnd without methodName argument
- *
- * @hide
- */
- @Deprecated
- public static void asyncTraceForTrackEnd(long traceTag,
- @NonNull String trackName, @NonNull String methodName, int cookie) {
- if (isTagEnabled(traceTag)) {
- nativeAsyncTraceForTrackEnd(traceTag, trackName, cookie);
- }
- }
-
- /**
* Writes a trace message to indicate that a given section of code was invoked.
*
* @param traceTag The trace tag.
diff --git a/core/java/android/os/UserManager.java b/core/java/android/os/UserManager.java
index fc02524..b016c781 100644
--- a/core/java/android/os/UserManager.java
+++ b/core/java/android/os/UserManager.java
@@ -1472,6 +1472,21 @@
public static final String DISALLOW_BIOMETRIC = "disallow_biometric";
/**
+ * Specifies whether the user is allowed to modify default apps in settings.
+ *
+ * <p>This restriction can be set by device or profile owner.
+ *
+ * <p>The default value is <code>false</code>.
+ *
+ * <p>Key for user restrictions.
+ * <p>Type: Boolean
+ * @see DevicePolicyManager#addUserRestriction(ComponentName, String)
+ * @see DevicePolicyManager#clearUserRestriction(ComponentName, String)
+ * @see #getUserRestrictions()
+ */
+ public static final String DISALLOW_CONFIG_DEFAULT_APPS = "disallow_config_default_apps";
+
+ /**
* Application restriction key that is used to indicate the pending arrival
* of real restrictions for the app.
*
@@ -1827,6 +1842,15 @@
public static final int REMOVE_RESULT_ERROR_SYSTEM_USER = -4;
/**
+ * A response code from {@link #removeUserWhenPossible(UserHandle, boolean)} indicating that
+ * user being removed is a {@link UserInfo#FLAG_MAIN} user and can't be removed because
+ * system property {@link com.android.internal.R.bool.isMainUserPermanentAdmin} is true.
+ * @hide
+ */
+ @SystemApi
+ public static final int REMOVE_RESULT_ERROR_MAIN_USER_PERMANENT_ADMIN = -5;
+
+ /**
* Possible response codes from {@link #removeUserWhenPossible(UserHandle, boolean)}.
*
* @hide
@@ -1838,6 +1862,7 @@
REMOVE_RESULT_ERROR_USER_RESTRICTION,
REMOVE_RESULT_ERROR_USER_NOT_FOUND,
REMOVE_RESULT_ERROR_SYSTEM_USER,
+ REMOVE_RESULT_ERROR_MAIN_USER_PERMANENT_ADMIN,
REMOVE_RESULT_ERROR_UNKNOWN,
})
@Retention(RetentionPolicy.SOURCE)
@@ -5236,8 +5261,9 @@
* @return the {@link RemoveResult} code: {@link #REMOVE_RESULT_REMOVED},
* {@link #REMOVE_RESULT_DEFERRED}, {@link #REMOVE_RESULT_ALREADY_BEING_REMOVED},
* {@link #REMOVE_RESULT_ERROR_USER_RESTRICTION}, {@link #REMOVE_RESULT_ERROR_USER_NOT_FOUND},
- * {@link #REMOVE_RESULT_ERROR_SYSTEM_USER}, or {@link #REMOVE_RESULT_ERROR_UNKNOWN}. All error
- * codes have negative values.
+ * {@link #REMOVE_RESULT_ERROR_SYSTEM_USER},
+ * {@link #REMOVE_RESULT_ERROR_MAIN_USER_PERMANENT_ADMIN}, or
+ * {@link #REMOVE_RESULT_ERROR_UNKNOWN}. All error codes have negative values.
*
* @hide
*/
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index 2bdd360..ec3ef9d 100644
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -22,6 +22,8 @@
import android.annotation.IntRange;
import android.annotation.NonNull;
import android.annotation.Nullable;
+import android.annotation.PermissionMethod;
+import android.annotation.PermissionName;
import android.annotation.RequiresPermission;
import android.annotation.SdkConstant;
import android.annotation.SdkConstant.SdkConstantType;
@@ -48,7 +50,6 @@
import android.content.pm.ActivityInfo;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager;
-import android.content.pm.PermissionName;
import android.content.pm.ResolveInfo;
import android.content.res.Configuration;
import android.content.res.Resources;
@@ -1079,6 +1080,17 @@
"android.settings.APP_LOCALE_SETTINGS";
/**
+ * Activity Action: Show settings to allow configuration of regional preferences
+ * <p>
+ * Input: Nothing
+ * <p>
+ * Output: Nothing.
+ */
+ @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION)
+ public static final String ACTION_REGIONAL_PREFERENCES_SETTINGS =
+ "android.settings.REGIONAL_PREFERENCES_SETTINGS";
+
+ /**
* Activity Action: Show settings to allow configuration of lockscreen.
* <p>
* In some cases, a matching Activity may not exist, so ensure you
@@ -2501,6 +2513,7 @@
*
* @hide
*/
+ @SystemApi
@SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
public static final String ACTION_SHOW_RESTRICTED_SETTING_DIALOG =
"android.settings.SHOW_RESTRICTED_SETTING_DIALOG";
@@ -9974,11 +9987,10 @@
"fingerprint_side_fps_auth_downtime";
/**
- * Whether or not a SFPS device is required to be interactive for auth to unlock the device.
+ * Whether or not a SFPS device is enabling the performant auth setting.
* @hide
*/
- public static final String SFPS_REQUIRE_SCREEN_ON_TO_AUTH_ENABLED =
- "sfps_require_screen_on_to_auth_enabled";
+ public static final String SFPS_PERFORMANT_AUTH_ENABLED = "sfps_performant_auth_enabled";
/**
* Whether or not debugging is enabled.
@@ -18088,6 +18100,14 @@
* @hide
*/
public static final int EARLY_UPDATES_STATUS_ABORTED = 4;
+
+ /**
+ * Whether dynamic color theming (e.g. Material You) is enabled for apps which support
+ * it.
+ *
+ * @hide
+ */
+ public static final String DYNAMIC_COLOR_THEME_ENABLED = "dynamic_color_theme_enabled";
}
}
@@ -18483,6 +18503,8 @@
* @see #checkCallingPermission
* @hide
*/
+ @PermissionMethod(orSelf = true)
+ @PackageManager.PermissionResult
public static int checkCallingOrSelfPermission(@NonNull @PermissionName String permission) {
return ActivityThread.currentApplication()
.getApplicationContext().checkCallingOrSelfPermission(permission);
diff --git a/core/java/android/security/net/config/SystemCertificateSource.java b/core/java/android/security/net/config/SystemCertificateSource.java
index 4892312..13f7e5d 100644
--- a/core/java/android/security/net/config/SystemCertificateSource.java
+++ b/core/java/android/security/net/config/SystemCertificateSource.java
@@ -41,7 +41,7 @@
private static File getDirectory() {
// TODO(miguelaranda): figure out correct code path.
File updatable_dir = new File("/apex/com.android.conscrypt/cacerts");
- if (updatable_dir.exists()) {
+ if (updatable_dir.exists() && !(updatable_dir.list().length == 0)) {
return updatable_dir;
}
return new File(System.getenv("ANDROID_ROOT") + "/etc/security/cacerts");
diff --git a/core/java/android/security/rkp/IRegistration.aidl b/core/java/android/security/rkp/IRegistration.aidl
index 6522a45..8ec13b9 100644
--- a/core/java/android/security/rkp/IRegistration.aidl
+++ b/core/java/android/security/rkp/IRegistration.aidl
@@ -17,6 +17,7 @@
package android.security.rkp;
import android.security.rkp.IGetKeyCallback;
+import android.security.rkp.IStoreUpgradedKeyCallback;
/**
* This interface is associated with the registration of an
@@ -70,16 +71,18 @@
* mechanism, see the documentation for IKeyMintDevice.upgradeKey.
*
* Once a key has been upgraded, the IRegistration where the key is stored
- * needs to be told about the new blob. After calling storeUpgradedKey,
+ * needs to be told about the new blob. After calling storeUpgradedKeyAsync,
* getKey will return the new key blob instead of the old one.
*
* Note that this function does NOT extend the lifetime of key blobs. The
* certificate for the key is unchanged, and the key will still expire at
- * the same time it would have if storeUpgradedKey had never been called.
+ * the same time it would have if storeUpgradedKeyAsync had never been called.
*
* @param oldKeyBlob The old key blob to be replaced by {@code newKeyBlob}.
- *
* @param newKeyblob The new blob to replace {@code oldKeyBlob}.
+ * @param callback Receives the result of the call. A callback must only
+ * be used with one {@code storeUpgradedKeyAsync} call at a time.
*/
- void storeUpgradedKey(in byte[] oldKeyBlob, in byte[] newKeyBlob);
+ void storeUpgradedKeyAsync(
+ in byte[] oldKeyBlob, in byte[] newKeyBlob, IStoreUpgradedKeyCallback callback);
}
diff --git a/core/java/android/security/rkp/IStoreUpgradedKeyCallback.aidl b/core/java/android/security/rkp/IStoreUpgradedKeyCallback.aidl
new file mode 100644
index 0000000..7f72fa0
--- /dev/null
+++ b/core/java/android/security/rkp/IStoreUpgradedKeyCallback.aidl
@@ -0,0 +1,39 @@
+/*
+ * 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 android.security.rkp;
+
+/**
+ * Callback interface for storing an upgraded remotely provisioned key blob.
+ * {@link IRegistration}.
+ *
+ * @hide
+ */
+oneway interface IStoreUpgradedKeyCallback {
+ /**
+ * Called in response to {@link IRegistration.storeUpgradedKeyAsync}, indicating
+ * a remotely-provisioned key is available.
+ */
+ void onSuccess();
+
+ /**
+ * Called when an error has occurred while trying to store an upgraded
+ * remotely provisioned key.
+ *
+ * @param error A description of what failed, suitable for logging.
+ */
+ void onError(String error);
+}
diff --git a/core/java/android/service/credentials/CredentialProviderInfo.java b/core/java/android/service/credentials/CredentialProviderInfo.java
index f89ad8e..6a10a6a 100644
--- a/core/java/android/service/credentials/CredentialProviderInfo.java
+++ b/core/java/android/service/credentials/CredentialProviderInfo.java
@@ -24,6 +24,7 @@
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
+import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager;
import android.content.pm.ResolveInfo;
import android.content.pm.ServiceInfo;
@@ -58,6 +59,7 @@
private final Drawable mIcon;
@Nullable
private final CharSequence mLabel;
+ private final boolean mIsSystemProvider;
/**
* Constructs an information instance of the credential provider.
@@ -65,13 +67,14 @@
* @param context the context object
* @param serviceComponent the serviceComponent of the provider service
* @param userId the android userId for which the current process is running
+ * @param isSystemProvider whether this provider is a system provider
* @throws PackageManager.NameNotFoundException If provider service is not found
* @throws SecurityException If provider does not require the relevant permission
*/
public CredentialProviderInfo(@NonNull Context context,
- @NonNull ComponentName serviceComponent, int userId)
+ @NonNull ComponentName serviceComponent, int userId, boolean isSystemProvider)
throws PackageManager.NameNotFoundException {
- this(context, getServiceInfoOrThrow(serviceComponent, userId));
+ this(context, getServiceInfoOrThrow(serviceComponent, userId), isSystemProvider);
}
/**
@@ -79,8 +82,11 @@
* @param context the context object
* @param serviceInfo the service info for the provider app. This must be retrieved from the
* {@code PackageManager}
+ * @param isSystemProvider whether the provider is a system app or not
*/
- public CredentialProviderInfo(@NonNull Context context, @NonNull ServiceInfo serviceInfo) {
+ public CredentialProviderInfo(@NonNull Context context,
+ @NonNull ServiceInfo serviceInfo,
+ boolean isSystemProvider) {
if (!Manifest.permission.BIND_CREDENTIAL_PROVIDER_SERVICE.equals(serviceInfo.permission)) {
Log.i(TAG, "Credential Provider Service from : " + serviceInfo.packageName
+ "does not require permission"
@@ -95,6 +101,7 @@
mLabel = mServiceInfo.loadSafeLabel(
mContext.getPackageManager(), 0 /* do not ellipsize */,
TextUtils.SAFE_STRING_FLAG_FIRST_LINE | TextUtils.SAFE_STRING_FLAG_TRIM);
+ mIsSystemProvider = isSystemProvider;
Log.i(TAG, "mLabel is : " + mLabel + ", for: " + mServiceInfo.getComponentName()
.flattenToString());
populateProviderCapabilities(context, serviceInfo);
@@ -147,6 +154,42 @@
}
/**
+ * Returns the valid credential provider services available for the user with the
+ * given {@code userId}.
+ */
+ @NonNull
+ public static List<CredentialProviderInfo> getAvailableSystemServices(
+ @NonNull Context context,
+ @UserIdInt int userId) {
+ final List<CredentialProviderInfo> services = new ArrayList<>();
+
+ final List<ResolveInfo> resolveInfos =
+ context.getPackageManager().queryIntentServicesAsUser(
+ new Intent(CredentialProviderService.SYSTEM_SERVICE_INTERFACE),
+ PackageManager.ResolveInfoFlags.of(PackageManager.GET_META_DATA),
+ userId);
+ for (ResolveInfo resolveInfo : resolveInfos) {
+ final ServiceInfo serviceInfo = resolveInfo.serviceInfo;
+ try {
+ ApplicationInfo appInfo = context.getPackageManager().getApplicationInfo(
+ serviceInfo.packageName,
+ PackageManager.ApplicationInfoFlags.of(PackageManager.MATCH_SYSTEM_ONLY));
+ if (appInfo != null
+ && context.checkPermission(Manifest.permission.SYSTEM_CREDENTIAL_PROVIDER,
+ /*pId=*/-1, appInfo.uid) == PackageManager.PERMISSION_GRANTED) {
+ services.add(new CredentialProviderInfo(context, serviceInfo,
+ /*isSystemProvider=*/true));
+ }
+ } catch (SecurityException e) {
+ Log.i(TAG, "Error getting info for " + serviceInfo + ": " + e);
+ } catch (PackageManager.NameNotFoundException e) {
+ Log.i(TAG, "Error getting info for " + serviceInfo + ": " + e);
+ }
+ }
+ return services;
+ }
+
+ /**
* Returns true if the service supports the given {@code credentialType}, false otherwise.
*/
@NonNull
@@ -160,6 +203,10 @@
return mServiceInfo;
}
+ public boolean isSystemProvider() {
+ return mIsSystemProvider;
+ }
+
/** Returns the service icon. */
@Nullable
public Drawable getServiceIcon() {
@@ -195,7 +242,8 @@
for (ResolveInfo resolveInfo : resolveInfos) {
final ServiceInfo serviceInfo = resolveInfo.serviceInfo;
try {
- services.add(new CredentialProviderInfo(context, serviceInfo));
+ services.add(new CredentialProviderInfo(context,
+ serviceInfo, false));
} catch (SecurityException e) {
Log.w(TAG, "Error getting info for " + serviceInfo + ": " + e);
}
diff --git a/core/java/android/service/credentials/CredentialProviderService.java b/core/java/android/service/credentials/CredentialProviderService.java
index 70dd16c..ee386c3 100644
--- a/core/java/android/service/credentials/CredentialProviderService.java
+++ b/core/java/android/service/credentials/CredentialProviderService.java
@@ -125,6 +125,33 @@
public static final String EXTRA_CREATE_CREDENTIAL_EXCEPTION =
"android.service.credentials.extra.CREATE_CREDENTIAL_EXCEPTION";
+ /**
+ * Intent extra: The {@link BeginGetCredentialRequest} attached with
+ * the {@code pendingIntent} that is invoked when the user selects an
+ * authentication entry (intending to unlock the provider app) on the UI.
+ *
+ * <p>When a provider app receives a {@link BeginGetCredentialRequest} through the
+ * {@link CredentialProviderService#onBeginGetCredential} call, it can construct the
+ * {@link BeginGetCredentialResponse} with either an authentication {@link Action} (if the app
+ * is locked), or a {@link CredentialsResponseContent} (if the app is unlocked). In the former
+ * case, i.e. the app is locked, user will be shown the authentication action. When selected,
+ * the underlying {@link PendingIntent} will be invoked which will lead the user to provider's
+ * unlock activity. This pending intent will also contain the original
+ * {@link BeginGetCredentialRequest} to be retrieved and processed after the unlock
+ * flow is complete.
+ *
+ * <p>After the app is unlocked, the {@link BeginGetCredentialResponse} must be constructed
+ * using a {@link CredentialsResponseContent}, which must be set on an {@link Intent} as an
+ * intent extra against CredentialProviderService#EXTRA_CREDENTIALS_RESPONSE_CONTENT}.
+ * This intent should then be set as a result through {@link android.app.Activity#setResult}
+ * before finishing the activity.
+ *
+ * <p>
+ * Type: {@link BeginGetCredentialRequest}
+ */
+ public static final String EXTRA_BEGIN_GET_CREDENTIAL_REQUEST =
+ "android.service.credentials.extra.BEGIN_GET_CREDENTIAL_REQUEST";
+
private static final String TAG = "CredProviderService";
public static final String CAPABILITY_META_DATA_KEY = "android.credentials.capabilities";
@@ -140,6 +167,20 @@
public static final String SERVICE_INTERFACE =
"android.service.credentials.CredentialProviderService";
+ /**
+ * The {@link Intent} that must be declared as handled by a system credential provider
+ * service.
+ *
+ * <p>The service must also require the
+ * {android.Manifest.permission#BIND_CREDENTIAL_PROVIDER_SERVICE} permission
+ * so that only the system can bind to it.
+ *
+ * @hide
+ */
+ @SdkConstant(SdkConstant.SdkConstantType.SERVICE_ACTION)
+ public static final String SYSTEM_SERVICE_INTERFACE =
+ "android.service.credentials.system.CredentialProviderService";
+
@CallSuper
@Override
public void onCreate() {
diff --git a/core/java/android/service/dreams/DreamActivity.java b/core/java/android/service/dreams/DreamActivity.java
index a2fa139..a389223 100644
--- a/core/java/android/service/dreams/DreamActivity.java
+++ b/core/java/android/service/dreams/DreamActivity.java
@@ -58,11 +58,13 @@
setTitle(title);
}
- final Bundle extras = getIntent().getExtras();
- mCallback = (DreamService.DreamActivityCallbacks) extras.getBinder(EXTRA_CALLBACK);
-
- if (mCallback != null) {
+ final Object callback = getIntent().getExtras().getBinder(EXTRA_CALLBACK);
+ if (callback instanceof DreamService.DreamActivityCallbacks) {
+ mCallback = (DreamService.DreamActivityCallbacks) callback;
mCallback.onActivityCreated(this);
+ } else {
+ mCallback = null;
+ finishAndRemoveTask();
}
}
diff --git a/core/java/android/service/quicksettings/TileService.java b/core/java/android/service/quicksettings/TileService.java
index 7b6ff97..d957029 100644
--- a/core/java/android/service/quicksettings/TileService.java
+++ b/core/java/android/service/quicksettings/TileService.java
@@ -24,6 +24,9 @@
import android.app.PendingIntent;
import android.app.Service;
import android.app.StatusBarManager;
+import android.app.compat.CompatChanges;
+import android.compat.annotation.ChangeId;
+import android.compat.annotation.EnabledSince;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
@@ -166,6 +169,17 @@
*/
public static final String EXTRA_STATE = "state";
+ /**
+ * The method {@link TileService#startActivityAndCollapse(Intent)} will verify that only
+ * apps targeting {@link android.os.Build.VERSION_CODES#UPSIDE_DOWN_CAKE} or higher will
+ * not be allowed to use it.
+ *
+ * @hide
+ */
+ @ChangeId
+ @EnabledSince(targetSdkVersion = Build.VERSION_CODES.UPSIDE_DOWN_CAKE)
+ public static final long START_ACTIVITY_NEEDS_PENDING_INTENT = 241766793L;
+
private final H mHandler = new H(Looper.getMainLooper());
private boolean mListening = false;
@@ -251,7 +265,6 @@
* This will collapse the Quick Settings panel and show the dialog.
*
* @param dialog Dialog to show.
- *
* @see #isLocked()
*/
public final void showDialog(Dialog dialog) {
@@ -330,8 +343,19 @@
/**
* Start an activity while collapsing the panel.
+ *
+ * @deprecated for versions {@link android.os.Build.VERSION_CODES#UPSIDE_DOWN_CAKE} and up,
+ * use {@link TileService#startActivityAndCollapse(PendingIntent)} instead.
+ * @throws UnsupportedOperationException if called in versions
+ * {@link android.os.Build.VERSION_CODES#UPSIDE_DOWN_CAKE} and up
*/
+ @Deprecated
public final void startActivityAndCollapse(Intent intent) {
+ if (CompatChanges.isChangeEnabled(START_ACTIVITY_NEEDS_PENDING_INTENT)) {
+ throw new UnsupportedOperationException(
+ "startActivityAndCollapse: Starting activity from TileService using an Intent"
+ + " is not allowed.");
+ }
startActivity(intent);
try {
mService.onStartActivity(mTileToken);
@@ -410,7 +434,7 @@
}
@Override
- public void onUnlockComplete() throws RemoteException{
+ public void onUnlockComplete() throws RemoteException {
mHandler.sendEmptyMessage(H.MSG_UNLOCK_COMPLETE);
}
};
diff --git a/core/java/android/text/SegmentFinder.java b/core/java/android/text/SegmentFinder.java
index be0094b..047d07a 100644
--- a/core/java/android/text/SegmentFinder.java
+++ b/core/java/android/text/SegmentFinder.java
@@ -74,7 +74,7 @@
/**
* The default {@link SegmentFinder} implementation based on given segment ranges.
*/
- public static class DefaultSegmentFinder extends SegmentFinder {
+ public static class PrescribedSegmentFinder extends SegmentFinder {
private final int[] mSegments;
/**
@@ -87,7 +87,7 @@
* @throws IllegalArgumentException if the given segments array's length is not even; the
* given segments are not sorted or there are segments overlap with others.
*/
- public DefaultSegmentFinder(@NonNull int[] segments) {
+ public PrescribedSegmentFinder(@NonNull int[] segments) {
checkSegmentsValid(segments);
mSegments = segments;
}
diff --git a/core/java/android/text/TextShaper.java b/core/java/android/text/TextShaper.java
index a1d6cc8..6da0b63 100644
--- a/core/java/android/text/TextShaper.java
+++ b/core/java/android/text/TextShaper.java
@@ -173,7 +173,7 @@
private TextShaper() {}
/**
- * An consumer interface for accepting text shape result.
+ * A consumer interface for accepting text shape result.
*/
public interface GlyphsConsumer {
/**
diff --git a/core/java/android/util/FeatureFlagUtils.java b/core/java/android/util/FeatureFlagUtils.java
index 493c800..70b04a1 100644
--- a/core/java/android/util/FeatureFlagUtils.java
+++ b/core/java/android/util/FeatureFlagUtils.java
@@ -158,6 +158,14 @@
*/
public static final String SETTINGS_FLASH_ALERTS = "settings_flash_alerts";
+ /**
+ * Flag to disable/enable showing udfps enroll view in settings. If it's disabled, udfps enroll
+ * view is shown in system ui.
+ * @hide
+ */
+ public static final String SETTINGS_SHOW_UDFPS_ENROLL_IN_SETTINGS =
+ "settings_show_udfps_enroll_in_settings";
+
private static final Map<String, String> DEFAULT_FLAGS;
static {
@@ -198,6 +206,7 @@
DEFAULT_FLAGS.put(SETTINGS_PREFER_ACCESSIBILITY_MENU_IN_SYSTEM, "false");
DEFAULT_FLAGS.put(SETTINGS_AUDIO_ROUTING, "false");
DEFAULT_FLAGS.put(SETTINGS_FLASH_ALERTS, "false");
+ DEFAULT_FLAGS.put(SETTINGS_SHOW_UDFPS_ENROLL_IN_SETTINGS, "false");
}
private static final Set<String> PERSISTENT_FLAGS;
diff --git a/core/java/android/view/ISurfaceControlViewHost.aidl b/core/java/android/view/ISurfaceControlViewHost.aidl
index bf72a30..15008ae 100644
--- a/core/java/android/view/ISurfaceControlViewHost.aidl
+++ b/core/java/android/view/ISurfaceControlViewHost.aidl
@@ -19,13 +19,19 @@
import android.content.res.Configuration;
import android.graphics.Rect;
import android.view.InsetsState;
+import android.window.ISurfaceSyncGroup;
/**
* API from content embedder back to embedded content in SurfaceControlViewHost
* {@hide}
*/
-oneway interface ISurfaceControlViewHost {
- void onConfigurationChanged(in Configuration newConfig);
- void onDispatchDetachedFromWindow();
- void onInsetsChanged(in InsetsState state, in Rect insetFrame);
+interface ISurfaceControlViewHost {
+ /**
+ * TODO (b/263273252): Investigate the need for these to be blocking calls or add additional
+ * APIs that are blocking
+ */
+ oneway void onConfigurationChanged(in Configuration newConfig);
+ oneway void onDispatchDetachedFromWindow();
+ oneway void onInsetsChanged(in InsetsState state, in Rect insetFrame);
+ ISurfaceSyncGroup getSurfaceSyncGroup();
}
diff --git a/core/java/android/view/IWindowManager.aidl b/core/java/android/view/IWindowManager.aidl
index e38e537..9fdda29 100644
--- a/core/java/android/view/IWindowManager.aidl
+++ b/core/java/android/view/IWindowManager.aidl
@@ -65,6 +65,8 @@
import android.view.SurfaceControl;
import android.view.displayhash.DisplayHash;
import android.view.displayhash.VerifiedDisplayHash;
+import android.window.AddToSurfaceSyncGroupResult;
+import android.window.ISurfaceSyncGroupCompletedListener;
import android.window.ITaskFpsCallback;
import android.window.ScreenCapture;
@@ -984,4 +986,18 @@
* @return {@code true} if the key will be handled globally.
*/
boolean isGlobalKey(int keyCode);
+
+ /**
+ * Create or add to a SurfaceSyncGroup in WindowManager. WindowManager maintains some
+ * SurfaceSyncGroups to ensure multiple processes can sync with each other without sharing
+ * SurfaceControls
+ */
+ boolean addToSurfaceSyncGroup(in IBinder syncGroupToken, boolean parentSyncGroupMerge,
+ in @nullable ISurfaceSyncGroupCompletedListener completedListener,
+ out AddToSurfaceSyncGroupResult addToSurfaceSyncGroupResult);
+
+ /**
+ * Mark a SurfaceSyncGroup stored in WindowManager as ready.
+ */
+ oneway void markSurfaceSyncGroupReady(in IBinder syncGroupToken);
}
diff --git a/core/java/android/view/InputDevice.java b/core/java/android/view/InputDevice.java
index 5a9a252..8683cc2 100644
--- a/core/java/android/view/InputDevice.java
+++ b/core/java/android/view/InputDevice.java
@@ -555,6 +555,7 @@
private String mKeyboardLanguageTag = null;
private String mKeyboardLayoutType = null;
private boolean mSupportsUsi = false;
+ private List<MotionRange> mMotionRanges = new ArrayList<>();
/** @see InputDevice#getId() */
public Builder setId(int id) {
@@ -670,12 +671,50 @@
return this;
}
+ /** @see InputDevice#getMotionRanges() */
+ public Builder addMotionRange(int axis, int source,
+ float min, float max, float flat, float fuzz, float resolution) {
+ mMotionRanges.add(new MotionRange(axis, source, min, max, flat, fuzz, resolution));
+ return this;
+ }
+
/** Build {@link InputDevice}. */
public InputDevice build() {
- return new InputDevice(mId, mGeneration, mControllerNumber, mName, mVendorId,
- mProductId, mDescriptor, mIsExternal, mSources, mKeyboardType, mKeyCharacterMap,
- mKeyboardLanguageTag, mKeyboardLayoutType, mHasVibrator, mHasMicrophone,
- mHasButtonUnderPad, mHasSensor, mHasBattery, mSupportsUsi);
+ InputDevice device = new InputDevice(
+ mId,
+ mGeneration,
+ mControllerNumber,
+ mName,
+ mVendorId,
+ mProductId,
+ mDescriptor,
+ mIsExternal,
+ mSources,
+ mKeyboardType,
+ mKeyCharacterMap,
+ mKeyboardLanguageTag,
+ mKeyboardLayoutType,
+ mHasVibrator,
+ mHasMicrophone,
+ mHasButtonUnderPad,
+ mHasSensor,
+ mHasBattery,
+ mSupportsUsi);
+
+ final int numRanges = mMotionRanges.size();
+ for (int i = 0; i < numRanges; i++) {
+ final MotionRange range = mMotionRanges.get(i);
+ device.addMotionRange(
+ range.getAxis(),
+ range.getSource(),
+ range.getMin(),
+ range.getMax(),
+ range.getFlat(),
+ range.getFuzz(),
+ range.getResolution());
+ }
+
+ return device;
}
}
@@ -1378,7 +1417,8 @@
out.writeInt(mHasBattery ? 1 : 0);
out.writeInt(mSupportsUsi ? 1 : 0);
- final int numRanges = mMotionRanges.size();
+ int numRanges = mMotionRanges.size();
+ numRanges = numRanges > MAX_RANGES ? MAX_RANGES : numRanges;
out.writeInt(numRanges);
for (int i = 0; i < numRanges; i++) {
MotionRange range = mMotionRanges.get(i);
diff --git a/core/java/android/view/MotionEvent.java b/core/java/android/view/MotionEvent.java
index 1ff7ae6..b91019c 100644
--- a/core/java/android/view/MotionEvent.java
+++ b/core/java/android/view/MotionEvent.java
@@ -1293,6 +1293,23 @@
*/
public static final int AXIS_GESTURE_Y_OFFSET = 49;
+ /**
+ * Axis constant: X scroll distance axis of a motion event.
+ * <p>
+ * <ul>
+ * <li>For a touch pad, reports the distance that should be scrolled in the X axis as a result
+ * of the user's two-finger scroll gesture, in display pixels.
+ * </ul>
+ */
+ public static final int AXIS_GESTURE_SCROLL_X_DISTANCE = 50;
+
+ /**
+ * Axis constant: Y scroll distance axis of a motion event.
+ *
+ * The same as {@link #AXIS_GESTURE_SCROLL_X_DISTANCE}, but for the Y axis.
+ */
+ public static final int AXIS_GESTURE_SCROLL_Y_DISTANCE = 51;
+
// NOTE: If you add a new axis here you must also add it to:
// frameworks/native/include/android/input.h
// frameworks/native/libs/input/InputEventLabels.cpp
@@ -1350,6 +1367,8 @@
names.append(AXIS_GENERIC_16, "AXIS_GENERIC_16");
names.append(AXIS_GESTURE_X_OFFSET, "AXIS_GESTURE_X_OFFSET");
names.append(AXIS_GESTURE_Y_OFFSET, "AXIS_GESTURE_Y_OFFSET");
+ names.append(AXIS_GESTURE_SCROLL_X_DISTANCE, "AXIS_GESTURE_SCROLL_X_DISTANCE");
+ names.append(AXIS_GESTURE_SCROLL_Y_DISTANCE, "AXIS_GESTURE_SCROLL_Y_DISTANCE");
}
/**
@@ -4234,6 +4253,13 @@
public float relativeY;
/**
+ * Whether these coordinate data were generated by resampling.
+ *
+ * @hide
+ */
+ public boolean isResampled;
+
+ /**
* Clears the contents of this object.
* Resets all axes to zero.
*/
@@ -4251,6 +4277,7 @@
orientation = 0;
relativeX = 0;
relativeY = 0;
+ isResampled = false;
}
/**
@@ -4283,6 +4310,7 @@
orientation = other.orientation;
relativeX = other.relativeX;
relativeY = other.relativeY;
+ isResampled = other.isResampled;
}
/**
diff --git a/core/java/android/view/MotionPredictor.java b/core/java/android/view/MotionPredictor.java
new file mode 100644
index 0000000..3e58a31
--- /dev/null
+++ b/core/java/android/view/MotionPredictor.java
@@ -0,0 +1,116 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.view;
+
+import android.annotation.NonNull;
+import android.content.Context;
+
+import libcore.util.NativeAllocationRegistry;
+
+import java.util.Arrays;
+import java.util.List;
+
+/**
+ * Calculates motion predictions.
+ *
+ * Add motions here to get predicted events!
+ * @hide
+ */
+// Acts as a pass-through to the native MotionPredictor object.
+// Do not store any state in this Java layer, or add any business logic here. All of the
+// implementation details should go into the native MotionPredictor.
+// The context / resource access must be here rather than in native layer due to the lack of the
+// corresponding native API surface.
+public final class MotionPredictor {
+
+ private static class RegistryHolder {
+ public static final NativeAllocationRegistry REGISTRY =
+ NativeAllocationRegistry.createMalloced(
+ MotionPredictor.class.getClassLoader(),
+ nativeGetNativeMotionPredictorFinalizer());
+ }
+
+ // Pointer to the native object.
+ private final long mPtr;
+ private final Context mContext;
+
+ /**
+ * Create a new MotionPredictor for the provided {@link Context}.
+ * @param context The context for the predictions
+ */
+ public MotionPredictor(@NonNull Context context) {
+ mContext = context;
+ final int offsetNanos = mContext.getResources().getInteger(
+ com.android.internal.R.integer.config_motionPredictionOffsetNanos);
+ mPtr = nativeInitialize(offsetNanos);
+ RegistryHolder.REGISTRY.registerNativeAllocation(this, mPtr);
+ }
+
+ /**
+ * Record a movement so that in the future, a prediction for the current gesture can be
+ * generated. Ensure to add all motions from the gesture of interest to generate the correct
+ * prediction.
+ * @param event The received event
+ */
+ public void record(@NonNull MotionEvent event) {
+ nativeRecord(mPtr, event);
+ }
+
+ /**
+ * Get predicted events for all gestures that have been provided to the 'record' function.
+ * If events from multiple devices were sent to 'record', this will produce a separate
+ * {@link MotionEvent} for each device id. The returned list may be empty if no predictions for
+ * any of the added events are available.
+ * Predictions may not reach the requested timestamp if the confidence in the prediction results
+ * is low.
+ *
+ * @param predictionTimeNanos The time that the prediction should target, in the
+ * {@link android.os.SystemClock#uptimeMillis} time base, but in nanoseconds.
+ *
+ * @return the list of predicted motion events, for each device id. Ensure to check the
+ * historical data in addition to the latest ({@link MotionEvent#getX getX()},
+ * {@link MotionEvent#getY getY()}) coordinates for smoothest prediction curves. Empty list is
+ * returned if predictions are not supported, or not possible for the current set of gestures.
+ */
+ @NonNull
+ public List<MotionEvent> predict(long predictionTimeNanos) {
+ return Arrays.asList(nativePredict(mPtr, predictionTimeNanos));
+ }
+
+ /**
+ * Check whether this device supports motion predictions for the given source type.
+ *
+ * @param deviceId The input device id
+ * @param source The source of input events
+ * @return True if the current device supports predictions, false otherwise.
+ */
+ public boolean isPredictionAvailable(int deviceId, int source) {
+ // Device-specific override
+ if (!mContext.getResources().getBoolean(
+ com.android.internal.R.bool.config_enableMotionPrediction)) {
+ return false;
+ }
+ return nativeIsPredictionAvailable(mPtr, deviceId, source);
+ }
+
+ private static native long nativeInitialize(int offsetNanos);
+ private static native void nativeRecord(long nativePtr, MotionEvent event);
+ private static native MotionEvent[] nativePredict(long nativePtr, long predictionTimeNanos);
+ private static native boolean nativeIsPredictionAvailable(long nativePtr, int deviceId,
+ int source);
+ private static native long nativeGetNativeMotionPredictorFinalizer();
+}
diff --git a/core/java/android/view/SurfaceControlViewHost.java b/core/java/android/view/SurfaceControlViewHost.java
index 134625e..3efbb75 100644
--- a/core/java/android/view/SurfaceControlViewHost.java
+++ b/core/java/android/view/SurfaceControlViewHost.java
@@ -29,9 +29,14 @@
import android.os.RemoteException;
import android.util.Log;
import android.view.accessibility.IAccessibilityEmbeddedConnection;
+import android.window.ISurfaceSyncGroup;
import android.window.WindowTokenClient;
import java.util.Objects;
+import java.util.concurrent.CompletableFuture;
+import java.util.concurrent.ExecutionException;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.TimeoutException;
/**
* Utility class for adding a View hierarchy to a {@link SurfaceControl}. The View hierarchy
@@ -87,6 +92,19 @@
}
mWm.setInsetsState(state);
}
+
+ @Override
+ public ISurfaceSyncGroup getSurfaceSyncGroup() {
+ CompletableFuture<ISurfaceSyncGroup> surfaceSyncGroup = new CompletableFuture<>();
+ mViewRoot.mHandler.post(
+ () -> surfaceSyncGroup.complete(mViewRoot.getOrCreateSurfaceSyncGroup()));
+ try {
+ return surfaceSyncGroup.get(1, TimeUnit.SECONDS);
+ } catch (InterruptedException | ExecutionException | TimeoutException e) {
+ Log.e(TAG, "Failed to get SurfaceSyncGroup for SCVH", e);
+ }
+ return null;
+ }
}
private ISurfaceControlViewHost mRemoteInterface = new ISurfaceControlViewHostImpl();
@@ -274,7 +292,7 @@
public SurfaceControlViewHost(@NonNull Context c, @NonNull Display d,
@NonNull WindowlessWindowManager wwm) {
mWm = wwm;
- mViewRoot = new ViewRootImpl(c, d, mWm, new WindowlessWindowLayout());
+ mViewRoot = new ViewRootImpl(c, d, mWm);
addConfigCallback(c, d);
WindowManagerGlobal.getInstance().addWindowlessRoot(mViewRoot);
@@ -304,7 +322,7 @@
mWm = new WindowlessWindowManager(context.getResources().getConfiguration(),
mSurfaceControl, hostToken);
- mViewRoot = new ViewRootImpl(context, display, mWm, new WindowlessWindowLayout());
+ mViewRoot = new ViewRootImpl(context, display, mWm);
addConfigCallback(context, display);
WindowManagerGlobal.getInstance().addWindowlessRoot(mViewRoot);
diff --git a/core/java/android/view/SurfaceView.java b/core/java/android/view/SurfaceView.java
index c64a2e8..e559a71 100644
--- a/core/java/android/view/SurfaceView.java
+++ b/core/java/android/view/SurfaceView.java
@@ -1091,7 +1091,8 @@
t = syncBufferTransactionCallback.waitForTransaction();
}
- surfaceSyncGroup.onTransactionReady(t);
+ surfaceSyncGroup.addTransactionToSync(t);
+ surfaceSyncGroup.markSyncReady();
onDrawFinished();
});
}
@@ -1106,7 +1107,7 @@
synchronized (mSyncGroups) {
mSyncGroups.remove(surfaceSyncGroup);
}
- surfaceSyncGroup.onTransactionReady(null);
+ surfaceSyncGroup.markSyncReady();
onDrawFinished();
});
diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java
index 0198457..c73cfc2 100644
--- a/core/java/android/view/View.java
+++ b/core/java/android/view/View.java
@@ -141,6 +141,7 @@
import android.view.animation.Animation;
import android.view.animation.AnimationUtils;
import android.view.animation.Transformation;
+import android.view.autofill.AutofillFeatureFlags;
import android.view.autofill.AutofillId;
import android.view.autofill.AutofillManager;
import android.view.autofill.AutofillValue;
@@ -3662,6 +3663,12 @@
* Indicates that the view enables auto handwriting initiation.
*/
private static final int PFLAG4_AUTO_HANDWRITING_ENABLED = 0x000010000;
+
+ /**
+ * Indicates that the view is important for Credential Manager.
+ */
+ private static final int PFLAG4_IMPORTANT_FOR_CREDENTIAL_MANAGER = 0x000020000;
+
/* End of masks for mPrivateFlags4 */
/** @hide */
@@ -6130,6 +6137,12 @@
setImportantForContentCapture(a.getInt(attr,
IMPORTANT_FOR_CONTENT_CAPTURE_AUTO));
}
+ break;
+ case R.styleable.View_isCredential:
+ if (a.peekValue(attr) != null) {
+ setIsCredential(a.getBoolean(attr, false));
+ }
+ break;
case R.styleable.View_defaultFocusHighlightEnabled:
if (a.peekValue(attr) != null) {
setDefaultFocusHighlightEnabled(a.getBoolean(attr, true));
@@ -10234,6 +10247,10 @@
private boolean isAutofillable() {
if (getAutofillType() == AUTOFILL_TYPE_NONE) return false;
+ // Disable triggering autofill if the view is integrated with CredentialManager.
+ if (AutofillFeatureFlags.shouldIgnoreCredentialViews()
+ && isCredential()) return false;
+
if (!isImportantForAutofill()) {
// View is not important for "regular" autofill, so we must check if Augmented Autofill
// is enabled for the activity
@@ -31861,6 +31878,37 @@
}
/**
+ * Gets the mode for determining whether this view is a credential.
+ *
+ * <p>See {@link #isCredential()}.
+ *
+ * @param isCredential Whether the view is a credential.
+ *
+ * @attr ref android.R.styleable#View_isCredential
+ */
+ public void setIsCredential(boolean isCredential) {
+ if (isCredential) {
+ mPrivateFlags4 |= PFLAG4_IMPORTANT_FOR_CREDENTIAL_MANAGER;
+ } else {
+ mPrivateFlags4 &= ~PFLAG4_IMPORTANT_FOR_CREDENTIAL_MANAGER;
+ }
+ }
+
+ /**
+ * Gets the mode for determining whether this view is a credential.
+ *
+ * <p>See {@link #setIsCredential(boolean)}.
+ *
+ * @return false by default, or value passed to {@link #setIsCredential(boolean)}.
+ *
+ * @attr ref android.R.styleable#View_isCredential
+ */
+ public boolean isCredential() {
+ return ((mPrivateFlags4 & PFLAG4_IMPORTANT_FOR_CREDENTIAL_MANAGER)
+ == PFLAG4_IMPORTANT_FOR_CREDENTIAL_MANAGER);
+ }
+
+ /**
* Set whether this view enables automatic handwriting initiation.
*
* For a view with an active {@link InputConnection}, if auto handwriting is enabled then
diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java
index 41c8728..2114ce7 100644
--- a/core/java/android/view/ViewRootImpl.java
+++ b/core/java/android/view/ViewRootImpl.java
@@ -227,9 +227,11 @@
import java.util.HashSet;
import java.util.List;
import java.util.Objects;
+import java.util.OptionalInt;
import java.util.Queue;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.Executor;
+import java.util.function.Consumer;
/**
* The top of a view hierarchy, implementing the needed protocol between View
@@ -860,6 +862,8 @@
// animations until all are done.
private static int sNumSyncsInProgress = 0;
+ private int mNumPausedForSync = 0;
+
private HashSet<ScrollCaptureCallback> mRootScrollCaptureCallbacks;
private long mScrollCaptureRequestTimeout = SCROLL_CAPTURE_REQUEST_TIMEOUT_MILLIS;
@@ -917,14 +921,13 @@
private String mTag = TAG;
public ViewRootImpl(Context context, Display display) {
- this(context, display, WindowManagerGlobal.getWindowSession(), new WindowLayout());
+ this(context, display, WindowManagerGlobal.getWindowSession());
}
- public ViewRootImpl(@UiContext Context context, Display display, IWindowSession session,
- WindowLayout windowLayout) {
+ public ViewRootImpl(@UiContext Context context, Display display, IWindowSession session) {
mContext = context;
mWindowSession = session;
- mWindowLayout = windowLayout;
+ mWindowLayout = new WindowLayout();
mDisplay = display;
mBasePackageName = context.getBasePackageName();
mThread = Thread.currentThread();
@@ -1107,6 +1110,8 @@
// Update the last resource config in case the resource configuration was changed while
// activity relaunched.
updateLastConfigurationFromResources(getConfiguration());
+ // Make sure to report the completion of draw for relaunch with preserved window.
+ reportNextDraw("rebuilt");
}
private Configuration getConfiguration() {
@@ -1421,7 +1426,7 @@
!= AccessibilityWindowInfo.UNDEFINED_WINDOW_ID;
if (registered) {
final AccessibilityWindowAttributes attributes = new AccessibilityWindowAttributes(
- mWindowAttributes);
+ mWindowAttributes, mContext.getResources().getConfiguration().getLocales());
if (!attributes.equals(mAccessibilityWindowAttributes)) {
mAccessibilityWindowAttributes = attributes;
mAccessibilityManager.setAccessibilityWindowAttributes(getDisplayId(),
@@ -2808,6 +2813,19 @@
return;
}
+ if (mNumPausedForSync > 0) {
+ if (Trace.isTagEnabled(Trace.TRACE_TAG_VIEW)) {
+ Trace.instant(Trace.TRACE_TAG_VIEW,
+ TextUtils.formatSimple("performTraversals#mNumPausedForSync=%d",
+ mNumPausedForSync));
+ }
+ if (DEBUG_BLAST) {
+ Log.d(mTag, "Skipping traversal due to sync " + mNumPausedForSync);
+ }
+ mLastPerformTraversalsSkipDrawReason = "paused_for_sync";
+ return;
+ }
+
mIsInTraversal = true;
mWillDrawSoon = true;
boolean cancelDraw = false;
@@ -3669,7 +3687,7 @@
}
if (mActiveSurfaceSyncGroup != null) {
- mActiveSurfaceSyncGroup.onTransactionReady(null);
+ mActiveSurfaceSyncGroup.markSyncReady();
}
} else if (cancelAndRedraw) {
mLastPerformTraversalsSkipDrawReason = cancelDueToPreDrawListener
@@ -3685,7 +3703,7 @@
mPendingTransitions.clear();
}
if (!performDraw() && mActiveSurfaceSyncGroup != null) {
- mActiveSurfaceSyncGroup.onTransactionReady(null);
+ mActiveSurfaceSyncGroup.markSyncReady();
}
}
@@ -3702,7 +3720,7 @@
mActiveSurfaceSyncGroup = null;
mSyncBuffer = false;
if (isInWMSRequestedSync()) {
- mWmsRequestSyncGroup.onTransactionReady(null);
+ mWmsRequestSyncGroup.markSyncReady();
mWmsRequestSyncGroup = null;
mWmsRequestSyncGroupState = WMS_SYNC_NONE;
}
@@ -4544,7 +4562,7 @@
if (mSurfaceHolder != null && mSurface.isValid()) {
final SurfaceSyncGroup surfaceSyncGroup = mActiveSurfaceSyncGroup;
SurfaceCallbackHelper sch = new SurfaceCallbackHelper(() ->
- mHandler.post(() -> surfaceSyncGroup.onTransactionReady(null)));
+ mHandler.post(() -> surfaceSyncGroup.markSyncReady()));
mActiveSurfaceSyncGroup = null;
SurfaceHolder.Callback callbacks[] = mSurfaceHolder.getCallbacks();
@@ -4557,7 +4575,7 @@
}
}
if (mActiveSurfaceSyncGroup != null && !usingAsyncReport) {
- mActiveSurfaceSyncGroup.onTransactionReady(null);
+ mActiveSurfaceSyncGroup.markSyncReady();
}
if (mPerformContentCapture) {
performContentCaptureInitialReport();
@@ -10850,6 +10868,12 @@
public View mSource;
public long mLastEventTimeMillis;
/**
+ * Keep track of action that caused the event.
+ * This is empty if there's no performing actions for pending events.
+ * This is zero if there're multiple events performed for pending events.
+ */
+ @NonNull public OptionalInt mAction = OptionalInt.empty();
+ /**
* Override for {@link AccessibilityEvent#originStackTrace} to provide the stack trace
* of the original {@link #runOrPost} call instead of one for sending the delayed event
* from a looper.
@@ -10872,6 +10896,7 @@
AccessibilityEvent event = AccessibilityEvent.obtain();
event.setEventType(AccessibilityEvent.TYPE_WINDOW_CONTENT_CHANGED);
event.setContentChangeTypes(mChangeTypes);
+ if (mAction.isPresent()) event.setAction(mAction.getAsInt());
if (AccessibilityEvent.DEBUG_ORIGIN) event.originStackTrace = mOrigin;
source.sendAccessibilityEventUnchecked(event);
} else {
@@ -10880,6 +10905,7 @@
// In any case reset to initial state.
source.resetSubtreeAccessibilityStateChanged();
mChangeTypes = 0;
+ mAction = OptionalInt.empty();
if (AccessibilityEvent.DEBUG_ORIGIN) mOrigin = null;
}
@@ -10909,10 +10935,27 @@
}
mSource = (predecessor != null) ? predecessor : source;
mChangeTypes |= changeType;
+
+ final int performingAction = mAccessibilityManager.getPerformingAction();
+ if (performingAction != 0) {
+ if (mAction.isEmpty()) {
+ mAction = OptionalInt.of(performingAction);
+ } else if (mAction.getAsInt() != performingAction) {
+ // Multiple actions are performed for pending events. We cannot decide one
+ // action here.
+ // We're doing best effort to set action value, and it's fine to set
+ // no action this case.
+ mAction = OptionalInt.of(0);
+ }
+ }
+
return;
}
mSource = source;
mChangeTypes = changeType;
+ if (mAccessibilityManager.getPerformingAction() != 0) {
+ mAction = OptionalInt.of(mAccessibilityManager.getPerformingAction());
+ }
if (AccessibilityEvent.DEBUG_ORIGIN) {
mOrigin = Thread.currentThread().getStackTrace();
}
@@ -11263,8 +11306,9 @@
// pendingDrawFinished.
if ((syncResult
& (SYNC_LOST_SURFACE_REWARD_IF_FOUND | SYNC_CONTEXT_IS_STOPPED)) != 0) {
- surfaceSyncGroup.onTransactionReady(
+ surfaceSyncGroup.addTransactionToSync(
mBlastBufferQueue.gatherPendingTransactions(frame));
+ surfaceSyncGroup.markSyncReady();
return null;
}
@@ -11273,8 +11317,13 @@
}
if (syncBuffer) {
- mBlastBufferQueue.syncNextTransaction(
- surfaceSyncGroup::onTransactionReady);
+ mBlastBufferQueue.syncNextTransaction(new Consumer<Transaction>() {
+ @Override
+ public void accept(Transaction transaction) {
+ surfaceSyncGroup.addTransactionToSync(transaction);
+ surfaceSyncGroup.markSyncReady();
+ }
+ });
}
return didProduceBuffer -> {
@@ -11294,8 +11343,9 @@
// since the frame didn't draw on this vsync. It's possible the frame will
// draw later, but it's better to not be sync than to block on a frame that
// may never come.
- surfaceSyncGroup.onTransactionReady(
+ surfaceSyncGroup.addTransactionToSync(
mBlastBufferQueue.gatherPendingTransactions(frame));
+ surfaceSyncGroup.markSyncReady();
return;
}
@@ -11303,22 +11353,41 @@
// syncNextTransaction callback. Instead, just report back to the Syncer so it
// knows that this sync request is complete.
if (!syncBuffer) {
- surfaceSyncGroup.onTransactionReady(null);
+ surfaceSyncGroup.markSyncReady();
}
};
}
});
}
+ private class VRISurfaceSyncGroup extends SurfaceSyncGroup {
+ VRISurfaceSyncGroup(String name) {
+ super(name);
+ }
+
+ @Override
+ public void onSyncReady() {
+ Runnable runnable = () -> {
+ mNumPausedForSync--;
+ if (!mIsInTraversal && mNumPausedForSync == 0) {
+ scheduleTraversals();
+ }
+ };
+
+ if (Thread.currentThread() == mThread) {
+ runnable.run();
+ } else {
+ mHandler.post(runnable);
+ }
+ }
+ }
+
@Override
public SurfaceSyncGroup getOrCreateSurfaceSyncGroup() {
boolean newSyncGroup = false;
if (mActiveSurfaceSyncGroup == null) {
- mActiveSurfaceSyncGroup = new SurfaceSyncGroup(mTag);
+ mActiveSurfaceSyncGroup = new VRISurfaceSyncGroup(mTag);
updateSyncInProgressCount(mActiveSurfaceSyncGroup);
- if (!mIsInTraversal && !mTraversalScheduled) {
- scheduleTraversals();
- }
newSyncGroup = true;
}
@@ -11334,6 +11403,7 @@
}
}
+ mNumPausedForSync++;
return mActiveSurfaceSyncGroup;
};
diff --git a/core/java/android/view/WindowInfo.java b/core/java/android/view/WindowInfo.java
index 11d63c8..27dca0af 100644
--- a/core/java/android/view/WindowInfo.java
+++ b/core/java/android/view/WindowInfo.java
@@ -20,6 +20,7 @@
import android.graphics.Matrix;
import android.graphics.Region;
import android.os.IBinder;
+import android.os.LocaleList;
import android.os.Parcel;
import android.os.Parcelable;
import android.util.Pools;
@@ -60,6 +61,8 @@
public MagnificationSpec mMagnificationSpec = new MagnificationSpec();
+ public LocaleList locales = LocaleList.getEmptyLocaleList();
+
private WindowInfo() {
/* do nothing - hide constructor */
}
@@ -99,6 +102,7 @@
}
}
window.mMagnificationSpec.setTo(other.mMagnificationSpec);
+ window.locales = other.locales;
return window;
}
@@ -136,6 +140,7 @@
parcel.writeInt(0);
}
mMagnificationSpec.writeToParcel(parcel, flags);
+ parcel.writeParcelable(locales, flags);
}
@Override
@@ -160,6 +165,7 @@
matrix.setValues(mTransformMatrix);
builder.append(", mTransformMatrix=").append(matrix);
builder.append(", mMagnificationSpec=").append(mMagnificationSpec);
+ builder.append(", locales=").append(locales);
builder.append(']');
return builder.toString();
}
@@ -187,6 +193,7 @@
parcel.readBinderList(childTokens);
}
mMagnificationSpec = MagnificationSpec.CREATOR.createFromParcel(parcel);
+ locales = parcel.readParcelable(null, LocaleList.class);
}
private void clear() {
@@ -210,6 +217,7 @@
mMagnificationSpec.clear();
title = null;
accessibilityIdOfAnchor = AccessibilityNodeInfo.UNDEFINED_NODE_ID;
+ locales = LocaleList.getEmptyLocaleList();
}
public static final @android.annotation.NonNull Parcelable.Creator<WindowInfo> CREATOR =
diff --git a/core/java/android/view/WindowManager.java b/core/java/android/view/WindowManager.java
index d0f0d4a..35f1787 100644
--- a/core/java/android/view/WindowManager.java
+++ b/core/java/android/view/WindowManager.java
@@ -853,6 +853,143 @@
"android.window.PROPERTY_COMPAT_IGNORE_REQUESTED_ORIENTATION";
/**
+ * Activity level {@link android.content.pm.PackageManager.Property PackageManager
+ * .Property} for an app to inform the system that the activity should be excluded from the
+ * camera compatibility force rotation treatment.
+ *
+ * <p>The camera compatibility treatment aligns orientations of portrait app window and natural
+ * orientation of the device and set opposite to natural orientation for a landscape app
+ * window. Mismatch between them can lead to camera issues like sideways or stretched
+ * viewfinder since this is one of the strongest assumptions that apps make when they implement
+ * camera previews. Since app and natural display orientations aren't guaranteed to match, the
+ * rotation can cause letterboxing. The forced rotation is triggered as soon as app opens to
+ * camera and is removed once camera is closed.
+ *
+ * <p>The camera compatibility can be enabled by device manufacturers on the displays that have
+ * ignoreOrientationRequest display setting enabled (enables compatibility mode for fixed
+ * orientation, see <a href="https://developer.android.com/guide/practices/enhanced-letterboxing">Enhanced letterboxing</a>
+ * for more details).
+ *
+ * <p>With this property set to {@code true} or unset, the system may apply the force rotation
+ * treatment to fixed orientation activities. Device manufacturers can exclude packages from the
+ * treatment using their discretion to improve display compatibility.
+ *
+ * <p>With this property set to {@code false}, the system will not apply the force rotation
+ * treatment.
+ *
+ * <p><b>Syntax:</b>
+ * <pre>
+ * <activity>
+ * <property
+ * android:name="android.window.PROPERTY_CAMERA_COMPAT_ALLOW_FORCE_ROTATION"
+ * android:value="true|false"/>
+ * </activity>
+ * </pre>
+ *
+ * @hide
+ */
+ // TODO(b/263984287): Make this public API.
+ String PROPERTY_CAMERA_COMPAT_ALLOW_FORCE_ROTATION =
+ "android.window.PROPERTY_CAMERA_COMPAT_ALLOW_FORCE_ROTATION";
+
+ /**
+ * Activity level {@link android.content.pm.PackageManager.Property PackageManager
+ * .Property} for an app to inform the system that the activity should be excluded
+ * from the activity "refresh" after the camera compatibility force rotation treatment.
+ *
+ * <p>The camera compatibility treatment aligns orientations of portrait app window and natural
+ * orientation of the device and set opposite to natural orientation for a landscape app
+ * window. Mismatch between them can lead to camera issues like sideways or stretched
+ * viewfinder since this is one of the strongest assumptions that apps make when they implement
+ * camera previews. Since app and natural display orientations aren't guaranteed to match, the
+ * rotation can cause letterboxing. The forced rotation is triggered as soon as app opens to
+ * camera and is removed once camera is closed.
+ *
+ * <p>Force rotation is followed by the "Refresh" of the activity by going through "resumed ->
+ * ... -> stopped -> ... -> resumed" cycle (by default) or "resumed -> paused -> resumed" cycle
+ * (if overridden, see {@link #PROPERTY_CAMERA_COMPAT_ENABLE_REFRESH_VIA_PAUSE} for context).
+ * This allows to clear cached values in apps (e.g. display or camera rotation) that influence
+ * camera preview and can lead to sideways or stretching issues persisting even after force
+ * rotation.
+ *
+ * <p>The camera compatibility can be enabled by device manufacturers on the displays that have
+ * ignoreOrientationRequest display setting enabled (enables compatibility mode for fixed
+ * orientation, see <a href="https://developer.android.com/guide/practices/enhanced-letterboxing">Enhanced letterboxing</a>
+ * for more details).
+ *
+ * <p>With this property set to {@code true} or unset, the system may "refresh" activity after
+ * the force rotation treatment. Device manufacturers can exclude packages from the "refresh"
+ * using their discretion to improve display compatibility.
+ *
+ * <p>With this property set to {@code false}, the system will not "refresh" activity after the
+ * force rotation treatment.
+ *
+ * <p><b>Syntax:</b>
+ * <pre>
+ * <activity>
+ * <property
+ * android:name="android.window.PROPERTY_CAMERA_COMPAT_ALLOW_REFRESH"
+ * android:value="true|false"/>
+ * </activity>
+ * </pre>
+ *
+ * @hide
+ */
+ // TODO(b/263984287): Make this public API.
+ String PROPERTY_CAMERA_COMPAT_ALLOW_REFRESH =
+ "android.window.PROPERTY_CAMERA_COMPAT_ALLOW_REFRESH";
+
+ /**
+ * Activity level {@link android.content.pm.PackageManager.Property PackageManager
+ * .Property} for an app to inform the system that the activity should be or shouldn't be
+ * "refreshed" after the camera compatibility force rotation treatment using "paused ->
+ * resumed" cycle rather than "stopped -> resumed".
+ *
+ * <p>The camera compatibility treatment aligns orientations of portrait app window and natural
+ * orientation of the device and set opposite to natural orientation for a landscape app
+ * window. Mismatch between them can lead to camera issues like sideways or stretched
+ * viewfinder since this is one of the strongest assumptions that apps make when they implement
+ * camera previews. Since app and natural display orientations aren't guaranteed to match, the
+ * rotation can cause letterboxing. The forced rotation is triggered as soon as app opens to
+ * camera and is removed once camera is closed.
+ *
+ * <p>Force rotation is followed by the "Refresh" of the activity by going through "resumed ->
+ * ... -> stopped -> ... -> resumed" cycle (by default) or "resumed -> paused -> resumed" cycle
+ * (if overridden by device manufacturers or using this property). This allows to clear cached
+ * values in apps (e.g., display or camera rotation) that influence camera preview and can lead
+ * to sideways or stretching issues persisting even after force rotation.
+ *
+ * <p>The camera compatibility can be enabled by device manufacturers on the displays that have
+ * ignoreOrientationRequest display setting enabled (enables compatibility mode for fixed
+ * orientation, see <a href="https://developer.android.com/guide/practices/enhanced-letterboxing">Enhanced letterboxing</a>
+ * for more details).
+ *
+ * <p>Device manufacturers can override packages to "refresh" via "resumed -> paused -> resumed"
+ * cycle using their discretion to improve display compatibility.
+ *
+ * <p>With this property set to {@code true}, the system will "refresh" activity after the
+ * force rotation treatment using "resumed -> paused -> resumed" cycle.
+ *
+ * <p>With this property set to {@code false}, the system will not "refresh" activity after the
+ * force rotation treatment using "resumed -> paused -> resumed" cycle even if the device
+ * manufacturer adds the corresponding override.
+ *
+ * <p><b>Syntax:</b>
+ * <pre>
+ * <activity>
+ * <property
+ * android:name="android.window.PROPERTY_CAMERA_COMPAT_ENABLE_REFRESH_VIA_PAUSE"
+ * android:value="true|false"/>
+ * </activity>
+ * </pre>
+ *
+ * @hide
+ */
+ // TODO(b/263984287): Make this public API.
+ String PROPERTY_CAMERA_COMPAT_ENABLE_REFRESH_VIA_PAUSE =
+ "android.window.PROPERTY_CAMERA_COMPAT_ENABLE_REFRESH_VIA_PAUSE";
+
+ /**
* @hide
*/
public static final String PARCEL_KEY_SHORTCUTS_ARRAY = "shortcuts_array";
diff --git a/core/java/android/view/WindowManagerGlobal.java b/core/java/android/view/WindowManagerGlobal.java
index 4a9dc5b..acc0c0b 100644
--- a/core/java/android/view/WindowManagerGlobal.java
+++ b/core/java/android/view/WindowManagerGlobal.java
@@ -388,8 +388,7 @@
if (windowlessSession == null) {
root = new ViewRootImpl(view.getContext(), display);
} else {
- root = new ViewRootImpl(view.getContext(), display,
- windowlessSession, new WindowlessWindowLayout());
+ root = new ViewRootImpl(view.getContext(), display, windowlessSession);
}
view.setLayoutParams(wparams);
diff --git a/core/java/android/view/WindowlessWindowLayout.java b/core/java/android/view/WindowlessWindowLayout.java
deleted file mode 100644
index 8ef4d78..0000000
--- a/core/java/android/view/WindowlessWindowLayout.java
+++ /dev/null
@@ -1,40 +0,0 @@
-/*
- * 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 android.view;
-
-import android.app.WindowConfiguration.WindowingMode;
-import android.graphics.Rect;
-import android.view.WindowInsets.Type.InsetsType;
-import android.window.ClientWindowFrames;
-
-/**
- * Computes window frames for the windowless window.
- * @hide
- */
-public class WindowlessWindowLayout extends WindowLayout {
-
- @Override
- public void computeFrames(WindowManager.LayoutParams attrs, InsetsState state,
- Rect displayCutoutSafe, Rect windowBounds, @WindowingMode int windowingMode,
- int requestedWidth, int requestedHeight, @InsetsType int requestedVisibleTypes,
- float compatScale, ClientWindowFrames frames) {
- frames.frame.set(0, 0, attrs.width, attrs.height);
- frames.displayFrame.set(frames.frame);
- frames.parentFrame.set(frames.frame);
- }
-}
-
diff --git a/core/java/android/view/WindowlessWindowManager.java b/core/java/android/view/WindowlessWindowManager.java
index ecb5557..4ddd485 100644
--- a/core/java/android/view/WindowlessWindowManager.java
+++ b/core/java/android/view/WindowlessWindowManager.java
@@ -17,6 +17,7 @@
package android.view;
import android.annotation.Nullable;
+import android.app.WindowConfiguration;
import android.content.res.Configuration;
import android.graphics.PixelFormat;
import android.graphics.Rect;
@@ -53,13 +54,21 @@
IBinder mInputChannelToken;
Region mInputRegion;
IWindow mClient;
- State(SurfaceControl sc, WindowManager.LayoutParams p, int displayId,
- IBinder inputChannelToken, IWindow client) {
+ SurfaceControl mLeash;
+ Rect mFrame;
+ Rect mAttachedFrame;
+
+ State(SurfaceControl sc, WindowManager.LayoutParams p,
+ int displayId, IBinder inputChannelToken, IWindow client, SurfaceControl leash,
+ Rect frame, Rect attachedFrame) {
mSurfaceControl = sc;
mParams.copyFrom(p);
mDisplayId = displayId;
mInputChannelToken = inputChannelToken;
mClient = client;
+ mLeash = leash;
+ mFrame = frame;
+ mAttachedFrame = attachedFrame;
}
};
@@ -85,6 +94,10 @@
private InsetsState mInsetsState;
private final ClientWindowFrames mTmpFrames = new ClientWindowFrames();
private final MergedConfiguration mTmpConfig = new MergedConfiguration();
+ private final InsetsState mTmpInsetsState = new InsetsState();
+ private final Rect mTmpDisplayCutoutSafe = new Rect();
+ private final Rect mTmpWindowBounds = new Rect();
+ private final WindowLayout mLayout = new WindowLayout();
public WindowlessWindowManager(Configuration c, SurfaceControl rootSurface,
IBinder hostInputToken) {
@@ -137,8 +150,15 @@
}
}
- protected void attachToParentSurface(IWindow window, SurfaceControl.Builder b) {
- b.setParent(mRootSurface);
+ protected SurfaceControl getParentSurface(IWindow window, WindowManager.LayoutParams attrs) {
+ // If this is the first window, the state map is empty and the parent surface is the
+ // root. Otherwise, the parent surface is in the state map.
+ synchronized (this) {
+ if (mStateForWindow.isEmpty()) {
+ return mRootSurface;
+ }
+ return mStateForWindow.get(attrs.token).mLeash;
+ }
}
/**
@@ -150,13 +170,20 @@
InputChannel outInputChannel, InsetsState outInsetsState,
InsetsSourceControl.Array outActiveControls, Rect outAttachedFrame,
float[] outSizeCompatScale) {
- final SurfaceControl.Builder b = new SurfaceControl.Builder(mSurfaceSession)
+ final SurfaceControl leash = new SurfaceControl.Builder(mSurfaceSession)
+ .setName(attrs.getTitle().toString() + "Leash")
+ .setCallsite("WindowlessWindowManager.addToDisplay")
+ .setParent(getParentSurface(window, attrs))
+ .build();
+
+ final SurfaceControl sc = new SurfaceControl.Builder(mSurfaceSession)
.setFormat(attrs.format)
.setBLASTLayer()
.setName(attrs.getTitle().toString())
- .setCallsite("WindowlessWindowManager.addToDisplay");
- attachToParentSurface(window, b);
- final SurfaceControl sc = b.build();
+ .setCallsite("WindowlessWindowManager.addToDisplay")
+ .setHidden(false)
+ .setParent(leash)
+ .build();
if (((attrs.inputFeatures &
WindowManager.LayoutParams.INPUT_FEATURE_NO_INPUT_CHANNEL) == 0)) {
@@ -178,11 +205,22 @@
}
final State state = new State(sc, attrs, displayId,
- outInputChannel != null ? outInputChannel.getToken() : null, window);
+ outInputChannel != null ? outInputChannel.getToken() : null, window,
+ leash, /* frame= */ new Rect(), /* attachedFrame= */ null);
+ Rect parentFrame = null;
synchronized (this) {
+ State parentState = mStateForWindow.get(attrs.token);
+ if (parentState != null) {
+ parentFrame = parentState.mFrame;
+ }
mStateForWindow.put(window.asBinder(), state);
}
- outAttachedFrame.set(0, 0, -1, -1);
+ state.mAttachedFrame = parentFrame;
+ if (parentFrame == null) {
+ outAttachedFrame.set(0, 0, -1, -1);
+ } else {
+ outAttachedFrame.set(parentFrame);
+ }
outSizeCompatScale[0] = 1f;
final int res = WindowManagerGlobal.ADD_OKAY | WindowManagerGlobal.ADD_FLAG_APP_VISIBLE |
@@ -227,6 +265,7 @@
"Invalid window token (never added or removed already)");
}
removeSurface(state.mSurfaceControl);
+ removeSurface(state.mLeash);
}
/** Separate from {@link #remove} so that subclasses can put removal on a sync transaction. */
@@ -301,6 +340,7 @@
"Invalid window token (never added or removed already)");
}
SurfaceControl sc = state.mSurfaceControl;
+ SurfaceControl leash = state.mLeash;
SurfaceControl.Transaction t = new SurfaceControl.Transaction();
int attrChanges = 0;
@@ -309,21 +349,42 @@
}
WindowManager.LayoutParams attrs = state.mParams;
+ mTmpFrames.attachedFrame = state.mAttachedFrame;
+
+ if (state.mAttachedFrame == null) {
+ mTmpWindowBounds.set(0, 0, requestedWidth, requestedHeight);
+ } else {
+ mTmpWindowBounds.set(state.mAttachedFrame);
+ }
+
+ mLayout.computeFrames(attrs, mTmpInsetsState, mTmpDisplayCutoutSafe, mTmpWindowBounds,
+ WindowConfiguration.WINDOWING_MODE_UNDEFINED, requestedWidth, requestedHeight, 0,
+ 1f, mTmpFrames);
+
+ state.mFrame.set(mTmpFrames.frame);
+ if (outFrames != null) {
+ outFrames.frame.set(mTmpFrames.frame);
+ outFrames.parentFrame.set(mTmpFrames.parentFrame);
+ outFrames.displayFrame.set(mTmpFrames.displayFrame);
+ }
+
+ t.setPosition(leash, mTmpFrames.frame.left, mTmpFrames.frame.top);
+ t.setWindowCrop(leash, mTmpFrames.frame.width(), mTmpFrames.frame.height());
+
if (viewFlags == View.VISIBLE) {
- t.setOpaque(sc, isOpaque(attrs)).show(sc).apply();
+ // TODO(b/262892794) ViewRootImpl modifies the app's rendering SurfaceControl
+ // opaqueness. We shouldn't need to modify opaqueness for this SurfaceControl here or
+ // in the real WindowManager.
+ t.setOpaque(sc, isOpaque(attrs)).show(leash).apply();
if (outSurfaceControl != null) {
outSurfaceControl.copyFrom(sc, "WindowlessWindowManager.relayout");
}
} else {
- t.hide(sc).apply();
+ t.hide(leash).apply();
if (outSurfaceControl != null) {
outSurfaceControl.release();
}
}
- if (outFrames != null) {
- outFrames.frame.set(0, 0, attrs.width, attrs.height);
- outFrames.displayFrame.set(outFrames.frame);
- }
if (outMergedConfiguration != null) {
outMergedConfiguration.setConfiguration(mConfiguration, mConfiguration);
diff --git a/core/java/android/view/accessibility/AccessibilityDisplayProxy.java b/core/java/android/view/accessibility/AccessibilityDisplayProxy.java
index a757236..dd320e1 100644
--- a/core/java/android/view/accessibility/AccessibilityDisplayProxy.java
+++ b/core/java/android/view/accessibility/AccessibilityDisplayProxy.java
@@ -83,7 +83,7 @@
* @param displayId the id of the display to proxy.
* @param executor the executor used to execute proxy callbacks.
* @param installedAndEnabledServices the list of infos representing the installed and
- * enabled a11y services.
+ * enabled accessibility services.
*/
public AccessibilityDisplayProxy(int displayId, @NonNull Executor executor,
@NonNull List<AccessibilityServiceInfo> installedAndEnabledServices) {
@@ -147,19 +147,27 @@
}
/**
- * Gets the focus of the window specified by {@code windowInfo}.
+ * Gets the node with focus, in this display.
*
- * @param windowInfo the window to search
- * @param focus The focus to find. One of {@link AccessibilityNodeInfo#FOCUS_INPUT} or
+ * <p>For {@link AccessibilityNodeInfo#FOCUS_INPUT}, this returns the input-focused node in the
+ * proxy display if this display can receive unspecified input events (input that does not
+ * specify a target display.)
+ *
+ * <p>For {@link AccessibilityNodeInfo#FOCUS_ACCESSIBILITY}, this returns the
+ * accessibility-focused node in the proxy display if the display has accessibility focus.
+ * @param focusType The focus to find. One of {@link AccessibilityNodeInfo#FOCUS_INPUT} or
* {@link AccessibilityNodeInfo#FOCUS_ACCESSIBILITY}.
* @return The node info of the focused view or null.
- * @hide
- * TODO(254545943): Do not expose until support for accessibility focus and/or input is in place
+
*/
@Nullable
- public AccessibilityNodeInfo findFocus(@NonNull AccessibilityWindowInfo windowInfo, int focus) {
- AccessibilityNodeInfo windowRoot = windowInfo.getRoot();
- return windowRoot != null ? windowRoot.findFocus(focus) : null;
+ public AccessibilityNodeInfo findFocus(int focusType) {
+ // TODO(264423198): Support querying the focused node of the proxy's display even if it is
+ // not the top-focused display and can't receive untargeted input events.
+ // TODO(254545943): Separate accessibility focus between proxy and phone state.
+ return AccessibilityInteractionClient.getInstance().findFocus(mConnectionId,
+ AccessibilityWindowInfo.ANY_WINDOW_ID, AccessibilityNodeInfo.ROOT_NODE_ID,
+ focusType);
}
/**
@@ -177,10 +185,10 @@
* Sets the list of {@link AccessibilityServiceInfo}s describing the services interested in the
* {@link AccessibilityDisplayProxy}'s display.
*
- * <p>These represent a11y features and services that are installed and running. These should
- * not include {@link AccessibilityService}s installed on the phone.
+ * <p>These represent accessibility features and services that are installed and running. These
+ * should not include {@link AccessibilityService}s installed on the phone.
*
- * @param installedAndEnabledServices the list of installed and running a11y services.
+ * @param installedAndEnabledServices the list of installed and running accessibility services.
*/
public void setInstalledAndEnabledServices(
@NonNull List<AccessibilityServiceInfo> installedAndEnabledServices) {
diff --git a/core/java/android/view/accessibility/AccessibilityInteractionClient.java b/core/java/android/view/accessibility/AccessibilityInteractionClient.java
index 52eda0a..83a6c5a 100644
--- a/core/java/android/view/accessibility/AccessibilityInteractionClient.java
+++ b/core/java/android/view/accessibility/AccessibilityInteractionClient.java
@@ -921,8 +921,6 @@
*
* @param connectionId The id of a connection for interacting with the system.
* @param accessibilityWindowId A unique window id. Use
- * {@link AccessibilityWindowInfo#ACTIVE_WINDOW_ID}
- * to query the currently active window. Use
* {@link AccessibilityWindowInfo#ANY_WINDOW_ID} to query all
* windows
* @param accessibilityNodeId A unique view id or virtual descendant id from
diff --git a/core/java/android/view/accessibility/AccessibilityManager.java b/core/java/android/view/accessibility/AccessibilityManager.java
index 9abbba9..8e335e8 100644
--- a/core/java/android/view/accessibility/AccessibilityManager.java
+++ b/core/java/android/view/accessibility/AccessibilityManager.java
@@ -1275,6 +1275,15 @@
}
/**
+ * Get the id of {@link AccessibilityNodeInfo.AccessibilityAction} currently being performed.
+ *
+ * @hide
+ */
+ public int getPerformingAction() {
+ return mPerformingAction;
+ }
+
+ /**
* Registers a {@link HighTextContrastChangeListener} for changes in
* the global high text contrast state of the system.
*
diff --git a/core/java/android/view/accessibility/AccessibilityWindowAttributes.java b/core/java/android/view/accessibility/AccessibilityWindowAttributes.java
index 562300c..92ed73b 100644
--- a/core/java/android/view/accessibility/AccessibilityWindowAttributes.java
+++ b/core/java/android/view/accessibility/AccessibilityWindowAttributes.java
@@ -17,11 +17,14 @@
package android.view.accessibility;
import android.annotation.NonNull;
+import android.os.LocaleList;
import android.os.Parcel;
import android.os.Parcelable;
import android.text.TextUtils;
import android.view.WindowManager;
+import java.util.Objects;
+
/**
* This class represents the attributes of a window needed for {@link AccessibilityWindowInfo}.
*
@@ -30,13 +33,22 @@
public final class AccessibilityWindowAttributes implements Parcelable {
private final CharSequence mWindowTitle;
+ private final LocaleList mLocales;
- public AccessibilityWindowAttributes(@NonNull WindowManager.LayoutParams layoutParams) {
+ public AccessibilityWindowAttributes(@NonNull WindowManager.LayoutParams layoutParams,
+ @NonNull LocaleList locales) {
mWindowTitle = populateWindowTitle(layoutParams);
+ mLocales = locales;
}
private AccessibilityWindowAttributes(Parcel in) {
mWindowTitle = in.readCharSequence();
+ LocaleList inLocales = in.readParcelable(null, LocaleList.class);
+ if (inLocales != null) {
+ mLocales = inLocales;
+ } else {
+ mLocales = LocaleList.getEmptyLocaleList();
+ }
}
public CharSequence getWindowTitle() {
@@ -63,6 +75,10 @@
return windowTitle;
}
+ public @NonNull LocaleList getLocales() {
+ return mLocales;
+ }
+
@Override
public boolean equals(Object o) {
if (this == o) return true;
@@ -70,12 +86,13 @@
AccessibilityWindowAttributes that = (AccessibilityWindowAttributes) o;
- return TextUtils.equals(mWindowTitle, that.mWindowTitle);
+ return TextUtils.equals(mWindowTitle, that.mWindowTitle) && Objects.equals(
+ mLocales, that.mLocales);
}
@Override
public int hashCode() {
- return mWindowTitle.hashCode();
+ return Objects.hash(mWindowTitle, mLocales);
}
public static final Creator<AccessibilityWindowAttributes> CREATOR =
@@ -99,12 +116,14 @@
@Override
public void writeToParcel(@NonNull Parcel parcel, int flags) {
parcel.writeCharSequence(mWindowTitle);
+ parcel.writeParcelable(mLocales, flags);
}
@Override
public String toString() {
return "AccessibilityWindowAttributes{"
+ "mAccessibilityWindowTitle=" + mWindowTitle
+ + "mLocales=" + mLocales
+ '}';
}
}
diff --git a/core/java/android/view/accessibility/AccessibilityWindowInfo.java b/core/java/android/view/accessibility/AccessibilityWindowInfo.java
index 9be9990..d84e0fb 100644
--- a/core/java/android/view/accessibility/AccessibilityWindowInfo.java
+++ b/core/java/android/view/accessibility/AccessibilityWindowInfo.java
@@ -23,6 +23,7 @@
import android.app.ActivityTaskManager;
import android.graphics.Rect;
import android.graphics.Region;
+import android.os.LocaleList;
import android.os.Parcel;
import android.os.Parcelable;
import android.os.SystemClock;
@@ -132,6 +133,8 @@
private int mConnectionId = UNDEFINED_CONNECTION_ID;
+ private LocaleList mLocales = LocaleList.getEmptyLocaleList();
+
/**
* Creates a new {@link AccessibilityWindowInfo}.
*/
@@ -555,6 +558,26 @@
}
/**
+ * Sets the locales of the window. Locales are populated by the view root by default.
+ *
+ * @param locales The {@link android.os.LocaleList}.
+ *
+ * @hide
+ */
+ public void setLocales(@NonNull LocaleList locales) {
+ mLocales = locales;
+ }
+
+ /**
+ * Return the {@link android.os.LocaleList} of the window.
+ *
+ * @return the locales of the window.
+ */
+ public @NonNull LocaleList getLocales() {
+ return mLocales;
+ }
+
+ /**
* Returns a cached instance if such is available or a new one is
* created.
*
@@ -676,6 +699,7 @@
}
parcel.writeInt(mConnectionId);
+ parcel.writeParcelable(mLocales, flags);
}
/**
@@ -706,6 +730,7 @@
}
mConnectionId = other.mConnectionId;
+ mLocales = other.mLocales;
}
private void initFromParcel(Parcel parcel) {
@@ -733,6 +758,7 @@
}
mConnectionId = parcel.readInt();
+ mLocales = parcel.readParcelable(null, LocaleList.class);
}
@Override
diff --git a/core/java/android/view/autofill/AutofillFeatureFlags.java b/core/java/android/view/autofill/AutofillFeatureFlags.java
new file mode 100644
index 0000000..59ad151
--- /dev/null
+++ b/core/java/android/view/autofill/AutofillFeatureFlags.java
@@ -0,0 +1,224 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.view.autofill;
+
+import android.annotation.TestApi;
+import android.provider.DeviceConfig;
+import android.text.TextUtils;
+import android.view.View;
+
+import com.android.internal.util.ArrayUtils;
+
+/**
+ * Feature flags associated with autofill.
+ * @hide
+ */
+@TestApi
+public class AutofillFeatureFlags {
+
+ /**
+ * {@code DeviceConfig} property used to set which Smart Suggestion modes for Augmented Autofill
+ * are available.
+ */
+ public static final String DEVICE_CONFIG_AUTOFILL_SMART_SUGGESTION_SUPPORTED_MODES =
+ "smart_suggestion_supported_modes";
+
+ /**
+ * Sets how long (in ms) the augmented autofill service is bound while idle.
+ *
+ * <p>Use {@code 0} to keep it permanently bound.
+ *
+ * @hide
+ */
+ public static final String DEVICE_CONFIG_AUGMENTED_SERVICE_IDLE_UNBIND_TIMEOUT =
+ "augmented_service_idle_unbind_timeout";
+
+ /**
+ * Sets how long (in ms) the augmented autofill service request is killed if not replied.
+ *
+ * @hide
+ */
+ public static final String DEVICE_CONFIG_AUGMENTED_SERVICE_REQUEST_TIMEOUT =
+ "augmented_service_request_timeout";
+
+ /**
+ * Sets allowed list for the autofill compatibility mode.
+ *
+ * The list of packages is {@code ":"} colon delimited, and each entry has the name of the
+ * package and an optional list of url bar resource ids (the list is delimited by
+ * brackets&mdash{@code [} and {@code ]}&mdash and is also comma delimited).
+ *
+ * <p>For example, a list with 3 packages {@code p1}, {@code p2}, and {@code p3}, where
+ * package {@code p1} have one id ({@code url_bar}, {@code p2} has none, and {@code p3 }
+ * have 2 ids {@code url_foo} and {@code url_bas}) would be
+ * {@code p1[url_bar]:p2:p3[url_foo,url_bas]}
+ */
+ public static final String DEVICE_CONFIG_AUTOFILL_COMPAT_MODE_ALLOWED_PACKAGES =
+ "compat_mode_allowed_packages";
+
+ /**
+ * Indicates Fill dialog feature enabled or not.
+ */
+ public static final String DEVICE_CONFIG_AUTOFILL_DIALOG_ENABLED =
+ "autofill_dialog_enabled";
+
+ /**
+ * Sets the autofill hints allowed list for the fields that can trigger the fill dialog
+ * feature at Activity starting.
+ *
+ * The list of autofill hints is {@code ":"} colon delimited.
+ *
+ * <p>For example, a list with 3 hints {@code password}, {@code phone}, and
+ * { @code emailAddress}, would be {@code password:phone:emailAddress}
+ *
+ * Note: By default the password field is enabled even there is no password hint in the list
+ *
+ * @see View#setAutofillHints(String...)
+ * @hide
+ */
+ public static final String DEVICE_CONFIG_AUTOFILL_DIALOG_HINTS =
+ "autofill_dialog_hints";
+
+ // START CREDENTIAL MANAGER FLAGS //
+
+ /**
+ * Indicates whether credential manager tagged views should be ignored from autofill structures.
+ * This flag is further gated by {@link #DEVICE_CONFIG_AUTOFILL_CREDENTIAL_MANAGER_ENABLED}
+ */
+ public static final String DEVICE_CONFIG_AUTOFILL_CREDENTIAL_MANAGER_IGNORE_VIEWS =
+ "autofill_credential_manager_ignore_views";
+
+ /**
+ * Indicates CredentialManager feature enabled or not.
+ * This is the overall feature flag. Individual behavior of credential manager may be controlled
+ * via a different flag, but gated by this flag.
+ */
+ public static final String DEVICE_CONFIG_AUTOFILL_CREDENTIAL_MANAGER_ENABLED =
+ "autofill_credential_manager_enabled";
+
+ /**
+ * Indicates whether credential manager tagged views should suppress fill dialog.
+ * This flag is further gated by {@link #DEVICE_CONFIG_AUTOFILL_CREDENTIAL_MANAGER_ENABLED}
+ *
+ * @hide
+ */
+ public static final String DEVICE_CONFIG_AUTOFILL_CREDENTIAL_MANAGER_SUPPRESS_FILL_DIALOG =
+ "autofill_credential_manager_suppress_fill_dialog";
+
+
+
+ /**
+ * Indicates whether credential manager tagged views should suppress save dialog.
+ * This flag is further gated by {@link #DEVICE_CONFIG_AUTOFILL_CREDENTIAL_MANAGER_ENABLED}
+ *
+ * @hide
+ */
+ public static final String DEVICE_CONFIG_AUTOFILL_CREDENTIAL_MANAGER_SUPPRESS_SAVE_DIALOG =
+ "autofill_credential_manager_suppress_save_dialog";
+ // END CREDENTIAL MANAGER FLAGS //
+
+ /**
+ * Sets a value of delay time to show up the inline tooltip view.
+ *
+ * @hide
+ */
+ public static final String DEVICE_CONFIG_AUTOFILL_TOOLTIP_SHOW_UP_DELAY =
+ "autofill_inline_tooltip_first_show_delay";
+
+ private static final String DIALOG_HINTS_DELIMITER = ":";
+
+ private static final boolean DEFAULT_HAS_FILL_DIALOG_UI_FEATURE = false;
+ private static final String DEFAULT_FILL_DIALOG_ENABLED_HINTS = "";
+
+ // CREDENTIAL MANAGER DEFAULTS
+ // Credential manager is enabled by default so as to allow testing by app developers
+ private static final boolean DEFAULT_CREDENTIAL_MANAGER_ENABLED = true;
+ private static final boolean DEFAULT_CREDENTIAL_MANAGER_IGNORE_VIEWS = true;
+ private static final boolean DEFAULT_CREDENTIAL_MANAGER_SUPPRESS_FILL_DIALOG = false;
+ private static final boolean DEFAULT_CREDENTIAL_MANAGER_SUPPRESS_SAVE_DIALOG = false;
+ // END CREDENTIAL MANAGER DEFAULTS
+
+ private AutofillFeatureFlags() {};
+
+ /**
+ * Whether the fill dialog feature is enabled or not
+ *
+ * @hide
+ */
+ public static boolean isFillDialogEnabled() {
+ return DeviceConfig.getBoolean(
+ DeviceConfig.NAMESPACE_AUTOFILL,
+ DEVICE_CONFIG_AUTOFILL_DIALOG_ENABLED,
+ DEFAULT_HAS_FILL_DIALOG_UI_FEATURE);
+ }
+
+ /**
+ * Gets fill dialog enabled hints.
+ *
+ * @hide
+ */
+ public static String[] getFillDialogEnabledHints() {
+ final String dialogHints = DeviceConfig.getString(
+ DeviceConfig.NAMESPACE_AUTOFILL,
+ DEVICE_CONFIG_AUTOFILL_DIALOG_HINTS,
+ DEFAULT_FILL_DIALOG_ENABLED_HINTS);
+ if (TextUtils.isEmpty(dialogHints)) {
+ return new String[0];
+ }
+
+ return ArrayUtils.filter(dialogHints.split(DIALOG_HINTS_DELIMITER), String[]::new,
+ (str) -> !TextUtils.isEmpty(str));
+ }
+
+ /**
+ * Whether the Credential Manager feature is enabled or not
+ *
+ * @hide
+ */
+ public static boolean isCredentialManagerEnabled() {
+ return DeviceConfig.getBoolean(
+ DeviceConfig.NAMESPACE_AUTOFILL,
+ DEVICE_CONFIG_AUTOFILL_CREDENTIAL_MANAGER_ENABLED,
+ DEFAULT_CREDENTIAL_MANAGER_ENABLED);
+ }
+
+ /**
+ * Whether credential manager tagged views should be ignored for autofill structure.
+ *
+ * @hide
+ */
+ public static boolean shouldIgnoreCredentialViews() {
+ return isCredentialManagerEnabled()
+ && DeviceConfig.getBoolean(
+ DeviceConfig.NAMESPACE_AUTOFILL,
+ DEVICE_CONFIG_AUTOFILL_CREDENTIAL_MANAGER_IGNORE_VIEWS,
+ DEFAULT_CREDENTIAL_MANAGER_IGNORE_VIEWS);
+ }
+
+ /**
+ * Whether credential manager tagged views should not trigger fill dialog requests.
+ *
+ * @hide
+ */
+ public static boolean isFillDialogDisabledForCredentialManager() {
+ return isCredentialManagerEnabled()
+ && DeviceConfig.getBoolean(
+ DeviceConfig.NAMESPACE_AUTOFILL,
+ DEVICE_CONFIG_AUTOFILL_CREDENTIAL_MANAGER_SUPPRESS_FILL_DIALOG,
+ DEFAULT_CREDENTIAL_MANAGER_SUPPRESS_FILL_DIALOG);
+ }
+}
diff --git a/core/java/android/view/autofill/AutofillManager.java b/core/java/android/view/autofill/AutofillManager.java
index a92bc94..58e7a70 100644
--- a/core/java/android/view/autofill/AutofillManager.java
+++ b/core/java/android/view/autofill/AutofillManager.java
@@ -60,7 +60,6 @@
import android.os.Parcelable;
import android.os.RemoteException;
import android.os.SystemClock;
-import android.provider.DeviceConfig;
import android.service.autofill.AutofillService;
import android.service.autofill.FillCallback;
import android.service.autofill.FillEventHistory;
@@ -450,88 +449,6 @@
@Retention(RetentionPolicy.SOURCE)
public @interface SmartSuggestionMode {}
- /**
- * {@code DeviceConfig} property used to set which Smart Suggestion modes for Augmented Autofill
- * are available.
- *
- * @hide
- */
- @TestApi
- public static final String DEVICE_CONFIG_AUTOFILL_SMART_SUGGESTION_SUPPORTED_MODES =
- "smart_suggestion_supported_modes";
-
- /**
- * Sets how long (in ms) the augmented autofill service is bound while idle.
- *
- * <p>Use {@code 0} to keep it permanently bound.
- *
- * @hide
- */
- public static final String DEVICE_CONFIG_AUGMENTED_SERVICE_IDLE_UNBIND_TIMEOUT =
- "augmented_service_idle_unbind_timeout";
-
- /**
- * Sets how long (in ms) the augmented autofill service request is killed if not replied.
- *
- * @hide
- */
- public static final String DEVICE_CONFIG_AUGMENTED_SERVICE_REQUEST_TIMEOUT =
- "augmented_service_request_timeout";
-
- /**
- * Sets allowed list for the autofill compatibility mode.
- *
- * The list of packages is {@code ":"} colon delimited, and each entry has the name of the
- * package and an optional list of url bar resource ids (the list is delimited by
- * brackets&mdash{@code [} and {@code ]}&mdash and is also comma delimited).
- *
- * <p>For example, a list with 3 packages {@code p1}, {@code p2}, and {@code p3}, where
- * package {@code p1} have one id ({@code url_bar}, {@code p2} has none, and {@code p3 }
- * have 2 ids {@code url_foo} and {@code url_bas}) would be
- * {@code p1[url_bar]:p2:p3[url_foo,url_bas]}
- *
- * @hide
- */
- @TestApi
- public static final String DEVICE_CONFIG_AUTOFILL_COMPAT_MODE_ALLOWED_PACKAGES =
- "compat_mode_allowed_packages";
-
- /**
- * Sets the fill dialog feature enabled or not.
- *
- * @hide
- */
- @TestApi
- public static final String DEVICE_CONFIG_AUTOFILL_DIALOG_ENABLED =
- "autofill_dialog_enabled";
-
- /**
- * Sets the autofill hints allowed list for the fields that can trigger the fill dialog
- * feature at Activity starting.
- *
- * The list of autofill hints is {@code ":"} colon delimited.
- *
- * <p>For example, a list with 3 hints {@code password}, {@code phone}, and
- * {@code emailAddress}, would be {@code password:phone:emailAddress}
- *
- * Note: By default the password field is enabled even there is no password hint in the list
- *
- * @see View#setAutofillHints(String...)
- * @hide
- */
- public static final String DEVICE_CONFIG_AUTOFILL_DIALOG_HINTS =
- "autofill_dialog_hints";
-
- /**
- * Sets a value of delay time to show up the inline tooltip view.
- *
- * @hide
- */
- public static final String DEVICE_CONFIG_AUTOFILL_TOOLTIP_SHOW_UP_DELAY =
- "autofill_inline_tooltip_first_show_delay";
-
- private static final String DIALOG_HINTS_DELIMITER = ":";
-
/** @hide */
public static final int RESULT_OK = 0;
/** @hide */
@@ -634,9 +551,6 @@
*/
public static final int NO_SESSION = Integer.MAX_VALUE;
- private static final boolean HAS_FILL_DIALOG_UI_FEATURE_DEFAULT = false;
- private static final String FILL_DIALOG_ENABLED_DEFAULT_HINTS = "";
-
private final IAutoFillManager mService;
private final Object mLock = new Object();
@@ -891,11 +805,8 @@
mOptions = context.getAutofillOptions();
mIsFillRequested = new AtomicBoolean(false);
- mIsFillDialogEnabled = DeviceConfig.getBoolean(
- DeviceConfig.NAMESPACE_AUTOFILL,
- DEVICE_CONFIG_AUTOFILL_DIALOG_ENABLED,
- HAS_FILL_DIALOG_UI_FEATURE_DEFAULT);
- mFillDialogEnabledHints = getFillDialogEnabledHints();
+ mIsFillDialogEnabled = AutofillFeatureFlags.isFillDialogEnabled();
+ mFillDialogEnabledHints = AutofillFeatureFlags.getFillDialogEnabledHints();
if (sDebug) {
Log.d(TAG, "Fill dialog is enabled:" + mIsFillDialogEnabled
+ ", hints=" + Arrays.toString(mFillDialogEnabledHints));
@@ -907,19 +818,6 @@
}
}
- private String[] getFillDialogEnabledHints() {
- final String dialogHints = DeviceConfig.getString(
- DeviceConfig.NAMESPACE_AUTOFILL,
- DEVICE_CONFIG_AUTOFILL_DIALOG_HINTS,
- FILL_DIALOG_ENABLED_DEFAULT_HINTS);
- if (TextUtils.isEmpty(dialogHints)) {
- return new String[0];
- }
-
- return ArrayUtils.filter(dialogHints.split(DIALOG_HINTS_DELIMITER), String[]::new,
- (str) -> !TextUtils.isEmpty(str));
- }
-
/**
* @hide
*/
@@ -1190,16 +1088,28 @@
}
/**
- * The {@link #DEVICE_CONFIG_AUTOFILL_DIALOG_ENABLED} is {@code true} or the view have
- * the allowed autofill hints, performs a fill request to know there is any field supported
- * fill dialog.
+ * The {@link AutofillFeatureFlags#DEVICE_CONFIG_AUTOFILL_DIALOG_ENABLED} is {@code true} or
+ * the view have the allowed autofill hints, performs a fill request to know there is any field
+ * supported fill dialog.
*
* @hide
*/
public void notifyViewEnteredForFillDialog(View v) {
+ if (sDebug) {
+ Log.d(TAG, "notifyViewEnteredForFillDialog:" + v.getAutofillId());
+ }
if (!hasAutofillFeature()) {
return;
}
+ if (AutofillFeatureFlags.isFillDialogDisabledForCredentialManager()
+ && v.isCredential()) {
+ if (sDebug) {
+ Log.d(TAG, "Ignoring Fill Dialog request since important for credMan:"
+ + v.getAutofillId().toString());
+ }
+ return;
+ }
+
synchronized (mLock) {
if (mTrackedViews != null) {
// To support the fill dialog can show for the autofillable Views in
@@ -1227,8 +1137,8 @@
synchronized (mLock) {
// To match the id of the IME served view, used AutofillId.NO_AUTOFILL_ID on prefill
// request, because IME will reset the id of IME served view to 0 when activity
- // start and does not focus on any view. If the id of the prefill request is
- // not match to the IME served view's, Autofill will be blocking to wait inline
+ // start and does not focus on any view. If the id of the prefill request does
+ // not match the IME served view's, Autofill will be blocking to wait inline
// request from the IME.
notifyViewEnteredLocked(/* view= */ null, AutofillId.NO_AUTOFILL_ID,
/* bounds= */ null, /* value= */ null, flags);
@@ -4075,6 +3985,7 @@
}
}
+ @Override
public void notifyFillDialogTriggerIds(List<AutofillId> ids) {
final AutofillManager afm = mAfm.get();
if (afm != null) {
diff --git a/core/java/android/view/contentcapture/ContentCaptureManager.java b/core/java/android/view/contentcapture/ContentCaptureManager.java
index d067d4b..497f066 100644
--- a/core/java/android/view/contentcapture/ContentCaptureManager.java
+++ b/core/java/android/view/contentcapture/ContentCaptureManager.java
@@ -66,8 +66,7 @@
import java.util.function.Consumer;
/**
- * <p>The {@link ContentCaptureManager} provides additional ways for for apps to
- * integrate with the content capture subsystem.
+ * <p>Provides additional ways for apps to integrate with the content capture subsystem.
*
* <p>Content capture provides real-time, continuous capture of application activity, display and
* events to an intelligence service that is provided by the Android system. The intelligence
diff --git a/core/java/android/view/inputmethod/HandwritingGesture.java b/core/java/android/view/inputmethod/HandwritingGesture.java
index 2516269..e0fc426 100644
--- a/core/java/android/view/inputmethod/HandwritingGesture.java
+++ b/core/java/android/view/inputmethod/HandwritingGesture.java
@@ -82,38 +82,60 @@
@IntDef({GRANULARITY_CHARACTER, GRANULARITY_WORD})
@interface Granularity {}
- /** Undefined gesture type. */
+ /**
+ * Undefined gesture type.
+ * @hide
+ */
+ @TestApi
public static final int GESTURE_TYPE_NONE = 0x0000;
/**
* Gesture of type {@link SelectGesture} to select an area of text.
+ * @hide
*/
+ @TestApi
public static final int GESTURE_TYPE_SELECT = 0x0001;
/**
* Gesture of type {@link InsertGesture} to insert text at a designated point.
+ * @hide
*/
+ @TestApi
public static final int GESTURE_TYPE_INSERT = 1 << 1;
/**
* Gesture of type {@link DeleteGesture} to delete an area of text.
+ * @hide
*/
+ @TestApi
public static final int GESTURE_TYPE_DELETE = 1 << 2;
- /** Gesture of type {@link RemoveSpaceGesture} to remove whitespace from text. */
+ /**
+ * Gesture of type {@link RemoveSpaceGesture} to remove whitespace from text.
+ * @hide
+ */
+ @TestApi
public static final int GESTURE_TYPE_REMOVE_SPACE = 1 << 3;
- /** Gesture of type {@link JoinOrSplitGesture} to join or split text. */
+ /**
+ * Gesture of type {@link JoinOrSplitGesture} to join or split text.
+ * @hide
+ */
+ @TestApi
public static final int GESTURE_TYPE_JOIN_OR_SPLIT = 1 << 4;
/**
* Gesture of type {@link SelectRangeGesture} to select range of text.
+ * @hide
*/
+ @TestApi
public static final int GESTURE_TYPE_SELECT_RANGE = 1 << 5;
/**
* Gesture of type {@link DeleteRangeGesture} to delete range of text.
+ * @hide
*/
+ @TestApi
public static final int GESTURE_TYPE_DELETE_RANGE = 1 << 6;
/**
diff --git a/core/java/android/view/inputmethod/InputConnection.java b/core/java/android/view/inputmethod/InputConnection.java
index 9b519c3..6872536 100644
--- a/core/java/android/view/inputmethod/InputConnection.java
+++ b/core/java/android/view/inputmethod/InputConnection.java
@@ -1262,13 +1262,13 @@
/**
* Called by input method to request the {@link TextBoundsInfo} for a range of text which is
- * covered by or in vicinity of the given {@code RectF}. It can be used as a supplementary
+ * covered by or in vicinity of the given {@code bounds}. It can be used as a supplementary
* method to implement the handwriting gesture API -
* {@link #performHandwritingGesture(HandwritingGesture, Executor, IntConsumer)}.
*
* <p><strong>Editor authors</strong>: It's preferred that the editor returns a
* {@link TextBoundsInfo} of all the text lines whose bounds intersect with the given
- * {@code rectF}.
+ * {@code bounds}.
* </p>
*
* <p><strong>IME authors</strong>: This method is expensive when the text is long. Please
@@ -1276,7 +1276,7 @@
* consuming. It's preferable to only request text bounds in smaller areas.
* </p>
*
- * @param rectF the interested area where the text bounds are requested, in the screen
+ * @param bounds the interested area where the text bounds are requested, in the screen
* coordinates.
* @param executor the executor to run the callback.
* @param consumer the callback invoked by editor to return the result. It must return a
@@ -1286,7 +1286,7 @@
* @see android.view.inputmethod.TextBoundsInfoResult
*/
default void requestTextBoundsInfo(
- @NonNull RectF rectF, @NonNull @CallbackExecutor Executor executor,
+ @NonNull RectF bounds, @NonNull @CallbackExecutor Executor executor,
@NonNull Consumer<TextBoundsInfoResult> consumer) {
Objects.requireNonNull(executor);
Objects.requireNonNull(consumer);
diff --git a/core/java/android/view/inputmethod/InputConnectionWrapper.java b/core/java/android/view/inputmethod/InputConnectionWrapper.java
index 4befd6f..5e323fa 100644
--- a/core/java/android/view/inputmethod/InputConnectionWrapper.java
+++ b/core/java/android/view/inputmethod/InputConnectionWrapper.java
@@ -362,9 +362,9 @@
*/
@Override
public void requestTextBoundsInfo(
- @NonNull RectF rectF, @NonNull @CallbackExecutor Executor executor,
+ @NonNull RectF bounds, @NonNull @CallbackExecutor Executor executor,
@NonNull Consumer<TextBoundsInfoResult> consumer) {
- mTarget.requestTextBoundsInfo(rectF, executor, consumer);
+ mTarget.requestTextBoundsInfo(bounds, executor, consumer);
}
/**
diff --git a/core/java/android/view/inputmethod/RemoteInputConnectionImpl.java b/core/java/android/view/inputmethod/RemoteInputConnectionImpl.java
index 7525d72..6f8b422 100644
--- a/core/java/android/view/inputmethod/RemoteInputConnectionImpl.java
+++ b/core/java/android/view/inputmethod/RemoteInputConnectionImpl.java
@@ -1106,7 +1106,7 @@
@Dispatching(cancellable = true)
@Override
public void requestTextBoundsInfo(
- InputConnectionCommandHeader header, RectF rectF,
+ InputConnectionCommandHeader header, RectF bounds,
@NonNull ResultReceiver resultReceiver) {
dispatchWithTracing("requestTextBoundsInfo", () -> {
if (header.mSessionId != mCurrentSessionId.get()) {
@@ -1121,7 +1121,7 @@
}
ic.requestTextBoundsInfo(
- rectF,
+ bounds,
Runnable::run,
(textBoundsInfoResult) -> {
final int resultCode = textBoundsInfoResult.getResultCode();
diff --git a/core/java/android/view/inputmethod/TextBoundsInfo.java b/core/java/android/view/inputmethod/TextBoundsInfo.java
index dd05543..d42d94e 100644
--- a/core/java/android/view/inputmethod/TextBoundsInfo.java
+++ b/core/java/android/view/inputmethod/TextBoundsInfo.java
@@ -43,8 +43,8 @@
* The text bounds information of a slice of text in the editor.
*
* <p> This class provides IME the layout information of the text within the range from
- * {@link #getStart()} to {@link #getEnd()}. It's intended to be used by IME as a supplementary API
- * to support handwriting gestures.
+ * {@link #getStartIndex()} to {@link #getEndIndex()}. It's intended to be used by IME as a
+ * supplementary API to support handwriting gestures.
* </p>
*/
public final class TextBoundsInfo implements Parcelable {
@@ -168,16 +168,13 @@
private final SegmentFinder mGraphemeSegmentFinder;
/**
- * Returns a new instance of {@link android.graphics.Matrix} that indicates the transformation
+ * Set the given {@link android.graphics.Matrix} to be the transformation
* matrix that is to be applied other positional data in this class.
- *
- * @return a new instance (copy) of the transformation matrix.
*/
@NonNull
- public Matrix getMatrix() {
- final Matrix matrix = new Matrix();
+ public void getMatrix(@NonNull Matrix matrix) {
+ Objects.requireNonNull(matrix);
matrix.setValues(mMatrixValues);
- return matrix;
}
/**
@@ -186,7 +183,7 @@
*
* @see Builder#setStartAndEnd(int, int)
*/
- public int getStart() {
+ public int getStartIndex() {
return mStart;
}
@@ -196,28 +193,28 @@
*
* @see Builder#setStartAndEnd(int, int)
*/
- public int getEnd() {
+ public int getEndIndex() {
return mEnd;
}
/**
- * Return the bounds of the character at the given {@code index}, in the coordinates of the
- * editor.
+ * Set the bounds of the character at the given {@code index} to the given {@link RectF}, in
+ * the coordinates of the editor.
*
* @param index the index of the queried character.
- * @return the bounding box of the queried character.
+ * @param bounds the {@link RectF} used to receive the result.
*
* @throws IndexOutOfBoundsException if the given {@code index} is out of the range from
* the {@code start} to the {@code end}.
*/
@NonNull
- public RectF getCharacterBounds(int index) {
+ public void getCharacterBounds(int index, @NonNull RectF bounds) {
if (index < mStart || index >= mEnd) {
throw new IndexOutOfBoundsException("Index is out of the bounds of "
+ "[" + mStart + ", " + mEnd + ").");
}
final int offset = 4 * (index - mStart);
- return new RectF(mCharacterBounds[offset], mCharacterBounds[offset + 1],
+ bounds.set(mCharacterBounds[offset], mCharacterBounds[offset + 1],
mCharacterBounds[offset + 2], mCharacterBounds[offset + 3]);
}
@@ -333,6 +330,16 @@
* won't check the text in the ranges of [5, 7) and [12, 15).
* </p>
*
+ * <p> Under the following conditions, this method will return -1 indicating that no valid
+ * character is found:
+ * <ul>
+ * <li> The given {@code y} coordinate is above the first line or below the last line (the
+ * first line or the last line is identified by the {@link SegmentFinder} returned from
+ * {@link #getLineSegmentFinder()}). </li>
+ * <li> There is no character in this {@link TextBoundsInfo}. </li>
+ * </ul>
+ * </p>
+ *
* @param x the x coordinates of the interested location, in the editor's coordinates.
* @param y the y coordinates of the interested location, in the editor's coordinates.
* @return the index of the character whose position is closest to the given location. It will
@@ -990,8 +997,8 @@
public static final class Builder {
private final float[] mMatrixValues = new float[9];
private boolean mMatrixInitialized;
- private int mStart;
- private int mEnd;
+ private int mStart = -1;
+ private int mEnd = -1;
private float[] mCharacterBounds;
private int[] mCharacterFlags;
private int[] mCharacterBidiLevels;
@@ -999,6 +1006,17 @@
private SegmentFinder mWordSegmentFinder;
private SegmentFinder mGraphemeSegmentFinder;
+ /**
+ * Create a builder for {@link TextBoundsInfo}.
+ * @param start the start index of the {@link TextBoundsInfo}, inclusive.
+ * @param end the end index of the {@link TextBoundsInfo}, exclusive.
+ * @throws IllegalArgumentException if the given {@code start} or {@code end} is negative,
+ * or {@code end} is smaller than the {@code start}.
+ */
+ public Builder(int start, int end) {
+ setStartAndEnd(start, end);
+ }
+
/** Clear all the parameters set on this {@link Builder} to reuse it. */
@NonNull
public Builder clear() {
@@ -1152,7 +1170,7 @@
*
* @see #getGraphemeSegmentFinder()
* @see SegmentFinder
- * @see SegmentFinder.DefaultSegmentFinder
+ * @see SegmentFinder.PrescribedSegmentFinder
*/
@NonNull
public Builder setGraphemeSegmentFinder(@NonNull SegmentFinder graphemeSegmentFinder) {
@@ -1171,7 +1189,7 @@
*
* @see #getWordSegmentFinder()
* @see SegmentFinder
- * @see SegmentFinder.DefaultSegmentFinder
+ * @see SegmentFinder.PrescribedSegmentFinder
*/
@NonNull
public Builder setWordSegmentFinder(@NonNull SegmentFinder wordSegmentFinder) {
@@ -1193,7 +1211,7 @@
*
* @see #getLineSegmentFinder()
* @see SegmentFinder
- * @see SegmentFinder.DefaultSegmentFinder
+ * @see SegmentFinder.PrescribedSegmentFinder
*/
@NonNull
public Builder setLineSegmentFinder(@NonNull SegmentFinder lineSegmentFinder) {
@@ -1360,7 +1378,7 @@
breaks = GrowingArrayUtils.append(breaks, count++, start + offset);
}
}
- return new SegmentFinder.DefaultSegmentFinder(Arrays.copyOf(breaks, count));
+ return new SegmentFinder.PrescribedSegmentFinder(Arrays.copyOf(breaks, count));
}
/**
diff --git a/core/java/android/webkit/TEST_MAPPING b/core/java/android/webkit/TEST_MAPPING
index bd25200..c1bc6d7 100644
--- a/core/java/android/webkit/TEST_MAPPING
+++ b/core/java/android/webkit/TEST_MAPPING
@@ -9,6 +9,14 @@
]
},
{
+ "name": "CtsSdkSandboxWebkitTestCases",
+ "options": [
+ {
+ "exclude-annotation": "androidx.test.filters.FlakyTest"
+ }
+ ]
+ },
+ {
"name": "CtsHostsideWebViewTests",
"options": [
{
diff --git a/core/java/android/webkit/WebResourceError.java b/core/java/android/webkit/WebResourceError.java
index 11f1b6f1..4c87489 100644
--- a/core/java/android/webkit/WebResourceError.java
+++ b/core/java/android/webkit/WebResourceError.java
@@ -19,7 +19,7 @@
import android.annotation.SystemApi;
/**
- * Encapsulates information about errors occured during loading of web resources. See
+ * Encapsulates information about errors that occurred during loading of web resources. See
* {@link WebViewClient#onReceivedError(WebView, WebResourceRequest, WebResourceError) WebViewClient.onReceivedError(WebView, WebResourceRequest, WebResourceError)}
*/
public abstract class WebResourceError {
diff --git a/core/java/android/widget/MediaController.java b/core/java/android/widget/MediaController.java
index ff2e175..2bd5c88 100644
--- a/core/java/android/widget/MediaController.java
+++ b/core/java/android/widget/MediaController.java
@@ -218,6 +218,7 @@
p.width = mAnchor.getWidth();
p.x = anchorPos[0] + (mAnchor.getWidth() - p.width) / 2;
p.y = anchorPos[1] + mAnchor.getHeight() - mDecor.getMeasuredHeight();
+ p.token = mAnchor.getWindowToken();
}
// This is called whenever mAnchor's layout bound changes
diff --git a/core/java/android/widget/TextView.java b/core/java/android/widget/TextView.java
index b9b928e..4005bc8 100644
--- a/core/java/android/widget/TextView.java
+++ b/core/java/android/widget/TextView.java
@@ -13245,7 +13245,7 @@
* Creates the {@link TextBoundsInfo} for the text lines that intersects with the {@code rectF}.
* @hide
*/
- public TextBoundsInfo getTextBoundsInfo(@NonNull RectF rectF) {
+ public TextBoundsInfo getTextBoundsInfo(@NonNull RectF bounds) {
final Layout layout = getLayout();
if (layout == null) {
// No valid text layout, return null.
@@ -13268,19 +13268,18 @@
final float layoutLeft = viewportToContentHorizontalOffset();
final float layoutTop = viewportToContentVerticalOffset();
- final RectF localRectF = new RectF(rectF);
- globalToLocalMatrix.mapRect(localRectF);
- localRectF.offset(-layoutLeft, -layoutTop);
+ final RectF localBounds = new RectF(bounds);
+ globalToLocalMatrix.mapRect(localBounds);
+ localBounds.offset(-layoutLeft, -layoutTop);
// Text length is 0. There is no character bounds, return empty TextBoundsInfo.
// rectF doesn't intersect with the layout, return empty TextBoundsInfo.
- if (!localRectF.intersects(0f, 0f, layout.getWidth(), layout.getHeight())
+ if (!localBounds.intersects(0f, 0f, layout.getWidth(), layout.getHeight())
|| text.length() == 0) {
- final TextBoundsInfo.Builder builder = new TextBoundsInfo.Builder();
+ final TextBoundsInfo.Builder builder = new TextBoundsInfo.Builder(0, 0);
final SegmentFinder emptySegmentFinder =
- new SegmentFinder.DefaultSegmentFinder(new int[0]);
- builder.setStartAndEnd(0, 0)
- .setMatrix(localToGlobalMatrix)
+ new SegmentFinder.PrescribedSegmentFinder(new int[0]);
+ builder.setMatrix(localToGlobalMatrix)
.setCharacterBounds(new float[0])
.setCharacterBidiLevel(new int[0])
.setCharacterFlags(new int[0])
@@ -13290,8 +13289,8 @@
return builder.build();
}
- final int startLine = layout.getLineForVertical((int) Math.floor(localRectF.top));
- final int endLine = layout.getLineForVertical((int) Math.floor(localRectF.bottom));
+ final int startLine = layout.getLineForVertical((int) Math.floor(localBounds.top));
+ final int endLine = layout.getLineForVertical((int) Math.floor(localBounds.bottom));
final int start = layout.getLineStart(startLine);
final int end = layout.getLineEnd(endLine);
@@ -13349,18 +13348,18 @@
lineRanges[2 * offset] = layout.getLineStart(line);
lineRanges[2 * offset + 1] = layout.getLineEnd(line);
}
- final SegmentFinder lineSegmentFinder = new SegmentFinder.DefaultSegmentFinder(lineRanges);
+ final SegmentFinder lineSegmentFinder =
+ new SegmentFinder.PrescribedSegmentFinder(lineRanges);
- final TextBoundsInfo.Builder builder = new TextBoundsInfo.Builder();
- builder.setStartAndEnd(start, end)
+ return new TextBoundsInfo.Builder(start, end)
.setMatrix(localToGlobalMatrix)
.setCharacterBounds(characterBounds)
.setCharacterBidiLevel(characterBidiLevels)
.setCharacterFlags(characterFlags)
.setGraphemeSegmentFinder(graphemeSegmentFinder)
.setLineSegmentFinder(lineSegmentFinder)
- .setWordSegmentFinder(wordSegmentFinder);
- return builder.build();
+ .setWordSegmentFinder(wordSegmentFinder)
+ .build();
}
/**
diff --git a/core/java/android/window/AddToSurfaceSyncGroupResult.aidl b/core/java/android/window/AddToSurfaceSyncGroupResult.aidl
new file mode 100644
index 0000000..ea38e65
--- /dev/null
+++ b/core/java/android/window/AddToSurfaceSyncGroupResult.aidl
@@ -0,0 +1,37 @@
+/*
+ * 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 android.window;
+
+import android.window.ISurfaceSyncGroup;
+import android.window.ITransactionReadyCallback;
+
+/**
+ * Data class that contains the results when adding a SufarceSyncGroup to WindowManagerService
+ * @hide
+ */
+parcelable AddToSurfaceSyncGroupResult {
+ /**
+ * The ISurfaceSyncGroup that the child was added to.
+ */
+ ISurfaceSyncGroup mParentSyncGroup;
+
+ /**
+ * The ITransactionReadyCallback that should be called when the child SurfaceSyncGroup
+ * completes.
+ */
+ ITransactionReadyCallback mTransactionReadyCallback;
+}
\ No newline at end of file
diff --git a/core/java/android/window/ISurfaceSyncGroup.aidl b/core/java/android/window/ISurfaceSyncGroup.aidl
new file mode 100644
index 0000000..c60133b
--- /dev/null
+++ b/core/java/android/window/ISurfaceSyncGroup.aidl
@@ -0,0 +1,55 @@
+/*
+ * 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 android.window;
+
+import android.os.IBinder;
+
+/**
+ * An ISurfaceSyncGroup that can be added to another ISurfaceSyncGroup or is the root
+ * ISurfaceSyncGroup.
+ *
+ * See SurfaceSyncGroup.md
+ *
+ * {@hide}
+ */
+interface ISurfaceSyncGroup {
+ /**
+ * Called when the ISurfaceSyncGroup is ready to begin handling a sync request. When invoked,
+ * the implementor should set up the {@link android.window.ITransactionReadyCallback}, either
+ * via system server or in the local process.
+ *
+ * @param parentSyncGroup The parent that added this ISurfaceSyncGroup
+ * @param parentSyncGroupMerge true if the ISurfaceSyncGroup is added because its child was
+ * added to a new SurfaceSyncGroup.
+ * @return true if it was successfully added to the sync, false otherwise.
+ */
+ boolean onAddedToSyncGroup(in IBinder parentSyncGroupToken, boolean parentSyncGroupMerge);
+
+ /**
+ * Call to add a ISurfaceSyncGroup to this ISurfaceSyncGroup. This is adding a child
+ * ISurfaceSyncGroup so this group can't complete until the child does.
+ *
+ * @param The child ISurfaceSyncGroup to add to this ISurfaceSyncGroup.
+ * @param parentSyncGroupMerge true if the current ISurfaceSyncGroup is added because its child
+ * was added to a new SurfaceSyncGroup. That would require the code
+ * to call newParent.addToSync(oldParent). When this occurs, we need
+ * to reverse the merge order because the oldParent should always be
+ * considered older than any other SurfaceSyncGroups.
+ * @return true if it was successfully added to the sync, false otherwise.
+ */
+ boolean addToSync(in ISurfaceSyncGroup surfaceSyncGroup, boolean parentSyncGroupMerge);
+}
\ No newline at end of file
diff --git a/core/java/android/window/ISurfaceSyncGroupCompletedListener.aidl b/core/java/android/window/ISurfaceSyncGroupCompletedListener.aidl
new file mode 100644
index 0000000..cac1079
--- /dev/null
+++ b/core/java/android/window/ISurfaceSyncGroupCompletedListener.aidl
@@ -0,0 +1,33 @@
+/*
+ * 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 android.window;
+
+/**
+ * A listener used to notify when a SurfaceSyncGroup has completed. This doesn't indicate anything
+ * about the state of what's on screen, but means everything in the SurfaceSyncGroup has
+ * completed, including all children. This is similar to
+ * {@link SurfaceSyncGroup#addSyncCompleteCallback}, except allows the callback to be invoked to
+ * another process.
+ *
+ * @hide
+ */
+interface ISurfaceSyncGroupCompletedListener {
+ /**
+ * Invoked when the SurfaceSyncGroup has completed.
+ */
+ oneway void onSurfaceSyncGroupComplete();
+}
\ No newline at end of file
diff --git a/core/java/android/window/ITaskOrganizerController.aidl b/core/java/android/window/ITaskOrganizerController.aidl
index e6bb1f6..0032b9c 100644
--- a/core/java/android/window/ITaskOrganizerController.aidl
+++ b/core/java/android/window/ITaskOrganizerController.aidl
@@ -40,7 +40,8 @@
void unregisterTaskOrganizer(ITaskOrganizer organizer);
/** Creates a persistent root task in WM for a particular windowing-mode. */
- void createRootTask(int displayId, int windowingMode, IBinder launchCookie);
+ void createRootTask(int displayId, int windowingMode, IBinder launchCookie,
+ boolean removeWithTaskOrganizer);
/** Deletes a persistent root task in WM */
boolean deleteRootTask(in WindowContainerToken task);
diff --git a/core/java/android/window/ITransactionReadyCallback.aidl b/core/java/android/window/ITransactionReadyCallback.aidl
new file mode 100644
index 0000000..36b1579
--- /dev/null
+++ b/core/java/android/window/ITransactionReadyCallback.aidl
@@ -0,0 +1,37 @@
+/*
+ * 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 android.window;
+
+import android.view.SurfaceControl.Transaction;
+
+/**
+ * Interface that is invoked when the ISurfaceSyncGroup has completed. The parent ISurfaceSyncGroup
+ * creates an ITransactionReadyCallback and sends it to the children who will invoke the
+ * {@link onTransactionReady} when they have completed, including waiting on their children.
+ *
+ * @hide
+ */
+interface ITransactionReadyCallback {
+ /**
+ * Invoked when ISurfaceSyncGroup has completed. This means the ISurfaceSyncGroup has been
+ * marked as ready and all children it was waiting on have been completed.
+ *
+ * @param t The transaction that contains everything to be included in the sync. This can be
+ null if there's nothing to sync
+ */
+ void onTransactionReady(in @nullable Transaction t);
+}
\ No newline at end of file
diff --git a/core/java/android/window/SurfaceSyncGroup.java b/core/java/android/window/SurfaceSyncGroup.java
index e1a9a48..12cd340 100644
--- a/core/java/android/window/SurfaceSyncGroup.java
+++ b/core/java/android/window/SurfaceSyncGroup.java
@@ -16,20 +16,26 @@
package android.window;
+import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.UiThread;
+import android.os.Binder;
+import android.os.BinderProxy;
import android.os.Debug;
+import android.os.IBinder;
+import android.os.RemoteException;
import android.os.Trace;
import android.util.ArraySet;
import android.util.Log;
import android.util.Pair;
import android.view.AttachedSurfaceControl;
import android.view.SurfaceControl.Transaction;
+import android.view.SurfaceControlViewHost;
import android.view.SurfaceView;
+import android.view.WindowManagerGlobal;
import com.android.internal.annotations.GuardedBy;
-import java.util.Set;
import java.util.concurrent.Executor;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.function.Consumer;
@@ -37,43 +43,13 @@
/**
* Used to organize syncs for surfaces.
- *
- * The SurfaceSyncGroup allows callers to add desired syncs into a set and wait for them to all
- * complete before getting a callback. The purpose of the SurfaceSyncGroup is to be an accounting
- * mechanism so each sync implementation doesn't need to handle it themselves. The SurfaceSyncGroup
- * class is used the following way.
- *
- * 1. {@link #addToSync(SurfaceSyncGroup, boolean)} is called for every SurfaceSyncGroup object that
- * wants to be included in the sync. If the addSync is called for an {@link AttachedSurfaceControl}
- * or {@link SurfaceView} it needs to be called on the UI thread. When addToSync is called, it's
- * guaranteed that any UI updates that were requested before addToSync but after the last frame
- * drew, will be included in the sync.
- * 2. {@link #markSyncReady()} should be called when all the {@link SurfaceSyncGroup}s have been
- * added to the SurfaceSyncGroup. At this point, the SurfaceSyncGroup is closed and no more
- * SurfaceSyncGroups can be added to it.
- * 3. The SurfaceSyncGroup will gather the data for each SurfaceSyncGroup using the steps described
- * below. When all the SurfaceSyncGroups have finished, the syncRequestComplete will be invoked and
- * the transaction will either be applied or sent to the caller. In most cases, only the
- * SurfaceSyncGroup should be handling the Transaction object directly. However, there are some
- * cases where the framework needs to send the Transaction elsewhere, like in ViewRootImpl, so that
- * option is provided.
- *
- * The following is what happens within the {@link android.window.SurfaceSyncGroup}
- * 1. Each SurfaceSyncGroup will get a
- * {@link SurfaceSyncGroup#onAddedToSyncGroup(SurfaceSyncGroup, TransactionReadyCallback)} callback
- * that contains a {@link TransactionReadyCallback}.
- * 2. Each {@link SurfaceSyncGroup} needs to invoke
- * {@link SurfaceSyncGroup#onTransactionReady(Transaction)}.
- * This makes sure the parent SurfaceSyncGroup knows when the SurfaceSyncGroup is complete, allowing
- * the parent SurfaceSyncGroup to get the Transaction that contains the changes for the child
- * SurfaceSyncGroup
- * 3. When the final TransactionReadyCallback finishes for the child SurfaceSyncGroups, the
- * transaction is either applied if it's the top most parent or the final merged transaction is sent
- * up to its parent SurfaceSyncGroup.
+ * </p>
+ * See SurfaceSyncGroup.md
+ * </p>
*
* @hide
*/
-public class SurfaceSyncGroup {
+public class SurfaceSyncGroup extends ISurfaceSyncGroup.Stub {
private static final String TAG = "SurfaceSyncGroup";
private static final boolean DEBUG = false;
@@ -92,7 +68,7 @@
private final String mName;
@GuardedBy("mLock")
- private final Set<TransactionReadyCallback> mPendingSyncs = new ArraySet<>();
+ private final ArraySet<ITransactionReadyCallback> mPendingSyncs = new ArraySet<>();
@GuardedBy("mLock")
private final Transaction mTransaction = sTransactionFactory.get();
@GuardedBy("mLock")
@@ -102,14 +78,38 @@
private boolean mFinished;
@GuardedBy("mLock")
- private TransactionReadyCallback mTransactionReadyCallback;
+ private Consumer<Transaction> mTransactionReadyConsumer;
@GuardedBy("mLock")
- private SurfaceSyncGroup mParentSyncGroup;
+ private ISurfaceSyncGroup mParentSyncGroup;
@GuardedBy("mLock")
private final ArraySet<Pair<Executor, Runnable>> mSyncCompleteCallbacks = new ArraySet<>();
+ @GuardedBy("mLock")
+ private boolean mHasWMSync;
+
+ @GuardedBy("mLock")
+ private ISurfaceSyncGroupCompletedListener mSurfaceSyncGroupCompletedListener;
+
+ /**
+ * Token to identify this SurfaceSyncGroup. This is used to register the SurfaceSyncGroup in
+ * WindowManager. This token is also sent to other processes' SurfaceSyncGroup that want to be
+ * included in this SurfaceSyncGroup.
+ */
+ private final Binder mToken = new Binder();
+
+ private static boolean isLocalBinder(IBinder binder) {
+ return !(binder instanceof BinderProxy);
+ }
+
+ private static SurfaceSyncGroup getSurfaceSyncGroup(ISurfaceSyncGroup iSurfaceSyncGroup) {
+ if (iSurfaceSyncGroup instanceof SurfaceSyncGroup) {
+ return (SurfaceSyncGroup) iSurfaceSyncGroup;
+ }
+ return null;
+ }
+
/**
* @hide
*/
@@ -129,20 +129,19 @@
transaction.apply();
}
});
-
}
/**
* Creates a sync.
*
- * @param transactionReadyCallback The complete callback that contains the syncId and
+ * @param transactionReadyConsumer The complete callback that contains the syncId and
* transaction with all the sync data merged. The Transaction
* passed back can be null.
- *
+ * <p>
* NOTE: Only should be used by ViewRootImpl
* @hide
*/
- public SurfaceSyncGroup(String name, Consumer<Transaction> transactionReadyCallback) {
+ public SurfaceSyncGroup(String name, Consumer<Transaction> transactionReadyConsumer) {
// sCounter is a way to give the SurfaceSyncGroup a unique name even if the name passed in
// is not.
// Avoid letting the count get too big so just reset to 0. It's unlikely that we'll have
@@ -153,17 +152,19 @@
mName = name + "#" + sCounter.getAndIncrement();
- mTransactionReadyCallback = transaction -> {
+ mTransactionReadyConsumer = (transaction) -> {
if (DEBUG && transaction != null) {
Log.d(TAG, "Sending non null transaction " + transaction + " to callback for "
+ mName);
}
Trace.instant(Trace.TRACE_TAG_VIEW,
"Final TransactionCallback with " + transaction + " for " + mName);
- transactionReadyCallback.accept(transaction);
+ transactionReadyConsumer.accept(transaction);
synchronized (mLock) {
- for (Pair<Executor, Runnable> callback : mSyncCompleteCallbacks) {
- callback.first.execute(callback.second);
+ // If there's a registered listener with WMS, that means we aren't actually complete
+ // until WMS notifies us that the parent has completed.
+ if (mSurfaceSyncGroupCompletedListener == null) {
+ invokeSyncCompleteListeners();
}
}
};
@@ -175,6 +176,13 @@
}
}
+ @GuardedBy("mLock")
+ private void invokeSyncCompleteListeners() {
+ mSyncCompleteCallbacks.forEach(
+ executorRunnablePair -> executorRunnablePair.first.execute(
+ executorRunnablePair.second));
+ }
+
/**
* Add a {@link Runnable} to be executed when the sync completes.
*
@@ -194,22 +202,15 @@
* set have completed their sync
*/
public void markSyncReady() {
- onTransactionReady(null);
- }
-
- /**
- * Similar to {@link #markSyncReady()}, but a transaction is passed in to merge with the
- * SurfaceSyncGroup.
- *
- * @param t The transaction that merges into the main Transaction for the SurfaceSyncGroup.
- */
- public void onTransactionReady(@Nullable Transaction t) {
Trace.traceBegin(Trace.TRACE_TAG_VIEW, "markSyncReady " + mName);
synchronized (mLock) {
- mSyncReady = true;
- if (t != null) {
- mTransaction.merge(t);
+ if (mHasWMSync) {
+ try {
+ WindowManagerGlobal.getWindowManagerService().markSurfaceSyncGroupReady(mToken);
+ } catch (RemoteException e) {
+ }
}
+ mSyncReady = true;
checkIfSyncIsComplete();
}
Trace.traceEnd(Trace.TRACE_TAG_VIEW);
@@ -232,21 +233,40 @@
Consumer<SurfaceViewFrameCallback> frameCallbackConsumer) {
SurfaceSyncGroup surfaceSyncGroup = new SurfaceSyncGroup(surfaceView.getName());
if (addToSync(surfaceSyncGroup, false /* parentSyncGroupMerge */)) {
- frameCallbackConsumer.accept(
- () -> surfaceView.syncNextFrame(surfaceSyncGroup::onTransactionReady));
+ frameCallbackConsumer.accept(() -> surfaceView.syncNextFrame(transaction -> {
+ surfaceSyncGroup.addTransactionToSync(transaction);
+ surfaceSyncGroup.markSyncReady();
+ }));
return true;
}
return false;
}
/**
- * Add a View's rootView to a sync set.
+ * Add an AttachedSurfaceControl to a sync set.
*
- * @param viewRoot The viewRoot that will be add to the sync set
+ * @param viewRoot The viewRoot that will be add to the sync set.
* @return true if the View was successfully added to the SyncGroup, false otherwise.
+ * @see #addToSync(AttachedSurfaceControl, Runnable)
*/
@UiThread
public boolean addToSync(@Nullable AttachedSurfaceControl viewRoot) {
+ return addToSync(viewRoot, null /* runnable */);
+ }
+
+ /**
+ * Add an AttachedSurfaceControl to a sync set. The AttachedSurfaceControl will pause rendering
+ * to ensure the runnable can be invoked and the sync picks up the frame that contains the
+ * changes.
+ *
+ * @param viewRoot The viewRoot that will be add to the sync set.
+ * @param runnable The runnable to be invoked before adding to the sync group.
+ * @return true if the View was successfully added to the SyncGroup, false otherwise.
+ * @see #addToSync(AttachedSurfaceControl)
+ */
+ @UiThread
+ public boolean addToSync(@Nullable AttachedSurfaceControl viewRoot,
+ @Nullable Runnable runnable) {
if (viewRoot == null) {
return false;
}
@@ -254,67 +274,133 @@
if (surfaceSyncGroup == null) {
return false;
}
- return addToSync(surfaceSyncGroup, false /* parentSyncGroupMerge */);
+
+ return addToSync(surfaceSyncGroup, false /* parentSyncGroupMerge */, runnable);
+ }
+
+ /**
+ * Helper method to add a SurfaceControlViewHost.SurfacePackage to the sync group. This will
+ * get the SurfaceSyncGroup from the SurfacePackage, which will pause rendering for the
+ * SurfaceControlViewHost. The runnable will be invoked to allow the host to update the SCVH
+ * in a synchronized way. Finally, it will add the SCVH to the SurfaceSyncGroup and unpause
+ * rendering in the SCVH, allowing the changes to get picked up and included in the sync.
+ *
+ * @param surfacePackage The SurfacePackage that should be synced
+ * @param runnable The Runnable that's invoked before getting the frame to sync.
+ * @return true if the SCVH was successfully added to the current SyncGroup, false
+ * otherwise.
+ */
+ public boolean addToSync(@NonNull SurfaceControlViewHost.SurfacePackage surfacePackage,
+ @Nullable Runnable runnable) {
+ ISurfaceSyncGroup surfaceSyncGroup;
+ try {
+ surfaceSyncGroup = surfacePackage.getRemoteInterface().getSurfaceSyncGroup();
+ } catch (RemoteException e) {
+ Log.e(TAG, "Failed to add SurfaceControlViewHost to SurfaceSyncGroup");
+ return false;
+ }
+
+ if (surfaceSyncGroup == null) {
+ Log.e(TAG, "Failed to add SurfaceControlViewHost to SurfaceSyncGroup. "
+ + "SCVH returned null SurfaceSyncGroup");
+ return false;
+ }
+ return addToSync(surfaceSyncGroup, false /* parentSyncGroupMerge */, runnable);
+ }
+
+ @Override
+ public boolean addToSync(ISurfaceSyncGroup surfaceSyncGroup, boolean parentSyncGroupMerge) {
+ return addToSync(surfaceSyncGroup, parentSyncGroupMerge, null);
}
/**
* Add a {@link SurfaceSyncGroup} to a sync set. The sync set will wait for all
* SyncableSurfaces to complete before notifying.
*
- * @param surfaceSyncGroup A SyncableSurface that implements how to handle syncing
- * buffers.
+ * @param surfaceSyncGroup A SyncableSurface that implements how to handle syncing
+ * buffers.
+ * @param parentSyncGroupMerge true if the ISurfaceSyncGroup is added because its child was
+ * added to a new SurfaceSyncGroup. That would require the code to
+ * call newParent.addToSync(oldParent). When this occurs, we need to
+ * reverse the merge order because the oldParent should always be
+ * considered older than any other SurfaceSyncGroups.
+ * @param runnable The Runnable that's invoked before adding the SurfaceSyncGroup
* @return true if the SyncGroup was successfully added to the current SyncGroup, false
* otherwise.
*/
- public boolean addToSync(SurfaceSyncGroup surfaceSyncGroup, boolean parentSyncGroupMerge) {
+ public boolean addToSync(ISurfaceSyncGroup surfaceSyncGroup, boolean parentSyncGroupMerge,
+ @Nullable Runnable runnable) {
Trace.traceBegin(Trace.TRACE_TAG_VIEW,
- "addToSync child=" + surfaceSyncGroup.mName + " parent=" + mName);
- TransactionReadyCallback transactionReadyCallback = new TransactionReadyCallback() {
- @Override
- public void onTransactionReady(Transaction t) {
- if (DEBUG) {
- Log.d(TAG, "onTransactionReady called for" + surfaceSyncGroup.mName
- + " and sent to " + mName);
- }
- synchronized (mLock) {
- if (t != null) {
- // When an older parent sync group is added due to a child syncGroup getting
- // added to multiple groups, we need to maintain merge order so the older
- // parentSyncGroup transactions are overwritten by anything in the newer
- // parentSyncGroup.
- if (parentSyncGroupMerge) {
- t.merge(mTransaction);
- }
- mTransaction.merge(t);
- }
- mPendingSyncs.remove(this);
- Trace.instant(Trace.TRACE_TAG_VIEW,
- "onTransactionReady child=" + surfaceSyncGroup.mName + " parent="
- + mName);
- checkIfSyncIsComplete();
- }
- }
- };
-
+ "addToSync token=" + mToken.hashCode() + " parent=" + mName);
synchronized (mLock) {
if (mSyncReady) {
- Log.e(TAG, "Sync " + mName + " was already marked as ready. No more "
- + "SurfaceSyncGroups can be added.");
+ Log.w(TAG, "Trying to add to sync when already marked as ready " + mName);
Trace.traceEnd(Trace.TRACE_TAG_VIEW);
return false;
}
- mPendingSyncs.add(transactionReadyCallback);
- if (DEBUG) {
- Log.d(TAG, "addToSync " + surfaceSyncGroup.mName + " to " + mName + " mSyncReady="
- + mSyncReady + " mPendingSyncs=" + mPendingSyncs.size());
+ }
+
+ if (runnable != null) {
+ runnable.run();
+ }
+
+ if (isLocalBinder(surfaceSyncGroup.asBinder())) {
+ boolean didAddLocalSync = addLocalSync(surfaceSyncGroup, parentSyncGroupMerge);
+ Trace.traceEnd(Trace.TRACE_TAG_VIEW);
+ return didAddLocalSync;
+ }
+
+ synchronized (mLock) {
+ if (!mHasWMSync) {
+ // We need to add a signal into WMS since WMS will be creating a new parent
+ // SurfaceSyncGroup. When the parent SSG in WMS completes, only then do we
+ // notify the registered listeners that the entire SurfaceSyncGroup is complete.
+ // This is because the callers don't realize that when adding a different process
+ // to this SSG, it isn't actually adding to this SSG and really just creating a
+ // link in WMS. Because of this, the callers would expect the complete listeners
+ // to only be called when everything, including the other process's
+ // SurfaceSyncGroups, have completed. Only WMS has that info so we need to send the
+ // listener to WMS when we set up a server side sync.
+ mSurfaceSyncGroupCompletedListener = new ISurfaceSyncGroupCompletedListener.Stub() {
+ @Override
+ public void onSurfaceSyncGroupComplete() {
+ synchronized (mLock) {
+ invokeSyncCompleteListeners();
+ }
+ }
+ };
+ if (!addSyncToWm(mToken, false /* parentSyncGroupMerge */,
+ mSurfaceSyncGroupCompletedListener)) {
+ mSurfaceSyncGroupCompletedListener = null;
+ Trace.traceEnd(Trace.TRACE_TAG_VIEW);
+ return false;
+ }
+ mHasWMSync = true;
}
}
- surfaceSyncGroup.onAddedToSyncGroup(this, transactionReadyCallback);
+ try {
+ surfaceSyncGroup.onAddedToSyncGroup(mToken, parentSyncGroupMerge);
+ } catch (RemoteException e) {
+ Trace.traceEnd(Trace.TRACE_TAG_VIEW);
+ return false;
+ }
+
Trace.traceEnd(Trace.TRACE_TAG_VIEW);
return true;
}
+ @Override
+ public final boolean onAddedToSyncGroup(IBinder parentSyncGroupToken,
+ boolean parentSyncGroupMerge) {
+ Trace.traceBegin(Trace.TRACE_TAG_VIEW,
+ "onAddedToSyncGroup token=" + parentSyncGroupToken.hashCode() + " child=" + mName);
+ boolean didAdd = addSyncToWm(parentSyncGroupToken, parentSyncGroupMerge, null);
+ Trace.traceEnd(Trace.TRACE_TAG_VIEW);
+ return didAdd;
+ }
+
+
/**
* Add a Transaction to this sync set. This allows the caller to provide other info that
* should be synced with the transactions.
@@ -325,39 +411,75 @@
}
}
- @GuardedBy("mLock")
- private void checkIfSyncIsComplete() {
- if (mFinished) {
- if (DEBUG) {
- Log.d(TAG, "SurfaceSyncGroup=" + mName + " is already complete");
- }
- return;
- }
-
- Trace.instant(Trace.TRACE_TAG_VIEW,
- "checkIfSyncIsComplete " + mName + " mSyncReady=" + mSyncReady + " mPendingSyncs="
- + mPendingSyncs.size());
- if (!mSyncReady || !mPendingSyncs.isEmpty()) {
- if (DEBUG) {
- Log.d(TAG,
- "SurfaceSyncGroup=" + mName + " is not complete. mSyncReady=" + mSyncReady
- + " mPendingSyncs=" + mPendingSyncs.size());
- }
- return;
- }
-
- if (DEBUG) {
- Log.d(TAG, "Successfully finished sync id=" + mName);
- }
- mTransactionReadyCallback.onTransactionReady(mTransaction);
- mFinished = true;
+ /**
+ * Invoked when the SurfaceSyncGroup has been added to another SurfaceSyncGroup and is ready
+ * to proceed.
+ */
+ public void onSyncReady() {
}
- private void onAddedToSyncGroup(SurfaceSyncGroup parentSyncGroup,
- TransactionReadyCallback transactionReadyCallback) {
+ private boolean addSyncToWm(IBinder token, boolean parentSyncGroupMerge,
+ @Nullable ISurfaceSyncGroupCompletedListener surfaceSyncGroupCompletedListener) {
+ try {
+ if (DEBUG) {
+ Log.d(TAG, "Attempting to add remote sync to " + mName
+ + ". Setting up Sync in WindowManager.");
+ }
+ Trace.traceBegin(Trace.TRACE_TAG_VIEW,
+ "addSyncToWm=" + token.hashCode() + " group=" + mName);
+ AddToSurfaceSyncGroupResult addToSyncGroupResult = new AddToSurfaceSyncGroupResult();
+ if (!WindowManagerGlobal.getWindowManagerService().addToSurfaceSyncGroup(token,
+ parentSyncGroupMerge, surfaceSyncGroupCompletedListener,
+ addToSyncGroupResult)) {
+ Trace.traceEnd(Trace.TRACE_TAG_VIEW);
+ return false;
+ }
+
+ setTransactionCallbackFromParent(addToSyncGroupResult.mParentSyncGroup,
+ addToSyncGroupResult.mTransactionReadyCallback);
+ } catch (RemoteException e) {
+ Trace.traceEnd(Trace.TRACE_TAG_VIEW);
+ return false;
+ }
+ Trace.traceEnd(Trace.TRACE_TAG_VIEW);
+ return true;
+ }
+
+ private boolean addLocalSync(ISurfaceSyncGroup childSyncToken, boolean parentSyncGroupMerge) {
+ if (DEBUG) {
+ Log.d(TAG, "Adding local sync " + mName);
+ }
+
+ SurfaceSyncGroup childSurfaceSyncGroup = getSurfaceSyncGroup(childSyncToken);
+ if (childSurfaceSyncGroup == null) {
+ Log.e(TAG, "Trying to add a local sync that's either not valid or not from the"
+ + " local process=" + childSyncToken);
+ return false;
+ }
+
Trace.traceBegin(Trace.TRACE_TAG_VIEW,
- "onAddedToSyncGroup child=" + mName + " parent=" + parentSyncGroup.mName);
+ "addLocalSync=" + childSurfaceSyncGroup.mName + " parent=" + mName);
+ ITransactionReadyCallback callback =
+ createTransactionReadyCallback(parentSyncGroupMerge);
+
+ if (callback == null) {
+ return false;
+ }
+
+ childSurfaceSyncGroup.setTransactionCallbackFromParent(this, callback);
+ Trace.traceEnd(Trace.TRACE_TAG_VIEW);
+ return true;
+ }
+
+ private void setTransactionCallbackFromParent(ISurfaceSyncGroup parentSyncGroup,
+ ITransactionReadyCallback transactionReadyCallback) {
+ if (DEBUG) {
+ Log.d(TAG, "setTransactionCallbackFromParent " + mName);
+ }
boolean finished = false;
+ Trace.traceBegin(Trace.TRACE_TAG_VIEW,
+ "setTransactionCallbackFromParent " + mName + " callback="
+ + transactionReadyCallback.hashCode());
synchronized (mLock) {
if (mFinished) {
finished = true;
@@ -370,26 +492,34 @@
// from the original parent are also combined with the new parent SurfaceSyncGroup.
if (mParentSyncGroup != null && mParentSyncGroup != parentSyncGroup) {
if (DEBUG) {
- Log.d(TAG, "Trying to add to " + parentSyncGroup.mName
- + " but already part of sync group " + mParentSyncGroup.mName + " "
+ Log.d(TAG, "Trying to add to " + parentSyncGroup
+ + " but already part of sync group " + mParentSyncGroup + " "
+ mName);
}
- parentSyncGroup.addToSync(mParentSyncGroup, true /* parentSyncGroupMerge */);
- }
-
- if (mParentSyncGroup == parentSyncGroup) {
- if (DEBUG) {
- Log.d(TAG, "Added to parent that was already the parent");
+ try {
+ parentSyncGroup.addToSync(mParentSyncGroup,
+ true /* parentSyncGroupMerge */);
+ } catch (RemoteException e) {
}
}
+
+ if (DEBUG && mParentSyncGroup == parentSyncGroup) {
+ Log.d(TAG, "Added to parent that was already the parent");
+ }
+
+ Consumer<Transaction> lastCallback = mTransactionReadyConsumer;
mParentSyncGroup = parentSyncGroup;
- final TransactionReadyCallback lastCallback = mTransactionReadyCallback;
- mTransactionReadyCallback = t -> {
+ mTransactionReadyConsumer = (transaction) -> {
Trace.traceBegin(Trace.TRACE_TAG_VIEW,
- "transactionReadyCallback " + mName + " parent="
- + parentSyncGroup.mName);
- lastCallback.onTransactionReady(null);
- transactionReadyCallback.onTransactionReady(t);
+ "transactionReadyCallback " + mName + " callback="
+ + transactionReadyCallback.hashCode());
+ lastCallback.accept(null);
+
+ try {
+ transactionReadyCallback.onTransactionReady(transaction);
+ } catch (RemoteException e) {
+ transaction.apply();
+ }
Trace.traceEnd(Trace.TRACE_TAG_VIEW);
};
}
@@ -398,7 +528,12 @@
// Invoke the callback outside of the lock when the SurfaceSyncGroup being added was already
// complete.
if (finished) {
- transactionReadyCallback.onTransactionReady(null);
+ try {
+ transactionReadyCallback.onTransactionReady(null);
+ } catch (RemoteException e) {
+ }
+ } else {
+ onSyncReady();
}
Trace.traceEnd(Trace.TRACE_TAG_VIEW);
}
@@ -407,19 +542,89 @@
return mName;
}
+ @GuardedBy("mLock")
+ private void checkIfSyncIsComplete() {
+ if (mFinished) {
+ if (DEBUG) {
+ Log.d(TAG, "SurfaceSyncGroup=" + mName + " is already complete");
+ }
+ mTransaction.apply();
+ return;
+ }
+
+ Trace.instant(Trace.TRACE_TAG_VIEW,
+ "checkIfSyncIsComplete " + mName + " mSyncReady=" + mSyncReady + " mPendingSyncs="
+ + mPendingSyncs.size());
+
+ if (!mSyncReady || !mPendingSyncs.isEmpty()) {
+ if (DEBUG) {
+ Log.d(TAG, "SurfaceSyncGroup=" + mName + " is not complete. mSyncReady="
+ + mSyncReady + " mPendingSyncs=" + mPendingSyncs.size());
+ }
+ return;
+ }
+
+ if (DEBUG) {
+ Log.d(TAG, "Successfully finished sync id=" + mName);
+ }
+ mTransactionReadyConsumer.accept(mTransaction);
+ mFinished = true;
+ }
+
/**
- * Interface so the SurfaceSyncer can know when it's safe to start and when everything has been
- * completed. The caller should invoke the calls when the rendering has started and finished a
- * frame.
+ * Create an {@link ITransactionReadyCallback} that the current SurfaceSyncGroup will wait on
+ * before completing. The caller must ensure that the
+ * {@link ITransactionReadyCallback#onTransactionReady(Transaction)} in order for this
+ * SurfaceSyncGroup to complete.
+ *
+ * @param parentSyncGroupMerge true if the ISurfaceSyncGroup is added because its child was
+ * added to a new SurfaceSyncGroup. That would require the code to
+ * call newParent.addToSync(oldParent). When this occurs, we need to
+ * reverse the merge order because the oldParent should always be
+ * considered older than any other SurfaceSyncGroups.
*/
- private interface TransactionReadyCallback {
- /**
- * Invoked when the transaction is ready to sync.
- *
- * @param t The transaction that contains the anything to be included in the synced. This
- * can be null if there's nothing to sync
- */
- void onTransactionReady(@Nullable Transaction t);
+ public ITransactionReadyCallback createTransactionReadyCallback(boolean parentSyncGroupMerge) {
+ if (DEBUG) {
+ Log.d(TAG, "createTransactionReadyCallback " + mName);
+ }
+ ITransactionReadyCallback transactionReadyCallback =
+ new ITransactionReadyCallback.Stub() {
+ @Override
+ public void onTransactionReady(Transaction t) {
+ synchronized (mLock) {
+ if (t != null) {
+ // When an older parent sync group is added due to a child syncGroup
+ // getting added to multiple groups, we need to maintain merge order
+ // so the older parentSyncGroup transactions are overwritten by
+ // anything in the newer parentSyncGroup.
+ if (parentSyncGroupMerge) {
+ t.merge(mTransaction);
+ }
+ mTransaction.merge(t);
+ }
+ mPendingSyncs.remove(this);
+ Trace.instant(Trace.TRACE_TAG_VIEW,
+ "onTransactionReady group=" + mName + " callback="
+ + hashCode());
+ checkIfSyncIsComplete();
+ }
+ }
+ };
+
+ synchronized (mLock) {
+ if (mSyncReady) {
+ Log.e(TAG, "Sync " + mName
+ + " was already marked as ready. No more SurfaceSyncGroups can be added.");
+ return null;
+ }
+ mPendingSyncs.add(transactionReadyCallback);
+ Trace.instant(Trace.TRACE_TAG_VIEW,
+ "createTransactionReadyCallback " + mName + " mPendingSyncs="
+ + mPendingSyncs.size() + " transactionReady="
+ + transactionReadyCallback.hashCode());
+ }
+
+ return transactionReadyCallback;
}
/**
diff --git a/core/java/android/window/SurfaceSyncGroup.md b/core/java/android/window/SurfaceSyncGroup.md
index b4faeac..406c230 100644
--- a/core/java/android/window/SurfaceSyncGroup.md
+++ b/core/java/android/window/SurfaceSyncGroup.md
@@ -2,7 +2,7 @@
### Overview
-A generic way for data to be gathered so multiple surfaces can be synced. This is intended to be used with Views, SurfaceView, and any other surface that wants to be involved in a sync. This allows different parts of the Android system to synchronize different windows and layers themselves without having to go through WindowManagerService
+A generic way for data to be gathered so multiple surfaces can be synced. This is intended to be used with Views, SurfaceView, and any other surface that wants to be involved in a sync. This allows different parts of the Android system to synchronize different windows and layers themselves.
### Code
@@ -12,47 +12,47 @@
The first step is to create a sync request. This is done by creating a new `SurfaceSyncGroup`.
There are two constructors: one that accepts a `Consumer<Transaction>` and one that's empty. The empty constructor will automatically apply the final transaction. The second constructor should only be used by ViewRootImpl. The purpose of this one is to allow the caller to get back the merged transaction without it being applied. ViewRootImpl uses it to send the transaction to WindowManagerService to be synced there. Using this one for other cases is unsafe because the caller may hold the transaction longer than expected and prevent buffers from being latched and released.
-##### markSyncReady
-
-When the caller has added all the `SyncTarget` to the sync, they should call `markSyncReady()` If the caller doesn't call this, the sync will never complete since the SurfaceSyncGroup wants to give the caller a chance to add all the SyncTargets before considering the sync ready. Before `markSyncReady` is called, the `SyncTargets` can actually produce a frame, which will just be held in a transaction until all other `SyncTargets` are ready AND `markSyncReady` has been called. Once markSyncReady has been called, you cannot add any more `SyncTargets` to that particular SurfaceSyncGroup.
-
##### addToSync
-The caller will invoke `addToSync` for every `SyncTarget` that it wants included. There are a few helper methods since the most common cases are Views and SurfaceView
+The caller will invoke `addToSync` for every `SurfaceSyncGroup` that it wants included. There are a few helper methods since the most common cases are Views and SurfaceView
* `addToSync(AttachedSurfaceControl)` - This is used for syncing the root of the View, specificially the ViewRootImpl
* `addToSync(SurfaceView, Consumer<SurfaceViewFrameCallback>)` - This is to sync a SurfaceView. Since SurfaceViews are rendered by the app, the caller will be expected to provide a way to get back the buffer to sync. More details about that [below](#surfaceviewframecallback)
-* `addToSync(SyncTarget)` - This is the generic method. It can be used to sync arbitrary info. The SyncTarget interface has required methods that need to be implemented to properly get the transaction to sync.
+* `addToSync(SurfaceControlViewHost.SurfacePackage)` - This is to sync an embedded window. The host can call addToSync and pass in the SurfacePackage, where the SurfaceSyncGroup will ensure it's added to the sync.
+* `addToSync(ISurfaceSyncGroup)` - This is the generic method. It can be used to sync arbitrary info. Most likely the caller will pass in a SurfaceSyncGroup object and then they are responsible for calling markSyncReady for the child SurfaceSyncGroup.
When calling addToSync with either AttachedSurfaceControl or SurfaceView, it must be called on the UI Thread. This is to ensure consistent behavior, where any UI changes done while still on the UI thread are included in this frame. The next vsync will pick up those changes and request to draw.
+An additional Runnable argument can be passed in which ensures the Runnable has executed before adding the child SurfaceSyncGroup to the parent. The purpose of this Runnable is to execute any changes the caller wants and they are guaranteed to be picked up in the sync.
+
+##### markSyncReady
+
+When the caller has added all the `SurfaceSyncGroup` to the sync, they should call `markSyncReady()` If the caller doesn't call this, the sync will never complete since the SurfaceSyncGroup wants to give the caller a chance to add SurfaceSyncGroups before considering the sync ready. Before `markSyncReady` is called, the `SurfaceSyncGroups` can actually produce a frame, which will just be held in a transaction until all other `SurfaceSyncGroup` are ready AND `markSyncReady` has been called. Once markSyncReady has been called, you cannot add any more `SurfaceSyncGroup` to that particular SurfaceSyncGroup.
+
##### addTransactionToSync
This is a simple method that allows callers to add generic Transactions to the sync. The caller invokes `addTransactionToSync(Transaction)`. This can be used for any additional things that need to be included in the same SyncGroup.
-##### merge
-
-To add more flexibility to Syncs, an API is provided to merge SurfaceSyncGroups. The caller provides the SurfaceSyncGroup it wants merged. The current SurfaceSyncGroup will now wait for the passed in SurfaceSyncGroup to complete, as well as its own SyncTargets to complete before invoking the callback. The passed in SurfaceSyncGroup will also get a complete callback but only when its SurfaceSyncGroup completes, not the one it merged into. If a `Consumer<Transaction>` was passed in to the SurfaceSyncGroup, it will get back an emtpy Transaction so it can't accidentally apply things that were meant to be merged.
-
##### addSyncCompleteCallback
-This allows callers to receive a callback when the sync is complete. The method takes in an Executor and a Runnable that will be invoked when the SurfaceSyncGroup has completed. The Executor is used to invoke the callback on the desired thread. You can add more than one callback.
-
-##### SyncTarget
-
-This interface is used to handle syncs. The interface has two methods
-* `onReadyToSync(SyncBufferCallback)` - This one must be implemented. The sync will notify the `SyncTarget` so it can invoke the `SyncBufferCallback`, letting the sync know when it's ready.
-* `onSyncComplete()` - This method is optional. It's used to notify the `SyncTarget` that the entire sync is complete. This is similar to the callback sent in `setupSync`, but it's invoked to the `SyncTargets` rather than the caller who started the sync. This is used by ViewRootImpl to restore the state when the entire sync is done
-
-When syncing ViewRootImpl, these methods are implemented already since ViewRootImpl handles the rendering requests and timing.
-
-##### SyncBufferCallback
-
-This interface is used to tell the sync that this SyncTarget is ready. There's only method here, `onBufferReady(Transaction)`, that sends back the transaction that contains the data to be synced, normally with a buffer.
+This allows callers to receive a callback when the sync is complete. The caller will only receive a complete callback when the specific SurfaceSyncGroup it registered with is complete. This means that the SurfaceSyncGroup has been marked as ready and all children are complete. This doesn't mean the transaction has been applied since it could be passed to a parent SurfaceSyncGroup or passed to another process. This can be helpful if the caller wants to know that all the children have rendered their frame and possibly to ensure they can pace. The method takes in an Executor and a Runnable that will be invoked when the SurfaceSyncGroup has completed. The Executor is used to invoke the callback on the desired thread. You can add more than one callback.
##### SurfaceViewFrameCallback
As mentioned above, SurfaceViews are a special case because the buffers produced are handled by the app, and not the framework. Because of this, the SurfaceSyncGroup doesn't know which frame to sync. Therefore, to sync SurfaceViews, the caller must provide a way to notify the SurfaceSyncGroup that it's going to render a buffer and that this next buffer is the one to sync. The `SurfaceViewFrameCallback` has one method `onFrameStarted()`. When this is invoked, the SurfaceSyncGroup sets up a request to sync the next buffer for the SurfaceView.
+#### ViewRootImpl's SurfaceSyncGroup
+
+The most common way to use SurfaceSyncGroups is to sync multiple ViewRootImpls. The framework handles the timing and rendering of the ViewRootImpl, so it's expected that the caller doesn't need to know about this to ensure it's properly synced. This is done by the following flow.
+
+When ViewRootImpl is added to a SurfaceSyncGroup, it's done so via `addToSync(AttachedSurfaceControl)`. The SurfaceSyncGroup code will call into ViewRootImpl, where either a new SurfaceSyncGroup is created or it returns an already active SurfaceSyncGroup. This active SurfaceSyncGroup is stored in ViewRootImpl and is tied to a rendering cycle. If multiple syncs are requested before VRI draws, they will all get back the same SurfaceSyncGroup object. This is to ensure we can make multiple changes without having to queue up several frames and causing things to get backed up. For example, if SurfaceSyncGroup1 wants to resize VRI and then SurfaceSyncGroup2 wants to change an attribute, if they are both done before a frame is drawn, then both those changes are picked up together. Once VRI starts a draw pass, it will clear the reference to the active SurfaceSyncGroup so any new changes that want to be synced are done with a new SurfaceSyncGroup object. The old active SurfaceSyncGroup is passed via lambda when the rendering is occuring. Once RenderThread completes the frame, VRI calls `SurfaceSyncGroup.addTransactionToSync(Transaction)`, passing in the transaction that contains the buffer and then `SurfaceSyncGroup.markSyncReady()` so the VRI SurfaceSyncGroup knows it's complete. This way we can start additional syncs without having to wait for the RenderThread to complete.
+
+#### SurfaceSyncGroup added to Multiple SurfaceSyncGroups
+There are cases where multiple places are trying to sync the same object. This is more common with VRI where you may have multiple changes for the same vsync rendering cycle, but different places requested the sync. Because each SurfaceSyncGroup may also contain other SurfaceSyncGroups, we need to combine everything. So for example, if SurfaceSyncGroup1 wants to sync VRI and SurfaceSyncGroup2 wants to sync VRI, but SSG-1 already contains SSG-A and SSG-2 already contains SSG-B, we need to ensure SSG-A, SSG-B, and VRI are all applied together to ensure the contract is held. This is done by creating a tree like structure and merging parents when needed. VRI will be added to SSG-1. Then SSG-2 also requests to sync VRI. VRI's SSG will see that it already is part of a SSG and keeps track of its last parent. The SSG will call newParentSyncGroup.add(oldParentSyncGroup). VRI is now added to both SSG-1 and SSG-2, but will only send it's transaction to SSG-2 (the one it was added to last). SSG-1 is also now added to SSG-2 so it will not apply it's transaction, but send it to SSG-2 to apply. SSG-2 will end up waiting for SSG-1 which is waiting for SSG-A so we know that SSG-2 will have the final transaction that includes everything from SSG-1 and its own children.
+
+#### WindowManagerService Involvement
+
+The above works fine when everything is in process. However, we don't want to expose transactions that are tied to SurfaceControls to other processes. This is because they can inject any call if they have a way to get the SurfaceControl object. Instead, use WMS as an intermediary when trying to sync cross-process. The APIs from the client perspectives don't change and the callers don't have to worry about the implementation. This is all done via the SurfaceSyncGroup code. When SurfaceSyncGroup recognizes that a process is trying to add another SurfaceSyncGroup from a different process, it will not be able to add it locally. Instead, it will call into WMS and register a new SurfaceSyncGroup that will be managed by WMS. It then notifies the other process that it should add itself to this SSG that was created in WMS. The other process will also call into WMS and add its own SSG. WMS is now the parent of both SSG from different processes. This means both processes will send their transaction to WMS, which is secure. When the original SSG calls markSyncReady, it will also mark the SSG in WMS as ready so the WMS created SSG can apply the transaction when all children have completed.
+
### Example
@@ -70,6 +70,7 @@
```
A SurfaceView example:
+
See `frameworks/base/tests/SurfaceViewSyncTest` for a working example
```java
@@ -83,4 +84,26 @@
frameCallback.onFrameStarted()
}
syncGroup.markSyncReady();
+```
+
+A SurfaceControlViewHost example (also an cross process example):
+
+See `frameworks/base/tests/SurfaceControlViewHostTest/.../SurfaceControlViewHostSyncTest.java` for working example
+
+This would sync both the view resize and the embedded resize in the same frame
+```java
+SurfaceSyncGroup syncGroup = new SurfaceSyncGroup(NAME);
+SyncGroup.addSyncCompleteCallback(mMainThreadExecutor, () -> {
+ Log.d(TAG, "syncComplete");
+};
+syncGroup.addToSync(getWindow().getRootSurfaceControl(), () -> {
+ view.getLayoutParams().width = 20;
+ view.getLayoutParams().height = 40;
+ view.requestLayout();
+});
+syncGroup.addToSync(mSurfacePackage, () -> {
+ // Side channel API that's decided between the two processes
+ mEmbedded.resize(20, 40);
+});
+syncGroup.markSyncReady();
```
\ No newline at end of file
diff --git a/core/java/android/window/TaskFragmentAnimationParams.aidl b/core/java/android/window/TaskFragmentAnimationParams.aidl
index 04dee58..8ae84c2 100644
--- a/core/java/android/window/TaskFragmentAnimationParams.aidl
+++ b/core/java/android/window/TaskFragmentAnimationParams.aidl
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2022 The Android Open Source Project
+ * 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.
diff --git a/core/java/android/window/TaskFragmentAnimationParams.java b/core/java/android/window/TaskFragmentAnimationParams.java
index a600a4d..12ad914 100644
--- a/core/java/android/window/TaskFragmentAnimationParams.java
+++ b/core/java/android/window/TaskFragmentAnimationParams.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2022 The Android Open Source Project
+ * 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.
diff --git a/core/java/android/window/TaskFragmentCreationParams.java b/core/java/android/window/TaskFragmentCreationParams.java
index c9ddf92..203d79a 100644
--- a/core/java/android/window/TaskFragmentCreationParams.java
+++ b/core/java/android/window/TaskFragmentCreationParams.java
@@ -71,20 +71,42 @@
*
* This is needed in case we need to launch a placeholder Activity to split below a transparent
* always-expand Activity.
+ *
+ * This should not be used with {@link #mPairedActivityToken}.
*/
@Nullable
private final IBinder mPairedPrimaryFragmentToken;
+ /**
+ * The Activity token to place the new TaskFragment on top of.
+ * When it is set, the new TaskFragment will be positioned right above the target Activity.
+ * Otherwise, the new TaskFragment will be positioned on the top of the Task by default.
+ *
+ * This is needed in case we need to place an Activity into TaskFragment to launch placeholder
+ * below a transparent always-expand Activity, or when there is another Intent being started in
+ * a TaskFragment above.
+ *
+ * This should not be used with {@link #mPairedPrimaryFragmentToken}.
+ */
+ @Nullable
+ private final IBinder mPairedActivityToken;
+
private TaskFragmentCreationParams(
@NonNull TaskFragmentOrganizerToken organizer, @NonNull IBinder fragmentToken,
@NonNull IBinder ownerToken, @NonNull Rect initialBounds,
- @WindowingMode int windowingMode, @Nullable IBinder pairedPrimaryFragmentToken) {
+ @WindowingMode int windowingMode, @Nullable IBinder pairedPrimaryFragmentToken,
+ @Nullable IBinder pairedActivityToken) {
+ if (pairedPrimaryFragmentToken != null && pairedActivityToken != null) {
+ throw new IllegalArgumentException("pairedPrimaryFragmentToken and"
+ + " pairedActivityToken should not be set at the same time.");
+ }
mOrganizer = organizer;
mFragmentToken = fragmentToken;
mOwnerToken = ownerToken;
mInitialBounds.set(initialBounds);
mWindowingMode = windowingMode;
mPairedPrimaryFragmentToken = pairedPrimaryFragmentToken;
+ mPairedActivityToken = pairedActivityToken;
}
@NonNull
@@ -121,6 +143,15 @@
return mPairedPrimaryFragmentToken;
}
+ /**
+ * TODO(b/232476698): remove the hide with adding CTS for this in next release.
+ * @hide
+ */
+ @Nullable
+ public IBinder getPairedActivityToken() {
+ return mPairedActivityToken;
+ }
+
private TaskFragmentCreationParams(Parcel in) {
mOrganizer = TaskFragmentOrganizerToken.CREATOR.createFromParcel(in);
mFragmentToken = in.readStrongBinder();
@@ -128,6 +159,7 @@
mInitialBounds.readFromParcel(in);
mWindowingMode = in.readInt();
mPairedPrimaryFragmentToken = in.readStrongBinder();
+ mPairedActivityToken = in.readStrongBinder();
}
/** @hide */
@@ -139,6 +171,7 @@
mInitialBounds.writeToParcel(dest, flags);
dest.writeInt(mWindowingMode);
dest.writeStrongBinder(mPairedPrimaryFragmentToken);
+ dest.writeStrongBinder(mPairedActivityToken);
}
@NonNull
@@ -164,6 +197,7 @@
+ " initialBounds=" + mInitialBounds
+ " windowingMode=" + mWindowingMode
+ " pairedFragmentToken=" + mPairedPrimaryFragmentToken
+ + " pairedActivityToken=" + mPairedActivityToken
+ "}";
}
@@ -194,6 +228,9 @@
@Nullable
private IBinder mPairedPrimaryFragmentToken;
+ @Nullable
+ private IBinder mPairedActivityToken;
+
public Builder(@NonNull TaskFragmentOrganizerToken organizer,
@NonNull IBinder fragmentToken, @NonNull IBinder ownerToken) {
mOrganizer = organizer;
@@ -224,6 +261,8 @@
* This is needed in case we need to launch a placeholder Activity to split below a
* transparent always-expand Activity.
*
+ * This should not be used with {@link #setPairedActivityToken}.
+ *
* TODO(b/232476698): remove the hide with adding CTS for this in next release.
* @hide
*/
@@ -233,11 +272,32 @@
return this;
}
+ /**
+ * Sets the Activity token to place the new TaskFragment on top of.
+ * When it is set, the new TaskFragment will be positioned right above the target Activity.
+ * Otherwise, the new TaskFragment will be positioned on the top of the Task by default.
+ *
+ * This is needed in case we need to place an Activity into TaskFragment to launch
+ * placeholder below a transparent always-expand Activity, or when there is another Intent
+ * being started in a TaskFragment above.
+ *
+ * This should not be used with {@link #setPairedPrimaryFragmentToken}.
+ *
+ * TODO(b/232476698): remove the hide with adding CTS for this in next release.
+ * @hide
+ */
+ @NonNull
+ public Builder setPairedActivityToken(@Nullable IBinder activityToken) {
+ mPairedActivityToken = activityToken;
+ return this;
+ }
+
/** Constructs the options to create TaskFragment with. */
@NonNull
public TaskFragmentCreationParams build() {
return new TaskFragmentCreationParams(mOrganizer, mFragmentToken, mOwnerToken,
- mInitialBounds, mWindowingMode, mPairedPrimaryFragmentToken);
+ mInitialBounds, mWindowingMode, mPairedPrimaryFragmentToken,
+ mPairedActivityToken);
}
}
}
diff --git a/core/java/android/window/TaskFragmentOperation.aidl b/core/java/android/window/TaskFragmentOperation.aidl
index c21700c..c1ed0c7 100644
--- a/core/java/android/window/TaskFragmentOperation.aidl
+++ b/core/java/android/window/TaskFragmentOperation.aidl
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2022 The Android Open Source Project
+ * 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.
diff --git a/core/java/android/window/TaskFragmentOperation.java b/core/java/android/window/TaskFragmentOperation.java
index bec6c58..0d6a58b 100644
--- a/core/java/android/window/TaskFragmentOperation.java
+++ b/core/java/android/window/TaskFragmentOperation.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2022 The Android Open Source Project
+ * 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.
@@ -19,6 +19,8 @@
import android.annotation.IntDef;
import android.annotation.NonNull;
import android.annotation.Nullable;
+import android.content.Intent;
+import android.os.Bundle;
import android.os.IBinder;
import android.os.Parcel;
import android.os.Parcelable;
@@ -30,41 +32,112 @@
/**
* Data object of params for TaskFragment related {@link WindowContainerTransaction} operation.
*
- * @see WindowContainerTransaction#setTaskFragmentOperation(IBinder, TaskFragmentOperation).
+ * @see WindowContainerTransaction#addTaskFragmentOperation(IBinder, TaskFragmentOperation).
* @hide
*/
-// TODO(b/263436063): move other TaskFragment related operation here.
public final class TaskFragmentOperation implements Parcelable {
+ /**
+ * Type for tracking other {@link WindowContainerTransaction} to TaskFragment that is not set
+ * through {@link TaskFragmentOperation}, such as {@link WindowContainerTransaction#setBounds}.
+ */
+ public static final int OP_TYPE_UNKNOWN = -1;
+
+ /** Creates a new TaskFragment. */
+ public static final int OP_TYPE_CREATE_TASK_FRAGMENT = 0;
+
+ /** Deletes the given TaskFragment. */
+ public static final int OP_TYPE_DELETE_TASK_FRAGMENT = 1;
+
+ /** Starts an Activity in the given TaskFragment. */
+ public static final int OP_TYPE_START_ACTIVITY_IN_TASK_FRAGMENT = 2;
+
+ /** Reparents the given Activity to the given TaskFragment. */
+ public static final int OP_TYPE_REPARENT_ACTIVITY_TO_TASK_FRAGMENT = 3;
+
+ /** Sets two TaskFragments adjacent to each other. */
+ public static final int OP_TYPE_SET_ADJACENT_TASK_FRAGMENTS = 4;
+
+ /** Clears the adjacent TaskFragments relationship. */
+ public static final int OP_TYPE_CLEAR_ADJACENT_TASK_FRAGMENTS = 5;
+
+ /** Requests focus on the top running Activity in the given TaskFragment. */
+ public static final int OP_TYPE_REQUEST_FOCUS_ON_TASK_FRAGMENT = 6;
+
+ /** Sets a given TaskFragment to have a companion TaskFragment. */
+ public static final int OP_TYPE_SET_COMPANION_TASK_FRAGMENT = 7;
+
/** Sets the {@link TaskFragmentAnimationParams} for the given TaskFragment. */
- public static final int OP_TYPE_SET_ANIMATION_PARAMS = 0;
+ public static final int OP_TYPE_SET_ANIMATION_PARAMS = 8;
@IntDef(prefix = { "OP_TYPE_" }, value = {
+ OP_TYPE_UNKNOWN,
+ OP_TYPE_CREATE_TASK_FRAGMENT,
+ OP_TYPE_DELETE_TASK_FRAGMENT,
+ OP_TYPE_START_ACTIVITY_IN_TASK_FRAGMENT,
+ OP_TYPE_REPARENT_ACTIVITY_TO_TASK_FRAGMENT,
+ OP_TYPE_SET_ADJACENT_TASK_FRAGMENTS,
+ OP_TYPE_CLEAR_ADJACENT_TASK_FRAGMENTS,
+ OP_TYPE_REQUEST_FOCUS_ON_TASK_FRAGMENT,
+ OP_TYPE_SET_COMPANION_TASK_FRAGMENT,
OP_TYPE_SET_ANIMATION_PARAMS
})
@Retention(RetentionPolicy.SOURCE)
- @interface OperationType {}
+ public @interface OperationType {}
@OperationType
private final int mOpType;
@Nullable
+ private final TaskFragmentCreationParams mTaskFragmentCreationParams;
+
+ @Nullable
+ private final IBinder mActivityToken;
+
+ @Nullable
+ private final Intent mActivityIntent;
+
+ @Nullable
+ private final Bundle mBundle;
+
+ @Nullable
+ private final IBinder mSecondaryFragmentToken;
+
+ @Nullable
private final TaskFragmentAnimationParams mAnimationParams;
private TaskFragmentOperation(@OperationType int opType,
+ @Nullable TaskFragmentCreationParams taskFragmentCreationParams,
+ @Nullable IBinder activityToken, @Nullable Intent activityIntent,
+ @Nullable Bundle bundle, @Nullable IBinder secondaryFragmentToken,
@Nullable TaskFragmentAnimationParams animationParams) {
mOpType = opType;
+ mTaskFragmentCreationParams = taskFragmentCreationParams;
+ mActivityToken = activityToken;
+ mActivityIntent = activityIntent;
+ mBundle = bundle;
+ mSecondaryFragmentToken = secondaryFragmentToken;
mAnimationParams = animationParams;
}
private TaskFragmentOperation(Parcel in) {
mOpType = in.readInt();
+ mTaskFragmentCreationParams = in.readTypedObject(TaskFragmentCreationParams.CREATOR);
+ mActivityToken = in.readStrongBinder();
+ mActivityIntent = in.readTypedObject(Intent.CREATOR);
+ mBundle = in.readBundle(getClass().getClassLoader());
+ mSecondaryFragmentToken = in.readStrongBinder();
mAnimationParams = in.readTypedObject(TaskFragmentAnimationParams.CREATOR);
}
@Override
public void writeToParcel(@NonNull Parcel dest, int flags) {
dest.writeInt(mOpType);
+ dest.writeTypedObject(mTaskFragmentCreationParams, flags);
+ dest.writeStrongBinder(mActivityToken);
+ dest.writeTypedObject(mActivityIntent, flags);
+ dest.writeBundle(mBundle);
+ dest.writeStrongBinder(mSecondaryFragmentToken);
dest.writeTypedObject(mAnimationParams, flags);
}
@@ -91,6 +164,46 @@
}
/**
+ * Gets the options to create a new TaskFragment.
+ */
+ @Nullable
+ public TaskFragmentCreationParams getTaskFragmentCreationParams() {
+ return mTaskFragmentCreationParams;
+ }
+
+ /**
+ * Gets the Activity token set in this operation.
+ */
+ @Nullable
+ public IBinder getActivityToken() {
+ return mActivityToken;
+ }
+
+ /**
+ * Gets the Intent to start a new Activity.
+ */
+ @Nullable
+ public Intent getActivityIntent() {
+ return mActivityIntent;
+ }
+
+ /**
+ * Gets the Bundle set in this operation.
+ */
+ @Nullable
+ public Bundle getBundle() {
+ return mBundle;
+ }
+
+ /**
+ * Gets the fragment token of the secondary TaskFragment set in this operation.
+ */
+ @Nullable
+ public IBinder getSecondaryFragmentToken() {
+ return mSecondaryFragmentToken;
+ }
+
+ /**
* Gets the animation related override of TaskFragment.
*/
@Nullable
@@ -102,6 +215,21 @@
public String toString() {
final StringBuilder sb = new StringBuilder();
sb.append("TaskFragmentOperation{ opType=").append(mOpType);
+ if (mTaskFragmentCreationParams != null) {
+ sb.append(", taskFragmentCreationParams=").append(mTaskFragmentCreationParams);
+ }
+ if (mActivityToken != null) {
+ sb.append(", activityToken=").append(mActivityToken);
+ }
+ if (mActivityIntent != null) {
+ sb.append(", activityIntent=").append(mActivityIntent);
+ }
+ if (mBundle != null) {
+ sb.append(", bundle=").append(mBundle);
+ }
+ if (mSecondaryFragmentToken != null) {
+ sb.append(", secondaryFragmentToken=").append(mSecondaryFragmentToken);
+ }
if (mAnimationParams != null) {
sb.append(", animationParams=").append(mAnimationParams);
}
@@ -112,9 +240,8 @@
@Override
public int hashCode() {
- int result = mOpType;
- result = result * 31 + mAnimationParams.hashCode();
- return result;
+ return Objects.hash(mOpType, mTaskFragmentCreationParams, mActivityToken, mActivityIntent,
+ mBundle, mSecondaryFragmentToken, mAnimationParams);
}
@Override
@@ -124,6 +251,11 @@
}
final TaskFragmentOperation other = (TaskFragmentOperation) obj;
return mOpType == other.mOpType
+ && Objects.equals(mTaskFragmentCreationParams, other.mTaskFragmentCreationParams)
+ && Objects.equals(mActivityToken, other.mActivityToken)
+ && Objects.equals(mActivityIntent, other.mActivityIntent)
+ && Objects.equals(mBundle, other.mBundle)
+ && Objects.equals(mSecondaryFragmentToken, other.mSecondaryFragmentToken)
&& Objects.equals(mAnimationParams, other.mAnimationParams);
}
@@ -139,6 +271,21 @@
private final int mOpType;
@Nullable
+ private TaskFragmentCreationParams mTaskFragmentCreationParams;
+
+ @Nullable
+ private IBinder mActivityToken;
+
+ @Nullable
+ private Intent mActivityIntent;
+
+ @Nullable
+ private Bundle mBundle;
+
+ @Nullable
+ private IBinder mSecondaryFragmentToken;
+
+ @Nullable
private TaskFragmentAnimationParams mAnimationParams;
/**
@@ -149,6 +296,52 @@
}
/**
+ * Sets the {@link TaskFragmentCreationParams} for creating a new TaskFragment.
+ */
+ @NonNull
+ public Builder setTaskFragmentCreationParams(
+ @Nullable TaskFragmentCreationParams taskFragmentCreationParams) {
+ mTaskFragmentCreationParams = taskFragmentCreationParams;
+ return this;
+ }
+
+ /**
+ * Sets an Activity token to this operation.
+ */
+ @NonNull
+ public Builder setActivityToken(@Nullable IBinder activityToken) {
+ mActivityToken = activityToken;
+ return this;
+ }
+
+ /**
+ * Sets the Intent to start a new Activity.
+ */
+ @NonNull
+ public Builder setActivityIntent(@Nullable Intent activityIntent) {
+ mActivityIntent = activityIntent;
+ return this;
+ }
+
+ /**
+ * Sets a Bundle to this operation.
+ */
+ @NonNull
+ public Builder setBundle(@Nullable Bundle bundle) {
+ mBundle = bundle;
+ return this;
+ }
+
+ /**
+ * Sets the secondary fragment token to this operation.
+ */
+ @NonNull
+ public Builder setSecondaryFragmentToken(@Nullable IBinder secondaryFragmentToken) {
+ mSecondaryFragmentToken = secondaryFragmentToken;
+ return this;
+ }
+
+ /**
* Sets the {@link TaskFragmentAnimationParams} for the given TaskFragment.
*/
@NonNull
@@ -162,7 +355,8 @@
*/
@NonNull
public TaskFragmentOperation build() {
- return new TaskFragmentOperation(mOpType, mAnimationParams);
+ return new TaskFragmentOperation(mOpType, mTaskFragmentCreationParams, mActivityToken,
+ mActivityIntent, mBundle, mSecondaryFragmentToken, mAnimationParams);
}
}
}
diff --git a/core/java/android/window/TaskFragmentOrganizer.java b/core/java/android/window/TaskFragmentOrganizer.java
index 283df76..f785a3d 100644
--- a/core/java/android/window/TaskFragmentOrganizer.java
+++ b/core/java/android/window/TaskFragmentOrganizer.java
@@ -55,7 +55,7 @@
public static final String KEY_ERROR_CALLBACK_TASK_FRAGMENT_INFO = "task_fragment_info";
/**
- * Key to the {@link WindowContainerTransaction.HierarchyOp} in
+ * Key to the {@link TaskFragmentOperation.OperationType} in
* {@link TaskFragmentTransaction.Change#getErrorBundle()}.
*/
public static final String KEY_ERROR_CALLBACK_OP_TYPE = "operation_type";
@@ -112,7 +112,7 @@
* @hide
*/
public static @NonNull Bundle putErrorInfoInBundle(@NonNull Throwable exception,
- @Nullable TaskFragmentInfo info, int opType) {
+ @Nullable TaskFragmentInfo info, @TaskFragmentOperation.OperationType int opType) {
final Bundle errorBundle = new Bundle();
errorBundle.putSerializable(KEY_ERROR_CALLBACK_THROWABLE, exception);
if (info != null) {
diff --git a/core/java/android/window/TaskOrganizer.java b/core/java/android/window/TaskOrganizer.java
index bffd4e4..02878f8 100644
--- a/core/java/android/window/TaskOrganizer.java
+++ b/core/java/android/window/TaskOrganizer.java
@@ -152,15 +152,31 @@
* @param windowingMode Windowing mode to put the root task in.
* @param launchCookie Launch cookie to associate with the task so that is can be identified
* when the {@link ITaskOrganizer#onTaskAppeared} callback is called.
+ * @param removeWithTaskOrganizer True if this task should be removed when organizer destroyed.
+ * @hide
+ */
+ @RequiresPermission(android.Manifest.permission.MANAGE_ACTIVITY_TASKS)
+ public void createRootTask(int displayId, int windowingMode, @Nullable IBinder launchCookie,
+ boolean removeWithTaskOrganizer) {
+ try {
+ mTaskOrganizerController.createRootTask(displayId, windowingMode, launchCookie,
+ removeWithTaskOrganizer);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
+ /**
+ * Creates a persistent root task in WM for a particular windowing-mode.
+ * @param displayId The display to create the root task on.
+ * @param windowingMode Windowing mode to put the root task in.
+ * @param launchCookie Launch cookie to associate with the task so that is can be identified
+ * when the {@link ITaskOrganizer#onTaskAppeared} callback is called.
*/
@RequiresPermission(android.Manifest.permission.MANAGE_ACTIVITY_TASKS)
@Nullable
public void createRootTask(int displayId, int windowingMode, @Nullable IBinder launchCookie) {
- try {
- mTaskOrganizerController.createRootTask(displayId, windowingMode, launchCookie);
- } catch (RemoteException e) {
- throw e.rethrowFromSystemServer();
- }
+ createRootTask(displayId, windowingMode, launchCookie, false /* removeWithTaskOrganizer */);
}
/** Deletes a persistent root task in WM */
diff --git a/core/java/android/window/WindowContainerTransaction.java b/core/java/android/window/WindowContainerTransaction.java
index 647ccf5..cc48d46 100644
--- a/core/java/android/window/WindowContainerTransaction.java
+++ b/core/java/android/window/WindowContainerTransaction.java
@@ -16,6 +16,15 @@
package android.window;
+import static android.window.TaskFragmentOperation.OP_TYPE_CLEAR_ADJACENT_TASK_FRAGMENTS;
+import static android.window.TaskFragmentOperation.OP_TYPE_CREATE_TASK_FRAGMENT;
+import static android.window.TaskFragmentOperation.OP_TYPE_DELETE_TASK_FRAGMENT;
+import static android.window.TaskFragmentOperation.OP_TYPE_REPARENT_ACTIVITY_TO_TASK_FRAGMENT;
+import static android.window.TaskFragmentOperation.OP_TYPE_REQUEST_FOCUS_ON_TASK_FRAGMENT;
+import static android.window.TaskFragmentOperation.OP_TYPE_SET_ADJACENT_TASK_FRAGMENTS;
+import static android.window.TaskFragmentOperation.OP_TYPE_SET_COMPANION_TASK_FRAGMENT;
+import static android.window.TaskFragmentOperation.OP_TYPE_START_ACTIVITY_IN_TASK_FRAGMENT;
+
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.TestApi;
@@ -505,32 +514,29 @@
/**
* Creates a new TaskFragment with the given options.
- * @param taskFragmentOptions the options used to create the TaskFragment.
+ * @param taskFragmentCreationParams the options used to create the TaskFragment.
*/
@NonNull
public WindowContainerTransaction createTaskFragment(
- @NonNull TaskFragmentCreationParams taskFragmentOptions) {
- final HierarchyOp hierarchyOp =
- new HierarchyOp.Builder(HierarchyOp.HIERARCHY_OP_TYPE_CREATE_TASK_FRAGMENT)
- .setTaskFragmentCreationOptions(taskFragmentOptions)
- .build();
- mHierarchyOps.add(hierarchyOp);
- return this;
+ @NonNull TaskFragmentCreationParams taskFragmentCreationParams) {
+ final TaskFragmentOperation operation = new TaskFragmentOperation.Builder(
+ OP_TYPE_CREATE_TASK_FRAGMENT)
+ .setTaskFragmentCreationParams(taskFragmentCreationParams)
+ .build();
+ return addTaskFragmentOperation(taskFragmentCreationParams.getFragmentToken(), operation);
}
/**
* Deletes an existing TaskFragment. Any remaining activities below it will be destroyed.
- * @param taskFragment the TaskFragment to be removed.
+ * @param fragmentToken client assigned unique token to create TaskFragment with specified in
+ * {@link TaskFragmentCreationParams#getFragmentToken()}.
*/
@NonNull
- public WindowContainerTransaction deleteTaskFragment(
- @NonNull WindowContainerToken taskFragment) {
- final HierarchyOp hierarchyOp =
- new HierarchyOp.Builder(HierarchyOp.HIERARCHY_OP_TYPE_DELETE_TASK_FRAGMENT)
- .setContainer(taskFragment.asBinder())
- .build();
- mHierarchyOps.add(hierarchyOp);
- return this;
+ public WindowContainerTransaction deleteTaskFragment(@NonNull IBinder fragmentToken) {
+ final TaskFragmentOperation operation = new TaskFragmentOperation.Builder(
+ OP_TYPE_DELETE_TASK_FRAGMENT)
+ .build();
+ return addTaskFragmentOperation(fragmentToken, operation);
}
/**
@@ -546,16 +552,13 @@
public WindowContainerTransaction startActivityInTaskFragment(
@NonNull IBinder fragmentToken, @NonNull IBinder callerToken,
@NonNull Intent activityIntent, @Nullable Bundle activityOptions) {
- final HierarchyOp hierarchyOp =
- new HierarchyOp.Builder(
- HierarchyOp.HIERARCHY_OP_TYPE_START_ACTIVITY_IN_TASK_FRAGMENT)
- .setContainer(fragmentToken)
- .setReparentContainer(callerToken)
- .setActivityIntent(activityIntent)
- .setLaunchOptions(activityOptions)
- .build();
- mHierarchyOps.add(hierarchyOp);
- return this;
+ final TaskFragmentOperation operation = new TaskFragmentOperation.Builder(
+ OP_TYPE_START_ACTIVITY_IN_TASK_FRAGMENT)
+ .setActivityToken(callerToken)
+ .setActivityIntent(activityIntent)
+ .setBundle(activityOptions)
+ .build();
+ return addTaskFragmentOperation(fragmentToken, operation);
}
/**
@@ -567,33 +570,11 @@
@NonNull
public WindowContainerTransaction reparentActivityToTaskFragment(
@NonNull IBinder fragmentToken, @NonNull IBinder activityToken) {
- final HierarchyOp hierarchyOp =
- new HierarchyOp.Builder(
- HierarchyOp.HIERARCHY_OP_TYPE_REPARENT_ACTIVITY_TO_TASK_FRAGMENT)
- .setReparentContainer(fragmentToken)
- .setContainer(activityToken)
- .build();
- mHierarchyOps.add(hierarchyOp);
- return this;
- }
-
- /**
- * Reparents all children of one TaskFragment to another.
- * @param oldParent children of this TaskFragment will be reparented.
- * @param newParent the new parent TaskFragment to move the children to. If {@code null}, the
- * children will be moved to the leaf Task.
- */
- @NonNull
- public WindowContainerTransaction reparentChildren(
- @NonNull WindowContainerToken oldParent,
- @Nullable WindowContainerToken newParent) {
- final HierarchyOp hierarchyOp =
- new HierarchyOp.Builder(HierarchyOp.HIERARCHY_OP_TYPE_REPARENT_CHILDREN)
- .setContainer(oldParent.asBinder())
- .setReparentContainer(newParent != null ? newParent.asBinder() : null)
- .build();
- mHierarchyOps.add(hierarchyOp);
- return this;
+ final TaskFragmentOperation operation = new TaskFragmentOperation.Builder(
+ OP_TYPE_REPARENT_ACTIVITY_TO_TASK_FRAGMENT)
+ .setActivityToken(activityToken)
+ .build();
+ return addTaskFragmentOperation(fragmentToken, operation);
}
/**
@@ -602,25 +583,36 @@
* {@link #setAdjacentRoots(WindowContainerToken, WindowContainerToken)}, but can be used with
* fragmentTokens when that TaskFragments haven't been created (but will be created in the same
* {@link WindowContainerTransaction}).
- * To reset it, pass {@code null} for {@code fragmentToken2}.
* @param fragmentToken1 client assigned unique token to create TaskFragment with specified
* in {@link TaskFragmentCreationParams#getFragmentToken()}.
* @param fragmentToken2 client assigned unique token to create TaskFragment with specified
- * in {@link TaskFragmentCreationParams#getFragmentToken()}. If it is
- * {@code null}, the transaction will reset the adjacent TaskFragment.
+ * in {@link TaskFragmentCreationParams#getFragmentToken()}.
*/
@NonNull
public WindowContainerTransaction setAdjacentTaskFragments(
- @NonNull IBinder fragmentToken1, @Nullable IBinder fragmentToken2,
+ @NonNull IBinder fragmentToken1, @NonNull IBinder fragmentToken2,
@Nullable TaskFragmentAdjacentParams params) {
- final HierarchyOp hierarchyOp =
- new HierarchyOp.Builder(HierarchyOp.HIERARCHY_OP_TYPE_SET_ADJACENT_TASK_FRAGMENTS)
- .setContainer(fragmentToken1)
- .setReparentContainer(fragmentToken2)
- .setLaunchOptions(params != null ? params.toBundle() : null)
- .build();
- mHierarchyOps.add(hierarchyOp);
- return this;
+ final TaskFragmentOperation operation = new TaskFragmentOperation.Builder(
+ OP_TYPE_SET_ADJACENT_TASK_FRAGMENTS)
+ .setSecondaryFragmentToken(fragmentToken2)
+ .setBundle(params != null ? params.toBundle() : null)
+ .build();
+ return addTaskFragmentOperation(fragmentToken1, operation);
+ }
+
+ /**
+ * Clears the adjacent TaskFragments relationship that is previously set through
+ * {@link #setAdjacentTaskFragments}. Clear operation on one TaskFragment will also clear its
+ * current adjacent TaskFragment's.
+ * @param fragmentToken client assigned unique token to create TaskFragment with specified
+ * in {@link TaskFragmentCreationParams#getFragmentToken()}.
+ */
+ @NonNull
+ public WindowContainerTransaction clearAdjacentTaskFragments(@NonNull IBinder fragmentToken) {
+ final TaskFragmentOperation operation = new TaskFragmentOperation.Builder(
+ OP_TYPE_CLEAR_ADJACENT_TASK_FRAGMENTS)
+ .build();
+ return addTaskFragmentOperation(fragmentToken, operation);
}
/**
@@ -700,14 +692,10 @@
*/
@NonNull
public WindowContainerTransaction requestFocusOnTaskFragment(@NonNull IBinder fragmentToken) {
- final HierarchyOp hierarchyOp =
- new HierarchyOp.Builder(
- HierarchyOp.HIERARCHY_OP_TYPE_REQUEST_FOCUS_ON_TASK_FRAGMENT)
- .setContainer(fragmentToken)
- .build();
- mHierarchyOps.add(hierarchyOp);
- return this;
-
+ final TaskFragmentOperation operation = new TaskFragmentOperation.Builder(
+ OP_TYPE_REQUEST_FOCUS_ON_TASK_FRAGMENT)
+ .build();
+ return addTaskFragmentOperation(fragmentToken, operation);
}
/**
@@ -728,30 +716,32 @@
}
/**
- * Sets the TaskFragment {@code container} to have a companion TaskFragment {@code companion}.
+ * Sets the TaskFragment {@code fragmentToken} to have a companion TaskFragment
+ * {@code companionFragmentToken}.
* This indicates that the organizer will remove the TaskFragment when the companion
* TaskFragment is removed.
*
- * @param container the TaskFragment container
- * @param companion the companion TaskFragment. If it is {@code null}, the transaction will
- * reset the companion TaskFragment.
+ * @param fragmentToken client assigned unique token to create TaskFragment with specified
+ * in {@link TaskFragmentCreationParams#getFragmentToken()}.
+ * @param companionFragmentToken client assigned unique token to create TaskFragment with
+ * specified in
+ * {@link TaskFragmentCreationParams#getFragmentToken()}.
+ * If it is {@code null}, the transaction will reset the companion
+ * TaskFragment.
* @hide
*/
@NonNull
- public WindowContainerTransaction setCompanionTaskFragment(@NonNull IBinder container,
- @Nullable IBinder companion) {
- final HierarchyOp hierarchyOp =
- new HierarchyOp.Builder(
- HierarchyOp.HIERARCHY_OP_TYPE_SET_COMPANION_TASK_FRAGMENT)
- .setContainer(container)
- .setReparentContainer(companion)
- .build();
- mHierarchyOps.add(hierarchyOp);
- return this;
+ public WindowContainerTransaction setCompanionTaskFragment(@NonNull IBinder fragmentToken,
+ @Nullable IBinder companionFragmentToken) {
+ final TaskFragmentOperation operation = new TaskFragmentOperation.Builder(
+ OP_TYPE_SET_COMPANION_TASK_FRAGMENT)
+ .setSecondaryFragmentToken(companionFragmentToken)
+ .build();
+ return addTaskFragmentOperation(fragmentToken, operation);
}
/**
- * Sets the {@link TaskFragmentOperation} to apply to the given TaskFragment.
+ * Adds a {@link TaskFragmentOperation} to apply to the given TaskFragment.
*
* @param fragmentToken client assigned unique token to create TaskFragment with specified in
* {@link TaskFragmentCreationParams#getFragmentToken()}.
@@ -760,13 +750,13 @@
* @hide
*/
@NonNull
- public WindowContainerTransaction setTaskFragmentOperation(@NonNull IBinder fragmentToken,
+ public WindowContainerTransaction addTaskFragmentOperation(@NonNull IBinder fragmentToken,
@NonNull TaskFragmentOperation taskFragmentOperation) {
Objects.requireNonNull(fragmentToken);
Objects.requireNonNull(taskFragmentOperation);
final HierarchyOp hierarchyOp =
new HierarchyOp.Builder(
- HierarchyOp.HIERARCHY_OP_TYPE_SET_TASK_FRAGMENT_OPERATION)
+ HierarchyOp.HIERARCHY_OP_TYPE_ADD_TASK_FRAGMENT_OPERATION)
.setContainer(fragmentToken)
.setTaskFragmentOperation(taskFragmentOperation)
.build();
@@ -1267,25 +1257,17 @@
public static final int HIERARCHY_OP_TYPE_SET_ADJACENT_ROOTS = 4;
public static final int HIERARCHY_OP_TYPE_LAUNCH_TASK = 5;
public static final int HIERARCHY_OP_TYPE_SET_LAUNCH_ADJACENT_FLAG_ROOT = 6;
- public static final int HIERARCHY_OP_TYPE_CREATE_TASK_FRAGMENT = 7;
- public static final int HIERARCHY_OP_TYPE_DELETE_TASK_FRAGMENT = 8;
- public static final int HIERARCHY_OP_TYPE_START_ACTIVITY_IN_TASK_FRAGMENT = 9;
- public static final int HIERARCHY_OP_TYPE_REPARENT_ACTIVITY_TO_TASK_FRAGMENT = 10;
- public static final int HIERARCHY_OP_TYPE_REPARENT_CHILDREN = 11;
- public static final int HIERARCHY_OP_TYPE_PENDING_INTENT = 12;
- public static final int HIERARCHY_OP_TYPE_SET_ADJACENT_TASK_FRAGMENTS = 13;
- public static final int HIERARCHY_OP_TYPE_START_SHORTCUT = 14;
- public static final int HIERARCHY_OP_TYPE_RESTORE_TRANSIENT_ORDER = 15;
- public static final int HIERARCHY_OP_TYPE_ADD_RECT_INSETS_PROVIDER = 16;
- public static final int HIERARCHY_OP_TYPE_REMOVE_INSETS_PROVIDER = 17;
- public static final int HIERARCHY_OP_TYPE_REQUEST_FOCUS_ON_TASK_FRAGMENT = 18;
- public static final int HIERARCHY_OP_TYPE_SET_ALWAYS_ON_TOP = 19;
- public static final int HIERARCHY_OP_TYPE_REMOVE_TASK = 20;
- public static final int HIERARCHY_OP_TYPE_FINISH_ACTIVITY = 21;
- public static final int HIERARCHY_OP_TYPE_SET_COMPANION_TASK_FRAGMENT = 22;
- public static final int HIERARCHY_OP_TYPE_CLEAR_ADJACENT_ROOTS = 23;
- public static final int HIERARCHY_OP_TYPE_SET_REPARENT_LEAF_TASK_IF_RELAUNCH = 24;
- public static final int HIERARCHY_OP_TYPE_SET_TASK_FRAGMENT_OPERATION = 25;
+ public static final int HIERARCHY_OP_TYPE_PENDING_INTENT = 7;
+ public static final int HIERARCHY_OP_TYPE_START_SHORTCUT = 8;
+ public static final int HIERARCHY_OP_TYPE_RESTORE_TRANSIENT_ORDER = 9;
+ public static final int HIERARCHY_OP_TYPE_ADD_RECT_INSETS_PROVIDER = 10;
+ public static final int HIERARCHY_OP_TYPE_REMOVE_INSETS_PROVIDER = 11;
+ public static final int HIERARCHY_OP_TYPE_SET_ALWAYS_ON_TOP = 12;
+ public static final int HIERARCHY_OP_TYPE_REMOVE_TASK = 13;
+ public static final int HIERARCHY_OP_TYPE_FINISH_ACTIVITY = 14;
+ public static final int HIERARCHY_OP_TYPE_CLEAR_ADJACENT_ROOTS = 15;
+ public static final int HIERARCHY_OP_TYPE_SET_REPARENT_LEAF_TASK_IF_RELAUNCH = 16;
+ public static final int HIERARCHY_OP_TYPE_ADD_TASK_FRAGMENT_OPERATION = 17;
// The following key(s) are for use with mLaunchOptions:
// When launching a task (eg. from recents), this is the taskId to be launched.
@@ -1326,11 +1308,7 @@
@Nullable
private Intent mActivityIntent;
- /** Used as options for {@link #createTaskFragment}. */
- @Nullable
- private TaskFragmentCreationParams mTaskFragmentCreationOptions;
-
- /** Used as options for {@link #setTaskFragmentOperation}. */
+ /** Used as options for {@link #addTaskFragmentOperation}. */
@Nullable
private TaskFragmentOperation mTaskFragmentOperation;
@@ -1452,7 +1430,6 @@
mActivityTypes = copy.mActivityTypes;
mLaunchOptions = copy.mLaunchOptions;
mActivityIntent = copy.mActivityIntent;
- mTaskFragmentCreationOptions = copy.mTaskFragmentCreationOptions;
mTaskFragmentOperation = copy.mTaskFragmentOperation;
mPendingIntent = copy.mPendingIntent;
mShortcutInfo = copy.mShortcutInfo;
@@ -1476,7 +1453,6 @@
mActivityTypes = in.createIntArray();
mLaunchOptions = in.readBundle();
mActivityIntent = in.readTypedObject(Intent.CREATOR);
- mTaskFragmentCreationOptions = in.readTypedObject(TaskFragmentCreationParams.CREATOR);
mTaskFragmentOperation = in.readTypedObject(TaskFragmentOperation.CREATOR);
mPendingIntent = in.readTypedObject(PendingIntent.CREATOR);
mShortcutInfo = in.readTypedObject(ShortcutInfo.CREATOR);
@@ -1516,16 +1492,6 @@
return mReparent;
}
- @NonNull
- public IBinder getCompanionContainer() {
- return mReparent;
- }
-
- @NonNull
- public IBinder getCallingActivity() {
- return mReparent;
- }
-
public boolean getToTop() {
return mToTop;
}
@@ -1561,11 +1527,6 @@
}
@Nullable
- public TaskFragmentCreationParams getTaskFragmentCreationOptions() {
- return mTaskFragmentCreationOptions;
- }
-
- @Nullable
public TaskFragmentOperation getTaskFragmentOperation() {
return mTaskFragmentOperation;
}
@@ -1605,22 +1566,6 @@
case HIERARCHY_OP_TYPE_SET_LAUNCH_ADJACENT_FLAG_ROOT:
return "{SetAdjacentFlagRoot: container=" + mContainer + " clearRoot=" + mToTop
+ "}";
- case HIERARCHY_OP_TYPE_CREATE_TASK_FRAGMENT:
- return "{CreateTaskFragment: options=" + mTaskFragmentCreationOptions + "}";
- case HIERARCHY_OP_TYPE_DELETE_TASK_FRAGMENT:
- return "{DeleteTaskFragment: taskFragment=" + mContainer + "}";
- case HIERARCHY_OP_TYPE_START_ACTIVITY_IN_TASK_FRAGMENT:
- return "{StartActivityInTaskFragment: fragmentToken=" + mContainer + " intent="
- + mActivityIntent + " options=" + mLaunchOptions + "}";
- case HIERARCHY_OP_TYPE_REPARENT_ACTIVITY_TO_TASK_FRAGMENT:
- return "{ReparentActivityToTaskFragment: fragmentToken=" + mReparent
- + " activity=" + mContainer + "}";
- case HIERARCHY_OP_TYPE_REPARENT_CHILDREN:
- return "{ReparentChildren: oldParent=" + mContainer + " newParent=" + mReparent
- + "}";
- case HIERARCHY_OP_TYPE_SET_ADJACENT_TASK_FRAGMENTS:
- return "{SetAdjacentTaskFragments: container=" + mContainer
- + " adjacentContainer=" + mReparent + "}";
case HIERARCHY_OP_TYPE_START_SHORTCUT:
return "{StartShortcut: options=" + mLaunchOptions + " info=" + mShortcutInfo
+ "}";
@@ -1631,8 +1576,6 @@
case HIERARCHY_OP_TYPE_REMOVE_INSETS_PROVIDER:
return "{removeLocalInsetsProvider: container=" + mContainer
+ " insetsType=" + Arrays.toString(mInsetsTypes) + "}";
- case HIERARCHY_OP_TYPE_REQUEST_FOCUS_ON_TASK_FRAGMENT:
- return "{requestFocusOnTaskFragment: container=" + mContainer + "}";
case HIERARCHY_OP_TYPE_SET_ALWAYS_ON_TOP:
return "{setAlwaysOnTop: container=" + mContainer
+ " alwaysOnTop=" + mAlwaysOnTop + "}";
@@ -1640,16 +1583,13 @@
return "{RemoveTask: task=" + mContainer + "}";
case HIERARCHY_OP_TYPE_FINISH_ACTIVITY:
return "{finishActivity: activity=" + mContainer + "}";
- case HIERARCHY_OP_TYPE_SET_COMPANION_TASK_FRAGMENT:
- return "{setCompanionTaskFragment: container = " + mContainer + " companion = "
- + mReparent + "}";
case HIERARCHY_OP_TYPE_CLEAR_ADJACENT_ROOTS:
return "{ClearAdjacentRoot: container=" + mContainer + "}";
case HIERARCHY_OP_TYPE_SET_REPARENT_LEAF_TASK_IF_RELAUNCH:
return "{setReparentLeafTaskIfRelaunch: container= " + mContainer
+ " reparentLeafTaskIfRelaunch= " + mReparentLeafTaskIfRelaunch + "}";
- case HIERARCHY_OP_TYPE_SET_TASK_FRAGMENT_OPERATION:
- return "{setTaskFragmentOperation: fragmentToken= " + mContainer
+ case HIERARCHY_OP_TYPE_ADD_TASK_FRAGMENT_OPERATION:
+ return "{addTaskFragmentOperation: fragmentToken= " + mContainer
+ " operation= " + mTaskFragmentOperation + "}";
default:
return "{mType=" + mType + " container=" + mContainer + " reparent=" + mReparent
@@ -1677,7 +1617,6 @@
dest.writeIntArray(mActivityTypes);
dest.writeBundle(mLaunchOptions);
dest.writeTypedObject(mActivityIntent, flags);
- dest.writeTypedObject(mTaskFragmentCreationOptions, flags);
dest.writeTypedObject(mTaskFragmentOperation, flags);
dest.writeTypedObject(mPendingIntent, flags);
dest.writeTypedObject(mShortcutInfo, flags);
@@ -1733,9 +1672,6 @@
private Intent mActivityIntent;
@Nullable
- private TaskFragmentCreationParams mTaskFragmentCreationOptions;
-
- @Nullable
private TaskFragmentOperation mTaskFragmentOperation;
@Nullable
@@ -1812,12 +1748,6 @@
return this;
}
- Builder setTaskFragmentCreationOptions(
- @Nullable TaskFragmentCreationParams taskFragmentCreationOptions) {
- mTaskFragmentCreationOptions = taskFragmentCreationOptions;
- return this;
- }
-
Builder setTaskFragmentOperation(
@Nullable TaskFragmentOperation taskFragmentOperation) {
mTaskFragmentOperation = taskFragmentOperation;
@@ -1852,7 +1782,6 @@
hierarchyOp.mActivityIntent = mActivityIntent;
hierarchyOp.mPendingIntent = mPendingIntent;
hierarchyOp.mAlwaysOnTop = mAlwaysOnTop;
- hierarchyOp.mTaskFragmentCreationOptions = mTaskFragmentCreationOptions;
hierarchyOp.mTaskFragmentOperation = mTaskFragmentOperation;
hierarchyOp.mShortcutInfo = mShortcutInfo;
hierarchyOp.mReparentLeafTaskIfRelaunch = mReparentLeafTaskIfRelaunch;
diff --git a/core/java/com/android/internal/accessibility/AccessibilityShortcutController.java b/core/java/com/android/internal/accessibility/AccessibilityShortcutController.java
index 4f97d21..bf55255 100644
--- a/core/java/com/android/internal/accessibility/AccessibilityShortcutController.java
+++ b/core/java/com/android/internal/accessibility/AccessibilityShortcutController.java
@@ -21,6 +21,7 @@
import static android.view.accessibility.AccessibilityManager.ACCESSIBILITY_SHORTCUT_KEY;
import static com.android.internal.accessibility.dialog.AccessibilityTargetHelper.getTargets;
+import static com.android.internal.os.RoSystemProperties.SUPPORT_ONE_HANDED_MODE;
import static com.android.internal.util.ArrayUtils.convertToLongArray;
import android.accessibilityservice.AccessibilityServiceInfo;
@@ -151,11 +152,13 @@
Settings.Secure.ACCESSIBILITY_DISPLAY_DALTONIZER_ENABLED,
"1" /* Value to enable */, "0" /* Value to disable */,
R.string.color_correction_feature_name));
- featuresMap.put(ONE_HANDED_COMPONENT_NAME,
- new ToggleableFrameworkFeatureInfo(
- Settings.Secure.ONE_HANDED_MODE_ACTIVATED,
- "1" /* Value to enable */, "0" /* Value to disable */,
- R.string.one_handed_mode_feature_name));
+ if (SUPPORT_ONE_HANDED_MODE) {
+ featuresMap.put(ONE_HANDED_COMPONENT_NAME,
+ new ToggleableFrameworkFeatureInfo(
+ Settings.Secure.ONE_HANDED_MODE_ACTIVATED,
+ "1" /* Value to enable */, "0" /* Value to disable */,
+ R.string.one_handed_mode_feature_name));
+ }
featuresMap.put(REDUCE_BRIGHT_COLORS_COMPONENT_NAME,
new ToggleableFrameworkFeatureInfo(
Settings.Secure.REDUCE_BRIGHT_COLORS_ACTIVATED,
diff --git a/core/java/com/android/internal/accessibility/dialog/AccessibilityTargetHelper.java b/core/java/com/android/internal/accessibility/dialog/AccessibilityTargetHelper.java
index b5455f2..a47a97c 100644
--- a/core/java/com/android/internal/accessibility/dialog/AccessibilityTargetHelper.java
+++ b/core/java/com/android/internal/accessibility/dialog/AccessibilityTargetHelper.java
@@ -26,6 +26,7 @@
import static com.android.internal.accessibility.AccessibilityShortcutController.REDUCE_BRIGHT_COLORS_COMPONENT_NAME;
import static com.android.internal.accessibility.util.AccessibilityUtils.getAccessibilityServiceFragmentType;
import static com.android.internal.accessibility.util.ShortcutUtils.isShortcutContained;
+import static com.android.internal.os.RoSystemProperties.SUPPORT_ONE_HANDED_MODE;
import android.accessibilityservice.AccessibilityServiceInfo;
import android.accessibilityservice.AccessibilityShortcutInfo;
@@ -210,6 +211,7 @@
context.getString(R.string.accessibility_magnification_chooser_text),
context.getDrawable(R.drawable.ic_accessibility_magnification),
Settings.Secure.ACCESSIBILITY_DISPLAY_MAGNIFICATION_NAVBAR_ENABLED);
+ targets.add(magnification);
final ToggleAllowListingFeatureTarget daltonizer =
new ToggleAllowListingFeatureTarget(context,
@@ -220,6 +222,7 @@
context.getString(R.string.color_correction_feature_name),
context.getDrawable(R.drawable.ic_accessibility_color_correction),
Settings.Secure.ACCESSIBILITY_DISPLAY_DALTONIZER_ENABLED);
+ targets.add(daltonizer);
final ToggleAllowListingFeatureTarget colorInversion =
new ToggleAllowListingFeatureTarget(context,
@@ -230,16 +233,20 @@
context.getString(R.string.color_inversion_feature_name),
context.getDrawable(R.drawable.ic_accessibility_color_inversion),
Settings.Secure.ACCESSIBILITY_DISPLAY_INVERSION_ENABLED);
+ targets.add(colorInversion);
- final ToggleAllowListingFeatureTarget oneHandedMode =
- new ToggleAllowListingFeatureTarget(context,
- shortcutType,
- isShortcutContained(context, shortcutType,
- ONE_HANDED_COMPONENT_NAME.flattenToString()),
- ONE_HANDED_COMPONENT_NAME.flattenToString(),
- context.getString(R.string.one_handed_mode_feature_name),
- context.getDrawable(R.drawable.ic_accessibility_one_handed),
- Settings.Secure.ONE_HANDED_MODE_ACTIVATED);
+ if (SUPPORT_ONE_HANDED_MODE) {
+ final ToggleAllowListingFeatureTarget oneHandedMode =
+ new ToggleAllowListingFeatureTarget(context,
+ shortcutType,
+ isShortcutContained(context, shortcutType,
+ ONE_HANDED_COMPONENT_NAME.flattenToString()),
+ ONE_HANDED_COMPONENT_NAME.flattenToString(),
+ context.getString(R.string.one_handed_mode_feature_name),
+ context.getDrawable(R.drawable.ic_accessibility_one_handed),
+ Settings.Secure.ONE_HANDED_MODE_ACTIVATED);
+ targets.add(oneHandedMode);
+ }
final ToggleAllowListingFeatureTarget reduceBrightColors =
new ToggleAllowListingFeatureTarget(context,
@@ -250,6 +257,7 @@
context.getString(R.string.reduce_bright_colors_feature_name),
context.getDrawable(R.drawable.ic_accessibility_reduce_bright_colors),
Settings.Secure.REDUCE_BRIGHT_COLORS_ACTIVATED);
+ targets.add(reduceBrightColors);
final InvisibleToggleAllowListingFeatureTarget hearingAids =
new InvisibleToggleAllowListingFeatureTarget(context,
@@ -260,11 +268,6 @@
context.getString(R.string.hearing_aids_feature_name),
context.getDrawable(R.drawable.ic_accessibility_hearing_aid),
/* key= */ null);
- targets.add(magnification);
- targets.add(daltonizer);
- targets.add(colorInversion);
- targets.add(oneHandedMode);
- targets.add(reduceBrightColors);
targets.add(hearingAids);
return targets;
diff --git a/core/java/com/android/internal/app/ChooserActivity.java b/core/java/com/android/internal/app/ChooserActivity.java
index 02cbd41..9f283d4 100644
--- a/core/java/com/android/internal/app/ChooserActivity.java
+++ b/core/java/com/android/internal/app/ChooserActivity.java
@@ -2953,12 +2953,24 @@
private boolean shouldShowStickyContentPreviewNoOrientationCheck() {
return shouldShowTabs()
- && mMultiProfilePagerAdapter.getListAdapterForUserHandle(
- UserHandle.of(UserHandle.myUserId())).getCount() > 0
+ && (mMultiProfilePagerAdapter.getListAdapterForUserHandle(
+ UserHandle.of(UserHandle.myUserId())).getCount() > 0
+ || shouldShowContentPreviewWhenEmpty())
&& shouldShowContentPreview();
}
/**
+ * This method could be used to override the default behavior when we hide the preview area
+ * when the current tab doesn't have any items.
+ *
+ * @return true if we want to show the content preview area even if the tab for the current
+ * user is empty
+ */
+ protected boolean shouldShowContentPreviewWhenEmpty() {
+ return false;
+ }
+
+ /**
* @return true if we want to show the content preview area
*/
protected boolean shouldShowContentPreview() {
diff --git a/core/java/com/android/internal/app/ResolverActivity.java b/core/java/com/android/internal/app/ResolverActivity.java
index 0706ee5..f098e2c 100644
--- a/core/java/com/android/internal/app/ResolverActivity.java
+++ b/core/java/com/android/internal/app/ResolverActivity.java
@@ -209,7 +209,7 @@
* <p>Can only be used if there is a work profile.
* <p>Possible values can be either {@link #PROFILE_PERSONAL} or {@link #PROFILE_WORK}.
*/
- static final String EXTRA_SELECTED_PROFILE =
+ protected static final String EXTRA_SELECTED_PROFILE =
"com.android.internal.app.ResolverActivity.EXTRA_SELECTED_PROFILE";
/**
@@ -224,8 +224,8 @@
static final String EXTRA_CALLING_USER =
"com.android.internal.app.ResolverActivity.EXTRA_CALLING_USER";
- static final int PROFILE_PERSONAL = AbstractMultiProfilePagerAdapter.PROFILE_PERSONAL;
- static final int PROFILE_WORK = AbstractMultiProfilePagerAdapter.PROFILE_WORK;
+ protected static final int PROFILE_PERSONAL = AbstractMultiProfilePagerAdapter.PROFILE_PERSONAL;
+ protected static final int PROFILE_WORK = AbstractMultiProfilePagerAdapter.PROFILE_WORK;
private BroadcastReceiver mWorkProfileStateReceiver;
private UserHandle mHeaderCreatorUser;
diff --git a/core/java/com/android/internal/app/UnlaunchableAppActivity.java b/core/java/com/android/internal/app/UnlaunchableAppActivity.java
index 0776572..e47c335 100644
--- a/core/java/com/android/internal/app/UnlaunchableAppActivity.java
+++ b/core/java/com/android/internal/app/UnlaunchableAppActivity.java
@@ -28,11 +28,13 @@
import android.content.DialogInterface;
import android.content.Intent;
import android.content.IntentSender;
+import android.content.pm.ResolveInfo;
import android.os.Bundle;
import android.os.Handler;
import android.os.Looper;
import android.os.UserHandle;
import android.os.UserManager;
+import android.telecom.TelecomManager;
import android.util.Log;
import android.view.Window;
@@ -52,6 +54,7 @@
private int mUserId;
private int mReason;
private IntentSender mTarget;
+ private TelecomManager mTelecomManager;
@Override
protected void onCreate(Bundle savedInstanceState) {
@@ -60,9 +63,11 @@
// TODO: Use AlertActivity so we don't need to hide title bar and create a dialog
requestWindowFeature(Window.FEATURE_NO_TITLE);
Intent intent = getIntent();
+ mTelecomManager = getSystemService(TelecomManager.class);
mReason = intent.getIntExtra(EXTRA_UNLAUNCHABLE_REASON, -1);
mUserId = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, UserHandle.USER_NULL);
- mTarget = intent.getParcelableExtra(Intent.EXTRA_INTENT, android.content.IntentSender.class);
+ mTarget = intent.getParcelableExtra(Intent.EXTRA_INTENT,
+ android.content.IntentSender.class);
if (mUserId == UserHandle.USER_NULL) {
Log.wtf(TAG, "Invalid user id: " + mUserId + ". Stopping.");
@@ -70,29 +75,40 @@
return;
}
- String dialogTitle;
- String dialogMessage = null;
- if (mReason == UNLAUNCHABLE_REASON_QUIET_MODE) {
- dialogTitle = getDialogTitle();
- dialogMessage = getDialogMessage();
- } else {
+ if (mReason != UNLAUNCHABLE_REASON_QUIET_MODE) {
Log.wtf(TAG, "Invalid unlaunchable type: " + mReason);
finish();
return;
}
- AlertDialog.Builder builder = new AlertDialog.Builder(this)
- .setTitle(dialogTitle)
- .setMessage(dialogMessage)
- .setOnDismissListener(this);
- if (mReason == UNLAUNCHABLE_REASON_QUIET_MODE) {
- builder.setPositiveButton(R.string.work_mode_turn_on, this)
- .setNegativeButton(R.string.cancel, null);
+ String targetPackageName = intent.getStringExtra(Intent.EXTRA_PACKAGE_NAME);
+ boolean showEmergencyCallButton =
+ (targetPackageName != null && targetPackageName.equals(
+ mTelecomManager.getDefaultDialerPackage(UserHandle.of(mUserId))));
+
+ final AlertDialog.Builder builder;
+ final String dialogMessage;
+ if (showEmergencyCallButton) {
+ builder = new AlertDialog.Builder(this, R.style.AlertDialogWithEmergencyButton);
+ dialogMessage = getDialogMessage(R.string.work_mode_dialer_off_message);
+ builder.setNeutralButton(R.string.work_mode_emergency_call_button, this);
} else {
- builder.setPositiveButton(R.string.ok, null);
+ builder = new AlertDialog.Builder(this);
+ dialogMessage = getDialogMessage(R.string.work_mode_off_message);
}
+ builder.setTitle(getDialogTitle())
+ .setMessage(dialogMessage)
+ .setOnDismissListener(this)
+ .setPositiveButton(R.string.work_mode_turn_on, this)
+ .setNegativeButton(R.string.cancel, null);
+
final AlertDialog dialog = builder.create();
dialog.create();
+ if (showEmergencyCallButton) {
+ dialog.getWindow().findViewById(R.id.parentPanel).setPadding(0, 0, 0, 30);
+ dialog.getWindow().findViewById(R.id.button3).setOutlineProvider(null);
+ }
+
// Prevents screen overlay attack.
getWindow().setHideOverlayWindows(true);
dialog.getButton(DialogInterface.BUTTON_POSITIVE).setFilterTouchesWhenObscured(true);
@@ -104,10 +120,10 @@
UNLAUNCHABLE_APP_WORK_PAUSED_TITLE, () -> getString(R.string.work_mode_off_title));
}
- private String getDialogMessage() {
+ private String getDialogMessage(int dialogMessageString) {
return getSystemService(DevicePolicyManager.class).getResources().getString(
UNLAUNCHABLE_APP_WORK_PAUSED_MESSAGE,
- () -> getString(R.string.work_mode_off_message));
+ () -> getString(dialogMessageString));
}
@Override
@@ -117,14 +133,27 @@
@Override
public void onClick(DialogInterface dialog, int which) {
- if (mReason == UNLAUNCHABLE_REASON_QUIET_MODE && which == DialogInterface.BUTTON_POSITIVE) {
+ if (mReason != UNLAUNCHABLE_REASON_QUIET_MODE) {
+ return;
+ }
+ if (which == DialogInterface.BUTTON_POSITIVE) {
UserManager userManager = UserManager.get(this);
new Handler(Looper.getMainLooper()).post(
() -> userManager.requestQuietModeEnabled(
/* enableQuietMode= */ false, UserHandle.of(mUserId), mTarget));
+ } else if (which == DialogInterface.BUTTON_NEUTRAL) {
+ launchEmergencyDialer();
}
}
+ private void launchEmergencyDialer() {
+ startActivity(mTelecomManager.createLaunchEmergencyDialerIntent(
+ null /* number*/)
+ .setFlags(Intent.FLAG_ACTIVITY_NEW_TASK
+ | Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS
+ | Intent.FLAG_ACTIVITY_CLEAR_TOP));
+ }
+
private static final Intent createBaseIntent() {
Intent intent = new Intent();
intent.setComponent(new ComponentName("android", UnlaunchableAppActivity.class.getName()));
@@ -139,9 +168,13 @@
return intent;
}
- public static Intent createInQuietModeDialogIntent(int userId, IntentSender target) {
+ public static Intent createInQuietModeDialogIntent(int userId, IntentSender target,
+ ResolveInfo resolveInfo) {
Intent intent = createInQuietModeDialogIntent(userId);
intent.putExtra(Intent.EXTRA_INTENT, target);
+ if (resolveInfo != null) {
+ intent.putExtra(Intent.EXTRA_PACKAGE_NAME, resolveInfo.getComponentInfo().packageName);
+ }
return intent;
}
}
diff --git a/core/java/com/android/internal/inputmethod/EditableInputConnection.java b/core/java/com/android/internal/inputmethod/EditableInputConnection.java
index 52e7471..8690e8d 100644
--- a/core/java/com/android/internal/inputmethod/EditableInputConnection.java
+++ b/core/java/com/android/internal/inputmethod/EditableInputConnection.java
@@ -271,9 +271,9 @@
@Override
public void requestTextBoundsInfo(
- @NonNull RectF rectF, @Nullable @CallbackExecutor Executor executor,
+ @NonNull RectF bounds, @Nullable @CallbackExecutor Executor executor,
@NonNull Consumer<TextBoundsInfoResult> consumer) {
- final TextBoundsInfo textBoundsInfo = mTextView.getTextBoundsInfo(rectF);
+ final TextBoundsInfo textBoundsInfo = mTextView.getTextBoundsInfo(bounds);
final int resultCode;
if (textBoundsInfo != null) {
resultCode = TextBoundsInfoResult.CODE_SUCCESS;
diff --git a/core/java/com/android/internal/inputmethod/IRemoteInputConnection.aidl b/core/java/com/android/internal/inputmethod/IRemoteInputConnection.aidl
index 65016c2..b375936 100644
--- a/core/java/com/android/internal/inputmethod/IRemoteInputConnection.aidl
+++ b/core/java/com/android/internal/inputmethod/IRemoteInputConnection.aidl
@@ -111,7 +111,7 @@
int cursorUpdateMode, int cursorUpdateFilter, int imeDisplayId,
in AndroidFuture future /* T=Boolean */);
- void requestTextBoundsInfo(in InputConnectionCommandHeader header, in RectF rect,
+ void requestTextBoundsInfo(in InputConnectionCommandHeader header, in RectF bounds,
in ResultReceiver resultReceiver /* T=TextBoundsInfoResult */);
void commitContent(in InputConnectionCommandHeader header, in InputContentInfo inputContentInfo,
diff --git a/core/java/com/android/internal/os/BatteryStatsHistory.java b/core/java/com/android/internal/os/BatteryStatsHistory.java
index 3d8982b..04b7239cb 100644
--- a/core/java/com/android/internal/os/BatteryStatsHistory.java
+++ b/core/java/com/android/internal/os/BatteryStatsHistory.java
@@ -187,8 +187,6 @@
private int mNextHistoryTagIdx = 0;
private int mNumHistoryTagChars = 0;
private int mHistoryBufferLastPos = -1;
- private int mActiveHistoryStates = 0xffffffff;
- private int mActiveHistoryStates2 = 0xffffffff;
private long mLastHistoryElapsedRealtimeMs = 0;
private long mTrackRunningHistoryElapsedRealtimeMs = 0;
private long mTrackRunningHistoryUptimeMs = 0;
@@ -362,8 +360,6 @@
mNextHistoryTagIdx = 0;
mNumHistoryTagChars = 0;
mHistoryBufferLastPos = -1;
- mActiveHistoryStates = 0xffffffff;
- mActiveHistoryStates2 = 0xffffffff;
if (mStepDetailsCalculator != null) {
mStepDetailsCalculator.clear();
}
@@ -1098,8 +1094,9 @@
*/
public void recordScreenBrightnessEvent(long elapsedRealtimeMs, long uptimeMs,
int brightnessBin) {
- mHistoryCur.states = (mHistoryCur.states & ~HistoryItem.STATE_BRIGHTNESS_MASK)
- | (brightnessBin << HistoryItem.STATE_BRIGHTNESS_SHIFT);
+ mHistoryCur.states = setBitField(mHistoryCur.states, brightnessBin,
+ HistoryItem.STATE_BRIGHTNESS_SHIFT,
+ HistoryItem.STATE_BRIGHTNESS_MASK);
writeHistoryItem(elapsedRealtimeMs, uptimeMs);
}
@@ -1108,8 +1105,9 @@
*/
public void recordGpsSignalQualityEvent(long elapsedRealtimeMs, long uptimeMs,
int signalLevel) {
- mHistoryCur.states2 = (mHistoryCur.states2 & ~HistoryItem.STATE2_GPS_SIGNAL_QUALITY_MASK)
- | (signalLevel << HistoryItem.STATE2_GPS_SIGNAL_QUALITY_SHIFT);
+ mHistoryCur.states2 = setBitField(mHistoryCur.states2, signalLevel,
+ HistoryItem.STATE2_GPS_SIGNAL_QUALITY_SHIFT,
+ HistoryItem.STATE2_GPS_SIGNAL_QUALITY_MASK);
writeHistoryItem(elapsedRealtimeMs, uptimeMs);
}
@@ -1117,8 +1115,9 @@
* Records a device idle mode change event.
*/
public void recordDeviceIdleEvent(long elapsedRealtimeMs, long uptimeMs, int mode) {
- mHistoryCur.states2 = (mHistoryCur.states2 & ~HistoryItem.STATE2_DEVICE_IDLE_MASK)
- | (mode << HistoryItem.STATE2_DEVICE_IDLE_SHIFT);
+ mHistoryCur.states2 = setBitField(mHistoryCur.states2, mode,
+ HistoryItem.STATE2_DEVICE_IDLE_SHIFT,
+ HistoryItem.STATE2_DEVICE_IDLE_MASK);
writeHistoryItem(elapsedRealtimeMs, uptimeMs);
}
@@ -1130,13 +1129,15 @@
mHistoryCur.states = (mHistoryCur.states | addStateFlag) & ~removeStateFlag;
if (state != -1) {
mHistoryCur.states =
- (mHistoryCur.states & ~HistoryItem.STATE_PHONE_STATE_MASK)
- | (state << HistoryItem.STATE_PHONE_STATE_SHIFT);
+ setBitField(mHistoryCur.states, state,
+ HistoryItem.STATE_PHONE_STATE_SHIFT,
+ HistoryItem.STATE_PHONE_STATE_MASK);
}
if (signalStrength != -1) {
mHistoryCur.states =
- (mHistoryCur.states & ~HistoryItem.STATE_PHONE_SIGNAL_STRENGTH_MASK)
- | (signalStrength << HistoryItem.STATE_PHONE_SIGNAL_STRENGTH_SHIFT);
+ setBitField(mHistoryCur.states, signalStrength,
+ HistoryItem.STATE_PHONE_SIGNAL_STRENGTH_SHIFT,
+ HistoryItem.STATE_PHONE_SIGNAL_STRENGTH_MASK);
}
writeHistoryItem(elapsedRealtimeMs, uptimeMs);
}
@@ -1146,8 +1147,9 @@
*/
public void recordDataConnectionTypeChangeEvent(long elapsedRealtimeMs, long uptimeMs,
int dataConnectionType) {
- mHistoryCur.states = (mHistoryCur.states & ~HistoryItem.STATE_DATA_CONNECTION_MASK)
- | (dataConnectionType << HistoryItem.STATE_DATA_CONNECTION_SHIFT);
+ mHistoryCur.states = setBitField(mHistoryCur.states, dataConnectionType,
+ HistoryItem.STATE_DATA_CONNECTION_SHIFT,
+ HistoryItem.STATE_DATA_CONNECTION_MASK);
writeHistoryItem(elapsedRealtimeMs, uptimeMs);
}
@@ -1157,8 +1159,9 @@
public void recordWifiSupplicantStateChangeEvent(long elapsedRealtimeMs, long uptimeMs,
int supplState) {
mHistoryCur.states2 =
- (mHistoryCur.states2 & ~HistoryItem.STATE2_WIFI_SUPPL_STATE_MASK)
- | (supplState << HistoryItem.STATE2_WIFI_SUPPL_STATE_SHIFT);
+ setBitField(mHistoryCur.states2, supplState,
+ HistoryItem.STATE2_WIFI_SUPPL_STATE_SHIFT,
+ HistoryItem.STATE2_WIFI_SUPPL_STATE_MASK);
writeHistoryItem(elapsedRealtimeMs, uptimeMs);
}
@@ -1168,8 +1171,9 @@
public void recordWifiSignalStrengthChangeEvent(long elapsedRealtimeMs, long uptimeMs,
int strengthBin) {
mHistoryCur.states2 =
- (mHistoryCur.states2 & ~HistoryItem.STATE2_WIFI_SIGNAL_STRENGTH_MASK)
- | (strengthBin << HistoryItem.STATE2_WIFI_SIGNAL_STRENGTH_SHIFT);
+ setBitField(mHistoryCur.states2, strengthBin,
+ HistoryItem.STATE2_WIFI_SIGNAL_STRENGTH_SHIFT,
+ HistoryItem.STATE2_WIFI_SIGNAL_STRENGTH_MASK);
writeHistoryItem(elapsedRealtimeMs, uptimeMs);
}
@@ -1227,6 +1231,16 @@
}
}
+ private int setBitField(int bits, int value, int shift, int mask) {
+ int shiftedValue = value << shift;
+ if ((shiftedValue & ~mask) != 0) {
+ Slog.wtfStack(TAG, "Value " + Integer.toHexString(value)
+ + " does not fit in the bit field: " + Integer.toHexString(mask));
+ shiftedValue &= mask;
+ }
+ return (bits & ~mask) | shiftedValue;
+ }
+
/**
* Writes the current history item to history.
*/
@@ -1260,8 +1274,8 @@
}
final long timeDiffMs = (mHistoryBaseTimeMs + elapsedRealtimeMs) - mHistoryLastWritten.time;
- final int diffStates = mHistoryLastWritten.states ^ (cur.states & mActiveHistoryStates);
- final int diffStates2 = mHistoryLastWritten.states2 ^ (cur.states2 & mActiveHistoryStates2);
+ final int diffStates = mHistoryLastWritten.states ^ cur.states;
+ final int diffStates2 = mHistoryLastWritten.states2 ^ cur.states2;
final int lastDiffStates = mHistoryLastWritten.states ^ mHistoryLastLastWritten.states;
final int lastDiffStates2 = mHistoryLastWritten.states2 ^ mHistoryLastLastWritten.states2;
if (DEBUG) {
@@ -1274,9 +1288,9 @@
recordTraceEvents(cur.eventCode, cur.eventTag);
recordTraceCounters(mHistoryLastWritten.states,
- cur.states & mActiveHistoryStates, BatteryStats.HISTORY_STATE_DESCRIPTIONS);
+ cur.states, BatteryStats.HISTORY_STATE_DESCRIPTIONS);
recordTraceCounters(mHistoryLastWritten.states2,
- cur.states2 & mActiveHistoryStates2, BatteryStats.HISTORY_STATE2_DESCRIPTIONS);
+ cur.states2, BatteryStats.HISTORY_STATE2_DESCRIPTIONS);
if (mHistoryBufferLastPos >= 0 && mHistoryLastWritten.cmd == HistoryItem.CMD_UPDATE
&& timeDiffMs < 1000 && (diffStates & lastDiffStates) == 0
@@ -1387,8 +1401,6 @@
final boolean hasTags = mHistoryLastWritten.tagsFirstOccurrence || cur.tagsFirstOccurrence;
mHistoryLastWritten.setTo(mHistoryBaseTimeMs + elapsedRealtimeMs, cmd, cur);
mHistoryLastWritten.tagsFirstOccurrence = hasTags;
- mHistoryLastWritten.states &= mActiveHistoryStates;
- mHistoryLastWritten.states2 &= mActiveHistoryStates2;
writeHistoryDelta(mHistoryBuffer, mHistoryLastWritten, mHistoryLastLastWritten);
mLastHistoryElapsedRealtimeMs = elapsedRealtimeMs;
cur.wakelockTag = null;
@@ -1627,7 +1639,7 @@
}
if (cur.eventCode != HistoryItem.EVENT_NONE) {
final int index = writeHistoryTag(cur.eventTag);
- final int codeAndIndex = (cur.eventCode & 0xffff) | (index << 16);
+ final int codeAndIndex = setBitField(cur.eventCode & 0xffff, index, 16, 0xFFFF0000);
dest.writeInt(codeAndIndex);
if ((index & BatteryStatsHistory.TAG_FIRST_OCCURRENCE_FLAG) != 0) {
cur.eventTag.writeToParcel(dest, 0);
@@ -1689,9 +1701,11 @@
}
private int buildBatteryLevelInt(HistoryItem h) {
- return ((((int) h.batteryLevel) << 25) & 0xfe000000)
- | ((((int) h.batteryTemperature) << 15) & 0x01ff8000)
- | ((((int) h.batteryVoltage) << 1) & 0x00007ffe);
+ int bits = 0;
+ bits = setBitField(bits, h.batteryLevel, 25, 0xfe000000 /* 7F << 25 */);
+ bits = setBitField(bits, h.batteryTemperature, 15, 0x01ff8000 /* 3FF << 15 */);
+ bits = setBitField(bits, h.batteryVoltage, 1, 0x00007ffe /* 3FFF << 1 */);
+ return bits;
}
private int buildStateInt(HistoryItem h) {
diff --git a/core/java/com/android/internal/os/RoSystemProperties.java b/core/java/com/android/internal/os/RoSystemProperties.java
index 6870d09..af205d2 100644
--- a/core/java/com/android/internal/os/RoSystemProperties.java
+++ b/core/java/com/android/internal/os/RoSystemProperties.java
@@ -31,6 +31,8 @@
SystemProperties.getInt("ro.factorytest", 0);
public static final String CONTROL_PRIVAPP_PERMISSIONS =
SystemProperties.get("ro.control_privapp_permissions");
+ public static final boolean SUPPORT_ONE_HANDED_MODE =
+ SystemProperties.getBoolean("ro.support_one_handed_mode", /* def= */ false);
// ------ ro.hdmi.* -------- //
/**
diff --git a/core/java/com/android/internal/policy/DecorView.java b/core/java/com/android/internal/policy/DecorView.java
index b5b27f52..47e6b6e 100644
--- a/core/java/com/android/internal/policy/DecorView.java
+++ b/core/java/com/android/internal/policy/DecorView.java
@@ -57,14 +57,12 @@
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Insets;
-import android.graphics.LinearGradient;
import android.graphics.Outline;
import android.graphics.Paint;
import android.graphics.PixelFormat;
import android.graphics.RecordingCanvas;
import android.graphics.Rect;
import android.graphics.Region;
-import android.graphics.Shader;
import android.graphics.drawable.ColorDrawable;
import android.graphics.drawable.Drawable;
import android.graphics.drawable.InsetDrawable;
@@ -274,9 +272,6 @@
private boolean mApplyFloatingVerticalInsets = false;
private boolean mApplyFloatingHorizontalInsets = false;
- private final int mResizeShadowSize;
- private final Paint mVerticalResizeShadowPaint = new Paint();
- private final Paint mHorizontalResizeShadowPaint = new Paint();
private final Paint mLegacyNavigationBarBackgroundPaint = new Paint();
private Insets mBackgroundInsets = Insets.NONE;
private Insets mLastBackgroundInsets = Insets.NONE;
@@ -317,10 +312,6 @@
updateLogTag(params);
- mResizeShadowSize = context.getResources().getDimensionPixelSize(
- R.dimen.resize_shadow_size);
- initResizingPaints();
-
mLegacyNavigationBarBackgroundPaint.setColor(Color.BLACK);
}
@@ -2447,38 +2438,9 @@
@Override
public void onPostDraw(RecordingCanvas canvas) {
- drawResizingShadowIfNeeded(canvas);
drawLegacyNavigationBarBackground(canvas);
}
- private void initResizingPaints() {
- final int startColor = mContext.getResources().getColor(
- R.color.resize_shadow_start_color, null);
- final int endColor = mContext.getResources().getColor(
- R.color.resize_shadow_end_color, null);
- final int middleColor = (startColor + endColor) / 2;
- mHorizontalResizeShadowPaint.setShader(new LinearGradient(
- 0, 0, 0, mResizeShadowSize, new int[] { startColor, middleColor, endColor },
- new float[] { 0f, 0.3f, 1f }, Shader.TileMode.CLAMP));
- mVerticalResizeShadowPaint.setShader(new LinearGradient(
- 0, 0, mResizeShadowSize, 0, new int[] { startColor, middleColor, endColor },
- new float[] { 0f, 0.3f, 1f }, Shader.TileMode.CLAMP));
- }
-
- private void drawResizingShadowIfNeeded(RecordingCanvas canvas) {
- if (mWindow.mIsFloating || mWindow.isTranslucent() || mWindow.isShowingWallpaper()) {
- return;
- }
- canvas.save();
- canvas.translate(0, getHeight() - mFrameOffsets.bottom);
- canvas.drawRect(0, 0, getWidth(), mResizeShadowSize, mHorizontalResizeShadowPaint);
- canvas.restore();
- canvas.save();
- canvas.translate(getWidth() - mFrameOffsets.right, 0);
- canvas.drawRect(0, 0, mResizeShadowSize, getHeight(), mVerticalResizeShadowPaint);
- canvas.restore();
- }
-
private void drawLegacyNavigationBarBackground(RecordingCanvas canvas) {
if (!mDrawLegacyNavigationBarBackground || mDrawLegacyNavigationBarBackgroundHandled) {
return;
diff --git a/core/java/com/android/internal/statusbar/IStatusBar.aidl b/core/java/com/android/internal/statusbar/IStatusBar.aidl
index db288c0..8fb345b 100644
--- a/core/java/com/android/internal/statusbar/IStatusBar.aidl
+++ b/core/java/com/android/internal/statusbar/IStatusBar.aidl
@@ -53,7 +53,7 @@
boolean showImeSwitcher);
void setWindowState(int display, int window, int state);
- void showRecentApps(boolean triggeredFromAltTab);
+ void showRecentApps(boolean triggeredFromAltTab, boolean forward);
void hideRecentApps(boolean triggeredFromAltTab, boolean triggeredFromHomeKey);
void toggleRecentApps();
void toggleSplitScreen();
diff --git a/core/java/com/android/internal/view/inline/InlineTooltipUi.java b/core/java/com/android/internal/view/inline/InlineTooltipUi.java
index 836786d..7e12574 100644
--- a/core/java/com/android/internal/view/inline/InlineTooltipUi.java
+++ b/core/java/com/android/internal/view/inline/InlineTooltipUi.java
@@ -15,7 +15,7 @@
*/
package com.android.internal.view.inline;
-import static android.view.autofill.AutofillManager.DEVICE_CONFIG_AUTOFILL_TOOLTIP_SHOW_UP_DELAY;
+import static android.view.autofill.AutofillFeatureFlags.DEVICE_CONFIG_AUTOFILL_TOOLTIP_SHOW_UP_DELAY;
import static android.view.autofill.Helper.sVerbose;
import android.annotation.NonNull;
diff --git a/core/jni/Android.bp b/core/jni/Android.bp
index a43f0b3..21f1d6d 100644
--- a/core/jni/Android.bp
+++ b/core/jni/Android.bp
@@ -129,6 +129,7 @@
"android_view_KeyCharacterMap.cpp",
"android_view_KeyEvent.cpp",
"android_view_MotionEvent.cpp",
+ "android_view_MotionPredictor.cpp",
"android_view_PointerIcon.cpp",
"android_view_Surface.cpp",
"android_view_SurfaceControl.cpp",
@@ -283,6 +284,7 @@
"libhwui",
"libmediandk",
"libpermission",
+ "libPlatformProperties",
"libsensor",
"libinput",
"libcamera_client",
diff --git a/core/jni/AndroidRuntime.cpp b/core/jni/AndroidRuntime.cpp
index 6ceffde..578cf24 100644
--- a/core/jni/AndroidRuntime.cpp
+++ b/core/jni/AndroidRuntime.cpp
@@ -187,6 +187,7 @@
extern int register_android_view_KeyCharacterMap(JNIEnv *env);
extern int register_android_view_KeyEvent(JNIEnv* env);
extern int register_android_view_MotionEvent(JNIEnv* env);
+extern int register_android_view_MotionPredictor(JNIEnv* env);
extern int register_android_view_PointerIcon(JNIEnv* env);
extern int register_android_view_VelocityTracker(JNIEnv* env);
extern int register_android_view_VerifiedKeyEvent(JNIEnv* env);
@@ -1643,6 +1644,7 @@
REG_JNI(register_android_view_InputQueue),
REG_JNI(register_android_view_KeyEvent),
REG_JNI(register_android_view_MotionEvent),
+ REG_JNI(register_android_view_MotionPredictor),
REG_JNI(register_android_view_PointerIcon),
REG_JNI(register_android_view_VelocityTracker),
REG_JNI(register_android_view_VerifiedKeyEvent),
diff --git a/core/jni/android_hardware_OverlayProperties.cpp b/core/jni/android_hardware_OverlayProperties.cpp
index a96af86..9941ca4 100644
--- a/core/jni/android_hardware_OverlayProperties.cpp
+++ b/core/jni/android_hardware_OverlayProperties.cpp
@@ -69,6 +69,16 @@
return false;
}
+static jboolean android_hardware_OverlayProperties_supportMixedColorSpaces(JNIEnv* env,
+ jobject thiz,
+ jlong nativeObject) {
+ gui::OverlayProperties* properties = reinterpret_cast<gui::OverlayProperties*>(nativeObject);
+ if (properties != nullptr && properties->supportMixedColorSpaces) {
+ return true;
+ }
+ return false;
+}
+
// ----------------------------------------------------------------------------
// Serialization
// ----------------------------------------------------------------------------
@@ -128,6 +138,8 @@
{ "nGetDestructor", "()J", (void*) android_hardware_OverlayProperties_getDestructor },
{ "nSupportFp16ForHdr", "(J)Z",
(void*) android_hardware_OverlayProperties_supportFp16ForHdr },
+ { "nSupportMixedColorSpaces", "(J)Z",
+ (void*) android_hardware_OverlayProperties_supportMixedColorSpaces },
{ "nWriteOverlayPropertiesToParcel", "(JLandroid/os/Parcel;)V",
(void*) android_hardware_OverlayProperties_write },
{ "nReadOverlayPropertiesFromParcel", "(Landroid/os/Parcel;)J",
diff --git a/core/jni/android_view_InputDevice.cpp b/core/jni/android_view_InputDevice.cpp
index 7002d9b..7d379e5 100644
--- a/core/jni/android_view_InputDevice.cpp
+++ b/core/jni/android_view_InputDevice.cpp
@@ -97,7 +97,6 @@
return env->NewLocalRef(inputDeviceObj.get());
}
-
int register_android_view_InputDevice(JNIEnv* env)
{
gInputDeviceClassInfo.clazz = FindClassOrDie(env, "android/view/InputDevice");
@@ -108,9 +107,8 @@
"String;ZIILandroid/view/KeyCharacterMap;Ljava/"
"lang/String;Ljava/lang/String;ZZZZZZ)V");
- gInputDeviceClassInfo.addMotionRange = GetMethodIDOrDie(env, gInputDeviceClassInfo.clazz,
- "addMotionRange", "(IIFFFFF)V");
-
+ gInputDeviceClassInfo.addMotionRange =
+ GetMethodIDOrDie(env, gInputDeviceClassInfo.clazz, "addMotionRange", "(IIFFFFF)V");
return 0;
}
diff --git a/core/jni/android_view_MotionEvent.cpp b/core/jni/android_view_MotionEvent.cpp
index 403c583..88444cb 100644
--- a/core/jni/android_view_MotionEvent.cpp
+++ b/core/jni/android_view_MotionEvent.cpp
@@ -59,6 +59,7 @@
jfieldID orientation;
jfieldID relativeX;
jfieldID relativeY;
+ jfieldID isResampled;
} gPointerCoordsClassInfo;
static struct {
@@ -102,6 +103,20 @@
return eventObj;
}
+jobject android_view_MotionEvent_obtainFromNative(JNIEnv* env, std::unique_ptr<MotionEvent> event) {
+ if (event == nullptr) {
+ return nullptr;
+ }
+ jobject eventObj =
+ env->CallStaticObjectMethod(gMotionEventClassInfo.clazz, gMotionEventClassInfo.obtain);
+ if (env->ExceptionCheck() || !eventObj) {
+ LOGE_EX(env);
+ LOG_ALWAYS_FATAL("An exception occurred while obtaining a Java motion event.");
+ }
+ android_view_MotionEvent_setNativePtr(env, eventObj, event.release());
+ return eventObj;
+}
+
status_t android_view_MotionEvent_recycle(JNIEnv* env, jobject eventObj) {
env->CallVoidMethod(eventObj, gMotionEventClassInfo.recycle);
if (env->ExceptionCheck()) {
@@ -223,6 +238,8 @@
outRawPointerCoords->setAxisValue(AMOTION_EVENT_AXIS_RELATIVE_Y,
env->GetFloatField(pointerCoordsObj,
gPointerCoordsClassInfo.relativeY));
+ outRawPointerCoords->isResampled =
+ env->GetBooleanField(pointerCoordsObj, gPointerCoordsClassInfo.isResampled);
BitSet64 bits =
BitSet64(env->GetLongField(pointerCoordsObj, gPointerCoordsClassInfo.mPackedAxisBits));
@@ -440,6 +457,11 @@
bits.clearBit(axis);
}
pointerCoordsFromNative(env, rawPointerCoords, bits, outPointerCoordsObj);
+
+ const bool isResampled = historyPos == HISTORY_CURRENT
+ ? event->isResampled(pointerIndex, event->getHistorySize())
+ : event->isResampled(pointerIndex, historyPos);
+ env->SetBooleanField(outPointerCoordsObj, gPointerCoordsClassInfo.isResampled, isResampled);
}
static void android_view_MotionEvent_nativeGetPointerProperties(JNIEnv* env, jclass clazz,
@@ -881,6 +903,7 @@
gPointerCoordsClassInfo.orientation = GetFieldIDOrDie(env, clazz, "orientation", "F");
gPointerCoordsClassInfo.relativeX = GetFieldIDOrDie(env, clazz, "relativeX", "F");
gPointerCoordsClassInfo.relativeY = GetFieldIDOrDie(env, clazz, "relativeY", "F");
+ gPointerCoordsClassInfo.isResampled = GetFieldIDOrDie(env, clazz, "isResampled", "Z");
clazz = FindClassOrDie(env, "android/view/MotionEvent$PointerProperties");
diff --git a/core/jni/android_view_MotionEvent.h b/core/jni/android_view_MotionEvent.h
index 32a280e..e812136 100644
--- a/core/jni/android_view_MotionEvent.h
+++ b/core/jni/android_view_MotionEvent.h
@@ -28,6 +28,11 @@
* Returns NULL on error. */
extern jobject android_view_MotionEvent_obtainAsCopy(JNIEnv* env, const MotionEvent& event);
+/* Obtains an instance of a Java MotionEvent object, taking over the ownership of the provided
+ * native MotionEvent instance. Crashes on error. */
+extern jobject android_view_MotionEvent_obtainFromNative(JNIEnv* env,
+ std::unique_ptr<MotionEvent> event);
+
/* Gets the underlying native MotionEvent instance within a DVM MotionEvent object.
* Returns NULL if the event is NULL or if it is uninitialized. */
extern MotionEvent* android_view_MotionEvent_getNativePtr(JNIEnv* env, jobject eventObj);
diff --git a/core/jni/android_view_MotionPredictor.cpp b/core/jni/android_view_MotionPredictor.cpp
new file mode 100644
index 0000000..2c232fa
--- /dev/null
+++ b/core/jni/android_view_MotionPredictor.cpp
@@ -0,0 +1,100 @@
+/*
+ * 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.
+ */
+
+#define LOG_TAG "MotionPredictor-JNI"
+
+#include <input/Input.h>
+#include <input/MotionPredictor.h>
+
+#include "android_view_MotionEvent.h"
+#include "core_jni_converters.h"
+#include "core_jni_helpers.h"
+
+/**
+ * This file is a bridge from Java to native for MotionPredictor class.
+ * It should be pass-through only. Do not store any state or put any business logic into this file.
+ */
+
+namespace android {
+
+// ----------------------------------------------------------------------------
+
+static struct {
+ jclass clazz;
+} gMotionEventClassInfo;
+
+// ----------------------------------------------------------------------------
+
+static void release(void* ptr) {
+ delete reinterpret_cast<MotionPredictor*>(ptr);
+}
+
+static jlong android_view_MotionPredictor_nativeGetNativeMotionPredictorFinalizer(JNIEnv* env,
+ jclass clazz) {
+ return reinterpret_cast<jlong>(release);
+}
+
+static jlong android_view_MotionPredictor_nativeInitialize(JNIEnv* env, jclass clazz,
+ jint offsetNanos) {
+ const nsecs_t offset = static_cast<nsecs_t>(offsetNanos);
+ return reinterpret_cast<jlong>(new MotionPredictor(offset));
+}
+
+static void android_view_MotionPredictor_nativeRecord(JNIEnv* env, jclass clazz, jlong ptr,
+ jobject event) {
+ MotionPredictor* predictor = reinterpret_cast<MotionPredictor*>(ptr);
+ MotionEvent* motionEvent = android_view_MotionEvent_getNativePtr(env, event);
+ predictor->record(*motionEvent);
+}
+
+static jobject android_view_MotionPredictor_nativePredict(JNIEnv* env, jclass clazz, jlong ptr,
+ jlong predictionTimeNanos) {
+ MotionPredictor* predictor = reinterpret_cast<MotionPredictor*>(ptr);
+ return toJavaArray(env, predictor->predict(static_cast<nsecs_t>(predictionTimeNanos)),
+ gMotionEventClassInfo.clazz, &android_view_MotionEvent_obtainFromNative);
+}
+
+static jboolean android_view_MotionPredictor_nativeIsPredictionAvailable(JNIEnv* env, jclass clazz,
+ jlong ptr, jint deviceId,
+ jint source) {
+ MotionPredictor* predictor = reinterpret_cast<MotionPredictor*>(ptr);
+ return predictor->isPredictionAvailable(static_cast<int32_t>(deviceId),
+ static_cast<int32_t>(source));
+}
+
+// ----------------------------------------------------------------------------
+
+static const std::array<JNINativeMethod, 5> gMotionPredictorMethods{{
+ /* name, signature, funcPtr */
+ {"nativeInitialize", "(I)J", (void*)android_view_MotionPredictor_nativeInitialize},
+ {"nativeGetNativeMotionPredictorFinalizer", "()J",
+ (void*)android_view_MotionPredictor_nativeGetNativeMotionPredictorFinalizer},
+ {"nativeRecord", "(JLandroid/view/MotionEvent;)V",
+ (void*)android_view_MotionPredictor_nativeRecord},
+ {"nativePredict", "(JJ)[Landroid/view/MotionEvent;",
+ (void*)android_view_MotionPredictor_nativePredict},
+ {"nativeIsPredictionAvailable", "(JII)Z",
+ (void*)android_view_MotionPredictor_nativeIsPredictionAvailable},
+}};
+
+int register_android_view_MotionPredictor(JNIEnv* env) {
+ jclass motionEventClazz = FindClassOrDie(env, "android/view/MotionEvent");
+ gMotionEventClassInfo.clazz = MakeGlobalRefOrDie(env, motionEventClazz);
+ return RegisterMethodsOrDie(env, "android/view/MotionPredictor", gMotionPredictorMethods.data(),
+ gMotionPredictorMethods.size());
+}
+
+} // namespace android
diff --git a/core/jni/core_jni_converters.h b/core/jni/core_jni_converters.h
new file mode 100644
index 0000000..cb9bdf7
--- /dev/null
+++ b/core/jni/core_jni_converters.h
@@ -0,0 +1,32 @@
+/*
+ * 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.
+ */
+
+#pragma once
+
+#include <nativehelper/scoped_local_ref.h>
+
+template <class T>
+static jobject toJavaArray(JNIEnv* env, std::vector<T>&& list, jclass clazz,
+ jobject (*convert)(JNIEnv* env, T)) {
+ jobjectArray arr = env->NewObjectArray(list.size(), clazz, nullptr);
+ LOG_ALWAYS_FATAL_IF(arr == nullptr);
+ for (size_t i = 0; i < list.size(); i++) {
+ T& t = list[i];
+ ScopedLocalRef<jobject> javaObj(env, convert(env, std::move(t)));
+ env->SetObjectArrayElement(arr, i, javaObj.get());
+ }
+ return arr;
+}
\ No newline at end of file
diff --git a/core/proto/android/service/package.proto b/core/proto/android/service/package.proto
index 1dedbb9..0fe2a6b 100644
--- a/core/proto/android/service/package.proto
+++ b/core/proto/android/service/package.proto
@@ -124,6 +124,9 @@
// The package on behalf of which the initiiating package requested the install.
optional string originating_package_name = 2;
+
+ // The package that is the update owner.
+ optional string update_owner_package_name = 3;
}
message StatesProto {
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index 31ae0aa..81b3af0 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -3993,6 +3993,18 @@
<permission android:name="android.permission.LIST_ENABLED_CREDENTIAL_PROVIDERS"
android:protectionLevel="signature|privileged" />
+ <!-- Allows a system application to be registered with credential manager without
+ having to be enabled by the user.
+ @hide -->
+ <permission android:name="android.permission.SYSTEM_CREDENTIAL_PROVIDER"
+ android:protectionLevel="signature|privileged" />
+
+ <!-- Allows an application to be able to store and retrieve credentials from a remote
+ device.
+ @hide -->
+ <permission android:name="android.permission.HYBRID_CREDENTIAL_PROVIDER"
+ android:protectionLevel="signature|privileged" />
+
<!-- ========================================= -->
<!-- Permissions for special development tools -->
<!-- ========================================= -->
@@ -6815,6 +6827,16 @@
android:protectionLevel="normal" />
<uses-permission android:name="android.permission.UPDATE_PACKAGES_WITHOUT_USER_ACTION"/>
+ <!-- Allows an application to indicate via {@link
+ android.content.pm.PackageInstaller.SessionParams#setRequestUpdateOwnership}
+ that it has the intention of becoming the update owner.
+ <p>Protection level: normal
+ -->
+ <permission android:name="android.permission.ENFORCE_UPDATE_OWNERSHIP"
+ android:protectionLevel="normal" />
+ <uses-permission android:name="android.permission.ENFORCE_UPDATE_OWNERSHIP" />
+
+
<!-- Allows an application to take screenshots of layers that normally would be blacked out when
a screenshot is taken. Specifically, layers that have the flag
{@link android.view.SurfaceControl#SECURE} will be screenshot if the caller requests to
@@ -6885,7 +6907,7 @@
@hide
-->
<permission android:name="android.permission.ACCESS_AMBIENT_CONTEXT_EVENT"
- android:protectionLevel="internal|role"/>
+ android:protectionLevel="signature|privileged|role"/>
<!-- @SystemApi Required by a AmbientContextEventDetectionService
to ensure that only the service with this permission can bind to it.
@@ -6986,7 +7008,7 @@
@hide
-->
<permission android:name="android.permission.GET_APP_METADATA"
- android:protectionLevel="signature" />
+ android:protectionLevel="signature|installer" />
<!-- @SystemApi Allows the holder to call health connect migration APIs.
@hide -->
diff --git a/core/res/res/drawable/work_mode_emergency_button_background.xml b/core/res/res/drawable/work_mode_emergency_button_background.xml
new file mode 100644
index 0000000..d9b6879
--- /dev/null
+++ b/core/res/res/drawable/work_mode_emergency_button_background.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ 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.
+ -->
+<inset xmlns:android="http://schemas.android.com/apk/res/android"
+ android:insetTop="6dp"
+ android:insetBottom="6dp">
+ <shape android:shape="rectangle">
+ <corners android:radius="18dp"/>
+ <solid android:color="@android:color/system_accent3_100" />
+ </shape>
+</inset>
\ No newline at end of file
diff --git a/core/res/res/values-television/themes_device_defaults.xml b/core/res/res/values-television/themes_device_defaults.xml
index 9d0e522..7cda99a 100644
--- a/core/res/res/values-television/themes_device_defaults.xml
+++ b/core/res/res/values-television/themes_device_defaults.xml
@@ -14,6 +14,7 @@
limitations under the License.
-->
<resources>
+ <style name="Theme.DeviceDefault.Dialog" parent="Theme.Leanback.Dialog" />
<style name="Theme.DeviceDefault.Dialog.Alert" parent="Theme.Leanback.Dialog.Alert" />
<style name="Theme.DeviceDefault.Dialog.AppError" parent="Theme.Leanback.Dialog.AppError" />
<style name="Theme.DeviceDefault.Light.Dialog.Alert" parent="Theme.Leanback.Dialog.Alert" />
diff --git a/core/res/res/values/attrs.xml b/core/res/res/values/attrs.xml
index 1d1c02d..f4d563c 100644
--- a/core/res/res/values/attrs.xml
+++ b/core/res/res/values/attrs.xml
@@ -2653,6 +2653,10 @@
<flag name="noExcludeDescendants" value="0x8" />
</attr>
+ <!-- Boolean that hints the Android System that the view is credntial and associated with
+ CredentialManager -->
+ <attr name="isCredential" format="boolean" />
+
<!-- Hints the Android System whether the this View should be considered a scroll capture target. -->
<attr name="scrollCaptureHint">
<!-- Let the Android System determine if the view can be a scroll capture target. -->
diff --git a/core/res/res/values/attrs_manifest.xml b/core/res/res/values/attrs_manifest.xml
index 8ac13ef..ef94484 100644
--- a/core/res/res/values/attrs_manifest.xml
+++ b/core/res/res/values/attrs_manifest.xml
@@ -1783,6 +1783,14 @@
-->
<attr name="attributionTags" format="string" />
+ <!-- Default value <code>true</code> allows an installer to enable update
+ ownership enforcement for this package via {@link
+ android.content.pm.PackageInstaller.SessionParams#setRequestUpdateOwnership}
+ during initial installation. This overrides the installer's use of {@link
+ android.content.pm.PackageInstaller.SessionParams#setRequestUpdateOwnership}.
+ -->
+ <attr name="allowUpdateOwnership" format="boolean" />
+
<!-- The <code>manifest</code> tag is the root of an
<code>AndroidManifest.xml</code> file,
describing the contents of an Android package (.apk) file. One
@@ -1820,6 +1828,7 @@
<attr name="isSplitRequired" />
<attr name="requiredSplitTypes" />
<attr name="splitTypes" />
+ <attr name="allowUpdateOwnership" />
</declare-styleable>
<!-- The <code>application</code> tag describes application-level components
diff --git a/core/res/res/values/colors.xml b/core/res/res/values/colors.xml
index 8c356b4..fa77c45 100644
--- a/core/res/res/values/colors.xml
+++ b/core/res/res/values/colors.xml
@@ -211,9 +211,6 @@
<color name="SIM_color_orange">#ff995400</color><!-- Material Custom Orange -->
<color name="SIM_dark_mode_color_orange">#fffcad70</color><!-- Material Orange 300 -->
- <color name="resize_shadow_start_color">#2a000000</color>
- <color name="resize_shadow_end_color">#00000000</color>
-
<color name="tooltip_background_dark">#e6616161</color>
<color name="tooltip_background_light">#e6FFFFFF</color>
diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml
index a4d6fdd..6d21fb6 100644
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -2344,6 +2344,24 @@
display, this value should be true. -->
<bool name="config_perDisplayFocusEnabled">false</bool>
+ <!-- Whether the system enables motion prediction. Only enable this after confirming that the
+ model works well on your device. To enable system-based prediction, set this value to true.
+ -->
+ <bool name="config_enableMotionPrediction">true</bool>
+
+ <!-- Additional offset to use for motion prediction, in nanoseconds. A positive number indicates
+ that the prediction will take place further in the future. For example, suppose a
+ MotionEvent arrives with timestamp t=1, and the current expected presentation time is t=2.
+ Typically, the prediction will target the presentation time, t=2. If you'd like to make
+ prediction more aggressive, you could set the offset to a positive number.
+ Setting the offset to 1 here would mean that the prediction will be done for time t=3.
+ A negative number may also be provided, to make the prediction less aggressive. In general,
+ the offset here should represent some built-in hardware delays that may not be accounted
+ for by the "expected present time". See also:
+ https://developer.android.com/reference/android/view/
+ Choreographer.FrameTimeline#getExpectedPresentationTimeNanos() -->
+ <integer name="config_motionPredictionOffsetNanos">0</integer>
+
<!-- Whether a software navigation bar should be shown. NOTE: in the future this may be
autodetected from the Configuration. -->
<bool name="config_showNavigationBar">false</bool>
@@ -2704,6 +2722,10 @@
frameworks/base/services/core/java/com/android/server/pm/UserSystemPackageInstaller.java -->
<integer name="config_userTypePackageWhitelistMode">13</integer> <!-- 1+4+8 -->
+ <!-- Whether the main user is a permanent admin user. If the main user is a permanent admin user
+ it can't be deleted or downgraded to non-admin status. -->
+ <bool name="config_isMainUserPermanentAdmin">false</bool>
+
<!-- Whether UI for multi user should be shown -->
<bool name="config_enableMultiUserUI">false</bool>
diff --git a/core/res/res/values/dimens.xml b/core/res/res/values/dimens.xml
index 9dbb6a0..e156c44 100644
--- a/core/res/res/values/dimens.xml
+++ b/core/res/res/values/dimens.xml
@@ -721,8 +721,6 @@
<item type="fraction" name="docked_stack_divider_fixed_ratio">34.15%</item>
- <dimen name="resize_shadow_size">5dp</dimen>
-
<!-- The default minimal size of a resizable task, in both dimensions. -->
<dimen name="default_minimal_size_resizable_task">220dp</dimen>
diff --git a/core/res/res/values/public-staging.xml b/core/res/res/values/public-staging.xml
index dfd4d9a..6047738 100644
--- a/core/res/res/values/public-staging.xml
+++ b/core/res/res/values/public-staging.xml
@@ -124,6 +124,8 @@
<public name="allowSharedIsolatedProcess" />
<public name="keyboardLocale" />
<public name="keyboardLayoutType" />
+ <public name="allowUpdateOwnership" />
+ <public name="isCredential"/>
</staging-public-group>
<staging-public-group type="id" first-id="0x01cd0000">
diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml
index b754440..7c6f81d 100644
--- a/core/res/res/values/strings.xml
+++ b/core/res/res/values/strings.xml
@@ -5329,6 +5329,10 @@
<string name="work_mode_off_message">Get access to your work apps and notifications</string>
<!-- Title for button to turn on work profile. [CHAR LIMIT=NONE] -->
<string name="work_mode_turn_on">Turn on</string>
+ <!-- Title for button to launch the personal safety app to make an emergency call -->
+ <string name="work_mode_emergency_call_button">Emergency</string>
+ <!-- Text shown in a dialog when the user tries to launch a disabled work profile app when work apps are paused-->
+ <string name="work_mode_dialer_off_message">Get access to your work apps and calls</string>
<!-- Title of the dialog that is shown when the user tries to launch a blocked application [CHAR LIMIT=50] -->
<string name="app_blocked_title">App is not available</string>
diff --git a/core/res/res/values/styles.xml b/core/res/res/values/styles.xml
index 476c18e..0a7ffca 100644
--- a/core/res/res/values/styles.xml
+++ b/core/res/res/values/styles.xml
@@ -30,7 +30,7 @@
-->
<resources>
<!-- Global Theme Styles -->
- <eat-comment />
+ <eat-comment/>
<style name="WindowTitleBackground">
<item name="background">@drawable/title_bar</item>
@@ -69,6 +69,19 @@
<item name="needsDefaultBackgrounds">false</item>
</style>
+ <!-- Base style for the alert dialog with emergency call button -->
+ <style name="AlertDialogWithEmergencyButton" parent="AlertDialog">
+ <item name="buttonBarNeutralButtonStyle">@style/AlertDialogEmergencyButtonStyle</item>
+ </style>
+
+ <style name="AlertDialogEmergencyButtonStyle" parent="AlertDialogWithEmergencyButton">
+ <item name="background">@drawable/work_mode_emergency_button_background</item>
+ <item name="textColor">@color/text_color_on_accent_device_default</item>
+ <item name="paddingLeft">15dip</item>
+ <item name="paddingRight">15dip</item>
+ <item name="layout_marginStart">10dip</item>
+ </style>
+
<style name="Widget.PreferenceFrameLayout">
<item name="borderTop">0dip</item>
<item name="borderBottom">0dip</item>
@@ -77,7 +90,7 @@
</style>
<!-- Base style for animations. This style specifies no animations. -->
- <style name="Animation" />
+ <style name="Animation"/>
<!-- Standard animations for a full-screen window or activity. -->
<style name="Animation.Activity">
@@ -231,7 +244,7 @@
</style>
<!-- A special animation value used internally for popup windows. -->
- <style name="Animation.PopupWindow" />
+ <style name="Animation.PopupWindow"/>
<!-- Window animations used for action mode UI in overlay mode. -->
<style name="Animation.PopupWindow.ActionMode">
@@ -503,7 +516,8 @@
<item name="textEditSidePasteWindowLayout">?attr/textEditSidePasteWindowLayout</item>
<item name="textEditSideNoPasteWindowLayout">?attr/textEditSideNoPasteWindowLayout</item>
<item name="textEditSuggestionItemLayout">?attr/textEditSuggestionItemLayout</item>
- <item name="textEditSuggestionContainerLayout">?attr/textEditSuggestionContainerLayout</item>
+ <item name="textEditSuggestionContainerLayout">?attr/textEditSuggestionContainerLayout
+ </item>
<item name="textEditSuggestionHighlightStyle">?attr/textEditSuggestionHighlightStyle</item>
<item name="textCursorDrawable">?attr/textCursorDrawable</item>
<item name="breakStrategy">high_quality</item>
@@ -593,7 +607,8 @@
<item name="weekNumberColor">#33FFFFFF</item>
<item name="weekSeparatorLineColor">#19FFFFFF</item>
<item name="selectedDateVerticalBar">@drawable/day_picker_week_view_dayline_holo</item>
- <item name="weekDayTextAppearance">@style/TextAppearance.Small.CalendarViewWeekDayView</item>
+ <item name="weekDayTextAppearance">@style/TextAppearance.Small.CalendarViewWeekDayView
+ </item>
<item name="dateTextAppearance">?attr/textAppearanceSmall</item>
<item name="calendarViewMode">holo</item>
</style>
@@ -689,12 +704,12 @@
</style>
<style name="Widget.ListView.DropDown">
- <item name="cacheColorHint">@null</item>
+ <item name="cacheColorHint">@null</item>
<item name="divider">@drawable/divider_horizontal_bright_opaque</item>
</style>
<style name="Widget.ListView.Menu" parent="Widget.Holo.ListView">
- <item name="cacheColorHint">@null</item>
+ <item name="cacheColorHint">@null</item>
<item name="scrollbars">vertical</item>
<item name="fadingEdge">none</item>
<!-- Light background for the list in menus, so the divider for bright themes -->
@@ -819,7 +834,7 @@
</style>
<!-- Text Appearances -->
- <eat-comment />
+ <eat-comment/>
<style name="TextAppearance">
<item name="textColor">?textColorPrimary</item>
@@ -878,9 +893,9 @@
<item name="textColorLink">?textColorLinkInverse</item>
</style>
- <style name="TextAppearance.Theme.Dialog" parent="TextAppearance.Theme" />
+ <style name="TextAppearance.Theme.Dialog" parent="TextAppearance.Theme"/>
- <style name="TextAppearance.Widget" />
+ <style name="TextAppearance.Widget"/>
<style name="TextAppearance.Widget.Button" parent="TextAppearance.Small.Inverse">
<item name="textColor">@color/primary_text_light_nodisable</item>
@@ -946,22 +961,22 @@
</style>
<!-- @hide -->
- <style name="TextAppearance.SearchResult">
- <item name="textStyle">normal</item>
- <item name="textColor">?textColorPrimaryInverse</item>
- <item name="textColorHint">?textColorHintInverse</item>
- </style>
+ <style name="TextAppearance.SearchResult">
+ <item name="textStyle">normal</item>
+ <item name="textColor">?textColorPrimaryInverse</item>
+ <item name="textColorHint">?textColorHintInverse</item>
+ </style>
- <!-- @hide -->
- <style name="TextAppearance.SearchResult.Title">
- <item name="textSize">18sp</item>
- </style>
+ <!-- @hide -->
+ <style name="TextAppearance.SearchResult.Title">
+ <item name="textSize">18sp</item>
+ </style>
- <!-- @hide -->
- <style name="TextAppearance.SearchResult.Subtitle">
- <item name="textSize">14sp</item>
- <item name="textColor">?textColorSecondaryInverse</item>
- </style>
+ <!-- @hide -->
+ <style name="TextAppearance.SearchResult.Subtitle">
+ <item name="textSize">14sp</item>
+ <item name="textColor">?textColorSecondaryInverse</item>
+ </style>
<style name="TextAppearance.WindowTitle">
<item name="textColor">#fff</item>
@@ -1165,7 +1180,7 @@
</style>
<!-- Other Misc Styles -->
- <eat-comment />
+ <eat-comment/>
<style name="MediaButton">
<item name="background">@null</item>
@@ -1298,10 +1313,12 @@
<item name="textColor">?attr/textColorSecondary</item>
</style>
- <style name="TextAppearance.Widget.Toolbar.Title" parent="TextAppearance.Widget.ActionBar.Title">
+ <style name="TextAppearance.Widget.Toolbar.Title"
+ parent="TextAppearance.Widget.ActionBar.Title">
</style>
- <style name="TextAppearance.Widget.Toolbar.Subtitle" parent="TextAppearance.Widget.ActionBar.Subtitle">
+ <style name="TextAppearance.Widget.Toolbar.Subtitle"
+ parent="TextAppearance.Widget.ActionBar.Subtitle">
</style>
<style name="Widget.ActionButton">
@@ -1527,8 +1544,8 @@
<!-- The style for normal action button on notification -->
<style name="NotificationAction" parent="Widget.Material.Light.Button.Borderless.Small">
- <item name="textColor">@color/notification_action_button_text_color</item>
- <item name="background">@drawable/notification_material_action_background</item>
+ <item name="textColor">@color/notification_action_button_text_color</item>
+ <item name="background">@drawable/notification_material_action_background</item>
</style>
<!-- The style for emphasized action button on notification: Colored bordered ink button -->
@@ -1539,6 +1556,6 @@
<!-- The style for disabled action button on notification -->
<style name="NotificationTombstoneAction" parent="NotificationAction">
- <item name="textColor">#555555</item>
+ <item name="textColor">#555555</item>
</style>
</resources>
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index 9b04c6b..2abb0d8 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -352,6 +352,7 @@
<java-symbol type="bool" name="config_restartRadioAfterProvisioning" />
<java-symbol type="bool" name="config_speed_up_audio_on_mt_calls" />
<java-symbol type="bool" name="config_useFixedVolume" />
+ <java-symbol type="bool" name="config_isMainUserPermanentAdmin"/>
<java-symbol type="bool" name="config_enableMultiUserUI"/>
<java-symbol type="bool" name="config_enableMultipleAdmins"/>
<java-symbol type="bool" name="config_enableNewAutoSelectNetworkUI"/>
@@ -1684,6 +1685,8 @@
<java-symbol type="bool" name="config_lockUiMode" />
<java-symbol type="bool" name="config_reverseDefaultRotation" />
<java-symbol type="bool" name="config_perDisplayFocusEnabled" />
+ <java-symbol type="bool" name="config_enableMotionPrediction" />
+ <java-symbol type="integer" name="config_motionPredictionOffsetNanos" />
<java-symbol type="bool" name="config_showNavigationBar" />
<java-symbol type="bool" name="config_supportAutoRotation" />
<java-symbol type="bool" name="config_dockedStackDividerFreeSnapMode" />
@@ -1695,9 +1698,6 @@
<java-symbol type="fraction" name="docked_stack_divider_fixed_ratio" />
<java-symbol type="fraction" name="thumbnail_fullscreen_scale" />
<java-symbol type="integer" name="thumbnail_width_tv" />
- <java-symbol type="dimen" name="resize_shadow_size" />
- <java-symbol type="color" name="resize_shadow_start_color" />
- <java-symbol type="color" name="resize_shadow_end_color" />
<java-symbol type="dimen" name="navigation_bar_height" />
<java-symbol type="dimen" name="navigation_bar_height_landscape" />
<java-symbol type="dimen" name="navigation_bar_width" />
@@ -3100,6 +3100,10 @@
<java-symbol type="string" name="language_selection_title" />
<java-symbol type="string" name="search_language_hint" />
+ <!-- Work profile unlaunchable app alert dialog-->
+ <java-symbol type="style" name="AlertDialogWithEmergencyButton"/>
+ <java-symbol type="string" name="work_mode_dialer_off_message" />
+ <java-symbol type="string" name="work_mode_emergency_call_button" />
<java-symbol type="string" name="work_mode_off_title" />
<java-symbol type="string" name="work_mode_off_message" />
<java-symbol type="string" name="work_mode_turn_on" />
diff --git a/core/tests/BroadcastRadioTests/src/com/android/server/broadcastradio/aidl/AidlTestUtils.java b/core/tests/BroadcastRadioTests/src/com/android/server/broadcastradio/aidl/AidlTestUtils.java
index 82db716..cce1b2b 100644
--- a/core/tests/BroadcastRadioTests/src/com/android/server/broadcastradio/aidl/AidlTestUtils.java
+++ b/core/tests/BroadcastRadioTests/src/com/android/server/broadcastradio/aidl/AidlTestUtils.java
@@ -21,10 +21,15 @@
import android.hardware.broadcastradio.ProgramInfo;
import android.hardware.broadcastradio.ProgramListChunk;
import android.hardware.broadcastradio.VendorKeyValue;
+import android.hardware.radio.ProgramList;
import android.hardware.radio.ProgramSelector;
import android.hardware.radio.RadioManager;
import android.hardware.radio.RadioMetadata;
+import android.os.RemoteException;
import android.util.ArrayMap;
+import android.util.ArraySet;
+
+import java.util.List;
final class AidlTestUtils {
@@ -94,6 +99,14 @@
return makeHalProgramInfo(hwSel, hwSel.primaryId, hwSel.primaryId, hwSignalQuality);
}
+ static ProgramInfo programInfoToHalProgramInfo(RadioManager.ProgramInfo info) {
+ return makeHalProgramInfo(
+ ConversionUtils.programSelectorToHalProgramSelector(info.getSelector()),
+ ConversionUtils.identifierToHalProgramIdentifier(info.getLogicallyTunedTo()),
+ ConversionUtils.identifierToHalProgramIdentifier(info.getPhysicallyTunedTo()),
+ info.getSignalStrength());
+ }
+
static ProgramInfo makeHalProgramInfo(
android.hardware.broadcastradio.ProgramSelector hwSel,
ProgramIdentifier logicallyTunedTo, ProgramIdentifier physicallyTunedTo,
@@ -108,7 +121,23 @@
return hwInfo;
}
- static ProgramListChunk makeProgramListChunk(boolean purge, boolean complete,
+ static ProgramListChunk makeHalChunk(boolean purge, boolean complete,
+ List<RadioManager.ProgramInfo> modified, List<ProgramSelector.Identifier> removed) {
+ ProgramInfo[] halModified =
+ new android.hardware.broadcastradio.ProgramInfo[modified.size()];
+ for (int i = 0; i < modified.size(); i++) {
+ halModified[i] = programInfoToHalProgramInfo(modified.get(i));
+ }
+
+ ProgramIdentifier[] halRemoved =
+ new android.hardware.broadcastradio.ProgramIdentifier[removed.size()];
+ for (int i = 0; i < removed.size(); i++) {
+ halRemoved[i] = ConversionUtils.identifierToHalProgramIdentifier(removed.get(i));
+ }
+ return makeHalChunk(purge, complete, halModified, halRemoved);
+ }
+
+ static ProgramListChunk makeHalChunk(boolean purge, boolean complete,
ProgramInfo[] modified, ProgramIdentifier[] removed) {
ProgramListChunk halChunk = new ProgramListChunk();
halChunk.purge = purge;
@@ -118,6 +147,21 @@
return halChunk;
}
+ static ProgramList.Chunk makeChunk(boolean purge, boolean complete,
+ List<RadioManager.ProgramInfo> modified,
+ List<ProgramSelector.Identifier> removed) throws RemoteException {
+ ArraySet<RadioManager.ProgramInfo> modifiedSet = new ArraySet<>();
+ if (modified != null) {
+ modifiedSet.addAll(modified);
+ }
+ ArraySet<ProgramSelector.Identifier> removedSet = new ArraySet<>();
+ if (removed != null) {
+ removedSet.addAll(removed);
+ }
+ ProgramList.Chunk chunk = new ProgramList.Chunk(purge, complete, modifiedSet, removedSet);
+ return chunk;
+ }
+
static VendorKeyValue makeVendorKeyValue(String vendorKey, String vendorValue) {
VendorKeyValue vendorKeyValue = new VendorKeyValue();
vendorKeyValue.key = vendorKey;
diff --git a/core/tests/BroadcastRadioTests/src/com/android/server/broadcastradio/aidl/ConversionUtilsTest.java b/core/tests/BroadcastRadioTests/src/com/android/server/broadcastradio/aidl/ConversionUtilsTest.java
index 710c150..5d0e076 100644
--- a/core/tests/BroadcastRadioTests/src/com/android/server/broadcastradio/aidl/ConversionUtilsTest.java
+++ b/core/tests/BroadcastRadioTests/src/com/android/server/broadcastradio/aidl/ConversionUtilsTest.java
@@ -328,7 +328,7 @@
TEST_HAL_DAB_SID_EXT_ID, TEST_HAL_DAB_FREQUENCY_ID, TEST_SIGNAL_QUALITY);
RadioManager.ProgramInfo dabInfo =
ConversionUtils.programInfoFromHalProgramInfo(halDabInfo);
- ProgramListChunk halChunk = AidlTestUtils.makeProgramListChunk(purge, complete,
+ ProgramListChunk halChunk = AidlTestUtils.makeHalChunk(purge, complete,
new ProgramInfo[]{halDabInfo},
new ProgramIdentifier[]{TEST_HAL_VENDOR_ID, TEST_HAL_FM_FREQUENCY_ID});
@@ -353,7 +353,7 @@
TEST_HAL_DAB_ENSEMBLE_ID, TEST_HAL_DAB_FREQUENCY_ID});
ProgramInfo halDabInfo = AidlTestUtils.makeHalProgramInfo(halDabSelector,
TEST_HAL_DAB_SID_EXT_ID, TEST_HAL_DAB_ENSEMBLE_ID, TEST_SIGNAL_QUALITY);
- ProgramListChunk halChunk = AidlTestUtils.makeProgramListChunk(purge, complete,
+ ProgramListChunk halChunk = AidlTestUtils.makeHalChunk(purge, complete,
new ProgramInfo[]{halDabInfo}, new ProgramIdentifier[]{TEST_HAL_FM_FREQUENCY_ID});
ProgramList.Chunk chunk = ConversionUtils.chunkFromHalProgramListChunk(halChunk);
diff --git a/core/tests/BroadcastRadioTests/src/com/android/server/broadcastradio/aidl/ProgramInfoCacheTest.java b/core/tests/BroadcastRadioTests/src/com/android/server/broadcastradio/aidl/ProgramInfoCacheTest.java
new file mode 100644
index 0000000..d54397e
--- /dev/null
+++ b/core/tests/BroadcastRadioTests/src/com/android/server/broadcastradio/aidl/ProgramInfoCacheTest.java
@@ -0,0 +1,409 @@
+/*
+ * 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 com.android.server.broadcastradio.aidl;
+
+import android.hardware.broadcastradio.ProgramIdentifier;
+import android.hardware.broadcastradio.ProgramInfo;
+import android.hardware.broadcastradio.ProgramListChunk;
+import android.hardware.radio.ProgramList;
+import android.hardware.radio.ProgramSelector;
+import android.hardware.radio.RadioManager;
+import android.os.RemoteException;
+import android.util.ArraySet;
+
+import com.google.common.truth.Expect;
+
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.junit.MockitoJUnitRunner;
+
+import java.util.List;
+import java.util.Set;
+
+/**
+ * Unit tests for AIDL ProgramInfoCache
+ */
+@RunWith(MockitoJUnitRunner.class)
+public class ProgramInfoCacheTest {
+
+ private static final int TEST_SIGNAL_QUALITY = 90;
+
+ private static final ProgramSelector.Identifier TEST_FM_FREQUENCY_ID =
+ new ProgramSelector.Identifier(ProgramSelector.IDENTIFIER_TYPE_AMFM_FREQUENCY,
+ /* value= */ 88_500);
+ private static final RadioManager.ProgramInfo TEST_FM_INFO = AidlTestUtils.makeProgramInfo(
+ AidlTestUtils.makeProgramSelector(ProgramSelector.PROGRAM_TYPE_FM,
+ TEST_FM_FREQUENCY_ID), TEST_FM_FREQUENCY_ID, TEST_FM_FREQUENCY_ID,
+ TEST_SIGNAL_QUALITY);
+ private static final RadioManager.ProgramInfo TEST_FM_INFO_MODIFIED =
+ AidlTestUtils.makeProgramInfo(AidlTestUtils.makeProgramSelector(
+ ProgramSelector.PROGRAM_TYPE_FM, TEST_FM_FREQUENCY_ID), TEST_FM_FREQUENCY_ID,
+ TEST_FM_FREQUENCY_ID, /* signalQuality= */ 99);
+
+ private static final ProgramSelector.Identifier TEST_AM_FREQUENCY_ID =
+ new ProgramSelector.Identifier(ProgramSelector.IDENTIFIER_TYPE_AMFM_FREQUENCY,
+ /* value= */ 1_700);
+ private static final RadioManager.ProgramInfo TEST_AM_INFO = AidlTestUtils.makeProgramInfo(
+ AidlTestUtils.makeProgramSelector(ProgramSelector.PROGRAM_TYPE_FM,
+ TEST_AM_FREQUENCY_ID), TEST_AM_FREQUENCY_ID, TEST_AM_FREQUENCY_ID,
+ TEST_SIGNAL_QUALITY);
+
+ private static final ProgramSelector.Identifier TEST_RDS_PI_ID =
+ new ProgramSelector.Identifier(ProgramSelector.IDENTIFIER_TYPE_RDS_PI,
+ /* value= */ 15_019);
+ private static final RadioManager.ProgramInfo TEST_RDS_INFO = AidlTestUtils.makeProgramInfo(
+ AidlTestUtils.makeProgramSelector(ProgramSelector.PROGRAM_TYPE_FM, TEST_RDS_PI_ID),
+ TEST_RDS_PI_ID, new ProgramSelector.Identifier(
+ ProgramSelector.IDENTIFIER_TYPE_AMFM_FREQUENCY, /* value= */ 89_500),
+ TEST_SIGNAL_QUALITY);
+
+ private static final ProgramSelector.Identifier TEST_DAB_DMB_SID_EXT_ID =
+ new ProgramSelector.Identifier(ProgramSelector.IDENTIFIER_TYPE_DAB_DMB_SID_EXT,
+ /* value= */ 0xA000000111L);
+ private static final ProgramSelector.Identifier TEST_DAB_ENSEMBLE_ID =
+ new ProgramSelector.Identifier(ProgramSelector.IDENTIFIER_TYPE_DAB_ENSEMBLE,
+ /* value= */ 0x1001);
+ private static final ProgramSelector.Identifier TEST_DAB_FREQUENCY_ID =
+ new ProgramSelector.Identifier(ProgramSelector.IDENTIFIER_TYPE_DAB_FREQUENCY,
+ /* value= */ 220_352);
+ private static final RadioManager.ProgramInfo TEST_DAB_INFO = AidlTestUtils.makeProgramInfo(
+ new ProgramSelector(ProgramSelector.PROGRAM_TYPE_DAB, TEST_DAB_DMB_SID_EXT_ID,
+ new ProgramSelector.Identifier[]{TEST_DAB_FREQUENCY_ID, TEST_DAB_ENSEMBLE_ID},
+ /* vendorIds= */ null), TEST_DAB_DMB_SID_EXT_ID, TEST_DAB_FREQUENCY_ID,
+ TEST_SIGNAL_QUALITY);
+
+ private static final ProgramSelector.Identifier TEST_VENDOR_ID =
+ new ProgramSelector.Identifier(ProgramSelector.IDENTIFIER_TYPE_VENDOR_START,
+ /* value= */ 9_001);
+ private static final RadioManager.ProgramInfo TEST_VENDOR_INFO = AidlTestUtils.makeProgramInfo(
+ AidlTestUtils.makeProgramSelector(ProgramSelector.PROGRAM_TYPE_VENDOR_START,
+ TEST_VENDOR_ID), TEST_VENDOR_ID, TEST_VENDOR_ID, TEST_SIGNAL_QUALITY);
+
+ private static final ProgramInfoCache FULL_PROGRAM_INFO_CACHE = new ProgramInfoCache(
+ /* filter= */ null, /* complete= */ true,
+ TEST_FM_INFO, TEST_AM_INFO, TEST_RDS_INFO, TEST_DAB_INFO, TEST_VENDOR_INFO);
+
+ @Rule
+ public final Expect expect = Expect.create();
+
+ @Test
+ public void isComplete_forCompleteProgramInfoCache_returnsTrue() {
+ expect.withMessage("Complete program info cache")
+ .that(FULL_PROGRAM_INFO_CACHE.isComplete()).isTrue();
+ }
+
+ @Test
+ public void isComplete_forIncompleteProgramInfoCache_returnsFalse() {
+ ProgramInfoCache programInfoCache = new ProgramInfoCache(/* filter= */ null,
+ /* complete= */ false);
+ expect.withMessage("Incomplete program info cache")
+ .that(programInfoCache.isComplete()).isFalse();
+ }
+
+ @Test
+ public void getFilter_forProgramInfoCache() {
+ ProgramList.Filter fmFilter = new ProgramList.Filter(
+ Set.of(ProgramSelector.IDENTIFIER_TYPE_AMFM_FREQUENCY), new ArraySet<>(),
+ /* includeCategories= */ true, /* excludeModifications= */ false);
+ ProgramInfoCache fmProgramInfoCache = new ProgramInfoCache(fmFilter);
+
+ expect.withMessage("Program info cache filter")
+ .that(fmProgramInfoCache.getFilter()).isEqualTo(fmFilter);
+ }
+
+ @Test
+ public void updateFromHalProgramListChunk_withPurgingCompleteChunk() {
+ ProgramInfoCache cache = new ProgramInfoCache(/* filter= */ null,
+ /* complete= */ false, TEST_FM_INFO);
+ ProgramListChunk chunk = AidlTestUtils.makeHalChunk(/* purge= */ true, /* complete= */ true,
+ new ProgramInfo[]{AidlTestUtils.programInfoToHalProgramInfo(TEST_RDS_INFO),
+ AidlTestUtils.programInfoToHalProgramInfo(TEST_VENDOR_INFO)},
+ new ProgramIdentifier[]{});
+
+ cache.updateFromHalProgramListChunk(chunk);
+
+ expect.withMessage("Program cache updated with purge-enabled and complete chunk")
+ .that(cache.toProgramInfoList())
+ .containsExactly(TEST_RDS_INFO, TEST_VENDOR_INFO);
+ expect.withMessage("Complete program cache").that(cache.isComplete()).isTrue();
+ }
+
+ @Test
+ public void updateFromHalProgramListChunk_withNonPurgingIncompleteChunk() {
+ ProgramInfoCache cache = new ProgramInfoCache(/* filter= */ null,
+ /* complete= */ false, TEST_FM_INFO, TEST_RDS_INFO, TEST_AM_INFO);
+ ProgramListChunk chunk = AidlTestUtils.makeHalChunk(/* purge= */ false,
+ /* complete= */ false,
+ new ProgramInfo[]{AidlTestUtils.programInfoToHalProgramInfo(TEST_FM_INFO_MODIFIED),
+ AidlTestUtils.programInfoToHalProgramInfo(TEST_VENDOR_INFO)},
+ new ProgramIdentifier[]{ConversionUtils.identifierToHalProgramIdentifier(
+ TEST_RDS_PI_ID)});
+
+ cache.updateFromHalProgramListChunk(chunk);
+
+ expect.withMessage("Program cache updated with non-purging and incomplete chunk")
+ .that(cache.toProgramInfoList())
+ .containsExactly(TEST_FM_INFO_MODIFIED, TEST_VENDOR_INFO, TEST_AM_INFO);
+ expect.withMessage("Incomplete program cache").that(cache.isComplete()).isFalse();
+ }
+
+ @Test
+ public void filterAndUpdateFromInternal_withNullFilter() {
+ ProgramInfoCache cache = new ProgramInfoCache(/* filter= */ null,
+ /* complete= */ true);
+
+ cache.filterAndUpdateFromInternal(FULL_PROGRAM_INFO_CACHE, /* purge= */ false);
+
+ expect.withMessage("Program cache filtered by null filter")
+ .that(cache.toProgramInfoList())
+ .containsExactly(TEST_FM_INFO, TEST_AM_INFO, TEST_RDS_INFO, TEST_DAB_INFO,
+ TEST_VENDOR_INFO);
+ }
+
+ @Test
+ public void filterAndUpdateFromInternal_withEmptyFilter() {
+ ProgramInfoCache cache = new ProgramInfoCache(new ProgramList.Filter(new ArraySet<>(),
+ new ArraySet<>(),
+ /* includeCategories= */ true, /* excludeModifications= */ false));
+
+ cache.filterAndUpdateFromInternal(FULL_PROGRAM_INFO_CACHE, /* purge= */ false);
+
+ expect.withMessage("Program cache filtered by empty filter")
+ .that(cache.toProgramInfoList())
+ .containsExactly(TEST_FM_INFO, TEST_AM_INFO, TEST_RDS_INFO, TEST_DAB_INFO,
+ TEST_VENDOR_INFO);
+ }
+
+ @Test
+ public void filterAndUpdateFromInternal_withFilterByIdentifierType() {
+ ProgramInfoCache cache = new ProgramInfoCache(
+ new ProgramList.Filter(Set.of(ProgramSelector.IDENTIFIER_TYPE_AMFM_FREQUENCY,
+ ProgramSelector.IDENTIFIER_TYPE_RDS_PI), new ArraySet<>(),
+ /* includeCategories= */ true, /* excludeModifications= */ false));
+
+ cache.filterAndUpdateFromInternal(FULL_PROGRAM_INFO_CACHE, /* purge= */ false);
+
+ expect.withMessage("Program cache filtered by identifier type")
+ .that(cache.toProgramInfoList())
+ .containsExactly(TEST_FM_INFO, TEST_AM_INFO, TEST_RDS_INFO);
+ }
+
+ @Test
+ public void filterAndUpdateFromInternal_withFilterByIdentifier() {
+ ProgramInfoCache cache = new ProgramInfoCache(new ProgramList.Filter(
+ new ArraySet<>(), Set.of(TEST_FM_FREQUENCY_ID, TEST_DAB_DMB_SID_EXT_ID),
+ /* includeCategories= */ true, /* excludeModifications= */ false));
+ int maxNumModifiedPerChunk = 2;
+ int maxNumRemovedPerChunk = 2;
+
+ List<ProgramList.Chunk> programListChunks = cache.filterAndUpdateFromInternal(
+ FULL_PROGRAM_INFO_CACHE, /* purge= */ true, maxNumModifiedPerChunk,
+ maxNumRemovedPerChunk);
+
+ expect.withMessage("Program cache filtered by identifier")
+ .that(cache.toProgramInfoList()).containsExactly(TEST_FM_INFO, TEST_DAB_INFO);
+ verifyChunkListPurge(programListChunks, /* purge= */ true);
+ verifyChunkListComplete(programListChunks, FULL_PROGRAM_INFO_CACHE.isComplete());
+ verifyChunkListModified(programListChunks, maxNumModifiedPerChunk, TEST_FM_INFO,
+ TEST_DAB_INFO);
+ verifyChunkListRemoved(programListChunks, maxNumRemovedPerChunk);
+ }
+
+ @Test
+ public void filterAndUpdateFromInternal_withFilterExcludingCategories() {
+ ProgramInfoCache cache = new ProgramInfoCache(new ProgramList.Filter(new ArraySet<>(),
+ new ArraySet<>(), /* includeCategories= */ false,
+ /* excludeModifications= */ false));
+ int maxNumModifiedPerChunk = 3;
+ int maxNumRemovedPerChunk = 2;
+
+ List<ProgramList.Chunk> programListChunks = cache.filterAndUpdateFromInternal(
+ FULL_PROGRAM_INFO_CACHE, /* purge= */ false, maxNumModifiedPerChunk,
+ maxNumRemovedPerChunk);
+
+ expect.withMessage("Program cache filtered by excluding categories")
+ .that(cache.toProgramInfoList())
+ .containsExactly(TEST_FM_INFO, TEST_AM_INFO, TEST_RDS_INFO, TEST_DAB_INFO);
+ verifyChunkListPurge(programListChunks, /* purge= */ true);
+ verifyChunkListComplete(programListChunks, FULL_PROGRAM_INFO_CACHE.isComplete());
+ verifyChunkListModified(programListChunks, maxNumModifiedPerChunk, TEST_FM_INFO,
+ TEST_AM_INFO, TEST_RDS_INFO, TEST_DAB_INFO);
+ verifyChunkListRemoved(programListChunks, maxNumRemovedPerChunk);
+ }
+
+ @Test
+ public void filterAndUpdateFromInternal_withFilterExcludingModifications() {
+ ProgramList.Filter filterExcludingModifications = new ProgramList.Filter(new ArraySet<>(),
+ new ArraySet<>(), /* includeCategories= */ true,
+ /* excludeModifications= */ true);
+ ProgramInfoCache cache = new ProgramInfoCache(filterExcludingModifications,
+ /* complete= */ true, TEST_FM_INFO, TEST_RDS_INFO, TEST_AM_INFO, TEST_DAB_INFO);
+ ProgramInfoCache halCache = new ProgramInfoCache(/* filter= */ null, /* complete= */ false,
+ TEST_FM_INFO_MODIFIED, TEST_VENDOR_INFO);
+ int maxNumModifiedPerChunk = 2;
+ int maxNumRemovedPerChunk = 2;
+
+ List<ProgramList.Chunk> programListChunks = cache.filterAndUpdateFromInternal(halCache,
+ /* purge= */ false, maxNumModifiedPerChunk, maxNumRemovedPerChunk);
+
+ expect.withMessage("Program cache filtered by excluding modifications")
+ .that(cache.toProgramInfoList())
+ .containsExactly(TEST_FM_INFO, TEST_VENDOR_INFO);
+ verifyChunkListPurge(programListChunks, /* purge= */ false);
+ verifyChunkListComplete(programListChunks, halCache.isComplete());
+ verifyChunkListModified(programListChunks, maxNumModifiedPerChunk, TEST_VENDOR_INFO);
+ verifyChunkListRemoved(programListChunks, maxNumRemovedPerChunk, TEST_RDS_PI_ID,
+ TEST_AM_FREQUENCY_ID, TEST_DAB_DMB_SID_EXT_ID);
+ }
+
+ @Test
+ public void filterAndUpdateFromInternal_withPurge() {
+ ProgramInfoCache cache = new ProgramInfoCache(new ProgramList.Filter(new ArraySet<>(),
+ new ArraySet<>(), /* includeCategories= */ true,
+ /* excludeModifications= */ false),
+ /* complete= */ true, TEST_FM_INFO, TEST_RDS_INFO);
+ ProgramInfoCache halCache = new ProgramInfoCache(/* filter= */ null, /* complete= */ false,
+ TEST_FM_INFO_MODIFIED, TEST_DAB_INFO, TEST_VENDOR_INFO);
+ int maxNumModifiedPerChunk = 2;
+ int maxNumRemovedPerChunk = 2;
+
+ List<ProgramList.Chunk> programListChunks = cache.filterAndUpdateFromInternal(halCache,
+ /* purge= */ true, maxNumModifiedPerChunk, maxNumRemovedPerChunk);
+
+ expect.withMessage("Purged program cache").that(cache.toProgramInfoList())
+ .containsExactly(TEST_FM_INFO_MODIFIED, TEST_DAB_INFO, TEST_VENDOR_INFO);
+ verifyChunkListPurge(programListChunks, /* purge= */ true);
+ verifyChunkListComplete(programListChunks, halCache.isComplete());
+ verifyChunkListModified(programListChunks, maxNumModifiedPerChunk, TEST_FM_INFO_MODIFIED,
+ TEST_DAB_INFO, TEST_VENDOR_INFO);
+ verifyChunkListRemoved(programListChunks, maxNumRemovedPerChunk);
+ }
+
+ @Test
+ public void filterAndApplyChunkInternal_withPurgingIncompleteChunk() throws RemoteException {
+ ProgramInfoCache cache = new ProgramInfoCache(/* filter= */ null,
+ /* complete= */ false, TEST_FM_INFO, TEST_DAB_INFO);
+ ProgramList.Chunk chunk = AidlTestUtils.makeChunk(/* purge= */ true, /* complete= */ false,
+ List.of(TEST_FM_INFO_MODIFIED, TEST_RDS_INFO, TEST_VENDOR_INFO),
+ List.of(TEST_DAB_DMB_SID_EXT_ID));
+ int maxNumModifiedPerChunk = 2;
+ int maxNumRemovedPerChunk = 2;
+
+ List<ProgramList.Chunk> programListChunks = cache.filterAndApplyChunkInternal(chunk,
+ maxNumModifiedPerChunk, maxNumRemovedPerChunk);
+
+ expect.withMessage("Program cache applied with non-purging and complete chunk")
+ .that(cache.toProgramInfoList())
+ .containsExactly(TEST_FM_INFO_MODIFIED, TEST_RDS_INFO, TEST_VENDOR_INFO);
+ verifyChunkListPurge(programListChunks, /* purge= */ true);
+ verifyChunkListComplete(programListChunks, /* complete= */ false);
+ verifyChunkListModified(programListChunks, maxNumModifiedPerChunk, TEST_FM_INFO_MODIFIED,
+ TEST_RDS_INFO, TEST_VENDOR_INFO);
+ verifyChunkListRemoved(programListChunks, maxNumRemovedPerChunk);
+ }
+
+ @Test
+ public void filterAndApplyChunk_withNonPurgingCompleteChunk() throws RemoteException {
+ ProgramInfoCache cache = new ProgramInfoCache(/* filter= */ null,
+ /* complete= */ false, TEST_FM_INFO, TEST_RDS_INFO, TEST_AM_INFO, TEST_DAB_INFO);
+ ProgramList.Chunk chunk = AidlTestUtils.makeChunk(/* purge= */ false, /* complete= */ true,
+ List.of(TEST_FM_INFO_MODIFIED, TEST_VENDOR_INFO),
+ List.of(TEST_RDS_PI_ID, TEST_AM_FREQUENCY_ID, TEST_DAB_DMB_SID_EXT_ID));
+ int maxNumModifiedPerChunk = 2;
+ int maxNumRemovedPerChunk = 2;
+
+ List<ProgramList.Chunk> programListChunks = cache.filterAndApplyChunkInternal(chunk,
+ maxNumModifiedPerChunk, maxNumRemovedPerChunk);
+
+ expect.withMessage("Program cache applied with purge-enabled complete chunk")
+ .that(cache.toProgramInfoList())
+ .containsExactly(TEST_FM_INFO_MODIFIED, TEST_VENDOR_INFO);
+ verifyChunkListPurge(programListChunks, /* purge= */ false);
+ verifyChunkListComplete(programListChunks, /* complete= */ true);
+ verifyChunkListModified(programListChunks, maxNumModifiedPerChunk, TEST_FM_INFO_MODIFIED,
+ TEST_VENDOR_INFO);
+ verifyChunkListRemoved(programListChunks, maxNumRemovedPerChunk, TEST_RDS_PI_ID,
+ TEST_AM_FREQUENCY_ID, TEST_DAB_DMB_SID_EXT_ID);
+ }
+
+ private void verifyChunkListPurge(List<ProgramList.Chunk> chunks, boolean purge) {
+ if (chunks.isEmpty()) {
+ return;
+ }
+ for (int i = 0; i < chunks.size(); i++) {
+ ProgramList.Chunk chunk = chunks.get(i);
+ boolean expectedPurge = (i == 0 && purge);
+
+ expect.withMessage("Purge for chunk %s", i)
+ .that(chunk.isPurge()).isEqualTo(expectedPurge);
+ }
+ }
+
+ private void verifyChunkListComplete(List<ProgramList.Chunk> chunks, boolean complete) {
+ if (chunks.isEmpty()) {
+ return;
+ }
+ for (int i = 0; i < chunks.size(); i++) {
+ ProgramList.Chunk chunk = chunks.get(i);
+ boolean expectedComplete = (i == chunks.size() - 1 && complete);
+
+ expect.withMessage("Purge for chunk %s", i)
+ .that(chunk.isComplete()).isEqualTo(expectedComplete);
+ }
+ }
+
+ private void verifyChunkListModified(List<ProgramList.Chunk> chunks,
+ int maxModifiedPerChunk, RadioManager.ProgramInfo... expectedProgramInfos) {
+ if (chunks.isEmpty()) {
+ expect.withMessage("Empty program info list")
+ .that(expectedProgramInfos.length).isEqualTo(0);
+ return;
+ }
+
+ ArraySet<RadioManager.ProgramInfo> actualSet = new ArraySet<>();
+ for (int i = 0; i < chunks.size(); i++) {
+ Set<RadioManager.ProgramInfo> chunkModified = chunks.get(i).getModified();
+ actualSet.addAll(chunkModified);
+
+ expect.withMessage("Chunk %s modified program info array size", i)
+ .that(chunkModified.size()).isAtMost(maxModifiedPerChunk);
+ }
+ expect.withMessage("Program info items")
+ .that(actualSet).containsExactlyElementsIn(expectedProgramInfos);
+ }
+
+ private void verifyChunkListRemoved(List<ProgramList.Chunk> chunks,
+ int maxRemovedPerChunk, ProgramSelector.Identifier... expectedIdentifiers) {
+ if (chunks.isEmpty()) {
+ expect.withMessage("Empty program info list")
+ .that(expectedIdentifiers.length).isEqualTo(0);
+ return;
+ }
+
+ ArraySet<ProgramSelector.Identifier> actualSet = new ArraySet<>();
+ for (int i = 0; i < chunks.size(); i++) {
+ Set<ProgramSelector.Identifier> chunkRemoved = chunks.get(i).getRemoved();
+ actualSet.addAll(chunkRemoved);
+
+ expect.withMessage("Chunk %s removed identifier array size ", i)
+ .that(chunkRemoved.size()).isAtMost(maxRemovedPerChunk);
+ }
+ expect.withMessage("Removed identifier items")
+ .that(actualSet).containsExactlyElementsIn(expectedIdentifiers);
+ }
+}
diff --git a/core/tests/BroadcastRadioTests/src/com/android/server/broadcastradio/aidl/TunerSessionTest.java b/core/tests/BroadcastRadioTests/src/com/android/server/broadcastradio/aidl/TunerSessionTest.java
index d7723ac..464ecb2 100644
--- a/core/tests/BroadcastRadioTests/src/com/android/server/broadcastradio/aidl/TunerSessionTest.java
+++ b/core/tests/BroadcastRadioTests/src/com/android/server/broadcastradio/aidl/TunerSessionTest.java
@@ -37,7 +37,9 @@
import android.hardware.broadcastradio.IBroadcastRadio;
import android.hardware.broadcastradio.ITunerCallback;
import android.hardware.broadcastradio.IdentifierType;
+import android.hardware.broadcastradio.ProgramFilter;
import android.hardware.broadcastradio.ProgramInfo;
+import android.hardware.broadcastradio.ProgramListChunk;
import android.hardware.broadcastradio.Result;
import android.hardware.broadcastradio.VendorKeyValue;
import android.hardware.radio.ProgramList;
@@ -61,8 +63,10 @@
import org.mockito.Mock;
import org.mockito.verification.VerificationWithTimeout;
+import java.util.ArrayList;
import java.util.List;
import java.util.Map;
+import java.util.Set;
/**
* Tests for AIDL HAL TunerSession.
@@ -72,7 +76,7 @@
private static final int TARGET_SDK_VERSION = Build.VERSION_CODES.CUR_DEVELOPMENT;
private static final VerificationWithTimeout CALLBACK_TIMEOUT =
timeout(/* millis= */ 200);
- private static final int SIGNAL_QUALITY = 1;
+ private static final int SIGNAL_QUALITY = 90;
private static final long AM_FM_FREQUENCY_SPACING = 500;
private static final long[] AM_FM_FREQUENCY_LIST = {97_500, 98_100, 99_100};
private static final RadioManager.FmBandDescriptor FM_BAND_DESCRIPTOR =
@@ -84,6 +88,27 @@
new RadioManager.FmBandConfig(FM_BAND_DESCRIPTOR);
private static final int UNSUPPORTED_CONFIG_FLAG = 0;
+ private static final ProgramSelector.Identifier TEST_FM_FREQUENCY_ID =
+ new ProgramSelector.Identifier(ProgramSelector.IDENTIFIER_TYPE_AMFM_FREQUENCY,
+ /* value= */ 88_500);
+ private static final ProgramSelector.Identifier TEST_RDS_PI_ID =
+ new ProgramSelector.Identifier(ProgramSelector.IDENTIFIER_TYPE_RDS_PI,
+ /* value= */ 15_019);
+
+ private static final RadioManager.ProgramInfo TEST_FM_INFO = AidlTestUtils.makeProgramInfo(
+ AidlTestUtils.makeProgramSelector(ProgramSelector.PROGRAM_TYPE_FM,
+ TEST_FM_FREQUENCY_ID), TEST_FM_FREQUENCY_ID, TEST_FM_FREQUENCY_ID,
+ SIGNAL_QUALITY);
+ private static final RadioManager.ProgramInfo TEST_FM_INFO_MODIFIED =
+ AidlTestUtils.makeProgramInfo(AidlTestUtils.makeProgramSelector(
+ ProgramSelector.PROGRAM_TYPE_FM, TEST_FM_FREQUENCY_ID), TEST_FM_FREQUENCY_ID,
+ TEST_FM_FREQUENCY_ID, /* signalQuality= */ 100);
+ private static final RadioManager.ProgramInfo TEST_RDS_INFO = AidlTestUtils.makeProgramInfo(
+ AidlTestUtils.makeProgramSelector(ProgramSelector.PROGRAM_TYPE_FM, TEST_RDS_PI_ID),
+ TEST_RDS_PI_ID, new ProgramSelector.Identifier(
+ ProgramSelector.IDENTIFIER_TYPE_AMFM_FREQUENCY, /* value= */ 89_500),
+ SIGNAL_QUALITY);
+
// Mocks
@Mock private IBroadcastRadio mBroadcastRadioMock;
private android.hardware.radio.ITunerCallback[] mAidlTunerCallbackMocks;
@@ -393,7 +418,7 @@
}
@Test
- public void tune_withHalHasUnknownError_fails() throws Exception {
+ public void tune_withUnknownErrorFromHal_fails() throws Exception {
openAidlClients(/* numClients= */ 1);
ProgramSelector sel = AidlTestUtils.makeFmSelector(AM_FM_FREQUENCY_LIST[1]);
doThrow(new ServiceSpecificException(Result.UNKNOWN_ERROR))
@@ -403,7 +428,7 @@
mTunerSessions[0].tune(sel);
});
- assertWithMessage("Exception for tuning when HAL has unknown error")
+ assertWithMessage("Unknown error HAL exception when tuning")
.that(thrown).hasMessageThat().contains("UNKNOWN_ERROR");
}
@@ -536,7 +561,7 @@
}
@Test
- public void seek_withHalHasInternalError_fails() throws Exception {
+ public void seek_withInternalErrorFromHal_fails() throws Exception {
openAidlClients(/* numClients= */ 1);
doThrow(new ServiceSpecificException(Result.INTERNAL_ERROR))
.when(mBroadcastRadioMock).seek(anyBoolean(), anyBoolean());
@@ -545,7 +570,7 @@
mTunerSessions[0].seek(/* directionDown= */ true, /* skipSubChannel= */ false);
});
- assertWithMessage("Exception for seeking when HAL has internal error")
+ assertWithMessage("Internal error HAL exception when seeking")
.that(thrown).hasMessageThat().contains("INTERNAL_ERROR");
}
@@ -644,11 +669,276 @@
}
@Test
+ public void startProgramListUpdates_withEmptyFilter() throws Exception {
+ openAidlClients(/* numClients= */ 1);
+ ProgramList.Filter filter = new ProgramList.Filter(new ArraySet<>(), new ArraySet<>(),
+ /* includeCategories= */ true, /* excludeModifications= */ false);
+ ProgramFilter halFilter = ConversionUtils.filterToHalProgramFilter(filter);
+ List<RadioManager.ProgramInfo> modified = List.of(TEST_FM_INFO, TEST_RDS_INFO);
+ List<ProgramSelector.Identifier> removed = new ArrayList<>();
+ ProgramListChunk halProgramList = AidlTestUtils.makeHalChunk(/* purge= */ true,
+ /* complete= */ true, modified, removed);
+ ProgramList.Chunk expectedProgramList =
+ AidlTestUtils.makeChunk(/* purge= */ true, /* complete= */ true, modified, removed);
+
+ mTunerSessions[0].startProgramListUpdates(filter);
+ mHalTunerCallback.onProgramListUpdated(halProgramList);
+
+ verify(mBroadcastRadioMock).startProgramListUpdates(halFilter);
+ verify(mAidlTunerCallbackMocks[0], CALLBACK_TIMEOUT)
+ .onProgramListUpdated(expectedProgramList);
+ }
+
+ @Test
+ public void startProgramListUpdates_withCallbackCalledForMultipleTimes() throws Exception {
+ openAidlClients(/* numClients= */ 1);
+ ProgramList.Filter filter = new ProgramList.Filter(new ArraySet<>(), new ArraySet<>(),
+ /* includeCategories= */ true, /* excludeModifications= */ false);
+ mTunerSessions[0].startProgramListUpdates(filter);
+ mHalTunerCallback.onProgramListUpdated(AidlTestUtils.makeHalChunk(/* purge= */ true,
+ /* complete= */ true, List.of(TEST_FM_INFO, TEST_RDS_INFO), new ArrayList<>()));
+ verify(mAidlTunerCallbackMocks[0], CALLBACK_TIMEOUT).onProgramListUpdated(
+ AidlTestUtils.makeChunk(/* purge= */ true, /* complete= */ true,
+ List.of(TEST_FM_INFO, TEST_RDS_INFO), new ArrayList<>()));
+
+ mHalTunerCallback.onProgramListUpdated(AidlTestUtils.makeHalChunk(/* purge= */ false,
+ /* complete= */ true, List.of(TEST_FM_INFO_MODIFIED), List.of(TEST_RDS_PI_ID)));
+
+ verify(mAidlTunerCallbackMocks[0], CALLBACK_TIMEOUT).onProgramListUpdated(
+ AidlTestUtils.makeChunk(/* purge= */ false, /* complete= */ true,
+ List.of(TEST_FM_INFO_MODIFIED), List.of(TEST_RDS_PI_ID)));
+ }
+
+ @Test
+ public void startProgramListUpdates_withTheSameFilterForMultipleTimes() throws Exception {
+ openAidlClients(/* numClients= */ 1);
+ ProgramList.Filter filter = new ProgramList.Filter(new ArraySet<>(), new ArraySet<>(),
+ /* includeCategories= */ true, /* excludeModifications= */ false);
+ mTunerSessions[0].startProgramListUpdates(filter);
+ mHalTunerCallback.onProgramListUpdated(AidlTestUtils.makeHalChunk(/* purge= */ true,
+ /* complete= */ true, List.of(TEST_FM_INFO, TEST_RDS_INFO), new ArrayList<>()));
+ verify(mAidlTunerCallbackMocks[0], CALLBACK_TIMEOUT).onProgramListUpdated(
+ AidlTestUtils.makeChunk(/* purge= */ true, /* complete= */ true,
+ List.of(TEST_FM_INFO, TEST_RDS_INFO), new ArrayList<>()));
+ mHalTunerCallback.onProgramListUpdated(AidlTestUtils.makeHalChunk(/* purge= */ false,
+ /* complete= */ true, List.of(TEST_FM_INFO_MODIFIED), List.of(TEST_RDS_PI_ID)));
+ verify(mAidlTunerCallbackMocks[0], CALLBACK_TIMEOUT).onProgramListUpdated(
+ AidlTestUtils.makeChunk(/* purge= */ false, /* complete= */ true,
+ List.of(TEST_FM_INFO_MODIFIED), List.of(TEST_RDS_PI_ID)));
+
+ mTunerSessions[0].startProgramListUpdates(filter);
+
+ verify(mBroadcastRadioMock).startProgramListUpdates(any());
+ verify(mAidlTunerCallbackMocks[0], CALLBACK_TIMEOUT).onProgramListUpdated(
+ AidlTestUtils.makeChunk(/* purge= */ true, /* complete= */ true,
+ List.of(TEST_FM_INFO_MODIFIED), new ArrayList<>()));
+ }
+
+ @Test
+ public void startProgramListUpdates_withNullFilter() throws Exception {
+ openAidlClients(/* numClients= */ 1);
+
+ mTunerSessions[0].startProgramListUpdates(/* filter= */ null);
+ mHalTunerCallback.onProgramListUpdated(AidlTestUtils.makeHalChunk(/* purge= */ true,
+ /* complete= */ true, List.of(TEST_FM_INFO, TEST_RDS_INFO), new ArrayList<>()));
+
+ verify(mBroadcastRadioMock).startProgramListUpdates(any());
+ verify(mAidlTunerCallbackMocks[0], CALLBACK_TIMEOUT).onProgramListUpdated(
+ AidlTestUtils.makeChunk(/* purge= */ true, /* complete= */ true,
+ List.of(TEST_FM_INFO, TEST_RDS_INFO), new ArrayList<>()));
+
+ mHalTunerCallback.onProgramListUpdated(AidlTestUtils.makeHalChunk(/* purge= */ false,
+ /* complete= */ true, List.of(TEST_FM_INFO_MODIFIED), List.of(TEST_RDS_PI_ID)));
+
+ verify(mAidlTunerCallbackMocks[0], CALLBACK_TIMEOUT).onProgramListUpdated(
+ AidlTestUtils.makeChunk(/* purge= */ false, /* complete= */ true,
+ List.of(TEST_FM_INFO_MODIFIED), List.of(TEST_RDS_PI_ID)));
+ }
+
+ @Test
+ public void startProgramListUpdates_withIdFilter() throws Exception {
+ openAidlClients(/* numClients= */ 1);
+ ProgramList.Filter idFilter = new ProgramList.Filter(new ArraySet<>(),
+ Set.of(TEST_RDS_PI_ID), /* includeCategories= */ true,
+ /* excludeModifications= */ true);
+ ProgramFilter halFilter = ConversionUtils.filterToHalProgramFilter(idFilter);
+
+ mTunerSessions[0].startProgramListUpdates(idFilter);
+ mHalTunerCallback.onProgramListUpdated(AidlTestUtils.makeHalChunk(/* purge= */ false,
+ /* complete= */ true, List.of(TEST_RDS_INFO), new ArrayList<>()));
+
+ verify(mBroadcastRadioMock).startProgramListUpdates(halFilter);
+ verify(mAidlTunerCallbackMocks[0], CALLBACK_TIMEOUT).onProgramListUpdated(
+ AidlTestUtils.makeChunk(/* purge= */ false, /* complete= */ true,
+ List.of(TEST_RDS_INFO), new ArrayList<>()));
+
+ mHalTunerCallback.onProgramListUpdated(AidlTestUtils.makeHalChunk(/* purge= */ false,
+ /* complete= */ true, List.of(TEST_FM_INFO), new ArrayList<>()));
+
+ verify(mAidlTunerCallbackMocks[0], CALLBACK_TIMEOUT).onProgramListUpdated(any());
+ }
+
+ @Test
+ public void startProgramListUpdates_withFilterExcludingModifications() throws Exception {
+ openAidlClients(/* numClients= */ 1);
+ ProgramList.Filter filterExcludingModifications = new ProgramList.Filter(
+ Set.of(ProgramSelector.IDENTIFIER_TYPE_AMFM_FREQUENCY), new ArraySet<>(),
+ /* includeCategories= */ true, /* excludeModifications= */ true);
+ ProgramFilter halFilter =
+ ConversionUtils.filterToHalProgramFilter(filterExcludingModifications);
+
+ mTunerSessions[0].startProgramListUpdates(filterExcludingModifications);
+ mHalTunerCallback.onProgramListUpdated(AidlTestUtils.makeHalChunk(/* purge= */ false,
+ /* complete= */ true, List.of(TEST_FM_INFO), new ArrayList<>()));
+
+ verify(mBroadcastRadioMock).startProgramListUpdates(halFilter);
+ verify(mAidlTunerCallbackMocks[0], CALLBACK_TIMEOUT).onProgramListUpdated(
+ AidlTestUtils.makeChunk(/* purge= */ false, /* complete= */ true,
+ List.of(TEST_FM_INFO), new ArrayList<>()));
+
+ mHalTunerCallback.onProgramListUpdated(AidlTestUtils.makeHalChunk(/* purge= */ false,
+ /* complete= */ true, List.of(TEST_FM_INFO_MODIFIED), new ArrayList<>()));
+
+ verify(mAidlTunerCallbackMocks[0], CALLBACK_TIMEOUT).onProgramListUpdated(any());
+ }
+
+ @Test
+ public void startProgramListUpdates_withFilterIncludingModifications() throws Exception {
+ openAidlClients(/* numClients= */ 1);
+ ProgramList.Filter filterIncludingModifications = new ProgramList.Filter(
+ Set.of(ProgramSelector.IDENTIFIER_TYPE_AMFM_FREQUENCY), new ArraySet<>(),
+ /* includeCategories= */ true, /* excludeModifications= */ false);
+ ProgramFilter halFilter =
+ ConversionUtils.filterToHalProgramFilter(filterIncludingModifications);
+
+ mTunerSessions[0].startProgramListUpdates(filterIncludingModifications);
+ mHalTunerCallback.onProgramListUpdated(AidlTestUtils.makeHalChunk(/* purge= */ false,
+ /* complete= */ true, List.of(TEST_FM_INFO), new ArrayList<>()));
+
+ verify(mBroadcastRadioMock).startProgramListUpdates(halFilter);
+ verify(mAidlTunerCallbackMocks[0], CALLBACK_TIMEOUT).onProgramListUpdated(
+ AidlTestUtils.makeChunk(/* purge= */ false, /* complete= */ true,
+ List.of(TEST_FM_INFO), new ArrayList<>()));
+
+ mHalTunerCallback.onProgramListUpdated(AidlTestUtils.makeHalChunk(/* purge= */ false,
+ /* complete= */ true, List.of(TEST_FM_INFO_MODIFIED), new ArrayList<>()));
+
+ verify(mAidlTunerCallbackMocks[0], CALLBACK_TIMEOUT).onProgramListUpdated(
+ AidlTestUtils.makeChunk(/* purge= */ false, /* complete= */ true,
+ List.of(TEST_FM_INFO_MODIFIED), new ArrayList<>()));
+ }
+
+ @Test
+ public void onProgramListUpdated_afterSessionClosed_doesNotUpdates() throws Exception {
+ openAidlClients(/* numClients= */ 1);
+ ProgramList.Filter filter = new ProgramList.Filter(new ArraySet<>(), new ArraySet<>(),
+ /* includeCategories= */ true, /* excludeModifications= */ false);
+ mTunerSessions[0].startProgramListUpdates(filter);
+
+ mTunerSessions[0].close();
+
+ verify(mBroadcastRadioMock).stopProgramListUpdates();
+
+ mHalTunerCallback.onProgramListUpdated(AidlTestUtils.makeHalChunk(/* purge= */ false,
+ /* complete= */ true, List.of(TEST_FM_INFO), new ArrayList<>()));
+
+ verify(mAidlTunerCallbackMocks[0], CALLBACK_TIMEOUT.times(0)).onProgramListUpdated(any());
+ }
+
+ @Test
+ public void startProgramListUpdates_forMultipleSessions() throws Exception {
+ int numSessions = 3;
+ openAidlClients(numSessions);
+ ProgramList.Filter fmIdFilter = new ProgramList.Filter(new ArraySet<>(),
+ Set.of(TEST_FM_FREQUENCY_ID), /* includeCategories= */ false,
+ /* excludeModifications= */ true);
+ ProgramList.Filter filterExcludingCategories = new ProgramList.Filter(new ArraySet<>(),
+ new ArraySet<>(), /* includeCategories= */ true,
+ /* excludeModifications= */ true);
+ ProgramList.Filter rdsTypeFilter = new ProgramList.Filter(
+ Set.of(ProgramSelector.IDENTIFIER_TYPE_RDS_PI), new ArraySet<>(),
+ /* includeCategories= */ true, /* excludeModifications= */ false);
+
+ mTunerSessions[0].startProgramListUpdates(fmIdFilter);
+
+ ProgramFilter halFilter = ConversionUtils.filterToHalProgramFilter(fmIdFilter);
+ verify(mBroadcastRadioMock).startProgramListUpdates(halFilter);
+
+ mTunerSessions[1].startProgramListUpdates(filterExcludingCategories);
+
+ halFilter.identifiers = new android.hardware.broadcastradio.ProgramIdentifier[]{};
+ halFilter.includeCategories = true;
+ verify(mBroadcastRadioMock).startProgramListUpdates(halFilter);
+
+ mTunerSessions[2].startProgramListUpdates(rdsTypeFilter);
+
+ halFilter.excludeModifications = false;
+ verify(mBroadcastRadioMock).startProgramListUpdates(halFilter);
+ }
+
+ @Test
+ public void onProgramListUpdated_forMultipleSessions() throws Exception {
+ int numSessions = 3;
+ openAidlClients(numSessions);
+ List<ProgramList.Filter> filters = List.of(new ProgramList.Filter(
+ Set.of(ProgramSelector.IDENTIFIER_TYPE_RDS_PI), new ArraySet<>(),
+ /* includeCategories= */ true, /* excludeModifications= */ false),
+ new ProgramList.Filter(new ArraySet<>(), Set.of(TEST_FM_FREQUENCY_ID),
+ /* includeCategories= */ false, /* excludeModifications= */ true),
+ new ProgramList.Filter(new ArraySet<>(), new ArraySet<>(),
+ /* includeCategories= */ true, /* excludeModifications= */ true));
+
+ for (int index = 0; index < numSessions; index++) {
+ mTunerSessions[index].startProgramListUpdates(filters.get(index));
+ }
+
+ mHalTunerCallback.onProgramListUpdated(AidlTestUtils.makeHalChunk(/* purge= */ false,
+ /* complete= */ true, List.of(TEST_FM_INFO, TEST_RDS_INFO), new ArrayList<>()));
+
+ verify(mAidlTunerCallbackMocks[0], CALLBACK_TIMEOUT)
+ .onProgramListUpdated(AidlTestUtils.makeChunk(/* purge= */ false,
+ /* complete= */ true, List.of(TEST_RDS_INFO), new ArrayList<>()));
+ verify(mAidlTunerCallbackMocks[1], CALLBACK_TIMEOUT)
+ .onProgramListUpdated(AidlTestUtils.makeChunk(/* purge= */ false,
+ /* complete= */ true, List.of(TEST_FM_INFO), new ArrayList<>()));
+ verify(mAidlTunerCallbackMocks[2], CALLBACK_TIMEOUT)
+ .onProgramListUpdated(AidlTestUtils.makeChunk(/* purge= */ false,
+ /* complete= */ true, List.of(TEST_RDS_INFO, TEST_FM_INFO),
+ new ArrayList<>()));
+ }
+
+ @Test
+ public void startProgramListUpdates_forNonCurrentUser_doesNotStartUpdates() throws Exception {
+ openAidlClients(/* numClients= */ 1);
+ ProgramList.Filter filter = new ProgramList.Filter(new ArraySet<>(), new ArraySet<>(),
+ /* includeCategories= */ true, /* excludeModifications= */ false);
+ doReturn(false).when(() -> RadioServiceUserController.isCurrentOrSystemUser());
+
+ mTunerSessions[0].startProgramListUpdates(filter);
+
+ verify(mBroadcastRadioMock, never()).startProgramListUpdates(any());
+ }
+
+ @Test
+ public void startProgramListUpdates_withUnknownErrorFromHal_fails() throws Exception {
+ openAidlClients(/* numClients= */ 1);
+ doThrow(new ServiceSpecificException(Result.UNKNOWN_ERROR))
+ .when(mBroadcastRadioMock).startProgramListUpdates(any());
+
+ ParcelableException thrown = assertThrows(ParcelableException.class, () -> {
+ mTunerSessions[0].startProgramListUpdates(/* filter= */ null);
+ });
+
+ assertWithMessage("Unknown error HAL exception when updating program list")
+ .that(thrown).hasMessageThat().contains("UNKNOWN_ERROR");
+ }
+
+ @Test
public void stopProgramListUpdates() throws Exception {
openAidlClients(/* numClients= */ 1);
- ProgramList.Filter aidlFilter = new ProgramList.Filter(new ArraySet<>(), new ArraySet<>(),
+ ProgramList.Filter filter = new ProgramList.Filter(new ArraySet<>(), new ArraySet<>(),
/* includeCategories= */ true, /* excludeModifications= */ false);
- mTunerSessions[0].startProgramListUpdates(aidlFilter);
+ mTunerSessions[0].startProgramListUpdates(filter);
mTunerSessions[0].stopProgramListUpdates();
@@ -658,9 +948,9 @@
@Test
public void stopProgramListUpdates_forNonCurrentUser_doesNotStopUpdates() throws Exception {
openAidlClients(/* numClients= */ 1);
- ProgramList.Filter aidlFilter = new ProgramList.Filter(new ArraySet<>(), new ArraySet<>(),
+ ProgramList.Filter filter = new ProgramList.Filter(new ArraySet<>(), new ArraySet<>(),
/* includeCategories= */ true, /* excludeModifications= */ false);
- mTunerSessions[0].startProgramListUpdates(aidlFilter);
+ mTunerSessions[0].startProgramListUpdates(filter);
doReturn(false).when(() -> RadioServiceUserController.isCurrentOrSystemUser());
mTunerSessions[0].stopProgramListUpdates();
diff --git a/core/tests/BroadcastRadioTests/src/com/android/server/broadcastradio/hal2/TunerSessionHidlTest.java b/core/tests/BroadcastRadioTests/src/com/android/server/broadcastradio/hal2/TunerSessionHidlTest.java
index ea9a846..3815008 100644
--- a/core/tests/BroadcastRadioTests/src/com/android/server/broadcastradio/hal2/TunerSessionHidlTest.java
+++ b/core/tests/BroadcastRadioTests/src/com/android/server/broadcastradio/hal2/TunerSessionHidlTest.java
@@ -373,7 +373,7 @@
}
@Test
- public void tune_withHalHasUnknownError_fails() throws Exception {
+ public void tune_withUnknownErrorFromHal_fails() throws Exception {
openAidlClients(/* numClients= */ 1);
ProgramSelector sel = TestUtils.makeFmSelector(AM_FM_FREQUENCY_LIST[1]);
doAnswer(invocation -> Result.UNKNOWN_ERROR).when(mHalTunerSessionMock).tune(any());
@@ -382,7 +382,7 @@
mTunerSessions[0].tune(sel);
});
- assertWithMessage("Exception for tuning when HAL has unknown error")
+ assertWithMessage("Unknown error HAL exception when tuning")
.that(thrown).hasMessageThat().contains(Result.toString(Result.UNKNOWN_ERROR));
}
@@ -513,7 +513,7 @@
}
@Test
- public void seek_withHalHasInternalError_fails() throws Exception {
+ public void seek_withInternalErrorFromHal_fails() throws Exception {
openAidlClients(/* numClients= */ 1);
doAnswer(invocation -> Result.INTERNAL_ERROR).when(mHalTunerSessionMock)
.scan(anyBoolean(), anyBoolean());
@@ -522,7 +522,7 @@
mTunerSessions[0].seek(/* directionDown= */ true, /* skipSubChannel= */ false);
});
- assertWithMessage("Exception for seeking when HAL has internal error")
+ assertWithMessage("Internal error HAL exception when seeking")
.that(thrown).hasMessageThat().contains(Result.toString(Result.INTERNAL_ERROR));
}
@@ -633,6 +633,32 @@
}
@Test
+ public void startProgramListUpdates_forNonCurrentUser_doesNotStartUpdates() throws Exception {
+ openAidlClients(/* numClients= */ 1);
+ ProgramList.Filter filter = new ProgramList.Filter(new ArraySet<>(), new ArraySet<>(),
+ /* includeCategories= */ true, /* excludeModifications= */ false);
+ doReturn(false).when(() -> RadioServiceUserController.isCurrentOrSystemUser());
+
+ mTunerSessions[0].startProgramListUpdates(filter);
+
+ verify(mHalTunerSessionMock, never()).startProgramListUpdates(any());
+ }
+
+ @Test
+ public void startProgramListUpdates_withUnknownErrorFromHal_fails() throws Exception {
+ openAidlClients(/* numClients= */ 1);
+ doAnswer(invocation -> Result.UNKNOWN_ERROR).when(mHalTunerSessionMock)
+ .startProgramListUpdates(any());
+
+ ParcelableException thrown = assertThrows(ParcelableException.class, () -> {
+ mTunerSessions[0].startProgramListUpdates(/* filter= */ null);
+ });
+
+ assertWithMessage("Unknown error HAL exception when updating program list")
+ .that(thrown).hasMessageThat().contains(Result.toString(Result.UNKNOWN_ERROR));
+ }
+
+ @Test
public void stopProgramListUpdates() throws Exception {
openAidlClients(/* numClients= */ 1);
ProgramList.Filter aidlFilter = new ProgramList.Filter(new ArraySet<>(), new ArraySet<>(),
diff --git a/core/tests/coretests/src/android/companion/virtual/camera/VirtualCameraOutputTest.java b/core/tests/coretests/src/android/companion/virtual/camera/VirtualCameraOutputTest.java
index 694b312..f96d138 100644
--- a/core/tests/coretests/src/android/companion/virtual/camera/VirtualCameraOutputTest.java
+++ b/core/tests/coretests/src/android/companion/virtual/camera/VirtualCameraOutputTest.java
@@ -23,13 +23,16 @@
import android.graphics.PixelFormat;
import android.hardware.camera2.params.InputConfiguration;
import android.os.ParcelFileDescriptor;
+import android.platform.test.annotations.Presubmit;
import android.util.Log;
import androidx.annotation.NonNull;
+import androidx.test.runner.AndroidJUnit4;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
+import org.junit.runner.RunWith;
import java.io.ByteArrayInputStream;
import java.io.FileInputStream;
@@ -38,6 +41,8 @@
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
+@Presubmit
+@RunWith(AndroidJUnit4.class)
public class VirtualCameraOutputTest {
private static final String TAG = "VirtualCameraOutputTest";
diff --git a/core/tests/coretests/src/android/companion/virtual/sensor/VirtualSensorConfigTest.java b/core/tests/coretests/src/android/companion/virtual/sensor/VirtualSensorConfigTest.java
index 11afd04..2a1881e 100644
--- a/core/tests/coretests/src/android/companion/virtual/sensor/VirtualSensorConfigTest.java
+++ b/core/tests/coretests/src/android/companion/virtual/sensor/VirtualSensorConfigTest.java
@@ -26,6 +26,7 @@
import static java.util.concurrent.TimeUnit.MILLISECONDS;
import android.os.Parcel;
+import android.platform.test.annotations.Presubmit;
import androidx.test.runner.AndroidJUnit4;
@@ -42,6 +43,7 @@
import java.time.Duration;
+@Presubmit
@RunWith(AndroidJUnit4.class)
public class VirtualSensorConfigTest {
diff --git a/core/tests/coretests/src/android/companion/virtual/sensor/VirtualSensorEventTest.java b/core/tests/coretests/src/android/companion/virtual/sensor/VirtualSensorEventTest.java
index a9583fd..c260ef9 100644
--- a/core/tests/coretests/src/android/companion/virtual/sensor/VirtualSensorEventTest.java
+++ b/core/tests/coretests/src/android/companion/virtual/sensor/VirtualSensorEventTest.java
@@ -22,12 +22,14 @@
import android.os.Parcel;
import android.os.SystemClock;
+import android.platform.test.annotations.Presubmit;
import androidx.test.runner.AndroidJUnit4;
import org.junit.Test;
import org.junit.runner.RunWith;
+@Presubmit
@RunWith(AndroidJUnit4.class)
public class VirtualSensorEventTest {
diff --git a/core/tests/coretests/src/android/content/res/FontScaleConverterFactoryTest.kt b/core/tests/coretests/src/android/content/res/FontScaleConverterFactoryTest.kt
index 625c318..249e246 100644
--- a/core/tests/coretests/src/android/content/res/FontScaleConverterFactoryTest.kt
+++ b/core/tests/coretests/src/android/content/res/FontScaleConverterFactoryTest.kt
@@ -16,6 +16,8 @@
package android.content.res
+
+import android.platform.test.annotations.Presubmit
import androidx.core.util.forEach
import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.LargeTest
@@ -27,6 +29,7 @@
import org.junit.Test
import org.junit.runner.RunWith
+@Presubmit
@RunWith(AndroidJUnit4::class)
class FontScaleConverterFactoryTest {
@@ -79,10 +82,10 @@
@LargeTest
@Test
fun allFeasibleScalesAndConversionsDoNotCrash() {
- generateSequenceOfFractions(-10000f..10000f, step = 0.01f)
+ generateSequenceOfFractions(-10f..10f, step = 0.01f)
.mapNotNull{ FontScaleConverterFactory.forScale(it) }
.flatMap{ table ->
- generateSequenceOfFractions(-10000f..10000f, step = 0.01f)
+ generateSequenceOfFractions(-2000f..2000f, step = 0.01f)
.map{ Pair(table, it) }
}
.forEach { (table, sp) ->
diff --git a/core/tests/coretests/src/android/content/res/FontScaleConverterTest.kt b/core/tests/coretests/src/android/content/res/FontScaleConverterTest.kt
index e9f850e..bfa8c9a 100644
--- a/core/tests/coretests/src/android/content/res/FontScaleConverterTest.kt
+++ b/core/tests/coretests/src/android/content/res/FontScaleConverterTest.kt
@@ -16,11 +16,13 @@
package android.content.res
+import android.platform.test.annotations.Presubmit
import androidx.test.ext.junit.runners.AndroidJUnit4
import com.google.common.truth.Truth.assertWithMessage
import org.junit.Test
import org.junit.runner.RunWith
+@Presubmit
@RunWith(AndroidJUnit4::class)
class FontScaleConverterTest {
diff --git a/core/tests/coretests/src/android/hardware/camera2/OWNERS b/core/tests/coretests/src/android/hardware/camera2/OWNERS
new file mode 100644
index 0000000..f48a95c
--- /dev/null
+++ b/core/tests/coretests/src/android/hardware/camera2/OWNERS
@@ -0,0 +1 @@
+include platform/frameworks/av:/camera/OWNERS
diff --git a/core/tests/coretests/src/android/hardware/camera2/impl/CaptureMetadataNativeTest.java b/core/tests/coretests/src/android/hardware/camera2/impl/CaptureMetadataNativeTest.java
new file mode 100644
index 0000000..a38c040
--- /dev/null
+++ b/core/tests/coretests/src/android/hardware/camera2/impl/CaptureMetadataNativeTest.java
@@ -0,0 +1,55 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.camera2.impl;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import android.hardware.camera2.CaptureResult;
+import android.hardware.camera2.params.LensShadingMap;
+import android.util.Size;
+
+import androidx.test.filters.SmallTest;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+
+import java.util.Arrays;
+
+@SmallTest
+@RunWith(JUnit4.class)
+/** Tests for {@link CameraMetadataNative} class. */
+public class CaptureMetadataNativeTest {
+
+ @Test
+ public void setLensShadingMap() {
+ final Size s = new Size(10, 10);
+ // 4 x rows x columns
+ final float[] elements = new float[400];
+ Arrays.fill(elements, 42);
+
+ final LensShadingMap lensShadingMap =
+ new LensShadingMap(elements, s.getHeight(), s.getWidth());
+ CameraMetadataNative captureResults = new CameraMetadataNative();
+ captureResults.set(CaptureResult.STATISTICS_LENS_SHADING_CORRECTION_MAP, lensShadingMap);
+
+ final LensShadingMap output =
+ captureResults.get(CaptureResult.STATISTICS_LENS_SHADING_CORRECTION_MAP);
+
+ assertThat(output).isEqualTo(lensShadingMap);
+ }
+}
diff --git a/core/tests/coretests/src/android/util/TypedValueTest.kt b/core/tests/coretests/src/android/util/TypedValueTest.kt
index b020c38..af01447 100644
--- a/core/tests/coretests/src/android/util/TypedValueTest.kt
+++ b/core/tests/coretests/src/android/util/TypedValueTest.kt
@@ -17,6 +17,7 @@
package android.util
import android.content.res.FontScaleConverterFactory
+import android.platform.test.annotations.Presubmit
import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.LargeTest
import androidx.test.filters.SmallTest
@@ -30,6 +31,7 @@
import kotlin.math.min
import kotlin.math.roundToInt
+@Presubmit
@RunWith(AndroidJUnit4::class)
class TypedValueTest {
@LargeTest
@@ -223,7 +225,6 @@
metrics.scaledDensity = 0f
listOf(
- TypedValue.COMPLEX_UNIT_PX,
TypedValue.COMPLEX_UNIT_DIP,
TypedValue.COMPLEX_UNIT_SP,
TypedValue.COMPLEX_UNIT_PT,
@@ -257,8 +258,7 @@
TypedValue.COMPLEX_UNIT_MM
)
.forEach { dimenType ->
- // Test for every integer value in the range...
- for (i: Int in -(1 shl 23) until (1 shl 23)) {
+ for (i: Int in -10000 until 10000) {
assertRoundTripIsEqual(i.toFloat(), dimenType, metrics)
assertRoundTripIsEqual(i - .1f, dimenType, metrics)
assertRoundTripIsEqual(i + .5f, dimenType, metrics)
diff --git a/core/tests/coretests/src/android/view/WindowInfoTest.java b/core/tests/coretests/src/android/view/WindowInfoTest.java
index f9e3f43..d927f06 100644
--- a/core/tests/coretests/src/android/view/WindowInfoTest.java
+++ b/core/tests/coretests/src/android/view/WindowInfoTest.java
@@ -28,6 +28,7 @@
import android.app.ActivityTaskManager;
import android.graphics.Matrix;
import android.os.IBinder;
+import android.os.LocaleList;
import android.os.Parcel;
import android.platform.test.annotations.Presubmit;
import android.text.TextUtils;
@@ -41,6 +42,7 @@
import java.util.ArrayList;
import java.util.Arrays;
+import java.util.Locale;
/**
* Class for testing {@link WindowInfo}.
@@ -48,6 +50,7 @@
@Presubmit
@RunWith(AndroidJUnit4.class)
public class WindowInfoTest {
+ private static final LocaleList TEST_LOCALES = new LocaleList(Locale.ROOT);
@SmallTest
@Test
@@ -129,6 +132,7 @@
assertTrue(windowinfo.regionInScreen.isEmpty());
assertEquals(windowinfo.mTransformMatrix.length, 9);
assertTrue(windowinfo.mMagnificationSpec.isNop());
+ assertEquals(windowinfo.locales, LocaleList.getEmptyLocaleList());
}
private boolean areWindowsEqual(WindowInfo w1, WindowInfo w2) {
@@ -141,6 +145,7 @@
equality &= w1.mMagnificationSpec.equals(w2.mMagnificationSpec);
equality &= Arrays.equals(w1.mTransformMatrix, w2.mTransformMatrix);
equality &= TextUtils.equals(w1.title, w2.title);
+ equality &= w1.locales.equals(w2.locales);
return equality;
}
@@ -164,5 +169,6 @@
windowInfo.mMagnificationSpec.offsetX = 100f;
windowInfo.mMagnificationSpec.offsetY = 200f;
Matrix.IDENTITY_MATRIX.getValues(windowInfo.mTransformMatrix);
+ windowInfo.locales = TEST_LOCALES;
}
}
diff --git a/core/tests/coretests/src/android/view/accessibility/AccessibilityWindowAttributesTest.java b/core/tests/coretests/src/android/view/accessibility/AccessibilityWindowAttributesTest.java
index a6abee5..8d1c2e3 100644
--- a/core/tests/coretests/src/android/view/accessibility/AccessibilityWindowAttributesTest.java
+++ b/core/tests/coretests/src/android/view/accessibility/AccessibilityWindowAttributesTest.java
@@ -20,6 +20,7 @@
import static org.junit.Assert.assertNotEquals;
import static org.junit.Assert.assertNotSame;
+import android.os.LocaleList;
import android.os.Parcel;
import android.platform.test.annotations.Presubmit;
import android.view.WindowManager;
@@ -30,6 +31,8 @@
import org.junit.Test;
import org.junit.runner.RunWith;
+import java.util.Locale;
+
/**
* Class for testing {@link AccessibilityWindowAttributes}.
*/
@@ -37,11 +40,13 @@
@RunWith(AndroidJUnit4.class)
public class AccessibilityWindowAttributesTest {
private static final String TEST_WINDOW_TITLE = "test window title";
+ private static final LocaleList TEST_LOCALES = new LocaleList(Locale.ROOT);
@SmallTest
@Test
public void testParceling() {
- final AccessibilityWindowAttributes windowAttributes = createInstance(TEST_WINDOW_TITLE);
+ final AccessibilityWindowAttributes windowAttributes = createInstance(
+ TEST_WINDOW_TITLE, TEST_LOCALES);
Parcel parcel = Parcel.obtain();
windowAttributes.writeToParcel(parcel, 0);
parcel.setDataPosition(0);
@@ -56,14 +61,21 @@
@SmallTest
@Test
public void testNonequality() {
- final AccessibilityWindowAttributes windowAttributes = createInstance(null);
- final AccessibilityWindowAttributes windowAttributes2 = createInstance(TEST_WINDOW_TITLE);
+ final AccessibilityWindowAttributes windowAttributes = createInstance(
+ null, TEST_LOCALES);
+ final AccessibilityWindowAttributes windowAttributes1 = createInstance(
+ TEST_WINDOW_TITLE, TEST_LOCALES);
+ final AccessibilityWindowAttributes windowAttributes2 = createInstance(
+ TEST_WINDOW_TITLE, null);
+ assertNotEquals(windowAttributes, windowAttributes1);
assertNotEquals(windowAttributes, windowAttributes2);
+ assertNotEquals(windowAttributes1, windowAttributes2);
}
- private static AccessibilityWindowAttributes createInstance(String windowTitle) {
+ private static AccessibilityWindowAttributes createInstance(
+ String windowTitle, LocaleList locales) {
final WindowManager.LayoutParams layoutParams = new WindowManager.LayoutParams();
layoutParams.accessibilityTitle = windowTitle;
- return new AccessibilityWindowAttributes(layoutParams);
+ return new AccessibilityWindowAttributes(layoutParams, locales);
}
}
diff --git a/core/tests/coretests/src/android/view/autofill/AutofillFeatureFlagsTest.java b/core/tests/coretests/src/android/view/autofill/AutofillFeatureFlagsTest.java
new file mode 100644
index 0000000..e03b722
--- /dev/null
+++ b/core/tests/coretests/src/android/view/autofill/AutofillFeatureFlagsTest.java
@@ -0,0 +1,94 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.view.autofill;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import android.provider.DeviceConfig;
+
+import androidx.test.ext.junit.runners.AndroidJUnit4;
+import androidx.test.filters.SmallTest;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+/**
+ * Tests for {@link AutofillFeatureFlags}
+ *
+ * run: atest FrameworksCoreTests:android.view.autofill.AutofillFeatureFlagsTest
+ */
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class AutofillFeatureFlagsTest {
+
+ @Test
+ public void testGetFillDialogEnabledHintsEmpty() {
+ setFillDialogHints("");
+ String[] fillDialogHints = AutofillFeatureFlags.getFillDialogEnabledHints();
+ assertThat(fillDialogHints).isEmpty();
+ }
+
+ @Test
+ public void testGetFillDialogEnabledHintsTwoValues() {
+ setFillDialogHints("password:creditCardNumber");
+ String[] fillDialogHints = AutofillFeatureFlags.getFillDialogEnabledHints();
+ assertThat(fillDialogHints.length).isEqualTo(2);
+ assertThat(fillDialogHints[0]).isEqualTo("password");
+ assertThat(fillDialogHints[1]).isEqualTo("creditCardNumber");
+ }
+
+ @Test
+ public void testIsCredentialManagerEnabled() {
+ setCredentialManagerEnabled(false);
+ assertThat(AutofillFeatureFlags.isCredentialManagerEnabled()).isFalse();
+ setCredentialManagerEnabled(true);
+ assertThat(AutofillFeatureFlags.isCredentialManagerEnabled()).isTrue();
+ }
+
+ @Test
+ public void testShouldIgnoreCredentialManagerViews() {
+ setCredentialManagerEnabled(false);
+ setIgnoreCredentialManagerViews(true);
+ // Overall feature is disabled, so we shouldn't ignore views.
+ assertThat(AutofillFeatureFlags.shouldIgnoreCredentialViews()).isFalse();
+ setCredentialManagerEnabled(true);
+ assertThat(AutofillFeatureFlags.shouldIgnoreCredentialViews()).isTrue();
+ }
+
+ private static void setFillDialogHints(String value) {
+ setDeviceConfig(
+ AutofillFeatureFlags.DEVICE_CONFIG_AUTOFILL_DIALOG_HINTS,
+ value);
+ }
+
+ private static void setCredentialManagerEnabled(boolean value) {
+ setDeviceConfig(
+ AutofillFeatureFlags.DEVICE_CONFIG_AUTOFILL_CREDENTIAL_MANAGER_ENABLED,
+ String.valueOf(value));
+ }
+
+ private static void setIgnoreCredentialManagerViews(boolean value) {
+ setDeviceConfig(
+ AutofillFeatureFlags.DEVICE_CONFIG_AUTOFILL_CREDENTIAL_MANAGER_IGNORE_VIEWS,
+ String.valueOf(value));
+ }
+
+ private static void setDeviceConfig(String key, String value) {
+ DeviceConfig.setProperty(
+ DeviceConfig.NAMESPACE_AUTOFILL, key, value, /* makeDefault */ false);
+ }
+}
diff --git a/core/tests/coretests/src/com/android/internal/accessibility/AccessibilityShortcutChooserActivityTest.java b/core/tests/coretests/src/com/android/internal/accessibility/AccessibilityShortcutChooserActivityTest.java
index 7287579..973b904 100644
--- a/core/tests/coretests/src/com/android/internal/accessibility/AccessibilityShortcutChooserActivityTest.java
+++ b/core/tests/coretests/src/com/android/internal/accessibility/AccessibilityShortcutChooserActivityTest.java
@@ -20,16 +20,19 @@
import static androidx.test.espresso.action.ViewActions.click;
import static androidx.test.espresso.action.ViewActions.doubleClick;
import static androidx.test.espresso.action.ViewActions.scrollTo;
+import static androidx.test.espresso.action.ViewActions.swipeUp;
import static androidx.test.espresso.assertion.ViewAssertions.doesNotExist;
import static androidx.test.espresso.assertion.ViewAssertions.matches;
import static androidx.test.espresso.matcher.RootMatchers.isDialog;
import static androidx.test.espresso.matcher.ViewMatchers.isDisplayed;
+import static androidx.test.espresso.matcher.ViewMatchers.withClassName;
import static androidx.test.espresso.matcher.ViewMatchers.withId;
import static androidx.test.espresso.matcher.ViewMatchers.withText;
+import static org.hamcrest.Matchers.allOf;
+import static org.hamcrest.Matchers.endsWith;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyInt;
-import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
import android.accessibilityservice.AccessibilityServiceInfo;
@@ -39,7 +42,6 @@
import android.content.pm.PackageManager;
import android.content.pm.ResolveInfo;
import android.content.pm.ServiceInfo;
-import android.os.Bundle;
import android.os.Handler;
import android.view.accessibility.AccessibilityManager;
import android.view.accessibility.IAccessibilityManager;
@@ -52,11 +54,12 @@
import com.android.internal.R;
import com.android.internal.accessibility.dialog.AccessibilityShortcutChooserActivity;
-import org.junit.Before;
+import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
-import org.mockito.MockitoAnnotations;
+import org.mockito.junit.MockitoJUnit;
+import org.mockito.junit.MockitoRule;
import java.util.Collections;
@@ -65,57 +68,93 @@
*/
@RunWith(AndroidJUnit4.class)
public class AccessibilityShortcutChooserActivityTest {
+ private static final String ONE_HANDED_MODE = "One-Handed mode";
private static final String TEST_LABEL = "TEST_LABEL";
- private static final Context sContext =
- InstrumentationRegistry.getInstrumentation().getContext();
- private ActivityScenario<TestAccessibilityShortcutChooserActivity> mScenario;
- private static IAccessibilityManager sAccessibilityManagerService;
+ private static final ComponentName TEST_COMPONENT_NAME = new ComponentName("package", "class");
+ @Rule
+ public final MockitoRule mMockitoRule = MockitoJUnit.rule();
@Mock
private AccessibilityServiceInfo mAccessibilityServiceInfo;
-
@Mock
private ResolveInfo mResolveInfo;
-
@Mock
private ServiceInfo mServiceInfo;
-
@Mock
private ApplicationInfo mApplicationInfo;
-
- @Before
- public void setUp() throws Exception {
- MockitoAnnotations.initMocks(this);
- sAccessibilityManagerService = mock(IAccessibilityManager.class);
-
- when(mAccessibilityServiceInfo.getResolveInfo()).thenReturn(mResolveInfo);
- mResolveInfo.serviceInfo = mServiceInfo;
- mServiceInfo.applicationInfo = mApplicationInfo;
- when(mResolveInfo.loadLabel(any(PackageManager.class))).thenReturn(TEST_LABEL);
- when(mAccessibilityServiceInfo.getComponentName()).thenReturn(
- new ComponentName("package", "class"));
- when(sAccessibilityManagerService.getInstalledAccessibilityServiceList(
- anyInt())).thenReturn(Collections.singletonList(mAccessibilityServiceInfo));
-
- mScenario = ActivityScenario.launch(TestAccessibilityShortcutChooserActivity.class);
- }
+ @Mock
+ private IAccessibilityManager mAccessibilityManagerService;
@Test
- public void doubleClickServiceTargetAndClickDenyButton_permissionDialogDoesNotExist() {
- mScenario.moveToState(Lifecycle.State.CREATED);
- mScenario.moveToState(Lifecycle.State.STARTED);
- mScenario.moveToState(Lifecycle.State.RESUMED);
+ public void doubleClickTestServiceAndClickDenyButton_permissionDialogDoesNotExist()
+ throws Exception {
+ configureTestService();
+ final ActivityScenario<TestAccessibilityShortcutChooserActivity> scenario =
+ ActivityScenario.launch(TestAccessibilityShortcutChooserActivity.class);
+ scenario.moveToState(Lifecycle.State.CREATED);
+ scenario.moveToState(Lifecycle.State.STARTED);
+ scenario.moveToState(Lifecycle.State.RESUMED);
+
onView(withText(R.string.accessibility_select_shortcut_menu_title)).inRoot(
isDialog()).check(matches(isDisplayed()));
onView(withText(R.string.edit_accessibility_shortcut_menu_button)).perform(click());
-
onView(withText(TEST_LABEL)).perform(scrollTo(), doubleClick());
onView(withId(R.id.accessibility_permission_enable_deny_button)).perform(scrollTo(),
click());
onView(withId(R.id.accessibility_permissionDialog_title)).inRoot(isDialog()).check(
doesNotExist());
- mScenario.moveToState(Lifecycle.State.DESTROYED);
+ scenario.moveToState(Lifecycle.State.DESTROYED);
+ }
+
+ @Test
+ public void popEditShortcutMenuList_oneHandedModeEnabled_shouldBeInListView() {
+ TestUtils.setOneHandedModeEnabled(this, /* enabled= */ true);
+ final ActivityScenario<TestAccessibilityShortcutChooserActivity> scenario =
+ ActivityScenario.launch(TestAccessibilityShortcutChooserActivity.class);
+ scenario.moveToState(Lifecycle.State.CREATED);
+ scenario.moveToState(Lifecycle.State.STARTED);
+ scenario.moveToState(Lifecycle.State.RESUMED);
+
+ onView(withText(R.string.accessibility_select_shortcut_menu_title)).inRoot(
+ isDialog()).check(matches(isDisplayed()));
+ onView(withText(R.string.edit_accessibility_shortcut_menu_button)).perform(click());
+ onView(allOf(withClassName(endsWith("ListView")), isDisplayed())).perform(swipeUp());
+ InstrumentationRegistry.getInstrumentation().waitForIdleSync();
+
+ onView(withText(ONE_HANDED_MODE)).inRoot(isDialog()).check(matches(isDisplayed()));
+ scenario.moveToState(Lifecycle.State.DESTROYED);
+ }
+
+ @Test
+ public void popEditShortcutMenuList_oneHandedModeDisabled_shouldNotBeInListView() {
+ TestUtils.setOneHandedModeEnabled(this, /* enabled= */ false);
+ final ActivityScenario<TestAccessibilityShortcutChooserActivity> scenario =
+ ActivityScenario.launch(TestAccessibilityShortcutChooserActivity.class);
+ scenario.moveToState(Lifecycle.State.CREATED);
+ scenario.moveToState(Lifecycle.State.STARTED);
+ scenario.moveToState(Lifecycle.State.RESUMED);
+
+ onView(withText(R.string.accessibility_select_shortcut_menu_title)).inRoot(
+ isDialog()).check(matches(isDisplayed()));
+ onView(withText(R.string.edit_accessibility_shortcut_menu_button)).perform(click());
+ onView(allOf(withClassName(endsWith("ListView")), isDisplayed())).perform(swipeUp());
+ InstrumentationRegistry.getInstrumentation().waitForIdleSync();
+
+ onView(withText(ONE_HANDED_MODE)).inRoot(isDialog()).check(doesNotExist());
+ scenario.moveToState(Lifecycle.State.DESTROYED);
+ }
+
+ private void configureTestService() throws Exception {
+ when(mAccessibilityServiceInfo.getResolveInfo()).thenReturn(mResolveInfo);
+ mResolveInfo.serviceInfo = mServiceInfo;
+ mServiceInfo.applicationInfo = mApplicationInfo;
+ when(mResolveInfo.loadLabel(any(PackageManager.class))).thenReturn(TEST_LABEL);
+ when(mAccessibilityServiceInfo.getComponentName()).thenReturn(TEST_COMPONENT_NAME);
+ when(mAccessibilityManagerService.getInstalledAccessibilityServiceList(
+ anyInt())).thenReturn(Collections.singletonList(mAccessibilityServiceInfo));
+
+ TestAccessibilityShortcutChooserActivity.setupForTesting(mAccessibilityManagerService);
}
/**
@@ -123,19 +162,18 @@
*/
public static class TestAccessibilityShortcutChooserActivity extends
AccessibilityShortcutChooserActivity {
- private AccessibilityManager mAccessibilityManager;
+ private static IAccessibilityManager sAccessibilityManagerService;
- @Override
- protected void onCreate(Bundle savedInstanceState) {
- mAccessibilityManager = new AccessibilityManager(sContext, new Handler(getMainLooper()),
- sAccessibilityManagerService, /* userId= */ 0, /* serviceConnect= */ true);
- super.onCreate(savedInstanceState);
+ public static void setupForTesting(IAccessibilityManager accessibilityManagerService) {
+ sAccessibilityManagerService = accessibilityManagerService;
}
@Override
public Object getSystemService(String name) {
- if (Context.ACCESSIBILITY_SERVICE.equals(name)) {
- return mAccessibilityManager;
+ if (Context.ACCESSIBILITY_SERVICE.equals(name)
+ && sAccessibilityManagerService != null) {
+ return new AccessibilityManager(this, new Handler(getMainLooper()),
+ sAccessibilityManagerService, /* userId= */ 0, /* serviceConnect= */ true);
}
return super.getSystemService(name);
diff --git a/core/tests/coretests/src/com/android/internal/accessibility/AccessibilityShortcutControllerTest.java b/core/tests/coretests/src/com/android/internal/accessibility/AccessibilityShortcutControllerTest.java
index a68c392..9763679 100644
--- a/core/tests/coretests/src/com/android/internal/accessibility/AccessibilityShortcutControllerTest.java
+++ b/core/tests/coretests/src/com/android/internal/accessibility/AccessibilityShortcutControllerTest.java
@@ -208,6 +208,17 @@
when(mAlertDialog.getWindow()).thenReturn(window);
when(mTextToSpeech.getVoice()).thenReturn(mVoice);
+
+ // Clears the sFrameworkShortcutFeaturesMap field which was not properly initialized
+ // during testing.
+ try {
+ Field field = AccessibilityShortcutController.class.getDeclaredField(
+ "sFrameworkShortcutFeaturesMap");
+ field.setAccessible(true);
+ field.set(window, null);
+ } catch (Exception e) {
+ throw new RuntimeException("Unable to set sFrameworkShortcutFeaturesMap", e);
+ }
}
@AfterClass
@@ -433,11 +444,10 @@
}
@Test
- public void getFrameworkFeatureMap_shouldBeNonNullAndUnmodifiable() {
- Map<ComponentName, AccessibilityShortcutController.FrameworkFeatureInfo>
+ public void getFrameworkFeatureMap_shouldBeUnmodifiable() {
+ final Map<ComponentName, AccessibilityShortcutController.FrameworkFeatureInfo>
frameworkFeatureMap =
AccessibilityShortcutController.getFrameworkShortcutFeaturesMap();
- assertTrue("Framework features not supported", frameworkFeatureMap.size() > 0);
try {
frameworkFeatureMap.clear();
@@ -448,19 +458,40 @@
}
@Test
- public void getFrameworkFeatureMap_containsExpectedKey() {
- Map<ComponentName, AccessibilityShortcutController.FrameworkFeatureInfo>
+ public void getFrameworkFeatureMap_containsExpectedDefaultKeys() {
+ final Map<ComponentName, AccessibilityShortcutController.FrameworkFeatureInfo>
frameworkFeatureMap =
AccessibilityShortcutController.getFrameworkShortcutFeaturesMap();
assertTrue(frameworkFeatureMap.containsKey(COLOR_INVERSION_COMPONENT_NAME));
assertTrue(frameworkFeatureMap.containsKey(DALTONIZER_COMPONENT_NAME));
- assertTrue(frameworkFeatureMap.containsKey(ONE_HANDED_COMPONENT_NAME));
assertTrue(frameworkFeatureMap.containsKey(REDUCE_BRIGHT_COLORS_COMPONENT_NAME));
assertTrue(frameworkFeatureMap.containsKey(ACCESSIBILITY_HEARING_AIDS_COMPONENT_NAME));
}
@Test
+ public void getFrameworkFeatureMap_oneHandedModeEnabled_containsExpectedKey() {
+ TestUtils.setOneHandedModeEnabled(this, /* enabled= */ true);
+
+ final Map<ComponentName, AccessibilityShortcutController.FrameworkFeatureInfo>
+ frameworkFeatureMap =
+ AccessibilityShortcutController.getFrameworkShortcutFeaturesMap();
+
+ assertTrue(frameworkFeatureMap.containsKey(ONE_HANDED_COMPONENT_NAME));
+ }
+
+ @Test
+ public void getFrameworkFeatureMap_oneHandedModeDisabled_containsExpectedKey() {
+ TestUtils.setOneHandedModeEnabled(this, /* enabled= */ false);
+
+ final Map<ComponentName, AccessibilityShortcutController.FrameworkFeatureInfo>
+ frameworkFeatureMap =
+ AccessibilityShortcutController.getFrameworkShortcutFeaturesMap();
+
+ assertFalse(frameworkFeatureMap.containsKey(ONE_HANDED_COMPONENT_NAME));
+ }
+
+ @Test
public void testOnAccessibilityShortcut_forServiceWithNoSummary_doesNotCrash()
throws Exception {
configureShortcutEnabled(ENABLED_EXCEPT_LOCK_SCREEN);
diff --git a/core/tests/coretests/src/com/android/internal/accessibility/TestUtils.java b/core/tests/coretests/src/com/android/internal/accessibility/TestUtils.java
new file mode 100644
index 0000000..ff014ad
--- /dev/null
+++ b/core/tests/coretests/src/com/android/internal/accessibility/TestUtils.java
@@ -0,0 +1,41 @@
+/*
+ * 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 com.android.internal.accessibility;
+
+import com.android.internal.os.RoSystemProperties;
+
+import java.lang.reflect.Field;
+
+/**
+ * Test utility methods.
+ */
+public class TestUtils {
+
+ /**
+ * Sets the {@code enabled} of the given OneHandedMode flags to simulate device behavior.
+ */
+ public static void setOneHandedModeEnabled(Object obj, boolean enabled) {
+ try {
+ final Field field = RoSystemProperties.class.getDeclaredField(
+ "SUPPORT_ONE_HANDED_MODE");
+ field.setAccessible(true);
+ field.setBoolean(obj, enabled);
+ } catch (ReflectiveOperationException e) {
+ throw new RuntimeException(e);
+ }
+ }
+}
diff --git a/data/etc/com.android.systemui.xml b/data/etc/com.android.systemui.xml
index e0e13f5..0aad0a8 100644
--- a/data/etc/com.android.systemui.xml
+++ b/data/etc/com.android.systemui.xml
@@ -24,6 +24,7 @@
<permission name="android.permission.CHANGE_COMPONENT_ENABLED_STATE"/>
<permission name="android.permission.CHANGE_DEVICE_IDLE_TEMP_WHITELIST"/>
<permission name="android.permission.CHANGE_OVERLAY_PACKAGES"/>
+ <permission name="android.permission.COMPONENT_OPTION_INTERACTIVE"/>
<permission name="android.permission.CONTROL_KEYGUARD_SECURE_NOTIFICATIONS"/>
<permission name="android.permission.CONTROL_REMOTE_APP_TRANSITION_ANIMATIONS"/>
<permission name="android.permission.CONTROL_VPN"/>
@@ -82,5 +83,6 @@
<permission name="android.permission.READ_SAFETY_CENTER_STATUS" />
<permission name="android.permission.SET_UNRESTRICTED_KEEP_CLEAR_AREAS" />
<permission name="android.permission.READ_SEARCH_INDEXABLES" />
+ <permission name="android.permission.ACCESS_AMBIENT_CONTEXT_EVENT"/>
</privapp-permissions>
</permissions>
diff --git a/data/etc/privapp-permissions-platform.xml b/data/etc/privapp-permissions-platform.xml
index 0210696..5040a86 100644
--- a/data/etc/privapp-permissions-platform.xml
+++ b/data/etc/privapp-permissions-platform.xml
@@ -498,6 +498,10 @@
<permission name="android.permission.CAPTURE_TUNER_AUDIO_INPUT" />
<permission name="android.permission.CAPTURE_VOICE_COMMUNICATION_OUTPUT" />
<permission name="android.permission.MODIFY_CELL_BROADCASTS" />
+ <!-- Permission required for CTS test - CtsBroadcastRadioTestCases -->
+ <permission name="android.permission.ACCESS_BROADCAST_RADIO"/>
+ <!-- Permission required for CTS test - CtsAmbientContextServiceTestCases -->
+ <permission name="android.permission.ACCESS_AMBIENT_CONTEXT_EVENT"/>
</privapp-permissions>
<privapp-permissions package="com.android.statementservice">
diff --git a/data/keyboards/Generic.kl b/data/keyboards/Generic.kl
index 0f8616d..247d484 100644
--- a/data/keyboards/Generic.kl
+++ b/data/keyboards/Generic.kl
@@ -249,6 +249,7 @@
key 228 KEYBOARD_BACKLIGHT_TOGGLE
key 229 KEYBOARD_BACKLIGHT_DOWN
key 230 KEYBOARD_BACKLIGHT_UP
+key 248 MUTE
key 256 BUTTON_1
key 257 BUTTON_2
diff --git a/graphics/java/android/graphics/HardwareRenderer.java b/graphics/java/android/graphics/HardwareRenderer.java
index c7c97e0..89d6304 100644
--- a/graphics/java/android/graphics/HardwareRenderer.java
+++ b/graphics/java/android/graphics/HardwareRenderer.java
@@ -1334,6 +1334,8 @@
final OverlayProperties overlayProperties = defaultDisplay.getOverlaySupport();
boolean supportFp16ForHdr = overlayProperties != null
? overlayProperties.supportFp16ForHdr() : false;
+ boolean supportMixedColorSpaces = overlayProperties != null
+ ? overlayProperties.supportMixedColorSpaces() : false;
for (int i = 0; i < allDisplays.length; i++) {
final Display display = allDisplays[i];
@@ -1361,7 +1363,7 @@
nInitDisplayInfo(largestWidth, largestHeight, defaultDisplay.getRefreshRate(),
wideColorDataspace, defaultDisplay.getAppVsyncOffsetNanos(),
defaultDisplay.getPresentationDeadlineNanos(),
- supportFp16ForHdr);
+ supportFp16ForHdr, supportMixedColorSpaces);
mDisplayInitialized = true;
}
@@ -1542,7 +1544,7 @@
private static native void nInitDisplayInfo(int width, int height, float refreshRate,
int wideColorDataspace, long appVsyncOffsetNanos, long presentationDeadlineNanos,
- boolean supportsFp16ForHdr);
+ boolean supportsFp16ForHdr, boolean nInitDisplayInfo);
private static native void nSetDrawingEnabled(boolean drawingEnabled);
diff --git a/graphics/java/android/graphics/Paint.java b/graphics/java/android/graphics/Paint.java
index f0e496f..d35dcab 100644
--- a/graphics/java/android/graphics/Paint.java
+++ b/graphics/java/android/graphics/Paint.java
@@ -3151,10 +3151,10 @@
* @see #getRunAdvance(char[], int, int, int, int, boolean, int) for more details.
*
* @param text the text to measure. Cannot be null.
- * @param start the index of the start of the range to measure
- * @param end the index + 1 of the end of the range to measure
- * @param contextStart the index of the start of the shaping context
- * @param contextEnd the index + 1 of the end of the shaping context
+ * @param start the start index of the range to measure, inclusive
+ * @param end the end index of the range to measure, exclusive
+ * @param contextStart the start index of the shaping context, inclusive
+ * @param contextEnd the end index of the shaping context, exclusive
* @param isRtl whether the run is in RTL direction
* @param offset index of caret position
* @param advances the array that receives the computed character advances
diff --git a/graphics/java/android/graphics/drawable/LottieDrawable.java b/graphics/java/android/graphics/drawable/LottieDrawable.java
new file mode 100644
index 0000000..c1f1b50
--- /dev/null
+++ b/graphics/java/android/graphics/drawable/LottieDrawable.java
@@ -0,0 +1,151 @@
+/*
+ * 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 android.graphics.drawable;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.annotation.SuppressLint;
+import android.graphics.Canvas;
+import android.graphics.ColorFilter;
+import android.graphics.PixelFormat;
+
+import dalvik.annotation.optimization.FastNative;
+
+import libcore.util.NativeAllocationRegistry;
+
+import java.io.IOException;
+
+/**
+ * {@link Drawable} for drawing Lottie files.
+ *
+ * <p>The framework handles decoding subsequent frames in another thread and
+ * updating when necessary. The drawable will only animate while it is being
+ * displayed.</p>
+ *
+ * @hide
+ */
+@SuppressLint("NotCloseable")
+public class LottieDrawable extends Drawable implements Animatable {
+ private long mNativePtr;
+
+ /**
+ * Create an animation from the provided JSON string
+ * @hide
+ */
+ private LottieDrawable(@NonNull String animationJson) throws IOException {
+ mNativePtr = nCreate(animationJson);
+ if (mNativePtr == 0) {
+ throw new IOException("could not make LottieDrawable from json");
+ }
+
+ final long nativeSize = nNativeByteSize(mNativePtr);
+ NativeAllocationRegistry registry = new NativeAllocationRegistry(
+ LottieDrawable.class.getClassLoader(), nGetNativeFinalizer(), nativeSize);
+ registry.registerNativeAllocation(this, mNativePtr);
+ }
+
+ /**
+ * Factory for LottieDrawable, throws IOException if native Skottie Builder fails to parse
+ */
+ public static LottieDrawable makeLottieDrawable(@NonNull String animationJson)
+ throws IOException {
+ return new LottieDrawable(animationJson);
+ }
+
+
+
+ /**
+ * Draw the current frame to the Canvas.
+ * @hide
+ */
+ @Override
+ public void draw(@NonNull Canvas canvas) {
+ if (mNativePtr == 0) {
+ throw new IllegalStateException("called draw on empty LottieDrawable");
+ }
+
+ nDraw(mNativePtr, canvas.getNativeCanvasWrapper());
+ }
+
+ /**
+ * Start the animation. Needs to be called before draw calls.
+ * @hide
+ */
+ @Override
+ public void start() {
+ if (mNativePtr == 0) {
+ throw new IllegalStateException("called start on empty LottieDrawable");
+ }
+
+ if (nStart(mNativePtr)) {
+ invalidateSelf();
+ }
+ }
+
+ /**
+ * Stops the animation playback. Does not release anything.
+ * @hide
+ */
+ @Override
+ public void stop() {
+ if (mNativePtr == 0) {
+ throw new IllegalStateException("called stop on empty LottieDrawable");
+ }
+ nStop(mNativePtr);
+ }
+
+ /**
+ * Return whether the animation is currently running.
+ */
+ @Override
+ public boolean isRunning() {
+ if (mNativePtr == 0) {
+ throw new IllegalStateException("called isRunning on empty LottieDrawable");
+ }
+ return nIsRunning(mNativePtr);
+ }
+
+ @Override
+ public int getOpacity() {
+ // We assume translucency to avoid checking each pixel.
+ return PixelFormat.TRANSLUCENT;
+ }
+
+ @Override
+ public void setAlpha(int alpha) {
+ //TODO
+ }
+
+ @Override
+ public void setColorFilter(@Nullable ColorFilter colorFilter) {
+ //TODO
+ }
+
+ private static native long nCreate(String json);
+ private static native void nDraw(long nativeInstance, long nativeCanvas);
+ @FastNative
+ private static native long nGetNativeFinalizer();
+ @FastNative
+ private static native long nNativeByteSize(long nativeInstance);
+ @FastNative
+ private static native boolean nIsRunning(long nativeInstance);
+ @FastNative
+ private static native boolean nStart(long nativeInstance);
+ @FastNative
+ private static native boolean nStop(long nativeInstance);
+
+}
diff --git a/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/JetpackTaskFragmentOrganizer.java b/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/JetpackTaskFragmentOrganizer.java
index 87fa63d..ee8ec1d 100644
--- a/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/JetpackTaskFragmentOrganizer.java
+++ b/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/JetpackTaskFragmentOrganizer.java
@@ -191,10 +191,25 @@
*/
void createTaskFragment(@NonNull WindowContainerTransaction wct, @NonNull IBinder fragmentToken,
@NonNull IBinder ownerToken, @NonNull Rect bounds, @WindowingMode int windowingMode) {
+ createTaskFragment(wct, fragmentToken, ownerToken, bounds, windowingMode,
+ null /* pairedActivityToken */);
+ }
+
+ /**
+ * @param ownerToken The token of the activity that creates this task fragment. It does not
+ * have to be a child of this task fragment, but must belong to the same task.
+ * @param pairedActivityToken The token of the activity that will be reparented to this task
+ * fragment. When it is not {@code null}, the task fragment will be
+ * positioned right above it.
+ */
+ void createTaskFragment(@NonNull WindowContainerTransaction wct, @NonNull IBinder fragmentToken,
+ @NonNull IBinder ownerToken, @NonNull Rect bounds, @WindowingMode int windowingMode,
+ @Nullable IBinder pairedActivityToken) {
final TaskFragmentCreationParams fragmentOptions = new TaskFragmentCreationParams.Builder(
getOrganizerToken(), fragmentToken, ownerToken)
.setInitialBounds(bounds)
.setWindowingMode(windowingMode)
+ .setPairedActivityToken(pairedActivityToken)
.build();
createTaskFragment(wct, fragmentOptions);
}
@@ -216,12 +231,19 @@
private void createTaskFragmentAndReparentActivity(@NonNull WindowContainerTransaction wct,
@NonNull IBinder fragmentToken, @NonNull IBinder ownerToken, @NonNull Rect bounds,
@WindowingMode int windowingMode, @NonNull Activity activity) {
- createTaskFragment(wct, fragmentToken, ownerToken, bounds, windowingMode);
- wct.reparentActivityToTaskFragment(fragmentToken, activity.getActivityToken());
+ final IBinder reparentActivityToken = activity.getActivityToken();
+ createTaskFragment(wct, fragmentToken, ownerToken, bounds, windowingMode,
+ reparentActivityToken);
+ wct.reparentActivityToTaskFragment(fragmentToken, reparentActivityToken);
}
void setAdjacentTaskFragments(@NonNull WindowContainerTransaction wct,
@NonNull IBinder primary, @Nullable IBinder secondary, @Nullable SplitRule splitRule) {
+ if (secondary == null) {
+ wct.clearAdjacentTaskFragments(primary);
+ return;
+ }
+
WindowContainerTransaction.TaskFragmentAdjacentParams adjacentParams = null;
final boolean finishSecondaryWithPrimary =
splitRule != null && SplitContainer.shouldFinishSecondaryWithPrimary(splitRule);
@@ -293,16 +315,12 @@
OP_TYPE_SET_ANIMATION_PARAMS)
.setAnimationParams(animationParams)
.build();
- wct.setTaskFragmentOperation(fragmentToken, operation);
+ wct.addTaskFragmentOperation(fragmentToken, operation);
}
void deleteTaskFragment(@NonNull WindowContainerTransaction wct,
@NonNull IBinder fragmentToken) {
- if (!mFragmentInfos.containsKey(fragmentToken)) {
- throw new IllegalArgumentException(
- "Can't find an existing TaskFragment with fragmentToken=" + fragmentToken);
- }
- wct.deleteTaskFragment(mFragmentInfos.get(fragmentToken).getToken());
+ wct.deleteTaskFragment(fragmentToken);
}
void updateTaskFragmentInfo(@NonNull TaskFragmentInfo taskFragmentInfo) {
diff --git a/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/SplitController.java b/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/SplitController.java
index 8c4de70..b13c672 100644
--- a/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/SplitController.java
+++ b/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/SplitController.java
@@ -20,6 +20,8 @@
import static android.app.WindowConfiguration.WINDOWING_MODE_PINNED;
import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED;
import static android.view.Display.DEFAULT_DISPLAY;
+import static android.window.TaskFragmentOperation.OP_TYPE_REPARENT_ACTIVITY_TO_TASK_FRAGMENT;
+import static android.window.TaskFragmentOperation.OP_TYPE_START_ACTIVITY_IN_TASK_FRAGMENT;
import static android.window.TaskFragmentOrganizer.KEY_ERROR_CALLBACK_OP_TYPE;
import static android.window.TaskFragmentOrganizer.KEY_ERROR_CALLBACK_TASK_FRAGMENT_INFO;
import static android.window.TaskFragmentOrganizer.KEY_ERROR_CALLBACK_THROWABLE;
@@ -31,8 +33,6 @@
import static android.window.TaskFragmentTransaction.TYPE_TASK_FRAGMENT_INFO_CHANGED;
import static android.window.TaskFragmentTransaction.TYPE_TASK_FRAGMENT_PARENT_INFO_CHANGED;
import static android.window.TaskFragmentTransaction.TYPE_TASK_FRAGMENT_VANISHED;
-import static android.window.WindowContainerTransaction.HierarchyOp.HIERARCHY_OP_TYPE_REPARENT_ACTIVITY_TO_TASK_FRAGMENT;
-import static android.window.WindowContainerTransaction.HierarchyOp.HIERARCHY_OP_TYPE_START_ACTIVITY_IN_TASK_FRAGMENT;
import static androidx.window.extensions.embedding.SplitContainer.getFinishPrimaryWithSecondaryBehavior;
import static androidx.window.extensions.embedding.SplitContainer.getFinishSecondaryWithPrimaryBehavior;
@@ -67,6 +67,7 @@
import android.view.WindowMetrics;
import android.window.TaskFragmentAnimationParams;
import android.window.TaskFragmentInfo;
+import android.window.TaskFragmentOperation;
import android.window.TaskFragmentParentInfo;
import android.window.TaskFragmentTransaction;
import android.window.WindowContainerTransaction;
@@ -592,11 +593,11 @@
@GuardedBy("mLock")
void onTaskFragmentError(@NonNull WindowContainerTransaction wct,
@Nullable IBinder errorCallbackToken, @Nullable TaskFragmentInfo taskFragmentInfo,
- int opType, @NonNull Throwable exception) {
+ @TaskFragmentOperation.OperationType int opType, @NonNull Throwable exception) {
Log.e(TAG, "onTaskFragmentError=" + exception.getMessage());
switch (opType) {
- case HIERARCHY_OP_TYPE_START_ACTIVITY_IN_TASK_FRAGMENT:
- case HIERARCHY_OP_TYPE_REPARENT_ACTIVITY_TO_TASK_FRAGMENT: {
+ case OP_TYPE_START_ACTIVITY_IN_TASK_FRAGMENT:
+ case OP_TYPE_REPARENT_ACTIVITY_TO_TASK_FRAGMENT: {
final TaskFragmentContainer container;
if (taskFragmentInfo != null) {
container = getContainer(taskFragmentInfo.getFragmentToken());
@@ -1507,7 +1508,7 @@
* Returns the active split that has the provided containers as primary and secondary or as
* secondary and primary, if available.
*/
- @VisibleForTesting
+ @GuardedBy("mLock")
@Nullable
SplitContainer getActiveSplitForContainers(
@NonNull TaskFragmentContainer firstContainer,
diff --git a/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/SplitPresenter.java b/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/SplitPresenter.java
index 6f2fe80..85a00df 100644
--- a/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/SplitPresenter.java
+++ b/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/SplitPresenter.java
@@ -30,6 +30,7 @@
import android.graphics.Rect;
import android.os.Bundle;
import android.os.IBinder;
+import android.util.DisplayMetrics;
import android.util.LayoutDirection;
import android.util.Pair;
import android.util.Size;
@@ -268,10 +269,11 @@
container = mController.newContainer(activity, taskId);
final int windowingMode = mController.getTaskContainer(taskId)
.getWindowingModeForSplitTaskFragment(bounds);
- createTaskFragment(wct, container.getTaskFragmentToken(), activity.getActivityToken(),
- bounds, windowingMode);
+ final IBinder reparentActivityToken = activity.getActivityToken();
+ createTaskFragment(wct, container.getTaskFragmentToken(), reparentActivityToken,
+ bounds, windowingMode, reparentActivityToken);
wct.reparentActivityToTaskFragment(container.getTaskFragmentToken(),
- activity.getActivityToken());
+ reparentActivityToken);
} else {
resizeTaskFragmentIfRegistered(wct, container, bounds);
final int windowingMode = mController.getTaskContainer(taskId)
@@ -554,9 +556,9 @@
final Function<SplitAttributesCalculatorParams, SplitAttributes> calculator =
mController.getSplitAttributesCalculator();
final SplitAttributes defaultSplitAttributes = rule.getDefaultSplitAttributes();
- final boolean isDefaultMinSizeSatisfied = rule.checkParentMetrics(taskWindowMetrics);
+ final boolean areDefaultConstraintsSatisfied = rule.checkParentMetrics(taskWindowMetrics);
if (calculator == null) {
- if (!isDefaultMinSizeSatisfied) {
+ if (!areDefaultConstraintsSatisfied) {
return EXPAND_CONTAINERS_ATTRIBUTES;
}
return sanitizeSplitAttributes(taskProperties, defaultSplitAttributes,
@@ -566,8 +568,8 @@
.getCurrentWindowLayoutInfo(taskProperties.getDisplayId(),
taskConfiguration.windowConfiguration);
final SplitAttributesCalculatorParams params = new SplitAttributesCalculatorParams(
- taskWindowMetrics, taskConfiguration, defaultSplitAttributes,
- isDefaultMinSizeSatisfied, windowLayoutInfo, rule.getTag());
+ taskWindowMetrics, taskConfiguration, windowLayoutInfo, defaultSplitAttributes,
+ areDefaultConstraintsSatisfied, rule.getTag());
final SplitAttributes splitAttributes = calculator.apply(params);
return sanitizeSplitAttributes(taskProperties, splitAttributes, minDimensionsPair);
}
@@ -971,6 +973,7 @@
private static WindowMetrics getTaskWindowMetrics(@NonNull Configuration taskConfiguration) {
final Rect taskBounds = taskConfiguration.windowConfiguration.getBounds();
// TODO(b/190433398): Supply correct insets.
- return new WindowMetrics(taskBounds, WindowInsets.CONSUMED);
+ final float density = taskConfiguration.densityDpi * DisplayMetrics.DENSITY_DEFAULT_SCALE;
+ return new WindowMetrics(taskBounds, WindowInsets.CONSUMED, density);
}
}
diff --git a/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/TaskFragmentContainer.java b/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/TaskFragmentContainer.java
index 076856c..17814c6 100644
--- a/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/TaskFragmentContainer.java
+++ b/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/TaskFragmentContainer.java
@@ -141,12 +141,26 @@
mToken = new Binder("TaskFragmentContainer");
mTaskContainer = taskContainer;
if (pairedPrimaryContainer != null) {
+ // The TaskFragment will be positioned right above the paired container.
if (pairedPrimaryContainer.getTaskContainer() != taskContainer) {
throw new IllegalArgumentException(
"pairedPrimaryContainer must be in the same Task");
}
final int primaryIndex = taskContainer.mContainers.indexOf(pairedPrimaryContainer);
taskContainer.mContainers.add(primaryIndex + 1, this);
+ } else if (pendingAppearedActivity != null) {
+ // The TaskFragment will be positioned right above the pending appeared Activity. If any
+ // existing TaskFragment is empty with pending Intent, it is likely that the Activity of
+ // the pending Intent hasn't been created yet, so the new Activity should be below the
+ // empty TaskFragment.
+ int i = taskContainer.mContainers.size() - 1;
+ for (; i >= 0; i--) {
+ final TaskFragmentContainer container = taskContainer.mContainers.get(i);
+ if (!container.isEmpty() || container.getPendingAppearedIntent() == null) {
+ break;
+ }
+ }
+ taskContainer.mContainers.add(i + 1, this);
} else {
taskContainer.mContainers.add(this);
}
@@ -500,6 +514,8 @@
}
if (!shouldFinishDependent) {
+ // Always finish the placeholder when the primary is finished.
+ finishPlaceholderIfAny(wct, presenter);
return;
}
@@ -526,6 +542,28 @@
mActivitiesToFinishOnExit.clear();
}
+ @GuardedBy("mController.mLock")
+ private void finishPlaceholderIfAny(@NonNull WindowContainerTransaction wct,
+ @NonNull SplitPresenter presenter) {
+ final List<TaskFragmentContainer> containersToRemove = new ArrayList<>();
+ for (TaskFragmentContainer container : mContainersToFinishOnExit) {
+ if (container.mIsFinished) {
+ continue;
+ }
+ final SplitContainer splitContainer = mController.getActiveSplitForContainers(
+ this, container);
+ if (splitContainer != null && splitContainer.isPlaceholderContainer()
+ && splitContainer.getSecondaryContainer() == container) {
+ // Remove the placeholder secondary TaskFragment.
+ containersToRemove.add(container);
+ }
+ }
+ mContainersToFinishOnExit.removeAll(containersToRemove);
+ for (TaskFragmentContainer container : containersToRemove) {
+ container.finish(false /* shouldFinishDependent */, presenter, wct, mController);
+ }
+ }
+
boolean isFinished() {
return mIsFinished;
}
diff --git a/libs/WindowManager/Jetpack/tests/unittest/src/androidx/window/extensions/embedding/SplitControllerTest.java b/libs/WindowManager/Jetpack/tests/unittest/src/androidx/window/extensions/embedding/SplitControllerTest.java
index 0bf0bc8..a26311e 100644
--- a/libs/WindowManager/Jetpack/tests/unittest/src/androidx/window/extensions/embedding/SplitControllerTest.java
+++ b/libs/WindowManager/Jetpack/tests/unittest/src/androidx/window/extensions/embedding/SplitControllerTest.java
@@ -20,13 +20,13 @@
import static android.app.WindowConfiguration.WINDOWING_MODE_MULTI_WINDOW;
import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED;
import static android.view.Display.DEFAULT_DISPLAY;
+import static android.window.TaskFragmentOperation.OP_TYPE_CREATE_TASK_FRAGMENT;
import static android.window.TaskFragmentTransaction.TYPE_ACTIVITY_REPARENTED_TO_TASK;
import static android.window.TaskFragmentTransaction.TYPE_TASK_FRAGMENT_APPEARED;
import static android.window.TaskFragmentTransaction.TYPE_TASK_FRAGMENT_ERROR;
import static android.window.TaskFragmentTransaction.TYPE_TASK_FRAGMENT_INFO_CHANGED;
import static android.window.TaskFragmentTransaction.TYPE_TASK_FRAGMENT_PARENT_INFO_CHANGED;
import static android.window.TaskFragmentTransaction.TYPE_TASK_FRAGMENT_VANISHED;
-import static android.window.WindowContainerTransaction.HierarchyOp.HIERARCHY_OP_TYPE_CREATE_TASK_FRAGMENT;
import static androidx.window.extensions.embedding.EmbeddingTestUtils.DEFAULT_FINISH_PRIMARY_WITH_SECONDARY;
import static androidx.window.extensions.embedding.EmbeddingTestUtils.DEFAULT_FINISH_SECONDARY_WITH_PRIMARY;
@@ -1139,7 +1139,7 @@
final TaskFragmentTransaction transaction = new TaskFragmentTransaction();
final IBinder errorToken = new Binder();
final TaskFragmentInfo info = mock(TaskFragmentInfo.class);
- final int opType = HIERARCHY_OP_TYPE_CREATE_TASK_FRAGMENT;
+ final int opType = OP_TYPE_CREATE_TASK_FRAGMENT;
final Exception exception = new SecurityException("test");
final Bundle errorBundle = TaskFragmentOrganizer.putErrorInfoInBundle(exception, info,
opType);
diff --git a/libs/WindowManager/Jetpack/tests/unittest/src/androidx/window/extensions/embedding/SplitPresenterTest.java b/libs/WindowManager/Jetpack/tests/unittest/src/androidx/window/extensions/embedding/SplitPresenterTest.java
index ff1256b..07d0158 100644
--- a/libs/WindowManager/Jetpack/tests/unittest/src/androidx/window/extensions/embedding/SplitPresenterTest.java
+++ b/libs/WindowManager/Jetpack/tests/unittest/src/androidx/window/extensions/embedding/SplitPresenterTest.java
@@ -66,8 +66,10 @@
import android.graphics.Rect;
import android.os.IBinder;
import android.platform.test.annotations.Presubmit;
+import android.util.DisplayMetrics;
import android.util.Pair;
import android.util.Size;
+import android.view.WindowMetrics;
import android.window.TaskFragmentAnimationParams;
import android.window.TaskFragmentInfo;
import android.window.TaskFragmentOperation;
@@ -101,7 +103,6 @@
@RunWith(AndroidJUnit4.class)
public class SplitPresenterTest {
- @Mock
private Activity mActivity;
@Mock
private Resources mActivityResources;
@@ -193,7 +194,7 @@
OP_TYPE_SET_ANIMATION_PARAMS)
.setAnimationParams(animationParams)
.build();
- verify(mTransaction).setTaskFragmentOperation(container.getTaskFragmentToken(),
+ verify(mTransaction).addTaskFragmentOperation(container.getTaskFragmentToken(),
expectedOperation);
assertTrue(container.areLastRequestedAnimationParamsEqual(animationParams));
@@ -202,7 +203,7 @@
mPresenter.updateAnimationParams(mTransaction, container.getTaskFragmentToken(),
animationParams);
- verify(mTransaction, never()).setTaskFragmentOperation(any(), any());
+ verify(mTransaction, never()).addTaskFragmentOperation(any(), any());
}
@Test
@@ -571,6 +572,21 @@
splitPairRule, null /* minDimensionsPair */));
}
+ @Test
+ public void testGetTaskWindowMetrics() {
+ final Configuration taskConfig = new Configuration();
+ taskConfig.windowConfiguration.setBounds(TASK_BOUNDS);
+ taskConfig.densityDpi = 123;
+ final TaskContainer.TaskProperties taskProperties = new TaskContainer.TaskProperties(
+ DEFAULT_DISPLAY, taskConfig);
+ doReturn(taskProperties).when(mPresenter).getTaskProperties(mActivity);
+
+ final WindowMetrics windowMetrics = mPresenter.getTaskWindowMetrics(mActivity);
+ assertEquals(TASK_BOUNDS, windowMetrics.getBounds());
+ assertEquals(123 * DisplayMetrics.DENSITY_DEFAULT_SCALE,
+ windowMetrics.getDensity(), 0f);
+ }
+
private Activity createMockActivity() {
final Activity activity = mock(Activity.class);
final Configuration activityConfig = new Configuration();
diff --git a/libs/WindowManager/Jetpack/tests/unittest/src/androidx/window/extensions/embedding/TaskFragmentContainerTest.java b/libs/WindowManager/Jetpack/tests/unittest/src/androidx/window/extensions/embedding/TaskFragmentContainerTest.java
index 7d9d8b0..78b85e6 100644
--- a/libs/WindowManager/Jetpack/tests/unittest/src/androidx/window/extensions/embedding/TaskFragmentContainerTest.java
+++ b/libs/WindowManager/Jetpack/tests/unittest/src/androidx/window/extensions/embedding/TaskFragmentContainerTest.java
@@ -154,17 +154,52 @@
null /* pendingAppearedIntent */, taskContainer, mController,
null /* pairedPrimaryContainer */);
doReturn(container1).when(mController).getContainerWithActivity(mActivity);
- final WindowContainerTransaction wct = new WindowContainerTransaction();
// The activity is requested to be reparented, so don't finish it.
- container0.finish(true /* shouldFinishDependent */, mPresenter, wct, mController);
+ container0.finish(true /* shouldFinishDependent */, mPresenter, mTransaction, mController);
verify(mTransaction, never()).finishActivity(any());
- verify(mPresenter).deleteTaskFragment(wct, container0.getTaskFragmentToken());
+ verify(mPresenter).deleteTaskFragment(mTransaction, container0.getTaskFragmentToken());
verify(mController).removeContainer(container0);
}
@Test
+ public void testFinish_alwaysFinishPlaceholder() {
+ // Register container1 as a placeholder
+ final TaskContainer taskContainer = createTestTaskContainer();
+ final TaskFragmentContainer container0 = new TaskFragmentContainer(mActivity,
+ null /* pendingAppearedIntent */, taskContainer, mController,
+ null /* pairedPrimaryContainer */);
+ final TaskFragmentInfo info0 = createMockTaskFragmentInfo(container0, mActivity);
+ container0.setInfo(mTransaction, info0);
+ final Activity placeholderActivity = createMockActivity();
+ final TaskFragmentContainer container1 = new TaskFragmentContainer(placeholderActivity,
+ null /* pendingAppearedIntent */, taskContainer, mController,
+ null /* pairedPrimaryContainer */);
+ final TaskFragmentInfo info1 = createMockTaskFragmentInfo(container1, placeholderActivity);
+ container1.setInfo(mTransaction, info1);
+ final SplitAttributes splitAttributes = new SplitAttributes.Builder().build();
+ final SplitPlaceholderRule rule = new SplitPlaceholderRule.Builder(new Intent(),
+ mActivity::equals, (java.util.function.Predicate) i -> false,
+ (java.util.function.Predicate) w -> true)
+ .setDefaultSplitAttributes(splitAttributes)
+ .build();
+ mController.registerSplit(mTransaction, container0, mActivity, container1, rule,
+ splitAttributes);
+
+ // The placeholder TaskFragment should be finished even if the primary is finished with
+ // shouldFinishDependent = false.
+ container0.finish(false /* shouldFinishDependent */, mPresenter, mTransaction, mController);
+
+ assertTrue(container0.isFinished());
+ assertTrue(container1.isFinished());
+ verify(mPresenter).deleteTaskFragment(mTransaction, container0.getTaskFragmentToken());
+ verify(mPresenter).deleteTaskFragment(mTransaction, container1.getTaskFragmentToken());
+ verify(mController).removeContainer(container0);
+ verify(mController).removeContainer(container1);
+ }
+
+ @Test
public void testSetInfo() {
final TaskContainer taskContainer = createTestTaskContainer();
// Pending activity should be cleared when it has appeared on server side.
@@ -493,8 +528,6 @@
final TaskFragmentContainer tf1 = new TaskFragmentContainer(
null /* pendingAppearedActivity */, new Intent(), taskContainer, mController,
null /* pairedPrimaryTaskFragment */);
- taskContainer.mContainers.add(tf0);
- taskContainer.mContainers.add(tf1);
// When tf2 is created with using tf0 as pairedPrimaryContainer, tf2 should be inserted
// right above tf0.
@@ -506,6 +539,26 @@
}
@Test
+ public void testNewContainerWithPairedPendingAppearedActivity() {
+ final TaskContainer taskContainer = createTestTaskContainer();
+ final TaskFragmentContainer tf0 = new TaskFragmentContainer(
+ createMockActivity(), null /* pendingAppearedIntent */, taskContainer, mController,
+ null /* pairedPrimaryTaskFragment */);
+ final TaskFragmentContainer tf1 = new TaskFragmentContainer(
+ null /* pendingAppearedActivity */, new Intent(), taskContainer, mController,
+ null /* pairedPrimaryTaskFragment */);
+
+ // When tf2 is created with pendingAppearedActivity, tf2 should be inserted below any
+ // TaskFragment without any Activity.
+ final TaskFragmentContainer tf2 = new TaskFragmentContainer(
+ createMockActivity(), null /* pendingAppearedIntent */, taskContainer, mController,
+ null /* pairedPrimaryTaskFragment */);
+ assertEquals(0, taskContainer.indexOf(tf0));
+ assertEquals(1, taskContainer.indexOf(tf2));
+ assertEquals(2, taskContainer.indexOf(tf1));
+ }
+
+ @Test
public void testIsVisible() {
final TaskContainer taskContainer = createTestTaskContainer();
final TaskFragmentContainer container = new TaskFragmentContainer(
diff --git a/libs/WindowManager/Jetpack/window-extensions-release.aar b/libs/WindowManager/Jetpack/window-extensions-release.aar
index a939cd8..5de5365 100644
--- a/libs/WindowManager/Jetpack/window-extensions-release.aar
+++ b/libs/WindowManager/Jetpack/window-extensions-release.aar
Binary files differ
diff --git a/libs/WindowManager/Shell/res/drawable/decor_minimize_button_dark.xml b/libs/WindowManager/Shell/res/drawable/decor_minimize_button_dark.xml
index 0bcaa53..b7ff96e 100644
--- a/libs/WindowManager/Shell/res/drawable/decor_minimize_button_dark.xml
+++ b/libs/WindowManager/Shell/res/drawable/decor_minimize_button_dark.xml
@@ -18,7 +18,7 @@
android:height="24dp"
android:viewportWidth="24"
android:viewportHeight="24"
- android:tint="?attr/colorControlNormal">
+ android:tint="@color/decor_button_dark_color">
<path
android:fillColor="@android:color/white" android:pathData="M6,21V19H18V21Z"/>
</vector>
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/ShellTaskOrganizer.java b/libs/WindowManager/Shell/src/com/android/wm/shell/ShellTaskOrganizer.java
index 065fd95..b5ef72a 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/ShellTaskOrganizer.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/ShellTaskOrganizer.java
@@ -257,12 +257,30 @@
}
}
+ /**
+ * Creates a persistent root task in WM for a particular windowing-mode.
+ * @param displayId The display to create the root task on.
+ * @param windowingMode Windowing mode to put the root task in.
+ * @param listener The listener to get the created task callback.
+ */
public void createRootTask(int displayId, int windowingMode, TaskListener listener) {
- ProtoLog.v(WM_SHELL_TASK_ORG, "createRootTask() displayId=%d winMode=%d listener=%s",
+ createRootTask(displayId, windowingMode, listener, false /* removeWithTaskOrganizer */);
+ }
+
+ /**
+ * Creates a persistent root task in WM for a particular windowing-mode.
+ * @param displayId The display to create the root task on.
+ * @param windowingMode Windowing mode to put the root task in.
+ * @param listener The listener to get the created task callback.
+ * @param removeWithTaskOrganizer True if this task should be removed when organizer destroyed.
+ */
+ public void createRootTask(int displayId, int windowingMode, TaskListener listener,
+ boolean removeWithTaskOrganizer) {
+ ProtoLog.v(WM_SHELL_TASK_ORG, "createRootTask() displayId=%d winMode=%d listener=%s" ,
displayId, windowingMode, listener.toString());
final IBinder cookie = new Binder();
setPendingLaunchCookieListener(cookie, listener);
- super.createRootTask(displayId, windowingMode, cookie);
+ super.createRootTask(displayId, windowingMode, cookie, removeWithTaskOrganizer);
}
/**
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleController.java
index 9674b69..360bfe7 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleController.java
@@ -981,21 +981,59 @@
}
/**
- * Adds and expands bubble for a specific intent. These bubbles are <b>not</b> backed by a n
- * otification and remain until the user dismisses the bubble or bubble stack. Only one intent
- * bubble is supported at a time.
+ * This method has different behavior depending on:
+ * - if an app bubble exists
+ * - if an app bubble is expanded
+ *
+ * If no app bubble exists, this will add and expand a bubble with the provided intent. The
+ * intent must be explicit (i.e. include a package name or fully qualified component class name)
+ * and the activity for it should be resizable.
+ *
+ * If an app bubble exists, this will toggle the visibility of it, i.e. if the app bubble is
+ * expanded, calling this method will collapse it. If the app bubble is not expanded, calling
+ * this method will expand it.
+ *
+ * These bubbles are <b>not</b> backed by a notification and remain until the user dismisses
+ * the bubble or bubble stack.
+ *
+ * Some notes:
+ * - Only one app bubble is supported at a time
+ * - Calling this method with a different intent than the existing app bubble will do nothing
*
* @param intent the intent to display in the bubble expanded view.
*/
- public void showAppBubble(Intent intent) {
- if (intent == null || intent.getPackage() == null) return;
+ public void showOrHideAppBubble(Intent intent) {
+ if (intent == null || intent.getPackage() == null) {
+ Log.w(TAG, "App bubble failed to show, invalid intent: " + intent
+ + ((intent != null) ? " with package: " + intent.getPackage() : " "));
+ return;
+ }
PackageManager packageManager = getPackageManagerForUser(mContext, mCurrentUserId);
if (!isResizableActivity(intent, packageManager, KEY_APP_BUBBLE)) return;
- Bubble b = new Bubble(intent, UserHandle.of(mCurrentUserId), mMainExecutor);
- b.setShouldAutoExpand(true);
- inflateAndAdd(b, /* suppressFlyout= */ true, /* showInShade= */ false);
+ Bubble existingAppBubble = mBubbleData.getBubbleInStackWithKey(KEY_APP_BUBBLE);
+ if (existingAppBubble != null) {
+ BubbleViewProvider selectedBubble = mBubbleData.getSelectedBubble();
+ if (isStackExpanded()) {
+ if (selectedBubble != null && KEY_APP_BUBBLE.equals(selectedBubble.getKey())) {
+ // App bubble is expanded, lets collapse
+ collapseStack();
+ } else {
+ // App bubble is not selected, select it
+ mBubbleData.setSelectedBubble(existingAppBubble);
+ }
+ } else {
+ // App bubble is not selected, select it & expand
+ mBubbleData.setSelectedBubble(existingAppBubble);
+ mBubbleData.setExpanded(true);
+ }
+ } else {
+ // App bubble does not exist, lets add and expand it
+ Bubble b = new Bubble(intent, UserHandle.of(mCurrentUserId), mMainExecutor);
+ b.setShouldAutoExpand(true);
+ inflateAndAdd(b, /* suppressFlyout= */ true, /* showInShade= */ false);
+ }
}
/**
@@ -1705,9 +1743,9 @@
}
@Override
- public void showAppBubble(Intent intent) {
+ public void showOrHideAppBubble(Intent intent) {
mMainExecutor.execute(() -> {
- BubbleController.this.showAppBubble(intent);
+ BubbleController.this.showOrHideAppBubble(intent);
});
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleData.java b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleData.java
index af31391..6230d22 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleData.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleData.java
@@ -17,6 +17,7 @@
import static com.android.internal.annotations.VisibleForTesting.Visibility.PACKAGE;
import static com.android.internal.annotations.VisibleForTesting.Visibility.PRIVATE;
+import static com.android.wm.shell.bubbles.Bubble.KEY_APP_BUBBLE;
import static com.android.wm.shell.bubbles.BubbleDebugConfig.DEBUG_BUBBLE_DATA;
import static com.android.wm.shell.bubbles.BubbleDebugConfig.TAG_BUBBLES;
import static com.android.wm.shell.bubbles.BubbleDebugConfig.TAG_WITH_CLASS_NAME;
@@ -684,7 +685,8 @@
if (bubble.getPendingIntentCanceled()
|| !(reason == Bubbles.DISMISS_AGED
|| reason == Bubbles.DISMISS_USER_GESTURE
- || reason == Bubbles.DISMISS_RELOAD_FROM_DISK)) {
+ || reason == Bubbles.DISMISS_RELOAD_FROM_DISK)
+ || KEY_APP_BUBBLE.equals(bubble.getKey())) {
return;
}
if (DEBUG_BUBBLE_DATA) {
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/Bubbles.java b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/Bubbles.java
index 465d1ab..df43257 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/Bubbles.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/Bubbles.java
@@ -109,13 +109,28 @@
void expandStackAndSelectBubble(Bubble bubble);
/**
- * Adds and expands bubble that is not notification based, but instead based on an intent from
- * the app. The intent must be explicit (i.e. include a package name or fully qualified
- * component class name) and the activity for it should be resizable.
+ * This method has different behavior depending on:
+ * - if an app bubble exists
+ * - if an app bubble is expanded
*
- * @param intent the intent to populate the bubble.
+ * If no app bubble exists, this will add and expand a bubble with the provided intent. The
+ * intent must be explicit (i.e. include a package name or fully qualified component class name)
+ * and the activity for it should be resizable.
+ *
+ * If an app bubble exists, this will toggle the visibility of it, i.e. if the app bubble is
+ * expanded, calling this method will collapse it. If the app bubble is not expanded, calling
+ * this method will expand it.
+ *
+ * These bubbles are <b>not</b> backed by a notification and remain until the user dismisses
+ * the bubble or bubble stack.
+ *
+ * Some notes:
+ * - Only one app bubble is supported at a time
+ * - Calling this method with a different intent than the existing app bubble will do nothing
+ *
+ * @param intent the intent to display in the bubble expanded view.
*/
- void showAppBubble(Intent intent);
+ void showOrHideAppBubble(Intent intent);
/**
* @return a bubble that matches the provided shortcutId, if one exists.
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/common/SystemWindows.java b/libs/WindowManager/Shell/src/com/android/wm/shell/common/SystemWindows.java
index 94aeb2b..5e46023 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/common/SystemWindows.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/common/SystemWindows.java
@@ -306,7 +306,9 @@
}
}
- protected void attachToParentSurface(IWindow window, SurfaceControl.Builder b) {
+ @Override
+ protected SurfaceControl getParentSurface(IWindow window,
+ WindowManager.LayoutParams attrs) {
SurfaceControl leash = new SurfaceControl.Builder(new SurfaceSession())
.setContainerLayer()
.setName("SystemWindowLeash")
@@ -316,7 +318,7 @@
synchronized (this) {
mLeashForWindow.put(window.asBinder(), leash);
}
- b.setParent(leash);
+ return leash;
}
@Override
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/SplitDecorManager.java b/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/SplitDecorManager.java
index a9d3c9f..fcbf9e0 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/SplitDecorManager.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/SplitDecorManager.java
@@ -92,7 +92,7 @@
}
@Override
- protected void attachToParentSurface(IWindow window, SurfaceControl.Builder b) {
+ protected SurfaceControl getParentSurface(IWindow window, WindowManager.LayoutParams attrs) {
// Can't set position for the ViewRootImpl SC directly. Create a leash to manipulate later.
final SurfaceControl.Builder builder = new SurfaceControl.Builder(new SurfaceSession())
.setContainerLayer()
@@ -101,7 +101,7 @@
.setParent(mHostLeash)
.setCallsite("SplitDecorManager#attachToParentSurface");
mIconLeash = builder.build();
- b.setParent(mIconLeash);
+ return mIconLeash;
}
/** Inflates split decor surface on the root surface. */
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/SplitWindowManager.java b/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/SplitWindowManager.java
index 5397552..6b5ddcb 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/SplitWindowManager.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/SplitWindowManager.java
@@ -93,7 +93,7 @@
}
@Override
- protected void attachToParentSurface(IWindow window, SurfaceControl.Builder b) {
+ protected SurfaceControl getParentSurface(IWindow window, WindowManager.LayoutParams attrs) {
// Can't set position for the ViewRootImpl SC directly. Create a leash to manipulate later.
final SurfaceControl.Builder builder = new SurfaceControl.Builder(new SurfaceSession())
.setContainerLayer()
@@ -103,7 +103,7 @@
mParentContainerCallbacks.attachToParentSurface(builder);
mLeash = builder.build();
mParentContainerCallbacks.onLeashReady(mLeash);
- b.setParent(mLeash);
+ return mLeash;
}
/** Inflates {@link DividerView} on to the root surface. */
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/compatui/CompatUIWindowManagerAbstract.java b/libs/WindowManager/Shell/src/com/android/wm/shell/compatui/CompatUIWindowManagerAbstract.java
index face243..2cc9f45 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/compatui/CompatUIWindowManagerAbstract.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/compatui/CompatUIWindowManagerAbstract.java
@@ -155,7 +155,7 @@
}
@Override
- protected void attachToParentSurface(IWindow window, SurfaceControl.Builder b) {
+ protected SurfaceControl getParentSurface(IWindow window, WindowManager.LayoutParams attrs) {
String className = getClass().getSimpleName();
final SurfaceControl.Builder builder = new SurfaceControl.Builder(new SurfaceSession())
.setContainerLayer()
@@ -164,9 +164,8 @@
.setCallsite(className + "#attachToParentSurface");
attachToParentSurface(builder);
mLeash = builder.build();
- b.setParent(mLeash);
-
initSurface(mLeash);
+ return mLeash;
}
/** Inits the z-order of the surface. */
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopModeController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopModeController.java
index f5f3573..63b03ab 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopModeController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopModeController.java
@@ -251,7 +251,8 @@
* Show apps on desktop
*/
void showDesktopApps() {
- WindowContainerTransaction wct = bringDesktopAppsToFront();
+ // Bring apps to front, ignoring their visibility status to always ensure they are on top.
+ WindowContainerTransaction wct = bringDesktopAppsToFront(true /* ignoreVisibility */);
if (Transitions.ENABLE_SHELL_TRANSITIONS) {
mTransitions.startTransition(TRANSIT_TO_FRONT, wct, null /* handler */);
@@ -261,7 +262,7 @@
}
@NonNull
- private WindowContainerTransaction bringDesktopAppsToFront() {
+ private WindowContainerTransaction bringDesktopAppsToFront(boolean force) {
final WindowContainerTransaction wct = new WindowContainerTransaction();
final ArraySet<Integer> activeTasks = mDesktopModeTaskRepository.getActiveTasks();
ProtoLog.d(WM_SHELL_DESKTOP_MODE, "bringDesktopAppsToFront: tasks=%s", activeTasks.size());
@@ -278,12 +279,14 @@
return wct;
}
- final boolean allActiveTasksAreVisible = taskInfos.stream()
- .allMatch(info -> mDesktopModeTaskRepository.isVisibleTask(info.taskId));
- if (allActiveTasksAreVisible) {
- ProtoLog.d(WM_SHELL_DESKTOP_MODE,
- "bringDesktopAppsToFront: active tasks are already in front, skipping.");
- return wct;
+ if (!force) {
+ final boolean allActiveTasksAreVisible = taskInfos.stream()
+ .allMatch(info -> mDesktopModeTaskRepository.isVisibleTask(info.taskId));
+ if (allActiveTasksAreVisible) {
+ ProtoLog.d(WM_SHELL_DESKTOP_MODE,
+ "bringDesktopAppsToFront: active tasks are already in front, skipping.");
+ return wct;
+ }
}
ProtoLog.d(WM_SHELL_DESKTOP_MODE,
"bringDesktopAppsToFront: reordering all active tasks to the front");
@@ -354,7 +357,7 @@
if (wct == null) {
wct = new WindowContainerTransaction();
}
- wct.merge(bringDesktopAppsToFront(), true /* transfer */);
+ wct.merge(bringDesktopAppsToFront(false /* ignoreVisibility */), true /* transfer */);
wct.reorder(request.getTriggerTask().token, true /* onTop */);
return wct;
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopTasksController.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopTasksController.kt
index 3341470..9165f70 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopTasksController.kt
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopTasksController.kt
@@ -84,8 +84,7 @@
fun showDesktopApps() {
ProtoLog.v(WM_SHELL_DESKTOP_MODE, "showDesktopApps")
val wct = WindowContainerTransaction()
-
- bringDesktopAppsToFront(wct)
+ bringDesktopAppsToFront(wct, force = true)
// Execute transaction if there are pending operations
if (!wct.isEmpty) {
@@ -150,11 +149,11 @@
?: WINDOWING_MODE_UNDEFINED
}
- private fun bringDesktopAppsToFront(wct: WindowContainerTransaction) {
+ private fun bringDesktopAppsToFront(wct: WindowContainerTransaction, force: Boolean = false) {
val activeTasks = desktopModeTaskRepository.getActiveTasks()
// Skip if all tasks are already visible
- if (activeTasks.isNotEmpty() && activeTasks.all(desktopModeTaskRepository::isVisibleTask)) {
+ if (!force && activeTasks.all(desktopModeTaskRepository::isVisibleTask)) {
ProtoLog.d(
WM_SHELL_DESKTOP_MODE,
"bringDesktopAppsToFront: active tasks are already in front, skipping."
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/onehanded/BackgroundWindowManager.java b/libs/WindowManager/Shell/src/com/android/wm/shell/onehanded/BackgroundWindowManager.java
index b310ee2..8ebcd81 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/onehanded/BackgroundWindowManager.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/onehanded/BackgroundWindowManager.java
@@ -104,7 +104,7 @@
}
@Override
- protected void attachToParentSurface(IWindow window, SurfaceControl.Builder b) {
+ protected SurfaceControl getParentSurface(IWindow window, WindowManager.LayoutParams attrs) {
final SurfaceControl.Builder builder = new SurfaceControl.Builder(new SurfaceSession())
.setColorLayer()
.setBufferSize(mDisplayBounds.width(), mDisplayBounds.height())
@@ -113,7 +113,7 @@
.setName(TAG)
.setCallsite("BackgroundWindowManager#attachToParentSurface");
mLeash = builder.build();
- b.setParent(mLeash);
+ return mLeash;
}
/** Inflates background view on to the root surface. */
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTransition.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTransition.java
index e6c7e10..83158ff 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTransition.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTransition.java
@@ -662,8 +662,8 @@
}
// Please file a bug to handle the unexpected transition type.
- throw new IllegalStateException("Entering PIP with unexpected transition type="
- + transitTypeToString(transitType));
+ android.util.Slog.e(TAG, "Found new PIP in transition with mis-matched type="
+ + transitTypeToString(transitType), new Throwable());
}
return false;
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PhonePipMenuController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PhonePipMenuController.java
index a0a8f9f..94e593b 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PhonePipMenuController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PhonePipMenuController.java
@@ -333,6 +333,9 @@
mTmpDestinationRectF.set(destinationBounds);
mMoveTransform.setRectToRect(mTmpSourceRectF, mTmpDestinationRectF, Matrix.ScaleToFit.FILL);
final SurfaceControl surfaceControl = getSurfaceControl();
+ if (surfaceControl == null) {
+ return;
+ }
final SurfaceControl.Transaction menuTx =
mSurfaceControlTransactionFactory.getTransaction();
menuTx.setMatrix(surfaceControl, mMoveTransform, mTmpTransform);
@@ -359,6 +362,9 @@
}
final SurfaceControl surfaceControl = getSurfaceControl();
+ if (surfaceControl == null) {
+ return;
+ }
final SurfaceControl.Transaction menuTx =
mSurfaceControlTransactionFactory.getTransaction();
menuTx.setCrop(surfaceControl, destinationBounds);
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipController.java
index 01d81ff..3153313 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipController.java
@@ -814,7 +814,7 @@
@Override
public void onKeyguardVisibilityChanged(boolean visible, boolean occluded,
boolean animatingDismiss) {
- if (!mPipTaskOrganizer.isInPip()) {
+ if (!mPipTransitionState.hasEnteredPip()) {
return;
}
if (visible) {
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageCoordinator.java b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageCoordinator.java
index 8ddc3c04..1488469 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageCoordinator.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageCoordinator.java
@@ -605,9 +605,19 @@
float splitRatio, RemoteAnimationAdapter adapter, InstanceId instanceId) {
final WindowContainerTransaction wct = new WindowContainerTransaction();
if (options1 == null) options1 = new Bundle();
+ if (taskId2 == INVALID_TASK_ID) {
+ // Launching a solo task.
+ ActivityOptions activityOptions = ActivityOptions.fromBundle(options1);
+ activityOptions.update(ActivityOptions.makeRemoteAnimation(adapter));
+ options1 = activityOptions.toBundle();
+ addActivityOptions(options1, null /* launchTarget */);
+ wct.startTask(taskId1, options1);
+ mSyncQueue.queue(wct);
+ return;
+ }
+
addActivityOptions(options1, mSideStage);
wct.startTask(taskId1, options1);
-
startWithLegacyTransition(wct, taskId2, options2, splitPosition, splitRatio, adapter,
instanceId);
}
@@ -632,9 +642,19 @@
InstanceId instanceId) {
final WindowContainerTransaction wct = new WindowContainerTransaction();
if (options1 == null) options1 = new Bundle();
+ if (taskId == INVALID_TASK_ID) {
+ // Launching a solo task.
+ ActivityOptions activityOptions = ActivityOptions.fromBundle(options1);
+ activityOptions.update(ActivityOptions.makeRemoteAnimation(adapter));
+ options1 = activityOptions.toBundle();
+ addActivityOptions(options1, null /* launchTarget */);
+ wct.sendPendingIntent(pendingIntent, fillInIntent, options1);
+ mSyncQueue.queue(wct);
+ return;
+ }
+
addActivityOptions(options1, mSideStage);
wct.sendPendingIntent(pendingIntent, fillInIntent, options1);
-
startWithLegacyTransition(wct, taskId, options2, splitPosition, splitRatio, adapter,
instanceId);
}
@@ -696,6 +716,34 @@
mShouldUpdateRecents = false;
mIsSplitEntering = true;
+ setSideStagePosition(sidePosition, wct);
+ if (!mMainStage.isActive()) {
+ mMainStage.activate(wct, false /* reparent */);
+ }
+
+ if (mainOptions == null) mainOptions = new Bundle();
+ addActivityOptions(mainOptions, mMainStage);
+ mainOptions = wrapAsSplitRemoteAnimation(adapter, mainOptions);
+
+ updateWindowBounds(mSplitLayout, wct);
+ if (mainTaskId == INVALID_TASK_ID) {
+ wct.sendPendingIntent(mainPendingIntent, mainFillInIntent, mainOptions);
+ } else {
+ wct.startTask(mainTaskId, mainOptions);
+ }
+
+ wct.reorder(mRootTaskInfo.token, true);
+ wct.setForceTranslucent(mRootTaskInfo.token, false);
+
+ mSyncQueue.queue(wct);
+ mSyncQueue.runInSync(t -> {
+ setDividerVisibility(true, t);
+ });
+
+ setEnterInstanceId(instanceId);
+ }
+
+ private Bundle wrapAsSplitRemoteAnimation(RemoteAnimationAdapter adapter, Bundle options) {
final WindowContainerTransaction evictWct = new WindowContainerTransaction();
if (isSplitScreenVisible()) {
mMainStage.evictAllChildren(evictWct);
@@ -739,37 +787,9 @@
};
RemoteAnimationAdapter wrappedAdapter = new RemoteAnimationAdapter(
wrapper, adapter.getDuration(), adapter.getStatusBarTransitionDelay());
-
- if (mainOptions == null) {
- mainOptions = ActivityOptions.makeRemoteAnimation(wrappedAdapter).toBundle();
- } else {
- ActivityOptions mainActivityOptions = ActivityOptions.fromBundle(mainOptions);
- mainActivityOptions.update(ActivityOptions.makeRemoteAnimation(wrappedAdapter));
- mainOptions = mainActivityOptions.toBundle();
- }
-
- setSideStagePosition(sidePosition, wct);
- if (!mMainStage.isActive()) {
- mMainStage.activate(wct, false /* reparent */);
- }
-
- if (mainOptions == null) mainOptions = new Bundle();
- addActivityOptions(mainOptions, mMainStage);
- updateWindowBounds(mSplitLayout, wct);
- if (mainTaskId == INVALID_TASK_ID) {
- wct.sendPendingIntent(mainPendingIntent, mainFillInIntent, mainOptions);
- } else {
- wct.startTask(mainTaskId, mainOptions);
- }
- wct.reorder(mRootTaskInfo.token, true);
- wct.setForceTranslucent(mRootTaskInfo.token, false);
-
- mSyncQueue.queue(wct);
- mSyncQueue.runInSync(t -> {
- setDividerVisibility(true, t);
- });
-
- setEnterInstanceId(instanceId);
+ ActivityOptions activityOptions = ActivityOptions.fromBundle(options);
+ activityOptions.update(ActivityOptions.makeRemoteAnimation(wrappedAdapter));
+ return activityOptions.toBundle();
}
private void setEnterInstanceId(InstanceId instanceId) {
@@ -1228,8 +1248,10 @@
return SPLIT_POSITION_UNDEFINED;
}
- private void addActivityOptions(Bundle opts, StageTaskListener stage) {
- opts.putParcelable(KEY_LAUNCH_ROOT_TASK_TOKEN, stage.mRootTaskInfo.token);
+ private void addActivityOptions(Bundle opts, @Nullable StageTaskListener launchTarget) {
+ if (launchTarget != null) {
+ opts.putParcelable(KEY_LAUNCH_ROOT_TASK_TOKEN, launchTarget.mRootTaskInfo.token);
+ }
// Put BAL flags to avoid activity start aborted. Otherwise, flows like shortcut to split
// will be canceled.
opts.putBoolean(KEY_PENDING_INTENT_BACKGROUND_ACTIVITY_ALLOWED, true);
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/bubble/DismissBubbleScreen.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/bubble/DismissBubbleScreen.kt
index 7fc12f0..7a86c25 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/bubble/DismissBubbleScreen.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/bubble/DismissBubbleScreen.kt
@@ -18,7 +18,6 @@
import android.content.Context
import android.graphics.Point
-import android.platform.test.annotations.Postsubmit
import android.platform.test.annotations.Presubmit
import android.util.DisplayMetrics
import android.view.WindowManager
@@ -74,20 +73,4 @@
open fun testAppIsAlwaysVisible() {
flicker.assertLayers { this.isVisible(testApp) }
}
-
- /** {@inheritDoc} */
- @Postsubmit
- @Test
- override fun taskBarLayerIsVisibleAtStartAndEnd() = super.taskBarLayerIsVisibleAtStartAndEnd()
-
- /** {@inheritDoc} */
- @Postsubmit
- @Test
- override fun taskBarWindowIsAlwaysVisible() = super.taskBarWindowIsAlwaysVisible()
-
- /** {@inheritDoc} */
- @Postsubmit
- @Test
- override fun visibleLayersShownMoreThanOneConsecutiveEntry() =
- super.visibleLayersShownMoreThanOneConsecutiveEntry()
}
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/bubble/LaunchBubbleFromLockScreen.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/bubble/LaunchBubbleFromLockScreen.kt
index 08ed91b..379d5e9 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/bubble/LaunchBubbleFromLockScreen.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/bubble/LaunchBubbleFromLockScreen.kt
@@ -94,9 +94,19 @@
flicker.assertLayersEnd { this.isVisible(testApp) }
}
- @Postsubmit @Test fun navBarLayerIsVisibleAtEnd() = flicker.navBarLayerIsVisibleAtEnd()
+ @Postsubmit
+ @Test
+ fun navBarLayerIsVisibleAtEnd() {
+ Assume.assumeFalse(flicker.scenario.isTablet)
+ flicker.navBarLayerIsVisibleAtEnd()
+ }
- @Postsubmit @Test fun navBarLayerPositionAtEnd() = flicker.navBarLayerPositionAtEnd()
+ @Postsubmit
+ @Test
+ fun navBarLayerPositionAtEnd() {
+ Assume.assumeFalse(flicker.scenario.isTablet)
+ flicker.navBarLayerPositionAtEnd()
+ }
/** {@inheritDoc} */
@FlakyTest
@@ -127,42 +137,4 @@
Assume.assumeTrue(flicker.scenario.isGesturalNavigation)
super.navBarWindowIsAlwaysVisible()
}
-
- /** {@inheritDoc} */
- @FlakyTest(bugId = 242088970)
- @Test
- override fun taskBarLayerIsVisibleAtStartAndEnd() = super.taskBarLayerIsVisibleAtStartAndEnd()
-
- /** {@inheritDoc} */
- @Postsubmit
- @Test
- override fun taskBarWindowIsAlwaysVisible() = super.taskBarWindowIsAlwaysVisible()
-
- /** {@inheritDoc} */
- @FlakyTest(bugId = 242088970)
- @Test
- override fun statusBarLayerIsVisibleAtStartAndEnd() =
- super.statusBarLayerIsVisibleAtStartAndEnd()
-
- /** {@inheritDoc} */
- @FlakyTest(bugId = 242088970)
- @Test
- override fun statusBarLayerPositionAtStartAndEnd() = super.statusBarLayerPositionAtStartAndEnd()
-
- /** {@inheritDoc} */
- @FlakyTest(bugId = 242088970)
- @Test
- override fun statusBarWindowIsAlwaysVisible() = super.statusBarWindowIsAlwaysVisible()
-
- /** {@inheritDoc} */
- @FlakyTest(bugId = 242088970)
- @Test
- override fun visibleWindowsShownMoreThanOneConsecutiveEntry() =
- super.visibleWindowsShownMoreThanOneConsecutiveEntry()
-
- @FlakyTest(bugId = 251217773)
- @Test
- override fun entireScreenCovered() {
- super.entireScreenCovered()
- }
}
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/bubble/LaunchBubbleScreen.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/bubble/LaunchBubbleScreen.kt
index b69ff64..5c0f854 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/bubble/LaunchBubbleScreen.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/bubble/LaunchBubbleScreen.kt
@@ -16,6 +16,7 @@
package com.android.wm.shell.flicker.bubble
+import android.platform.test.annotations.Presubmit
import androidx.test.filters.RequiresDevice
import androidx.test.uiautomator.By
import androidx.test.uiautomator.Until
@@ -57,6 +58,7 @@
}
}
+ @Presubmit
@Test
open fun testAppIsAlwaysVisible() {
flicker.assertLayers { this.isVisible(testApp) }
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/AutoEnterPipOnGoToHomeTest.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/AutoEnterPipOnGoToHomeTest.kt
index 5e898e8..4f3facb 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/AutoEnterPipOnGoToHomeTest.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/AutoEnterPipOnGoToHomeTest.kt
@@ -21,12 +21,7 @@
import androidx.test.filters.RequiresDevice
import com.android.server.wm.flicker.FlickerBuilder
import com.android.server.wm.flicker.FlickerTest
-import com.android.server.wm.flicker.helpers.setRotation
-import com.android.server.wm.flicker.helpers.wakeUpAndGoToHomeScreen
import com.android.server.wm.flicker.junit.FlickerParametersRunnerFactory
-import com.android.server.wm.flicker.rules.RemoveAllTasksButHomeRule
-import com.android.server.wm.flicker.rules.RemoveAllTasksButHomeRule.Companion.removeAllTasksButHome
-import com.android.server.wm.traces.common.service.PlatformConsts
import org.junit.Assume
import org.junit.FixMethodOrder
import org.junit.Test
@@ -64,17 +59,12 @@
override val transition: FlickerBuilder.() -> Unit
get() = {
setup {
- removeAllTasksButHome()
- device.wakeUpAndGoToHomeScreen()
pipApp.launchViaIntent(wmHelper)
pipApp.enableAutoEnterForPipActivity()
}
teardown {
// close gracefully so that onActivityUnpinned() can be called before force exit
pipApp.closePipWindow(wmHelper)
-
- setRotation(PlatformConsts.Rotation.ROTATION_0)
- RemoveAllTasksButHomeRule.removeAllTasksButHome()
pipApp.exit(wmHelper)
}
transitions { tapl.goHome() }
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/EnterPipOnUserLeaveHintTest.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/EnterPipOnUserLeaveHintTest.kt
index 79feeaa..8a694f7 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/EnterPipOnUserLeaveHintTest.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/EnterPipOnUserLeaveHintTest.kt
@@ -20,11 +20,7 @@
import androidx.test.filters.RequiresDevice
import com.android.server.wm.flicker.FlickerBuilder
import com.android.server.wm.flicker.FlickerTest
-import com.android.server.wm.flicker.helpers.setRotation
-import com.android.server.wm.flicker.helpers.wakeUpAndGoToHomeScreen
import com.android.server.wm.flicker.junit.FlickerParametersRunnerFactory
-import com.android.server.wm.flicker.rules.RemoveAllTasksButHomeRule
-import com.android.server.wm.traces.common.service.PlatformConsts
import org.junit.Assume
import org.junit.FixMethodOrder
import org.junit.Test
@@ -56,20 +52,17 @@
@RunWith(Parameterized::class)
@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
-class EnterPipOnUserLeaveHintTest(flicker: FlickerTest) : EnterPipTest(flicker) {
+open class EnterPipOnUserLeaveHintTest(flicker: FlickerTest) : EnterPipTest(flicker) {
/** Defines the transition used to run the test */
override val transition: FlickerBuilder.() -> Unit
get() = {
setup {
- RemoveAllTasksButHomeRule.removeAllTasksButHome()
- device.wakeUpAndGoToHomeScreen()
- device.wakeUpAndGoToHomeScreen()
pipApp.launchViaIntent(wmHelper)
pipApp.enableEnterPipOnUserLeaveHint()
}
teardown {
- setRotation(PlatformConsts.Rotation.ROTATION_0)
- RemoveAllTasksButHomeRule.removeAllTasksButHome()
+ // close gracefully so that onActivityUnpinned() can be called before force exit
+ pipApp.closePipWindow(wmHelper)
pipApp.exit(wmHelper)
}
transitions { tapl.goHome() }
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/EnterPipOnUserLeaveHintTestCfArm.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/EnterPipOnUserLeaveHintTestCfArm.kt
new file mode 100644
index 0000000..e478050
--- /dev/null
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/EnterPipOnUserLeaveHintTestCfArm.kt
@@ -0,0 +1,30 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.wm.shell.flicker.pip
+
+import com.android.server.wm.flicker.FlickerTest
+import com.android.server.wm.flicker.junit.FlickerParametersRunnerFactory
+import org.junit.FixMethodOrder
+import org.junit.runner.RunWith
+import org.junit.runners.MethodSorters
+import org.junit.runners.Parameterized
+
+/** This test will fail because of b/264261596 */
+@RunWith(Parameterized::class)
+@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
+@FixMethodOrder(MethodSorters.NAME_ASCENDING)
+class EnterPipOnUserLeaveHintTestCfArm(flicker: FlickerTest) : EnterPipOnUserLeaveHintTest(flicker)
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/EnterPipTest.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/EnterPipTest.kt
index 1a76142..1524b16 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/EnterPipTest.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/EnterPipTest.kt
@@ -21,10 +21,7 @@
import com.android.server.wm.flicker.FlickerBuilder
import com.android.server.wm.flicker.FlickerTest
import com.android.server.wm.flicker.FlickerTestFactory
-import com.android.server.wm.flicker.helpers.setRotation
-import com.android.server.wm.flicker.helpers.wakeUpAndGoToHomeScreen
import com.android.server.wm.flicker.junit.FlickerParametersRunnerFactory
-import com.android.server.wm.flicker.rules.RemoveAllTasksButHomeRule
import com.android.server.wm.traces.common.ComponentNameMatcher
import com.android.server.wm.traces.common.service.PlatformConsts
import org.junit.FixMethodOrder
@@ -63,13 +60,9 @@
override val transition: FlickerBuilder.() -> Unit
get() = {
setup {
- RemoveAllTasksButHomeRule.removeAllTasksButHome()
- device.wakeUpAndGoToHomeScreen()
pipApp.launchViaIntent(wmHelper)
}
teardown {
- setRotation(PlatformConsts.Rotation.ROTATION_0)
- RemoveAllTasksButHomeRule.removeAllTasksButHome()
pipApp.exit(wmHelper)
}
transitions { pipApp.clickEnterPipButton(wmHelper) }
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/EnterPipTestCfArm.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/EnterPipTestCfArm.kt
new file mode 100644
index 0000000..d2e8645
--- /dev/null
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/EnterPipTestCfArm.kt
@@ -0,0 +1,47 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.wm.shell.flicker.pip
+
+import com.android.server.wm.flicker.FlickerTest
+import com.android.server.wm.flicker.FlickerTestFactory
+import com.android.server.wm.flicker.junit.FlickerParametersRunnerFactory
+import com.android.server.wm.traces.common.service.PlatformConsts
+import org.junit.FixMethodOrder
+import org.junit.runner.RunWith
+import org.junit.runners.MethodSorters
+import org.junit.runners.Parameterized
+
+@RunWith(Parameterized::class)
+@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
+@FixMethodOrder(MethodSorters.NAME_ASCENDING)
+class EnterPipTestCfArm(flicker: FlickerTest) : EnterPipTest(flicker) {
+ companion object {
+ /**
+ * Creates the test configurations.
+ *
+ * See [FlickerTestFactory.nonRotationTests] for configuring repetitions, screen orientation
+ * and navigation modes.
+ */
+ @Parameterized.Parameters(name = "{0}")
+ @JvmStatic
+ fun getParams(): List<FlickerTest> {
+ return FlickerTestFactory.nonRotationTests(
+ supportedRotations = listOf(PlatformConsts.Rotation.ROTATION_0)
+ )
+ }
+ }
+}
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/EnterPipToOtherOrientationTest.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/EnterPipToOtherOrientationTest.kt
index a4c8d6f..94a16da 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/EnterPipToOtherOrientationTest.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/EnterPipToOtherOrientationTest.kt
@@ -17,7 +17,6 @@
package com.android.wm.shell.flicker.pip
import android.app.Activity
-import android.platform.test.annotations.FlakyTest
import android.platform.test.annotations.Presubmit
import androidx.test.filters.RequiresDevice
import com.android.server.wm.flicker.FlickerBuilder
@@ -26,14 +25,9 @@
import com.android.server.wm.flicker.entireScreenCovered
import com.android.server.wm.flicker.helpers.FixedOrientationAppHelper
import com.android.server.wm.flicker.helpers.WindowUtils
-import com.android.server.wm.flicker.helpers.setRotation
-import com.android.server.wm.flicker.helpers.wakeUpAndGoToHomeScreen
import com.android.server.wm.flicker.junit.FlickerParametersRunnerFactory
-import com.android.server.wm.flicker.navBarLayerPositionAtStartAndEnd
-import com.android.server.wm.flicker.rules.RemoveAllTasksButHomeRule
import com.android.server.wm.flicker.testapp.ActivityOptions.Pip.ACTION_ENTER_PIP
import com.android.server.wm.flicker.testapp.ActivityOptions.PortraitOnlyActivity.EXTRA_FIXED_ORIENTATION
-import com.android.server.wm.traces.common.ComponentNameMatcher
import com.android.server.wm.traces.common.service.PlatformConsts
import com.android.wm.shell.flicker.pip.PipTransition.BroadcastActionTrigger.Companion.ORIENTATION_LANDSCAPE
import com.android.wm.shell.flicker.pip.PipTransition.BroadcastActionTrigger.Companion.ORIENTATION_PORTRAIT
@@ -70,7 +64,7 @@
@RunWith(Parameterized::class)
@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
-class EnterPipToOtherOrientationTest(flicker: FlickerTest) : PipTransition(flicker) {
+open class EnterPipToOtherOrientationTest(flicker: FlickerTest) : PipTransition(flicker) {
private val testApp = FixedOrientationAppHelper(instrumentation)
private val startingBounds = WindowUtils.getDisplayBounds(PlatformConsts.Rotation.ROTATION_90)
private val endingBounds = WindowUtils.getDisplayBounds(PlatformConsts.Rotation.ROTATION_0)
@@ -79,9 +73,6 @@
override val transition: FlickerBuilder.() -> Unit
get() = {
setup {
- RemoveAllTasksButHomeRule.removeAllTasksButHome()
- device.wakeUpAndGoToHomeScreen()
-
// Launch a portrait only app on the fullscreen stack
testApp.launchViaIntent(
wmHelper,
@@ -95,8 +86,6 @@
)
}
teardown {
- setRotation(PlatformConsts.Rotation.ROTATION_0)
- RemoveAllTasksButHomeRule.removeAllTasksButHome()
pipApp.exit(wmHelper)
testApp.exit(wmHelper)
}
@@ -124,14 +113,6 @@
}
/**
- * Checks that the [ComponentNameMatcher.NAV_BAR] has the correct position at the start and end
- * of the transition
- */
- @FlakyTest
- @Test
- override fun navBarLayerPositionAtStartAndEnd() = flicker.navBarLayerPositionAtStartAndEnd()
-
- /**
* Checks that all parts of the screen are covered at the start and end of the transition
*
* TODO b/197726599 Prevents all states from being checked
@@ -140,12 +121,6 @@
@Test
fun entireScreenCoveredAtStartAndEnd() = flicker.entireScreenCovered(allStates = false)
- @FlakyTest(bugId = 251219769)
- @Test
- override fun entireScreenCovered() {
- super.entireScreenCovered()
- }
-
/** Checks [pipApp] window remains visible and on top throughout the transition */
@Presubmit
@Test
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/EnterPipToOtherOrientationTestCfArm.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/EnterPipToOtherOrientationTestCfArm.kt
new file mode 100644
index 0000000..39aab6e
--- /dev/null
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/EnterPipToOtherOrientationTestCfArm.kt
@@ -0,0 +1,49 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.wm.shell.flicker.pip
+
+import com.android.server.wm.flicker.FlickerTest
+import com.android.server.wm.flicker.FlickerTestFactory
+import com.android.server.wm.flicker.junit.FlickerParametersRunnerFactory
+import com.android.server.wm.traces.common.service.PlatformConsts
+import org.junit.FixMethodOrder
+import org.junit.runner.RunWith
+import org.junit.runners.MethodSorters
+import org.junit.runners.Parameterized
+
+/** This test fails because of b/264261596 */
+@RunWith(Parameterized::class)
+@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
+@FixMethodOrder(MethodSorters.NAME_ASCENDING)
+open class EnterPipToOtherOrientationTestCfArm(flicker: FlickerTest) :
+ EnterPipToOtherOrientationTest(flicker) {
+ companion object {
+ /**
+ * Creates the test configurations.
+ *
+ * See [FlickerTestFactory.nonRotationTests] for configuring screen orientation and
+ * navigation modes.
+ */
+ @Parameterized.Parameters(name = "{0}")
+ @JvmStatic
+ fun getParams(): Collection<FlickerTest> {
+ return FlickerTestFactory.nonRotationTests(
+ supportedRotations = listOf(PlatformConsts.Rotation.ROTATION_0)
+ )
+ }
+ }
+}
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/ExitPipViaExpandButtonClickTest.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/ExitPipViaExpandButtonClickTest.kt
index 1420f8ce..3bfcde3 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/ExitPipViaExpandButtonClickTest.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/ExitPipViaExpandButtonClickTest.kt
@@ -22,8 +22,10 @@
import com.android.server.wm.flicker.FlickerBuilder
import com.android.server.wm.flicker.FlickerTest
import com.android.server.wm.flicker.FlickerTestFactory
+import com.android.server.wm.flicker.helpers.isShellTransitionsEnabled
import com.android.server.wm.flicker.junit.FlickerParametersRunnerFactory
import com.android.server.wm.traces.common.service.PlatformConsts
+import org.junit.Assume
import org.junit.FixMethodOrder
import org.junit.Test
import org.junit.runner.RunWith
@@ -56,7 +58,7 @@
@RunWith(Parameterized::class)
@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
-class ExitPipViaExpandButtonClickTest(flicker: FlickerTest) : ExitPipToAppTransition(flicker) {
+open class ExitPipViaExpandButtonClickTest(flicker: FlickerTest) : ExitPipToAppTransition(flicker) {
/** Defines the transition used to run the test */
override val transition: FlickerBuilder.() -> Unit
@@ -74,10 +76,19 @@
}
/** {@inheritDoc} */
- @Presubmit @Test override fun entireScreenCovered() = super.entireScreenCovered()
+ @FlakyTest(bugId = 197726610)
+ @Test
+ override fun pipLayerExpands() {
+ Assume.assumeFalse(isShellTransitionsEnabled)
+ super.pipLayerExpands()
+ }
- /** {@inheritDoc} */
- @FlakyTest(bugId = 197726610) @Test override fun pipLayerExpands() = super.pipLayerExpands()
+ @Presubmit
+ @Test
+ fun pipLayerExpands_ShellTransit() {
+ Assume.assumeTrue(isShellTransitionsEnabled)
+ super.pipLayerExpands()
+ }
companion object {
/**
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/ExitPipViaExpandButtonClickTestCfArm.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/ExitPipViaExpandButtonClickTestCfArm.kt
new file mode 100644
index 0000000..f77e335
--- /dev/null
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/ExitPipViaExpandButtonClickTestCfArm.kt
@@ -0,0 +1,48 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.wm.shell.flicker.pip
+
+import com.android.server.wm.flicker.FlickerTest
+import com.android.server.wm.flicker.FlickerTestFactory
+import com.android.server.wm.flicker.junit.FlickerParametersRunnerFactory
+import com.android.server.wm.traces.common.service.PlatformConsts
+import org.junit.FixMethodOrder
+import org.junit.runner.RunWith
+import org.junit.runners.MethodSorters
+import org.junit.runners.Parameterized
+
+@RunWith(Parameterized::class)
+@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
+@FixMethodOrder(MethodSorters.NAME_ASCENDING)
+class ExitPipViaExpandButtonClickTestCfArm(flicker: FlickerTest) :
+ ExitPipViaExpandButtonClickTest(flicker) {
+ companion object {
+ /**
+ * Creates the test configurations.
+ *
+ * See [FlickerTestFactory.nonRotationTests] for configuring screen orientation and
+ * navigation modes.
+ */
+ @Parameterized.Parameters(name = "{0}")
+ @JvmStatic
+ fun getParams(): List<FlickerTest> {
+ return FlickerTestFactory.nonRotationTests(
+ supportedRotations = listOf(PlatformConsts.Rotation.ROTATION_0)
+ )
+ }
+ }
+}
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/ExpandPipOnDoubleClickTest.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/ExpandPipOnDoubleClickTest.kt
index f213cc9..c90c2d4 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/ExpandPipOnDoubleClickTest.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/ExpandPipOnDoubleClickTest.kt
@@ -16,7 +16,7 @@
package com.android.wm.shell.flicker.pip
-import android.platform.test.annotations.FlakyTest
+import android.platform.test.annotations.Presubmit
import androidx.test.filters.RequiresDevice
import com.android.server.wm.flicker.FlickerBuilder
import com.android.server.wm.flicker.FlickerTest
@@ -62,7 +62,7 @@
* Checks that the pip app window remains inside the display bounds throughout the whole
* animation
*/
- @FlakyTest(bugId = 249308003)
+ @Presubmit
@Test
fun pipWindowRemainInsideVisibleBounds() {
flicker.assertWmVisibleRegion(pipApp) { coversAtMost(displayBounds) }
@@ -72,28 +72,28 @@
* Checks that the pip app layer remains inside the display bounds throughout the whole
* animation
*/
- @FlakyTest(bugId = 249308003)
+ @Presubmit
@Test
fun pipLayerRemainInsideVisibleBounds() {
flicker.assertLayersVisibleRegion(pipApp) { coversAtMost(displayBounds) }
}
/** Checks [pipApp] window remains visible throughout the animation */
- @FlakyTest(bugId = 249308003)
+ @Presubmit
@Test
fun pipWindowIsAlwaysVisible() {
flicker.assertWm { isAppWindowVisible(pipApp) }
}
/** Checks [pipApp] layer remains visible throughout the animation */
- @FlakyTest(bugId = 249308003)
+ @Presubmit
@Test
fun pipLayerIsAlwaysVisible() {
flicker.assertLayers { isVisible(pipApp) }
}
/** Checks that the visible region of [pipApp] always expands during the animation */
- @FlakyTest(bugId = 249308003)
+ @Presubmit
@Test
fun pipLayerExpands() {
flicker.assertLayers {
@@ -104,7 +104,7 @@
}
}
- @FlakyTest(bugId = 249308003)
+ @Presubmit
@Test
fun pipSameAspectRatio() {
flicker.assertLayers {
@@ -116,92 +116,26 @@
}
/** Checks [pipApp] window remains pinned throughout the animation */
- @FlakyTest(bugId = 249308003)
+ @Presubmit
@Test
fun windowIsAlwaysPinned() {
flicker.assertWm { this.invoke("hasPipWindow") { it.isPinned(pipApp) } }
}
- /** Checks [ComponentMatcher.LAUNCHER] layer remains visible throughout the animation */
- @FlakyTest(bugId = 249308003)
+ /** Checks [ComponentNameMatcher.LAUNCHER] layer remains visible throughout the animation */
+ @Presubmit
@Test
fun launcherIsAlwaysVisible() {
flicker.assertLayers { isVisible(ComponentNameMatcher.LAUNCHER) }
}
/** Checks that the focus doesn't change between windows during the transition */
- @FlakyTest(bugId = 216306753)
+ @Presubmit
@Test
fun focusDoesNotChange() {
flicker.assertEventLog { this.focusDoesNotChange() }
}
- @FlakyTest(bugId = 216306753)
- @Test
- override fun navBarLayerIsVisibleAtStartAndEnd() {
- super.navBarLayerIsVisibleAtStartAndEnd()
- }
-
- @FlakyTest(bugId = 216306753)
- @Test
- override fun navBarWindowIsAlwaysVisible() {
- super.navBarWindowIsAlwaysVisible()
- }
-
- @FlakyTest(bugId = 216306753)
- @Test
- override fun statusBarLayerIsVisibleAtStartAndEnd() {
- super.statusBarLayerIsVisibleAtStartAndEnd()
- }
-
- @FlakyTest(bugId = 216306753)
- @Test
- override fun statusBarLayerPositionAtStartAndEnd() {
- super.statusBarLayerPositionAtStartAndEnd()
- }
-
- @FlakyTest(bugId = 216306753)
- @Test
- override fun taskBarLayerIsVisibleAtStartAndEnd() {
- super.taskBarLayerIsVisibleAtStartAndEnd()
- }
-
- @FlakyTest(bugId = 216306753)
- @Test
- override fun taskBarWindowIsAlwaysVisible() {
- super.taskBarWindowIsAlwaysVisible()
- }
-
- @FlakyTest(bugId = 216306753)
- @Test
- override fun visibleLayersShownMoreThanOneConsecutiveEntry() {
- super.visibleLayersShownMoreThanOneConsecutiveEntry()
- }
-
- @FlakyTest(bugId = 216306753)
- @Test
- override fun statusBarWindowIsAlwaysVisible() {
- super.statusBarWindowIsAlwaysVisible()
- }
-
- @FlakyTest(bugId = 216306753)
- @Test
- override fun visibleWindowsShownMoreThanOneConsecutiveEntry() {
- super.visibleWindowsShownMoreThanOneConsecutiveEntry()
- }
-
- @FlakyTest(bugId = 216306753)
- @Test
- override fun entireScreenCovered() {
- super.entireScreenCovered()
- }
-
- @FlakyTest(bugId = 216306753)
- @Test
- override fun navBarLayerPositionAtStartAndEnd() {
- super.navBarLayerPositionAtStartAndEnd()
- }
-
companion object {
/**
* Creates the test configurations.
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/ExpandPipOnPinchOpenTest.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/ExpandPipOnPinchOpenTest.kt
index 34f6659..cb2326c 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/ExpandPipOnPinchOpenTest.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/ExpandPipOnPinchOpenTest.kt
@@ -16,7 +16,7 @@
package com.android.wm.shell.flicker.pip
-import android.platform.test.annotations.Postsubmit
+import android.platform.test.annotations.Presubmit
import androidx.test.filters.RequiresDevice
import com.android.server.wm.flicker.FlickerBuilder
import com.android.server.wm.flicker.FlickerTest
@@ -39,7 +39,7 @@
get() = buildTransition { transitions { pipApp.pinchOpenPipWindow(wmHelper, 0.4f, 30) } }
/** Checks that the visible region area of [pipApp] always increases during the animation. */
- @Postsubmit
+ @Presubmit
@Test
fun pipLayerAreaIncreases() {
flicker.assertLayers {
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipKeyboardTest.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipKeyboardTest.kt
index 12d6362..737e65c 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipKeyboardTest.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipKeyboardTest.kt
@@ -58,7 +58,6 @@
}
teardown {
imeApp.exit(wmHelper)
- setRotation(PlatformConsts.Rotation.ROTATION_0)
}
transitions {
// open the soft keyboard
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipRotationTest.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipRotationTest.kt
index eee00bd..4557a15 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipRotationTest.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipRotationTest.kt
@@ -16,7 +16,6 @@
package com.android.wm.shell.flicker.pip
-import android.platform.test.annotations.FlakyTest
import android.platform.test.annotations.Presubmit
import androidx.test.filters.RequiresDevice
import com.android.server.wm.flicker.FlickerBuilder
@@ -24,11 +23,8 @@
import com.android.server.wm.flicker.FlickerTestFactory
import com.android.server.wm.flicker.helpers.SimpleAppHelper
import com.android.server.wm.flicker.helpers.WindowUtils
-import com.android.server.wm.flicker.helpers.isShellTransitionsEnabled
import com.android.server.wm.flicker.helpers.setRotation
import com.android.server.wm.flicker.junit.FlickerParametersRunnerFactory
-import org.junit.Assume
-import org.junit.Before
import org.junit.FixMethodOrder
import org.junit.Test
import org.junit.runner.RunWith
@@ -66,11 +62,6 @@
private val screenBoundsStart = WindowUtils.getDisplayBounds(flicker.scenario.startRotation)
private val screenBoundsEnd = WindowUtils.getDisplayBounds(flicker.scenario.endRotation)
- @Before
- open fun before() {
- Assume.assumeFalse(isShellTransitionsEnabled)
- }
-
override val transition: FlickerBuilder.() -> Unit
get() = buildTransition {
setup {
@@ -80,11 +71,6 @@
transitions { setRotation(flicker.scenario.endRotation) }
}
- /** Checks the position of the navigation bar at the start and end of the transition */
- @FlakyTest(bugId = 240499181)
- @Test
- override fun navBarLayerPositionAtStartAndEnd() = super.navBarLayerPositionAtStartAndEnd()
-
/** Checks that [testApp] layer is within [screenBoundsStart] at the start of the transition */
@Presubmit
@Test
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipRotationTest_ShellTransit.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipRotationTest_ShellTransit.kt
deleted file mode 100644
index d0d9167..0000000
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipRotationTest_ShellTransit.kt
+++ /dev/null
@@ -1,69 +0,0 @@
-/*
- * Copyright (C) 2020 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.wm.shell.flicker.pip
-
-import android.platform.test.annotations.FlakyTest
-import androidx.test.filters.RequiresDevice
-import com.android.server.wm.flicker.FlickerTest
-import com.android.server.wm.flicker.helpers.isShellTransitionsEnabled
-import com.android.server.wm.flicker.junit.FlickerParametersRunnerFactory
-import org.junit.Assume
-import org.junit.Before
-import org.junit.FixMethodOrder
-import org.junit.Test
-import org.junit.runner.RunWith
-import org.junit.runners.MethodSorters
-import org.junit.runners.Parameterized
-
-/**
- * Test Pip Stack in bounds after rotations.
- *
- * To run this test: `atest WMShellFlickerTests:PipRotationTest_ShellTransit`
- *
- * Actions:
- * ```
- * Launch a [pipApp] in pip mode
- * Launch another app [fixedApp] (appears below pip)
- * Rotate the screen from [flicker.scenario.startRotation] to [flicker.scenario.endRotation]
- * (usually, 0->90 and 90->0)
- * ```
- * Notes:
- * ```
- * 1. Some default assertions (e.g., nav bar, status bar and screen covered)
- * are inherited from [PipTransition]
- * 2. Part of the test setup occurs automatically via
- * [com.android.server.wm.flicker.TransitionRunnerWithRules],
- * including configuring navigation mode, initial orientation and ensuring no
- * apps are running before setup
- * ```
- */
-@RequiresDevice
-@RunWith(Parameterized::class)
-@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
-@FixMethodOrder(MethodSorters.NAME_ASCENDING)
-@FlakyTest(bugId = 239575053)
-class PipRotationTest_ShellTransit(flicker: FlickerTest) : PipRotationTest(flicker) {
- @Before
- override fun before() {
- Assume.assumeTrue(isShellTransitionsEnabled)
- }
-
- /** {@inheritDoc} */
- @FlakyTest
- @Test
- override fun navBarLayerPositionAtStartAndEnd() = super.navBarLayerPositionAtStartAndEnd()
-}
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipTransition.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipTransition.kt
index 0e0be79..1bf1354 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipTransition.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipTransition.kt
@@ -18,6 +18,7 @@
import android.app.Instrumentation
import android.content.Intent
+import android.platform.test.annotations.Postsubmit
import com.android.server.wm.flicker.FlickerBuilder
import com.android.server.wm.flicker.FlickerTest
import com.android.server.wm.flicker.helpers.PipAppHelper
@@ -25,8 +26,11 @@
import com.android.server.wm.flicker.helpers.setRotation
import com.android.server.wm.flicker.rules.RemoveAllTasksButHomeRule.Companion.removeAllTasksButHome
import com.android.server.wm.flicker.testapp.ActivityOptions
+import com.android.server.wm.traces.common.ComponentNameMatcher
import com.android.server.wm.traces.common.service.PlatformConsts
import com.android.wm.shell.flicker.BaseTest
+import com.google.common.truth.Truth
+import org.junit.Test
abstract class PipTransition(flicker: FlickerTest) : BaseTest(flicker) {
protected val pipApp = PipAppHelper(instrumentation)
@@ -56,7 +60,6 @@
* Gets a configuration that handles basic setup and teardown of pip tests and that launches the
* Pip app for test
*
- * @param eachRun If the pip app should be launched in each run (otherwise only 1x per test)
* @param stringExtras Arguments to pass to the PIP launch intent
* @param extraSpec Additional segment of flicker specification
*/
@@ -72,12 +75,27 @@
pipApp.launchViaIntentAndWaitForPip(wmHelper, stringExtras = stringExtras)
}
teardown {
- setRotation(PlatformConsts.Rotation.ROTATION_0)
- removeAllTasksButHome()
pipApp.exit(wmHelper)
}
extraSpec(this)
}
}
+
+ @Postsubmit
+ @Test
+ fun hasAtMostOnePipDismissOverlayWindow() {
+ val matcher = ComponentNameMatcher("", "pip-dismiss-overlay")
+ flicker.assertWm {
+ val overlaysPerState = trace.entries.map { entry ->
+ entry.windowStates.count { window ->
+ matcher.windowMatchesAnyOf(window)
+ } <= 1
+ }
+
+ Truth.assertWithMessage("Number of dismiss overlays per state")
+ .that(overlaysPerState)
+ .doesNotContain(false)
+ }
+ }
}
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/SetRequestedOrientationWhilePinnedTest.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/SetRequestedOrientationWhilePinnedTest.kt
index 7d5dd89..871515b 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/SetRequestedOrientationWhilePinnedTest.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/SetRequestedOrientationWhilePinnedTest.kt
@@ -25,11 +25,7 @@
import com.android.server.wm.flicker.FlickerTest
import com.android.server.wm.flicker.FlickerTestFactory
import com.android.server.wm.flicker.helpers.WindowUtils
-import com.android.server.wm.flicker.helpers.isShellTransitionsEnabled
-import com.android.server.wm.flicker.helpers.setRotation
-import com.android.server.wm.flicker.helpers.wakeUpAndGoToHomeScreen
import com.android.server.wm.flicker.junit.FlickerParametersRunnerFactory
-import com.android.server.wm.flicker.rules.RemoveAllTasksButHomeRule.Companion.removeAllTasksButHome
import com.android.server.wm.flicker.testapp.ActivityOptions
import com.android.server.wm.flicker.testapp.ActivityOptions.PortraitOnlyActivity.EXTRA_FIXED_ORIENTATION
import com.android.server.wm.traces.common.service.PlatformConsts
@@ -58,9 +54,6 @@
override val transition: FlickerBuilder.() -> Unit
get() = {
setup {
- removeAllTasksButHome()
- device.wakeUpAndGoToHomeScreen()
-
// Launch the PiP activity fixed as landscape.
pipApp.launchViaIntent(
wmHelper,
@@ -80,8 +73,6 @@
}
teardown {
pipApp.exit(wmHelper)
- setRotation(PlatformConsts.Rotation.ROTATION_0)
- removeAllTasksButHome()
}
transitions {
// Launch the activity back into fullscreen and ensure that it is now in landscape
@@ -112,22 +103,6 @@
flicker.assertWmEnd { hasRotation(PlatformConsts.Rotation.ROTATION_90) }
}
- /** {@inheritDoc} */
- @Presubmit
- @Test
- override fun navBarLayerIsVisibleAtStartAndEnd() = super.navBarLayerIsVisibleAtStartAndEnd()
-
- /** {@inheritDoc} */
- @Presubmit
- @Test
- override fun statusBarLayerIsVisibleAtStartAndEnd() =
- super.statusBarLayerIsVisibleAtStartAndEnd()
-
- /** {@inheritDoc} */
- @FlakyTest
- @Test
- override fun navBarLayerPositionAtStartAndEnd() = super.navBarLayerPositionAtStartAndEnd()
-
@Presubmit
@Test
fun pipWindowInsideDisplay() {
@@ -140,22 +115,10 @@
flicker.assertWmEnd { isAppWindowOnTop(pipApp) }
}
- private fun pipLayerInsideDisplay_internal() {
- flicker.assertLayersStart { visibleRegion(pipApp).coversAtMost(startingBounds) }
- }
-
@Presubmit
@Test
fun pipLayerInsideDisplay() {
- Assume.assumeFalse(isShellTransitionsEnabled)
- pipLayerInsideDisplay_internal()
- }
-
- @FlakyTest(bugId = 250527829)
- @Test
- fun pipLayerInsideDisplay_shellTransit() {
- Assume.assumeTrue(isShellTransitionsEnabled)
- pipLayerInsideDisplay_internal()
+ flicker.assertLayersStart { visibleRegion(pipApp).coversAtMost(startingBounds) }
}
@Presubmit
@@ -181,7 +144,9 @@
override fun taskBarWindowIsAlwaysVisible() = super.taskBarWindowIsAlwaysVisible()
/** {@inheritDoc} */
- @Postsubmit @Test override fun entireScreenCovered() = super.entireScreenCovered()
+ @FlakyTest(bugId = 264243884)
+ @Test
+ override fun entireScreenCovered() = super.entireScreenCovered()
companion object {
@Parameterized.Parameters(name = "{0}")
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/tv/TvPipMenuTests.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/tv/TvPipMenuTests.kt
index 7403aab..0432a84 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/tv/TvPipMenuTests.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/tv/TvPipMenuTests.kt
@@ -31,22 +31,26 @@
@RequiresDevice
class TvPipMenuTests : TvPipTestBase() {
- private val systemUiResources =
+ private val systemUiResources by lazy {
packageManager.getResourcesForApplication(SYSTEM_UI_PACKAGE_NAME)
- private val pipBoundsWhileInMenu: Rect =
+ }
+ private val pipBoundsWhileInMenu: Rect by lazy {
systemUiResources.run {
val bounds =
getString(getIdentifier("pip_menu_bounds", "string", SYSTEM_UI_PACKAGE_NAME))
Rect.unflattenFromString(bounds) ?: error("Could not retrieve PiP menu bounds")
}
- private val playButtonDescription =
+ }
+ private val playButtonDescription by lazy {
systemUiResources.run {
getString(getIdentifier("pip_play", "string", SYSTEM_UI_PACKAGE_NAME))
}
- private val pauseButtonDescription =
+ }
+ private val pauseButtonDescription by lazy {
systemUiResources.run {
getString(getIdentifier("pip_pause", "string", SYSTEM_UI_PACKAGE_NAME))
}
+ }
@Before
fun tvPipMenuTestsTestUp() {
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/CopyContentInSplit.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/CopyContentInSplit.kt
index 65cbea0..c08ad69 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/CopyContentInSplit.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/CopyContentInSplit.kt
@@ -16,7 +16,6 @@
package com.android.wm.shell.flicker.splitscreen
-import android.platform.test.annotations.FlakyTest
import android.platform.test.annotations.IwTest
import android.platform.test.annotations.Presubmit
import androidx.test.filters.RequiresDevice
@@ -116,46 +115,6 @@
/** {@inheritDoc} */
@Presubmit @Test override fun entireScreenCovered() = super.entireScreenCovered()
- /** {@inheritDoc} */
- @Presubmit
- @Test
- override fun navBarLayerIsVisibleAtStartAndEnd() = super.navBarLayerIsVisibleAtStartAndEnd()
-
- /** {@inheritDoc} */
- @FlakyTest(bugId = 206753786)
- @Test
- override fun navBarLayerPositionAtStartAndEnd() = super.navBarLayerPositionAtStartAndEnd()
-
- /** {@inheritDoc} */
- @Presubmit
- @Test
- override fun navBarWindowIsAlwaysVisible() = super.navBarWindowIsAlwaysVisible()
-
- /** {@inheritDoc} */
- @Presubmit
- @Test
- override fun statusBarLayerIsVisibleAtStartAndEnd() =
- super.statusBarLayerIsVisibleAtStartAndEnd()
-
- /** {@inheritDoc} */
- @Presubmit
- @Test
- override fun statusBarLayerPositionAtStartAndEnd() = super.statusBarLayerPositionAtStartAndEnd()
-
- /** {@inheritDoc} */
- @Presubmit
- @Test
- override fun statusBarWindowIsAlwaysVisible() = super.statusBarWindowIsAlwaysVisible()
-
- /** {@inheritDoc} */
- @Presubmit
- @Test
- override fun taskBarLayerIsVisibleAtStartAndEnd() = super.taskBarLayerIsVisibleAtStartAndEnd()
-
- /** {@inheritDoc} */
- @Presubmit
- @Test
- override fun taskBarWindowIsAlwaysVisible() = super.taskBarWindowIsAlwaysVisible()
/** {@inheritDoc} */
@Presubmit
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/DragDividerToResize.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/DragDividerToResize.kt
index fcdad96..514365f 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/DragDividerToResize.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/DragDividerToResize.kt
@@ -18,7 +18,6 @@
import android.platform.test.annotations.FlakyTest
import android.platform.test.annotations.IwTest
-import android.platform.test.annotations.Postsubmit
import android.platform.test.annotations.Presubmit
import androidx.test.filters.RequiresDevice
import com.android.server.wm.flicker.FlickerBuilder
@@ -149,60 +148,9 @@
)
/** {@inheritDoc} */
- @Postsubmit @Test override fun entireScreenCovered() = super.entireScreenCovered()
-
- /** {@inheritDoc} */
- @Postsubmit
+ @FlakyTest(bugId = 263213649)
@Test
- override fun navBarLayerIsVisibleAtStartAndEnd() = super.navBarLayerIsVisibleAtStartAndEnd()
-
- /** {@inheritDoc} */
- @Postsubmit
- @Test
- override fun navBarLayerPositionAtStartAndEnd() = super.navBarLayerPositionAtStartAndEnd()
-
- /** {@inheritDoc} */
- @Postsubmit
- @Test
- override fun navBarWindowIsAlwaysVisible() = super.navBarWindowIsAlwaysVisible()
-
- /** {@inheritDoc} */
- @Postsubmit
- @Test
- override fun statusBarLayerIsVisibleAtStartAndEnd() =
- super.statusBarLayerIsVisibleAtStartAndEnd()
-
- /** {@inheritDoc} */
- @Postsubmit
- @Test
- override fun statusBarLayerPositionAtStartAndEnd() = super.statusBarLayerPositionAtStartAndEnd()
-
- /** {@inheritDoc} */
- @Postsubmit
- @Test
- override fun statusBarWindowIsAlwaysVisible() = super.statusBarWindowIsAlwaysVisible()
-
- /** {@inheritDoc} */
- @Postsubmit
- @Test
- override fun taskBarLayerIsVisibleAtStartAndEnd() = super.taskBarLayerIsVisibleAtStartAndEnd()
-
- /** {@inheritDoc} */
- @Postsubmit
- @Test
- override fun taskBarWindowIsAlwaysVisible() = super.taskBarWindowIsAlwaysVisible()
-
- /** {@inheritDoc} */
- @Postsubmit
- @Test
- override fun visibleLayersShownMoreThanOneConsecutiveEntry() =
- super.visibleLayersShownMoreThanOneConsecutiveEntry()
-
- /** {@inheritDoc} */
- @Postsubmit
- @Test
- override fun visibleWindowsShownMoreThanOneConsecutiveEntry() =
- super.visibleWindowsShownMoreThanOneConsecutiveEntry()
+ override fun entireScreenCovered() = super.entireScreenCovered()
companion object {
@Parameterized.Parameters(name = "{0}")
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/EnterSplitScreenByDragFromShortcut.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/EnterSplitScreenByDragFromShortcut.kt
index af63f7c..d086f7e 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/EnterSplitScreenByDragFromShortcut.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/EnterSplitScreenByDragFromShortcut.kt
@@ -16,8 +16,8 @@
package com.android.wm.shell.flicker.splitscreen
+import android.platform.test.annotations.FlakyTest
import android.platform.test.annotations.IwTest
-import android.platform.test.annotations.Postsubmit
import android.platform.test.annotations.Presubmit
import androidx.test.filters.RequiresDevice
import com.android.server.wm.flicker.FlickerBuilder
@@ -126,60 +126,9 @@
}
/** {@inheritDoc} */
- @Postsubmit @Test override fun entireScreenCovered() = super.entireScreenCovered()
-
- /** {@inheritDoc} */
- @Postsubmit
+ @FlakyTest(bugId = 241523824)
@Test
- override fun navBarLayerIsVisibleAtStartAndEnd() = super.navBarLayerIsVisibleAtStartAndEnd()
-
- /** {@inheritDoc} */
- @Postsubmit
- @Test
- override fun navBarLayerPositionAtStartAndEnd() = super.navBarLayerPositionAtStartAndEnd()
-
- /** {@inheritDoc} */
- @Postsubmit
- @Test
- override fun navBarWindowIsAlwaysVisible() = super.navBarWindowIsAlwaysVisible()
-
- /** {@inheritDoc} */
- @Postsubmit
- @Test
- override fun statusBarLayerIsVisibleAtStartAndEnd() =
- super.statusBarLayerIsVisibleAtStartAndEnd()
-
- /** {@inheritDoc} */
- @Postsubmit
- @Test
- override fun statusBarLayerPositionAtStartAndEnd() = super.statusBarLayerPositionAtStartAndEnd()
-
- /** {@inheritDoc} */
- @Postsubmit
- @Test
- override fun statusBarWindowIsAlwaysVisible() = super.statusBarWindowIsAlwaysVisible()
-
- /** {@inheritDoc} */
- @Postsubmit
- @Test
- override fun taskBarLayerIsVisibleAtStartAndEnd() = super.taskBarLayerIsVisibleAtStartAndEnd()
-
- /** {@inheritDoc} */
- @Postsubmit
- @Test
- override fun taskBarWindowIsAlwaysVisible() = super.taskBarWindowIsAlwaysVisible()
-
- /** {@inheritDoc} */
- @Postsubmit
- @Test
- override fun visibleLayersShownMoreThanOneConsecutiveEntry() =
- super.visibleLayersShownMoreThanOneConsecutiveEntry()
-
- /** {@inheritDoc} */
- @Postsubmit
- @Test
- override fun visibleWindowsShownMoreThanOneConsecutiveEntry() =
- super.visibleWindowsShownMoreThanOneConsecutiveEntry()
+ override fun entireScreenCovered() = super.entireScreenCovered()
companion object {
@Parameterized.Parameters(name = "{0}")
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/EnterSplitScreenFromOverview.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/EnterSplitScreenFromOverview.kt
index c09ca91..a9cbb74 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/EnterSplitScreenFromOverview.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/EnterSplitScreenFromOverview.kt
@@ -18,13 +18,11 @@
import android.platform.test.annotations.FlakyTest
import android.platform.test.annotations.IwTest
-import android.platform.test.annotations.Postsubmit
import android.platform.test.annotations.Presubmit
import androidx.test.filters.RequiresDevice
import com.android.server.wm.flicker.FlickerBuilder
import com.android.server.wm.flicker.FlickerTest
import com.android.server.wm.flicker.FlickerTestFactory
-import com.android.server.wm.flicker.helpers.isShellTransitionsEnabled
import com.android.server.wm.flicker.junit.FlickerParametersRunnerFactory
import com.android.wm.shell.flicker.appWindowBecomesVisible
import com.android.wm.shell.flicker.layerBecomesVisible
@@ -33,7 +31,6 @@
import com.android.wm.shell.flicker.splitAppLayerBoundsIsVisibleAtEnd
import com.android.wm.shell.flicker.splitScreenDividerBecomesVisible
import com.android.wm.shell.flicker.splitScreenEntered
-import org.junit.Assume
import org.junit.FixMethodOrder
import org.junit.Test
import org.junit.runner.RunWith
@@ -96,18 +93,6 @@
@Presubmit
@Test
fun secondaryAppBoundsBecomesVisible() {
- Assume.assumeFalse(isShellTransitionsEnabled)
- flicker.splitAppLayerBoundsBecomesVisible(
- secondaryApp,
- landscapePosLeft = !tapl.isTablet,
- portraitPosTop = true
- )
- }
-
- @FlakyTest(bugId = 244407465)
- @Test
- fun secondaryAppBoundsBecomesVisible_shellTransit() {
- Assume.assumeTrue(isShellTransitionsEnabled)
flicker.splitAppLayerBoundsBecomesVisible(
secondaryApp,
landscapePosLeft = !tapl.isTablet,
@@ -129,58 +114,11 @@
override fun entireScreenCovered() = super.entireScreenCovered()
/** {@inheritDoc} */
- @Presubmit
- @Test
- override fun navBarLayerIsVisibleAtStartAndEnd() = super.navBarLayerIsVisibleAtStartAndEnd()
-
- /** {@inheritDoc} */
- @Postsubmit
- @Test
- override fun navBarLayerPositionAtStartAndEnd() = super.navBarLayerPositionAtStartAndEnd()
-
- /** {@inheritDoc} */
- @Presubmit
- @Test
- override fun navBarWindowIsAlwaysVisible() = super.navBarWindowIsAlwaysVisible()
-
- /** {@inheritDoc} */
- @Presubmit
- @Test
- override fun statusBarLayerIsVisibleAtStartAndEnd() =
- super.statusBarLayerIsVisibleAtStartAndEnd()
-
- /** {@inheritDoc} */
- @Presubmit
- @Test
- override fun statusBarLayerPositionAtStartAndEnd() = super.statusBarLayerPositionAtStartAndEnd()
-
- /** {@inheritDoc} */
- @Presubmit
- @Test
- override fun statusBarWindowIsAlwaysVisible() = super.statusBarWindowIsAlwaysVisible()
-
- /** {@inheritDoc} */
- @Presubmit
- @Test
- override fun taskBarLayerIsVisibleAtStartAndEnd() = super.taskBarLayerIsVisibleAtStartAndEnd()
-
- /** {@inheritDoc} */
- @Presubmit
- @Test
- override fun taskBarWindowIsAlwaysVisible() = super.taskBarWindowIsAlwaysVisible()
-
- /** {@inheritDoc} */
@FlakyTest(bugId = 252736515)
@Test
override fun visibleLayersShownMoreThanOneConsecutiveEntry() =
super.visibleLayersShownMoreThanOneConsecutiveEntry()
- /** {@inheritDoc} */
- @Presubmit
- @Test
- override fun visibleWindowsShownMoreThanOneConsecutiveEntry() =
- super.visibleWindowsShownMoreThanOneConsecutiveEntry()
-
companion object {
@Parameterized.Parameters(name = "{0}")
@JvmStatic
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/SwitchAppByDoubleTapDivider.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/SwitchAppByDoubleTapDivider.kt
index 09568b2..c7b81d9 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/SwitchAppByDoubleTapDivider.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/SwitchAppByDoubleTapDivider.kt
@@ -196,56 +196,9 @@
/** {@inheritDoc} */
@Postsubmit
@Test
- override fun navBarLayerIsVisibleAtStartAndEnd() = super.navBarLayerIsVisibleAtStartAndEnd()
-
- /** {@inheritDoc} */
- @Postsubmit
- @Test
- override fun navBarLayerPositionAtStartAndEnd() = super.navBarLayerPositionAtStartAndEnd()
-
- /** {@inheritDoc} */
- @Postsubmit
- @Test
- override fun navBarWindowIsAlwaysVisible() = super.navBarWindowIsAlwaysVisible()
-
- /** {@inheritDoc} */
- @Postsubmit
- @Test
- override fun statusBarLayerIsVisibleAtStartAndEnd() =
- super.statusBarLayerIsVisibleAtStartAndEnd()
-
- /** {@inheritDoc} */
- @Postsubmit
- @Test
- override fun statusBarLayerPositionAtStartAndEnd() = super.statusBarLayerPositionAtStartAndEnd()
-
- /** {@inheritDoc} */
- @Postsubmit
- @Test
- override fun statusBarWindowIsAlwaysVisible() = super.statusBarWindowIsAlwaysVisible()
-
- /** {@inheritDoc} */
- @Postsubmit
- @Test
- override fun taskBarLayerIsVisibleAtStartAndEnd() = super.taskBarLayerIsVisibleAtStartAndEnd()
-
- /** {@inheritDoc} */
- @Postsubmit
- @Test
- override fun taskBarWindowIsAlwaysVisible() = super.taskBarWindowIsAlwaysVisible()
-
- /** {@inheritDoc} */
- @Postsubmit
- @Test
override fun visibleLayersShownMoreThanOneConsecutiveEntry() =
super.visibleLayersShownMoreThanOneConsecutiveEntry()
- /** {@inheritDoc} */
- @Postsubmit
- @Test
- override fun visibleWindowsShownMoreThanOneConsecutiveEntry() =
- super.visibleWindowsShownMoreThanOneConsecutiveEntry()
-
companion object {
@Parameterized.Parameters(name = "{0}")
@JvmStatic
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/bubbles/BubbleDataTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/bubbles/BubbleDataTest.java
index e6711ac..8b025cd 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/bubbles/BubbleDataTest.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/bubbles/BubbleDataTest.java
@@ -16,6 +16,8 @@
package com.android.wm.shell.bubbles;
+import static com.android.wm.shell.bubbles.Bubble.KEY_APP_BUBBLE;
+
import static com.google.common.truth.Truth.assertThat;
import static com.google.common.truth.Truth.assertWithMessage;
@@ -32,6 +34,7 @@
import android.app.Notification;
import android.app.PendingIntent;
+import android.content.Intent;
import android.content.LocusId;
import android.graphics.drawable.Icon;
import android.os.Bundle;
@@ -94,6 +97,7 @@
private Bubble mBubbleInterruptive;
private Bubble mBubbleDismissed;
private Bubble mBubbleLocusId;
+ private Bubble mAppBubble;
private BubbleData mBubbleData;
private TestableBubblePositioner mPositioner;
@@ -178,6 +182,11 @@
mBubbleMetadataFlagListener,
mPendingIntentCanceledListener,
mMainExecutor);
+
+ Intent appBubbleIntent = new Intent(mContext, BubblesTestActivity.class);
+ appBubbleIntent.setPackage(mContext.getPackageName());
+ mAppBubble = new Bubble(appBubbleIntent, new UserHandle(1), mMainExecutor);
+
mPositioner = new TestableBubblePositioner(mContext,
mock(WindowManager.class));
mBubbleData = new BubbleData(getContext(), mBubbleLogger, mPositioner,
@@ -1089,6 +1098,18 @@
assertOverflowChangedTo(ImmutableList.of());
}
+ @Test
+ public void test_removeAppBubble_skipsOverflow() {
+ mBubbleData.notificationEntryUpdated(mAppBubble, true /* suppressFlyout*/,
+ false /* showInShade */);
+ assertThat(mBubbleData.getBubbleInStackWithKey(KEY_APP_BUBBLE)).isEqualTo(mAppBubble);
+
+ mBubbleData.dismissBubbleWithKey(KEY_APP_BUBBLE, Bubbles.DISMISS_USER_GESTURE);
+
+ assertThat(mBubbleData.getOverflowBubbleWithKey(KEY_APP_BUBBLE)).isNull();
+ assertThat(mBubbleData.getBubbleInStackWithKey(KEY_APP_BUBBLE)).isNull();
+ }
+
private void verifyUpdateReceived() {
verify(mListener).applyUpdate(mUpdateCaptor.capture());
reset(mListener);
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopModeControllerTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopModeControllerTest.java
index 08af3d3..35cc168 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopModeControllerTest.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopModeControllerTest.java
@@ -279,7 +279,7 @@
}
@Test
- public void testShowDesktopApps_appsAlreadyVisible_doesNothing() {
+ public void testShowDesktopApps_appsAlreadyVisible_bringsToFront() {
final RunningTaskInfo task1 = createFreeformTask();
mDesktopModeTaskRepository.addActiveTask(task1.taskId);
mDesktopModeTaskRepository.addOrMoveFreeformTaskToTop(task1.taskId);
@@ -294,8 +294,17 @@
mController.showDesktopApps();
final WindowContainerTransaction wct = getBringAppsToFrontTransaction();
- // No reordering needed.
- assertThat(wct.getHierarchyOps()).isEmpty();
+ // Check wct has reorder calls
+ assertThat(wct.getHierarchyOps()).hasSize(2);
+ // Task 1 appeared first, must be first reorder to top.
+ HierarchyOp op1 = wct.getHierarchyOps().get(0);
+ assertThat(op1.getType()).isEqualTo(HIERARCHY_OP_TYPE_REORDER);
+ assertThat(op1.getContainer()).isEqualTo(task1.token.asBinder());
+
+ // Task 2 appeared last, must be last reorder to top.
+ HierarchyOp op2 = wct.getHierarchyOps().get(1);
+ assertThat(op2.getType()).isEqualTo(HIERARCHY_OP_TYPE_REORDER);
+ assertThat(op2.getContainer()).isEqualTo(task2.token.asBinder());
}
@Test
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopTasksControllerTest.kt b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopTasksControllerTest.kt
index 9a92879..4011d08 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopTasksControllerTest.kt
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopTasksControllerTest.kt
@@ -150,8 +150,8 @@
}
@Test
- fun showDesktopApps_appsAlreadyVisible_doesNothing() {
- setUpHomeTask()
+ fun showDesktopApps_appsAlreadyVisible_bringsToFront() {
+ val homeTask = setUpHomeTask()
val task1 = setUpFreeformTask()
val task2 = setUpFreeformTask()
markTaskVisible(task1)
@@ -159,7 +159,12 @@
controller.showDesktopApps()
- verifyWCTNotExecuted()
+ val wct = getLatestWct()
+ assertThat(wct.hierarchyOps).hasSize(3)
+ // Expect order to be from bottom: home, task1, task2
+ wct.assertReorderAt(index = 0, homeTask)
+ wct.assertReorderAt(index = 1, task1)
+ wct.assertReorderAt(index = 2, task2)
}
@Test
@@ -207,6 +212,23 @@
}
@Test
+ fun moveToDesktop_otherFreeformTasksBroughtToFront() {
+ val homeTask = setUpHomeTask()
+ val freeformTask = setUpFreeformTask()
+ val fullscreenTask = setUpFullscreenTask()
+ markTaskHidden(freeformTask)
+
+ controller.moveToDesktop(fullscreenTask)
+
+ with(getLatestWct()) {
+ assertThat(hierarchyOps).hasSize(3)
+ assertReorderSequence(homeTask, freeformTask, fullscreenTask)
+ assertThat(changes[fullscreenTask.token.asBinder()]?.windowingMode)
+ .isEqualTo(WINDOWING_MODE_FREEFORM)
+ }
+ }
+
+ @Test
fun moveToFullscreen() {
val task = setUpFreeformTask()
controller.moveToFullscreen(task)
@@ -406,3 +428,9 @@
assertThat(op.type).isEqualTo(HIERARCHY_OP_TYPE_REORDER)
assertThat(op.container).isEqualTo(task.token.asBinder())
}
+
+private fun WindowContainerTransaction.assertReorderSequence(vararg tasks: RunningTaskInfo) {
+ for (i in tasks.indices) {
+ assertReorderAt(i, tasks[i])
+ }
+}
diff --git a/libs/hwui/Android.bp b/libs/hwui/Android.bp
index 59e4b7a..aeead5e 100644
--- a/libs/hwui/Android.bp
+++ b/libs/hwui/Android.bp
@@ -78,6 +78,7 @@
"external/skia/src/utils",
"external/skia/src/gpu",
"external/skia/src/shaders",
+ "external/skia/modules/skottie",
],
},
host: {
@@ -214,6 +215,15 @@
path: "apex/java",
}
+java_api_contribution {
+ name: "framework-graphics-public-stubs",
+ api_surface: "public",
+ api_file: "api/current.txt",
+ visibility: [
+ "//build/orchestrator/apis",
+ ],
+}
+
// ------------------------
// APEX
// ------------------------
@@ -375,6 +385,7 @@
"external/skia/src/effects",
"external/skia/src/image",
"external/skia/src/images",
+ "external/skia/modules/skottie",
],
shared_libs: [
@@ -402,6 +413,7 @@
"jni/BitmapRegionDecoder.cpp",
"jni/GIFMovie.cpp",
"jni/GraphicsStatsService.cpp",
+ "jni/LottieDrawable.cpp",
"jni/Movie.cpp",
"jni/MovieImpl.cpp",
"jni/pdf/PdfDocument.cpp",
@@ -509,6 +521,7 @@
"hwui/BlurDrawLooper.cpp",
"hwui/Canvas.cpp",
"hwui/ImageDecoder.cpp",
+ "hwui/LottieDrawable.cpp",
"hwui/MinikinSkia.cpp",
"hwui/MinikinUtils.cpp",
"hwui/PaintImpl.cpp",
diff --git a/libs/hwui/DeviceInfo.cpp b/libs/hwui/DeviceInfo.cpp
index 0240c86..32bc122 100644
--- a/libs/hwui/DeviceInfo.cpp
+++ b/libs/hwui/DeviceInfo.cpp
@@ -108,6 +108,10 @@
get()->mSupportFp16ForHdr = supportFp16ForHdr;
}
+void DeviceInfo::setSupportMixedColorSpaces(bool supportMixedColorSpaces) {
+ get()->mSupportMixedColorSpaces = supportMixedColorSpaces;
+}
+
void DeviceInfo::onRefreshRateChanged(int64_t vsyncPeriod) {
mVsyncPeriod = vsyncPeriod;
}
diff --git a/libs/hwui/DeviceInfo.h b/libs/hwui/DeviceInfo.h
index 577780b..d4af087 100644
--- a/libs/hwui/DeviceInfo.h
+++ b/libs/hwui/DeviceInfo.h
@@ -62,6 +62,9 @@
static void setSupportFp16ForHdr(bool supportFp16ForHdr);
static bool isSupportFp16ForHdr() { return get()->mSupportFp16ForHdr; };
+ static void setSupportMixedColorSpaces(bool supportMixedColorSpaces);
+ static bool isSupportMixedColorSpaces() { return get()->mSupportMixedColorSpaces; };
+
// this value is only valid after the GPU has been initialized and there is a valid graphics
// context or if you are using the HWUI_NULL_GPU
int maxTextureSize() const;
@@ -92,6 +95,7 @@
int mMaxTextureSize;
sk_sp<SkColorSpace> mWideColorSpace = SkColorSpace::MakeSRGB();
bool mSupportFp16ForHdr = false;
+ bool mSupportMixedColorSpaces = false;
SkColorType mWideColorType = SkColorType::kN32_SkColorType;
int mDisplaysSize = 0;
int mPhysicalDisplayIndex = -1;
diff --git a/libs/hwui/MemoryPolicy.h b/libs/hwui/MemoryPolicy.h
index 41ced8c..2f0f7f5 100644
--- a/libs/hwui/MemoryPolicy.h
+++ b/libs/hwui/MemoryPolicy.h
@@ -53,8 +53,8 @@
// Whether or not to only purge scratch resources when triggering UI Hidden or background
// collection
bool purgeScratchOnly = true;
- // EXPERIMENTAL: Whether or not to trigger releasing GPU context when all contexts are stopped
- bool releaseContextOnStoppedOnly = false;
+ // Whether or not to trigger releasing GPU context when all contexts are stopped
+ bool releaseContextOnStoppedOnly = true;
};
const MemoryPolicy& loadMemoryPolicy();
diff --git a/libs/hwui/Readback.cpp b/libs/hwui/Readback.cpp
index 8dcd6db..045de35 100644
--- a/libs/hwui/Readback.cpp
+++ b/libs/hwui/Readback.cpp
@@ -28,6 +28,7 @@
#include <SkRefCnt.h>
#include <SkSamplingOptions.h>
#include <SkSurface.h>
+#include "include/gpu/GpuTypes.h" // from Skia
#include <gui/TraceUtils.h>
#include <private/android/AHardwareBufferHelpers.h>
#include <shaders/shaders.h>
@@ -170,14 +171,15 @@
SkBitmap skBitmap = request->getDestinationBitmap(srcRect.width(), srcRect.height());
SkBitmap* bitmap = &skBitmap;
sk_sp<SkSurface> tmpSurface =
- SkSurface::MakeRenderTarget(mRenderThread.getGrContext(), SkBudgeted::kYes,
+ SkSurface::MakeRenderTarget(mRenderThread.getGrContext(), skgpu::Budgeted::kYes,
bitmap->info(), 0, kTopLeft_GrSurfaceOrigin, nullptr);
// if we can't generate a GPU surface that matches the destination bitmap (e.g. 565) then we
// attempt to do the intermediate rendering step in 8888
if (!tmpSurface.get()) {
SkImageInfo tmpInfo = bitmap->info().makeColorType(SkColorType::kN32_SkColorType);
- tmpSurface = SkSurface::MakeRenderTarget(mRenderThread.getGrContext(), SkBudgeted::kYes,
+ tmpSurface = SkSurface::MakeRenderTarget(mRenderThread.getGrContext(),
+ skgpu::Budgeted::kYes,
tmpInfo, 0, kTopLeft_GrSurfaceOrigin, nullptr);
if (!tmpSurface.get()) {
ALOGW("Unable to generate GPU buffer in a format compatible with the provided bitmap");
@@ -345,14 +347,17 @@
* software buffer.
*/
sk_sp<SkSurface> tmpSurface = SkSurface::MakeRenderTarget(mRenderThread.getGrContext(),
- SkBudgeted::kYes, bitmap->info(), 0,
+ skgpu::Budgeted::kYes,
+ bitmap->info(),
+ 0,
kTopLeft_GrSurfaceOrigin, nullptr);
// if we can't generate a GPU surface that matches the destination bitmap (e.g. 565) then we
// attempt to do the intermediate rendering step in 8888
if (!tmpSurface.get()) {
SkImageInfo tmpInfo = bitmap->info().makeColorType(SkColorType::kN32_SkColorType);
- tmpSurface = SkSurface::MakeRenderTarget(mRenderThread.getGrContext(), SkBudgeted::kYes,
+ tmpSurface = SkSurface::MakeRenderTarget(mRenderThread.getGrContext(),
+ skgpu::Budgeted::kYes,
tmpInfo, 0, kTopLeft_GrSurfaceOrigin, nullptr);
if (!tmpSurface.get()) {
ALOGW("Unable to generate GPU buffer in a format compatible with the provided bitmap");
diff --git a/libs/hwui/RecordingCanvas.cpp b/libs/hwui/RecordingCanvas.cpp
index 3f21940..e1030b0 100644
--- a/libs/hwui/RecordingCanvas.cpp
+++ b/libs/hwui/RecordingCanvas.cpp
@@ -44,6 +44,7 @@
#include "SkTextBlob.h"
#include "SkVertices.h"
#include "VectorDrawable.h"
+#include "include/gpu/GpuTypes.h" // from Skia
#include "pipeline/skia/AnimatedDrawables.h"
#include "pipeline/skia/FunctorDrawable.h"
@@ -570,7 +571,7 @@
GrRecordingContext* directContext = c->recordingContext();
mLayerImageInfo =
c->imageInfo().makeWH(deviceBounds.width(), deviceBounds.height());
- mLayerSurface = SkSurface::MakeRenderTarget(directContext, SkBudgeted::kYes,
+ mLayerSurface = SkSurface::MakeRenderTarget(directContext, skgpu::Budgeted::kYes,
mLayerImageInfo, 0,
kTopLeft_GrSurfaceOrigin, nullptr);
}
@@ -605,12 +606,17 @@
};
}
+static constexpr inline bool is_power_of_two(int value) {
+ return (value & (value - 1)) == 0;
+}
+
template <typename T, typename... Args>
void* DisplayListData::push(size_t pod, Args&&... args) {
size_t skip = SkAlignPtr(sizeof(T) + pod);
SkASSERT(skip < (1 << 24));
if (fUsed + skip > fReserved) {
- static_assert(SkIsPow2(SKLITEDL_PAGE), "This math needs updating for non-pow2.");
+ static_assert(is_power_of_two(SKLITEDL_PAGE),
+ "This math needs updating for non-pow2.");
// Next greater multiple of SKLITEDL_PAGE.
fReserved = (fUsed + skip + SKLITEDL_PAGE) & ~(SKLITEDL_PAGE - 1);
fBytes.realloc(fReserved);
diff --git a/libs/hwui/RecordingCanvas.h b/libs/hwui/RecordingCanvas.h
index 2539694..b7d4dc9 100644
--- a/libs/hwui/RecordingCanvas.h
+++ b/libs/hwui/RecordingCanvas.h
@@ -16,11 +16,13 @@
#pragma once
-#include "CanvasTransform.h"
-#include "hwui/Bitmap.h"
-#include "utils/Macros.h"
-#include "utils/TypeLogic.h"
+#include <SkRuntimeEffect.h>
+#include <log/log.h>
+#include <cstdlib>
+#include <vector>
+
+#include "CanvasTransform.h"
#include "SkCanvas.h"
#include "SkCanvasVirtualEnforcer.h"
#include "SkDrawable.h"
@@ -28,11 +30,11 @@
#include "SkPaint.h"
#include "SkPath.h"
#include "SkRect.h"
-
+#include "hwui/Bitmap.h"
#include "pipeline/skia/AnimatedDrawables.h"
-
-#include <SkRuntimeEffect.h>
-#include <vector>
+#include "utils/AutoMalloc.h"
+#include "utils/Macros.h"
+#include "utils/TypeLogic.h"
enum class SkBlendMode;
class SkRRect;
@@ -145,7 +147,7 @@
template <typename Fn, typename... Args>
void map(const Fn[], Args...) const;
- SkAutoTMalloc<uint8_t> fBytes;
+ AutoTMalloc<uint8_t> fBytes;
size_t fUsed = 0;
size_t fReserved = 0;
diff --git a/libs/hwui/SkiaCanvas.cpp b/libs/hwui/SkiaCanvas.cpp
index d83d78f..af8bd26 100644
--- a/libs/hwui/SkiaCanvas.cpp
+++ b/libs/hwui/SkiaCanvas.cpp
@@ -16,23 +16,12 @@
#include "SkiaCanvas.h"
-#include "CanvasProperty.h"
-#include "NinePatchUtils.h"
-#include "SkBlendMode.h"
-#include "VectorDrawable.h"
-#include "hwui/Bitmap.h"
-#include "hwui/MinikinUtils.h"
-#include "hwui/PaintFilter.h"
-#include "pipeline/skia/AnimatedDrawables.h"
-#include "pipeline/skia/HolePunch.h"
-
#include <SkAndroidFrameworkUtils.h>
#include <SkAnimatedImage.h>
#include <SkBitmap.h>
#include <SkCanvasPriv.h>
#include <SkCanvasStateUtils.h>
#include <SkColorFilter.h>
-#include <SkDeque.h>
#include <SkDrawable.h>
#include <SkFont.h>
#include <SkGraphics.h>
@@ -41,8 +30,8 @@
#include <SkMatrix.h>
#include <SkPaint.h>
#include <SkPicture.h>
-#include <SkRSXform.h>
#include <SkRRect.h>
+#include <SkRSXform.h>
#include <SkRect.h>
#include <SkRefCnt.h>
#include <SkShader.h>
@@ -54,6 +43,16 @@
#include <optional>
#include <utility>
+#include "CanvasProperty.h"
+#include "NinePatchUtils.h"
+#include "SkBlendMode.h"
+#include "VectorDrawable.h"
+#include "hwui/Bitmap.h"
+#include "hwui/MinikinUtils.h"
+#include "hwui/PaintFilter.h"
+#include "pipeline/skia/AnimatedDrawables.h"
+#include "pipeline/skia/HolePunch.h"
+
namespace android {
using uirenderer::PaintUtils;
@@ -176,7 +175,7 @@
// operation. It does this by explicitly saving off the clip & matrix state
// when requested and playing it back after the SkCanvas::restore.
void SkiaCanvas::restore() {
- const auto* rec = this->currentSaveRec();
+ const SaveRec* rec = this->currentSaveRec();
if (!rec) {
// Fast path - no record for this frame.
mCanvas->restore();
@@ -245,7 +244,9 @@
}
const SkiaCanvas::SaveRec* SkiaCanvas::currentSaveRec() const {
- const SaveRec* rec = mSaveStack ? static_cast<const SaveRec*>(mSaveStack->back()) : nullptr;
+ const SaveRec* rec = (mSaveStack && !mSaveStack->empty())
+ ? static_cast<const SaveRec*>(&mSaveStack->back())
+ : nullptr;
int currentSaveCount = mCanvas->getSaveCount();
SkASSERT(!rec || currentSaveCount >= rec->saveCount);
@@ -277,13 +278,12 @@
}
if (!mSaveStack) {
- mSaveStack.reset(new SkDeque(sizeof(struct SaveRec), 8));
+ mSaveStack.reset(new std::deque<SaveRec>());
}
- SaveRec* rec = static_cast<SaveRec*>(mSaveStack->push_back());
- rec->saveCount = mCanvas->getSaveCount();
- rec->saveFlags = flags;
- rec->clipIndex = mClipStack.size();
+ mSaveStack->emplace_back(mCanvas->getSaveCount(), // saveCount
+ flags, // saveFlags
+ mClipStack.size()); // clipIndex
}
template <typename T>
@@ -314,7 +314,7 @@
// If the current/post-restore save rec is also persisting clips, we
// leave them on the stack to be reapplied part of the next restore().
// Otherwise we're done and just pop them.
- const auto* rec = this->currentSaveRec();
+ const SaveRec* rec = this->currentSaveRec();
if (!rec || (rec->saveFlags & SaveFlags::Clip)) {
mClipStack.erase(begin, end);
}
@@ -736,6 +736,10 @@
return imgDrawable->drawStaging(mCanvas);
}
+void SkiaCanvas::drawLottie(LottieDrawable* lottieDrawable) {
+ lottieDrawable->drawStaging(mCanvas);
+}
+
void SkiaCanvas::drawVectorDrawable(VectorDrawableRoot* vectorDrawable) {
vectorDrawable->drawStaging(this);
}
diff --git a/libs/hwui/SkiaCanvas.h b/libs/hwui/SkiaCanvas.h
index 31e3b4c..1524dff 100644
--- a/libs/hwui/SkiaCanvas.h
+++ b/libs/hwui/SkiaCanvas.h
@@ -19,20 +19,19 @@
#ifdef __ANDROID__ // Layoutlib does not support hardware acceleration
#include "DeferredLayerUpdater.h"
#endif
-#include "RenderNode.h"
-#include "VectorDrawable.h"
-#include "hwui/Canvas.h"
-#include "hwui/Paint.h"
-#include "hwui/BlurDrawLooper.h"
-
#include <SkCanvas.h>
-#include <SkDeque.h>
-#include "pipeline/skia/AnimatedDrawables.h"
-#include "src/core/SkArenaAlloc.h"
#include <cassert>
+#include <deque>
#include <optional>
+#include "RenderNode.h"
+#include "VectorDrawable.h"
+#include "hwui/BlurDrawLooper.h"
+#include "hwui/Canvas.h"
+#include "hwui/Paint.h"
+#include "pipeline/skia/AnimatedDrawables.h"
+
enum class SkBlendMode;
class SkRRect;
@@ -145,6 +144,7 @@
float dstTop, float dstRight, float dstBottom,
const Paint* paint) override;
virtual double drawAnimatedImage(AnimatedImageDrawable* imgDrawable) override;
+ virtual void drawLottie(LottieDrawable* lottieDrawable) override;
virtual void drawVectorDrawable(VectorDrawableRoot* vectorDrawable) override;
@@ -211,6 +211,9 @@
int saveCount;
SaveFlags::Flags saveFlags;
size_t clipIndex;
+
+ SaveRec(int saveCount, SaveFlags::Flags saveFlags, size_t clipIndex)
+ : saveCount(saveCount), saveFlags(saveFlags), clipIndex(clipIndex) {}
};
const SaveRec* currentSaveRec() const;
@@ -224,11 +227,11 @@
class Clip;
- std::unique_ptr<SkCanvas> mCanvasOwned; // might own a canvas we allocated
- SkCanvas* mCanvas; // we do NOT own this canvas, it must survive us
- // unless it is the same as mCanvasOwned.get()
- std::unique_ptr<SkDeque> mSaveStack; // lazily allocated, tracks partial saves.
- std::vector<Clip> mClipStack; // tracks persistent clips.
+ std::unique_ptr<SkCanvas> mCanvasOwned; // Might own a canvas we allocated.
+ SkCanvas* mCanvas; // We do NOT own this canvas, it must survive us
+ // unless it is the same as mCanvasOwned.get().
+ std::unique_ptr<std::deque<SaveRec>> mSaveStack; // Lazily allocated, tracks partial saves.
+ std::vector<Clip> mClipStack; // Tracks persistent clips.
sk_sp<PaintFilter> mPaintFilter;
};
diff --git a/libs/hwui/SkiaInterpolator.cpp b/libs/hwui/SkiaInterpolator.cpp
index b28b15a..47bd0b9 100644
--- a/libs/hwui/SkiaInterpolator.cpp
+++ b/libs/hwui/SkiaInterpolator.cpp
@@ -20,9 +20,10 @@
#include "include/core/SkScalar.h"
#include "include/core/SkTypes.h"
#include "include/private/SkFixed.h"
-#include "include/private/SkMalloc.h"
#include "src/core/SkTSearch.h"
+#include <log/log.h>
+
typedef int Dot14;
#define Dot14_ONE (1 << 14)
#define Dot14_HALF (1 << 13)
@@ -96,7 +97,7 @@
SkiaInterpolatorBase::~SkiaInterpolatorBase() {
if (fStorage) {
- sk_free(fStorage);
+ free(fStorage);
}
}
@@ -106,7 +107,7 @@
fFrameCount = static_cast<int16_t>(frameCount);
fRepeat = SK_Scalar1;
if (fStorage) {
- sk_free(fStorage);
+ free(fStorage);
fStorage = nullptr;
fTimes = nullptr;
}
@@ -213,7 +214,10 @@
void SkiaInterpolator::reset(int elemCount, int frameCount) {
INHERITED::reset(elemCount, frameCount);
- fStorage = sk_malloc_throw((sizeof(float) * elemCount + sizeof(SkTimeCode)) * frameCount);
+ size_t numBytes = (sizeof(float) * elemCount + sizeof(SkTimeCode)) * frameCount;
+ fStorage = malloc(numBytes);
+ LOG_ALWAYS_FATAL_IF(!fStorage, "Failed to allocate %zu bytes in %s",
+ numBytes, __func__);
fTimes = (SkTimeCode*)fStorage;
fValues = (float*)((char*)fStorage + sizeof(SkTimeCode) * frameCount);
}
diff --git a/libs/hwui/apex/jni_runtime.cpp b/libs/hwui/apex/jni_runtime.cpp
index f57d80c..b1aa1947 100644
--- a/libs/hwui/apex/jni_runtime.cpp
+++ b/libs/hwui/apex/jni_runtime.cpp
@@ -37,6 +37,7 @@
extern int register_android_graphics_Graphics(JNIEnv* env);
extern int register_android_graphics_ImageDecoder(JNIEnv*);
extern int register_android_graphics_drawable_AnimatedImageDrawable(JNIEnv*);
+extern int register_android_graphics_drawable_LottieDrawable(JNIEnv*);
extern int register_android_graphics_Interpolator(JNIEnv* env);
extern int register_android_graphics_MaskFilter(JNIEnv* env);
extern int register_android_graphics_Movie(JNIEnv* env);
@@ -117,6 +118,7 @@
REG_JNI(register_android_graphics_HardwareRendererObserver),
REG_JNI(register_android_graphics_ImageDecoder),
REG_JNI(register_android_graphics_drawable_AnimatedImageDrawable),
+ REG_JNI(register_android_graphics_drawable_LottieDrawable),
REG_JNI(register_android_graphics_Interpolator),
REG_JNI(register_android_graphics_MaskFilter),
REG_JNI(register_android_graphics_Matrix),
diff --git a/libs/hwui/hwui/Canvas.h b/libs/hwui/hwui/Canvas.h
index 2a20191..07e2fe2 100644
--- a/libs/hwui/hwui/Canvas.h
+++ b/libs/hwui/hwui/Canvas.h
@@ -60,6 +60,7 @@
typedef std::function<void(uint16_t* text, float* positions)> ReadGlyphFunc;
class AnimatedImageDrawable;
+class LottieDrawable;
class Bitmap;
class Paint;
struct Typeface;
@@ -242,6 +243,7 @@
const Paint* paint) = 0;
virtual double drawAnimatedImage(AnimatedImageDrawable* imgDrawable) = 0;
+ virtual void drawLottie(LottieDrawable* lottieDrawable) = 0;
virtual void drawPicture(const SkPicture& picture) = 0;
/**
diff --git a/libs/hwui/hwui/LottieDrawable.cpp b/libs/hwui/hwui/LottieDrawable.cpp
new file mode 100644
index 0000000..92dc51e
--- /dev/null
+++ b/libs/hwui/hwui/LottieDrawable.cpp
@@ -0,0 +1,83 @@
+/*
+ * 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.
+ */
+
+#include "LottieDrawable.h"
+
+#include <SkTime.h>
+#include <log/log.h>
+#include <pipeline/skia/SkiaUtils.h>
+
+namespace android {
+
+sk_sp<LottieDrawable> LottieDrawable::Make(sk_sp<skottie::Animation> animation, size_t bytesUsed) {
+ if (animation) {
+ return sk_sp<LottieDrawable>(new LottieDrawable(std::move(animation), bytesUsed));
+ }
+ return nullptr;
+}
+LottieDrawable::LottieDrawable(sk_sp<skottie::Animation> animation, size_t bytesUsed)
+ : mAnimation(std::move(animation)), mBytesUsed(bytesUsed) {}
+
+bool LottieDrawable::start() {
+ if (mRunning) {
+ return false;
+ }
+
+ mRunning = true;
+ return true;
+}
+
+bool LottieDrawable::stop() {
+ bool wasRunning = mRunning;
+ mRunning = false;
+ return wasRunning;
+}
+
+bool LottieDrawable::isRunning() {
+ return mRunning;
+}
+
+// TODO: Check to see if drawable is actually dirty
+bool LottieDrawable::isDirty() {
+ return true;
+}
+
+void LottieDrawable::onDraw(SkCanvas* canvas) {
+ if (mRunning) {
+ const nsecs_t currentTime = systemTime(SYSTEM_TIME_MONOTONIC);
+
+ nsecs_t t = 0;
+ if (mStartTime == 0) {
+ mStartTime = currentTime;
+ } else {
+ t = currentTime - mStartTime;
+ }
+ double seekTime = std::fmod((double)t * 1e-9, mAnimation->duration());
+ mAnimation->seekFrameTime(seekTime);
+ mAnimation->render(canvas);
+ }
+}
+
+void LottieDrawable::drawStaging(SkCanvas* canvas) {
+ onDraw(canvas);
+}
+
+SkRect LottieDrawable::onGetBounds() {
+ // We do not actually know the bounds, so give a conservative answer.
+ return SkRectMakeLargest();
+}
+
+} // namespace android
diff --git a/libs/hwui/hwui/LottieDrawable.h b/libs/hwui/hwui/LottieDrawable.h
new file mode 100644
index 0000000..9cc34bf
--- /dev/null
+++ b/libs/hwui/hwui/LottieDrawable.h
@@ -0,0 +1,67 @@
+/*
+ * 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.
+ */
+
+#pragma once
+
+#include <SkDrawable.h>
+#include <Skottie.h>
+#include <utils/Timers.h>
+
+class SkCanvas;
+
+namespace android {
+
+/**
+ * Native component of android.graphics.drawable.LottieDrawable.java.
+ * This class can be drawn into Canvas.h and maintains the state needed to drive
+ * the animation from the RenderThread.
+ */
+class LottieDrawable : public SkDrawable {
+public:
+ static sk_sp<LottieDrawable> Make(sk_sp<skottie::Animation> animation, size_t bytes);
+
+ // Draw to software canvas
+ void drawStaging(SkCanvas* canvas);
+
+ // Returns true if the animation was started; false otherwise (e.g. it was
+ // already running)
+ bool start();
+ // Returns true if the animation was stopped; false otherwise (e.g. it was
+ // already stopped)
+ bool stop();
+ bool isRunning();
+
+ // TODO: Is dirty should take in a time til next frame to determine if it is dirty
+ bool isDirty();
+
+ SkRect onGetBounds() override;
+
+ size_t byteSize() const { return sizeof(*this) + mBytesUsed; }
+
+protected:
+ void onDraw(SkCanvas* canvas) override;
+
+private:
+ LottieDrawable(sk_sp<skottie::Animation> animation, size_t bytes_used);
+
+ sk_sp<skottie::Animation> mAnimation;
+ bool mRunning = false;
+ // The start time for the drawable itself.
+ nsecs_t mStartTime = 0;
+ const size_t mBytesUsed = 0;
+};
+
+} // namespace android
diff --git a/libs/hwui/jni/LottieDrawable.cpp b/libs/hwui/jni/LottieDrawable.cpp
new file mode 100644
index 0000000..fb6eede
--- /dev/null
+++ b/libs/hwui/jni/LottieDrawable.cpp
@@ -0,0 +1,91 @@
+/*
+ * 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.
+ */
+
+#include <SkRect.h>
+#include <Skottie.h>
+#include <hwui/Canvas.h>
+#include <hwui/LottieDrawable.h>
+
+#include "GraphicsJNI.h"
+#include "Utils.h"
+
+using namespace android;
+
+static jclass gLottieDrawableClass;
+
+static jlong LottieDrawable_nCreate(JNIEnv* env, jobject, jstring jjson) {
+ const ScopedUtfChars cstr(env, jjson);
+ // TODO(b/259267150) provide more accurate byteSize
+ size_t bytes = strlen(cstr.c_str());
+ auto animation = skottie::Animation::Builder().make(cstr.c_str(), bytes);
+ sk_sp<LottieDrawable> drawable(LottieDrawable::Make(std::move(animation), bytes));
+ if (!drawable) {
+ return 0;
+ }
+ return reinterpret_cast<jlong>(drawable.release());
+}
+
+static void LottieDrawable_destruct(LottieDrawable* drawable) {
+ SkSafeUnref(drawable);
+}
+
+static jlong LottieDrawable_nGetNativeFinalizer(JNIEnv* /*env*/, jobject /*clazz*/) {
+ return static_cast<jlong>(reinterpret_cast<uintptr_t>(&LottieDrawable_destruct));
+}
+
+static void LottieDrawable_nDraw(JNIEnv* env, jobject /*clazz*/, jlong nativePtr, jlong canvasPtr) {
+ auto* drawable = reinterpret_cast<LottieDrawable*>(nativePtr);
+ auto* canvas = reinterpret_cast<Canvas*>(canvasPtr);
+ canvas->drawLottie(drawable);
+}
+
+static jboolean LottieDrawable_nIsRunning(JNIEnv* env, jobject /*clazz*/, jlong nativePtr) {
+ auto* drawable = reinterpret_cast<LottieDrawable*>(nativePtr);
+ return drawable->isRunning();
+}
+
+static jboolean LottieDrawable_nStart(JNIEnv* env, jobject /*clazz*/, jlong nativePtr) {
+ auto* drawable = reinterpret_cast<LottieDrawable*>(nativePtr);
+ return drawable->start();
+}
+
+static jboolean LottieDrawable_nStop(JNIEnv* env, jobject /*clazz*/, jlong nativePtr) {
+ auto* drawable = reinterpret_cast<LottieDrawable*>(nativePtr);
+ return drawable->stop();
+}
+
+static jlong LottieDrawable_nNativeByteSize(JNIEnv* env, jobject /*clazz*/, jlong nativePtr) {
+ auto* drawable = reinterpret_cast<LottieDrawable*>(nativePtr);
+ return drawable->byteSize();
+}
+
+static const JNINativeMethod gLottieDrawableMethods[] = {
+ {"nCreate", "(Ljava/lang/String;)J", (void*)LottieDrawable_nCreate},
+ {"nNativeByteSize", "(J)J", (void*)LottieDrawable_nNativeByteSize},
+ {"nGetNativeFinalizer", "()J", (void*)LottieDrawable_nGetNativeFinalizer},
+ {"nDraw", "(JJ)V", (void*)LottieDrawable_nDraw},
+ {"nIsRunning", "(J)Z", (void*)LottieDrawable_nIsRunning},
+ {"nStart", "(J)Z", (void*)LottieDrawable_nStart},
+ {"nStop", "(J)Z", (void*)LottieDrawable_nStop},
+};
+
+int register_android_graphics_drawable_LottieDrawable(JNIEnv* env) {
+ gLottieDrawableClass = reinterpret_cast<jclass>(
+ env->NewGlobalRef(FindClassOrDie(env, "android/graphics/drawable/LottieDrawable")));
+
+ return android::RegisterMethodsOrDie(env, "android/graphics/drawable/LottieDrawable",
+ gLottieDrawableMethods, NELEM(gLottieDrawableMethods));
+}
diff --git a/libs/hwui/jni/android_graphics_HardwareRenderer.cpp b/libs/hwui/jni/android_graphics_HardwareRenderer.cpp
index 47e2edb..3f4d004 100644
--- a/libs/hwui/jni/android_graphics_HardwareRenderer.cpp
+++ b/libs/hwui/jni/android_graphics_HardwareRenderer.cpp
@@ -829,12 +829,10 @@
DeviceInfo::setDensity(density);
}
-static void android_view_ThreadedRenderer_initDisplayInfo(JNIEnv* env, jclass, jint physicalWidth,
- jint physicalHeight, jfloat refreshRate,
- jint wideColorDataspace,
- jlong appVsyncOffsetNanos,
- jlong presentationDeadlineNanos,
- jboolean supportFp16ForHdr) {
+static void android_view_ThreadedRenderer_initDisplayInfo(
+ JNIEnv* env, jclass, jint physicalWidth, jint physicalHeight, jfloat refreshRate,
+ jint wideColorDataspace, jlong appVsyncOffsetNanos, jlong presentationDeadlineNanos,
+ jboolean supportFp16ForHdr, jboolean supportMixedColorSpaces) {
DeviceInfo::setWidth(physicalWidth);
DeviceInfo::setHeight(physicalHeight);
DeviceInfo::setRefreshRate(refreshRate);
@@ -842,6 +840,7 @@
DeviceInfo::setAppVsyncOffsetNanos(appVsyncOffsetNanos);
DeviceInfo::setPresentationDeadlineNanos(presentationDeadlineNanos);
DeviceInfo::setSupportFp16ForHdr(supportFp16ForHdr);
+ DeviceInfo::setSupportMixedColorSpaces(supportMixedColorSpaces);
}
static void android_view_ThreadedRenderer_setDrawingEnabled(JNIEnv*, jclass, jboolean enabled) {
@@ -991,7 +990,7 @@
{"nSetForceDark", "(JZ)V", (void*)android_view_ThreadedRenderer_setForceDark},
{"nSetDisplayDensityDpi", "(I)V",
(void*)android_view_ThreadedRenderer_setDisplayDensityDpi},
- {"nInitDisplayInfo", "(IIFIJJZ)V", (void*)android_view_ThreadedRenderer_initDisplayInfo},
+ {"nInitDisplayInfo", "(IIFIJJZZ)V", (void*)android_view_ThreadedRenderer_initDisplayInfo},
{"preload", "()V", (void*)android_view_ThreadedRenderer_preload},
{"isWebViewOverlaysEnabled", "()Z",
(void*)android_view_ThreadedRenderer_isWebViewOverlaysEnabled},
diff --git a/libs/hwui/pipeline/skia/GLFunctorDrawable.cpp b/libs/hwui/pipeline/skia/GLFunctorDrawable.cpp
index dc72aea..a4960ea 100644
--- a/libs/hwui/pipeline/skia/GLFunctorDrawable.cpp
+++ b/libs/hwui/pipeline/skia/GLFunctorDrawable.cpp
@@ -24,6 +24,7 @@
#include "SkClipStack.h"
#include "SkRect.h"
#include "SkM44.h"
+#include "include/gpu/GpuTypes.h" // from Skia
#include "utils/GLUtils.h"
namespace android {
@@ -92,7 +93,7 @@
SkImageInfo surfaceInfo =
canvas->imageInfo().makeWH(clipBounds.width(), clipBounds.height());
tmpSurface =
- SkSurface::MakeRenderTarget(directContext, SkBudgeted::kYes, surfaceInfo);
+ SkSurface::MakeRenderTarget(directContext, skgpu::Budgeted::kYes, surfaceInfo);
tmpSurface->getCanvas()->clear(SK_ColorTRANSPARENT);
GrGLFramebufferInfo fboInfo;
diff --git a/libs/hwui/pipeline/skia/SkiaDisplayList.cpp b/libs/hwui/pipeline/skia/SkiaDisplayList.cpp
index fcfc4f8..f0dc5eb 100644
--- a/libs/hwui/pipeline/skia/SkiaDisplayList.cpp
+++ b/libs/hwui/pipeline/skia/SkiaDisplayList.cpp
@@ -146,6 +146,16 @@
}
}
+ for (auto& lottie : mLotties) {
+ // If any animated image in the display list needs updated, then damage the node.
+ if (lottie->isDirty()) {
+ isDirty = true;
+ }
+ if (lottie->isRunning()) {
+ info.out.hasAnimations = true;
+ }
+ }
+
for (auto& [vectorDrawable, cachedMatrix] : mVectorDrawables) {
// If any vector drawable in the display list needs update, damage the node.
if (vectorDrawable->isDirty()) {
diff --git a/libs/hwui/pipeline/skia/SkiaDisplayList.h b/libs/hwui/pipeline/skia/SkiaDisplayList.h
index 2a67734..39217fc 100644
--- a/libs/hwui/pipeline/skia/SkiaDisplayList.h
+++ b/libs/hwui/pipeline/skia/SkiaDisplayList.h
@@ -22,6 +22,7 @@
#include "RenderNodeDrawable.h"
#include "TreeInfo.h"
#include "hwui/AnimatedImageDrawable.h"
+#include "hwui/LottieDrawable.h"
#include "utils/LinearAllocator.h"
#include "utils/Pair.h"
@@ -186,6 +187,8 @@
return mHasHolePunches;
}
+ // TODO(b/257304231): create common base class for Lotties and AnimatedImages
+ std::vector<LottieDrawable*> mLotties;
std::vector<AnimatedImageDrawable*> mAnimatedImages;
DisplayListData mDisplayList;
diff --git a/libs/hwui/pipeline/skia/SkiaPipeline.cpp b/libs/hwui/pipeline/skia/SkiaPipeline.cpp
index 1a336c5..3692f09 100644
--- a/libs/hwui/pipeline/skia/SkiaPipeline.cpp
+++ b/libs/hwui/pipeline/skia/SkiaPipeline.cpp
@@ -36,6 +36,7 @@
#include <SkStream.h>
#include <SkString.h>
#include <SkTypeface.h>
+#include "include/gpu/GpuTypes.h" // from Skia
#include <android-base/properties.h>
#include <unistd.h>
@@ -187,7 +188,7 @@
SkSurfaceProps props(0, kUnknown_SkPixelGeometry);
SkASSERT(mRenderThread.getGrContext() != nullptr);
node->setLayerSurface(SkSurface::MakeRenderTarget(mRenderThread.getGrContext(),
- SkBudgeted::kYes, info, 0,
+ skgpu::Budgeted::kYes, info, 0,
this->getSurfaceOrigin(), &props));
if (node->getLayerSurface()) {
// update the transform in window of the layer to reset its origin wrt light source
diff --git a/libs/hwui/pipeline/skia/SkiaRecordingCanvas.cpp b/libs/hwui/pipeline/skia/SkiaRecordingCanvas.cpp
index 1f87865..db449d6 100644
--- a/libs/hwui/pipeline/skia/SkiaRecordingCanvas.cpp
+++ b/libs/hwui/pipeline/skia/SkiaRecordingCanvas.cpp
@@ -188,6 +188,11 @@
#endif
}
+void SkiaRecordingCanvas::drawLottie(LottieDrawable* lottie) {
+ drawDrawable(lottie);
+ mDisplayList->mLotties.push_back(lottie);
+}
+
void SkiaRecordingCanvas::drawVectorDrawable(VectorDrawableRoot* tree) {
mRecorder.drawVectorDrawable(tree);
SkMatrix mat;
diff --git a/libs/hwui/pipeline/skia/SkiaRecordingCanvas.h b/libs/hwui/pipeline/skia/SkiaRecordingCanvas.h
index 7844e2c..c823d8d 100644
--- a/libs/hwui/pipeline/skia/SkiaRecordingCanvas.h
+++ b/libs/hwui/pipeline/skia/SkiaRecordingCanvas.h
@@ -78,6 +78,7 @@
uirenderer::CanvasPropertyPaint* paint) override;
virtual void drawRipple(const RippleDrawableParams& params) override;
+ virtual void drawLottie(LottieDrawable* lottieDrawable) override;
virtual void drawVectorDrawable(VectorDrawableRoot* vectorDrawable) override;
virtual void enableZ(bool enableZ) override;
diff --git a/libs/hwui/pipeline/skia/StretchMask.cpp b/libs/hwui/pipeline/skia/StretchMask.cpp
index b169c92..cad3703 100644
--- a/libs/hwui/pipeline/skia/StretchMask.cpp
+++ b/libs/hwui/pipeline/skia/StretchMask.cpp
@@ -18,6 +18,8 @@
#include "SkBlendMode.h"
#include "SkCanvas.h"
#include "SkSurface.h"
+#include "include/gpu/GpuTypes.h" // from Skia
+
#include "TransformCanvas.h"
#include "SkiaDisplayList.h"
@@ -36,7 +38,7 @@
// not match.
mMaskSurface = SkSurface::MakeRenderTarget(
context,
- SkBudgeted::kYes,
+ skgpu::Budgeted::kYes,
SkImageInfo::Make(
width,
height,
diff --git a/libs/hwui/tests/unit/CacheManagerTests.cpp b/libs/hwui/tests/unit/CacheManagerTests.cpp
index 508e198..2b90bda 100644
--- a/libs/hwui/tests/unit/CacheManagerTests.cpp
+++ b/libs/hwui/tests/unit/CacheManagerTests.cpp
@@ -21,6 +21,7 @@
#include "tests/common/TestUtils.h"
#include <SkImagePriv.h>
+#include "include/gpu/GpuTypes.h" // from Skia
using namespace android;
using namespace android::uirenderer;
@@ -45,7 +46,8 @@
while (getCacheUsage(grContext) <= renderThread.cacheManager().getBackgroundCacheSize()) {
SkImageInfo info = SkImageInfo::MakeA8(width, height);
- sk_sp<SkSurface> surface = SkSurface::MakeRenderTarget(grContext, SkBudgeted::kYes, info);
+ sk_sp<SkSurface> surface = SkSurface::MakeRenderTarget(grContext, skgpu::Budgeted::kYes,
+ info);
surface->getCanvas()->drawColor(SK_AlphaTRANSPARENT);
grContext->flushAndSubmit();
diff --git a/libs/hwui/tests/unit/GraphicsStatsServiceTests.cpp b/libs/hwui/tests/unit/GraphicsStatsServiceTests.cpp
index 92fd829..c2d23e6 100644
--- a/libs/hwui/tests/unit/GraphicsStatsServiceTests.cpp
+++ b/libs/hwui/tests/unit/GraphicsStatsServiceTests.cpp
@@ -15,6 +15,7 @@
*/
#include <android-base/macros.h>
+#include <gmock/gmock.h>
#include <gtest/gtest.h>
#include <stdio.h>
#include <stdlib.h>
@@ -49,8 +50,14 @@
// No code left untested
TEST(GraphicsStats, findRootPath) {
- std::string expected = "/data/local/tmp/nativetest/hwui_unit_tests/" ABI_STRING;
- EXPECT_EQ(expected, findRootPath());
+ // Different tools/infrastructure seem to push this to different locations. It shouldn't really
+ // matter where the binary is, so add new locations here as needed. This test still seems good
+ // as it's nice to understand the possibility space, and ensure findRootPath continues working
+ // as expected.
+ std::string acceptableLocations[] = {"/data/nativetest/hwui_unit_tests",
+ "/data/nativetest64/hwui_unit_tests",
+ "/data/local/tmp/nativetest/hwui_unit_tests/" ABI_STRING};
+ EXPECT_THAT(acceptableLocations, ::testing::Contains(findRootPath()));
}
TEST(GraphicsStats, saveLoad) {
diff --git a/libs/hwui/utils/AutoMalloc.h b/libs/hwui/utils/AutoMalloc.h
new file mode 100644
index 0000000..05f5e9f
--- /dev/null
+++ b/libs/hwui/utils/AutoMalloc.h
@@ -0,0 +1,94 @@
+/**
+ * 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.
+ */
+
+#pragma once
+
+#include <cstdlib>
+#include <memory>
+#include <type_traits>
+
+namespace android {
+namespace uirenderer {
+
+/** Manages an array of T elements, freeing the array in the destructor.
+ * Does NOT call any constructors/destructors on T (T must be POD).
+ */
+template <typename T,
+ typename = std::enable_if_t<std::is_trivially_default_constructible<T>::value &&
+ std::is_trivially_destructible<T>::value>>
+class AutoTMalloc {
+public:
+ /** Takes ownership of the ptr. The ptr must be a value which can be passed to std::free. */
+ explicit AutoTMalloc(T* ptr = nullptr) : fPtr(ptr) {}
+
+ /** Allocates space for 'count' Ts. */
+ explicit AutoTMalloc(size_t count) : fPtr(mallocIfCountThrowOnFail(count)) {}
+
+ AutoTMalloc(AutoTMalloc&&) = default;
+ AutoTMalloc& operator=(AutoTMalloc&&) = default;
+
+ /** Resize the memory area pointed to by the current ptr preserving contents. */
+ void realloc(size_t count) { fPtr.reset(reallocIfCountThrowOnFail(count)); }
+
+ /** Resize the memory area pointed to by the current ptr without preserving contents. */
+ T* reset(size_t count = 0) {
+ fPtr.reset(mallocIfCountThrowOnFail(count));
+ return this->get();
+ }
+
+ T* get() const { return fPtr.get(); }
+
+ operator T*() { return fPtr.get(); }
+
+ operator const T*() const { return fPtr.get(); }
+
+ T& operator[](int index) { return fPtr.get()[index]; }
+
+ const T& operator[](int index) const { return fPtr.get()[index]; }
+
+ /**
+ * Transfer ownership of the ptr to the caller, setting the internal
+ * pointer to NULL. Note that this differs from get(), which also returns
+ * the pointer, but it does not transfer ownership.
+ */
+ T* release() { return fPtr.release(); }
+
+private:
+ struct FreeDeleter {
+ void operator()(uint8_t* p) { std::free(p); }
+ };
+ std::unique_ptr<T, FreeDeleter> fPtr;
+
+ T* mallocIfCountThrowOnFail(size_t count) {
+ T* newPtr = nullptr;
+ if (count) {
+ newPtr = (T*)std::malloc(count * sizeof(T));
+ LOG_ALWAYS_FATAL_IF(!newPtr, "failed to malloc %zu bytes", count * sizeof(T));
+ }
+ return newPtr;
+ }
+ T* reallocIfCountThrowOnFail(size_t count) {
+ T* newPtr = nullptr;
+ if (count) {
+ newPtr = (T*)std::realloc(fPtr.release(), count * sizeof(T));
+ LOG_ALWAYS_FATAL_IF(!newPtr, "failed to realloc %zu bytes", count * sizeof(T));
+ }
+ return newPtr;
+ }
+};
+
+} // namespace uirenderer
+} // namespace android
diff --git a/libs/incident/Android.bp b/libs/incident/Android.bp
index ff1714d..a996700 100644
--- a/libs/incident/Android.bp
+++ b/libs/incident/Android.bp
@@ -60,6 +60,7 @@
":libincident_aidl",
"src/IncidentReportArgs.cpp",
],
+ min_sdk_version: "29",
}
cc_library_shared {
diff --git a/media/java/android/media/AudioManager.java b/media/java/android/media/AudioManager.java
index 761edf6..24c5b41 100644
--- a/media/java/android/media/AudioManager.java
+++ b/media/java/android/media/AudioManager.java
@@ -3500,6 +3500,19 @@
}
/**
+ * Suspends the use of LE Audio.
+ *
+ * @param enable {@code true} to suspend le audio, {@code false} to unsuspend
+ *
+ * @hide
+ */
+ @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
+ @RequiresPermission(android.Manifest.permission.BLUETOOTH_STACK)
+ public void setLeAudioSuspended(boolean enable) {
+ AudioSystem.setParameters("LeAudioSuspended=" + enable);
+ }
+
+ /**
* Gets a variable number of parameter values from audio hardware.
*
* @param keys list of parameters
@@ -7009,6 +7022,10 @@
* Returns an array of {@link AudioDeviceInfo} objects corresponding to the audio devices
* currently connected to the system and meeting the criteria specified in the
* <code>flags</code> parameter.
+ * Notes that Android audio framework only support one device per device type. In that case,
+ * if there are multiple audio device with the same device type connected to the Android device,
+ * only the last reported device will be known by Android audio framework and returned by this
+ * API.
* @param flags A set of bitflags specifying the criteria to test.
* @see #GET_DEVICES_OUTPUTS
* @see #GET_DEVICES_INPUTS
diff --git a/media/java/android/media/MediaCas.java b/media/java/android/media/MediaCas.java
index 582a28e..015602e 100644
--- a/media/java/android/media/MediaCas.java
+++ b/media/java/android/media/MediaCas.java
@@ -21,11 +21,12 @@
import android.annotation.Nullable;
import android.annotation.TestApi;
import android.content.Context;
+import android.hardware.cas.AidlCasPluginDescriptor;
+import android.hardware.cas.ICas;
+import android.hardware.cas.ICasListener;
+import android.hardware.cas.IMediaCasService;
+import android.hardware.cas.Status;
import android.hardware.cas.V1_0.HidlCasPluginDescriptor;
-import android.hardware.cas.V1_0.ICas;
-import android.hardware.cas.V1_0.IMediaCasService;
-import android.hardware.cas.V1_2.ICasListener;
-import android.hardware.cas.V1_2.Status;
import android.media.MediaCasException.*;
import android.media.tv.TvInputService.PriorityHintUseCaseType;
import android.media.tv.tunerresourcemanager.CasSessionRequest;
@@ -39,6 +40,7 @@
import android.os.Message;
import android.os.Process;
import android.os.RemoteException;
+import android.os.ServiceManager;
import android.util.Log;
import android.util.Singleton;
@@ -47,6 +49,7 @@
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.util.ArrayList;
+import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
@@ -114,9 +117,10 @@
*/
public final class MediaCas implements AutoCloseable {
private static final String TAG = "MediaCas";
- private ICas mICas;
- private android.hardware.cas.V1_1.ICas mICasV11;
- private android.hardware.cas.V1_2.ICas mICasV12;
+ private ICas mICas = null;
+ private android.hardware.cas.V1_0.ICas mICasHidl = null;
+ private android.hardware.cas.V1_1.ICas mICasHidl11 = null;
+ private android.hardware.cas.V1_2.ICas mICasHidl12 = null;
private EventListener mListener;
private HandlerThread mHandlerThread;
private EventHandler mEventHandler;
@@ -133,88 +137,84 @@
*
* @hide
*/
- @IntDef(prefix = "SCRAMBLING_MODE_",
- value = {SCRAMBLING_MODE_RESERVED, SCRAMBLING_MODE_DVB_CSA1, SCRAMBLING_MODE_DVB_CSA2,
- SCRAMBLING_MODE_DVB_CSA3_STANDARD,
- SCRAMBLING_MODE_DVB_CSA3_MINIMAL, SCRAMBLING_MODE_DVB_CSA3_ENHANCE,
- SCRAMBLING_MODE_DVB_CISSA_V1, SCRAMBLING_MODE_DVB_IDSA,
- SCRAMBLING_MODE_MULTI2, SCRAMBLING_MODE_AES128, SCRAMBLING_MODE_AES_ECB,
- SCRAMBLING_MODE_AES_SCTE52, SCRAMBLING_MODE_TDES_ECB, SCRAMBLING_MODE_TDES_SCTE52})
+ @IntDef(
+ prefix = "SCRAMBLING_MODE_",
+ value = {
+ SCRAMBLING_MODE_RESERVED,
+ SCRAMBLING_MODE_DVB_CSA1,
+ SCRAMBLING_MODE_DVB_CSA2,
+ SCRAMBLING_MODE_DVB_CSA3_STANDARD,
+ SCRAMBLING_MODE_DVB_CSA3_MINIMAL,
+ SCRAMBLING_MODE_DVB_CSA3_ENHANCE,
+ SCRAMBLING_MODE_DVB_CISSA_V1,
+ SCRAMBLING_MODE_DVB_IDSA,
+ SCRAMBLING_MODE_MULTI2,
+ SCRAMBLING_MODE_AES128,
+ SCRAMBLING_MODE_AES_CBC,
+ SCRAMBLING_MODE_AES_ECB,
+ SCRAMBLING_MODE_AES_SCTE52,
+ SCRAMBLING_MODE_TDES_ECB,
+ SCRAMBLING_MODE_TDES_SCTE52
+ })
@Retention(RetentionPolicy.SOURCE)
public @interface ScramblingMode {}
- /**
- * DVB (Digital Video Broadcasting) reserved mode.
- */
- public static final int SCRAMBLING_MODE_RESERVED =
- android.hardware.cas.V1_2.ScramblingMode.RESERVED;
- /**
- * DVB (Digital Video Broadcasting) Common Scrambling Algorithm (CSA) 1.
- */
- public static final int SCRAMBLING_MODE_DVB_CSA1 =
- android.hardware.cas.V1_2.ScramblingMode.DVB_CSA1;
- /**
- * DVB CSA 2.
- */
- public static final int SCRAMBLING_MODE_DVB_CSA2 =
- android.hardware.cas.V1_2.ScramblingMode.DVB_CSA2;
- /**
- * DVB CSA 3 in standard mode.
- */
+ /** DVB (Digital Video Broadcasting) reserved mode. */
+ public static final int SCRAMBLING_MODE_RESERVED = android.hardware.cas.ScramblingMode.RESERVED;
+
+ /** DVB (Digital Video Broadcasting) Common Scrambling Algorithm (CSA) 1. */
+ public static final int SCRAMBLING_MODE_DVB_CSA1 = android.hardware.cas.ScramblingMode.DVB_CSA1;
+
+ /** DVB CSA 2. */
+ public static final int SCRAMBLING_MODE_DVB_CSA2 = android.hardware.cas.ScramblingMode.DVB_CSA2;
+
+ /** DVB CSA 3 in standard mode. */
public static final int SCRAMBLING_MODE_DVB_CSA3_STANDARD =
- android.hardware.cas.V1_2.ScramblingMode.DVB_CSA3_STANDARD;
- /**
- * DVB CSA 3 in minimally enhanced mode.
- */
+ android.hardware.cas.ScramblingMode.DVB_CSA3_STANDARD;
+
+ /** DVB CSA 3 in minimally enhanced mode. */
public static final int SCRAMBLING_MODE_DVB_CSA3_MINIMAL =
- android.hardware.cas.V1_2.ScramblingMode.DVB_CSA3_MINIMAL;
- /**
- * DVB CSA 3 in fully enhanced mode.
- */
+ android.hardware.cas.ScramblingMode.DVB_CSA3_MINIMAL;
+
+ /** DVB CSA 3 in fully enhanced mode. */
public static final int SCRAMBLING_MODE_DVB_CSA3_ENHANCE =
- android.hardware.cas.V1_2.ScramblingMode.DVB_CSA3_ENHANCE;
- /**
- * DVB Common IPTV Software-oriented Scrambling Algorithm (CISSA) Version 1.
- */
+ android.hardware.cas.ScramblingMode.DVB_CSA3_ENHANCE;
+
+ /** DVB Common IPTV Software-oriented Scrambling Algorithm (CISSA) Version 1. */
public static final int SCRAMBLING_MODE_DVB_CISSA_V1 =
- android.hardware.cas.V1_2.ScramblingMode.DVB_CISSA_V1;
- /**
- * ATIS-0800006 IIF Default Scrambling Algorithm (IDSA).
- */
- public static final int SCRAMBLING_MODE_DVB_IDSA =
- android.hardware.cas.V1_2.ScramblingMode.DVB_IDSA;
- /**
- * A symmetric key algorithm.
- */
- public static final int SCRAMBLING_MODE_MULTI2 =
- android.hardware.cas.V1_2.ScramblingMode.MULTI2;
- /**
- * Advanced Encryption System (AES) 128-bit Encryption mode.
- */
- public static final int SCRAMBLING_MODE_AES128 =
- android.hardware.cas.V1_2.ScramblingMode.AES128;
- /**
- * Advanced Encryption System (AES) Electronic Code Book (ECB) mode.
- */
- public static final int SCRAMBLING_MODE_AES_ECB =
- android.hardware.cas.V1_2.ScramblingMode.AES_ECB;
+ android.hardware.cas.ScramblingMode.DVB_CISSA_V1;
+
+ /** ATIS-0800006 IIF Default Scrambling Algorithm (IDSA). */
+ public static final int SCRAMBLING_MODE_DVB_IDSA = android.hardware.cas.ScramblingMode.DVB_IDSA;
+
+ /** A symmetric key algorithm. */
+ public static final int SCRAMBLING_MODE_MULTI2 = android.hardware.cas.ScramblingMode.MULTI2;
+
+ /** Advanced Encryption System (AES) 128-bit Encryption mode. */
+ public static final int SCRAMBLING_MODE_AES128 = android.hardware.cas.ScramblingMode.AES128;
+
+ /** Advanced Encryption System (AES) Cipher Block Chaining (CBC) mode. */
+ public static final int SCRAMBLING_MODE_AES_CBC = android.hardware.cas.ScramblingMode.AES_CBC;
+
+ /** Advanced Encryption System (AES) Electronic Code Book (ECB) mode. */
+ public static final int SCRAMBLING_MODE_AES_ECB = android.hardware.cas.ScramblingMode.AES_ECB;
+
/**
* Advanced Encryption System (AES) Society of Cable Telecommunications Engineers (SCTE) 52
* mode.
*/
public static final int SCRAMBLING_MODE_AES_SCTE52 =
- android.hardware.cas.V1_2.ScramblingMode.AES_SCTE52;
- /**
- * Triple Data Encryption Algorithm (TDES) Electronic Code Book (ECB) mode.
- */
- public static final int SCRAMBLING_MODE_TDES_ECB =
- android.hardware.cas.V1_2.ScramblingMode.TDES_ECB;
+ android.hardware.cas.ScramblingMode.AES_SCTE52;
+
+ /** Triple Data Encryption Algorithm (TDES) Electronic Code Book (ECB) mode. */
+ public static final int SCRAMBLING_MODE_TDES_ECB = android.hardware.cas.ScramblingMode.TDES_ECB;
+
/**
* Triple Data Encryption Algorithm (TDES) Society of Cable Telecommunications Engineers (SCTE)
* 52 mode.
*/
public static final int SCRAMBLING_MODE_TDES_SCTE52 =
- android.hardware.cas.V1_2.ScramblingMode.TDES_SCTE52;
+ android.hardware.cas.ScramblingMode.TDES_SCTE52;
/**
* Usages used to open cas sessions.
@@ -226,25 +226,21 @@
SESSION_USAGE_TIMESHIFT})
@Retention(RetentionPolicy.SOURCE)
public @interface SessionUsage {}
- /**
- * Cas session is used to descramble live streams.
- */
- public static final int SESSION_USAGE_LIVE = android.hardware.cas.V1_2.SessionIntent.LIVE;
- /**
- * Cas session is used to descramble recoreded streams.
- */
- public static final int SESSION_USAGE_PLAYBACK =
- android.hardware.cas.V1_2.SessionIntent.PLAYBACK;
- /**
- * Cas session is used to descramble live streams and encrypt local recorded content
- */
- public static final int SESSION_USAGE_RECORD = android.hardware.cas.V1_2.SessionIntent.RECORD;
+
+ /** Cas session is used to descramble live streams. */
+ public static final int SESSION_USAGE_LIVE = android.hardware.cas.SessionIntent.LIVE;
+
+ /** Cas session is used to descramble recoreded streams. */
+ public static final int SESSION_USAGE_PLAYBACK = android.hardware.cas.SessionIntent.PLAYBACK;
+
+ /** Cas session is used to descramble live streams and encrypt local recorded content */
+ public static final int SESSION_USAGE_RECORD = android.hardware.cas.SessionIntent.RECORD;
+
/**
* Cas session is used to descramble live streams , encrypt local recorded content and playback
* local encrypted content.
*/
- public static final int SESSION_USAGE_TIMESHIFT =
- android.hardware.cas.V1_2.SessionIntent.TIMESHIFT;
+ public static final int SESSION_USAGE_TIMESHIFT = android.hardware.cas.SessionIntent.TIMESHIFT;
/**
* Plugin status events sent from cas system.
@@ -261,63 +257,90 @@
* physical CAS modules.
*/
public static final int PLUGIN_STATUS_PHYSICAL_MODULE_CHANGED =
- android.hardware.cas.V1_2.StatusEvent.PLUGIN_PHYSICAL_MODULE_CHANGED;
- /**
- * The event to indicate that the number of CAS system's session is changed.
- */
+ android.hardware.cas.StatusEvent.PLUGIN_PHYSICAL_MODULE_CHANGED;
+
+ /** The event to indicate that the number of CAS system's session is changed. */
public static final int PLUGIN_STATUS_SESSION_NUMBER_CHANGED =
- android.hardware.cas.V1_2.StatusEvent.PLUGIN_SESSION_NUMBER_CHANGED;
+ android.hardware.cas.StatusEvent.PLUGIN_SESSION_NUMBER_CHANGED;
- private static final Singleton<IMediaCasService> sService = new Singleton<IMediaCasService>() {
- @Override
- protected IMediaCasService create() {
- try {
- Log.d(TAG, "Trying to get cas@1.2 service");
- android.hardware.cas.V1_2.IMediaCasService serviceV12 =
- android.hardware.cas.V1_2.IMediaCasService.getService(true /*wait*/);
- if (serviceV12 != null) {
- return serviceV12;
- }
- } catch (Exception eV1_2) {
- Log.d(TAG, "Failed to get cas@1.2 service");
- }
-
- try {
- Log.d(TAG, "Trying to get cas@1.1 service");
- android.hardware.cas.V1_1.IMediaCasService serviceV11 =
- android.hardware.cas.V1_1.IMediaCasService.getService(true /*wait*/);
- if (serviceV11 != null) {
- return serviceV11;
+ private static final Singleton<IMediaCasService> sService =
+ new Singleton<IMediaCasService>() {
+ @Override
+ protected IMediaCasService create() {
+ try {
+ Log.d(TAG, "Trying to get AIDL service");
+ IMediaCasService serviceAidl =
+ IMediaCasService.Stub.asInterface(
+ ServiceManager.getService(
+ IMediaCasService.DESCRIPTOR + "/default"));
+ if (serviceAidl != null) {
+ return serviceAidl;
+ }
+ } catch (Exception eAidl) {
+ Log.d(TAG, "Failed to get cas AIDL service");
}
- } catch (Exception eV1_1) {
- Log.d(TAG, "Failed to get cas@1.1 service");
- }
+ return null;
+ }
+ };
- try {
- Log.d(TAG, "Trying to get cas@1.0 service");
- return IMediaCasService.getService(true /*wait*/);
- } catch (Exception eV1_0) {
- Log.d(TAG, "Failed to get cas@1.0 service");
- }
+ private static final Singleton<android.hardware.cas.V1_0.IMediaCasService> sServiceHidl =
+ new Singleton<android.hardware.cas.V1_0.IMediaCasService>() {
+ @Override
+ protected android.hardware.cas.V1_0.IMediaCasService create() {
+ try {
+ Log.d(TAG, "Trying to get cas@1.2 service");
+ android.hardware.cas.V1_2.IMediaCasService serviceV12 =
+ android.hardware.cas.V1_2.IMediaCasService.getService(
+ true /*wait*/);
+ if (serviceV12 != null) {
+ return serviceV12;
+ }
+ } catch (Exception eV1_2) {
+ Log.d(TAG, "Failed to get cas@1.2 service");
+ }
- return null;
- }
- };
+ try {
+ Log.d(TAG, "Trying to get cas@1.1 service");
+ android.hardware.cas.V1_1.IMediaCasService serviceV11 =
+ android.hardware.cas.V1_1.IMediaCasService.getService(
+ true /*wait*/);
+ if (serviceV11 != null) {
+ return serviceV11;
+ }
+ } catch (Exception eV1_1) {
+ Log.d(TAG, "Failed to get cas@1.1 service");
+ }
+
+ try {
+ Log.d(TAG, "Trying to get cas@1.0 service");
+ return android.hardware.cas.V1_0.IMediaCasService.getService(true /*wait*/);
+ } catch (Exception eV1_0) {
+ Log.d(TAG, "Failed to get cas@1.0 service");
+ }
+
+ return null;
+ }
+ };
static IMediaCasService getService() {
return sService.get();
}
+ static android.hardware.cas.V1_0.IMediaCasService getServiceHidl() {
+ return sServiceHidl.get();
+ }
+
private void validateInternalStates() {
- if (mICas == null) {
+ if (mICas == null && mICasHidl == null) {
throw new IllegalStateException();
}
}
private void cleanupAndRethrowIllegalState() {
mICas = null;
- mICasV11 = null;
- mICasV12 = null;
+ mICasHidl = null;
+ mICasHidl11 = null;
+ mICasHidl12 = null;
throw new IllegalStateException();
}
@@ -341,7 +364,7 @@
toBytes((ArrayList<Byte>) msg.obj));
} else if (msg.what == MSG_CAS_SESSION_EVENT) {
Bundle bundle = msg.getData();
- ArrayList<Byte> sessionId = toByteArray(bundle.getByteArray(SESSION_KEY));
+ byte[] sessionId = bundle.getByteArray(SESSION_KEY);
mListener.onSessionEvent(MediaCas.this,
createFromSessionId(sessionId), msg.arg1, msg.arg2,
bundle.getByteArray(DATA_KEY));
@@ -357,40 +380,94 @@
}
}
- private final ICasListener.Stub mBinder = new ICasListener.Stub() {
- @Override
- public void onEvent(int event, int arg, @Nullable ArrayList<Byte> data)
- throws RemoteException {
- if (mEventHandler != null) {
- mEventHandler.sendMessage(mEventHandler.obtainMessage(
- EventHandler.MSG_CAS_EVENT, event, arg, data));
- }
- }
- @Override
- public void onSessionEvent(@NonNull ArrayList<Byte> sessionId,
- int event, int arg, @Nullable ArrayList<Byte> data)
- throws RemoteException {
- if (mEventHandler != null) {
- Message msg = mEventHandler.obtainMessage();
- msg.what = EventHandler.MSG_CAS_SESSION_EVENT;
- msg.arg1 = event;
- msg.arg2 = arg;
- Bundle bundle = new Bundle();
- bundle.putByteArray(EventHandler.SESSION_KEY, toBytes(sessionId));
- bundle.putByteArray(EventHandler.DATA_KEY, toBytes(data));
- msg.setData(bundle);
- mEventHandler.sendMessage(msg);
- }
- }
- @Override
- public void onStatusUpdate(byte status, int arg)
- throws RemoteException {
- if (mEventHandler != null) {
- mEventHandler.sendMessage(mEventHandler.obtainMessage(
- EventHandler.MSG_CAS_STATUS_EVENT, status, arg));
- }
- }
- };
+ private final ICasListener.Stub mBinder =
+ new ICasListener.Stub() {
+ @Override
+ public void onEvent(int event, int arg, byte[] data) throws RemoteException {
+ if (mEventHandler != null) {
+ mEventHandler.sendMessage(
+ mEventHandler.obtainMessage(
+ EventHandler.MSG_CAS_EVENT, event, arg, data));
+ }
+ }
+
+ @Override
+ public void onSessionEvent(byte[] sessionId, int event, int arg, byte[] data)
+ throws RemoteException {
+ if (mEventHandler != null) {
+ Message msg = mEventHandler.obtainMessage();
+ msg.what = EventHandler.MSG_CAS_SESSION_EVENT;
+ msg.arg1 = event;
+ msg.arg2 = arg;
+ Bundle bundle = new Bundle();
+ bundle.putByteArray(EventHandler.SESSION_KEY, sessionId);
+ bundle.putByteArray(EventHandler.DATA_KEY, data);
+ msg.setData(bundle);
+ mEventHandler.sendMessage(msg);
+ }
+ }
+
+ @Override
+ public void onStatusUpdate(byte status, int arg) throws RemoteException {
+ if (mEventHandler != null) {
+ mEventHandler.sendMessage(
+ mEventHandler.obtainMessage(
+ EventHandler.MSG_CAS_STATUS_EVENT, status, arg));
+ }
+ }
+
+ @Override
+ public synchronized String getInterfaceHash() throws android.os.RemoteException {
+ return ICasListener.Stub.HASH;
+ }
+
+ @Override
+ public int getInterfaceVersion() throws android.os.RemoteException {
+ return ICasListener.Stub.VERSION;
+ }
+ };
+
+ private final android.hardware.cas.V1_2.ICasListener.Stub mBinderHidl =
+ new android.hardware.cas.V1_2.ICasListener.Stub() {
+ @Override
+ public void onEvent(int event, int arg, @Nullable ArrayList<Byte> data)
+ throws RemoteException {
+ if (mEventHandler != null) {
+ mEventHandler.sendMessage(
+ mEventHandler.obtainMessage(
+ EventHandler.MSG_CAS_EVENT, event, arg, data));
+ }
+ }
+
+ @Override
+ public void onSessionEvent(
+ @NonNull ArrayList<Byte> sessionId,
+ int event,
+ int arg,
+ @Nullable ArrayList<Byte> data)
+ throws RemoteException {
+ if (mEventHandler != null) {
+ Message msg = mEventHandler.obtainMessage();
+ msg.what = EventHandler.MSG_CAS_SESSION_EVENT;
+ msg.arg1 = event;
+ msg.arg2 = arg;
+ Bundle bundle = new Bundle();
+ bundle.putByteArray(EventHandler.SESSION_KEY, toBytes(sessionId));
+ bundle.putByteArray(EventHandler.DATA_KEY, toBytes(data));
+ msg.setData(bundle);
+ mEventHandler.sendMessage(msg);
+ }
+ }
+
+ @Override
+ public void onStatusUpdate(byte status, int arg) throws RemoteException {
+ if (mEventHandler != null) {
+ mEventHandler.sendMessage(
+ mEventHandler.obtainMessage(
+ EventHandler.MSG_CAS_STATUS_EVENT, status, arg));
+ }
+ }
+ };
private final TunerResourceManager.ResourcesReclaimListener mResourceListener =
new TunerResourceManager.ResourcesReclaimListener() {
@@ -422,6 +499,11 @@
mName = null;
}
+ PluginDescriptor(@NonNull AidlCasPluginDescriptor descriptor) {
+ mCASystemId = descriptor.caSystemId;
+ mName = descriptor.name;
+ }
+
PluginDescriptor(@NonNull HidlCasPluginDescriptor descriptor) {
mCASystemId = descriptor.caSystemId;
mName = descriptor.name;
@@ -467,19 +549,20 @@
}
return data;
}
+
/**
* Class for an open session with the CA system.
*/
public final class Session implements AutoCloseable {
- final ArrayList<Byte> mSessionId;
+ final byte[] mSessionId;
boolean mIsClosed = false;
- Session(@NonNull ArrayList<Byte> sessionId) {
- mSessionId = new ArrayList<Byte>(sessionId);
+ Session(@NonNull byte[] sessionId) {
+ mSessionId = sessionId;
}
private void validateSessionInternalStates() {
- if (mICas == null) {
+ if (mICas == null && mICasHidl == null) {
throw new IllegalStateException();
}
if (mIsClosed) {
@@ -496,7 +579,7 @@
*/
public boolean equals(Object obj) {
if (obj instanceof Session) {
- return mSessionId.equals(((Session) obj).mSessionId);
+ return Arrays.equals(mSessionId, ((Session) obj).mSessionId);
}
return false;
}
@@ -515,8 +598,13 @@
validateSessionInternalStates();
try {
- MediaCasException.throwExceptionIfNeeded(
- mICas.setSessionPrivateData(mSessionId, toByteArray(data, 0, data.length)));
+ if (mICas != null) {
+ mICas.setSessionPrivateData(mSessionId, data);
+ } else {
+ MediaCasException.throwExceptionIfNeeded(
+ mICasHidl.setSessionPrivateData(
+ toByteArray(mSessionId), toByteArray(data, 0, data.length)));
+ }
} catch (RemoteException e) {
cleanupAndRethrowIllegalState();
}
@@ -539,8 +627,13 @@
validateSessionInternalStates();
try {
- MediaCasException.throwExceptionIfNeeded(
- mICas.processEcm(mSessionId, toByteArray(data, offset, length)));
+ if (mICas != null) {
+ mICas.processEcm(mSessionId, data);
+ } else {
+ MediaCasException.throwExceptionIfNeeded(
+ mICasHidl.processEcm(
+ toByteArray(mSessionId), toByteArray(data, offset, length)));
+ }
} catch (RemoteException e) {
cleanupAndRethrowIllegalState();
}
@@ -576,15 +669,23 @@
public void sendSessionEvent(int event, int arg, @Nullable byte[] data)
throws MediaCasException {
validateSessionInternalStates();
+ if (mICas != null) {
+ try {
+ mICas.sendSessionEvent(mSessionId, event, arg, data);
+ } catch (RemoteException e) {
+ cleanupAndRethrowIllegalState();
+ }
+ }
- if (mICasV11 == null) {
+ if (mICasHidl11 == null) {
Log.d(TAG, "Send Session Event isn't supported by cas@1.0 interface");
throw new UnsupportedCasException("Send Session Event is not supported");
}
try {
MediaCasException.throwExceptionIfNeeded(
- mICasV11.sendSessionEvent(mSessionId, event, arg, toByteArray(data)));
+ mICasHidl11.sendSessionEvent(
+ toByteArray(mSessionId), event, arg, toByteArray(data)));
} catch (RemoteException e) {
cleanupAndRethrowIllegalState();
}
@@ -600,7 +701,7 @@
@NonNull
public byte[] getSessionId() {
validateSessionInternalStates();
- return toBytes(mSessionId);
+ return mSessionId;
}
/**
@@ -613,8 +714,12 @@
public void close() {
validateSessionInternalStates();
try {
- MediaCasStateException.throwExceptionIfNeeded(
- mICas.closeSession(mSessionId));
+ if (mICas != null) {
+ mICas.closeSession(mSessionId);
+ } else {
+ MediaCasStateException.throwExceptionIfNeeded(
+ mICasHidl.closeSession(toByteArray(mSessionId)));
+ }
mIsClosed = true;
removeSessionFromResourceMap(this);
} catch (RemoteException e) {
@@ -623,8 +728,8 @@
}
}
- Session createFromSessionId(@NonNull ArrayList<Byte> sessionId) {
- if (sessionId == null || sessionId.size() == 0) {
+ Session createFromSessionId(byte[] sessionId) {
+ if (sessionId == null || sessionId.length == 0) {
return null;
}
return new Session(sessionId);
@@ -638,12 +743,20 @@
* @return Whether the specified CA system is supported on this device.
*/
public static boolean isSystemIdSupported(int CA_system_id) {
- IMediaCasService service = getService();
-
+ IMediaCasService service = sService.get();
if (service != null) {
try {
return service.isSystemIdSupported(CA_system_id);
} catch (RemoteException e) {
+ return false;
+ }
+ }
+
+ android.hardware.cas.V1_0.IMediaCasService serviceHidl = sServiceHidl.get();
+ if (serviceHidl != null) {
+ try {
+ return serviceHidl.isSystemIdSupported(CA_system_id);
+ } catch (RemoteException e) {
}
}
return false;
@@ -655,12 +768,26 @@
* @return an array of descriptors for the available CA plugins.
*/
public static PluginDescriptor[] enumeratePlugins() {
- IMediaCasService service = getService();
-
+ IMediaCasService service = sService.get();
if (service != null) {
try {
- ArrayList<HidlCasPluginDescriptor> descriptors =
- service.enumeratePlugins();
+ AidlCasPluginDescriptor[] descriptors = service.enumeratePlugins();
+ if (descriptors.length == 0) {
+ return null;
+ }
+ PluginDescriptor[] results = new PluginDescriptor[descriptors.length];
+ for (int i = 0; i < results.length; i++) {
+ results[i] = new PluginDescriptor(descriptors[i]);
+ }
+ return results;
+ } catch (RemoteException e) {
+ }
+ }
+
+ android.hardware.cas.V1_0.IMediaCasService serviceHidl = sServiceHidl.get();
+ if (serviceHidl != null) {
+ try {
+ ArrayList<HidlCasPluginDescriptor> descriptors = serviceHidl.enumeratePlugins();
if (descriptors.size() == 0) {
return null;
}
@@ -680,29 +807,40 @@
mCasSystemId = casSystemId;
mUserId = Process.myUid();
IMediaCasService service = getService();
- android.hardware.cas.V1_2.IMediaCasService serviceV12 =
- android.hardware.cas.V1_2.IMediaCasService.castFrom(service);
- if (serviceV12 == null) {
- android.hardware.cas.V1_1.IMediaCasService serviceV11 =
- android.hardware.cas.V1_1.IMediaCasService.castFrom(service);
- if (serviceV11 == null) {
- Log.d(TAG, "Used cas@1_0 interface to create plugin");
- mICas = service.createPlugin(casSystemId, mBinder);
- } else {
- Log.d(TAG, "Used cas@1.1 interface to create plugin");
- mICas = mICasV11 = serviceV11.createPluginExt(casSystemId, mBinder);
- }
+ if (service != null) {
+ Log.d(TAG, "Use CAS AIDL interface to create plugin");
+ mICas = service.createPlugin(casSystemId, mBinder);
} else {
- Log.d(TAG, "Used cas@1.2 interface to create plugin");
- mICas = mICasV11 = mICasV12 =
- android.hardware.cas.V1_2.ICas
- .castFrom(serviceV12.createPluginExt(casSystemId, mBinder));
+ android.hardware.cas.V1_0.IMediaCasService serviceV10 = getServiceHidl();
+ android.hardware.cas.V1_2.IMediaCasService serviceV12 =
+ android.hardware.cas.V1_2.IMediaCasService.castFrom(serviceV10);
+ if (serviceV12 == null) {
+ android.hardware.cas.V1_1.IMediaCasService serviceV11 =
+ android.hardware.cas.V1_1.IMediaCasService.castFrom(serviceV10);
+ if (serviceV11 == null) {
+ Log.d(TAG, "Used cas@1_0 interface to create plugin");
+ mICasHidl = serviceV10.createPlugin(casSystemId, mBinderHidl);
+ } else {
+ Log.d(TAG, "Used cas@1.1 interface to create plugin");
+ mICasHidl =
+ mICasHidl11 = serviceV11.createPluginExt(casSystemId, mBinderHidl);
+ }
+ } else {
+ Log.d(TAG, "Used cas@1.2 interface to create plugin");
+ mICasHidl =
+ mICasHidl11 =
+ mICasHidl12 =
+ android.hardware.cas.V1_2.ICas.castFrom(
+ serviceV12.createPluginExt(
+ casSystemId, mBinderHidl));
+ }
}
} catch(Exception e) {
Log.e(TAG, "Failed to create plugin: " + e);
mICas = null;
+ mICasHidl = null;
} finally {
- if (mICas == null) {
+ if (mICas == null && mICasHidl == null) {
throw new UnsupportedCasException(
"Unsupported casSystemId " + casSystemId);
}
@@ -783,9 +921,22 @@
}
IHwBinder getBinder() {
+ if (mICas != null) {
+ return null; // Return IHwBinder only for HIDL
+ }
+
validateInternalStates();
- return mICas.asBinder();
+ return mICasHidl.asBinder();
+ }
+
+ /**
+ * Check if the HAL is an AIDL implementation
+ *
+ * @hide
+ */
+ public boolean isAidlHal() {
+ return mICas != null;
}
/**
@@ -886,8 +1037,12 @@
validateInternalStates();
try {
- MediaCasException.throwExceptionIfNeeded(
- mICas.setPrivateData(toByteArray(data, 0, data.length)));
+ if (mICas != null) {
+ mICas.setPrivateData(data);
+ } else {
+ MediaCasException.throwExceptionIfNeeded(
+ mICasHidl.setPrivateData(toByteArray(data, 0, data.length)));
+ }
} catch (RemoteException e) {
cleanupAndRethrowIllegalState();
}
@@ -899,7 +1054,7 @@
@Override
public void onValues(int status, ArrayList<Byte> sessionId) {
mStatus = status;
- mSession = createFromSessionId(sessionId);
+ mSession = createFromSessionId(toBytes(sessionId));
}
}
@@ -912,7 +1067,7 @@
@Override
public void onValues(int status, ArrayList<Byte> sessionId) {
mStatus = status;
- mSession = createFromSessionId(sessionId);
+ mSession = createFromSessionId(toBytes(sessionId));
}
}
@@ -971,15 +1126,19 @@
int sessionResourceHandle = getSessionResourceHandle();
try {
- OpenSessionCallback cb = new OpenSessionCallback();
- mICas.openSession(cb);
- MediaCasException.throwExceptionIfNeeded(cb.mStatus);
- addSessionToResourceMap(cb.mSession, sessionResourceHandle);
- Log.d(TAG, "Write Stats Log for succeed to Open Session.");
- FrameworkStatsLog
- .write(FrameworkStatsLog.TV_CAS_SESSION_OPEN_STATUS, mUserId, mCasSystemId,
+ if (mICasHidl != null) {
+ OpenSessionCallback cb = new OpenSessionCallback();
+ mICasHidl.openSession(cb);
+ MediaCasException.throwExceptionIfNeeded(cb.mStatus);
+ addSessionToResourceMap(cb.mSession, sessionResourceHandle);
+ Log.d(TAG, "Write Stats Log for succeed to Open Session.");
+ FrameworkStatsLog.write(
+ FrameworkStatsLog.TV_CAS_SESSION_OPEN_STATUS,
+ mUserId,
+ mCasSystemId,
FrameworkStatsLog.TV_CAS_SESSION_OPEN_STATUS__STATE__SUCCEEDED);
- return cb.mSession;
+ return cb.mSession;
+ }
} catch (RemoteException e) {
cleanupAndRethrowIllegalState();
}
@@ -1012,14 +1171,30 @@
throws MediaCasException {
int sessionResourceHandle = getSessionResourceHandle();
- if (mICasV12 == null) {
+ if (mICas != null) {
+ try {
+ byte[] sessionId = mICas.openSession(sessionUsage, scramblingMode);
+ Session session = createFromSessionId(sessionId);
+ addSessionToResourceMap(session, sessionResourceHandle);
+ Log.d(TAG, "Write Stats Log for succeed to Open Session.");
+ FrameworkStatsLog.write(
+ FrameworkStatsLog.TV_CAS_SESSION_OPEN_STATUS,
+ mUserId,
+ mCasSystemId,
+ FrameworkStatsLog.TV_CAS_SESSION_OPEN_STATUS__STATE__SUCCEEDED);
+ return session;
+ } catch (RemoteException e) {
+ cleanupAndRethrowIllegalState();
+ }
+ }
+ if (mICasHidl12 == null) {
Log.d(TAG, "Open Session with scrambling mode is only supported by cas@1.2+ interface");
throw new UnsupportedCasException("Open Session with scrambling mode is not supported");
}
try {
OpenSession_1_2_Callback cb = new OpenSession_1_2_Callback();
- mICasV12.openSession_1_2(sessionUsage, scramblingMode, cb);
+ mICasHidl12.openSession_1_2(sessionUsage, scramblingMode, cb);
MediaCasException.throwExceptionIfNeeded(cb.mStatus);
addSessionToResourceMap(cb.mSession, sessionResourceHandle);
Log.d(TAG, "Write Stats Log for succeed to Open Session.");
@@ -1053,8 +1228,12 @@
validateInternalStates();
try {
- MediaCasException.throwExceptionIfNeeded(
- mICas.processEmm(toByteArray(data, offset, length)));
+ if (mICas != null) {
+ mICas.processEmm(Arrays.copyOfRange(data, offset, length));
+ } else {
+ MediaCasException.throwExceptionIfNeeded(
+ mICasHidl.processEmm(toByteArray(data, offset, length)));
+ }
} catch (RemoteException e) {
cleanupAndRethrowIllegalState();
}
@@ -1092,8 +1271,12 @@
validateInternalStates();
try {
- MediaCasException.throwExceptionIfNeeded(
- mICas.sendEvent(event, arg, toByteArray(data)));
+ if (mICas != null) {
+ mICas.sendEvent(event, arg, data);
+ } else {
+ MediaCasException.throwExceptionIfNeeded(
+ mICasHidl.sendEvent(event, arg, toByteArray(data)));
+ }
} catch (RemoteException e) {
cleanupAndRethrowIllegalState();
}
@@ -1114,8 +1297,11 @@
validateInternalStates();
try {
- MediaCasException.throwExceptionIfNeeded(
- mICas.provision(provisionString));
+ if (mICas != null) {
+ mICas.provision(provisionString);
+ } else {
+ MediaCasException.throwExceptionIfNeeded(mICasHidl.provision(provisionString));
+ }
} catch (RemoteException e) {
cleanupAndRethrowIllegalState();
}
@@ -1136,8 +1322,12 @@
validateInternalStates();
try {
- MediaCasException.throwExceptionIfNeeded(
- mICas.refreshEntitlements(refreshType, toByteArray(refreshData)));
+ if (mICas != null) {
+ mICas.refreshEntitlements(refreshType, refreshData);
+ } else {
+ MediaCasException.throwExceptionIfNeeded(
+ mICasHidl.refreshEntitlements(refreshType, toByteArray(refreshData)));
+ }
} catch (RemoteException e) {
cleanupAndRethrowIllegalState();
}
@@ -1163,6 +1353,13 @@
} finally {
mICas = null;
}
+ } else if (mICasHidl != null) {
+ try {
+ mICasHidl.release();
+ } catch (RemoteException e) {
+ } finally {
+ mICasHidl = mICasHidl11 = mICasHidl12 = null;
+ }
}
if (mTunerResourceManager != null) {
diff --git a/media/java/android/media/MediaDescrambler.java b/media/java/android/media/MediaDescrambler.java
index 99bd254..b4bdf93d 100644
--- a/media/java/android/media/MediaDescrambler.java
+++ b/media/java/android/media/MediaDescrambler.java
@@ -17,14 +17,26 @@
package android.media;
import android.annotation.NonNull;
-import android.hardware.cas.V1_0.*;
+import android.hardware.cas.DestinationBuffer;
+import android.hardware.cas.IDescrambler;
+import android.hardware.cas.ScramblingControl;
+import android.hardware.cas.SharedBuffer;
+import android.hardware.cas.SubSample;
+import android.hardware.cas.V1_0.IDescramblerBase;
+import android.hardware.common.Ashmem;
+import android.hardware.common.NativeHandle;
import android.media.MediaCasException.UnsupportedCasException;
import android.os.IHwBinder;
+import android.os.ParcelFileDescriptor;
import android.os.RemoteException;
import android.os.ServiceSpecificException;
+import android.os.SharedMemory;
+import android.system.ErrnoException;
import android.util.Log;
+import java.io.IOException;
import java.nio.ByteBuffer;
+import java.util.ArrayList;
/**
* MediaDescrambler class can be used in conjunction with {@link android.media.MediaCodec}
@@ -39,7 +51,198 @@
*/
public final class MediaDescrambler implements AutoCloseable {
private static final String TAG = "MediaDescrambler";
- private IDescramblerBase mIDescrambler;
+ private DescramblerWrapper mIDescrambler;
+
+ private interface DescramblerWrapper {
+
+ IHwBinder asBinder();
+
+ int descramble(
+ @NonNull ByteBuffer srcBuf,
+ @NonNull ByteBuffer dstBuf,
+ @NonNull MediaCodec.CryptoInfo cryptoInfo)
+ throws RemoteException;
+
+ boolean requiresSecureDecoderComponent(@NonNull String mime) throws RemoteException;
+
+ void setMediaCasSession(byte[] sessionId) throws RemoteException;
+
+ void release() throws RemoteException;
+ }
+ ;
+
+ private long getSubsampleInfo(
+ int numSubSamples,
+ int[] numBytesOfClearData,
+ int[] numBytesOfEncryptedData,
+ SubSample[] subSamples) {
+ long totalSize = 0;
+
+ for (int i = 0; i < numSubSamples; i++) {
+ totalSize += numBytesOfClearData[i];
+ subSamples[i].numBytesOfClearData = numBytesOfClearData[i];
+ totalSize += numBytesOfEncryptedData[i];
+ subSamples[i].numBytesOfEncryptedData = numBytesOfEncryptedData[i];
+ }
+ return totalSize;
+ }
+
+ private ParcelFileDescriptor createSharedMemory(ByteBuffer buffer, String name)
+ throws RemoteException {
+ byte[] source = buffer.array();
+ if (source.length == 0) {
+ return null;
+ }
+ ParcelFileDescriptor fd = null;
+ try {
+ SharedMemory ashmem = SharedMemory.create(name == null ? "" : name, source.length);
+ ByteBuffer ptr = ashmem.mapReadWrite();
+ ptr.put(buffer);
+ ashmem.unmap(ptr);
+ fd = ashmem.getFdDup();
+ return fd;
+ } catch (ErrnoException | IOException e) {
+ throw new RemoteException(e);
+ }
+ }
+
+ private class AidlDescrambler implements DescramblerWrapper {
+
+ IDescrambler mAidlDescrambler;
+
+ AidlDescrambler(IDescrambler aidlDescrambler) {
+ mAidlDescrambler = aidlDescrambler;
+ }
+
+ @Override
+ public IHwBinder asBinder() {
+ return null;
+ }
+
+ @Override
+ public int descramble(
+ @NonNull ByteBuffer src,
+ @NonNull ByteBuffer dst,
+ @NonNull MediaCodec.CryptoInfo cryptoInfo)
+ throws RemoteException {
+ SubSample[] subSamples = new SubSample[cryptoInfo.numSubSamples];
+ long totalLength =
+ getSubsampleInfo(
+ cryptoInfo.numSubSamples,
+ cryptoInfo.numBytesOfClearData,
+ cryptoInfo.numBytesOfEncryptedData,
+ subSamples);
+ SharedBuffer srcBuffer = new SharedBuffer();
+ DestinationBuffer dstBuffer;
+ srcBuffer.heapBase = new Ashmem();
+ srcBuffer.heapBase.fd = createSharedMemory(src, "Descrambler Source Buffer");
+ srcBuffer.heapBase.size = src.array().length;
+ if (dst == null) {
+ dstBuffer = DestinationBuffer.nonsecureMemory(srcBuffer);
+ } else {
+ ParcelFileDescriptor pfd =
+ createSharedMemory(dst, "Descrambler Destination Buffer");
+ NativeHandle nh = new NativeHandle();
+ nh.fds = new ParcelFileDescriptor[] {pfd};
+ nh.ints = new int[] {1}; // Mark 1 since source buffer also uses it?
+ dstBuffer = DestinationBuffer.secureMemory(nh);
+ }
+ @ScramblingControl int control = cryptoInfo.key[0];
+
+ return mAidlDescrambler.descramble(
+ (byte) control,
+ subSamples,
+ srcBuffer,
+ src.position(),
+ dstBuffer,
+ dst.position());
+ }
+
+ @Override
+ public boolean requiresSecureDecoderComponent(@NonNull String mime) throws RemoteException {
+ return mAidlDescrambler.requiresSecureDecoderComponent(mime);
+ }
+
+ @Override
+ public void setMediaCasSession(byte[] sessionId) throws RemoteException {
+ mAidlDescrambler.setMediaCasSession(sessionId);
+ }
+
+ @Override
+ public void release() throws RemoteException {
+ mAidlDescrambler.release();
+ }
+ }
+
+ private class HidlDescrambler implements DescramblerWrapper {
+
+ IDescramblerBase mHidlDescrambler;
+
+ HidlDescrambler(IDescramblerBase hidlDescrambler) {
+ mHidlDescrambler = hidlDescrambler;
+ native_setup(hidlDescrambler.asBinder());
+ }
+
+ @Override
+ public IHwBinder asBinder() {
+ return mHidlDescrambler.asBinder();
+ }
+
+ @Override
+ public int descramble(
+ @NonNull ByteBuffer srcBuf,
+ @NonNull ByteBuffer dstBuf,
+ @NonNull MediaCodec.CryptoInfo cryptoInfo)
+ throws RemoteException {
+
+ try {
+ return native_descramble(
+ cryptoInfo.key[0],
+ cryptoInfo.key[1],
+ cryptoInfo.numSubSamples,
+ cryptoInfo.numBytesOfClearData,
+ cryptoInfo.numBytesOfEncryptedData,
+ srcBuf,
+ srcBuf.position(),
+ srcBuf.limit(),
+ dstBuf,
+ dstBuf.position(),
+ dstBuf.limit());
+ } catch (ServiceSpecificException e) {
+ MediaCasStateException.throwExceptionIfNeeded(e.errorCode, e.getMessage());
+ } catch (RemoteException e) {
+ cleanupAndRethrowIllegalState();
+ }
+ return -1;
+ }
+
+ @Override
+ public boolean requiresSecureDecoderComponent(@NonNull String mime) throws RemoteException {
+ return mHidlDescrambler.requiresSecureDecoderComponent(mime);
+ }
+
+ @Override
+ public void setMediaCasSession(byte[] sessionId) throws RemoteException {
+ ArrayList<Byte> byteArray = new ArrayList<>();
+
+ if (sessionId != null) {
+ int length = sessionId.length;
+ byteArray = new ArrayList<Byte>(length);
+ for (int i = 0; i < length; i++) {
+ byteArray.add(Byte.valueOf(sessionId[i]));
+ }
+ }
+
+ MediaCasStateException.throwExceptionIfNeeded(
+ mHidlDescrambler.setMediaCasSession(byteArray));
+ }
+
+ @Override
+ public void release() throws RemoteException {
+ mHidlDescrambler.release();
+ native_release();
+ }
+ }
private final void validateInternalStates() {
if (mIDescrambler == null) {
@@ -61,7 +264,14 @@
*/
public MediaDescrambler(int CA_system_id) throws UnsupportedCasException {
try {
- mIDescrambler = MediaCas.getService().createDescrambler(CA_system_id);
+ if (MediaCas.getService() != null) {
+ mIDescrambler =
+ new AidlDescrambler(MediaCas.getService().createDescrambler(CA_system_id));
+ } else if (MediaCas.getServiceHidl() != null) {
+ mIDescrambler =
+ new HidlDescrambler(
+ MediaCas.getServiceHidl().createDescrambler(CA_system_id));
+ }
} catch(Exception e) {
Log.e(TAG, "Failed to create descrambler: " + e);
mIDescrambler = null;
@@ -70,7 +280,6 @@
throw new UnsupportedCasException("Unsupported CA_system_id " + CA_system_id);
}
}
- native_setup(mIDescrambler.asBinder());
}
IHwBinder getBinder() {
@@ -117,8 +326,7 @@
validateInternalStates();
try {
- MediaCasStateException.throwExceptionIfNeeded(
- mIDescrambler.setMediaCasSession(session.mSessionId));
+ mIDescrambler.setMediaCasSession(session.mSessionId);
} catch (RemoteException e) {
cleanupAndRethrowIllegalState();
}
@@ -126,27 +334,31 @@
/**
* Scramble control value indicating that the samples are not scrambled.
+ *
* @see #descramble(ByteBuffer, ByteBuffer, android.media.MediaCodec.CryptoInfo)
*/
- public static final byte SCRAMBLE_CONTROL_UNSCRAMBLED = 0;
+ public static final byte SCRAMBLE_CONTROL_UNSCRAMBLED = (byte) ScramblingControl.UNSCRAMBLED;
/**
* Scramble control value reserved and shouldn't be used currently.
+ *
* @see #descramble(ByteBuffer, ByteBuffer, android.media.MediaCodec.CryptoInfo)
*/
- public static final byte SCRAMBLE_CONTROL_RESERVED = 1;
+ public static final byte SCRAMBLE_CONTROL_RESERVED = (byte) ScramblingControl.RESERVED;
/**
* Scramble control value indicating that the even key is used.
+ *
* @see #descramble(ByteBuffer, ByteBuffer, android.media.MediaCodec.CryptoInfo)
*/
- public static final byte SCRAMBLE_CONTROL_EVEN_KEY = 2;
+ public static final byte SCRAMBLE_CONTROL_EVEN_KEY = (byte) ScramblingControl.EVENKEY;
/**
* Scramble control value indicating that the odd key is used.
+ *
* @see #descramble(ByteBuffer, ByteBuffer, android.media.MediaCodec.CryptoInfo)
*/
- public static final byte SCRAMBLE_CONTROL_ODD_KEY = 3;
+ public static final byte SCRAMBLE_CONTROL_ODD_KEY = (byte) ScramblingControl.ODDKEY;
/**
* Scramble flag for a hint indicating that the descrambling request is for
@@ -207,14 +419,7 @@
}
try {
- return native_descramble(
- cryptoInfo.key[0],
- cryptoInfo.key[1],
- cryptoInfo.numSubSamples,
- cryptoInfo.numBytesOfClearData,
- cryptoInfo.numBytesOfEncryptedData,
- srcBuf, srcBuf.position(), srcBuf.limit(),
- dstBuf, dstBuf.position(), dstBuf.limit());
+ return mIDescrambler.descramble(srcBuf, dstBuf, cryptoInfo);
} catch (ServiceSpecificException e) {
MediaCasStateException.throwExceptionIfNeeded(e.errorCode, e.getMessage());
} catch (RemoteException e) {
@@ -233,7 +438,6 @@
mIDescrambler = null;
}
}
- native_release();
}
@Override
@@ -256,4 +460,4 @@
}
private long mNativeContext;
-}
\ No newline at end of file
+}
diff --git a/media/java/android/media/MediaExtractor.java b/media/java/android/media/MediaExtractor.java
index dab188e..b11a810 100644
--- a/media/java/android/media/MediaExtractor.java
+++ b/media/java/android/media/MediaExtractor.java
@@ -36,7 +36,6 @@
import java.lang.annotation.RetentionPolicy;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
-import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
@@ -325,14 +324,6 @@
}
}
- private ArrayList<Byte> toByteArray(@NonNull byte[] data) {
- ArrayList<Byte> byteArray = new ArrayList<Byte>(data.length);
- for (int i = 0; i < data.length; i++) {
- byteArray.add(i, Byte.valueOf(data[i]));
- }
- return byteArray;
- }
-
/**
* Retrieves the information about the conditional access system used to scramble
* a track.
@@ -357,7 +348,7 @@
buf.rewind();
final byte[] sessionId = new byte[buf.remaining()];
buf.get(sessionId);
- session = mMediaCas.createFromSessionId(toByteArray(sessionId));
+ session = mMediaCas.createFromSessionId(sessionId);
}
return new CasInfo(systemId, session, privateData);
}
diff --git a/media/java/android/media/RoutingSessionInfo.java b/media/java/android/media/RoutingSessionInfo.java
index 0982132..e1af909 100644
--- a/media/java/android/media/RoutingSessionInfo.java
+++ b/media/java/android/media/RoutingSessionInfo.java
@@ -23,7 +23,6 @@
import android.os.Parcel;
import android.os.Parcelable;
import android.text.TextUtils;
-import android.util.Log;
import com.android.internal.util.Preconditions;
@@ -117,6 +116,8 @@
mProviderId = src.readString();
mSelectedRoutes = ensureList(src.createStringArrayList());
+ Preconditions.checkArgument(!mSelectedRoutes.isEmpty());
+
mSelectableRoutes = ensureList(src.createStringArrayList());
mDeselectableRoutes = ensureList(src.createStringArrayList());
mTransferableRoutes = ensureList(src.createStringArrayList());
@@ -416,15 +417,21 @@
return result.toString();
}
+ /**
+ * Provides a new list with unique route IDs if {@link #mProviderId} is set, or the original IDs
+ * otherwise.
+ *
+ * @param routeIds list of route IDs to convert
+ * @return new list with unique IDs or original IDs
+ */
+
+ @NonNull
private List<String> convertToUniqueRouteIds(@NonNull List<String> routeIds) {
- if (routeIds == null) {
- Log.w(TAG, "routeIds is null. Returning an empty list");
- return Collections.emptyList();
- }
+ Objects.requireNonNull(routeIds, "RouteIds cannot be null.");
// mProviderId can be null if not set. Return the original list for this case.
if (TextUtils.isEmpty(mProviderId)) {
- return routeIds;
+ return new ArrayList<>(routeIds);
}
List<String> result = new ArrayList<>();
diff --git a/media/java/android/media/tv/ITvInputClient.aidl b/media/java/android/media/tv/ITvInputClient.aidl
index ed2fd20..d55d287 100644
--- a/media/java/android/media/tv/ITvInputClient.aidl
+++ b/media/java/android/media/tv/ITvInputClient.aidl
@@ -49,6 +49,7 @@
void onTimeShiftCurrentPositionChanged(long timeMs, int seq);
void onAitInfoUpdated(in AitInfo aitInfo, int seq);
void onSignalStrength(int stength, int seq);
+ void onTvMessage(in String type, in Bundle data, int seq);
void onTuned(in Uri channelUri, int seq);
// For the recording session
diff --git a/media/java/android/media/tv/ITvInputSessionCallback.aidl b/media/java/android/media/tv/ITvInputSessionCallback.aidl
index b2a8d1c..8216622 100644
--- a/media/java/android/media/tv/ITvInputSessionCallback.aidl
+++ b/media/java/android/media/tv/ITvInputSessionCallback.aidl
@@ -58,4 +58,7 @@
// For ad response
void onAdResponse(in AdResponse response);
void onAdBufferConsumed(in AdBuffer buffer);
+
+ // For messages sent from the TV input
+ void onTvMessage(in String type, in Bundle data);
}
diff --git a/media/java/android/media/tv/TvInputManager.java b/media/java/android/media/tv/TvInputManager.java
index 690fcb1..e6da1a3 100644
--- a/media/java/android/media/tv/TvInputManager.java
+++ b/media/java/android/media/tv/TvInputManager.java
@@ -22,6 +22,7 @@
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.RequiresPermission;
+import android.annotation.StringDef;
import android.annotation.SystemApi;
import android.annotation.SystemService;
import android.annotation.TestApi;
@@ -130,6 +131,20 @@
VIDEO_UNAVAILABLE_REASON_CAS_REBOOTING, VIDEO_UNAVAILABLE_REASON_CAS_UNKNOWN})
public @interface VideoUnavailableReason {}
+ /**
+ * @hide
+ */
+ public static final String TV_MESSAGE_TYPE_WATERMARK = "Watermark";
+ /**
+ * @hide
+ */
+ public static final String TV_MESSAGE_TYPE_ATSC_CC = "ATSC_CC";
+
+ /** @hide */
+ @Retention(RetentionPolicy.SOURCE)
+ @StringDef({TV_MESSAGE_TYPE_WATERMARK, TV_MESSAGE_TYPE_ATSC_CC})
+ public @interface TvMessageType {}
+
static final int VIDEO_UNAVAILABLE_REASON_START = 0;
static final int VIDEO_UNAVAILABLE_REASON_END = 18;
@@ -690,6 +705,17 @@
public void onTuned(Session session, Uri channelUri) {
}
+ /**
+ * This is called when the session receives a new Tv Message
+ *
+ * @param type the type of {@link TvMessageType}
+ * @param data the raw data of the message
+ * @hide
+ */
+ public void onTvMessage(Session session, @TvInputManager.TvMessageType String type,
+ Bundle data) {
+ }
+
// For the recording session only
/**
* This is called when the current recording session has stopped recording and created a
@@ -919,6 +945,19 @@
});
}
+ void postTvMessage(String type, Bundle data) {
+ mHandler.post(new Runnable() {
+ @Override
+ public void run() {
+ mSessionCallback.onTvMessage(mSession, type, data);
+ if (mSession.mIAppNotificationEnabled
+ && mSession.getInteractiveAppSession() != null) {
+ mSession.getInteractiveAppSession().notifyTvMessage(type, data);
+ }
+ }
+ });
+ }
+
// For the recording session only
void postRecordingStopped(final Uri recordedProgramUri) {
mHandler.post(new Runnable() {
@@ -1379,6 +1418,18 @@
}
@Override
+ public void onTvMessage(String type, Bundle data, int seq) {
+ synchronized (mSessionCallbackRecordMap) {
+ SessionCallbackRecord record = mSessionCallbackRecordMap.get(seq);
+ if (record == null) {
+ Log.e(TAG, "Callback not found for seq " + seq);
+ return;
+ }
+ record.postTvMessage(type, data);
+ }
+ }
+
+ @Override
public void onRecordingStopped(Uri recordedProgramUri, int seq) {
synchronized (mSessionCallbackRecordMap) {
SessionCallbackRecord record = mSessionCallbackRecordMap.get(seq);
diff --git a/media/java/android/media/tv/TvInputService.java b/media/java/android/media/tv/TvInputService.java
index c46cdbc..15f511b 100755
--- a/media/java/android/media/tv/TvInputService.java
+++ b/media/java/android/media/tv/TvInputService.java
@@ -2063,6 +2063,27 @@
}
/**
+ * Informs the application of the raw data from the TV message.
+ * @param type The {@link TvInputManager.TvMessageType} of message that was sent.
+ * @param data The data sent with the message.
+ * @hide
+ */
+ public void notifyTvMessage(@TvInputManager.TvMessageType String type, Bundle data) {
+ }
+
+ /**
+ * Called when the application enables or disables the detection of the specified message
+ * type.
+ * @param type The {@link TvInputManager.TvMessageType} of message that was sent.
+ * @param enabled {@code true} if you want to enable TV message detecting
+ * {@code false} otherwise.
+ * @hide
+ */
+ public void onSetTvMessageEnabled(@TvInputManager.TvMessageType String type,
+ boolean enabled) {
+ }
+
+ /**
* Called when the application requests to tune to a given channel for TV program recording.
*
* <p>The application may call this method before starting or after stopping recording, but
diff --git a/media/java/android/media/tv/TvView.java b/media/java/android/media/tv/TvView.java
index ff3d06c..2fdbc3b 100644
--- a/media/java/android/media/tv/TvView.java
+++ b/media/java/android/media/tv/TvView.java
@@ -653,6 +653,17 @@
mOnUnhandledInputEventListener = listener;
}
+ /**
+ * Enables or disables TV message detecting in the streams of bound TV input.
+ *
+ * @param type The type of {@link android.media.tv.TvInputManager.TvMessageType}
+ * @param enabled {@code true} if you want to enable TV message detecting
+ * {@code false} otherwise.
+ * @hide
+ */
+ public void setTvMessageEnabled(@TvInputManager.TvMessageType String type, boolean enabled) {
+ }
+
@Override
public boolean dispatchKeyEvent(KeyEvent event) {
if (super.dispatchKeyEvent(event)) {
@@ -1094,6 +1105,17 @@
*/
public void onTuned(@NonNull String inputId, @NonNull Uri channelUri) {
}
+
+ /**
+ * This is called when the session has been tuned to the given channel.
+ *
+ * @param type The type of {@link android.media.tv.TvInputManager.TvMessageType}
+ * @param data The raw data of the message
+ * @hide
+ */
+ public void onTvMessage(@NonNull String inputId, @TvInputManager.TvMessageType String type,
+ Bundle data) {
+ }
}
/**
@@ -1432,5 +1454,19 @@
mCallback.onTuned(mInputId, channelUri);
}
}
+
+ @Override
+ public void onTvMessage(Session session, String type, Bundle data) {
+ if (DEBUG) {
+ Log.d(TAG, "onTvMessage(type=" + type + ", data=" + data + ")");
+ }
+ if (this != mSessionCallback) {
+ Log.w(TAG, "onTvMessage - session not created");
+ return;
+ }
+ if (mCallback != null) {
+ mCallback.onTvMessage(mInputId, type, data);
+ }
+ }
}
}
diff --git a/media/java/android/media/tv/interactive/ITvInteractiveAppClient.aidl b/media/java/android/media/tv/interactive/ITvInteractiveAppClient.aidl
index 537e711..494571f 100644
--- a/media/java/android/media/tv/interactive/ITvInteractiveAppClient.aidl
+++ b/media/java/android/media/tv/interactive/ITvInteractiveAppClient.aidl
@@ -41,6 +41,7 @@
void onTeletextAppStateChanged(int state, int seq);
void onAdBuffer(in AdBuffer buffer, int seq);
void onCommandRequest(in String cmdType, in Bundle parameters, int seq);
+ void onTimeShiftCommandRequest(in String cmdType, in Bundle parameters, int seq);
void onSetVideoBounds(in Rect rect, int seq);
void onRequestCurrentChannelUri(int seq);
void onRequestCurrentChannelLcn(int seq);
diff --git a/media/java/android/media/tv/interactive/ITvInteractiveAppManager.aidl b/media/java/android/media/tv/interactive/ITvInteractiveAppManager.aidl
index 3b272daa..1cfb6ef 100644
--- a/media/java/android/media/tv/interactive/ITvInteractiveAppManager.aidl
+++ b/media/java/android/media/tv/interactive/ITvInteractiveAppManager.aidl
@@ -26,6 +26,7 @@
import android.media.tv.interactive.ITvInteractiveAppClient;
import android.media.tv.interactive.ITvInteractiveAppManagerCallback;
import android.media.tv.interactive.TvInteractiveAppServiceInfo;
+import android.media.PlaybackParams;
import android.net.Uri;
import android.os.Bundle;
import android.view.Surface;
@@ -57,6 +58,14 @@
void sendTvRecordingInfoList(in IBinder sessionToken,
in List<TvRecordingInfo> recordingInfoList, int userId);
void notifyError(in IBinder sessionToken, in String errMsg, in Bundle params, int userId);
+ void notifyTimeShiftPlaybackParams(
+ in IBinder sessionToken, in PlaybackParams params, int userId);
+ void notifyTimeShiftStatusChanged(
+ in IBinder sessionToken, in String inputId, int status, int userId);
+ void notifyTimeShiftStartPositionChanged(
+ in IBinder sessionToken, in String inputId, long timeMs, int userId);
+ void notifyTimeShiftCurrentPositionChanged(
+ in IBinder sessionToken, in String inputId, long timeMs, int userId);
void createSession(in ITvInteractiveAppClient client, in String iAppServiceId, int type,
int seq, int userId);
void releaseSession(in IBinder sessionToken, int userId);
@@ -70,6 +79,7 @@
void notifySignalStrength(in IBinder sessionToken, int stength, int userId);
void notifyRecordingStarted(in IBinder sessionToken, in String recordingId, int userId);
void notifyRecordingStopped(in IBinder sessionToken, in String recordingId, int userId);
+ void notifyTvMessage(in IBinder sessionToken, in String type, in Bundle data, int userId);
void setSurface(in IBinder sessionToken, in Surface surface, int userId);
void dispatchSurfaceChanged(in IBinder sessionToken, int format, int width, int height,
int userId);
diff --git a/media/java/android/media/tv/interactive/ITvInteractiveAppSession.aidl b/media/java/android/media/tv/interactive/ITvInteractiveAppSession.aidl
index bc09cea..17a70d1 100644
--- a/media/java/android/media/tv/interactive/ITvInteractiveAppSession.aidl
+++ b/media/java/android/media/tv/interactive/ITvInteractiveAppSession.aidl
@@ -20,6 +20,7 @@
import android.media.tv.BroadcastInfoResponse;
import android.net.Uri;
import android.media.tv.AdBuffer;
+import android.media.PlaybackParams;
import android.media.tv.AdResponse;
import android.media.tv.BroadcastInfoResponse;
import android.media.tv.TvTrackInfo;
@@ -48,6 +49,10 @@
void sendTvRecordingInfo(in TvRecordingInfo recordingInfo);
void sendTvRecordingInfoList(in List<TvRecordingInfo> recordingInfoList);
void notifyError(in String errMsg, in Bundle params);
+ void notifyTimeShiftPlaybackParams(in PlaybackParams params);
+ void notifyTimeShiftStatusChanged(in String inputId, int status);
+ void notifyTimeShiftStartPositionChanged(in String inputId, long timeMs);
+ void notifyTimeShiftCurrentPositionChanged(in String inputId, long timeMs);
void release();
void notifyTuned(in Uri channelUri);
void notifyTrackSelected(int type, in String trackId);
@@ -59,6 +64,7 @@
void notifySignalStrength(int strength);
void notifyRecordingStarted(in String recordingId);
void notifyRecordingStopped(in String recordingId);
+ void notifyTvMessage(in String type, in Bundle data);
void setSurface(in Surface surface);
void dispatchSurfaceChanged(int format, int width, int height);
void notifyBroadcastInfoResponse(in BroadcastInfoResponse response);
diff --git a/media/java/android/media/tv/interactive/ITvInteractiveAppSessionCallback.aidl b/media/java/android/media/tv/interactive/ITvInteractiveAppSessionCallback.aidl
index c5dbd19..0565742 100644
--- a/media/java/android/media/tv/interactive/ITvInteractiveAppSessionCallback.aidl
+++ b/media/java/android/media/tv/interactive/ITvInteractiveAppSessionCallback.aidl
@@ -40,6 +40,7 @@
void onTeletextAppStateChanged(int state);
void onAdBuffer(in AdBuffer buffer);
void onCommandRequest(in String cmdType, in Bundle parameters);
+ void onTimeShiftCommandRequest(in String cmdType, in Bundle parameters);
void onSetVideoBounds(in Rect rect);
void onRequestCurrentChannelUri();
void onRequestCurrentChannelLcn();
diff --git a/media/java/android/media/tv/interactive/ITvInteractiveAppSessionWrapper.java b/media/java/android/media/tv/interactive/ITvInteractiveAppSessionWrapper.java
index af031dc..b8158cd 100644
--- a/media/java/android/media/tv/interactive/ITvInteractiveAppSessionWrapper.java
+++ b/media/java/android/media/tv/interactive/ITvInteractiveAppSessionWrapper.java
@@ -20,6 +20,7 @@
import android.annotation.Nullable;
import android.content.Context;
import android.graphics.Rect;
+import android.media.PlaybackParams;
import android.media.tv.AdBuffer;
import android.media.tv.AdResponse;
import android.media.tv.BroadcastInfoResponse;
@@ -86,8 +87,13 @@
private static final int DO_NOTIFY_RECORDING_STARTED = 30;
private static final int DO_NOTIFY_RECORDING_STOPPED = 31;
private static final int DO_NOTIFY_AD_BUFFER_CONSUMED = 32;
- private static final int DO_SEND_RECORDING_INFO = 33;
- private static final int DO_SEND_RECORDING_INFO_LIST = 34;
+ private static final int DO_NOTIFY_TV_MESSAGE = 33;
+ private static final int DO_SEND_RECORDING_INFO = 34;
+ private static final int DO_SEND_RECORDING_INFO_LIST = 35;
+ private static final int DO_NOTIFY_TIME_SHIFT_PLAYBACK_PARAMS = 36;
+ private static final int DO_NOTIFY_TIME_SHIFT_STATUS_CHANGED = 37;
+ private static final int DO_NOTIFY_TIME_SHIFT_START_POSITION_CHANGED = 38;
+ private static final int DO_NOTIFY_TIME_SHIFT_CURRENT_POSITION_CHANGED = 39;
private final HandlerCaller mCaller;
private Session mSessionImpl;
@@ -213,6 +219,12 @@
mSessionImpl.notifyTracksChanged((List<TvTrackInfo>) msg.obj);
break;
}
+ case DO_NOTIFY_TV_MESSAGE: {
+ SomeArgs args = (SomeArgs) msg.obj;
+ mSessionImpl.notifyTvMessage((String) args.arg1, (Bundle) args.arg2);
+ args.recycle();
+ break;
+ }
case DO_NOTIFY_VIDEO_AVAILABLE: {
mSessionImpl.notifyVideoAvailable();
break;
@@ -270,6 +282,30 @@
mSessionImpl.notifyAdBufferConsumed((AdBuffer) msg.obj);
break;
}
+ case DO_NOTIFY_TIME_SHIFT_PLAYBACK_PARAMS: {
+ mSessionImpl.notifyTimeShiftPlaybackParams((PlaybackParams) msg.obj);
+ break;
+ }
+ case DO_NOTIFY_TIME_SHIFT_STATUS_CHANGED: {
+ SomeArgs args = (SomeArgs) msg.obj;
+ mSessionImpl.notifyTimeShiftStatusChanged((String) args.arg1, (Integer) args.arg2);
+ args.recycle();
+ break;
+ }
+ case DO_NOTIFY_TIME_SHIFT_START_POSITION_CHANGED: {
+ SomeArgs args = (SomeArgs) msg.obj;
+ mSessionImpl.notifyTimeShiftStartPositionChanged(
+ (String) args.arg1, (Long) args.arg2);
+ args.recycle();
+ break;
+ }
+ case DO_NOTIFY_TIME_SHIFT_CURRENT_POSITION_CHANGED: {
+ SomeArgs args = (SomeArgs) msg.obj;
+ mSessionImpl.notifyTimeShiftCurrentPositionChanged(
+ (String) args.arg1, (Long) args.arg2);
+ args.recycle();
+ break;
+ }
default: {
Log.w(TAG, "Unhandled message code: " + msg.what);
break;
@@ -373,6 +409,30 @@
}
@Override
+ public void notifyTimeShiftPlaybackParams(@NonNull PlaybackParams params) {
+ mCaller.executeOrSendMessage(
+ mCaller.obtainMessageO(DO_NOTIFY_TIME_SHIFT_PLAYBACK_PARAMS, params));
+ }
+
+ @Override
+ public void notifyTimeShiftStatusChanged(@NonNull String inputId, int status) {
+ mCaller.executeOrSendMessage(
+ mCaller.obtainMessageOO(DO_NOTIFY_TIME_SHIFT_STATUS_CHANGED, inputId, status));
+ }
+
+ @Override
+ public void notifyTimeShiftStartPositionChanged(@NonNull String inputId, long timeMs) {
+ mCaller.executeOrSendMessage(mCaller.obtainMessageOO(
+ DO_NOTIFY_TIME_SHIFT_START_POSITION_CHANGED, inputId, timeMs));
+ }
+
+ @Override
+ public void notifyTimeShiftCurrentPositionChanged(@NonNull String inputId, long timeMs) {
+ mCaller.executeOrSendMessage(mCaller.obtainMessageOO(
+ DO_NOTIFY_TIME_SHIFT_CURRENT_POSITION_CHANGED, inputId, timeMs));
+ }
+
+ @Override
public void release() {
mSessionImpl.scheduleMediaViewCleanup();
mCaller.executeOrSendMessage(mCaller.obtainMessage(DO_RELEASE));
@@ -390,6 +450,12 @@
}
@Override
+ public void notifyTvMessage(String type, Bundle data) {
+ mCaller.executeOrSendMessage(
+ mCaller.obtainMessageOO(DO_NOTIFY_TRACK_SELECTED, type, data));
+ }
+
+ @Override
public void notifyTracksChanged(List<TvTrackInfo> tracks) {
mCaller.executeOrSendMessage(mCaller.obtainMessageO(DO_NOTIFY_TRACKS_CHANGED, tracks));
}
diff --git a/media/java/android/media/tv/interactive/TvInteractiveAppManager.java b/media/java/android/media/tv/interactive/TvInteractiveAppManager.java
index fa60b66..3647a9c 100755
--- a/media/java/android/media/tv/interactive/TvInteractiveAppManager.java
+++ b/media/java/android/media/tv/interactive/TvInteractiveAppManager.java
@@ -23,6 +23,7 @@
import android.annotation.SystemService;
import android.content.Context;
import android.graphics.Rect;
+import android.media.PlaybackParams;
import android.media.tv.AdBuffer;
import android.media.tv.AdRequest;
import android.media.tv.AdResponse;
@@ -405,6 +406,21 @@
}
@Override
+ public void onTimeShiftCommandRequest(
+ @TvInteractiveAppService.TimeShiftCommandType String cmdType,
+ Bundle parameters,
+ int seq) {
+ synchronized (mSessionCallbackRecordMap) {
+ SessionCallbackRecord record = mSessionCallbackRecordMap.get(seq);
+ if (record == null) {
+ Log.e(TAG, "Callback not found for seq " + seq);
+ return;
+ }
+ record.postTimeShiftCommandRequest(cmdType, parameters);
+ }
+ }
+
+ @Override
public void onSetVideoBounds(Rect rect, int seq) {
synchronized (mSessionCallbackRecordMap) {
SessionCallbackRecord record = mSessionCallbackRecordMap.get(seq);
@@ -1182,6 +1198,55 @@
}
}
+ void notifyTimeShiftPlaybackParams(@NonNull PlaybackParams params) {
+ if (mToken == null) {
+ Log.w(TAG, "The session has been already released");
+ return;
+ }
+ try {
+ mService.notifyTimeShiftPlaybackParams(mToken, params, mUserId);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
+ void notifyTimeShiftStatusChanged(
+ @NonNull String inputId, @TvInputManager.TimeShiftStatus int status) {
+ if (mToken == null) {
+ Log.w(TAG, "The session has been already released");
+ return;
+ }
+ try {
+ mService.notifyTimeShiftStatusChanged(mToken, inputId, status, mUserId);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
+ void notifyTimeShiftStartPositionChanged(@NonNull String inputId, long timeMs) {
+ if (mToken == null) {
+ Log.w(TAG, "The session has been already released");
+ return;
+ }
+ try {
+ mService.notifyTimeShiftStartPositionChanged(mToken, inputId, timeMs, mUserId);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
+ void notifyTimeShiftCurrentPositionChanged(@NonNull String inputId, long timeMs) {
+ if (mToken == null) {
+ Log.w(TAG, "The session has been already released");
+ return;
+ }
+ try {
+ mService.notifyTimeShiftCurrentPositionChanged(mToken, inputId, timeMs, mUserId);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
/**
* Sets the {@link android.view.Surface} for this session.
*
@@ -1504,6 +1569,21 @@
}
}
+ /**
+ * Notifies Interactive APP session when a new TV message is received.
+ */
+ public void notifyTvMessage(String type, Bundle data) {
+ if (mToken == null) {
+ Log.w(TAG, "The session has been already released");
+ return;
+ }
+ try {
+ mService.notifyTvMessage(mToken, type, data, mUserId);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
private void flushPendingEventsLocked() {
mHandler.removeMessages(InputEventHandler.MSG_FLUSH_INPUT_EVENT);
@@ -1780,6 +1860,17 @@
});
}
+ void postTimeShiftCommandRequest(
+ final @TvInteractiveAppService.TimeShiftCommandType String cmdType,
+ final Bundle parameters) {
+ mHandler.post(new Runnable() {
+ @Override
+ public void run() {
+ mSessionCallback.onTimeShiftCommandRequest(mSession, cmdType, parameters);
+ }
+ });
+ }
+
void postSetVideoBounds(Rect rect) {
mHandler.post(new Runnable() {
@Override
@@ -1988,6 +2079,20 @@
}
/**
+ * This is called when {@link TvInteractiveAppService.Session#requestTimeShiftCommand} is
+ * called.
+ *
+ * @param session A {@link TvInteractiveAppManager.Session} associated with this callback.
+ * @param cmdType type of the time shift command.
+ * @param parameters parameters of the command.
+ */
+ public void onTimeShiftCommandRequest(
+ Session session,
+ @TvInteractiveAppService.TimeShiftCommandType String cmdType,
+ Bundle parameters) {
+ }
+
+ /**
* This is called when {@link TvInteractiveAppService.Session#SetVideoBounds} is called.
*
* @param session A {@link TvInteractiveAppManager.Session} associated with this callback.
diff --git a/media/java/android/media/tv/interactive/TvInteractiveAppService.java b/media/java/android/media/tv/interactive/TvInteractiveAppService.java
index 1fa0aaa..949e017 100755
--- a/media/java/android/media/tv/interactive/TvInteractiveAppService.java
+++ b/media/java/android/media/tv/interactive/TvInteractiveAppService.java
@@ -30,6 +30,7 @@
import android.content.Intent;
import android.graphics.PixelFormat;
import android.graphics.Rect;
+import android.media.PlaybackParams;
import android.media.tv.AdBuffer;
import android.media.tv.AdRequest;
import android.media.tv.AdResponse;
@@ -182,6 +183,78 @@
public static final String COMMAND_PARAMETER_KEY_CHANGE_CHANNEL_QUIETLY =
"command_change_channel_quietly";
+ /** @hide */
+ @Retention(RetentionPolicy.SOURCE)
+ @StringDef(prefix = "TIME_SHIFT_COMMAND_TYPE_", value = {
+ TIME_SHIFT_COMMAND_TYPE_PLAY,
+ TIME_SHIFT_COMMAND_TYPE_PAUSE,
+ TIME_SHIFT_COMMAND_TYPE_RESUME,
+ TIME_SHIFT_COMMAND_TYPE_SEEK_TO,
+ TIME_SHIFT_COMMAND_TYPE_SET_PLAYBACK_PARAMS,
+ })
+ public @interface TimeShiftCommandType {}
+
+ /**
+ * Time shift command type: play.
+ *
+ * @see TvView#timeShiftPlay(String, Uri)
+ * @hide
+ */
+ public static final String TIME_SHIFT_COMMAND_TYPE_PLAY = "play";
+ /**
+ * Time shift command type: pause.
+ *
+ * @see TvView#timeShiftPause()
+ * @hide
+ */
+ public static final String TIME_SHIFT_COMMAND_TYPE_PAUSE = "pause";
+ /**
+ * Time shift command type: resume.
+ *
+ * @see TvView#timeShiftResume()
+ * @hide
+ */
+ public static final String TIME_SHIFT_COMMAND_TYPE_RESUME = "resume";
+ /**
+ * Time shift command type: seek to.
+ *
+ * @see TvView#timeShiftSeekTo(long)
+ * @hide
+ */
+ public static final String TIME_SHIFT_COMMAND_TYPE_SEEK_TO = "seek_to";
+ /**
+ * Time shift command type: set playback params.
+ *
+ * @see TvView#timeShiftSetPlaybackParams(PlaybackParams)
+ * @hide
+ */
+ public static final String TIME_SHIFT_COMMAND_TYPE_SET_PLAYBACK_PARAMS = "set_playback_params";
+
+ /**
+ * Time shift command parameter: program URI.
+ * <p>Type: android.net.Uri
+ *
+ * @see #TIME_SHIFT_COMMAND_TYPE_PLAY
+ * @hide
+ */
+ public static final String COMMAND_PARAMETER_KEY_PROGRAM_URI = "command_program_uri";
+ /**
+ * Time shift command parameter: time position for time shifting, in milliseconds.
+ * <p>Type: long
+ *
+ * @see #TIME_SHIFT_COMMAND_TYPE_SEEK_TO
+ * @hide
+ */
+ public static final String COMMAND_PARAMETER_KEY_TIME_POSITION = "command_time_position";
+ /**
+ * Time shift command parameter: playback params.
+ * <p>Type: android.media.PlaybackParams
+ *
+ * @see #TIME_SHIFT_COMMAND_TYPE_SET_PLAYBACK_PARAMS
+ * @hide
+ */
+ public static final String COMMAND_PARAMETER_KEY_PLAYBACK_PARAMS = "command_playback_params";
+
private final Handler mServiceHandler = new ServiceHandler();
private final RemoteCallbackList<ITvInteractiveAppServiceCallback> mCallbacks =
new RemoteCallbackList<>();
@@ -520,6 +593,44 @@
}
/**
+ * Called when the time shift {@link android.media.PlaybackParams} is set or changed.
+ *
+ * @see TvView#timeShiftSetPlaybackParams(PlaybackParams)
+ * @hide
+ */
+ public void onTimeShiftPlaybackParams(@NonNull PlaybackParams params) {
+ }
+
+ /**
+ * Called when time shift status is changed.
+ *
+ * @see TvView.TvInputCallback#onTimeShiftStatusChanged(String, int)
+ * @see android.media.tv.TvInputService.Session#notifyTimeShiftStatusChanged(int)
+ * @hide
+ */
+ public void onTimeShiftStatusChanged(
+ @NonNull String inputId, @TvInputManager.TimeShiftStatus int status) {
+ }
+
+ /**
+ * Called when time shift start position is changed.
+ *
+ * @see TvView.TimeShiftPositionCallback#onTimeShiftStartPositionChanged(String, long)
+ * @hide
+ */
+ public void onTimeShiftStartPositionChanged(@NonNull String inputId, long timeMs) {
+ }
+
+ /**
+ * Called when time shift current position is changed.
+ *
+ * @see TvView.TimeShiftPositionCallback#onTimeShiftCurrentPositionChanged(String, long)
+ * @hide
+ */
+ public void onTimeShiftCurrentPositionChanged(@NonNull String inputId, long timeMs) {
+ }
+
+ /**
* Called when the application sets the surface.
*
* <p>The TV Interactive App service should render interactive app UI onto the given
@@ -641,6 +752,14 @@
* @hide
*/
public void onAdBufferConsumed(AdBuffer buffer) {
+
+ }
+
+ /**
+ * Called when a tv message is received
+ * @hide
+ */
+ public void onTvMessage(@NonNull String type, @NonNull Bundle data) {
}
@Override
@@ -812,6 +931,35 @@
}
/**
+ * Sends a specific time shift command to be processed by the related TV input.
+ *
+ * @param cmdType type of the specific command
+ * @param parameters parameters of the specific command
+ * @hide
+ */
+ @CallSuper
+ public void sendTimeShiftCommandRequest(
+ @TimeShiftCommandType @NonNull String cmdType, @Nullable Bundle parameters) {
+ executeOrPostRunnableOnMainThread(new Runnable() {
+ @MainThread
+ @Override
+ public void run() {
+ try {
+ if (DEBUG) {
+ Log.d(TAG, "requestTimeShiftCommand (cmdType=" + cmdType
+ + ", parameters=" + parameters.toString() + ")");
+ }
+ if (mSessionCallback != null) {
+ mSessionCallback.onTimeShiftCommandRequest(cmdType, parameters);
+ }
+ } catch (RemoteException e) {
+ Log.w(TAG, "error in requestTimeShiftCommand", e);
+ }
+ }
+ });
+ }
+
+ /**
* Sets broadcast video bounds.
*/
@CallSuper
@@ -1289,6 +1437,13 @@
onAdResponse(response);
}
+ void notifyTvMessage(String type, Bundle data) {
+ if (DEBUG) {
+ Log.d(TAG, "notifyTvMessage (type=" + type + ", data= " + data + ")");
+ }
+ onTvMessage(type, data);
+ }
+
/**
* Calls {@link #onAdBufferConsumed}.
*/
@@ -1315,6 +1470,34 @@
}
/**
+ * Calls {@link #onTimeShiftPlaybackParams(PlaybackParams)}.
+ */
+ void notifyTimeShiftPlaybackParams(PlaybackParams params) {
+ onTimeShiftPlaybackParams(params);
+ }
+
+ /**
+ * Calls {@link #onTimeShiftStatusChanged(String, int)}.
+ */
+ void notifyTimeShiftStatusChanged(String inputId, int status) {
+ onTimeShiftStatusChanged(inputId, status);
+ }
+
+ /**
+ * Calls {@link #onTimeShiftStartPositionChanged(String, long)}.
+ */
+ void notifyTimeShiftStartPositionChanged(String inputId, long timeMs) {
+ onTimeShiftStartPositionChanged(inputId, timeMs);
+ }
+
+ /**
+ * Calls {@link #onTimeShiftCurrentPositionChanged(String, long)}.
+ */
+ void notifyTimeShiftCurrentPositionChanged(String inputId, long timeMs) {
+ onTimeShiftCurrentPositionChanged(inputId, timeMs);
+ }
+
+ /**
* Notifies when the session state is changed.
*
* @param state the current session state.
diff --git a/media/java/android/media/tv/interactive/TvInteractiveAppView.java b/media/java/android/media/tv/interactive/TvInteractiveAppView.java
index 6777d1a..9211a12 100755
--- a/media/java/android/media/tv/interactive/TvInteractiveAppView.java
+++ b/media/java/android/media/tv/interactive/TvInteractiveAppView.java
@@ -25,6 +25,7 @@
import android.graphics.PixelFormat;
import android.graphics.Rect;
import android.graphics.RectF;
+import android.media.PlaybackParams;
import android.media.tv.TvInputManager;
import android.media.tv.TvRecordingInfo;
import android.media.tv.TvTrackInfo;
@@ -684,6 +685,75 @@
}
}
+ /**
+ * Notifies the corresponding {@link TvInteractiveAppService} when a time shift
+ * {@link android.media.PlaybackParams} is set or changed.
+ *
+ * @see TvView#timeShiftSetPlaybackParams(PlaybackParams)
+ * @hide
+ */
+ public void notifyTimeShiftPlaybackParams(@NonNull PlaybackParams params) {
+ if (DEBUG) {
+ Log.d(TAG, "notifyTimeShiftPlaybackParams params=" + params);
+ }
+ if (mSession != null) {
+ mSession.notifyTimeShiftPlaybackParams(params);
+ }
+ }
+
+ /**
+ * Notifies the corresponding {@link TvInteractiveAppService} when time shift
+ * status is changed.
+ *
+ * @see TvView.TvInputCallback#onTimeShiftStatusChanged(String, int)
+ * @see android.media.tv.TvInputService.Session#notifyTimeShiftStatusChanged(int)
+ * @hide
+ */
+ public void notifyTimeShiftStatusChanged(
+ @NonNull String inputId, @TvInputManager.TimeShiftStatus int status) {
+ if (DEBUG) {
+ Log.d(TAG,
+ "notifyTimeShiftStatusChanged inputId=" + inputId + "; status=" + status);
+ }
+ if (mSession != null) {
+ mSession.notifyTimeShiftStatusChanged(inputId, status);
+ }
+ }
+
+ /**
+ * Notifies the corresponding {@link TvInteractiveAppService} when time shift
+ * start position is changed.
+ *
+ * @see TvView.TimeShiftPositionCallback#onTimeShiftStartPositionChanged(String, long)
+ * @hide
+ */
+ public void notifyTimeShiftStartPositionChanged(@NonNull String inputId, long timeMs) {
+ if (DEBUG) {
+ Log.d(TAG, "notifyTimeShiftStartPositionChanged inputId=" + inputId
+ + "; timeMs=" + timeMs);
+ }
+ if (mSession != null) {
+ mSession.notifyTimeShiftStartPositionChanged(inputId, timeMs);
+ }
+ }
+
+ /**
+ * Notifies the corresponding {@link TvInteractiveAppService} when time shift
+ * current position is changed.
+ *
+ * @see TvView.TimeShiftPositionCallback#onTimeShiftCurrentPositionChanged(String, long)
+ * @hide
+ */
+ public void notifyTimeShiftCurrentPositionChanged(@NonNull String inputId, long timeMs) {
+ if (DEBUG) {
+ Log.d(TAG, "notifyTimeShiftCurrentPositionChanged inputId=" + inputId
+ + "; timeMs=" + timeMs);
+ }
+ if (mSession != null) {
+ mSession.notifyTimeShiftCurrentPositionChanged(inputId, timeMs);
+ }
+ }
+
private void resetInternal() {
mSessionCallback = null;
if (mSession != null) {
@@ -808,6 +878,21 @@
}
/**
+ * This is called when a time shift command is requested to be processed by the related TV
+ * input.
+ *
+ * @param iAppServiceId The ID of the TV interactive app service bound to this view.
+ * @param cmdType type of the command
+ * @param parameters parameters of the command
+ * @hide
+ */
+ public void onTimeShiftCommandRequest(
+ @NonNull String iAppServiceId,
+ @NonNull @TvInteractiveAppService.TimeShiftCommandType String cmdType,
+ @NonNull Bundle parameters) {
+ }
+
+ /**
* This is called when the state of corresponding interactive app is changed.
*
* @param iAppServiceId The ID of the TV interactive app service bound to this view.
@@ -1068,6 +1153,33 @@
}
@Override
+ public void onTimeShiftCommandRequest(
+ Session session,
+ @TvInteractiveAppService.TimeShiftCommandType String cmdType,
+ Bundle parameters) {
+ if (DEBUG) {
+ Log.d(TAG, "onTimeShiftCommandRequest (cmdType=" + cmdType + ", parameters="
+ + parameters.toString() + ")");
+ }
+ if (this != mSessionCallback) {
+ Log.w(TAG, "onTimeShiftCommandRequest - session not created");
+ return;
+ }
+ synchronized (mCallbackLock) {
+ if (mCallbackExecutor != null) {
+ mCallbackExecutor.execute(() -> {
+ synchronized (mCallbackLock) {
+ if (mCallback != null) {
+ mCallback.onTimeShiftCommandRequest(
+ mIAppServiceId, cmdType, parameters);
+ }
+ }
+ });
+ }
+ }
+ }
+
+ @Override
public void onSessionStateChanged(
Session session,
@TvInteractiveAppManager.InteractiveAppState int state,
diff --git a/media/jni/android_media_MediaCodec.cpp b/media/jni/android_media_MediaCodec.cpp
index d8705a7..5b0c2a2 100644
--- a/media/jni/android_media_MediaCodec.cpp
+++ b/media/jni/android_media_MediaCodec.cpp
@@ -2432,13 +2432,12 @@
throwExceptionAsNecessary(env, BAD_VALUE);
return;
}
- NativeCryptoInfo cryptoInfo = [env, cryptoInfoObj, size]{
- if (cryptoInfoObj == nullptr) {
- return NativeCryptoInfo{size};
- } else {
- return NativeCryptoInfo{env, cryptoInfoObj};
- }
- }();
+ auto cryptoInfo =
+ cryptoInfoObj ? NativeCryptoInfo{size} : NativeCryptoInfo{env, cryptoInfoObj};
+ if (env->ExceptionCheck()) {
+ // Creation of cryptoInfo failed. Let the exception bubble up.
+ return;
+ }
err = codec->queueEncryptedLinearBlock(
index,
memory,
diff --git a/media/lib/remotedisplay/java/com/android/media/remotedisplay/RemoteDisplayProvider.java b/media/lib/remotedisplay/java/com/android/media/remotedisplay/RemoteDisplayProvider.java
index 2cba03b..8752e3d 100644
--- a/media/lib/remotedisplay/java/com/android/media/remotedisplay/RemoteDisplayProvider.java
+++ b/media/lib/remotedisplay/java/com/android/media/remotedisplay/RemoteDisplayProvider.java
@@ -312,7 +312,7 @@
| Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED
| Intent.FLAG_ACTIVITY_CLEAR_TOP);
mSettingsPendingIntent = PendingIntent.getActivity(
- mContext, 0, settingsIntent, PendingIntent.FLAG_MUTABLE_UNAUDITED, null);
+ mContext, 0, settingsIntent, PendingIntent.FLAG_IMMUTABLE, null);
}
return mSettingsPendingIntent;
}
diff --git a/media/tests/AudioPolicyTest/res/values/strings.xml b/media/tests/AudioPolicyTest/res/values/strings.xml
index 0365927..128c3c5 100644
--- a/media/tests/AudioPolicyTest/res/values/strings.xml
+++ b/media/tests/AudioPolicyTest/res/values/strings.xml
@@ -2,4 +2,7 @@
<resources>
<!-- name of the app [CHAR LIMIT=25]-->
<string name="app_name">Audio Policy APIs Tests</string>
+ <string name="capture_duration_key">captureDurationMs</string>
+ <string name="callback_key">callback</string>
+ <string name="status_key">result</string>
</resources>
diff --git a/media/tests/AudioPolicyTest/src/com/android/audiopolicytest/AudioPolicyDeathTest.java b/media/tests/AudioPolicyTest/src/com/android/audiopolicytest/AudioPolicyDeathTest.java
index 841804b..48c51af 100644
--- a/media/tests/AudioPolicyTest/src/com/android/audiopolicytest/AudioPolicyDeathTest.java
+++ b/media/tests/AudioPolicyTest/src/com/android/audiopolicytest/AudioPolicyDeathTest.java
@@ -20,6 +20,8 @@
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
+import static org.junit.Assume.assumeNoException;
+import static org.junit.Assume.assumeTrue;
import android.content.BroadcastReceiver;
import android.content.Context;
@@ -30,6 +32,8 @@
import android.media.AudioFormat;
import android.media.AudioManager;
import android.media.AudioTrack;
+import android.os.Bundle;
+import android.os.RemoteCallback;
import android.platform.test.annotations.Presubmit;
import android.util.Log;
@@ -39,33 +43,62 @@
import org.junit.Test;
import org.junit.runner.RunWith;
+import java.util.concurrent.CompletableFuture;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.ExecutionException;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.TimeoutException;
+
@Presubmit
@RunWith(AndroidJUnit4.class)
public class AudioPolicyDeathTest {
private static final String TAG = "AudioPolicyDeathTest";
private static final int SAMPLE_RATE = 48000;
- private static final int PLAYBACK_TIME_MS = 2000;
+ private static final int PLAYBACK_TIME_MS = 4000;
+ private static final int RECORD_TIME_MS = 1000;
+ private static final int ACTIVITY_TIMEOUT_SEC = 5;
+ private static final int BROADCAST_TIMEOUT_SEC = 10;
+ private static final int MAX_ATTEMPTS = 5;
+ private static final int DELAY_BETWEEN_ATTEMPTS_MS = 2000;
private static final IntentFilter AUDIO_NOISY_INTENT_FILTER =
new IntentFilter(AudioManager.ACTION_AUDIO_BECOMING_NOISY);
private class MyBroadcastReceiver extends BroadcastReceiver {
- private boolean mReceived = false;
+ private CountDownLatch mLatch = new CountDownLatch(1);
+
@Override
public void onReceive(Context context, Intent intent) {
if (AudioManager.ACTION_AUDIO_BECOMING_NOISY.equals(intent.getAction())) {
- synchronized (this) {
- mReceived = true;
- notify();
- }
+ mLatch.countDown();
}
}
- public synchronized boolean received() {
- return mReceived;
+ public void reset() {
+ mLatch = new CountDownLatch(1);
+ }
+
+ public boolean waitForBroadcast() {
+ boolean received = false;
+ long startTimeMs = System.currentTimeMillis();
+ long elapsedTimeMs = 0;
+
+ Log.i(TAG, "waiting for broadcast");
+
+ while (elapsedTimeMs < BROADCAST_TIMEOUT_SEC && !received) {
+ try {
+ received = mLatch.await(BROADCAST_TIMEOUT_SEC, TimeUnit.SECONDS);
+ } catch (InterruptedException e) {
+ Log.w(TAG, "wait interrupted");
+ }
+ elapsedTimeMs = System.currentTimeMillis() - startTimeMs;
+ }
+ Log.i(TAG, "broadcast " + (received ? "" : "NOT ") + "received");
+ return received;
}
}
+
private final MyBroadcastReceiver mReceiver = new MyBroadcastReceiver();
private Context mContext;
@@ -85,31 +118,55 @@
public void testPolicyClientDeathSendBecomingNoisyIntent() {
mContext.registerReceiver(mReceiver, AUDIO_NOISY_INTENT_FILTER);
- // Launch process registering a dynamic auido policy and dying after PLAYBACK_TIME_MS/2 ms
- Intent intent = new Intent(mContext, AudioPolicyDeathTestActivity.class);
- intent.putExtra("captureDurationMs", PLAYBACK_TIME_MS / 2);
- intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK);
- mContext.startActivity(intent);
+ boolean result = false;
+ for (int numAttempts = 1; numAttempts <= MAX_ATTEMPTS && !result; numAttempts++) {
+ mReceiver.reset();
- AudioTrack track = createAudioTrack();
- track.play();
- synchronized (mReceiver) {
- long startTimeMs = System.currentTimeMillis();
- long elapsedTimeMs = 0;
- while (elapsedTimeMs < PLAYBACK_TIME_MS && !mReceiver.received()) {
- try {
- mReceiver.wait(PLAYBACK_TIME_MS - elapsedTimeMs);
- } catch (InterruptedException e) {
- Log.w(TAG, "wait interrupted");
+ CompletableFuture<Integer> callbackReturn = new CompletableFuture<>();
+ RemoteCallback cb = new RemoteCallback((Bundle res) -> {
+ callbackReturn.complete(
+ res.getInt(mContext.getResources().getString(R.string.status_key)));
+ });
+
+ // Launch process registering a dynamic auido policy and dying after RECORD_TIME_MS ms
+ // RECORD_TIME_MS must be shorter than PLAYBACK_TIME_MS
+ Intent intent = new Intent(mContext, AudioPolicyDeathTestActivity.class);
+ intent.putExtra(mContext.getResources().getString(R.string.capture_duration_key),
+ RECORD_TIME_MS);
+ intent.putExtra(mContext.getResources().getString(R.string.callback_key), cb);
+ intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK);
+
+ mContext.startActivity(intent);
+
+ Integer status = AudioManager.ERROR;
+ try {
+ status = callbackReturn.get(ACTIVITY_TIMEOUT_SEC, TimeUnit.SECONDS);
+ } catch (InterruptedException | ExecutionException | TimeoutException e) {
+ assumeNoException(e);
+ }
+ assumeTrue(status != null && status == AudioManager.SUCCESS);
+
+ Log.i(TAG, "Activity started");
+ AudioTrack track = null;
+ try {
+ track = createAudioTrack();
+ track.play();
+ result = mReceiver.waitForBroadcast();
+ } finally {
+ if (track != null) {
+ track.stop();
+ track.release();
}
- elapsedTimeMs = System.currentTimeMillis() - startTimeMs;
+ }
+ if (!result) {
+ try {
+ Log.i(TAG, "Retrying after attempt: " + numAttempts);
+ Thread.sleep(DELAY_BETWEEN_ATTEMPTS_MS);
+ } catch (InterruptedException e) {
+ }
}
}
-
- track.stop();
- track.release();
-
- assertTrue(mReceiver.received());
+ assertTrue(result);
}
private AudioTrack createAudioTrack() {
diff --git a/media/tests/AudioPolicyTest/src/com/android/audiopolicytest/AudioPolicyDeathTestActivity.java b/media/tests/AudioPolicyTest/src/com/android/audiopolicytest/AudioPolicyDeathTestActivity.java
index 957e719..ce5f56c 100644
--- a/media/tests/AudioPolicyTest/src/com/android/audiopolicytest/AudioPolicyDeathTestActivity.java
+++ b/media/tests/AudioPolicyTest/src/com/android/audiopolicytest/AudioPolicyDeathTestActivity.java
@@ -26,6 +26,7 @@
import android.media.audiopolicy.AudioPolicy;
import android.os.Bundle;
import android.os.Looper;
+import android.os.RemoteCallback;
import android.util.Log;
// This activity will register a dynamic audio policy to intercept media playback and launch
@@ -71,19 +72,29 @@
mAudioPolicy = audioPolicyBuilder.build();
int result = mAudioManager.registerAudioPolicy(mAudioPolicy);
- if (result != AudioManager.SUCCESS) {
+ if (result == AudioManager.SUCCESS) {
+ AudioRecord audioRecord = mAudioPolicy.createAudioRecordSink(audioMix);
+ if (audioRecord != null && audioRecord.getState() != AudioRecord.STATE_UNINITIALIZED) {
+ int captureDurationMs = getIntent().getIntExtra(
+ getString(R.string.capture_duration_key), RECORD_TIME_MS);
+ AudioCapturingThread thread =
+ new AudioCapturingThread(audioRecord, captureDurationMs);
+ thread.start();
+ } else {
+ Log.w(TAG, "AudioRecord creation failed");
+ result = AudioManager.ERROR_NO_INIT;
+ }
+ } else {
Log.w(TAG, "registerAudioPolicy failed, status: " + result);
- return;
- }
- AudioRecord audioRecord = mAudioPolicy.createAudioRecordSink(audioMix);
- if (audioRecord == null) {
- Log.w(TAG, "AudioRecord creation failed");
- return;
}
- int captureDurationMs = getIntent().getIntExtra("captureDurationMs", RECORD_TIME_MS);
- AudioCapturingThread thread = new AudioCapturingThread(audioRecord, captureDurationMs);
- thread.start();
+ RemoteCallback cb =
+ (RemoteCallback) getIntent().getExtras().get(getString(R.string.callback_key));
+ Bundle res = new Bundle();
+ res.putInt(getString(R.string.status_key), result);
+ Log.i(TAG, "policy " + (result == AudioManager.SUCCESS ? "" : "un")
+ + "successfully registered");
+ cb.sendResult(res);
}
@Override
diff --git a/native/webview/TEST_MAPPING b/native/webview/TEST_MAPPING
index bd25200..c1bc6d7 100644
--- a/native/webview/TEST_MAPPING
+++ b/native/webview/TEST_MAPPING
@@ -9,6 +9,14 @@
]
},
{
+ "name": "CtsSdkSandboxWebkitTestCases",
+ "options": [
+ {
+ "exclude-annotation": "androidx.test.filters.FlakyTest"
+ }
+ ]
+ },
+ {
"name": "CtsHostsideWebViewTests",
"options": [
{
diff --git a/packages/CredentialManager/Android.bp b/packages/CredentialManager/Android.bp
index d8577c3..90bb2d1 100644
--- a/packages/CredentialManager/Android.bp
+++ b/packages/CredentialManager/Android.bp
@@ -14,6 +14,11 @@
srcs: ["src/**/*.kt"],
resource_dirs: ["res"],
+ dex_preopt: {
+ profile_guided: true,
+ profile: "profile.txt.prof",
+ },
+
static_libs: [
"androidx.activity_activity-compose",
"androidx.appcompat_appcompat",
diff --git a/packages/CredentialManager/AndroidManifest.xml b/packages/CredentialManager/AndroidManifest.xml
index bd27dab..5a4d256 100644
--- a/packages/CredentialManager/AndroidManifest.xml
+++ b/packages/CredentialManager/AndroidManifest.xml
@@ -32,9 +32,11 @@
android:supportsRtl="true"
android:theme="@style/Theme.CredentialSelector">
+ <!--TODO: make sure implementing singleTop on NewIntent-->
<activity
android:name=".CredentialSelectorActivity"
android:exported="true"
+ android:launchMode="singleTop"
android:label="@string/app_name"
android:excludeFromRecents="true"
android:theme="@style/Theme.CredentialSelector">
diff --git a/packages/CredentialManager/profile.txt.prof b/packages/CredentialManager/profile.txt.prof
new file mode 100644
index 0000000..16f8798
--- /dev/null
+++ b/packages/CredentialManager/profile.txt.prof
@@ -0,0 +1,14627 @@
+HPLandroidx/compose/animation/core/FloatSpringSpec;->getValueFromNanos(JFFF)F
+HPLandroidx/compose/animation/core/FloatSpringSpec;->getVelocityFromNanos(JFFF)F
+HPLandroidx/compose/animation/core/SpringSimulation;->updateValues-IJZedt4$animation_core_release(FFJ)J
+HPLandroidx/compose/animation/core/VectorConvertersKt$FloatToVector$2;->invoke(Landroidx/compose/animation/core/AnimationVector1D;)Ljava/lang/Float;
+HPLandroidx/compose/animation/core/VectorizedSpringSpec;->getValueFromNanos(JLandroidx/compose/animation/core/AnimationVector;Landroidx/compose/animation/core/AnimationVector;Landroidx/compose/animation/core/AnimationVector;)Landroidx/compose/animation/core/AnimationVector;
+HPLandroidx/compose/animation/core/VectorizedSpringSpec;->getVelocityFromNanos(JLandroidx/compose/animation/core/AnimationVector;Landroidx/compose/animation/core/AnimationVector;Landroidx/compose/animation/core/AnimationVector;)Landroidx/compose/animation/core/AnimationVector;
+HPLandroidx/compose/foundation/ImageKt;->Image(Landroidx/compose/ui/graphics/painter/Painter;Ljava/lang/String;Landroidx/compose/ui/Modifier;Landroidx/compose/ui/Alignment;Landroidx/compose/ui/layout/ContentScale;FLandroidx/compose/ui/graphics/ColorFilter;Landroidx/compose/runtime/Composer;II)V
+HPLandroidx/compose/foundation/gestures/TapGestureDetectorKt;->waitForUpOrCancellation(Landroidx/compose/ui/input/pointer/AwaitPointerEventScope;Landroidx/compose/ui/input/pointer/PointerEventPass;Lkotlin/coroutines/Continuation;)Ljava/lang/Object;
+HPLandroidx/compose/foundation/lazy/LazyListKt$rememberLazyListMeasurePolicy$1$1$measuredItemProvider$1;->createItem-HK0c1C0(ILjava/lang/Object;Ljava/util/List;)Landroidx/compose/foundation/lazy/LazyMeasuredItem;
+HPLandroidx/compose/foundation/lazy/LazyListKt$rememberLazyListMeasurePolicy$1$1;->invoke-0kLqBqw(Landroidx/compose/foundation/lazy/layout/LazyLayoutMeasureScope;J)Landroidx/compose/foundation/lazy/LazyListMeasureResult;
+HPLandroidx/compose/foundation/lazy/LazyListMeasureKt;->measureLazyList-jIHJTys(ILandroidx/compose/foundation/lazy/LazyMeasuredItemProvider;IIIIIIFJZLjava/util/List;Landroidx/compose/foundation/layout/Arrangement$Vertical;Landroidx/compose/foundation/layout/Arrangement$Horizontal;ZLandroidx/compose/ui/unit/Density;Landroidx/compose/foundation/lazy/LazyListItemPlacementAnimator;Landroidx/compose/foundation/lazy/LazyListBeyondBoundsInfo;ILkotlin/jvm/functions/Function3;)Landroidx/compose/foundation/lazy/LazyListMeasureResult;
+HPLandroidx/compose/foundation/lazy/LazyListPositionedItem;->place(Landroidx/compose/ui/layout/Placeable$PlacementScope;)V
+HPLandroidx/compose/foundation/lazy/LazyMeasuredItem;-><init>(ILjava/util/List;ZLandroidx/compose/ui/Alignment$Horizontal;Landroidx/compose/ui/Alignment$Vertical;Landroidx/compose/ui/unit/LayoutDirection;ZIILandroidx/compose/foundation/lazy/LazyListItemPlacementAnimator;IJLjava/lang/Object;)V
+HPLandroidx/compose/foundation/lazy/layout/DefaultLazyLayoutItemsProvider;->getKey(I)Ljava/lang/Object;
+HPLandroidx/compose/foundation/lazy/layout/LazyLayoutItemContentFactory;->getContent(ILjava/lang/Object;)Lkotlin/jvm/functions/Function2;
+HPLandroidx/compose/foundation/lazy/layout/LazyLayoutMeasureScopeImpl;->measure-0kLqBqw(IJ)Ljava/util/List;
+HPLandroidx/compose/runtime/ComposerKt;->removeCurrentGroup(Landroidx/compose/runtime/SlotWriter;Landroidx/compose/runtime/RememberManager;)V
+HPLandroidx/compose/runtime/DerivedSnapshotState$ResultRecord;->isValid(Landroidx/compose/runtime/DerivedState;Landroidx/compose/runtime/snapshots/Snapshot;)Z
+HPLandroidx/compose/runtime/DerivedSnapshotState$ResultRecord;->readableHash(Landroidx/compose/runtime/DerivedState;Landroidx/compose/runtime/snapshots/Snapshot;)I
+HPLandroidx/compose/runtime/DerivedSnapshotState;->currentRecord(Landroidx/compose/runtime/DerivedSnapshotState$ResultRecord;Landroidx/compose/runtime/snapshots/Snapshot;ZLkotlin/jvm/functions/Function0;)Landroidx/compose/runtime/DerivedSnapshotState$ResultRecord;
+HPLandroidx/compose/runtime/DerivedSnapshotState;->getValue()Ljava/lang/Object;
+HPLandroidx/compose/runtime/SlotWriter$groupSlots$1;->hasNext()Z
+HPLandroidx/compose/runtime/SlotWriter$groupSlots$1;->next()Ljava/lang/Object;
+HPLandroidx/compose/runtime/SlotWriter;->access$dataIndexToDataAddress(Landroidx/compose/runtime/SlotWriter;I)I
+HPLandroidx/compose/runtime/SnapshotStateKt__SnapshotFlowKt$snapshotFlow$1$unregisterApplyObserver$1;->invoke(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;
+HPLandroidx/compose/runtime/SnapshotStateKt__SnapshotFlowKt$snapshotFlow$1$unregisterApplyObserver$1;->invoke(Ljava/util/Set;Landroidx/compose/runtime/snapshots/Snapshot;)V
+HPLandroidx/compose/runtime/SnapshotStateKt__SnapshotFlowKt$snapshotFlow$1;->invokeSuspend(Ljava/lang/Object;)Ljava/lang/Object;
+HPLandroidx/compose/runtime/SnapshotStateKt__SnapshotFlowKt;->intersects$SnapshotStateKt__SnapshotFlowKt(Ljava/util/Set;Ljava/util/Set;)Z
+HPLandroidx/compose/runtime/snapshots/SnapshotKt;->current(Landroidx/compose/runtime/snapshots/StateRecord;Landroidx/compose/runtime/snapshots/Snapshot;)Landroidx/compose/runtime/snapshots/StateRecord;
+HPLandroidx/compose/runtime/snapshots/SnapshotStateObserver$ObservedScopeMap$derivedStateEnterObserver$1;->invoke(Landroidx/compose/runtime/State;)V
+HPLandroidx/compose/runtime/snapshots/SnapshotStateObserver$ObservedScopeMap$derivedStateExitObserver$1;->invoke(Landroidx/compose/runtime/State;)V
+HPLandroidx/compose/runtime/snapshots/SnapshotStateObserver$ObservedScopeMap$derivedStateExitObserver$1;->invoke(Ljava/lang/Object;)Ljava/lang/Object;
+HPLandroidx/compose/runtime/snapshots/SnapshotStateObserver$ObservedScopeMap;->access$getDeriveStateScopeCount$p(Landroidx/compose/runtime/snapshots/SnapshotStateObserver$ObservedScopeMap;)I
+HPLandroidx/compose/ui/Modifier$Node;->detach$ui_release()V
+HPLandroidx/compose/ui/geometry/OffsetKt;->isFinite-k-4lQ0M(J)Z
+HPLandroidx/compose/ui/graphics/Matrix;->map-MK-Hz9U([FJ)J
+HPLandroidx/compose/ui/input/pointer/InternalPointerEvent;->issuesEnterExitEvent-0FcD4WY(J)Z
+HPLandroidx/compose/ui/input/pointer/MotionEventAdapter;->convertToPointerInputEvent$ui_release(Landroid/view/MotionEvent;Landroidx/compose/ui/input/pointer/PositionCalculator;)Landroidx/compose/ui/input/pointer/PointerInputEvent;
+HPLandroidx/compose/ui/input/pointer/MotionEventAdapter;->createPointerInputEventData(Landroidx/compose/ui/input/pointer/PositionCalculator;Landroid/view/MotionEvent;IZ)Landroidx/compose/ui/input/pointer/PointerInputEventData;
+HPLandroidx/compose/ui/input/pointer/Node;->buildCache(Ljava/util/Map;Landroidx/compose/ui/layout/LayoutCoordinates;Landroidx/compose/ui/input/pointer/InternalPointerEvent;Z)Z
+HPLandroidx/compose/ui/input/pointer/Node;->cleanUpHits(Landroidx/compose/ui/input/pointer/InternalPointerEvent;)V
+HPLandroidx/compose/ui/input/pointer/Node;->dispatchFinalEventPass(Landroidx/compose/ui/input/pointer/InternalPointerEvent;)Z
+HPLandroidx/compose/ui/input/pointer/Node;->dispatchMainEventPass(Ljava/util/Map;Landroidx/compose/ui/layout/LayoutCoordinates;Landroidx/compose/ui/input/pointer/InternalPointerEvent;Z)Z
+HPLandroidx/compose/ui/input/pointer/PointerId;-><init>(J)V
+HPLandroidx/compose/ui/input/pointer/PointerId;->equals-impl(JLjava/lang/Object;)Z
+HPLandroidx/compose/ui/input/pointer/PointerInputChange;-><init>(JJJZJJZZIJ)V
+HPLandroidx/compose/ui/input/pointer/PointerInputChange;->copy-OHpmEuE$default(Landroidx/compose/ui/input/pointer/PointerInputChange;JJJZJJZILjava/util/List;JILjava/lang/Object;)Landroidx/compose/ui/input/pointer/PointerInputChange;
+HPLandroidx/compose/ui/input/pointer/PointerInputChange;->copy-OHpmEuE(JJJZJJZILjava/util/List;J)Landroidx/compose/ui/input/pointer/PointerInputChange;
+HPLandroidx/compose/ui/input/pointer/PointerInputChangeEventProducer;->produce(Landroidx/compose/ui/input/pointer/PointerInputEvent;Landroidx/compose/ui/input/pointer/PositionCalculator;)Landroidx/compose/ui/input/pointer/InternalPointerEvent;
+HPLandroidx/compose/ui/input/pointer/PointerInputEventProcessor;->process-BIzXfog(Landroidx/compose/ui/input/pointer/PointerInputEvent;Landroidx/compose/ui/input/pointer/PositionCalculator;Z)I
+HPLandroidx/compose/ui/input/pointer/SuspendingPointerInputFilter$PointerEventHandlerCoroutine;->offerPointerEvent(Landroidx/compose/ui/input/pointer/PointerEvent;Landroidx/compose/ui/input/pointer/PointerEventPass;)V
+HPLandroidx/compose/ui/input/pointer/SuspendingPointerInputFilter;->dispatchPointerEvent(Landroidx/compose/ui/input/pointer/PointerEvent;Landroidx/compose/ui/input/pointer/PointerEventPass;)V
+HPLandroidx/compose/ui/input/pointer/SuspendingPointerInputFilter;->onPointerEvent-H0pRuoY(Landroidx/compose/ui/input/pointer/PointerEvent;Landroidx/compose/ui/input/pointer/PointerEventPass;J)V
+HPLandroidx/compose/ui/node/AlignmentLines;->reset$ui_release()V
+HPLandroidx/compose/ui/node/BackwardsCompatNode;->onPointerEvent-H0pRuoY(Landroidx/compose/ui/input/pointer/PointerEvent;Landroidx/compose/ui/input/pointer/PointerEventPass;J)V
+HPLandroidx/compose/ui/node/InnerNodeCoordinator;->hitTestChild-YqVAtuI(Landroidx/compose/ui/node/NodeCoordinator$HitTestSource;JLandroidx/compose/ui/node/HitTestResult;ZZ)V
+HPLandroidx/compose/ui/node/LayoutNode;->detach$ui_release()V
+HPLandroidx/compose/ui/node/NodeChain;->detach$ui_release()V
+HPLandroidx/compose/ui/node/NodeCoordinator;->ancestorToLocal-R5De75A(Landroidx/compose/ui/node/NodeCoordinator;J)J
+HPLandroidx/compose/ui/node/NodeCoordinator;->detach()V
+HPLandroidx/compose/ui/node/NodeCoordinator;->findCommonAncestor$ui_release(Landroidx/compose/ui/node/NodeCoordinator;)Landroidx/compose/ui/node/NodeCoordinator;
+HPLandroidx/compose/ui/node/NodeCoordinator;->fromParentPosition-MK-Hz9U(J)J
+HPLandroidx/compose/ui/node/NodeCoordinator;->hitTestChild-YqVAtuI(Landroidx/compose/ui/node/NodeCoordinator$HitTestSource;JLandroidx/compose/ui/node/HitTestResult;ZZ)V
+HPLandroidx/compose/ui/node/NodeCoordinator;->localPositionOf-R5De75A(Landroidx/compose/ui/layout/LayoutCoordinates;J)J
+HPLandroidx/compose/ui/node/PointerInputModifierNodeKt;->isAttached(Landroidx/compose/ui/node/PointerInputModifierNode;)Z
+HPLandroidx/compose/ui/platform/AndroidComposeView;->handleMotionEvent-8iAsVTc(Landroid/view/MotionEvent;)I
+HPLandroidx/compose/ui/platform/AndroidComposeView;->screenToLocal-MK-Hz9U(J)J
+HPLandroidx/compose/ui/platform/AndroidComposeView;->sendMotionEvent-8iAsVTc(Landroid/view/MotionEvent;)I
+HPLandroidx/compose/ui/platform/CalculateMatrixToWindowApi29;->calculateMatrixToWindow-EL8BTi8(Landroid/view/View;[F)V
+HPLandroidx/compose/ui/platform/LayerMatrixCache;->calculateInverseMatrix-bWbORWo(Ljava/lang/Object;)[F
+HPLandroidx/compose/ui/platform/LayerMatrixCache;->calculateMatrix-GrdbGEg(Ljava/lang/Object;)[F
+HPLandroidx/compose/ui/platform/RenderNodeLayer;->mapOffset-8S9VItk(JZ)J
+HPLandroidx/compose/ui/platform/ShapeContainingUtilKt;->cornersFit(Landroidx/compose/ui/geometry/RoundRect;)Z
+HPLandroidx/compose/ui/platform/ShapeContainingUtilKt;->isInRoundedRect(Landroidx/compose/ui/graphics/Outline$Rounded;FFLandroidx/compose/ui/graphics/Path;Landroidx/compose/ui/graphics/Path;)Z
+HPLandroidx/compose/ui/unit/IntOffsetKt;->minus-Nv-tHpc(JJ)J
+HPLcom/android/credentialmanager/common/material/SwipeableState$animateInternalToOffset$2$1;->invoke(Landroidx/compose/animation/core/Animatable;)V
+HPLcom/android/credentialmanager/getflow/GetCredentialComponentsKt$CredentialEntryRow$2;->invoke(Landroidx/compose/runtime/Composer;I)V
+HPLkotlinx/coroutines/JobSupport;->cancelMakeCompleting(Ljava/lang/Object;)Ljava/lang/Object;
+HPLkotlinx/coroutines/channels/AbstractSendChannel;->offerInternal(Ljava/lang/Object;)Ljava/lang/Object;
+HSPLandroidx/activity/ComponentActivity$$ExternalSyntheticLambda0;-><init>(Landroidx/activity/ComponentActivity;)V
+HSPLandroidx/activity/ComponentActivity$$ExternalSyntheticLambda1;-><init>(Landroidx/activity/ComponentActivity;)V
+HSPLandroidx/activity/ComponentActivity$$ExternalSyntheticLambda2;-><init>(Landroidx/activity/ComponentActivity;)V
+HSPLandroidx/activity/ComponentActivity$$ExternalSyntheticLambda3;-><init>(Landroidx/activity/ComponentActivity;)V
+HSPLandroidx/activity/ComponentActivity$$ExternalSyntheticLambda3;->onContextAvailable(Landroid/content/Context;)V
+HSPLandroidx/activity/ComponentActivity$1;-><init>(Landroidx/activity/ComponentActivity;)V
+HSPLandroidx/activity/ComponentActivity$2;-><init>(Landroidx/activity/ComponentActivity;)V
+HSPLandroidx/activity/ComponentActivity$3;-><init>(Landroidx/activity/ComponentActivity;)V
+HSPLandroidx/activity/ComponentActivity$3;->onStateChanged(Landroidx/lifecycle/LifecycleOwner;Landroidx/lifecycle/Lifecycle$Event;)V
+HSPLandroidx/activity/ComponentActivity$4;-><init>(Landroidx/activity/ComponentActivity;)V
+HSPLandroidx/activity/ComponentActivity$4;->onStateChanged(Landroidx/lifecycle/LifecycleOwner;Landroidx/lifecycle/Lifecycle$Event;)V
+HSPLandroidx/activity/ComponentActivity$5;-><init>(Landroidx/activity/ComponentActivity;)V
+HSPLandroidx/activity/ComponentActivity$5;->onStateChanged(Landroidx/lifecycle/LifecycleOwner;Landroidx/lifecycle/Lifecycle$Event;)V
+HSPLandroidx/activity/ComponentActivity$Api33Impl;->getOnBackInvokedDispatcher(Landroid/app/Activity;)Landroid/window/OnBackInvokedDispatcher;
+HSPLandroidx/activity/ComponentActivity$ReportFullyDrawnExecutorApi16Impl;-><init>(Landroidx/activity/ComponentActivity;)V
+HSPLandroidx/activity/ComponentActivity$ReportFullyDrawnExecutorApi16Impl;->onDraw()V
+HSPLandroidx/activity/ComponentActivity$ReportFullyDrawnExecutorApi16Impl;->viewCreated(Landroid/view/View;)V
+HSPLandroidx/activity/ComponentActivity;->$r8$lambda$h2i_RK2mddCIbAsGubaI4eL8_cU(Landroidx/activity/ComponentActivity;Landroid/content/Context;)V
+HSPLandroidx/activity/ComponentActivity;-><init>()V
+HSPLandroidx/activity/ComponentActivity;->addOnContextAvailableListener(Landroidx/activity/contextaware/OnContextAvailableListener;)V
+HSPLandroidx/activity/ComponentActivity;->createFullyDrawnExecutor()Landroidx/activity/ComponentActivity$ReportFullyDrawnExecutor;
+HSPLandroidx/activity/ComponentActivity;->ensureViewModelStore()V
+HSPLandroidx/activity/ComponentActivity;->getActivityResultRegistry()Landroidx/activity/result/ActivityResultRegistry;
+HSPLandroidx/activity/ComponentActivity;->getDefaultViewModelCreationExtras()Landroidx/lifecycle/viewmodel/CreationExtras;
+HSPLandroidx/activity/ComponentActivity;->getDefaultViewModelProviderFactory()Landroidx/lifecycle/ViewModelProvider$Factory;
+HSPLandroidx/activity/ComponentActivity;->getLifecycle()Landroidx/lifecycle/Lifecycle;
+HSPLandroidx/activity/ComponentActivity;->getSavedStateRegistry()Landroidx/savedstate/SavedStateRegistry;
+HSPLandroidx/activity/ComponentActivity;->getViewModelStore()Landroidx/lifecycle/ViewModelStore;
+HSPLandroidx/activity/ComponentActivity;->initViewTreeOwners()V
+HSPLandroidx/activity/ComponentActivity;->lambda$new$2(Landroid/content/Context;)V
+HSPLandroidx/activity/ComponentActivity;->onCreate(Landroid/os/Bundle;)V
+HSPLandroidx/activity/ComponentActivity;->setContentView(Landroid/view/View;Landroid/view/ViewGroup$LayoutParams;)V
+HSPLandroidx/activity/FullyDrawnReporter$$ExternalSyntheticLambda0;-><init>(Landroidx/activity/FullyDrawnReporter;)V
+HSPLandroidx/activity/FullyDrawnReporter;-><init>(Ljava/util/concurrent/Executor;Lkotlin/jvm/functions/Function0;)V
+HSPLandroidx/activity/OnBackPressedDispatcher$$ExternalSyntheticLambda1;-><init>(Landroidx/activity/OnBackPressedDispatcher;)V
+HSPLandroidx/activity/OnBackPressedDispatcher$$ExternalSyntheticLambda2;-><init>(Landroidx/activity/OnBackPressedDispatcher;)V
+HSPLandroidx/activity/OnBackPressedDispatcher$$ExternalSyntheticThrowCCEIfNotNull0;->m(Ljava/lang/Object;)V
+HSPLandroidx/activity/OnBackPressedDispatcher$Api33Impl$$ExternalSyntheticLambda0;-><init>(Ljava/lang/Runnable;)V
+HSPLandroidx/activity/OnBackPressedDispatcher$Api33Impl;->createOnBackInvokedCallback(Ljava/lang/Runnable;)Landroid/window/OnBackInvokedCallback;
+HSPLandroidx/activity/OnBackPressedDispatcher;-><init>(Ljava/lang/Runnable;)V
+HSPLandroidx/activity/OnBackPressedDispatcher;->hasEnabledCallbacks()Z
+HSPLandroidx/activity/OnBackPressedDispatcher;->setOnBackInvokedDispatcher(Landroid/window/OnBackInvokedDispatcher;)V
+HSPLandroidx/activity/OnBackPressedDispatcher;->updateBackInvokedCallbackState()V
+HSPLandroidx/activity/ViewTreeFullyDrawnReporterOwner;->set(Landroid/view/View;Landroidx/activity/FullyDrawnReporterOwner;)V
+HSPLandroidx/activity/ViewTreeOnBackPressedDispatcherOwner;->set(Landroid/view/View;Landroidx/activity/OnBackPressedDispatcherOwner;)V
+HSPLandroidx/activity/compose/ActivityResultLauncherHolder;-><init>()V
+HSPLandroidx/activity/compose/ActivityResultLauncherHolder;->setLauncher(Landroidx/activity/result/ActivityResultLauncher;)V
+HSPLandroidx/activity/compose/ActivityResultLauncherHolder;->unregister()V
+HSPLandroidx/activity/compose/ActivityResultRegistryKt$rememberLauncherForActivityResult$1$1;-><init>(Landroidx/compose/runtime/State;)V
+HSPLandroidx/activity/compose/ActivityResultRegistryKt$rememberLauncherForActivityResult$1$invoke$$inlined$onDispose$1;-><init>(Landroidx/activity/compose/ActivityResultLauncherHolder;)V
+HSPLandroidx/activity/compose/ActivityResultRegistryKt$rememberLauncherForActivityResult$1$invoke$$inlined$onDispose$1;->dispose()V
+HSPLandroidx/activity/compose/ActivityResultRegistryKt$rememberLauncherForActivityResult$1;-><init>(Landroidx/activity/compose/ActivityResultLauncherHolder;Landroidx/activity/result/ActivityResultRegistry;Ljava/lang/String;Landroidx/activity/result/contract/ActivityResultContract;Landroidx/compose/runtime/State;)V
+HSPLandroidx/activity/compose/ActivityResultRegistryKt$rememberLauncherForActivityResult$1;->invoke(Landroidx/compose/runtime/DisposableEffectScope;)Landroidx/compose/runtime/DisposableEffectResult;
+HSPLandroidx/activity/compose/ActivityResultRegistryKt$rememberLauncherForActivityResult$1;->invoke(Ljava/lang/Object;)Ljava/lang/Object;
+HSPLandroidx/activity/compose/ActivityResultRegistryKt$rememberLauncherForActivityResult$key$1;-><clinit>()V
+HSPLandroidx/activity/compose/ActivityResultRegistryKt$rememberLauncherForActivityResult$key$1;-><init>()V
+HSPLandroidx/activity/compose/ActivityResultRegistryKt$rememberLauncherForActivityResult$key$1;->invoke()Ljava/lang/Object;
+HSPLandroidx/activity/compose/ActivityResultRegistryKt$rememberLauncherForActivityResult$key$1;->invoke()Ljava/lang/String;
+HSPLandroidx/activity/compose/ActivityResultRegistryKt;->rememberLauncherForActivityResult(Landroidx/activity/result/contract/ActivityResultContract;Lkotlin/jvm/functions/Function1;Landroidx/compose/runtime/Composer;I)Landroidx/activity/compose/ManagedActivityResultLauncher;
+HSPLandroidx/activity/compose/ComponentActivityKt;-><clinit>()V
+HSPLandroidx/activity/compose/ComponentActivityKt;->setContent$default(Landroidx/activity/ComponentActivity;Landroidx/compose/runtime/CompositionContext;Lkotlin/jvm/functions/Function2;ILjava/lang/Object;)V
+HSPLandroidx/activity/compose/ComponentActivityKt;->setContent(Landroidx/activity/ComponentActivity;Landroidx/compose/runtime/CompositionContext;Lkotlin/jvm/functions/Function2;)V
+HSPLandroidx/activity/compose/ComponentActivityKt;->setOwners(Landroidx/activity/ComponentActivity;)V
+HSPLandroidx/activity/compose/LocalActivityResultRegistryOwner$LocalComposition$1;-><clinit>()V
+HSPLandroidx/activity/compose/LocalActivityResultRegistryOwner$LocalComposition$1;-><init>()V
+HSPLandroidx/activity/compose/LocalActivityResultRegistryOwner$LocalComposition$1;->invoke()Landroidx/activity/result/ActivityResultRegistryOwner;
+HSPLandroidx/activity/compose/LocalActivityResultRegistryOwner$LocalComposition$1;->invoke()Ljava/lang/Object;
+HSPLandroidx/activity/compose/LocalActivityResultRegistryOwner;-><clinit>()V
+HSPLandroidx/activity/compose/LocalActivityResultRegistryOwner;-><init>()V
+HSPLandroidx/activity/compose/LocalActivityResultRegistryOwner;->getCurrent(Landroidx/compose/runtime/Composer;I)Landroidx/activity/result/ActivityResultRegistryOwner;
+HSPLandroidx/activity/compose/ManagedActivityResultLauncher;-><clinit>()V
+HSPLandroidx/activity/compose/ManagedActivityResultLauncher;-><init>(Landroidx/activity/compose/ActivityResultLauncherHolder;Landroidx/compose/runtime/State;)V
+HSPLandroidx/activity/contextaware/ContextAwareHelper;-><init>()V
+HSPLandroidx/activity/contextaware/ContextAwareHelper;->addOnContextAvailableListener(Landroidx/activity/contextaware/OnContextAvailableListener;)V
+HSPLandroidx/activity/contextaware/ContextAwareHelper;->dispatchOnContextAvailable(Landroid/content/Context;)V
+HSPLandroidx/activity/result/ActivityResultLauncher;-><init>()V
+HSPLandroidx/activity/result/ActivityResultRegistry$3;-><init>(Landroidx/activity/result/ActivityResultRegistry;Ljava/lang/String;Landroidx/activity/result/contract/ActivityResultContract;)V
+HSPLandroidx/activity/result/ActivityResultRegistry$3;->unregister()V
+HSPLandroidx/activity/result/ActivityResultRegistry$CallbackAndContract;-><init>(Landroidx/activity/result/ActivityResultCallback;Landroidx/activity/result/contract/ActivityResultContract;)V
+HSPLandroidx/activity/result/ActivityResultRegistry;-><init>()V
+HSPLandroidx/activity/result/ActivityResultRegistry;->bindRcKey(ILjava/lang/String;)V
+HSPLandroidx/activity/result/ActivityResultRegistry;->generateRandomNumber()I
+HSPLandroidx/activity/result/ActivityResultRegistry;->register(Ljava/lang/String;Landroidx/activity/result/contract/ActivityResultContract;Landroidx/activity/result/ActivityResultCallback;)Landroidx/activity/result/ActivityResultLauncher;
+HSPLandroidx/activity/result/ActivityResultRegistry;->registerKey(Ljava/lang/String;)V
+HSPLandroidx/activity/result/ActivityResultRegistry;->unregister(Ljava/lang/String;)V
+HSPLandroidx/activity/result/contract/ActivityResultContract;-><init>()V
+HSPLandroidx/activity/result/contract/ActivityResultContracts$StartIntentSenderForResult$Companion;-><init>()V
+HSPLandroidx/activity/result/contract/ActivityResultContracts$StartIntentSenderForResult$Companion;-><init>(Lkotlin/jvm/internal/DefaultConstructorMarker;)V
+HSPLandroidx/activity/result/contract/ActivityResultContracts$StartIntentSenderForResult;-><clinit>()V
+HSPLandroidx/activity/result/contract/ActivityResultContracts$StartIntentSenderForResult;-><init>()V
+HSPLandroidx/arch/core/executor/ArchTaskExecutor$$ExternalSyntheticLambda0;-><init>()V
+HSPLandroidx/arch/core/executor/ArchTaskExecutor$$ExternalSyntheticLambda1;-><init>()V
+HSPLandroidx/arch/core/executor/ArchTaskExecutor;-><clinit>()V
+HSPLandroidx/arch/core/executor/ArchTaskExecutor;-><init>()V
+HSPLandroidx/arch/core/executor/ArchTaskExecutor;->getInstance()Landroidx/arch/core/executor/ArchTaskExecutor;
+HSPLandroidx/arch/core/executor/ArchTaskExecutor;->isMainThread()Z
+HSPLandroidx/arch/core/executor/DefaultTaskExecutor$1;-><init>(Landroidx/arch/core/executor/DefaultTaskExecutor;)V
+HSPLandroidx/arch/core/executor/DefaultTaskExecutor;-><init>()V
+HSPLandroidx/arch/core/executor/DefaultTaskExecutor;->isMainThread()Z
+HSPLandroidx/arch/core/executor/TaskExecutor;-><init>()V
+HSPLandroidx/arch/core/internal/FastSafeIterableMap;-><init>()V
+HSPLandroidx/arch/core/internal/FastSafeIterableMap;->ceil(Ljava/lang/Object;)Ljava/util/Map$Entry;
+HSPLandroidx/arch/core/internal/FastSafeIterableMap;->contains(Ljava/lang/Object;)Z
+HSPLandroidx/arch/core/internal/FastSafeIterableMap;->get(Ljava/lang/Object;)Landroidx/arch/core/internal/SafeIterableMap$Entry;
+HSPLandroidx/arch/core/internal/FastSafeIterableMap;->putIfAbsent(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;
+HSPLandroidx/arch/core/internal/FastSafeIterableMap;->remove(Ljava/lang/Object;)Ljava/lang/Object;
+HSPLandroidx/arch/core/internal/SafeIterableMap$AscendingIterator;-><init>(Landroidx/arch/core/internal/SafeIterableMap$Entry;Landroidx/arch/core/internal/SafeIterableMap$Entry;)V
+HSPLandroidx/arch/core/internal/SafeIterableMap$Entry;-><init>(Ljava/lang/Object;Ljava/lang/Object;)V
+HSPLandroidx/arch/core/internal/SafeIterableMap$Entry;->getKey()Ljava/lang/Object;
+HSPLandroidx/arch/core/internal/SafeIterableMap$Entry;->getValue()Ljava/lang/Object;
+HSPLandroidx/arch/core/internal/SafeIterableMap$IteratorWithAdditions;-><init>(Landroidx/arch/core/internal/SafeIterableMap;)V
+HSPLandroidx/arch/core/internal/SafeIterableMap$IteratorWithAdditions;->hasNext()Z
+HSPLandroidx/arch/core/internal/SafeIterableMap$IteratorWithAdditions;->next()Ljava/lang/Object;
+HSPLandroidx/arch/core/internal/SafeIterableMap$IteratorWithAdditions;->next()Ljava/util/Map$Entry;
+HSPLandroidx/arch/core/internal/SafeIterableMap$IteratorWithAdditions;->supportRemove(Landroidx/arch/core/internal/SafeIterableMap$Entry;)V
+HSPLandroidx/arch/core/internal/SafeIterableMap$ListIterator;-><init>(Landroidx/arch/core/internal/SafeIterableMap$Entry;Landroidx/arch/core/internal/SafeIterableMap$Entry;)V
+HSPLandroidx/arch/core/internal/SafeIterableMap$ListIterator;->hasNext()Z
+HSPLandroidx/arch/core/internal/SafeIterableMap$SupportRemove;-><init>()V
+HSPLandroidx/arch/core/internal/SafeIterableMap;-><init>()V
+HSPLandroidx/arch/core/internal/SafeIterableMap;->eldest()Ljava/util/Map$Entry;
+HSPLandroidx/arch/core/internal/SafeIterableMap;->get(Ljava/lang/Object;)Landroidx/arch/core/internal/SafeIterableMap$Entry;
+HSPLandroidx/arch/core/internal/SafeIterableMap;->iterator()Ljava/util/Iterator;
+HSPLandroidx/arch/core/internal/SafeIterableMap;->iteratorWithAdditions()Landroidx/arch/core/internal/SafeIterableMap$IteratorWithAdditions;
+HSPLandroidx/arch/core/internal/SafeIterableMap;->newest()Ljava/util/Map$Entry;
+HSPLandroidx/arch/core/internal/SafeIterableMap;->put(Ljava/lang/Object;Ljava/lang/Object;)Landroidx/arch/core/internal/SafeIterableMap$Entry;
+HSPLandroidx/arch/core/internal/SafeIterableMap;->putIfAbsent(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;
+HSPLandroidx/arch/core/internal/SafeIterableMap;->remove(Ljava/lang/Object;)Ljava/lang/Object;
+HSPLandroidx/arch/core/internal/SafeIterableMap;->size()I
+HSPLandroidx/collection/ArraySet$Companion;-><init>()V
+HSPLandroidx/collection/ArraySet$Companion;-><init>(Lkotlin/jvm/internal/DefaultConstructorMarker;)V
+HSPLandroidx/collection/ArraySet;-><clinit>()V
+HSPLandroidx/collection/ArraySet;-><init>()V
+HSPLandroidx/collection/ArraySet;-><init>(I)V
+HSPLandroidx/collection/ArraySet;-><init>(IILkotlin/jvm/internal/DefaultConstructorMarker;)V
+HSPLandroidx/collection/ArraySet;->add(Ljava/lang/Object;)Z
+HSPLandroidx/collection/ArraySet;->allocArrays(I)V
+HSPLandroidx/collection/ArraySet;->clear()V
+HSPLandroidx/collection/ArraySet;->indexOf(Ljava/lang/Object;I)I
+HSPLandroidx/collection/ArraySet;->toArray()[Ljava/lang/Object;
+HSPLandroidx/collection/LruCache;-><init>(I)V
+HSPLandroidx/collection/SimpleArrayMap;-><init>()V
+HSPLandroidx/collection/SimpleArrayMap;-><init>(I)V
+HSPLandroidx/collection/SimpleArrayMap;-><init>(IILkotlin/jvm/internal/DefaultConstructorMarker;)V
+HSPLandroidx/collection/SparseArrayCompat;-><init>()V
+HSPLandroidx/collection/SparseArrayCompat;-><init>(I)V
+HSPLandroidx/collection/SparseArrayCompat;-><init>(IILkotlin/jvm/internal/DefaultConstructorMarker;)V
+HSPLandroidx/collection/internal/ContainerHelpersKt;-><clinit>()V
+HSPLandroidx/collection/internal/ContainerHelpersKt;->idealByteArraySize(I)I
+HSPLandroidx/collection/internal/ContainerHelpersKt;->idealIntArraySize(I)I
+HSPLandroidx/collection/internal/Lock;-><init>()V
+HSPLandroidx/collection/internal/LruHashMap;-><init>(IF)V
+HSPLandroidx/compose/animation/core/Animatable$runAnimation$2$1;-><init>(Landroidx/compose/animation/core/Animatable;Landroidx/compose/animation/core/AnimationState;Lkotlin/jvm/functions/Function1;Lkotlin/jvm/internal/Ref$BooleanRef;)V
+HSPLandroidx/compose/animation/core/Animatable$runAnimation$2$1;->invoke(Landroidx/compose/animation/core/AnimationScope;)V
+HSPLandroidx/compose/animation/core/Animatable$runAnimation$2$1;->invoke(Ljava/lang/Object;)Ljava/lang/Object;
+HSPLandroidx/compose/animation/core/Animatable$runAnimation$2;-><init>(Landroidx/compose/animation/core/Animatable;Ljava/lang/Object;Landroidx/compose/animation/core/Animation;JLkotlin/jvm/functions/Function1;Lkotlin/coroutines/Continuation;)V
+HSPLandroidx/compose/animation/core/Animatable$runAnimation$2;->create(Lkotlin/coroutines/Continuation;)Lkotlin/coroutines/Continuation;
+HSPLandroidx/compose/animation/core/Animatable$runAnimation$2;->invoke(Ljava/lang/Object;)Ljava/lang/Object;
+HSPLandroidx/compose/animation/core/Animatable$runAnimation$2;->invoke(Lkotlin/coroutines/Continuation;)Ljava/lang/Object;
+HSPLandroidx/compose/animation/core/Animatable$runAnimation$2;->invokeSuspend(Ljava/lang/Object;)Ljava/lang/Object;
+HSPLandroidx/compose/animation/core/Animatable;-><clinit>()V
+HSPLandroidx/compose/animation/core/Animatable;-><init>(Ljava/lang/Object;Landroidx/compose/animation/core/TwoWayConverter;Ljava/lang/Object;Ljava/lang/String;)V
+HSPLandroidx/compose/animation/core/Animatable;-><init>(Ljava/lang/Object;Landroidx/compose/animation/core/TwoWayConverter;Ljava/lang/Object;Ljava/lang/String;ILkotlin/jvm/internal/DefaultConstructorMarker;)V
+HSPLandroidx/compose/animation/core/Animatable;->access$clampToBounds(Landroidx/compose/animation/core/Animatable;Ljava/lang/Object;)Ljava/lang/Object;
+HSPLandroidx/compose/animation/core/Animatable;->access$endAnimation(Landroidx/compose/animation/core/Animatable;)V
+HSPLandroidx/compose/animation/core/Animatable;->access$setRunning(Landroidx/compose/animation/core/Animatable;Z)V
+HSPLandroidx/compose/animation/core/Animatable;->access$setTargetValue(Landroidx/compose/animation/core/Animatable;Ljava/lang/Object;)V
+HSPLandroidx/compose/animation/core/Animatable;->animateTo$default(Landroidx/compose/animation/core/Animatable;Ljava/lang/Object;Landroidx/compose/animation/core/AnimationSpec;Ljava/lang/Object;Lkotlin/jvm/functions/Function1;Lkotlin/coroutines/Continuation;ILjava/lang/Object;)Ljava/lang/Object;
+HSPLandroidx/compose/animation/core/Animatable;->animateTo(Ljava/lang/Object;Landroidx/compose/animation/core/AnimationSpec;Ljava/lang/Object;Lkotlin/jvm/functions/Function1;Lkotlin/coroutines/Continuation;)Ljava/lang/Object;
+HSPLandroidx/compose/animation/core/Animatable;->asState()Landroidx/compose/runtime/State;
+HSPLandroidx/compose/animation/core/Animatable;->clampToBounds(Ljava/lang/Object;)Ljava/lang/Object;
+HSPLandroidx/compose/animation/core/Animatable;->createVector(Ljava/lang/Object;F)Landroidx/compose/animation/core/AnimationVector;
+HSPLandroidx/compose/animation/core/Animatable;->endAnimation()V
+HSPLandroidx/compose/animation/core/Animatable;->getInternalState$animation_core_release()Landroidx/compose/animation/core/AnimationState;
+HSPLandroidx/compose/animation/core/Animatable;->getTargetValue()Ljava/lang/Object;
+HSPLandroidx/compose/animation/core/Animatable;->getTypeConverter()Landroidx/compose/animation/core/TwoWayConverter;
+HSPLandroidx/compose/animation/core/Animatable;->getValue()Ljava/lang/Object;
+HSPLandroidx/compose/animation/core/Animatable;->getVelocity()Ljava/lang/Object;
+HSPLandroidx/compose/animation/core/Animatable;->getVelocityVector()Landroidx/compose/animation/core/AnimationVector;
+HSPLandroidx/compose/animation/core/Animatable;->runAnimation(Landroidx/compose/animation/core/Animation;Ljava/lang/Object;Lkotlin/jvm/functions/Function1;Lkotlin/coroutines/Continuation;)Ljava/lang/Object;
+HSPLandroidx/compose/animation/core/Animatable;->setRunning(Z)V
+HSPLandroidx/compose/animation/core/Animatable;->setTargetValue(Ljava/lang/Object;)V
+HSPLandroidx/compose/animation/core/AnimatableKt;->Animatable$default(FFILjava/lang/Object;)Landroidx/compose/animation/core/Animatable;
+HSPLandroidx/compose/animation/core/AnimatableKt;->Animatable(FF)Landroidx/compose/animation/core/Animatable;
+HSPLandroidx/compose/animation/core/AnimateAsStateKt$animateValueAsState$2;-><init>(Lkotlinx/coroutines/channels/Channel;Ljava/lang/Object;)V
+HSPLandroidx/compose/animation/core/AnimateAsStateKt$animateValueAsState$2;->invoke()Ljava/lang/Object;
+HSPLandroidx/compose/animation/core/AnimateAsStateKt$animateValueAsState$2;->invoke()V
+HSPLandroidx/compose/animation/core/AnimateAsStateKt$animateValueAsState$3$1;-><init>(Ljava/lang/Object;Landroidx/compose/animation/core/Animatable;Landroidx/compose/runtime/State;Landroidx/compose/runtime/State;Lkotlin/coroutines/Continuation;)V
+HSPLandroidx/compose/animation/core/AnimateAsStateKt$animateValueAsState$3$1;->create(Ljava/lang/Object;Lkotlin/coroutines/Continuation;)Lkotlin/coroutines/Continuation;
+HSPLandroidx/compose/animation/core/AnimateAsStateKt$animateValueAsState$3$1;->invokeSuspend(Ljava/lang/Object;)Ljava/lang/Object;
+HSPLandroidx/compose/animation/core/AnimateAsStateKt$animateValueAsState$3;-><init>(Lkotlinx/coroutines/channels/Channel;Landroidx/compose/animation/core/Animatable;Landroidx/compose/runtime/State;Landroidx/compose/runtime/State;Lkotlin/coroutines/Continuation;)V
+HSPLandroidx/compose/animation/core/AnimateAsStateKt$animateValueAsState$3;->create(Ljava/lang/Object;Lkotlin/coroutines/Continuation;)Lkotlin/coroutines/Continuation;
+HSPLandroidx/compose/animation/core/AnimateAsStateKt$animateValueAsState$3;->invokeSuspend(Ljava/lang/Object;)Ljava/lang/Object;
+HSPLandroidx/compose/animation/core/AnimateAsStateKt;-><clinit>()V
+HSPLandroidx/compose/animation/core/AnimateAsStateKt;->animateFloatAsState(FLandroidx/compose/animation/core/AnimationSpec;FLjava/lang/String;Lkotlin/jvm/functions/Function1;Landroidx/compose/runtime/Composer;II)Landroidx/compose/runtime/State;
+HSPLandroidx/compose/animation/core/AnimateAsStateKt;->animateValueAsState(Ljava/lang/Object;Landroidx/compose/animation/core/TwoWayConverter;Landroidx/compose/animation/core/AnimationSpec;Ljava/lang/Object;Ljava/lang/String;Lkotlin/jvm/functions/Function1;Landroidx/compose/runtime/Composer;II)Landroidx/compose/runtime/State;
+HSPLandroidx/compose/animation/core/Animation;->isFinishedFromNanos(J)Z
+HSPLandroidx/compose/animation/core/AnimationEndReason;->$values()[Landroidx/compose/animation/core/AnimationEndReason;
+HSPLandroidx/compose/animation/core/AnimationEndReason;-><clinit>()V
+HSPLandroidx/compose/animation/core/AnimationEndReason;-><init>(Ljava/lang/String;I)V
+HSPLandroidx/compose/animation/core/AnimationKt;->TargetBasedAnimation(Landroidx/compose/animation/core/AnimationSpec;Landroidx/compose/animation/core/TwoWayConverter;Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;)Landroidx/compose/animation/core/TargetBasedAnimation;
+HSPLandroidx/compose/animation/core/AnimationResult;-><clinit>()V
+HSPLandroidx/compose/animation/core/AnimationResult;-><init>(Landroidx/compose/animation/core/AnimationState;Landroidx/compose/animation/core/AnimationEndReason;)V
+HSPLandroidx/compose/animation/core/AnimationScope;-><clinit>()V
+HSPLandroidx/compose/animation/core/AnimationScope;-><init>(Ljava/lang/Object;Landroidx/compose/animation/core/TwoWayConverter;Landroidx/compose/animation/core/AnimationVector;JLjava/lang/Object;JZLkotlin/jvm/functions/Function0;)V
+HSPLandroidx/compose/animation/core/AnimationScope;->getFinishedTimeNanos()J
+HSPLandroidx/compose/animation/core/AnimationScope;->getLastFrameTimeNanos()J
+HSPLandroidx/compose/animation/core/AnimationScope;->getStartTimeNanos()J
+HSPLandroidx/compose/animation/core/AnimationScope;->getValue()Ljava/lang/Object;
+HSPLandroidx/compose/animation/core/AnimationScope;->getVelocityVector()Landroidx/compose/animation/core/AnimationVector;
+HSPLandroidx/compose/animation/core/AnimationScope;->isRunning()Z
+HSPLandroidx/compose/animation/core/AnimationScope;->setFinishedTimeNanos$animation_core_release(J)V
+HSPLandroidx/compose/animation/core/AnimationScope;->setLastFrameTimeNanos$animation_core_release(J)V
+HSPLandroidx/compose/animation/core/AnimationScope;->setRunning$animation_core_release(Z)V
+HSPLandroidx/compose/animation/core/AnimationScope;->setValue$animation_core_release(Ljava/lang/Object;)V
+HSPLandroidx/compose/animation/core/AnimationScope;->setVelocityVector$animation_core_release(Landroidx/compose/animation/core/AnimationVector;)V
+HSPLandroidx/compose/animation/core/AnimationSpecKt;->spring$default(FFLjava/lang/Object;ILjava/lang/Object;)Landroidx/compose/animation/core/SpringSpec;
+HSPLandroidx/compose/animation/core/AnimationSpecKt;->spring(FFLjava/lang/Object;)Landroidx/compose/animation/core/SpringSpec;
+HSPLandroidx/compose/animation/core/AnimationState;-><clinit>()V
+HSPLandroidx/compose/animation/core/AnimationState;-><init>(Landroidx/compose/animation/core/TwoWayConverter;Ljava/lang/Object;Landroidx/compose/animation/core/AnimationVector;JJZ)V
+HSPLandroidx/compose/animation/core/AnimationState;-><init>(Landroidx/compose/animation/core/TwoWayConverter;Ljava/lang/Object;Landroidx/compose/animation/core/AnimationVector;JJZILkotlin/jvm/internal/DefaultConstructorMarker;)V
+HSPLandroidx/compose/animation/core/AnimationState;->getLastFrameTimeNanos()J
+HSPLandroidx/compose/animation/core/AnimationState;->getTypeConverter()Landroidx/compose/animation/core/TwoWayConverter;
+HSPLandroidx/compose/animation/core/AnimationState;->getValue()Ljava/lang/Object;
+HSPLandroidx/compose/animation/core/AnimationState;->getVelocityVector()Landroidx/compose/animation/core/AnimationVector;
+HSPLandroidx/compose/animation/core/AnimationState;->isRunning()Z
+HSPLandroidx/compose/animation/core/AnimationState;->setFinishedTimeNanos$animation_core_release(J)V
+HSPLandroidx/compose/animation/core/AnimationState;->setLastFrameTimeNanos$animation_core_release(J)V
+HSPLandroidx/compose/animation/core/AnimationState;->setRunning$animation_core_release(Z)V
+HSPLandroidx/compose/animation/core/AnimationState;->setValue$animation_core_release(Ljava/lang/Object;)V
+HSPLandroidx/compose/animation/core/AnimationState;->setVelocityVector$animation_core_release(Landroidx/compose/animation/core/AnimationVector;)V
+HSPLandroidx/compose/animation/core/AnimationStateKt;->copy$default(Landroidx/compose/animation/core/AnimationState;Ljava/lang/Object;Landroidx/compose/animation/core/AnimationVector;JJZILjava/lang/Object;)Landroidx/compose/animation/core/AnimationState;
+HSPLandroidx/compose/animation/core/AnimationStateKt;->copy(Landroidx/compose/animation/core/AnimationState;Ljava/lang/Object;Landroidx/compose/animation/core/AnimationVector;JJZ)Landroidx/compose/animation/core/AnimationState;
+HSPLandroidx/compose/animation/core/AnimationStateKt;->createZeroVectorFrom(Landroidx/compose/animation/core/TwoWayConverter;Ljava/lang/Object;)Landroidx/compose/animation/core/AnimationVector;
+HSPLandroidx/compose/animation/core/AnimationVector1D;-><clinit>()V
+HSPLandroidx/compose/animation/core/AnimationVector1D;-><init>(F)V
+HSPLandroidx/compose/animation/core/AnimationVector1D;->equals(Ljava/lang/Object;)Z
+HSPLandroidx/compose/animation/core/AnimationVector1D;->get$animation_core_release(I)F
+HSPLandroidx/compose/animation/core/AnimationVector1D;->getSize$animation_core_release()I
+HSPLandroidx/compose/animation/core/AnimationVector1D;->getValue()F
+HSPLandroidx/compose/animation/core/AnimationVector1D;->newVector$animation_core_release()Landroidx/compose/animation/core/AnimationVector1D;
+HSPLandroidx/compose/animation/core/AnimationVector1D;->newVector$animation_core_release()Landroidx/compose/animation/core/AnimationVector;
+HSPLandroidx/compose/animation/core/AnimationVector1D;->reset$animation_core_release()V
+HSPLandroidx/compose/animation/core/AnimationVector1D;->set$animation_core_release(IF)V
+HSPLandroidx/compose/animation/core/AnimationVector;-><clinit>()V
+HSPLandroidx/compose/animation/core/AnimationVector;-><init>()V
+HSPLandroidx/compose/animation/core/AnimationVector;-><init>(Lkotlin/jvm/internal/DefaultConstructorMarker;)V
+HSPLandroidx/compose/animation/core/AnimationVectorsKt;->copy(Landroidx/compose/animation/core/AnimationVector;)Landroidx/compose/animation/core/AnimationVector;
+HSPLandroidx/compose/animation/core/AnimationVectorsKt;->copyFrom(Landroidx/compose/animation/core/AnimationVector;Landroidx/compose/animation/core/AnimationVector;)V
+HSPLandroidx/compose/animation/core/AnimationVectorsKt;->newInstance(Landroidx/compose/animation/core/AnimationVector;)Landroidx/compose/animation/core/AnimationVector;
+HSPLandroidx/compose/animation/core/CubicBezierEasing;-><init>(FFFF)V
+HSPLandroidx/compose/animation/core/CubicBezierEasing;->equals(Ljava/lang/Object;)Z
+HSPLandroidx/compose/animation/core/CubicBezierEasing;->evaluateCubic(FFF)F
+HSPLandroidx/compose/animation/core/CubicBezierEasing;->transform(F)F
+HSPLandroidx/compose/animation/core/EasingKt$LinearEasing$1;-><clinit>()V
+HSPLandroidx/compose/animation/core/EasingKt$LinearEasing$1;-><init>()V
+HSPLandroidx/compose/animation/core/EasingKt;-><clinit>()V
+HSPLandroidx/compose/animation/core/EasingKt;->getFastOutSlowInEasing()Landroidx/compose/animation/core/Easing;
+HSPLandroidx/compose/animation/core/EasingKt;->getLinearEasing()Landroidx/compose/animation/core/Easing;
+HSPLandroidx/compose/animation/core/FloatTweenSpec;-><clinit>()V
+HSPLandroidx/compose/animation/core/FloatTweenSpec;-><init>(IILandroidx/compose/animation/core/Easing;)V
+HSPLandroidx/compose/animation/core/FloatTweenSpec;->clampPlayTime(J)J
+HSPLandroidx/compose/animation/core/FloatTweenSpec;->getValueFromNanos(JFFF)F
+HSPLandroidx/compose/animation/core/FloatTweenSpec;->getVelocityFromNanos(JFFF)F
+HSPLandroidx/compose/animation/core/MutatePriority;->$values()[Landroidx/compose/animation/core/MutatePriority;
+HSPLandroidx/compose/animation/core/MutatePriority;-><clinit>()V
+HSPLandroidx/compose/animation/core/MutatePriority;-><init>(Ljava/lang/String;I)V
+HSPLandroidx/compose/animation/core/MutatorMutex$Mutator;-><init>(Landroidx/compose/animation/core/MutatePriority;Lkotlinx/coroutines/Job;)V
+HSPLandroidx/compose/animation/core/MutatorMutex$mutate$2;-><init>(Landroidx/compose/animation/core/MutatePriority;Landroidx/compose/animation/core/MutatorMutex;Lkotlin/jvm/functions/Function1;Lkotlin/coroutines/Continuation;)V
+HSPLandroidx/compose/animation/core/MutatorMutex$mutate$2;->create(Ljava/lang/Object;Lkotlin/coroutines/Continuation;)Lkotlin/coroutines/Continuation;
+HSPLandroidx/compose/animation/core/MutatorMutex$mutate$2;->invoke(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;
+HSPLandroidx/compose/animation/core/MutatorMutex$mutate$2;->invoke(Lkotlinx/coroutines/CoroutineScope;Lkotlin/coroutines/Continuation;)Ljava/lang/Object;
+HSPLandroidx/compose/animation/core/MutatorMutex$mutate$2;->invokeSuspend(Ljava/lang/Object;)Ljava/lang/Object;
+HSPLandroidx/compose/animation/core/MutatorMutex;-><init>()V
+HSPLandroidx/compose/animation/core/MutatorMutex;->access$getCurrentMutator$p(Landroidx/compose/animation/core/MutatorMutex;)Ljava/util/concurrent/atomic/AtomicReference;
+HSPLandroidx/compose/animation/core/MutatorMutex;->access$getMutex$p(Landroidx/compose/animation/core/MutatorMutex;)Lkotlinx/coroutines/sync/Mutex;
+HSPLandroidx/compose/animation/core/MutatorMutex;->access$tryMutateOrCancel(Landroidx/compose/animation/core/MutatorMutex;Landroidx/compose/animation/core/MutatorMutex$Mutator;)V
+HSPLandroidx/compose/animation/core/MutatorMutex;->mutate$default(Landroidx/compose/animation/core/MutatorMutex;Landroidx/compose/animation/core/MutatePriority;Lkotlin/jvm/functions/Function1;Lkotlin/coroutines/Continuation;ILjava/lang/Object;)Ljava/lang/Object;
+HSPLandroidx/compose/animation/core/MutatorMutex;->mutate(Landroidx/compose/animation/core/MutatePriority;Lkotlin/jvm/functions/Function1;Lkotlin/coroutines/Continuation;)Ljava/lang/Object;
+HSPLandroidx/compose/animation/core/MutatorMutex;->tryMutateOrCancel(Landroidx/compose/animation/core/MutatorMutex$Mutator;)V
+HSPLandroidx/compose/animation/core/SpringSpec;-><init>(FFLjava/lang/Object;)V
+HSPLandroidx/compose/animation/core/SpringSpec;-><init>(FFLjava/lang/Object;ILkotlin/jvm/internal/DefaultConstructorMarker;)V
+HSPLandroidx/compose/animation/core/SpringSpec;->equals(Ljava/lang/Object;)Z
+HSPLandroidx/compose/animation/core/SuspendAnimationKt$animate$4;-><init>(Lkotlin/coroutines/Continuation;)V
+HSPLandroidx/compose/animation/core/SuspendAnimationKt$animate$4;->invokeSuspend(Ljava/lang/Object;)Ljava/lang/Object;
+HSPLandroidx/compose/animation/core/SuspendAnimationKt$animate$6$1;-><init>(Landroidx/compose/animation/core/AnimationState;)V
+HSPLandroidx/compose/animation/core/SuspendAnimationKt$animate$6;-><init>(Lkotlin/jvm/internal/Ref$ObjectRef;Ljava/lang/Object;Landroidx/compose/animation/core/Animation;Landroidx/compose/animation/core/AnimationVector;Landroidx/compose/animation/core/AnimationState;FLkotlin/jvm/functions/Function1;)V
+HSPLandroidx/compose/animation/core/SuspendAnimationKt$animate$6;->invoke(J)V
+HSPLandroidx/compose/animation/core/SuspendAnimationKt$animate$6;->invoke(Ljava/lang/Object;)Ljava/lang/Object;
+HSPLandroidx/compose/animation/core/SuspendAnimationKt$animate$9;-><init>(Lkotlin/jvm/internal/Ref$ObjectRef;FLandroidx/compose/animation/core/Animation;Landroidx/compose/animation/core/AnimationState;Lkotlin/jvm/functions/Function1;)V
+HSPLandroidx/compose/animation/core/SuspendAnimationKt$animate$9;->invoke(J)V
+HSPLandroidx/compose/animation/core/SuspendAnimationKt$animate$9;->invoke(Ljava/lang/Object;)Ljava/lang/Object;
+HSPLandroidx/compose/animation/core/SuspendAnimationKt$callWithFrameNanos$2;-><init>(Lkotlin/jvm/functions/Function1;)V
+HSPLandroidx/compose/animation/core/SuspendAnimationKt$callWithFrameNanos$2;->invoke(J)Ljava/lang/Object;
+HSPLandroidx/compose/animation/core/SuspendAnimationKt$callWithFrameNanos$2;->invoke(Ljava/lang/Object;)Ljava/lang/Object;
+HSPLandroidx/compose/animation/core/SuspendAnimationKt;->access$doAnimationFrameWithScale(Landroidx/compose/animation/core/AnimationScope;JFLandroidx/compose/animation/core/Animation;Landroidx/compose/animation/core/AnimationState;Lkotlin/jvm/functions/Function1;)V
+HSPLandroidx/compose/animation/core/SuspendAnimationKt;->animate(Landroidx/compose/animation/core/AnimationState;Landroidx/compose/animation/core/Animation;JLkotlin/jvm/functions/Function1;Lkotlin/coroutines/Continuation;)Ljava/lang/Object;
+HSPLandroidx/compose/animation/core/SuspendAnimationKt;->callWithFrameNanos(Landroidx/compose/animation/core/Animation;Lkotlin/jvm/functions/Function1;Lkotlin/coroutines/Continuation;)Ljava/lang/Object;
+HSPLandroidx/compose/animation/core/SuspendAnimationKt;->doAnimationFrame(Landroidx/compose/animation/core/AnimationScope;JJLandroidx/compose/animation/core/Animation;Landroidx/compose/animation/core/AnimationState;Lkotlin/jvm/functions/Function1;)V
+HSPLandroidx/compose/animation/core/SuspendAnimationKt;->doAnimationFrameWithScale(Landroidx/compose/animation/core/AnimationScope;JFLandroidx/compose/animation/core/Animation;Landroidx/compose/animation/core/AnimationState;Lkotlin/jvm/functions/Function1;)V
+HSPLandroidx/compose/animation/core/SuspendAnimationKt;->getDurationScale(Lkotlin/coroutines/CoroutineContext;)F
+HSPLandroidx/compose/animation/core/SuspendAnimationKt;->updateState(Landroidx/compose/animation/core/AnimationScope;Landroidx/compose/animation/core/AnimationState;)V
+HSPLandroidx/compose/animation/core/TargetBasedAnimation;-><clinit>()V
+HSPLandroidx/compose/animation/core/TargetBasedAnimation;-><init>(Landroidx/compose/animation/core/AnimationSpec;Landroidx/compose/animation/core/TwoWayConverter;Ljava/lang/Object;Ljava/lang/Object;Landroidx/compose/animation/core/AnimationVector;)V
+HSPLandroidx/compose/animation/core/TargetBasedAnimation;-><init>(Landroidx/compose/animation/core/VectorizedAnimationSpec;Landroidx/compose/animation/core/TwoWayConverter;Ljava/lang/Object;Ljava/lang/Object;Landroidx/compose/animation/core/AnimationVector;)V
+HSPLandroidx/compose/animation/core/TargetBasedAnimation;->getDurationNanos()J
+HSPLandroidx/compose/animation/core/TargetBasedAnimation;->getTargetValue()Ljava/lang/Object;
+HSPLandroidx/compose/animation/core/TargetBasedAnimation;->getTypeConverter()Landroidx/compose/animation/core/TwoWayConverter;
+HSPLandroidx/compose/animation/core/TargetBasedAnimation;->getValueFromNanos(J)Ljava/lang/Object;
+HSPLandroidx/compose/animation/core/TargetBasedAnimation;->getVelocityVectorFromNanos(J)Landroidx/compose/animation/core/AnimationVector;
+HSPLandroidx/compose/animation/core/TargetBasedAnimation;->isInfinite()Z
+HSPLandroidx/compose/animation/core/TweenSpec;-><init>(IILandroidx/compose/animation/core/Easing;)V
+HSPLandroidx/compose/animation/core/TweenSpec;-><init>(IILandroidx/compose/animation/core/Easing;ILkotlin/jvm/internal/DefaultConstructorMarker;)V
+HSPLandroidx/compose/animation/core/TweenSpec;->equals(Ljava/lang/Object;)Z
+HSPLandroidx/compose/animation/core/TweenSpec;->vectorize(Landroidx/compose/animation/core/TwoWayConverter;)Landroidx/compose/animation/core/VectorizedAnimationSpec;
+HSPLandroidx/compose/animation/core/TweenSpec;->vectorize(Landroidx/compose/animation/core/TwoWayConverter;)Landroidx/compose/animation/core/VectorizedTweenSpec;
+HSPLandroidx/compose/animation/core/TwoWayConverterImpl;-><init>(Lkotlin/jvm/functions/Function1;Lkotlin/jvm/functions/Function1;)V
+HSPLandroidx/compose/animation/core/TwoWayConverterImpl;->getConvertFromVector()Lkotlin/jvm/functions/Function1;
+HSPLandroidx/compose/animation/core/TwoWayConverterImpl;->getConvertToVector()Lkotlin/jvm/functions/Function1;
+HSPLandroidx/compose/animation/core/VectorConvertersKt$DpOffsetToVector$1;-><clinit>()V
+HSPLandroidx/compose/animation/core/VectorConvertersKt$DpOffsetToVector$1;-><init>()V
+HSPLandroidx/compose/animation/core/VectorConvertersKt$DpOffsetToVector$2;-><clinit>()V
+HSPLandroidx/compose/animation/core/VectorConvertersKt$DpOffsetToVector$2;-><init>()V
+HSPLandroidx/compose/animation/core/VectorConvertersKt$DpToVector$1;-><clinit>()V
+HSPLandroidx/compose/animation/core/VectorConvertersKt$DpToVector$1;-><init>()V
+HSPLandroidx/compose/animation/core/VectorConvertersKt$DpToVector$1;->invoke(Ljava/lang/Object;)Ljava/lang/Object;
+HSPLandroidx/compose/animation/core/VectorConvertersKt$DpToVector$1;->invoke-0680j_4(F)Landroidx/compose/animation/core/AnimationVector1D;
+HSPLandroidx/compose/animation/core/VectorConvertersKt$DpToVector$2;-><clinit>()V
+HSPLandroidx/compose/animation/core/VectorConvertersKt$DpToVector$2;-><init>()V
+HSPLandroidx/compose/animation/core/VectorConvertersKt$DpToVector$2;->invoke(Ljava/lang/Object;)Ljava/lang/Object;
+HSPLandroidx/compose/animation/core/VectorConvertersKt$DpToVector$2;->invoke-u2uoSUM(Landroidx/compose/animation/core/AnimationVector1D;)F
+HSPLandroidx/compose/animation/core/VectorConvertersKt$FloatToVector$1;-><clinit>()V
+HSPLandroidx/compose/animation/core/VectorConvertersKt$FloatToVector$1;-><init>()V
+HSPLandroidx/compose/animation/core/VectorConvertersKt$FloatToVector$1;->invoke(F)Landroidx/compose/animation/core/AnimationVector1D;
+HSPLandroidx/compose/animation/core/VectorConvertersKt$FloatToVector$1;->invoke(Ljava/lang/Object;)Ljava/lang/Object;
+HSPLandroidx/compose/animation/core/VectorConvertersKt$FloatToVector$2;-><clinit>()V
+HSPLandroidx/compose/animation/core/VectorConvertersKt$FloatToVector$2;-><init>()V
+HSPLandroidx/compose/animation/core/VectorConvertersKt$IntOffsetToVector$1;-><clinit>()V
+HSPLandroidx/compose/animation/core/VectorConvertersKt$IntOffsetToVector$1;-><init>()V
+HSPLandroidx/compose/animation/core/VectorConvertersKt$IntOffsetToVector$2;-><clinit>()V
+HSPLandroidx/compose/animation/core/VectorConvertersKt$IntOffsetToVector$2;-><init>()V
+HSPLandroidx/compose/animation/core/VectorConvertersKt$IntSizeToVector$1;-><clinit>()V
+HSPLandroidx/compose/animation/core/VectorConvertersKt$IntSizeToVector$1;-><init>()V
+HSPLandroidx/compose/animation/core/VectorConvertersKt$IntSizeToVector$2;-><clinit>()V
+HSPLandroidx/compose/animation/core/VectorConvertersKt$IntSizeToVector$2;-><init>()V
+HSPLandroidx/compose/animation/core/VectorConvertersKt$IntToVector$1;-><clinit>()V
+HSPLandroidx/compose/animation/core/VectorConvertersKt$IntToVector$1;-><init>()V
+HSPLandroidx/compose/animation/core/VectorConvertersKt$IntToVector$2;-><clinit>()V
+HSPLandroidx/compose/animation/core/VectorConvertersKt$IntToVector$2;-><init>()V
+HSPLandroidx/compose/animation/core/VectorConvertersKt$OffsetToVector$1;-><clinit>()V
+HSPLandroidx/compose/animation/core/VectorConvertersKt$OffsetToVector$1;-><init>()V
+HSPLandroidx/compose/animation/core/VectorConvertersKt$OffsetToVector$2;-><clinit>()V
+HSPLandroidx/compose/animation/core/VectorConvertersKt$OffsetToVector$2;-><init>()V
+HSPLandroidx/compose/animation/core/VectorConvertersKt$RectToVector$1;-><clinit>()V
+HSPLandroidx/compose/animation/core/VectorConvertersKt$RectToVector$1;-><init>()V
+HSPLandroidx/compose/animation/core/VectorConvertersKt$RectToVector$2;-><clinit>()V
+HSPLandroidx/compose/animation/core/VectorConvertersKt$RectToVector$2;-><init>()V
+HSPLandroidx/compose/animation/core/VectorConvertersKt$SizeToVector$1;-><clinit>()V
+HSPLandroidx/compose/animation/core/VectorConvertersKt$SizeToVector$1;-><init>()V
+HSPLandroidx/compose/animation/core/VectorConvertersKt$SizeToVector$2;-><clinit>()V
+HSPLandroidx/compose/animation/core/VectorConvertersKt$SizeToVector$2;-><init>()V
+HSPLandroidx/compose/animation/core/VectorConvertersKt;-><clinit>()V
+HSPLandroidx/compose/animation/core/VectorConvertersKt;->TwoWayConverter(Lkotlin/jvm/functions/Function1;Lkotlin/jvm/functions/Function1;)Landroidx/compose/animation/core/TwoWayConverter;
+HSPLandroidx/compose/animation/core/VectorConvertersKt;->getVectorConverter(Landroidx/compose/ui/geometry/Offset$Companion;)Landroidx/compose/animation/core/TwoWayConverter;
+HSPLandroidx/compose/animation/core/VectorConvertersKt;->getVectorConverter(Landroidx/compose/ui/geometry/Rect$Companion;)Landroidx/compose/animation/core/TwoWayConverter;
+HSPLandroidx/compose/animation/core/VectorConvertersKt;->getVectorConverter(Landroidx/compose/ui/geometry/Size$Companion;)Landroidx/compose/animation/core/TwoWayConverter;
+HSPLandroidx/compose/animation/core/VectorConvertersKt;->getVectorConverter(Landroidx/compose/ui/unit/Dp$Companion;)Landroidx/compose/animation/core/TwoWayConverter;
+HSPLandroidx/compose/animation/core/VectorConvertersKt;->getVectorConverter(Landroidx/compose/ui/unit/DpOffset$Companion;)Landroidx/compose/animation/core/TwoWayConverter;
+HSPLandroidx/compose/animation/core/VectorConvertersKt;->getVectorConverter(Landroidx/compose/ui/unit/IntOffset$Companion;)Landroidx/compose/animation/core/TwoWayConverter;
+HSPLandroidx/compose/animation/core/VectorConvertersKt;->getVectorConverter(Landroidx/compose/ui/unit/IntSize$Companion;)Landroidx/compose/animation/core/TwoWayConverter;
+HSPLandroidx/compose/animation/core/VectorConvertersKt;->getVectorConverter(Lkotlin/jvm/internal/FloatCompanionObject;)Landroidx/compose/animation/core/TwoWayConverter;
+HSPLandroidx/compose/animation/core/VectorConvertersKt;->getVectorConverter(Lkotlin/jvm/internal/IntCompanionObject;)Landroidx/compose/animation/core/TwoWayConverter;
+HSPLandroidx/compose/animation/core/VectorConvertersKt;->lerp(FFF)F
+HSPLandroidx/compose/animation/core/VectorizedAnimationSpec;->getEndVelocity(Landroidx/compose/animation/core/AnimationVector;Landroidx/compose/animation/core/AnimationVector;Landroidx/compose/animation/core/AnimationVector;)Landroidx/compose/animation/core/AnimationVector;
+HSPLandroidx/compose/animation/core/VectorizedDurationBasedAnimationSpec;->getDurationNanos(Landroidx/compose/animation/core/AnimationVector;Landroidx/compose/animation/core/AnimationVector;Landroidx/compose/animation/core/AnimationVector;)J
+HSPLandroidx/compose/animation/core/VectorizedFiniteAnimationSpec;->isInfinite()Z
+HSPLandroidx/compose/animation/core/VectorizedFloatAnimationSpec$1;-><init>(Landroidx/compose/animation/core/FloatAnimationSpec;)V
+HSPLandroidx/compose/animation/core/VectorizedFloatAnimationSpec$1;->get(I)Landroidx/compose/animation/core/FloatAnimationSpec;
+HSPLandroidx/compose/animation/core/VectorizedFloatAnimationSpec;-><clinit>()V
+HSPLandroidx/compose/animation/core/VectorizedFloatAnimationSpec;-><init>(Landroidx/compose/animation/core/Animations;)V
+HSPLandroidx/compose/animation/core/VectorizedFloatAnimationSpec;-><init>(Landroidx/compose/animation/core/FloatAnimationSpec;)V
+HSPLandroidx/compose/animation/core/VectorizedFloatAnimationSpec;->getValueFromNanos(JLandroidx/compose/animation/core/AnimationVector;Landroidx/compose/animation/core/AnimationVector;Landroidx/compose/animation/core/AnimationVector;)Landroidx/compose/animation/core/AnimationVector;
+HSPLandroidx/compose/animation/core/VectorizedFloatAnimationSpec;->getVelocityFromNanos(JLandroidx/compose/animation/core/AnimationVector;Landroidx/compose/animation/core/AnimationVector;Landroidx/compose/animation/core/AnimationVector;)Landroidx/compose/animation/core/AnimationVector;
+HSPLandroidx/compose/animation/core/VectorizedTweenSpec;-><clinit>()V
+HSPLandroidx/compose/animation/core/VectorizedTweenSpec;-><init>(IILandroidx/compose/animation/core/Easing;)V
+HSPLandroidx/compose/animation/core/VectorizedTweenSpec;->getDelayMillis()I
+HSPLandroidx/compose/animation/core/VectorizedTweenSpec;->getDurationMillis()I
+HSPLandroidx/compose/animation/core/VectorizedTweenSpec;->getValueFromNanos(JLandroidx/compose/animation/core/AnimationVector;Landroidx/compose/animation/core/AnimationVector;Landroidx/compose/animation/core/AnimationVector;)Landroidx/compose/animation/core/AnimationVector;
+HSPLandroidx/compose/animation/core/VectorizedTweenSpec;->getVelocityFromNanos(JLandroidx/compose/animation/core/AnimationVector;Landroidx/compose/animation/core/AnimationVector;Landroidx/compose/animation/core/AnimationVector;)Landroidx/compose/animation/core/AnimationVector;
+HSPLandroidx/compose/animation/core/VisibilityThresholdsKt;-><clinit>()V
+HSPLandroidx/compose/animation/core/VisibilityThresholdsKt;->getVisibilityThreshold(Landroidx/compose/ui/geometry/Offset$Companion;)J
+HSPLandroidx/compose/animation/core/VisibilityThresholdsKt;->getVisibilityThreshold(Landroidx/compose/ui/geometry/Rect$Companion;)Landroidx/compose/ui/geometry/Rect;
+HSPLandroidx/compose/animation/core/VisibilityThresholdsKt;->getVisibilityThreshold(Landroidx/compose/ui/geometry/Size$Companion;)J
+HSPLandroidx/compose/animation/core/VisibilityThresholdsKt;->getVisibilityThreshold(Landroidx/compose/ui/unit/Dp$Companion;)F
+HSPLandroidx/compose/animation/core/VisibilityThresholdsKt;->getVisibilityThreshold(Landroidx/compose/ui/unit/IntOffset$Companion;)J
+HSPLandroidx/compose/animation/core/VisibilityThresholdsKt;->getVisibilityThreshold(Landroidx/compose/ui/unit/IntSize$Companion;)J
+HSPLandroidx/compose/animation/core/VisibilityThresholdsKt;->getVisibilityThreshold(Lkotlin/jvm/internal/IntCompanionObject;)I
+HSPLandroidx/compose/foundation/Background;-><init>(Landroidx/compose/ui/graphics/Color;Landroidx/compose/ui/graphics/Brush;FLandroidx/compose/ui/graphics/Shape;Lkotlin/jvm/functions/Function1;)V
+HSPLandroidx/compose/foundation/Background;-><init>(Landroidx/compose/ui/graphics/Color;Landroidx/compose/ui/graphics/Brush;FLandroidx/compose/ui/graphics/Shape;Lkotlin/jvm/functions/Function1;ILkotlin/jvm/internal/DefaultConstructorMarker;)V
+HSPLandroidx/compose/foundation/Background;-><init>(Landroidx/compose/ui/graphics/Color;Landroidx/compose/ui/graphics/Brush;FLandroidx/compose/ui/graphics/Shape;Lkotlin/jvm/functions/Function1;Lkotlin/jvm/internal/DefaultConstructorMarker;)V
+HSPLandroidx/compose/foundation/Background;->draw(Landroidx/compose/ui/graphics/drawscope/ContentDrawScope;)V
+HSPLandroidx/compose/foundation/Background;->drawOutline(Landroidx/compose/ui/graphics/drawscope/ContentDrawScope;)V
+HSPLandroidx/compose/foundation/Background;->drawRect(Landroidx/compose/ui/graphics/drawscope/ContentDrawScope;)V
+HSPLandroidx/compose/foundation/Background;->equals(Ljava/lang/Object;)Z
+HSPLandroidx/compose/foundation/BackgroundKt;->background-bw27NRU$default(Landroidx/compose/ui/Modifier;JLandroidx/compose/ui/graphics/Shape;ILjava/lang/Object;)Landroidx/compose/ui/Modifier;
+HSPLandroidx/compose/foundation/BackgroundKt;->background-bw27NRU(Landroidx/compose/ui/Modifier;JLandroidx/compose/ui/graphics/Shape;)Landroidx/compose/ui/Modifier;
+HSPLandroidx/compose/foundation/CanvasKt;->Canvas(Landroidx/compose/ui/Modifier;Lkotlin/jvm/functions/Function1;Landroidx/compose/runtime/Composer;I)V
+HSPLandroidx/compose/foundation/ClickableKt$PressedInteractionSourceDisposableEffect$1$invoke$$inlined$onDispose$1;-><init>(Landroidx/compose/runtime/MutableState;Ljava/util/Map;Landroidx/compose/foundation/interaction/MutableInteractionSource;)V
+HSPLandroidx/compose/foundation/ClickableKt$PressedInteractionSourceDisposableEffect$1;-><init>(Landroidx/compose/runtime/MutableState;Ljava/util/Map;Landroidx/compose/foundation/interaction/MutableInteractionSource;)V
+HSPLandroidx/compose/foundation/ClickableKt$PressedInteractionSourceDisposableEffect$1;->invoke(Landroidx/compose/runtime/DisposableEffectScope;)Landroidx/compose/runtime/DisposableEffectResult;
+HSPLandroidx/compose/foundation/ClickableKt$PressedInteractionSourceDisposableEffect$1;->invoke(Ljava/lang/Object;)Ljava/lang/Object;
+HSPLandroidx/compose/foundation/ClickableKt$clickable$4$1$1$1;-><init>(Landroidx/compose/ui/input/ScrollContainerInfo;)V
+HSPLandroidx/compose/foundation/ClickableKt$clickable$4$1$1;-><init>(Landroidx/compose/runtime/MutableState;)V
+HSPLandroidx/compose/foundation/ClickableKt$clickable$4$1$1;->invoke(Landroidx/compose/ui/input/ScrollContainerInfo;)V
+HSPLandroidx/compose/foundation/ClickableKt$clickable$4$1$1;->invoke(Ljava/lang/Object;)Ljava/lang/Object;
+HSPLandroidx/compose/foundation/ClickableKt$clickable$4$delayPressInteraction$1$1;-><clinit>()V
+HSPLandroidx/compose/foundation/ClickableKt$clickable$4$delayPressInteraction$1$1;-><init>()V
+HSPLandroidx/compose/foundation/ClickableKt$clickable$4$gesture$1$1$1;-><init>(ZLandroidx/compose/foundation/interaction/MutableInteractionSource;Landroidx/compose/runtime/MutableState;Landroidx/compose/runtime/MutableState;Lkotlin/coroutines/Continuation;)V
+HSPLandroidx/compose/foundation/ClickableKt$clickable$4$gesture$1$1$2;-><init>(ZLandroidx/compose/runtime/State;)V
+HSPLandroidx/compose/foundation/ClickableKt$clickable$4$gesture$1$1;-><init>(Landroidx/compose/runtime/MutableState;ZLandroidx/compose/foundation/interaction/MutableInteractionSource;Landroidx/compose/runtime/MutableState;Landroidx/compose/runtime/MutableState;Landroidx/compose/runtime/State;Lkotlin/coroutines/Continuation;)V
+HSPLandroidx/compose/foundation/ClickableKt$clickable$4$gesture$1$1;->create(Ljava/lang/Object;Lkotlin/coroutines/Continuation;)Lkotlin/coroutines/Continuation;
+HSPLandroidx/compose/foundation/ClickableKt$clickable$4$gesture$1$1;->invoke(Landroidx/compose/ui/input/pointer/PointerInputScope;Lkotlin/coroutines/Continuation;)Ljava/lang/Object;
+HSPLandroidx/compose/foundation/ClickableKt$clickable$4$gesture$1$1;->invoke(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;
+HSPLandroidx/compose/foundation/ClickableKt$clickable$4$gesture$1$1;->invokeSuspend(Ljava/lang/Object;)Ljava/lang/Object;
+HSPLandroidx/compose/foundation/ClickableKt$clickable$4;-><init>(Lkotlin/jvm/functions/Function0;ZLandroidx/compose/foundation/interaction/MutableInteractionSource;Landroidx/compose/foundation/Indication;Ljava/lang/String;Landroidx/compose/ui/semantics/Role;)V
+HSPLandroidx/compose/foundation/ClickableKt$clickable$4;->invoke(Landroidx/compose/ui/Modifier;Landroidx/compose/runtime/Composer;I)Landroidx/compose/ui/Modifier;
+HSPLandroidx/compose/foundation/ClickableKt$clickable$4;->invoke(Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;
+HSPLandroidx/compose/foundation/ClickableKt$genericClickableWithoutGesture$clickSemantics$1$1;-><init>(Lkotlin/jvm/functions/Function0;)V
+HSPLandroidx/compose/foundation/ClickableKt$genericClickableWithoutGesture$clickSemantics$1;-><init>(Landroidx/compose/ui/semantics/Role;Ljava/lang/String;Lkotlin/jvm/functions/Function0;Ljava/lang/String;ZLkotlin/jvm/functions/Function0;)V
+HSPLandroidx/compose/foundation/ClickableKt$genericClickableWithoutGesture$clickSemantics$1;->invoke(Landroidx/compose/ui/semantics/SemanticsPropertyReceiver;)V
+HSPLandroidx/compose/foundation/ClickableKt$genericClickableWithoutGesture$clickSemantics$1;->invoke(Ljava/lang/Object;)Ljava/lang/Object;
+HSPLandroidx/compose/foundation/ClickableKt$genericClickableWithoutGesture$detectPressAndClickFromKey$1;-><init>(ZLjava/util/Map;Landroidx/compose/runtime/State;Lkotlinx/coroutines/CoroutineScope;Lkotlin/jvm/functions/Function0;Landroidx/compose/foundation/interaction/MutableInteractionSource;)V
+HSPLandroidx/compose/foundation/ClickableKt;->PressedInteractionSourceDisposableEffect(Landroidx/compose/foundation/interaction/MutableInteractionSource;Landroidx/compose/runtime/MutableState;Ljava/util/Map;Landroidx/compose/runtime/Composer;I)V
+HSPLandroidx/compose/foundation/ClickableKt;->clickable-O2vRcR0$default(Landroidx/compose/ui/Modifier;Landroidx/compose/foundation/interaction/MutableInteractionSource;Landroidx/compose/foundation/Indication;ZLjava/lang/String;Landroidx/compose/ui/semantics/Role;Lkotlin/jvm/functions/Function0;ILjava/lang/Object;)Landroidx/compose/ui/Modifier;
+HSPLandroidx/compose/foundation/ClickableKt;->clickable-O2vRcR0(Landroidx/compose/ui/Modifier;Landroidx/compose/foundation/interaction/MutableInteractionSource;Landroidx/compose/foundation/Indication;ZLjava/lang/String;Landroidx/compose/ui/semantics/Role;Lkotlin/jvm/functions/Function0;)Landroidx/compose/ui/Modifier;
+HSPLandroidx/compose/foundation/ClickableKt;->genericClickableWithoutGesture-bdNGguI(Landroidx/compose/ui/Modifier;Landroidx/compose/ui/Modifier;Landroidx/compose/foundation/interaction/MutableInteractionSource;Landroidx/compose/foundation/Indication;Lkotlinx/coroutines/CoroutineScope;Ljava/util/Map;Landroidx/compose/runtime/State;ZLjava/lang/String;Landroidx/compose/ui/semantics/Role;Ljava/lang/String;Lkotlin/jvm/functions/Function0;Lkotlin/jvm/functions/Function0;)Landroidx/compose/ui/Modifier;
+HSPLandroidx/compose/foundation/ClickableKt;->genericClickableWithoutGesture_bdNGguI$clickSemantics(Landroidx/compose/ui/Modifier;Landroidx/compose/ui/semantics/Role;Ljava/lang/String;Lkotlin/jvm/functions/Function0;Ljava/lang/String;ZLkotlin/jvm/functions/Function0;)Landroidx/compose/ui/Modifier;
+HSPLandroidx/compose/foundation/ClickableKt;->genericClickableWithoutGesture_bdNGguI$detectPressAndClickFromKey(Landroidx/compose/ui/Modifier;ZLjava/util/Map;Landroidx/compose/runtime/State;Lkotlinx/coroutines/CoroutineScope;Lkotlin/jvm/functions/Function0;Landroidx/compose/foundation/interaction/MutableInteractionSource;)Landroidx/compose/ui/Modifier;
+HSPLandroidx/compose/foundation/DarkThemeKt;->isSystemInDarkTheme(Landroidx/compose/runtime/Composer;I)Z
+HSPLandroidx/compose/foundation/DarkTheme_androidKt;->_isSystemInDarkTheme(Landroidx/compose/runtime/Composer;I)Z
+HSPLandroidx/compose/foundation/FocusableKt$focusable$2$1$1$invoke$$inlined$onDispose$1;-><init>(Landroidx/compose/runtime/MutableState;Landroidx/compose/foundation/interaction/MutableInteractionSource;)V
+HSPLandroidx/compose/foundation/FocusableKt$focusable$2$1$1;-><init>(Landroidx/compose/runtime/MutableState;Landroidx/compose/foundation/interaction/MutableInteractionSource;)V
+HSPLandroidx/compose/foundation/FocusableKt$focusable$2$1$1;->invoke(Landroidx/compose/runtime/DisposableEffectScope;)Landroidx/compose/runtime/DisposableEffectResult;
+HSPLandroidx/compose/foundation/FocusableKt$focusable$2$1$1;->invoke(Ljava/lang/Object;)Ljava/lang/Object;
+HSPLandroidx/compose/foundation/FocusableKt$focusable$2$2$invoke$$inlined$onDispose$1;-><init>()V
+HSPLandroidx/compose/foundation/FocusableKt$focusable$2$2;-><init>(ZLkotlinx/coroutines/CoroutineScope;Landroidx/compose/runtime/MutableState;Landroidx/compose/foundation/interaction/MutableInteractionSource;)V
+HSPLandroidx/compose/foundation/FocusableKt$focusable$2$2;->invoke(Landroidx/compose/runtime/DisposableEffectScope;)Landroidx/compose/runtime/DisposableEffectResult;
+HSPLandroidx/compose/foundation/FocusableKt$focusable$2$2;->invoke(Ljava/lang/Object;)Ljava/lang/Object;
+HSPLandroidx/compose/foundation/FocusableKt$focusable$2$3$1;-><init>(Landroidx/compose/ui/focus/FocusRequester;Landroidx/compose/runtime/MutableState;)V
+HSPLandroidx/compose/foundation/FocusableKt$focusable$2$3;-><init>(Landroidx/compose/runtime/MutableState;Landroidx/compose/ui/focus/FocusRequester;)V
+HSPLandroidx/compose/foundation/FocusableKt$focusable$2$3;->invoke(Landroidx/compose/ui/semantics/SemanticsPropertyReceiver;)V
+HSPLandroidx/compose/foundation/FocusableKt$focusable$2$3;->invoke(Ljava/lang/Object;)Ljava/lang/Object;
+HSPLandroidx/compose/foundation/FocusableKt$focusable$2$4$1;-><init>(Landroidx/compose/runtime/MutableState;)V
+HSPLandroidx/compose/foundation/FocusableKt$focusable$2$4$1;->invoke(Landroidx/compose/foundation/lazy/layout/PinnableParent;)V
+HSPLandroidx/compose/foundation/FocusableKt$focusable$2$4$1;->invoke(Ljava/lang/Object;)Ljava/lang/Object;
+HSPLandroidx/compose/foundation/FocusableKt$focusable$2$5$3;-><init>(Landroidx/compose/runtime/MutableState;Landroidx/compose/foundation/interaction/MutableInteractionSource;Lkotlin/coroutines/Continuation;)V
+HSPLandroidx/compose/foundation/FocusableKt$focusable$2$5$3;->create(Ljava/lang/Object;Lkotlin/coroutines/Continuation;)Lkotlin/coroutines/Continuation;
+HSPLandroidx/compose/foundation/FocusableKt$focusable$2$5$3;->invokeSuspend(Ljava/lang/Object;)Ljava/lang/Object;
+HSPLandroidx/compose/foundation/FocusableKt$focusable$2$5;-><init>(Lkotlinx/coroutines/CoroutineScope;Landroidx/compose/runtime/MutableState;Landroidx/compose/foundation/relocation/BringIntoViewRequester;Landroidx/compose/runtime/MutableState;Landroidx/compose/runtime/MutableState;Landroidx/compose/foundation/interaction/MutableInteractionSource;)V
+HSPLandroidx/compose/foundation/FocusableKt$focusable$2$5;->invoke(Landroidx/compose/ui/focus/FocusState;)V
+HSPLandroidx/compose/foundation/FocusableKt$focusable$2$5;->invoke(Ljava/lang/Object;)Ljava/lang/Object;
+HSPLandroidx/compose/foundation/FocusableKt$focusable$2;-><init>(Landroidx/compose/foundation/interaction/MutableInteractionSource;Z)V
+HSPLandroidx/compose/foundation/FocusableKt$focusable$2;->access$invoke$lambda$3(Landroidx/compose/runtime/MutableState;Landroidx/compose/foundation/lazy/layout/PinnableParent;)V
+HSPLandroidx/compose/foundation/FocusableKt$focusable$2;->access$invoke$lambda$5(Landroidx/compose/runtime/MutableState;)Z
+HSPLandroidx/compose/foundation/FocusableKt$focusable$2;->access$invoke$lambda$6(Landroidx/compose/runtime/MutableState;Z)V
+HSPLandroidx/compose/foundation/FocusableKt$focusable$2;->invoke$lambda$3(Landroidx/compose/runtime/MutableState;Landroidx/compose/foundation/lazy/layout/PinnableParent;)V
+HSPLandroidx/compose/foundation/FocusableKt$focusable$2;->invoke$lambda$5(Landroidx/compose/runtime/MutableState;)Z
+HSPLandroidx/compose/foundation/FocusableKt$focusable$2;->invoke$lambda$6(Landroidx/compose/runtime/MutableState;Z)V
+HSPLandroidx/compose/foundation/FocusableKt$focusable$2;->invoke(Landroidx/compose/ui/Modifier;Landroidx/compose/runtime/Composer;I)Landroidx/compose/ui/Modifier;
+HSPLandroidx/compose/foundation/FocusableKt$focusable$2;->invoke(Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;
+HSPLandroidx/compose/foundation/FocusableKt$focusableInNonTouchMode$2$1;-><init>(Landroidx/compose/ui/input/InputModeManager;)V
+HSPLandroidx/compose/foundation/FocusableKt$focusableInNonTouchMode$2$1;->invoke(Landroidx/compose/ui/focus/FocusProperties;)V
+HSPLandroidx/compose/foundation/FocusableKt$focusableInNonTouchMode$2$1;->invoke(Ljava/lang/Object;)Ljava/lang/Object;
+HSPLandroidx/compose/foundation/FocusableKt$focusableInNonTouchMode$2;-><init>(ZLandroidx/compose/foundation/interaction/MutableInteractionSource;)V
+HSPLandroidx/compose/foundation/FocusableKt$focusableInNonTouchMode$2;->invoke(Landroidx/compose/ui/Modifier;Landroidx/compose/runtime/Composer;I)Landroidx/compose/ui/Modifier;
+HSPLandroidx/compose/foundation/FocusableKt$focusableInNonTouchMode$2;->invoke(Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;
+HSPLandroidx/compose/foundation/FocusableKt;-><clinit>()V
+HSPLandroidx/compose/foundation/FocusableKt;->access$onPinnableParentAvailable(Landroidx/compose/ui/Modifier;Lkotlin/jvm/functions/Function1;)Landroidx/compose/ui/Modifier;
+HSPLandroidx/compose/foundation/FocusableKt;->focusable(Landroidx/compose/ui/Modifier;ZLandroidx/compose/foundation/interaction/MutableInteractionSource;)Landroidx/compose/ui/Modifier;
+HSPLandroidx/compose/foundation/FocusableKt;->focusableInNonTouchMode(Landroidx/compose/ui/Modifier;ZLandroidx/compose/foundation/interaction/MutableInteractionSource;)Landroidx/compose/ui/Modifier;
+HSPLandroidx/compose/foundation/FocusableKt;->onPinnableParentAvailable(Landroidx/compose/ui/Modifier;Lkotlin/jvm/functions/Function1;)Landroidx/compose/ui/Modifier;
+HSPLandroidx/compose/foundation/HoverableKt$hoverable$2$1$1$invoke$$inlined$onDispose$1;-><init>(Landroidx/compose/runtime/MutableState;Landroidx/compose/foundation/interaction/MutableInteractionSource;)V
+HSPLandroidx/compose/foundation/HoverableKt$hoverable$2$1$1;-><init>(Landroidx/compose/runtime/MutableState;Landroidx/compose/foundation/interaction/MutableInteractionSource;)V
+HSPLandroidx/compose/foundation/HoverableKt$hoverable$2$1$1;->invoke(Landroidx/compose/runtime/DisposableEffectScope;)Landroidx/compose/runtime/DisposableEffectResult;
+HSPLandroidx/compose/foundation/HoverableKt$hoverable$2$1$1;->invoke(Ljava/lang/Object;)Ljava/lang/Object;
+HSPLandroidx/compose/foundation/HoverableKt$hoverable$2$2$1;-><init>(ZLandroidx/compose/runtime/MutableState;Landroidx/compose/foundation/interaction/MutableInteractionSource;Lkotlin/coroutines/Continuation;)V
+HSPLandroidx/compose/foundation/HoverableKt$hoverable$2$2$1;->create(Ljava/lang/Object;Lkotlin/coroutines/Continuation;)Lkotlin/coroutines/Continuation;
+HSPLandroidx/compose/foundation/HoverableKt$hoverable$2$2$1;->invokeSuspend(Ljava/lang/Object;)Ljava/lang/Object;
+HSPLandroidx/compose/foundation/HoverableKt$hoverable$2$3$1;-><init>(Lkotlin/coroutines/CoroutineContext;Lkotlinx/coroutines/CoroutineScope;Landroidx/compose/foundation/interaction/MutableInteractionSource;Landroidx/compose/runtime/MutableState;Lkotlin/coroutines/Continuation;)V
+HSPLandroidx/compose/foundation/HoverableKt$hoverable$2$3$1;->create(Ljava/lang/Object;Lkotlin/coroutines/Continuation;)Lkotlin/coroutines/Continuation;
+HSPLandroidx/compose/foundation/HoverableKt$hoverable$2$3$1;->invokeSuspend(Ljava/lang/Object;)Ljava/lang/Object;
+HSPLandroidx/compose/foundation/HoverableKt$hoverable$2$3;-><init>(Lkotlinx/coroutines/CoroutineScope;Landroidx/compose/foundation/interaction/MutableInteractionSource;Landroidx/compose/runtime/MutableState;Lkotlin/coroutines/Continuation;)V
+HSPLandroidx/compose/foundation/HoverableKt$hoverable$2$3;->create(Ljava/lang/Object;Lkotlin/coroutines/Continuation;)Lkotlin/coroutines/Continuation;
+HSPLandroidx/compose/foundation/HoverableKt$hoverable$2$3;->invoke(Landroidx/compose/ui/input/pointer/PointerInputScope;Lkotlin/coroutines/Continuation;)Ljava/lang/Object;
+HSPLandroidx/compose/foundation/HoverableKt$hoverable$2$3;->invoke(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;
+HSPLandroidx/compose/foundation/HoverableKt$hoverable$2$3;->invokeSuspend(Ljava/lang/Object;)Ljava/lang/Object;
+HSPLandroidx/compose/foundation/HoverableKt$hoverable$2;-><init>(Landroidx/compose/foundation/interaction/MutableInteractionSource;Z)V
+HSPLandroidx/compose/foundation/HoverableKt$hoverable$2;->invoke(Landroidx/compose/ui/Modifier;Landroidx/compose/runtime/Composer;I)Landroidx/compose/ui/Modifier;
+HSPLandroidx/compose/foundation/HoverableKt$hoverable$2;->invoke(Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;
+HSPLandroidx/compose/foundation/HoverableKt;->hoverable(Landroidx/compose/ui/Modifier;Landroidx/compose/foundation/interaction/MutableInteractionSource;Z)Landroidx/compose/ui/Modifier;
+HSPLandroidx/compose/foundation/IndicationKt$LocalIndication$1;-><clinit>()V
+HSPLandroidx/compose/foundation/IndicationKt$LocalIndication$1;-><init>()V
+HSPLandroidx/compose/foundation/IndicationKt$indication$2;-><init>(Landroidx/compose/foundation/Indication;Landroidx/compose/foundation/interaction/InteractionSource;)V
+HSPLandroidx/compose/foundation/IndicationKt$indication$2;->invoke(Landroidx/compose/ui/Modifier;Landroidx/compose/runtime/Composer;I)Landroidx/compose/ui/Modifier;
+HSPLandroidx/compose/foundation/IndicationKt$indication$2;->invoke(Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;
+HSPLandroidx/compose/foundation/IndicationKt;-><clinit>()V
+HSPLandroidx/compose/foundation/IndicationKt;->getLocalIndication()Landroidx/compose/runtime/ProvidableCompositionLocal;
+HSPLandroidx/compose/foundation/IndicationKt;->indication(Landroidx/compose/ui/Modifier;Landroidx/compose/foundation/interaction/InteractionSource;Landroidx/compose/foundation/Indication;)Landroidx/compose/ui/Modifier;
+HSPLandroidx/compose/foundation/IndicationModifier;-><init>(Landroidx/compose/foundation/IndicationInstance;)V
+HSPLandroidx/compose/foundation/IndicationModifier;->draw(Landroidx/compose/ui/graphics/drawscope/ContentDrawScope;)V
+HSPLandroidx/compose/foundation/MutatePriority;->$values()[Landroidx/compose/foundation/MutatePriority;
+HSPLandroidx/compose/foundation/MutatePriority;-><clinit>()V
+HSPLandroidx/compose/foundation/MutatePriority;-><init>(Ljava/lang/String;I)V
+HSPLandroidx/compose/foundation/MutatorMutex$Mutator;-><init>(Landroidx/compose/foundation/MutatePriority;Lkotlinx/coroutines/Job;)V
+HSPLandroidx/compose/foundation/MutatorMutex$mutateWith$2;-><init>(Landroidx/compose/foundation/MutatePriority;Landroidx/compose/foundation/MutatorMutex;Lkotlin/jvm/functions/Function2;Ljava/lang/Object;Lkotlin/coroutines/Continuation;)V
+HSPLandroidx/compose/foundation/MutatorMutex$mutateWith$2;->create(Ljava/lang/Object;Lkotlin/coroutines/Continuation;)Lkotlin/coroutines/Continuation;
+HSPLandroidx/compose/foundation/MutatorMutex$mutateWith$2;->invoke(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;
+HSPLandroidx/compose/foundation/MutatorMutex$mutateWith$2;->invoke(Lkotlinx/coroutines/CoroutineScope;Lkotlin/coroutines/Continuation;)Ljava/lang/Object;
+HSPLandroidx/compose/foundation/MutatorMutex$mutateWith$2;->invokeSuspend(Ljava/lang/Object;)Ljava/lang/Object;
+HSPLandroidx/compose/foundation/MutatorMutex;-><init>()V
+HSPLandroidx/compose/foundation/MutatorMutex;->access$getCurrentMutator$p(Landroidx/compose/foundation/MutatorMutex;)Ljava/util/concurrent/atomic/AtomicReference;
+HSPLandroidx/compose/foundation/MutatorMutex;->access$getMutex$p(Landroidx/compose/foundation/MutatorMutex;)Lkotlinx/coroutines/sync/Mutex;
+HSPLandroidx/compose/foundation/MutatorMutex;->access$tryMutateOrCancel(Landroidx/compose/foundation/MutatorMutex;Landroidx/compose/foundation/MutatorMutex$Mutator;)V
+HSPLandroidx/compose/foundation/MutatorMutex;->mutateWith(Ljava/lang/Object;Landroidx/compose/foundation/MutatePriority;Lkotlin/jvm/functions/Function2;Lkotlin/coroutines/Continuation;)Ljava/lang/Object;
+HSPLandroidx/compose/foundation/MutatorMutex;->tryMutateOrCancel(Landroidx/compose/foundation/MutatorMutex$Mutator;)V
+HSPLandroidx/compose/foundation/PinnableParentConsumer;-><init>(Lkotlin/jvm/functions/Function1;)V
+HSPLandroidx/compose/foundation/PinnableParentConsumer;->equals(Ljava/lang/Object;)Z
+HSPLandroidx/compose/foundation/PinnableParentConsumer;->onModifierLocalsUpdated(Landroidx/compose/ui/modifier/ModifierLocalReadScope;)V
+HSPLandroidx/compose/foundation/gestures/DefaultDraggableState$drag$2;-><init>(Landroidx/compose/foundation/gestures/DefaultDraggableState;Landroidx/compose/foundation/MutatePriority;Lkotlin/jvm/functions/Function2;Lkotlin/coroutines/Continuation;)V
+HSPLandroidx/compose/foundation/gestures/DefaultDraggableState$drag$2;->create(Ljava/lang/Object;Lkotlin/coroutines/Continuation;)Lkotlin/coroutines/Continuation;
+HSPLandroidx/compose/foundation/gestures/DefaultDraggableState$drag$2;->invoke(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;
+HSPLandroidx/compose/foundation/gestures/DefaultDraggableState$drag$2;->invoke(Lkotlinx/coroutines/CoroutineScope;Lkotlin/coroutines/Continuation;)Ljava/lang/Object;
+HSPLandroidx/compose/foundation/gestures/DefaultDraggableState$drag$2;->invokeSuspend(Ljava/lang/Object;)Ljava/lang/Object;
+HSPLandroidx/compose/foundation/gestures/DefaultDraggableState$dragScope$1;-><init>(Landroidx/compose/foundation/gestures/DefaultDraggableState;)V
+HSPLandroidx/compose/foundation/gestures/DefaultDraggableState$dragScope$1;->dragBy(F)V
+HSPLandroidx/compose/foundation/gestures/DefaultDraggableState;-><init>(Lkotlin/jvm/functions/Function1;)V
+HSPLandroidx/compose/foundation/gestures/DefaultDraggableState;->access$getDragScope$p(Landroidx/compose/foundation/gestures/DefaultDraggableState;)Landroidx/compose/foundation/gestures/DragScope;
+HSPLandroidx/compose/foundation/gestures/DefaultDraggableState;->access$getScrollMutex$p(Landroidx/compose/foundation/gestures/DefaultDraggableState;)Landroidx/compose/foundation/MutatorMutex;
+HSPLandroidx/compose/foundation/gestures/DefaultDraggableState;->drag(Landroidx/compose/foundation/MutatePriority;Lkotlin/jvm/functions/Function2;Lkotlin/coroutines/Continuation;)Ljava/lang/Object;
+HSPLandroidx/compose/foundation/gestures/DefaultDraggableState;->getOnDelta()Lkotlin/jvm/functions/Function1;
+HSPLandroidx/compose/foundation/gestures/DragLogic;-><init>(Lkotlin/jvm/functions/Function3;Lkotlin/jvm/functions/Function3;Landroidx/compose/runtime/MutableState;Landroidx/compose/foundation/interaction/MutableInteractionSource;)V
+HSPLandroidx/compose/foundation/gestures/DraggableKt$awaitDownAndSlop$1;-><init>(Lkotlin/coroutines/Continuation;)V
+HSPLandroidx/compose/foundation/gestures/DraggableKt$draggable$1;-><init>(Lkotlin/coroutines/Continuation;)V
+HSPLandroidx/compose/foundation/gestures/DraggableKt$draggable$3;-><clinit>()V
+HSPLandroidx/compose/foundation/gestures/DraggableKt$draggable$3;-><init>()V
+HSPLandroidx/compose/foundation/gestures/DraggableKt$draggable$4;-><init>(Z)V
+HSPLandroidx/compose/foundation/gestures/DraggableKt$draggable$5;-><init>(Lkotlin/jvm/functions/Function3;Landroidx/compose/foundation/gestures/Orientation;Lkotlin/coroutines/Continuation;)V
+HSPLandroidx/compose/foundation/gestures/DraggableKt$draggable$9$1$1$invoke$$inlined$onDispose$1;-><init>(Landroidx/compose/runtime/MutableState;Landroidx/compose/foundation/interaction/MutableInteractionSource;)V
+HSPLandroidx/compose/foundation/gestures/DraggableKt$draggable$9$1$1;-><init>(Landroidx/compose/runtime/MutableState;Landroidx/compose/foundation/interaction/MutableInteractionSource;)V
+HSPLandroidx/compose/foundation/gestures/DraggableKt$draggable$9$1$1;->invoke(Landroidx/compose/runtime/DisposableEffectScope;)Landroidx/compose/runtime/DisposableEffectResult;
+HSPLandroidx/compose/foundation/gestures/DraggableKt$draggable$9$1$1;->invoke(Ljava/lang/Object;)Ljava/lang/Object;
+HSPLandroidx/compose/foundation/gestures/DraggableKt$draggable$9$2;-><init>(Lkotlinx/coroutines/channels/Channel;Landroidx/compose/foundation/gestures/DraggableState;Landroidx/compose/runtime/State;Landroidx/compose/foundation/gestures/Orientation;Lkotlin/coroutines/Continuation;)V
+HSPLandroidx/compose/foundation/gestures/DraggableKt$draggable$9$2;->create(Ljava/lang/Object;Lkotlin/coroutines/Continuation;)Lkotlin/coroutines/Continuation;
+HSPLandroidx/compose/foundation/gestures/DraggableKt$draggable$9$2;->invokeSuspend(Ljava/lang/Object;)Ljava/lang/Object;
+HSPLandroidx/compose/foundation/gestures/DraggableKt$draggable$9$3$1$1;-><init>(Lkotlinx/coroutines/CoroutineScope;Landroidx/compose/runtime/State;Landroidx/compose/runtime/State;Landroidx/compose/foundation/gestures/Orientation;Lkotlinx/coroutines/channels/Channel;ZLkotlin/coroutines/Continuation;)V
+HSPLandroidx/compose/foundation/gestures/DraggableKt$draggable$9$3$1$1;->create(Ljava/lang/Object;Lkotlin/coroutines/Continuation;)Lkotlin/coroutines/Continuation;
+HSPLandroidx/compose/foundation/gestures/DraggableKt$draggable$9$3$1$1;->invokeSuspend(Ljava/lang/Object;)Ljava/lang/Object;
+HSPLandroidx/compose/foundation/gestures/DraggableKt$draggable$9$3$1;-><init>(Landroidx/compose/ui/input/pointer/PointerInputScope;Landroidx/compose/runtime/State;Landroidx/compose/runtime/State;Landroidx/compose/foundation/gestures/Orientation;Lkotlinx/coroutines/channels/Channel;ZLkotlin/coroutines/Continuation;)V
+HSPLandroidx/compose/foundation/gestures/DraggableKt$draggable$9$3$1;->create(Ljava/lang/Object;Lkotlin/coroutines/Continuation;)Lkotlin/coroutines/Continuation;
+HSPLandroidx/compose/foundation/gestures/DraggableKt$draggable$9$3$1;->invoke(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;
+HSPLandroidx/compose/foundation/gestures/DraggableKt$draggable$9$3$1;->invoke(Lkotlinx/coroutines/CoroutineScope;Lkotlin/coroutines/Continuation;)Ljava/lang/Object;
+HSPLandroidx/compose/foundation/gestures/DraggableKt$draggable$9$3$1;->invokeSuspend(Ljava/lang/Object;)Ljava/lang/Object;
+HSPLandroidx/compose/foundation/gestures/DraggableKt$draggable$9$3;-><init>(ZLandroidx/compose/runtime/State;Landroidx/compose/runtime/State;Landroidx/compose/foundation/gestures/Orientation;Lkotlinx/coroutines/channels/Channel;ZLkotlin/coroutines/Continuation;)V
+HSPLandroidx/compose/foundation/gestures/DraggableKt$draggable$9$3;->create(Ljava/lang/Object;Lkotlin/coroutines/Continuation;)Lkotlin/coroutines/Continuation;
+HSPLandroidx/compose/foundation/gestures/DraggableKt$draggable$9$3;->invoke(Landroidx/compose/ui/input/pointer/PointerInputScope;Lkotlin/coroutines/Continuation;)Ljava/lang/Object;
+HSPLandroidx/compose/foundation/gestures/DraggableKt$draggable$9$3;->invoke(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;
+HSPLandroidx/compose/foundation/gestures/DraggableKt$draggable$9$3;->invokeSuspend(Ljava/lang/Object;)Ljava/lang/Object;
+HSPLandroidx/compose/foundation/gestures/DraggableKt$draggable$9;-><init>(Landroidx/compose/foundation/interaction/MutableInteractionSource;Lkotlin/jvm/functions/Function0;Lkotlin/jvm/functions/Function1;Lkotlin/jvm/functions/Function3;Lkotlin/jvm/functions/Function3;Landroidx/compose/foundation/gestures/DraggableState;Landroidx/compose/foundation/gestures/Orientation;ZZ)V
+HSPLandroidx/compose/foundation/gestures/DraggableKt$draggable$9;->invoke(Landroidx/compose/ui/Modifier;Landroidx/compose/runtime/Composer;I)Landroidx/compose/ui/Modifier;
+HSPLandroidx/compose/foundation/gestures/DraggableKt$draggable$9;->invoke(Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;
+HSPLandroidx/compose/foundation/gestures/DraggableKt;->DraggableState(Lkotlin/jvm/functions/Function1;)Landroidx/compose/foundation/gestures/DraggableState;
+HSPLandroidx/compose/foundation/gestures/DraggableKt;->access$awaitDownAndSlop(Landroidx/compose/ui/input/pointer/AwaitPointerEventScope;Landroidx/compose/runtime/State;Landroidx/compose/runtime/State;Landroidx/compose/ui/input/pointer/util/VelocityTracker;Landroidx/compose/foundation/gestures/Orientation;Lkotlin/coroutines/Continuation;)Ljava/lang/Object;
+HSPLandroidx/compose/foundation/gestures/DraggableKt;->awaitDownAndSlop(Landroidx/compose/ui/input/pointer/AwaitPointerEventScope;Landroidx/compose/runtime/State;Landroidx/compose/runtime/State;Landroidx/compose/ui/input/pointer/util/VelocityTracker;Landroidx/compose/foundation/gestures/Orientation;Lkotlin/coroutines/Continuation;)Ljava/lang/Object;
+HSPLandroidx/compose/foundation/gestures/DraggableKt;->draggable$default(Landroidx/compose/ui/Modifier;Landroidx/compose/foundation/gestures/DraggableState;Landroidx/compose/foundation/gestures/Orientation;ZLandroidx/compose/foundation/interaction/MutableInteractionSource;ZLkotlin/jvm/functions/Function3;Lkotlin/jvm/functions/Function3;ZILjava/lang/Object;)Landroidx/compose/ui/Modifier;
+HSPLandroidx/compose/foundation/gestures/DraggableKt;->draggable(Landroidx/compose/ui/Modifier;Landroidx/compose/foundation/gestures/DraggableState;Landroidx/compose/foundation/gestures/Orientation;ZLandroidx/compose/foundation/interaction/MutableInteractionSource;ZLkotlin/jvm/functions/Function3;Lkotlin/jvm/functions/Function3;Z)Landroidx/compose/ui/Modifier;
+HSPLandroidx/compose/foundation/gestures/DraggableKt;->draggable(Landroidx/compose/ui/Modifier;Landroidx/compose/foundation/gestures/DraggableState;Lkotlin/jvm/functions/Function1;Landroidx/compose/foundation/gestures/Orientation;ZLandroidx/compose/foundation/interaction/MutableInteractionSource;Lkotlin/jvm/functions/Function0;Lkotlin/jvm/functions/Function3;Lkotlin/jvm/functions/Function3;Z)Landroidx/compose/ui/Modifier;
+HSPLandroidx/compose/foundation/gestures/DraggableState;->drag$default(Landroidx/compose/foundation/gestures/DraggableState;Landroidx/compose/foundation/MutatePriority;Lkotlin/jvm/functions/Function2;Lkotlin/coroutines/Continuation;ILjava/lang/Object;)Ljava/lang/Object;
+HSPLandroidx/compose/foundation/gestures/ForEachGestureKt$awaitEachGesture$2;-><init>(Lkotlin/coroutines/CoroutineContext;Lkotlin/jvm/functions/Function2;Lkotlin/coroutines/Continuation;)V
+HSPLandroidx/compose/foundation/gestures/ForEachGestureKt$awaitEachGesture$2;->create(Ljava/lang/Object;Lkotlin/coroutines/Continuation;)Lkotlin/coroutines/Continuation;
+HSPLandroidx/compose/foundation/gestures/ForEachGestureKt$awaitEachGesture$2;->invokeSuspend(Ljava/lang/Object;)Ljava/lang/Object;
+HSPLandroidx/compose/foundation/gestures/ForEachGestureKt;->awaitEachGesture(Landroidx/compose/ui/input/pointer/PointerInputScope;Lkotlin/jvm/functions/Function2;Lkotlin/coroutines/Continuation;)Ljava/lang/Object;
+HSPLandroidx/compose/foundation/gestures/Orientation;->$values()[Landroidx/compose/foundation/gestures/Orientation;
+HSPLandroidx/compose/foundation/gestures/Orientation;-><clinit>()V
+HSPLandroidx/compose/foundation/gestures/Orientation;-><init>(Ljava/lang/String;I)V
+HSPLandroidx/compose/foundation/gestures/PressGestureScopeImpl$reset$1;-><init>(Landroidx/compose/foundation/gestures/PressGestureScopeImpl;Lkotlin/coroutines/Continuation;)V
+HSPLandroidx/compose/foundation/gestures/PressGestureScopeImpl;-><init>(Landroidx/compose/ui/unit/Density;)V
+HSPLandroidx/compose/foundation/gestures/PressGestureScopeImpl;->reset(Lkotlin/coroutines/Continuation;)Ljava/lang/Object;
+HSPLandroidx/compose/foundation/gestures/TapGestureDetectorKt$NoPressGesture$1;-><init>(Lkotlin/coroutines/Continuation;)V
+HSPLandroidx/compose/foundation/gestures/TapGestureDetectorKt$awaitFirstDown$2;-><init>(Lkotlin/coroutines/Continuation;)V
+HSPLandroidx/compose/foundation/gestures/TapGestureDetectorKt$awaitFirstDown$2;->invokeSuspend(Ljava/lang/Object;)Ljava/lang/Object;
+HSPLandroidx/compose/foundation/gestures/TapGestureDetectorKt$detectTapAndPress$2$1$1;-><init>(Landroidx/compose/foundation/gestures/PressGestureScopeImpl;Lkotlin/coroutines/Continuation;)V
+HSPLandroidx/compose/foundation/gestures/TapGestureDetectorKt$detectTapAndPress$2$1$1;->create(Ljava/lang/Object;Lkotlin/coroutines/Continuation;)Lkotlin/coroutines/Continuation;
+HSPLandroidx/compose/foundation/gestures/TapGestureDetectorKt$detectTapAndPress$2$1$1;->invokeSuspend(Ljava/lang/Object;)Ljava/lang/Object;
+HSPLandroidx/compose/foundation/gestures/TapGestureDetectorKt$detectTapAndPress$2$1;-><init>(Lkotlinx/coroutines/CoroutineScope;Lkotlin/jvm/functions/Function3;Lkotlin/jvm/functions/Function1;Landroidx/compose/foundation/gestures/PressGestureScopeImpl;Lkotlin/coroutines/Continuation;)V
+HSPLandroidx/compose/foundation/gestures/TapGestureDetectorKt$detectTapAndPress$2$1;->create(Ljava/lang/Object;Lkotlin/coroutines/Continuation;)Lkotlin/coroutines/Continuation;
+HSPLandroidx/compose/foundation/gestures/TapGestureDetectorKt$detectTapAndPress$2$1;->invoke(Landroidx/compose/ui/input/pointer/AwaitPointerEventScope;Lkotlin/coroutines/Continuation;)Ljava/lang/Object;
+HSPLandroidx/compose/foundation/gestures/TapGestureDetectorKt$detectTapAndPress$2$1;->invoke(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;
+HSPLandroidx/compose/foundation/gestures/TapGestureDetectorKt$detectTapAndPress$2$1;->invokeSuspend(Ljava/lang/Object;)Ljava/lang/Object;
+HSPLandroidx/compose/foundation/gestures/TapGestureDetectorKt$detectTapAndPress$2;-><init>(Landroidx/compose/ui/input/pointer/PointerInputScope;Lkotlin/jvm/functions/Function3;Lkotlin/jvm/functions/Function1;Landroidx/compose/foundation/gestures/PressGestureScopeImpl;Lkotlin/coroutines/Continuation;)V
+HSPLandroidx/compose/foundation/gestures/TapGestureDetectorKt$detectTapAndPress$2;->create(Ljava/lang/Object;Lkotlin/coroutines/Continuation;)Lkotlin/coroutines/Continuation;
+HSPLandroidx/compose/foundation/gestures/TapGestureDetectorKt$detectTapAndPress$2;->invoke(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;
+HSPLandroidx/compose/foundation/gestures/TapGestureDetectorKt$detectTapAndPress$2;->invoke(Lkotlinx/coroutines/CoroutineScope;Lkotlin/coroutines/Continuation;)Ljava/lang/Object;
+HSPLandroidx/compose/foundation/gestures/TapGestureDetectorKt$detectTapAndPress$2;->invokeSuspend(Ljava/lang/Object;)Ljava/lang/Object;
+HSPLandroidx/compose/foundation/gestures/TapGestureDetectorKt$detectTapGestures$2$1;-><init>(Lkotlinx/coroutines/CoroutineScope;Lkotlin/jvm/functions/Function3;Lkotlin/jvm/functions/Function1;Lkotlin/jvm/functions/Function1;Lkotlin/jvm/functions/Function1;Landroidx/compose/foundation/gestures/PressGestureScopeImpl;Lkotlin/coroutines/Continuation;)V
+HSPLandroidx/compose/foundation/gestures/TapGestureDetectorKt$detectTapGestures$2$1;->create(Ljava/lang/Object;Lkotlin/coroutines/Continuation;)Lkotlin/coroutines/Continuation;
+HSPLandroidx/compose/foundation/gestures/TapGestureDetectorKt$detectTapGestures$2$1;->invoke(Landroidx/compose/ui/input/pointer/AwaitPointerEventScope;Lkotlin/coroutines/Continuation;)Ljava/lang/Object;
+HSPLandroidx/compose/foundation/gestures/TapGestureDetectorKt$detectTapGestures$2$1;->invoke(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;
+HSPLandroidx/compose/foundation/gestures/TapGestureDetectorKt$detectTapGestures$2$1;->invokeSuspend(Ljava/lang/Object;)Ljava/lang/Object;
+HSPLandroidx/compose/foundation/gestures/TapGestureDetectorKt$detectTapGestures$2;-><init>(Landroidx/compose/ui/input/pointer/PointerInputScope;Lkotlin/jvm/functions/Function3;Lkotlin/jvm/functions/Function1;Lkotlin/jvm/functions/Function1;Lkotlin/jvm/functions/Function1;Lkotlin/coroutines/Continuation;)V
+HSPLandroidx/compose/foundation/gestures/TapGestureDetectorKt$detectTapGestures$2;->create(Ljava/lang/Object;Lkotlin/coroutines/Continuation;)Lkotlin/coroutines/Continuation;
+HSPLandroidx/compose/foundation/gestures/TapGestureDetectorKt$detectTapGestures$2;->invoke(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;
+HSPLandroidx/compose/foundation/gestures/TapGestureDetectorKt$detectTapGestures$2;->invoke(Lkotlinx/coroutines/CoroutineScope;Lkotlin/coroutines/Continuation;)Ljava/lang/Object;
+HSPLandroidx/compose/foundation/gestures/TapGestureDetectorKt$detectTapGestures$2;->invokeSuspend(Ljava/lang/Object;)Ljava/lang/Object;
+HSPLandroidx/compose/foundation/gestures/TapGestureDetectorKt;-><clinit>()V
+HSPLandroidx/compose/foundation/gestures/TapGestureDetectorKt;->awaitFirstDown$default(Landroidx/compose/ui/input/pointer/AwaitPointerEventScope;ZLandroidx/compose/ui/input/pointer/PointerEventPass;Lkotlin/coroutines/Continuation;ILjava/lang/Object;)Ljava/lang/Object;
+HSPLandroidx/compose/foundation/gestures/TapGestureDetectorKt;->awaitFirstDown(Landroidx/compose/ui/input/pointer/AwaitPointerEventScope;ZLandroidx/compose/ui/input/pointer/PointerEventPass;Lkotlin/coroutines/Continuation;)Ljava/lang/Object;
+HSPLandroidx/compose/foundation/gestures/TapGestureDetectorKt;->detectTapAndPress(Landroidx/compose/ui/input/pointer/PointerInputScope;Lkotlin/jvm/functions/Function3;Lkotlin/jvm/functions/Function1;Lkotlin/coroutines/Continuation;)Ljava/lang/Object;
+HSPLandroidx/compose/foundation/gestures/TapGestureDetectorKt;->detectTapGestures$default(Landroidx/compose/ui/input/pointer/PointerInputScope;Lkotlin/jvm/functions/Function1;Lkotlin/jvm/functions/Function1;Lkotlin/jvm/functions/Function3;Lkotlin/jvm/functions/Function1;Lkotlin/coroutines/Continuation;ILjava/lang/Object;)Ljava/lang/Object;
+HSPLandroidx/compose/foundation/gestures/TapGestureDetectorKt;->detectTapGestures(Landroidx/compose/ui/input/pointer/PointerInputScope;Lkotlin/jvm/functions/Function1;Lkotlin/jvm/functions/Function1;Lkotlin/jvm/functions/Function3;Lkotlin/jvm/functions/Function1;Lkotlin/coroutines/Continuation;)Ljava/lang/Object;
+HSPLandroidx/compose/foundation/interaction/InteractionSourceKt;->MutableInteractionSource()Landroidx/compose/foundation/interaction/MutableInteractionSource;
+HSPLandroidx/compose/foundation/interaction/MutableInteractionSourceImpl;-><init>()V
+HSPLandroidx/compose/foundation/interaction/MutableInteractionSourceImpl;->getInteractions()Lkotlinx/coroutines/flow/Flow;
+HSPLandroidx/compose/foundation/interaction/MutableInteractionSourceImpl;->getInteractions()Lkotlinx/coroutines/flow/MutableSharedFlow;
+HSPLandroidx/compose/foundation/interaction/PressInteraction$Press;-><clinit>()V
+HSPLandroidx/compose/foundation/interaction/PressInteraction$Press;-><init>(J)V
+HSPLandroidx/compose/foundation/interaction/PressInteraction$Press;-><init>(JLkotlin/jvm/internal/DefaultConstructorMarker;)V
+HSPLandroidx/compose/foundation/layout/Arrangement$Bottom$1;-><init>()V
+HSPLandroidx/compose/foundation/layout/Arrangement$Center$1;-><init>()V
+HSPLandroidx/compose/foundation/layout/Arrangement$Center$1;->arrange(Landroidx/compose/ui/unit/Density;I[ILandroidx/compose/ui/unit/LayoutDirection;[I)V
+HSPLandroidx/compose/foundation/layout/Arrangement$Center$1;->getSpacing-D9Ej5fM()F
+HSPLandroidx/compose/foundation/layout/Arrangement$End$1;-><init>()V
+HSPLandroidx/compose/foundation/layout/Arrangement$Horizontal;->getSpacing-D9Ej5fM()F
+HSPLandroidx/compose/foundation/layout/Arrangement$SpaceAround$1;-><init>()V
+HSPLandroidx/compose/foundation/layout/Arrangement$SpaceBetween$1;-><init>()V
+HSPLandroidx/compose/foundation/layout/Arrangement$SpaceBetween$1;->arrange(Landroidx/compose/ui/unit/Density;I[ILandroidx/compose/ui/unit/LayoutDirection;[I)V
+HSPLandroidx/compose/foundation/layout/Arrangement$SpaceBetween$1;->getSpacing-D9Ej5fM()F
+HSPLandroidx/compose/foundation/layout/Arrangement$SpaceEvenly$1;-><init>()V
+HSPLandroidx/compose/foundation/layout/Arrangement$Start$1;-><init>()V
+HSPLandroidx/compose/foundation/layout/Arrangement$Start$1;->arrange(Landroidx/compose/ui/unit/Density;I[ILandroidx/compose/ui/unit/LayoutDirection;[I)V
+HSPLandroidx/compose/foundation/layout/Arrangement$Top$1;-><init>()V
+HSPLandroidx/compose/foundation/layout/Arrangement$Top$1;->arrange(Landroidx/compose/ui/unit/Density;I[I[I)V
+HSPLandroidx/compose/foundation/layout/Arrangement$Vertical;->getSpacing-D9Ej5fM()F
+HSPLandroidx/compose/foundation/layout/Arrangement;-><clinit>()V
+HSPLandroidx/compose/foundation/layout/Arrangement;-><init>()V
+HSPLandroidx/compose/foundation/layout/Arrangement;->getCenter()Landroidx/compose/foundation/layout/Arrangement$HorizontalOrVertical;
+HSPLandroidx/compose/foundation/layout/Arrangement;->getSpaceBetween()Landroidx/compose/foundation/layout/Arrangement$HorizontalOrVertical;
+HSPLandroidx/compose/foundation/layout/Arrangement;->getStart()Landroidx/compose/foundation/layout/Arrangement$Horizontal;
+HSPLandroidx/compose/foundation/layout/Arrangement;->getTop()Landroidx/compose/foundation/layout/Arrangement$Vertical;
+HSPLandroidx/compose/foundation/layout/Arrangement;->placeCenter$foundation_layout_release(I[I[IZ)V
+HSPLandroidx/compose/foundation/layout/Arrangement;->placeLeftOrTop$foundation_layout_release([I[IZ)V
+HSPLandroidx/compose/foundation/layout/Arrangement;->placeSpaceBetween$foundation_layout_release(I[I[IZ)V
+HSPLandroidx/compose/foundation/layout/BoxKt$EmptyBoxMeasurePolicy$1$measure$1;-><clinit>()V
+HSPLandroidx/compose/foundation/layout/BoxKt$EmptyBoxMeasurePolicy$1$measure$1;-><init>()V
+HSPLandroidx/compose/foundation/layout/BoxKt$EmptyBoxMeasurePolicy$1$measure$1;->invoke(Landroidx/compose/ui/layout/Placeable$PlacementScope;)V
+HSPLandroidx/compose/foundation/layout/BoxKt$EmptyBoxMeasurePolicy$1$measure$1;->invoke(Ljava/lang/Object;)Ljava/lang/Object;
+HSPLandroidx/compose/foundation/layout/BoxKt$EmptyBoxMeasurePolicy$1;-><clinit>()V
+HSPLandroidx/compose/foundation/layout/BoxKt$EmptyBoxMeasurePolicy$1;-><init>()V
+HSPLandroidx/compose/foundation/layout/BoxKt$EmptyBoxMeasurePolicy$1;->measure-3p2s80s(Landroidx/compose/ui/layout/MeasureScope;Ljava/util/List;J)Landroidx/compose/ui/layout/MeasureResult;
+HSPLandroidx/compose/foundation/layout/BoxKt$boxMeasurePolicy$1$measure$2;-><init>(Landroidx/compose/ui/layout/Placeable;Landroidx/compose/ui/layout/Measurable;Landroidx/compose/ui/layout/MeasureScope;IILandroidx/compose/ui/Alignment;)V
+HSPLandroidx/compose/foundation/layout/BoxKt$boxMeasurePolicy$1$measure$2;->invoke(Landroidx/compose/ui/layout/Placeable$PlacementScope;)V
+HSPLandroidx/compose/foundation/layout/BoxKt$boxMeasurePolicy$1$measure$2;->invoke(Ljava/lang/Object;)Ljava/lang/Object;
+HSPLandroidx/compose/foundation/layout/BoxKt$boxMeasurePolicy$1$measure$5;-><init>([Landroidx/compose/ui/layout/Placeable;Ljava/util/List;Landroidx/compose/ui/layout/MeasureScope;Lkotlin/jvm/internal/Ref$IntRef;Lkotlin/jvm/internal/Ref$IntRef;Landroidx/compose/ui/Alignment;)V
+HSPLandroidx/compose/foundation/layout/BoxKt$boxMeasurePolicy$1$measure$5;->invoke(Landroidx/compose/ui/layout/Placeable$PlacementScope;)V
+HSPLandroidx/compose/foundation/layout/BoxKt$boxMeasurePolicy$1$measure$5;->invoke(Ljava/lang/Object;)Ljava/lang/Object;
+HSPLandroidx/compose/foundation/layout/BoxKt$boxMeasurePolicy$1;-><init>(ZLandroidx/compose/ui/Alignment;)V
+HSPLandroidx/compose/foundation/layout/BoxKt$boxMeasurePolicy$1;->measure-3p2s80s(Landroidx/compose/ui/layout/MeasureScope;Ljava/util/List;J)Landroidx/compose/ui/layout/MeasureResult;
+HSPLandroidx/compose/foundation/layout/BoxKt;-><clinit>()V
+HSPLandroidx/compose/foundation/layout/BoxKt;->Box(Landroidx/compose/ui/Modifier;Landroidx/compose/runtime/Composer;I)V
+HSPLandroidx/compose/foundation/layout/BoxKt;->access$getMatchesParentSize(Landroidx/compose/ui/layout/Measurable;)Z
+HSPLandroidx/compose/foundation/layout/BoxKt;->access$placeInBox(Landroidx/compose/ui/layout/Placeable$PlacementScope;Landroidx/compose/ui/layout/Placeable;Landroidx/compose/ui/layout/Measurable;Landroidx/compose/ui/unit/LayoutDirection;IILandroidx/compose/ui/Alignment;)V
+HSPLandroidx/compose/foundation/layout/BoxKt;->boxMeasurePolicy(Landroidx/compose/ui/Alignment;Z)Landroidx/compose/ui/layout/MeasurePolicy;
+HSPLandroidx/compose/foundation/layout/BoxKt;->getBoxChildData(Landroidx/compose/ui/layout/Measurable;)Landroidx/compose/foundation/layout/BoxChildData;
+HSPLandroidx/compose/foundation/layout/BoxKt;->getMatchesParentSize(Landroidx/compose/ui/layout/Measurable;)Z
+HSPLandroidx/compose/foundation/layout/BoxKt;->placeInBox(Landroidx/compose/ui/layout/Placeable$PlacementScope;Landroidx/compose/ui/layout/Placeable;Landroidx/compose/ui/layout/Measurable;Landroidx/compose/ui/unit/LayoutDirection;IILandroidx/compose/ui/Alignment;)V
+HSPLandroidx/compose/foundation/layout/BoxKt;->rememberBoxMeasurePolicy(Landroidx/compose/ui/Alignment;ZLandroidx/compose/runtime/Composer;I)Landroidx/compose/ui/layout/MeasurePolicy;
+HSPLandroidx/compose/foundation/layout/BoxScopeInstance;-><clinit>()V
+HSPLandroidx/compose/foundation/layout/BoxScopeInstance;-><init>()V
+HSPLandroidx/compose/foundation/layout/BoxWithConstraintsKt$BoxWithConstraints$1$1$measurables$1;-><init>(Lkotlin/jvm/functions/Function3;Landroidx/compose/foundation/layout/BoxWithConstraintsScopeImpl;I)V
+HSPLandroidx/compose/foundation/layout/BoxWithConstraintsKt$BoxWithConstraints$1$1$measurables$1;->invoke(Landroidx/compose/runtime/Composer;I)V
+HSPLandroidx/compose/foundation/layout/BoxWithConstraintsKt$BoxWithConstraints$1$1$measurables$1;->invoke(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;
+HSPLandroidx/compose/foundation/layout/BoxWithConstraintsKt$BoxWithConstraints$1$1;-><init>(Landroidx/compose/ui/layout/MeasurePolicy;Lkotlin/jvm/functions/Function3;I)V
+HSPLandroidx/compose/foundation/layout/BoxWithConstraintsKt$BoxWithConstraints$1$1;->invoke(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;
+HSPLandroidx/compose/foundation/layout/BoxWithConstraintsKt$BoxWithConstraints$1$1;->invoke-0kLqBqw(Landroidx/compose/ui/layout/SubcomposeMeasureScope;J)Landroidx/compose/ui/layout/MeasureResult;
+HSPLandroidx/compose/foundation/layout/BoxWithConstraintsKt;->BoxWithConstraints(Landroidx/compose/ui/Modifier;Landroidx/compose/ui/Alignment;ZLkotlin/jvm/functions/Function3;Landroidx/compose/runtime/Composer;II)V
+HSPLandroidx/compose/foundation/layout/BoxWithConstraintsScopeImpl;-><init>(Landroidx/compose/ui/unit/Density;J)V
+HSPLandroidx/compose/foundation/layout/BoxWithConstraintsScopeImpl;-><init>(Landroidx/compose/ui/unit/Density;JLkotlin/jvm/internal/DefaultConstructorMarker;)V
+HSPLandroidx/compose/foundation/layout/BoxWithConstraintsScopeImpl;->equals(Ljava/lang/Object;)Z
+HSPLandroidx/compose/foundation/layout/BoxWithConstraintsScopeImpl;->getConstraints-msEJaDk()J
+HSPLandroidx/compose/foundation/layout/ColumnKt$DefaultColumnMeasurePolicy$1;-><clinit>()V
+HSPLandroidx/compose/foundation/layout/ColumnKt$DefaultColumnMeasurePolicy$1;-><init>()V
+HSPLandroidx/compose/foundation/layout/ColumnKt$DefaultColumnMeasurePolicy$1;->invoke(I[ILandroidx/compose/ui/unit/LayoutDirection;Landroidx/compose/ui/unit/Density;[I)V
+HSPLandroidx/compose/foundation/layout/ColumnKt$DefaultColumnMeasurePolicy$1;->invoke(Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;
+HSPLandroidx/compose/foundation/layout/ColumnKt;-><clinit>()V
+HSPLandroidx/compose/foundation/layout/ColumnKt;->columnMeasurePolicy(Landroidx/compose/foundation/layout/Arrangement$Vertical;Landroidx/compose/ui/Alignment$Horizontal;Landroidx/compose/runtime/Composer;I)Landroidx/compose/ui/layout/MeasurePolicy;
+HSPLandroidx/compose/foundation/layout/ColumnScopeInstance;-><clinit>()V
+HSPLandroidx/compose/foundation/layout/ColumnScopeInstance;-><init>()V
+HSPLandroidx/compose/foundation/layout/ColumnScopeInstance;->align(Landroidx/compose/ui/Modifier;Landroidx/compose/ui/Alignment$Horizontal;)Landroidx/compose/ui/Modifier;
+HSPLandroidx/compose/foundation/layout/CrossAxisAlignment$CenterCrossAxisAlignment;-><clinit>()V
+HSPLandroidx/compose/foundation/layout/CrossAxisAlignment$CenterCrossAxisAlignment;-><init>()V
+HSPLandroidx/compose/foundation/layout/CrossAxisAlignment$Companion;-><init>()V
+HSPLandroidx/compose/foundation/layout/CrossAxisAlignment$Companion;-><init>(Lkotlin/jvm/internal/DefaultConstructorMarker;)V
+HSPLandroidx/compose/foundation/layout/CrossAxisAlignment$Companion;->horizontal$foundation_layout_release(Landroidx/compose/ui/Alignment$Horizontal;)Landroidx/compose/foundation/layout/CrossAxisAlignment;
+HSPLandroidx/compose/foundation/layout/CrossAxisAlignment$Companion;->vertical$foundation_layout_release(Landroidx/compose/ui/Alignment$Vertical;)Landroidx/compose/foundation/layout/CrossAxisAlignment;
+HSPLandroidx/compose/foundation/layout/CrossAxisAlignment$EndCrossAxisAlignment;-><clinit>()V
+HSPLandroidx/compose/foundation/layout/CrossAxisAlignment$EndCrossAxisAlignment;-><init>()V
+HSPLandroidx/compose/foundation/layout/CrossAxisAlignment$HorizontalCrossAxisAlignment;-><init>(Landroidx/compose/ui/Alignment$Horizontal;)V
+HSPLandroidx/compose/foundation/layout/CrossAxisAlignment$HorizontalCrossAxisAlignment;->align$foundation_layout_release(ILandroidx/compose/ui/unit/LayoutDirection;Landroidx/compose/ui/layout/Placeable;I)I
+HSPLandroidx/compose/foundation/layout/CrossAxisAlignment$StartCrossAxisAlignment;-><clinit>()V
+HSPLandroidx/compose/foundation/layout/CrossAxisAlignment$StartCrossAxisAlignment;-><init>()V
+HSPLandroidx/compose/foundation/layout/CrossAxisAlignment$VerticalCrossAxisAlignment;-><init>(Landroidx/compose/ui/Alignment$Vertical;)V
+HSPLandroidx/compose/foundation/layout/CrossAxisAlignment$VerticalCrossAxisAlignment;->align$foundation_layout_release(ILandroidx/compose/ui/unit/LayoutDirection;Landroidx/compose/ui/layout/Placeable;I)I
+HSPLandroidx/compose/foundation/layout/CrossAxisAlignment;-><clinit>()V
+HSPLandroidx/compose/foundation/layout/CrossAxisAlignment;-><init>()V
+HSPLandroidx/compose/foundation/layout/CrossAxisAlignment;-><init>(Lkotlin/jvm/internal/DefaultConstructorMarker;)V
+HSPLandroidx/compose/foundation/layout/CrossAxisAlignment;->isRelative$foundation_layout_release()Z
+HSPLandroidx/compose/foundation/layout/Direction;->$values()[Landroidx/compose/foundation/layout/Direction;
+HSPLandroidx/compose/foundation/layout/Direction;-><clinit>()V
+HSPLandroidx/compose/foundation/layout/Direction;-><init>(Ljava/lang/String;I)V
+HSPLandroidx/compose/foundation/layout/FillModifier$measure$1;-><init>(Landroidx/compose/ui/layout/Placeable;)V
+HSPLandroidx/compose/foundation/layout/FillModifier$measure$1;->invoke(Landroidx/compose/ui/layout/Placeable$PlacementScope;)V
+HSPLandroidx/compose/foundation/layout/FillModifier$measure$1;->invoke(Ljava/lang/Object;)Ljava/lang/Object;
+HSPLandroidx/compose/foundation/layout/FillModifier;-><init>(Landroidx/compose/foundation/layout/Direction;FLkotlin/jvm/functions/Function1;)V
+HSPLandroidx/compose/foundation/layout/FillModifier;->equals(Ljava/lang/Object;)Z
+HSPLandroidx/compose/foundation/layout/FillModifier;->measure-3p2s80s(Landroidx/compose/ui/layout/MeasureScope;Landroidx/compose/ui/layout/Measurable;J)Landroidx/compose/ui/layout/MeasureResult;
+HSPLandroidx/compose/foundation/layout/HorizontalAlignModifier;-><init>(Landroidx/compose/ui/Alignment$Horizontal;Lkotlin/jvm/functions/Function1;)V
+HSPLandroidx/compose/foundation/layout/HorizontalAlignModifier;->equals(Ljava/lang/Object;)Z
+HSPLandroidx/compose/foundation/layout/HorizontalAlignModifier;->modifyParentData(Landroidx/compose/ui/unit/Density;Ljava/lang/Object;)Landroidx/compose/foundation/layout/RowColumnParentData;
+HSPLandroidx/compose/foundation/layout/HorizontalAlignModifier;->modifyParentData(Landroidx/compose/ui/unit/Density;Ljava/lang/Object;)Ljava/lang/Object;
+HSPLandroidx/compose/foundation/layout/LayoutOrientation;->$values()[Landroidx/compose/foundation/layout/LayoutOrientation;
+HSPLandroidx/compose/foundation/layout/LayoutOrientation;-><clinit>()V
+HSPLandroidx/compose/foundation/layout/LayoutOrientation;-><init>(Ljava/lang/String;I)V
+HSPLandroidx/compose/foundation/layout/OffsetKt;->offset(Landroidx/compose/ui/Modifier;Lkotlin/jvm/functions/Function1;)Landroidx/compose/ui/Modifier;
+HSPLandroidx/compose/foundation/layout/OffsetPxModifier$measure$1;-><init>(Landroidx/compose/foundation/layout/OffsetPxModifier;Landroidx/compose/ui/layout/MeasureScope;Landroidx/compose/ui/layout/Placeable;)V
+HSPLandroidx/compose/foundation/layout/OffsetPxModifier$measure$1;->invoke(Landroidx/compose/ui/layout/Placeable$PlacementScope;)V
+HSPLandroidx/compose/foundation/layout/OffsetPxModifier$measure$1;->invoke(Ljava/lang/Object;)Ljava/lang/Object;
+HSPLandroidx/compose/foundation/layout/OffsetPxModifier;-><init>(Lkotlin/jvm/functions/Function1;ZLkotlin/jvm/functions/Function1;)V
+HSPLandroidx/compose/foundation/layout/OffsetPxModifier;->equals(Ljava/lang/Object;)Z
+HSPLandroidx/compose/foundation/layout/OffsetPxModifier;->getOffset()Lkotlin/jvm/functions/Function1;
+HSPLandroidx/compose/foundation/layout/OffsetPxModifier;->getRtlAware()Z
+HSPLandroidx/compose/foundation/layout/OffsetPxModifier;->measure-3p2s80s(Landroidx/compose/ui/layout/MeasureScope;Landroidx/compose/ui/layout/Measurable;J)Landroidx/compose/ui/layout/MeasureResult;
+HSPLandroidx/compose/foundation/layout/OrientationIndependentConstraints;-><init>(IIII)V
+HSPLandroidx/compose/foundation/layout/OrientationIndependentConstraints;-><init>(JLandroidx/compose/foundation/layout/LayoutOrientation;)V
+HSPLandroidx/compose/foundation/layout/OrientationIndependentConstraints;-><init>(JLandroidx/compose/foundation/layout/LayoutOrientation;Lkotlin/jvm/internal/DefaultConstructorMarker;)V
+HSPLandroidx/compose/foundation/layout/OrientationIndependentConstraints;->copy$default(Landroidx/compose/foundation/layout/OrientationIndependentConstraints;IIIIILjava/lang/Object;)Landroidx/compose/foundation/layout/OrientationIndependentConstraints;
+HSPLandroidx/compose/foundation/layout/OrientationIndependentConstraints;->copy(IIII)Landroidx/compose/foundation/layout/OrientationIndependentConstraints;
+HSPLandroidx/compose/foundation/layout/OrientationIndependentConstraints;->getCrossAxisMax()I
+HSPLandroidx/compose/foundation/layout/OrientationIndependentConstraints;->getCrossAxisMin()I
+HSPLandroidx/compose/foundation/layout/OrientationIndependentConstraints;->getMainAxisMax()I
+HSPLandroidx/compose/foundation/layout/OrientationIndependentConstraints;->getMainAxisMin()I
+HSPLandroidx/compose/foundation/layout/OrientationIndependentConstraints;->toBoxConstraints-OenEA2s(Landroidx/compose/foundation/layout/LayoutOrientation;)J
+HSPLandroidx/compose/foundation/layout/PaddingKt;->PaddingValues-YgX7TsA$default(FFILjava/lang/Object;)Landroidx/compose/foundation/layout/PaddingValues;
+HSPLandroidx/compose/foundation/layout/PaddingKt;->PaddingValues-YgX7TsA(FF)Landroidx/compose/foundation/layout/PaddingValues;
+HSPLandroidx/compose/foundation/layout/PaddingKt;->PaddingValues-a9UjIt4(FFFF)Landroidx/compose/foundation/layout/PaddingValues;
+HSPLandroidx/compose/foundation/layout/PaddingKt;->padding(Landroidx/compose/ui/Modifier;Landroidx/compose/foundation/layout/PaddingValues;)Landroidx/compose/ui/Modifier;
+HSPLandroidx/compose/foundation/layout/PaddingKt;->padding-3ABfNKs(Landroidx/compose/ui/Modifier;F)Landroidx/compose/ui/Modifier;
+HSPLandroidx/compose/foundation/layout/PaddingKt;->padding-VpY3zN4$default(Landroidx/compose/ui/Modifier;FFILjava/lang/Object;)Landroidx/compose/ui/Modifier;
+HSPLandroidx/compose/foundation/layout/PaddingKt;->padding-VpY3zN4(Landroidx/compose/ui/Modifier;FF)Landroidx/compose/ui/Modifier;
+HSPLandroidx/compose/foundation/layout/PaddingKt;->padding-qDBjuR0$default(Landroidx/compose/ui/Modifier;FFFFILjava/lang/Object;)Landroidx/compose/ui/Modifier;
+HSPLandroidx/compose/foundation/layout/PaddingKt;->padding-qDBjuR0(Landroidx/compose/ui/Modifier;FFFF)Landroidx/compose/ui/Modifier;
+HSPLandroidx/compose/foundation/layout/PaddingModifier$measure$1;-><init>(Landroidx/compose/foundation/layout/PaddingModifier;Landroidx/compose/ui/layout/Placeable;Landroidx/compose/ui/layout/MeasureScope;)V
+HSPLandroidx/compose/foundation/layout/PaddingModifier$measure$1;->invoke(Landroidx/compose/ui/layout/Placeable$PlacementScope;)V
+HSPLandroidx/compose/foundation/layout/PaddingModifier$measure$1;->invoke(Ljava/lang/Object;)Ljava/lang/Object;
+HSPLandroidx/compose/foundation/layout/PaddingModifier;-><init>(FFFFZLkotlin/jvm/functions/Function1;)V
+HSPLandroidx/compose/foundation/layout/PaddingModifier;-><init>(FFFFZLkotlin/jvm/functions/Function1;Lkotlin/jvm/internal/DefaultConstructorMarker;)V
+HSPLandroidx/compose/foundation/layout/PaddingModifier;->equals(Ljava/lang/Object;)Z
+HSPLandroidx/compose/foundation/layout/PaddingModifier;->getRtlAware()Z
+HSPLandroidx/compose/foundation/layout/PaddingModifier;->getStart-D9Ej5fM()F
+HSPLandroidx/compose/foundation/layout/PaddingModifier;->getTop-D9Ej5fM()F
+HSPLandroidx/compose/foundation/layout/PaddingModifier;->measure-3p2s80s(Landroidx/compose/ui/layout/MeasureScope;Landroidx/compose/ui/layout/Measurable;J)Landroidx/compose/ui/layout/MeasureResult;
+HSPLandroidx/compose/foundation/layout/PaddingValuesImpl;-><init>(FFFF)V
+HSPLandroidx/compose/foundation/layout/PaddingValuesImpl;-><init>(FFFFLkotlin/jvm/internal/DefaultConstructorMarker;)V
+HSPLandroidx/compose/foundation/layout/PaddingValuesImpl;->calculateBottomPadding-D9Ej5fM()F
+HSPLandroidx/compose/foundation/layout/PaddingValuesImpl;->calculateLeftPadding-u2uoSUM(Landroidx/compose/ui/unit/LayoutDirection;)F
+HSPLandroidx/compose/foundation/layout/PaddingValuesImpl;->calculateRightPadding-u2uoSUM(Landroidx/compose/ui/unit/LayoutDirection;)F
+HSPLandroidx/compose/foundation/layout/PaddingValuesImpl;->calculateTopPadding-D9Ej5fM()F
+HSPLandroidx/compose/foundation/layout/PaddingValuesImpl;->equals(Ljava/lang/Object;)Z
+HSPLandroidx/compose/foundation/layout/PaddingValuesModifier$measure$2;-><init>(Landroidx/compose/ui/layout/Placeable;Landroidx/compose/ui/layout/MeasureScope;Landroidx/compose/foundation/layout/PaddingValuesModifier;)V
+HSPLandroidx/compose/foundation/layout/PaddingValuesModifier$measure$2;->invoke(Landroidx/compose/ui/layout/Placeable$PlacementScope;)V
+HSPLandroidx/compose/foundation/layout/PaddingValuesModifier$measure$2;->invoke(Ljava/lang/Object;)Ljava/lang/Object;
+HSPLandroidx/compose/foundation/layout/PaddingValuesModifier;-><init>(Landroidx/compose/foundation/layout/PaddingValues;Lkotlin/jvm/functions/Function1;)V
+HSPLandroidx/compose/foundation/layout/PaddingValuesModifier;->equals(Ljava/lang/Object;)Z
+HSPLandroidx/compose/foundation/layout/PaddingValuesModifier;->getPaddingValues()Landroidx/compose/foundation/layout/PaddingValues;
+HSPLandroidx/compose/foundation/layout/PaddingValuesModifier;->measure-3p2s80s(Landroidx/compose/ui/layout/MeasureScope;Landroidx/compose/ui/layout/Measurable;J)Landroidx/compose/ui/layout/MeasureResult;
+HSPLandroidx/compose/foundation/layout/RowColumnImplKt$rowColumnMeasurePolicy$1$measure$4;-><init>(Ljava/util/List;[Landroidx/compose/ui/layout/Placeable;Lkotlin/jvm/functions/Function5;ILandroidx/compose/ui/layout/MeasureScope;[ILandroidx/compose/foundation/layout/LayoutOrientation;[Landroidx/compose/foundation/layout/RowColumnParentData;Landroidx/compose/foundation/layout/CrossAxisAlignment;ILkotlin/jvm/internal/Ref$IntRef;)V
+HSPLandroidx/compose/foundation/layout/RowColumnImplKt$rowColumnMeasurePolicy$1$measure$4;->invoke(Landroidx/compose/ui/layout/Placeable$PlacementScope;)V
+HSPLandroidx/compose/foundation/layout/RowColumnImplKt$rowColumnMeasurePolicy$1$measure$4;->invoke(Ljava/lang/Object;)Ljava/lang/Object;
+HSPLandroidx/compose/foundation/layout/RowColumnImplKt$rowColumnMeasurePolicy$1;-><init>(Landroidx/compose/foundation/layout/LayoutOrientation;FLandroidx/compose/foundation/layout/SizeMode;Lkotlin/jvm/functions/Function5;Landroidx/compose/foundation/layout/CrossAxisAlignment;)V
+HSPLandroidx/compose/foundation/layout/RowColumnImplKt$rowColumnMeasurePolicy$1;->measure-3p2s80s(Landroidx/compose/ui/layout/MeasureScope;Ljava/util/List;J)Landroidx/compose/ui/layout/MeasureResult;
+HSPLandroidx/compose/foundation/layout/RowColumnImplKt;->access$getCrossAxisAlignment(Landroidx/compose/foundation/layout/RowColumnParentData;)Landroidx/compose/foundation/layout/CrossAxisAlignment;
+HSPLandroidx/compose/foundation/layout/RowColumnImplKt;->access$getData(Landroidx/compose/ui/layout/IntrinsicMeasurable;)Landroidx/compose/foundation/layout/RowColumnParentData;
+HSPLandroidx/compose/foundation/layout/RowColumnImplKt;->access$getWeight(Landroidx/compose/foundation/layout/RowColumnParentData;)F
+HSPLandroidx/compose/foundation/layout/RowColumnImplKt;->access$isRelative(Landroidx/compose/foundation/layout/RowColumnParentData;)Z
+HSPLandroidx/compose/foundation/layout/RowColumnImplKt;->access$rowColumnMeasurePolicy_TDGSqEk$crossAxisSize(Landroidx/compose/ui/layout/Placeable;Landroidx/compose/foundation/layout/LayoutOrientation;)I
+HSPLandroidx/compose/foundation/layout/RowColumnImplKt;->access$rowColumnMeasurePolicy_TDGSqEk$mainAxisSize(Landroidx/compose/ui/layout/Placeable;Landroidx/compose/foundation/layout/LayoutOrientation;)I
+HSPLandroidx/compose/foundation/layout/RowColumnImplKt;->getCrossAxisAlignment(Landroidx/compose/foundation/layout/RowColumnParentData;)Landroidx/compose/foundation/layout/CrossAxisAlignment;
+HSPLandroidx/compose/foundation/layout/RowColumnImplKt;->getData(Landroidx/compose/ui/layout/IntrinsicMeasurable;)Landroidx/compose/foundation/layout/RowColumnParentData;
+HSPLandroidx/compose/foundation/layout/RowColumnImplKt;->getWeight(Landroidx/compose/foundation/layout/RowColumnParentData;)F
+HSPLandroidx/compose/foundation/layout/RowColumnImplKt;->isRelative(Landroidx/compose/foundation/layout/RowColumnParentData;)Z
+HSPLandroidx/compose/foundation/layout/RowColumnImplKt;->rowColumnMeasurePolicy-TDGSqEk(Landroidx/compose/foundation/layout/LayoutOrientation;Lkotlin/jvm/functions/Function5;FLandroidx/compose/foundation/layout/SizeMode;Landroidx/compose/foundation/layout/CrossAxisAlignment;)Landroidx/compose/ui/layout/MeasurePolicy;
+HSPLandroidx/compose/foundation/layout/RowColumnImplKt;->rowColumnMeasurePolicy_TDGSqEk$crossAxisSize(Landroidx/compose/ui/layout/Placeable;Landroidx/compose/foundation/layout/LayoutOrientation;)I
+HSPLandroidx/compose/foundation/layout/RowColumnImplKt;->rowColumnMeasurePolicy_TDGSqEk$mainAxisSize(Landroidx/compose/ui/layout/Placeable;Landroidx/compose/foundation/layout/LayoutOrientation;)I
+HSPLandroidx/compose/foundation/layout/RowColumnParentData;-><init>(FZLandroidx/compose/foundation/layout/CrossAxisAlignment;)V
+HSPLandroidx/compose/foundation/layout/RowColumnParentData;-><init>(FZLandroidx/compose/foundation/layout/CrossAxisAlignment;ILkotlin/jvm/internal/DefaultConstructorMarker;)V
+HSPLandroidx/compose/foundation/layout/RowColumnParentData;->getCrossAxisAlignment()Landroidx/compose/foundation/layout/CrossAxisAlignment;
+HSPLandroidx/compose/foundation/layout/RowColumnParentData;->getWeight()F
+HSPLandroidx/compose/foundation/layout/RowColumnParentData;->setCrossAxisAlignment(Landroidx/compose/foundation/layout/CrossAxisAlignment;)V
+HSPLandroidx/compose/foundation/layout/RowKt$DefaultRowMeasurePolicy$1;-><clinit>()V
+HSPLandroidx/compose/foundation/layout/RowKt$DefaultRowMeasurePolicy$1;-><init>()V
+HSPLandroidx/compose/foundation/layout/RowKt$rowMeasurePolicy$1$1;-><init>(Landroidx/compose/foundation/layout/Arrangement$Horizontal;)V
+HSPLandroidx/compose/foundation/layout/RowKt$rowMeasurePolicy$1$1;->invoke(I[ILandroidx/compose/ui/unit/LayoutDirection;Landroidx/compose/ui/unit/Density;[I)V
+HSPLandroidx/compose/foundation/layout/RowKt$rowMeasurePolicy$1$1;->invoke(Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;
+HSPLandroidx/compose/foundation/layout/RowKt;-><clinit>()V
+HSPLandroidx/compose/foundation/layout/RowKt;->rowMeasurePolicy(Landroidx/compose/foundation/layout/Arrangement$Horizontal;Landroidx/compose/ui/Alignment$Vertical;Landroidx/compose/runtime/Composer;I)Landroidx/compose/ui/layout/MeasurePolicy;
+HSPLandroidx/compose/foundation/layout/RowScopeInstance;-><clinit>()V
+HSPLandroidx/compose/foundation/layout/RowScopeInstance;-><init>()V
+HSPLandroidx/compose/foundation/layout/SizeKt$createFillHeightModifier$1;-><init>(F)V
+HSPLandroidx/compose/foundation/layout/SizeKt$createFillSizeModifier$1;-><init>(F)V
+HSPLandroidx/compose/foundation/layout/SizeKt$createFillWidthModifier$1;-><init>(F)V
+HSPLandroidx/compose/foundation/layout/SizeKt$createWrapContentHeightModifier$1;-><init>(Landroidx/compose/ui/Alignment$Vertical;)V
+HSPLandroidx/compose/foundation/layout/SizeKt$createWrapContentHeightModifier$2;-><init>(Landroidx/compose/ui/Alignment$Vertical;Z)V
+HSPLandroidx/compose/foundation/layout/SizeKt$createWrapContentSizeModifier$1;-><init>(Landroidx/compose/ui/Alignment;)V
+HSPLandroidx/compose/foundation/layout/SizeKt$createWrapContentSizeModifier$2;-><init>(Landroidx/compose/ui/Alignment;Z)V
+HSPLandroidx/compose/foundation/layout/SizeKt$createWrapContentWidthModifier$1;-><init>(Landroidx/compose/ui/Alignment$Horizontal;)V
+HSPLandroidx/compose/foundation/layout/SizeKt$createWrapContentWidthModifier$2;-><init>(Landroidx/compose/ui/Alignment$Horizontal;Z)V
+HSPLandroidx/compose/foundation/layout/SizeKt;-><clinit>()V
+HSPLandroidx/compose/foundation/layout/SizeKt;->createFillHeightModifier(F)Landroidx/compose/foundation/layout/FillModifier;
+HSPLandroidx/compose/foundation/layout/SizeKt;->createFillSizeModifier(F)Landroidx/compose/foundation/layout/FillModifier;
+HSPLandroidx/compose/foundation/layout/SizeKt;->createFillWidthModifier(F)Landroidx/compose/foundation/layout/FillModifier;
+HSPLandroidx/compose/foundation/layout/SizeKt;->createWrapContentHeightModifier(Landroidx/compose/ui/Alignment$Vertical;Z)Landroidx/compose/foundation/layout/WrapContentModifier;
+HSPLandroidx/compose/foundation/layout/SizeKt;->createWrapContentSizeModifier(Landroidx/compose/ui/Alignment;Z)Landroidx/compose/foundation/layout/WrapContentModifier;
+HSPLandroidx/compose/foundation/layout/SizeKt;->createWrapContentWidthModifier(Landroidx/compose/ui/Alignment$Horizontal;Z)Landroidx/compose/foundation/layout/WrapContentModifier;
+HSPLandroidx/compose/foundation/layout/SizeKt;->defaultMinSize-VpY3zN4$default(Landroidx/compose/ui/Modifier;FFILjava/lang/Object;)Landroidx/compose/ui/Modifier;
+HSPLandroidx/compose/foundation/layout/SizeKt;->defaultMinSize-VpY3zN4(Landroidx/compose/ui/Modifier;FF)Landroidx/compose/ui/Modifier;
+HSPLandroidx/compose/foundation/layout/SizeKt;->fillMaxSize$default(Landroidx/compose/ui/Modifier;FILjava/lang/Object;)Landroidx/compose/ui/Modifier;
+HSPLandroidx/compose/foundation/layout/SizeKt;->fillMaxSize(Landroidx/compose/ui/Modifier;F)Landroidx/compose/ui/Modifier;
+HSPLandroidx/compose/foundation/layout/SizeKt;->fillMaxWidth$default(Landroidx/compose/ui/Modifier;FILjava/lang/Object;)Landroidx/compose/ui/Modifier;
+HSPLandroidx/compose/foundation/layout/SizeKt;->fillMaxWidth(Landroidx/compose/ui/Modifier;F)Landroidx/compose/ui/Modifier;
+HSPLandroidx/compose/foundation/layout/SizeKt;->height-3ABfNKs(Landroidx/compose/ui/Modifier;F)Landroidx/compose/ui/Modifier;
+HSPLandroidx/compose/foundation/layout/SizeKt;->size-3ABfNKs(Landroidx/compose/ui/Modifier;F)Landroidx/compose/ui/Modifier;
+HSPLandroidx/compose/foundation/layout/SizeKt;->width-3ABfNKs(Landroidx/compose/ui/Modifier;F)Landroidx/compose/ui/Modifier;
+HSPLandroidx/compose/foundation/layout/SizeMode;->$values()[Landroidx/compose/foundation/layout/SizeMode;
+HSPLandroidx/compose/foundation/layout/SizeMode;-><clinit>()V
+HSPLandroidx/compose/foundation/layout/SizeMode;-><init>(Ljava/lang/String;I)V
+HSPLandroidx/compose/foundation/layout/SizeModifier$measure$1;-><init>(Landroidx/compose/ui/layout/Placeable;)V
+HSPLandroidx/compose/foundation/layout/SizeModifier$measure$1;->invoke(Landroidx/compose/ui/layout/Placeable$PlacementScope;)V
+HSPLandroidx/compose/foundation/layout/SizeModifier$measure$1;->invoke(Ljava/lang/Object;)Ljava/lang/Object;
+HSPLandroidx/compose/foundation/layout/SizeModifier;-><init>(FFFFZLkotlin/jvm/functions/Function1;)V
+HSPLandroidx/compose/foundation/layout/SizeModifier;-><init>(FFFFZLkotlin/jvm/functions/Function1;ILkotlin/jvm/internal/DefaultConstructorMarker;)V
+HSPLandroidx/compose/foundation/layout/SizeModifier;-><init>(FFFFZLkotlin/jvm/functions/Function1;Lkotlin/jvm/internal/DefaultConstructorMarker;)V
+HSPLandroidx/compose/foundation/layout/SizeModifier;->equals(Ljava/lang/Object;)Z
+HSPLandroidx/compose/foundation/layout/SizeModifier;->getTargetConstraints-OenEA2s(Landroidx/compose/ui/unit/Density;)J
+HSPLandroidx/compose/foundation/layout/SizeModifier;->measure-3p2s80s(Landroidx/compose/ui/layout/MeasureScope;Landroidx/compose/ui/layout/Measurable;J)Landroidx/compose/ui/layout/MeasureResult;
+HSPLandroidx/compose/foundation/layout/SpacerKt;->Spacer(Landroidx/compose/ui/Modifier;Landroidx/compose/runtime/Composer;I)V
+HSPLandroidx/compose/foundation/layout/SpacerMeasurePolicy$measure$1$1;-><clinit>()V
+HSPLandroidx/compose/foundation/layout/SpacerMeasurePolicy$measure$1$1;-><init>()V
+HSPLandroidx/compose/foundation/layout/SpacerMeasurePolicy$measure$1$1;->invoke(Landroidx/compose/ui/layout/Placeable$PlacementScope;)V
+HSPLandroidx/compose/foundation/layout/SpacerMeasurePolicy$measure$1$1;->invoke(Ljava/lang/Object;)Ljava/lang/Object;
+HSPLandroidx/compose/foundation/layout/SpacerMeasurePolicy;-><clinit>()V
+HSPLandroidx/compose/foundation/layout/SpacerMeasurePolicy;-><init>()V
+HSPLandroidx/compose/foundation/layout/SpacerMeasurePolicy;->measure-3p2s80s(Landroidx/compose/ui/layout/MeasureScope;Ljava/util/List;J)Landroidx/compose/ui/layout/MeasureResult;
+HSPLandroidx/compose/foundation/layout/UnspecifiedConstraintsModifier$measure$1;-><init>(Landroidx/compose/ui/layout/Placeable;)V
+HSPLandroidx/compose/foundation/layout/UnspecifiedConstraintsModifier$measure$1;->invoke(Landroidx/compose/ui/layout/Placeable$PlacementScope;)V
+HSPLandroidx/compose/foundation/layout/UnspecifiedConstraintsModifier$measure$1;->invoke(Ljava/lang/Object;)Ljava/lang/Object;
+HSPLandroidx/compose/foundation/layout/UnspecifiedConstraintsModifier;-><init>(FFLkotlin/jvm/functions/Function1;)V
+HSPLandroidx/compose/foundation/layout/UnspecifiedConstraintsModifier;-><init>(FFLkotlin/jvm/functions/Function1;Lkotlin/jvm/internal/DefaultConstructorMarker;)V
+HSPLandroidx/compose/foundation/layout/UnspecifiedConstraintsModifier;->equals(Ljava/lang/Object;)Z
+HSPLandroidx/compose/foundation/layout/UnspecifiedConstraintsModifier;->measure-3p2s80s(Landroidx/compose/ui/layout/MeasureScope;Landroidx/compose/ui/layout/Measurable;J)Landroidx/compose/ui/layout/MeasureResult;
+HSPLandroidx/compose/foundation/layout/WrapContentModifier;-><init>(Landroidx/compose/foundation/layout/Direction;ZLkotlin/jvm/functions/Function2;Ljava/lang/Object;Lkotlin/jvm/functions/Function1;)V
+HSPLandroidx/compose/foundation/lazy/layout/PinnableParentKt$ModifierLocalPinnableParent$1;-><clinit>()V
+HSPLandroidx/compose/foundation/lazy/layout/PinnableParentKt$ModifierLocalPinnableParent$1;-><init>()V
+HSPLandroidx/compose/foundation/lazy/layout/PinnableParentKt$ModifierLocalPinnableParent$1;->invoke()Landroidx/compose/foundation/lazy/layout/PinnableParent;
+HSPLandroidx/compose/foundation/lazy/layout/PinnableParentKt$ModifierLocalPinnableParent$1;->invoke()Ljava/lang/Object;
+HSPLandroidx/compose/foundation/lazy/layout/PinnableParentKt;-><clinit>()V
+HSPLandroidx/compose/foundation/lazy/layout/PinnableParentKt;->getModifierLocalPinnableParent()Landroidx/compose/ui/modifier/ProvidableModifierLocal;
+HSPLandroidx/compose/foundation/relocation/AndroidBringIntoViewParent;-><init>(Landroid/view/View;)V
+HSPLandroidx/compose/foundation/relocation/BringIntoViewChildModifier;-><init>(Landroidx/compose/foundation/relocation/BringIntoViewParent;)V
+HSPLandroidx/compose/foundation/relocation/BringIntoViewChildModifier;->onModifierLocalsUpdated(Landroidx/compose/ui/modifier/ModifierLocalReadScope;)V
+HSPLandroidx/compose/foundation/relocation/BringIntoViewChildModifier;->onPlaced(Landroidx/compose/ui/layout/LayoutCoordinates;)V
+HSPLandroidx/compose/foundation/relocation/BringIntoViewKt$ModifierLocalBringIntoViewParent$1;-><clinit>()V
+HSPLandroidx/compose/foundation/relocation/BringIntoViewKt$ModifierLocalBringIntoViewParent$1;-><init>()V
+HSPLandroidx/compose/foundation/relocation/BringIntoViewKt$ModifierLocalBringIntoViewParent$1;->invoke()Landroidx/compose/foundation/relocation/BringIntoViewParent;
+HSPLandroidx/compose/foundation/relocation/BringIntoViewKt$ModifierLocalBringIntoViewParent$1;->invoke()Ljava/lang/Object;
+HSPLandroidx/compose/foundation/relocation/BringIntoViewKt;-><clinit>()V
+HSPLandroidx/compose/foundation/relocation/BringIntoViewKt;->getModifierLocalBringIntoViewParent()Landroidx/compose/ui/modifier/ProvidableModifierLocal;
+HSPLandroidx/compose/foundation/relocation/BringIntoViewRequesterImpl;-><init>()V
+HSPLandroidx/compose/foundation/relocation/BringIntoViewRequesterImpl;->getModifiers()Landroidx/compose/runtime/collection/MutableVector;
+HSPLandroidx/compose/foundation/relocation/BringIntoViewRequesterKt$bringIntoViewRequester$2$1$invoke$$inlined$onDispose$1;-><init>(Landroidx/compose/foundation/relocation/BringIntoViewRequester;Landroidx/compose/foundation/relocation/BringIntoViewRequesterModifier;)V
+HSPLandroidx/compose/foundation/relocation/BringIntoViewRequesterKt$bringIntoViewRequester$2$1;-><init>(Landroidx/compose/foundation/relocation/BringIntoViewRequester;Landroidx/compose/foundation/relocation/BringIntoViewRequesterModifier;)V
+HSPLandroidx/compose/foundation/relocation/BringIntoViewRequesterKt$bringIntoViewRequester$2$1;->invoke(Landroidx/compose/runtime/DisposableEffectScope;)Landroidx/compose/runtime/DisposableEffectResult;
+HSPLandroidx/compose/foundation/relocation/BringIntoViewRequesterKt$bringIntoViewRequester$2$1;->invoke(Ljava/lang/Object;)Ljava/lang/Object;
+HSPLandroidx/compose/foundation/relocation/BringIntoViewRequesterKt$bringIntoViewRequester$2;-><init>(Landroidx/compose/foundation/relocation/BringIntoViewRequester;)V
+HSPLandroidx/compose/foundation/relocation/BringIntoViewRequesterKt$bringIntoViewRequester$2;->invoke(Landroidx/compose/ui/Modifier;Landroidx/compose/runtime/Composer;I)Landroidx/compose/ui/Modifier;
+HSPLandroidx/compose/foundation/relocation/BringIntoViewRequesterKt$bringIntoViewRequester$2;->invoke(Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;
+HSPLandroidx/compose/foundation/relocation/BringIntoViewRequesterKt;->BringIntoViewRequester()Landroidx/compose/foundation/relocation/BringIntoViewRequester;
+HSPLandroidx/compose/foundation/relocation/BringIntoViewRequesterKt;->bringIntoViewRequester(Landroidx/compose/ui/Modifier;Landroidx/compose/foundation/relocation/BringIntoViewRequester;)Landroidx/compose/ui/Modifier;
+HSPLandroidx/compose/foundation/relocation/BringIntoViewRequesterModifier;-><init>(Landroidx/compose/foundation/relocation/BringIntoViewParent;)V
+HSPLandroidx/compose/foundation/relocation/BringIntoViewResponder_androidKt;->rememberDefaultBringIntoViewParent(Landroidx/compose/runtime/Composer;I)Landroidx/compose/foundation/relocation/BringIntoViewParent;
+HSPLandroidx/compose/foundation/shape/CornerBasedShape;-><clinit>()V
+HSPLandroidx/compose/foundation/shape/CornerBasedShape;-><init>(Landroidx/compose/foundation/shape/CornerSize;Landroidx/compose/foundation/shape/CornerSize;Landroidx/compose/foundation/shape/CornerSize;Landroidx/compose/foundation/shape/CornerSize;)V
+HSPLandroidx/compose/foundation/shape/CornerBasedShape;->createOutline-Pq9zytI(JLandroidx/compose/ui/unit/LayoutDirection;Landroidx/compose/ui/unit/Density;)Landroidx/compose/ui/graphics/Outline;
+HSPLandroidx/compose/foundation/shape/CornerSizeKt$ZeroCornerSize$1;-><init>()V
+HSPLandroidx/compose/foundation/shape/CornerSizeKt;-><clinit>()V
+HSPLandroidx/compose/foundation/shape/CornerSizeKt;->CornerSize(I)Landroidx/compose/foundation/shape/CornerSize;
+HSPLandroidx/compose/foundation/shape/CornerSizeKt;->CornerSize-0680j_4(F)Landroidx/compose/foundation/shape/CornerSize;
+HSPLandroidx/compose/foundation/shape/DpCornerSize;-><init>(F)V
+HSPLandroidx/compose/foundation/shape/DpCornerSize;-><init>(FLkotlin/jvm/internal/DefaultConstructorMarker;)V
+HSPLandroidx/compose/foundation/shape/DpCornerSize;->toPx-TmRCtEA(JLandroidx/compose/ui/unit/Density;)F
+HSPLandroidx/compose/foundation/shape/PercentCornerSize;-><init>(F)V
+HSPLandroidx/compose/foundation/shape/PercentCornerSize;->toPx-TmRCtEA(JLandroidx/compose/ui/unit/Density;)F
+HSPLandroidx/compose/foundation/shape/RoundedCornerShape;-><clinit>()V
+HSPLandroidx/compose/foundation/shape/RoundedCornerShape;-><init>(Landroidx/compose/foundation/shape/CornerSize;Landroidx/compose/foundation/shape/CornerSize;Landroidx/compose/foundation/shape/CornerSize;Landroidx/compose/foundation/shape/CornerSize;)V
+HSPLandroidx/compose/foundation/shape/RoundedCornerShape;->createOutline-LjSzlW0(JFFFFLandroidx/compose/ui/unit/LayoutDirection;)Landroidx/compose/ui/graphics/Outline;
+HSPLandroidx/compose/foundation/shape/RoundedCornerShape;->equals(Ljava/lang/Object;)Z
+HSPLandroidx/compose/foundation/shape/RoundedCornerShapeKt;-><clinit>()V
+HSPLandroidx/compose/foundation/shape/RoundedCornerShapeKt;->RoundedCornerShape(I)Landroidx/compose/foundation/shape/RoundedCornerShape;
+HSPLandroidx/compose/foundation/shape/RoundedCornerShapeKt;->RoundedCornerShape(Landroidx/compose/foundation/shape/CornerSize;)Landroidx/compose/foundation/shape/RoundedCornerShape;
+HSPLandroidx/compose/foundation/shape/RoundedCornerShapeKt;->RoundedCornerShape-0680j_4(F)Landroidx/compose/foundation/shape/RoundedCornerShape;
+HSPLandroidx/compose/foundation/shape/RoundedCornerShapeKt;->RoundedCornerShape-a9UjIt4(FFFF)Landroidx/compose/foundation/shape/RoundedCornerShape;
+HSPLandroidx/compose/foundation/shape/RoundedCornerShapeKt;->getCircleShape()Landroidx/compose/foundation/shape/RoundedCornerShape;
+HSPLandroidx/compose/foundation/text/BasicTextKt$BasicText-4YKlhWE$$inlined$Layout$1;-><init>(Lkotlin/jvm/functions/Function0;)V
+HSPLandroidx/compose/foundation/text/BasicTextKt$BasicText-4YKlhWE$$inlined$Layout$1;->invoke()Ljava/lang/Object;
+HSPLandroidx/compose/foundation/text/BasicTextKt;->BasicText-4YKlhWE(Ljava/lang/String;Landroidx/compose/ui/Modifier;Landroidx/compose/ui/text/TextStyle;Lkotlin/jvm/functions/Function1;IZIILandroidx/compose/runtime/Composer;II)V
+HSPLandroidx/compose/foundation/text/CoreTextKt;-><clinit>()V
+HSPLandroidx/compose/foundation/text/CoreTextKt;->updateTextDelegate-x_uQXYA(Landroidx/compose/foundation/text/TextDelegate;Ljava/lang/String;Landroidx/compose/ui/text/TextStyle;Landroidx/compose/ui/unit/Density;Landroidx/compose/ui/text/font/FontFamily$Resolver;ZIII)Landroidx/compose/foundation/text/TextDelegate;
+HSPLandroidx/compose/foundation/text/HeightInLinesModifierKt$heightInLines$2;-><init>(IILandroidx/compose/ui/text/TextStyle;)V
+HSPLandroidx/compose/foundation/text/HeightInLinesModifierKt$heightInLines$2;->invoke(Landroidx/compose/ui/Modifier;Landroidx/compose/runtime/Composer;I)Landroidx/compose/ui/Modifier;
+HSPLandroidx/compose/foundation/text/HeightInLinesModifierKt$heightInLines$2;->invoke(Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;
+HSPLandroidx/compose/foundation/text/HeightInLinesModifierKt;->heightInLines$default(Landroidx/compose/ui/Modifier;Landroidx/compose/ui/text/TextStyle;IIILjava/lang/Object;)Landroidx/compose/ui/Modifier;
+HSPLandroidx/compose/foundation/text/HeightInLinesModifierKt;->heightInLines(Landroidx/compose/ui/Modifier;Landroidx/compose/ui/text/TextStyle;II)Landroidx/compose/ui/Modifier;
+HSPLandroidx/compose/foundation/text/HeightInLinesModifierKt;->validateMinMaxLines(II)V
+HSPLandroidx/compose/foundation/text/TextController$coreModifiers$1;-><init>(Landroidx/compose/foundation/text/TextController;)V
+HSPLandroidx/compose/foundation/text/TextController$coreModifiers$1;->invoke(Landroidx/compose/ui/layout/LayoutCoordinates;)V
+HSPLandroidx/compose/foundation/text/TextController$coreModifiers$1;->invoke(Ljava/lang/Object;)Ljava/lang/Object;
+HSPLandroidx/compose/foundation/text/TextController$createSemanticsModifierFor$1$1;-><init>(Landroidx/compose/foundation/text/TextController;)V
+HSPLandroidx/compose/foundation/text/TextController$createSemanticsModifierFor$1;-><init>(Landroidx/compose/ui/text/AnnotatedString;Landroidx/compose/foundation/text/TextController;)V
+HSPLandroidx/compose/foundation/text/TextController$createSemanticsModifierFor$1;->invoke(Landroidx/compose/ui/semantics/SemanticsPropertyReceiver;)V
+HSPLandroidx/compose/foundation/text/TextController$createSemanticsModifierFor$1;->invoke(Ljava/lang/Object;)Ljava/lang/Object;
+HSPLandroidx/compose/foundation/text/TextController$drawTextAndSelectionBehind$1;-><init>(Landroidx/compose/foundation/text/TextController;)V
+HSPLandroidx/compose/foundation/text/TextController$drawTextAndSelectionBehind$1;->invoke(Landroidx/compose/ui/graphics/drawscope/DrawScope;)V
+HSPLandroidx/compose/foundation/text/TextController$drawTextAndSelectionBehind$1;->invoke(Ljava/lang/Object;)Ljava/lang/Object;
+HSPLandroidx/compose/foundation/text/TextController$measurePolicy$1$measure$2;-><init>(Ljava/util/List;)V
+HSPLandroidx/compose/foundation/text/TextController$measurePolicy$1$measure$2;->invoke(Landroidx/compose/ui/layout/Placeable$PlacementScope;)V
+HSPLandroidx/compose/foundation/text/TextController$measurePolicy$1$measure$2;->invoke(Ljava/lang/Object;)Ljava/lang/Object;
+HSPLandroidx/compose/foundation/text/TextController$measurePolicy$1;-><init>(Landroidx/compose/foundation/text/TextController;)V
+HSPLandroidx/compose/foundation/text/TextController$measurePolicy$1;->measure-3p2s80s(Landroidx/compose/ui/layout/MeasureScope;Ljava/util/List;J)Landroidx/compose/ui/layout/MeasureResult;
+HSPLandroidx/compose/foundation/text/TextController;-><init>(Landroidx/compose/foundation/text/TextState;)V
+HSPLandroidx/compose/foundation/text/TextController;->access$getSelectionRegistrar$p(Landroidx/compose/foundation/text/TextController;)Landroidx/compose/foundation/text/selection/SelectionRegistrar;
+HSPLandroidx/compose/foundation/text/TextController;->createSemanticsModifierFor(Landroidx/compose/ui/text/AnnotatedString;)Landroidx/compose/ui/Modifier;
+HSPLandroidx/compose/foundation/text/TextController;->drawTextAndSelectionBehind(Landroidx/compose/ui/Modifier;)Landroidx/compose/ui/Modifier;
+HSPLandroidx/compose/foundation/text/TextController;->getMeasurePolicy()Landroidx/compose/ui/layout/MeasurePolicy;
+HSPLandroidx/compose/foundation/text/TextController;->getModifiers()Landroidx/compose/ui/Modifier;
+HSPLandroidx/compose/foundation/text/TextController;->getState()Landroidx/compose/foundation/text/TextState;
+HSPLandroidx/compose/foundation/text/TextController;->onRemembered()V
+HSPLandroidx/compose/foundation/text/TextController;->setTextDelegate(Landroidx/compose/foundation/text/TextDelegate;)V
+HSPLandroidx/compose/foundation/text/TextController;->update(Landroidx/compose/foundation/text/selection/SelectionRegistrar;)V
+HSPLandroidx/compose/foundation/text/TextDelegate$Companion;-><init>()V
+HSPLandroidx/compose/foundation/text/TextDelegate$Companion;-><init>(Lkotlin/jvm/internal/DefaultConstructorMarker;)V
+HSPLandroidx/compose/foundation/text/TextDelegate$Companion;->paint(Landroidx/compose/ui/graphics/Canvas;Landroidx/compose/ui/text/TextLayoutResult;)V
+HSPLandroidx/compose/foundation/text/TextDelegate;-><clinit>()V
+HSPLandroidx/compose/foundation/text/TextDelegate;-><init>(Landroidx/compose/ui/text/AnnotatedString;Landroidx/compose/ui/text/TextStyle;IIZILandroidx/compose/ui/unit/Density;Landroidx/compose/ui/text/font/FontFamily$Resolver;Ljava/util/List;)V
+HSPLandroidx/compose/foundation/text/TextDelegate;-><init>(Landroidx/compose/ui/text/AnnotatedString;Landroidx/compose/ui/text/TextStyle;IIZILandroidx/compose/ui/unit/Density;Landroidx/compose/ui/text/font/FontFamily$Resolver;Ljava/util/List;ILkotlin/jvm/internal/DefaultConstructorMarker;)V
+HSPLandroidx/compose/foundation/text/TextDelegate;-><init>(Landroidx/compose/ui/text/AnnotatedString;Landroidx/compose/ui/text/TextStyle;IIZILandroidx/compose/ui/unit/Density;Landroidx/compose/ui/text/font/FontFamily$Resolver;Ljava/util/List;Lkotlin/jvm/internal/DefaultConstructorMarker;)V
+HSPLandroidx/compose/foundation/text/TextDelegate;->getDensity()Landroidx/compose/ui/unit/Density;
+HSPLandroidx/compose/foundation/text/TextDelegate;->getFontFamilyResolver()Landroidx/compose/ui/text/font/FontFamily$Resolver;
+HSPLandroidx/compose/foundation/text/TextDelegate;->getMaxIntrinsicWidth()I
+HSPLandroidx/compose/foundation/text/TextDelegate;->getMaxLines()I
+HSPLandroidx/compose/foundation/text/TextDelegate;->getMinLines()I
+HSPLandroidx/compose/foundation/text/TextDelegate;->getNonNullIntrinsics()Landroidx/compose/ui/text/MultiParagraphIntrinsics;
+HSPLandroidx/compose/foundation/text/TextDelegate;->getOverflow-gIe3tQ8()I
+HSPLandroidx/compose/foundation/text/TextDelegate;->getSoftWrap()Z
+HSPLandroidx/compose/foundation/text/TextDelegate;->getStyle()Landroidx/compose/ui/text/TextStyle;
+HSPLandroidx/compose/foundation/text/TextDelegate;->getText()Landroidx/compose/ui/text/AnnotatedString;
+HSPLandroidx/compose/foundation/text/TextDelegate;->layout-NN6Ew-U(JLandroidx/compose/ui/unit/LayoutDirection;Landroidx/compose/ui/text/TextLayoutResult;)Landroidx/compose/ui/text/TextLayoutResult;
+HSPLandroidx/compose/foundation/text/TextDelegate;->layoutIntrinsics(Landroidx/compose/ui/unit/LayoutDirection;)V
+HSPLandroidx/compose/foundation/text/TextDelegate;->layoutText-K40F9xA(JLandroidx/compose/ui/unit/LayoutDirection;)Landroidx/compose/ui/text/MultiParagraph;
+HSPLandroidx/compose/foundation/text/TextDelegateKt;->ceilToIntPx(F)I
+HSPLandroidx/compose/foundation/text/TextLayoutHelperKt;->canReuse-7_7YC6M(Landroidx/compose/ui/text/TextLayoutResult;Landroidx/compose/ui/text/AnnotatedString;Landroidx/compose/ui/text/TextStyle;Ljava/util/List;IZILandroidx/compose/ui/unit/Density;Landroidx/compose/ui/unit/LayoutDirection;Landroidx/compose/ui/text/font/FontFamily$Resolver;J)Z
+HSPLandroidx/compose/foundation/text/TextState$onTextLayout$1;-><clinit>()V
+HSPLandroidx/compose/foundation/text/TextState$onTextLayout$1;-><init>()V
+HSPLandroidx/compose/foundation/text/TextState;-><init>(Landroidx/compose/foundation/text/TextDelegate;J)V
+HSPLandroidx/compose/foundation/text/TextState;->getDrawScopeInvalidation()Lkotlin/Unit;
+HSPLandroidx/compose/foundation/text/TextState;->getLayoutInvalidation()Lkotlin/Unit;
+HSPLandroidx/compose/foundation/text/TextState;->getLayoutResult()Landroidx/compose/ui/text/TextLayoutResult;
+HSPLandroidx/compose/foundation/text/TextState;->getOnTextLayout()Lkotlin/jvm/functions/Function1;
+HSPLandroidx/compose/foundation/text/TextState;->getSelectableId()J
+HSPLandroidx/compose/foundation/text/TextState;->getTextDelegate()Landroidx/compose/foundation/text/TextDelegate;
+HSPLandroidx/compose/foundation/text/TextState;->setDrawScopeInvalidation(Lkotlin/Unit;)V
+HSPLandroidx/compose/foundation/text/TextState;->setLayoutCoordinates(Landroidx/compose/ui/layout/LayoutCoordinates;)V
+HSPLandroidx/compose/foundation/text/TextState;->setLayoutResult(Landroidx/compose/ui/text/TextLayoutResult;)V
+HSPLandroidx/compose/foundation/text/TextState;->setOnTextLayout(Lkotlin/jvm/functions/Function1;)V
+HSPLandroidx/compose/foundation/text/selection/SelectionRegistrarKt$LocalSelectionRegistrar$1;-><clinit>()V
+HSPLandroidx/compose/foundation/text/selection/SelectionRegistrarKt$LocalSelectionRegistrar$1;-><init>()V
+HSPLandroidx/compose/foundation/text/selection/SelectionRegistrarKt$LocalSelectionRegistrar$1;->invoke()Landroidx/compose/foundation/text/selection/SelectionRegistrar;
+HSPLandroidx/compose/foundation/text/selection/SelectionRegistrarKt$LocalSelectionRegistrar$1;->invoke()Ljava/lang/Object;
+HSPLandroidx/compose/foundation/text/selection/SelectionRegistrarKt;-><clinit>()V
+HSPLandroidx/compose/foundation/text/selection/SelectionRegistrarKt;->getLocalSelectionRegistrar()Landroidx/compose/runtime/ProvidableCompositionLocal;
+HSPLandroidx/compose/foundation/text/selection/SelectionRegistrarKt;->hasSelection(Landroidx/compose/foundation/text/selection/SelectionRegistrar;J)Z
+HSPLandroidx/compose/foundation/text/selection/TextSelectionColors;-><init>(JJ)V
+HSPLandroidx/compose/foundation/text/selection/TextSelectionColors;-><init>(JJLkotlin/jvm/internal/DefaultConstructorMarker;)V
+HSPLandroidx/compose/foundation/text/selection/TextSelectionColors;->equals(Ljava/lang/Object;)Z
+HSPLandroidx/compose/foundation/text/selection/TextSelectionColorsKt$LocalTextSelectionColors$1;-><clinit>()V
+HSPLandroidx/compose/foundation/text/selection/TextSelectionColorsKt$LocalTextSelectionColors$1;-><init>()V
+HSPLandroidx/compose/foundation/text/selection/TextSelectionColorsKt;-><clinit>()V
+HSPLandroidx/compose/foundation/text/selection/TextSelectionColorsKt;->getLocalTextSelectionColors()Landroidx/compose/runtime/ProvidableCompositionLocal;
+HSPLandroidx/compose/material/ripple/AndroidRippleIndicationInstance$onInvalidateRipple$1;-><init>(Landroidx/compose/material/ripple/AndroidRippleIndicationInstance;)V
+HSPLandroidx/compose/material/ripple/AndroidRippleIndicationInstance;-><init>(ZFLandroidx/compose/runtime/State;Landroidx/compose/runtime/State;Landroidx/compose/material/ripple/RippleContainer;)V
+HSPLandroidx/compose/material/ripple/AndroidRippleIndicationInstance;-><init>(ZFLandroidx/compose/runtime/State;Landroidx/compose/runtime/State;Landroidx/compose/material/ripple/RippleContainer;Lkotlin/jvm/internal/DefaultConstructorMarker;)V
+HSPLandroidx/compose/material/ripple/AndroidRippleIndicationInstance;->drawIndication(Landroidx/compose/ui/graphics/drawscope/ContentDrawScope;)V
+HSPLandroidx/compose/material/ripple/AndroidRippleIndicationInstance;->getInvalidateTick()Z
+HSPLandroidx/compose/material/ripple/AndroidRippleIndicationInstance;->getRippleHostView()Landroidx/compose/material/ripple/RippleHostView;
+HSPLandroidx/compose/material/ripple/AndroidRippleIndicationInstance;->onRemembered()V
+HSPLandroidx/compose/material/ripple/PlatformRipple;-><init>(ZFLandroidx/compose/runtime/State;)V
+HSPLandroidx/compose/material/ripple/PlatformRipple;-><init>(ZFLandroidx/compose/runtime/State;Lkotlin/jvm/internal/DefaultConstructorMarker;)V
+HSPLandroidx/compose/material/ripple/PlatformRipple;->findNearestViewGroup(Landroidx/compose/runtime/Composer;I)Landroid/view/ViewGroup;
+HSPLandroidx/compose/material/ripple/PlatformRipple;->rememberUpdatedRippleInstance-942rkJo(Landroidx/compose/foundation/interaction/InteractionSource;ZFLandroidx/compose/runtime/State;Landroidx/compose/runtime/State;Landroidx/compose/runtime/Composer;I)Landroidx/compose/material/ripple/RippleIndicationInstance;
+HSPLandroidx/compose/material/ripple/Ripple$rememberUpdatedInstance$1$1;-><init>(Landroidx/compose/material/ripple/RippleIndicationInstance;Lkotlinx/coroutines/CoroutineScope;)V
+HSPLandroidx/compose/material/ripple/Ripple$rememberUpdatedInstance$1;-><init>(Landroidx/compose/foundation/interaction/InteractionSource;Landroidx/compose/material/ripple/RippleIndicationInstance;Lkotlin/coroutines/Continuation;)V
+HSPLandroidx/compose/material/ripple/Ripple$rememberUpdatedInstance$1;->create(Ljava/lang/Object;Lkotlin/coroutines/Continuation;)Lkotlin/coroutines/Continuation;
+HSPLandroidx/compose/material/ripple/Ripple$rememberUpdatedInstance$1;->invokeSuspend(Ljava/lang/Object;)Ljava/lang/Object;
+HSPLandroidx/compose/material/ripple/Ripple;-><init>(ZFLandroidx/compose/runtime/State;)V
+HSPLandroidx/compose/material/ripple/Ripple;-><init>(ZFLandroidx/compose/runtime/State;Lkotlin/jvm/internal/DefaultConstructorMarker;)V
+HSPLandroidx/compose/material/ripple/Ripple;->equals(Ljava/lang/Object;)Z
+HSPLandroidx/compose/material/ripple/Ripple;->rememberUpdatedInstance(Landroidx/compose/foundation/interaction/InteractionSource;Landroidx/compose/runtime/Composer;I)Landroidx/compose/foundation/IndicationInstance;
+HSPLandroidx/compose/material/ripple/RippleAlpha;-><init>(FFFF)V
+HSPLandroidx/compose/material/ripple/RippleAlpha;->equals(Ljava/lang/Object;)Z
+HSPLandroidx/compose/material/ripple/RippleAlpha;->getPressedAlpha()F
+HSPLandroidx/compose/material/ripple/RippleAnimationKt;-><clinit>()V
+HSPLandroidx/compose/material/ripple/RippleAnimationKt;->getRippleEndRadius-cSwnlzA(Landroidx/compose/ui/unit/Density;ZJ)F
+HSPLandroidx/compose/material/ripple/RippleContainer;-><init>(Landroid/content/Context;)V
+HSPLandroidx/compose/material/ripple/RippleHostMap;-><init>()V
+HSPLandroidx/compose/material/ripple/RippleHostView$Companion;-><init>()V
+HSPLandroidx/compose/material/ripple/RippleHostView$Companion;-><init>(Lkotlin/jvm/internal/DefaultConstructorMarker;)V
+HSPLandroidx/compose/material/ripple/RippleHostView;-><clinit>()V
+HSPLandroidx/compose/material/ripple/RippleHostView;-><init>(Landroid/content/Context;)V
+HSPLandroidx/compose/material/ripple/RippleHostView;->refreshDrawableState()V
+HSPLandroidx/compose/material/ripple/RippleIndicationInstance;-><init>(ZLandroidx/compose/runtime/State;)V
+HSPLandroidx/compose/material/ripple/RippleIndicationInstance;->drawStateLayer-H2RKhps(Landroidx/compose/ui/graphics/drawscope/DrawScope;FJ)V
+HSPLandroidx/compose/material/ripple/RippleKt;-><clinit>()V
+HSPLandroidx/compose/material/ripple/RippleKt;->rememberRipple-9IZ8Weo(ZFJLandroidx/compose/runtime/Composer;II)Landroidx/compose/foundation/Indication;
+HSPLandroidx/compose/material/ripple/RippleThemeKt$LocalRippleTheme$1;-><clinit>()V
+HSPLandroidx/compose/material/ripple/RippleThemeKt$LocalRippleTheme$1;-><init>()V
+HSPLandroidx/compose/material/ripple/RippleThemeKt;-><clinit>()V
+HSPLandroidx/compose/material/ripple/RippleThemeKt;->getLocalRippleTheme()Landroidx/compose/runtime/ProvidableCompositionLocal;
+HSPLandroidx/compose/material/ripple/StateLayer;-><init>(ZLandroidx/compose/runtime/State;)V
+HSPLandroidx/compose/material/ripple/StateLayer;->drawStateLayer-H2RKhps(Landroidx/compose/ui/graphics/drawscope/DrawScope;FJ)V
+HSPLandroidx/compose/material3/ButtonColors;-><init>(JJJJ)V
+HSPLandroidx/compose/material3/ButtonColors;-><init>(JJJJLkotlin/jvm/internal/DefaultConstructorMarker;)V
+HSPLandroidx/compose/material3/ButtonColors;->containerColor$material3_release(ZLandroidx/compose/runtime/Composer;I)Landroidx/compose/runtime/State;
+HSPLandroidx/compose/material3/ButtonColors;->contentColor$material3_release(ZLandroidx/compose/runtime/Composer;I)Landroidx/compose/runtime/State;
+HSPLandroidx/compose/material3/ButtonColors;->equals(Ljava/lang/Object;)Z
+HSPLandroidx/compose/material3/ButtonDefaults;-><clinit>()V
+HSPLandroidx/compose/material3/ButtonDefaults;-><init>()V
+HSPLandroidx/compose/material3/ButtonDefaults;->filledTonalButtonColors-ro_MJ88(JJJJLandroidx/compose/runtime/Composer;II)Landroidx/compose/material3/ButtonColors;
+HSPLandroidx/compose/material3/ButtonDefaults;->filledTonalButtonElevation-R_JCAzs(FFFFFLandroidx/compose/runtime/Composer;II)Landroidx/compose/material3/ButtonElevation;
+HSPLandroidx/compose/material3/ButtonDefaults;->getContentPadding()Landroidx/compose/foundation/layout/PaddingValues;
+HSPLandroidx/compose/material3/ButtonDefaults;->getFilledTonalShape(Landroidx/compose/runtime/Composer;I)Landroidx/compose/ui/graphics/Shape;
+HSPLandroidx/compose/material3/ButtonDefaults;->getMinHeight-D9Ej5fM()F
+HSPLandroidx/compose/material3/ButtonDefaults;->getMinWidth-D9Ej5fM()F
+HSPLandroidx/compose/material3/ButtonDefaults;->getTextButtonContentPadding()Landroidx/compose/foundation/layout/PaddingValues;
+HSPLandroidx/compose/material3/ButtonDefaults;->getTextShape(Landroidx/compose/runtime/Composer;I)Landroidx/compose/ui/graphics/Shape;
+HSPLandroidx/compose/material3/ButtonDefaults;->textButtonColors-ro_MJ88(JJJJLandroidx/compose/runtime/Composer;II)Landroidx/compose/material3/ButtonColors;
+HSPLandroidx/compose/material3/ButtonElevation$animateElevation$1$1$1;-><init>(Landroidx/compose/runtime/snapshots/SnapshotStateList;)V
+HSPLandroidx/compose/material3/ButtonElevation$animateElevation$1$1;-><init>(Landroidx/compose/foundation/interaction/InteractionSource;Landroidx/compose/runtime/snapshots/SnapshotStateList;Lkotlin/coroutines/Continuation;)V
+HSPLandroidx/compose/material3/ButtonElevation$animateElevation$1$1;->create(Ljava/lang/Object;Lkotlin/coroutines/Continuation;)Lkotlin/coroutines/Continuation;
+HSPLandroidx/compose/material3/ButtonElevation$animateElevation$1$1;->invokeSuspend(Ljava/lang/Object;)Ljava/lang/Object;
+HSPLandroidx/compose/material3/ButtonElevation$animateElevation$3;-><init>(Landroidx/compose/animation/core/Animatable;Landroidx/compose/material3/ButtonElevation;FLandroidx/compose/foundation/interaction/Interaction;Lkotlin/coroutines/Continuation;)V
+HSPLandroidx/compose/material3/ButtonElevation$animateElevation$3;->create(Ljava/lang/Object;Lkotlin/coroutines/Continuation;)Lkotlin/coroutines/Continuation;
+HSPLandroidx/compose/material3/ButtonElevation$animateElevation$3;->invokeSuspend(Ljava/lang/Object;)Ljava/lang/Object;
+HSPLandroidx/compose/material3/ButtonElevation;-><init>(FFFFF)V
+HSPLandroidx/compose/material3/ButtonElevation;-><init>(FFFFFLkotlin/jvm/internal/DefaultConstructorMarker;)V
+HSPLandroidx/compose/material3/ButtonElevation;->access$getPressedElevation$p(Landroidx/compose/material3/ButtonElevation;)F
+HSPLandroidx/compose/material3/ButtonElevation;->animateElevation(ZLandroidx/compose/foundation/interaction/InteractionSource;Landroidx/compose/runtime/Composer;I)Landroidx/compose/runtime/State;
+HSPLandroidx/compose/material3/ButtonElevation;->equals(Ljava/lang/Object;)Z
+HSPLandroidx/compose/material3/ButtonElevation;->shadowElevation$material3_release(ZLandroidx/compose/foundation/interaction/InteractionSource;Landroidx/compose/runtime/Composer;I)Landroidx/compose/runtime/State;
+HSPLandroidx/compose/material3/ButtonElevation;->tonalElevation$material3_release(ZLandroidx/compose/foundation/interaction/InteractionSource;Landroidx/compose/runtime/Composer;I)Landroidx/compose/runtime/State;
+HSPLandroidx/compose/material3/ButtonKt$Button$2$1$1;-><init>(Landroidx/compose/foundation/layout/PaddingValues;Lkotlin/jvm/functions/Function3;I)V
+HSPLandroidx/compose/material3/ButtonKt$Button$2$1$1;->invoke(Landroidx/compose/runtime/Composer;I)V
+HSPLandroidx/compose/material3/ButtonKt$Button$2$1$1;->invoke(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;
+HSPLandroidx/compose/material3/ButtonKt$Button$2$1;-><init>(Landroidx/compose/foundation/layout/PaddingValues;Lkotlin/jvm/functions/Function3;I)V
+HSPLandroidx/compose/material3/ButtonKt$Button$2$1;->invoke(Landroidx/compose/runtime/Composer;I)V
+HSPLandroidx/compose/material3/ButtonKt$Button$2$1;->invoke(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;
+HSPLandroidx/compose/material3/ButtonKt$Button$2;-><init>(JLandroidx/compose/foundation/layout/PaddingValues;Lkotlin/jvm/functions/Function3;I)V
+HSPLandroidx/compose/material3/ButtonKt$Button$2;->invoke(Landroidx/compose/runtime/Composer;I)V
+HSPLandroidx/compose/material3/ButtonKt$Button$2;->invoke(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;
+HSPLandroidx/compose/material3/ButtonKt$Button$3;-><init>(Lkotlin/jvm/functions/Function0;Landroidx/compose/ui/Modifier;ZLandroidx/compose/ui/graphics/Shape;Landroidx/compose/material3/ButtonColors;Landroidx/compose/material3/ButtonElevation;Landroidx/compose/foundation/BorderStroke;Landroidx/compose/foundation/layout/PaddingValues;Landroidx/compose/foundation/interaction/MutableInteractionSource;Lkotlin/jvm/functions/Function3;II)V
+HSPLandroidx/compose/material3/ButtonKt;->Button(Lkotlin/jvm/functions/Function0;Landroidx/compose/ui/Modifier;ZLandroidx/compose/ui/graphics/Shape;Landroidx/compose/material3/ButtonColors;Landroidx/compose/material3/ButtonElevation;Landroidx/compose/foundation/BorderStroke;Landroidx/compose/foundation/layout/PaddingValues;Landroidx/compose/foundation/interaction/MutableInteractionSource;Lkotlin/jvm/functions/Function3;Landroidx/compose/runtime/Composer;II)V
+HSPLandroidx/compose/material3/ButtonKt;->FilledTonalButton(Lkotlin/jvm/functions/Function0;Landroidx/compose/ui/Modifier;ZLandroidx/compose/ui/graphics/Shape;Landroidx/compose/material3/ButtonColors;Landroidx/compose/material3/ButtonElevation;Landroidx/compose/foundation/BorderStroke;Landroidx/compose/foundation/layout/PaddingValues;Landroidx/compose/foundation/interaction/MutableInteractionSource;Lkotlin/jvm/functions/Function3;Landroidx/compose/runtime/Composer;II)V
+HSPLandroidx/compose/material3/ButtonKt;->TextButton(Lkotlin/jvm/functions/Function0;Landroidx/compose/ui/Modifier;ZLandroidx/compose/ui/graphics/Shape;Landroidx/compose/material3/ButtonColors;Landroidx/compose/material3/ButtonElevation;Landroidx/compose/foundation/BorderStroke;Landroidx/compose/foundation/layout/PaddingValues;Landroidx/compose/foundation/interaction/MutableInteractionSource;Lkotlin/jvm/functions/Function3;Landroidx/compose/runtime/Composer;II)V
+HSPLandroidx/compose/material3/CardColors;-><init>(JJJJ)V
+HSPLandroidx/compose/material3/CardColors;-><init>(JJJJLkotlin/jvm/internal/DefaultConstructorMarker;)V
+HSPLandroidx/compose/material3/CardColors;->containerColor$material3_release(ZLandroidx/compose/runtime/Composer;I)Landroidx/compose/runtime/State;
+HSPLandroidx/compose/material3/CardColors;->contentColor$material3_release(ZLandroidx/compose/runtime/Composer;I)Landroidx/compose/runtime/State;
+HSPLandroidx/compose/material3/CardColors;->equals(Ljava/lang/Object;)Z
+HSPLandroidx/compose/material3/CardDefaults;-><clinit>()V
+HSPLandroidx/compose/material3/CardDefaults;-><init>()V
+HSPLandroidx/compose/material3/CardDefaults;->cardColors-ro_MJ88(JJJJLandroidx/compose/runtime/Composer;II)Landroidx/compose/material3/CardColors;
+HSPLandroidx/compose/material3/CardDefaults;->cardElevation-aqJV_2Y(FFFFFFLandroidx/compose/runtime/Composer;II)Landroidx/compose/material3/CardElevation;
+HSPLandroidx/compose/material3/CardDefaults;->getShape(Landroidx/compose/runtime/Composer;I)Landroidx/compose/ui/graphics/Shape;
+HSPLandroidx/compose/material3/CardElevation;-><init>(FFFFFF)V
+HSPLandroidx/compose/material3/CardElevation;-><init>(FFFFFFLkotlin/jvm/internal/DefaultConstructorMarker;)V
+HSPLandroidx/compose/material3/CardElevation;->access$getDefaultElevation$p(Landroidx/compose/material3/CardElevation;)F
+HSPLandroidx/compose/material3/CardElevation;->shadowElevation$material3_release(ZLandroidx/compose/foundation/interaction/InteractionSource;Landroidx/compose/runtime/Composer;I)Landroidx/compose/runtime/State;
+HSPLandroidx/compose/material3/CardElevation;->tonalElevation$material3_release(ZLandroidx/compose/foundation/interaction/InteractionSource;Landroidx/compose/runtime/Composer;I)Landroidx/compose/runtime/State;
+HSPLandroidx/compose/material3/CardKt$Card$1;-><init>(Lkotlin/jvm/functions/Function3;I)V
+HSPLandroidx/compose/material3/CardKt$Card$1;->invoke(Landroidx/compose/runtime/Composer;I)V
+HSPLandroidx/compose/material3/CardKt$Card$1;->invoke(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;
+HSPLandroidx/compose/material3/CardKt$Card$2;-><init>(Landroidx/compose/ui/Modifier;Landroidx/compose/ui/graphics/Shape;Landroidx/compose/material3/CardColors;Landroidx/compose/material3/CardElevation;Landroidx/compose/foundation/BorderStroke;Lkotlin/jvm/functions/Function3;II)V
+HSPLandroidx/compose/material3/CardKt;->Card(Landroidx/compose/ui/Modifier;Landroidx/compose/ui/graphics/Shape;Landroidx/compose/material3/CardColors;Landroidx/compose/material3/CardElevation;Landroidx/compose/foundation/BorderStroke;Lkotlin/jvm/functions/Function3;Landroidx/compose/runtime/Composer;II)V
+HSPLandroidx/compose/material3/ChipColors;-><init>(JJJJJJJJ)V
+HSPLandroidx/compose/material3/ChipColors;-><init>(JJJJJJJJLkotlin/jvm/internal/DefaultConstructorMarker;)V
+HSPLandroidx/compose/material3/ChipColors;->containerColor$material3_release(ZLandroidx/compose/runtime/Composer;I)Landroidx/compose/runtime/State;
+HSPLandroidx/compose/material3/ChipColors;->equals(Ljava/lang/Object;)Z
+HSPLandroidx/compose/material3/ChipColors;->labelColor$material3_release(ZLandroidx/compose/runtime/Composer;I)Landroidx/compose/runtime/State;
+HSPLandroidx/compose/material3/ChipColors;->leadingIconContentColor$material3_release(ZLandroidx/compose/runtime/Composer;I)Landroidx/compose/runtime/State;
+HSPLandroidx/compose/material3/ChipColors;->trailingIconContentColor$material3_release(ZLandroidx/compose/runtime/Composer;I)Landroidx/compose/runtime/State;
+HSPLandroidx/compose/material3/ChipElevation$animateElevation$1$1$1;-><init>(Landroidx/compose/runtime/snapshots/SnapshotStateList;)V
+HSPLandroidx/compose/material3/ChipElevation$animateElevation$1$1;-><init>(Landroidx/compose/foundation/interaction/InteractionSource;Landroidx/compose/runtime/snapshots/SnapshotStateList;Lkotlin/coroutines/Continuation;)V
+HSPLandroidx/compose/material3/ChipElevation$animateElevation$1$1;->create(Ljava/lang/Object;Lkotlin/coroutines/Continuation;)Lkotlin/coroutines/Continuation;
+HSPLandroidx/compose/material3/ChipElevation$animateElevation$1$1;->invokeSuspend(Ljava/lang/Object;)Ljava/lang/Object;
+HSPLandroidx/compose/material3/ChipElevation$animateElevation$3;-><init>(Landroidx/compose/animation/core/Animatable;Landroidx/compose/material3/ChipElevation;FLandroidx/compose/foundation/interaction/Interaction;Lkotlin/coroutines/Continuation;)V
+HSPLandroidx/compose/material3/ChipElevation$animateElevation$3;->create(Ljava/lang/Object;Lkotlin/coroutines/Continuation;)Lkotlin/coroutines/Continuation;
+HSPLandroidx/compose/material3/ChipElevation$animateElevation$3;->invokeSuspend(Ljava/lang/Object;)Ljava/lang/Object;
+HSPLandroidx/compose/material3/ChipElevation;-><init>(FFFFFF)V
+HSPLandroidx/compose/material3/ChipElevation;-><init>(FFFFFFLkotlin/jvm/internal/DefaultConstructorMarker;)V
+HSPLandroidx/compose/material3/ChipElevation;->access$getPressedElevation$p(Landroidx/compose/material3/ChipElevation;)F
+HSPLandroidx/compose/material3/ChipElevation;->animateElevation(ZLandroidx/compose/foundation/interaction/InteractionSource;Landroidx/compose/runtime/Composer;I)Landroidx/compose/runtime/State;
+HSPLandroidx/compose/material3/ChipElevation;->equals(Ljava/lang/Object;)Z
+HSPLandroidx/compose/material3/ChipElevation;->shadowElevation$material3_release(ZLandroidx/compose/foundation/interaction/InteractionSource;Landroidx/compose/runtime/Composer;I)Landroidx/compose/runtime/State;
+HSPLandroidx/compose/material3/ChipElevation;->tonalElevation$material3_release(ZLandroidx/compose/foundation/interaction/InteractionSource;Landroidx/compose/runtime/Composer;I)Landroidx/compose/runtime/State;
+HSPLandroidx/compose/material3/ChipKt$Chip$1;-><init>(Lkotlin/jvm/functions/Function2;Landroidx/compose/ui/text/TextStyle;JLkotlin/jvm/functions/Function2;Lkotlin/jvm/functions/Function2;Landroidx/compose/material3/ChipColors;ZIFLandroidx/compose/foundation/layout/PaddingValues;I)V
+HSPLandroidx/compose/material3/ChipKt$Chip$1;->invoke(Landroidx/compose/runtime/Composer;I)V
+HSPLandroidx/compose/material3/ChipKt$Chip$1;->invoke(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;
+HSPLandroidx/compose/material3/ChipKt$Chip$2;-><init>(Landroidx/compose/ui/Modifier;Lkotlin/jvm/functions/Function0;ZLkotlin/jvm/functions/Function2;Landroidx/compose/ui/text/TextStyle;JLkotlin/jvm/functions/Function2;Lkotlin/jvm/functions/Function2;Landroidx/compose/ui/graphics/Shape;Landroidx/compose/material3/ChipColors;Landroidx/compose/material3/ChipElevation;Landroidx/compose/foundation/BorderStroke;FLandroidx/compose/foundation/layout/PaddingValues;Landroidx/compose/foundation/interaction/MutableInteractionSource;II)V
+HSPLandroidx/compose/material3/ChipKt$ChipContent$1;-><init>(FLandroidx/compose/foundation/layout/PaddingValues;Lkotlin/jvm/functions/Function2;ILkotlin/jvm/functions/Function2;JLkotlin/jvm/functions/Function2;Lkotlin/jvm/functions/Function2;J)V
+HSPLandroidx/compose/material3/ChipKt$ChipContent$1;->invoke(Landroidx/compose/runtime/Composer;I)V
+HSPLandroidx/compose/material3/ChipKt$ChipContent$1;->invoke(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;
+HSPLandroidx/compose/material3/ChipKt$SuggestionChip$2;-><init>(Lkotlin/jvm/functions/Function0;Lkotlin/jvm/functions/Function2;Landroidx/compose/ui/Modifier;ZLkotlin/jvm/functions/Function2;Landroidx/compose/ui/graphics/Shape;Landroidx/compose/material3/ChipColors;Landroidx/compose/material3/ChipElevation;Landroidx/compose/material3/ChipBorder;Landroidx/compose/foundation/interaction/MutableInteractionSource;II)V
+HSPLandroidx/compose/material3/ChipKt;-><clinit>()V
+HSPLandroidx/compose/material3/ChipKt;->Chip-nkUnTEs(Landroidx/compose/ui/Modifier;Lkotlin/jvm/functions/Function0;ZLkotlin/jvm/functions/Function2;Landroidx/compose/ui/text/TextStyle;JLkotlin/jvm/functions/Function2;Lkotlin/jvm/functions/Function2;Landroidx/compose/ui/graphics/Shape;Landroidx/compose/material3/ChipColors;Landroidx/compose/material3/ChipElevation;Landroidx/compose/foundation/BorderStroke;FLandroidx/compose/foundation/layout/PaddingValues;Landroidx/compose/foundation/interaction/MutableInteractionSource;Landroidx/compose/runtime/Composer;II)V
+HSPLandroidx/compose/material3/ChipKt;->ChipContent-fe0OD_I(Lkotlin/jvm/functions/Function2;Landroidx/compose/ui/text/TextStyle;JLkotlin/jvm/functions/Function2;Lkotlin/jvm/functions/Function2;Lkotlin/jvm/functions/Function2;JJFLandroidx/compose/foundation/layout/PaddingValues;Landroidx/compose/runtime/Composer;I)V
+HSPLandroidx/compose/material3/ChipKt;->SuggestionChip(Lkotlin/jvm/functions/Function0;Lkotlin/jvm/functions/Function2;Landroidx/compose/ui/Modifier;ZLkotlin/jvm/functions/Function2;Landroidx/compose/ui/graphics/Shape;Landroidx/compose/material3/ChipColors;Landroidx/compose/material3/ChipElevation;Landroidx/compose/material3/ChipBorder;Landroidx/compose/foundation/interaction/MutableInteractionSource;Landroidx/compose/runtime/Composer;II)V
+HSPLandroidx/compose/material3/ChipKt;->access$ChipContent-fe0OD_I(Lkotlin/jvm/functions/Function2;Landroidx/compose/ui/text/TextStyle;JLkotlin/jvm/functions/Function2;Lkotlin/jvm/functions/Function2;Lkotlin/jvm/functions/Function2;JJFLandroidx/compose/foundation/layout/PaddingValues;Landroidx/compose/runtime/Composer;I)V
+HSPLandroidx/compose/material3/ChipKt;->access$getHorizontalElementsPadding$p()F
+HSPLandroidx/compose/material3/ColorResourceHelper;-><clinit>()V
+HSPLandroidx/compose/material3/ColorResourceHelper;-><init>()V
+HSPLandroidx/compose/material3/ColorResourceHelper;->getColor-WaAFU9c(Landroid/content/Context;I)J
+HSPLandroidx/compose/material3/ColorScheme;-><init>(JJJJJJJJJJJJJJJJJJJJJJJJJJJJJ)V
+HSPLandroidx/compose/material3/ColorScheme;-><init>(JJJJJJJJJJJJJJJJJJJJJJJJJJJJJLkotlin/jvm/internal/DefaultConstructorMarker;)V
+HSPLandroidx/compose/material3/ColorScheme;->copy-G1PFc-w$default(Landroidx/compose/material3/ColorScheme;JJJJJJJJJJJJJJJJJJJJJJJJJJJJJILjava/lang/Object;)Landroidx/compose/material3/ColorScheme;
+HSPLandroidx/compose/material3/ColorScheme;->copy-G1PFc-w(JJJJJJJJJJJJJJJJJJJJJJJJJJJJJ)Landroidx/compose/material3/ColorScheme;
+HSPLandroidx/compose/material3/ColorScheme;->getBackground-0d7_KjU()J
+HSPLandroidx/compose/material3/ColorScheme;->getError-0d7_KjU()J
+HSPLandroidx/compose/material3/ColorScheme;->getErrorContainer-0d7_KjU()J
+HSPLandroidx/compose/material3/ColorScheme;->getInverseOnSurface-0d7_KjU()J
+HSPLandroidx/compose/material3/ColorScheme;->getInversePrimary-0d7_KjU()J
+HSPLandroidx/compose/material3/ColorScheme;->getInverseSurface-0d7_KjU()J
+HSPLandroidx/compose/material3/ColorScheme;->getOnBackground-0d7_KjU()J
+HSPLandroidx/compose/material3/ColorScheme;->getOnError-0d7_KjU()J
+HSPLandroidx/compose/material3/ColorScheme;->getOnErrorContainer-0d7_KjU()J
+HSPLandroidx/compose/material3/ColorScheme;->getOnPrimary-0d7_KjU()J
+HSPLandroidx/compose/material3/ColorScheme;->getOnPrimaryContainer-0d7_KjU()J
+HSPLandroidx/compose/material3/ColorScheme;->getOnSecondary-0d7_KjU()J
+HSPLandroidx/compose/material3/ColorScheme;->getOnSecondaryContainer-0d7_KjU()J
+HSPLandroidx/compose/material3/ColorScheme;->getOnSurface-0d7_KjU()J
+HSPLandroidx/compose/material3/ColorScheme;->getOnSurfaceVariant-0d7_KjU()J
+HSPLandroidx/compose/material3/ColorScheme;->getOnTertiary-0d7_KjU()J
+HSPLandroidx/compose/material3/ColorScheme;->getOnTertiaryContainer-0d7_KjU()J
+HSPLandroidx/compose/material3/ColorScheme;->getOutline-0d7_KjU()J
+HSPLandroidx/compose/material3/ColorScheme;->getOutlineVariant-0d7_KjU()J
+HSPLandroidx/compose/material3/ColorScheme;->getPrimary-0d7_KjU()J
+HSPLandroidx/compose/material3/ColorScheme;->getPrimaryContainer-0d7_KjU()J
+HSPLandroidx/compose/material3/ColorScheme;->getScrim-0d7_KjU()J
+HSPLandroidx/compose/material3/ColorScheme;->getSecondary-0d7_KjU()J
+HSPLandroidx/compose/material3/ColorScheme;->getSecondaryContainer-0d7_KjU()J
+HSPLandroidx/compose/material3/ColorScheme;->getSurface-0d7_KjU()J
+HSPLandroidx/compose/material3/ColorScheme;->getSurfaceTint-0d7_KjU()J
+HSPLandroidx/compose/material3/ColorScheme;->getSurfaceVariant-0d7_KjU()J
+HSPLandroidx/compose/material3/ColorScheme;->getTertiary-0d7_KjU()J
+HSPLandroidx/compose/material3/ColorScheme;->getTertiaryContainer-0d7_KjU()J
+HSPLandroidx/compose/material3/ColorScheme;->setBackground-8_81llA$material3_release(J)V
+HSPLandroidx/compose/material3/ColorScheme;->setError-8_81llA$material3_release(J)V
+HSPLandroidx/compose/material3/ColorScheme;->setErrorContainer-8_81llA$material3_release(J)V
+HSPLandroidx/compose/material3/ColorScheme;->setInverseOnSurface-8_81llA$material3_release(J)V
+HSPLandroidx/compose/material3/ColorScheme;->setInversePrimary-8_81llA$material3_release(J)V
+HSPLandroidx/compose/material3/ColorScheme;->setInverseSurface-8_81llA$material3_release(J)V
+HSPLandroidx/compose/material3/ColorScheme;->setOnBackground-8_81llA$material3_release(J)V
+HSPLandroidx/compose/material3/ColorScheme;->setOnError-8_81llA$material3_release(J)V
+HSPLandroidx/compose/material3/ColorScheme;->setOnErrorContainer-8_81llA$material3_release(J)V
+HSPLandroidx/compose/material3/ColorScheme;->setOnPrimary-8_81llA$material3_release(J)V
+HSPLandroidx/compose/material3/ColorScheme;->setOnPrimaryContainer-8_81llA$material3_release(J)V
+HSPLandroidx/compose/material3/ColorScheme;->setOnSecondary-8_81llA$material3_release(J)V
+HSPLandroidx/compose/material3/ColorScheme;->setOnSecondaryContainer-8_81llA$material3_release(J)V
+HSPLandroidx/compose/material3/ColorScheme;->setOnSurface-8_81llA$material3_release(J)V
+HSPLandroidx/compose/material3/ColorScheme;->setOnSurfaceVariant-8_81llA$material3_release(J)V
+HSPLandroidx/compose/material3/ColorScheme;->setOnTertiary-8_81llA$material3_release(J)V
+HSPLandroidx/compose/material3/ColorScheme;->setOnTertiaryContainer-8_81llA$material3_release(J)V
+HSPLandroidx/compose/material3/ColorScheme;->setOutline-8_81llA$material3_release(J)V
+HSPLandroidx/compose/material3/ColorScheme;->setOutlineVariant-8_81llA$material3_release(J)V
+HSPLandroidx/compose/material3/ColorScheme;->setPrimary-8_81llA$material3_release(J)V
+HSPLandroidx/compose/material3/ColorScheme;->setPrimaryContainer-8_81llA$material3_release(J)V
+HSPLandroidx/compose/material3/ColorScheme;->setScrim-8_81llA$material3_release(J)V
+HSPLandroidx/compose/material3/ColorScheme;->setSecondary-8_81llA$material3_release(J)V
+HSPLandroidx/compose/material3/ColorScheme;->setSecondaryContainer-8_81llA$material3_release(J)V
+HSPLandroidx/compose/material3/ColorScheme;->setSurface-8_81llA$material3_release(J)V
+HSPLandroidx/compose/material3/ColorScheme;->setSurfaceTint-8_81llA$material3_release(J)V
+HSPLandroidx/compose/material3/ColorScheme;->setSurfaceVariant-8_81llA$material3_release(J)V
+HSPLandroidx/compose/material3/ColorScheme;->setTertiary-8_81llA$material3_release(J)V
+HSPLandroidx/compose/material3/ColorScheme;->setTertiaryContainer-8_81llA$material3_release(J)V
+HSPLandroidx/compose/material3/ColorSchemeKt$LocalColorScheme$1;-><clinit>()V
+HSPLandroidx/compose/material3/ColorSchemeKt$LocalColorScheme$1;-><init>()V
+HSPLandroidx/compose/material3/ColorSchemeKt$WhenMappings;-><clinit>()V
+HSPLandroidx/compose/material3/ColorSchemeKt;-><clinit>()V
+HSPLandroidx/compose/material3/ColorSchemeKt;->contentColorFor-4WTKRHQ(Landroidx/compose/material3/ColorScheme;J)J
+HSPLandroidx/compose/material3/ColorSchemeKt;->contentColorFor-ek8zF_U(JLandroidx/compose/runtime/Composer;I)J
+HSPLandroidx/compose/material3/ColorSchemeKt;->fromToken(Landroidx/compose/material3/ColorScheme;Landroidx/compose/material3/tokens/ColorSchemeKeyTokens;)J
+HSPLandroidx/compose/material3/ColorSchemeKt;->getLocalColorScheme()Landroidx/compose/runtime/ProvidableCompositionLocal;
+HSPLandroidx/compose/material3/ColorSchemeKt;->lightColorScheme-G1PFc-w$default(JJJJJJJJJJJJJJJJJJJJJJJJJJJJJILjava/lang/Object;)Landroidx/compose/material3/ColorScheme;
+HSPLandroidx/compose/material3/ColorSchemeKt;->lightColorScheme-G1PFc-w(JJJJJJJJJJJJJJJJJJJJJJJJJJJJJ)Landroidx/compose/material3/ColorScheme;
+HSPLandroidx/compose/material3/ColorSchemeKt;->surfaceColorAtElevation-3ABfNKs(Landroidx/compose/material3/ColorScheme;F)J
+HSPLandroidx/compose/material3/ColorSchemeKt;->toColor(Landroidx/compose/material3/tokens/ColorSchemeKeyTokens;Landroidx/compose/runtime/Composer;I)J
+HSPLandroidx/compose/material3/ColorSchemeKt;->updateColorSchemeFrom(Landroidx/compose/material3/ColorScheme;Landroidx/compose/material3/ColorScheme;)V
+HSPLandroidx/compose/material3/ContentColorKt$LocalContentColor$1;-><clinit>()V
+HSPLandroidx/compose/material3/ContentColorKt$LocalContentColor$1;-><init>()V
+HSPLandroidx/compose/material3/ContentColorKt;-><clinit>()V
+HSPLandroidx/compose/material3/ContentColorKt;->getLocalContentColor()Landroidx/compose/runtime/ProvidableCompositionLocal;
+HSPLandroidx/compose/material3/DividerKt;->Divider-9IZ8Weo(Landroidx/compose/ui/Modifier;FJLandroidx/compose/runtime/Composer;II)V
+HSPLandroidx/compose/material3/DynamicTonalPaletteKt;->dynamicLightColorScheme(Landroid/content/Context;)Landroidx/compose/material3/ColorScheme;
+HSPLandroidx/compose/material3/DynamicTonalPaletteKt;->dynamicTonalPalette(Landroid/content/Context;)Landroidx/compose/material3/TonalPalette;
+HSPLandroidx/compose/material3/ElevationDefaults;-><clinit>()V
+HSPLandroidx/compose/material3/ElevationDefaults;-><init>()V
+HSPLandroidx/compose/material3/ElevationDefaults;->outgoingAnimationSpecForInteraction(Landroidx/compose/foundation/interaction/Interaction;)Landroidx/compose/animation/core/AnimationSpec;
+HSPLandroidx/compose/material3/ElevationKt;-><clinit>()V
+HSPLandroidx/compose/material3/ElevationKt;->access$getDefaultOutgoingSpec$p()Landroidx/compose/animation/core/TweenSpec;
+HSPLandroidx/compose/material3/ElevationKt;->animateElevation-rAjV9yQ(Landroidx/compose/animation/core/Animatable;FLandroidx/compose/foundation/interaction/Interaction;Landroidx/compose/foundation/interaction/Interaction;Lkotlin/coroutines/Continuation;)Ljava/lang/Object;
+HSPLandroidx/compose/material3/IconKt;-><clinit>()V
+HSPLandroidx/compose/material3/IconKt;->Icon-ww6aTOc(Landroidx/compose/ui/graphics/ImageBitmap;Ljava/lang/String;Landroidx/compose/ui/Modifier;JLandroidx/compose/runtime/Composer;II)V
+HSPLandroidx/compose/material3/IconKt;->Icon-ww6aTOc(Landroidx/compose/ui/graphics/painter/Painter;Ljava/lang/String;Landroidx/compose/ui/Modifier;JLandroidx/compose/runtime/Composer;II)V
+HSPLandroidx/compose/material3/IconKt;->defaultSizeFor(Landroidx/compose/ui/Modifier;Landroidx/compose/ui/graphics/painter/Painter;)Landroidx/compose/ui/Modifier;
+HSPLandroidx/compose/material3/IconKt;->isInfinite-uvyYCjk(J)Z
+HSPLandroidx/compose/material3/MaterialRippleTheme;-><clinit>()V
+HSPLandroidx/compose/material3/MaterialRippleTheme;-><init>()V
+HSPLandroidx/compose/material3/MaterialRippleTheme;->defaultColor-WaAFU9c(Landroidx/compose/runtime/Composer;I)J
+HSPLandroidx/compose/material3/MaterialRippleTheme;->rippleAlpha(Landroidx/compose/runtime/Composer;I)Landroidx/compose/material/ripple/RippleAlpha;
+HSPLandroidx/compose/material3/MaterialTheme;-><clinit>()V
+HSPLandroidx/compose/material3/MaterialTheme;-><init>()V
+HSPLandroidx/compose/material3/MaterialTheme;->getColorScheme(Landroidx/compose/runtime/Composer;I)Landroidx/compose/material3/ColorScheme;
+HSPLandroidx/compose/material3/MaterialTheme;->getShapes(Landroidx/compose/runtime/Composer;I)Landroidx/compose/material3/Shapes;
+HSPLandroidx/compose/material3/MaterialTheme;->getTypography(Landroidx/compose/runtime/Composer;I)Landroidx/compose/material3/Typography;
+HSPLandroidx/compose/material3/MaterialThemeKt$MaterialTheme$1;-><init>(Landroidx/compose/material3/Typography;Lkotlin/jvm/functions/Function2;I)V
+HSPLandroidx/compose/material3/MaterialThemeKt$MaterialTheme$1;->invoke(Landroidx/compose/runtime/Composer;I)V
+HSPLandroidx/compose/material3/MaterialThemeKt$MaterialTheme$1;->invoke(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;
+HSPLandroidx/compose/material3/MaterialThemeKt$MaterialTheme$2;-><init>(Landroidx/compose/material3/ColorScheme;Landroidx/compose/material3/Shapes;Landroidx/compose/material3/Typography;Lkotlin/jvm/functions/Function2;II)V
+HSPLandroidx/compose/material3/MaterialThemeKt;-><clinit>()V
+HSPLandroidx/compose/material3/MaterialThemeKt;->MaterialTheme(Landroidx/compose/material3/ColorScheme;Landroidx/compose/material3/Shapes;Landroidx/compose/material3/Typography;Lkotlin/jvm/functions/Function2;Landroidx/compose/runtime/Composer;II)V
+HSPLandroidx/compose/material3/MaterialThemeKt;->access$getDefaultRippleAlpha$p()Landroidx/compose/material/ripple/RippleAlpha;
+HSPLandroidx/compose/material3/MaterialThemeKt;->rememberTextSelectionColors(Landroidx/compose/material3/ColorScheme;Landroidx/compose/runtime/Composer;I)Landroidx/compose/foundation/text/selection/TextSelectionColors;
+HSPLandroidx/compose/material3/MinimumTouchTargetModifier$measure$1;-><init>(ILandroidx/compose/ui/layout/Placeable;I)V
+HSPLandroidx/compose/material3/MinimumTouchTargetModifier$measure$1;->invoke(Landroidx/compose/ui/layout/Placeable$PlacementScope;)V
+HSPLandroidx/compose/material3/MinimumTouchTargetModifier$measure$1;->invoke(Ljava/lang/Object;)Ljava/lang/Object;
+HSPLandroidx/compose/material3/MinimumTouchTargetModifier;-><init>(J)V
+HSPLandroidx/compose/material3/MinimumTouchTargetModifier;-><init>(JLkotlin/jvm/internal/DefaultConstructorMarker;)V
+HSPLandroidx/compose/material3/MinimumTouchTargetModifier;->equals(Ljava/lang/Object;)Z
+HSPLandroidx/compose/material3/MinimumTouchTargetModifier;->measure-3p2s80s(Landroidx/compose/ui/layout/MeasureScope;Landroidx/compose/ui/layout/Measurable;J)Landroidx/compose/ui/layout/MeasureResult;
+HSPLandroidx/compose/material3/ShapeDefaults;-><clinit>()V
+HSPLandroidx/compose/material3/ShapeDefaults;-><init>()V
+HSPLandroidx/compose/material3/ShapeDefaults;->getExtraLarge()Landroidx/compose/foundation/shape/CornerBasedShape;
+HSPLandroidx/compose/material3/ShapeDefaults;->getExtraSmall()Landroidx/compose/foundation/shape/CornerBasedShape;
+HSPLandroidx/compose/material3/Shapes;-><init>(Landroidx/compose/foundation/shape/CornerBasedShape;Landroidx/compose/foundation/shape/CornerBasedShape;Landroidx/compose/foundation/shape/CornerBasedShape;Landroidx/compose/foundation/shape/CornerBasedShape;Landroidx/compose/foundation/shape/CornerBasedShape;)V
+HSPLandroidx/compose/material3/Shapes;-><init>(Landroidx/compose/foundation/shape/CornerBasedShape;Landroidx/compose/foundation/shape/CornerBasedShape;Landroidx/compose/foundation/shape/CornerBasedShape;Landroidx/compose/foundation/shape/CornerBasedShape;Landroidx/compose/foundation/shape/CornerBasedShape;ILkotlin/jvm/internal/DefaultConstructorMarker;)V
+HSPLandroidx/compose/material3/Shapes;->equals(Ljava/lang/Object;)Z
+HSPLandroidx/compose/material3/Shapes;->getMedium()Landroidx/compose/foundation/shape/CornerBasedShape;
+HSPLandroidx/compose/material3/ShapesKt$LocalShapes$1;-><clinit>()V
+HSPLandroidx/compose/material3/ShapesKt$LocalShapes$1;-><init>()V
+HSPLandroidx/compose/material3/ShapesKt$WhenMappings;-><clinit>()V
+HSPLandroidx/compose/material3/ShapesKt;-><clinit>()V
+HSPLandroidx/compose/material3/ShapesKt;->fromToken(Landroidx/compose/material3/Shapes;Landroidx/compose/material3/tokens/ShapeKeyTokens;)Landroidx/compose/ui/graphics/Shape;
+HSPLandroidx/compose/material3/ShapesKt;->getLocalShapes()Landroidx/compose/runtime/ProvidableCompositionLocal;
+HSPLandroidx/compose/material3/ShapesKt;->toShape(Landroidx/compose/material3/tokens/ShapeKeyTokens;Landroidx/compose/runtime/Composer;I)Landroidx/compose/ui/graphics/Shape;
+HSPLandroidx/compose/material3/SuggestionChipDefaults;-><clinit>()V
+HSPLandroidx/compose/material3/SuggestionChipDefaults;-><init>()V
+HSPLandroidx/compose/material3/SuggestionChipDefaults;->getHeight-D9Ej5fM()F
+HSPLandroidx/compose/material3/SuggestionChipDefaults;->suggestionChipColors-5tl4gsc(JJJJJJLandroidx/compose/runtime/Composer;II)Landroidx/compose/material3/ChipColors;
+HSPLandroidx/compose/material3/SuggestionChipDefaults;->suggestionChipElevation-aqJV_2Y(FFFFFFLandroidx/compose/runtime/Composer;II)Landroidx/compose/material3/ChipElevation;
+HSPLandroidx/compose/material3/SurfaceKt$LocalAbsoluteTonalElevation$1;-><clinit>()V
+HSPLandroidx/compose/material3/SurfaceKt$LocalAbsoluteTonalElevation$1;-><init>()V
+HSPLandroidx/compose/material3/SurfaceKt$LocalAbsoluteTonalElevation$1;->invoke()Ljava/lang/Object;
+HSPLandroidx/compose/material3/SurfaceKt$LocalAbsoluteTonalElevation$1;->invoke-D9Ej5fM()F
+HSPLandroidx/compose/material3/SurfaceKt$Surface$1$1;-><clinit>()V
+HSPLandroidx/compose/material3/SurfaceKt$Surface$1$1;-><init>()V
+HSPLandroidx/compose/material3/SurfaceKt$Surface$1$1;->invoke(Landroidx/compose/ui/semantics/SemanticsPropertyReceiver;)V
+HSPLandroidx/compose/material3/SurfaceKt$Surface$1$1;->invoke(Ljava/lang/Object;)Ljava/lang/Object;
+HSPLandroidx/compose/material3/SurfaceKt$Surface$1$2;-><init>(Lkotlin/coroutines/Continuation;)V
+HSPLandroidx/compose/material3/SurfaceKt$Surface$1$2;->create(Ljava/lang/Object;Lkotlin/coroutines/Continuation;)Lkotlin/coroutines/Continuation;
+HSPLandroidx/compose/material3/SurfaceKt$Surface$1$2;->invoke(Landroidx/compose/ui/input/pointer/PointerInputScope;Lkotlin/coroutines/Continuation;)Ljava/lang/Object;
+HSPLandroidx/compose/material3/SurfaceKt$Surface$1$2;->invoke(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;
+HSPLandroidx/compose/material3/SurfaceKt$Surface$1$2;->invokeSuspend(Ljava/lang/Object;)Ljava/lang/Object;
+HSPLandroidx/compose/material3/SurfaceKt$Surface$1;-><init>(Landroidx/compose/ui/Modifier;Landroidx/compose/ui/graphics/Shape;JFILandroidx/compose/foundation/BorderStroke;FLkotlin/jvm/functions/Function2;)V
+HSPLandroidx/compose/material3/SurfaceKt$Surface$1;->invoke(Landroidx/compose/runtime/Composer;I)V
+HSPLandroidx/compose/material3/SurfaceKt$Surface$1;->invoke(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;
+HSPLandroidx/compose/material3/SurfaceKt$Surface$3;-><init>(Landroidx/compose/ui/Modifier;Landroidx/compose/ui/graphics/Shape;JFILandroidx/compose/foundation/BorderStroke;FLandroidx/compose/foundation/interaction/MutableInteractionSource;ZLkotlin/jvm/functions/Function0;Lkotlin/jvm/functions/Function2;I)V
+HSPLandroidx/compose/material3/SurfaceKt$Surface$3;->invoke(Landroidx/compose/runtime/Composer;I)V
+HSPLandroidx/compose/material3/SurfaceKt$Surface$3;->invoke(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;
+HSPLandroidx/compose/material3/SurfaceKt;-><clinit>()V
+HSPLandroidx/compose/material3/SurfaceKt;->Surface-T9BRK9s(Landroidx/compose/ui/Modifier;Landroidx/compose/ui/graphics/Shape;JJFFLandroidx/compose/foundation/BorderStroke;Lkotlin/jvm/functions/Function2;Landroidx/compose/runtime/Composer;II)V
+HSPLandroidx/compose/material3/SurfaceKt;->Surface-o_FOJdg(Lkotlin/jvm/functions/Function0;Landroidx/compose/ui/Modifier;ZLandroidx/compose/ui/graphics/Shape;JJFFLandroidx/compose/foundation/BorderStroke;Landroidx/compose/foundation/interaction/MutableInteractionSource;Lkotlin/jvm/functions/Function2;Landroidx/compose/runtime/Composer;III)V
+HSPLandroidx/compose/material3/SurfaceKt;->access$surface-8ww4TTg(Landroidx/compose/ui/Modifier;Landroidx/compose/ui/graphics/Shape;JLandroidx/compose/foundation/BorderStroke;F)Landroidx/compose/ui/Modifier;
+HSPLandroidx/compose/material3/SurfaceKt;->access$surfaceColorAtElevation-CLU3JFs(JFLandroidx/compose/runtime/Composer;I)J
+HSPLandroidx/compose/material3/SurfaceKt;->surface-8ww4TTg(Landroidx/compose/ui/Modifier;Landroidx/compose/ui/graphics/Shape;JLandroidx/compose/foundation/BorderStroke;F)Landroidx/compose/ui/Modifier;
+HSPLandroidx/compose/material3/SurfaceKt;->surfaceColorAtElevation-CLU3JFs(JFLandroidx/compose/runtime/Composer;I)J
+HSPLandroidx/compose/material3/TextKt$LocalTextStyle$1;-><clinit>()V
+HSPLandroidx/compose/material3/TextKt$LocalTextStyle$1;-><init>()V
+HSPLandroidx/compose/material3/TextKt$LocalTextStyle$1;->invoke()Landroidx/compose/ui/text/TextStyle;
+HSPLandroidx/compose/material3/TextKt$LocalTextStyle$1;->invoke()Ljava/lang/Object;
+HSPLandroidx/compose/material3/TextKt$ProvideTextStyle$1;-><init>(Landroidx/compose/ui/text/TextStyle;Lkotlin/jvm/functions/Function2;I)V
+HSPLandroidx/compose/material3/TextKt$Text$1;-><clinit>()V
+HSPLandroidx/compose/material3/TextKt$Text$1;-><init>()V
+HSPLandroidx/compose/material3/TextKt$Text$1;->invoke(Landroidx/compose/ui/text/TextLayoutResult;)V
+HSPLandroidx/compose/material3/TextKt$Text$1;->invoke(Ljava/lang/Object;)Ljava/lang/Object;
+HSPLandroidx/compose/material3/TextKt$Text$2;-><init>(Ljava/lang/String;Landroidx/compose/ui/Modifier;JJLandroidx/compose/ui/text/font/FontStyle;Landroidx/compose/ui/text/font/FontWeight;Landroidx/compose/ui/text/font/FontFamily;JLandroidx/compose/ui/text/style/TextDecoration;Landroidx/compose/ui/text/style/TextAlign;JIZIILkotlin/jvm/functions/Function1;Landroidx/compose/ui/text/TextStyle;III)V
+HSPLandroidx/compose/material3/TextKt;-><clinit>()V
+HSPLandroidx/compose/material3/TextKt;->ProvideTextStyle(Landroidx/compose/ui/text/TextStyle;Lkotlin/jvm/functions/Function2;Landroidx/compose/runtime/Composer;I)V
+HSPLandroidx/compose/material3/TextKt;->Text--4IGK_g(Ljava/lang/String;Landroidx/compose/ui/Modifier;JJLandroidx/compose/ui/text/font/FontStyle;Landroidx/compose/ui/text/font/FontWeight;Landroidx/compose/ui/text/font/FontFamily;JLandroidx/compose/ui/text/style/TextDecoration;Landroidx/compose/ui/text/style/TextAlign;JIZIILkotlin/jvm/functions/Function1;Landroidx/compose/ui/text/TextStyle;Landroidx/compose/runtime/Composer;III)V
+HSPLandroidx/compose/material3/TextKt;->getLocalTextStyle()Landroidx/compose/runtime/ProvidableCompositionLocal;
+HSPLandroidx/compose/material3/TonalPalette;-><init>(JJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJ)V
+HSPLandroidx/compose/material3/TonalPalette;-><init>(JJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJLkotlin/jvm/internal/DefaultConstructorMarker;)V
+HSPLandroidx/compose/material3/TonalPalette;->getNeutral10-0d7_KjU()J
+HSPLandroidx/compose/material3/TonalPalette;->getNeutral20-0d7_KjU()J
+HSPLandroidx/compose/material3/TonalPalette;->getNeutral95-0d7_KjU()J
+HSPLandroidx/compose/material3/TonalPalette;->getNeutral99-0d7_KjU()J
+HSPLandroidx/compose/material3/TonalPalette;->getNeutralVariant30-0d7_KjU()J
+HSPLandroidx/compose/material3/TonalPalette;->getNeutralVariant50-0d7_KjU()J
+HSPLandroidx/compose/material3/TonalPalette;->getNeutralVariant90-0d7_KjU()J
+HSPLandroidx/compose/material3/TonalPalette;->getPrimary10-0d7_KjU()J
+HSPLandroidx/compose/material3/TonalPalette;->getPrimary100-0d7_KjU()J
+HSPLandroidx/compose/material3/TonalPalette;->getPrimary40-0d7_KjU()J
+HSPLandroidx/compose/material3/TonalPalette;->getPrimary80-0d7_KjU()J
+HSPLandroidx/compose/material3/TonalPalette;->getPrimary90-0d7_KjU()J
+HSPLandroidx/compose/material3/TonalPalette;->getSecondary10-0d7_KjU()J
+HSPLandroidx/compose/material3/TonalPalette;->getSecondary100-0d7_KjU()J
+HSPLandroidx/compose/material3/TonalPalette;->getSecondary40-0d7_KjU()J
+HSPLandroidx/compose/material3/TonalPalette;->getSecondary90-0d7_KjU()J
+HSPLandroidx/compose/material3/TonalPalette;->getTertiary10-0d7_KjU()J
+HSPLandroidx/compose/material3/TonalPalette;->getTertiary100-0d7_KjU()J
+HSPLandroidx/compose/material3/TonalPalette;->getTertiary40-0d7_KjU()J
+HSPLandroidx/compose/material3/TonalPalette;->getTertiary90-0d7_KjU()J
+HSPLandroidx/compose/material3/TouchTargetKt$LocalMinimumTouchTargetEnforcement$1;-><clinit>()V
+HSPLandroidx/compose/material3/TouchTargetKt$LocalMinimumTouchTargetEnforcement$1;-><init>()V
+HSPLandroidx/compose/material3/TouchTargetKt$LocalMinimumTouchTargetEnforcement$1;->invoke()Ljava/lang/Boolean;
+HSPLandroidx/compose/material3/TouchTargetKt$LocalMinimumTouchTargetEnforcement$1;->invoke()Ljava/lang/Object;
+HSPLandroidx/compose/material3/TouchTargetKt$minimumTouchTargetSize$2;-><clinit>()V
+HSPLandroidx/compose/material3/TouchTargetKt$minimumTouchTargetSize$2;-><init>()V
+HSPLandroidx/compose/material3/TouchTargetKt$minimumTouchTargetSize$2;->invoke(Landroidx/compose/ui/Modifier;Landroidx/compose/runtime/Composer;I)Landroidx/compose/ui/Modifier;
+HSPLandroidx/compose/material3/TouchTargetKt$minimumTouchTargetSize$2;->invoke(Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;
+HSPLandroidx/compose/material3/TouchTargetKt;-><clinit>()V
+HSPLandroidx/compose/material3/TouchTargetKt;->getLocalMinimumTouchTargetEnforcement()Landroidx/compose/runtime/ProvidableCompositionLocal;
+HSPLandroidx/compose/material3/TouchTargetKt;->minimumTouchTargetSize(Landroidx/compose/ui/Modifier;)Landroidx/compose/ui/Modifier;
+HSPLandroidx/compose/material3/Typography;-><init>(Landroidx/compose/ui/text/TextStyle;Landroidx/compose/ui/text/TextStyle;Landroidx/compose/ui/text/TextStyle;Landroidx/compose/ui/text/TextStyle;Landroidx/compose/ui/text/TextStyle;Landroidx/compose/ui/text/TextStyle;Landroidx/compose/ui/text/TextStyle;Landroidx/compose/ui/text/TextStyle;Landroidx/compose/ui/text/TextStyle;Landroidx/compose/ui/text/TextStyle;Landroidx/compose/ui/text/TextStyle;Landroidx/compose/ui/text/TextStyle;Landroidx/compose/ui/text/TextStyle;Landroidx/compose/ui/text/TextStyle;Landroidx/compose/ui/text/TextStyle;)V
+HSPLandroidx/compose/material3/Typography;-><init>(Landroidx/compose/ui/text/TextStyle;Landroidx/compose/ui/text/TextStyle;Landroidx/compose/ui/text/TextStyle;Landroidx/compose/ui/text/TextStyle;Landroidx/compose/ui/text/TextStyle;Landroidx/compose/ui/text/TextStyle;Landroidx/compose/ui/text/TextStyle;Landroidx/compose/ui/text/TextStyle;Landroidx/compose/ui/text/TextStyle;Landroidx/compose/ui/text/TextStyle;Landroidx/compose/ui/text/TextStyle;Landroidx/compose/ui/text/TextStyle;Landroidx/compose/ui/text/TextStyle;Landroidx/compose/ui/text/TextStyle;Landroidx/compose/ui/text/TextStyle;ILkotlin/jvm/internal/DefaultConstructorMarker;)V
+HSPLandroidx/compose/material3/Typography;->equals(Ljava/lang/Object;)Z
+HSPLandroidx/compose/material3/Typography;->getBodyLarge()Landroidx/compose/ui/text/TextStyle;
+HSPLandroidx/compose/material3/Typography;->getBodyMedium()Landroidx/compose/ui/text/TextStyle;
+HSPLandroidx/compose/material3/Typography;->getLabelLarge()Landroidx/compose/ui/text/TextStyle;
+HSPLandroidx/compose/material3/Typography;->getTitleLarge()Landroidx/compose/ui/text/TextStyle;
+HSPLandroidx/compose/material3/Typography;->getTitleMedium()Landroidx/compose/ui/text/TextStyle;
+HSPLandroidx/compose/material3/TypographyKt$LocalTypography$1;-><clinit>()V
+HSPLandroidx/compose/material3/TypographyKt$LocalTypography$1;-><init>()V
+HSPLandroidx/compose/material3/TypographyKt$WhenMappings;-><clinit>()V
+HSPLandroidx/compose/material3/TypographyKt;-><clinit>()V
+HSPLandroidx/compose/material3/TypographyKt;->fromToken(Landroidx/compose/material3/Typography;Landroidx/compose/material3/tokens/TypographyKeyTokens;)Landroidx/compose/ui/text/TextStyle;
+HSPLandroidx/compose/material3/TypographyKt;->getLocalTypography()Landroidx/compose/runtime/ProvidableCompositionLocal;
+HSPLandroidx/compose/material3/tokens/ColorLightTokens;-><clinit>()V
+HSPLandroidx/compose/material3/tokens/ColorLightTokens;-><init>()V
+HSPLandroidx/compose/material3/tokens/ColorLightTokens;->getError-0d7_KjU()J
+HSPLandroidx/compose/material3/tokens/ColorLightTokens;->getErrorContainer-0d7_KjU()J
+HSPLandroidx/compose/material3/tokens/ColorLightTokens;->getOnError-0d7_KjU()J
+HSPLandroidx/compose/material3/tokens/ColorLightTokens;->getOnErrorContainer-0d7_KjU()J
+HSPLandroidx/compose/material3/tokens/ColorLightTokens;->getOutlineVariant-0d7_KjU()J
+HSPLandroidx/compose/material3/tokens/ColorLightTokens;->getScrim-0d7_KjU()J
+HSPLandroidx/compose/material3/tokens/ColorSchemeKeyTokens;->$values()[Landroidx/compose/material3/tokens/ColorSchemeKeyTokens;
+HSPLandroidx/compose/material3/tokens/ColorSchemeKeyTokens;-><clinit>()V
+HSPLandroidx/compose/material3/tokens/ColorSchemeKeyTokens;-><init>(Ljava/lang/String;I)V
+HSPLandroidx/compose/material3/tokens/ColorSchemeKeyTokens;->values()[Landroidx/compose/material3/tokens/ColorSchemeKeyTokens;
+HSPLandroidx/compose/material3/tokens/ElevationTokens;-><clinit>()V
+HSPLandroidx/compose/material3/tokens/ElevationTokens;-><init>()V
+HSPLandroidx/compose/material3/tokens/ElevationTokens;->getLevel0-D9Ej5fM()F
+HSPLandroidx/compose/material3/tokens/ElevationTokens;->getLevel1-D9Ej5fM()F
+HSPLandroidx/compose/material3/tokens/ElevationTokens;->getLevel2-D9Ej5fM()F
+HSPLandroidx/compose/material3/tokens/ElevationTokens;->getLevel3-D9Ej5fM()F
+HSPLandroidx/compose/material3/tokens/ElevationTokens;->getLevel4-D9Ej5fM()F
+HSPLandroidx/compose/material3/tokens/FilledButtonTokens;-><clinit>()V
+HSPLandroidx/compose/material3/tokens/FilledButtonTokens;-><init>()V
+HSPLandroidx/compose/material3/tokens/FilledButtonTokens;->getIconSize-D9Ej5fM()F
+HSPLandroidx/compose/material3/tokens/FilledCardTokens;-><clinit>()V
+HSPLandroidx/compose/material3/tokens/FilledCardTokens;-><init>()V
+HSPLandroidx/compose/material3/tokens/FilledCardTokens;->getContainerElevation-D9Ej5fM()F
+HSPLandroidx/compose/material3/tokens/FilledCardTokens;->getContainerShape()Landroidx/compose/material3/tokens/ShapeKeyTokens;
+HSPLandroidx/compose/material3/tokens/FilledCardTokens;->getDisabledContainerColor()Landroidx/compose/material3/tokens/ColorSchemeKeyTokens;
+HSPLandroidx/compose/material3/tokens/FilledCardTokens;->getDisabledContainerElevation-D9Ej5fM()F
+HSPLandroidx/compose/material3/tokens/FilledCardTokens;->getDraggedContainerElevation-D9Ej5fM()F
+HSPLandroidx/compose/material3/tokens/FilledCardTokens;->getFocusContainerElevation-D9Ej5fM()F
+HSPLandroidx/compose/material3/tokens/FilledCardTokens;->getHoverContainerElevation-D9Ej5fM()F
+HSPLandroidx/compose/material3/tokens/FilledCardTokens;->getPressedContainerElevation-D9Ej5fM()F
+HSPLandroidx/compose/material3/tokens/FilledTonalButtonTokens;-><clinit>()V
+HSPLandroidx/compose/material3/tokens/FilledTonalButtonTokens;-><init>()V
+HSPLandroidx/compose/material3/tokens/FilledTonalButtonTokens;->getContainerElevation-D9Ej5fM()F
+HSPLandroidx/compose/material3/tokens/FilledTonalButtonTokens;->getContainerShape()Landroidx/compose/material3/tokens/ShapeKeyTokens;
+HSPLandroidx/compose/material3/tokens/FilledTonalButtonTokens;->getDisabledContainerColor()Landroidx/compose/material3/tokens/ColorSchemeKeyTokens;
+HSPLandroidx/compose/material3/tokens/FilledTonalButtonTokens;->getDisabledLabelTextColor()Landroidx/compose/material3/tokens/ColorSchemeKeyTokens;
+HSPLandroidx/compose/material3/tokens/FilledTonalButtonTokens;->getFocusContainerElevation-D9Ej5fM()F
+HSPLandroidx/compose/material3/tokens/FilledTonalButtonTokens;->getHoverContainerElevation-D9Ej5fM()F
+HSPLandroidx/compose/material3/tokens/FilledTonalButtonTokens;->getPressedContainerElevation-D9Ej5fM()F
+HSPLandroidx/compose/material3/tokens/IconButtonTokens;-><clinit>()V
+HSPLandroidx/compose/material3/tokens/IconButtonTokens;-><init>()V
+HSPLandroidx/compose/material3/tokens/IconButtonTokens;->getIconSize-D9Ej5fM()F
+HSPLandroidx/compose/material3/tokens/PaletteTokens;-><clinit>()V
+HSPLandroidx/compose/material3/tokens/PaletteTokens;-><init>()V
+HSPLandroidx/compose/material3/tokens/PaletteTokens;->getError10-0d7_KjU()J
+HSPLandroidx/compose/material3/tokens/PaletteTokens;->getError100-0d7_KjU()J
+HSPLandroidx/compose/material3/tokens/PaletteTokens;->getError40-0d7_KjU()J
+HSPLandroidx/compose/material3/tokens/PaletteTokens;->getError90-0d7_KjU()J
+HSPLandroidx/compose/material3/tokens/PaletteTokens;->getNeutral0-0d7_KjU()J
+HSPLandroidx/compose/material3/tokens/PaletteTokens;->getNeutral10-0d7_KjU()J
+HSPLandroidx/compose/material3/tokens/PaletteTokens;->getNeutral20-0d7_KjU()J
+HSPLandroidx/compose/material3/tokens/PaletteTokens;->getNeutral95-0d7_KjU()J
+HSPLandroidx/compose/material3/tokens/PaletteTokens;->getNeutral99-0d7_KjU()J
+HSPLandroidx/compose/material3/tokens/PaletteTokens;->getNeutralVariant30-0d7_KjU()J
+HSPLandroidx/compose/material3/tokens/PaletteTokens;->getNeutralVariant50-0d7_KjU()J
+HSPLandroidx/compose/material3/tokens/PaletteTokens;->getNeutralVariant80-0d7_KjU()J
+HSPLandroidx/compose/material3/tokens/PaletteTokens;->getNeutralVariant90-0d7_KjU()J
+HSPLandroidx/compose/material3/tokens/PaletteTokens;->getPrimary10-0d7_KjU()J
+HSPLandroidx/compose/material3/tokens/PaletteTokens;->getPrimary100-0d7_KjU()J
+HSPLandroidx/compose/material3/tokens/PaletteTokens;->getPrimary40-0d7_KjU()J
+HSPLandroidx/compose/material3/tokens/PaletteTokens;->getPrimary80-0d7_KjU()J
+HSPLandroidx/compose/material3/tokens/PaletteTokens;->getPrimary90-0d7_KjU()J
+HSPLandroidx/compose/material3/tokens/PaletteTokens;->getSecondary10-0d7_KjU()J
+HSPLandroidx/compose/material3/tokens/PaletteTokens;->getSecondary100-0d7_KjU()J
+HSPLandroidx/compose/material3/tokens/PaletteTokens;->getSecondary40-0d7_KjU()J
+HSPLandroidx/compose/material3/tokens/PaletteTokens;->getSecondary90-0d7_KjU()J
+HSPLandroidx/compose/material3/tokens/PaletteTokens;->getTertiary10-0d7_KjU()J
+HSPLandroidx/compose/material3/tokens/PaletteTokens;->getTertiary100-0d7_KjU()J
+HSPLandroidx/compose/material3/tokens/PaletteTokens;->getTertiary40-0d7_KjU()J
+HSPLandroidx/compose/material3/tokens/PaletteTokens;->getTertiary90-0d7_KjU()J
+HSPLandroidx/compose/material3/tokens/ShapeKeyTokens;->$values()[Landroidx/compose/material3/tokens/ShapeKeyTokens;
+HSPLandroidx/compose/material3/tokens/ShapeKeyTokens;-><clinit>()V
+HSPLandroidx/compose/material3/tokens/ShapeKeyTokens;-><init>(Ljava/lang/String;I)V
+HSPLandroidx/compose/material3/tokens/ShapeKeyTokens;->values()[Landroidx/compose/material3/tokens/ShapeKeyTokens;
+HSPLandroidx/compose/material3/tokens/ShapeTokens;-><clinit>()V
+HSPLandroidx/compose/material3/tokens/ShapeTokens;-><init>()V
+HSPLandroidx/compose/material3/tokens/ShapeTokens;->getCornerExtraLarge()Landroidx/compose/foundation/shape/RoundedCornerShape;
+HSPLandroidx/compose/material3/tokens/ShapeTokens;->getCornerExtraSmall()Landroidx/compose/foundation/shape/RoundedCornerShape;
+HSPLandroidx/compose/material3/tokens/ShapeTokens;->getCornerLarge()Landroidx/compose/foundation/shape/RoundedCornerShape;
+HSPLandroidx/compose/material3/tokens/ShapeTokens;->getCornerMedium()Landroidx/compose/foundation/shape/RoundedCornerShape;
+HSPLandroidx/compose/material3/tokens/ShapeTokens;->getCornerSmall()Landroidx/compose/foundation/shape/RoundedCornerShape;
+HSPLandroidx/compose/material3/tokens/SuggestionChipTokens;-><clinit>()V
+HSPLandroidx/compose/material3/tokens/SuggestionChipTokens;-><init>()V
+HSPLandroidx/compose/material3/tokens/SuggestionChipTokens;->getContainerHeight-D9Ej5fM()F
+HSPLandroidx/compose/material3/tokens/SuggestionChipTokens;->getDisabledLabelTextColor()Landroidx/compose/material3/tokens/ColorSchemeKeyTokens;
+HSPLandroidx/compose/material3/tokens/SuggestionChipTokens;->getDisabledLeadingIconColor()Landroidx/compose/material3/tokens/ColorSchemeKeyTokens;
+HSPLandroidx/compose/material3/tokens/SuggestionChipTokens;->getDraggedContainerElevation-D9Ej5fM()F
+HSPLandroidx/compose/material3/tokens/SuggestionChipTokens;->getFlatContainerElevation-D9Ej5fM()F
+HSPLandroidx/compose/material3/tokens/SuggestionChipTokens;->getLabelTextFont()Landroidx/compose/material3/tokens/TypographyKeyTokens;
+HSPLandroidx/compose/material3/tokens/SuggestionChipTokens;->getLeadingIconSize-D9Ej5fM()F
+HSPLandroidx/compose/material3/tokens/TextButtonTokens;-><clinit>()V
+HSPLandroidx/compose/material3/tokens/TextButtonTokens;-><init>()V
+HSPLandroidx/compose/material3/tokens/TextButtonTokens;->getContainerShape()Landroidx/compose/material3/tokens/ShapeKeyTokens;
+HSPLandroidx/compose/material3/tokens/TextButtonTokens;->getDisabledLabelTextColor()Landroidx/compose/material3/tokens/ColorSchemeKeyTokens;
+HSPLandroidx/compose/material3/tokens/TypeScaleTokens;-><clinit>()V
+HSPLandroidx/compose/material3/tokens/TypeScaleTokens;-><init>()V
+HSPLandroidx/compose/material3/tokens/TypeScaleTokens;->getBodyLargeFont()Landroidx/compose/ui/text/font/GenericFontFamily;
+HSPLandroidx/compose/material3/tokens/TypeScaleTokens;->getBodyLargeLineHeight-XSAIIZE()J
+HSPLandroidx/compose/material3/tokens/TypeScaleTokens;->getBodyLargeSize-XSAIIZE()J
+HSPLandroidx/compose/material3/tokens/TypeScaleTokens;->getBodyLargeTracking-XSAIIZE()J
+HSPLandroidx/compose/material3/tokens/TypeScaleTokens;->getBodyLargeWeight()Landroidx/compose/ui/text/font/FontWeight;
+HSPLandroidx/compose/material3/tokens/TypeScaleTokens;->getBodyMediumFont()Landroidx/compose/ui/text/font/GenericFontFamily;
+HSPLandroidx/compose/material3/tokens/TypeScaleTokens;->getBodyMediumLineHeight-XSAIIZE()J
+HSPLandroidx/compose/material3/tokens/TypeScaleTokens;->getBodyMediumSize-XSAIIZE()J
+HSPLandroidx/compose/material3/tokens/TypeScaleTokens;->getBodyMediumTracking-XSAIIZE()J
+HSPLandroidx/compose/material3/tokens/TypeScaleTokens;->getBodyMediumWeight()Landroidx/compose/ui/text/font/FontWeight;
+HSPLandroidx/compose/material3/tokens/TypeScaleTokens;->getBodySmallFont()Landroidx/compose/ui/text/font/GenericFontFamily;
+HSPLandroidx/compose/material3/tokens/TypeScaleTokens;->getBodySmallLineHeight-XSAIIZE()J
+HSPLandroidx/compose/material3/tokens/TypeScaleTokens;->getBodySmallSize-XSAIIZE()J
+HSPLandroidx/compose/material3/tokens/TypeScaleTokens;->getBodySmallTracking-XSAIIZE()J
+HSPLandroidx/compose/material3/tokens/TypeScaleTokens;->getBodySmallWeight()Landroidx/compose/ui/text/font/FontWeight;
+HSPLandroidx/compose/material3/tokens/TypeScaleTokens;->getDisplayLargeFont()Landroidx/compose/ui/text/font/GenericFontFamily;
+HSPLandroidx/compose/material3/tokens/TypeScaleTokens;->getDisplayLargeLineHeight-XSAIIZE()J
+HSPLandroidx/compose/material3/tokens/TypeScaleTokens;->getDisplayLargeSize-XSAIIZE()J
+HSPLandroidx/compose/material3/tokens/TypeScaleTokens;->getDisplayLargeTracking-XSAIIZE()J
+HSPLandroidx/compose/material3/tokens/TypeScaleTokens;->getDisplayLargeWeight()Landroidx/compose/ui/text/font/FontWeight;
+HSPLandroidx/compose/material3/tokens/TypeScaleTokens;->getDisplayMediumFont()Landroidx/compose/ui/text/font/GenericFontFamily;
+HSPLandroidx/compose/material3/tokens/TypeScaleTokens;->getDisplayMediumLineHeight-XSAIIZE()J
+HSPLandroidx/compose/material3/tokens/TypeScaleTokens;->getDisplayMediumSize-XSAIIZE()J
+HSPLandroidx/compose/material3/tokens/TypeScaleTokens;->getDisplayMediumTracking-XSAIIZE()J
+HSPLandroidx/compose/material3/tokens/TypeScaleTokens;->getDisplayMediumWeight()Landroidx/compose/ui/text/font/FontWeight;
+HSPLandroidx/compose/material3/tokens/TypeScaleTokens;->getDisplaySmallFont()Landroidx/compose/ui/text/font/GenericFontFamily;
+HSPLandroidx/compose/material3/tokens/TypeScaleTokens;->getDisplaySmallLineHeight-XSAIIZE()J
+HSPLandroidx/compose/material3/tokens/TypeScaleTokens;->getDisplaySmallSize-XSAIIZE()J
+HSPLandroidx/compose/material3/tokens/TypeScaleTokens;->getDisplaySmallTracking-XSAIIZE()J
+HSPLandroidx/compose/material3/tokens/TypeScaleTokens;->getDisplaySmallWeight()Landroidx/compose/ui/text/font/FontWeight;
+HSPLandroidx/compose/material3/tokens/TypeScaleTokens;->getHeadlineLargeFont()Landroidx/compose/ui/text/font/GenericFontFamily;
+HSPLandroidx/compose/material3/tokens/TypeScaleTokens;->getHeadlineLargeLineHeight-XSAIIZE()J
+HSPLandroidx/compose/material3/tokens/TypeScaleTokens;->getHeadlineLargeSize-XSAIIZE()J
+HSPLandroidx/compose/material3/tokens/TypeScaleTokens;->getHeadlineLargeTracking-XSAIIZE()J
+HSPLandroidx/compose/material3/tokens/TypeScaleTokens;->getHeadlineLargeWeight()Landroidx/compose/ui/text/font/FontWeight;
+HSPLandroidx/compose/material3/tokens/TypeScaleTokens;->getHeadlineMediumFont()Landroidx/compose/ui/text/font/GenericFontFamily;
+HSPLandroidx/compose/material3/tokens/TypeScaleTokens;->getHeadlineMediumLineHeight-XSAIIZE()J
+HSPLandroidx/compose/material3/tokens/TypeScaleTokens;->getHeadlineMediumSize-XSAIIZE()J
+HSPLandroidx/compose/material3/tokens/TypeScaleTokens;->getHeadlineMediumTracking-XSAIIZE()J
+HSPLandroidx/compose/material3/tokens/TypeScaleTokens;->getHeadlineMediumWeight()Landroidx/compose/ui/text/font/FontWeight;
+HSPLandroidx/compose/material3/tokens/TypeScaleTokens;->getHeadlineSmallFont()Landroidx/compose/ui/text/font/GenericFontFamily;
+HSPLandroidx/compose/material3/tokens/TypeScaleTokens;->getHeadlineSmallLineHeight-XSAIIZE()J
+HSPLandroidx/compose/material3/tokens/TypeScaleTokens;->getHeadlineSmallSize-XSAIIZE()J
+HSPLandroidx/compose/material3/tokens/TypeScaleTokens;->getHeadlineSmallTracking-XSAIIZE()J
+HSPLandroidx/compose/material3/tokens/TypeScaleTokens;->getHeadlineSmallWeight()Landroidx/compose/ui/text/font/FontWeight;
+HSPLandroidx/compose/material3/tokens/TypeScaleTokens;->getLabelLargeFont()Landroidx/compose/ui/text/font/GenericFontFamily;
+HSPLandroidx/compose/material3/tokens/TypeScaleTokens;->getLabelLargeLineHeight-XSAIIZE()J
+HSPLandroidx/compose/material3/tokens/TypeScaleTokens;->getLabelLargeSize-XSAIIZE()J
+HSPLandroidx/compose/material3/tokens/TypeScaleTokens;->getLabelLargeTracking-XSAIIZE()J
+HSPLandroidx/compose/material3/tokens/TypeScaleTokens;->getLabelLargeWeight()Landroidx/compose/ui/text/font/FontWeight;
+HSPLandroidx/compose/material3/tokens/TypeScaleTokens;->getLabelMediumFont()Landroidx/compose/ui/text/font/GenericFontFamily;
+HSPLandroidx/compose/material3/tokens/TypeScaleTokens;->getLabelMediumLineHeight-XSAIIZE()J
+HSPLandroidx/compose/material3/tokens/TypeScaleTokens;->getLabelMediumSize-XSAIIZE()J
+HSPLandroidx/compose/material3/tokens/TypeScaleTokens;->getLabelMediumTracking-XSAIIZE()J
+HSPLandroidx/compose/material3/tokens/TypeScaleTokens;->getLabelMediumWeight()Landroidx/compose/ui/text/font/FontWeight;
+HSPLandroidx/compose/material3/tokens/TypeScaleTokens;->getLabelSmallFont()Landroidx/compose/ui/text/font/GenericFontFamily;
+HSPLandroidx/compose/material3/tokens/TypeScaleTokens;->getLabelSmallLineHeight-XSAIIZE()J
+HSPLandroidx/compose/material3/tokens/TypeScaleTokens;->getLabelSmallSize-XSAIIZE()J
+HSPLandroidx/compose/material3/tokens/TypeScaleTokens;->getLabelSmallTracking-XSAIIZE()J
+HSPLandroidx/compose/material3/tokens/TypeScaleTokens;->getLabelSmallWeight()Landroidx/compose/ui/text/font/FontWeight;
+HSPLandroidx/compose/material3/tokens/TypeScaleTokens;->getTitleLargeFont()Landroidx/compose/ui/text/font/GenericFontFamily;
+HSPLandroidx/compose/material3/tokens/TypeScaleTokens;->getTitleLargeLineHeight-XSAIIZE()J
+HSPLandroidx/compose/material3/tokens/TypeScaleTokens;->getTitleLargeSize-XSAIIZE()J
+HSPLandroidx/compose/material3/tokens/TypeScaleTokens;->getTitleLargeTracking-XSAIIZE()J
+HSPLandroidx/compose/material3/tokens/TypeScaleTokens;->getTitleLargeWeight()Landroidx/compose/ui/text/font/FontWeight;
+HSPLandroidx/compose/material3/tokens/TypeScaleTokens;->getTitleMediumFont()Landroidx/compose/ui/text/font/GenericFontFamily;
+HSPLandroidx/compose/material3/tokens/TypeScaleTokens;->getTitleMediumLineHeight-XSAIIZE()J
+HSPLandroidx/compose/material3/tokens/TypeScaleTokens;->getTitleMediumSize-XSAIIZE()J
+HSPLandroidx/compose/material3/tokens/TypeScaleTokens;->getTitleMediumTracking-XSAIIZE()J
+HSPLandroidx/compose/material3/tokens/TypeScaleTokens;->getTitleMediumWeight()Landroidx/compose/ui/text/font/FontWeight;
+HSPLandroidx/compose/material3/tokens/TypeScaleTokens;->getTitleSmallFont()Landroidx/compose/ui/text/font/GenericFontFamily;
+HSPLandroidx/compose/material3/tokens/TypeScaleTokens;->getTitleSmallLineHeight-XSAIIZE()J
+HSPLandroidx/compose/material3/tokens/TypeScaleTokens;->getTitleSmallSize-XSAIIZE()J
+HSPLandroidx/compose/material3/tokens/TypeScaleTokens;->getTitleSmallTracking-XSAIIZE()J
+HSPLandroidx/compose/material3/tokens/TypeScaleTokens;->getTitleSmallWeight()Landroidx/compose/ui/text/font/FontWeight;
+HSPLandroidx/compose/material3/tokens/TypefaceTokens;-><clinit>()V
+HSPLandroidx/compose/material3/tokens/TypefaceTokens;-><init>()V
+HSPLandroidx/compose/material3/tokens/TypefaceTokens;->getBrand()Landroidx/compose/ui/text/font/GenericFontFamily;
+HSPLandroidx/compose/material3/tokens/TypefaceTokens;->getPlain()Landroidx/compose/ui/text/font/GenericFontFamily;
+HSPLandroidx/compose/material3/tokens/TypefaceTokens;->getWeightMedium()Landroidx/compose/ui/text/font/FontWeight;
+HSPLandroidx/compose/material3/tokens/TypefaceTokens;->getWeightRegular()Landroidx/compose/ui/text/font/FontWeight;
+HSPLandroidx/compose/material3/tokens/TypographyKeyTokens;->$values()[Landroidx/compose/material3/tokens/TypographyKeyTokens;
+HSPLandroidx/compose/material3/tokens/TypographyKeyTokens;-><clinit>()V
+HSPLandroidx/compose/material3/tokens/TypographyKeyTokens;-><init>(Ljava/lang/String;I)V
+HSPLandroidx/compose/material3/tokens/TypographyKeyTokens;->values()[Landroidx/compose/material3/tokens/TypographyKeyTokens;
+HSPLandroidx/compose/material3/tokens/TypographyTokens;-><clinit>()V
+HSPLandroidx/compose/material3/tokens/TypographyTokens;-><init>()V
+HSPLandroidx/compose/material3/tokens/TypographyTokens;->getBodySmall()Landroidx/compose/ui/text/TextStyle;
+HSPLandroidx/compose/material3/tokens/TypographyTokens;->getDisplayLarge()Landroidx/compose/ui/text/TextStyle;
+HSPLandroidx/compose/material3/tokens/TypographyTokens;->getDisplayMedium()Landroidx/compose/ui/text/TextStyle;
+HSPLandroidx/compose/material3/tokens/TypographyTokens;->getDisplaySmall()Landroidx/compose/ui/text/TextStyle;
+HSPLandroidx/compose/material3/tokens/TypographyTokens;->getHeadlineLarge()Landroidx/compose/ui/text/TextStyle;
+HSPLandroidx/compose/material3/tokens/TypographyTokens;->getHeadlineMedium()Landroidx/compose/ui/text/TextStyle;
+HSPLandroidx/compose/material3/tokens/TypographyTokens;->getHeadlineSmall()Landroidx/compose/ui/text/TextStyle;
+HSPLandroidx/compose/material3/tokens/TypographyTokens;->getLabelMedium()Landroidx/compose/ui/text/TextStyle;
+HSPLandroidx/compose/material3/tokens/TypographyTokens;->getLabelSmall()Landroidx/compose/ui/text/TextStyle;
+HSPLandroidx/compose/material3/tokens/TypographyTokens;->getTitleSmall()Landroidx/compose/ui/text/TextStyle;
+HSPLandroidx/compose/runtime/AbstractApplier;-><clinit>()V
+HSPLandroidx/compose/runtime/AbstractApplier;-><init>(Ljava/lang/Object;)V
+HSPLandroidx/compose/runtime/AbstractApplier;->down(Ljava/lang/Object;)V
+HSPLandroidx/compose/runtime/AbstractApplier;->getCurrent()Ljava/lang/Object;
+HSPLandroidx/compose/runtime/AbstractApplier;->getRoot()Ljava/lang/Object;
+HSPLandroidx/compose/runtime/AbstractApplier;->setCurrent(Ljava/lang/Object;)V
+HSPLandroidx/compose/runtime/AbstractApplier;->up()V
+HSPLandroidx/compose/runtime/ActualAndroid_androidKt$DefaultMonotonicFrameClock$2;-><clinit>()V
+HSPLandroidx/compose/runtime/ActualAndroid_androidKt$DefaultMonotonicFrameClock$2;-><init>()V
+HSPLandroidx/compose/runtime/ActualAndroid_androidKt;-><clinit>()V
+HSPLandroidx/compose/runtime/ActualAndroid_androidKt;->createSnapshotMutableState(Ljava/lang/Object;Landroidx/compose/runtime/SnapshotMutationPolicy;)Landroidx/compose/runtime/snapshots/SnapshotMutableState;
+HSPLandroidx/compose/runtime/ActualJvm_jvmKt;->identityHashCode(Ljava/lang/Object;)I
+HSPLandroidx/compose/runtime/ActualJvm_jvmKt;->invokeComposable(Landroidx/compose/runtime/Composer;Lkotlin/jvm/functions/Function2;)V
+HSPLandroidx/compose/runtime/ActualJvm_jvmKt;->invokeComposableForResult(Landroidx/compose/runtime/Composer;Lkotlin/jvm/functions/Function2;)Ljava/lang/Object;
+HSPLandroidx/compose/runtime/Anchor;-><init>(I)V
+HSPLandroidx/compose/runtime/Anchor;->getLocation$runtime_release()I
+HSPLandroidx/compose/runtime/Anchor;->getValid()Z
+HSPLandroidx/compose/runtime/Anchor;->setLocation$runtime_release(I)V
+HSPLandroidx/compose/runtime/Anchor;->toIndexFor(Landroidx/compose/runtime/SlotTable;)I
+HSPLandroidx/compose/runtime/Anchor;->toIndexFor(Landroidx/compose/runtime/SlotWriter;)I
+HSPLandroidx/compose/runtime/Applier;->onBeginChanges()V
+HSPLandroidx/compose/runtime/Applier;->onEndChanges()V
+HSPLandroidx/compose/runtime/BroadcastFrameClock$FrameAwaiter;-><init>(Lkotlin/jvm/functions/Function1;Lkotlin/coroutines/Continuation;)V
+HSPLandroidx/compose/runtime/BroadcastFrameClock$FrameAwaiter;->resume(J)V
+HSPLandroidx/compose/runtime/BroadcastFrameClock$withFrameNanos$2$1;-><init>(Landroidx/compose/runtime/BroadcastFrameClock;Lkotlin/jvm/internal/Ref$ObjectRef;)V
+HSPLandroidx/compose/runtime/BroadcastFrameClock;-><clinit>()V
+HSPLandroidx/compose/runtime/BroadcastFrameClock;-><init>(Lkotlin/jvm/functions/Function0;)V
+HSPLandroidx/compose/runtime/BroadcastFrameClock;->access$getAwaiters$p(Landroidx/compose/runtime/BroadcastFrameClock;)Ljava/util/List;
+HSPLandroidx/compose/runtime/BroadcastFrameClock;->access$getFailureCause$p(Landroidx/compose/runtime/BroadcastFrameClock;)Ljava/lang/Throwable;
+HSPLandroidx/compose/runtime/BroadcastFrameClock;->access$getLock$p(Landroidx/compose/runtime/BroadcastFrameClock;)Ljava/lang/Object;
+HSPLandroidx/compose/runtime/BroadcastFrameClock;->access$getOnNewAwaiters$p(Landroidx/compose/runtime/BroadcastFrameClock;)Lkotlin/jvm/functions/Function0;
+HSPLandroidx/compose/runtime/BroadcastFrameClock;->fold(Ljava/lang/Object;Lkotlin/jvm/functions/Function2;)Ljava/lang/Object;
+HSPLandroidx/compose/runtime/BroadcastFrameClock;->get(Lkotlin/coroutines/CoroutineContext$Key;)Lkotlin/coroutines/CoroutineContext$Element;
+HSPLandroidx/compose/runtime/BroadcastFrameClock;->getHasAwaiters()Z
+HSPLandroidx/compose/runtime/BroadcastFrameClock;->sendFrame(J)V
+HSPLandroidx/compose/runtime/BroadcastFrameClock;->withFrameNanos(Lkotlin/jvm/functions/Function1;Lkotlin/coroutines/Continuation;)Ljava/lang/Object;
+HSPLandroidx/compose/runtime/ComposableSingletons$CompositionKt$lambda-1$1;-><clinit>()V
+HSPLandroidx/compose/runtime/ComposableSingletons$CompositionKt$lambda-1$1;-><init>()V
+HSPLandroidx/compose/runtime/ComposableSingletons$CompositionKt$lambda-2$1;-><clinit>()V
+HSPLandroidx/compose/runtime/ComposableSingletons$CompositionKt$lambda-2$1;-><init>()V
+HSPLandroidx/compose/runtime/ComposableSingletons$CompositionKt;-><clinit>()V
+HSPLandroidx/compose/runtime/ComposableSingletons$CompositionKt;-><init>()V
+HSPLandroidx/compose/runtime/ComposableSingletons$CompositionKt;->getLambda-1$runtime_release()Lkotlin/jvm/functions/Function2;
+HSPLandroidx/compose/runtime/ComposablesKt;->getCurrentCompositeKeyHash(Landroidx/compose/runtime/Composer;I)I
+HSPLandroidx/compose/runtime/ComposablesKt;->rememberCompositionContext(Landroidx/compose/runtime/Composer;I)Landroidx/compose/runtime/CompositionContext;
+HSPLandroidx/compose/runtime/Composer$Companion$Empty$1;-><init>()V
+HSPLandroidx/compose/runtime/Composer$Companion;-><clinit>()V
+HSPLandroidx/compose/runtime/Composer$Companion;-><init>()V
+HSPLandroidx/compose/runtime/Composer$Companion;->getEmpty()Ljava/lang/Object;
+HSPLandroidx/compose/runtime/Composer;-><clinit>()V
+HSPLandroidx/compose/runtime/ComposerImpl$CompositionContextHolder;-><init>(Landroidx/compose/runtime/ComposerImpl$CompositionContextImpl;)V
+HSPLandroidx/compose/runtime/ComposerImpl$CompositionContextHolder;->getRef()Landroidx/compose/runtime/ComposerImpl$CompositionContextImpl;
+HSPLandroidx/compose/runtime/ComposerImpl$CompositionContextHolder;->onRemembered()V
+HSPLandroidx/compose/runtime/ComposerImpl$CompositionContextImpl;-><init>(Landroidx/compose/runtime/ComposerImpl;IZ)V
+HSPLandroidx/compose/runtime/ComposerImpl$CompositionContextImpl;->composeInitial$runtime_release(Landroidx/compose/runtime/ControlledComposition;Lkotlin/jvm/functions/Function2;)V
+HSPLandroidx/compose/runtime/ComposerImpl$CompositionContextImpl;->doneComposing$runtime_release()V
+HSPLandroidx/compose/runtime/ComposerImpl$CompositionContextImpl;->getCollectingParameterInformation$runtime_release()Z
+HSPLandroidx/compose/runtime/ComposerImpl$CompositionContextImpl;->getCompositionLocalScope$runtime_release()Landroidx/compose/runtime/external/kotlinx/collections/immutable/PersistentMap;
+HSPLandroidx/compose/runtime/ComposerImpl$CompositionContextImpl;->getCompositionLocalScope()Landroidx/compose/runtime/external/kotlinx/collections/immutable/PersistentMap;
+HSPLandroidx/compose/runtime/ComposerImpl$CompositionContextImpl;->getCompoundHashKey$runtime_release()I
+HSPLandroidx/compose/runtime/ComposerImpl$CompositionContextImpl;->getEffectCoroutineContext$runtime_release()Lkotlin/coroutines/CoroutineContext;
+HSPLandroidx/compose/runtime/ComposerImpl$CompositionContextImpl;->invalidate$runtime_release(Landroidx/compose/runtime/ControlledComposition;)V
+HSPLandroidx/compose/runtime/ComposerImpl$CompositionContextImpl;->registerComposer$runtime_release(Landroidx/compose/runtime/Composer;)V
+HSPLandroidx/compose/runtime/ComposerImpl$CompositionContextImpl;->setCompositionLocalScope(Landroidx/compose/runtime/external/kotlinx/collections/immutable/PersistentMap;)V
+HSPLandroidx/compose/runtime/ComposerImpl$CompositionContextImpl;->startComposing$runtime_release()V
+HSPLandroidx/compose/runtime/ComposerImpl$CompositionContextImpl;->updateCompositionLocalScope(Landroidx/compose/runtime/external/kotlinx/collections/immutable/PersistentMap;)V
+HSPLandroidx/compose/runtime/ComposerImpl$apply$operation$1;-><init>(Lkotlin/jvm/functions/Function2;Ljava/lang/Object;)V
+HSPLandroidx/compose/runtime/ComposerImpl$apply$operation$1;->invoke(Landroidx/compose/runtime/Applier;Landroidx/compose/runtime/SlotWriter;Landroidx/compose/runtime/RememberManager;)V
+HSPLandroidx/compose/runtime/ComposerImpl$apply$operation$1;->invoke(Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;
+HSPLandroidx/compose/runtime/ComposerImpl$createNode$2;-><init>(Lkotlin/jvm/functions/Function0;Landroidx/compose/runtime/Anchor;I)V
+HSPLandroidx/compose/runtime/ComposerImpl$createNode$2;->invoke(Landroidx/compose/runtime/Applier;Landroidx/compose/runtime/SlotWriter;Landroidx/compose/runtime/RememberManager;)V
+HSPLandroidx/compose/runtime/ComposerImpl$createNode$2;->invoke(Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;
+HSPLandroidx/compose/runtime/ComposerImpl$createNode$3;-><init>(Landroidx/compose/runtime/Anchor;I)V
+HSPLandroidx/compose/runtime/ComposerImpl$createNode$3;->invoke(Landroidx/compose/runtime/Applier;Landroidx/compose/runtime/SlotWriter;Landroidx/compose/runtime/RememberManager;)V
+HSPLandroidx/compose/runtime/ComposerImpl$createNode$3;->invoke(Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;
+HSPLandroidx/compose/runtime/ComposerImpl$doCompose$2$3;-><init>(Landroidx/compose/runtime/ComposerImpl;)V
+HSPLandroidx/compose/runtime/ComposerImpl$doCompose$2$4;-><init>(Landroidx/compose/runtime/ComposerImpl;)V
+HSPLandroidx/compose/runtime/ComposerImpl$doCompose$2$5;-><init>(Lkotlin/jvm/functions/Function2;Landroidx/compose/runtime/ComposerImpl;Ljava/lang/Object;)V
+HSPLandroidx/compose/runtime/ComposerImpl$doCompose$2$5;->invoke()Ljava/lang/Object;
+HSPLandroidx/compose/runtime/ComposerImpl$doCompose$2$5;->invoke()V
+HSPLandroidx/compose/runtime/ComposerImpl$doCompose$lambda$37$$inlined$sortBy$1;-><init>()V
+HSPLandroidx/compose/runtime/ComposerImpl$doCompose$lambda$37$$inlined$sortBy$1;->compare(Ljava/lang/Object;Ljava/lang/Object;)I
+HSPLandroidx/compose/runtime/ComposerImpl$endRestartGroup$1$1;-><init>(Lkotlin/jvm/functions/Function1;Landroidx/compose/runtime/ComposerImpl;)V
+HSPLandroidx/compose/runtime/ComposerImpl$endRestartGroup$1$1;->invoke(Landroidx/compose/runtime/Applier;Landroidx/compose/runtime/SlotWriter;Landroidx/compose/runtime/RememberManager;)V
+HSPLandroidx/compose/runtime/ComposerImpl$endRestartGroup$1$1;->invoke(Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;
+HSPLandroidx/compose/runtime/ComposerImpl$realizeDowns$1;-><init>([Ljava/lang/Object;)V
+HSPLandroidx/compose/runtime/ComposerImpl$realizeDowns$1;->invoke(Landroidx/compose/runtime/Applier;Landroidx/compose/runtime/SlotWriter;Landroidx/compose/runtime/RememberManager;)V
+HSPLandroidx/compose/runtime/ComposerImpl$realizeDowns$1;->invoke(Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;
+HSPLandroidx/compose/runtime/ComposerImpl$realizeOperationLocation$2;-><init>(I)V
+HSPLandroidx/compose/runtime/ComposerImpl$realizeOperationLocation$2;->invoke(Landroidx/compose/runtime/Applier;Landroidx/compose/runtime/SlotWriter;Landroidx/compose/runtime/RememberManager;)V
+HSPLandroidx/compose/runtime/ComposerImpl$realizeOperationLocation$2;->invoke(Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;
+HSPLandroidx/compose/runtime/ComposerImpl$realizeUps$1;-><init>(I)V
+HSPLandroidx/compose/runtime/ComposerImpl$realizeUps$1;->invoke(Landroidx/compose/runtime/Applier;Landroidx/compose/runtime/SlotWriter;Landroidx/compose/runtime/RememberManager;)V
+HSPLandroidx/compose/runtime/ComposerImpl$realizeUps$1;->invoke(Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;
+HSPLandroidx/compose/runtime/ComposerImpl$recordInsert$1;-><init>(Landroidx/compose/runtime/SlotTable;Landroidx/compose/runtime/Anchor;)V
+HSPLandroidx/compose/runtime/ComposerImpl$recordInsert$1;->invoke(Landroidx/compose/runtime/Applier;Landroidx/compose/runtime/SlotWriter;Landroidx/compose/runtime/RememberManager;)V
+HSPLandroidx/compose/runtime/ComposerImpl$recordInsert$1;->invoke(Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;
+HSPLandroidx/compose/runtime/ComposerImpl$recordInsert$2;-><init>(Landroidx/compose/runtime/SlotTable;Landroidx/compose/runtime/Anchor;Ljava/util/List;)V
+HSPLandroidx/compose/runtime/ComposerImpl$recordInsert$2;->invoke(Landroidx/compose/runtime/Applier;Landroidx/compose/runtime/SlotWriter;Landroidx/compose/runtime/RememberManager;)V
+HSPLandroidx/compose/runtime/ComposerImpl$recordInsert$2;->invoke(Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;
+HSPLandroidx/compose/runtime/ComposerImpl$recordSideEffect$1;-><init>(Lkotlin/jvm/functions/Function0;)V
+HSPLandroidx/compose/runtime/ComposerImpl$recordSideEffect$1;->invoke(Landroidx/compose/runtime/Applier;Landroidx/compose/runtime/SlotWriter;Landroidx/compose/runtime/RememberManager;)V
+HSPLandroidx/compose/runtime/ComposerImpl$recordSideEffect$1;->invoke(Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;
+HSPLandroidx/compose/runtime/ComposerImpl$recordSlotEditing$1;-><init>(Landroidx/compose/runtime/Anchor;)V
+HSPLandroidx/compose/runtime/ComposerImpl$recordSlotEditing$1;->invoke(Landroidx/compose/runtime/Applier;Landroidx/compose/runtime/SlotWriter;Landroidx/compose/runtime/RememberManager;)V
+HSPLandroidx/compose/runtime/ComposerImpl$recordSlotEditing$1;->invoke(Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;
+HSPLandroidx/compose/runtime/ComposerImpl$startProviders$currentProviders$1;-><init>([Landroidx/compose/runtime/ProvidedValue;Landroidx/compose/runtime/external/kotlinx/collections/immutable/PersistentMap;)V
+HSPLandroidx/compose/runtime/ComposerImpl$startProviders$currentProviders$1;->invoke(Landroidx/compose/runtime/Composer;I)Landroidx/compose/runtime/external/kotlinx/collections/immutable/PersistentMap;
+HSPLandroidx/compose/runtime/ComposerImpl$startProviders$currentProviders$1;->invoke(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;
+HSPLandroidx/compose/runtime/ComposerImpl$startReaderGroup$1;-><init>(Ljava/lang/Object;)V
+HSPLandroidx/compose/runtime/ComposerImpl$startReaderGroup$1;->invoke(Landroidx/compose/runtime/Applier;Landroidx/compose/runtime/SlotWriter;Landroidx/compose/runtime/RememberManager;)V
+HSPLandroidx/compose/runtime/ComposerImpl$startReaderGroup$1;->invoke(Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;
+HSPLandroidx/compose/runtime/ComposerImpl$updateValue$1;-><init>(Ljava/lang/Object;)V
+HSPLandroidx/compose/runtime/ComposerImpl$updateValue$1;->invoke(Landroidx/compose/runtime/Applier;Landroidx/compose/runtime/SlotWriter;Landroidx/compose/runtime/RememberManager;)V
+HSPLandroidx/compose/runtime/ComposerImpl$updateValue$1;->invoke(Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;
+HSPLandroidx/compose/runtime/ComposerImpl$updateValue$2;-><init>(Ljava/lang/Object;I)V
+HSPLandroidx/compose/runtime/ComposerImpl$updateValue$2;->invoke(Landroidx/compose/runtime/Applier;Landroidx/compose/runtime/SlotWriter;Landroidx/compose/runtime/RememberManager;)V
+HSPLandroidx/compose/runtime/ComposerImpl$updateValue$2;->invoke(Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;
+HSPLandroidx/compose/runtime/ComposerImpl;-><init>(Landroidx/compose/runtime/Applier;Landroidx/compose/runtime/CompositionContext;Landroidx/compose/runtime/SlotTable;Ljava/util/Set;Ljava/util/List;Ljava/util/List;Landroidx/compose/runtime/ControlledComposition;)V
+HSPLandroidx/compose/runtime/ComposerImpl;->access$endGroup(Landroidx/compose/runtime/ComposerImpl;)V
+HSPLandroidx/compose/runtime/ComposerImpl;->access$getChildrenComposing$p(Landroidx/compose/runtime/ComposerImpl;)I
+HSPLandroidx/compose/runtime/ComposerImpl;->access$getForciblyRecompose$p(Landroidx/compose/runtime/ComposerImpl;)Z
+HSPLandroidx/compose/runtime/ComposerImpl;->access$getParentContext$p(Landroidx/compose/runtime/ComposerImpl;)Landroidx/compose/runtime/CompositionContext;
+HSPLandroidx/compose/runtime/ComposerImpl;->access$getProvidersInvalid$p(Landroidx/compose/runtime/ComposerImpl;)Z
+HSPLandroidx/compose/runtime/ComposerImpl;->access$setChildrenComposing$p(Landroidx/compose/runtime/ComposerImpl;I)V
+HSPLandroidx/compose/runtime/ComposerImpl;->access$startGroup(Landroidx/compose/runtime/ComposerImpl;ILjava/lang/Object;)V
+HSPLandroidx/compose/runtime/ComposerImpl;->addRecomposeScope()V
+HSPLandroidx/compose/runtime/ComposerImpl;->apply(Ljava/lang/Object;Lkotlin/jvm/functions/Function2;)V
+HSPLandroidx/compose/runtime/ComposerImpl;->buildContext()Landroidx/compose/runtime/CompositionContext;
+HSPLandroidx/compose/runtime/ComposerImpl;->changed(J)Z
+HSPLandroidx/compose/runtime/ComposerImpl;->changed(Ljava/lang/Object;)Z
+HSPLandroidx/compose/runtime/ComposerImpl;->changed(Z)Z
+HSPLandroidx/compose/runtime/ComposerImpl;->changedInstance(Ljava/lang/Object;)Z
+HSPLandroidx/compose/runtime/ComposerImpl;->changesApplied$runtime_release()V
+HSPLandroidx/compose/runtime/ComposerImpl;->cleanUpCompose()V
+HSPLandroidx/compose/runtime/ComposerImpl;->clearUpdatedNodeCounts()V
+HSPLandroidx/compose/runtime/ComposerImpl;->composeContent$runtime_release(Landroidx/compose/runtime/collection/IdentityArrayMap;Lkotlin/jvm/functions/Function2;)V
+HSPLandroidx/compose/runtime/ComposerImpl;->compoundKeyOf(III)I
+HSPLandroidx/compose/runtime/ComposerImpl;->consume(Landroidx/compose/runtime/CompositionLocal;)Ljava/lang/Object;
+HSPLandroidx/compose/runtime/ComposerImpl;->createNode(Lkotlin/jvm/functions/Function0;)V
+HSPLandroidx/compose/runtime/ComposerImpl;->currentCompositionLocalScope$default(Landroidx/compose/runtime/ComposerImpl;Ljava/lang/Integer;ILjava/lang/Object;)Landroidx/compose/runtime/external/kotlinx/collections/immutable/PersistentMap;
+HSPLandroidx/compose/runtime/ComposerImpl;->currentCompositionLocalScope(Ljava/lang/Integer;)Landroidx/compose/runtime/external/kotlinx/collections/immutable/PersistentMap;
+HSPLandroidx/compose/runtime/ComposerImpl;->disableReusing()V
+HSPLandroidx/compose/runtime/ComposerImpl;->doCompose(Landroidx/compose/runtime/collection/IdentityArrayMap;Lkotlin/jvm/functions/Function2;)V
+HSPLandroidx/compose/runtime/ComposerImpl;->doRecordDownsFor(II)V
+HSPLandroidx/compose/runtime/ComposerImpl;->enableReusing()V
+HSPLandroidx/compose/runtime/ComposerImpl;->end(Z)V
+HSPLandroidx/compose/runtime/ComposerImpl;->endDefaults()V
+HSPLandroidx/compose/runtime/ComposerImpl;->endGroup()V
+HSPLandroidx/compose/runtime/ComposerImpl;->endNode()V
+HSPLandroidx/compose/runtime/ComposerImpl;->endProviders()V
+HSPLandroidx/compose/runtime/ComposerImpl;->endReplaceableGroup()V
+HSPLandroidx/compose/runtime/ComposerImpl;->endRestartGroup()Landroidx/compose/runtime/ScopeUpdateScope;
+HSPLandroidx/compose/runtime/ComposerImpl;->endReusableGroup()V
+HSPLandroidx/compose/runtime/ComposerImpl;->endRoot()V
+HSPLandroidx/compose/runtime/ComposerImpl;->ensureWriter()V
+HSPLandroidx/compose/runtime/ComposerImpl;->enterGroup(ZLandroidx/compose/runtime/Pending;)V
+HSPLandroidx/compose/runtime/ComposerImpl;->exitGroup(IZ)V
+HSPLandroidx/compose/runtime/ComposerImpl;->finalizeCompose()V
+HSPLandroidx/compose/runtime/ComposerImpl;->getApplier()Landroidx/compose/runtime/Applier;
+HSPLandroidx/compose/runtime/ComposerImpl;->getApplyCoroutineContext()Lkotlin/coroutines/CoroutineContext;
+HSPLandroidx/compose/runtime/ComposerImpl;->getAreChildrenComposing$runtime_release()Z
+HSPLandroidx/compose/runtime/ComposerImpl;->getComposition()Landroidx/compose/runtime/ControlledComposition;
+HSPLandroidx/compose/runtime/ComposerImpl;->getCompoundKeyHash()I
+HSPLandroidx/compose/runtime/ComposerImpl;->getCurrentRecomposeScope$runtime_release()Landroidx/compose/runtime/RecomposeScopeImpl;
+HSPLandroidx/compose/runtime/ComposerImpl;->getDefaultsInvalid()Z
+HSPLandroidx/compose/runtime/ComposerImpl;->getInserting()Z
+HSPLandroidx/compose/runtime/ComposerImpl;->getNode(Landroidx/compose/runtime/SlotReader;)Ljava/lang/Object;
+HSPLandroidx/compose/runtime/ComposerImpl;->getRecomposeScope()Landroidx/compose/runtime/RecomposeScope;
+HSPLandroidx/compose/runtime/ComposerImpl;->getSkipping()Z
+HSPLandroidx/compose/runtime/ComposerImpl;->groupCompoundKeyPart(Landroidx/compose/runtime/SlotReader;I)I
+HSPLandroidx/compose/runtime/ComposerImpl;->insertedGroupVirtualIndex(I)I
+HSPLandroidx/compose/runtime/ComposerImpl;->isComposing$runtime_release()Z
+HSPLandroidx/compose/runtime/ComposerImpl;->nextSlot()Ljava/lang/Object;
+HSPLandroidx/compose/runtime/ComposerImpl;->nodeIndexOf(IIII)I
+HSPLandroidx/compose/runtime/ComposerImpl;->prepareCompose$runtime_release(Lkotlin/jvm/functions/Function0;)V
+HSPLandroidx/compose/runtime/ComposerImpl;->realizeDowns()V
+HSPLandroidx/compose/runtime/ComposerImpl;->realizeDowns([Ljava/lang/Object;)V
+HSPLandroidx/compose/runtime/ComposerImpl;->realizeMovement()V
+HSPLandroidx/compose/runtime/ComposerImpl;->realizeOperationLocation$default(Landroidx/compose/runtime/ComposerImpl;ZILjava/lang/Object;)V
+HSPLandroidx/compose/runtime/ComposerImpl;->realizeOperationLocation(Z)V
+HSPLandroidx/compose/runtime/ComposerImpl;->realizeUps()V
+HSPLandroidx/compose/runtime/ComposerImpl;->recompose$runtime_release(Landroidx/compose/runtime/collection/IdentityArrayMap;)Z
+HSPLandroidx/compose/runtime/ComposerImpl;->recomposeToGroupEnd()V
+HSPLandroidx/compose/runtime/ComposerImpl;->record(Lkotlin/jvm/functions/Function3;)V
+HSPLandroidx/compose/runtime/ComposerImpl;->recordApplierOperation(Lkotlin/jvm/functions/Function3;)V
+HSPLandroidx/compose/runtime/ComposerImpl;->recordDown(Ljava/lang/Object;)V
+HSPLandroidx/compose/runtime/ComposerImpl;->recordEndGroup()V
+HSPLandroidx/compose/runtime/ComposerImpl;->recordEndRoot()V
+HSPLandroidx/compose/runtime/ComposerImpl;->recordFixup(Lkotlin/jvm/functions/Function3;)V
+HSPLandroidx/compose/runtime/ComposerImpl;->recordInsert(Landroidx/compose/runtime/Anchor;)V
+HSPLandroidx/compose/runtime/ComposerImpl;->recordInsertUpFixup(Lkotlin/jvm/functions/Function3;)V
+HSPLandroidx/compose/runtime/ComposerImpl;->recordReaderMoving(I)V
+HSPLandroidx/compose/runtime/ComposerImpl;->recordSideEffect(Lkotlin/jvm/functions/Function0;)V
+HSPLandroidx/compose/runtime/ComposerImpl;->recordSlotEditing()V
+HSPLandroidx/compose/runtime/ComposerImpl;->recordSlotEditingOperation(Lkotlin/jvm/functions/Function3;)V
+HSPLandroidx/compose/runtime/ComposerImpl;->recordSlotTableOperation$default(Landroidx/compose/runtime/ComposerImpl;ZLkotlin/jvm/functions/Function3;ILjava/lang/Object;)V
+HSPLandroidx/compose/runtime/ComposerImpl;->recordSlotTableOperation(ZLkotlin/jvm/functions/Function3;)V
+HSPLandroidx/compose/runtime/ComposerImpl;->recordUp()V
+HSPLandroidx/compose/runtime/ComposerImpl;->recordUpsAndDowns(III)V
+HSPLandroidx/compose/runtime/ComposerImpl;->recordUsed(Landroidx/compose/runtime/RecomposeScope;)V
+HSPLandroidx/compose/runtime/ComposerImpl;->registerInsertUpFixup()V
+HSPLandroidx/compose/runtime/ComposerImpl;->rememberedValue()Ljava/lang/Object;
+HSPLandroidx/compose/runtime/ComposerImpl;->resolveCompositionLocal(Landroidx/compose/runtime/CompositionLocal;Landroidx/compose/runtime/external/kotlinx/collections/immutable/PersistentMap;)Ljava/lang/Object;
+HSPLandroidx/compose/runtime/ComposerImpl;->skipCurrentGroup()V
+HSPLandroidx/compose/runtime/ComposerImpl;->skipGroup()V
+HSPLandroidx/compose/runtime/ComposerImpl;->skipReaderToGroupEnd()V
+HSPLandroidx/compose/runtime/ComposerImpl;->skipToGroupEnd()V
+HSPLandroidx/compose/runtime/ComposerImpl;->start(ILjava/lang/Object;ZLjava/lang/Object;)V
+HSPLandroidx/compose/runtime/ComposerImpl;->startDefaults()V
+HSPLandroidx/compose/runtime/ComposerImpl;->startGroup(I)V
+HSPLandroidx/compose/runtime/ComposerImpl;->startGroup(ILjava/lang/Object;)V
+HSPLandroidx/compose/runtime/ComposerImpl;->startNode()V
+HSPLandroidx/compose/runtime/ComposerImpl;->startProviders([Landroidx/compose/runtime/ProvidedValue;)V
+HSPLandroidx/compose/runtime/ComposerImpl;->startReaderGroup(ZLjava/lang/Object;)V
+HSPLandroidx/compose/runtime/ComposerImpl;->startReplaceableGroup(I)V
+HSPLandroidx/compose/runtime/ComposerImpl;->startRestartGroup(I)Landroidx/compose/runtime/Composer;
+HSPLandroidx/compose/runtime/ComposerImpl;->startReusableGroup(ILjava/lang/Object;)V
+HSPLandroidx/compose/runtime/ComposerImpl;->startReusableNode()V
+HSPLandroidx/compose/runtime/ComposerImpl;->startRoot()V
+HSPLandroidx/compose/runtime/ComposerImpl;->tryImminentInvalidation$runtime_release(Landroidx/compose/runtime/RecomposeScopeImpl;Ljava/lang/Object;)Z
+HSPLandroidx/compose/runtime/ComposerImpl;->updateCompoundKeyWhenWeEnterGroup(ILjava/lang/Object;Ljava/lang/Object;)V
+HSPLandroidx/compose/runtime/ComposerImpl;->updateCompoundKeyWhenWeEnterGroupKeyHash(I)V
+HSPLandroidx/compose/runtime/ComposerImpl;->updateCompoundKeyWhenWeExitGroup(ILjava/lang/Object;Ljava/lang/Object;)V
+HSPLandroidx/compose/runtime/ComposerImpl;->updateCompoundKeyWhenWeExitGroupKeyHash(I)V
+HSPLandroidx/compose/runtime/ComposerImpl;->updateNodeCount(II)V
+HSPLandroidx/compose/runtime/ComposerImpl;->updateNodeCountOverrides(II)V
+HSPLandroidx/compose/runtime/ComposerImpl;->updateProviderMapGroup(Landroidx/compose/runtime/external/kotlinx/collections/immutable/PersistentMap;Landroidx/compose/runtime/external/kotlinx/collections/immutable/PersistentMap;)Landroidx/compose/runtime/external/kotlinx/collections/immutable/PersistentMap;
+HSPLandroidx/compose/runtime/ComposerImpl;->updateRememberedValue(Ljava/lang/Object;)V
+HSPLandroidx/compose/runtime/ComposerImpl;->updateValue(Ljava/lang/Object;)V
+HSPLandroidx/compose/runtime/ComposerImpl;->updatedNodeCount(I)I
+HSPLandroidx/compose/runtime/ComposerImpl;->useNode()V
+HSPLandroidx/compose/runtime/ComposerImpl;->validateNodeExpected()V
+HSPLandroidx/compose/runtime/ComposerImpl;->validateNodeNotExpected()V
+HSPLandroidx/compose/runtime/ComposerKt$endGroupInstance$1;-><clinit>()V
+HSPLandroidx/compose/runtime/ComposerKt$endGroupInstance$1;-><init>()V
+HSPLandroidx/compose/runtime/ComposerKt$endGroupInstance$1;->invoke(Landroidx/compose/runtime/Applier;Landroidx/compose/runtime/SlotWriter;Landroidx/compose/runtime/RememberManager;)V
+HSPLandroidx/compose/runtime/ComposerKt$endGroupInstance$1;->invoke(Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;
+HSPLandroidx/compose/runtime/ComposerKt$removeCurrentGroupInstance$1;-><clinit>()V
+HSPLandroidx/compose/runtime/ComposerKt$removeCurrentGroupInstance$1;-><init>()V
+HSPLandroidx/compose/runtime/ComposerKt$resetSlotsInstance$1;-><clinit>()V
+HSPLandroidx/compose/runtime/ComposerKt$resetSlotsInstance$1;-><init>()V
+HSPLandroidx/compose/runtime/ComposerKt$skipToGroupEndInstance$1;-><clinit>()V
+HSPLandroidx/compose/runtime/ComposerKt$skipToGroupEndInstance$1;-><init>()V
+HSPLandroidx/compose/runtime/ComposerKt$startRootGroup$1;-><clinit>()V
+HSPLandroidx/compose/runtime/ComposerKt$startRootGroup$1;-><init>()V
+HSPLandroidx/compose/runtime/ComposerKt$startRootGroup$1;->invoke(Landroidx/compose/runtime/Applier;Landroidx/compose/runtime/SlotWriter;Landroidx/compose/runtime/RememberManager;)V
+HSPLandroidx/compose/runtime/ComposerKt$startRootGroup$1;->invoke(Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;
+HSPLandroidx/compose/runtime/ComposerKt;-><clinit>()V
+HSPLandroidx/compose/runtime/ComposerKt;->access$asBool(I)Z
+HSPLandroidx/compose/runtime/ComposerKt;->access$asInt(Z)I
+HSPLandroidx/compose/runtime/ComposerKt;->access$compositionLocalMapOf([Landroidx/compose/runtime/ProvidedValue;Landroidx/compose/runtime/external/kotlinx/collections/immutable/PersistentMap;Landroidx/compose/runtime/Composer;I)Landroidx/compose/runtime/external/kotlinx/collections/immutable/PersistentMap;
+HSPLandroidx/compose/runtime/ComposerKt;->access$firstInRange(Ljava/util/List;II)Landroidx/compose/runtime/Invalidation;
+HSPLandroidx/compose/runtime/ComposerKt;->access$getEndGroupInstance$p()Lkotlin/jvm/functions/Function3;
+HSPLandroidx/compose/runtime/ComposerKt;->access$getJoinedKey(Landroidx/compose/runtime/KeyInfo;)Ljava/lang/Object;
+HSPLandroidx/compose/runtime/ComposerKt;->access$getStartRootGroup$p()Lkotlin/jvm/functions/Function3;
+HSPLandroidx/compose/runtime/ComposerKt;->access$insertIfMissing(Ljava/util/List;ILandroidx/compose/runtime/RecomposeScopeImpl;Ljava/lang/Object;)V
+HSPLandroidx/compose/runtime/ComposerKt;->access$multiMap()Ljava/util/HashMap;
+HSPLandroidx/compose/runtime/ComposerKt;->access$nearestCommonRootOf(Landroidx/compose/runtime/SlotReader;III)I
+HSPLandroidx/compose/runtime/ComposerKt;->access$pop(Ljava/util/HashMap;Ljava/lang/Object;)Ljava/lang/Object;
+HSPLandroidx/compose/runtime/ComposerKt;->access$put(Ljava/util/HashMap;Ljava/lang/Object;Ljava/lang/Object;)Z
+HSPLandroidx/compose/runtime/ComposerKt;->access$removeLocation(Ljava/util/List;I)Landroidx/compose/runtime/Invalidation;
+HSPLandroidx/compose/runtime/ComposerKt;->asBool(I)Z
+HSPLandroidx/compose/runtime/ComposerKt;->asInt(Z)I
+HSPLandroidx/compose/runtime/ComposerKt;->compositionLocalMapOf([Landroidx/compose/runtime/ProvidedValue;Landroidx/compose/runtime/external/kotlinx/collections/immutable/PersistentMap;Landroidx/compose/runtime/Composer;I)Landroidx/compose/runtime/external/kotlinx/collections/immutable/PersistentMap;
+HSPLandroidx/compose/runtime/ComposerKt;->contains(Landroidx/compose/runtime/external/kotlinx/collections/immutable/PersistentMap;Landroidx/compose/runtime/CompositionLocal;)Z
+HSPLandroidx/compose/runtime/ComposerKt;->findInsertLocation(Ljava/util/List;I)I
+HSPLandroidx/compose/runtime/ComposerKt;->findLocation(Ljava/util/List;I)I
+HSPLandroidx/compose/runtime/ComposerKt;->firstInRange(Ljava/util/List;II)Landroidx/compose/runtime/Invalidation;
+HSPLandroidx/compose/runtime/ComposerKt;->getCompositionLocalMap()Ljava/lang/Object;
+HSPLandroidx/compose/runtime/ComposerKt;->getInvocation()Ljava/lang/Object;
+HSPLandroidx/compose/runtime/ComposerKt;->getJoinedKey(Landroidx/compose/runtime/KeyInfo;)Ljava/lang/Object;
+HSPLandroidx/compose/runtime/ComposerKt;->getProvider()Ljava/lang/Object;
+HSPLandroidx/compose/runtime/ComposerKt;->getProviderMaps()Ljava/lang/Object;
+HSPLandroidx/compose/runtime/ComposerKt;->getProviderValues()Ljava/lang/Object;
+HSPLandroidx/compose/runtime/ComposerKt;->getReference()Ljava/lang/Object;
+HSPLandroidx/compose/runtime/ComposerKt;->getValueOf(Landroidx/compose/runtime/external/kotlinx/collections/immutable/PersistentMap;Landroidx/compose/runtime/CompositionLocal;)Ljava/lang/Object;
+HSPLandroidx/compose/runtime/ComposerKt;->insertIfMissing(Ljava/util/List;ILandroidx/compose/runtime/RecomposeScopeImpl;Ljava/lang/Object;)V
+HSPLandroidx/compose/runtime/ComposerKt;->isTraceInProgress()Z
+HSPLandroidx/compose/runtime/ComposerKt;->multiMap()Ljava/util/HashMap;
+HSPLandroidx/compose/runtime/ComposerKt;->nearestCommonRootOf(Landroidx/compose/runtime/SlotReader;III)I
+HSPLandroidx/compose/runtime/ComposerKt;->pop(Ljava/util/HashMap;Ljava/lang/Object;)Ljava/lang/Object;
+HSPLandroidx/compose/runtime/ComposerKt;->put(Ljava/util/HashMap;Ljava/lang/Object;Ljava/lang/Object;)Z
+HSPLandroidx/compose/runtime/ComposerKt;->remove(Ljava/util/HashMap;Ljava/lang/Object;Ljava/lang/Object;)Lkotlin/Unit;
+HSPLandroidx/compose/runtime/ComposerKt;->removeLocation(Ljava/util/List;I)Landroidx/compose/runtime/Invalidation;
+HSPLandroidx/compose/runtime/ComposerKt;->runtimeCheck(Z)V
+HSPLandroidx/compose/runtime/CompositionContext;-><clinit>()V
+HSPLandroidx/compose/runtime/CompositionContext;-><init>()V
+HSPLandroidx/compose/runtime/CompositionContext;->doneComposing$runtime_release()V
+HSPLandroidx/compose/runtime/CompositionContext;->getCompositionLocalScope$runtime_release()Landroidx/compose/runtime/external/kotlinx/collections/immutable/PersistentMap;
+HSPLandroidx/compose/runtime/CompositionContext;->registerComposer$runtime_release(Landroidx/compose/runtime/Composer;)V
+HSPLandroidx/compose/runtime/CompositionContext;->startComposing$runtime_release()V
+HSPLandroidx/compose/runtime/CompositionContextKt;-><clinit>()V
+HSPLandroidx/compose/runtime/CompositionContextKt;->access$getEmptyCompositionLocalMap$p()Landroidx/compose/runtime/external/kotlinx/collections/immutable/PersistentMap;
+HSPLandroidx/compose/runtime/CompositionImpl$RememberEventDispatcher;-><init>(Ljava/util/Set;)V
+HSPLandroidx/compose/runtime/CompositionImpl$RememberEventDispatcher;->dispatchAbandons()V
+HSPLandroidx/compose/runtime/CompositionImpl$RememberEventDispatcher;->dispatchRememberObservers()V
+HSPLandroidx/compose/runtime/CompositionImpl$RememberEventDispatcher;->dispatchSideEffects()V
+HSPLandroidx/compose/runtime/CompositionImpl$RememberEventDispatcher;->forgetting(Landroidx/compose/runtime/RememberObserver;)V
+HSPLandroidx/compose/runtime/CompositionImpl$RememberEventDispatcher;->remembering(Landroidx/compose/runtime/RememberObserver;)V
+HSPLandroidx/compose/runtime/CompositionImpl$RememberEventDispatcher;->sideEffect(Lkotlin/jvm/functions/Function0;)V
+HSPLandroidx/compose/runtime/CompositionImpl;-><init>(Landroidx/compose/runtime/CompositionContext;Landroidx/compose/runtime/Applier;Lkotlin/coroutines/CoroutineContext;)V
+HSPLandroidx/compose/runtime/CompositionImpl;-><init>(Landroidx/compose/runtime/CompositionContext;Landroidx/compose/runtime/Applier;Lkotlin/coroutines/CoroutineContext;ILkotlin/jvm/internal/DefaultConstructorMarker;)V
+HSPLandroidx/compose/runtime/CompositionImpl;->addPendingInvalidationsLocked$invalidate(Landroidx/compose/runtime/CompositionImpl;ZLkotlin/jvm/internal/Ref$ObjectRef;Ljava/lang/Object;)V
+HSPLandroidx/compose/runtime/CompositionImpl;->addPendingInvalidationsLocked(Ljava/util/Set;Z)V
+HSPLandroidx/compose/runtime/CompositionImpl;->applyChanges()V
+HSPLandroidx/compose/runtime/CompositionImpl;->applyChangesInLocked(Ljava/util/List;)V
+HSPLandroidx/compose/runtime/CompositionImpl;->applyLateChanges()V
+HSPLandroidx/compose/runtime/CompositionImpl;->changesApplied()V
+HSPLandroidx/compose/runtime/CompositionImpl;->cleanUpDerivedStateObservations()V
+HSPLandroidx/compose/runtime/CompositionImpl;->composeContent(Lkotlin/jvm/functions/Function2;)V
+HSPLandroidx/compose/runtime/CompositionImpl;->drainPendingModificationsForCompositionLocked()V
+HSPLandroidx/compose/runtime/CompositionImpl;->drainPendingModificationsLocked()V
+HSPLandroidx/compose/runtime/CompositionImpl;->getAreChildrenComposing()Z
+HSPLandroidx/compose/runtime/CompositionImpl;->getHasInvalidations()Z
+HSPLandroidx/compose/runtime/CompositionImpl;->invalidate(Landroidx/compose/runtime/RecomposeScopeImpl;Ljava/lang/Object;)Landroidx/compose/runtime/InvalidationResult;
+HSPLandroidx/compose/runtime/CompositionImpl;->invalidateChecked(Landroidx/compose/runtime/RecomposeScopeImpl;Landroidx/compose/runtime/Anchor;Ljava/lang/Object;)Landroidx/compose/runtime/InvalidationResult;
+HSPLandroidx/compose/runtime/CompositionImpl;->invalidateScopeOfLocked(Ljava/lang/Object;)V
+HSPLandroidx/compose/runtime/CompositionImpl;->isComposing()Z
+HSPLandroidx/compose/runtime/CompositionImpl;->isDisposed()Z
+HSPLandroidx/compose/runtime/CompositionImpl;->prepareCompose(Lkotlin/jvm/functions/Function0;)V
+HSPLandroidx/compose/runtime/CompositionImpl;->recompose()Z
+HSPLandroidx/compose/runtime/CompositionImpl;->recordModificationsOf(Ljava/util/Set;)V
+HSPLandroidx/compose/runtime/CompositionImpl;->recordReadOf(Ljava/lang/Object;)V
+HSPLandroidx/compose/runtime/CompositionImpl;->recordWriteOf(Ljava/lang/Object;)V
+HSPLandroidx/compose/runtime/CompositionImpl;->removeObservation$runtime_release(Ljava/lang/Object;Landroidx/compose/runtime/RecomposeScopeImpl;)V
+HSPLandroidx/compose/runtime/CompositionImpl;->setContent(Lkotlin/jvm/functions/Function2;)V
+HSPLandroidx/compose/runtime/CompositionImpl;->takeInvalidations()Landroidx/compose/runtime/collection/IdentityArrayMap;
+HSPLandroidx/compose/runtime/CompositionKt;-><clinit>()V
+HSPLandroidx/compose/runtime/CompositionKt;->Composition(Landroidx/compose/runtime/Applier;Landroidx/compose/runtime/CompositionContext;)Landroidx/compose/runtime/Composition;
+HSPLandroidx/compose/runtime/CompositionKt;->access$addValue(Landroidx/compose/runtime/collection/IdentityArrayMap;Ljava/lang/Object;Ljava/lang/Object;)V
+HSPLandroidx/compose/runtime/CompositionKt;->access$getPendingApplyNoModifications$p()Ljava/lang/Object;
+HSPLandroidx/compose/runtime/CompositionKt;->addValue(Landroidx/compose/runtime/collection/IdentityArrayMap;Ljava/lang/Object;Ljava/lang/Object;)V
+HSPLandroidx/compose/runtime/CompositionLocal;-><init>(Lkotlin/jvm/functions/Function0;)V
+HSPLandroidx/compose/runtime/CompositionLocal;-><init>(Lkotlin/jvm/functions/Function0;Lkotlin/jvm/internal/DefaultConstructorMarker;)V
+HSPLandroidx/compose/runtime/CompositionLocal;->getDefaultValueHolder$runtime_release()Landroidx/compose/runtime/LazyValueHolder;
+HSPLandroidx/compose/runtime/CompositionLocalKt;->CompositionLocalProvider([Landroidx/compose/runtime/ProvidedValue;Lkotlin/jvm/functions/Function2;Landroidx/compose/runtime/Composer;I)V
+HSPLandroidx/compose/runtime/CompositionLocalKt;->compositionLocalOf$default(Landroidx/compose/runtime/SnapshotMutationPolicy;Lkotlin/jvm/functions/Function0;ILjava/lang/Object;)Landroidx/compose/runtime/ProvidableCompositionLocal;
+HSPLandroidx/compose/runtime/CompositionLocalKt;->compositionLocalOf(Landroidx/compose/runtime/SnapshotMutationPolicy;Lkotlin/jvm/functions/Function0;)Landroidx/compose/runtime/ProvidableCompositionLocal;
+HSPLandroidx/compose/runtime/CompositionLocalKt;->staticCompositionLocalOf(Lkotlin/jvm/functions/Function0;)Landroidx/compose/runtime/ProvidableCompositionLocal;
+HSPLandroidx/compose/runtime/CompositionScopedCoroutineScopeCanceller;-><init>(Lkotlinx/coroutines/CoroutineScope;)V
+HSPLandroidx/compose/runtime/CompositionScopedCoroutineScopeCanceller;->getCoroutineScope()Lkotlinx/coroutines/CoroutineScope;
+HSPLandroidx/compose/runtime/CompositionScopedCoroutineScopeCanceller;->onRemembered()V
+HSPLandroidx/compose/runtime/DisposableEffectImpl;-><init>(Lkotlin/jvm/functions/Function1;)V
+HSPLandroidx/compose/runtime/DisposableEffectImpl;->onForgotten()V
+HSPLandroidx/compose/runtime/DisposableEffectImpl;->onRemembered()V
+HSPLandroidx/compose/runtime/DisposableEffectScope;-><clinit>()V
+HSPLandroidx/compose/runtime/DisposableEffectScope;-><init>()V
+HSPLandroidx/compose/runtime/DynamicProvidableCompositionLocal;-><init>(Landroidx/compose/runtime/SnapshotMutationPolicy;Lkotlin/jvm/functions/Function0;)V
+HSPLandroidx/compose/runtime/DynamicProvidableCompositionLocal;->provided$runtime_release(Ljava/lang/Object;Landroidx/compose/runtime/Composer;I)Landroidx/compose/runtime/State;
+HSPLandroidx/compose/runtime/EffectsKt;-><clinit>()V
+HSPLandroidx/compose/runtime/EffectsKt;->DisposableEffect(Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;Lkotlin/jvm/functions/Function1;Landroidx/compose/runtime/Composer;I)V
+HSPLandroidx/compose/runtime/EffectsKt;->DisposableEffect(Ljava/lang/Object;Ljava/lang/Object;Lkotlin/jvm/functions/Function1;Landroidx/compose/runtime/Composer;I)V
+HSPLandroidx/compose/runtime/EffectsKt;->DisposableEffect(Ljava/lang/Object;Lkotlin/jvm/functions/Function1;Landroidx/compose/runtime/Composer;I)V
+HSPLandroidx/compose/runtime/EffectsKt;->LaunchedEffect(Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;Lkotlin/jvm/functions/Function2;Landroidx/compose/runtime/Composer;I)V
+HSPLandroidx/compose/runtime/EffectsKt;->LaunchedEffect(Ljava/lang/Object;Ljava/lang/Object;Lkotlin/jvm/functions/Function2;Landroidx/compose/runtime/Composer;I)V
+HSPLandroidx/compose/runtime/EffectsKt;->LaunchedEffect(Ljava/lang/Object;Lkotlin/jvm/functions/Function2;Landroidx/compose/runtime/Composer;I)V
+HSPLandroidx/compose/runtime/EffectsKt;->LaunchedEffect([Ljava/lang/Object;Lkotlin/jvm/functions/Function2;Landroidx/compose/runtime/Composer;I)V
+HSPLandroidx/compose/runtime/EffectsKt;->SideEffect(Lkotlin/jvm/functions/Function0;Landroidx/compose/runtime/Composer;I)V
+HSPLandroidx/compose/runtime/EffectsKt;->access$getInternalDisposableEffectScope$p()Landroidx/compose/runtime/DisposableEffectScope;
+HSPLandroidx/compose/runtime/EffectsKt;->createCompositionCoroutineScope(Lkotlin/coroutines/CoroutineContext;Landroidx/compose/runtime/Composer;)Lkotlinx/coroutines/CoroutineScope;
+HSPLandroidx/compose/runtime/GroupInfo;-><init>(III)V
+HSPLandroidx/compose/runtime/GroupInfo;->getNodeCount()I
+HSPLandroidx/compose/runtime/GroupInfo;->getNodeIndex()I
+HSPLandroidx/compose/runtime/GroupInfo;->getSlotIndex()I
+HSPLandroidx/compose/runtime/IntStack;-><init>()V
+HSPLandroidx/compose/runtime/IntStack;->clear()V
+HSPLandroidx/compose/runtime/IntStack;->getSize()I
+HSPLandroidx/compose/runtime/IntStack;->isEmpty()Z
+HSPLandroidx/compose/runtime/IntStack;->peek()I
+HSPLandroidx/compose/runtime/IntStack;->peekOr(I)I
+HSPLandroidx/compose/runtime/IntStack;->pop()I
+HSPLandroidx/compose/runtime/IntStack;->push(I)V
+HSPLandroidx/compose/runtime/Invalidation;-><init>(Landroidx/compose/runtime/RecomposeScopeImpl;ILandroidx/compose/runtime/collection/IdentityArraySet;)V
+HSPLandroidx/compose/runtime/Invalidation;->getLocation()I
+HSPLandroidx/compose/runtime/Invalidation;->getScope()Landroidx/compose/runtime/RecomposeScopeImpl;
+HSPLandroidx/compose/runtime/Invalidation;->isInvalid()Z
+HSPLandroidx/compose/runtime/Invalidation;->setInstances(Landroidx/compose/runtime/collection/IdentityArraySet;)V
+HSPLandroidx/compose/runtime/InvalidationResult;->$values()[Landroidx/compose/runtime/InvalidationResult;
+HSPLandroidx/compose/runtime/InvalidationResult;-><clinit>()V
+HSPLandroidx/compose/runtime/InvalidationResult;-><init>(Ljava/lang/String;I)V
+HSPLandroidx/compose/runtime/KeyInfo;-><init>(ILjava/lang/Object;III)V
+HSPLandroidx/compose/runtime/KeyInfo;->getKey()I
+HSPLandroidx/compose/runtime/KeyInfo;->getLocation()I
+HSPLandroidx/compose/runtime/KeyInfo;->getNodes()I
+HSPLandroidx/compose/runtime/KeyInfo;->getObjectKey()Ljava/lang/Object;
+HSPLandroidx/compose/runtime/Latch;-><init>()V
+HSPLandroidx/compose/runtime/Latch;->await(Lkotlin/coroutines/Continuation;)Ljava/lang/Object;
+HSPLandroidx/compose/runtime/Latch;->closeLatch()V
+HSPLandroidx/compose/runtime/Latch;->isOpen()Z
+HSPLandroidx/compose/runtime/Latch;->openLatch()V
+HSPLandroidx/compose/runtime/LaunchedEffectImpl;-><init>(Lkotlin/coroutines/CoroutineContext;Lkotlin/jvm/functions/Function2;)V
+HSPLandroidx/compose/runtime/LaunchedEffectImpl;->onForgotten()V
+HSPLandroidx/compose/runtime/LaunchedEffectImpl;->onRemembered()V
+HSPLandroidx/compose/runtime/LazyValueHolder;-><init>(Lkotlin/jvm/functions/Function0;)V
+HSPLandroidx/compose/runtime/LazyValueHolder;->getCurrent()Ljava/lang/Object;
+HSPLandroidx/compose/runtime/LazyValueHolder;->getValue()Ljava/lang/Object;
+HSPLandroidx/compose/runtime/MonotonicFrameClock$DefaultImpls;->fold(Landroidx/compose/runtime/MonotonicFrameClock;Ljava/lang/Object;Lkotlin/jvm/functions/Function2;)Ljava/lang/Object;
+HSPLandroidx/compose/runtime/MonotonicFrameClock$DefaultImpls;->get(Landroidx/compose/runtime/MonotonicFrameClock;Lkotlin/coroutines/CoroutineContext$Key;)Lkotlin/coroutines/CoroutineContext$Element;
+HSPLandroidx/compose/runtime/MonotonicFrameClock$DefaultImpls;->minusKey(Landroidx/compose/runtime/MonotonicFrameClock;Lkotlin/coroutines/CoroutineContext$Key;)Lkotlin/coroutines/CoroutineContext;
+HSPLandroidx/compose/runtime/MonotonicFrameClock$Key;-><clinit>()V
+HSPLandroidx/compose/runtime/MonotonicFrameClock$Key;-><init>()V
+HSPLandroidx/compose/runtime/MonotonicFrameClock;-><clinit>()V
+HSPLandroidx/compose/runtime/MonotonicFrameClock;->getKey()Lkotlin/coroutines/CoroutineContext$Key;
+HSPLandroidx/compose/runtime/MonotonicFrameClockKt;->getMonotonicFrameClock(Lkotlin/coroutines/CoroutineContext;)Landroidx/compose/runtime/MonotonicFrameClock;
+HSPLandroidx/compose/runtime/MonotonicFrameClockKt;->withFrameNanos(Lkotlin/jvm/functions/Function1;Lkotlin/coroutines/Continuation;)Ljava/lang/Object;
+HSPLandroidx/compose/runtime/NeverEqualPolicy;-><clinit>()V
+HSPLandroidx/compose/runtime/NeverEqualPolicy;-><init>()V
+HSPLandroidx/compose/runtime/NeverEqualPolicy;->equivalent(Ljava/lang/Object;Ljava/lang/Object;)Z
+HSPLandroidx/compose/runtime/OpaqueKey;-><init>(Ljava/lang/String;)V
+HSPLandroidx/compose/runtime/OpaqueKey;->equals(Ljava/lang/Object;)Z
+HSPLandroidx/compose/runtime/OpaqueKey;->hashCode()I
+HSPLandroidx/compose/runtime/ParcelableSnapshotMutableState$Companion$CREATOR$1;-><init>()V
+HSPLandroidx/compose/runtime/ParcelableSnapshotMutableState$Companion;-><init>()V
+HSPLandroidx/compose/runtime/ParcelableSnapshotMutableState$Companion;-><init>(Lkotlin/jvm/internal/DefaultConstructorMarker;)V
+HSPLandroidx/compose/runtime/ParcelableSnapshotMutableState;-><clinit>()V
+HSPLandroidx/compose/runtime/ParcelableSnapshotMutableState;-><init>(Ljava/lang/Object;Landroidx/compose/runtime/SnapshotMutationPolicy;)V
+HSPLandroidx/compose/runtime/PausableMonotonicFrameClock$withFrameNanos$1;-><init>(Landroidx/compose/runtime/PausableMonotonicFrameClock;Lkotlin/coroutines/Continuation;)V
+HSPLandroidx/compose/runtime/PausableMonotonicFrameClock$withFrameNanos$1;->invokeSuspend(Ljava/lang/Object;)Ljava/lang/Object;
+HSPLandroidx/compose/runtime/PausableMonotonicFrameClock;-><clinit>()V
+HSPLandroidx/compose/runtime/PausableMonotonicFrameClock;-><init>(Landroidx/compose/runtime/MonotonicFrameClock;)V
+HSPLandroidx/compose/runtime/PausableMonotonicFrameClock;->fold(Ljava/lang/Object;Lkotlin/jvm/functions/Function2;)Ljava/lang/Object;
+HSPLandroidx/compose/runtime/PausableMonotonicFrameClock;->get(Lkotlin/coroutines/CoroutineContext$Key;)Lkotlin/coroutines/CoroutineContext$Element;
+HSPLandroidx/compose/runtime/PausableMonotonicFrameClock;->minusKey(Lkotlin/coroutines/CoroutineContext$Key;)Lkotlin/coroutines/CoroutineContext;
+HSPLandroidx/compose/runtime/PausableMonotonicFrameClock;->pause()V
+HSPLandroidx/compose/runtime/PausableMonotonicFrameClock;->resume()V
+HSPLandroidx/compose/runtime/PausableMonotonicFrameClock;->withFrameNanos(Lkotlin/jvm/functions/Function1;Lkotlin/coroutines/Continuation;)Ljava/lang/Object;
+HSPLandroidx/compose/runtime/Pending$keyMap$2;-><init>(Landroidx/compose/runtime/Pending;)V
+HSPLandroidx/compose/runtime/Pending$keyMap$2;->invoke()Ljava/lang/Object;
+HSPLandroidx/compose/runtime/Pending$keyMap$2;->invoke()Ljava/util/HashMap;
+HSPLandroidx/compose/runtime/Pending;-><init>(Ljava/util/List;I)V
+HSPLandroidx/compose/runtime/Pending;->getGroupIndex()I
+HSPLandroidx/compose/runtime/Pending;->getKeyInfos()Ljava/util/List;
+HSPLandroidx/compose/runtime/Pending;->getKeyMap()Ljava/util/HashMap;
+HSPLandroidx/compose/runtime/Pending;->getNext(ILjava/lang/Object;)Landroidx/compose/runtime/KeyInfo;
+HSPLandroidx/compose/runtime/Pending;->getStartIndex()I
+HSPLandroidx/compose/runtime/Pending;->getUsed()Ljava/util/List;
+HSPLandroidx/compose/runtime/Pending;->nodePositionOf(Landroidx/compose/runtime/KeyInfo;)I
+HSPLandroidx/compose/runtime/Pending;->recordUsed(Landroidx/compose/runtime/KeyInfo;)Z
+HSPLandroidx/compose/runtime/Pending;->registerInsert(Landroidx/compose/runtime/KeyInfo;I)V
+HSPLandroidx/compose/runtime/Pending;->registerMoveSlot(II)V
+HSPLandroidx/compose/runtime/Pending;->setGroupIndex(I)V
+HSPLandroidx/compose/runtime/Pending;->slotPositionOf(Landroidx/compose/runtime/KeyInfo;)I
+HSPLandroidx/compose/runtime/Pending;->updatedNodeCountOf(Landroidx/compose/runtime/KeyInfo;)I
+HSPLandroidx/compose/runtime/PrioritySet;-><init>(Ljava/util/List;)V
+HSPLandroidx/compose/runtime/PrioritySet;-><init>(Ljava/util/List;ILkotlin/jvm/internal/DefaultConstructorMarker;)V
+HSPLandroidx/compose/runtime/PrioritySet;->add(I)V
+HSPLandroidx/compose/runtime/PrioritySet;->isNotEmpty()Z
+HSPLandroidx/compose/runtime/PrioritySet;->takeMax()I
+HSPLandroidx/compose/runtime/ProvidableCompositionLocal;-><init>(Lkotlin/jvm/functions/Function0;)V
+HSPLandroidx/compose/runtime/ProvidableCompositionLocal;->provides(Ljava/lang/Object;)Landroidx/compose/runtime/ProvidedValue;
+HSPLandroidx/compose/runtime/ProvidableCompositionLocal;->providesDefault(Ljava/lang/Object;)Landroidx/compose/runtime/ProvidedValue;
+HSPLandroidx/compose/runtime/ProvidedValue;-><clinit>()V
+HSPLandroidx/compose/runtime/ProvidedValue;-><init>(Landroidx/compose/runtime/CompositionLocal;Ljava/lang/Object;Z)V
+HSPLandroidx/compose/runtime/ProvidedValue;->getCanOverride()Z
+HSPLandroidx/compose/runtime/ProvidedValue;->getCompositionLocal()Landroidx/compose/runtime/CompositionLocal;
+HSPLandroidx/compose/runtime/ProvidedValue;->getValue()Ljava/lang/Object;
+HSPLandroidx/compose/runtime/RecomposeScopeImpl$end$1$2;-><init>(Landroidx/compose/runtime/RecomposeScopeImpl;ILandroidx/compose/runtime/collection/IdentityArrayIntMap;)V
+HSPLandroidx/compose/runtime/RecomposeScopeImpl$end$1$2;->invoke(Landroidx/compose/runtime/Composition;)V
+HSPLandroidx/compose/runtime/RecomposeScopeImpl$end$1$2;->invoke(Ljava/lang/Object;)Ljava/lang/Object;
+HSPLandroidx/compose/runtime/RecomposeScopeImpl;-><init>(Landroidx/compose/runtime/CompositionImpl;)V
+HSPLandroidx/compose/runtime/RecomposeScopeImpl;->access$getCurrentToken$p(Landroidx/compose/runtime/RecomposeScopeImpl;)I
+HSPLandroidx/compose/runtime/RecomposeScopeImpl;->access$getTrackedInstances$p(Landroidx/compose/runtime/RecomposeScopeImpl;)Landroidx/compose/runtime/collection/IdentityArrayIntMap;
+HSPLandroidx/compose/runtime/RecomposeScopeImpl;->compose(Landroidx/compose/runtime/Composer;)V
+HSPLandroidx/compose/runtime/RecomposeScopeImpl;->end(I)Lkotlin/jvm/functions/Function1;
+HSPLandroidx/compose/runtime/RecomposeScopeImpl;->getAnchor()Landroidx/compose/runtime/Anchor;
+HSPLandroidx/compose/runtime/RecomposeScopeImpl;->getCanRecompose()Z
+HSPLandroidx/compose/runtime/RecomposeScopeImpl;->getDefaultsInScope()Z
+HSPLandroidx/compose/runtime/RecomposeScopeImpl;->getDefaultsInvalid()Z
+HSPLandroidx/compose/runtime/RecomposeScopeImpl;->getRequiresRecompose()Z
+HSPLandroidx/compose/runtime/RecomposeScopeImpl;->getRereading()Z
+HSPLandroidx/compose/runtime/RecomposeScopeImpl;->getSkipped$runtime_release()Z
+HSPLandroidx/compose/runtime/RecomposeScopeImpl;->getUsed()Z
+HSPLandroidx/compose/runtime/RecomposeScopeImpl;->getValid()Z
+HSPLandroidx/compose/runtime/RecomposeScopeImpl;->invalidate()V
+HSPLandroidx/compose/runtime/RecomposeScopeImpl;->invalidateForResult(Ljava/lang/Object;)Landroidx/compose/runtime/InvalidationResult;
+HSPLandroidx/compose/runtime/RecomposeScopeImpl;->isConditional()Z
+HSPLandroidx/compose/runtime/RecomposeScopeImpl;->isInvalidFor(Landroidx/compose/runtime/collection/IdentityArraySet;)Z
+HSPLandroidx/compose/runtime/RecomposeScopeImpl;->recordRead(Ljava/lang/Object;)V
+HSPLandroidx/compose/runtime/RecomposeScopeImpl;->scopeSkipped()V
+HSPLandroidx/compose/runtime/RecomposeScopeImpl;->setAnchor(Landroidx/compose/runtime/Anchor;)V
+HSPLandroidx/compose/runtime/RecomposeScopeImpl;->setDefaultsInScope(Z)V
+HSPLandroidx/compose/runtime/RecomposeScopeImpl;->setDefaultsInvalid(Z)V
+HSPLandroidx/compose/runtime/RecomposeScopeImpl;->setRequiresRecompose(Z)V
+HSPLandroidx/compose/runtime/RecomposeScopeImpl;->setSkipped(Z)V
+HSPLandroidx/compose/runtime/RecomposeScopeImpl;->setUsed(Z)V
+HSPLandroidx/compose/runtime/RecomposeScopeImpl;->start(I)V
+HSPLandroidx/compose/runtime/RecomposeScopeImpl;->updateScope(Lkotlin/jvm/functions/Function2;)V
+HSPLandroidx/compose/runtime/RecomposeScopeImplKt;->updateChangedFlags(I)I
+HSPLandroidx/compose/runtime/Recomposer$Companion;-><init>()V
+HSPLandroidx/compose/runtime/Recomposer$Companion;-><init>(Lkotlin/jvm/internal/DefaultConstructorMarker;)V
+HSPLandroidx/compose/runtime/Recomposer$Companion;->access$addRunning(Landroidx/compose/runtime/Recomposer$Companion;Landroidx/compose/runtime/Recomposer$RecomposerInfoImpl;)V
+HSPLandroidx/compose/runtime/Recomposer$Companion;->addRunning(Landroidx/compose/runtime/Recomposer$RecomposerInfoImpl;)V
+HSPLandroidx/compose/runtime/Recomposer$RecomposerInfoImpl;-><init>(Landroidx/compose/runtime/Recomposer;)V
+HSPLandroidx/compose/runtime/Recomposer$State;->$values()[Landroidx/compose/runtime/Recomposer$State;
+HSPLandroidx/compose/runtime/Recomposer$State;-><clinit>()V
+HSPLandroidx/compose/runtime/Recomposer$State;-><init>(Ljava/lang/String;I)V
+HSPLandroidx/compose/runtime/Recomposer$broadcastFrameClock$1;-><init>(Landroidx/compose/runtime/Recomposer;)V
+HSPLandroidx/compose/runtime/Recomposer$broadcastFrameClock$1;->invoke()Ljava/lang/Object;
+HSPLandroidx/compose/runtime/Recomposer$broadcastFrameClock$1;->invoke()V
+HSPLandroidx/compose/runtime/Recomposer$effectJob$1$1;-><init>(Landroidx/compose/runtime/Recomposer;)V
+HSPLandroidx/compose/runtime/Recomposer$join$2;-><init>(Lkotlin/coroutines/Continuation;)V
+HSPLandroidx/compose/runtime/Recomposer$join$2;->create(Ljava/lang/Object;Lkotlin/coroutines/Continuation;)Lkotlin/coroutines/Continuation;
+HSPLandroidx/compose/runtime/Recomposer$join$2;->invoke(Landroidx/compose/runtime/Recomposer$State;Lkotlin/coroutines/Continuation;)Ljava/lang/Object;
+HSPLandroidx/compose/runtime/Recomposer$join$2;->invoke(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;
+HSPLandroidx/compose/runtime/Recomposer$join$2;->invokeSuspend(Ljava/lang/Object;)Ljava/lang/Object;
+HSPLandroidx/compose/runtime/Recomposer$performRecompose$1$1;-><init>(Landroidx/compose/runtime/collection/IdentityArraySet;Landroidx/compose/runtime/ControlledComposition;)V
+HSPLandroidx/compose/runtime/Recomposer$performRecompose$1$1;->invoke()Ljava/lang/Object;
+HSPLandroidx/compose/runtime/Recomposer$performRecompose$1$1;->invoke()V
+HSPLandroidx/compose/runtime/Recomposer$readObserverOf$1;-><init>(Landroidx/compose/runtime/ControlledComposition;)V
+HSPLandroidx/compose/runtime/Recomposer$readObserverOf$1;->invoke(Ljava/lang/Object;)Ljava/lang/Object;
+HSPLandroidx/compose/runtime/Recomposer$readObserverOf$1;->invoke(Ljava/lang/Object;)V
+HSPLandroidx/compose/runtime/Recomposer$recompositionRunner$2$2;-><init>(Lkotlin/jvm/functions/Function3;Landroidx/compose/runtime/MonotonicFrameClock;Lkotlin/coroutines/Continuation;)V
+HSPLandroidx/compose/runtime/Recomposer$recompositionRunner$2$2;->create(Ljava/lang/Object;Lkotlin/coroutines/Continuation;)Lkotlin/coroutines/Continuation;
+HSPLandroidx/compose/runtime/Recomposer$recompositionRunner$2$2;->invoke(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;
+HSPLandroidx/compose/runtime/Recomposer$recompositionRunner$2$2;->invoke(Lkotlinx/coroutines/CoroutineScope;Lkotlin/coroutines/Continuation;)Ljava/lang/Object;
+HSPLandroidx/compose/runtime/Recomposer$recompositionRunner$2$2;->invokeSuspend(Ljava/lang/Object;)Ljava/lang/Object;
+HSPLandroidx/compose/runtime/Recomposer$recompositionRunner$2$unregisterApplyObserver$1;-><init>(Landroidx/compose/runtime/Recomposer;)V
+HSPLandroidx/compose/runtime/Recomposer$recompositionRunner$2$unregisterApplyObserver$1;->invoke(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;
+HSPLandroidx/compose/runtime/Recomposer$recompositionRunner$2$unregisterApplyObserver$1;->invoke(Ljava/util/Set;Landroidx/compose/runtime/snapshots/Snapshot;)V
+HSPLandroidx/compose/runtime/Recomposer$recompositionRunner$2;-><init>(Landroidx/compose/runtime/Recomposer;Lkotlin/jvm/functions/Function3;Landroidx/compose/runtime/MonotonicFrameClock;Lkotlin/coroutines/Continuation;)V
+HSPLandroidx/compose/runtime/Recomposer$recompositionRunner$2;->create(Ljava/lang/Object;Lkotlin/coroutines/Continuation;)Lkotlin/coroutines/Continuation;
+HSPLandroidx/compose/runtime/Recomposer$recompositionRunner$2;->invoke(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;
+HSPLandroidx/compose/runtime/Recomposer$recompositionRunner$2;->invoke(Lkotlinx/coroutines/CoroutineScope;Lkotlin/coroutines/Continuation;)Ljava/lang/Object;
+HSPLandroidx/compose/runtime/Recomposer$recompositionRunner$2;->invokeSuspend(Ljava/lang/Object;)Ljava/lang/Object;
+HSPLandroidx/compose/runtime/Recomposer$runRecomposeAndApplyChanges$2$2;-><init>(Landroidx/compose/runtime/Recomposer;Ljava/util/List;Ljava/util/List;Ljava/util/Set;Ljava/util/List;Ljava/util/Set;)V
+HSPLandroidx/compose/runtime/Recomposer$runRecomposeAndApplyChanges$2$2;->invoke(J)V
+HSPLandroidx/compose/runtime/Recomposer$runRecomposeAndApplyChanges$2$2;->invoke(Ljava/lang/Object;)Ljava/lang/Object;
+HSPLandroidx/compose/runtime/Recomposer$runRecomposeAndApplyChanges$2;-><init>(Landroidx/compose/runtime/Recomposer;Lkotlin/coroutines/Continuation;)V
+HSPLandroidx/compose/runtime/Recomposer$runRecomposeAndApplyChanges$2;->access$invokeSuspend$fillToInsert(Ljava/util/List;Landroidx/compose/runtime/Recomposer;)V
+HSPLandroidx/compose/runtime/Recomposer$runRecomposeAndApplyChanges$2;->invoke(Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;
+HSPLandroidx/compose/runtime/Recomposer$runRecomposeAndApplyChanges$2;->invoke(Lkotlinx/coroutines/CoroutineScope;Landroidx/compose/runtime/MonotonicFrameClock;Lkotlin/coroutines/Continuation;)Ljava/lang/Object;
+HSPLandroidx/compose/runtime/Recomposer$runRecomposeAndApplyChanges$2;->invokeSuspend$fillToInsert(Ljava/util/List;Landroidx/compose/runtime/Recomposer;)V
+HSPLandroidx/compose/runtime/Recomposer$runRecomposeAndApplyChanges$2;->invokeSuspend(Ljava/lang/Object;)Ljava/lang/Object;
+HSPLandroidx/compose/runtime/Recomposer$writeObserverOf$1;-><init>(Landroidx/compose/runtime/ControlledComposition;Landroidx/compose/runtime/collection/IdentityArraySet;)V
+HSPLandroidx/compose/runtime/Recomposer$writeObserverOf$1;->invoke(Ljava/lang/Object;)Ljava/lang/Object;
+HSPLandroidx/compose/runtime/Recomposer$writeObserverOf$1;->invoke(Ljava/lang/Object;)V
+HSPLandroidx/compose/runtime/Recomposer;-><clinit>()V
+HSPLandroidx/compose/runtime/Recomposer;-><init>(Lkotlin/coroutines/CoroutineContext;)V
+HSPLandroidx/compose/runtime/Recomposer;->access$awaitWorkAvailable(Landroidx/compose/runtime/Recomposer;Lkotlin/coroutines/Continuation;)Ljava/lang/Object;
+HSPLandroidx/compose/runtime/Recomposer;->access$deriveStateLocked(Landroidx/compose/runtime/Recomposer;)Lkotlinx/coroutines/CancellableContinuation;
+HSPLandroidx/compose/runtime/Recomposer;->access$discardUnusedValues(Landroidx/compose/runtime/Recomposer;)V
+HSPLandroidx/compose/runtime/Recomposer;->access$getBroadcastFrameClock$p(Landroidx/compose/runtime/Recomposer;)Landroidx/compose/runtime/BroadcastFrameClock;
+HSPLandroidx/compose/runtime/Recomposer;->access$getCompositionInvalidations$p(Landroidx/compose/runtime/Recomposer;)Ljava/util/List;
+HSPLandroidx/compose/runtime/Recomposer;->access$getCompositionValuesAwaitingInsert$p(Landroidx/compose/runtime/Recomposer;)Ljava/util/List;
+HSPLandroidx/compose/runtime/Recomposer;->access$getHasFrameWorkLocked(Landroidx/compose/runtime/Recomposer;)Z
+HSPLandroidx/compose/runtime/Recomposer;->access$getHasSchedulingWork(Landroidx/compose/runtime/Recomposer;)Z
+HSPLandroidx/compose/runtime/Recomposer;->access$getKnownCompositions$p(Landroidx/compose/runtime/Recomposer;)Ljava/util/List;
+HSPLandroidx/compose/runtime/Recomposer;->access$getRecomposerInfo$p(Landroidx/compose/runtime/Recomposer;)Landroidx/compose/runtime/Recomposer$RecomposerInfoImpl;
+HSPLandroidx/compose/runtime/Recomposer;->access$getShouldKeepRecomposing(Landroidx/compose/runtime/Recomposer;)Z
+HSPLandroidx/compose/runtime/Recomposer;->access$getSnapshotInvalidations$p(Landroidx/compose/runtime/Recomposer;)Ljava/util/Set;
+HSPLandroidx/compose/runtime/Recomposer;->access$getStateLock$p(Landroidx/compose/runtime/Recomposer;)Ljava/lang/Object;
+HSPLandroidx/compose/runtime/Recomposer;->access$get_runningRecomposers$cp()Lkotlinx/coroutines/flow/MutableStateFlow;
+HSPLandroidx/compose/runtime/Recomposer;->access$get_state$p(Landroidx/compose/runtime/Recomposer;)Lkotlinx/coroutines/flow/MutableStateFlow;
+HSPLandroidx/compose/runtime/Recomposer;->access$performRecompose(Landroidx/compose/runtime/Recomposer;Landroidx/compose/runtime/ControlledComposition;Landroidx/compose/runtime/collection/IdentityArraySet;)Landroidx/compose/runtime/ControlledComposition;
+HSPLandroidx/compose/runtime/Recomposer;->access$recordComposerModificationsLocked(Landroidx/compose/runtime/Recomposer;)V
+HSPLandroidx/compose/runtime/Recomposer;->access$registerRunnerJob(Landroidx/compose/runtime/Recomposer;Lkotlinx/coroutines/Job;)V
+HSPLandroidx/compose/runtime/Recomposer;->access$setChangeCount$p(Landroidx/compose/runtime/Recomposer;J)V
+HSPLandroidx/compose/runtime/Recomposer;->access$setWorkContinuation$p(Landroidx/compose/runtime/Recomposer;Lkotlinx/coroutines/CancellableContinuation;)V
+HSPLandroidx/compose/runtime/Recomposer;->applyAndCheck(Landroidx/compose/runtime/snapshots/MutableSnapshot;)V
+HSPLandroidx/compose/runtime/Recomposer;->awaitWorkAvailable(Lkotlin/coroutines/Continuation;)Ljava/lang/Object;
+HSPLandroidx/compose/runtime/Recomposer;->composeInitial$runtime_release(Landroidx/compose/runtime/ControlledComposition;Lkotlin/jvm/functions/Function2;)V
+HSPLandroidx/compose/runtime/Recomposer;->deriveStateLocked()Lkotlinx/coroutines/CancellableContinuation;
+HSPLandroidx/compose/runtime/Recomposer;->discardUnusedValues()V
+HSPLandroidx/compose/runtime/Recomposer;->getChangeCount()J
+HSPLandroidx/compose/runtime/Recomposer;->getCollectingParameterInformation$runtime_release()Z
+HSPLandroidx/compose/runtime/Recomposer;->getCompoundHashKey$runtime_release()I
+HSPLandroidx/compose/runtime/Recomposer;->getCurrentState()Lkotlinx/coroutines/flow/StateFlow;
+HSPLandroidx/compose/runtime/Recomposer;->getEffectCoroutineContext$runtime_release()Lkotlin/coroutines/CoroutineContext;
+HSPLandroidx/compose/runtime/Recomposer;->getHasFrameWorkLocked()Z
+HSPLandroidx/compose/runtime/Recomposer;->getHasSchedulingWork()Z
+HSPLandroidx/compose/runtime/Recomposer;->getShouldKeepRecomposing()Z
+HSPLandroidx/compose/runtime/Recomposer;->invalidate$runtime_release(Landroidx/compose/runtime/ControlledComposition;)V
+HSPLandroidx/compose/runtime/Recomposer;->join(Lkotlin/coroutines/Continuation;)Ljava/lang/Object;
+HSPLandroidx/compose/runtime/Recomposer;->performInitialMovableContentInserts(Landroidx/compose/runtime/ControlledComposition;)V
+HSPLandroidx/compose/runtime/Recomposer;->performRecompose(Landroidx/compose/runtime/ControlledComposition;Landroidx/compose/runtime/collection/IdentityArraySet;)Landroidx/compose/runtime/ControlledComposition;
+HSPLandroidx/compose/runtime/Recomposer;->readObserverOf(Landroidx/compose/runtime/ControlledComposition;)Lkotlin/jvm/functions/Function1;
+HSPLandroidx/compose/runtime/Recomposer;->recompositionRunner(Lkotlin/jvm/functions/Function3;Lkotlin/coroutines/Continuation;)Ljava/lang/Object;
+HSPLandroidx/compose/runtime/Recomposer;->recordComposerModificationsLocked()V
+HSPLandroidx/compose/runtime/Recomposer;->registerRunnerJob(Lkotlinx/coroutines/Job;)V
+HSPLandroidx/compose/runtime/Recomposer;->runRecomposeAndApplyChanges(Lkotlin/coroutines/Continuation;)Ljava/lang/Object;
+HSPLandroidx/compose/runtime/Recomposer;->writeObserverOf(Landroidx/compose/runtime/ControlledComposition;Landroidx/compose/runtime/collection/IdentityArraySet;)Lkotlin/jvm/functions/Function1;
+HSPLandroidx/compose/runtime/ReferentialEqualityPolicy;-><clinit>()V
+HSPLandroidx/compose/runtime/ReferentialEqualityPolicy;-><init>()V
+HSPLandroidx/compose/runtime/SkippableUpdater;-><init>(Landroidx/compose/runtime/Composer;)V
+HSPLandroidx/compose/runtime/SkippableUpdater;->box-impl(Landroidx/compose/runtime/Composer;)Landroidx/compose/runtime/SkippableUpdater;
+HSPLandroidx/compose/runtime/SkippableUpdater;->constructor-impl(Landroidx/compose/runtime/Composer;)Landroidx/compose/runtime/Composer;
+HSPLandroidx/compose/runtime/SkippableUpdater;->unbox-impl()Landroidx/compose/runtime/Composer;
+HSPLandroidx/compose/runtime/SlotReader;-><init>(Landroidx/compose/runtime/SlotTable;)V
+HSPLandroidx/compose/runtime/SlotReader;->anchor(I)Landroidx/compose/runtime/Anchor;
+HSPLandroidx/compose/runtime/SlotReader;->aux([II)Ljava/lang/Object;
+HSPLandroidx/compose/runtime/SlotReader;->beginEmpty()V
+HSPLandroidx/compose/runtime/SlotReader;->close()V
+HSPLandroidx/compose/runtime/SlotReader;->endEmpty()V
+HSPLandroidx/compose/runtime/SlotReader;->endGroup()V
+HSPLandroidx/compose/runtime/SlotReader;->extractKeys()Ljava/util/List;
+HSPLandroidx/compose/runtime/SlotReader;->getCurrentGroup()I
+HSPLandroidx/compose/runtime/SlotReader;->getGroupAux()Ljava/lang/Object;
+HSPLandroidx/compose/runtime/SlotReader;->getGroupEnd()I
+HSPLandroidx/compose/runtime/SlotReader;->getGroupKey()I
+HSPLandroidx/compose/runtime/SlotReader;->getGroupObjectKey()Ljava/lang/Object;
+HSPLandroidx/compose/runtime/SlotReader;->getGroupSlotIndex()I
+HSPLandroidx/compose/runtime/SlotReader;->getInEmpty()Z
+HSPLandroidx/compose/runtime/SlotReader;->getParent()I
+HSPLandroidx/compose/runtime/SlotReader;->getParentNodes()I
+HSPLandroidx/compose/runtime/SlotReader;->getSize()I
+HSPLandroidx/compose/runtime/SlotReader;->getTable$runtime_release()Landroidx/compose/runtime/SlotTable;
+HSPLandroidx/compose/runtime/SlotReader;->groupAux(I)Ljava/lang/Object;
+HSPLandroidx/compose/runtime/SlotReader;->groupGet(I)Ljava/lang/Object;
+HSPLandroidx/compose/runtime/SlotReader;->groupGet(II)Ljava/lang/Object;
+HSPLandroidx/compose/runtime/SlotReader;->groupKey(I)I
+HSPLandroidx/compose/runtime/SlotReader;->groupObjectKey(I)Ljava/lang/Object;
+HSPLandroidx/compose/runtime/SlotReader;->groupSize(I)I
+HSPLandroidx/compose/runtime/SlotReader;->hasObjectKey(I)Z
+HSPLandroidx/compose/runtime/SlotReader;->isGroupEnd()Z
+HSPLandroidx/compose/runtime/SlotReader;->isNode()Z
+HSPLandroidx/compose/runtime/SlotReader;->isNode(I)Z
+HSPLandroidx/compose/runtime/SlotReader;->next()Ljava/lang/Object;
+HSPLandroidx/compose/runtime/SlotReader;->node(I)Ljava/lang/Object;
+HSPLandroidx/compose/runtime/SlotReader;->node([II)Ljava/lang/Object;
+HSPLandroidx/compose/runtime/SlotReader;->nodeCount(I)I
+HSPLandroidx/compose/runtime/SlotReader;->objectKey([II)Ljava/lang/Object;
+HSPLandroidx/compose/runtime/SlotReader;->parent(I)I
+HSPLandroidx/compose/runtime/SlotReader;->reposition(I)V
+HSPLandroidx/compose/runtime/SlotReader;->restoreParent(I)V
+HSPLandroidx/compose/runtime/SlotReader;->skipGroup()I
+HSPLandroidx/compose/runtime/SlotReader;->skipToGroupEnd()V
+HSPLandroidx/compose/runtime/SlotReader;->startGroup()V
+HSPLandroidx/compose/runtime/SlotReader;->startNode()V
+HSPLandroidx/compose/runtime/SlotTable;-><init>()V
+HSPLandroidx/compose/runtime/SlotTable;->anchorIndex(Landroidx/compose/runtime/Anchor;)I
+HSPLandroidx/compose/runtime/SlotTable;->close$runtime_release(Landroidx/compose/runtime/SlotReader;)V
+HSPLandroidx/compose/runtime/SlotTable;->close$runtime_release(Landroidx/compose/runtime/SlotWriter;[II[Ljava/lang/Object;ILjava/util/ArrayList;)V
+HSPLandroidx/compose/runtime/SlotTable;->getAnchors$runtime_release()Ljava/util/ArrayList;
+HSPLandroidx/compose/runtime/SlotTable;->getGroups()[I
+HSPLandroidx/compose/runtime/SlotTable;->getGroupsSize()I
+HSPLandroidx/compose/runtime/SlotTable;->getSlots()[Ljava/lang/Object;
+HSPLandroidx/compose/runtime/SlotTable;->getSlotsSize()I
+HSPLandroidx/compose/runtime/SlotTable;->isEmpty()Z
+HSPLandroidx/compose/runtime/SlotTable;->openReader()Landroidx/compose/runtime/SlotReader;
+HSPLandroidx/compose/runtime/SlotTable;->openWriter()Landroidx/compose/runtime/SlotWriter;
+HSPLandroidx/compose/runtime/SlotTable;->ownsAnchor(Landroidx/compose/runtime/Anchor;)Z
+HSPLandroidx/compose/runtime/SlotTable;->setTo$runtime_release([II[Ljava/lang/Object;ILjava/util/ArrayList;)V
+HSPLandroidx/compose/runtime/SlotTableKt;->access$auxIndex([II)I
+HSPLandroidx/compose/runtime/SlotTableKt;->access$containsAnyMark([II)Z
+HSPLandroidx/compose/runtime/SlotTableKt;->access$containsMark([II)Z
+HSPLandroidx/compose/runtime/SlotTableKt;->access$countOneBits(I)I
+HSPLandroidx/compose/runtime/SlotTableKt;->access$dataAnchor([II)I
+HSPLandroidx/compose/runtime/SlotTableKt;->access$groupInfo([II)I
+HSPLandroidx/compose/runtime/SlotTableKt;->access$groupSize([II)I
+HSPLandroidx/compose/runtime/SlotTableKt;->access$hasAux([II)Z
+HSPLandroidx/compose/runtime/SlotTableKt;->access$hasMark([II)Z
+HSPLandroidx/compose/runtime/SlotTableKt;->access$hasObjectKey([II)Z
+HSPLandroidx/compose/runtime/SlotTableKt;->access$initGroup([IIIZZZII)V
+HSPLandroidx/compose/runtime/SlotTableKt;->access$isNode([II)Z
+HSPLandroidx/compose/runtime/SlotTableKt;->access$key([II)I
+HSPLandroidx/compose/runtime/SlotTableKt;->access$locationOf(Ljava/util/ArrayList;II)I
+HSPLandroidx/compose/runtime/SlotTableKt;->access$nodeCount([II)I
+HSPLandroidx/compose/runtime/SlotTableKt;->access$nodeIndex([II)I
+HSPLandroidx/compose/runtime/SlotTableKt;->access$objectKeyIndex([II)I
+HSPLandroidx/compose/runtime/SlotTableKt;->access$parentAnchor([II)I
+HSPLandroidx/compose/runtime/SlotTableKt;->access$search(Ljava/util/ArrayList;II)I
+HSPLandroidx/compose/runtime/SlotTableKt;->access$slotAnchor([II)I
+HSPLandroidx/compose/runtime/SlotTableKt;->access$updateContainsMark([IIZ)V
+HSPLandroidx/compose/runtime/SlotTableKt;->access$updateDataAnchor([III)V
+HSPLandroidx/compose/runtime/SlotTableKt;->access$updateGroupSize([III)V
+HSPLandroidx/compose/runtime/SlotTableKt;->access$updateMark([IIZ)V
+HSPLandroidx/compose/runtime/SlotTableKt;->access$updateNodeCount([III)V
+HSPLandroidx/compose/runtime/SlotTableKt;->access$updateParentAnchor([III)V
+HSPLandroidx/compose/runtime/SlotTableKt;->auxIndex([II)I
+HSPLandroidx/compose/runtime/SlotTableKt;->containsAnyMark([II)Z
+HSPLandroidx/compose/runtime/SlotTableKt;->containsMark([II)Z
+HSPLandroidx/compose/runtime/SlotTableKt;->countOneBits(I)I
+HSPLandroidx/compose/runtime/SlotTableKt;->dataAnchor([II)I
+HSPLandroidx/compose/runtime/SlotTableKt;->groupInfo([II)I
+HSPLandroidx/compose/runtime/SlotTableKt;->groupSize([II)I
+HSPLandroidx/compose/runtime/SlotTableKt;->hasAux([II)Z
+HSPLandroidx/compose/runtime/SlotTableKt;->hasMark([II)Z
+HSPLandroidx/compose/runtime/SlotTableKt;->hasObjectKey([II)Z
+HSPLandroidx/compose/runtime/SlotTableKt;->initGroup([IIIZZZII)V
+HSPLandroidx/compose/runtime/SlotTableKt;->isNode([II)Z
+HSPLandroidx/compose/runtime/SlotTableKt;->key([II)I
+HSPLandroidx/compose/runtime/SlotTableKt;->locationOf(Ljava/util/ArrayList;II)I
+HSPLandroidx/compose/runtime/SlotTableKt;->nodeCount([II)I
+HSPLandroidx/compose/runtime/SlotTableKt;->nodeIndex([II)I
+HSPLandroidx/compose/runtime/SlotTableKt;->objectKeyIndex([II)I
+HSPLandroidx/compose/runtime/SlotTableKt;->parentAnchor([II)I
+HSPLandroidx/compose/runtime/SlotTableKt;->search(Ljava/util/ArrayList;II)I
+HSPLandroidx/compose/runtime/SlotTableKt;->slotAnchor([II)I
+HSPLandroidx/compose/runtime/SlotTableKt;->updateContainsMark([IIZ)V
+HSPLandroidx/compose/runtime/SlotTableKt;->updateDataAnchor([III)V
+HSPLandroidx/compose/runtime/SlotTableKt;->updateGroupSize([III)V
+HSPLandroidx/compose/runtime/SlotTableKt;->updateMark([IIZ)V
+HSPLandroidx/compose/runtime/SlotTableKt;->updateNodeCount([III)V
+HSPLandroidx/compose/runtime/SlotTableKt;->updateParentAnchor([III)V
+HSPLandroidx/compose/runtime/SlotWriter$Companion;-><init>()V
+HSPLandroidx/compose/runtime/SlotWriter$Companion;-><init>(Lkotlin/jvm/internal/DefaultConstructorMarker;)V
+HSPLandroidx/compose/runtime/SlotWriter$Companion;->access$moveGroup(Landroidx/compose/runtime/SlotWriter$Companion;Landroidx/compose/runtime/SlotWriter;ILandroidx/compose/runtime/SlotWriter;ZZ)Ljava/util/List;
+HSPLandroidx/compose/runtime/SlotWriter$Companion;->moveGroup(Landroidx/compose/runtime/SlotWriter;ILandroidx/compose/runtime/SlotWriter;ZZ)Ljava/util/List;
+HSPLandroidx/compose/runtime/SlotWriter;-><clinit>()V
+HSPLandroidx/compose/runtime/SlotWriter;-><init>(Landroidx/compose/runtime/SlotTable;)V
+HSPLandroidx/compose/runtime/SlotWriter;->access$containsAnyGroupMarks(Landroidx/compose/runtime/SlotWriter;I)Z
+HSPLandroidx/compose/runtime/SlotWriter;->access$dataIndex(Landroidx/compose/runtime/SlotWriter;I)I
+HSPLandroidx/compose/runtime/SlotWriter;->access$dataIndex(Landroidx/compose/runtime/SlotWriter;[II)I
+HSPLandroidx/compose/runtime/SlotWriter;->access$dataIndexToDataAnchor(Landroidx/compose/runtime/SlotWriter;IIII)I
+HSPLandroidx/compose/runtime/SlotWriter;->access$getAnchors$p(Landroidx/compose/runtime/SlotWriter;)Ljava/util/ArrayList;
+HSPLandroidx/compose/runtime/SlotWriter;->access$getCurrentSlot$p(Landroidx/compose/runtime/SlotWriter;)I
+HSPLandroidx/compose/runtime/SlotWriter;->access$getGroupGapStart$p(Landroidx/compose/runtime/SlotWriter;)I
+HSPLandroidx/compose/runtime/SlotWriter;->access$getGroups$p(Landroidx/compose/runtime/SlotWriter;)[I
+HSPLandroidx/compose/runtime/SlotWriter;->access$getNodeCount$p(Landroidx/compose/runtime/SlotWriter;)I
+HSPLandroidx/compose/runtime/SlotWriter;->access$getSlots$p(Landroidx/compose/runtime/SlotWriter;)[Ljava/lang/Object;
+HSPLandroidx/compose/runtime/SlotWriter;->access$getSlotsGapLen$p(Landroidx/compose/runtime/SlotWriter;)I
+HSPLandroidx/compose/runtime/SlotWriter;->access$getSlotsGapOwner$p(Landroidx/compose/runtime/SlotWriter;)I
+HSPLandroidx/compose/runtime/SlotWriter;->access$getSlotsGapStart$p(Landroidx/compose/runtime/SlotWriter;)I
+HSPLandroidx/compose/runtime/SlotWriter;->access$insertGroups(Landroidx/compose/runtime/SlotWriter;I)V
+HSPLandroidx/compose/runtime/SlotWriter;->access$insertSlots(Landroidx/compose/runtime/SlotWriter;II)V
+HSPLandroidx/compose/runtime/SlotWriter;->access$setCurrentGroup$p(Landroidx/compose/runtime/SlotWriter;I)V
+HSPLandroidx/compose/runtime/SlotWriter;->access$setCurrentSlot$p(Landroidx/compose/runtime/SlotWriter;I)V
+HSPLandroidx/compose/runtime/SlotWriter;->access$setNodeCount$p(Landroidx/compose/runtime/SlotWriter;I)V
+HSPLandroidx/compose/runtime/SlotWriter;->access$setSlotsGapOwner$p(Landroidx/compose/runtime/SlotWriter;I)V
+HSPLandroidx/compose/runtime/SlotWriter;->advanceBy(I)V
+HSPLandroidx/compose/runtime/SlotWriter;->anchor(I)Landroidx/compose/runtime/Anchor;
+HSPLandroidx/compose/runtime/SlotWriter;->anchorIndex(Landroidx/compose/runtime/Anchor;)I
+HSPLandroidx/compose/runtime/SlotWriter;->auxIndex([II)I
+HSPLandroidx/compose/runtime/SlotWriter;->beginInsert()V
+HSPLandroidx/compose/runtime/SlotWriter;->childContainsAnyMarks(I)Z
+HSPLandroidx/compose/runtime/SlotWriter;->close()V
+HSPLandroidx/compose/runtime/SlotWriter;->containsAnyGroupMarks(I)Z
+HSPLandroidx/compose/runtime/SlotWriter;->containsGroupMark(I)Z
+HSPLandroidx/compose/runtime/SlotWriter;->dataAnchorToDataIndex(III)I
+HSPLandroidx/compose/runtime/SlotWriter;->dataIndex(I)I
+HSPLandroidx/compose/runtime/SlotWriter;->dataIndex([II)I
+HSPLandroidx/compose/runtime/SlotWriter;->dataIndexToDataAddress(I)I
+HSPLandroidx/compose/runtime/SlotWriter;->dataIndexToDataAnchor(IIII)I
+HSPLandroidx/compose/runtime/SlotWriter;->endGroup()I
+HSPLandroidx/compose/runtime/SlotWriter;->endInsert()V
+HSPLandroidx/compose/runtime/SlotWriter;->ensureStarted(I)V
+HSPLandroidx/compose/runtime/SlotWriter;->ensureStarted(Landroidx/compose/runtime/Anchor;)V
+HSPLandroidx/compose/runtime/SlotWriter;->getCapacity()I
+HSPLandroidx/compose/runtime/SlotWriter;->getClosed()Z
+HSPLandroidx/compose/runtime/SlotWriter;->getCurrentGroup()I
+HSPLandroidx/compose/runtime/SlotWriter;->getParent()I
+HSPLandroidx/compose/runtime/SlotWriter;->getSize$runtime_release()I
+HSPLandroidx/compose/runtime/SlotWriter;->getTable$runtime_release()Landroidx/compose/runtime/SlotTable;
+HSPLandroidx/compose/runtime/SlotWriter;->groupAux(I)Ljava/lang/Object;
+HSPLandroidx/compose/runtime/SlotWriter;->groupIndexToAddress(I)I
+HSPLandroidx/compose/runtime/SlotWriter;->groupKey(I)I
+HSPLandroidx/compose/runtime/SlotWriter;->groupObjectKey(I)Ljava/lang/Object;
+HSPLandroidx/compose/runtime/SlotWriter;->groupSize(I)I
+HSPLandroidx/compose/runtime/SlotWriter;->insertGroups(I)V
+HSPLandroidx/compose/runtime/SlotWriter;->insertSlots(II)V
+HSPLandroidx/compose/runtime/SlotWriter;->markGroup$default(Landroidx/compose/runtime/SlotWriter;IILjava/lang/Object;)V
+HSPLandroidx/compose/runtime/SlotWriter;->markGroup(I)V
+HSPLandroidx/compose/runtime/SlotWriter;->moveFrom(Landroidx/compose/runtime/SlotTable;I)Ljava/util/List;
+HSPLandroidx/compose/runtime/SlotWriter;->moveGroupGapTo(I)V
+HSPLandroidx/compose/runtime/SlotWriter;->moveSlotGapTo(II)V+]Landroidx/compose/runtime/SlotWriter;Landroidx/compose/runtime/SlotWriter;
+HSPLandroidx/compose/runtime/SlotWriter;->node(I)Ljava/lang/Object;
+HSPLandroidx/compose/runtime/SlotWriter;->node(Landroidx/compose/runtime/Anchor;)Ljava/lang/Object;
+HSPLandroidx/compose/runtime/SlotWriter;->nodeIndex([II)I
+HSPLandroidx/compose/runtime/SlotWriter;->parent(I)I
+HSPLandroidx/compose/runtime/SlotWriter;->parent([II)I
+HSPLandroidx/compose/runtime/SlotWriter;->parentAnchorToIndex(I)I+]Landroidx/compose/runtime/SlotWriter;Landroidx/compose/runtime/SlotWriter;
+HSPLandroidx/compose/runtime/SlotWriter;->parentIndexToAnchor(II)I
+HSPLandroidx/compose/runtime/SlotWriter;->recalculateMarks()V
+HSPLandroidx/compose/runtime/SlotWriter;->removeAnchors(II)Z
+HSPLandroidx/compose/runtime/SlotWriter;->removeGroup()Z
+HSPLandroidx/compose/runtime/SlotWriter;->removeGroups(II)Z
+HSPLandroidx/compose/runtime/SlotWriter;->removeSlots(III)V
+HSPLandroidx/compose/runtime/SlotWriter;->restoreCurrentGroupEnd()I
+HSPLandroidx/compose/runtime/SlotWriter;->saveCurrentGroupEnd()V
+HSPLandroidx/compose/runtime/SlotWriter;->set(ILjava/lang/Object;)Ljava/lang/Object;
+HSPLandroidx/compose/runtime/SlotWriter;->set(Ljava/lang/Object;)V
+HSPLandroidx/compose/runtime/SlotWriter;->skip()Ljava/lang/Object;
+HSPLandroidx/compose/runtime/SlotWriter;->skipGroup()I
+HSPLandroidx/compose/runtime/SlotWriter;->skipToGroupEnd()V
+HSPLandroidx/compose/runtime/SlotWriter;->slotIndex([II)I
+HSPLandroidx/compose/runtime/SlotWriter;->startData(ILjava/lang/Object;Ljava/lang/Object;)V
+HSPLandroidx/compose/runtime/SlotWriter;->startGroup()V
+HSPLandroidx/compose/runtime/SlotWriter;->startGroup(ILjava/lang/Object;)V
+HSPLandroidx/compose/runtime/SlotWriter;->startGroup(ILjava/lang/Object;ZLjava/lang/Object;)V
+HSPLandroidx/compose/runtime/SlotWriter;->startNode(Ljava/lang/Object;)V
+HSPLandroidx/compose/runtime/SlotWriter;->update(Ljava/lang/Object;)Ljava/lang/Object;
+HSPLandroidx/compose/runtime/SlotWriter;->updateAnchors(II)V
+HSPLandroidx/compose/runtime/SlotWriter;->updateAux(Ljava/lang/Object;)V
+HSPLandroidx/compose/runtime/SlotWriter;->updateContainsMark(I)V
+HSPLandroidx/compose/runtime/SlotWriter;->updateContainsMarkNow(ILandroidx/compose/runtime/PrioritySet;)V
+HSPLandroidx/compose/runtime/SlotWriter;->updateNode(Landroidx/compose/runtime/Anchor;Ljava/lang/Object;)V
+HSPLandroidx/compose/runtime/SlotWriter;->updateNodeOfGroup(ILjava/lang/Object;)V
+HSPLandroidx/compose/runtime/SnapshotMutableStateImpl$StateStateRecord;-><init>(Ljava/lang/Object;)V
+HSPLandroidx/compose/runtime/SnapshotMutableStateImpl$StateStateRecord;->create()Landroidx/compose/runtime/snapshots/StateRecord;
+HSPLandroidx/compose/runtime/SnapshotMutableStateImpl$StateStateRecord;->getValue()Ljava/lang/Object;
+HSPLandroidx/compose/runtime/SnapshotMutableStateImpl$StateStateRecord;->setValue(Ljava/lang/Object;)V
+HSPLandroidx/compose/runtime/SnapshotMutableStateImpl;-><init>(Ljava/lang/Object;Landroidx/compose/runtime/SnapshotMutationPolicy;)V
+HSPLandroidx/compose/runtime/SnapshotMutableStateImpl;->getFirstStateRecord()Landroidx/compose/runtime/snapshots/StateRecord;
+HSPLandroidx/compose/runtime/SnapshotMutableStateImpl;->getPolicy()Landroidx/compose/runtime/SnapshotMutationPolicy;
+HSPLandroidx/compose/runtime/SnapshotMutableStateImpl;->getValue()Ljava/lang/Object;
+HSPLandroidx/compose/runtime/SnapshotMutableStateImpl;->prependStateRecord(Landroidx/compose/runtime/snapshots/StateRecord;)V
+HSPLandroidx/compose/runtime/SnapshotMutableStateImpl;->setValue(Ljava/lang/Object;)V
+HSPLandroidx/compose/runtime/SnapshotStateKt;->mutableStateListOf()Landroidx/compose/runtime/snapshots/SnapshotStateList;
+HSPLandroidx/compose/runtime/SnapshotStateKt;->mutableStateOf$default(Ljava/lang/Object;Landroidx/compose/runtime/SnapshotMutationPolicy;ILjava/lang/Object;)Landroidx/compose/runtime/MutableState;
+HSPLandroidx/compose/runtime/SnapshotStateKt;->mutableStateOf(Ljava/lang/Object;Landroidx/compose/runtime/SnapshotMutationPolicy;)Landroidx/compose/runtime/MutableState;
+HSPLandroidx/compose/runtime/SnapshotStateKt;->neverEqualPolicy()Landroidx/compose/runtime/SnapshotMutationPolicy;
+HSPLandroidx/compose/runtime/SnapshotStateKt;->observeDerivedStateRecalculations(Lkotlin/jvm/functions/Function1;Lkotlin/jvm/functions/Function1;Lkotlin/jvm/functions/Function0;)V
+HSPLandroidx/compose/runtime/SnapshotStateKt;->referentialEqualityPolicy()Landroidx/compose/runtime/SnapshotMutationPolicy;
+HSPLandroidx/compose/runtime/SnapshotStateKt;->rememberUpdatedState(Ljava/lang/Object;Landroidx/compose/runtime/Composer;I)Landroidx/compose/runtime/State;
+HSPLandroidx/compose/runtime/SnapshotStateKt;->snapshotFlow(Lkotlin/jvm/functions/Function0;)Lkotlinx/coroutines/flow/Flow;
+HSPLandroidx/compose/runtime/SnapshotStateKt;->structuralEqualityPolicy()Landroidx/compose/runtime/SnapshotMutationPolicy;
+HSPLandroidx/compose/runtime/SnapshotStateKt__DerivedStateKt;-><clinit>()V
+HSPLandroidx/compose/runtime/SnapshotStateKt__DerivedStateKt;->observeDerivedStateRecalculations(Lkotlin/jvm/functions/Function1;Lkotlin/jvm/functions/Function1;Lkotlin/jvm/functions/Function0;)V
+HSPLandroidx/compose/runtime/SnapshotStateKt__SnapshotFlowKt$snapshotFlow$1;-><init>(Lkotlin/jvm/functions/Function0;Lkotlin/coroutines/Continuation;)V
+HSPLandroidx/compose/runtime/SnapshotStateKt__SnapshotFlowKt;->snapshotFlow(Lkotlin/jvm/functions/Function0;)Lkotlinx/coroutines/flow/Flow;
+HSPLandroidx/compose/runtime/SnapshotStateKt__SnapshotMutationPolicyKt;->neverEqualPolicy()Landroidx/compose/runtime/SnapshotMutationPolicy;
+HSPLandroidx/compose/runtime/SnapshotStateKt__SnapshotMutationPolicyKt;->referentialEqualityPolicy()Landroidx/compose/runtime/SnapshotMutationPolicy;
+HSPLandroidx/compose/runtime/SnapshotStateKt__SnapshotMutationPolicyKt;->structuralEqualityPolicy()Landroidx/compose/runtime/SnapshotMutationPolicy;
+HSPLandroidx/compose/runtime/SnapshotStateKt__SnapshotStateKt;->mutableStateListOf()Landroidx/compose/runtime/snapshots/SnapshotStateList;
+HSPLandroidx/compose/runtime/SnapshotStateKt__SnapshotStateKt;->mutableStateOf$default(Ljava/lang/Object;Landroidx/compose/runtime/SnapshotMutationPolicy;ILjava/lang/Object;)Landroidx/compose/runtime/MutableState;
+HSPLandroidx/compose/runtime/SnapshotStateKt__SnapshotStateKt;->mutableStateOf(Ljava/lang/Object;Landroidx/compose/runtime/SnapshotMutationPolicy;)Landroidx/compose/runtime/MutableState;
+HSPLandroidx/compose/runtime/SnapshotStateKt__SnapshotStateKt;->rememberUpdatedState(Ljava/lang/Object;Landroidx/compose/runtime/Composer;I)Landroidx/compose/runtime/State;
+HSPLandroidx/compose/runtime/SnapshotThreadLocal;-><init>()V
+HSPLandroidx/compose/runtime/SnapshotThreadLocal;->get()Ljava/lang/Object;+]Landroidx/compose/runtime/internal/ThreadMap;Landroidx/compose/runtime/internal/ThreadMap;
+HSPLandroidx/compose/runtime/SnapshotThreadLocal;->set(Ljava/lang/Object;)V
+HSPLandroidx/compose/runtime/Stack;-><init>()V
+HSPLandroidx/compose/runtime/Stack;->clear()V
+HSPLandroidx/compose/runtime/Stack;->getSize()I
+HSPLandroidx/compose/runtime/Stack;->isEmpty()Z
+HSPLandroidx/compose/runtime/Stack;->isNotEmpty()Z
+HSPLandroidx/compose/runtime/Stack;->peek()Ljava/lang/Object;
+HSPLandroidx/compose/runtime/Stack;->pop()Ljava/lang/Object;
+HSPLandroidx/compose/runtime/Stack;->push(Ljava/lang/Object;)Z
+HSPLandroidx/compose/runtime/Stack;->toArray()[Ljava/lang/Object;
+HSPLandroidx/compose/runtime/StaticProvidableCompositionLocal;-><init>(Lkotlin/jvm/functions/Function0;)V
+HSPLandroidx/compose/runtime/StaticProvidableCompositionLocal;->provided$runtime_release(Ljava/lang/Object;Landroidx/compose/runtime/Composer;I)Landroidx/compose/runtime/State;
+HSPLandroidx/compose/runtime/StaticValueHolder;-><init>(Ljava/lang/Object;)V
+HSPLandroidx/compose/runtime/StaticValueHolder;->equals(Ljava/lang/Object;)Z
+HSPLandroidx/compose/runtime/StaticValueHolder;->getValue()Ljava/lang/Object;
+HSPLandroidx/compose/runtime/StructuralEqualityPolicy;-><clinit>()V
+HSPLandroidx/compose/runtime/StructuralEqualityPolicy;-><init>()V
+HSPLandroidx/compose/runtime/StructuralEqualityPolicy;->equivalent(Ljava/lang/Object;Ljava/lang/Object;)Z
+HSPLandroidx/compose/runtime/Trace;-><clinit>()V
+HSPLandroidx/compose/runtime/Trace;-><init>()V
+HSPLandroidx/compose/runtime/Trace;->beginSection(Ljava/lang/String;)Ljava/lang/Object;
+HSPLandroidx/compose/runtime/Trace;->endSection(Ljava/lang/Object;)V
+HSPLandroidx/compose/runtime/Updater;->constructor-impl(Landroidx/compose/runtime/Composer;)Landroidx/compose/runtime/Composer;
+HSPLandroidx/compose/runtime/Updater;->set-impl(Landroidx/compose/runtime/Composer;Ljava/lang/Object;Lkotlin/jvm/functions/Function2;)V
+HSPLandroidx/compose/runtime/collection/IdentityArrayIntMap;-><init>()V
+HSPLandroidx/compose/runtime/collection/IdentityArrayIntMap;->add(Ljava/lang/Object;I)I
+HSPLandroidx/compose/runtime/collection/IdentityArrayIntMap;->find(Ljava/lang/Object;)I
+HSPLandroidx/compose/runtime/collection/IdentityArrayIntMap;->getKeys()[Ljava/lang/Object;
+HSPLandroidx/compose/runtime/collection/IdentityArrayIntMap;->getSize()I
+HSPLandroidx/compose/runtime/collection/IdentityArrayIntMap;->getValues()[I
+HSPLandroidx/compose/runtime/collection/IdentityArrayIntMap;->setSize(I)V
+HSPLandroidx/compose/runtime/collection/IdentityArrayMap;-><init>(I)V
+HSPLandroidx/compose/runtime/collection/IdentityArrayMap;-><init>(IILkotlin/jvm/internal/DefaultConstructorMarker;)V
+HSPLandroidx/compose/runtime/collection/IdentityArrayMap;->contains(Ljava/lang/Object;)Z
+HSPLandroidx/compose/runtime/collection/IdentityArrayMap;->find(Ljava/lang/Object;)I
+HSPLandroidx/compose/runtime/collection/IdentityArrayMap;->get(Ljava/lang/Object;)Ljava/lang/Object;
+HSPLandroidx/compose/runtime/collection/IdentityArrayMap;->getKeys$runtime_release()[Ljava/lang/Object;
+HSPLandroidx/compose/runtime/collection/IdentityArrayMap;->getSize$runtime_release()I
+HSPLandroidx/compose/runtime/collection/IdentityArrayMap;->getValues$runtime_release()[Ljava/lang/Object;
+HSPLandroidx/compose/runtime/collection/IdentityArrayMap;->isNotEmpty()Z
+HSPLandroidx/compose/runtime/collection/IdentityArrayMap;->set(Ljava/lang/Object;Ljava/lang/Object;)V
+HSPLandroidx/compose/runtime/collection/IdentityArraySet;-><init>()V
+HSPLandroidx/compose/runtime/collection/IdentityArraySet;->add(Ljava/lang/Object;)Z
+HSPLandroidx/compose/runtime/collection/IdentityArraySet;->clear()V
+HSPLandroidx/compose/runtime/collection/IdentityArraySet;->contains(Ljava/lang/Object;)Z
+HSPLandroidx/compose/runtime/collection/IdentityArraySet;->find(Ljava/lang/Object;)I
+HSPLandroidx/compose/runtime/collection/IdentityArraySet;->get(I)Ljava/lang/Object;
+HSPLandroidx/compose/runtime/collection/IdentityArraySet;->getSize()I
+HSPLandroidx/compose/runtime/collection/IdentityArraySet;->getValues()[Ljava/lang/Object;
+HSPLandroidx/compose/runtime/collection/IdentityArraySet;->isNotEmpty()Z
+HSPLandroidx/compose/runtime/collection/IdentityArraySet;->remove(Ljava/lang/Object;)Z
+HSPLandroidx/compose/runtime/collection/IdentityArraySet;->setSize(I)V
+HSPLandroidx/compose/runtime/collection/IdentityArraySet;->size()I+]Landroidx/compose/runtime/collection/IdentityArraySet;Landroidx/compose/runtime/collection/IdentityArraySet;
+HSPLandroidx/compose/runtime/collection/IdentityScopeMap;-><init>()V
+HSPLandroidx/compose/runtime/collection/IdentityScopeMap;->access$find(Landroidx/compose/runtime/collection/IdentityScopeMap;Ljava/lang/Object;)I
+HSPLandroidx/compose/runtime/collection/IdentityScopeMap;->access$scopeSetAt(Landroidx/compose/runtime/collection/IdentityScopeMap;I)Landroidx/compose/runtime/collection/IdentityArraySet;
+HSPLandroidx/compose/runtime/collection/IdentityScopeMap;->add(Ljava/lang/Object;Ljava/lang/Object;)Z
+HSPLandroidx/compose/runtime/collection/IdentityScopeMap;->contains(Ljava/lang/Object;)Z
+HSPLandroidx/compose/runtime/collection/IdentityScopeMap;->find(Ljava/lang/Object;)I
+HSPLandroidx/compose/runtime/collection/IdentityScopeMap;->getOrCreateIdentitySet(Ljava/lang/Object;)Landroidx/compose/runtime/collection/IdentityArraySet;
+HSPLandroidx/compose/runtime/collection/IdentityScopeMap;->getScopeSets()[Landroidx/compose/runtime/collection/IdentityArraySet;
+HSPLandroidx/compose/runtime/collection/IdentityScopeMap;->getSize()I
+HSPLandroidx/compose/runtime/collection/IdentityScopeMap;->getValueOrder()[I
+HSPLandroidx/compose/runtime/collection/IdentityScopeMap;->getValues()[Ljava/lang/Object;
+HSPLandroidx/compose/runtime/collection/IdentityScopeMap;->remove(Ljava/lang/Object;Ljava/lang/Object;)Z
+HSPLandroidx/compose/runtime/collection/IdentityScopeMap;->scopeSetAt(I)Landroidx/compose/runtime/collection/IdentityArraySet;
+HSPLandroidx/compose/runtime/collection/IdentityScopeMap;->setSize(I)V
+HSPLandroidx/compose/runtime/collection/MutableVector$MutableVectorList;-><init>(Landroidx/compose/runtime/collection/MutableVector;)V
+HSPLandroidx/compose/runtime/collection/MutableVector$MutableVectorList;->get(I)Ljava/lang/Object;
+HSPLandroidx/compose/runtime/collection/MutableVector$MutableVectorList;->getSize()I
+HSPLandroidx/compose/runtime/collection/MutableVector$MutableVectorList;->indexOf(Ljava/lang/Object;)I
+HSPLandroidx/compose/runtime/collection/MutableVector$MutableVectorList;->isEmpty()Z
+HSPLandroidx/compose/runtime/collection/MutableVector$MutableVectorList;->size()I
+HSPLandroidx/compose/runtime/collection/MutableVector;-><clinit>()V
+HSPLandroidx/compose/runtime/collection/MutableVector;-><init>([Ljava/lang/Object;I)V
+HSPLandroidx/compose/runtime/collection/MutableVector;->add(ILjava/lang/Object;)V
+HSPLandroidx/compose/runtime/collection/MutableVector;->add(Ljava/lang/Object;)Z
+HSPLandroidx/compose/runtime/collection/MutableVector;->addAll(ILandroidx/compose/runtime/collection/MutableVector;)Z
+HSPLandroidx/compose/runtime/collection/MutableVector;->asMutableList()Ljava/util/List;
+HSPLandroidx/compose/runtime/collection/MutableVector;->clear()V
+HSPLandroidx/compose/runtime/collection/MutableVector;->contains(Ljava/lang/Object;)Z
+HSPLandroidx/compose/runtime/collection/MutableVector;->ensureCapacity(I)V
+HSPLandroidx/compose/runtime/collection/MutableVector;->getContent()[Ljava/lang/Object;
+HSPLandroidx/compose/runtime/collection/MutableVector;->getSize()I
+HSPLandroidx/compose/runtime/collection/MutableVector;->indexOf(Ljava/lang/Object;)I
+HSPLandroidx/compose/runtime/collection/MutableVector;->isEmpty()Z
+HSPLandroidx/compose/runtime/collection/MutableVector;->isNotEmpty()Z
+HSPLandroidx/compose/runtime/collection/MutableVector;->remove(Ljava/lang/Object;)Z
+HSPLandroidx/compose/runtime/collection/MutableVector;->removeAt(I)Ljava/lang/Object;
+HSPLandroidx/compose/runtime/collection/MutableVector;->removeRange(II)V
+HSPLandroidx/compose/runtime/collection/MutableVector;->set(ILjava/lang/Object;)Ljava/lang/Object;
+HSPLandroidx/compose/runtime/collection/MutableVector;->sortWith(Ljava/util/Comparator;)V
+HSPLandroidx/compose/runtime/collection/MutableVectorKt;->access$checkIndex(Ljava/util/List;I)V
+HSPLandroidx/compose/runtime/collection/MutableVectorKt;->checkIndex(Ljava/util/List;I)V
+HSPLandroidx/compose/runtime/external/kotlinx/collections/immutable/ExtensionsKt;->persistentHashMapOf()Landroidx/compose/runtime/external/kotlinx/collections/immutable/PersistentMap;
+HSPLandroidx/compose/runtime/external/kotlinx/collections/immutable/ExtensionsKt;->persistentListOf()Landroidx/compose/runtime/external/kotlinx/collections/immutable/PersistentList;
+HSPLandroidx/compose/runtime/external/kotlinx/collections/immutable/ExtensionsKt;->persistentSetOf()Landroidx/compose/runtime/external/kotlinx/collections/immutable/PersistentSet;
+HSPLandroidx/compose/runtime/external/kotlinx/collections/immutable/implementations/immutableList/AbstractPersistentList;-><init>()V
+HSPLandroidx/compose/runtime/external/kotlinx/collections/immutable/implementations/immutableList/SmallPersistentVector$Companion;-><init>()V
+HSPLandroidx/compose/runtime/external/kotlinx/collections/immutable/implementations/immutableList/SmallPersistentVector$Companion;-><init>(Lkotlin/jvm/internal/DefaultConstructorMarker;)V
+HSPLandroidx/compose/runtime/external/kotlinx/collections/immutable/implementations/immutableList/SmallPersistentVector$Companion;->getEMPTY()Landroidx/compose/runtime/external/kotlinx/collections/immutable/implementations/immutableList/SmallPersistentVector;
+HSPLandroidx/compose/runtime/external/kotlinx/collections/immutable/implementations/immutableList/SmallPersistentVector;-><clinit>()V
+HSPLandroidx/compose/runtime/external/kotlinx/collections/immutable/implementations/immutableList/SmallPersistentVector;-><init>([Ljava/lang/Object;)V
+HSPLandroidx/compose/runtime/external/kotlinx/collections/immutable/implementations/immutableList/SmallPersistentVector;->access$getEMPTY$cp()Landroidx/compose/runtime/external/kotlinx/collections/immutable/implementations/immutableList/SmallPersistentVector;
+HSPLandroidx/compose/runtime/external/kotlinx/collections/immutable/implementations/immutableList/SmallPersistentVector;->getSize()I
+HSPLandroidx/compose/runtime/external/kotlinx/collections/immutable/implementations/immutableList/UtilsKt;->persistentVectorOf()Landroidx/compose/runtime/external/kotlinx/collections/immutable/PersistentList;
+HSPLandroidx/compose/runtime/external/kotlinx/collections/immutable/implementations/immutableMap/MapEntry;-><init>(Ljava/lang/Object;Ljava/lang/Object;)V
+HSPLandroidx/compose/runtime/external/kotlinx/collections/immutable/implementations/immutableMap/MapEntry;->getKey()Ljava/lang/Object;
+HSPLandroidx/compose/runtime/external/kotlinx/collections/immutable/implementations/immutableMap/MapEntry;->getValue()Ljava/lang/Object;
+HSPLandroidx/compose/runtime/external/kotlinx/collections/immutable/implementations/immutableMap/PersistentHashMap$Companion;-><init>()V
+HSPLandroidx/compose/runtime/external/kotlinx/collections/immutable/implementations/immutableMap/PersistentHashMap$Companion;-><init>(Lkotlin/jvm/internal/DefaultConstructorMarker;)V
+HSPLandroidx/compose/runtime/external/kotlinx/collections/immutable/implementations/immutableMap/PersistentHashMap$Companion;->emptyOf$runtime_release()Landroidx/compose/runtime/external/kotlinx/collections/immutable/implementations/immutableMap/PersistentHashMap;
+HSPLandroidx/compose/runtime/external/kotlinx/collections/immutable/implementations/immutableMap/PersistentHashMap;-><clinit>()V
+HSPLandroidx/compose/runtime/external/kotlinx/collections/immutable/implementations/immutableMap/PersistentHashMap;-><init>(Landroidx/compose/runtime/external/kotlinx/collections/immutable/implementations/immutableMap/TrieNode;I)V
+HSPLandroidx/compose/runtime/external/kotlinx/collections/immutable/implementations/immutableMap/PersistentHashMap;->access$getEMPTY$cp()Landroidx/compose/runtime/external/kotlinx/collections/immutable/implementations/immutableMap/PersistentHashMap;
+HSPLandroidx/compose/runtime/external/kotlinx/collections/immutable/implementations/immutableMap/PersistentHashMap;->builder()Landroidx/compose/runtime/external/kotlinx/collections/immutable/PersistentMap$Builder;
+HSPLandroidx/compose/runtime/external/kotlinx/collections/immutable/implementations/immutableMap/PersistentHashMap;->builder()Landroidx/compose/runtime/external/kotlinx/collections/immutable/implementations/immutableMap/PersistentHashMapBuilder;
+HSPLandroidx/compose/runtime/external/kotlinx/collections/immutable/implementations/immutableMap/PersistentHashMap;->containsKey(Ljava/lang/Object;)Z
+HSPLandroidx/compose/runtime/external/kotlinx/collections/immutable/implementations/immutableMap/PersistentHashMap;->createEntries()Landroidx/compose/runtime/external/kotlinx/collections/immutable/ImmutableSet;
+HSPLandroidx/compose/runtime/external/kotlinx/collections/immutable/implementations/immutableMap/PersistentHashMap;->get(Ljava/lang/Object;)Ljava/lang/Object;
+HSPLandroidx/compose/runtime/external/kotlinx/collections/immutable/implementations/immutableMap/PersistentHashMap;->getEntries()Ljava/util/Set;
+HSPLandroidx/compose/runtime/external/kotlinx/collections/immutable/implementations/immutableMap/PersistentHashMap;->getNode$runtime_release()Landroidx/compose/runtime/external/kotlinx/collections/immutable/implementations/immutableMap/TrieNode;
+HSPLandroidx/compose/runtime/external/kotlinx/collections/immutable/implementations/immutableMap/PersistentHashMap;->getSize()I
+HSPLandroidx/compose/runtime/external/kotlinx/collections/immutable/implementations/immutableMap/PersistentHashMap;->put(Ljava/lang/Object;Ljava/lang/Object;)Landroidx/compose/runtime/external/kotlinx/collections/immutable/implementations/immutableMap/PersistentHashMap;
+HSPLandroidx/compose/runtime/external/kotlinx/collections/immutable/implementations/immutableMap/PersistentHashMapBaseIterator;-><init>(Landroidx/compose/runtime/external/kotlinx/collections/immutable/implementations/immutableMap/TrieNode;[Landroidx/compose/runtime/external/kotlinx/collections/immutable/implementations/immutableMap/TrieNodeBaseIterator;)V
+HSPLandroidx/compose/runtime/external/kotlinx/collections/immutable/implementations/immutableMap/PersistentHashMapBaseIterator;->checkHasNext()V
+HSPLandroidx/compose/runtime/external/kotlinx/collections/immutable/implementations/immutableMap/PersistentHashMapBaseIterator;->ensureNextEntryIsReady()V
+HSPLandroidx/compose/runtime/external/kotlinx/collections/immutable/implementations/immutableMap/PersistentHashMapBaseIterator;->hasNext()Z
+HSPLandroidx/compose/runtime/external/kotlinx/collections/immutable/implementations/immutableMap/PersistentHashMapBaseIterator;->moveToNextNodeWithData(I)I
+HSPLandroidx/compose/runtime/external/kotlinx/collections/immutable/implementations/immutableMap/PersistentHashMapBaseIterator;->next()Ljava/lang/Object;
+HSPLandroidx/compose/runtime/external/kotlinx/collections/immutable/implementations/immutableMap/PersistentHashMapBuilder;-><init>(Landroidx/compose/runtime/external/kotlinx/collections/immutable/implementations/immutableMap/PersistentHashMap;)V
+HSPLandroidx/compose/runtime/external/kotlinx/collections/immutable/implementations/immutableMap/PersistentHashMapBuilder;->build()Landroidx/compose/runtime/external/kotlinx/collections/immutable/PersistentMap;
+HSPLandroidx/compose/runtime/external/kotlinx/collections/immutable/implementations/immutableMap/PersistentHashMapBuilder;->build()Landroidx/compose/runtime/external/kotlinx/collections/immutable/implementations/immutableMap/PersistentHashMap;
+HSPLandroidx/compose/runtime/external/kotlinx/collections/immutable/implementations/immutableMap/PersistentHashMapBuilder;->getModCount$runtime_release()I
+HSPLandroidx/compose/runtime/external/kotlinx/collections/immutable/implementations/immutableMap/PersistentHashMapBuilder;->getOwnership$runtime_release()Landroidx/compose/runtime/external/kotlinx/collections/immutable/internal/MutabilityOwnership;
+HSPLandroidx/compose/runtime/external/kotlinx/collections/immutable/implementations/immutableMap/PersistentHashMapBuilder;->getSize()I
+HSPLandroidx/compose/runtime/external/kotlinx/collections/immutable/implementations/immutableMap/PersistentHashMapBuilder;->put(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;
+HSPLandroidx/compose/runtime/external/kotlinx/collections/immutable/implementations/immutableMap/PersistentHashMapBuilder;->putAll(Ljava/util/Map;)V
+HSPLandroidx/compose/runtime/external/kotlinx/collections/immutable/implementations/immutableMap/PersistentHashMapBuilder;->setModCount$runtime_release(I)V
+HSPLandroidx/compose/runtime/external/kotlinx/collections/immutable/implementations/immutableMap/PersistentHashMapBuilder;->setOperationResult$runtime_release(Ljava/lang/Object;)V
+HSPLandroidx/compose/runtime/external/kotlinx/collections/immutable/implementations/immutableMap/PersistentHashMapBuilder;->setSize(I)V
+HSPLandroidx/compose/runtime/external/kotlinx/collections/immutable/implementations/immutableMap/PersistentHashMapEntries;-><init>(Landroidx/compose/runtime/external/kotlinx/collections/immutable/implementations/immutableMap/PersistentHashMap;)V
+HSPLandroidx/compose/runtime/external/kotlinx/collections/immutable/implementations/immutableMap/PersistentHashMapEntries;->getSize()I
+HSPLandroidx/compose/runtime/external/kotlinx/collections/immutable/implementations/immutableMap/PersistentHashMapEntries;->iterator()Ljava/util/Iterator;
+HSPLandroidx/compose/runtime/external/kotlinx/collections/immutable/implementations/immutableMap/PersistentHashMapEntriesIterator;-><init>(Landroidx/compose/runtime/external/kotlinx/collections/immutable/implementations/immutableMap/TrieNode;)V
+HSPLandroidx/compose/runtime/external/kotlinx/collections/immutable/implementations/immutableMap/TrieNode$Companion;-><init>()V
+HSPLandroidx/compose/runtime/external/kotlinx/collections/immutable/implementations/immutableMap/TrieNode$Companion;-><init>(Lkotlin/jvm/internal/DefaultConstructorMarker;)V
+HSPLandroidx/compose/runtime/external/kotlinx/collections/immutable/implementations/immutableMap/TrieNode$Companion;->getEMPTY$runtime_release()Landroidx/compose/runtime/external/kotlinx/collections/immutable/implementations/immutableMap/TrieNode;
+HSPLandroidx/compose/runtime/external/kotlinx/collections/immutable/implementations/immutableMap/TrieNode$ModificationResult;-><init>(Landroidx/compose/runtime/external/kotlinx/collections/immutable/implementations/immutableMap/TrieNode;I)V
+HSPLandroidx/compose/runtime/external/kotlinx/collections/immutable/implementations/immutableMap/TrieNode$ModificationResult;->getNode()Landroidx/compose/runtime/external/kotlinx/collections/immutable/implementations/immutableMap/TrieNode;
+HSPLandroidx/compose/runtime/external/kotlinx/collections/immutable/implementations/immutableMap/TrieNode$ModificationResult;->getSizeDelta()I
+HSPLandroidx/compose/runtime/external/kotlinx/collections/immutable/implementations/immutableMap/TrieNode;-><clinit>()V
+HSPLandroidx/compose/runtime/external/kotlinx/collections/immutable/implementations/immutableMap/TrieNode;-><init>(II[Ljava/lang/Object;)V
+HSPLandroidx/compose/runtime/external/kotlinx/collections/immutable/implementations/immutableMap/TrieNode;-><init>(II[Ljava/lang/Object;Landroidx/compose/runtime/external/kotlinx/collections/immutable/internal/MutabilityOwnership;)V
+HSPLandroidx/compose/runtime/external/kotlinx/collections/immutable/implementations/immutableMap/TrieNode;->access$getEMPTY$cp()Landroidx/compose/runtime/external/kotlinx/collections/immutable/implementations/immutableMap/TrieNode;
+HSPLandroidx/compose/runtime/external/kotlinx/collections/immutable/implementations/immutableMap/TrieNode;->asInsertResult()Landroidx/compose/runtime/external/kotlinx/collections/immutable/implementations/immutableMap/TrieNode$ModificationResult;
+HSPLandroidx/compose/runtime/external/kotlinx/collections/immutable/implementations/immutableMap/TrieNode;->containsKey(ILjava/lang/Object;I)Z
+HSPLandroidx/compose/runtime/external/kotlinx/collections/immutable/implementations/immutableMap/TrieNode;->elementsIdentityEquals(Landroidx/compose/runtime/external/kotlinx/collections/immutable/implementations/immutableMap/TrieNode;)Z
+HSPLandroidx/compose/runtime/external/kotlinx/collections/immutable/implementations/immutableMap/TrieNode;->entryCount$runtime_release()I
+HSPLandroidx/compose/runtime/external/kotlinx/collections/immutable/implementations/immutableMap/TrieNode;->entryKeyIndex$runtime_release(I)I
+HSPLandroidx/compose/runtime/external/kotlinx/collections/immutable/implementations/immutableMap/TrieNode;->get(ILjava/lang/Object;I)Ljava/lang/Object;
+HSPLandroidx/compose/runtime/external/kotlinx/collections/immutable/implementations/immutableMap/TrieNode;->getBuffer$runtime_release()[Ljava/lang/Object;
+HSPLandroidx/compose/runtime/external/kotlinx/collections/immutable/implementations/immutableMap/TrieNode;->hasEntryAt$runtime_release(I)Z
+HSPLandroidx/compose/runtime/external/kotlinx/collections/immutable/implementations/immutableMap/TrieNode;->hasNodeAt(I)Z
+HSPLandroidx/compose/runtime/external/kotlinx/collections/immutable/implementations/immutableMap/TrieNode;->insertEntryAt(ILjava/lang/Object;Ljava/lang/Object;)Landroidx/compose/runtime/external/kotlinx/collections/immutable/implementations/immutableMap/TrieNode;
+HSPLandroidx/compose/runtime/external/kotlinx/collections/immutable/implementations/immutableMap/TrieNode;->keyAtIndex(I)Ljava/lang/Object;
+HSPLandroidx/compose/runtime/external/kotlinx/collections/immutable/implementations/immutableMap/TrieNode;->makeNode(ILjava/lang/Object;Ljava/lang/Object;ILjava/lang/Object;Ljava/lang/Object;ILandroidx/compose/runtime/external/kotlinx/collections/immutable/internal/MutabilityOwnership;)Landroidx/compose/runtime/external/kotlinx/collections/immutable/implementations/immutableMap/TrieNode;
+HSPLandroidx/compose/runtime/external/kotlinx/collections/immutable/implementations/immutableMap/TrieNode;->mutableInsertEntryAt(ILjava/lang/Object;Ljava/lang/Object;Landroidx/compose/runtime/external/kotlinx/collections/immutable/internal/MutabilityOwnership;)Landroidx/compose/runtime/external/kotlinx/collections/immutable/implementations/immutableMap/TrieNode;
+HSPLandroidx/compose/runtime/external/kotlinx/collections/immutable/implementations/immutableMap/TrieNode;->mutablePut(ILjava/lang/Object;Ljava/lang/Object;ILandroidx/compose/runtime/external/kotlinx/collections/immutable/implementations/immutableMap/PersistentHashMapBuilder;)Landroidx/compose/runtime/external/kotlinx/collections/immutable/implementations/immutableMap/TrieNode;
+HSPLandroidx/compose/runtime/external/kotlinx/collections/immutable/implementations/immutableMap/TrieNode;->mutablePutAll(Landroidx/compose/runtime/external/kotlinx/collections/immutable/implementations/immutableMap/TrieNode;ILandroidx/compose/runtime/external/kotlinx/collections/immutable/internal/DeltaCounter;Landroidx/compose/runtime/external/kotlinx/collections/immutable/implementations/immutableMap/PersistentHashMapBuilder;)Landroidx/compose/runtime/external/kotlinx/collections/immutable/implementations/immutableMap/TrieNode;
+HSPLandroidx/compose/runtime/external/kotlinx/collections/immutable/implementations/immutableMap/TrieNode;->mutablePutAllFromOtherNodeCell(Landroidx/compose/runtime/external/kotlinx/collections/immutable/implementations/immutableMap/TrieNode;IILandroidx/compose/runtime/external/kotlinx/collections/immutable/internal/DeltaCounter;Landroidx/compose/runtime/external/kotlinx/collections/immutable/implementations/immutableMap/PersistentHashMapBuilder;)Landroidx/compose/runtime/external/kotlinx/collections/immutable/implementations/immutableMap/TrieNode;
+HSPLandroidx/compose/runtime/external/kotlinx/collections/immutable/implementations/immutableMap/TrieNode;->mutableUpdateValueAtIndex(ILjava/lang/Object;Landroidx/compose/runtime/external/kotlinx/collections/immutable/implementations/immutableMap/PersistentHashMapBuilder;)Landroidx/compose/runtime/external/kotlinx/collections/immutable/implementations/immutableMap/TrieNode;
+HSPLandroidx/compose/runtime/external/kotlinx/collections/immutable/implementations/immutableMap/TrieNode;->nodeAtIndex$runtime_release(I)Landroidx/compose/runtime/external/kotlinx/collections/immutable/implementations/immutableMap/TrieNode;
+HSPLandroidx/compose/runtime/external/kotlinx/collections/immutable/implementations/immutableMap/TrieNode;->nodeIndex$runtime_release(I)I
+HSPLandroidx/compose/runtime/external/kotlinx/collections/immutable/implementations/immutableMap/TrieNode;->put(ILjava/lang/Object;Ljava/lang/Object;I)Landroidx/compose/runtime/external/kotlinx/collections/immutable/implementations/immutableMap/TrieNode$ModificationResult;
+HSPLandroidx/compose/runtime/external/kotlinx/collections/immutable/implementations/immutableMap/TrieNode;->valueAtKeyIndex(I)Ljava/lang/Object;
+HSPLandroidx/compose/runtime/external/kotlinx/collections/immutable/implementations/immutableMap/TrieNodeBaseIterator;-><init>()V
+HSPLandroidx/compose/runtime/external/kotlinx/collections/immutable/implementations/immutableMap/TrieNodeBaseIterator;->currentNode()Landroidx/compose/runtime/external/kotlinx/collections/immutable/implementations/immutableMap/TrieNode;
+HSPLandroidx/compose/runtime/external/kotlinx/collections/immutable/implementations/immutableMap/TrieNodeBaseIterator;->getBuffer()[Ljava/lang/Object;
+HSPLandroidx/compose/runtime/external/kotlinx/collections/immutable/implementations/immutableMap/TrieNodeBaseIterator;->getIndex()I
+HSPLandroidx/compose/runtime/external/kotlinx/collections/immutable/implementations/immutableMap/TrieNodeBaseIterator;->hasNextKey()Z
+HSPLandroidx/compose/runtime/external/kotlinx/collections/immutable/implementations/immutableMap/TrieNodeBaseIterator;->hasNextNode()Z
+HSPLandroidx/compose/runtime/external/kotlinx/collections/immutable/implementations/immutableMap/TrieNodeBaseIterator;->reset([Ljava/lang/Object;I)V
+HSPLandroidx/compose/runtime/external/kotlinx/collections/immutable/implementations/immutableMap/TrieNodeBaseIterator;->reset([Ljava/lang/Object;II)V
+HSPLandroidx/compose/runtime/external/kotlinx/collections/immutable/implementations/immutableMap/TrieNodeBaseIterator;->setIndex(I)V
+HSPLandroidx/compose/runtime/external/kotlinx/collections/immutable/implementations/immutableMap/TrieNodeEntriesIterator;-><init>()V
+HSPLandroidx/compose/runtime/external/kotlinx/collections/immutable/implementations/immutableMap/TrieNodeEntriesIterator;->next()Ljava/lang/Object;
+HSPLandroidx/compose/runtime/external/kotlinx/collections/immutable/implementations/immutableMap/TrieNodeEntriesIterator;->next()Ljava/util/Map$Entry;
+HSPLandroidx/compose/runtime/external/kotlinx/collections/immutable/implementations/immutableMap/TrieNodeKt;->access$insertEntryAtIndex([Ljava/lang/Object;ILjava/lang/Object;Ljava/lang/Object;)[Ljava/lang/Object;
+HSPLandroidx/compose/runtime/external/kotlinx/collections/immutable/implementations/immutableMap/TrieNodeKt;->indexSegment(II)I
+HSPLandroidx/compose/runtime/external/kotlinx/collections/immutable/implementations/immutableMap/TrieNodeKt;->insertEntryAtIndex([Ljava/lang/Object;ILjava/lang/Object;Ljava/lang/Object;)[Ljava/lang/Object;
+HSPLandroidx/compose/runtime/external/kotlinx/collections/immutable/implementations/persistentOrderedSet/Links;-><init>()V
+HSPLandroidx/compose/runtime/external/kotlinx/collections/immutable/implementations/persistentOrderedSet/Links;-><init>(Ljava/lang/Object;Ljava/lang/Object;)V
+HSPLandroidx/compose/runtime/external/kotlinx/collections/immutable/implementations/persistentOrderedSet/PersistentOrderedSet$Companion;-><init>()V
+HSPLandroidx/compose/runtime/external/kotlinx/collections/immutable/implementations/persistentOrderedSet/PersistentOrderedSet$Companion;-><init>(Lkotlin/jvm/internal/DefaultConstructorMarker;)V
+HSPLandroidx/compose/runtime/external/kotlinx/collections/immutable/implementations/persistentOrderedSet/PersistentOrderedSet$Companion;->emptyOf$runtime_release()Landroidx/compose/runtime/external/kotlinx/collections/immutable/PersistentSet;
+HSPLandroidx/compose/runtime/external/kotlinx/collections/immutable/implementations/persistentOrderedSet/PersistentOrderedSet;-><clinit>()V
+HSPLandroidx/compose/runtime/external/kotlinx/collections/immutable/implementations/persistentOrderedSet/PersistentOrderedSet;-><init>(Ljava/lang/Object;Ljava/lang/Object;Landroidx/compose/runtime/external/kotlinx/collections/immutable/implementations/immutableMap/PersistentHashMap;)V
+HSPLandroidx/compose/runtime/external/kotlinx/collections/immutable/implementations/persistentOrderedSet/PersistentOrderedSet;->access$getEMPTY$cp()Landroidx/compose/runtime/external/kotlinx/collections/immutable/implementations/persistentOrderedSet/PersistentOrderedSet;
+HSPLandroidx/compose/runtime/external/kotlinx/collections/immutable/implementations/persistentOrderedSet/PersistentOrderedSet;->add(Ljava/lang/Object;)Landroidx/compose/runtime/external/kotlinx/collections/immutable/PersistentSet;
+HSPLandroidx/compose/runtime/external/kotlinx/collections/immutable/implementations/persistentOrderedSet/PersistentOrderedSet;->getSize()I
+HSPLandroidx/compose/runtime/external/kotlinx/collections/immutable/internal/CommonFunctionsKt;->assert(Z)V
+HSPLandroidx/compose/runtime/external/kotlinx/collections/immutable/internal/DeltaCounter;-><init>(I)V
+HSPLandroidx/compose/runtime/external/kotlinx/collections/immutable/internal/DeltaCounter;-><init>(IILkotlin/jvm/internal/DefaultConstructorMarker;)V
+HSPLandroidx/compose/runtime/external/kotlinx/collections/immutable/internal/DeltaCounter;->getCount()I
+HSPLandroidx/compose/runtime/external/kotlinx/collections/immutable/internal/DeltaCounter;->setCount(I)V
+HSPLandroidx/compose/runtime/external/kotlinx/collections/immutable/internal/EndOfChain;-><clinit>()V
+HSPLandroidx/compose/runtime/external/kotlinx/collections/immutable/internal/EndOfChain;-><init>()V
+HSPLandroidx/compose/runtime/external/kotlinx/collections/immutable/internal/MutabilityOwnership;-><init>()V
+HSPLandroidx/compose/runtime/internal/ComposableLambdaImpl$invoke$1;-><init>(Landroidx/compose/runtime/internal/ComposableLambdaImpl;Ljava/lang/Object;I)V
+HSPLandroidx/compose/runtime/internal/ComposableLambdaImpl$invoke$1;->invoke(Landroidx/compose/runtime/Composer;I)V
+HSPLandroidx/compose/runtime/internal/ComposableLambdaImpl$invoke$1;->invoke(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;
+HSPLandroidx/compose/runtime/internal/ComposableLambdaImpl;-><init>(IZ)V
+HSPLandroidx/compose/runtime/internal/ComposableLambdaImpl;->invoke(Landroidx/compose/runtime/Composer;I)Ljava/lang/Object;
+HSPLandroidx/compose/runtime/internal/ComposableLambdaImpl;->invoke(Ljava/lang/Object;Landroidx/compose/runtime/Composer;I)Ljava/lang/Object;
+HSPLandroidx/compose/runtime/internal/ComposableLambdaImpl;->invoke(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;
+HSPLandroidx/compose/runtime/internal/ComposableLambdaImpl;->invoke(Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;
+HSPLandroidx/compose/runtime/internal/ComposableLambdaImpl;->trackRead(Landroidx/compose/runtime/Composer;)V
+HSPLandroidx/compose/runtime/internal/ComposableLambdaImpl;->trackWrite()V
+HSPLandroidx/compose/runtime/internal/ComposableLambdaImpl;->update(Ljava/lang/Object;)V
+HSPLandroidx/compose/runtime/internal/ComposableLambdaKt;->bitsForSlot(II)I
+HSPLandroidx/compose/runtime/internal/ComposableLambdaKt;->composableLambda(Landroidx/compose/runtime/Composer;IZLjava/lang/Object;)Landroidx/compose/runtime/internal/ComposableLambda;
+HSPLandroidx/compose/runtime/internal/ComposableLambdaKt;->composableLambdaInstance(IZLjava/lang/Object;)Landroidx/compose/runtime/internal/ComposableLambda;
+HSPLandroidx/compose/runtime/internal/ComposableLambdaKt;->differentBits(I)I
+HSPLandroidx/compose/runtime/internal/ComposableLambdaKt;->replacableWith(Landroidx/compose/runtime/RecomposeScope;Landroidx/compose/runtime/RecomposeScope;)Z
+HSPLandroidx/compose/runtime/internal/ComposableLambdaKt;->sameBits(I)I
+HSPLandroidx/compose/runtime/internal/ThreadMap;-><init>(I[J[Ljava/lang/Object;)V
+HSPLandroidx/compose/runtime/internal/ThreadMap;->find(J)I
+HSPLandroidx/compose/runtime/internal/ThreadMap;->get(J)Ljava/lang/Object;
+HSPLandroidx/compose/runtime/internal/ThreadMap;->newWith(JLjava/lang/Object;)Landroidx/compose/runtime/internal/ThreadMap;
+HSPLandroidx/compose/runtime/internal/ThreadMap;->trySet(JLjava/lang/Object;)Z
+HSPLandroidx/compose/runtime/internal/ThreadMapKt;-><clinit>()V
+HSPLandroidx/compose/runtime/internal/ThreadMapKt;->getEmptyThreadMap()Landroidx/compose/runtime/internal/ThreadMap;
+HSPLandroidx/compose/runtime/saveable/RememberSaveableKt$rememberSaveable$1$invoke$$inlined$onDispose$1;-><init>(Landroidx/compose/runtime/saveable/SaveableStateRegistry$Entry;)V
+HSPLandroidx/compose/runtime/saveable/RememberSaveableKt$rememberSaveable$1$valueProvider$1$1$1;-><init>(Landroidx/compose/runtime/saveable/SaveableStateRegistry;)V
+HSPLandroidx/compose/runtime/saveable/RememberSaveableKt$rememberSaveable$1$valueProvider$1;-><init>(Landroidx/compose/runtime/State;Landroidx/compose/runtime/State;Landroidx/compose/runtime/saveable/SaveableStateRegistry;)V
+HSPLandroidx/compose/runtime/saveable/RememberSaveableKt$rememberSaveable$1$valueProvider$1;->invoke()Ljava/lang/Object;
+HSPLandroidx/compose/runtime/saveable/RememberSaveableKt$rememberSaveable$1;-><init>(Landroidx/compose/runtime/saveable/SaveableStateRegistry;Ljava/lang/String;Landroidx/compose/runtime/State;Landroidx/compose/runtime/State;)V
+HSPLandroidx/compose/runtime/saveable/RememberSaveableKt$rememberSaveable$1;->invoke(Landroidx/compose/runtime/DisposableEffectScope;)Landroidx/compose/runtime/DisposableEffectResult;
+HSPLandroidx/compose/runtime/saveable/RememberSaveableKt$rememberSaveable$1;->invoke(Ljava/lang/Object;)Ljava/lang/Object;
+HSPLandroidx/compose/runtime/saveable/RememberSaveableKt;-><clinit>()V
+HSPLandroidx/compose/runtime/saveable/RememberSaveableKt;->access$requireCanBeSaved(Landroidx/compose/runtime/saveable/SaveableStateRegistry;Ljava/lang/Object;)V
+HSPLandroidx/compose/runtime/saveable/RememberSaveableKt;->rememberSaveable([Ljava/lang/Object;Landroidx/compose/runtime/saveable/Saver;Ljava/lang/String;Lkotlin/jvm/functions/Function0;Landroidx/compose/runtime/Composer;II)Ljava/lang/Object;
+HSPLandroidx/compose/runtime/saveable/RememberSaveableKt;->requireCanBeSaved(Landroidx/compose/runtime/saveable/SaveableStateRegistry;Ljava/lang/Object;)V
+HSPLandroidx/compose/runtime/saveable/SaveableStateRegistryImpl$registerProvider$3;-><init>(Landroidx/compose/runtime/saveable/SaveableStateRegistryImpl;Ljava/lang/String;Lkotlin/jvm/functions/Function0;)V
+HSPLandroidx/compose/runtime/saveable/SaveableStateRegistryImpl;-><init>(Ljava/util/Map;Lkotlin/jvm/functions/Function1;)V
+HSPLandroidx/compose/runtime/saveable/SaveableStateRegistryImpl;->canBeSaved(Ljava/lang/Object;)Z
+HSPLandroidx/compose/runtime/saveable/SaveableStateRegistryImpl;->consumeRestored(Ljava/lang/String;)Ljava/lang/Object;
+HSPLandroidx/compose/runtime/saveable/SaveableStateRegistryImpl;->registerProvider(Ljava/lang/String;Lkotlin/jvm/functions/Function0;)Landroidx/compose/runtime/saveable/SaveableStateRegistry$Entry;
+HSPLandroidx/compose/runtime/saveable/SaveableStateRegistryKt$LocalSaveableStateRegistry$1;-><clinit>()V
+HSPLandroidx/compose/runtime/saveable/SaveableStateRegistryKt$LocalSaveableStateRegistry$1;-><init>()V
+HSPLandroidx/compose/runtime/saveable/SaveableStateRegistryKt;-><clinit>()V
+HSPLandroidx/compose/runtime/saveable/SaveableStateRegistryKt;->SaveableStateRegistry(Ljava/util/Map;Lkotlin/jvm/functions/Function1;)Landroidx/compose/runtime/saveable/SaveableStateRegistry;
+HSPLandroidx/compose/runtime/saveable/SaveableStateRegistryKt;->getLocalSaveableStateRegistry()Landroidx/compose/runtime/ProvidableCompositionLocal;
+HSPLandroidx/compose/runtime/saveable/SaverKt$AutoSaver$1;-><clinit>()V
+HSPLandroidx/compose/runtime/saveable/SaverKt$AutoSaver$1;-><init>()V
+HSPLandroidx/compose/runtime/saveable/SaverKt$AutoSaver$1;->invoke(Landroidx/compose/runtime/saveable/SaverScope;Ljava/lang/Object;)Ljava/lang/Object;
+HSPLandroidx/compose/runtime/saveable/SaverKt$AutoSaver$1;->invoke(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;
+HSPLandroidx/compose/runtime/saveable/SaverKt$AutoSaver$2;-><clinit>()V
+HSPLandroidx/compose/runtime/saveable/SaverKt$AutoSaver$2;-><init>()V
+HSPLandroidx/compose/runtime/saveable/SaverKt$Saver$1;-><init>(Lkotlin/jvm/functions/Function2;Lkotlin/jvm/functions/Function1;)V
+HSPLandroidx/compose/runtime/saveable/SaverKt$Saver$1;->save(Landroidx/compose/runtime/saveable/SaverScope;Ljava/lang/Object;)Ljava/lang/Object;
+HSPLandroidx/compose/runtime/saveable/SaverKt;-><clinit>()V
+HSPLandroidx/compose/runtime/saveable/SaverKt;->Saver(Lkotlin/jvm/functions/Function2;Lkotlin/jvm/functions/Function1;)Landroidx/compose/runtime/saveable/Saver;
+HSPLandroidx/compose/runtime/saveable/SaverKt;->autoSaver()Landroidx/compose/runtime/saveable/Saver;
+HSPLandroidx/compose/runtime/snapshots/GlobalSnapshot$takeNestedMutableSnapshot$1;-><init>(Lkotlin/jvm/functions/Function1;Lkotlin/jvm/functions/Function1;)V
+HSPLandroidx/compose/runtime/snapshots/GlobalSnapshot$takeNestedMutableSnapshot$1;->invoke(Landroidx/compose/runtime/snapshots/SnapshotIdSet;)Landroidx/compose/runtime/snapshots/MutableSnapshot;
+HSPLandroidx/compose/runtime/snapshots/GlobalSnapshot$takeNestedMutableSnapshot$1;->invoke(Ljava/lang/Object;)Ljava/lang/Object;
+HSPLandroidx/compose/runtime/snapshots/GlobalSnapshot;-><init>(ILandroidx/compose/runtime/snapshots/SnapshotIdSet;)V
+HSPLandroidx/compose/runtime/snapshots/GlobalSnapshot;->dispose()V
+HSPLandroidx/compose/runtime/snapshots/GlobalSnapshot;->notifyObjectsInitialized$runtime_release()V
+HSPLandroidx/compose/runtime/snapshots/GlobalSnapshot;->takeNestedMutableSnapshot(Lkotlin/jvm/functions/Function1;Lkotlin/jvm/functions/Function1;)Landroidx/compose/runtime/snapshots/MutableSnapshot;
+HSPLandroidx/compose/runtime/snapshots/ListUtilsKt;->fastToSet(Ljava/util/List;)Ljava/util/Set;
+HSPLandroidx/compose/runtime/snapshots/MutableSnapshot;-><clinit>()V
+HSPLandroidx/compose/runtime/snapshots/MutableSnapshot;-><init>(ILandroidx/compose/runtime/snapshots/SnapshotIdSet;Lkotlin/jvm/functions/Function1;Lkotlin/jvm/functions/Function1;)V
+HSPLandroidx/compose/runtime/snapshots/MutableSnapshot;->apply()Landroidx/compose/runtime/snapshots/SnapshotApplyResult;
+HSPLandroidx/compose/runtime/snapshots/MutableSnapshot;->closeLocked$runtime_release()V
+HSPLandroidx/compose/runtime/snapshots/MutableSnapshot;->dispose()V
+HSPLandroidx/compose/runtime/snapshots/MutableSnapshot;->getModified$runtime_release()Ljava/util/Set;
+HSPLandroidx/compose/runtime/snapshots/MutableSnapshot;->getPreviousIds$runtime_release()Landroidx/compose/runtime/snapshots/SnapshotIdSet;
+HSPLandroidx/compose/runtime/snapshots/MutableSnapshot;->getReadObserver$runtime_release()Lkotlin/jvm/functions/Function1;
+HSPLandroidx/compose/runtime/snapshots/MutableSnapshot;->getReadOnly()Z
+HSPLandroidx/compose/runtime/snapshots/MutableSnapshot;->getWriteObserver$runtime_release()Lkotlin/jvm/functions/Function1;
+HSPLandroidx/compose/runtime/snapshots/MutableSnapshot;->innerApplyLocked$runtime_release(ILjava/util/Map;Landroidx/compose/runtime/snapshots/SnapshotIdSet;)Landroidx/compose/runtime/snapshots/SnapshotApplyResult;
+HSPLandroidx/compose/runtime/snapshots/MutableSnapshot;->nestedDeactivated$runtime_release(Landroidx/compose/runtime/snapshots/Snapshot;)V
+HSPLandroidx/compose/runtime/snapshots/MutableSnapshot;->recordModified$runtime_release(Landroidx/compose/runtime/snapshots/StateObject;)V
+HSPLandroidx/compose/runtime/snapshots/MutableSnapshot;->releasePinnedSnapshotsForCloseLocked$runtime_release()V
+HSPLandroidx/compose/runtime/snapshots/MutableSnapshot;->releasePreviouslyPinnedSnapshotsLocked$runtime_release()V
+HSPLandroidx/compose/runtime/snapshots/MutableSnapshot;->setModified(Ljava/util/Set;)V
+HSPLandroidx/compose/runtime/snapshots/Snapshot$Companion$registerApplyObserver$2;-><init>(Lkotlin/jvm/functions/Function2;)V
+HSPLandroidx/compose/runtime/snapshots/Snapshot$Companion$registerGlobalWriteObserver$2;-><init>(Lkotlin/jvm/functions/Function1;)V
+HSPLandroidx/compose/runtime/snapshots/Snapshot$Companion;-><init>()V
+HSPLandroidx/compose/runtime/snapshots/Snapshot$Companion;-><init>(Lkotlin/jvm/internal/DefaultConstructorMarker;)V
+HSPLandroidx/compose/runtime/snapshots/Snapshot$Companion;->createNonObservableSnapshot()Landroidx/compose/runtime/snapshots/Snapshot;
+HSPLandroidx/compose/runtime/snapshots/Snapshot$Companion;->getCurrent()Landroidx/compose/runtime/snapshots/Snapshot;
+HSPLandroidx/compose/runtime/snapshots/Snapshot$Companion;->notifyObjectsInitialized()V
+HSPLandroidx/compose/runtime/snapshots/Snapshot$Companion;->observe(Lkotlin/jvm/functions/Function1;Lkotlin/jvm/functions/Function1;Lkotlin/jvm/functions/Function0;)Ljava/lang/Object;
+HSPLandroidx/compose/runtime/snapshots/Snapshot$Companion;->registerApplyObserver(Lkotlin/jvm/functions/Function2;)Landroidx/compose/runtime/snapshots/ObserverHandle;
+HSPLandroidx/compose/runtime/snapshots/Snapshot$Companion;->registerGlobalWriteObserver(Lkotlin/jvm/functions/Function1;)Landroidx/compose/runtime/snapshots/ObserverHandle;
+HSPLandroidx/compose/runtime/snapshots/Snapshot$Companion;->sendApplyNotifications()V
+HSPLandroidx/compose/runtime/snapshots/Snapshot$Companion;->takeMutableSnapshot(Lkotlin/jvm/functions/Function1;Lkotlin/jvm/functions/Function1;)Landroidx/compose/runtime/snapshots/MutableSnapshot;
+HSPLandroidx/compose/runtime/snapshots/Snapshot;-><clinit>()V
+HSPLandroidx/compose/runtime/snapshots/Snapshot;-><init>(ILandroidx/compose/runtime/snapshots/SnapshotIdSet;)V
+HSPLandroidx/compose/runtime/snapshots/Snapshot;-><init>(ILandroidx/compose/runtime/snapshots/SnapshotIdSet;Lkotlin/jvm/internal/DefaultConstructorMarker;)V
+HSPLandroidx/compose/runtime/snapshots/Snapshot;->dispose()V
+HSPLandroidx/compose/runtime/snapshots/Snapshot;->getDisposed$runtime_release()Z
+HSPLandroidx/compose/runtime/snapshots/Snapshot;->getId()I
+HSPLandroidx/compose/runtime/snapshots/Snapshot;->getInvalid$runtime_release()Landroidx/compose/runtime/snapshots/SnapshotIdSet;
+HSPLandroidx/compose/runtime/snapshots/Snapshot;->makeCurrent()Landroidx/compose/runtime/snapshots/Snapshot;
+HSPLandroidx/compose/runtime/snapshots/Snapshot;->releasePinnedSnapshotLocked$runtime_release()V
+HSPLandroidx/compose/runtime/snapshots/Snapshot;->releasePinnedSnapshotsForCloseLocked$runtime_release()V
+HSPLandroidx/compose/runtime/snapshots/Snapshot;->restoreCurrent(Landroidx/compose/runtime/snapshots/Snapshot;)V
+HSPLandroidx/compose/runtime/snapshots/Snapshot;->setDisposed$runtime_release(Z)V
+HSPLandroidx/compose/runtime/snapshots/SnapshotApplyResult$Success;-><clinit>()V
+HSPLandroidx/compose/runtime/snapshots/SnapshotApplyResult$Success;-><init>()V
+HSPLandroidx/compose/runtime/snapshots/SnapshotApplyResult;-><clinit>()V
+HSPLandroidx/compose/runtime/snapshots/SnapshotApplyResult;-><init>()V
+HSPLandroidx/compose/runtime/snapshots/SnapshotApplyResult;-><init>(Lkotlin/jvm/internal/DefaultConstructorMarker;)V
+HSPLandroidx/compose/runtime/snapshots/SnapshotDoubleIndexHeap;-><init>()V
+HSPLandroidx/compose/runtime/snapshots/SnapshotDoubleIndexHeap;->add(I)I
+HSPLandroidx/compose/runtime/snapshots/SnapshotDoubleIndexHeap;->allocateHandle()I
+HSPLandroidx/compose/runtime/snapshots/SnapshotDoubleIndexHeap;->ensure(I)V
+HSPLandroidx/compose/runtime/snapshots/SnapshotDoubleIndexHeap;->freeHandle(I)V
+HSPLandroidx/compose/runtime/snapshots/SnapshotDoubleIndexHeap;->lowestOrDefault(I)I
+HSPLandroidx/compose/runtime/snapshots/SnapshotDoubleIndexHeap;->remove(I)V
+HSPLandroidx/compose/runtime/snapshots/SnapshotDoubleIndexHeap;->shiftDown(I)V
+HSPLandroidx/compose/runtime/snapshots/SnapshotDoubleIndexHeap;->shiftUp(I)V
+HSPLandroidx/compose/runtime/snapshots/SnapshotDoubleIndexHeap;->swap(II)V
+HSPLandroidx/compose/runtime/snapshots/SnapshotIdSet$Companion;-><init>()V
+HSPLandroidx/compose/runtime/snapshots/SnapshotIdSet$Companion;-><init>(Lkotlin/jvm/internal/DefaultConstructorMarker;)V
+HSPLandroidx/compose/runtime/snapshots/SnapshotIdSet$Companion;->getEMPTY()Landroidx/compose/runtime/snapshots/SnapshotIdSet;
+HSPLandroidx/compose/runtime/snapshots/SnapshotIdSet;-><clinit>()V
+HSPLandroidx/compose/runtime/snapshots/SnapshotIdSet;-><init>(JJI[I)V
+HSPLandroidx/compose/runtime/snapshots/SnapshotIdSet;->access$getEMPTY$cp()Landroidx/compose/runtime/snapshots/SnapshotIdSet;
+HSPLandroidx/compose/runtime/snapshots/SnapshotIdSet;->andNot(Landroidx/compose/runtime/snapshots/SnapshotIdSet;)Landroidx/compose/runtime/snapshots/SnapshotIdSet;
+HSPLandroidx/compose/runtime/snapshots/SnapshotIdSet;->clear(I)Landroidx/compose/runtime/snapshots/SnapshotIdSet;
+HSPLandroidx/compose/runtime/snapshots/SnapshotIdSet;->get(I)Z
+HSPLandroidx/compose/runtime/snapshots/SnapshotIdSet;->lowest(I)I
+HSPLandroidx/compose/runtime/snapshots/SnapshotIdSet;->or(Landroidx/compose/runtime/snapshots/SnapshotIdSet;)Landroidx/compose/runtime/snapshots/SnapshotIdSet;
+HSPLandroidx/compose/runtime/snapshots/SnapshotIdSet;->set(I)Landroidx/compose/runtime/snapshots/SnapshotIdSet;
+HSPLandroidx/compose/runtime/snapshots/SnapshotIdSetKt;->access$lowestBitOf(J)I
+HSPLandroidx/compose/runtime/snapshots/SnapshotIdSetKt;->lowestBitOf(J)I
+HSPLandroidx/compose/runtime/snapshots/SnapshotKt$advanceGlobalSnapshot$2;-><clinit>()V
+HSPLandroidx/compose/runtime/snapshots/SnapshotKt$advanceGlobalSnapshot$2;-><init>()V
+HSPLandroidx/compose/runtime/snapshots/SnapshotKt$advanceGlobalSnapshot$2;->invoke(Landroidx/compose/runtime/snapshots/SnapshotIdSet;)V
+HSPLandroidx/compose/runtime/snapshots/SnapshotKt$advanceGlobalSnapshot$2;->invoke(Ljava/lang/Object;)Ljava/lang/Object;
+HSPLandroidx/compose/runtime/snapshots/SnapshotKt$emptyLambda$1;-><clinit>()V
+HSPLandroidx/compose/runtime/snapshots/SnapshotKt$emptyLambda$1;-><init>()V
+HSPLandroidx/compose/runtime/snapshots/SnapshotKt$emptyLambda$1;->invoke(Landroidx/compose/runtime/snapshots/SnapshotIdSet;)V
+HSPLandroidx/compose/runtime/snapshots/SnapshotKt$emptyLambda$1;->invoke(Ljava/lang/Object;)Ljava/lang/Object;
+HSPLandroidx/compose/runtime/snapshots/SnapshotKt$mergedWriteObserver$1;-><init>(Lkotlin/jvm/functions/Function1;Lkotlin/jvm/functions/Function1;)V
+HSPLandroidx/compose/runtime/snapshots/SnapshotKt$mergedWriteObserver$1;->invoke(Ljava/lang/Object;)Ljava/lang/Object;
+HSPLandroidx/compose/runtime/snapshots/SnapshotKt$mergedWriteObserver$1;->invoke(Ljava/lang/Object;)V
+HSPLandroidx/compose/runtime/snapshots/SnapshotKt$takeNewSnapshot$1;-><init>(Lkotlin/jvm/functions/Function1;)V
+HSPLandroidx/compose/runtime/snapshots/SnapshotKt$takeNewSnapshot$1;->invoke(Landroidx/compose/runtime/snapshots/SnapshotIdSet;)Landroidx/compose/runtime/snapshots/Snapshot;
+HSPLandroidx/compose/runtime/snapshots/SnapshotKt$takeNewSnapshot$1;->invoke(Ljava/lang/Object;)Ljava/lang/Object;
+HSPLandroidx/compose/runtime/snapshots/SnapshotKt;-><clinit>()V
+HSPLandroidx/compose/runtime/snapshots/SnapshotKt;->access$advanceGlobalSnapshot()V
+HSPLandroidx/compose/runtime/snapshots/SnapshotKt;->access$advanceGlobalSnapshot(Lkotlin/jvm/functions/Function1;)Ljava/lang/Object;
+HSPLandroidx/compose/runtime/snapshots/SnapshotKt;->access$getApplyObservers$p()Ljava/util/List;
+HSPLandroidx/compose/runtime/snapshots/SnapshotKt;->access$getCurrentGlobalSnapshot$p()Ljava/util/concurrent/atomic/AtomicReference;
+HSPLandroidx/compose/runtime/snapshots/SnapshotKt;->access$getEmptyLambda$p()Lkotlin/jvm/functions/Function1;
+HSPLandroidx/compose/runtime/snapshots/SnapshotKt;->access$getGlobalWriteObservers$p()Ljava/util/List;
+HSPLandroidx/compose/runtime/snapshots/SnapshotKt;->access$getNextSnapshotId$p()I
+HSPLandroidx/compose/runtime/snapshots/SnapshotKt;->access$getOpenSnapshots$p()Landroidx/compose/runtime/snapshots/SnapshotIdSet;
+HSPLandroidx/compose/runtime/snapshots/SnapshotKt;->access$getThreadSnapshot$p()Landroidx/compose/runtime/SnapshotThreadLocal;
+HSPLandroidx/compose/runtime/snapshots/SnapshotKt;->access$mergedReadObserver(Lkotlin/jvm/functions/Function1;Lkotlin/jvm/functions/Function1;Z)Lkotlin/jvm/functions/Function1;
+HSPLandroidx/compose/runtime/snapshots/SnapshotKt;->access$mergedWriteObserver(Lkotlin/jvm/functions/Function1;Lkotlin/jvm/functions/Function1;)Lkotlin/jvm/functions/Function1;
+HSPLandroidx/compose/runtime/snapshots/SnapshotKt;->access$optimisticMerges(Landroidx/compose/runtime/snapshots/MutableSnapshot;Landroidx/compose/runtime/snapshots/MutableSnapshot;Landroidx/compose/runtime/snapshots/SnapshotIdSet;)Ljava/util/Map;
+HSPLandroidx/compose/runtime/snapshots/SnapshotKt;->access$readable(Landroidx/compose/runtime/snapshots/StateRecord;ILandroidx/compose/runtime/snapshots/SnapshotIdSet;)Landroidx/compose/runtime/snapshots/StateRecord;
+HSPLandroidx/compose/runtime/snapshots/SnapshotKt;->access$setNextSnapshotId$p(I)V
+HSPLandroidx/compose/runtime/snapshots/SnapshotKt;->access$setOpenSnapshots$p(Landroidx/compose/runtime/snapshots/SnapshotIdSet;)V
+HSPLandroidx/compose/runtime/snapshots/SnapshotKt;->access$takeNewGlobalSnapshot(Landroidx/compose/runtime/snapshots/Snapshot;Lkotlin/jvm/functions/Function1;)Ljava/lang/Object;
+HSPLandroidx/compose/runtime/snapshots/SnapshotKt;->access$takeNewSnapshot(Lkotlin/jvm/functions/Function1;)Landroidx/compose/runtime/snapshots/Snapshot;
+HSPLandroidx/compose/runtime/snapshots/SnapshotKt;->access$validateOpen(Landroidx/compose/runtime/snapshots/Snapshot;)V
+HSPLandroidx/compose/runtime/snapshots/SnapshotKt;->advanceGlobalSnapshot()V
+HSPLandroidx/compose/runtime/snapshots/SnapshotKt;->advanceGlobalSnapshot(Lkotlin/jvm/functions/Function1;)Ljava/lang/Object;
+HSPLandroidx/compose/runtime/snapshots/SnapshotKt;->createTransparentSnapshotWithNoParentReadObserver$default(Landroidx/compose/runtime/snapshots/Snapshot;Lkotlin/jvm/functions/Function1;ZILjava/lang/Object;)Landroidx/compose/runtime/snapshots/Snapshot;
+HSPLandroidx/compose/runtime/snapshots/SnapshotKt;->createTransparentSnapshotWithNoParentReadObserver(Landroidx/compose/runtime/snapshots/Snapshot;Lkotlin/jvm/functions/Function1;Z)Landroidx/compose/runtime/snapshots/Snapshot;
+HSPLandroidx/compose/runtime/snapshots/SnapshotKt;->current(Landroidx/compose/runtime/snapshots/StateRecord;)Landroidx/compose/runtime/snapshots/StateRecord;
+HSPLandroidx/compose/runtime/snapshots/SnapshotKt;->currentSnapshot()Landroidx/compose/runtime/snapshots/Snapshot;+]Landroidx/compose/runtime/SnapshotThreadLocal;Landroidx/compose/runtime/SnapshotThreadLocal;
+HSPLandroidx/compose/runtime/snapshots/SnapshotKt;->getLock()Ljava/lang/Object;
+HSPLandroidx/compose/runtime/snapshots/SnapshotKt;->getSnapshotInitializer()Landroidx/compose/runtime/snapshots/Snapshot;
+HSPLandroidx/compose/runtime/snapshots/SnapshotKt;->mergedReadObserver$default(Lkotlin/jvm/functions/Function1;Lkotlin/jvm/functions/Function1;ZILjava/lang/Object;)Lkotlin/jvm/functions/Function1;
+HSPLandroidx/compose/runtime/snapshots/SnapshotKt;->mergedReadObserver(Lkotlin/jvm/functions/Function1;Lkotlin/jvm/functions/Function1;Z)Lkotlin/jvm/functions/Function1;
+HSPLandroidx/compose/runtime/snapshots/SnapshotKt;->mergedWriteObserver(Lkotlin/jvm/functions/Function1;Lkotlin/jvm/functions/Function1;)Lkotlin/jvm/functions/Function1;
+HSPLandroidx/compose/runtime/snapshots/SnapshotKt;->newOverwritableRecord(Landroidx/compose/runtime/snapshots/StateRecord;Landroidx/compose/runtime/snapshots/StateObject;)Landroidx/compose/runtime/snapshots/StateRecord;
+HSPLandroidx/compose/runtime/snapshots/SnapshotKt;->notifyWrite(Landroidx/compose/runtime/snapshots/Snapshot;Landroidx/compose/runtime/snapshots/StateObject;)V
+HSPLandroidx/compose/runtime/snapshots/SnapshotKt;->optimisticMerges(Landroidx/compose/runtime/snapshots/MutableSnapshot;Landroidx/compose/runtime/snapshots/MutableSnapshot;Landroidx/compose/runtime/snapshots/SnapshotIdSet;)Ljava/util/Map;
+HSPLandroidx/compose/runtime/snapshots/SnapshotKt;->overwritableRecord(Landroidx/compose/runtime/snapshots/StateRecord;Landroidx/compose/runtime/snapshots/StateObject;Landroidx/compose/runtime/snapshots/Snapshot;Landroidx/compose/runtime/snapshots/StateRecord;)Landroidx/compose/runtime/snapshots/StateRecord;
+HSPLandroidx/compose/runtime/snapshots/SnapshotKt;->readable(Landroidx/compose/runtime/snapshots/StateRecord;ILandroidx/compose/runtime/snapshots/SnapshotIdSet;)Landroidx/compose/runtime/snapshots/StateRecord;+]Landroidx/compose/runtime/snapshots/StateRecord;Landroidx/compose/runtime/DerivedSnapshotState$ResultRecord;,Landroidx/compose/runtime/SnapshotMutableStateImpl$StateStateRecord;,Landroidx/compose/runtime/snapshots/SnapshotStateList$StateListStateRecord;
+HSPLandroidx/compose/runtime/snapshots/SnapshotKt;->readable(Landroidx/compose/runtime/snapshots/StateRecord;Landroidx/compose/runtime/snapshots/StateObject;)Landroidx/compose/runtime/snapshots/StateRecord;
+HSPLandroidx/compose/runtime/snapshots/SnapshotKt;->releasePinningLocked(I)V
+HSPLandroidx/compose/runtime/snapshots/SnapshotKt;->takeNewGlobalSnapshot(Landroidx/compose/runtime/snapshots/Snapshot;Lkotlin/jvm/functions/Function1;)Ljava/lang/Object;
+HSPLandroidx/compose/runtime/snapshots/SnapshotKt;->takeNewSnapshot(Lkotlin/jvm/functions/Function1;)Landroidx/compose/runtime/snapshots/Snapshot;
+HSPLandroidx/compose/runtime/snapshots/SnapshotKt;->trackPinning(ILandroidx/compose/runtime/snapshots/SnapshotIdSet;)I
+HSPLandroidx/compose/runtime/snapshots/SnapshotKt;->used(Landroidx/compose/runtime/snapshots/StateObject;)Landroidx/compose/runtime/snapshots/StateRecord;
+HSPLandroidx/compose/runtime/snapshots/SnapshotKt;->valid(IILandroidx/compose/runtime/snapshots/SnapshotIdSet;)Z
+HSPLandroidx/compose/runtime/snapshots/SnapshotKt;->valid(Landroidx/compose/runtime/snapshots/StateRecord;ILandroidx/compose/runtime/snapshots/SnapshotIdSet;)Z
+HSPLandroidx/compose/runtime/snapshots/SnapshotKt;->validateOpen(Landroidx/compose/runtime/snapshots/Snapshot;)V
+HSPLandroidx/compose/runtime/snapshots/SnapshotStateList$StateListStateRecord;-><init>(Landroidx/compose/runtime/external/kotlinx/collections/immutable/PersistentList;)V
+HSPLandroidx/compose/runtime/snapshots/SnapshotStateList$StateListStateRecord;->getList$runtime_release()Landroidx/compose/runtime/external/kotlinx/collections/immutable/PersistentList;
+HSPLandroidx/compose/runtime/snapshots/SnapshotStateList;-><init>()V
+HSPLandroidx/compose/runtime/snapshots/SnapshotStateList;->getFirstStateRecord()Landroidx/compose/runtime/snapshots/StateRecord;
+HSPLandroidx/compose/runtime/snapshots/SnapshotStateList;->getReadable$runtime_release()Landroidx/compose/runtime/snapshots/SnapshotStateList$StateListStateRecord;
+HSPLandroidx/compose/runtime/snapshots/SnapshotStateList;->isEmpty()Z
+HSPLandroidx/compose/runtime/snapshots/SnapshotStateObserver$ObservedScopeMap$derivedStateEnterObserver$1;-><init>(Landroidx/compose/runtime/snapshots/SnapshotStateObserver$ObservedScopeMap;)V
+HSPLandroidx/compose/runtime/snapshots/SnapshotStateObserver$ObservedScopeMap$derivedStateExitObserver$1;-><init>(Landroidx/compose/runtime/snapshots/SnapshotStateObserver$ObservedScopeMap;)V
+HSPLandroidx/compose/runtime/snapshots/SnapshotStateObserver$ObservedScopeMap;-><init>(Lkotlin/jvm/functions/Function1;)V
+HSPLandroidx/compose/runtime/snapshots/SnapshotStateObserver$ObservedScopeMap;->access$clearObsoleteStateReads(Landroidx/compose/runtime/snapshots/SnapshotStateObserver$ObservedScopeMap;Ljava/lang/Object;)V
+HSPLandroidx/compose/runtime/snapshots/SnapshotStateObserver$ObservedScopeMap;->access$getCurrentScope$p(Landroidx/compose/runtime/snapshots/SnapshotStateObserver$ObservedScopeMap;)Ljava/lang/Object;
+HSPLandroidx/compose/runtime/snapshots/SnapshotStateObserver$ObservedScopeMap;->access$getCurrentScopeReads$p(Landroidx/compose/runtime/snapshots/SnapshotStateObserver$ObservedScopeMap;)Landroidx/compose/runtime/collection/IdentityArrayIntMap;
+HSPLandroidx/compose/runtime/snapshots/SnapshotStateObserver$ObservedScopeMap;->access$getCurrentToken$p(Landroidx/compose/runtime/snapshots/SnapshotStateObserver$ObservedScopeMap;)I
+HSPLandroidx/compose/runtime/snapshots/SnapshotStateObserver$ObservedScopeMap;->access$getScopeToValues$p(Landroidx/compose/runtime/snapshots/SnapshotStateObserver$ObservedScopeMap;)Landroidx/compose/runtime/collection/IdentityArrayMap;
+HSPLandroidx/compose/runtime/snapshots/SnapshotStateObserver$ObservedScopeMap;->access$setCurrentScope$p(Landroidx/compose/runtime/snapshots/SnapshotStateObserver$ObservedScopeMap;Ljava/lang/Object;)V
+HSPLandroidx/compose/runtime/snapshots/SnapshotStateObserver$ObservedScopeMap;->access$setCurrentScopeReads$p(Landroidx/compose/runtime/snapshots/SnapshotStateObserver$ObservedScopeMap;Landroidx/compose/runtime/collection/IdentityArrayIntMap;)V
+HSPLandroidx/compose/runtime/snapshots/SnapshotStateObserver$ObservedScopeMap;->access$setCurrentToken$p(Landroidx/compose/runtime/snapshots/SnapshotStateObserver$ObservedScopeMap;I)V
+HSPLandroidx/compose/runtime/snapshots/SnapshotStateObserver$ObservedScopeMap;->clearObsoleteStateReads(Ljava/lang/Object;)V
+HSPLandroidx/compose/runtime/snapshots/SnapshotStateObserver$ObservedScopeMap;->getDerivedStateEnterObserver()Lkotlin/jvm/functions/Function1;
+HSPLandroidx/compose/runtime/snapshots/SnapshotStateObserver$ObservedScopeMap;->getDerivedStateExitObserver()Lkotlin/jvm/functions/Function1;
+HSPLandroidx/compose/runtime/snapshots/SnapshotStateObserver$ObservedScopeMap;->getOnChanged()Lkotlin/jvm/functions/Function1;
+HSPLandroidx/compose/runtime/snapshots/SnapshotStateObserver$ObservedScopeMap;->notifyInvalidatedScopes()V
+HSPLandroidx/compose/runtime/snapshots/SnapshotStateObserver$ObservedScopeMap;->recordInvalidation(Ljava/util/Set;)Z+]Landroidx/compose/runtime/collection/IdentityArraySet;Landroidx/compose/runtime/collection/IdentityArraySet;]Landroidx/compose/runtime/collection/IdentityScopeMap;Landroidx/compose/runtime/collection/IdentityScopeMap;
+HSPLandroidx/compose/runtime/snapshots/SnapshotStateObserver$ObservedScopeMap;->recordRead(Ljava/lang/Object;)V
+HSPLandroidx/compose/runtime/snapshots/SnapshotStateObserver$ObservedScopeMap;->removeObservation(Ljava/lang/Object;Ljava/lang/Object;)V
+HSPLandroidx/compose/runtime/snapshots/SnapshotStateObserver$applyObserver$1$2;-><init>(Landroidx/compose/runtime/snapshots/SnapshotStateObserver;)V
+HSPLandroidx/compose/runtime/snapshots/SnapshotStateObserver$applyObserver$1$2;->invoke()Ljava/lang/Object;
+HSPLandroidx/compose/runtime/snapshots/SnapshotStateObserver$applyObserver$1$2;->invoke()V
+HSPLandroidx/compose/runtime/snapshots/SnapshotStateObserver$applyObserver$1;-><init>(Landroidx/compose/runtime/snapshots/SnapshotStateObserver;)V
+HSPLandroidx/compose/runtime/snapshots/SnapshotStateObserver$applyObserver$1;->invoke(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;
+HSPLandroidx/compose/runtime/snapshots/SnapshotStateObserver$applyObserver$1;->invoke(Ljava/util/Set;Landroidx/compose/runtime/snapshots/Snapshot;)V
+HSPLandroidx/compose/runtime/snapshots/SnapshotStateObserver$observeReads$1$1;-><init>(Landroidx/compose/runtime/snapshots/SnapshotStateObserver;Lkotlin/jvm/functions/Function0;)V
+HSPLandroidx/compose/runtime/snapshots/SnapshotStateObserver$observeReads$1$1;->invoke()Ljava/lang/Object;
+HSPLandroidx/compose/runtime/snapshots/SnapshotStateObserver$observeReads$1$1;->invoke()V
+HSPLandroidx/compose/runtime/snapshots/SnapshotStateObserver$readObserver$1;-><init>(Landroidx/compose/runtime/snapshots/SnapshotStateObserver;)V
+HSPLandroidx/compose/runtime/snapshots/SnapshotStateObserver$readObserver$1;->invoke(Ljava/lang/Object;)Ljava/lang/Object;
+HSPLandroidx/compose/runtime/snapshots/SnapshotStateObserver$readObserver$1;->invoke(Ljava/lang/Object;)V
+HSPLandroidx/compose/runtime/snapshots/SnapshotStateObserver;-><clinit>()V
+HSPLandroidx/compose/runtime/snapshots/SnapshotStateObserver;-><init>(Lkotlin/jvm/functions/Function1;)V
+HSPLandroidx/compose/runtime/snapshots/SnapshotStateObserver;->access$getCurrentMap$p(Landroidx/compose/runtime/snapshots/SnapshotStateObserver;)Landroidx/compose/runtime/snapshots/SnapshotStateObserver$ObservedScopeMap;
+HSPLandroidx/compose/runtime/snapshots/SnapshotStateObserver;->access$getObservedScopeMaps$p(Landroidx/compose/runtime/snapshots/SnapshotStateObserver;)Landroidx/compose/runtime/collection/MutableVector;
+HSPLandroidx/compose/runtime/snapshots/SnapshotStateObserver;->access$getOnChangedExecutor$p(Landroidx/compose/runtime/snapshots/SnapshotStateObserver;)Lkotlin/jvm/functions/Function1;
+HSPLandroidx/compose/runtime/snapshots/SnapshotStateObserver;->access$getReadObserver$p(Landroidx/compose/runtime/snapshots/SnapshotStateObserver;)Lkotlin/jvm/functions/Function1;
+HSPLandroidx/compose/runtime/snapshots/SnapshotStateObserver;->access$isPaused$p(Landroidx/compose/runtime/snapshots/SnapshotStateObserver;)Z
+HSPLandroidx/compose/runtime/snapshots/SnapshotStateObserver;->ensureMap(Lkotlin/jvm/functions/Function1;)Landroidx/compose/runtime/snapshots/SnapshotStateObserver$ObservedScopeMap;
+HSPLandroidx/compose/runtime/snapshots/SnapshotStateObserver;->observeReads(Ljava/lang/Object;Lkotlin/jvm/functions/Function1;Lkotlin/jvm/functions/Function0;)V
+HSPLandroidx/compose/runtime/snapshots/SnapshotStateObserver;->start()V
+HSPLandroidx/compose/runtime/snapshots/StateRecord;-><clinit>()V
+HSPLandroidx/compose/runtime/snapshots/StateRecord;-><init>()V
+HSPLandroidx/compose/runtime/snapshots/StateRecord;->getNext$runtime_release()Landroidx/compose/runtime/snapshots/StateRecord;
+HSPLandroidx/compose/runtime/snapshots/StateRecord;->getSnapshotId$runtime_release()I
+HSPLandroidx/compose/runtime/snapshots/StateRecord;->setNext$runtime_release(Landroidx/compose/runtime/snapshots/StateRecord;)V
+HSPLandroidx/compose/runtime/snapshots/StateRecord;->setSnapshotId$runtime_release(I)V
+HSPLandroidx/compose/runtime/snapshots/TransparentObserverMutableSnapshot;-><init>(Landroidx/compose/runtime/snapshots/MutableSnapshot;Lkotlin/jvm/functions/Function1;Lkotlin/jvm/functions/Function1;ZZ)V
+HSPLandroidx/compose/runtime/snapshots/TransparentObserverMutableSnapshot;->apply()Landroidx/compose/runtime/snapshots/SnapshotApplyResult;
+HSPLandroidx/compose/runtime/snapshots/TransparentObserverMutableSnapshot;->dispose()V
+HSPLandroidx/compose/runtime/snapshots/TransparentObserverMutableSnapshot;->getCurrentSnapshot()Landroidx/compose/runtime/snapshots/MutableSnapshot;
+HSPLandroidx/compose/runtime/snapshots/TransparentObserverMutableSnapshot;->getId()I+]Landroidx/compose/runtime/snapshots/Snapshot;Landroidx/compose/runtime/snapshots/GlobalSnapshot;,Landroidx/compose/runtime/snapshots/MutableSnapshot;,Landroidx/compose/runtime/snapshots/NestedMutableSnapshot;,Landroidx/compose/runtime/snapshots/TransparentObserverMutableSnapshot;
+HSPLandroidx/compose/runtime/snapshots/TransparentObserverMutableSnapshot;->getInvalid$runtime_release()Landroidx/compose/runtime/snapshots/SnapshotIdSet;
+HSPLandroidx/compose/runtime/snapshots/TransparentObserverMutableSnapshot;->getReadOnly()Z
+HSPLandroidx/compose/runtime/snapshots/TransparentObserverMutableSnapshot;->notifyObjectsInitialized$runtime_release()V
+HSPLandroidx/compose/runtime/snapshots/TransparentObserverMutableSnapshot;->recordModified$runtime_release(Landroidx/compose/runtime/snapshots/StateObject;)V
+HSPLandroidx/compose/runtime/snapshots/TransparentObserverMutableSnapshot;->takeNestedMutableSnapshot(Lkotlin/jvm/functions/Function1;Lkotlin/jvm/functions/Function1;)Landroidx/compose/runtime/snapshots/MutableSnapshot;
+HSPLandroidx/compose/runtime/tooling/InspectionTablesKt$LocalInspectionTables$1;-><clinit>()V
+HSPLandroidx/compose/runtime/tooling/InspectionTablesKt$LocalInspectionTables$1;-><init>()V
+HSPLandroidx/compose/runtime/tooling/InspectionTablesKt$LocalInspectionTables$1;->invoke()Ljava/lang/Object;
+HSPLandroidx/compose/runtime/tooling/InspectionTablesKt$LocalInspectionTables$1;->invoke()Ljava/util/Set;
+HSPLandroidx/compose/runtime/tooling/InspectionTablesKt;-><clinit>()V
+HSPLandroidx/compose/runtime/tooling/InspectionTablesKt;->getLocalInspectionTables()Landroidx/compose/runtime/ProvidableCompositionLocal;
+HSPLandroidx/compose/ui/ActualKt;->areObjectsOfSameType(Ljava/lang/Object;Ljava/lang/Object;)Z
+HSPLandroidx/compose/ui/Alignment$Companion;-><clinit>()V
+HSPLandroidx/compose/ui/Alignment$Companion;-><init>()V
+HSPLandroidx/compose/ui/Alignment$Companion;->getCenter()Landroidx/compose/ui/Alignment;
+HSPLandroidx/compose/ui/Alignment$Companion;->getCenterHorizontally()Landroidx/compose/ui/Alignment$Horizontal;
+HSPLandroidx/compose/ui/Alignment$Companion;->getCenterVertically()Landroidx/compose/ui/Alignment$Vertical;
+HSPLandroidx/compose/ui/Alignment$Companion;->getStart()Landroidx/compose/ui/Alignment$Horizontal;
+HSPLandroidx/compose/ui/Alignment$Companion;->getTop()Landroidx/compose/ui/Alignment$Vertical;
+HSPLandroidx/compose/ui/Alignment$Companion;->getTopStart()Landroidx/compose/ui/Alignment;
+HSPLandroidx/compose/ui/Alignment;-><clinit>()V
+HSPLandroidx/compose/ui/BiasAlignment$Horizontal;-><init>(F)V
+HSPLandroidx/compose/ui/BiasAlignment$Horizontal;->align(IILandroidx/compose/ui/unit/LayoutDirection;)I
+HSPLandroidx/compose/ui/BiasAlignment$Horizontal;->equals(Ljava/lang/Object;)Z
+HSPLandroidx/compose/ui/BiasAlignment$Vertical;-><init>(F)V
+HSPLandroidx/compose/ui/BiasAlignment$Vertical;->align(II)I
+HSPLandroidx/compose/ui/BiasAlignment$Vertical;->equals(Ljava/lang/Object;)Z
+HSPLandroidx/compose/ui/BiasAlignment;-><init>(FF)V
+HSPLandroidx/compose/ui/BiasAlignment;->align-KFBX0sM(JJLandroidx/compose/ui/unit/LayoutDirection;)J
+HSPLandroidx/compose/ui/BiasAlignment;->equals(Ljava/lang/Object;)Z
+HSPLandroidx/compose/ui/CombinedModifier;-><clinit>()V
+HSPLandroidx/compose/ui/CombinedModifier;-><init>(Landroidx/compose/ui/Modifier;Landroidx/compose/ui/Modifier;)V
+HSPLandroidx/compose/ui/CombinedModifier;->all(Lkotlin/jvm/functions/Function1;)Z
+HSPLandroidx/compose/ui/CombinedModifier;->equals(Ljava/lang/Object;)Z
+HSPLandroidx/compose/ui/CombinedModifier;->foldIn(Ljava/lang/Object;Lkotlin/jvm/functions/Function2;)Ljava/lang/Object;
+HSPLandroidx/compose/ui/CombinedModifier;->getInner$ui_release()Landroidx/compose/ui/Modifier;
+HSPLandroidx/compose/ui/CombinedModifier;->getOuter$ui_release()Landroidx/compose/ui/Modifier;
+HSPLandroidx/compose/ui/ComposedModifier;-><init>(Lkotlin/jvm/functions/Function1;Lkotlin/jvm/functions/Function3;)V
+HSPLandroidx/compose/ui/ComposedModifier;->getFactory()Lkotlin/jvm/functions/Function3;
+HSPLandroidx/compose/ui/ComposedModifierKt$WrapFocusEventModifier$1;-><clinit>()V
+HSPLandroidx/compose/ui/ComposedModifierKt$WrapFocusEventModifier$1;-><init>()V
+HSPLandroidx/compose/ui/ComposedModifierKt$WrapFocusRequesterModifier$1;-><clinit>()V
+HSPLandroidx/compose/ui/ComposedModifierKt$WrapFocusRequesterModifier$1;-><init>()V
+HSPLandroidx/compose/ui/ComposedModifierKt$materialize$1;-><clinit>()V
+HSPLandroidx/compose/ui/ComposedModifierKt$materialize$1;-><init>()V
+HSPLandroidx/compose/ui/ComposedModifierKt$materialize$1;->invoke(Landroidx/compose/ui/Modifier$Element;)Ljava/lang/Boolean;
+HSPLandroidx/compose/ui/ComposedModifierKt$materialize$1;->invoke(Ljava/lang/Object;)Ljava/lang/Object;
+HSPLandroidx/compose/ui/ComposedModifierKt$materialize$result$1;-><init>(Landroidx/compose/runtime/Composer;)V
+HSPLandroidx/compose/ui/ComposedModifierKt$materialize$result$1;->invoke(Landroidx/compose/ui/Modifier;Landroidx/compose/ui/Modifier$Element;)Landroidx/compose/ui/Modifier;
+HSPLandroidx/compose/ui/ComposedModifierKt$materialize$result$1;->invoke(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;
+HSPLandroidx/compose/ui/ComposedModifierKt;-><clinit>()V
+HSPLandroidx/compose/ui/ComposedModifierKt;->composed(Landroidx/compose/ui/Modifier;Lkotlin/jvm/functions/Function1;Lkotlin/jvm/functions/Function3;)Landroidx/compose/ui/Modifier;
+HSPLandroidx/compose/ui/ComposedModifierKt;->materialize(Landroidx/compose/runtime/Composer;Landroidx/compose/ui/Modifier;)Landroidx/compose/ui/Modifier;
+HSPLandroidx/compose/ui/Modifier$Companion;-><clinit>()V
+HSPLandroidx/compose/ui/Modifier$Companion;-><init>()V
+HSPLandroidx/compose/ui/Modifier$Companion;->all(Lkotlin/jvm/functions/Function1;)Z
+HSPLandroidx/compose/ui/Modifier$Companion;->then(Landroidx/compose/ui/Modifier;)Landroidx/compose/ui/Modifier;
+HSPLandroidx/compose/ui/Modifier$Element;->all(Lkotlin/jvm/functions/Function1;)Z
+HSPLandroidx/compose/ui/Modifier$Element;->foldIn(Ljava/lang/Object;Lkotlin/jvm/functions/Function2;)Ljava/lang/Object;
+HSPLandroidx/compose/ui/Modifier$Node;-><clinit>()V
+HSPLandroidx/compose/ui/Modifier$Node;-><init>()V
+HSPLandroidx/compose/ui/Modifier$Node;->attach$ui_release()V
+HSPLandroidx/compose/ui/Modifier$Node;->getAggregateChildKindSet$ui_release()I
+HSPLandroidx/compose/ui/Modifier$Node;->getChild$ui_release()Landroidx/compose/ui/Modifier$Node;
+HSPLandroidx/compose/ui/Modifier$Node;->getCoordinator$ui_release()Landroidx/compose/ui/node/NodeCoordinator;
+HSPLandroidx/compose/ui/Modifier$Node;->getKindSet$ui_release()I
+HSPLandroidx/compose/ui/Modifier$Node;->getNode()Landroidx/compose/ui/Modifier$Node;
+HSPLandroidx/compose/ui/Modifier$Node;->getParent$ui_release()Landroidx/compose/ui/Modifier$Node;
+HSPLandroidx/compose/ui/Modifier$Node;->isAttached()Z
+HSPLandroidx/compose/ui/Modifier$Node;->onAttach()V
+HSPLandroidx/compose/ui/Modifier$Node;->setAggregateChildKindSet$ui_release(I)V
+HSPLandroidx/compose/ui/Modifier$Node;->setChild$ui_release(Landroidx/compose/ui/Modifier$Node;)V
+HSPLandroidx/compose/ui/Modifier$Node;->setKindSet$ui_release(I)V
+HSPLandroidx/compose/ui/Modifier$Node;->setParent$ui_release(Landroidx/compose/ui/Modifier$Node;)V
+HSPLandroidx/compose/ui/Modifier$Node;->sideEffect(Lkotlin/jvm/functions/Function0;)V
+HSPLandroidx/compose/ui/Modifier$Node;->updateCoordinator$ui_release(Landroidx/compose/ui/node/NodeCoordinator;)V
+HSPLandroidx/compose/ui/Modifier;-><clinit>()V
+HSPLandroidx/compose/ui/Modifier;->then(Landroidx/compose/ui/Modifier;)Landroidx/compose/ui/Modifier;
+HSPLandroidx/compose/ui/MotionDurationScale$DefaultImpls;->fold(Landroidx/compose/ui/MotionDurationScale;Ljava/lang/Object;Lkotlin/jvm/functions/Function2;)Ljava/lang/Object;
+HSPLandroidx/compose/ui/MotionDurationScale$DefaultImpls;->get(Landroidx/compose/ui/MotionDurationScale;Lkotlin/coroutines/CoroutineContext$Key;)Lkotlin/coroutines/CoroutineContext$Element;
+HSPLandroidx/compose/ui/MotionDurationScale$DefaultImpls;->minusKey(Landroidx/compose/ui/MotionDurationScale;Lkotlin/coroutines/CoroutineContext$Key;)Lkotlin/coroutines/CoroutineContext;
+HSPLandroidx/compose/ui/MotionDurationScale$Key;-><clinit>()V
+HSPLandroidx/compose/ui/MotionDurationScale$Key;-><init>()V
+HSPLandroidx/compose/ui/MotionDurationScale;-><clinit>()V
+HSPLandroidx/compose/ui/MotionDurationScale;->getKey()Lkotlin/coroutines/CoroutineContext$Key;
+HSPLandroidx/compose/ui/autofill/AndroidAutofill;-><init>(Landroid/view/View;Landroidx/compose/ui/autofill/AutofillTree;)V
+HSPLandroidx/compose/ui/autofill/AndroidAutofill;->getAutofillManager()Landroid/view/autofill/AutofillManager;
+HSPLandroidx/compose/ui/autofill/AutofillCallback;-><clinit>()V
+HSPLandroidx/compose/ui/autofill/AutofillCallback;-><init>()V
+HSPLandroidx/compose/ui/autofill/AutofillCallback;->register(Landroidx/compose/ui/autofill/AndroidAutofill;)V
+HSPLandroidx/compose/ui/autofill/AutofillTree;-><clinit>()V
+HSPLandroidx/compose/ui/autofill/AutofillTree;-><init>()V
+HSPLandroidx/compose/ui/draw/ClipKt;->clip(Landroidx/compose/ui/Modifier;Landroidx/compose/ui/graphics/Shape;)Landroidx/compose/ui/Modifier;
+HSPLandroidx/compose/ui/draw/DrawBackgroundModifier;-><init>(Lkotlin/jvm/functions/Function1;Lkotlin/jvm/functions/Function1;)V
+HSPLandroidx/compose/ui/draw/DrawBackgroundModifier;->draw(Landroidx/compose/ui/graphics/drawscope/ContentDrawScope;)V
+HSPLandroidx/compose/ui/draw/DrawBackgroundModifier;->equals(Ljava/lang/Object;)Z
+HSPLandroidx/compose/ui/draw/DrawModifierKt;->drawBehind(Landroidx/compose/ui/Modifier;Lkotlin/jvm/functions/Function1;)Landroidx/compose/ui/Modifier;
+HSPLandroidx/compose/ui/draw/PainterModifier$measure$1;-><init>(Landroidx/compose/ui/layout/Placeable;)V
+HSPLandroidx/compose/ui/draw/PainterModifier$measure$1;->invoke(Landroidx/compose/ui/layout/Placeable$PlacementScope;)V
+HSPLandroidx/compose/ui/draw/PainterModifier$measure$1;->invoke(Ljava/lang/Object;)Ljava/lang/Object;
+HSPLandroidx/compose/ui/draw/PainterModifier;-><init>(Landroidx/compose/ui/graphics/painter/Painter;ZLandroidx/compose/ui/Alignment;Landroidx/compose/ui/layout/ContentScale;FLandroidx/compose/ui/graphics/ColorFilter;Lkotlin/jvm/functions/Function1;)V
+HSPLandroidx/compose/ui/draw/PainterModifier;->draw(Landroidx/compose/ui/graphics/drawscope/ContentDrawScope;)V
+HSPLandroidx/compose/ui/draw/PainterModifier;->equals(Ljava/lang/Object;)Z
+HSPLandroidx/compose/ui/draw/PainterModifier;->getUseIntrinsicSize()Z
+HSPLandroidx/compose/ui/draw/PainterModifier;->hasSpecifiedAndFiniteHeight-uvyYCjk(J)Z
+HSPLandroidx/compose/ui/draw/PainterModifier;->hasSpecifiedAndFiniteWidth-uvyYCjk(J)Z
+HSPLandroidx/compose/ui/draw/PainterModifier;->measure-3p2s80s(Landroidx/compose/ui/layout/MeasureScope;Landroidx/compose/ui/layout/Measurable;J)Landroidx/compose/ui/layout/MeasureResult;
+HSPLandroidx/compose/ui/draw/PainterModifier;->modifyConstraints-ZezNO4M(J)J
+HSPLandroidx/compose/ui/draw/PainterModifierKt;->paint$default(Landroidx/compose/ui/Modifier;Landroidx/compose/ui/graphics/painter/Painter;ZLandroidx/compose/ui/Alignment;Landroidx/compose/ui/layout/ContentScale;FLandroidx/compose/ui/graphics/ColorFilter;ILjava/lang/Object;)Landroidx/compose/ui/Modifier;
+HSPLandroidx/compose/ui/draw/PainterModifierKt;->paint(Landroidx/compose/ui/Modifier;Landroidx/compose/ui/graphics/painter/Painter;ZLandroidx/compose/ui/Alignment;Landroidx/compose/ui/layout/ContentScale;FLandroidx/compose/ui/graphics/ColorFilter;)Landroidx/compose/ui/Modifier;
+HSPLandroidx/compose/ui/draw/ShadowKt$shadow$2$1;-><init>(FLandroidx/compose/ui/graphics/Shape;ZJJ)V
+HSPLandroidx/compose/ui/draw/ShadowKt$shadow$2$1;->invoke(Landroidx/compose/ui/graphics/GraphicsLayerScope;)V
+HSPLandroidx/compose/ui/draw/ShadowKt$shadow$2$1;->invoke(Ljava/lang/Object;)Ljava/lang/Object;
+HSPLandroidx/compose/ui/draw/ShadowKt;->shadow-s4CzXII$default(Landroidx/compose/ui/Modifier;FLandroidx/compose/ui/graphics/Shape;ZJJILjava/lang/Object;)Landroidx/compose/ui/Modifier;
+HSPLandroidx/compose/ui/draw/ShadowKt;->shadow-s4CzXII(Landroidx/compose/ui/Modifier;FLandroidx/compose/ui/graphics/Shape;ZJJ)Landroidx/compose/ui/Modifier;
+HSPLandroidx/compose/ui/focus/FocusChangedModifierKt$onFocusChanged$2$1$1;-><init>(Landroidx/compose/runtime/MutableState;Lkotlin/jvm/functions/Function1;)V
+HSPLandroidx/compose/ui/focus/FocusChangedModifierKt$onFocusChanged$2$1$1;->invoke(Landroidx/compose/ui/focus/FocusState;)V
+HSPLandroidx/compose/ui/focus/FocusChangedModifierKt$onFocusChanged$2$1$1;->invoke(Ljava/lang/Object;)Ljava/lang/Object;
+HSPLandroidx/compose/ui/focus/FocusChangedModifierKt$onFocusChanged$2;-><init>(Lkotlin/jvm/functions/Function1;)V
+HSPLandroidx/compose/ui/focus/FocusChangedModifierKt$onFocusChanged$2;->invoke(Landroidx/compose/ui/Modifier;Landroidx/compose/runtime/Composer;I)Landroidx/compose/ui/Modifier;
+HSPLandroidx/compose/ui/focus/FocusChangedModifierKt$onFocusChanged$2;->invoke(Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;
+HSPLandroidx/compose/ui/focus/FocusChangedModifierKt;->onFocusChanged(Landroidx/compose/ui/Modifier;Lkotlin/jvm/functions/Function1;)Landroidx/compose/ui/Modifier;
+HSPLandroidx/compose/ui/focus/FocusEventModifierKt$ModifierLocalFocusEvent$1;-><clinit>()V
+HSPLandroidx/compose/ui/focus/FocusEventModifierKt$ModifierLocalFocusEvent$1;-><init>()V
+HSPLandroidx/compose/ui/focus/FocusEventModifierKt$ModifierLocalFocusEvent$1;->invoke()Landroidx/compose/ui/focus/FocusEventModifierLocal;
+HSPLandroidx/compose/ui/focus/FocusEventModifierKt$ModifierLocalFocusEvent$1;->invoke()Ljava/lang/Object;
+HSPLandroidx/compose/ui/focus/FocusEventModifierKt$onFocusEvent$2$1$1;-><init>(Landroidx/compose/ui/focus/FocusEventModifierLocal;)V
+HSPLandroidx/compose/ui/focus/FocusEventModifierKt$onFocusEvent$2$1$1;->invoke()Ljava/lang/Object;
+HSPLandroidx/compose/ui/focus/FocusEventModifierKt$onFocusEvent$2$1$1;->invoke()V
+HSPLandroidx/compose/ui/focus/FocusEventModifierKt$onFocusEvent$2;-><init>(Lkotlin/jvm/functions/Function1;)V
+HSPLandroidx/compose/ui/focus/FocusEventModifierKt$onFocusEvent$2;->invoke(Landroidx/compose/ui/Modifier;Landroidx/compose/runtime/Composer;I)Landroidx/compose/ui/Modifier;
+HSPLandroidx/compose/ui/focus/FocusEventModifierKt$onFocusEvent$2;->invoke(Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;
+HSPLandroidx/compose/ui/focus/FocusEventModifierKt;-><clinit>()V
+HSPLandroidx/compose/ui/focus/FocusEventModifierKt;->getModifierLocalFocusEvent()Landroidx/compose/ui/modifier/ProvidableModifierLocal;
+HSPLandroidx/compose/ui/focus/FocusEventModifierKt;->onFocusEvent(Landroidx/compose/ui/Modifier;Lkotlin/jvm/functions/Function1;)Landroidx/compose/ui/Modifier;
+HSPLandroidx/compose/ui/focus/FocusEventModifierLocal;-><init>(Lkotlin/jvm/functions/Function1;)V
+HSPLandroidx/compose/ui/focus/FocusEventModifierLocal;->addFocusModifier(Landroidx/compose/ui/focus/FocusModifier;)V
+HSPLandroidx/compose/ui/focus/FocusEventModifierLocal;->getKey()Landroidx/compose/ui/modifier/ProvidableModifierLocal;
+HSPLandroidx/compose/ui/focus/FocusEventModifierLocal;->getValue()Landroidx/compose/ui/focus/FocusEventModifierLocal;
+HSPLandroidx/compose/ui/focus/FocusEventModifierLocal;->getValue()Ljava/lang/Object;
+HSPLandroidx/compose/ui/focus/FocusEventModifierLocal;->notifyIfNoFocusModifiers()V
+HSPLandroidx/compose/ui/focus/FocusEventModifierLocal;->onModifierLocalsUpdated(Landroidx/compose/ui/modifier/ModifierLocalReadScope;)V
+HSPLandroidx/compose/ui/focus/FocusEventModifierLocal;->propagateFocusEvent()V
+HSPLandroidx/compose/ui/focus/FocusEventModifierLocal;->removeFocusModifier(Landroidx/compose/ui/focus/FocusModifier;)V
+HSPLandroidx/compose/ui/focus/FocusManagerImpl;-><init>(Landroidx/compose/ui/focus/FocusModifier;)V
+HSPLandroidx/compose/ui/focus/FocusManagerImpl;-><init>(Landroidx/compose/ui/focus/FocusModifier;ILkotlin/jvm/internal/DefaultConstructorMarker;)V
+HSPLandroidx/compose/ui/focus/FocusManagerImpl;->fetchUpdatedFocusProperties()V
+HSPLandroidx/compose/ui/focus/FocusManagerImpl;->getModifier()Landroidx/compose/ui/Modifier;
+HSPLandroidx/compose/ui/focus/FocusManagerImpl;->setLayoutDirection(Landroidx/compose/ui/unit/LayoutDirection;)V
+HSPLandroidx/compose/ui/focus/FocusManagerKt;->access$updateProperties(Landroidx/compose/ui/focus/FocusModifier;)V
+HSPLandroidx/compose/ui/focus/FocusManagerKt;->updateProperties(Landroidx/compose/ui/focus/FocusModifier;)V
+HSPLandroidx/compose/ui/focus/FocusModifier$Companion$RefreshFocusProperties$1;-><clinit>()V
+HSPLandroidx/compose/ui/focus/FocusModifier$Companion$RefreshFocusProperties$1;-><init>()V
+HSPLandroidx/compose/ui/focus/FocusModifier$Companion;-><init>()V
+HSPLandroidx/compose/ui/focus/FocusModifier$Companion;-><init>(Lkotlin/jvm/internal/DefaultConstructorMarker;)V
+HSPLandroidx/compose/ui/focus/FocusModifier$Companion;->getRefreshFocusProperties()Lkotlin/jvm/functions/Function1;
+HSPLandroidx/compose/ui/focus/FocusModifier;-><clinit>()V
+HSPLandroidx/compose/ui/focus/FocusModifier;-><init>(Landroidx/compose/ui/focus/FocusStateImpl;Lkotlin/jvm/functions/Function1;)V
+HSPLandroidx/compose/ui/focus/FocusModifier;-><init>(Landroidx/compose/ui/focus/FocusStateImpl;Lkotlin/jvm/functions/Function1;ILkotlin/jvm/internal/DefaultConstructorMarker;)V
+HSPLandroidx/compose/ui/focus/FocusModifier;->access$getRefreshFocusProperties$cp()Lkotlin/jvm/functions/Function1;
+HSPLandroidx/compose/ui/focus/FocusModifier;->getChildren()Landroidx/compose/runtime/collection/MutableVector;
+HSPLandroidx/compose/ui/focus/FocusModifier;->getCoordinator()Landroidx/compose/ui/node/NodeCoordinator;
+HSPLandroidx/compose/ui/focus/FocusModifier;->getFocusEventListener()Landroidx/compose/ui/focus/FocusEventModifierLocal;
+HSPLandroidx/compose/ui/focus/FocusModifier;->getFocusProperties()Landroidx/compose/ui/focus/FocusProperties;
+HSPLandroidx/compose/ui/focus/FocusModifier;->getFocusPropertiesModifier()Landroidx/compose/ui/focus/FocusPropertiesModifier;
+HSPLandroidx/compose/ui/focus/FocusModifier;->getFocusState()Landroidx/compose/ui/focus/FocusStateImpl;
+HSPLandroidx/compose/ui/focus/FocusModifier;->getKey()Landroidx/compose/ui/modifier/ProvidableModifierLocal;
+HSPLandroidx/compose/ui/focus/FocusModifier;->getKeyInputChildren()Landroidx/compose/runtime/collection/MutableVector;
+HSPLandroidx/compose/ui/focus/FocusModifier;->getValue()Landroidx/compose/ui/focus/FocusModifier;
+HSPLandroidx/compose/ui/focus/FocusModifier;->getValue()Ljava/lang/Object;
+HSPLandroidx/compose/ui/focus/FocusModifier;->onModifierLocalsUpdated(Landroidx/compose/ui/modifier/ModifierLocalReadScope;)V
+HSPLandroidx/compose/ui/focus/FocusModifier;->onPlaced(Landroidx/compose/ui/layout/LayoutCoordinates;)V
+HSPLandroidx/compose/ui/focus/FocusModifier;->setFocusState(Landroidx/compose/ui/focus/FocusStateImpl;)V
+HSPLandroidx/compose/ui/focus/FocusModifier;->setModifierLocalReadScope(Landroidx/compose/ui/modifier/ModifierLocalReadScope;)V
+HSPLandroidx/compose/ui/focus/FocusModifierKt$ModifierLocalParentFocusModifier$1;-><clinit>()V
+HSPLandroidx/compose/ui/focus/FocusModifierKt$ModifierLocalParentFocusModifier$1;-><init>()V
+HSPLandroidx/compose/ui/focus/FocusModifierKt$ModifierLocalParentFocusModifier$1;->invoke()Landroidx/compose/ui/focus/FocusModifier;
+HSPLandroidx/compose/ui/focus/FocusModifierKt$ModifierLocalParentFocusModifier$1;->invoke()Ljava/lang/Object;
+HSPLandroidx/compose/ui/focus/FocusModifierKt$ResetFocusModifierLocals$1;-><init>()V
+HSPLandroidx/compose/ui/focus/FocusModifierKt$ResetFocusModifierLocals$1;->getKey()Landroidx/compose/ui/modifier/ProvidableModifierLocal;
+HSPLandroidx/compose/ui/focus/FocusModifierKt$ResetFocusModifierLocals$1;->getValue()Landroidx/compose/ui/focus/FocusPropertiesModifier;
+HSPLandroidx/compose/ui/focus/FocusModifierKt$ResetFocusModifierLocals$1;->getValue()Ljava/lang/Object;
+HSPLandroidx/compose/ui/focus/FocusModifierKt$ResetFocusModifierLocals$2;-><init>()V
+HSPLandroidx/compose/ui/focus/FocusModifierKt$ResetFocusModifierLocals$2;->getKey()Landroidx/compose/ui/modifier/ProvidableModifierLocal;
+HSPLandroidx/compose/ui/focus/FocusModifierKt$ResetFocusModifierLocals$2;->getValue()Landroidx/compose/ui/focus/FocusEventModifierLocal;
+HSPLandroidx/compose/ui/focus/FocusModifierKt$ResetFocusModifierLocals$2;->getValue()Ljava/lang/Object;
+HSPLandroidx/compose/ui/focus/FocusModifierKt$ResetFocusModifierLocals$3;-><init>()V
+HSPLandroidx/compose/ui/focus/FocusModifierKt$ResetFocusModifierLocals$3;->getKey()Landroidx/compose/ui/modifier/ProvidableModifierLocal;
+HSPLandroidx/compose/ui/focus/FocusModifierKt$ResetFocusModifierLocals$3;->getValue()Landroidx/compose/ui/focus/FocusRequesterModifierLocal;
+HSPLandroidx/compose/ui/focus/FocusModifierKt$ResetFocusModifierLocals$3;->getValue()Ljava/lang/Object;
+HSPLandroidx/compose/ui/focus/FocusModifierKt$focusTarget$2$1$1;-><init>(Landroidx/compose/ui/focus/FocusModifier;)V
+HSPLandroidx/compose/ui/focus/FocusModifierKt$focusTarget$2$1$1;->invoke()Ljava/lang/Object;
+HSPLandroidx/compose/ui/focus/FocusModifierKt$focusTarget$2$1$1;->invoke()V
+HSPLandroidx/compose/ui/focus/FocusModifierKt$focusTarget$2;-><clinit>()V
+HSPLandroidx/compose/ui/focus/FocusModifierKt$focusTarget$2;-><init>()V
+HSPLandroidx/compose/ui/focus/FocusModifierKt$focusTarget$2;->invoke(Landroidx/compose/ui/Modifier;Landroidx/compose/runtime/Composer;I)Landroidx/compose/ui/Modifier;
+HSPLandroidx/compose/ui/focus/FocusModifierKt$focusTarget$2;->invoke(Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;
+HSPLandroidx/compose/ui/focus/FocusModifierKt;-><clinit>()V
+HSPLandroidx/compose/ui/focus/FocusModifierKt;->focusTarget(Landroidx/compose/ui/Modifier;)Landroidx/compose/ui/Modifier;
+HSPLandroidx/compose/ui/focus/FocusModifierKt;->focusTarget(Landroidx/compose/ui/Modifier;Landroidx/compose/ui/focus/FocusModifier;)Landroidx/compose/ui/Modifier;
+HSPLandroidx/compose/ui/focus/FocusModifierKt;->getModifierLocalParentFocusModifier()Landroidx/compose/ui/modifier/ProvidableModifierLocal;
+HSPLandroidx/compose/ui/focus/FocusPropertiesImpl$enter$1;-><clinit>()V
+HSPLandroidx/compose/ui/focus/FocusPropertiesImpl$enter$1;-><init>()V
+HSPLandroidx/compose/ui/focus/FocusPropertiesImpl$exit$1;-><clinit>()V
+HSPLandroidx/compose/ui/focus/FocusPropertiesImpl$exit$1;-><init>()V
+HSPLandroidx/compose/ui/focus/FocusPropertiesImpl;-><init>()V
+HSPLandroidx/compose/ui/focus/FocusPropertiesImpl;->getCanFocus()Z
+HSPLandroidx/compose/ui/focus/FocusPropertiesImpl;->setCanFocus(Z)V
+HSPLandroidx/compose/ui/focus/FocusPropertiesImpl;->setDown(Landroidx/compose/ui/focus/FocusRequester;)V
+HSPLandroidx/compose/ui/focus/FocusPropertiesImpl;->setEnd(Landroidx/compose/ui/focus/FocusRequester;)V
+HSPLandroidx/compose/ui/focus/FocusPropertiesImpl;->setEnter(Lkotlin/jvm/functions/Function1;)V
+HSPLandroidx/compose/ui/focus/FocusPropertiesImpl;->setExit(Lkotlin/jvm/functions/Function1;)V
+HSPLandroidx/compose/ui/focus/FocusPropertiesImpl;->setLeft(Landroidx/compose/ui/focus/FocusRequester;)V
+HSPLandroidx/compose/ui/focus/FocusPropertiesImpl;->setNext(Landroidx/compose/ui/focus/FocusRequester;)V
+HSPLandroidx/compose/ui/focus/FocusPropertiesImpl;->setPrevious(Landroidx/compose/ui/focus/FocusRequester;)V
+HSPLandroidx/compose/ui/focus/FocusPropertiesImpl;->setRight(Landroidx/compose/ui/focus/FocusRequester;)V
+HSPLandroidx/compose/ui/focus/FocusPropertiesImpl;->setStart(Landroidx/compose/ui/focus/FocusRequester;)V
+HSPLandroidx/compose/ui/focus/FocusPropertiesImpl;->setUp(Landroidx/compose/ui/focus/FocusRequester;)V
+HSPLandroidx/compose/ui/focus/FocusPropertiesKt$ModifierLocalFocusProperties$1;-><clinit>()V
+HSPLandroidx/compose/ui/focus/FocusPropertiesKt$ModifierLocalFocusProperties$1;-><init>()V
+HSPLandroidx/compose/ui/focus/FocusPropertiesKt$ModifierLocalFocusProperties$1;->invoke()Landroidx/compose/ui/focus/FocusPropertiesModifier;
+HSPLandroidx/compose/ui/focus/FocusPropertiesKt$ModifierLocalFocusProperties$1;->invoke()Ljava/lang/Object;
+HSPLandroidx/compose/ui/focus/FocusPropertiesKt$clear$1;-><clinit>()V
+HSPLandroidx/compose/ui/focus/FocusPropertiesKt$clear$1;-><init>()V
+HSPLandroidx/compose/ui/focus/FocusPropertiesKt$clear$2;-><clinit>()V
+HSPLandroidx/compose/ui/focus/FocusPropertiesKt$clear$2;-><init>()V
+HSPLandroidx/compose/ui/focus/FocusPropertiesKt$refreshFocusProperties$1;-><init>(Landroidx/compose/ui/focus/FocusModifier;)V
+HSPLandroidx/compose/ui/focus/FocusPropertiesKt$refreshFocusProperties$1;->invoke()Ljava/lang/Object;
+HSPLandroidx/compose/ui/focus/FocusPropertiesKt$refreshFocusProperties$1;->invoke()V
+HSPLandroidx/compose/ui/focus/FocusPropertiesKt;-><clinit>()V
+HSPLandroidx/compose/ui/focus/FocusPropertiesKt;->clear(Landroidx/compose/ui/focus/FocusProperties;)V
+HSPLandroidx/compose/ui/focus/FocusPropertiesKt;->focusProperties(Landroidx/compose/ui/Modifier;Lkotlin/jvm/functions/Function1;)Landroidx/compose/ui/Modifier;
+HSPLandroidx/compose/ui/focus/FocusPropertiesKt;->getModifierLocalFocusProperties()Landroidx/compose/ui/modifier/ProvidableModifierLocal;
+HSPLandroidx/compose/ui/focus/FocusPropertiesKt;->refreshFocusProperties(Landroidx/compose/ui/focus/FocusModifier;)V
+HSPLandroidx/compose/ui/focus/FocusPropertiesKt;->setUpdatedProperties(Landroidx/compose/ui/focus/FocusModifier;Landroidx/compose/ui/focus/FocusProperties;)V
+HSPLandroidx/compose/ui/focus/FocusPropertiesModifier;-><init>(Lkotlin/jvm/functions/Function1;Lkotlin/jvm/functions/Function1;)V
+HSPLandroidx/compose/ui/focus/FocusPropertiesModifier;->calculateProperties(Landroidx/compose/ui/focus/FocusProperties;)V
+HSPLandroidx/compose/ui/focus/FocusPropertiesModifier;->equals(Ljava/lang/Object;)Z
+HSPLandroidx/compose/ui/focus/FocusPropertiesModifier;->getKey()Landroidx/compose/ui/modifier/ProvidableModifierLocal;
+HSPLandroidx/compose/ui/focus/FocusPropertiesModifier;->getParent()Landroidx/compose/ui/focus/FocusPropertiesModifier;
+HSPLandroidx/compose/ui/focus/FocusPropertiesModifier;->getValue()Landroidx/compose/ui/focus/FocusPropertiesModifier;
+HSPLandroidx/compose/ui/focus/FocusPropertiesModifier;->getValue()Ljava/lang/Object;
+HSPLandroidx/compose/ui/focus/FocusPropertiesModifier;->onModifierLocalsUpdated(Landroidx/compose/ui/modifier/ModifierLocalReadScope;)V
+HSPLandroidx/compose/ui/focus/FocusPropertiesModifier;->setParent(Landroidx/compose/ui/focus/FocusPropertiesModifier;)V
+HSPLandroidx/compose/ui/focus/FocusRequester$Companion;-><init>()V
+HSPLandroidx/compose/ui/focus/FocusRequester$Companion;-><init>(Lkotlin/jvm/internal/DefaultConstructorMarker;)V
+HSPLandroidx/compose/ui/focus/FocusRequester$Companion;->getDefault()Landroidx/compose/ui/focus/FocusRequester;
+HSPLandroidx/compose/ui/focus/FocusRequester;-><clinit>()V
+HSPLandroidx/compose/ui/focus/FocusRequester;-><init>()V
+HSPLandroidx/compose/ui/focus/FocusRequester;->access$getDefault$cp()Landroidx/compose/ui/focus/FocusRequester;
+HSPLandroidx/compose/ui/focus/FocusRequester;->getFocusRequesterModifierLocals$ui_release()Landroidx/compose/runtime/collection/MutableVector;
+HSPLandroidx/compose/ui/focus/FocusRequesterModifierKt$ModifierLocalFocusRequester$1;-><clinit>()V
+HSPLandroidx/compose/ui/focus/FocusRequesterModifierKt$ModifierLocalFocusRequester$1;-><init>()V
+HSPLandroidx/compose/ui/focus/FocusRequesterModifierKt$ModifierLocalFocusRequester$1;->invoke()Landroidx/compose/ui/focus/FocusRequesterModifierLocal;
+HSPLandroidx/compose/ui/focus/FocusRequesterModifierKt$ModifierLocalFocusRequester$1;->invoke()Ljava/lang/Object;
+HSPLandroidx/compose/ui/focus/FocusRequesterModifierKt$focusRequester$2;-><init>(Landroidx/compose/ui/focus/FocusRequester;)V
+HSPLandroidx/compose/ui/focus/FocusRequesterModifierKt$focusRequester$2;->invoke(Landroidx/compose/ui/Modifier;Landroidx/compose/runtime/Composer;I)Landroidx/compose/ui/Modifier;
+HSPLandroidx/compose/ui/focus/FocusRequesterModifierKt$focusRequester$2;->invoke(Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;
+HSPLandroidx/compose/ui/focus/FocusRequesterModifierKt;-><clinit>()V
+HSPLandroidx/compose/ui/focus/FocusRequesterModifierKt;->focusRequester(Landroidx/compose/ui/Modifier;Landroidx/compose/ui/focus/FocusRequester;)Landroidx/compose/ui/Modifier;
+HSPLandroidx/compose/ui/focus/FocusRequesterModifierKt;->getModifierLocalFocusRequester()Landroidx/compose/ui/modifier/ProvidableModifierLocal;
+HSPLandroidx/compose/ui/focus/FocusRequesterModifierLocal;-><init>(Landroidx/compose/ui/focus/FocusRequester;)V
+HSPLandroidx/compose/ui/focus/FocusRequesterModifierLocal;->addFocusModifier(Landroidx/compose/ui/focus/FocusModifier;)V
+HSPLandroidx/compose/ui/focus/FocusRequesterModifierLocal;->getKey()Landroidx/compose/ui/modifier/ProvidableModifierLocal;
+HSPLandroidx/compose/ui/focus/FocusRequesterModifierLocal;->getValue()Landroidx/compose/ui/focus/FocusRequesterModifierLocal;
+HSPLandroidx/compose/ui/focus/FocusRequesterModifierLocal;->getValue()Ljava/lang/Object;
+HSPLandroidx/compose/ui/focus/FocusRequesterModifierLocal;->onModifierLocalsUpdated(Landroidx/compose/ui/modifier/ModifierLocalReadScope;)V
+HSPLandroidx/compose/ui/focus/FocusStateImpl$WhenMappings;-><clinit>()V
+HSPLandroidx/compose/ui/focus/FocusStateImpl;->$values()[Landroidx/compose/ui/focus/FocusStateImpl;
+HSPLandroidx/compose/ui/focus/FocusStateImpl;-><clinit>()V
+HSPLandroidx/compose/ui/focus/FocusStateImpl;-><init>(Ljava/lang/String;I)V
+HSPLandroidx/compose/ui/focus/FocusStateImpl;->isFocused()Z
+HSPLandroidx/compose/ui/focus/FocusStateImpl;->values()[Landroidx/compose/ui/focus/FocusStateImpl;
+HSPLandroidx/compose/ui/focus/FocusTransactionsKt$WhenMappings;-><clinit>()V
+HSPLandroidx/compose/ui/focus/FocusTransactionsKt;->activateNode(Landroidx/compose/ui/focus/FocusModifier;)V
+HSPLandroidx/compose/ui/focus/FocusTransactionsKt;->deactivateNode(Landroidx/compose/ui/focus/FocusModifier;)V
+HSPLandroidx/compose/ui/focus/FocusTransactionsKt;->sendOnFocusEvent(Landroidx/compose/ui/focus/FocusModifier;)V
+HSPLandroidx/compose/ui/geometry/CornerRadius$Companion;-><init>()V
+HSPLandroidx/compose/ui/geometry/CornerRadius$Companion;-><init>(Lkotlin/jvm/internal/DefaultConstructorMarker;)V
+HSPLandroidx/compose/ui/geometry/CornerRadius$Companion;->getZero-kKHJgLs()J
+HSPLandroidx/compose/ui/geometry/CornerRadius;-><clinit>()V
+HSPLandroidx/compose/ui/geometry/CornerRadius;->access$getZero$cp()J
+HSPLandroidx/compose/ui/geometry/CornerRadius;->constructor-impl(J)J
+HSPLandroidx/compose/ui/geometry/CornerRadius;->getX-impl(J)F
+HSPLandroidx/compose/ui/geometry/CornerRadius;->getY-impl(J)F
+HSPLandroidx/compose/ui/geometry/CornerRadiusKt;->CornerRadius$default(FFILjava/lang/Object;)J
+HSPLandroidx/compose/ui/geometry/CornerRadiusKt;->CornerRadius(FF)J
+HSPLandroidx/compose/ui/geometry/Offset$Companion;-><init>()V
+HSPLandroidx/compose/ui/geometry/Offset$Companion;-><init>(Lkotlin/jvm/internal/DefaultConstructorMarker;)V
+HSPLandroidx/compose/ui/geometry/Offset$Companion;->getInfinite-F1C5BW0()J
+HSPLandroidx/compose/ui/geometry/Offset$Companion;->getUnspecified-F1C5BW0()J
+HSPLandroidx/compose/ui/geometry/Offset$Companion;->getZero-F1C5BW0()J
+HSPLandroidx/compose/ui/geometry/Offset;-><clinit>()V
+HSPLandroidx/compose/ui/geometry/Offset;-><init>(J)V
+HSPLandroidx/compose/ui/geometry/Offset;->access$getInfinite$cp()J
+HSPLandroidx/compose/ui/geometry/Offset;->access$getUnspecified$cp()J
+HSPLandroidx/compose/ui/geometry/Offset;->access$getZero$cp()J
+HSPLandroidx/compose/ui/geometry/Offset;->box-impl(J)Landroidx/compose/ui/geometry/Offset;
+HSPLandroidx/compose/ui/geometry/Offset;->constructor-impl(J)J
+HSPLandroidx/compose/ui/geometry/Offset;->equals(Ljava/lang/Object;)Z
+HSPLandroidx/compose/ui/geometry/Offset;->equals-impl(JLjava/lang/Object;)Z
+HSPLandroidx/compose/ui/geometry/Offset;->getDistance-impl(J)F
+HSPLandroidx/compose/ui/geometry/Offset;->getX-impl(J)F
+HSPLandroidx/compose/ui/geometry/Offset;->getY-impl(J)F
+HSPLandroidx/compose/ui/geometry/Offset;->unbox-impl()J
+HSPLandroidx/compose/ui/geometry/OffsetKt;->Offset(FF)J
+HSPLandroidx/compose/ui/geometry/Rect$Companion;-><init>()V
+HSPLandroidx/compose/ui/geometry/Rect$Companion;-><init>(Lkotlin/jvm/internal/DefaultConstructorMarker;)V
+HSPLandroidx/compose/ui/geometry/Rect$Companion;->getZero()Landroidx/compose/ui/geometry/Rect;
+HSPLandroidx/compose/ui/geometry/Rect;-><clinit>()V
+HSPLandroidx/compose/ui/geometry/Rect;-><init>(FFFF)V
+HSPLandroidx/compose/ui/geometry/Rect;->access$getZero$cp()Landroidx/compose/ui/geometry/Rect;
+HSPLandroidx/compose/ui/geometry/Rect;->getBottom()F
+HSPLandroidx/compose/ui/geometry/Rect;->getLeft()F
+HSPLandroidx/compose/ui/geometry/Rect;->getRight()F
+HSPLandroidx/compose/ui/geometry/Rect;->getTop()F
+HSPLandroidx/compose/ui/geometry/RectKt;->Rect-tz77jQw(JJ)Landroidx/compose/ui/geometry/Rect;
+HSPLandroidx/compose/ui/geometry/RoundRect$Companion;-><init>()V
+HSPLandroidx/compose/ui/geometry/RoundRect$Companion;-><init>(Lkotlin/jvm/internal/DefaultConstructorMarker;)V
+HSPLandroidx/compose/ui/geometry/RoundRect;-><clinit>()V
+HSPLandroidx/compose/ui/geometry/RoundRect;-><init>(FFFFJJJJ)V
+HSPLandroidx/compose/ui/geometry/RoundRect;-><init>(FFFFJJJJLkotlin/jvm/internal/DefaultConstructorMarker;)V
+HSPLandroidx/compose/ui/geometry/RoundRect;->getBottom()F
+HSPLandroidx/compose/ui/geometry/RoundRect;->getBottomLeftCornerRadius-kKHJgLs()J
+HSPLandroidx/compose/ui/geometry/RoundRect;->getBottomRightCornerRadius-kKHJgLs()J
+HSPLandroidx/compose/ui/geometry/RoundRect;->getHeight()F
+HSPLandroidx/compose/ui/geometry/RoundRect;->getLeft()F
+HSPLandroidx/compose/ui/geometry/RoundRect;->getRight()F
+HSPLandroidx/compose/ui/geometry/RoundRect;->getTop()F
+HSPLandroidx/compose/ui/geometry/RoundRect;->getTopLeftCornerRadius-kKHJgLs()J
+HSPLandroidx/compose/ui/geometry/RoundRect;->getTopRightCornerRadius-kKHJgLs()J
+HSPLandroidx/compose/ui/geometry/RoundRect;->getWidth()F
+HSPLandroidx/compose/ui/geometry/RoundRectKt;->RoundRect(FFFFFF)Landroidx/compose/ui/geometry/RoundRect;
+HSPLandroidx/compose/ui/geometry/RoundRectKt;->RoundRect-ZAM2FJo(Landroidx/compose/ui/geometry/Rect;JJJJ)Landroidx/compose/ui/geometry/RoundRect;
+HSPLandroidx/compose/ui/geometry/RoundRectKt;->RoundRect-gG7oq9Y(FFFFJ)Landroidx/compose/ui/geometry/RoundRect;
+HSPLandroidx/compose/ui/geometry/RoundRectKt;->isSimple(Landroidx/compose/ui/geometry/RoundRect;)Z
+HSPLandroidx/compose/ui/geometry/Size$Companion;-><init>()V
+HSPLandroidx/compose/ui/geometry/Size$Companion;-><init>(Lkotlin/jvm/internal/DefaultConstructorMarker;)V
+HSPLandroidx/compose/ui/geometry/Size$Companion;->getUnspecified-NH-jbRc()J
+HSPLandroidx/compose/ui/geometry/Size$Companion;->getZero-NH-jbRc()J
+HSPLandroidx/compose/ui/geometry/Size;-><clinit>()V
+HSPLandroidx/compose/ui/geometry/Size;-><init>(J)V
+HSPLandroidx/compose/ui/geometry/Size;->access$getUnspecified$cp()J
+HSPLandroidx/compose/ui/geometry/Size;->access$getZero$cp()J
+HSPLandroidx/compose/ui/geometry/Size;->box-impl(J)Landroidx/compose/ui/geometry/Size;
+HSPLandroidx/compose/ui/geometry/Size;->constructor-impl(J)J
+HSPLandroidx/compose/ui/geometry/Size;->equals-impl(JLjava/lang/Object;)Z
+HSPLandroidx/compose/ui/geometry/Size;->equals-impl0(JJ)Z
+HSPLandroidx/compose/ui/geometry/Size;->getHeight-impl(J)F
+HSPLandroidx/compose/ui/geometry/Size;->getMinDimension-impl(J)F
+HSPLandroidx/compose/ui/geometry/Size;->getWidth-impl(J)F
+HSPLandroidx/compose/ui/geometry/Size;->unbox-impl()J
+HSPLandroidx/compose/ui/geometry/SizeKt;->Size(FF)J
+HSPLandroidx/compose/ui/geometry/SizeKt;->toRect-uvyYCjk(J)Landroidx/compose/ui/geometry/Rect;
+HSPLandroidx/compose/ui/graphics/AndroidBlendMode_androidKt;->toAndroidBlendMode-s9anfk8(I)Landroid/graphics/BlendMode;
+HSPLandroidx/compose/ui/graphics/AndroidCanvas;-><init>()V
+HSPLandroidx/compose/ui/graphics/AndroidCanvas;->disableZ()V
+HSPLandroidx/compose/ui/graphics/AndroidCanvas;->drawImageRect-HPBpro0(Landroidx/compose/ui/graphics/ImageBitmap;JJJJLandroidx/compose/ui/graphics/Paint;)V
+HSPLandroidx/compose/ui/graphics/AndroidCanvas;->drawPath(Landroidx/compose/ui/graphics/Path;Landroidx/compose/ui/graphics/Paint;)V
+HSPLandroidx/compose/ui/graphics/AndroidCanvas;->drawRect(FFFFLandroidx/compose/ui/graphics/Paint;)V
+HSPLandroidx/compose/ui/graphics/AndroidCanvas;->drawRoundRect(FFFFFFLandroidx/compose/ui/graphics/Paint;)V
+HSPLandroidx/compose/ui/graphics/AndroidCanvas;->enableZ()V
+HSPLandroidx/compose/ui/graphics/AndroidCanvas;->getInternalCanvas()Landroid/graphics/Canvas;
+HSPLandroidx/compose/ui/graphics/AndroidCanvas;->restore()V
+HSPLandroidx/compose/ui/graphics/AndroidCanvas;->save()V
+HSPLandroidx/compose/ui/graphics/AndroidCanvas;->setInternalCanvas(Landroid/graphics/Canvas;)V
+HSPLandroidx/compose/ui/graphics/AndroidCanvas;->translate(FF)V
+HSPLandroidx/compose/ui/graphics/AndroidCanvas_androidKt;-><clinit>()V
+HSPLandroidx/compose/ui/graphics/AndroidCanvas_androidKt;->access$getEmptyCanvas$p()Landroid/graphics/Canvas;
+HSPLandroidx/compose/ui/graphics/AndroidCanvas_androidKt;->getNativeCanvas(Landroidx/compose/ui/graphics/Canvas;)Landroid/graphics/Canvas;
+HSPLandroidx/compose/ui/graphics/AndroidColorFilter_androidKt;->actualTintColorFilter-xETnrds(JI)Landroidx/compose/ui/graphics/ColorFilter;
+HSPLandroidx/compose/ui/graphics/AndroidColorFilter_androidKt;->asAndroidColorFilter(Landroidx/compose/ui/graphics/ColorFilter;)Landroid/graphics/ColorFilter;
+HSPLandroidx/compose/ui/graphics/AndroidImageBitmap;-><init>(Landroid/graphics/Bitmap;)V
+HSPLandroidx/compose/ui/graphics/AndroidImageBitmap;->getBitmap$ui_graphics_release()Landroid/graphics/Bitmap;
+HSPLandroidx/compose/ui/graphics/AndroidImageBitmap;->getHeight()I
+HSPLandroidx/compose/ui/graphics/AndroidImageBitmap;->getWidth()I
+HSPLandroidx/compose/ui/graphics/AndroidImageBitmap_androidKt;->asAndroidBitmap(Landroidx/compose/ui/graphics/ImageBitmap;)Landroid/graphics/Bitmap;
+HSPLandroidx/compose/ui/graphics/AndroidImageBitmap_androidKt;->asImageBitmap(Landroid/graphics/Bitmap;)Landroidx/compose/ui/graphics/ImageBitmap;
+HSPLandroidx/compose/ui/graphics/AndroidPaint;-><init>()V
+HSPLandroidx/compose/ui/graphics/AndroidPaint;-><init>(Landroid/graphics/Paint;)V
+HSPLandroidx/compose/ui/graphics/AndroidPaint;->asFrameworkPaint()Landroid/graphics/Paint;
+HSPLandroidx/compose/ui/graphics/AndroidPaint;->getAlpha()F
+HSPLandroidx/compose/ui/graphics/AndroidPaint;->getBlendMode-0nO6VwU()I
+HSPLandroidx/compose/ui/graphics/AndroidPaint;->getColor-0d7_KjU()J
+HSPLandroidx/compose/ui/graphics/AndroidPaint;->getColorFilter()Landroidx/compose/ui/graphics/ColorFilter;
+HSPLandroidx/compose/ui/graphics/AndroidPaint;->getFilterQuality-f-v9h1I()I
+HSPLandroidx/compose/ui/graphics/AndroidPaint;->getShader()Landroid/graphics/Shader;
+HSPLandroidx/compose/ui/graphics/AndroidPaint;->setAlpha(F)V
+HSPLandroidx/compose/ui/graphics/AndroidPaint;->setColor-8_81llA(J)V
+HSPLandroidx/compose/ui/graphics/AndroidPaint;->setColorFilter(Landroidx/compose/ui/graphics/ColorFilter;)V
+HSPLandroidx/compose/ui/graphics/AndroidPaint;->setShader(Landroid/graphics/Shader;)V
+HSPLandroidx/compose/ui/graphics/AndroidPaint;->setStrokeWidth(F)V
+HSPLandroidx/compose/ui/graphics/AndroidPaint;->setStyle-k9PVt8s(I)V
+HSPLandroidx/compose/ui/graphics/AndroidPaint_androidKt;->Paint()Landroidx/compose/ui/graphics/Paint;
+HSPLandroidx/compose/ui/graphics/AndroidPaint_androidKt;->getNativeAlpha(Landroid/graphics/Paint;)F
+HSPLandroidx/compose/ui/graphics/AndroidPaint_androidKt;->getNativeColor(Landroid/graphics/Paint;)J
+HSPLandroidx/compose/ui/graphics/AndroidPaint_androidKt;->getNativeFilterQuality(Landroid/graphics/Paint;)I
+HSPLandroidx/compose/ui/graphics/AndroidPaint_androidKt;->makeNativePaint()Landroid/graphics/Paint;
+HSPLandroidx/compose/ui/graphics/AndroidPaint_androidKt;->setNativeAlpha(Landroid/graphics/Paint;F)V
+HSPLandroidx/compose/ui/graphics/AndroidPaint_androidKt;->setNativeColor-4WTKRHQ(Landroid/graphics/Paint;J)V
+HSPLandroidx/compose/ui/graphics/AndroidPaint_androidKt;->setNativeColorFilter(Landroid/graphics/Paint;Landroidx/compose/ui/graphics/ColorFilter;)V
+HSPLandroidx/compose/ui/graphics/AndroidPaint_androidKt;->setNativeShader(Landroid/graphics/Paint;Landroid/graphics/Shader;)V
+HSPLandroidx/compose/ui/graphics/AndroidPaint_androidKt;->setNativeStrokeWidth(Landroid/graphics/Paint;F)V
+HSPLandroidx/compose/ui/graphics/AndroidPaint_androidKt;->setNativeStyle--5YerkU(Landroid/graphics/Paint;I)V
+HSPLandroidx/compose/ui/graphics/AndroidPaint_androidKt;->toComposePaint(Landroid/graphics/Paint;)Landroidx/compose/ui/graphics/Paint;
+HSPLandroidx/compose/ui/graphics/AndroidPath;-><init>(Landroid/graphics/Path;)V
+HSPLandroidx/compose/ui/graphics/AndroidPath;-><init>(Landroid/graphics/Path;ILkotlin/jvm/internal/DefaultConstructorMarker;)V
+HSPLandroidx/compose/ui/graphics/AndroidPath;->addRoundRect(Landroidx/compose/ui/geometry/RoundRect;)V
+HSPLandroidx/compose/ui/graphics/AndroidPath;->getInternalPath()Landroid/graphics/Path;
+HSPLandroidx/compose/ui/graphics/AndroidPath;->reset()V
+HSPLandroidx/compose/ui/graphics/AndroidPath_androidKt;->Path()Landroidx/compose/ui/graphics/Path;
+HSPLandroidx/compose/ui/graphics/BlendMode$Companion;-><init>()V
+HSPLandroidx/compose/ui/graphics/BlendMode$Companion;-><init>(Lkotlin/jvm/internal/DefaultConstructorMarker;)V
+HSPLandroidx/compose/ui/graphics/BlendMode$Companion;->getClear-0nO6VwU()I
+HSPLandroidx/compose/ui/graphics/BlendMode$Companion;->getDst-0nO6VwU()I
+HSPLandroidx/compose/ui/graphics/BlendMode$Companion;->getDstOver-0nO6VwU()I
+HSPLandroidx/compose/ui/graphics/BlendMode$Companion;->getSrc-0nO6VwU()I
+HSPLandroidx/compose/ui/graphics/BlendMode$Companion;->getSrcIn-0nO6VwU()I
+HSPLandroidx/compose/ui/graphics/BlendMode$Companion;->getSrcOver-0nO6VwU()I
+HSPLandroidx/compose/ui/graphics/BlendMode;-><clinit>()V
+HSPLandroidx/compose/ui/graphics/BlendMode;->access$getClear$cp()I
+HSPLandroidx/compose/ui/graphics/BlendMode;->access$getDst$cp()I
+HSPLandroidx/compose/ui/graphics/BlendMode;->access$getDstOver$cp()I
+HSPLandroidx/compose/ui/graphics/BlendMode;->access$getSrc$cp()I
+HSPLandroidx/compose/ui/graphics/BlendMode;->access$getSrcIn$cp()I
+HSPLandroidx/compose/ui/graphics/BlendMode;->access$getSrcOver$cp()I
+HSPLandroidx/compose/ui/graphics/BlendMode;->constructor-impl(I)I
+HSPLandroidx/compose/ui/graphics/BlendMode;->equals-impl0(II)Z
+HSPLandroidx/compose/ui/graphics/BlendModeColorFilterHelper;-><clinit>()V
+HSPLandroidx/compose/ui/graphics/BlendModeColorFilterHelper;-><init>()V
+HSPLandroidx/compose/ui/graphics/BlendModeColorFilterHelper;->BlendModeColorFilter-xETnrds(JI)Landroid/graphics/BlendModeColorFilter;
+HSPLandroidx/compose/ui/graphics/BlockGraphicsLayerModifier$measure$1;-><init>(Landroidx/compose/ui/layout/Placeable;Landroidx/compose/ui/graphics/BlockGraphicsLayerModifier;)V
+HSPLandroidx/compose/ui/graphics/BlockGraphicsLayerModifier$measure$1;->invoke(Landroidx/compose/ui/layout/Placeable$PlacementScope;)V
+HSPLandroidx/compose/ui/graphics/BlockGraphicsLayerModifier$measure$1;->invoke(Ljava/lang/Object;)Ljava/lang/Object;
+HSPLandroidx/compose/ui/graphics/BlockGraphicsLayerModifier;-><init>(Lkotlin/jvm/functions/Function1;Lkotlin/jvm/functions/Function1;)V
+HSPLandroidx/compose/ui/graphics/BlockGraphicsLayerModifier;->access$getLayerBlock$p(Landroidx/compose/ui/graphics/BlockGraphicsLayerModifier;)Lkotlin/jvm/functions/Function1;
+HSPLandroidx/compose/ui/graphics/BlockGraphicsLayerModifier;->equals(Ljava/lang/Object;)Z
+HSPLandroidx/compose/ui/graphics/BlockGraphicsLayerModifier;->measure-3p2s80s(Landroidx/compose/ui/layout/MeasureScope;Landroidx/compose/ui/layout/Measurable;J)Landroidx/compose/ui/layout/MeasureResult;
+HSPLandroidx/compose/ui/graphics/CanvasHolder;-><init>()V
+HSPLandroidx/compose/ui/graphics/CanvasHolder;->getAndroidCanvas()Landroidx/compose/ui/graphics/AndroidCanvas;
+HSPLandroidx/compose/ui/graphics/CanvasUtils;-><clinit>()V
+HSPLandroidx/compose/ui/graphics/CanvasUtils;-><init>()V
+HSPLandroidx/compose/ui/graphics/CanvasUtils;->enableZ(Landroid/graphics/Canvas;Z)V
+HSPLandroidx/compose/ui/graphics/CanvasZHelper;-><clinit>()V
+HSPLandroidx/compose/ui/graphics/CanvasZHelper;-><init>()V
+HSPLandroidx/compose/ui/graphics/CanvasZHelper;->enableZ(Landroid/graphics/Canvas;Z)V
+HSPLandroidx/compose/ui/graphics/Color$Companion;-><init>()V
+HSPLandroidx/compose/ui/graphics/Color$Companion;-><init>(Lkotlin/jvm/internal/DefaultConstructorMarker;)V
+HSPLandroidx/compose/ui/graphics/Color$Companion;->getBlack-0d7_KjU()J
+HSPLandroidx/compose/ui/graphics/Color$Companion;->getBlue-0d7_KjU()J
+HSPLandroidx/compose/ui/graphics/Color$Companion;->getLightGray-0d7_KjU()J
+HSPLandroidx/compose/ui/graphics/Color$Companion;->getRed-0d7_KjU()J
+HSPLandroidx/compose/ui/graphics/Color$Companion;->getTransparent-0d7_KjU()J
+HSPLandroidx/compose/ui/graphics/Color$Companion;->getUnspecified-0d7_KjU()J
+HSPLandroidx/compose/ui/graphics/Color;-><clinit>()V
+HSPLandroidx/compose/ui/graphics/Color;-><init>(J)V
+HSPLandroidx/compose/ui/graphics/Color;->access$getBlack$cp()J
+HSPLandroidx/compose/ui/graphics/Color;->access$getBlue$cp()J
+HSPLandroidx/compose/ui/graphics/Color;->access$getLightGray$cp()J
+HSPLandroidx/compose/ui/graphics/Color;->access$getRed$cp()J
+HSPLandroidx/compose/ui/graphics/Color;->access$getTransparent$cp()J
+HSPLandroidx/compose/ui/graphics/Color;->access$getUnspecified$cp()J
+HSPLandroidx/compose/ui/graphics/Color;->box-impl(J)Landroidx/compose/ui/graphics/Color;
+HSPLandroidx/compose/ui/graphics/Color;->constructor-impl(J)J
+HSPLandroidx/compose/ui/graphics/Color;->convert-vNxB06k(JLandroidx/compose/ui/graphics/colorspace/ColorSpace;)J
+HSPLandroidx/compose/ui/graphics/Color;->copy-wmQWz5c$default(JFFFFILjava/lang/Object;)J
+HSPLandroidx/compose/ui/graphics/Color;->copy-wmQWz5c(JFFFF)J
+HSPLandroidx/compose/ui/graphics/Color;->equals(Ljava/lang/Object;)Z
+HSPLandroidx/compose/ui/graphics/Color;->equals-impl(JLjava/lang/Object;)Z
+HSPLandroidx/compose/ui/graphics/Color;->equals-impl0(JJ)Z
+HSPLandroidx/compose/ui/graphics/Color;->getAlpha-impl(J)F
+HSPLandroidx/compose/ui/graphics/Color;->getBlue-impl(J)F
+HSPLandroidx/compose/ui/graphics/Color;->getColorSpace-impl(J)Landroidx/compose/ui/graphics/colorspace/ColorSpace;
+HSPLandroidx/compose/ui/graphics/Color;->getGreen-impl(J)F
+HSPLandroidx/compose/ui/graphics/Color;->getRed-impl(J)F
+HSPLandroidx/compose/ui/graphics/Color;->unbox-impl()J
+HSPLandroidx/compose/ui/graphics/ColorFilter$Companion;-><init>()V
+HSPLandroidx/compose/ui/graphics/ColorFilter$Companion;-><init>(Lkotlin/jvm/internal/DefaultConstructorMarker;)V
+HSPLandroidx/compose/ui/graphics/ColorFilter$Companion;->tint-xETnrds$default(Landroidx/compose/ui/graphics/ColorFilter$Companion;JIILjava/lang/Object;)Landroidx/compose/ui/graphics/ColorFilter;
+HSPLandroidx/compose/ui/graphics/ColorFilter$Companion;->tint-xETnrds(JI)Landroidx/compose/ui/graphics/ColorFilter;
+HSPLandroidx/compose/ui/graphics/ColorFilter;-><clinit>()V
+HSPLandroidx/compose/ui/graphics/ColorFilter;-><init>(Landroid/graphics/ColorFilter;)V
+HSPLandroidx/compose/ui/graphics/ColorFilter;->getNativeColorFilter$ui_graphics_release()Landroid/graphics/ColorFilter;
+HSPLandroidx/compose/ui/graphics/ColorKt;->Color$default(IIIIILjava/lang/Object;)J
+HSPLandroidx/compose/ui/graphics/ColorKt;->Color(FFFFLandroidx/compose/ui/graphics/colorspace/ColorSpace;)J
+HSPLandroidx/compose/ui/graphics/ColorKt;->Color(I)J
+HSPLandroidx/compose/ui/graphics/ColorKt;->Color(IIII)J
+HSPLandroidx/compose/ui/graphics/ColorKt;->Color(J)J
+HSPLandroidx/compose/ui/graphics/ColorKt;->compositeOver--OWjLjI(JJ)J
+HSPLandroidx/compose/ui/graphics/ColorKt;->toArgb-8_81llA(J)I
+HSPLandroidx/compose/ui/graphics/CompositingStrategy$Companion;-><init>()V
+HSPLandroidx/compose/ui/graphics/CompositingStrategy$Companion;-><init>(Lkotlin/jvm/internal/DefaultConstructorMarker;)V
+HSPLandroidx/compose/ui/graphics/CompositingStrategy$Companion;->getAuto--NrFUSI()I
+HSPLandroidx/compose/ui/graphics/CompositingStrategy$Companion;->getModulateAlpha--NrFUSI()I
+HSPLandroidx/compose/ui/graphics/CompositingStrategy$Companion;->getOffscreen--NrFUSI()I
+HSPLandroidx/compose/ui/graphics/CompositingStrategy;-><clinit>()V
+HSPLandroidx/compose/ui/graphics/CompositingStrategy;->access$getAuto$cp()I
+HSPLandroidx/compose/ui/graphics/CompositingStrategy;->access$getModulateAlpha$cp()I
+HSPLandroidx/compose/ui/graphics/CompositingStrategy;->access$getOffscreen$cp()I
+HSPLandroidx/compose/ui/graphics/CompositingStrategy;->constructor-impl(I)I
+HSPLandroidx/compose/ui/graphics/CompositingStrategy;->equals-impl0(II)Z
+HSPLandroidx/compose/ui/graphics/FilterQuality$Companion;-><init>()V
+HSPLandroidx/compose/ui/graphics/FilterQuality$Companion;-><init>(Lkotlin/jvm/internal/DefaultConstructorMarker;)V
+HSPLandroidx/compose/ui/graphics/FilterQuality$Companion;->getLow-f-v9h1I()I
+HSPLandroidx/compose/ui/graphics/FilterQuality;-><clinit>()V
+HSPLandroidx/compose/ui/graphics/FilterQuality;->access$getLow$cp()I
+HSPLandroidx/compose/ui/graphics/FilterQuality;->constructor-impl(I)I
+HSPLandroidx/compose/ui/graphics/FilterQuality;->equals-impl0(II)Z
+HSPLandroidx/compose/ui/graphics/Float16$Companion;-><init>()V
+HSPLandroidx/compose/ui/graphics/Float16$Companion;-><init>(Lkotlin/jvm/internal/DefaultConstructorMarker;)V
+HSPLandroidx/compose/ui/graphics/Float16$Companion;->access$floatToHalf(Landroidx/compose/ui/graphics/Float16$Companion;F)S
+HSPLandroidx/compose/ui/graphics/Float16$Companion;->floatToHalf(F)S
+HSPLandroidx/compose/ui/graphics/Float16;-><clinit>()V
+HSPLandroidx/compose/ui/graphics/Float16;->constructor-impl(F)S
+HSPLandroidx/compose/ui/graphics/Float16;->constructor-impl(S)S
+HSPLandroidx/compose/ui/graphics/GraphicsLayerModifierKt;->graphicsLayer(Landroidx/compose/ui/Modifier;Lkotlin/jvm/functions/Function1;)Landroidx/compose/ui/Modifier;
+HSPLandroidx/compose/ui/graphics/GraphicsLayerModifierKt;->graphicsLayer-Ap8cVGQ$default(Landroidx/compose/ui/Modifier;FFFFFFFFFFJLandroidx/compose/ui/graphics/Shape;ZLandroidx/compose/ui/graphics/RenderEffect;JJIILjava/lang/Object;)Landroidx/compose/ui/Modifier;
+HSPLandroidx/compose/ui/graphics/GraphicsLayerModifierKt;->graphicsLayer-Ap8cVGQ(Landroidx/compose/ui/Modifier;FFFFFFFFFFJLandroidx/compose/ui/graphics/Shape;ZLandroidx/compose/ui/graphics/RenderEffect;JJI)Landroidx/compose/ui/Modifier;
+HSPLandroidx/compose/ui/graphics/GraphicsLayerModifierKt;->toolingGraphicsLayer(Landroidx/compose/ui/Modifier;)Landroidx/compose/ui/Modifier;
+HSPLandroidx/compose/ui/graphics/GraphicsLayerScopeKt;-><clinit>()V
+HSPLandroidx/compose/ui/graphics/GraphicsLayerScopeKt;->getDefaultShadowColor()J
+HSPLandroidx/compose/ui/graphics/Matrix$Companion;-><init>()V
+HSPLandroidx/compose/ui/graphics/Matrix$Companion;-><init>(Lkotlin/jvm/internal/DefaultConstructorMarker;)V
+HSPLandroidx/compose/ui/graphics/Matrix;-><clinit>()V
+HSPLandroidx/compose/ui/graphics/Matrix;->constructor-impl$default([FILkotlin/jvm/internal/DefaultConstructorMarker;)[F
+HSPLandroidx/compose/ui/graphics/Matrix;->constructor-impl([F)[F
+HSPLandroidx/compose/ui/graphics/Outline$Rounded;-><init>(Landroidx/compose/ui/geometry/RoundRect;)V
+HSPLandroidx/compose/ui/graphics/Outline$Rounded;->getRoundRect()Landroidx/compose/ui/geometry/RoundRect;
+HSPLandroidx/compose/ui/graphics/Outline$Rounded;->getRoundRectPath$ui_graphics_release()Landroidx/compose/ui/graphics/Path;
+HSPLandroidx/compose/ui/graphics/Outline;-><init>()V
+HSPLandroidx/compose/ui/graphics/Outline;-><init>(Lkotlin/jvm/internal/DefaultConstructorMarker;)V
+HSPLandroidx/compose/ui/graphics/OutlineKt;->access$hasSameCornerRadius(Landroidx/compose/ui/geometry/RoundRect;)Z
+HSPLandroidx/compose/ui/graphics/OutlineKt;->drawOutline-wDX37Ww$default(Landroidx/compose/ui/graphics/drawscope/DrawScope;Landroidx/compose/ui/graphics/Outline;JFLandroidx/compose/ui/graphics/drawscope/DrawStyle;Landroidx/compose/ui/graphics/ColorFilter;IILjava/lang/Object;)V
+HSPLandroidx/compose/ui/graphics/OutlineKt;->drawOutline-wDX37Ww(Landroidx/compose/ui/graphics/drawscope/DrawScope;Landroidx/compose/ui/graphics/Outline;JFLandroidx/compose/ui/graphics/drawscope/DrawStyle;Landroidx/compose/ui/graphics/ColorFilter;I)V
+HSPLandroidx/compose/ui/graphics/OutlineKt;->hasSameCornerRadius(Landroidx/compose/ui/geometry/RoundRect;)Z
+HSPLandroidx/compose/ui/graphics/OutlineKt;->size(Landroidx/compose/ui/geometry/RoundRect;)J
+HSPLandroidx/compose/ui/graphics/OutlineKt;->topLeft(Landroidx/compose/ui/geometry/RoundRect;)J
+HSPLandroidx/compose/ui/graphics/PaintingStyle$Companion;-><init>()V
+HSPLandroidx/compose/ui/graphics/PaintingStyle$Companion;-><init>(Lkotlin/jvm/internal/DefaultConstructorMarker;)V
+HSPLandroidx/compose/ui/graphics/PaintingStyle$Companion;->getFill-TiuSbCo()I
+HSPLandroidx/compose/ui/graphics/PaintingStyle$Companion;->getStroke-TiuSbCo()I
+HSPLandroidx/compose/ui/graphics/PaintingStyle;-><clinit>()V
+HSPLandroidx/compose/ui/graphics/PaintingStyle;->access$getFill$cp()I
+HSPLandroidx/compose/ui/graphics/PaintingStyle;->access$getStroke$cp()I
+HSPLandroidx/compose/ui/graphics/PaintingStyle;->constructor-impl(I)I
+HSPLandroidx/compose/ui/graphics/PaintingStyle;->equals-impl0(II)Z
+HSPLandroidx/compose/ui/graphics/RectangleShapeKt$RectangleShape$1;-><init>()V
+HSPLandroidx/compose/ui/graphics/RectangleShapeKt;-><clinit>()V
+HSPLandroidx/compose/ui/graphics/RectangleShapeKt;->getRectangleShape()Landroidx/compose/ui/graphics/Shape;
+HSPLandroidx/compose/ui/graphics/ReusableGraphicsLayerScope;-><init>()V
+HSPLandroidx/compose/ui/graphics/ReusableGraphicsLayerScope;->getAlpha()F
+HSPLandroidx/compose/ui/graphics/ReusableGraphicsLayerScope;->getAmbientShadowColor-0d7_KjU()J
+HSPLandroidx/compose/ui/graphics/ReusableGraphicsLayerScope;->getCameraDistance()F
+HSPLandroidx/compose/ui/graphics/ReusableGraphicsLayerScope;->getClip()Z
+HSPLandroidx/compose/ui/graphics/ReusableGraphicsLayerScope;->getCompositingStrategy--NrFUSI()I
+HSPLandroidx/compose/ui/graphics/ReusableGraphicsLayerScope;->getDensity()F
+HSPLandroidx/compose/ui/graphics/ReusableGraphicsLayerScope;->getRenderEffect()Landroidx/compose/ui/graphics/RenderEffect;
+HSPLandroidx/compose/ui/graphics/ReusableGraphicsLayerScope;->getRotationX()F
+HSPLandroidx/compose/ui/graphics/ReusableGraphicsLayerScope;->getRotationY()F
+HSPLandroidx/compose/ui/graphics/ReusableGraphicsLayerScope;->getRotationZ()F
+HSPLandroidx/compose/ui/graphics/ReusableGraphicsLayerScope;->getScaleX()F
+HSPLandroidx/compose/ui/graphics/ReusableGraphicsLayerScope;->getScaleY()F
+HSPLandroidx/compose/ui/graphics/ReusableGraphicsLayerScope;->getShadowElevation()F
+HSPLandroidx/compose/ui/graphics/ReusableGraphicsLayerScope;->getShape()Landroidx/compose/ui/graphics/Shape;
+HSPLandroidx/compose/ui/graphics/ReusableGraphicsLayerScope;->getSpotShadowColor-0d7_KjU()J
+HSPLandroidx/compose/ui/graphics/ReusableGraphicsLayerScope;->getTransformOrigin-SzJe1aQ()J
+HSPLandroidx/compose/ui/graphics/ReusableGraphicsLayerScope;->getTranslationX()F
+HSPLandroidx/compose/ui/graphics/ReusableGraphicsLayerScope;->getTranslationY()F
+HSPLandroidx/compose/ui/graphics/ReusableGraphicsLayerScope;->reset()V
+HSPLandroidx/compose/ui/graphics/ReusableGraphicsLayerScope;->setAlpha(F)V
+HSPLandroidx/compose/ui/graphics/ReusableGraphicsLayerScope;->setAmbientShadowColor-8_81llA(J)V
+HSPLandroidx/compose/ui/graphics/ReusableGraphicsLayerScope;->setCameraDistance(F)V
+HSPLandroidx/compose/ui/graphics/ReusableGraphicsLayerScope;->setClip(Z)V
+HSPLandroidx/compose/ui/graphics/ReusableGraphicsLayerScope;->setCompositingStrategy-aDBOjCE(I)V
+HSPLandroidx/compose/ui/graphics/ReusableGraphicsLayerScope;->setGraphicsDensity$ui_release(Landroidx/compose/ui/unit/Density;)V
+HSPLandroidx/compose/ui/graphics/ReusableGraphicsLayerScope;->setRenderEffect(Landroidx/compose/ui/graphics/RenderEffect;)V
+HSPLandroidx/compose/ui/graphics/ReusableGraphicsLayerScope;->setRotationX(F)V
+HSPLandroidx/compose/ui/graphics/ReusableGraphicsLayerScope;->setRotationY(F)V
+HSPLandroidx/compose/ui/graphics/ReusableGraphicsLayerScope;->setRotationZ(F)V
+HSPLandroidx/compose/ui/graphics/ReusableGraphicsLayerScope;->setScaleX(F)V
+HSPLandroidx/compose/ui/graphics/ReusableGraphicsLayerScope;->setScaleY(F)V
+HSPLandroidx/compose/ui/graphics/ReusableGraphicsLayerScope;->setShadowElevation(F)V
+HSPLandroidx/compose/ui/graphics/ReusableGraphicsLayerScope;->setShape(Landroidx/compose/ui/graphics/Shape;)V
+HSPLandroidx/compose/ui/graphics/ReusableGraphicsLayerScope;->setSize-uvyYCjk(J)V
+HSPLandroidx/compose/ui/graphics/ReusableGraphicsLayerScope;->setSpotShadowColor-8_81llA(J)V
+HSPLandroidx/compose/ui/graphics/ReusableGraphicsLayerScope;->setTransformOrigin-__ExYCQ(J)V
+HSPLandroidx/compose/ui/graphics/ReusableGraphicsLayerScope;->setTranslationX(F)V
+HSPLandroidx/compose/ui/graphics/ReusableGraphicsLayerScope;->setTranslationY(F)V
+HSPLandroidx/compose/ui/graphics/Shadow$Companion;-><init>()V
+HSPLandroidx/compose/ui/graphics/Shadow$Companion;-><init>(Lkotlin/jvm/internal/DefaultConstructorMarker;)V
+HSPLandroidx/compose/ui/graphics/Shadow$Companion;->getNone()Landroidx/compose/ui/graphics/Shadow;
+HSPLandroidx/compose/ui/graphics/Shadow;-><clinit>()V
+HSPLandroidx/compose/ui/graphics/Shadow;-><init>(JJF)V
+HSPLandroidx/compose/ui/graphics/Shadow;-><init>(JJFILkotlin/jvm/internal/DefaultConstructorMarker;)V
+HSPLandroidx/compose/ui/graphics/Shadow;-><init>(JJFLkotlin/jvm/internal/DefaultConstructorMarker;)V
+HSPLandroidx/compose/ui/graphics/Shadow;->access$getNone$cp()Landroidx/compose/ui/graphics/Shadow;
+HSPLandroidx/compose/ui/graphics/Shadow;->equals(Ljava/lang/Object;)Z
+HSPLandroidx/compose/ui/graphics/SimpleGraphicsLayerModifier$layerBlock$1;-><init>(Landroidx/compose/ui/graphics/SimpleGraphicsLayerModifier;)V
+HSPLandroidx/compose/ui/graphics/SimpleGraphicsLayerModifier$layerBlock$1;->invoke(Landroidx/compose/ui/graphics/GraphicsLayerScope;)V
+HSPLandroidx/compose/ui/graphics/SimpleGraphicsLayerModifier$layerBlock$1;->invoke(Ljava/lang/Object;)Ljava/lang/Object;
+HSPLandroidx/compose/ui/graphics/SimpleGraphicsLayerModifier$measure$1;-><init>(Landroidx/compose/ui/layout/Placeable;Landroidx/compose/ui/graphics/SimpleGraphicsLayerModifier;)V
+HSPLandroidx/compose/ui/graphics/SimpleGraphicsLayerModifier$measure$1;->invoke(Landroidx/compose/ui/layout/Placeable$PlacementScope;)V
+HSPLandroidx/compose/ui/graphics/SimpleGraphicsLayerModifier$measure$1;->invoke(Ljava/lang/Object;)Ljava/lang/Object;
+HSPLandroidx/compose/ui/graphics/SimpleGraphicsLayerModifier;-><init>(FFFFFFFFFFJLandroidx/compose/ui/graphics/Shape;ZLandroidx/compose/ui/graphics/RenderEffect;JJILkotlin/jvm/functions/Function1;)V
+HSPLandroidx/compose/ui/graphics/SimpleGraphicsLayerModifier;-><init>(FFFFFFFFFFJLandroidx/compose/ui/graphics/Shape;ZLandroidx/compose/ui/graphics/RenderEffect;JJILkotlin/jvm/functions/Function1;Lkotlin/jvm/internal/DefaultConstructorMarker;)V
+HSPLandroidx/compose/ui/graphics/SimpleGraphicsLayerModifier;->access$getAlpha$p(Landroidx/compose/ui/graphics/SimpleGraphicsLayerModifier;)F
+HSPLandroidx/compose/ui/graphics/SimpleGraphicsLayerModifier;->access$getAmbientShadowColor$p(Landroidx/compose/ui/graphics/SimpleGraphicsLayerModifier;)J
+HSPLandroidx/compose/ui/graphics/SimpleGraphicsLayerModifier;->access$getCameraDistance$p(Landroidx/compose/ui/graphics/SimpleGraphicsLayerModifier;)F
+HSPLandroidx/compose/ui/graphics/SimpleGraphicsLayerModifier;->access$getClip$p(Landroidx/compose/ui/graphics/SimpleGraphicsLayerModifier;)Z
+HSPLandroidx/compose/ui/graphics/SimpleGraphicsLayerModifier;->access$getCompositingStrategy$p(Landroidx/compose/ui/graphics/SimpleGraphicsLayerModifier;)I
+HSPLandroidx/compose/ui/graphics/SimpleGraphicsLayerModifier;->access$getLayerBlock$p(Landroidx/compose/ui/graphics/SimpleGraphicsLayerModifier;)Lkotlin/jvm/functions/Function1;
+HSPLandroidx/compose/ui/graphics/SimpleGraphicsLayerModifier;->access$getRenderEffect$p(Landroidx/compose/ui/graphics/SimpleGraphicsLayerModifier;)Landroidx/compose/ui/graphics/RenderEffect;
+HSPLandroidx/compose/ui/graphics/SimpleGraphicsLayerModifier;->access$getRotationX$p(Landroidx/compose/ui/graphics/SimpleGraphicsLayerModifier;)F
+HSPLandroidx/compose/ui/graphics/SimpleGraphicsLayerModifier;->access$getRotationY$p(Landroidx/compose/ui/graphics/SimpleGraphicsLayerModifier;)F
+HSPLandroidx/compose/ui/graphics/SimpleGraphicsLayerModifier;->access$getRotationZ$p(Landroidx/compose/ui/graphics/SimpleGraphicsLayerModifier;)F
+HSPLandroidx/compose/ui/graphics/SimpleGraphicsLayerModifier;->access$getScaleX$p(Landroidx/compose/ui/graphics/SimpleGraphicsLayerModifier;)F
+HSPLandroidx/compose/ui/graphics/SimpleGraphicsLayerModifier;->access$getScaleY$p(Landroidx/compose/ui/graphics/SimpleGraphicsLayerModifier;)F
+HSPLandroidx/compose/ui/graphics/SimpleGraphicsLayerModifier;->access$getShadowElevation$p(Landroidx/compose/ui/graphics/SimpleGraphicsLayerModifier;)F
+HSPLandroidx/compose/ui/graphics/SimpleGraphicsLayerModifier;->access$getShape$p(Landroidx/compose/ui/graphics/SimpleGraphicsLayerModifier;)Landroidx/compose/ui/graphics/Shape;
+HSPLandroidx/compose/ui/graphics/SimpleGraphicsLayerModifier;->access$getSpotShadowColor$p(Landroidx/compose/ui/graphics/SimpleGraphicsLayerModifier;)J
+HSPLandroidx/compose/ui/graphics/SimpleGraphicsLayerModifier;->access$getTransformOrigin$p(Landroidx/compose/ui/graphics/SimpleGraphicsLayerModifier;)J
+HSPLandroidx/compose/ui/graphics/SimpleGraphicsLayerModifier;->access$getTranslationX$p(Landroidx/compose/ui/graphics/SimpleGraphicsLayerModifier;)F
+HSPLandroidx/compose/ui/graphics/SimpleGraphicsLayerModifier;->access$getTranslationY$p(Landroidx/compose/ui/graphics/SimpleGraphicsLayerModifier;)F
+HSPLandroidx/compose/ui/graphics/SimpleGraphicsLayerModifier;->equals(Ljava/lang/Object;)Z
+HSPLandroidx/compose/ui/graphics/SimpleGraphicsLayerModifier;->measure-3p2s80s(Landroidx/compose/ui/layout/MeasureScope;Landroidx/compose/ui/layout/Measurable;J)Landroidx/compose/ui/layout/MeasureResult;
+HSPLandroidx/compose/ui/graphics/TransformOrigin$Companion;-><init>()V
+HSPLandroidx/compose/ui/graphics/TransformOrigin$Companion;-><init>(Lkotlin/jvm/internal/DefaultConstructorMarker;)V
+HSPLandroidx/compose/ui/graphics/TransformOrigin$Companion;->getCenter-SzJe1aQ()J
+HSPLandroidx/compose/ui/graphics/TransformOrigin;-><clinit>()V
+HSPLandroidx/compose/ui/graphics/TransformOrigin;->access$getCenter$cp()J
+HSPLandroidx/compose/ui/graphics/TransformOrigin;->constructor-impl(J)J
+HSPLandroidx/compose/ui/graphics/TransformOrigin;->equals-impl0(JJ)Z
+HSPLandroidx/compose/ui/graphics/TransformOrigin;->getPivotFractionX-impl(J)F
+HSPLandroidx/compose/ui/graphics/TransformOrigin;->getPivotFractionY-impl(J)F
+HSPLandroidx/compose/ui/graphics/TransformOriginKt;->TransformOrigin(FF)J
+HSPLandroidx/compose/ui/graphics/colorspace/Adaptation$Companion$Bradford$1;-><init>([F)V
+HSPLandroidx/compose/ui/graphics/colorspace/Adaptation$Companion$Ciecat02$1;-><init>([F)V
+HSPLandroidx/compose/ui/graphics/colorspace/Adaptation$Companion$VonKries$1;-><init>([F)V
+HSPLandroidx/compose/ui/graphics/colorspace/Adaptation$Companion;-><init>()V
+HSPLandroidx/compose/ui/graphics/colorspace/Adaptation$Companion;-><init>(Lkotlin/jvm/internal/DefaultConstructorMarker;)V
+HSPLandroidx/compose/ui/graphics/colorspace/Adaptation$Companion;->getBradford()Landroidx/compose/ui/graphics/colorspace/Adaptation;
+HSPLandroidx/compose/ui/graphics/colorspace/Adaptation;-><clinit>()V
+HSPLandroidx/compose/ui/graphics/colorspace/Adaptation;-><init>([F)V
+HSPLandroidx/compose/ui/graphics/colorspace/Adaptation;-><init>([FLkotlin/jvm/internal/DefaultConstructorMarker;)V
+HSPLandroidx/compose/ui/graphics/colorspace/Adaptation;->access$getBradford$cp()Landroidx/compose/ui/graphics/colorspace/Adaptation;
+HSPLandroidx/compose/ui/graphics/colorspace/Adaptation;->getTransform$ui_graphics_release()[F
+HSPLandroidx/compose/ui/graphics/colorspace/ColorModel$Companion;-><init>()V
+HSPLandroidx/compose/ui/graphics/colorspace/ColorModel$Companion;-><init>(Lkotlin/jvm/internal/DefaultConstructorMarker;)V
+HSPLandroidx/compose/ui/graphics/colorspace/ColorModel$Companion;->getLab-xdoWZVw()J
+HSPLandroidx/compose/ui/graphics/colorspace/ColorModel$Companion;->getRgb-xdoWZVw()J
+HSPLandroidx/compose/ui/graphics/colorspace/ColorModel$Companion;->getXyz-xdoWZVw()J
+HSPLandroidx/compose/ui/graphics/colorspace/ColorModel;-><clinit>()V
+HSPLandroidx/compose/ui/graphics/colorspace/ColorModel;->access$getLab$cp()J
+HSPLandroidx/compose/ui/graphics/colorspace/ColorModel;->access$getRgb$cp()J
+HSPLandroidx/compose/ui/graphics/colorspace/ColorModel;->access$getXyz$cp()J
+HSPLandroidx/compose/ui/graphics/colorspace/ColorModel;->constructor-impl(J)J
+HSPLandroidx/compose/ui/graphics/colorspace/ColorModel;->getComponentCount-impl(J)I
+HSPLandroidx/compose/ui/graphics/colorspace/ColorSpace$Companion;-><init>()V
+HSPLandroidx/compose/ui/graphics/colorspace/ColorSpace$Companion;-><init>(Lkotlin/jvm/internal/DefaultConstructorMarker;)V
+HSPLandroidx/compose/ui/graphics/colorspace/ColorSpace;-><clinit>()V
+HSPLandroidx/compose/ui/graphics/colorspace/ColorSpace;-><init>(Ljava/lang/String;JI)V
+HSPLandroidx/compose/ui/graphics/colorspace/ColorSpace;-><init>(Ljava/lang/String;JILkotlin/jvm/internal/DefaultConstructorMarker;)V
+HSPLandroidx/compose/ui/graphics/colorspace/ColorSpace;->getComponentCount()I
+HSPLandroidx/compose/ui/graphics/colorspace/ColorSpace;->getId$ui_graphics_release()I
+HSPLandroidx/compose/ui/graphics/colorspace/ColorSpaceKt;->chromaticAdaptation([F[F[F)[F
+HSPLandroidx/compose/ui/graphics/colorspace/ColorSpaceKt;->compare(Landroidx/compose/ui/graphics/colorspace/WhitePoint;Landroidx/compose/ui/graphics/colorspace/WhitePoint;)Z
+HSPLandroidx/compose/ui/graphics/colorspace/ColorSpaceKt;->compare([F[F)Z
+HSPLandroidx/compose/ui/graphics/colorspace/ColorSpaceKt;->inverse3x3([F)[F
+HSPLandroidx/compose/ui/graphics/colorspace/ColorSpaceKt;->mul3x3([F[F)[F
+HSPLandroidx/compose/ui/graphics/colorspace/ColorSpaceKt;->mul3x3Diag([F[F)[F
+HSPLandroidx/compose/ui/graphics/colorspace/ColorSpaceKt;->mul3x3Float3([F[F)[F
+HSPLandroidx/compose/ui/graphics/colorspace/ColorSpaceKt;->rcpResponse(DDDDDD)D
+HSPLandroidx/compose/ui/graphics/colorspace/ColorSpaceKt;->response(DDDDDD)D
+HSPLandroidx/compose/ui/graphics/colorspace/ColorSpaces$ExtendedSrgb$1;-><clinit>()V
+HSPLandroidx/compose/ui/graphics/colorspace/ColorSpaces$ExtendedSrgb$1;-><init>()V
+HSPLandroidx/compose/ui/graphics/colorspace/ColorSpaces$ExtendedSrgb$2;-><clinit>()V
+HSPLandroidx/compose/ui/graphics/colorspace/ColorSpaces$ExtendedSrgb$2;-><init>()V
+HSPLandroidx/compose/ui/graphics/colorspace/ColorSpaces;-><clinit>()V
+HSPLandroidx/compose/ui/graphics/colorspace/ColorSpaces;-><init>()V
+HSPLandroidx/compose/ui/graphics/colorspace/ColorSpaces;->getColorSpacesArray$ui_graphics_release()[Landroidx/compose/ui/graphics/colorspace/ColorSpace;
+HSPLandroidx/compose/ui/graphics/colorspace/ColorSpaces;->getNtsc1953Primaries$ui_graphics_release()[F
+HSPLandroidx/compose/ui/graphics/colorspace/ColorSpaces;->getSrgb()Landroidx/compose/ui/graphics/colorspace/Rgb;
+HSPLandroidx/compose/ui/graphics/colorspace/ColorSpaces;->getSrgbPrimaries$ui_graphics_release()[F
+HSPLandroidx/compose/ui/graphics/colorspace/ColorSpaces;->getUnspecified$ui_graphics_release()Landroidx/compose/ui/graphics/colorspace/Rgb;
+HSPLandroidx/compose/ui/graphics/colorspace/Illuminant;-><clinit>()V
+HSPLandroidx/compose/ui/graphics/colorspace/Illuminant;-><init>()V
+HSPLandroidx/compose/ui/graphics/colorspace/Illuminant;->getC()Landroidx/compose/ui/graphics/colorspace/WhitePoint;
+HSPLandroidx/compose/ui/graphics/colorspace/Illuminant;->getD50()Landroidx/compose/ui/graphics/colorspace/WhitePoint;
+HSPLandroidx/compose/ui/graphics/colorspace/Illuminant;->getD60()Landroidx/compose/ui/graphics/colorspace/WhitePoint;
+HSPLandroidx/compose/ui/graphics/colorspace/Illuminant;->getD65()Landroidx/compose/ui/graphics/colorspace/WhitePoint;
+HSPLandroidx/compose/ui/graphics/colorspace/Lab$Companion;-><init>()V
+HSPLandroidx/compose/ui/graphics/colorspace/Lab$Companion;-><init>(Lkotlin/jvm/internal/DefaultConstructorMarker;)V
+HSPLandroidx/compose/ui/graphics/colorspace/Lab;-><clinit>()V
+HSPLandroidx/compose/ui/graphics/colorspace/Lab;-><init>(Ljava/lang/String;I)V
+HSPLandroidx/compose/ui/graphics/colorspace/Oklab$Companion;-><init>()V
+HSPLandroidx/compose/ui/graphics/colorspace/Oklab$Companion;-><init>(Lkotlin/jvm/internal/DefaultConstructorMarker;)V
+HSPLandroidx/compose/ui/graphics/colorspace/Oklab;-><clinit>()V
+HSPLandroidx/compose/ui/graphics/colorspace/Oklab;-><init>(Ljava/lang/String;I)V
+HSPLandroidx/compose/ui/graphics/colorspace/Rgb$1;-><init>(Landroidx/compose/ui/graphics/colorspace/TransferParameters;)V
+HSPLandroidx/compose/ui/graphics/colorspace/Rgb$1;->invoke(D)Ljava/lang/Double;
+HSPLandroidx/compose/ui/graphics/colorspace/Rgb$1;->invoke(Ljava/lang/Object;)Ljava/lang/Object;
+HSPLandroidx/compose/ui/graphics/colorspace/Rgb$3;-><init>(Landroidx/compose/ui/graphics/colorspace/TransferParameters;)V
+HSPLandroidx/compose/ui/graphics/colorspace/Rgb$3;->invoke(D)Ljava/lang/Double;
+HSPLandroidx/compose/ui/graphics/colorspace/Rgb$3;->invoke(Ljava/lang/Object;)Ljava/lang/Object;
+HSPLandroidx/compose/ui/graphics/colorspace/Rgb$5;-><init>(D)V
+HSPLandroidx/compose/ui/graphics/colorspace/Rgb$6;-><init>(D)V
+HSPLandroidx/compose/ui/graphics/colorspace/Rgb$Companion$DoubleIdentity$1;-><clinit>()V
+HSPLandroidx/compose/ui/graphics/colorspace/Rgb$Companion$DoubleIdentity$1;-><init>()V
+HSPLandroidx/compose/ui/graphics/colorspace/Rgb$Companion$DoubleIdentity$1;->invoke(D)Ljava/lang/Double;
+HSPLandroidx/compose/ui/graphics/colorspace/Rgb$Companion$DoubleIdentity$1;->invoke(Ljava/lang/Object;)Ljava/lang/Object;
+HSPLandroidx/compose/ui/graphics/colorspace/Rgb$Companion;-><init>()V
+HSPLandroidx/compose/ui/graphics/colorspace/Rgb$Companion;-><init>(Lkotlin/jvm/internal/DefaultConstructorMarker;)V
+HSPLandroidx/compose/ui/graphics/colorspace/Rgb$Companion;->access$computeXYZMatrix(Landroidx/compose/ui/graphics/colorspace/Rgb$Companion;[FLandroidx/compose/ui/graphics/colorspace/WhitePoint;)[F
+HSPLandroidx/compose/ui/graphics/colorspace/Rgb$Companion;->access$isSrgb(Landroidx/compose/ui/graphics/colorspace/Rgb$Companion;[FLandroidx/compose/ui/graphics/colorspace/WhitePoint;Lkotlin/jvm/functions/Function1;Lkotlin/jvm/functions/Function1;FFI)Z
+HSPLandroidx/compose/ui/graphics/colorspace/Rgb$Companion;->access$isWideGamut(Landroidx/compose/ui/graphics/colorspace/Rgb$Companion;[FFF)Z
+HSPLandroidx/compose/ui/graphics/colorspace/Rgb$Companion;->access$xyPrimaries(Landroidx/compose/ui/graphics/colorspace/Rgb$Companion;[F)[F
+HSPLandroidx/compose/ui/graphics/colorspace/Rgb$Companion;->area([F)F
+HSPLandroidx/compose/ui/graphics/colorspace/Rgb$Companion;->compare(DLkotlin/jvm/functions/Function1;Lkotlin/jvm/functions/Function1;)Z
+HSPLandroidx/compose/ui/graphics/colorspace/Rgb$Companion;->computeXYZMatrix([FLandroidx/compose/ui/graphics/colorspace/WhitePoint;)[F
+HSPLandroidx/compose/ui/graphics/colorspace/Rgb$Companion;->contains([F[F)Z
+HSPLandroidx/compose/ui/graphics/colorspace/Rgb$Companion;->cross(FFFF)F
+HSPLandroidx/compose/ui/graphics/colorspace/Rgb$Companion;->isSrgb([FLandroidx/compose/ui/graphics/colorspace/WhitePoint;Lkotlin/jvm/functions/Function1;Lkotlin/jvm/functions/Function1;FFI)Z
+HSPLandroidx/compose/ui/graphics/colorspace/Rgb$Companion;->isWideGamut([FFF)Z
+HSPLandroidx/compose/ui/graphics/colorspace/Rgb$Companion;->xyPrimaries([F)[F
+HSPLandroidx/compose/ui/graphics/colorspace/Rgb$eotf$1;-><init>(Landroidx/compose/ui/graphics/colorspace/Rgb;)V
+HSPLandroidx/compose/ui/graphics/colorspace/Rgb$oetf$1;-><init>(Landroidx/compose/ui/graphics/colorspace/Rgb;)V
+HSPLandroidx/compose/ui/graphics/colorspace/Rgb;-><clinit>()V
+HSPLandroidx/compose/ui/graphics/colorspace/Rgb;-><init>(Ljava/lang/String;[FLandroidx/compose/ui/graphics/colorspace/WhitePoint;DFFI)V
+HSPLandroidx/compose/ui/graphics/colorspace/Rgb;-><init>(Ljava/lang/String;[FLandroidx/compose/ui/graphics/colorspace/WhitePoint;Landroidx/compose/ui/graphics/colorspace/TransferParameters;I)V
+HSPLandroidx/compose/ui/graphics/colorspace/Rgb;-><init>(Ljava/lang/String;[FLandroidx/compose/ui/graphics/colorspace/WhitePoint;[FLkotlin/jvm/functions/Function1;Lkotlin/jvm/functions/Function1;FFLandroidx/compose/ui/graphics/colorspace/TransferParameters;I)V
+HSPLandroidx/compose/ui/graphics/colorspace/Rgb;->equals(Ljava/lang/Object;)Z
+HSPLandroidx/compose/ui/graphics/colorspace/Rgb;->getEotfOrig$ui_graphics_release()Lkotlin/jvm/functions/Function1;
+HSPLandroidx/compose/ui/graphics/colorspace/Rgb;->getMaxValue(I)F
+HSPLandroidx/compose/ui/graphics/colorspace/Rgb;->getMinValue(I)F
+HSPLandroidx/compose/ui/graphics/colorspace/Rgb;->getOetfOrig$ui_graphics_release()Lkotlin/jvm/functions/Function1;
+HSPLandroidx/compose/ui/graphics/colorspace/Rgb;->isSrgb()Z
+HSPLandroidx/compose/ui/graphics/colorspace/TransferParameters;-><init>(DDDDDDD)V
+HSPLandroidx/compose/ui/graphics/colorspace/TransferParameters;-><init>(DDDDDDDILkotlin/jvm/internal/DefaultConstructorMarker;)V
+HSPLandroidx/compose/ui/graphics/colorspace/TransferParameters;->getA()D
+HSPLandroidx/compose/ui/graphics/colorspace/TransferParameters;->getB()D
+HSPLandroidx/compose/ui/graphics/colorspace/TransferParameters;->getC()D
+HSPLandroidx/compose/ui/graphics/colorspace/TransferParameters;->getD()D
+HSPLandroidx/compose/ui/graphics/colorspace/TransferParameters;->getE()D
+HSPLandroidx/compose/ui/graphics/colorspace/TransferParameters;->getF()D
+HSPLandroidx/compose/ui/graphics/colorspace/TransferParameters;->getGamma()D
+HSPLandroidx/compose/ui/graphics/colorspace/WhitePoint;-><init>(FF)V
+HSPLandroidx/compose/ui/graphics/colorspace/WhitePoint;->getX()F
+HSPLandroidx/compose/ui/graphics/colorspace/WhitePoint;->getY()F
+HSPLandroidx/compose/ui/graphics/colorspace/WhitePoint;->toXyz$ui_graphics_release()[F
+HSPLandroidx/compose/ui/graphics/colorspace/Xyz;-><init>(Ljava/lang/String;I)V
+HSPLandroidx/compose/ui/graphics/drawscope/CanvasDrawScope$DrawParams;-><init>(Landroidx/compose/ui/unit/Density;Landroidx/compose/ui/unit/LayoutDirection;Landroidx/compose/ui/graphics/Canvas;J)V
+HSPLandroidx/compose/ui/graphics/drawscope/CanvasDrawScope$DrawParams;-><init>(Landroidx/compose/ui/unit/Density;Landroidx/compose/ui/unit/LayoutDirection;Landroidx/compose/ui/graphics/Canvas;JILkotlin/jvm/internal/DefaultConstructorMarker;)V
+HSPLandroidx/compose/ui/graphics/drawscope/CanvasDrawScope$DrawParams;-><init>(Landroidx/compose/ui/unit/Density;Landroidx/compose/ui/unit/LayoutDirection;Landroidx/compose/ui/graphics/Canvas;JLkotlin/jvm/internal/DefaultConstructorMarker;)V
+HSPLandroidx/compose/ui/graphics/drawscope/CanvasDrawScope$DrawParams;->component1()Landroidx/compose/ui/unit/Density;
+HSPLandroidx/compose/ui/graphics/drawscope/CanvasDrawScope$DrawParams;->component2()Landroidx/compose/ui/unit/LayoutDirection;
+HSPLandroidx/compose/ui/graphics/drawscope/CanvasDrawScope$DrawParams;->component3()Landroidx/compose/ui/graphics/Canvas;
+HSPLandroidx/compose/ui/graphics/drawscope/CanvasDrawScope$DrawParams;->component4-NH-jbRc()J
+HSPLandroidx/compose/ui/graphics/drawscope/CanvasDrawScope$DrawParams;->getCanvas()Landroidx/compose/ui/graphics/Canvas;
+HSPLandroidx/compose/ui/graphics/drawscope/CanvasDrawScope$DrawParams;->getDensity()Landroidx/compose/ui/unit/Density;
+HSPLandroidx/compose/ui/graphics/drawscope/CanvasDrawScope$DrawParams;->getLayoutDirection()Landroidx/compose/ui/unit/LayoutDirection;
+HSPLandroidx/compose/ui/graphics/drawscope/CanvasDrawScope$DrawParams;->getSize-NH-jbRc()J
+HSPLandroidx/compose/ui/graphics/drawscope/CanvasDrawScope$DrawParams;->setCanvas(Landroidx/compose/ui/graphics/Canvas;)V
+HSPLandroidx/compose/ui/graphics/drawscope/CanvasDrawScope$DrawParams;->setDensity(Landroidx/compose/ui/unit/Density;)V
+HSPLandroidx/compose/ui/graphics/drawscope/CanvasDrawScope$DrawParams;->setLayoutDirection(Landroidx/compose/ui/unit/LayoutDirection;)V
+HSPLandroidx/compose/ui/graphics/drawscope/CanvasDrawScope$DrawParams;->setSize-uvyYCjk(J)V
+HSPLandroidx/compose/ui/graphics/drawscope/CanvasDrawScope$drawContext$1;-><init>(Landroidx/compose/ui/graphics/drawscope/CanvasDrawScope;)V
+HSPLandroidx/compose/ui/graphics/drawscope/CanvasDrawScope$drawContext$1;->getCanvas()Landroidx/compose/ui/graphics/Canvas;
+HSPLandroidx/compose/ui/graphics/drawscope/CanvasDrawScope$drawContext$1;->getSize-NH-jbRc()J
+HSPLandroidx/compose/ui/graphics/drawscope/CanvasDrawScope$drawContext$1;->getTransform()Landroidx/compose/ui/graphics/drawscope/DrawTransform;
+HSPLandroidx/compose/ui/graphics/drawscope/CanvasDrawScope$drawContext$1;->setSize-uvyYCjk(J)V
+HSPLandroidx/compose/ui/graphics/drawscope/CanvasDrawScope;-><init>()V
+HSPLandroidx/compose/ui/graphics/drawscope/CanvasDrawScope;->configurePaint-2qPWKa0$default(Landroidx/compose/ui/graphics/drawscope/CanvasDrawScope;JLandroidx/compose/ui/graphics/drawscope/DrawStyle;FLandroidx/compose/ui/graphics/ColorFilter;IIILjava/lang/Object;)Landroidx/compose/ui/graphics/Paint;
+HSPLandroidx/compose/ui/graphics/drawscope/CanvasDrawScope;->configurePaint-2qPWKa0(JLandroidx/compose/ui/graphics/drawscope/DrawStyle;FLandroidx/compose/ui/graphics/ColorFilter;II)Landroidx/compose/ui/graphics/Paint;
+HSPLandroidx/compose/ui/graphics/drawscope/CanvasDrawScope;->configurePaint-swdJneE(Landroidx/compose/ui/graphics/Brush;Landroidx/compose/ui/graphics/drawscope/DrawStyle;FLandroidx/compose/ui/graphics/ColorFilter;II)Landroidx/compose/ui/graphics/Paint;
+HSPLandroidx/compose/ui/graphics/drawscope/CanvasDrawScope;->drawImage-AZ2fEMs(Landroidx/compose/ui/graphics/ImageBitmap;JJJJFLandroidx/compose/ui/graphics/drawscope/DrawStyle;Landroidx/compose/ui/graphics/ColorFilter;II)V
+HSPLandroidx/compose/ui/graphics/drawscope/CanvasDrawScope;->drawPath-LG529CI(Landroidx/compose/ui/graphics/Path;JFLandroidx/compose/ui/graphics/drawscope/DrawStyle;Landroidx/compose/ui/graphics/ColorFilter;I)V
+HSPLandroidx/compose/ui/graphics/drawscope/CanvasDrawScope;->drawRect-n-J9OG0(JJJFLandroidx/compose/ui/graphics/drawscope/DrawStyle;Landroidx/compose/ui/graphics/ColorFilter;I)V
+HSPLandroidx/compose/ui/graphics/drawscope/CanvasDrawScope;->drawRoundRect-u-Aw5IA(JJJJLandroidx/compose/ui/graphics/drawscope/DrawStyle;FLandroidx/compose/ui/graphics/ColorFilter;I)V
+HSPLandroidx/compose/ui/graphics/drawscope/CanvasDrawScope;->getDensity()F
+HSPLandroidx/compose/ui/graphics/drawscope/CanvasDrawScope;->getDrawContext()Landroidx/compose/ui/graphics/drawscope/DrawContext;
+HSPLandroidx/compose/ui/graphics/drawscope/CanvasDrawScope;->getDrawParams()Landroidx/compose/ui/graphics/drawscope/CanvasDrawScope$DrawParams;
+HSPLandroidx/compose/ui/graphics/drawscope/CanvasDrawScope;->getLayoutDirection()Landroidx/compose/ui/unit/LayoutDirection;
+HSPLandroidx/compose/ui/graphics/drawscope/CanvasDrawScope;->modulate-5vOe2sY(JF)J
+HSPLandroidx/compose/ui/graphics/drawscope/CanvasDrawScope;->obtainFillPaint()Landroidx/compose/ui/graphics/Paint;
+HSPLandroidx/compose/ui/graphics/drawscope/CanvasDrawScope;->selectPaint(Landroidx/compose/ui/graphics/drawscope/DrawStyle;)Landroidx/compose/ui/graphics/Paint;
+HSPLandroidx/compose/ui/graphics/drawscope/CanvasDrawScopeKt$asDrawTransform$1;-><init>(Landroidx/compose/ui/graphics/drawscope/DrawContext;)V
+HSPLandroidx/compose/ui/graphics/drawscope/CanvasDrawScopeKt$asDrawTransform$1;->getSize-NH-jbRc()J
+HSPLandroidx/compose/ui/graphics/drawscope/CanvasDrawScopeKt$asDrawTransform$1;->inset(FFFF)V
+HSPLandroidx/compose/ui/graphics/drawscope/CanvasDrawScopeKt$asDrawTransform$1;->translate(FF)V
+HSPLandroidx/compose/ui/graphics/drawscope/CanvasDrawScopeKt;-><clinit>()V
+HSPLandroidx/compose/ui/graphics/drawscope/CanvasDrawScopeKt;->access$asDrawTransform(Landroidx/compose/ui/graphics/drawscope/DrawContext;)Landroidx/compose/ui/graphics/drawscope/DrawTransform;
+HSPLandroidx/compose/ui/graphics/drawscope/CanvasDrawScopeKt;->access$getDefaultDensity$p()Landroidx/compose/ui/unit/Density;
+HSPLandroidx/compose/ui/graphics/drawscope/CanvasDrawScopeKt;->asDrawTransform(Landroidx/compose/ui/graphics/drawscope/DrawContext;)Landroidx/compose/ui/graphics/drawscope/DrawTransform;
+HSPLandroidx/compose/ui/graphics/drawscope/DrawScope$Companion;-><clinit>()V
+HSPLandroidx/compose/ui/graphics/drawscope/DrawScope$Companion;-><init>()V
+HSPLandroidx/compose/ui/graphics/drawscope/DrawScope$Companion;->getDefaultBlendMode-0nO6VwU()I
+HSPLandroidx/compose/ui/graphics/drawscope/DrawScope$Companion;->getDefaultFilterQuality-f-v9h1I()I
+HSPLandroidx/compose/ui/graphics/drawscope/DrawScope;-><clinit>()V
+HSPLandroidx/compose/ui/graphics/drawscope/DrawScope;->drawImage-AZ2fEMs$default(Landroidx/compose/ui/graphics/drawscope/DrawScope;Landroidx/compose/ui/graphics/ImageBitmap;JJJJFLandroidx/compose/ui/graphics/drawscope/DrawStyle;Landroidx/compose/ui/graphics/ColorFilter;IIILjava/lang/Object;)V
+HSPLandroidx/compose/ui/graphics/drawscope/DrawScope;->drawRect-n-J9OG0$default(Landroidx/compose/ui/graphics/drawscope/DrawScope;JJJFLandroidx/compose/ui/graphics/drawscope/DrawStyle;Landroidx/compose/ui/graphics/ColorFilter;IILjava/lang/Object;)V
+HSPLandroidx/compose/ui/graphics/drawscope/DrawScope;->getSize-NH-jbRc()J
+HSPLandroidx/compose/ui/graphics/drawscope/DrawScope;->offsetSize-PENXr5M(JJ)J
+HSPLandroidx/compose/ui/graphics/drawscope/DrawStyle;-><init>()V
+HSPLandroidx/compose/ui/graphics/drawscope/DrawStyle;-><init>(Lkotlin/jvm/internal/DefaultConstructorMarker;)V
+HSPLandroidx/compose/ui/graphics/drawscope/EmptyCanvas;-><init>()V
+HSPLandroidx/compose/ui/graphics/drawscope/Fill;-><clinit>()V
+HSPLandroidx/compose/ui/graphics/drawscope/Fill;-><init>()V
+HSPLandroidx/compose/ui/graphics/painter/BitmapPainter;-><init>(Landroidx/compose/ui/graphics/ImageBitmap;JJ)V
+HSPLandroidx/compose/ui/graphics/painter/BitmapPainter;-><init>(Landroidx/compose/ui/graphics/ImageBitmap;JJILkotlin/jvm/internal/DefaultConstructorMarker;)V
+HSPLandroidx/compose/ui/graphics/painter/BitmapPainter;-><init>(Landroidx/compose/ui/graphics/ImageBitmap;JJLkotlin/jvm/internal/DefaultConstructorMarker;)V
+HSPLandroidx/compose/ui/graphics/painter/BitmapPainter;->applyColorFilter(Landroidx/compose/ui/graphics/ColorFilter;)Z
+HSPLandroidx/compose/ui/graphics/painter/BitmapPainter;->equals(Ljava/lang/Object;)Z
+HSPLandroidx/compose/ui/graphics/painter/BitmapPainter;->getIntrinsicSize-NH-jbRc()J
+HSPLandroidx/compose/ui/graphics/painter/BitmapPainter;->onDraw(Landroidx/compose/ui/graphics/drawscope/DrawScope;)V
+HSPLandroidx/compose/ui/graphics/painter/BitmapPainter;->validateSize-N5eqBDc(JJ)J
+HSPLandroidx/compose/ui/graphics/painter/Painter$drawLambda$1;-><init>(Landroidx/compose/ui/graphics/painter/Painter;)V
+HSPLandroidx/compose/ui/graphics/painter/Painter;-><init>()V
+HSPLandroidx/compose/ui/graphics/painter/Painter;->configureAlpha(F)V
+HSPLandroidx/compose/ui/graphics/painter/Painter;->configureColorFilter(Landroidx/compose/ui/graphics/ColorFilter;)V
+HSPLandroidx/compose/ui/graphics/painter/Painter;->configureLayoutDirection(Landroidx/compose/ui/unit/LayoutDirection;)V
+HSPLandroidx/compose/ui/graphics/painter/Painter;->draw-x_KDEd0(Landroidx/compose/ui/graphics/drawscope/DrawScope;JFLandroidx/compose/ui/graphics/ColorFilter;)V
+HSPLandroidx/compose/ui/hapticfeedback/PlatformHapticFeedback;-><init>(Landroid/view/View;)V
+HSPLandroidx/compose/ui/input/InputMode$Companion;-><init>()V
+HSPLandroidx/compose/ui/input/InputMode$Companion;-><init>(Lkotlin/jvm/internal/DefaultConstructorMarker;)V
+HSPLandroidx/compose/ui/input/InputMode$Companion;->getTouch-aOaMEAU()I
+HSPLandroidx/compose/ui/input/InputMode;-><clinit>()V
+HSPLandroidx/compose/ui/input/InputMode;-><init>(I)V
+HSPLandroidx/compose/ui/input/InputMode;->access$getTouch$cp()I
+HSPLandroidx/compose/ui/input/InputMode;->box-impl(I)Landroidx/compose/ui/input/InputMode;
+HSPLandroidx/compose/ui/input/InputMode;->constructor-impl(I)I
+HSPLandroidx/compose/ui/input/InputMode;->equals(Ljava/lang/Object;)Z
+HSPLandroidx/compose/ui/input/InputMode;->equals-impl(ILjava/lang/Object;)Z
+HSPLandroidx/compose/ui/input/InputMode;->equals-impl0(II)Z
+HSPLandroidx/compose/ui/input/InputMode;->unbox-impl()I
+HSPLandroidx/compose/ui/input/InputModeManagerImpl;-><init>(ILkotlin/jvm/functions/Function1;)V
+HSPLandroidx/compose/ui/input/InputModeManagerImpl;-><init>(ILkotlin/jvm/functions/Function1;Lkotlin/jvm/internal/DefaultConstructorMarker;)V
+HSPLandroidx/compose/ui/input/InputModeManagerImpl;->getInputMode-aOaMEAU()I
+HSPLandroidx/compose/ui/input/InputModeManagerImpl;->setInputMode-iuPiT84(I)V
+HSPLandroidx/compose/ui/input/ScrollContainerInfoKt$ModifierLocalScrollContainerInfo$1;-><clinit>()V
+HSPLandroidx/compose/ui/input/ScrollContainerInfoKt$ModifierLocalScrollContainerInfo$1;-><init>()V
+HSPLandroidx/compose/ui/input/ScrollContainerInfoKt$ModifierLocalScrollContainerInfo$1;->invoke()Landroidx/compose/ui/input/ScrollContainerInfo;
+HSPLandroidx/compose/ui/input/ScrollContainerInfoKt$ModifierLocalScrollContainerInfo$1;->invoke()Ljava/lang/Object;
+HSPLandroidx/compose/ui/input/ScrollContainerInfoKt$consumeScrollContainerInfo$1;-><init>(Lkotlin/jvm/functions/Function1;)V
+HSPLandroidx/compose/ui/input/ScrollContainerInfoKt$consumeScrollContainerInfo$1;->invoke(Landroidx/compose/ui/modifier/ModifierLocalReadScope;)V
+HSPLandroidx/compose/ui/input/ScrollContainerInfoKt$consumeScrollContainerInfo$1;->invoke(Ljava/lang/Object;)Ljava/lang/Object;
+HSPLandroidx/compose/ui/input/ScrollContainerInfoKt;-><clinit>()V
+HSPLandroidx/compose/ui/input/ScrollContainerInfoKt;->consumeScrollContainerInfo(Landroidx/compose/ui/Modifier;Lkotlin/jvm/functions/Function1;)Landroidx/compose/ui/Modifier;
+HSPLandroidx/compose/ui/input/ScrollContainerInfoKt;->getModifierLocalScrollContainerInfo()Landroidx/compose/ui/modifier/ProvidableModifierLocal;
+HSPLandroidx/compose/ui/input/focus/FocusAwareInputModifier;-><init>(Lkotlin/jvm/functions/Function1;Lkotlin/jvm/functions/Function1;Landroidx/compose/ui/modifier/ProvidableModifierLocal;)V
+HSPLandroidx/compose/ui/input/focus/FocusAwareInputModifier;->getKey()Landroidx/compose/ui/modifier/ProvidableModifierLocal;
+HSPLandroidx/compose/ui/input/focus/FocusAwareInputModifier;->getValue()Landroidx/compose/ui/input/focus/FocusAwareInputModifier;
+HSPLandroidx/compose/ui/input/focus/FocusAwareInputModifier;->getValue()Ljava/lang/Object;
+HSPLandroidx/compose/ui/input/focus/FocusAwareInputModifier;->onModifierLocalsUpdated(Landroidx/compose/ui/modifier/ModifierLocalReadScope;)V
+HSPLandroidx/compose/ui/input/key/KeyInputModifier;-><init>(Lkotlin/jvm/functions/Function1;Lkotlin/jvm/functions/Function1;)V
+HSPLandroidx/compose/ui/input/key/KeyInputModifier;->getKey()Landroidx/compose/ui/modifier/ProvidableModifierLocal;
+HSPLandroidx/compose/ui/input/key/KeyInputModifier;->getValue()Landroidx/compose/ui/input/key/KeyInputModifier;
+HSPLandroidx/compose/ui/input/key/KeyInputModifier;->getValue()Ljava/lang/Object;
+HSPLandroidx/compose/ui/input/key/KeyInputModifier;->onModifierLocalsUpdated(Landroidx/compose/ui/modifier/ModifierLocalReadScope;)V
+HSPLandroidx/compose/ui/input/key/KeyInputModifier;->onPlaced(Landroidx/compose/ui/layout/LayoutCoordinates;)V
+HSPLandroidx/compose/ui/input/key/KeyInputModifierKt$ModifierLocalKeyInput$1;-><clinit>()V
+HSPLandroidx/compose/ui/input/key/KeyInputModifierKt$ModifierLocalKeyInput$1;-><init>()V
+HSPLandroidx/compose/ui/input/key/KeyInputModifierKt$ModifierLocalKeyInput$1;->invoke()Landroidx/compose/ui/input/key/KeyInputModifier;
+HSPLandroidx/compose/ui/input/key/KeyInputModifierKt$ModifierLocalKeyInput$1;->invoke()Ljava/lang/Object;
+HSPLandroidx/compose/ui/input/key/KeyInputModifierKt;-><clinit>()V
+HSPLandroidx/compose/ui/input/key/KeyInputModifierKt;->getModifierLocalKeyInput()Landroidx/compose/ui/modifier/ProvidableModifierLocal;
+HSPLandroidx/compose/ui/input/key/KeyInputModifierKt;->onKeyEvent(Landroidx/compose/ui/Modifier;Lkotlin/jvm/functions/Function1;)Landroidx/compose/ui/Modifier;
+HSPLandroidx/compose/ui/input/nestedscroll/NestedScrollDispatcher$calculateNestedScrollScope$1;-><init>(Landroidx/compose/ui/input/nestedscroll/NestedScrollDispatcher;)V
+HSPLandroidx/compose/ui/input/nestedscroll/NestedScrollDispatcher;-><clinit>()V
+HSPLandroidx/compose/ui/input/nestedscroll/NestedScrollDispatcher;-><init>()V
+HSPLandroidx/compose/ui/input/nestedscroll/NestedScrollDispatcher;->setCalculateNestedScrollScope$ui_release(Lkotlin/jvm/functions/Function0;)V
+HSPLandroidx/compose/ui/input/nestedscroll/NestedScrollDispatcher;->setOriginNestedScrollScope$ui_release(Lkotlinx/coroutines/CoroutineScope;)V
+HSPLandroidx/compose/ui/input/nestedscroll/NestedScrollDispatcher;->setParent$ui_release(Landroidx/compose/ui/input/nestedscroll/NestedScrollConnection;)V
+HSPLandroidx/compose/ui/input/nestedscroll/NestedScrollModifierKt$nestedScroll$2;-><init>(Landroidx/compose/ui/input/nestedscroll/NestedScrollDispatcher;Landroidx/compose/ui/input/nestedscroll/NestedScrollConnection;)V
+HSPLandroidx/compose/ui/input/nestedscroll/NestedScrollModifierKt$nestedScroll$2;->invoke(Landroidx/compose/ui/Modifier;Landroidx/compose/runtime/Composer;I)Landroidx/compose/ui/Modifier;
+HSPLandroidx/compose/ui/input/nestedscroll/NestedScrollModifierKt$nestedScroll$2;->invoke(Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;
+HSPLandroidx/compose/ui/input/nestedscroll/NestedScrollModifierKt;->nestedScroll$default(Landroidx/compose/ui/Modifier;Landroidx/compose/ui/input/nestedscroll/NestedScrollConnection;Landroidx/compose/ui/input/nestedscroll/NestedScrollDispatcher;ILjava/lang/Object;)Landroidx/compose/ui/Modifier;
+HSPLandroidx/compose/ui/input/nestedscroll/NestedScrollModifierKt;->nestedScroll(Landroidx/compose/ui/Modifier;Landroidx/compose/ui/input/nestedscroll/NestedScrollConnection;Landroidx/compose/ui/input/nestedscroll/NestedScrollDispatcher;)Landroidx/compose/ui/Modifier;
+HSPLandroidx/compose/ui/input/nestedscroll/NestedScrollModifierLocal$1;-><init>(Landroidx/compose/ui/input/nestedscroll/NestedScrollModifierLocal;)V
+HSPLandroidx/compose/ui/input/nestedscroll/NestedScrollModifierLocal;-><init>(Landroidx/compose/ui/input/nestedscroll/NestedScrollDispatcher;Landroidx/compose/ui/input/nestedscroll/NestedScrollConnection;)V
+HSPLandroidx/compose/ui/input/nestedscroll/NestedScrollModifierLocal;->getKey()Landroidx/compose/ui/modifier/ProvidableModifierLocal;
+HSPLandroidx/compose/ui/input/nestedscroll/NestedScrollModifierLocal;->getParent()Landroidx/compose/ui/input/nestedscroll/NestedScrollModifierLocal;
+HSPLandroidx/compose/ui/input/nestedscroll/NestedScrollModifierLocal;->onModifierLocalsUpdated(Landroidx/compose/ui/modifier/ModifierLocalReadScope;)V
+HSPLandroidx/compose/ui/input/nestedscroll/NestedScrollModifierLocal;->setParent(Landroidx/compose/ui/input/nestedscroll/NestedScrollModifierLocal;)V
+HSPLandroidx/compose/ui/input/nestedscroll/NestedScrollModifierLocalKt$ModifierLocalNestedScroll$1;-><clinit>()V
+HSPLandroidx/compose/ui/input/nestedscroll/NestedScrollModifierLocalKt$ModifierLocalNestedScroll$1;-><init>()V
+HSPLandroidx/compose/ui/input/nestedscroll/NestedScrollModifierLocalKt$ModifierLocalNestedScroll$1;->invoke()Landroidx/compose/ui/input/nestedscroll/NestedScrollModifierLocal;
+HSPLandroidx/compose/ui/input/nestedscroll/NestedScrollModifierLocalKt$ModifierLocalNestedScroll$1;->invoke()Ljava/lang/Object;
+HSPLandroidx/compose/ui/input/nestedscroll/NestedScrollModifierLocalKt;-><clinit>()V
+HSPLandroidx/compose/ui/input/nestedscroll/NestedScrollModifierLocalKt;->getModifierLocalNestedScroll()Landroidx/compose/ui/modifier/ProvidableModifierLocal;
+HSPLandroidx/compose/ui/input/pointer/AwaitPointerEventScope;->awaitPointerEvent$default(Landroidx/compose/ui/input/pointer/AwaitPointerEventScope;Landroidx/compose/ui/input/pointer/PointerEventPass;Lkotlin/coroutines/Continuation;ILjava/lang/Object;)Ljava/lang/Object;
+HSPLandroidx/compose/ui/input/pointer/HitPathTracker;-><init>(Landroidx/compose/ui/layout/LayoutCoordinates;)V
+HSPLandroidx/compose/ui/input/pointer/MotionEventAdapter;-><init>()V
+HSPLandroidx/compose/ui/input/pointer/NodeParent;-><init>()V
+HSPLandroidx/compose/ui/input/pointer/PointerButtons;->constructor-impl(I)I
+HSPLandroidx/compose/ui/input/pointer/PointerEvent;-><clinit>()V
+HSPLandroidx/compose/ui/input/pointer/PointerEvent;-><init>(Ljava/util/List;)V
+HSPLandroidx/compose/ui/input/pointer/PointerEvent;-><init>(Ljava/util/List;Landroidx/compose/ui/input/pointer/InternalPointerEvent;)V
+HSPLandroidx/compose/ui/input/pointer/PointerEvent;->calculatePointerEventType-7fucELk()I
+HSPLandroidx/compose/ui/input/pointer/PointerEvent;->getMotionEvent$ui_release()Landroid/view/MotionEvent;
+HSPLandroidx/compose/ui/input/pointer/PointerEventPass;->$values()[Landroidx/compose/ui/input/pointer/PointerEventPass;
+HSPLandroidx/compose/ui/input/pointer/PointerEventPass;-><clinit>()V
+HSPLandroidx/compose/ui/input/pointer/PointerEventPass;-><init>(Ljava/lang/String;I)V
+HSPLandroidx/compose/ui/input/pointer/PointerEventType$Companion;-><init>()V
+HSPLandroidx/compose/ui/input/pointer/PointerEventType$Companion;-><init>(Lkotlin/jvm/internal/DefaultConstructorMarker;)V
+HSPLandroidx/compose/ui/input/pointer/PointerEventType$Companion;->getMove-7fucELk()I
+HSPLandroidx/compose/ui/input/pointer/PointerEventType;-><clinit>()V
+HSPLandroidx/compose/ui/input/pointer/PointerEventType;->access$getMove$cp()I
+HSPLandroidx/compose/ui/input/pointer/PointerEventType;->constructor-impl(I)I
+HSPLandroidx/compose/ui/input/pointer/PointerEvent_androidKt;->EmptyPointerKeyboardModifiers()I
+HSPLandroidx/compose/ui/input/pointer/PointerInputChangeEventProducer;-><init>()V
+HSPLandroidx/compose/ui/input/pointer/PointerInputEventProcessor;-><init>(Landroidx/compose/ui/node/LayoutNode;)V
+HSPLandroidx/compose/ui/input/pointer/PointerInputFilter;-><clinit>()V
+HSPLandroidx/compose/ui/input/pointer/PointerInputFilter;-><init>()V
+HSPLandroidx/compose/ui/input/pointer/PointerInputFilter;->getSize-YbymL2g()J
+HSPLandroidx/compose/ui/input/pointer/PointerInputFilter;->setLayoutCoordinates$ui_release(Landroidx/compose/ui/layout/LayoutCoordinates;)V
+HSPLandroidx/compose/ui/input/pointer/PointerKeyboardModifiers;-><init>(I)V
+HSPLandroidx/compose/ui/input/pointer/PointerKeyboardModifiers;->box-impl(I)Landroidx/compose/ui/input/pointer/PointerKeyboardModifiers;
+HSPLandroidx/compose/ui/input/pointer/PointerKeyboardModifiers;->constructor-impl(I)I
+HSPLandroidx/compose/ui/input/pointer/SuspendingPointerInputFilter$PointerEventHandlerCoroutine;-><init>(Landroidx/compose/ui/input/pointer/SuspendingPointerInputFilter;Lkotlin/coroutines/Continuation;)V
+HSPLandroidx/compose/ui/input/pointer/SuspendingPointerInputFilter$PointerEventHandlerCoroutine;->access$setAwaitPass$p(Landroidx/compose/ui/input/pointer/SuspendingPointerInputFilter$PointerEventHandlerCoroutine;Landroidx/compose/ui/input/pointer/PointerEventPass;)V
+HSPLandroidx/compose/ui/input/pointer/SuspendingPointerInputFilter$PointerEventHandlerCoroutine;->access$setPointerAwaiter$p(Landroidx/compose/ui/input/pointer/SuspendingPointerInputFilter$PointerEventHandlerCoroutine;Lkotlinx/coroutines/CancellableContinuation;)V
+HSPLandroidx/compose/ui/input/pointer/SuspendingPointerInputFilter$PointerEventHandlerCoroutine;->awaitPointerEvent(Landroidx/compose/ui/input/pointer/PointerEventPass;Lkotlin/coroutines/Continuation;)Ljava/lang/Object;
+HSPLandroidx/compose/ui/input/pointer/SuspendingPointerInputFilter$PointerEventHandlerCoroutine;->cancel(Ljava/lang/Throwable;)V
+HSPLandroidx/compose/ui/input/pointer/SuspendingPointerInputFilter$PointerEventHandlerCoroutine;->getContext()Lkotlin/coroutines/CoroutineContext;
+HSPLandroidx/compose/ui/input/pointer/SuspendingPointerInputFilter$PointerEventHandlerCoroutine;->resumeWith(Ljava/lang/Object;)V
+HSPLandroidx/compose/ui/input/pointer/SuspendingPointerInputFilter$awaitPointerEventScope$2$2;-><init>(Landroidx/compose/ui/input/pointer/SuspendingPointerInputFilter$PointerEventHandlerCoroutine;)V
+HSPLandroidx/compose/ui/input/pointer/SuspendingPointerInputFilter$awaitPointerEventScope$2$2;->invoke(Ljava/lang/Object;)Ljava/lang/Object;
+HSPLandroidx/compose/ui/input/pointer/SuspendingPointerInputFilter$awaitPointerEventScope$2$2;->invoke(Ljava/lang/Throwable;)V
+HSPLandroidx/compose/ui/input/pointer/SuspendingPointerInputFilter;-><init>(Landroidx/compose/ui/platform/ViewConfiguration;Landroidx/compose/ui/unit/Density;)V
+HSPLandroidx/compose/ui/input/pointer/SuspendingPointerInputFilter;->access$getPointerHandlers$p(Landroidx/compose/ui/input/pointer/SuspendingPointerInputFilter;)Landroidx/compose/runtime/collection/MutableVector;
+HSPLandroidx/compose/ui/input/pointer/SuspendingPointerInputFilter;->awaitPointerEventScope(Lkotlin/jvm/functions/Function2;Lkotlin/coroutines/Continuation;)Ljava/lang/Object;
+HSPLandroidx/compose/ui/input/pointer/SuspendingPointerInputFilter;->getPointerInputFilter()Landroidx/compose/ui/input/pointer/PointerInputFilter;
+HSPLandroidx/compose/ui/input/pointer/SuspendingPointerInputFilter;->setCoroutineScope(Lkotlinx/coroutines/CoroutineScope;)V
+HSPLandroidx/compose/ui/input/pointer/SuspendingPointerInputFilterKt$pointerInput$2$2$1;-><init>(Landroidx/compose/ui/input/pointer/SuspendingPointerInputFilter;Lkotlin/jvm/functions/Function2;Lkotlin/coroutines/Continuation;)V
+HSPLandroidx/compose/ui/input/pointer/SuspendingPointerInputFilterKt$pointerInput$2$2$1;->create(Ljava/lang/Object;Lkotlin/coroutines/Continuation;)Lkotlin/coroutines/Continuation;
+HSPLandroidx/compose/ui/input/pointer/SuspendingPointerInputFilterKt$pointerInput$2$2$1;->invokeSuspend(Ljava/lang/Object;)Ljava/lang/Object;
+HSPLandroidx/compose/ui/input/pointer/SuspendingPointerInputFilterKt$pointerInput$2;-><init>(Ljava/lang/Object;Lkotlin/jvm/functions/Function2;)V
+HSPLandroidx/compose/ui/input/pointer/SuspendingPointerInputFilterKt$pointerInput$2;->invoke(Landroidx/compose/ui/Modifier;Landroidx/compose/runtime/Composer;I)Landroidx/compose/ui/Modifier;
+HSPLandroidx/compose/ui/input/pointer/SuspendingPointerInputFilterKt$pointerInput$2;->invoke(Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;
+HSPLandroidx/compose/ui/input/pointer/SuspendingPointerInputFilterKt$pointerInput$4$2$1;-><init>(Landroidx/compose/ui/input/pointer/SuspendingPointerInputFilter;Lkotlin/jvm/functions/Function2;Lkotlin/coroutines/Continuation;)V
+HSPLandroidx/compose/ui/input/pointer/SuspendingPointerInputFilterKt$pointerInput$4$2$1;->create(Ljava/lang/Object;Lkotlin/coroutines/Continuation;)Lkotlin/coroutines/Continuation;
+HSPLandroidx/compose/ui/input/pointer/SuspendingPointerInputFilterKt$pointerInput$4$2$1;->invokeSuspend(Ljava/lang/Object;)Ljava/lang/Object;
+HSPLandroidx/compose/ui/input/pointer/SuspendingPointerInputFilterKt$pointerInput$4;-><init>(Ljava/lang/Object;Ljava/lang/Object;Lkotlin/jvm/functions/Function2;)V
+HSPLandroidx/compose/ui/input/pointer/SuspendingPointerInputFilterKt$pointerInput$4;->invoke(Landroidx/compose/ui/Modifier;Landroidx/compose/runtime/Composer;I)Landroidx/compose/ui/Modifier;
+HSPLandroidx/compose/ui/input/pointer/SuspendingPointerInputFilterKt$pointerInput$4;->invoke(Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;
+HSPLandroidx/compose/ui/input/pointer/SuspendingPointerInputFilterKt$pointerInput$6$2$1;-><init>(Landroidx/compose/ui/input/pointer/SuspendingPointerInputFilter;Lkotlin/jvm/functions/Function2;Lkotlin/coroutines/Continuation;)V
+HSPLandroidx/compose/ui/input/pointer/SuspendingPointerInputFilterKt$pointerInput$6$2$1;->create(Ljava/lang/Object;Lkotlin/coroutines/Continuation;)Lkotlin/coroutines/Continuation;
+HSPLandroidx/compose/ui/input/pointer/SuspendingPointerInputFilterKt$pointerInput$6$2$1;->invokeSuspend(Ljava/lang/Object;)Ljava/lang/Object;
+HSPLandroidx/compose/ui/input/pointer/SuspendingPointerInputFilterKt$pointerInput$6;-><init>([Ljava/lang/Object;Lkotlin/jvm/functions/Function2;)V
+HSPLandroidx/compose/ui/input/pointer/SuspendingPointerInputFilterKt$pointerInput$6;->invoke(Landroidx/compose/ui/Modifier;Landroidx/compose/runtime/Composer;I)Landroidx/compose/ui/Modifier;
+HSPLandroidx/compose/ui/input/pointer/SuspendingPointerInputFilterKt$pointerInput$6;->invoke(Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;
+HSPLandroidx/compose/ui/input/pointer/SuspendingPointerInputFilterKt;-><clinit>()V
+HSPLandroidx/compose/ui/input/pointer/SuspendingPointerInputFilterKt;->access$getEmptyPointerEvent$p()Landroidx/compose/ui/input/pointer/PointerEvent;
+HSPLandroidx/compose/ui/input/pointer/SuspendingPointerInputFilterKt;->pointerInput(Landroidx/compose/ui/Modifier;Ljava/lang/Object;Ljava/lang/Object;Lkotlin/jvm/functions/Function2;)Landroidx/compose/ui/Modifier;
+HSPLandroidx/compose/ui/input/pointer/SuspendingPointerInputFilterKt;->pointerInput(Landroidx/compose/ui/Modifier;Ljava/lang/Object;Lkotlin/jvm/functions/Function2;)Landroidx/compose/ui/Modifier;
+HSPLandroidx/compose/ui/input/pointer/SuspendingPointerInputFilterKt;->pointerInput(Landroidx/compose/ui/Modifier;[Ljava/lang/Object;Lkotlin/jvm/functions/Function2;)Landroidx/compose/ui/Modifier;
+HSPLandroidx/compose/ui/input/pointer/util/VelocityTracker;-><clinit>()V
+HSPLandroidx/compose/ui/input/pointer/util/VelocityTracker;-><init>()V
+HSPLandroidx/compose/ui/input/rotary/RotaryInputModifierKt$ModifierLocalRotaryScrollParent$1;-><clinit>()V
+HSPLandroidx/compose/ui/input/rotary/RotaryInputModifierKt$ModifierLocalRotaryScrollParent$1;-><init>()V
+HSPLandroidx/compose/ui/input/rotary/RotaryInputModifierKt$ModifierLocalRotaryScrollParent$1;->invoke()Landroidx/compose/ui/input/focus/FocusAwareInputModifier;
+HSPLandroidx/compose/ui/input/rotary/RotaryInputModifierKt$ModifierLocalRotaryScrollParent$1;->invoke()Ljava/lang/Object;
+HSPLandroidx/compose/ui/input/rotary/RotaryInputModifierKt$focusAwareCallback$1;-><init>(Lkotlin/jvm/functions/Function1;)V
+HSPLandroidx/compose/ui/input/rotary/RotaryInputModifierKt;-><clinit>()V
+HSPLandroidx/compose/ui/input/rotary/RotaryInputModifierKt;->focusAwareCallback(Lkotlin/jvm/functions/Function1;)Lkotlin/jvm/functions/Function1;
+HSPLandroidx/compose/ui/input/rotary/RotaryInputModifierKt;->getModifierLocalRotaryScrollParent()Landroidx/compose/ui/modifier/ProvidableModifierLocal;
+HSPLandroidx/compose/ui/input/rotary/RotaryInputModifierKt;->onRotaryScrollEvent(Landroidx/compose/ui/Modifier;Lkotlin/jvm/functions/Function1;)Landroidx/compose/ui/Modifier;
+HSPLandroidx/compose/ui/layout/AlignmentLine$Companion;-><init>()V
+HSPLandroidx/compose/ui/layout/AlignmentLine$Companion;-><init>(Lkotlin/jvm/internal/DefaultConstructorMarker;)V
+HSPLandroidx/compose/ui/layout/AlignmentLine;-><clinit>()V
+HSPLandroidx/compose/ui/layout/AlignmentLine;-><init>(Lkotlin/jvm/functions/Function2;)V
+HSPLandroidx/compose/ui/layout/AlignmentLine;-><init>(Lkotlin/jvm/functions/Function2;Lkotlin/jvm/internal/DefaultConstructorMarker;)V
+HSPLandroidx/compose/ui/layout/AlignmentLineKt$FirstBaseline$1;-><clinit>()V
+HSPLandroidx/compose/ui/layout/AlignmentLineKt$FirstBaseline$1;-><init>()V
+HSPLandroidx/compose/ui/layout/AlignmentLineKt$LastBaseline$1;-><clinit>()V
+HSPLandroidx/compose/ui/layout/AlignmentLineKt$LastBaseline$1;-><init>()V
+HSPLandroidx/compose/ui/layout/AlignmentLineKt;-><clinit>()V
+HSPLandroidx/compose/ui/layout/AlignmentLineKt;->getFirstBaseline()Landroidx/compose/ui/layout/HorizontalAlignmentLine;
+HSPLandroidx/compose/ui/layout/AlignmentLineKt;->getLastBaseline()Landroidx/compose/ui/layout/HorizontalAlignmentLine;
+HSPLandroidx/compose/ui/layout/BeyondBoundsLayoutKt$ModifierLocalBeyondBoundsLayout$1;-><clinit>()V
+HSPLandroidx/compose/ui/layout/BeyondBoundsLayoutKt$ModifierLocalBeyondBoundsLayout$1;-><init>()V
+HSPLandroidx/compose/ui/layout/BeyondBoundsLayoutKt$ModifierLocalBeyondBoundsLayout$1;->invoke()Landroidx/compose/ui/layout/BeyondBoundsLayout;
+HSPLandroidx/compose/ui/layout/BeyondBoundsLayoutKt$ModifierLocalBeyondBoundsLayout$1;->invoke()Ljava/lang/Object;
+HSPLandroidx/compose/ui/layout/BeyondBoundsLayoutKt;-><clinit>()V
+HSPLandroidx/compose/ui/layout/BeyondBoundsLayoutKt;->getModifierLocalBeyondBoundsLayout()Landroidx/compose/ui/modifier/ProvidableModifierLocal;
+HSPLandroidx/compose/ui/layout/ComposableSingletons$SubcomposeLayoutKt$lambda-1$1;-><clinit>()V
+HSPLandroidx/compose/ui/layout/ComposableSingletons$SubcomposeLayoutKt$lambda-1$1;-><init>()V
+HSPLandroidx/compose/ui/layout/ComposableSingletons$SubcomposeLayoutKt;-><clinit>()V
+HSPLandroidx/compose/ui/layout/ComposableSingletons$SubcomposeLayoutKt;-><init>()V
+HSPLandroidx/compose/ui/layout/ComposableSingletons$SubcomposeLayoutKt;->getLambda-1$ui_release()Lkotlin/jvm/functions/Function2;
+HSPLandroidx/compose/ui/layout/ContentScale$Companion$Crop$1;-><init>()V
+HSPLandroidx/compose/ui/layout/ContentScale$Companion$FillBounds$1;-><init>()V
+HSPLandroidx/compose/ui/layout/ContentScale$Companion$FillHeight$1;-><init>()V
+HSPLandroidx/compose/ui/layout/ContentScale$Companion$FillWidth$1;-><init>()V
+HSPLandroidx/compose/ui/layout/ContentScale$Companion$Fit$1;-><init>()V
+HSPLandroidx/compose/ui/layout/ContentScale$Companion$Fit$1;->computeScaleFactor-H7hwNQA(JJ)J
+HSPLandroidx/compose/ui/layout/ContentScale$Companion$Inside$1;-><init>()V
+HSPLandroidx/compose/ui/layout/ContentScale$Companion;-><clinit>()V
+HSPLandroidx/compose/ui/layout/ContentScale$Companion;-><init>()V
+HSPLandroidx/compose/ui/layout/ContentScale$Companion;->getFit()Landroidx/compose/ui/layout/ContentScale;
+HSPLandroidx/compose/ui/layout/ContentScale;-><clinit>()V
+HSPLandroidx/compose/ui/layout/ContentScaleKt;->access$computeFillMinDimension-iLBOSCw(JJ)F
+HSPLandroidx/compose/ui/layout/ContentScaleKt;->computeFillHeight-iLBOSCw(JJ)F
+HSPLandroidx/compose/ui/layout/ContentScaleKt;->computeFillMinDimension-iLBOSCw(JJ)F
+HSPLandroidx/compose/ui/layout/ContentScaleKt;->computeFillWidth-iLBOSCw(JJ)F
+HSPLandroidx/compose/ui/layout/FixedScale;-><init>(F)V
+HSPLandroidx/compose/ui/layout/HorizontalAlignmentLine;-><clinit>()V
+HSPLandroidx/compose/ui/layout/HorizontalAlignmentLine;-><init>(Lkotlin/jvm/functions/Function2;)V
+HSPLandroidx/compose/ui/layout/LayoutKt$materializerOf$1;-><init>(Landroidx/compose/ui/Modifier;)V
+HSPLandroidx/compose/ui/layout/LayoutKt$materializerOf$1;->invoke(Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;
+HSPLandroidx/compose/ui/layout/LayoutKt$materializerOf$1;->invoke-Deg8D_g(Landroidx/compose/runtime/Composer;Landroidx/compose/runtime/Composer;I)V
+HSPLandroidx/compose/ui/layout/LayoutKt;->materializerOf(Landroidx/compose/ui/Modifier;)Lkotlin/jvm/functions/Function3;
+HSPLandroidx/compose/ui/layout/LayoutNodeSubcompositionsState$NodeState;-><init>(Ljava/lang/Object;Lkotlin/jvm/functions/Function2;Landroidx/compose/runtime/Composition;)V
+HSPLandroidx/compose/ui/layout/LayoutNodeSubcompositionsState$NodeState;-><init>(Ljava/lang/Object;Lkotlin/jvm/functions/Function2;Landroidx/compose/runtime/Composition;ILkotlin/jvm/internal/DefaultConstructorMarker;)V
+HSPLandroidx/compose/ui/layout/LayoutNodeSubcompositionsState$NodeState;->getActive()Z
+HSPLandroidx/compose/ui/layout/LayoutNodeSubcompositionsState$NodeState;->getComposition()Landroidx/compose/runtime/Composition;
+HSPLandroidx/compose/ui/layout/LayoutNodeSubcompositionsState$NodeState;->getContent()Lkotlin/jvm/functions/Function2;
+HSPLandroidx/compose/ui/layout/LayoutNodeSubcompositionsState$NodeState;->setComposition(Landroidx/compose/runtime/Composition;)V
+HSPLandroidx/compose/ui/layout/LayoutNodeSubcompositionsState$NodeState;->setContent(Lkotlin/jvm/functions/Function2;)V
+HSPLandroidx/compose/ui/layout/LayoutNodeSubcompositionsState$NodeState;->setForceRecompose(Z)V
+HSPLandroidx/compose/ui/layout/LayoutNodeSubcompositionsState$Scope;-><init>(Landroidx/compose/ui/layout/LayoutNodeSubcompositionsState;)V
+HSPLandroidx/compose/ui/layout/LayoutNodeSubcompositionsState$Scope;->getLayoutDirection()Landroidx/compose/ui/unit/LayoutDirection;
+HSPLandroidx/compose/ui/layout/LayoutNodeSubcompositionsState$Scope;->setDensity(F)V
+HSPLandroidx/compose/ui/layout/LayoutNodeSubcompositionsState$Scope;->setFontScale(F)V
+HSPLandroidx/compose/ui/layout/LayoutNodeSubcompositionsState$Scope;->setLayoutDirection(Landroidx/compose/ui/unit/LayoutDirection;)V
+HSPLandroidx/compose/ui/layout/LayoutNodeSubcompositionsState$Scope;->subcompose(Ljava/lang/Object;Lkotlin/jvm/functions/Function2;)Ljava/util/List;
+HSPLandroidx/compose/ui/layout/LayoutNodeSubcompositionsState$createMeasurePolicy$1$measure$1;-><init>(Landroidx/compose/ui/layout/MeasureResult;Landroidx/compose/ui/layout/LayoutNodeSubcompositionsState;I)V
+HSPLandroidx/compose/ui/layout/LayoutNodeSubcompositionsState$createMeasurePolicy$1$measure$1;->getAlignmentLines()Ljava/util/Map;
+HSPLandroidx/compose/ui/layout/LayoutNodeSubcompositionsState$createMeasurePolicy$1$measure$1;->getHeight()I
+HSPLandroidx/compose/ui/layout/LayoutNodeSubcompositionsState$createMeasurePolicy$1$measure$1;->getWidth()I
+HSPLandroidx/compose/ui/layout/LayoutNodeSubcompositionsState$createMeasurePolicy$1$measure$1;->placeChildren()V
+HSPLandroidx/compose/ui/layout/LayoutNodeSubcompositionsState$createMeasurePolicy$1;-><init>(Landroidx/compose/ui/layout/LayoutNodeSubcompositionsState;Lkotlin/jvm/functions/Function2;Ljava/lang/String;)V
+HSPLandroidx/compose/ui/layout/LayoutNodeSubcompositionsState$createMeasurePolicy$1;->measure-3p2s80s(Landroidx/compose/ui/layout/MeasureScope;Ljava/util/List;J)Landroidx/compose/ui/layout/MeasureResult;
+HSPLandroidx/compose/ui/layout/LayoutNodeSubcompositionsState$subcompose$2$1$1;-><init>(Landroidx/compose/ui/layout/LayoutNodeSubcompositionsState$NodeState;Lkotlin/jvm/functions/Function2;)V
+HSPLandroidx/compose/ui/layout/LayoutNodeSubcompositionsState$subcompose$2$1$1;->invoke(Landroidx/compose/runtime/Composer;I)V
+HSPLandroidx/compose/ui/layout/LayoutNodeSubcompositionsState$subcompose$2$1$1;->invoke(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;
+HSPLandroidx/compose/ui/layout/LayoutNodeSubcompositionsState;-><init>(Landroidx/compose/ui/node/LayoutNode;Landroidx/compose/ui/layout/SubcomposeSlotReusePolicy;)V
+HSPLandroidx/compose/ui/layout/LayoutNodeSubcompositionsState;->access$getCurrentIndex$p(Landroidx/compose/ui/layout/LayoutNodeSubcompositionsState;)I
+HSPLandroidx/compose/ui/layout/LayoutNodeSubcompositionsState;->access$getScope$p(Landroidx/compose/ui/layout/LayoutNodeSubcompositionsState;)Landroidx/compose/ui/layout/LayoutNodeSubcompositionsState$Scope;
+HSPLandroidx/compose/ui/layout/LayoutNodeSubcompositionsState;->access$setCurrentIndex$p(Landroidx/compose/ui/layout/LayoutNodeSubcompositionsState;I)V
+HSPLandroidx/compose/ui/layout/LayoutNodeSubcompositionsState;->createMeasurePolicy(Lkotlin/jvm/functions/Function2;)Landroidx/compose/ui/layout/MeasurePolicy;
+HSPLandroidx/compose/ui/layout/LayoutNodeSubcompositionsState;->createNodeAt(I)Landroidx/compose/ui/node/LayoutNode;
+HSPLandroidx/compose/ui/layout/LayoutNodeSubcompositionsState;->disposeOrReuseStartingFromIndex(I)V
+HSPLandroidx/compose/ui/layout/LayoutNodeSubcompositionsState;->forceRecomposeChildren()V
+HSPLandroidx/compose/ui/layout/LayoutNodeSubcompositionsState;->makeSureStateIsConsistent()V
+HSPLandroidx/compose/ui/layout/LayoutNodeSubcompositionsState;->setCompositionContext(Landroidx/compose/runtime/CompositionContext;)V
+HSPLandroidx/compose/ui/layout/LayoutNodeSubcompositionsState;->setSlotReusePolicy(Landroidx/compose/ui/layout/SubcomposeSlotReusePolicy;)V
+HSPLandroidx/compose/ui/layout/LayoutNodeSubcompositionsState;->subcompose(Landroidx/compose/ui/node/LayoutNode;Landroidx/compose/ui/layout/LayoutNodeSubcompositionsState$NodeState;)V
+HSPLandroidx/compose/ui/layout/LayoutNodeSubcompositionsState;->subcompose(Landroidx/compose/ui/node/LayoutNode;Ljava/lang/Object;Lkotlin/jvm/functions/Function2;)V
+HSPLandroidx/compose/ui/layout/LayoutNodeSubcompositionsState;->subcompose(Ljava/lang/Object;Lkotlin/jvm/functions/Function2;)Ljava/util/List;
+HSPLandroidx/compose/ui/layout/LayoutNodeSubcompositionsState;->subcomposeInto(Landroidx/compose/runtime/Composition;Landroidx/compose/ui/node/LayoutNode;Landroidx/compose/runtime/CompositionContext;Lkotlin/jvm/functions/Function2;)Landroidx/compose/runtime/Composition;
+HSPLandroidx/compose/ui/layout/LayoutNodeSubcompositionsState;->takeNodeFromReusables(Ljava/lang/Object;)Landroidx/compose/ui/node/LayoutNode;
+HSPLandroidx/compose/ui/layout/MeasureScope$layout$1;-><init>(IILjava/util/Map;Landroidx/compose/ui/layout/MeasureScope;Lkotlin/jvm/functions/Function1;)V
+HSPLandroidx/compose/ui/layout/MeasureScope$layout$1;->getAlignmentLines()Ljava/util/Map;
+HSPLandroidx/compose/ui/layout/MeasureScope$layout$1;->getHeight()I
+HSPLandroidx/compose/ui/layout/MeasureScope$layout$1;->getWidth()I
+HSPLandroidx/compose/ui/layout/MeasureScope$layout$1;->placeChildren()V
+HSPLandroidx/compose/ui/layout/MeasureScope;->layout$default(Landroidx/compose/ui/layout/MeasureScope;IILjava/util/Map;Lkotlin/jvm/functions/Function1;ILjava/lang/Object;)Landroidx/compose/ui/layout/MeasureResult;
+HSPLandroidx/compose/ui/layout/MeasureScope;->layout(IILjava/util/Map;Lkotlin/jvm/functions/Function1;)Landroidx/compose/ui/layout/MeasureResult;
+HSPLandroidx/compose/ui/layout/NoOpSubcomposeSlotReusePolicy;-><clinit>()V
+HSPLandroidx/compose/ui/layout/NoOpSubcomposeSlotReusePolicy;-><init>()V
+HSPLandroidx/compose/ui/layout/OnGloballyPositionedModifierImpl;-><init>(Lkotlin/jvm/functions/Function1;Lkotlin/jvm/functions/Function1;)V
+HSPLandroidx/compose/ui/layout/OnGloballyPositionedModifierImpl;->equals(Ljava/lang/Object;)Z
+HSPLandroidx/compose/ui/layout/OnGloballyPositionedModifierImpl;->onGloballyPositioned(Landroidx/compose/ui/layout/LayoutCoordinates;)V
+HSPLandroidx/compose/ui/layout/OnGloballyPositionedModifierKt;->onGloballyPositioned(Landroidx/compose/ui/Modifier;Lkotlin/jvm/functions/Function1;)Landroidx/compose/ui/Modifier;
+HSPLandroidx/compose/ui/layout/Placeable$PlacementScope$Companion;-><init>()V
+HSPLandroidx/compose/ui/layout/Placeable$PlacementScope$Companion;-><init>(Lkotlin/jvm/internal/DefaultConstructorMarker;)V
+HSPLandroidx/compose/ui/layout/Placeable$PlacementScope$Companion;->access$configureForPlacingForAlignment(Landroidx/compose/ui/layout/Placeable$PlacementScope$Companion;Landroidx/compose/ui/node/LookaheadCapablePlaceable;)Z
+HSPLandroidx/compose/ui/layout/Placeable$PlacementScope$Companion;->access$getParentLayoutDirection(Landroidx/compose/ui/layout/Placeable$PlacementScope$Companion;)Landroidx/compose/ui/unit/LayoutDirection;
+HSPLandroidx/compose/ui/layout/Placeable$PlacementScope$Companion;->access$getParentWidth(Landroidx/compose/ui/layout/Placeable$PlacementScope$Companion;)I
+HSPLandroidx/compose/ui/layout/Placeable$PlacementScope$Companion;->configureForPlacingForAlignment(Landroidx/compose/ui/node/LookaheadCapablePlaceable;)Z
+HSPLandroidx/compose/ui/layout/Placeable$PlacementScope$Companion;->getParentLayoutDirection()Landroidx/compose/ui/unit/LayoutDirection;
+HSPLandroidx/compose/ui/layout/Placeable$PlacementScope$Companion;->getParentWidth()I
+HSPLandroidx/compose/ui/layout/Placeable$PlacementScope;-><clinit>()V
+HSPLandroidx/compose/ui/layout/Placeable$PlacementScope;-><init>()V
+HSPLandroidx/compose/ui/layout/Placeable$PlacementScope;->access$getLayoutDelegate$cp()Landroidx/compose/ui/node/LayoutNodeLayoutDelegate;
+HSPLandroidx/compose/ui/layout/Placeable$PlacementScope;->access$getParentLayoutDirection$cp()Landroidx/compose/ui/unit/LayoutDirection;
+HSPLandroidx/compose/ui/layout/Placeable$PlacementScope;->access$getParentLayoutDirection(Landroidx/compose/ui/layout/Placeable$PlacementScope;)Landroidx/compose/ui/unit/LayoutDirection;
+HSPLandroidx/compose/ui/layout/Placeable$PlacementScope;->access$getParentWidth$cp()I
+HSPLandroidx/compose/ui/layout/Placeable$PlacementScope;->access$get_coordinates$cp()Landroidx/compose/ui/layout/LayoutCoordinates;
+HSPLandroidx/compose/ui/layout/Placeable$PlacementScope;->access$setLayoutDelegate$cp(Landroidx/compose/ui/node/LayoutNodeLayoutDelegate;)V
+HSPLandroidx/compose/ui/layout/Placeable$PlacementScope;->access$setParentLayoutDirection$cp(Landroidx/compose/ui/unit/LayoutDirection;)V
+HSPLandroidx/compose/ui/layout/Placeable$PlacementScope;->access$setParentWidth$cp(I)V
+HSPLandroidx/compose/ui/layout/Placeable$PlacementScope;->access$set_coordinates$cp(Landroidx/compose/ui/layout/LayoutCoordinates;)V
+HSPLandroidx/compose/ui/layout/Placeable$PlacementScope;->place$default(Landroidx/compose/ui/layout/Placeable$PlacementScope;Landroidx/compose/ui/layout/Placeable;IIFILjava/lang/Object;)V
+HSPLandroidx/compose/ui/layout/Placeable$PlacementScope;->place(Landroidx/compose/ui/layout/Placeable;IIF)V
+HSPLandroidx/compose/ui/layout/Placeable$PlacementScope;->place-70tqf50$default(Landroidx/compose/ui/layout/Placeable$PlacementScope;Landroidx/compose/ui/layout/Placeable;JFILjava/lang/Object;)V
+HSPLandroidx/compose/ui/layout/Placeable$PlacementScope;->place-70tqf50(Landroidx/compose/ui/layout/Placeable;JF)V
+HSPLandroidx/compose/ui/layout/Placeable$PlacementScope;->placeRelative$default(Landroidx/compose/ui/layout/Placeable$PlacementScope;Landroidx/compose/ui/layout/Placeable;IIFILjava/lang/Object;)V
+HSPLandroidx/compose/ui/layout/Placeable$PlacementScope;->placeRelative(Landroidx/compose/ui/layout/Placeable;IIF)V
+HSPLandroidx/compose/ui/layout/Placeable$PlacementScope;->placeRelativeWithLayer$default(Landroidx/compose/ui/layout/Placeable$PlacementScope;Landroidx/compose/ui/layout/Placeable;IIFLkotlin/jvm/functions/Function1;ILjava/lang/Object;)V
+HSPLandroidx/compose/ui/layout/Placeable$PlacementScope;->placeRelativeWithLayer(Landroidx/compose/ui/layout/Placeable;IIFLkotlin/jvm/functions/Function1;)V
+HSPLandroidx/compose/ui/layout/Placeable$PlacementScope;->placeWithLayer$default(Landroidx/compose/ui/layout/Placeable$PlacementScope;Landroidx/compose/ui/layout/Placeable;IIFLkotlin/jvm/functions/Function1;ILjava/lang/Object;)V
+HSPLandroidx/compose/ui/layout/Placeable$PlacementScope;->placeWithLayer(Landroidx/compose/ui/layout/Placeable;IIFLkotlin/jvm/functions/Function1;)V
+HSPLandroidx/compose/ui/layout/Placeable$PlacementScope;->placeWithLayer-aW-9-wM(Landroidx/compose/ui/layout/Placeable;JFLkotlin/jvm/functions/Function1;)V
+HSPLandroidx/compose/ui/layout/Placeable;-><clinit>()V
+HSPLandroidx/compose/ui/layout/Placeable;-><init>()V
+HSPLandroidx/compose/ui/layout/Placeable;->access$getApparentToRealOffset-nOcc-ac(Landroidx/compose/ui/layout/Placeable;)J
+HSPLandroidx/compose/ui/layout/Placeable;->access$placeAt-f8xVGno(Landroidx/compose/ui/layout/Placeable;JFLkotlin/jvm/functions/Function1;)V
+HSPLandroidx/compose/ui/layout/Placeable;->getApparentToRealOffset-nOcc-ac()J
+HSPLandroidx/compose/ui/layout/Placeable;->getHeight()I
+HSPLandroidx/compose/ui/layout/Placeable;->getMeasuredSize-YbymL2g()J
+HSPLandroidx/compose/ui/layout/Placeable;->getMeasuredWidth()I
+HSPLandroidx/compose/ui/layout/Placeable;->getMeasurementConstraints-msEJaDk()J
+HSPLandroidx/compose/ui/layout/Placeable;->getWidth()I
+HSPLandroidx/compose/ui/layout/Placeable;->recalculateWidthAndHeight()V
+HSPLandroidx/compose/ui/layout/Placeable;->setMeasuredSize-ozmzZPI(J)V
+HSPLandroidx/compose/ui/layout/Placeable;->setMeasurementConstraints-BRTryo0(J)V
+HSPLandroidx/compose/ui/layout/PlaceableKt$DefaultLayerBlock$1;-><clinit>()V
+HSPLandroidx/compose/ui/layout/PlaceableKt$DefaultLayerBlock$1;-><init>()V
+HSPLandroidx/compose/ui/layout/PlaceableKt$DefaultLayerBlock$1;->invoke(Landroidx/compose/ui/graphics/GraphicsLayerScope;)V
+HSPLandroidx/compose/ui/layout/PlaceableKt$DefaultLayerBlock$1;->invoke(Ljava/lang/Object;)Ljava/lang/Object;
+HSPLandroidx/compose/ui/layout/PlaceableKt;-><clinit>()V
+HSPLandroidx/compose/ui/layout/PlaceableKt;->access$getDefaultConstraints$p()J
+HSPLandroidx/compose/ui/layout/PlaceableKt;->access$getDefaultLayerBlock$p()Lkotlin/jvm/functions/Function1;
+HSPLandroidx/compose/ui/layout/RootMeasurePolicy$measure$2;-><init>(Landroidx/compose/ui/layout/Placeable;)V
+HSPLandroidx/compose/ui/layout/RootMeasurePolicy$measure$2;->invoke(Landroidx/compose/ui/layout/Placeable$PlacementScope;)V
+HSPLandroidx/compose/ui/layout/RootMeasurePolicy$measure$2;->invoke(Ljava/lang/Object;)Ljava/lang/Object;
+HSPLandroidx/compose/ui/layout/RootMeasurePolicy;-><clinit>()V
+HSPLandroidx/compose/ui/layout/RootMeasurePolicy;-><init>()V
+HSPLandroidx/compose/ui/layout/RootMeasurePolicy;->measure-3p2s80s(Landroidx/compose/ui/layout/MeasureScope;Ljava/util/List;J)Landroidx/compose/ui/layout/MeasureResult;
+HSPLandroidx/compose/ui/layout/ScaleFactor$Companion;-><init>()V
+HSPLandroidx/compose/ui/layout/ScaleFactor$Companion;-><init>(Lkotlin/jvm/internal/DefaultConstructorMarker;)V
+HSPLandroidx/compose/ui/layout/ScaleFactor;-><clinit>()V
+HSPLandroidx/compose/ui/layout/ScaleFactor;->constructor-impl(J)J
+HSPLandroidx/compose/ui/layout/ScaleFactor;->getScaleX-impl(J)F
+HSPLandroidx/compose/ui/layout/ScaleFactor;->getScaleY-impl(J)F
+HSPLandroidx/compose/ui/layout/ScaleFactorKt;->ScaleFactor(FF)J
+HSPLandroidx/compose/ui/layout/ScaleFactorKt;->times-UQTWf7w(JJ)J
+HSPLandroidx/compose/ui/layout/SubcomposeLayoutKt$SubcomposeLayout$$inlined$ComposeNode$1;-><init>(Lkotlin/jvm/functions/Function0;)V
+HSPLandroidx/compose/ui/layout/SubcomposeLayoutKt$SubcomposeLayout$$inlined$ComposeNode$1;->invoke()Ljava/lang/Object;
+HSPLandroidx/compose/ui/layout/SubcomposeLayoutKt$SubcomposeLayout$4;-><init>(Landroidx/compose/ui/layout/SubcomposeLayoutState;)V
+HSPLandroidx/compose/ui/layout/SubcomposeLayoutKt$SubcomposeLayout$4;->invoke()Ljava/lang/Object;
+HSPLandroidx/compose/ui/layout/SubcomposeLayoutKt$SubcomposeLayout$4;->invoke()V
+HSPLandroidx/compose/ui/layout/SubcomposeLayoutKt$SubcomposeLayout$5$1$invoke$$inlined$onDispose$1;-><init>(Landroidx/compose/runtime/State;)V
+HSPLandroidx/compose/ui/layout/SubcomposeLayoutKt$SubcomposeLayout$5$1;-><init>(Landroidx/compose/runtime/State;)V
+HSPLandroidx/compose/ui/layout/SubcomposeLayoutKt$SubcomposeLayout$5$1;->invoke(Landroidx/compose/runtime/DisposableEffectScope;)Landroidx/compose/runtime/DisposableEffectResult;
+HSPLandroidx/compose/ui/layout/SubcomposeLayoutKt$SubcomposeLayout$5$1;->invoke(Ljava/lang/Object;)Ljava/lang/Object;
+HSPLandroidx/compose/ui/layout/SubcomposeLayoutKt;->SubcomposeLayout(Landroidx/compose/ui/Modifier;Lkotlin/jvm/functions/Function2;Landroidx/compose/runtime/Composer;II)V
+HSPLandroidx/compose/ui/layout/SubcomposeLayoutKt;->SubcomposeLayout(Landroidx/compose/ui/layout/SubcomposeLayoutState;Landroidx/compose/ui/Modifier;Lkotlin/jvm/functions/Function2;Landroidx/compose/runtime/Composer;II)V
+HSPLandroidx/compose/ui/layout/SubcomposeLayoutState$setCompositionContext$1;-><init>(Landroidx/compose/ui/layout/SubcomposeLayoutState;)V
+HSPLandroidx/compose/ui/layout/SubcomposeLayoutState$setCompositionContext$1;->invoke(Landroidx/compose/ui/node/LayoutNode;Landroidx/compose/runtime/CompositionContext;)V
+HSPLandroidx/compose/ui/layout/SubcomposeLayoutState$setCompositionContext$1;->invoke(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;
+HSPLandroidx/compose/ui/layout/SubcomposeLayoutState$setMeasurePolicy$1;-><init>(Landroidx/compose/ui/layout/SubcomposeLayoutState;)V
+HSPLandroidx/compose/ui/layout/SubcomposeLayoutState$setMeasurePolicy$1;->invoke(Landroidx/compose/ui/node/LayoutNode;Lkotlin/jvm/functions/Function2;)V
+HSPLandroidx/compose/ui/layout/SubcomposeLayoutState$setMeasurePolicy$1;->invoke(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;
+HSPLandroidx/compose/ui/layout/SubcomposeLayoutState$setRoot$1;-><init>(Landroidx/compose/ui/layout/SubcomposeLayoutState;)V
+HSPLandroidx/compose/ui/layout/SubcomposeLayoutState$setRoot$1;->invoke(Landroidx/compose/ui/node/LayoutNode;Landroidx/compose/ui/layout/SubcomposeLayoutState;)V
+HSPLandroidx/compose/ui/layout/SubcomposeLayoutState$setRoot$1;->invoke(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;
+HSPLandroidx/compose/ui/layout/SubcomposeLayoutState;-><clinit>()V
+HSPLandroidx/compose/ui/layout/SubcomposeLayoutState;-><init>()V
+HSPLandroidx/compose/ui/layout/SubcomposeLayoutState;-><init>(Landroidx/compose/ui/layout/SubcomposeSlotReusePolicy;)V
+HSPLandroidx/compose/ui/layout/SubcomposeLayoutState;->access$getSlotReusePolicy$p(Landroidx/compose/ui/layout/SubcomposeLayoutState;)Landroidx/compose/ui/layout/SubcomposeSlotReusePolicy;
+HSPLandroidx/compose/ui/layout/SubcomposeLayoutState;->access$getState(Landroidx/compose/ui/layout/SubcomposeLayoutState;)Landroidx/compose/ui/layout/LayoutNodeSubcompositionsState;
+HSPLandroidx/compose/ui/layout/SubcomposeLayoutState;->access$set_state$p(Landroidx/compose/ui/layout/SubcomposeLayoutState;Landroidx/compose/ui/layout/LayoutNodeSubcompositionsState;)V
+HSPLandroidx/compose/ui/layout/SubcomposeLayoutState;->forceRecomposeChildren$ui_release()V
+HSPLandroidx/compose/ui/layout/SubcomposeLayoutState;->getSetCompositionContext$ui_release()Lkotlin/jvm/functions/Function2;
+HSPLandroidx/compose/ui/layout/SubcomposeLayoutState;->getSetMeasurePolicy$ui_release()Lkotlin/jvm/functions/Function2;
+HSPLandroidx/compose/ui/layout/SubcomposeLayoutState;->getSetRoot$ui_release()Lkotlin/jvm/functions/Function2;
+HSPLandroidx/compose/ui/layout/SubcomposeLayoutState;->getState()Landroidx/compose/ui/layout/LayoutNodeSubcompositionsState;
+HSPLandroidx/compose/ui/layout/SubcomposeSlotReusePolicy$SlotIdsSet;-><clinit>()V
+HSPLandroidx/compose/ui/layout/SubcomposeSlotReusePolicy$SlotIdsSet;-><init>(Ljava/util/Set;)V
+HSPLandroidx/compose/ui/layout/SubcomposeSlotReusePolicy$SlotIdsSet;-><init>(Ljava/util/Set;ILkotlin/jvm/internal/DefaultConstructorMarker;)V
+HSPLandroidx/compose/ui/modifier/BackwardsCompatLocalMap;-><init>(Landroidx/compose/ui/modifier/ModifierLocalProvider;)V
+HSPLandroidx/compose/ui/modifier/BackwardsCompatLocalMap;->contains$ui_release(Landroidx/compose/ui/modifier/ModifierLocal;)Z
+HSPLandroidx/compose/ui/modifier/BackwardsCompatLocalMap;->get$ui_release(Landroidx/compose/ui/modifier/ModifierLocal;)Ljava/lang/Object;
+HSPLandroidx/compose/ui/modifier/BackwardsCompatLocalMap;->setElement(Landroidx/compose/ui/modifier/ModifierLocalProvider;)V
+HSPLandroidx/compose/ui/modifier/EmptyMap;-><clinit>()V
+HSPLandroidx/compose/ui/modifier/EmptyMap;-><init>()V
+HSPLandroidx/compose/ui/modifier/EmptyMap;->contains$ui_release(Landroidx/compose/ui/modifier/ModifierLocal;)Z
+HSPLandroidx/compose/ui/modifier/ModifierLocal;-><init>(Lkotlin/jvm/functions/Function0;)V
+HSPLandroidx/compose/ui/modifier/ModifierLocal;-><init>(Lkotlin/jvm/functions/Function0;Lkotlin/jvm/internal/DefaultConstructorMarker;)V
+HSPLandroidx/compose/ui/modifier/ModifierLocal;->getDefaultFactory$ui_release()Lkotlin/jvm/functions/Function0;
+HSPLandroidx/compose/ui/modifier/ModifierLocalConsumerImpl;-><init>(Lkotlin/jvm/functions/Function1;Lkotlin/jvm/functions/Function1;)V
+HSPLandroidx/compose/ui/modifier/ModifierLocalConsumerImpl;->equals(Ljava/lang/Object;)Z
+HSPLandroidx/compose/ui/modifier/ModifierLocalConsumerImpl;->onModifierLocalsUpdated(Landroidx/compose/ui/modifier/ModifierLocalReadScope;)V
+HSPLandroidx/compose/ui/modifier/ModifierLocalConsumerKt;->modifierLocalConsumer(Landroidx/compose/ui/Modifier;Lkotlin/jvm/functions/Function1;)Landroidx/compose/ui/Modifier;
+HSPLandroidx/compose/ui/modifier/ModifierLocalKt;->modifierLocalOf(Lkotlin/jvm/functions/Function0;)Landroidx/compose/ui/modifier/ProvidableModifierLocal;
+HSPLandroidx/compose/ui/modifier/ModifierLocalManager$invalidate$1;-><init>(Landroidx/compose/ui/modifier/ModifierLocalManager;)V
+HSPLandroidx/compose/ui/modifier/ModifierLocalManager$invalidate$1;->invoke()Ljava/lang/Object;
+HSPLandroidx/compose/ui/modifier/ModifierLocalManager$invalidate$1;->invoke()V
+HSPLandroidx/compose/ui/modifier/ModifierLocalManager;-><init>(Landroidx/compose/ui/node/Owner;)V
+HSPLandroidx/compose/ui/modifier/ModifierLocalManager;->invalidate()V
+HSPLandroidx/compose/ui/modifier/ModifierLocalManager;->invalidateConsumersOfNodeForKey(Landroidx/compose/ui/Modifier$Node;Landroidx/compose/ui/modifier/ModifierLocal;Ljava/util/Set;)V
+HSPLandroidx/compose/ui/modifier/ModifierLocalManager;->removedProvider(Landroidx/compose/ui/node/BackwardsCompatNode;Landroidx/compose/ui/modifier/ModifierLocal;)V
+HSPLandroidx/compose/ui/modifier/ModifierLocalManager;->triggerUpdates()V
+HSPLandroidx/compose/ui/modifier/ModifierLocalManager;->updatedProvider(Landroidx/compose/ui/node/BackwardsCompatNode;Landroidx/compose/ui/modifier/ModifierLocal;)V
+HSPLandroidx/compose/ui/modifier/ModifierLocalMap;-><clinit>()V
+HSPLandroidx/compose/ui/modifier/ModifierLocalMap;-><init>()V
+HSPLandroidx/compose/ui/modifier/ModifierLocalMap;-><init>(Lkotlin/jvm/internal/DefaultConstructorMarker;)V
+HSPLandroidx/compose/ui/modifier/ModifierLocalNodeKt;->modifierLocalMapOf()Landroidx/compose/ui/modifier/ModifierLocalMap;
+HSPLandroidx/compose/ui/modifier/ProvidableModifierLocal;-><init>(Lkotlin/jvm/functions/Function0;)V
+HSPLandroidx/compose/ui/node/AlignmentLines;-><init>(Landroidx/compose/ui/node/AlignmentLinesOwner;)V
+HSPLandroidx/compose/ui/node/AlignmentLines;-><init>(Landroidx/compose/ui/node/AlignmentLinesOwner;Lkotlin/jvm/internal/DefaultConstructorMarker;)V
+HSPLandroidx/compose/ui/node/AlignmentLines;->getDirty$ui_release()Z
+HSPLandroidx/compose/ui/node/AlignmentLines;->getQueried$ui_release()Z
+HSPLandroidx/compose/ui/node/AlignmentLines;->getRequired$ui_release()Z
+HSPLandroidx/compose/ui/node/AlignmentLines;->getUsedDuringParentLayout$ui_release()Z
+HSPLandroidx/compose/ui/node/AlignmentLines;->onAlignmentsChanged()V
+HSPLandroidx/compose/ui/node/AlignmentLines;->recalculateQueryOwner()V
+HSPLandroidx/compose/ui/node/AlignmentLines;->setPreviousUsedDuringParentLayout$ui_release(Z)V
+HSPLandroidx/compose/ui/node/AlignmentLines;->setUsedByModifierLayout$ui_release(Z)V
+HSPLandroidx/compose/ui/node/AlignmentLines;->setUsedByModifierMeasurement$ui_release(Z)V
+HSPLandroidx/compose/ui/node/AlignmentLines;->setUsedDuringParentMeasurement$ui_release(Z)V
+HSPLandroidx/compose/ui/node/BackwardsCompatNode$initializeModifier$1;-><init>(Landroidx/compose/ui/node/BackwardsCompatNode;)V
+HSPLandroidx/compose/ui/node/BackwardsCompatNode$initializeModifier$1;->invoke()Ljava/lang/Object;
+HSPLandroidx/compose/ui/node/BackwardsCompatNode$initializeModifier$1;->invoke()V
+HSPLandroidx/compose/ui/node/BackwardsCompatNode$initializeModifier$4;-><init>(Landroidx/compose/ui/node/BackwardsCompatNode;)V
+HSPLandroidx/compose/ui/node/BackwardsCompatNode$initializeModifier$4;->onLayoutComplete()V
+HSPLandroidx/compose/ui/node/BackwardsCompatNode$updateModifierLocalConsumer$1;-><init>(Landroidx/compose/ui/node/BackwardsCompatNode;)V
+HSPLandroidx/compose/ui/node/BackwardsCompatNode$updateModifierLocalConsumer$1;->invoke()Ljava/lang/Object;
+HSPLandroidx/compose/ui/node/BackwardsCompatNode$updateModifierLocalConsumer$1;->invoke()V
+HSPLandroidx/compose/ui/node/BackwardsCompatNode;-><init>(Landroidx/compose/ui/Modifier$Element;)V
+HSPLandroidx/compose/ui/node/BackwardsCompatNode;->access$getLastOnPlacedCoordinates$p(Landroidx/compose/ui/node/BackwardsCompatNode;)Landroidx/compose/ui/layout/LayoutCoordinates;
+HSPLandroidx/compose/ui/node/BackwardsCompatNode;->draw(Landroidx/compose/ui/graphics/drawscope/ContentDrawScope;)V
+HSPLandroidx/compose/ui/node/BackwardsCompatNode;->getCurrent(Landroidx/compose/ui/modifier/ModifierLocal;)Ljava/lang/Object;+]Landroidx/compose/ui/modifier/ModifierLocal;Landroidx/compose/ui/modifier/ProvidableModifierLocal;]Landroidx/compose/ui/modifier/ModifierLocalMap;Landroidx/compose/ui/modifier/BackwardsCompatLocalMap;,Landroidx/compose/ui/modifier/EmptyMap;]Landroidx/compose/ui/Modifier$Node;Landroidx/compose/ui/node/BackwardsCompatNode;,Landroidx/compose/ui/node/InnerNodeCoordinator$tail$1;]Landroidx/compose/ui/node/NodeChain;Landroidx/compose/ui/node/NodeChain;]Landroidx/compose/ui/modifier/ModifierLocalNode;Landroidx/compose/ui/node/BackwardsCompatNode;]Landroidx/compose/ui/node/LayoutNode;Landroidx/compose/ui/node/LayoutNode;]Lkotlin/jvm/functions/Function0;megamorphic_types]Landroidx/compose/ui/node/DelegatableNode;Landroidx/compose/ui/node/BackwardsCompatNode;
+HSPLandroidx/compose/ui/node/BackwardsCompatNode;->getElement()Landroidx/compose/ui/Modifier$Element;
+HSPLandroidx/compose/ui/node/BackwardsCompatNode;->getProvidedValues()Landroidx/compose/ui/modifier/ModifierLocalMap;
+HSPLandroidx/compose/ui/node/BackwardsCompatNode;->getReadValues()Ljava/util/HashSet;
+HSPLandroidx/compose/ui/node/BackwardsCompatNode;->getSemanticsConfiguration()Landroidx/compose/ui/semantics/SemanticsConfiguration;
+HSPLandroidx/compose/ui/node/BackwardsCompatNode;->initializeModifier(Z)V
+HSPLandroidx/compose/ui/node/BackwardsCompatNode;->measure-3p2s80s(Landroidx/compose/ui/layout/MeasureScope;Landroidx/compose/ui/layout/Measurable;J)Landroidx/compose/ui/layout/MeasureResult;
+HSPLandroidx/compose/ui/node/BackwardsCompatNode;->modifyParentData(Landroidx/compose/ui/unit/Density;Ljava/lang/Object;)Ljava/lang/Object;
+HSPLandroidx/compose/ui/node/BackwardsCompatNode;->onAttach()V
+HSPLandroidx/compose/ui/node/BackwardsCompatNode;->onGloballyPositioned(Landroidx/compose/ui/layout/LayoutCoordinates;)V
+HSPLandroidx/compose/ui/node/BackwardsCompatNode;->onMeasureResultChanged()V
+HSPLandroidx/compose/ui/node/BackwardsCompatNode;->onPlaced(Landroidx/compose/ui/layout/LayoutCoordinates;)V
+HSPLandroidx/compose/ui/node/BackwardsCompatNode;->onRemeasured-ozmzZPI(J)V
+HSPLandroidx/compose/ui/node/BackwardsCompatNode;->setElement(Landroidx/compose/ui/Modifier$Element;)V
+HSPLandroidx/compose/ui/node/BackwardsCompatNode;->uninitializeModifier()V
+HSPLandroidx/compose/ui/node/BackwardsCompatNode;->updateModifierLocalConsumer()V
+HSPLandroidx/compose/ui/node/BackwardsCompatNode;->updateModifierLocalProvider(Landroidx/compose/ui/modifier/ModifierLocalProvider;)V
+HSPLandroidx/compose/ui/node/BackwardsCompatNodeKt$DetachedModifierLocalReadScope$1;-><init>()V
+HSPLandroidx/compose/ui/node/BackwardsCompatNodeKt$DetachedModifierLocalReadScope$1;->getCurrent(Landroidx/compose/ui/modifier/ModifierLocal;)Ljava/lang/Object;
+HSPLandroidx/compose/ui/node/BackwardsCompatNodeKt$onDrawCacheReadsChanged$1;-><clinit>()V
+HSPLandroidx/compose/ui/node/BackwardsCompatNodeKt$onDrawCacheReadsChanged$1;-><init>()V
+HSPLandroidx/compose/ui/node/BackwardsCompatNodeKt$updateFocusOrderModifierLocalConsumer$1;-><clinit>()V
+HSPLandroidx/compose/ui/node/BackwardsCompatNodeKt$updateFocusOrderModifierLocalConsumer$1;-><init>()V
+HSPLandroidx/compose/ui/node/BackwardsCompatNodeKt$updateModifierLocalConsumer$1;-><clinit>()V
+HSPLandroidx/compose/ui/node/BackwardsCompatNodeKt$updateModifierLocalConsumer$1;-><init>()V
+HSPLandroidx/compose/ui/node/BackwardsCompatNodeKt;-><clinit>()V
+HSPLandroidx/compose/ui/node/BackwardsCompatNodeKt;->access$getDetachedModifierLocalReadScope$p()Landroidx/compose/ui/node/BackwardsCompatNodeKt$DetachedModifierLocalReadScope$1;
+HSPLandroidx/compose/ui/node/BackwardsCompatNodeKt;->access$getUpdateModifierLocalConsumer$p()Lkotlin/jvm/functions/Function1;
+HSPLandroidx/compose/ui/node/CenteredArray;->constructor-impl([I)[I
+HSPLandroidx/compose/ui/node/CenteredArray;->get-impl([II)I
+HSPLandroidx/compose/ui/node/CenteredArray;->getMid-impl([I)I
+HSPLandroidx/compose/ui/node/CenteredArray;->set-impl([III)V
+HSPLandroidx/compose/ui/node/ComposeUiNode$Companion$SetDensity$1;-><clinit>()V
+HSPLandroidx/compose/ui/node/ComposeUiNode$Companion$SetDensity$1;-><init>()V
+HSPLandroidx/compose/ui/node/ComposeUiNode$Companion$SetDensity$1;->invoke(Landroidx/compose/ui/node/ComposeUiNode;Landroidx/compose/ui/unit/Density;)V
+HSPLandroidx/compose/ui/node/ComposeUiNode$Companion$SetDensity$1;->invoke(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;
+HSPLandroidx/compose/ui/node/ComposeUiNode$Companion$SetLayoutDirection$1;-><clinit>()V
+HSPLandroidx/compose/ui/node/ComposeUiNode$Companion$SetLayoutDirection$1;-><init>()V
+HSPLandroidx/compose/ui/node/ComposeUiNode$Companion$SetLayoutDirection$1;->invoke(Landroidx/compose/ui/node/ComposeUiNode;Landroidx/compose/ui/unit/LayoutDirection;)V
+HSPLandroidx/compose/ui/node/ComposeUiNode$Companion$SetLayoutDirection$1;->invoke(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;
+HSPLandroidx/compose/ui/node/ComposeUiNode$Companion$SetMeasurePolicy$1;-><clinit>()V
+HSPLandroidx/compose/ui/node/ComposeUiNode$Companion$SetMeasurePolicy$1;-><init>()V
+HSPLandroidx/compose/ui/node/ComposeUiNode$Companion$SetMeasurePolicy$1;->invoke(Landroidx/compose/ui/node/ComposeUiNode;Landroidx/compose/ui/layout/MeasurePolicy;)V
+HSPLandroidx/compose/ui/node/ComposeUiNode$Companion$SetMeasurePolicy$1;->invoke(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;
+HSPLandroidx/compose/ui/node/ComposeUiNode$Companion$SetModifier$1;-><clinit>()V
+HSPLandroidx/compose/ui/node/ComposeUiNode$Companion$SetModifier$1;-><init>()V
+HSPLandroidx/compose/ui/node/ComposeUiNode$Companion$SetModifier$1;->invoke(Landroidx/compose/ui/node/ComposeUiNode;Landroidx/compose/ui/Modifier;)V
+HSPLandroidx/compose/ui/node/ComposeUiNode$Companion$SetModifier$1;->invoke(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;
+HSPLandroidx/compose/ui/node/ComposeUiNode$Companion$SetViewConfiguration$1;-><clinit>()V
+HSPLandroidx/compose/ui/node/ComposeUiNode$Companion$SetViewConfiguration$1;-><init>()V
+HSPLandroidx/compose/ui/node/ComposeUiNode$Companion$SetViewConfiguration$1;->invoke(Landroidx/compose/ui/node/ComposeUiNode;Landroidx/compose/ui/platform/ViewConfiguration;)V
+HSPLandroidx/compose/ui/node/ComposeUiNode$Companion$SetViewConfiguration$1;->invoke(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;
+HSPLandroidx/compose/ui/node/ComposeUiNode$Companion$VirtualConstructor$1;-><clinit>()V
+HSPLandroidx/compose/ui/node/ComposeUiNode$Companion$VirtualConstructor$1;-><init>()V
+HSPLandroidx/compose/ui/node/ComposeUiNode$Companion;-><clinit>()V
+HSPLandroidx/compose/ui/node/ComposeUiNode$Companion;-><init>()V
+HSPLandroidx/compose/ui/node/ComposeUiNode$Companion;->getConstructor()Lkotlin/jvm/functions/Function0;
+HSPLandroidx/compose/ui/node/ComposeUiNode$Companion;->getSetDensity()Lkotlin/jvm/functions/Function2;
+HSPLandroidx/compose/ui/node/ComposeUiNode$Companion;->getSetLayoutDirection()Lkotlin/jvm/functions/Function2;
+HSPLandroidx/compose/ui/node/ComposeUiNode$Companion;->getSetMeasurePolicy()Lkotlin/jvm/functions/Function2;
+HSPLandroidx/compose/ui/node/ComposeUiNode$Companion;->getSetModifier()Lkotlin/jvm/functions/Function2;
+HSPLandroidx/compose/ui/node/ComposeUiNode$Companion;->getSetViewConfiguration()Lkotlin/jvm/functions/Function2;
+HSPLandroidx/compose/ui/node/ComposeUiNode;-><clinit>()V
+HSPLandroidx/compose/ui/node/DelegatableNodeKt;->access$addLayoutNodeChildren(Landroidx/compose/runtime/collection/MutableVector;Landroidx/compose/ui/Modifier$Node;)V
+HSPLandroidx/compose/ui/node/DelegatableNodeKt;->addLayoutNodeChildren(Landroidx/compose/runtime/collection/MutableVector;Landroidx/compose/ui/Modifier$Node;)V
+HSPLandroidx/compose/ui/node/DelegatableNodeKt;->has-64DMado(Landroidx/compose/ui/node/DelegatableNode;I)Z
+HSPLandroidx/compose/ui/node/DelegatableNodeKt;->localChild(Landroidx/compose/ui/node/DelegatableNode;I)Landroidx/compose/ui/Modifier$Node;
+HSPLandroidx/compose/ui/node/DelegatableNodeKt;->requireCoordinator-64DMado(Landroidx/compose/ui/node/DelegatableNode;I)Landroidx/compose/ui/node/NodeCoordinator;
+HSPLandroidx/compose/ui/node/DelegatableNodeKt;->requireLayoutNode(Landroidx/compose/ui/node/DelegatableNode;)Landroidx/compose/ui/node/LayoutNode;
+HSPLandroidx/compose/ui/node/DelegatableNodeKt;->requireOwner(Landroidx/compose/ui/node/DelegatableNode;)Landroidx/compose/ui/node/Owner;
+HSPLandroidx/compose/ui/node/DepthSortedSet$DepthComparator$1;-><init>()V
+HSPLandroidx/compose/ui/node/DepthSortedSet$DepthComparator$1;->compare(Landroidx/compose/ui/node/LayoutNode;Landroidx/compose/ui/node/LayoutNode;)I
+HSPLandroidx/compose/ui/node/DepthSortedSet$DepthComparator$1;->compare(Ljava/lang/Object;Ljava/lang/Object;)I
+HSPLandroidx/compose/ui/node/DepthSortedSet$mapOfOriginalDepth$2;-><clinit>()V
+HSPLandroidx/compose/ui/node/DepthSortedSet$mapOfOriginalDepth$2;-><init>()V
+HSPLandroidx/compose/ui/node/DepthSortedSet;-><init>(Z)V
+HSPLandroidx/compose/ui/node/DepthSortedSet;->add(Landroidx/compose/ui/node/LayoutNode;)V
+HSPLandroidx/compose/ui/node/DepthSortedSet;->isEmpty()Z
+HSPLandroidx/compose/ui/node/DepthSortedSet;->pop()Landroidx/compose/ui/node/LayoutNode;
+HSPLandroidx/compose/ui/node/DepthSortedSet;->remove(Landroidx/compose/ui/node/LayoutNode;)Z
+HSPLandroidx/compose/ui/node/DrawModifierNodeKt;->invalidateDraw(Landroidx/compose/ui/node/DrawModifierNode;)V
+HSPLandroidx/compose/ui/node/HitTestResult;-><init>()V
+HSPLandroidx/compose/ui/node/InnerNodeCoordinator$Companion;-><init>()V
+HSPLandroidx/compose/ui/node/InnerNodeCoordinator$Companion;-><init>(Lkotlin/jvm/internal/DefaultConstructorMarker;)V
+HSPLandroidx/compose/ui/node/InnerNodeCoordinator$tail$1;-><init>()V
+HSPLandroidx/compose/ui/node/InnerNodeCoordinator;-><clinit>()V
+HSPLandroidx/compose/ui/node/InnerNodeCoordinator;-><init>(Landroidx/compose/ui/node/LayoutNode;)V
+HSPLandroidx/compose/ui/node/InnerNodeCoordinator;->getTail()Landroidx/compose/ui/Modifier$Node;
+HSPLandroidx/compose/ui/node/InnerNodeCoordinator;->measure-BRTryo0(J)Landroidx/compose/ui/layout/Placeable;
+HSPLandroidx/compose/ui/node/InnerNodeCoordinator;->performDraw(Landroidx/compose/ui/graphics/Canvas;)V
+HSPLandroidx/compose/ui/node/InnerNodeCoordinator;->placeAt-f8xVGno(JFLkotlin/jvm/functions/Function1;)V
+HSPLandroidx/compose/ui/node/IntStack;-><init>(I)V
+HSPLandroidx/compose/ui/node/IntStack;->compareDiagonal(II)Z
+HSPLandroidx/compose/ui/node/IntStack;->isNotEmpty()Z
+HSPLandroidx/compose/ui/node/IntStack;->partition(III)I
+HSPLandroidx/compose/ui/node/IntStack;->pop()I
+HSPLandroidx/compose/ui/node/IntStack;->pushDiagonal(III)V
+HSPLandroidx/compose/ui/node/IntStack;->pushRange(IIII)V
+HSPLandroidx/compose/ui/node/IntStack;->quickSort(III)V
+HSPLandroidx/compose/ui/node/IntStack;->sortDiagonals()V
+HSPLandroidx/compose/ui/node/IntStack;->swapDiagonal(II)V
+HSPLandroidx/compose/ui/node/IntrinsicsPolicy$Companion;-><init>()V
+HSPLandroidx/compose/ui/node/IntrinsicsPolicy$Companion;-><init>(Lkotlin/jvm/internal/DefaultConstructorMarker;)V
+HSPLandroidx/compose/ui/node/IntrinsicsPolicy;-><clinit>()V
+HSPLandroidx/compose/ui/node/IntrinsicsPolicy;-><init>(Landroidx/compose/ui/node/LayoutNode;)V
+HSPLandroidx/compose/ui/node/IntrinsicsPolicy;->setMeasurePolicyState(Landroidx/compose/ui/layout/MeasurePolicy;)V
+HSPLandroidx/compose/ui/node/IntrinsicsPolicy;->updateFrom(Landroidx/compose/ui/layout/MeasurePolicy;)V
+HSPLandroidx/compose/ui/node/LayerPositionalProperties;-><init>()V
+HSPLandroidx/compose/ui/node/LayerPositionalProperties;->copyFrom(Landroidx/compose/ui/graphics/GraphicsLayerScope;)V
+HSPLandroidx/compose/ui/node/LayoutModifierNodeCoordinator$Companion;-><init>()V
+HSPLandroidx/compose/ui/node/LayoutModifierNodeCoordinator$Companion;-><init>(Lkotlin/jvm/internal/DefaultConstructorMarker;)V
+HSPLandroidx/compose/ui/node/LayoutModifierNodeCoordinator;-><clinit>()V
+HSPLandroidx/compose/ui/node/LayoutModifierNodeCoordinator;-><init>(Landroidx/compose/ui/node/LayoutNode;Landroidx/compose/ui/node/LayoutModifierNode;)V
+HSPLandroidx/compose/ui/node/LayoutModifierNodeCoordinator;->getLayoutModifierNode()Landroidx/compose/ui/node/LayoutModifierNode;
+HSPLandroidx/compose/ui/node/LayoutModifierNodeCoordinator;->getTail()Landroidx/compose/ui/Modifier$Node;
+HSPLandroidx/compose/ui/node/LayoutModifierNodeCoordinator;->getWrappedNonNull()Landroidx/compose/ui/node/NodeCoordinator;
+HSPLandroidx/compose/ui/node/LayoutModifierNodeCoordinator;->measure-BRTryo0(J)Landroidx/compose/ui/layout/Placeable;
+HSPLandroidx/compose/ui/node/LayoutModifierNodeCoordinator;->onLayoutModifierNodeChanged()V
+HSPLandroidx/compose/ui/node/LayoutModifierNodeCoordinator;->performDraw(Landroidx/compose/ui/graphics/Canvas;)V
+HSPLandroidx/compose/ui/node/LayoutModifierNodeCoordinator;->placeAt-f8xVGno(JFLkotlin/jvm/functions/Function1;)V
+HSPLandroidx/compose/ui/node/LayoutModifierNodeCoordinator;->setLayoutModifierNode$ui_release(Landroidx/compose/ui/node/LayoutModifierNode;)V
+HSPLandroidx/compose/ui/node/LayoutModifierNodeKt;->invalidateLayer(Landroidx/compose/ui/node/LayoutModifierNode;)V
+HSPLandroidx/compose/ui/node/LayoutModifierNodeKt;->invalidateMeasurements(Landroidx/compose/ui/node/LayoutModifierNode;)V
+HSPLandroidx/compose/ui/node/LayoutNode$$ExternalSyntheticLambda0;-><init>()V
+HSPLandroidx/compose/ui/node/LayoutNode$$ExternalSyntheticLambda0;->compare(Ljava/lang/Object;Ljava/lang/Object;)I
+HSPLandroidx/compose/ui/node/LayoutNode$Companion$Constructor$1;-><clinit>()V
+HSPLandroidx/compose/ui/node/LayoutNode$Companion$Constructor$1;-><init>()V
+HSPLandroidx/compose/ui/node/LayoutNode$Companion$Constructor$1;->invoke()Landroidx/compose/ui/node/LayoutNode;
+HSPLandroidx/compose/ui/node/LayoutNode$Companion$Constructor$1;->invoke()Ljava/lang/Object;
+HSPLandroidx/compose/ui/node/LayoutNode$Companion$DummyViewConfiguration$1;-><init>()V
+HSPLandroidx/compose/ui/node/LayoutNode$Companion$ErrorMeasurePolicy$1;-><init>()V
+HSPLandroidx/compose/ui/node/LayoutNode$Companion;-><init>()V
+HSPLandroidx/compose/ui/node/LayoutNode$Companion;-><init>(Lkotlin/jvm/internal/DefaultConstructorMarker;)V
+HSPLandroidx/compose/ui/node/LayoutNode$Companion;->getConstructor$ui_release()Lkotlin/jvm/functions/Function0;
+HSPLandroidx/compose/ui/node/LayoutNode$LayoutState;->$values()[Landroidx/compose/ui/node/LayoutNode$LayoutState;
+HSPLandroidx/compose/ui/node/LayoutNode$LayoutState;-><clinit>()V
+HSPLandroidx/compose/ui/node/LayoutNode$LayoutState;-><init>(Ljava/lang/String;I)V
+HSPLandroidx/compose/ui/node/LayoutNode$LayoutState;->values()[Landroidx/compose/ui/node/LayoutNode$LayoutState;
+HSPLandroidx/compose/ui/node/LayoutNode$NoIntrinsicsMeasurePolicy;-><init>(Ljava/lang/String;)V
+HSPLandroidx/compose/ui/node/LayoutNode$UsageByParent;->$values()[Landroidx/compose/ui/node/LayoutNode$UsageByParent;
+HSPLandroidx/compose/ui/node/LayoutNode$UsageByParent;-><clinit>()V
+HSPLandroidx/compose/ui/node/LayoutNode$UsageByParent;-><init>(Ljava/lang/String;I)V
+HSPLandroidx/compose/ui/node/LayoutNode$UsageByParent;->values()[Landroidx/compose/ui/node/LayoutNode$UsageByParent;
+HSPLandroidx/compose/ui/node/LayoutNode$_foldedChildren$1;-><init>(Landroidx/compose/ui/node/LayoutNode;)V
+HSPLandroidx/compose/ui/node/LayoutNode$_foldedChildren$1;->invoke()Ljava/lang/Object;
+HSPLandroidx/compose/ui/node/LayoutNode$_foldedChildren$1;->invoke()V
+HSPLandroidx/compose/ui/node/LayoutNode;->$r8$lambda$7po1rmUuVs6tXeBa5BDq-nmH7XI(Landroidx/compose/ui/node/LayoutNode;Landroidx/compose/ui/node/LayoutNode;)I
+HSPLandroidx/compose/ui/node/LayoutNode;-><clinit>()V
+HSPLandroidx/compose/ui/node/LayoutNode;-><init>(ZI)V
+HSPLandroidx/compose/ui/node/LayoutNode;-><init>(ZIILkotlin/jvm/internal/DefaultConstructorMarker;)V
+HSPLandroidx/compose/ui/node/LayoutNode;->ZComparator$lambda$39(Landroidx/compose/ui/node/LayoutNode;Landroidx/compose/ui/node/LayoutNode;)I
+HSPLandroidx/compose/ui/node/LayoutNode;->access$getConstructor$cp()Lkotlin/jvm/functions/Function0;
+HSPLandroidx/compose/ui/node/LayoutNode;->access$setIgnoreRemeasureRequests$p(Landroidx/compose/ui/node/LayoutNode;Z)V
+HSPLandroidx/compose/ui/node/LayoutNode;->attach$ui_release(Landroidx/compose/ui/node/Owner;)V
+HSPLandroidx/compose/ui/node/LayoutNode;->checkChildrenPlaceOrderForUpdates$ui_release()V
+HSPLandroidx/compose/ui/node/LayoutNode;->clearPlaceOrder$ui_release()V
+HSPLandroidx/compose/ui/node/LayoutNode;->clearSubtreeIntrinsicsUsage$ui_release()V
+HSPLandroidx/compose/ui/node/LayoutNode;->clearSubtreePlacementIntrinsicsUsage()V
+HSPLandroidx/compose/ui/node/LayoutNode;->dispatchOnPositionedCallbacks$ui_release()V+]Landroidx/compose/ui/node/GlobalPositionAwareModifierNode;Landroidx/compose/ui/node/BackwardsCompatNode;]Landroidx/compose/ui/Modifier$Node;Landroidx/compose/ui/node/BackwardsCompatNode;]Landroidx/compose/ui/node/NodeChain;Landroidx/compose/ui/node/NodeChain;]Landroidx/compose/ui/node/LayoutNode;Landroidx/compose/ui/node/LayoutNode;
+HSPLandroidx/compose/ui/node/LayoutNode;->draw$ui_release(Landroidx/compose/ui/graphics/Canvas;)V
+HSPLandroidx/compose/ui/node/LayoutNode;->getCanMultiMeasure$ui_release()Z
+HSPLandroidx/compose/ui/node/LayoutNode;->getChildMeasurables$ui_release()Ljava/util/List;
+HSPLandroidx/compose/ui/node/LayoutNode;->getChildren$ui_release()Ljava/util/List;
+HSPLandroidx/compose/ui/node/LayoutNode;->getCoordinates()Landroidx/compose/ui/layout/LayoutCoordinates;
+HSPLandroidx/compose/ui/node/LayoutNode;->getDensity()Landroidx/compose/ui/unit/Density;
+HSPLandroidx/compose/ui/node/LayoutNode;->getDepth$ui_release()I
+HSPLandroidx/compose/ui/node/LayoutNode;->getFoldedChildren$ui_release()Ljava/util/List;
+HSPLandroidx/compose/ui/node/LayoutNode;->getHeight()I
+HSPLandroidx/compose/ui/node/LayoutNode;->getInnerCoordinator$ui_release()Landroidx/compose/ui/node/NodeCoordinator;
+HSPLandroidx/compose/ui/node/LayoutNode;->getInnerLayerCoordinator()Landroidx/compose/ui/node/NodeCoordinator;
+HSPLandroidx/compose/ui/node/LayoutNode;->getIntrinsicsUsageByParent$ui_release()Landroidx/compose/ui/node/LayoutNode$UsageByParent;
+HSPLandroidx/compose/ui/node/LayoutNode;->getLayoutDelegate$ui_release()Landroidx/compose/ui/node/LayoutNodeLayoutDelegate;
+HSPLandroidx/compose/ui/node/LayoutNode;->getLayoutDirection()Landroidx/compose/ui/unit/LayoutDirection;
+HSPLandroidx/compose/ui/node/LayoutNode;->getLayoutPending$ui_release()Z
+HSPLandroidx/compose/ui/node/LayoutNode;->getLayoutState$ui_release()Landroidx/compose/ui/node/LayoutNode$LayoutState;
+HSPLandroidx/compose/ui/node/LayoutNode;->getLookaheadLayoutPending$ui_release()Z
+HSPLandroidx/compose/ui/node/LayoutNode;->getLookaheadMeasurePending$ui_release()Z
+HSPLandroidx/compose/ui/node/LayoutNode;->getMDrawScope$ui_release()Landroidx/compose/ui/node/LayoutNodeDrawScope;
+HSPLandroidx/compose/ui/node/LayoutNode;->getMLookaheadScope$ui_release()Landroidx/compose/ui/layout/LookaheadScope;
+HSPLandroidx/compose/ui/node/LayoutNode;->getMeasurePassDelegate()Landroidx/compose/ui/node/LayoutNodeLayoutDelegate$MeasurePassDelegate;
+HSPLandroidx/compose/ui/node/LayoutNode;->getMeasurePending$ui_release()Z
+HSPLandroidx/compose/ui/node/LayoutNode;->getMeasurePolicy()Landroidx/compose/ui/layout/MeasurePolicy;
+HSPLandroidx/compose/ui/node/LayoutNode;->getMeasuredByParent$ui_release()Landroidx/compose/ui/node/LayoutNode$UsageByParent;
+HSPLandroidx/compose/ui/node/LayoutNode;->getNeedsOnPositionedDispatch$ui_release()Z
+HSPLandroidx/compose/ui/node/LayoutNode;->getNodes$ui_release()Landroidx/compose/ui/node/NodeChain;
+HSPLandroidx/compose/ui/node/LayoutNode;->getOuterCoordinator$ui_release()Landroidx/compose/ui/node/NodeCoordinator;
+HSPLandroidx/compose/ui/node/LayoutNode;->getOwner$ui_release()Landroidx/compose/ui/node/Owner;
+HSPLandroidx/compose/ui/node/LayoutNode;->getParent$ui_release()Landroidx/compose/ui/node/LayoutNode;+]Landroidx/compose/ui/node/LayoutNode;Landroidx/compose/ui/node/LayoutNode;
+HSPLandroidx/compose/ui/node/LayoutNode;->getSemanticsId()I
+HSPLandroidx/compose/ui/node/LayoutNode;->getSubcompositionsState$ui_release()Landroidx/compose/ui/layout/LayoutNodeSubcompositionsState;
+HSPLandroidx/compose/ui/node/LayoutNode;->getWidth()I
+HSPLandroidx/compose/ui/node/LayoutNode;->getZSortedChildren()Landroidx/compose/runtime/collection/MutableVector;
+HSPLandroidx/compose/ui/node/LayoutNode;->get_children$ui_release()Landroidx/compose/runtime/collection/MutableVector;
+HSPLandroidx/compose/ui/node/LayoutNode;->insertAt$ui_release(ILandroidx/compose/ui/node/LayoutNode;)V
+HSPLandroidx/compose/ui/node/LayoutNode;->invalidateLayer$ui_release()V
+HSPLandroidx/compose/ui/node/LayoutNode;->invalidateLayers$ui_release()V
+HSPLandroidx/compose/ui/node/LayoutNode;->invalidateMeasurements$ui_release()V
+HSPLandroidx/compose/ui/node/LayoutNode;->invalidateUnfoldedVirtualChildren()V
+HSPLandroidx/compose/ui/node/LayoutNode;->isAttached()Z
+HSPLandroidx/compose/ui/node/LayoutNode;->isPlaced()Z
+HSPLandroidx/compose/ui/node/LayoutNode;->isValid()Z
+HSPLandroidx/compose/ui/node/LayoutNode;->markLayoutPending$ui_release()V
+HSPLandroidx/compose/ui/node/LayoutNode;->markMeasurePending$ui_release()V
+HSPLandroidx/compose/ui/node/LayoutNode;->markNodeAndSubtreeAsPlaced()V
+HSPLandroidx/compose/ui/node/LayoutNode;->onDensityOrLayoutDirectionChanged()V
+HSPLandroidx/compose/ui/node/LayoutNode;->onNodePlaced$ui_release()V
+HSPLandroidx/compose/ui/node/LayoutNode;->onZSortedChildrenInvalidated$ui_release()V
+HSPLandroidx/compose/ui/node/LayoutNode;->place$ui_release(II)V
+HSPLandroidx/compose/ui/node/LayoutNode;->recreateUnfoldedChildrenIfDirty()V
+HSPLandroidx/compose/ui/node/LayoutNode;->remeasure-_Sx5XlM$ui_release$default(Landroidx/compose/ui/node/LayoutNode;Landroidx/compose/ui/unit/Constraints;ILjava/lang/Object;)Z
+HSPLandroidx/compose/ui/node/LayoutNode;->remeasure-_Sx5XlM$ui_release(Landroidx/compose/ui/unit/Constraints;)Z
+HSPLandroidx/compose/ui/node/LayoutNode;->replace$ui_release()V
+HSPLandroidx/compose/ui/node/LayoutNode;->requestRelayout$ui_release$default(Landroidx/compose/ui/node/LayoutNode;ZILjava/lang/Object;)V
+HSPLandroidx/compose/ui/node/LayoutNode;->requestRelayout$ui_release(Z)V
+HSPLandroidx/compose/ui/node/LayoutNode;->requestRemeasure$ui_release$default(Landroidx/compose/ui/node/LayoutNode;ZILjava/lang/Object;)V
+HSPLandroidx/compose/ui/node/LayoutNode;->requestRemeasure$ui_release(Z)V
+HSPLandroidx/compose/ui/node/LayoutNode;->resetSubtreeIntrinsicsUsage$ui_release()V
+HSPLandroidx/compose/ui/node/LayoutNode;->setCanMultiMeasure$ui_release(Z)V
+HSPLandroidx/compose/ui/node/LayoutNode;->setDensity(Landroidx/compose/ui/unit/Density;)V
+HSPLandroidx/compose/ui/node/LayoutNode;->setInnerLayerCoordinatorIsDirty$ui_release(Z)V
+HSPLandroidx/compose/ui/node/LayoutNode;->setLayoutDirection(Landroidx/compose/ui/unit/LayoutDirection;)V
+HSPLandroidx/compose/ui/node/LayoutNode;->setMLookaheadScope(Landroidx/compose/ui/layout/LookaheadScope;)V
+HSPLandroidx/compose/ui/node/LayoutNode;->setMeasurePolicy(Landroidx/compose/ui/layout/MeasurePolicy;)V
+HSPLandroidx/compose/ui/node/LayoutNode;->setMeasuredByParent$ui_release(Landroidx/compose/ui/node/LayoutNode$UsageByParent;)V
+HSPLandroidx/compose/ui/node/LayoutNode;->setModifier(Landroidx/compose/ui/Modifier;)V
+HSPLandroidx/compose/ui/node/LayoutNode;->setNeedsOnPositionedDispatch$ui_release(Z)V
+HSPLandroidx/compose/ui/node/LayoutNode;->setSubcompositionsState$ui_release(Landroidx/compose/ui/layout/LayoutNodeSubcompositionsState;)V
+HSPLandroidx/compose/ui/node/LayoutNode;->setViewConfiguration(Landroidx/compose/ui/platform/ViewConfiguration;)V
+HSPLandroidx/compose/ui/node/LayoutNode;->updateChildrenIfDirty$ui_release()V
+HSPLandroidx/compose/ui/node/LayoutNodeAlignmentLines;-><init>(Landroidx/compose/ui/node/AlignmentLinesOwner;)V
+HSPLandroidx/compose/ui/node/LayoutNodeDrawScope;-><init>(Landroidx/compose/ui/graphics/drawscope/CanvasDrawScope;)V
+HSPLandroidx/compose/ui/node/LayoutNodeDrawScope;-><init>(Landroidx/compose/ui/graphics/drawscope/CanvasDrawScope;ILkotlin/jvm/internal/DefaultConstructorMarker;)V
+HSPLandroidx/compose/ui/node/LayoutNodeDrawScope;->draw-x_KDEd0$ui_release(Landroidx/compose/ui/graphics/Canvas;JLandroidx/compose/ui/node/NodeCoordinator;Landroidx/compose/ui/node/DrawModifierNode;)V
+HSPLandroidx/compose/ui/node/LayoutNodeDrawScope;->drawContent()V
+HSPLandroidx/compose/ui/node/LayoutNodeDrawScope;->drawImage-AZ2fEMs(Landroidx/compose/ui/graphics/ImageBitmap;JJJJFLandroidx/compose/ui/graphics/drawscope/DrawStyle;Landroidx/compose/ui/graphics/ColorFilter;II)V
+HSPLandroidx/compose/ui/node/LayoutNodeDrawScope;->drawPath-LG529CI(Landroidx/compose/ui/graphics/Path;JFLandroidx/compose/ui/graphics/drawscope/DrawStyle;Landroidx/compose/ui/graphics/ColorFilter;I)V
+HSPLandroidx/compose/ui/node/LayoutNodeDrawScope;->drawRect-n-J9OG0(JJJFLandroidx/compose/ui/graphics/drawscope/DrawStyle;Landroidx/compose/ui/graphics/ColorFilter;I)V
+HSPLandroidx/compose/ui/node/LayoutNodeDrawScope;->drawRoundRect-u-Aw5IA(JJJJLandroidx/compose/ui/graphics/drawscope/DrawStyle;FLandroidx/compose/ui/graphics/ColorFilter;I)V
+HSPLandroidx/compose/ui/node/LayoutNodeDrawScope;->getDrawContext()Landroidx/compose/ui/graphics/drawscope/DrawContext;
+HSPLandroidx/compose/ui/node/LayoutNodeDrawScope;->getLayoutDirection()Landroidx/compose/ui/unit/LayoutDirection;
+HSPLandroidx/compose/ui/node/LayoutNodeDrawScope;->getSize-NH-jbRc()J
+HSPLandroidx/compose/ui/node/LayoutNodeDrawScope;->toPx-0680j_4(F)F
+HSPLandroidx/compose/ui/node/LayoutNodeDrawScopeKt;->access$nextDrawNode(Landroidx/compose/ui/node/DelegatableNode;)Landroidx/compose/ui/node/DrawModifierNode;
+HSPLandroidx/compose/ui/node/LayoutNodeDrawScopeKt;->nextDrawNode(Landroidx/compose/ui/node/DelegatableNode;)Landroidx/compose/ui/node/DrawModifierNode;
+HSPLandroidx/compose/ui/node/LayoutNodeKt;->requireOwner(Landroidx/compose/ui/node/LayoutNode;)Landroidx/compose/ui/node/Owner;
+HSPLandroidx/compose/ui/node/LayoutNodeLayoutDelegate$MeasurePassDelegate$WhenMappings;-><clinit>()V
+HSPLandroidx/compose/ui/node/LayoutNodeLayoutDelegate$MeasurePassDelegate$childMeasurables$1;-><clinit>()V
+HSPLandroidx/compose/ui/node/LayoutNodeLayoutDelegate$MeasurePassDelegate$childMeasurables$1;-><init>()V
+HSPLandroidx/compose/ui/node/LayoutNodeLayoutDelegate$MeasurePassDelegate$childMeasurables$1;->invoke(Landroidx/compose/ui/node/LayoutNode;)Landroidx/compose/ui/layout/Measurable;
+HSPLandroidx/compose/ui/node/LayoutNodeLayoutDelegate$MeasurePassDelegate$childMeasurables$1;->invoke(Ljava/lang/Object;)Ljava/lang/Object;
+HSPLandroidx/compose/ui/node/LayoutNodeLayoutDelegate$MeasurePassDelegate$layoutChildren$1$1$1;-><clinit>()V
+HSPLandroidx/compose/ui/node/LayoutNodeLayoutDelegate$MeasurePassDelegate$layoutChildren$1$1$1;-><init>()V
+HSPLandroidx/compose/ui/node/LayoutNodeLayoutDelegate$MeasurePassDelegate$layoutChildren$1$1$1;->invoke(Landroidx/compose/ui/node/AlignmentLinesOwner;)V
+HSPLandroidx/compose/ui/node/LayoutNodeLayoutDelegate$MeasurePassDelegate$layoutChildren$1$1$1;->invoke(Ljava/lang/Object;)Ljava/lang/Object;
+HSPLandroidx/compose/ui/node/LayoutNodeLayoutDelegate$MeasurePassDelegate$layoutChildren$1$1$2;-><clinit>()V
+HSPLandroidx/compose/ui/node/LayoutNodeLayoutDelegate$MeasurePassDelegate$layoutChildren$1$1$2;-><init>()V
+HSPLandroidx/compose/ui/node/LayoutNodeLayoutDelegate$MeasurePassDelegate$layoutChildren$1$1$2;->invoke(Landroidx/compose/ui/node/AlignmentLinesOwner;)V
+HSPLandroidx/compose/ui/node/LayoutNodeLayoutDelegate$MeasurePassDelegate$layoutChildren$1$1$2;->invoke(Ljava/lang/Object;)Ljava/lang/Object;
+HSPLandroidx/compose/ui/node/LayoutNodeLayoutDelegate$MeasurePassDelegate$layoutChildren$1$1;-><init>(Landroidx/compose/ui/node/LayoutNodeLayoutDelegate;Landroidx/compose/ui/node/LayoutNodeLayoutDelegate$MeasurePassDelegate;Landroidx/compose/ui/node/LayoutNode;)V
+HSPLandroidx/compose/ui/node/LayoutNodeLayoutDelegate$MeasurePassDelegate$layoutChildren$1$1;->invoke()Ljava/lang/Object;
+HSPLandroidx/compose/ui/node/LayoutNodeLayoutDelegate$MeasurePassDelegate$layoutChildren$1$1;->invoke()V
+HSPLandroidx/compose/ui/node/LayoutNodeLayoutDelegate$MeasurePassDelegate$placeOuterCoordinator$1;-><init>(Lkotlin/jvm/functions/Function1;Landroidx/compose/ui/node/LayoutNodeLayoutDelegate;JF)V
+HSPLandroidx/compose/ui/node/LayoutNodeLayoutDelegate$MeasurePassDelegate$placeOuterCoordinator$1;->invoke()Ljava/lang/Object;
+HSPLandroidx/compose/ui/node/LayoutNodeLayoutDelegate$MeasurePassDelegate$placeOuterCoordinator$1;->invoke()V
+HSPLandroidx/compose/ui/node/LayoutNodeLayoutDelegate$MeasurePassDelegate$remeasure$1;-><clinit>()V
+HSPLandroidx/compose/ui/node/LayoutNodeLayoutDelegate$MeasurePassDelegate$remeasure$1;-><init>()V
+HSPLandroidx/compose/ui/node/LayoutNodeLayoutDelegate$MeasurePassDelegate$remeasure$1;->invoke(Landroidx/compose/ui/node/AlignmentLinesOwner;)V
+HSPLandroidx/compose/ui/node/LayoutNodeLayoutDelegate$MeasurePassDelegate$remeasure$1;->invoke(Ljava/lang/Object;)Ljava/lang/Object;
+HSPLandroidx/compose/ui/node/LayoutNodeLayoutDelegate$MeasurePassDelegate;-><init>(Landroidx/compose/ui/node/LayoutNodeLayoutDelegate;)V
+HSPLandroidx/compose/ui/node/LayoutNodeLayoutDelegate$MeasurePassDelegate;->forEachChildAlignmentLinesOwner(Lkotlin/jvm/functions/Function1;)V
+HSPLandroidx/compose/ui/node/LayoutNodeLayoutDelegate$MeasurePassDelegate;->getAlignmentLines()Landroidx/compose/ui/node/AlignmentLines;
+HSPLandroidx/compose/ui/node/LayoutNodeLayoutDelegate$MeasurePassDelegate;->getChildMeasurables$ui_release()Ljava/util/List;
+HSPLandroidx/compose/ui/node/LayoutNodeLayoutDelegate$MeasurePassDelegate;->getInnerCoordinator()Landroidx/compose/ui/node/NodeCoordinator;
+HSPLandroidx/compose/ui/node/LayoutNodeLayoutDelegate$MeasurePassDelegate;->getLastConstraints-DWUhwKw()Landroidx/compose/ui/unit/Constraints;
+HSPLandroidx/compose/ui/node/LayoutNodeLayoutDelegate$MeasurePassDelegate;->getMeasuredWidth()I
+HSPLandroidx/compose/ui/node/LayoutNodeLayoutDelegate$MeasurePassDelegate;->getParentAlignmentLinesOwner()Landroidx/compose/ui/node/AlignmentLinesOwner;
+HSPLandroidx/compose/ui/node/LayoutNodeLayoutDelegate$MeasurePassDelegate;->getParentData()Ljava/lang/Object;
+HSPLandroidx/compose/ui/node/LayoutNodeLayoutDelegate$MeasurePassDelegate;->invalidateIntrinsicsParent(Z)V
+HSPLandroidx/compose/ui/node/LayoutNodeLayoutDelegate$MeasurePassDelegate;->layoutChildren()V
+HSPLandroidx/compose/ui/node/LayoutNodeLayoutDelegate$MeasurePassDelegate;->measure-BRTryo0(J)Landroidx/compose/ui/layout/Placeable;
+HSPLandroidx/compose/ui/node/LayoutNodeLayoutDelegate$MeasurePassDelegate;->notifyChildrenUsingCoordinatesWhilePlacing()V
+HSPLandroidx/compose/ui/node/LayoutNodeLayoutDelegate$MeasurePassDelegate;->onBeforeLayoutChildren()V
+HSPLandroidx/compose/ui/node/LayoutNodeLayoutDelegate$MeasurePassDelegate;->placeAt-f8xVGno(JFLkotlin/jvm/functions/Function1;)V
+HSPLandroidx/compose/ui/node/LayoutNodeLayoutDelegate$MeasurePassDelegate;->placeOuterCoordinator-f8xVGno(JFLkotlin/jvm/functions/Function1;)V
+HSPLandroidx/compose/ui/node/LayoutNodeLayoutDelegate$MeasurePassDelegate;->remeasure-BRTryo0(J)Z
+HSPLandroidx/compose/ui/node/LayoutNodeLayoutDelegate$MeasurePassDelegate;->replace()V
+HSPLandroidx/compose/ui/node/LayoutNodeLayoutDelegate$MeasurePassDelegate;->setChildMeasurablesDirty$ui_release(Z)V
+HSPLandroidx/compose/ui/node/LayoutNodeLayoutDelegate$MeasurePassDelegate;->trackMeasurementByParent(Landroidx/compose/ui/node/LayoutNode;)V
+HSPLandroidx/compose/ui/node/LayoutNodeLayoutDelegate$MeasurePassDelegate;->updateParentData()Z
+HSPLandroidx/compose/ui/node/LayoutNodeLayoutDelegate$performMeasure$2;-><init>(Landroidx/compose/ui/node/LayoutNodeLayoutDelegate;J)V
+HSPLandroidx/compose/ui/node/LayoutNodeLayoutDelegate$performMeasure$2;->invoke()Ljava/lang/Object;
+HSPLandroidx/compose/ui/node/LayoutNodeLayoutDelegate$performMeasure$2;->invoke()V
+HSPLandroidx/compose/ui/node/LayoutNodeLayoutDelegate;-><init>(Landroidx/compose/ui/node/LayoutNode;)V
+HSPLandroidx/compose/ui/node/LayoutNodeLayoutDelegate;->access$getLayoutNode$p(Landroidx/compose/ui/node/LayoutNodeLayoutDelegate;)Landroidx/compose/ui/node/LayoutNode;
+HSPLandroidx/compose/ui/node/LayoutNodeLayoutDelegate;->access$getLayoutPendingForAlignment$p(Landroidx/compose/ui/node/LayoutNodeLayoutDelegate;)Z
+HSPLandroidx/compose/ui/node/LayoutNodeLayoutDelegate;->access$isOutMostLookaheadRoot(Landroidx/compose/ui/node/LayoutNodeLayoutDelegate;Landroidx/compose/ui/node/LayoutNode;)Z
+HSPLandroidx/compose/ui/node/LayoutNodeLayoutDelegate;->access$performMeasure-BRTryo0(Landroidx/compose/ui/node/LayoutNodeLayoutDelegate;J)V
+HSPLandroidx/compose/ui/node/LayoutNodeLayoutDelegate;->access$setLayoutPending$p(Landroidx/compose/ui/node/LayoutNodeLayoutDelegate;Z)V
+HSPLandroidx/compose/ui/node/LayoutNodeLayoutDelegate;->access$setLayoutPendingForAlignment$p(Landroidx/compose/ui/node/LayoutNodeLayoutDelegate;Z)V
+HSPLandroidx/compose/ui/node/LayoutNodeLayoutDelegate;->access$setLayoutState$p(Landroidx/compose/ui/node/LayoutNodeLayoutDelegate;Landroidx/compose/ui/node/LayoutNode$LayoutState;)V
+HSPLandroidx/compose/ui/node/LayoutNodeLayoutDelegate;->getAlignmentLinesOwner$ui_release()Landroidx/compose/ui/node/AlignmentLinesOwner;
+HSPLandroidx/compose/ui/node/LayoutNodeLayoutDelegate;->getChildrenAccessingCoordinatesDuringPlacement()I
+HSPLandroidx/compose/ui/node/LayoutNodeLayoutDelegate;->getHeight$ui_release()I
+HSPLandroidx/compose/ui/node/LayoutNodeLayoutDelegate;->getLastConstraints-DWUhwKw()Landroidx/compose/ui/unit/Constraints;
+HSPLandroidx/compose/ui/node/LayoutNodeLayoutDelegate;->getLayoutPending$ui_release()Z
+HSPLandroidx/compose/ui/node/LayoutNodeLayoutDelegate;->getLayoutState$ui_release()Landroidx/compose/ui/node/LayoutNode$LayoutState;
+HSPLandroidx/compose/ui/node/LayoutNodeLayoutDelegate;->getLookaheadLayoutPending$ui_release()Z
+HSPLandroidx/compose/ui/node/LayoutNodeLayoutDelegate;->getLookaheadMeasurePending$ui_release()Z
+HSPLandroidx/compose/ui/node/LayoutNodeLayoutDelegate;->getMeasurePassDelegate$ui_release()Landroidx/compose/ui/node/LayoutNodeLayoutDelegate$MeasurePassDelegate;
+HSPLandroidx/compose/ui/node/LayoutNodeLayoutDelegate;->getMeasurePending$ui_release()Z
+HSPLandroidx/compose/ui/node/LayoutNodeLayoutDelegate;->getOuterCoordinator()Landroidx/compose/ui/node/NodeCoordinator;
+HSPLandroidx/compose/ui/node/LayoutNodeLayoutDelegate;->getWidth$ui_release()I
+HSPLandroidx/compose/ui/node/LayoutNodeLayoutDelegate;->isOutMostLookaheadRoot(Landroidx/compose/ui/node/LayoutNode;)Z
+HSPLandroidx/compose/ui/node/LayoutNodeLayoutDelegate;->markChildrenDirty()V
+HSPLandroidx/compose/ui/node/LayoutNodeLayoutDelegate;->markLayoutPending$ui_release()V
+HSPLandroidx/compose/ui/node/LayoutNodeLayoutDelegate;->markMeasurePending$ui_release()V
+HSPLandroidx/compose/ui/node/LayoutNodeLayoutDelegate;->performMeasure-BRTryo0(J)V
+HSPLandroidx/compose/ui/node/LayoutNodeLayoutDelegate;->setCoordinatesAccessedDuringPlacement(Z)V
+HSPLandroidx/compose/ui/node/LayoutNodeLayoutDelegate;->updateParentData()V
+HSPLandroidx/compose/ui/node/LayoutNodeLayoutDelegateKt;->access$updateChildMeasurables(Landroidx/compose/ui/node/LayoutNode;Landroidx/compose/runtime/collection/MutableVector;Lkotlin/jvm/functions/Function1;)V
+HSPLandroidx/compose/ui/node/LayoutNodeLayoutDelegateKt;->updateChildMeasurables(Landroidx/compose/ui/node/LayoutNode;Landroidx/compose/runtime/collection/MutableVector;Lkotlin/jvm/functions/Function1;)V
+HSPLandroidx/compose/ui/node/LookaheadCapablePlaceable;-><init>()V
+HSPLandroidx/compose/ui/node/LookaheadCapablePlaceable;->invalidateAlignmentLinesFromPositionChange(Landroidx/compose/ui/node/NodeCoordinator;)V
+HSPLandroidx/compose/ui/node/LookaheadCapablePlaceable;->isPlacingForAlignment$ui_release()Z
+HSPLandroidx/compose/ui/node/LookaheadCapablePlaceable;->isShallowPlacing$ui_release()Z
+HSPLandroidx/compose/ui/node/LookaheadCapablePlaceable;->setPlacingForAlignment$ui_release(Z)V
+HSPLandroidx/compose/ui/node/MeasureAndLayoutDelegate$WhenMappings;-><clinit>()V
+HSPLandroidx/compose/ui/node/MeasureAndLayoutDelegate;-><init>(Landroidx/compose/ui/node/LayoutNode;)V
+HSPLandroidx/compose/ui/node/MeasureAndLayoutDelegate;->access$getRoot$p(Landroidx/compose/ui/node/MeasureAndLayoutDelegate;)Landroidx/compose/ui/node/LayoutNode;
+HSPLandroidx/compose/ui/node/MeasureAndLayoutDelegate;->access$remeasureAndRelayoutIfNeeded(Landroidx/compose/ui/node/MeasureAndLayoutDelegate;Landroidx/compose/ui/node/LayoutNode;)Z
+HSPLandroidx/compose/ui/node/MeasureAndLayoutDelegate;->callOnLayoutCompletedListeners()V
+HSPLandroidx/compose/ui/node/MeasureAndLayoutDelegate;->dispatchOnPositionedCallbacks$default(Landroidx/compose/ui/node/MeasureAndLayoutDelegate;ZILjava/lang/Object;)V
+HSPLandroidx/compose/ui/node/MeasureAndLayoutDelegate;->dispatchOnPositionedCallbacks(Z)V
+HSPLandroidx/compose/ui/node/MeasureAndLayoutDelegate;->doRemeasure-sdFAvZA(Landroidx/compose/ui/node/LayoutNode;Landroidx/compose/ui/unit/Constraints;)Z
+HSPLandroidx/compose/ui/node/MeasureAndLayoutDelegate;->forceMeasureTheSubtree(Landroidx/compose/ui/node/LayoutNode;)V
+HSPLandroidx/compose/ui/node/MeasureAndLayoutDelegate;->getCanAffectParent(Landroidx/compose/ui/node/LayoutNode;)Z
+HSPLandroidx/compose/ui/node/MeasureAndLayoutDelegate;->getMeasureAffectsParent(Landroidx/compose/ui/node/LayoutNode;)Z
+HSPLandroidx/compose/ui/node/MeasureAndLayoutDelegate;->measureAndLayout(Lkotlin/jvm/functions/Function0;)Z
+HSPLandroidx/compose/ui/node/MeasureAndLayoutDelegate;->measureOnly()V
+HSPLandroidx/compose/ui/node/MeasureAndLayoutDelegate;->recurseRemeasure(Landroidx/compose/ui/node/LayoutNode;)V
+HSPLandroidx/compose/ui/node/MeasureAndLayoutDelegate;->registerOnLayoutCompletedListener(Landroidx/compose/ui/node/Owner$OnLayoutCompletedListener;)V
+HSPLandroidx/compose/ui/node/MeasureAndLayoutDelegate;->remeasureAndRelayoutIfNeeded(Landroidx/compose/ui/node/LayoutNode;)Z
+HSPLandroidx/compose/ui/node/MeasureAndLayoutDelegate;->remeasureOnly(Landroidx/compose/ui/node/LayoutNode;)V
+HSPLandroidx/compose/ui/node/MeasureAndLayoutDelegate;->requestRelayout(Landroidx/compose/ui/node/LayoutNode;Z)Z
+HSPLandroidx/compose/ui/node/MeasureAndLayoutDelegate;->requestRemeasure$default(Landroidx/compose/ui/node/MeasureAndLayoutDelegate;Landroidx/compose/ui/node/LayoutNode;ZILjava/lang/Object;)Z
+HSPLandroidx/compose/ui/node/MeasureAndLayoutDelegate;->requestRemeasure(Landroidx/compose/ui/node/LayoutNode;Z)Z
+HSPLandroidx/compose/ui/node/MeasureAndLayoutDelegate;->updateRootConstraints-BRTryo0(J)V
+HSPLandroidx/compose/ui/node/MutableVectorWithMutationTracking;-><init>(Landroidx/compose/runtime/collection/MutableVector;Lkotlin/jvm/functions/Function0;)V
+HSPLandroidx/compose/ui/node/MutableVectorWithMutationTracking;->add(ILjava/lang/Object;)V
+HSPLandroidx/compose/ui/node/MutableVectorWithMutationTracking;->asList()Ljava/util/List;
+HSPLandroidx/compose/ui/node/MutableVectorWithMutationTracking;->getVector()Landroidx/compose/runtime/collection/MutableVector;
+HSPLandroidx/compose/ui/node/MyersDiffKt;->access$swap([III)V
+HSPLandroidx/compose/ui/node/MyersDiffKt;->applyDiff(IILandroidx/compose/ui/node/IntStack;Landroidx/compose/ui/node/DiffCallback;)V
+HSPLandroidx/compose/ui/node/MyersDiffKt;->backward-4l5_RBY(IIIILandroidx/compose/ui/node/DiffCallback;[I[II[I)Z
+HSPLandroidx/compose/ui/node/MyersDiffKt;->calculateDiff(IILandroidx/compose/ui/node/DiffCallback;)Landroidx/compose/ui/node/IntStack;
+HSPLandroidx/compose/ui/node/MyersDiffKt;->executeDiff(IILandroidx/compose/ui/node/DiffCallback;)V
+HSPLandroidx/compose/ui/node/MyersDiffKt;->fillSnake(IIIIZ[I)V
+HSPLandroidx/compose/ui/node/MyersDiffKt;->forward-4l5_RBY(IIIILandroidx/compose/ui/node/DiffCallback;[I[II[I)Z
+HSPLandroidx/compose/ui/node/MyersDiffKt;->midPoint-q5eDKzI(IIIILandroidx/compose/ui/node/DiffCallback;[I[I[I)Z
+HSPLandroidx/compose/ui/node/MyersDiffKt;->swap([III)V
+HSPLandroidx/compose/ui/node/NodeChain$Differ;-><init>(Landroidx/compose/ui/node/NodeChain;Landroidx/compose/ui/Modifier$Node;ILandroidx/compose/runtime/collection/MutableVector;Landroidx/compose/runtime/collection/MutableVector;)V
+HSPLandroidx/compose/ui/node/NodeChain$Differ;->areItemsTheSame(II)Z
+HSPLandroidx/compose/ui/node/NodeChain$Differ;->insert(II)V
+HSPLandroidx/compose/ui/node/NodeChain$Differ;->same(II)V
+HSPLandroidx/compose/ui/node/NodeChain;-><init>(Landroidx/compose/ui/node/LayoutNode;)V
+HSPLandroidx/compose/ui/node/NodeChain;->access$createAndInsertNodeAsParent(Landroidx/compose/ui/node/NodeChain;Landroidx/compose/ui/Modifier$Element;Landroidx/compose/ui/Modifier$Node;)Landroidx/compose/ui/Modifier$Node;
+HSPLandroidx/compose/ui/node/NodeChain;->access$getAggregateChildKindSet(Landroidx/compose/ui/node/NodeChain;)I
+HSPLandroidx/compose/ui/node/NodeChain;->access$getLogger$p(Landroidx/compose/ui/node/NodeChain;)Landroidx/compose/ui/node/NodeChain$Logger;
+HSPLandroidx/compose/ui/node/NodeChain;->access$updateNodeAndReplaceIfNeeded(Landroidx/compose/ui/node/NodeChain;Landroidx/compose/ui/Modifier$Element;Landroidx/compose/ui/Modifier$Element;Landroidx/compose/ui/Modifier$Node;)Landroidx/compose/ui/Modifier$Node;
+HSPLandroidx/compose/ui/node/NodeChain;->attach(Z)V
+HSPLandroidx/compose/ui/node/NodeChain;->createAndInsertNodeAsParent(Landroidx/compose/ui/Modifier$Element;Landroidx/compose/ui/Modifier$Node;)Landroidx/compose/ui/Modifier$Node;
+HSPLandroidx/compose/ui/node/NodeChain;->getAggregateChildKindSet()I
+HSPLandroidx/compose/ui/node/NodeChain;->getDiffer(Landroidx/compose/ui/Modifier$Node;Landroidx/compose/runtime/collection/MutableVector;Landroidx/compose/runtime/collection/MutableVector;)Landroidx/compose/ui/node/NodeChain$Differ;
+HSPLandroidx/compose/ui/node/NodeChain;->getHead$ui_release()Landroidx/compose/ui/Modifier$Node;
+HSPLandroidx/compose/ui/node/NodeChain;->getInnerCoordinator$ui_release()Landroidx/compose/ui/node/InnerNodeCoordinator;
+HSPLandroidx/compose/ui/node/NodeChain;->getOuterCoordinator$ui_release()Landroidx/compose/ui/node/NodeCoordinator;
+HSPLandroidx/compose/ui/node/NodeChain;->getTail$ui_release()Landroidx/compose/ui/Modifier$Node;
+HSPLandroidx/compose/ui/node/NodeChain;->has-H91voCI$ui_release(I)Z
+HSPLandroidx/compose/ui/node/NodeChain;->insertParent(Landroidx/compose/ui/Modifier$Node;Landroidx/compose/ui/Modifier$Node;)Landroidx/compose/ui/Modifier$Node;
+HSPLandroidx/compose/ui/node/NodeChain;->padChain()V
+HSPLandroidx/compose/ui/node/NodeChain;->structuralUpdate(Landroidx/compose/runtime/collection/MutableVector;ILandroidx/compose/runtime/collection/MutableVector;ILandroidx/compose/ui/Modifier$Node;)V
+HSPLandroidx/compose/ui/node/NodeChain;->syncCoordinators()V
+HSPLandroidx/compose/ui/node/NodeChain;->trimChain()V
+HSPLandroidx/compose/ui/node/NodeChain;->updateFrom$ui_release(Landroidx/compose/ui/Modifier;)V
+HSPLandroidx/compose/ui/node/NodeChain;->updateNodeAndReplaceIfNeeded(Landroidx/compose/ui/Modifier$Element;Landroidx/compose/ui/Modifier$Element;Landroidx/compose/ui/Modifier$Node;)Landroidx/compose/ui/Modifier$Node;
+HSPLandroidx/compose/ui/node/NodeChainKt$SentinelHead$1;-><init>()V
+HSPLandroidx/compose/ui/node/NodeChainKt;-><clinit>()V
+HSPLandroidx/compose/ui/node/NodeChainKt;->access$fillVector(Landroidx/compose/ui/Modifier;Landroidx/compose/runtime/collection/MutableVector;)Landroidx/compose/runtime/collection/MutableVector;
+HSPLandroidx/compose/ui/node/NodeChainKt;->access$getSentinelHead$p()Landroidx/compose/ui/node/NodeChainKt$SentinelHead$1;
+HSPLandroidx/compose/ui/node/NodeChainKt;->fillVector(Landroidx/compose/ui/Modifier;Landroidx/compose/runtime/collection/MutableVector;)Landroidx/compose/runtime/collection/MutableVector;
+HSPLandroidx/compose/ui/node/NodeChainKt;->reuseActionForModifiers(Landroidx/compose/ui/Modifier$Element;Landroidx/compose/ui/Modifier$Element;)I
+HSPLandroidx/compose/ui/node/NodeCoordinator$Companion$PointerInputSource$1;-><init>()V
+HSPLandroidx/compose/ui/node/NodeCoordinator$Companion$SemanticsSource$1;-><init>()V
+HSPLandroidx/compose/ui/node/NodeCoordinator$Companion$onCommitAffectingLayer$1;-><clinit>()V
+HSPLandroidx/compose/ui/node/NodeCoordinator$Companion$onCommitAffectingLayer$1;-><init>()V
+HSPLandroidx/compose/ui/node/NodeCoordinator$Companion$onCommitAffectingLayer$1;->invoke(Landroidx/compose/ui/node/NodeCoordinator;)V
+HSPLandroidx/compose/ui/node/NodeCoordinator$Companion$onCommitAffectingLayer$1;->invoke(Ljava/lang/Object;)Ljava/lang/Object;
+HSPLandroidx/compose/ui/node/NodeCoordinator$Companion$onCommitAffectingLayerParams$1;-><clinit>()V
+HSPLandroidx/compose/ui/node/NodeCoordinator$Companion$onCommitAffectingLayerParams$1;-><init>()V
+HSPLandroidx/compose/ui/node/NodeCoordinator$Companion;-><init>()V
+HSPLandroidx/compose/ui/node/NodeCoordinator$Companion;-><init>(Lkotlin/jvm/internal/DefaultConstructorMarker;)V
+HSPLandroidx/compose/ui/node/NodeCoordinator$invalidateParentLayer$1;-><init>(Landroidx/compose/ui/node/NodeCoordinator;)V
+HSPLandroidx/compose/ui/node/NodeCoordinator$invalidateParentLayer$1;->invoke()Ljava/lang/Object;
+HSPLandroidx/compose/ui/node/NodeCoordinator$invalidateParentLayer$1;->invoke()V
+HSPLandroidx/compose/ui/node/NodeCoordinator$invoke$1;-><init>(Landroidx/compose/ui/node/NodeCoordinator;Landroidx/compose/ui/graphics/Canvas;)V
+HSPLandroidx/compose/ui/node/NodeCoordinator$invoke$1;->invoke()Ljava/lang/Object;
+HSPLandroidx/compose/ui/node/NodeCoordinator$invoke$1;->invoke()V
+HSPLandroidx/compose/ui/node/NodeCoordinator$updateLayerParameters$1;-><init>(Lkotlin/jvm/functions/Function1;)V
+HSPLandroidx/compose/ui/node/NodeCoordinator$updateLayerParameters$1;->invoke()Ljava/lang/Object;
+HSPLandroidx/compose/ui/node/NodeCoordinator$updateLayerParameters$1;->invoke()V
+HSPLandroidx/compose/ui/node/NodeCoordinator;-><clinit>()V
+HSPLandroidx/compose/ui/node/NodeCoordinator;-><init>(Landroidx/compose/ui/node/LayoutNode;)V
+HSPLandroidx/compose/ui/node/NodeCoordinator;->access$drawContainedDrawModifiers(Landroidx/compose/ui/node/NodeCoordinator;Landroidx/compose/ui/graphics/Canvas;)V
+HSPLandroidx/compose/ui/node/NodeCoordinator;->access$getGraphicsLayerScope$cp()Landroidx/compose/ui/graphics/ReusableGraphicsLayerScope;
+HSPLandroidx/compose/ui/node/NodeCoordinator;->access$getMeasuredSize-YbymL2g(Landroidx/compose/ui/node/NodeCoordinator;)J
+HSPLandroidx/compose/ui/node/NodeCoordinator;->access$headNode(Landroidx/compose/ui/node/NodeCoordinator;Z)Landroidx/compose/ui/Modifier$Node;
+HSPLandroidx/compose/ui/node/NodeCoordinator;->access$setMeasurementConstraints-BRTryo0(Landroidx/compose/ui/node/NodeCoordinator;J)V
+HSPLandroidx/compose/ui/node/NodeCoordinator;->attach()V
+HSPLandroidx/compose/ui/node/NodeCoordinator;->draw(Landroidx/compose/ui/graphics/Canvas;)V
+HSPLandroidx/compose/ui/node/NodeCoordinator;->drawContainedDrawModifiers(Landroidx/compose/ui/graphics/Canvas;)V
+HSPLandroidx/compose/ui/node/NodeCoordinator;->getAlignmentLinesOwner()Landroidx/compose/ui/node/AlignmentLinesOwner;
+HSPLandroidx/compose/ui/node/NodeCoordinator;->getCoordinates()Landroidx/compose/ui/layout/LayoutCoordinates;
+HSPLandroidx/compose/ui/node/NodeCoordinator;->getDensity()F
+HSPLandroidx/compose/ui/node/NodeCoordinator;->getFontScale()F
+HSPLandroidx/compose/ui/node/NodeCoordinator;->getLastLayerDrawingWasSkipped$ui_release()Z
+HSPLandroidx/compose/ui/node/NodeCoordinator;->getLayer()Landroidx/compose/ui/node/OwnedLayer;
+HSPLandroidx/compose/ui/node/NodeCoordinator;->getLayoutDirection()Landroidx/compose/ui/unit/LayoutDirection;
+HSPLandroidx/compose/ui/node/NodeCoordinator;->getLayoutNode()Landroidx/compose/ui/node/LayoutNode;
+HSPLandroidx/compose/ui/node/NodeCoordinator;->getLookaheadDelegate$ui_release()Landroidx/compose/ui/node/LookaheadDelegate;
+HSPLandroidx/compose/ui/node/NodeCoordinator;->getMeasureResult$ui_release()Landroidx/compose/ui/layout/MeasureResult;
+HSPLandroidx/compose/ui/node/NodeCoordinator;->getParent()Landroidx/compose/ui/node/LookaheadCapablePlaceable;
+HSPLandroidx/compose/ui/node/NodeCoordinator;->getParentData()Ljava/lang/Object;
+HSPLandroidx/compose/ui/node/NodeCoordinator;->getPosition-nOcc-ac()J
+HSPLandroidx/compose/ui/node/NodeCoordinator;->getSize-YbymL2g()J
+HSPLandroidx/compose/ui/node/NodeCoordinator;->getSnapshotObserver()Landroidx/compose/ui/node/OwnerSnapshotObserver;
+HSPLandroidx/compose/ui/node/NodeCoordinator;->getWrapped$ui_release()Landroidx/compose/ui/node/NodeCoordinator;
+HSPLandroidx/compose/ui/node/NodeCoordinator;->getWrappedBy$ui_release()Landroidx/compose/ui/node/NodeCoordinator;
+HSPLandroidx/compose/ui/node/NodeCoordinator;->getZIndex()F
+HSPLandroidx/compose/ui/node/NodeCoordinator;->hasNode-H91voCI(I)Z
+HSPLandroidx/compose/ui/node/NodeCoordinator;->headNode(Z)Landroidx/compose/ui/Modifier$Node;
+HSPLandroidx/compose/ui/node/NodeCoordinator;->invalidateLayer()V+]Landroidx/compose/ui/node/NodeCoordinator;Landroidx/compose/ui/node/InnerNodeCoordinator;,Landroidx/compose/ui/node/LayoutModifierNodeCoordinator;]Landroidx/compose/ui/node/OwnedLayer;Landroidx/compose/ui/platform/RenderNodeLayer;
+HSPLandroidx/compose/ui/node/NodeCoordinator;->invoke(Landroidx/compose/ui/graphics/Canvas;)V
+HSPLandroidx/compose/ui/node/NodeCoordinator;->invoke(Ljava/lang/Object;)Ljava/lang/Object;
+HSPLandroidx/compose/ui/node/NodeCoordinator;->isAttached()Z
+HSPLandroidx/compose/ui/node/NodeCoordinator;->onLayerBlockUpdated(Lkotlin/jvm/functions/Function1;)V
+HSPLandroidx/compose/ui/node/NodeCoordinator;->onLayoutModifierNodeChanged()V
+HSPLandroidx/compose/ui/node/NodeCoordinator;->onMeasureResultChanged(II)V
+HSPLandroidx/compose/ui/node/NodeCoordinator;->onMeasured()V
+HSPLandroidx/compose/ui/node/NodeCoordinator;->onPlaced()V
+HSPLandroidx/compose/ui/node/NodeCoordinator;->placeAt-f8xVGno(JFLkotlin/jvm/functions/Function1;)V
+HSPLandroidx/compose/ui/node/NodeCoordinator;->setMeasureResult$ui_release(Landroidx/compose/ui/layout/MeasureResult;)V
+HSPLandroidx/compose/ui/node/NodeCoordinator;->setPosition--gyyYBs(J)V
+HSPLandroidx/compose/ui/node/NodeCoordinator;->setWrapped$ui_release(Landroidx/compose/ui/node/NodeCoordinator;)V
+HSPLandroidx/compose/ui/node/NodeCoordinator;->setWrappedBy$ui_release(Landroidx/compose/ui/node/NodeCoordinator;)V
+HSPLandroidx/compose/ui/node/NodeCoordinator;->updateLayerParameters()V
+HSPLandroidx/compose/ui/node/NodeCoordinator;->updateLookaheadScope$ui_release(Landroidx/compose/ui/layout/LookaheadScope;)V
+HSPLandroidx/compose/ui/node/NodeKind;->constructor-impl(I)I
+HSPLandroidx/compose/ui/node/NodeKindKt;->autoInvalidateInsertedNode(Landroidx/compose/ui/Modifier$Node;)V
+HSPLandroidx/compose/ui/node/NodeKindKt;->autoInvalidateNode(Landroidx/compose/ui/Modifier$Node;I)V
+HSPLandroidx/compose/ui/node/NodeKindKt;->autoInvalidateUpdatedNode(Landroidx/compose/ui/Modifier$Node;)V
+HSPLandroidx/compose/ui/node/NodeKindKt;->calculateNodeKindSetFrom(Landroidx/compose/ui/Modifier$Element;)I
+HSPLandroidx/compose/ui/node/NodeKindKt;->getIncludeSelfInTraversal-H91voCI(I)Z
+HSPLandroidx/compose/ui/node/OnPositionedDispatcher$Companion$DepthComparator;-><clinit>()V
+HSPLandroidx/compose/ui/node/OnPositionedDispatcher$Companion$DepthComparator;-><init>()V
+HSPLandroidx/compose/ui/node/OnPositionedDispatcher$Companion$DepthComparator;->compare(Landroidx/compose/ui/node/LayoutNode;Landroidx/compose/ui/node/LayoutNode;)I
+HSPLandroidx/compose/ui/node/OnPositionedDispatcher$Companion$DepthComparator;->compare(Ljava/lang/Object;Ljava/lang/Object;)I
+HSPLandroidx/compose/ui/node/OnPositionedDispatcher$Companion;-><init>()V
+HSPLandroidx/compose/ui/node/OnPositionedDispatcher$Companion;-><init>(Lkotlin/jvm/internal/DefaultConstructorMarker;)V
+HSPLandroidx/compose/ui/node/OnPositionedDispatcher;-><clinit>()V
+HSPLandroidx/compose/ui/node/OnPositionedDispatcher;-><init>()V
+HSPLandroidx/compose/ui/node/OnPositionedDispatcher;->dispatch()V
+HSPLandroidx/compose/ui/node/OnPositionedDispatcher;->dispatchHierarchy(Landroidx/compose/ui/node/LayoutNode;)V
+HSPLandroidx/compose/ui/node/OnPositionedDispatcher;->onNodePositioned(Landroidx/compose/ui/node/LayoutNode;)V
+HSPLandroidx/compose/ui/node/Owner$Companion;-><clinit>()V
+HSPLandroidx/compose/ui/node/Owner$Companion;-><init>()V
+HSPLandroidx/compose/ui/node/Owner$Companion;->getEnableExtraAssertions()Z
+HSPLandroidx/compose/ui/node/Owner;-><clinit>()V
+HSPLandroidx/compose/ui/node/Owner;->measureAndLayout$default(Landroidx/compose/ui/node/Owner;ZILjava/lang/Object;)V
+HSPLandroidx/compose/ui/node/Owner;->onRequestMeasure$default(Landroidx/compose/ui/node/Owner;Landroidx/compose/ui/node/LayoutNode;ZZILjava/lang/Object;)V
+HSPLandroidx/compose/ui/node/Owner;->onRequestRelayout$default(Landroidx/compose/ui/node/Owner;Landroidx/compose/ui/node/LayoutNode;ZZILjava/lang/Object;)V
+HSPLandroidx/compose/ui/node/OwnerSnapshotObserver$onCommitAffectingLayout$1;-><clinit>()V
+HSPLandroidx/compose/ui/node/OwnerSnapshotObserver$onCommitAffectingLayout$1;-><init>()V
+HSPLandroidx/compose/ui/node/OwnerSnapshotObserver$onCommitAffectingLayoutModifier$1;-><clinit>()V
+HSPLandroidx/compose/ui/node/OwnerSnapshotObserver$onCommitAffectingLayoutModifier$1;-><init>()V
+HSPLandroidx/compose/ui/node/OwnerSnapshotObserver$onCommitAffectingLayoutModifier$1;->invoke(Landroidx/compose/ui/node/LayoutNode;)V
+HSPLandroidx/compose/ui/node/OwnerSnapshotObserver$onCommitAffectingLayoutModifier$1;->invoke(Ljava/lang/Object;)Ljava/lang/Object;
+HSPLandroidx/compose/ui/node/OwnerSnapshotObserver$onCommitAffectingLayoutModifierInLookahead$1;-><clinit>()V
+HSPLandroidx/compose/ui/node/OwnerSnapshotObserver$onCommitAffectingLayoutModifierInLookahead$1;-><init>()V
+HSPLandroidx/compose/ui/node/OwnerSnapshotObserver$onCommitAffectingLookaheadLayout$1;-><clinit>()V
+HSPLandroidx/compose/ui/node/OwnerSnapshotObserver$onCommitAffectingLookaheadLayout$1;-><init>()V
+HSPLandroidx/compose/ui/node/OwnerSnapshotObserver$onCommitAffectingLookaheadMeasure$1;-><clinit>()V
+HSPLandroidx/compose/ui/node/OwnerSnapshotObserver$onCommitAffectingLookaheadMeasure$1;-><init>()V
+HSPLandroidx/compose/ui/node/OwnerSnapshotObserver$onCommitAffectingMeasure$1;-><clinit>()V
+HSPLandroidx/compose/ui/node/OwnerSnapshotObserver$onCommitAffectingMeasure$1;-><init>()V
+HSPLandroidx/compose/ui/node/OwnerSnapshotObserver$onCommitAffectingMeasure$1;->invoke(Landroidx/compose/ui/node/LayoutNode;)V
+HSPLandroidx/compose/ui/node/OwnerSnapshotObserver$onCommitAffectingMeasure$1;->invoke(Ljava/lang/Object;)Ljava/lang/Object;
+HSPLandroidx/compose/ui/node/OwnerSnapshotObserver;-><init>(Lkotlin/jvm/functions/Function1;)V
+HSPLandroidx/compose/ui/node/OwnerSnapshotObserver;->observeLayoutModifierSnapshotReads$ui_release(Landroidx/compose/ui/node/LayoutNode;ZLkotlin/jvm/functions/Function0;)V
+HSPLandroidx/compose/ui/node/OwnerSnapshotObserver;->observeLayoutSnapshotReads$ui_release(Landroidx/compose/ui/node/LayoutNode;ZLkotlin/jvm/functions/Function0;)V
+HSPLandroidx/compose/ui/node/OwnerSnapshotObserver;->observeMeasureSnapshotReads$ui_release(Landroidx/compose/ui/node/LayoutNode;ZLkotlin/jvm/functions/Function0;)V
+HSPLandroidx/compose/ui/node/OwnerSnapshotObserver;->observeReads$ui_release(Landroidx/compose/ui/node/OwnerScope;Lkotlin/jvm/functions/Function1;Lkotlin/jvm/functions/Function0;)V
+HSPLandroidx/compose/ui/node/OwnerSnapshotObserver;->startObserving$ui_release()V
+HSPLandroidx/compose/ui/node/SemanticsModifierNodeKt;->collapsedSemanticsConfiguration(Landroidx/compose/ui/node/SemanticsModifierNode;)Landroidx/compose/ui/semantics/SemanticsConfiguration;
+HSPLandroidx/compose/ui/node/SemanticsModifierNodeKt;->invalidateSemantics(Landroidx/compose/ui/node/SemanticsModifierNode;)V
+HSPLandroidx/compose/ui/node/Snake;->addDiagonalToStack-impl([ILandroidx/compose/ui/node/IntStack;)V
+HSPLandroidx/compose/ui/node/Snake;->constructor-impl([I)[I
+HSPLandroidx/compose/ui/node/Snake;->getDiagonalSize-impl([I)I
+HSPLandroidx/compose/ui/node/Snake;->getEndX-impl([I)I
+HSPLandroidx/compose/ui/node/Snake;->getEndY-impl([I)I
+HSPLandroidx/compose/ui/node/Snake;->getHasAdditionOrRemoval-impl([I)Z
+HSPLandroidx/compose/ui/node/Snake;->getReverse-impl([I)Z
+HSPLandroidx/compose/ui/node/Snake;->getStartX-impl([I)I
+HSPLandroidx/compose/ui/node/Snake;->getStartY-impl([I)I
+HSPLandroidx/compose/ui/node/Snake;->isAddition-impl([I)Z
+HSPLandroidx/compose/ui/node/TreeSet;-><init>(Ljava/util/Comparator;)V
+HSPLandroidx/compose/ui/node/UiApplier;-><init>(Landroidx/compose/ui/node/LayoutNode;)V
+HSPLandroidx/compose/ui/node/UiApplier;->insertBottomUp(ILandroidx/compose/ui/node/LayoutNode;)V
+HSPLandroidx/compose/ui/node/UiApplier;->insertBottomUp(ILjava/lang/Object;)V
+HSPLandroidx/compose/ui/node/UiApplier;->insertTopDown(ILandroidx/compose/ui/node/LayoutNode;)V
+HSPLandroidx/compose/ui/node/UiApplier;->insertTopDown(ILjava/lang/Object;)V
+HSPLandroidx/compose/ui/node/UiApplier;->onEndChanges()V
+HSPLandroidx/compose/ui/platform/AbstractComposeView$ensureCompositionCreated$1;-><init>(Landroidx/compose/ui/platform/AbstractComposeView;)V
+HSPLandroidx/compose/ui/platform/AbstractComposeView$ensureCompositionCreated$1;->invoke(Landroidx/compose/runtime/Composer;I)V
+HSPLandroidx/compose/ui/platform/AbstractComposeView$ensureCompositionCreated$1;->invoke(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;
+HSPLandroidx/compose/ui/platform/AbstractComposeView;-><clinit>()V
+HSPLandroidx/compose/ui/platform/AbstractComposeView;-><init>(Landroid/content/Context;Landroid/util/AttributeSet;I)V
+HSPLandroidx/compose/ui/platform/AbstractComposeView;->addView(Landroid/view/View;ILandroid/view/ViewGroup$LayoutParams;)V
+HSPLandroidx/compose/ui/platform/AbstractComposeView;->addView(Landroid/view/View;Landroid/view/ViewGroup$LayoutParams;)V
+HSPLandroidx/compose/ui/platform/AbstractComposeView;->cacheIfAlive(Landroidx/compose/runtime/CompositionContext;)Landroidx/compose/runtime/CompositionContext;
+HSPLandroidx/compose/ui/platform/AbstractComposeView;->checkAddView()V
+HSPLandroidx/compose/ui/platform/AbstractComposeView;->ensureCompositionCreated()V
+HSPLandroidx/compose/ui/platform/AbstractComposeView;->internalOnLayout$ui_release(ZIIII)V
+HSPLandroidx/compose/ui/platform/AbstractComposeView;->internalOnMeasure$ui_release(II)V
+HSPLandroidx/compose/ui/platform/AbstractComposeView;->isAlive(Landroidx/compose/runtime/CompositionContext;)Z
+HSPLandroidx/compose/ui/platform/AbstractComposeView;->onAttachedToWindow()V
+HSPLandroidx/compose/ui/platform/AbstractComposeView;->onLayout(ZIIII)V
+HSPLandroidx/compose/ui/platform/AbstractComposeView;->onMeasure(II)V
+HSPLandroidx/compose/ui/platform/AbstractComposeView;->onRtlPropertiesChanged(I)V
+HSPLandroidx/compose/ui/platform/AbstractComposeView;->resolveParentCompositionContext()Landroidx/compose/runtime/CompositionContext;
+HSPLandroidx/compose/ui/platform/AbstractComposeView;->setParentCompositionContext(Landroidx/compose/runtime/CompositionContext;)V
+HSPLandroidx/compose/ui/platform/AbstractComposeView;->setParentContext(Landroidx/compose/runtime/CompositionContext;)V
+HSPLandroidx/compose/ui/platform/AbstractComposeView;->setPreviousAttachedWindowToken(Landroid/os/IBinder;)V
+HSPLandroidx/compose/ui/platform/AndroidAccessibilityManager$Companion;-><init>()V
+HSPLandroidx/compose/ui/platform/AndroidAccessibilityManager$Companion;-><init>(Lkotlin/jvm/internal/DefaultConstructorMarker;)V
+HSPLandroidx/compose/ui/platform/AndroidAccessibilityManager;-><clinit>()V
+HSPLandroidx/compose/ui/platform/AndroidAccessibilityManager;-><init>(Landroid/content/Context;)V
+HSPLandroidx/compose/ui/platform/AndroidClipboardManager;-><init>(Landroid/content/ClipboardManager;)V
+HSPLandroidx/compose/ui/platform/AndroidClipboardManager;-><init>(Landroid/content/Context;)V
+HSPLandroidx/compose/ui/platform/AndroidComposeView$$ExternalSyntheticLambda0;-><init>(Landroidx/compose/ui/platform/AndroidComposeView;)V
+HSPLandroidx/compose/ui/platform/AndroidComposeView$$ExternalSyntheticLambda0;->onGlobalLayout()V
+HSPLandroidx/compose/ui/platform/AndroidComposeView$$ExternalSyntheticLambda1;-><init>(Landroidx/compose/ui/platform/AndroidComposeView;)V
+HSPLandroidx/compose/ui/platform/AndroidComposeView$$ExternalSyntheticLambda2;-><init>(Landroidx/compose/ui/platform/AndroidComposeView;)V
+HSPLandroidx/compose/ui/platform/AndroidComposeView$$ExternalSyntheticLambda2;->onTouchModeChanged(Z)V
+HSPLandroidx/compose/ui/platform/AndroidComposeView$$ExternalSyntheticLambda3;-><init>(Landroidx/compose/ui/platform/AndroidComposeView;)V
+HSPLandroidx/compose/ui/platform/AndroidComposeView$Companion;-><init>()V
+HSPLandroidx/compose/ui/platform/AndroidComposeView$Companion;-><init>(Lkotlin/jvm/internal/DefaultConstructorMarker;)V
+HSPLandroidx/compose/ui/platform/AndroidComposeView$Companion;->access$getIsShowingLayoutBounds(Landroidx/compose/ui/platform/AndroidComposeView$Companion;)Z
+HSPLandroidx/compose/ui/platform/AndroidComposeView$Companion;->getIsShowingLayoutBounds()Z
+HSPLandroidx/compose/ui/platform/AndroidComposeView$ViewTreeOwners;-><clinit>()V
+HSPLandroidx/compose/ui/platform/AndroidComposeView$ViewTreeOwners;-><init>(Landroidx/lifecycle/LifecycleOwner;Landroidx/savedstate/SavedStateRegistryOwner;)V
+HSPLandroidx/compose/ui/platform/AndroidComposeView$ViewTreeOwners;->getLifecycleOwner()Landroidx/lifecycle/LifecycleOwner;
+HSPLandroidx/compose/ui/platform/AndroidComposeView$ViewTreeOwners;->getSavedStateRegistryOwner()Landroidx/savedstate/SavedStateRegistryOwner;
+HSPLandroidx/compose/ui/platform/AndroidComposeView$_inputModeManager$1;-><init>(Landroidx/compose/ui/platform/AndroidComposeView;)V
+HSPLandroidx/compose/ui/platform/AndroidComposeView$configurationChangeObserver$1;-><clinit>()V
+HSPLandroidx/compose/ui/platform/AndroidComposeView$configurationChangeObserver$1;-><init>()V
+HSPLandroidx/compose/ui/platform/AndroidComposeView$keyInputModifier$1;-><init>(Landroidx/compose/ui/platform/AndroidComposeView;)V
+HSPLandroidx/compose/ui/platform/AndroidComposeView$pointerIconService$1;-><init>(Landroidx/compose/ui/platform/AndroidComposeView;)V
+HSPLandroidx/compose/ui/platform/AndroidComposeView$resendMotionEventOnLayout$1;-><init>(Landroidx/compose/ui/platform/AndroidComposeView;)V
+HSPLandroidx/compose/ui/platform/AndroidComposeView$resendMotionEventOnLayout$1;->invoke()Ljava/lang/Object;
+HSPLandroidx/compose/ui/platform/AndroidComposeView$resendMotionEventOnLayout$1;->invoke()V
+HSPLandroidx/compose/ui/platform/AndroidComposeView$resendMotionEventRunnable$1;-><init>(Landroidx/compose/ui/platform/AndroidComposeView;)V
+HSPLandroidx/compose/ui/platform/AndroidComposeView$rotaryInputModifier$1;-><clinit>()V
+HSPLandroidx/compose/ui/platform/AndroidComposeView$rotaryInputModifier$1;-><init>()V
+HSPLandroidx/compose/ui/platform/AndroidComposeView$scrollContainerInfo$1$value$1;-><init>(Landroidx/compose/ui/platform/AndroidComposeView;)V
+HSPLandroidx/compose/ui/platform/AndroidComposeView$scrollContainerInfo$1;-><init>(Landroidx/compose/ui/platform/AndroidComposeView;)V
+HSPLandroidx/compose/ui/platform/AndroidComposeView$scrollContainerInfo$1;->getKey()Landroidx/compose/ui/modifier/ProvidableModifierLocal;
+HSPLandroidx/compose/ui/platform/AndroidComposeView$scrollContainerInfo$1;->getValue()Landroidx/compose/ui/platform/AndroidComposeView$scrollContainerInfo$1$value$1;
+HSPLandroidx/compose/ui/platform/AndroidComposeView$scrollContainerInfo$1;->getValue()Ljava/lang/Object;
+HSPLandroidx/compose/ui/platform/AndroidComposeView$semanticsModifier$1;-><clinit>()V
+HSPLandroidx/compose/ui/platform/AndroidComposeView$semanticsModifier$1;-><init>()V
+HSPLandroidx/compose/ui/platform/AndroidComposeView$semanticsModifier$1;->invoke(Landroidx/compose/ui/semantics/SemanticsPropertyReceiver;)V
+HSPLandroidx/compose/ui/platform/AndroidComposeView$semanticsModifier$1;->invoke(Ljava/lang/Object;)Ljava/lang/Object;
+HSPLandroidx/compose/ui/platform/AndroidComposeView$snapshotObserver$1;-><init>(Landroidx/compose/ui/platform/AndroidComposeView;)V
+HSPLandroidx/compose/ui/platform/AndroidComposeView$snapshotObserver$1;->invoke(Ljava/lang/Object;)Ljava/lang/Object;
+HSPLandroidx/compose/ui/platform/AndroidComposeView$snapshotObserver$1;->invoke(Lkotlin/jvm/functions/Function0;)V
+HSPLandroidx/compose/ui/platform/AndroidComposeView;->$r8$lambda$6rnsioIDxAVR319ScBkOteeoeiE(Landroidx/compose/ui/platform/AndroidComposeView;)V
+HSPLandroidx/compose/ui/platform/AndroidComposeView;->$r8$lambda$TvhWqMihl4JwF42Odovn0ewO6fk(Landroidx/compose/ui/platform/AndroidComposeView;Z)V
+HSPLandroidx/compose/ui/platform/AndroidComposeView;-><clinit>()V
+HSPLandroidx/compose/ui/platform/AndroidComposeView;-><init>(Landroid/content/Context;)V
+HSPLandroidx/compose/ui/platform/AndroidComposeView;->access$getGetBooleanMethod$cp()Ljava/lang/reflect/Method;
+HSPLandroidx/compose/ui/platform/AndroidComposeView;->access$getPreviousMotionEvent$p(Landroidx/compose/ui/platform/AndroidComposeView;)Landroid/view/MotionEvent;
+HSPLandroidx/compose/ui/platform/AndroidComposeView;->access$getSystemPropertiesClass$cp()Ljava/lang/Class;
+HSPLandroidx/compose/ui/platform/AndroidComposeView;->access$setGetBooleanMethod$cp(Ljava/lang/reflect/Method;)V
+HSPLandroidx/compose/ui/platform/AndroidComposeView;->access$setSystemPropertiesClass$cp(Ljava/lang/Class;)V
+HSPLandroidx/compose/ui/platform/AndroidComposeView;->autofillSupported()Z
+HSPLandroidx/compose/ui/platform/AndroidComposeView;->boundsUpdatesEventLoop(Lkotlin/coroutines/Continuation;)Ljava/lang/Object;
+HSPLandroidx/compose/ui/platform/AndroidComposeView;->convertMeasureSpec(I)Lkotlin/Pair;
+HSPLandroidx/compose/ui/platform/AndroidComposeView;->createLayer(Lkotlin/jvm/functions/Function1;Lkotlin/jvm/functions/Function0;)Landroidx/compose/ui/node/OwnedLayer;
+HSPLandroidx/compose/ui/platform/AndroidComposeView;->dispatchDraw(Landroid/graphics/Canvas;)V
+HSPLandroidx/compose/ui/platform/AndroidComposeView;->forceMeasureTheSubtree(Landroidx/compose/ui/node/LayoutNode;)V
+HSPLandroidx/compose/ui/platform/AndroidComposeView;->getAccessibilityManager()Landroidx/compose/ui/platform/AccessibilityManager;
+HSPLandroidx/compose/ui/platform/AndroidComposeView;->getAccessibilityManager()Landroidx/compose/ui/platform/AndroidAccessibilityManager;
+HSPLandroidx/compose/ui/platform/AndroidComposeView;->getAutofill()Landroidx/compose/ui/autofill/Autofill;
+HSPLandroidx/compose/ui/platform/AndroidComposeView;->getAutofillTree()Landroidx/compose/ui/autofill/AutofillTree;
+HSPLandroidx/compose/ui/platform/AndroidComposeView;->getClipboardManager()Landroidx/compose/ui/platform/AndroidClipboardManager;
+HSPLandroidx/compose/ui/platform/AndroidComposeView;->getClipboardManager()Landroidx/compose/ui/platform/ClipboardManager;
+HSPLandroidx/compose/ui/platform/AndroidComposeView;->getDensity()Landroidx/compose/ui/unit/Density;
+HSPLandroidx/compose/ui/platform/AndroidComposeView;->getFocusManager()Landroidx/compose/ui/focus/FocusManager;
+HSPLandroidx/compose/ui/platform/AndroidComposeView;->getFontFamilyResolver()Landroidx/compose/ui/text/font/FontFamily$Resolver;
+HSPLandroidx/compose/ui/platform/AndroidComposeView;->getFontLoader()Landroidx/compose/ui/text/font/Font$ResourceLoader;
+HSPLandroidx/compose/ui/platform/AndroidComposeView;->getFontWeightAdjustmentCompat(Landroid/content/res/Configuration;)I
+HSPLandroidx/compose/ui/platform/AndroidComposeView;->getHapticFeedBack()Landroidx/compose/ui/hapticfeedback/HapticFeedback;
+HSPLandroidx/compose/ui/platform/AndroidComposeView;->getInputModeManager()Landroidx/compose/ui/input/InputModeManager;
+HSPLandroidx/compose/ui/platform/AndroidComposeView;->getLayoutDirection()Landroidx/compose/ui/unit/LayoutDirection;
+HSPLandroidx/compose/ui/platform/AndroidComposeView;->getModifierLocalManager()Landroidx/compose/ui/modifier/ModifierLocalManager;
+HSPLandroidx/compose/ui/platform/AndroidComposeView;->getPointerIconService()Landroidx/compose/ui/input/pointer/PointerIconService;
+HSPLandroidx/compose/ui/platform/AndroidComposeView;->getRoot()Landroidx/compose/ui/node/LayoutNode;
+HSPLandroidx/compose/ui/platform/AndroidComposeView;->getSemanticsOwner()Landroidx/compose/ui/semantics/SemanticsOwner;
+HSPLandroidx/compose/ui/platform/AndroidComposeView;->getSharedDrawScope()Landroidx/compose/ui/node/LayoutNodeDrawScope;
+HSPLandroidx/compose/ui/platform/AndroidComposeView;->getShowLayoutBounds()Z
+HSPLandroidx/compose/ui/platform/AndroidComposeView;->getSnapshotObserver()Landroidx/compose/ui/node/OwnerSnapshotObserver;
+HSPLandroidx/compose/ui/platform/AndroidComposeView;->getTextInputService()Landroidx/compose/ui/text/input/TextInputService;
+HSPLandroidx/compose/ui/platform/AndroidComposeView;->getTextToolbar()Landroidx/compose/ui/platform/TextToolbar;
+HSPLandroidx/compose/ui/platform/AndroidComposeView;->getView()Landroid/view/View;
+HSPLandroidx/compose/ui/platform/AndroidComposeView;->getViewConfiguration()Landroidx/compose/ui/platform/ViewConfiguration;
+HSPLandroidx/compose/ui/platform/AndroidComposeView;->getViewTreeOwners()Landroidx/compose/ui/platform/AndroidComposeView$ViewTreeOwners;
+HSPLandroidx/compose/ui/platform/AndroidComposeView;->getWindowInfo()Landroidx/compose/ui/platform/WindowInfo;
+HSPLandroidx/compose/ui/platform/AndroidComposeView;->globalLayoutListener$lambda$1(Landroidx/compose/ui/platform/AndroidComposeView;)V
+HSPLandroidx/compose/ui/platform/AndroidComposeView;->invalidateLayers(Landroidx/compose/ui/node/LayoutNode;)V
+HSPLandroidx/compose/ui/platform/AndroidComposeView;->invalidateLayoutNodeMeasurement(Landroidx/compose/ui/node/LayoutNode;)V
+HSPLandroidx/compose/ui/platform/AndroidComposeView;->keyboardVisibilityEventLoop(Lkotlin/coroutines/Continuation;)Ljava/lang/Object;
+HSPLandroidx/compose/ui/platform/AndroidComposeView;->measureAndLayout(Z)V
+HSPLandroidx/compose/ui/platform/AndroidComposeView;->notifyLayerIsDirty$ui_release(Landroidx/compose/ui/node/OwnedLayer;Z)V
+HSPLandroidx/compose/ui/platform/AndroidComposeView;->onAttach(Landroidx/compose/ui/node/LayoutNode;)V
+HSPLandroidx/compose/ui/platform/AndroidComposeView;->onAttachedToWindow()V
+HSPLandroidx/compose/ui/platform/AndroidComposeView;->onCheckIsTextEditor()Z
+HSPLandroidx/compose/ui/platform/AndroidComposeView;->onDraw(Landroid/graphics/Canvas;)V
+HSPLandroidx/compose/ui/platform/AndroidComposeView;->onEndApplyChanges()V
+HSPLandroidx/compose/ui/platform/AndroidComposeView;->onLayout(ZIIII)V
+HSPLandroidx/compose/ui/platform/AndroidComposeView;->onLayoutChange(Landroidx/compose/ui/node/LayoutNode;)V
+HSPLandroidx/compose/ui/platform/AndroidComposeView;->onMeasure(II)V
+HSPLandroidx/compose/ui/platform/AndroidComposeView;->onRequestMeasure(Landroidx/compose/ui/node/LayoutNode;ZZ)V
+HSPLandroidx/compose/ui/platform/AndroidComposeView;->onRequestRelayout(Landroidx/compose/ui/node/LayoutNode;ZZ)V
+HSPLandroidx/compose/ui/platform/AndroidComposeView;->onResume(Landroidx/lifecycle/LifecycleOwner;)V
+HSPLandroidx/compose/ui/platform/AndroidComposeView;->onRtlPropertiesChanged(I)V
+HSPLandroidx/compose/ui/platform/AndroidComposeView;->onSemanticsChange()V
+HSPLandroidx/compose/ui/platform/AndroidComposeView;->onWindowFocusChanged(Z)V
+HSPLandroidx/compose/ui/platform/AndroidComposeView;->registerOnEndApplyChangesListener(Lkotlin/jvm/functions/Function0;)V
+HSPLandroidx/compose/ui/platform/AndroidComposeView;->registerOnLayoutCompletedListener(Landroidx/compose/ui/node/Owner$OnLayoutCompletedListener;)V
+HSPLandroidx/compose/ui/platform/AndroidComposeView;->scheduleMeasureAndLayout$default(Landroidx/compose/ui/platform/AndroidComposeView;Landroidx/compose/ui/node/LayoutNode;ILjava/lang/Object;)V
+HSPLandroidx/compose/ui/platform/AndroidComposeView;->scheduleMeasureAndLayout(Landroidx/compose/ui/node/LayoutNode;)V
+HSPLandroidx/compose/ui/platform/AndroidComposeView;->setConfigurationChangeObserver(Lkotlin/jvm/functions/Function1;)V
+HSPLandroidx/compose/ui/platform/AndroidComposeView;->setLayoutDirection(Landroidx/compose/ui/unit/LayoutDirection;)V
+HSPLandroidx/compose/ui/platform/AndroidComposeView;->setOnViewTreeOwnersAvailable(Lkotlin/jvm/functions/Function1;)V
+HSPLandroidx/compose/ui/platform/AndroidComposeView;->setShowLayoutBounds(Z)V
+HSPLandroidx/compose/ui/platform/AndroidComposeView;->setViewTreeOwners(Landroidx/compose/ui/platform/AndroidComposeView$ViewTreeOwners;)V
+HSPLandroidx/compose/ui/platform/AndroidComposeView;->touchModeChangeListener$lambda$3(Landroidx/compose/ui/platform/AndroidComposeView;Z)V
+HSPLandroidx/compose/ui/platform/AndroidComposeView;->updatePositionCacheAndDispatch()V
+HSPLandroidx/compose/ui/platform/AndroidComposeViewAccessibilityDelegateCompat$$ExternalSyntheticLambda0;-><init>(Landroidx/compose/ui/platform/AndroidComposeViewAccessibilityDelegateCompat;)V
+HSPLandroidx/compose/ui/platform/AndroidComposeViewAccessibilityDelegateCompat$$ExternalSyntheticLambda1;-><init>(Landroidx/compose/ui/platform/AndroidComposeViewAccessibilityDelegateCompat;)V
+HSPLandroidx/compose/ui/platform/AndroidComposeViewAccessibilityDelegateCompat$$ExternalSyntheticLambda2;-><init>(Landroidx/compose/ui/platform/AndroidComposeViewAccessibilityDelegateCompat;)V
+HSPLandroidx/compose/ui/platform/AndroidComposeViewAccessibilityDelegateCompat$1;-><init>(Landroidx/compose/ui/platform/AndroidComposeViewAccessibilityDelegateCompat;)V
+HSPLandroidx/compose/ui/platform/AndroidComposeViewAccessibilityDelegateCompat$1;->onViewAttachedToWindow(Landroid/view/View;)V
+HSPLandroidx/compose/ui/platform/AndroidComposeViewAccessibilityDelegateCompat$Companion;-><init>()V
+HSPLandroidx/compose/ui/platform/AndroidComposeViewAccessibilityDelegateCompat$Companion;-><init>(Lkotlin/jvm/internal/DefaultConstructorMarker;)V
+HSPLandroidx/compose/ui/platform/AndroidComposeViewAccessibilityDelegateCompat$MyNodeProvider;-><init>(Landroidx/compose/ui/platform/AndroidComposeViewAccessibilityDelegateCompat;)V
+HSPLandroidx/compose/ui/platform/AndroidComposeViewAccessibilityDelegateCompat$SemanticsNodeCopy;-><init>(Landroidx/compose/ui/semantics/SemanticsNode;Ljava/util/Map;)V
+HSPLandroidx/compose/ui/platform/AndroidComposeViewAccessibilityDelegateCompat$boundsUpdatesEventLoop$1;-><init>(Landroidx/compose/ui/platform/AndroidComposeViewAccessibilityDelegateCompat;Lkotlin/coroutines/Continuation;)V
+HSPLandroidx/compose/ui/platform/AndroidComposeViewAccessibilityDelegateCompat$sendScrollEventIfNeededLambda$1;-><init>(Landroidx/compose/ui/platform/AndroidComposeViewAccessibilityDelegateCompat;)V
+HSPLandroidx/compose/ui/platform/AndroidComposeViewAccessibilityDelegateCompat;-><clinit>()V
+HSPLandroidx/compose/ui/platform/AndroidComposeViewAccessibilityDelegateCompat;-><init>(Landroidx/compose/ui/platform/AndroidComposeView;)V
+HSPLandroidx/compose/ui/platform/AndroidComposeViewAccessibilityDelegateCompat;->boundsUpdatesEventLoop(Lkotlin/coroutines/Continuation;)Ljava/lang/Object;
+HSPLandroidx/compose/ui/platform/AndroidComposeViewAccessibilityDelegateCompat;->getAccessibilityManager$ui_release()Landroid/view/accessibility/AccessibilityManager;
+HSPLandroidx/compose/ui/platform/AndroidComposeViewAccessibilityDelegateCompat;->getEnabledStateListener$ui_release()Landroid/view/accessibility/AccessibilityManager$AccessibilityStateChangeListener;
+HSPLandroidx/compose/ui/platform/AndroidComposeViewAccessibilityDelegateCompat;->getTouchExplorationStateListener$ui_release()Landroid/view/accessibility/AccessibilityManager$TouchExplorationStateChangeListener;
+HSPLandroidx/compose/ui/platform/AndroidComposeViewAccessibilityDelegateCompat;->isEnabled$ui_release()Z
+HSPLandroidx/compose/ui/platform/AndroidComposeViewAccessibilityDelegateCompat;->onLayoutChange$ui_release(Landroidx/compose/ui/node/LayoutNode;)V
+HSPLandroidx/compose/ui/platform/AndroidComposeViewAccessibilityDelegateCompat;->onSemanticsChange$ui_release()V
+HSPLandroidx/compose/ui/platform/AndroidComposeViewForceDarkModeQ;-><clinit>()V
+HSPLandroidx/compose/ui/platform/AndroidComposeViewForceDarkModeQ;-><init>()V
+HSPLandroidx/compose/ui/platform/AndroidComposeViewForceDarkModeQ;->disallowForceDark(Landroid/view/View;)V
+HSPLandroidx/compose/ui/platform/AndroidComposeViewVerificationHelperMethodsO;-><clinit>()V
+HSPLandroidx/compose/ui/platform/AndroidComposeViewVerificationHelperMethodsO;-><init>()V
+HSPLandroidx/compose/ui/platform/AndroidComposeViewVerificationHelperMethodsO;->focusable(Landroid/view/View;IZ)V
+HSPLandroidx/compose/ui/platform/AndroidComposeView_androidKt$textInputServiceFactory$1;-><clinit>()V
+HSPLandroidx/compose/ui/platform/AndroidComposeView_androidKt$textInputServiceFactory$1;-><init>()V
+HSPLandroidx/compose/ui/platform/AndroidComposeView_androidKt$textInputServiceFactory$1;->invoke(Landroidx/compose/ui/text/input/PlatformTextInputService;)Landroidx/compose/ui/text/input/TextInputService;
+HSPLandroidx/compose/ui/platform/AndroidComposeView_androidKt$textInputServiceFactory$1;->invoke(Ljava/lang/Object;)Ljava/lang/Object;
+HSPLandroidx/compose/ui/platform/AndroidComposeView_androidKt;-><clinit>()V
+HSPLandroidx/compose/ui/platform/AndroidComposeView_androidKt;->access$layoutDirectionFromInt(I)Landroidx/compose/ui/unit/LayoutDirection;
+HSPLandroidx/compose/ui/platform/AndroidComposeView_androidKt;->getLocaleLayoutDirection(Landroid/content/res/Configuration;)Landroidx/compose/ui/unit/LayoutDirection;
+HSPLandroidx/compose/ui/platform/AndroidComposeView_androidKt;->getTextInputServiceFactory()Lkotlin/jvm/functions/Function1;
+HSPLandroidx/compose/ui/platform/AndroidComposeView_androidKt;->layoutDirectionFromInt(I)Landroidx/compose/ui/unit/LayoutDirection;
+HSPLandroidx/compose/ui/platform/AndroidCompositionLocals_androidKt$LocalConfiguration$1;-><clinit>()V
+HSPLandroidx/compose/ui/platform/AndroidCompositionLocals_androidKt$LocalConfiguration$1;-><init>()V
+HSPLandroidx/compose/ui/platform/AndroidCompositionLocals_androidKt$LocalContext$1;-><clinit>()V
+HSPLandroidx/compose/ui/platform/AndroidCompositionLocals_androidKt$LocalContext$1;-><init>()V
+HSPLandroidx/compose/ui/platform/AndroidCompositionLocals_androidKt$LocalImageVectorCache$1;-><clinit>()V
+HSPLandroidx/compose/ui/platform/AndroidCompositionLocals_androidKt$LocalImageVectorCache$1;-><init>()V
+HSPLandroidx/compose/ui/platform/AndroidCompositionLocals_androidKt$LocalLifecycleOwner$1;-><clinit>()V
+HSPLandroidx/compose/ui/platform/AndroidCompositionLocals_androidKt$LocalLifecycleOwner$1;-><init>()V
+HSPLandroidx/compose/ui/platform/AndroidCompositionLocals_androidKt$LocalSavedStateRegistryOwner$1;-><clinit>()V
+HSPLandroidx/compose/ui/platform/AndroidCompositionLocals_androidKt$LocalSavedStateRegistryOwner$1;-><init>()V
+HSPLandroidx/compose/ui/platform/AndroidCompositionLocals_androidKt$LocalView$1;-><clinit>()V
+HSPLandroidx/compose/ui/platform/AndroidCompositionLocals_androidKt$LocalView$1;-><init>()V
+HSPLandroidx/compose/ui/platform/AndroidCompositionLocals_androidKt$ProvideAndroidCompositionLocals$1$1;-><init>(Landroidx/compose/runtime/MutableState;)V
+HSPLandroidx/compose/ui/platform/AndroidCompositionLocals_androidKt$ProvideAndroidCompositionLocals$2$invoke$$inlined$onDispose$1;-><init>(Landroidx/compose/ui/platform/DisposableSaveableStateRegistry;)V
+HSPLandroidx/compose/ui/platform/AndroidCompositionLocals_androidKt$ProvideAndroidCompositionLocals$2;-><init>(Landroidx/compose/ui/platform/DisposableSaveableStateRegistry;)V
+HSPLandroidx/compose/ui/platform/AndroidCompositionLocals_androidKt$ProvideAndroidCompositionLocals$2;->invoke(Landroidx/compose/runtime/DisposableEffectScope;)Landroidx/compose/runtime/DisposableEffectResult;
+HSPLandroidx/compose/ui/platform/AndroidCompositionLocals_androidKt$ProvideAndroidCompositionLocals$2;->invoke(Ljava/lang/Object;)Ljava/lang/Object;
+HSPLandroidx/compose/ui/platform/AndroidCompositionLocals_androidKt$ProvideAndroidCompositionLocals$3;-><init>(Landroidx/compose/ui/platform/AndroidComposeView;Landroidx/compose/ui/platform/AndroidUriHandler;Lkotlin/jvm/functions/Function2;I)V
+HSPLandroidx/compose/ui/platform/AndroidCompositionLocals_androidKt$ProvideAndroidCompositionLocals$3;->invoke(Landroidx/compose/runtime/Composer;I)V
+HSPLandroidx/compose/ui/platform/AndroidCompositionLocals_androidKt$ProvideAndroidCompositionLocals$3;->invoke(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;
+HSPLandroidx/compose/ui/platform/AndroidCompositionLocals_androidKt$ProvideAndroidCompositionLocals$4;-><init>(Landroidx/compose/ui/platform/AndroidComposeView;Lkotlin/jvm/functions/Function2;I)V
+HSPLandroidx/compose/ui/platform/AndroidCompositionLocals_androidKt$ProvideAndroidCompositionLocals$4;->invoke(Landroidx/compose/runtime/Composer;I)V
+HSPLandroidx/compose/ui/platform/AndroidCompositionLocals_androidKt$ProvideAndroidCompositionLocals$4;->invoke(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;
+HSPLandroidx/compose/ui/platform/AndroidCompositionLocals_androidKt$obtainImageVectorCache$1$invoke$$inlined$onDispose$1;-><init>(Landroid/content/Context;Landroidx/compose/ui/platform/AndroidCompositionLocals_androidKt$obtainImageVectorCache$callbacks$1$1;)V
+HSPLandroidx/compose/ui/platform/AndroidCompositionLocals_androidKt$obtainImageVectorCache$1;-><init>(Landroid/content/Context;Landroidx/compose/ui/platform/AndroidCompositionLocals_androidKt$obtainImageVectorCache$callbacks$1$1;)V
+HSPLandroidx/compose/ui/platform/AndroidCompositionLocals_androidKt$obtainImageVectorCache$1;->invoke(Landroidx/compose/runtime/DisposableEffectScope;)Landroidx/compose/runtime/DisposableEffectResult;
+HSPLandroidx/compose/ui/platform/AndroidCompositionLocals_androidKt$obtainImageVectorCache$1;->invoke(Ljava/lang/Object;)Ljava/lang/Object;
+HSPLandroidx/compose/ui/platform/AndroidCompositionLocals_androidKt$obtainImageVectorCache$callbacks$1$1;-><init>(Landroid/content/res/Configuration;Landroidx/compose/ui/res/ImageVectorCache;)V
+HSPLandroidx/compose/ui/platform/AndroidCompositionLocals_androidKt;-><clinit>()V
+HSPLandroidx/compose/ui/platform/AndroidCompositionLocals_androidKt;->ProvideAndroidCompositionLocals$lambda$1(Landroidx/compose/runtime/MutableState;)Landroid/content/res/Configuration;
+HSPLandroidx/compose/ui/platform/AndroidCompositionLocals_androidKt;->ProvideAndroidCompositionLocals(Landroidx/compose/ui/platform/AndroidComposeView;Lkotlin/jvm/functions/Function2;Landroidx/compose/runtime/Composer;I)V
+HSPLandroidx/compose/ui/platform/AndroidCompositionLocals_androidKt;->getLocalConfiguration()Landroidx/compose/runtime/ProvidableCompositionLocal;
+HSPLandroidx/compose/ui/platform/AndroidCompositionLocals_androidKt;->getLocalContext()Landroidx/compose/runtime/ProvidableCompositionLocal;
+HSPLandroidx/compose/ui/platform/AndroidCompositionLocals_androidKt;->getLocalView()Landroidx/compose/runtime/ProvidableCompositionLocal;
+HSPLandroidx/compose/ui/platform/AndroidCompositionLocals_androidKt;->obtainImageVectorCache(Landroid/content/Context;Landroid/content/res/Configuration;Landroidx/compose/runtime/Composer;I)Landroidx/compose/ui/res/ImageVectorCache;
+HSPLandroidx/compose/ui/platform/AndroidFontResourceLoader;-><init>(Landroid/content/Context;)V
+HSPLandroidx/compose/ui/platform/AndroidTextToolbar$textActionModeCallback$1;-><init>(Landroidx/compose/ui/platform/AndroidTextToolbar;)V
+HSPLandroidx/compose/ui/platform/AndroidTextToolbar;-><init>(Landroid/view/View;)V
+HSPLandroidx/compose/ui/platform/AndroidUiDispatcher$Companion$Main$2;-><clinit>()V
+HSPLandroidx/compose/ui/platform/AndroidUiDispatcher$Companion$Main$2;-><init>()V
+HSPLandroidx/compose/ui/platform/AndroidUiDispatcher$Companion$Main$2;->invoke()Ljava/lang/Object;
+HSPLandroidx/compose/ui/platform/AndroidUiDispatcher$Companion$Main$2;->invoke()Lkotlin/coroutines/CoroutineContext;
+HSPLandroidx/compose/ui/platform/AndroidUiDispatcher$Companion$currentThread$1;-><init>()V
+HSPLandroidx/compose/ui/platform/AndroidUiDispatcher$Companion;-><init>()V
+HSPLandroidx/compose/ui/platform/AndroidUiDispatcher$Companion;-><init>(Lkotlin/jvm/internal/DefaultConstructorMarker;)V
+HSPLandroidx/compose/ui/platform/AndroidUiDispatcher$Companion;->getCurrentThread()Lkotlin/coroutines/CoroutineContext;
+HSPLandroidx/compose/ui/platform/AndroidUiDispatcher$Companion;->getMain()Lkotlin/coroutines/CoroutineContext;
+HSPLandroidx/compose/ui/platform/AndroidUiDispatcher$dispatchCallback$1;-><init>(Landroidx/compose/ui/platform/AndroidUiDispatcher;)V
+HSPLandroidx/compose/ui/platform/AndroidUiDispatcher$dispatchCallback$1;->doFrame(J)V
+HSPLandroidx/compose/ui/platform/AndroidUiDispatcher$dispatchCallback$1;->run()V
+HSPLandroidx/compose/ui/platform/AndroidUiDispatcher;-><clinit>()V
+HSPLandroidx/compose/ui/platform/AndroidUiDispatcher;-><init>(Landroid/view/Choreographer;Landroid/os/Handler;)V
+HSPLandroidx/compose/ui/platform/AndroidUiDispatcher;-><init>(Landroid/view/Choreographer;Landroid/os/Handler;Lkotlin/jvm/internal/DefaultConstructorMarker;)V
+HSPLandroidx/compose/ui/platform/AndroidUiDispatcher;->access$getHandler$p(Landroidx/compose/ui/platform/AndroidUiDispatcher;)Landroid/os/Handler;
+HSPLandroidx/compose/ui/platform/AndroidUiDispatcher;->access$getLock$p(Landroidx/compose/ui/platform/AndroidUiDispatcher;)Ljava/lang/Object;
+HSPLandroidx/compose/ui/platform/AndroidUiDispatcher;->access$getMain$delegate$cp()Lkotlin/Lazy;
+HSPLandroidx/compose/ui/platform/AndroidUiDispatcher;->access$getToRunOnFrame$p(Landroidx/compose/ui/platform/AndroidUiDispatcher;)Ljava/util/List;
+HSPLandroidx/compose/ui/platform/AndroidUiDispatcher;->access$performFrameDispatch(Landroidx/compose/ui/platform/AndroidUiDispatcher;J)V
+HSPLandroidx/compose/ui/platform/AndroidUiDispatcher;->access$performTrampolineDispatch(Landroidx/compose/ui/platform/AndroidUiDispatcher;)V
+HSPLandroidx/compose/ui/platform/AndroidUiDispatcher;->access$setScheduledFrameDispatch$p(Landroidx/compose/ui/platform/AndroidUiDispatcher;Z)V
+HSPLandroidx/compose/ui/platform/AndroidUiDispatcher;->dispatch(Lkotlin/coroutines/CoroutineContext;Ljava/lang/Runnable;)V
+HSPLandroidx/compose/ui/platform/AndroidUiDispatcher;->getChoreographer()Landroid/view/Choreographer;
+HSPLandroidx/compose/ui/platform/AndroidUiDispatcher;->getFrameClock()Landroidx/compose/runtime/MonotonicFrameClock;
+HSPLandroidx/compose/ui/platform/AndroidUiDispatcher;->nextTask()Ljava/lang/Runnable;
+HSPLandroidx/compose/ui/platform/AndroidUiDispatcher;->performFrameDispatch(J)V
+HSPLandroidx/compose/ui/platform/AndroidUiDispatcher;->performTrampolineDispatch()V
+HSPLandroidx/compose/ui/platform/AndroidUiDispatcher;->postFrameCallback$ui_release(Landroid/view/Choreographer$FrameCallback;)V
+HSPLandroidx/compose/ui/platform/AndroidUiDispatcher_androidKt;->access$isMainThread()Z
+HSPLandroidx/compose/ui/platform/AndroidUiDispatcher_androidKt;->isMainThread()Z
+HSPLandroidx/compose/ui/platform/AndroidUiFrameClock$withFrameNanos$2$1;-><init>(Landroidx/compose/ui/platform/AndroidUiDispatcher;Landroid/view/Choreographer$FrameCallback;)V
+HSPLandroidx/compose/ui/platform/AndroidUiFrameClock$withFrameNanos$2$callback$1;-><init>(Lkotlinx/coroutines/CancellableContinuation;Landroidx/compose/ui/platform/AndroidUiFrameClock;Lkotlin/jvm/functions/Function1;)V
+HSPLandroidx/compose/ui/platform/AndroidUiFrameClock$withFrameNanos$2$callback$1;->doFrame(J)V
+HSPLandroidx/compose/ui/platform/AndroidUiFrameClock;-><clinit>()V
+HSPLandroidx/compose/ui/platform/AndroidUiFrameClock;-><init>(Landroid/view/Choreographer;)V
+HSPLandroidx/compose/ui/platform/AndroidUiFrameClock;->fold(Ljava/lang/Object;Lkotlin/jvm/functions/Function2;)Ljava/lang/Object;
+HSPLandroidx/compose/ui/platform/AndroidUiFrameClock;->get(Lkotlin/coroutines/CoroutineContext$Key;)Lkotlin/coroutines/CoroutineContext$Element;
+HSPLandroidx/compose/ui/platform/AndroidUiFrameClock;->getChoreographer()Landroid/view/Choreographer;
+HSPLandroidx/compose/ui/platform/AndroidUiFrameClock;->minusKey(Lkotlin/coroutines/CoroutineContext$Key;)Lkotlin/coroutines/CoroutineContext;
+HSPLandroidx/compose/ui/platform/AndroidUiFrameClock;->withFrameNanos(Lkotlin/jvm/functions/Function1;Lkotlin/coroutines/Continuation;)Ljava/lang/Object;
+HSPLandroidx/compose/ui/platform/AndroidUriHandler;-><clinit>()V
+HSPLandroidx/compose/ui/platform/AndroidUriHandler;-><init>(Landroid/content/Context;)V
+HSPLandroidx/compose/ui/platform/AndroidViewConfiguration;-><clinit>()V
+HSPLandroidx/compose/ui/platform/AndroidViewConfiguration;-><init>(Landroid/view/ViewConfiguration;)V
+HSPLandroidx/compose/ui/platform/CalculateMatrixToWindowApi29;-><init>()V
+HSPLandroidx/compose/ui/platform/ComposableSingletons$Wrapper_androidKt$lambda-1$1;-><clinit>()V
+HSPLandroidx/compose/ui/platform/ComposableSingletons$Wrapper_androidKt$lambda-1$1;-><init>()V
+HSPLandroidx/compose/ui/platform/ComposableSingletons$Wrapper_androidKt;-><clinit>()V
+HSPLandroidx/compose/ui/platform/ComposableSingletons$Wrapper_androidKt;-><init>()V
+HSPLandroidx/compose/ui/platform/ComposableSingletons$Wrapper_androidKt;->getLambda-1$ui_release()Lkotlin/jvm/functions/Function2;
+HSPLandroidx/compose/ui/platform/ComposeView$Content$1;-><init>(Landroidx/compose/ui/platform/ComposeView;I)V
+HSPLandroidx/compose/ui/platform/ComposeView;-><clinit>()V
+HSPLandroidx/compose/ui/platform/ComposeView;-><init>(Landroid/content/Context;Landroid/util/AttributeSet;I)V
+HSPLandroidx/compose/ui/platform/ComposeView;-><init>(Landroid/content/Context;Landroid/util/AttributeSet;IILkotlin/jvm/internal/DefaultConstructorMarker;)V
+HSPLandroidx/compose/ui/platform/ComposeView;->Content(Landroidx/compose/runtime/Composer;I)V
+HSPLandroidx/compose/ui/platform/ComposeView;->getShouldCreateCompositionOnAttachedToWindow()Z
+HSPLandroidx/compose/ui/platform/ComposeView;->setContent(Lkotlin/jvm/functions/Function2;)V
+HSPLandroidx/compose/ui/platform/CompositionLocalsKt$LocalAccessibilityManager$1;-><clinit>()V
+HSPLandroidx/compose/ui/platform/CompositionLocalsKt$LocalAccessibilityManager$1;-><init>()V
+HSPLandroidx/compose/ui/platform/CompositionLocalsKt$LocalAutofill$1;-><clinit>()V
+HSPLandroidx/compose/ui/platform/CompositionLocalsKt$LocalAutofill$1;-><init>()V
+HSPLandroidx/compose/ui/platform/CompositionLocalsKt$LocalAutofillTree$1;-><clinit>()V
+HSPLandroidx/compose/ui/platform/CompositionLocalsKt$LocalAutofillTree$1;-><init>()V
+HSPLandroidx/compose/ui/platform/CompositionLocalsKt$LocalClipboardManager$1;-><clinit>()V
+HSPLandroidx/compose/ui/platform/CompositionLocalsKt$LocalClipboardManager$1;-><init>()V
+HSPLandroidx/compose/ui/platform/CompositionLocalsKt$LocalDensity$1;-><clinit>()V
+HSPLandroidx/compose/ui/platform/CompositionLocalsKt$LocalDensity$1;-><init>()V
+HSPLandroidx/compose/ui/platform/CompositionLocalsKt$LocalFocusManager$1;-><clinit>()V
+HSPLandroidx/compose/ui/platform/CompositionLocalsKt$LocalFocusManager$1;-><init>()V
+HSPLandroidx/compose/ui/platform/CompositionLocalsKt$LocalFontFamilyResolver$1;-><clinit>()V
+HSPLandroidx/compose/ui/platform/CompositionLocalsKt$LocalFontFamilyResolver$1;-><init>()V
+HSPLandroidx/compose/ui/platform/CompositionLocalsKt$LocalFontLoader$1;-><clinit>()V
+HSPLandroidx/compose/ui/platform/CompositionLocalsKt$LocalFontLoader$1;-><init>()V
+HSPLandroidx/compose/ui/platform/CompositionLocalsKt$LocalHapticFeedback$1;-><clinit>()V
+HSPLandroidx/compose/ui/platform/CompositionLocalsKt$LocalHapticFeedback$1;-><init>()V
+HSPLandroidx/compose/ui/platform/CompositionLocalsKt$LocalInputModeManager$1;-><clinit>()V
+HSPLandroidx/compose/ui/platform/CompositionLocalsKt$LocalInputModeManager$1;-><init>()V
+HSPLandroidx/compose/ui/platform/CompositionLocalsKt$LocalLayoutDirection$1;-><clinit>()V
+HSPLandroidx/compose/ui/platform/CompositionLocalsKt$LocalLayoutDirection$1;-><init>()V
+HSPLandroidx/compose/ui/platform/CompositionLocalsKt$LocalPointerIconService$1;-><clinit>()V
+HSPLandroidx/compose/ui/platform/CompositionLocalsKt$LocalPointerIconService$1;-><init>()V
+HSPLandroidx/compose/ui/platform/CompositionLocalsKt$LocalTextInputService$1;-><clinit>()V
+HSPLandroidx/compose/ui/platform/CompositionLocalsKt$LocalTextInputService$1;-><init>()V
+HSPLandroidx/compose/ui/platform/CompositionLocalsKt$LocalTextToolbar$1;-><clinit>()V
+HSPLandroidx/compose/ui/platform/CompositionLocalsKt$LocalTextToolbar$1;-><init>()V
+HSPLandroidx/compose/ui/platform/CompositionLocalsKt$LocalUriHandler$1;-><clinit>()V
+HSPLandroidx/compose/ui/platform/CompositionLocalsKt$LocalUriHandler$1;-><init>()V
+HSPLandroidx/compose/ui/platform/CompositionLocalsKt$LocalViewConfiguration$1;-><clinit>()V
+HSPLandroidx/compose/ui/platform/CompositionLocalsKt$LocalViewConfiguration$1;-><init>()V
+HSPLandroidx/compose/ui/platform/CompositionLocalsKt$LocalWindowInfo$1;-><clinit>()V
+HSPLandroidx/compose/ui/platform/CompositionLocalsKt$LocalWindowInfo$1;-><init>()V
+HSPLandroidx/compose/ui/platform/CompositionLocalsKt$ProvideCommonCompositionLocals$1;-><init>(Landroidx/compose/ui/node/Owner;Landroidx/compose/ui/platform/UriHandler;Lkotlin/jvm/functions/Function2;I)V
+HSPLandroidx/compose/ui/platform/CompositionLocalsKt;-><clinit>()V
+HSPLandroidx/compose/ui/platform/CompositionLocalsKt;->ProvideCommonCompositionLocals(Landroidx/compose/ui/node/Owner;Landroidx/compose/ui/platform/UriHandler;Lkotlin/jvm/functions/Function2;Landroidx/compose/runtime/Composer;I)V
+HSPLandroidx/compose/ui/platform/CompositionLocalsKt;->getLocalDensity()Landroidx/compose/runtime/ProvidableCompositionLocal;
+HSPLandroidx/compose/ui/platform/CompositionLocalsKt;->getLocalFontFamilyResolver()Landroidx/compose/runtime/ProvidableCompositionLocal;
+HSPLandroidx/compose/ui/platform/CompositionLocalsKt;->getLocalInputModeManager()Landroidx/compose/runtime/ProvidableCompositionLocal;
+HSPLandroidx/compose/ui/platform/CompositionLocalsKt;->getLocalLayoutDirection()Landroidx/compose/runtime/ProvidableCompositionLocal;
+HSPLandroidx/compose/ui/platform/CompositionLocalsKt;->getLocalViewConfiguration()Landroidx/compose/runtime/ProvidableCompositionLocal;
+HSPLandroidx/compose/ui/platform/DisposableSaveableStateRegistry;-><init>(Landroidx/compose/runtime/saveable/SaveableStateRegistry;Lkotlin/jvm/functions/Function0;)V
+HSPLandroidx/compose/ui/platform/DisposableSaveableStateRegistry;->canBeSaved(Ljava/lang/Object;)Z
+HSPLandroidx/compose/ui/platform/DisposableSaveableStateRegistry;->consumeRestored(Ljava/lang/String;)Ljava/lang/Object;
+HSPLandroidx/compose/ui/platform/DisposableSaveableStateRegistry;->registerProvider(Ljava/lang/String;Lkotlin/jvm/functions/Function0;)Landroidx/compose/runtime/saveable/SaveableStateRegistry$Entry;
+HSPLandroidx/compose/ui/platform/DisposableSaveableStateRegistry_androidKt$DisposableSaveableStateRegistry$1;-><init>(ZLandroidx/savedstate/SavedStateRegistry;Ljava/lang/String;)V
+HSPLandroidx/compose/ui/platform/DisposableSaveableStateRegistry_androidKt$DisposableSaveableStateRegistry$registered$1;-><init>(Landroidx/compose/runtime/saveable/SaveableStateRegistry;)V
+HSPLandroidx/compose/ui/platform/DisposableSaveableStateRegistry_androidKt$DisposableSaveableStateRegistry$saveableStateRegistry$1;-><clinit>()V
+HSPLandroidx/compose/ui/platform/DisposableSaveableStateRegistry_androidKt$DisposableSaveableStateRegistry$saveableStateRegistry$1;-><init>()V
+HSPLandroidx/compose/ui/platform/DisposableSaveableStateRegistry_androidKt$DisposableSaveableStateRegistry$saveableStateRegistry$1;->invoke(Ljava/lang/Object;)Ljava/lang/Boolean;
+HSPLandroidx/compose/ui/platform/DisposableSaveableStateRegistry_androidKt$DisposableSaveableStateRegistry$saveableStateRegistry$1;->invoke(Ljava/lang/Object;)Ljava/lang/Object;
+HSPLandroidx/compose/ui/platform/DisposableSaveableStateRegistry_androidKt;-><clinit>()V
+HSPLandroidx/compose/ui/platform/DisposableSaveableStateRegistry_androidKt;->DisposableSaveableStateRegistry(Landroid/view/View;Landroidx/savedstate/SavedStateRegistryOwner;)Landroidx/compose/ui/platform/DisposableSaveableStateRegistry;
+HSPLandroidx/compose/ui/platform/DisposableSaveableStateRegistry_androidKt;->DisposableSaveableStateRegistry(Ljava/lang/String;Landroidx/savedstate/SavedStateRegistryOwner;)Landroidx/compose/ui/platform/DisposableSaveableStateRegistry;
+HSPLandroidx/compose/ui/platform/DisposableSaveableStateRegistry_androidKt;->access$canBeSavedToBundle(Ljava/lang/Object;)Z
+HSPLandroidx/compose/ui/platform/DisposableSaveableStateRegistry_androidKt;->canBeSavedToBundle(Ljava/lang/Object;)Z
+HSPLandroidx/compose/ui/platform/GlobalSnapshotManager$ensureStarted$1;-><init>(Lkotlinx/coroutines/channels/Channel;Lkotlin/coroutines/Continuation;)V
+HSPLandroidx/compose/ui/platform/GlobalSnapshotManager$ensureStarted$1;->create(Ljava/lang/Object;Lkotlin/coroutines/Continuation;)Lkotlin/coroutines/Continuation;
+HSPLandroidx/compose/ui/platform/GlobalSnapshotManager$ensureStarted$1;->invokeSuspend(Ljava/lang/Object;)Ljava/lang/Object;
+HSPLandroidx/compose/ui/platform/GlobalSnapshotManager$ensureStarted$2;-><init>(Lkotlinx/coroutines/channels/Channel;)V
+HSPLandroidx/compose/ui/platform/GlobalSnapshotManager$ensureStarted$2;->invoke(Ljava/lang/Object;)Ljava/lang/Object;
+HSPLandroidx/compose/ui/platform/GlobalSnapshotManager$ensureStarted$2;->invoke(Ljava/lang/Object;)V
+HSPLandroidx/compose/ui/platform/GlobalSnapshotManager;-><clinit>()V
+HSPLandroidx/compose/ui/platform/GlobalSnapshotManager;-><init>()V
+HSPLandroidx/compose/ui/platform/GlobalSnapshotManager;->ensureStarted()V
+HSPLandroidx/compose/ui/platform/InspectableModifier$End;-><init>(Landroidx/compose/ui/platform/InspectableModifier;)V
+HSPLandroidx/compose/ui/platform/InspectableModifier;-><clinit>()V
+HSPLandroidx/compose/ui/platform/InspectableModifier;-><init>(Lkotlin/jvm/functions/Function1;)V
+HSPLandroidx/compose/ui/platform/InspectableModifier;->getEnd()Landroidx/compose/ui/platform/InspectableModifier$End;
+HSPLandroidx/compose/ui/platform/InspectableValueKt$NoInspectorInfo$1;-><clinit>()V
+HSPLandroidx/compose/ui/platform/InspectableValueKt$NoInspectorInfo$1;-><init>()V
+HSPLandroidx/compose/ui/platform/InspectableValueKt;-><clinit>()V
+HSPLandroidx/compose/ui/platform/InspectableValueKt;->getNoInspectorInfo()Lkotlin/jvm/functions/Function1;
+HSPLandroidx/compose/ui/platform/InspectableValueKt;->inspectableWrapper(Landroidx/compose/ui/Modifier;Lkotlin/jvm/functions/Function1;Landroidx/compose/ui/Modifier;)Landroidx/compose/ui/Modifier;
+HSPLandroidx/compose/ui/platform/InspectableValueKt;->isDebugInspectorInfoEnabled()Z
+HSPLandroidx/compose/ui/platform/InspectorValueInfo;-><clinit>()V
+HSPLandroidx/compose/ui/platform/InspectorValueInfo;-><init>(Lkotlin/jvm/functions/Function1;)V
+HSPLandroidx/compose/ui/platform/LayerMatrixCache;-><init>(Lkotlin/jvm/functions/Function2;)V
+HSPLandroidx/compose/ui/platform/LayerMatrixCache;->invalidate()V
+HSPLandroidx/compose/ui/platform/MotionDurationScaleImpl;-><init>()V
+HSPLandroidx/compose/ui/platform/MotionDurationScaleImpl;->fold(Ljava/lang/Object;Lkotlin/jvm/functions/Function2;)Ljava/lang/Object;
+HSPLandroidx/compose/ui/platform/MotionDurationScaleImpl;->get(Lkotlin/coroutines/CoroutineContext$Key;)Lkotlin/coroutines/CoroutineContext$Element;
+HSPLandroidx/compose/ui/platform/MotionDurationScaleImpl;->getScaleFactor()F
+HSPLandroidx/compose/ui/platform/MotionDurationScaleImpl;->minusKey(Lkotlin/coroutines/CoroutineContext$Key;)Lkotlin/coroutines/CoroutineContext;
+HSPLandroidx/compose/ui/platform/MotionDurationScaleImpl;->setScaleFactor(F)V
+HSPLandroidx/compose/ui/platform/OutlineResolver;-><init>(Landroidx/compose/ui/unit/Density;)V
+HSPLandroidx/compose/ui/platform/OutlineResolver;->getOutline()Landroid/graphics/Outline;
+HSPLandroidx/compose/ui/platform/OutlineResolver;->getOutlineClipSupported()Z
+HSPLandroidx/compose/ui/platform/OutlineResolver;->update(Landroidx/compose/ui/graphics/Shape;FZFLandroidx/compose/ui/unit/LayoutDirection;Landroidx/compose/ui/unit/Density;)Z
+HSPLandroidx/compose/ui/platform/OutlineResolver;->update-uvyYCjk(J)V
+HSPLandroidx/compose/ui/platform/OutlineResolver;->updateCache()V
+HSPLandroidx/compose/ui/platform/OutlineResolver;->updateCacheWithPath(Landroidx/compose/ui/graphics/Path;)V
+HSPLandroidx/compose/ui/platform/OutlineResolver;->updateCacheWithRoundRect(Landroidx/compose/ui/geometry/RoundRect;)V
+HSPLandroidx/compose/ui/platform/RenderNodeApi29;-><init>(Landroidx/compose/ui/platform/AndroidComposeView;)V
+HSPLandroidx/compose/ui/platform/RenderNodeApi29;->drawInto(Landroid/graphics/Canvas;)V
+HSPLandroidx/compose/ui/platform/RenderNodeApi29;->getAlpha()F
+HSPLandroidx/compose/ui/platform/RenderNodeApi29;->getClipToOutline()Z
+HSPLandroidx/compose/ui/platform/RenderNodeApi29;->getElevation()F
+HSPLandroidx/compose/ui/platform/RenderNodeApi29;->getHasDisplayList()Z
+HSPLandroidx/compose/ui/platform/RenderNodeApi29;->getHeight()I
+HSPLandroidx/compose/ui/platform/RenderNodeApi29;->getLeft()I
+HSPLandroidx/compose/ui/platform/RenderNodeApi29;->getTop()I
+HSPLandroidx/compose/ui/platform/RenderNodeApi29;->getWidth()I
+HSPLandroidx/compose/ui/platform/RenderNodeApi29;->offsetLeftAndRight(I)V
+HSPLandroidx/compose/ui/platform/RenderNodeApi29;->offsetTopAndBottom(I)V
+HSPLandroidx/compose/ui/platform/RenderNodeApi29;->record(Landroidx/compose/ui/graphics/CanvasHolder;Landroidx/compose/ui/graphics/Path;Lkotlin/jvm/functions/Function1;)V
+HSPLandroidx/compose/ui/platform/RenderNodeApi29;->setAlpha(F)V
+HSPLandroidx/compose/ui/platform/RenderNodeApi29;->setAmbientShadowColor(I)V
+HSPLandroidx/compose/ui/platform/RenderNodeApi29;->setCameraDistance(F)V
+HSPLandroidx/compose/ui/platform/RenderNodeApi29;->setClipToBounds(Z)V
+HSPLandroidx/compose/ui/platform/RenderNodeApi29;->setClipToOutline(Z)V
+HSPLandroidx/compose/ui/platform/RenderNodeApi29;->setCompositingStrategy-aDBOjCE(I)V
+HSPLandroidx/compose/ui/platform/RenderNodeApi29;->setElevation(F)V
+HSPLandroidx/compose/ui/platform/RenderNodeApi29;->setHasOverlappingRendering(Z)Z
+HSPLandroidx/compose/ui/platform/RenderNodeApi29;->setOutline(Landroid/graphics/Outline;)V
+HSPLandroidx/compose/ui/platform/RenderNodeApi29;->setPivotX(F)V
+HSPLandroidx/compose/ui/platform/RenderNodeApi29;->setPivotY(F)V
+HSPLandroidx/compose/ui/platform/RenderNodeApi29;->setPosition(IIII)Z
+HSPLandroidx/compose/ui/platform/RenderNodeApi29;->setRenderEffect(Landroidx/compose/ui/graphics/RenderEffect;)V
+HSPLandroidx/compose/ui/platform/RenderNodeApi29;->setRotationX(F)V
+HSPLandroidx/compose/ui/platform/RenderNodeApi29;->setRotationY(F)V
+HSPLandroidx/compose/ui/platform/RenderNodeApi29;->setRotationZ(F)V
+HSPLandroidx/compose/ui/platform/RenderNodeApi29;->setScaleX(F)V
+HSPLandroidx/compose/ui/platform/RenderNodeApi29;->setScaleY(F)V
+HSPLandroidx/compose/ui/platform/RenderNodeApi29;->setSpotShadowColor(I)V
+HSPLandroidx/compose/ui/platform/RenderNodeApi29;->setTranslationX(F)V
+HSPLandroidx/compose/ui/platform/RenderNodeApi29;->setTranslationY(F)V
+HSPLandroidx/compose/ui/platform/RenderNodeApi29VerificationHelper;-><clinit>()V
+HSPLandroidx/compose/ui/platform/RenderNodeApi29VerificationHelper;-><init>()V
+HSPLandroidx/compose/ui/platform/RenderNodeApi29VerificationHelper;->setRenderEffect(Landroid/graphics/RenderNode;Landroidx/compose/ui/graphics/RenderEffect;)V
+HSPLandroidx/compose/ui/platform/RenderNodeLayer$Companion$getMatrix$1;-><clinit>()V
+HSPLandroidx/compose/ui/platform/RenderNodeLayer$Companion$getMatrix$1;-><init>()V
+HSPLandroidx/compose/ui/platform/RenderNodeLayer$Companion;-><init>()V
+HSPLandroidx/compose/ui/platform/RenderNodeLayer$Companion;-><init>(Lkotlin/jvm/internal/DefaultConstructorMarker;)V
+HSPLandroidx/compose/ui/platform/RenderNodeLayer;-><clinit>()V
+HSPLandroidx/compose/ui/platform/RenderNodeLayer;-><init>(Landroidx/compose/ui/platform/AndroidComposeView;Lkotlin/jvm/functions/Function1;Lkotlin/jvm/functions/Function0;)V
+HSPLandroidx/compose/ui/platform/RenderNodeLayer;->drawLayer(Landroidx/compose/ui/graphics/Canvas;)V
+HSPLandroidx/compose/ui/platform/RenderNodeLayer;->invalidate()V
+HSPLandroidx/compose/ui/platform/RenderNodeLayer;->move--gyyYBs(J)V
+HSPLandroidx/compose/ui/platform/RenderNodeLayer;->resize-ozmzZPI(J)V
+HSPLandroidx/compose/ui/platform/RenderNodeLayer;->setDirty(Z)V
+HSPLandroidx/compose/ui/platform/RenderNodeLayer;->triggerRepaint()V
+HSPLandroidx/compose/ui/platform/RenderNodeLayer;->updateDisplayList()V
+HSPLandroidx/compose/ui/platform/RenderNodeLayer;->updateLayerProperties-dDxr-wY(FFFFFFFFFFJLandroidx/compose/ui/graphics/Shape;ZLandroidx/compose/ui/graphics/RenderEffect;JJILandroidx/compose/ui/unit/LayoutDirection;Landroidx/compose/ui/unit/Density;)V
+HSPLandroidx/compose/ui/platform/TextToolbarStatus;->$values()[Landroidx/compose/ui/platform/TextToolbarStatus;
+HSPLandroidx/compose/ui/platform/TextToolbarStatus;-><clinit>()V
+HSPLandroidx/compose/ui/platform/TextToolbarStatus;-><init>(Ljava/lang/String;I)V
+HSPLandroidx/compose/ui/platform/ViewCompositionStrategy$Companion;-><clinit>()V
+HSPLandroidx/compose/ui/platform/ViewCompositionStrategy$Companion;-><init>()V
+HSPLandroidx/compose/ui/platform/ViewCompositionStrategy$Companion;->getDefault()Landroidx/compose/ui/platform/ViewCompositionStrategy;
+HSPLandroidx/compose/ui/platform/ViewCompositionStrategy$DisposeOnDetachedFromWindowOrReleasedFromPool$installFor$1;-><init>(Landroidx/compose/ui/platform/AbstractComposeView;Landroidx/compose/ui/platform/ViewCompositionStrategy$DisposeOnDetachedFromWindowOrReleasedFromPool$installFor$listener$1;Landroidx/customview/poolingcontainer/PoolingContainerListener;)V
+HSPLandroidx/compose/ui/platform/ViewCompositionStrategy$DisposeOnDetachedFromWindowOrReleasedFromPool$installFor$listener$1;-><init>(Landroidx/compose/ui/platform/AbstractComposeView;)V
+HSPLandroidx/compose/ui/platform/ViewCompositionStrategy$DisposeOnDetachedFromWindowOrReleasedFromPool$installFor$listener$1;->onViewAttachedToWindow(Landroid/view/View;)V
+HSPLandroidx/compose/ui/platform/ViewCompositionStrategy$DisposeOnDetachedFromWindowOrReleasedFromPool$installFor$poolingContainerListener$1;-><init>(Landroidx/compose/ui/platform/AbstractComposeView;)V
+HSPLandroidx/compose/ui/platform/ViewCompositionStrategy$DisposeOnDetachedFromWindowOrReleasedFromPool;-><clinit>()V
+HSPLandroidx/compose/ui/platform/ViewCompositionStrategy$DisposeOnDetachedFromWindowOrReleasedFromPool;-><init>()V
+HSPLandroidx/compose/ui/platform/ViewCompositionStrategy$DisposeOnDetachedFromWindowOrReleasedFromPool;->installFor(Landroidx/compose/ui/platform/AbstractComposeView;)Lkotlin/jvm/functions/Function0;
+HSPLandroidx/compose/ui/platform/ViewCompositionStrategy;-><clinit>()V
+HSPLandroidx/compose/ui/platform/ViewConfiguration;->getMinimumTouchTargetSize-MYxV2XQ()J
+HSPLandroidx/compose/ui/platform/ViewLayer$Companion$OutlineProvider$1;-><init>()V
+HSPLandroidx/compose/ui/platform/ViewLayer$Companion$getMatrix$1;-><clinit>()V
+HSPLandroidx/compose/ui/platform/ViewLayer$Companion$getMatrix$1;-><init>()V
+HSPLandroidx/compose/ui/platform/ViewLayer$Companion;-><init>()V
+HSPLandroidx/compose/ui/platform/ViewLayer$Companion;-><init>(Lkotlin/jvm/internal/DefaultConstructorMarker;)V
+HSPLandroidx/compose/ui/platform/ViewLayer$Companion;->getShouldUseDispatchDraw()Z
+HSPLandroidx/compose/ui/platform/ViewLayer;-><clinit>()V
+HSPLandroidx/compose/ui/platform/ViewLayer;->access$getShouldUseDispatchDraw$cp()Z
+HSPLandroidx/compose/ui/platform/ViewRootForTest$Companion;-><clinit>()V
+HSPLandroidx/compose/ui/platform/ViewRootForTest$Companion;-><init>()V
+HSPLandroidx/compose/ui/platform/ViewRootForTest$Companion;->getOnViewCreatedCallback()Lkotlin/jvm/functions/Function1;
+HSPLandroidx/compose/ui/platform/ViewRootForTest;-><clinit>()V
+HSPLandroidx/compose/ui/platform/WeakCache;-><init>()V
+HSPLandroidx/compose/ui/platform/WeakCache;->clearWeakReferences()V
+HSPLandroidx/compose/ui/platform/WeakCache;->pop()Ljava/lang/Object;
+HSPLandroidx/compose/ui/platform/WindowInfoImpl$Companion;-><init>()V
+HSPLandroidx/compose/ui/platform/WindowInfoImpl$Companion;-><init>(Lkotlin/jvm/internal/DefaultConstructorMarker;)V
+HSPLandroidx/compose/ui/platform/WindowInfoImpl;-><clinit>()V
+HSPLandroidx/compose/ui/platform/WindowInfoImpl;-><init>()V
+HSPLandroidx/compose/ui/platform/WindowInfoImpl;->setWindowFocused(Z)V
+HSPLandroidx/compose/ui/platform/WindowRecomposerFactory$Companion$LifecycleAware$1;-><clinit>()V
+HSPLandroidx/compose/ui/platform/WindowRecomposerFactory$Companion$LifecycleAware$1;-><init>()V
+HSPLandroidx/compose/ui/platform/WindowRecomposerFactory$Companion$LifecycleAware$1;->createRecomposer(Landroid/view/View;)Landroidx/compose/runtime/Recomposer;
+HSPLandroidx/compose/ui/platform/WindowRecomposerFactory$Companion;-><clinit>()V
+HSPLandroidx/compose/ui/platform/WindowRecomposerFactory$Companion;-><init>()V
+HSPLandroidx/compose/ui/platform/WindowRecomposerFactory$Companion;->getLifecycleAware()Landroidx/compose/ui/platform/WindowRecomposerFactory;
+HSPLandroidx/compose/ui/platform/WindowRecomposerFactory;-><clinit>()V
+HSPLandroidx/compose/ui/platform/WindowRecomposerPolicy$createAndInstallWindowRecomposer$1;-><init>(Lkotlinx/coroutines/Job;)V
+HSPLandroidx/compose/ui/platform/WindowRecomposerPolicy$createAndInstallWindowRecomposer$1;->onViewAttachedToWindow(Landroid/view/View;)V
+HSPLandroidx/compose/ui/platform/WindowRecomposerPolicy$createAndInstallWindowRecomposer$unsetJob$1;-><init>(Landroidx/compose/runtime/Recomposer;Landroid/view/View;Lkotlin/coroutines/Continuation;)V
+HSPLandroidx/compose/ui/platform/WindowRecomposerPolicy$createAndInstallWindowRecomposer$unsetJob$1;->create(Ljava/lang/Object;Lkotlin/coroutines/Continuation;)Lkotlin/coroutines/Continuation;
+HSPLandroidx/compose/ui/platform/WindowRecomposerPolicy$createAndInstallWindowRecomposer$unsetJob$1;->invokeSuspend(Ljava/lang/Object;)Ljava/lang/Object;
+HSPLandroidx/compose/ui/platform/WindowRecomposerPolicy;-><clinit>()V
+HSPLandroidx/compose/ui/platform/WindowRecomposerPolicy;-><init>()V
+HSPLandroidx/compose/ui/platform/WindowRecomposerPolicy;->createAndInstallWindowRecomposer$ui_release(Landroid/view/View;)Landroidx/compose/runtime/Recomposer;
+HSPLandroidx/compose/ui/platform/WindowRecomposer_androidKt$createLifecycleAwareWindowRecomposer$1;-><init>(Landroid/view/View;Landroidx/compose/runtime/Recomposer;)V
+HSPLandroidx/compose/ui/platform/WindowRecomposer_androidKt$createLifecycleAwareWindowRecomposer$1;->onViewAttachedToWindow(Landroid/view/View;)V
+HSPLandroidx/compose/ui/platform/WindowRecomposer_androidKt$createLifecycleAwareWindowRecomposer$2$WhenMappings;-><clinit>()V
+HSPLandroidx/compose/ui/platform/WindowRecomposer_androidKt$createLifecycleAwareWindowRecomposer$2$onStateChanged$1$1$1$1;-><init>(Landroidx/compose/ui/platform/MotionDurationScaleImpl;)V
+HSPLandroidx/compose/ui/platform/WindowRecomposer_androidKt$createLifecycleAwareWindowRecomposer$2$onStateChanged$1$1$1$1;->emit(FLkotlin/coroutines/Continuation;)Ljava/lang/Object;
+HSPLandroidx/compose/ui/platform/WindowRecomposer_androidKt$createLifecycleAwareWindowRecomposer$2$onStateChanged$1$1$1$1;->emit(Ljava/lang/Object;Lkotlin/coroutines/Continuation;)Ljava/lang/Object;
+HSPLandroidx/compose/ui/platform/WindowRecomposer_androidKt$createLifecycleAwareWindowRecomposer$2$onStateChanged$1$1$1;-><init>(Lkotlinx/coroutines/flow/StateFlow;Landroidx/compose/ui/platform/MotionDurationScaleImpl;Lkotlin/coroutines/Continuation;)V
+HSPLandroidx/compose/ui/platform/WindowRecomposer_androidKt$createLifecycleAwareWindowRecomposer$2$onStateChanged$1$1$1;->create(Ljava/lang/Object;Lkotlin/coroutines/Continuation;)Lkotlin/coroutines/Continuation;
+HSPLandroidx/compose/ui/platform/WindowRecomposer_androidKt$createLifecycleAwareWindowRecomposer$2$onStateChanged$1$1$1;->invokeSuspend(Ljava/lang/Object;)Ljava/lang/Object;
+HSPLandroidx/compose/ui/platform/WindowRecomposer_androidKt$createLifecycleAwareWindowRecomposer$2$onStateChanged$1;-><init>(Lkotlin/jvm/internal/Ref$ObjectRef;Landroidx/compose/runtime/Recomposer;Landroidx/lifecycle/LifecycleOwner;Landroidx/compose/ui/platform/WindowRecomposer_androidKt$createLifecycleAwareWindowRecomposer$2;Landroid/view/View;Lkotlin/coroutines/Continuation;)V
+HSPLandroidx/compose/ui/platform/WindowRecomposer_androidKt$createLifecycleAwareWindowRecomposer$2$onStateChanged$1;->create(Ljava/lang/Object;Lkotlin/coroutines/Continuation;)Lkotlin/coroutines/Continuation;
+HSPLandroidx/compose/ui/platform/WindowRecomposer_androidKt$createLifecycleAwareWindowRecomposer$2$onStateChanged$1;->invoke(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;
+HSPLandroidx/compose/ui/platform/WindowRecomposer_androidKt$createLifecycleAwareWindowRecomposer$2$onStateChanged$1;->invoke(Lkotlinx/coroutines/CoroutineScope;Lkotlin/coroutines/Continuation;)Ljava/lang/Object;
+HSPLandroidx/compose/ui/platform/WindowRecomposer_androidKt$createLifecycleAwareWindowRecomposer$2$onStateChanged$1;->invokeSuspend(Ljava/lang/Object;)Ljava/lang/Object;
+HSPLandroidx/compose/ui/platform/WindowRecomposer_androidKt$createLifecycleAwareWindowRecomposer$2;-><init>(Lkotlinx/coroutines/CoroutineScope;Landroidx/compose/runtime/PausableMonotonicFrameClock;Landroidx/compose/runtime/Recomposer;Lkotlin/jvm/internal/Ref$ObjectRef;Landroid/view/View;)V
+HSPLandroidx/compose/ui/platform/WindowRecomposer_androidKt$createLifecycleAwareWindowRecomposer$2;->onStateChanged(Landroidx/lifecycle/LifecycleOwner;Landroidx/lifecycle/Lifecycle$Event;)V
+HSPLandroidx/compose/ui/platform/WindowRecomposer_androidKt$getAnimationScaleFlowFor$1$1$1;-><init>(Landroid/content/ContentResolver;Landroid/net/Uri;Landroidx/compose/ui/platform/WindowRecomposer_androidKt$getAnimationScaleFlowFor$1$1$contentObserver$1;Lkotlinx/coroutines/channels/Channel;Landroid/content/Context;Lkotlin/coroutines/Continuation;)V
+HSPLandroidx/compose/ui/platform/WindowRecomposer_androidKt$getAnimationScaleFlowFor$1$1$1;->create(Ljava/lang/Object;Lkotlin/coroutines/Continuation;)Lkotlin/coroutines/Continuation;
+HSPLandroidx/compose/ui/platform/WindowRecomposer_androidKt$getAnimationScaleFlowFor$1$1$1;->invoke(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;
+HSPLandroidx/compose/ui/platform/WindowRecomposer_androidKt$getAnimationScaleFlowFor$1$1$1;->invoke(Lkotlinx/coroutines/flow/FlowCollector;Lkotlin/coroutines/Continuation;)Ljava/lang/Object;
+HSPLandroidx/compose/ui/platform/WindowRecomposer_androidKt$getAnimationScaleFlowFor$1$1$1;->invokeSuspend(Ljava/lang/Object;)Ljava/lang/Object;
+HSPLandroidx/compose/ui/platform/WindowRecomposer_androidKt$getAnimationScaleFlowFor$1$1$contentObserver$1;-><init>(Lkotlinx/coroutines/channels/Channel;Landroid/os/Handler;)V
+HSPLandroidx/compose/ui/platform/WindowRecomposer_androidKt;-><clinit>()V
+HSPLandroidx/compose/ui/platform/WindowRecomposer_androidKt;->access$getAnimationScaleFlowFor(Landroid/content/Context;)Lkotlinx/coroutines/flow/StateFlow;
+HSPLandroidx/compose/ui/platform/WindowRecomposer_androidKt;->createLifecycleAwareWindowRecomposer$default(Landroid/view/View;Lkotlin/coroutines/CoroutineContext;Landroidx/lifecycle/Lifecycle;ILjava/lang/Object;)Landroidx/compose/runtime/Recomposer;
+HSPLandroidx/compose/ui/platform/WindowRecomposer_androidKt;->createLifecycleAwareWindowRecomposer(Landroid/view/View;Lkotlin/coroutines/CoroutineContext;Landroidx/lifecycle/Lifecycle;)Landroidx/compose/runtime/Recomposer;
+HSPLandroidx/compose/ui/platform/WindowRecomposer_androidKt;->findViewTreeCompositionContext(Landroid/view/View;)Landroidx/compose/runtime/CompositionContext;
+HSPLandroidx/compose/ui/platform/WindowRecomposer_androidKt;->getAnimationScaleFlowFor(Landroid/content/Context;)Lkotlinx/coroutines/flow/StateFlow;
+HSPLandroidx/compose/ui/platform/WindowRecomposer_androidKt;->getCompositionContext(Landroid/view/View;)Landroidx/compose/runtime/CompositionContext;
+HSPLandroidx/compose/ui/platform/WindowRecomposer_androidKt;->getContentChild(Landroid/view/View;)Landroid/view/View;
+HSPLandroidx/compose/ui/platform/WindowRecomposer_androidKt;->getWindowRecomposer(Landroid/view/View;)Landroidx/compose/runtime/Recomposer;
+HSPLandroidx/compose/ui/platform/WindowRecomposer_androidKt;->setCompositionContext(Landroid/view/View;Landroidx/compose/runtime/CompositionContext;)V
+HSPLandroidx/compose/ui/platform/WrappedComposition$setContent$1$1$1;-><init>(Landroidx/compose/ui/platform/WrappedComposition;Lkotlin/coroutines/Continuation;)V
+HSPLandroidx/compose/ui/platform/WrappedComposition$setContent$1$1$1;->create(Ljava/lang/Object;Lkotlin/coroutines/Continuation;)Lkotlin/coroutines/Continuation;
+HSPLandroidx/compose/ui/platform/WrappedComposition$setContent$1$1$1;->invokeSuspend(Ljava/lang/Object;)Ljava/lang/Object;
+HSPLandroidx/compose/ui/platform/WrappedComposition$setContent$1$1$2;-><init>(Landroidx/compose/ui/platform/WrappedComposition;Lkotlin/coroutines/Continuation;)V
+HSPLandroidx/compose/ui/platform/WrappedComposition$setContent$1$1$2;->create(Ljava/lang/Object;Lkotlin/coroutines/Continuation;)Lkotlin/coroutines/Continuation;
+HSPLandroidx/compose/ui/platform/WrappedComposition$setContent$1$1$2;->invokeSuspend(Ljava/lang/Object;)Ljava/lang/Object;
+HSPLandroidx/compose/ui/platform/WrappedComposition$setContent$1$1$3;-><init>(Landroidx/compose/ui/platform/WrappedComposition;Lkotlin/jvm/functions/Function2;)V
+HSPLandroidx/compose/ui/platform/WrappedComposition$setContent$1$1$3;->invoke(Landroidx/compose/runtime/Composer;I)V
+HSPLandroidx/compose/ui/platform/WrappedComposition$setContent$1$1$3;->invoke(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;
+HSPLandroidx/compose/ui/platform/WrappedComposition$setContent$1$1;-><init>(Landroidx/compose/ui/platform/WrappedComposition;Lkotlin/jvm/functions/Function2;)V
+HSPLandroidx/compose/ui/platform/WrappedComposition$setContent$1$1;->invoke(Landroidx/compose/runtime/Composer;I)V
+HSPLandroidx/compose/ui/platform/WrappedComposition$setContent$1$1;->invoke(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;
+HSPLandroidx/compose/ui/platform/WrappedComposition$setContent$1;-><init>(Landroidx/compose/ui/platform/WrappedComposition;Lkotlin/jvm/functions/Function2;)V
+HSPLandroidx/compose/ui/platform/WrappedComposition$setContent$1;->invoke(Landroidx/compose/ui/platform/AndroidComposeView$ViewTreeOwners;)V
+HSPLandroidx/compose/ui/platform/WrappedComposition$setContent$1;->invoke(Ljava/lang/Object;)Ljava/lang/Object;
+HSPLandroidx/compose/ui/platform/WrappedComposition;-><init>(Landroidx/compose/ui/platform/AndroidComposeView;Landroidx/compose/runtime/Composition;)V
+HSPLandroidx/compose/ui/platform/WrappedComposition;->access$getAddedToLifecycle$p(Landroidx/compose/ui/platform/WrappedComposition;)Landroidx/lifecycle/Lifecycle;
+HSPLandroidx/compose/ui/platform/WrappedComposition;->access$getDisposed$p(Landroidx/compose/ui/platform/WrappedComposition;)Z
+HSPLandroidx/compose/ui/platform/WrappedComposition;->access$setAddedToLifecycle$p(Landroidx/compose/ui/platform/WrappedComposition;Landroidx/lifecycle/Lifecycle;)V
+HSPLandroidx/compose/ui/platform/WrappedComposition;->access$setLastContent$p(Landroidx/compose/ui/platform/WrappedComposition;Lkotlin/jvm/functions/Function2;)V
+HSPLandroidx/compose/ui/platform/WrappedComposition;->getOriginal()Landroidx/compose/runtime/Composition;
+HSPLandroidx/compose/ui/platform/WrappedComposition;->getOwner()Landroidx/compose/ui/platform/AndroidComposeView;
+HSPLandroidx/compose/ui/platform/WrappedComposition;->onStateChanged(Landroidx/lifecycle/LifecycleOwner;Landroidx/lifecycle/Lifecycle$Event;)V
+HSPLandroidx/compose/ui/platform/WrappedComposition;->setContent(Lkotlin/jvm/functions/Function2;)V
+HSPLandroidx/compose/ui/platform/WrapperRenderNodeLayerHelperMethods;-><clinit>()V
+HSPLandroidx/compose/ui/platform/WrapperRenderNodeLayerHelperMethods;-><init>()V
+HSPLandroidx/compose/ui/platform/WrapperRenderNodeLayerHelperMethods;->onDescendantInvalidated(Landroidx/compose/ui/platform/AndroidComposeView;)V
+HSPLandroidx/compose/ui/platform/WrapperVerificationHelperMethods;-><clinit>()V
+HSPLandroidx/compose/ui/platform/WrapperVerificationHelperMethods;-><init>()V
+HSPLandroidx/compose/ui/platform/WrapperVerificationHelperMethods;->attributeSourceResourceMap(Landroid/view/View;)Ljava/util/Map;
+HSPLandroidx/compose/ui/platform/Wrapper_androidKt;-><clinit>()V
+HSPLandroidx/compose/ui/platform/Wrapper_androidKt;->createSubcomposition(Landroidx/compose/ui/node/LayoutNode;Landroidx/compose/runtime/CompositionContext;)Landroidx/compose/runtime/Composition;
+HSPLandroidx/compose/ui/platform/Wrapper_androidKt;->doSetContent(Landroidx/compose/ui/platform/AndroidComposeView;Landroidx/compose/runtime/CompositionContext;Lkotlin/jvm/functions/Function2;)Landroidx/compose/runtime/Composition;
+HSPLandroidx/compose/ui/platform/Wrapper_androidKt;->inspectionWanted(Landroidx/compose/ui/platform/AndroidComposeView;)Z
+HSPLandroidx/compose/ui/platform/Wrapper_androidKt;->setContent(Landroidx/compose/ui/platform/AbstractComposeView;Landroidx/compose/runtime/CompositionContext;Lkotlin/jvm/functions/Function2;)Landroidx/compose/runtime/Composition;
+HSPLandroidx/compose/ui/platform/actionmodecallback/TextActionModeCallback;-><init>(Lkotlin/jvm/functions/Function0;Landroidx/compose/ui/geometry/Rect;Lkotlin/jvm/functions/Function0;Lkotlin/jvm/functions/Function0;Lkotlin/jvm/functions/Function0;Lkotlin/jvm/functions/Function0;)V
+HSPLandroidx/compose/ui/platform/actionmodecallback/TextActionModeCallback;-><init>(Lkotlin/jvm/functions/Function0;Landroidx/compose/ui/geometry/Rect;Lkotlin/jvm/functions/Function0;Lkotlin/jvm/functions/Function0;Lkotlin/jvm/functions/Function0;Lkotlin/jvm/functions/Function0;ILkotlin/jvm/internal/DefaultConstructorMarker;)V
+HSPLandroidx/compose/ui/res/ImageVectorCache;-><init>()V
+HSPLandroidx/compose/ui/res/Resources_androidKt;->resources(Landroidx/compose/runtime/Composer;I)Landroid/content/res/Resources;
+HSPLandroidx/compose/ui/res/StringResources_androidKt;->stringResource(ILandroidx/compose/runtime/Composer;I)Ljava/lang/String;
+HSPLandroidx/compose/ui/res/StringResources_androidKt;->stringResource(I[Ljava/lang/Object;Landroidx/compose/runtime/Composer;I)Ljava/lang/String;
+HSPLandroidx/compose/ui/semantics/AccessibilityAction;-><clinit>()V
+HSPLandroidx/compose/ui/semantics/AccessibilityAction;-><init>(Ljava/lang/String;Lkotlin/Function;)V
+HSPLandroidx/compose/ui/semantics/AccessibilityAction;->equals(Ljava/lang/Object;)Z
+HSPLandroidx/compose/ui/semantics/Role$Companion;-><init>()V
+HSPLandroidx/compose/ui/semantics/Role$Companion;-><init>(Lkotlin/jvm/internal/DefaultConstructorMarker;)V
+HSPLandroidx/compose/ui/semantics/Role$Companion;->getButton-o7Vup1c()I
+HSPLandroidx/compose/ui/semantics/Role;-><clinit>()V
+HSPLandroidx/compose/ui/semantics/Role;-><init>(I)V
+HSPLandroidx/compose/ui/semantics/Role;->access$getButton$cp()I
+HSPLandroidx/compose/ui/semantics/Role;->box-impl(I)Landroidx/compose/ui/semantics/Role;
+HSPLandroidx/compose/ui/semantics/Role;->constructor-impl(I)I
+HSPLandroidx/compose/ui/semantics/Role;->equals(Ljava/lang/Object;)Z
+HSPLandroidx/compose/ui/semantics/Role;->equals-impl(ILjava/lang/Object;)Z
+HSPLandroidx/compose/ui/semantics/Role;->unbox-impl()I
+HSPLandroidx/compose/ui/semantics/SemanticsActions;-><clinit>()V
+HSPLandroidx/compose/ui/semantics/SemanticsActions;-><init>()V
+HSPLandroidx/compose/ui/semantics/SemanticsActions;->getCustomActions()Landroidx/compose/ui/semantics/SemanticsPropertyKey;
+HSPLandroidx/compose/ui/semantics/SemanticsActions;->getDismiss()Landroidx/compose/ui/semantics/SemanticsPropertyKey;
+HSPLandroidx/compose/ui/semantics/SemanticsActions;->getGetTextLayoutResult()Landroidx/compose/ui/semantics/SemanticsPropertyKey;
+HSPLandroidx/compose/ui/semantics/SemanticsActions;->getOnClick()Landroidx/compose/ui/semantics/SemanticsPropertyKey;
+HSPLandroidx/compose/ui/semantics/SemanticsActions;->getRequestFocus()Landroidx/compose/ui/semantics/SemanticsPropertyKey;
+HSPLandroidx/compose/ui/semantics/SemanticsConfiguration;-><clinit>()V
+HSPLandroidx/compose/ui/semantics/SemanticsConfiguration;-><init>()V
+HSPLandroidx/compose/ui/semantics/SemanticsConfiguration;->contains(Landroidx/compose/ui/semantics/SemanticsPropertyKey;)Z
+HSPLandroidx/compose/ui/semantics/SemanticsConfiguration;->equals(Ljava/lang/Object;)Z
+HSPLandroidx/compose/ui/semantics/SemanticsConfiguration;->getOrElseNullable(Landroidx/compose/ui/semantics/SemanticsPropertyKey;Lkotlin/jvm/functions/Function0;)Ljava/lang/Object;
+HSPLandroidx/compose/ui/semantics/SemanticsConfiguration;->isClearingSemantics()Z
+HSPLandroidx/compose/ui/semantics/SemanticsConfiguration;->set(Landroidx/compose/ui/semantics/SemanticsPropertyKey;Ljava/lang/Object;)V
+HSPLandroidx/compose/ui/semantics/SemanticsConfiguration;->setClearingSemantics(Z)V
+HSPLandroidx/compose/ui/semantics/SemanticsConfiguration;->setMergingSemanticsOfDescendants(Z)V
+HSPLandroidx/compose/ui/semantics/SemanticsConfigurationKt$getOrNull$1;-><clinit>()V
+HSPLandroidx/compose/ui/semantics/SemanticsConfigurationKt$getOrNull$1;-><init>()V
+HSPLandroidx/compose/ui/semantics/SemanticsConfigurationKt$getOrNull$1;->invoke()Ljava/lang/Object;
+HSPLandroidx/compose/ui/semantics/SemanticsConfigurationKt;->getOrNull(Landroidx/compose/ui/semantics/SemanticsConfiguration;Landroidx/compose/ui/semantics/SemanticsPropertyKey;)Ljava/lang/Object;
+HSPLandroidx/compose/ui/semantics/SemanticsModifierCore$Companion;-><init>()V
+HSPLandroidx/compose/ui/semantics/SemanticsModifierCore$Companion;-><init>(Lkotlin/jvm/internal/DefaultConstructorMarker;)V
+HSPLandroidx/compose/ui/semantics/SemanticsModifierCore$Companion;->generateSemanticsId()I
+HSPLandroidx/compose/ui/semantics/SemanticsModifierCore;-><clinit>()V
+HSPLandroidx/compose/ui/semantics/SemanticsModifierCore;-><init>(ZZLkotlin/jvm/functions/Function1;Lkotlin/jvm/functions/Function1;)V
+HSPLandroidx/compose/ui/semantics/SemanticsModifierCore;-><init>(ZZLkotlin/jvm/functions/Function1;Lkotlin/jvm/functions/Function1;ILkotlin/jvm/internal/DefaultConstructorMarker;)V
+HSPLandroidx/compose/ui/semantics/SemanticsModifierCore;->access$getLastIdentifier$cp()Ljava/util/concurrent/atomic/AtomicInteger;
+HSPLandroidx/compose/ui/semantics/SemanticsModifierCore;->equals(Ljava/lang/Object;)Z
+HSPLandroidx/compose/ui/semantics/SemanticsModifierCore;->getSemanticsConfiguration()Landroidx/compose/ui/semantics/SemanticsConfiguration;
+HSPLandroidx/compose/ui/semantics/SemanticsModifierKt;->semantics$default(Landroidx/compose/ui/Modifier;ZLkotlin/jvm/functions/Function1;ILjava/lang/Object;)Landroidx/compose/ui/Modifier;
+HSPLandroidx/compose/ui/semantics/SemanticsModifierKt;->semantics(Landroidx/compose/ui/Modifier;ZLkotlin/jvm/functions/Function1;)Landroidx/compose/ui/Modifier;
+HSPLandroidx/compose/ui/semantics/SemanticsNode;-><clinit>()V
+HSPLandroidx/compose/ui/semantics/SemanticsNode;-><init>(Landroidx/compose/ui/node/SemanticsModifierNode;ZLandroidx/compose/ui/node/LayoutNode;)V
+HSPLandroidx/compose/ui/semantics/SemanticsNode;-><init>(Landroidx/compose/ui/node/SemanticsModifierNode;ZLandroidx/compose/ui/node/LayoutNode;ILkotlin/jvm/internal/DefaultConstructorMarker;)V
+HSPLandroidx/compose/ui/semantics/SemanticsNode;->emitFakeNodes(Ljava/util/List;)V
+HSPLandroidx/compose/ui/semantics/SemanticsNode;->getChildren(ZZZ)Ljava/util/List;
+HSPLandroidx/compose/ui/semantics/SemanticsNode;->getReplacedChildren$ui_release()Ljava/util/List;
+HSPLandroidx/compose/ui/semantics/SemanticsNode;->getUnmergedConfig$ui_release()Landroidx/compose/ui/semantics/SemanticsConfiguration;
+HSPLandroidx/compose/ui/semantics/SemanticsNode;->isMergingSemanticsOfDescendants()Z
+HSPLandroidx/compose/ui/semantics/SemanticsNode;->unmergedChildren$ui_release(ZZ)Ljava/util/List;
+HSPLandroidx/compose/ui/semantics/SemanticsNodeKt;->access$getRole(Landroidx/compose/ui/semantics/SemanticsNode;)Landroidx/compose/ui/semantics/Role;
+HSPLandroidx/compose/ui/semantics/SemanticsNodeKt;->findOneLayerOfSemanticsWrappers$default(Landroidx/compose/ui/node/LayoutNode;Ljava/util/List;ILjava/lang/Object;)Ljava/util/List;
+HSPLandroidx/compose/ui/semantics/SemanticsNodeKt;->findOneLayerOfSemanticsWrappers(Landroidx/compose/ui/node/LayoutNode;Ljava/util/List;)Ljava/util/List;
+HSPLandroidx/compose/ui/semantics/SemanticsNodeKt;->getOuterSemantics(Landroidx/compose/ui/node/LayoutNode;)Landroidx/compose/ui/node/SemanticsModifierNode;
+HSPLandroidx/compose/ui/semantics/SemanticsNodeKt;->getRole(Landroidx/compose/ui/semantics/SemanticsNode;)Landroidx/compose/ui/semantics/Role;
+HSPLandroidx/compose/ui/semantics/SemanticsOwner;-><clinit>()V
+HSPLandroidx/compose/ui/semantics/SemanticsOwner;-><init>(Landroidx/compose/ui/node/LayoutNode;)V
+HSPLandroidx/compose/ui/semantics/SemanticsOwner;->getUnmergedRootSemanticsNode()Landroidx/compose/ui/semantics/SemanticsNode;
+HSPLandroidx/compose/ui/semantics/SemanticsProperties$ContentDescription$1;-><clinit>()V
+HSPLandroidx/compose/ui/semantics/SemanticsProperties$ContentDescription$1;-><init>()V
+HSPLandroidx/compose/ui/semantics/SemanticsProperties$InvisibleToUser$1;-><clinit>()V
+HSPLandroidx/compose/ui/semantics/SemanticsProperties$InvisibleToUser$1;-><init>()V
+HSPLandroidx/compose/ui/semantics/SemanticsProperties$IsDialog$1;-><clinit>()V
+HSPLandroidx/compose/ui/semantics/SemanticsProperties$IsDialog$1;-><init>()V
+HSPLandroidx/compose/ui/semantics/SemanticsProperties$IsPopup$1;-><clinit>()V
+HSPLandroidx/compose/ui/semantics/SemanticsProperties$IsPopup$1;-><init>()V
+HSPLandroidx/compose/ui/semantics/SemanticsProperties$PaneTitle$1;-><clinit>()V
+HSPLandroidx/compose/ui/semantics/SemanticsProperties$PaneTitle$1;-><init>()V
+HSPLandroidx/compose/ui/semantics/SemanticsProperties$Role$1;-><clinit>()V
+HSPLandroidx/compose/ui/semantics/SemanticsProperties$Role$1;-><init>()V
+HSPLandroidx/compose/ui/semantics/SemanticsProperties$TestTag$1;-><clinit>()V
+HSPLandroidx/compose/ui/semantics/SemanticsProperties$TestTag$1;-><init>()V
+HSPLandroidx/compose/ui/semantics/SemanticsProperties$Text$1;-><clinit>()V
+HSPLandroidx/compose/ui/semantics/SemanticsProperties$Text$1;-><init>()V
+HSPLandroidx/compose/ui/semantics/SemanticsProperties;-><clinit>()V
+HSPLandroidx/compose/ui/semantics/SemanticsProperties;-><init>()V
+HSPLandroidx/compose/ui/semantics/SemanticsProperties;->getCollectionInfo()Landroidx/compose/ui/semantics/SemanticsPropertyKey;
+HSPLandroidx/compose/ui/semantics/SemanticsProperties;->getCollectionItemInfo()Landroidx/compose/ui/semantics/SemanticsPropertyKey;
+HSPLandroidx/compose/ui/semantics/SemanticsProperties;->getContentDescription()Landroidx/compose/ui/semantics/SemanticsPropertyKey;
+HSPLandroidx/compose/ui/semantics/SemanticsProperties;->getEditableText()Landroidx/compose/ui/semantics/SemanticsPropertyKey;
+HSPLandroidx/compose/ui/semantics/SemanticsProperties;->getFocused()Landroidx/compose/ui/semantics/SemanticsPropertyKey;
+HSPLandroidx/compose/ui/semantics/SemanticsProperties;->getHorizontalScrollAxisRange()Landroidx/compose/ui/semantics/SemanticsPropertyKey;
+HSPLandroidx/compose/ui/semantics/SemanticsProperties;->getImeAction()Landroidx/compose/ui/semantics/SemanticsPropertyKey;
+HSPLandroidx/compose/ui/semantics/SemanticsProperties;->getLiveRegion()Landroidx/compose/ui/semantics/SemanticsPropertyKey;
+HSPLandroidx/compose/ui/semantics/SemanticsProperties;->getPaneTitle()Landroidx/compose/ui/semantics/SemanticsPropertyKey;
+HSPLandroidx/compose/ui/semantics/SemanticsProperties;->getProgressBarRangeInfo()Landroidx/compose/ui/semantics/SemanticsPropertyKey;
+HSPLandroidx/compose/ui/semantics/SemanticsProperties;->getRole()Landroidx/compose/ui/semantics/SemanticsPropertyKey;
+HSPLandroidx/compose/ui/semantics/SemanticsProperties;->getSelected()Landroidx/compose/ui/semantics/SemanticsPropertyKey;
+HSPLandroidx/compose/ui/semantics/SemanticsProperties;->getStateDescription()Landroidx/compose/ui/semantics/SemanticsPropertyKey;
+HSPLandroidx/compose/ui/semantics/SemanticsProperties;->getTestTag()Landroidx/compose/ui/semantics/SemanticsPropertyKey;
+HSPLandroidx/compose/ui/semantics/SemanticsProperties;->getText()Landroidx/compose/ui/semantics/SemanticsPropertyKey;
+HSPLandroidx/compose/ui/semantics/SemanticsProperties;->getTextSelectionRange()Landroidx/compose/ui/semantics/SemanticsPropertyKey;
+HSPLandroidx/compose/ui/semantics/SemanticsProperties;->getToggleableState()Landroidx/compose/ui/semantics/SemanticsPropertyKey;
+HSPLandroidx/compose/ui/semantics/SemanticsProperties;->getVerticalScrollAxisRange()Landroidx/compose/ui/semantics/SemanticsPropertyKey;
+HSPLandroidx/compose/ui/semantics/SemanticsPropertiesKt$ActionPropertyKey$1;-><clinit>()V
+HSPLandroidx/compose/ui/semantics/SemanticsPropertiesKt$ActionPropertyKey$1;-><init>()V
+HSPLandroidx/compose/ui/semantics/SemanticsPropertiesKt;-><clinit>()V
+HSPLandroidx/compose/ui/semantics/SemanticsPropertiesKt;->dismiss$default(Landroidx/compose/ui/semantics/SemanticsPropertyReceiver;Ljava/lang/String;Lkotlin/jvm/functions/Function0;ILjava/lang/Object;)V
+HSPLandroidx/compose/ui/semantics/SemanticsPropertiesKt;->dismiss(Landroidx/compose/ui/semantics/SemanticsPropertyReceiver;Ljava/lang/String;Lkotlin/jvm/functions/Function0;)V
+HSPLandroidx/compose/ui/semantics/SemanticsPropertiesKt;->getTextLayoutResult$default(Landroidx/compose/ui/semantics/SemanticsPropertyReceiver;Ljava/lang/String;Lkotlin/jvm/functions/Function1;ILjava/lang/Object;)V
+HSPLandroidx/compose/ui/semantics/SemanticsPropertiesKt;->getTextLayoutResult(Landroidx/compose/ui/semantics/SemanticsPropertyReceiver;Ljava/lang/String;Lkotlin/jvm/functions/Function1;)V
+HSPLandroidx/compose/ui/semantics/SemanticsPropertiesKt;->onClick$default(Landroidx/compose/ui/semantics/SemanticsPropertyReceiver;Ljava/lang/String;Lkotlin/jvm/functions/Function0;ILjava/lang/Object;)V
+HSPLandroidx/compose/ui/semantics/SemanticsPropertiesKt;->onClick(Landroidx/compose/ui/semantics/SemanticsPropertyReceiver;Ljava/lang/String;Lkotlin/jvm/functions/Function0;)V
+HSPLandroidx/compose/ui/semantics/SemanticsPropertiesKt;->requestFocus$default(Landroidx/compose/ui/semantics/SemanticsPropertyReceiver;Ljava/lang/String;Lkotlin/jvm/functions/Function0;ILjava/lang/Object;)V
+HSPLandroidx/compose/ui/semantics/SemanticsPropertiesKt;->requestFocus(Landroidx/compose/ui/semantics/SemanticsPropertyReceiver;Ljava/lang/String;Lkotlin/jvm/functions/Function0;)V
+HSPLandroidx/compose/ui/semantics/SemanticsPropertiesKt;->setContentDescription(Landroidx/compose/ui/semantics/SemanticsPropertyReceiver;Ljava/lang/String;)V
+HSPLandroidx/compose/ui/semantics/SemanticsPropertiesKt;->setFocused(Landroidx/compose/ui/semantics/SemanticsPropertyReceiver;Z)V
+HSPLandroidx/compose/ui/semantics/SemanticsPropertiesKt;->setRole-kuIjeqM(Landroidx/compose/ui/semantics/SemanticsPropertyReceiver;I)V
+HSPLandroidx/compose/ui/semantics/SemanticsPropertiesKt;->setText(Landroidx/compose/ui/semantics/SemanticsPropertyReceiver;Landroidx/compose/ui/text/AnnotatedString;)V
+HSPLandroidx/compose/ui/semantics/SemanticsPropertyKey$1;-><clinit>()V
+HSPLandroidx/compose/ui/semantics/SemanticsPropertyKey$1;-><init>()V
+HSPLandroidx/compose/ui/semantics/SemanticsPropertyKey;-><clinit>()V
+HSPLandroidx/compose/ui/semantics/SemanticsPropertyKey;-><init>(Ljava/lang/String;Lkotlin/jvm/functions/Function2;)V
+HSPLandroidx/compose/ui/semantics/SemanticsPropertyKey;-><init>(Ljava/lang/String;Lkotlin/jvm/functions/Function2;ILkotlin/jvm/internal/DefaultConstructorMarker;)V
+HSPLandroidx/compose/ui/semantics/SemanticsPropertyKey;->setValue(Landroidx/compose/ui/semantics/SemanticsPropertyReceiver;Lkotlin/reflect/KProperty;Ljava/lang/Object;)V
+HSPLandroidx/compose/ui/text/AndroidParagraph$wordBoundary$2;-><init>(Landroidx/compose/ui/text/AndroidParagraph;)V
+HSPLandroidx/compose/ui/text/AndroidParagraph;-><init>(Landroidx/compose/ui/text/platform/AndroidParagraphIntrinsics;IZJ)V
+HSPLandroidx/compose/ui/text/AndroidParagraph;-><init>(Landroidx/compose/ui/text/platform/AndroidParagraphIntrinsics;IZJLkotlin/jvm/internal/DefaultConstructorMarker;)V
+HSPLandroidx/compose/ui/text/AndroidParagraph;->constructTextLayout(IILandroid/text/TextUtils$TruncateAt;IIIII)Landroidx/compose/ui/text/android/TextLayout;
+HSPLandroidx/compose/ui/text/AndroidParagraph;->getDidExceedMaxLines()Z
+HSPLandroidx/compose/ui/text/AndroidParagraph;->getFirstBaseline()F
+HSPLandroidx/compose/ui/text/AndroidParagraph;->getHeight()F
+HSPLandroidx/compose/ui/text/AndroidParagraph;->getLastBaseline()F
+HSPLandroidx/compose/ui/text/AndroidParagraph;->getLineBaseline$ui_text_release(I)F
+HSPLandroidx/compose/ui/text/AndroidParagraph;->getLineCount()I
+HSPLandroidx/compose/ui/text/AndroidParagraph;->getPlaceholderRects()Ljava/util/List;
+HSPLandroidx/compose/ui/text/AndroidParagraph;->getShaderBrushSpans(Landroidx/compose/ui/text/android/TextLayout;)[Landroidx/compose/ui/text/platform/style/ShaderBrushSpan;
+HSPLandroidx/compose/ui/text/AndroidParagraph;->getTextPaint$ui_text_release()Landroidx/compose/ui/text/platform/AndroidTextPaint;
+HSPLandroidx/compose/ui/text/AndroidParagraph;->getWidth()F
+HSPLandroidx/compose/ui/text/AndroidParagraph;->paint(Landroidx/compose/ui/graphics/Canvas;)V
+HSPLandroidx/compose/ui/text/AndroidParagraph;->paint-iJQMabo(Landroidx/compose/ui/graphics/Canvas;JLandroidx/compose/ui/graphics/Shadow;Landroidx/compose/ui/text/style/TextDecoration;Landroidx/compose/ui/graphics/drawscope/DrawStyle;)V
+HSPLandroidx/compose/ui/text/AndroidParagraph_androidKt;->access$shouldAttachIndentationFixSpan(Landroidx/compose/ui/text/TextStyle;Z)Z
+HSPLandroidx/compose/ui/text/AndroidParagraph_androidKt;->access$toLayoutAlign-AMY3VfE(Landroidx/compose/ui/text/style/TextAlign;)I
+HSPLandroidx/compose/ui/text/AndroidParagraph_androidKt;->access$toLayoutBreakStrategy-u6PBz3U(Landroidx/compose/ui/text/style/LineBreak$Strategy;)I
+HSPLandroidx/compose/ui/text/AndroidParagraph_androidKt;->access$toLayoutHyphenationFrequency(Landroidx/compose/ui/text/style/Hyphens;)I
+HSPLandroidx/compose/ui/text/AndroidParagraph_androidKt;->access$toLayoutLineBreakStyle-4a2g8L8(Landroidx/compose/ui/text/style/LineBreak$Strictness;)I
+HSPLandroidx/compose/ui/text/AndroidParagraph_androidKt;->access$toLayoutLineBreakWordStyle-gvcdTPQ(Landroidx/compose/ui/text/style/LineBreak$WordBreak;)I
+HSPLandroidx/compose/ui/text/AndroidParagraph_androidKt;->shouldAttachIndentationFixSpan(Landroidx/compose/ui/text/TextStyle;Z)Z
+HSPLandroidx/compose/ui/text/AndroidParagraph_androidKt;->toLayoutAlign-AMY3VfE(Landroidx/compose/ui/text/style/TextAlign;)I
+HSPLandroidx/compose/ui/text/AndroidParagraph_androidKt;->toLayoutBreakStrategy-u6PBz3U(Landroidx/compose/ui/text/style/LineBreak$Strategy;)I
+HSPLandroidx/compose/ui/text/AndroidParagraph_androidKt;->toLayoutHyphenationFrequency(Landroidx/compose/ui/text/style/Hyphens;)I
+HSPLandroidx/compose/ui/text/AndroidParagraph_androidKt;->toLayoutLineBreakStyle-4a2g8L8(Landroidx/compose/ui/text/style/LineBreak$Strictness;)I
+HSPLandroidx/compose/ui/text/AndroidParagraph_androidKt;->toLayoutLineBreakWordStyle-gvcdTPQ(Landroidx/compose/ui/text/style/LineBreak$WordBreak;)I
+HSPLandroidx/compose/ui/text/AnnotatedString$Range;-><init>(Ljava/lang/Object;II)V
+HSPLandroidx/compose/ui/text/AnnotatedString$Range;-><init>(Ljava/lang/Object;IILjava/lang/String;)V
+HSPLandroidx/compose/ui/text/AnnotatedString$Range;->getEnd()I
+HSPLandroidx/compose/ui/text/AnnotatedString$Range;->getItem()Ljava/lang/Object;
+HSPLandroidx/compose/ui/text/AnnotatedString$Range;->getStart()I
+HSPLandroidx/compose/ui/text/AnnotatedString$special$$inlined$sortedBy$1;-><init>()V
+HSPLandroidx/compose/ui/text/AnnotatedString;-><init>(Ljava/lang/String;Ljava/util/List;Ljava/util/List;)V
+HSPLandroidx/compose/ui/text/AnnotatedString;-><init>(Ljava/lang/String;Ljava/util/List;Ljava/util/List;ILkotlin/jvm/internal/DefaultConstructorMarker;)V
+HSPLandroidx/compose/ui/text/AnnotatedString;-><init>(Ljava/lang/String;Ljava/util/List;Ljava/util/List;Ljava/util/List;)V
+HSPLandroidx/compose/ui/text/AnnotatedString;->equals(Ljava/lang/Object;)Z
+HSPLandroidx/compose/ui/text/AnnotatedString;->getParagraphStyles()Ljava/util/List;
+HSPLandroidx/compose/ui/text/AnnotatedString;->getSpanStyles()Ljava/util/List;
+HSPLandroidx/compose/ui/text/AnnotatedString;->getText()Ljava/lang/String;
+HSPLandroidx/compose/ui/text/AnnotatedStringKt;-><clinit>()V
+HSPLandroidx/compose/ui/text/AnnotatedStringKt;->access$substringWithoutParagraphStyles(Landroidx/compose/ui/text/AnnotatedString;II)Landroidx/compose/ui/text/AnnotatedString;
+HSPLandroidx/compose/ui/text/AnnotatedStringKt;->getLocalSpanStyles(Landroidx/compose/ui/text/AnnotatedString;II)Ljava/util/List;
+HSPLandroidx/compose/ui/text/AnnotatedStringKt;->normalizedParagraphStyles(Landroidx/compose/ui/text/AnnotatedString;Landroidx/compose/ui/text/ParagraphStyle;)Ljava/util/List;
+HSPLandroidx/compose/ui/text/AnnotatedStringKt;->substringWithoutParagraphStyles(Landroidx/compose/ui/text/AnnotatedString;II)Landroidx/compose/ui/text/AnnotatedString;
+HSPLandroidx/compose/ui/text/MultiParagraph;-><clinit>()V
+HSPLandroidx/compose/ui/text/MultiParagraph;-><init>(Landroidx/compose/ui/text/MultiParagraphIntrinsics;JIZ)V
+HSPLandroidx/compose/ui/text/MultiParagraph;-><init>(Landroidx/compose/ui/text/MultiParagraphIntrinsics;JIZLkotlin/jvm/internal/DefaultConstructorMarker;)V
+HSPLandroidx/compose/ui/text/MultiParagraph;->getDidExceedMaxLines()Z
+HSPLandroidx/compose/ui/text/MultiParagraph;->getFirstBaseline()F
+HSPLandroidx/compose/ui/text/MultiParagraph;->getHeight()F
+HSPLandroidx/compose/ui/text/MultiParagraph;->getIntrinsics()Landroidx/compose/ui/text/MultiParagraphIntrinsics;
+HSPLandroidx/compose/ui/text/MultiParagraph;->getLastBaseline()F
+HSPLandroidx/compose/ui/text/MultiParagraph;->getPlaceholderRects()Ljava/util/List;
+HSPLandroidx/compose/ui/text/MultiParagraph;->getWidth()F
+HSPLandroidx/compose/ui/text/MultiParagraph;->paint-iJQMabo(Landroidx/compose/ui/graphics/Canvas;JLandroidx/compose/ui/graphics/Shadow;Landroidx/compose/ui/text/style/TextDecoration;Landroidx/compose/ui/graphics/drawscope/DrawStyle;)V
+HSPLandroidx/compose/ui/text/MultiParagraphIntrinsics$maxIntrinsicWidth$2;-><init>(Landroidx/compose/ui/text/MultiParagraphIntrinsics;)V
+HSPLandroidx/compose/ui/text/MultiParagraphIntrinsics$maxIntrinsicWidth$2;->invoke()Ljava/lang/Float;
+HSPLandroidx/compose/ui/text/MultiParagraphIntrinsics$maxIntrinsicWidth$2;->invoke()Ljava/lang/Object;
+HSPLandroidx/compose/ui/text/MultiParagraphIntrinsics$minIntrinsicWidth$2;-><init>(Landroidx/compose/ui/text/MultiParagraphIntrinsics;)V
+HSPLandroidx/compose/ui/text/MultiParagraphIntrinsics;-><clinit>()V
+HSPLandroidx/compose/ui/text/MultiParagraphIntrinsics;-><init>(Landroidx/compose/ui/text/AnnotatedString;Landroidx/compose/ui/text/TextStyle;Ljava/util/List;Landroidx/compose/ui/unit/Density;Landroidx/compose/ui/text/font/FontFamily$Resolver;)V
+HSPLandroidx/compose/ui/text/MultiParagraphIntrinsics;->access$resolveTextDirection(Landroidx/compose/ui/text/MultiParagraphIntrinsics;Landroidx/compose/ui/text/ParagraphStyle;Landroidx/compose/ui/text/ParagraphStyle;)Landroidx/compose/ui/text/ParagraphStyle;
+HSPLandroidx/compose/ui/text/MultiParagraphIntrinsics;->getHasStaleResolvedFonts()Z
+HSPLandroidx/compose/ui/text/MultiParagraphIntrinsics;->getInfoList$ui_text_release()Ljava/util/List;
+HSPLandroidx/compose/ui/text/MultiParagraphIntrinsics;->getMaxIntrinsicWidth()F
+HSPLandroidx/compose/ui/text/MultiParagraphIntrinsics;->getPlaceholders()Ljava/util/List;
+HSPLandroidx/compose/ui/text/MultiParagraphIntrinsics;->resolveTextDirection(Landroidx/compose/ui/text/ParagraphStyle;Landroidx/compose/ui/text/ParagraphStyle;)Landroidx/compose/ui/text/ParagraphStyle;
+HSPLandroidx/compose/ui/text/MultiParagraphIntrinsicsKt;->access$getLocalPlaceholders(Ljava/util/List;II)Ljava/util/List;
+HSPLandroidx/compose/ui/text/MultiParagraphIntrinsicsKt;->getLocalPlaceholders(Ljava/util/List;II)Ljava/util/List;
+HSPLandroidx/compose/ui/text/ParagraphInfo;-><init>(Landroidx/compose/ui/text/Paragraph;IIIIFF)V
+HSPLandroidx/compose/ui/text/ParagraphInfo;->getParagraph()Landroidx/compose/ui/text/Paragraph;
+HSPLandroidx/compose/ui/text/ParagraphInfo;->toGlobalYPosition(F)F
+HSPLandroidx/compose/ui/text/ParagraphIntrinsicInfo;-><init>(Landroidx/compose/ui/text/ParagraphIntrinsics;II)V
+HSPLandroidx/compose/ui/text/ParagraphIntrinsicInfo;->getEndIndex()I
+HSPLandroidx/compose/ui/text/ParagraphIntrinsicInfo;->getIntrinsics()Landroidx/compose/ui/text/ParagraphIntrinsics;
+HSPLandroidx/compose/ui/text/ParagraphIntrinsicInfo;->getStartIndex()I
+HSPLandroidx/compose/ui/text/ParagraphIntrinsicsKt;->ParagraphIntrinsics(Ljava/lang/String;Landroidx/compose/ui/text/TextStyle;Ljava/util/List;Ljava/util/List;Landroidx/compose/ui/unit/Density;Landroidx/compose/ui/text/font/FontFamily$Resolver;)Landroidx/compose/ui/text/ParagraphIntrinsics;
+HSPLandroidx/compose/ui/text/ParagraphKt;->Paragraph-_EkL_-Y(Landroidx/compose/ui/text/ParagraphIntrinsics;JIZ)Landroidx/compose/ui/text/Paragraph;
+HSPLandroidx/compose/ui/text/ParagraphKt;->ceilToInt(F)I
+HSPLandroidx/compose/ui/text/ParagraphStyle;-><init>(Landroidx/compose/ui/text/style/TextAlign;Landroidx/compose/ui/text/style/TextDirection;JLandroidx/compose/ui/text/style/TextIndent;Landroidx/compose/ui/text/PlatformParagraphStyle;Landroidx/compose/ui/text/style/LineHeightStyle;Landroidx/compose/ui/text/style/LineBreak;Landroidx/compose/ui/text/style/Hyphens;)V
+HSPLandroidx/compose/ui/text/ParagraphStyle;-><init>(Landroidx/compose/ui/text/style/TextAlign;Landroidx/compose/ui/text/style/TextDirection;JLandroidx/compose/ui/text/style/TextIndent;Landroidx/compose/ui/text/PlatformParagraphStyle;Landroidx/compose/ui/text/style/LineHeightStyle;Landroidx/compose/ui/text/style/LineBreak;Landroidx/compose/ui/text/style/Hyphens;Lkotlin/jvm/internal/DefaultConstructorMarker;)V
+HSPLandroidx/compose/ui/text/ParagraphStyle;->equals(Ljava/lang/Object;)Z
+HSPLandroidx/compose/ui/text/ParagraphStyle;->getHyphens()Landroidx/compose/ui/text/style/Hyphens;
+HSPLandroidx/compose/ui/text/ParagraphStyle;->getLineBreak()Landroidx/compose/ui/text/style/LineBreak;
+HSPLandroidx/compose/ui/text/ParagraphStyle;->getLineHeight-XSAIIZE()J
+HSPLandroidx/compose/ui/text/ParagraphStyle;->getLineHeightStyle()Landroidx/compose/ui/text/style/LineHeightStyle;
+HSPLandroidx/compose/ui/text/ParagraphStyle;->getPlatformStyle()Landroidx/compose/ui/text/PlatformParagraphStyle;
+HSPLandroidx/compose/ui/text/ParagraphStyle;->getTextAlign-buA522U()Landroidx/compose/ui/text/style/TextAlign;
+HSPLandroidx/compose/ui/text/ParagraphStyle;->getTextDirection-mmuk1to()Landroidx/compose/ui/text/style/TextDirection;
+HSPLandroidx/compose/ui/text/ParagraphStyle;->getTextIndent()Landroidx/compose/ui/text/style/TextIndent;
+HSPLandroidx/compose/ui/text/ParagraphStyle;->merge(Landroidx/compose/ui/text/ParagraphStyle;)Landroidx/compose/ui/text/ParagraphStyle;
+HSPLandroidx/compose/ui/text/ParagraphStyle;->mergePlatformStyle(Landroidx/compose/ui/text/PlatformParagraphStyle;)Landroidx/compose/ui/text/PlatformParagraphStyle;
+HSPLandroidx/compose/ui/text/ParagraphStyleKt;-><clinit>()V
+HSPLandroidx/compose/ui/text/ParagraphStyleKt;->resolveParagraphStyleDefaults(Landroidx/compose/ui/text/ParagraphStyle;Landroidx/compose/ui/unit/LayoutDirection;)Landroidx/compose/ui/text/ParagraphStyle;
+HSPLandroidx/compose/ui/text/SpanStyle;-><init>(JJLandroidx/compose/ui/text/font/FontWeight;Landroidx/compose/ui/text/font/FontStyle;Landroidx/compose/ui/text/font/FontSynthesis;Landroidx/compose/ui/text/font/FontFamily;Ljava/lang/String;JLandroidx/compose/ui/text/style/BaselineShift;Landroidx/compose/ui/text/style/TextGeometricTransform;Landroidx/compose/ui/text/intl/LocaleList;JLandroidx/compose/ui/text/style/TextDecoration;Landroidx/compose/ui/graphics/Shadow;)V
+HSPLandroidx/compose/ui/text/SpanStyle;-><init>(JJLandroidx/compose/ui/text/font/FontWeight;Landroidx/compose/ui/text/font/FontStyle;Landroidx/compose/ui/text/font/FontSynthesis;Landroidx/compose/ui/text/font/FontFamily;Ljava/lang/String;JLandroidx/compose/ui/text/style/BaselineShift;Landroidx/compose/ui/text/style/TextGeometricTransform;Landroidx/compose/ui/text/intl/LocaleList;JLandroidx/compose/ui/text/style/TextDecoration;Landroidx/compose/ui/graphics/Shadow;ILkotlin/jvm/internal/DefaultConstructorMarker;)V
+HSPLandroidx/compose/ui/text/SpanStyle;-><init>(JJLandroidx/compose/ui/text/font/FontWeight;Landroidx/compose/ui/text/font/FontStyle;Landroidx/compose/ui/text/font/FontSynthesis;Landroidx/compose/ui/text/font/FontFamily;Ljava/lang/String;JLandroidx/compose/ui/text/style/BaselineShift;Landroidx/compose/ui/text/style/TextGeometricTransform;Landroidx/compose/ui/text/intl/LocaleList;JLandroidx/compose/ui/text/style/TextDecoration;Landroidx/compose/ui/graphics/Shadow;Landroidx/compose/ui/text/PlatformSpanStyle;)V
+HSPLandroidx/compose/ui/text/SpanStyle;-><init>(JJLandroidx/compose/ui/text/font/FontWeight;Landroidx/compose/ui/text/font/FontStyle;Landroidx/compose/ui/text/font/FontSynthesis;Landroidx/compose/ui/text/font/FontFamily;Ljava/lang/String;JLandroidx/compose/ui/text/style/BaselineShift;Landroidx/compose/ui/text/style/TextGeometricTransform;Landroidx/compose/ui/text/intl/LocaleList;JLandroidx/compose/ui/text/style/TextDecoration;Landroidx/compose/ui/graphics/Shadow;Landroidx/compose/ui/text/PlatformSpanStyle;Lkotlin/jvm/internal/DefaultConstructorMarker;)V
+HSPLandroidx/compose/ui/text/SpanStyle;-><init>(JJLandroidx/compose/ui/text/font/FontWeight;Landroidx/compose/ui/text/font/FontStyle;Landroidx/compose/ui/text/font/FontSynthesis;Landroidx/compose/ui/text/font/FontFamily;Ljava/lang/String;JLandroidx/compose/ui/text/style/BaselineShift;Landroidx/compose/ui/text/style/TextGeometricTransform;Landroidx/compose/ui/text/intl/LocaleList;JLandroidx/compose/ui/text/style/TextDecoration;Landroidx/compose/ui/graphics/Shadow;Lkotlin/jvm/internal/DefaultConstructorMarker;)V
+HSPLandroidx/compose/ui/text/SpanStyle;-><init>(Landroidx/compose/ui/text/style/TextForegroundStyle;JLandroidx/compose/ui/text/font/FontWeight;Landroidx/compose/ui/text/font/FontStyle;Landroidx/compose/ui/text/font/FontSynthesis;Landroidx/compose/ui/text/font/FontFamily;Ljava/lang/String;JLandroidx/compose/ui/text/style/BaselineShift;Landroidx/compose/ui/text/style/TextGeometricTransform;Landroidx/compose/ui/text/intl/LocaleList;JLandroidx/compose/ui/text/style/TextDecoration;Landroidx/compose/ui/graphics/Shadow;Landroidx/compose/ui/text/PlatformSpanStyle;Landroidx/compose/ui/graphics/drawscope/DrawStyle;)V
+HSPLandroidx/compose/ui/text/SpanStyle;-><init>(Landroidx/compose/ui/text/style/TextForegroundStyle;JLandroidx/compose/ui/text/font/FontWeight;Landroidx/compose/ui/text/font/FontStyle;Landroidx/compose/ui/text/font/FontSynthesis;Landroidx/compose/ui/text/font/FontFamily;Ljava/lang/String;JLandroidx/compose/ui/text/style/BaselineShift;Landroidx/compose/ui/text/style/TextGeometricTransform;Landroidx/compose/ui/text/intl/LocaleList;JLandroidx/compose/ui/text/style/TextDecoration;Landroidx/compose/ui/graphics/Shadow;Landroidx/compose/ui/text/PlatformSpanStyle;Landroidx/compose/ui/graphics/drawscope/DrawStyle;ILkotlin/jvm/internal/DefaultConstructorMarker;)V
+HSPLandroidx/compose/ui/text/SpanStyle;-><init>(Landroidx/compose/ui/text/style/TextForegroundStyle;JLandroidx/compose/ui/text/font/FontWeight;Landroidx/compose/ui/text/font/FontStyle;Landroidx/compose/ui/text/font/FontSynthesis;Landroidx/compose/ui/text/font/FontFamily;Ljava/lang/String;JLandroidx/compose/ui/text/style/BaselineShift;Landroidx/compose/ui/text/style/TextGeometricTransform;Landroidx/compose/ui/text/intl/LocaleList;JLandroidx/compose/ui/text/style/TextDecoration;Landroidx/compose/ui/graphics/Shadow;Landroidx/compose/ui/text/PlatformSpanStyle;Landroidx/compose/ui/graphics/drawscope/DrawStyle;Lkotlin/jvm/internal/DefaultConstructorMarker;)V
+HSPLandroidx/compose/ui/text/SpanStyle;->equals(Ljava/lang/Object;)Z
+HSPLandroidx/compose/ui/text/SpanStyle;->getAlpha()F
+HSPLandroidx/compose/ui/text/SpanStyle;->getBackground-0d7_KjU()J
+HSPLandroidx/compose/ui/text/SpanStyle;->getBaselineShift-5SSeXJ0()Landroidx/compose/ui/text/style/BaselineShift;
+HSPLandroidx/compose/ui/text/SpanStyle;->getBrush()Landroidx/compose/ui/graphics/Brush;
+HSPLandroidx/compose/ui/text/SpanStyle;->getColor-0d7_KjU()J
+HSPLandroidx/compose/ui/text/SpanStyle;->getDrawStyle()Landroidx/compose/ui/graphics/drawscope/DrawStyle;
+HSPLandroidx/compose/ui/text/SpanStyle;->getFontFamily()Landroidx/compose/ui/text/font/FontFamily;
+HSPLandroidx/compose/ui/text/SpanStyle;->getFontFeatureSettings()Ljava/lang/String;
+HSPLandroidx/compose/ui/text/SpanStyle;->getFontSize-XSAIIZE()J
+HSPLandroidx/compose/ui/text/SpanStyle;->getFontStyle-4Lr2A7w()Landroidx/compose/ui/text/font/FontStyle;
+HSPLandroidx/compose/ui/text/SpanStyle;->getFontSynthesis-ZQGJjVo()Landroidx/compose/ui/text/font/FontSynthesis;
+HSPLandroidx/compose/ui/text/SpanStyle;->getFontWeight()Landroidx/compose/ui/text/font/FontWeight;
+HSPLandroidx/compose/ui/text/SpanStyle;->getLetterSpacing-XSAIIZE()J
+HSPLandroidx/compose/ui/text/SpanStyle;->getLocaleList()Landroidx/compose/ui/text/intl/LocaleList;
+HSPLandroidx/compose/ui/text/SpanStyle;->getPlatformStyle()Landroidx/compose/ui/text/PlatformSpanStyle;
+HSPLandroidx/compose/ui/text/SpanStyle;->getShadow()Landroidx/compose/ui/graphics/Shadow;
+HSPLandroidx/compose/ui/text/SpanStyle;->getTextDecoration()Landroidx/compose/ui/text/style/TextDecoration;
+HSPLandroidx/compose/ui/text/SpanStyle;->getTextForegroundStyle$ui_text_release()Landroidx/compose/ui/text/style/TextForegroundStyle;
+HSPLandroidx/compose/ui/text/SpanStyle;->getTextGeometricTransform()Landroidx/compose/ui/text/style/TextGeometricTransform;
+HSPLandroidx/compose/ui/text/SpanStyle;->hasSameLayoutAffectingAttributes$ui_text_release(Landroidx/compose/ui/text/SpanStyle;)Z
+HSPLandroidx/compose/ui/text/SpanStyle;->hasSameNonLayoutAttributes(Landroidx/compose/ui/text/SpanStyle;)Z
+HSPLandroidx/compose/ui/text/SpanStyle;->merge(Landroidx/compose/ui/text/SpanStyle;)Landroidx/compose/ui/text/SpanStyle;
+HSPLandroidx/compose/ui/text/SpanStyle;->mergePlatformStyle(Landroidx/compose/ui/text/PlatformSpanStyle;)Landroidx/compose/ui/text/PlatformSpanStyle;
+HSPLandroidx/compose/ui/text/SpanStyleKt$resolveSpanStyleDefaults$1;-><clinit>()V
+HSPLandroidx/compose/ui/text/SpanStyleKt$resolveSpanStyleDefaults$1;-><init>()V
+HSPLandroidx/compose/ui/text/SpanStyleKt;-><clinit>()V
+HSPLandroidx/compose/ui/text/SpanStyleKt;->resolveSpanStyleDefaults(Landroidx/compose/ui/text/SpanStyle;)Landroidx/compose/ui/text/SpanStyle;
+HSPLandroidx/compose/ui/text/TextLayoutInput;-><clinit>()V
+HSPLandroidx/compose/ui/text/TextLayoutInput;-><init>(Landroidx/compose/ui/text/AnnotatedString;Landroidx/compose/ui/text/TextStyle;Ljava/util/List;IZILandroidx/compose/ui/unit/Density;Landroidx/compose/ui/unit/LayoutDirection;Landroidx/compose/ui/text/font/Font$ResourceLoader;Landroidx/compose/ui/text/font/FontFamily$Resolver;J)V
+HSPLandroidx/compose/ui/text/TextLayoutInput;-><init>(Landroidx/compose/ui/text/AnnotatedString;Landroidx/compose/ui/text/TextStyle;Ljava/util/List;IZILandroidx/compose/ui/unit/Density;Landroidx/compose/ui/unit/LayoutDirection;Landroidx/compose/ui/text/font/FontFamily$Resolver;J)V
+HSPLandroidx/compose/ui/text/TextLayoutInput;-><init>(Landroidx/compose/ui/text/AnnotatedString;Landroidx/compose/ui/text/TextStyle;Ljava/util/List;IZILandroidx/compose/ui/unit/Density;Landroidx/compose/ui/unit/LayoutDirection;Landroidx/compose/ui/text/font/FontFamily$Resolver;JLkotlin/jvm/internal/DefaultConstructorMarker;)V
+HSPLandroidx/compose/ui/text/TextLayoutInput;->equals(Ljava/lang/Object;)Z
+HSPLandroidx/compose/ui/text/TextLayoutInput;->getStyle()Landroidx/compose/ui/text/TextStyle;
+HSPLandroidx/compose/ui/text/TextLayoutInput;->getText()Landroidx/compose/ui/text/AnnotatedString;
+HSPLandroidx/compose/ui/text/TextLayoutResult;-><clinit>()V
+HSPLandroidx/compose/ui/text/TextLayoutResult;-><init>(Landroidx/compose/ui/text/TextLayoutInput;Landroidx/compose/ui/text/MultiParagraph;J)V
+HSPLandroidx/compose/ui/text/TextLayoutResult;-><init>(Landroidx/compose/ui/text/TextLayoutInput;Landroidx/compose/ui/text/MultiParagraph;JLkotlin/jvm/internal/DefaultConstructorMarker;)V
+HSPLandroidx/compose/ui/text/TextLayoutResult;->equals(Ljava/lang/Object;)Z
+HSPLandroidx/compose/ui/text/TextLayoutResult;->getDidOverflowHeight()Z
+HSPLandroidx/compose/ui/text/TextLayoutResult;->getDidOverflowWidth()Z
+HSPLandroidx/compose/ui/text/TextLayoutResult;->getFirstBaseline()F
+HSPLandroidx/compose/ui/text/TextLayoutResult;->getHasVisualOverflow()Z
+HSPLandroidx/compose/ui/text/TextLayoutResult;->getLastBaseline()F
+HSPLandroidx/compose/ui/text/TextLayoutResult;->getLayoutInput()Landroidx/compose/ui/text/TextLayoutInput;
+HSPLandroidx/compose/ui/text/TextLayoutResult;->getMultiParagraph()Landroidx/compose/ui/text/MultiParagraph;
+HSPLandroidx/compose/ui/text/TextLayoutResult;->getPlaceholderRects()Ljava/util/List;
+HSPLandroidx/compose/ui/text/TextLayoutResult;->getSize-YbymL2g()J
+HSPLandroidx/compose/ui/text/TextPainter;-><clinit>()V
+HSPLandroidx/compose/ui/text/TextPainter;-><init>()V
+HSPLandroidx/compose/ui/text/TextPainter;->paint(Landroidx/compose/ui/graphics/Canvas;Landroidx/compose/ui/text/TextLayoutResult;)V
+HSPLandroidx/compose/ui/text/TextRange$Companion;-><init>()V
+HSPLandroidx/compose/ui/text/TextRange$Companion;-><init>(Lkotlin/jvm/internal/DefaultConstructorMarker;)V
+HSPLandroidx/compose/ui/text/TextRange$Companion;->getZero-d9O1mEE()J
+HSPLandroidx/compose/ui/text/TextRange;-><clinit>()V
+HSPLandroidx/compose/ui/text/TextRange;->access$getZero$cp()J
+HSPLandroidx/compose/ui/text/TextRange;->constructor-impl(J)J
+HSPLandroidx/compose/ui/text/TextRange;->getEnd-impl(J)I
+HSPLandroidx/compose/ui/text/TextRange;->getStart-impl(J)I
+HSPLandroidx/compose/ui/text/TextRangeKt;->TextRange(I)J
+HSPLandroidx/compose/ui/text/TextRangeKt;->TextRange(II)J
+HSPLandroidx/compose/ui/text/TextRangeKt;->constrain-8ffj60Q(JII)J
+HSPLandroidx/compose/ui/text/TextRangeKt;->packWithCheck(II)J
+HSPLandroidx/compose/ui/text/TextStyle$Companion;-><init>()V
+HSPLandroidx/compose/ui/text/TextStyle$Companion;-><init>(Lkotlin/jvm/internal/DefaultConstructorMarker;)V
+HSPLandroidx/compose/ui/text/TextStyle$Companion;->getDefault()Landroidx/compose/ui/text/TextStyle;
+HSPLandroidx/compose/ui/text/TextStyle;-><clinit>()V
+HSPLandroidx/compose/ui/text/TextStyle;-><init>(JJLandroidx/compose/ui/text/font/FontWeight;Landroidx/compose/ui/text/font/FontStyle;Landroidx/compose/ui/text/font/FontSynthesis;Landroidx/compose/ui/text/font/FontFamily;Ljava/lang/String;JLandroidx/compose/ui/text/style/BaselineShift;Landroidx/compose/ui/text/style/TextGeometricTransform;Landroidx/compose/ui/text/intl/LocaleList;JLandroidx/compose/ui/text/style/TextDecoration;Landroidx/compose/ui/graphics/Shadow;Landroidx/compose/ui/text/style/TextAlign;Landroidx/compose/ui/text/style/TextDirection;JLandroidx/compose/ui/text/style/TextIndent;)V
+HSPLandroidx/compose/ui/text/TextStyle;-><init>(JJLandroidx/compose/ui/text/font/FontWeight;Landroidx/compose/ui/text/font/FontStyle;Landroidx/compose/ui/text/font/FontSynthesis;Landroidx/compose/ui/text/font/FontFamily;Ljava/lang/String;JLandroidx/compose/ui/text/style/BaselineShift;Landroidx/compose/ui/text/style/TextGeometricTransform;Landroidx/compose/ui/text/intl/LocaleList;JLandroidx/compose/ui/text/style/TextDecoration;Landroidx/compose/ui/graphics/Shadow;Landroidx/compose/ui/text/style/TextAlign;Landroidx/compose/ui/text/style/TextDirection;JLandroidx/compose/ui/text/style/TextIndent;ILkotlin/jvm/internal/DefaultConstructorMarker;)V
+HSPLandroidx/compose/ui/text/TextStyle;-><init>(JJLandroidx/compose/ui/text/font/FontWeight;Landroidx/compose/ui/text/font/FontStyle;Landroidx/compose/ui/text/font/FontSynthesis;Landroidx/compose/ui/text/font/FontFamily;Ljava/lang/String;JLandroidx/compose/ui/text/style/BaselineShift;Landroidx/compose/ui/text/style/TextGeometricTransform;Landroidx/compose/ui/text/intl/LocaleList;JLandroidx/compose/ui/text/style/TextDecoration;Landroidx/compose/ui/graphics/Shadow;Landroidx/compose/ui/text/style/TextAlign;Landroidx/compose/ui/text/style/TextDirection;JLandroidx/compose/ui/text/style/TextIndent;Lkotlin/jvm/internal/DefaultConstructorMarker;)V
+HSPLandroidx/compose/ui/text/TextStyle;-><init>(Landroidx/compose/ui/text/SpanStyle;Landroidx/compose/ui/text/ParagraphStyle;)V
+HSPLandroidx/compose/ui/text/TextStyle;-><init>(Landroidx/compose/ui/text/SpanStyle;Landroidx/compose/ui/text/ParagraphStyle;Landroidx/compose/ui/text/PlatformTextStyle;)V
+HSPLandroidx/compose/ui/text/TextStyle;->access$getDefault$cp()Landroidx/compose/ui/text/TextStyle;
+HSPLandroidx/compose/ui/text/TextStyle;->equals(Ljava/lang/Object;)Z
+HSPLandroidx/compose/ui/text/TextStyle;->getAlpha()F
+HSPLandroidx/compose/ui/text/TextStyle;->getBrush()Landroidx/compose/ui/graphics/Brush;
+HSPLandroidx/compose/ui/text/TextStyle;->getColor-0d7_KjU()J
+HSPLandroidx/compose/ui/text/TextStyle;->getFontFamily()Landroidx/compose/ui/text/font/FontFamily;
+HSPLandroidx/compose/ui/text/TextStyle;->getFontStyle-4Lr2A7w()Landroidx/compose/ui/text/font/FontStyle;
+HSPLandroidx/compose/ui/text/TextStyle;->getFontSynthesis-ZQGJjVo()Landroidx/compose/ui/text/font/FontSynthesis;
+HSPLandroidx/compose/ui/text/TextStyle;->getFontWeight()Landroidx/compose/ui/text/font/FontWeight;
+HSPLandroidx/compose/ui/text/TextStyle;->getLineBreak()Landroidx/compose/ui/text/style/LineBreak;
+HSPLandroidx/compose/ui/text/TextStyle;->getLineHeight-XSAIIZE()J
+HSPLandroidx/compose/ui/text/TextStyle;->getLineHeightStyle()Landroidx/compose/ui/text/style/LineHeightStyle;
+HSPLandroidx/compose/ui/text/TextStyle;->getLocaleList()Landroidx/compose/ui/text/intl/LocaleList;
+HSPLandroidx/compose/ui/text/TextStyle;->getParagraphStyle$ui_text_release()Landroidx/compose/ui/text/ParagraphStyle;
+HSPLandroidx/compose/ui/text/TextStyle;->getPlatformStyle()Landroidx/compose/ui/text/PlatformTextStyle;
+HSPLandroidx/compose/ui/text/TextStyle;->getSpanStyle$ui_text_release()Landroidx/compose/ui/text/SpanStyle;
+HSPLandroidx/compose/ui/text/TextStyle;->getTextAlign-buA522U()Landroidx/compose/ui/text/style/TextAlign;
+HSPLandroidx/compose/ui/text/TextStyle;->getTextDecoration()Landroidx/compose/ui/text/style/TextDecoration;
+HSPLandroidx/compose/ui/text/TextStyle;->getTextDirection-mmuk1to()Landroidx/compose/ui/text/style/TextDirection;
+HSPLandroidx/compose/ui/text/TextStyle;->getTextIndent()Landroidx/compose/ui/text/style/TextIndent;
+HSPLandroidx/compose/ui/text/TextStyle;->merge(Landroidx/compose/ui/text/ParagraphStyle;)Landroidx/compose/ui/text/TextStyle;
+HSPLandroidx/compose/ui/text/TextStyle;->merge(Landroidx/compose/ui/text/TextStyle;)Landroidx/compose/ui/text/TextStyle;
+HSPLandroidx/compose/ui/text/TextStyle;->toParagraphStyle()Landroidx/compose/ui/text/ParagraphStyle;
+HSPLandroidx/compose/ui/text/TextStyle;->toSpanStyle()Landroidx/compose/ui/text/SpanStyle;
+HSPLandroidx/compose/ui/text/TextStyleKt$WhenMappings;-><clinit>()V
+HSPLandroidx/compose/ui/text/TextStyleKt;->access$createPlatformTextStyleInternal(Landroidx/compose/ui/text/PlatformSpanStyle;Landroidx/compose/ui/text/PlatformParagraphStyle;)Landroidx/compose/ui/text/PlatformTextStyle;
+HSPLandroidx/compose/ui/text/TextStyleKt;->createPlatformTextStyleInternal(Landroidx/compose/ui/text/PlatformSpanStyle;Landroidx/compose/ui/text/PlatformParagraphStyle;)Landroidx/compose/ui/text/PlatformTextStyle;
+HSPLandroidx/compose/ui/text/TextStyleKt;->resolveDefaults(Landroidx/compose/ui/text/TextStyle;Landroidx/compose/ui/unit/LayoutDirection;)Landroidx/compose/ui/text/TextStyle;
+HSPLandroidx/compose/ui/text/TextStyleKt;->resolveTextDirection-Yj3eThk(Landroidx/compose/ui/unit/LayoutDirection;Landroidx/compose/ui/text/style/TextDirection;)I
+HSPLandroidx/compose/ui/text/android/BoringLayoutFactory33;-><clinit>()V
+HSPLandroidx/compose/ui/text/android/BoringLayoutFactory33;-><init>()V
+HSPLandroidx/compose/ui/text/android/BoringLayoutFactory33;->isBoring(Ljava/lang/CharSequence;Landroid/text/TextPaint;Landroid/text/TextDirectionHeuristic;)Landroid/text/BoringLayout$Metrics;
+HSPLandroidx/compose/ui/text/android/BoringLayoutFactory;-><clinit>()V
+HSPLandroidx/compose/ui/text/android/BoringLayoutFactory;-><init>()V
+HSPLandroidx/compose/ui/text/android/BoringLayoutFactory;->measure(Ljava/lang/CharSequence;Landroid/text/TextPaint;Landroid/text/TextDirectionHeuristic;)Landroid/text/BoringLayout$Metrics;
+HSPLandroidx/compose/ui/text/android/LayoutIntrinsics$boringMetrics$2;-><init>(ILjava/lang/CharSequence;Landroid/text/TextPaint;)V
+HSPLandroidx/compose/ui/text/android/LayoutIntrinsics$boringMetrics$2;->invoke()Landroid/text/BoringLayout$Metrics;
+HSPLandroidx/compose/ui/text/android/LayoutIntrinsics$boringMetrics$2;->invoke()Ljava/lang/Object;
+HSPLandroidx/compose/ui/text/android/LayoutIntrinsics$maxIntrinsicWidth$2;-><init>(Landroidx/compose/ui/text/android/LayoutIntrinsics;Ljava/lang/CharSequence;Landroid/text/TextPaint;)V
+HSPLandroidx/compose/ui/text/android/LayoutIntrinsics$maxIntrinsicWidth$2;->invoke()Ljava/lang/Float;
+HSPLandroidx/compose/ui/text/android/LayoutIntrinsics$maxIntrinsicWidth$2;->invoke()Ljava/lang/Object;
+HSPLandroidx/compose/ui/text/android/LayoutIntrinsics$minIntrinsicWidth$2;-><init>(Ljava/lang/CharSequence;Landroid/text/TextPaint;)V
+HSPLandroidx/compose/ui/text/android/LayoutIntrinsics;-><clinit>()V
+HSPLandroidx/compose/ui/text/android/LayoutIntrinsics;-><init>(Ljava/lang/CharSequence;Landroid/text/TextPaint;I)V
+HSPLandroidx/compose/ui/text/android/LayoutIntrinsics;->getBoringMetrics()Landroid/text/BoringLayout$Metrics;
+HSPLandroidx/compose/ui/text/android/LayoutIntrinsics;->getMaxIntrinsicWidth()F
+HSPLandroidx/compose/ui/text/android/LayoutIntrinsicsKt;->access$shouldIncreaseMaxIntrinsic(FLjava/lang/CharSequence;Landroid/text/TextPaint;)Z
+HSPLandroidx/compose/ui/text/android/LayoutIntrinsicsKt;->shouldIncreaseMaxIntrinsic(FLjava/lang/CharSequence;Landroid/text/TextPaint;)Z
+HSPLandroidx/compose/ui/text/android/SpannedExtensionsKt;->hasSpan(Landroid/text/Spanned;Ljava/lang/Class;)Z
+HSPLandroidx/compose/ui/text/android/StaticLayoutFactory23;-><init>()V
+HSPLandroidx/compose/ui/text/android/StaticLayoutFactory23;->create(Landroidx/compose/ui/text/android/StaticLayoutParams;)Landroid/text/StaticLayout;
+HSPLandroidx/compose/ui/text/android/StaticLayoutFactory26;-><clinit>()V
+HSPLandroidx/compose/ui/text/android/StaticLayoutFactory26;-><init>()V
+HSPLandroidx/compose/ui/text/android/StaticLayoutFactory26;->setJustificationMode(Landroid/text/StaticLayout$Builder;I)V
+HSPLandroidx/compose/ui/text/android/StaticLayoutFactory28;-><clinit>()V
+HSPLandroidx/compose/ui/text/android/StaticLayoutFactory28;-><init>()V
+HSPLandroidx/compose/ui/text/android/StaticLayoutFactory28;->setUseLineSpacingFromFallbacks(Landroid/text/StaticLayout$Builder;Z)V
+HSPLandroidx/compose/ui/text/android/StaticLayoutFactory33;-><clinit>()V
+HSPLandroidx/compose/ui/text/android/StaticLayoutFactory33;-><init>()V
+HSPLandroidx/compose/ui/text/android/StaticLayoutFactory33;->setLineBreakConfig(Landroid/text/StaticLayout$Builder;II)V
+HSPLandroidx/compose/ui/text/android/StaticLayoutFactory;-><clinit>()V
+HSPLandroidx/compose/ui/text/android/StaticLayoutFactory;-><init>()V
+HSPLandroidx/compose/ui/text/android/StaticLayoutFactory;->create(Ljava/lang/CharSequence;IILandroid/text/TextPaint;ILandroid/text/TextDirectionHeuristic;Landroid/text/Layout$Alignment;ILandroid/text/TextUtils$TruncateAt;IFFIZZIIII[I[I)Landroid/text/StaticLayout;
+HSPLandroidx/compose/ui/text/android/StaticLayoutParams;-><init>(Ljava/lang/CharSequence;IILandroid/text/TextPaint;ILandroid/text/TextDirectionHeuristic;Landroid/text/Layout$Alignment;ILandroid/text/TextUtils$TruncateAt;IFFIZZIIII[I[I)V
+HSPLandroidx/compose/ui/text/android/StaticLayoutParams;->getAlignment()Landroid/text/Layout$Alignment;
+HSPLandroidx/compose/ui/text/android/StaticLayoutParams;->getBreakStrategy()I
+HSPLandroidx/compose/ui/text/android/StaticLayoutParams;->getEllipsize()Landroid/text/TextUtils$TruncateAt;
+HSPLandroidx/compose/ui/text/android/StaticLayoutParams;->getEllipsizedWidth()I
+HSPLandroidx/compose/ui/text/android/StaticLayoutParams;->getEnd()I
+HSPLandroidx/compose/ui/text/android/StaticLayoutParams;->getHyphenationFrequency()I
+HSPLandroidx/compose/ui/text/android/StaticLayoutParams;->getIncludePadding()Z
+HSPLandroidx/compose/ui/text/android/StaticLayoutParams;->getJustificationMode()I
+HSPLandroidx/compose/ui/text/android/StaticLayoutParams;->getLeftIndents()[I
+HSPLandroidx/compose/ui/text/android/StaticLayoutParams;->getLineBreakStyle()I
+HSPLandroidx/compose/ui/text/android/StaticLayoutParams;->getLineBreakWordStyle()I
+HSPLandroidx/compose/ui/text/android/StaticLayoutParams;->getLineSpacingExtra()F
+HSPLandroidx/compose/ui/text/android/StaticLayoutParams;->getLineSpacingMultiplier()F
+HSPLandroidx/compose/ui/text/android/StaticLayoutParams;->getMaxLines()I
+HSPLandroidx/compose/ui/text/android/StaticLayoutParams;->getPaint()Landroid/text/TextPaint;
+HSPLandroidx/compose/ui/text/android/StaticLayoutParams;->getRightIndents()[I
+HSPLandroidx/compose/ui/text/android/StaticLayoutParams;->getStart()I
+HSPLandroidx/compose/ui/text/android/StaticLayoutParams;->getText()Ljava/lang/CharSequence;
+HSPLandroidx/compose/ui/text/android/StaticLayoutParams;->getTextDir()Landroid/text/TextDirectionHeuristic;
+HSPLandroidx/compose/ui/text/android/StaticLayoutParams;->getUseFallbackLineSpacing()Z
+HSPLandroidx/compose/ui/text/android/StaticLayoutParams;->getWidth()I
+HSPLandroidx/compose/ui/text/android/TextAlignmentAdapter;-><clinit>()V
+HSPLandroidx/compose/ui/text/android/TextAlignmentAdapter;-><init>()V
+HSPLandroidx/compose/ui/text/android/TextAlignmentAdapter;->get(I)Landroid/text/Layout$Alignment;
+HSPLandroidx/compose/ui/text/android/TextAndroidCanvas;-><init>()V
+HSPLandroidx/compose/ui/text/android/TextAndroidCanvas;->drawTextRun(Ljava/lang/CharSequence;IIIIFFZLandroid/graphics/Paint;)V
+HSPLandroidx/compose/ui/text/android/TextAndroidCanvas;->getClipBounds(Landroid/graphics/Rect;)Z
+HSPLandroidx/compose/ui/text/android/TextAndroidCanvas;->setCanvas(Landroid/graphics/Canvas;)V
+HSPLandroidx/compose/ui/text/android/TextLayout$Companion;-><init>()V
+HSPLandroidx/compose/ui/text/android/TextLayout$Companion;-><init>(Lkotlin/jvm/internal/DefaultConstructorMarker;)V
+HSPLandroidx/compose/ui/text/android/TextLayout$layoutHelper$2;-><init>(Landroidx/compose/ui/text/android/TextLayout;)V
+HSPLandroidx/compose/ui/text/android/TextLayout;-><clinit>()V
+HSPLandroidx/compose/ui/text/android/TextLayout;-><init>(Ljava/lang/CharSequence;FLandroid/text/TextPaint;ILandroid/text/TextUtils$TruncateAt;IFFZZIIIIII[I[ILandroidx/compose/ui/text/android/LayoutIntrinsics;)V
+HSPLandroidx/compose/ui/text/android/TextLayout;-><init>(Ljava/lang/CharSequence;FLandroid/text/TextPaint;ILandroid/text/TextUtils$TruncateAt;IFFZZIIIIII[I[ILandroidx/compose/ui/text/android/LayoutIntrinsics;ILkotlin/jvm/internal/DefaultConstructorMarker;)V
+HSPLandroidx/compose/ui/text/android/TextLayout;->getDidExceedMaxLines()Z
+HSPLandroidx/compose/ui/text/android/TextLayout;->getHeight()I
+HSPLandroidx/compose/ui/text/android/TextLayout;->getIncludePadding()Z
+HSPLandroidx/compose/ui/text/android/TextLayout;->getLayout()Landroid/text/Layout;
+HSPLandroidx/compose/ui/text/android/TextLayout;->getLineBaseline(I)F
+HSPLandroidx/compose/ui/text/android/TextLayout;->getLineCount()I
+HSPLandroidx/compose/ui/text/android/TextLayout;->getText()Ljava/lang/CharSequence;
+HSPLandroidx/compose/ui/text/android/TextLayout;->paint(Landroid/graphics/Canvas;)V
+HSPLandroidx/compose/ui/text/android/TextLayoutKt;-><clinit>()V
+HSPLandroidx/compose/ui/text/android/TextLayoutKt;->access$getLastLineMetrics(Landroidx/compose/ui/text/android/TextLayout;Landroid/text/TextPaint;Landroid/text/TextDirectionHeuristic;[Landroidx/compose/ui/text/android/style/LineHeightStyleSpan;)Lkotlin/Pair;
+HSPLandroidx/compose/ui/text/android/TextLayoutKt;->access$getLineHeightPaddings(Landroidx/compose/ui/text/android/TextLayout;[Landroidx/compose/ui/text/android/style/LineHeightStyleSpan;)Lkotlin/Pair;
+HSPLandroidx/compose/ui/text/android/TextLayoutKt;->access$getLineHeightSpans(Landroidx/compose/ui/text/android/TextLayout;)[Landroidx/compose/ui/text/android/style/LineHeightStyleSpan;
+HSPLandroidx/compose/ui/text/android/TextLayoutKt;->access$getVerticalPaddings(Landroidx/compose/ui/text/android/TextLayout;)Lkotlin/Pair;
+HSPLandroidx/compose/ui/text/android/TextLayoutKt;->getLastLineMetrics(Landroidx/compose/ui/text/android/TextLayout;Landroid/text/TextPaint;Landroid/text/TextDirectionHeuristic;[Landroidx/compose/ui/text/android/style/LineHeightStyleSpan;)Lkotlin/Pair;
+HSPLandroidx/compose/ui/text/android/TextLayoutKt;->getLineHeightPaddings(Landroidx/compose/ui/text/android/TextLayout;[Landroidx/compose/ui/text/android/style/LineHeightStyleSpan;)Lkotlin/Pair;
+HSPLandroidx/compose/ui/text/android/TextLayoutKt;->getLineHeightSpans(Landroidx/compose/ui/text/android/TextLayout;)[Landroidx/compose/ui/text/android/style/LineHeightStyleSpan;
+HSPLandroidx/compose/ui/text/android/TextLayoutKt;->getTextDirectionHeuristic(I)Landroid/text/TextDirectionHeuristic;
+HSPLandroidx/compose/ui/text/android/TextLayoutKt;->getVerticalPaddings(Landroidx/compose/ui/text/android/TextLayout;)Lkotlin/Pair;
+HSPLandroidx/compose/ui/text/android/TextLayoutKt;->isLineEllipsized(Landroid/text/Layout;I)Z
+HSPLandroidx/compose/ui/text/android/style/IndentationFixSpanKt;->getEllipsizedLeftPadding$default(Landroid/text/Layout;ILandroid/graphics/Paint;ILjava/lang/Object;)F
+HSPLandroidx/compose/ui/text/android/style/IndentationFixSpanKt;->getEllipsizedLeftPadding(Landroid/text/Layout;ILandroid/graphics/Paint;)F
+HSPLandroidx/compose/ui/text/android/style/IndentationFixSpanKt;->getEllipsizedRightPadding$default(Landroid/text/Layout;ILandroid/graphics/Paint;ILjava/lang/Object;)F
+HSPLandroidx/compose/ui/text/android/style/IndentationFixSpanKt;->getEllipsizedRightPadding(Landroid/text/Layout;ILandroid/graphics/Paint;)F
+HSPLandroidx/compose/ui/text/android/style/LineHeightSpan;-><clinit>()V
+HSPLandroidx/compose/ui/text/android/style/LineHeightSpan;-><init>(F)V
+HSPLandroidx/compose/ui/text/android/style/LineHeightSpan;->chooseHeight(Ljava/lang/CharSequence;IIIILandroid/graphics/Paint$FontMetricsInt;)V
+HSPLandroidx/compose/ui/text/android/style/LineHeightStyleSpanKt;->lineHeight(Landroid/graphics/Paint$FontMetricsInt;)I
+HSPLandroidx/compose/ui/text/caches/ContainerHelpersKt;-><clinit>()V
+HSPLandroidx/compose/ui/text/caches/LruCache;-><init>(I)V
+HSPLandroidx/compose/ui/text/caches/LruCache;->access$getMonitor$p(Landroidx/compose/ui/text/caches/LruCache;)Landroidx/compose/ui/text/platform/SynchronizedObject;
+HSPLandroidx/compose/ui/text/caches/LruCache;->create(Ljava/lang/Object;)Ljava/lang/Object;
+HSPLandroidx/compose/ui/text/caches/LruCache;->get(Ljava/lang/Object;)Ljava/lang/Object;
+HSPLandroidx/compose/ui/text/caches/LruCache;->put(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;
+HSPLandroidx/compose/ui/text/caches/LruCache;->safeSizeOf(Ljava/lang/Object;Ljava/lang/Object;)I
+HSPLandroidx/compose/ui/text/caches/LruCache;->size()I
+HSPLandroidx/compose/ui/text/caches/LruCache;->sizeOf(Ljava/lang/Object;Ljava/lang/Object;)I
+HSPLandroidx/compose/ui/text/caches/LruCache;->trimToSize(I)V
+HSPLandroidx/compose/ui/text/caches/SimpleArrayMap;-><init>(I)V
+HSPLandroidx/compose/ui/text/caches/SimpleArrayMap;-><init>(IILkotlin/jvm/internal/DefaultConstructorMarker;)V
+HSPLandroidx/compose/ui/text/font/AndroidFontLoader;-><init>(Landroid/content/Context;)V
+HSPLandroidx/compose/ui/text/font/AndroidFontLoader;->getCacheKey()Ljava/lang/Object;
+HSPLandroidx/compose/ui/text/font/AndroidFontResolveInterceptor;-><init>(I)V
+HSPLandroidx/compose/ui/text/font/AndroidFontResolveInterceptor;->interceptFontWeight(Landroidx/compose/ui/text/font/FontWeight;)Landroidx/compose/ui/text/font/FontWeight;
+HSPLandroidx/compose/ui/text/font/AndroidFontResolveInterceptor_androidKt;->AndroidFontResolveInterceptor(Landroid/content/Context;)Landroidx/compose/ui/text/font/AndroidFontResolveInterceptor;
+HSPLandroidx/compose/ui/text/font/AsyncTypefaceCache$AsyncTypefaceResult;->constructor-impl(Ljava/lang/Object;)Ljava/lang/Object;
+HSPLandroidx/compose/ui/text/font/AsyncTypefaceCache;-><init>()V
+HSPLandroidx/compose/ui/text/font/DefaultFontFamily;-><init>()V
+HSPLandroidx/compose/ui/text/font/FontFamily$Companion;-><init>()V
+HSPLandroidx/compose/ui/text/font/FontFamily$Companion;-><init>(Lkotlin/jvm/internal/DefaultConstructorMarker;)V
+HSPLandroidx/compose/ui/text/font/FontFamily$Companion;->getDefault()Landroidx/compose/ui/text/font/SystemFontFamily;
+HSPLandroidx/compose/ui/text/font/FontFamily$Companion;->getSansSerif()Landroidx/compose/ui/text/font/GenericFontFamily;
+HSPLandroidx/compose/ui/text/font/FontFamily;-><clinit>()V
+HSPLandroidx/compose/ui/text/font/FontFamily;-><init>(Z)V
+HSPLandroidx/compose/ui/text/font/FontFamily;-><init>(ZLkotlin/jvm/internal/DefaultConstructorMarker;)V
+HSPLandroidx/compose/ui/text/font/FontFamily;->access$getDefault$cp()Landroidx/compose/ui/text/font/SystemFontFamily;
+HSPLandroidx/compose/ui/text/font/FontFamily;->access$getSansSerif$cp()Landroidx/compose/ui/text/font/GenericFontFamily;
+HSPLandroidx/compose/ui/text/font/FontFamilyResolverImpl$createDefaultTypeface$1;-><init>(Landroidx/compose/ui/text/font/FontFamilyResolverImpl;)V
+HSPLandroidx/compose/ui/text/font/FontFamilyResolverImpl$resolve$result$1;-><init>(Landroidx/compose/ui/text/font/FontFamilyResolverImpl;Landroidx/compose/ui/text/font/TypefaceRequest;)V
+HSPLandroidx/compose/ui/text/font/FontFamilyResolverImpl$resolve$result$1;->invoke(Ljava/lang/Object;)Ljava/lang/Object;
+HSPLandroidx/compose/ui/text/font/FontFamilyResolverImpl$resolve$result$1;->invoke(Lkotlin/jvm/functions/Function1;)Landroidx/compose/ui/text/font/TypefaceResult;
+HSPLandroidx/compose/ui/text/font/FontFamilyResolverImpl;-><init>(Landroidx/compose/ui/text/font/PlatformFontLoader;Landroidx/compose/ui/text/font/PlatformResolveInterceptor;Landroidx/compose/ui/text/font/TypefaceRequestCache;Landroidx/compose/ui/text/font/FontListFontFamilyTypefaceAdapter;Landroidx/compose/ui/text/font/PlatformFontFamilyTypefaceAdapter;)V
+HSPLandroidx/compose/ui/text/font/FontFamilyResolverImpl;-><init>(Landroidx/compose/ui/text/font/PlatformFontLoader;Landroidx/compose/ui/text/font/PlatformResolveInterceptor;Landroidx/compose/ui/text/font/TypefaceRequestCache;Landroidx/compose/ui/text/font/FontListFontFamilyTypefaceAdapter;Landroidx/compose/ui/text/font/PlatformFontFamilyTypefaceAdapter;ILkotlin/jvm/internal/DefaultConstructorMarker;)V
+HSPLandroidx/compose/ui/text/font/FontFamilyResolverImpl;->access$getCreateDefaultTypeface$p(Landroidx/compose/ui/text/font/FontFamilyResolverImpl;)Lkotlin/jvm/functions/Function1;
+HSPLandroidx/compose/ui/text/font/FontFamilyResolverImpl;->access$getFontListFontFamilyTypefaceAdapter$p(Landroidx/compose/ui/text/font/FontFamilyResolverImpl;)Landroidx/compose/ui/text/font/FontListFontFamilyTypefaceAdapter;
+HSPLandroidx/compose/ui/text/font/FontFamilyResolverImpl;->access$getPlatformFamilyTypefaceAdapter$p(Landroidx/compose/ui/text/font/FontFamilyResolverImpl;)Landroidx/compose/ui/text/font/PlatformFontFamilyTypefaceAdapter;
+HSPLandroidx/compose/ui/text/font/FontFamilyResolverImpl;->getPlatformFontLoader$ui_text_release()Landroidx/compose/ui/text/font/PlatformFontLoader;
+HSPLandroidx/compose/ui/text/font/FontFamilyResolverImpl;->resolve(Landroidx/compose/ui/text/font/TypefaceRequest;)Landroidx/compose/runtime/State;
+HSPLandroidx/compose/ui/text/font/FontFamilyResolverImpl;->resolve-DPcqOEQ(Landroidx/compose/ui/text/font/FontFamily;Landroidx/compose/ui/text/font/FontWeight;II)Landroidx/compose/runtime/State;
+HSPLandroidx/compose/ui/text/font/FontFamilyResolverKt;-><clinit>()V
+HSPLandroidx/compose/ui/text/font/FontFamilyResolverKt;->getGlobalAsyncTypefaceCache()Landroidx/compose/ui/text/font/AsyncTypefaceCache;
+HSPLandroidx/compose/ui/text/font/FontFamilyResolverKt;->getGlobalTypefaceRequestCache()Landroidx/compose/ui/text/font/TypefaceRequestCache;
+HSPLandroidx/compose/ui/text/font/FontFamilyResolver_androidKt;->createFontFamilyResolver(Landroid/content/Context;)Landroidx/compose/ui/text/font/FontFamily$Resolver;
+HSPLandroidx/compose/ui/text/font/FontListFontFamilyTypefaceAdapter$Companion;-><init>()V
+HSPLandroidx/compose/ui/text/font/FontListFontFamilyTypefaceAdapter$Companion;-><init>(Lkotlin/jvm/internal/DefaultConstructorMarker;)V
+HSPLandroidx/compose/ui/text/font/FontListFontFamilyTypefaceAdapter$special$$inlined$CoroutineExceptionHandler$1;-><init>(Lkotlinx/coroutines/CoroutineExceptionHandler$Key;)V
+HSPLandroidx/compose/ui/text/font/FontListFontFamilyTypefaceAdapter;-><clinit>()V
+HSPLandroidx/compose/ui/text/font/FontListFontFamilyTypefaceAdapter;-><init>(Landroidx/compose/ui/text/font/AsyncTypefaceCache;Lkotlin/coroutines/CoroutineContext;)V
+HSPLandroidx/compose/ui/text/font/FontListFontFamilyTypefaceAdapter;-><init>(Landroidx/compose/ui/text/font/AsyncTypefaceCache;Lkotlin/coroutines/CoroutineContext;ILkotlin/jvm/internal/DefaultConstructorMarker;)V
+HSPLandroidx/compose/ui/text/font/FontListFontFamilyTypefaceAdapter;->resolve(Landroidx/compose/ui/text/font/TypefaceRequest;Landroidx/compose/ui/text/font/PlatformFontLoader;Lkotlin/jvm/functions/Function1;Lkotlin/jvm/functions/Function1;)Landroidx/compose/ui/text/font/TypefaceResult;
+HSPLandroidx/compose/ui/text/font/FontMatcher;-><init>()V
+HSPLandroidx/compose/ui/text/font/FontStyle$Companion;-><init>()V
+HSPLandroidx/compose/ui/text/font/FontStyle$Companion;-><init>(Lkotlin/jvm/internal/DefaultConstructorMarker;)V
+HSPLandroidx/compose/ui/text/font/FontStyle$Companion;->getItalic-_-LCdwA()I
+HSPLandroidx/compose/ui/text/font/FontStyle$Companion;->getNormal-_-LCdwA()I
+HSPLandroidx/compose/ui/text/font/FontStyle;-><clinit>()V
+HSPLandroidx/compose/ui/text/font/FontStyle;-><init>(I)V
+HSPLandroidx/compose/ui/text/font/FontStyle;->access$getItalic$cp()I
+HSPLandroidx/compose/ui/text/font/FontStyle;->access$getNormal$cp()I
+HSPLandroidx/compose/ui/text/font/FontStyle;->box-impl(I)Landroidx/compose/ui/text/font/FontStyle;
+HSPLandroidx/compose/ui/text/font/FontStyle;->constructor-impl(I)I
+HSPLandroidx/compose/ui/text/font/FontStyle;->equals-impl0(II)Z
+HSPLandroidx/compose/ui/text/font/FontStyle;->hashCode-impl(I)I
+HSPLandroidx/compose/ui/text/font/FontStyle;->unbox-impl()I
+HSPLandroidx/compose/ui/text/font/FontSynthesis$Companion;-><init>()V
+HSPLandroidx/compose/ui/text/font/FontSynthesis$Companion;-><init>(Lkotlin/jvm/internal/DefaultConstructorMarker;)V
+HSPLandroidx/compose/ui/text/font/FontSynthesis$Companion;->getAll-GVVA2EU()I
+HSPLandroidx/compose/ui/text/font/FontSynthesis;-><clinit>()V
+HSPLandroidx/compose/ui/text/font/FontSynthesis;-><init>(I)V
+HSPLandroidx/compose/ui/text/font/FontSynthesis;->access$getAll$cp()I
+HSPLandroidx/compose/ui/text/font/FontSynthesis;->box-impl(I)Landroidx/compose/ui/text/font/FontSynthesis;
+HSPLandroidx/compose/ui/text/font/FontSynthesis;->constructor-impl(I)I
+HSPLandroidx/compose/ui/text/font/FontSynthesis;->equals-impl0(II)Z
+HSPLandroidx/compose/ui/text/font/FontSynthesis;->hashCode-impl(I)I
+HSPLandroidx/compose/ui/text/font/FontSynthesis;->unbox-impl()I
+HSPLandroidx/compose/ui/text/font/FontWeight$Companion;-><init>()V
+HSPLandroidx/compose/ui/text/font/FontWeight$Companion;-><init>(Lkotlin/jvm/internal/DefaultConstructorMarker;)V
+HSPLandroidx/compose/ui/text/font/FontWeight$Companion;->getBold()Landroidx/compose/ui/text/font/FontWeight;
+HSPLandroidx/compose/ui/text/font/FontWeight$Companion;->getMedium()Landroidx/compose/ui/text/font/FontWeight;
+HSPLandroidx/compose/ui/text/font/FontWeight$Companion;->getNormal()Landroidx/compose/ui/text/font/FontWeight;
+HSPLandroidx/compose/ui/text/font/FontWeight;-><clinit>()V
+HSPLandroidx/compose/ui/text/font/FontWeight;-><init>(I)V
+HSPLandroidx/compose/ui/text/font/FontWeight;->access$getBold$cp()Landroidx/compose/ui/text/font/FontWeight;
+HSPLandroidx/compose/ui/text/font/FontWeight;->access$getMedium$cp()Landroidx/compose/ui/text/font/FontWeight;
+HSPLandroidx/compose/ui/text/font/FontWeight;->access$getNormal$cp()Landroidx/compose/ui/text/font/FontWeight;
+HSPLandroidx/compose/ui/text/font/FontWeight;->equals(Ljava/lang/Object;)Z
+HSPLandroidx/compose/ui/text/font/FontWeight;->getWeight()I
+HSPLandroidx/compose/ui/text/font/FontWeight;->hashCode()I
+HSPLandroidx/compose/ui/text/font/GenericFontFamily;-><init>(Ljava/lang/String;Ljava/lang/String;)V
+HSPLandroidx/compose/ui/text/font/PlatformFontFamilyTypefaceAdapter;-><init>()V
+HSPLandroidx/compose/ui/text/font/PlatformFontFamilyTypefaceAdapter;->resolve(Landroidx/compose/ui/text/font/TypefaceRequest;Landroidx/compose/ui/text/font/PlatformFontLoader;Lkotlin/jvm/functions/Function1;Lkotlin/jvm/functions/Function1;)Landroidx/compose/ui/text/font/TypefaceResult;
+HSPLandroidx/compose/ui/text/font/PlatformResolveInterceptor$Companion$Default$1;-><init>()V
+HSPLandroidx/compose/ui/text/font/PlatformResolveInterceptor$Companion;-><clinit>()V
+HSPLandroidx/compose/ui/text/font/PlatformResolveInterceptor$Companion;-><init>()V
+HSPLandroidx/compose/ui/text/font/PlatformResolveInterceptor;-><clinit>()V
+HSPLandroidx/compose/ui/text/font/PlatformResolveInterceptor;->interceptFontFamily(Landroidx/compose/ui/text/font/FontFamily;)Landroidx/compose/ui/text/font/FontFamily;
+HSPLandroidx/compose/ui/text/font/PlatformResolveInterceptor;->interceptFontStyle-T2F_aPo(I)I
+HSPLandroidx/compose/ui/text/font/PlatformResolveInterceptor;->interceptFontSynthesis-Mscr08Y(I)I
+HSPLandroidx/compose/ui/text/font/PlatformTypefacesApi28;-><init>()V
+HSPLandroidx/compose/ui/text/font/PlatformTypefacesApi28;->createAndroidTypefaceApi28-RetOiIg(Ljava/lang/String;Landroidx/compose/ui/text/font/FontWeight;I)Landroid/graphics/Typeface;
+HSPLandroidx/compose/ui/text/font/PlatformTypefacesApi28;->createDefault-FO1MlWM(Landroidx/compose/ui/text/font/FontWeight;I)Landroid/graphics/Typeface;
+HSPLandroidx/compose/ui/text/font/PlatformTypefacesKt;->PlatformTypefaces()Landroidx/compose/ui/text/font/PlatformTypefaces;
+HSPLandroidx/compose/ui/text/font/SystemFontFamily;-><clinit>()V
+HSPLandroidx/compose/ui/text/font/SystemFontFamily;-><init>()V
+HSPLandroidx/compose/ui/text/font/SystemFontFamily;-><init>(Lkotlin/jvm/internal/DefaultConstructorMarker;)V
+HSPLandroidx/compose/ui/text/font/TypefaceRequest;-><init>(Landroidx/compose/ui/text/font/FontFamily;Landroidx/compose/ui/text/font/FontWeight;IILjava/lang/Object;)V
+HSPLandroidx/compose/ui/text/font/TypefaceRequest;-><init>(Landroidx/compose/ui/text/font/FontFamily;Landroidx/compose/ui/text/font/FontWeight;IILjava/lang/Object;Lkotlin/jvm/internal/DefaultConstructorMarker;)V
+HSPLandroidx/compose/ui/text/font/TypefaceRequest;->equals(Ljava/lang/Object;)Z
+HSPLandroidx/compose/ui/text/font/TypefaceRequest;->getFontFamily()Landroidx/compose/ui/text/font/FontFamily;
+HSPLandroidx/compose/ui/text/font/TypefaceRequest;->getFontStyle-_-LCdwA()I
+HSPLandroidx/compose/ui/text/font/TypefaceRequest;->getFontWeight()Landroidx/compose/ui/text/font/FontWeight;
+HSPLandroidx/compose/ui/text/font/TypefaceRequest;->hashCode()I
+HSPLandroidx/compose/ui/text/font/TypefaceRequestCache$runCached$currentTypefaceResult$1;-><init>(Landroidx/compose/ui/text/font/TypefaceRequestCache;Landroidx/compose/ui/text/font/TypefaceRequest;)V
+HSPLandroidx/compose/ui/text/font/TypefaceRequestCache;-><init>()V
+HSPLandroidx/compose/ui/text/font/TypefaceRequestCache;->runCached(Landroidx/compose/ui/text/font/TypefaceRequest;Lkotlin/jvm/functions/Function1;)Landroidx/compose/runtime/State;
+HSPLandroidx/compose/ui/text/font/TypefaceResult$Immutable;-><clinit>()V
+HSPLandroidx/compose/ui/text/font/TypefaceResult$Immutable;-><init>(Ljava/lang/Object;Z)V
+HSPLandroidx/compose/ui/text/font/TypefaceResult$Immutable;-><init>(Ljava/lang/Object;ZILkotlin/jvm/internal/DefaultConstructorMarker;)V
+HSPLandroidx/compose/ui/text/font/TypefaceResult$Immutable;->getCacheable()Z
+HSPLandroidx/compose/ui/text/font/TypefaceResult$Immutable;->getValue()Ljava/lang/Object;
+HSPLandroidx/compose/ui/text/input/ImeAction$Companion;-><init>()V
+HSPLandroidx/compose/ui/text/input/ImeAction$Companion;-><init>(Lkotlin/jvm/internal/DefaultConstructorMarker;)V
+HSPLandroidx/compose/ui/text/input/ImeAction$Companion;->getDefault-eUduSuo()I
+HSPLandroidx/compose/ui/text/input/ImeAction;-><clinit>()V
+HSPLandroidx/compose/ui/text/input/ImeAction;->access$getDefault$cp()I
+HSPLandroidx/compose/ui/text/input/ImeAction;->constructor-impl(I)I
+HSPLandroidx/compose/ui/text/input/ImeOptions$Companion;-><init>()V
+HSPLandroidx/compose/ui/text/input/ImeOptions$Companion;-><init>(Lkotlin/jvm/internal/DefaultConstructorMarker;)V
+HSPLandroidx/compose/ui/text/input/ImeOptions$Companion;->getDefault()Landroidx/compose/ui/text/input/ImeOptions;
+HSPLandroidx/compose/ui/text/input/ImeOptions;-><clinit>()V
+HSPLandroidx/compose/ui/text/input/ImeOptions;-><init>(ZIZII)V
+HSPLandroidx/compose/ui/text/input/ImeOptions;-><init>(ZIZIIILkotlin/jvm/internal/DefaultConstructorMarker;)V
+HSPLandroidx/compose/ui/text/input/ImeOptions;-><init>(ZIZIILkotlin/jvm/internal/DefaultConstructorMarker;)V
+HSPLandroidx/compose/ui/text/input/ImeOptions;->access$getDefault$cp()Landroidx/compose/ui/text/input/ImeOptions;
+HSPLandroidx/compose/ui/text/input/ImmHelper30;-><init>(Landroid/view/View;)V
+HSPLandroidx/compose/ui/text/input/InputMethodManagerImpl$imm$2;-><init>(Landroidx/compose/ui/text/input/InputMethodManagerImpl;)V
+HSPLandroidx/compose/ui/text/input/InputMethodManagerImpl;-><init>(Landroid/view/View;)V
+HSPLandroidx/compose/ui/text/input/KeyboardCapitalization$Companion;-><init>()V
+HSPLandroidx/compose/ui/text/input/KeyboardCapitalization$Companion;-><init>(Lkotlin/jvm/internal/DefaultConstructorMarker;)V
+HSPLandroidx/compose/ui/text/input/KeyboardCapitalization$Companion;->getNone-IUNYP9k()I
+HSPLandroidx/compose/ui/text/input/KeyboardCapitalization;-><clinit>()V
+HSPLandroidx/compose/ui/text/input/KeyboardCapitalization;->access$getNone$cp()I
+HSPLandroidx/compose/ui/text/input/KeyboardCapitalization;->constructor-impl(I)I
+HSPLandroidx/compose/ui/text/input/KeyboardType$Companion;-><init>()V
+HSPLandroidx/compose/ui/text/input/KeyboardType$Companion;-><init>(Lkotlin/jvm/internal/DefaultConstructorMarker;)V
+HSPLandroidx/compose/ui/text/input/KeyboardType$Companion;->getText-PjHm6EE()I
+HSPLandroidx/compose/ui/text/input/KeyboardType;-><clinit>()V
+HSPLandroidx/compose/ui/text/input/KeyboardType;->access$getText$cp()I
+HSPLandroidx/compose/ui/text/input/KeyboardType;->constructor-impl(I)I
+HSPLandroidx/compose/ui/text/input/TextFieldValue$Companion$Saver$1;-><clinit>()V
+HSPLandroidx/compose/ui/text/input/TextFieldValue$Companion$Saver$1;-><init>()V
+HSPLandroidx/compose/ui/text/input/TextFieldValue$Companion$Saver$2;-><clinit>()V
+HSPLandroidx/compose/ui/text/input/TextFieldValue$Companion$Saver$2;-><init>()V
+HSPLandroidx/compose/ui/text/input/TextFieldValue$Companion;-><init>()V
+HSPLandroidx/compose/ui/text/input/TextFieldValue$Companion;-><init>(Lkotlin/jvm/internal/DefaultConstructorMarker;)V
+HSPLandroidx/compose/ui/text/input/TextFieldValue;-><clinit>()V
+HSPLandroidx/compose/ui/text/input/TextFieldValue;-><init>(Landroidx/compose/ui/text/AnnotatedString;JLandroidx/compose/ui/text/TextRange;)V
+HSPLandroidx/compose/ui/text/input/TextFieldValue;-><init>(Landroidx/compose/ui/text/AnnotatedString;JLandroidx/compose/ui/text/TextRange;Lkotlin/jvm/internal/DefaultConstructorMarker;)V
+HSPLandroidx/compose/ui/text/input/TextFieldValue;-><init>(Ljava/lang/String;JLandroidx/compose/ui/text/TextRange;)V
+HSPLandroidx/compose/ui/text/input/TextFieldValue;-><init>(Ljava/lang/String;JLandroidx/compose/ui/text/TextRange;ILkotlin/jvm/internal/DefaultConstructorMarker;)V
+HSPLandroidx/compose/ui/text/input/TextFieldValue;-><init>(Ljava/lang/String;JLandroidx/compose/ui/text/TextRange;Lkotlin/jvm/internal/DefaultConstructorMarker;)V
+HSPLandroidx/compose/ui/text/input/TextFieldValue;->getText()Ljava/lang/String;
+HSPLandroidx/compose/ui/text/input/TextInputService;-><clinit>()V
+HSPLandroidx/compose/ui/text/input/TextInputService;-><init>(Landroidx/compose/ui/text/input/PlatformTextInputService;)V
+HSPLandroidx/compose/ui/text/input/TextInputServiceAndroid$baseInputConnection$2;-><init>(Landroidx/compose/ui/text/input/TextInputServiceAndroid;)V
+HSPLandroidx/compose/ui/text/input/TextInputServiceAndroid$onEditCommand$1;-><clinit>()V
+HSPLandroidx/compose/ui/text/input/TextInputServiceAndroid$onEditCommand$1;-><init>()V
+HSPLandroidx/compose/ui/text/input/TextInputServiceAndroid$onImeActionPerformed$1;-><clinit>()V
+HSPLandroidx/compose/ui/text/input/TextInputServiceAndroid$onImeActionPerformed$1;-><init>()V
+HSPLandroidx/compose/ui/text/input/TextInputServiceAndroid$textInputCommandEventLoop$1;-><init>(Landroidx/compose/ui/text/input/TextInputServiceAndroid;Lkotlin/coroutines/Continuation;)V
+HSPLandroidx/compose/ui/text/input/TextInputServiceAndroid;-><init>(Landroid/view/View;)V
+HSPLandroidx/compose/ui/text/input/TextInputServiceAndroid;-><init>(Landroid/view/View;Landroidx/compose/ui/text/input/InputMethodManager;)V
+HSPLandroidx/compose/ui/text/input/TextInputServiceAndroid;->isEditorFocused()Z
+HSPLandroidx/compose/ui/text/input/TextInputServiceAndroid;->textInputCommandEventLoop(Lkotlin/coroutines/Continuation;)Ljava/lang/Object;
+HSPLandroidx/compose/ui/text/intl/AndroidLocale;-><init>(Ljava/util/Locale;)V
+HSPLandroidx/compose/ui/text/intl/AndroidLocale;->toLanguageTag()Ljava/lang/String;
+HSPLandroidx/compose/ui/text/intl/AndroidLocaleDelegateAPI24;-><init>()V
+HSPLandroidx/compose/ui/text/intl/AndroidLocaleDelegateAPI24;->getCurrent()Ljava/util/List;
+HSPLandroidx/compose/ui/text/intl/AndroidPlatformLocale_androidKt;->createPlatformLocaleDelegate()Landroidx/compose/ui/text/intl/PlatformLocaleDelegate;
+HSPLandroidx/compose/ui/text/intl/Locale$Companion;-><init>()V
+HSPLandroidx/compose/ui/text/intl/Locale$Companion;-><init>(Lkotlin/jvm/internal/DefaultConstructorMarker;)V
+HSPLandroidx/compose/ui/text/intl/Locale;-><clinit>()V
+HSPLandroidx/compose/ui/text/intl/Locale;-><init>(Landroidx/compose/ui/text/intl/PlatformLocale;)V
+HSPLandroidx/compose/ui/text/intl/Locale;->equals(Ljava/lang/Object;)Z
+HSPLandroidx/compose/ui/text/intl/Locale;->toLanguageTag()Ljava/lang/String;
+HSPLandroidx/compose/ui/text/intl/LocaleList$Companion;-><init>()V
+HSPLandroidx/compose/ui/text/intl/LocaleList$Companion;-><init>(Lkotlin/jvm/internal/DefaultConstructorMarker;)V
+HSPLandroidx/compose/ui/text/intl/LocaleList$Companion;->getCurrent()Landroidx/compose/ui/text/intl/LocaleList;
+HSPLandroidx/compose/ui/text/intl/LocaleList;-><clinit>()V
+HSPLandroidx/compose/ui/text/intl/LocaleList;-><init>(Ljava/util/List;)V
+HSPLandroidx/compose/ui/text/intl/LocaleList;->equals(Ljava/lang/Object;)Z
+HSPLandroidx/compose/ui/text/intl/PlatformLocaleKt;-><clinit>()V
+HSPLandroidx/compose/ui/text/intl/PlatformLocaleKt;->getPlatformLocaleDelegate()Landroidx/compose/ui/text/intl/PlatformLocaleDelegate;
+HSPLandroidx/compose/ui/text/platform/AndroidParagraphHelper_androidKt$NoopSpan$1;-><init>()V
+HSPLandroidx/compose/ui/text/platform/AndroidParagraphHelper_androidKt;-><clinit>()V
+HSPLandroidx/compose/ui/text/platform/AndroidParagraphHelper_androidKt;->createCharSequence(Ljava/lang/String;FLandroidx/compose/ui/text/TextStyle;Ljava/util/List;Ljava/util/List;Landroidx/compose/ui/unit/Density;Lkotlin/jvm/functions/Function4;Z)Ljava/lang/CharSequence;
+HSPLandroidx/compose/ui/text/platform/AndroidParagraphHelper_androidKt;->isIncludeFontPaddingEnabled(Landroidx/compose/ui/text/TextStyle;)Z
+HSPLandroidx/compose/ui/text/platform/AndroidParagraphIntrinsics$resolveTypeface$1;-><init>(Landroidx/compose/ui/text/platform/AndroidParagraphIntrinsics;)V
+HSPLandroidx/compose/ui/text/platform/AndroidParagraphIntrinsics$resolveTypeface$1;->invoke(Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;
+HSPLandroidx/compose/ui/text/platform/AndroidParagraphIntrinsics$resolveTypeface$1;->invoke-DPcqOEQ(Landroidx/compose/ui/text/font/FontFamily;Landroidx/compose/ui/text/font/FontWeight;II)Landroid/graphics/Typeface;
+HSPLandroidx/compose/ui/text/platform/AndroidParagraphIntrinsics;-><init>(Ljava/lang/String;Landroidx/compose/ui/text/TextStyle;Ljava/util/List;Ljava/util/List;Landroidx/compose/ui/text/font/FontFamily$Resolver;Landroidx/compose/ui/unit/Density;)V
+HSPLandroidx/compose/ui/text/platform/AndroidParagraphIntrinsics;->access$getResolvedTypefaces$p(Landroidx/compose/ui/text/platform/AndroidParagraphIntrinsics;)Ljava/util/List;
+HSPLandroidx/compose/ui/text/platform/AndroidParagraphIntrinsics;->getCharSequence$ui_text_release()Ljava/lang/CharSequence;
+HSPLandroidx/compose/ui/text/platform/AndroidParagraphIntrinsics;->getFontFamilyResolver()Landroidx/compose/ui/text/font/FontFamily$Resolver;
+HSPLandroidx/compose/ui/text/platform/AndroidParagraphIntrinsics;->getHasStaleResolvedFonts()Z
+HSPLandroidx/compose/ui/text/platform/AndroidParagraphIntrinsics;->getLayoutIntrinsics$ui_text_release()Landroidx/compose/ui/text/android/LayoutIntrinsics;
+HSPLandroidx/compose/ui/text/platform/AndroidParagraphIntrinsics;->getMaxIntrinsicWidth()F
+HSPLandroidx/compose/ui/text/platform/AndroidParagraphIntrinsics;->getStyle()Landroidx/compose/ui/text/TextStyle;
+HSPLandroidx/compose/ui/text/platform/AndroidParagraphIntrinsics;->getTextDirectionHeuristic$ui_text_release()I
+HSPLandroidx/compose/ui/text/platform/AndroidParagraphIntrinsics;->getTextPaint$ui_text_release()Landroidx/compose/ui/text/platform/AndroidTextPaint;
+HSPLandroidx/compose/ui/text/platform/AndroidParagraphIntrinsics_androidKt;->ActualParagraphIntrinsics(Ljava/lang/String;Landroidx/compose/ui/text/TextStyle;Ljava/util/List;Ljava/util/List;Landroidx/compose/ui/unit/Density;Landroidx/compose/ui/text/font/FontFamily$Resolver;)Landroidx/compose/ui/text/ParagraphIntrinsics;
+HSPLandroidx/compose/ui/text/platform/AndroidParagraphIntrinsics_androidKt;->resolveTextDirectionHeuristics-9GRLPo0(Landroidx/compose/ui/text/style/TextDirection;Landroidx/compose/ui/text/intl/LocaleList;)I
+HSPLandroidx/compose/ui/text/platform/AndroidParagraph_androidKt;->ActualParagraph--hBUhpc(Landroidx/compose/ui/text/ParagraphIntrinsics;IZJ)Landroidx/compose/ui/text/Paragraph;
+HSPLandroidx/compose/ui/text/platform/AndroidTextPaint;-><init>(IF)V
+HSPLandroidx/compose/ui/text/platform/AndroidTextPaint;->setBrush-12SF9DM(Landroidx/compose/ui/graphics/Brush;JF)V
+HSPLandroidx/compose/ui/text/platform/AndroidTextPaint;->setColor-8_81llA(J)V
+HSPLandroidx/compose/ui/text/platform/AndroidTextPaint;->setDrawStyle(Landroidx/compose/ui/graphics/drawscope/DrawStyle;)V
+HSPLandroidx/compose/ui/text/platform/AndroidTextPaint;->setShadow(Landroidx/compose/ui/graphics/Shadow;)V
+HSPLandroidx/compose/ui/text/platform/AndroidTextPaint;->setTextDecoration(Landroidx/compose/ui/text/style/TextDecoration;)V
+HSPLandroidx/compose/ui/text/platform/DefaultImpl$getFontLoadState$initCallback$1;-><init>(Landroidx/compose/runtime/MutableState;Landroidx/compose/ui/text/platform/DefaultImpl;)V
+HSPLandroidx/compose/ui/text/platform/DefaultImpl$getFontLoadState$initCallback$1;->onInitialized()V
+HSPLandroidx/compose/ui/text/platform/DefaultImpl;-><init>()V
+HSPLandroidx/compose/ui/text/platform/DefaultImpl;->access$setLoadState$p(Landroidx/compose/ui/text/platform/DefaultImpl;Landroidx/compose/runtime/State;)V
+HSPLandroidx/compose/ui/text/platform/DefaultImpl;->getFontLoadState()Landroidx/compose/runtime/State;
+HSPLandroidx/compose/ui/text/platform/DefaultImpl;->getFontLoaded()Landroidx/compose/runtime/State;
+HSPLandroidx/compose/ui/text/platform/EmojiCompatStatus;-><clinit>()V
+HSPLandroidx/compose/ui/text/platform/EmojiCompatStatus;-><init>()V
+HSPLandroidx/compose/ui/text/platform/EmojiCompatStatus;->getFontLoaded()Landroidx/compose/runtime/State;
+HSPLandroidx/compose/ui/text/platform/ImmutableBool;-><init>(Z)V
+HSPLandroidx/compose/ui/text/platform/ImmutableBool;->getValue()Ljava/lang/Boolean;
+HSPLandroidx/compose/ui/text/platform/ImmutableBool;->getValue()Ljava/lang/Object;
+HSPLandroidx/compose/ui/text/platform/Synchronization_jvmKt;->createSynchronizedObject()Landroidx/compose/ui/text/platform/SynchronizedObject;
+HSPLandroidx/compose/ui/text/platform/SynchronizedObject;-><init>()V
+HSPLandroidx/compose/ui/text/platform/TypefaceDirtyTracker;-><init>(Landroidx/compose/runtime/State;)V
+HSPLandroidx/compose/ui/text/platform/TypefaceDirtyTracker;->getTypeface()Landroid/graphics/Typeface;
+HSPLandroidx/compose/ui/text/platform/TypefaceDirtyTracker;->isStaleResolvedFont()Z
+HSPLandroidx/compose/ui/text/platform/extensions/PlaceholderExtensions_androidKt;->setPlaceholders(Landroid/text/Spannable;Ljava/util/List;Landroidx/compose/ui/unit/Density;)V
+HSPLandroidx/compose/ui/text/platform/extensions/SpannableExtensions_androidKt$setFontAttributes$1;-><init>(Landroid/text/Spannable;Lkotlin/jvm/functions/Function4;)V
+HSPLandroidx/compose/ui/text/platform/extensions/SpannableExtensions_androidKt;->createLetterSpacingSpan-eAf_CNQ(JLandroidx/compose/ui/unit/Density;)Landroid/text/style/MetricAffectingSpan;
+HSPLandroidx/compose/ui/text/platform/extensions/SpannableExtensions_androidKt;->flattenFontStylesAndApply(Landroidx/compose/ui/text/SpanStyle;Ljava/util/List;Lkotlin/jvm/functions/Function3;)V
+HSPLandroidx/compose/ui/text/platform/extensions/SpannableExtensions_androidKt;->hasFontAttributes(Landroidx/compose/ui/text/TextStyle;)Z
+HSPLandroidx/compose/ui/text/platform/extensions/SpannableExtensions_androidKt;->resolveLineHeightInPx-o2QH7mI(JFLandroidx/compose/ui/unit/Density;)F
+HSPLandroidx/compose/ui/text/platform/extensions/SpannableExtensions_androidKt;->setBackground-RPmYEkk(Landroid/text/Spannable;JII)V
+HSPLandroidx/compose/ui/text/platform/extensions/SpannableExtensions_androidKt;->setBaselineShift-0ocSgnM(Landroid/text/Spannable;Landroidx/compose/ui/text/style/BaselineShift;II)V
+HSPLandroidx/compose/ui/text/platform/extensions/SpannableExtensions_androidKt;->setBrush(Landroid/text/Spannable;Landroidx/compose/ui/graphics/Brush;FII)V
+HSPLandroidx/compose/ui/text/platform/extensions/SpannableExtensions_androidKt;->setColor-RPmYEkk(Landroid/text/Spannable;JII)V
+HSPLandroidx/compose/ui/text/platform/extensions/SpannableExtensions_androidKt;->setDrawStyle(Landroid/text/Spannable;Landroidx/compose/ui/graphics/drawscope/DrawStyle;II)V
+HSPLandroidx/compose/ui/text/platform/extensions/SpannableExtensions_androidKt;->setFontAttributes(Landroid/text/Spannable;Landroidx/compose/ui/text/TextStyle;Ljava/util/List;Lkotlin/jvm/functions/Function4;)V
+HSPLandroidx/compose/ui/text/platform/extensions/SpannableExtensions_androidKt;->setFontFeatureSettings(Landroid/text/Spannable;Ljava/lang/String;II)V
+HSPLandroidx/compose/ui/text/platform/extensions/SpannableExtensions_androidKt;->setFontSize-KmRG4DE(Landroid/text/Spannable;JLandroidx/compose/ui/unit/Density;II)V
+HSPLandroidx/compose/ui/text/platform/extensions/SpannableExtensions_androidKt;->setGeometricTransform(Landroid/text/Spannable;Landroidx/compose/ui/text/style/TextGeometricTransform;II)V
+HSPLandroidx/compose/ui/text/platform/extensions/SpannableExtensions_androidKt;->setLineHeight-r9BaKPg(Landroid/text/Spannable;JFLandroidx/compose/ui/unit/Density;)V
+HSPLandroidx/compose/ui/text/platform/extensions/SpannableExtensions_androidKt;->setLocaleList(Landroid/text/Spannable;Landroidx/compose/ui/text/intl/LocaleList;II)V
+HSPLandroidx/compose/ui/text/platform/extensions/SpannableExtensions_androidKt;->setShadow(Landroid/text/Spannable;Landroidx/compose/ui/graphics/Shadow;II)V
+HSPLandroidx/compose/ui/text/platform/extensions/SpannableExtensions_androidKt;->setSpan(Landroid/text/Spannable;Ljava/lang/Object;II)V
+HSPLandroidx/compose/ui/text/platform/extensions/SpannableExtensions_androidKt;->setSpanStyle(Landroid/text/Spannable;Landroidx/compose/ui/text/AnnotatedString$Range;Landroidx/compose/ui/unit/Density;Ljava/util/ArrayList;)V
+HSPLandroidx/compose/ui/text/platform/extensions/SpannableExtensions_androidKt;->setSpanStyles(Landroid/text/Spannable;Landroidx/compose/ui/text/TextStyle;Ljava/util/List;Landroidx/compose/ui/unit/Density;Lkotlin/jvm/functions/Function4;)V
+HSPLandroidx/compose/ui/text/platform/extensions/SpannableExtensions_androidKt;->setTextDecoration(Landroid/text/Spannable;Landroidx/compose/ui/text/style/TextDecoration;II)V
+HSPLandroidx/compose/ui/text/platform/extensions/SpannableExtensions_androidKt;->setTextIndent(Landroid/text/Spannable;Landroidx/compose/ui/text/style/TextIndent;FLandroidx/compose/ui/unit/Density;)V
+HSPLandroidx/compose/ui/text/platform/extensions/TextPaintExtensions_androidKt;->applySpanStyle(Landroidx/compose/ui/text/platform/AndroidTextPaint;Landroidx/compose/ui/text/SpanStyle;Lkotlin/jvm/functions/Function4;Landroidx/compose/ui/unit/Density;)Landroidx/compose/ui/text/SpanStyle;
+HSPLandroidx/compose/ui/text/platform/extensions/TextPaintExtensions_androidKt;->hasFontAttributes(Landroidx/compose/ui/text/SpanStyle;)Z
+HSPLandroidx/compose/ui/text/style/BaselineShift$Companion;-><init>()V
+HSPLandroidx/compose/ui/text/style/BaselineShift$Companion;-><init>(Lkotlin/jvm/internal/DefaultConstructorMarker;)V
+HSPLandroidx/compose/ui/text/style/BaselineShift$Companion;->getNone-y9eOQZs()F
+HSPLandroidx/compose/ui/text/style/BaselineShift;-><clinit>()V
+HSPLandroidx/compose/ui/text/style/BaselineShift;-><init>(F)V
+HSPLandroidx/compose/ui/text/style/BaselineShift;->access$getNone$cp()F
+HSPLandroidx/compose/ui/text/style/BaselineShift;->box-impl(F)Landroidx/compose/ui/text/style/BaselineShift;
+HSPLandroidx/compose/ui/text/style/BaselineShift;->constructor-impl(F)F
+HSPLandroidx/compose/ui/text/style/BaselineShift;->equals-impl0(FF)Z
+HSPLandroidx/compose/ui/text/style/BaselineShift;->unbox-impl()F
+HSPLandroidx/compose/ui/text/style/ColorStyle;-><init>(J)V
+HSPLandroidx/compose/ui/text/style/ColorStyle;-><init>(JLkotlin/jvm/internal/DefaultConstructorMarker;)V
+HSPLandroidx/compose/ui/text/style/ColorStyle;->equals(Ljava/lang/Object;)Z
+HSPLandroidx/compose/ui/text/style/ColorStyle;->getAlpha()F
+HSPLandroidx/compose/ui/text/style/ColorStyle;->getBrush()Landroidx/compose/ui/graphics/Brush;
+HSPLandroidx/compose/ui/text/style/ColorStyle;->getColor-0d7_KjU()J
+HSPLandroidx/compose/ui/text/style/Hyphens$Companion;-><init>()V
+HSPLandroidx/compose/ui/text/style/Hyphens$Companion;-><init>(Lkotlin/jvm/internal/DefaultConstructorMarker;)V
+HSPLandroidx/compose/ui/text/style/Hyphens$Companion;->getAuto()Landroidx/compose/ui/text/style/Hyphens;
+HSPLandroidx/compose/ui/text/style/Hyphens$Companion;->getNone()Landroidx/compose/ui/text/style/Hyphens;
+HSPLandroidx/compose/ui/text/style/Hyphens;-><clinit>()V
+HSPLandroidx/compose/ui/text/style/Hyphens;-><init>()V
+HSPLandroidx/compose/ui/text/style/Hyphens;->access$getAuto$cp()Landroidx/compose/ui/text/style/Hyphens;
+HSPLandroidx/compose/ui/text/style/Hyphens;->access$getNone$cp()Landroidx/compose/ui/text/style/Hyphens;
+HSPLandroidx/compose/ui/text/style/LineBreak$Companion;-><init>()V
+HSPLandroidx/compose/ui/text/style/LineBreak$Companion;-><init>(Lkotlin/jvm/internal/DefaultConstructorMarker;)V
+HSPLandroidx/compose/ui/text/style/LineBreak$Companion;->getSimple()Landroidx/compose/ui/text/style/LineBreak;
+HSPLandroidx/compose/ui/text/style/LineBreak$Strategy$Companion;-><init>()V
+HSPLandroidx/compose/ui/text/style/LineBreak$Strategy$Companion;-><init>(Lkotlin/jvm/internal/DefaultConstructorMarker;)V
+HSPLandroidx/compose/ui/text/style/LineBreak$Strategy$Companion;->getBalanced-fcGXIks()I
+HSPLandroidx/compose/ui/text/style/LineBreak$Strategy$Companion;->getHighQuality-fcGXIks()I
+HSPLandroidx/compose/ui/text/style/LineBreak$Strategy$Companion;->getSimple-fcGXIks()I
+HSPLandroidx/compose/ui/text/style/LineBreak$Strategy;-><clinit>()V
+HSPLandroidx/compose/ui/text/style/LineBreak$Strategy;-><init>(I)V
+HSPLandroidx/compose/ui/text/style/LineBreak$Strategy;->access$getBalanced$cp()I
+HSPLandroidx/compose/ui/text/style/LineBreak$Strategy;->access$getHighQuality$cp()I
+HSPLandroidx/compose/ui/text/style/LineBreak$Strategy;->access$getSimple$cp()I
+HSPLandroidx/compose/ui/text/style/LineBreak$Strategy;->box-impl(I)Landroidx/compose/ui/text/style/LineBreak$Strategy;
+HSPLandroidx/compose/ui/text/style/LineBreak$Strategy;->constructor-impl(I)I
+HSPLandroidx/compose/ui/text/style/LineBreak$Strategy;->equals-impl0(II)Z
+HSPLandroidx/compose/ui/text/style/LineBreak$Strategy;->unbox-impl()I
+HSPLandroidx/compose/ui/text/style/LineBreak$Strictness$Companion;-><init>()V
+HSPLandroidx/compose/ui/text/style/LineBreak$Strictness$Companion;-><init>(Lkotlin/jvm/internal/DefaultConstructorMarker;)V
+HSPLandroidx/compose/ui/text/style/LineBreak$Strictness$Companion;->getDefault-usljTpc()I
+HSPLandroidx/compose/ui/text/style/LineBreak$Strictness$Companion;->getLoose-usljTpc()I
+HSPLandroidx/compose/ui/text/style/LineBreak$Strictness$Companion;->getNormal-usljTpc()I
+HSPLandroidx/compose/ui/text/style/LineBreak$Strictness$Companion;->getStrict-usljTpc()I
+HSPLandroidx/compose/ui/text/style/LineBreak$Strictness;-><clinit>()V
+HSPLandroidx/compose/ui/text/style/LineBreak$Strictness;-><init>(I)V
+HSPLandroidx/compose/ui/text/style/LineBreak$Strictness;->access$getDefault$cp()I
+HSPLandroidx/compose/ui/text/style/LineBreak$Strictness;->access$getLoose$cp()I
+HSPLandroidx/compose/ui/text/style/LineBreak$Strictness;->access$getNormal$cp()I
+HSPLandroidx/compose/ui/text/style/LineBreak$Strictness;->access$getStrict$cp()I
+HSPLandroidx/compose/ui/text/style/LineBreak$Strictness;->box-impl(I)Landroidx/compose/ui/text/style/LineBreak$Strictness;
+HSPLandroidx/compose/ui/text/style/LineBreak$Strictness;->constructor-impl(I)I
+HSPLandroidx/compose/ui/text/style/LineBreak$Strictness;->equals-impl0(II)Z
+HSPLandroidx/compose/ui/text/style/LineBreak$Strictness;->unbox-impl()I
+HSPLandroidx/compose/ui/text/style/LineBreak$WordBreak$Companion;-><init>()V
+HSPLandroidx/compose/ui/text/style/LineBreak$WordBreak$Companion;-><init>(Lkotlin/jvm/internal/DefaultConstructorMarker;)V
+HSPLandroidx/compose/ui/text/style/LineBreak$WordBreak$Companion;->getDefault-jp8hJ3c()I
+HSPLandroidx/compose/ui/text/style/LineBreak$WordBreak$Companion;->getPhrase-jp8hJ3c()I
+HSPLandroidx/compose/ui/text/style/LineBreak$WordBreak;-><clinit>()V
+HSPLandroidx/compose/ui/text/style/LineBreak$WordBreak;-><init>(I)V
+HSPLandroidx/compose/ui/text/style/LineBreak$WordBreak;->access$getDefault$cp()I
+HSPLandroidx/compose/ui/text/style/LineBreak$WordBreak;->access$getPhrase$cp()I
+HSPLandroidx/compose/ui/text/style/LineBreak$WordBreak;->box-impl(I)Landroidx/compose/ui/text/style/LineBreak$WordBreak;
+HSPLandroidx/compose/ui/text/style/LineBreak$WordBreak;->constructor-impl(I)I
+HSPLandroidx/compose/ui/text/style/LineBreak$WordBreak;->equals-impl0(II)Z
+HSPLandroidx/compose/ui/text/style/LineBreak$WordBreak;->unbox-impl()I
+HSPLandroidx/compose/ui/text/style/LineBreak;-><clinit>()V
+HSPLandroidx/compose/ui/text/style/LineBreak;-><init>(III)V
+HSPLandroidx/compose/ui/text/style/LineBreak;-><init>(IIILkotlin/jvm/internal/DefaultConstructorMarker;)V
+HSPLandroidx/compose/ui/text/style/LineBreak;->access$getSimple$cp()Landroidx/compose/ui/text/style/LineBreak;
+HSPLandroidx/compose/ui/text/style/LineBreak;->getStrategy-fcGXIks()I
+HSPLandroidx/compose/ui/text/style/LineBreak;->getStrictness-usljTpc()I
+HSPLandroidx/compose/ui/text/style/LineBreak;->getWordBreak-jp8hJ3c()I
+HSPLandroidx/compose/ui/text/style/TextAlign$Companion;-><init>()V
+HSPLandroidx/compose/ui/text/style/TextAlign$Companion;-><init>(Lkotlin/jvm/internal/DefaultConstructorMarker;)V
+HSPLandroidx/compose/ui/text/style/TextAlign$Companion;->getCenter-e0LSkKk()I
+HSPLandroidx/compose/ui/text/style/TextAlign$Companion;->getJustify-e0LSkKk()I
+HSPLandroidx/compose/ui/text/style/TextAlign$Companion;->getLeft-e0LSkKk()I
+HSPLandroidx/compose/ui/text/style/TextAlign$Companion;->getRight-e0LSkKk()I
+HSPLandroidx/compose/ui/text/style/TextAlign$Companion;->getStart-e0LSkKk()I
+HSPLandroidx/compose/ui/text/style/TextAlign;-><clinit>()V
+HSPLandroidx/compose/ui/text/style/TextAlign;-><init>(I)V
+HSPLandroidx/compose/ui/text/style/TextAlign;->access$getCenter$cp()I
+HSPLandroidx/compose/ui/text/style/TextAlign;->access$getJustify$cp()I
+HSPLandroidx/compose/ui/text/style/TextAlign;->access$getLeft$cp()I
+HSPLandroidx/compose/ui/text/style/TextAlign;->access$getRight$cp()I
+HSPLandroidx/compose/ui/text/style/TextAlign;->access$getStart$cp()I
+HSPLandroidx/compose/ui/text/style/TextAlign;->box-impl(I)Landroidx/compose/ui/text/style/TextAlign;
+HSPLandroidx/compose/ui/text/style/TextAlign;->constructor-impl(I)I
+HSPLandroidx/compose/ui/text/style/TextAlign;->equals(Ljava/lang/Object;)Z
+HSPLandroidx/compose/ui/text/style/TextAlign;->equals-impl(ILjava/lang/Object;)Z
+HSPLandroidx/compose/ui/text/style/TextAlign;->equals-impl0(II)Z
+HSPLandroidx/compose/ui/text/style/TextAlign;->unbox-impl()I
+HSPLandroidx/compose/ui/text/style/TextDecoration$Companion;-><init>()V
+HSPLandroidx/compose/ui/text/style/TextDecoration$Companion;-><init>(Lkotlin/jvm/internal/DefaultConstructorMarker;)V
+HSPLandroidx/compose/ui/text/style/TextDecoration$Companion;->getNone()Landroidx/compose/ui/text/style/TextDecoration;
+HSPLandroidx/compose/ui/text/style/TextDecoration$Companion;->getUnderline()Landroidx/compose/ui/text/style/TextDecoration;
+HSPLandroidx/compose/ui/text/style/TextDecoration;-><clinit>()V
+HSPLandroidx/compose/ui/text/style/TextDecoration;-><init>(I)V
+HSPLandroidx/compose/ui/text/style/TextDecoration;->access$getNone$cp()Landroidx/compose/ui/text/style/TextDecoration;
+HSPLandroidx/compose/ui/text/style/TextDecoration;->access$getUnderline$cp()Landroidx/compose/ui/text/style/TextDecoration;
+HSPLandroidx/compose/ui/text/style/TextDecoration;->equals(Ljava/lang/Object;)Z
+HSPLandroidx/compose/ui/text/style/TextDirection$Companion;-><init>()V
+HSPLandroidx/compose/ui/text/style/TextDirection$Companion;-><init>(Lkotlin/jvm/internal/DefaultConstructorMarker;)V
+HSPLandroidx/compose/ui/text/style/TextDirection$Companion;->getContent-s_7X-co()I
+HSPLandroidx/compose/ui/text/style/TextDirection$Companion;->getContentOrLtr-s_7X-co()I
+HSPLandroidx/compose/ui/text/style/TextDirection$Companion;->getContentOrRtl-s_7X-co()I
+HSPLandroidx/compose/ui/text/style/TextDirection$Companion;->getLtr-s_7X-co()I
+HSPLandroidx/compose/ui/text/style/TextDirection;-><clinit>()V
+HSPLandroidx/compose/ui/text/style/TextDirection;-><init>(I)V
+HSPLandroidx/compose/ui/text/style/TextDirection;->access$getContent$cp()I
+HSPLandroidx/compose/ui/text/style/TextDirection;->access$getContentOrLtr$cp()I
+HSPLandroidx/compose/ui/text/style/TextDirection;->access$getContentOrRtl$cp()I
+HSPLandroidx/compose/ui/text/style/TextDirection;->access$getLtr$cp()I
+HSPLandroidx/compose/ui/text/style/TextDirection;->box-impl(I)Landroidx/compose/ui/text/style/TextDirection;
+HSPLandroidx/compose/ui/text/style/TextDirection;->constructor-impl(I)I
+HSPLandroidx/compose/ui/text/style/TextDirection;->equals-impl0(II)Z
+HSPLandroidx/compose/ui/text/style/TextDirection;->unbox-impl()I
+HSPLandroidx/compose/ui/text/style/TextForegroundStyle$Companion;-><clinit>()V
+HSPLandroidx/compose/ui/text/style/TextForegroundStyle$Companion;-><init>()V
+HSPLandroidx/compose/ui/text/style/TextForegroundStyle$Companion;->from-8_81llA(J)Landroidx/compose/ui/text/style/TextForegroundStyle;
+HSPLandroidx/compose/ui/text/style/TextForegroundStyle$Unspecified;-><clinit>()V
+HSPLandroidx/compose/ui/text/style/TextForegroundStyle$Unspecified;-><init>()V
+HSPLandroidx/compose/ui/text/style/TextForegroundStyle$Unspecified;->getAlpha()F
+HSPLandroidx/compose/ui/text/style/TextForegroundStyle$Unspecified;->getBrush()Landroidx/compose/ui/graphics/Brush;
+HSPLandroidx/compose/ui/text/style/TextForegroundStyle$Unspecified;->getColor-0d7_KjU()J
+HSPLandroidx/compose/ui/text/style/TextForegroundStyle$merge$2;-><init>(Landroidx/compose/ui/text/style/TextForegroundStyle;)V
+HSPLandroidx/compose/ui/text/style/TextForegroundStyle$merge$2;->invoke()Landroidx/compose/ui/text/style/TextForegroundStyle;
+HSPLandroidx/compose/ui/text/style/TextForegroundStyle$merge$2;->invoke()Ljava/lang/Object;
+HSPLandroidx/compose/ui/text/style/TextForegroundStyle;-><clinit>()V
+HSPLandroidx/compose/ui/text/style/TextForegroundStyle;->merge(Landroidx/compose/ui/text/style/TextForegroundStyle;)Landroidx/compose/ui/text/style/TextForegroundStyle;
+HSPLandroidx/compose/ui/text/style/TextForegroundStyle;->takeOrElse(Lkotlin/jvm/functions/Function0;)Landroidx/compose/ui/text/style/TextForegroundStyle;
+HSPLandroidx/compose/ui/text/style/TextGeometricTransform$Companion;-><init>()V
+HSPLandroidx/compose/ui/text/style/TextGeometricTransform$Companion;-><init>(Lkotlin/jvm/internal/DefaultConstructorMarker;)V
+HSPLandroidx/compose/ui/text/style/TextGeometricTransform$Companion;->getNone$ui_text_release()Landroidx/compose/ui/text/style/TextGeometricTransform;
+HSPLandroidx/compose/ui/text/style/TextGeometricTransform;-><clinit>()V
+HSPLandroidx/compose/ui/text/style/TextGeometricTransform;-><init>(FF)V
+HSPLandroidx/compose/ui/text/style/TextGeometricTransform;->access$getNone$cp()Landroidx/compose/ui/text/style/TextGeometricTransform;
+HSPLandroidx/compose/ui/text/style/TextGeometricTransform;->equals(Ljava/lang/Object;)Z
+HSPLandroidx/compose/ui/text/style/TextIndent$Companion;-><init>()V
+HSPLandroidx/compose/ui/text/style/TextIndent$Companion;-><init>(Lkotlin/jvm/internal/DefaultConstructorMarker;)V
+HSPLandroidx/compose/ui/text/style/TextIndent$Companion;->getNone()Landroidx/compose/ui/text/style/TextIndent;
+HSPLandroidx/compose/ui/text/style/TextIndent;-><clinit>()V
+HSPLandroidx/compose/ui/text/style/TextIndent;-><init>(JJ)V
+HSPLandroidx/compose/ui/text/style/TextIndent;-><init>(JJILkotlin/jvm/internal/DefaultConstructorMarker;)V
+HSPLandroidx/compose/ui/text/style/TextIndent;-><init>(JJLkotlin/jvm/internal/DefaultConstructorMarker;)V
+HSPLandroidx/compose/ui/text/style/TextIndent;->access$getNone$cp()Landroidx/compose/ui/text/style/TextIndent;
+HSPLandroidx/compose/ui/text/style/TextIndent;->getFirstLine-XSAIIZE()J
+HSPLandroidx/compose/ui/text/style/TextIndent;->getRestLine-XSAIIZE()J
+HSPLandroidx/compose/ui/text/style/TextOverflow$Companion;-><init>()V
+HSPLandroidx/compose/ui/text/style/TextOverflow$Companion;-><init>(Lkotlin/jvm/internal/DefaultConstructorMarker;)V
+HSPLandroidx/compose/ui/text/style/TextOverflow$Companion;->getClip-gIe3tQ8()I
+HSPLandroidx/compose/ui/text/style/TextOverflow$Companion;->getEllipsis-gIe3tQ8()I
+HSPLandroidx/compose/ui/text/style/TextOverflow;-><clinit>()V
+HSPLandroidx/compose/ui/text/style/TextOverflow;->access$getClip$cp()I
+HSPLandroidx/compose/ui/text/style/TextOverflow;->access$getEllipsis$cp()I
+HSPLandroidx/compose/ui/text/style/TextOverflow;->constructor-impl(I)I
+HSPLandroidx/compose/ui/text/style/TextOverflow;->equals-impl0(II)Z
+HSPLandroidx/compose/ui/unit/AndroidDensity_androidKt;->Density(Landroid/content/Context;)Landroidx/compose/ui/unit/Density;
+HSPLandroidx/compose/ui/unit/Constraints$Companion;-><init>()V
+HSPLandroidx/compose/ui/unit/Constraints$Companion;-><init>(Lkotlin/jvm/internal/DefaultConstructorMarker;)V
+HSPLandroidx/compose/ui/unit/Constraints$Companion;->bitsNeedForSize(I)I
+HSPLandroidx/compose/ui/unit/Constraints$Companion;->createConstraints-Zbe2FdA$ui_unit_release(IIII)J
+HSPLandroidx/compose/ui/unit/Constraints;-><clinit>()V
+HSPLandroidx/compose/ui/unit/Constraints;-><init>(J)V
+HSPLandroidx/compose/ui/unit/Constraints;->access$getMinHeightOffsets$cp()[I
+HSPLandroidx/compose/ui/unit/Constraints;->box-impl(J)Landroidx/compose/ui/unit/Constraints;
+HSPLandroidx/compose/ui/unit/Constraints;->constructor-impl(J)J
+HSPLandroidx/compose/ui/unit/Constraints;->copy-Zbe2FdA$default(JIIIIILjava/lang/Object;)J
+HSPLandroidx/compose/ui/unit/Constraints;->copy-Zbe2FdA(JIIII)J
+HSPLandroidx/compose/ui/unit/Constraints;->equals-impl0(JJ)Z
+HSPLandroidx/compose/ui/unit/Constraints;->getFocusIndex-impl(J)I
+HSPLandroidx/compose/ui/unit/Constraints;->getHasBoundedHeight-impl(J)Z
+HSPLandroidx/compose/ui/unit/Constraints;->getHasBoundedWidth-impl(J)Z
+HSPLandroidx/compose/ui/unit/Constraints;->getHasFixedHeight-impl(J)Z
+HSPLandroidx/compose/ui/unit/Constraints;->getHasFixedWidth-impl(J)Z
+HSPLandroidx/compose/ui/unit/Constraints;->getMaxHeight-impl(J)I
+HSPLandroidx/compose/ui/unit/Constraints;->getMaxWidth-impl(J)I
+HSPLandroidx/compose/ui/unit/Constraints;->getMinHeight-impl(J)I
+HSPLandroidx/compose/ui/unit/Constraints;->getMinWidth-impl(J)I
+HSPLandroidx/compose/ui/unit/Constraints;->unbox-impl()J
+HSPLandroidx/compose/ui/unit/ConstraintsKt;->Constraints$default(IIIIILjava/lang/Object;)J
+HSPLandroidx/compose/ui/unit/ConstraintsKt;->Constraints(IIII)J
+HSPLandroidx/compose/ui/unit/ConstraintsKt;->addMaxWithMinimum(II)I
+HSPLandroidx/compose/ui/unit/ConstraintsKt;->constrain-4WqzIAM(JJ)J
+HSPLandroidx/compose/ui/unit/ConstraintsKt;->constrain-N9IONVI(JJ)J
+HSPLandroidx/compose/ui/unit/ConstraintsKt;->constrainHeight-K40F9xA(JI)I
+HSPLandroidx/compose/ui/unit/ConstraintsKt;->constrainWidth-K40F9xA(JI)I
+HSPLandroidx/compose/ui/unit/ConstraintsKt;->offset-NN6Ew-U(JII)J
+HSPLandroidx/compose/ui/unit/Density;->roundToPx-0680j_4(F)I
+HSPLandroidx/compose/ui/unit/Density;->toPx--R2X_6o(J)F
+HSPLandroidx/compose/ui/unit/Density;->toPx-0680j_4(F)F
+HSPLandroidx/compose/ui/unit/DensityImpl;-><init>(FF)V
+HSPLandroidx/compose/ui/unit/DensityImpl;->equals(Ljava/lang/Object;)Z
+HSPLandroidx/compose/ui/unit/DensityImpl;->getDensity()F
+HSPLandroidx/compose/ui/unit/DensityImpl;->getFontScale()F
+HSPLandroidx/compose/ui/unit/DensityKt;->Density$default(FFILjava/lang/Object;)Landroidx/compose/ui/unit/Density;
+HSPLandroidx/compose/ui/unit/DensityKt;->Density(FF)Landroidx/compose/ui/unit/Density;
+HSPLandroidx/compose/ui/unit/Dp$Companion;-><init>()V
+HSPLandroidx/compose/ui/unit/Dp$Companion;-><init>(Lkotlin/jvm/internal/DefaultConstructorMarker;)V
+HSPLandroidx/compose/ui/unit/Dp$Companion;->getHairline-D9Ej5fM()F
+HSPLandroidx/compose/ui/unit/Dp$Companion;->getUnspecified-D9Ej5fM()F
+HSPLandroidx/compose/ui/unit/Dp;-><clinit>()V
+HSPLandroidx/compose/ui/unit/Dp;-><init>(F)V
+HSPLandroidx/compose/ui/unit/Dp;->access$getHairline$cp()F
+HSPLandroidx/compose/ui/unit/Dp;->access$getUnspecified$cp()F
+HSPLandroidx/compose/ui/unit/Dp;->box-impl(F)Landroidx/compose/ui/unit/Dp;
+HSPLandroidx/compose/ui/unit/Dp;->compareTo(Ljava/lang/Object;)I
+HSPLandroidx/compose/ui/unit/Dp;->compareTo-0680j_4(F)I
+HSPLandroidx/compose/ui/unit/Dp;->compareTo-0680j_4(FF)I
+HSPLandroidx/compose/ui/unit/Dp;->constructor-impl(F)F
+HSPLandroidx/compose/ui/unit/Dp;->equals(Ljava/lang/Object;)Z
+HSPLandroidx/compose/ui/unit/Dp;->equals-impl(FLjava/lang/Object;)Z
+HSPLandroidx/compose/ui/unit/Dp;->equals-impl0(FF)Z
+HSPLandroidx/compose/ui/unit/Dp;->unbox-impl()F
+HSPLandroidx/compose/ui/unit/DpKt;->DpOffset-YgX7TsA(FF)J
+HSPLandroidx/compose/ui/unit/DpKt;->DpSize-YgX7TsA(FF)J
+HSPLandroidx/compose/ui/unit/DpOffset$Companion;-><init>()V
+HSPLandroidx/compose/ui/unit/DpOffset$Companion;-><init>(Lkotlin/jvm/internal/DefaultConstructorMarker;)V
+HSPLandroidx/compose/ui/unit/DpOffset;-><clinit>()V
+HSPLandroidx/compose/ui/unit/DpOffset;->constructor-impl(J)J
+HSPLandroidx/compose/ui/unit/DpSize$Companion;-><init>()V
+HSPLandroidx/compose/ui/unit/DpSize$Companion;-><init>(Lkotlin/jvm/internal/DefaultConstructorMarker;)V
+HSPLandroidx/compose/ui/unit/DpSize;-><clinit>()V
+HSPLandroidx/compose/ui/unit/DpSize;->constructor-impl(J)J
+HSPLandroidx/compose/ui/unit/DpSize;->equals-impl0(JJ)Z
+HSPLandroidx/compose/ui/unit/DpSize;->getHeight-D9Ej5fM(J)F
+HSPLandroidx/compose/ui/unit/DpSize;->getWidth-D9Ej5fM(J)F
+HSPLandroidx/compose/ui/unit/IntOffset$Companion;-><init>()V
+HSPLandroidx/compose/ui/unit/IntOffset$Companion;-><init>(Lkotlin/jvm/internal/DefaultConstructorMarker;)V
+HSPLandroidx/compose/ui/unit/IntOffset$Companion;->getZero-nOcc-ac()J
+HSPLandroidx/compose/ui/unit/IntOffset;-><clinit>()V
+HSPLandroidx/compose/ui/unit/IntOffset;-><init>(J)V
+HSPLandroidx/compose/ui/unit/IntOffset;->access$getZero$cp()J
+HSPLandroidx/compose/ui/unit/IntOffset;->box-impl(J)Landroidx/compose/ui/unit/IntOffset;
+HSPLandroidx/compose/ui/unit/IntOffset;->component1-impl(J)I
+HSPLandroidx/compose/ui/unit/IntOffset;->component2-impl(J)I
+HSPLandroidx/compose/ui/unit/IntOffset;->constructor-impl(J)J
+HSPLandroidx/compose/ui/unit/IntOffset;->equals-impl0(JJ)Z
+HSPLandroidx/compose/ui/unit/IntOffset;->getX-impl(J)I
+HSPLandroidx/compose/ui/unit/IntOffset;->getY-impl(J)I
+HSPLandroidx/compose/ui/unit/IntOffset;->unbox-impl()J
+HSPLandroidx/compose/ui/unit/IntOffsetKt;->IntOffset(II)J
+HSPLandroidx/compose/ui/unit/IntSize$Companion;-><init>()V
+HSPLandroidx/compose/ui/unit/IntSize$Companion;-><init>(Lkotlin/jvm/internal/DefaultConstructorMarker;)V
+HSPLandroidx/compose/ui/unit/IntSize$Companion;->getZero-YbymL2g()J
+HSPLandroidx/compose/ui/unit/IntSize;-><clinit>()V
+HSPLandroidx/compose/ui/unit/IntSize;-><init>(J)V
+HSPLandroidx/compose/ui/unit/IntSize;->access$getZero$cp()J
+HSPLandroidx/compose/ui/unit/IntSize;->box-impl(J)Landroidx/compose/ui/unit/IntSize;
+HSPLandroidx/compose/ui/unit/IntSize;->constructor-impl(J)J
+HSPLandroidx/compose/ui/unit/IntSize;->equals-impl0(JJ)Z
+HSPLandroidx/compose/ui/unit/IntSize;->getHeight-impl(J)I
+HSPLandroidx/compose/ui/unit/IntSize;->getWidth-impl(J)I
+HSPLandroidx/compose/ui/unit/IntSizeKt;->IntSize(II)J
+HSPLandroidx/compose/ui/unit/IntSizeKt;->getCenter-ozmzZPI(J)J
+HSPLandroidx/compose/ui/unit/IntSizeKt;->toSize-ozmzZPI(J)J
+HSPLandroidx/compose/ui/unit/LayoutDirection;->$values()[Landroidx/compose/ui/unit/LayoutDirection;
+HSPLandroidx/compose/ui/unit/LayoutDirection;-><clinit>()V
+HSPLandroidx/compose/ui/unit/LayoutDirection;-><init>(Ljava/lang/String;I)V
+HSPLandroidx/compose/ui/unit/LayoutDirection;->values()[Landroidx/compose/ui/unit/LayoutDirection;
+HSPLandroidx/compose/ui/unit/TextUnit$Companion;-><init>()V
+HSPLandroidx/compose/ui/unit/TextUnit$Companion;-><init>(Lkotlin/jvm/internal/DefaultConstructorMarker;)V
+HSPLandroidx/compose/ui/unit/TextUnit$Companion;->getUnspecified-XSAIIZE()J
+HSPLandroidx/compose/ui/unit/TextUnit;-><clinit>()V
+HSPLandroidx/compose/ui/unit/TextUnit;->access$getUnspecified$cp()J
+HSPLandroidx/compose/ui/unit/TextUnit;->constructor-impl(J)J
+HSPLandroidx/compose/ui/unit/TextUnit;->equals-impl0(JJ)Z
+HSPLandroidx/compose/ui/unit/TextUnit;->getRawType-impl(J)J
+HSPLandroidx/compose/ui/unit/TextUnit;->getType-UIouoOA(J)J
+HSPLandroidx/compose/ui/unit/TextUnit;->getValue-impl(J)F
+HSPLandroidx/compose/ui/unit/TextUnitKt;->checkArithmetic--R2X_6o(J)V
+HSPLandroidx/compose/ui/unit/TextUnitKt;->getSp(D)J
+HSPLandroidx/compose/ui/unit/TextUnitKt;->getSp(I)J
+HSPLandroidx/compose/ui/unit/TextUnitKt;->isUnspecified--R2X_6o(J)Z
+HSPLandroidx/compose/ui/unit/TextUnitKt;->pack(JF)J
+HSPLandroidx/compose/ui/unit/TextUnitType$Companion;-><init>()V
+HSPLandroidx/compose/ui/unit/TextUnitType$Companion;-><init>(Lkotlin/jvm/internal/DefaultConstructorMarker;)V
+HSPLandroidx/compose/ui/unit/TextUnitType$Companion;->getEm-UIouoOA()J
+HSPLandroidx/compose/ui/unit/TextUnitType$Companion;->getSp-UIouoOA()J
+HSPLandroidx/compose/ui/unit/TextUnitType$Companion;->getUnspecified-UIouoOA()J
+HSPLandroidx/compose/ui/unit/TextUnitType;-><clinit>()V
+HSPLandroidx/compose/ui/unit/TextUnitType;-><init>(J)V
+HSPLandroidx/compose/ui/unit/TextUnitType;->access$getEm$cp()J
+HSPLandroidx/compose/ui/unit/TextUnitType;->access$getSp$cp()J
+HSPLandroidx/compose/ui/unit/TextUnitType;->access$getUnspecified$cp()J
+HSPLandroidx/compose/ui/unit/TextUnitType;->box-impl(J)Landroidx/compose/ui/unit/TextUnitType;
+HSPLandroidx/compose/ui/unit/TextUnitType;->constructor-impl(J)J
+HSPLandroidx/compose/ui/unit/TextUnitType;->equals-impl0(JJ)Z
+HSPLandroidx/compose/ui/unit/TextUnitType;->unbox-impl()J
+HSPLandroidx/core/app/ComponentActivity;-><init>()V
+HSPLandroidx/core/app/ComponentActivity;->onCreate(Landroid/os/Bundle;)V
+HSPLandroidx/core/app/CoreComponentFactory;-><init>()V
+HSPLandroidx/core/app/CoreComponentFactory;->checkCompatWrapper(Ljava/lang/Object;)Ljava/lang/Object;
+HSPLandroidx/core/app/CoreComponentFactory;->instantiateActivity(Ljava/lang/ClassLoader;Ljava/lang/String;Landroid/content/Intent;)Landroid/app/Activity;
+HSPLandroidx/core/app/CoreComponentFactory;->instantiateApplication(Ljava/lang/ClassLoader;Ljava/lang/String;)Landroid/app/Application;
+HSPLandroidx/core/app/CoreComponentFactory;->instantiateProvider(Ljava/lang/ClassLoader;Ljava/lang/String;)Landroid/content/ContentProvider;
+HSPLandroidx/core/graphics/TypefaceCompat;-><clinit>()V
+HSPLandroidx/core/graphics/TypefaceCompat;->createFromFontInfo(Landroid/content/Context;Landroid/os/CancellationSignal;[Landroidx/core/provider/FontsContractCompat$FontInfo;I)Landroid/graphics/Typeface;
+HSPLandroidx/core/graphics/TypefaceCompatApi29Impl;-><init>()V
+HSPLandroidx/core/graphics/TypefaceCompatApi29Impl;->createFromFontInfo(Landroid/content/Context;Landroid/os/CancellationSignal;[Landroidx/core/provider/FontsContractCompat$FontInfo;I)Landroid/graphics/Typeface;
+HSPLandroidx/core/graphics/TypefaceCompatApi29Impl;->findBaseFont(Landroid/graphics/fonts/FontFamily;I)Landroid/graphics/fonts/Font;
+HSPLandroidx/core/graphics/TypefaceCompatApi29Impl;->getMatchScore(Landroid/graphics/fonts/FontStyle;Landroid/graphics/fonts/FontStyle;)I
+HSPLandroidx/core/graphics/TypefaceCompatBaseImpl;-><init>()V
+HSPLandroidx/core/graphics/TypefaceCompatUtil$Api19Impl;->openFileDescriptor(Landroid/content/ContentResolver;Landroid/net/Uri;Ljava/lang/String;Landroid/os/CancellationSignal;)Landroid/os/ParcelFileDescriptor;
+HSPLandroidx/core/graphics/TypefaceCompatUtil;->mmap(Landroid/content/Context;Landroid/os/CancellationSignal;Landroid/net/Uri;)Ljava/nio/ByteBuffer;
+HSPLandroidx/core/graphics/drawable/DrawableKt;->toBitmap$default(Landroid/graphics/drawable/Drawable;IILandroid/graphics/Bitmap$Config;ILjava/lang/Object;)Landroid/graphics/Bitmap;
+HSPLandroidx/core/graphics/drawable/DrawableKt;->toBitmap(Landroid/graphics/drawable/Drawable;IILandroid/graphics/Bitmap$Config;)Landroid/graphics/Bitmap;
+HSPLandroidx/core/os/BuildCompat;->isAtLeastT()Z
+HSPLandroidx/core/os/HandlerCompat$Api28Impl;->createAsync(Landroid/os/Looper;)Landroid/os/Handler;
+HSPLandroidx/core/os/HandlerCompat;->createAsync(Landroid/os/Looper;)Landroid/os/Handler;
+HSPLandroidx/core/os/TraceCompat$Api18Impl;->beginSection(Ljava/lang/String;)V
+HSPLandroidx/core/os/TraceCompat$Api18Impl;->endSection()V
+HSPLandroidx/core/os/TraceCompat;-><clinit>()V
+HSPLandroidx/core/os/TraceCompat;->beginSection(Ljava/lang/String;)V
+HSPLandroidx/core/os/TraceCompat;->endSection()V
+HSPLandroidx/core/provider/FontProvider$$ExternalSyntheticLambda0;-><init>()V
+HSPLandroidx/core/provider/FontProvider$Api16Impl;->query(Landroid/content/ContentResolver;Landroid/net/Uri;[Ljava/lang/String;Ljava/lang/String;[Ljava/lang/String;Ljava/lang/String;Ljava/lang/Object;)Landroid/database/Cursor;
+HSPLandroidx/core/provider/FontProvider;-><clinit>()V
+HSPLandroidx/core/provider/FontProvider;->convertToByteArrayList([Landroid/content/pm/Signature;)Ljava/util/List;
+HSPLandroidx/core/provider/FontProvider;->equalsByteArrayList(Ljava/util/List;Ljava/util/List;)Z
+HSPLandroidx/core/provider/FontProvider;->getCertificates(Landroidx/core/provider/FontRequest;Landroid/content/res/Resources;)Ljava/util/List;
+HSPLandroidx/core/provider/FontProvider;->getFontFamilyResult(Landroid/content/Context;Landroidx/core/provider/FontRequest;Landroid/os/CancellationSignal;)Landroidx/core/provider/FontsContractCompat$FontFamilyResult;
+HSPLandroidx/core/provider/FontProvider;->getProvider(Landroid/content/pm/PackageManager;Landroidx/core/provider/FontRequest;Landroid/content/res/Resources;)Landroid/content/pm/ProviderInfo;
+HSPLandroidx/core/provider/FontProvider;->query(Landroid/content/Context;Landroidx/core/provider/FontRequest;Ljava/lang/String;Landroid/os/CancellationSignal;)[Landroidx/core/provider/FontsContractCompat$FontInfo;
+HSPLandroidx/core/provider/FontRequest;-><init>(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/util/List;)V
+HSPLandroidx/core/provider/FontRequest;->createIdentifier(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)Ljava/lang/String;
+HSPLandroidx/core/provider/FontRequest;->getCertificates()Ljava/util/List;
+HSPLandroidx/core/provider/FontRequest;->getProviderAuthority()Ljava/lang/String;
+HSPLandroidx/core/provider/FontRequest;->getProviderPackage()Ljava/lang/String;
+HSPLandroidx/core/provider/FontRequest;->getQuery()Ljava/lang/String;
+HSPLandroidx/core/provider/FontsContractCompat$FontFamilyResult;-><init>(I[Landroidx/core/provider/FontsContractCompat$FontInfo;)V
+HSPLandroidx/core/provider/FontsContractCompat$FontFamilyResult;->create(I[Landroidx/core/provider/FontsContractCompat$FontInfo;)Landroidx/core/provider/FontsContractCompat$FontFamilyResult;
+HSPLandroidx/core/provider/FontsContractCompat$FontFamilyResult;->getFonts()[Landroidx/core/provider/FontsContractCompat$FontInfo;
+HSPLandroidx/core/provider/FontsContractCompat$FontFamilyResult;->getStatusCode()I
+HSPLandroidx/core/provider/FontsContractCompat$FontInfo;-><init>(Landroid/net/Uri;IIZI)V
+HSPLandroidx/core/provider/FontsContractCompat$FontInfo;->create(Landroid/net/Uri;IIZI)Landroidx/core/provider/FontsContractCompat$FontInfo;
+HSPLandroidx/core/provider/FontsContractCompat$FontInfo;->getResultCode()I
+HSPLandroidx/core/provider/FontsContractCompat$FontInfo;->getTtcIndex()I
+HSPLandroidx/core/provider/FontsContractCompat$FontInfo;->getUri()Landroid/net/Uri;
+HSPLandroidx/core/provider/FontsContractCompat$FontInfo;->getWeight()I
+HSPLandroidx/core/provider/FontsContractCompat$FontInfo;->isItalic()Z
+HSPLandroidx/core/provider/FontsContractCompat;->buildTypeface(Landroid/content/Context;Landroid/os/CancellationSignal;[Landroidx/core/provider/FontsContractCompat$FontInfo;)Landroid/graphics/Typeface;
+HSPLandroidx/core/provider/FontsContractCompat;->fetchFonts(Landroid/content/Context;Landroid/os/CancellationSignal;Landroidx/core/provider/FontRequest;)Landroidx/core/provider/FontsContractCompat$FontFamilyResult;
+HSPLandroidx/core/util/Preconditions;->checkArgument(ZLjava/lang/Object;)V
+HSPLandroidx/core/util/Preconditions;->checkArgumentNonnegative(ILjava/lang/String;)I
+HSPLandroidx/core/util/Preconditions;->checkNotNull(Ljava/lang/Object;)Ljava/lang/Object;
+HSPLandroidx/core/util/Preconditions;->checkNotNull(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;
+HSPLandroidx/core/util/Preconditions;->checkState(ZLjava/lang/String;)V
+HSPLandroidx/core/view/AccessibilityDelegateCompat$AccessibilityDelegateAdapter;-><init>(Landroidx/core/view/AccessibilityDelegateCompat;)V
+HSPLandroidx/core/view/AccessibilityDelegateCompat;-><clinit>()V
+HSPLandroidx/core/view/AccessibilityDelegateCompat;-><init>()V
+HSPLandroidx/core/view/AccessibilityDelegateCompat;-><init>(Landroid/view/View$AccessibilityDelegate;)V
+HSPLandroidx/core/view/AccessibilityDelegateCompat;->getBridge()Landroid/view/View$AccessibilityDelegate;
+HSPLandroidx/core/view/MenuHostHelper;-><init>(Ljava/lang/Runnable;)V
+HSPLandroidx/core/view/ViewCompat$$ExternalSyntheticLambda0;-><init>()V
+HSPLandroidx/core/view/ViewCompat$AccessibilityPaneVisibilityManager;-><init>()V
+HSPLandroidx/core/view/ViewCompat;-><clinit>()V
+HSPLandroidx/core/view/ViewCompat;->setAccessibilityDelegate(Landroid/view/View;Landroidx/core/view/AccessibilityDelegateCompat;)V
+HSPLandroidx/core/view/accessibility/AccessibilityNodeProviderCompat;-><init>(Ljava/lang/Object;)V
+HSPLandroidx/customview/poolingcontainer/PoolingContainer;-><clinit>()V
+HSPLandroidx/customview/poolingcontainer/PoolingContainer;->addPoolingContainerListener(Landroid/view/View;Landroidx/customview/poolingcontainer/PoolingContainerListener;)V
+HSPLandroidx/customview/poolingcontainer/PoolingContainer;->getPoolingContainerListenerHolder(Landroid/view/View;)Landroidx/customview/poolingcontainer/PoolingContainerListenerHolder;
+HSPLandroidx/customview/poolingcontainer/PoolingContainerListenerHolder;-><init>()V
+HSPLandroidx/customview/poolingcontainer/PoolingContainerListenerHolder;->addListener(Landroidx/customview/poolingcontainer/PoolingContainerListener;)V
+HSPLandroidx/emoji2/text/ConcurrencyHelpers$$ExternalSyntheticLambda0;-><init>(Ljava/lang/String;)V
+HSPLandroidx/emoji2/text/ConcurrencyHelpers$$ExternalSyntheticLambda0;->newThread(Ljava/lang/Runnable;)Ljava/lang/Thread;
+HSPLandroidx/emoji2/text/ConcurrencyHelpers$Handler28Impl;->createAsync(Landroid/os/Looper;)Landroid/os/Handler;
+HSPLandroidx/emoji2/text/ConcurrencyHelpers;->$r8$lambda$rm7NN8F9tEuy2Vr8i0fl8_hnx_A(Ljava/lang/String;Ljava/lang/Runnable;)Ljava/lang/Thread;
+HSPLandroidx/emoji2/text/ConcurrencyHelpers;->createBackgroundPriorityExecutor(Ljava/lang/String;)Ljava/util/concurrent/ThreadPoolExecutor;
+HSPLandroidx/emoji2/text/ConcurrencyHelpers;->lambda$createBackgroundPriorityExecutor$0(Ljava/lang/String;Ljava/lang/Runnable;)Ljava/lang/Thread;
+HSPLandroidx/emoji2/text/ConcurrencyHelpers;->mainHandlerAsync()Landroid/os/Handler;
+HSPLandroidx/emoji2/text/DefaultEmojiCompatConfig$DefaultEmojiCompatConfigFactory;-><init>(Landroidx/emoji2/text/DefaultEmojiCompatConfig$DefaultEmojiCompatConfigHelper;)V
+HSPLandroidx/emoji2/text/DefaultEmojiCompatConfig$DefaultEmojiCompatConfigFactory;->configOrNull(Landroid/content/Context;Landroidx/core/provider/FontRequest;)Landroidx/emoji2/text/EmojiCompat$Config;
+HSPLandroidx/emoji2/text/DefaultEmojiCompatConfig$DefaultEmojiCompatConfigFactory;->convertToByteArray([Landroid/content/pm/Signature;)Ljava/util/List;
+HSPLandroidx/emoji2/text/DefaultEmojiCompatConfig$DefaultEmojiCompatConfigFactory;->create(Landroid/content/Context;)Landroidx/emoji2/text/EmojiCompat$Config;
+HSPLandroidx/emoji2/text/DefaultEmojiCompatConfig$DefaultEmojiCompatConfigFactory;->generateFontRequestFrom(Landroid/content/pm/ProviderInfo;Landroid/content/pm/PackageManager;)Landroidx/core/provider/FontRequest;
+HSPLandroidx/emoji2/text/DefaultEmojiCompatConfig$DefaultEmojiCompatConfigFactory;->getHelperForApi()Landroidx/emoji2/text/DefaultEmojiCompatConfig$DefaultEmojiCompatConfigHelper;
+HSPLandroidx/emoji2/text/DefaultEmojiCompatConfig$DefaultEmojiCompatConfigFactory;->hasFlagSystem(Landroid/content/pm/ProviderInfo;)Z
+HSPLandroidx/emoji2/text/DefaultEmojiCompatConfig$DefaultEmojiCompatConfigFactory;->queryDefaultInstalledContentProvider(Landroid/content/pm/PackageManager;)Landroid/content/pm/ProviderInfo;
+HSPLandroidx/emoji2/text/DefaultEmojiCompatConfig$DefaultEmojiCompatConfigFactory;->queryForDefaultFontRequest(Landroid/content/Context;)Landroidx/core/provider/FontRequest;
+HSPLandroidx/emoji2/text/DefaultEmojiCompatConfig$DefaultEmojiCompatConfigHelper;-><init>()V
+HSPLandroidx/emoji2/text/DefaultEmojiCompatConfig$DefaultEmojiCompatConfigHelper_API19;-><init>()V
+HSPLandroidx/emoji2/text/DefaultEmojiCompatConfig$DefaultEmojiCompatConfigHelper_API19;->getProviderInfo(Landroid/content/pm/ResolveInfo;)Landroid/content/pm/ProviderInfo;
+HSPLandroidx/emoji2/text/DefaultEmojiCompatConfig$DefaultEmojiCompatConfigHelper_API19;->queryIntentContentProviders(Landroid/content/pm/PackageManager;Landroid/content/Intent;I)Ljava/util/List;
+HSPLandroidx/emoji2/text/DefaultEmojiCompatConfig$DefaultEmojiCompatConfigHelper_API28;-><init>()V
+HSPLandroidx/emoji2/text/DefaultEmojiCompatConfig$DefaultEmojiCompatConfigHelper_API28;->getSigningSignatures(Landroid/content/pm/PackageManager;Ljava/lang/String;)[Landroid/content/pm/Signature;
+HSPLandroidx/emoji2/text/DefaultEmojiCompatConfig;->create(Landroid/content/Context;)Landroidx/emoji2/text/FontRequestEmojiCompatConfig;
+HSPLandroidx/emoji2/text/DefaultGlyphChecker;-><clinit>()V
+HSPLandroidx/emoji2/text/DefaultGlyphChecker;-><init>()V
+HSPLandroidx/emoji2/text/EmojiCompat$CompatInternal19$1;-><init>(Landroidx/emoji2/text/EmojiCompat$CompatInternal19;)V
+HSPLandroidx/emoji2/text/EmojiCompat$CompatInternal19$1;->onLoaded(Landroidx/emoji2/text/MetadataRepo;)V
+HSPLandroidx/emoji2/text/EmojiCompat$CompatInternal19;-><init>(Landroidx/emoji2/text/EmojiCompat;)V
+HSPLandroidx/emoji2/text/EmojiCompat$CompatInternal19;->loadMetadata()V
+HSPLandroidx/emoji2/text/EmojiCompat$CompatInternal19;->onMetadataLoadSuccess(Landroidx/emoji2/text/MetadataRepo;)V
+HSPLandroidx/emoji2/text/EmojiCompat$CompatInternal19;->process(Ljava/lang/CharSequence;IIIZ)Ljava/lang/CharSequence;
+HSPLandroidx/emoji2/text/EmojiCompat$CompatInternal;-><init>(Landroidx/emoji2/text/EmojiCompat;)V
+HSPLandroidx/emoji2/text/EmojiCompat$Config;-><init>(Landroidx/emoji2/text/EmojiCompat$MetadataRepoLoader;)V
+HSPLandroidx/emoji2/text/EmojiCompat$Config;->getMetadataRepoLoader()Landroidx/emoji2/text/EmojiCompat$MetadataRepoLoader;
+HSPLandroidx/emoji2/text/EmojiCompat$Config;->setMetadataLoadStrategy(I)Landroidx/emoji2/text/EmojiCompat$Config;
+HSPLandroidx/emoji2/text/EmojiCompat$InitCallback;-><init>()V
+HSPLandroidx/emoji2/text/EmojiCompat$ListenerDispatcher;-><init>(Ljava/util/Collection;I)V
+HSPLandroidx/emoji2/text/EmojiCompat$ListenerDispatcher;-><init>(Ljava/util/Collection;ILjava/lang/Throwable;)V
+HSPLandroidx/emoji2/text/EmojiCompat$ListenerDispatcher;->run()V
+HSPLandroidx/emoji2/text/EmojiCompat$MetadataRepoLoaderCallback;-><init>()V
+HSPLandroidx/emoji2/text/EmojiCompat$SpanFactory;-><init>()V
+HSPLandroidx/emoji2/text/EmojiCompat;-><clinit>()V
+HSPLandroidx/emoji2/text/EmojiCompat;-><init>(Landroidx/emoji2/text/EmojiCompat$Config;)V
+HSPLandroidx/emoji2/text/EmojiCompat;->access$000(Landroidx/emoji2/text/EmojiCompat;)Landroidx/emoji2/text/EmojiCompat$GlyphChecker;
+HSPLandroidx/emoji2/text/EmojiCompat;->get()Landroidx/emoji2/text/EmojiCompat;
+HSPLandroidx/emoji2/text/EmojiCompat;->getLoadState()I
+HSPLandroidx/emoji2/text/EmojiCompat;->init(Landroidx/emoji2/text/EmojiCompat$Config;)Landroidx/emoji2/text/EmojiCompat;
+HSPLandroidx/emoji2/text/EmojiCompat;->isConfigured()Z
+HSPLandroidx/emoji2/text/EmojiCompat;->isInitialized()Z
+HSPLandroidx/emoji2/text/EmojiCompat;->load()V
+HSPLandroidx/emoji2/text/EmojiCompat;->loadMetadata()V
+HSPLandroidx/emoji2/text/EmojiCompat;->onMetadataLoadSuccess()V
+HSPLandroidx/emoji2/text/EmojiCompat;->process(Ljava/lang/CharSequence;)Ljava/lang/CharSequence;
+HSPLandroidx/emoji2/text/EmojiCompat;->process(Ljava/lang/CharSequence;II)Ljava/lang/CharSequence;
+HSPLandroidx/emoji2/text/EmojiCompat;->process(Ljava/lang/CharSequence;III)Ljava/lang/CharSequence;
+HSPLandroidx/emoji2/text/EmojiCompat;->process(Ljava/lang/CharSequence;IIII)Ljava/lang/CharSequence;
+HSPLandroidx/emoji2/text/EmojiCompat;->registerInitCallback(Landroidx/emoji2/text/EmojiCompat$InitCallback;)V
+HSPLandroidx/emoji2/text/EmojiCompatInitializer$1;-><init>(Landroidx/emoji2/text/EmojiCompatInitializer;Landroidx/lifecycle/Lifecycle;)V
+HSPLandroidx/emoji2/text/EmojiCompatInitializer$1;->onResume(Landroidx/lifecycle/LifecycleOwner;)V
+HSPLandroidx/emoji2/text/EmojiCompatInitializer$BackgroundDefaultConfig;-><init>(Landroid/content/Context;)V
+HSPLandroidx/emoji2/text/EmojiCompatInitializer$BackgroundDefaultLoader$$ExternalSyntheticLambda0;-><init>(Landroidx/emoji2/text/EmojiCompatInitializer$BackgroundDefaultLoader;Landroidx/emoji2/text/EmojiCompat$MetadataRepoLoaderCallback;Ljava/util/concurrent/ThreadPoolExecutor;)V
+HSPLandroidx/emoji2/text/EmojiCompatInitializer$BackgroundDefaultLoader$$ExternalSyntheticLambda0;->run()V
+HSPLandroidx/emoji2/text/EmojiCompatInitializer$BackgroundDefaultLoader$1;-><init>(Landroidx/emoji2/text/EmojiCompatInitializer$BackgroundDefaultLoader;Landroidx/emoji2/text/EmojiCompat$MetadataRepoLoaderCallback;Ljava/util/concurrent/ThreadPoolExecutor;)V
+HSPLandroidx/emoji2/text/EmojiCompatInitializer$BackgroundDefaultLoader$1;->onLoaded(Landroidx/emoji2/text/MetadataRepo;)V
+HSPLandroidx/emoji2/text/EmojiCompatInitializer$BackgroundDefaultLoader;->$r8$lambda$2V1iWTiAwNxOBlVvz73bbuEdzIw(Landroidx/emoji2/text/EmojiCompatInitializer$BackgroundDefaultLoader;Landroidx/emoji2/text/EmojiCompat$MetadataRepoLoaderCallback;Ljava/util/concurrent/ThreadPoolExecutor;)V
+HSPLandroidx/emoji2/text/EmojiCompatInitializer$BackgroundDefaultLoader;-><init>(Landroid/content/Context;)V
+HSPLandroidx/emoji2/text/EmojiCompatInitializer$BackgroundDefaultLoader;->doLoad(Landroidx/emoji2/text/EmojiCompat$MetadataRepoLoaderCallback;Ljava/util/concurrent/ThreadPoolExecutor;)V
+HSPLandroidx/emoji2/text/EmojiCompatInitializer$BackgroundDefaultLoader;->lambda$load$0(Landroidx/emoji2/text/EmojiCompat$MetadataRepoLoaderCallback;Ljava/util/concurrent/ThreadPoolExecutor;)V
+HSPLandroidx/emoji2/text/EmojiCompatInitializer$BackgroundDefaultLoader;->load(Landroidx/emoji2/text/EmojiCompat$MetadataRepoLoaderCallback;)V
+HSPLandroidx/emoji2/text/EmojiCompatInitializer$LoadEmojiCompatRunnable;-><init>()V
+HSPLandroidx/emoji2/text/EmojiCompatInitializer$LoadEmojiCompatRunnable;->run()V
+HSPLandroidx/emoji2/text/EmojiCompatInitializer;-><init>()V
+HSPLandroidx/emoji2/text/EmojiCompatInitializer;->create(Landroid/content/Context;)Ljava/lang/Boolean;
+HSPLandroidx/emoji2/text/EmojiCompatInitializer;->create(Landroid/content/Context;)Ljava/lang/Object;
+HSPLandroidx/emoji2/text/EmojiCompatInitializer;->delayUntilFirstResume(Landroid/content/Context;)V
+HSPLandroidx/emoji2/text/EmojiCompatInitializer;->dependencies()Ljava/util/List;
+HSPLandroidx/emoji2/text/EmojiCompatInitializer;->loadEmojiCompatAfterDelay()V
+HSPLandroidx/emoji2/text/EmojiMetadata;-><clinit>()V
+HSPLandroidx/emoji2/text/EmojiMetadata;-><init>(Landroidx/emoji2/text/MetadataRepo;I)V
+HSPLandroidx/emoji2/text/EmojiMetadata;->getCodepointAt(I)I
+HSPLandroidx/emoji2/text/EmojiMetadata;->getCodepointsLength()I
+HSPLandroidx/emoji2/text/EmojiMetadata;->getId()I
+HSPLandroidx/emoji2/text/EmojiMetadata;->getMetadataItem()Landroidx/emoji2/text/flatbuffer/MetadataItem;+]Landroidx/emoji2/text/flatbuffer/MetadataList;Landroidx/emoji2/text/flatbuffer/MetadataList;]Landroidx/emoji2/text/MetadataRepo;Landroidx/emoji2/text/MetadataRepo;
+HSPLandroidx/emoji2/text/EmojiProcessor$ProcessorSm;-><init>(Landroidx/emoji2/text/MetadataRepo$Node;Z[I)V
+HSPLandroidx/emoji2/text/EmojiProcessor$ProcessorSm;->check(I)I
+HSPLandroidx/emoji2/text/EmojiProcessor$ProcessorSm;->isInFlushableState()Z
+HSPLandroidx/emoji2/text/EmojiProcessor$ProcessorSm;->reset()I
+HSPLandroidx/emoji2/text/EmojiProcessor;-><init>(Landroidx/emoji2/text/MetadataRepo;Landroidx/emoji2/text/EmojiCompat$SpanFactory;Landroidx/emoji2/text/EmojiCompat$GlyphChecker;Z[I)V
+HSPLandroidx/emoji2/text/EmojiProcessor;->process(Ljava/lang/CharSequence;IIIZ)Ljava/lang/CharSequence;
+HSPLandroidx/emoji2/text/FontRequestEmojiCompatConfig$FontProviderHelper;-><init>()V
+HSPLandroidx/emoji2/text/FontRequestEmojiCompatConfig$FontProviderHelper;->buildTypeface(Landroid/content/Context;Landroidx/core/provider/FontsContractCompat$FontInfo;)Landroid/graphics/Typeface;
+HSPLandroidx/emoji2/text/FontRequestEmojiCompatConfig$FontProviderHelper;->fetchFonts(Landroid/content/Context;Landroidx/core/provider/FontRequest;)Landroidx/core/provider/FontsContractCompat$FontFamilyResult;
+HSPLandroidx/emoji2/text/FontRequestEmojiCompatConfig$FontRequestMetadataLoader$$ExternalSyntheticLambda0;-><init>(Landroidx/emoji2/text/FontRequestEmojiCompatConfig$FontRequestMetadataLoader;)V
+HSPLandroidx/emoji2/text/FontRequestEmojiCompatConfig$FontRequestMetadataLoader$$ExternalSyntheticLambda0;->run()V
+HSPLandroidx/emoji2/text/FontRequestEmojiCompatConfig$FontRequestMetadataLoader;-><init>(Landroid/content/Context;Landroidx/core/provider/FontRequest;Landroidx/emoji2/text/FontRequestEmojiCompatConfig$FontProviderHelper;)V
+HSPLandroidx/emoji2/text/FontRequestEmojiCompatConfig$FontRequestMetadataLoader;->cleanUp()V
+HSPLandroidx/emoji2/text/FontRequestEmojiCompatConfig$FontRequestMetadataLoader;->createMetadata()V
+HSPLandroidx/emoji2/text/FontRequestEmojiCompatConfig$FontRequestMetadataLoader;->load(Landroidx/emoji2/text/EmojiCompat$MetadataRepoLoaderCallback;)V
+HSPLandroidx/emoji2/text/FontRequestEmojiCompatConfig$FontRequestMetadataLoader;->loadInternal()V
+HSPLandroidx/emoji2/text/FontRequestEmojiCompatConfig$FontRequestMetadataLoader;->retrieveFontInfo()Landroidx/core/provider/FontsContractCompat$FontInfo;
+HSPLandroidx/emoji2/text/FontRequestEmojiCompatConfig$FontRequestMetadataLoader;->setExecutor(Ljava/util/concurrent/Executor;)V
+HSPLandroidx/emoji2/text/FontRequestEmojiCompatConfig;-><clinit>()V
+HSPLandroidx/emoji2/text/FontRequestEmojiCompatConfig;-><init>(Landroid/content/Context;Landroidx/core/provider/FontRequest;)V
+HSPLandroidx/emoji2/text/FontRequestEmojiCompatConfig;->setLoadingExecutor(Ljava/util/concurrent/Executor;)Landroidx/emoji2/text/FontRequestEmojiCompatConfig;
+HSPLandroidx/emoji2/text/MetadataListReader$ByteBufferReader;-><init>(Ljava/nio/ByteBuffer;)V
+HSPLandroidx/emoji2/text/MetadataListReader$ByteBufferReader;->getPosition()J
+HSPLandroidx/emoji2/text/MetadataListReader$ByteBufferReader;->readTag()I
+HSPLandroidx/emoji2/text/MetadataListReader$ByteBufferReader;->readUnsignedInt()J
+HSPLandroidx/emoji2/text/MetadataListReader$ByteBufferReader;->readUnsignedShort()I
+HSPLandroidx/emoji2/text/MetadataListReader$ByteBufferReader;->skip(I)V
+HSPLandroidx/emoji2/text/MetadataListReader$OffsetInfo;-><init>(JJ)V
+HSPLandroidx/emoji2/text/MetadataListReader$OffsetInfo;->getStartOffset()J
+HSPLandroidx/emoji2/text/MetadataListReader;->findOffsetInfo(Landroidx/emoji2/text/MetadataListReader$OpenTypeReader;)Landroidx/emoji2/text/MetadataListReader$OffsetInfo;
+HSPLandroidx/emoji2/text/MetadataListReader;->read(Ljava/nio/ByteBuffer;)Landroidx/emoji2/text/flatbuffer/MetadataList;
+HSPLandroidx/emoji2/text/MetadataListReader;->toUnsignedInt(I)J
+HSPLandroidx/emoji2/text/MetadataListReader;->toUnsignedShort(S)I
+HSPLandroidx/emoji2/text/MetadataRepo$Node;-><init>()V
+HSPLandroidx/emoji2/text/MetadataRepo$Node;-><init>(I)V
+HSPLandroidx/emoji2/text/MetadataRepo$Node;->get(I)Landroidx/emoji2/text/MetadataRepo$Node;
+HSPLandroidx/emoji2/text/MetadataRepo$Node;->put(Landroidx/emoji2/text/EmojiMetadata;II)V
+HSPLandroidx/emoji2/text/MetadataRepo;-><init>(Landroid/graphics/Typeface;Landroidx/emoji2/text/flatbuffer/MetadataList;)V
+HSPLandroidx/emoji2/text/MetadataRepo;->constructIndex(Landroidx/emoji2/text/flatbuffer/MetadataList;)V
+HSPLandroidx/emoji2/text/MetadataRepo;->create(Landroid/graphics/Typeface;Ljava/nio/ByteBuffer;)Landroidx/emoji2/text/MetadataRepo;
+HSPLandroidx/emoji2/text/MetadataRepo;->getMetadataList()Landroidx/emoji2/text/flatbuffer/MetadataList;
+HSPLandroidx/emoji2/text/MetadataRepo;->getRootNode()Landroidx/emoji2/text/MetadataRepo$Node;
+HSPLandroidx/emoji2/text/MetadataRepo;->put(Landroidx/emoji2/text/EmojiMetadata;)V
+HSPLandroidx/emoji2/text/flatbuffer/MetadataItem;-><init>()V
+HSPLandroidx/emoji2/text/flatbuffer/MetadataItem;->__assign(ILjava/nio/ByteBuffer;)Landroidx/emoji2/text/flatbuffer/MetadataItem;
+HSPLandroidx/emoji2/text/flatbuffer/MetadataItem;->__init(ILjava/nio/ByteBuffer;)V
+HSPLandroidx/emoji2/text/flatbuffer/MetadataItem;->codepoints(I)I
+HSPLandroidx/emoji2/text/flatbuffer/MetadataItem;->codepointsLength()I
+HSPLandroidx/emoji2/text/flatbuffer/MetadataItem;->id()I
+HSPLandroidx/emoji2/text/flatbuffer/MetadataList;-><init>()V
+HSPLandroidx/emoji2/text/flatbuffer/MetadataList;->__assign(ILjava/nio/ByteBuffer;)Landroidx/emoji2/text/flatbuffer/MetadataList;
+HSPLandroidx/emoji2/text/flatbuffer/MetadataList;->__init(ILjava/nio/ByteBuffer;)V
+HSPLandroidx/emoji2/text/flatbuffer/MetadataList;->getRootAsMetadataList(Ljava/nio/ByteBuffer;)Landroidx/emoji2/text/flatbuffer/MetadataList;
+HSPLandroidx/emoji2/text/flatbuffer/MetadataList;->getRootAsMetadataList(Ljava/nio/ByteBuffer;Landroidx/emoji2/text/flatbuffer/MetadataList;)Landroidx/emoji2/text/flatbuffer/MetadataList;
+HSPLandroidx/emoji2/text/flatbuffer/MetadataList;->list(Landroidx/emoji2/text/flatbuffer/MetadataItem;I)Landroidx/emoji2/text/flatbuffer/MetadataItem;+]Landroidx/emoji2/text/flatbuffer/MetadataItem;Landroidx/emoji2/text/flatbuffer/MetadataItem;]Landroidx/emoji2/text/flatbuffer/Table;Landroidx/emoji2/text/flatbuffer/MetadataList;
+HSPLandroidx/emoji2/text/flatbuffer/MetadataList;->listLength()I
+HSPLandroidx/emoji2/text/flatbuffer/Table;-><init>()V
+HSPLandroidx/emoji2/text/flatbuffer/Table;->__indirect(I)I
+HSPLandroidx/emoji2/text/flatbuffer/Table;->__offset(I)I
+HSPLandroidx/emoji2/text/flatbuffer/Table;->__reset(ILjava/nio/ByteBuffer;)V
+HSPLandroidx/emoji2/text/flatbuffer/Table;->__vector(I)I
+HSPLandroidx/emoji2/text/flatbuffer/Table;->__vector_len(I)I
+HSPLandroidx/emoji2/text/flatbuffer/Utf8;-><init>()V
+HSPLandroidx/emoji2/text/flatbuffer/Utf8;->getDefault()Landroidx/emoji2/text/flatbuffer/Utf8;
+HSPLandroidx/emoji2/text/flatbuffer/Utf8Safe;-><init>()V
+HSPLandroidx/lifecycle/DefaultLifecycleObserver;->onCreate(Landroidx/lifecycle/LifecycleOwner;)V
+HSPLandroidx/lifecycle/DefaultLifecycleObserver;->onStart(Landroidx/lifecycle/LifecycleOwner;)V
+HSPLandroidx/lifecycle/EmptyActivityLifecycleCallbacks;-><init>()V
+HSPLandroidx/lifecycle/EmptyActivityLifecycleCallbacks;->onActivityCreated(Landroid/app/Activity;Landroid/os/Bundle;)V
+HSPLandroidx/lifecycle/EmptyActivityLifecycleCallbacks;->onActivityResumed(Landroid/app/Activity;)V
+HSPLandroidx/lifecycle/EmptyActivityLifecycleCallbacks;->onActivityStarted(Landroid/app/Activity;)V
+HSPLandroidx/lifecycle/FullLifecycleObserverAdapter$1;-><clinit>()V
+HSPLandroidx/lifecycle/FullLifecycleObserverAdapter;-><init>(Landroidx/lifecycle/FullLifecycleObserver;Landroidx/lifecycle/LifecycleEventObserver;)V
+HSPLandroidx/lifecycle/FullLifecycleObserverAdapter;->onStateChanged(Landroidx/lifecycle/LifecycleOwner;Landroidx/lifecycle/Lifecycle$Event;)V
+HSPLandroidx/lifecycle/LegacySavedStateHandleController;->attachHandleIfNeeded(Landroidx/lifecycle/ViewModel;Landroidx/savedstate/SavedStateRegistry;Landroidx/lifecycle/Lifecycle;)V
+HSPLandroidx/lifecycle/Lifecycle$1;-><clinit>()V
+HSPLandroidx/lifecycle/Lifecycle$Event;->$values()[Landroidx/lifecycle/Lifecycle$Event;
+HSPLandroidx/lifecycle/Lifecycle$Event;-><clinit>()V
+HSPLandroidx/lifecycle/Lifecycle$Event;-><init>(Ljava/lang/String;I)V
+HSPLandroidx/lifecycle/Lifecycle$Event;->getTargetState()Landroidx/lifecycle/Lifecycle$State;
+HSPLandroidx/lifecycle/Lifecycle$Event;->upFrom(Landroidx/lifecycle/Lifecycle$State;)Landroidx/lifecycle/Lifecycle$Event;
+HSPLandroidx/lifecycle/Lifecycle$Event;->values()[Landroidx/lifecycle/Lifecycle$Event;
+HSPLandroidx/lifecycle/Lifecycle$State;->$values()[Landroidx/lifecycle/Lifecycle$State;
+HSPLandroidx/lifecycle/Lifecycle$State;-><clinit>()V
+HSPLandroidx/lifecycle/Lifecycle$State;-><init>(Ljava/lang/String;I)V
+HSPLandroidx/lifecycle/Lifecycle$State;->isAtLeast(Landroidx/lifecycle/Lifecycle$State;)Z
+HSPLandroidx/lifecycle/Lifecycle$State;->values()[Landroidx/lifecycle/Lifecycle$State;
+HSPLandroidx/lifecycle/Lifecycle;-><init>()V
+HSPLandroidx/lifecycle/LifecycleDispatcher$DispatcherActivityCallback;-><init>()V
+HSPLandroidx/lifecycle/LifecycleDispatcher$DispatcherActivityCallback;->onActivityCreated(Landroid/app/Activity;Landroid/os/Bundle;)V
+HSPLandroidx/lifecycle/LifecycleDispatcher;-><clinit>()V
+HSPLandroidx/lifecycle/LifecycleDispatcher;->init(Landroid/content/Context;)V
+HSPLandroidx/lifecycle/LifecycleRegistry$ObserverWithState;-><init>(Landroidx/lifecycle/LifecycleObserver;Landroidx/lifecycle/Lifecycle$State;)V
+HSPLandroidx/lifecycle/LifecycleRegistry$ObserverWithState;->dispatchEvent(Landroidx/lifecycle/LifecycleOwner;Landroidx/lifecycle/Lifecycle$Event;)V
+HSPLandroidx/lifecycle/LifecycleRegistry;-><init>(Landroidx/lifecycle/LifecycleOwner;)V
+HSPLandroidx/lifecycle/LifecycleRegistry;-><init>(Landroidx/lifecycle/LifecycleOwner;Z)V
+HSPLandroidx/lifecycle/LifecycleRegistry;->addObserver(Landroidx/lifecycle/LifecycleObserver;)V
+HSPLandroidx/lifecycle/LifecycleRegistry;->calculateTargetState(Landroidx/lifecycle/LifecycleObserver;)Landroidx/lifecycle/Lifecycle$State;
+HSPLandroidx/lifecycle/LifecycleRegistry;->enforceMainThreadIfNeeded(Ljava/lang/String;)V
+HSPLandroidx/lifecycle/LifecycleRegistry;->forwardPass(Landroidx/lifecycle/LifecycleOwner;)V
+HSPLandroidx/lifecycle/LifecycleRegistry;->getCurrentState()Landroidx/lifecycle/Lifecycle$State;
+HSPLandroidx/lifecycle/LifecycleRegistry;->handleLifecycleEvent(Landroidx/lifecycle/Lifecycle$Event;)V
+HSPLandroidx/lifecycle/LifecycleRegistry;->isSynced()Z
+HSPLandroidx/lifecycle/LifecycleRegistry;->min(Landroidx/lifecycle/Lifecycle$State;Landroidx/lifecycle/Lifecycle$State;)Landroidx/lifecycle/Lifecycle$State;
+HSPLandroidx/lifecycle/LifecycleRegistry;->moveToState(Landroidx/lifecycle/Lifecycle$State;)V
+HSPLandroidx/lifecycle/LifecycleRegistry;->popParentState()V
+HSPLandroidx/lifecycle/LifecycleRegistry;->pushParentState(Landroidx/lifecycle/Lifecycle$State;)V
+HSPLandroidx/lifecycle/LifecycleRegistry;->removeObserver(Landroidx/lifecycle/LifecycleObserver;)V
+HSPLandroidx/lifecycle/LifecycleRegistry;->sync()V
+HSPLandroidx/lifecycle/Lifecycling;-><clinit>()V
+HSPLandroidx/lifecycle/Lifecycling;->lifecycleEventObserver(Ljava/lang/Object;)Landroidx/lifecycle/LifecycleEventObserver;
+HSPLandroidx/lifecycle/LiveData$1;-><init>(Landroidx/lifecycle/LiveData;)V
+HSPLandroidx/lifecycle/LiveData$LifecycleBoundObserver;-><init>(Landroidx/lifecycle/LiveData;Landroidx/lifecycle/LifecycleOwner;Landroidx/lifecycle/Observer;)V
+HSPLandroidx/lifecycle/LiveData$LifecycleBoundObserver;->isAttachedTo(Landroidx/lifecycle/LifecycleOwner;)Z
+HSPLandroidx/lifecycle/LiveData$LifecycleBoundObserver;->onStateChanged(Landroidx/lifecycle/LifecycleOwner;Landroidx/lifecycle/Lifecycle$Event;)V
+HSPLandroidx/lifecycle/LiveData$LifecycleBoundObserver;->shouldBeActive()Z
+HSPLandroidx/lifecycle/LiveData$ObserverWrapper;-><init>(Landroidx/lifecycle/LiveData;Landroidx/lifecycle/Observer;)V
+HSPLandroidx/lifecycle/LiveData$ObserverWrapper;->activeStateChanged(Z)V
+HSPLandroidx/lifecycle/LiveData;-><clinit>()V
+HSPLandroidx/lifecycle/LiveData;-><init>()V
+HSPLandroidx/lifecycle/LiveData;->assertMainThread(Ljava/lang/String;)V
+HSPLandroidx/lifecycle/LiveData;->changeActiveCounter(I)V
+HSPLandroidx/lifecycle/LiveData;->considerNotify(Landroidx/lifecycle/LiveData$ObserverWrapper;)V
+HSPLandroidx/lifecycle/LiveData;->dispatchingValue(Landroidx/lifecycle/LiveData$ObserverWrapper;)V
+HSPLandroidx/lifecycle/LiveData;->observe(Landroidx/lifecycle/LifecycleOwner;Landroidx/lifecycle/Observer;)V
+HSPLandroidx/lifecycle/LiveData;->onActive()V
+HSPLandroidx/lifecycle/MutableLiveData;-><init>()V
+HSPLandroidx/lifecycle/ProcessLifecycleInitializer;-><init>()V
+HSPLandroidx/lifecycle/ProcessLifecycleInitializer;->create(Landroid/content/Context;)Landroidx/lifecycle/LifecycleOwner;
+HSPLandroidx/lifecycle/ProcessLifecycleInitializer;->create(Landroid/content/Context;)Ljava/lang/Object;
+HSPLandroidx/lifecycle/ProcessLifecycleInitializer;->dependencies()Ljava/util/List;
+HSPLandroidx/lifecycle/ProcessLifecycleOwner$1;-><init>(Landroidx/lifecycle/ProcessLifecycleOwner;)V
+HSPLandroidx/lifecycle/ProcessLifecycleOwner$2;-><init>(Landroidx/lifecycle/ProcessLifecycleOwner;)V
+HSPLandroidx/lifecycle/ProcessLifecycleOwner$3$1;-><init>(Landroidx/lifecycle/ProcessLifecycleOwner$3;)V
+HSPLandroidx/lifecycle/ProcessLifecycleOwner$3$1;->onActivityPostResumed(Landroid/app/Activity;)V
+HSPLandroidx/lifecycle/ProcessLifecycleOwner$3$1;->onActivityPostStarted(Landroid/app/Activity;)V
+HSPLandroidx/lifecycle/ProcessLifecycleOwner$3;-><init>(Landroidx/lifecycle/ProcessLifecycleOwner;)V
+HSPLandroidx/lifecycle/ProcessLifecycleOwner$3;->onActivityCreated(Landroid/app/Activity;Landroid/os/Bundle;)V
+HSPLandroidx/lifecycle/ProcessLifecycleOwner$3;->onActivityPreCreated(Landroid/app/Activity;Landroid/os/Bundle;)V
+HSPLandroidx/lifecycle/ProcessLifecycleOwner$Api29Impl;->registerActivityLifecycleCallbacks(Landroid/app/Activity;Landroid/app/Application$ActivityLifecycleCallbacks;)V
+HSPLandroidx/lifecycle/ProcessLifecycleOwner;-><clinit>()V
+HSPLandroidx/lifecycle/ProcessLifecycleOwner;-><init>()V
+HSPLandroidx/lifecycle/ProcessLifecycleOwner;->activityResumed()V
+HSPLandroidx/lifecycle/ProcessLifecycleOwner;->activityStarted()V
+HSPLandroidx/lifecycle/ProcessLifecycleOwner;->attach(Landroid/content/Context;)V
+HSPLandroidx/lifecycle/ProcessLifecycleOwner;->get()Landroidx/lifecycle/LifecycleOwner;
+HSPLandroidx/lifecycle/ProcessLifecycleOwner;->getLifecycle()Landroidx/lifecycle/Lifecycle;
+HSPLandroidx/lifecycle/ProcessLifecycleOwner;->init(Landroid/content/Context;)V
+HSPLandroidx/lifecycle/ReportFragment$LifecycleCallbacks;-><init>()V
+HSPLandroidx/lifecycle/ReportFragment$LifecycleCallbacks;->onActivityCreated(Landroid/app/Activity;Landroid/os/Bundle;)V
+HSPLandroidx/lifecycle/ReportFragment$LifecycleCallbacks;->onActivityPostCreated(Landroid/app/Activity;Landroid/os/Bundle;)V
+HSPLandroidx/lifecycle/ReportFragment$LifecycleCallbacks;->onActivityPostResumed(Landroid/app/Activity;)V
+HSPLandroidx/lifecycle/ReportFragment$LifecycleCallbacks;->onActivityPostStarted(Landroid/app/Activity;)V
+HSPLandroidx/lifecycle/ReportFragment$LifecycleCallbacks;->onActivityResumed(Landroid/app/Activity;)V
+HSPLandroidx/lifecycle/ReportFragment$LifecycleCallbacks;->onActivityStarted(Landroid/app/Activity;)V
+HSPLandroidx/lifecycle/ReportFragment$LifecycleCallbacks;->registerIn(Landroid/app/Activity;)V
+HSPLandroidx/lifecycle/ReportFragment;-><init>()V
+HSPLandroidx/lifecycle/ReportFragment;->dispatch(Landroid/app/Activity;Landroidx/lifecycle/Lifecycle$Event;)V
+HSPLandroidx/lifecycle/ReportFragment;->dispatch(Landroidx/lifecycle/Lifecycle$Event;)V
+HSPLandroidx/lifecycle/ReportFragment;->dispatchCreate(Landroidx/lifecycle/ReportFragment$ActivityInitializationListener;)V
+HSPLandroidx/lifecycle/ReportFragment;->dispatchResume(Landroidx/lifecycle/ReportFragment$ActivityInitializationListener;)V
+HSPLandroidx/lifecycle/ReportFragment;->dispatchStart(Landroidx/lifecycle/ReportFragment$ActivityInitializationListener;)V
+HSPLandroidx/lifecycle/ReportFragment;->injectIfNeededIn(Landroid/app/Activity;)V
+HSPLandroidx/lifecycle/ReportFragment;->onActivityCreated(Landroid/os/Bundle;)V
+HSPLandroidx/lifecycle/ReportFragment;->onResume()V
+HSPLandroidx/lifecycle/ReportFragment;->onStart()V
+HSPLandroidx/lifecycle/SavedStateHandleAttacher;-><init>(Landroidx/lifecycle/SavedStateHandlesProvider;)V
+HSPLandroidx/lifecycle/SavedStateHandleAttacher;->onStateChanged(Landroidx/lifecycle/LifecycleOwner;Landroidx/lifecycle/Lifecycle$Event;)V
+HSPLandroidx/lifecycle/SavedStateHandleSupport$DEFAULT_ARGS_KEY$1;-><init>()V
+HSPLandroidx/lifecycle/SavedStateHandleSupport$SAVED_STATE_REGISTRY_OWNER_KEY$1;-><init>()V
+HSPLandroidx/lifecycle/SavedStateHandleSupport$VIEW_MODEL_STORE_OWNER_KEY$1;-><init>()V
+HSPLandroidx/lifecycle/SavedStateHandleSupport$savedStateHandlesVM$1$1;-><clinit>()V
+HSPLandroidx/lifecycle/SavedStateHandleSupport$savedStateHandlesVM$1$1;-><init>()V
+HSPLandroidx/lifecycle/SavedStateHandleSupport$savedStateHandlesVM$1$1;->invoke(Landroidx/lifecycle/viewmodel/CreationExtras;)Landroidx/lifecycle/SavedStateHandlesVM;
+HSPLandroidx/lifecycle/SavedStateHandleSupport$savedStateHandlesVM$1$1;->invoke(Ljava/lang/Object;)Ljava/lang/Object;
+HSPLandroidx/lifecycle/SavedStateHandleSupport;-><clinit>()V
+HSPLandroidx/lifecycle/SavedStateHandleSupport;->enableSavedStateHandles(Landroidx/savedstate/SavedStateRegistryOwner;)V
+HSPLandroidx/lifecycle/SavedStateHandleSupport;->getSavedStateHandlesVM(Landroidx/lifecycle/ViewModelStoreOwner;)Landroidx/lifecycle/SavedStateHandlesVM;
+HSPLandroidx/lifecycle/SavedStateHandlesProvider$viewModel$2;-><init>(Landroidx/lifecycle/ViewModelStoreOwner;)V
+HSPLandroidx/lifecycle/SavedStateHandlesProvider$viewModel$2;->invoke()Landroidx/lifecycle/SavedStateHandlesVM;
+HSPLandroidx/lifecycle/SavedStateHandlesProvider$viewModel$2;->invoke()Ljava/lang/Object;
+HSPLandroidx/lifecycle/SavedStateHandlesProvider;-><init>(Landroidx/savedstate/SavedStateRegistry;Landroidx/lifecycle/ViewModelStoreOwner;)V
+HSPLandroidx/lifecycle/SavedStateHandlesProvider;->getViewModel()Landroidx/lifecycle/SavedStateHandlesVM;
+HSPLandroidx/lifecycle/SavedStateHandlesProvider;->performRestore()V
+HSPLandroidx/lifecycle/SavedStateHandlesVM;-><init>()V
+HSPLandroidx/lifecycle/SavedStateViewModelFactory;-><init>(Landroid/app/Application;Landroidx/savedstate/SavedStateRegistryOwner;Landroid/os/Bundle;)V
+HSPLandroidx/lifecycle/SavedStateViewModelFactory;->create(Ljava/lang/Class;Landroidx/lifecycle/viewmodel/CreationExtras;)Landroidx/lifecycle/ViewModel;
+HSPLandroidx/lifecycle/SavedStateViewModelFactory;->onRequery(Landroidx/lifecycle/ViewModel;)V
+HSPLandroidx/lifecycle/SavedStateViewModelFactoryKt;-><clinit>()V
+HSPLandroidx/lifecycle/SavedStateViewModelFactoryKt;->access$getVIEWMODEL_SIGNATURE$p()Ljava/util/List;
+HSPLandroidx/lifecycle/SavedStateViewModelFactoryKt;->findMatchingConstructor(Ljava/lang/Class;Ljava/util/List;)Ljava/lang/reflect/Constructor;
+HSPLandroidx/lifecycle/ViewModel;-><init>()V
+HSPLandroidx/lifecycle/ViewModel;->getTag(Ljava/lang/String;)Ljava/lang/Object;
+HSPLandroidx/lifecycle/ViewModelProvider$AndroidViewModelFactory$Companion$ApplicationKeyImpl;-><clinit>()V
+HSPLandroidx/lifecycle/ViewModelProvider$AndroidViewModelFactory$Companion$ApplicationKeyImpl;-><init>()V
+HSPLandroidx/lifecycle/ViewModelProvider$AndroidViewModelFactory$Companion;-><init>()V
+HSPLandroidx/lifecycle/ViewModelProvider$AndroidViewModelFactory$Companion;-><init>(Lkotlin/jvm/internal/DefaultConstructorMarker;)V
+HSPLandroidx/lifecycle/ViewModelProvider$AndroidViewModelFactory$Companion;->getInstance(Landroid/app/Application;)Landroidx/lifecycle/ViewModelProvider$AndroidViewModelFactory;
+HSPLandroidx/lifecycle/ViewModelProvider$AndroidViewModelFactory;-><clinit>()V
+HSPLandroidx/lifecycle/ViewModelProvider$AndroidViewModelFactory;-><init>(Landroid/app/Application;)V
+HSPLandroidx/lifecycle/ViewModelProvider$AndroidViewModelFactory;-><init>(Landroid/app/Application;I)V
+HSPLandroidx/lifecycle/ViewModelProvider$AndroidViewModelFactory;->access$getSInstance$cp()Landroidx/lifecycle/ViewModelProvider$AndroidViewModelFactory;
+HSPLandroidx/lifecycle/ViewModelProvider$AndroidViewModelFactory;->access$setSInstance$cp(Landroidx/lifecycle/ViewModelProvider$AndroidViewModelFactory;)V
+HSPLandroidx/lifecycle/ViewModelProvider$AndroidViewModelFactory;->create(Ljava/lang/Class;)Landroidx/lifecycle/ViewModel;
+HSPLandroidx/lifecycle/ViewModelProvider$AndroidViewModelFactory;->create(Ljava/lang/Class;Landroid/app/Application;)Landroidx/lifecycle/ViewModel;
+HSPLandroidx/lifecycle/ViewModelProvider$AndroidViewModelFactory;->create(Ljava/lang/Class;Landroidx/lifecycle/viewmodel/CreationExtras;)Landroidx/lifecycle/ViewModel;
+HSPLandroidx/lifecycle/ViewModelProvider$Factory$Companion;-><clinit>()V
+HSPLandroidx/lifecycle/ViewModelProvider$Factory$Companion;-><init>()V
+HSPLandroidx/lifecycle/ViewModelProvider$Factory;-><clinit>()V
+HSPLandroidx/lifecycle/ViewModelProvider$NewInstanceFactory$Companion$ViewModelKeyImpl;-><clinit>()V
+HSPLandroidx/lifecycle/ViewModelProvider$NewInstanceFactory$Companion$ViewModelKeyImpl;-><init>()V
+HSPLandroidx/lifecycle/ViewModelProvider$NewInstanceFactory$Companion;-><init>()V
+HSPLandroidx/lifecycle/ViewModelProvider$NewInstanceFactory$Companion;-><init>(Lkotlin/jvm/internal/DefaultConstructorMarker;)V
+HSPLandroidx/lifecycle/ViewModelProvider$NewInstanceFactory;-><clinit>()V
+HSPLandroidx/lifecycle/ViewModelProvider$NewInstanceFactory;-><init>()V
+HSPLandroidx/lifecycle/ViewModelProvider$NewInstanceFactory;->create(Ljava/lang/Class;)Landroidx/lifecycle/ViewModel;
+HSPLandroidx/lifecycle/ViewModelProvider$OnRequeryFactory;-><init>()V
+HSPLandroidx/lifecycle/ViewModelProvider;-><init>(Landroidx/lifecycle/ViewModelStore;Landroidx/lifecycle/ViewModelProvider$Factory;Landroidx/lifecycle/viewmodel/CreationExtras;)V
+HSPLandroidx/lifecycle/ViewModelProvider;-><init>(Landroidx/lifecycle/ViewModelStoreOwner;Landroidx/lifecycle/ViewModelProvider$Factory;)V
+HSPLandroidx/lifecycle/ViewModelProvider;->get(Ljava/lang/Class;)Landroidx/lifecycle/ViewModel;
+HSPLandroidx/lifecycle/ViewModelProvider;->get(Ljava/lang/String;Ljava/lang/Class;)Landroidx/lifecycle/ViewModel;
+HSPLandroidx/lifecycle/ViewModelProviderGetKt;->defaultCreationExtras(Landroidx/lifecycle/ViewModelStoreOwner;)Landroidx/lifecycle/viewmodel/CreationExtras;
+HSPLandroidx/lifecycle/ViewModelStore;-><init>()V
+HSPLandroidx/lifecycle/ViewModelStore;->get(Ljava/lang/String;)Landroidx/lifecycle/ViewModel;
+HSPLandroidx/lifecycle/ViewModelStore;->put(Ljava/lang/String;Landroidx/lifecycle/ViewModel;)V
+HSPLandroidx/lifecycle/ViewTreeLifecycleOwner;->get(Landroid/view/View;)Landroidx/lifecycle/LifecycleOwner;
+HSPLandroidx/lifecycle/ViewTreeLifecycleOwner;->set(Landroid/view/View;Landroidx/lifecycle/LifecycleOwner;)V
+HSPLandroidx/lifecycle/ViewTreeViewModelStoreOwner;->get(Landroid/view/View;)Landroidx/lifecycle/ViewModelStoreOwner;
+HSPLandroidx/lifecycle/ViewTreeViewModelStoreOwner;->set(Landroid/view/View;Landroidx/lifecycle/ViewModelStoreOwner;)V
+HSPLandroidx/lifecycle/viewmodel/CreationExtras$Empty;-><clinit>()V
+HSPLandroidx/lifecycle/viewmodel/CreationExtras$Empty;-><init>()V
+HSPLandroidx/lifecycle/viewmodel/CreationExtras;-><init>()V
+HSPLandroidx/lifecycle/viewmodel/CreationExtras;->getMap$lifecycle_viewmodel_release()Ljava/util/Map;
+HSPLandroidx/lifecycle/viewmodel/InitializerViewModelFactory;-><init>([Landroidx/lifecycle/viewmodel/ViewModelInitializer;)V
+HSPLandroidx/lifecycle/viewmodel/InitializerViewModelFactory;->create(Ljava/lang/Class;Landroidx/lifecycle/viewmodel/CreationExtras;)Landroidx/lifecycle/ViewModel;
+HSPLandroidx/lifecycle/viewmodel/InitializerViewModelFactoryBuilder;-><init>()V
+HSPLandroidx/lifecycle/viewmodel/InitializerViewModelFactoryBuilder;->addInitializer(Lkotlin/reflect/KClass;Lkotlin/jvm/functions/Function1;)V
+HSPLandroidx/lifecycle/viewmodel/InitializerViewModelFactoryBuilder;->build()Landroidx/lifecycle/ViewModelProvider$Factory;
+HSPLandroidx/lifecycle/viewmodel/MutableCreationExtras;-><init>()V
+HSPLandroidx/lifecycle/viewmodel/MutableCreationExtras;-><init>(Landroidx/lifecycle/viewmodel/CreationExtras;)V
+HSPLandroidx/lifecycle/viewmodel/MutableCreationExtras;-><init>(Landroidx/lifecycle/viewmodel/CreationExtras;ILkotlin/jvm/internal/DefaultConstructorMarker;)V
+HSPLandroidx/lifecycle/viewmodel/MutableCreationExtras;->get(Landroidx/lifecycle/viewmodel/CreationExtras$Key;)Ljava/lang/Object;
+HSPLandroidx/lifecycle/viewmodel/MutableCreationExtras;->set(Landroidx/lifecycle/viewmodel/CreationExtras$Key;Ljava/lang/Object;)V
+HSPLandroidx/lifecycle/viewmodel/ViewModelInitializer;-><init>(Ljava/lang/Class;Lkotlin/jvm/functions/Function1;)V
+HSPLandroidx/lifecycle/viewmodel/ViewModelInitializer;->getClazz$lifecycle_viewmodel_release()Ljava/lang/Class;
+HSPLandroidx/lifecycle/viewmodel/ViewModelInitializer;->getInitializer$lifecycle_viewmodel_release()Lkotlin/jvm/functions/Function1;
+HSPLandroidx/lifecycle/viewmodel/compose/LocalViewModelStoreOwner$LocalViewModelStoreOwner$1;-><clinit>()V
+HSPLandroidx/lifecycle/viewmodel/compose/LocalViewModelStoreOwner$LocalViewModelStoreOwner$1;-><init>()V
+HSPLandroidx/lifecycle/viewmodel/compose/LocalViewModelStoreOwner$LocalViewModelStoreOwner$1;->invoke()Landroidx/lifecycle/ViewModelStoreOwner;
+HSPLandroidx/lifecycle/viewmodel/compose/LocalViewModelStoreOwner$LocalViewModelStoreOwner$1;->invoke()Ljava/lang/Object;
+HSPLandroidx/lifecycle/viewmodel/compose/LocalViewModelStoreOwner;-><clinit>()V
+HSPLandroidx/lifecycle/viewmodel/compose/LocalViewModelStoreOwner;-><init>()V
+HSPLandroidx/lifecycle/viewmodel/compose/LocalViewModelStoreOwner;->getCurrent(Landroidx/compose/runtime/Composer;I)Landroidx/lifecycle/ViewModelStoreOwner;
+HSPLandroidx/lifecycle/viewmodel/compose/ViewModelKt;->get(Landroidx/lifecycle/ViewModelStoreOwner;Ljava/lang/Class;Ljava/lang/String;Landroidx/lifecycle/ViewModelProvider$Factory;Landroidx/lifecycle/viewmodel/CreationExtras;)Landroidx/lifecycle/ViewModel;
+HSPLandroidx/lifecycle/viewmodel/compose/ViewModelKt;->viewModel(Ljava/lang/Class;Landroidx/lifecycle/ViewModelStoreOwner;Ljava/lang/String;Landroidx/lifecycle/ViewModelProvider$Factory;Landroidx/lifecycle/viewmodel/CreationExtras;Landroidx/compose/runtime/Composer;II)Landroidx/lifecycle/ViewModel;
+HSPLandroidx/profileinstaller/ProfileInstallerInitializer$$ExternalSyntheticLambda0;-><init>(Landroidx/profileinstaller/ProfileInstallerInitializer;Landroid/content/Context;)V
+HSPLandroidx/profileinstaller/ProfileInstallerInitializer$$ExternalSyntheticLambda0;->run()V
+HSPLandroidx/profileinstaller/ProfileInstallerInitializer$$ExternalSyntheticLambda1;-><init>(Landroid/content/Context;)V
+HSPLandroidx/profileinstaller/ProfileInstallerInitializer$Choreographer16Impl$$ExternalSyntheticLambda0;-><init>(Ljava/lang/Runnable;)V
+HSPLandroidx/profileinstaller/ProfileInstallerInitializer$Choreographer16Impl$$ExternalSyntheticLambda0;->doFrame(J)V
+HSPLandroidx/profileinstaller/ProfileInstallerInitializer$Choreographer16Impl;->$r8$lambda$DSwPKNQiVu4DdgIKQZrSpqkWM-A(Ljava/lang/Runnable;J)V
+HSPLandroidx/profileinstaller/ProfileInstallerInitializer$Choreographer16Impl;->lambda$postFrameCallback$0(Ljava/lang/Runnable;J)V
+HSPLandroidx/profileinstaller/ProfileInstallerInitializer$Choreographer16Impl;->postFrameCallback(Ljava/lang/Runnable;)V
+HSPLandroidx/profileinstaller/ProfileInstallerInitializer$Handler28Impl;->createAsync(Landroid/os/Looper;)Landroid/os/Handler;
+HSPLandroidx/profileinstaller/ProfileInstallerInitializer$Result;-><init>()V
+HSPLandroidx/profileinstaller/ProfileInstallerInitializer;->$r8$lambda$QGpANLTF0YGY0pXfe2eje4OKwkc(Landroidx/profileinstaller/ProfileInstallerInitializer;Landroid/content/Context;)V
+HSPLandroidx/profileinstaller/ProfileInstallerInitializer;-><init>()V
+HSPLandroidx/profileinstaller/ProfileInstallerInitializer;->create(Landroid/content/Context;)Landroidx/profileinstaller/ProfileInstallerInitializer$Result;
+HSPLandroidx/profileinstaller/ProfileInstallerInitializer;->create(Landroid/content/Context;)Ljava/lang/Object;
+HSPLandroidx/profileinstaller/ProfileInstallerInitializer;->delayAfterFirstFrame(Landroid/content/Context;)V
+HSPLandroidx/profileinstaller/ProfileInstallerInitializer;->dependencies()Ljava/util/List;
+HSPLandroidx/profileinstaller/ProfileInstallerInitializer;->installAfterDelay(Landroid/content/Context;)V
+HSPLandroidx/profileinstaller/ProfileInstallerInitializer;->lambda$delayAfterFirstFrame$0(Landroid/content/Context;)V
+HSPLandroidx/savedstate/Recreator$Companion;-><init>()V
+HSPLandroidx/savedstate/Recreator$Companion;-><init>(Lkotlin/jvm/internal/DefaultConstructorMarker;)V
+HSPLandroidx/savedstate/Recreator;-><clinit>()V
+HSPLandroidx/savedstate/Recreator;-><init>(Landroidx/savedstate/SavedStateRegistryOwner;)V
+HSPLandroidx/savedstate/Recreator;->onStateChanged(Landroidx/lifecycle/LifecycleOwner;Landroidx/lifecycle/Lifecycle$Event;)V
+HSPLandroidx/savedstate/SavedStateRegistry$$ExternalSyntheticLambda0;-><init>(Landroidx/savedstate/SavedStateRegistry;)V
+HSPLandroidx/savedstate/SavedStateRegistry$$ExternalSyntheticLambda0;->onStateChanged(Landroidx/lifecycle/LifecycleOwner;Landroidx/lifecycle/Lifecycle$Event;)V
+HSPLandroidx/savedstate/SavedStateRegistry$Companion;-><init>()V
+HSPLandroidx/savedstate/SavedStateRegistry$Companion;-><init>(Lkotlin/jvm/internal/DefaultConstructorMarker;)V
+HSPLandroidx/savedstate/SavedStateRegistry;->$r8$lambda$AUDDdpkzZrJMhBj0r-_9pI-j6hA(Landroidx/savedstate/SavedStateRegistry;Landroidx/lifecycle/LifecycleOwner;Landroidx/lifecycle/Lifecycle$Event;)V
+HSPLandroidx/savedstate/SavedStateRegistry;-><clinit>()V
+HSPLandroidx/savedstate/SavedStateRegistry;-><init>()V
+HSPLandroidx/savedstate/SavedStateRegistry;->consumeRestoredStateForKey(Ljava/lang/String;)Landroid/os/Bundle;
+HSPLandroidx/savedstate/SavedStateRegistry;->getSavedStateProvider(Ljava/lang/String;)Landroidx/savedstate/SavedStateRegistry$SavedStateProvider;
+HSPLandroidx/savedstate/SavedStateRegistry;->performAttach$lambda$4(Landroidx/savedstate/SavedStateRegistry;Landroidx/lifecycle/LifecycleOwner;Landroidx/lifecycle/Lifecycle$Event;)V
+HSPLandroidx/savedstate/SavedStateRegistry;->performAttach$savedstate_release(Landroidx/lifecycle/Lifecycle;)V
+HSPLandroidx/savedstate/SavedStateRegistry;->performRestore$savedstate_release(Landroid/os/Bundle;)V
+HSPLandroidx/savedstate/SavedStateRegistry;->registerSavedStateProvider(Ljava/lang/String;Landroidx/savedstate/SavedStateRegistry$SavedStateProvider;)V
+HSPLandroidx/savedstate/SavedStateRegistryController$Companion;-><init>()V
+HSPLandroidx/savedstate/SavedStateRegistryController$Companion;-><init>(Lkotlin/jvm/internal/DefaultConstructorMarker;)V
+HSPLandroidx/savedstate/SavedStateRegistryController$Companion;->create(Landroidx/savedstate/SavedStateRegistryOwner;)Landroidx/savedstate/SavedStateRegistryController;
+HSPLandroidx/savedstate/SavedStateRegistryController;-><clinit>()V
+HSPLandroidx/savedstate/SavedStateRegistryController;-><init>(Landroidx/savedstate/SavedStateRegistryOwner;)V
+HSPLandroidx/savedstate/SavedStateRegistryController;-><init>(Landroidx/savedstate/SavedStateRegistryOwner;Lkotlin/jvm/internal/DefaultConstructorMarker;)V
+HSPLandroidx/savedstate/SavedStateRegistryController;->create(Landroidx/savedstate/SavedStateRegistryOwner;)Landroidx/savedstate/SavedStateRegistryController;
+HSPLandroidx/savedstate/SavedStateRegistryController;->getSavedStateRegistry()Landroidx/savedstate/SavedStateRegistry;
+HSPLandroidx/savedstate/SavedStateRegistryController;->performAttach()V
+HSPLandroidx/savedstate/SavedStateRegistryController;->performRestore(Landroid/os/Bundle;)V
+HSPLandroidx/savedstate/ViewTreeSavedStateRegistryOwner$findViewTreeSavedStateRegistryOwner$1;-><clinit>()V
+HSPLandroidx/savedstate/ViewTreeSavedStateRegistryOwner$findViewTreeSavedStateRegistryOwner$1;-><init>()V
+HSPLandroidx/savedstate/ViewTreeSavedStateRegistryOwner$findViewTreeSavedStateRegistryOwner$1;->invoke(Landroid/view/View;)Landroid/view/View;
+HSPLandroidx/savedstate/ViewTreeSavedStateRegistryOwner$findViewTreeSavedStateRegistryOwner$1;->invoke(Ljava/lang/Object;)Ljava/lang/Object;
+HSPLandroidx/savedstate/ViewTreeSavedStateRegistryOwner$findViewTreeSavedStateRegistryOwner$2;-><clinit>()V
+HSPLandroidx/savedstate/ViewTreeSavedStateRegistryOwner$findViewTreeSavedStateRegistryOwner$2;-><init>()V
+HSPLandroidx/savedstate/ViewTreeSavedStateRegistryOwner$findViewTreeSavedStateRegistryOwner$2;->invoke(Landroid/view/View;)Landroidx/savedstate/SavedStateRegistryOwner;
+HSPLandroidx/savedstate/ViewTreeSavedStateRegistryOwner$findViewTreeSavedStateRegistryOwner$2;->invoke(Ljava/lang/Object;)Ljava/lang/Object;
+HSPLandroidx/savedstate/ViewTreeSavedStateRegistryOwner;->get(Landroid/view/View;)Landroidx/savedstate/SavedStateRegistryOwner;
+HSPLandroidx/savedstate/ViewTreeSavedStateRegistryOwner;->set(Landroid/view/View;Landroidx/savedstate/SavedStateRegistryOwner;)V
+HSPLandroidx/startup/AppInitializer;-><clinit>()V
+HSPLandroidx/startup/AppInitializer;-><init>(Landroid/content/Context;)V
+HSPLandroidx/startup/AppInitializer;->discoverAndInitialize(Landroid/os/Bundle;)V
+HSPLandroidx/startup/AppInitializer;->discoverAndInitialize(Ljava/lang/Class;)V
+HSPLandroidx/startup/AppInitializer;->doInitialize(Ljava/lang/Class;)Ljava/lang/Object;
+HSPLandroidx/startup/AppInitializer;->doInitialize(Ljava/lang/Class;Ljava/util/Set;)Ljava/lang/Object;
+HSPLandroidx/startup/AppInitializer;->getInstance(Landroid/content/Context;)Landroidx/startup/AppInitializer;
+HSPLandroidx/startup/AppInitializer;->initializeComponent(Ljava/lang/Class;)Ljava/lang/Object;
+HSPLandroidx/startup/AppInitializer;->isEagerlyInitialized(Ljava/lang/Class;)Z
+HSPLandroidx/startup/InitializationProvider;-><init>()V
+HSPLandroidx/startup/InitializationProvider;->onCreate()Z
+HSPLandroidx/tracing/Trace;->beginSection(Ljava/lang/String;)V
+HSPLandroidx/tracing/Trace;->endSection()V
+HSPLandroidx/tracing/Trace;->isEnabled()Z
+HSPLandroidx/tracing/TraceApi18Impl;->beginSection(Ljava/lang/String;)V
+HSPLandroidx/tracing/TraceApi18Impl;->endSection()V
+HSPLandroidx/tracing/TraceApi29Impl;->isEnabled()Z
+HSPLcom/android/credentialmanager/CreateFlowUtils$Companion$toCreateCredentialUiState$$inlined$compareByDescending$1;-><init>()V
+HSPLcom/android/credentialmanager/CreateFlowUtils$Companion$toCreateCredentialUiState$$inlined$compareByDescending$1;->compare(Ljava/lang/Object;Ljava/lang/Object;)I
+HSPLcom/android/credentialmanager/CreateFlowUtils$Companion;-><init>()V
+HSPLcom/android/credentialmanager/CreateFlowUtils$Companion;-><init>(Lkotlin/jvm/internal/DefaultConstructorMarker;)V
+HSPLcom/android/credentialmanager/CreateFlowUtils$Companion;->toActiveEntry(Lcom/android/credentialmanager/createflow/EnabledProviderInfo;ILcom/android/credentialmanager/createflow/EnabledProviderInfo;Lcom/android/credentialmanager/createflow/RemoteInfo;)Lcom/android/credentialmanager/createflow/ActiveEntry;
+HSPLcom/android/credentialmanager/CreateFlowUtils$Companion;->toCreateCredentialUiState(Ljava/util/List;Ljava/util/List;Ljava/lang/String;Lcom/android/credentialmanager/createflow/RequestDisplayInfo;ZZ)Lcom/android/credentialmanager/createflow/CreateCredentialUiState;
+HSPLcom/android/credentialmanager/CreateFlowUtils$Companion;->toCreateScreenState(IZLcom/android/credentialmanager/createflow/RequestDisplayInfo;Lcom/android/credentialmanager/createflow/EnabledProviderInfo;Lcom/android/credentialmanager/createflow/RemoteInfo;Z)Lcom/android/credentialmanager/createflow/CreateScreenState;
+HSPLcom/android/credentialmanager/CreateFlowUtils$Companion;->toCreationOptionInfoList(Ljava/lang/String;Ljava/util/List;Landroid/content/Context;)Ljava/util/List;
+HSPLcom/android/credentialmanager/CreateFlowUtils$Companion;->toDisabledProviderList(Ljava/util/List;Landroid/content/Context;)Ljava/util/List;
+HSPLcom/android/credentialmanager/CreateFlowUtils$Companion;->toEnabledProviderList(Ljava/util/List;Landroid/content/Context;)Ljava/util/List;
+HSPLcom/android/credentialmanager/CreateFlowUtils$Companion;->toRemoteInfo(Ljava/lang/String;Landroid/credentials/ui/Entry;)Lcom/android/credentialmanager/createflow/RemoteInfo;
+HSPLcom/android/credentialmanager/CreateFlowUtils$Companion;->toRequestDisplayInfo(Landroid/credentials/ui/RequestInfo;Landroid/content/Context;)Lcom/android/credentialmanager/createflow/RequestDisplayInfo;
+HSPLcom/android/credentialmanager/CreateFlowUtils;-><clinit>()V
+HSPLcom/android/credentialmanager/CredentialManagerRepo$Companion;-><init>()V
+HSPLcom/android/credentialmanager/CredentialManagerRepo$Companion;-><init>(Lkotlin/jvm/internal/DefaultConstructorMarker;)V
+HSPLcom/android/credentialmanager/CredentialManagerRepo$Companion;->getInstance()Lcom/android/credentialmanager/CredentialManagerRepo;
+HSPLcom/android/credentialmanager/CredentialManagerRepo$Companion;->getRepo()Lcom/android/credentialmanager/CredentialManagerRepo;
+HSPLcom/android/credentialmanager/CredentialManagerRepo$Companion;->setRepo(Lcom/android/credentialmanager/CredentialManagerRepo;)V
+HSPLcom/android/credentialmanager/CredentialManagerRepo$Companion;->setup(Landroid/content/Context;Landroid/content/Intent;)V
+HSPLcom/android/credentialmanager/CredentialManagerRepo;-><clinit>()V
+HSPLcom/android/credentialmanager/CredentialManagerRepo;-><init>(Landroid/content/Context;Landroid/content/Intent;)V
+HSPLcom/android/credentialmanager/CredentialManagerRepo;->getCreateProviderDisableListInitialUiState()Ljava/util/List;
+HSPLcom/android/credentialmanager/CredentialManagerRepo;->getCreateProviderEnableListInitialUiState()Ljava/util/List;
+HSPLcom/android/credentialmanager/CredentialManagerRepo;->getCreateRequestDisplayInfoInitialUiState()Lcom/android/credentialmanager/createflow/RequestDisplayInfo;
+HSPLcom/android/credentialmanager/CredentialManagerRepo;->getRequestInfo()Landroid/credentials/ui/RequestInfo;
+HSPLcom/android/credentialmanager/CredentialSelectorActivity$CredentialManagerBottomSheet$3;-><init>(Lcom/android/credentialmanager/CredentialSelectorActivity;Lcom/android/credentialmanager/common/DialogType;I)V
+HSPLcom/android/credentialmanager/CredentialSelectorActivity$CredentialManagerBottomSheet$launcher$1$1;-><init>(Landroidx/compose/runtime/MutableState;)V
+HSPLcom/android/credentialmanager/CredentialSelectorActivity$WhenMappings;-><clinit>()V
+HSPLcom/android/credentialmanager/CredentialSelectorActivity$onCancel$1;-><init>(Lcom/android/credentialmanager/CredentialSelectorActivity;)V
+HSPLcom/android/credentialmanager/CredentialSelectorActivity$onCreate$1$1;-><init>(Lcom/android/credentialmanager/CredentialSelectorActivity;Landroid/credentials/ui/RequestInfo;)V
+HSPLcom/android/credentialmanager/CredentialSelectorActivity$onCreate$1$1;->invoke(Landroidx/compose/runtime/Composer;I)V
+HSPLcom/android/credentialmanager/CredentialSelectorActivity$onCreate$1$1;->invoke(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;
+HSPLcom/android/credentialmanager/CredentialSelectorActivity$onCreate$1;-><init>(Lcom/android/credentialmanager/CredentialSelectorActivity;Landroid/credentials/ui/RequestInfo;)V
+HSPLcom/android/credentialmanager/CredentialSelectorActivity$onCreate$1;->invoke(Landroidx/compose/runtime/Composer;I)V
+HSPLcom/android/credentialmanager/CredentialSelectorActivity$onCreate$1;->invoke(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;
+HSPLcom/android/credentialmanager/CredentialSelectorActivity;-><clinit>()V
+HSPLcom/android/credentialmanager/CredentialSelectorActivity;-><init>()V
+HSPLcom/android/credentialmanager/CredentialSelectorActivity;->CredentialManagerBottomSheet(Lcom/android/credentialmanager/common/DialogType;Landroidx/compose/runtime/Composer;I)V
+HSPLcom/android/credentialmanager/CredentialSelectorActivity;->onCreate(Landroid/os/Bundle;)V
+HSPLcom/android/credentialmanager/UserConfigRepo$Companion;-><init>()V
+HSPLcom/android/credentialmanager/UserConfigRepo$Companion;-><init>(Lkotlin/jvm/internal/DefaultConstructorMarker;)V
+HSPLcom/android/credentialmanager/UserConfigRepo$Companion;->getInstance()Lcom/android/credentialmanager/UserConfigRepo;
+HSPLcom/android/credentialmanager/UserConfigRepo$Companion;->getRepo()Lcom/android/credentialmanager/UserConfigRepo;
+HSPLcom/android/credentialmanager/UserConfigRepo$Companion;->setRepo(Lcom/android/credentialmanager/UserConfigRepo;)V
+HSPLcom/android/credentialmanager/UserConfigRepo$Companion;->setup(Landroid/content/Context;)V
+HSPLcom/android/credentialmanager/UserConfigRepo;-><clinit>()V
+HSPLcom/android/credentialmanager/UserConfigRepo;-><init>(Landroid/content/Context;)V
+HSPLcom/android/credentialmanager/UserConfigRepo;->getDefaultProviderId()Ljava/lang/String;
+HSPLcom/android/credentialmanager/UserConfigRepo;->getIsPasskeyFirstUse()Z
+HSPLcom/android/credentialmanager/common/DialogType$Companion;-><init>()V
+HSPLcom/android/credentialmanager/common/DialogType$Companion;-><init>(Lkotlin/jvm/internal/DefaultConstructorMarker;)V
+HSPLcom/android/credentialmanager/common/DialogType$Companion;->toDialogType(Ljava/lang/String;)Lcom/android/credentialmanager/common/DialogType;
+HSPLcom/android/credentialmanager/common/DialogType;->$values()[Lcom/android/credentialmanager/common/DialogType;
+HSPLcom/android/credentialmanager/common/DialogType;-><clinit>()V
+HSPLcom/android/credentialmanager/common/DialogType;-><init>(Ljava/lang/String;I)V
+HSPLcom/android/credentialmanager/common/DialogType;->values()[Lcom/android/credentialmanager/common/DialogType;
+HSPLcom/android/credentialmanager/common/material/ModalBottomSheetDefaults;-><clinit>()V
+HSPLcom/android/credentialmanager/common/material/ModalBottomSheetDefaults;-><init>()V
+HSPLcom/android/credentialmanager/common/material/ModalBottomSheetDefaults;->getElevation-D9Ej5fM()F
+HSPLcom/android/credentialmanager/common/material/ModalBottomSheetKt$ModalBottomSheetLayout$1$1$1;-><init>(Lcom/android/credentialmanager/common/material/ModalBottomSheetState;Lkotlinx/coroutines/CoroutineScope;)V
+HSPLcom/android/credentialmanager/common/material/ModalBottomSheetKt$ModalBottomSheetLayout$1$2$1;-><init>(Lcom/android/credentialmanager/common/material/ModalBottomSheetState;F)V
+HSPLcom/android/credentialmanager/common/material/ModalBottomSheetKt$ModalBottomSheetLayout$1$2$1;->invoke(Ljava/lang/Object;)Ljava/lang/Object;
+HSPLcom/android/credentialmanager/common/material/ModalBottomSheetKt$ModalBottomSheetLayout$1$2$1;->invoke-Bjo55l4(Landroidx/compose/ui/unit/Density;)J
+HSPLcom/android/credentialmanager/common/material/ModalBottomSheetKt$ModalBottomSheetLayout$1$3$1;-><init>(Landroidx/compose/runtime/MutableState;)V
+HSPLcom/android/credentialmanager/common/material/ModalBottomSheetKt$ModalBottomSheetLayout$1$3$1;->invoke(Landroidx/compose/ui/layout/LayoutCoordinates;)V
+HSPLcom/android/credentialmanager/common/material/ModalBottomSheetKt$ModalBottomSheetLayout$1$3$1;->invoke(Ljava/lang/Object;)Ljava/lang/Object;
+HSPLcom/android/credentialmanager/common/material/ModalBottomSheetKt$ModalBottomSheetLayout$1$4$1;-><init>(Lcom/android/credentialmanager/common/material/ModalBottomSheetState;Lkotlinx/coroutines/CoroutineScope;)V
+HSPLcom/android/credentialmanager/common/material/ModalBottomSheetKt$ModalBottomSheetLayout$1$4;-><init>(Lcom/android/credentialmanager/common/material/ModalBottomSheetState;Lkotlinx/coroutines/CoroutineScope;)V
+HSPLcom/android/credentialmanager/common/material/ModalBottomSheetKt$ModalBottomSheetLayout$1$4;->invoke(Landroidx/compose/ui/semantics/SemanticsPropertyReceiver;)V
+HSPLcom/android/credentialmanager/common/material/ModalBottomSheetKt$ModalBottomSheetLayout$1$4;->invoke(Ljava/lang/Object;)Ljava/lang/Object;
+HSPLcom/android/credentialmanager/common/material/ModalBottomSheetKt$ModalBottomSheetLayout$1$5;-><init>(Lkotlin/jvm/functions/Function3;I)V
+HSPLcom/android/credentialmanager/common/material/ModalBottomSheetKt$ModalBottomSheetLayout$1$5;->invoke(Landroidx/compose/runtime/Composer;I)V
+HSPLcom/android/credentialmanager/common/material/ModalBottomSheetKt$ModalBottomSheetLayout$1$5;->invoke(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;
+HSPLcom/android/credentialmanager/common/material/ModalBottomSheetKt$ModalBottomSheetLayout$1;-><init>(Lcom/android/credentialmanager/common/material/ModalBottomSheetState;ILandroidx/compose/ui/graphics/Shape;JJFLkotlin/jvm/functions/Function2;JLkotlinx/coroutines/CoroutineScope;Lkotlin/jvm/functions/Function3;)V
+HSPLcom/android/credentialmanager/common/material/ModalBottomSheetKt$ModalBottomSheetLayout$1;->invoke(Landroidx/compose/foundation/layout/BoxWithConstraintsScope;Landroidx/compose/runtime/Composer;I)V
+HSPLcom/android/credentialmanager/common/material/ModalBottomSheetKt$ModalBottomSheetLayout$1;->invoke(Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;
+HSPLcom/android/credentialmanager/common/material/ModalBottomSheetKt$ModalBottomSheetLayout$2;-><init>(Lkotlin/jvm/functions/Function3;Landroidx/compose/ui/Modifier;Lcom/android/credentialmanager/common/material/ModalBottomSheetState;Landroidx/compose/ui/graphics/Shape;FJJJLkotlin/jvm/functions/Function2;II)V
+HSPLcom/android/credentialmanager/common/material/ModalBottomSheetKt$Scrim$1$1;-><init>(JLandroidx/compose/runtime/State;)V
+HSPLcom/android/credentialmanager/common/material/ModalBottomSheetKt$Scrim$1$1;->invoke(Landroidx/compose/ui/graphics/drawscope/DrawScope;)V
+HSPLcom/android/credentialmanager/common/material/ModalBottomSheetKt$Scrim$1$1;->invoke(Ljava/lang/Object;)Ljava/lang/Object;
+HSPLcom/android/credentialmanager/common/material/ModalBottomSheetKt$Scrim$2;-><init>(JLkotlin/jvm/functions/Function0;ZI)V
+HSPLcom/android/credentialmanager/common/material/ModalBottomSheetKt$Scrim$dismissModifier$1$1$1;-><init>(Lkotlin/jvm/functions/Function0;)V
+HSPLcom/android/credentialmanager/common/material/ModalBottomSheetKt$Scrim$dismissModifier$1$1;-><init>(Lkotlin/jvm/functions/Function0;Lkotlin/coroutines/Continuation;)V
+HSPLcom/android/credentialmanager/common/material/ModalBottomSheetKt$Scrim$dismissModifier$1$1;->create(Ljava/lang/Object;Lkotlin/coroutines/Continuation;)Lkotlin/coroutines/Continuation;
+HSPLcom/android/credentialmanager/common/material/ModalBottomSheetKt$Scrim$dismissModifier$1$1;->invoke(Landroidx/compose/ui/input/pointer/PointerInputScope;Lkotlin/coroutines/Continuation;)Ljava/lang/Object;
+HSPLcom/android/credentialmanager/common/material/ModalBottomSheetKt$Scrim$dismissModifier$1$1;->invoke(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;
+HSPLcom/android/credentialmanager/common/material/ModalBottomSheetKt$Scrim$dismissModifier$1$1;->invokeSuspend(Ljava/lang/Object;)Ljava/lang/Object;
+HSPLcom/android/credentialmanager/common/material/ModalBottomSheetKt$Scrim$dismissModifier$2$1$1;-><init>(Lkotlin/jvm/functions/Function0;)V
+HSPLcom/android/credentialmanager/common/material/ModalBottomSheetKt$Scrim$dismissModifier$2$1;-><init>(Ljava/lang/String;Lkotlin/jvm/functions/Function0;)V
+HSPLcom/android/credentialmanager/common/material/ModalBottomSheetKt$Scrim$dismissModifier$2$1;->invoke(Landroidx/compose/ui/semantics/SemanticsPropertyReceiver;)V
+HSPLcom/android/credentialmanager/common/material/ModalBottomSheetKt$Scrim$dismissModifier$2$1;->invoke(Ljava/lang/Object;)Ljava/lang/Object;
+HSPLcom/android/credentialmanager/common/material/ModalBottomSheetKt$rememberModalBottomSheetState$1;-><clinit>()V
+HSPLcom/android/credentialmanager/common/material/ModalBottomSheetKt$rememberModalBottomSheetState$1;-><init>()V
+HSPLcom/android/credentialmanager/common/material/ModalBottomSheetKt$rememberModalBottomSheetState$2;-><init>(Lcom/android/credentialmanager/common/material/ModalBottomSheetValue;Landroidx/compose/animation/core/AnimationSpec;ZLkotlin/jvm/functions/Function1;)V
+HSPLcom/android/credentialmanager/common/material/ModalBottomSheetKt$rememberModalBottomSheetState$2;->invoke()Lcom/android/credentialmanager/common/material/ModalBottomSheetState;
+HSPLcom/android/credentialmanager/common/material/ModalBottomSheetKt$rememberModalBottomSheetState$2;->invoke()Ljava/lang/Object;
+HSPLcom/android/credentialmanager/common/material/ModalBottomSheetKt;->ModalBottomSheetLayout-BzaUkTc(Lkotlin/jvm/functions/Function3;Landroidx/compose/ui/Modifier;Lcom/android/credentialmanager/common/material/ModalBottomSheetState;Landroidx/compose/ui/graphics/Shape;FJJJLkotlin/jvm/functions/Function2;Landroidx/compose/runtime/Composer;II)V
+HSPLcom/android/credentialmanager/common/material/ModalBottomSheetKt;->Scrim-3J-VO9M(JLkotlin/jvm/functions/Function0;ZLandroidx/compose/runtime/Composer;I)V
+HSPLcom/android/credentialmanager/common/material/ModalBottomSheetKt;->Scrim_3J_VO9M$lambda$0(Landroidx/compose/runtime/State;)F
+HSPLcom/android/credentialmanager/common/material/ModalBottomSheetKt;->access$Scrim-3J-VO9M(JLkotlin/jvm/functions/Function0;ZLandroidx/compose/runtime/Composer;I)V
+HSPLcom/android/credentialmanager/common/material/ModalBottomSheetKt;->access$Scrim_3J_VO9M$lambda$0(Landroidx/compose/runtime/State;)F
+HSPLcom/android/credentialmanager/common/material/ModalBottomSheetKt;->access$bottomSheetSwipeable(Landroidx/compose/ui/Modifier;Lcom/android/credentialmanager/common/material/ModalBottomSheetState;FLandroidx/compose/runtime/State;)Landroidx/compose/ui/Modifier;
+HSPLcom/android/credentialmanager/common/material/ModalBottomSheetKt;->bottomSheetSwipeable(Landroidx/compose/ui/Modifier;Lcom/android/credentialmanager/common/material/ModalBottomSheetState;FLandroidx/compose/runtime/State;)Landroidx/compose/ui/Modifier;
+HSPLcom/android/credentialmanager/common/material/ModalBottomSheetKt;->rememberModalBottomSheetState(Lcom/android/credentialmanager/common/material/ModalBottomSheetValue;Landroidx/compose/animation/core/AnimationSpec;ZLkotlin/jvm/functions/Function1;Landroidx/compose/runtime/Composer;II)Lcom/android/credentialmanager/common/material/ModalBottomSheetState;
+HSPLcom/android/credentialmanager/common/material/ModalBottomSheetState$Companion$Saver$1;-><clinit>()V
+HSPLcom/android/credentialmanager/common/material/ModalBottomSheetState$Companion$Saver$1;-><init>()V
+HSPLcom/android/credentialmanager/common/material/ModalBottomSheetState$Companion$Saver$1;->invoke(Landroidx/compose/runtime/saveable/SaverScope;Lcom/android/credentialmanager/common/material/ModalBottomSheetState;)Lcom/android/credentialmanager/common/material/ModalBottomSheetValue;
+HSPLcom/android/credentialmanager/common/material/ModalBottomSheetState$Companion$Saver$1;->invoke(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;
+HSPLcom/android/credentialmanager/common/material/ModalBottomSheetState$Companion$Saver$2;-><init>(Landroidx/compose/animation/core/AnimationSpec;ZLkotlin/jvm/functions/Function1;)V
+HSPLcom/android/credentialmanager/common/material/ModalBottomSheetState$Companion;-><init>()V
+HSPLcom/android/credentialmanager/common/material/ModalBottomSheetState$Companion;-><init>(Lkotlin/jvm/internal/DefaultConstructorMarker;)V
+HSPLcom/android/credentialmanager/common/material/ModalBottomSheetState$Companion;->Saver(Landroidx/compose/animation/core/AnimationSpec;ZLkotlin/jvm/functions/Function1;)Landroidx/compose/runtime/saveable/Saver;
+HSPLcom/android/credentialmanager/common/material/ModalBottomSheetState;-><clinit>()V
+HSPLcom/android/credentialmanager/common/material/ModalBottomSheetState;-><init>(Lcom/android/credentialmanager/common/material/ModalBottomSheetValue;Landroidx/compose/animation/core/AnimationSpec;ZLkotlin/jvm/functions/Function1;)V
+HSPLcom/android/credentialmanager/common/material/ModalBottomSheetState;->getHasHalfExpandedState$frameworks__base__packages__CredentialManager__android_common__CredentialManager()Z
+HSPLcom/android/credentialmanager/common/material/ModalBottomSheetState;->getNestedScrollConnection$frameworks__base__packages__CredentialManager__android_common__CredentialManager()Landroidx/compose/ui/input/nestedscroll/NestedScrollConnection;
+HSPLcom/android/credentialmanager/common/material/ModalBottomSheetState;->isSkipHalfExpanded$frameworks__base__packages__CredentialManager__android_common__CredentialManager()Z
+HSPLcom/android/credentialmanager/common/material/ModalBottomSheetState;->isVisible()Z
+HSPLcom/android/credentialmanager/common/material/ModalBottomSheetValue;->$values()[Lcom/android/credentialmanager/common/material/ModalBottomSheetValue;
+HSPLcom/android/credentialmanager/common/material/ModalBottomSheetValue;-><clinit>()V
+HSPLcom/android/credentialmanager/common/material/ModalBottomSheetValue;-><init>(Ljava/lang/String;I)V
+HSPLcom/android/credentialmanager/common/material/SwipeableDefaults;-><clinit>()V
+HSPLcom/android/credentialmanager/common/material/SwipeableDefaults;-><init>()V
+HSPLcom/android/credentialmanager/common/material/SwipeableDefaults;->getAnimationSpec()Landroidx/compose/animation/core/SpringSpec;
+HSPLcom/android/credentialmanager/common/material/SwipeableDefaults;->getVelocityThreshold-D9Ej5fM()F
+HSPLcom/android/credentialmanager/common/material/SwipeableKt$PreUpPostDownNestedScrollConnection$1;-><init>(Lcom/android/credentialmanager/common/material/SwipeableState;)V
+HSPLcom/android/credentialmanager/common/material/SwipeableKt$swipeable$1;-><clinit>()V
+HSPLcom/android/credentialmanager/common/material/SwipeableKt$swipeable$1;-><init>()V
+HSPLcom/android/credentialmanager/common/material/SwipeableKt$swipeable$3$3$1;-><init>(Ljava/util/Map;Lkotlin/jvm/functions/Function2;Landroidx/compose/ui/unit/Density;)V
+HSPLcom/android/credentialmanager/common/material/SwipeableKt$swipeable$3$3;-><init>(Lcom/android/credentialmanager/common/material/SwipeableState;Ljava/util/Map;Lcom/android/credentialmanager/common/material/ResistanceConfig;Landroidx/compose/ui/unit/Density;Lkotlin/jvm/functions/Function2;FLkotlin/coroutines/Continuation;)V
+HSPLcom/android/credentialmanager/common/material/SwipeableKt$swipeable$3$3;->create(Ljava/lang/Object;Lkotlin/coroutines/Continuation;)Lkotlin/coroutines/Continuation;
+HSPLcom/android/credentialmanager/common/material/SwipeableKt$swipeable$3$3;->invokeSuspend(Ljava/lang/Object;)Ljava/lang/Object;
+HSPLcom/android/credentialmanager/common/material/SwipeableKt$swipeable$3$4$1;-><init>(Lcom/android/credentialmanager/common/material/SwipeableState;Lkotlin/coroutines/Continuation;)V
+HSPLcom/android/credentialmanager/common/material/SwipeableKt$swipeable$3;-><init>(Ljava/util/Map;Lcom/android/credentialmanager/common/material/SwipeableState;Landroidx/compose/foundation/gestures/Orientation;ZLandroidx/compose/foundation/interaction/MutableInteractionSource;ZLcom/android/credentialmanager/common/material/ResistanceConfig;Lkotlin/jvm/functions/Function2;F)V
+HSPLcom/android/credentialmanager/common/material/SwipeableKt$swipeable$3;->invoke(Landroidx/compose/ui/Modifier;Landroidx/compose/runtime/Composer;I)Landroidx/compose/ui/Modifier;
+HSPLcom/android/credentialmanager/common/material/SwipeableKt$swipeable$3;->invoke(Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;
+HSPLcom/android/credentialmanager/common/material/SwipeableKt;->access$computeTarget(FFLjava/util/Set;Lkotlin/jvm/functions/Function2;FF)F
+HSPLcom/android/credentialmanager/common/material/SwipeableKt;->access$getOffset(Ljava/util/Map;Ljava/lang/Object;)Ljava/lang/Float;
+HSPLcom/android/credentialmanager/common/material/SwipeableKt;->computeTarget(FFLjava/util/Set;Lkotlin/jvm/functions/Function2;FF)F
+HSPLcom/android/credentialmanager/common/material/SwipeableKt;->findBounds(FLjava/util/Set;)Ljava/util/List;
+HSPLcom/android/credentialmanager/common/material/SwipeableKt;->getOffset(Ljava/util/Map;Ljava/lang/Object;)Ljava/lang/Float;
+HSPLcom/android/credentialmanager/common/material/SwipeableKt;->getPreUpPostDownNestedScrollConnection(Lcom/android/credentialmanager/common/material/SwipeableState;)Landroidx/compose/ui/input/nestedscroll/NestedScrollConnection;
+HSPLcom/android/credentialmanager/common/material/SwipeableKt;->swipeable-pPrIpRY$default(Landroidx/compose/ui/Modifier;Lcom/android/credentialmanager/common/material/SwipeableState;Ljava/util/Map;Landroidx/compose/foundation/gestures/Orientation;ZZLandroidx/compose/foundation/interaction/MutableInteractionSource;Lkotlin/jvm/functions/Function2;Lcom/android/credentialmanager/common/material/ResistanceConfig;FILjava/lang/Object;)Landroidx/compose/ui/Modifier;
+HSPLcom/android/credentialmanager/common/material/SwipeableKt;->swipeable-pPrIpRY(Landroidx/compose/ui/Modifier;Lcom/android/credentialmanager/common/material/SwipeableState;Ljava/util/Map;Landroidx/compose/foundation/gestures/Orientation;ZZLandroidx/compose/foundation/interaction/MutableInteractionSource;Lkotlin/jvm/functions/Function2;Lcom/android/credentialmanager/common/material/ResistanceConfig;F)Landroidx/compose/ui/Modifier;
+HSPLcom/android/credentialmanager/common/material/SwipeableState$Companion;-><init>()V
+HSPLcom/android/credentialmanager/common/material/SwipeableState$Companion;-><init>(Lkotlin/jvm/internal/DefaultConstructorMarker;)V
+HSPLcom/android/credentialmanager/common/material/SwipeableState$draggableState$1;-><init>(Lcom/android/credentialmanager/common/material/SwipeableState;)V
+HSPLcom/android/credentialmanager/common/material/SwipeableState$draggableState$1;->invoke(F)V
+HSPLcom/android/credentialmanager/common/material/SwipeableState$draggableState$1;->invoke(Ljava/lang/Object;)Ljava/lang/Object;
+HSPLcom/android/credentialmanager/common/material/SwipeableState$latestNonEmptyAnchorsFlow$1;-><init>(Lcom/android/credentialmanager/common/material/SwipeableState;)V
+HSPLcom/android/credentialmanager/common/material/SwipeableState$processNewAnchors$1;-><init>(Lcom/android/credentialmanager/common/material/SwipeableState;Lkotlin/coroutines/Continuation;)V
+HSPLcom/android/credentialmanager/common/material/SwipeableState$snapInternalToOffset$2;-><init>(FLcom/android/credentialmanager/common/material/SwipeableState;Lkotlin/coroutines/Continuation;)V
+HSPLcom/android/credentialmanager/common/material/SwipeableState$snapInternalToOffset$2;->create(Ljava/lang/Object;Lkotlin/coroutines/Continuation;)Lkotlin/coroutines/Continuation;
+HSPLcom/android/credentialmanager/common/material/SwipeableState$snapInternalToOffset$2;->invoke(Landroidx/compose/foundation/gestures/DragScope;Lkotlin/coroutines/Continuation;)Ljava/lang/Object;
+HSPLcom/android/credentialmanager/common/material/SwipeableState$snapInternalToOffset$2;->invoke(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;
+HSPLcom/android/credentialmanager/common/material/SwipeableState$snapInternalToOffset$2;->invokeSuspend(Ljava/lang/Object;)Ljava/lang/Object;
+HSPLcom/android/credentialmanager/common/material/SwipeableState$special$$inlined$filter$1;-><init>(Lkotlinx/coroutines/flow/Flow;)V
+HSPLcom/android/credentialmanager/common/material/SwipeableState$thresholds$2;-><clinit>()V
+HSPLcom/android/credentialmanager/common/material/SwipeableState$thresholds$2;-><init>()V
+HSPLcom/android/credentialmanager/common/material/SwipeableState;-><clinit>()V
+HSPLcom/android/credentialmanager/common/material/SwipeableState;-><init>(Ljava/lang/Object;Landroidx/compose/animation/core/AnimationSpec;Lkotlin/jvm/functions/Function1;)V
+HSPLcom/android/credentialmanager/common/material/SwipeableState;->access$getAbsoluteOffset$p(Lcom/android/credentialmanager/common/material/SwipeableState;)Landroidx/compose/runtime/MutableState;
+HSPLcom/android/credentialmanager/common/material/SwipeableState;->access$getOffsetState$p(Lcom/android/credentialmanager/common/material/SwipeableState;)Landroidx/compose/runtime/MutableState;
+HSPLcom/android/credentialmanager/common/material/SwipeableState;->access$getOverflowState$p(Lcom/android/credentialmanager/common/material/SwipeableState;)Landroidx/compose/runtime/MutableState;
+HSPLcom/android/credentialmanager/common/material/SwipeableState;->ensureInit$frameworks__base__packages__CredentialManager__android_common__CredentialManager(Ljava/util/Map;)V
+HSPLcom/android/credentialmanager/common/material/SwipeableState;->getAnchors$frameworks__base__packages__CredentialManager__android_common__CredentialManager()Ljava/util/Map;
+HSPLcom/android/credentialmanager/common/material/SwipeableState;->getCurrentValue()Ljava/lang/Object;
+HSPLcom/android/credentialmanager/common/material/SwipeableState;->getDraggableState$frameworks__base__packages__CredentialManager__android_common__CredentialManager()Landroidx/compose/foundation/gestures/DraggableState;
+HSPLcom/android/credentialmanager/common/material/SwipeableState;->getMaxBound$frameworks__base__packages__CredentialManager__android_common__CredentialManager()F
+HSPLcom/android/credentialmanager/common/material/SwipeableState;->getMinBound$frameworks__base__packages__CredentialManager__android_common__CredentialManager()F
+HSPLcom/android/credentialmanager/common/material/SwipeableState;->getOffset()Landroidx/compose/runtime/State;
+HSPLcom/android/credentialmanager/common/material/SwipeableState;->getResistance$frameworks__base__packages__CredentialManager__android_common__CredentialManager()Lcom/android/credentialmanager/common/material/ResistanceConfig;
+HSPLcom/android/credentialmanager/common/material/SwipeableState;->getTargetValue()Ljava/lang/Object;
+HSPLcom/android/credentialmanager/common/material/SwipeableState;->getThresholds$frameworks__base__packages__CredentialManager__android_common__CredentialManager()Lkotlin/jvm/functions/Function2;
+HSPLcom/android/credentialmanager/common/material/SwipeableState;->isAnimationRunning()Z
+HSPLcom/android/credentialmanager/common/material/SwipeableState;->processNewAnchors$frameworks__base__packages__CredentialManager__android_common__CredentialManager(Ljava/util/Map;Ljava/util/Map;Lkotlin/coroutines/Continuation;)Ljava/lang/Object;
+HSPLcom/android/credentialmanager/common/material/SwipeableState;->setAnchors$frameworks__base__packages__CredentialManager__android_common__CredentialManager(Ljava/util/Map;)V
+HSPLcom/android/credentialmanager/common/material/SwipeableState;->setResistance$frameworks__base__packages__CredentialManager__android_common__CredentialManager(Lcom/android/credentialmanager/common/material/ResistanceConfig;)V
+HSPLcom/android/credentialmanager/common/material/SwipeableState;->setThresholds$frameworks__base__packages__CredentialManager__android_common__CredentialManager(Lkotlin/jvm/functions/Function2;)V
+HSPLcom/android/credentialmanager/common/material/SwipeableState;->setVelocityThreshold$frameworks__base__packages__CredentialManager__android_common__CredentialManager(F)V
+HSPLcom/android/credentialmanager/common/material/SwipeableState;->snapInternalToOffset(FLkotlin/coroutines/Continuation;)Ljava/lang/Object;
+HSPLcom/android/credentialmanager/common/ui/ActionButtonKt$ActionButton$1;-><init>(Ljava/lang/String;I)V
+HSPLcom/android/credentialmanager/common/ui/ActionButtonKt$ActionButton$1;->invoke(Landroidx/compose/foundation/layout/RowScope;Landroidx/compose/runtime/Composer;I)V
+HSPLcom/android/credentialmanager/common/ui/ActionButtonKt$ActionButton$1;->invoke(Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;
+HSPLcom/android/credentialmanager/common/ui/ActionButtonKt$ActionButton$2;-><init>(Ljava/lang/String;Lkotlin/jvm/functions/Function0;I)V
+HSPLcom/android/credentialmanager/common/ui/ActionButtonKt;->ActionButton(Ljava/lang/String;Lkotlin/jvm/functions/Function0;Landroidx/compose/runtime/Composer;I)V
+HSPLcom/android/credentialmanager/common/ui/CardsKt$ContainerCard$1;-><init>(Landroidx/compose/ui/Modifier;Landroidx/compose/ui/graphics/Shape;Landroidx/compose/foundation/BorderStroke;Lkotlin/jvm/functions/Function3;II)V
+HSPLcom/android/credentialmanager/common/ui/CardsKt;->ContainerCard(Landroidx/compose/ui/Modifier;Landroidx/compose/ui/graphics/Shape;Landroidx/compose/foundation/BorderStroke;Lkotlin/jvm/functions/Function3;Landroidx/compose/runtime/Composer;II)V
+HSPLcom/android/credentialmanager/common/ui/ConfirmButtonKt$ConfirmButton$1;-><init>(Ljava/lang/String;I)V
+HSPLcom/android/credentialmanager/common/ui/ConfirmButtonKt$ConfirmButton$1;->invoke(Landroidx/compose/foundation/layout/RowScope;Landroidx/compose/runtime/Composer;I)V
+HSPLcom/android/credentialmanager/common/ui/ConfirmButtonKt$ConfirmButton$1;->invoke(Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;
+HSPLcom/android/credentialmanager/common/ui/ConfirmButtonKt$ConfirmButton$2;-><init>(Ljava/lang/String;Lkotlin/jvm/functions/Function0;I)V
+HSPLcom/android/credentialmanager/common/ui/ConfirmButtonKt;->ConfirmButton(Ljava/lang/String;Lkotlin/jvm/functions/Function0;Landroidx/compose/runtime/Composer;I)V
+HSPLcom/android/credentialmanager/common/ui/EntryKt$Entry$1;-><init>(Lkotlin/jvm/functions/Function0;Lkotlin/jvm/functions/Function2;Landroidx/compose/ui/Modifier;Lkotlin/jvm/functions/Function2;II)V
+HSPLcom/android/credentialmanager/common/ui/EntryKt;->Entry(Lkotlin/jvm/functions/Function0;Lkotlin/jvm/functions/Function2;Landroidx/compose/ui/Modifier;Lkotlin/jvm/functions/Function2;Landroidx/compose/runtime/Composer;II)V
+HSPLcom/android/credentialmanager/common/ui/TextsKt$TextOnSurface$1;-><init>(Ljava/lang/String;Landroidx/compose/ui/Modifier;Landroidx/compose/ui/text/style/TextAlign;Landroidx/compose/ui/text/TextStyle;II)V
+HSPLcom/android/credentialmanager/common/ui/TextsKt$TextOnSurfaceVariant$1;-><init>(Ljava/lang/String;Landroidx/compose/ui/Modifier;Landroidx/compose/ui/text/style/TextAlign;Landroidx/compose/ui/text/TextStyle;II)V
+HSPLcom/android/credentialmanager/common/ui/TextsKt$TextSecondary$1;-><init>(Ljava/lang/String;Landroidx/compose/ui/Modifier;Landroidx/compose/ui/text/style/TextAlign;Landroidx/compose/ui/text/TextStyle;II)V
+HSPLcom/android/credentialmanager/common/ui/TextsKt;->TextInternal-2rk-Xng(Ljava/lang/String;JLandroidx/compose/ui/Modifier;Landroidx/compose/ui/text/style/TextAlign;Landroidx/compose/ui/text/TextStyle;Landroidx/compose/runtime/Composer;I)V
+HSPLcom/android/credentialmanager/common/ui/TextsKt;->TextOnSurface-B9Ufvwk(Ljava/lang/String;Landroidx/compose/ui/Modifier;Landroidx/compose/ui/text/style/TextAlign;Landroidx/compose/ui/text/TextStyle;Landroidx/compose/runtime/Composer;II)V
+HSPLcom/android/credentialmanager/common/ui/TextsKt;->TextOnSurfaceVariant-B9Ufvwk(Ljava/lang/String;Landroidx/compose/ui/Modifier;Landroidx/compose/ui/text/style/TextAlign;Landroidx/compose/ui/text/TextStyle;Landroidx/compose/runtime/Composer;II)V
+HSPLcom/android/credentialmanager/common/ui/TextsKt;->TextSecondary-B9Ufvwk(Ljava/lang/String;Landroidx/compose/ui/Modifier;Landroidx/compose/ui/text/style/TextAlign;Landroidx/compose/ui/text/TextStyle;Landroidx/compose/runtime/Composer;II)V
+HSPLcom/android/credentialmanager/createflow/ActiveEntry;-><clinit>()V
+HSPLcom/android/credentialmanager/createflow/ActiveEntry;-><init>(Lcom/android/credentialmanager/createflow/EnabledProviderInfo;Lcom/android/credentialmanager/createflow/EntryInfo;)V
+HSPLcom/android/credentialmanager/createflow/ActiveEntry;->getActiveEntryInfo()Lcom/android/credentialmanager/createflow/EntryInfo;
+HSPLcom/android/credentialmanager/createflow/ActiveEntry;->getActiveProvider()Lcom/android/credentialmanager/createflow/EnabledProviderInfo;
+HSPLcom/android/credentialmanager/createflow/ComposableSingletons$CreateCredentialComponentsKt$lambda-1$1;-><clinit>()V
+HSPLcom/android/credentialmanager/createflow/ComposableSingletons$CreateCredentialComponentsKt$lambda-1$1;-><init>()V
+HSPLcom/android/credentialmanager/createflow/ComposableSingletons$CreateCredentialComponentsKt$lambda-1$1;->invoke(Landroidx/compose/runtime/Composer;I)V
+HSPLcom/android/credentialmanager/createflow/ComposableSingletons$CreateCredentialComponentsKt$lambda-1$1;->invoke(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;
+HSPLcom/android/credentialmanager/createflow/ComposableSingletons$CreateCredentialComponentsKt$lambda-2$1;-><clinit>()V
+HSPLcom/android/credentialmanager/createflow/ComposableSingletons$CreateCredentialComponentsKt$lambda-2$1;-><init>()V
+HSPLcom/android/credentialmanager/createflow/ComposableSingletons$CreateCredentialComponentsKt$lambda-3$1;-><clinit>()V
+HSPLcom/android/credentialmanager/createflow/ComposableSingletons$CreateCredentialComponentsKt$lambda-3$1;-><init>()V
+HSPLcom/android/credentialmanager/createflow/ComposableSingletons$CreateCredentialComponentsKt$lambda-4$1;-><clinit>()V
+HSPLcom/android/credentialmanager/createflow/ComposableSingletons$CreateCredentialComponentsKt$lambda-4$1;-><init>()V
+HSPLcom/android/credentialmanager/createflow/ComposableSingletons$CreateCredentialComponentsKt$lambda-5$1;-><clinit>()V
+HSPLcom/android/credentialmanager/createflow/ComposableSingletons$CreateCredentialComponentsKt$lambda-5$1;-><init>()V
+HSPLcom/android/credentialmanager/createflow/ComposableSingletons$CreateCredentialComponentsKt;-><clinit>()V
+HSPLcom/android/credentialmanager/createflow/ComposableSingletons$CreateCredentialComponentsKt;-><init>()V
+HSPLcom/android/credentialmanager/createflow/ComposableSingletons$CreateCredentialComponentsKt;->getLambda-1$frameworks__base__packages__CredentialManager__android_common__CredentialManager()Lkotlin/jvm/functions/Function2;
+HSPLcom/android/credentialmanager/createflow/CreateCredentialComponentsKt$CreateCredentialScreen$1$6;-><init>(Ljava/lang/Object;)V
+HSPLcom/android/credentialmanager/createflow/CreateCredentialComponentsKt$CreateCredentialScreen$1$7;-><init>(Ljava/lang/Object;)V
+HSPLcom/android/credentialmanager/createflow/CreateCredentialComponentsKt$CreateCredentialScreen$1$8;-><init>(Ljava/lang/Object;)V
+HSPLcom/android/credentialmanager/createflow/CreateCredentialComponentsKt$CreateCredentialScreen$1$WhenMappings;-><clinit>()V
+HSPLcom/android/credentialmanager/createflow/CreateCredentialComponentsKt$CreateCredentialScreen$1;-><init>(Lcom/android/credentialmanager/createflow/CreateCredentialViewModel;Landroidx/activity/compose/ManagedActivityResultLauncher;)V
+HSPLcom/android/credentialmanager/createflow/CreateCredentialComponentsKt$CreateCredentialScreen$1;->invoke(Landroidx/compose/foundation/layout/ColumnScope;Landroidx/compose/runtime/Composer;I)V
+HSPLcom/android/credentialmanager/createflow/CreateCredentialComponentsKt$CreateCredentialScreen$1;->invoke(Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;
+HSPLcom/android/credentialmanager/createflow/CreateCredentialComponentsKt$CreateCredentialScreen$2;-><init>(Lcom/android/credentialmanager/common/material/ModalBottomSheetState;Lcom/android/credentialmanager/createflow/CreateCredentialViewModel;Lkotlin/coroutines/Continuation;)V
+HSPLcom/android/credentialmanager/createflow/CreateCredentialComponentsKt$CreateCredentialScreen$2;->create(Ljava/lang/Object;Lkotlin/coroutines/Continuation;)Lkotlin/coroutines/Continuation;
+HSPLcom/android/credentialmanager/createflow/CreateCredentialComponentsKt$CreateCredentialScreen$2;->invokeSuspend(Ljava/lang/Object;)Ljava/lang/Object;
+HSPLcom/android/credentialmanager/createflow/CreateCredentialComponentsKt$CreateCredentialScreen$3;-><init>(Lcom/android/credentialmanager/createflow/CreateCredentialViewModel;Landroidx/activity/compose/ManagedActivityResultLauncher;I)V
+HSPLcom/android/credentialmanager/createflow/CreateCredentialComponentsKt$CreationSelectionCard$1$1$1;-><init>(Lcom/android/credentialmanager/createflow/RequestDisplayInfo;Lcom/android/credentialmanager/createflow/CreateOptionInfo;Lkotlin/jvm/functions/Function1;I)V
+HSPLcom/android/credentialmanager/createflow/CreateCredentialComponentsKt$CreationSelectionCard$1$1$1;->invoke(Landroidx/compose/foundation/layout/ColumnScope;Landroidx/compose/runtime/Composer;I)V
+HSPLcom/android/credentialmanager/createflow/CreateCredentialComponentsKt$CreationSelectionCard$1$1$1;->invoke(Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;
+HSPLcom/android/credentialmanager/createflow/CreateCredentialComponentsKt$CreationSelectionCard$1;-><init>(Lcom/android/credentialmanager/createflow/EnabledProviderInfo;Lcom/android/credentialmanager/createflow/RequestDisplayInfo;Ljava/util/List;Lcom/android/credentialmanager/createflow/CreateOptionInfo;Lkotlin/jvm/functions/Function1;ILkotlin/jvm/functions/Function0;Lkotlin/jvm/functions/Function0;)V
+HSPLcom/android/credentialmanager/createflow/CreateCredentialComponentsKt$CreationSelectionCard$1;->invoke(Landroidx/compose/foundation/layout/ColumnScope;Landroidx/compose/runtime/Composer;I)V
+HSPLcom/android/credentialmanager/createflow/CreateCredentialComponentsKt$CreationSelectionCard$1;->invoke(Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;
+HSPLcom/android/credentialmanager/createflow/CreateCredentialComponentsKt$PrimaryCreateOptionRow$1;-><init>(Lkotlin/jvm/functions/Function1;Lcom/android/credentialmanager/createflow/EntryInfo;)V
+HSPLcom/android/credentialmanager/createflow/CreateCredentialComponentsKt$PrimaryCreateOptionRow$2;-><init>(Lcom/android/credentialmanager/createflow/RequestDisplayInfo;)V
+HSPLcom/android/credentialmanager/createflow/CreateCredentialComponentsKt$PrimaryCreateOptionRow$2;->invoke(Landroidx/compose/runtime/Composer;I)V
+HSPLcom/android/credentialmanager/createflow/CreateCredentialComponentsKt$PrimaryCreateOptionRow$2;->invoke(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;
+HSPLcom/android/credentialmanager/createflow/CreateCredentialComponentsKt$PrimaryCreateOptionRow$3;-><init>(Lcom/android/credentialmanager/createflow/EntryInfo;Lcom/android/credentialmanager/createflow/RequestDisplayInfo;)V
+HSPLcom/android/credentialmanager/createflow/CreateCredentialComponentsKt$PrimaryCreateOptionRow$3;->invoke(Landroidx/compose/runtime/Composer;I)V
+HSPLcom/android/credentialmanager/createflow/CreateCredentialComponentsKt$PrimaryCreateOptionRow$3;->invoke(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;
+HSPLcom/android/credentialmanager/createflow/CreateCredentialComponentsKt;->CreateCredentialScreen(Lcom/android/credentialmanager/createflow/CreateCredentialViewModel;Landroidx/activity/compose/ManagedActivityResultLauncher;Landroidx/compose/runtime/Composer;I)V
+HSPLcom/android/credentialmanager/createflow/CreateCredentialComponentsKt;->CreationSelectionCard(Lcom/android/credentialmanager/createflow/RequestDisplayInfo;Ljava/util/List;Lcom/android/credentialmanager/createflow/EnabledProviderInfo;Lcom/android/credentialmanager/createflow/CreateOptionInfo;Lkotlin/jvm/functions/Function1;Lkotlin/jvm/functions/Function0;Lkotlin/jvm/functions/Function0;Landroidx/compose/runtime/Composer;I)V
+HSPLcom/android/credentialmanager/createflow/CreateCredentialComponentsKt;->PrimaryCreateOptionRow(Lcom/android/credentialmanager/createflow/RequestDisplayInfo;Lcom/android/credentialmanager/createflow/EntryInfo;Lkotlin/jvm/functions/Function1;Landroidx/compose/runtime/Composer;I)V
+HSPLcom/android/credentialmanager/createflow/CreateCredentialUiState;-><clinit>()V
+HSPLcom/android/credentialmanager/createflow/CreateCredentialUiState;-><init>(Ljava/util/List;Ljava/util/List;Lcom/android/credentialmanager/createflow/CreateScreenState;Lcom/android/credentialmanager/createflow/RequestDisplayInfo;Ljava/util/List;ZLcom/android/credentialmanager/createflow/ActiveEntry;Lcom/android/credentialmanager/createflow/EntryInfo;ZZLjava/lang/Boolean;)V
+HSPLcom/android/credentialmanager/createflow/CreateCredentialUiState;-><init>(Ljava/util/List;Ljava/util/List;Lcom/android/credentialmanager/createflow/CreateScreenState;Lcom/android/credentialmanager/createflow/RequestDisplayInfo;Ljava/util/List;ZLcom/android/credentialmanager/createflow/ActiveEntry;Lcom/android/credentialmanager/createflow/EntryInfo;ZZLjava/lang/Boolean;ILkotlin/jvm/internal/DefaultConstructorMarker;)V
+HSPLcom/android/credentialmanager/createflow/CreateCredentialUiState;->getActiveEntry()Lcom/android/credentialmanager/createflow/ActiveEntry;
+HSPLcom/android/credentialmanager/createflow/CreateCredentialUiState;->getCurrentScreenState()Lcom/android/credentialmanager/createflow/CreateScreenState;
+HSPLcom/android/credentialmanager/createflow/CreateCredentialUiState;->getEnabledProviders()Ljava/util/List;
+HSPLcom/android/credentialmanager/createflow/CreateCredentialUiState;->getHidden()Z
+HSPLcom/android/credentialmanager/createflow/CreateCredentialUiState;->getRequestDisplayInfo()Lcom/android/credentialmanager/createflow/RequestDisplayInfo;
+HSPLcom/android/credentialmanager/createflow/CreateCredentialViewModel$dialogResult$2;-><clinit>()V
+HSPLcom/android/credentialmanager/createflow/CreateCredentialViewModel$dialogResult$2;-><init>()V
+HSPLcom/android/credentialmanager/createflow/CreateCredentialViewModel$dialogResult$2;->invoke()Landroidx/lifecycle/MutableLiveData;
+HSPLcom/android/credentialmanager/createflow/CreateCredentialViewModel$dialogResult$2;->invoke()Ljava/lang/Object;
+HSPLcom/android/credentialmanager/createflow/CreateCredentialViewModel;-><clinit>()V
+HSPLcom/android/credentialmanager/createflow/CreateCredentialViewModel;-><init>()V
+HSPLcom/android/credentialmanager/createflow/CreateCredentialViewModel;-><init>(Lcom/android/credentialmanager/CredentialManagerRepo;Lcom/android/credentialmanager/UserConfigRepo;)V
+HSPLcom/android/credentialmanager/createflow/CreateCredentialViewModel;-><init>(Lcom/android/credentialmanager/CredentialManagerRepo;Lcom/android/credentialmanager/UserConfigRepo;ILkotlin/jvm/internal/DefaultConstructorMarker;)V
+HSPLcom/android/credentialmanager/createflow/CreateCredentialViewModel;->getDialogResult()Landroidx/lifecycle/MutableLiveData;
+HSPLcom/android/credentialmanager/createflow/CreateCredentialViewModel;->getUiState()Lcom/android/credentialmanager/createflow/CreateCredentialUiState;
+HSPLcom/android/credentialmanager/createflow/CreateCredentialViewModel;->observeDialogResult()Landroidx/lifecycle/LiveData;
+HSPLcom/android/credentialmanager/createflow/CreateOptionInfo;-><clinit>()V
+HSPLcom/android/credentialmanager/createflow/CreateOptionInfo;-><init>(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Landroid/app/PendingIntent;Landroid/content/Intent;Ljava/lang/String;Landroid/graphics/drawable/Drawable;Ljava/lang/Integer;Ljava/lang/Integer;Ljava/lang/Integer;Ljava/lang/Long;)V
+HSPLcom/android/credentialmanager/createflow/CreateOptionInfo;->getLastUsedTimeMillis()Ljava/lang/Long;
+HSPLcom/android/credentialmanager/createflow/CreateOptionInfo;->getProfileIcon()Landroid/graphics/drawable/Drawable;
+HSPLcom/android/credentialmanager/createflow/CreateOptionInfo;->getUserProviderDisplayName()Ljava/lang/String;
+HSPLcom/android/credentialmanager/createflow/CreateScreenState;->$values()[Lcom/android/credentialmanager/createflow/CreateScreenState;
+HSPLcom/android/credentialmanager/createflow/CreateScreenState;-><clinit>()V
+HSPLcom/android/credentialmanager/createflow/CreateScreenState;-><init>(Ljava/lang/String;I)V
+HSPLcom/android/credentialmanager/createflow/CreateScreenState;->values()[Lcom/android/credentialmanager/createflow/CreateScreenState;
+HSPLcom/android/credentialmanager/createflow/DisabledProviderInfo;-><clinit>()V
+HSPLcom/android/credentialmanager/createflow/DisabledProviderInfo;-><init>(Landroid/graphics/drawable/Drawable;Ljava/lang/String;Ljava/lang/String;)V
+HSPLcom/android/credentialmanager/createflow/EnabledProviderInfo;-><clinit>()V
+HSPLcom/android/credentialmanager/createflow/EnabledProviderInfo;-><init>(Landroid/graphics/drawable/Drawable;Ljava/lang/String;Ljava/lang/String;Ljava/util/List;Lcom/android/credentialmanager/createflow/RemoteInfo;)V
+HSPLcom/android/credentialmanager/createflow/EnabledProviderInfo;->getCreateOptions()Ljava/util/List;
+HSPLcom/android/credentialmanager/createflow/EnabledProviderInfo;->getRemoteEntry()Lcom/android/credentialmanager/createflow/RemoteInfo;
+HSPLcom/android/credentialmanager/createflow/EntryInfo;-><clinit>()V
+HSPLcom/android/credentialmanager/createflow/EntryInfo;-><init>(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Landroid/app/PendingIntent;Landroid/content/Intent;)V
+HSPLcom/android/credentialmanager/createflow/ProviderInfo;-><clinit>()V
+HSPLcom/android/credentialmanager/createflow/ProviderInfo;-><init>(Landroid/graphics/drawable/Drawable;Ljava/lang/String;Ljava/lang/String;)V
+HSPLcom/android/credentialmanager/createflow/ProviderInfo;->getDisplayName()Ljava/lang/String;
+HSPLcom/android/credentialmanager/createflow/ProviderInfo;->getIcon()Landroid/graphics/drawable/Drawable;
+HSPLcom/android/credentialmanager/createflow/ProviderInfo;->getId()Ljava/lang/String;
+HSPLcom/android/credentialmanager/createflow/RequestDisplayInfo;-><clinit>()V
+HSPLcom/android/credentialmanager/createflow/RequestDisplayInfo;-><init>(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Landroid/graphics/drawable/Drawable;)V
+HSPLcom/android/credentialmanager/createflow/RequestDisplayInfo;->getAppName()Ljava/lang/String;
+HSPLcom/android/credentialmanager/createflow/RequestDisplayInfo;->getSubtitle()Ljava/lang/String;
+HSPLcom/android/credentialmanager/createflow/RequestDisplayInfo;->getTitle()Ljava/lang/String;
+HSPLcom/android/credentialmanager/createflow/RequestDisplayInfo;->getType()Ljava/lang/String;
+HSPLcom/android/credentialmanager/createflow/RequestDisplayInfo;->getTypeIcon()Landroid/graphics/drawable/Drawable;
+HSPLcom/android/credentialmanager/jetpack/developer/CreateCredentialRequest$Companion;-><init>()V
+HSPLcom/android/credentialmanager/jetpack/developer/CreateCredentialRequest$Companion;-><init>(Lkotlin/jvm/internal/DefaultConstructorMarker;)V
+HSPLcom/android/credentialmanager/jetpack/developer/CreateCredentialRequest$Companion;->createFrom(Ljava/lang/String;Landroid/os/Bundle;Landroid/os/Bundle;Z)Lcom/android/credentialmanager/jetpack/developer/CreateCredentialRequest;
+HSPLcom/android/credentialmanager/jetpack/developer/CreateCredentialRequest;-><clinit>()V
+HSPLcom/android/credentialmanager/jetpack/developer/CreateCredentialRequest;-><init>(Ljava/lang/String;Landroid/os/Bundle;Landroid/os/Bundle;Z)V
+HSPLcom/android/credentialmanager/jetpack/developer/CreateCredentialRequest;->getType()Ljava/lang/String;
+HSPLcom/android/credentialmanager/jetpack/developer/CreatePublicKeyCredentialRequest$Companion;-><init>()V
+HSPLcom/android/credentialmanager/jetpack/developer/CreatePublicKeyCredentialRequest$Companion;-><init>(Lkotlin/jvm/internal/DefaultConstructorMarker;)V
+HSPLcom/android/credentialmanager/jetpack/developer/CreatePublicKeyCredentialRequest$Companion;->createFrom$frameworks__base__packages__CredentialManager__android_common__CredentialManager(Landroid/os/Bundle;)Lcom/android/credentialmanager/jetpack/developer/CreatePublicKeyCredentialRequest;
+HSPLcom/android/credentialmanager/jetpack/developer/CreatePublicKeyCredentialRequest$Companion;->toCredentialDataBundle$frameworks__base__packages__CredentialManager__android_common__CredentialManager(Ljava/lang/String;Z)Landroid/os/Bundle;
+HSPLcom/android/credentialmanager/jetpack/developer/CreatePublicKeyCredentialRequest;-><clinit>()V
+HSPLcom/android/credentialmanager/jetpack/developer/CreatePublicKeyCredentialRequest;-><init>(Ljava/lang/String;Z)V
+HSPLcom/android/credentialmanager/jetpack/developer/CreatePublicKeyCredentialRequest;->getRequestJson()Ljava/lang/String;
+HSPLcom/android/credentialmanager/jetpack/provider/CreateEntry$Companion;-><init>()V
+HSPLcom/android/credentialmanager/jetpack/provider/CreateEntry$Companion;-><init>(Lkotlin/jvm/internal/DefaultConstructorMarker;)V
+HSPLcom/android/credentialmanager/jetpack/provider/CreateEntry$Companion;->fromSlice(Landroid/app/slice/Slice;)Lcom/android/credentialmanager/jetpack/provider/CreateEntry;
+HSPLcom/android/credentialmanager/jetpack/provider/CreateEntry;-><clinit>()V
+HSPLcom/android/credentialmanager/jetpack/provider/CreateEntry;-><init>(Ljava/lang/CharSequence;Landroid/app/PendingIntent;Landroid/graphics/drawable/Icon;JLjava/util/List;)V
+HSPLcom/android/credentialmanager/jetpack/provider/CreateEntry;->getAccountName()Ljava/lang/CharSequence;
+HSPLcom/android/credentialmanager/jetpack/provider/CreateEntry;->getCredentialCountInformationList()Ljava/util/List;
+HSPLcom/android/credentialmanager/jetpack/provider/CreateEntry;->getIcon()Landroid/graphics/drawable/Icon;
+HSPLcom/android/credentialmanager/jetpack/provider/CreateEntry;->getLastUsedTimeMillis()J
+HSPLcom/android/credentialmanager/jetpack/provider/CreateEntry;->getPendingIntent()Landroid/app/PendingIntent;
+HSPLcom/android/credentialmanager/jetpack/provider/CredentialCountInformation$Companion;-><init>()V
+HSPLcom/android/credentialmanager/jetpack/provider/CredentialCountInformation$Companion;-><init>(Lkotlin/jvm/internal/DefaultConstructorMarker;)V
+HSPLcom/android/credentialmanager/jetpack/provider/CredentialCountInformation$Companion;->getCountForType(Ljava/util/List;Ljava/lang/String;)Ljava/lang/Integer;
+HSPLcom/android/credentialmanager/jetpack/provider/CredentialCountInformation$Companion;->getPasskeyCount(Ljava/util/List;)Ljava/lang/Integer;
+HSPLcom/android/credentialmanager/jetpack/provider/CredentialCountInformation$Companion;->getPasswordCount(Ljava/util/List;)Ljava/lang/Integer;
+HSPLcom/android/credentialmanager/jetpack/provider/CredentialCountInformation$Companion;->getTotalCount(Ljava/util/List;)Ljava/lang/Integer;
+HSPLcom/android/credentialmanager/jetpack/provider/CredentialCountInformation;-><clinit>()V
+HSPLcom/android/credentialmanager/ui/theme/AndroidColorScheme;-><clinit>()V
+HSPLcom/android/credentialmanager/ui/theme/AndroidColorScheme;-><init>(Landroid/content/Context;)V
+HSPLcom/android/credentialmanager/ui/theme/AndroidColorScheme;->getColor-WaAFU9c(Landroid/content/Context;I)J
+HSPLcom/android/credentialmanager/ui/theme/AndroidColorScheme;->getColorAccentPrimaryVariant-0d7_KjU()J
+HSPLcom/android/credentialmanager/ui/theme/AndroidColorSchemeKt$LocalAndroidColorScheme$1;-><clinit>()V
+HSPLcom/android/credentialmanager/ui/theme/AndroidColorSchemeKt$LocalAndroidColorScheme$1;-><init>()V
+HSPLcom/android/credentialmanager/ui/theme/AndroidColorSchemeKt;-><clinit>()V
+HSPLcom/android/credentialmanager/ui/theme/AndroidColorSchemeKt;->getLocalAndroidColorScheme()Landroidx/compose/runtime/ProvidableCompositionLocal;
+HSPLcom/android/credentialmanager/ui/theme/ColorKt;-><clinit>()V
+HSPLcom/android/credentialmanager/ui/theme/ColorKt;->getTextColorPrimary()J
+HSPLcom/android/credentialmanager/ui/theme/ColorKt;->getTextColorSecondary()J
+HSPLcom/android/credentialmanager/ui/theme/EntryShape;-><clinit>()V
+HSPLcom/android/credentialmanager/ui/theme/EntryShape;-><init>()V
+HSPLcom/android/credentialmanager/ui/theme/EntryShape;->getFullSmallRoundedCorner()Landroidx/compose/foundation/shape/RoundedCornerShape;
+HSPLcom/android/credentialmanager/ui/theme/EntryShape;->getTopRoundedCorner()Landroidx/compose/foundation/shape/RoundedCornerShape;
+HSPLcom/android/credentialmanager/ui/theme/ShapeKt;-><clinit>()V
+HSPLcom/android/credentialmanager/ui/theme/ShapeKt;->getShapes()Landroidx/compose/material3/Shapes;
+HSPLcom/android/credentialmanager/ui/theme/ThemeKt$CredentialSelectorTheme$1$1;-><init>(Lkotlin/jvm/functions/Function2;I)V
+HSPLcom/android/credentialmanager/ui/theme/ThemeKt$CredentialSelectorTheme$1$1;->invoke(Landroidx/compose/runtime/Composer;I)V
+HSPLcom/android/credentialmanager/ui/theme/ThemeKt$CredentialSelectorTheme$1$1;->invoke(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;
+HSPLcom/android/credentialmanager/ui/theme/ThemeKt$CredentialSelectorTheme$1;-><init>(Lcom/android/credentialmanager/ui/theme/AndroidColorScheme;Lkotlin/jvm/functions/Function2;I)V
+HSPLcom/android/credentialmanager/ui/theme/ThemeKt$CredentialSelectorTheme$1;->invoke(Landroidx/compose/runtime/Composer;I)V
+HSPLcom/android/credentialmanager/ui/theme/ThemeKt$CredentialSelectorTheme$1;->invoke(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;
+HSPLcom/android/credentialmanager/ui/theme/ThemeKt$CredentialSelectorTheme$2;-><init>(ZLkotlin/jvm/functions/Function2;II)V
+HSPLcom/android/credentialmanager/ui/theme/ThemeKt$CredentialSelectorTheme$2;->invoke(Landroidx/compose/runtime/Composer;I)V
+HSPLcom/android/credentialmanager/ui/theme/ThemeKt$CredentialSelectorTheme$2;->invoke(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;
+HSPLcom/android/credentialmanager/ui/theme/ThemeKt;->CredentialSelectorTheme(ZLkotlin/jvm/functions/Function2;Landroidx/compose/runtime/Composer;II)V
+HSPLcom/android/credentialmanager/ui/theme/TypeKt;-><clinit>()V
+HSPLcom/android/credentialmanager/ui/theme/TypeKt;->getTypography()Landroidx/compose/material3/Typography;
+HSPLkotlin/LazyKt;->lazy(Lkotlin/LazyThreadSafetyMode;Lkotlin/jvm/functions/Function0;)Lkotlin/Lazy;
+HSPLkotlin/LazyKt;->lazy(Lkotlin/jvm/functions/Function0;)Lkotlin/Lazy;
+HSPLkotlin/LazyKt__LazyJVMKt$WhenMappings;-><clinit>()V
+HSPLkotlin/LazyKt__LazyJVMKt;->lazy(Lkotlin/LazyThreadSafetyMode;Lkotlin/jvm/functions/Function0;)Lkotlin/Lazy;
+HSPLkotlin/LazyKt__LazyJVMKt;->lazy(Lkotlin/jvm/functions/Function0;)Lkotlin/Lazy;
+HSPLkotlin/LazyThreadSafetyMode;->$values()[Lkotlin/LazyThreadSafetyMode;
+HSPLkotlin/LazyThreadSafetyMode;-><clinit>()V
+HSPLkotlin/LazyThreadSafetyMode;-><init>(Ljava/lang/String;I)V
+HSPLkotlin/LazyThreadSafetyMode;->values()[Lkotlin/LazyThreadSafetyMode;
+HSPLkotlin/Pair;-><init>(Ljava/lang/Object;Ljava/lang/Object;)V
+HSPLkotlin/Pair;->component1()Ljava/lang/Object;
+HSPLkotlin/Pair;->component2()Ljava/lang/Object;
+HSPLkotlin/Pair;->getFirst()Ljava/lang/Object;
+HSPLkotlin/Pair;->getSecond()Ljava/lang/Object;
+HSPLkotlin/Result$Companion;-><init>()V
+HSPLkotlin/Result$Companion;-><init>(Lkotlin/jvm/internal/DefaultConstructorMarker;)V
+HSPLkotlin/Result$Failure;-><init>(Ljava/lang/Throwable;)V
+HSPLkotlin/Result;-><clinit>()V
+HSPLkotlin/Result;->constructor-impl(Ljava/lang/Object;)Ljava/lang/Object;
+HSPLkotlin/Result;->exceptionOrNull-impl(Ljava/lang/Object;)Ljava/lang/Throwable;
+HSPLkotlin/Result;->isFailure-impl(Ljava/lang/Object;)Z
+HSPLkotlin/Result;->isSuccess-impl(Ljava/lang/Object;)Z
+HSPLkotlin/ResultKt;->createFailure(Ljava/lang/Throwable;)Ljava/lang/Object;
+HSPLkotlin/ResultKt;->throwOnFailure(Ljava/lang/Object;)V
+HSPLkotlin/SynchronizedLazyImpl;-><init>(Lkotlin/jvm/functions/Function0;Ljava/lang/Object;)V
+HSPLkotlin/SynchronizedLazyImpl;-><init>(Lkotlin/jvm/functions/Function0;Ljava/lang/Object;ILkotlin/jvm/internal/DefaultConstructorMarker;)V
+HSPLkotlin/SynchronizedLazyImpl;->getValue()Ljava/lang/Object;
+HSPLkotlin/TuplesKt;->to(Ljava/lang/Object;Ljava/lang/Object;)Lkotlin/Pair;
+HSPLkotlin/ULong$Companion;-><init>()V
+HSPLkotlin/ULong$Companion;-><init>(Lkotlin/jvm/internal/DefaultConstructorMarker;)V
+HSPLkotlin/ULong;-><clinit>()V
+HSPLkotlin/ULong;->constructor-impl(J)J
+HSPLkotlin/UNINITIALIZED_VALUE;-><clinit>()V
+HSPLkotlin/UNINITIALIZED_VALUE;-><init>()V
+HSPLkotlin/Unit;-><clinit>()V
+HSPLkotlin/Unit;-><init>()V
+HSPLkotlin/UnsafeLazyImpl;-><init>(Lkotlin/jvm/functions/Function0;)V
+HSPLkotlin/UnsafeLazyImpl;->getValue()Ljava/lang/Object;
+HSPLkotlin/UnsignedKt;->ulongToDouble(J)D
+HSPLkotlin/collections/AbstractCollection;-><init>()V
+HSPLkotlin/collections/AbstractCollection;->isEmpty()Z
+HSPLkotlin/collections/AbstractCollection;->size()I
+HSPLkotlin/collections/AbstractList$Companion;-><init>()V
+HSPLkotlin/collections/AbstractList$Companion;-><init>(Lkotlin/jvm/internal/DefaultConstructorMarker;)V
+HSPLkotlin/collections/AbstractList;-><clinit>()V
+HSPLkotlin/collections/AbstractList;-><init>()V
+HSPLkotlin/collections/AbstractMap$Companion;-><init>()V
+HSPLkotlin/collections/AbstractMap$Companion;-><init>(Lkotlin/jvm/internal/DefaultConstructorMarker;)V
+HSPLkotlin/collections/AbstractMap;-><clinit>()V
+HSPLkotlin/collections/AbstractMap;-><init>()V
+HSPLkotlin/collections/AbstractMap;->containsEntry$kotlin_stdlib(Ljava/util/Map$Entry;)Z
+HSPLkotlin/collections/AbstractMap;->entrySet()Ljava/util/Set;
+HSPLkotlin/collections/AbstractMap;->equals(Ljava/lang/Object;)Z
+HSPLkotlin/collections/AbstractMap;->size()I
+HSPLkotlin/collections/AbstractMutableList;-><init>()V
+HSPLkotlin/collections/AbstractMutableList;->size()I
+HSPLkotlin/collections/AbstractMutableMap;-><init>()V
+HSPLkotlin/collections/AbstractMutableMap;->size()I
+HSPLkotlin/collections/AbstractSet$Companion;-><init>()V
+HSPLkotlin/collections/AbstractSet$Companion;-><init>(Lkotlin/jvm/internal/DefaultConstructorMarker;)V
+HSPLkotlin/collections/AbstractSet$Companion;->setEquals$kotlin_stdlib(Ljava/util/Set;Ljava/util/Set;)Z
+HSPLkotlin/collections/AbstractSet;-><clinit>()V
+HSPLkotlin/collections/AbstractSet;-><init>()V
+HSPLkotlin/collections/AbstractSet;->equals(Ljava/lang/Object;)Z
+HSPLkotlin/collections/ArrayAsCollection;-><init>([Ljava/lang/Object;Z)V
+HSPLkotlin/collections/ArrayAsCollection;->toArray()[Ljava/lang/Object;
+HSPLkotlin/collections/ArrayDeque$Companion;-><init>()V
+HSPLkotlin/collections/ArrayDeque$Companion;-><init>(Lkotlin/jvm/internal/DefaultConstructorMarker;)V
+HSPLkotlin/collections/ArrayDeque$Companion;->newCapacity$kotlin_stdlib(II)I
+HSPLkotlin/collections/ArrayDeque;-><clinit>()V
+HSPLkotlin/collections/ArrayDeque;-><init>()V
+HSPLkotlin/collections/ArrayDeque;->addLast(Ljava/lang/Object;)V
+HSPLkotlin/collections/ArrayDeque;->copyElements(I)V
+HSPLkotlin/collections/ArrayDeque;->ensureCapacity(I)V
+HSPLkotlin/collections/ArrayDeque;->getSize()I
+HSPLkotlin/collections/ArrayDeque;->incremented(I)I
+HSPLkotlin/collections/ArrayDeque;->isEmpty()Z
+HSPLkotlin/collections/ArrayDeque;->positiveMod(I)I
+HSPLkotlin/collections/ArrayDeque;->removeFirst()Ljava/lang/Object;
+HSPLkotlin/collections/ArrayDeque;->removeFirstOrNull()Ljava/lang/Object;
+HSPLkotlin/collections/ArraysKt;->asList([Ljava/lang/Object;)Ljava/util/List;
+HSPLkotlin/collections/ArraysKt;->copyInto$default([F[FIIIILjava/lang/Object;)[F
+HSPLkotlin/collections/ArraysKt;->copyInto$default([I[IIIIILjava/lang/Object;)[I
+HSPLkotlin/collections/ArraysKt;->copyInto$default([Ljava/lang/Object;[Ljava/lang/Object;IIIILjava/lang/Object;)[Ljava/lang/Object;
+HSPLkotlin/collections/ArraysKt;->copyInto([F[FIII)[F
+HSPLkotlin/collections/ArraysKt;->copyInto([I[IIII)[I
+HSPLkotlin/collections/ArraysKt;->copyInto([Ljava/lang/Object;[Ljava/lang/Object;III)[Ljava/lang/Object;
+HSPLkotlin/collections/ArraysKt;->copyOfRange([Ljava/lang/Object;II)[Ljava/lang/Object;
+HSPLkotlin/collections/ArraysKt;->fill$default([Ljava/lang/Object;Ljava/lang/Object;IIILjava/lang/Object;)V
+HSPLkotlin/collections/ArraysKt;->fill([Ljava/lang/Object;Ljava/lang/Object;II)V
+HSPLkotlin/collections/ArraysKt;->getLastIndex([Ljava/lang/Object;)I
+HSPLkotlin/collections/ArraysKt;->sortWith([Ljava/lang/Object;Ljava/util/Comparator;II)V
+HSPLkotlin/collections/ArraysKt;->toList([Ljava/lang/Object;)Ljava/util/List;
+HSPLkotlin/collections/ArraysKt__ArraysJVMKt;->copyOfRangeToIndexCheck(II)V
+HSPLkotlin/collections/ArraysKt___ArraysJvmKt;->asList([Ljava/lang/Object;)Ljava/util/List;
+HSPLkotlin/collections/ArraysKt___ArraysJvmKt;->copyInto$default([F[FIIIILjava/lang/Object;)[F
+HSPLkotlin/collections/ArraysKt___ArraysJvmKt;->copyInto$default([I[IIIIILjava/lang/Object;)[I
+HSPLkotlin/collections/ArraysKt___ArraysJvmKt;->copyInto$default([Ljava/lang/Object;[Ljava/lang/Object;IIIILjava/lang/Object;)[Ljava/lang/Object;
+HSPLkotlin/collections/ArraysKt___ArraysJvmKt;->copyInto([F[FIII)[F
+HSPLkotlin/collections/ArraysKt___ArraysJvmKt;->copyInto([I[IIII)[I
+HSPLkotlin/collections/ArraysKt___ArraysJvmKt;->copyInto([Ljava/lang/Object;[Ljava/lang/Object;III)[Ljava/lang/Object;
+HSPLkotlin/collections/ArraysKt___ArraysJvmKt;->copyOfRange([Ljava/lang/Object;II)[Ljava/lang/Object;
+HSPLkotlin/collections/ArraysKt___ArraysJvmKt;->fill$default([Ljava/lang/Object;Ljava/lang/Object;IIILjava/lang/Object;)V
+HSPLkotlin/collections/ArraysKt___ArraysJvmKt;->fill([Ljava/lang/Object;Ljava/lang/Object;II)V
+HSPLkotlin/collections/ArraysKt___ArraysJvmKt;->sortWith([Ljava/lang/Object;Ljava/util/Comparator;)V
+HSPLkotlin/collections/ArraysKt___ArraysJvmKt;->sortWith([Ljava/lang/Object;Ljava/util/Comparator;II)V
+HSPLkotlin/collections/ArraysKt___ArraysKt;->getLastIndex([Ljava/lang/Object;)I
+HSPLkotlin/collections/ArraysKt___ArraysKt;->toList([Ljava/lang/Object;)Ljava/util/List;
+HSPLkotlin/collections/ArraysKt___ArraysKt;->toMutableList([Ljava/lang/Object;)Ljava/util/List;
+HSPLkotlin/collections/ArraysUtilJVM;->asList([Ljava/lang/Object;)Ljava/util/List;
+HSPLkotlin/collections/CollectionsKt;->addAll(Ljava/util/Collection;Ljava/lang/Iterable;)Z
+HSPLkotlin/collections/CollectionsKt;->collectionSizeOrDefault(Ljava/lang/Iterable;I)I
+HSPLkotlin/collections/CollectionsKt;->distinct(Ljava/lang/Iterable;)Ljava/util/List;
+HSPLkotlin/collections/CollectionsKt;->emptyList()Ljava/util/List;
+HSPLkotlin/collections/CollectionsKt;->first(Ljava/util/List;)Ljava/lang/Object;
+HSPLkotlin/collections/CollectionsKt;->firstOrNull(Ljava/lang/Iterable;)Ljava/lang/Object;
+HSPLkotlin/collections/CollectionsKt;->getLastIndex(Ljava/util/List;)I
+HSPLkotlin/collections/CollectionsKt;->last(Ljava/util/List;)Ljava/lang/Object;
+HSPLkotlin/collections/CollectionsKt;->lastOrNull(Ljava/util/List;)Ljava/lang/Object;
+HSPLkotlin/collections/CollectionsKt;->listOf(Ljava/lang/Object;)Ljava/util/List;
+HSPLkotlin/collections/CollectionsKt;->listOf([Ljava/lang/Object;)Ljava/util/List;
+HSPLkotlin/collections/CollectionsKt;->listOfNotNull(Ljava/lang/Object;)Ljava/util/List;
+HSPLkotlin/collections/CollectionsKt;->maxOrNull(Ljava/lang/Iterable;)Ljava/lang/Float;
+HSPLkotlin/collections/CollectionsKt;->minOrNull(Ljava/lang/Iterable;)Ljava/lang/Float;
+HSPLkotlin/collections/CollectionsKt;->plus(Ljava/util/Collection;Ljava/lang/Iterable;)Ljava/util/List;
+HSPLkotlin/collections/CollectionsKt;->singleOrNull(Ljava/util/List;)Ljava/lang/Object;
+HSPLkotlin/collections/CollectionsKt;->sortWith(Ljava/util/List;Ljava/util/Comparator;)V
+HSPLkotlin/collections/CollectionsKt;->sortedWith(Ljava/lang/Iterable;Ljava/util/Comparator;)Ljava/util/List;
+HSPLkotlin/collections/CollectionsKt;->toList(Ljava/lang/Iterable;)Ljava/util/List;
+HSPLkotlin/collections/CollectionsKt;->toMutableList(Ljava/util/Collection;)Ljava/util/List;
+HSPLkotlin/collections/CollectionsKt__CollectionsJVMKt;->copyToArrayOfAny([Ljava/lang/Object;Z)[Ljava/lang/Object;
+HSPLkotlin/collections/CollectionsKt__CollectionsJVMKt;->listOf(Ljava/lang/Object;)Ljava/util/List;
+HSPLkotlin/collections/CollectionsKt__CollectionsKt;->asCollection([Ljava/lang/Object;)Ljava/util/Collection;
+HSPLkotlin/collections/CollectionsKt__CollectionsKt;->emptyList()Ljava/util/List;
+HSPLkotlin/collections/CollectionsKt__CollectionsKt;->getLastIndex(Ljava/util/List;)I
+HSPLkotlin/collections/CollectionsKt__CollectionsKt;->listOf([Ljava/lang/Object;)Ljava/util/List;
+HSPLkotlin/collections/CollectionsKt__CollectionsKt;->listOfNotNull(Ljava/lang/Object;)Ljava/util/List;
+HSPLkotlin/collections/CollectionsKt__IterablesKt;->collectionSizeOrDefault(Ljava/lang/Iterable;I)I
+HSPLkotlin/collections/CollectionsKt__MutableCollectionsJVMKt;->sortWith(Ljava/util/List;Ljava/util/Comparator;)V
+HSPLkotlin/collections/CollectionsKt__MutableCollectionsKt;->addAll(Ljava/util/Collection;Ljava/lang/Iterable;)Z
+HSPLkotlin/collections/CollectionsKt___CollectionsKt;->distinct(Ljava/lang/Iterable;)Ljava/util/List;
+HSPLkotlin/collections/CollectionsKt___CollectionsKt;->first(Ljava/util/List;)Ljava/lang/Object;
+HSPLkotlin/collections/CollectionsKt___CollectionsKt;->firstOrNull(Ljava/lang/Iterable;)Ljava/lang/Object;
+HSPLkotlin/collections/CollectionsKt___CollectionsKt;->last(Ljava/util/List;)Ljava/lang/Object;
+HSPLkotlin/collections/CollectionsKt___CollectionsKt;->lastOrNull(Ljava/util/List;)Ljava/lang/Object;
+HSPLkotlin/collections/CollectionsKt___CollectionsKt;->maxOrNull(Ljava/lang/Iterable;)Ljava/lang/Float;
+HSPLkotlin/collections/CollectionsKt___CollectionsKt;->minOrNull(Ljava/lang/Iterable;)Ljava/lang/Float;
+HSPLkotlin/collections/CollectionsKt___CollectionsKt;->plus(Ljava/util/Collection;Ljava/lang/Iterable;)Ljava/util/List;
+HSPLkotlin/collections/CollectionsKt___CollectionsKt;->singleOrNull(Ljava/util/List;)Ljava/lang/Object;
+HSPLkotlin/collections/CollectionsKt___CollectionsKt;->sortedWith(Ljava/lang/Iterable;Ljava/util/Comparator;)Ljava/util/List;
+HSPLkotlin/collections/CollectionsKt___CollectionsKt;->toList(Ljava/lang/Iterable;)Ljava/util/List;
+HSPLkotlin/collections/CollectionsKt___CollectionsKt;->toMutableList(Ljava/util/Collection;)Ljava/util/List;
+HSPLkotlin/collections/CollectionsKt___CollectionsKt;->toMutableSet(Ljava/lang/Iterable;)Ljava/util/Set;
+HSPLkotlin/collections/EmptyIterator;-><clinit>()V
+HSPLkotlin/collections/EmptyIterator;-><init>()V
+HSPLkotlin/collections/EmptyIterator;->hasNext()Z
+HSPLkotlin/collections/EmptyList;-><clinit>()V
+HSPLkotlin/collections/EmptyList;-><init>()V
+HSPLkotlin/collections/EmptyList;->contains(Ljava/lang/Object;)Z
+HSPLkotlin/collections/EmptyList;->equals(Ljava/lang/Object;)Z
+HSPLkotlin/collections/EmptyList;->getSize()I
+HSPLkotlin/collections/EmptyList;->isEmpty()Z
+HSPLkotlin/collections/EmptyList;->iterator()Ljava/util/Iterator;
+HSPLkotlin/collections/EmptyList;->listIterator()Ljava/util/ListIterator;
+HSPLkotlin/collections/EmptyList;->size()I
+HSPLkotlin/collections/EmptyList;->toArray()[Ljava/lang/Object;
+HSPLkotlin/collections/EmptyMap;-><clinit>()V
+HSPLkotlin/collections/EmptyMap;-><init>()V
+HSPLkotlin/collections/EmptyMap;->entrySet()Ljava/util/Set;
+HSPLkotlin/collections/EmptyMap;->equals(Ljava/lang/Object;)Z
+HSPLkotlin/collections/EmptyMap;->get(Ljava/lang/Object;)Ljava/lang/Object;
+HSPLkotlin/collections/EmptyMap;->get(Ljava/lang/Object;)Ljava/lang/Void;
+HSPLkotlin/collections/EmptyMap;->getEntries()Ljava/util/Set;
+HSPLkotlin/collections/EmptyMap;->getKeys()Ljava/util/Set;
+HSPLkotlin/collections/EmptyMap;->getValues()Ljava/util/Collection;
+HSPLkotlin/collections/EmptyMap;->isEmpty()Z
+HSPLkotlin/collections/EmptyMap;->keySet()Ljava/util/Set;
+HSPLkotlin/collections/EmptyMap;->values()Ljava/util/Collection;
+HSPLkotlin/collections/EmptySet;-><clinit>()V
+HSPLkotlin/collections/EmptySet;-><init>()V
+HSPLkotlin/collections/EmptySet;->iterator()Ljava/util/Iterator;
+HSPLkotlin/collections/IntIterator;-><init>()V
+HSPLkotlin/collections/MapsKt;->emptyMap()Ljava/util/Map;
+HSPLkotlin/collections/MapsKt;->mapCapacity(I)I
+HSPLkotlin/collections/MapsKt;->mapOf([Lkotlin/Pair;)Ljava/util/Map;
+HSPLkotlin/collections/MapsKt;->toMap(Ljava/lang/Iterable;)Ljava/util/Map;
+HSPLkotlin/collections/MapsKt__MapsJVMKt;->mapCapacity(I)I
+HSPLkotlin/collections/MapsKt__MapsKt;->emptyMap()Ljava/util/Map;
+HSPLkotlin/collections/MapsKt__MapsKt;->mapOf([Lkotlin/Pair;)Ljava/util/Map;
+HSPLkotlin/collections/MapsKt__MapsKt;->putAll(Ljava/util/Map;Ljava/lang/Iterable;)V
+HSPLkotlin/collections/MapsKt__MapsKt;->putAll(Ljava/util/Map;[Lkotlin/Pair;)V
+HSPLkotlin/collections/MapsKt__MapsKt;->toMap(Ljava/lang/Iterable;)Ljava/util/Map;
+HSPLkotlin/collections/MapsKt__MapsKt;->toMap(Ljava/lang/Iterable;Ljava/util/Map;)Ljava/util/Map;
+HSPLkotlin/collections/MapsKt__MapsKt;->toMap([Lkotlin/Pair;Ljava/util/Map;)Ljava/util/Map;
+HSPLkotlin/comparisons/ComparisonsKt;->compareValues(Ljava/lang/Comparable;Ljava/lang/Comparable;)I
+HSPLkotlin/comparisons/ComparisonsKt__ComparisonsKt;->compareValues(Ljava/lang/Comparable;Ljava/lang/Comparable;)I
+HSPLkotlin/coroutines/AbstractCoroutineContextElement;-><init>(Lkotlin/coroutines/CoroutineContext$Key;)V
+HSPLkotlin/coroutines/AbstractCoroutineContextElement;->fold(Ljava/lang/Object;Lkotlin/jvm/functions/Function2;)Ljava/lang/Object;
+HSPLkotlin/coroutines/AbstractCoroutineContextElement;->get(Lkotlin/coroutines/CoroutineContext$Key;)Lkotlin/coroutines/CoroutineContext$Element;
+HSPLkotlin/coroutines/AbstractCoroutineContextElement;->getKey()Lkotlin/coroutines/CoroutineContext$Key;
+HSPLkotlin/coroutines/AbstractCoroutineContextElement;->minusKey(Lkotlin/coroutines/CoroutineContext$Key;)Lkotlin/coroutines/CoroutineContext;
+HSPLkotlin/coroutines/AbstractCoroutineContextElement;->plus(Lkotlin/coroutines/CoroutineContext;)Lkotlin/coroutines/CoroutineContext;
+HSPLkotlin/coroutines/AbstractCoroutineContextKey;-><init>(Lkotlin/coroutines/CoroutineContext$Key;Lkotlin/jvm/functions/Function1;)V
+HSPLkotlin/coroutines/CombinedContext;-><init>(Lkotlin/coroutines/CoroutineContext;Lkotlin/coroutines/CoroutineContext$Element;)V
+HSPLkotlin/coroutines/CombinedContext;->fold(Ljava/lang/Object;Lkotlin/jvm/functions/Function2;)Ljava/lang/Object;
+HSPLkotlin/coroutines/CombinedContext;->get(Lkotlin/coroutines/CoroutineContext$Key;)Lkotlin/coroutines/CoroutineContext$Element;+]Lkotlin/coroutines/CoroutineContext;megamorphic_types]Lkotlin/coroutines/CoroutineContext$Element;megamorphic_types
+HSPLkotlin/coroutines/CombinedContext;->minusKey(Lkotlin/coroutines/CoroutineContext$Key;)Lkotlin/coroutines/CoroutineContext;
+HSPLkotlin/coroutines/CombinedContext;->plus(Lkotlin/coroutines/CoroutineContext;)Lkotlin/coroutines/CoroutineContext;
+HSPLkotlin/coroutines/ContinuationInterceptor$DefaultImpls;->get(Lkotlin/coroutines/ContinuationInterceptor;Lkotlin/coroutines/CoroutineContext$Key;)Lkotlin/coroutines/CoroutineContext$Element;
+HSPLkotlin/coroutines/ContinuationInterceptor$DefaultImpls;->minusKey(Lkotlin/coroutines/ContinuationInterceptor;Lkotlin/coroutines/CoroutineContext$Key;)Lkotlin/coroutines/CoroutineContext;
+HSPLkotlin/coroutines/ContinuationInterceptor$Key;-><clinit>()V
+HSPLkotlin/coroutines/ContinuationInterceptor$Key;-><init>()V
+HSPLkotlin/coroutines/ContinuationInterceptor;-><clinit>()V
+HSPLkotlin/coroutines/ContinuationKt;->createCoroutine(Lkotlin/jvm/functions/Function2;Ljava/lang/Object;Lkotlin/coroutines/Continuation;)Lkotlin/coroutines/Continuation;
+HSPLkotlin/coroutines/ContinuationKt;->startCoroutine(Lkotlin/jvm/functions/Function2;Ljava/lang/Object;Lkotlin/coroutines/Continuation;)V
+HSPLkotlin/coroutines/CoroutineContext$DefaultImpls;->plus(Lkotlin/coroutines/CoroutineContext;Lkotlin/coroutines/CoroutineContext;)Lkotlin/coroutines/CoroutineContext;
+HSPLkotlin/coroutines/CoroutineContext$Element$DefaultImpls;->fold(Lkotlin/coroutines/CoroutineContext$Element;Ljava/lang/Object;Lkotlin/jvm/functions/Function2;)Ljava/lang/Object;
+HSPLkotlin/coroutines/CoroutineContext$Element$DefaultImpls;->get(Lkotlin/coroutines/CoroutineContext$Element;Lkotlin/coroutines/CoroutineContext$Key;)Lkotlin/coroutines/CoroutineContext$Element;
+HSPLkotlin/coroutines/CoroutineContext$Element$DefaultImpls;->minusKey(Lkotlin/coroutines/CoroutineContext$Element;Lkotlin/coroutines/CoroutineContext$Key;)Lkotlin/coroutines/CoroutineContext;
+HSPLkotlin/coroutines/CoroutineContext$Element$DefaultImpls;->plus(Lkotlin/coroutines/CoroutineContext$Element;Lkotlin/coroutines/CoroutineContext;)Lkotlin/coroutines/CoroutineContext;
+HSPLkotlin/coroutines/CoroutineContext$plus$1;-><clinit>()V
+HSPLkotlin/coroutines/CoroutineContext$plus$1;-><init>()V
+HSPLkotlin/coroutines/CoroutineContext$plus$1;->invoke(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;
+HSPLkotlin/coroutines/CoroutineContext$plus$1;->invoke(Lkotlin/coroutines/CoroutineContext;Lkotlin/coroutines/CoroutineContext$Element;)Lkotlin/coroutines/CoroutineContext;
+HSPLkotlin/coroutines/EmptyCoroutineContext;-><clinit>()V
+HSPLkotlin/coroutines/EmptyCoroutineContext;-><init>()V
+HSPLkotlin/coroutines/EmptyCoroutineContext;->fold(Ljava/lang/Object;Lkotlin/jvm/functions/Function2;)Ljava/lang/Object;
+HSPLkotlin/coroutines/EmptyCoroutineContext;->get(Lkotlin/coroutines/CoroutineContext$Key;)Lkotlin/coroutines/CoroutineContext$Element;
+HSPLkotlin/coroutines/EmptyCoroutineContext;->plus(Lkotlin/coroutines/CoroutineContext;)Lkotlin/coroutines/CoroutineContext;
+HSPLkotlin/coroutines/SafeContinuation$Companion;-><init>()V
+HSPLkotlin/coroutines/SafeContinuation$Companion;-><init>(Lkotlin/jvm/internal/DefaultConstructorMarker;)V
+HSPLkotlin/coroutines/SafeContinuation;-><clinit>()V
+HSPLkotlin/coroutines/SafeContinuation;-><init>(Lkotlin/coroutines/Continuation;Ljava/lang/Object;)V
+HSPLkotlin/coroutines/SafeContinuation;->resumeWith(Ljava/lang/Object;)V
+HSPLkotlin/coroutines/intrinsics/CoroutineSingletons;->$values()[Lkotlin/coroutines/intrinsics/CoroutineSingletons;
+HSPLkotlin/coroutines/intrinsics/CoroutineSingletons;-><clinit>()V
+HSPLkotlin/coroutines/intrinsics/CoroutineSingletons;-><init>(Ljava/lang/String;I)V
+HSPLkotlin/coroutines/intrinsics/IntrinsicsKt;->createCoroutineUnintercepted(Lkotlin/jvm/functions/Function2;Ljava/lang/Object;Lkotlin/coroutines/Continuation;)Lkotlin/coroutines/Continuation;
+HSPLkotlin/coroutines/intrinsics/IntrinsicsKt;->getCOROUTINE_SUSPENDED()Ljava/lang/Object;
+HSPLkotlin/coroutines/intrinsics/IntrinsicsKt;->intercepted(Lkotlin/coroutines/Continuation;)Lkotlin/coroutines/Continuation;
+HSPLkotlin/coroutines/intrinsics/IntrinsicsKt__IntrinsicsJvmKt;->createCoroutineUnintercepted(Lkotlin/jvm/functions/Function2;Ljava/lang/Object;Lkotlin/coroutines/Continuation;)Lkotlin/coroutines/Continuation;
+HSPLkotlin/coroutines/intrinsics/IntrinsicsKt__IntrinsicsJvmKt;->intercepted(Lkotlin/coroutines/Continuation;)Lkotlin/coroutines/Continuation;
+HSPLkotlin/coroutines/intrinsics/IntrinsicsKt__IntrinsicsKt;->getCOROUTINE_SUSPENDED()Ljava/lang/Object;
+HSPLkotlin/coroutines/jvm/internal/BaseContinuationImpl;-><init>(Lkotlin/coroutines/Continuation;)V
+HSPLkotlin/coroutines/jvm/internal/BaseContinuationImpl;->releaseIntercepted()V
+HSPLkotlin/coroutines/jvm/internal/BaseContinuationImpl;->resumeWith(Ljava/lang/Object;)V
+HSPLkotlin/coroutines/jvm/internal/Boxing;->boxBoolean(Z)Ljava/lang/Boolean;
+HSPLkotlin/coroutines/jvm/internal/CompletedContinuation;-><clinit>()V
+HSPLkotlin/coroutines/jvm/internal/CompletedContinuation;-><init>()V
+HSPLkotlin/coroutines/jvm/internal/ContinuationImpl;-><init>(Lkotlin/coroutines/Continuation;)V
+HSPLkotlin/coroutines/jvm/internal/ContinuationImpl;-><init>(Lkotlin/coroutines/Continuation;Lkotlin/coroutines/CoroutineContext;)V
+HSPLkotlin/coroutines/jvm/internal/ContinuationImpl;->getContext()Lkotlin/coroutines/CoroutineContext;
+HSPLkotlin/coroutines/jvm/internal/ContinuationImpl;->intercepted()Lkotlin/coroutines/Continuation;
+HSPLkotlin/coroutines/jvm/internal/ContinuationImpl;->releaseIntercepted()V
+HSPLkotlin/coroutines/jvm/internal/DebugProbesKt;->probeCoroutineCreated(Lkotlin/coroutines/Continuation;)Lkotlin/coroutines/Continuation;
+HSPLkotlin/coroutines/jvm/internal/DebugProbesKt;->probeCoroutineResumed(Lkotlin/coroutines/Continuation;)V
+HSPLkotlin/coroutines/jvm/internal/DebugProbesKt;->probeCoroutineSuspended(Lkotlin/coroutines/Continuation;)V
+HSPLkotlin/coroutines/jvm/internal/RestrictedContinuationImpl;-><init>(Lkotlin/coroutines/Continuation;)V
+HSPLkotlin/coroutines/jvm/internal/RestrictedContinuationImpl;->getContext()Lkotlin/coroutines/CoroutineContext;
+HSPLkotlin/coroutines/jvm/internal/RestrictedSuspendLambda;-><init>(ILkotlin/coroutines/Continuation;)V
+HSPLkotlin/coroutines/jvm/internal/SuspendLambda;-><init>(ILkotlin/coroutines/Continuation;)V
+HSPLkotlin/coroutines/jvm/internal/SuspendLambda;->getArity()I
+HSPLkotlin/internal/ProgressionUtilKt;->differenceModulo(III)I
+HSPLkotlin/internal/ProgressionUtilKt;->getProgressionLastElement(III)I
+HSPLkotlin/internal/ProgressionUtilKt;->mod(II)I
+HSPLkotlin/jvm/JvmClassMappingKt;->getJavaClass(Lkotlin/reflect/KClass;)Ljava/lang/Class;
+HSPLkotlin/jvm/JvmClassMappingKt;->getJavaObjectType(Lkotlin/reflect/KClass;)Ljava/lang/Class;
+HSPLkotlin/jvm/internal/CallableReference$NoReceiver;-><clinit>()V
+HSPLkotlin/jvm/internal/CallableReference$NoReceiver;-><init>()V
+HSPLkotlin/jvm/internal/CallableReference$NoReceiver;->access$000()Lkotlin/jvm/internal/CallableReference$NoReceiver;
+HSPLkotlin/jvm/internal/CallableReference;-><clinit>()V
+HSPLkotlin/jvm/internal/CallableReference;-><init>(Ljava/lang/Object;Ljava/lang/Class;Ljava/lang/String;Ljava/lang/String;Z)V
+HSPLkotlin/jvm/internal/CallableReference;->getBoundReceiver()Ljava/lang/Object;
+HSPLkotlin/jvm/internal/CallableReference;->getName()Ljava/lang/String;
+HSPLkotlin/jvm/internal/CallableReference;->getOwner()Lkotlin/reflect/KDeclarationContainer;
+HSPLkotlin/jvm/internal/CallableReference;->getSignature()Ljava/lang/String;
+HSPLkotlin/jvm/internal/ClassReference$Companion;-><init>()V
+HSPLkotlin/jvm/internal/ClassReference$Companion;-><init>(Lkotlin/jvm/internal/DefaultConstructorMarker;)V
+HSPLkotlin/jvm/internal/ClassReference;-><clinit>()V
+HSPLkotlin/jvm/internal/ClassReference;-><init>(Ljava/lang/Class;)V
+HSPLkotlin/jvm/internal/ClassReference;->equals(Ljava/lang/Object;)Z
+HSPLkotlin/jvm/internal/ClassReference;->getJClass()Ljava/lang/Class;
+HSPLkotlin/jvm/internal/CollectionToArray;-><clinit>()V
+HSPLkotlin/jvm/internal/CollectionToArray;->toArray(Ljava/util/Collection;)[Ljava/lang/Object;
+HSPLkotlin/jvm/internal/FloatCompanionObject;-><clinit>()V
+HSPLkotlin/jvm/internal/FloatCompanionObject;-><init>()V
+HSPLkotlin/jvm/internal/FunctionReference;-><init>(ILjava/lang/Object;Ljava/lang/Class;Ljava/lang/String;Ljava/lang/String;I)V
+HSPLkotlin/jvm/internal/FunctionReference;->equals(Ljava/lang/Object;)Z
+HSPLkotlin/jvm/internal/FunctionReferenceImpl;-><init>(ILjava/lang/Class;Ljava/lang/String;Ljava/lang/String;I)V
+HSPLkotlin/jvm/internal/FunctionReferenceImpl;-><init>(ILjava/lang/Object;Ljava/lang/Class;Ljava/lang/String;Ljava/lang/String;I)V
+HSPLkotlin/jvm/internal/InlineMarker;->mark(I)V
+HSPLkotlin/jvm/internal/IntCompanionObject;-><clinit>()V
+HSPLkotlin/jvm/internal/IntCompanionObject;-><init>()V
+HSPLkotlin/jvm/internal/Intrinsics;->areEqual(Ljava/lang/Float;Ljava/lang/Float;)Z
+HSPLkotlin/jvm/internal/Intrinsics;->areEqual(Ljava/lang/Object;Ljava/lang/Object;)Z+]Ljava/lang/Object;megamorphic_types
+HSPLkotlin/jvm/internal/Intrinsics;->checkNotNull(Ljava/lang/Object;)V
+HSPLkotlin/jvm/internal/Intrinsics;->checkNotNull(Ljava/lang/Object;Ljava/lang/String;)V
+HSPLkotlin/jvm/internal/Intrinsics;->checkNotNullExpressionValue(Ljava/lang/Object;Ljava/lang/String;)V
+HSPLkotlin/jvm/internal/Intrinsics;->checkNotNullParameter(Ljava/lang/Object;Ljava/lang/String;)V
+HSPLkotlin/jvm/internal/Intrinsics;->compare(II)I
+HSPLkotlin/jvm/internal/Lambda;-><init>(I)V
+HSPLkotlin/jvm/internal/Lambda;->getArity()I
+HSPLkotlin/jvm/internal/MutablePropertyReference1;-><init>(Ljava/lang/Object;Ljava/lang/Class;Ljava/lang/String;Ljava/lang/String;I)V
+HSPLkotlin/jvm/internal/MutablePropertyReference1Impl;-><init>(Ljava/lang/Class;Ljava/lang/String;Ljava/lang/String;I)V
+HSPLkotlin/jvm/internal/MutablePropertyReference;-><init>(Ljava/lang/Object;Ljava/lang/Class;Ljava/lang/String;Ljava/lang/String;I)V
+HSPLkotlin/jvm/internal/PropertyReference;-><init>(Ljava/lang/Object;Ljava/lang/Class;Ljava/lang/String;Ljava/lang/String;I)V
+HSPLkotlin/jvm/internal/Ref$BooleanRef;-><init>()V
+HSPLkotlin/jvm/internal/Ref$IntRef;-><init>()V
+HSPLkotlin/jvm/internal/Ref$ObjectRef;-><init>()V
+HSPLkotlin/jvm/internal/Reflection;-><clinit>()V
+HSPLkotlin/jvm/internal/Reflection;->getOrCreateKotlinClass(Ljava/lang/Class;)Lkotlin/reflect/KClass;
+HSPLkotlin/jvm/internal/Reflection;->mutableProperty1(Lkotlin/jvm/internal/MutablePropertyReference1;)Lkotlin/reflect/KMutableProperty1;
+HSPLkotlin/jvm/internal/ReflectionFactory;-><init>()V
+HSPLkotlin/jvm/internal/ReflectionFactory;->getOrCreateKotlinClass(Ljava/lang/Class;)Lkotlin/reflect/KClass;
+HSPLkotlin/jvm/internal/ReflectionFactory;->mutableProperty1(Lkotlin/jvm/internal/MutablePropertyReference1;)Lkotlin/reflect/KMutableProperty1;
+HSPLkotlin/jvm/internal/SpreadBuilder;-><init>(I)V
+HSPLkotlin/jvm/internal/SpreadBuilder;->add(Ljava/lang/Object;)V
+HSPLkotlin/jvm/internal/SpreadBuilder;->addSpread(Ljava/lang/Object;)V
+HSPLkotlin/jvm/internal/SpreadBuilder;->size()I
+HSPLkotlin/jvm/internal/SpreadBuilder;->toArray([Ljava/lang/Object;)[Ljava/lang/Object;
+HSPLkotlin/jvm/internal/TypeIntrinsics;->beforeCheckcastToFunctionOfArity(Ljava/lang/Object;I)Ljava/lang/Object;
+HSPLkotlin/jvm/internal/TypeIntrinsics;->getFunctionArity(Ljava/lang/Object;)I
+HSPLkotlin/jvm/internal/TypeIntrinsics;->isFunctionOfArity(Ljava/lang/Object;I)Z
+HSPLkotlin/jvm/internal/TypeIntrinsics;->isMutableSet(Ljava/lang/Object;)Z
+HSPLkotlin/math/MathKt;->roundToInt(F)I
+HSPLkotlin/math/MathKt__MathJVMKt;->roundToInt(F)I
+HSPLkotlin/ranges/IntProgression$Companion;-><init>()V
+HSPLkotlin/ranges/IntProgression$Companion;-><init>(Lkotlin/jvm/internal/DefaultConstructorMarker;)V
+HSPLkotlin/ranges/IntProgression;-><clinit>()V
+HSPLkotlin/ranges/IntProgression;-><init>(III)V
+HSPLkotlin/ranges/IntProgression;->getFirst()I
+HSPLkotlin/ranges/IntProgression;->getLast()I
+HSPLkotlin/ranges/IntProgression;->iterator()Ljava/util/Iterator;
+HSPLkotlin/ranges/IntProgression;->iterator()Lkotlin/collections/IntIterator;
+HSPLkotlin/ranges/IntProgressionIterator;-><init>(III)V
+HSPLkotlin/ranges/IntProgressionIterator;->hasNext()Z
+HSPLkotlin/ranges/IntProgressionIterator;->nextInt()I
+HSPLkotlin/ranges/IntRange$Companion;-><init>()V
+HSPLkotlin/ranges/IntRange$Companion;-><init>(Lkotlin/jvm/internal/DefaultConstructorMarker;)V
+HSPLkotlin/ranges/IntRange;-><clinit>()V
+HSPLkotlin/ranges/IntRange;-><init>(II)V
+HSPLkotlin/ranges/IntRange;->contains(I)Z
+HSPLkotlin/ranges/RangesKt;->coerceAtLeast(II)I
+HSPLkotlin/ranges/RangesKt;->coerceAtLeast(Ljava/lang/Comparable;Ljava/lang/Comparable;)Ljava/lang/Comparable;
+HSPLkotlin/ranges/RangesKt;->coerceAtMost(II)I
+HSPLkotlin/ranges/RangesKt;->coerceIn(FFF)F
+HSPLkotlin/ranges/RangesKt;->coerceIn(III)I
+HSPLkotlin/ranges/RangesKt;->coerceIn(JJJ)J
+HSPLkotlin/ranges/RangesKt___RangesKt;->coerceAtLeast(II)I
+HSPLkotlin/ranges/RangesKt___RangesKt;->coerceAtLeast(Ljava/lang/Comparable;Ljava/lang/Comparable;)Ljava/lang/Comparable;
+HSPLkotlin/ranges/RangesKt___RangesKt;->coerceAtMost(II)I
+HSPLkotlin/ranges/RangesKt___RangesKt;->coerceIn(FFF)F
+HSPLkotlin/ranges/RangesKt___RangesKt;->coerceIn(III)I
+HSPLkotlin/ranges/RangesKt___RangesKt;->coerceIn(JJJ)J
+HSPLkotlin/sequences/FilteringSequence$iterator$1;-><init>(Lkotlin/sequences/FilteringSequence;)V
+HSPLkotlin/sequences/FilteringSequence$iterator$1;->calcNext()V
+HSPLkotlin/sequences/FilteringSequence$iterator$1;->hasNext()Z
+HSPLkotlin/sequences/FilteringSequence$iterator$1;->next()Ljava/lang/Object;
+HSPLkotlin/sequences/FilteringSequence;-><init>(Lkotlin/sequences/Sequence;ZLkotlin/jvm/functions/Function1;)V
+HSPLkotlin/sequences/FilteringSequence;->access$getPredicate$p(Lkotlin/sequences/FilteringSequence;)Lkotlin/jvm/functions/Function1;
+HSPLkotlin/sequences/FilteringSequence;->access$getSendWhen$p(Lkotlin/sequences/FilteringSequence;)Z
+HSPLkotlin/sequences/FilteringSequence;->access$getSequence$p(Lkotlin/sequences/FilteringSequence;)Lkotlin/sequences/Sequence;
+HSPLkotlin/sequences/FilteringSequence;->iterator()Ljava/util/Iterator;
+HSPLkotlin/sequences/GeneratorSequence$iterator$1;-><init>(Lkotlin/sequences/GeneratorSequence;)V
+HSPLkotlin/sequences/GeneratorSequence$iterator$1;->calcNext()V
+HSPLkotlin/sequences/GeneratorSequence$iterator$1;->hasNext()Z
+HSPLkotlin/sequences/GeneratorSequence$iterator$1;->next()Ljava/lang/Object;
+HSPLkotlin/sequences/GeneratorSequence;-><init>(Lkotlin/jvm/functions/Function0;Lkotlin/jvm/functions/Function1;)V
+HSPLkotlin/sequences/GeneratorSequence;->access$getGetInitialValue$p(Lkotlin/sequences/GeneratorSequence;)Lkotlin/jvm/functions/Function0;
+HSPLkotlin/sequences/GeneratorSequence;->access$getGetNextValue$p(Lkotlin/sequences/GeneratorSequence;)Lkotlin/jvm/functions/Function1;
+HSPLkotlin/sequences/GeneratorSequence;->iterator()Ljava/util/Iterator;
+HSPLkotlin/sequences/SequencesKt;->firstOrNull(Lkotlin/sequences/Sequence;)Ljava/lang/Object;
+HSPLkotlin/sequences/SequencesKt;->generateSequence(Ljava/lang/Object;Lkotlin/jvm/functions/Function1;)Lkotlin/sequences/Sequence;
+HSPLkotlin/sequences/SequencesKt;->mapNotNull(Lkotlin/sequences/Sequence;Lkotlin/jvm/functions/Function1;)Lkotlin/sequences/Sequence;
+HSPLkotlin/sequences/SequencesKt__SequencesKt$generateSequence$2;-><init>(Ljava/lang/Object;)V
+HSPLkotlin/sequences/SequencesKt__SequencesKt$generateSequence$2;->invoke()Ljava/lang/Object;
+HSPLkotlin/sequences/SequencesKt__SequencesKt;->generateSequence(Ljava/lang/Object;Lkotlin/jvm/functions/Function1;)Lkotlin/sequences/Sequence;
+HSPLkotlin/sequences/SequencesKt___SequencesKt$filterNotNull$1;-><clinit>()V
+HSPLkotlin/sequences/SequencesKt___SequencesKt$filterNotNull$1;-><init>()V
+HSPLkotlin/sequences/SequencesKt___SequencesKt$filterNotNull$1;->invoke(Ljava/lang/Object;)Ljava/lang/Boolean;
+HSPLkotlin/sequences/SequencesKt___SequencesKt$filterNotNull$1;->invoke(Ljava/lang/Object;)Ljava/lang/Object;
+HSPLkotlin/sequences/SequencesKt___SequencesKt;->filterNot(Lkotlin/sequences/Sequence;Lkotlin/jvm/functions/Function1;)Lkotlin/sequences/Sequence;
+HSPLkotlin/sequences/SequencesKt___SequencesKt;->filterNotNull(Lkotlin/sequences/Sequence;)Lkotlin/sequences/Sequence;
+HSPLkotlin/sequences/SequencesKt___SequencesKt;->firstOrNull(Lkotlin/sequences/Sequence;)Ljava/lang/Object;
+HSPLkotlin/sequences/SequencesKt___SequencesKt;->mapNotNull(Lkotlin/sequences/Sequence;Lkotlin/jvm/functions/Function1;)Lkotlin/sequences/Sequence;
+HSPLkotlin/sequences/TransformingSequence$iterator$1;-><init>(Lkotlin/sequences/TransformingSequence;)V
+HSPLkotlin/sequences/TransformingSequence$iterator$1;->hasNext()Z
+HSPLkotlin/sequences/TransformingSequence$iterator$1;->next()Ljava/lang/Object;
+HSPLkotlin/sequences/TransformingSequence;-><init>(Lkotlin/sequences/Sequence;Lkotlin/jvm/functions/Function1;)V
+HSPLkotlin/sequences/TransformingSequence;->access$getSequence$p(Lkotlin/sequences/TransformingSequence;)Lkotlin/sequences/Sequence;
+HSPLkotlin/sequences/TransformingSequence;->access$getTransformer$p(Lkotlin/sequences/TransformingSequence;)Lkotlin/jvm/functions/Function1;
+HSPLkotlin/sequences/TransformingSequence;->iterator()Ljava/util/Iterator;
+HSPLkotlin/text/CharsKt;->checkRadix(I)I
+HSPLkotlin/text/CharsKt__CharJVMKt;->checkRadix(I)I
+HSPLkotlin/text/CharsKt__CharJVMKt;->isWhitespace(C)Z
+HSPLkotlin/text/StringsKt;->isBlank(Ljava/lang/CharSequence;)Z
+HSPLkotlin/text/StringsKt;->substringAfterLast$default(Ljava/lang/String;CLjava/lang/String;ILjava/lang/Object;)Ljava/lang/String;
+HSPLkotlin/text/StringsKt__StringsJVMKt;->isBlank(Ljava/lang/CharSequence;)Z
+HSPLkotlin/text/StringsKt__StringsKt;->getIndices(Ljava/lang/CharSequence;)Lkotlin/ranges/IntRange;
+HSPLkotlin/text/StringsKt__StringsKt;->getLastIndex(Ljava/lang/CharSequence;)I
+HSPLkotlin/text/StringsKt__StringsKt;->lastIndexOf$default(Ljava/lang/CharSequence;CIZILjava/lang/Object;)I
+HSPLkotlin/text/StringsKt__StringsKt;->lastIndexOf(Ljava/lang/CharSequence;CIZ)I
+HSPLkotlin/text/StringsKt__StringsKt;->substringAfterLast$default(Ljava/lang/String;CLjava/lang/String;ILjava/lang/Object;)Ljava/lang/String;
+HSPLkotlin/text/StringsKt__StringsKt;->substringAfterLast(Ljava/lang/String;CLjava/lang/String;)Ljava/lang/String;
+HSPLkotlinx/atomicfu/AtomicArray;-><init>(I)V
+HSPLkotlinx/atomicfu/AtomicBoolean$Companion;-><init>()V
+HSPLkotlinx/atomicfu/AtomicBoolean$Companion;-><init>(Lkotlin/jvm/internal/DefaultConstructorMarker;)V
+HSPLkotlinx/atomicfu/AtomicBoolean;-><clinit>()V
+HSPLkotlinx/atomicfu/AtomicBoolean;-><init>(ZLkotlinx/atomicfu/TraceBase;)V
+HSPLkotlinx/atomicfu/AtomicBoolean;->compareAndSet(ZZ)Z
+HSPLkotlinx/atomicfu/AtomicBoolean;->getValue()Z
+HSPLkotlinx/atomicfu/AtomicBoolean;->setValue(Z)V
+HSPLkotlinx/atomicfu/AtomicFU;->atomic(I)Lkotlinx/atomicfu/AtomicInt;
+HSPLkotlinx/atomicfu/AtomicFU;->atomic(ILkotlinx/atomicfu/TraceBase;)Lkotlinx/atomicfu/AtomicInt;
+HSPLkotlinx/atomicfu/AtomicFU;->atomic(J)Lkotlinx/atomicfu/AtomicLong;
+HSPLkotlinx/atomicfu/AtomicFU;->atomic(JLkotlinx/atomicfu/TraceBase;)Lkotlinx/atomicfu/AtomicLong;
+HSPLkotlinx/atomicfu/AtomicFU;->atomic(Ljava/lang/Object;)Lkotlinx/atomicfu/AtomicRef;
+HSPLkotlinx/atomicfu/AtomicFU;->atomic(Ljava/lang/Object;Lkotlinx/atomicfu/TraceBase;)Lkotlinx/atomicfu/AtomicRef;
+HSPLkotlinx/atomicfu/AtomicFU;->atomic(Z)Lkotlinx/atomicfu/AtomicBoolean;
+HSPLkotlinx/atomicfu/AtomicFU;->atomic(ZLkotlinx/atomicfu/TraceBase;)Lkotlinx/atomicfu/AtomicBoolean;
+HSPLkotlinx/atomicfu/AtomicFU_commonKt;->atomicArrayOfNulls(I)Lkotlinx/atomicfu/AtomicArray;
+HSPLkotlinx/atomicfu/AtomicInt$Companion;-><init>()V
+HSPLkotlinx/atomicfu/AtomicInt$Companion;-><init>(Lkotlin/jvm/internal/DefaultConstructorMarker;)V
+HSPLkotlinx/atomicfu/AtomicInt;-><clinit>()V
+HSPLkotlinx/atomicfu/AtomicInt;-><init>(ILkotlinx/atomicfu/TraceBase;)V
+HSPLkotlinx/atomicfu/AtomicInt;->compareAndSet(II)Z
+HSPLkotlinx/atomicfu/AtomicInt;->getValue()I
+HSPLkotlinx/atomicfu/AtomicInt;->setValue(I)V
+HSPLkotlinx/atomicfu/AtomicLong$Companion;-><init>()V
+HSPLkotlinx/atomicfu/AtomicLong$Companion;-><init>(Lkotlin/jvm/internal/DefaultConstructorMarker;)V
+HSPLkotlinx/atomicfu/AtomicLong;-><clinit>()V
+HSPLkotlinx/atomicfu/AtomicLong;-><init>(JLkotlinx/atomicfu/TraceBase;)V
+HSPLkotlinx/atomicfu/AtomicRef$Companion;-><init>()V
+HSPLkotlinx/atomicfu/AtomicRef$Companion;-><init>(Lkotlin/jvm/internal/DefaultConstructorMarker;)V
+HSPLkotlinx/atomicfu/AtomicRef;-><clinit>()V
+HSPLkotlinx/atomicfu/AtomicRef;-><init>(Ljava/lang/Object;Lkotlinx/atomicfu/TraceBase;)V
+HSPLkotlinx/atomicfu/AtomicRef;->compareAndSet(Ljava/lang/Object;Ljava/lang/Object;)Z
+HSPLkotlinx/atomicfu/AtomicRef;->getAndSet(Ljava/lang/Object;)Ljava/lang/Object;
+HSPLkotlinx/atomicfu/AtomicRef;->getValue()Ljava/lang/Object;
+HSPLkotlinx/atomicfu/AtomicRef;->lazySet(Ljava/lang/Object;)V
+HSPLkotlinx/atomicfu/AtomicRef;->setValue(Ljava/lang/Object;)V
+HSPLkotlinx/atomicfu/TraceBase$None;-><clinit>()V
+HSPLkotlinx/atomicfu/TraceBase$None;-><init>()V
+HSPLkotlinx/atomicfu/TraceBase;-><init>()V
+HSPLkotlinx/coroutines/AbstractCoroutine;-><init>(Lkotlin/coroutines/CoroutineContext;ZZ)V
+HSPLkotlinx/coroutines/AbstractCoroutine;->afterResume(Ljava/lang/Object;)V
+HSPLkotlinx/coroutines/AbstractCoroutine;->cancellationExceptionMessage()Ljava/lang/String;
+HSPLkotlinx/coroutines/AbstractCoroutine;->getContext()Lkotlin/coroutines/CoroutineContext;
+HSPLkotlinx/coroutines/AbstractCoroutine;->getCoroutineContext()Lkotlin/coroutines/CoroutineContext;
+HSPLkotlinx/coroutines/AbstractCoroutine;->isActive()Z
+HSPLkotlinx/coroutines/AbstractCoroutine;->onCancelled(Ljava/lang/Throwable;Z)V
+HSPLkotlinx/coroutines/AbstractCoroutine;->onCompleted(Ljava/lang/Object;)V
+HSPLkotlinx/coroutines/AbstractCoroutine;->onCompletionInternal(Ljava/lang/Object;)V
+HSPLkotlinx/coroutines/AbstractCoroutine;->resumeWith(Ljava/lang/Object;)V
+HSPLkotlinx/coroutines/AbstractCoroutine;->start(Lkotlinx/coroutines/CoroutineStart;Ljava/lang/Object;Lkotlin/jvm/functions/Function2;)V
+HSPLkotlinx/coroutines/Active;-><clinit>()V
+HSPLkotlinx/coroutines/Active;-><init>()V
+HSPLkotlinx/coroutines/BeforeResumeCancelHandler;-><init>()V
+HSPLkotlinx/coroutines/BlockingEventLoop;-><init>(Ljava/lang/Thread;)V
+HSPLkotlinx/coroutines/BuildersKt;->launch$default(Lkotlinx/coroutines/CoroutineScope;Lkotlin/coroutines/CoroutineContext;Lkotlinx/coroutines/CoroutineStart;Lkotlin/jvm/functions/Function2;ILjava/lang/Object;)Lkotlinx/coroutines/Job;
+HSPLkotlinx/coroutines/BuildersKt;->launch(Lkotlinx/coroutines/CoroutineScope;Lkotlin/coroutines/CoroutineContext;Lkotlinx/coroutines/CoroutineStart;Lkotlin/jvm/functions/Function2;)Lkotlinx/coroutines/Job;
+HSPLkotlinx/coroutines/BuildersKt;->withContext(Lkotlin/coroutines/CoroutineContext;Lkotlin/jvm/functions/Function2;Lkotlin/coroutines/Continuation;)Ljava/lang/Object;
+HSPLkotlinx/coroutines/BuildersKt__Builders_commonKt;->launch$default(Lkotlinx/coroutines/CoroutineScope;Lkotlin/coroutines/CoroutineContext;Lkotlinx/coroutines/CoroutineStart;Lkotlin/jvm/functions/Function2;ILjava/lang/Object;)Lkotlinx/coroutines/Job;
+HSPLkotlinx/coroutines/BuildersKt__Builders_commonKt;->launch(Lkotlinx/coroutines/CoroutineScope;Lkotlin/coroutines/CoroutineContext;Lkotlinx/coroutines/CoroutineStart;Lkotlin/jvm/functions/Function2;)Lkotlinx/coroutines/Job;
+HSPLkotlinx/coroutines/BuildersKt__Builders_commonKt;->withContext(Lkotlin/coroutines/CoroutineContext;Lkotlin/jvm/functions/Function2;Lkotlin/coroutines/Continuation;)Ljava/lang/Object;
+HSPLkotlinx/coroutines/CancelHandler;-><init>()V
+HSPLkotlinx/coroutines/CancelHandlerBase;-><init>()V
+HSPLkotlinx/coroutines/CancellableContinuationImpl;-><init>(Lkotlin/coroutines/Continuation;I)V
+HSPLkotlinx/coroutines/CancellableContinuationImpl;->callCancelHandler(Lkotlinx/coroutines/CancelHandler;Ljava/lang/Throwable;)V
+HSPLkotlinx/coroutines/CancellableContinuationImpl;->cancel(Ljava/lang/Throwable;)Z
+HSPLkotlinx/coroutines/CancellableContinuationImpl;->cancelLater(Ljava/lang/Throwable;)Z
+HSPLkotlinx/coroutines/CancellableContinuationImpl;->completeResume(Ljava/lang/Object;)V
+HSPLkotlinx/coroutines/CancellableContinuationImpl;->detachChild$external__kotlinx_coroutines__android_common__kotlinx_coroutines()V
+HSPLkotlinx/coroutines/CancellableContinuationImpl;->detachChildIfNonResuable()V
+HSPLkotlinx/coroutines/CancellableContinuationImpl;->dispatchResume(I)V
+HSPLkotlinx/coroutines/CancellableContinuationImpl;->getContext()Lkotlin/coroutines/CoroutineContext;
+HSPLkotlinx/coroutines/CancellableContinuationImpl;->getContinuationCancellationCause(Lkotlinx/coroutines/Job;)Ljava/lang/Throwable;
+HSPLkotlinx/coroutines/CancellableContinuationImpl;->getDelegate$external__kotlinx_coroutines__android_common__kotlinx_coroutines()Lkotlin/coroutines/Continuation;
+HSPLkotlinx/coroutines/CancellableContinuationImpl;->getExceptionalResult$external__kotlinx_coroutines__android_common__kotlinx_coroutines(Ljava/lang/Object;)Ljava/lang/Throwable;
+HSPLkotlinx/coroutines/CancellableContinuationImpl;->getResult()Ljava/lang/Object;
+HSPLkotlinx/coroutines/CancellableContinuationImpl;->getState$external__kotlinx_coroutines__android_common__kotlinx_coroutines()Ljava/lang/Object;
+HSPLkotlinx/coroutines/CancellableContinuationImpl;->getSuccessfulResult$external__kotlinx_coroutines__android_common__kotlinx_coroutines(Ljava/lang/Object;)Ljava/lang/Object;
+HSPLkotlinx/coroutines/CancellableContinuationImpl;->initCancellability()V
+HSPLkotlinx/coroutines/CancellableContinuationImpl;->installParentHandle()Lkotlinx/coroutines/DisposableHandle;
+HSPLkotlinx/coroutines/CancellableContinuationImpl;->invokeOnCancellation(Lkotlin/jvm/functions/Function1;)V
+HSPLkotlinx/coroutines/CancellableContinuationImpl;->isCompleted()Z
+HSPLkotlinx/coroutines/CancellableContinuationImpl;->isReusable()Z
+HSPLkotlinx/coroutines/CancellableContinuationImpl;->makeCancelHandler(Lkotlin/jvm/functions/Function1;)Lkotlinx/coroutines/CancelHandler;
+HSPLkotlinx/coroutines/CancellableContinuationImpl;->parentCancelled$external__kotlinx_coroutines__android_common__kotlinx_coroutines(Ljava/lang/Throwable;)V
+HSPLkotlinx/coroutines/CancellableContinuationImpl;->releaseClaimedReusableContinuation()V
+HSPLkotlinx/coroutines/CancellableContinuationImpl;->resetStateReusable()Z
+HSPLkotlinx/coroutines/CancellableContinuationImpl;->resumeImpl$default(Lkotlinx/coroutines/CancellableContinuationImpl;Ljava/lang/Object;ILkotlin/jvm/functions/Function1;ILjava/lang/Object;)V
+HSPLkotlinx/coroutines/CancellableContinuationImpl;->resumeImpl(Ljava/lang/Object;ILkotlin/jvm/functions/Function1;)V
+HSPLkotlinx/coroutines/CancellableContinuationImpl;->resumeWith(Ljava/lang/Object;)V
+HSPLkotlinx/coroutines/CancellableContinuationImpl;->resumedState(Lkotlinx/coroutines/NotCompleted;Ljava/lang/Object;ILkotlin/jvm/functions/Function1;Ljava/lang/Object;)Ljava/lang/Object;
+HSPLkotlinx/coroutines/CancellableContinuationImpl;->takeState$external__kotlinx_coroutines__android_common__kotlinx_coroutines()Ljava/lang/Object;
+HSPLkotlinx/coroutines/CancellableContinuationImpl;->tryResume()Z
+HSPLkotlinx/coroutines/CancellableContinuationImpl;->tryResume(Ljava/lang/Object;Ljava/lang/Object;Lkotlin/jvm/functions/Function1;)Ljava/lang/Object;
+HSPLkotlinx/coroutines/CancellableContinuationImpl;->tryResumeImpl(Ljava/lang/Object;Ljava/lang/Object;Lkotlin/jvm/functions/Function1;)Lkotlinx/coroutines/internal/Symbol;
+HSPLkotlinx/coroutines/CancellableContinuationImpl;->trySuspend()Z
+HSPLkotlinx/coroutines/CancellableContinuationImplKt;-><clinit>()V
+HSPLkotlinx/coroutines/CancellableContinuationKt;->getOrCreateCancellableContinuation(Lkotlin/coroutines/Continuation;)Lkotlinx/coroutines/CancellableContinuationImpl;
+HSPLkotlinx/coroutines/CancelledContinuation;-><init>(Lkotlin/coroutines/Continuation;Ljava/lang/Throwable;Z)V
+HSPLkotlinx/coroutines/CancelledContinuation;->makeResumed()Z
+HSPLkotlinx/coroutines/ChildContinuation;-><init>(Lkotlinx/coroutines/CancellableContinuationImpl;)V
+HSPLkotlinx/coroutines/ChildContinuation;->invoke(Ljava/lang/Throwable;)V
+HSPLkotlinx/coroutines/ChildHandleNode;-><init>(Lkotlinx/coroutines/ChildJob;)V
+HSPLkotlinx/coroutines/ChildHandleNode;->childCancelled(Ljava/lang/Throwable;)Z
+HSPLkotlinx/coroutines/ChildHandleNode;->invoke(Ljava/lang/Throwable;)V
+HSPLkotlinx/coroutines/CompletedContinuation;-><init>(Ljava/lang/Object;Lkotlinx/coroutines/CancelHandler;Lkotlin/jvm/functions/Function1;Ljava/lang/Object;Ljava/lang/Throwable;)V
+HSPLkotlinx/coroutines/CompletedContinuation;-><init>(Ljava/lang/Object;Lkotlinx/coroutines/CancelHandler;Lkotlin/jvm/functions/Function1;Ljava/lang/Object;Ljava/lang/Throwable;ILkotlin/jvm/internal/DefaultConstructorMarker;)V
+HSPLkotlinx/coroutines/CompletedExceptionally;-><init>(Ljava/lang/Throwable;Z)V
+HSPLkotlinx/coroutines/CompletedExceptionally;-><init>(Ljava/lang/Throwable;ZILkotlin/jvm/internal/DefaultConstructorMarker;)V
+HSPLkotlinx/coroutines/CompletedExceptionally;->getHandled()Z
+HSPLkotlinx/coroutines/CompletedExceptionally;->makeHandled()Z
+HSPLkotlinx/coroutines/CompletionHandlerBase;-><init>()V
+HSPLkotlinx/coroutines/CompletionStateKt;->recoverResult(Ljava/lang/Object;Lkotlin/coroutines/Continuation;)Ljava/lang/Object;
+HSPLkotlinx/coroutines/CompletionStateKt;->toState$default(Ljava/lang/Object;Lkotlin/jvm/functions/Function1;ILjava/lang/Object;)Ljava/lang/Object;
+HSPLkotlinx/coroutines/CompletionStateKt;->toState(Ljava/lang/Object;Lkotlin/jvm/functions/Function1;)Ljava/lang/Object;
+HSPLkotlinx/coroutines/CompletionStateKt;->toState(Ljava/lang/Object;Lkotlinx/coroutines/CancellableContinuation;)Ljava/lang/Object;
+HSPLkotlinx/coroutines/CoroutineContextKt$hasCopyableElements$1;-><clinit>()V
+HSPLkotlinx/coroutines/CoroutineContextKt$hasCopyableElements$1;-><init>()V
+HSPLkotlinx/coroutines/CoroutineContextKt$hasCopyableElements$1;->invoke(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;
+HSPLkotlinx/coroutines/CoroutineContextKt$hasCopyableElements$1;->invoke(ZLkotlin/coroutines/CoroutineContext$Element;)Ljava/lang/Boolean;
+HSPLkotlinx/coroutines/CoroutineContextKt;->foldCopies(Lkotlin/coroutines/CoroutineContext;Lkotlin/coroutines/CoroutineContext;Z)Lkotlin/coroutines/CoroutineContext;
+HSPLkotlinx/coroutines/CoroutineContextKt;->hasCopyableElements(Lkotlin/coroutines/CoroutineContext;)Z
+HSPLkotlinx/coroutines/CoroutineContextKt;->newCoroutineContext(Lkotlin/coroutines/CoroutineContext;Lkotlin/coroutines/CoroutineContext;)Lkotlin/coroutines/CoroutineContext;
+HSPLkotlinx/coroutines/CoroutineContextKt;->newCoroutineContext(Lkotlinx/coroutines/CoroutineScope;Lkotlin/coroutines/CoroutineContext;)Lkotlin/coroutines/CoroutineContext;
+HSPLkotlinx/coroutines/CoroutineDispatcher$Key$1;-><clinit>()V
+HSPLkotlinx/coroutines/CoroutineDispatcher$Key$1;-><init>()V
+HSPLkotlinx/coroutines/CoroutineDispatcher$Key;-><init>()V
+HSPLkotlinx/coroutines/CoroutineDispatcher$Key;-><init>(Lkotlin/jvm/internal/DefaultConstructorMarker;)V
+HSPLkotlinx/coroutines/CoroutineDispatcher;-><clinit>()V
+HSPLkotlinx/coroutines/CoroutineDispatcher;-><init>()V
+HSPLkotlinx/coroutines/CoroutineDispatcher;->get(Lkotlin/coroutines/CoroutineContext$Key;)Lkotlin/coroutines/CoroutineContext$Element;
+HSPLkotlinx/coroutines/CoroutineDispatcher;->interceptContinuation(Lkotlin/coroutines/Continuation;)Lkotlin/coroutines/Continuation;
+HSPLkotlinx/coroutines/CoroutineDispatcher;->isDispatchNeeded(Lkotlin/coroutines/CoroutineContext;)Z
+HSPLkotlinx/coroutines/CoroutineDispatcher;->limitedParallelism(I)Lkotlinx/coroutines/CoroutineDispatcher;
+HSPLkotlinx/coroutines/CoroutineDispatcher;->minusKey(Lkotlin/coroutines/CoroutineContext$Key;)Lkotlin/coroutines/CoroutineContext;
+HSPLkotlinx/coroutines/CoroutineDispatcher;->releaseInterceptedContinuation(Lkotlin/coroutines/Continuation;)V
+HSPLkotlinx/coroutines/CoroutineExceptionHandler$Key;-><clinit>()V
+HSPLkotlinx/coroutines/CoroutineExceptionHandler$Key;-><init>()V
+HSPLkotlinx/coroutines/CoroutineExceptionHandler;-><clinit>()V
+HSPLkotlinx/coroutines/CoroutineScopeKt;->CoroutineScope(Lkotlin/coroutines/CoroutineContext;)Lkotlinx/coroutines/CoroutineScope;
+HSPLkotlinx/coroutines/CoroutineScopeKt;->MainScope()Lkotlinx/coroutines/CoroutineScope;
+HSPLkotlinx/coroutines/CoroutineScopeKt;->coroutineScope(Lkotlin/jvm/functions/Function2;Lkotlin/coroutines/Continuation;)Ljava/lang/Object;
+HSPLkotlinx/coroutines/CoroutineScopeKt;->isActive(Lkotlinx/coroutines/CoroutineScope;)Z
+HSPLkotlinx/coroutines/CoroutineStart$WhenMappings;-><clinit>()V
+HSPLkotlinx/coroutines/CoroutineStart;->$values()[Lkotlinx/coroutines/CoroutineStart;
+HSPLkotlinx/coroutines/CoroutineStart;-><clinit>()V
+HSPLkotlinx/coroutines/CoroutineStart;-><init>(Ljava/lang/String;I)V
+HSPLkotlinx/coroutines/CoroutineStart;->invoke(Lkotlin/jvm/functions/Function2;Ljava/lang/Object;Lkotlin/coroutines/Continuation;)V
+HSPLkotlinx/coroutines/CoroutineStart;->isLazy()Z
+HSPLkotlinx/coroutines/CoroutineStart;->values()[Lkotlinx/coroutines/CoroutineStart;
+HSPLkotlinx/coroutines/DebugKt;-><clinit>()V
+HSPLkotlinx/coroutines/DebugKt;->getASSERTIONS_ENABLED()Z
+HSPLkotlinx/coroutines/DebugKt;->getDEBUG()Z
+HSPLkotlinx/coroutines/DebugKt;->getRECOVER_STACK_TRACES()Z
+HSPLkotlinx/coroutines/DebugStringsKt;->getClassSimpleName(Ljava/lang/Object;)Ljava/lang/String;
+HSPLkotlinx/coroutines/DefaultExecutor;-><clinit>()V
+HSPLkotlinx/coroutines/DefaultExecutor;-><init>()V
+HSPLkotlinx/coroutines/DefaultExecutorKt;-><clinit>()V
+HSPLkotlinx/coroutines/DefaultExecutorKt;->getDefaultDelay()Lkotlinx/coroutines/Delay;
+HSPLkotlinx/coroutines/DefaultExecutorKt;->initializeDefaultDelay()Lkotlinx/coroutines/Delay;
+HSPLkotlinx/coroutines/DispatchedTask;-><init>(I)V
+HSPLkotlinx/coroutines/DispatchedTask;->getExceptionalResult$external__kotlinx_coroutines__android_common__kotlinx_coroutines(Ljava/lang/Object;)Ljava/lang/Throwable;
+HSPLkotlinx/coroutines/DispatchedTask;->getSuccessfulResult$external__kotlinx_coroutines__android_common__kotlinx_coroutines(Ljava/lang/Object;)Ljava/lang/Object;
+HSPLkotlinx/coroutines/DispatchedTask;->handleFatalException(Ljava/lang/Throwable;Ljava/lang/Throwable;)V
+HSPLkotlinx/coroutines/DispatchedTask;->run()V
+HSPLkotlinx/coroutines/DispatchedTaskKt;->dispatch(Lkotlinx/coroutines/DispatchedTask;I)V
+HSPLkotlinx/coroutines/DispatchedTaskKt;->isCancellableMode(I)Z
+HSPLkotlinx/coroutines/DispatchedTaskKt;->isReusableMode(I)Z
+HSPLkotlinx/coroutines/DispatchedTaskKt;->resume(Lkotlinx/coroutines/DispatchedTask;Lkotlin/coroutines/Continuation;Z)V
+HSPLkotlinx/coroutines/DispatchedTaskKt;->resumeUnconfined(Lkotlinx/coroutines/DispatchedTask;)V
+HSPLkotlinx/coroutines/Dispatchers;-><clinit>()V
+HSPLkotlinx/coroutines/Dispatchers;-><init>()V
+HSPLkotlinx/coroutines/Dispatchers;->getDefault()Lkotlinx/coroutines/CoroutineDispatcher;
+HSPLkotlinx/coroutines/Dispatchers;->getMain()Lkotlinx/coroutines/MainCoroutineDispatcher;
+HSPLkotlinx/coroutines/Empty;-><init>(Z)V
+HSPLkotlinx/coroutines/Empty;->getList()Lkotlinx/coroutines/NodeList;
+HSPLkotlinx/coroutines/Empty;->isActive()Z
+HSPLkotlinx/coroutines/EventLoop;-><init>()V
+HSPLkotlinx/coroutines/EventLoop;->decrementUseCount(Z)V
+HSPLkotlinx/coroutines/EventLoop;->delta(Z)J
+HSPLkotlinx/coroutines/EventLoop;->incrementUseCount$default(Lkotlinx/coroutines/EventLoop;ZILjava/lang/Object;)V
+HSPLkotlinx/coroutines/EventLoop;->incrementUseCount(Z)V
+HSPLkotlinx/coroutines/EventLoop;->isUnconfinedLoopActive()Z
+HSPLkotlinx/coroutines/EventLoop;->processUnconfinedEvent()Z
+HSPLkotlinx/coroutines/EventLoopImplBase;-><init>()V
+HSPLkotlinx/coroutines/EventLoopImplPlatform;-><init>()V
+HSPLkotlinx/coroutines/EventLoopKt;->createEventLoop()Lkotlinx/coroutines/EventLoop;
+HSPLkotlinx/coroutines/ExecutorCoroutineDispatcher$Key$1;-><clinit>()V
+HSPLkotlinx/coroutines/ExecutorCoroutineDispatcher$Key$1;-><init>()V
+HSPLkotlinx/coroutines/ExecutorCoroutineDispatcher$Key;-><init>()V
+HSPLkotlinx/coroutines/ExecutorCoroutineDispatcher$Key;-><init>(Lkotlin/jvm/internal/DefaultConstructorMarker;)V
+HSPLkotlinx/coroutines/ExecutorCoroutineDispatcher;-><clinit>()V
+HSPLkotlinx/coroutines/ExecutorCoroutineDispatcher;-><init>()V
+HSPLkotlinx/coroutines/GlobalScope;-><clinit>()V
+HSPLkotlinx/coroutines/GlobalScope;-><init>()V
+HSPLkotlinx/coroutines/GlobalScope;->getCoroutineContext()Lkotlin/coroutines/CoroutineContext;
+HSPLkotlinx/coroutines/InvokeOnCancel;-><init>(Lkotlin/jvm/functions/Function1;)V
+HSPLkotlinx/coroutines/InvokeOnCancel;->invoke(Ljava/lang/Throwable;)V
+HSPLkotlinx/coroutines/InvokeOnCompletion;-><init>(Lkotlin/jvm/functions/Function1;)V
+HSPLkotlinx/coroutines/Job$DefaultImpls;->cancel$default(Lkotlinx/coroutines/Job;Ljava/util/concurrent/CancellationException;ILjava/lang/Object;)V
+HSPLkotlinx/coroutines/Job$DefaultImpls;->fold(Lkotlinx/coroutines/Job;Ljava/lang/Object;Lkotlin/jvm/functions/Function2;)Ljava/lang/Object;
+HSPLkotlinx/coroutines/Job$DefaultImpls;->get(Lkotlinx/coroutines/Job;Lkotlin/coroutines/CoroutineContext$Key;)Lkotlin/coroutines/CoroutineContext$Element;
+HSPLkotlinx/coroutines/Job$DefaultImpls;->invokeOnCompletion$default(Lkotlinx/coroutines/Job;ZZLkotlin/jvm/functions/Function1;ILjava/lang/Object;)Lkotlinx/coroutines/DisposableHandle;
+HSPLkotlinx/coroutines/Job$DefaultImpls;->minusKey(Lkotlinx/coroutines/Job;Lkotlin/coroutines/CoroutineContext$Key;)Lkotlin/coroutines/CoroutineContext;
+HSPLkotlinx/coroutines/Job$DefaultImpls;->plus(Lkotlinx/coroutines/Job;Lkotlin/coroutines/CoroutineContext;)Lkotlin/coroutines/CoroutineContext;
+HSPLkotlinx/coroutines/Job$Key;-><clinit>()V
+HSPLkotlinx/coroutines/Job$Key;-><init>()V
+HSPLkotlinx/coroutines/Job;-><clinit>()V
+HSPLkotlinx/coroutines/JobCancellationException;-><init>(Ljava/lang/String;Ljava/lang/Throwable;Lkotlinx/coroutines/Job;)V
+HSPLkotlinx/coroutines/JobCancellationException;->equals(Ljava/lang/Object;)Z
+HSPLkotlinx/coroutines/JobCancellationException;->fillInStackTrace()Ljava/lang/Throwable;
+HSPLkotlinx/coroutines/JobCancellingNode;-><init>()V
+HSPLkotlinx/coroutines/JobImpl;-><init>(Lkotlinx/coroutines/Job;)V
+HSPLkotlinx/coroutines/JobImpl;->getHandlesException$external__kotlinx_coroutines__android_common__kotlinx_coroutines()Z
+HSPLkotlinx/coroutines/JobImpl;->handlesException()Z
+HSPLkotlinx/coroutines/JobKt;->Job$default(Lkotlinx/coroutines/Job;ILjava/lang/Object;)Lkotlinx/coroutines/CompletableJob;
+HSPLkotlinx/coroutines/JobKt;->Job(Lkotlinx/coroutines/Job;)Lkotlinx/coroutines/CompletableJob;
+HSPLkotlinx/coroutines/JobKt;->ensureActive(Lkotlin/coroutines/CoroutineContext;)V
+HSPLkotlinx/coroutines/JobKt;->ensureActive(Lkotlinx/coroutines/Job;)V
+HSPLkotlinx/coroutines/JobKt;->getJob(Lkotlin/coroutines/CoroutineContext;)Lkotlinx/coroutines/Job;
+HSPLkotlinx/coroutines/JobKt;->isActive(Lkotlin/coroutines/CoroutineContext;)Z
+HSPLkotlinx/coroutines/JobKt__JobKt;->Job$default(Lkotlinx/coroutines/Job;ILjava/lang/Object;)Lkotlinx/coroutines/CompletableJob;
+HSPLkotlinx/coroutines/JobKt__JobKt;->Job(Lkotlinx/coroutines/Job;)Lkotlinx/coroutines/CompletableJob;
+HSPLkotlinx/coroutines/JobKt__JobKt;->ensureActive(Lkotlin/coroutines/CoroutineContext;)V
+HSPLkotlinx/coroutines/JobKt__JobKt;->ensureActive(Lkotlinx/coroutines/Job;)V
+HSPLkotlinx/coroutines/JobKt__JobKt;->getJob(Lkotlin/coroutines/CoroutineContext;)Lkotlinx/coroutines/Job;
+HSPLkotlinx/coroutines/JobKt__JobKt;->isActive(Lkotlin/coroutines/CoroutineContext;)Z
+HSPLkotlinx/coroutines/JobNode;-><init>()V
+HSPLkotlinx/coroutines/JobNode;->dispose()V
+HSPLkotlinx/coroutines/JobNode;->getJob()Lkotlinx/coroutines/JobSupport;
+HSPLkotlinx/coroutines/JobNode;->getList()Lkotlinx/coroutines/NodeList;
+HSPLkotlinx/coroutines/JobNode;->isActive()Z
+HSPLkotlinx/coroutines/JobNode;->setJob(Lkotlinx/coroutines/JobSupport;)V
+HSPLkotlinx/coroutines/JobSupport$Finishing;-><init>(Lkotlinx/coroutines/NodeList;ZLjava/lang/Throwable;)V
+HSPLkotlinx/coroutines/JobSupport$Finishing;->addExceptionLocked(Ljava/lang/Throwable;)V
+HSPLkotlinx/coroutines/JobSupport$Finishing;->allocateList()Ljava/util/ArrayList;
+HSPLkotlinx/coroutines/JobSupport$Finishing;->getExceptionsHolder()Ljava/lang/Object;
+HSPLkotlinx/coroutines/JobSupport$Finishing;->getList()Lkotlinx/coroutines/NodeList;
+HSPLkotlinx/coroutines/JobSupport$Finishing;->getRootCause()Ljava/lang/Throwable;
+HSPLkotlinx/coroutines/JobSupport$Finishing;->isActive()Z
+HSPLkotlinx/coroutines/JobSupport$Finishing;->isCancelling()Z
+HSPLkotlinx/coroutines/JobSupport$Finishing;->isCompleting()Z
+HSPLkotlinx/coroutines/JobSupport$Finishing;->sealLocked(Ljava/lang/Throwable;)Ljava/util/List;
+HSPLkotlinx/coroutines/JobSupport$Finishing;->setCompleting(Z)V
+HSPLkotlinx/coroutines/JobSupport$Finishing;->setExceptionsHolder(Ljava/lang/Object;)V
+HSPLkotlinx/coroutines/JobSupport$addLastAtomic$$inlined$addLastIf$1;-><init>(Lkotlinx/coroutines/internal/LockFreeLinkedListNode;Lkotlinx/coroutines/JobSupport;Ljava/lang/Object;)V
+HSPLkotlinx/coroutines/JobSupport$addLastAtomic$$inlined$addLastIf$1;->prepare(Ljava/lang/Object;)Ljava/lang/Object;
+HSPLkotlinx/coroutines/JobSupport$addLastAtomic$$inlined$addLastIf$1;->prepare(Lkotlinx/coroutines/internal/LockFreeLinkedListNode;)Ljava/lang/Object;
+HSPLkotlinx/coroutines/JobSupport;-><init>(Z)V
+HSPLkotlinx/coroutines/JobSupport;->access$cancellationExceptionMessage(Lkotlinx/coroutines/JobSupport;)Ljava/lang/String;
+HSPLkotlinx/coroutines/JobSupport;->addLastAtomic(Ljava/lang/Object;Lkotlinx/coroutines/NodeList;Lkotlinx/coroutines/JobNode;)Z
+HSPLkotlinx/coroutines/JobSupport;->addSuppressedExceptions(Ljava/lang/Throwable;Ljava/util/List;)V
+HSPLkotlinx/coroutines/JobSupport;->afterCompletion(Ljava/lang/Object;)V
+HSPLkotlinx/coroutines/JobSupport;->attachChild(Lkotlinx/coroutines/ChildJob;)Lkotlinx/coroutines/ChildHandle;
+HSPLkotlinx/coroutines/JobSupport;->cancel(Ljava/util/concurrent/CancellationException;)V
+HSPLkotlinx/coroutines/JobSupport;->cancelImpl$external__kotlinx_coroutines__android_common__kotlinx_coroutines(Ljava/lang/Object;)Z
+HSPLkotlinx/coroutines/JobSupport;->cancelInternal(Ljava/lang/Throwable;)V
+HSPLkotlinx/coroutines/JobSupport;->cancelParent(Ljava/lang/Throwable;)Z
+HSPLkotlinx/coroutines/JobSupport;->childCancelled(Ljava/lang/Throwable;)Z
+HSPLkotlinx/coroutines/JobSupport;->completeStateFinalization(Lkotlinx/coroutines/Incomplete;Ljava/lang/Object;)V
+HSPLkotlinx/coroutines/JobSupport;->createCauseException(Ljava/lang/Object;)Ljava/lang/Throwable;
+HSPLkotlinx/coroutines/JobSupport;->finalizeFinishingState(Lkotlinx/coroutines/JobSupport$Finishing;Ljava/lang/Object;)Ljava/lang/Object;
+HSPLkotlinx/coroutines/JobSupport;->firstChild(Lkotlinx/coroutines/Incomplete;)Lkotlinx/coroutines/ChildHandleNode;
+HSPLkotlinx/coroutines/JobSupport;->fold(Ljava/lang/Object;Lkotlin/jvm/functions/Function2;)Ljava/lang/Object;
+HSPLkotlinx/coroutines/JobSupport;->get(Lkotlin/coroutines/CoroutineContext$Key;)Lkotlin/coroutines/CoroutineContext$Element;
+HSPLkotlinx/coroutines/JobSupport;->getCancellationException()Ljava/util/concurrent/CancellationException;
+HSPLkotlinx/coroutines/JobSupport;->getChildJobCancellationCause()Ljava/util/concurrent/CancellationException;
+HSPLkotlinx/coroutines/JobSupport;->getFinalRootCause(Lkotlinx/coroutines/JobSupport$Finishing;Ljava/util/List;)Ljava/lang/Throwable;
+HSPLkotlinx/coroutines/JobSupport;->getKey()Lkotlin/coroutines/CoroutineContext$Key;
+HSPLkotlinx/coroutines/JobSupport;->getOnCancelComplete$external__kotlinx_coroutines__android_common__kotlinx_coroutines()Z
+HSPLkotlinx/coroutines/JobSupport;->getOrPromoteCancellingList(Lkotlinx/coroutines/Incomplete;)Lkotlinx/coroutines/NodeList;
+HSPLkotlinx/coroutines/JobSupport;->getParentHandle$external__kotlinx_coroutines__android_common__kotlinx_coroutines()Lkotlinx/coroutines/ChildHandle;
+HSPLkotlinx/coroutines/JobSupport;->getState$external__kotlinx_coroutines__android_common__kotlinx_coroutines()Ljava/lang/Object;
+HSPLkotlinx/coroutines/JobSupport;->initParentJob(Lkotlinx/coroutines/Job;)V
+HSPLkotlinx/coroutines/JobSupport;->invokeOnCompletion(Lkotlin/jvm/functions/Function1;)Lkotlinx/coroutines/DisposableHandle;
+HSPLkotlinx/coroutines/JobSupport;->invokeOnCompletion(ZZLkotlin/jvm/functions/Function1;)Lkotlinx/coroutines/DisposableHandle;
+HSPLkotlinx/coroutines/JobSupport;->isActive()Z
+HSPLkotlinx/coroutines/JobSupport;->isCompleted()Z
+HSPLkotlinx/coroutines/JobSupport;->isScopedCoroutine()Z
+HSPLkotlinx/coroutines/JobSupport;->makeCancelling(Ljava/lang/Object;)Ljava/lang/Object;
+HSPLkotlinx/coroutines/JobSupport;->makeCompletingOnce$external__kotlinx_coroutines__android_common__kotlinx_coroutines(Ljava/lang/Object;)Ljava/lang/Object;
+HSPLkotlinx/coroutines/JobSupport;->makeNode(Lkotlin/jvm/functions/Function1;Z)Lkotlinx/coroutines/JobNode;
+HSPLkotlinx/coroutines/JobSupport;->minusKey(Lkotlin/coroutines/CoroutineContext$Key;)Lkotlin/coroutines/CoroutineContext;
+HSPLkotlinx/coroutines/JobSupport;->nextChild(Lkotlinx/coroutines/internal/LockFreeLinkedListNode;)Lkotlinx/coroutines/ChildHandleNode;
+HSPLkotlinx/coroutines/JobSupport;->notifyCancelling(Lkotlinx/coroutines/NodeList;Ljava/lang/Throwable;)V
+HSPLkotlinx/coroutines/JobSupport;->notifyCompletion(Lkotlinx/coroutines/NodeList;Ljava/lang/Throwable;)V
+HSPLkotlinx/coroutines/JobSupport;->onCancelling(Ljava/lang/Throwable;)V
+HSPLkotlinx/coroutines/JobSupport;->parentCancelled(Lkotlinx/coroutines/ParentJob;)V
+HSPLkotlinx/coroutines/JobSupport;->plus(Lkotlin/coroutines/CoroutineContext;)Lkotlin/coroutines/CoroutineContext;
+HSPLkotlinx/coroutines/JobSupport;->promoteSingleToNodeList(Lkotlinx/coroutines/JobNode;)V
+HSPLkotlinx/coroutines/JobSupport;->removeNode$external__kotlinx_coroutines__android_common__kotlinx_coroutines(Lkotlinx/coroutines/JobNode;)V
+HSPLkotlinx/coroutines/JobSupport;->setParentHandle$external__kotlinx_coroutines__android_common__kotlinx_coroutines(Lkotlinx/coroutines/ChildHandle;)V
+HSPLkotlinx/coroutines/JobSupport;->start()Z
+HSPLkotlinx/coroutines/JobSupport;->startInternal(Ljava/lang/Object;)I
+HSPLkotlinx/coroutines/JobSupport;->toCancellationException(Ljava/lang/Throwable;Ljava/lang/String;)Ljava/util/concurrent/CancellationException;
+HSPLkotlinx/coroutines/JobSupport;->tryFinalizeSimpleState(Lkotlinx/coroutines/Incomplete;Ljava/lang/Object;)Z
+HSPLkotlinx/coroutines/JobSupport;->tryMakeCancelling(Lkotlinx/coroutines/Incomplete;Ljava/lang/Throwable;)Z
+HSPLkotlinx/coroutines/JobSupport;->tryMakeCompleting(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;
+HSPLkotlinx/coroutines/JobSupport;->tryMakeCompletingSlowPath(Lkotlinx/coroutines/Incomplete;Ljava/lang/Object;)Ljava/lang/Object;
+HSPLkotlinx/coroutines/JobSupportKt;-><clinit>()V
+HSPLkotlinx/coroutines/JobSupportKt;->access$getCOMPLETING_ALREADY$p()Lkotlinx/coroutines/internal/Symbol;
+HSPLkotlinx/coroutines/JobSupportKt;->access$getCOMPLETING_RETRY$p()Lkotlinx/coroutines/internal/Symbol;
+HSPLkotlinx/coroutines/JobSupportKt;->access$getEMPTY_ACTIVE$p()Lkotlinx/coroutines/Empty;
+HSPLkotlinx/coroutines/JobSupportKt;->access$getSEALED$p()Lkotlinx/coroutines/internal/Symbol;
+HSPLkotlinx/coroutines/JobSupportKt;->boxIncomplete(Ljava/lang/Object;)Ljava/lang/Object;
+HSPLkotlinx/coroutines/JobSupportKt;->unboxState(Ljava/lang/Object;)Ljava/lang/Object;
+HSPLkotlinx/coroutines/MainCoroutineDispatcher;-><init>()V
+HSPLkotlinx/coroutines/NodeList;-><init>()V
+HSPLkotlinx/coroutines/NodeList;->getList()Lkotlinx/coroutines/NodeList;
+HSPLkotlinx/coroutines/NodeList;->isActive()Z
+HSPLkotlinx/coroutines/NonDisposableHandle;-><clinit>()V
+HSPLkotlinx/coroutines/NonDisposableHandle;-><init>()V
+HSPLkotlinx/coroutines/NonDisposableHandle;->dispose()V
+HSPLkotlinx/coroutines/StandaloneCoroutine;-><init>(Lkotlin/coroutines/CoroutineContext;Z)V
+HSPLkotlinx/coroutines/SupervisorJobImpl;-><init>(Lkotlinx/coroutines/Job;)V
+HSPLkotlinx/coroutines/SupervisorKt;->SupervisorJob$default(Lkotlinx/coroutines/Job;ILjava/lang/Object;)Lkotlinx/coroutines/CompletableJob;
+HSPLkotlinx/coroutines/SupervisorKt;->SupervisorJob(Lkotlinx/coroutines/Job;)Lkotlinx/coroutines/CompletableJob;
+HSPLkotlinx/coroutines/ThreadLocalEventLoop;-><clinit>()V
+HSPLkotlinx/coroutines/ThreadLocalEventLoop;-><init>()V
+HSPLkotlinx/coroutines/ThreadLocalEventLoop;->getEventLoop$external__kotlinx_coroutines__android_common__kotlinx_coroutines()Lkotlinx/coroutines/EventLoop;
+HSPLkotlinx/coroutines/Unconfined;-><clinit>()V
+HSPLkotlinx/coroutines/Unconfined;-><init>()V
+HSPLkotlinx/coroutines/UndispatchedCoroutine;-><init>(Lkotlin/coroutines/CoroutineContext;Lkotlin/coroutines/Continuation;)V
+HSPLkotlinx/coroutines/UndispatchedMarker;-><clinit>()V
+HSPLkotlinx/coroutines/UndispatchedMarker;-><init>()V
+HSPLkotlinx/coroutines/UndispatchedMarker;->fold(Ljava/lang/Object;Lkotlin/jvm/functions/Function2;)Ljava/lang/Object;
+HSPLkotlinx/coroutines/UndispatchedMarker;->get(Lkotlin/coroutines/CoroutineContext$Key;)Lkotlin/coroutines/CoroutineContext$Element;
+HSPLkotlinx/coroutines/UndispatchedMarker;->getKey()Lkotlin/coroutines/CoroutineContext$Key;
+HSPLkotlinx/coroutines/android/AndroidDispatcherFactory;-><init>()V
+HSPLkotlinx/coroutines/android/AndroidDispatcherFactory;->createDispatcher(Ljava/util/List;)Lkotlinx/coroutines/MainCoroutineDispatcher;
+HSPLkotlinx/coroutines/android/HandlerContext;-><init>(Landroid/os/Handler;Ljava/lang/String;)V
+HSPLkotlinx/coroutines/android/HandlerContext;-><init>(Landroid/os/Handler;Ljava/lang/String;ILkotlin/jvm/internal/DefaultConstructorMarker;)V
+HSPLkotlinx/coroutines/android/HandlerContext;-><init>(Landroid/os/Handler;Ljava/lang/String;Z)V
+HSPLkotlinx/coroutines/android/HandlerContext;->dispatch(Lkotlin/coroutines/CoroutineContext;Ljava/lang/Runnable;)V
+HSPLkotlinx/coroutines/android/HandlerContext;->getImmediate()Lkotlinx/coroutines/android/HandlerContext;
+HSPLkotlinx/coroutines/android/HandlerContext;->getImmediate()Lkotlinx/coroutines/android/HandlerDispatcher;
+HSPLkotlinx/coroutines/android/HandlerContext;->isDispatchNeeded(Lkotlin/coroutines/CoroutineContext;)Z
+HSPLkotlinx/coroutines/android/HandlerDispatcher;-><init>()V
+HSPLkotlinx/coroutines/android/HandlerDispatcher;-><init>(Lkotlin/jvm/internal/DefaultConstructorMarker;)V
+HSPLkotlinx/coroutines/android/HandlerDispatcherKt;-><clinit>()V
+HSPLkotlinx/coroutines/android/HandlerDispatcherKt;->asHandler(Landroid/os/Looper;Z)Landroid/os/Handler;
+HSPLkotlinx/coroutines/android/HandlerDispatcherKt;->from(Landroid/os/Handler;Ljava/lang/String;)Lkotlinx/coroutines/android/HandlerDispatcher;
+HSPLkotlinx/coroutines/channels/AbstractChannel$Itr;-><init>(Lkotlinx/coroutines/channels/AbstractChannel;)V
+HSPLkotlinx/coroutines/channels/AbstractChannel$Itr;->hasNext(Lkotlin/coroutines/Continuation;)Ljava/lang/Object;
+HSPLkotlinx/coroutines/channels/AbstractChannel$Itr;->hasNextResult(Ljava/lang/Object;)Z
+HSPLkotlinx/coroutines/channels/AbstractChannel$Itr;->hasNextSuspend(Lkotlin/coroutines/Continuation;)Ljava/lang/Object;
+HSPLkotlinx/coroutines/channels/AbstractChannel$Itr;->next()Ljava/lang/Object;
+HSPLkotlinx/coroutines/channels/AbstractChannel$Itr;->setResult(Ljava/lang/Object;)V
+HSPLkotlinx/coroutines/channels/AbstractChannel$ReceiveElement;-><init>(Lkotlinx/coroutines/CancellableContinuation;I)V
+HSPLkotlinx/coroutines/channels/AbstractChannel$ReceiveElement;->completeResumeReceive(Ljava/lang/Object;)V
+HSPLkotlinx/coroutines/channels/AbstractChannel$ReceiveElement;->resumeValue(Ljava/lang/Object;)Ljava/lang/Object;
+HSPLkotlinx/coroutines/channels/AbstractChannel$ReceiveElement;->tryResumeReceive(Ljava/lang/Object;Lkotlinx/coroutines/internal/LockFreeLinkedListNode$PrepareOp;)Lkotlinx/coroutines/internal/Symbol;
+HSPLkotlinx/coroutines/channels/AbstractChannel$ReceiveHasNext;-><init>(Lkotlinx/coroutines/channels/AbstractChannel$Itr;Lkotlinx/coroutines/CancellableContinuation;)V
+HSPLkotlinx/coroutines/channels/AbstractChannel$ReceiveHasNext;->completeResumeReceive(Ljava/lang/Object;)V
+HSPLkotlinx/coroutines/channels/AbstractChannel$ReceiveHasNext;->resumeOnCancellationFun(Ljava/lang/Object;)Lkotlin/jvm/functions/Function1;
+HSPLkotlinx/coroutines/channels/AbstractChannel$ReceiveHasNext;->tryResumeReceive(Ljava/lang/Object;Lkotlinx/coroutines/internal/LockFreeLinkedListNode$PrepareOp;)Lkotlinx/coroutines/internal/Symbol;
+HSPLkotlinx/coroutines/channels/AbstractChannel$RemoveReceiveOnCancel;-><init>(Lkotlinx/coroutines/channels/AbstractChannel;Lkotlinx/coroutines/channels/Receive;)V
+HSPLkotlinx/coroutines/channels/AbstractChannel$enqueueReceiveInternal$$inlined$addLastIfPrevAndIf$1;-><init>(Lkotlinx/coroutines/internal/LockFreeLinkedListNode;Lkotlinx/coroutines/channels/AbstractChannel;)V
+HSPLkotlinx/coroutines/channels/AbstractChannel$enqueueReceiveInternal$$inlined$addLastIfPrevAndIf$1;->prepare(Ljava/lang/Object;)Ljava/lang/Object;
+HSPLkotlinx/coroutines/channels/AbstractChannel$enqueueReceiveInternal$$inlined$addLastIfPrevAndIf$1;->prepare(Lkotlinx/coroutines/internal/LockFreeLinkedListNode;)Ljava/lang/Object;
+HSPLkotlinx/coroutines/channels/AbstractChannel$receiveCatching$1;-><init>(Lkotlinx/coroutines/channels/AbstractChannel;Lkotlin/coroutines/Continuation;)V
+HSPLkotlinx/coroutines/channels/AbstractChannel$receiveCatching$1;->invokeSuspend(Ljava/lang/Object;)Ljava/lang/Object;
+HSPLkotlinx/coroutines/channels/AbstractChannel;-><init>(Lkotlin/jvm/functions/Function1;)V
+HSPLkotlinx/coroutines/channels/AbstractChannel;->access$enqueueReceive(Lkotlinx/coroutines/channels/AbstractChannel;Lkotlinx/coroutines/channels/Receive;)Z
+HSPLkotlinx/coroutines/channels/AbstractChannel;->access$removeReceiveOnCancel(Lkotlinx/coroutines/channels/AbstractChannel;Lkotlinx/coroutines/CancellableContinuation;Lkotlinx/coroutines/channels/Receive;)V
+HSPLkotlinx/coroutines/channels/AbstractChannel;->enqueueReceive(Lkotlinx/coroutines/channels/Receive;)Z
+HSPLkotlinx/coroutines/channels/AbstractChannel;->enqueueReceiveInternal(Lkotlinx/coroutines/channels/Receive;)Z
+HSPLkotlinx/coroutines/channels/AbstractChannel;->iterator()Lkotlinx/coroutines/channels/ChannelIterator;
+HSPLkotlinx/coroutines/channels/AbstractChannel;->onReceiveDequeued()V
+HSPLkotlinx/coroutines/channels/AbstractChannel;->onReceiveEnqueued()V
+HSPLkotlinx/coroutines/channels/AbstractChannel;->pollInternal()Ljava/lang/Object;
+HSPLkotlinx/coroutines/channels/AbstractChannel;->receive(Lkotlin/coroutines/Continuation;)Ljava/lang/Object;
+HSPLkotlinx/coroutines/channels/AbstractChannel;->receiveCatching-JP2dKIU(Lkotlin/coroutines/Continuation;)Ljava/lang/Object;
+HSPLkotlinx/coroutines/channels/AbstractChannel;->receiveSuspend(ILkotlin/coroutines/Continuation;)Ljava/lang/Object;
+HSPLkotlinx/coroutines/channels/AbstractChannel;->removeReceiveOnCancel(Lkotlinx/coroutines/CancellableContinuation;Lkotlinx/coroutines/channels/Receive;)V
+HSPLkotlinx/coroutines/channels/AbstractChannel;->takeFirstReceiveOrPeekClosed()Lkotlinx/coroutines/channels/ReceiveOrClosed;
+HSPLkotlinx/coroutines/channels/AbstractChannel;->tryReceive-PtdJZtk()Ljava/lang/Object;
+HSPLkotlinx/coroutines/channels/AbstractChannelKt;-><clinit>()V
+HSPLkotlinx/coroutines/channels/AbstractSendChannel;-><init>(Lkotlin/jvm/functions/Function1;)V
+HSPLkotlinx/coroutines/channels/AbstractSendChannel;->getClosedForSend()Lkotlinx/coroutines/channels/Closed;
+HSPLkotlinx/coroutines/channels/AbstractSendChannel;->getQueue()Lkotlinx/coroutines/internal/LockFreeLinkedListHead;
+HSPLkotlinx/coroutines/channels/AbstractSendChannel;->send(Ljava/lang/Object;Lkotlin/coroutines/Continuation;)Ljava/lang/Object;
+HSPLkotlinx/coroutines/channels/AbstractSendChannel;->takeFirstReceiveOrPeekClosed()Lkotlinx/coroutines/channels/ReceiveOrClosed;
+HSPLkotlinx/coroutines/channels/AbstractSendChannel;->takeFirstSendOrPeekClosed()Lkotlinx/coroutines/channels/Send;
+HSPLkotlinx/coroutines/channels/AbstractSendChannel;->trySend-JP2dKIU(Ljava/lang/Object;)Ljava/lang/Object;
+HSPLkotlinx/coroutines/channels/ArrayChannel;-><init>(ILkotlinx/coroutines/channels/BufferOverflow;Lkotlin/jvm/functions/Function1;)V
+HSPLkotlinx/coroutines/channels/ArrayChannel;->enqueueReceiveInternal(Lkotlinx/coroutines/channels/Receive;)Z
+HSPLkotlinx/coroutines/channels/ArrayChannel;->isBufferAlwaysEmpty()Z
+HSPLkotlinx/coroutines/channels/ArrayChannel;->isBufferEmpty()Z
+HSPLkotlinx/coroutines/channels/ArrayChannel;->offerInternal(Ljava/lang/Object;)Ljava/lang/Object;
+HSPLkotlinx/coroutines/channels/ArrayChannel;->pollInternal()Ljava/lang/Object;
+HSPLkotlinx/coroutines/channels/ArrayChannel;->updateBufferSize(I)Lkotlinx/coroutines/internal/Symbol;
+HSPLkotlinx/coroutines/channels/BufferOverflow;->$values()[Lkotlinx/coroutines/channels/BufferOverflow;
+HSPLkotlinx/coroutines/channels/BufferOverflow;-><clinit>()V
+HSPLkotlinx/coroutines/channels/BufferOverflow;-><init>(Ljava/lang/String;I)V
+HSPLkotlinx/coroutines/channels/Channel$Factory;-><clinit>()V
+HSPLkotlinx/coroutines/channels/Channel$Factory;-><init>()V
+HSPLkotlinx/coroutines/channels/Channel$Factory;->getCHANNEL_DEFAULT_CAPACITY$external__kotlinx_coroutines__android_common__kotlinx_coroutines()I
+HSPLkotlinx/coroutines/channels/Channel;-><clinit>()V
+HSPLkotlinx/coroutines/channels/ChannelCoroutine;-><init>(Lkotlin/coroutines/CoroutineContext;Lkotlinx/coroutines/channels/Channel;ZZ)V
+HSPLkotlinx/coroutines/channels/ChannelCoroutine;->receiveCatching-JP2dKIU(Lkotlin/coroutines/Continuation;)Ljava/lang/Object;
+HSPLkotlinx/coroutines/channels/ChannelCoroutine;->send(Ljava/lang/Object;Lkotlin/coroutines/Continuation;)Ljava/lang/Object;
+HSPLkotlinx/coroutines/channels/ChannelKt;->Channel$default(ILkotlinx/coroutines/channels/BufferOverflow;Lkotlin/jvm/functions/Function1;ILjava/lang/Object;)Lkotlinx/coroutines/channels/Channel;
+HSPLkotlinx/coroutines/channels/ChannelKt;->Channel(ILkotlinx/coroutines/channels/BufferOverflow;Lkotlin/jvm/functions/Function1;)Lkotlinx/coroutines/channels/Channel;
+HSPLkotlinx/coroutines/channels/ChannelResult$Companion;-><init>()V
+HSPLkotlinx/coroutines/channels/ChannelResult$Companion;-><init>(Lkotlin/jvm/internal/DefaultConstructorMarker;)V
+HSPLkotlinx/coroutines/channels/ChannelResult$Companion;->failure-PtdJZtk()Ljava/lang/Object;
+HSPLkotlinx/coroutines/channels/ChannelResult$Companion;->success-JP2dKIU(Ljava/lang/Object;)Ljava/lang/Object;
+HSPLkotlinx/coroutines/channels/ChannelResult$Failed;-><init>()V
+HSPLkotlinx/coroutines/channels/ChannelResult;-><clinit>()V
+HSPLkotlinx/coroutines/channels/ChannelResult;-><init>(Ljava/lang/Object;)V
+HSPLkotlinx/coroutines/channels/ChannelResult;->access$getFailed$cp()Lkotlinx/coroutines/channels/ChannelResult$Failed;
+HSPLkotlinx/coroutines/channels/ChannelResult;->box-impl(Ljava/lang/Object;)Lkotlinx/coroutines/channels/ChannelResult;
+HSPLkotlinx/coroutines/channels/ChannelResult;->constructor-impl(Ljava/lang/Object;)Ljava/lang/Object;
+HSPLkotlinx/coroutines/channels/ChannelResult;->getOrNull-impl(Ljava/lang/Object;)Ljava/lang/Object;
+HSPLkotlinx/coroutines/channels/ChannelResult;->getOrThrow-impl(Ljava/lang/Object;)Ljava/lang/Object;
+HSPLkotlinx/coroutines/channels/ChannelResult;->isClosed-impl(Ljava/lang/Object;)Z
+HSPLkotlinx/coroutines/channels/ChannelResult;->unbox-impl()Ljava/lang/Object;
+HSPLkotlinx/coroutines/channels/ConflatedChannel;-><init>(Lkotlin/jvm/functions/Function1;)V
+HSPLkotlinx/coroutines/channels/ConflatedChannel;->enqueueReceiveInternal(Lkotlinx/coroutines/channels/Receive;)Z
+HSPLkotlinx/coroutines/channels/ConflatedChannel;->isBufferAlwaysEmpty()Z
+HSPLkotlinx/coroutines/channels/ConflatedChannel;->isBufferEmpty()Z
+HSPLkotlinx/coroutines/channels/ConflatedChannel;->offerInternal(Ljava/lang/Object;)Ljava/lang/Object;
+HSPLkotlinx/coroutines/channels/ConflatedChannel;->pollInternal()Ljava/lang/Object;
+HSPLkotlinx/coroutines/channels/ConflatedChannel;->updateValueLocked(Ljava/lang/Object;)Lkotlinx/coroutines/internal/UndeliveredElementException;
+HSPLkotlinx/coroutines/channels/LinkedListChannel;-><init>(Lkotlin/jvm/functions/Function1;)V
+HSPLkotlinx/coroutines/channels/LinkedListChannel;->isBufferAlwaysEmpty()Z
+HSPLkotlinx/coroutines/channels/ProduceKt;->produce$default(Lkotlinx/coroutines/CoroutineScope;Lkotlin/coroutines/CoroutineContext;ILkotlinx/coroutines/channels/BufferOverflow;Lkotlinx/coroutines/CoroutineStart;Lkotlin/jvm/functions/Function1;Lkotlin/jvm/functions/Function2;ILjava/lang/Object;)Lkotlinx/coroutines/channels/ReceiveChannel;
+HSPLkotlinx/coroutines/channels/ProduceKt;->produce(Lkotlinx/coroutines/CoroutineScope;Lkotlin/coroutines/CoroutineContext;ILkotlinx/coroutines/channels/BufferOverflow;Lkotlinx/coroutines/CoroutineStart;Lkotlin/jvm/functions/Function1;Lkotlin/jvm/functions/Function2;)Lkotlinx/coroutines/channels/ReceiveChannel;
+HSPLkotlinx/coroutines/channels/ProducerCoroutine;-><init>(Lkotlin/coroutines/CoroutineContext;Lkotlinx/coroutines/channels/Channel;)V
+HSPLkotlinx/coroutines/channels/Receive;-><init>()V
+HSPLkotlinx/coroutines/channels/Receive;->getOfferResult()Ljava/lang/Object;
+HSPLkotlinx/coroutines/channels/Receive;->getOfferResult()Lkotlinx/coroutines/internal/Symbol;
+HSPLkotlinx/coroutines/channels/Receive;->resumeOnCancellationFun(Ljava/lang/Object;)Lkotlin/jvm/functions/Function1;
+HSPLkotlinx/coroutines/channels/RendezvousChannel;-><init>(Lkotlin/jvm/functions/Function1;)V
+HSPLkotlinx/coroutines/channels/RendezvousChannel;->isBufferAlwaysEmpty()Z
+HSPLkotlinx/coroutines/flow/AbstractFlow$collect$1;-><init>(Lkotlinx/coroutines/flow/AbstractFlow;Lkotlin/coroutines/Continuation;)V
+HSPLkotlinx/coroutines/flow/AbstractFlow;-><init>()V
+HSPLkotlinx/coroutines/flow/AbstractFlow;->collect(Lkotlinx/coroutines/flow/FlowCollector;Lkotlin/coroutines/Continuation;)Ljava/lang/Object;
+HSPLkotlinx/coroutines/flow/DistinctFlowImpl$collect$2$emit$1;-><init>(Lkotlinx/coroutines/flow/DistinctFlowImpl$collect$2;Lkotlin/coroutines/Continuation;)V
+HSPLkotlinx/coroutines/flow/DistinctFlowImpl$collect$2;-><init>(Lkotlinx/coroutines/flow/DistinctFlowImpl;Lkotlin/jvm/internal/Ref$ObjectRef;Lkotlinx/coroutines/flow/FlowCollector;)V
+HSPLkotlinx/coroutines/flow/DistinctFlowImpl$collect$2;->emit(Ljava/lang/Object;Lkotlin/coroutines/Continuation;)Ljava/lang/Object;
+HSPLkotlinx/coroutines/flow/DistinctFlowImpl;-><init>(Lkotlinx/coroutines/flow/Flow;Lkotlin/jvm/functions/Function1;Lkotlin/jvm/functions/Function2;)V
+HSPLkotlinx/coroutines/flow/DistinctFlowImpl;->collect(Lkotlinx/coroutines/flow/FlowCollector;Lkotlin/coroutines/Continuation;)Ljava/lang/Object;
+HSPLkotlinx/coroutines/flow/FlowKt;->buffer$default(Lkotlinx/coroutines/flow/Flow;ILkotlinx/coroutines/channels/BufferOverflow;ILjava/lang/Object;)Lkotlinx/coroutines/flow/Flow;
+HSPLkotlinx/coroutines/flow/FlowKt;->buffer(Lkotlinx/coroutines/flow/Flow;ILkotlinx/coroutines/channels/BufferOverflow;)Lkotlinx/coroutines/flow/Flow;
+HSPLkotlinx/coroutines/flow/FlowKt;->collect(Lkotlinx/coroutines/flow/Flow;Lkotlin/coroutines/Continuation;)Ljava/lang/Object;
+HSPLkotlinx/coroutines/flow/FlowKt;->collectLatest(Lkotlinx/coroutines/flow/Flow;Lkotlin/jvm/functions/Function2;Lkotlin/coroutines/Continuation;)Ljava/lang/Object;
+HSPLkotlinx/coroutines/flow/FlowKt;->distinctUntilChanged(Lkotlinx/coroutines/flow/Flow;)Lkotlinx/coroutines/flow/Flow;
+HSPLkotlinx/coroutines/flow/FlowKt;->dropWhile(Lkotlinx/coroutines/flow/Flow;Lkotlin/jvm/functions/Function2;)Lkotlinx/coroutines/flow/Flow;
+HSPLkotlinx/coroutines/flow/FlowKt;->emitAll(Lkotlinx/coroutines/flow/FlowCollector;Lkotlinx/coroutines/channels/ReceiveChannel;Lkotlin/coroutines/Continuation;)Ljava/lang/Object;
+HSPLkotlinx/coroutines/flow/FlowKt;->ensureActive(Lkotlinx/coroutines/flow/FlowCollector;)V
+HSPLkotlinx/coroutines/flow/FlowKt;->first(Lkotlinx/coroutines/flow/Flow;Lkotlin/jvm/functions/Function2;Lkotlin/coroutines/Continuation;)Ljava/lang/Object;
+HSPLkotlinx/coroutines/flow/FlowKt;->flow(Lkotlin/jvm/functions/Function2;)Lkotlinx/coroutines/flow/Flow;
+HSPLkotlinx/coroutines/flow/FlowKt;->mapLatest(Lkotlinx/coroutines/flow/Flow;Lkotlin/jvm/functions/Function2;)Lkotlinx/coroutines/flow/Flow;
+HSPLkotlinx/coroutines/flow/FlowKt;->stateIn(Lkotlinx/coroutines/flow/Flow;Lkotlinx/coroutines/CoroutineScope;Lkotlinx/coroutines/flow/SharingStarted;Ljava/lang/Object;)Lkotlinx/coroutines/flow/StateFlow;
+HSPLkotlinx/coroutines/flow/FlowKt;->take(Lkotlinx/coroutines/flow/Flow;I)Lkotlinx/coroutines/flow/Flow;
+HSPLkotlinx/coroutines/flow/FlowKt;->transformLatest(Lkotlinx/coroutines/flow/Flow;Lkotlin/jvm/functions/Function3;)Lkotlinx/coroutines/flow/Flow;
+HSPLkotlinx/coroutines/flow/FlowKt__BuildersKt;->flow(Lkotlin/jvm/functions/Function2;)Lkotlinx/coroutines/flow/Flow;
+HSPLkotlinx/coroutines/flow/FlowKt__ChannelsKt$emitAllImpl$1;-><init>(Lkotlin/coroutines/Continuation;)V
+HSPLkotlinx/coroutines/flow/FlowKt__ChannelsKt$emitAllImpl$1;->invokeSuspend(Ljava/lang/Object;)Ljava/lang/Object;
+HSPLkotlinx/coroutines/flow/FlowKt__ChannelsKt;->access$emitAllImpl$FlowKt__ChannelsKt(Lkotlinx/coroutines/flow/FlowCollector;Lkotlinx/coroutines/channels/ReceiveChannel;ZLkotlin/coroutines/Continuation;)Ljava/lang/Object;
+HSPLkotlinx/coroutines/flow/FlowKt__ChannelsKt;->emitAll(Lkotlinx/coroutines/flow/FlowCollector;Lkotlinx/coroutines/channels/ReceiveChannel;Lkotlin/coroutines/Continuation;)Ljava/lang/Object;
+HSPLkotlinx/coroutines/flow/FlowKt__ChannelsKt;->emitAllImpl$FlowKt__ChannelsKt(Lkotlinx/coroutines/flow/FlowCollector;Lkotlinx/coroutines/channels/ReceiveChannel;ZLkotlin/coroutines/Continuation;)Ljava/lang/Object;
+HSPLkotlinx/coroutines/flow/FlowKt__CollectKt;->collect(Lkotlinx/coroutines/flow/Flow;Lkotlin/coroutines/Continuation;)Ljava/lang/Object;
+HSPLkotlinx/coroutines/flow/FlowKt__CollectKt;->collectLatest(Lkotlinx/coroutines/flow/Flow;Lkotlin/jvm/functions/Function2;Lkotlin/coroutines/Continuation;)Ljava/lang/Object;
+HSPLkotlinx/coroutines/flow/FlowKt__ContextKt;->buffer$default(Lkotlinx/coroutines/flow/Flow;ILkotlinx/coroutines/channels/BufferOverflow;ILjava/lang/Object;)Lkotlinx/coroutines/flow/Flow;
+HSPLkotlinx/coroutines/flow/FlowKt__ContextKt;->buffer(Lkotlinx/coroutines/flow/Flow;ILkotlinx/coroutines/channels/BufferOverflow;)Lkotlinx/coroutines/flow/Flow;
+HSPLkotlinx/coroutines/flow/FlowKt__DistinctKt$defaultAreEquivalent$1;-><clinit>()V
+HSPLkotlinx/coroutines/flow/FlowKt__DistinctKt$defaultAreEquivalent$1;-><init>()V
+HSPLkotlinx/coroutines/flow/FlowKt__DistinctKt$defaultKeySelector$1;-><clinit>()V
+HSPLkotlinx/coroutines/flow/FlowKt__DistinctKt$defaultKeySelector$1;-><init>()V
+HSPLkotlinx/coroutines/flow/FlowKt__DistinctKt$defaultKeySelector$1;->invoke(Ljava/lang/Object;)Ljava/lang/Object;
+HSPLkotlinx/coroutines/flow/FlowKt__DistinctKt;-><clinit>()V
+HSPLkotlinx/coroutines/flow/FlowKt__DistinctKt;->distinctUntilChanged(Lkotlinx/coroutines/flow/Flow;)Lkotlinx/coroutines/flow/Flow;
+HSPLkotlinx/coroutines/flow/FlowKt__DistinctKt;->distinctUntilChangedBy$FlowKt__DistinctKt(Lkotlinx/coroutines/flow/Flow;Lkotlin/jvm/functions/Function1;Lkotlin/jvm/functions/Function2;)Lkotlinx/coroutines/flow/Flow;
+HSPLkotlinx/coroutines/flow/FlowKt__EmittersKt;->ensureActive(Lkotlinx/coroutines/flow/FlowCollector;)V
+HSPLkotlinx/coroutines/flow/FlowKt__LimitKt$dropWhile$$inlined$unsafeFlow$1;-><init>(Lkotlinx/coroutines/flow/Flow;Lkotlin/jvm/functions/Function2;)V
+HSPLkotlinx/coroutines/flow/FlowKt__LimitKt$dropWhile$$inlined$unsafeFlow$1;->collect(Lkotlinx/coroutines/flow/FlowCollector;Lkotlin/coroutines/Continuation;)Ljava/lang/Object;
+HSPLkotlinx/coroutines/flow/FlowKt__LimitKt$dropWhile$1$1$emit$1;-><init>(Lkotlinx/coroutines/flow/FlowKt__LimitKt$dropWhile$1$1;Lkotlin/coroutines/Continuation;)V
+HSPLkotlinx/coroutines/flow/FlowKt__LimitKt$dropWhile$1$1;-><init>(Lkotlin/jvm/internal/Ref$BooleanRef;Lkotlinx/coroutines/flow/FlowCollector;Lkotlin/jvm/functions/Function2;)V
+HSPLkotlinx/coroutines/flow/FlowKt__LimitKt$dropWhile$1$1;->emit(Ljava/lang/Object;Lkotlin/coroutines/Continuation;)Ljava/lang/Object;
+HSPLkotlinx/coroutines/flow/FlowKt__LimitKt$take$$inlined$unsafeFlow$1;-><init>(Lkotlinx/coroutines/flow/Flow;I)V
+HSPLkotlinx/coroutines/flow/FlowKt__LimitKt;->dropWhile(Lkotlinx/coroutines/flow/Flow;Lkotlin/jvm/functions/Function2;)Lkotlinx/coroutines/flow/Flow;
+HSPLkotlinx/coroutines/flow/FlowKt__LimitKt;->take(Lkotlinx/coroutines/flow/Flow;I)Lkotlinx/coroutines/flow/Flow;
+HSPLkotlinx/coroutines/flow/FlowKt__MergeKt$mapLatest$1;-><init>(Lkotlin/jvm/functions/Function2;Lkotlin/coroutines/Continuation;)V
+HSPLkotlinx/coroutines/flow/FlowKt__MergeKt$mapLatest$1;->invoke(Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;
+HSPLkotlinx/coroutines/flow/FlowKt__MergeKt$mapLatest$1;->invoke(Lkotlinx/coroutines/flow/FlowCollector;Ljava/lang/Object;Lkotlin/coroutines/Continuation;)Ljava/lang/Object;
+HSPLkotlinx/coroutines/flow/FlowKt__MergeKt$mapLatest$1;->invokeSuspend(Ljava/lang/Object;)Ljava/lang/Object;
+HSPLkotlinx/coroutines/flow/FlowKt__MergeKt;-><clinit>()V
+HSPLkotlinx/coroutines/flow/FlowKt__MergeKt;->mapLatest(Lkotlinx/coroutines/flow/Flow;Lkotlin/jvm/functions/Function2;)Lkotlinx/coroutines/flow/Flow;
+HSPLkotlinx/coroutines/flow/FlowKt__MergeKt;->transformLatest(Lkotlinx/coroutines/flow/Flow;Lkotlin/jvm/functions/Function3;)Lkotlinx/coroutines/flow/Flow;
+HSPLkotlinx/coroutines/flow/FlowKt__ReduceKt$first$$inlined$collectWhile$2$1;-><init>(Lkotlinx/coroutines/flow/FlowKt__ReduceKt$first$$inlined$collectWhile$2;Lkotlin/coroutines/Continuation;)V
+HSPLkotlinx/coroutines/flow/FlowKt__ReduceKt$first$$inlined$collectWhile$2;-><init>(Lkotlin/jvm/functions/Function2;Lkotlin/jvm/internal/Ref$ObjectRef;)V
+HSPLkotlinx/coroutines/flow/FlowKt__ReduceKt$first$$inlined$collectWhile$2;->emit(Ljava/lang/Object;Lkotlin/coroutines/Continuation;)Ljava/lang/Object;
+HSPLkotlinx/coroutines/flow/FlowKt__ReduceKt$first$3;-><init>(Lkotlin/coroutines/Continuation;)V
+HSPLkotlinx/coroutines/flow/FlowKt__ReduceKt;->first(Lkotlinx/coroutines/flow/Flow;Lkotlin/jvm/functions/Function2;Lkotlin/coroutines/Continuation;)Ljava/lang/Object;
+HSPLkotlinx/coroutines/flow/FlowKt__ShareKt$launchSharing$1$2$WhenMappings;-><clinit>()V
+HSPLkotlinx/coroutines/flow/FlowKt__ShareKt$launchSharing$1$2;-><init>(Lkotlinx/coroutines/flow/Flow;Lkotlinx/coroutines/flow/MutableSharedFlow;Ljava/lang/Object;Lkotlin/coroutines/Continuation;)V
+HSPLkotlinx/coroutines/flow/FlowKt__ShareKt$launchSharing$1$2;->create(Ljava/lang/Object;Lkotlin/coroutines/Continuation;)Lkotlin/coroutines/Continuation;
+HSPLkotlinx/coroutines/flow/FlowKt__ShareKt$launchSharing$1$2;->invoke(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;
+HSPLkotlinx/coroutines/flow/FlowKt__ShareKt$launchSharing$1$2;->invoke(Lkotlinx/coroutines/flow/SharingCommand;Lkotlin/coroutines/Continuation;)Ljava/lang/Object;
+HSPLkotlinx/coroutines/flow/FlowKt__ShareKt$launchSharing$1$2;->invokeSuspend(Ljava/lang/Object;)Ljava/lang/Object;
+HSPLkotlinx/coroutines/flow/FlowKt__ShareKt$launchSharing$1;-><init>(Lkotlinx/coroutines/flow/SharingStarted;Lkotlinx/coroutines/flow/Flow;Lkotlinx/coroutines/flow/MutableSharedFlow;Ljava/lang/Object;Lkotlin/coroutines/Continuation;)V
+HSPLkotlinx/coroutines/flow/FlowKt__ShareKt$launchSharing$1;->create(Ljava/lang/Object;Lkotlin/coroutines/Continuation;)Lkotlin/coroutines/Continuation;
+HSPLkotlinx/coroutines/flow/FlowKt__ShareKt$launchSharing$1;->invoke(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;
+HSPLkotlinx/coroutines/flow/FlowKt__ShareKt$launchSharing$1;->invoke(Lkotlinx/coroutines/CoroutineScope;Lkotlin/coroutines/Continuation;)Ljava/lang/Object;
+HSPLkotlinx/coroutines/flow/FlowKt__ShareKt$launchSharing$1;->invokeSuspend(Ljava/lang/Object;)Ljava/lang/Object;
+HSPLkotlinx/coroutines/flow/FlowKt__ShareKt;->configureSharing$FlowKt__ShareKt(Lkotlinx/coroutines/flow/Flow;I)Lkotlinx/coroutines/flow/SharingConfig;
+HSPLkotlinx/coroutines/flow/FlowKt__ShareKt;->launchSharing$FlowKt__ShareKt(Lkotlinx/coroutines/CoroutineScope;Lkotlin/coroutines/CoroutineContext;Lkotlinx/coroutines/flow/Flow;Lkotlinx/coroutines/flow/MutableSharedFlow;Lkotlinx/coroutines/flow/SharingStarted;Ljava/lang/Object;)Lkotlinx/coroutines/Job;
+HSPLkotlinx/coroutines/flow/FlowKt__ShareKt;->stateIn(Lkotlinx/coroutines/flow/Flow;Lkotlinx/coroutines/CoroutineScope;Lkotlinx/coroutines/flow/SharingStarted;Ljava/lang/Object;)Lkotlinx/coroutines/flow/StateFlow;
+HSPLkotlinx/coroutines/flow/ReadonlyStateFlow;-><init>(Lkotlinx/coroutines/flow/StateFlow;Lkotlinx/coroutines/Job;)V
+HSPLkotlinx/coroutines/flow/ReadonlyStateFlow;->collect(Lkotlinx/coroutines/flow/FlowCollector;Lkotlin/coroutines/Continuation;)Ljava/lang/Object;
+HSPLkotlinx/coroutines/flow/ReadonlyStateFlow;->getValue()Ljava/lang/Object;
+HSPLkotlinx/coroutines/flow/SafeFlow;-><init>(Lkotlin/jvm/functions/Function2;)V
+HSPLkotlinx/coroutines/flow/SafeFlow;->collectSafely(Lkotlinx/coroutines/flow/FlowCollector;Lkotlin/coroutines/Continuation;)Ljava/lang/Object;
+HSPLkotlinx/coroutines/flow/SharedFlowImpl$collect$1;-><init>(Lkotlinx/coroutines/flow/SharedFlowImpl;Lkotlin/coroutines/Continuation;)V
+HSPLkotlinx/coroutines/flow/SharedFlowImpl;-><init>(IILkotlinx/coroutines/channels/BufferOverflow;)V
+HSPLkotlinx/coroutines/flow/SharedFlowImpl;->access$tryPeekLocked(Lkotlinx/coroutines/flow/SharedFlowImpl;Lkotlinx/coroutines/flow/SharedFlowSlot;)J
+HSPLkotlinx/coroutines/flow/SharedFlowImpl;->awaitValue(Lkotlinx/coroutines/flow/SharedFlowSlot;Lkotlin/coroutines/Continuation;)Ljava/lang/Object;
+HSPLkotlinx/coroutines/flow/SharedFlowImpl;->cleanupTailLocked()V
+HSPLkotlinx/coroutines/flow/SharedFlowImpl;->collect$suspendImpl(Lkotlinx/coroutines/flow/SharedFlowImpl;Lkotlinx/coroutines/flow/FlowCollector;Lkotlin/coroutines/Continuation;)Ljava/lang/Object;
+HSPLkotlinx/coroutines/flow/SharedFlowImpl;->collect(Lkotlinx/coroutines/flow/FlowCollector;Lkotlin/coroutines/Continuation;)Ljava/lang/Object;
+HSPLkotlinx/coroutines/flow/SharedFlowImpl;->createSlot()Lkotlinx/coroutines/flow/SharedFlowSlot;
+HSPLkotlinx/coroutines/flow/SharedFlowImpl;->createSlot()Lkotlinx/coroutines/flow/internal/AbstractSharedFlowSlot;
+HSPLkotlinx/coroutines/flow/SharedFlowImpl;->createSlotArray(I)[Lkotlinx/coroutines/flow/SharedFlowSlot;
+HSPLkotlinx/coroutines/flow/SharedFlowImpl;->createSlotArray(I)[Lkotlinx/coroutines/flow/internal/AbstractSharedFlowSlot;
+HSPLkotlinx/coroutines/flow/SharedFlowImpl;->dropOldestLocked()V
+HSPLkotlinx/coroutines/flow/SharedFlowImpl;->enqueueLocked(Ljava/lang/Object;)V
+HSPLkotlinx/coroutines/flow/SharedFlowImpl;->findSlotsToResumeLocked([Lkotlin/coroutines/Continuation;)[Lkotlin/coroutines/Continuation;
+HSPLkotlinx/coroutines/flow/SharedFlowImpl;->getBufferEndIndex()J
+HSPLkotlinx/coroutines/flow/SharedFlowImpl;->getHead()J
+HSPLkotlinx/coroutines/flow/SharedFlowImpl;->getLastReplayedLocked()Ljava/lang/Object;
+HSPLkotlinx/coroutines/flow/SharedFlowImpl;->getPeekedValueLockedAt(J)Ljava/lang/Object;
+HSPLkotlinx/coroutines/flow/SharedFlowImpl;->getReplaySize()I
+HSPLkotlinx/coroutines/flow/SharedFlowImpl;->getTotalSize()I
+HSPLkotlinx/coroutines/flow/SharedFlowImpl;->growBuffer([Ljava/lang/Object;II)[Ljava/lang/Object;
+HSPLkotlinx/coroutines/flow/SharedFlowImpl;->tryEmit(Ljava/lang/Object;)Z
+HSPLkotlinx/coroutines/flow/SharedFlowImpl;->tryEmitLocked(Ljava/lang/Object;)Z
+HSPLkotlinx/coroutines/flow/SharedFlowImpl;->tryEmitNoCollectorsLocked(Ljava/lang/Object;)Z
+HSPLkotlinx/coroutines/flow/SharedFlowImpl;->tryPeekLocked(Lkotlinx/coroutines/flow/SharedFlowSlot;)J
+HSPLkotlinx/coroutines/flow/SharedFlowImpl;->tryTakeValue(Lkotlinx/coroutines/flow/SharedFlowSlot;)Ljava/lang/Object;
+HSPLkotlinx/coroutines/flow/SharedFlowImpl;->updateBufferLocked(JJJJ)V
+HSPLkotlinx/coroutines/flow/SharedFlowImpl;->updateCollectorIndexLocked$external__kotlinx_coroutines__android_common__kotlinx_coroutines(J)[Lkotlin/coroutines/Continuation;
+HSPLkotlinx/coroutines/flow/SharedFlowImpl;->updateNewCollectorIndexLocked$external__kotlinx_coroutines__android_common__kotlinx_coroutines()J
+HSPLkotlinx/coroutines/flow/SharedFlowKt;-><clinit>()V
+HSPLkotlinx/coroutines/flow/SharedFlowKt;->MutableSharedFlow$default(IILkotlinx/coroutines/channels/BufferOverflow;ILjava/lang/Object;)Lkotlinx/coroutines/flow/MutableSharedFlow;
+HSPLkotlinx/coroutines/flow/SharedFlowKt;->MutableSharedFlow(IILkotlinx/coroutines/channels/BufferOverflow;)Lkotlinx/coroutines/flow/MutableSharedFlow;
+HSPLkotlinx/coroutines/flow/SharedFlowKt;->access$getBufferAt([Ljava/lang/Object;J)Ljava/lang/Object;
+HSPLkotlinx/coroutines/flow/SharedFlowKt;->access$setBufferAt([Ljava/lang/Object;JLjava/lang/Object;)V
+HSPLkotlinx/coroutines/flow/SharedFlowKt;->getBufferAt([Ljava/lang/Object;J)Ljava/lang/Object;
+HSPLkotlinx/coroutines/flow/SharedFlowKt;->setBufferAt([Ljava/lang/Object;JLjava/lang/Object;)V
+HSPLkotlinx/coroutines/flow/SharedFlowSlot;-><init>()V
+HSPLkotlinx/coroutines/flow/SharedFlowSlot;->allocateLocked(Ljava/lang/Object;)Z
+HSPLkotlinx/coroutines/flow/SharedFlowSlot;->allocateLocked(Lkotlinx/coroutines/flow/SharedFlowImpl;)Z
+HSPLkotlinx/coroutines/flow/SharingCommand;->$values()[Lkotlinx/coroutines/flow/SharingCommand;
+HSPLkotlinx/coroutines/flow/SharingCommand;-><clinit>()V
+HSPLkotlinx/coroutines/flow/SharingCommand;-><init>(Ljava/lang/String;I)V
+HSPLkotlinx/coroutines/flow/SharingCommand;->values()[Lkotlinx/coroutines/flow/SharingCommand;
+HSPLkotlinx/coroutines/flow/SharingConfig;-><init>(Lkotlinx/coroutines/flow/Flow;ILkotlinx/coroutines/channels/BufferOverflow;Lkotlin/coroutines/CoroutineContext;)V
+HSPLkotlinx/coroutines/flow/SharingStarted$Companion;-><clinit>()V
+HSPLkotlinx/coroutines/flow/SharingStarted$Companion;-><init>()V
+HSPLkotlinx/coroutines/flow/SharingStarted$Companion;->WhileSubscribed$default(Lkotlinx/coroutines/flow/SharingStarted$Companion;JJILjava/lang/Object;)Lkotlinx/coroutines/flow/SharingStarted;
+HSPLkotlinx/coroutines/flow/SharingStarted$Companion;->WhileSubscribed(JJ)Lkotlinx/coroutines/flow/SharingStarted;
+HSPLkotlinx/coroutines/flow/SharingStarted$Companion;->getEagerly()Lkotlinx/coroutines/flow/SharingStarted;
+HSPLkotlinx/coroutines/flow/SharingStarted$Companion;->getLazily()Lkotlinx/coroutines/flow/SharingStarted;
+HSPLkotlinx/coroutines/flow/SharingStarted;-><clinit>()V
+HSPLkotlinx/coroutines/flow/StartedEagerly;-><init>()V
+HSPLkotlinx/coroutines/flow/StartedLazily;-><init>()V
+HSPLkotlinx/coroutines/flow/StartedWhileSubscribed$command$1;-><init>(Lkotlinx/coroutines/flow/StartedWhileSubscribed;Lkotlin/coroutines/Continuation;)V
+HSPLkotlinx/coroutines/flow/StartedWhileSubscribed$command$1;->invoke(Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;
+HSPLkotlinx/coroutines/flow/StartedWhileSubscribed$command$1;->invoke(Lkotlinx/coroutines/flow/FlowCollector;ILkotlin/coroutines/Continuation;)Ljava/lang/Object;
+HSPLkotlinx/coroutines/flow/StartedWhileSubscribed$command$1;->invokeSuspend(Ljava/lang/Object;)Ljava/lang/Object;
+HSPLkotlinx/coroutines/flow/StartedWhileSubscribed$command$2;-><init>(Lkotlin/coroutines/Continuation;)V
+HSPLkotlinx/coroutines/flow/StartedWhileSubscribed$command$2;->create(Ljava/lang/Object;Lkotlin/coroutines/Continuation;)Lkotlin/coroutines/Continuation;
+HSPLkotlinx/coroutines/flow/StartedWhileSubscribed$command$2;->invoke(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;
+HSPLkotlinx/coroutines/flow/StartedWhileSubscribed$command$2;->invoke(Lkotlinx/coroutines/flow/SharingCommand;Lkotlin/coroutines/Continuation;)Ljava/lang/Object;
+HSPLkotlinx/coroutines/flow/StartedWhileSubscribed$command$2;->invokeSuspend(Ljava/lang/Object;)Ljava/lang/Object;
+HSPLkotlinx/coroutines/flow/StartedWhileSubscribed;-><init>(JJ)V
+HSPLkotlinx/coroutines/flow/StartedWhileSubscribed;->command(Lkotlinx/coroutines/flow/StateFlow;)Lkotlinx/coroutines/flow/Flow;
+HSPLkotlinx/coroutines/flow/StartedWhileSubscribed;->equals(Ljava/lang/Object;)Z
+HSPLkotlinx/coroutines/flow/StateFlowImpl$collect$1;-><init>(Lkotlinx/coroutines/flow/StateFlowImpl;Lkotlin/coroutines/Continuation;)V
+HSPLkotlinx/coroutines/flow/StateFlowImpl$collect$1;->invokeSuspend(Ljava/lang/Object;)Ljava/lang/Object;
+HSPLkotlinx/coroutines/flow/StateFlowImpl;-><init>(Ljava/lang/Object;)V
+HSPLkotlinx/coroutines/flow/StateFlowImpl;->collect(Lkotlinx/coroutines/flow/FlowCollector;Lkotlin/coroutines/Continuation;)Ljava/lang/Object;
+HSPLkotlinx/coroutines/flow/StateFlowImpl;->compareAndSet(Ljava/lang/Object;Ljava/lang/Object;)Z
+HSPLkotlinx/coroutines/flow/StateFlowImpl;->createSlot()Lkotlinx/coroutines/flow/StateFlowSlot;
+HSPLkotlinx/coroutines/flow/StateFlowImpl;->createSlot()Lkotlinx/coroutines/flow/internal/AbstractSharedFlowSlot;
+HSPLkotlinx/coroutines/flow/StateFlowImpl;->createSlotArray(I)[Lkotlinx/coroutines/flow/StateFlowSlot;
+HSPLkotlinx/coroutines/flow/StateFlowImpl;->createSlotArray(I)[Lkotlinx/coroutines/flow/internal/AbstractSharedFlowSlot;
+HSPLkotlinx/coroutines/flow/StateFlowImpl;->getValue()Ljava/lang/Object;
+HSPLkotlinx/coroutines/flow/StateFlowImpl;->setValue(Ljava/lang/Object;)V
+HSPLkotlinx/coroutines/flow/StateFlowImpl;->updateState(Ljava/lang/Object;Ljava/lang/Object;)Z
+HSPLkotlinx/coroutines/flow/StateFlowKt;-><clinit>()V
+HSPLkotlinx/coroutines/flow/StateFlowKt;->MutableStateFlow(Ljava/lang/Object;)Lkotlinx/coroutines/flow/MutableStateFlow;
+HSPLkotlinx/coroutines/flow/StateFlowKt;->access$getNONE$p()Lkotlinx/coroutines/internal/Symbol;
+HSPLkotlinx/coroutines/flow/StateFlowKt;->access$getPENDING$p()Lkotlinx/coroutines/internal/Symbol;
+HSPLkotlinx/coroutines/flow/StateFlowSlot;-><init>()V
+HSPLkotlinx/coroutines/flow/StateFlowSlot;->access$get_state$p(Lkotlinx/coroutines/flow/StateFlowSlot;)Lkotlinx/atomicfu/AtomicRef;
+HSPLkotlinx/coroutines/flow/StateFlowSlot;->allocateLocked(Ljava/lang/Object;)Z
+HSPLkotlinx/coroutines/flow/StateFlowSlot;->allocateLocked(Lkotlinx/coroutines/flow/StateFlowImpl;)Z
+HSPLkotlinx/coroutines/flow/StateFlowSlot;->awaitPending(Lkotlin/coroutines/Continuation;)Ljava/lang/Object;
+HSPLkotlinx/coroutines/flow/StateFlowSlot;->makePending()V
+HSPLkotlinx/coroutines/flow/StateFlowSlot;->takePending()Z
+HSPLkotlinx/coroutines/flow/internal/AbstractSharedFlow;-><init>()V
+HSPLkotlinx/coroutines/flow/internal/AbstractSharedFlow;->access$getNCollectors(Lkotlinx/coroutines/flow/internal/AbstractSharedFlow;)I
+HSPLkotlinx/coroutines/flow/internal/AbstractSharedFlow;->access$getSlots(Lkotlinx/coroutines/flow/internal/AbstractSharedFlow;)[Lkotlinx/coroutines/flow/internal/AbstractSharedFlowSlot;
+HSPLkotlinx/coroutines/flow/internal/AbstractSharedFlow;->allocateSlot()Lkotlinx/coroutines/flow/internal/AbstractSharedFlowSlot;
+HSPLkotlinx/coroutines/flow/internal/AbstractSharedFlow;->getNCollectors()I
+HSPLkotlinx/coroutines/flow/internal/AbstractSharedFlow;->getSlots()[Lkotlinx/coroutines/flow/internal/AbstractSharedFlowSlot;
+HSPLkotlinx/coroutines/flow/internal/AbstractSharedFlow;->getSubscriptionCount()Lkotlinx/coroutines/flow/StateFlow;
+HSPLkotlinx/coroutines/flow/internal/AbstractSharedFlowKt;-><clinit>()V
+HSPLkotlinx/coroutines/flow/internal/AbstractSharedFlowSlot;-><init>()V
+HSPLkotlinx/coroutines/flow/internal/ChannelFlow$collect$2;-><init>(Lkotlinx/coroutines/flow/FlowCollector;Lkotlinx/coroutines/flow/internal/ChannelFlow;Lkotlin/coroutines/Continuation;)V
+HSPLkotlinx/coroutines/flow/internal/ChannelFlow$collect$2;->create(Ljava/lang/Object;Lkotlin/coroutines/Continuation;)Lkotlin/coroutines/Continuation;
+HSPLkotlinx/coroutines/flow/internal/ChannelFlow$collect$2;->invoke(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;
+HSPLkotlinx/coroutines/flow/internal/ChannelFlow$collect$2;->invoke(Lkotlinx/coroutines/CoroutineScope;Lkotlin/coroutines/Continuation;)Ljava/lang/Object;
+HSPLkotlinx/coroutines/flow/internal/ChannelFlow$collect$2;->invokeSuspend(Ljava/lang/Object;)Ljava/lang/Object;
+HSPLkotlinx/coroutines/flow/internal/ChannelFlow$collectToFun$1;-><init>(Lkotlinx/coroutines/flow/internal/ChannelFlow;Lkotlin/coroutines/Continuation;)V
+HSPLkotlinx/coroutines/flow/internal/ChannelFlow$collectToFun$1;->create(Ljava/lang/Object;Lkotlin/coroutines/Continuation;)Lkotlin/coroutines/Continuation;
+HSPLkotlinx/coroutines/flow/internal/ChannelFlow$collectToFun$1;->invokeSuspend(Ljava/lang/Object;)Ljava/lang/Object;
+HSPLkotlinx/coroutines/flow/internal/ChannelFlow;-><init>(Lkotlin/coroutines/CoroutineContext;ILkotlinx/coroutines/channels/BufferOverflow;)V
+HSPLkotlinx/coroutines/flow/internal/ChannelFlow;->collect$suspendImpl(Lkotlinx/coroutines/flow/internal/ChannelFlow;Lkotlinx/coroutines/flow/FlowCollector;Lkotlin/coroutines/Continuation;)Ljava/lang/Object;
+HSPLkotlinx/coroutines/flow/internal/ChannelFlow;->collect(Lkotlinx/coroutines/flow/FlowCollector;Lkotlin/coroutines/Continuation;)Ljava/lang/Object;
+HSPLkotlinx/coroutines/flow/internal/ChannelFlow;->fuse(Lkotlin/coroutines/CoroutineContext;ILkotlinx/coroutines/channels/BufferOverflow;)Lkotlinx/coroutines/flow/Flow;
+HSPLkotlinx/coroutines/flow/internal/ChannelFlow;->getCollectToFun$external__kotlinx_coroutines__android_common__kotlinx_coroutines()Lkotlin/jvm/functions/Function2;
+HSPLkotlinx/coroutines/flow/internal/ChannelFlow;->getProduceCapacity$external__kotlinx_coroutines__android_common__kotlinx_coroutines()I
+HSPLkotlinx/coroutines/flow/internal/ChannelFlow;->produceImpl(Lkotlinx/coroutines/CoroutineScope;)Lkotlinx/coroutines/channels/ReceiveChannel;
+HSPLkotlinx/coroutines/flow/internal/ChannelFlowOperator;-><init>(Lkotlinx/coroutines/flow/Flow;Lkotlin/coroutines/CoroutineContext;ILkotlinx/coroutines/channels/BufferOverflow;)V
+HSPLkotlinx/coroutines/flow/internal/ChannelFlowOperator;->collect$suspendImpl(Lkotlinx/coroutines/flow/internal/ChannelFlowOperator;Lkotlinx/coroutines/flow/FlowCollector;Lkotlin/coroutines/Continuation;)Ljava/lang/Object;
+HSPLkotlinx/coroutines/flow/internal/ChannelFlowOperator;->collect(Lkotlinx/coroutines/flow/FlowCollector;Lkotlin/coroutines/Continuation;)Ljava/lang/Object;
+HSPLkotlinx/coroutines/flow/internal/ChannelFlowOperator;->collectTo$suspendImpl(Lkotlinx/coroutines/flow/internal/ChannelFlowOperator;Lkotlinx/coroutines/channels/ProducerScope;Lkotlin/coroutines/Continuation;)Ljava/lang/Object;
+HSPLkotlinx/coroutines/flow/internal/ChannelFlowOperator;->collectTo(Lkotlinx/coroutines/channels/ProducerScope;Lkotlin/coroutines/Continuation;)Ljava/lang/Object;
+HSPLkotlinx/coroutines/flow/internal/ChannelFlowTransformLatest$flowCollect$3$1$2;-><init>(Lkotlinx/coroutines/flow/internal/ChannelFlowTransformLatest;Lkotlinx/coroutines/flow/FlowCollector;Ljava/lang/Object;Lkotlin/coroutines/Continuation;)V
+HSPLkotlinx/coroutines/flow/internal/ChannelFlowTransformLatest$flowCollect$3$1$2;->create(Ljava/lang/Object;Lkotlin/coroutines/Continuation;)Lkotlin/coroutines/Continuation;
+HSPLkotlinx/coroutines/flow/internal/ChannelFlowTransformLatest$flowCollect$3$1$2;->invoke(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;
+HSPLkotlinx/coroutines/flow/internal/ChannelFlowTransformLatest$flowCollect$3$1$2;->invoke(Lkotlinx/coroutines/CoroutineScope;Lkotlin/coroutines/Continuation;)Ljava/lang/Object;
+HSPLkotlinx/coroutines/flow/internal/ChannelFlowTransformLatest$flowCollect$3$1$2;->invokeSuspend(Ljava/lang/Object;)Ljava/lang/Object;
+HSPLkotlinx/coroutines/flow/internal/ChannelFlowTransformLatest$flowCollect$3$1$emit$1;-><init>(Lkotlinx/coroutines/flow/internal/ChannelFlowTransformLatest$flowCollect$3$1;Lkotlin/coroutines/Continuation;)V
+HSPLkotlinx/coroutines/flow/internal/ChannelFlowTransformLatest$flowCollect$3$1;-><init>(Lkotlin/jvm/internal/Ref$ObjectRef;Lkotlinx/coroutines/CoroutineScope;Lkotlinx/coroutines/flow/internal/ChannelFlowTransformLatest;Lkotlinx/coroutines/flow/FlowCollector;)V
+HSPLkotlinx/coroutines/flow/internal/ChannelFlowTransformLatest$flowCollect$3$1;->emit(Ljava/lang/Object;Lkotlin/coroutines/Continuation;)Ljava/lang/Object;
+HSPLkotlinx/coroutines/flow/internal/ChannelFlowTransformLatest$flowCollect$3;-><init>(Lkotlinx/coroutines/flow/internal/ChannelFlowTransformLatest;Lkotlinx/coroutines/flow/FlowCollector;Lkotlin/coroutines/Continuation;)V
+HSPLkotlinx/coroutines/flow/internal/ChannelFlowTransformLatest$flowCollect$3;->create(Ljava/lang/Object;Lkotlin/coroutines/Continuation;)Lkotlin/coroutines/Continuation;
+HSPLkotlinx/coroutines/flow/internal/ChannelFlowTransformLatest$flowCollect$3;->invoke(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;
+HSPLkotlinx/coroutines/flow/internal/ChannelFlowTransformLatest$flowCollect$3;->invoke(Lkotlinx/coroutines/CoroutineScope;Lkotlin/coroutines/Continuation;)Ljava/lang/Object;
+HSPLkotlinx/coroutines/flow/internal/ChannelFlowTransformLatest$flowCollect$3;->invokeSuspend(Ljava/lang/Object;)Ljava/lang/Object;
+HSPLkotlinx/coroutines/flow/internal/ChannelFlowTransformLatest;-><init>(Lkotlin/jvm/functions/Function3;Lkotlinx/coroutines/flow/Flow;Lkotlin/coroutines/CoroutineContext;ILkotlinx/coroutines/channels/BufferOverflow;)V
+HSPLkotlinx/coroutines/flow/internal/ChannelFlowTransformLatest;-><init>(Lkotlin/jvm/functions/Function3;Lkotlinx/coroutines/flow/Flow;Lkotlin/coroutines/CoroutineContext;ILkotlinx/coroutines/channels/BufferOverflow;ILkotlin/jvm/internal/DefaultConstructorMarker;)V
+HSPLkotlinx/coroutines/flow/internal/ChannelFlowTransformLatest;->access$getTransform$p(Lkotlinx/coroutines/flow/internal/ChannelFlowTransformLatest;)Lkotlin/jvm/functions/Function3;
+HSPLkotlinx/coroutines/flow/internal/ChannelFlowTransformLatest;->create(Lkotlin/coroutines/CoroutineContext;ILkotlinx/coroutines/channels/BufferOverflow;)Lkotlinx/coroutines/flow/internal/ChannelFlow;
+HSPLkotlinx/coroutines/flow/internal/ChannelFlowTransformLatest;->flowCollect(Lkotlinx/coroutines/flow/FlowCollector;Lkotlin/coroutines/Continuation;)Ljava/lang/Object;
+HSPLkotlinx/coroutines/flow/internal/FusibleFlow$DefaultImpls;->fuse$default(Lkotlinx/coroutines/flow/internal/FusibleFlow;Lkotlin/coroutines/CoroutineContext;ILkotlinx/coroutines/channels/BufferOverflow;ILjava/lang/Object;)Lkotlinx/coroutines/flow/Flow;
+HSPLkotlinx/coroutines/flow/internal/NoOpContinuation;-><clinit>()V
+HSPLkotlinx/coroutines/flow/internal/NoOpContinuation;-><init>()V
+HSPLkotlinx/coroutines/flow/internal/NopCollector;-><clinit>()V
+HSPLkotlinx/coroutines/flow/internal/NopCollector;-><init>()V
+HSPLkotlinx/coroutines/flow/internal/NullSurrogateKt;-><clinit>()V
+HSPLkotlinx/coroutines/flow/internal/SafeCollector$collectContextSize$1;-><clinit>()V
+HSPLkotlinx/coroutines/flow/internal/SafeCollector$collectContextSize$1;-><init>()V
+HSPLkotlinx/coroutines/flow/internal/SafeCollector$collectContextSize$1;->invoke(ILkotlin/coroutines/CoroutineContext$Element;)Ljava/lang/Integer;
+HSPLkotlinx/coroutines/flow/internal/SafeCollector$collectContextSize$1;->invoke(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;
+HSPLkotlinx/coroutines/flow/internal/SafeCollector;-><init>(Lkotlinx/coroutines/flow/FlowCollector;Lkotlin/coroutines/CoroutineContext;)V
+HSPLkotlinx/coroutines/flow/internal/SendingCollector;-><init>(Lkotlinx/coroutines/channels/SendChannel;)V
+HSPLkotlinx/coroutines/flow/internal/SendingCollector;->emit(Ljava/lang/Object;Lkotlin/coroutines/Continuation;)Ljava/lang/Object;
+HSPLkotlinx/coroutines/flow/internal/SubscriptionCountStateFlow;-><init>(I)V
+HSPLkotlinx/coroutines/flow/internal/SubscriptionCountStateFlow;->increment(I)Z
+HSPLkotlinx/coroutines/internal/AtomicKt;-><clinit>()V
+HSPLkotlinx/coroutines/internal/AtomicOp;-><init>()V
+HSPLkotlinx/coroutines/internal/AtomicOp;->decide(Ljava/lang/Object;)Ljava/lang/Object;
+HSPLkotlinx/coroutines/internal/AtomicOp;->perform(Ljava/lang/Object;)Ljava/lang/Object;
+HSPLkotlinx/coroutines/internal/ContextScope;-><init>(Lkotlin/coroutines/CoroutineContext;)V
+HSPLkotlinx/coroutines/internal/ContextScope;->getCoroutineContext()Lkotlin/coroutines/CoroutineContext;
+HSPLkotlinx/coroutines/internal/DispatchedContinuation;-><init>(Lkotlinx/coroutines/CoroutineDispatcher;Lkotlin/coroutines/Continuation;)V
+HSPLkotlinx/coroutines/internal/DispatchedContinuation;->awaitReusability()V
+HSPLkotlinx/coroutines/internal/DispatchedContinuation;->cancelCompletedResult$external__kotlinx_coroutines__android_common__kotlinx_coroutines(Ljava/lang/Object;Ljava/lang/Throwable;)V
+HSPLkotlinx/coroutines/internal/DispatchedContinuation;->claimReusableCancellableContinuation()Lkotlinx/coroutines/CancellableContinuationImpl;
+HSPLkotlinx/coroutines/internal/DispatchedContinuation;->getContext()Lkotlin/coroutines/CoroutineContext;
+HSPLkotlinx/coroutines/internal/DispatchedContinuation;->getDelegate$external__kotlinx_coroutines__android_common__kotlinx_coroutines()Lkotlin/coroutines/Continuation;
+HSPLkotlinx/coroutines/internal/DispatchedContinuation;->getReusableCancellableContinuation()Lkotlinx/coroutines/CancellableContinuationImpl;
+HSPLkotlinx/coroutines/internal/DispatchedContinuation;->isReusable()Z
+HSPLkotlinx/coroutines/internal/DispatchedContinuation;->release()V
+HSPLkotlinx/coroutines/internal/DispatchedContinuation;->resumeWith(Ljava/lang/Object;)V
+HSPLkotlinx/coroutines/internal/DispatchedContinuation;->takeState$external__kotlinx_coroutines__android_common__kotlinx_coroutines()Ljava/lang/Object;
+HSPLkotlinx/coroutines/internal/DispatchedContinuation;->tryReleaseClaimedContinuation(Lkotlinx/coroutines/CancellableContinuation;)Ljava/lang/Throwable;
+HSPLkotlinx/coroutines/internal/DispatchedContinuationKt;-><clinit>()V
+HSPLkotlinx/coroutines/internal/DispatchedContinuationKt;->access$getUNDEFINED$p()Lkotlinx/coroutines/internal/Symbol;
+HSPLkotlinx/coroutines/internal/DispatchedContinuationKt;->resumeCancellableWith(Lkotlin/coroutines/Continuation;Ljava/lang/Object;Lkotlin/jvm/functions/Function1;)V
+HSPLkotlinx/coroutines/internal/FastServiceLoader;-><clinit>()V
+HSPLkotlinx/coroutines/internal/FastServiceLoader;-><init>()V
+HSPLkotlinx/coroutines/internal/FastServiceLoader;->loadMainDispatcherFactory$external__kotlinx_coroutines__android_common__kotlinx_coroutines()Ljava/util/List;
+HSPLkotlinx/coroutines/internal/FastServiceLoaderKt;-><clinit>()V
+HSPLkotlinx/coroutines/internal/FastServiceLoaderKt;->getANDROID_DETECTED()Z
+HSPLkotlinx/coroutines/internal/LimitedDispatcher;-><init>(Lkotlinx/coroutines/CoroutineDispatcher;I)V
+HSPLkotlinx/coroutines/internal/LimitedDispatcherKt;->checkParallelism(I)V
+HSPLkotlinx/coroutines/internal/LockFreeLinkedListHead;-><init>()V
+HSPLkotlinx/coroutines/internal/LockFreeLinkedListHead;->isRemoved()Z
+HSPLkotlinx/coroutines/internal/LockFreeLinkedListKt;-><clinit>()V
+HSPLkotlinx/coroutines/internal/LockFreeLinkedListKt;->unwrap(Ljava/lang/Object;)Lkotlinx/coroutines/internal/LockFreeLinkedListNode;
+HSPLkotlinx/coroutines/internal/LockFreeLinkedListNode$CondAddOp;-><init>(Lkotlinx/coroutines/internal/LockFreeLinkedListNode;)V
+HSPLkotlinx/coroutines/internal/LockFreeLinkedListNode$CondAddOp;->complete(Ljava/lang/Object;Ljava/lang/Object;)V
+HSPLkotlinx/coroutines/internal/LockFreeLinkedListNode$CondAddOp;->complete(Lkotlinx/coroutines/internal/LockFreeLinkedListNode;Ljava/lang/Object;)V
+HSPLkotlinx/coroutines/internal/LockFreeLinkedListNode;-><init>()V
+HSPLkotlinx/coroutines/internal/LockFreeLinkedListNode;->access$finishAdd(Lkotlinx/coroutines/internal/LockFreeLinkedListNode;Lkotlinx/coroutines/internal/LockFreeLinkedListNode;)V
+HSPLkotlinx/coroutines/internal/LockFreeLinkedListNode;->access$get_next$p(Lkotlinx/coroutines/internal/LockFreeLinkedListNode;)Lkotlinx/atomicfu/AtomicRef;
+HSPLkotlinx/coroutines/internal/LockFreeLinkedListNode;->addNext(Lkotlinx/coroutines/internal/LockFreeLinkedListNode;Lkotlinx/coroutines/internal/LockFreeLinkedListNode;)Z
+HSPLkotlinx/coroutines/internal/LockFreeLinkedListNode;->addOneIfEmpty(Lkotlinx/coroutines/internal/LockFreeLinkedListNode;)Z
+HSPLkotlinx/coroutines/internal/LockFreeLinkedListNode;->correctPrev(Lkotlinx/coroutines/internal/OpDescriptor;)Lkotlinx/coroutines/internal/LockFreeLinkedListNode;
+HSPLkotlinx/coroutines/internal/LockFreeLinkedListNode;->finishAdd(Lkotlinx/coroutines/internal/LockFreeLinkedListNode;)V
+HSPLkotlinx/coroutines/internal/LockFreeLinkedListNode;->getNext()Ljava/lang/Object;
+HSPLkotlinx/coroutines/internal/LockFreeLinkedListNode;->getNextNode()Lkotlinx/coroutines/internal/LockFreeLinkedListNode;
+HSPLkotlinx/coroutines/internal/LockFreeLinkedListNode;->getPrevNode()Lkotlinx/coroutines/internal/LockFreeLinkedListNode;
+HSPLkotlinx/coroutines/internal/LockFreeLinkedListNode;->isRemoved()Z
+HSPLkotlinx/coroutines/internal/LockFreeLinkedListNode;->remove()Z
+HSPLkotlinx/coroutines/internal/LockFreeLinkedListNode;->removeOrNext()Lkotlinx/coroutines/internal/LockFreeLinkedListNode;
+HSPLkotlinx/coroutines/internal/LockFreeLinkedListNode;->removed()Lkotlinx/coroutines/internal/Removed;
+HSPLkotlinx/coroutines/internal/LockFreeLinkedListNode;->tryCondAddNext(Lkotlinx/coroutines/internal/LockFreeLinkedListNode;Lkotlinx/coroutines/internal/LockFreeLinkedListNode;Lkotlinx/coroutines/internal/LockFreeLinkedListNode$CondAddOp;)I
+HSPLkotlinx/coroutines/internal/LockFreeTaskQueue;-><init>(Z)V
+HSPLkotlinx/coroutines/internal/LockFreeTaskQueueCore$Companion;-><init>()V
+HSPLkotlinx/coroutines/internal/LockFreeTaskQueueCore$Companion;-><init>(Lkotlin/jvm/internal/DefaultConstructorMarker;)V
+HSPLkotlinx/coroutines/internal/LockFreeTaskQueueCore;-><clinit>()V
+HSPLkotlinx/coroutines/internal/LockFreeTaskQueueCore;-><init>(IZ)V
+HSPLkotlinx/coroutines/internal/MainDispatcherLoader;-><clinit>()V
+HSPLkotlinx/coroutines/internal/MainDispatcherLoader;-><init>()V
+HSPLkotlinx/coroutines/internal/MainDispatcherLoader;->loadMainDispatcher()Lkotlinx/coroutines/MainCoroutineDispatcher;
+HSPLkotlinx/coroutines/internal/MainDispatchersKt;-><clinit>()V
+HSPLkotlinx/coroutines/internal/MainDispatchersKt;->tryCreateDispatcher(Lkotlinx/coroutines/internal/MainDispatcherFactory;Ljava/util/List;)Lkotlinx/coroutines/MainCoroutineDispatcher;
+HSPLkotlinx/coroutines/internal/OpDescriptor;-><init>()V
+HSPLkotlinx/coroutines/internal/Removed;-><init>(Lkotlinx/coroutines/internal/LockFreeLinkedListNode;)V
+HSPLkotlinx/coroutines/internal/ResizableAtomicArray;-><init>(I)V
+HSPLkotlinx/coroutines/internal/ScopeCoroutine;-><init>(Lkotlin/coroutines/CoroutineContext;Lkotlin/coroutines/Continuation;)V
+HSPLkotlinx/coroutines/internal/ScopeCoroutine;->afterResume(Ljava/lang/Object;)V
+HSPLkotlinx/coroutines/internal/ScopeCoroutine;->isScopedCoroutine()Z
+HSPLkotlinx/coroutines/internal/Symbol;-><init>(Ljava/lang/String;)V
+HSPLkotlinx/coroutines/internal/SystemPropsKt;->getAVAILABLE_PROCESSORS()I
+HSPLkotlinx/coroutines/internal/SystemPropsKt;->systemProp$default(Ljava/lang/String;IIIILjava/lang/Object;)I
+HSPLkotlinx/coroutines/internal/SystemPropsKt;->systemProp$default(Ljava/lang/String;JJJILjava/lang/Object;)J
+HSPLkotlinx/coroutines/internal/SystemPropsKt;->systemProp(Ljava/lang/String;)Ljava/lang/String;
+HSPLkotlinx/coroutines/internal/SystemPropsKt;->systemProp(Ljava/lang/String;III)I
+HSPLkotlinx/coroutines/internal/SystemPropsKt;->systemProp(Ljava/lang/String;JJJ)J
+HSPLkotlinx/coroutines/internal/SystemPropsKt;->systemProp(Ljava/lang/String;Z)Z
+HSPLkotlinx/coroutines/internal/SystemPropsKt__SystemPropsKt;-><clinit>()V
+HSPLkotlinx/coroutines/internal/SystemPropsKt__SystemPropsKt;->getAVAILABLE_PROCESSORS()I
+HSPLkotlinx/coroutines/internal/SystemPropsKt__SystemPropsKt;->systemProp(Ljava/lang/String;)Ljava/lang/String;
+HSPLkotlinx/coroutines/internal/SystemPropsKt__SystemProps_commonKt;->systemProp$default(Ljava/lang/String;IIIILjava/lang/Object;)I
+HSPLkotlinx/coroutines/internal/SystemPropsKt__SystemProps_commonKt;->systemProp$default(Ljava/lang/String;JJJILjava/lang/Object;)J
+HSPLkotlinx/coroutines/internal/SystemPropsKt__SystemProps_commonKt;->systemProp(Ljava/lang/String;III)I
+HSPLkotlinx/coroutines/internal/SystemPropsKt__SystemProps_commonKt;->systemProp(Ljava/lang/String;JJJ)J
+HSPLkotlinx/coroutines/internal/SystemPropsKt__SystemProps_commonKt;->systemProp(Ljava/lang/String;Z)Z
+HSPLkotlinx/coroutines/internal/ThreadContextKt$countAll$1;-><clinit>()V
+HSPLkotlinx/coroutines/internal/ThreadContextKt$countAll$1;-><init>()V
+HSPLkotlinx/coroutines/internal/ThreadContextKt$countAll$1;->invoke(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;
+HSPLkotlinx/coroutines/internal/ThreadContextKt$countAll$1;->invoke(Ljava/lang/Object;Lkotlin/coroutines/CoroutineContext$Element;)Ljava/lang/Object;
+HSPLkotlinx/coroutines/internal/ThreadContextKt$findOne$1;-><clinit>()V
+HSPLkotlinx/coroutines/internal/ThreadContextKt$findOne$1;-><init>()V
+HSPLkotlinx/coroutines/internal/ThreadContextKt$updateState$1;-><clinit>()V
+HSPLkotlinx/coroutines/internal/ThreadContextKt$updateState$1;-><init>()V
+HSPLkotlinx/coroutines/internal/ThreadContextKt;-><clinit>()V
+HSPLkotlinx/coroutines/internal/ThreadContextKt;->restoreThreadContext(Lkotlin/coroutines/CoroutineContext;Ljava/lang/Object;)V
+HSPLkotlinx/coroutines/internal/ThreadContextKt;->threadContextElements(Lkotlin/coroutines/CoroutineContext;)Ljava/lang/Object;
+HSPLkotlinx/coroutines/internal/ThreadContextKt;->updateThreadContext(Lkotlin/coroutines/CoroutineContext;Ljava/lang/Object;)Ljava/lang/Object;
+HSPLkotlinx/coroutines/intrinsics/CancellableKt;->startCoroutineCancellable$default(Lkotlin/jvm/functions/Function2;Ljava/lang/Object;Lkotlin/coroutines/Continuation;Lkotlin/jvm/functions/Function1;ILjava/lang/Object;)V
+HSPLkotlinx/coroutines/intrinsics/CancellableKt;->startCoroutineCancellable(Lkotlin/jvm/functions/Function2;Ljava/lang/Object;Lkotlin/coroutines/Continuation;Lkotlin/jvm/functions/Function1;)V
+HSPLkotlinx/coroutines/intrinsics/UndispatchedKt;->startCoroutineUndispatched(Lkotlin/jvm/functions/Function2;Ljava/lang/Object;Lkotlin/coroutines/Continuation;)V
+HSPLkotlinx/coroutines/intrinsics/UndispatchedKt;->startUndispatchedOrReturn(Lkotlinx/coroutines/internal/ScopeCoroutine;Ljava/lang/Object;Lkotlin/jvm/functions/Function2;)Ljava/lang/Object;
+HSPLkotlinx/coroutines/scheduling/CoroutineScheduler$Companion;-><init>()V
+HSPLkotlinx/coroutines/scheduling/CoroutineScheduler$Companion;-><init>(Lkotlin/jvm/internal/DefaultConstructorMarker;)V
+HSPLkotlinx/coroutines/scheduling/CoroutineScheduler;-><clinit>()V
+HSPLkotlinx/coroutines/scheduling/CoroutineScheduler;-><init>(IIJLjava/lang/String;)V
+HSPLkotlinx/coroutines/scheduling/DefaultIoScheduler;-><clinit>()V
+HSPLkotlinx/coroutines/scheduling/DefaultIoScheduler;-><init>()V
+HSPLkotlinx/coroutines/scheduling/DefaultScheduler;-><clinit>()V
+HSPLkotlinx/coroutines/scheduling/DefaultScheduler;-><init>()V
+HSPLkotlinx/coroutines/scheduling/GlobalQueue;-><init>()V
+HSPLkotlinx/coroutines/scheduling/NanoTimeSource;-><clinit>()V
+HSPLkotlinx/coroutines/scheduling/NanoTimeSource;-><init>()V
+HSPLkotlinx/coroutines/scheduling/SchedulerCoroutineDispatcher;-><init>(IIJLjava/lang/String;)V
+HSPLkotlinx/coroutines/scheduling/SchedulerCoroutineDispatcher;->createScheduler()Lkotlinx/coroutines/scheduling/CoroutineScheduler;
+HSPLkotlinx/coroutines/scheduling/SchedulerTimeSource;-><init>()V
+HSPLkotlinx/coroutines/scheduling/Task;-><init>()V
+HSPLkotlinx/coroutines/scheduling/Task;-><init>(JLkotlinx/coroutines/scheduling/TaskContext;)V
+HSPLkotlinx/coroutines/scheduling/TaskContextImpl;-><init>(I)V
+HSPLkotlinx/coroutines/scheduling/TaskContextImpl;->afterTask()V
+HSPLkotlinx/coroutines/scheduling/TasksKt;-><clinit>()V
+HSPLkotlinx/coroutines/scheduling/UnlimitedIoScheduler;-><clinit>()V
+HSPLkotlinx/coroutines/scheduling/UnlimitedIoScheduler;-><init>()V
+HSPLkotlinx/coroutines/sync/Empty;-><init>(Ljava/lang/Object;)V
+HSPLkotlinx/coroutines/sync/Mutex$DefaultImpls;->lock$default(Lkotlinx/coroutines/sync/Mutex;Ljava/lang/Object;Lkotlin/coroutines/Continuation;ILjava/lang/Object;)Ljava/lang/Object;
+HSPLkotlinx/coroutines/sync/MutexImpl;-><init>(Z)V
+HSPLkotlinx/coroutines/sync/MutexImpl;->lock(Ljava/lang/Object;Lkotlin/coroutines/Continuation;)Ljava/lang/Object;
+HSPLkotlinx/coroutines/sync/MutexImpl;->tryLock(Ljava/lang/Object;)Z
+HSPLkotlinx/coroutines/sync/MutexImpl;->unlock(Ljava/lang/Object;)V
+HSPLkotlinx/coroutines/sync/MutexKt;-><clinit>()V
+HSPLkotlinx/coroutines/sync/MutexKt;->Mutex$default(ZILjava/lang/Object;)Lkotlinx/coroutines/sync/Mutex;
+HSPLkotlinx/coroutines/sync/MutexKt;->Mutex(Z)Lkotlinx/coroutines/sync/Mutex;
+HSPLkotlinx/coroutines/sync/MutexKt;->access$getEMPTY_LOCKED$p()Lkotlinx/coroutines/sync/Empty;
+HSPLkotlinx/coroutines/sync/MutexKt;->access$getEMPTY_UNLOCKED$p()Lkotlinx/coroutines/sync/Empty;
+HSPLkotlinx/coroutines/sync/MutexKt;->access$getUNLOCKED$p()Lkotlinx/coroutines/internal/Symbol;
+Landroidx/activity/Cancellable;
+Landroidx/activity/ComponentActivity$$ExternalSyntheticLambda0;
+Landroidx/activity/ComponentActivity$$ExternalSyntheticLambda1;
+Landroidx/activity/ComponentActivity$$ExternalSyntheticLambda2;
+Landroidx/activity/ComponentActivity$$ExternalSyntheticLambda3;
+Landroidx/activity/ComponentActivity$1;
+Landroidx/activity/ComponentActivity$2$2;
+Landroidx/activity/ComponentActivity$2;
+Landroidx/activity/ComponentActivity$3;
+Landroidx/activity/ComponentActivity$4;
+Landroidx/activity/ComponentActivity$5;
+Landroidx/activity/ComponentActivity$Api19Impl;
+Landroidx/activity/ComponentActivity$Api33Impl;
+Landroidx/activity/ComponentActivity$NonConfigurationInstances;
+Landroidx/activity/ComponentActivity$ReportFullyDrawnExecutor;
+Landroidx/activity/ComponentActivity$ReportFullyDrawnExecutorApi16Impl$$ExternalSyntheticLambda0;
+Landroidx/activity/ComponentActivity$ReportFullyDrawnExecutorApi16Impl;
+Landroidx/activity/ComponentActivity;
+Landroidx/activity/FullyDrawnReporter$$ExternalSyntheticLambda0;
+Landroidx/activity/FullyDrawnReporter;
+Landroidx/activity/FullyDrawnReporterOwner;
+Landroidx/activity/OnBackPressedCallback;
+Landroidx/activity/OnBackPressedDispatcher$$ExternalSyntheticLambda1;
+Landroidx/activity/OnBackPressedDispatcher$$ExternalSyntheticLambda2;
+Landroidx/activity/OnBackPressedDispatcher$$ExternalSyntheticThrowCCEIfNotNull0;
+Landroidx/activity/OnBackPressedDispatcher$Api33Impl$$ExternalSyntheticLambda0;
+Landroidx/activity/OnBackPressedDispatcher$Api33Impl;
+Landroidx/activity/OnBackPressedDispatcher$OnBackPressedCancellable;
+Landroidx/activity/OnBackPressedDispatcher;
+Landroidx/activity/OnBackPressedDispatcherOwner;
+Landroidx/activity/R$id;
+Landroidx/activity/ViewTreeFullyDrawnReporterOwner;
+Landroidx/activity/ViewTreeOnBackPressedDispatcherOwner;
+Landroidx/activity/compose/ActivityResultLauncherHolder;
+Landroidx/activity/compose/ActivityResultRegistryKt$rememberLauncherForActivityResult$1$1;
+Landroidx/activity/compose/ActivityResultRegistryKt$rememberLauncherForActivityResult$1$invoke$$inlined$onDispose$1;
+Landroidx/activity/compose/ActivityResultRegistryKt$rememberLauncherForActivityResult$1;
+Landroidx/activity/compose/ActivityResultRegistryKt$rememberLauncherForActivityResult$key$1;
+Landroidx/activity/compose/ActivityResultRegistryKt;
+Landroidx/activity/compose/ComponentActivityKt;
+Landroidx/activity/compose/LocalActivityResultRegistryOwner$LocalComposition$1;
+Landroidx/activity/compose/LocalActivityResultRegistryOwner;
+Landroidx/activity/compose/ManagedActivityResultLauncher;
+Landroidx/activity/contextaware/ContextAwareHelper;
+Landroidx/activity/contextaware/OnContextAvailableListener;
+Landroidx/activity/result/ActivityResult;
+Landroidx/activity/result/ActivityResultCallback;
+Landroidx/activity/result/ActivityResultLauncher;
+Landroidx/activity/result/ActivityResultRegistry$3;
+Landroidx/activity/result/ActivityResultRegistry$CallbackAndContract;
+Landroidx/activity/result/ActivityResultRegistry;
+Landroidx/activity/result/ActivityResultRegistryOwner;
+Landroidx/activity/result/IntentSenderRequest$Builder;
+Landroidx/activity/result/IntentSenderRequest;
+Landroidx/activity/result/contract/ActivityResultContract$SynchronousResult;
+Landroidx/activity/result/contract/ActivityResultContract;
+Landroidx/activity/result/contract/ActivityResultContracts$StartIntentSenderForResult$Companion;
+Landroidx/activity/result/contract/ActivityResultContracts$StartIntentSenderForResult;
+Landroidx/arch/core/executor/ArchTaskExecutor$$ExternalSyntheticLambda0;
+Landroidx/arch/core/executor/ArchTaskExecutor$$ExternalSyntheticLambda1;
+Landroidx/arch/core/executor/ArchTaskExecutor;
+Landroidx/arch/core/executor/DefaultTaskExecutor$1;
+Landroidx/arch/core/executor/DefaultTaskExecutor$Api28Impl;
+Landroidx/arch/core/executor/DefaultTaskExecutor;
+Landroidx/arch/core/executor/TaskExecutor;
+Landroidx/arch/core/internal/FastSafeIterableMap;
+Landroidx/arch/core/internal/SafeIterableMap$AscendingIterator;
+Landroidx/arch/core/internal/SafeIterableMap$DescendingIterator;
+Landroidx/arch/core/internal/SafeIterableMap$Entry;
+Landroidx/arch/core/internal/SafeIterableMap$IteratorWithAdditions;
+Landroidx/arch/core/internal/SafeIterableMap$ListIterator;
+Landroidx/arch/core/internal/SafeIterableMap$SupportRemove;
+Landroidx/arch/core/internal/SafeIterableMap;
+Landroidx/collection/ArraySet$Companion;
+Landroidx/collection/ArraySet$ElementIterator;
+Landroidx/collection/ArraySet;
+Landroidx/collection/IndexBasedArrayIterator;
+Landroidx/collection/LruCache;
+Landroidx/collection/SimpleArrayMap;
+Landroidx/collection/SparseArrayCompat;
+Landroidx/collection/SparseArrayCompatKt;
+Landroidx/collection/internal/ContainerHelpersKt;
+Landroidx/collection/internal/Lock;
+Landroidx/collection/internal/LruHashMap;
+Landroidx/compose/animation/core/Animatable$runAnimation$2$1;
+Landroidx/compose/animation/core/Animatable$runAnimation$2;
+Landroidx/compose/animation/core/Animatable$snapTo$2;
+Landroidx/compose/animation/core/Animatable;
+Landroidx/compose/animation/core/AnimatableKt;
+Landroidx/compose/animation/core/AnimateAsStateKt$animateValueAsState$2;
+Landroidx/compose/animation/core/AnimateAsStateKt$animateValueAsState$3$1;
+Landroidx/compose/animation/core/AnimateAsStateKt$animateValueAsState$3;
+Landroidx/compose/animation/core/AnimateAsStateKt;
+Landroidx/compose/animation/core/Animation;
+Landroidx/compose/animation/core/AnimationEndReason;
+Landroidx/compose/animation/core/AnimationKt;
+Landroidx/compose/animation/core/AnimationResult;
+Landroidx/compose/animation/core/AnimationScope;
+Landroidx/compose/animation/core/AnimationSpec;
+Landroidx/compose/animation/core/AnimationSpecKt;
+Landroidx/compose/animation/core/AnimationState;
+Landroidx/compose/animation/core/AnimationStateKt;
+Landroidx/compose/animation/core/AnimationVector1D;
+Landroidx/compose/animation/core/AnimationVector2D;
+Landroidx/compose/animation/core/AnimationVector4D;
+Landroidx/compose/animation/core/AnimationVector;
+Landroidx/compose/animation/core/AnimationVectorsKt;
+Landroidx/compose/animation/core/Animations;
+Landroidx/compose/animation/core/CubicBezierEasing;
+Landroidx/compose/animation/core/DecayAnimation;
+Landroidx/compose/animation/core/DecayAnimationSpec;
+Landroidx/compose/animation/core/Easing;
+Landroidx/compose/animation/core/EasingKt$LinearEasing$1;
+Landroidx/compose/animation/core/EasingKt;
+Landroidx/compose/animation/core/FiniteAnimationSpec;
+Landroidx/compose/animation/core/FloatAnimationSpec;
+Landroidx/compose/animation/core/FloatTweenSpec;
+Landroidx/compose/animation/core/InfiniteAnimationPolicyKt;
+Landroidx/compose/animation/core/MutatePriority;
+Landroidx/compose/animation/core/MutatorMutex$Mutator;
+Landroidx/compose/animation/core/MutatorMutex$mutate$2;
+Landroidx/compose/animation/core/MutatorMutex;
+Landroidx/compose/animation/core/SpringSpec;
+Landroidx/compose/animation/core/SuspendAnimationKt$animate$3;
+Landroidx/compose/animation/core/SuspendAnimationKt$animate$4;
+Landroidx/compose/animation/core/SuspendAnimationKt$animate$5;
+Landroidx/compose/animation/core/SuspendAnimationKt$animate$6$1;
+Landroidx/compose/animation/core/SuspendAnimationKt$animate$6;
+Landroidx/compose/animation/core/SuspendAnimationKt$animate$7;
+Landroidx/compose/animation/core/SuspendAnimationKt$animate$9;
+Landroidx/compose/animation/core/SuspendAnimationKt$animateDecay$4;
+Landroidx/compose/animation/core/SuspendAnimationKt$callWithFrameNanos$2;
+Landroidx/compose/animation/core/SuspendAnimationKt;
+Landroidx/compose/animation/core/TargetBasedAnimation;
+Landroidx/compose/animation/core/TweenSpec;
+Landroidx/compose/animation/core/TwoWayConverter;
+Landroidx/compose/animation/core/TwoWayConverterImpl;
+Landroidx/compose/animation/core/VectorConvertersKt$DpOffsetToVector$1;
+Landroidx/compose/animation/core/VectorConvertersKt$DpOffsetToVector$2;
+Landroidx/compose/animation/core/VectorConvertersKt$DpToVector$1;
+Landroidx/compose/animation/core/VectorConvertersKt$DpToVector$2;
+Landroidx/compose/animation/core/VectorConvertersKt$FloatToVector$1;
+Landroidx/compose/animation/core/VectorConvertersKt$FloatToVector$2;
+Landroidx/compose/animation/core/VectorConvertersKt$IntOffsetToVector$1;
+Landroidx/compose/animation/core/VectorConvertersKt$IntOffsetToVector$2;
+Landroidx/compose/animation/core/VectorConvertersKt$IntSizeToVector$1;
+Landroidx/compose/animation/core/VectorConvertersKt$IntSizeToVector$2;
+Landroidx/compose/animation/core/VectorConvertersKt$IntToVector$1;
+Landroidx/compose/animation/core/VectorConvertersKt$IntToVector$2;
+Landroidx/compose/animation/core/VectorConvertersKt$OffsetToVector$1;
+Landroidx/compose/animation/core/VectorConvertersKt$OffsetToVector$2;
+Landroidx/compose/animation/core/VectorConvertersKt$RectToVector$1;
+Landroidx/compose/animation/core/VectorConvertersKt$RectToVector$2;
+Landroidx/compose/animation/core/VectorConvertersKt$SizeToVector$1;
+Landroidx/compose/animation/core/VectorConvertersKt$SizeToVector$2;
+Landroidx/compose/animation/core/VectorConvertersKt;
+Landroidx/compose/animation/core/VectorizedAnimationSpec;
+Landroidx/compose/animation/core/VectorizedDurationBasedAnimationSpec;
+Landroidx/compose/animation/core/VectorizedFiniteAnimationSpec;
+Landroidx/compose/animation/core/VectorizedFloatAnimationSpec$1;
+Landroidx/compose/animation/core/VectorizedFloatAnimationSpec;
+Landroidx/compose/animation/core/VectorizedSpringSpec;
+Landroidx/compose/animation/core/VectorizedTweenSpec;
+Landroidx/compose/animation/core/VisibilityThresholdsKt;
+Landroidx/compose/foundation/Background;
+Landroidx/compose/foundation/BackgroundKt$background-bw27NRU$$inlined$debugInspectorInfo$1;
+Landroidx/compose/foundation/BackgroundKt;
+Landroidx/compose/foundation/BorderKt;
+Landroidx/compose/foundation/BorderStroke;
+Landroidx/compose/foundation/CanvasKt$Canvas$1;
+Landroidx/compose/foundation/CanvasKt;
+Landroidx/compose/foundation/ClickableKt$PressedInteractionSourceDisposableEffect$1$invoke$$inlined$onDispose$1;
+Landroidx/compose/foundation/ClickableKt$PressedInteractionSourceDisposableEffect$1;
+Landroidx/compose/foundation/ClickableKt$PressedInteractionSourceDisposableEffect$2;
+Landroidx/compose/foundation/ClickableKt$clickable$4$1$1$1;
+Landroidx/compose/foundation/ClickableKt$clickable$4$1$1;
+Landroidx/compose/foundation/ClickableKt$clickable$4$delayPressInteraction$1$1;
+Landroidx/compose/foundation/ClickableKt$clickable$4$gesture$1$1$1;
+Landroidx/compose/foundation/ClickableKt$clickable$4$gesture$1$1$2;
+Landroidx/compose/foundation/ClickableKt$clickable$4$gesture$1$1;
+Landroidx/compose/foundation/ClickableKt$clickable$4;
+Landroidx/compose/foundation/ClickableKt$clickable-O2vRcR0$$inlined$debugInspectorInfo$1;
+Landroidx/compose/foundation/ClickableKt$genericClickableWithoutGesture$clickSemantics$1$1;
+Landroidx/compose/foundation/ClickableKt$genericClickableWithoutGesture$clickSemantics$1$2;
+Landroidx/compose/foundation/ClickableKt$genericClickableWithoutGesture$clickSemantics$1;
+Landroidx/compose/foundation/ClickableKt$genericClickableWithoutGesture$detectPressAndClickFromKey$1$1;
+Landroidx/compose/foundation/ClickableKt$genericClickableWithoutGesture$detectPressAndClickFromKey$1$2$1;
+Landroidx/compose/foundation/ClickableKt$genericClickableWithoutGesture$detectPressAndClickFromKey$1;
+Landroidx/compose/foundation/ClickableKt$handlePressInteraction$2;
+Landroidx/compose/foundation/ClickableKt;
+Landroidx/compose/foundation/Clickable_androidKt;
+Landroidx/compose/foundation/DarkThemeKt;
+Landroidx/compose/foundation/DarkTheme_androidKt;
+Landroidx/compose/foundation/DefaultDebugIndication;
+Landroidx/compose/foundation/FocusableKt$focusGroup$1;
+Landroidx/compose/foundation/FocusableKt$focusable$$inlined$debugInspectorInfo$1;
+Landroidx/compose/foundation/FocusableKt$focusable$2$1$1$invoke$$inlined$onDispose$1;
+Landroidx/compose/foundation/FocusableKt$focusable$2$1$1;
+Landroidx/compose/foundation/FocusableKt$focusable$2$2$1;
+Landroidx/compose/foundation/FocusableKt$focusable$2$2$invoke$$inlined$onDispose$1;
+Landroidx/compose/foundation/FocusableKt$focusable$2$2;
+Landroidx/compose/foundation/FocusableKt$focusable$2$3$1;
+Landroidx/compose/foundation/FocusableKt$focusable$2$3;
+Landroidx/compose/foundation/FocusableKt$focusable$2$4$1;
+Landroidx/compose/foundation/FocusableKt$focusable$2$5$1;
+Landroidx/compose/foundation/FocusableKt$focusable$2$5$2;
+Landroidx/compose/foundation/FocusableKt$focusable$2$5$3;
+Landroidx/compose/foundation/FocusableKt$focusable$2$5;
+Landroidx/compose/foundation/FocusableKt$focusable$2;
+Landroidx/compose/foundation/FocusableKt$focusableInNonTouchMode$$inlined$debugInspectorInfo$1;
+Landroidx/compose/foundation/FocusableKt$focusableInNonTouchMode$2$1;
+Landroidx/compose/foundation/FocusableKt$focusableInNonTouchMode$2;
+Landroidx/compose/foundation/FocusableKt$onPinnableParentAvailable$$inlined$debugInspectorInfo$1;
+Landroidx/compose/foundation/FocusableKt$special$$inlined$debugInspectorInfo$1;
+Landroidx/compose/foundation/FocusableKt;
+Landroidx/compose/foundation/FocusedBoundsModifier;
+Landroidx/compose/foundation/HoverableKt$hoverable$$inlined$debugInspectorInfo$1;
+Landroidx/compose/foundation/HoverableKt$hoverable$2$1$1$invoke$$inlined$onDispose$1;
+Landroidx/compose/foundation/HoverableKt$hoverable$2$1$1;
+Landroidx/compose/foundation/HoverableKt$hoverable$2$2$1;
+Landroidx/compose/foundation/HoverableKt$hoverable$2$3$1$1;
+Landroidx/compose/foundation/HoverableKt$hoverable$2$3$1$2;
+Landroidx/compose/foundation/HoverableKt$hoverable$2$3$1;
+Landroidx/compose/foundation/HoverableKt$hoverable$2$3;
+Landroidx/compose/foundation/HoverableKt$hoverable$2$invoke$emitEnter$1;
+Landroidx/compose/foundation/HoverableKt$hoverable$2$invoke$emitExit$1;
+Landroidx/compose/foundation/HoverableKt$hoverable$2;
+Landroidx/compose/foundation/HoverableKt;
+Landroidx/compose/foundation/ImageKt;
+Landroidx/compose/foundation/Indication;
+Landroidx/compose/foundation/IndicationInstance;
+Landroidx/compose/foundation/IndicationKt$LocalIndication$1;
+Landroidx/compose/foundation/IndicationKt$indication$$inlined$debugInspectorInfo$1;
+Landroidx/compose/foundation/IndicationKt$indication$2;
+Landroidx/compose/foundation/IndicationKt;
+Landroidx/compose/foundation/IndicationModifier;
+Landroidx/compose/foundation/MutatePriority;
+Landroidx/compose/foundation/MutatorMutex$Mutator;
+Landroidx/compose/foundation/MutatorMutex$mutateWith$2;
+Landroidx/compose/foundation/MutatorMutex;
+Landroidx/compose/foundation/NoIndication;
+Landroidx/compose/foundation/PinnableParentConsumer;
+Landroidx/compose/foundation/gestures/DefaultDraggableState$drag$2;
+Landroidx/compose/foundation/gestures/DefaultDraggableState$dragScope$1;
+Landroidx/compose/foundation/gestures/DefaultDraggableState;
+Landroidx/compose/foundation/gestures/DragEvent$DragCancelled;
+Landroidx/compose/foundation/gestures/DragEvent$DragDelta;
+Landroidx/compose/foundation/gestures/DragEvent$DragStarted;
+Landroidx/compose/foundation/gestures/DragEvent$DragStopped;
+Landroidx/compose/foundation/gestures/DragEvent;
+Landroidx/compose/foundation/gestures/DragGestureDetectorKt;
+Landroidx/compose/foundation/gestures/DragLogic$processDragCancel$1;
+Landroidx/compose/foundation/gestures/DragLogic$processDragStart$1;
+Landroidx/compose/foundation/gestures/DragLogic$processDragStop$1;
+Landroidx/compose/foundation/gestures/DragLogic;
+Landroidx/compose/foundation/gestures/DragScope;
+Landroidx/compose/foundation/gestures/DraggableKt$awaitDownAndSlop$1;
+Landroidx/compose/foundation/gestures/DraggableKt$awaitDownAndSlop$postPointerSlop$1;
+Landroidx/compose/foundation/gestures/DraggableKt$awaitDrag$dragTick$1;
+Landroidx/compose/foundation/gestures/DraggableKt$draggable$$inlined$debugInspectorInfo$1;
+Landroidx/compose/foundation/gestures/DraggableKt$draggable$1;
+Landroidx/compose/foundation/gestures/DraggableKt$draggable$2;
+Landroidx/compose/foundation/gestures/DraggableKt$draggable$3;
+Landroidx/compose/foundation/gestures/DraggableKt$draggable$4;
+Landroidx/compose/foundation/gestures/DraggableKt$draggable$5;
+Landroidx/compose/foundation/gestures/DraggableKt$draggable$6;
+Landroidx/compose/foundation/gestures/DraggableKt$draggable$7;
+Landroidx/compose/foundation/gestures/DraggableKt$draggable$9$1$1$invoke$$inlined$onDispose$1;
+Landroidx/compose/foundation/gestures/DraggableKt$draggable$9$1$1;
+Landroidx/compose/foundation/gestures/DraggableKt$draggable$9$2$2;
+Landroidx/compose/foundation/gestures/DraggableKt$draggable$9$2;
+Landroidx/compose/foundation/gestures/DraggableKt$draggable$9$3$1$1;
+Landroidx/compose/foundation/gestures/DraggableKt$draggable$9$3$1;
+Landroidx/compose/foundation/gestures/DraggableKt$draggable$9$3;
+Landroidx/compose/foundation/gestures/DraggableKt$draggable$9;
+Landroidx/compose/foundation/gestures/DraggableKt$rememberDraggableState$1$1;
+Landroidx/compose/foundation/gestures/DraggableKt;
+Landroidx/compose/foundation/gestures/DraggableState;
+Landroidx/compose/foundation/gestures/ForEachGestureKt$awaitAllPointersUp$3;
+Landroidx/compose/foundation/gestures/ForEachGestureKt$awaitEachGesture$2;
+Landroidx/compose/foundation/gestures/ForEachGestureKt;
+Landroidx/compose/foundation/gestures/Orientation;
+Landroidx/compose/foundation/gestures/PointerDirectionConfig;
+Landroidx/compose/foundation/gestures/PressGestureScope;
+Landroidx/compose/foundation/gestures/PressGestureScopeImpl$reset$1;
+Landroidx/compose/foundation/gestures/PressGestureScopeImpl$tryAwaitRelease$1;
+Landroidx/compose/foundation/gestures/PressGestureScopeImpl;
+Landroidx/compose/foundation/gestures/TapGestureDetectorKt$NoPressGesture$1;
+Landroidx/compose/foundation/gestures/TapGestureDetectorKt$awaitFirstDown$2;
+Landroidx/compose/foundation/gestures/TapGestureDetectorKt$awaitSecondDown$2;
+Landroidx/compose/foundation/gestures/TapGestureDetectorKt$consumeUntilUp$1;
+Landroidx/compose/foundation/gestures/TapGestureDetectorKt$detectTapAndPress$2$1$1;
+Landroidx/compose/foundation/gestures/TapGestureDetectorKt$detectTapAndPress$2$1$2;
+Landroidx/compose/foundation/gestures/TapGestureDetectorKt$detectTapAndPress$2$1$3;
+Landroidx/compose/foundation/gestures/TapGestureDetectorKt$detectTapAndPress$2$1$4;
+Landroidx/compose/foundation/gestures/TapGestureDetectorKt$detectTapAndPress$2$1;
+Landroidx/compose/foundation/gestures/TapGestureDetectorKt$detectTapAndPress$2;
+Landroidx/compose/foundation/gestures/TapGestureDetectorKt$detectTapGestures$2$1$10;
+Landroidx/compose/foundation/gestures/TapGestureDetectorKt$detectTapGestures$2$1$1;
+Landroidx/compose/foundation/gestures/TapGestureDetectorKt$detectTapGestures$2$1$2;
+Landroidx/compose/foundation/gestures/TapGestureDetectorKt$detectTapGestures$2$1$3;
+Landroidx/compose/foundation/gestures/TapGestureDetectorKt$detectTapGestures$2$1$4;
+Landroidx/compose/foundation/gestures/TapGestureDetectorKt$detectTapGestures$2$1$5;
+Landroidx/compose/foundation/gestures/TapGestureDetectorKt$detectTapGestures$2$1$6;
+Landroidx/compose/foundation/gestures/TapGestureDetectorKt$detectTapGestures$2$1$7;
+Landroidx/compose/foundation/gestures/TapGestureDetectorKt$detectTapGestures$2$1$8;
+Landroidx/compose/foundation/gestures/TapGestureDetectorKt$detectTapGestures$2$1$9;
+Landroidx/compose/foundation/gestures/TapGestureDetectorKt$detectTapGestures$2$1;
+Landroidx/compose/foundation/gestures/TapGestureDetectorKt$detectTapGestures$2;
+Landroidx/compose/foundation/gestures/TapGestureDetectorKt$waitForUpOrCancellation$2;
+Landroidx/compose/foundation/gestures/TapGestureDetectorKt;
+Landroidx/compose/foundation/interaction/DragInteraction$Cancel;
+Landroidx/compose/foundation/interaction/DragInteraction$Start;
+Landroidx/compose/foundation/interaction/DragInteraction$Stop;
+Landroidx/compose/foundation/interaction/FocusInteraction$Focus;
+Landroidx/compose/foundation/interaction/FocusInteraction$Unfocus;
+Landroidx/compose/foundation/interaction/HoverInteraction$Enter;
+Landroidx/compose/foundation/interaction/HoverInteraction$Exit;
+Landroidx/compose/foundation/interaction/Interaction;
+Landroidx/compose/foundation/interaction/InteractionSource;
+Landroidx/compose/foundation/interaction/InteractionSourceKt;
+Landroidx/compose/foundation/interaction/MutableInteractionSource;
+Landroidx/compose/foundation/interaction/MutableInteractionSourceImpl;
+Landroidx/compose/foundation/interaction/PressInteraction$Cancel;
+Landroidx/compose/foundation/interaction/PressInteraction$Press;
+Landroidx/compose/foundation/interaction/PressInteraction$Release;
+Landroidx/compose/foundation/layout/Arrangement$Bottom$1;
+Landroidx/compose/foundation/layout/Arrangement$Center$1;
+Landroidx/compose/foundation/layout/Arrangement$End$1;
+Landroidx/compose/foundation/layout/Arrangement$Horizontal;
+Landroidx/compose/foundation/layout/Arrangement$HorizontalOrVertical;
+Landroidx/compose/foundation/layout/Arrangement$SpaceAround$1;
+Landroidx/compose/foundation/layout/Arrangement$SpaceBetween$1;
+Landroidx/compose/foundation/layout/Arrangement$SpaceEvenly$1;
+Landroidx/compose/foundation/layout/Arrangement$SpacedAligned;
+Landroidx/compose/foundation/layout/Arrangement$Start$1;
+Landroidx/compose/foundation/layout/Arrangement$Top$1;
+Landroidx/compose/foundation/layout/Arrangement$Vertical;
+Landroidx/compose/foundation/layout/Arrangement$spacedBy$1;
+Landroidx/compose/foundation/layout/Arrangement;
+Landroidx/compose/foundation/layout/BoxChildData;
+Landroidx/compose/foundation/layout/BoxKt$Box$3;
+Landroidx/compose/foundation/layout/BoxKt$EmptyBoxMeasurePolicy$1$measure$1;
+Landroidx/compose/foundation/layout/BoxKt$EmptyBoxMeasurePolicy$1;
+Landroidx/compose/foundation/layout/BoxKt$boxMeasurePolicy$1$measure$1;
+Landroidx/compose/foundation/layout/BoxKt$boxMeasurePolicy$1$measure$2;
+Landroidx/compose/foundation/layout/BoxKt$boxMeasurePolicy$1$measure$5;
+Landroidx/compose/foundation/layout/BoxKt$boxMeasurePolicy$1;
+Landroidx/compose/foundation/layout/BoxKt;
+Landroidx/compose/foundation/layout/BoxScopeInstance;
+Landroidx/compose/foundation/layout/BoxWithConstraintsKt$BoxWithConstraints$1$1$measurables$1;
+Landroidx/compose/foundation/layout/BoxWithConstraintsKt$BoxWithConstraints$1$1;
+Landroidx/compose/foundation/layout/BoxWithConstraintsKt$BoxWithConstraints$2;
+Landroidx/compose/foundation/layout/BoxWithConstraintsKt;
+Landroidx/compose/foundation/layout/BoxWithConstraintsScope;
+Landroidx/compose/foundation/layout/BoxWithConstraintsScopeImpl;
+Landroidx/compose/foundation/layout/ColumnKt$DefaultColumnMeasurePolicy$1;
+Landroidx/compose/foundation/layout/ColumnKt$columnMeasurePolicy$1$1;
+Landroidx/compose/foundation/layout/ColumnKt;
+Landroidx/compose/foundation/layout/ColumnScope;
+Landroidx/compose/foundation/layout/ColumnScopeInstance$align$$inlined$debugInspectorInfo$1;
+Landroidx/compose/foundation/layout/ColumnScopeInstance;
+Landroidx/compose/foundation/layout/CrossAxisAlignment$CenterCrossAxisAlignment;
+Landroidx/compose/foundation/layout/CrossAxisAlignment$Companion;
+Landroidx/compose/foundation/layout/CrossAxisAlignment$EndCrossAxisAlignment;
+Landroidx/compose/foundation/layout/CrossAxisAlignment$HorizontalCrossAxisAlignment;
+Landroidx/compose/foundation/layout/CrossAxisAlignment$StartCrossAxisAlignment;
+Landroidx/compose/foundation/layout/CrossAxisAlignment$VerticalCrossAxisAlignment;
+Landroidx/compose/foundation/layout/CrossAxisAlignment;
+Landroidx/compose/foundation/layout/Direction;
+Landroidx/compose/foundation/layout/FillModifier$measure$1;
+Landroidx/compose/foundation/layout/FillModifier;
+Landroidx/compose/foundation/layout/HorizontalAlignModifier;
+Landroidx/compose/foundation/layout/LayoutOrientation;
+Landroidx/compose/foundation/layout/OffsetKt$offset$$inlined$debugInspectorInfo$1;
+Landroidx/compose/foundation/layout/OffsetKt;
+Landroidx/compose/foundation/layout/OffsetPxModifier$measure$1;
+Landroidx/compose/foundation/layout/OffsetPxModifier;
+Landroidx/compose/foundation/layout/OrientationIndependentConstraints;
+Landroidx/compose/foundation/layout/PaddingKt$padding$$inlined$debugInspectorInfo$1;
+Landroidx/compose/foundation/layout/PaddingKt$padding-3ABfNKs$$inlined$debugInspectorInfo$1;
+Landroidx/compose/foundation/layout/PaddingKt$padding-VpY3zN4$$inlined$debugInspectorInfo$1;
+Landroidx/compose/foundation/layout/PaddingKt$padding-qDBjuR0$$inlined$debugInspectorInfo$1;
+Landroidx/compose/foundation/layout/PaddingKt;
+Landroidx/compose/foundation/layout/PaddingModifier$measure$1;
+Landroidx/compose/foundation/layout/PaddingModifier;
+Landroidx/compose/foundation/layout/PaddingValues;
+Landroidx/compose/foundation/layout/PaddingValuesImpl;
+Landroidx/compose/foundation/layout/PaddingValuesModifier$measure$2;
+Landroidx/compose/foundation/layout/PaddingValuesModifier;
+Landroidx/compose/foundation/layout/RowColumnImplKt$rowColumnMeasurePolicy$1$measure$4;
+Landroidx/compose/foundation/layout/RowColumnImplKt$rowColumnMeasurePolicy$1;
+Landroidx/compose/foundation/layout/RowColumnImplKt;
+Landroidx/compose/foundation/layout/RowColumnParentData;
+Landroidx/compose/foundation/layout/RowKt$DefaultRowMeasurePolicy$1;
+Landroidx/compose/foundation/layout/RowKt$rowMeasurePolicy$1$1;
+Landroidx/compose/foundation/layout/RowKt;
+Landroidx/compose/foundation/layout/RowScope;
+Landroidx/compose/foundation/layout/RowScopeInstance$align$$inlined$debugInspectorInfo$1;
+Landroidx/compose/foundation/layout/RowScopeInstance;
+Landroidx/compose/foundation/layout/SizeKt$createFillHeightModifier$1;
+Landroidx/compose/foundation/layout/SizeKt$createFillSizeModifier$1;
+Landroidx/compose/foundation/layout/SizeKt$createFillWidthModifier$1;
+Landroidx/compose/foundation/layout/SizeKt$createWrapContentHeightModifier$1;
+Landroidx/compose/foundation/layout/SizeKt$createWrapContentHeightModifier$2;
+Landroidx/compose/foundation/layout/SizeKt$createWrapContentSizeModifier$1;
+Landroidx/compose/foundation/layout/SizeKt$createWrapContentSizeModifier$2;
+Landroidx/compose/foundation/layout/SizeKt$createWrapContentWidthModifier$1;
+Landroidx/compose/foundation/layout/SizeKt$createWrapContentWidthModifier$2;
+Landroidx/compose/foundation/layout/SizeKt$defaultMinSize-VpY3zN4$$inlined$debugInspectorInfo$1;
+Landroidx/compose/foundation/layout/SizeKt$height-3ABfNKs$$inlined$debugInspectorInfo$1;
+Landroidx/compose/foundation/layout/SizeKt$heightIn-VpY3zN4$$inlined$debugInspectorInfo$1;
+Landroidx/compose/foundation/layout/SizeKt$size-3ABfNKs$$inlined$debugInspectorInfo$1;
+Landroidx/compose/foundation/layout/SizeKt$size-VpY3zN4$$inlined$debugInspectorInfo$1;
+Landroidx/compose/foundation/layout/SizeKt$sizeIn-qDBjuR0$$inlined$debugInspectorInfo$1;
+Landroidx/compose/foundation/layout/SizeKt$width-3ABfNKs$$inlined$debugInspectorInfo$1;
+Landroidx/compose/foundation/layout/SizeKt$widthIn-VpY3zN4$$inlined$debugInspectorInfo$1;
+Landroidx/compose/foundation/layout/SizeKt;
+Landroidx/compose/foundation/layout/SizeMode;
+Landroidx/compose/foundation/layout/SizeModifier$measure$1;
+Landroidx/compose/foundation/layout/SizeModifier;
+Landroidx/compose/foundation/layout/SpacerKt;
+Landroidx/compose/foundation/layout/SpacerMeasurePolicy$measure$1$1;
+Landroidx/compose/foundation/layout/SpacerMeasurePolicy;
+Landroidx/compose/foundation/layout/UnspecifiedConstraintsModifier$measure$1;
+Landroidx/compose/foundation/layout/UnspecifiedConstraintsModifier;
+Landroidx/compose/foundation/layout/VerticalAlignModifier;
+Landroidx/compose/foundation/layout/WrapContentModifier$measure$1;
+Landroidx/compose/foundation/layout/WrapContentModifier;
+Landroidx/compose/foundation/lazy/layout/PinnableParent;
+Landroidx/compose/foundation/lazy/layout/PinnableParentKt$ModifierLocalPinnableParent$1;
+Landroidx/compose/foundation/lazy/layout/PinnableParentKt;
+Landroidx/compose/foundation/relocation/AndroidBringIntoViewParent;
+Landroidx/compose/foundation/relocation/BringIntoViewChildModifier;
+Landroidx/compose/foundation/relocation/BringIntoViewKt$ModifierLocalBringIntoViewParent$1;
+Landroidx/compose/foundation/relocation/BringIntoViewKt;
+Landroidx/compose/foundation/relocation/BringIntoViewParent;
+Landroidx/compose/foundation/relocation/BringIntoViewRequester;
+Landroidx/compose/foundation/relocation/BringIntoViewRequesterImpl$bringIntoView$1;
+Landroidx/compose/foundation/relocation/BringIntoViewRequesterImpl;
+Landroidx/compose/foundation/relocation/BringIntoViewRequesterKt$bringIntoViewRequester$$inlined$debugInspectorInfo$1;
+Landroidx/compose/foundation/relocation/BringIntoViewRequesterKt$bringIntoViewRequester$2$1$invoke$$inlined$onDispose$1;
+Landroidx/compose/foundation/relocation/BringIntoViewRequesterKt$bringIntoViewRequester$2$1;
+Landroidx/compose/foundation/relocation/BringIntoViewRequesterKt$bringIntoViewRequester$2;
+Landroidx/compose/foundation/relocation/BringIntoViewRequesterKt;
+Landroidx/compose/foundation/relocation/BringIntoViewRequesterModifier$bringIntoView$2;
+Landroidx/compose/foundation/relocation/BringIntoViewRequesterModifier;
+Landroidx/compose/foundation/relocation/BringIntoViewResponder_androidKt;
+Landroidx/compose/foundation/shape/CornerBasedShape;
+Landroidx/compose/foundation/shape/CornerSize;
+Landroidx/compose/foundation/shape/CornerSizeKt$ZeroCornerSize$1;
+Landroidx/compose/foundation/shape/CornerSizeKt;
+Landroidx/compose/foundation/shape/DpCornerSize;
+Landroidx/compose/foundation/shape/PercentCornerSize;
+Landroidx/compose/foundation/shape/RoundedCornerShape;
+Landroidx/compose/foundation/shape/RoundedCornerShapeKt;
+Landroidx/compose/foundation/text/BasicTextKt$BasicText$1;
+Landroidx/compose/foundation/text/BasicTextKt$BasicText$2;
+Landroidx/compose/foundation/text/BasicTextKt$BasicText-4YKlhWE$$inlined$Layout$1;
+Landroidx/compose/foundation/text/BasicTextKt;
+Landroidx/compose/foundation/text/CoreTextKt;
+Landroidx/compose/foundation/text/HeightInLinesModifierKt$heightInLines$$inlined$debugInspectorInfo$1;
+Landroidx/compose/foundation/text/HeightInLinesModifierKt$heightInLines$2;
+Landroidx/compose/foundation/text/HeightInLinesModifierKt;
+Landroidx/compose/foundation/text/TextController$coreModifiers$1;
+Landroidx/compose/foundation/text/TextController$createSemanticsModifierFor$1$1;
+Landroidx/compose/foundation/text/TextController$createSemanticsModifierFor$1;
+Landroidx/compose/foundation/text/TextController$drawTextAndSelectionBehind$1;
+Landroidx/compose/foundation/text/TextController$measurePolicy$1$measure$2;
+Landroidx/compose/foundation/text/TextController$measurePolicy$1;
+Landroidx/compose/foundation/text/TextController$update$1;
+Landroidx/compose/foundation/text/TextController$update$2;
+Landroidx/compose/foundation/text/TextController$update$3;
+Landroidx/compose/foundation/text/TextController$update$mouseSelectionObserver$1;
+Landroidx/compose/foundation/text/TextController;
+Landroidx/compose/foundation/text/TextDelegate$Companion;
+Landroidx/compose/foundation/text/TextDelegate;
+Landroidx/compose/foundation/text/TextDelegateKt;
+Landroidx/compose/foundation/text/TextDragObserver;
+Landroidx/compose/foundation/text/TextFieldDelegateKt;
+Landroidx/compose/foundation/text/TextLayoutHelperKt;
+Landroidx/compose/foundation/text/TextPointerIcon_androidKt;
+Landroidx/compose/foundation/text/TextState$onTextLayout$1;
+Landroidx/compose/foundation/text/TextState;
+Landroidx/compose/foundation/text/TouchMode_androidKt;
+Landroidx/compose/foundation/text/selection/MouseSelectionObserver;
+Landroidx/compose/foundation/text/selection/Selectable;
+Landroidx/compose/foundation/text/selection/SelectionRegistrar;
+Landroidx/compose/foundation/text/selection/SelectionRegistrarKt$LocalSelectionRegistrar$1;
+Landroidx/compose/foundation/text/selection/SelectionRegistrarKt;
+Landroidx/compose/foundation/text/selection/TextSelectionColors;
+Landroidx/compose/foundation/text/selection/TextSelectionColorsKt$LocalTextSelectionColors$1;
+Landroidx/compose/foundation/text/selection/TextSelectionColorsKt;
+Landroidx/compose/material/icons/Icons$Filled;
+Landroidx/compose/material/icons/filled/AddKt;
+Landroidx/compose/material/icons/filled/ArrowBackKt;
+Landroidx/compose/material/ripple/AndroidRippleIndicationInstance$onInvalidateRipple$1;
+Landroidx/compose/material/ripple/AndroidRippleIndicationInstance;
+Landroidx/compose/material/ripple/CommonRippleIndicationInstance;
+Landroidx/compose/material/ripple/DebugRippleTheme;
+Landroidx/compose/material/ripple/PlatformRipple;
+Landroidx/compose/material/ripple/Ripple$rememberUpdatedInstance$1$1;
+Landroidx/compose/material/ripple/Ripple$rememberUpdatedInstance$1;
+Landroidx/compose/material/ripple/Ripple;
+Landroidx/compose/material/ripple/RippleAlpha;
+Landroidx/compose/material/ripple/RippleAnimationKt;
+Landroidx/compose/material/ripple/RippleContainer;
+Landroidx/compose/material/ripple/RippleHostMap;
+Landroidx/compose/material/ripple/RippleHostView$$ExternalSyntheticLambda0;
+Landroidx/compose/material/ripple/RippleHostView$Companion;
+Landroidx/compose/material/ripple/RippleHostView;
+Landroidx/compose/material/ripple/RippleIndicationInstance;
+Landroidx/compose/material/ripple/RippleKt;
+Landroidx/compose/material/ripple/RippleTheme;
+Landroidx/compose/material/ripple/RippleThemeKt$LocalRippleTheme$1;
+Landroidx/compose/material/ripple/RippleThemeKt;
+Landroidx/compose/material/ripple/StateLayer$handleInteraction$1;
+Landroidx/compose/material/ripple/StateLayer$handleInteraction$2;
+Landroidx/compose/material/ripple/StateLayer;
+Landroidx/compose/material/ripple/UnprojectedRipple;
+Landroidx/compose/material3/ButtonColors;
+Landroidx/compose/material3/ButtonDefaults;
+Landroidx/compose/material3/ButtonElevation$animateElevation$1$1$1;
+Landroidx/compose/material3/ButtonElevation$animateElevation$1$1;
+Landroidx/compose/material3/ButtonElevation$animateElevation$2;
+Landroidx/compose/material3/ButtonElevation$animateElevation$3;
+Landroidx/compose/material3/ButtonElevation;
+Landroidx/compose/material3/ButtonKt$Button$2$1$1;
+Landroidx/compose/material3/ButtonKt$Button$2$1;
+Landroidx/compose/material3/ButtonKt$Button$2;
+Landroidx/compose/material3/ButtonKt$Button$3;
+Landroidx/compose/material3/ButtonKt$FilledTonalButton$2;
+Landroidx/compose/material3/ButtonKt$TextButton$2;
+Landroidx/compose/material3/ButtonKt;
+Landroidx/compose/material3/CardColors;
+Landroidx/compose/material3/CardDefaults;
+Landroidx/compose/material3/CardElevation$animateElevation$1$1;
+Landroidx/compose/material3/CardElevation$animateElevation$2;
+Landroidx/compose/material3/CardElevation;
+Landroidx/compose/material3/CardKt$Card$1;
+Landroidx/compose/material3/CardKt$Card$2;
+Landroidx/compose/material3/CardKt;
+Landroidx/compose/material3/ChipBorder;
+Landroidx/compose/material3/ChipColors;
+Landroidx/compose/material3/ChipElevation$animateElevation$1$1$1;
+Landroidx/compose/material3/ChipElevation$animateElevation$1$1;
+Landroidx/compose/material3/ChipElevation$animateElevation$2;
+Landroidx/compose/material3/ChipElevation$animateElevation$3;
+Landroidx/compose/material3/ChipElevation;
+Landroidx/compose/material3/ChipKt$Chip$1;
+Landroidx/compose/material3/ChipKt$Chip$2;
+Landroidx/compose/material3/ChipKt$ChipContent$1;
+Landroidx/compose/material3/ChipKt$ChipContent$2;
+Landroidx/compose/material3/ChipKt$SuggestionChip$2;
+Landroidx/compose/material3/ChipKt;
+Landroidx/compose/material3/ColorResourceHelper;
+Landroidx/compose/material3/ColorScheme;
+Landroidx/compose/material3/ColorSchemeKt$LocalColorScheme$1;
+Landroidx/compose/material3/ColorSchemeKt$WhenMappings;
+Landroidx/compose/material3/ColorSchemeKt;
+Landroidx/compose/material3/ContentColorKt$LocalContentColor$1;
+Landroidx/compose/material3/ContentColorKt;
+Landroidx/compose/material3/DividerDefaults;
+Landroidx/compose/material3/DividerKt$Divider$1;
+Landroidx/compose/material3/DividerKt;
+Landroidx/compose/material3/DynamicTonalPaletteKt;
+Landroidx/compose/material3/ElevationDefaults;
+Landroidx/compose/material3/ElevationKt;
+Landroidx/compose/material3/IconKt$Icon$1;
+Landroidx/compose/material3/IconKt$Icon$2;
+Landroidx/compose/material3/IconKt$Icon$3;
+Landroidx/compose/material3/IconKt$Icon$semantics$1$1;
+Landroidx/compose/material3/IconKt;
+Landroidx/compose/material3/MaterialRippleTheme;
+Landroidx/compose/material3/MaterialTheme;
+Landroidx/compose/material3/MaterialThemeKt$MaterialTheme$1;
+Landroidx/compose/material3/MaterialThemeKt$MaterialTheme$2;
+Landroidx/compose/material3/MaterialThemeKt;
+Landroidx/compose/material3/MinimumTouchTargetModifier$measure$1;
+Landroidx/compose/material3/MinimumTouchTargetModifier;
+Landroidx/compose/material3/ShapeDefaults;
+Landroidx/compose/material3/Shapes;
+Landroidx/compose/material3/ShapesKt$LocalShapes$1;
+Landroidx/compose/material3/ShapesKt$WhenMappings;
+Landroidx/compose/material3/ShapesKt;
+Landroidx/compose/material3/SuggestionChipDefaults;
+Landroidx/compose/material3/SurfaceKt$LocalAbsoluteTonalElevation$1;
+Landroidx/compose/material3/SurfaceKt$Surface$1$1;
+Landroidx/compose/material3/SurfaceKt$Surface$1$2;
+Landroidx/compose/material3/SurfaceKt$Surface$1;
+Landroidx/compose/material3/SurfaceKt$Surface$3;
+Landroidx/compose/material3/SurfaceKt;
+Landroidx/compose/material3/TextKt$LocalTextStyle$1;
+Landroidx/compose/material3/TextKt$ProvideTextStyle$1;
+Landroidx/compose/material3/TextKt$Text$1;
+Landroidx/compose/material3/TextKt$Text$2;
+Landroidx/compose/material3/TextKt;
+Landroidx/compose/material3/TonalPalette;
+Landroidx/compose/material3/TouchTargetKt$LocalMinimumTouchTargetEnforcement$1;
+Landroidx/compose/material3/TouchTargetKt$minimumTouchTargetSize$$inlined$debugInspectorInfo$1;
+Landroidx/compose/material3/TouchTargetKt$minimumTouchTargetSize$2;
+Landroidx/compose/material3/TouchTargetKt;
+Landroidx/compose/material3/Typography;
+Landroidx/compose/material3/TypographyKt$LocalTypography$1;
+Landroidx/compose/material3/TypographyKt$WhenMappings;
+Landroidx/compose/material3/TypographyKt;
+Landroidx/compose/material3/tokens/ColorDarkTokens;
+Landroidx/compose/material3/tokens/ColorLightTokens;
+Landroidx/compose/material3/tokens/ColorSchemeKeyTokens;
+Landroidx/compose/material3/tokens/ElevationTokens;
+Landroidx/compose/material3/tokens/FilledButtonTokens;
+Landroidx/compose/material3/tokens/FilledCardTokens;
+Landroidx/compose/material3/tokens/FilledTonalButtonTokens;
+Landroidx/compose/material3/tokens/IconButtonTokens;
+Landroidx/compose/material3/tokens/PaletteTokens;
+Landroidx/compose/material3/tokens/ShapeKeyTokens;
+Landroidx/compose/material3/tokens/ShapeTokens;
+Landroidx/compose/material3/tokens/SuggestionChipTokens;
+Landroidx/compose/material3/tokens/TextButtonTokens;
+Landroidx/compose/material3/tokens/TypeScaleTokens;
+Landroidx/compose/material3/tokens/TypefaceTokens;
+Landroidx/compose/material3/tokens/TypographyKeyTokens;
+Landroidx/compose/material3/tokens/TypographyTokens;
+Landroidx/compose/runtime/AbstractApplier;
+Landroidx/compose/runtime/ActualAndroid_androidKt$DefaultMonotonicFrameClock$2;
+Landroidx/compose/runtime/ActualAndroid_androidKt;
+Landroidx/compose/runtime/ActualJvm_jvmKt;
+Landroidx/compose/runtime/Anchor;
+Landroidx/compose/runtime/Applier;
+Landroidx/compose/runtime/BroadcastFrameClock$FrameAwaiter;
+Landroidx/compose/runtime/BroadcastFrameClock$withFrameNanos$2$1;
+Landroidx/compose/runtime/BroadcastFrameClock;
+Landroidx/compose/runtime/ComposableSingletons$CompositionKt$lambda-1$1;
+Landroidx/compose/runtime/ComposableSingletons$CompositionKt$lambda-2$1;
+Landroidx/compose/runtime/ComposableSingletons$CompositionKt;
+Landroidx/compose/runtime/ComposablesKt;
+Landroidx/compose/runtime/ComposeRuntimeError;
+Landroidx/compose/runtime/Composer$Companion$Empty$1;
+Landroidx/compose/runtime/Composer$Companion;
+Landroidx/compose/runtime/Composer;
+Landroidx/compose/runtime/ComposerImpl$CompositionContextHolder;
+Landroidx/compose/runtime/ComposerImpl$CompositionContextImpl;
+Landroidx/compose/runtime/ComposerImpl$apply$operation$1;
+Landroidx/compose/runtime/ComposerImpl$createNode$2;
+Landroidx/compose/runtime/ComposerImpl$createNode$3;
+Landroidx/compose/runtime/ComposerImpl$deactivateToEndGroup$2;
+Landroidx/compose/runtime/ComposerImpl$doCompose$2$3;
+Landroidx/compose/runtime/ComposerImpl$doCompose$2$4;
+Landroidx/compose/runtime/ComposerImpl$doCompose$2$5;
+Landroidx/compose/runtime/ComposerImpl$doCompose$lambda$37$$inlined$sortBy$1;
+Landroidx/compose/runtime/ComposerImpl$endRestartGroup$1$1;
+Landroidx/compose/runtime/ComposerImpl$insertMovableContentGuarded$1$1$1;
+Landroidx/compose/runtime/ComposerImpl$insertMovableContentGuarded$1$1$2$1;
+Landroidx/compose/runtime/ComposerImpl$insertMovableContentGuarded$1$1$2$2;
+Landroidx/compose/runtime/ComposerImpl$insertMovableContentGuarded$1$1$3;
+Landroidx/compose/runtime/ComposerImpl$insertMovableContentGuarded$1$1$4;
+Landroidx/compose/runtime/ComposerImpl$insertMovableContentGuarded$1$1$5$1$1$1;
+Landroidx/compose/runtime/ComposerImpl$insertMovableContentGuarded$1$1$5$1$2;
+Landroidx/compose/runtime/ComposerImpl$insertMovableContentGuarded$1$2;
+Landroidx/compose/runtime/ComposerImpl$invokeMovableContentLambda$1;
+Landroidx/compose/runtime/ComposerImpl$realizeDowns$1;
+Landroidx/compose/runtime/ComposerImpl$realizeMovement$1;
+Landroidx/compose/runtime/ComposerImpl$realizeMovement$2;
+Landroidx/compose/runtime/ComposerImpl$realizeOperationLocation$2;
+Landroidx/compose/runtime/ComposerImpl$realizeUps$1;
+Landroidx/compose/runtime/ComposerImpl$recordInsert$1;
+Landroidx/compose/runtime/ComposerImpl$recordInsert$2;
+Landroidx/compose/runtime/ComposerImpl$recordSideEffect$1;
+Landroidx/compose/runtime/ComposerImpl$recordSlotEditing$1;
+Landroidx/compose/runtime/ComposerImpl$start$2;
+Landroidx/compose/runtime/ComposerImpl$startProviders$currentProviders$1;
+Landroidx/compose/runtime/ComposerImpl$startReaderGroup$1;
+Landroidx/compose/runtime/ComposerImpl$updateValue$1;
+Landroidx/compose/runtime/ComposerImpl$updateValue$2;
+Landroidx/compose/runtime/ComposerImpl;
+Landroidx/compose/runtime/ComposerKt$endGroupInstance$1;
+Landroidx/compose/runtime/ComposerKt$removeCurrentGroupInstance$1;
+Landroidx/compose/runtime/ComposerKt$resetSlotsInstance$1;
+Landroidx/compose/runtime/ComposerKt$skipToGroupEndInstance$1;
+Landroidx/compose/runtime/ComposerKt$startRootGroup$1;
+Landroidx/compose/runtime/ComposerKt;
+Landroidx/compose/runtime/Composition;
+Landroidx/compose/runtime/CompositionContext;
+Landroidx/compose/runtime/CompositionContextKt;
+Landroidx/compose/runtime/CompositionImpl$RememberEventDispatcher;
+Landroidx/compose/runtime/CompositionImpl;
+Landroidx/compose/runtime/CompositionKt;
+Landroidx/compose/runtime/CompositionLocal;
+Landroidx/compose/runtime/CompositionLocalKt$CompositionLocalProvider$1;
+Landroidx/compose/runtime/CompositionLocalKt;
+Landroidx/compose/runtime/CompositionScopedCoroutineScopeCanceller;
+Landroidx/compose/runtime/ControlledComposition;
+Landroidx/compose/runtime/DefaultChoreographerFrameClock;
+Landroidx/compose/runtime/DerivedSnapshotState;
+Landroidx/compose/runtime/DerivedState;
+Landroidx/compose/runtime/DisposableEffectImpl;
+Landroidx/compose/runtime/DisposableEffectResult;
+Landroidx/compose/runtime/DisposableEffectScope;
+Landroidx/compose/runtime/DynamicProvidableCompositionLocal;
+Landroidx/compose/runtime/EffectsKt;
+Landroidx/compose/runtime/GroupInfo;
+Landroidx/compose/runtime/GroupIterator;
+Landroidx/compose/runtime/IntStack;
+Landroidx/compose/runtime/Invalidation;
+Landroidx/compose/runtime/InvalidationResult;
+Landroidx/compose/runtime/JoinedKey;
+Landroidx/compose/runtime/KeyInfo;
+Landroidx/compose/runtime/Latch$await$2$2;
+Landroidx/compose/runtime/Latch;
+Landroidx/compose/runtime/LaunchedEffectImpl;
+Landroidx/compose/runtime/LazyValueHolder;
+Landroidx/compose/runtime/MonotonicFrameClock$DefaultImpls;
+Landroidx/compose/runtime/MonotonicFrameClock$Key;
+Landroidx/compose/runtime/MonotonicFrameClock;
+Landroidx/compose/runtime/MonotonicFrameClockKt;
+Landroidx/compose/runtime/MovableContent;
+Landroidx/compose/runtime/MovableContentState;
+Landroidx/compose/runtime/MovableContentStateReference;
+Landroidx/compose/runtime/MutableState;
+Landroidx/compose/runtime/NeverEqualPolicy;
+Landroidx/compose/runtime/OpaqueKey;
+Landroidx/compose/runtime/ParcelableSnapshotMutableState$Companion$CREATOR$1;
+Landroidx/compose/runtime/ParcelableSnapshotMutableState$Companion;
+Landroidx/compose/runtime/ParcelableSnapshotMutableState;
+Landroidx/compose/runtime/PausableMonotonicFrameClock$withFrameNanos$1;
+Landroidx/compose/runtime/PausableMonotonicFrameClock;
+Landroidx/compose/runtime/Pending$keyMap$2;
+Landroidx/compose/runtime/Pending;
+Landroidx/compose/runtime/PrioritySet;
+Landroidx/compose/runtime/ProvidableCompositionLocal;
+Landroidx/compose/runtime/ProvidedValue;
+Landroidx/compose/runtime/RecomposeScope;
+Landroidx/compose/runtime/RecomposeScopeImpl$end$1$2;
+Landroidx/compose/runtime/RecomposeScopeImpl;
+Landroidx/compose/runtime/RecomposeScopeImplKt;
+Landroidx/compose/runtime/Recomposer$Companion;
+Landroidx/compose/runtime/Recomposer$RecomposerErrorState;
+Landroidx/compose/runtime/Recomposer$RecomposerInfoImpl;
+Landroidx/compose/runtime/Recomposer$State;
+Landroidx/compose/runtime/Recomposer$broadcastFrameClock$1;
+Landroidx/compose/runtime/Recomposer$effectJob$1$1$1$1;
+Landroidx/compose/runtime/Recomposer$effectJob$1$1;
+Landroidx/compose/runtime/Recomposer$join$2;
+Landroidx/compose/runtime/Recomposer$performRecompose$1$1;
+Landroidx/compose/runtime/Recomposer$readObserverOf$1;
+Landroidx/compose/runtime/Recomposer$recompositionRunner$2$2;
+Landroidx/compose/runtime/Recomposer$recompositionRunner$2$unregisterApplyObserver$1;
+Landroidx/compose/runtime/Recomposer$recompositionRunner$2;
+Landroidx/compose/runtime/Recomposer$runRecomposeAndApplyChanges$2$2;
+Landroidx/compose/runtime/Recomposer$runRecomposeAndApplyChanges$2;
+Landroidx/compose/runtime/Recomposer$writeObserverOf$1;
+Landroidx/compose/runtime/Recomposer;
+Landroidx/compose/runtime/RecomposerKt;
+Landroidx/compose/runtime/ReferentialEqualityPolicy;
+Landroidx/compose/runtime/RememberManager;
+Landroidx/compose/runtime/RememberObserver;
+Landroidx/compose/runtime/ScopeUpdateScope;
+Landroidx/compose/runtime/SdkStubsFallbackFrameClock;
+Landroidx/compose/runtime/SkippableUpdater;
+Landroidx/compose/runtime/SlotReader;
+Landroidx/compose/runtime/SlotTable;
+Landroidx/compose/runtime/SlotTableKt;
+Landroidx/compose/runtime/SlotWriter$Companion;
+Landroidx/compose/runtime/SlotWriter$groupSlots$1;
+Landroidx/compose/runtime/SlotWriter;
+Landroidx/compose/runtime/SnapshotMutableStateImpl$StateStateRecord;
+Landroidx/compose/runtime/SnapshotMutableStateImpl;
+Landroidx/compose/runtime/SnapshotMutationPolicy;
+Landroidx/compose/runtime/SnapshotStateKt;
+Landroidx/compose/runtime/SnapshotStateKt__DerivedStateKt;
+Landroidx/compose/runtime/SnapshotStateKt__SnapshotFlowKt$snapshotFlow$1$readObserver$1;
+Landroidx/compose/runtime/SnapshotStateKt__SnapshotFlowKt$snapshotFlow$1$unregisterApplyObserver$1;
+Landroidx/compose/runtime/SnapshotStateKt__SnapshotFlowKt$snapshotFlow$1;
+Landroidx/compose/runtime/SnapshotStateKt__SnapshotFlowKt;
+Landroidx/compose/runtime/SnapshotStateKt__SnapshotMutationPolicyKt;
+Landroidx/compose/runtime/SnapshotStateKt__SnapshotStateKt;
+Landroidx/compose/runtime/SnapshotThreadLocal;
+Landroidx/compose/runtime/Stack;
+Landroidx/compose/runtime/State;
+Landroidx/compose/runtime/StaticProvidableCompositionLocal;
+Landroidx/compose/runtime/StaticValueHolder;
+Landroidx/compose/runtime/StructuralEqualityPolicy;
+Landroidx/compose/runtime/Trace;
+Landroidx/compose/runtime/Updater;
+Landroidx/compose/runtime/collection/IdentityArrayIntMap;
+Landroidx/compose/runtime/collection/IdentityArrayMap;
+Landroidx/compose/runtime/collection/IdentityArraySet$iterator$1;
+Landroidx/compose/runtime/collection/IdentityArraySet;
+Landroidx/compose/runtime/collection/IdentityScopeMap;
+Landroidx/compose/runtime/collection/MutableVector$MutableVectorList;
+Landroidx/compose/runtime/collection/MutableVector$SubList;
+Landroidx/compose/runtime/collection/MutableVector$VectorListIterator;
+Landroidx/compose/runtime/collection/MutableVector;
+Landroidx/compose/runtime/collection/MutableVectorKt;
+Landroidx/compose/runtime/external/kotlinx/collections/immutable/ExtensionsKt;
+Landroidx/compose/runtime/external/kotlinx/collections/immutable/ImmutableCollection;
+Landroidx/compose/runtime/external/kotlinx/collections/immutable/ImmutableList$SubList;
+Landroidx/compose/runtime/external/kotlinx/collections/immutable/ImmutableList;
+Landroidx/compose/runtime/external/kotlinx/collections/immutable/ImmutableSet;
+Landroidx/compose/runtime/external/kotlinx/collections/immutable/PersistentList$Builder;
+Landroidx/compose/runtime/external/kotlinx/collections/immutable/PersistentList;
+Landroidx/compose/runtime/external/kotlinx/collections/immutable/PersistentMap$Builder;
+Landroidx/compose/runtime/external/kotlinx/collections/immutable/PersistentMap;
+Landroidx/compose/runtime/external/kotlinx/collections/immutable/PersistentSet;
+Landroidx/compose/runtime/external/kotlinx/collections/immutable/implementations/immutableList/AbstractListIterator;
+Landroidx/compose/runtime/external/kotlinx/collections/immutable/implementations/immutableList/AbstractPersistentList$removeAll$1;
+Landroidx/compose/runtime/external/kotlinx/collections/immutable/implementations/immutableList/AbstractPersistentList;
+Landroidx/compose/runtime/external/kotlinx/collections/immutable/implementations/immutableList/BufferIterator;
+Landroidx/compose/runtime/external/kotlinx/collections/immutable/implementations/immutableList/PersistentVector;
+Landroidx/compose/runtime/external/kotlinx/collections/immutable/implementations/immutableList/PersistentVectorBuilder;
+Landroidx/compose/runtime/external/kotlinx/collections/immutable/implementations/immutableList/SmallPersistentVector$Companion;
+Landroidx/compose/runtime/external/kotlinx/collections/immutable/implementations/immutableList/SmallPersistentVector;
+Landroidx/compose/runtime/external/kotlinx/collections/immutable/implementations/immutableList/UtilsKt;
+Landroidx/compose/runtime/external/kotlinx/collections/immutable/implementations/immutableMap/AbstractMapBuilderEntries;
+Landroidx/compose/runtime/external/kotlinx/collections/immutable/implementations/immutableMap/MapEntry;
+Landroidx/compose/runtime/external/kotlinx/collections/immutable/implementations/immutableMap/PersistentHashMap$Companion;
+Landroidx/compose/runtime/external/kotlinx/collections/immutable/implementations/immutableMap/PersistentHashMap;
+Landroidx/compose/runtime/external/kotlinx/collections/immutable/implementations/immutableMap/PersistentHashMapBaseIterator;
+Landroidx/compose/runtime/external/kotlinx/collections/immutable/implementations/immutableMap/PersistentHashMapBuilder;
+Landroidx/compose/runtime/external/kotlinx/collections/immutable/implementations/immutableMap/PersistentHashMapBuilderEntries;
+Landroidx/compose/runtime/external/kotlinx/collections/immutable/implementations/immutableMap/PersistentHashMapBuilderKeys;
+Landroidx/compose/runtime/external/kotlinx/collections/immutable/implementations/immutableMap/PersistentHashMapBuilderValues;
+Landroidx/compose/runtime/external/kotlinx/collections/immutable/implementations/immutableMap/PersistentHashMapEntries;
+Landroidx/compose/runtime/external/kotlinx/collections/immutable/implementations/immutableMap/PersistentHashMapEntriesIterator;
+Landroidx/compose/runtime/external/kotlinx/collections/immutable/implementations/immutableMap/PersistentHashMapKeys;
+Landroidx/compose/runtime/external/kotlinx/collections/immutable/implementations/immutableMap/PersistentHashMapValues;
+Landroidx/compose/runtime/external/kotlinx/collections/immutable/implementations/immutableMap/TrieNode$Companion;
+Landroidx/compose/runtime/external/kotlinx/collections/immutable/implementations/immutableMap/TrieNode$ModificationResult;
+Landroidx/compose/runtime/external/kotlinx/collections/immutable/implementations/immutableMap/TrieNode;
+Landroidx/compose/runtime/external/kotlinx/collections/immutable/implementations/immutableMap/TrieNodeBaseIterator;
+Landroidx/compose/runtime/external/kotlinx/collections/immutable/implementations/immutableMap/TrieNodeEntriesIterator;
+Landroidx/compose/runtime/external/kotlinx/collections/immutable/implementations/immutableMap/TrieNodeKt;
+Landroidx/compose/runtime/external/kotlinx/collections/immutable/implementations/persistentOrderedSet/Links;
+Landroidx/compose/runtime/external/kotlinx/collections/immutable/implementations/persistentOrderedSet/PersistentOrderedSet$Companion;
+Landroidx/compose/runtime/external/kotlinx/collections/immutable/implementations/persistentOrderedSet/PersistentOrderedSet;
+Landroidx/compose/runtime/external/kotlinx/collections/immutable/implementations/persistentOrderedSet/PersistentOrderedSetIterator;
+Landroidx/compose/runtime/external/kotlinx/collections/immutable/internal/CommonFunctionsKt;
+Landroidx/compose/runtime/external/kotlinx/collections/immutable/internal/DeltaCounter;
+Landroidx/compose/runtime/external/kotlinx/collections/immutable/internal/EndOfChain;
+Landroidx/compose/runtime/external/kotlinx/collections/immutable/internal/ListImplementation;
+Landroidx/compose/runtime/external/kotlinx/collections/immutable/internal/MutabilityOwnership;
+Landroidx/compose/runtime/internal/ComposableLambda;
+Landroidx/compose/runtime/internal/ComposableLambdaImpl$invoke$1;
+Landroidx/compose/runtime/internal/ComposableLambdaImpl$invoke$2;
+Landroidx/compose/runtime/internal/ComposableLambdaImpl$invoke$3;
+Landroidx/compose/runtime/internal/ComposableLambdaImpl;
+Landroidx/compose/runtime/internal/ComposableLambdaKt;
+Landroidx/compose/runtime/internal/ThreadMap;
+Landroidx/compose/runtime/internal/ThreadMapKt;
+Landroidx/compose/runtime/saveable/RememberSaveableKt$rememberSaveable$1$invoke$$inlined$onDispose$1;
+Landroidx/compose/runtime/saveable/RememberSaveableKt$rememberSaveable$1$valueProvider$1$1$1;
+Landroidx/compose/runtime/saveable/RememberSaveableKt$rememberSaveable$1$valueProvider$1;
+Landroidx/compose/runtime/saveable/RememberSaveableKt$rememberSaveable$1;
+Landroidx/compose/runtime/saveable/RememberSaveableKt;
+Landroidx/compose/runtime/saveable/SaveableStateRegistry$Entry;
+Landroidx/compose/runtime/saveable/SaveableStateRegistry;
+Landroidx/compose/runtime/saveable/SaveableStateRegistryImpl$registerProvider$3;
+Landroidx/compose/runtime/saveable/SaveableStateRegistryImpl;
+Landroidx/compose/runtime/saveable/SaveableStateRegistryKt$LocalSaveableStateRegistry$1;
+Landroidx/compose/runtime/saveable/SaveableStateRegistryKt;
+Landroidx/compose/runtime/saveable/Saver;
+Landroidx/compose/runtime/saveable/SaverKt$AutoSaver$1;
+Landroidx/compose/runtime/saveable/SaverKt$AutoSaver$2;
+Landroidx/compose/runtime/saveable/SaverKt$Saver$1;
+Landroidx/compose/runtime/saveable/SaverKt;
+Landroidx/compose/runtime/saveable/SaverScope;
+Landroidx/compose/runtime/snapshots/GlobalSnapshot$1$1$1;
+Landroidx/compose/runtime/snapshots/GlobalSnapshot$takeNestedMutableSnapshot$1;
+Landroidx/compose/runtime/snapshots/GlobalSnapshot$takeNestedSnapshot$1;
+Landroidx/compose/runtime/snapshots/GlobalSnapshot;
+Landroidx/compose/runtime/snapshots/ListUtilsKt;
+Landroidx/compose/runtime/snapshots/MutableSnapshot;
+Landroidx/compose/runtime/snapshots/NestedMutableSnapshot;
+Landroidx/compose/runtime/snapshots/NestedReadonlySnapshot;
+Landroidx/compose/runtime/snapshots/ObserverHandle;
+Landroidx/compose/runtime/snapshots/Snapshot$Companion$registerApplyObserver$2;
+Landroidx/compose/runtime/snapshots/Snapshot$Companion$registerGlobalWriteObserver$2;
+Landroidx/compose/runtime/snapshots/Snapshot$Companion;
+Landroidx/compose/runtime/snapshots/Snapshot;
+Landroidx/compose/runtime/snapshots/SnapshotApplyResult$Failure;
+Landroidx/compose/runtime/snapshots/SnapshotApplyResult$Success;
+Landroidx/compose/runtime/snapshots/SnapshotApplyResult;
+Landroidx/compose/runtime/snapshots/SnapshotDoubleIndexHeap;
+Landroidx/compose/runtime/snapshots/SnapshotIdSet$Companion;
+Landroidx/compose/runtime/snapshots/SnapshotIdSet$iterator$1;
+Landroidx/compose/runtime/snapshots/SnapshotIdSet;
+Landroidx/compose/runtime/snapshots/SnapshotIdSetKt;
+Landroidx/compose/runtime/snapshots/SnapshotKt$advanceGlobalSnapshot$2;
+Landroidx/compose/runtime/snapshots/SnapshotKt$emptyLambda$1;
+Landroidx/compose/runtime/snapshots/SnapshotKt$mergedReadObserver$1;
+Landroidx/compose/runtime/snapshots/SnapshotKt$mergedWriteObserver$1;
+Landroidx/compose/runtime/snapshots/SnapshotKt$takeNewSnapshot$1;
+Landroidx/compose/runtime/snapshots/SnapshotKt;
+Landroidx/compose/runtime/snapshots/SnapshotMutableState;
+Landroidx/compose/runtime/snapshots/SnapshotStateList$StateListStateRecord;
+Landroidx/compose/runtime/snapshots/SnapshotStateList$addAll$1;
+Landroidx/compose/runtime/snapshots/SnapshotStateList$retainAll$1;
+Landroidx/compose/runtime/snapshots/SnapshotStateList;
+Landroidx/compose/runtime/snapshots/SnapshotStateListKt;
+Landroidx/compose/runtime/snapshots/SnapshotStateMap;
+Landroidx/compose/runtime/snapshots/SnapshotStateMapKt;
+Landroidx/compose/runtime/snapshots/SnapshotStateObserver$ObservedScopeMap$derivedStateEnterObserver$1;
+Landroidx/compose/runtime/snapshots/SnapshotStateObserver$ObservedScopeMap$derivedStateExitObserver$1;
+Landroidx/compose/runtime/snapshots/SnapshotStateObserver$ObservedScopeMap;
+Landroidx/compose/runtime/snapshots/SnapshotStateObserver$applyObserver$1$2;
+Landroidx/compose/runtime/snapshots/SnapshotStateObserver$applyObserver$1;
+Landroidx/compose/runtime/snapshots/SnapshotStateObserver$observeReads$1$1;
+Landroidx/compose/runtime/snapshots/SnapshotStateObserver$readObserver$1;
+Landroidx/compose/runtime/snapshots/SnapshotStateObserver;
+Landroidx/compose/runtime/snapshots/StateListIterator;
+Landroidx/compose/runtime/snapshots/StateObject;
+Landroidx/compose/runtime/snapshots/StateRecord;
+Landroidx/compose/runtime/snapshots/SubList;
+Landroidx/compose/runtime/snapshots/TransparentObserverMutableSnapshot;
+Landroidx/compose/runtime/snapshots/TransparentObserverSnapshot;
+Landroidx/compose/runtime/tooling/CompositionData;
+Landroidx/compose/runtime/tooling/InspectionTablesKt$LocalInspectionTables$1;
+Landroidx/compose/runtime/tooling/InspectionTablesKt;
+Landroidx/compose/ui/ActualKt;
+Landroidx/compose/ui/Alignment$Companion;
+Landroidx/compose/ui/Alignment$Horizontal;
+Landroidx/compose/ui/Alignment$Vertical;
+Landroidx/compose/ui/Alignment;
+Landroidx/compose/ui/BiasAlignment$Horizontal;
+Landroidx/compose/ui/BiasAlignment$Vertical;
+Landroidx/compose/ui/BiasAlignment;
+Landroidx/compose/ui/CombinedModifier$toString$1;
+Landroidx/compose/ui/CombinedModifier;
+Landroidx/compose/ui/ComposedModifier;
+Landroidx/compose/ui/ComposedModifierKt$WrapFocusEventModifier$1$1$1;
+Landroidx/compose/ui/ComposedModifierKt$WrapFocusEventModifier$1$modifier$1$1;
+Landroidx/compose/ui/ComposedModifierKt$WrapFocusEventModifier$1;
+Landroidx/compose/ui/ComposedModifierKt$WrapFocusRequesterModifier$1;
+Landroidx/compose/ui/ComposedModifierKt$materialize$1;
+Landroidx/compose/ui/ComposedModifierKt$materialize$result$1;
+Landroidx/compose/ui/ComposedModifierKt;
+Landroidx/compose/ui/Modifier$Companion;
+Landroidx/compose/ui/Modifier$Element;
+Landroidx/compose/ui/Modifier$Node;
+Landroidx/compose/ui/Modifier;
+Landroidx/compose/ui/MotionDurationScale$DefaultImpls;
+Landroidx/compose/ui/MotionDurationScale$Key;
+Landroidx/compose/ui/MotionDurationScale;
+Landroidx/compose/ui/R$id;
+Landroidx/compose/ui/R$string;
+Landroidx/compose/ui/TempListUtilsKt;
+Landroidx/compose/ui/autofill/AndroidAutofill;
+Landroidx/compose/ui/autofill/AndroidAutofill_androidKt;
+Landroidx/compose/ui/autofill/Autofill;
+Landroidx/compose/ui/autofill/AutofillCallback;
+Landroidx/compose/ui/autofill/AutofillTree;
+Landroidx/compose/ui/draw/BuildDrawCacheParams;
+Landroidx/compose/ui/draw/ClipKt;
+Landroidx/compose/ui/draw/DrawBackgroundModifier;
+Landroidx/compose/ui/draw/DrawCacheModifier;
+Landroidx/compose/ui/draw/DrawModifier;
+Landroidx/compose/ui/draw/DrawModifierKt$drawBehind$$inlined$debugInspectorInfo$1;
+Landroidx/compose/ui/draw/DrawModifierKt$drawWithCache$$inlined$debugInspectorInfo$1;
+Landroidx/compose/ui/draw/DrawModifierKt$drawWithCache$2;
+Landroidx/compose/ui/draw/DrawModifierKt;
+Landroidx/compose/ui/draw/PainterModifier$measure$1;
+Landroidx/compose/ui/draw/PainterModifier;
+Landroidx/compose/ui/draw/PainterModifierKt$paint$$inlined$debugInspectorInfo$1;
+Landroidx/compose/ui/draw/PainterModifierKt;
+Landroidx/compose/ui/draw/ShadowKt$shadow$2$1;
+Landroidx/compose/ui/draw/ShadowKt$shadow-s4CzXII$$inlined$debugInspectorInfo$1;
+Landroidx/compose/ui/draw/ShadowKt;
+Landroidx/compose/ui/focus/FocusChangedModifierKt$onFocusChanged$$inlined$debugInspectorInfo$1;
+Landroidx/compose/ui/focus/FocusChangedModifierKt$onFocusChanged$2$1$1;
+Landroidx/compose/ui/focus/FocusChangedModifierKt$onFocusChanged$2;
+Landroidx/compose/ui/focus/FocusChangedModifierKt;
+Landroidx/compose/ui/focus/FocusDirection$Companion;
+Landroidx/compose/ui/focus/FocusDirection;
+Landroidx/compose/ui/focus/FocusEventModifier;
+Landroidx/compose/ui/focus/FocusEventModifierKt$ModifierLocalFocusEvent$1;
+Landroidx/compose/ui/focus/FocusEventModifierKt$onFocusEvent$$inlined$debugInspectorInfo$1;
+Landroidx/compose/ui/focus/FocusEventModifierKt$onFocusEvent$2$1$1;
+Landroidx/compose/ui/focus/FocusEventModifierKt$onFocusEvent$2;
+Landroidx/compose/ui/focus/FocusEventModifierKt;
+Landroidx/compose/ui/focus/FocusEventModifierLocal$WhenMappings;
+Landroidx/compose/ui/focus/FocusEventModifierLocal;
+Landroidx/compose/ui/focus/FocusManager;
+Landroidx/compose/ui/focus/FocusManagerImpl$WhenMappings;
+Landroidx/compose/ui/focus/FocusManagerImpl$moveFocus$foundNextItem$1;
+Landroidx/compose/ui/focus/FocusManagerImpl;
+Landroidx/compose/ui/focus/FocusManagerKt$WhenMappings;
+Landroidx/compose/ui/focus/FocusManagerKt;
+Landroidx/compose/ui/focus/FocusModifier$Companion$RefreshFocusProperties$1;
+Landroidx/compose/ui/focus/FocusModifier$Companion;
+Landroidx/compose/ui/focus/FocusModifier$WhenMappings;
+Landroidx/compose/ui/focus/FocusModifier;
+Landroidx/compose/ui/focus/FocusModifierKt$ModifierLocalParentFocusModifier$1;
+Landroidx/compose/ui/focus/FocusModifierKt$ResetFocusModifierLocals$1;
+Landroidx/compose/ui/focus/FocusModifierKt$ResetFocusModifierLocals$2;
+Landroidx/compose/ui/focus/FocusModifierKt$ResetFocusModifierLocals$3;
+Landroidx/compose/ui/focus/FocusModifierKt$focusTarget$$inlined$debugInspectorInfo$1;
+Landroidx/compose/ui/focus/FocusModifierKt$focusTarget$2$1$1;
+Landroidx/compose/ui/focus/FocusModifierKt$focusTarget$2;
+Landroidx/compose/ui/focus/FocusModifierKt;
+Landroidx/compose/ui/focus/FocusOrderModifierKt;
+Landroidx/compose/ui/focus/FocusProperties;
+Landroidx/compose/ui/focus/FocusPropertiesImpl$enter$1;
+Landroidx/compose/ui/focus/FocusPropertiesImpl$exit$1;
+Landroidx/compose/ui/focus/FocusPropertiesImpl;
+Landroidx/compose/ui/focus/FocusPropertiesKt$ModifierLocalFocusProperties$1;
+Landroidx/compose/ui/focus/FocusPropertiesKt$clear$1;
+Landroidx/compose/ui/focus/FocusPropertiesKt$clear$2;
+Landroidx/compose/ui/focus/FocusPropertiesKt$focusProperties$$inlined$debugInspectorInfo$1;
+Landroidx/compose/ui/focus/FocusPropertiesKt$refreshFocusProperties$1;
+Landroidx/compose/ui/focus/FocusPropertiesKt;
+Landroidx/compose/ui/focus/FocusPropertiesModifier;
+Landroidx/compose/ui/focus/FocusRequester$Companion;
+Landroidx/compose/ui/focus/FocusRequester$requestFocus$2;
+Landroidx/compose/ui/focus/FocusRequester;
+Landroidx/compose/ui/focus/FocusRequesterModifier;
+Landroidx/compose/ui/focus/FocusRequesterModifierKt$ModifierLocalFocusRequester$1;
+Landroidx/compose/ui/focus/FocusRequesterModifierKt$focusRequester$$inlined$debugInspectorInfo$1;
+Landroidx/compose/ui/focus/FocusRequesterModifierKt$focusRequester$2;
+Landroidx/compose/ui/focus/FocusRequesterModifierKt;
+Landroidx/compose/ui/focus/FocusRequesterModifierLocal;
+Landroidx/compose/ui/focus/FocusState;
+Landroidx/compose/ui/focus/FocusStateImpl$WhenMappings;
+Landroidx/compose/ui/focus/FocusStateImpl;
+Landroidx/compose/ui/focus/FocusTransactionsKt$WhenMappings;
+Landroidx/compose/ui/focus/FocusTransactionsKt$requestFocus$1;
+Landroidx/compose/ui/focus/FocusTransactionsKt;
+Landroidx/compose/ui/focus/FocusTraversalKt;
+Landroidx/compose/ui/focus/TwoDimensionalFocusSearchKt;
+Landroidx/compose/ui/geometry/CornerRadius$Companion;
+Landroidx/compose/ui/geometry/CornerRadius;
+Landroidx/compose/ui/geometry/CornerRadiusKt;
+Landroidx/compose/ui/geometry/GeometryUtilsKt;
+Landroidx/compose/ui/geometry/MutableRect;
+Landroidx/compose/ui/geometry/MutableRectKt;
+Landroidx/compose/ui/geometry/Offset$Companion;
+Landroidx/compose/ui/geometry/Offset;
+Landroidx/compose/ui/geometry/OffsetKt;
+Landroidx/compose/ui/geometry/Rect$Companion;
+Landroidx/compose/ui/geometry/Rect;
+Landroidx/compose/ui/geometry/RectKt;
+Landroidx/compose/ui/geometry/RoundRect$Companion;
+Landroidx/compose/ui/geometry/RoundRect;
+Landroidx/compose/ui/geometry/RoundRectKt;
+Landroidx/compose/ui/geometry/Size$Companion;
+Landroidx/compose/ui/geometry/Size;
+Landroidx/compose/ui/geometry/SizeKt;
+Landroidx/compose/ui/graphics/AndroidBlendMode_androidKt;
+Landroidx/compose/ui/graphics/AndroidCanvas;
+Landroidx/compose/ui/graphics/AndroidCanvas_androidKt;
+Landroidx/compose/ui/graphics/AndroidColorFilter_androidKt;
+Landroidx/compose/ui/graphics/AndroidImageBitmap;
+Landroidx/compose/ui/graphics/AndroidImageBitmap_androidKt;
+Landroidx/compose/ui/graphics/AndroidMatrixConversions_androidKt;
+Landroidx/compose/ui/graphics/AndroidPaint;
+Landroidx/compose/ui/graphics/AndroidPaint_androidKt$WhenMappings;
+Landroidx/compose/ui/graphics/AndroidPaint_androidKt;
+Landroidx/compose/ui/graphics/AndroidPath;
+Landroidx/compose/ui/graphics/AndroidPath_androidKt;
+Landroidx/compose/ui/graphics/Api26Bitmap;
+Landroidx/compose/ui/graphics/BlendMode$Companion;
+Landroidx/compose/ui/graphics/BlendMode;
+Landroidx/compose/ui/graphics/BlendModeColorFilterHelper;
+Landroidx/compose/ui/graphics/BlockGraphicsLayerModifier$measure$1;
+Landroidx/compose/ui/graphics/BlockGraphicsLayerModifier;
+Landroidx/compose/ui/graphics/Brush;
+Landroidx/compose/ui/graphics/Canvas;
+Landroidx/compose/ui/graphics/CanvasHolder;
+Landroidx/compose/ui/graphics/CanvasUtils;
+Landroidx/compose/ui/graphics/CanvasZHelper;
+Landroidx/compose/ui/graphics/ClipOp$Companion;
+Landroidx/compose/ui/graphics/ClipOp;
+Landroidx/compose/ui/graphics/Color$Companion;
+Landroidx/compose/ui/graphics/Color;
+Landroidx/compose/ui/graphics/ColorFilter$Companion;
+Landroidx/compose/ui/graphics/ColorFilter;
+Landroidx/compose/ui/graphics/ColorKt;
+Landroidx/compose/ui/graphics/CompositingStrategy$Companion;
+Landroidx/compose/ui/graphics/CompositingStrategy;
+Landroidx/compose/ui/graphics/FilterQuality$Companion;
+Landroidx/compose/ui/graphics/FilterQuality;
+Landroidx/compose/ui/graphics/Float16$Companion;
+Landroidx/compose/ui/graphics/Float16;
+Landroidx/compose/ui/graphics/GraphicsLayerModifierKt$graphicsLayer$$inlined$debugInspectorInfo$1;
+Landroidx/compose/ui/graphics/GraphicsLayerModifierKt$graphicsLayer-Ap8cVGQ$$inlined$debugInspectorInfo$1;
+Landroidx/compose/ui/graphics/GraphicsLayerModifierKt;
+Landroidx/compose/ui/graphics/GraphicsLayerScope;
+Landroidx/compose/ui/graphics/GraphicsLayerScopeKt;
+Landroidx/compose/ui/graphics/ImageBitmap;
+Landroidx/compose/ui/graphics/ImageBitmapConfig$Companion;
+Landroidx/compose/ui/graphics/ImageBitmapConfig;
+Landroidx/compose/ui/graphics/Matrix$Companion;
+Landroidx/compose/ui/graphics/Matrix;
+Landroidx/compose/ui/graphics/MatrixKt;
+Landroidx/compose/ui/graphics/Outline$Rectangle;
+Landroidx/compose/ui/graphics/Outline$Rounded;
+Landroidx/compose/ui/graphics/Outline;
+Landroidx/compose/ui/graphics/OutlineKt;
+Landroidx/compose/ui/graphics/Paint;
+Landroidx/compose/ui/graphics/PaintingStyle$Companion;
+Landroidx/compose/ui/graphics/PaintingStyle;
+Landroidx/compose/ui/graphics/Path;
+Landroidx/compose/ui/graphics/PathEffect;
+Landroidx/compose/ui/graphics/PathFillType$Companion;
+Landroidx/compose/ui/graphics/PathFillType;
+Landroidx/compose/ui/graphics/PathOperation$Companion;
+Landroidx/compose/ui/graphics/PathOperation;
+Landroidx/compose/ui/graphics/RectHelper_androidKt;
+Landroidx/compose/ui/graphics/RectangleShapeKt$RectangleShape$1;
+Landroidx/compose/ui/graphics/RectangleShapeKt;
+Landroidx/compose/ui/graphics/RenderEffect;
+Landroidx/compose/ui/graphics/ReusableGraphicsLayerScope;
+Landroidx/compose/ui/graphics/ShaderBrush;
+Landroidx/compose/ui/graphics/Shadow$Companion;
+Landroidx/compose/ui/graphics/Shadow;
+Landroidx/compose/ui/graphics/Shape;
+Landroidx/compose/ui/graphics/SimpleGraphicsLayerModifier$layerBlock$1;
+Landroidx/compose/ui/graphics/SimpleGraphicsLayerModifier$measure$1;
+Landroidx/compose/ui/graphics/SimpleGraphicsLayerModifier;
+Landroidx/compose/ui/graphics/SolidColor;
+Landroidx/compose/ui/graphics/StrokeCap$Companion;
+Landroidx/compose/ui/graphics/StrokeCap;
+Landroidx/compose/ui/graphics/StrokeJoin$Companion;
+Landroidx/compose/ui/graphics/StrokeJoin;
+Landroidx/compose/ui/graphics/TransformOrigin$Companion;
+Landroidx/compose/ui/graphics/TransformOrigin;
+Landroidx/compose/ui/graphics/TransformOriginKt;
+Landroidx/compose/ui/graphics/WrapperVerificationHelperMethods;
+Landroidx/compose/ui/graphics/colorspace/Adaptation$Companion$Bradford$1;
+Landroidx/compose/ui/graphics/colorspace/Adaptation$Companion$Ciecat02$1;
+Landroidx/compose/ui/graphics/colorspace/Adaptation$Companion$VonKries$1;
+Landroidx/compose/ui/graphics/colorspace/Adaptation$Companion;
+Landroidx/compose/ui/graphics/colorspace/Adaptation;
+Landroidx/compose/ui/graphics/colorspace/ColorModel$Companion;
+Landroidx/compose/ui/graphics/colorspace/ColorModel;
+Landroidx/compose/ui/graphics/colorspace/ColorSpace$Companion;
+Landroidx/compose/ui/graphics/colorspace/ColorSpace;
+Landroidx/compose/ui/graphics/colorspace/ColorSpaceKt;
+Landroidx/compose/ui/graphics/colorspace/ColorSpaces$ExtendedSrgb$1;
+Landroidx/compose/ui/graphics/colorspace/ColorSpaces$ExtendedSrgb$2;
+Landroidx/compose/ui/graphics/colorspace/ColorSpaces;
+Landroidx/compose/ui/graphics/colorspace/Connector$Companion;
+Landroidx/compose/ui/graphics/colorspace/Connector$RgbConnector;
+Landroidx/compose/ui/graphics/colorspace/Connector;
+Landroidx/compose/ui/graphics/colorspace/Illuminant;
+Landroidx/compose/ui/graphics/colorspace/Lab$Companion;
+Landroidx/compose/ui/graphics/colorspace/Lab;
+Landroidx/compose/ui/graphics/colorspace/Oklab$Companion;
+Landroidx/compose/ui/graphics/colorspace/Oklab;
+Landroidx/compose/ui/graphics/colorspace/RenderIntent$Companion;
+Landroidx/compose/ui/graphics/colorspace/RenderIntent;
+Landroidx/compose/ui/graphics/colorspace/Rgb$1;
+Landroidx/compose/ui/graphics/colorspace/Rgb$2;
+Landroidx/compose/ui/graphics/colorspace/Rgb$3;
+Landroidx/compose/ui/graphics/colorspace/Rgb$4;
+Landroidx/compose/ui/graphics/colorspace/Rgb$5;
+Landroidx/compose/ui/graphics/colorspace/Rgb$6;
+Landroidx/compose/ui/graphics/colorspace/Rgb$Companion$DoubleIdentity$1;
+Landroidx/compose/ui/graphics/colorspace/Rgb$Companion;
+Landroidx/compose/ui/graphics/colorspace/Rgb$eotf$1;
+Landroidx/compose/ui/graphics/colorspace/Rgb$oetf$1;
+Landroidx/compose/ui/graphics/colorspace/Rgb;
+Landroidx/compose/ui/graphics/colorspace/TransferParameters;
+Landroidx/compose/ui/graphics/colorspace/WhitePoint;
+Landroidx/compose/ui/graphics/colorspace/Xyz;
+Landroidx/compose/ui/graphics/drawscope/CanvasDrawScope$DrawParams;
+Landroidx/compose/ui/graphics/drawscope/CanvasDrawScope$drawContext$1;
+Landroidx/compose/ui/graphics/drawscope/CanvasDrawScope;
+Landroidx/compose/ui/graphics/drawscope/CanvasDrawScopeKt$asDrawTransform$1;
+Landroidx/compose/ui/graphics/drawscope/CanvasDrawScopeKt;
+Landroidx/compose/ui/graphics/drawscope/ContentDrawScope;
+Landroidx/compose/ui/graphics/drawscope/DrawContext;
+Landroidx/compose/ui/graphics/drawscope/DrawScope$Companion;
+Landroidx/compose/ui/graphics/drawscope/DrawScope;
+Landroidx/compose/ui/graphics/drawscope/DrawStyle;
+Landroidx/compose/ui/graphics/drawscope/DrawTransform;
+Landroidx/compose/ui/graphics/drawscope/EmptyCanvas;
+Landroidx/compose/ui/graphics/drawscope/Fill;
+Landroidx/compose/ui/graphics/drawscope/Stroke;
+Landroidx/compose/ui/graphics/painter/BitmapPainter;
+Landroidx/compose/ui/graphics/painter/Painter$drawLambda$1;
+Landroidx/compose/ui/graphics/painter/Painter;
+Landroidx/compose/ui/graphics/vector/ImageVector;
+Landroidx/compose/ui/graphics/vector/VectorPainter;
+Landroidx/compose/ui/graphics/vector/VectorPainterKt;
+Landroidx/compose/ui/hapticfeedback/HapticFeedback;
+Landroidx/compose/ui/hapticfeedback/PlatformHapticFeedback;
+Landroidx/compose/ui/input/InputMode$Companion;
+Landroidx/compose/ui/input/InputMode;
+Landroidx/compose/ui/input/InputModeManager;
+Landroidx/compose/ui/input/InputModeManagerImpl;
+Landroidx/compose/ui/input/ScrollContainerInfo;
+Landroidx/compose/ui/input/ScrollContainerInfoKt$ModifierLocalScrollContainerInfo$1;
+Landroidx/compose/ui/input/ScrollContainerInfoKt$consumeScrollContainerInfo$1;
+Landroidx/compose/ui/input/ScrollContainerInfoKt$provideScrollContainerInfo$$inlined$debugInspectorInfo$1;
+Landroidx/compose/ui/input/ScrollContainerInfoKt$provideScrollContainerInfo$2;
+Landroidx/compose/ui/input/ScrollContainerInfoKt;
+Landroidx/compose/ui/input/focus/FocusAwareInputModifier;
+Landroidx/compose/ui/input/focus/FocusDirectedInputEvent;
+Landroidx/compose/ui/input/key/Key$Companion;
+Landroidx/compose/ui/input/key/Key;
+Landroidx/compose/ui/input/key/KeyEvent;
+Landroidx/compose/ui/input/key/KeyEventType$Companion;
+Landroidx/compose/ui/input/key/KeyEventType;
+Landroidx/compose/ui/input/key/KeyEvent_androidKt;
+Landroidx/compose/ui/input/key/KeyInputModifier;
+Landroidx/compose/ui/input/key/KeyInputModifierKt$ModifierLocalKeyInput$1;
+Landroidx/compose/ui/input/key/KeyInputModifierKt$onKeyEvent$$inlined$debugInspectorInfo$1;
+Landroidx/compose/ui/input/key/KeyInputModifierKt;
+Landroidx/compose/ui/input/nestedscroll/NestedScrollConnection;
+Landroidx/compose/ui/input/nestedscroll/NestedScrollDispatcher$calculateNestedScrollScope$1;
+Landroidx/compose/ui/input/nestedscroll/NestedScrollDispatcher$dispatchPostFling$1;
+Landroidx/compose/ui/input/nestedscroll/NestedScrollDispatcher$dispatchPreFling$1;
+Landroidx/compose/ui/input/nestedscroll/NestedScrollDispatcher;
+Landroidx/compose/ui/input/nestedscroll/NestedScrollModifierKt$nestedScroll$$inlined$debugInspectorInfo$1;
+Landroidx/compose/ui/input/nestedscroll/NestedScrollModifierKt$nestedScroll$2;
+Landroidx/compose/ui/input/nestedscroll/NestedScrollModifierKt;
+Landroidx/compose/ui/input/nestedscroll/NestedScrollModifierLocal$1;
+Landroidx/compose/ui/input/nestedscroll/NestedScrollModifierLocal$onPostFling$1;
+Landroidx/compose/ui/input/nestedscroll/NestedScrollModifierLocal$onPreFling$1;
+Landroidx/compose/ui/input/nestedscroll/NestedScrollModifierLocal;
+Landroidx/compose/ui/input/nestedscroll/NestedScrollModifierLocalKt$ModifierLocalNestedScroll$1;
+Landroidx/compose/ui/input/nestedscroll/NestedScrollModifierLocalKt;
+Landroidx/compose/ui/input/nestedscroll/NestedScrollSource$Companion;
+Landroidx/compose/ui/input/nestedscroll/NestedScrollSource;
+Landroidx/compose/ui/input/pointer/AwaitPointerEventScope;
+Landroidx/compose/ui/input/pointer/HistoricalChange;
+Landroidx/compose/ui/input/pointer/HitPathTracker;
+Landroidx/compose/ui/input/pointer/InternalPointerEvent;
+Landroidx/compose/ui/input/pointer/MotionEventAdapter;
+Landroidx/compose/ui/input/pointer/MotionEventHelper;
+Landroidx/compose/ui/input/pointer/Node;
+Landroidx/compose/ui/input/pointer/NodeParent;
+Landroidx/compose/ui/input/pointer/PointerButtons;
+Landroidx/compose/ui/input/pointer/PointerEvent;
+Landroidx/compose/ui/input/pointer/PointerEventKt;
+Landroidx/compose/ui/input/pointer/PointerEventPass;
+Landroidx/compose/ui/input/pointer/PointerEventTimeoutCancellationException;
+Landroidx/compose/ui/input/pointer/PointerEventType$Companion;
+Landroidx/compose/ui/input/pointer/PointerEventType;
+Landroidx/compose/ui/input/pointer/PointerEvent_androidKt;
+Landroidx/compose/ui/input/pointer/PointerIcon;
+Landroidx/compose/ui/input/pointer/PointerIconKt;
+Landroidx/compose/ui/input/pointer/PointerIconService;
+Landroidx/compose/ui/input/pointer/PointerId;
+Landroidx/compose/ui/input/pointer/PointerInputChange;
+Landroidx/compose/ui/input/pointer/PointerInputChangeEventProducer$PointerInputData;
+Landroidx/compose/ui/input/pointer/PointerInputChangeEventProducer;
+Landroidx/compose/ui/input/pointer/PointerInputEvent;
+Landroidx/compose/ui/input/pointer/PointerInputEventData;
+Landroidx/compose/ui/input/pointer/PointerInputEventProcessor;
+Landroidx/compose/ui/input/pointer/PointerInputEventProcessorKt;
+Landroidx/compose/ui/input/pointer/PointerInputFilter;
+Landroidx/compose/ui/input/pointer/PointerInputModifier;
+Landroidx/compose/ui/input/pointer/PointerInputScope;
+Landroidx/compose/ui/input/pointer/PointerKeyboardModifiers;
+Landroidx/compose/ui/input/pointer/PointerType$Companion;
+Landroidx/compose/ui/input/pointer/PointerType;
+Landroidx/compose/ui/input/pointer/PositionCalculator;
+Landroidx/compose/ui/input/pointer/ProcessResult;
+Landroidx/compose/ui/input/pointer/SuspendingPointerInputFilter$PointerEventHandlerCoroutine$withTimeout$1;
+Landroidx/compose/ui/input/pointer/SuspendingPointerInputFilter$PointerEventHandlerCoroutine$withTimeout$job$1;
+Landroidx/compose/ui/input/pointer/SuspendingPointerInputFilter$PointerEventHandlerCoroutine$withTimeoutOrNull$1;
+Landroidx/compose/ui/input/pointer/SuspendingPointerInputFilter$PointerEventHandlerCoroutine;
+Landroidx/compose/ui/input/pointer/SuspendingPointerInputFilter$WhenMappings;
+Landroidx/compose/ui/input/pointer/SuspendingPointerInputFilter$awaitPointerEventScope$2$2;
+Landroidx/compose/ui/input/pointer/SuspendingPointerInputFilter;
+Landroidx/compose/ui/input/pointer/SuspendingPointerInputFilterKt$pointerInput$$inlined$debugInspectorInfo$1;
+Landroidx/compose/ui/input/pointer/SuspendingPointerInputFilterKt$pointerInput$$inlined$debugInspectorInfo$2;
+Landroidx/compose/ui/input/pointer/SuspendingPointerInputFilterKt$pointerInput$$inlined$debugInspectorInfo$3;
+Landroidx/compose/ui/input/pointer/SuspendingPointerInputFilterKt$pointerInput$2$2$1;
+Landroidx/compose/ui/input/pointer/SuspendingPointerInputFilterKt$pointerInput$2;
+Landroidx/compose/ui/input/pointer/SuspendingPointerInputFilterKt$pointerInput$4$2$1;
+Landroidx/compose/ui/input/pointer/SuspendingPointerInputFilterKt$pointerInput$4;
+Landroidx/compose/ui/input/pointer/SuspendingPointerInputFilterKt$pointerInput$6$2$1;
+Landroidx/compose/ui/input/pointer/SuspendingPointerInputFilterKt$pointerInput$6;
+Landroidx/compose/ui/input/pointer/SuspendingPointerInputFilterKt;
+Landroidx/compose/ui/input/pointer/util/PointAtTime;
+Landroidx/compose/ui/input/pointer/util/PolynomialFit;
+Landroidx/compose/ui/input/pointer/util/VelocityEstimate$Companion;
+Landroidx/compose/ui/input/pointer/util/VelocityEstimate;
+Landroidx/compose/ui/input/pointer/util/VelocityTracker;
+Landroidx/compose/ui/input/pointer/util/VelocityTrackerKt;
+Landroidx/compose/ui/input/rotary/RotaryInputModifierKt$ModifierLocalRotaryScrollParent$1;
+Landroidx/compose/ui/input/rotary/RotaryInputModifierKt$focusAwareCallback$1;
+Landroidx/compose/ui/input/rotary/RotaryInputModifierKt$onRotaryScrollEvent$$inlined$debugInspectorInfo$1;
+Landroidx/compose/ui/input/rotary/RotaryInputModifierKt;
+Landroidx/compose/ui/input/rotary/RotaryScrollEvent;
+Landroidx/compose/ui/layout/AlignmentLine$Companion;
+Landroidx/compose/ui/layout/AlignmentLine;
+Landroidx/compose/ui/layout/AlignmentLineKt$FirstBaseline$1;
+Landroidx/compose/ui/layout/AlignmentLineKt$LastBaseline$1;
+Landroidx/compose/ui/layout/AlignmentLineKt;
+Landroidx/compose/ui/layout/BeyondBoundsLayout;
+Landroidx/compose/ui/layout/BeyondBoundsLayoutKt$ModifierLocalBeyondBoundsLayout$1;
+Landroidx/compose/ui/layout/BeyondBoundsLayoutKt;
+Landroidx/compose/ui/layout/ComposableSingletons$SubcomposeLayoutKt$lambda-1$1;
+Landroidx/compose/ui/layout/ComposableSingletons$SubcomposeLayoutKt;
+Landroidx/compose/ui/layout/ContentScale$Companion$Crop$1;
+Landroidx/compose/ui/layout/ContentScale$Companion$FillBounds$1;
+Landroidx/compose/ui/layout/ContentScale$Companion$FillHeight$1;
+Landroidx/compose/ui/layout/ContentScale$Companion$FillWidth$1;
+Landroidx/compose/ui/layout/ContentScale$Companion$Fit$1;
+Landroidx/compose/ui/layout/ContentScale$Companion$Inside$1;
+Landroidx/compose/ui/layout/ContentScale$Companion;
+Landroidx/compose/ui/layout/ContentScale;
+Landroidx/compose/ui/layout/ContentScaleKt;
+Landroidx/compose/ui/layout/FixedScale;
+Landroidx/compose/ui/layout/HorizontalAlignmentLine;
+Landroidx/compose/ui/layout/IntrinsicMeasurable;
+Landroidx/compose/ui/layout/IntrinsicMeasureScope;
+Landroidx/compose/ui/layout/LayoutCoordinates;
+Landroidx/compose/ui/layout/LayoutCoordinatesKt;
+Landroidx/compose/ui/layout/LayoutInfo;
+Landroidx/compose/ui/layout/LayoutKt$materializerOf$1;
+Landroidx/compose/ui/layout/LayoutKt;
+Landroidx/compose/ui/layout/LayoutModifier;
+Landroidx/compose/ui/layout/LayoutNodeSubcompositionsState$NodeState;
+Landroidx/compose/ui/layout/LayoutNodeSubcompositionsState$Scope;
+Landroidx/compose/ui/layout/LayoutNodeSubcompositionsState$createMeasurePolicy$1$measure$1;
+Landroidx/compose/ui/layout/LayoutNodeSubcompositionsState$createMeasurePolicy$1;
+Landroidx/compose/ui/layout/LayoutNodeSubcompositionsState$precompose$1;
+Landroidx/compose/ui/layout/LayoutNodeSubcompositionsState$subcompose$2$1$1;
+Landroidx/compose/ui/layout/LayoutNodeSubcompositionsState;
+Landroidx/compose/ui/layout/LookaheadLayoutCoordinates;
+Landroidx/compose/ui/layout/LookaheadLayoutCoordinatesImpl;
+Landroidx/compose/ui/layout/LookaheadScope;
+Landroidx/compose/ui/layout/Measurable;
+Landroidx/compose/ui/layout/MeasurePolicy;
+Landroidx/compose/ui/layout/MeasureResult;
+Landroidx/compose/ui/layout/MeasureScope$layout$1;
+Landroidx/compose/ui/layout/MeasureScope;
+Landroidx/compose/ui/layout/Measured;
+Landroidx/compose/ui/layout/NoOpSubcomposeSlotReusePolicy;
+Landroidx/compose/ui/layout/OnGloballyPositionedModifier;
+Landroidx/compose/ui/layout/OnGloballyPositionedModifierImpl;
+Landroidx/compose/ui/layout/OnGloballyPositionedModifierKt$onGloballyPositioned$$inlined$debugInspectorInfo$1;
+Landroidx/compose/ui/layout/OnGloballyPositionedModifierKt;
+Landroidx/compose/ui/layout/OnPlacedModifier;
+Landroidx/compose/ui/layout/OnRemeasuredModifier;
+Landroidx/compose/ui/layout/ParentDataModifier;
+Landroidx/compose/ui/layout/Placeable$PlacementScope$Companion;
+Landroidx/compose/ui/layout/Placeable$PlacementScope;
+Landroidx/compose/ui/layout/Placeable;
+Landroidx/compose/ui/layout/PlaceableKt$DefaultLayerBlock$1;
+Landroidx/compose/ui/layout/PlaceableKt;
+Landroidx/compose/ui/layout/Remeasurement;
+Landroidx/compose/ui/layout/RemeasurementModifier;
+Landroidx/compose/ui/layout/RootMeasurePolicy$measure$1;
+Landroidx/compose/ui/layout/RootMeasurePolicy$measure$2;
+Landroidx/compose/ui/layout/RootMeasurePolicy$measure$4;
+Landroidx/compose/ui/layout/RootMeasurePolicy;
+Landroidx/compose/ui/layout/ScaleFactor$Companion;
+Landroidx/compose/ui/layout/ScaleFactor;
+Landroidx/compose/ui/layout/ScaleFactorKt;
+Landroidx/compose/ui/layout/SubcomposeLayoutKt$SubcomposeLayout$$inlined$ComposeNode$1;
+Landroidx/compose/ui/layout/SubcomposeLayoutKt$SubcomposeLayout$2;
+Landroidx/compose/ui/layout/SubcomposeLayoutKt$SubcomposeLayout$4;
+Landroidx/compose/ui/layout/SubcomposeLayoutKt$SubcomposeLayout$5$1$invoke$$inlined$onDispose$1;
+Landroidx/compose/ui/layout/SubcomposeLayoutKt$SubcomposeLayout$5$1;
+Landroidx/compose/ui/layout/SubcomposeLayoutKt$SubcomposeLayout$6;
+Landroidx/compose/ui/layout/SubcomposeLayoutKt;
+Landroidx/compose/ui/layout/SubcomposeLayoutState$PrecomposedSlotHandle;
+Landroidx/compose/ui/layout/SubcomposeLayoutState$setCompositionContext$1;
+Landroidx/compose/ui/layout/SubcomposeLayoutState$setMeasurePolicy$1;
+Landroidx/compose/ui/layout/SubcomposeLayoutState$setRoot$1;
+Landroidx/compose/ui/layout/SubcomposeLayoutState;
+Landroidx/compose/ui/layout/SubcomposeMeasureScope;
+Landroidx/compose/ui/layout/SubcomposeSlotReusePolicy$SlotIdsSet;
+Landroidx/compose/ui/layout/SubcomposeSlotReusePolicy;
+Landroidx/compose/ui/modifier/BackwardsCompatLocalMap;
+Landroidx/compose/ui/modifier/EmptyMap;
+Landroidx/compose/ui/modifier/ModifierLocal;
+Landroidx/compose/ui/modifier/ModifierLocalConsumer;
+Landroidx/compose/ui/modifier/ModifierLocalConsumerImpl;
+Landroidx/compose/ui/modifier/ModifierLocalConsumerKt$modifierLocalConsumer$$inlined$debugInspectorInfo$1;
+Landroidx/compose/ui/modifier/ModifierLocalConsumerKt;
+Landroidx/compose/ui/modifier/ModifierLocalKt;
+Landroidx/compose/ui/modifier/ModifierLocalManager$invalidate$1;
+Landroidx/compose/ui/modifier/ModifierLocalManager;
+Landroidx/compose/ui/modifier/ModifierLocalMap;
+Landroidx/compose/ui/modifier/ModifierLocalNode;
+Landroidx/compose/ui/modifier/ModifierLocalNodeKt;
+Landroidx/compose/ui/modifier/ModifierLocalProvider;
+Landroidx/compose/ui/modifier/ModifierLocalReadScope;
+Landroidx/compose/ui/modifier/ProvidableModifierLocal;
+Landroidx/compose/ui/node/AlignmentLines$recalculate$1;
+Landroidx/compose/ui/node/AlignmentLines;
+Landroidx/compose/ui/node/AlignmentLinesOwner;
+Landroidx/compose/ui/node/BackwardsCompatNode$initializeModifier$1;
+Landroidx/compose/ui/node/BackwardsCompatNode$initializeModifier$4;
+Landroidx/compose/ui/node/BackwardsCompatNode$updateDrawCache$1;
+Landroidx/compose/ui/node/BackwardsCompatNode$updateFocusOrderModifierLocalConsumer$1;
+Landroidx/compose/ui/node/BackwardsCompatNode$updateModifierLocalConsumer$1;
+Landroidx/compose/ui/node/BackwardsCompatNode;
+Landroidx/compose/ui/node/BackwardsCompatNodeKt$DetachedModifierLocalReadScope$1;
+Landroidx/compose/ui/node/BackwardsCompatNodeKt$onDrawCacheReadsChanged$1;
+Landroidx/compose/ui/node/BackwardsCompatNodeKt$updateFocusOrderModifierLocalConsumer$1;
+Landroidx/compose/ui/node/BackwardsCompatNodeKt$updateModifierLocalConsumer$1;
+Landroidx/compose/ui/node/BackwardsCompatNodeKt;
+Landroidx/compose/ui/node/CenteredArray;
+Landroidx/compose/ui/node/ComposeUiNode$Companion$SetDensity$1;
+Landroidx/compose/ui/node/ComposeUiNode$Companion$SetLayoutDirection$1;
+Landroidx/compose/ui/node/ComposeUiNode$Companion$SetMeasurePolicy$1;
+Landroidx/compose/ui/node/ComposeUiNode$Companion$SetModifier$1;
+Landroidx/compose/ui/node/ComposeUiNode$Companion$SetViewConfiguration$1;
+Landroidx/compose/ui/node/ComposeUiNode$Companion$VirtualConstructor$1;
+Landroidx/compose/ui/node/ComposeUiNode$Companion;
+Landroidx/compose/ui/node/ComposeUiNode;
+Landroidx/compose/ui/node/DelegatableNode;
+Landroidx/compose/ui/node/DelegatableNodeKt;
+Landroidx/compose/ui/node/DepthSortedSet$DepthComparator$1;
+Landroidx/compose/ui/node/DepthSortedSet$mapOfOriginalDepth$2;
+Landroidx/compose/ui/node/DepthSortedSet;
+Landroidx/compose/ui/node/DiffCallback;
+Landroidx/compose/ui/node/DistanceAndInLayer;
+Landroidx/compose/ui/node/DrawModifierNode;
+Landroidx/compose/ui/node/DrawModifierNodeKt;
+Landroidx/compose/ui/node/GlobalPositionAwareModifierNode;
+Landroidx/compose/ui/node/HitTestResult$HitTestResultIterator;
+Landroidx/compose/ui/node/HitTestResult$SubList;
+Landroidx/compose/ui/node/HitTestResult;
+Landroidx/compose/ui/node/HitTestResultKt;
+Landroidx/compose/ui/node/InnerNodeCoordinator$Companion;
+Landroidx/compose/ui/node/InnerNodeCoordinator$LookaheadDelegateImpl;
+Landroidx/compose/ui/node/InnerNodeCoordinator$tail$1;
+Landroidx/compose/ui/node/InnerNodeCoordinator;
+Landroidx/compose/ui/node/IntStack;
+Landroidx/compose/ui/node/IntermediateLayoutModifierNode;
+Landroidx/compose/ui/node/IntrinsicsPolicy$Companion;
+Landroidx/compose/ui/node/IntrinsicsPolicy;
+Landroidx/compose/ui/node/LayerPositionalProperties;
+Landroidx/compose/ui/node/LayoutAwareModifierNode;
+Landroidx/compose/ui/node/LayoutModifierNode;
+Landroidx/compose/ui/node/LayoutModifierNodeCoordinator$Companion;
+Landroidx/compose/ui/node/LayoutModifierNodeCoordinator$LookaheadDelegateForIntermediateLayoutModifier;
+Landroidx/compose/ui/node/LayoutModifierNodeCoordinator$LookaheadDelegateForLayoutModifierNode;
+Landroidx/compose/ui/node/LayoutModifierNodeCoordinator;
+Landroidx/compose/ui/node/LayoutModifierNodeCoordinatorKt;
+Landroidx/compose/ui/node/LayoutModifierNodeKt;
+Landroidx/compose/ui/node/LayoutNode$$ExternalSyntheticLambda0;
+Landroidx/compose/ui/node/LayoutNode$Companion$Constructor$1;
+Landroidx/compose/ui/node/LayoutNode$Companion$DummyViewConfiguration$1;
+Landroidx/compose/ui/node/LayoutNode$Companion$ErrorMeasurePolicy$1;
+Landroidx/compose/ui/node/LayoutNode$Companion;
+Landroidx/compose/ui/node/LayoutNode$LayoutState;
+Landroidx/compose/ui/node/LayoutNode$NoIntrinsicsMeasurePolicy;
+Landroidx/compose/ui/node/LayoutNode$UsageByParent;
+Landroidx/compose/ui/node/LayoutNode$WhenMappings;
+Landroidx/compose/ui/node/LayoutNode$_foldedChildren$1;
+Landroidx/compose/ui/node/LayoutNode;
+Landroidx/compose/ui/node/LayoutNodeAlignmentLines;
+Landroidx/compose/ui/node/LayoutNodeDrawScope;
+Landroidx/compose/ui/node/LayoutNodeDrawScopeKt;
+Landroidx/compose/ui/node/LayoutNodeKt;
+Landroidx/compose/ui/node/LayoutNodeLayoutDelegate$LookaheadPassDelegate;
+Landroidx/compose/ui/node/LayoutNodeLayoutDelegate$MeasurePassDelegate$WhenMappings;
+Landroidx/compose/ui/node/LayoutNodeLayoutDelegate$MeasurePassDelegate$childMeasurables$1;
+Landroidx/compose/ui/node/LayoutNodeLayoutDelegate$MeasurePassDelegate$layoutChildren$1$1$1;
+Landroidx/compose/ui/node/LayoutNodeLayoutDelegate$MeasurePassDelegate$layoutChildren$1$1$2;
+Landroidx/compose/ui/node/LayoutNodeLayoutDelegate$MeasurePassDelegate$layoutChildren$1$1;
+Landroidx/compose/ui/node/LayoutNodeLayoutDelegate$MeasurePassDelegate$placeOuterCoordinator$1;
+Landroidx/compose/ui/node/LayoutNodeLayoutDelegate$MeasurePassDelegate$remeasure$1;
+Landroidx/compose/ui/node/LayoutNodeLayoutDelegate$MeasurePassDelegate;
+Landroidx/compose/ui/node/LayoutNodeLayoutDelegate$performLookaheadMeasure$1;
+Landroidx/compose/ui/node/LayoutNodeLayoutDelegate$performMeasure$2;
+Landroidx/compose/ui/node/LayoutNodeLayoutDelegate;
+Landroidx/compose/ui/node/LayoutNodeLayoutDelegateKt;
+Landroidx/compose/ui/node/LayoutTreeConsistencyChecker;
+Landroidx/compose/ui/node/LookaheadCapablePlaceable;
+Landroidx/compose/ui/node/LookaheadDelegate;
+Landroidx/compose/ui/node/MeasureAndLayoutDelegate$PostponedRequest;
+Landroidx/compose/ui/node/MeasureAndLayoutDelegate$WhenMappings;
+Landroidx/compose/ui/node/MeasureAndLayoutDelegate;
+Landroidx/compose/ui/node/MutableVectorWithMutationTracking;
+Landroidx/compose/ui/node/MyersDiffKt;
+Landroidx/compose/ui/node/NodeChain$Differ;
+Landroidx/compose/ui/node/NodeChain$Logger;
+Landroidx/compose/ui/node/NodeChain;
+Landroidx/compose/ui/node/NodeChainKt$SentinelHead$1;
+Landroidx/compose/ui/node/NodeChainKt$fillVector$1;
+Landroidx/compose/ui/node/NodeChainKt;
+Landroidx/compose/ui/node/NodeCoordinator$Companion$PointerInputSource$1;
+Landroidx/compose/ui/node/NodeCoordinator$Companion$SemanticsSource$1;
+Landroidx/compose/ui/node/NodeCoordinator$Companion$onCommitAffectingLayer$1;
+Landroidx/compose/ui/node/NodeCoordinator$Companion$onCommitAffectingLayerParams$1;
+Landroidx/compose/ui/node/NodeCoordinator$Companion;
+Landroidx/compose/ui/node/NodeCoordinator$HitTestSource;
+Landroidx/compose/ui/node/NodeCoordinator$hit$1;
+Landroidx/compose/ui/node/NodeCoordinator$hitNear$1;
+Landroidx/compose/ui/node/NodeCoordinator$invalidateParentLayer$1;
+Landroidx/compose/ui/node/NodeCoordinator$invoke$1;
+Landroidx/compose/ui/node/NodeCoordinator$speculativeHit$1;
+Landroidx/compose/ui/node/NodeCoordinator$updateLayerParameters$1;
+Landroidx/compose/ui/node/NodeCoordinator;
+Landroidx/compose/ui/node/NodeCoordinatorKt;
+Landroidx/compose/ui/node/NodeKind;
+Landroidx/compose/ui/node/NodeKindKt;
+Landroidx/compose/ui/node/OnPositionedDispatcher$Companion$DepthComparator;
+Landroidx/compose/ui/node/OnPositionedDispatcher$Companion;
+Landroidx/compose/ui/node/OnPositionedDispatcher;
+Landroidx/compose/ui/node/OwnedLayer;
+Landroidx/compose/ui/node/Owner$Companion;
+Landroidx/compose/ui/node/Owner$OnLayoutCompletedListener;
+Landroidx/compose/ui/node/Owner;
+Landroidx/compose/ui/node/OwnerScope;
+Landroidx/compose/ui/node/OwnerSnapshotObserver$clearInvalidObservations$1;
+Landroidx/compose/ui/node/OwnerSnapshotObserver$onCommitAffectingLayout$1;
+Landroidx/compose/ui/node/OwnerSnapshotObserver$onCommitAffectingLayoutModifier$1;
+Landroidx/compose/ui/node/OwnerSnapshotObserver$onCommitAffectingLayoutModifierInLookahead$1;
+Landroidx/compose/ui/node/OwnerSnapshotObserver$onCommitAffectingLookaheadLayout$1;
+Landroidx/compose/ui/node/OwnerSnapshotObserver$onCommitAffectingLookaheadMeasure$1;
+Landroidx/compose/ui/node/OwnerSnapshotObserver$onCommitAffectingMeasure$1;
+Landroidx/compose/ui/node/OwnerSnapshotObserver;
+Landroidx/compose/ui/node/ParentDataModifierNode;
+Landroidx/compose/ui/node/ParentDataModifierNodeKt;
+Landroidx/compose/ui/node/PointerInputModifierNode;
+Landroidx/compose/ui/node/PointerInputModifierNodeKt;
+Landroidx/compose/ui/node/RootForTest;
+Landroidx/compose/ui/node/SemanticsModifierNode;
+Landroidx/compose/ui/node/SemanticsModifierNodeKt;
+Landroidx/compose/ui/node/Snake;
+Landroidx/compose/ui/node/TreeSet;
+Landroidx/compose/ui/node/UiApplier;
+Landroidx/compose/ui/platform/AbstractComposeView$ensureCompositionCreated$1;
+Landroidx/compose/ui/platform/AbstractComposeView;
+Landroidx/compose/ui/platform/AccessibilityIterators$AbstractTextSegmentIterator;
+Landroidx/compose/ui/platform/AccessibilityIterators$CharacterTextSegmentIterator$Companion;
+Landroidx/compose/ui/platform/AccessibilityIterators$CharacterTextSegmentIterator;
+Landroidx/compose/ui/platform/AccessibilityIterators$LineTextSegmentIterator$Companion;
+Landroidx/compose/ui/platform/AccessibilityIterators$LineTextSegmentIterator;
+Landroidx/compose/ui/platform/AccessibilityIterators$PageTextSegmentIterator$Companion;
+Landroidx/compose/ui/platform/AccessibilityIterators$PageTextSegmentIterator;
+Landroidx/compose/ui/platform/AccessibilityIterators$ParagraphTextSegmentIterator$Companion;
+Landroidx/compose/ui/platform/AccessibilityIterators$ParagraphTextSegmentIterator;
+Landroidx/compose/ui/platform/AccessibilityIterators$TextSegmentIterator;
+Landroidx/compose/ui/platform/AccessibilityIterators$WordTextSegmentIterator$Companion;
+Landroidx/compose/ui/platform/AccessibilityIterators$WordTextSegmentIterator;
+Landroidx/compose/ui/platform/AccessibilityManager;
+Landroidx/compose/ui/platform/AccessibilityNodeInfoVerificationHelperMethods;
+Landroidx/compose/ui/platform/AndroidAccessibilityManager$Companion;
+Landroidx/compose/ui/platform/AndroidAccessibilityManager;
+Landroidx/compose/ui/platform/AndroidClipboardManager;
+Landroidx/compose/ui/platform/AndroidComposeView$$ExternalSyntheticLambda0;
+Landroidx/compose/ui/platform/AndroidComposeView$$ExternalSyntheticLambda1;
+Landroidx/compose/ui/platform/AndroidComposeView$$ExternalSyntheticLambda2;
+Landroidx/compose/ui/platform/AndroidComposeView$$ExternalSyntheticLambda3;
+Landroidx/compose/ui/platform/AndroidComposeView$Companion;
+Landroidx/compose/ui/platform/AndroidComposeView$ViewTreeOwners;
+Landroidx/compose/ui/platform/AndroidComposeView$_inputModeManager$1;
+Landroidx/compose/ui/platform/AndroidComposeView$configurationChangeObserver$1;
+Landroidx/compose/ui/platform/AndroidComposeView$keyInputModifier$1;
+Landroidx/compose/ui/platform/AndroidComposeView$pointerIconService$1;
+Landroidx/compose/ui/platform/AndroidComposeView$resendMotionEventOnLayout$1;
+Landroidx/compose/ui/platform/AndroidComposeView$resendMotionEventRunnable$1;
+Landroidx/compose/ui/platform/AndroidComposeView$rotaryInputModifier$1;
+Landroidx/compose/ui/platform/AndroidComposeView$scrollContainerInfo$1$value$1;
+Landroidx/compose/ui/platform/AndroidComposeView$scrollContainerInfo$1;
+Landroidx/compose/ui/platform/AndroidComposeView$semanticsModifier$1;
+Landroidx/compose/ui/platform/AndroidComposeView$snapshotObserver$1$$ExternalSyntheticLambda0;
+Landroidx/compose/ui/platform/AndroidComposeView$snapshotObserver$1;
+Landroidx/compose/ui/platform/AndroidComposeView;
+Landroidx/compose/ui/platform/AndroidComposeViewAccessibilityDelegateCompat$$ExternalSyntheticLambda0;
+Landroidx/compose/ui/platform/AndroidComposeViewAccessibilityDelegateCompat$$ExternalSyntheticLambda1;
+Landroidx/compose/ui/platform/AndroidComposeViewAccessibilityDelegateCompat$$ExternalSyntheticLambda2;
+Landroidx/compose/ui/platform/AndroidComposeViewAccessibilityDelegateCompat$1;
+Landroidx/compose/ui/platform/AndroidComposeViewAccessibilityDelegateCompat$Api24Impl;
+Landroidx/compose/ui/platform/AndroidComposeViewAccessibilityDelegateCompat$Api29Impl;
+Landroidx/compose/ui/platform/AndroidComposeViewAccessibilityDelegateCompat$Companion;
+Landroidx/compose/ui/platform/AndroidComposeViewAccessibilityDelegateCompat$MyNodeProvider;
+Landroidx/compose/ui/platform/AndroidComposeViewAccessibilityDelegateCompat$PendingTextTraversedEvent;
+Landroidx/compose/ui/platform/AndroidComposeViewAccessibilityDelegateCompat$SemanticsNodeCopy;
+Landroidx/compose/ui/platform/AndroidComposeViewAccessibilityDelegateCompat$WhenMappings;
+Landroidx/compose/ui/platform/AndroidComposeViewAccessibilityDelegateCompat$boundsUpdatesEventLoop$1;
+Landroidx/compose/ui/platform/AndroidComposeViewAccessibilityDelegateCompat$populateAccessibilityNodeInfoProperties$isUnmergedLeafNode$1;
+Landroidx/compose/ui/platform/AndroidComposeViewAccessibilityDelegateCompat$sendScrollEventIfNeeded$1;
+Landroidx/compose/ui/platform/AndroidComposeViewAccessibilityDelegateCompat$sendScrollEventIfNeededLambda$1;
+Landroidx/compose/ui/platform/AndroidComposeViewAccessibilityDelegateCompat$sendSubtreeChangeAccessibilityEvents$1;
+Landroidx/compose/ui/platform/AndroidComposeViewAccessibilityDelegateCompat$sendSubtreeChangeAccessibilityEvents$semanticsWrapper$1;
+Landroidx/compose/ui/platform/AndroidComposeViewAccessibilityDelegateCompat;
+Landroidx/compose/ui/platform/AndroidComposeViewAccessibilityDelegateCompat_androidKt;
+Landroidx/compose/ui/platform/AndroidComposeViewForceDarkModeQ;
+Landroidx/compose/ui/platform/AndroidComposeViewVerificationHelperMethodsN;
+Landroidx/compose/ui/platform/AndroidComposeViewVerificationHelperMethodsO;
+Landroidx/compose/ui/platform/AndroidComposeView_androidKt$textInputServiceFactory$1;
+Landroidx/compose/ui/platform/AndroidComposeView_androidKt;
+Landroidx/compose/ui/platform/AndroidCompositionLocals_androidKt$LocalConfiguration$1;
+Landroidx/compose/ui/platform/AndroidCompositionLocals_androidKt$LocalContext$1;
+Landroidx/compose/ui/platform/AndroidCompositionLocals_androidKt$LocalImageVectorCache$1;
+Landroidx/compose/ui/platform/AndroidCompositionLocals_androidKt$LocalLifecycleOwner$1;
+Landroidx/compose/ui/platform/AndroidCompositionLocals_androidKt$LocalSavedStateRegistryOwner$1;
+Landroidx/compose/ui/platform/AndroidCompositionLocals_androidKt$LocalView$1;
+Landroidx/compose/ui/platform/AndroidCompositionLocals_androidKt$ProvideAndroidCompositionLocals$1$1;
+Landroidx/compose/ui/platform/AndroidCompositionLocals_androidKt$ProvideAndroidCompositionLocals$2$invoke$$inlined$onDispose$1;
+Landroidx/compose/ui/platform/AndroidCompositionLocals_androidKt$ProvideAndroidCompositionLocals$2;
+Landroidx/compose/ui/platform/AndroidCompositionLocals_androidKt$ProvideAndroidCompositionLocals$3;
+Landroidx/compose/ui/platform/AndroidCompositionLocals_androidKt$ProvideAndroidCompositionLocals$4;
+Landroidx/compose/ui/platform/AndroidCompositionLocals_androidKt$obtainImageVectorCache$1$invoke$$inlined$onDispose$1;
+Landroidx/compose/ui/platform/AndroidCompositionLocals_androidKt$obtainImageVectorCache$1;
+Landroidx/compose/ui/platform/AndroidCompositionLocals_androidKt$obtainImageVectorCache$callbacks$1$1;
+Landroidx/compose/ui/platform/AndroidCompositionLocals_androidKt;
+Landroidx/compose/ui/platform/AndroidFontResourceLoader;
+Landroidx/compose/ui/platform/AndroidTextToolbar$textActionModeCallback$1;
+Landroidx/compose/ui/platform/AndroidTextToolbar;
+Landroidx/compose/ui/platform/AndroidUiDispatcher$Companion$Main$2$dispatcher$1;
+Landroidx/compose/ui/platform/AndroidUiDispatcher$Companion$Main$2;
+Landroidx/compose/ui/platform/AndroidUiDispatcher$Companion$currentThread$1;
+Landroidx/compose/ui/platform/AndroidUiDispatcher$Companion;
+Landroidx/compose/ui/platform/AndroidUiDispatcher$dispatchCallback$1;
+Landroidx/compose/ui/platform/AndroidUiDispatcher;
+Landroidx/compose/ui/platform/AndroidUiDispatcher_androidKt;
+Landroidx/compose/ui/platform/AndroidUiFrameClock$withFrameNanos$2$1;
+Landroidx/compose/ui/platform/AndroidUiFrameClock$withFrameNanos$2$2;
+Landroidx/compose/ui/platform/AndroidUiFrameClock$withFrameNanos$2$callback$1;
+Landroidx/compose/ui/platform/AndroidUiFrameClock;
+Landroidx/compose/ui/platform/AndroidUriHandler;
+Landroidx/compose/ui/platform/AndroidViewConfiguration;
+Landroidx/compose/ui/platform/AndroidViewsHandler;
+Landroidx/compose/ui/platform/CalculateMatrixToWindow;
+Landroidx/compose/ui/platform/CalculateMatrixToWindowApi29;
+Landroidx/compose/ui/platform/ClipboardManager;
+Landroidx/compose/ui/platform/ComposableSingletons$Wrapper_androidKt$lambda-1$1;
+Landroidx/compose/ui/platform/ComposableSingletons$Wrapper_androidKt;
+Landroidx/compose/ui/platform/ComposeView$Content$1;
+Landroidx/compose/ui/platform/ComposeView;
+Landroidx/compose/ui/platform/CompositionLocalsKt$LocalAccessibilityManager$1;
+Landroidx/compose/ui/platform/CompositionLocalsKt$LocalAutofill$1;
+Landroidx/compose/ui/platform/CompositionLocalsKt$LocalAutofillTree$1;
+Landroidx/compose/ui/platform/CompositionLocalsKt$LocalClipboardManager$1;
+Landroidx/compose/ui/platform/CompositionLocalsKt$LocalDensity$1;
+Landroidx/compose/ui/platform/CompositionLocalsKt$LocalFocusManager$1;
+Landroidx/compose/ui/platform/CompositionLocalsKt$LocalFontFamilyResolver$1;
+Landroidx/compose/ui/platform/CompositionLocalsKt$LocalFontLoader$1;
+Landroidx/compose/ui/platform/CompositionLocalsKt$LocalHapticFeedback$1;
+Landroidx/compose/ui/platform/CompositionLocalsKt$LocalInputModeManager$1;
+Landroidx/compose/ui/platform/CompositionLocalsKt$LocalLayoutDirection$1;
+Landroidx/compose/ui/platform/CompositionLocalsKt$LocalPointerIconService$1;
+Landroidx/compose/ui/platform/CompositionLocalsKt$LocalTextInputService$1;
+Landroidx/compose/ui/platform/CompositionLocalsKt$LocalTextToolbar$1;
+Landroidx/compose/ui/platform/CompositionLocalsKt$LocalUriHandler$1;
+Landroidx/compose/ui/platform/CompositionLocalsKt$LocalViewConfiguration$1;
+Landroidx/compose/ui/platform/CompositionLocalsKt$LocalWindowInfo$1;
+Landroidx/compose/ui/platform/CompositionLocalsKt$ProvideCommonCompositionLocals$1;
+Landroidx/compose/ui/platform/CompositionLocalsKt;
+Landroidx/compose/ui/platform/DeviceRenderNode;
+Landroidx/compose/ui/platform/DisposableSaveableStateRegistry;
+Landroidx/compose/ui/platform/DisposableSaveableStateRegistry_androidKt$DisposableSaveableStateRegistry$1;
+Landroidx/compose/ui/platform/DisposableSaveableStateRegistry_androidKt$DisposableSaveableStateRegistry$registered$1;
+Landroidx/compose/ui/platform/DisposableSaveableStateRegistry_androidKt$DisposableSaveableStateRegistry$saveableStateRegistry$1;
+Landroidx/compose/ui/platform/DisposableSaveableStateRegistry_androidKt;
+Landroidx/compose/ui/platform/DrawChildContainer;
+Landroidx/compose/ui/platform/GlobalSnapshotManager$ensureStarted$1;
+Landroidx/compose/ui/platform/GlobalSnapshotManager$ensureStarted$2;
+Landroidx/compose/ui/platform/GlobalSnapshotManager;
+Landroidx/compose/ui/platform/InspectableModifier$End;
+Landroidx/compose/ui/platform/InspectableModifier;
+Landroidx/compose/ui/platform/InspectableValueKt$NoInspectorInfo$1;
+Landroidx/compose/ui/platform/InspectableValueKt;
+Landroidx/compose/ui/platform/InspectorInfo;
+Landroidx/compose/ui/platform/InspectorValueInfo;
+Landroidx/compose/ui/platform/InvertMatrixKt;
+Landroidx/compose/ui/platform/JvmActuals_jvmKt;
+Landroidx/compose/ui/platform/LayerMatrixCache;
+Landroidx/compose/ui/platform/MotionDurationScaleImpl;
+Landroidx/compose/ui/platform/OutlineResolver;
+Landroidx/compose/ui/platform/RenderNodeApi29;
+Landroidx/compose/ui/platform/RenderNodeApi29VerificationHelper;
+Landroidx/compose/ui/platform/RenderNodeLayer$Companion$getMatrix$1;
+Landroidx/compose/ui/platform/RenderNodeLayer$Companion;
+Landroidx/compose/ui/platform/RenderNodeLayer;
+Landroidx/compose/ui/platform/ScrollObservationScope;
+Landroidx/compose/ui/platform/SemanticsNodeWithAdjustedBounds;
+Landroidx/compose/ui/platform/ShapeContainingUtilKt;
+Landroidx/compose/ui/platform/TextToolbar;
+Landroidx/compose/ui/platform/TextToolbarStatus;
+Landroidx/compose/ui/platform/UriHandler;
+Landroidx/compose/ui/platform/ViewCompositionStrategy$Companion;
+Landroidx/compose/ui/platform/ViewCompositionStrategy$DisposeOnDetachedFromWindowOrReleasedFromPool$installFor$1;
+Landroidx/compose/ui/platform/ViewCompositionStrategy$DisposeOnDetachedFromWindowOrReleasedFromPool$installFor$listener$1;
+Landroidx/compose/ui/platform/ViewCompositionStrategy$DisposeOnDetachedFromWindowOrReleasedFromPool$installFor$poolingContainerListener$1;
+Landroidx/compose/ui/platform/ViewCompositionStrategy$DisposeOnDetachedFromWindowOrReleasedFromPool;
+Landroidx/compose/ui/platform/ViewCompositionStrategy;
+Landroidx/compose/ui/platform/ViewConfiguration;
+Landroidx/compose/ui/platform/ViewLayer$Companion$OutlineProvider$1;
+Landroidx/compose/ui/platform/ViewLayer$Companion$getMatrix$1;
+Landroidx/compose/ui/platform/ViewLayer$Companion;
+Landroidx/compose/ui/platform/ViewLayer;
+Landroidx/compose/ui/platform/ViewLayerContainer;
+Landroidx/compose/ui/platform/ViewLayerVerificationHelper28;
+Landroidx/compose/ui/platform/ViewLayerVerificationHelper31;
+Landroidx/compose/ui/platform/ViewRootForTest$Companion;
+Landroidx/compose/ui/platform/ViewRootForTest;
+Landroidx/compose/ui/platform/WeakCache;
+Landroidx/compose/ui/platform/WindowInfo;
+Landroidx/compose/ui/platform/WindowInfoImpl$Companion;
+Landroidx/compose/ui/platform/WindowInfoImpl;
+Landroidx/compose/ui/platform/WindowRecomposerFactory$Companion$LifecycleAware$1;
+Landroidx/compose/ui/platform/WindowRecomposerFactory$Companion;
+Landroidx/compose/ui/platform/WindowRecomposerFactory;
+Landroidx/compose/ui/platform/WindowRecomposerPolicy$createAndInstallWindowRecomposer$1;
+Landroidx/compose/ui/platform/WindowRecomposerPolicy$createAndInstallWindowRecomposer$unsetJob$1;
+Landroidx/compose/ui/platform/WindowRecomposerPolicy;
+Landroidx/compose/ui/platform/WindowRecomposer_androidKt$createLifecycleAwareWindowRecomposer$1;
+Landroidx/compose/ui/platform/WindowRecomposer_androidKt$createLifecycleAwareWindowRecomposer$2$WhenMappings;
+Landroidx/compose/ui/platform/WindowRecomposer_androidKt$createLifecycleAwareWindowRecomposer$2$onStateChanged$1$1$1$1;
+Landroidx/compose/ui/platform/WindowRecomposer_androidKt$createLifecycleAwareWindowRecomposer$2$onStateChanged$1$1$1;
+Landroidx/compose/ui/platform/WindowRecomposer_androidKt$createLifecycleAwareWindowRecomposer$2$onStateChanged$1;
+Landroidx/compose/ui/platform/WindowRecomposer_androidKt$createLifecycleAwareWindowRecomposer$2;
+Landroidx/compose/ui/platform/WindowRecomposer_androidKt$getAnimationScaleFlowFor$1$1$1;
+Landroidx/compose/ui/platform/WindowRecomposer_androidKt$getAnimationScaleFlowFor$1$1$contentObserver$1;
+Landroidx/compose/ui/platform/WindowRecomposer_androidKt;
+Landroidx/compose/ui/platform/WrappedComposition$setContent$1$1$1;
+Landroidx/compose/ui/platform/WrappedComposition$setContent$1$1$2;
+Landroidx/compose/ui/platform/WrappedComposition$setContent$1$1$3;
+Landroidx/compose/ui/platform/WrappedComposition$setContent$1$1;
+Landroidx/compose/ui/platform/WrappedComposition$setContent$1;
+Landroidx/compose/ui/platform/WrappedComposition;
+Landroidx/compose/ui/platform/WrapperRenderNodeLayerHelperMethods;
+Landroidx/compose/ui/platform/WrapperVerificationHelperMethods;
+Landroidx/compose/ui/platform/Wrapper_androidKt;
+Landroidx/compose/ui/platform/accessibility/CollectionInfoKt;
+Landroidx/compose/ui/platform/actionmodecallback/TextActionModeCallback;
+Landroidx/compose/ui/res/ImageVectorCache$ImageVectorEntry;
+Landroidx/compose/ui/res/ImageVectorCache$Key;
+Landroidx/compose/ui/res/ImageVectorCache;
+Landroidx/compose/ui/res/PainterResources_androidKt;
+Landroidx/compose/ui/res/Resources_androidKt;
+Landroidx/compose/ui/res/StringResources_androidKt;
+Landroidx/compose/ui/semantics/AccessibilityAction;
+Landroidx/compose/ui/semantics/CollectionInfo;
+Landroidx/compose/ui/semantics/LiveRegionMode$Companion;
+Landroidx/compose/ui/semantics/LiveRegionMode;
+Landroidx/compose/ui/semantics/ProgressBarRangeInfo$Companion;
+Landroidx/compose/ui/semantics/ProgressBarRangeInfo;
+Landroidx/compose/ui/semantics/Role$Companion;
+Landroidx/compose/ui/semantics/Role;
+Landroidx/compose/ui/semantics/ScrollAxisRange;
+Landroidx/compose/ui/semantics/SemanticsActions;
+Landroidx/compose/ui/semantics/SemanticsConfiguration;
+Landroidx/compose/ui/semantics/SemanticsConfigurationKt$getOrNull$1;
+Landroidx/compose/ui/semantics/SemanticsConfigurationKt;
+Landroidx/compose/ui/semantics/SemanticsModifier;
+Landroidx/compose/ui/semantics/SemanticsModifierCore$Companion;
+Landroidx/compose/ui/semantics/SemanticsModifierCore;
+Landroidx/compose/ui/semantics/SemanticsModifierKt$clearAndSetSemantics$$inlined$debugInspectorInfo$1;
+Landroidx/compose/ui/semantics/SemanticsModifierKt$semantics$$inlined$debugInspectorInfo$1;
+Landroidx/compose/ui/semantics/SemanticsModifierKt;
+Landroidx/compose/ui/semantics/SemanticsNode$emitFakeNodes$fakeNode$1;
+Landroidx/compose/ui/semantics/SemanticsNode$emitFakeNodes$fakeNode$2;
+Landroidx/compose/ui/semantics/SemanticsNode$fakeSemanticsNode$fakeNode$1;
+Landroidx/compose/ui/semantics/SemanticsNode$parent$1;
+Landroidx/compose/ui/semantics/SemanticsNode$parent$2;
+Landroidx/compose/ui/semantics/SemanticsNode;
+Landroidx/compose/ui/semantics/SemanticsNodeKt;
+Landroidx/compose/ui/semantics/SemanticsOwner;
+Landroidx/compose/ui/semantics/SemanticsProperties$ContentDescription$1;
+Landroidx/compose/ui/semantics/SemanticsProperties$InvisibleToUser$1;
+Landroidx/compose/ui/semantics/SemanticsProperties$IsDialog$1;
+Landroidx/compose/ui/semantics/SemanticsProperties$IsPopup$1;
+Landroidx/compose/ui/semantics/SemanticsProperties$PaneTitle$1;
+Landroidx/compose/ui/semantics/SemanticsProperties$Role$1;
+Landroidx/compose/ui/semantics/SemanticsProperties$TestTag$1;
+Landroidx/compose/ui/semantics/SemanticsProperties$Text$1;
+Landroidx/compose/ui/semantics/SemanticsProperties;
+Landroidx/compose/ui/semantics/SemanticsPropertiesAndroid;
+Landroidx/compose/ui/semantics/SemanticsPropertiesKt$ActionPropertyKey$1;
+Landroidx/compose/ui/semantics/SemanticsPropertiesKt;
+Landroidx/compose/ui/semantics/SemanticsPropertyKey$1;
+Landroidx/compose/ui/semantics/SemanticsPropertyKey;
+Landroidx/compose/ui/semantics/SemanticsPropertyReceiver;
+Landroidx/compose/ui/semantics/SemanticsSortKt;
+Landroidx/compose/ui/state/ToggleableState;
+Landroidx/compose/ui/text/AndroidParagraph$WhenMappings;
+Landroidx/compose/ui/text/AndroidParagraph$wordBoundary$2;
+Landroidx/compose/ui/text/AndroidParagraph;
+Landroidx/compose/ui/text/AndroidParagraph_androidKt;
+Landroidx/compose/ui/text/AnnotatedString$Range;
+Landroidx/compose/ui/text/AnnotatedString$special$$inlined$sortedBy$1;
+Landroidx/compose/ui/text/AnnotatedString;
+Landroidx/compose/ui/text/AnnotatedStringKt;
+Landroidx/compose/ui/text/MultiParagraph;
+Landroidx/compose/ui/text/MultiParagraphIntrinsics$maxIntrinsicWidth$2;
+Landroidx/compose/ui/text/MultiParagraphIntrinsics$minIntrinsicWidth$2;
+Landroidx/compose/ui/text/MultiParagraphIntrinsics;
+Landroidx/compose/ui/text/MultiParagraphIntrinsicsKt;
+Landroidx/compose/ui/text/MultiParagraphKt;
+Landroidx/compose/ui/text/Paragraph;
+Landroidx/compose/ui/text/ParagraphInfo;
+Landroidx/compose/ui/text/ParagraphIntrinsicInfo;
+Landroidx/compose/ui/text/ParagraphIntrinsics;
+Landroidx/compose/ui/text/ParagraphIntrinsicsKt;
+Landroidx/compose/ui/text/ParagraphKt;
+Landroidx/compose/ui/text/ParagraphStyle;
+Landroidx/compose/ui/text/ParagraphStyleKt;
+Landroidx/compose/ui/text/Placeholder;
+Landroidx/compose/ui/text/PlatformParagraphStyle;
+Landroidx/compose/ui/text/PlatformSpanStyle;
+Landroidx/compose/ui/text/PlatformTextStyle;
+Landroidx/compose/ui/text/SaversKt;
+Landroidx/compose/ui/text/SpanStyle;
+Landroidx/compose/ui/text/SpanStyleKt$resolveSpanStyleDefaults$1;
+Landroidx/compose/ui/text/SpanStyleKt;
+Landroidx/compose/ui/text/TempListUtilsKt;
+Landroidx/compose/ui/text/TextLayoutInput;
+Landroidx/compose/ui/text/TextLayoutResult;
+Landroidx/compose/ui/text/TextPainter;
+Landroidx/compose/ui/text/TextRange$Companion;
+Landroidx/compose/ui/text/TextRange;
+Landroidx/compose/ui/text/TextRangeKt;
+Landroidx/compose/ui/text/TextStyle$Companion;
+Landroidx/compose/ui/text/TextStyle;
+Landroidx/compose/ui/text/TextStyleKt$WhenMappings;
+Landroidx/compose/ui/text/TextStyleKt;
+Landroidx/compose/ui/text/TtsAnnotation;
+Landroidx/compose/ui/text/UrlAnnotation;
+Landroidx/compose/ui/text/android/BoringLayoutConstructor33;
+Landroidx/compose/ui/text/android/BoringLayoutFactory33;
+Landroidx/compose/ui/text/android/BoringLayoutFactory;
+Landroidx/compose/ui/text/android/BoringLayoutFactoryDefault;
+Landroidx/compose/ui/text/android/CharSequenceCharacterIterator;
+Landroidx/compose/ui/text/android/LayoutCompat;
+Landroidx/compose/ui/text/android/LayoutHelper;
+Landroidx/compose/ui/text/android/LayoutIntrinsics$boringMetrics$2;
+Landroidx/compose/ui/text/android/LayoutIntrinsics$maxIntrinsicWidth$2;
+Landroidx/compose/ui/text/android/LayoutIntrinsics$minIntrinsicWidth$2;
+Landroidx/compose/ui/text/android/LayoutIntrinsics;
+Landroidx/compose/ui/text/android/LayoutIntrinsicsKt$$ExternalSyntheticLambda0;
+Landroidx/compose/ui/text/android/LayoutIntrinsicsKt;
+Landroidx/compose/ui/text/android/PaintExtensionsKt;
+Landroidx/compose/ui/text/android/SpannedExtensionsKt;
+Landroidx/compose/ui/text/android/StaticLayoutFactory23;
+Landroidx/compose/ui/text/android/StaticLayoutFactory26;
+Landroidx/compose/ui/text/android/StaticLayoutFactory28;
+Landroidx/compose/ui/text/android/StaticLayoutFactory33;
+Landroidx/compose/ui/text/android/StaticLayoutFactory;
+Landroidx/compose/ui/text/android/StaticLayoutFactoryImpl;
+Landroidx/compose/ui/text/android/StaticLayoutParams;
+Landroidx/compose/ui/text/android/TextAlignmentAdapter;
+Landroidx/compose/ui/text/android/TextAndroidCanvas;
+Landroidx/compose/ui/text/android/TextLayout$Companion;
+Landroidx/compose/ui/text/android/TextLayout$layoutHelper$2;
+Landroidx/compose/ui/text/android/TextLayout;
+Landroidx/compose/ui/text/android/TextLayoutKt;
+Landroidx/compose/ui/text/android/selection/WordBoundary;
+Landroidx/compose/ui/text/android/style/BaselineShiftSpan;
+Landroidx/compose/ui/text/android/style/FontFeatureSpan;
+Landroidx/compose/ui/text/android/style/IndentationFixSpan;
+Landroidx/compose/ui/text/android/style/IndentationFixSpanKt$WhenMappings;
+Landroidx/compose/ui/text/android/style/IndentationFixSpanKt;
+Landroidx/compose/ui/text/android/style/LetterSpacingSpanEm;
+Landroidx/compose/ui/text/android/style/LetterSpacingSpanPx;
+Landroidx/compose/ui/text/android/style/LineHeightSpan;
+Landroidx/compose/ui/text/android/style/LineHeightStyleSpan;
+Landroidx/compose/ui/text/android/style/LineHeightStyleSpanKt;
+Landroidx/compose/ui/text/android/style/PlaceholderSpan;
+Landroidx/compose/ui/text/android/style/ShadowSpan;
+Landroidx/compose/ui/text/android/style/SkewXSpan;
+Landroidx/compose/ui/text/android/style/TextDecorationSpan;
+Landroidx/compose/ui/text/android/style/TypefaceSpan;
+Landroidx/compose/ui/text/caches/ContainerHelpersKt;
+Landroidx/compose/ui/text/caches/LruCache;
+Landroidx/compose/ui/text/caches/SimpleArrayMap;
+Landroidx/compose/ui/text/font/AndroidFontLoader;
+Landroidx/compose/ui/text/font/AndroidFontResolveInterceptor;
+Landroidx/compose/ui/text/font/AndroidFontResolveInterceptor_androidKt;
+Landroidx/compose/ui/text/font/AsyncTypefaceCache$AsyncTypefaceResult;
+Landroidx/compose/ui/text/font/AsyncTypefaceCache;
+Landroidx/compose/ui/text/font/DefaultFontFamily;
+Landroidx/compose/ui/text/font/Font$ResourceLoader;
+Landroidx/compose/ui/text/font/FontFamily$Companion;
+Landroidx/compose/ui/text/font/FontFamily$Resolver;
+Landroidx/compose/ui/text/font/FontFamily;
+Landroidx/compose/ui/text/font/FontFamilyResolverImpl$createDefaultTypeface$1;
+Landroidx/compose/ui/text/font/FontFamilyResolverImpl$resolve$result$1;
+Landroidx/compose/ui/text/font/FontFamilyResolverImpl;
+Landroidx/compose/ui/text/font/FontFamilyResolverKt;
+Landroidx/compose/ui/text/font/FontFamilyResolver_androidKt;
+Landroidx/compose/ui/text/font/FontListFontFamilyTypefaceAdapter$Companion;
+Landroidx/compose/ui/text/font/FontListFontFamilyTypefaceAdapter$special$$inlined$CoroutineExceptionHandler$1;
+Landroidx/compose/ui/text/font/FontListFontFamilyTypefaceAdapter;
+Landroidx/compose/ui/text/font/FontMatcher;
+Landroidx/compose/ui/text/font/FontStyle$Companion;
+Landroidx/compose/ui/text/font/FontStyle;
+Landroidx/compose/ui/text/font/FontSynthesis$Companion;
+Landroidx/compose/ui/text/font/FontSynthesis;
+Landroidx/compose/ui/text/font/FontWeight$Companion;
+Landroidx/compose/ui/text/font/FontWeight;
+Landroidx/compose/ui/text/font/GenericFontFamily;
+Landroidx/compose/ui/text/font/PlatformFontFamilyTypefaceAdapter;
+Landroidx/compose/ui/text/font/PlatformFontLoader;
+Landroidx/compose/ui/text/font/PlatformResolveInterceptor$Companion$Default$1;
+Landroidx/compose/ui/text/font/PlatformResolveInterceptor$Companion;
+Landroidx/compose/ui/text/font/PlatformResolveInterceptor;
+Landroidx/compose/ui/text/font/PlatformTypefaces;
+Landroidx/compose/ui/text/font/PlatformTypefacesApi28;
+Landroidx/compose/ui/text/font/PlatformTypefacesKt;
+Landroidx/compose/ui/text/font/SystemFontFamily;
+Landroidx/compose/ui/text/font/TypefaceRequest;
+Landroidx/compose/ui/text/font/TypefaceRequestCache$runCached$currentTypefaceResult$1;
+Landroidx/compose/ui/text/font/TypefaceRequestCache;
+Landroidx/compose/ui/text/font/TypefaceResult$Immutable;
+Landroidx/compose/ui/text/font/TypefaceResult;
+Landroidx/compose/ui/text/input/ImeAction$Companion;
+Landroidx/compose/ui/text/input/ImeAction;
+Landroidx/compose/ui/text/input/ImeOptions$Companion;
+Landroidx/compose/ui/text/input/ImeOptions;
+Landroidx/compose/ui/text/input/ImmHelper21;
+Landroidx/compose/ui/text/input/ImmHelper30;
+Landroidx/compose/ui/text/input/ImmHelper;
+Landroidx/compose/ui/text/input/InputEventCallback2;
+Landroidx/compose/ui/text/input/InputMethodManager;
+Landroidx/compose/ui/text/input/InputMethodManagerImpl$imm$2;
+Landroidx/compose/ui/text/input/InputMethodManagerImpl;
+Landroidx/compose/ui/text/input/KeyboardCapitalization$Companion;
+Landroidx/compose/ui/text/input/KeyboardCapitalization;
+Landroidx/compose/ui/text/input/KeyboardType$Companion;
+Landroidx/compose/ui/text/input/KeyboardType;
+Landroidx/compose/ui/text/input/PlatformTextInputService;
+Landroidx/compose/ui/text/input/RecordingInputConnection;
+Landroidx/compose/ui/text/input/TextFieldValue$Companion$Saver$1;
+Landroidx/compose/ui/text/input/TextFieldValue$Companion$Saver$2;
+Landroidx/compose/ui/text/input/TextFieldValue$Companion;
+Landroidx/compose/ui/text/input/TextFieldValue;
+Landroidx/compose/ui/text/input/TextInputService;
+Landroidx/compose/ui/text/input/TextInputServiceAndroid$TextInputCommand;
+Landroidx/compose/ui/text/input/TextInputServiceAndroid$WhenMappings;
+Landroidx/compose/ui/text/input/TextInputServiceAndroid$baseInputConnection$2;
+Landroidx/compose/ui/text/input/TextInputServiceAndroid$createInputConnection$1;
+Landroidx/compose/ui/text/input/TextInputServiceAndroid$onEditCommand$1;
+Landroidx/compose/ui/text/input/TextInputServiceAndroid$onImeActionPerformed$1;
+Landroidx/compose/ui/text/input/TextInputServiceAndroid$textInputCommandEventLoop$1;
+Landroidx/compose/ui/text/input/TextInputServiceAndroid;
+Landroidx/compose/ui/text/input/TextInputServiceAndroid_androidKt;
+Landroidx/compose/ui/text/intl/AndroidLocale;
+Landroidx/compose/ui/text/intl/AndroidLocaleDelegateAPI24;
+Landroidx/compose/ui/text/intl/AndroidPlatformLocale_androidKt;
+Landroidx/compose/ui/text/intl/Locale$Companion;
+Landroidx/compose/ui/text/intl/Locale;
+Landroidx/compose/ui/text/intl/LocaleList$Companion;
+Landroidx/compose/ui/text/intl/LocaleList;
+Landroidx/compose/ui/text/intl/PlatformLocale;
+Landroidx/compose/ui/text/intl/PlatformLocaleDelegate;
+Landroidx/compose/ui/text/intl/PlatformLocaleKt;
+Landroidx/compose/ui/text/platform/AndroidAccessibilitySpannableString_androidKt;
+Landroidx/compose/ui/text/platform/AndroidMultiParagraphDrawKt;
+Landroidx/compose/ui/text/platform/AndroidParagraphHelper_androidKt$NoopSpan$1;
+Landroidx/compose/ui/text/platform/AndroidParagraphHelper_androidKt;
+Landroidx/compose/ui/text/platform/AndroidParagraphIntrinsics$resolveTypeface$1;
+Landroidx/compose/ui/text/platform/AndroidParagraphIntrinsics;
+Landroidx/compose/ui/text/platform/AndroidParagraphIntrinsics_androidKt;
+Landroidx/compose/ui/text/platform/AndroidParagraph_androidKt;
+Landroidx/compose/ui/text/platform/AndroidTextPaint;
+Landroidx/compose/ui/text/platform/DefaultImpl$getFontLoadState$initCallback$1;
+Landroidx/compose/ui/text/platform/DefaultImpl;
+Landroidx/compose/ui/text/platform/EmojiCompatStatus;
+Landroidx/compose/ui/text/platform/EmojiCompatStatusDelegate;
+Landroidx/compose/ui/text/platform/EmojiCompatStatusKt;
+Landroidx/compose/ui/text/platform/ImmutableBool;
+Landroidx/compose/ui/text/platform/Synchronization_jvmKt;
+Landroidx/compose/ui/text/platform/SynchronizedObject;
+Landroidx/compose/ui/text/platform/TypefaceDirtyTracker;
+Landroidx/compose/ui/text/platform/extensions/LocaleListHelperMethods;
+Landroidx/compose/ui/text/platform/extensions/PlaceholderExtensions_androidKt;
+Landroidx/compose/ui/text/platform/extensions/SpanRange;
+Landroidx/compose/ui/text/platform/extensions/SpannableExtensions_androidKt$setFontAttributes$1;
+Landroidx/compose/ui/text/platform/extensions/SpannableExtensions_androidKt;
+Landroidx/compose/ui/text/platform/extensions/TextPaintExtensions_androidKt;
+Landroidx/compose/ui/text/platform/style/DrawStyleSpan;
+Landroidx/compose/ui/text/platform/style/ShaderBrushSpan;
+Landroidx/compose/ui/text/style/BaselineShift$Companion;
+Landroidx/compose/ui/text/style/BaselineShift;
+Landroidx/compose/ui/text/style/BrushStyle;
+Landroidx/compose/ui/text/style/ColorStyle;
+Landroidx/compose/ui/text/style/Hyphens$Companion;
+Landroidx/compose/ui/text/style/Hyphens;
+Landroidx/compose/ui/text/style/LineBreak$Companion;
+Landroidx/compose/ui/text/style/LineBreak$Strategy$Companion;
+Landroidx/compose/ui/text/style/LineBreak$Strategy;
+Landroidx/compose/ui/text/style/LineBreak$Strictness$Companion;
+Landroidx/compose/ui/text/style/LineBreak$Strictness;
+Landroidx/compose/ui/text/style/LineBreak$WordBreak$Companion;
+Landroidx/compose/ui/text/style/LineBreak$WordBreak;
+Landroidx/compose/ui/text/style/LineBreak;
+Landroidx/compose/ui/text/style/LineHeightStyle$Companion;
+Landroidx/compose/ui/text/style/LineHeightStyle$Trim;
+Landroidx/compose/ui/text/style/LineHeightStyle;
+Landroidx/compose/ui/text/style/ResolvedTextDirection;
+Landroidx/compose/ui/text/style/TextAlign$Companion;
+Landroidx/compose/ui/text/style/TextAlign;
+Landroidx/compose/ui/text/style/TextDecoration$Companion;
+Landroidx/compose/ui/text/style/TextDecoration;
+Landroidx/compose/ui/text/style/TextDirection$Companion;
+Landroidx/compose/ui/text/style/TextDirection;
+Landroidx/compose/ui/text/style/TextDrawStyleKt;
+Landroidx/compose/ui/text/style/TextForegroundStyle$Companion;
+Landroidx/compose/ui/text/style/TextForegroundStyle$Unspecified;
+Landroidx/compose/ui/text/style/TextForegroundStyle$merge$1;
+Landroidx/compose/ui/text/style/TextForegroundStyle$merge$2;
+Landroidx/compose/ui/text/style/TextForegroundStyle;
+Landroidx/compose/ui/text/style/TextGeometricTransform$Companion;
+Landroidx/compose/ui/text/style/TextGeometricTransform;
+Landroidx/compose/ui/text/style/TextIndent$Companion;
+Landroidx/compose/ui/text/style/TextIndent;
+Landroidx/compose/ui/text/style/TextOverflow$Companion;
+Landroidx/compose/ui/text/style/TextOverflow;
+Landroidx/compose/ui/unit/AndroidDensity_androidKt;
+Landroidx/compose/ui/unit/Constraints$Companion;
+Landroidx/compose/ui/unit/Constraints;
+Landroidx/compose/ui/unit/ConstraintsKt;
+Landroidx/compose/ui/unit/Density;
+Landroidx/compose/ui/unit/DensityImpl;
+Landroidx/compose/ui/unit/DensityKt;
+Landroidx/compose/ui/unit/Dp$Companion;
+Landroidx/compose/ui/unit/Dp;
+Landroidx/compose/ui/unit/DpKt;
+Landroidx/compose/ui/unit/DpOffset$Companion;
+Landroidx/compose/ui/unit/DpOffset;
+Landroidx/compose/ui/unit/DpSize$Companion;
+Landroidx/compose/ui/unit/DpSize;
+Landroidx/compose/ui/unit/IntOffset$Companion;
+Landroidx/compose/ui/unit/IntOffset;
+Landroidx/compose/ui/unit/IntOffsetKt;
+Landroidx/compose/ui/unit/IntSize$Companion;
+Landroidx/compose/ui/unit/IntSize;
+Landroidx/compose/ui/unit/IntSizeKt;
+Landroidx/compose/ui/unit/LayoutDirection;
+Landroidx/compose/ui/unit/TextUnit$Companion;
+Landroidx/compose/ui/unit/TextUnit;
+Landroidx/compose/ui/unit/TextUnitKt;
+Landroidx/compose/ui/unit/TextUnitType$Companion;
+Landroidx/compose/ui/unit/TextUnitType;
+Landroidx/compose/ui/unit/Velocity$Companion;
+Landroidx/compose/ui/unit/Velocity;
+Landroidx/compose/ui/unit/VelocityKt;
+Landroidx/compose/ui/util/MathHelpersKt;
+Landroidx/core/R$id;
+Landroidx/core/app/ActivityCompat;
+Landroidx/core/app/ActivityOptionsCompat;
+Landroidx/core/app/ComponentActivity;
+Landroidx/core/app/CoreComponentFactory;
+Landroidx/core/app/MultiWindowModeChangedInfo;
+Landroidx/core/app/PictureInPictureModeChangedInfo;
+Landroidx/core/content/ContextCompat;
+Landroidx/core/content/res/FontResourcesParserCompat$FamilyResourceEntry;
+Landroidx/core/content/res/FontResourcesParserCompat$FontFamilyFilesResourceEntry;
+Landroidx/core/content/res/FontResourcesParserCompat$FontFileResourceEntry;
+Landroidx/core/content/res/FontResourcesParserCompat$ProviderResourceEntry;
+Landroidx/core/content/res/FontResourcesParserCompat;
+Landroidx/core/content/res/ResourcesCompat$FontCallback;
+Landroidx/core/graphics/PaintCompat;
+Landroidx/core/graphics/TypefaceCompat$ResourcesCallbackAdapter;
+Landroidx/core/graphics/TypefaceCompat;
+Landroidx/core/graphics/TypefaceCompatApi29Impl;
+Landroidx/core/graphics/TypefaceCompatBaseImpl;
+Landroidx/core/graphics/TypefaceCompatUtil$Api19Impl;
+Landroidx/core/graphics/TypefaceCompatUtil;
+Landroidx/core/graphics/drawable/DrawableKt;
+Landroidx/core/os/BuildCompat;
+Landroidx/core/os/HandlerCompat$Api28Impl;
+Landroidx/core/os/HandlerCompat;
+Landroidx/core/os/TraceCompat$Api18Impl;
+Landroidx/core/os/TraceCompat;
+Landroidx/core/provider/CallbackWithHandler;
+Landroidx/core/provider/FontProvider$$ExternalSyntheticLambda0;
+Landroidx/core/provider/FontProvider$Api16Impl;
+Landroidx/core/provider/FontProvider;
+Landroidx/core/provider/FontRequest;
+Landroidx/core/provider/FontRequestWorker;
+Landroidx/core/provider/FontsContractCompat$FontFamilyResult;
+Landroidx/core/provider/FontsContractCompat$FontInfo;
+Landroidx/core/provider/FontsContractCompat$FontRequestCallback;
+Landroidx/core/provider/FontsContractCompat;
+Landroidx/core/text/TextUtilsCompat;
+Landroidx/core/util/Consumer;
+Landroidx/core/util/Preconditions;
+Landroidx/core/view/AccessibilityDelegateCompat$AccessibilityDelegateAdapter;
+Landroidx/core/view/AccessibilityDelegateCompat$Api16Impl;
+Landroidx/core/view/AccessibilityDelegateCompat;
+Landroidx/core/view/KeyEventDispatcher$Component;
+Landroidx/core/view/KeyEventDispatcher;
+Landroidx/core/view/MenuHostHelper;
+Landroidx/core/view/OnApplyWindowInsetsListener;
+Landroidx/core/view/OnReceiveContentViewBehavior;
+Landroidx/core/view/ViewCompat$$ExternalSyntheticLambda0;
+Landroidx/core/view/ViewCompat$1;
+Landroidx/core/view/ViewCompat$2;
+Landroidx/core/view/ViewCompat$3;
+Landroidx/core/view/ViewCompat$4;
+Landroidx/core/view/ViewCompat$AccessibilityPaneVisibilityManager;
+Landroidx/core/view/ViewCompat$AccessibilityViewProperty;
+Landroidx/core/view/ViewCompat$Api16Impl;
+Landroidx/core/view/ViewCompat$Api17Impl;
+Landroidx/core/view/ViewCompat$Api19Impl;
+Landroidx/core/view/ViewCompat$Api20Impl;
+Landroidx/core/view/ViewCompat$Api21Impl;
+Landroidx/core/view/ViewCompat$Api23Impl;
+Landroidx/core/view/ViewCompat$Api29Impl;
+Landroidx/core/view/ViewCompat;
+Landroidx/core/view/ViewConfigurationCompat;
+Landroidx/core/view/ViewKt;
+Landroidx/core/view/WindowInsetsAnimationCompat$Callback;
+Landroidx/core/view/WindowInsetsAnimationCompat;
+Landroidx/core/view/WindowInsetsCompat$Type;
+Landroidx/core/view/WindowInsetsCompat;
+Landroidx/core/view/WindowInsetsControllerCompat;
+Landroidx/core/view/accessibility/AccessibilityNodeInfoCompat$AccessibilityActionCompat;
+Landroidx/core/view/accessibility/AccessibilityNodeInfoCompat$RangeInfoCompat;
+Landroidx/core/view/accessibility/AccessibilityNodeInfoCompat;
+Landroidx/core/view/accessibility/AccessibilityNodeProviderCompat;
+Landroidx/customview/poolingcontainer/PoolingContainer;
+Landroidx/customview/poolingcontainer/PoolingContainerListener;
+Landroidx/customview/poolingcontainer/PoolingContainerListenerHolder;
+Landroidx/customview/poolingcontainer/R$id;
+Landroidx/emoji2/text/ConcurrencyHelpers$$ExternalSyntheticLambda0;
+Landroidx/emoji2/text/ConcurrencyHelpers$Handler28Impl;
+Landroidx/emoji2/text/ConcurrencyHelpers;
+Landroidx/emoji2/text/DefaultEmojiCompatConfig$DefaultEmojiCompatConfigFactory;
+Landroidx/emoji2/text/DefaultEmojiCompatConfig$DefaultEmojiCompatConfigHelper;
+Landroidx/emoji2/text/DefaultEmojiCompatConfig$DefaultEmojiCompatConfigHelper_API19;
+Landroidx/emoji2/text/DefaultEmojiCompatConfig$DefaultEmojiCompatConfigHelper_API28;
+Landroidx/emoji2/text/DefaultEmojiCompatConfig;
+Landroidx/emoji2/text/DefaultGlyphChecker;
+Landroidx/emoji2/text/EmojiCompat$CompatInternal19$1;
+Landroidx/emoji2/text/EmojiCompat$CompatInternal19;
+Landroidx/emoji2/text/EmojiCompat$CompatInternal;
+Landroidx/emoji2/text/EmojiCompat$Config;
+Landroidx/emoji2/text/EmojiCompat$GlyphChecker;
+Landroidx/emoji2/text/EmojiCompat$InitCallback;
+Landroidx/emoji2/text/EmojiCompat$ListenerDispatcher;
+Landroidx/emoji2/text/EmojiCompat$MetadataRepoLoader;
+Landroidx/emoji2/text/EmojiCompat$MetadataRepoLoaderCallback;
+Landroidx/emoji2/text/EmojiCompat$SpanFactory;
+Landroidx/emoji2/text/EmojiCompat;
+Landroidx/emoji2/text/EmojiCompatInitializer$1;
+Landroidx/emoji2/text/EmojiCompatInitializer$BackgroundDefaultConfig;
+Landroidx/emoji2/text/EmojiCompatInitializer$BackgroundDefaultLoader$$ExternalSyntheticLambda0;
+Landroidx/emoji2/text/EmojiCompatInitializer$BackgroundDefaultLoader$1;
+Landroidx/emoji2/text/EmojiCompatInitializer$BackgroundDefaultLoader;
+Landroidx/emoji2/text/EmojiCompatInitializer$LoadEmojiCompatRunnable;
+Landroidx/emoji2/text/EmojiCompatInitializer;
+Landroidx/emoji2/text/EmojiMetadata;
+Landroidx/emoji2/text/EmojiProcessor$CodepointIndexFinder;
+Landroidx/emoji2/text/EmojiProcessor$ProcessorSm;
+Landroidx/emoji2/text/EmojiProcessor;
+Landroidx/emoji2/text/EmojiSpan;
+Landroidx/emoji2/text/FontRequestEmojiCompatConfig$FontProviderHelper;
+Landroidx/emoji2/text/FontRequestEmojiCompatConfig$FontRequestMetadataLoader$$ExternalSyntheticLambda0;
+Landroidx/emoji2/text/FontRequestEmojiCompatConfig$FontRequestMetadataLoader;
+Landroidx/emoji2/text/FontRequestEmojiCompatConfig;
+Landroidx/emoji2/text/MetadataListReader$ByteBufferReader;
+Landroidx/emoji2/text/MetadataListReader$OffsetInfo;
+Landroidx/emoji2/text/MetadataListReader$OpenTypeReader;
+Landroidx/emoji2/text/MetadataListReader;
+Landroidx/emoji2/text/MetadataRepo$Node;
+Landroidx/emoji2/text/MetadataRepo;
+Landroidx/emoji2/text/SpannableBuilder;
+Landroidx/emoji2/text/TypefaceEmojiSpan;
+Landroidx/emoji2/text/UnprecomputeTextOnModificationSpannable;
+Landroidx/emoji2/text/flatbuffer/MetadataItem;
+Landroidx/emoji2/text/flatbuffer/MetadataList;
+Landroidx/emoji2/text/flatbuffer/Table;
+Landroidx/emoji2/text/flatbuffer/Utf8;
+Landroidx/emoji2/text/flatbuffer/Utf8Safe;
+Landroidx/lifecycle/AndroidViewModel;
+Landroidx/lifecycle/ClassesInfoCache;
+Landroidx/lifecycle/CompositeGeneratedAdaptersObserver;
+Landroidx/lifecycle/DefaultLifecycleObserver;
+Landroidx/lifecycle/EmptyActivityLifecycleCallbacks;
+Landroidx/lifecycle/FullLifecycleObserver;
+Landroidx/lifecycle/FullLifecycleObserverAdapter$1;
+Landroidx/lifecycle/FullLifecycleObserverAdapter;
+Landroidx/lifecycle/GeneratedAdapter;
+Landroidx/lifecycle/HasDefaultViewModelProviderFactory;
+Landroidx/lifecycle/LegacySavedStateHandleController$1;
+Landroidx/lifecycle/LegacySavedStateHandleController$OnRecreation;
+Landroidx/lifecycle/LegacySavedStateHandleController;
+Landroidx/lifecycle/Lifecycle$1;
+Landroidx/lifecycle/Lifecycle$Event;
+Landroidx/lifecycle/Lifecycle$State;
+Landroidx/lifecycle/Lifecycle;
+Landroidx/lifecycle/LifecycleDispatcher$DispatcherActivityCallback;
+Landroidx/lifecycle/LifecycleDispatcher;
+Landroidx/lifecycle/LifecycleEventObserver;
+Landroidx/lifecycle/LifecycleObserver;
+Landroidx/lifecycle/LifecycleOwner;
+Landroidx/lifecycle/LifecycleRegistry$ObserverWithState;
+Landroidx/lifecycle/LifecycleRegistry;
+Landroidx/lifecycle/Lifecycling;
+Landroidx/lifecycle/LiveData$1;
+Landroidx/lifecycle/LiveData$LifecycleBoundObserver;
+Landroidx/lifecycle/LiveData$ObserverWrapper;
+Landroidx/lifecycle/LiveData;
+Landroidx/lifecycle/MutableLiveData;
+Landroidx/lifecycle/Observer;
+Landroidx/lifecycle/ProcessLifecycleInitializer;
+Landroidx/lifecycle/ProcessLifecycleOwner$1;
+Landroidx/lifecycle/ProcessLifecycleOwner$2;
+Landroidx/lifecycle/ProcessLifecycleOwner$3$1;
+Landroidx/lifecycle/ProcessLifecycleOwner$3;
+Landroidx/lifecycle/ProcessLifecycleOwner$Api29Impl;
+Landroidx/lifecycle/ProcessLifecycleOwner;
+Landroidx/lifecycle/ReflectiveGenericLifecycleObserver;
+Landroidx/lifecycle/ReportFragment$ActivityInitializationListener;
+Landroidx/lifecycle/ReportFragment$LifecycleCallbacks;
+Landroidx/lifecycle/ReportFragment;
+Landroidx/lifecycle/SavedStateHandle$Companion;
+Landroidx/lifecycle/SavedStateHandle;
+Landroidx/lifecycle/SavedStateHandleAttacher;
+Landroidx/lifecycle/SavedStateHandleController;
+Landroidx/lifecycle/SavedStateHandleSupport$DEFAULT_ARGS_KEY$1;
+Landroidx/lifecycle/SavedStateHandleSupport$SAVED_STATE_REGISTRY_OWNER_KEY$1;
+Landroidx/lifecycle/SavedStateHandleSupport$VIEW_MODEL_STORE_OWNER_KEY$1;
+Landroidx/lifecycle/SavedStateHandleSupport$savedStateHandlesVM$1$1;
+Landroidx/lifecycle/SavedStateHandleSupport;
+Landroidx/lifecycle/SavedStateHandlesProvider$viewModel$2;
+Landroidx/lifecycle/SavedStateHandlesProvider;
+Landroidx/lifecycle/SavedStateHandlesVM;
+Landroidx/lifecycle/SavedStateViewModelFactory;
+Landroidx/lifecycle/SavedStateViewModelFactoryKt;
+Landroidx/lifecycle/SingleGeneratedAdapterObserver;
+Landroidx/lifecycle/ViewModel;
+Landroidx/lifecycle/ViewModelProvider$AndroidViewModelFactory$Companion$ApplicationKeyImpl;
+Landroidx/lifecycle/ViewModelProvider$AndroidViewModelFactory$Companion;
+Landroidx/lifecycle/ViewModelProvider$AndroidViewModelFactory;
+Landroidx/lifecycle/ViewModelProvider$Factory$Companion;
+Landroidx/lifecycle/ViewModelProvider$Factory;
+Landroidx/lifecycle/ViewModelProvider$NewInstanceFactory$Companion$ViewModelKeyImpl;
+Landroidx/lifecycle/ViewModelProvider$NewInstanceFactory$Companion;
+Landroidx/lifecycle/ViewModelProvider$NewInstanceFactory;
+Landroidx/lifecycle/ViewModelProvider$OnRequeryFactory;
+Landroidx/lifecycle/ViewModelProvider;
+Landroidx/lifecycle/ViewModelProviderGetKt;
+Landroidx/lifecycle/ViewModelStore;
+Landroidx/lifecycle/ViewModelStoreOwner;
+Landroidx/lifecycle/ViewTreeLifecycleOwner;
+Landroidx/lifecycle/ViewTreeViewModelStoreOwner;
+Landroidx/lifecycle/runtime/R$id;
+Landroidx/lifecycle/viewmodel/CreationExtras$Empty;
+Landroidx/lifecycle/viewmodel/CreationExtras$Key;
+Landroidx/lifecycle/viewmodel/CreationExtras;
+Landroidx/lifecycle/viewmodel/InitializerViewModelFactory;
+Landroidx/lifecycle/viewmodel/InitializerViewModelFactoryBuilder;
+Landroidx/lifecycle/viewmodel/MutableCreationExtras;
+Landroidx/lifecycle/viewmodel/R$id;
+Landroidx/lifecycle/viewmodel/ViewModelInitializer;
+Landroidx/lifecycle/viewmodel/compose/LocalViewModelStoreOwner$LocalViewModelStoreOwner$1;
+Landroidx/lifecycle/viewmodel/compose/LocalViewModelStoreOwner;
+Landroidx/lifecycle/viewmodel/compose/ViewModelKt;
+Landroidx/profileinstaller/ProfileInstaller;
+Landroidx/profileinstaller/ProfileInstallerInitializer$$ExternalSyntheticLambda0;
+Landroidx/profileinstaller/ProfileInstallerInitializer$$ExternalSyntheticLambda1;
+Landroidx/profileinstaller/ProfileInstallerInitializer$$ExternalSyntheticLambda2;
+Landroidx/profileinstaller/ProfileInstallerInitializer$Choreographer16Impl$$ExternalSyntheticLambda0;
+Landroidx/profileinstaller/ProfileInstallerInitializer$Choreographer16Impl;
+Landroidx/profileinstaller/ProfileInstallerInitializer$Handler28Impl;
+Landroidx/profileinstaller/ProfileInstallerInitializer$Result;
+Landroidx/profileinstaller/ProfileInstallerInitializer;
+Landroidx/savedstate/R$id;
+Landroidx/savedstate/Recreator$Companion;
+Landroidx/savedstate/Recreator$SavedStateProvider;
+Landroidx/savedstate/Recreator;
+Landroidx/savedstate/SavedStateRegistry$$ExternalSyntheticLambda0;
+Landroidx/savedstate/SavedStateRegistry$AutoRecreated;
+Landroidx/savedstate/SavedStateRegistry$Companion;
+Landroidx/savedstate/SavedStateRegistry$SavedStateProvider;
+Landroidx/savedstate/SavedStateRegistry;
+Landroidx/savedstate/SavedStateRegistryController$Companion;
+Landroidx/savedstate/SavedStateRegistryController;
+Landroidx/savedstate/SavedStateRegistryOwner;
+Landroidx/savedstate/ViewTreeSavedStateRegistryOwner$findViewTreeSavedStateRegistryOwner$1;
+Landroidx/savedstate/ViewTreeSavedStateRegistryOwner$findViewTreeSavedStateRegistryOwner$2;
+Landroidx/savedstate/ViewTreeSavedStateRegistryOwner;
+Landroidx/startup/AppInitializer;
+Landroidx/startup/InitializationProvider;
+Landroidx/startup/Initializer;
+Landroidx/startup/R$string;
+Landroidx/startup/StartupException;
+Landroidx/tracing/Trace;
+Landroidx/tracing/TraceApi18Impl;
+Landroidx/tracing/TraceApi29Impl;
+Lcom/android/credentialmanager/CreateFlowUtils$Companion$toCreateCredentialUiState$$inlined$compareByDescending$1;
+Lcom/android/credentialmanager/CreateFlowUtils$Companion;
+Lcom/android/credentialmanager/CreateFlowUtils;
+Lcom/android/credentialmanager/CredentialManagerRepo$Companion;
+Lcom/android/credentialmanager/CredentialManagerRepo;
+Lcom/android/credentialmanager/CredentialSelectorActivity$CredentialManagerBottomSheet$3;
+Lcom/android/credentialmanager/CredentialSelectorActivity$CredentialManagerBottomSheet$launcher$1$1;
+Lcom/android/credentialmanager/CredentialSelectorActivity$WhenMappings;
+Lcom/android/credentialmanager/CredentialSelectorActivity$onCancel$1;
+Lcom/android/credentialmanager/CredentialSelectorActivity$onCreate$1$1;
+Lcom/android/credentialmanager/CredentialSelectorActivity$onCreate$1;
+Lcom/android/credentialmanager/CredentialSelectorActivity;
+Lcom/android/credentialmanager/GetFlowUtils$Companion;
+Lcom/android/credentialmanager/GetFlowUtils;
+Lcom/android/credentialmanager/UserConfigRepo$Companion;
+Lcom/android/credentialmanager/UserConfigRepo;
+Lcom/android/credentialmanager/common/DialogResult;
+Lcom/android/credentialmanager/common/DialogType$Companion;
+Lcom/android/credentialmanager/common/DialogType;
+Lcom/android/credentialmanager/common/ProviderActivityResult;
+Lcom/android/credentialmanager/common/ResultState;
+Lcom/android/credentialmanager/common/material/FixedThreshold;
+Lcom/android/credentialmanager/common/material/ModalBottomSheetDefaults;
+Lcom/android/credentialmanager/common/material/ModalBottomSheetKt$ModalBottomSheetLayout$1$1$1$1;
+Lcom/android/credentialmanager/common/material/ModalBottomSheetKt$ModalBottomSheetLayout$1$1$1;
+Lcom/android/credentialmanager/common/material/ModalBottomSheetKt$ModalBottomSheetLayout$1$2$1;
+Lcom/android/credentialmanager/common/material/ModalBottomSheetKt$ModalBottomSheetLayout$1$3$1;
+Lcom/android/credentialmanager/common/material/ModalBottomSheetKt$ModalBottomSheetLayout$1$4$1$1;
+Lcom/android/credentialmanager/common/material/ModalBottomSheetKt$ModalBottomSheetLayout$1$4$1;
+Lcom/android/credentialmanager/common/material/ModalBottomSheetKt$ModalBottomSheetLayout$1$4$2;
+Lcom/android/credentialmanager/common/material/ModalBottomSheetKt$ModalBottomSheetLayout$1$4$3;
+Lcom/android/credentialmanager/common/material/ModalBottomSheetKt$ModalBottomSheetLayout$1$4;
+Lcom/android/credentialmanager/common/material/ModalBottomSheetKt$ModalBottomSheetLayout$1$5;
+Lcom/android/credentialmanager/common/material/ModalBottomSheetKt$ModalBottomSheetLayout$1;
+Lcom/android/credentialmanager/common/material/ModalBottomSheetKt$ModalBottomSheetLayout$2;
+Lcom/android/credentialmanager/common/material/ModalBottomSheetKt$Scrim$1$1;
+Lcom/android/credentialmanager/common/material/ModalBottomSheetKt$Scrim$2;
+Lcom/android/credentialmanager/common/material/ModalBottomSheetKt$Scrim$dismissModifier$1$1$1;
+Lcom/android/credentialmanager/common/material/ModalBottomSheetKt$Scrim$dismissModifier$1$1;
+Lcom/android/credentialmanager/common/material/ModalBottomSheetKt$Scrim$dismissModifier$2$1$1;
+Lcom/android/credentialmanager/common/material/ModalBottomSheetKt$Scrim$dismissModifier$2$1;
+Lcom/android/credentialmanager/common/material/ModalBottomSheetKt$rememberModalBottomSheetState$1;
+Lcom/android/credentialmanager/common/material/ModalBottomSheetKt$rememberModalBottomSheetState$2;
+Lcom/android/credentialmanager/common/material/ModalBottomSheetKt$rememberModalBottomSheetState$3;
+Lcom/android/credentialmanager/common/material/ModalBottomSheetKt;
+Lcom/android/credentialmanager/common/material/ModalBottomSheetState$Companion$Saver$1;
+Lcom/android/credentialmanager/common/material/ModalBottomSheetState$Companion$Saver$2;
+Lcom/android/credentialmanager/common/material/ModalBottomSheetState$Companion;
+Lcom/android/credentialmanager/common/material/ModalBottomSheetState;
+Lcom/android/credentialmanager/common/material/ModalBottomSheetValue;
+Lcom/android/credentialmanager/common/material/ResistanceConfig;
+Lcom/android/credentialmanager/common/material/SwipeableDefaults;
+Lcom/android/credentialmanager/common/material/SwipeableKt$PreUpPostDownNestedScrollConnection$1$onPostFling$1;
+Lcom/android/credentialmanager/common/material/SwipeableKt$PreUpPostDownNestedScrollConnection$1$onPreFling$1;
+Lcom/android/credentialmanager/common/material/SwipeableKt$PreUpPostDownNestedScrollConnection$1;
+Lcom/android/credentialmanager/common/material/SwipeableKt$swipeable$1;
+Lcom/android/credentialmanager/common/material/SwipeableKt$swipeable$3$3$1;
+Lcom/android/credentialmanager/common/material/SwipeableKt$swipeable$3$3;
+Lcom/android/credentialmanager/common/material/SwipeableKt$swipeable$3$4$1$1;
+Lcom/android/credentialmanager/common/material/SwipeableKt$swipeable$3$4$1;
+Lcom/android/credentialmanager/common/material/SwipeableKt$swipeable$3;
+Lcom/android/credentialmanager/common/material/SwipeableKt$swipeable-pPrIpRY$$inlined$debugInspectorInfo$1;
+Lcom/android/credentialmanager/common/material/SwipeableKt;
+Lcom/android/credentialmanager/common/material/SwipeableState$Companion;
+Lcom/android/credentialmanager/common/material/SwipeableState$animateInternalToOffset$2;
+Lcom/android/credentialmanager/common/material/SwipeableState$animateTo$2;
+Lcom/android/credentialmanager/common/material/SwipeableState$draggableState$1;
+Lcom/android/credentialmanager/common/material/SwipeableState$latestNonEmptyAnchorsFlow$1;
+Lcom/android/credentialmanager/common/material/SwipeableState$performFling$2;
+Lcom/android/credentialmanager/common/material/SwipeableState$processNewAnchors$1;
+Lcom/android/credentialmanager/common/material/SwipeableState$snapInternalToOffset$2;
+Lcom/android/credentialmanager/common/material/SwipeableState$special$$inlined$filter$1$2;
+Lcom/android/credentialmanager/common/material/SwipeableState$special$$inlined$filter$1;
+Lcom/android/credentialmanager/common/material/SwipeableState$thresholds$2;
+Lcom/android/credentialmanager/common/material/SwipeableState;
+Lcom/android/credentialmanager/common/material/ThresholdConfig;
+Lcom/android/credentialmanager/common/ui/ActionButtonKt$ActionButton$1;
+Lcom/android/credentialmanager/common/ui/ActionButtonKt$ActionButton$2;
+Lcom/android/credentialmanager/common/ui/ActionButtonKt;
+Lcom/android/credentialmanager/common/ui/CardsKt$ContainerCard$1;
+Lcom/android/credentialmanager/common/ui/CardsKt;
+Lcom/android/credentialmanager/common/ui/ConfirmButtonKt$ConfirmButton$1;
+Lcom/android/credentialmanager/common/ui/ConfirmButtonKt$ConfirmButton$2;
+Lcom/android/credentialmanager/common/ui/ConfirmButtonKt;
+Lcom/android/credentialmanager/common/ui/EntryKt$Entry$1;
+Lcom/android/credentialmanager/common/ui/EntryKt$TransparentBackgroundEntry$1;
+Lcom/android/credentialmanager/common/ui/EntryKt;
+Lcom/android/credentialmanager/common/ui/TextsKt$TextInternal$1;
+Lcom/android/credentialmanager/common/ui/TextsKt$TextOnSurface$1;
+Lcom/android/credentialmanager/common/ui/TextsKt$TextOnSurfaceVariant$1;
+Lcom/android/credentialmanager/common/ui/TextsKt$TextSecondary$1;
+Lcom/android/credentialmanager/common/ui/TextsKt;
+Lcom/android/credentialmanager/createflow/ActiveEntry;
+Lcom/android/credentialmanager/createflow/ComposableSingletons$CreateCredentialComponentsKt$lambda-1$1;
+Lcom/android/credentialmanager/createflow/ComposableSingletons$CreateCredentialComponentsKt$lambda-2$1;
+Lcom/android/credentialmanager/createflow/ComposableSingletons$CreateCredentialComponentsKt$lambda-3$1;
+Lcom/android/credentialmanager/createflow/ComposableSingletons$CreateCredentialComponentsKt$lambda-4$1;
+Lcom/android/credentialmanager/createflow/ComposableSingletons$CreateCredentialComponentsKt$lambda-5$1;
+Lcom/android/credentialmanager/createflow/ComposableSingletons$CreateCredentialComponentsKt;
+Lcom/android/credentialmanager/createflow/CreateCredentialComponentsKt$ConfirmationCard$1;
+Lcom/android/credentialmanager/createflow/CreateCredentialComponentsKt$ConfirmationCard$2;
+Lcom/android/credentialmanager/createflow/CreateCredentialComponentsKt$CreateCredentialScreen$1$10;
+Lcom/android/credentialmanager/createflow/CreateCredentialComponentsKt$CreateCredentialScreen$1$11;
+Lcom/android/credentialmanager/createflow/CreateCredentialComponentsKt$CreateCredentialScreen$1$12;
+Lcom/android/credentialmanager/createflow/CreateCredentialComponentsKt$CreateCredentialScreen$1$13;
+Lcom/android/credentialmanager/createflow/CreateCredentialComponentsKt$CreateCredentialScreen$1$14;
+Lcom/android/credentialmanager/createflow/CreateCredentialComponentsKt$CreateCredentialScreen$1$15;
+Lcom/android/credentialmanager/createflow/CreateCredentialComponentsKt$CreateCredentialScreen$1$16;
+Lcom/android/credentialmanager/createflow/CreateCredentialComponentsKt$CreateCredentialScreen$1$17;
+Lcom/android/credentialmanager/createflow/CreateCredentialComponentsKt$CreateCredentialScreen$1$18;
+Lcom/android/credentialmanager/createflow/CreateCredentialComponentsKt$CreateCredentialScreen$1$1;
+Lcom/android/credentialmanager/createflow/CreateCredentialComponentsKt$CreateCredentialScreen$1$2;
+Lcom/android/credentialmanager/createflow/CreateCredentialComponentsKt$CreateCredentialScreen$1$3;
+Lcom/android/credentialmanager/createflow/CreateCredentialComponentsKt$CreateCredentialScreen$1$4;
+Lcom/android/credentialmanager/createflow/CreateCredentialComponentsKt$CreateCredentialScreen$1$5;
+Lcom/android/credentialmanager/createflow/CreateCredentialComponentsKt$CreateCredentialScreen$1$6;
+Lcom/android/credentialmanager/createflow/CreateCredentialComponentsKt$CreateCredentialScreen$1$7;
+Lcom/android/credentialmanager/createflow/CreateCredentialComponentsKt$CreateCredentialScreen$1$8;
+Lcom/android/credentialmanager/createflow/CreateCredentialComponentsKt$CreateCredentialScreen$1$9;
+Lcom/android/credentialmanager/createflow/CreateCredentialComponentsKt$CreateCredentialScreen$1$WhenMappings;
+Lcom/android/credentialmanager/createflow/CreateCredentialComponentsKt$CreateCredentialScreen$1;
+Lcom/android/credentialmanager/createflow/CreateCredentialComponentsKt$CreateCredentialScreen$2;
+Lcom/android/credentialmanager/createflow/CreateCredentialComponentsKt$CreateCredentialScreen$3;
+Lcom/android/credentialmanager/createflow/CreateCredentialComponentsKt$CreationSelectionCard$1$1$1;
+Lcom/android/credentialmanager/createflow/CreateCredentialComponentsKt$CreationSelectionCard$1;
+Lcom/android/credentialmanager/createflow/CreateCredentialComponentsKt$CreationSelectionCard$2;
+Lcom/android/credentialmanager/createflow/CreateCredentialComponentsKt$ExternalOnlySelectionCard$1;
+Lcom/android/credentialmanager/createflow/CreateCredentialComponentsKt$ExternalOnlySelectionCard$2;
+Lcom/android/credentialmanager/createflow/CreateCredentialComponentsKt$MoreOptionsDisabledProvidersRow$1;
+Lcom/android/credentialmanager/createflow/CreateCredentialComponentsKt$MoreOptionsDisabledProvidersRow$2;
+Lcom/android/credentialmanager/createflow/CreateCredentialComponentsKt$MoreOptionsInfoRow$1;
+Lcom/android/credentialmanager/createflow/CreateCredentialComponentsKt$MoreOptionsInfoRow$2;
+Lcom/android/credentialmanager/createflow/CreateCredentialComponentsKt$MoreOptionsInfoRow$3;
+Lcom/android/credentialmanager/createflow/CreateCredentialComponentsKt$MoreOptionsRowIntroCard$1;
+Lcom/android/credentialmanager/createflow/CreateCredentialComponentsKt$MoreOptionsRowIntroCard$2;
+Lcom/android/credentialmanager/createflow/CreateCredentialComponentsKt$MoreOptionsSelectionCard$1;
+Lcom/android/credentialmanager/createflow/CreateCredentialComponentsKt$MoreOptionsSelectionCard$2;
+Lcom/android/credentialmanager/createflow/CreateCredentialComponentsKt$PrimaryCreateOptionRow$1;
+Lcom/android/credentialmanager/createflow/CreateCredentialComponentsKt$PrimaryCreateOptionRow$2;
+Lcom/android/credentialmanager/createflow/CreateCredentialComponentsKt$PrimaryCreateOptionRow$3;
+Lcom/android/credentialmanager/createflow/CreateCredentialComponentsKt$PrimaryCreateOptionRow$4;
+Lcom/android/credentialmanager/createflow/CreateCredentialComponentsKt$ProviderSelectionCard$1;
+Lcom/android/credentialmanager/createflow/CreateCredentialComponentsKt$ProviderSelectionCard$2;
+Lcom/android/credentialmanager/createflow/CreateCredentialComponentsKt$RemoteEntryRow$1$1;
+Lcom/android/credentialmanager/createflow/CreateCredentialComponentsKt$RemoteEntryRow$2;
+Lcom/android/credentialmanager/createflow/CreateCredentialComponentsKt;
+Lcom/android/credentialmanager/createflow/CreateCredentialUiState;
+Lcom/android/credentialmanager/createflow/CreateCredentialViewModel$dialogResult$2;
+Lcom/android/credentialmanager/createflow/CreateCredentialViewModel;
+Lcom/android/credentialmanager/createflow/CreateOptionInfo;
+Lcom/android/credentialmanager/createflow/CreateScreenState;
+Lcom/android/credentialmanager/createflow/DisabledProviderInfo;
+Lcom/android/credentialmanager/createflow/EnabledProviderInfo;
+Lcom/android/credentialmanager/createflow/EntryInfo;
+Lcom/android/credentialmanager/createflow/ProviderInfo;
+Lcom/android/credentialmanager/createflow/RemoteInfo;
+Lcom/android/credentialmanager/createflow/RequestDisplayInfo;
+Lcom/android/credentialmanager/getflow/EntryInfo;
+Lcom/android/credentialmanager/getflow/GetCredentialComponentsKt;
+Lcom/android/credentialmanager/getflow/GetCredentialUiState;
+Lcom/android/credentialmanager/getflow/GetCredentialViewModel;
+Lcom/android/credentialmanager/getflow/GetScreenState;
+Lcom/android/credentialmanager/getflow/ProviderDisplayInfo;
+Lcom/android/credentialmanager/getflow/RequestDisplayInfo;
+Lcom/android/credentialmanager/jetpack/developer/CreateCredentialRequest$Companion;
+Lcom/android/credentialmanager/jetpack/developer/CreateCredentialRequest;
+Lcom/android/credentialmanager/jetpack/developer/CreateCustomCredentialRequest;
+Lcom/android/credentialmanager/jetpack/developer/CreatePasswordRequest$Companion;
+Lcom/android/credentialmanager/jetpack/developer/CreatePasswordRequest;
+Lcom/android/credentialmanager/jetpack/developer/CreatePublicKeyCredentialRequest$Companion;
+Lcom/android/credentialmanager/jetpack/developer/CreatePublicKeyCredentialRequest;
+Lcom/android/credentialmanager/jetpack/developer/CreatePublicKeyCredentialRequestPrivileged$Companion;
+Lcom/android/credentialmanager/jetpack/developer/CreatePublicKeyCredentialRequestPrivileged;
+Lcom/android/credentialmanager/jetpack/developer/FrameworkClassParsingException;
+Lcom/android/credentialmanager/jetpack/provider/Action$Companion;
+Lcom/android/credentialmanager/jetpack/provider/Action;
+Lcom/android/credentialmanager/jetpack/provider/CreateEntry$Companion;
+Lcom/android/credentialmanager/jetpack/provider/CreateEntry;
+Lcom/android/credentialmanager/jetpack/provider/CredentialCountInformation$Companion;
+Lcom/android/credentialmanager/jetpack/provider/CredentialCountInformation;
+Lcom/android/credentialmanager/jetpack/provider/CredentialEntry$Companion;
+Lcom/android/credentialmanager/jetpack/provider/CredentialEntry;
+Lcom/android/credentialmanager/ui/theme/AndroidColorScheme;
+Lcom/android/credentialmanager/ui/theme/AndroidColorSchemeKt$LocalAndroidColorScheme$1;
+Lcom/android/credentialmanager/ui/theme/AndroidColorSchemeKt;
+Lcom/android/credentialmanager/ui/theme/ColorKt;
+Lcom/android/credentialmanager/ui/theme/EntryShape;
+Lcom/android/credentialmanager/ui/theme/ShapeKt;
+Lcom/android/credentialmanager/ui/theme/ThemeKt$CredentialSelectorTheme$1$1;
+Lcom/android/credentialmanager/ui/theme/ThemeKt$CredentialSelectorTheme$1;
+Lcom/android/credentialmanager/ui/theme/ThemeKt$CredentialSelectorTheme$2;
+Lcom/android/credentialmanager/ui/theme/ThemeKt;
+Lcom/android/credentialmanager/ui/theme/TypeKt;
+Lkotlin/ExceptionsKt;
+Lkotlin/ExceptionsKt__ExceptionsKt;
+Lkotlin/Function;
+Lkotlin/InitializedLazyImpl;
+Lkotlin/KotlinNothingValueException;
+Lkotlin/Lazy;
+Lkotlin/LazyKt;
+Lkotlin/LazyKt__LazyJVMKt$WhenMappings;
+Lkotlin/LazyKt__LazyJVMKt;
+Lkotlin/LazyKt__LazyKt;
+Lkotlin/LazyThreadSafetyMode;
+Lkotlin/NoWhenBranchMatchedException;
+Lkotlin/Pair;
+Lkotlin/Result$Companion;
+Lkotlin/Result$Failure;
+Lkotlin/Result;
+Lkotlin/ResultKt;
+Lkotlin/SafePublicationLazyImpl;
+Lkotlin/SynchronizedLazyImpl;
+Lkotlin/TuplesKt;
+Lkotlin/ULong$Companion;
+Lkotlin/ULong;
+Lkotlin/UNINITIALIZED_VALUE;
+Lkotlin/UninitializedPropertyAccessException;
+Lkotlin/Unit;
+Lkotlin/UnsafeLazyImpl;
+Lkotlin/UnsignedKt;
+Lkotlin/collections/AbstractCollection$toString$1;
+Lkotlin/collections/AbstractCollection;
+Lkotlin/collections/AbstractList$Companion;
+Lkotlin/collections/AbstractList$IteratorImpl;
+Lkotlin/collections/AbstractList$ListIteratorImpl;
+Lkotlin/collections/AbstractList;
+Lkotlin/collections/AbstractMap$Companion;
+Lkotlin/collections/AbstractMap$toString$1;
+Lkotlin/collections/AbstractMap;
+Lkotlin/collections/AbstractMutableCollection;
+Lkotlin/collections/AbstractMutableList;
+Lkotlin/collections/AbstractMutableMap;
+Lkotlin/collections/AbstractMutableSet;
+Lkotlin/collections/AbstractSet$Companion;
+Lkotlin/collections/AbstractSet;
+Lkotlin/collections/ArrayAsCollection;
+Lkotlin/collections/ArrayDeque$Companion;
+Lkotlin/collections/ArrayDeque;
+Lkotlin/collections/ArraysKt;
+Lkotlin/collections/ArraysKt__ArraysJVMKt;
+Lkotlin/collections/ArraysKt__ArraysKt;
+Lkotlin/collections/ArraysKt___ArraysJvmKt;
+Lkotlin/collections/ArraysKt___ArraysKt;
+Lkotlin/collections/ArraysUtilJVM;
+Lkotlin/collections/CollectionsKt;
+Lkotlin/collections/CollectionsKt__CollectionsJVMKt;
+Lkotlin/collections/CollectionsKt__CollectionsKt;
+Lkotlin/collections/CollectionsKt__IterablesKt;
+Lkotlin/collections/CollectionsKt__IteratorsJVMKt;
+Lkotlin/collections/CollectionsKt__IteratorsKt;
+Lkotlin/collections/CollectionsKt__MutableCollectionsJVMKt;
+Lkotlin/collections/CollectionsKt__MutableCollectionsKt;
+Lkotlin/collections/CollectionsKt__ReversedViewsKt;
+Lkotlin/collections/CollectionsKt___CollectionsJvmKt;
+Lkotlin/collections/CollectionsKt___CollectionsKt;
+Lkotlin/collections/EmptyIterator;
+Lkotlin/collections/EmptyList;
+Lkotlin/collections/EmptyMap;
+Lkotlin/collections/EmptySet;
+Lkotlin/collections/IntIterator;
+Lkotlin/collections/MapsKt;
+Lkotlin/collections/MapsKt__MapWithDefaultKt;
+Lkotlin/collections/MapsKt__MapsJVMKt;
+Lkotlin/collections/MapsKt__MapsKt;
+Lkotlin/collections/MapsKt___MapsJvmKt;
+Lkotlin/collections/MapsKt___MapsKt;
+Lkotlin/collections/SetsKt__SetsJVMKt;
+Lkotlin/collections/SetsKt__SetsKt;
+Lkotlin/collections/builders/ListBuilder;
+Lkotlin/collections/builders/MapBuilder;
+Lkotlin/comparisons/ComparisonsKt;
+Lkotlin/comparisons/ComparisonsKt__ComparisonsKt;
+Lkotlin/comparisons/ComparisonsKt___ComparisonsJvmKt;
+Lkotlin/comparisons/ComparisonsKt___ComparisonsKt;
+Lkotlin/coroutines/AbstractCoroutineContextElement;
+Lkotlin/coroutines/AbstractCoroutineContextKey;
+Lkotlin/coroutines/CombinedContext$Serialized;
+Lkotlin/coroutines/CombinedContext$toString$1;
+Lkotlin/coroutines/CombinedContext$writeReplace$1;
+Lkotlin/coroutines/CombinedContext;
+Lkotlin/coroutines/Continuation;
+Lkotlin/coroutines/ContinuationInterceptor$DefaultImpls;
+Lkotlin/coroutines/ContinuationInterceptor$Key;
+Lkotlin/coroutines/ContinuationInterceptor;
+Lkotlin/coroutines/ContinuationKt;
+Lkotlin/coroutines/CoroutineContext$DefaultImpls;
+Lkotlin/coroutines/CoroutineContext$Element$DefaultImpls;
+Lkotlin/coroutines/CoroutineContext$Element;
+Lkotlin/coroutines/CoroutineContext$Key;
+Lkotlin/coroutines/CoroutineContext$plus$1;
+Lkotlin/coroutines/CoroutineContext;
+Lkotlin/coroutines/EmptyCoroutineContext;
+Lkotlin/coroutines/SafeContinuation$Companion;
+Lkotlin/coroutines/SafeContinuation;
+Lkotlin/coroutines/intrinsics/CoroutineSingletons;
+Lkotlin/coroutines/intrinsics/IntrinsicsKt;
+Lkotlin/coroutines/intrinsics/IntrinsicsKt__IntrinsicsJvmKt$createCoroutineUnintercepted$$inlined$createCoroutineFromSuspendFunction$IntrinsicsKt__IntrinsicsJvmKt$3;
+Lkotlin/coroutines/intrinsics/IntrinsicsKt__IntrinsicsJvmKt$createCoroutineUnintercepted$$inlined$createCoroutineFromSuspendFunction$IntrinsicsKt__IntrinsicsJvmKt$4;
+Lkotlin/coroutines/intrinsics/IntrinsicsKt__IntrinsicsJvmKt;
+Lkotlin/coroutines/intrinsics/IntrinsicsKt__IntrinsicsKt;
+Lkotlin/coroutines/jvm/internal/BaseContinuationImpl;
+Lkotlin/coroutines/jvm/internal/Boxing;
+Lkotlin/coroutines/jvm/internal/CompletedContinuation;
+Lkotlin/coroutines/jvm/internal/ContinuationImpl;
+Lkotlin/coroutines/jvm/internal/CoroutineStackFrame;
+Lkotlin/coroutines/jvm/internal/DebugMetadataKt;
+Lkotlin/coroutines/jvm/internal/DebugProbesKt;
+Lkotlin/coroutines/jvm/internal/RestrictedContinuationImpl;
+Lkotlin/coroutines/jvm/internal/RestrictedSuspendLambda;
+Lkotlin/coroutines/jvm/internal/SuspendLambda;
+Lkotlin/internal/ProgressionUtilKt;
+Lkotlin/io/CloseableKt;
+Lkotlin/jvm/JvmClassMappingKt;
+Lkotlin/jvm/KotlinReflectionNotSupportedError;
+Lkotlin/jvm/functions/Function0;
+Lkotlin/jvm/functions/Function10;
+Lkotlin/jvm/functions/Function11;
+Lkotlin/jvm/functions/Function12;
+Lkotlin/jvm/functions/Function13;
+Lkotlin/jvm/functions/Function14;
+Lkotlin/jvm/functions/Function15;
+Lkotlin/jvm/functions/Function16;
+Lkotlin/jvm/functions/Function17;
+Lkotlin/jvm/functions/Function18;
+Lkotlin/jvm/functions/Function19;
+Lkotlin/jvm/functions/Function1;
+Lkotlin/jvm/functions/Function20;
+Lkotlin/jvm/functions/Function21;
+Lkotlin/jvm/functions/Function22;
+Lkotlin/jvm/functions/Function2;
+Lkotlin/jvm/functions/Function3;
+Lkotlin/jvm/functions/Function4;
+Lkotlin/jvm/functions/Function5;
+Lkotlin/jvm/functions/Function6;
+Lkotlin/jvm/functions/Function7;
+Lkotlin/jvm/functions/Function8;
+Lkotlin/jvm/functions/Function9;
+Lkotlin/jvm/internal/ArrayIteratorKt;
+Lkotlin/jvm/internal/CallableReference$NoReceiver;
+Lkotlin/jvm/internal/CallableReference;
+Lkotlin/jvm/internal/ClassBasedDeclarationContainer;
+Lkotlin/jvm/internal/ClassReference$Companion;
+Lkotlin/jvm/internal/ClassReference;
+Lkotlin/jvm/internal/CollectionToArray;
+Lkotlin/jvm/internal/DefaultConstructorMarker;
+Lkotlin/jvm/internal/FloatCompanionObject;
+Lkotlin/jvm/internal/FunctionBase;
+Lkotlin/jvm/internal/FunctionReference;
+Lkotlin/jvm/internal/FunctionReferenceImpl;
+Lkotlin/jvm/internal/InlineMarker;
+Lkotlin/jvm/internal/IntCompanionObject;
+Lkotlin/jvm/internal/Intrinsics;
+Lkotlin/jvm/internal/Lambda;
+Lkotlin/jvm/internal/MutablePropertyReference1;
+Lkotlin/jvm/internal/MutablePropertyReference1Impl;
+Lkotlin/jvm/internal/MutablePropertyReference;
+Lkotlin/jvm/internal/PackageReference;
+Lkotlin/jvm/internal/PropertyReference0;
+Lkotlin/jvm/internal/PropertyReference0Impl;
+Lkotlin/jvm/internal/PropertyReference;
+Lkotlin/jvm/internal/Ref$BooleanRef;
+Lkotlin/jvm/internal/Ref$IntRef;
+Lkotlin/jvm/internal/Ref$LongRef;
+Lkotlin/jvm/internal/Ref$ObjectRef;
+Lkotlin/jvm/internal/Reflection;
+Lkotlin/jvm/internal/ReflectionFactory;
+Lkotlin/jvm/internal/SpreadBuilder;
+Lkotlin/jvm/internal/TypeIntrinsics;
+Lkotlin/jvm/internal/markers/KMappedMarker;
+Lkotlin/jvm/internal/markers/KMutableCollection;
+Lkotlin/jvm/internal/markers/KMutableIterable;
+Lkotlin/jvm/internal/markers/KMutableMap$Entry;
+Lkotlin/jvm/internal/markers/KMutableMap;
+Lkotlin/jvm/internal/markers/KMutableSet;
+Lkotlin/math/MathKt;
+Lkotlin/math/MathKt__MathHKt;
+Lkotlin/math/MathKt__MathJVMKt;
+Lkotlin/ranges/ClosedFloatRange;
+Lkotlin/ranges/ClosedFloatingPointRange;
+Lkotlin/ranges/ClosedRange;
+Lkotlin/ranges/IntProgression$Companion;
+Lkotlin/ranges/IntProgression;
+Lkotlin/ranges/IntProgressionIterator;
+Lkotlin/ranges/IntRange$Companion;
+Lkotlin/ranges/IntRange;
+Lkotlin/ranges/RangesKt;
+Lkotlin/ranges/RangesKt__RangesKt;
+Lkotlin/ranges/RangesKt___RangesKt;
+Lkotlin/reflect/KCallable;
+Lkotlin/reflect/KClass;
+Lkotlin/reflect/KDeclarationContainer;
+Lkotlin/reflect/KFunction;
+Lkotlin/reflect/KMutableProperty1;
+Lkotlin/reflect/KProperty0;
+Lkotlin/reflect/KProperty1$Getter;
+Lkotlin/reflect/KProperty1;
+Lkotlin/reflect/KProperty;
+Lkotlin/sequences/ConstrainedOnceSequence;
+Lkotlin/sequences/EmptySequence;
+Lkotlin/sequences/FilteringSequence$iterator$1;
+Lkotlin/sequences/FilteringSequence;
+Lkotlin/sequences/GeneratorSequence$iterator$1;
+Lkotlin/sequences/GeneratorSequence;
+Lkotlin/sequences/Sequence;
+Lkotlin/sequences/SequenceBuilderIterator;
+Lkotlin/sequences/SequenceScope;
+Lkotlin/sequences/SequencesKt;
+Lkotlin/sequences/SequencesKt__SequenceBuilderKt$sequence$$inlined$Sequence$1;
+Lkotlin/sequences/SequencesKt__SequenceBuilderKt;
+Lkotlin/sequences/SequencesKt__SequencesJVMKt;
+Lkotlin/sequences/SequencesKt__SequencesKt$asSequence$$inlined$Sequence$1;
+Lkotlin/sequences/SequencesKt__SequencesKt$generateSequence$2;
+Lkotlin/sequences/SequencesKt__SequencesKt;
+Lkotlin/sequences/SequencesKt___SequencesJvmKt;
+Lkotlin/sequences/SequencesKt___SequencesKt$filterNotNull$1;
+Lkotlin/sequences/SequencesKt___SequencesKt;
+Lkotlin/sequences/TransformingSequence$iterator$1;
+Lkotlin/sequences/TransformingSequence;
+Lkotlin/text/CharsKt;
+Lkotlin/text/CharsKt__CharJVMKt;
+Lkotlin/text/CharsKt__CharKt;
+Lkotlin/text/DelimitedRangesSequence;
+Lkotlin/text/StringsKt;
+Lkotlin/text/StringsKt__AppendableKt;
+Lkotlin/text/StringsKt__IndentKt$getIndentFunction$1;
+Lkotlin/text/StringsKt__IndentKt$getIndentFunction$2;
+Lkotlin/text/StringsKt__IndentKt;
+Lkotlin/text/StringsKt__RegexExtensionsJVMKt;
+Lkotlin/text/StringsKt__RegexExtensionsKt;
+Lkotlin/text/StringsKt__StringBuilderJVMKt;
+Lkotlin/text/StringsKt__StringBuilderKt;
+Lkotlin/text/StringsKt__StringNumberConversionsJVMKt;
+Lkotlin/text/StringsKt__StringNumberConversionsKt;
+Lkotlin/text/StringsKt__StringsJVMKt;
+Lkotlin/text/StringsKt__StringsKt$rangesDelimitedBy$2;
+Lkotlin/text/StringsKt__StringsKt$splitToSequence$1;
+Lkotlin/text/StringsKt__StringsKt;
+Lkotlin/text/StringsKt___StringsJvmKt;
+Lkotlin/text/StringsKt___StringsKt;
+Lkotlinx/atomicfu/AtomicArray;
+Lkotlinx/atomicfu/AtomicBoolean$Companion;
+Lkotlinx/atomicfu/AtomicBoolean;
+Lkotlinx/atomicfu/AtomicFU;
+Lkotlinx/atomicfu/AtomicFU_commonKt;
+Lkotlinx/atomicfu/AtomicInt$Companion;
+Lkotlinx/atomicfu/AtomicInt;
+Lkotlinx/atomicfu/AtomicLong$Companion;
+Lkotlinx/atomicfu/AtomicLong;
+Lkotlinx/atomicfu/AtomicRef$Companion;
+Lkotlinx/atomicfu/AtomicRef;
+Lkotlinx/atomicfu/TraceBase$None;
+Lkotlinx/atomicfu/TraceBase;
+Lkotlinx/coroutines/AbstractCoroutine;
+Lkotlinx/coroutines/AbstractTimeSource;
+Lkotlinx/coroutines/AbstractTimeSourceKt;
+Lkotlinx/coroutines/Active;
+Lkotlinx/coroutines/BeforeResumeCancelHandler;
+Lkotlinx/coroutines/BlockingEventLoop;
+Lkotlinx/coroutines/BuildersKt;
+Lkotlinx/coroutines/BuildersKt__BuildersKt;
+Lkotlinx/coroutines/BuildersKt__Builders_commonKt;
+Lkotlinx/coroutines/CancelHandler;
+Lkotlinx/coroutines/CancelHandlerBase;
+Lkotlinx/coroutines/CancellableContinuation$DefaultImpls;
+Lkotlinx/coroutines/CancellableContinuation;
+Lkotlinx/coroutines/CancellableContinuationImpl;
+Lkotlinx/coroutines/CancellableContinuationImplKt;
+Lkotlinx/coroutines/CancellableContinuationKt;
+Lkotlinx/coroutines/CancelledContinuation;
+Lkotlinx/coroutines/ChildContinuation;
+Lkotlinx/coroutines/ChildHandle;
+Lkotlinx/coroutines/ChildHandleNode;
+Lkotlinx/coroutines/ChildJob;
+Lkotlinx/coroutines/CompletableJob;
+Lkotlinx/coroutines/CompletedContinuation;
+Lkotlinx/coroutines/CompletedExceptionally;
+Lkotlinx/coroutines/CompletedWithCancellation;
+Lkotlinx/coroutines/CompletionHandlerBase;
+Lkotlinx/coroutines/CompletionHandlerException;
+Lkotlinx/coroutines/CompletionStateKt;
+Lkotlinx/coroutines/CopyableThrowable;
+Lkotlinx/coroutines/CoroutineContextKt$foldCopies$1;
+Lkotlinx/coroutines/CoroutineContextKt$foldCopies$folded$1;
+Lkotlinx/coroutines/CoroutineContextKt$hasCopyableElements$1;
+Lkotlinx/coroutines/CoroutineContextKt;
+Lkotlinx/coroutines/CoroutineDispatcher$Key$1;
+Lkotlinx/coroutines/CoroutineDispatcher$Key;
+Lkotlinx/coroutines/CoroutineDispatcher;
+Lkotlinx/coroutines/CoroutineExceptionHandler$Key;
+Lkotlinx/coroutines/CoroutineExceptionHandler;
+Lkotlinx/coroutines/CoroutineExceptionHandlerKt;
+Lkotlinx/coroutines/CoroutineId$Key;
+Lkotlinx/coroutines/CoroutineId;
+Lkotlinx/coroutines/CoroutineName$Key;
+Lkotlinx/coroutines/CoroutineName;
+Lkotlinx/coroutines/CoroutineScope;
+Lkotlinx/coroutines/CoroutineScopeKt;
+Lkotlinx/coroutines/CoroutineStart$WhenMappings;
+Lkotlinx/coroutines/CoroutineStart;
+Lkotlinx/coroutines/CoroutinesInternalError;
+Lkotlinx/coroutines/DebugKt;
+Lkotlinx/coroutines/DebugStringsKt;
+Lkotlinx/coroutines/DefaultExecutor;
+Lkotlinx/coroutines/DefaultExecutorKt;
+Lkotlinx/coroutines/Delay;
+Lkotlinx/coroutines/DelayKt;
+Lkotlinx/coroutines/DispatchedCoroutine;
+Lkotlinx/coroutines/DispatchedTask;
+Lkotlinx/coroutines/DispatchedTaskKt;
+Lkotlinx/coroutines/Dispatchers;
+Lkotlinx/coroutines/DisposableHandle;
+Lkotlinx/coroutines/DisposeOnCancel;
+Lkotlinx/coroutines/Empty;
+Lkotlinx/coroutines/EventLoop;
+Lkotlinx/coroutines/EventLoopImplBase$DelayedResumeTask;
+Lkotlinx/coroutines/EventLoopImplBase$DelayedTask;
+Lkotlinx/coroutines/EventLoopImplBase$DelayedTaskQueue;
+Lkotlinx/coroutines/EventLoopImplBase;
+Lkotlinx/coroutines/EventLoopImplPlatform;
+Lkotlinx/coroutines/EventLoopKt;
+Lkotlinx/coroutines/EventLoop_commonKt;
+Lkotlinx/coroutines/ExceptionsKt;
+Lkotlinx/coroutines/ExecutorCoroutineDispatcher$Key$1;
+Lkotlinx/coroutines/ExecutorCoroutineDispatcher$Key;
+Lkotlinx/coroutines/ExecutorCoroutineDispatcher;
+Lkotlinx/coroutines/GlobalScope;
+Lkotlinx/coroutines/InactiveNodeList;
+Lkotlinx/coroutines/Incomplete;
+Lkotlinx/coroutines/IncompleteStateBox;
+Lkotlinx/coroutines/InvokeOnCancel;
+Lkotlinx/coroutines/InvokeOnCancelling;
+Lkotlinx/coroutines/InvokeOnCompletion;
+Lkotlinx/coroutines/Job$DefaultImpls;
+Lkotlinx/coroutines/Job$Key;
+Lkotlinx/coroutines/Job;
+Lkotlinx/coroutines/JobCancellationException;
+Lkotlinx/coroutines/JobCancellingNode;
+Lkotlinx/coroutines/JobImpl;
+Lkotlinx/coroutines/JobKt;
+Lkotlinx/coroutines/JobKt__JobKt;
+Lkotlinx/coroutines/JobNode;
+Lkotlinx/coroutines/JobSupport$AwaitContinuation;
+Lkotlinx/coroutines/JobSupport$ChildCompletion;
+Lkotlinx/coroutines/JobSupport$Finishing;
+Lkotlinx/coroutines/JobSupport$addLastAtomic$$inlined$addLastIf$1;
+Lkotlinx/coroutines/JobSupport$children$1;
+Lkotlinx/coroutines/JobSupport;
+Lkotlinx/coroutines/JobSupportKt;
+Lkotlinx/coroutines/LazyStandaloneCoroutine;
+Lkotlinx/coroutines/MainCoroutineDispatcher;
+Lkotlinx/coroutines/NodeList;
+Lkotlinx/coroutines/NonDisposableHandle;
+Lkotlinx/coroutines/NotCompleted;
+Lkotlinx/coroutines/ParentJob;
+Lkotlinx/coroutines/RemoveOnCancel;
+Lkotlinx/coroutines/ResumeAwaitOnCompletion;
+Lkotlinx/coroutines/ResumeOnCompletion;
+Lkotlinx/coroutines/StandaloneCoroutine;
+Lkotlinx/coroutines/SupervisorJobImpl;
+Lkotlinx/coroutines/SupervisorKt;
+Lkotlinx/coroutines/ThreadContextElement;
+Lkotlinx/coroutines/ThreadLocalEventLoop;
+Lkotlinx/coroutines/TimeoutCancellationException;
+Lkotlinx/coroutines/Unconfined;
+Lkotlinx/coroutines/UndispatchedCoroutine;
+Lkotlinx/coroutines/UndispatchedMarker;
+Lkotlinx/coroutines/YieldContext$Key;
+Lkotlinx/coroutines/YieldContext;
+Lkotlinx/coroutines/android/AndroidDispatcherFactory;
+Lkotlinx/coroutines/android/HandlerContext$scheduleResumeAfterDelay$$inlined$Runnable$1;
+Lkotlinx/coroutines/android/HandlerContext$scheduleResumeAfterDelay$1;
+Lkotlinx/coroutines/android/HandlerContext;
+Lkotlinx/coroutines/android/HandlerDispatcher;
+Lkotlinx/coroutines/android/HandlerDispatcherKt;
+Lkotlinx/coroutines/channels/AbstractChannel$Itr;
+Lkotlinx/coroutines/channels/AbstractChannel$ReceiveElement;
+Lkotlinx/coroutines/channels/AbstractChannel$ReceiveElementWithUndeliveredHandler;
+Lkotlinx/coroutines/channels/AbstractChannel$ReceiveHasNext;
+Lkotlinx/coroutines/channels/AbstractChannel$RemoveReceiveOnCancel;
+Lkotlinx/coroutines/channels/AbstractChannel$enqueueReceiveInternal$$inlined$addLastIfPrevAndIf$1;
+Lkotlinx/coroutines/channels/AbstractChannel$receiveCatching$1;
+Lkotlinx/coroutines/channels/AbstractChannel;
+Lkotlinx/coroutines/channels/AbstractChannelKt;
+Lkotlinx/coroutines/channels/AbstractSendChannel$SendBuffered;
+Lkotlinx/coroutines/channels/AbstractSendChannel$enqueueSend$$inlined$addLastIfPrevAndIf$1;
+Lkotlinx/coroutines/channels/AbstractSendChannel;
+Lkotlinx/coroutines/channels/ArrayChannel$WhenMappings;
+Lkotlinx/coroutines/channels/ArrayChannel;
+Lkotlinx/coroutines/channels/BufferOverflow;
+Lkotlinx/coroutines/channels/Channel$Factory;
+Lkotlinx/coroutines/channels/Channel;
+Lkotlinx/coroutines/channels/ChannelCoroutine;
+Lkotlinx/coroutines/channels/ChannelIterator;
+Lkotlinx/coroutines/channels/ChannelKt;
+Lkotlinx/coroutines/channels/ChannelResult$Closed;
+Lkotlinx/coroutines/channels/ChannelResult$Companion;
+Lkotlinx/coroutines/channels/ChannelResult$Failed;
+Lkotlinx/coroutines/channels/ChannelResult;
+Lkotlinx/coroutines/channels/ChannelsKt;
+Lkotlinx/coroutines/channels/Closed;
+Lkotlinx/coroutines/channels/ConflatedChannel;
+Lkotlinx/coroutines/channels/LinkedListChannel;
+Lkotlinx/coroutines/channels/ProduceKt;
+Lkotlinx/coroutines/channels/ProducerCoroutine;
+Lkotlinx/coroutines/channels/ProducerScope;
+Lkotlinx/coroutines/channels/Receive;
+Lkotlinx/coroutines/channels/ReceiveChannel;
+Lkotlinx/coroutines/channels/ReceiveOrClosed;
+Lkotlinx/coroutines/channels/RendezvousChannel;
+Lkotlinx/coroutines/channels/Send;
+Lkotlinx/coroutines/channels/SendChannel$DefaultImpls;
+Lkotlinx/coroutines/channels/SendChannel;
+Lkotlinx/coroutines/channels/SendElement;
+Lkotlinx/coroutines/channels/SendElementWithUndeliveredHandler;
+Lkotlinx/coroutines/flow/AbstractFlow$collect$1;
+Lkotlinx/coroutines/flow/AbstractFlow;
+Lkotlinx/coroutines/flow/DistinctFlowImpl$collect$2$emit$1;
+Lkotlinx/coroutines/flow/DistinctFlowImpl$collect$2;
+Lkotlinx/coroutines/flow/DistinctFlowImpl;
+Lkotlinx/coroutines/flow/Flow;
+Lkotlinx/coroutines/flow/FlowCollector;
+Lkotlinx/coroutines/flow/FlowKt;
+Lkotlinx/coroutines/flow/FlowKt__BuildersKt$flowOf$$inlined$unsafeFlow$2;
+Lkotlinx/coroutines/flow/FlowKt__BuildersKt;
+Lkotlinx/coroutines/flow/FlowKt__ChannelsKt$emitAllImpl$1;
+Lkotlinx/coroutines/flow/FlowKt__ChannelsKt;
+Lkotlinx/coroutines/flow/FlowKt__CollectKt;
+Lkotlinx/coroutines/flow/FlowKt__ContextKt;
+Lkotlinx/coroutines/flow/FlowKt__DistinctKt$defaultAreEquivalent$1;
+Lkotlinx/coroutines/flow/FlowKt__DistinctKt$defaultKeySelector$1;
+Lkotlinx/coroutines/flow/FlowKt__DistinctKt;
+Lkotlinx/coroutines/flow/FlowKt__EmittersKt;
+Lkotlinx/coroutines/flow/FlowKt__LimitKt$dropWhile$$inlined$unsafeFlow$1;
+Lkotlinx/coroutines/flow/FlowKt__LimitKt$dropWhile$1$1$emit$1;
+Lkotlinx/coroutines/flow/FlowKt__LimitKt$dropWhile$1$1;
+Lkotlinx/coroutines/flow/FlowKt__LimitKt$emitAbort$1;
+Lkotlinx/coroutines/flow/FlowKt__LimitKt$take$$inlined$unsafeFlow$1$1;
+Lkotlinx/coroutines/flow/FlowKt__LimitKt$take$$inlined$unsafeFlow$1;
+Lkotlinx/coroutines/flow/FlowKt__LimitKt$take$2$1;
+Lkotlinx/coroutines/flow/FlowKt__LimitKt;
+Lkotlinx/coroutines/flow/FlowKt__MergeKt$mapLatest$1;
+Lkotlinx/coroutines/flow/FlowKt__MergeKt;
+Lkotlinx/coroutines/flow/FlowKt__ReduceKt$first$$inlined$collectWhile$2$1;
+Lkotlinx/coroutines/flow/FlowKt__ReduceKt$first$$inlined$collectWhile$2;
+Lkotlinx/coroutines/flow/FlowKt__ReduceKt$first$3;
+Lkotlinx/coroutines/flow/FlowKt__ReduceKt;
+Lkotlinx/coroutines/flow/FlowKt__ShareKt$launchSharing$1$1;
+Lkotlinx/coroutines/flow/FlowKt__ShareKt$launchSharing$1$2$WhenMappings;
+Lkotlinx/coroutines/flow/FlowKt__ShareKt$launchSharing$1$2;
+Lkotlinx/coroutines/flow/FlowKt__ShareKt$launchSharing$1;
+Lkotlinx/coroutines/flow/FlowKt__ShareKt;
+Lkotlinx/coroutines/flow/MutableSharedFlow;
+Lkotlinx/coroutines/flow/MutableStateFlow;
+Lkotlinx/coroutines/flow/ReadonlyStateFlow;
+Lkotlinx/coroutines/flow/SafeFlow;
+Lkotlinx/coroutines/flow/SharedFlow;
+Lkotlinx/coroutines/flow/SharedFlowImpl$Emitter;
+Lkotlinx/coroutines/flow/SharedFlowImpl$WhenMappings;
+Lkotlinx/coroutines/flow/SharedFlowImpl$collect$1;
+Lkotlinx/coroutines/flow/SharedFlowImpl;
+Lkotlinx/coroutines/flow/SharedFlowKt;
+Lkotlinx/coroutines/flow/SharedFlowSlot;
+Lkotlinx/coroutines/flow/SharingCommand;
+Lkotlinx/coroutines/flow/SharingConfig;
+Lkotlinx/coroutines/flow/SharingStarted$Companion;
+Lkotlinx/coroutines/flow/SharingStarted;
+Lkotlinx/coroutines/flow/StartedEagerly;
+Lkotlinx/coroutines/flow/StartedLazily$command$1;
+Lkotlinx/coroutines/flow/StartedLazily;
+Lkotlinx/coroutines/flow/StartedWhileSubscribed$command$1;
+Lkotlinx/coroutines/flow/StartedWhileSubscribed$command$2;
+Lkotlinx/coroutines/flow/StartedWhileSubscribed;
+Lkotlinx/coroutines/flow/StateFlow;
+Lkotlinx/coroutines/flow/StateFlowImpl$collect$1;
+Lkotlinx/coroutines/flow/StateFlowImpl;
+Lkotlinx/coroutines/flow/StateFlowKt;
+Lkotlinx/coroutines/flow/StateFlowSlot;
+Lkotlinx/coroutines/flow/internal/AbortFlowException;
+Lkotlinx/coroutines/flow/internal/AbstractSharedFlow;
+Lkotlinx/coroutines/flow/internal/AbstractSharedFlowKt;
+Lkotlinx/coroutines/flow/internal/AbstractSharedFlowSlot;
+Lkotlinx/coroutines/flow/internal/ChannelFlow$collect$2;
+Lkotlinx/coroutines/flow/internal/ChannelFlow$collectToFun$1;
+Lkotlinx/coroutines/flow/internal/ChannelFlow;
+Lkotlinx/coroutines/flow/internal/ChannelFlowKt;
+Lkotlinx/coroutines/flow/internal/ChannelFlowOperator$collectWithContextUndispatched$2;
+Lkotlinx/coroutines/flow/internal/ChannelFlowOperator;
+Lkotlinx/coroutines/flow/internal/ChannelFlowOperatorImpl;
+Lkotlinx/coroutines/flow/internal/ChannelFlowTransformLatest$flowCollect$3$1$2;
+Lkotlinx/coroutines/flow/internal/ChannelFlowTransformLatest$flowCollect$3$1$emit$1;
+Lkotlinx/coroutines/flow/internal/ChannelFlowTransformLatest$flowCollect$3$1;
+Lkotlinx/coroutines/flow/internal/ChannelFlowTransformLatest$flowCollect$3;
+Lkotlinx/coroutines/flow/internal/ChannelFlowTransformLatest;
+Lkotlinx/coroutines/flow/internal/ChildCancelledException;
+Lkotlinx/coroutines/flow/internal/DownstreamExceptionContext;
+Lkotlinx/coroutines/flow/internal/FlowExceptions_commonKt;
+Lkotlinx/coroutines/flow/internal/FusibleFlow$DefaultImpls;
+Lkotlinx/coroutines/flow/internal/FusibleFlow;
+Lkotlinx/coroutines/flow/internal/NoOpContinuation;
+Lkotlinx/coroutines/flow/internal/NopCollector;
+Lkotlinx/coroutines/flow/internal/NullSurrogateKt;
+Lkotlinx/coroutines/flow/internal/SafeCollector$collectContextSize$1;
+Lkotlinx/coroutines/flow/internal/SafeCollector;
+Lkotlinx/coroutines/flow/internal/SafeCollectorKt;
+Lkotlinx/coroutines/flow/internal/SafeCollector_commonKt;
+Lkotlinx/coroutines/flow/internal/SendingCollector;
+Lkotlinx/coroutines/flow/internal/SubscriptionCountStateFlow;
+Lkotlinx/coroutines/internal/ArrayQueue;
+Lkotlinx/coroutines/internal/AtomicKt;
+Lkotlinx/coroutines/internal/AtomicOp;
+Lkotlinx/coroutines/internal/ContextScope;
+Lkotlinx/coroutines/internal/DispatchedContinuation;
+Lkotlinx/coroutines/internal/DispatchedContinuationKt;
+Lkotlinx/coroutines/internal/FastServiceLoader;
+Lkotlinx/coroutines/internal/FastServiceLoaderKt;
+Lkotlinx/coroutines/internal/InlineList;
+Lkotlinx/coroutines/internal/LimitedDispatcher;
+Lkotlinx/coroutines/internal/LimitedDispatcherKt;
+Lkotlinx/coroutines/internal/LockFreeLinkedListHead;
+Lkotlinx/coroutines/internal/LockFreeLinkedListKt;
+Lkotlinx/coroutines/internal/LockFreeLinkedListNode$CondAddOp;
+Lkotlinx/coroutines/internal/LockFreeLinkedListNode$PrepareOp;
+Lkotlinx/coroutines/internal/LockFreeLinkedListNode$toString$1;
+Lkotlinx/coroutines/internal/LockFreeLinkedListNode;
+Lkotlinx/coroutines/internal/LockFreeTaskQueue;
+Lkotlinx/coroutines/internal/LockFreeTaskQueueCore$Companion;
+Lkotlinx/coroutines/internal/LockFreeTaskQueueCore$Placeholder;
+Lkotlinx/coroutines/internal/LockFreeTaskQueueCore;
+Lkotlinx/coroutines/internal/MainDispatcherFactory;
+Lkotlinx/coroutines/internal/MainDispatcherLoader;
+Lkotlinx/coroutines/internal/MainDispatchersKt;
+Lkotlinx/coroutines/internal/MissingMainCoroutineDispatcher;
+Lkotlinx/coroutines/internal/OnUndeliveredElementKt;
+Lkotlinx/coroutines/internal/OpDescriptor;
+Lkotlinx/coroutines/internal/Removed;
+Lkotlinx/coroutines/internal/ResizableAtomicArray;
+Lkotlinx/coroutines/internal/ScopeCoroutine;
+Lkotlinx/coroutines/internal/StackTraceRecoveryKt;
+Lkotlinx/coroutines/internal/Symbol;
+Lkotlinx/coroutines/internal/SystemPropsKt;
+Lkotlinx/coroutines/internal/SystemPropsKt__SystemPropsKt;
+Lkotlinx/coroutines/internal/SystemPropsKt__SystemProps_commonKt;
+Lkotlinx/coroutines/internal/ThreadContextKt$countAll$1;
+Lkotlinx/coroutines/internal/ThreadContextKt$findOne$1;
+Lkotlinx/coroutines/internal/ThreadContextKt$updateState$1;
+Lkotlinx/coroutines/internal/ThreadContextKt;
+Lkotlinx/coroutines/internal/ThreadSafeHeap;
+Lkotlinx/coroutines/internal/ThreadSafeHeapNode;
+Lkotlinx/coroutines/internal/ThreadState;
+Lkotlinx/coroutines/internal/UndeliveredElementException;
+Lkotlinx/coroutines/intrinsics/CancellableKt;
+Lkotlinx/coroutines/intrinsics/UndispatchedKt;
+Lkotlinx/coroutines/scheduling/CoroutineScheduler$Companion;
+Lkotlinx/coroutines/scheduling/CoroutineScheduler$WhenMappings;
+Lkotlinx/coroutines/scheduling/CoroutineScheduler$Worker;
+Lkotlinx/coroutines/scheduling/CoroutineScheduler$WorkerState;
+Lkotlinx/coroutines/scheduling/CoroutineScheduler;
+Lkotlinx/coroutines/scheduling/DefaultIoScheduler;
+Lkotlinx/coroutines/scheduling/DefaultScheduler;
+Lkotlinx/coroutines/scheduling/GlobalQueue;
+Lkotlinx/coroutines/scheduling/NanoTimeSource;
+Lkotlinx/coroutines/scheduling/SchedulerCoroutineDispatcher;
+Lkotlinx/coroutines/scheduling/SchedulerTimeSource;
+Lkotlinx/coroutines/scheduling/Task;
+Lkotlinx/coroutines/scheduling/TaskContext;
+Lkotlinx/coroutines/scheduling/TaskContextImpl;
+Lkotlinx/coroutines/scheduling/TaskImpl;
+Lkotlinx/coroutines/scheduling/TasksKt;
+Lkotlinx/coroutines/scheduling/UnlimitedIoScheduler;
+Lkotlinx/coroutines/scheduling/WorkQueue;
+Lkotlinx/coroutines/sync/Empty;
+Lkotlinx/coroutines/sync/Mutex$DefaultImpls;
+Lkotlinx/coroutines/sync/Mutex;
+Lkotlinx/coroutines/sync/MutexImpl$LockCont;
+Lkotlinx/coroutines/sync/MutexImpl$LockWaiter;
+Lkotlinx/coroutines/sync/MutexImpl$LockedQueue;
+Lkotlinx/coroutines/sync/MutexImpl$UnlockOp;
+Lkotlinx/coroutines/sync/MutexImpl$lockSuspend$2$1$1;
+Lkotlinx/coroutines/sync/MutexImpl;
+Lkotlinx/coroutines/sync/MutexKt;
+PLandroidx/activity/ComponentActivity$$ExternalSyntheticLambda2;->saveState()Landroid/os/Bundle;
+PLandroidx/activity/ComponentActivity$1;->run()V
+PLandroidx/activity/ComponentActivity$2;->onLaunch(ILandroidx/activity/result/contract/ActivityResultContract;Ljava/lang/Object;Landroidx/core/app/ActivityOptionsCompat;)V
+PLandroidx/activity/ComponentActivity$Api19Impl;->cancelPendingInputEvents(Landroid/view/View;)V
+PLandroidx/activity/ComponentActivity$ReportFullyDrawnExecutorApi16Impl;->run()V
+PLandroidx/activity/ComponentActivity;->$r8$lambda$OnwlVMZzrLePIRy-6IUDTtLLUV0(Landroidx/activity/ComponentActivity;)Landroid/os/Bundle;
+PLandroidx/activity/ComponentActivity;->access$001(Landroidx/activity/ComponentActivity;)V
+PLandroidx/activity/ComponentActivity;->lambda$new$1()Landroid/os/Bundle;
+PLandroidx/activity/ComponentActivity;->onActivityResult(IILandroid/content/Intent;)V
+PLandroidx/activity/ComponentActivity;->onBackPressed()V
+PLandroidx/activity/ComponentActivity;->onNewIntent(Landroid/content/Intent;)V
+PLandroidx/activity/ComponentActivity;->onSaveInstanceState(Landroid/os/Bundle;)V
+PLandroidx/activity/ComponentActivity;->onTrimMemory(I)V
+PLandroidx/activity/ComponentActivity;->startIntentSenderForResult(Landroid/content/IntentSender;ILandroid/content/Intent;IIILandroid/os/Bundle;)V
+PLandroidx/activity/OnBackPressedDispatcher;->onBackPressed()V
+PLandroidx/activity/compose/ActivityResultLauncherHolder;->launch(Ljava/lang/Object;Landroidx/core/app/ActivityOptionsCompat;)V
+PLandroidx/activity/compose/ActivityResultRegistryKt$rememberLauncherForActivityResult$1$1;->onActivityResult(Ljava/lang/Object;)V
+PLandroidx/activity/compose/ManagedActivityResultLauncher;->launch(Ljava/lang/Object;Landroidx/core/app/ActivityOptionsCompat;)V
+PLandroidx/activity/contextaware/ContextAwareHelper;->clearAvailableContext()V
+PLandroidx/activity/result/ActivityResult$1;-><init>()V
+PLandroidx/activity/result/ActivityResult;-><clinit>()V
+PLandroidx/activity/result/ActivityResult;-><init>(ILandroid/content/Intent;)V
+PLandroidx/activity/result/ActivityResult;->getData()Landroid/content/Intent;
+PLandroidx/activity/result/ActivityResult;->getResultCode()I
+PLandroidx/activity/result/ActivityResultLauncher;->launch(Ljava/lang/Object;)V
+PLandroidx/activity/result/ActivityResultRegistry$3;->launch(Ljava/lang/Object;Landroidx/core/app/ActivityOptionsCompat;)V
+PLandroidx/activity/result/ActivityResultRegistry;->dispatchResult(IILandroid/content/Intent;)Z
+PLandroidx/activity/result/ActivityResultRegistry;->doDispatch(Ljava/lang/String;ILandroid/content/Intent;Landroidx/activity/result/ActivityResultRegistry$CallbackAndContract;)V
+PLandroidx/activity/result/ActivityResultRegistry;->onSaveInstanceState(Landroid/os/Bundle;)V
+PLandroidx/activity/result/IntentSenderRequest$1;-><init>()V
+PLandroidx/activity/result/IntentSenderRequest$Builder;-><init>(Landroid/app/PendingIntent;)V
+PLandroidx/activity/result/IntentSenderRequest$Builder;-><init>(Landroid/content/IntentSender;)V
+PLandroidx/activity/result/IntentSenderRequest$Builder;->build()Landroidx/activity/result/IntentSenderRequest;
+PLandroidx/activity/result/IntentSenderRequest$Builder;->setFillInIntent(Landroid/content/Intent;)Landroidx/activity/result/IntentSenderRequest$Builder;
+PLandroidx/activity/result/IntentSenderRequest;-><clinit>()V
+PLandroidx/activity/result/IntentSenderRequest;-><init>(Landroid/content/IntentSender;Landroid/content/Intent;II)V
+PLandroidx/activity/result/IntentSenderRequest;->getFillInIntent()Landroid/content/Intent;
+PLandroidx/activity/result/IntentSenderRequest;->getFlagsMask()I
+PLandroidx/activity/result/IntentSenderRequest;->getFlagsValues()I
+PLandroidx/activity/result/IntentSenderRequest;->getIntentSender()Landroid/content/IntentSender;
+PLandroidx/activity/result/contract/ActivityResultContract;->getSynchronousResult(Landroid/content/Context;Ljava/lang/Object;)Landroidx/activity/result/contract/ActivityResultContract$SynchronousResult;
+PLandroidx/activity/result/contract/ActivityResultContracts$StartIntentSenderForResult;->createIntent(Landroid/content/Context;Landroidx/activity/result/IntentSenderRequest;)Landroid/content/Intent;
+PLandroidx/activity/result/contract/ActivityResultContracts$StartIntentSenderForResult;->createIntent(Landroid/content/Context;Ljava/lang/Object;)Landroid/content/Intent;
+PLandroidx/activity/result/contract/ActivityResultContracts$StartIntentSenderForResult;->parseResult(ILandroid/content/Intent;)Landroidx/activity/result/ActivityResult;
+PLandroidx/activity/result/contract/ActivityResultContracts$StartIntentSenderForResult;->parseResult(ILandroid/content/Intent;)Ljava/lang/Object;
+PLandroidx/arch/core/internal/SafeIterableMap$DescendingIterator;-><init>(Landroidx/arch/core/internal/SafeIterableMap$Entry;Landroidx/arch/core/internal/SafeIterableMap$Entry;)V
+PLandroidx/arch/core/internal/SafeIterableMap$DescendingIterator;->forward(Landroidx/arch/core/internal/SafeIterableMap$Entry;)Landroidx/arch/core/internal/SafeIterableMap$Entry;
+PLandroidx/arch/core/internal/SafeIterableMap$ListIterator;->next()Ljava/lang/Object;
+PLandroidx/arch/core/internal/SafeIterableMap$ListIterator;->next()Ljava/util/Map$Entry;
+PLandroidx/arch/core/internal/SafeIterableMap$ListIterator;->nextNode()Landroidx/arch/core/internal/SafeIterableMap$Entry;
+PLandroidx/arch/core/internal/SafeIterableMap$ListIterator;->supportRemove(Landroidx/arch/core/internal/SafeIterableMap$Entry;)V
+PLandroidx/arch/core/internal/SafeIterableMap;->descendingIterator()Ljava/util/Iterator;
+PLandroidx/compose/animation/AndroidFlingSpline$FlingResult;-><clinit>()V
+PLandroidx/compose/animation/AndroidFlingSpline$FlingResult;-><init>(FF)V
+PLandroidx/compose/animation/AndroidFlingSpline$FlingResult;->getDistanceCoefficient()F
+PLandroidx/compose/animation/AndroidFlingSpline$FlingResult;->getVelocityCoefficient()F
+PLandroidx/compose/animation/AndroidFlingSpline;-><clinit>()V
+PLandroidx/compose/animation/AndroidFlingSpline;-><init>()V
+PLandroidx/compose/animation/AndroidFlingSpline;->deceleration(FF)D
+PLandroidx/compose/animation/AndroidFlingSpline;->flingPosition(F)Landroidx/compose/animation/AndroidFlingSpline$FlingResult;
+PLandroidx/compose/animation/ColorVectorConverterKt$ColorToVector$1$1;-><clinit>()V
+PLandroidx/compose/animation/ColorVectorConverterKt$ColorToVector$1$1;-><init>()V
+PLandroidx/compose/animation/ColorVectorConverterKt$ColorToVector$1$1;->invoke(Ljava/lang/Object;)Ljava/lang/Object;
+PLandroidx/compose/animation/ColorVectorConverterKt$ColorToVector$1$1;->invoke-8_81llA(J)Landroidx/compose/animation/core/AnimationVector4D;
+PLandroidx/compose/animation/ColorVectorConverterKt$ColorToVector$1$2;-><init>(Landroidx/compose/ui/graphics/colorspace/ColorSpace;)V
+PLandroidx/compose/animation/ColorVectorConverterKt$ColorToVector$1;-><clinit>()V
+PLandroidx/compose/animation/ColorVectorConverterKt$ColorToVector$1;-><init>()V
+PLandroidx/compose/animation/ColorVectorConverterKt$ColorToVector$1;->invoke(Landroidx/compose/ui/graphics/colorspace/ColorSpace;)Landroidx/compose/animation/core/TwoWayConverter;
+PLandroidx/compose/animation/ColorVectorConverterKt$ColorToVector$1;->invoke(Ljava/lang/Object;)Ljava/lang/Object;
+PLandroidx/compose/animation/ColorVectorConverterKt;-><clinit>()V
+PLandroidx/compose/animation/ColorVectorConverterKt;->access$getM1$p()[F
+PLandroidx/compose/animation/ColorVectorConverterKt;->access$multiplyColumn(IFFF[F)F
+PLandroidx/compose/animation/ColorVectorConverterKt;->getVectorConverter(Landroidx/compose/ui/graphics/Color$Companion;)Lkotlin/jvm/functions/Function1;
+PLandroidx/compose/animation/ColorVectorConverterKt;->multiplyColumn(IFFF[F)F
+PLandroidx/compose/animation/FlingCalculator$FlingInfo;-><clinit>()V
+PLandroidx/compose/animation/FlingCalculator$FlingInfo;-><init>(FFJ)V
+PLandroidx/compose/animation/FlingCalculator$FlingInfo;->position(J)F
+PLandroidx/compose/animation/FlingCalculator$FlingInfo;->velocity(J)F
+PLandroidx/compose/animation/FlingCalculator;-><init>(FLandroidx/compose/ui/unit/Density;)V
+PLandroidx/compose/animation/FlingCalculator;->computeDeceleration(Landroidx/compose/ui/unit/Density;)F
+PLandroidx/compose/animation/FlingCalculator;->flingDistance(F)F
+PLandroidx/compose/animation/FlingCalculator;->flingDuration(F)J
+PLandroidx/compose/animation/FlingCalculator;->flingInfo(F)Landroidx/compose/animation/FlingCalculator$FlingInfo;
+PLandroidx/compose/animation/FlingCalculator;->getSplineDeceleration(F)D
+PLandroidx/compose/animation/FlingCalculatorKt;-><clinit>()V
+PLandroidx/compose/animation/FlingCalculatorKt;->access$computeDeceleration(FF)F
+PLandroidx/compose/animation/FlingCalculatorKt;->access$getDecelerationRate$p()F
+PLandroidx/compose/animation/FlingCalculatorKt;->computeDeceleration(FF)F
+PLandroidx/compose/animation/SingleValueAnimationKt;-><clinit>()V
+PLandroidx/compose/animation/SingleValueAnimationKt;->animateColorAsState-KTwxG1Y(JLandroidx/compose/animation/core/AnimationSpec;Lkotlin/jvm/functions/Function1;Landroidx/compose/runtime/Composer;II)Landroidx/compose/runtime/State;
+PLandroidx/compose/animation/SingleValueAnimationKt;->animateColorAsState-euL9pac(JLandroidx/compose/animation/core/AnimationSpec;Ljava/lang/String;Lkotlin/jvm/functions/Function1;Landroidx/compose/runtime/Composer;II)Landroidx/compose/runtime/State;
+PLandroidx/compose/animation/SplineBasedDecayKt;->access$computeSplineInfo([F[FI)V
+PLandroidx/compose/animation/SplineBasedDecayKt;->computeSplineInfo([F[FI)V
+PLandroidx/compose/animation/SplineBasedFloatDecayAnimationSpec;-><clinit>()V
+PLandroidx/compose/animation/SplineBasedFloatDecayAnimationSpec;-><init>(Landroidx/compose/ui/unit/Density;)V
+PLandroidx/compose/animation/SplineBasedFloatDecayAnimationSpec;->flingDistance(F)F
+PLandroidx/compose/animation/SplineBasedFloatDecayAnimationSpec;->getAbsVelocityThreshold()F
+PLandroidx/compose/animation/SplineBasedFloatDecayAnimationSpec;->getDurationNanos(FF)J
+PLandroidx/compose/animation/SplineBasedFloatDecayAnimationSpec;->getTargetValue(FF)F
+PLandroidx/compose/animation/SplineBasedFloatDecayAnimationSpec;->getValueFromNanos(JFF)F
+PLandroidx/compose/animation/SplineBasedFloatDecayAnimationSpec;->getVelocityFromNanos(JFF)F
+PLandroidx/compose/animation/SplineBasedFloatDecayAnimationSpec_androidKt;-><clinit>()V
+PLandroidx/compose/animation/SplineBasedFloatDecayAnimationSpec_androidKt;->getPlatformFlingScrollFriction()F
+PLandroidx/compose/animation/SplineBasedFloatDecayAnimationSpec_androidKt;->rememberSplineBasedDecay(Landroidx/compose/runtime/Composer;I)Landroidx/compose/animation/core/DecayAnimationSpec;
+PLandroidx/compose/animation/core/AnimateAsStateKt;->access$animateValueAsState$lambda$4(Landroidx/compose/runtime/State;)Lkotlin/jvm/functions/Function1;
+PLandroidx/compose/animation/core/AnimateAsStateKt;->access$animateValueAsState$lambda$6(Landroidx/compose/runtime/State;)Landroidx/compose/animation/core/AnimationSpec;
+PLandroidx/compose/animation/core/AnimateAsStateKt;->animateValueAsState$lambda$4(Landroidx/compose/runtime/State;)Lkotlin/jvm/functions/Function1;
+PLandroidx/compose/animation/core/AnimateAsStateKt;->animateValueAsState$lambda$6(Landroidx/compose/runtime/State;)Landroidx/compose/animation/core/AnimationSpec;
+PLandroidx/compose/animation/core/AnimationScope;->cancelAnimation()V
+PLandroidx/compose/animation/core/AnimationScope;->getVelocity()Ljava/lang/Object;
+PLandroidx/compose/animation/core/AnimationSpecKt;->access$convert(Landroidx/compose/animation/core/TwoWayConverter;Ljava/lang/Object;)Landroidx/compose/animation/core/AnimationVector;
+PLandroidx/compose/animation/core/AnimationSpecKt;->convert(Landroidx/compose/animation/core/TwoWayConverter;Ljava/lang/Object;)Landroidx/compose/animation/core/AnimationVector;
+PLandroidx/compose/animation/core/AnimationStateKt;->AnimationState$default(FFJJZILjava/lang/Object;)Landroidx/compose/animation/core/AnimationState;
+PLandroidx/compose/animation/core/AnimationStateKt;->AnimationState(FFJJZ)Landroidx/compose/animation/core/AnimationState;
+PLandroidx/compose/animation/core/AnimationVector4D;-><clinit>()V
+PLandroidx/compose/animation/core/AnimationVector4D;-><init>(FFFF)V
+PLandroidx/compose/animation/core/AnimationVector4D;->getSize$animation_core_release()I
+PLandroidx/compose/animation/core/AnimationVector4D;->newVector$animation_core_release()Landroidx/compose/animation/core/AnimationVector4D;
+PLandroidx/compose/animation/core/AnimationVector4D;->newVector$animation_core_release()Landroidx/compose/animation/core/AnimationVector;
+PLandroidx/compose/animation/core/AnimationVector4D;->set$animation_core_release(IF)V
+PLandroidx/compose/animation/core/AnimationVectorsKt;->AnimationVector(F)Landroidx/compose/animation/core/AnimationVector1D;
+PLandroidx/compose/animation/core/ComplexDouble;-><init>(DD)V
+PLandroidx/compose/animation/core/ComplexDouble;->access$get_imaginary$p(Landroidx/compose/animation/core/ComplexDouble;)D
+PLandroidx/compose/animation/core/ComplexDouble;->access$get_real$p(Landroidx/compose/animation/core/ComplexDouble;)D
+PLandroidx/compose/animation/core/ComplexDouble;->access$set_imaginary$p(Landroidx/compose/animation/core/ComplexDouble;D)V
+PLandroidx/compose/animation/core/ComplexDouble;->access$set_real$p(Landroidx/compose/animation/core/ComplexDouble;D)V
+PLandroidx/compose/animation/core/ComplexDouble;->getReal()D
+PLandroidx/compose/animation/core/ComplexDoubleKt;->complexQuadraticFormula(DDD)Lkotlin/Pair;
+PLandroidx/compose/animation/core/ComplexDoubleKt;->complexSqrt(D)Landroidx/compose/animation/core/ComplexDouble;
+PLandroidx/compose/animation/core/DecayAnimation;-><clinit>()V
+PLandroidx/compose/animation/core/DecayAnimation;-><init>(Landroidx/compose/animation/core/DecayAnimationSpec;Landroidx/compose/animation/core/TwoWayConverter;Ljava/lang/Object;Landroidx/compose/animation/core/AnimationVector;)V
+PLandroidx/compose/animation/core/DecayAnimation;-><init>(Landroidx/compose/animation/core/VectorizedDecayAnimationSpec;Landroidx/compose/animation/core/TwoWayConverter;Ljava/lang/Object;Landroidx/compose/animation/core/AnimationVector;)V
+PLandroidx/compose/animation/core/DecayAnimation;->getDurationNanos()J
+PLandroidx/compose/animation/core/DecayAnimation;->getTargetValue()Ljava/lang/Object;
+PLandroidx/compose/animation/core/DecayAnimation;->getTypeConverter()Landroidx/compose/animation/core/TwoWayConverter;
+PLandroidx/compose/animation/core/DecayAnimation;->getValueFromNanos(J)Ljava/lang/Object;
+PLandroidx/compose/animation/core/DecayAnimation;->getVelocityVectorFromNanos(J)Landroidx/compose/animation/core/AnimationVector;
+PLandroidx/compose/animation/core/DecayAnimation;->isInfinite()Z
+PLandroidx/compose/animation/core/DecayAnimationSpecImpl;-><init>(Landroidx/compose/animation/core/FloatDecayAnimationSpec;)V
+PLandroidx/compose/animation/core/DecayAnimationSpecImpl;->vectorize(Landroidx/compose/animation/core/TwoWayConverter;)Landroidx/compose/animation/core/VectorizedDecayAnimationSpec;
+PLandroidx/compose/animation/core/DecayAnimationSpecKt;->generateDecayAnimationSpec(Landroidx/compose/animation/core/FloatDecayAnimationSpec;)Landroidx/compose/animation/core/DecayAnimationSpec;
+PLandroidx/compose/animation/core/EasingKt;->getFastOutLinearInEasing()Landroidx/compose/animation/core/Easing;
+PLandroidx/compose/animation/core/FloatSpringSpec;-><clinit>()V
+PLandroidx/compose/animation/core/FloatSpringSpec;-><init>(FFF)V
+PLandroidx/compose/animation/core/FloatSpringSpec;-><init>(FFFILkotlin/jvm/internal/DefaultConstructorMarker;)V
+PLandroidx/compose/animation/core/FloatSpringSpec;->getDurationNanos(FFF)J
+PLandroidx/compose/animation/core/FloatSpringSpec;->getEndVelocity(FFF)F
+PLandroidx/compose/animation/core/Motion;->constructor-impl(J)J
+PLandroidx/compose/animation/core/Motion;->getValue-impl(J)F
+PLandroidx/compose/animation/core/Motion;->getVelocity-impl(J)F
+PLandroidx/compose/animation/core/SpringEstimationKt$estimateCriticallyDamped$fn$1;-><init>(DDDD)V
+PLandroidx/compose/animation/core/SpringEstimationKt$estimateCriticallyDamped$fn$1;->invoke(D)Ljava/lang/Double;
+PLandroidx/compose/animation/core/SpringEstimationKt$estimateCriticallyDamped$fn$1;->invoke(Ljava/lang/Object;)Ljava/lang/Object;
+PLandroidx/compose/animation/core/SpringEstimationKt$estimateCriticallyDamped$fnPrime$1;-><init>(DDD)V
+PLandroidx/compose/animation/core/SpringEstimationKt$estimateCriticallyDamped$fnPrime$1;->invoke(D)Ljava/lang/Double;
+PLandroidx/compose/animation/core/SpringEstimationKt$estimateCriticallyDamped$fnPrime$1;->invoke(Ljava/lang/Object;)Ljava/lang/Object;
+PLandroidx/compose/animation/core/SpringEstimationKt;->estimateAnimationDurationMillis(DDDDD)J
+PLandroidx/compose/animation/core/SpringEstimationKt;->estimateAnimationDurationMillis(FFFFF)J
+PLandroidx/compose/animation/core/SpringEstimationKt;->estimateCriticallyDamped$t2Iterate(DD)D
+PLandroidx/compose/animation/core/SpringEstimationKt;->estimateCriticallyDamped(Lkotlin/Pair;DDD)D
+PLandroidx/compose/animation/core/SpringEstimationKt;->estimateDurationInternal(Lkotlin/Pair;DDDD)J
+PLandroidx/compose/animation/core/SpringSimulation;-><init>(F)V
+PLandroidx/compose/animation/core/SpringSimulation;->getDampingRatio()F
+PLandroidx/compose/animation/core/SpringSimulation;->getStiffness()F
+PLandroidx/compose/animation/core/SpringSimulation;->init()V
+PLandroidx/compose/animation/core/SpringSimulation;->setDampingRatio(F)V
+PLandroidx/compose/animation/core/SpringSimulation;->setFinalPosition(F)V
+PLandroidx/compose/animation/core/SpringSimulation;->setStiffness(F)V
+PLandroidx/compose/animation/core/SpringSimulationKt;-><clinit>()V
+PLandroidx/compose/animation/core/SpringSimulationKt;->Motion(FF)J
+PLandroidx/compose/animation/core/SpringSimulationKt;->getUNSET()F
+PLandroidx/compose/animation/core/SpringSpec;->vectorize(Landroidx/compose/animation/core/TwoWayConverter;)Landroidx/compose/animation/core/VectorizedAnimationSpec;
+PLandroidx/compose/animation/core/SpringSpec;->vectorize(Landroidx/compose/animation/core/TwoWayConverter;)Landroidx/compose/animation/core/VectorizedSpringSpec;
+PLandroidx/compose/animation/core/SuspendAnimationKt$animate$6$1;->invoke()Ljava/lang/Object;
+PLandroidx/compose/animation/core/SuspendAnimationKt$animate$6$1;->invoke()V
+PLandroidx/compose/animation/core/SuspendAnimationKt;->animateDecay$default(Landroidx/compose/animation/core/AnimationState;Landroidx/compose/animation/core/DecayAnimationSpec;ZLkotlin/jvm/functions/Function1;Lkotlin/coroutines/Continuation;ILjava/lang/Object;)Ljava/lang/Object;
+PLandroidx/compose/animation/core/SuspendAnimationKt;->animateDecay(Landroidx/compose/animation/core/AnimationState;Landroidx/compose/animation/core/DecayAnimationSpec;ZLkotlin/jvm/functions/Function1;Lkotlin/coroutines/Continuation;)Ljava/lang/Object;
+PLandroidx/compose/animation/core/VectorConvertersKt$FloatToVector$2;->invoke(Ljava/lang/Object;)Ljava/lang/Object;
+PLandroidx/compose/animation/core/VectorizedAnimationSpecKt$createSpringAnimations$2;-><init>(FF)V
+PLandroidx/compose/animation/core/VectorizedAnimationSpecKt$createSpringAnimations$2;->get(I)Landroidx/compose/animation/core/FloatAnimationSpec;
+PLandroidx/compose/animation/core/VectorizedAnimationSpecKt$createSpringAnimations$2;->get(I)Landroidx/compose/animation/core/FloatSpringSpec;
+PLandroidx/compose/animation/core/VectorizedAnimationSpecKt;->access$createSpringAnimations(Landroidx/compose/animation/core/AnimationVector;FF)Landroidx/compose/animation/core/Animations;
+PLandroidx/compose/animation/core/VectorizedAnimationSpecKt;->createSpringAnimations(Landroidx/compose/animation/core/AnimationVector;FF)Landroidx/compose/animation/core/Animations;
+PLandroidx/compose/animation/core/VectorizedFloatAnimationSpec;->getDurationNanos(Landroidx/compose/animation/core/AnimationVector;Landroidx/compose/animation/core/AnimationVector;Landroidx/compose/animation/core/AnimationVector;)J
+PLandroidx/compose/animation/core/VectorizedFloatAnimationSpec;->getEndVelocity(Landroidx/compose/animation/core/AnimationVector;Landroidx/compose/animation/core/AnimationVector;Landroidx/compose/animation/core/AnimationVector;)Landroidx/compose/animation/core/AnimationVector;
+PLandroidx/compose/animation/core/VectorizedFloatDecaySpec;-><init>(Landroidx/compose/animation/core/FloatDecayAnimationSpec;)V
+PLandroidx/compose/animation/core/VectorizedFloatDecaySpec;->getAbsVelocityThreshold()F
+PLandroidx/compose/animation/core/VectorizedFloatDecaySpec;->getDurationNanos(Landroidx/compose/animation/core/AnimationVector;Landroidx/compose/animation/core/AnimationVector;)J
+PLandroidx/compose/animation/core/VectorizedFloatDecaySpec;->getTargetValue(Landroidx/compose/animation/core/AnimationVector;Landroidx/compose/animation/core/AnimationVector;)Landroidx/compose/animation/core/AnimationVector;
+PLandroidx/compose/animation/core/VectorizedFloatDecaySpec;->getValueFromNanos(JLandroidx/compose/animation/core/AnimationVector;Landroidx/compose/animation/core/AnimationVector;)Landroidx/compose/animation/core/AnimationVector;
+PLandroidx/compose/animation/core/VectorizedFloatDecaySpec;->getVelocityFromNanos(JLandroidx/compose/animation/core/AnimationVector;Landroidx/compose/animation/core/AnimationVector;)Landroidx/compose/animation/core/AnimationVector;
+PLandroidx/compose/animation/core/VectorizedSpringSpec;-><clinit>()V
+PLandroidx/compose/animation/core/VectorizedSpringSpec;-><init>(FFLandroidx/compose/animation/core/AnimationVector;)V
+PLandroidx/compose/animation/core/VectorizedSpringSpec;-><init>(FFLandroidx/compose/animation/core/Animations;)V
+PLandroidx/compose/animation/core/VectorizedSpringSpec;->getDurationNanos(Landroidx/compose/animation/core/AnimationVector;Landroidx/compose/animation/core/AnimationVector;Landroidx/compose/animation/core/AnimationVector;)J
+PLandroidx/compose/animation/core/VectorizedSpringSpec;->getEndVelocity(Landroidx/compose/animation/core/AnimationVector;Landroidx/compose/animation/core/AnimationVector;Landroidx/compose/animation/core/AnimationVector;)Landroidx/compose/animation/core/AnimationVector;
+PLandroidx/compose/animation/core/VectorizedSpringSpec;->isInfinite()Z
+PLandroidx/compose/foundation/AndroidEdgeEffectOverscrollEffect$effectModifier$1$1;-><init>(Landroidx/compose/foundation/AndroidEdgeEffectOverscrollEffect;Lkotlin/coroutines/Continuation;)V
+PLandroidx/compose/foundation/AndroidEdgeEffectOverscrollEffect$effectModifier$1$1;->create(Ljava/lang/Object;Lkotlin/coroutines/Continuation;)Lkotlin/coroutines/Continuation;
+PLandroidx/compose/foundation/AndroidEdgeEffectOverscrollEffect$effectModifier$1$1;->invoke(Landroidx/compose/ui/input/pointer/AwaitPointerEventScope;Lkotlin/coroutines/Continuation;)Ljava/lang/Object;
+PLandroidx/compose/foundation/AndroidEdgeEffectOverscrollEffect$effectModifier$1$1;->invoke(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;
+PLandroidx/compose/foundation/AndroidEdgeEffectOverscrollEffect$effectModifier$1$1;->invokeSuspend(Ljava/lang/Object;)Ljava/lang/Object;
+PLandroidx/compose/foundation/AndroidEdgeEffectOverscrollEffect$effectModifier$1;-><init>(Landroidx/compose/foundation/AndroidEdgeEffectOverscrollEffect;Lkotlin/coroutines/Continuation;)V
+PLandroidx/compose/foundation/AndroidEdgeEffectOverscrollEffect$effectModifier$1;->create(Ljava/lang/Object;Lkotlin/coroutines/Continuation;)Lkotlin/coroutines/Continuation;
+PLandroidx/compose/foundation/AndroidEdgeEffectOverscrollEffect$effectModifier$1;->invoke(Landroidx/compose/ui/input/pointer/PointerInputScope;Lkotlin/coroutines/Continuation;)Ljava/lang/Object;
+PLandroidx/compose/foundation/AndroidEdgeEffectOverscrollEffect$effectModifier$1;->invoke(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;
+PLandroidx/compose/foundation/AndroidEdgeEffectOverscrollEffect$effectModifier$1;->invokeSuspend(Ljava/lang/Object;)Ljava/lang/Object;
+PLandroidx/compose/foundation/AndroidEdgeEffectOverscrollEffect$onNewSize$1;-><init>(Landroidx/compose/foundation/AndroidEdgeEffectOverscrollEffect;)V
+PLandroidx/compose/foundation/AndroidEdgeEffectOverscrollEffect$onNewSize$1;->invoke(Ljava/lang/Object;)Ljava/lang/Object;
+PLandroidx/compose/foundation/AndroidEdgeEffectOverscrollEffect$onNewSize$1;->invoke-ozmzZPI(J)V
+PLandroidx/compose/foundation/AndroidEdgeEffectOverscrollEffect;-><init>(Landroid/content/Context;Landroidx/compose/foundation/OverscrollConfiguration;)V
+PLandroidx/compose/foundation/AndroidEdgeEffectOverscrollEffect;->access$animateToRelease(Landroidx/compose/foundation/AndroidEdgeEffectOverscrollEffect;)V
+PLandroidx/compose/foundation/AndroidEdgeEffectOverscrollEffect;->access$getBottomEffect$p(Landroidx/compose/foundation/AndroidEdgeEffectOverscrollEffect;)Landroid/widget/EdgeEffect;
+PLandroidx/compose/foundation/AndroidEdgeEffectOverscrollEffect;->access$getBottomEffectNegation$p(Landroidx/compose/foundation/AndroidEdgeEffectOverscrollEffect;)Landroid/widget/EdgeEffect;
+PLandroidx/compose/foundation/AndroidEdgeEffectOverscrollEffect;->access$getContainerSize$p(Landroidx/compose/foundation/AndroidEdgeEffectOverscrollEffect;)J
+PLandroidx/compose/foundation/AndroidEdgeEffectOverscrollEffect;->access$getLeftEffect$p(Landroidx/compose/foundation/AndroidEdgeEffectOverscrollEffect;)Landroid/widget/EdgeEffect;
+PLandroidx/compose/foundation/AndroidEdgeEffectOverscrollEffect;->access$getLeftEffectNegation$p(Landroidx/compose/foundation/AndroidEdgeEffectOverscrollEffect;)Landroid/widget/EdgeEffect;
+PLandroidx/compose/foundation/AndroidEdgeEffectOverscrollEffect;->access$getPointerId$p(Landroidx/compose/foundation/AndroidEdgeEffectOverscrollEffect;)Landroidx/compose/ui/input/pointer/PointerId;
+PLandroidx/compose/foundation/AndroidEdgeEffectOverscrollEffect;->access$getRightEffect$p(Landroidx/compose/foundation/AndroidEdgeEffectOverscrollEffect;)Landroid/widget/EdgeEffect;
+PLandroidx/compose/foundation/AndroidEdgeEffectOverscrollEffect;->access$getRightEffectNegation$p(Landroidx/compose/foundation/AndroidEdgeEffectOverscrollEffect;)Landroid/widget/EdgeEffect;
+PLandroidx/compose/foundation/AndroidEdgeEffectOverscrollEffect;->access$getTopEffect$p(Landroidx/compose/foundation/AndroidEdgeEffectOverscrollEffect;)Landroid/widget/EdgeEffect;
+PLandroidx/compose/foundation/AndroidEdgeEffectOverscrollEffect;->access$getTopEffectNegation$p(Landroidx/compose/foundation/AndroidEdgeEffectOverscrollEffect;)Landroid/widget/EdgeEffect;
+PLandroidx/compose/foundation/AndroidEdgeEffectOverscrollEffect;->access$invalidateOverscroll(Landroidx/compose/foundation/AndroidEdgeEffectOverscrollEffect;)V
+PLandroidx/compose/foundation/AndroidEdgeEffectOverscrollEffect;->access$setContainerSize$p(Landroidx/compose/foundation/AndroidEdgeEffectOverscrollEffect;J)V
+PLandroidx/compose/foundation/AndroidEdgeEffectOverscrollEffect;->access$setPointerId$p(Landroidx/compose/foundation/AndroidEdgeEffectOverscrollEffect;Landroidx/compose/ui/input/pointer/PointerId;)V
+PLandroidx/compose/foundation/AndroidEdgeEffectOverscrollEffect;->access$setPointerPosition$p(Landroidx/compose/foundation/AndroidEdgeEffectOverscrollEffect;Landroidx/compose/ui/geometry/Offset;)V
+PLandroidx/compose/foundation/AndroidEdgeEffectOverscrollEffect;->animateToRelease()V
+PLandroidx/compose/foundation/AndroidEdgeEffectOverscrollEffect;->consumePostFling-sF-c-tU(JLkotlin/coroutines/Continuation;)Ljava/lang/Object;
+PLandroidx/compose/foundation/AndroidEdgeEffectOverscrollEffect;->consumePostScroll-OMhpSzk(JJI)V
+PLandroidx/compose/foundation/AndroidEdgeEffectOverscrollEffect;->consumePreFling-QWom1Mo(JLkotlin/coroutines/Continuation;)Ljava/lang/Object;
+PLandroidx/compose/foundation/AndroidEdgeEffectOverscrollEffect;->consumePreScroll-OzD1aCk(JI)J
+PLandroidx/compose/foundation/AndroidEdgeEffectOverscrollEffect;->drawOverscroll(Landroidx/compose/ui/graphics/drawscope/DrawScope;)V
+PLandroidx/compose/foundation/AndroidEdgeEffectOverscrollEffect;->getEffectModifier()Landroidx/compose/ui/Modifier;
+PLandroidx/compose/foundation/AndroidEdgeEffectOverscrollEffect;->invalidateOverscroll()V
+PLandroidx/compose/foundation/AndroidEdgeEffectOverscrollEffect;->isInProgress()Z
+PLandroidx/compose/foundation/AndroidEdgeEffectOverscrollEffect;->releaseOppositeOverscroll-k-4lQ0M(J)Z
+PLandroidx/compose/foundation/AndroidEdgeEffectOverscrollEffect;->stopOverscrollAnimation()Z
+PLandroidx/compose/foundation/AndroidOverscrollKt$NoOpOverscrollEffect$1;-><init>()V
+PLandroidx/compose/foundation/AndroidOverscrollKt$StretchOverscrollNonClippingLayer$1$1;-><init>(Landroidx/compose/ui/layout/Placeable;I)V
+PLandroidx/compose/foundation/AndroidOverscrollKt$StretchOverscrollNonClippingLayer$1$1;->invoke(Landroidx/compose/ui/layout/Placeable$PlacementScope;)V
+PLandroidx/compose/foundation/AndroidOverscrollKt$StretchOverscrollNonClippingLayer$1$1;->invoke(Ljava/lang/Object;)Ljava/lang/Object;
+PLandroidx/compose/foundation/AndroidOverscrollKt$StretchOverscrollNonClippingLayer$1;-><clinit>()V
+PLandroidx/compose/foundation/AndroidOverscrollKt$StretchOverscrollNonClippingLayer$1;-><init>()V
+PLandroidx/compose/foundation/AndroidOverscrollKt$StretchOverscrollNonClippingLayer$1;->invoke(Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;
+PLandroidx/compose/foundation/AndroidOverscrollKt$StretchOverscrollNonClippingLayer$1;->invoke-3p2s80s(Landroidx/compose/ui/layout/MeasureScope;Landroidx/compose/ui/layout/Measurable;J)Landroidx/compose/ui/layout/MeasureResult;
+PLandroidx/compose/foundation/AndroidOverscrollKt$StretchOverscrollNonClippingLayer$2$1;-><init>(Landroidx/compose/ui/layout/Placeable;I)V
+PLandroidx/compose/foundation/AndroidOverscrollKt$StretchOverscrollNonClippingLayer$2$1;->invoke(Landroidx/compose/ui/layout/Placeable$PlacementScope;)V
+PLandroidx/compose/foundation/AndroidOverscrollKt$StretchOverscrollNonClippingLayer$2$1;->invoke(Ljava/lang/Object;)Ljava/lang/Object;
+PLandroidx/compose/foundation/AndroidOverscrollKt$StretchOverscrollNonClippingLayer$2;-><clinit>()V
+PLandroidx/compose/foundation/AndroidOverscrollKt$StretchOverscrollNonClippingLayer$2;-><init>()V
+PLandroidx/compose/foundation/AndroidOverscrollKt$StretchOverscrollNonClippingLayer$2;->invoke(Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;
+PLandroidx/compose/foundation/AndroidOverscrollKt$StretchOverscrollNonClippingLayer$2;->invoke-3p2s80s(Landroidx/compose/ui/layout/MeasureScope;Landroidx/compose/ui/layout/Measurable;J)Landroidx/compose/ui/layout/MeasureResult;
+PLandroidx/compose/foundation/AndroidOverscrollKt;-><clinit>()V
+PLandroidx/compose/foundation/AndroidOverscrollKt;->access$getStretchOverscrollNonClippingLayer$p()Landroidx/compose/ui/Modifier;
+PLandroidx/compose/foundation/AndroidOverscrollKt;->rememberOverscrollEffect(Landroidx/compose/runtime/Composer;I)Landroidx/compose/foundation/OverscrollEffect;
+PLandroidx/compose/foundation/Api31Impl;-><clinit>()V
+PLandroidx/compose/foundation/Api31Impl;-><init>()V
+PLandroidx/compose/foundation/Api31Impl;->create(Landroid/content/Context;Landroid/util/AttributeSet;)Landroid/widget/EdgeEffect;
+PLandroidx/compose/foundation/Api31Impl;->getDistance(Landroid/widget/EdgeEffect;)F
+PLandroidx/compose/foundation/CheckScrollableContainerConstraintsKt;->checkScrollableContainerConstraints-K40F9xA(JLandroidx/compose/foundation/gestures/Orientation;)V
+PLandroidx/compose/foundation/ClickableKt$PressedInteractionSourceDisposableEffect$1$invoke$$inlined$onDispose$1;->dispose()V
+PLandroidx/compose/foundation/ClickableKt$clickable$4$1$1$1;->invoke()Ljava/lang/Boolean;
+PLandroidx/compose/foundation/ClickableKt$clickable$4$1$1$1;->invoke()Ljava/lang/Object;
+PLandroidx/compose/foundation/ClickableKt$clickable$4$gesture$1$1$1;->invoke(Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;
+PLandroidx/compose/foundation/ClickableKt$clickable$4$gesture$1$1$1;->invoke-d-4ec7I(Landroidx/compose/foundation/gestures/PressGestureScope;JLkotlin/coroutines/Continuation;)Ljava/lang/Object;
+PLandroidx/compose/foundation/ClickableKt$clickable$4$gesture$1$1$1;->invokeSuspend(Ljava/lang/Object;)Ljava/lang/Object;
+PLandroidx/compose/foundation/ClickableKt$clickable$4$gesture$1$1$2;->invoke(Ljava/lang/Object;)Ljava/lang/Object;
+PLandroidx/compose/foundation/ClickableKt$clickable$4$gesture$1$1$2;->invoke-k-4lQ0M(J)V
+PLandroidx/compose/foundation/ClickableKt$handlePressInteraction$2$delayJob$1;-><init>(Landroidx/compose/runtime/State;JLandroidx/compose/foundation/interaction/MutableInteractionSource;Landroidx/compose/runtime/MutableState;Lkotlin/coroutines/Continuation;)V
+PLandroidx/compose/foundation/ClickableKt$handlePressInteraction$2$delayJob$1;->create(Ljava/lang/Object;Lkotlin/coroutines/Continuation;)Lkotlin/coroutines/Continuation;
+PLandroidx/compose/foundation/ClickableKt$handlePressInteraction$2$delayJob$1;->invokeSuspend(Ljava/lang/Object;)Ljava/lang/Object;
+PLandroidx/compose/foundation/ClickableKt$handlePressInteraction$2;-><init>(Landroidx/compose/foundation/gestures/PressGestureScope;JLandroidx/compose/foundation/interaction/MutableInteractionSource;Landroidx/compose/runtime/MutableState;Landroidx/compose/runtime/State;Lkotlin/coroutines/Continuation;)V
+PLandroidx/compose/foundation/ClickableKt$handlePressInteraction$2;->create(Ljava/lang/Object;Lkotlin/coroutines/Continuation;)Lkotlin/coroutines/Continuation;
+PLandroidx/compose/foundation/ClickableKt$handlePressInteraction$2;->invoke(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;
+PLandroidx/compose/foundation/ClickableKt$handlePressInteraction$2;->invoke(Lkotlinx/coroutines/CoroutineScope;Lkotlin/coroutines/Continuation;)Ljava/lang/Object;
+PLandroidx/compose/foundation/ClickableKt$handlePressInteraction$2;->invokeSuspend(Ljava/lang/Object;)Ljava/lang/Object;
+PLandroidx/compose/foundation/ClickableKt;->handlePressInteraction-EPk0efs(Landroidx/compose/foundation/gestures/PressGestureScope;JLandroidx/compose/foundation/interaction/MutableInteractionSource;Landroidx/compose/runtime/MutableState;Landroidx/compose/runtime/State;Lkotlin/coroutines/Continuation;)Ljava/lang/Object;
+PLandroidx/compose/foundation/Clickable_androidKt;-><clinit>()V
+PLandroidx/compose/foundation/Clickable_androidKt;->getTapIndicationDelay()J
+PLandroidx/compose/foundation/ClipScrollableContainerKt$HorizontalScrollableClipModifier$1;-><init>()V
+PLandroidx/compose/foundation/ClipScrollableContainerKt$VerticalScrollableClipModifier$1;-><init>()V
+PLandroidx/compose/foundation/ClipScrollableContainerKt$VerticalScrollableClipModifier$1;->createOutline-Pq9zytI(JLandroidx/compose/ui/unit/LayoutDirection;Landroidx/compose/ui/unit/Density;)Landroidx/compose/ui/graphics/Outline;
+PLandroidx/compose/foundation/ClipScrollableContainerKt;-><clinit>()V
+PLandroidx/compose/foundation/ClipScrollableContainerKt;->clipScrollableContainer(Landroidx/compose/ui/Modifier;Landroidx/compose/foundation/gestures/Orientation;)Landroidx/compose/ui/Modifier;
+PLandroidx/compose/foundation/ClipScrollableContainerKt;->getMaxSupportedElevation()F
+PLandroidx/compose/foundation/DrawOverscrollModifier;-><init>(Landroidx/compose/foundation/AndroidEdgeEffectOverscrollEffect;Lkotlin/jvm/functions/Function1;)V
+PLandroidx/compose/foundation/DrawOverscrollModifier;->draw(Landroidx/compose/ui/graphics/drawscope/ContentDrawScope;)V
+PLandroidx/compose/foundation/DrawOverscrollModifier;->equals(Ljava/lang/Object;)Z
+PLandroidx/compose/foundation/EdgeEffectCompat;-><clinit>()V
+PLandroidx/compose/foundation/EdgeEffectCompat;-><init>()V
+PLandroidx/compose/foundation/EdgeEffectCompat;->create(Landroid/content/Context;Landroid/util/AttributeSet;)Landroid/widget/EdgeEffect;
+PLandroidx/compose/foundation/EdgeEffectCompat;->getDistanceCompat(Landroid/widget/EdgeEffect;)F
+PLandroidx/compose/foundation/FocusableKt$focusGroup$1;-><clinit>()V
+PLandroidx/compose/foundation/FocusableKt$focusGroup$1;-><init>()V
+PLandroidx/compose/foundation/FocusableKt$focusGroup$1;->invoke(Landroidx/compose/ui/focus/FocusProperties;)V
+PLandroidx/compose/foundation/FocusableKt$focusGroup$1;->invoke(Ljava/lang/Object;)Ljava/lang/Object;
+PLandroidx/compose/foundation/FocusableKt$focusable$2$1$1$invoke$$inlined$onDispose$1;->dispose()V
+PLandroidx/compose/foundation/FocusableKt$focusable$2$2$invoke$$inlined$onDispose$1;->dispose()V
+PLandroidx/compose/foundation/FocusableKt;->focusGroup(Landroidx/compose/ui/Modifier;)Landroidx/compose/ui/Modifier;
+PLandroidx/compose/foundation/FocusedBoundsKt$ModifierLocalFocusedBoundsObserver$1;-><clinit>()V
+PLandroidx/compose/foundation/FocusedBoundsKt$ModifierLocalFocusedBoundsObserver$1;-><init>()V
+PLandroidx/compose/foundation/FocusedBoundsKt$ModifierLocalFocusedBoundsObserver$1;->invoke()Ljava/lang/Object;
+PLandroidx/compose/foundation/FocusedBoundsKt$ModifierLocalFocusedBoundsObserver$1;->invoke()Lkotlin/jvm/functions/Function1;
+PLandroidx/compose/foundation/FocusedBoundsKt$onFocusedBoundsChanged$2;-><init>(Lkotlin/jvm/functions/Function1;)V
+PLandroidx/compose/foundation/FocusedBoundsKt$onFocusedBoundsChanged$2;->invoke(Landroidx/compose/ui/Modifier;Landroidx/compose/runtime/Composer;I)Landroidx/compose/ui/Modifier;
+PLandroidx/compose/foundation/FocusedBoundsKt$onFocusedBoundsChanged$2;->invoke(Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;
+PLandroidx/compose/foundation/FocusedBoundsKt;-><clinit>()V
+PLandroidx/compose/foundation/FocusedBoundsKt;->getModifierLocalFocusedBoundsObserver()Landroidx/compose/ui/modifier/ProvidableModifierLocal;
+PLandroidx/compose/foundation/FocusedBoundsKt;->onFocusedBoundsChanged(Landroidx/compose/ui/Modifier;Lkotlin/jvm/functions/Function1;)Landroidx/compose/ui/Modifier;
+PLandroidx/compose/foundation/FocusedBoundsObserverModifier;-><init>(Lkotlin/jvm/functions/Function1;)V
+PLandroidx/compose/foundation/FocusedBoundsObserverModifier;->getKey()Landroidx/compose/ui/modifier/ProvidableModifierLocal;
+PLandroidx/compose/foundation/FocusedBoundsObserverModifier;->onModifierLocalsUpdated(Landroidx/compose/ui/modifier/ModifierLocalReadScope;)V
+PLandroidx/compose/foundation/HoverableKt$hoverable$2$1$1$invoke$$inlined$onDispose$1;->dispose()V
+PLandroidx/compose/foundation/HoverableKt$hoverable$2;->access$invoke$tryEmitExit(Landroidx/compose/runtime/MutableState;Landroidx/compose/foundation/interaction/MutableInteractionSource;)V
+PLandroidx/compose/foundation/HoverableKt$hoverable$2;->invoke$lambda$1(Landroidx/compose/runtime/MutableState;)Landroidx/compose/foundation/interaction/HoverInteraction$Enter;
+PLandroidx/compose/foundation/HoverableKt$hoverable$2;->invoke$tryEmitExit(Landroidx/compose/runtime/MutableState;Landroidx/compose/foundation/interaction/MutableInteractionSource;)V
+PLandroidx/compose/foundation/ImageKt$Image$2$measure$1;-><clinit>()V
+PLandroidx/compose/foundation/ImageKt$Image$2$measure$1;-><init>()V
+PLandroidx/compose/foundation/ImageKt$Image$2$measure$1;->invoke(Landroidx/compose/ui/layout/Placeable$PlacementScope;)V
+PLandroidx/compose/foundation/ImageKt$Image$2$measure$1;->invoke(Ljava/lang/Object;)Ljava/lang/Object;
+PLandroidx/compose/foundation/ImageKt$Image$2;-><clinit>()V
+PLandroidx/compose/foundation/ImageKt$Image$2;-><init>()V
+PLandroidx/compose/foundation/ImageKt$Image$2;->measure-3p2s80s(Landroidx/compose/ui/layout/MeasureScope;Ljava/util/List;J)Landroidx/compose/ui/layout/MeasureResult;
+PLandroidx/compose/foundation/ImageKt$Image$semantics$1$1;-><init>(Ljava/lang/String;)V
+PLandroidx/compose/foundation/ImageKt$Image$semantics$1$1;->invoke(Landroidx/compose/ui/semantics/SemanticsPropertyReceiver;)V
+PLandroidx/compose/foundation/ImageKt$Image$semantics$1$1;->invoke(Ljava/lang/Object;)Ljava/lang/Object;
+PLandroidx/compose/foundation/ImageKt;->Image-5h-nEew(Landroidx/compose/ui/graphics/ImageBitmap;Ljava/lang/String;Landroidx/compose/ui/Modifier;Landroidx/compose/ui/Alignment;Landroidx/compose/ui/layout/ContentScale;FLandroidx/compose/ui/graphics/ColorFilter;ILandroidx/compose/runtime/Composer;II)V
+PLandroidx/compose/foundation/OverscrollConfiguration;-><init>(JLandroidx/compose/foundation/layout/PaddingValues;)V
+PLandroidx/compose/foundation/OverscrollConfiguration;-><init>(JLandroidx/compose/foundation/layout/PaddingValues;ILkotlin/jvm/internal/DefaultConstructorMarker;)V
+PLandroidx/compose/foundation/OverscrollConfiguration;-><init>(JLandroidx/compose/foundation/layout/PaddingValues;Lkotlin/jvm/internal/DefaultConstructorMarker;)V
+PLandroidx/compose/foundation/OverscrollConfiguration;->equals(Ljava/lang/Object;)Z
+PLandroidx/compose/foundation/OverscrollConfiguration;->getGlowColor-0d7_KjU()J
+PLandroidx/compose/foundation/OverscrollConfigurationKt$LocalOverscrollConfiguration$1;-><clinit>()V
+PLandroidx/compose/foundation/OverscrollConfigurationKt$LocalOverscrollConfiguration$1;-><init>()V
+PLandroidx/compose/foundation/OverscrollConfigurationKt$LocalOverscrollConfiguration$1;->invoke()Landroidx/compose/foundation/OverscrollConfiguration;
+PLandroidx/compose/foundation/OverscrollConfigurationKt$LocalOverscrollConfiguration$1;->invoke()Ljava/lang/Object;
+PLandroidx/compose/foundation/OverscrollConfigurationKt;-><clinit>()V
+PLandroidx/compose/foundation/OverscrollConfigurationKt;->getLocalOverscrollConfiguration()Landroidx/compose/runtime/ProvidableCompositionLocal;
+PLandroidx/compose/foundation/OverscrollKt;->overscroll(Landroidx/compose/ui/Modifier;Landroidx/compose/foundation/OverscrollEffect;)Landroidx/compose/ui/Modifier;
+PLandroidx/compose/foundation/gestures/AndroidConfig;-><clinit>()V
+PLandroidx/compose/foundation/gestures/AndroidConfig;-><init>()V
+PLandroidx/compose/foundation/gestures/AndroidScrollable_androidKt;->platformScrollConfig(Landroidx/compose/runtime/Composer;I)Landroidx/compose/foundation/gestures/ScrollConfig;
+PLandroidx/compose/foundation/gestures/ContentInViewModifier$modifier$1;-><init>(Landroidx/compose/foundation/gestures/ContentInViewModifier;)V
+PLandroidx/compose/foundation/gestures/ContentInViewModifier;-><init>(Lkotlinx/coroutines/CoroutineScope;Landroidx/compose/foundation/gestures/Orientation;Landroidx/compose/foundation/gestures/ScrollableState;Z)V
+PLandroidx/compose/foundation/gestures/ContentInViewModifier;->getModifier()Landroidx/compose/ui/Modifier;
+PLandroidx/compose/foundation/gestures/ContentInViewModifier;->onPlaced(Landroidx/compose/ui/layout/LayoutCoordinates;)V
+PLandroidx/compose/foundation/gestures/ContentInViewModifier;->onRemeasured-ozmzZPI(J)V
+PLandroidx/compose/foundation/gestures/DefaultFlingBehavior$performFling$2$1;-><init>(Lkotlin/jvm/internal/Ref$FloatRef;Landroidx/compose/foundation/gestures/ScrollScope;Lkotlin/jvm/internal/Ref$FloatRef;Landroidx/compose/foundation/gestures/DefaultFlingBehavior;)V
+PLandroidx/compose/foundation/gestures/DefaultFlingBehavior$performFling$2$1;->invoke(Landroidx/compose/animation/core/AnimationScope;)V
+PLandroidx/compose/foundation/gestures/DefaultFlingBehavior$performFling$2$1;->invoke(Ljava/lang/Object;)Ljava/lang/Object;
+PLandroidx/compose/foundation/gestures/DefaultFlingBehavior$performFling$2;-><init>(FLandroidx/compose/foundation/gestures/DefaultFlingBehavior;Landroidx/compose/foundation/gestures/ScrollScope;Lkotlin/coroutines/Continuation;)V
+PLandroidx/compose/foundation/gestures/DefaultFlingBehavior$performFling$2;->create(Ljava/lang/Object;Lkotlin/coroutines/Continuation;)Lkotlin/coroutines/Continuation;
+PLandroidx/compose/foundation/gestures/DefaultFlingBehavior$performFling$2;->invoke(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;
+PLandroidx/compose/foundation/gestures/DefaultFlingBehavior$performFling$2;->invoke(Lkotlinx/coroutines/CoroutineScope;Lkotlin/coroutines/Continuation;)Ljava/lang/Object;
+PLandroidx/compose/foundation/gestures/DefaultFlingBehavior$performFling$2;->invokeSuspend(Ljava/lang/Object;)Ljava/lang/Object;
+PLandroidx/compose/foundation/gestures/DefaultFlingBehavior;-><init>(Landroidx/compose/animation/core/DecayAnimationSpec;Landroidx/compose/ui/MotionDurationScale;)V
+PLandroidx/compose/foundation/gestures/DefaultFlingBehavior;-><init>(Landroidx/compose/animation/core/DecayAnimationSpec;Landroidx/compose/ui/MotionDurationScale;ILkotlin/jvm/internal/DefaultConstructorMarker;)V
+PLandroidx/compose/foundation/gestures/DefaultFlingBehavior;->access$getFlingDecay$p(Landroidx/compose/foundation/gestures/DefaultFlingBehavior;)Landroidx/compose/animation/core/DecayAnimationSpec;
+PLandroidx/compose/foundation/gestures/DefaultFlingBehavior;->getLastAnimationCycleCount()I
+PLandroidx/compose/foundation/gestures/DefaultFlingBehavior;->performFling(Landroidx/compose/foundation/gestures/ScrollScope;FLkotlin/coroutines/Continuation;)Ljava/lang/Object;
+PLandroidx/compose/foundation/gestures/DefaultFlingBehavior;->setLastAnimationCycleCount(I)V
+PLandroidx/compose/foundation/gestures/DefaultScrollableState$scroll$2$1;-><init>(Landroidx/compose/foundation/gestures/DefaultScrollableState;Lkotlin/jvm/functions/Function2;Lkotlin/coroutines/Continuation;)V
+PLandroidx/compose/foundation/gestures/DefaultScrollableState$scroll$2$1;->create(Ljava/lang/Object;Lkotlin/coroutines/Continuation;)Lkotlin/coroutines/Continuation;
+PLandroidx/compose/foundation/gestures/DefaultScrollableState$scroll$2$1;->invoke(Landroidx/compose/foundation/gestures/ScrollScope;Lkotlin/coroutines/Continuation;)Ljava/lang/Object;
+PLandroidx/compose/foundation/gestures/DefaultScrollableState$scroll$2$1;->invoke(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;
+PLandroidx/compose/foundation/gestures/DefaultScrollableState$scroll$2$1;->invokeSuspend(Ljava/lang/Object;)Ljava/lang/Object;
+PLandroidx/compose/foundation/gestures/DefaultScrollableState$scroll$2;-><init>(Landroidx/compose/foundation/gestures/DefaultScrollableState;Landroidx/compose/foundation/MutatePriority;Lkotlin/jvm/functions/Function2;Lkotlin/coroutines/Continuation;)V
+PLandroidx/compose/foundation/gestures/DefaultScrollableState$scroll$2;->create(Ljava/lang/Object;Lkotlin/coroutines/Continuation;)Lkotlin/coroutines/Continuation;
+PLandroidx/compose/foundation/gestures/DefaultScrollableState$scroll$2;->invoke(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;
+PLandroidx/compose/foundation/gestures/DefaultScrollableState$scroll$2;->invoke(Lkotlinx/coroutines/CoroutineScope;Lkotlin/coroutines/Continuation;)Ljava/lang/Object;
+PLandroidx/compose/foundation/gestures/DefaultScrollableState$scroll$2;->invokeSuspend(Ljava/lang/Object;)Ljava/lang/Object;
+PLandroidx/compose/foundation/gestures/DefaultScrollableState$scrollScope$1;-><init>(Landroidx/compose/foundation/gestures/DefaultScrollableState;)V
+PLandroidx/compose/foundation/gestures/DefaultScrollableState$scrollScope$1;->scrollBy(F)F
+PLandroidx/compose/foundation/gestures/DefaultScrollableState;-><init>(Lkotlin/jvm/functions/Function1;)V
+PLandroidx/compose/foundation/gestures/DefaultScrollableState;->access$getScrollMutex$p(Landroidx/compose/foundation/gestures/DefaultScrollableState;)Landroidx/compose/foundation/MutatorMutex;
+PLandroidx/compose/foundation/gestures/DefaultScrollableState;->access$getScrollScope$p(Landroidx/compose/foundation/gestures/DefaultScrollableState;)Landroidx/compose/foundation/gestures/ScrollScope;
+PLandroidx/compose/foundation/gestures/DefaultScrollableState;->access$isScrollingState$p(Landroidx/compose/foundation/gestures/DefaultScrollableState;)Landroidx/compose/runtime/MutableState;
+PLandroidx/compose/foundation/gestures/DefaultScrollableState;->getOnDelta()Lkotlin/jvm/functions/Function1;
+PLandroidx/compose/foundation/gestures/DefaultScrollableState;->isScrollInProgress()Z
+PLandroidx/compose/foundation/gestures/DefaultScrollableState;->scroll(Landroidx/compose/foundation/MutatePriority;Lkotlin/jvm/functions/Function2;Lkotlin/coroutines/Continuation;)Ljava/lang/Object;
+PLandroidx/compose/foundation/gestures/DragEvent$DragDelta;-><clinit>()V
+PLandroidx/compose/foundation/gestures/DragEvent$DragDelta;-><init>(J)V
+PLandroidx/compose/foundation/gestures/DragEvent$DragDelta;-><init>(JLkotlin/jvm/internal/DefaultConstructorMarker;)V
+PLandroidx/compose/foundation/gestures/DragEvent$DragDelta;->getDelta-F1C5BW0()J
+PLandroidx/compose/foundation/gestures/DragEvent$DragStarted;-><clinit>()V
+PLandroidx/compose/foundation/gestures/DragEvent$DragStarted;-><init>(J)V
+PLandroidx/compose/foundation/gestures/DragEvent$DragStarted;-><init>(JLkotlin/jvm/internal/DefaultConstructorMarker;)V
+PLandroidx/compose/foundation/gestures/DragEvent$DragStarted;->getStartPoint-F1C5BW0()J
+PLandroidx/compose/foundation/gestures/DragEvent$DragStopped;-><clinit>()V
+PLandroidx/compose/foundation/gestures/DragEvent$DragStopped;-><init>(J)V
+PLandroidx/compose/foundation/gestures/DragEvent$DragStopped;-><init>(JLkotlin/jvm/internal/DefaultConstructorMarker;)V
+PLandroidx/compose/foundation/gestures/DragEvent$DragStopped;->getVelocity-9UxMQ8M()J
+PLandroidx/compose/foundation/gestures/DragEvent;-><init>()V
+PLandroidx/compose/foundation/gestures/DragEvent;-><init>(Lkotlin/jvm/internal/DefaultConstructorMarker;)V
+PLandroidx/compose/foundation/gestures/DragGestureDetectorKt$HorizontalPointerDirectionConfig$1;-><init>()V
+PLandroidx/compose/foundation/gestures/DragGestureDetectorKt$VerticalPointerDirectionConfig$1;-><init>()V
+PLandroidx/compose/foundation/gestures/DragGestureDetectorKt$VerticalPointerDirectionConfig$1;->crossAxisDelta-k-4lQ0M(J)F
+PLandroidx/compose/foundation/gestures/DragGestureDetectorKt$VerticalPointerDirectionConfig$1;->mainAxisDelta-k-4lQ0M(J)F
+PLandroidx/compose/foundation/gestures/DragGestureDetectorKt$VerticalPointerDirectionConfig$1;->offsetFromChanges-dBAh8RU(FF)J
+PLandroidx/compose/foundation/gestures/DragGestureDetectorKt$verticalDrag$1;-><init>(Lkotlin/coroutines/Continuation;)V
+PLandroidx/compose/foundation/gestures/DragGestureDetectorKt$verticalDrag$1;->invokeSuspend(Ljava/lang/Object;)Ljava/lang/Object;
+PLandroidx/compose/foundation/gestures/DragGestureDetectorKt;-><clinit>()V
+PLandroidx/compose/foundation/gestures/DragGestureDetectorKt;->access$isPointerUp-DmW0f2w(Landroidx/compose/ui/input/pointer/PointerEvent;J)Z
+PLandroidx/compose/foundation/gestures/DragGestureDetectorKt;->isPointerUp-DmW0f2w(Landroidx/compose/ui/input/pointer/PointerEvent;J)Z
+PLandroidx/compose/foundation/gestures/DragGestureDetectorKt;->pointerSlop-E8SPZFQ(Landroidx/compose/ui/platform/ViewConfiguration;I)F
+PLandroidx/compose/foundation/gestures/DragGestureDetectorKt;->toPointerDirectionConfig(Landroidx/compose/foundation/gestures/Orientation;)Landroidx/compose/foundation/gestures/PointerDirectionConfig;
+PLandroidx/compose/foundation/gestures/DragGestureDetectorKt;->verticalDrag-jO51t88(Landroidx/compose/ui/input/pointer/AwaitPointerEventScope;JLkotlin/jvm/functions/Function1;Lkotlin/coroutines/Continuation;)Ljava/lang/Object;
+PLandroidx/compose/foundation/gestures/DragLogic$processDragStart$1;-><init>(Landroidx/compose/foundation/gestures/DragLogic;Lkotlin/coroutines/Continuation;)V
+PLandroidx/compose/foundation/gestures/DragLogic$processDragStop$1;-><init>(Landroidx/compose/foundation/gestures/DragLogic;Lkotlin/coroutines/Continuation;)V
+PLandroidx/compose/foundation/gestures/DragLogic;->processDragStart(Lkotlinx/coroutines/CoroutineScope;Landroidx/compose/foundation/gestures/DragEvent$DragStarted;Lkotlin/coroutines/Continuation;)Ljava/lang/Object;
+PLandroidx/compose/foundation/gestures/DragLogic;->processDragStop(Lkotlinx/coroutines/CoroutineScope;Landroidx/compose/foundation/gestures/DragEvent$DragStopped;Lkotlin/coroutines/Continuation;)Ljava/lang/Object;
+PLandroidx/compose/foundation/gestures/DraggableKt$awaitDownAndSlop$1;->invokeSuspend(Ljava/lang/Object;)Ljava/lang/Object;
+PLandroidx/compose/foundation/gestures/DraggableKt$awaitDownAndSlop$postPointerSlop$1;-><init>(Landroidx/compose/ui/input/pointer/util/VelocityTracker;Lkotlin/jvm/internal/Ref$LongRef;)V
+PLandroidx/compose/foundation/gestures/DraggableKt$awaitDownAndSlop$postPointerSlop$1;->invoke(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;
+PLandroidx/compose/foundation/gestures/DraggableKt$awaitDownAndSlop$postPointerSlop$1;->invoke-Uv8p0NA(Landroidx/compose/ui/input/pointer/PointerInputChange;J)V
+PLandroidx/compose/foundation/gestures/DraggableKt$awaitDrag$dragTick$1;-><init>(Landroidx/compose/ui/input/pointer/util/VelocityTracker;Lkotlinx/coroutines/channels/SendChannel;Z)V
+PLandroidx/compose/foundation/gestures/DraggableKt$awaitDrag$dragTick$1;->invoke(Landroidx/compose/ui/input/pointer/PointerInputChange;)V
+PLandroidx/compose/foundation/gestures/DraggableKt$awaitDrag$dragTick$1;->invoke(Ljava/lang/Object;)Ljava/lang/Object;
+PLandroidx/compose/foundation/gestures/DraggableKt$draggable$1;->invoke(Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;
+PLandroidx/compose/foundation/gestures/DraggableKt$draggable$1;->invoke-d-4ec7I(Lkotlinx/coroutines/CoroutineScope;JLkotlin/coroutines/Continuation;)Ljava/lang/Object;
+PLandroidx/compose/foundation/gestures/DraggableKt$draggable$1;->invokeSuspend(Ljava/lang/Object;)Ljava/lang/Object;
+PLandroidx/compose/foundation/gestures/DraggableKt$draggable$3;->invoke(Landroidx/compose/ui/input/pointer/PointerInputChange;)Ljava/lang/Boolean;
+PLandroidx/compose/foundation/gestures/DraggableKt$draggable$3;->invoke(Ljava/lang/Object;)Ljava/lang/Object;
+PLandroidx/compose/foundation/gestures/DraggableKt$draggable$4;->invoke()Ljava/lang/Boolean;
+PLandroidx/compose/foundation/gestures/DraggableKt$draggable$4;->invoke()Ljava/lang/Object;
+PLandroidx/compose/foundation/gestures/DraggableKt$draggable$5;->invoke(Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;
+PLandroidx/compose/foundation/gestures/DraggableKt$draggable$5;->invoke-LuvzFrg(Lkotlinx/coroutines/CoroutineScope;JLkotlin/coroutines/Continuation;)Ljava/lang/Object;
+PLandroidx/compose/foundation/gestures/DraggableKt$draggable$5;->invokeSuspend(Ljava/lang/Object;)Ljava/lang/Object;
+PLandroidx/compose/foundation/gestures/DraggableKt$draggable$6;-><init>(Lkotlin/coroutines/Continuation;)V
+PLandroidx/compose/foundation/gestures/DraggableKt$draggable$6;->invoke(Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;
+PLandroidx/compose/foundation/gestures/DraggableKt$draggable$6;->invoke-d-4ec7I(Lkotlinx/coroutines/CoroutineScope;JLkotlin/coroutines/Continuation;)Ljava/lang/Object;
+PLandroidx/compose/foundation/gestures/DraggableKt$draggable$6;->invokeSuspend(Ljava/lang/Object;)Ljava/lang/Object;
+PLandroidx/compose/foundation/gestures/DraggableKt$draggable$9$1$1$invoke$$inlined$onDispose$1;->dispose()V
+PLandroidx/compose/foundation/gestures/DraggableKt$draggable$9$2$2;-><init>(Lkotlin/jvm/internal/Ref$ObjectRef;Lkotlinx/coroutines/channels/Channel;Landroidx/compose/foundation/gestures/Orientation;Lkotlin/coroutines/Continuation;)V
+PLandroidx/compose/foundation/gestures/DraggableKt$draggable$9$2$2;->create(Ljava/lang/Object;Lkotlin/coroutines/Continuation;)Lkotlin/coroutines/Continuation;
+PLandroidx/compose/foundation/gestures/DraggableKt$draggable$9$2$2;->invoke(Landroidx/compose/foundation/gestures/DragScope;Lkotlin/coroutines/Continuation;)Ljava/lang/Object;
+PLandroidx/compose/foundation/gestures/DraggableKt$draggable$9$2$2;->invoke(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;
+PLandroidx/compose/foundation/gestures/DraggableKt$draggable$9$2$2;->invokeSuspend(Ljava/lang/Object;)Ljava/lang/Object;
+PLandroidx/compose/foundation/gestures/DraggableKt$draggable$9;->access$invoke$lambda$3(Landroidx/compose/runtime/State;)Landroidx/compose/foundation/gestures/DragLogic;
+PLandroidx/compose/foundation/gestures/DraggableKt$draggable$9;->invoke$lambda$3(Landroidx/compose/runtime/State;)Landroidx/compose/foundation/gestures/DragLogic;
+PLandroidx/compose/foundation/gestures/DraggableKt;->access$awaitDrag-Su4bsnU(Landroidx/compose/ui/input/pointer/AwaitPointerEventScope;Landroidx/compose/ui/input/pointer/PointerInputChange;JLandroidx/compose/ui/input/pointer/util/VelocityTracker;Lkotlinx/coroutines/channels/SendChannel;ZLandroidx/compose/foundation/gestures/Orientation;Lkotlin/coroutines/Continuation;)Ljava/lang/Object;
+PLandroidx/compose/foundation/gestures/DraggableKt;->access$toFloat-3MmeM6k(JLandroidx/compose/foundation/gestures/Orientation;)F
+PLandroidx/compose/foundation/gestures/DraggableKt;->access$toFloat-sF-c-tU(JLandroidx/compose/foundation/gestures/Orientation;)F
+PLandroidx/compose/foundation/gestures/DraggableKt;->awaitDrag-Su4bsnU(Landroidx/compose/ui/input/pointer/AwaitPointerEventScope;Landroidx/compose/ui/input/pointer/PointerInputChange;JLandroidx/compose/ui/input/pointer/util/VelocityTracker;Lkotlinx/coroutines/channels/SendChannel;ZLandroidx/compose/foundation/gestures/Orientation;Lkotlin/coroutines/Continuation;)Ljava/lang/Object;
+PLandroidx/compose/foundation/gestures/DraggableKt;->draggable$default(Landroidx/compose/ui/Modifier;Landroidx/compose/foundation/gestures/DraggableState;Lkotlin/jvm/functions/Function1;Landroidx/compose/foundation/gestures/Orientation;ZLandroidx/compose/foundation/interaction/MutableInteractionSource;Lkotlin/jvm/functions/Function0;Lkotlin/jvm/functions/Function3;Lkotlin/jvm/functions/Function3;ZILjava/lang/Object;)Landroidx/compose/ui/Modifier;
+PLandroidx/compose/foundation/gestures/DraggableKt;->toFloat-3MmeM6k(JLandroidx/compose/foundation/gestures/Orientation;)F
+PLandroidx/compose/foundation/gestures/DraggableKt;->toFloat-sF-c-tU(JLandroidx/compose/foundation/gestures/Orientation;)F
+PLandroidx/compose/foundation/gestures/ForEachGestureKt$awaitAllPointersUp$3;-><init>(Lkotlin/coroutines/Continuation;)V
+PLandroidx/compose/foundation/gestures/ForEachGestureKt$awaitAllPointersUp$3;->invokeSuspend(Ljava/lang/Object;)Ljava/lang/Object;
+PLandroidx/compose/foundation/gestures/ForEachGestureKt;->allPointersUp(Landroidx/compose/ui/input/pointer/AwaitPointerEventScope;)Z
+PLandroidx/compose/foundation/gestures/ForEachGestureKt;->awaitAllPointersUp(Landroidx/compose/ui/input/pointer/AwaitPointerEventScope;Lkotlin/coroutines/Continuation;)Ljava/lang/Object;
+PLandroidx/compose/foundation/gestures/PressGestureScopeImpl$reset$1;->invokeSuspend(Ljava/lang/Object;)Ljava/lang/Object;
+PLandroidx/compose/foundation/gestures/PressGestureScopeImpl$tryAwaitRelease$1;-><init>(Landroidx/compose/foundation/gestures/PressGestureScopeImpl;Lkotlin/coroutines/Continuation;)V
+PLandroidx/compose/foundation/gestures/PressGestureScopeImpl$tryAwaitRelease$1;->invokeSuspend(Ljava/lang/Object;)Ljava/lang/Object;
+PLandroidx/compose/foundation/gestures/PressGestureScopeImpl;->cancel()V
+PLandroidx/compose/foundation/gestures/PressGestureScopeImpl;->release()V
+PLandroidx/compose/foundation/gestures/PressGestureScopeImpl;->tryAwaitRelease(Lkotlin/coroutines/Continuation;)Ljava/lang/Object;
+PLandroidx/compose/foundation/gestures/ScrollDraggableState$drag$2;-><init>(Landroidx/compose/foundation/gestures/ScrollDraggableState;Lkotlin/jvm/functions/Function2;Lkotlin/coroutines/Continuation;)V
+PLandroidx/compose/foundation/gestures/ScrollDraggableState$drag$2;->create(Ljava/lang/Object;Lkotlin/coroutines/Continuation;)Lkotlin/coroutines/Continuation;
+PLandroidx/compose/foundation/gestures/ScrollDraggableState$drag$2;->invoke(Landroidx/compose/foundation/gestures/ScrollScope;Lkotlin/coroutines/Continuation;)Ljava/lang/Object;
+PLandroidx/compose/foundation/gestures/ScrollDraggableState$drag$2;->invoke(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;
+PLandroidx/compose/foundation/gestures/ScrollDraggableState$drag$2;->invokeSuspend(Ljava/lang/Object;)Ljava/lang/Object;
+PLandroidx/compose/foundation/gestures/ScrollDraggableState;-><init>(Landroidx/compose/runtime/State;)V
+PLandroidx/compose/foundation/gestures/ScrollDraggableState;->drag(Landroidx/compose/foundation/MutatePriority;Lkotlin/jvm/functions/Function2;Lkotlin/coroutines/Continuation;)Ljava/lang/Object;
+PLandroidx/compose/foundation/gestures/ScrollDraggableState;->dragBy(F)V
+PLandroidx/compose/foundation/gestures/ScrollDraggableState;->setLatestScrollScope(Landroidx/compose/foundation/gestures/ScrollScope;)V
+PLandroidx/compose/foundation/gestures/ScrollableDefaults;-><clinit>()V
+PLandroidx/compose/foundation/gestures/ScrollableDefaults;-><init>()V
+PLandroidx/compose/foundation/gestures/ScrollableDefaults;->flingBehavior(Landroidx/compose/runtime/Composer;I)Landroidx/compose/foundation/gestures/FlingBehavior;
+PLandroidx/compose/foundation/gestures/ScrollableDefaults;->overscrollEffect(Landroidx/compose/runtime/Composer;I)Landroidx/compose/foundation/OverscrollEffect;
+PLandroidx/compose/foundation/gestures/ScrollableDefaults;->reverseDirection(Landroidx/compose/ui/unit/LayoutDirection;Landroidx/compose/foundation/gestures/Orientation;Z)Z
+PLandroidx/compose/foundation/gestures/ScrollableKt$DefaultScrollMotionDurationScale$1;-><init>()V
+PLandroidx/compose/foundation/gestures/ScrollableKt$DefaultScrollMotionDurationScale$1;->fold(Ljava/lang/Object;Lkotlin/jvm/functions/Function2;)Ljava/lang/Object;
+PLandroidx/compose/foundation/gestures/ScrollableKt$DefaultScrollMotionDurationScale$1;->get(Lkotlin/coroutines/CoroutineContext$Key;)Lkotlin/coroutines/CoroutineContext$Element;
+PLandroidx/compose/foundation/gestures/ScrollableKt$DefaultScrollMotionDurationScale$1;->getScaleFactor()F
+PLandroidx/compose/foundation/gestures/ScrollableKt$NoOpScrollScope$1;-><init>()V
+PLandroidx/compose/foundation/gestures/ScrollableKt$awaitScrollEvent$1;-><init>(Lkotlin/coroutines/Continuation;)V
+PLandroidx/compose/foundation/gestures/ScrollableKt$awaitScrollEvent$1;->invokeSuspend(Ljava/lang/Object;)Ljava/lang/Object;
+PLandroidx/compose/foundation/gestures/ScrollableKt$mouseWheelScroll$1$1;-><init>(Landroidx/compose/foundation/gestures/ScrollConfig;Landroidx/compose/runtime/State;Lkotlin/coroutines/Continuation;)V
+PLandroidx/compose/foundation/gestures/ScrollableKt$mouseWheelScroll$1$1;->create(Ljava/lang/Object;Lkotlin/coroutines/Continuation;)Lkotlin/coroutines/Continuation;
+PLandroidx/compose/foundation/gestures/ScrollableKt$mouseWheelScroll$1$1;->invokeSuspend(Ljava/lang/Object;)Ljava/lang/Object;
+PLandroidx/compose/foundation/gestures/ScrollableKt$mouseWheelScroll$1;-><init>(Landroidx/compose/foundation/gestures/ScrollConfig;Landroidx/compose/runtime/State;Lkotlin/coroutines/Continuation;)V
+PLandroidx/compose/foundation/gestures/ScrollableKt$mouseWheelScroll$1;->create(Ljava/lang/Object;Lkotlin/coroutines/Continuation;)Lkotlin/coroutines/Continuation;
+PLandroidx/compose/foundation/gestures/ScrollableKt$mouseWheelScroll$1;->invoke(Landroidx/compose/ui/input/pointer/PointerInputScope;Lkotlin/coroutines/Continuation;)Ljava/lang/Object;
+PLandroidx/compose/foundation/gestures/ScrollableKt$mouseWheelScroll$1;->invoke(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;
+PLandroidx/compose/foundation/gestures/ScrollableKt$mouseWheelScroll$1;->invokeSuspend(Ljava/lang/Object;)Ljava/lang/Object;
+PLandroidx/compose/foundation/gestures/ScrollableKt$pointerScrollable$1;-><clinit>()V
+PLandroidx/compose/foundation/gestures/ScrollableKt$pointerScrollable$1;-><init>()V
+PLandroidx/compose/foundation/gestures/ScrollableKt$pointerScrollable$1;->invoke(Landroidx/compose/ui/input/pointer/PointerInputChange;)Ljava/lang/Boolean;
+PLandroidx/compose/foundation/gestures/ScrollableKt$pointerScrollable$1;->invoke(Ljava/lang/Object;)Ljava/lang/Object;
+PLandroidx/compose/foundation/gestures/ScrollableKt$pointerScrollable$2$1;-><init>(Landroidx/compose/runtime/State;)V
+PLandroidx/compose/foundation/gestures/ScrollableKt$pointerScrollable$2$1;->invoke()Ljava/lang/Boolean;
+PLandroidx/compose/foundation/gestures/ScrollableKt$pointerScrollable$2$1;->invoke()Ljava/lang/Object;
+PLandroidx/compose/foundation/gestures/ScrollableKt$pointerScrollable$3$1$1;-><init>(Landroidx/compose/runtime/State;JLkotlin/coroutines/Continuation;)V
+PLandroidx/compose/foundation/gestures/ScrollableKt$pointerScrollable$3$1$1;->create(Ljava/lang/Object;Lkotlin/coroutines/Continuation;)Lkotlin/coroutines/Continuation;
+PLandroidx/compose/foundation/gestures/ScrollableKt$pointerScrollable$3$1$1;->invokeSuspend(Ljava/lang/Object;)Ljava/lang/Object;
+PLandroidx/compose/foundation/gestures/ScrollableKt$pointerScrollable$3$1;-><init>(Landroidx/compose/runtime/MutableState;Landroidx/compose/runtime/State;Lkotlin/coroutines/Continuation;)V
+PLandroidx/compose/foundation/gestures/ScrollableKt$pointerScrollable$3$1;->invoke(Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;
+PLandroidx/compose/foundation/gestures/ScrollableKt$pointerScrollable$3$1;->invoke-LuvzFrg(Lkotlinx/coroutines/CoroutineScope;JLkotlin/coroutines/Continuation;)Ljava/lang/Object;
+PLandroidx/compose/foundation/gestures/ScrollableKt$pointerScrollable$3$1;->invokeSuspend(Ljava/lang/Object;)Ljava/lang/Object;
+PLandroidx/compose/foundation/gestures/ScrollableKt$pointerScrollable$scrollContainerInfo$1$1;-><init>(ZLandroidx/compose/foundation/gestures/Orientation;)V
+PLandroidx/compose/foundation/gestures/ScrollableKt$pointerScrollable$scrollContainerInfo$1$1;->canScrollVertically()Z
+PLandroidx/compose/foundation/gestures/ScrollableKt$scrollable$2;-><init>(Landroidx/compose/foundation/gestures/Orientation;Landroidx/compose/foundation/gestures/ScrollableState;ZLandroidx/compose/foundation/interaction/MutableInteractionSource;Landroidx/compose/foundation/gestures/FlingBehavior;Landroidx/compose/foundation/OverscrollEffect;Z)V
+PLandroidx/compose/foundation/gestures/ScrollableKt$scrollable$2;->invoke(Landroidx/compose/ui/Modifier;Landroidx/compose/runtime/Composer;I)Landroidx/compose/ui/Modifier;
+PLandroidx/compose/foundation/gestures/ScrollableKt$scrollable$2;->invoke(Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;
+PLandroidx/compose/foundation/gestures/ScrollableKt$scrollableNestedScrollConnection$1;-><init>(Landroidx/compose/runtime/State;Z)V
+PLandroidx/compose/foundation/gestures/ScrollableKt;-><clinit>()V
+PLandroidx/compose/foundation/gestures/ScrollableKt;->access$awaitScrollEvent(Landroidx/compose/ui/input/pointer/AwaitPointerEventScope;Lkotlin/coroutines/Continuation;)Ljava/lang/Object;
+PLandroidx/compose/foundation/gestures/ScrollableKt;->access$getNoOpScrollScope$p()Landroidx/compose/foundation/gestures/ScrollScope;
+PLandroidx/compose/foundation/gestures/ScrollableKt;->access$pointerScrollable(Landroidx/compose/ui/Modifier;Landroidx/compose/foundation/interaction/MutableInteractionSource;Landroidx/compose/foundation/gestures/Orientation;ZLandroidx/compose/foundation/gestures/ScrollableState;Landroidx/compose/foundation/gestures/FlingBehavior;Landroidx/compose/foundation/OverscrollEffect;ZLandroidx/compose/runtime/Composer;I)Landroidx/compose/ui/Modifier;
+PLandroidx/compose/foundation/gestures/ScrollableKt;->access$scrollableNestedScrollConnection(Landroidx/compose/runtime/State;Z)Landroidx/compose/ui/input/nestedscroll/NestedScrollConnection;
+PLandroidx/compose/foundation/gestures/ScrollableKt;->awaitScrollEvent(Landroidx/compose/ui/input/pointer/AwaitPointerEventScope;Lkotlin/coroutines/Continuation;)Ljava/lang/Object;
+PLandroidx/compose/foundation/gestures/ScrollableKt;->getDefaultScrollMotionDurationScale()Landroidx/compose/ui/MotionDurationScale;
+PLandroidx/compose/foundation/gestures/ScrollableKt;->mouseWheelScroll(Landroidx/compose/ui/Modifier;Landroidx/compose/runtime/State;Landroidx/compose/foundation/gestures/ScrollConfig;)Landroidx/compose/ui/Modifier;
+PLandroidx/compose/foundation/gestures/ScrollableKt;->pointerScrollable(Landroidx/compose/ui/Modifier;Landroidx/compose/foundation/interaction/MutableInteractionSource;Landroidx/compose/foundation/gestures/Orientation;ZLandroidx/compose/foundation/gestures/ScrollableState;Landroidx/compose/foundation/gestures/FlingBehavior;Landroidx/compose/foundation/OverscrollEffect;ZLandroidx/compose/runtime/Composer;I)Landroidx/compose/ui/Modifier;
+PLandroidx/compose/foundation/gestures/ScrollableKt;->scrollable(Landroidx/compose/ui/Modifier;Landroidx/compose/foundation/gestures/ScrollableState;Landroidx/compose/foundation/gestures/Orientation;Landroidx/compose/foundation/OverscrollEffect;ZZLandroidx/compose/foundation/gestures/FlingBehavior;Landroidx/compose/foundation/interaction/MutableInteractionSource;)Landroidx/compose/ui/Modifier;
+PLandroidx/compose/foundation/gestures/ScrollableKt;->scrollableNestedScrollConnection(Landroidx/compose/runtime/State;Z)Landroidx/compose/ui/input/nestedscroll/NestedScrollConnection;
+PLandroidx/compose/foundation/gestures/ScrollableState;->scroll$default(Landroidx/compose/foundation/gestures/ScrollableState;Landroidx/compose/foundation/MutatePriority;Lkotlin/jvm/functions/Function2;Lkotlin/coroutines/Continuation;ILjava/lang/Object;)Ljava/lang/Object;
+PLandroidx/compose/foundation/gestures/ScrollableStateKt;->ScrollableState(Lkotlin/jvm/functions/Function1;)Landroidx/compose/foundation/gestures/ScrollableState;
+PLandroidx/compose/foundation/gestures/ScrollingLogic$doFlingAnimation$1;-><init>(Landroidx/compose/foundation/gestures/ScrollingLogic;Lkotlin/coroutines/Continuation;)V
+PLandroidx/compose/foundation/gestures/ScrollingLogic$doFlingAnimation$1;->invokeSuspend(Ljava/lang/Object;)Ljava/lang/Object;
+PLandroidx/compose/foundation/gestures/ScrollingLogic$doFlingAnimation$2$outerScopeScroll$1;-><init>(Landroidx/compose/foundation/gestures/ScrollingLogic;Landroidx/compose/foundation/gestures/ScrollScope;)V
+PLandroidx/compose/foundation/gestures/ScrollingLogic$doFlingAnimation$2$outerScopeScroll$1;->invoke(Ljava/lang/Object;)Ljava/lang/Object;
+PLandroidx/compose/foundation/gestures/ScrollingLogic$doFlingAnimation$2$outerScopeScroll$1;->invoke-MK-Hz9U(J)J
+PLandroidx/compose/foundation/gestures/ScrollingLogic$doFlingAnimation$2$scope$1;-><init>(Landroidx/compose/foundation/gestures/ScrollingLogic;Lkotlin/jvm/functions/Function1;)V
+PLandroidx/compose/foundation/gestures/ScrollingLogic$doFlingAnimation$2$scope$1;->scrollBy(F)F
+PLandroidx/compose/foundation/gestures/ScrollingLogic$doFlingAnimation$2;-><init>(Landroidx/compose/foundation/gestures/ScrollingLogic;Lkotlin/jvm/internal/Ref$LongRef;JLkotlin/coroutines/Continuation;)V
+PLandroidx/compose/foundation/gestures/ScrollingLogic$doFlingAnimation$2;->create(Ljava/lang/Object;Lkotlin/coroutines/Continuation;)Lkotlin/coroutines/Continuation;
+PLandroidx/compose/foundation/gestures/ScrollingLogic$doFlingAnimation$2;->invoke(Landroidx/compose/foundation/gestures/ScrollScope;Lkotlin/coroutines/Continuation;)Ljava/lang/Object;
+PLandroidx/compose/foundation/gestures/ScrollingLogic$doFlingAnimation$2;->invoke(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;
+PLandroidx/compose/foundation/gestures/ScrollingLogic$doFlingAnimation$2;->invokeSuspend(Ljava/lang/Object;)Ljava/lang/Object;
+PLandroidx/compose/foundation/gestures/ScrollingLogic$onDragStopped$1;-><init>(Landroidx/compose/foundation/gestures/ScrollingLogic;Lkotlin/coroutines/Continuation;)V
+PLandroidx/compose/foundation/gestures/ScrollingLogic$onDragStopped$1;->invokeSuspend(Ljava/lang/Object;)Ljava/lang/Object;
+PLandroidx/compose/foundation/gestures/ScrollingLogic;-><init>(Landroidx/compose/foundation/gestures/Orientation;ZLandroidx/compose/runtime/State;Landroidx/compose/foundation/gestures/ScrollableState;Landroidx/compose/foundation/gestures/FlingBehavior;Landroidx/compose/foundation/OverscrollEffect;)V
+PLandroidx/compose/foundation/gestures/ScrollingLogic;->dispatchScroll-3eAAhYA(Landroidx/compose/foundation/gestures/ScrollScope;JI)J
+PLandroidx/compose/foundation/gestures/ScrollingLogic;->doFlingAnimation-QWom1Mo(JLkotlin/coroutines/Continuation;)Ljava/lang/Object;
+PLandroidx/compose/foundation/gestures/ScrollingLogic;->getFlingBehavior()Landroidx/compose/foundation/gestures/FlingBehavior;
+PLandroidx/compose/foundation/gestures/ScrollingLogic;->getScrollableState()Landroidx/compose/foundation/gestures/ScrollableState;
+PLandroidx/compose/foundation/gestures/ScrollingLogic;->getShouldDispatchOverscroll()Z
+PLandroidx/compose/foundation/gestures/ScrollingLogic;->onDragStopped-sF-c-tU(JLkotlin/coroutines/Continuation;)Ljava/lang/Object;
+PLandroidx/compose/foundation/gestures/ScrollingLogic;->overscrollPostConsumeDelta-OMhpSzk(JJI)V
+PLandroidx/compose/foundation/gestures/ScrollingLogic;->overscrollPreConsumeDelta-OzD1aCk(JI)J
+PLandroidx/compose/foundation/gestures/ScrollingLogic;->registerNestedFling(Z)V
+PLandroidx/compose/foundation/gestures/ScrollingLogic;->reverseIfNeeded(F)F
+PLandroidx/compose/foundation/gestures/ScrollingLogic;->reverseIfNeeded-MK-Hz9U(J)J
+PLandroidx/compose/foundation/gestures/ScrollingLogic;->shouldScrollImmediately()Z
+PLandroidx/compose/foundation/gestures/ScrollingLogic;->singleAxisOffset-MK-Hz9U(J)J
+PLandroidx/compose/foundation/gestures/ScrollingLogic;->singleAxisVelocity-AH228Gc(J)J
+PLandroidx/compose/foundation/gestures/ScrollingLogic;->toFloat-TH1AsA0(J)F
+PLandroidx/compose/foundation/gestures/ScrollingLogic;->toFloat-k-4lQ0M(J)F
+PLandroidx/compose/foundation/gestures/ScrollingLogic;->toOffset-tuRUvjQ(F)J
+PLandroidx/compose/foundation/gestures/ScrollingLogic;->update-QWom1Mo(JF)J
+PLandroidx/compose/foundation/gestures/TapGestureDetectorKt$detectTapAndPress$2$1$2;-><init>(Lkotlin/jvm/functions/Function3;Landroidx/compose/foundation/gestures/PressGestureScopeImpl;Landroidx/compose/ui/input/pointer/PointerInputChange;Lkotlin/coroutines/Continuation;)V
+PLandroidx/compose/foundation/gestures/TapGestureDetectorKt$detectTapAndPress$2$1$2;->create(Ljava/lang/Object;Lkotlin/coroutines/Continuation;)Lkotlin/coroutines/Continuation;
+PLandroidx/compose/foundation/gestures/TapGestureDetectorKt$detectTapAndPress$2$1$2;->invokeSuspend(Ljava/lang/Object;)Ljava/lang/Object;
+PLandroidx/compose/foundation/gestures/TapGestureDetectorKt$detectTapAndPress$2$1$3;-><init>(Landroidx/compose/foundation/gestures/PressGestureScopeImpl;Lkotlin/coroutines/Continuation;)V
+PLandroidx/compose/foundation/gestures/TapGestureDetectorKt$detectTapAndPress$2$1$3;->create(Ljava/lang/Object;Lkotlin/coroutines/Continuation;)Lkotlin/coroutines/Continuation;
+PLandroidx/compose/foundation/gestures/TapGestureDetectorKt$detectTapAndPress$2$1$3;->invokeSuspend(Ljava/lang/Object;)Ljava/lang/Object;
+PLandroidx/compose/foundation/gestures/TapGestureDetectorKt$detectTapAndPress$2$1$4;-><init>(Landroidx/compose/foundation/gestures/PressGestureScopeImpl;Lkotlin/coroutines/Continuation;)V
+PLandroidx/compose/foundation/gestures/TapGestureDetectorKt$detectTapAndPress$2$1$4;->create(Ljava/lang/Object;Lkotlin/coroutines/Continuation;)Lkotlin/coroutines/Continuation;
+PLandroidx/compose/foundation/gestures/TapGestureDetectorKt$detectTapAndPress$2$1$4;->invokeSuspend(Ljava/lang/Object;)Ljava/lang/Object;
+PLandroidx/compose/foundation/gestures/TapGestureDetectorKt$detectTapGestures$2$1$1;-><init>(Landroidx/compose/foundation/gestures/PressGestureScopeImpl;Lkotlin/coroutines/Continuation;)V
+PLandroidx/compose/foundation/gestures/TapGestureDetectorKt$detectTapGestures$2$1$1;->create(Ljava/lang/Object;Lkotlin/coroutines/Continuation;)Lkotlin/coroutines/Continuation;
+PLandroidx/compose/foundation/gestures/TapGestureDetectorKt$detectTapGestures$2$1$1;->invokeSuspend(Ljava/lang/Object;)Ljava/lang/Object;
+PLandroidx/compose/foundation/gestures/TapGestureDetectorKt$detectTapGestures$2$1$3;-><init>(Lkotlin/coroutines/Continuation;)V
+PLandroidx/compose/foundation/gestures/TapGestureDetectorKt$detectTapGestures$2$1$3;->create(Ljava/lang/Object;Lkotlin/coroutines/Continuation;)Lkotlin/coroutines/Continuation;
+PLandroidx/compose/foundation/gestures/TapGestureDetectorKt$detectTapGestures$2$1$3;->invoke(Landroidx/compose/ui/input/pointer/AwaitPointerEventScope;Lkotlin/coroutines/Continuation;)Ljava/lang/Object;
+PLandroidx/compose/foundation/gestures/TapGestureDetectorKt$detectTapGestures$2$1$3;->invoke(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;
+PLandroidx/compose/foundation/gestures/TapGestureDetectorKt$detectTapGestures$2$1$3;->invokeSuspend(Ljava/lang/Object;)Ljava/lang/Object;
+PLandroidx/compose/foundation/gestures/TapGestureDetectorKt$detectTapGestures$2$1$5;-><init>(Landroidx/compose/foundation/gestures/PressGestureScopeImpl;Lkotlin/coroutines/Continuation;)V
+PLandroidx/compose/foundation/gestures/TapGestureDetectorKt$detectTapGestures$2$1$5;->create(Ljava/lang/Object;Lkotlin/coroutines/Continuation;)Lkotlin/coroutines/Continuation;
+PLandroidx/compose/foundation/gestures/TapGestureDetectorKt$detectTapGestures$2$1$5;->invokeSuspend(Ljava/lang/Object;)Ljava/lang/Object;
+PLandroidx/compose/foundation/gestures/TapGestureDetectorKt$waitForUpOrCancellation$2;-><init>(Lkotlin/coroutines/Continuation;)V
+PLandroidx/compose/foundation/gestures/TapGestureDetectorKt$waitForUpOrCancellation$2;->invokeSuspend(Ljava/lang/Object;)Ljava/lang/Object;
+PLandroidx/compose/foundation/gestures/TapGestureDetectorKt;->access$getNoPressGesture$p()Lkotlin/jvm/functions/Function3;
+PLandroidx/compose/foundation/gestures/TapGestureDetectorKt;->waitForUpOrCancellation$default(Landroidx/compose/ui/input/pointer/AwaitPointerEventScope;Landroidx/compose/ui/input/pointer/PointerEventPass;Lkotlin/coroutines/Continuation;ILjava/lang/Object;)Ljava/lang/Object;
+PLandroidx/compose/foundation/interaction/DragInteraction$Start;-><clinit>()V
+PLandroidx/compose/foundation/interaction/DragInteraction$Start;-><init>()V
+PLandroidx/compose/foundation/interaction/DragInteraction$Stop;-><clinit>()V
+PLandroidx/compose/foundation/interaction/DragInteraction$Stop;-><init>(Landroidx/compose/foundation/interaction/DragInteraction$Start;)V
+PLandroidx/compose/foundation/interaction/MutableInteractionSourceImpl;->emit(Landroidx/compose/foundation/interaction/Interaction;Lkotlin/coroutines/Continuation;)Ljava/lang/Object;
+PLandroidx/compose/foundation/interaction/PressInteraction$Cancel;-><clinit>()V
+PLandroidx/compose/foundation/interaction/PressInteraction$Cancel;-><init>(Landroidx/compose/foundation/interaction/PressInteraction$Press;)V
+PLandroidx/compose/foundation/interaction/PressInteraction$Cancel;->getPress()Landroidx/compose/foundation/interaction/PressInteraction$Press;
+PLandroidx/compose/foundation/interaction/PressInteraction$Press;->getPressPosition-F1C5BW0()J
+PLandroidx/compose/foundation/interaction/PressInteraction$Release;-><clinit>()V
+PLandroidx/compose/foundation/interaction/PressInteraction$Release;-><init>(Landroidx/compose/foundation/interaction/PressInteraction$Press;)V
+PLandroidx/compose/foundation/interaction/PressInteraction$Release;->getPress()Landroidx/compose/foundation/interaction/PressInteraction$Press;
+PLandroidx/compose/foundation/layout/AndroidWindowInsets;-><init>(ILjava/lang/String;)V
+PLandroidx/compose/foundation/layout/AndroidWindowInsets;->getInsets$foundation_layout_release()Landroidx/core/graphics/Insets;
+PLandroidx/compose/foundation/layout/AndroidWindowInsets;->getLeft(Landroidx/compose/ui/unit/Density;Landroidx/compose/ui/unit/LayoutDirection;)I
+PLandroidx/compose/foundation/layout/AndroidWindowInsets;->getRight(Landroidx/compose/ui/unit/Density;Landroidx/compose/ui/unit/LayoutDirection;)I
+PLandroidx/compose/foundation/layout/AndroidWindowInsets;->getTop(Landroidx/compose/ui/unit/Density;)I
+PLandroidx/compose/foundation/layout/Arrangement$End$1;->arrange(Landroidx/compose/ui/unit/Density;I[ILandroidx/compose/ui/unit/LayoutDirection;[I)V
+PLandroidx/compose/foundation/layout/Arrangement$SpacedAligned;-><init>(FZLkotlin/jvm/functions/Function2;)V
+PLandroidx/compose/foundation/layout/Arrangement$SpacedAligned;-><init>(FZLkotlin/jvm/functions/Function2;Lkotlin/jvm/internal/DefaultConstructorMarker;)V
+PLandroidx/compose/foundation/layout/Arrangement$SpacedAligned;->arrange(Landroidx/compose/ui/unit/Density;I[ILandroidx/compose/ui/unit/LayoutDirection;[I)V
+PLandroidx/compose/foundation/layout/Arrangement$SpacedAligned;->arrange(Landroidx/compose/ui/unit/Density;I[I[I)V
+PLandroidx/compose/foundation/layout/Arrangement$SpacedAligned;->equals(Ljava/lang/Object;)Z
+PLandroidx/compose/foundation/layout/Arrangement$SpacedAligned;->getSpacing-D9Ej5fM()F
+PLandroidx/compose/foundation/layout/Arrangement$spacedBy$1;-><clinit>()V
+PLandroidx/compose/foundation/layout/Arrangement$spacedBy$1;-><init>()V
+PLandroidx/compose/foundation/layout/Arrangement;->getEnd()Landroidx/compose/foundation/layout/Arrangement$Horizontal;
+PLandroidx/compose/foundation/layout/Arrangement;->placeRightOrBottom$foundation_layout_release(I[I[IZ)V
+PLandroidx/compose/foundation/layout/Arrangement;->spacedBy-0680j_4(F)Landroidx/compose/foundation/layout/Arrangement$HorizontalOrVertical;
+PLandroidx/compose/foundation/layout/ColumnKt$columnMeasurePolicy$1$1;-><init>(Landroidx/compose/foundation/layout/Arrangement$Vertical;)V
+PLandroidx/compose/foundation/layout/ColumnKt$columnMeasurePolicy$1$1;->invoke(I[ILandroidx/compose/ui/unit/LayoutDirection;Landroidx/compose/ui/unit/Density;[I)V
+PLandroidx/compose/foundation/layout/ColumnKt$columnMeasurePolicy$1$1;->invoke(Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;
+PLandroidx/compose/foundation/layout/ExcludeInsets;-><init>(Landroidx/compose/foundation/layout/WindowInsets;Landroidx/compose/foundation/layout/WindowInsets;)V
+PLandroidx/compose/foundation/layout/ExcludeInsets;->equals(Ljava/lang/Object;)Z
+PLandroidx/compose/foundation/layout/ExcludeInsets;->getBottom(Landroidx/compose/ui/unit/Density;)I
+PLandroidx/compose/foundation/layout/ExcludeInsets;->getLeft(Landroidx/compose/ui/unit/Density;Landroidx/compose/ui/unit/LayoutDirection;)I
+PLandroidx/compose/foundation/layout/ExcludeInsets;->getRight(Landroidx/compose/ui/unit/Density;Landroidx/compose/ui/unit/LayoutDirection;)I
+PLandroidx/compose/foundation/layout/ExcludeInsets;->getTop(Landroidx/compose/ui/unit/Density;)I
+PLandroidx/compose/foundation/layout/FixedIntInsets;-><init>(IIII)V
+PLandroidx/compose/foundation/layout/FixedIntInsets;->equals(Ljava/lang/Object;)Z
+PLandroidx/compose/foundation/layout/FixedIntInsets;->getBottom(Landroidx/compose/ui/unit/Density;)I
+PLandroidx/compose/foundation/layout/FixedIntInsets;->getLeft(Landroidx/compose/ui/unit/Density;Landroidx/compose/ui/unit/LayoutDirection;)I
+PLandroidx/compose/foundation/layout/FixedIntInsets;->getRight(Landroidx/compose/ui/unit/Density;Landroidx/compose/ui/unit/LayoutDirection;)I
+PLandroidx/compose/foundation/layout/FixedIntInsets;->getTop(Landroidx/compose/ui/unit/Density;)I
+PLandroidx/compose/foundation/layout/InsetsListener;-><init>(Landroidx/compose/foundation/layout/WindowInsetsHolder;)V
+PLandroidx/compose/foundation/layout/InsetsPaddingModifier$measure$1;-><init>(Landroidx/compose/ui/layout/Placeable;II)V
+PLandroidx/compose/foundation/layout/InsetsPaddingModifier$measure$1;->invoke(Landroidx/compose/ui/layout/Placeable$PlacementScope;)V
+PLandroidx/compose/foundation/layout/InsetsPaddingModifier$measure$1;->invoke(Ljava/lang/Object;)Ljava/lang/Object;
+PLandroidx/compose/foundation/layout/InsetsPaddingModifier;-><init>(Landroidx/compose/foundation/layout/WindowInsets;Lkotlin/jvm/functions/Function1;)V
+PLandroidx/compose/foundation/layout/InsetsPaddingModifier;->getKey()Landroidx/compose/ui/modifier/ProvidableModifierLocal;
+PLandroidx/compose/foundation/layout/InsetsPaddingModifier;->getUnconsumedInsets()Landroidx/compose/foundation/layout/WindowInsets;
+PLandroidx/compose/foundation/layout/InsetsPaddingModifier;->measure-3p2s80s(Landroidx/compose/ui/layout/MeasureScope;Landroidx/compose/ui/layout/Measurable;J)Landroidx/compose/ui/layout/MeasureResult;
+PLandroidx/compose/foundation/layout/InsetsPaddingModifier;->onModifierLocalsUpdated(Landroidx/compose/ui/modifier/ModifierLocalReadScope;)V
+PLandroidx/compose/foundation/layout/InsetsPaddingModifier;->setConsumedInsets(Landroidx/compose/foundation/layout/WindowInsets;)V
+PLandroidx/compose/foundation/layout/InsetsPaddingModifier;->setUnconsumedInsets(Landroidx/compose/foundation/layout/WindowInsets;)V
+PLandroidx/compose/foundation/layout/InsetsValues;-><init>(IIII)V
+PLandroidx/compose/foundation/layout/LimitInsets;-><init>(Landroidx/compose/foundation/layout/WindowInsets;I)V
+PLandroidx/compose/foundation/layout/LimitInsets;-><init>(Landroidx/compose/foundation/layout/WindowInsets;ILkotlin/jvm/internal/DefaultConstructorMarker;)V
+PLandroidx/compose/foundation/layout/LimitInsets;->equals(Ljava/lang/Object;)Z
+PLandroidx/compose/foundation/layout/LimitInsets;->getBottom(Landroidx/compose/ui/unit/Density;)I
+PLandroidx/compose/foundation/layout/LimitInsets;->getLeft(Landroidx/compose/ui/unit/Density;Landroidx/compose/ui/unit/LayoutDirection;)I
+PLandroidx/compose/foundation/layout/LimitInsets;->getRight(Landroidx/compose/ui/unit/Density;Landroidx/compose/ui/unit/LayoutDirection;)I
+PLandroidx/compose/foundation/layout/LimitInsets;->getTop(Landroidx/compose/ui/unit/Density;)I
+PLandroidx/compose/foundation/layout/PaddingKt;->PaddingValues-0680j_4(F)Landroidx/compose/foundation/layout/PaddingValues;
+PLandroidx/compose/foundation/layout/SizeKt$createWrapContentHeightModifier$1;->invoke(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;
+PLandroidx/compose/foundation/layout/SizeKt$createWrapContentHeightModifier$1;->invoke-5SAbXVA(JLandroidx/compose/ui/unit/LayoutDirection;)J
+PLandroidx/compose/foundation/layout/SizeKt;->wrapContentHeight$default(Landroidx/compose/ui/Modifier;Landroidx/compose/ui/Alignment$Vertical;ZILjava/lang/Object;)Landroidx/compose/ui/Modifier;
+PLandroidx/compose/foundation/layout/SizeKt;->wrapContentHeight(Landroidx/compose/ui/Modifier;Landroidx/compose/ui/Alignment$Vertical;Z)Landroidx/compose/ui/Modifier;
+PLandroidx/compose/foundation/layout/UnionInsets;-><init>(Landroidx/compose/foundation/layout/WindowInsets;Landroidx/compose/foundation/layout/WindowInsets;)V
+PLandroidx/compose/foundation/layout/UnionInsets;->equals(Ljava/lang/Object;)Z
+PLandroidx/compose/foundation/layout/ValueInsets;-><init>(Landroidx/compose/foundation/layout/InsetsValues;Ljava/lang/String;)V
+PLandroidx/compose/foundation/layout/WindowInsets$Companion;-><clinit>()V
+PLandroidx/compose/foundation/layout/WindowInsets$Companion;-><init>()V
+PLandroidx/compose/foundation/layout/WindowInsets;-><clinit>()V
+PLandroidx/compose/foundation/layout/WindowInsetsHolder$Companion$current$1$invoke$$inlined$onDispose$1;-><init>(Landroidx/compose/foundation/layout/WindowInsetsHolder;Landroid/view/View;)V
+PLandroidx/compose/foundation/layout/WindowInsetsHolder$Companion$current$1$invoke$$inlined$onDispose$1;->dispose()V
+PLandroidx/compose/foundation/layout/WindowInsetsHolder$Companion$current$1;-><init>(Landroidx/compose/foundation/layout/WindowInsetsHolder;Landroid/view/View;)V
+PLandroidx/compose/foundation/layout/WindowInsetsHolder$Companion$current$1;->invoke(Landroidx/compose/runtime/DisposableEffectScope;)Landroidx/compose/runtime/DisposableEffectResult;
+PLandroidx/compose/foundation/layout/WindowInsetsHolder$Companion$current$1;->invoke(Ljava/lang/Object;)Ljava/lang/Object;
+PLandroidx/compose/foundation/layout/WindowInsetsHolder$Companion;-><init>()V
+PLandroidx/compose/foundation/layout/WindowInsetsHolder$Companion;-><init>(Lkotlin/jvm/internal/DefaultConstructorMarker;)V
+PLandroidx/compose/foundation/layout/WindowInsetsHolder$Companion;->access$systemInsets(Landroidx/compose/foundation/layout/WindowInsetsHolder$Companion;Landroidx/core/view/WindowInsetsCompat;ILjava/lang/String;)Landroidx/compose/foundation/layout/AndroidWindowInsets;
+PLandroidx/compose/foundation/layout/WindowInsetsHolder$Companion;->access$valueInsetsIgnoringVisibility(Landroidx/compose/foundation/layout/WindowInsetsHolder$Companion;Landroidx/core/view/WindowInsetsCompat;ILjava/lang/String;)Landroidx/compose/foundation/layout/ValueInsets;
+PLandroidx/compose/foundation/layout/WindowInsetsHolder$Companion;->current(Landroidx/compose/runtime/Composer;I)Landroidx/compose/foundation/layout/WindowInsetsHolder;
+PLandroidx/compose/foundation/layout/WindowInsetsHolder$Companion;->getOrCreateFor(Landroid/view/View;)Landroidx/compose/foundation/layout/WindowInsetsHolder;
+PLandroidx/compose/foundation/layout/WindowInsetsHolder$Companion;->systemInsets(Landroidx/core/view/WindowInsetsCompat;ILjava/lang/String;)Landroidx/compose/foundation/layout/AndroidWindowInsets;
+PLandroidx/compose/foundation/layout/WindowInsetsHolder$Companion;->valueInsetsIgnoringVisibility(Landroidx/core/view/WindowInsetsCompat;ILjava/lang/String;)Landroidx/compose/foundation/layout/ValueInsets;
+PLandroidx/compose/foundation/layout/WindowInsetsHolder;-><clinit>()V
+PLandroidx/compose/foundation/layout/WindowInsetsHolder;-><init>(Landroidx/core/view/WindowInsetsCompat;Landroid/view/View;)V
+PLandroidx/compose/foundation/layout/WindowInsetsHolder;-><init>(Landroidx/core/view/WindowInsetsCompat;Landroid/view/View;Lkotlin/jvm/internal/DefaultConstructorMarker;)V
+PLandroidx/compose/foundation/layout/WindowInsetsHolder;->access$getViewMap$cp()Ljava/util/WeakHashMap;
+PLandroidx/compose/foundation/layout/WindowInsetsHolder;->decrementAccessors(Landroid/view/View;)V
+PLandroidx/compose/foundation/layout/WindowInsetsHolder;->getConsumes()Z
+PLandroidx/compose/foundation/layout/WindowInsetsHolder;->getSystemBars()Landroidx/compose/foundation/layout/AndroidWindowInsets;
+PLandroidx/compose/foundation/layout/WindowInsetsHolder;->incrementAccessors(Landroid/view/View;)V
+PLandroidx/compose/foundation/layout/WindowInsetsKt;->WindowInsets(IIII)Landroidx/compose/foundation/layout/WindowInsets;
+PLandroidx/compose/foundation/layout/WindowInsetsKt;->exclude(Landroidx/compose/foundation/layout/WindowInsets;Landroidx/compose/foundation/layout/WindowInsets;)Landroidx/compose/foundation/layout/WindowInsets;
+PLandroidx/compose/foundation/layout/WindowInsetsKt;->only-bOOhFvg(Landroidx/compose/foundation/layout/WindowInsets;I)Landroidx/compose/foundation/layout/WindowInsets;
+PLandroidx/compose/foundation/layout/WindowInsetsKt;->union(Landroidx/compose/foundation/layout/WindowInsets;Landroidx/compose/foundation/layout/WindowInsets;)Landroidx/compose/foundation/layout/WindowInsets;
+PLandroidx/compose/foundation/layout/WindowInsetsPaddingKt$ModifierLocalConsumedWindowInsets$1;-><clinit>()V
+PLandroidx/compose/foundation/layout/WindowInsetsPaddingKt$ModifierLocalConsumedWindowInsets$1;-><init>()V
+PLandroidx/compose/foundation/layout/WindowInsetsPaddingKt$ModifierLocalConsumedWindowInsets$1;->invoke()Landroidx/compose/foundation/layout/WindowInsets;
+PLandroidx/compose/foundation/layout/WindowInsetsPaddingKt$ModifierLocalConsumedWindowInsets$1;->invoke()Ljava/lang/Object;
+PLandroidx/compose/foundation/layout/WindowInsetsPaddingKt;-><clinit>()V
+PLandroidx/compose/foundation/layout/WindowInsetsPaddingKt;->getModifierLocalConsumedWindowInsets()Landroidx/compose/ui/modifier/ProvidableModifierLocal;
+PLandroidx/compose/foundation/layout/WindowInsetsPaddingKt;->windowInsetsPadding(Landroidx/compose/ui/Modifier;Landroidx/compose/foundation/layout/WindowInsets;)Landroidx/compose/ui/Modifier;
+PLandroidx/compose/foundation/layout/WindowInsetsSides$Companion;-><init>()V
+PLandroidx/compose/foundation/layout/WindowInsetsSides$Companion;-><init>(Lkotlin/jvm/internal/DefaultConstructorMarker;)V
+PLandroidx/compose/foundation/layout/WindowInsetsSides$Companion;->getAllowLeftInLtr-JoeWqyM$foundation_layout_release()I
+PLandroidx/compose/foundation/layout/WindowInsetsSides$Companion;->getAllowRightInLtr-JoeWqyM$foundation_layout_release()I
+PLandroidx/compose/foundation/layout/WindowInsetsSides$Companion;->getBottom-JoeWqyM()I
+PLandroidx/compose/foundation/layout/WindowInsetsSides$Companion;->getHorizontal-JoeWqyM()I
+PLandroidx/compose/foundation/layout/WindowInsetsSides$Companion;->getTop-JoeWqyM()I
+PLandroidx/compose/foundation/layout/WindowInsetsSides;-><clinit>()V
+PLandroidx/compose/foundation/layout/WindowInsetsSides;->access$getAllowLeftInLtr$cp()I
+PLandroidx/compose/foundation/layout/WindowInsetsSides;->access$getAllowRightInLtr$cp()I
+PLandroidx/compose/foundation/layout/WindowInsetsSides;->access$getBottom$cp()I
+PLandroidx/compose/foundation/layout/WindowInsetsSides;->access$getHorizontal$cp()I
+PLandroidx/compose/foundation/layout/WindowInsetsSides;->access$getTop$cp()I
+PLandroidx/compose/foundation/layout/WindowInsetsSides;->constructor-impl(I)I
+PLandroidx/compose/foundation/layout/WindowInsetsSides;->hasAny-bkgdKaI$foundation_layout_release(II)Z
+PLandroidx/compose/foundation/layout/WindowInsetsSides;->plus-gK_yJZ4(II)I
+PLandroidx/compose/foundation/layout/WindowInsets_androidKt;->ValueInsets(Landroidx/core/graphics/Insets;Ljava/lang/String;)Landroidx/compose/foundation/layout/ValueInsets;
+PLandroidx/compose/foundation/layout/WindowInsets_androidKt;->getSystemBars(Landroidx/compose/foundation/layout/WindowInsets$Companion;Landroidx/compose/runtime/Composer;I)Landroidx/compose/foundation/layout/WindowInsets;
+PLandroidx/compose/foundation/layout/WindowInsets_androidKt;->toInsetsValues(Landroidx/core/graphics/Insets;)Landroidx/compose/foundation/layout/InsetsValues;
+PLandroidx/compose/foundation/layout/WrapContentModifier$measure$1;-><init>(Landroidx/compose/foundation/layout/WrapContentModifier;ILandroidx/compose/ui/layout/Placeable;ILandroidx/compose/ui/layout/MeasureScope;)V
+PLandroidx/compose/foundation/layout/WrapContentModifier$measure$1;->invoke(Landroidx/compose/ui/layout/Placeable$PlacementScope;)V
+PLandroidx/compose/foundation/layout/WrapContentModifier$measure$1;->invoke(Ljava/lang/Object;)Ljava/lang/Object;
+PLandroidx/compose/foundation/layout/WrapContentModifier;->access$getAlignmentCallback$p(Landroidx/compose/foundation/layout/WrapContentModifier;)Lkotlin/jvm/functions/Function2;
+PLandroidx/compose/foundation/layout/WrapContentModifier;->measure-3p2s80s(Landroidx/compose/ui/layout/MeasureScope;Landroidx/compose/ui/layout/Measurable;J)Landroidx/compose/ui/layout/MeasureResult;
+PLandroidx/compose/foundation/lazy/AwaitFirstLayoutModifier$waitForFirstLayout$1;-><init>(Landroidx/compose/foundation/lazy/AwaitFirstLayoutModifier;Lkotlin/coroutines/Continuation;)V
+PLandroidx/compose/foundation/lazy/AwaitFirstLayoutModifier;-><init>()V
+PLandroidx/compose/foundation/lazy/AwaitFirstLayoutModifier;->onGloballyPositioned(Landroidx/compose/ui/layout/LayoutCoordinates;)V
+PLandroidx/compose/foundation/lazy/AwaitFirstLayoutModifier;->waitForFirstLayout(Lkotlin/coroutines/Continuation;)Ljava/lang/Object;
+PLandroidx/compose/foundation/lazy/DataIndex;-><init>(I)V
+PLandroidx/compose/foundation/lazy/DataIndex;->box-impl(I)Landroidx/compose/foundation/lazy/DataIndex;
+PLandroidx/compose/foundation/lazy/DataIndex;->constructor-impl(I)I
+PLandroidx/compose/foundation/lazy/DataIndex;->equals(Ljava/lang/Object;)Z
+PLandroidx/compose/foundation/lazy/DataIndex;->equals-impl(ILjava/lang/Object;)Z
+PLandroidx/compose/foundation/lazy/DataIndex;->equals-impl0(II)Z
+PLandroidx/compose/foundation/lazy/DataIndex;->unbox-impl()I
+PLandroidx/compose/foundation/lazy/EmptyLazyListLayoutInfo;-><clinit>()V
+PLandroidx/compose/foundation/lazy/EmptyLazyListLayoutInfo;-><init>()V
+PLandroidx/compose/foundation/lazy/LazyBeyondBoundsModifierKt;->lazyListBeyondBoundsModifier(Landroidx/compose/ui/Modifier;Landroidx/compose/foundation/lazy/LazyListState;Landroidx/compose/foundation/lazy/LazyListBeyondBoundsInfo;ZLandroidx/compose/foundation/gestures/Orientation;Landroidx/compose/runtime/Composer;I)Landroidx/compose/ui/Modifier;
+PLandroidx/compose/foundation/lazy/LazyDslKt;->LazyColumn(Landroidx/compose/ui/Modifier;Landroidx/compose/foundation/lazy/LazyListState;Landroidx/compose/foundation/layout/PaddingValues;ZLandroidx/compose/foundation/layout/Arrangement$Vertical;Landroidx/compose/ui/Alignment$Horizontal;Landroidx/compose/foundation/gestures/FlingBehavior;ZLkotlin/jvm/functions/Function1;Landroidx/compose/runtime/Composer;II)V
+PLandroidx/compose/foundation/lazy/LazyItemScopeImpl;-><init>()V
+PLandroidx/compose/foundation/lazy/LazyItemScopeImpl;->setMaxSize(II)V
+PLandroidx/compose/foundation/lazy/LazyListAnimateScrollScope;-><init>(Landroidx/compose/foundation/lazy/LazyListState;)V
+PLandroidx/compose/foundation/lazy/LazyListBeyondBoundsInfo;-><init>()V
+PLandroidx/compose/foundation/lazy/LazyListBeyondBoundsInfo;->hasIntervals()Z
+PLandroidx/compose/foundation/lazy/LazyListBeyondBoundsModifierLocal;-><init>(Landroidx/compose/foundation/lazy/LazyListState;Landroidx/compose/foundation/lazy/LazyListBeyondBoundsInfo;ZLandroidx/compose/ui/unit/LayoutDirection;Landroidx/compose/foundation/gestures/Orientation;)V
+PLandroidx/compose/foundation/lazy/LazyListBeyondBoundsModifierLocal;->getKey()Landroidx/compose/ui/modifier/ProvidableModifierLocal;
+PLandroidx/compose/foundation/lazy/LazyListBeyondBoundsModifierLocal;->getValue()Landroidx/compose/ui/layout/BeyondBoundsLayout;
+PLandroidx/compose/foundation/lazy/LazyListBeyondBoundsModifierLocal;->getValue()Ljava/lang/Object;
+PLandroidx/compose/foundation/lazy/LazyListIntervalContent;-><init>(Lkotlin/jvm/functions/Function1;Lkotlin/jvm/functions/Function1;Lkotlin/jvm/functions/Function4;)V
+PLandroidx/compose/foundation/lazy/LazyListIntervalContent;->getItem()Lkotlin/jvm/functions/Function4;
+PLandroidx/compose/foundation/lazy/LazyListIntervalContent;->getKey()Lkotlin/jvm/functions/Function1;
+PLandroidx/compose/foundation/lazy/LazyListIntervalContent;->getType()Lkotlin/jvm/functions/Function1;
+PLandroidx/compose/foundation/lazy/LazyListItemPlacementAnimator;-><init>(Lkotlinx/coroutines/CoroutineScope;Z)V
+PLandroidx/compose/foundation/lazy/LazyListItemPlacementAnimator;->onMeasured(IIILjava/util/List;Landroidx/compose/foundation/lazy/LazyMeasuredItemProvider;)V
+PLandroidx/compose/foundation/lazy/LazyListItemPlacementAnimator;->reset()V
+PLandroidx/compose/foundation/lazy/LazyListItemProviderImpl$1;-><init>(Landroidx/compose/foundation/lazy/LazyItemScopeImpl;)V
+PLandroidx/compose/foundation/lazy/LazyListItemProviderImpl$1;->invoke(Landroidx/compose/foundation/lazy/LazyListIntervalContent;ILandroidx/compose/runtime/Composer;I)V
+PLandroidx/compose/foundation/lazy/LazyListItemProviderImpl$1;->invoke(Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;
+PLandroidx/compose/foundation/lazy/LazyListItemProviderImpl;-><init>(Landroidx/compose/foundation/lazy/layout/IntervalList;Lkotlin/ranges/IntRange;Ljava/util/List;Landroidx/compose/foundation/lazy/LazyItemScopeImpl;)V
+PLandroidx/compose/foundation/lazy/LazyListItemProviderImpl;->Item(ILandroidx/compose/runtime/Composer;I)V
+PLandroidx/compose/foundation/lazy/LazyListItemProviderImpl;->getContentType(I)Ljava/lang/Object;
+PLandroidx/compose/foundation/lazy/LazyListItemProviderImpl;->getHeaderIndexes()Ljava/util/List;
+PLandroidx/compose/foundation/lazy/LazyListItemProviderImpl;->getItemCount()I
+PLandroidx/compose/foundation/lazy/LazyListItemProviderImpl;->getItemScope()Landroidx/compose/foundation/lazy/LazyItemScopeImpl;
+PLandroidx/compose/foundation/lazy/LazyListItemProviderImpl;->getKey(I)Ljava/lang/Object;
+PLandroidx/compose/foundation/lazy/LazyListItemProviderImpl;->getKeyToIndexMap()Ljava/util/Map;
+PLandroidx/compose/foundation/lazy/LazyListItemProviderKt$rememberLazyListItemProvider$1$1;-><init>(Landroidx/compose/runtime/State;)V
+PLandroidx/compose/foundation/lazy/LazyListItemProviderKt$rememberLazyListItemProvider$1$1;->Item(ILandroidx/compose/runtime/Composer;I)V
+PLandroidx/compose/foundation/lazy/LazyListItemProviderKt$rememberLazyListItemProvider$1$1;->getContentType(I)Ljava/lang/Object;
+PLandroidx/compose/foundation/lazy/LazyListItemProviderKt$rememberLazyListItemProvider$1$1;->getHeaderIndexes()Ljava/util/List;
+PLandroidx/compose/foundation/lazy/LazyListItemProviderKt$rememberLazyListItemProvider$1$1;->getItemCount()I
+PLandroidx/compose/foundation/lazy/LazyListItemProviderKt$rememberLazyListItemProvider$1$1;->getItemScope()Landroidx/compose/foundation/lazy/LazyItemScopeImpl;
+PLandroidx/compose/foundation/lazy/LazyListItemProviderKt$rememberLazyListItemProvider$1$1;->getKey(I)Ljava/lang/Object;
+PLandroidx/compose/foundation/lazy/LazyListItemProviderKt$rememberLazyListItemProvider$1$1;->getKeyToIndexMap()Ljava/util/Map;
+PLandroidx/compose/foundation/lazy/LazyListItemProviderKt$rememberLazyListItemProvider$1$itemProviderState$1;-><init>(Landroidx/compose/runtime/State;Landroidx/compose/runtime/State;Landroidx/compose/foundation/lazy/LazyItemScopeImpl;)V
+PLandroidx/compose/foundation/lazy/LazyListItemProviderKt$rememberLazyListItemProvider$1$itemProviderState$1;->invoke()Landroidx/compose/foundation/lazy/LazyListItemProviderImpl;
+PLandroidx/compose/foundation/lazy/LazyListItemProviderKt$rememberLazyListItemProvider$1$itemProviderState$1;->invoke()Ljava/lang/Object;
+PLandroidx/compose/foundation/lazy/LazyListItemProviderKt$rememberLazyListItemProvider$nearestItemsRangeState$1$1;-><init>(Landroidx/compose/foundation/lazy/LazyListState;)V
+PLandroidx/compose/foundation/lazy/LazyListItemProviderKt$rememberLazyListItemProvider$nearestItemsRangeState$1$1;->invoke()Ljava/lang/Integer;
+PLandroidx/compose/foundation/lazy/LazyListItemProviderKt$rememberLazyListItemProvider$nearestItemsRangeState$1$1;->invoke()Ljava/lang/Object;
+PLandroidx/compose/foundation/lazy/LazyListItemProviderKt$rememberLazyListItemProvider$nearestItemsRangeState$2;-><clinit>()V
+PLandroidx/compose/foundation/lazy/LazyListItemProviderKt$rememberLazyListItemProvider$nearestItemsRangeState$2;-><init>()V
+PLandroidx/compose/foundation/lazy/LazyListItemProviderKt$rememberLazyListItemProvider$nearestItemsRangeState$2;->invoke()Ljava/lang/Integer;
+PLandroidx/compose/foundation/lazy/LazyListItemProviderKt$rememberLazyListItemProvider$nearestItemsRangeState$2;->invoke()Ljava/lang/Object;
+PLandroidx/compose/foundation/lazy/LazyListItemProviderKt$rememberLazyListItemProvider$nearestItemsRangeState$3;-><clinit>()V
+PLandroidx/compose/foundation/lazy/LazyListItemProviderKt$rememberLazyListItemProvider$nearestItemsRangeState$3;-><init>()V
+PLandroidx/compose/foundation/lazy/LazyListItemProviderKt$rememberLazyListItemProvider$nearestItemsRangeState$3;->invoke()Ljava/lang/Integer;
+PLandroidx/compose/foundation/lazy/LazyListItemProviderKt$rememberLazyListItemProvider$nearestItemsRangeState$3;->invoke()Ljava/lang/Object;
+PLandroidx/compose/foundation/lazy/LazyListItemProviderKt;->rememberLazyListItemProvider(Landroidx/compose/foundation/lazy/LazyListState;Lkotlin/jvm/functions/Function1;Landroidx/compose/runtime/Composer;I)Landroidx/compose/foundation/lazy/LazyListItemProvider;
+PLandroidx/compose/foundation/lazy/LazyListKt$ScrollPositionUpdater$1;-><init>(Landroidx/compose/foundation/lazy/LazyListItemProvider;Landroidx/compose/foundation/lazy/LazyListState;I)V
+PLandroidx/compose/foundation/lazy/LazyListKt$rememberLazyListMeasurePolicy$1$1$2;-><init>(Landroidx/compose/foundation/lazy/layout/LazyLayoutMeasureScope;JII)V
+PLandroidx/compose/foundation/lazy/LazyListKt$rememberLazyListMeasurePolicy$1$1$2;->invoke(IILkotlin/jvm/functions/Function1;)Landroidx/compose/ui/layout/MeasureResult;
+PLandroidx/compose/foundation/lazy/LazyListKt$rememberLazyListMeasurePolicy$1$1$2;->invoke(Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;
+PLandroidx/compose/foundation/lazy/LazyListKt$rememberLazyListMeasurePolicy$1$1$measuredItemProvider$1;-><init>(IILandroidx/compose/foundation/lazy/layout/LazyLayoutMeasureScope;ZLandroidx/compose/ui/Alignment$Horizontal;Landroidx/compose/ui/Alignment$Vertical;ZIILandroidx/compose/foundation/lazy/LazyListItemPlacementAnimator;J)V
+PLandroidx/compose/foundation/lazy/LazyListKt$rememberLazyListMeasurePolicy$1$1;-><init>(ZLandroidx/compose/foundation/layout/PaddingValues;ZLandroidx/compose/foundation/lazy/LazyListState;Landroidx/compose/foundation/lazy/LazyListItemProvider;Landroidx/compose/foundation/layout/Arrangement$Vertical;Landroidx/compose/foundation/layout/Arrangement$Horizontal;Landroidx/compose/foundation/lazy/LazyListItemPlacementAnimator;Landroidx/compose/foundation/lazy/LazyListBeyondBoundsInfo;ILandroidx/compose/ui/Alignment$Horizontal;Landroidx/compose/ui/Alignment$Vertical;)V
+PLandroidx/compose/foundation/lazy/LazyListKt$rememberLazyListMeasurePolicy$1$1;->invoke(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;
+PLandroidx/compose/foundation/lazy/LazyListKt;->LazyList(Landroidx/compose/ui/Modifier;Landroidx/compose/foundation/lazy/LazyListState;Landroidx/compose/foundation/layout/PaddingValues;ZZLandroidx/compose/foundation/gestures/FlingBehavior;ZILandroidx/compose/ui/Alignment$Horizontal;Landroidx/compose/foundation/layout/Arrangement$Vertical;Landroidx/compose/ui/Alignment$Vertical;Landroidx/compose/foundation/layout/Arrangement$Horizontal;Lkotlin/jvm/functions/Function1;Landroidx/compose/runtime/Composer;III)V
+PLandroidx/compose/foundation/lazy/LazyListKt;->ScrollPositionUpdater(Landroidx/compose/foundation/lazy/LazyListItemProvider;Landroidx/compose/foundation/lazy/LazyListState;Landroidx/compose/runtime/Composer;I)V
+PLandroidx/compose/foundation/lazy/LazyListKt;->rememberLazyListMeasurePolicy(Landroidx/compose/foundation/lazy/LazyListItemProvider;Landroidx/compose/foundation/lazy/LazyListState;Landroidx/compose/foundation/lazy/LazyListBeyondBoundsInfo;Landroidx/compose/foundation/layout/PaddingValues;ZZILandroidx/compose/ui/Alignment$Horizontal;Landroidx/compose/ui/Alignment$Vertical;Landroidx/compose/foundation/layout/Arrangement$Horizontal;Landroidx/compose/foundation/layout/Arrangement$Vertical;Landroidx/compose/foundation/lazy/LazyListItemPlacementAnimator;Landroidx/compose/runtime/Composer;III)Lkotlin/jvm/functions/Function2;
+PLandroidx/compose/foundation/lazy/LazyListMeasureKt$measureLazyList$5;-><init>(Ljava/util/List;Landroidx/compose/foundation/lazy/LazyListPositionedItem;)V
+PLandroidx/compose/foundation/lazy/LazyListMeasureKt$measureLazyList$5;->invoke(Landroidx/compose/ui/layout/Placeable$PlacementScope;)V
+PLandroidx/compose/foundation/lazy/LazyListMeasureKt$measureLazyList$5;->invoke(Ljava/lang/Object;)Ljava/lang/Object;
+PLandroidx/compose/foundation/lazy/LazyListMeasureKt;-><clinit>()V
+PLandroidx/compose/foundation/lazy/LazyListMeasureKt;->calculateItemsOffsets(Ljava/util/List;Ljava/util/List;Ljava/util/List;IIIIIZLandroidx/compose/foundation/layout/Arrangement$Vertical;Landroidx/compose/foundation/layout/Arrangement$Horizontal;ZLandroidx/compose/ui/unit/Density;)Ljava/util/List;
+PLandroidx/compose/foundation/lazy/LazyListMeasureKt;->createItemsAfterList(Landroidx/compose/foundation/lazy/LazyListBeyondBoundsInfo;Ljava/util/List;Landroidx/compose/foundation/lazy/LazyMeasuredItemProvider;II)Ljava/util/List;
+PLandroidx/compose/foundation/lazy/LazyListMeasureKt;->createItemsBeforeList-aZfr-iw(Landroidx/compose/foundation/lazy/LazyListBeyondBoundsInfo;ILandroidx/compose/foundation/lazy/LazyMeasuredItemProvider;II)Ljava/util/List;
+PLandroidx/compose/foundation/lazy/LazyListMeasureKt;->getNotInEmptyRange(I)Z
+PLandroidx/compose/foundation/lazy/LazyListMeasureResult;-><init>(Landroidx/compose/foundation/lazy/LazyMeasuredItem;IZFLandroidx/compose/ui/layout/MeasureResult;Ljava/util/List;IIIZLandroidx/compose/foundation/gestures/Orientation;I)V
+PLandroidx/compose/foundation/lazy/LazyListMeasureResult;->getAlignmentLines()Ljava/util/Map;
+PLandroidx/compose/foundation/lazy/LazyListMeasureResult;->getCanScrollForward()Z
+PLandroidx/compose/foundation/lazy/LazyListMeasureResult;->getConsumedScroll()F
+PLandroidx/compose/foundation/lazy/LazyListMeasureResult;->getFirstVisibleItem()Landroidx/compose/foundation/lazy/LazyMeasuredItem;
+PLandroidx/compose/foundation/lazy/LazyListMeasureResult;->getFirstVisibleItemScrollOffset()I
+PLandroidx/compose/foundation/lazy/LazyListMeasureResult;->getHeight()I
+PLandroidx/compose/foundation/lazy/LazyListMeasureResult;->getTotalItemsCount()I
+PLandroidx/compose/foundation/lazy/LazyListMeasureResult;->getVisibleItemsInfo()Ljava/util/List;
+PLandroidx/compose/foundation/lazy/LazyListMeasureResult;->getWidth()I
+PLandroidx/compose/foundation/lazy/LazyListMeasureResult;->placeChildren()V
+PLandroidx/compose/foundation/lazy/LazyListPinningModifier$Companion$EmptyPinnedItemsHandle$1;-><init>()V
+PLandroidx/compose/foundation/lazy/LazyListPinningModifier$Companion;-><init>()V
+PLandroidx/compose/foundation/lazy/LazyListPinningModifier$Companion;-><init>(Lkotlin/jvm/internal/DefaultConstructorMarker;)V
+PLandroidx/compose/foundation/lazy/LazyListPinningModifier;-><clinit>()V
+PLandroidx/compose/foundation/lazy/LazyListPinningModifier;-><init>(Landroidx/compose/foundation/lazy/LazyListState;Landroidx/compose/foundation/lazy/LazyListBeyondBoundsInfo;)V
+PLandroidx/compose/foundation/lazy/LazyListPinningModifier;->getKey()Landroidx/compose/ui/modifier/ProvidableModifierLocal;
+PLandroidx/compose/foundation/lazy/LazyListPinningModifier;->getValue()Landroidx/compose/foundation/lazy/layout/PinnableParent;
+PLandroidx/compose/foundation/lazy/LazyListPinningModifier;->getValue()Ljava/lang/Object;
+PLandroidx/compose/foundation/lazy/LazyListPinningModifier;->onModifierLocalsUpdated(Landroidx/compose/ui/modifier/ModifierLocalReadScope;)V
+PLandroidx/compose/foundation/lazy/LazyListPinningModifierKt;->lazyListPinningModifier(Landroidx/compose/ui/Modifier;Landroidx/compose/foundation/lazy/LazyListState;Landroidx/compose/foundation/lazy/LazyListBeyondBoundsInfo;Landroidx/compose/runtime/Composer;I)Landroidx/compose/ui/Modifier;
+PLandroidx/compose/foundation/lazy/LazyListPlaceableWrapper;-><init>(JLandroidx/compose/ui/layout/Placeable;)V
+PLandroidx/compose/foundation/lazy/LazyListPlaceableWrapper;-><init>(JLandroidx/compose/ui/layout/Placeable;Lkotlin/jvm/internal/DefaultConstructorMarker;)V
+PLandroidx/compose/foundation/lazy/LazyListPlaceableWrapper;->getOffset-nOcc-ac()J
+PLandroidx/compose/foundation/lazy/LazyListPlaceableWrapper;->getPlaceable()Landroidx/compose/ui/layout/Placeable;
+PLandroidx/compose/foundation/lazy/LazyListPositionedItem;-><init>(IILjava/lang/Object;IIIZLjava/util/List;Landroidx/compose/foundation/lazy/LazyListItemPlacementAnimator;JZI)V
+PLandroidx/compose/foundation/lazy/LazyListPositionedItem;-><init>(IILjava/lang/Object;IIIZLjava/util/List;Landroidx/compose/foundation/lazy/LazyListItemPlacementAnimator;JZILkotlin/jvm/internal/DefaultConstructorMarker;)V
+PLandroidx/compose/foundation/lazy/LazyListPositionedItem;->getAnimationSpec(I)Landroidx/compose/animation/core/FiniteAnimationSpec;
+PLandroidx/compose/foundation/lazy/LazyListPositionedItem;->getHasAnimations()Z
+PLandroidx/compose/foundation/lazy/LazyListPositionedItem;->getIndex()I
+PLandroidx/compose/foundation/lazy/LazyListPositionedItem;->getMainAxisSize(Landroidx/compose/ui/layout/Placeable;)I
+PLandroidx/compose/foundation/lazy/LazyListPositionedItem;->getOffset-Bjo55l4(I)J
+PLandroidx/compose/foundation/lazy/LazyListPositionedItem;->getPlaceablesCount()I
+PLandroidx/compose/foundation/lazy/LazyListScope;->item$default(Landroidx/compose/foundation/lazy/LazyListScope;Ljava/lang/Object;Ljava/lang/Object;Lkotlin/jvm/functions/Function3;ILjava/lang/Object;)V
+PLandroidx/compose/foundation/lazy/LazyListScopeImpl$item$2;-><init>(Ljava/lang/Object;)V
+PLandroidx/compose/foundation/lazy/LazyListScopeImpl$item$2;->invoke(I)Ljava/lang/Object;
+PLandroidx/compose/foundation/lazy/LazyListScopeImpl$item$2;->invoke(Ljava/lang/Object;)Ljava/lang/Object;
+PLandroidx/compose/foundation/lazy/LazyListScopeImpl$item$3;-><init>(Lkotlin/jvm/functions/Function3;)V
+PLandroidx/compose/foundation/lazy/LazyListScopeImpl$item$3;->invoke(Landroidx/compose/foundation/lazy/LazyItemScope;ILandroidx/compose/runtime/Composer;I)V
+PLandroidx/compose/foundation/lazy/LazyListScopeImpl$item$3;->invoke(Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;
+PLandroidx/compose/foundation/lazy/LazyListScopeImpl;-><init>()V
+PLandroidx/compose/foundation/lazy/LazyListScopeImpl;->getHeaderIndexes()Ljava/util/List;
+PLandroidx/compose/foundation/lazy/LazyListScopeImpl;->getIntervals()Landroidx/compose/foundation/lazy/layout/IntervalList;
+PLandroidx/compose/foundation/lazy/LazyListScopeImpl;->item(Ljava/lang/Object;Ljava/lang/Object;Lkotlin/jvm/functions/Function3;)V
+PLandroidx/compose/foundation/lazy/LazyListScopeImpl;->items(ILkotlin/jvm/functions/Function1;Lkotlin/jvm/functions/Function1;Lkotlin/jvm/functions/Function4;)V
+PLandroidx/compose/foundation/lazy/LazyListScrollPosition;-><init>(II)V
+PLandroidx/compose/foundation/lazy/LazyListScrollPosition;->getIndex-jQJCoq8()I
+PLandroidx/compose/foundation/lazy/LazyListScrollPosition;->getScrollOffset()I
+PLandroidx/compose/foundation/lazy/LazyListScrollPosition;->setIndex-ZjPyQlc(I)V
+PLandroidx/compose/foundation/lazy/LazyListScrollPosition;->setScrollOffset(I)V
+PLandroidx/compose/foundation/lazy/LazyListScrollPosition;->update-AhXoVpI(II)V
+PLandroidx/compose/foundation/lazy/LazyListScrollPosition;->updateFromMeasureResult(Landroidx/compose/foundation/lazy/LazyListMeasureResult;)V
+PLandroidx/compose/foundation/lazy/LazyListScrollPosition;->updateScrollPositionIfTheFirstItemWasMoved(Landroidx/compose/foundation/lazy/LazyListItemProvider;)V
+PLandroidx/compose/foundation/lazy/LazyListState$Companion$Saver$1;-><clinit>()V
+PLandroidx/compose/foundation/lazy/LazyListState$Companion$Saver$1;-><init>()V
+PLandroidx/compose/foundation/lazy/LazyListState$Companion$Saver$1;->invoke(Landroidx/compose/runtime/saveable/SaverScope;Landroidx/compose/foundation/lazy/LazyListState;)Ljava/util/List;
+PLandroidx/compose/foundation/lazy/LazyListState$Companion$Saver$1;->invoke(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;
+PLandroidx/compose/foundation/lazy/LazyListState$Companion$Saver$2;-><clinit>()V
+PLandroidx/compose/foundation/lazy/LazyListState$Companion$Saver$2;-><init>()V
+PLandroidx/compose/foundation/lazy/LazyListState$Companion;-><init>()V
+PLandroidx/compose/foundation/lazy/LazyListState$Companion;-><init>(Lkotlin/jvm/internal/DefaultConstructorMarker;)V
+PLandroidx/compose/foundation/lazy/LazyListState$Companion;->getSaver()Landroidx/compose/runtime/saveable/Saver;
+PLandroidx/compose/foundation/lazy/LazyListState$remeasurementModifier$1;-><init>(Landroidx/compose/foundation/lazy/LazyListState;)V
+PLandroidx/compose/foundation/lazy/LazyListState$remeasurementModifier$1;->onRemeasurementAvailable(Landroidx/compose/ui/layout/Remeasurement;)V
+PLandroidx/compose/foundation/lazy/LazyListState$scroll$1;-><init>(Landroidx/compose/foundation/lazy/LazyListState;Lkotlin/coroutines/Continuation;)V
+PLandroidx/compose/foundation/lazy/LazyListState$scroll$1;->invokeSuspend(Ljava/lang/Object;)Ljava/lang/Object;
+PLandroidx/compose/foundation/lazy/LazyListState$scrollableState$1;-><init>(Landroidx/compose/foundation/lazy/LazyListState;)V
+PLandroidx/compose/foundation/lazy/LazyListState$scrollableState$1;->invoke(F)Ljava/lang/Float;
+PLandroidx/compose/foundation/lazy/LazyListState$scrollableState$1;->invoke(Ljava/lang/Object;)Ljava/lang/Object;
+PLandroidx/compose/foundation/lazy/LazyListState;-><clinit>()V
+PLandroidx/compose/foundation/lazy/LazyListState;-><init>(II)V
+PLandroidx/compose/foundation/lazy/LazyListState;->access$getSaver$cp()Landroidx/compose/runtime/saveable/Saver;
+PLandroidx/compose/foundation/lazy/LazyListState;->access$setRemeasurement(Landroidx/compose/foundation/lazy/LazyListState;Landroidx/compose/ui/layout/Remeasurement;)V
+PLandroidx/compose/foundation/lazy/LazyListState;->applyMeasureResult$foundation_release(Landroidx/compose/foundation/lazy/LazyListMeasureResult;)V
+PLandroidx/compose/foundation/lazy/LazyListState;->cancelPrefetchIfVisibleItemsChanged(Landroidx/compose/foundation/lazy/LazyListLayoutInfo;)V
+PLandroidx/compose/foundation/lazy/LazyListState;->getAwaitLayoutModifier$foundation_release()Landroidx/compose/foundation/lazy/AwaitFirstLayoutModifier;
+PLandroidx/compose/foundation/lazy/LazyListState;->getCanScrollBackward()Z
+PLandroidx/compose/foundation/lazy/LazyListState;->getCanScrollForward()Z
+PLandroidx/compose/foundation/lazy/LazyListState;->getFirstVisibleItemIndex()I
+PLandroidx/compose/foundation/lazy/LazyListState;->getFirstVisibleItemScrollOffset()I
+PLandroidx/compose/foundation/lazy/LazyListState;->getInternalInteractionSource$foundation_release()Landroidx/compose/foundation/interaction/MutableInteractionSource;
+PLandroidx/compose/foundation/lazy/LazyListState;->getLayoutInfo()Landroidx/compose/foundation/lazy/LazyListLayoutInfo;
+PLandroidx/compose/foundation/lazy/LazyListState;->getPrefetchState$foundation_release()Landroidx/compose/foundation/lazy/layout/LazyLayoutPrefetchState;
+PLandroidx/compose/foundation/lazy/LazyListState;->getPremeasureConstraints-msEJaDk$foundation_release()J
+PLandroidx/compose/foundation/lazy/LazyListState;->getRemeasurement$foundation_release()Landroidx/compose/ui/layout/Remeasurement;
+PLandroidx/compose/foundation/lazy/LazyListState;->getRemeasurementModifier$foundation_release()Landroidx/compose/ui/layout/RemeasurementModifier;
+PLandroidx/compose/foundation/lazy/LazyListState;->getScrollToBeConsumed$foundation_release()F
+PLandroidx/compose/foundation/lazy/LazyListState;->isScrollInProgress()Z
+PLandroidx/compose/foundation/lazy/LazyListState;->notifyPrefetch(F)V
+PLandroidx/compose/foundation/lazy/LazyListState;->onScroll$foundation_release(F)F
+PLandroidx/compose/foundation/lazy/LazyListState;->scroll(Landroidx/compose/foundation/MutatePriority;Lkotlin/jvm/functions/Function2;Lkotlin/coroutines/Continuation;)Ljava/lang/Object;
+PLandroidx/compose/foundation/lazy/LazyListState;->setCanScrollBackward(Z)V
+PLandroidx/compose/foundation/lazy/LazyListState;->setCanScrollForward(Z)V
+PLandroidx/compose/foundation/lazy/LazyListState;->setDensity$foundation_release(Landroidx/compose/ui/unit/Density;)V
+PLandroidx/compose/foundation/lazy/LazyListState;->setPlacementAnimator$foundation_release(Landroidx/compose/foundation/lazy/LazyListItemPlacementAnimator;)V
+PLandroidx/compose/foundation/lazy/LazyListState;->setPremeasureConstraints-BRTryo0$foundation_release(J)V
+PLandroidx/compose/foundation/lazy/LazyListState;->setRemeasurement(Landroidx/compose/ui/layout/Remeasurement;)V
+PLandroidx/compose/foundation/lazy/LazyListState;->updateScrollPositionIfTheFirstItemWasMoved$foundation_release(Landroidx/compose/foundation/lazy/LazyListItemProvider;)V
+PLandroidx/compose/foundation/lazy/LazyListStateKt$rememberLazyListState$1$1;-><init>(II)V
+PLandroidx/compose/foundation/lazy/LazyListStateKt$rememberLazyListState$1$1;->invoke()Landroidx/compose/foundation/lazy/LazyListState;
+PLandroidx/compose/foundation/lazy/LazyListStateKt$rememberLazyListState$1$1;->invoke()Ljava/lang/Object;
+PLandroidx/compose/foundation/lazy/LazyListStateKt;->rememberLazyListState(IILandroidx/compose/runtime/Composer;II)Landroidx/compose/foundation/lazy/LazyListState;
+PLandroidx/compose/foundation/lazy/LazyMeasuredItem;-><init>(ILjava/util/List;ZLandroidx/compose/ui/Alignment$Horizontal;Landroidx/compose/ui/Alignment$Vertical;Landroidx/compose/ui/unit/LayoutDirection;ZIILandroidx/compose/foundation/lazy/LazyListItemPlacementAnimator;IJLjava/lang/Object;Lkotlin/jvm/internal/DefaultConstructorMarker;)V
+PLandroidx/compose/foundation/lazy/LazyMeasuredItem;->getCrossAxisSize()I
+PLandroidx/compose/foundation/lazy/LazyMeasuredItem;->getIndex()I
+PLandroidx/compose/foundation/lazy/LazyMeasuredItem;->getKey()Ljava/lang/Object;
+PLandroidx/compose/foundation/lazy/LazyMeasuredItem;->getSizeWithSpacings()I
+PLandroidx/compose/foundation/lazy/LazyMeasuredItem;->position(III)Landroidx/compose/foundation/lazy/LazyListPositionedItem;
+PLandroidx/compose/foundation/lazy/LazyMeasuredItemProvider;-><init>(JZLandroidx/compose/foundation/lazy/LazyListItemProvider;Landroidx/compose/foundation/lazy/layout/LazyLayoutMeasureScope;Landroidx/compose/foundation/lazy/MeasuredItemFactory;)V
+PLandroidx/compose/foundation/lazy/LazyMeasuredItemProvider;-><init>(JZLandroidx/compose/foundation/lazy/LazyListItemProvider;Landroidx/compose/foundation/lazy/layout/LazyLayoutMeasureScope;Landroidx/compose/foundation/lazy/MeasuredItemFactory;Lkotlin/jvm/internal/DefaultConstructorMarker;)V
+PLandroidx/compose/foundation/lazy/LazyMeasuredItemProvider;->getAndMeasure-ZjPyQlc(I)Landroidx/compose/foundation/lazy/LazyMeasuredItem;
+PLandroidx/compose/foundation/lazy/LazyMeasuredItemProvider;->getChildConstraints-msEJaDk()J
+PLandroidx/compose/foundation/lazy/LazySemanticsKt$rememberLazyListSemanticState$1$1$scrollAxisRange$1;-><init>(Landroidx/compose/foundation/lazy/LazyListState;)V
+PLandroidx/compose/foundation/lazy/LazySemanticsKt$rememberLazyListSemanticState$1$1$scrollAxisRange$2;-><init>(Landroidx/compose/foundation/lazy/LazyListState;Landroidx/compose/foundation/lazy/layout/LazyLayoutItemProvider;)V
+PLandroidx/compose/foundation/lazy/LazySemanticsKt$rememberLazyListSemanticState$1$1;-><init>(ZLandroidx/compose/foundation/lazy/LazyListState;Landroidx/compose/foundation/lazy/layout/LazyLayoutItemProvider;Z)V
+PLandroidx/compose/foundation/lazy/LazySemanticsKt$rememberLazyListSemanticState$1$1;->collectionInfo()Landroidx/compose/ui/semantics/CollectionInfo;
+PLandroidx/compose/foundation/lazy/LazySemanticsKt$rememberLazyListSemanticState$1$1;->scrollAxisRange()Landroidx/compose/ui/semantics/ScrollAxisRange;
+PLandroidx/compose/foundation/lazy/LazySemanticsKt;->rememberLazyListSemanticState(Landroidx/compose/foundation/lazy/LazyListState;Landroidx/compose/foundation/lazy/layout/LazyLayoutItemProvider;ZZLandroidx/compose/runtime/Composer;I)Landroidx/compose/foundation/lazy/layout/LazyLayoutSemanticState;
+PLandroidx/compose/foundation/lazy/layout/DefaultDelegatingLazyLayoutItemProvider$Item$1;-><init>(Landroidx/compose/foundation/lazy/layout/DefaultDelegatingLazyLayoutItemProvider;II)V
+PLandroidx/compose/foundation/lazy/layout/DefaultDelegatingLazyLayoutItemProvider;-><init>(Landroidx/compose/runtime/State;)V
+PLandroidx/compose/foundation/lazy/layout/DefaultDelegatingLazyLayoutItemProvider;->Item(ILandroidx/compose/runtime/Composer;I)V
+PLandroidx/compose/foundation/lazy/layout/DefaultDelegatingLazyLayoutItemProvider;->getContentType(I)Ljava/lang/Object;
+PLandroidx/compose/foundation/lazy/layout/DefaultDelegatingLazyLayoutItemProvider;->getItemCount()I
+PLandroidx/compose/foundation/lazy/layout/DefaultDelegatingLazyLayoutItemProvider;->getKey(I)Ljava/lang/Object;
+PLandroidx/compose/foundation/lazy/layout/DefaultDelegatingLazyLayoutItemProvider;->getKeyToIndexMap()Ljava/util/Map;
+PLandroidx/compose/foundation/lazy/layout/DefaultLazyKey$Companion$CREATOR$1;-><init>()V
+PLandroidx/compose/foundation/lazy/layout/DefaultLazyKey$Companion;-><init>()V
+PLandroidx/compose/foundation/lazy/layout/DefaultLazyKey$Companion;-><init>(Lkotlin/jvm/internal/DefaultConstructorMarker;)V
+PLandroidx/compose/foundation/lazy/layout/DefaultLazyKey;-><clinit>()V
+PLandroidx/compose/foundation/lazy/layout/DefaultLazyKey;-><init>(I)V
+PLandroidx/compose/foundation/lazy/layout/DefaultLazyKey;->equals(Ljava/lang/Object;)Z
+PLandroidx/compose/foundation/lazy/layout/DefaultLazyKey;->hashCode()I
+PLandroidx/compose/foundation/lazy/layout/DefaultLazyLayoutItemsProvider$generateKeyToIndexMap$1$1;-><init>(IILjava/util/HashMap;)V
+PLandroidx/compose/foundation/lazy/layout/DefaultLazyLayoutItemsProvider$generateKeyToIndexMap$1$1;->invoke(Landroidx/compose/foundation/lazy/layout/IntervalList$Interval;)V
+PLandroidx/compose/foundation/lazy/layout/DefaultLazyLayoutItemsProvider$generateKeyToIndexMap$1$1;->invoke(Ljava/lang/Object;)Ljava/lang/Object;
+PLandroidx/compose/foundation/lazy/layout/DefaultLazyLayoutItemsProvider;-><init>(Lkotlin/jvm/functions/Function4;Landroidx/compose/foundation/lazy/layout/IntervalList;Lkotlin/ranges/IntRange;)V
+PLandroidx/compose/foundation/lazy/layout/DefaultLazyLayoutItemsProvider;->Item(ILandroidx/compose/runtime/Composer;I)V
+PLandroidx/compose/foundation/lazy/layout/DefaultLazyLayoutItemsProvider;->generateKeyToIndexMap(Lkotlin/ranges/IntRange;Landroidx/compose/foundation/lazy/layout/IntervalList;)Ljava/util/Map;
+PLandroidx/compose/foundation/lazy/layout/DefaultLazyLayoutItemsProvider;->getContentType(I)Ljava/lang/Object;
+PLandroidx/compose/foundation/lazy/layout/DefaultLazyLayoutItemsProvider;->getItemCount()I
+PLandroidx/compose/foundation/lazy/layout/DefaultLazyLayoutItemsProvider;->getKeyToIndexMap()Ljava/util/Map;
+PLandroidx/compose/foundation/lazy/layout/IntervalList$Interval;-><clinit>()V
+PLandroidx/compose/foundation/lazy/layout/IntervalList$Interval;-><init>(IILjava/lang/Object;)V
+PLandroidx/compose/foundation/lazy/layout/IntervalList$Interval;->getSize()I
+PLandroidx/compose/foundation/lazy/layout/IntervalList$Interval;->getStartIndex()I
+PLandroidx/compose/foundation/lazy/layout/IntervalList$Interval;->getValue()Ljava/lang/Object;
+PLandroidx/compose/foundation/lazy/layout/IntervalListKt;->access$binarySearch(Landroidx/compose/runtime/collection/MutableVector;I)I
+PLandroidx/compose/foundation/lazy/layout/IntervalListKt;->binarySearch(Landroidx/compose/runtime/collection/MutableVector;I)I
+PLandroidx/compose/foundation/lazy/layout/LazyLayoutItemContentFactory$CachedItemContent$createContentLambda$1$1;-><init>(Landroidx/compose/foundation/lazy/layout/LazyLayoutItemProvider;I)V
+PLandroidx/compose/foundation/lazy/layout/LazyLayoutItemContentFactory$CachedItemContent$createContentLambda$1$1;->invoke(Landroidx/compose/runtime/Composer;I)V
+PLandroidx/compose/foundation/lazy/layout/LazyLayoutItemContentFactory$CachedItemContent$createContentLambda$1$1;->invoke(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;
+PLandroidx/compose/foundation/lazy/layout/LazyLayoutItemContentFactory$CachedItemContent$createContentLambda$1$2$invoke$$inlined$onDispose$1;-><init>(Landroidx/compose/foundation/lazy/layout/LazyLayoutItemContentFactory$CachedItemContent;)V
+PLandroidx/compose/foundation/lazy/layout/LazyLayoutItemContentFactory$CachedItemContent$createContentLambda$1$2$invoke$$inlined$onDispose$1;->dispose()V
+PLandroidx/compose/foundation/lazy/layout/LazyLayoutItemContentFactory$CachedItemContent$createContentLambda$1$2;-><init>(Landroidx/compose/foundation/lazy/layout/LazyLayoutItemContentFactory$CachedItemContent;)V
+PLandroidx/compose/foundation/lazy/layout/LazyLayoutItemContentFactory$CachedItemContent$createContentLambda$1$2;->invoke(Landroidx/compose/runtime/DisposableEffectScope;)Landroidx/compose/runtime/DisposableEffectResult;
+PLandroidx/compose/foundation/lazy/layout/LazyLayoutItemContentFactory$CachedItemContent$createContentLambda$1$2;->invoke(Ljava/lang/Object;)Ljava/lang/Object;
+PLandroidx/compose/foundation/lazy/layout/LazyLayoutItemContentFactory$CachedItemContent$createContentLambda$1;-><init>(Landroidx/compose/foundation/lazy/layout/LazyLayoutItemContentFactory;Landroidx/compose/foundation/lazy/layout/LazyLayoutItemContentFactory$CachedItemContent;)V
+PLandroidx/compose/foundation/lazy/layout/LazyLayoutItemContentFactory$CachedItemContent$createContentLambda$1;->invoke(Landroidx/compose/runtime/Composer;I)V
+PLandroidx/compose/foundation/lazy/layout/LazyLayoutItemContentFactory$CachedItemContent$createContentLambda$1;->invoke(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;
+PLandroidx/compose/foundation/lazy/layout/LazyLayoutItemContentFactory$CachedItemContent;-><init>(Landroidx/compose/foundation/lazy/layout/LazyLayoutItemContentFactory;ILjava/lang/Object;Ljava/lang/Object;)V
+PLandroidx/compose/foundation/lazy/layout/LazyLayoutItemContentFactory$CachedItemContent;->access$set_content$p(Landroidx/compose/foundation/lazy/layout/LazyLayoutItemContentFactory$CachedItemContent;Lkotlin/jvm/functions/Function2;)V
+PLandroidx/compose/foundation/lazy/layout/LazyLayoutItemContentFactory$CachedItemContent;->createContentLambda()Lkotlin/jvm/functions/Function2;
+PLandroidx/compose/foundation/lazy/layout/LazyLayoutItemContentFactory$CachedItemContent;->getContent()Lkotlin/jvm/functions/Function2;
+PLandroidx/compose/foundation/lazy/layout/LazyLayoutItemContentFactory$CachedItemContent;->getKey()Ljava/lang/Object;
+PLandroidx/compose/foundation/lazy/layout/LazyLayoutItemContentFactory$CachedItemContent;->getLastKnownIndex()I
+PLandroidx/compose/foundation/lazy/layout/LazyLayoutItemContentFactory$CachedItemContent;->getType()Ljava/lang/Object;
+PLandroidx/compose/foundation/lazy/layout/LazyLayoutItemContentFactory;-><init>(Landroidx/compose/runtime/saveable/SaveableStateHolder;Lkotlin/jvm/functions/Function0;)V
+PLandroidx/compose/foundation/lazy/layout/LazyLayoutItemContentFactory;->access$getSaveableStateHolder$p(Landroidx/compose/foundation/lazy/layout/LazyLayoutItemContentFactory;)Landroidx/compose/runtime/saveable/SaveableStateHolder;
+PLandroidx/compose/foundation/lazy/layout/LazyLayoutItemContentFactory;->getContentType(Ljava/lang/Object;)Ljava/lang/Object;
+PLandroidx/compose/foundation/lazy/layout/LazyLayoutItemContentFactory;->getItemProvider()Lkotlin/jvm/functions/Function0;
+PLandroidx/compose/foundation/lazy/layout/LazyLayoutItemProviderKt;->DelegatingLazyLayoutItemProvider(Landroidx/compose/runtime/State;)Landroidx/compose/foundation/lazy/layout/LazyLayoutItemProvider;
+PLandroidx/compose/foundation/lazy/layout/LazyLayoutItemProviderKt;->LazyLayoutItemProvider(Landroidx/compose/foundation/lazy/layout/IntervalList;Lkotlin/ranges/IntRange;Lkotlin/jvm/functions/Function4;)Landroidx/compose/foundation/lazy/layout/LazyLayoutItemProvider;
+PLandroidx/compose/foundation/lazy/layout/LazyLayoutItemProviderKt;->findIndexByKey(Landroidx/compose/foundation/lazy/layout/LazyLayoutItemProvider;Ljava/lang/Object;I)I
+PLandroidx/compose/foundation/lazy/layout/LazyLayoutItemReusePolicy;-><init>(Landroidx/compose/foundation/lazy/layout/LazyLayoutItemContentFactory;)V
+PLandroidx/compose/foundation/lazy/layout/LazyLayoutItemReusePolicy;->areCompatible(Ljava/lang/Object;Ljava/lang/Object;)Z
+PLandroidx/compose/foundation/lazy/layout/LazyLayoutItemReusePolicy;->getSlotsToRetain(Landroidx/compose/ui/layout/SubcomposeSlotReusePolicy$SlotIdsSet;)V
+PLandroidx/compose/foundation/lazy/layout/LazyLayoutKt$LazyLayout$1$2$1;-><init>(Landroidx/compose/foundation/lazy/layout/LazyLayoutItemContentFactory;Lkotlin/jvm/functions/Function2;)V
+PLandroidx/compose/foundation/lazy/layout/LazyLayoutKt$LazyLayout$1$2$1;->invoke(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;
+PLandroidx/compose/foundation/lazy/layout/LazyLayoutKt$LazyLayout$1$2$1;->invoke-0kLqBqw(Landroidx/compose/ui/layout/SubcomposeMeasureScope;J)Landroidx/compose/ui/layout/MeasureResult;
+PLandroidx/compose/foundation/lazy/layout/LazyLayoutKt$LazyLayout$1$itemContentFactory$1$1;-><init>(Landroidx/compose/runtime/State;)V
+PLandroidx/compose/foundation/lazy/layout/LazyLayoutKt$LazyLayout$1$itemContentFactory$1$1;->invoke()Landroidx/compose/foundation/lazy/layout/LazyLayoutItemProvider;
+PLandroidx/compose/foundation/lazy/layout/LazyLayoutKt$LazyLayout$1$itemContentFactory$1$1;->invoke()Ljava/lang/Object;
+PLandroidx/compose/foundation/lazy/layout/LazyLayoutKt$LazyLayout$1;-><init>(Landroidx/compose/foundation/lazy/layout/LazyLayoutPrefetchState;Landroidx/compose/ui/Modifier;Lkotlin/jvm/functions/Function2;ILandroidx/compose/runtime/State;)V
+PLandroidx/compose/foundation/lazy/layout/LazyLayoutKt$LazyLayout$1;->invoke(Landroidx/compose/runtime/saveable/SaveableStateHolder;Landroidx/compose/runtime/Composer;I)V
+PLandroidx/compose/foundation/lazy/layout/LazyLayoutKt$LazyLayout$1;->invoke(Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;
+PLandroidx/compose/foundation/lazy/layout/LazyLayoutKt;->LazyLayout(Landroidx/compose/foundation/lazy/layout/LazyLayoutItemProvider;Landroidx/compose/ui/Modifier;Landroidx/compose/foundation/lazy/layout/LazyLayoutPrefetchState;Lkotlin/jvm/functions/Function2;Landroidx/compose/runtime/Composer;II)V
+PLandroidx/compose/foundation/lazy/layout/LazyLayoutMeasureScopeImpl;-><init>(Landroidx/compose/foundation/lazy/layout/LazyLayoutItemContentFactory;Landroidx/compose/ui/layout/SubcomposeMeasureScope;)V
+PLandroidx/compose/foundation/lazy/layout/LazyLayoutMeasureScopeImpl;->getLayoutDirection()Landroidx/compose/ui/unit/LayoutDirection;
+PLandroidx/compose/foundation/lazy/layout/LazyLayoutMeasureScopeImpl;->layout(IILjava/util/Map;Lkotlin/jvm/functions/Function1;)Landroidx/compose/ui/layout/MeasureResult;
+PLandroidx/compose/foundation/lazy/layout/LazyLayoutMeasureScopeImpl;->roundToPx-0680j_4(F)I
+PLandroidx/compose/foundation/lazy/layout/LazyLayoutPrefetchState;-><init>()V
+PLandroidx/compose/foundation/lazy/layout/LazyLayoutPrefetchState;->getPrefetcher$foundation_release()Landroidx/compose/foundation/lazy/layout/LazyLayoutPrefetchState$Prefetcher;
+PLandroidx/compose/foundation/lazy/layout/LazyLayoutPrefetchState;->schedulePrefetch-0kLqBqw(IJ)Landroidx/compose/foundation/lazy/layout/LazyLayoutPrefetchState$PrefetchHandle;
+PLandroidx/compose/foundation/lazy/layout/LazyLayoutPrefetchState;->setPrefetcher$foundation_release(Landroidx/compose/foundation/lazy/layout/LazyLayoutPrefetchState$Prefetcher;)V
+PLandroidx/compose/foundation/lazy/layout/LazyLayoutPrefetcher$Companion;-><init>()V
+PLandroidx/compose/foundation/lazy/layout/LazyLayoutPrefetcher$Companion;-><init>(Lkotlin/jvm/internal/DefaultConstructorMarker;)V
+PLandroidx/compose/foundation/lazy/layout/LazyLayoutPrefetcher$Companion;->access$calculateFrameIntervalIfNeeded(Landroidx/compose/foundation/lazy/layout/LazyLayoutPrefetcher$Companion;Landroid/view/View;)V
+PLandroidx/compose/foundation/lazy/layout/LazyLayoutPrefetcher$Companion;->calculateFrameIntervalIfNeeded(Landroid/view/View;)V
+PLandroidx/compose/foundation/lazy/layout/LazyLayoutPrefetcher$PrefetchRequest;-><init>(IJ)V
+PLandroidx/compose/foundation/lazy/layout/LazyLayoutPrefetcher$PrefetchRequest;-><init>(IJLkotlin/jvm/internal/DefaultConstructorMarker;)V
+PLandroidx/compose/foundation/lazy/layout/LazyLayoutPrefetcher$PrefetchRequest;->cancel()V
+PLandroidx/compose/foundation/lazy/layout/LazyLayoutPrefetcher$PrefetchRequest;->getCanceled()Z
+PLandroidx/compose/foundation/lazy/layout/LazyLayoutPrefetcher$PrefetchRequest;->getConstraints-msEJaDk()J
+PLandroidx/compose/foundation/lazy/layout/LazyLayoutPrefetcher$PrefetchRequest;->getIndex()I
+PLandroidx/compose/foundation/lazy/layout/LazyLayoutPrefetcher$PrefetchRequest;->getMeasured()Z
+PLandroidx/compose/foundation/lazy/layout/LazyLayoutPrefetcher$PrefetchRequest;->getPrecomposeHandle()Landroidx/compose/ui/layout/SubcomposeLayoutState$PrecomposedSlotHandle;
+PLandroidx/compose/foundation/lazy/layout/LazyLayoutPrefetcher$PrefetchRequest;->setPrecomposeHandle(Landroidx/compose/ui/layout/SubcomposeLayoutState$PrecomposedSlotHandle;)V
+PLandroidx/compose/foundation/lazy/layout/LazyLayoutPrefetcher;-><clinit>()V
+PLandroidx/compose/foundation/lazy/layout/LazyLayoutPrefetcher;-><init>(Landroidx/compose/foundation/lazy/layout/LazyLayoutPrefetchState;Landroidx/compose/ui/layout/SubcomposeLayoutState;Landroidx/compose/foundation/lazy/layout/LazyLayoutItemContentFactory;Landroid/view/View;)V
+PLandroidx/compose/foundation/lazy/layout/LazyLayoutPrefetcher;->access$getFrameIntervalNs$cp()J
+PLandroidx/compose/foundation/lazy/layout/LazyLayoutPrefetcher;->access$setFrameIntervalNs$cp(J)V
+PLandroidx/compose/foundation/lazy/layout/LazyLayoutPrefetcher;->calculateAverageTime(JJ)J
+PLandroidx/compose/foundation/lazy/layout/LazyLayoutPrefetcher;->doFrame(J)V
+PLandroidx/compose/foundation/lazy/layout/LazyLayoutPrefetcher;->enoughTimeLeft(JJJ)Z
+PLandroidx/compose/foundation/lazy/layout/LazyLayoutPrefetcher;->onForgotten()V
+PLandroidx/compose/foundation/lazy/layout/LazyLayoutPrefetcher;->onRemembered()V
+PLandroidx/compose/foundation/lazy/layout/LazyLayoutPrefetcher;->run()V
+PLandroidx/compose/foundation/lazy/layout/LazyLayoutPrefetcher;->schedulePrefetch-0kLqBqw(IJ)Landroidx/compose/foundation/lazy/layout/LazyLayoutPrefetchState$PrefetchHandle;
+PLandroidx/compose/foundation/lazy/layout/LazyLayoutPrefetcher_androidKt;->LazyLayoutPrefetcher(Landroidx/compose/foundation/lazy/layout/LazyLayoutPrefetchState;Landroidx/compose/foundation/lazy/layout/LazyLayoutItemContentFactory;Landroidx/compose/ui/layout/SubcomposeLayoutState;Landroidx/compose/runtime/Composer;I)V
+PLandroidx/compose/foundation/lazy/layout/LazyLayoutSemanticsKt$lazyLayoutSemantics$1$1;-><init>(Lkotlin/jvm/functions/Function1;ZLandroidx/compose/ui/semantics/ScrollAxisRange;Lkotlin/jvm/functions/Function2;Lkotlin/jvm/functions/Function1;Landroidx/compose/ui/semantics/CollectionInfo;)V
+PLandroidx/compose/foundation/lazy/layout/LazyLayoutSemanticsKt$lazyLayoutSemantics$1$1;->invoke(Landroidx/compose/ui/semantics/SemanticsPropertyReceiver;)V
+PLandroidx/compose/foundation/lazy/layout/LazyLayoutSemanticsKt$lazyLayoutSemantics$1$1;->invoke(Ljava/lang/Object;)Ljava/lang/Object;
+PLandroidx/compose/foundation/lazy/layout/LazyLayoutSemanticsKt$lazyLayoutSemantics$1$indexForKeyMapping$1;-><init>(Landroidx/compose/foundation/lazy/layout/LazyLayoutItemProvider;)V
+PLandroidx/compose/foundation/lazy/layout/LazyLayoutSemanticsKt$lazyLayoutSemantics$1$scrollByAction$1;-><init>(ZLkotlinx/coroutines/CoroutineScope;Landroidx/compose/foundation/lazy/layout/LazyLayoutSemanticState;)V
+PLandroidx/compose/foundation/lazy/layout/LazyLayoutSemanticsKt$lazyLayoutSemantics$1$scrollToIndexAction$1;-><init>(Landroidx/compose/foundation/lazy/layout/LazyLayoutItemProvider;Lkotlinx/coroutines/CoroutineScope;Landroidx/compose/foundation/lazy/layout/LazyLayoutSemanticState;)V
+PLandroidx/compose/foundation/lazy/layout/LazyLayoutSemanticsKt;->lazyLayoutSemantics(Landroidx/compose/ui/Modifier;Landroidx/compose/foundation/lazy/layout/LazyLayoutItemProvider;Landroidx/compose/foundation/lazy/layout/LazyLayoutSemanticState;Landroidx/compose/foundation/gestures/Orientation;ZLandroidx/compose/runtime/Composer;I)Landroidx/compose/ui/Modifier;
+PLandroidx/compose/foundation/lazy/layout/LazyNearestItemsRangeKt$rememberLazyNearestItemsRangeState$1$1$1;-><init>(Lkotlin/jvm/functions/Function0;Lkotlin/jvm/functions/Function0;Lkotlin/jvm/functions/Function0;)V
+PLandroidx/compose/foundation/lazy/layout/LazyNearestItemsRangeKt$rememberLazyNearestItemsRangeState$1$1$1;->invoke()Ljava/lang/Object;
+PLandroidx/compose/foundation/lazy/layout/LazyNearestItemsRangeKt$rememberLazyNearestItemsRangeState$1$1$1;->invoke()Lkotlin/ranges/IntRange;
+PLandroidx/compose/foundation/lazy/layout/LazyNearestItemsRangeKt$rememberLazyNearestItemsRangeState$1$1$2;-><init>(Landroidx/compose/runtime/MutableState;)V
+PLandroidx/compose/foundation/lazy/layout/LazyNearestItemsRangeKt$rememberLazyNearestItemsRangeState$1$1$2;->emit(Ljava/lang/Object;Lkotlin/coroutines/Continuation;)Ljava/lang/Object;
+PLandroidx/compose/foundation/lazy/layout/LazyNearestItemsRangeKt$rememberLazyNearestItemsRangeState$1$1$2;->emit(Lkotlin/ranges/IntRange;Lkotlin/coroutines/Continuation;)Ljava/lang/Object;
+PLandroidx/compose/foundation/lazy/layout/LazyNearestItemsRangeKt$rememberLazyNearestItemsRangeState$1$1;-><init>(Lkotlin/jvm/functions/Function0;Lkotlin/jvm/functions/Function0;Lkotlin/jvm/functions/Function0;Landroidx/compose/runtime/MutableState;Lkotlin/coroutines/Continuation;)V
+PLandroidx/compose/foundation/lazy/layout/LazyNearestItemsRangeKt$rememberLazyNearestItemsRangeState$1$1;->create(Ljava/lang/Object;Lkotlin/coroutines/Continuation;)Lkotlin/coroutines/Continuation;
+PLandroidx/compose/foundation/lazy/layout/LazyNearestItemsRangeKt$rememberLazyNearestItemsRangeState$1$1;->invokeSuspend(Ljava/lang/Object;)Ljava/lang/Object;
+PLandroidx/compose/foundation/lazy/layout/LazyNearestItemsRangeKt;->access$calculateNearestItemsRange(III)Lkotlin/ranges/IntRange;
+PLandroidx/compose/foundation/lazy/layout/LazyNearestItemsRangeKt;->calculateNearestItemsRange(III)Lkotlin/ranges/IntRange;
+PLandroidx/compose/foundation/lazy/layout/LazyNearestItemsRangeKt;->rememberLazyNearestItemsRangeState(Lkotlin/jvm/functions/Function0;Lkotlin/jvm/functions/Function0;Lkotlin/jvm/functions/Function0;Landroidx/compose/runtime/Composer;I)Landroidx/compose/runtime/State;
+PLandroidx/compose/foundation/lazy/layout/LazySaveableStateHolder$1;-><init>(Landroidx/compose/runtime/saveable/SaveableStateRegistry;)V
+PLandroidx/compose/foundation/lazy/layout/LazySaveableStateHolder$1;->invoke(Ljava/lang/Object;)Ljava/lang/Boolean;
+PLandroidx/compose/foundation/lazy/layout/LazySaveableStateHolder$1;->invoke(Ljava/lang/Object;)Ljava/lang/Object;
+PLandroidx/compose/foundation/lazy/layout/LazySaveableStateHolder$Companion$saver$1;-><clinit>()V
+PLandroidx/compose/foundation/lazy/layout/LazySaveableStateHolder$Companion$saver$1;-><init>()V
+PLandroidx/compose/foundation/lazy/layout/LazySaveableStateHolder$Companion$saver$1;->invoke(Landroidx/compose/runtime/saveable/SaverScope;Landroidx/compose/foundation/lazy/layout/LazySaveableStateHolder;)Ljava/util/Map;
+PLandroidx/compose/foundation/lazy/layout/LazySaveableStateHolder$Companion$saver$1;->invoke(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;
+PLandroidx/compose/foundation/lazy/layout/LazySaveableStateHolder$Companion$saver$2;-><init>(Landroidx/compose/runtime/saveable/SaveableStateRegistry;)V
+PLandroidx/compose/foundation/lazy/layout/LazySaveableStateHolder$Companion;-><init>()V
+PLandroidx/compose/foundation/lazy/layout/LazySaveableStateHolder$Companion;-><init>(Lkotlin/jvm/internal/DefaultConstructorMarker;)V
+PLandroidx/compose/foundation/lazy/layout/LazySaveableStateHolder$Companion;->saver(Landroidx/compose/runtime/saveable/SaveableStateRegistry;)Landroidx/compose/runtime/saveable/Saver;
+PLandroidx/compose/foundation/lazy/layout/LazySaveableStateHolder$SaveableStateProvider$1$invoke$$inlined$onDispose$1;-><init>(Landroidx/compose/foundation/lazy/layout/LazySaveableStateHolder;Ljava/lang/Object;)V
+PLandroidx/compose/foundation/lazy/layout/LazySaveableStateHolder$SaveableStateProvider$1$invoke$$inlined$onDispose$1;->dispose()V
+PLandroidx/compose/foundation/lazy/layout/LazySaveableStateHolder$SaveableStateProvider$1;-><init>(Landroidx/compose/foundation/lazy/layout/LazySaveableStateHolder;Ljava/lang/Object;)V
+PLandroidx/compose/foundation/lazy/layout/LazySaveableStateHolder$SaveableStateProvider$1;->invoke(Landroidx/compose/runtime/DisposableEffectScope;)Landroidx/compose/runtime/DisposableEffectResult;
+PLandroidx/compose/foundation/lazy/layout/LazySaveableStateHolder$SaveableStateProvider$1;->invoke(Ljava/lang/Object;)Ljava/lang/Object;
+PLandroidx/compose/foundation/lazy/layout/LazySaveableStateHolder$SaveableStateProvider$2;-><init>(Landroidx/compose/foundation/lazy/layout/LazySaveableStateHolder;Ljava/lang/Object;Lkotlin/jvm/functions/Function2;I)V
+PLandroidx/compose/foundation/lazy/layout/LazySaveableStateHolder;-><clinit>()V
+PLandroidx/compose/foundation/lazy/layout/LazySaveableStateHolder;-><init>(Landroidx/compose/runtime/saveable/SaveableStateRegistry;)V
+PLandroidx/compose/foundation/lazy/layout/LazySaveableStateHolder;-><init>(Landroidx/compose/runtime/saveable/SaveableStateRegistry;Ljava/util/Map;)V
+PLandroidx/compose/foundation/lazy/layout/LazySaveableStateHolder;->SaveableStateProvider(Ljava/lang/Object;Lkotlin/jvm/functions/Function2;Landroidx/compose/runtime/Composer;I)V
+PLandroidx/compose/foundation/lazy/layout/LazySaveableStateHolder;->access$getPreviouslyComposedKeys$p(Landroidx/compose/foundation/lazy/layout/LazySaveableStateHolder;)Ljava/util/Set;
+PLandroidx/compose/foundation/lazy/layout/LazySaveableStateHolder;->canBeSaved(Ljava/lang/Object;)Z
+PLandroidx/compose/foundation/lazy/layout/LazySaveableStateHolder;->consumeRestored(Ljava/lang/String;)Ljava/lang/Object;
+PLandroidx/compose/foundation/lazy/layout/LazySaveableStateHolder;->getWrappedHolder()Landroidx/compose/runtime/saveable/SaveableStateHolder;
+PLandroidx/compose/foundation/lazy/layout/LazySaveableStateHolder;->performSave()Ljava/util/Map;
+PLandroidx/compose/foundation/lazy/layout/LazySaveableStateHolder;->registerProvider(Ljava/lang/String;Lkotlin/jvm/functions/Function0;)Landroidx/compose/runtime/saveable/SaveableStateRegistry$Entry;
+PLandroidx/compose/foundation/lazy/layout/LazySaveableStateHolder;->setWrappedHolder(Landroidx/compose/runtime/saveable/SaveableStateHolder;)V
+PLandroidx/compose/foundation/lazy/layout/LazySaveableStateHolderKt$LazySaveableStateHolderProvider$1;-><init>(Landroidx/compose/foundation/lazy/layout/LazySaveableStateHolder;Lkotlin/jvm/functions/Function3;I)V
+PLandroidx/compose/foundation/lazy/layout/LazySaveableStateHolderKt$LazySaveableStateHolderProvider$1;->invoke(Landroidx/compose/runtime/Composer;I)V
+PLandroidx/compose/foundation/lazy/layout/LazySaveableStateHolderKt$LazySaveableStateHolderProvider$1;->invoke(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;
+PLandroidx/compose/foundation/lazy/layout/LazySaveableStateHolderKt$LazySaveableStateHolderProvider$holder$1;-><init>(Landroidx/compose/runtime/saveable/SaveableStateRegistry;)V
+PLandroidx/compose/foundation/lazy/layout/LazySaveableStateHolderKt$LazySaveableStateHolderProvider$holder$1;->invoke()Landroidx/compose/foundation/lazy/layout/LazySaveableStateHolder;
+PLandroidx/compose/foundation/lazy/layout/LazySaveableStateHolderKt$LazySaveableStateHolderProvider$holder$1;->invoke()Ljava/lang/Object;
+PLandroidx/compose/foundation/lazy/layout/LazySaveableStateHolderKt;->LazySaveableStateHolderProvider(Lkotlin/jvm/functions/Function3;Landroidx/compose/runtime/Composer;I)V
+PLandroidx/compose/foundation/lazy/layout/Lazy_androidKt;->getDefaultLazyLayoutKey(I)Ljava/lang/Object;
+PLandroidx/compose/foundation/lazy/layout/MutableIntervalList;-><clinit>()V
+PLandroidx/compose/foundation/lazy/layout/MutableIntervalList;-><init>()V
+PLandroidx/compose/foundation/lazy/layout/MutableIntervalList;->addInterval(ILjava/lang/Object;)V
+PLandroidx/compose/foundation/lazy/layout/MutableIntervalList;->checkIndexBounds(I)V
+PLandroidx/compose/foundation/lazy/layout/MutableIntervalList;->contains(Landroidx/compose/foundation/lazy/layout/IntervalList$Interval;I)Z
+PLandroidx/compose/foundation/lazy/layout/MutableIntervalList;->forEach(IILkotlin/jvm/functions/Function1;)V
+PLandroidx/compose/foundation/lazy/layout/MutableIntervalList;->get(I)Landroidx/compose/foundation/lazy/layout/IntervalList$Interval;
+PLandroidx/compose/foundation/lazy/layout/MutableIntervalList;->getIntervalForIndex(I)Landroidx/compose/foundation/lazy/layout/IntervalList$Interval;
+PLandroidx/compose/foundation/lazy/layout/MutableIntervalList;->getSize()I
+PLandroidx/compose/foundation/relocation/BringIntoViewRequesterKt$bringIntoViewRequester$2$1$invoke$$inlined$onDispose$1;->dispose()V
+PLandroidx/compose/foundation/relocation/BringIntoViewResponderKt$bringIntoViewResponder$2;-><init>(Landroidx/compose/foundation/relocation/BringIntoViewResponder;)V
+PLandroidx/compose/foundation/relocation/BringIntoViewResponderKt$bringIntoViewResponder$2;->invoke(Landroidx/compose/ui/Modifier;Landroidx/compose/runtime/Composer;I)Landroidx/compose/ui/Modifier;
+PLandroidx/compose/foundation/relocation/BringIntoViewResponderKt$bringIntoViewResponder$2;->invoke(Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;
+PLandroidx/compose/foundation/relocation/BringIntoViewResponderKt;->bringIntoViewResponder(Landroidx/compose/ui/Modifier;Landroidx/compose/foundation/relocation/BringIntoViewResponder;)Landroidx/compose/ui/Modifier;
+PLandroidx/compose/foundation/relocation/BringIntoViewResponderModifier;-><init>(Landroidx/compose/foundation/relocation/BringIntoViewParent;)V
+PLandroidx/compose/foundation/relocation/BringIntoViewResponderModifier;->getKey()Landroidx/compose/ui/modifier/ProvidableModifierLocal;
+PLandroidx/compose/foundation/relocation/BringIntoViewResponderModifier;->getValue()Landroidx/compose/foundation/relocation/BringIntoViewParent;
+PLandroidx/compose/foundation/relocation/BringIntoViewResponderModifier;->getValue()Ljava/lang/Object;
+PLandroidx/compose/foundation/relocation/BringIntoViewResponderModifier;->setResponder(Landroidx/compose/foundation/relocation/BringIntoViewResponder;)V
+PLandroidx/compose/foundation/text/TextController;->onForgotten()V
+PLandroidx/compose/foundation/text/TextState;->getSelectable()Landroidx/compose/foundation/text/selection/Selectable;
+PLandroidx/compose/material/icons/Icons$Filled;-><clinit>()V
+PLandroidx/compose/material/icons/Icons$Filled;-><init>()V
+PLandroidx/compose/material/icons/Icons$Outlined;-><clinit>()V
+PLandroidx/compose/material/icons/Icons$Outlined;-><init>()V
+PLandroidx/compose/material/icons/filled/AddKt;-><clinit>()V
+PLandroidx/compose/material/icons/filled/AddKt;->getAdd(Landroidx/compose/material/icons/Icons$Filled;)Landroidx/compose/ui/graphics/vector/ImageVector;
+PLandroidx/compose/material/icons/filled/ArrowBackKt;-><clinit>()V
+PLandroidx/compose/material/icons/filled/ArrowBackKt;->getArrowBack(Landroidx/compose/material/icons/Icons$Filled;)Landroidx/compose/ui/graphics/vector/ImageVector;
+PLandroidx/compose/material/icons/outlined/NewReleasesKt;-><clinit>()V
+PLandroidx/compose/material/icons/outlined/NewReleasesKt;->getNewReleases(Landroidx/compose/material/icons/Icons$Outlined;)Landroidx/compose/ui/graphics/vector/ImageVector;
+PLandroidx/compose/material/ripple/AndroidRippleIndicationInstance$onInvalidateRipple$1;->invoke()Ljava/lang/Object;
+PLandroidx/compose/material/ripple/AndroidRippleIndicationInstance$onInvalidateRipple$1;->invoke()V
+PLandroidx/compose/material/ripple/AndroidRippleIndicationInstance;->access$getInvalidateTick(Landroidx/compose/material/ripple/AndroidRippleIndicationInstance;)Z
+PLandroidx/compose/material/ripple/AndroidRippleIndicationInstance;->access$setInvalidateTick(Landroidx/compose/material/ripple/AndroidRippleIndicationInstance;Z)V
+PLandroidx/compose/material/ripple/AndroidRippleIndicationInstance;->addRipple(Landroidx/compose/foundation/interaction/PressInteraction$Press;Lkotlinx/coroutines/CoroutineScope;)V
+PLandroidx/compose/material/ripple/AndroidRippleIndicationInstance;->dispose()V
+PLandroidx/compose/material/ripple/AndroidRippleIndicationInstance;->onForgotten()V
+PLandroidx/compose/material/ripple/AndroidRippleIndicationInstance;->removeRipple(Landroidx/compose/foundation/interaction/PressInteraction$Press;)V
+PLandroidx/compose/material/ripple/AndroidRippleIndicationInstance;->resetHostView()V
+PLandroidx/compose/material/ripple/AndroidRippleIndicationInstance;->setInvalidateTick(Z)V
+PLandroidx/compose/material/ripple/AndroidRippleIndicationInstance;->setRippleHostView(Landroidx/compose/material/ripple/RippleHostView;)V
+PLandroidx/compose/material/ripple/Ripple$rememberUpdatedInstance$1$1;->emit(Landroidx/compose/foundation/interaction/Interaction;Lkotlin/coroutines/Continuation;)Ljava/lang/Object;
+PLandroidx/compose/material/ripple/Ripple$rememberUpdatedInstance$1$1;->emit(Ljava/lang/Object;Lkotlin/coroutines/Continuation;)Ljava/lang/Object;
+PLandroidx/compose/material/ripple/RippleContainer;->disposeRippleIfNeeded(Landroidx/compose/material/ripple/AndroidRippleIndicationInstance;)V
+PLandroidx/compose/material/ripple/RippleContainer;->getRippleHostView(Landroidx/compose/material/ripple/AndroidRippleIndicationInstance;)Landroidx/compose/material/ripple/RippleHostView;
+PLandroidx/compose/material/ripple/RippleHostMap;->get(Landroidx/compose/material/ripple/AndroidRippleIndicationInstance;)Landroidx/compose/material/ripple/RippleHostView;
+PLandroidx/compose/material/ripple/RippleHostMap;->remove(Landroidx/compose/material/ripple/AndroidRippleIndicationInstance;)V
+PLandroidx/compose/material/ripple/RippleHostMap;->set(Landroidx/compose/material/ripple/AndroidRippleIndicationInstance;Landroidx/compose/material/ripple/RippleHostView;)V
+PLandroidx/compose/material/ripple/RippleHostView$$ExternalSyntheticLambda0;-><init>(Landroidx/compose/material/ripple/RippleHostView;)V
+PLandroidx/compose/material/ripple/RippleHostView$$ExternalSyntheticLambda0;->run()V
+PLandroidx/compose/material/ripple/RippleHostView;->$r8$lambda$4nztiuYeQHklB-09QfMAnp7Ay8E(Landroidx/compose/material/ripple/RippleHostView;)V
+PLandroidx/compose/material/ripple/RippleHostView;->addRipple-KOepWvA(Landroidx/compose/foundation/interaction/PressInteraction$Press;ZJIJFLkotlin/jvm/functions/Function0;)V
+PLandroidx/compose/material/ripple/RippleHostView;->createRipple(Z)V
+PLandroidx/compose/material/ripple/RippleHostView;->disposeRipple()V
+PLandroidx/compose/material/ripple/RippleHostView;->invalidateDrawable(Landroid/graphics/drawable/Drawable;)V
+PLandroidx/compose/material/ripple/RippleHostView;->removeRipple()V
+PLandroidx/compose/material/ripple/RippleHostView;->setRippleState$lambda$2(Landroidx/compose/material/ripple/RippleHostView;)V
+PLandroidx/compose/material/ripple/RippleHostView;->setRippleState(Z)V
+PLandroidx/compose/material/ripple/RippleHostView;->updateRippleProperties-biQXAtU(JIJF)V
+PLandroidx/compose/material/ripple/UnprojectedRipple$Companion;-><init>()V
+PLandroidx/compose/material/ripple/UnprojectedRipple$Companion;-><init>(Lkotlin/jvm/internal/DefaultConstructorMarker;)V
+PLandroidx/compose/material/ripple/UnprojectedRipple$MRadiusHelper;-><clinit>()V
+PLandroidx/compose/material/ripple/UnprojectedRipple$MRadiusHelper;-><init>()V
+PLandroidx/compose/material/ripple/UnprojectedRipple$MRadiusHelper;->setRadius(Landroid/graphics/drawable/RippleDrawable;I)V
+PLandroidx/compose/material/ripple/UnprojectedRipple;-><clinit>()V
+PLandroidx/compose/material/ripple/UnprojectedRipple;-><init>(Z)V
+PLandroidx/compose/material/ripple/UnprojectedRipple;->calculateRippleColor-5vOe2sY(JF)J
+PLandroidx/compose/material/ripple/UnprojectedRipple;->getDirtyBounds()Landroid/graphics/Rect;
+PLandroidx/compose/material/ripple/UnprojectedRipple;->isProjected()Z
+PLandroidx/compose/material/ripple/UnprojectedRipple;->setColor-DxMtmZc(JF)V
+PLandroidx/compose/material/ripple/UnprojectedRipple;->trySetRadius(I)V
+PLandroidx/compose/material3/AppBarKt$SingleRowTopAppBar$1$1;-><init>(Landroidx/compose/material3/TopAppBarScrollBehavior;F)V
+PLandroidx/compose/material3/AppBarKt$SingleRowTopAppBar$1$1;->invoke()Ljava/lang/Object;
+PLandroidx/compose/material3/AppBarKt$SingleRowTopAppBar$1$1;->invoke()V
+PLandroidx/compose/material3/AppBarKt$SingleRowTopAppBar$2;-><init>(Landroidx/compose/foundation/layout/WindowInsets;Landroidx/compose/material3/TopAppBarColors;Lkotlin/jvm/functions/Function2;Landroidx/compose/ui/text/TextStyle;ZLkotlin/jvm/functions/Function2;Lkotlin/jvm/functions/Function2;ILandroidx/compose/material3/TopAppBarScrollBehavior;)V
+PLandroidx/compose/material3/AppBarKt$SingleRowTopAppBar$2;->invoke(Landroidx/compose/runtime/Composer;I)V
+PLandroidx/compose/material3/AppBarKt$SingleRowTopAppBar$2;->invoke(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;
+PLandroidx/compose/material3/AppBarKt$SingleRowTopAppBar$3;-><init>(Landroidx/compose/ui/Modifier;Lkotlin/jvm/functions/Function2;Landroidx/compose/ui/text/TextStyle;ZLkotlin/jvm/functions/Function2;Lkotlin/jvm/functions/Function3;Landroidx/compose/foundation/layout/WindowInsets;Landroidx/compose/material3/TopAppBarColors;Landroidx/compose/material3/TopAppBarScrollBehavior;II)V
+PLandroidx/compose/material3/AppBarKt$SingleRowTopAppBar$actionsRow$1;-><init>(Lkotlin/jvm/functions/Function3;I)V
+PLandroidx/compose/material3/AppBarKt$SingleRowTopAppBar$actionsRow$1;->invoke(Landroidx/compose/runtime/Composer;I)V
+PLandroidx/compose/material3/AppBarKt$SingleRowTopAppBar$actionsRow$1;->invoke(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;
+PLandroidx/compose/material3/AppBarKt$TopAppBarLayout$1$3$1;-><init>(JLkotlin/jvm/functions/Function2;I)V
+PLandroidx/compose/material3/AppBarKt$TopAppBarLayout$1$3$1;->invoke(Landroidx/compose/runtime/Composer;I)V
+PLandroidx/compose/material3/AppBarKt$TopAppBarLayout$1$3$1;->invoke(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;
+PLandroidx/compose/material3/AppBarKt$TopAppBarLayout$2$measure$1;-><init>(Landroidx/compose/ui/layout/Placeable;ILandroidx/compose/ui/layout/Placeable;Landroidx/compose/foundation/layout/Arrangement$Horizontal;JLandroidx/compose/ui/layout/Placeable;Landroidx/compose/ui/layout/MeasureScope;Landroidx/compose/foundation/layout/Arrangement$Vertical;II)V
+PLandroidx/compose/material3/AppBarKt$TopAppBarLayout$2$measure$1;->invoke(Landroidx/compose/ui/layout/Placeable$PlacementScope;)V
+PLandroidx/compose/material3/AppBarKt$TopAppBarLayout$2$measure$1;->invoke(Ljava/lang/Object;)Ljava/lang/Object;
+PLandroidx/compose/material3/AppBarKt$TopAppBarLayout$2;-><init>(FLandroidx/compose/foundation/layout/Arrangement$Horizontal;Landroidx/compose/foundation/layout/Arrangement$Vertical;I)V
+PLandroidx/compose/material3/AppBarKt$TopAppBarLayout$2;->measure-3p2s80s(Landroidx/compose/ui/layout/MeasureScope;Ljava/util/List;J)Landroidx/compose/ui/layout/MeasureResult;
+PLandroidx/compose/material3/AppBarKt;-><clinit>()V
+PLandroidx/compose/material3/AppBarKt;->SingleRowTopAppBar$lambda$3(Landroidx/compose/runtime/State;)J
+PLandroidx/compose/material3/AppBarKt;->SingleRowTopAppBar(Landroidx/compose/ui/Modifier;Lkotlin/jvm/functions/Function2;Landroidx/compose/ui/text/TextStyle;ZLkotlin/jvm/functions/Function2;Lkotlin/jvm/functions/Function3;Landroidx/compose/foundation/layout/WindowInsets;Landroidx/compose/material3/TopAppBarColors;Landroidx/compose/material3/TopAppBarScrollBehavior;Landroidx/compose/runtime/Composer;II)V
+PLandroidx/compose/material3/AppBarKt;->TopAppBar(Lkotlin/jvm/functions/Function2;Landroidx/compose/ui/Modifier;Lkotlin/jvm/functions/Function2;Lkotlin/jvm/functions/Function3;Landroidx/compose/foundation/layout/WindowInsets;Landroidx/compose/material3/TopAppBarColors;Landroidx/compose/material3/TopAppBarScrollBehavior;Landroidx/compose/runtime/Composer;II)V
+PLandroidx/compose/material3/AppBarKt;->TopAppBarLayout-kXwM9vE(Landroidx/compose/ui/Modifier;FJJJLkotlin/jvm/functions/Function2;Landroidx/compose/ui/text/TextStyle;FLandroidx/compose/foundation/layout/Arrangement$Vertical;Landroidx/compose/foundation/layout/Arrangement$Horizontal;IZLkotlin/jvm/functions/Function2;Lkotlin/jvm/functions/Function2;Landroidx/compose/runtime/Composer;II)V
+PLandroidx/compose/material3/AppBarKt;->access$TopAppBarLayout-kXwM9vE(Landroidx/compose/ui/Modifier;FJJJLkotlin/jvm/functions/Function2;Landroidx/compose/ui/text/TextStyle;FLandroidx/compose/foundation/layout/Arrangement$Vertical;Landroidx/compose/foundation/layout/Arrangement$Horizontal;IZLkotlin/jvm/functions/Function2;Lkotlin/jvm/functions/Function2;Landroidx/compose/runtime/Composer;II)V
+PLandroidx/compose/material3/AppBarKt;->access$getTopAppBarTitleInset$p()F
+PLandroidx/compose/material3/ButtonElevation$animateElevation$1$1$1;->emit(Landroidx/compose/foundation/interaction/Interaction;Lkotlin/coroutines/Continuation;)Ljava/lang/Object;
+PLandroidx/compose/material3/ButtonElevation$animateElevation$1$1$1;->emit(Ljava/lang/Object;Lkotlin/coroutines/Continuation;)Ljava/lang/Object;
+PLandroidx/compose/material3/ButtonKt$Button$3;->invoke(Landroidx/compose/runtime/Composer;I)V
+PLandroidx/compose/material3/ButtonKt$Button$3;->invoke(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;
+PLandroidx/compose/material3/ChipElevation$animateElevation$1$1$1;->emit(Landroidx/compose/foundation/interaction/Interaction;Lkotlin/coroutines/Continuation;)Ljava/lang/Object;
+PLandroidx/compose/material3/ChipElevation$animateElevation$1$1$1;->emit(Ljava/lang/Object;Lkotlin/coroutines/Continuation;)Ljava/lang/Object;
+PLandroidx/compose/material3/ChipKt$Chip$2;->invoke(Landroidx/compose/runtime/Composer;I)V
+PLandroidx/compose/material3/ChipKt$Chip$2;->invoke(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;
+PLandroidx/compose/material3/ChipKt;->access$Chip-nkUnTEs(Landroidx/compose/ui/Modifier;Lkotlin/jvm/functions/Function0;ZLkotlin/jvm/functions/Function2;Landroidx/compose/ui/text/TextStyle;JLkotlin/jvm/functions/Function2;Lkotlin/jvm/functions/Function2;Landroidx/compose/ui/graphics/Shape;Landroidx/compose/material3/ChipColors;Landroidx/compose/material3/ChipElevation;Landroidx/compose/foundation/BorderStroke;FLandroidx/compose/foundation/layout/PaddingValues;Landroidx/compose/foundation/interaction/MutableInteractionSource;Landroidx/compose/runtime/Composer;II)V
+PLandroidx/compose/material3/ColorSchemeKt;->applyTonalElevation-Hht5A8o(Landroidx/compose/material3/ColorScheme;JF)J
+PLandroidx/compose/material3/ComposableSingletons$AppBarKt$lambda-1$1;-><clinit>()V
+PLandroidx/compose/material3/ComposableSingletons$AppBarKt$lambda-1$1;-><init>()V
+PLandroidx/compose/material3/ComposableSingletons$AppBarKt$lambda-10$1;-><clinit>()V
+PLandroidx/compose/material3/ComposableSingletons$AppBarKt$lambda-10$1;-><init>()V
+PLandroidx/compose/material3/ComposableSingletons$AppBarKt$lambda-11$1;-><clinit>()V
+PLandroidx/compose/material3/ComposableSingletons$AppBarKt$lambda-11$1;-><init>()V
+PLandroidx/compose/material3/ComposableSingletons$AppBarKt$lambda-12$1;-><clinit>()V
+PLandroidx/compose/material3/ComposableSingletons$AppBarKt$lambda-12$1;-><init>()V
+PLandroidx/compose/material3/ComposableSingletons$AppBarKt$lambda-2$1;-><clinit>()V
+PLandroidx/compose/material3/ComposableSingletons$AppBarKt$lambda-2$1;-><init>()V
+PLandroidx/compose/material3/ComposableSingletons$AppBarKt$lambda-2$1;->invoke(Landroidx/compose/foundation/layout/RowScope;Landroidx/compose/runtime/Composer;I)V
+PLandroidx/compose/material3/ComposableSingletons$AppBarKt$lambda-2$1;->invoke(Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;
+PLandroidx/compose/material3/ComposableSingletons$AppBarKt$lambda-3$1;-><clinit>()V
+PLandroidx/compose/material3/ComposableSingletons$AppBarKt$lambda-3$1;-><init>()V
+PLandroidx/compose/material3/ComposableSingletons$AppBarKt$lambda-4$1;-><clinit>()V
+PLandroidx/compose/material3/ComposableSingletons$AppBarKt$lambda-4$1;-><init>()V
+PLandroidx/compose/material3/ComposableSingletons$AppBarKt$lambda-5$1;-><clinit>()V
+PLandroidx/compose/material3/ComposableSingletons$AppBarKt$lambda-5$1;-><init>()V
+PLandroidx/compose/material3/ComposableSingletons$AppBarKt$lambda-6$1;-><clinit>()V
+PLandroidx/compose/material3/ComposableSingletons$AppBarKt$lambda-6$1;-><init>()V
+PLandroidx/compose/material3/ComposableSingletons$AppBarKt$lambda-7$1;-><clinit>()V
+PLandroidx/compose/material3/ComposableSingletons$AppBarKt$lambda-7$1;-><init>()V
+PLandroidx/compose/material3/ComposableSingletons$AppBarKt$lambda-8$1;-><clinit>()V
+PLandroidx/compose/material3/ComposableSingletons$AppBarKt$lambda-8$1;-><init>()V
+PLandroidx/compose/material3/ComposableSingletons$AppBarKt$lambda-9$1;-><clinit>()V
+PLandroidx/compose/material3/ComposableSingletons$AppBarKt$lambda-9$1;-><init>()V
+PLandroidx/compose/material3/ComposableSingletons$AppBarKt;-><clinit>()V
+PLandroidx/compose/material3/ComposableSingletons$AppBarKt;-><init>()V
+PLandroidx/compose/material3/ComposableSingletons$AppBarKt;->getLambda-2$material3_release()Lkotlin/jvm/functions/Function3;
+PLandroidx/compose/material3/IconButtonColors;-><init>(JJJJ)V
+PLandroidx/compose/material3/IconButtonColors;-><init>(JJJJLkotlin/jvm/internal/DefaultConstructorMarker;)V
+PLandroidx/compose/material3/IconButtonColors;->containerColor$material3_release(ZLandroidx/compose/runtime/Composer;I)Landroidx/compose/runtime/State;
+PLandroidx/compose/material3/IconButtonColors;->contentColor$material3_release(ZLandroidx/compose/runtime/Composer;I)Landroidx/compose/runtime/State;
+PLandroidx/compose/material3/IconButtonDefaults;-><clinit>()V
+PLandroidx/compose/material3/IconButtonDefaults;-><init>()V
+PLandroidx/compose/material3/IconButtonDefaults;->iconButtonColors-ro_MJ88(JJJJLandroidx/compose/runtime/Composer;II)Landroidx/compose/material3/IconButtonColors;
+PLandroidx/compose/material3/IconButtonKt$IconButton$3;-><init>(Lkotlin/jvm/functions/Function0;Landroidx/compose/ui/Modifier;ZLandroidx/compose/material3/IconButtonColors;Landroidx/compose/foundation/interaction/MutableInteractionSource;Lkotlin/jvm/functions/Function2;II)V
+PLandroidx/compose/material3/IconButtonKt;->IconButton(Lkotlin/jvm/functions/Function0;Landroidx/compose/ui/Modifier;ZLandroidx/compose/material3/IconButtonColors;Landroidx/compose/foundation/interaction/MutableInteractionSource;Lkotlin/jvm/functions/Function2;Landroidx/compose/runtime/Composer;II)V
+PLandroidx/compose/material3/IconKt$Icon$1;-><init>(Landroidx/compose/ui/graphics/vector/ImageVector;Ljava/lang/String;Landroidx/compose/ui/Modifier;JII)V
+PLandroidx/compose/material3/IconKt$Icon$3;-><init>(Landroidx/compose/ui/graphics/painter/Painter;Ljava/lang/String;Landroidx/compose/ui/Modifier;JII)V
+PLandroidx/compose/material3/IconKt$Icon$semantics$1$1;-><init>(Ljava/lang/String;)V
+PLandroidx/compose/material3/IconKt$Icon$semantics$1$1;->invoke(Landroidx/compose/ui/semantics/SemanticsPropertyReceiver;)V
+PLandroidx/compose/material3/IconKt$Icon$semantics$1$1;->invoke(Ljava/lang/Object;)Ljava/lang/Object;
+PLandroidx/compose/material3/IconKt;->Icon-ww6aTOc(Landroidx/compose/ui/graphics/vector/ImageVector;Ljava/lang/String;Landroidx/compose/ui/Modifier;JLandroidx/compose/runtime/Composer;II)V
+PLandroidx/compose/material3/Shapes;->getLarge()Landroidx/compose/foundation/shape/CornerBasedShape;
+PLandroidx/compose/material3/Shapes;->getSmall()Landroidx/compose/foundation/shape/CornerBasedShape;
+PLandroidx/compose/material3/SuggestionChipDefaults;->getShape(Landroidx/compose/runtime/Composer;I)Landroidx/compose/ui/graphics/Shape;
+PLandroidx/compose/material3/SystemBarsDefaultInsets_androidKt;->getSystemBarsForVisualComponents(Landroidx/compose/foundation/layout/WindowInsets$Companion;Landroidx/compose/runtime/Composer;I)Landroidx/compose/foundation/layout/WindowInsets;
+PLandroidx/compose/material3/TopAppBarColors;-><init>(JJJJJ)V
+PLandroidx/compose/material3/TopAppBarColors;-><init>(JJJJJLkotlin/jvm/internal/DefaultConstructorMarker;)V
+PLandroidx/compose/material3/TopAppBarColors;->containerColor-XeAY9LY$material3_release(FLandroidx/compose/runtime/Composer;I)J
+PLandroidx/compose/material3/TopAppBarColors;->equals(Ljava/lang/Object;)Z
+PLandroidx/compose/material3/TopAppBarColors;->getActionIconContentColor-0d7_KjU$material3_release()J
+PLandroidx/compose/material3/TopAppBarColors;->getNavigationIconContentColor-0d7_KjU$material3_release()J
+PLandroidx/compose/material3/TopAppBarColors;->getTitleContentColor-0d7_KjU$material3_release()J
+PLandroidx/compose/material3/TopAppBarDefaults;-><clinit>()V
+PLandroidx/compose/material3/TopAppBarDefaults;-><init>()V
+PLandroidx/compose/material3/TopAppBarDefaults;->getWindowInsets(Landroidx/compose/runtime/Composer;I)Landroidx/compose/foundation/layout/WindowInsets;
+PLandroidx/compose/material3/TopAppBarDefaults;->smallTopAppBarColors-zjMxDiM(JJJJJLandroidx/compose/runtime/Composer;II)Landroidx/compose/material3/TopAppBarColors;
+PLandroidx/compose/material3/TopAppBarDefaults;->topAppBarColors-zjMxDiM(JJJJJLandroidx/compose/runtime/Composer;II)Landroidx/compose/material3/TopAppBarColors;
+PLandroidx/compose/material3/Typography;->getHeadlineSmall()Landroidx/compose/ui/text/TextStyle;
+PLandroidx/compose/material3/tokens/IconButtonTokens;->getStateLayerShape()Landroidx/compose/material3/tokens/ShapeKeyTokens;
+PLandroidx/compose/material3/tokens/IconButtonTokens;->getStateLayerSize-D9Ej5fM()F
+PLandroidx/compose/material3/tokens/SuggestionChipTokens;->getContainerShape()Landroidx/compose/material3/tokens/ShapeKeyTokens;
+PLandroidx/compose/material3/tokens/SuggestionChipTokens;->getLabelTextColor()Landroidx/compose/material3/tokens/ColorSchemeKeyTokens;
+PLandroidx/compose/material3/tokens/SuggestionChipTokens;->getLeadingIconColor()Landroidx/compose/material3/tokens/ColorSchemeKeyTokens;
+PLandroidx/compose/material3/tokens/TopAppBarSmallTokens;-><clinit>()V
+PLandroidx/compose/material3/tokens/TopAppBarSmallTokens;-><init>()V
+PLandroidx/compose/material3/tokens/TopAppBarSmallTokens;->getContainerHeight-D9Ej5fM()F
+PLandroidx/compose/material3/tokens/TopAppBarSmallTokens;->getHeadlineColor()Landroidx/compose/material3/tokens/ColorSchemeKeyTokens;
+PLandroidx/compose/material3/tokens/TopAppBarSmallTokens;->getHeadlineFont()Landroidx/compose/material3/tokens/TypographyKeyTokens;
+PLandroidx/compose/material3/tokens/TopAppBarSmallTokens;->getLeadingIconColor()Landroidx/compose/material3/tokens/ColorSchemeKeyTokens;
+PLandroidx/compose/material3/tokens/TopAppBarSmallTokens;->getOnScrollContainerElevation-D9Ej5fM()F
+PLandroidx/compose/material3/tokens/TopAppBarSmallTokens;->getTrailingIconColor()Landroidx/compose/material3/tokens/ColorSchemeKeyTokens;
+PLandroidx/compose/runtime/AbstractApplier;->clear()V
+PLandroidx/compose/runtime/BroadcastFrameClock;->minusKey(Lkotlin/coroutines/CoroutineContext$Key;)Lkotlin/coroutines/CoroutineContext;
+PLandroidx/compose/runtime/ComposableSingletons$CompositionKt;->getLambda-2$runtime_release()Lkotlin/jvm/functions/Function2;
+PLandroidx/compose/runtime/ComposerImpl$CompositionContextHolder;->onForgotten()V
+PLandroidx/compose/runtime/ComposerImpl$CompositionContextImpl;->dispose()V
+PLandroidx/compose/runtime/ComposerImpl$CompositionContextImpl;->getComposers()Ljava/util/Set;
+PLandroidx/compose/runtime/ComposerImpl$CompositionContextImpl;->unregisterComposer$runtime_release(Landroidx/compose/runtime/Composer;)V
+PLandroidx/compose/runtime/ComposerImpl$CompositionContextImpl;->unregisterComposition$runtime_release(Landroidx/compose/runtime/ControlledComposition;)V
+PLandroidx/compose/runtime/ComposerImpl$deactivateToEndGroup$2$1;-><init>(Ljava/lang/Object;II)V
+PLandroidx/compose/runtime/ComposerImpl$deactivateToEndGroup$2$1;->invoke(Landroidx/compose/runtime/Applier;Landroidx/compose/runtime/SlotWriter;Landroidx/compose/runtime/RememberManager;)V
+PLandroidx/compose/runtime/ComposerImpl$deactivateToEndGroup$2$1;->invoke(Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;
+PLandroidx/compose/runtime/ComposerImpl$deactivateToEndGroup$2$2;-><init>(Ljava/lang/Object;II)V
+PLandroidx/compose/runtime/ComposerImpl$deactivateToEndGroup$2$2;->invoke(Landroidx/compose/runtime/Applier;Landroidx/compose/runtime/SlotWriter;Landroidx/compose/runtime/RememberManager;)V
+PLandroidx/compose/runtime/ComposerImpl$deactivateToEndGroup$2$2;->invoke(Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;
+PLandroidx/compose/runtime/ComposerImpl$deactivateToEndGroup$2;-><init>(Landroidx/compose/runtime/ComposerImpl;I)V
+PLandroidx/compose/runtime/ComposerImpl$deactivateToEndGroup$2;->invoke(ILjava/lang/Object;)V
+PLandroidx/compose/runtime/ComposerImpl$deactivateToEndGroup$2;->invoke(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;
+PLandroidx/compose/runtime/ComposerImpl$doCompose$2$3;->invoke(Landroidx/compose/runtime/State;)V
+PLandroidx/compose/runtime/ComposerImpl$doCompose$2$3;->invoke(Ljava/lang/Object;)Ljava/lang/Object;
+PLandroidx/compose/runtime/ComposerImpl$doCompose$2$4;->invoke(Landroidx/compose/runtime/State;)V
+PLandroidx/compose/runtime/ComposerImpl$doCompose$2$4;->invoke(Ljava/lang/Object;)Ljava/lang/Object;
+PLandroidx/compose/runtime/ComposerImpl$realizeMovement$1;-><init>(II)V
+PLandroidx/compose/runtime/ComposerImpl$realizeMovement$1;->invoke(Landroidx/compose/runtime/Applier;Landroidx/compose/runtime/SlotWriter;Landroidx/compose/runtime/RememberManager;)V
+PLandroidx/compose/runtime/ComposerImpl$realizeMovement$1;->invoke(Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;
+PLandroidx/compose/runtime/ComposerImpl$start$2;-><init>(I)V
+PLandroidx/compose/runtime/ComposerImpl$start$2;->invoke(Landroidx/compose/runtime/Applier;Landroidx/compose/runtime/SlotWriter;Landroidx/compose/runtime/RememberManager;)V
+PLandroidx/compose/runtime/ComposerImpl$start$2;->invoke(Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;
+PLandroidx/compose/runtime/ComposerImpl;->access$getChanges$p(Landroidx/compose/runtime/ComposerImpl;)Ljava/util/List;
+PLandroidx/compose/runtime/ComposerImpl;->access$getReader$p(Landroidx/compose/runtime/ComposerImpl;)Landroidx/compose/runtime/SlotReader;
+PLandroidx/compose/runtime/ComposerImpl;->access$setChanges$p(Landroidx/compose/runtime/ComposerImpl;Ljava/util/List;)V
+PLandroidx/compose/runtime/ComposerImpl;->changed(F)Z
+PLandroidx/compose/runtime/ComposerImpl;->changed(I)Z
+PLandroidx/compose/runtime/ComposerImpl;->deactivateToEndGroup(Z)V
+PLandroidx/compose/runtime/ComposerImpl;->dispose$runtime_release()V
+PLandroidx/compose/runtime/ComposerImpl;->getDeferredChanges$runtime_release()Ljava/util/List;
+PLandroidx/compose/runtime/ComposerImpl;->nodeAt(Landroidx/compose/runtime/SlotReader;I)Ljava/lang/Object;
+PLandroidx/compose/runtime/ComposerImpl;->recordDelete()V
+PLandroidx/compose/runtime/ComposerImpl;->recordRemoveNode(II)V
+PLandroidx/compose/runtime/ComposerImpl;->reportAllMovableContent()V
+PLandroidx/compose/runtime/ComposerImpl;->reportFreeMovableContent$reportGroup(Landroidx/compose/runtime/ComposerImpl;IZI)I
+PLandroidx/compose/runtime/ComposerImpl;->reportFreeMovableContent(I)V
+PLandroidx/compose/runtime/ComposerKt$removeCurrentGroupInstance$1;->invoke(Landroidx/compose/runtime/Applier;Landroidx/compose/runtime/SlotWriter;Landroidx/compose/runtime/RememberManager;)V
+PLandroidx/compose/runtime/ComposerKt$removeCurrentGroupInstance$1;->invoke(Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;
+PLandroidx/compose/runtime/ComposerKt;->access$getRemoveCurrentGroupInstance$p()Lkotlin/jvm/functions/Function3;
+PLandroidx/compose/runtime/ComposerKt;->access$removeRange(Ljava/util/List;II)V
+PLandroidx/compose/runtime/ComposerKt;->distanceFrom(Landroidx/compose/runtime/SlotReader;II)I
+PLandroidx/compose/runtime/ComposerKt;->removeRange(Ljava/util/List;II)V
+PLandroidx/compose/runtime/CompositionContext;->unregisterComposer$runtime_release(Landroidx/compose/runtime/Composer;)V
+PLandroidx/compose/runtime/CompositionImpl;->dispose()V
+PLandroidx/compose/runtime/CompositionImpl;->observesAnyOf(Ljava/util/Set;)Z
+PLandroidx/compose/runtime/CompositionImpl;->setPendingInvalidScopes$runtime_release(Z)V
+PLandroidx/compose/runtime/CompositionScopedCoroutineScopeCanceller;->onForgotten()V
+PLandroidx/compose/runtime/DerivedSnapshotState$ResultRecord$Companion;-><init>()V
+PLandroidx/compose/runtime/DerivedSnapshotState$ResultRecord$Companion;-><init>(Lkotlin/jvm/internal/DefaultConstructorMarker;)V
+PLandroidx/compose/runtime/DerivedSnapshotState$ResultRecord$Companion;->getUnset()Ljava/lang/Object;
+PLandroidx/compose/runtime/DerivedSnapshotState$ResultRecord;-><clinit>()V
+PLandroidx/compose/runtime/DerivedSnapshotState$ResultRecord;-><init>()V
+PLandroidx/compose/runtime/DerivedSnapshotState$ResultRecord;->access$getUnset$cp()Ljava/lang/Object;
+PLandroidx/compose/runtime/DerivedSnapshotState$ResultRecord;->assign(Landroidx/compose/runtime/snapshots/StateRecord;)V
+PLandroidx/compose/runtime/DerivedSnapshotState$ResultRecord;->create()Landroidx/compose/runtime/snapshots/StateRecord;
+PLandroidx/compose/runtime/DerivedSnapshotState$ResultRecord;->getDependencies()Landroidx/compose/runtime/collection/IdentityArrayMap;
+PLandroidx/compose/runtime/DerivedSnapshotState$ResultRecord;->getResult()Ljava/lang/Object;
+PLandroidx/compose/runtime/DerivedSnapshotState$ResultRecord;->setDependencies(Landroidx/compose/runtime/collection/IdentityArrayMap;)V
+PLandroidx/compose/runtime/DerivedSnapshotState$ResultRecord;->setResult(Ljava/lang/Object;)V
+PLandroidx/compose/runtime/DerivedSnapshotState$ResultRecord;->setResultHash(I)V
+PLandroidx/compose/runtime/DerivedSnapshotState$currentRecord$result$1$result$1;-><init>(Landroidx/compose/runtime/DerivedSnapshotState;Landroidx/compose/runtime/collection/IdentityArrayMap;I)V
+PLandroidx/compose/runtime/DerivedSnapshotState$currentRecord$result$1$result$1;->invoke(Ljava/lang/Object;)Ljava/lang/Object;
+PLandroidx/compose/runtime/DerivedSnapshotState$currentRecord$result$1$result$1;->invoke(Ljava/lang/Object;)V
+PLandroidx/compose/runtime/DerivedSnapshotState;-><init>(Lkotlin/jvm/functions/Function0;Landroidx/compose/runtime/SnapshotMutationPolicy;)V
+PLandroidx/compose/runtime/DerivedSnapshotState;->getCurrentValue()Ljava/lang/Object;
+PLandroidx/compose/runtime/DerivedSnapshotState;->getDependencies()[Ljava/lang/Object;
+PLandroidx/compose/runtime/DerivedSnapshotState;->getFirstStateRecord()Landroidx/compose/runtime/snapshots/StateRecord;
+PLandroidx/compose/runtime/DerivedSnapshotState;->getPolicy()Landroidx/compose/runtime/SnapshotMutationPolicy;
+PLandroidx/compose/runtime/DerivedSnapshotState;->prependStateRecord(Landroidx/compose/runtime/snapshots/StateRecord;)V
+PLandroidx/compose/runtime/GroupInfo;->setNodeCount(I)V
+PLandroidx/compose/runtime/GroupInfo;->setNodeIndex(I)V
+PLandroidx/compose/runtime/GroupInfo;->setSlotIndex(I)V
+PLandroidx/compose/runtime/Pending;->updateNodeCount(II)Z
+PLandroidx/compose/runtime/PrioritySet;->peek()I
+PLandroidx/compose/runtime/RecomposeScopeImpl;->access$setTrackedInstances$p(Landroidx/compose/runtime/RecomposeScopeImpl;Landroidx/compose/runtime/collection/IdentityArrayIntMap;)V
+PLandroidx/compose/runtime/RecomposeScopeImpl;->getComposition()Landroidx/compose/runtime/CompositionImpl;
+PLandroidx/compose/runtime/RecomposeScopeImpl;->release()V
+PLandroidx/compose/runtime/RecomposeScopeImpl;->rereadTrackedInstances()V
+PLandroidx/compose/runtime/RecomposeScopeImpl;->setRereading(Z)V
+PLandroidx/compose/runtime/Recomposer$Companion;->access$removeRunning(Landroidx/compose/runtime/Recomposer$Companion;Landroidx/compose/runtime/Recomposer$RecomposerInfoImpl;)V
+PLandroidx/compose/runtime/Recomposer$Companion;->removeRunning(Landroidx/compose/runtime/Recomposer$RecomposerInfoImpl;)V
+PLandroidx/compose/runtime/Recomposer$effectJob$1$1$1$1;-><init>(Landroidx/compose/runtime/Recomposer;Ljava/lang/Throwable;)V
+PLandroidx/compose/runtime/Recomposer$effectJob$1$1$1$1;->invoke(Ljava/lang/Object;)Ljava/lang/Object;
+PLandroidx/compose/runtime/Recomposer$effectJob$1$1$1$1;->invoke(Ljava/lang/Throwable;)V
+PLandroidx/compose/runtime/Recomposer$effectJob$1$1;->invoke(Ljava/lang/Object;)Ljava/lang/Object;
+PLandroidx/compose/runtime/Recomposer$effectJob$1$1;->invoke(Ljava/lang/Throwable;)V
+PLandroidx/compose/runtime/Recomposer;->access$getRunnerJob$p(Landroidx/compose/runtime/Recomposer;)Lkotlinx/coroutines/Job;
+PLandroidx/compose/runtime/Recomposer;->access$isClosed$p(Landroidx/compose/runtime/Recomposer;)Z
+PLandroidx/compose/runtime/Recomposer;->access$setCloseCause$p(Landroidx/compose/runtime/Recomposer;Ljava/lang/Throwable;)V
+PLandroidx/compose/runtime/Recomposer;->access$setRunnerJob$p(Landroidx/compose/runtime/Recomposer;Lkotlinx/coroutines/Job;)V
+PLandroidx/compose/runtime/Recomposer;->cancel()V
+PLandroidx/compose/runtime/Recomposer;->unregisterComposition$runtime_release(Landroidx/compose/runtime/ControlledComposition;)V
+PLandroidx/compose/runtime/SlotReader;->containsMark(I)Z
+PLandroidx/compose/runtime/SlotReader;->forEachData$runtime_release(ILkotlin/jvm/functions/Function2;)V
+PLandroidx/compose/runtime/SlotReader;->getCurrentEnd()I
+PLandroidx/compose/runtime/SlotReader;->getGroupSize()I
+PLandroidx/compose/runtime/SlotReader;->hasMark(I)Z
+PLandroidx/compose/runtime/SlotTable;->containsMark()Z
+PLandroidx/compose/runtime/SlotWriter$groupSlots$1;-><init>(IILandroidx/compose/runtime/SlotWriter;)V
+PLandroidx/compose/runtime/SlotWriter;->access$updateContainsMark(Landroidx/compose/runtime/SlotWriter;I)V
+PLandroidx/compose/runtime/SlotWriter;->fixParentAnchorsFor(III)V
+PLandroidx/compose/runtime/SlotWriter;->groupSlots()Ljava/util/Iterator;
+PLandroidx/compose/runtime/SlotWriter;->moveAnchors(III)V
+PLandroidx/compose/runtime/SlotWriter;->moveGroup(I)V
+PLandroidx/compose/runtime/SlotWriter;->slot(II)Ljava/lang/Object;
+PLandroidx/compose/runtime/SlotWriter;->updateDataIndex([III)V
+PLandroidx/compose/runtime/SnapshotStateKt;->derivedStateOf(Lkotlin/jvm/functions/Function0;)Landroidx/compose/runtime/State;
+PLandroidx/compose/runtime/SnapshotStateKt__DerivedStateKt;->access$getCalculationBlockNestedLevel$p()Landroidx/compose/runtime/SnapshotThreadLocal;
+PLandroidx/compose/runtime/SnapshotStateKt__DerivedStateKt;->access$getDerivedStateObservers$p()Landroidx/compose/runtime/SnapshotThreadLocal;
+PLandroidx/compose/runtime/SnapshotStateKt__DerivedStateKt;->derivedStateOf(Lkotlin/jvm/functions/Function0;)Landroidx/compose/runtime/State;
+PLandroidx/compose/runtime/SnapshotStateKt__SnapshotFlowKt$snapshotFlow$1$readObserver$1;-><init>(Ljava/util/Set;)V
+PLandroidx/compose/runtime/SnapshotStateKt__SnapshotFlowKt$snapshotFlow$1$readObserver$1;->invoke(Ljava/lang/Object;)Ljava/lang/Object;
+PLandroidx/compose/runtime/SnapshotStateKt__SnapshotFlowKt$snapshotFlow$1$readObserver$1;->invoke(Ljava/lang/Object;)V
+PLandroidx/compose/runtime/SnapshotStateKt__SnapshotFlowKt$snapshotFlow$1$unregisterApplyObserver$1;-><init>(Lkotlinx/coroutines/channels/Channel;)V
+PLandroidx/compose/runtime/SnapshotStateKt__SnapshotFlowKt$snapshotFlow$1;->create(Ljava/lang/Object;Lkotlin/coroutines/Continuation;)Lkotlin/coroutines/Continuation;
+PLandroidx/compose/runtime/SnapshotStateKt__SnapshotFlowKt$snapshotFlow$1;->invoke(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;
+PLandroidx/compose/runtime/SnapshotStateKt__SnapshotFlowKt$snapshotFlow$1;->invoke(Lkotlinx/coroutines/flow/FlowCollector;Lkotlin/coroutines/Continuation;)Ljava/lang/Object;
+PLandroidx/compose/runtime/SnapshotStateKt__SnapshotFlowKt;->access$intersects(Ljava/util/Set;Ljava/util/Set;)Z
+PLandroidx/compose/runtime/Stack;->peek(I)Ljava/lang/Object;
+PLandroidx/compose/runtime/collection/IdentityArrayMap;->clear()V
+PLandroidx/compose/runtime/collection/IdentityArrayMap;->setSize$runtime_release(I)V
+PLandroidx/compose/runtime/collection/IdentityArraySet$iterator$1;-><init>(Landroidx/compose/runtime/collection/IdentityArraySet;)V
+PLandroidx/compose/runtime/collection/IdentityArraySet$iterator$1;->hasNext()Z
+PLandroidx/compose/runtime/collection/IdentityArraySet$iterator$1;->next()Ljava/lang/Object;
+PLandroidx/compose/runtime/collection/IdentityArraySet;->isEmpty()Z
+PLandroidx/compose/runtime/collection/IdentityArraySet;->iterator()Ljava/util/Iterator;
+PLandroidx/compose/runtime/collection/IdentityScopeMap;->clear()V
+PLandroidx/compose/runtime/collection/IdentityScopeMap;->removeScope(Ljava/lang/Object;)V
+PLandroidx/compose/runtime/collection/MutableVector$MutableVectorList;->iterator()Ljava/util/Iterator;
+PLandroidx/compose/runtime/collection/MutableVector$VectorListIterator;-><init>(Ljava/util/List;I)V
+PLandroidx/compose/runtime/collection/MutableVector$VectorListIterator;->hasNext()Z
+PLandroidx/compose/runtime/collection/MutableVector$VectorListIterator;->next()Ljava/lang/Object;
+PLandroidx/compose/runtime/external/kotlinx/collections/immutable/implementations/immutableList/AbstractPersistentList;->remove(Ljava/lang/Object;)Landroidx/compose/runtime/external/kotlinx/collections/immutable/PersistentList;
+PLandroidx/compose/runtime/external/kotlinx/collections/immutable/implementations/immutableList/SmallPersistentVector;->add(Ljava/lang/Object;)Landroidx/compose/runtime/external/kotlinx/collections/immutable/PersistentList;
+PLandroidx/compose/runtime/external/kotlinx/collections/immutable/implementations/immutableList/SmallPersistentVector;->get(I)Ljava/lang/Object;
+PLandroidx/compose/runtime/external/kotlinx/collections/immutable/implementations/immutableList/SmallPersistentVector;->indexOf(Ljava/lang/Object;)I
+PLandroidx/compose/runtime/external/kotlinx/collections/immutable/implementations/immutableList/SmallPersistentVector;->removeAt(I)Landroidx/compose/runtime/external/kotlinx/collections/immutable/PersistentList;
+PLandroidx/compose/runtime/external/kotlinx/collections/immutable/implementations/immutableMap/PersistentHashMap;->remove(Ljava/lang/Object;)Landroidx/compose/runtime/external/kotlinx/collections/immutable/implementations/immutableMap/PersistentHashMap;
+PLandroidx/compose/runtime/external/kotlinx/collections/immutable/implementations/immutableMap/TrieNode;->remove(ILjava/lang/Object;I)Landroidx/compose/runtime/external/kotlinx/collections/immutable/implementations/immutableMap/TrieNode;
+PLandroidx/compose/runtime/external/kotlinx/collections/immutable/implementations/immutableMap/TrieNode;->removeEntryAtIndex(II)Landroidx/compose/runtime/external/kotlinx/collections/immutable/implementations/immutableMap/TrieNode;
+PLandroidx/compose/runtime/external/kotlinx/collections/immutable/implementations/immutableMap/TrieNodeBaseIterator;->moveToNextNode()V
+PLandroidx/compose/runtime/external/kotlinx/collections/immutable/implementations/persistentOrderedSet/Links;->getHasNext()Z
+PLandroidx/compose/runtime/external/kotlinx/collections/immutable/implementations/persistentOrderedSet/Links;->getHasPrevious()Z
+PLandroidx/compose/runtime/external/kotlinx/collections/immutable/implementations/persistentOrderedSet/Links;->getNext()Ljava/lang/Object;
+PLandroidx/compose/runtime/external/kotlinx/collections/immutable/implementations/persistentOrderedSet/Links;->getPrevious()Ljava/lang/Object;
+PLandroidx/compose/runtime/external/kotlinx/collections/immutable/implementations/persistentOrderedSet/PersistentOrderedSet;->remove(Ljava/lang/Object;)Landroidx/compose/runtime/external/kotlinx/collections/immutable/PersistentSet;
+PLandroidx/compose/runtime/external/kotlinx/collections/immutable/internal/ListImplementation;-><clinit>()V
+PLandroidx/compose/runtime/external/kotlinx/collections/immutable/internal/ListImplementation;-><init>()V
+PLandroidx/compose/runtime/external/kotlinx/collections/immutable/internal/ListImplementation;->checkElementIndex$runtime_release(II)V
+PLandroidx/compose/runtime/internal/ComposableLambdaImpl$invoke$2;-><init>(Landroidx/compose/runtime/internal/ComposableLambdaImpl;Ljava/lang/Object;Ljava/lang/Object;I)V
+PLandroidx/compose/runtime/internal/ComposableLambdaImpl;->invoke(Ljava/lang/Object;Ljava/lang/Object;Landroidx/compose/runtime/Composer;I)Ljava/lang/Object;
+PLandroidx/compose/runtime/internal/ComposableLambdaImpl;->invoke(Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;
+PLandroidx/compose/runtime/saveable/ListSaverKt$listSaver$1;-><init>(Lkotlin/jvm/functions/Function2;)V
+PLandroidx/compose/runtime/saveable/ListSaverKt$listSaver$1;->invoke(Landroidx/compose/runtime/saveable/SaverScope;Ljava/lang/Object;)Ljava/lang/Object;
+PLandroidx/compose/runtime/saveable/ListSaverKt$listSaver$1;->invoke(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;
+PLandroidx/compose/runtime/saveable/ListSaverKt;->listSaver(Lkotlin/jvm/functions/Function2;Lkotlin/jvm/functions/Function1;)Landroidx/compose/runtime/saveable/Saver;
+PLandroidx/compose/runtime/saveable/RememberSaveableKt$rememberSaveable$1$invoke$$inlined$onDispose$1;->dispose()V
+PLandroidx/compose/runtime/saveable/RememberSaveableKt$rememberSaveable$1$valueProvider$1$1$1;->canBeSaved(Ljava/lang/Object;)Z
+PLandroidx/compose/runtime/saveable/SaveableStateHolderImpl$Companion$Saver$1;-><clinit>()V
+PLandroidx/compose/runtime/saveable/SaveableStateHolderImpl$Companion$Saver$1;-><init>()V
+PLandroidx/compose/runtime/saveable/SaveableStateHolderImpl$Companion$Saver$1;->invoke(Landroidx/compose/runtime/saveable/SaverScope;Landroidx/compose/runtime/saveable/SaveableStateHolderImpl;)Ljava/util/Map;
+PLandroidx/compose/runtime/saveable/SaveableStateHolderImpl$Companion$Saver$1;->invoke(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;
+PLandroidx/compose/runtime/saveable/SaveableStateHolderImpl$Companion$Saver$2;-><clinit>()V
+PLandroidx/compose/runtime/saveable/SaveableStateHolderImpl$Companion$Saver$2;-><init>()V
+PLandroidx/compose/runtime/saveable/SaveableStateHolderImpl$Companion;-><init>()V
+PLandroidx/compose/runtime/saveable/SaveableStateHolderImpl$Companion;-><init>(Lkotlin/jvm/internal/DefaultConstructorMarker;)V
+PLandroidx/compose/runtime/saveable/SaveableStateHolderImpl$Companion;->getSaver()Landroidx/compose/runtime/saveable/Saver;
+PLandroidx/compose/runtime/saveable/SaveableStateHolderImpl$RegistryHolder$registry$1;-><init>(Landroidx/compose/runtime/saveable/SaveableStateHolderImpl;)V
+PLandroidx/compose/runtime/saveable/SaveableStateHolderImpl$RegistryHolder;-><init>(Landroidx/compose/runtime/saveable/SaveableStateHolderImpl;Ljava/lang/Object;)V
+PLandroidx/compose/runtime/saveable/SaveableStateHolderImpl$RegistryHolder;->getRegistry()Landroidx/compose/runtime/saveable/SaveableStateRegistry;
+PLandroidx/compose/runtime/saveable/SaveableStateHolderImpl$RegistryHolder;->saveTo(Ljava/util/Map;)V
+PLandroidx/compose/runtime/saveable/SaveableStateHolderImpl$SaveableStateProvider$1$1$invoke$$inlined$onDispose$1;-><init>(Landroidx/compose/runtime/saveable/SaveableStateHolderImpl$RegistryHolder;Landroidx/compose/runtime/saveable/SaveableStateHolderImpl;Ljava/lang/Object;)V
+PLandroidx/compose/runtime/saveable/SaveableStateHolderImpl$SaveableStateProvider$1$1$invoke$$inlined$onDispose$1;->dispose()V
+PLandroidx/compose/runtime/saveable/SaveableStateHolderImpl$SaveableStateProvider$1$1;-><init>(Landroidx/compose/runtime/saveable/SaveableStateHolderImpl;Ljava/lang/Object;Landroidx/compose/runtime/saveable/SaveableStateHolderImpl$RegistryHolder;)V
+PLandroidx/compose/runtime/saveable/SaveableStateHolderImpl$SaveableStateProvider$1$1;->invoke(Landroidx/compose/runtime/DisposableEffectScope;)Landroidx/compose/runtime/DisposableEffectResult;
+PLandroidx/compose/runtime/saveable/SaveableStateHolderImpl$SaveableStateProvider$1$1;->invoke(Ljava/lang/Object;)Ljava/lang/Object;
+PLandroidx/compose/runtime/saveable/SaveableStateHolderImpl;-><clinit>()V
+PLandroidx/compose/runtime/saveable/SaveableStateHolderImpl;-><init>(Ljava/util/Map;)V
+PLandroidx/compose/runtime/saveable/SaveableStateHolderImpl;-><init>(Ljava/util/Map;ILkotlin/jvm/internal/DefaultConstructorMarker;)V
+PLandroidx/compose/runtime/saveable/SaveableStateHolderImpl;->SaveableStateProvider(Ljava/lang/Object;Lkotlin/jvm/functions/Function2;Landroidx/compose/runtime/Composer;I)V
+PLandroidx/compose/runtime/saveable/SaveableStateHolderImpl;->access$getRegistryHolders$p(Landroidx/compose/runtime/saveable/SaveableStateHolderImpl;)Ljava/util/Map;
+PLandroidx/compose/runtime/saveable/SaveableStateHolderImpl;->access$getSavedStates$p(Landroidx/compose/runtime/saveable/SaveableStateHolderImpl;)Ljava/util/Map;
+PLandroidx/compose/runtime/saveable/SaveableStateHolderImpl;->access$getSaver$cp()Landroidx/compose/runtime/saveable/Saver;
+PLandroidx/compose/runtime/saveable/SaveableStateHolderImpl;->access$saveAll(Landroidx/compose/runtime/saveable/SaveableStateHolderImpl;)Ljava/util/Map;
+PLandroidx/compose/runtime/saveable/SaveableStateHolderImpl;->getParentSaveableStateRegistry()Landroidx/compose/runtime/saveable/SaveableStateRegistry;
+PLandroidx/compose/runtime/saveable/SaveableStateHolderImpl;->removeState(Ljava/lang/Object;)V
+PLandroidx/compose/runtime/saveable/SaveableStateHolderImpl;->saveAll()Ljava/util/Map;
+PLandroidx/compose/runtime/saveable/SaveableStateHolderImpl;->setParentSaveableStateRegistry(Landroidx/compose/runtime/saveable/SaveableStateRegistry;)V
+PLandroidx/compose/runtime/saveable/SaveableStateHolderKt$rememberSaveableStateHolder$1;-><clinit>()V
+PLandroidx/compose/runtime/saveable/SaveableStateHolderKt$rememberSaveableStateHolder$1;-><init>()V
+PLandroidx/compose/runtime/saveable/SaveableStateHolderKt$rememberSaveableStateHolder$1;->invoke()Landroidx/compose/runtime/saveable/SaveableStateHolderImpl;
+PLandroidx/compose/runtime/saveable/SaveableStateHolderKt$rememberSaveableStateHolder$1;->invoke()Ljava/lang/Object;
+PLandroidx/compose/runtime/saveable/SaveableStateHolderKt;->rememberSaveableStateHolder(Landroidx/compose/runtime/Composer;I)Landroidx/compose/runtime/saveable/SaveableStateHolder;
+PLandroidx/compose/runtime/saveable/SaveableStateRegistryImpl$registerProvider$3;->unregister()V
+PLandroidx/compose/runtime/saveable/SaveableStateRegistryImpl;->access$getValueProviders$p(Landroidx/compose/runtime/saveable/SaveableStateRegistryImpl;)Ljava/util/Map;
+PLandroidx/compose/runtime/saveable/SaveableStateRegistryImpl;->performSave()Ljava/util/Map;
+PLandroidx/compose/runtime/snapshots/GlobalSnapshot$takeNestedSnapshot$1;-><init>(Lkotlin/jvm/functions/Function1;)V
+PLandroidx/compose/runtime/snapshots/GlobalSnapshot$takeNestedSnapshot$1;->invoke(Landroidx/compose/runtime/snapshots/SnapshotIdSet;)Landroidx/compose/runtime/snapshots/ReadonlySnapshot;
+PLandroidx/compose/runtime/snapshots/GlobalSnapshot$takeNestedSnapshot$1;->invoke(Ljava/lang/Object;)Ljava/lang/Object;
+PLandroidx/compose/runtime/snapshots/GlobalSnapshot;->takeNestedSnapshot(Lkotlin/jvm/functions/Function1;)Landroidx/compose/runtime/snapshots/Snapshot;
+PLandroidx/compose/runtime/snapshots/MutableSnapshot;->advance$runtime_release()V
+PLandroidx/compose/runtime/snapshots/MutableSnapshot;->getApplied$runtime_release()Z
+PLandroidx/compose/runtime/snapshots/MutableSnapshot;->getPreviousPinnedSnapshots$runtime_release()[I
+PLandroidx/compose/runtime/snapshots/MutableSnapshot;->nestedActivated$runtime_release(Landroidx/compose/runtime/snapshots/Snapshot;)V
+PLandroidx/compose/runtime/snapshots/MutableSnapshot;->notifyObjectsInitialized$runtime_release()V
+PLandroidx/compose/runtime/snapshots/MutableSnapshot;->recordPrevious$runtime_release(I)V
+PLandroidx/compose/runtime/snapshots/MutableSnapshot;->recordPreviousList$runtime_release(Landroidx/compose/runtime/snapshots/SnapshotIdSet;)V
+PLandroidx/compose/runtime/snapshots/MutableSnapshot;->recordPreviousPinnedSnapshot$runtime_release(I)V
+PLandroidx/compose/runtime/snapshots/MutableSnapshot;->recordPreviousPinnedSnapshots$runtime_release([I)V
+PLandroidx/compose/runtime/snapshots/MutableSnapshot;->setApplied$runtime_release(Z)V
+PLandroidx/compose/runtime/snapshots/MutableSnapshot;->takeNestedMutableSnapshot(Lkotlin/jvm/functions/Function1;Lkotlin/jvm/functions/Function1;)Landroidx/compose/runtime/snapshots/MutableSnapshot;
+PLandroidx/compose/runtime/snapshots/MutableSnapshot;->validateNotAppliedOrPinned$runtime_release()V
+PLandroidx/compose/runtime/snapshots/NestedMutableSnapshot;-><init>(ILandroidx/compose/runtime/snapshots/SnapshotIdSet;Lkotlin/jvm/functions/Function1;Lkotlin/jvm/functions/Function1;Landroidx/compose/runtime/snapshots/MutableSnapshot;)V
+PLandroidx/compose/runtime/snapshots/NestedMutableSnapshot;->apply()Landroidx/compose/runtime/snapshots/SnapshotApplyResult;
+PLandroidx/compose/runtime/snapshots/NestedMutableSnapshot;->deactivate()V
+PLandroidx/compose/runtime/snapshots/NestedMutableSnapshot;->dispose()V
+PLandroidx/compose/runtime/snapshots/ReadonlySnapshot;-><init>(ILandroidx/compose/runtime/snapshots/SnapshotIdSet;Lkotlin/jvm/functions/Function1;)V
+PLandroidx/compose/runtime/snapshots/ReadonlySnapshot;->dispose()V
+PLandroidx/compose/runtime/snapshots/ReadonlySnapshot;->getReadObserver$runtime_release()Lkotlin/jvm/functions/Function1;
+PLandroidx/compose/runtime/snapshots/ReadonlySnapshot;->nestedDeactivated$runtime_release(Landroidx/compose/runtime/snapshots/Snapshot;)V
+PLandroidx/compose/runtime/snapshots/Snapshot$Companion$registerApplyObserver$2;->dispose()V
+PLandroidx/compose/runtime/snapshots/Snapshot$Companion;->takeSnapshot(Lkotlin/jvm/functions/Function1;)Landroidx/compose/runtime/snapshots/Snapshot;
+PLandroidx/compose/runtime/snapshots/Snapshot;->closeAndReleasePinning$runtime_release()V
+PLandroidx/compose/runtime/snapshots/Snapshot;->closeLocked$runtime_release()V
+PLandroidx/compose/runtime/snapshots/Snapshot;->setId$runtime_release(I)V
+PLandroidx/compose/runtime/snapshots/Snapshot;->setInvalid$runtime_release(Landroidx/compose/runtime/snapshots/SnapshotIdSet;)V
+PLandroidx/compose/runtime/snapshots/Snapshot;->takeoverPinnedSnapshot$runtime_release()I
+PLandroidx/compose/runtime/snapshots/Snapshot;->validateNotDisposed$runtime_release()V
+PLandroidx/compose/runtime/snapshots/SnapshotIdSet$iterator$1;-><init>(Landroidx/compose/runtime/snapshots/SnapshotIdSet;Lkotlin/coroutines/Continuation;)V
+PLandroidx/compose/runtime/snapshots/SnapshotIdSet$iterator$1;->create(Ljava/lang/Object;Lkotlin/coroutines/Continuation;)Lkotlin/coroutines/Continuation;
+PLandroidx/compose/runtime/snapshots/SnapshotIdSet$iterator$1;->invokeSuspend(Ljava/lang/Object;)Ljava/lang/Object;
+PLandroidx/compose/runtime/snapshots/SnapshotIdSet;->access$getBelowBound$p(Landroidx/compose/runtime/snapshots/SnapshotIdSet;)[I
+PLandroidx/compose/runtime/snapshots/SnapshotIdSet;->access$getLowerBound$p(Landroidx/compose/runtime/snapshots/SnapshotIdSet;)I
+PLandroidx/compose/runtime/snapshots/SnapshotIdSet;->access$getLowerSet$p(Landroidx/compose/runtime/snapshots/SnapshotIdSet;)J
+PLandroidx/compose/runtime/snapshots/SnapshotIdSet;->access$getUpperSet$p(Landroidx/compose/runtime/snapshots/SnapshotIdSet;)J
+PLandroidx/compose/runtime/snapshots/SnapshotIdSet;->iterator()Ljava/util/Iterator;
+PLandroidx/compose/runtime/snapshots/SnapshotIdSetKt;->binarySearch([II)I
+PLandroidx/compose/runtime/snapshots/SnapshotKt$mergedReadObserver$1;-><init>(Lkotlin/jvm/functions/Function1;Lkotlin/jvm/functions/Function1;)V
+PLandroidx/compose/runtime/snapshots/SnapshotKt$mergedReadObserver$1;->invoke(Ljava/lang/Object;)Ljava/lang/Object;
+PLandroidx/compose/runtime/snapshots/SnapshotKt$mergedReadObserver$1;->invoke(Ljava/lang/Object;)V
+PLandroidx/compose/runtime/snapshots/SnapshotKt;->addRange(Landroidx/compose/runtime/snapshots/SnapshotIdSet;II)Landroidx/compose/runtime/snapshots/SnapshotIdSet;
+PLandroidx/compose/runtime/snapshots/SnapshotKt;->newWritableRecord(Landroidx/compose/runtime/snapshots/StateRecord;Landroidx/compose/runtime/snapshots/StateObject;Landroidx/compose/runtime/snapshots/Snapshot;)Landroidx/compose/runtime/snapshots/StateRecord;
+PLandroidx/compose/runtime/snapshots/SnapshotKt;->writableRecord(Landroidx/compose/runtime/snapshots/StateRecord;Landroidx/compose/runtime/snapshots/StateObject;Landroidx/compose/runtime/snapshots/Snapshot;)Landroidx/compose/runtime/snapshots/StateRecord;
+PLandroidx/compose/runtime/snapshots/SnapshotStateList$StateListStateRecord;->assign(Landroidx/compose/runtime/snapshots/StateRecord;)V
+PLandroidx/compose/runtime/snapshots/SnapshotStateList$StateListStateRecord;->create()Landroidx/compose/runtime/snapshots/StateRecord;
+PLandroidx/compose/runtime/snapshots/SnapshotStateList$StateListStateRecord;->getModification$runtime_release()I
+PLandroidx/compose/runtime/snapshots/SnapshotStateList$StateListStateRecord;->setList$runtime_release(Landroidx/compose/runtime/external/kotlinx/collections/immutable/PersistentList;)V
+PLandroidx/compose/runtime/snapshots/SnapshotStateList$StateListStateRecord;->setModification$runtime_release(I)V
+PLandroidx/compose/runtime/snapshots/SnapshotStateList;->add(Ljava/lang/Object;)Z
+PLandroidx/compose/runtime/snapshots/SnapshotStateList;->get(I)Ljava/lang/Object;
+PLandroidx/compose/runtime/snapshots/SnapshotStateList;->getSize()I
+PLandroidx/compose/runtime/snapshots/SnapshotStateList;->prependStateRecord(Landroidx/compose/runtime/snapshots/StateRecord;)V
+PLandroidx/compose/runtime/snapshots/SnapshotStateList;->remove(Ljava/lang/Object;)Z
+PLandroidx/compose/runtime/snapshots/SnapshotStateList;->size()I
+PLandroidx/compose/runtime/snapshots/SnapshotStateListKt;-><clinit>()V
+PLandroidx/compose/runtime/snapshots/SnapshotStateListKt;->access$getSync$p()Ljava/lang/Object;
+PLandroidx/compose/runtime/snapshots/SnapshotStateObserver$ObservedScopeMap$derivedStateEnterObserver$1;->invoke(Ljava/lang/Object;)Ljava/lang/Object;
+PLandroidx/compose/runtime/snapshots/SnapshotStateObserver$ObservedScopeMap;->access$setDeriveStateScopeCount$p(Landroidx/compose/runtime/snapshots/SnapshotStateObserver$ObservedScopeMap;I)V
+PLandroidx/compose/runtime/snapshots/SnapshotStateObserver$ObservedScopeMap;->clear()V
+PLandroidx/compose/runtime/snapshots/SnapshotStateObserver$ObservedScopeMap;->removeScopeIf(Lkotlin/jvm/functions/Function1;)V
+PLandroidx/compose/runtime/snapshots/SnapshotStateObserver;->clear()V
+PLandroidx/compose/runtime/snapshots/SnapshotStateObserver;->clearIf(Lkotlin/jvm/functions/Function1;)V
+PLandroidx/compose/runtime/snapshots/SnapshotStateObserver;->stop()V
+PLandroidx/compose/ui/Modifier$Node;->onDetach()V
+PLandroidx/compose/ui/autofill/AutofillCallback;->unregister(Landroidx/compose/ui/autofill/AndroidAutofill;)V
+PLandroidx/compose/ui/draw/ClipKt;->clipToBounds(Landroidx/compose/ui/Modifier;)Landroidx/compose/ui/Modifier;
+PLandroidx/compose/ui/draw/PainterModifier;->calculateScaledSize-E7KxVPU(J)J
+PLandroidx/compose/ui/focus/FocusModifier$WhenMappings;-><clinit>()V
+PLandroidx/compose/ui/focus/FocusModifier;->isValid()Z
+PLandroidx/compose/ui/focus/FocusRequesterModifierLocal;->removeFocusModifier(Landroidx/compose/ui/focus/FocusModifier;)V
+PLandroidx/compose/ui/geometry/Offset;->copy-dBAh8RU$default(JFFILjava/lang/Object;)J
+PLandroidx/compose/ui/geometry/Offset;->copy-dBAh8RU(JFF)J
+PLandroidx/compose/ui/geometry/Offset;->equals-impl0(JJ)Z
+PLandroidx/compose/ui/geometry/Offset;->getDistanceSquared-impl(J)F
+PLandroidx/compose/ui/geometry/Offset;->minus-MK-Hz9U(JJ)J
+PLandroidx/compose/ui/geometry/Offset;->plus-MK-Hz9U(JJ)J
+PLandroidx/compose/ui/geometry/Offset;->times-tuRUvjQ(JF)J
+PLandroidx/compose/ui/geometry/Rect;->getHeight()F
+PLandroidx/compose/ui/geometry/Rect;->getWidth()F
+PLandroidx/compose/ui/geometry/Size;->equals(Ljava/lang/Object;)Z
+PLandroidx/compose/ui/geometry/Size;->isEmpty-impl(J)Z
+PLandroidx/compose/ui/geometry/SizeKt;->getCenter-uvyYCjk(J)J
+PLandroidx/compose/ui/graphics/AndroidCanvas;->concat-58bKbWc([F)V
+PLandroidx/compose/ui/graphics/AndroidCanvas_androidKt;->ActualCanvas(Landroidx/compose/ui/graphics/ImageBitmap;)Landroidx/compose/ui/graphics/Canvas;
+PLandroidx/compose/ui/graphics/AndroidImageBitmap;->prepareToDraw()V
+PLandroidx/compose/ui/graphics/AndroidImageBitmap_androidKt;->ActualImageBitmap-x__-hDU(IIIZLandroidx/compose/ui/graphics/colorspace/ColorSpace;)Landroidx/compose/ui/graphics/ImageBitmap;
+PLandroidx/compose/ui/graphics/AndroidImageBitmap_androidKt;->toBitmapConfig-1JJdX4A(I)Landroid/graphics/Bitmap$Config;
+PLandroidx/compose/ui/graphics/AndroidMatrixConversions_androidKt;->setFrom-EL8BTi8(Landroid/graphics/Matrix;[F)V
+PLandroidx/compose/ui/graphics/AndroidMatrixConversions_androidKt;->setFrom-tU-YjHk([FLandroid/graphics/Matrix;)V
+PLandroidx/compose/ui/graphics/AndroidPaint;->setBlendMode-s9anfk8(I)V
+PLandroidx/compose/ui/graphics/AndroidPaint_androidKt;->setNativeBlendMode-GB0RdKg(Landroid/graphics/Paint;I)V
+PLandroidx/compose/ui/graphics/AndroidPath;->addPath-Uv8p0NA(Landroidx/compose/ui/graphics/Path;J)V
+PLandroidx/compose/ui/graphics/AndroidPath;->close()V
+PLandroidx/compose/ui/graphics/AndroidPath;->lineTo(FF)V
+PLandroidx/compose/ui/graphics/AndroidPath;->moveTo(FF)V
+PLandroidx/compose/ui/graphics/AndroidPath;->relativeLineTo(FF)V
+PLandroidx/compose/ui/graphics/AndroidPath;->setFillType-oQ8Xj4U(I)V
+PLandroidx/compose/ui/graphics/Api26Bitmap;-><clinit>()V
+PLandroidx/compose/ui/graphics/Api26Bitmap;-><init>()V
+PLandroidx/compose/ui/graphics/Api26Bitmap;->createBitmap-x__-hDU$ui_graphics_release(IIIZLandroidx/compose/ui/graphics/colorspace/ColorSpace;)Landroid/graphics/Bitmap;
+PLandroidx/compose/ui/graphics/Api26Bitmap;->toFrameworkColorSpace$ui_graphics_release(Landroidx/compose/ui/graphics/colorspace/ColorSpace;)Landroid/graphics/ColorSpace;
+PLandroidx/compose/ui/graphics/BlendMode;-><init>(I)V
+PLandroidx/compose/ui/graphics/BlendMode;->box-impl(I)Landroidx/compose/ui/graphics/BlendMode;
+PLandroidx/compose/ui/graphics/Brush$Companion;-><init>()V
+PLandroidx/compose/ui/graphics/Brush$Companion;-><init>(Lkotlin/jvm/internal/DefaultConstructorMarker;)V
+PLandroidx/compose/ui/graphics/Brush;-><clinit>()V
+PLandroidx/compose/ui/graphics/Brush;-><init>()V
+PLandroidx/compose/ui/graphics/Brush;-><init>(Lkotlin/jvm/internal/DefaultConstructorMarker;)V
+PLandroidx/compose/ui/graphics/CanvasKt;->Canvas(Landroidx/compose/ui/graphics/ImageBitmap;)Landroidx/compose/ui/graphics/Canvas;
+PLandroidx/compose/ui/graphics/ColorKt;->access$getComponents-8_81llA(J)[F
+PLandroidx/compose/ui/graphics/ColorKt;->getComponents-8_81llA(J)[F
+PLandroidx/compose/ui/graphics/ColorKt;->lerp-jxsXWHM(JJF)J
+PLandroidx/compose/ui/graphics/Float16;->toFloat-impl(S)F
+PLandroidx/compose/ui/graphics/ImageBitmapConfig$Companion;-><init>()V
+PLandroidx/compose/ui/graphics/ImageBitmapConfig$Companion;-><init>(Lkotlin/jvm/internal/DefaultConstructorMarker;)V
+PLandroidx/compose/ui/graphics/ImageBitmapConfig$Companion;->getArgb8888-_sVssgQ()I
+PLandroidx/compose/ui/graphics/ImageBitmapConfig;-><clinit>()V
+PLandroidx/compose/ui/graphics/ImageBitmapConfig;->access$getArgb8888$cp()I
+PLandroidx/compose/ui/graphics/ImageBitmapConfig;->constructor-impl(I)I
+PLandroidx/compose/ui/graphics/ImageBitmapConfig;->equals-impl0(II)Z
+PLandroidx/compose/ui/graphics/ImageBitmapKt;->ImageBitmap-x__-hDU$default(IIIZLandroidx/compose/ui/graphics/colorspace/ColorSpace;ILjava/lang/Object;)Landroidx/compose/ui/graphics/ImageBitmap;
+PLandroidx/compose/ui/graphics/ImageBitmapKt;->ImageBitmap-x__-hDU(IIIZLandroidx/compose/ui/graphics/colorspace/ColorSpace;)Landroidx/compose/ui/graphics/ImageBitmap;
+PLandroidx/compose/ui/graphics/Matrix;-><init>([F)V
+PLandroidx/compose/ui/graphics/Matrix;->box-impl([F)Landroidx/compose/ui/graphics/Matrix;
+PLandroidx/compose/ui/graphics/Matrix;->rotateZ-impl([FF)V
+PLandroidx/compose/ui/graphics/Matrix;->scale-impl([FFFF)V
+PLandroidx/compose/ui/graphics/Matrix;->translate-impl$default([FFFFILjava/lang/Object;)V
+PLandroidx/compose/ui/graphics/Matrix;->translate-impl([FFFF)V
+PLandroidx/compose/ui/graphics/Matrix;->unbox-impl()[F
+PLandroidx/compose/ui/graphics/MatrixKt;->isIdentity-58bKbWc([F)Z
+PLandroidx/compose/ui/graphics/Outline$Rectangle;-><init>(Landroidx/compose/ui/geometry/Rect;)V
+PLandroidx/compose/ui/graphics/Outline$Rectangle;->getRect()Landroidx/compose/ui/geometry/Rect;
+PLandroidx/compose/ui/graphics/OutlineKt;->size(Landroidx/compose/ui/geometry/Rect;)J
+PLandroidx/compose/ui/graphics/OutlineKt;->topLeft(Landroidx/compose/ui/geometry/Rect;)J
+PLandroidx/compose/ui/graphics/Path$Companion;-><clinit>()V
+PLandroidx/compose/ui/graphics/Path$Companion;-><init>()V
+PLandroidx/compose/ui/graphics/Path;-><clinit>()V
+PLandroidx/compose/ui/graphics/Path;->addPath-Uv8p0NA$default(Landroidx/compose/ui/graphics/Path;Landroidx/compose/ui/graphics/Path;JILjava/lang/Object;)V
+PLandroidx/compose/ui/graphics/PathFillType$Companion;-><init>()V
+PLandroidx/compose/ui/graphics/PathFillType$Companion;-><init>(Lkotlin/jvm/internal/DefaultConstructorMarker;)V
+PLandroidx/compose/ui/graphics/PathFillType$Companion;->getEvenOdd-Rg-k1Os()I
+PLandroidx/compose/ui/graphics/PathFillType$Companion;->getNonZero-Rg-k1Os()I
+PLandroidx/compose/ui/graphics/PathFillType;-><clinit>()V
+PLandroidx/compose/ui/graphics/PathFillType;-><init>(I)V
+PLandroidx/compose/ui/graphics/PathFillType;->access$getEvenOdd$cp()I
+PLandroidx/compose/ui/graphics/PathFillType;->access$getNonZero$cp()I
+PLandroidx/compose/ui/graphics/PathFillType;->box-impl(I)Landroidx/compose/ui/graphics/PathFillType;
+PLandroidx/compose/ui/graphics/PathFillType;->constructor-impl(I)I
+PLandroidx/compose/ui/graphics/PathFillType;->equals-impl0(II)Z
+PLandroidx/compose/ui/graphics/PathFillType;->unbox-impl()I
+PLandroidx/compose/ui/graphics/RectHelper_androidKt;->toAndroidRect(Landroidx/compose/ui/geometry/Rect;)Landroid/graphics/Rect;
+PLandroidx/compose/ui/graphics/SolidColor;-><init>(J)V
+PLandroidx/compose/ui/graphics/SolidColor;-><init>(JLkotlin/jvm/internal/DefaultConstructorMarker;)V
+PLandroidx/compose/ui/graphics/SolidColor;->applyTo-Pq9zytI(JLandroidx/compose/ui/graphics/Paint;F)V
+PLandroidx/compose/ui/graphics/StrokeCap$Companion;-><init>()V
+PLandroidx/compose/ui/graphics/StrokeCap$Companion;-><init>(Lkotlin/jvm/internal/DefaultConstructorMarker;)V
+PLandroidx/compose/ui/graphics/StrokeCap$Companion;->getButt-KaPHkGw()I
+PLandroidx/compose/ui/graphics/StrokeCap;-><clinit>()V
+PLandroidx/compose/ui/graphics/StrokeCap;-><init>(I)V
+PLandroidx/compose/ui/graphics/StrokeCap;->access$getButt$cp()I
+PLandroidx/compose/ui/graphics/StrokeCap;->box-impl(I)Landroidx/compose/ui/graphics/StrokeCap;
+PLandroidx/compose/ui/graphics/StrokeCap;->constructor-impl(I)I
+PLandroidx/compose/ui/graphics/StrokeCap;->unbox-impl()I
+PLandroidx/compose/ui/graphics/StrokeJoin$Companion;-><init>()V
+PLandroidx/compose/ui/graphics/StrokeJoin$Companion;-><init>(Lkotlin/jvm/internal/DefaultConstructorMarker;)V
+PLandroidx/compose/ui/graphics/StrokeJoin$Companion;->getBevel-LxFBmk8()I
+PLandroidx/compose/ui/graphics/StrokeJoin$Companion;->getMiter-LxFBmk8()I
+PLandroidx/compose/ui/graphics/StrokeJoin;-><clinit>()V
+PLandroidx/compose/ui/graphics/StrokeJoin;-><init>(I)V
+PLandroidx/compose/ui/graphics/StrokeJoin;->access$getBevel$cp()I
+PLandroidx/compose/ui/graphics/StrokeJoin;->access$getMiter$cp()I
+PLandroidx/compose/ui/graphics/StrokeJoin;->box-impl(I)Landroidx/compose/ui/graphics/StrokeJoin;
+PLandroidx/compose/ui/graphics/StrokeJoin;->constructor-impl(I)I
+PLandroidx/compose/ui/graphics/StrokeJoin;->unbox-impl()I
+PLandroidx/compose/ui/graphics/WrapperVerificationHelperMethods;-><clinit>()V
+PLandroidx/compose/ui/graphics/WrapperVerificationHelperMethods;-><init>()V
+PLandroidx/compose/ui/graphics/WrapperVerificationHelperMethods;->setBlendMode-GB0RdKg(Landroid/graphics/Paint;I)V
+PLandroidx/compose/ui/graphics/colorspace/ColorModel;->equals-impl0(JJ)Z
+PLandroidx/compose/ui/graphics/colorspace/ColorSpace;->equals(Ljava/lang/Object;)Z
+PLandroidx/compose/ui/graphics/colorspace/ColorSpace;->getModel-xdoWZVw()J
+PLandroidx/compose/ui/graphics/colorspace/ColorSpace;->getName()Ljava/lang/String;
+PLandroidx/compose/ui/graphics/colorspace/ColorSpace;->isSrgb()Z
+PLandroidx/compose/ui/graphics/colorspace/ColorSpaceKt;->adapt$default(Landroidx/compose/ui/graphics/colorspace/ColorSpace;Landroidx/compose/ui/graphics/colorspace/WhitePoint;Landroidx/compose/ui/graphics/colorspace/Adaptation;ILjava/lang/Object;)Landroidx/compose/ui/graphics/colorspace/ColorSpace;
+PLandroidx/compose/ui/graphics/colorspace/ColorSpaceKt;->adapt(Landroidx/compose/ui/graphics/colorspace/ColorSpace;Landroidx/compose/ui/graphics/colorspace/WhitePoint;Landroidx/compose/ui/graphics/colorspace/Adaptation;)Landroidx/compose/ui/graphics/colorspace/ColorSpace;
+PLandroidx/compose/ui/graphics/colorspace/ColorSpaceKt;->connect-YBCOT_4$default(Landroidx/compose/ui/graphics/colorspace/ColorSpace;Landroidx/compose/ui/graphics/colorspace/ColorSpace;IILjava/lang/Object;)Landroidx/compose/ui/graphics/colorspace/Connector;
+PLandroidx/compose/ui/graphics/colorspace/ColorSpaceKt;->connect-YBCOT_4(Landroidx/compose/ui/graphics/colorspace/ColorSpace;Landroidx/compose/ui/graphics/colorspace/ColorSpace;I)Landroidx/compose/ui/graphics/colorspace/Connector;
+PLandroidx/compose/ui/graphics/colorspace/ColorSpaces;->getCieXyz()Landroidx/compose/ui/graphics/colorspace/ColorSpace;
+PLandroidx/compose/ui/graphics/colorspace/ColorSpaces;->getOklab()Landroidx/compose/ui/graphics/colorspace/ColorSpace;
+PLandroidx/compose/ui/graphics/colorspace/Connector$Companion;-><init>()V
+PLandroidx/compose/ui/graphics/colorspace/Connector$Companion;-><init>(Lkotlin/jvm/internal/DefaultConstructorMarker;)V
+PLandroidx/compose/ui/graphics/colorspace/Connector$Companion;->access$computeTransform-YBCOT_4(Landroidx/compose/ui/graphics/colorspace/Connector$Companion;Landroidx/compose/ui/graphics/colorspace/ColorSpace;Landroidx/compose/ui/graphics/colorspace/ColorSpace;I)[F
+PLandroidx/compose/ui/graphics/colorspace/Connector$Companion;->computeTransform-YBCOT_4(Landroidx/compose/ui/graphics/colorspace/ColorSpace;Landroidx/compose/ui/graphics/colorspace/ColorSpace;I)[F
+PLandroidx/compose/ui/graphics/colorspace/Connector;-><clinit>()V
+PLandroidx/compose/ui/graphics/colorspace/Connector;-><init>(Landroidx/compose/ui/graphics/colorspace/ColorSpace;Landroidx/compose/ui/graphics/colorspace/ColorSpace;I)V
+PLandroidx/compose/ui/graphics/colorspace/Connector;-><init>(Landroidx/compose/ui/graphics/colorspace/ColorSpace;Landroidx/compose/ui/graphics/colorspace/ColorSpace;ILkotlin/jvm/internal/DefaultConstructorMarker;)V
+PLandroidx/compose/ui/graphics/colorspace/Connector;-><init>(Landroidx/compose/ui/graphics/colorspace/ColorSpace;Landroidx/compose/ui/graphics/colorspace/ColorSpace;Landroidx/compose/ui/graphics/colorspace/ColorSpace;Landroidx/compose/ui/graphics/colorspace/ColorSpace;I[F)V
+PLandroidx/compose/ui/graphics/colorspace/Connector;-><init>(Landroidx/compose/ui/graphics/colorspace/ColorSpace;Landroidx/compose/ui/graphics/colorspace/ColorSpace;Landroidx/compose/ui/graphics/colorspace/ColorSpace;Landroidx/compose/ui/graphics/colorspace/ColorSpace;I[FLkotlin/jvm/internal/DefaultConstructorMarker;)V
+PLandroidx/compose/ui/graphics/colorspace/Connector;->transform([F)[F
+PLandroidx/compose/ui/graphics/colorspace/Oklab;->fromXyz([F)[F
+PLandroidx/compose/ui/graphics/colorspace/Oklab;->getMaxValue(I)F
+PLandroidx/compose/ui/graphics/colorspace/Oklab;->getMinValue(I)F
+PLandroidx/compose/ui/graphics/colorspace/Oklab;->toXyz([F)[F
+PLandroidx/compose/ui/graphics/colorspace/RenderIntent$Companion;-><init>()V
+PLandroidx/compose/ui/graphics/colorspace/RenderIntent$Companion;-><init>(Lkotlin/jvm/internal/DefaultConstructorMarker;)V
+PLandroidx/compose/ui/graphics/colorspace/RenderIntent$Companion;->getAbsolute-uksYyKA()I
+PLandroidx/compose/ui/graphics/colorspace/RenderIntent$Companion;->getPerceptual-uksYyKA()I
+PLandroidx/compose/ui/graphics/colorspace/RenderIntent;-><clinit>()V
+PLandroidx/compose/ui/graphics/colorspace/RenderIntent;->access$getAbsolute$cp()I
+PLandroidx/compose/ui/graphics/colorspace/RenderIntent;->access$getPerceptual$cp()I
+PLandroidx/compose/ui/graphics/colorspace/RenderIntent;->constructor-impl(I)I
+PLandroidx/compose/ui/graphics/colorspace/RenderIntent;->equals-impl0(II)Z
+PLandroidx/compose/ui/graphics/colorspace/Rgb$eotf$1;->invoke(D)Ljava/lang/Double;
+PLandroidx/compose/ui/graphics/colorspace/Rgb$eotf$1;->invoke(Ljava/lang/Object;)Ljava/lang/Object;
+PLandroidx/compose/ui/graphics/colorspace/Rgb$oetf$1;->invoke(D)Ljava/lang/Double;
+PLandroidx/compose/ui/graphics/colorspace/Rgb$oetf$1;->invoke(Ljava/lang/Object;)Ljava/lang/Object;
+PLandroidx/compose/ui/graphics/colorspace/Rgb;-><init>(Landroidx/compose/ui/graphics/colorspace/Rgb;[FLandroidx/compose/ui/graphics/colorspace/WhitePoint;)V
+PLandroidx/compose/ui/graphics/colorspace/Rgb;->access$getMax$p(Landroidx/compose/ui/graphics/colorspace/Rgb;)F
+PLandroidx/compose/ui/graphics/colorspace/Rgb;->access$getMin$p(Landroidx/compose/ui/graphics/colorspace/Rgb;)F
+PLandroidx/compose/ui/graphics/colorspace/Rgb;->fromXyz([F)[F
+PLandroidx/compose/ui/graphics/colorspace/Rgb;->getTransform$ui_graphics_release()[F
+PLandroidx/compose/ui/graphics/colorspace/Rgb;->getWhitePoint()Landroidx/compose/ui/graphics/colorspace/WhitePoint;
+PLandroidx/compose/ui/graphics/colorspace/Rgb;->toXyz([F)[F
+PLandroidx/compose/ui/graphics/colorspace/Xyz;->clamp(F)F
+PLandroidx/compose/ui/graphics/colorspace/Xyz;->fromXyz([F)[F
+PLandroidx/compose/ui/graphics/colorspace/Xyz;->getMaxValue(I)F
+PLandroidx/compose/ui/graphics/colorspace/Xyz;->getMinValue(I)F
+PLandroidx/compose/ui/graphics/drawscope/CanvasDrawScope;->configurePaint-swdJneE$default(Landroidx/compose/ui/graphics/drawscope/CanvasDrawScope;Landroidx/compose/ui/graphics/Brush;Landroidx/compose/ui/graphics/drawscope/DrawStyle;FLandroidx/compose/ui/graphics/ColorFilter;IIILjava/lang/Object;)Landroidx/compose/ui/graphics/Paint;
+PLandroidx/compose/ui/graphics/drawscope/CanvasDrawScope;->drawPath-GBMwjPU(Landroidx/compose/ui/graphics/Path;Landroidx/compose/ui/graphics/Brush;FLandroidx/compose/ui/graphics/drawscope/DrawStyle;Landroidx/compose/ui/graphics/ColorFilter;I)V
+PLandroidx/compose/ui/graphics/drawscope/CanvasDrawScopeKt$asDrawTransform$1;->transform-58bKbWc([F)V
+PLandroidx/compose/ui/graphics/drawscope/DrawScope;->drawPath-GBMwjPU$default(Landroidx/compose/ui/graphics/drawscope/DrawScope;Landroidx/compose/ui/graphics/Path;Landroidx/compose/ui/graphics/Brush;FLandroidx/compose/ui/graphics/drawscope/DrawStyle;Landroidx/compose/ui/graphics/ColorFilter;IILjava/lang/Object;)V
+PLandroidx/compose/ui/graphics/painter/BitmapPainter;->setFilterQuality-vDHp3xo$ui_graphics_release(I)V
+PLandroidx/compose/ui/graphics/painter/BitmapPainterKt;->BitmapPainter-QZhYCtY$default(Landroidx/compose/ui/graphics/ImageBitmap;JJIILjava/lang/Object;)Landroidx/compose/ui/graphics/painter/BitmapPainter;
+PLandroidx/compose/ui/graphics/painter/BitmapPainterKt;->BitmapPainter-QZhYCtY(Landroidx/compose/ui/graphics/ImageBitmap;JJI)Landroidx/compose/ui/graphics/painter/BitmapPainter;
+PLandroidx/compose/ui/graphics/vector/DrawCache;-><init>()V
+PLandroidx/compose/ui/graphics/vector/DrawCache;->clear(Landroidx/compose/ui/graphics/drawscope/DrawScope;)V
+PLandroidx/compose/ui/graphics/vector/DrawCache;->drawCachedImage-CJJAR-o(JLandroidx/compose/ui/unit/Density;Landroidx/compose/ui/unit/LayoutDirection;Lkotlin/jvm/functions/Function1;)V
+PLandroidx/compose/ui/graphics/vector/DrawCache;->drawInto(Landroidx/compose/ui/graphics/drawscope/DrawScope;FLandroidx/compose/ui/graphics/ColorFilter;)V
+PLandroidx/compose/ui/graphics/vector/GroupComponent;-><init>()V
+PLandroidx/compose/ui/graphics/vector/GroupComponent;->draw(Landroidx/compose/ui/graphics/drawscope/DrawScope;)V
+PLandroidx/compose/ui/graphics/vector/GroupComponent;->getInvalidateListener$ui_release()Lkotlin/jvm/functions/Function0;
+PLandroidx/compose/ui/graphics/vector/GroupComponent;->getNumChildren()I
+PLandroidx/compose/ui/graphics/vector/GroupComponent;->getWillClipPath()Z
+PLandroidx/compose/ui/graphics/vector/GroupComponent;->insertAt(ILandroidx/compose/ui/graphics/vector/VNode;)V
+PLandroidx/compose/ui/graphics/vector/GroupComponent;->remove(II)V
+PLandroidx/compose/ui/graphics/vector/GroupComponent;->setInvalidateListener$ui_release(Lkotlin/jvm/functions/Function0;)V
+PLandroidx/compose/ui/graphics/vector/GroupComponent;->setName(Ljava/lang/String;)V
+PLandroidx/compose/ui/graphics/vector/GroupComponent;->setPivotX(F)V
+PLandroidx/compose/ui/graphics/vector/GroupComponent;->setPivotY(F)V
+PLandroidx/compose/ui/graphics/vector/GroupComponent;->setScaleX(F)V
+PLandroidx/compose/ui/graphics/vector/GroupComponent;->setScaleY(F)V
+PLandroidx/compose/ui/graphics/vector/GroupComponent;->updateClipPath()V
+PLandroidx/compose/ui/graphics/vector/GroupComponent;->updateMatrix()V
+PLandroidx/compose/ui/graphics/vector/ImageVector$Builder$GroupParams;-><init>(Ljava/lang/String;FFFFFFFLjava/util/List;Ljava/util/List;)V
+PLandroidx/compose/ui/graphics/vector/ImageVector$Builder$GroupParams;-><init>(Ljava/lang/String;FFFFFFFLjava/util/List;Ljava/util/List;ILkotlin/jvm/internal/DefaultConstructorMarker;)V
+PLandroidx/compose/ui/graphics/vector/ImageVector$Builder$GroupParams;->getChildren()Ljava/util/List;
+PLandroidx/compose/ui/graphics/vector/ImageVector$Builder$GroupParams;->getClipPathData()Ljava/util/List;
+PLandroidx/compose/ui/graphics/vector/ImageVector$Builder$GroupParams;->getName()Ljava/lang/String;
+PLandroidx/compose/ui/graphics/vector/ImageVector$Builder$GroupParams;->getPivotX()F
+PLandroidx/compose/ui/graphics/vector/ImageVector$Builder$GroupParams;->getPivotY()F
+PLandroidx/compose/ui/graphics/vector/ImageVector$Builder$GroupParams;->getRotate()F
+PLandroidx/compose/ui/graphics/vector/ImageVector$Builder$GroupParams;->getScaleX()F
+PLandroidx/compose/ui/graphics/vector/ImageVector$Builder$GroupParams;->getScaleY()F
+PLandroidx/compose/ui/graphics/vector/ImageVector$Builder$GroupParams;->getTranslationX()F
+PLandroidx/compose/ui/graphics/vector/ImageVector$Builder$GroupParams;->getTranslationY()F
+PLandroidx/compose/ui/graphics/vector/ImageVector$Builder;-><clinit>()V
+PLandroidx/compose/ui/graphics/vector/ImageVector$Builder;-><init>(Ljava/lang/String;FFFFJIZ)V
+PLandroidx/compose/ui/graphics/vector/ImageVector$Builder;-><init>(Ljava/lang/String;FFFFJIZILkotlin/jvm/internal/DefaultConstructorMarker;)V
+PLandroidx/compose/ui/graphics/vector/ImageVector$Builder;-><init>(Ljava/lang/String;FFFFJIZLkotlin/jvm/internal/DefaultConstructorMarker;)V
+PLandroidx/compose/ui/graphics/vector/ImageVector$Builder;->addPath-oIyEayM$default(Landroidx/compose/ui/graphics/vector/ImageVector$Builder;Ljava/util/List;ILjava/lang/String;Landroidx/compose/ui/graphics/Brush;FLandroidx/compose/ui/graphics/Brush;FFIIFFFFILjava/lang/Object;)Landroidx/compose/ui/graphics/vector/ImageVector$Builder;
+PLandroidx/compose/ui/graphics/vector/ImageVector$Builder;->addPath-oIyEayM(Ljava/util/List;ILjava/lang/String;Landroidx/compose/ui/graphics/Brush;FLandroidx/compose/ui/graphics/Brush;FFIIFFFF)Landroidx/compose/ui/graphics/vector/ImageVector$Builder;
+PLandroidx/compose/ui/graphics/vector/ImageVector$Builder;->asVectorGroup(Landroidx/compose/ui/graphics/vector/ImageVector$Builder$GroupParams;)Landroidx/compose/ui/graphics/vector/VectorGroup;
+PLandroidx/compose/ui/graphics/vector/ImageVector$Builder;->build()Landroidx/compose/ui/graphics/vector/ImageVector;
+PLandroidx/compose/ui/graphics/vector/ImageVector$Builder;->ensureNotConsumed()V
+PLandroidx/compose/ui/graphics/vector/ImageVector$Builder;->getCurrentGroup()Landroidx/compose/ui/graphics/vector/ImageVector$Builder$GroupParams;
+PLandroidx/compose/ui/graphics/vector/ImageVector$Companion;-><init>()V
+PLandroidx/compose/ui/graphics/vector/ImageVector$Companion;-><init>(Lkotlin/jvm/internal/DefaultConstructorMarker;)V
+PLandroidx/compose/ui/graphics/vector/ImageVector;-><clinit>()V
+PLandroidx/compose/ui/graphics/vector/ImageVector;-><init>(Ljava/lang/String;FFFFLandroidx/compose/ui/graphics/vector/VectorGroup;JIZ)V
+PLandroidx/compose/ui/graphics/vector/ImageVector;-><init>(Ljava/lang/String;FFFFLandroidx/compose/ui/graphics/vector/VectorGroup;JIZLkotlin/jvm/internal/DefaultConstructorMarker;)V
+PLandroidx/compose/ui/graphics/vector/ImageVector;->equals(Ljava/lang/Object;)Z
+PLandroidx/compose/ui/graphics/vector/ImageVector;->getAutoMirror()Z
+PLandroidx/compose/ui/graphics/vector/ImageVector;->getDefaultHeight-D9Ej5fM()F
+PLandroidx/compose/ui/graphics/vector/ImageVector;->getDefaultWidth-D9Ej5fM()F
+PLandroidx/compose/ui/graphics/vector/ImageVector;->getName()Ljava/lang/String;
+PLandroidx/compose/ui/graphics/vector/ImageVector;->getRoot()Landroidx/compose/ui/graphics/vector/VectorGroup;
+PLandroidx/compose/ui/graphics/vector/ImageVector;->getTintBlendMode-0nO6VwU()I
+PLandroidx/compose/ui/graphics/vector/ImageVector;->getTintColor-0d7_KjU()J
+PLandroidx/compose/ui/graphics/vector/ImageVector;->getViewportHeight()F
+PLandroidx/compose/ui/graphics/vector/ImageVector;->getViewportWidth()F
+PLandroidx/compose/ui/graphics/vector/ImageVectorKt;->access$peek(Ljava/util/ArrayList;)Ljava/lang/Object;
+PLandroidx/compose/ui/graphics/vector/ImageVectorKt;->access$push(Ljava/util/ArrayList;Ljava/lang/Object;)Z
+PLandroidx/compose/ui/graphics/vector/ImageVectorKt;->peek(Ljava/util/ArrayList;)Ljava/lang/Object;
+PLandroidx/compose/ui/graphics/vector/ImageVectorKt;->push(Ljava/util/ArrayList;Ljava/lang/Object;)Z
+PLandroidx/compose/ui/graphics/vector/PathBuilder;-><init>()V
+PLandroidx/compose/ui/graphics/vector/PathBuilder;->addNode(Landroidx/compose/ui/graphics/vector/PathNode;)Landroidx/compose/ui/graphics/vector/PathBuilder;
+PLandroidx/compose/ui/graphics/vector/PathBuilder;->close()Landroidx/compose/ui/graphics/vector/PathBuilder;
+PLandroidx/compose/ui/graphics/vector/PathBuilder;->getNodes()Ljava/util/List;
+PLandroidx/compose/ui/graphics/vector/PathBuilder;->horizontalLineTo(F)Landroidx/compose/ui/graphics/vector/PathBuilder;
+PLandroidx/compose/ui/graphics/vector/PathBuilder;->horizontalLineToRelative(F)Landroidx/compose/ui/graphics/vector/PathBuilder;
+PLandroidx/compose/ui/graphics/vector/PathBuilder;->lineTo(FF)Landroidx/compose/ui/graphics/vector/PathBuilder;
+PLandroidx/compose/ui/graphics/vector/PathBuilder;->lineToRelative(FF)Landroidx/compose/ui/graphics/vector/PathBuilder;
+PLandroidx/compose/ui/graphics/vector/PathBuilder;->moveTo(FF)Landroidx/compose/ui/graphics/vector/PathBuilder;
+PLandroidx/compose/ui/graphics/vector/PathBuilder;->verticalLineTo(F)Landroidx/compose/ui/graphics/vector/PathBuilder;
+PLandroidx/compose/ui/graphics/vector/PathBuilder;->verticalLineToRelative(F)Landroidx/compose/ui/graphics/vector/PathBuilder;
+PLandroidx/compose/ui/graphics/vector/PathComponent$pathMeasure$2;-><clinit>()V
+PLandroidx/compose/ui/graphics/vector/PathComponent$pathMeasure$2;-><init>()V
+PLandroidx/compose/ui/graphics/vector/PathComponent;-><init>()V
+PLandroidx/compose/ui/graphics/vector/PathComponent;->draw(Landroidx/compose/ui/graphics/drawscope/DrawScope;)V
+PLandroidx/compose/ui/graphics/vector/PathComponent;->setFill(Landroidx/compose/ui/graphics/Brush;)V
+PLandroidx/compose/ui/graphics/vector/PathComponent;->setFillAlpha(F)V
+PLandroidx/compose/ui/graphics/vector/PathComponent;->setName(Ljava/lang/String;)V
+PLandroidx/compose/ui/graphics/vector/PathComponent;->setPathData(Ljava/util/List;)V
+PLandroidx/compose/ui/graphics/vector/PathComponent;->setPathFillType-oQ8Xj4U(I)V
+PLandroidx/compose/ui/graphics/vector/PathComponent;->setStroke(Landroidx/compose/ui/graphics/Brush;)V
+PLandroidx/compose/ui/graphics/vector/PathComponent;->setStrokeAlpha(F)V
+PLandroidx/compose/ui/graphics/vector/PathComponent;->setStrokeLineCap-BeK7IIE(I)V
+PLandroidx/compose/ui/graphics/vector/PathComponent;->setStrokeLineJoin-Ww9F2mQ(I)V
+PLandroidx/compose/ui/graphics/vector/PathComponent;->setStrokeLineMiter(F)V
+PLandroidx/compose/ui/graphics/vector/PathComponent;->setStrokeLineWidth(F)V
+PLandroidx/compose/ui/graphics/vector/PathComponent;->setTrimPathEnd(F)V
+PLandroidx/compose/ui/graphics/vector/PathComponent;->setTrimPathOffset(F)V
+PLandroidx/compose/ui/graphics/vector/PathComponent;->setTrimPathStart(F)V
+PLandroidx/compose/ui/graphics/vector/PathComponent;->updatePath()V
+PLandroidx/compose/ui/graphics/vector/PathComponent;->updateRenderPath()V
+PLandroidx/compose/ui/graphics/vector/PathNode$Close;-><clinit>()V
+PLandroidx/compose/ui/graphics/vector/PathNode$Close;-><init>()V
+PLandroidx/compose/ui/graphics/vector/PathNode$HorizontalTo;-><init>(F)V
+PLandroidx/compose/ui/graphics/vector/PathNode$HorizontalTo;->getX()F
+PLandroidx/compose/ui/graphics/vector/PathNode$LineTo;-><init>(FF)V
+PLandroidx/compose/ui/graphics/vector/PathNode$LineTo;->getX()F
+PLandroidx/compose/ui/graphics/vector/PathNode$LineTo;->getY()F
+PLandroidx/compose/ui/graphics/vector/PathNode$MoveTo;-><init>(FF)V
+PLandroidx/compose/ui/graphics/vector/PathNode$MoveTo;->getX()F
+PLandroidx/compose/ui/graphics/vector/PathNode$MoveTo;->getY()F
+PLandroidx/compose/ui/graphics/vector/PathNode$RelativeHorizontalTo;-><init>(F)V
+PLandroidx/compose/ui/graphics/vector/PathNode$RelativeHorizontalTo;->getDx()F
+PLandroidx/compose/ui/graphics/vector/PathNode$RelativeLineTo;-><init>(FF)V
+PLandroidx/compose/ui/graphics/vector/PathNode$RelativeLineTo;->getDx()F
+PLandroidx/compose/ui/graphics/vector/PathNode$RelativeLineTo;->getDy()F
+PLandroidx/compose/ui/graphics/vector/PathNode$RelativeVerticalTo;-><init>(F)V
+PLandroidx/compose/ui/graphics/vector/PathNode$RelativeVerticalTo;->getDy()F
+PLandroidx/compose/ui/graphics/vector/PathNode$VerticalTo;-><init>(F)V
+PLandroidx/compose/ui/graphics/vector/PathNode$VerticalTo;->getY()F
+PLandroidx/compose/ui/graphics/vector/PathNode;-><init>(ZZ)V
+PLandroidx/compose/ui/graphics/vector/PathNode;-><init>(ZZILkotlin/jvm/internal/DefaultConstructorMarker;)V
+PLandroidx/compose/ui/graphics/vector/PathNode;-><init>(ZZLkotlin/jvm/internal/DefaultConstructorMarker;)V
+PLandroidx/compose/ui/graphics/vector/PathParser$PathPoint;-><init>(FF)V
+PLandroidx/compose/ui/graphics/vector/PathParser$PathPoint;-><init>(FFILkotlin/jvm/internal/DefaultConstructorMarker;)V
+PLandroidx/compose/ui/graphics/vector/PathParser$PathPoint;->getX()F
+PLandroidx/compose/ui/graphics/vector/PathParser$PathPoint;->getY()F
+PLandroidx/compose/ui/graphics/vector/PathParser$PathPoint;->reset()V
+PLandroidx/compose/ui/graphics/vector/PathParser$PathPoint;->setX(F)V
+PLandroidx/compose/ui/graphics/vector/PathParser$PathPoint;->setY(F)V
+PLandroidx/compose/ui/graphics/vector/PathParser;-><init>()V
+PLandroidx/compose/ui/graphics/vector/PathParser;->addPathNodes(Ljava/util/List;)Landroidx/compose/ui/graphics/vector/PathParser;
+PLandroidx/compose/ui/graphics/vector/PathParser;->clear()V
+PLandroidx/compose/ui/graphics/vector/PathParser;->close(Landroidx/compose/ui/graphics/Path;)V
+PLandroidx/compose/ui/graphics/vector/PathParser;->horizontalTo(Landroidx/compose/ui/graphics/vector/PathNode$HorizontalTo;Landroidx/compose/ui/graphics/Path;)V
+PLandroidx/compose/ui/graphics/vector/PathParser;->lineTo(Landroidx/compose/ui/graphics/vector/PathNode$LineTo;Landroidx/compose/ui/graphics/Path;)V
+PLandroidx/compose/ui/graphics/vector/PathParser;->moveTo(Landroidx/compose/ui/graphics/vector/PathNode$MoveTo;Landroidx/compose/ui/graphics/Path;)V
+PLandroidx/compose/ui/graphics/vector/PathParser;->relativeHorizontalTo(Landroidx/compose/ui/graphics/vector/PathNode$RelativeHorizontalTo;Landroidx/compose/ui/graphics/Path;)V
+PLandroidx/compose/ui/graphics/vector/PathParser;->relativeLineTo(Landroidx/compose/ui/graphics/vector/PathNode$RelativeLineTo;Landroidx/compose/ui/graphics/Path;)V
+PLandroidx/compose/ui/graphics/vector/PathParser;->relativeVerticalTo(Landroidx/compose/ui/graphics/vector/PathNode$RelativeVerticalTo;Landroidx/compose/ui/graphics/Path;)V
+PLandroidx/compose/ui/graphics/vector/PathParser;->toPath(Landroidx/compose/ui/graphics/Path;)Landroidx/compose/ui/graphics/Path;
+PLandroidx/compose/ui/graphics/vector/PathParser;->verticalTo(Landroidx/compose/ui/graphics/vector/PathNode$VerticalTo;Landroidx/compose/ui/graphics/Path;)V
+PLandroidx/compose/ui/graphics/vector/VNode;-><clinit>()V
+PLandroidx/compose/ui/graphics/vector/VNode;-><init>()V
+PLandroidx/compose/ui/graphics/vector/VNode;-><init>(Lkotlin/jvm/internal/DefaultConstructorMarker;)V
+PLandroidx/compose/ui/graphics/vector/VNode;->getInvalidateListener$ui_release()Lkotlin/jvm/functions/Function0;
+PLandroidx/compose/ui/graphics/vector/VNode;->invalidate()V
+PLandroidx/compose/ui/graphics/vector/VNode;->setInvalidateListener$ui_release(Lkotlin/jvm/functions/Function0;)V
+PLandroidx/compose/ui/graphics/vector/VectorApplier;-><clinit>()V
+PLandroidx/compose/ui/graphics/vector/VectorApplier;-><init>(Landroidx/compose/ui/graphics/vector/VNode;)V
+PLandroidx/compose/ui/graphics/vector/VectorApplier;->asGroup(Landroidx/compose/ui/graphics/vector/VNode;)Landroidx/compose/ui/graphics/vector/GroupComponent;
+PLandroidx/compose/ui/graphics/vector/VectorApplier;->insertBottomUp(ILandroidx/compose/ui/graphics/vector/VNode;)V
+PLandroidx/compose/ui/graphics/vector/VectorApplier;->insertBottomUp(ILjava/lang/Object;)V
+PLandroidx/compose/ui/graphics/vector/VectorApplier;->insertTopDown(ILandroidx/compose/ui/graphics/vector/VNode;)V
+PLandroidx/compose/ui/graphics/vector/VectorApplier;->insertTopDown(ILjava/lang/Object;)V
+PLandroidx/compose/ui/graphics/vector/VectorApplier;->onClear()V
+PLandroidx/compose/ui/graphics/vector/VectorComponent$drawVectorBlock$1;-><init>(Landroidx/compose/ui/graphics/vector/VectorComponent;)V
+PLandroidx/compose/ui/graphics/vector/VectorComponent$drawVectorBlock$1;->invoke(Landroidx/compose/ui/graphics/drawscope/DrawScope;)V
+PLandroidx/compose/ui/graphics/vector/VectorComponent$drawVectorBlock$1;->invoke(Ljava/lang/Object;)Ljava/lang/Object;
+PLandroidx/compose/ui/graphics/vector/VectorComponent$invalidateCallback$1;-><clinit>()V
+PLandroidx/compose/ui/graphics/vector/VectorComponent$invalidateCallback$1;-><init>()V
+PLandroidx/compose/ui/graphics/vector/VectorComponent$root$1$1;-><init>(Landroidx/compose/ui/graphics/vector/VectorComponent;)V
+PLandroidx/compose/ui/graphics/vector/VectorComponent$root$1$1;->invoke()Ljava/lang/Object;
+PLandroidx/compose/ui/graphics/vector/VectorComponent$root$1$1;->invoke()V
+PLandroidx/compose/ui/graphics/vector/VectorComponent;-><init>()V
+PLandroidx/compose/ui/graphics/vector/VectorComponent;->access$doInvalidate(Landroidx/compose/ui/graphics/vector/VectorComponent;)V
+PLandroidx/compose/ui/graphics/vector/VectorComponent;->doInvalidate()V
+PLandroidx/compose/ui/graphics/vector/VectorComponent;->draw(Landroidx/compose/ui/graphics/drawscope/DrawScope;FLandroidx/compose/ui/graphics/ColorFilter;)V
+PLandroidx/compose/ui/graphics/vector/VectorComponent;->getRoot()Landroidx/compose/ui/graphics/vector/GroupComponent;
+PLandroidx/compose/ui/graphics/vector/VectorComponent;->getViewportHeight()F
+PLandroidx/compose/ui/graphics/vector/VectorComponent;->getViewportWidth()F
+PLandroidx/compose/ui/graphics/vector/VectorComponent;->setIntrinsicColorFilter$ui_release(Landroidx/compose/ui/graphics/ColorFilter;)V
+PLandroidx/compose/ui/graphics/vector/VectorComponent;->setInvalidateCallback$ui_release(Lkotlin/jvm/functions/Function0;)V
+PLandroidx/compose/ui/graphics/vector/VectorComponent;->setName(Ljava/lang/String;)V
+PLandroidx/compose/ui/graphics/vector/VectorComponent;->setViewportHeight(F)V
+PLandroidx/compose/ui/graphics/vector/VectorComponent;->setViewportWidth(F)V
+PLandroidx/compose/ui/graphics/vector/VectorComposeKt$Path$1;-><clinit>()V
+PLandroidx/compose/ui/graphics/vector/VectorComposeKt$Path$1;-><init>()V
+PLandroidx/compose/ui/graphics/vector/VectorComposeKt$Path$1;->invoke()Landroidx/compose/ui/graphics/vector/PathComponent;
+PLandroidx/compose/ui/graphics/vector/VectorComposeKt$Path$1;->invoke()Ljava/lang/Object;
+PLandroidx/compose/ui/graphics/vector/VectorComposeKt$Path$2$10;-><clinit>()V
+PLandroidx/compose/ui/graphics/vector/VectorComposeKt$Path$2$10;-><init>()V
+PLandroidx/compose/ui/graphics/vector/VectorComposeKt$Path$2$10;->invoke(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;
+PLandroidx/compose/ui/graphics/vector/VectorComposeKt$Path$2$10;->invoke-CSYIeUk(Landroidx/compose/ui/graphics/vector/PathComponent;I)V
+PLandroidx/compose/ui/graphics/vector/VectorComposeKt$Path$2$11;-><clinit>()V
+PLandroidx/compose/ui/graphics/vector/VectorComposeKt$Path$2$11;-><init>()V
+PLandroidx/compose/ui/graphics/vector/VectorComposeKt$Path$2$11;->invoke(Landroidx/compose/ui/graphics/vector/PathComponent;F)V
+PLandroidx/compose/ui/graphics/vector/VectorComposeKt$Path$2$11;->invoke(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;
+PLandroidx/compose/ui/graphics/vector/VectorComposeKt$Path$2$12;-><clinit>()V
+PLandroidx/compose/ui/graphics/vector/VectorComposeKt$Path$2$12;-><init>()V
+PLandroidx/compose/ui/graphics/vector/VectorComposeKt$Path$2$12;->invoke(Landroidx/compose/ui/graphics/vector/PathComponent;F)V
+PLandroidx/compose/ui/graphics/vector/VectorComposeKt$Path$2$12;->invoke(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;
+PLandroidx/compose/ui/graphics/vector/VectorComposeKt$Path$2$13;-><clinit>()V
+PLandroidx/compose/ui/graphics/vector/VectorComposeKt$Path$2$13;-><init>()V
+PLandroidx/compose/ui/graphics/vector/VectorComposeKt$Path$2$13;->invoke(Landroidx/compose/ui/graphics/vector/PathComponent;F)V
+PLandroidx/compose/ui/graphics/vector/VectorComposeKt$Path$2$13;->invoke(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;
+PLandroidx/compose/ui/graphics/vector/VectorComposeKt$Path$2$14;-><clinit>()V
+PLandroidx/compose/ui/graphics/vector/VectorComposeKt$Path$2$14;-><init>()V
+PLandroidx/compose/ui/graphics/vector/VectorComposeKt$Path$2$14;->invoke(Landroidx/compose/ui/graphics/vector/PathComponent;F)V
+PLandroidx/compose/ui/graphics/vector/VectorComposeKt$Path$2$14;->invoke(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;
+PLandroidx/compose/ui/graphics/vector/VectorComposeKt$Path$2$1;-><clinit>()V
+PLandroidx/compose/ui/graphics/vector/VectorComposeKt$Path$2$1;-><init>()V
+PLandroidx/compose/ui/graphics/vector/VectorComposeKt$Path$2$1;->invoke(Landroidx/compose/ui/graphics/vector/PathComponent;Ljava/lang/String;)V
+PLandroidx/compose/ui/graphics/vector/VectorComposeKt$Path$2$1;->invoke(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;
+PLandroidx/compose/ui/graphics/vector/VectorComposeKt$Path$2$2;-><clinit>()V
+PLandroidx/compose/ui/graphics/vector/VectorComposeKt$Path$2$2;-><init>()V
+PLandroidx/compose/ui/graphics/vector/VectorComposeKt$Path$2$2;->invoke(Landroidx/compose/ui/graphics/vector/PathComponent;Ljava/util/List;)V
+PLandroidx/compose/ui/graphics/vector/VectorComposeKt$Path$2$2;->invoke(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;
+PLandroidx/compose/ui/graphics/vector/VectorComposeKt$Path$2$3;-><clinit>()V
+PLandroidx/compose/ui/graphics/vector/VectorComposeKt$Path$2$3;-><init>()V
+PLandroidx/compose/ui/graphics/vector/VectorComposeKt$Path$2$3;->invoke(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;
+PLandroidx/compose/ui/graphics/vector/VectorComposeKt$Path$2$3;->invoke-pweu1eQ(Landroidx/compose/ui/graphics/vector/PathComponent;I)V
+PLandroidx/compose/ui/graphics/vector/VectorComposeKt$Path$2$4;-><clinit>()V
+PLandroidx/compose/ui/graphics/vector/VectorComposeKt$Path$2$4;-><init>()V
+PLandroidx/compose/ui/graphics/vector/VectorComposeKt$Path$2$4;->invoke(Landroidx/compose/ui/graphics/vector/PathComponent;Landroidx/compose/ui/graphics/Brush;)V
+PLandroidx/compose/ui/graphics/vector/VectorComposeKt$Path$2$4;->invoke(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;
+PLandroidx/compose/ui/graphics/vector/VectorComposeKt$Path$2$5;-><clinit>()V
+PLandroidx/compose/ui/graphics/vector/VectorComposeKt$Path$2$5;-><init>()V
+PLandroidx/compose/ui/graphics/vector/VectorComposeKt$Path$2$5;->invoke(Landroidx/compose/ui/graphics/vector/PathComponent;F)V
+PLandroidx/compose/ui/graphics/vector/VectorComposeKt$Path$2$5;->invoke(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;
+PLandroidx/compose/ui/graphics/vector/VectorComposeKt$Path$2$6;-><clinit>()V
+PLandroidx/compose/ui/graphics/vector/VectorComposeKt$Path$2$6;-><init>()V
+PLandroidx/compose/ui/graphics/vector/VectorComposeKt$Path$2$6;->invoke(Landroidx/compose/ui/graphics/vector/PathComponent;Landroidx/compose/ui/graphics/Brush;)V
+PLandroidx/compose/ui/graphics/vector/VectorComposeKt$Path$2$6;->invoke(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;
+PLandroidx/compose/ui/graphics/vector/VectorComposeKt$Path$2$7;-><clinit>()V
+PLandroidx/compose/ui/graphics/vector/VectorComposeKt$Path$2$7;-><init>()V
+PLandroidx/compose/ui/graphics/vector/VectorComposeKt$Path$2$7;->invoke(Landroidx/compose/ui/graphics/vector/PathComponent;F)V
+PLandroidx/compose/ui/graphics/vector/VectorComposeKt$Path$2$7;->invoke(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;
+PLandroidx/compose/ui/graphics/vector/VectorComposeKt$Path$2$8;-><clinit>()V
+PLandroidx/compose/ui/graphics/vector/VectorComposeKt$Path$2$8;-><init>()V
+PLandroidx/compose/ui/graphics/vector/VectorComposeKt$Path$2$8;->invoke(Landroidx/compose/ui/graphics/vector/PathComponent;F)V
+PLandroidx/compose/ui/graphics/vector/VectorComposeKt$Path$2$8;->invoke(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;
+PLandroidx/compose/ui/graphics/vector/VectorComposeKt$Path$2$9;-><clinit>()V
+PLandroidx/compose/ui/graphics/vector/VectorComposeKt$Path$2$9;-><init>()V
+PLandroidx/compose/ui/graphics/vector/VectorComposeKt$Path$2$9;->invoke(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;
+PLandroidx/compose/ui/graphics/vector/VectorComposeKt$Path$2$9;->invoke-kLtJ_vA(Landroidx/compose/ui/graphics/vector/PathComponent;I)V
+PLandroidx/compose/ui/graphics/vector/VectorComposeKt$Path-9cdaXJ4$$inlined$ComposeNode$1;-><init>(Lkotlin/jvm/functions/Function0;)V
+PLandroidx/compose/ui/graphics/vector/VectorComposeKt$Path-9cdaXJ4$$inlined$ComposeNode$1;->invoke()Ljava/lang/Object;
+PLandroidx/compose/ui/graphics/vector/VectorComposeKt;->Path-9cdaXJ4(Ljava/util/List;ILjava/lang/String;Landroidx/compose/ui/graphics/Brush;FLandroidx/compose/ui/graphics/Brush;FFIIFFFFLandroidx/compose/runtime/Composer;III)V
+PLandroidx/compose/ui/graphics/vector/VectorConfig;->getOrDefault(Landroidx/compose/ui/graphics/vector/VectorProperty;Ljava/lang/Object;)Ljava/lang/Object;
+PLandroidx/compose/ui/graphics/vector/VectorGroup$iterator$1;-><init>(Landroidx/compose/ui/graphics/vector/VectorGroup;)V
+PLandroidx/compose/ui/graphics/vector/VectorGroup$iterator$1;->hasNext()Z
+PLandroidx/compose/ui/graphics/vector/VectorGroup$iterator$1;->next()Landroidx/compose/ui/graphics/vector/VectorNode;
+PLandroidx/compose/ui/graphics/vector/VectorGroup$iterator$1;->next()Ljava/lang/Object;
+PLandroidx/compose/ui/graphics/vector/VectorGroup;-><init>(Ljava/lang/String;FFFFFFFLjava/util/List;Ljava/util/List;)V
+PLandroidx/compose/ui/graphics/vector/VectorGroup;->access$getChildren$p(Landroidx/compose/ui/graphics/vector/VectorGroup;)Ljava/util/List;
+PLandroidx/compose/ui/graphics/vector/VectorGroup;->iterator()Ljava/util/Iterator;
+PLandroidx/compose/ui/graphics/vector/VectorKt;-><clinit>()V
+PLandroidx/compose/ui/graphics/vector/VectorKt;->getDefaultFillType()I
+PLandroidx/compose/ui/graphics/vector/VectorKt;->getDefaultStrokeLineCap()I
+PLandroidx/compose/ui/graphics/vector/VectorKt;->getDefaultStrokeLineJoin()I
+PLandroidx/compose/ui/graphics/vector/VectorKt;->getEmptyPath()Ljava/util/List;
+PLandroidx/compose/ui/graphics/vector/VectorNode;-><clinit>()V
+PLandroidx/compose/ui/graphics/vector/VectorNode;-><init>()V
+PLandroidx/compose/ui/graphics/vector/VectorNode;-><init>(Lkotlin/jvm/internal/DefaultConstructorMarker;)V
+PLandroidx/compose/ui/graphics/vector/VectorPainter$RenderVector$2$invoke$$inlined$onDispose$1;-><init>(Landroidx/compose/runtime/Composition;)V
+PLandroidx/compose/ui/graphics/vector/VectorPainter$RenderVector$2$invoke$$inlined$onDispose$1;->dispose()V
+PLandroidx/compose/ui/graphics/vector/VectorPainter$RenderVector$2;-><init>(Landroidx/compose/runtime/Composition;)V
+PLandroidx/compose/ui/graphics/vector/VectorPainter$RenderVector$2;->invoke(Landroidx/compose/runtime/DisposableEffectScope;)Landroidx/compose/runtime/DisposableEffectResult;
+PLandroidx/compose/ui/graphics/vector/VectorPainter$RenderVector$2;->invoke(Ljava/lang/Object;)Ljava/lang/Object;
+PLandroidx/compose/ui/graphics/vector/VectorPainter$composeVector$1;-><init>(Lkotlin/jvm/functions/Function4;Landroidx/compose/ui/graphics/vector/VectorPainter;)V
+PLandroidx/compose/ui/graphics/vector/VectorPainter$composeVector$1;->invoke(Landroidx/compose/runtime/Composer;I)V
+PLandroidx/compose/ui/graphics/vector/VectorPainter$composeVector$1;->invoke(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;
+PLandroidx/compose/ui/graphics/vector/VectorPainter$vector$1$1;-><init>(Landroidx/compose/ui/graphics/vector/VectorPainter;)V
+PLandroidx/compose/ui/graphics/vector/VectorPainter$vector$1$1;->invoke()Ljava/lang/Object;
+PLandroidx/compose/ui/graphics/vector/VectorPainter$vector$1$1;->invoke()V
+PLandroidx/compose/ui/graphics/vector/VectorPainter;-><clinit>()V
+PLandroidx/compose/ui/graphics/vector/VectorPainter;-><init>()V
+PLandroidx/compose/ui/graphics/vector/VectorPainter;->RenderVector$ui_release(Ljava/lang/String;FFLkotlin/jvm/functions/Function4;Landroidx/compose/runtime/Composer;I)V
+PLandroidx/compose/ui/graphics/vector/VectorPainter;->access$getVector$p(Landroidx/compose/ui/graphics/vector/VectorPainter;)Landroidx/compose/ui/graphics/vector/VectorComponent;
+PLandroidx/compose/ui/graphics/vector/VectorPainter;->access$setDirty(Landroidx/compose/ui/graphics/vector/VectorPainter;Z)V
+PLandroidx/compose/ui/graphics/vector/VectorPainter;->applyColorFilter(Landroidx/compose/ui/graphics/ColorFilter;)Z
+PLandroidx/compose/ui/graphics/vector/VectorPainter;->composeVector(Landroidx/compose/runtime/CompositionContext;Lkotlin/jvm/functions/Function4;)Landroidx/compose/runtime/Composition;
+PLandroidx/compose/ui/graphics/vector/VectorPainter;->getAutoMirror$ui_release()Z
+PLandroidx/compose/ui/graphics/vector/VectorPainter;->getIntrinsicSize-NH-jbRc()J
+PLandroidx/compose/ui/graphics/vector/VectorPainter;->getSize-NH-jbRc$ui_release()J
+PLandroidx/compose/ui/graphics/vector/VectorPainter;->isDirty()Z
+PLandroidx/compose/ui/graphics/vector/VectorPainter;->onDraw(Landroidx/compose/ui/graphics/drawscope/DrawScope;)V
+PLandroidx/compose/ui/graphics/vector/VectorPainter;->setAutoMirror$ui_release(Z)V
+PLandroidx/compose/ui/graphics/vector/VectorPainter;->setDirty(Z)V
+PLandroidx/compose/ui/graphics/vector/VectorPainter;->setIntrinsicColorFilter$ui_release(Landroidx/compose/ui/graphics/ColorFilter;)V
+PLandroidx/compose/ui/graphics/vector/VectorPainter;->setSize-uvyYCjk$ui_release(J)V
+PLandroidx/compose/ui/graphics/vector/VectorPainterKt$RenderVectorGroup$config$1;-><init>()V
+PLandroidx/compose/ui/graphics/vector/VectorPainterKt$rememberVectorPainter$3;-><init>(Landroidx/compose/ui/graphics/vector/ImageVector;)V
+PLandroidx/compose/ui/graphics/vector/VectorPainterKt$rememberVectorPainter$3;->invoke(FFLandroidx/compose/runtime/Composer;I)V
+PLandroidx/compose/ui/graphics/vector/VectorPainterKt$rememberVectorPainter$3;->invoke(Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;
+PLandroidx/compose/ui/graphics/vector/VectorPainterKt;->RenderVectorGroup(Landroidx/compose/ui/graphics/vector/VectorGroup;Ljava/util/Map;Landroidx/compose/runtime/Composer;II)V
+PLandroidx/compose/ui/graphics/vector/VectorPainterKt;->rememberVectorPainter(Landroidx/compose/ui/graphics/vector/ImageVector;Landroidx/compose/runtime/Composer;I)Landroidx/compose/ui/graphics/vector/VectorPainter;
+PLandroidx/compose/ui/graphics/vector/VectorPainterKt;->rememberVectorPainter-vIP8VLU(FFFFLjava/lang/String;JIZLkotlin/jvm/functions/Function4;Landroidx/compose/runtime/Composer;II)Landroidx/compose/ui/graphics/vector/VectorPainter;
+PLandroidx/compose/ui/graphics/vector/VectorPath;-><init>(Ljava/lang/String;Ljava/util/List;ILandroidx/compose/ui/graphics/Brush;FLandroidx/compose/ui/graphics/Brush;FFIIFFFF)V
+PLandroidx/compose/ui/graphics/vector/VectorPath;-><init>(Ljava/lang/String;Ljava/util/List;ILandroidx/compose/ui/graphics/Brush;FLandroidx/compose/ui/graphics/Brush;FFIIFFFFLkotlin/jvm/internal/DefaultConstructorMarker;)V
+PLandroidx/compose/ui/graphics/vector/VectorPath;->getFill()Landroidx/compose/ui/graphics/Brush;
+PLandroidx/compose/ui/graphics/vector/VectorPath;->getFillAlpha()F
+PLandroidx/compose/ui/graphics/vector/VectorPath;->getName()Ljava/lang/String;
+PLandroidx/compose/ui/graphics/vector/VectorPath;->getPathData()Ljava/util/List;
+PLandroidx/compose/ui/graphics/vector/VectorPath;->getPathFillType-Rg-k1Os()I
+PLandroidx/compose/ui/graphics/vector/VectorPath;->getStroke()Landroidx/compose/ui/graphics/Brush;
+PLandroidx/compose/ui/graphics/vector/VectorPath;->getStrokeAlpha()F
+PLandroidx/compose/ui/graphics/vector/VectorPath;->getStrokeLineCap-KaPHkGw()I
+PLandroidx/compose/ui/graphics/vector/VectorPath;->getStrokeLineJoin-LxFBmk8()I
+PLandroidx/compose/ui/graphics/vector/VectorPath;->getStrokeLineMiter()F
+PLandroidx/compose/ui/graphics/vector/VectorPath;->getStrokeLineWidth()F
+PLandroidx/compose/ui/graphics/vector/VectorPath;->getTrimPathEnd()F
+PLandroidx/compose/ui/graphics/vector/VectorPath;->getTrimPathOffset()F
+PLandroidx/compose/ui/graphics/vector/VectorPath;->getTrimPathStart()F
+PLandroidx/compose/ui/graphics/vector/VectorProperty$Fill;-><clinit>()V
+PLandroidx/compose/ui/graphics/vector/VectorProperty$Fill;-><init>()V
+PLandroidx/compose/ui/graphics/vector/VectorProperty$FillAlpha;-><clinit>()V
+PLandroidx/compose/ui/graphics/vector/VectorProperty$FillAlpha;-><init>()V
+PLandroidx/compose/ui/graphics/vector/VectorProperty$PathData;-><clinit>()V
+PLandroidx/compose/ui/graphics/vector/VectorProperty$PathData;-><init>()V
+PLandroidx/compose/ui/graphics/vector/VectorProperty$Stroke;-><clinit>()V
+PLandroidx/compose/ui/graphics/vector/VectorProperty$Stroke;-><init>()V
+PLandroidx/compose/ui/graphics/vector/VectorProperty$StrokeAlpha;-><clinit>()V
+PLandroidx/compose/ui/graphics/vector/VectorProperty$StrokeAlpha;-><init>()V
+PLandroidx/compose/ui/graphics/vector/VectorProperty$StrokeLineWidth;-><clinit>()V
+PLandroidx/compose/ui/graphics/vector/VectorProperty$StrokeLineWidth;-><init>()V
+PLandroidx/compose/ui/graphics/vector/VectorProperty$TrimPathEnd;-><clinit>()V
+PLandroidx/compose/ui/graphics/vector/VectorProperty$TrimPathEnd;-><init>()V
+PLandroidx/compose/ui/graphics/vector/VectorProperty$TrimPathOffset;-><clinit>()V
+PLandroidx/compose/ui/graphics/vector/VectorProperty$TrimPathOffset;-><init>()V
+PLandroidx/compose/ui/graphics/vector/VectorProperty$TrimPathStart;-><clinit>()V
+PLandroidx/compose/ui/graphics/vector/VectorProperty$TrimPathStart;-><init>()V
+PLandroidx/compose/ui/graphics/vector/VectorProperty;-><clinit>()V
+PLandroidx/compose/ui/graphics/vector/VectorProperty;-><init>()V
+PLandroidx/compose/ui/graphics/vector/VectorProperty;-><init>(Lkotlin/jvm/internal/DefaultConstructorMarker;)V
+PLandroidx/compose/ui/input/ScrollContainerInfoKt$provideScrollContainerInfo$2;-><init>(Landroidx/compose/ui/input/ScrollContainerInfo;)V
+PLandroidx/compose/ui/input/ScrollContainerInfoKt$provideScrollContainerInfo$2;->invoke(Landroidx/compose/ui/Modifier;Landroidx/compose/runtime/Composer;I)Landroidx/compose/ui/Modifier;
+PLandroidx/compose/ui/input/ScrollContainerInfoKt$provideScrollContainerInfo$2;->invoke(Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;
+PLandroidx/compose/ui/input/ScrollContainerInfoKt;->canScroll(Landroidx/compose/ui/input/ScrollContainerInfo;)Z
+PLandroidx/compose/ui/input/ScrollContainerInfoKt;->provideScrollContainerInfo(Landroidx/compose/ui/Modifier;Landroidx/compose/ui/input/ScrollContainerInfo;)Landroidx/compose/ui/Modifier;
+PLandroidx/compose/ui/input/ScrollContainerInfoModifierLocal;-><init>(Landroidx/compose/ui/input/ScrollContainerInfo;)V
+PLandroidx/compose/ui/input/ScrollContainerInfoModifierLocal;->canScrollVertically()Z
+PLandroidx/compose/ui/input/ScrollContainerInfoModifierLocal;->getKey()Landroidx/compose/ui/modifier/ProvidableModifierLocal;
+PLandroidx/compose/ui/input/ScrollContainerInfoModifierLocal;->getValue()Landroidx/compose/ui/input/ScrollContainerInfoModifierLocal;
+PLandroidx/compose/ui/input/ScrollContainerInfoModifierLocal;->getValue()Ljava/lang/Object;
+PLandroidx/compose/ui/input/ScrollContainerInfoModifierLocal;->onModifierLocalsUpdated(Landroidx/compose/ui/modifier/ModifierLocalReadScope;)V
+PLandroidx/compose/ui/input/ScrollContainerInfoModifierLocal;->setParent(Landroidx/compose/ui/input/ScrollContainerInfo;)V
+PLandroidx/compose/ui/input/nestedscroll/NestedScrollDispatcher$dispatchPostFling$1;-><init>(Landroidx/compose/ui/input/nestedscroll/NestedScrollDispatcher;Lkotlin/coroutines/Continuation;)V
+PLandroidx/compose/ui/input/nestedscroll/NestedScrollDispatcher$dispatchPostFling$1;->invokeSuspend(Ljava/lang/Object;)Ljava/lang/Object;
+PLandroidx/compose/ui/input/nestedscroll/NestedScrollDispatcher$dispatchPreFling$1;-><init>(Landroidx/compose/ui/input/nestedscroll/NestedScrollDispatcher;Lkotlin/coroutines/Continuation;)V
+PLandroidx/compose/ui/input/nestedscroll/NestedScrollDispatcher;->dispatchPostFling-RZ2iAVY(JJLkotlin/coroutines/Continuation;)Ljava/lang/Object;
+PLandroidx/compose/ui/input/nestedscroll/NestedScrollDispatcher;->dispatchPostScroll-DzOQY0M(JJI)J
+PLandroidx/compose/ui/input/nestedscroll/NestedScrollDispatcher;->dispatchPreFling-QWom1Mo(JLkotlin/coroutines/Continuation;)Ljava/lang/Object;
+PLandroidx/compose/ui/input/nestedscroll/NestedScrollDispatcher;->dispatchPreScroll-OzD1aCk(JI)J
+PLandroidx/compose/ui/input/nestedscroll/NestedScrollDispatcher;->getCoroutineScope()Lkotlinx/coroutines/CoroutineScope;
+PLandroidx/compose/ui/input/nestedscroll/NestedScrollDispatcher;->getOriginNestedScrollScope$ui_release()Lkotlinx/coroutines/CoroutineScope;
+PLandroidx/compose/ui/input/nestedscroll/NestedScrollModifierLocal$1;->invoke()Ljava/lang/Object;
+PLandroidx/compose/ui/input/nestedscroll/NestedScrollModifierLocal$1;->invoke()Lkotlinx/coroutines/CoroutineScope;
+PLandroidx/compose/ui/input/nestedscroll/NestedScrollModifierLocal$onPostFling$1;-><init>(Landroidx/compose/ui/input/nestedscroll/NestedScrollModifierLocal;Lkotlin/coroutines/Continuation;)V
+PLandroidx/compose/ui/input/nestedscroll/NestedScrollModifierLocal$onPostFling$1;->invokeSuspend(Ljava/lang/Object;)Ljava/lang/Object;
+PLandroidx/compose/ui/input/nestedscroll/NestedScrollModifierLocal$onPreFling$1;-><init>(Landroidx/compose/ui/input/nestedscroll/NestedScrollModifierLocal;Lkotlin/coroutines/Continuation;)V
+PLandroidx/compose/ui/input/nestedscroll/NestedScrollModifierLocal;->access$getNestedCoroutineScope(Landroidx/compose/ui/input/nestedscroll/NestedScrollModifierLocal;)Lkotlinx/coroutines/CoroutineScope;
+PLandroidx/compose/ui/input/nestedscroll/NestedScrollModifierLocal;->getNestedCoroutineScope()Lkotlinx/coroutines/CoroutineScope;
+PLandroidx/compose/ui/input/nestedscroll/NestedScrollModifierLocal;->getValue()Landroidx/compose/ui/input/nestedscroll/NestedScrollModifierLocal;
+PLandroidx/compose/ui/input/nestedscroll/NestedScrollModifierLocal;->getValue()Ljava/lang/Object;
+PLandroidx/compose/ui/input/nestedscroll/NestedScrollModifierLocal;->onPostFling-RZ2iAVY(JJLkotlin/coroutines/Continuation;)Ljava/lang/Object;
+PLandroidx/compose/ui/input/nestedscroll/NestedScrollModifierLocal;->onPostScroll-DzOQY0M(JJI)J
+PLandroidx/compose/ui/input/nestedscroll/NestedScrollModifierLocal;->onPreFling-QWom1Mo(JLkotlin/coroutines/Continuation;)Ljava/lang/Object;
+PLandroidx/compose/ui/input/nestedscroll/NestedScrollModifierLocal;->onPreScroll-OzD1aCk(JI)J
+PLandroidx/compose/ui/input/nestedscroll/NestedScrollSource$Companion;-><init>()V
+PLandroidx/compose/ui/input/nestedscroll/NestedScrollSource$Companion;-><init>(Lkotlin/jvm/internal/DefaultConstructorMarker;)V
+PLandroidx/compose/ui/input/nestedscroll/NestedScrollSource$Companion;->getDrag-WNlRxjI()I
+PLandroidx/compose/ui/input/nestedscroll/NestedScrollSource$Companion;->getFling-WNlRxjI()I
+PLandroidx/compose/ui/input/nestedscroll/NestedScrollSource;-><clinit>()V
+PLandroidx/compose/ui/input/nestedscroll/NestedScrollSource;->access$getDrag$cp()I
+PLandroidx/compose/ui/input/nestedscroll/NestedScrollSource;->access$getFling$cp()I
+PLandroidx/compose/ui/input/nestedscroll/NestedScrollSource;->constructor-impl(I)I
+PLandroidx/compose/ui/input/nestedscroll/NestedScrollSource;->equals-impl0(II)Z
+PLandroidx/compose/ui/input/pointer/ConsumedData;-><clinit>()V
+PLandroidx/compose/ui/input/pointer/ConsumedData;-><init>(ZZ)V
+PLandroidx/compose/ui/input/pointer/ConsumedData;->getDownChange()Z
+PLandroidx/compose/ui/input/pointer/ConsumedData;->getPositionChange()Z
+PLandroidx/compose/ui/input/pointer/ConsumedData;->setDownChange(Z)V
+PLandroidx/compose/ui/input/pointer/ConsumedData;->setPositionChange(Z)V
+PLandroidx/compose/ui/input/pointer/HistoricalChange;-><init>(JJ)V
+PLandroidx/compose/ui/input/pointer/HistoricalChange;-><init>(JJLkotlin/jvm/internal/DefaultConstructorMarker;)V
+PLandroidx/compose/ui/input/pointer/HistoricalChange;->getPosition-F1C5BW0()J
+PLandroidx/compose/ui/input/pointer/HistoricalChange;->getUptimeMillis()J
+PLandroidx/compose/ui/input/pointer/HitPathTracker;->addHitPath-KNwqfcY(JLjava/util/List;)V
+PLandroidx/compose/ui/input/pointer/HitPathTracker;->dispatchChanges(Landroidx/compose/ui/input/pointer/InternalPointerEvent;Z)Z
+PLandroidx/compose/ui/input/pointer/HitPathTracker;->processCancel()V
+PLandroidx/compose/ui/input/pointer/HitPathTracker;->removeDetachedPointerInputFilters()V
+PLandroidx/compose/ui/input/pointer/InternalPointerEvent;-><init>(Ljava/util/Map;Landroidx/compose/ui/input/pointer/PointerInputEvent;)V
+PLandroidx/compose/ui/input/pointer/InternalPointerEvent;->getChanges()Ljava/util/Map;
+PLandroidx/compose/ui/input/pointer/InternalPointerEvent;->getMotionEvent()Landroid/view/MotionEvent;
+PLandroidx/compose/ui/input/pointer/InternalPointerEvent;->getSuppressMovementConsumption()Z
+PLandroidx/compose/ui/input/pointer/MotionEventAdapter;->addFreshIds(Landroid/view/MotionEvent;)V
+PLandroidx/compose/ui/input/pointer/MotionEventAdapter;->clearOnDeviceChange(Landroid/view/MotionEvent;)V
+PLandroidx/compose/ui/input/pointer/MotionEventAdapter;->endStream(I)V
+PLandroidx/compose/ui/input/pointer/MotionEventAdapter;->getComposePointerId-_I2yYro(I)J
+PLandroidx/compose/ui/input/pointer/MotionEventAdapter;->removeStaleIds(Landroid/view/MotionEvent;)V
+PLandroidx/compose/ui/input/pointer/Node;-><init>(Landroidx/compose/ui/node/PointerInputModifierNode;)V
+PLandroidx/compose/ui/input/pointer/Node;->clearCache()V
+PLandroidx/compose/ui/input/pointer/Node;->dispatchCancel()V
+PLandroidx/compose/ui/input/pointer/Node;->getPointerIds()Landroidx/compose/runtime/collection/MutableVector;
+PLandroidx/compose/ui/input/pointer/Node;->getPointerInputNode()Landroidx/compose/ui/node/PointerInputModifierNode;
+PLandroidx/compose/ui/input/pointer/Node;->hasPositionChanged(Landroidx/compose/ui/input/pointer/PointerEvent;Landroidx/compose/ui/input/pointer/PointerEvent;)Z
+PLandroidx/compose/ui/input/pointer/NodeParent;->buildCache(Ljava/util/Map;Landroidx/compose/ui/layout/LayoutCoordinates;Landroidx/compose/ui/input/pointer/InternalPointerEvent;Z)Z
+PLandroidx/compose/ui/input/pointer/NodeParent;->cleanUpHits(Landroidx/compose/ui/input/pointer/InternalPointerEvent;)V
+PLandroidx/compose/ui/input/pointer/NodeParent;->clear()V
+PLandroidx/compose/ui/input/pointer/NodeParent;->dispatchCancel()V
+PLandroidx/compose/ui/input/pointer/NodeParent;->dispatchFinalEventPass(Landroidx/compose/ui/input/pointer/InternalPointerEvent;)Z
+PLandroidx/compose/ui/input/pointer/NodeParent;->dispatchMainEventPass(Ljava/util/Map;Landroidx/compose/ui/layout/LayoutCoordinates;Landroidx/compose/ui/input/pointer/InternalPointerEvent;Z)Z
+PLandroidx/compose/ui/input/pointer/NodeParent;->getChildren()Landroidx/compose/runtime/collection/MutableVector;
+PLandroidx/compose/ui/input/pointer/NodeParent;->removeDetachedPointerInputFilters()V
+PLandroidx/compose/ui/input/pointer/PointerEvent;->getChanges()Ljava/util/List;
+PLandroidx/compose/ui/input/pointer/PointerEvent;->getType-7fucELk()I
+PLandroidx/compose/ui/input/pointer/PointerEventKt;->changedToDown(Landroidx/compose/ui/input/pointer/PointerInputChange;)Z
+PLandroidx/compose/ui/input/pointer/PointerEventKt;->changedToDownIgnoreConsumed(Landroidx/compose/ui/input/pointer/PointerInputChange;)Z
+PLandroidx/compose/ui/input/pointer/PointerEventKt;->changedToUp(Landroidx/compose/ui/input/pointer/PointerInputChange;)Z
+PLandroidx/compose/ui/input/pointer/PointerEventKt;->changedToUpIgnoreConsumed(Landroidx/compose/ui/input/pointer/PointerInputChange;)Z
+PLandroidx/compose/ui/input/pointer/PointerEventKt;->isOutOfBounds-jwHxaWs(Landroidx/compose/ui/input/pointer/PointerInputChange;JJ)Z
+PLandroidx/compose/ui/input/pointer/PointerEventKt;->positionChange(Landroidx/compose/ui/input/pointer/PointerInputChange;)J
+PLandroidx/compose/ui/input/pointer/PointerEventKt;->positionChangeIgnoreConsumed(Landroidx/compose/ui/input/pointer/PointerInputChange;)J
+PLandroidx/compose/ui/input/pointer/PointerEventKt;->positionChangeInternal(Landroidx/compose/ui/input/pointer/PointerInputChange;Z)J
+PLandroidx/compose/ui/input/pointer/PointerEventKt;->positionChangedIgnoreConsumed(Landroidx/compose/ui/input/pointer/PointerInputChange;)Z
+PLandroidx/compose/ui/input/pointer/PointerEventPass;->values()[Landroidx/compose/ui/input/pointer/PointerEventPass;
+PLandroidx/compose/ui/input/pointer/PointerEventType$Companion;->getEnter-7fucELk()I
+PLandroidx/compose/ui/input/pointer/PointerEventType$Companion;->getExit-7fucELk()I
+PLandroidx/compose/ui/input/pointer/PointerEventType$Companion;->getPress-7fucELk()I
+PLandroidx/compose/ui/input/pointer/PointerEventType$Companion;->getRelease-7fucELk()I
+PLandroidx/compose/ui/input/pointer/PointerEventType$Companion;->getScroll-7fucELk()I
+PLandroidx/compose/ui/input/pointer/PointerEventType;->access$getEnter$cp()I
+PLandroidx/compose/ui/input/pointer/PointerEventType;->access$getExit$cp()I
+PLandroidx/compose/ui/input/pointer/PointerEventType;->access$getPress$cp()I
+PLandroidx/compose/ui/input/pointer/PointerEventType;->access$getRelease$cp()I
+PLandroidx/compose/ui/input/pointer/PointerEventType;->access$getScroll$cp()I
+PLandroidx/compose/ui/input/pointer/PointerEventType;->equals-impl0(II)Z
+PLandroidx/compose/ui/input/pointer/PointerId;->box-impl(J)Landroidx/compose/ui/input/pointer/PointerId;
+PLandroidx/compose/ui/input/pointer/PointerId;->constructor-impl(J)J
+PLandroidx/compose/ui/input/pointer/PointerId;->equals(Ljava/lang/Object;)Z
+PLandroidx/compose/ui/input/pointer/PointerId;->equals-impl0(JJ)Z
+PLandroidx/compose/ui/input/pointer/PointerId;->hashCode()I
+PLandroidx/compose/ui/input/pointer/PointerId;->hashCode-impl(J)I
+PLandroidx/compose/ui/input/pointer/PointerId;->unbox-impl()J
+PLandroidx/compose/ui/input/pointer/PointerInputChange;-><init>(JJJZFJJZZIJ)V
+PLandroidx/compose/ui/input/pointer/PointerInputChange;-><init>(JJJZFJJZZIJILkotlin/jvm/internal/DefaultConstructorMarker;)V
+PLandroidx/compose/ui/input/pointer/PointerInputChange;-><init>(JJJZFJJZZIJLkotlin/jvm/internal/DefaultConstructorMarker;)V
+PLandroidx/compose/ui/input/pointer/PointerInputChange;-><init>(JJJZFJJZZILjava/util/List;J)V
+PLandroidx/compose/ui/input/pointer/PointerInputChange;-><init>(JJJZFJJZZILjava/util/List;JLkotlin/jvm/internal/DefaultConstructorMarker;)V
+PLandroidx/compose/ui/input/pointer/PointerInputChange;-><init>(JJJZJJZZIJLkotlin/jvm/internal/DefaultConstructorMarker;)V
+PLandroidx/compose/ui/input/pointer/PointerInputChange;->consume()V
+PLandroidx/compose/ui/input/pointer/PointerInputChange;->getHistorical()Ljava/util/List;
+PLandroidx/compose/ui/input/pointer/PointerInputChange;->getId-J3iCeTQ()J
+PLandroidx/compose/ui/input/pointer/PointerInputChange;->getPosition-F1C5BW0()J
+PLandroidx/compose/ui/input/pointer/PointerInputChange;->getPressed()Z
+PLandroidx/compose/ui/input/pointer/PointerInputChange;->getPressure()F
+PLandroidx/compose/ui/input/pointer/PointerInputChange;->getPreviousPosition-F1C5BW0()J
+PLandroidx/compose/ui/input/pointer/PointerInputChange;->getPreviousPressed()Z
+PLandroidx/compose/ui/input/pointer/PointerInputChange;->getType-T8wyACA()I
+PLandroidx/compose/ui/input/pointer/PointerInputChange;->getUptimeMillis()J
+PLandroidx/compose/ui/input/pointer/PointerInputChange;->isConsumed()Z
+PLandroidx/compose/ui/input/pointer/PointerInputChangeEventProducer$PointerInputData;-><init>(JJZI)V
+PLandroidx/compose/ui/input/pointer/PointerInputChangeEventProducer$PointerInputData;-><init>(JJZILkotlin/jvm/internal/DefaultConstructorMarker;)V
+PLandroidx/compose/ui/input/pointer/PointerInputChangeEventProducer$PointerInputData;->getDown()Z
+PLandroidx/compose/ui/input/pointer/PointerInputChangeEventProducer$PointerInputData;->getPositionOnScreen-F1C5BW0()J
+PLandroidx/compose/ui/input/pointer/PointerInputChangeEventProducer$PointerInputData;->getUptime()J
+PLandroidx/compose/ui/input/pointer/PointerInputChangeEventProducer;->clear()V
+PLandroidx/compose/ui/input/pointer/PointerInputEvent;-><init>(JLjava/util/List;Landroid/view/MotionEvent;)V
+PLandroidx/compose/ui/input/pointer/PointerInputEvent;->getMotionEvent()Landroid/view/MotionEvent;
+PLandroidx/compose/ui/input/pointer/PointerInputEvent;->getPointers()Ljava/util/List;
+PLandroidx/compose/ui/input/pointer/PointerInputEventData;-><init>(JJJJZFIZLjava/util/List;J)V
+PLandroidx/compose/ui/input/pointer/PointerInputEventData;-><init>(JJJJZFIZLjava/util/List;JLkotlin/jvm/internal/DefaultConstructorMarker;)V
+PLandroidx/compose/ui/input/pointer/PointerInputEventData;->getDown()Z
+PLandroidx/compose/ui/input/pointer/PointerInputEventData;->getHistorical()Ljava/util/List;
+PLandroidx/compose/ui/input/pointer/PointerInputEventData;->getId-J3iCeTQ()J
+PLandroidx/compose/ui/input/pointer/PointerInputEventData;->getIssuesEnterExit()Z
+PLandroidx/compose/ui/input/pointer/PointerInputEventData;->getPosition-F1C5BW0()J
+PLandroidx/compose/ui/input/pointer/PointerInputEventData;->getPositionOnScreen-F1C5BW0()J
+PLandroidx/compose/ui/input/pointer/PointerInputEventData;->getPressure()F
+PLandroidx/compose/ui/input/pointer/PointerInputEventData;->getScrollDelta-F1C5BW0()J
+PLandroidx/compose/ui/input/pointer/PointerInputEventData;->getType-T8wyACA()I
+PLandroidx/compose/ui/input/pointer/PointerInputEventData;->getUptime()J
+PLandroidx/compose/ui/input/pointer/PointerInputEventProcessor;->processCancel()V
+PLandroidx/compose/ui/input/pointer/PointerInputEventProcessorKt;->ProcessResult(ZZ)I
+PLandroidx/compose/ui/input/pointer/PointerInputFilter;->getShareWithSiblings()Z
+PLandroidx/compose/ui/input/pointer/PointerKeyboardModifiers;->equals(Ljava/lang/Object;)Z
+PLandroidx/compose/ui/input/pointer/PointerKeyboardModifiers;->equals-impl(ILjava/lang/Object;)Z
+PLandroidx/compose/ui/input/pointer/PointerKeyboardModifiers;->unbox-impl()I
+PLandroidx/compose/ui/input/pointer/PointerType$Companion;-><init>()V
+PLandroidx/compose/ui/input/pointer/PointerType$Companion;-><init>(Lkotlin/jvm/internal/DefaultConstructorMarker;)V
+PLandroidx/compose/ui/input/pointer/PointerType$Companion;->getMouse-T8wyACA()I
+PLandroidx/compose/ui/input/pointer/PointerType$Companion;->getTouch-T8wyACA()I
+PLandroidx/compose/ui/input/pointer/PointerType;-><clinit>()V
+PLandroidx/compose/ui/input/pointer/PointerType;->access$getMouse$cp()I
+PLandroidx/compose/ui/input/pointer/PointerType;->access$getTouch$cp()I
+PLandroidx/compose/ui/input/pointer/PointerType;->constructor-impl(I)I
+PLandroidx/compose/ui/input/pointer/PointerType;->equals-impl0(II)Z
+PLandroidx/compose/ui/input/pointer/ProcessResult;->constructor-impl(I)I
+PLandroidx/compose/ui/input/pointer/ProcessResult;->getAnyMovementConsumed-impl(I)Z
+PLandroidx/compose/ui/input/pointer/ProcessResult;->getDispatchedToAPointerInputModifier-impl(I)Z
+PLandroidx/compose/ui/input/pointer/SuspendingPointerInputFilter$PointerEventHandlerCoroutine$withTimeout$1;-><init>(Landroidx/compose/ui/input/pointer/SuspendingPointerInputFilter$PointerEventHandlerCoroutine;Lkotlin/coroutines/Continuation;)V
+PLandroidx/compose/ui/input/pointer/SuspendingPointerInputFilter$PointerEventHandlerCoroutine$withTimeout$1;->invokeSuspend(Ljava/lang/Object;)Ljava/lang/Object;
+PLandroidx/compose/ui/input/pointer/SuspendingPointerInputFilter$PointerEventHandlerCoroutine$withTimeout$job$1;-><init>(JLandroidx/compose/ui/input/pointer/SuspendingPointerInputFilter$PointerEventHandlerCoroutine;Lkotlin/coroutines/Continuation;)V
+PLandroidx/compose/ui/input/pointer/SuspendingPointerInputFilter$PointerEventHandlerCoroutine$withTimeout$job$1;->create(Ljava/lang/Object;Lkotlin/coroutines/Continuation;)Lkotlin/coroutines/Continuation;
+PLandroidx/compose/ui/input/pointer/SuspendingPointerInputFilter$PointerEventHandlerCoroutine$withTimeout$job$1;->invokeSuspend(Ljava/lang/Object;)Ljava/lang/Object;
+PLandroidx/compose/ui/input/pointer/SuspendingPointerInputFilter$PointerEventHandlerCoroutine;->getCurrentEvent()Landroidx/compose/ui/input/pointer/PointerEvent;
+PLandroidx/compose/ui/input/pointer/SuspendingPointerInputFilter$PointerEventHandlerCoroutine;->getExtendedTouchPadding-NH-jbRc()J
+PLandroidx/compose/ui/input/pointer/SuspendingPointerInputFilter$PointerEventHandlerCoroutine;->getSize-YbymL2g()J
+PLandroidx/compose/ui/input/pointer/SuspendingPointerInputFilter$PointerEventHandlerCoroutine;->getViewConfiguration()Landroidx/compose/ui/platform/ViewConfiguration;
+PLandroidx/compose/ui/input/pointer/SuspendingPointerInputFilter$PointerEventHandlerCoroutine;->withTimeout(JLkotlin/jvm/functions/Function2;Lkotlin/coroutines/Continuation;)Ljava/lang/Object;
+PLandroidx/compose/ui/input/pointer/SuspendingPointerInputFilter$WhenMappings;-><clinit>()V
+PLandroidx/compose/ui/input/pointer/SuspendingPointerInputFilter;->access$getBoundsSize$p(Landroidx/compose/ui/input/pointer/SuspendingPointerInputFilter;)J
+PLandroidx/compose/ui/input/pointer/SuspendingPointerInputFilter;->access$getCurrentEvent$p(Landroidx/compose/ui/input/pointer/SuspendingPointerInputFilter;)Landroidx/compose/ui/input/pointer/PointerEvent;
+PLandroidx/compose/ui/input/pointer/SuspendingPointerInputFilter;->getCoroutineScope()Lkotlinx/coroutines/CoroutineScope;
+PLandroidx/compose/ui/input/pointer/SuspendingPointerInputFilter;->getExtendedTouchPadding-NH-jbRc()J
+PLandroidx/compose/ui/input/pointer/SuspendingPointerInputFilter;->getInterceptOutOfBoundsChildEvents()Z
+PLandroidx/compose/ui/input/pointer/SuspendingPointerInputFilter;->getViewConfiguration()Landroidx/compose/ui/platform/ViewConfiguration;
+PLandroidx/compose/ui/input/pointer/SuspendingPointerInputFilter;->onCancel()V
+PLandroidx/compose/ui/input/pointer/SuspendingPointerInputFilter;->toSize-XkaWNTQ(J)J
+PLandroidx/compose/ui/input/pointer/util/Matrix;-><init>(II)V
+PLandroidx/compose/ui/input/pointer/util/Matrix;->get(II)F
+PLandroidx/compose/ui/input/pointer/util/Matrix;->getRow(I)Landroidx/compose/ui/input/pointer/util/Vector;
+PLandroidx/compose/ui/input/pointer/util/Matrix;->set(IIF)V
+PLandroidx/compose/ui/input/pointer/util/PointAtTime;-><init>(JJ)V
+PLandroidx/compose/ui/input/pointer/util/PointAtTime;-><init>(JJLkotlin/jvm/internal/DefaultConstructorMarker;)V
+PLandroidx/compose/ui/input/pointer/util/PointAtTime;->getPoint-F1C5BW0()J
+PLandroidx/compose/ui/input/pointer/util/PointAtTime;->getTime()J
+PLandroidx/compose/ui/input/pointer/util/PolynomialFit;-><init>(Ljava/util/List;F)V
+PLandroidx/compose/ui/input/pointer/util/PolynomialFit;->getCoefficients()Ljava/util/List;
+PLandroidx/compose/ui/input/pointer/util/PolynomialFit;->getConfidence()F
+PLandroidx/compose/ui/input/pointer/util/Vector;-><init>(I)V
+PLandroidx/compose/ui/input/pointer/util/Vector;->get(I)F
+PLandroidx/compose/ui/input/pointer/util/Vector;->norm()F
+PLandroidx/compose/ui/input/pointer/util/Vector;->set(IF)V
+PLandroidx/compose/ui/input/pointer/util/Vector;->times(Landroidx/compose/ui/input/pointer/util/Vector;)F
+PLandroidx/compose/ui/input/pointer/util/VelocityEstimate$Companion;-><init>()V
+PLandroidx/compose/ui/input/pointer/util/VelocityEstimate$Companion;-><init>(Lkotlin/jvm/internal/DefaultConstructorMarker;)V
+PLandroidx/compose/ui/input/pointer/util/VelocityEstimate;-><clinit>()V
+PLandroidx/compose/ui/input/pointer/util/VelocityEstimate;-><init>(JFJJ)V
+PLandroidx/compose/ui/input/pointer/util/VelocityEstimate;-><init>(JFJJLkotlin/jvm/internal/DefaultConstructorMarker;)V
+PLandroidx/compose/ui/input/pointer/util/VelocityEstimate;->getPixelsPerSecond-F1C5BW0()J
+PLandroidx/compose/ui/input/pointer/util/VelocityTracker;->addPosition-Uv8p0NA(JJ)V
+PLandroidx/compose/ui/input/pointer/util/VelocityTracker;->calculateVelocity-9UxMQ8M()J
+PLandroidx/compose/ui/input/pointer/util/VelocityTracker;->getCurrentPointerPositionAccumulator-F1C5BW0$ui_release()J
+PLandroidx/compose/ui/input/pointer/util/VelocityTracker;->getVelocityEstimate()Landroidx/compose/ui/input/pointer/util/VelocityEstimate;
+PLandroidx/compose/ui/input/pointer/util/VelocityTracker;->resetTracking()V
+PLandroidx/compose/ui/input/pointer/util/VelocityTracker;->setCurrentPointerPositionAccumulator-k-4lQ0M$ui_release(J)V
+PLandroidx/compose/ui/input/pointer/util/VelocityTrackerKt;->addPointerInputChange(Landroidx/compose/ui/input/pointer/util/VelocityTracker;Landroidx/compose/ui/input/pointer/PointerInputChange;)V
+PLandroidx/compose/ui/input/pointer/util/VelocityTrackerKt;->polyFitLeastSquares(Ljava/util/List;Ljava/util/List;I)Landroidx/compose/ui/input/pointer/util/PolynomialFit;
+PLandroidx/compose/ui/layout/LayoutId;-><init>(Ljava/lang/Object;Lkotlin/jvm/functions/Function1;)V
+PLandroidx/compose/ui/layout/LayoutId;->getLayoutId()Ljava/lang/Object;
+PLandroidx/compose/ui/layout/LayoutId;->modifyParentData(Landroidx/compose/ui/unit/Density;Ljava/lang/Object;)Ljava/lang/Object;
+PLandroidx/compose/ui/layout/LayoutIdKt;->getLayoutId(Landroidx/compose/ui/layout/Measurable;)Ljava/lang/Object;
+PLandroidx/compose/ui/layout/LayoutIdKt;->layoutId(Landroidx/compose/ui/Modifier;Ljava/lang/Object;)Landroidx/compose/ui/Modifier;
+PLandroidx/compose/ui/layout/LayoutModifierImpl;-><init>(Lkotlin/jvm/functions/Function3;Lkotlin/jvm/functions/Function1;)V
+PLandroidx/compose/ui/layout/LayoutModifierImpl;->equals(Ljava/lang/Object;)Z
+PLandroidx/compose/ui/layout/LayoutModifierImpl;->measure-3p2s80s(Landroidx/compose/ui/layout/MeasureScope;Landroidx/compose/ui/layout/Measurable;J)Landroidx/compose/ui/layout/MeasureResult;
+PLandroidx/compose/ui/layout/LayoutModifierKt;->layout(Landroidx/compose/ui/Modifier;Lkotlin/jvm/functions/Function3;)Landroidx/compose/ui/Modifier;
+PLandroidx/compose/ui/layout/LayoutNodeSubcompositionsState$NodeState;->getForceRecompose()Z
+PLandroidx/compose/ui/layout/LayoutNodeSubcompositionsState$NodeState;->getSlotId()Ljava/lang/Object;
+PLandroidx/compose/ui/layout/LayoutNodeSubcompositionsState$NodeState;->setActive(Z)V
+PLandroidx/compose/ui/layout/LayoutNodeSubcompositionsState$NodeState;->setSlotId(Ljava/lang/Object;)V
+PLandroidx/compose/ui/layout/LayoutNodeSubcompositionsState$Scope;->getDensity()F
+PLandroidx/compose/ui/layout/LayoutNodeSubcompositionsState$precompose$1;-><init>(Landroidx/compose/ui/layout/LayoutNodeSubcompositionsState;Ljava/lang/Object;)V
+PLandroidx/compose/ui/layout/LayoutNodeSubcompositionsState$precompose$1;->dispose()V
+PLandroidx/compose/ui/layout/LayoutNodeSubcompositionsState$precompose$1;->getPlaceablesCount()I
+PLandroidx/compose/ui/layout/LayoutNodeSubcompositionsState$precompose$1;->premeasure-0kLqBqw(IJ)V
+PLandroidx/compose/ui/layout/LayoutNodeSubcompositionsState;->access$getPrecomposeMap$p(Landroidx/compose/ui/layout/LayoutNodeSubcompositionsState;)Ljava/util/Map;
+PLandroidx/compose/ui/layout/LayoutNodeSubcompositionsState;->access$getRoot$p(Landroidx/compose/ui/layout/LayoutNodeSubcompositionsState;)Landroidx/compose/ui/node/LayoutNode;
+PLandroidx/compose/ui/layout/LayoutNodeSubcompositionsState;->disposeCurrentNodes()V
+PLandroidx/compose/ui/layout/LayoutNodeSubcompositionsState;->getSlotIdAtIndex(I)Ljava/lang/Object;
+PLandroidx/compose/ui/layout/LayoutNodeSubcompositionsState;->move$default(Landroidx/compose/ui/layout/LayoutNodeSubcompositionsState;IIIILjava/lang/Object;)V
+PLandroidx/compose/ui/layout/LayoutNodeSubcompositionsState;->move(III)V
+PLandroidx/compose/ui/layout/LayoutNodeSubcompositionsState;->precompose(Ljava/lang/Object;Lkotlin/jvm/functions/Function2;)Landroidx/compose/ui/layout/SubcomposeLayoutState$PrecomposedSlotHandle;
+PLandroidx/compose/ui/layout/OnRemeasuredModifierKt;->onSizeChanged(Landroidx/compose/ui/Modifier;Lkotlin/jvm/functions/Function1;)Landroidx/compose/ui/Modifier;
+PLandroidx/compose/ui/layout/OnSizeChangedModifier;-><init>(Lkotlin/jvm/functions/Function1;Lkotlin/jvm/functions/Function1;)V
+PLandroidx/compose/ui/layout/OnSizeChangedModifier;->equals(Ljava/lang/Object;)Z
+PLandroidx/compose/ui/layout/OnSizeChangedModifier;->onRemeasured-ozmzZPI(J)V
+PLandroidx/compose/ui/layout/Placeable$PlacementScope;->placeWithLayer-aW-9-wM$default(Landroidx/compose/ui/layout/Placeable$PlacementScope;Landroidx/compose/ui/layout/Placeable;JFLkotlin/jvm/functions/Function1;ILjava/lang/Object;)V
+PLandroidx/compose/ui/layout/Placeable;->getMeasuredHeight()I
+PLandroidx/compose/ui/layout/SubcomposeLayoutKt$SubcomposeLayout$5$1$invoke$$inlined$onDispose$1;->dispose()V
+PLandroidx/compose/ui/layout/SubcomposeLayoutKt$SubcomposeLayout$6;-><init>(Landroidx/compose/ui/layout/SubcomposeLayoutState;Landroidx/compose/ui/Modifier;Lkotlin/jvm/functions/Function2;II)V
+PLandroidx/compose/ui/layout/SubcomposeLayoutState;->disposeCurrentNodes$ui_release()V
+PLandroidx/compose/ui/layout/SubcomposeLayoutState;->precompose(Ljava/lang/Object;Lkotlin/jvm/functions/Function2;)Landroidx/compose/ui/layout/SubcomposeLayoutState$PrecomposedSlotHandle;
+PLandroidx/compose/ui/layout/SubcomposeSlotReusePolicy$SlotIdsSet;->add$ui_release(Ljava/lang/Object;)Z
+PLandroidx/compose/ui/layout/SubcomposeSlotReusePolicy$SlotIdsSet;->clear()V
+PLandroidx/compose/ui/layout/SubcomposeSlotReusePolicy$SlotIdsSet;->contains(Ljava/lang/Object;)Z
+PLandroidx/compose/ui/layout/SubcomposeSlotReusePolicy$SlotIdsSet;->iterator()Ljava/util/Iterator;
+PLandroidx/compose/ui/node/AlignmentLines$recalculate$1;-><init>(Landroidx/compose/ui/node/AlignmentLines;)V
+PLandroidx/compose/ui/node/AlignmentLines$recalculate$1;->invoke(Landroidx/compose/ui/node/AlignmentLinesOwner;)V
+PLandroidx/compose/ui/node/AlignmentLines$recalculate$1;->invoke(Ljava/lang/Object;)Ljava/lang/Object;
+PLandroidx/compose/ui/node/AlignmentLines;->access$addAlignmentLine(Landroidx/compose/ui/node/AlignmentLines;Landroidx/compose/ui/layout/AlignmentLine;ILandroidx/compose/ui/node/NodeCoordinator;)V
+PLandroidx/compose/ui/node/AlignmentLines;->access$getAlignmentLineMap$p(Landroidx/compose/ui/node/AlignmentLines;)Ljava/util/Map;
+PLandroidx/compose/ui/node/AlignmentLines;->addAlignmentLine(Landroidx/compose/ui/layout/AlignmentLine;ILandroidx/compose/ui/node/NodeCoordinator;)V
+PLandroidx/compose/ui/node/AlignmentLines;->getAlignmentLinesOwner()Landroidx/compose/ui/node/AlignmentLinesOwner;
+PLandroidx/compose/ui/node/AlignmentLines;->getLastCalculation()Ljava/util/Map;
+PLandroidx/compose/ui/node/AlignmentLines;->recalculate()V
+PLandroidx/compose/ui/node/BackwardsCompatNode;->interceptOutOfBoundsChildEvents()Z
+PLandroidx/compose/ui/node/BackwardsCompatNode;->isValid()Z
+PLandroidx/compose/ui/node/BackwardsCompatNode;->onCancelPointerInput()V
+PLandroidx/compose/ui/node/BackwardsCompatNode;->onDetach()V
+PLandroidx/compose/ui/node/BackwardsCompatNode;->sharePointerInputWithSiblings()Z
+PLandroidx/compose/ui/node/BackwardsCompatNodeKt$updateModifierLocalConsumer$1;->invoke(Landroidx/compose/ui/node/BackwardsCompatNode;)V
+PLandroidx/compose/ui/node/BackwardsCompatNodeKt$updateModifierLocalConsumer$1;->invoke(Ljava/lang/Object;)Ljava/lang/Object;
+PLandroidx/compose/ui/node/DistanceAndInLayer;->compareTo-S_HNhKs(JJ)I
+PLandroidx/compose/ui/node/DistanceAndInLayer;->constructor-impl(J)J
+PLandroidx/compose/ui/node/DistanceAndInLayer;->getDistance-impl(J)F
+PLandroidx/compose/ui/node/DistanceAndInLayer;->isInLayer-impl(J)Z
+PLandroidx/compose/ui/node/HitTestResult;->access$getHitDepth$p(Landroidx/compose/ui/node/HitTestResult;)I
+PLandroidx/compose/ui/node/HitTestResult;->access$setHitDepth$p(Landroidx/compose/ui/node/HitTestResult;I)V
+PLandroidx/compose/ui/node/HitTestResult;->clear()V
+PLandroidx/compose/ui/node/HitTestResult;->ensureContainerSize()V
+PLandroidx/compose/ui/node/HitTestResult;->findBestHitDistance-ptXAw2c()J
+PLandroidx/compose/ui/node/HitTestResult;->get(I)Ljava/lang/Object;
+PLandroidx/compose/ui/node/HitTestResult;->getSize()I
+PLandroidx/compose/ui/node/HitTestResult;->hasHit()Z
+PLandroidx/compose/ui/node/HitTestResult;->hit(Ljava/lang/Object;ZLkotlin/jvm/functions/Function0;)V
+PLandroidx/compose/ui/node/HitTestResult;->hitInMinimumTouchTarget(Ljava/lang/Object;FZLkotlin/jvm/functions/Function0;)V
+PLandroidx/compose/ui/node/HitTestResult;->isEmpty()Z
+PLandroidx/compose/ui/node/HitTestResult;->isHitInMinimumTouchTargetBetter(FZ)Z
+PLandroidx/compose/ui/node/HitTestResult;->resizeToHitDepth()V
+PLandroidx/compose/ui/node/HitTestResult;->size()I
+PLandroidx/compose/ui/node/HitTestResultKt;->DistanceAndInLayer(FZ)J
+PLandroidx/compose/ui/node/HitTestResultKt;->access$DistanceAndInLayer(FZ)J
+PLandroidx/compose/ui/node/InnerNodeCoordinator;->calculateAlignmentLine(Landroidx/compose/ui/layout/AlignmentLine;)I
+PLandroidx/compose/ui/node/LayoutModifierNode;->forceRemeasure()V
+PLandroidx/compose/ui/node/LayoutModifierNodeCoordinator;->calculateAlignmentLine(Landroidx/compose/ui/layout/AlignmentLine;)I
+PLandroidx/compose/ui/node/LayoutModifierNodeCoordinatorKt;->access$calculateAlignmentAndPlaceChildAsNeeded(Landroidx/compose/ui/node/LookaheadCapablePlaceable;Landroidx/compose/ui/layout/AlignmentLine;)I
+PLandroidx/compose/ui/node/LayoutModifierNodeCoordinatorKt;->calculateAlignmentAndPlaceChildAsNeeded(Landroidx/compose/ui/node/LookaheadCapablePlaceable;Landroidx/compose/ui/layout/AlignmentLine;)I
+PLandroidx/compose/ui/node/LayoutNode$WhenMappings;-><clinit>()V
+PLandroidx/compose/ui/node/LayoutNode;->forceRemeasure()V
+PLandroidx/compose/ui/node/LayoutNode;->getViewConfiguration()Landroidx/compose/ui/platform/ViewConfiguration;
+PLandroidx/compose/ui/node/LayoutNode;->hitTest-M_7yMNQ$ui_release$default(Landroidx/compose/ui/node/LayoutNode;JLandroidx/compose/ui/node/HitTestResult;ZZILjava/lang/Object;)V
+PLandroidx/compose/ui/node/LayoutNode;->hitTest-M_7yMNQ$ui_release(JLandroidx/compose/ui/node/HitTestResult;ZZ)V
+PLandroidx/compose/ui/node/LayoutNode;->markSubtreeAsNotPlaced()V
+PLandroidx/compose/ui/node/LayoutNode;->move$ui_release(III)V
+PLandroidx/compose/ui/node/LayoutNode;->onChildRemoved(Landroidx/compose/ui/node/LayoutNode;)V
+PLandroidx/compose/ui/node/LayoutNode;->removeAll$ui_release()V
+PLandroidx/compose/ui/node/LayoutNode;->removeAt$ui_release(II)V
+PLandroidx/compose/ui/node/LayoutNode;->rescheduleRemeasureOrRelayout$ui_release(Landroidx/compose/ui/node/LayoutNode;)V
+PLandroidx/compose/ui/node/LayoutNodeAlignmentLines;->calculatePositionInParent-R5De75A(Landroidx/compose/ui/node/NodeCoordinator;J)J
+PLandroidx/compose/ui/node/LayoutNodeAlignmentLines;->getAlignmentLinesMap(Landroidx/compose/ui/node/NodeCoordinator;)Ljava/util/Map;
+PLandroidx/compose/ui/node/LayoutNodeDrawScope;->performDraw(Landroidx/compose/ui/node/DrawModifierNode;Landroidx/compose/ui/graphics/Canvas;)V
+PLandroidx/compose/ui/node/LayoutNodeDrawScope;->roundToPx-0680j_4(F)I
+PLandroidx/compose/ui/node/LayoutNodeLayoutDelegate$MeasurePassDelegate;->calculateAlignmentLines()Ljava/util/Map;
+PLandroidx/compose/ui/node/LayoutNodeLayoutDelegate$MeasurePassDelegate;->get(Landroidx/compose/ui/layout/AlignmentLine;)I
+PLandroidx/compose/ui/node/LayoutNodeLayoutDelegate$MeasurePassDelegate;->isPlaced()Z
+PLandroidx/compose/ui/node/LayoutNodeLayoutDelegate;->getCoordinatesAccessedDuringPlacement()Z
+PLandroidx/compose/ui/node/LayoutNodeLayoutDelegate;->resetAlignmentLines()V
+PLandroidx/compose/ui/node/LookaheadCapablePlaceable;->get(Landroidx/compose/ui/layout/AlignmentLine;)I
+PLandroidx/compose/ui/node/LookaheadCapablePlaceable;->setShallowPlacing$ui_release(Z)V
+PLandroidx/compose/ui/node/MeasureAndLayoutDelegate;->doLookaheadRemeasure-sdFAvZA(Landroidx/compose/ui/node/LayoutNode;Landroidx/compose/ui/unit/Constraints;)Z
+PLandroidx/compose/ui/node/MeasureAndLayoutDelegate;->measureAndLayout-0kLqBqw(Landroidx/compose/ui/node/LayoutNode;J)V
+PLandroidx/compose/ui/node/MeasureAndLayoutDelegate;->onNodeDetached(Landroidx/compose/ui/node/LayoutNode;)V
+PLandroidx/compose/ui/node/MutableVectorWithMutationTracking;->clear()V
+PLandroidx/compose/ui/node/MutableVectorWithMutationTracking;->get(I)Ljava/lang/Object;
+PLandroidx/compose/ui/node/MutableVectorWithMutationTracking;->getSize()I
+PLandroidx/compose/ui/node/MutableVectorWithMutationTracking;->removeAt(I)Ljava/lang/Object;
+PLandroidx/compose/ui/node/NodeChain$Differ;->remove(I)V
+PLandroidx/compose/ui/node/NodeChain;->access$disposeAndRemoveNode(Landroidx/compose/ui/node/NodeChain;Landroidx/compose/ui/Modifier$Node;)Landroidx/compose/ui/Modifier$Node;
+PLandroidx/compose/ui/node/NodeChain;->disposeAndRemoveNode(Landroidx/compose/ui/Modifier$Node;)Landroidx/compose/ui/Modifier$Node;
+PLandroidx/compose/ui/node/NodeChain;->removeNode(Landroidx/compose/ui/Modifier$Node;)Landroidx/compose/ui/Modifier$Node;
+PLandroidx/compose/ui/node/NodeCoordinator$Companion$PointerInputSource$1;->childHitTest-YqVAtuI(Landroidx/compose/ui/node/LayoutNode;JLandroidx/compose/ui/node/HitTestResult;ZZ)V
+PLandroidx/compose/ui/node/NodeCoordinator$Companion$PointerInputSource$1;->entityType-OLwlOKw()I
+PLandroidx/compose/ui/node/NodeCoordinator$Companion$PointerInputSource$1;->interceptOutOfBoundsChildEvents(Landroidx/compose/ui/node/DelegatableNode;)Z
+PLandroidx/compose/ui/node/NodeCoordinator$Companion$PointerInputSource$1;->interceptOutOfBoundsChildEvents(Landroidx/compose/ui/node/PointerInputModifierNode;)Z
+PLandroidx/compose/ui/node/NodeCoordinator$Companion$PointerInputSource$1;->shouldHitTestChildren(Landroidx/compose/ui/node/LayoutNode;)Z
+PLandroidx/compose/ui/node/NodeCoordinator$Companion;->getPointerInputSource()Landroidx/compose/ui/node/NodeCoordinator$HitTestSource;
+PLandroidx/compose/ui/node/NodeCoordinator$hit$1;-><init>(Landroidx/compose/ui/node/NodeCoordinator;Landroidx/compose/ui/node/DelegatableNode;Landroidx/compose/ui/node/NodeCoordinator$HitTestSource;JLandroidx/compose/ui/node/HitTestResult;ZZ)V
+PLandroidx/compose/ui/node/NodeCoordinator$hit$1;->invoke()Ljava/lang/Object;
+PLandroidx/compose/ui/node/NodeCoordinator$hit$1;->invoke()V
+PLandroidx/compose/ui/node/NodeCoordinator$hitNear$1;-><init>(Landroidx/compose/ui/node/NodeCoordinator;Landroidx/compose/ui/node/DelegatableNode;Landroidx/compose/ui/node/NodeCoordinator$HitTestSource;JLandroidx/compose/ui/node/HitTestResult;ZZF)V
+PLandroidx/compose/ui/node/NodeCoordinator$hitNear$1;->invoke()Ljava/lang/Object;
+PLandroidx/compose/ui/node/NodeCoordinator$hitNear$1;->invoke()V
+PLandroidx/compose/ui/node/NodeCoordinator;->access$getPointerInputSource$cp()Landroidx/compose/ui/node/NodeCoordinator$HitTestSource;
+PLandroidx/compose/ui/node/NodeCoordinator;->access$hit-1hIXUjU(Landroidx/compose/ui/node/NodeCoordinator;Landroidx/compose/ui/node/DelegatableNode;Landroidx/compose/ui/node/NodeCoordinator$HitTestSource;JLandroidx/compose/ui/node/HitTestResult;ZZ)V
+PLandroidx/compose/ui/node/NodeCoordinator;->access$hitNear-JHbHoSQ(Landroidx/compose/ui/node/NodeCoordinator;Landroidx/compose/ui/node/DelegatableNode;Landroidx/compose/ui/node/NodeCoordinator$HitTestSource;JLandroidx/compose/ui/node/HitTestResult;ZZF)V
+PLandroidx/compose/ui/node/NodeCoordinator;->calculateMinimumTouchTargetPadding-E7KxVPU(J)J
+PLandroidx/compose/ui/node/NodeCoordinator;->distanceInMinimumTouchTarget-tz77jQw(JJ)F
+PLandroidx/compose/ui/node/NodeCoordinator;->getChild()Landroidx/compose/ui/node/LookaheadCapablePlaceable;
+PLandroidx/compose/ui/node/NodeCoordinator;->getHasMeasureResult()Z
+PLandroidx/compose/ui/node/NodeCoordinator;->getMinimumTouchTargetSize-NH-jbRc()J
+PLandroidx/compose/ui/node/NodeCoordinator;->headUnchecked-H91voCI(I)Ljava/lang/Object;
+PLandroidx/compose/ui/node/NodeCoordinator;->hit-1hIXUjU(Landroidx/compose/ui/node/DelegatableNode;Landroidx/compose/ui/node/NodeCoordinator$HitTestSource;JLandroidx/compose/ui/node/HitTestResult;ZZ)V
+PLandroidx/compose/ui/node/NodeCoordinator;->hitNear-JHbHoSQ(Landroidx/compose/ui/node/DelegatableNode;Landroidx/compose/ui/node/NodeCoordinator$HitTestSource;JLandroidx/compose/ui/node/HitTestResult;ZZF)V
+PLandroidx/compose/ui/node/NodeCoordinator;->hitTest-YqVAtuI(Landroidx/compose/ui/node/NodeCoordinator$HitTestSource;JLandroidx/compose/ui/node/HitTestResult;ZZ)V
+PLandroidx/compose/ui/node/NodeCoordinator;->isPointerInBounds-k-4lQ0M(J)Z
+PLandroidx/compose/ui/node/NodeCoordinator;->isValid()Z
+PLandroidx/compose/ui/node/NodeCoordinator;->offsetFromEdge-MK-Hz9U(J)J
+PLandroidx/compose/ui/node/NodeCoordinator;->replace$ui_release()V
+PLandroidx/compose/ui/node/NodeCoordinator;->shouldSharePointerInputWithSiblings()Z
+PLandroidx/compose/ui/node/NodeCoordinator;->speculativeHit-JHbHoSQ(Landroidx/compose/ui/node/DelegatableNode;Landroidx/compose/ui/node/NodeCoordinator$HitTestSource;JLandroidx/compose/ui/node/HitTestResult;ZZF)V
+PLandroidx/compose/ui/node/NodeCoordinator;->toCoordinator(Landroidx/compose/ui/layout/LayoutCoordinates;)Landroidx/compose/ui/node/NodeCoordinator;
+PLandroidx/compose/ui/node/NodeCoordinator;->toParentPosition-MK-Hz9U(J)J
+PLandroidx/compose/ui/node/NodeCoordinator;->withinLayerBounds-k-4lQ0M(J)Z
+PLandroidx/compose/ui/node/NodeCoordinatorKt;->access$nextUncheckedUntil-hw7D004(Landroidx/compose/ui/node/DelegatableNode;II)Ljava/lang/Object;
+PLandroidx/compose/ui/node/NodeCoordinatorKt;->nextUncheckedUntil-hw7D004(Landroidx/compose/ui/node/DelegatableNode;II)Ljava/lang/Object;
+PLandroidx/compose/ui/node/NodeKindKt;->autoInvalidateRemovedNode(Landroidx/compose/ui/Modifier$Node;)V
+PLandroidx/compose/ui/node/OwnerSnapshotObserver$clearInvalidObservations$1;-><clinit>()V
+PLandroidx/compose/ui/node/OwnerSnapshotObserver$clearInvalidObservations$1;-><init>()V
+PLandroidx/compose/ui/node/OwnerSnapshotObserver$clearInvalidObservations$1;->invoke(Ljava/lang/Object;)Ljava/lang/Boolean;
+PLandroidx/compose/ui/node/OwnerSnapshotObserver$clearInvalidObservations$1;->invoke(Ljava/lang/Object;)Ljava/lang/Object;
+PLandroidx/compose/ui/node/OwnerSnapshotObserver;->clearInvalidObservations$ui_release()V
+PLandroidx/compose/ui/node/OwnerSnapshotObserver;->stopObserving$ui_release()V
+PLandroidx/compose/ui/node/PointerInputModifierNodeKt;->getLayoutCoordinates(Landroidx/compose/ui/node/PointerInputModifierNode;)Landroidx/compose/ui/layout/LayoutCoordinates;
+PLandroidx/compose/ui/node/UiApplier;->onClear()V
+PLandroidx/compose/ui/node/UiApplier;->remove(II)V
+PLandroidx/compose/ui/platform/AbstractComposeView;->disposeComposition()V
+PLandroidx/compose/ui/platform/AbstractComposeView;->shouldDelayChildPressedState()Z
+PLandroidx/compose/ui/platform/AndroidComposeView$scrollContainerInfo$1$value$1;->canScrollHorizontally()Z
+PLandroidx/compose/ui/platform/AndroidComposeView$scrollContainerInfo$1$value$1;->canScrollVertically()Z
+PLandroidx/compose/ui/platform/AndroidComposeView$scrollContainerInfo$1$value$1;->isInScrollableViewGroup(Landroid/view/View;)Z
+PLandroidx/compose/ui/platform/AndroidComposeView;->dispatchTouchEvent(Landroid/view/MotionEvent;)Z
+PLandroidx/compose/ui/platform/AndroidComposeView;->hasChangedDevices(Landroid/view/MotionEvent;Landroid/view/MotionEvent;)Z
+PLandroidx/compose/ui/platform/AndroidComposeView;->isBadMotionEvent(Landroid/view/MotionEvent;)Z
+PLandroidx/compose/ui/platform/AndroidComposeView;->isInBounds(Landroid/view/MotionEvent;)Z
+PLandroidx/compose/ui/platform/AndroidComposeView;->isPositionChanged(Landroid/view/MotionEvent;)Z
+PLandroidx/compose/ui/platform/AndroidComposeView;->measureAndLayout-0kLqBqw(Landroidx/compose/ui/node/LayoutNode;J)V
+PLandroidx/compose/ui/platform/AndroidComposeView;->onDetach(Landroidx/compose/ui/node/LayoutNode;)V
+PLandroidx/compose/ui/platform/AndroidComposeView;->onDetachedFromWindow()V
+PLandroidx/compose/ui/platform/AndroidComposeView;->recalculateWindowPosition()V
+PLandroidx/compose/ui/platform/AndroidComposeView;->recalculateWindowPosition(Landroid/view/MotionEvent;)V
+PLandroidx/compose/ui/platform/AndroidComposeView;->recalculateWindowViewTransforms()V
+PLandroidx/compose/ui/platform/AndroidComposeView;->requestClearInvalidObservations()V
+PLandroidx/compose/ui/platform/AndroidComposeViewAccessibilityDelegateCompat$1;->onViewDetachedFromWindow(Landroid/view/View;)V
+PLandroidx/compose/ui/platform/AndroidComposeViewAccessibilityDelegateCompat$boundsUpdatesEventLoop$1;->invokeSuspend(Ljava/lang/Object;)Ljava/lang/Object;
+PLandroidx/compose/ui/platform/AndroidComposeViewAccessibilityDelegateCompat;->access$getHandler$p(Landroidx/compose/ui/platform/AndroidComposeViewAccessibilityDelegateCompat;)Landroid/os/Handler;
+PLandroidx/compose/ui/platform/AndroidComposeViewAccessibilityDelegateCompat;->access$getSemanticsChangeChecker$p(Landroidx/compose/ui/platform/AndroidComposeViewAccessibilityDelegateCompat;)Ljava/lang/Runnable;
+PLandroidx/compose/ui/platform/AndroidComposeViewVerificationHelperMethodsN;-><clinit>()V
+PLandroidx/compose/ui/platform/AndroidComposeViewVerificationHelperMethodsN;-><init>()V
+PLandroidx/compose/ui/platform/AndroidComposeViewVerificationHelperMethodsN;->setPointerIcon(Landroid/view/View;Landroidx/compose/ui/input/pointer/PointerIcon;)V
+PLandroidx/compose/ui/platform/AndroidCompositionLocals_androidKt$ProvideAndroidCompositionLocals$2$invoke$$inlined$onDispose$1;->dispose()V
+PLandroidx/compose/ui/platform/AndroidCompositionLocals_androidKt$obtainImageVectorCache$1$invoke$$inlined$onDispose$1;->dispose()V
+PLandroidx/compose/ui/platform/AndroidCompositionLocals_androidKt$obtainImageVectorCache$callbacks$1$1;->onTrimMemory(I)V
+PLandroidx/compose/ui/platform/AndroidViewConfiguration;->getTouchSlop()F
+PLandroidx/compose/ui/platform/DisposableSaveableStateRegistry;->dispose()V
+PLandroidx/compose/ui/platform/DisposableSaveableStateRegistry_androidKt$DisposableSaveableStateRegistry$1;->invoke()Ljava/lang/Object;
+PLandroidx/compose/ui/platform/DisposableSaveableStateRegistry_androidKt$DisposableSaveableStateRegistry$1;->invoke()V
+PLandroidx/compose/ui/platform/DisposableSaveableStateRegistry_androidKt$DisposableSaveableStateRegistry$registered$1;->saveState()Landroid/os/Bundle;
+PLandroidx/compose/ui/platform/DisposableSaveableStateRegistry_androidKt;->access$toBundle(Ljava/util/Map;)Landroid/os/Bundle;
+PLandroidx/compose/ui/platform/DisposableSaveableStateRegistry_androidKt;->toBundle(Ljava/util/Map;)Landroid/os/Bundle;
+PLandroidx/compose/ui/platform/InvertMatrixKt;->invertTo-JiSxe2E([F[F)Z
+PLandroidx/compose/ui/platform/OutlineResolver;->isInOutline-k-4lQ0M(J)Z
+PLandroidx/compose/ui/platform/OutlineResolver;->updateCacheWithRect(Landroidx/compose/ui/geometry/Rect;)V
+PLandroidx/compose/ui/platform/RenderNodeApi29;->getClipToBounds()Z
+PLandroidx/compose/ui/platform/RenderNodeApi29;->getMatrix(Landroid/graphics/Matrix;)V
+PLandroidx/compose/ui/platform/RenderNodeLayer$Companion$getMatrix$1;->invoke(Landroidx/compose/ui/platform/DeviceRenderNode;Landroid/graphics/Matrix;)V
+PLandroidx/compose/ui/platform/RenderNodeLayer$Companion$getMatrix$1;->invoke(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;
+PLandroidx/compose/ui/platform/RenderNodeLayer;->isInLayer-k-4lQ0M(J)Z
+PLandroidx/compose/ui/platform/ShapeContainingUtilKt;->isInOutline(Landroidx/compose/ui/graphics/Outline;FFLandroidx/compose/ui/graphics/Path;Landroidx/compose/ui/graphics/Path;)Z
+PLandroidx/compose/ui/platform/ShapeContainingUtilKt;->isInRectangle(Landroidx/compose/ui/geometry/Rect;FF)Z
+PLandroidx/compose/ui/platform/ShapeContainingUtilKt;->isWithinEllipse-VE1yxkc(FFJFF)Z
+PLandroidx/compose/ui/platform/ViewCompositionStrategy$DisposeOnDetachedFromWindowOrReleasedFromPool$installFor$listener$1;->onViewDetachedFromWindow(Landroid/view/View;)V
+PLandroidx/compose/ui/platform/WindowInfoImpl;->setKeyboardModifiers-5xRPYO0(I)V
+PLandroidx/compose/ui/platform/WindowRecomposerPolicy$createAndInstallWindowRecomposer$1;->onViewDetachedFromWindow(Landroid/view/View;)V
+PLandroidx/compose/ui/platform/WindowRecomposer_androidKt$createLifecycleAwareWindowRecomposer$1;->onViewDetachedFromWindow(Landroid/view/View;)V
+PLandroidx/compose/ui/platform/WrappedComposition;->dispose()V
+PLandroidx/compose/ui/res/ImageVectorCache;->clear()V
+PLandroidx/compose/ui/semantics/CollectionInfo;-><clinit>()V
+PLandroidx/compose/ui/semantics/CollectionInfo;-><init>(II)V
+PLandroidx/compose/ui/semantics/Role$Companion;->getImage-o7Vup1c()I
+PLandroidx/compose/ui/semantics/Role;->access$getImage$cp()I
+PLandroidx/compose/ui/semantics/ScrollAxisRange;-><clinit>()V
+PLandroidx/compose/ui/semantics/ScrollAxisRange;-><init>(Lkotlin/jvm/functions/Function0;Lkotlin/jvm/functions/Function0;Z)V
+PLandroidx/compose/ui/semantics/SemanticsActions;->getScrollBy()Landroidx/compose/ui/semantics/SemanticsPropertyKey;
+PLandroidx/compose/ui/semantics/SemanticsActions;->getScrollToIndex()Landroidx/compose/ui/semantics/SemanticsPropertyKey;
+PLandroidx/compose/ui/semantics/SemanticsProperties;->getIndexForKey()Landroidx/compose/ui/semantics/SemanticsPropertyKey;
+PLandroidx/compose/ui/semantics/SemanticsPropertiesKt;->indexForKey(Landroidx/compose/ui/semantics/SemanticsPropertyReceiver;Lkotlin/jvm/functions/Function1;)V
+PLandroidx/compose/ui/semantics/SemanticsPropertiesKt;->scrollBy$default(Landroidx/compose/ui/semantics/SemanticsPropertyReceiver;Ljava/lang/String;Lkotlin/jvm/functions/Function2;ILjava/lang/Object;)V
+PLandroidx/compose/ui/semantics/SemanticsPropertiesKt;->scrollBy(Landroidx/compose/ui/semantics/SemanticsPropertyReceiver;Ljava/lang/String;Lkotlin/jvm/functions/Function2;)V
+PLandroidx/compose/ui/semantics/SemanticsPropertiesKt;->scrollToIndex$default(Landroidx/compose/ui/semantics/SemanticsPropertyReceiver;Ljava/lang/String;Lkotlin/jvm/functions/Function1;ILjava/lang/Object;)V
+PLandroidx/compose/ui/semantics/SemanticsPropertiesKt;->scrollToIndex(Landroidx/compose/ui/semantics/SemanticsPropertyReceiver;Ljava/lang/String;Lkotlin/jvm/functions/Function1;)V
+PLandroidx/compose/ui/semantics/SemanticsPropertiesKt;->setCollectionInfo(Landroidx/compose/ui/semantics/SemanticsPropertyReceiver;Landroidx/compose/ui/semantics/CollectionInfo;)V
+PLandroidx/compose/ui/semantics/SemanticsPropertiesKt;->setVerticalScrollAxisRange(Landroidx/compose/ui/semantics/SemanticsPropertyReceiver;Landroidx/compose/ui/semantics/ScrollAxisRange;)V
+PLandroidx/compose/ui/text/font/GenericFontFamily;->getName()Ljava/lang/String;
+PLandroidx/compose/ui/text/font/PlatformTypefacesApi28;->createNamed-RetOiIg(Landroidx/compose/ui/text/font/GenericFontFamily;Landroidx/compose/ui/text/font/FontWeight;I)Landroid/graphics/Typeface;
+PLandroidx/compose/ui/text/input/TextInputServiceAndroid$textInputCommandEventLoop$1;->invokeSuspend(Ljava/lang/Object;)Ljava/lang/Object;
+PLandroidx/compose/ui/unit/Constraints;->equals(Ljava/lang/Object;)Z
+PLandroidx/compose/ui/unit/Constraints;->equals-impl(JLjava/lang/Object;)Z
+PLandroidx/compose/ui/unit/Density;->toSize-XkaWNTQ(J)J
+PLandroidx/compose/ui/unit/DpSize$Companion;->getUnspecified-MYxV2XQ()J
+PLandroidx/compose/ui/unit/DpSize;->access$getUnspecified$cp()J
+PLandroidx/compose/ui/unit/IntOffsetKt;->plus-Nv-tHpc(JJ)J
+PLandroidx/compose/ui/unit/IntSize;->unbox-impl()J
+PLandroidx/compose/ui/unit/Velocity$Companion;-><init>()V
+PLandroidx/compose/ui/unit/Velocity$Companion;-><init>(Lkotlin/jvm/internal/DefaultConstructorMarker;)V
+PLandroidx/compose/ui/unit/Velocity$Companion;->getZero-9UxMQ8M()J
+PLandroidx/compose/ui/unit/Velocity;-><clinit>()V
+PLandroidx/compose/ui/unit/Velocity;-><init>(J)V
+PLandroidx/compose/ui/unit/Velocity;->access$getZero$cp()J
+PLandroidx/compose/ui/unit/Velocity;->box-impl(J)Landroidx/compose/ui/unit/Velocity;
+PLandroidx/compose/ui/unit/Velocity;->constructor-impl(J)J
+PLandroidx/compose/ui/unit/Velocity;->copy-OhffZ5M$default(JFFILjava/lang/Object;)J
+PLandroidx/compose/ui/unit/Velocity;->copy-OhffZ5M(JFF)J
+PLandroidx/compose/ui/unit/Velocity;->equals-impl0(JJ)Z
+PLandroidx/compose/ui/unit/Velocity;->getX-impl(J)F
+PLandroidx/compose/ui/unit/Velocity;->getY-impl(J)F
+PLandroidx/compose/ui/unit/Velocity;->minus-AH228Gc(JJ)J
+PLandroidx/compose/ui/unit/Velocity;->plus-AH228Gc(JJ)J
+PLandroidx/compose/ui/unit/Velocity;->times-adjELrA(JF)J
+PLandroidx/compose/ui/unit/Velocity;->unbox-impl()J
+PLandroidx/compose/ui/unit/VelocityKt;->Velocity(FF)J
+PLandroidx/compose/ui/util/MathHelpersKt;->lerp(FFF)F
+PLandroidx/concurrent/futures/AbstractResolvableFuture$AtomicHelper;-><init>()V
+PLandroidx/concurrent/futures/AbstractResolvableFuture$AtomicHelper;-><init>(Landroidx/concurrent/futures/AbstractResolvableFuture$1;)V
+PLandroidx/concurrent/futures/AbstractResolvableFuture$Listener;-><clinit>()V
+PLandroidx/concurrent/futures/AbstractResolvableFuture$Listener;-><init>(Ljava/lang/Runnable;Ljava/util/concurrent/Executor;)V
+PLandroidx/concurrent/futures/AbstractResolvableFuture$SafeAtomicHelper;-><init>(Ljava/util/concurrent/atomic/AtomicReferenceFieldUpdater;Ljava/util/concurrent/atomic/AtomicReferenceFieldUpdater;Ljava/util/concurrent/atomic/AtomicReferenceFieldUpdater;Ljava/util/concurrent/atomic/AtomicReferenceFieldUpdater;Ljava/util/concurrent/atomic/AtomicReferenceFieldUpdater;)V
+PLandroidx/concurrent/futures/AbstractResolvableFuture$SafeAtomicHelper;->casListeners(Landroidx/concurrent/futures/AbstractResolvableFuture;Landroidx/concurrent/futures/AbstractResolvableFuture$Listener;Landroidx/concurrent/futures/AbstractResolvableFuture$Listener;)Z
+PLandroidx/concurrent/futures/AbstractResolvableFuture$SafeAtomicHelper;->casValue(Landroidx/concurrent/futures/AbstractResolvableFuture;Ljava/lang/Object;Ljava/lang/Object;)Z
+PLandroidx/concurrent/futures/AbstractResolvableFuture$SafeAtomicHelper;->casWaiters(Landroidx/concurrent/futures/AbstractResolvableFuture;Landroidx/concurrent/futures/AbstractResolvableFuture$Waiter;Landroidx/concurrent/futures/AbstractResolvableFuture$Waiter;)Z
+PLandroidx/concurrent/futures/AbstractResolvableFuture$Waiter;-><clinit>()V
+PLandroidx/concurrent/futures/AbstractResolvableFuture$Waiter;-><init>(Z)V
+PLandroidx/concurrent/futures/AbstractResolvableFuture;-><clinit>()V
+PLandroidx/concurrent/futures/AbstractResolvableFuture;-><init>()V
+PLandroidx/concurrent/futures/AbstractResolvableFuture;->afterDone()V
+PLandroidx/concurrent/futures/AbstractResolvableFuture;->clearListeners(Landroidx/concurrent/futures/AbstractResolvableFuture$Listener;)Landroidx/concurrent/futures/AbstractResolvableFuture$Listener;
+PLandroidx/concurrent/futures/AbstractResolvableFuture;->complete(Landroidx/concurrent/futures/AbstractResolvableFuture;)V
+PLandroidx/concurrent/futures/AbstractResolvableFuture;->releaseWaiters()V
+PLandroidx/concurrent/futures/AbstractResolvableFuture;->set(Ljava/lang/Object;)Z
+PLandroidx/concurrent/futures/ResolvableFuture;-><init>()V
+PLandroidx/concurrent/futures/ResolvableFuture;->create()Landroidx/concurrent/futures/ResolvableFuture;
+PLandroidx/concurrent/futures/ResolvableFuture;->set(Ljava/lang/Object;)Z
+PLandroidx/core/app/ActivityCompat$Api16Impl;->startIntentSenderForResult(Landroid/app/Activity;Landroid/content/IntentSender;ILandroid/content/Intent;IIILandroid/os/Bundle;)V
+PLandroidx/core/app/ActivityCompat;->startIntentSenderForResult(Landroid/app/Activity;Landroid/content/IntentSender;ILandroid/content/Intent;IIILandroid/os/Bundle;)V
+PLandroidx/core/app/ComponentActivity;->dispatchKeyEvent(Landroid/view/KeyEvent;)Z
+PLandroidx/core/app/ComponentActivity;->onSaveInstanceState(Landroid/os/Bundle;)V
+PLandroidx/core/app/ComponentActivity;->superDispatchKeyEvent(Landroid/view/KeyEvent;)Z
+PLandroidx/core/content/ContextCompat;-><clinit>()V
+PLandroidx/core/graphics/Insets;-><clinit>()V
+PLandroidx/core/graphics/Insets;-><init>(IIII)V
+PLandroidx/core/view/KeyEventDispatcher;-><clinit>()V
+PLandroidx/core/view/KeyEventDispatcher;->dispatchBeforeHierarchy(Landroid/view/View;Landroid/view/KeyEvent;)Z
+PLandroidx/core/view/KeyEventDispatcher;->dispatchKeyEvent(Landroidx/core/view/KeyEventDispatcher$Component;Landroid/view/View;Landroid/view/Window$Callback;Landroid/view/KeyEvent;)Z
+PLandroidx/core/view/ViewCompat$Api21Impl$1;-><init>(Landroid/view/View;Landroidx/core/view/OnApplyWindowInsetsListener;)V
+PLandroidx/core/view/ViewCompat$Api21Impl;->setOnApplyWindowInsetsListener(Landroid/view/View;Landroidx/core/view/OnApplyWindowInsetsListener;)V
+PLandroidx/core/view/ViewCompat;->dispatchUnhandledKeyEventBeforeHierarchy(Landroid/view/View;Landroid/view/KeyEvent;)Z
+PLandroidx/core/view/ViewCompat;->setOnApplyWindowInsetsListener(Landroid/view/View;Landroidx/core/view/OnApplyWindowInsetsListener;)V
+PLandroidx/core/view/ViewCompat;->setWindowInsetsAnimationCallback(Landroid/view/View;Landroidx/core/view/WindowInsetsAnimationCompat$Callback;)V
+PLandroidx/core/view/ViewKt$ancestors$1;-><clinit>()V
+PLandroidx/core/view/ViewKt$ancestors$1;-><init>()V
+PLandroidx/core/view/ViewKt$ancestors$1;->invoke(Landroid/view/ViewParent;)Landroid/view/ViewParent;
+PLandroidx/core/view/ViewKt$ancestors$1;->invoke(Ljava/lang/Object;)Ljava/lang/Object;
+PLandroidx/core/view/ViewKt;->getAncestors(Landroid/view/View;)Lkotlin/sequences/Sequence;
+PLandroidx/core/view/WindowInsetsAnimationCompat$Callback;-><init>(I)V
+PLandroidx/core/view/WindowInsetsAnimationCompat$Callback;->getDispatchMode()I
+PLandroidx/core/view/WindowInsetsAnimationCompat$Impl30$ProxyCallback;-><init>(Landroidx/core/view/WindowInsetsAnimationCompat$Callback;)V
+PLandroidx/core/view/WindowInsetsAnimationCompat$Impl30;->setCallback(Landroid/view/View;Landroidx/core/view/WindowInsetsAnimationCompat$Callback;)V
+PLandroidx/core/view/WindowInsetsAnimationCompat;->setCallback(Landroid/view/View;Landroidx/core/view/WindowInsetsAnimationCompat$Callback;)V
+PLandroidx/core/view/WindowInsetsCompat$Type;->captionBar()I
+PLandroidx/core/view/WindowInsetsCompat$Type;->displayCutout()I
+PLandroidx/core/view/WindowInsetsCompat$Type;->ime()I
+PLandroidx/core/view/WindowInsetsCompat$Type;->mandatorySystemGestures()I
+PLandroidx/core/view/WindowInsetsCompat$Type;->navigationBars()I
+PLandroidx/core/view/WindowInsetsCompat$Type;->statusBars()I
+PLandroidx/core/view/WindowInsetsCompat$Type;->systemBars()I
+PLandroidx/core/view/WindowInsetsCompat$Type;->systemGestures()I
+PLandroidx/core/view/WindowInsetsCompat$Type;->tappableElement()I
+PLandroidx/customview/poolingcontainer/PoolingContainer;->isPoolingContainer(Landroid/view/View;)Z
+PLandroidx/customview/poolingcontainer/PoolingContainer;->isWithinPoolingContainer(Landroid/view/View;)Z
+PLandroidx/emoji2/text/EmojiMetadata;->isDefaultEmoji()Z
+PLandroidx/emoji2/text/EmojiProcessor$ProcessorSm;->isEmojiStyle(I)Z
+PLandroidx/emoji2/text/EmojiProcessor$ProcessorSm;->isTextStyle(I)Z
+PLandroidx/emoji2/text/EmojiProcessor$ProcessorSm;->shouldUseEmojiPresentationStyleForSingleCodepoint()Z
+PLandroidx/emoji2/text/MetadataRepo$Node;->getData()Landroidx/emoji2/text/EmojiMetadata;
+PLandroidx/emoji2/text/flatbuffer/MetadataItem;->emojiStyle()Z
+PLandroidx/lifecycle/DefaultLifecycleObserver;->onDestroy(Landroidx/lifecycle/LifecycleOwner;)V
+PLandroidx/lifecycle/DefaultLifecycleObserver;->onPause(Landroidx/lifecycle/LifecycleOwner;)V
+PLandroidx/lifecycle/DefaultLifecycleObserver;->onStop(Landroidx/lifecycle/LifecycleOwner;)V
+PLandroidx/lifecycle/EmptyActivityLifecycleCallbacks;->onActivityDestroyed(Landroid/app/Activity;)V
+PLandroidx/lifecycle/EmptyActivityLifecycleCallbacks;->onActivityPaused(Landroid/app/Activity;)V
+PLandroidx/lifecycle/EmptyActivityLifecycleCallbacks;->onActivitySaveInstanceState(Landroid/app/Activity;Landroid/os/Bundle;)V
+PLandroidx/lifecycle/EmptyActivityLifecycleCallbacks;->onActivityStopped(Landroid/app/Activity;)V
+PLandroidx/lifecycle/Lifecycle$Event;->downFrom(Landroidx/lifecycle/Lifecycle$State;)Landroidx/lifecycle/Lifecycle$Event;
+PLandroidx/lifecycle/LifecycleDispatcher$DispatcherActivityCallback;->onActivitySaveInstanceState(Landroid/app/Activity;Landroid/os/Bundle;)V
+PLandroidx/lifecycle/LifecycleDispatcher$DispatcherActivityCallback;->onActivityStopped(Landroid/app/Activity;)V
+PLandroidx/lifecycle/LifecycleRegistry;->backwardPass(Landroidx/lifecycle/LifecycleOwner;)V
+PLandroidx/lifecycle/LifecycleRegistry;->markState(Landroidx/lifecycle/Lifecycle$State;)V
+PLandroidx/lifecycle/LifecycleRegistry;->setCurrentState(Landroidx/lifecycle/Lifecycle$State;)V
+PLandroidx/lifecycle/LiveData$LifecycleBoundObserver;->detachObserver()V
+PLandroidx/lifecycle/LiveData;->onInactive()V
+PLandroidx/lifecycle/LiveData;->removeObserver(Landroidx/lifecycle/Observer;)V
+PLandroidx/lifecycle/LiveData;->setValue(Ljava/lang/Object;)V
+PLandroidx/lifecycle/MutableLiveData;->setValue(Ljava/lang/Object;)V
+PLandroidx/lifecycle/ProcessLifecycleOwner$1;->run()V
+PLandroidx/lifecycle/ProcessLifecycleOwner$3;->onActivityPaused(Landroid/app/Activity;)V
+PLandroidx/lifecycle/ProcessLifecycleOwner$3;->onActivityStopped(Landroid/app/Activity;)V
+PLandroidx/lifecycle/ProcessLifecycleOwner;->activityPaused()V
+PLandroidx/lifecycle/ProcessLifecycleOwner;->activityStopped()V
+PLandroidx/lifecycle/ProcessLifecycleOwner;->dispatchPauseIfNeeded()V
+PLandroidx/lifecycle/ProcessLifecycleOwner;->dispatchStopIfNeeded()V
+PLandroidx/lifecycle/ReportFragment$LifecycleCallbacks;->onActivityDestroyed(Landroid/app/Activity;)V
+PLandroidx/lifecycle/ReportFragment$LifecycleCallbacks;->onActivityPaused(Landroid/app/Activity;)V
+PLandroidx/lifecycle/ReportFragment$LifecycleCallbacks;->onActivityPreDestroyed(Landroid/app/Activity;)V
+PLandroidx/lifecycle/ReportFragment$LifecycleCallbacks;->onActivityPrePaused(Landroid/app/Activity;)V
+PLandroidx/lifecycle/ReportFragment$LifecycleCallbacks;->onActivityPreStopped(Landroid/app/Activity;)V
+PLandroidx/lifecycle/ReportFragment$LifecycleCallbacks;->onActivitySaveInstanceState(Landroid/app/Activity;Landroid/os/Bundle;)V
+PLandroidx/lifecycle/ReportFragment$LifecycleCallbacks;->onActivityStopped(Landroid/app/Activity;)V
+PLandroidx/lifecycle/ReportFragment;->onDestroy()V
+PLandroidx/lifecycle/ReportFragment;->onPause()V
+PLandroidx/lifecycle/ReportFragment;->onStop()V
+PLandroidx/lifecycle/SavedStateHandlesProvider;->saveState()Landroid/os/Bundle;
+PLandroidx/lifecycle/SavedStateHandlesVM;->getHandles()Ljava/util/Map;
+PLandroidx/lifecycle/ViewModel;->clear()V
+PLandroidx/lifecycle/ViewModel;->onCleared()V
+PLandroidx/lifecycle/ViewModelStore;->clear()V
+PLandroidx/profileinstaller/DeviceProfileWriter$$ExternalSyntheticLambda0;-><init>(Landroidx/profileinstaller/DeviceProfileWriter;ILjava/lang/Object;)V
+PLandroidx/profileinstaller/DeviceProfileWriter$$ExternalSyntheticLambda0;->run()V
+PLandroidx/profileinstaller/DeviceProfileWriter;->$r8$lambda$ERhlvXCSfTRq-n5iULYjO-Ntn-w(Landroidx/profileinstaller/DeviceProfileWriter;ILjava/lang/Object;)V
+PLandroidx/profileinstaller/DeviceProfileWriter;-><init>(Landroid/content/res/AssetManager;Ljava/util/concurrent/Executor;Landroidx/profileinstaller/ProfileInstaller$DiagnosticsCallback;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/io/File;)V
+PLandroidx/profileinstaller/DeviceProfileWriter;->desiredVersion()[B
+PLandroidx/profileinstaller/DeviceProfileWriter;->deviceAllowsProfileInstallerAotWrites()Z
+PLandroidx/profileinstaller/DeviceProfileWriter;->lambda$result$0(ILjava/lang/Object;)V
+PLandroidx/profileinstaller/DeviceProfileWriter;->result(ILjava/lang/Object;)V
+PLandroidx/profileinstaller/ProfileInstallReceiver$$ExternalSyntheticLambda0;-><init>()V
+PLandroidx/profileinstaller/ProfileInstallReceiver$$ExternalSyntheticLambda0;->execute(Ljava/lang/Runnable;)V
+PLandroidx/profileinstaller/ProfileInstaller$1;-><init>()V
+PLandroidx/profileinstaller/ProfileInstaller$1;->onResultReceived(ILjava/lang/Object;)V
+PLandroidx/profileinstaller/ProfileInstaller$2;-><init>()V
+PLandroidx/profileinstaller/ProfileInstaller;-><clinit>()V
+PLandroidx/profileinstaller/ProfileInstaller;->hasAlreadyWrittenProfileForThisInstall(Landroid/content/pm/PackageInfo;Ljava/io/File;Landroidx/profileinstaller/ProfileInstaller$DiagnosticsCallback;)Z
+PLandroidx/profileinstaller/ProfileInstaller;->transcodeAndWrite(Landroid/content/res/AssetManager;Ljava/lang/String;Landroid/content/pm/PackageInfo;Ljava/io/File;Ljava/lang/String;Ljava/util/concurrent/Executor;Landroidx/profileinstaller/ProfileInstaller$DiagnosticsCallback;)Z
+PLandroidx/profileinstaller/ProfileInstaller;->writeProfile(Landroid/content/Context;)V
+PLandroidx/profileinstaller/ProfileInstaller;->writeProfile(Landroid/content/Context;Ljava/util/concurrent/Executor;Landroidx/profileinstaller/ProfileInstaller$DiagnosticsCallback;)V
+PLandroidx/profileinstaller/ProfileInstaller;->writeProfile(Landroid/content/Context;Ljava/util/concurrent/Executor;Landroidx/profileinstaller/ProfileInstaller$DiagnosticsCallback;Z)V
+PLandroidx/profileinstaller/ProfileInstallerInitializer$$ExternalSyntheticLambda1;->run()V
+PLandroidx/profileinstaller/ProfileInstallerInitializer$$ExternalSyntheticLambda2;-><init>(Landroid/content/Context;)V
+PLandroidx/profileinstaller/ProfileInstallerInitializer$$ExternalSyntheticLambda2;->run()V
+PLandroidx/profileinstaller/ProfileInstallerInitializer;->$r8$lambda$nkOIpN4NfyreWbcXjHv0xCvwgTY(Landroid/content/Context;)V
+PLandroidx/profileinstaller/ProfileInstallerInitializer;->$r8$lambda$nvFqT5BztGB-MvszW9GUTUoI9rw(Landroid/content/Context;)V
+PLandroidx/profileinstaller/ProfileInstallerInitializer;->lambda$installAfterDelay$1(Landroid/content/Context;)V
+PLandroidx/profileinstaller/ProfileInstallerInitializer;->lambda$writeInBackground$2(Landroid/content/Context;)V
+PLandroidx/profileinstaller/ProfileInstallerInitializer;->writeInBackground(Landroid/content/Context;)V
+PLandroidx/profileinstaller/ProfileVerifier$Api33Impl;->getPackageInfo(Landroid/content/pm/PackageManager;Landroid/content/Context;)Landroid/content/pm/PackageInfo;
+PLandroidx/profileinstaller/ProfileVerifier$Cache;-><init>(IIJJ)V
+PLandroidx/profileinstaller/ProfileVerifier$Cache;->equals(Ljava/lang/Object;)Z
+PLandroidx/profileinstaller/ProfileVerifier$Cache;->readFromFile(Ljava/io/File;)Landroidx/profileinstaller/ProfileVerifier$Cache;
+PLandroidx/profileinstaller/ProfileVerifier$Cache;->writeOnFile(Ljava/io/File;)V
+PLandroidx/profileinstaller/ProfileVerifier$CompilationStatus;-><init>(IZZ)V
+PLandroidx/profileinstaller/ProfileVerifier;-><clinit>()V
+PLandroidx/profileinstaller/ProfileVerifier;->getPackageLastUpdateTime(Landroid/content/Context;)J
+PLandroidx/profileinstaller/ProfileVerifier;->setCompilationStatus(IZZ)Landroidx/profileinstaller/ProfileVerifier$CompilationStatus;
+PLandroidx/profileinstaller/ProfileVerifier;->writeProfileVerification(Landroid/content/Context;Z)Landroidx/profileinstaller/ProfileVerifier$CompilationStatus;
+PLandroidx/savedstate/SavedStateRegistry;->performSave(Landroid/os/Bundle;)V
+PLandroidx/savedstate/SavedStateRegistry;->unregisterSavedStateProvider(Ljava/lang/String;)V
+PLandroidx/savedstate/SavedStateRegistryController;->performSave(Landroid/os/Bundle;)V
+PLcom/android/credentialmanager/CredentialManagerRepo;->getCredentialInitialUiState()Lcom/android/credentialmanager/getflow/GetCredentialUiState;
+PLcom/android/credentialmanager/CredentialManagerRepo;->onCancel()V
+PLcom/android/credentialmanager/CredentialManagerRepo;->onOptionSelected(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/Integer;Landroid/content/Intent;)V
+PLcom/android/credentialmanager/CredentialSelectorActivity$CredentialManagerBottomSheet$3;->invoke(Landroidx/compose/runtime/Composer;I)V
+PLcom/android/credentialmanager/CredentialSelectorActivity$CredentialManagerBottomSheet$3;->invoke(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;
+PLcom/android/credentialmanager/CredentialSelectorActivity$CredentialManagerBottomSheet$launcher$1$1;->invoke(Landroidx/activity/result/ActivityResult;)V
+PLcom/android/credentialmanager/CredentialSelectorActivity$CredentialManagerBottomSheet$launcher$1$1;->invoke(Ljava/lang/Object;)Ljava/lang/Object;
+PLcom/android/credentialmanager/CredentialSelectorActivity$onCancel$1;->onChanged(Lcom/android/credentialmanager/common/DialogResult;)V
+PLcom/android/credentialmanager/CredentialSelectorActivity$onCancel$1;->onChanged(Ljava/lang/Object;)V
+PLcom/android/credentialmanager/GetFlowUtils$Companion;-><init>()V
+PLcom/android/credentialmanager/GetFlowUtils$Companion;-><init>(Lkotlin/jvm/internal/DefaultConstructorMarker;)V
+PLcom/android/credentialmanager/GetFlowUtils$Companion;->getActionEntryList(Ljava/lang/String;Ljava/util/List;Landroid/graphics/drawable/Drawable;)Ljava/util/List;
+PLcom/android/credentialmanager/GetFlowUtils$Companion;->getAuthenticationEntry(Ljava/lang/String;Ljava/lang/String;Landroid/graphics/drawable/Drawable;Landroid/credentials/ui/Entry;)Lcom/android/credentialmanager/getflow/AuthenticationEntryInfo;
+PLcom/android/credentialmanager/GetFlowUtils$Companion;->getCredentialOptionInfoList(Ljava/lang/String;Ljava/util/List;Landroid/content/Context;)Ljava/util/List;
+PLcom/android/credentialmanager/GetFlowUtils$Companion;->getRemoteEntry(Ljava/lang/String;Landroid/credentials/ui/Entry;)Lcom/android/credentialmanager/getflow/RemoteEntryInfo;
+PLcom/android/credentialmanager/GetFlowUtils$Companion;->toProviderList(Ljava/util/List;Landroid/content/Context;)Ljava/util/List;
+PLcom/android/credentialmanager/GetFlowUtils$Companion;->toRequestDisplayInfo(Landroid/credentials/ui/RequestInfo;Landroid/content/Context;)Lcom/android/credentialmanager/getflow/RequestDisplayInfo;
+PLcom/android/credentialmanager/GetFlowUtils;-><clinit>()V
+PLcom/android/credentialmanager/UserConfigRepo;->setDefaultProvider(Ljava/lang/String;)V
+PLcom/android/credentialmanager/common/DialogResult;-><clinit>()V
+PLcom/android/credentialmanager/common/DialogResult;-><init>(Lcom/android/credentialmanager/common/ResultState;)V
+PLcom/android/credentialmanager/common/DialogResult;->getResultState()Lcom/android/credentialmanager/common/ResultState;
+PLcom/android/credentialmanager/common/ProviderActivityResult;-><clinit>()V
+PLcom/android/credentialmanager/common/ProviderActivityResult;-><init>(ILandroid/content/Intent;)V
+PLcom/android/credentialmanager/common/ProviderActivityResult;->equals(Ljava/lang/Object;)Z
+PLcom/android/credentialmanager/common/ProviderActivityResult;->getData()Landroid/content/Intent;
+PLcom/android/credentialmanager/common/ProviderActivityResult;->getResultCode()I
+PLcom/android/credentialmanager/common/ResultState;->$values()[Lcom/android/credentialmanager/common/ResultState;
+PLcom/android/credentialmanager/common/ResultState;-><clinit>()V
+PLcom/android/credentialmanager/common/ResultState;-><init>(Ljava/lang/String;I)V
+PLcom/android/credentialmanager/common/material/ModalBottomSheetKt$ModalBottomSheetLayout$1$1$1$1;-><init>(Lcom/android/credentialmanager/common/material/ModalBottomSheetState;Lkotlin/coroutines/Continuation;)V
+PLcom/android/credentialmanager/common/material/ModalBottomSheetKt$ModalBottomSheetLayout$1$1$1$1;->create(Ljava/lang/Object;Lkotlin/coroutines/Continuation;)Lkotlin/coroutines/Continuation;
+PLcom/android/credentialmanager/common/material/ModalBottomSheetKt$ModalBottomSheetLayout$1$1$1$1;->invokeSuspend(Ljava/lang/Object;)Ljava/lang/Object;
+PLcom/android/credentialmanager/common/material/ModalBottomSheetKt$ModalBottomSheetLayout$1$1$1;->invoke()Ljava/lang/Object;
+PLcom/android/credentialmanager/common/material/ModalBottomSheetKt$ModalBottomSheetLayout$1$1$1;->invoke()V
+PLcom/android/credentialmanager/common/material/ModalBottomSheetKt$Scrim$dismissModifier$1$1$1;->invoke(Ljava/lang/Object;)Ljava/lang/Object;
+PLcom/android/credentialmanager/common/material/ModalBottomSheetKt$Scrim$dismissModifier$1$1$1;->invoke-k-4lQ0M(J)V
+PLcom/android/credentialmanager/common/material/ModalBottomSheetKt$rememberModalBottomSheetState$1;->invoke(Lcom/android/credentialmanager/common/material/ModalBottomSheetValue;)Ljava/lang/Boolean;
+PLcom/android/credentialmanager/common/material/ModalBottomSheetKt$rememberModalBottomSheetState$1;->invoke(Ljava/lang/Object;)Ljava/lang/Object;
+PLcom/android/credentialmanager/common/material/ModalBottomSheetState;->hide(Lkotlin/coroutines/Continuation;)Ljava/lang/Object;
+PLcom/android/credentialmanager/common/material/SwipeableKt$PreUpPostDownNestedScrollConnection$1$onPostFling$1;-><init>(Lcom/android/credentialmanager/common/material/SwipeableKt$PreUpPostDownNestedScrollConnection$1;Lkotlin/coroutines/Continuation;)V
+PLcom/android/credentialmanager/common/material/SwipeableKt$PreUpPostDownNestedScrollConnection$1$onPostFling$1;->invokeSuspend(Ljava/lang/Object;)Ljava/lang/Object;
+PLcom/android/credentialmanager/common/material/SwipeableKt$PreUpPostDownNestedScrollConnection$1$onPreFling$1;-><init>(Lcom/android/credentialmanager/common/material/SwipeableKt$PreUpPostDownNestedScrollConnection$1;Lkotlin/coroutines/Continuation;)V
+PLcom/android/credentialmanager/common/material/SwipeableKt$PreUpPostDownNestedScrollConnection$1;->onPostFling-RZ2iAVY(JJLkotlin/coroutines/Continuation;)Ljava/lang/Object;
+PLcom/android/credentialmanager/common/material/SwipeableKt$PreUpPostDownNestedScrollConnection$1;->onPostScroll-DzOQY0M(JJI)J
+PLcom/android/credentialmanager/common/material/SwipeableKt$PreUpPostDownNestedScrollConnection$1;->onPreFling-QWom1Mo(JLkotlin/coroutines/Continuation;)Ljava/lang/Object;
+PLcom/android/credentialmanager/common/material/SwipeableKt$PreUpPostDownNestedScrollConnection$1;->onPreScroll-OzD1aCk(JI)J
+PLcom/android/credentialmanager/common/material/SwipeableKt$PreUpPostDownNestedScrollConnection$1;->toFloat(J)F
+PLcom/android/credentialmanager/common/material/SwipeableKt$PreUpPostDownNestedScrollConnection$1;->toOffset(F)J
+PLcom/android/credentialmanager/common/material/SwipeableKt$swipeable$3$4$1$1;-><init>(Lcom/android/credentialmanager/common/material/SwipeableState;FLkotlin/coroutines/Continuation;)V
+PLcom/android/credentialmanager/common/material/SwipeableKt$swipeable$3$4$1$1;->create(Ljava/lang/Object;Lkotlin/coroutines/Continuation;)Lkotlin/coroutines/Continuation;
+PLcom/android/credentialmanager/common/material/SwipeableKt$swipeable$3$4$1$1;->invokeSuspend(Ljava/lang/Object;)Ljava/lang/Object;
+PLcom/android/credentialmanager/common/material/SwipeableKt$swipeable$3$4$1;->invoke(Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;
+PLcom/android/credentialmanager/common/material/SwipeableKt$swipeable$3$4$1;->invoke(Lkotlinx/coroutines/CoroutineScope;FLkotlin/coroutines/Continuation;)Ljava/lang/Object;
+PLcom/android/credentialmanager/common/material/SwipeableKt$swipeable$3$4$1;->invokeSuspend(Ljava/lang/Object;)Ljava/lang/Object;
+PLcom/android/credentialmanager/common/material/SwipeableState$animateInternalToOffset$2$1;-><init>(Landroidx/compose/foundation/gestures/DragScope;Lkotlin/jvm/internal/Ref$FloatRef;)V
+PLcom/android/credentialmanager/common/material/SwipeableState$animateInternalToOffset$2$1;->invoke(Ljava/lang/Object;)Ljava/lang/Object;
+PLcom/android/credentialmanager/common/material/SwipeableState$animateInternalToOffset$2;-><init>(Lcom/android/credentialmanager/common/material/SwipeableState;FLandroidx/compose/animation/core/AnimationSpec;Lkotlin/coroutines/Continuation;)V
+PLcom/android/credentialmanager/common/material/SwipeableState$animateInternalToOffset$2;->create(Ljava/lang/Object;Lkotlin/coroutines/Continuation;)Lkotlin/coroutines/Continuation;
+PLcom/android/credentialmanager/common/material/SwipeableState$animateInternalToOffset$2;->invoke(Landroidx/compose/foundation/gestures/DragScope;Lkotlin/coroutines/Continuation;)Ljava/lang/Object;
+PLcom/android/credentialmanager/common/material/SwipeableState$animateInternalToOffset$2;->invoke(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;
+PLcom/android/credentialmanager/common/material/SwipeableState$animateInternalToOffset$2;->invokeSuspend(Ljava/lang/Object;)Ljava/lang/Object;
+PLcom/android/credentialmanager/common/material/SwipeableState$animateTo$2$emit$1;-><init>(Lcom/android/credentialmanager/common/material/SwipeableState$animateTo$2;Lkotlin/coroutines/Continuation;)V
+PLcom/android/credentialmanager/common/material/SwipeableState$animateTo$2$emit$1;->invokeSuspend(Ljava/lang/Object;)Ljava/lang/Object;
+PLcom/android/credentialmanager/common/material/SwipeableState$animateTo$2;-><init>(Ljava/lang/Object;Lcom/android/credentialmanager/common/material/SwipeableState;Landroidx/compose/animation/core/AnimationSpec;)V
+PLcom/android/credentialmanager/common/material/SwipeableState$animateTo$2;->emit(Ljava/lang/Object;Lkotlin/coroutines/Continuation;)Ljava/lang/Object;
+PLcom/android/credentialmanager/common/material/SwipeableState$animateTo$2;->emit(Ljava/util/Map;Lkotlin/coroutines/Continuation;)Ljava/lang/Object;
+PLcom/android/credentialmanager/common/material/SwipeableState$latestNonEmptyAnchorsFlow$1;->invoke()Ljava/lang/Object;
+PLcom/android/credentialmanager/common/material/SwipeableState$latestNonEmptyAnchorsFlow$1;->invoke()Ljava/util/Map;
+PLcom/android/credentialmanager/common/material/SwipeableState$performFling$2;-><init>(Lcom/android/credentialmanager/common/material/SwipeableState;F)V
+PLcom/android/credentialmanager/common/material/SwipeableState$performFling$2;->emit(Ljava/lang/Object;Lkotlin/coroutines/Continuation;)Ljava/lang/Object;
+PLcom/android/credentialmanager/common/material/SwipeableState$performFling$2;->emit(Ljava/util/Map;Lkotlin/coroutines/Continuation;)Ljava/lang/Object;
+PLcom/android/credentialmanager/common/material/SwipeableState$processNewAnchors$1;->invokeSuspend(Ljava/lang/Object;)Ljava/lang/Object;
+PLcom/android/credentialmanager/common/material/SwipeableState$special$$inlined$filter$1$2$1;-><init>(Lcom/android/credentialmanager/common/material/SwipeableState$special$$inlined$filter$1$2;Lkotlin/coroutines/Continuation;)V
+PLcom/android/credentialmanager/common/material/SwipeableState$special$$inlined$filter$1$2$1;->invokeSuspend(Ljava/lang/Object;)Ljava/lang/Object;
+PLcom/android/credentialmanager/common/material/SwipeableState$special$$inlined$filter$1$2;-><init>(Lkotlinx/coroutines/flow/FlowCollector;)V
+PLcom/android/credentialmanager/common/material/SwipeableState$special$$inlined$filter$1$2;->emit(Ljava/lang/Object;Lkotlin/coroutines/Continuation;)Ljava/lang/Object;
+PLcom/android/credentialmanager/common/material/SwipeableState$special$$inlined$filter$1;->collect(Lkotlinx/coroutines/flow/FlowCollector;Lkotlin/coroutines/Continuation;)Ljava/lang/Object;
+PLcom/android/credentialmanager/common/material/SwipeableState;->access$animateInternalToOffset(Lcom/android/credentialmanager/common/material/SwipeableState;FLandroidx/compose/animation/core/AnimationSpec;Lkotlin/coroutines/Continuation;)Ljava/lang/Object;
+PLcom/android/credentialmanager/common/material/SwipeableState;->access$getAnimationTarget$p(Lcom/android/credentialmanager/common/material/SwipeableState;)Landroidx/compose/runtime/MutableState;
+PLcom/android/credentialmanager/common/material/SwipeableState;->access$setAnimationRunning(Lcom/android/credentialmanager/common/material/SwipeableState;Z)V
+PLcom/android/credentialmanager/common/material/SwipeableState;->access$setCurrentValue(Lcom/android/credentialmanager/common/material/SwipeableState;Ljava/lang/Object;)V
+PLcom/android/credentialmanager/common/material/SwipeableState;->animateInternalToOffset(FLandroidx/compose/animation/core/AnimationSpec;Lkotlin/coroutines/Continuation;)Ljava/lang/Object;
+PLcom/android/credentialmanager/common/material/SwipeableState;->animateTo$default(Lcom/android/credentialmanager/common/material/SwipeableState;Ljava/lang/Object;Landroidx/compose/animation/core/AnimationSpec;Lkotlin/coroutines/Continuation;ILjava/lang/Object;)Ljava/lang/Object;
+PLcom/android/credentialmanager/common/material/SwipeableState;->animateTo(Ljava/lang/Object;Landroidx/compose/animation/core/AnimationSpec;Lkotlin/coroutines/Continuation;)Ljava/lang/Object;
+PLcom/android/credentialmanager/common/material/SwipeableState;->getConfirmStateChange$frameworks__base__packages__CredentialManager__android_common__CredentialManager()Lkotlin/jvm/functions/Function1;
+PLcom/android/credentialmanager/common/material/SwipeableState;->getVelocityThreshold$frameworks__base__packages__CredentialManager__android_common__CredentialManager()F
+PLcom/android/credentialmanager/common/material/SwipeableState;->performDrag(F)F
+PLcom/android/credentialmanager/common/material/SwipeableState;->performFling(FLkotlin/coroutines/Continuation;)Ljava/lang/Object;
+PLcom/android/credentialmanager/common/material/SwipeableState;->setAnimationRunning(Z)V
+PLcom/android/credentialmanager/common/material/SwipeableState;->setCurrentValue(Ljava/lang/Object;)V
+PLcom/android/credentialmanager/common/ui/EntryKt$TransparentBackgroundEntry$1;-><init>(Lkotlin/jvm/functions/Function0;Lkotlin/jvm/functions/Function2;Landroidx/compose/ui/Modifier;Lkotlin/jvm/functions/Function2;II)V
+PLcom/android/credentialmanager/common/ui/EntryKt;->TransparentBackgroundEntry(Lkotlin/jvm/functions/Function0;Lkotlin/jvm/functions/Function2;Landroidx/compose/ui/Modifier;Lkotlin/jvm/functions/Function2;Landroidx/compose/runtime/Composer;II)V
+PLcom/android/credentialmanager/createflow/ActiveEntry;->equals(Ljava/lang/Object;)Z
+PLcom/android/credentialmanager/createflow/ComposableSingletons$CreateCredentialComponentsKt$lambda-2$1;->invoke(Landroidx/compose/runtime/Composer;I)V
+PLcom/android/credentialmanager/createflow/ComposableSingletons$CreateCredentialComponentsKt$lambda-2$1;->invoke(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;
+PLcom/android/credentialmanager/createflow/ComposableSingletons$CreateCredentialComponentsKt$lambda-3$1;->invoke(Landroidx/compose/runtime/Composer;I)V
+PLcom/android/credentialmanager/createflow/ComposableSingletons$CreateCredentialComponentsKt$lambda-3$1;->invoke(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;
+PLcom/android/credentialmanager/createflow/ComposableSingletons$CreateCredentialComponentsKt;->getLambda-2$frameworks__base__packages__CredentialManager__android_common__CredentialManager()Lkotlin/jvm/functions/Function2;
+PLcom/android/credentialmanager/createflow/ComposableSingletons$CreateCredentialComponentsKt;->getLambda-3$frameworks__base__packages__CredentialManager__android_common__CredentialManager()Lkotlin/jvm/functions/Function2;
+PLcom/android/credentialmanager/createflow/CreateCredentialComponentsKt$CreateCredentialScreen$1$10;-><init>(Ljava/lang/Object;)V
+PLcom/android/credentialmanager/createflow/CreateCredentialComponentsKt$CreateCredentialScreen$1$10;->invoke()Ljava/lang/Object;
+PLcom/android/credentialmanager/createflow/CreateCredentialComponentsKt$CreateCredentialScreen$1$10;->invoke()V
+PLcom/android/credentialmanager/createflow/CreateCredentialComponentsKt$CreateCredentialScreen$1$11;-><init>(Ljava/lang/Object;)V
+PLcom/android/credentialmanager/createflow/CreateCredentialComponentsKt$CreateCredentialScreen$1$11;->invoke(Lcom/android/credentialmanager/createflow/ActiveEntry;)V
+PLcom/android/credentialmanager/createflow/CreateCredentialComponentsKt$CreateCredentialScreen$1$11;->invoke(Ljava/lang/Object;)Ljava/lang/Object;
+PLcom/android/credentialmanager/createflow/CreateCredentialComponentsKt$CreateCredentialScreen$1$12;-><init>(Ljava/lang/Object;)V
+PLcom/android/credentialmanager/createflow/CreateCredentialComponentsKt$CreateCredentialScreen$1$12;->invoke()Ljava/lang/Object;
+PLcom/android/credentialmanager/createflow/CreateCredentialComponentsKt$CreateCredentialScreen$1$12;->invoke()V
+PLcom/android/credentialmanager/createflow/CreateCredentialComponentsKt$CreateCredentialScreen$1$13;-><init>(Ljava/lang/Object;)V
+PLcom/android/credentialmanager/createflow/CreateCredentialComponentsKt$CreateCredentialScreen$1$14;-><init>(Ljava/lang/Object;)V
+PLcom/android/credentialmanager/createflow/CreateCredentialComponentsKt$CreateCredentialScreen$1$14;->invoke()Ljava/lang/Object;
+PLcom/android/credentialmanager/createflow/CreateCredentialComponentsKt$CreateCredentialScreen$1$14;->invoke()V
+PLcom/android/credentialmanager/createflow/CreateCredentialComponentsKt$CreateCredentialScreen$1$15;-><init>(Ljava/lang/Object;)V
+PLcom/android/credentialmanager/createflow/CreateCredentialComponentsKt$CreateCredentialScreen$1$15;->invoke()Ljava/lang/Object;
+PLcom/android/credentialmanager/createflow/CreateCredentialComponentsKt$CreateCredentialScreen$1$15;->invoke()V
+PLcom/android/credentialmanager/createflow/CreateCredentialComponentsKt$CreateCredentialScreen$1$6;->invoke(Lcom/android/credentialmanager/createflow/EntryInfo;)V
+PLcom/android/credentialmanager/createflow/CreateCredentialComponentsKt$CreateCredentialScreen$1$6;->invoke(Ljava/lang/Object;)Ljava/lang/Object;
+PLcom/android/credentialmanager/createflow/CreateCredentialComponentsKt$CreateCredentialScreen$1$7;->invoke()Ljava/lang/Object;
+PLcom/android/credentialmanager/createflow/CreateCredentialComponentsKt$CreateCredentialScreen$1$7;->invoke()V
+PLcom/android/credentialmanager/createflow/CreateCredentialComponentsKt$CreateCredentialScreen$1$8;->invoke()Ljava/lang/Object;
+PLcom/android/credentialmanager/createflow/CreateCredentialComponentsKt$CreateCredentialScreen$1$8;->invoke()V
+PLcom/android/credentialmanager/createflow/CreateCredentialComponentsKt$CreateCredentialScreen$1$9;-><init>(Ljava/lang/Object;)V
+PLcom/android/credentialmanager/createflow/CreateCredentialComponentsKt$CreateCredentialScreen$3;->invoke(Landroidx/compose/runtime/Composer;I)V
+PLcom/android/credentialmanager/createflow/CreateCredentialComponentsKt$CreateCredentialScreen$3;->invoke(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;
+PLcom/android/credentialmanager/createflow/CreateCredentialComponentsKt$MoreOptionsDisabledProvidersRow$1$1$1;-><clinit>()V
+PLcom/android/credentialmanager/createflow/CreateCredentialComponentsKt$MoreOptionsDisabledProvidersRow$1$1$1;-><init>()V
+PLcom/android/credentialmanager/createflow/CreateCredentialComponentsKt$MoreOptionsDisabledProvidersRow$1$1$1;->invoke(Lcom/android/credentialmanager/createflow/ProviderInfo;)Ljava/lang/CharSequence;
+PLcom/android/credentialmanager/createflow/CreateCredentialComponentsKt$MoreOptionsDisabledProvidersRow$1$1$1;->invoke(Ljava/lang/Object;)Ljava/lang/Object;
+PLcom/android/credentialmanager/createflow/CreateCredentialComponentsKt$MoreOptionsDisabledProvidersRow$1;-><init>(Ljava/util/List;)V
+PLcom/android/credentialmanager/createflow/CreateCredentialComponentsKt$MoreOptionsDisabledProvidersRow$1;->invoke(Landroidx/compose/runtime/Composer;I)V
+PLcom/android/credentialmanager/createflow/CreateCredentialComponentsKt$MoreOptionsDisabledProvidersRow$1;->invoke(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;
+PLcom/android/credentialmanager/createflow/CreateCredentialComponentsKt$MoreOptionsInfoRow$1;-><init>(Lcom/android/credentialmanager/createflow/EnabledProviderInfo;Lcom/android/credentialmanager/createflow/CreateOptionInfo;Lcom/android/credentialmanager/createflow/RequestDisplayInfo;)V
+PLcom/android/credentialmanager/createflow/CreateCredentialComponentsKt$MoreOptionsInfoRow$1;->invoke(Landroidx/compose/runtime/Composer;I)V
+PLcom/android/credentialmanager/createflow/CreateCredentialComponentsKt$MoreOptionsInfoRow$1;->invoke(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;
+PLcom/android/credentialmanager/createflow/CreateCredentialComponentsKt$MoreOptionsInfoRow$2;-><init>(Lcom/android/credentialmanager/createflow/EnabledProviderInfo;)V
+PLcom/android/credentialmanager/createflow/CreateCredentialComponentsKt$MoreOptionsInfoRow$2;->invoke(Landroidx/compose/runtime/Composer;I)V
+PLcom/android/credentialmanager/createflow/CreateCredentialComponentsKt$MoreOptionsInfoRow$2;->invoke(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;
+PLcom/android/credentialmanager/createflow/CreateCredentialComponentsKt$MoreOptionsRowIntroCard$1;-><init>(Lcom/android/credentialmanager/createflow/EnabledProviderInfo;Lkotlin/jvm/functions/Function0;ILkotlin/jvm/functions/Function0;)V
+PLcom/android/credentialmanager/createflow/CreateCredentialComponentsKt$MoreOptionsRowIntroCard$1;->invoke(Landroidx/compose/foundation/layout/ColumnScope;Landroidx/compose/runtime/Composer;I)V
+PLcom/android/credentialmanager/createflow/CreateCredentialComponentsKt$MoreOptionsRowIntroCard$1;->invoke(Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;
+PLcom/android/credentialmanager/createflow/CreateCredentialComponentsKt$MoreOptionsSelectionCard$1$1$1;-><init>(Lcom/android/credentialmanager/createflow/RequestDisplayInfo;)V
+PLcom/android/credentialmanager/createflow/CreateCredentialComponentsKt$MoreOptionsSelectionCard$1$1$1;->invoke(Landroidx/compose/runtime/Composer;I)V
+PLcom/android/credentialmanager/createflow/CreateCredentialComponentsKt$MoreOptionsSelectionCard$1$1$1;->invoke(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;
+PLcom/android/credentialmanager/createflow/CreateCredentialComponentsKt$MoreOptionsSelectionCard$1$1$2;-><init>(ZLkotlin/jvm/functions/Function0;Lkotlin/jvm/functions/Function0;)V
+PLcom/android/credentialmanager/createflow/CreateCredentialComponentsKt$MoreOptionsSelectionCard$1$1$2;->invoke(Landroidx/compose/runtime/Composer;I)V
+PLcom/android/credentialmanager/createflow/CreateCredentialComponentsKt$MoreOptionsSelectionCard$1$1$2;->invoke(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;
+PLcom/android/credentialmanager/createflow/CreateCredentialComponentsKt$MoreOptionsSelectionCard$1$1$3$1$1$1$1;-><init>(Lkotlin/jvm/functions/Function1;Lkotlin/Pair;)V
+PLcom/android/credentialmanager/createflow/CreateCredentialComponentsKt$MoreOptionsSelectionCard$1$1$3$1$1$1$1;->invoke()Ljava/lang/Object;
+PLcom/android/credentialmanager/createflow/CreateCredentialComponentsKt$MoreOptionsSelectionCard$1$1$3$1$1$1$1;->invoke()V
+PLcom/android/credentialmanager/createflow/CreateCredentialComponentsKt$MoreOptionsSelectionCard$1$1$3$1$1$1;-><init>(Lcom/android/credentialmanager/createflow/RequestDisplayInfo;Lkotlin/Pair;Lkotlin/jvm/functions/Function1;)V
+PLcom/android/credentialmanager/createflow/CreateCredentialComponentsKt$MoreOptionsSelectionCard$1$1$3$1$1$1;->invoke(Landroidx/compose/foundation/lazy/LazyItemScope;Landroidx/compose/runtime/Composer;I)V
+PLcom/android/credentialmanager/createflow/CreateCredentialComponentsKt$MoreOptionsSelectionCard$1$1$3$1$1$1;->invoke(Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;
+PLcom/android/credentialmanager/createflow/CreateCredentialComponentsKt$MoreOptionsSelectionCard$1$1$3$1$2;-><init>(Ljava/util/List;Lkotlin/jvm/functions/Function0;I)V
+PLcom/android/credentialmanager/createflow/CreateCredentialComponentsKt$MoreOptionsSelectionCard$1$1$3$1$2;->invoke(Landroidx/compose/foundation/lazy/LazyItemScope;Landroidx/compose/runtime/Composer;I)V
+PLcom/android/credentialmanager/createflow/CreateCredentialComponentsKt$MoreOptionsSelectionCard$1$1$3$1$2;->invoke(Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;
+PLcom/android/credentialmanager/createflow/CreateCredentialComponentsKt$MoreOptionsSelectionCard$1$1$3$1;-><init>(ZLjava/util/List;Ljava/util/List;Lcom/android/credentialmanager/createflow/RequestDisplayInfo;Lkotlin/jvm/functions/Function1;Ljava/util/List;Lkotlin/jvm/functions/Function0;ILkotlin/jvm/functions/Function1;I)V
+PLcom/android/credentialmanager/createflow/CreateCredentialComponentsKt$MoreOptionsSelectionCard$1$1$3$1;->invoke(Landroidx/compose/foundation/lazy/LazyListScope;)V
+PLcom/android/credentialmanager/createflow/CreateCredentialComponentsKt$MoreOptionsSelectionCard$1$1$3$1;->invoke(Ljava/lang/Object;)Ljava/lang/Object;
+PLcom/android/credentialmanager/createflow/CreateCredentialComponentsKt$MoreOptionsSelectionCard$1$1$3;-><init>(ZLjava/util/List;Ljava/util/List;Lcom/android/credentialmanager/createflow/RequestDisplayInfo;Lkotlin/jvm/functions/Function1;Ljava/util/List;Lkotlin/jvm/functions/Function0;ILkotlin/jvm/functions/Function1;I)V
+PLcom/android/credentialmanager/createflow/CreateCredentialComponentsKt$MoreOptionsSelectionCard$1$1$3;->invoke(Landroidx/compose/foundation/layout/ColumnScope;Landroidx/compose/runtime/Composer;I)V
+PLcom/android/credentialmanager/createflow/CreateCredentialComponentsKt$MoreOptionsSelectionCard$1$1$3;->invoke(Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;
+PLcom/android/credentialmanager/createflow/CreateCredentialComponentsKt$MoreOptionsSelectionCard$1;-><init>(Lcom/android/credentialmanager/createflow/RequestDisplayInfo;ZLkotlin/jvm/functions/Function0;Lkotlin/jvm/functions/Function0;ZLjava/util/List;Ljava/util/List;Lkotlin/jvm/functions/Function1;Ljava/util/List;Lkotlin/jvm/functions/Function0;ILkotlin/jvm/functions/Function1;I)V
+PLcom/android/credentialmanager/createflow/CreateCredentialComponentsKt$MoreOptionsSelectionCard$1;->invoke(Landroidx/compose/foundation/layout/ColumnScope;Landroidx/compose/runtime/Composer;I)V
+PLcom/android/credentialmanager/createflow/CreateCredentialComponentsKt$MoreOptionsSelectionCard$1;->invoke(Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;
+PLcom/android/credentialmanager/createflow/CreateCredentialComponentsKt$PrimaryCreateOptionRow$1;->invoke()Ljava/lang/Object;
+PLcom/android/credentialmanager/createflow/CreateCredentialComponentsKt$PrimaryCreateOptionRow$1;->invoke()V
+PLcom/android/credentialmanager/createflow/CreateCredentialComponentsKt;->MoreOptionsDisabledProvidersRow(Ljava/util/List;Lkotlin/jvm/functions/Function0;Landroidx/compose/runtime/Composer;I)V
+PLcom/android/credentialmanager/createflow/CreateCredentialComponentsKt;->MoreOptionsInfoRow(Lcom/android/credentialmanager/createflow/RequestDisplayInfo;Lcom/android/credentialmanager/createflow/EnabledProviderInfo;Lcom/android/credentialmanager/createflow/CreateOptionInfo;Lkotlin/jvm/functions/Function0;Landroidx/compose/runtime/Composer;I)V
+PLcom/android/credentialmanager/createflow/CreateCredentialComponentsKt;->MoreOptionsRowIntroCard(Lcom/android/credentialmanager/createflow/EnabledProviderInfo;Lkotlin/jvm/functions/Function0;Lkotlin/jvm/functions/Function0;Landroidx/compose/runtime/Composer;I)V
+PLcom/android/credentialmanager/createflow/CreateCredentialComponentsKt;->MoreOptionsSelectionCard(Lcom/android/credentialmanager/createflow/RequestDisplayInfo;Ljava/util/List;Ljava/util/List;Ljava/util/List;ZZLkotlin/jvm/functions/Function0;Lkotlin/jvm/functions/Function0;Lkotlin/jvm/functions/Function1;Lkotlin/jvm/functions/Function0;Lkotlin/jvm/functions/Function1;Landroidx/compose/runtime/Composer;II)V
+PLcom/android/credentialmanager/createflow/CreateCredentialUiState;->copy$default(Lcom/android/credentialmanager/createflow/CreateCredentialUiState;Ljava/util/List;Ljava/util/List;Lcom/android/credentialmanager/createflow/CreateScreenState;Lcom/android/credentialmanager/createflow/RequestDisplayInfo;Ljava/util/List;ZLcom/android/credentialmanager/createflow/ActiveEntry;Lcom/android/credentialmanager/createflow/EntryInfo;ZZLjava/lang/Boolean;ILjava/lang/Object;)Lcom/android/credentialmanager/createflow/CreateCredentialUiState;
+PLcom/android/credentialmanager/createflow/CreateCredentialUiState;->copy(Ljava/util/List;Ljava/util/List;Lcom/android/credentialmanager/createflow/CreateScreenState;Lcom/android/credentialmanager/createflow/RequestDisplayInfo;Ljava/util/List;ZLcom/android/credentialmanager/createflow/ActiveEntry;Lcom/android/credentialmanager/createflow/EntryInfo;ZZLjava/lang/Boolean;)Lcom/android/credentialmanager/createflow/CreateCredentialUiState;
+PLcom/android/credentialmanager/createflow/CreateCredentialUiState;->equals(Ljava/lang/Object;)Z
+PLcom/android/credentialmanager/createflow/CreateCredentialUiState;->getDisabledProviders()Ljava/util/List;
+PLcom/android/credentialmanager/createflow/CreateCredentialUiState;->getHasDefaultProvider()Z
+PLcom/android/credentialmanager/createflow/CreateCredentialUiState;->getProviderActivityPending()Z
+PLcom/android/credentialmanager/createflow/CreateCredentialUiState;->getSelectedEntry()Lcom/android/credentialmanager/createflow/EntryInfo;
+PLcom/android/credentialmanager/createflow/CreateCredentialUiState;->getSortedCreateOptionsPairs()Ljava/util/List;
+PLcom/android/credentialmanager/createflow/CreateCredentialUiState;->isFromProviderSelection()Ljava/lang/Boolean;
+PLcom/android/credentialmanager/createflow/CreateCredentialViewModel;->launchProviderUi(Landroidx/activity/compose/ManagedActivityResultLauncher;)V
+PLcom/android/credentialmanager/createflow/CreateCredentialViewModel;->onBackCreationSelectionButtonSelected()V
+PLcom/android/credentialmanager/createflow/CreateCredentialViewModel;->onCancel()V
+PLcom/android/credentialmanager/createflow/CreateCredentialViewModel;->onChangeDefaultSelected()V
+PLcom/android/credentialmanager/createflow/CreateCredentialViewModel;->onConfirmEntrySelected()V
+PLcom/android/credentialmanager/createflow/CreateCredentialViewModel;->onDefaultChanged(Ljava/lang/String;)V
+PLcom/android/credentialmanager/createflow/CreateCredentialViewModel;->onDisabledPasswordManagerSelected()V
+PLcom/android/credentialmanager/createflow/CreateCredentialViewModel;->onEntrySelected(Lcom/android/credentialmanager/createflow/EntryInfo;)V
+PLcom/android/credentialmanager/createflow/CreateCredentialViewModel;->onEntrySelectedFromMoreOptionScreen(Lcom/android/credentialmanager/createflow/ActiveEntry;)V
+PLcom/android/credentialmanager/createflow/CreateCredentialViewModel;->onMoreOptionsSelectedOnCreationSelection()V
+PLcom/android/credentialmanager/createflow/CreateCredentialViewModel;->onProviderActivityResult(Lcom/android/credentialmanager/common/ProviderActivityResult;)V
+PLcom/android/credentialmanager/createflow/CreateCredentialViewModel;->onUseOnceSelected()V
+PLcom/android/credentialmanager/createflow/CreateCredentialViewModel;->setUiState(Lcom/android/credentialmanager/createflow/CreateCredentialUiState;)V
+PLcom/android/credentialmanager/createflow/CreateOptionInfo;->getPasskeyCount()Ljava/lang/Integer;
+PLcom/android/credentialmanager/createflow/CreateOptionInfo;->getPasswordCount()Ljava/lang/Integer;
+PLcom/android/credentialmanager/createflow/EntryInfo;->getEntryKey()Ljava/lang/String;
+PLcom/android/credentialmanager/createflow/EntryInfo;->getEntrySubkey()Ljava/lang/String;
+PLcom/android/credentialmanager/createflow/EntryInfo;->getFillInIntent()Landroid/content/Intent;
+PLcom/android/credentialmanager/createflow/EntryInfo;->getPendingIntent()Landroid/app/PendingIntent;
+PLcom/android/credentialmanager/createflow/EntryInfo;->getProviderId()Ljava/lang/String;
+PLcom/android/credentialmanager/createflow/RequestDisplayInfo;->equals(Ljava/lang/Object;)Z
+PLcom/android/credentialmanager/getflow/ActionEntryInfo;-><clinit>()V
+PLcom/android/credentialmanager/getflow/ActionEntryInfo;-><init>(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Landroid/app/PendingIntent;Landroid/content/Intent;Ljava/lang/String;Landroid/graphics/drawable/Drawable;Ljava/lang/String;)V
+PLcom/android/credentialmanager/getflow/ActionEntryInfo;->getIcon()Landroid/graphics/drawable/Drawable;
+PLcom/android/credentialmanager/getflow/ActionEntryInfo;->getSubTitle()Ljava/lang/String;
+PLcom/android/credentialmanager/getflow/ActionEntryInfo;->getTitle()Ljava/lang/String;
+PLcom/android/credentialmanager/getflow/ComposableSingletons$GetCredentialComponentsKt$lambda-1$1;-><clinit>()V
+PLcom/android/credentialmanager/getflow/ComposableSingletons$GetCredentialComponentsKt$lambda-1$1;-><init>()V
+PLcom/android/credentialmanager/getflow/ComposableSingletons$GetCredentialComponentsKt$lambda-1$1;->invoke(Landroidx/compose/runtime/Composer;I)V
+PLcom/android/credentialmanager/getflow/ComposableSingletons$GetCredentialComponentsKt$lambda-1$1;->invoke(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;
+PLcom/android/credentialmanager/getflow/ComposableSingletons$GetCredentialComponentsKt$lambda-2$1;-><clinit>()V
+PLcom/android/credentialmanager/getflow/ComposableSingletons$GetCredentialComponentsKt$lambda-2$1;-><init>()V
+PLcom/android/credentialmanager/getflow/ComposableSingletons$GetCredentialComponentsKt$lambda-2$1;->invoke(Landroidx/compose/runtime/Composer;I)V
+PLcom/android/credentialmanager/getflow/ComposableSingletons$GetCredentialComponentsKt$lambda-2$1;->invoke(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;
+PLcom/android/credentialmanager/getflow/ComposableSingletons$GetCredentialComponentsKt$lambda-3$1;-><clinit>()V
+PLcom/android/credentialmanager/getflow/ComposableSingletons$GetCredentialComponentsKt$lambda-3$1;-><init>()V
+PLcom/android/credentialmanager/getflow/ComposableSingletons$GetCredentialComponentsKt$lambda-3$1;->invoke(Landroidx/compose/runtime/Composer;I)V
+PLcom/android/credentialmanager/getflow/ComposableSingletons$GetCredentialComponentsKt$lambda-3$1;->invoke(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;
+PLcom/android/credentialmanager/getflow/ComposableSingletons$GetCredentialComponentsKt$lambda-4$1;-><clinit>()V
+PLcom/android/credentialmanager/getflow/ComposableSingletons$GetCredentialComponentsKt$lambda-4$1;-><init>()V
+PLcom/android/credentialmanager/getflow/ComposableSingletons$GetCredentialComponentsKt$lambda-5$1;-><clinit>()V
+PLcom/android/credentialmanager/getflow/ComposableSingletons$GetCredentialComponentsKt$lambda-5$1;-><init>()V
+PLcom/android/credentialmanager/getflow/ComposableSingletons$GetCredentialComponentsKt$lambda-6$1;-><clinit>()V
+PLcom/android/credentialmanager/getflow/ComposableSingletons$GetCredentialComponentsKt$lambda-6$1;-><init>()V
+PLcom/android/credentialmanager/getflow/ComposableSingletons$GetCredentialComponentsKt$lambda-7$1;-><clinit>()V
+PLcom/android/credentialmanager/getflow/ComposableSingletons$GetCredentialComponentsKt$lambda-7$1;-><init>()V
+PLcom/android/credentialmanager/getflow/ComposableSingletons$GetCredentialComponentsKt;-><clinit>()V
+PLcom/android/credentialmanager/getflow/ComposableSingletons$GetCredentialComponentsKt;-><init>()V
+PLcom/android/credentialmanager/getflow/ComposableSingletons$GetCredentialComponentsKt;->getLambda-1$frameworks__base__packages__CredentialManager__android_common__CredentialManager()Lkotlin/jvm/functions/Function2;
+PLcom/android/credentialmanager/getflow/ComposableSingletons$GetCredentialComponentsKt;->getLambda-2$frameworks__base__packages__CredentialManager__android_common__CredentialManager()Lkotlin/jvm/functions/Function2;
+PLcom/android/credentialmanager/getflow/ComposableSingletons$GetCredentialComponentsKt;->getLambda-3$frameworks__base__packages__CredentialManager__android_common__CredentialManager()Lkotlin/jvm/functions/Function2;
+PLcom/android/credentialmanager/getflow/CredentialEntryInfo;-><clinit>()V
+PLcom/android/credentialmanager/getflow/CredentialEntryInfo;-><init>(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Landroid/app/PendingIntent;Landroid/content/Intent;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Landroid/graphics/drawable/Drawable;Ljava/lang/Long;)V
+PLcom/android/credentialmanager/getflow/CredentialEntryInfo;->getCredentialType()Ljava/lang/String;
+PLcom/android/credentialmanager/getflow/CredentialEntryInfo;->getCredentialTypeDisplayName()Ljava/lang/String;
+PLcom/android/credentialmanager/getflow/CredentialEntryInfo;->getDisplayName()Ljava/lang/String;
+PLcom/android/credentialmanager/getflow/CredentialEntryInfo;->getIcon()Landroid/graphics/drawable/Drawable;
+PLcom/android/credentialmanager/getflow/CredentialEntryInfo;->getLastUsedTimeMillis()Ljava/lang/Long;
+PLcom/android/credentialmanager/getflow/CredentialEntryInfo;->getUserName()Ljava/lang/String;
+PLcom/android/credentialmanager/getflow/CredentialEntryInfoComparatorByTypeThenTimestamp;-><init>()V
+PLcom/android/credentialmanager/getflow/CredentialEntryInfoComparatorByTypeThenTimestamp;->compare(Lcom/android/credentialmanager/getflow/CredentialEntryInfo;Lcom/android/credentialmanager/getflow/CredentialEntryInfo;)I
+PLcom/android/credentialmanager/getflow/CredentialEntryInfoComparatorByTypeThenTimestamp;->compare(Ljava/lang/Object;Ljava/lang/Object;)I
+PLcom/android/credentialmanager/getflow/EntryInfo;-><clinit>()V
+PLcom/android/credentialmanager/getflow/EntryInfo;-><init>(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Landroid/app/PendingIntent;Landroid/content/Intent;)V
+PLcom/android/credentialmanager/getflow/EntryInfo;->getEntryKey()Ljava/lang/String;
+PLcom/android/credentialmanager/getflow/EntryInfo;->getEntrySubkey()Ljava/lang/String;
+PLcom/android/credentialmanager/getflow/EntryInfo;->getFillInIntent()Landroid/content/Intent;
+PLcom/android/credentialmanager/getflow/EntryInfo;->getPendingIntent()Landroid/app/PendingIntent;
+PLcom/android/credentialmanager/getflow/EntryInfo;->getProviderId()Ljava/lang/String;
+PLcom/android/credentialmanager/getflow/GetCredentialComponentsKt$ActionChips$2;-><init>(Ljava/util/List;Lkotlin/jvm/functions/Function1;I)V
+PLcom/android/credentialmanager/getflow/GetCredentialComponentsKt$ActionChips$2;->invoke(Landroidx/compose/foundation/layout/ColumnScope;Landroidx/compose/runtime/Composer;I)V
+PLcom/android/credentialmanager/getflow/GetCredentialComponentsKt$ActionChips$2;->invoke(Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;
+PLcom/android/credentialmanager/getflow/GetCredentialComponentsKt$ActionChips$3;-><init>(Ljava/util/List;Lkotlin/jvm/functions/Function1;I)V
+PLcom/android/credentialmanager/getflow/GetCredentialComponentsKt$ActionEntryRow$1;-><init>(Lkotlin/jvm/functions/Function1;Lcom/android/credentialmanager/getflow/ActionEntryInfo;)V
+PLcom/android/credentialmanager/getflow/GetCredentialComponentsKt$ActionEntryRow$1;->invoke()Ljava/lang/Object;
+PLcom/android/credentialmanager/getflow/GetCredentialComponentsKt$ActionEntryRow$1;->invoke()V
+PLcom/android/credentialmanager/getflow/GetCredentialComponentsKt$ActionEntryRow$2;-><init>(Lcom/android/credentialmanager/getflow/ActionEntryInfo;)V
+PLcom/android/credentialmanager/getflow/GetCredentialComponentsKt$ActionEntryRow$2;->invoke(Landroidx/compose/runtime/Composer;I)V
+PLcom/android/credentialmanager/getflow/GetCredentialComponentsKt$ActionEntryRow$2;->invoke(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;
+PLcom/android/credentialmanager/getflow/GetCredentialComponentsKt$ActionEntryRow$3;-><init>(Lcom/android/credentialmanager/getflow/ActionEntryInfo;)V
+PLcom/android/credentialmanager/getflow/GetCredentialComponentsKt$ActionEntryRow$3;->invoke(Landroidx/compose/runtime/Composer;I)V
+PLcom/android/credentialmanager/getflow/GetCredentialComponentsKt$ActionEntryRow$3;->invoke(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;
+PLcom/android/credentialmanager/getflow/GetCredentialComponentsKt$AllSignInOptionCard$1$1$1;-><init>(ZLkotlin/jvm/functions/Function0;Lkotlin/jvm/functions/Function0;)V
+PLcom/android/credentialmanager/getflow/GetCredentialComponentsKt$AllSignInOptionCard$1$1$1;->invoke(Landroidx/compose/runtime/Composer;I)V
+PLcom/android/credentialmanager/getflow/GetCredentialComponentsKt$AllSignInOptionCard$1$1$1;->invoke(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;
+PLcom/android/credentialmanager/getflow/GetCredentialComponentsKt$AllSignInOptionCard$1$1$2$1$4;-><init>(Ljava/util/List;Lkotlin/jvm/functions/Function1;I)V
+PLcom/android/credentialmanager/getflow/GetCredentialComponentsKt$AllSignInOptionCard$1$1$2$1$4;->invoke(Landroidx/compose/foundation/lazy/LazyItemScope;Landroidx/compose/runtime/Composer;I)V
+PLcom/android/credentialmanager/getflow/GetCredentialComponentsKt$AllSignInOptionCard$1$1$2$1$4;->invoke(Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;
+PLcom/android/credentialmanager/getflow/GetCredentialComponentsKt$AllSignInOptionCard$1$1$2$1$invoke$$inlined$items$default$1;-><clinit>()V
+PLcom/android/credentialmanager/getflow/GetCredentialComponentsKt$AllSignInOptionCard$1$1$2$1$invoke$$inlined$items$default$1;-><init>()V
+PLcom/android/credentialmanager/getflow/GetCredentialComponentsKt$AllSignInOptionCard$1$1$2$1$invoke$$inlined$items$default$1;->invoke(Ljava/lang/Object;)Ljava/lang/Object;
+PLcom/android/credentialmanager/getflow/GetCredentialComponentsKt$AllSignInOptionCard$1$1$2$1$invoke$$inlined$items$default$1;->invoke(Ljava/lang/Object;)Ljava/lang/Void;
+PLcom/android/credentialmanager/getflow/GetCredentialComponentsKt$AllSignInOptionCard$1$1$2$1$invoke$$inlined$items$default$3;-><init>(Lkotlin/jvm/functions/Function1;Ljava/util/List;)V
+PLcom/android/credentialmanager/getflow/GetCredentialComponentsKt$AllSignInOptionCard$1$1$2$1$invoke$$inlined$items$default$3;->invoke(I)Ljava/lang/Object;
+PLcom/android/credentialmanager/getflow/GetCredentialComponentsKt$AllSignInOptionCard$1$1$2$1$invoke$$inlined$items$default$3;->invoke(Ljava/lang/Object;)Ljava/lang/Object;
+PLcom/android/credentialmanager/getflow/GetCredentialComponentsKt$AllSignInOptionCard$1$1$2$1$invoke$$inlined$items$default$4;-><init>(Ljava/util/List;Lkotlin/jvm/functions/Function1;I)V
+PLcom/android/credentialmanager/getflow/GetCredentialComponentsKt$AllSignInOptionCard$1$1$2$1$invoke$$inlined$items$default$4;->invoke(Landroidx/compose/foundation/lazy/LazyItemScope;ILandroidx/compose/runtime/Composer;I)V
+PLcom/android/credentialmanager/getflow/GetCredentialComponentsKt$AllSignInOptionCard$1$1$2$1$invoke$$inlined$items$default$4;->invoke(Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;
+PLcom/android/credentialmanager/getflow/GetCredentialComponentsKt$AllSignInOptionCard$1$1$2$1;-><init>(Ljava/util/List;Ljava/util/List;Lcom/android/credentialmanager/getflow/ProviderDisplayInfo;Lkotlin/jvm/functions/Function1;ILjava/util/List;)V
+PLcom/android/credentialmanager/getflow/GetCredentialComponentsKt$AllSignInOptionCard$1$1$2$1;->invoke(Landroidx/compose/foundation/lazy/LazyListScope;)V
+PLcom/android/credentialmanager/getflow/GetCredentialComponentsKt$AllSignInOptionCard$1$1$2$1;->invoke(Ljava/lang/Object;)Ljava/lang/Object;
+PLcom/android/credentialmanager/getflow/GetCredentialComponentsKt$AllSignInOptionCard$1$1$2;-><init>(Ljava/util/List;Ljava/util/List;Lcom/android/credentialmanager/getflow/ProviderDisplayInfo;Lkotlin/jvm/functions/Function1;ILjava/util/List;)V
+PLcom/android/credentialmanager/getflow/GetCredentialComponentsKt$AllSignInOptionCard$1$1$2;->invoke(Landroidx/compose/foundation/layout/ColumnScope;Landroidx/compose/runtime/Composer;I)V
+PLcom/android/credentialmanager/getflow/GetCredentialComponentsKt$AllSignInOptionCard$1$1$2;->invoke(Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;
+PLcom/android/credentialmanager/getflow/GetCredentialComponentsKt$AllSignInOptionCard$1;-><init>(ZLkotlin/jvm/functions/Function0;Lkotlin/jvm/functions/Function0;Ljava/util/List;Ljava/util/List;Lcom/android/credentialmanager/getflow/ProviderDisplayInfo;Lkotlin/jvm/functions/Function1;ILjava/util/List;)V
+PLcom/android/credentialmanager/getflow/GetCredentialComponentsKt$AllSignInOptionCard$1;->invoke(Landroidx/compose/foundation/layout/ColumnScope;Landroidx/compose/runtime/Composer;I)V
+PLcom/android/credentialmanager/getflow/GetCredentialComponentsKt$AllSignInOptionCard$1;->invoke(Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;
+PLcom/android/credentialmanager/getflow/GetCredentialComponentsKt$CredentialEntryRow$1;-><init>(Lkotlin/jvm/functions/Function1;Lcom/android/credentialmanager/getflow/CredentialEntryInfo;)V
+PLcom/android/credentialmanager/getflow/GetCredentialComponentsKt$CredentialEntryRow$1;->invoke()Ljava/lang/Object;
+PLcom/android/credentialmanager/getflow/GetCredentialComponentsKt$CredentialEntryRow$1;->invoke()V
+PLcom/android/credentialmanager/getflow/GetCredentialComponentsKt$CredentialEntryRow$2;-><init>(Lcom/android/credentialmanager/getflow/CredentialEntryInfo;)V
+PLcom/android/credentialmanager/getflow/GetCredentialComponentsKt$CredentialEntryRow$2;->invoke(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;
+PLcom/android/credentialmanager/getflow/GetCredentialComponentsKt$CredentialEntryRow$3;-><init>(Lcom/android/credentialmanager/getflow/CredentialEntryInfo;)V
+PLcom/android/credentialmanager/getflow/GetCredentialComponentsKt$CredentialEntryRow$3;->invoke(Landroidx/compose/runtime/Composer;I)V
+PLcom/android/credentialmanager/getflow/GetCredentialComponentsKt$CredentialEntryRow$3;->invoke(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;
+PLcom/android/credentialmanager/getflow/GetCredentialComponentsKt$GetCredentialScreen$1$1;-><init>(Ljava/lang/Object;)V
+PLcom/android/credentialmanager/getflow/GetCredentialComponentsKt$GetCredentialScreen$1$2;-><init>(Ljava/lang/Object;)V
+PLcom/android/credentialmanager/getflow/GetCredentialComponentsKt$GetCredentialScreen$1$2;->invoke()Ljava/lang/Object;
+PLcom/android/credentialmanager/getflow/GetCredentialComponentsKt$GetCredentialScreen$1$2;->invoke()V
+PLcom/android/credentialmanager/getflow/GetCredentialComponentsKt$GetCredentialScreen$1$3;-><init>(Ljava/lang/Object;)V
+PLcom/android/credentialmanager/getflow/GetCredentialComponentsKt$GetCredentialScreen$1$3;->invoke(Lcom/android/credentialmanager/getflow/EntryInfo;)V
+PLcom/android/credentialmanager/getflow/GetCredentialComponentsKt$GetCredentialScreen$1$3;->invoke(Ljava/lang/Object;)Ljava/lang/Object;
+PLcom/android/credentialmanager/getflow/GetCredentialComponentsKt$GetCredentialScreen$1$4;-><init>(Ljava/lang/Object;)V
+PLcom/android/credentialmanager/getflow/GetCredentialComponentsKt$GetCredentialScreen$1$5;-><init>(Ljava/lang/Object;)V
+PLcom/android/credentialmanager/getflow/GetCredentialComponentsKt$GetCredentialScreen$1;-><init>(Lcom/android/credentialmanager/getflow/GetCredentialUiState;Lcom/android/credentialmanager/getflow/GetCredentialViewModel;Landroidx/activity/compose/ManagedActivityResultLauncher;)V
+PLcom/android/credentialmanager/getflow/GetCredentialComponentsKt$GetCredentialScreen$1;->invoke(Landroidx/compose/foundation/layout/ColumnScope;Landroidx/compose/runtime/Composer;I)V
+PLcom/android/credentialmanager/getflow/GetCredentialComponentsKt$GetCredentialScreen$1;->invoke(Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;
+PLcom/android/credentialmanager/getflow/GetCredentialComponentsKt$GetCredentialScreen$2;-><init>(Lcom/android/credentialmanager/common/material/ModalBottomSheetState;Lcom/android/credentialmanager/getflow/GetCredentialViewModel;Lkotlin/coroutines/Continuation;)V
+PLcom/android/credentialmanager/getflow/GetCredentialComponentsKt$GetCredentialScreen$2;->create(Ljava/lang/Object;Lkotlin/coroutines/Continuation;)Lkotlin/coroutines/Continuation;
+PLcom/android/credentialmanager/getflow/GetCredentialComponentsKt$GetCredentialScreen$2;->invokeSuspend(Ljava/lang/Object;)Ljava/lang/Object;
+PLcom/android/credentialmanager/getflow/GetCredentialComponentsKt$GetCredentialScreen$5;-><init>(Lcom/android/credentialmanager/getflow/GetCredentialViewModel;Landroidx/activity/compose/ManagedActivityResultLauncher;I)V
+PLcom/android/credentialmanager/getflow/GetCredentialComponentsKt$GetCredentialScreen$5;->invoke(Landroidx/compose/runtime/Composer;I)V
+PLcom/android/credentialmanager/getflow/GetCredentialComponentsKt$GetCredentialScreen$5;->invoke(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;
+PLcom/android/credentialmanager/getflow/GetCredentialComponentsKt$PerUserNameCredentials$1;-><init>(Lcom/android/credentialmanager/getflow/PerUserNameCredentialEntryList;Lkotlin/jvm/functions/Function1;I)V
+PLcom/android/credentialmanager/getflow/GetCredentialComponentsKt$PerUserNameCredentials$1;->invoke(Landroidx/compose/foundation/layout/ColumnScope;Landroidx/compose/runtime/Composer;I)V
+PLcom/android/credentialmanager/getflow/GetCredentialComponentsKt$PerUserNameCredentials$1;->invoke(Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;
+PLcom/android/credentialmanager/getflow/GetCredentialComponentsKt$PerUserNameCredentials$2;-><init>(Lcom/android/credentialmanager/getflow/PerUserNameCredentialEntryList;Lkotlin/jvm/functions/Function1;I)V
+PLcom/android/credentialmanager/getflow/GetCredentialComponentsKt$PrimarySelectionCard$1$1$1$1$invoke$$inlined$items$default$17;-><clinit>()V
+PLcom/android/credentialmanager/getflow/GetCredentialComponentsKt$PrimarySelectionCard$1$1$1$1$invoke$$inlined$items$default$17;-><init>()V
+PLcom/android/credentialmanager/getflow/GetCredentialComponentsKt$PrimarySelectionCard$1$1$1$1$invoke$$inlined$items$default$17;->invoke(Ljava/lang/Object;)Ljava/lang/Object;
+PLcom/android/credentialmanager/getflow/GetCredentialComponentsKt$PrimarySelectionCard$1$1$1$1$invoke$$inlined$items$default$17;->invoke(Ljava/lang/Object;)Ljava/lang/Void;
+PLcom/android/credentialmanager/getflow/GetCredentialComponentsKt$PrimarySelectionCard$1$1$1$1$invoke$$inlined$items$default$19;-><init>(Lkotlin/jvm/functions/Function1;Ljava/util/List;)V
+PLcom/android/credentialmanager/getflow/GetCredentialComponentsKt$PrimarySelectionCard$1$1$1$1$invoke$$inlined$items$default$19;->invoke(I)Ljava/lang/Object;
+PLcom/android/credentialmanager/getflow/GetCredentialComponentsKt$PrimarySelectionCard$1$1$1$1$invoke$$inlined$items$default$19;->invoke(Ljava/lang/Object;)Ljava/lang/Object;
+PLcom/android/credentialmanager/getflow/GetCredentialComponentsKt$PrimarySelectionCard$1$1$1$1$invoke$$inlined$items$default$1;-><clinit>()V
+PLcom/android/credentialmanager/getflow/GetCredentialComponentsKt$PrimarySelectionCard$1$1$1$1$invoke$$inlined$items$default$1;-><init>()V
+PLcom/android/credentialmanager/getflow/GetCredentialComponentsKt$PrimarySelectionCard$1$1$1$1$invoke$$inlined$items$default$1;->invoke(Ljava/lang/Object;)Ljava/lang/Object;
+PLcom/android/credentialmanager/getflow/GetCredentialComponentsKt$PrimarySelectionCard$1$1$1$1$invoke$$inlined$items$default$1;->invoke(Ljava/lang/Object;)Ljava/lang/Void;
+PLcom/android/credentialmanager/getflow/GetCredentialComponentsKt$PrimarySelectionCard$1$1$1$1$invoke$$inlined$items$default$20;-><init>(Ljava/util/List;Lkotlin/jvm/functions/Function1;I)V
+PLcom/android/credentialmanager/getflow/GetCredentialComponentsKt$PrimarySelectionCard$1$1$1$1$invoke$$inlined$items$default$20;->invoke(Landroidx/compose/foundation/lazy/LazyItemScope;ILandroidx/compose/runtime/Composer;I)V
+PLcom/android/credentialmanager/getflow/GetCredentialComponentsKt$PrimarySelectionCard$1$1$1$1$invoke$$inlined$items$default$20;->invoke(Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;
+PLcom/android/credentialmanager/getflow/GetCredentialComponentsKt$PrimarySelectionCard$1$1$1$1$invoke$$inlined$items$default$3;-><init>(Lkotlin/jvm/functions/Function1;Ljava/util/List;)V
+PLcom/android/credentialmanager/getflow/GetCredentialComponentsKt$PrimarySelectionCard$1$1$1$1$invoke$$inlined$items$default$3;->invoke(I)Ljava/lang/Object;
+PLcom/android/credentialmanager/getflow/GetCredentialComponentsKt$PrimarySelectionCard$1$1$1$1$invoke$$inlined$items$default$3;->invoke(Ljava/lang/Object;)Ljava/lang/Object;
+PLcom/android/credentialmanager/getflow/GetCredentialComponentsKt$PrimarySelectionCard$1$1$1$1$invoke$$inlined$items$default$4;-><init>(Ljava/util/List;Lkotlin/jvm/functions/Function1;I)V
+PLcom/android/credentialmanager/getflow/GetCredentialComponentsKt$PrimarySelectionCard$1$1$1$1$invoke$$inlined$items$default$4;->invoke(Landroidx/compose/foundation/lazy/LazyItemScope;ILandroidx/compose/runtime/Composer;I)V
+PLcom/android/credentialmanager/getflow/GetCredentialComponentsKt$PrimarySelectionCard$1$1$1$1$invoke$$inlined$items$default$4;->invoke(Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;
+PLcom/android/credentialmanager/getflow/GetCredentialComponentsKt$PrimarySelectionCard$1$1$1$1$invoke$$inlined$items$default$5;-><clinit>()V
+PLcom/android/credentialmanager/getflow/GetCredentialComponentsKt$PrimarySelectionCard$1$1$1$1$invoke$$inlined$items$default$5;-><init>()V
+PLcom/android/credentialmanager/getflow/GetCredentialComponentsKt$PrimarySelectionCard$1$1$1$1$invoke$$inlined$items$default$7;-><init>(Lkotlin/jvm/functions/Function1;Ljava/util/List;)V
+PLcom/android/credentialmanager/getflow/GetCredentialComponentsKt$PrimarySelectionCard$1$1$1$1$invoke$$inlined$items$default$8;-><init>(Ljava/util/List;Lkotlin/jvm/functions/Function1;I)V
+PLcom/android/credentialmanager/getflow/GetCredentialComponentsKt$PrimarySelectionCard$1$1$1$1;-><init>(IILjava/util/List;Ljava/util/List;Lkotlin/jvm/functions/Function1;I)V
+PLcom/android/credentialmanager/getflow/GetCredentialComponentsKt$PrimarySelectionCard$1$1$1$1;->invoke(Landroidx/compose/foundation/lazy/LazyListScope;)V
+PLcom/android/credentialmanager/getflow/GetCredentialComponentsKt$PrimarySelectionCard$1$1$1$1;->invoke(Ljava/lang/Object;)Ljava/lang/Object;
+PLcom/android/credentialmanager/getflow/GetCredentialComponentsKt$PrimarySelectionCard$1$1$1;-><init>(Ljava/util/List;Ljava/util/List;Lkotlin/jvm/functions/Function1;I)V
+PLcom/android/credentialmanager/getflow/GetCredentialComponentsKt$PrimarySelectionCard$1$1$1;->invoke(Landroidx/compose/foundation/layout/ColumnScope;Landroidx/compose/runtime/Composer;I)V
+PLcom/android/credentialmanager/getflow/GetCredentialComponentsKt$PrimarySelectionCard$1$1$1;->invoke(Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;
+PLcom/android/credentialmanager/getflow/GetCredentialComponentsKt$PrimarySelectionCard$1;-><init>(Ljava/util/List;Ljava/util/List;Lcom/android/credentialmanager/getflow/RequestDisplayInfo;Lkotlin/jvm/functions/Function1;ILkotlin/jvm/functions/Function0;)V
+PLcom/android/credentialmanager/getflow/GetCredentialComponentsKt$PrimarySelectionCard$1;->invoke(Landroidx/compose/foundation/layout/ColumnScope;Landroidx/compose/runtime/Composer;I)V
+PLcom/android/credentialmanager/getflow/GetCredentialComponentsKt$PrimarySelectionCard$1;->invoke(Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;
+PLcom/android/credentialmanager/getflow/GetCredentialComponentsKt;->ActionChips(Ljava/util/List;Lkotlin/jvm/functions/Function1;Landroidx/compose/runtime/Composer;I)V
+PLcom/android/credentialmanager/getflow/GetCredentialComponentsKt;->ActionEntryRow(Lcom/android/credentialmanager/getflow/ActionEntryInfo;Lkotlin/jvm/functions/Function1;Landroidx/compose/runtime/Composer;I)V
+PLcom/android/credentialmanager/getflow/GetCredentialComponentsKt;->AllSignInOptionCard(Ljava/util/List;Lcom/android/credentialmanager/getflow/ProviderDisplayInfo;Lkotlin/jvm/functions/Function1;Lkotlin/jvm/functions/Function0;Lkotlin/jvm/functions/Function0;ZLandroidx/compose/runtime/Composer;I)V
+PLcom/android/credentialmanager/getflow/GetCredentialComponentsKt;->CredentialEntryRow(Lcom/android/credentialmanager/getflow/CredentialEntryInfo;Lkotlin/jvm/functions/Function1;Landroidx/compose/runtime/Composer;I)V
+PLcom/android/credentialmanager/getflow/GetCredentialComponentsKt;->GetCredentialScreen(Lcom/android/credentialmanager/getflow/GetCredentialViewModel;Landroidx/activity/compose/ManagedActivityResultLauncher;Landroidx/compose/runtime/Composer;I)V
+PLcom/android/credentialmanager/getflow/GetCredentialComponentsKt;->PerUserNameCredentials(Lcom/android/credentialmanager/getflow/PerUserNameCredentialEntryList;Lkotlin/jvm/functions/Function1;Landroidx/compose/runtime/Composer;I)V
+PLcom/android/credentialmanager/getflow/GetCredentialComponentsKt;->PrimarySelectionCard(Lcom/android/credentialmanager/getflow/RequestDisplayInfo;Lcom/android/credentialmanager/getflow/ProviderDisplayInfo;Lkotlin/jvm/functions/Function1;Lkotlin/jvm/functions/Function0;Landroidx/compose/runtime/Composer;I)V
+PLcom/android/credentialmanager/getflow/GetCredentialUiState;-><clinit>()V
+PLcom/android/credentialmanager/getflow/GetCredentialUiState;-><init>(Ljava/util/List;Lcom/android/credentialmanager/getflow/RequestDisplayInfo;Lcom/android/credentialmanager/getflow/GetScreenState;Lcom/android/credentialmanager/getflow/ProviderDisplayInfo;Lcom/android/credentialmanager/getflow/EntryInfo;ZZZ)V
+PLcom/android/credentialmanager/getflow/GetCredentialUiState;-><init>(Ljava/util/List;Lcom/android/credentialmanager/getflow/RequestDisplayInfo;Lcom/android/credentialmanager/getflow/GetScreenState;Lcom/android/credentialmanager/getflow/ProviderDisplayInfo;Lcom/android/credentialmanager/getflow/EntryInfo;ZZZILkotlin/jvm/internal/DefaultConstructorMarker;)V
+PLcom/android/credentialmanager/getflow/GetCredentialUiState;->copy$default(Lcom/android/credentialmanager/getflow/GetCredentialUiState;Ljava/util/List;Lcom/android/credentialmanager/getflow/RequestDisplayInfo;Lcom/android/credentialmanager/getflow/GetScreenState;Lcom/android/credentialmanager/getflow/ProviderDisplayInfo;Lcom/android/credentialmanager/getflow/EntryInfo;ZZZILjava/lang/Object;)Lcom/android/credentialmanager/getflow/GetCredentialUiState;
+PLcom/android/credentialmanager/getflow/GetCredentialUiState;->copy(Ljava/util/List;Lcom/android/credentialmanager/getflow/RequestDisplayInfo;Lcom/android/credentialmanager/getflow/GetScreenState;Lcom/android/credentialmanager/getflow/ProviderDisplayInfo;Lcom/android/credentialmanager/getflow/EntryInfo;ZZZ)Lcom/android/credentialmanager/getflow/GetCredentialUiState;
+PLcom/android/credentialmanager/getflow/GetCredentialUiState;->equals(Ljava/lang/Object;)Z
+PLcom/android/credentialmanager/getflow/GetCredentialUiState;->getCurrentScreenState()Lcom/android/credentialmanager/getflow/GetScreenState;
+PLcom/android/credentialmanager/getflow/GetCredentialUiState;->getHidden()Z
+PLcom/android/credentialmanager/getflow/GetCredentialUiState;->getProviderActivityPending()Z
+PLcom/android/credentialmanager/getflow/GetCredentialUiState;->getProviderDisplayInfo()Lcom/android/credentialmanager/getflow/ProviderDisplayInfo;
+PLcom/android/credentialmanager/getflow/GetCredentialUiState;->getProviderInfoList()Ljava/util/List;
+PLcom/android/credentialmanager/getflow/GetCredentialUiState;->getRequestDisplayInfo()Lcom/android/credentialmanager/getflow/RequestDisplayInfo;
+PLcom/android/credentialmanager/getflow/GetCredentialUiState;->getSelectedEntry()Lcom/android/credentialmanager/getflow/EntryInfo;
+PLcom/android/credentialmanager/getflow/GetCredentialUiState;->isNoAccount()Z
+PLcom/android/credentialmanager/getflow/GetCredentialViewModel$dialogResult$2;-><clinit>()V
+PLcom/android/credentialmanager/getflow/GetCredentialViewModel$dialogResult$2;-><init>()V
+PLcom/android/credentialmanager/getflow/GetCredentialViewModel$dialogResult$2;->invoke()Landroidx/lifecycle/MutableLiveData;
+PLcom/android/credentialmanager/getflow/GetCredentialViewModel$dialogResult$2;->invoke()Ljava/lang/Object;
+PLcom/android/credentialmanager/getflow/GetCredentialViewModel;-><clinit>()V
+PLcom/android/credentialmanager/getflow/GetCredentialViewModel;-><init>()V
+PLcom/android/credentialmanager/getflow/GetCredentialViewModel;-><init>(Lcom/android/credentialmanager/CredentialManagerRepo;)V
+PLcom/android/credentialmanager/getflow/GetCredentialViewModel;-><init>(Lcom/android/credentialmanager/CredentialManagerRepo;ILkotlin/jvm/internal/DefaultConstructorMarker;)V
+PLcom/android/credentialmanager/getflow/GetCredentialViewModel;->getDialogResult()Landroidx/lifecycle/MutableLiveData;
+PLcom/android/credentialmanager/getflow/GetCredentialViewModel;->getUiState()Lcom/android/credentialmanager/getflow/GetCredentialUiState;
+PLcom/android/credentialmanager/getflow/GetCredentialViewModel;->launchProviderUi(Landroidx/activity/compose/ManagedActivityResultLauncher;)V
+PLcom/android/credentialmanager/getflow/GetCredentialViewModel;->observeDialogResult()Landroidx/lifecycle/LiveData;
+PLcom/android/credentialmanager/getflow/GetCredentialViewModel;->onCancel()V
+PLcom/android/credentialmanager/getflow/GetCredentialViewModel;->onEntrySelected(Lcom/android/credentialmanager/getflow/EntryInfo;)V
+PLcom/android/credentialmanager/getflow/GetCredentialViewModel;->onMoreOptionSelected()V
+PLcom/android/credentialmanager/getflow/GetCredentialViewModel;->onProviderActivityResult(Lcom/android/credentialmanager/common/ProviderActivityResult;)V
+PLcom/android/credentialmanager/getflow/GetCredentialViewModel;->setUiState(Lcom/android/credentialmanager/getflow/GetCredentialUiState;)V
+PLcom/android/credentialmanager/getflow/GetCredentialViewModelKt$toProviderDisplayInfo$$inlined$compareByDescending$1;-><init>()V
+PLcom/android/credentialmanager/getflow/GetCredentialViewModelKt$toProviderDisplayInfo$$inlined$compareByDescending$1;->compare(Ljava/lang/Object;Ljava/lang/Object;)I
+PLcom/android/credentialmanager/getflow/GetCredentialViewModelKt$toProviderDisplayInfo$1$1$1;-><init>(Lcom/android/credentialmanager/getflow/CredentialEntryInfo;)V
+PLcom/android/credentialmanager/getflow/GetCredentialViewModelKt$toProviderDisplayInfo$1$1$1;->apply(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;
+PLcom/android/credentialmanager/getflow/GetCredentialViewModelKt$toProviderDisplayInfo$1$1$1;->apply(Ljava/lang/String;Ljava/util/List;)Ljava/util/List;
+PLcom/android/credentialmanager/getflow/GetCredentialViewModelKt;->access$toGetScreenState(Ljava/util/List;)Lcom/android/credentialmanager/getflow/GetScreenState;
+PLcom/android/credentialmanager/getflow/GetCredentialViewModelKt;->access$toProviderDisplayInfo(Ljava/util/List;)Lcom/android/credentialmanager/getflow/ProviderDisplayInfo;
+PLcom/android/credentialmanager/getflow/GetCredentialViewModelKt;->toGetScreenState(Ljava/util/List;)Lcom/android/credentialmanager/getflow/GetScreenState;
+PLcom/android/credentialmanager/getflow/GetCredentialViewModelKt;->toProviderDisplayInfo(Ljava/util/List;)Lcom/android/credentialmanager/getflow/ProviderDisplayInfo;
+PLcom/android/credentialmanager/getflow/GetScreenState;->$values()[Lcom/android/credentialmanager/getflow/GetScreenState;
+PLcom/android/credentialmanager/getflow/GetScreenState;-><clinit>()V
+PLcom/android/credentialmanager/getflow/GetScreenState;-><init>(Ljava/lang/String;I)V
+PLcom/android/credentialmanager/getflow/PerUserNameCredentialEntryList;-><clinit>()V
+PLcom/android/credentialmanager/getflow/PerUserNameCredentialEntryList;-><init>(Ljava/lang/String;Ljava/util/List;)V
+PLcom/android/credentialmanager/getflow/PerUserNameCredentialEntryList;->getSortedCredentialEntryList()Ljava/util/List;
+PLcom/android/credentialmanager/getflow/PerUserNameCredentialEntryList;->getUserName()Ljava/lang/String;
+PLcom/android/credentialmanager/getflow/ProviderDisplayInfo;-><clinit>()V
+PLcom/android/credentialmanager/getflow/ProviderDisplayInfo;-><init>(Ljava/util/List;Ljava/util/List;Lcom/android/credentialmanager/getflow/RemoteEntryInfo;)V
+PLcom/android/credentialmanager/getflow/ProviderDisplayInfo;->equals(Ljava/lang/Object;)Z
+PLcom/android/credentialmanager/getflow/ProviderDisplayInfo;->getAuthenticationEntryList()Ljava/util/List;
+PLcom/android/credentialmanager/getflow/ProviderDisplayInfo;->getRemoteEntry()Lcom/android/credentialmanager/getflow/RemoteEntryInfo;
+PLcom/android/credentialmanager/getflow/ProviderDisplayInfo;->getSortedUserNameToCredentialEntryList()Ljava/util/List;
+PLcom/android/credentialmanager/getflow/ProviderInfo;-><clinit>()V
+PLcom/android/credentialmanager/getflow/ProviderInfo;-><init>(Ljava/lang/String;Landroid/graphics/drawable/Drawable;Ljava/lang/String;Ljava/util/List;Lcom/android/credentialmanager/getflow/AuthenticationEntryInfo;Lcom/android/credentialmanager/getflow/RemoteEntryInfo;Ljava/util/List;)V
+PLcom/android/credentialmanager/getflow/ProviderInfo;->getActionEntryList()Ljava/util/List;
+PLcom/android/credentialmanager/getflow/ProviderInfo;->getAuthenticationEntry()Lcom/android/credentialmanager/getflow/AuthenticationEntryInfo;
+PLcom/android/credentialmanager/getflow/ProviderInfo;->getCredentialEntryList()Ljava/util/List;
+PLcom/android/credentialmanager/getflow/ProviderInfo;->getRemoteEntry()Lcom/android/credentialmanager/getflow/RemoteEntryInfo;
+PLcom/android/credentialmanager/getflow/RequestDisplayInfo;-><clinit>()V
+PLcom/android/credentialmanager/getflow/RequestDisplayInfo;-><init>(Ljava/lang/String;)V
+PLcom/android/credentialmanager/getflow/RequestDisplayInfo;->equals(Ljava/lang/Object;)Z
+PLcom/android/credentialmanager/getflow/RequestDisplayInfo;->getAppName()Ljava/lang/String;
+PLcom/android/credentialmanager/jetpack/provider/Action$Companion;-><init>()V
+PLcom/android/credentialmanager/jetpack/provider/Action$Companion;-><init>(Lkotlin/jvm/internal/DefaultConstructorMarker;)V
+PLcom/android/credentialmanager/jetpack/provider/Action$Companion;->fromSlice(Landroid/app/slice/Slice;)Lcom/android/credentialmanager/jetpack/provider/Action;
+PLcom/android/credentialmanager/jetpack/provider/Action;-><clinit>()V
+PLcom/android/credentialmanager/jetpack/provider/Action;-><init>(Ljava/lang/CharSequence;Ljava/lang/CharSequence;Landroid/app/PendingIntent;)V
+PLcom/android/credentialmanager/jetpack/provider/Action;->getPendingIntent()Landroid/app/PendingIntent;
+PLcom/android/credentialmanager/jetpack/provider/Action;->getSubTitle()Ljava/lang/CharSequence;
+PLcom/android/credentialmanager/jetpack/provider/Action;->getTitle()Ljava/lang/CharSequence;
+PLcom/android/credentialmanager/jetpack/provider/CredentialEntry$Companion;-><init>()V
+PLcom/android/credentialmanager/jetpack/provider/CredentialEntry$Companion;-><init>(Lkotlin/jvm/internal/DefaultConstructorMarker;)V
+PLcom/android/credentialmanager/jetpack/provider/CredentialEntry$Companion;->fromSlice(Landroid/app/slice/Slice;)Lcom/android/credentialmanager/jetpack/provider/CredentialEntry;
+PLcom/android/credentialmanager/jetpack/provider/CredentialEntry;-><clinit>()V
+PLcom/android/credentialmanager/jetpack/provider/CredentialEntry;-><init>(Ljava/lang/String;Ljava/lang/CharSequence;Ljava/lang/CharSequence;Ljava/lang/CharSequence;Landroid/app/PendingIntent;JLandroid/graphics/drawable/Icon;Z)V
+PLcom/android/credentialmanager/jetpack/provider/CredentialEntry;->getDisplayName()Ljava/lang/CharSequence;
+PLcom/android/credentialmanager/jetpack/provider/CredentialEntry;->getIcon()Landroid/graphics/drawable/Icon;
+PLcom/android/credentialmanager/jetpack/provider/CredentialEntry;->getLastUsedTimeMillis()J
+PLcom/android/credentialmanager/jetpack/provider/CredentialEntry;->getPendingIntent()Landroid/app/PendingIntent;
+PLcom/android/credentialmanager/jetpack/provider/CredentialEntry;->getType()Ljava/lang/String;
+PLcom/android/credentialmanager/jetpack/provider/CredentialEntry;->getTypeDisplayName()Ljava/lang/CharSequence;
+PLcom/android/credentialmanager/jetpack/provider/CredentialEntry;->getUsername()Ljava/lang/CharSequence;
+PLkotlin/collections/AbstractList$Companion;->orderedEquals$kotlin_stdlib(Ljava/util/Collection;Ljava/util/Collection;)Z
+PLkotlin/collections/AbstractList;->equals(Ljava/lang/Object;)Z
+PLkotlin/collections/ArraysKt;->fill$default([IIIIILjava/lang/Object;)V
+PLkotlin/collections/ArraysKt;->fill([IIII)V
+PLkotlin/collections/ArraysKt;->indexOf([Ljava/lang/Object;Ljava/lang/Object;)I
+PLkotlin/collections/ArraysKt___ArraysJvmKt;->fill$default([IIIIILjava/lang/Object;)V
+PLkotlin/collections/ArraysKt___ArraysJvmKt;->fill([IIII)V
+PLkotlin/collections/ArraysKt___ArraysKt;->indexOf([Ljava/lang/Object;Ljava/lang/Object;)I
+PLkotlin/collections/CollectionsKt;->arrayListOf([Ljava/lang/Object;)Ljava/util/ArrayList;
+PLkotlin/collections/CollectionsKt;->firstOrNull(Ljava/util/List;)Ljava/lang/Object;
+PLkotlin/collections/CollectionsKt;->getOrNull(Ljava/util/List;I)Ljava/lang/Object;
+PLkotlin/collections/CollectionsKt;->joinToString$default(Ljava/lang/Iterable;Ljava/lang/CharSequence;Ljava/lang/CharSequence;Ljava/lang/CharSequence;ILjava/lang/CharSequence;Lkotlin/jvm/functions/Function1;ILjava/lang/Object;)Ljava/lang/String;
+PLkotlin/collections/CollectionsKt;->mutableListOf([Ljava/lang/Object;)Ljava/util/List;
+PLkotlin/collections/CollectionsKt;->optimizeReadOnlyList(Ljava/util/List;)Ljava/util/List;
+PLkotlin/collections/CollectionsKt;->removeFirstOrNull(Ljava/util/List;)Ljava/lang/Object;
+PLkotlin/collections/CollectionsKt;->take(Ljava/lang/Iterable;I)Ljava/util/List;
+PLkotlin/collections/CollectionsKt;->toIntArray(Ljava/util/Collection;)[I
+PLkotlin/collections/CollectionsKt__CollectionsKt;->arrayListOf([Ljava/lang/Object;)Ljava/util/ArrayList;
+PLkotlin/collections/CollectionsKt__CollectionsKt;->mutableListOf([Ljava/lang/Object;)Ljava/util/List;
+PLkotlin/collections/CollectionsKt__CollectionsKt;->optimizeReadOnlyList(Ljava/util/List;)Ljava/util/List;
+PLkotlin/collections/CollectionsKt__MutableCollectionsKt;->removeFirstOrNull(Ljava/util/List;)Ljava/lang/Object;
+PLkotlin/collections/CollectionsKt___CollectionsKt;->firstOrNull(Ljava/util/List;)Ljava/lang/Object;
+PLkotlin/collections/CollectionsKt___CollectionsKt;->getOrNull(Ljava/util/List;I)Ljava/lang/Object;
+PLkotlin/collections/CollectionsKt___CollectionsKt;->joinTo(Ljava/lang/Iterable;Ljava/lang/Appendable;Ljava/lang/CharSequence;Ljava/lang/CharSequence;Ljava/lang/CharSequence;ILjava/lang/CharSequence;Lkotlin/jvm/functions/Function1;)Ljava/lang/Appendable;
+PLkotlin/collections/CollectionsKt___CollectionsKt;->joinToString$default(Ljava/lang/Iterable;Ljava/lang/CharSequence;Ljava/lang/CharSequence;Ljava/lang/CharSequence;ILjava/lang/CharSequence;Lkotlin/jvm/functions/Function1;ILjava/lang/Object;)Ljava/lang/String;
+PLkotlin/collections/CollectionsKt___CollectionsKt;->joinToString(Ljava/lang/Iterable;Ljava/lang/CharSequence;Ljava/lang/CharSequence;Ljava/lang/CharSequence;ILjava/lang/CharSequence;Lkotlin/jvm/functions/Function1;)Ljava/lang/String;
+PLkotlin/collections/CollectionsKt___CollectionsKt;->take(Ljava/lang/Iterable;I)Ljava/util/List;
+PLkotlin/collections/CollectionsKt___CollectionsKt;->toIntArray(Ljava/util/Collection;)[I
+PLkotlin/collections/EmptyMap;->containsKey(Ljava/lang/Object;)Z
+PLkotlin/collections/EmptyMap;->getSize()I
+PLkotlin/collections/EmptyMap;->size()I
+PLkotlin/collections/MapsKt;->getValue(Ljava/util/Map;Ljava/lang/Object;)Ljava/lang/Object;
+PLkotlin/collections/MapsKt;->toMutableMap(Ljava/util/Map;)Ljava/util/Map;
+PLkotlin/collections/MapsKt__MapWithDefaultKt;->getOrImplicitDefaultNullable(Ljava/util/Map;Ljava/lang/Object;)Ljava/lang/Object;
+PLkotlin/collections/MapsKt__MapsKt;->getValue(Ljava/util/Map;Ljava/lang/Object;)Ljava/lang/Object;
+PLkotlin/collections/MapsKt__MapsKt;->toMutableMap(Ljava/util/Map;)Ljava/util/Map;
+PLkotlin/coroutines/jvm/internal/Boxing;->boxFloat(F)Ljava/lang/Float;
+PLkotlin/coroutines/jvm/internal/Boxing;->boxInt(I)Ljava/lang/Integer;
+PLkotlin/jvm/internal/FunctionReference;->getArity()I
+PLkotlin/jvm/internal/Intrinsics;->areEqual(Ljava/lang/Float;F)Z
+PLkotlin/jvm/internal/Ref$FloatRef;-><init>()V
+PLkotlin/jvm/internal/Ref$LongRef;-><init>()V
+PLkotlin/jvm/internal/TypeIntrinsics;->asMutableCollection(Ljava/lang/Object;)Ljava/util/Collection;
+PLkotlin/jvm/internal/TypeIntrinsics;->castToCollection(Ljava/lang/Object;)Ljava/util/Collection;
+PLkotlin/math/MathKt;->getSign(I)I
+PLkotlin/math/MathKt__MathJVMKt;->getSign(I)I
+PLkotlin/ranges/IntRange;->equals(Ljava/lang/Object;)Z
+PLkotlin/ranges/IntRange;->isEmpty()Z
+PLkotlin/ranges/RangesKt;->coerceAtLeast(JJ)J
+PLkotlin/ranges/RangesKt;->coerceAtMost(FF)F
+PLkotlin/ranges/RangesKt;->coerceAtMost(JJ)J
+PLkotlin/ranges/RangesKt;->coerceIn(DDD)D
+PLkotlin/ranges/RangesKt;->until(II)Lkotlin/ranges/IntRange;
+PLkotlin/ranges/RangesKt___RangesKt;->coerceAtLeast(JJ)J
+PLkotlin/ranges/RangesKt___RangesKt;->coerceAtMost(FF)F
+PLkotlin/ranges/RangesKt___RangesKt;->coerceAtMost(JJ)J
+PLkotlin/ranges/RangesKt___RangesKt;->coerceIn(DDD)D
+PLkotlin/ranges/RangesKt___RangesKt;->until(II)Lkotlin/ranges/IntRange;
+PLkotlin/sequences/SequenceBuilderIterator;-><init>()V
+PLkotlin/sequences/SequenceBuilderIterator;->getContext()Lkotlin/coroutines/CoroutineContext;
+PLkotlin/sequences/SequenceBuilderIterator;->hasNext()Z
+PLkotlin/sequences/SequenceBuilderIterator;->next()Ljava/lang/Object;
+PLkotlin/sequences/SequenceBuilderIterator;->resumeWith(Ljava/lang/Object;)V
+PLkotlin/sequences/SequenceBuilderIterator;->setNextStep(Lkotlin/coroutines/Continuation;)V
+PLkotlin/sequences/SequenceBuilderIterator;->yield(Ljava/lang/Object;Lkotlin/coroutines/Continuation;)Ljava/lang/Object;
+PLkotlin/sequences/SequenceScope;-><init>()V
+PLkotlin/sequences/SequencesKt;->sequence(Lkotlin/jvm/functions/Function2;)Lkotlin/sequences/Sequence;
+PLkotlin/sequences/SequencesKt__SequenceBuilderKt$sequence$$inlined$Sequence$1;-><init>(Lkotlin/jvm/functions/Function2;)V
+PLkotlin/sequences/SequencesKt__SequenceBuilderKt$sequence$$inlined$Sequence$1;->iterator()Ljava/util/Iterator;
+PLkotlin/sequences/SequencesKt__SequenceBuilderKt;->iterator(Lkotlin/jvm/functions/Function2;)Ljava/util/Iterator;
+PLkotlin/sequences/SequencesKt__SequenceBuilderKt;->sequence(Lkotlin/jvm/functions/Function2;)Lkotlin/sequences/Sequence;
+PLkotlin/text/StringsKt;->appendElement(Ljava/lang/Appendable;Ljava/lang/Object;Lkotlin/jvm/functions/Function1;)V
+PLkotlin/text/StringsKt__AppendableKt;->appendElement(Ljava/lang/Appendable;Ljava/lang/Object;Lkotlin/jvm/functions/Function1;)V
+PLkotlinx/coroutines/AbstractTimeSourceKt;-><clinit>()V
+PLkotlinx/coroutines/AbstractTimeSourceKt;->getTimeSource()Lkotlinx/coroutines/AbstractTimeSource;
+PLkotlinx/coroutines/CancellableContinuationImpl;->cancelCompletedResult$external__kotlinx_coroutines__android_common__kotlinx_coroutines(Ljava/lang/Object;Ljava/lang/Throwable;)V
+PLkotlinx/coroutines/CancellableContinuationKt;->disposeOnCancellation(Lkotlinx/coroutines/CancellableContinuation;Lkotlinx/coroutines/DisposableHandle;)V
+PLkotlinx/coroutines/CancellableContinuationKt;->removeOnCancellation(Lkotlinx/coroutines/CancellableContinuation;Lkotlinx/coroutines/internal/LockFreeLinkedListNode;)V
+PLkotlinx/coroutines/CoroutineScopeKt;->cancel$default(Lkotlinx/coroutines/CoroutineScope;Ljava/util/concurrent/CancellationException;ILjava/lang/Object;)V
+PLkotlinx/coroutines/CoroutineScopeKt;->cancel(Lkotlinx/coroutines/CoroutineScope;Ljava/util/concurrent/CancellationException;)V
+PLkotlinx/coroutines/DefaultExecutor;->acknowledgeShutdownIfNeeded()V
+PLkotlinx/coroutines/DefaultExecutor;->createThreadSync()Ljava/lang/Thread;
+PLkotlinx/coroutines/DefaultExecutor;->getThread()Ljava/lang/Thread;
+PLkotlinx/coroutines/DefaultExecutor;->isShutdownRequested()Z
+PLkotlinx/coroutines/DefaultExecutor;->notifyStartup()Z
+PLkotlinx/coroutines/DefaultExecutor;->run()V
+PLkotlinx/coroutines/DelayKt;->delay(JLkotlin/coroutines/Continuation;)Ljava/lang/Object;
+PLkotlinx/coroutines/DelayKt;->getDelay(Lkotlin/coroutines/CoroutineContext;)Lkotlinx/coroutines/Delay;
+PLkotlinx/coroutines/DisposeOnCancel;-><init>(Lkotlinx/coroutines/DisposableHandle;)V
+PLkotlinx/coroutines/DisposeOnCancel;->invoke(Ljava/lang/Throwable;)V
+PLkotlinx/coroutines/EventLoop;->getNextTime()J
+PLkotlinx/coroutines/EventLoop;->isUnconfinedQueueEmpty()Z
+PLkotlinx/coroutines/EventLoopImplBase$DelayedResumeTask;-><init>(Lkotlinx/coroutines/EventLoopImplBase;JLkotlinx/coroutines/CancellableContinuation;)V
+PLkotlinx/coroutines/EventLoopImplBase$DelayedTask;-><init>(J)V
+PLkotlinx/coroutines/EventLoopImplBase$DelayedTask;->dispose()V
+PLkotlinx/coroutines/EventLoopImplBase$DelayedTask;->getHeap()Lkotlinx/coroutines/internal/ThreadSafeHeap;
+PLkotlinx/coroutines/EventLoopImplBase$DelayedTask;->getIndex()I
+PLkotlinx/coroutines/EventLoopImplBase$DelayedTask;->scheduleTask(JLkotlinx/coroutines/EventLoopImplBase$DelayedTaskQueue;Lkotlinx/coroutines/EventLoopImplBase;)I
+PLkotlinx/coroutines/EventLoopImplBase$DelayedTask;->setHeap(Lkotlinx/coroutines/internal/ThreadSafeHeap;)V
+PLkotlinx/coroutines/EventLoopImplBase$DelayedTask;->setIndex(I)V
+PLkotlinx/coroutines/EventLoopImplBase$DelayedTask;->timeToExecute(J)Z
+PLkotlinx/coroutines/EventLoopImplBase$DelayedTaskQueue;-><init>(J)V
+PLkotlinx/coroutines/EventLoopImplBase;->access$isCompleted(Lkotlinx/coroutines/EventLoopImplBase;)Z
+PLkotlinx/coroutines/EventLoopImplBase;->dequeue()Ljava/lang/Runnable;
+PLkotlinx/coroutines/EventLoopImplBase;->getNextTime()J
+PLkotlinx/coroutines/EventLoopImplBase;->isCompleted()Z
+PLkotlinx/coroutines/EventLoopImplBase;->isEmpty()Z
+PLkotlinx/coroutines/EventLoopImplBase;->processNextEvent()J
+PLkotlinx/coroutines/EventLoopImplBase;->schedule(JLkotlinx/coroutines/EventLoopImplBase$DelayedTask;)V
+PLkotlinx/coroutines/EventLoopImplBase;->scheduleImpl(JLkotlinx/coroutines/EventLoopImplBase$DelayedTask;)I
+PLkotlinx/coroutines/EventLoopImplBase;->scheduleResumeAfterDelay(JLkotlinx/coroutines/CancellableContinuation;)V
+PLkotlinx/coroutines/EventLoopImplBase;->shouldUnpark(Lkotlinx/coroutines/EventLoopImplBase$DelayedTask;)Z
+PLkotlinx/coroutines/EventLoopImplPlatform;->unpark()V
+PLkotlinx/coroutines/EventLoop_commonKt;-><clinit>()V
+PLkotlinx/coroutines/EventLoop_commonKt;->access$getDISPOSED_TASK$p()Lkotlinx/coroutines/internal/Symbol;
+PLkotlinx/coroutines/EventLoop_commonKt;->delayToNanos(J)J
+PLkotlinx/coroutines/ExceptionsKt;->CancellationException(Ljava/lang/String;Ljava/lang/Throwable;)Ljava/util/concurrent/CancellationException;
+PLkotlinx/coroutines/InvokeOnCompletion;->invoke(Ljava/lang/Throwable;)V
+PLkotlinx/coroutines/JobImpl;->getOnCancelComplete$external__kotlinx_coroutines__android_common__kotlinx_coroutines()Z
+PLkotlinx/coroutines/JobKt;->cancelAndJoin(Lkotlinx/coroutines/Job;Lkotlin/coroutines/Continuation;)Ljava/lang/Object;
+PLkotlinx/coroutines/JobKt__JobKt;->cancelAndJoin(Lkotlinx/coroutines/Job;Lkotlin/coroutines/Continuation;)Ljava/lang/Object;
+PLkotlinx/coroutines/JobSupport$ChildCompletion;-><init>(Lkotlinx/coroutines/JobSupport;Lkotlinx/coroutines/JobSupport$Finishing;Lkotlinx/coroutines/ChildHandleNode;Ljava/lang/Object;)V
+PLkotlinx/coroutines/JobSupport$ChildCompletion;->invoke(Ljava/lang/Throwable;)V
+PLkotlinx/coroutines/JobSupport$Finishing;->isSealed()Z
+PLkotlinx/coroutines/JobSupport$Finishing;->setRootCause(Ljava/lang/Throwable;)V
+PLkotlinx/coroutines/JobSupport;->access$continueCompleting(Lkotlinx/coroutines/JobSupport;Lkotlinx/coroutines/JobSupport$Finishing;Lkotlinx/coroutines/ChildHandleNode;Ljava/lang/Object;)V
+PLkotlinx/coroutines/JobSupport;->cancellationExceptionMessage()Ljava/lang/String;
+PLkotlinx/coroutines/JobSupport;->continueCompleting(Lkotlinx/coroutines/JobSupport$Finishing;Lkotlinx/coroutines/ChildHandleNode;Ljava/lang/Object;)V
+PLkotlinx/coroutines/JobSupport;->join(Lkotlin/coroutines/Continuation;)Ljava/lang/Object;
+PLkotlinx/coroutines/JobSupport;->joinInternal()Z
+PLkotlinx/coroutines/JobSupport;->joinSuspend(Lkotlin/coroutines/Continuation;)Ljava/lang/Object;
+PLkotlinx/coroutines/JobSupport;->onCompletionInternal(Ljava/lang/Object;)V
+PLkotlinx/coroutines/JobSupport;->tryWaitForChild(Lkotlinx/coroutines/JobSupport$Finishing;Lkotlinx/coroutines/ChildHandleNode;Ljava/lang/Object;)Z
+PLkotlinx/coroutines/JobSupportKt;->access$getTOO_LATE_TO_CANCEL$p()Lkotlinx/coroutines/internal/Symbol;
+PLkotlinx/coroutines/RemoveOnCancel;-><init>(Lkotlinx/coroutines/internal/LockFreeLinkedListNode;)V
+PLkotlinx/coroutines/ResumeOnCompletion;-><init>(Lkotlin/coroutines/Continuation;)V
+PLkotlinx/coroutines/ResumeOnCompletion;->invoke(Ljava/lang/Throwable;)V
+PLkotlinx/coroutines/ThreadLocalEventLoop;->setEventLoop$external__kotlinx_coroutines__android_common__kotlinx_coroutines(Lkotlinx/coroutines/EventLoop;)V
+PLkotlinx/coroutines/UndispatchedCoroutine;->afterResume(Ljava/lang/Object;)V
+PLkotlinx/coroutines/channels/AbstractChannel$RemoveReceiveOnCancel;->invoke(Ljava/lang/Throwable;)V
+PLkotlinx/coroutines/channels/AbstractSendChannel$SendBuffered;-><init>(Ljava/lang/Object;)V
+PLkotlinx/coroutines/channels/AbstractSendChannel$SendBuffered;->completeResumeSend()V
+PLkotlinx/coroutines/channels/AbstractSendChannel$SendBuffered;->getPollResult()Ljava/lang/Object;
+PLkotlinx/coroutines/channels/AbstractSendChannel$SendBuffered;->tryResumeSend(Lkotlinx/coroutines/internal/LockFreeLinkedListNode$PrepareOp;)Lkotlinx/coroutines/internal/Symbol;
+PLkotlinx/coroutines/channels/AbstractSendChannel;->sendBuffered(Ljava/lang/Object;)Lkotlinx/coroutines/channels/ReceiveOrClosed;
+PLkotlinx/coroutines/channels/LinkedListChannel;->offerInternal(Ljava/lang/Object;)Ljava/lang/Object;
+PLkotlinx/coroutines/channels/Send;-><init>()V
+PLkotlinx/coroutines/flow/AbstractFlow$collect$1;->invokeSuspend(Ljava/lang/Object;)Ljava/lang/Object;
+PLkotlinx/coroutines/flow/DistinctFlowImpl$collect$2$emit$1;->invokeSuspend(Ljava/lang/Object;)Ljava/lang/Object;
+PLkotlinx/coroutines/flow/FlowKt__DistinctKt$defaultAreEquivalent$1;->invoke(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Boolean;
+PLkotlinx/coroutines/flow/FlowKt__DistinctKt$defaultAreEquivalent$1;->invoke(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;
+PLkotlinx/coroutines/flow/FlowKt__LimitKt$dropWhile$1$1$emit$1;->invokeSuspend(Ljava/lang/Object;)Ljava/lang/Object;
+PLkotlinx/coroutines/flow/FlowKt__LimitKt$emitAbort$1;-><init>(Lkotlin/coroutines/Continuation;)V
+PLkotlinx/coroutines/flow/FlowKt__LimitKt$emitAbort$1;->invokeSuspend(Ljava/lang/Object;)Ljava/lang/Object;
+PLkotlinx/coroutines/flow/FlowKt__LimitKt$take$$inlined$unsafeFlow$1$1;-><init>(Lkotlinx/coroutines/flow/FlowKt__LimitKt$take$$inlined$unsafeFlow$1;Lkotlin/coroutines/Continuation;)V
+PLkotlinx/coroutines/flow/FlowKt__LimitKt$take$$inlined$unsafeFlow$1$1;->invokeSuspend(Ljava/lang/Object;)Ljava/lang/Object;
+PLkotlinx/coroutines/flow/FlowKt__LimitKt$take$$inlined$unsafeFlow$1;->collect(Lkotlinx/coroutines/flow/FlowCollector;Lkotlin/coroutines/Continuation;)Ljava/lang/Object;
+PLkotlinx/coroutines/flow/FlowKt__LimitKt$take$2$1$emit$1;-><init>(Lkotlinx/coroutines/flow/FlowKt__LimitKt$take$2$1;Lkotlin/coroutines/Continuation;)V
+PLkotlinx/coroutines/flow/FlowKt__LimitKt$take$2$1$emit$1;->invokeSuspend(Ljava/lang/Object;)Ljava/lang/Object;
+PLkotlinx/coroutines/flow/FlowKt__LimitKt$take$2$1;-><init>(Lkotlin/jvm/internal/Ref$IntRef;ILkotlinx/coroutines/flow/FlowCollector;)V
+PLkotlinx/coroutines/flow/FlowKt__LimitKt$take$2$1;->emit(Ljava/lang/Object;Lkotlin/coroutines/Continuation;)Ljava/lang/Object;
+PLkotlinx/coroutines/flow/FlowKt__LimitKt;->access$emitAbort$FlowKt__LimitKt(Lkotlinx/coroutines/flow/FlowCollector;Ljava/lang/Object;Lkotlin/coroutines/Continuation;)Ljava/lang/Object;
+PLkotlinx/coroutines/flow/FlowKt__LimitKt;->emitAbort$FlowKt__LimitKt(Lkotlinx/coroutines/flow/FlowCollector;Ljava/lang/Object;Lkotlin/coroutines/Continuation;)Ljava/lang/Object;
+PLkotlinx/coroutines/flow/FlowKt__ReduceKt$first$3;->invokeSuspend(Ljava/lang/Object;)Ljava/lang/Object;
+PLkotlinx/coroutines/flow/SharedFlowImpl$collect$1;->invokeSuspend(Ljava/lang/Object;)Ljava/lang/Object;
+PLkotlinx/coroutines/flow/SharedFlowImpl;->emit$suspendImpl(Lkotlinx/coroutines/flow/SharedFlowImpl;Ljava/lang/Object;Lkotlin/coroutines/Continuation;)Ljava/lang/Object;
+PLkotlinx/coroutines/flow/SharedFlowImpl;->emit(Ljava/lang/Object;Lkotlin/coroutines/Continuation;)Ljava/lang/Object;
+PLkotlinx/coroutines/flow/SharedFlowImpl;->getQueueEndIndex()J
+PLkotlinx/coroutines/flow/SharedFlowSlot;->freeLocked(Ljava/lang/Object;)[Lkotlin/coroutines/Continuation;
+PLkotlinx/coroutines/flow/SharedFlowSlot;->freeLocked(Lkotlinx/coroutines/flow/SharedFlowImpl;)[Lkotlin/coroutines/Continuation;
+PLkotlinx/coroutines/flow/StartedWhileSubscribed;->access$getReplayExpiration$p(Lkotlinx/coroutines/flow/StartedWhileSubscribed;)J
+PLkotlinx/coroutines/flow/StartedWhileSubscribed;->access$getStopTimeout$p(Lkotlinx/coroutines/flow/StartedWhileSubscribed;)J
+PLkotlinx/coroutines/flow/StateFlowSlot;->freeLocked(Ljava/lang/Object;)[Lkotlin/coroutines/Continuation;
+PLkotlinx/coroutines/flow/StateFlowSlot;->freeLocked(Lkotlinx/coroutines/flow/StateFlowImpl;)[Lkotlin/coroutines/Continuation;
+PLkotlinx/coroutines/flow/internal/AbortFlowException;-><init>(Lkotlinx/coroutines/flow/FlowCollector;)V
+PLkotlinx/coroutines/flow/internal/AbortFlowException;->fillInStackTrace()Ljava/lang/Throwable;
+PLkotlinx/coroutines/flow/internal/AbstractSharedFlow;->freeSlot(Lkotlinx/coroutines/flow/internal/AbstractSharedFlowSlot;)V
+PLkotlinx/coroutines/flow/internal/ChannelFlowTransformLatest$flowCollect$3$1$emit$1;->invokeSuspend(Ljava/lang/Object;)Ljava/lang/Object;
+PLkotlinx/coroutines/flow/internal/ChildCancelledException;-><init>()V
+PLkotlinx/coroutines/flow/internal/ChildCancelledException;->fillInStackTrace()Ljava/lang/Throwable;
+PLkotlinx/coroutines/flow/internal/DownstreamExceptionContext;-><init>(Ljava/lang/Throwable;Lkotlin/coroutines/CoroutineContext;)V
+PLkotlinx/coroutines/flow/internal/FlowExceptions_commonKt;->checkOwnership(Lkotlinx/coroutines/flow/internal/AbortFlowException;Lkotlinx/coroutines/flow/FlowCollector;)V
+PLkotlinx/coroutines/flow/internal/NopCollector;->emit(Ljava/lang/Object;Lkotlin/coroutines/Continuation;)Ljava/lang/Object;
+PLkotlinx/coroutines/flow/internal/SafeCollector;->checkContext(Lkotlin/coroutines/CoroutineContext;Lkotlin/coroutines/CoroutineContext;Ljava/lang/Object;)V
+PLkotlinx/coroutines/flow/internal/SafeCollector;->emit(Ljava/lang/Object;Lkotlin/coroutines/Continuation;)Ljava/lang/Object;
+PLkotlinx/coroutines/flow/internal/SafeCollector;->emit(Lkotlin/coroutines/Continuation;Ljava/lang/Object;)Ljava/lang/Object;
+PLkotlinx/coroutines/flow/internal/SafeCollector;->getContext()Lkotlin/coroutines/CoroutineContext;
+PLkotlinx/coroutines/flow/internal/SafeCollector;->invokeSuspend(Ljava/lang/Object;)Ljava/lang/Object;
+PLkotlinx/coroutines/flow/internal/SafeCollector;->releaseIntercepted()V
+PLkotlinx/coroutines/flow/internal/SafeCollectorKt$emitFun$1;-><clinit>()V
+PLkotlinx/coroutines/flow/internal/SafeCollectorKt$emitFun$1;-><init>()V
+PLkotlinx/coroutines/flow/internal/SafeCollectorKt$emitFun$1;->invoke(Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;
+PLkotlinx/coroutines/flow/internal/SafeCollectorKt$emitFun$1;->invoke(Lkotlinx/coroutines/flow/FlowCollector;Ljava/lang/Object;Lkotlin/coroutines/Continuation;)Ljava/lang/Object;
+PLkotlinx/coroutines/flow/internal/SafeCollectorKt;-><clinit>()V
+PLkotlinx/coroutines/flow/internal/SafeCollectorKt;->access$getEmitFun$p()Lkotlin/jvm/functions/Function3;
+PLkotlinx/coroutines/flow/internal/SafeCollector_commonKt$checkContext$result$1;-><init>(Lkotlinx/coroutines/flow/internal/SafeCollector;)V
+PLkotlinx/coroutines/flow/internal/SafeCollector_commonKt$checkContext$result$1;->invoke(ILkotlin/coroutines/CoroutineContext$Element;)Ljava/lang/Integer;
+PLkotlinx/coroutines/flow/internal/SafeCollector_commonKt$checkContext$result$1;->invoke(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;
+PLkotlinx/coroutines/flow/internal/SafeCollector_commonKt;->checkContext(Lkotlinx/coroutines/flow/internal/SafeCollector;Lkotlin/coroutines/CoroutineContext;)V
+PLkotlinx/coroutines/flow/internal/SafeCollector_commonKt;->transitiveCoroutineParent(Lkotlinx/coroutines/Job;Lkotlinx/coroutines/Job;)Lkotlinx/coroutines/Job;
+PLkotlinx/coroutines/internal/DispatchedContinuation;->postponeCancellation(Ljava/lang/Throwable;)Z
+PLkotlinx/coroutines/internal/LockFreeLinkedListHead;->isEmpty()Z
+PLkotlinx/coroutines/internal/LockFreeLinkedListNode;->addLast(Lkotlinx/coroutines/internal/LockFreeLinkedListNode;)V
+PLkotlinx/coroutines/internal/LockFreeLinkedListNode;->findPrevNonRemoved(Lkotlinx/coroutines/internal/LockFreeLinkedListNode;)Lkotlinx/coroutines/internal/LockFreeLinkedListNode;
+PLkotlinx/coroutines/internal/LockFreeLinkedListNode;->removeFirstOrNull()Lkotlinx/coroutines/internal/LockFreeLinkedListNode;
+PLkotlinx/coroutines/internal/ThreadSafeHeap;-><init>()V
+PLkotlinx/coroutines/internal/ThreadSafeHeap;->addImpl(Lkotlinx/coroutines/internal/ThreadSafeHeapNode;)V
+PLkotlinx/coroutines/internal/ThreadSafeHeap;->firstImpl()Lkotlinx/coroutines/internal/ThreadSafeHeapNode;
+PLkotlinx/coroutines/internal/ThreadSafeHeap;->getSize()I
+PLkotlinx/coroutines/internal/ThreadSafeHeap;->isEmpty()Z
+PLkotlinx/coroutines/internal/ThreadSafeHeap;->peek()Lkotlinx/coroutines/internal/ThreadSafeHeapNode;
+PLkotlinx/coroutines/internal/ThreadSafeHeap;->realloc()[Lkotlinx/coroutines/internal/ThreadSafeHeapNode;
+PLkotlinx/coroutines/internal/ThreadSafeHeap;->remove(Lkotlinx/coroutines/internal/ThreadSafeHeapNode;)Z
+PLkotlinx/coroutines/internal/ThreadSafeHeap;->removeAtImpl(I)Lkotlinx/coroutines/internal/ThreadSafeHeapNode;
+PLkotlinx/coroutines/internal/ThreadSafeHeap;->setSize(I)V
+PLkotlinx/coroutines/internal/ThreadSafeHeap;->siftUpFrom(I)V
+PLkotlinx/coroutines/sync/Mutex$DefaultImpls;->unlock$default(Lkotlinx/coroutines/sync/Mutex;Ljava/lang/Object;ILjava/lang/Object;)V
+PLkotlinx/coroutines/sync/MutexImpl$LockCont$tryResumeLockWaiter$1;-><init>(Lkotlinx/coroutines/sync/MutexImpl;Lkotlinx/coroutines/sync/MutexImpl$LockCont;)V
+PLkotlinx/coroutines/sync/MutexImpl$LockCont;-><init>(Lkotlinx/coroutines/sync/MutexImpl;Ljava/lang/Object;Lkotlinx/coroutines/CancellableContinuation;)V
+PLkotlinx/coroutines/sync/MutexImpl$LockCont;->completeResumeLockWaiter()V
+PLkotlinx/coroutines/sync/MutexImpl$LockCont;->tryResumeLockWaiter()Z
+PLkotlinx/coroutines/sync/MutexImpl$LockWaiter;-><init>(Lkotlinx/coroutines/sync/MutexImpl;Ljava/lang/Object;)V
+PLkotlinx/coroutines/sync/MutexImpl$LockWaiter;->take()Z
+PLkotlinx/coroutines/sync/MutexImpl$LockedQueue;-><init>(Ljava/lang/Object;)V
+PLkotlinx/coroutines/sync/MutexImpl$UnlockOp;-><init>(Lkotlinx/coroutines/sync/MutexImpl$LockedQueue;)V
+PLkotlinx/coroutines/sync/MutexImpl$UnlockOp;->complete(Ljava/lang/Object;Ljava/lang/Object;)V
+PLkotlinx/coroutines/sync/MutexImpl$UnlockOp;->complete(Lkotlinx/coroutines/sync/MutexImpl;Ljava/lang/Object;)V
+PLkotlinx/coroutines/sync/MutexImpl$UnlockOp;->prepare(Ljava/lang/Object;)Ljava/lang/Object;
+PLkotlinx/coroutines/sync/MutexImpl$UnlockOp;->prepare(Lkotlinx/coroutines/sync/MutexImpl;)Ljava/lang/Object;
+PLkotlinx/coroutines/sync/MutexImpl;->access$get_state$p(Lkotlinx/coroutines/sync/MutexImpl;)Lkotlinx/atomicfu/AtomicRef;
+PLkotlinx/coroutines/sync/MutexImpl;->lockSuspend(Ljava/lang/Object;Lkotlin/coroutines/Continuation;)Ljava/lang/Object;
+PLkotlinx/coroutines/sync/MutexKt;->access$getLOCKED$p()Lkotlinx/coroutines/internal/Symbol;
+[Landroidx/compose/animation/core/AnimationEndReason;
+[Landroidx/compose/animation/core/MutatePriority;
+[Landroidx/compose/foundation/MutatePriority;
+[Landroidx/compose/foundation/gestures/Orientation;
+[Landroidx/compose/foundation/layout/Direction;
+[Landroidx/compose/foundation/layout/LayoutOrientation;
+[Landroidx/compose/foundation/layout/RowColumnParentData;
+[Landroidx/compose/foundation/layout/SizeMode;
+[Landroidx/compose/foundation/relocation/BringIntoViewRequesterModifier;
+[Landroidx/compose/material3/tokens/ColorSchemeKeyTokens;
+[Landroidx/compose/material3/tokens/ShapeKeyTokens;
+[Landroidx/compose/material3/tokens/TypographyKeyTokens;
+[Landroidx/compose/runtime/InvalidationResult;
+[Landroidx/compose/runtime/ParcelableSnapshotMutableState;
+[Landroidx/compose/runtime/ProvidedValue;
+[Landroidx/compose/runtime/Recomposer$State;
+[Landroidx/compose/runtime/collection/IdentityArraySet;
+[Landroidx/compose/runtime/external/kotlinx/collections/immutable/implementations/immutableMap/TrieNodeBaseIterator;
+[Landroidx/compose/runtime/snapshots/SnapshotStateObserver$ObservedScopeMap;
+[Landroidx/compose/ui/Modifier$Element;
+[Landroidx/compose/ui/Modifier$Node;
+[Landroidx/compose/ui/Modifier;
+[Landroidx/compose/ui/focus/FocusEventModifierLocal;
+[Landroidx/compose/ui/focus/FocusModifier;
+[Landroidx/compose/ui/focus/FocusRequesterModifierLocal;
+[Landroidx/compose/ui/focus/FocusStateImpl;
+[Landroidx/compose/ui/graphics/colorspace/ColorSpace;
+[Landroidx/compose/ui/input/key/KeyInputModifier;
+[Landroidx/compose/ui/input/pointer/Node;
+[Landroidx/compose/ui/input/pointer/PointerEventPass;
+[Landroidx/compose/ui/input/pointer/SuspendingPointerInputFilter$PointerEventHandlerCoroutine;
+[Landroidx/compose/ui/input/pointer/util/PointAtTime;
+[Landroidx/compose/ui/layout/Measurable;
+[Landroidx/compose/ui/layout/Placeable;
+[Landroidx/compose/ui/modifier/ModifierLocal;
+[Landroidx/compose/ui/node/BackwardsCompatNode;
+[Landroidx/compose/ui/node/LayoutNode$LayoutState;
+[Landroidx/compose/ui/node/LayoutNode$UsageByParent;
+[Landroidx/compose/ui/node/LayoutNode;
+[Landroidx/compose/ui/node/MeasureAndLayoutDelegate$PostponedRequest;
+[Landroidx/compose/ui/node/Owner$OnLayoutCompletedListener;
+[Landroidx/compose/ui/platform/TextToolbarStatus;
+[Landroidx/compose/ui/text/android/style/LineHeightStyleSpan;
+[Landroidx/compose/ui/text/android/style/PlaceholderSpan;
+[Landroidx/compose/ui/text/font/FontWeight;
+[Landroidx/compose/ui/text/platform/style/ShaderBrushSpan;
+[Landroidx/compose/ui/unit/LayoutDirection;
+[Landroidx/compose/ui/unit/TextUnitType;
+[Landroidx/core/content/res/FontResourcesParserCompat$FontFileResourceEntry;
+[Landroidx/core/provider/FontsContractCompat$FontInfo;
+[Landroidx/emoji2/text/EmojiCompat$InitCallback;
+[Landroidx/emoji2/text/EmojiSpan;
+[Landroidx/lifecycle/GeneratedAdapter;
+[Landroidx/lifecycle/Lifecycle$Event;
+[Landroidx/lifecycle/Lifecycle$State;
+[Landroidx/lifecycle/viewmodel/ViewModelInitializer;
+[Lcom/android/credentialmanager/common/DialogType;
+[Lcom/android/credentialmanager/common/material/ModalBottomSheetValue;
+[Lcom/android/credentialmanager/createflow/CreateScreenState;
+[Lcom/android/credentialmanager/jetpack/provider/CredentialCountInformation;
+[Lkotlin/LazyThreadSafetyMode;
+[Lkotlin/Pair;
+[Lkotlin/coroutines/Continuation;
+[Lkotlin/coroutines/CoroutineContext;
+[Lkotlin/coroutines/intrinsics/CoroutineSingletons;
+[Lkotlin/jvm/functions/Function0;
+[Lkotlin/reflect/KClass;
+[Lkotlin/reflect/KProperty;
+[Lkotlinx/atomicfu/AtomicRef;
+[Lkotlinx/coroutines/CoroutineStart;
+[Lkotlinx/coroutines/channels/BufferOverflow;
+[Lkotlinx/coroutines/flow/SharedFlowSlot;
+[Lkotlinx/coroutines/flow/SharingCommand;
+[Lkotlinx/coroutines/flow/StateFlowSlot;
+[Lkotlinx/coroutines/flow/internal/AbstractSharedFlowSlot;
diff --git a/packages/CredentialManager/res/values/strings.xml b/packages/CredentialManager/res/values/strings.xml
index 91ffc44..81505e1 100644
--- a/packages/CredentialManager/res/values/strings.xml
+++ b/packages/CredentialManager/res/values/strings.xml
@@ -5,63 +5,49 @@
<string name="app_name">Credential Manager</string>
<!-- Strings for the create flow. -->
- <!-- Button label to close the dialog when the user does not want to create the credential. [CHAR LIMIT=40] -->
+ <!-- Button label to close the dialog when the user does not want to create the credential. [CHAR LIMIT=20] -->
<string name="string_cancel">Cancel</string>
- <!-- Button label to confirm choosing the default dialog information and continue. [CHAR LIMIT=40] -->
+ <!-- This is a label for a button that takes user to the next screen. [CHAR LIMIT=20] -->
<string name="string_continue">Continue</string>
- <!-- Button label to create this credential in other available places. [CHAR LIMIT=40] -->
+ <!-- This is a label for a button that links to different places where the user can save their passkeys. [CHAR LIMIT=20] -->
<string name="string_more_options">More options</string>
- <!-- This appears as a text button where users can click to create this passkey in other available places. [CHAR LIMIT=80] -->
- <string name="string_create_in_another_place">Create in another place</string>
- <!-- This appears as a text button where users can click to create this password or other credential types in other available places. [CHAR LIMIT=80] -->
- <string name="string_save_to_another_place">Save to another place</string>
- <!-- This appears as a text button where users can click to use another device to create this credential. [CHAR LIMIT=80] -->
- <string name="string_use_another_device">Use another device</string>
- <!-- This appears as a text button where users can click to save this credential to another device. [CHAR LIMIT=80] -->
- <string name="string_save_to_another_device">Save to another device</string>
- <!-- This appears as the title of the modal bottom sheet introducing what is passkey to users. [CHAR LIMIT=200] -->
+ <!-- This string introduces passkeys to the users for the first time they use this method. Tip: to avoid gendered language patterns, this header could be translated as if the original string were "More safety with passkeys". [CHAR LIMIT=200] -->
<string name="passkey_creation_intro_title">Safer with passkeys</string>
- <!-- This appears as the description body of the modal bottom sheet introducing why passkey beneficial on the passwords side. [CHAR LIMIT=200] -->
+ <!-- These strings highlight passkey benefits. [CHAR LIMIT=200] -->
<string name="passkey_creation_intro_body_password">With passkeys, you don’t need to create or remember complex passwords</string>
- <!-- This appears as the description body of the modal bottom sheet introducing why passkey beneficial on the safety side. [CHAR LIMIT=200] -->
<string name="passkey_creation_intro_body_fingerprint">Passkeys are encrypted digital keys you create using your fingerprint, face, or screen lock</string>
- <!-- This appears as the description body of the modal bottom sheet introducing why passkey beneficial on the using other devices side. [CHAR LIMIT=200] -->
<string name="passkey_creation_intro_body_device">They are saved to a password manager, so you can sign in on other devices</string>
- <!-- This appears as the title of the modal bottom sheet which provides all available providers for users to choose. [CHAR LIMIT=200] -->
- <string name="choose_provider_title">Choose where to <xliff:g id="createTypes" example="create your passkeys">%1$s</xliff:g></string>
- <!-- Create types which are inserted as a placeholder for string choose_provider_title. [CHAR LIMIT=200] -->
- <string name="create_your_passkeys">create your passkeys</string>
- <string name="save_your_password">save your password</string>
- <string name="save_your_sign_in_info">save your sign-in info</string>
+ <!-- This appears as the title of the modal bottom sheet which provides all available providers for users to choose. [CHAR LIMIT=200] -->
+ <string name="choose_provider_title">Choose where to save your <xliff:g id="createTypes" example="passkeys">%1$s</xliff:g></string>
<!-- This appears as the description body of the modal bottom sheet which provides all available providers for users to choose. [CHAR LIMIT=200] -->
- <string name="choose_provider_body">Select a password manager to save your info and sign in faster next time.</string>
+ <string name="choose_provider_body">Select a password manager to save your info and sign in faster next time</string>
<!-- This appears as the title of the modal bottom sheet for users to choose the create option inside a provider when the credential type is passkey. [CHAR LIMIT=200] -->
<string name="choose_create_option_passkey_title">Create passkey for <xliff:g id="appName" example="Tribank">%1$s</xliff:g>?</string>
<!-- This appears as the title of the modal bottom sheet for users to choose the create option inside a provider when the credential type is password. [CHAR LIMIT=200] -->
<string name="choose_create_option_password_title">Save password for <xliff:g id="appName" example="Tribank">%1$s</xliff:g>?</string>
<!-- This appears as the title of the modal bottom sheet for users to choose the create option inside a provider when the credential type is others. [CHAR LIMIT=200] -->
<string name="choose_create_option_sign_in_title">Save sign-in info for <xliff:g id="appName" example="Tribank">%1$s</xliff:g>?</string>
- <!-- This appears as the description body of the modal bottom sheet for users to choose the create option inside a provider. [CHAR LIMIT=200] -->
- <string name="choose_create_option_description">You can use your <xliff:g id="appDomainName" example="Tribank">%1$s</xliff:g> <xliff:g id="credentialTypes" example="passkey">%2$s</xliff:g> on any device. It is saved to <xliff:g id="providerInfoDisplayName" example="Google Password Manager">%3$s</xliff:g> for <xliff:g id="createInfoDisplayName" example="elisa.beckett@gmail.com">%4$s</xliff:g>.</string>
<!-- Types which are inserted as a placeholder as credentialTypes for other strings. [CHAR LIMIT=200] -->
<string name="passkey">passkey</string>
<string name="password">password</string>
+ <string name="passkeys">passkeys</string>
+ <string name="passwords">passwords</string>
<string name="sign_ins">sign-ins</string>
<string name="sign_in_info">sign-in info</string>
- <!-- This appears as the title of the modal bottom sheet for users to choose other available places the created password can be saved to. [CHAR LIMIT=200] -->
+ <!-- This text is followed by a list of one or more options. [CHAR LIMIT=200] -->
<string name="save_credential_to_title">Save <xliff:g id="credentialTypes" example="passkey">%1$s</xliff:g> to</string>
<!-- This appears as the title of the modal bottom sheet for users to choose to create a passkey on another device. [CHAR LIMIT=200] -->
- <string name="create_passkey_in_other_device_title">Create a passkey in another device?</string>
+ <string name="create_passkey_in_other_device_title">Create passkey in another device?</string>
<!-- This appears as the title of the modal bottom sheet for users to confirm whether they should use the selected provider as default or not. [CHAR LIMIT=200] -->
<string name="use_provider_for_all_title">Use <xliff:g id="providerInfoDisplayName" example="Google Password Manager">%1$s</xliff:g> for all your sign-ins?</string>
<!-- TODO: Check the wording here. -->
<!-- This appears as the description body of the modal bottom sheet for users to confirm whether they should use the selected provider as default or not. [CHAR LIMIT=200] -->
- <string name="use_provider_for_all_description">This password manager will store your passwords and passkeys to help you easily sign in.</string>
- <!-- Button label to set the selected provider on the modal bottom sheet as default. [CHAR LIMIT=40] -->
+ <string name="use_provider_for_all_description">This password manager will store your passwords and passkeys to help you easily sign in</string>
+ <!-- This is a label for a button that sets this password manager as the default. [CHAR LIMIT=20] -->
<string name="set_as_default">Set as default</string>
- <!-- Button label to set the selected provider on the modal bottom sheet not as default but just use once. [CHAR LIMIT=40] -->
+ <!-- This is a label for a button that makes this password manager be used just in this specific case. [CHAR LIMIT=20] -->
<string name="use_once">Use once</string>
<!-- Appears as an option row subtitle to show how many passwords and passkeys are saved in this option when there are passwords and passkeys. [CHAR LIMIT=80] -->
<string name="more_options_usage_passwords_passkeys"><xliff:g id="passwordsNumber" example="1">%1$s</xliff:g> passwords • <xliff:g id="passkeysNumber" example="2">%2$s</xliff:g> passkeys</string>
@@ -73,7 +59,7 @@
<string name="more_options_usage_credentials"><xliff:g id="totalCredentialsNumber" example="5">%1$s</xliff:g> credentials</string>
<!-- Appears before a request display name when the credential type is passkey . [CHAR LIMIT=80] -->
<string name="passkey_before_subtitle">Passkey</string>
- <!-- Appears as an option row title that users can choose to use another device for this creation. [CHAR LIMIT=80] -->
+ <!-- This is a label for a button that lets users save their passkey to a different device. [CHAR LIMIT=80] -->
<string name="another_device">Another device</string>
<!-- Appears as an option row title that users can choose to view other disabled providers. [CHAR LIMIT=80] -->
<string name="other_password_manager">Other password managers</string>
@@ -91,15 +77,15 @@
<string name="get_dialog_title_use_sign_in_for">Use your saved sign-in for <xliff:g id="app_name" example="YouTube">%1$s</xliff:g>?</string>
<!-- This appears as the title of the dialog asking for user to make a choice from various previously saved credentials to sign in to the app. [CHAR LIMIT=200] -->
<string name="get_dialog_title_choose_sign_in_for">Choose a saved sign-in for <xliff:g id="app_name" example="YouTube">%1$s</xliff:g></string>
- <!-- Appears as an option row for viewing all the available sign-in options. [CHAR LIMIT=80] -->
+ <!-- This is a label for a button that links the user to different sign-in methods . [CHAR LIMIT=80] -->
<string name="get_dialog_use_saved_passkey_for">Sign in another way</string>
- <!-- Appears as a text button in the snackbar for users to click to view all options. [CHAR LIMIT=80] -->
+ <!-- This is a label for a button that links the user to different sign-in methods. [CHAR LIMIT=80] -->
<string name="snackbar_action">View options</string>
- <!-- Button label to continue with the selected sign-in. [CHAR LIMIT=40] -->
+ <!-- This is a label for a button that takes user to the next screen. [CHAR LIMIT=20] -->
<string name="get_dialog_button_label_continue">Continue</string>
<!-- Separator for sign-in type and username in a sign-in entry. -->
<string name="get_dialog_sign_in_type_username_separator" translatable="false">" - "</string>
- <!-- Modal bottom sheet title for displaying all the available sign-in options. [CHAR LIMIT=80] -->
+ <!-- This text is followed by a list of one or more options. [CHAR LIMIT=80] -->
<string name="get_dialog_title_sign_in_options">Sign-in options</string>
<!-- Column heading for displaying sign-ins for a specific username. [CHAR LIMIT=80] -->
<string name="get_dialog_heading_for_username">For <xliff:g id="username" example="becket@gmail.com">%1$s</xliff:g></string>
@@ -111,6 +97,6 @@
<string name="get_dialog_heading_manage_sign_ins">Manage sign-ins</string>
<!-- Column heading for displaying option to use sign-ins saved on a different device. [CHAR LIMIT=80] -->
<string name="get_dialog_heading_from_another_device">From another device</string>
- <!-- Headline text for an option to use sign-ins saved on a different device. [CHAR LIMIT=120] -->
+ <!-- This is a label for a button that takes the user to other available devices. [CHAR LIMIT=120] -->
<string name="get_dialog_option_headline_use_a_different_device">Use a different device</string>
</resources>
\ No newline at end of file
diff --git a/packages/CredentialManager/src/com/android/credentialmanager/CredentialManagerRepo.kt b/packages/CredentialManager/src/com/android/credentialmanager/CredentialManagerRepo.kt
index 0e3772a..7d43364 100644
--- a/packages/CredentialManager/src/com/android/credentialmanager/CredentialManagerRepo.kt
+++ b/packages/CredentialManager/src/com/android/credentialmanager/CredentialManagerRepo.kt
@@ -45,7 +45,7 @@
import com.android.credentialmanager.createflow.EnabledProviderInfo
import com.android.credentialmanager.createflow.RequestDisplayInfo
import com.android.credentialmanager.getflow.GetCredentialUiState
-import com.android.credentialmanager.jetpack.developer.CreatePasswordRequest.Companion.toBundle
+import com.android.credentialmanager.jetpack.developer.CreatePasswordRequest.Companion.toCredentialDataBundle
import com.android.credentialmanager.jetpack.developer.CreatePublicKeyCredentialRequest
import com.android.credentialmanager.jetpack.developer.PublicKeyCredential.Companion.TYPE_PUBLIC_KEY_CREDENTIAL
import com.android.credentialmanager.jetpack.provider.Action
@@ -128,7 +128,7 @@
val providerEnabledList = GetFlowUtils.toProviderList(
// TODO: handle runtime cast error
providerEnabledList as List<GetCredentialProviderData>, context)
- val requestDisplayInfo = GetFlowUtils.toRequestDisplayInfo(requestInfo)
+ val requestDisplayInfo = GetFlowUtils.toRequestDisplayInfo(requestInfo, context)
return GetCredentialUiState(
providerEnabledList,
requestDisplayInfo,
@@ -152,22 +152,6 @@
return CreateFlowUtils.toRequestDisplayInfo(requestInfo, context)
}
- companion object {
- // TODO: find a way to resolve this static field leak problem
- lateinit var repo: CredentialManagerRepo
-
- fun setup(
- context: Context,
- intent: Intent,
- ) {
- repo = CredentialManagerRepo(context, intent)
- }
-
- fun getInstance(): CredentialManagerRepo {
- return repo
- }
- }
-
// TODO: below are prototype functionalities. To be removed for productionization.
private fun testCreateCredentialEnabledProviderList(): List<CreateCredentialProviderData> {
return listOf(
@@ -176,9 +160,11 @@
.setSaveEntries(
listOf<Entry>(
newCreateEntry("key1", "subkey-1", "elisa.beckett@gmail.com",
- 20, 7, 27, 10L),
+ 20, 7, 27, 10L,
+ "Optional footer description"),
newCreateEntry("key1", "subkey-2", "elisa.work@google.com",
- 20, 7, 27, 12L),
+ 20, 7, 27, 12L,
+ null),
)
)
.setRemoteEntry(
@@ -190,9 +176,11 @@
.setSaveEntries(
listOf<Entry>(
newCreateEntry("key1", "subkey-3", "elisa.beckett@dashlane.com",
- 20, 7, 27, 11L),
+ 20, 7, 27, 11L,
+ null),
newCreateEntry("key1", "subkey-4", "elisa.work@dashlane.com",
- 20, 7, 27, 14L),
+ 20, 7, 27, 14L,
+ null),
)
)
.build(),
@@ -325,7 +313,7 @@
key,
subkey,
CredentialEntry.toSlice(credentialEntry),
- null
+ Intent()
)
}
@@ -337,6 +325,7 @@
passkeyCount: Int,
totalCredentialCount: Int,
lastUsedTimeMillis: Long,
+ footerDescription: String?,
): Entry {
val intent = Intent("com.androidauth.androidvault.CONFIRM_PASSWORD")
.setPackage("com.androidauth.androidvault")
@@ -348,7 +337,7 @@
android.service.credentials.CallingAppInfo(
context.applicationInfo.packageName, SigningInfo()),
TYPE_PASSWORD_CREDENTIAL,
- toBundle("beckett-bakert@gmail.com", "password123")
+ toCredentialDataBundle("beckett-bakert@gmail.com", "password123")
)
val fillInIntent = Intent().putExtra(
CredentialProviderService.EXTRA_CREATE_CREDENTIAL_REQUEST,
@@ -360,7 +349,7 @@
listOf(
CredentialCountInformation.createPasswordCountInformation(passwordCount),
CredentialCountInformation.createPublicKeyCountInformation(passkeyCount),
- ))
+ ), footerDescription)
return Entry(
key,
subkey,
@@ -417,7 +406,7 @@
" \"residentKey\": \"required\",\n" +
" \"requireResidentKey\": true\n" +
" }}")
- val credentialData = request.data
+ val credentialData = request.credentialData
return RequestInfo.newCreateRequestInfo(
Binder(),
CreateCredentialRequest(
@@ -427,12 +416,12 @@
/*candidateQueryData=*/ Bundle(),
/*requireSystemProvider=*/ false
),
- "tribank"
+ "com.google.android.youtube"
)
}
private fun testCreatePasswordRequestInfo(): RequestInfo {
- val data = toBundle("beckett-bakert@gmail.com", "password123")
+ val data = toCredentialDataBundle("beckett-bakert@gmail.com", "password123")
return RequestInfo.newCreateRequestInfo(
Binder(),
CreateCredentialRequest(
@@ -442,7 +431,7 @@
/*candidateQueryData=*/ Bundle(),
/*requireSystemProvider=*/ false
),
- "tribank"
+ "com.google.android.youtube"
)
}
@@ -456,7 +445,7 @@
/*candidateQueryData=*/ Bundle(),
/*requireSystemProvider=*/ false
),
- "tribank"
+ "com.google.android.youtube"
)
}
@@ -471,7 +460,7 @@
TYPE_PUBLIC_KEY_CREDENTIAL, Bundle(), Bundle(), /*requireSystemProvider=*/ false)
)
.build(),
- "tribank.us"
+ "com.google.android.youtube"
)
}
}
diff --git a/packages/CredentialManager/src/com/android/credentialmanager/CredentialSelectorActivity.kt b/packages/CredentialManager/src/com/android/credentialmanager/CredentialSelectorActivity.kt
index cdff2d4..0620f9a 100644
--- a/packages/CredentialManager/src/com/android/credentialmanager/CredentialSelectorActivity.kt
+++ b/packages/CredentialManager/src/com/android/credentialmanager/CredentialSelectorActivity.kt
@@ -16,7 +16,9 @@
package com.android.credentialmanager
+import android.content.Intent
import android.os.Bundle
+import android.provider.Settings
import android.util.Log
import androidx.activity.ComponentActivity
import androidx.activity.compose.rememberLauncherForActivityResult
@@ -26,7 +28,7 @@
import androidx.compose.runtime.Composable
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
-import androidx.lifecycle.Observer
+import androidx.lifecycle.lifecycleScope
import androidx.lifecycle.viewmodel.compose.viewModel
import com.android.credentialmanager.common.DialogType
import com.android.credentialmanager.common.DialogResult
@@ -37,24 +39,25 @@
import com.android.credentialmanager.getflow.GetCredentialScreen
import com.android.credentialmanager.getflow.GetCredentialViewModel
import com.android.credentialmanager.ui.theme.CredentialSelectorTheme
+import kotlinx.coroutines.launch
@ExperimentalMaterialApi
class CredentialSelectorActivity : ComponentActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
- CredentialManagerRepo.setup(this, intent)
+ val credManRepo = CredentialManagerRepo(this, intent)
UserConfigRepo.setup(this)
- val requestInfo = CredentialManagerRepo.getInstance().requestInfo
+ val requestInfo = credManRepo.requestInfo
setContent {
CredentialSelectorTheme {
- CredentialManagerBottomSheet(DialogType.toDialogType(requestInfo.type))
+ CredentialManagerBottomSheet(DialogType.toDialogType(requestInfo.type), credManRepo)
}
}
}
@ExperimentalMaterialApi
@Composable
- fun CredentialManagerBottomSheet(dialogType: DialogType) {
+ fun CredentialManagerBottomSheet(dialogType: DialogType, credManRepo: CredentialManagerRepo) {
val providerActivityResult = remember { mutableStateOf<ProviderActivityResult?>(null) }
val launcher = rememberLauncherForActivityResult(
ActivityResultContracts.StartIntentSenderForResult()
@@ -63,11 +66,14 @@
}
when (dialogType) {
DialogType.CREATE_PASSKEY -> {
- val viewModel: CreateCredentialViewModel = viewModel()
- viewModel.observeDialogResult().observe(
- this@CredentialSelectorActivity,
- onCancel
- )
+ val viewModel: CreateCredentialViewModel = viewModel{
+ CreateCredentialViewModel(credManRepo)
+ }
+ lifecycleScope.launch {
+ viewModel.observeDialogResult().collect{ dialogResult ->
+ onCancel(dialogResult)
+ }
+ }
providerActivityResult.value?.let {
viewModel.onProviderActivityResult(it)
providerActivityResult.value = null
@@ -75,11 +81,14 @@
CreateCredentialScreen(viewModel = viewModel, providerActivityLauncher = launcher)
}
DialogType.GET_CREDENTIALS -> {
- val viewModel: GetCredentialViewModel = viewModel()
- viewModel.observeDialogResult().observe(
- this@CredentialSelectorActivity,
- onCancel
- )
+ val viewModel: GetCredentialViewModel = viewModel{
+ GetCredentialViewModel(credManRepo)
+ }
+ lifecycleScope.launch {
+ viewModel.observeDialogResult().collect{ dialogResult ->
+ onCancel(dialogResult)
+ }
+ }
providerActivityResult.value?.let {
viewModel.onProviderActivityResult(it)
providerActivityResult.value = null
@@ -93,8 +102,12 @@
}
}
- private val onCancel = Observer<DialogResult> {
- if (it.resultState == ResultState.COMPLETE || it.resultState == ResultState.CANCELED) {
+ private fun onCancel(dialogResut: DialogResult) {
+ if (dialogResut.resultState == ResultState
+ .COMPLETE || dialogResut.resultState == ResultState.NORMAL_CANCELED) {
+ this@CredentialSelectorActivity.finish()
+ } else if (dialogResut.resultState == ResultState.LAUNCH_SETTING_CANCELED) {
+ this@CredentialSelectorActivity.startActivity(Intent(Settings.ACTION_SYNC_SETTINGS))
this@CredentialSelectorActivity.finish()
}
}
diff --git a/packages/CredentialManager/src/com/android/credentialmanager/DataConverter.kt b/packages/CredentialManager/src/com/android/credentialmanager/DataConverter.kt
index 217f8f9..09f9b5e 100644
--- a/packages/CredentialManager/src/com/android/credentialmanager/DataConverter.kt
+++ b/packages/CredentialManager/src/com/android/credentialmanager/DataConverter.kt
@@ -25,6 +25,7 @@
import android.credentials.ui.DisabledProviderData
import android.credentials.ui.RequestInfo
import android.graphics.drawable.Drawable
+import android.text.TextUtils
import com.android.credentialmanager.createflow.CreateOptionInfo
import com.android.credentialmanager.createflow.RemoteInfo
import com.android.credentialmanager.createflow.RequestDisplayInfo
@@ -43,6 +44,7 @@
import com.android.credentialmanager.jetpack.developer.CreatePublicKeyCredentialRequest
import com.android.credentialmanager.jetpack.developer.PublicKeyCredential.Companion.TYPE_PUBLIC_KEY_CREDENTIAL
import com.android.credentialmanager.jetpack.provider.Action
+import com.android.credentialmanager.jetpack.provider.AuthenticationAction
import com.android.credentialmanager.jetpack.provider.CredentialCountInformation
import com.android.credentialmanager.jetpack.provider.CredentialEntry
import com.android.credentialmanager.jetpack.provider.CreateEntry
@@ -58,7 +60,6 @@
): List<ProviderInfo> {
val packageManager = context.packageManager
return providerDataList.map {
- // TODO: get from the actual service info
val componentName = ComponentName.unflattenFromString(it.providerFlattenedComponentName)
var packageName = componentName?.packageName
if (componentName == null) {
@@ -70,8 +71,7 @@
.getPackageInfo(packageName!!,
PackageManager.PackageInfoFlags.of(0))
val providerDisplayName = pkgInfo.applicationInfo.loadLabel(packageManager).toString()
- // TODO: get the provider icon from the service
- // and decide what to do when failed to load a provider icon
+ // TODO: decide what to do when failed to load a provider icon
val providerIcon = pkgInfo.applicationInfo.loadIcon(packageManager)!!
ProviderInfo(
id = it.providerFlattenedComponentName,
@@ -94,9 +94,15 @@
fun toRequestDisplayInfo(
requestInfo: RequestInfo,
+ context: Context,
): com.android.credentialmanager.getflow.RequestDisplayInfo {
- return com.android.credentialmanager.getflow.RequestDisplayInfo(
- appDomainName = requestInfo.appPackageName
+ val packageName = requestInfo.appPackageName
+ val pkgInfo = context.packageManager.getPackageInfo(packageName,
+ PackageManager.PackageInfoFlags.of(0))
+ val appLabel = pkgInfo.applicationInfo.loadSafeLabel(context.packageManager, 0f,
+ TextUtils.SAFE_STRING_FLAG_FIRST_LINE or TextUtils.SAFE_STRING_FLAG_TRIM)
+ return com.android.credentialmanager.getflow.RequestDisplayInfo(
+ appName = appLabel.toString()
)
}
@@ -135,16 +141,20 @@
providerIcon: Drawable,
authEntry: Entry?,
): AuthenticationEntryInfo? {
- // TODO: should also call fromSlice after getting the official jetpack code.
-
if (authEntry == null) {
return null
}
+ val authStructuredEntry = AuthenticationAction.fromSlice(
+ authEntry!!.slice)
+ if (authStructuredEntry == null) {
+ return null
+ }
+
return AuthenticationEntryInfo(
providerId = providerId,
entryKey = authEntry.key,
entrySubkey = authEntry.subkey,
- pendingIntent = authEntry.pendingIntent,
+ pendingIntent = authStructuredEntry.pendingIntent,
fillInIntent = authEntry.frameworkExtrasIntent,
title = providerDisplayName,
icon = providerIcon,
@@ -237,7 +247,7 @@
packageName = it.providerFlattenedComponentName
}
val pkgInfo = packageManager
- .getPackageInfo(packageName,
+ .getPackageInfo(packageName!!,
PackageManager.PackageInfoFlags.of(0))
DisabledProviderInfo(
icon = pkgInfo.applicationInfo.loadIcon(packageManager)!!,
@@ -251,10 +261,15 @@
requestInfo: RequestInfo,
context: Context,
): RequestDisplayInfo {
+ val packageName = requestInfo.appPackageName
+ val pkgInfo = context.packageManager.getPackageInfo(packageName,
+ PackageManager.PackageInfoFlags.of(0))
+ val appLabel = pkgInfo.applicationInfo.loadSafeLabel(context.packageManager, 0f,
+ TextUtils.SAFE_STRING_FLAG_FIRST_LINE or TextUtils.SAFE_STRING_FLAG_TRIM)
val createCredentialRequest = requestInfo.createCredentialRequest
val createCredentialRequestJetpack = createCredentialRequest?.let {
CreateCredentialRequest.createFrom(
- it
+ it.type, it.credentialData, it.candidateQueryData, it.requireSystemProvider()
)
}
when (createCredentialRequestJetpack) {
@@ -263,7 +278,7 @@
createCredentialRequestJetpack.id,
createCredentialRequestJetpack.password,
createCredentialRequestJetpack.type,
- requestInfo.appPackageName,
+ appLabel.toString(),
context.getDrawable(R.drawable.ic_password)!!
)
}
@@ -281,7 +296,7 @@
name,
displayName,
createCredentialRequestJetpack.type,
- requestInfo.appPackageName,
+ appLabel.toString(),
context.getDrawable(R.drawable.ic_passkey)!!)
}
// TODO: correctly parsing for other sign-ins
@@ -290,7 +305,7 @@
"beckett-bakert@gmail.com",
"Elisa Beckett",
"other-sign-ins",
- requestInfo.appPackageName,
+ appLabel.toString(),
context.getDrawable(R.drawable.ic_other_sign_in)!!)
}
}
@@ -421,6 +436,7 @@
totalCredentialCount = CredentialCountInformation.getTotalCount(
createEntry.credentialCountInformationList) ?: 0,
lastUsedTimeMillis = createEntry.lastUsedTimeMillis ?: 0,
+ footerDescription = createEntry.footerDescription?.toString()
)
}
}
diff --git a/packages/CredentialManager/src/com/android/credentialmanager/common/DialogResult.kt b/packages/CredentialManager/src/com/android/credentialmanager/common/DialogResult.kt
index b751663..743f49b 100644
--- a/packages/CredentialManager/src/com/android/credentialmanager/common/DialogResult.kt
+++ b/packages/CredentialManager/src/com/android/credentialmanager/common/DialogResult.kt
@@ -18,7 +18,8 @@
enum class ResultState {
COMPLETE,
- CANCELED,
+ NORMAL_CANCELED,
+ LAUNCH_SETTING_CANCELED
}
data class DialogResult(
diff --git a/packages/CredentialManager/src/com/android/credentialmanager/createflow/CreateCredentialComponents.kt b/packages/CredentialManager/src/com/android/credentialmanager/createflow/CreateCredentialComponents.kt
index 46e1b60..498f0a1 100644
--- a/packages/CredentialManager/src/com/android/credentialmanager/createflow/CreateCredentialComponents.kt
+++ b/packages/CredentialManager/src/com/android/credentialmanager/createflow/CreateCredentialComponents.kt
@@ -78,8 +78,7 @@
disabledProviderList = uiState.disabledProviders,
sortedCreateOptionsPairs = uiState.sortedCreateOptionsPairs,
onOptionSelected = viewModel::onEntrySelectedFromFirstUseScreen,
- onDisabledPasswordManagerSelected =
- viewModel::onDisabledPasswordManagerSelected,
+ onDisabledProvidersSelected = viewModel::onDisabledProvidersSelected,
onMoreOptionsSelected = viewModel::onMoreOptionsSelectedOnProviderSelection,
)
CreateScreenState.CREATION_OPTION_SELECTION -> CreationSelectionCard(
@@ -103,8 +102,7 @@
onBackCreationSelectionButtonSelected =
viewModel::onBackCreationSelectionButtonSelected,
onOptionSelected = viewModel::onEntrySelectedFromMoreOptionScreen,
- onDisabledPasswordManagerSelected =
- viewModel::onDisabledPasswordManagerSelected,
+ onDisabledProvidersSelected = viewModel::onDisabledProvidersSelected,
onRemoteEntrySelected = viewModel::onEntrySelected,
)
CreateScreenState.MORE_OPTIONS_ROW_INTRO -> MoreOptionsRowIntroCard(
@@ -250,7 +248,7 @@
disabledProviderList: List<DisabledProviderInfo>?,
sortedCreateOptionsPairs: List<Pair<CreateOptionInfo, EnabledProviderInfo>>,
onOptionSelected: (ActiveEntry) -> Unit,
- onDisabledPasswordManagerSelected: () -> Unit,
+ onDisabledProvidersSelected: () -> Unit,
onMoreOptionsSelected: () -> Unit,
) {
ContainerCard() {
@@ -266,11 +264,12 @@
text = stringResource(
R.string.choose_provider_title,
when (requestDisplayInfo.type) {
- TYPE_PUBLIC_KEY_CREDENTIAL -> stringResource(R.string.create_your_passkeys)
- TYPE_PASSWORD_CREDENTIAL -> stringResource(R.string.save_your_password)
- else -> stringResource(R.string.save_your_sign_in_info)
- },
- ),
+ TYPE_PUBLIC_KEY_CREDENTIAL ->
+ stringResource(R.string.passkeys)
+ TYPE_PASSWORD_CREDENTIAL ->
+ stringResource(R.string.passwords)
+ else -> stringResource(R.string.sign_in_info)
+ }),
style = MaterialTheme.typography.titleMedium,
modifier = Modifier.padding(horizontal = 24.dp)
.align(alignment = Alignment.CenterHorizontally),
@@ -318,8 +317,8 @@
item {
MoreOptionsDisabledProvidersRow(
disabledProviders = disabledProviderList,
- onDisabledPasswordManagerSelected =
- onDisabledPasswordManagerSelected,
+ onDisabledProvidersSelected =
+ onDisabledProvidersSelected,
)
}
}
@@ -363,7 +362,7 @@
onBackProviderSelectionButtonSelected: () -> Unit,
onBackCreationSelectionButtonSelected: () -> Unit,
onOptionSelected: (ActiveEntry) -> Unit,
- onDisabledPasswordManagerSelected: () -> Unit,
+ onDisabledProvidersSelected: () -> Unit,
onRemoteEntrySelected: (EntryInfo) -> Unit,
) {
ContainerCard() {
@@ -436,8 +435,8 @@
item {
MoreOptionsDisabledProvidersRow(
disabledProviders = disabledProviderList,
- onDisabledPasswordManagerSelected =
- onDisabledPasswordManagerSelected,
+ onDisabledProvidersSelected =
+ onDisabledProvidersSelected,
)
}
}
@@ -550,15 +549,15 @@
text = when (requestDisplayInfo.type) {
TYPE_PUBLIC_KEY_CREDENTIAL -> stringResource(
R.string.choose_create_option_passkey_title,
- requestDisplayInfo.appDomainName
+ requestDisplayInfo.appName
)
TYPE_PASSWORD_CREDENTIAL -> stringResource(
R.string.choose_create_option_password_title,
- requestDisplayInfo.appDomainName
+ requestDisplayInfo.appName
)
else -> stringResource(
R.string.choose_create_option_sign_in_title,
- requestDisplayInfo.appDomainName
+ requestDisplayInfo.appName
)
},
style = MaterialTheme.typography.titleMedium,
@@ -606,27 +605,17 @@
onClick = onConfirm
)
}
- Divider(
- thickness = 1.dp,
- color = Color.LightGray,
- modifier = Modifier.padding(start = 24.dp, end = 24.dp, top = 18.dp)
- )
- if (createOptionInfo.userProviderDisplayName != null) {
+ if (createOptionInfo.footerDescription != null) {
+ Divider(
+ thickness = 1.dp,
+ color = Color.LightGray,
+ modifier = Modifier.padding(start = 24.dp, end = 24.dp, top = 18.dp)
+ )
TextSecondary(
- text = stringResource(
- R.string.choose_create_option_description,
- requestDisplayInfo.appDomainName,
- when (requestDisplayInfo.type) {
- TYPE_PUBLIC_KEY_CREDENTIAL -> stringResource(R.string.passkey)
- TYPE_PASSWORD_CREDENTIAL -> stringResource(R.string.password)
- else -> stringResource(R.string.sign_ins)
- },
- providerInfo.displayName,
- createOptionInfo.userProviderDisplayName
- ),
+ text = createOptionInfo.footerDescription,
style = MaterialTheme.typography.bodyLarge,
modifier = Modifier.padding(
- start = 24.dp, top = 8.dp, bottom = 18.dp, end = 24.dp)
+ start = 29.dp, top = 8.dp, bottom = 18.dp, end = 28.dp)
)
}
Divider(
@@ -891,11 +880,11 @@
@Composable
fun MoreOptionsDisabledProvidersRow(
disabledProviders: List<ProviderInfo>?,
- onDisabledPasswordManagerSelected: () -> Unit,
+ onDisabledProvidersSelected: () -> Unit,
) {
if (disabledProviders != null && disabledProviders.isNotEmpty()) {
Entry(
- onClick = onDisabledPasswordManagerSelected,
+ onClick = onDisabledProvidersSelected,
icon = {
Icon(
Icons.Filled.Add,
diff --git a/packages/CredentialManager/src/com/android/credentialmanager/createflow/CreateCredentialViewModel.kt b/packages/CredentialManager/src/com/android/credentialmanager/createflow/CreateCredentialViewModel.kt
index 55e14a9..ac84503 100644
--- a/packages/CredentialManager/src/com/android/credentialmanager/createflow/CreateCredentialViewModel.kt
+++ b/packages/CredentialManager/src/com/android/credentialmanager/createflow/CreateCredentialViewModel.kt
@@ -24,8 +24,6 @@
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.setValue
-import androidx.lifecycle.LiveData
-import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.ViewModel
import com.android.credentialmanager.CreateFlowUtils
import com.android.credentialmanager.CredentialManagerRepo
@@ -33,6 +31,9 @@
import com.android.credentialmanager.common.DialogResult
import com.android.credentialmanager.common.ProviderActivityResult
import com.android.credentialmanager.common.ResultState
+import kotlinx.coroutines.channels.BufferOverflow
+import kotlinx.coroutines.flow.MutableSharedFlow
+import kotlinx.coroutines.flow.SharedFlow
data class CreateCredentialUiState(
val enabledProviders: List<EnabledProviderInfo>,
@@ -51,10 +52,9 @@
)
class CreateCredentialViewModel(
- credManRepo: CredentialManagerRepo = CredentialManagerRepo.getInstance(),
- userConfigRepo: UserConfigRepo = UserConfigRepo.getInstance()
+ private val credManRepo: CredentialManagerRepo,
+ userConfigRepo: UserConfigRepo = UserConfigRepo.getInstance(),
) : ViewModel() {
-
var providerEnableListUiState = credManRepo.getCreateProviderEnableListInitialUiState()
var providerDisableListUiState = credManRepo.getCreateProviderDisableListInitialUiState()
@@ -75,11 +75,11 @@
isPasskeyFirstUse))
private set
- val dialogResult: MutableLiveData<DialogResult> by lazy {
- MutableLiveData<DialogResult>()
- }
+ val dialogResult: MutableSharedFlow<DialogResult> =
+ MutableSharedFlow(replay = 0, extraBufferCapacity = 1,
+ onBufferOverflow = BufferOverflow.DROP_OLDEST)
- fun observeDialogResult(): LiveData<DialogResult> {
+ fun observeDialogResult(): SharedFlow<DialogResult> {
return dialogResult
}
@@ -124,7 +124,9 @@
fun onEntrySelectedFromMoreOptionScreen(activeEntry: ActiveEntry) {
uiState = uiState.copy(
- currentScreenState = CreateScreenState.MORE_OPTIONS_ROW_INTRO,
+ currentScreenState = if (
+ activeEntry.activeProvider.id == UserConfigRepo.getInstance().getDefaultProviderId()
+ ) CreateScreenState.CREATION_OPTION_SELECTION else CreateScreenState.MORE_OPTIONS_ROW_INTRO,
activeEntry = activeEntry
)
}
@@ -138,13 +140,14 @@
onDefaultChanged(providerId)
}
- fun onDisabledPasswordManagerSelected() {
- // TODO: Complete this function
+ fun onDisabledProvidersSelected() {
+ credManRepo.onCancel()
+ dialogResult.tryEmit(DialogResult(ResultState.LAUNCH_SETTING_CANCELED))
}
fun onCancel() {
- CredentialManagerRepo.getInstance().onCancel()
- dialogResult.value = DialogResult(ResultState.CANCELED)
+ credManRepo.onCancel()
+ dialogResult.tryEmit(DialogResult(ResultState.NORMAL_CANCELED))
}
fun onChangeDefaultSelected() {
@@ -185,14 +188,12 @@
hidden = true,
)
} else {
- CredentialManagerRepo.getInstance().onOptionSelected(
+ credManRepo.onOptionSelected(
providerId,
entryKey,
entrySubkey
)
- dialogResult.value = DialogResult(
- ResultState.COMPLETE,
- )
+ dialogResult.tryEmit(DialogResult(ResultState.COMPLETE))
}
}
@@ -219,9 +220,7 @@
} else {
Log.w("Account Selector",
"Illegal state: confirm is pressed but activeEntry isn't set.")
- dialogResult.value = DialogResult(
- ResultState.COMPLETE,
- )
+ dialogResult.tryEmit(DialogResult(ResultState.COMPLETE))
}
}
@@ -243,16 +242,14 @@
"$providerId, key=${entry.entryKey}, subkey=${entry.entrySubkey}, " +
"resultCode=$resultCode, resultData=$resultData}"
)
- CredentialManagerRepo.getInstance().onOptionSelected(
+ credManRepo.onOptionSelected(
providerId, entry.entryKey, entry.entrySubkey, resultCode, resultData,
)
} else {
Log.w("Account Selector",
"Illegal state: received a provider result but found no matching entry.")
}
- dialogResult.value = DialogResult(
- ResultState.COMPLETE,
- )
+ dialogResult.tryEmit(DialogResult(ResultState.COMPLETE))
}
}
}
diff --git a/packages/CredentialManager/src/com/android/credentialmanager/createflow/CreateModel.kt b/packages/CredentialManager/src/com/android/credentialmanager/createflow/CreateModel.kt
index 1035c46..97477a7 100644
--- a/packages/CredentialManager/src/com/android/credentialmanager/createflow/CreateModel.kt
+++ b/packages/CredentialManager/src/com/android/credentialmanager/createflow/CreateModel.kt
@@ -60,6 +60,7 @@
val passkeyCount: Int?,
val totalCredentialCount: Int?,
val lastUsedTimeMillis: Long?,
+ val footerDescription: String?,
) : EntryInfo(providerId, entryKey, entrySubkey, pendingIntent, fillInIntent)
class RemoteInfo(
@@ -74,7 +75,7 @@
val title: String,
val subtitle: String?,
val type: String,
- val appDomainName: String,
+ val appName: String,
val typeIcon: Drawable,
)
diff --git a/packages/CredentialManager/src/com/android/credentialmanager/getflow/GetCredentialComponents.kt b/packages/CredentialManager/src/com/android/credentialmanager/getflow/GetCredentialComponents.kt
index ac0db5a..03f39e1 100644
--- a/packages/CredentialManager/src/com/android/credentialmanager/getflow/GetCredentialComponents.kt
+++ b/packages/CredentialManager/src/com/android/credentialmanager/getflow/GetCredentialComponents.kt
@@ -160,7 +160,7 @@
) {
R.string.get_dialog_title_use_sign_in_for
} else R.string.get_dialog_title_choose_sign_in_for,
- requestDisplayInfo.appDomainName
+ requestDisplayInfo.appName
),
)
diff --git a/packages/CredentialManager/src/com/android/credentialmanager/getflow/GetCredentialViewModel.kt b/packages/CredentialManager/src/com/android/credentialmanager/getflow/GetCredentialViewModel.kt
index 294e468..6f0f76b 100644
--- a/packages/CredentialManager/src/com/android/credentialmanager/getflow/GetCredentialViewModel.kt
+++ b/packages/CredentialManager/src/com/android/credentialmanager/getflow/GetCredentialViewModel.kt
@@ -24,8 +24,6 @@
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.setValue
-import androidx.lifecycle.LiveData
-import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.ViewModel
import com.android.credentialmanager.CredentialManagerRepo
import com.android.credentialmanager.common.DialogResult
@@ -33,6 +31,9 @@
import com.android.credentialmanager.common.ResultState
import com.android.credentialmanager.jetpack.developer.PublicKeyCredential
import com.android.internal.util.Preconditions
+import kotlinx.coroutines.channels.BufferOverflow
+import kotlinx.coroutines.flow.MutableSharedFlow
+import kotlinx.coroutines.flow.SharedFlow
data class GetCredentialUiState(
val providerInfoList: List<ProviderInfo>,
@@ -45,18 +46,16 @@
val isNoAccount: Boolean = false,
)
-class GetCredentialViewModel(
- credManRepo: CredentialManagerRepo = CredentialManagerRepo.getInstance()
-) : ViewModel() {
+class GetCredentialViewModel(private val credManRepo: CredentialManagerRepo) : ViewModel() {
var uiState by mutableStateOf(credManRepo.getCredentialInitialUiState())
private set
- val dialogResult: MutableLiveData<DialogResult> by lazy {
- MutableLiveData<DialogResult>()
- }
+ val dialogResult: MutableSharedFlow<DialogResult> =
+ MutableSharedFlow(replay = 0, extraBufferCapacity = 1,
+ onBufferOverflow = BufferOverflow.DROP_OLDEST)
- fun observeDialogResult(): LiveData<DialogResult> {
+ fun observeDialogResult(): SharedFlow<DialogResult> {
return dialogResult
}
@@ -69,10 +68,8 @@
hidden = true,
)
} else {
- CredentialManagerRepo.getInstance().onOptionSelected(
- entry.providerId, entry.entryKey, entry.entrySubkey,
- )
- dialogResult.value = DialogResult(ResultState.COMPLETE)
+ credManRepo.onOptionSelected(entry.providerId, entry.entryKey, entry.entrySubkey)
+ dialogResult.tryEmit(DialogResult(ResultState.COMPLETE))
}
}
@@ -109,7 +106,7 @@
"${entry.providerId}, key=${entry.entryKey}, subkey=${entry.entrySubkey}, " +
"resultCode=$resultCode, resultData=$resultData}"
)
- CredentialManagerRepo.getInstance().onOptionSelected(
+ credManRepo.onOptionSelected(
entry.providerId, entry.entryKey, entry.entrySubkey,
resultCode, resultData,
)
@@ -117,7 +114,7 @@
Log.w("Account Selector",
"Illegal state: received a provider result but found no matching entry.")
}
- dialogResult.value = DialogResult(ResultState.COMPLETE)
+ dialogResult.tryEmit(DialogResult(ResultState.COMPLETE))
}
}
@@ -143,8 +140,8 @@
}
fun onCancel() {
- CredentialManagerRepo.getInstance().onCancel()
- dialogResult.value = DialogResult(ResultState.CANCELED)
+ credManRepo.onCancel()
+ dialogResult.tryEmit(DialogResult(ResultState.NORMAL_CANCELED))
}
}
diff --git a/packages/CredentialManager/src/com/android/credentialmanager/getflow/GetModel.kt b/packages/CredentialManager/src/com/android/credentialmanager/getflow/GetModel.kt
index 60939b5..8ce31bd 100644
--- a/packages/CredentialManager/src/com/android/credentialmanager/getflow/GetModel.kt
+++ b/packages/CredentialManager/src/com/android/credentialmanager/getflow/GetModel.kt
@@ -101,7 +101,7 @@
) : EntryInfo(providerId, entryKey, entrySubkey, pendingIntent, fillInIntent)
data class RequestDisplayInfo(
- val appDomainName: String,
+ val appName: String,
)
/**
diff --git a/packages/CredentialManager/src/com/android/credentialmanager/jetpack/developer/CreateCredentialRequest.kt b/packages/CredentialManager/src/com/android/credentialmanager/jetpack/developer/CreateCredentialRequest.kt
index 008e1b6..eaa2ad4 100644
--- a/packages/CredentialManager/src/com/android/credentialmanager/jetpack/developer/CreateCredentialRequest.kt
+++ b/packages/CredentialManager/src/com/android/credentialmanager/jetpack/developer/CreateCredentialRequest.kt
@@ -18,6 +18,7 @@
import android.credentials.Credential
import android.os.Bundle
+import com.android.credentialmanager.jetpack.developer.PublicKeyCredential.Companion.BUNDLE_KEY_SUBTYPE
/**
* Base request class for registering a credential.
@@ -28,27 +29,44 @@
* otherwise
*/
open class CreateCredentialRequest(
- val type: String,
- val data: Bundle,
- val requireSystemProvider: Boolean,
+ open val type: String,
+ open val credentialData: Bundle,
+ open val candidateQueryData: Bundle,
+ open val requireSystemProvider: Boolean
) {
companion object {
@JvmStatic
- fun createFrom(from: android.credentials.CreateCredentialRequest): CreateCredentialRequest {
+ fun createFrom(
+ type: String,
+ credentialData: Bundle,
+ candidateQueryData: Bundle,
+ requireSystemProvider: Boolean
+ ): CreateCredentialRequest {
return try {
- when (from.type) {
+ when (type) {
Credential.TYPE_PASSWORD_CREDENTIAL ->
- CreatePasswordRequest.createFrom(from.credentialData)
+ CreatePasswordRequest.createFrom(credentialData)
PublicKeyCredential.TYPE_PUBLIC_KEY_CREDENTIAL ->
- CreatePublicKeyCredentialBaseRequest.createFrom(from.credentialData)
- else ->
- CreateCredentialRequest(
- from.type, from.credentialData, from.requireSystemProvider()
- )
+ when (credentialData.getString(BUNDLE_KEY_SUBTYPE)) {
+ CreatePublicKeyCredentialRequest
+ .BUNDLE_VALUE_SUBTYPE_CREATE_PUBLIC_KEY_CREDENTIAL_REQUEST ->
+ CreatePublicKeyCredentialRequest.createFrom(credentialData)
+ CreatePublicKeyCredentialRequestPrivileged
+ .BUNDLE_VALUE_SUBTYPE_CREATE_PUBLIC_KEY_CREDENTIAL_REQUEST_PRIV ->
+ CreatePublicKeyCredentialRequestPrivileged
+ .createFrom(credentialData)
+ else -> throw FrameworkClassParsingException()
+ }
+ else -> throw FrameworkClassParsingException()
}
} catch (e: FrameworkClassParsingException) {
- CreateCredentialRequest(
- from.type, from.credentialData, from.requireSystemProvider()
+ // Parsing failed but don't crash the process. Instead just output a request with
+ // the raw framework values.
+ CreateCustomCredentialRequest(
+ type,
+ credentialData,
+ candidateQueryData,
+ requireSystemProvider
)
}
}
diff --git a/packages/CredentialManager/src/com/android/credentialmanager/jetpack/developer/CreateCustomCredentialRequest.kt b/packages/CredentialManager/src/com/android/credentialmanager/jetpack/developer/CreateCustomCredentialRequest.kt
new file mode 100644
index 0000000..50da9a1
--- /dev/null
+++ b/packages/CredentialManager/src/com/android/credentialmanager/jetpack/developer/CreateCustomCredentialRequest.kt
@@ -0,0 +1,50 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.credentialmanager.jetpack.developer
+
+import android.os.Bundle
+
+/**
+ * Base custom create request class for registering a credential.
+ *
+ * An application can construct a subtype custom request and call
+ * [CredentialManager.executeCreateCredential] to launch framework UI flows to collect consent and
+ * any other metadata needed from the user to register a new user credential.
+ *
+ * @property type the credential type determined by the credential-type-specific subclass for custom
+ * use cases
+ * @property credentialData the full credential creation request data in the [Bundle] format for
+ * custom use cases
+ * @property candidateQueryData the partial request data in the [Bundle] format that will be sent to
+ * the provider during the initial candidate query stage, which should not contain sensitive user
+ * credential information
+ * @property requireSystemProvider true if must only be fulfilled by a system provider and false
+ * otherwise
+ * @throws IllegalArgumentException If [type] is empty
+ * @throws NullPointerException If [type] or [credentialData] are null
+ */
+open class CreateCustomCredentialRequest(
+ final override val type: String,
+ final override val credentialData: Bundle,
+ final override val candidateQueryData: Bundle,
+ @get:JvmName("requireSystemProvider")
+ final override val requireSystemProvider: Boolean
+) : CreateCredentialRequest(type, credentialData, candidateQueryData, requireSystemProvider) {
+ init {
+ require(type.isNotEmpty()) { "type should not be empty" }
+ }
+}
\ No newline at end of file
diff --git a/packages/CredentialManager/src/com/android/credentialmanager/jetpack/developer/CreatePasswordRequest.kt b/packages/CredentialManager/src/com/android/credentialmanager/jetpack/developer/CreatePasswordRequest.kt
index f0da9f9..bf0aa8a 100644
--- a/packages/CredentialManager/src/com/android/credentialmanager/jetpack/developer/CreatePasswordRequest.kt
+++ b/packages/CredentialManager/src/com/android/credentialmanager/jetpack/developer/CreatePasswordRequest.kt
@@ -32,9 +32,11 @@
val id: String,
val password: String,
) : CreateCredentialRequest(
- Credential.TYPE_PASSWORD_CREDENTIAL,
- toBundle(id, password),
- false,
+ type = Credential.TYPE_PASSWORD_CREDENTIAL,
+ credentialData = toCredentialDataBundle(id, password),
+ // No credential data should be sent during the query phase.
+ candidateQueryData = Bundle(),
+ requireSystemProvider = false,
) {
init {
@@ -46,7 +48,7 @@
const val BUNDLE_KEY_PASSWORD = "androidx.credentials.BUNDLE_KEY_PASSWORD"
@JvmStatic
- internal fun toBundle(id: String, password: String): Bundle {
+ internal fun toCredentialDataBundle(id: String, password: String): Bundle {
val bundle = Bundle()
bundle.putString(BUNDLE_KEY_ID, id)
bundle.putString(BUNDLE_KEY_PASSWORD, password)
@@ -54,7 +56,14 @@
}
@JvmStatic
- fun createFrom(data: Bundle): CreatePasswordRequest {
+ internal fun toCandidateDataBundle(id: String): Bundle {
+ val bundle = Bundle()
+ bundle.putString(BUNDLE_KEY_ID, id)
+ return bundle
+ }
+
+ @JvmStatic
+ internal fun createFrom(data: Bundle): CreatePasswordRequest {
try {
val id = data.getString(BUNDLE_KEY_ID)
val password = data.getString(BUNDLE_KEY_PASSWORD)
diff --git a/packages/CredentialManager/src/com/android/credentialmanager/jetpack/developer/CreatePublicKeyCredentialBaseRequest.kt b/packages/CredentialManager/src/com/android/credentialmanager/jetpack/developer/CreatePublicKeyCredentialBaseRequest.kt
deleted file mode 100644
index 37a4f76..0000000
--- a/packages/CredentialManager/src/com/android/credentialmanager/jetpack/developer/CreatePublicKeyCredentialBaseRequest.kt
+++ /dev/null
@@ -1,58 +0,0 @@
-/*
- * 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 com.android.credentialmanager.jetpack.developer
-
-import android.os.Bundle
-
-/**
- * Base request class for registering a public key credential.
- *
- * @property requestJson The request in JSON format
- * @throws NullPointerException If [requestJson] is null. This is handled by the Kotlin runtime
- * @throws IllegalArgumentException If [requestJson] is empty
- *
- * @hide
- */
-abstract class CreatePublicKeyCredentialBaseRequest constructor(
- val requestJson: String,
- type: String,
- data: Bundle,
- requireSystemProvider: Boolean,
-) : CreateCredentialRequest(type, data, requireSystemProvider) {
-
- init {
- require(requestJson.isNotEmpty()) { "request json must not be empty" }
- }
-
- companion object {
- const val BUNDLE_KEY_REQUEST_JSON = "androidx.credentials.BUNDLE_KEY_REQUEST_JSON"
- const val BUNDLE_KEY_SUBTYPE = "androidx.credentials.BUNDLE_KEY_SUBTYPE"
-
- @JvmStatic
- fun createFrom(data: Bundle): CreatePublicKeyCredentialBaseRequest {
- return when (data.getString(BUNDLE_KEY_SUBTYPE)) {
- CreatePublicKeyCredentialRequest
- .BUNDLE_VALUE_SUBTYPE_CREATE_PUBLIC_KEY_CREDENTIAL_REQUEST ->
- CreatePublicKeyCredentialRequest.createFrom(data)
- CreatePublicKeyCredentialRequestPrivileged
- .BUNDLE_VALUE_SUBTYPE_CREATE_PUBLIC_KEY_CREDENTIAL_REQUEST_PRIVILEGED ->
- CreatePublicKeyCredentialRequestPrivileged.createFrom(data)
- else -> throw FrameworkClassParsingException()
- }
- }
- }
-}
diff --git a/packages/CredentialManager/src/com/android/credentialmanager/jetpack/developer/CreatePublicKeyCredentialRequest.kt b/packages/CredentialManager/src/com/android/credentialmanager/jetpack/developer/CreatePublicKeyCredentialRequest.kt
index 2eda90b..f3d402a 100644
--- a/packages/CredentialManager/src/com/android/credentialmanager/jetpack/developer/CreatePublicKeyCredentialRequest.kt
+++ b/packages/CredentialManager/src/com/android/credentialmanager/jetpack/developer/CreatePublicKeyCredentialRequest.kt
@@ -17,50 +17,81 @@
package com.android.credentialmanager.jetpack.developer
import android.os.Bundle
+import com.android.credentialmanager.jetpack.developer.PublicKeyCredential.Companion.BUNDLE_KEY_SUBTYPE
/**
- * A request to register a passkey from the user's public key credential provider.
- *
- * @property requestJson the request in JSON format
- * @property allowHybrid defines whether hybrid credentials are allowed to fulfill this request,
- * true by default
- * @throws NullPointerException If [requestJson] or [allowHybrid] is null. This is handled by the
- * Kotlin runtime
- * @throws IllegalArgumentException If [requestJson] is empty
- *
- * @hide
- */
+* A request to register a passkey 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).
+* @property preferImmediatelyAvailableCredentials true if you prefer the operation to return
+* immediately when there is no available passkey registration offering instead of falling back to
+* discovering remote options, and false (default) otherwise
+* @throws NullPointerException If [requestJson] is null
+* @throws IllegalArgumentException If [requestJson] is empty
+*/
class CreatePublicKeyCredentialRequest @JvmOverloads constructor(
- requestJson: String,
- @get:JvmName("allowHybrid")
- val allowHybrid: Boolean = true
-) : CreatePublicKeyCredentialBaseRequest(
- requestJson,
- PublicKeyCredential.TYPE_PUBLIC_KEY_CREDENTIAL,
- toBundle(requestJson, allowHybrid),
- false,
+ val requestJson: String,
+ @get:JvmName("preferImmediatelyAvailableCredentials")
+ val preferImmediatelyAvailableCredentials: Boolean = false
+) : CreateCredentialRequest(
+ type = PublicKeyCredential.TYPE_PUBLIC_KEY_CREDENTIAL,
+ credentialData = toCredentialDataBundle(requestJson, preferImmediatelyAvailableCredentials),
+ // The whole request data should be passed during the query phase.
+ candidateQueryData = toCredentialDataBundle(requestJson, preferImmediatelyAvailableCredentials),
+ requireSystemProvider = false,
) {
+
+ init {
+ require(requestJson.isNotEmpty()) { "requestJson must not be empty" }
+ }
+
+ /** @hide */
companion object {
- const val BUNDLE_KEY_ALLOW_HYBRID = "androidx.credentials.BUNDLE_KEY_ALLOW_HYBRID"
- const val BUNDLE_VALUE_SUBTYPE_CREATE_PUBLIC_KEY_CREDENTIAL_REQUEST =
- "androidx.credentials.BUNDLE_VALUE_SUBTYPE_CREATE_PUBLIC_KEY_CREDENTIAL_REQUEST"
+ const val BUNDLE_KEY_PREFER_IMMEDIATELY_AVAILABLE_CREDENTIALS =
+ "androidx.credentials.BUNDLE_KEY_PREFER_IMMEDIATELY_AVAILABLE_CREDENTIALS"
+ internal const val BUNDLE_KEY_REQUEST_JSON = "androidx.credentials.BUNDLE_KEY_REQUEST_JSON"
+ internal const val BUNDLE_VALUE_SUBTYPE_CREATE_PUBLIC_KEY_CREDENTIAL_REQUEST =
+ "androidx.credentials.BUNDLE_VALUE_SUBTYPE_CREATE_PUBLIC_KEY_CREDENTIAL_REQUEST"
@JvmStatic
- internal fun toBundle(requestJson: String, allowHybrid: Boolean): Bundle {
+ internal fun toCredentialDataBundle(
+ requestJson: String,
+ preferImmediatelyAvailableCredentials: Boolean
+ ): Bundle {
val bundle = Bundle()
bundle.putString(BUNDLE_KEY_SUBTYPE,
- BUNDLE_VALUE_SUBTYPE_CREATE_PUBLIC_KEY_CREDENTIAL_REQUEST)
+ BUNDLE_VALUE_SUBTYPE_CREATE_PUBLIC_KEY_CREDENTIAL_REQUEST)
bundle.putString(BUNDLE_KEY_REQUEST_JSON, requestJson)
- bundle.putBoolean(BUNDLE_KEY_ALLOW_HYBRID, allowHybrid)
+ bundle.putBoolean(BUNDLE_KEY_PREFER_IMMEDIATELY_AVAILABLE_CREDENTIALS,
+ preferImmediatelyAvailableCredentials)
return bundle
}
@JvmStatic
- fun createFrom(data: Bundle): CreatePublicKeyCredentialRequest {
+ internal fun toCandidateDataBundle(
+ requestJson: String,
+ preferImmediatelyAvailableCredentials: Boolean
+ ): Bundle {
+ val bundle = Bundle()
+ bundle.putString(BUNDLE_KEY_SUBTYPE,
+ BUNDLE_VALUE_SUBTYPE_CREATE_PUBLIC_KEY_CREDENTIAL_REQUEST)
+ bundle.putString(BUNDLE_KEY_REQUEST_JSON, requestJson)
+ bundle.putBoolean(BUNDLE_KEY_PREFER_IMMEDIATELY_AVAILABLE_CREDENTIALS,
+ preferImmediatelyAvailableCredentials)
+ return bundle
+ }
+
+ @Suppress("deprecation") // bundle.get() used for boolean value to prevent default
+ // boolean value from being returned.
+ @JvmStatic
+ internal fun createFrom(data: Bundle): CreatePublicKeyCredentialRequest {
try {
val requestJson = data.getString(BUNDLE_KEY_REQUEST_JSON)
- val allowHybrid = data.get(BUNDLE_KEY_ALLOW_HYBRID)
- return CreatePublicKeyCredentialRequest(requestJson!!, (allowHybrid!!) as Boolean)
+ val preferImmediatelyAvailableCredentials =
+ data.get(BUNDLE_KEY_PREFER_IMMEDIATELY_AVAILABLE_CREDENTIALS)
+ return CreatePublicKeyCredentialRequest(requestJson!!,
+ (preferImmediatelyAvailableCredentials!!) as Boolean)
} catch (e: Exception) {
throw FrameworkClassParsingException()
}
diff --git a/packages/CredentialManager/src/com/android/credentialmanager/jetpack/developer/CreatePublicKeyCredentialRequestPrivileged.kt b/packages/CredentialManager/src/com/android/credentialmanager/jetpack/developer/CreatePublicKeyCredentialRequestPrivileged.kt
index 36324f8..85ab2d2 100644
--- a/packages/CredentialManager/src/com/android/credentialmanager/jetpack/developer/CreatePublicKeyCredentialRequestPrivileged.kt
+++ b/packages/CredentialManager/src/com/android/credentialmanager/jetpack/developer/CreatePublicKeyCredentialRequestPrivileged.kt
@@ -17,45 +17,62 @@
package com.android.credentialmanager.jetpack.developer
import android.os.Bundle
+import com.android.credentialmanager.jetpack.developer.PublicKeyCredential.Companion.BUNDLE_KEY_SUBTYPE
/**
* A privileged request to register a passkey from the user’s public key credential provider, where
* the caller can modify the rp. Only callers with privileged permission, e.g. user’s default
- * brower, caBLE, can use this.
+ * brower, 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
- * @property allowHybrid defines whether hybrid credentials are allowed to fulfill this request,
- * true by default
- * @property rp the expected true RP ID which will override the one in the [requestJson]
- * @property clientDataHash a hash that is used to verify the [rp] Identity
- * @throws NullPointerException If any of [allowHybrid], [requestJson], [rp], or [clientDataHash] is
- * null. This is handled by the Kotlin runtime
- * @throws IllegalArgumentException If any of [requestJson], [rp], or [clientDataHash] is empty
- *
- * @hide
+ * @property requestJson the privileged request in JSON format in the standard webauthn web json
+ * shown [here](https://w3c.github.io/webauthn/#dictdef-publickeycredentialrequestoptionsjson).
+ * @property preferImmediatelyAvailableCredentials true if you prefer the operation to return
+ * immediately when there is no available passkey registration offering instead of falling back to
+ * discovering remote options, and false (default) otherwise
+ * @property relyingParty the expected true RP ID which will override the one in the [requestJson],
+ * where rp is defined [here](https://w3c.github.io/webauthn/#rp-id)
+ * @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
*/
class CreatePublicKeyCredentialRequestPrivileged @JvmOverloads constructor(
- requestJson: String,
- val rp: String,
- val clientDataHash: String,
- @get:JvmName("allowHybrid")
- val allowHybrid: Boolean = true
-) : CreatePublicKeyCredentialBaseRequest(
+ val requestJson: String,
+ val relyingParty: String,
+ val clientDataHash: String,
+ @get:JvmName("preferImmediatelyAvailableCredentials")
+ val preferImmediatelyAvailableCredentials: Boolean = false
+) : CreateCredentialRequest(
+ type = PublicKeyCredential.TYPE_PUBLIC_KEY_CREDENTIAL,
+ credentialData = toCredentialDataBundle(
requestJson,
- PublicKeyCredential.TYPE_PUBLIC_KEY_CREDENTIAL,
- toBundle(requestJson, rp, clientDataHash, allowHybrid),
- false,
+ relyingParty,
+ clientDataHash,
+ preferImmediatelyAvailableCredentials
+ ),
+ // The whole request data should be passed during the query phase.
+ candidateQueryData = toCredentialDataBundle(
+ requestJson, relyingParty, clientDataHash, preferImmediatelyAvailableCredentials
+ ),
+ requireSystemProvider = false,
) {
init {
- require(rp.isNotEmpty()) { "rp must not be empty" }
+ require(requestJson.isNotEmpty()) { "requestJson must not be empty" }
+ require(relyingParty.isNotEmpty()) { "rp must not be empty" }
require(clientDataHash.isNotEmpty()) { "clientDataHash must not be empty" }
}
/** A builder for [CreatePublicKeyCredentialRequestPrivileged]. */
- class Builder(var requestJson: String, var rp: String, var clientDataHash: String) {
+ class Builder(
+ private var requestJson: String,
+ private var relyingParty: String,
+ private var clientDataHash: String
+ ) {
- private var allowHybrid: Boolean = true
+ private var preferImmediatelyAvailableCredentials: Boolean = false
/**
* Sets the privileged request in JSON format.
@@ -66,23 +83,30 @@
}
/**
- * Sets whether hybrid credentials are allowed to fulfill this request, true by default.
+ * Sets to true if you prefer the operation to return immediately when there is no available
+ * passkey registration offering instead of falling back to discovering remote options, and
+ * false otherwise.
+ *
+ * The default value is false.
*/
- fun setAllowHybrid(allowHybrid: Boolean): Builder {
- this.allowHybrid = allowHybrid
+ @Suppress("MissingGetterMatchingBuilder")
+ fun setPreferImmediatelyAvailableCredentials(
+ preferImmediatelyAvailableCredentials: Boolean
+ ): Builder {
+ this.preferImmediatelyAvailableCredentials = preferImmediatelyAvailableCredentials
return this
}
/**
* Sets the expected true RP ID which will override the one in the [requestJson].
*/
- fun setRp(rp: String): Builder {
- this.rp = rp
+ fun setRelyingParty(relyingParty: String): Builder {
+ this.relyingParty = relyingParty
return this
}
/**
- * Sets a hash that is used to verify the [rp] Identity.
+ * Sets a hash that is used to verify the [relyingParty] Identity.
*/
fun setClientDataHash(clientDataHash: String): Builder {
this.clientDataHash = clientDataHash
@@ -91,49 +115,65 @@
/** Builds a [CreatePublicKeyCredentialRequestPrivileged]. */
fun build(): CreatePublicKeyCredentialRequestPrivileged {
- return CreatePublicKeyCredentialRequestPrivileged(this.requestJson,
- this.rp, this.clientDataHash, this.allowHybrid)
+ return CreatePublicKeyCredentialRequestPrivileged(
+ this.requestJson,
+ this.relyingParty, this.clientDataHash, this.preferImmediatelyAvailableCredentials
+ )
}
}
+ /** @hide */
companion object {
- const val BUNDLE_KEY_RP = "androidx.credentials.BUNDLE_KEY_RP"
- const val BUNDLE_KEY_CLIENT_DATA_HASH =
- "androidx.credentials.BUNDLE_KEY_CLIENT_DATA_HASH"
- const val BUNDLE_KEY_ALLOW_HYBRID = "androidx.credentials.BUNDLE_KEY_ALLOW_HYBRID"
- const val BUNDLE_VALUE_SUBTYPE_CREATE_PUBLIC_KEY_CREDENTIAL_REQUEST_PRIVILEGED =
- "androidx.credentials.BUNDLE_VALUE_SUBTYPE_CREATE_PUBLIC_KEY_CREDENTIAL_REQUEST_" +
- "PRIVILEGED"
+ internal const val BUNDLE_KEY_RELYING_PARTY =
+ "androidx.credentials.BUNDLE_KEY_RELYING_PARTY"
+ internal const val BUNDLE_KEY_CLIENT_DATA_HASH =
+ "androidx.credentials.BUNDLE_KEY_CLIENT_DATA_HASH"
+ internal const val BUNDLE_KEY_PREFER_IMMEDIATELY_AVAILABLE_CREDENTIALS =
+ "androidx.credentials.BUNDLE_KEY_PREFER_IMMEDIATELY_AVAILABLE_CREDENTIALS"
+
+ internal const val BUNDLE_KEY_REQUEST_JSON = "androidx.credentials.BUNDLE_KEY_REQUEST_JSON"
+
+ internal const val BUNDLE_VALUE_SUBTYPE_CREATE_PUBLIC_KEY_CREDENTIAL_REQUEST_PRIV =
+ "androidx.credentials.BUNDLE_VALUE_SUBTYPE_CREATE_PUBLIC_KEY_CREDENTIAL_REQUEST_" +
+ "PRIVILEGED"
@JvmStatic
- internal fun toBundle(
- requestJson: String,
- rp: String,
- clientDataHash: String,
- allowHybrid: Boolean
+ internal fun toCredentialDataBundle(
+ requestJson: String,
+ relyingParty: String,
+ clientDataHash: String,
+ preferImmediatelyAvailableCredentials: Boolean
): Bundle {
val bundle = Bundle()
- bundle.putString(BUNDLE_KEY_SUBTYPE,
- BUNDLE_VALUE_SUBTYPE_CREATE_PUBLIC_KEY_CREDENTIAL_REQUEST_PRIVILEGED)
+ bundle.putString(
+ PublicKeyCredential.BUNDLE_KEY_SUBTYPE,
+ BUNDLE_VALUE_SUBTYPE_CREATE_PUBLIC_KEY_CREDENTIAL_REQUEST_PRIV
+ )
bundle.putString(BUNDLE_KEY_REQUEST_JSON, requestJson)
- bundle.putString(BUNDLE_KEY_RP, rp)
+ bundle.putString(BUNDLE_KEY_RELYING_PARTY, relyingParty)
bundle.putString(BUNDLE_KEY_CLIENT_DATA_HASH, clientDataHash)
- bundle.putBoolean(BUNDLE_KEY_ALLOW_HYBRID, allowHybrid)
+ bundle.putBoolean(
+ BUNDLE_KEY_PREFER_IMMEDIATELY_AVAILABLE_CREDENTIALS,
+ preferImmediatelyAvailableCredentials
+ )
return bundle
}
+ @Suppress("deprecation") // bundle.get() used for boolean value to prevent default
+ // boolean value from being returned.
@JvmStatic
- fun createFrom(data: Bundle): CreatePublicKeyCredentialRequestPrivileged {
+ internal fun createFrom(data: Bundle): CreatePublicKeyCredentialRequestPrivileged {
try {
val requestJson = data.getString(BUNDLE_KEY_REQUEST_JSON)
- val rp = data.getString(BUNDLE_KEY_RP)
+ val rp = data.getString(BUNDLE_KEY_RELYING_PARTY)
val clientDataHash = data.getString(BUNDLE_KEY_CLIENT_DATA_HASH)
- val allowHybrid = data.get(BUNDLE_KEY_ALLOW_HYBRID)
+ val preferImmediatelyAvailableCredentials =
+ data.get(BUNDLE_KEY_PREFER_IMMEDIATELY_AVAILABLE_CREDENTIALS)
return CreatePublicKeyCredentialRequestPrivileged(
- requestJson!!,
- rp!!,
- clientDataHash!!,
- (allowHybrid!!) as Boolean,
+ requestJson!!,
+ rp!!,
+ clientDataHash!!,
+ (preferImmediatelyAvailableCredentials!!) as Boolean,
)
} catch (e: Exception) {
throw FrameworkClassParsingException()
diff --git a/packages/CredentialManager/src/com/android/credentialmanager/jetpack/developer/GetCredentialOption.kt b/packages/CredentialManager/src/com/android/credentialmanager/jetpack/developer/GetCredentialOption.kt
index ef48a77..fc7b7de 100644
--- a/packages/CredentialManager/src/com/android/credentialmanager/jetpack/developer/GetCredentialOption.kt
+++ b/packages/CredentialManager/src/com/android/credentialmanager/jetpack/developer/GetCredentialOption.kt
@@ -28,30 +28,40 @@
* otherwise
*/
open class GetCredentialOption(
- val type: String,
- val data: Bundle,
- val requireSystemProvider: Boolean,
+ open val type: String,
+ open val requestData: Bundle,
+ open val candidateQueryData: Bundle,
+ open val requireSystemProvider: Boolean,
) {
companion object {
@JvmStatic
- fun createFrom(from: android.credentials.GetCredentialOption): GetCredentialOption {
+ fun createFrom(
+ type: String,
+ requestData: Bundle,
+ candidateQueryData: Bundle,
+ requireSystemProvider: Boolean
+ ): GetCredentialOption {
return try {
- when (from.type) {
+ when (type) {
Credential.TYPE_PASSWORD_CREDENTIAL ->
- GetPasswordOption.createFrom(from.credentialRetrievalData)
+ GetPasswordOption.createFrom(requestData)
PublicKeyCredential.TYPE_PUBLIC_KEY_CREDENTIAL ->
- GetPublicKeyCredentialBaseOption.createFrom(from.credentialRetrievalData)
- else ->
- GetCredentialOption(
- from.type, from.credentialRetrievalData, from.requireSystemProvider()
- )
+ when (requestData.getString(PublicKeyCredential.BUNDLE_KEY_SUBTYPE)) {
+ GetPublicKeyCredentialOption
+ .BUNDLE_VALUE_SUBTYPE_GET_PUBLIC_KEY_CREDENTIAL_OPTION ->
+ GetPublicKeyCredentialOption.createFrom(requestData)
+ GetPublicKeyCredentialOptionPrivileged
+ .BUNDLE_VALUE_SUBTYPE_GET_PUBLIC_KEY_CREDENTIAL_OPTION_PRIVILEGED ->
+ GetPublicKeyCredentialOptionPrivileged.createFrom(requestData)
+ else -> throw FrameworkClassParsingException()
+ }
+ else -> throw FrameworkClassParsingException()
}
} catch (e: FrameworkClassParsingException) {
- GetCredentialOption(
- from.type,
- from.credentialRetrievalData,
- from.requireSystemProvider()
- )
+ // Parsing failed but don't crash the process. Instead just output a request with
+ // the raw framework values.
+ GetCustomCredentialOption(
+ type, requestData, candidateQueryData, requireSystemProvider)
}
}
}
diff --git a/packages/CredentialManager/src/com/android/credentialmanager/jetpack/developer/GetCredentialRequest.kt b/packages/CredentialManager/src/com/android/credentialmanager/jetpack/developer/GetCredentialRequest.kt
index 7f9256e..18d5089 100644
--- a/packages/CredentialManager/src/com/android/credentialmanager/jetpack/developer/GetCredentialRequest.kt
+++ b/packages/CredentialManager/src/com/android/credentialmanager/jetpack/developer/GetCredentialRequest.kt
@@ -24,7 +24,7 @@
* @throws IllegalArgumentException If [getCredentialOptions] is empty
*/
class GetCredentialRequest constructor(
- val getCredentialOptions: List<GetCredentialOption>,
+ val getCredentialOptions: List<GetCredentialOption>,
) {
init {
@@ -61,7 +61,14 @@
@JvmStatic
fun createFrom(from: android.credentials.GetCredentialRequest): GetCredentialRequest {
return GetCredentialRequest(
- from.getCredentialOptions.map {GetCredentialOption.createFrom(it)}
+ from.getCredentialOptions.map {
+ GetCredentialOption.createFrom(
+ it.type,
+ it.credentialRetrievalData,
+ it.candidateQueryData,
+ it.requireSystemProvider()
+ )
+ }
)
}
}
diff --git a/packages/CredentialManager/src/com/android/credentialmanager/jetpack/developer/GetCustomCredentialOption.kt b/packages/CredentialManager/src/com/android/credentialmanager/jetpack/developer/GetCustomCredentialOption.kt
new file mode 100644
index 0000000..803885c
--- /dev/null
+++ b/packages/CredentialManager/src/com/android/credentialmanager/jetpack/developer/GetCustomCredentialOption.kt
@@ -0,0 +1,50 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.credentialmanager.jetpack.developer
+
+import android.os.Bundle
+
+/**
+ * Allows extending custom versions of GetCredentialOptions for unique use cases.
+ *
+ * @property type the credential type determined by the credential-type-specific subclass
+ * generated for custom use cases
+ * @property requestData the request data in the [Bundle] format, generated for custom use cases
+ * @property candidateQueryData the partial request data in the [Bundle] format that will be sent to
+ * the provider during the initial candidate query stage, which should not contain sensitive user
+ * information
+ * @property requireSystemProvider true if must only be fulfilled by a system provider and false
+ * otherwise
+ * @throws IllegalArgumentException If [type] is empty
+ * @throws NullPointerException If [requestData] or [type] is null
+ */
+open class GetCustomCredentialOption(
+ final override val type: String,
+ final override val requestData: Bundle,
+ final override val candidateQueryData: Bundle,
+ @get:JvmName("requireSystemProvider")
+ final override val requireSystemProvider: Boolean
+) : GetCredentialOption(
+ type,
+ requestData,
+ candidateQueryData,
+ requireSystemProvider
+) {
+ init {
+ require(type.isNotEmpty()) { "type should not be empty" }
+ }
+}
diff --git a/packages/CredentialManager/src/com/android/credentialmanager/jetpack/developer/GetPasswordOption.kt b/packages/CredentialManager/src/com/android/credentialmanager/jetpack/developer/GetPasswordOption.kt
index 2facad1..2b9cfa3 100644
--- a/packages/CredentialManager/src/com/android/credentialmanager/jetpack/developer/GetPasswordOption.kt
+++ b/packages/CredentialManager/src/com/android/credentialmanager/jetpack/developer/GetPasswordOption.kt
@@ -23,6 +23,7 @@
class GetPasswordOption : GetCredentialOption(
Credential.TYPE_PASSWORD_CREDENTIAL,
Bundle(),
+ Bundle(),
false,
) {
companion object {
diff --git a/packages/CredentialManager/src/com/android/credentialmanager/jetpack/developer/GetPublicKeyCredentialBaseOption.kt b/packages/CredentialManager/src/com/android/credentialmanager/jetpack/developer/GetPublicKeyCredentialBaseOption.kt
deleted file mode 100644
index 9b51b30..0000000
--- a/packages/CredentialManager/src/com/android/credentialmanager/jetpack/developer/GetPublicKeyCredentialBaseOption.kt
+++ /dev/null
@@ -1,59 +0,0 @@
-/*
- * 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 com.android.credentialmanager.jetpack.developer
-
-import android.os.Bundle
-
-/**
- * Base request class for getting a registered public key credential.
- *
- * @property requestJson the request in JSON format
- * @throws NullPointerException If [requestJson] is null - auto handled by the
- * Kotlin runtime
- * @throws IllegalArgumentException If [requestJson] is empty
- *
- * @hide
- */
-abstract class GetPublicKeyCredentialBaseOption constructor(
- val requestJson: String,
- type: String,
- data: Bundle,
- requireSystemProvider: Boolean,
-) : GetCredentialOption(type, data, requireSystemProvider) {
-
- init {
- require(requestJson.isNotEmpty()) { "request json must not be empty" }
- }
-
- companion object {
- const val BUNDLE_KEY_REQUEST_JSON = "androidx.credentials.BUNDLE_KEY_REQUEST_JSON"
- const val BUNDLE_KEY_SUBTYPE = "androidx.credentials.BUNDLE_KEY_SUBTYPE"
-
- @JvmStatic
- fun createFrom(data: Bundle): GetPublicKeyCredentialBaseOption {
- return when (data.getString(BUNDLE_KEY_SUBTYPE)) {
- GetPublicKeyCredentialOption
- .BUNDLE_VALUE_SUBTYPE_GET_PUBLIC_KEY_CREDENTIAL_OPTION ->
- GetPublicKeyCredentialOption.createFrom(data)
- GetPublicKeyCredentialOptionPrivileged
- .BUNDLE_VALUE_SUBTYPE_GET_PUBLIC_KEY_CREDENTIAL_OPTION_PRIVILEGED ->
- GetPublicKeyCredentialOptionPrivileged.createFrom(data)
- else -> throw FrameworkClassParsingException()
- }
- }
- }
-}
diff --git a/packages/CredentialManager/src/com/android/credentialmanager/jetpack/developer/GetPublicKeyCredentialOption.kt b/packages/CredentialManager/src/com/android/credentialmanager/jetpack/developer/GetPublicKeyCredentialOption.kt
index 6f13c17..2f9b249 100644
--- a/packages/CredentialManager/src/com/android/credentialmanager/jetpack/developer/GetPublicKeyCredentialOption.kt
+++ b/packages/CredentialManager/src/com/android/credentialmanager/jetpack/developer/GetPublicKeyCredentialOption.kt
@@ -21,44 +21,62 @@
/**
* A request to get passkeys from the user's public key credential provider.
*
- * @property requestJson the request in JSON format
- * @property allowHybrid defines whether hybrid credentials are allowed to fulfill this request,
- * true by default
- * @throws NullPointerException If [requestJson] or [allowHybrid] is null. It is handled by the
- * Kotlin runtime
+ * @property requestJson the privileged request in JSON format in the standard webauthn web json
+ * shown [here](https://w3c.github.io/webauthn/#dictdef-publickeycredentialrequestoptionsjson).
+ * @property preferImmediatelyAvailableCredentials true if you prefer the operation to return
+ * immediately when there is no available credential instead of falling back to discovering remote
+ * credentials, and false (default) otherwise
+ * @throws NullPointerException If [requestJson] is null
* @throws IllegalArgumentException If [requestJson] is empty
- *
- * @hide
*/
class GetPublicKeyCredentialOption @JvmOverloads constructor(
- requestJson: String,
- @get:JvmName("allowHybrid")
- val allowHybrid: Boolean = true,
-) : GetPublicKeyCredentialBaseOption(
- requestJson,
- PublicKeyCredential.TYPE_PUBLIC_KEY_CREDENTIAL,
- toBundle(requestJson, allowHybrid),
- false
+ val requestJson: String,
+ @get:JvmName("preferImmediatelyAvailableCredentials")
+ val preferImmediatelyAvailableCredentials: Boolean = false,
+) : GetCredentialOption(
+ type = PublicKeyCredential.TYPE_PUBLIC_KEY_CREDENTIAL,
+ requestData = toRequestDataBundle(requestJson, preferImmediatelyAvailableCredentials),
+ candidateQueryData = toRequestDataBundle(requestJson, preferImmediatelyAvailableCredentials),
+ requireSystemProvider = false
) {
+ init {
+ require(requestJson.isNotEmpty()) { "requestJson must not be empty" }
+ }
+
+ /** @hide */
companion object {
- const val BUNDLE_KEY_ALLOW_HYBRID = "androidx.credentials.BUNDLE_KEY_ALLOW_HYBRID"
- const val BUNDLE_VALUE_SUBTYPE_GET_PUBLIC_KEY_CREDENTIAL_OPTION =
- "androidx.credentials.BUNDLE_VALUE_SUBTYPE_GET_PUBLIC_KEY_CREDENTIAL_OPTION"
+ internal const val BUNDLE_KEY_PREFER_IMMEDIATELY_AVAILABLE_CREDENTIALS =
+ "androidx.credentials.BUNDLE_KEY_PREFER_IMMEDIATELY_AVAILABLE_CREDENTIALS"
+ internal const val BUNDLE_KEY_REQUEST_JSON = "androidx.credentials.BUNDLE_KEY_REQUEST_JSON"
+ internal const val BUNDLE_VALUE_SUBTYPE_GET_PUBLIC_KEY_CREDENTIAL_OPTION =
+ "androidx.credentials.BUNDLE_VALUE_SUBTYPE_GET_PUBLIC_KEY_CREDENTIAL_OPTION"
@JvmStatic
- internal fun toBundle(requestJson: String, allowHybrid: Boolean): Bundle {
+ internal fun toRequestDataBundle(
+ requestJson: String,
+ preferImmediatelyAvailableCredentials: Boolean
+ ): Bundle {
val bundle = Bundle()
+ bundle.putString(
+ PublicKeyCredential.BUNDLE_KEY_SUBTYPE,
+ BUNDLE_VALUE_SUBTYPE_GET_PUBLIC_KEY_CREDENTIAL_OPTION
+ )
bundle.putString(BUNDLE_KEY_REQUEST_JSON, requestJson)
- bundle.putBoolean(BUNDLE_KEY_ALLOW_HYBRID, allowHybrid)
+ bundle.putBoolean(BUNDLE_KEY_PREFER_IMMEDIATELY_AVAILABLE_CREDENTIALS,
+ preferImmediatelyAvailableCredentials)
return bundle
}
+ @Suppress("deprecation") // bundle.get() used for boolean value to prevent default
+ // boolean value from being returned.
@JvmStatic
- fun createFrom(data: Bundle): GetPublicKeyCredentialOption {
+ internal fun createFrom(data: Bundle): GetPublicKeyCredentialOption {
try {
val requestJson = data.getString(BUNDLE_KEY_REQUEST_JSON)
- val allowHybrid = data.get(BUNDLE_KEY_ALLOW_HYBRID)
- return GetPublicKeyCredentialOption(requestJson!!, (allowHybrid!!) as Boolean)
+ val preferImmediatelyAvailableCredentials =
+ data.get(BUNDLE_KEY_PREFER_IMMEDIATELY_AVAILABLE_CREDENTIALS)
+ return GetPublicKeyCredentialOption(requestJson!!,
+ (preferImmediatelyAvailableCredentials!!) as Boolean)
} catch (e: Exception) {
throw FrameworkClassParsingException()
}
diff --git a/packages/CredentialManager/src/com/android/credentialmanager/jetpack/developer/GetPublicKeyCredentialOptionPrivileged.kt b/packages/CredentialManager/src/com/android/credentialmanager/jetpack/developer/GetPublicKeyCredentialOptionPrivileged.kt
index 79c62a1..6f4782a 100644
--- a/packages/CredentialManager/src/com/android/credentialmanager/jetpack/developer/GetPublicKeyCredentialOptionPrivileged.kt
+++ b/packages/CredentialManager/src/com/android/credentialmanager/jetpack/developer/GetPublicKeyCredentialOptionPrivileged.kt
@@ -21,41 +21,59 @@
/**
* 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.
+ * 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
- * @property allowHybrid defines whether hybrid credentials are allowed to fulfill this request,
- * true by default
- * @property rp the expected true RP ID which will override the one in the [requestJson]
- * @property clientDataHash a hash that is used to verify the [rp] Identity
- * @throws NullPointerException If any of [allowHybrid], [requestJson], [rp], or [clientDataHash]
- * is null. This is handled by the Kotlin runtime
- * @throws IllegalArgumentException If any of [requestJson], [rp], or [clientDataHash] is empty
- *
- * @hide
+ * @property requestJson the privileged request in JSON format in the standard webauthn web json
+ * shown [here](https://w3c.github.io/webauthn/#dictdef-publickeycredentialrequestoptionsjson).
+ * @property preferImmediatelyAvailableCredentials true if you prefer the operation to return
+ * immediately when there is no available credential instead of falling back to discovering remote
+ * credentials, and false (default) otherwise
+ * @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
*/
class GetPublicKeyCredentialOptionPrivileged @JvmOverloads constructor(
- requestJson: String,
- val rp: String,
- val clientDataHash: String,
- @get:JvmName("allowHybrid")
- val allowHybrid: Boolean = true
-) : GetPublicKeyCredentialBaseOption(
+ val requestJson: String,
+ val relyingParty: String,
+ val clientDataHash: String,
+ @get:JvmName("preferImmediatelyAvailableCredentials")
+ val preferImmediatelyAvailableCredentials: Boolean = false
+) : GetCredentialOption(
+ type = PublicKeyCredential.TYPE_PUBLIC_KEY_CREDENTIAL,
+ requestData = toBundle(
requestJson,
- PublicKeyCredential.TYPE_PUBLIC_KEY_CREDENTIAL,
- toBundle(requestJson, rp, clientDataHash, allowHybrid),
- false,
+ relyingParty,
+ clientDataHash,
+ preferImmediatelyAvailableCredentials
+ ),
+ candidateQueryData = toBundle(
+ requestJson,
+ relyingParty,
+ clientDataHash,
+ preferImmediatelyAvailableCredentials
+ ),
+ requireSystemProvider = false,
) {
init {
- require(rp.isNotEmpty()) { "rp must not be empty" }
+ require(requestJson.isNotEmpty()) { "requestJson must not be empty" }
+ require(relyingParty.isNotEmpty()) { "rp must not be empty" }
require(clientDataHash.isNotEmpty()) { "clientDataHash must not be empty" }
}
/** A builder for [GetPublicKeyCredentialOptionPrivileged]. */
- class Builder(var requestJson: String, var rp: String, var clientDataHash: String) {
+ class Builder(
+ private var requestJson: String,
+ private var relyingParty: String,
+ private var clientDataHash: String
+ ) {
- private var allowHybrid: Boolean = true
+ private var preferImmediatelyAvailableCredentials: Boolean = false
/**
* Sets the privileged request in JSON format.
@@ -66,23 +84,30 @@
}
/**
- * Sets whether hybrid credentials are allowed to fulfill this request, true by default.
+ * Sets to true if you prefer the operation to return immediately when there is no available
+ * credential instead of falling back to discovering remote credentials, and false
+ * otherwise.
+ *
+ * The default value is false.
*/
- fun setAllowHybrid(allowHybrid: Boolean): Builder {
- this.allowHybrid = allowHybrid
+ @Suppress("MissingGetterMatchingBuilder")
+ fun setPreferImmediatelyAvailableCredentials(
+ preferImmediatelyAvailableCredentials: Boolean
+ ): Builder {
+ this.preferImmediatelyAvailableCredentials = preferImmediatelyAvailableCredentials
return this
}
/**
* Sets the expected true RP ID which will override the one in the [requestJson].
*/
- fun setRp(rp: String): Builder {
- this.rp = rp
+ fun setRelyingParty(relyingParty: String): Builder {
+ this.relyingParty = relyingParty
return this
}
/**
- * Sets a hash that is used to verify the [rp] Identity.
+ * Sets a hash that is used to verify the [relyingParty] Identity.
*/
fun setClientDataHash(clientDataHash: String): Builder {
this.clientDataHash = clientDataHash
@@ -91,47 +116,63 @@
/** Builds a [GetPublicKeyCredentialOptionPrivileged]. */
fun build(): GetPublicKeyCredentialOptionPrivileged {
- return GetPublicKeyCredentialOptionPrivileged(this.requestJson,
- this.rp, this.clientDataHash, this.allowHybrid)
+ return GetPublicKeyCredentialOptionPrivileged(
+ this.requestJson,
+ this.relyingParty, this.clientDataHash, this.preferImmediatelyAvailableCredentials
+ )
}
}
+ /** @hide */
companion object {
- const val BUNDLE_KEY_RP = "androidx.credentials.BUNDLE_KEY_RP"
- const val BUNDLE_KEY_CLIENT_DATA_HASH =
- "androidx.credentials.BUNDLE_KEY_CLIENT_DATA_HASH"
- const val BUNDLE_KEY_ALLOW_HYBRID = "androidx.credentials.BUNDLE_KEY_ALLOW_HYBRID"
- const val BUNDLE_VALUE_SUBTYPE_GET_PUBLIC_KEY_CREDENTIAL_OPTION_PRIVILEGED =
- "androidx.credentials.BUNDLE_VALUE_SUBTYPE_GET_PUBLIC_KEY_CREDENTIAL_OPTION" +
- "_PRIVILEGED"
+ internal const val BUNDLE_KEY_RELYING_PARTY =
+ "androidx.credentials.BUNDLE_KEY_RELYING_PARTY"
+ internal const val BUNDLE_KEY_CLIENT_DATA_HASH =
+ "androidx.credentials.BUNDLE_KEY_CLIENT_DATA_HASH"
+ internal const val BUNDLE_KEY_PREFER_IMMEDIATELY_AVAILABLE_CREDENTIALS =
+ "androidx.credentials.BUNDLE_KEY_PREFER_IMMEDIATELY_AVAILABLE_CREDENTIALS"
+ internal const val BUNDLE_KEY_REQUEST_JSON = "androidx.credentials.BUNDLE_KEY_REQUEST_JSON"
+ internal const val BUNDLE_VALUE_SUBTYPE_GET_PUBLIC_KEY_CREDENTIAL_OPTION_PRIVILEGED =
+ "androidx.credentials.BUNDLE_VALUE_SUBTYPE_GET_PUBLIC_KEY_CREDENTIAL_OPTION" +
+ "_PRIVILEGED"
@JvmStatic
internal fun toBundle(
- requestJson: String,
- rp: String,
- clientDataHash: String,
- allowHybrid: Boolean
+ requestJson: String,
+ relyingParty: String,
+ clientDataHash: String,
+ preferImmediatelyAvailableCredentials: Boolean
): Bundle {
val bundle = Bundle()
+ bundle.putString(
+ PublicKeyCredential.BUNDLE_KEY_SUBTYPE,
+ BUNDLE_VALUE_SUBTYPE_GET_PUBLIC_KEY_CREDENTIAL_OPTION_PRIVILEGED
+ )
bundle.putString(BUNDLE_KEY_REQUEST_JSON, requestJson)
- bundle.putString(BUNDLE_KEY_RP, rp)
+ bundle.putString(BUNDLE_KEY_RELYING_PARTY, relyingParty)
bundle.putString(BUNDLE_KEY_CLIENT_DATA_HASH, clientDataHash)
- bundle.putBoolean(BUNDLE_KEY_ALLOW_HYBRID, allowHybrid)
+ bundle.putBoolean(
+ BUNDLE_KEY_PREFER_IMMEDIATELY_AVAILABLE_CREDENTIALS,
+ preferImmediatelyAvailableCredentials
+ )
return bundle
}
+ @Suppress("deprecation") // bundle.get() used for boolean value to prevent default
+ // boolean value from being returned.
@JvmStatic
- fun createFrom(data: Bundle): GetPublicKeyCredentialOptionPrivileged {
+ internal fun createFrom(data: Bundle): GetPublicKeyCredentialOptionPrivileged {
try {
val requestJson = data.getString(BUNDLE_KEY_REQUEST_JSON)
- val rp = data.getString(BUNDLE_KEY_RP)
+ val rp = data.getString(BUNDLE_KEY_RELYING_PARTY)
val clientDataHash = data.getString(BUNDLE_KEY_CLIENT_DATA_HASH)
- val allowHybrid = data.get(BUNDLE_KEY_ALLOW_HYBRID)
+ val preferImmediatelyAvailableCredentials =
+ data.get(BUNDLE_KEY_PREFER_IMMEDIATELY_AVAILABLE_CREDENTIALS)
return GetPublicKeyCredentialOptionPrivileged(
- requestJson!!,
- rp!!,
- clientDataHash!!,
- (allowHybrid!!) as Boolean,
+ requestJson!!,
+ rp!!,
+ clientDataHash!!,
+ (preferImmediatelyAvailableCredentials!!) as Boolean,
)
} catch (e: Exception) {
throw FrameworkClassParsingException()
diff --git a/packages/CredentialManager/src/com/android/credentialmanager/jetpack/developer/PublicKeyCredential.kt b/packages/CredentialManager/src/com/android/credentialmanager/jetpack/developer/PublicKeyCredential.kt
index b45a63b..6a81167 100644
--- a/packages/CredentialManager/src/com/android/credentialmanager/jetpack/developer/PublicKeyCredential.kt
+++ b/packages/CredentialManager/src/com/android/credentialmanager/jetpack/developer/PublicKeyCredential.kt
@@ -45,6 +45,8 @@
/** The type value for public key credential related operations. */
const val TYPE_PUBLIC_KEY_CREDENTIAL: String =
"androidx.credentials.TYPE_PUBLIC_KEY_CREDENTIAL"
+ /** The Bundle key value for the public key credential subtype (privileged or regular). */
+ internal const val BUNDLE_KEY_SUBTYPE = "androidx.credentials.BUNDLE_KEY_SUBTYPE"
const val BUNDLE_KEY_AUTHENTICATION_RESPONSE_JSON =
"androidx.credentials.BUNDLE_KEY_AUTHENTICATION_RESPONSE_JSON"
diff --git a/packages/CredentialManager/src/com/android/credentialmanager/jetpack/provider/AuthenticationAction.kt b/packages/CredentialManager/src/com/android/credentialmanager/jetpack/provider/AuthenticationAction.kt
new file mode 100644
index 0000000..283c7ba
--- /dev/null
+++ b/packages/CredentialManager/src/com/android/credentialmanager/jetpack/provider/AuthenticationAction.kt
@@ -0,0 +1,55 @@
+/*
+ * 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 com.android.credentialmanager.jetpack.provider
+
+import android.app.PendingIntent
+import android.app.slice.Slice
+import android.util.Log
+import androidx.annotation.VisibleForTesting
+
+/**
+ * UI representation for a credential entry used during the get credential flow.
+ *
+ * TODO: move to jetpack.
+ */
+class AuthenticationAction constructor(
+ val pendingIntent: PendingIntent
+) {
+
+
+ companion object {
+ private const val TAG = "AuthenticationAction"
+ @VisibleForTesting(otherwise = VisibleForTesting.PRIVATE)
+ internal const val SLICE_HINT_PENDING_INTENT =
+ "androidx.credentials.provider.authenticationAction.SLICE_HINT_PENDING_INTENT"
+
+ @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
+ }
+ }
+}
diff --git a/packages/CredentialManager/src/com/android/credentialmanager/jetpack/provider/CreateEntry.kt b/packages/CredentialManager/src/com/android/credentialmanager/jetpack/provider/CreateEntry.kt
index bed02f8..0ec91d6 100644
--- a/packages/CredentialManager/src/com/android/credentialmanager/jetpack/provider/CreateEntry.kt
+++ b/packages/CredentialManager/src/com/android/credentialmanager/jetpack/provider/CreateEntry.kt
@@ -36,7 +36,8 @@
val pendingIntent: PendingIntent?,
val icon: Icon?,
val lastUsedTimeMillis: Long,
- val credentialCountInformationList: List<CredentialCountInformation>
+ val credentialCountInformationList: List<CredentialCountInformation>,
+ val footerDescription: CharSequence?,
) {
init {
@@ -61,6 +62,7 @@
mutableListOf()
private var icon: Icon? = null
private var lastUsedTimeMillis: Long = 0
+ private var footerDescription: CharSequence? = null
/** Adds a [CredentialCountInformation] denoting a given credential
* type and the count of credentials that the provider has stored for that
@@ -99,6 +101,12 @@
return this
}
+ /** Sets the footer description of this */
+ fun setFooterDescription(footerDescription: CharSequence): Builder {
+ this.footerDescription = footerDescription
+ return this
+ }
+
/**
* Builds an instance of [CreateEntry]
*
@@ -106,7 +114,7 @@
*/
fun build(): CreateEntry {
return CreateEntry(accountName, pendingIntent, icon, lastUsedTimeMillis,
- credentialCountInformationList)
+ credentialCountInformationList, footerDescription)
}
}
@@ -122,6 +130,8 @@
"androidx.credentials.provider.createEntry.SLICE_HINT_LAST_USED_TIME_MILLIS"
internal const val SLICE_HINT_PENDING_INTENT =
"androidx.credentials.provider.createEntry.SLICE_HINT_PENDING_INTENT"
+ internal const val SLICE_HINT_FOOTER_DESCRIPTION =
+ "androidx.credentials.provider.createEntry.SLICE_HINT_FOOTER_DESCRIPTION"
@JvmStatic
fun toSlice(createEntry: CreateEntry): Slice {
@@ -150,6 +160,10 @@
.build(),
/*subType=*/null)
}
+ if (createEntry.footerDescription != null) {
+ sliceBuilder.addText(createEntry.footerDescription, /*subType=*/null,
+ listOf(SLICE_HINT_FOOTER_DESCRIPTION))
+ }
return sliceBuilder.build()
}
@@ -167,6 +181,7 @@
var pendingIntent: PendingIntent? = null
var credentialCountInfo: List<CredentialCountInformation> = listOf()
var lastUsedTimeMillis: Long = 0
+ var footerDescription: CharSequence? = null
slice.items.forEach {
if (it.hasHint(SLICE_HINT_ACCOUNT_NAME)) {
@@ -179,12 +194,14 @@
credentialCountInfo = convertBundleToCredentialCountInfo(it.bundle)
} else if (it.hasHint(SLICE_HINT_LAST_USED_TIME_MILLIS)) {
lastUsedTimeMillis = it.long
+ } else if (it.hasHint(SLICE_HINT_FOOTER_DESCRIPTION)) {
+ footerDescription = it.text
}
}
return try {
CreateEntry(accountName, pendingIntent, icon,
- lastUsedTimeMillis, credentialCountInfo)
+ lastUsedTimeMillis, credentialCountInfo, footerDescription)
} catch (e: Exception) {
Log.i(TAG, "fromSlice failed with: " + e.message)
null
diff --git a/packages/PackageInstaller/res/values/strings.xml b/packages/PackageInstaller/res/values/strings.xml
index b713c14..cb2baa9 100644
--- a/packages/PackageInstaller/res/values/strings.xml
+++ b/packages/PackageInstaller/res/values/strings.xml
@@ -37,6 +37,11 @@
<string name="install_confirm_question">Do you want to install this app?</string>
<!-- Message for updating an existing app [CHAR LIMIT=NONE] -->
<string name="install_confirm_question_update">Do you want to update this app?</string>
+ <!-- TODO(b/244413073) Revise the description after getting UX input and UXR on this. -->
+ <!-- Message for updating an existing app when updating owner changed [CHAR LIMIT=NONE] -->
+ <string name="install_confirm_question_update_owner_changed">Updates to this app are currently managed by <xliff:g id="existing_update_owner">%1$s</xliff:g>.\n\nBy updating, you\'ll get future updates from <xliff:g id="new_update_owner">%2$s</xliff:g> instead.</string>
+ <!-- Message for updating an existing app with update owner reminder [CHAR LIMIT=NONE] -->
+ <string name="install_confirm_question_update_owner_reminder">Updates to this app are currently managed by <xliff:g id="existing_update_owner">%1$s</xliff:g>.\n\nDo you want to install this update from <xliff:g id="new_update_owner">%2$s</xliff:g>.</string>
<!-- [CHAR LIMIT=100] -->
<string name="install_failed">App not installed.</string>
<!-- Reason displayed when installation fails because the package was blocked
diff --git a/packages/PackageInstaller/src/com/android/packageinstaller/PackageInstallerActivity.java b/packages/PackageInstaller/src/com/android/packageinstaller/PackageInstallerActivity.java
index 3138158..49c9188 100644
--- a/packages/PackageInstaller/src/com/android/packageinstaller/PackageInstallerActivity.java
+++ b/packages/PackageInstaller/src/com/android/packageinstaller/PackageInstallerActivity.java
@@ -33,10 +33,12 @@
import android.content.DialogInterface;
import android.content.Intent;
import android.content.pm.ApplicationInfo;
+import android.content.pm.InstallSourceInfo;
import android.content.pm.PackageInfo;
import android.content.pm.PackageInstaller;
import android.content.pm.PackageInstaller.SessionInfo;
import android.content.pm.PackageManager;
+import android.content.pm.PackageManager.ApplicationInfoFlags;
import android.content.pm.PackageManager.NameNotFoundException;
import android.graphics.drawable.BitmapDrawable;
import android.net.Uri;
@@ -47,9 +49,11 @@
import android.os.UserHandle;
import android.os.UserManager;
import android.provider.Settings;
+import android.text.TextUtils;
import android.util.Log;
import android.view.View;
import android.widget.Button;
+import android.widget.TextView;
import androidx.annotation.NonNull;
import androidx.annotation.StringRes;
@@ -88,6 +92,7 @@
private int mOriginatingUid = Process.INVALID_UID;
private String mOriginatingPackage; // The package name corresponding to #mOriginatingUid
private int mActivityResultCode = Activity.RESULT_CANCELED;
+ private int mPendingUserActionReason = -1;
private final boolean mLocalLOGV = false;
PackageManager mPm;
@@ -132,10 +137,27 @@
private boolean mEnableOk = false;
private void startInstallConfirm() {
- View viewToEnable;
+ TextView viewToEnable;
if (mAppInfo != null) {
viewToEnable = requireViewById(R.id.install_confirm_question_update);
+
+ final CharSequence existingUpdateOwnerLabel = getExistingUpdateOwnerLabel();
+ final CharSequence requestedUpdateOwnerLabel = getApplicationLabel(mCallingPackage);
+ if (!TextUtils.isEmpty(existingUpdateOwnerLabel)) {
+ if (mPendingUserActionReason == PackageInstaller.REASON_OWNERSHIP_CHANGED) {
+ viewToEnable.setText(
+ getString(R.string.install_confirm_question_update_owner_changed,
+ existingUpdateOwnerLabel, requestedUpdateOwnerLabel));
+ } else if (mPendingUserActionReason == PackageInstaller.REASON_REMIND_OWNERSHIP
+ || mPendingUserActionReason
+ == PackageInstaller.REASON_CONFIRM_PACKAGE_CHANGE) {
+ viewToEnable.setText(
+ getString(R.string.install_confirm_question_update_owner_reminder,
+ existingUpdateOwnerLabel, requestedUpdateOwnerLabel));
+ }
+ }
+
mOk.setText(R.string.update);
} else {
// This is a new application with no permissions.
@@ -149,6 +171,27 @@
mOk.setFilterTouchesWhenObscured(true);
}
+ private CharSequence getExistingUpdateOwnerLabel() {
+ try {
+ final String packageName = mPkgInfo.packageName;
+ final InstallSourceInfo sourceInfo = mPm.getInstallSourceInfo(packageName);
+ final String existingUpdateOwner = sourceInfo.getUpdateOwnerPackageName();
+ return getApplicationLabel(existingUpdateOwner);
+ } catch (NameNotFoundException e) {
+ return null;
+ }
+ }
+
+ private CharSequence getApplicationLabel(String packageName) {
+ try {
+ final ApplicationInfo appInfo = mPm.getApplicationInfo(packageName,
+ ApplicationInfoFlags.of(0));
+ return mPm.getApplicationLabel(appInfo);
+ } catch (NameNotFoundException e) {
+ return null;
+ }
+ }
+
/**
* Replace any dialog shown by the dialog with the one for the given {@link #createDialog(int)}.
*
@@ -344,6 +387,7 @@
packageSource = Uri.fromFile(new File(resolvedBaseCodePath));
mOriginatingURI = null;
mReferrerURI = null;
+ mPendingUserActionReason = info.getPendingUserActionReason();
} else if (PackageInstaller.ACTION_CONFIRM_PRE_APPROVAL.equals(action)) {
final int sessionId = intent.getIntExtra(PackageInstaller.EXTRA_SESSION_ID,
-1 /* defaultValue */);
@@ -358,11 +402,13 @@
packageSource = info;
mOriginatingURI = null;
mReferrerURI = null;
+ mPendingUserActionReason = info.getPendingUserActionReason();
} else {
mSessionId = -1;
packageSource = intent.getData();
mOriginatingURI = intent.getParcelableExtra(Intent.EXTRA_ORIGINATING_URI);
mReferrerURI = intent.getParcelableExtra(Intent.EXTRA_REFERRER);
+ mPendingUserActionReason = PackageInstaller.REASON_CONFIRM_PACKAGE_CHANGE;
}
// if there's nothing to do, quietly slip into the ether
diff --git a/packages/SettingsLib/IllustrationPreference/Android.bp b/packages/SettingsLib/IllustrationPreference/Android.bp
index 5904589..e80eb66 100644
--- a/packages/SettingsLib/IllustrationPreference/Android.bp
+++ b/packages/SettingsLib/IllustrationPreference/Android.bp
@@ -20,4 +20,9 @@
sdk_version: "system_current",
min_sdk_version: "28",
+
+ apex_available: [
+ "//apex_available:platform",
+ "com.android.permission",
+ ],
}
diff --git a/packages/SettingsLib/IllustrationPreference/src/com/android/settingslib/widget/IllustrationPreference.java b/packages/SettingsLib/IllustrationPreference/src/com/android/settingslib/widget/IllustrationPreference.java
index 468a976..1592094 100644
--- a/packages/SettingsLib/IllustrationPreference/src/com/android/settingslib/widget/IllustrationPreference.java
+++ b/packages/SettingsLib/IllustrationPreference/src/com/android/settingslib/widget/IllustrationPreference.java
@@ -59,6 +59,18 @@
private Uri mImageUri;
private Drawable mImageDrawable;
private View mMiddleGroundView;
+ private OnBindListener mOnBindListener;
+
+ /**
+ * Interface to listen in on when {@link #onBindViewHolder(PreferenceViewHolder)} occurs.
+ */
+ public interface OnBindListener {
+ /**
+ * Called when when {@link #onBindViewHolder(PreferenceViewHolder)} occurs.
+ * @param animationView the animation view for this preference.
+ */
+ void onBind(LottieAnimationView animationView);
+ }
private final Animatable2.AnimationCallback mAnimationCallback =
new Animatable2.AnimationCallback() {
@@ -133,6 +145,17 @@
if (IS_ENABLED_LOTTIE_ADAPTIVE_COLOR) {
ColorUtils.applyDynamicColors(getContext(), illustrationView);
}
+
+ if (mOnBindListener != null) {
+ mOnBindListener.onBind(illustrationView);
+ }
+ }
+
+ /**
+ * Sets a listener to be notified when the views are binded.
+ */
+ public void setOnBindListener(OnBindListener listener) {
+ mOnBindListener = listener;
}
/**
diff --git a/packages/SettingsLib/RestrictedLockUtils/src/com/android/settingslib/RestrictedLockUtils.java b/packages/SettingsLib/RestrictedLockUtils/src/com/android/settingslib/RestrictedLockUtils.java
index 80f02b4..96a11ee 100644
--- a/packages/SettingsLib/RestrictedLockUtils/src/com/android/settingslib/RestrictedLockUtils.java
+++ b/packages/SettingsLib/RestrictedLockUtils/src/com/android/settingslib/RestrictedLockUtils.java
@@ -37,7 +37,7 @@
*/
public class RestrictedLockUtils {
/**
- * Get EnforcedAdmin from DevicePolicyManager
+ * Gets EnforcedAdmin from DevicePolicyManager
*/
@RequiresApi(Build.VERSION_CODES.M)
public static EnforcedAdmin getProfileOrDeviceOwner(Context context, UserHandle user) {
@@ -45,7 +45,7 @@
}
/**
- * Get EnforcedAdmin from DevicePolicyManager
+ * Gets EnforcedAdmin from DevicePolicyManager
*/
@RequiresApi(Build.VERSION_CODES.M)
public static EnforcedAdmin getProfileOrDeviceOwner(
@@ -81,7 +81,7 @@
}
/**
- * Send the intent to trigger the {@code android.settings.ShowAdminSupportDetailsDialog}.
+ * Sends the intent to trigger the {@code android.settings.ShowAdminSupportDetailsDialog}.
*/
@RequiresApi(Build.VERSION_CODES.M)
public static void sendShowAdminSupportDetailsIntent(Context context, EnforcedAdmin admin) {
@@ -97,6 +97,9 @@
context.startActivityAsUser(intent, UserHandle.of(targetUserId));
}
+ /**
+ * Gets the intent to trigger the {@code android.settings.ShowAdminSupportDetailsDialog}.
+ */
public static Intent getShowAdminSupportDetailsIntent(Context context, EnforcedAdmin admin) {
final Intent intent = new Intent(Settings.ACTION_SHOW_ADMIN_SUPPORT_DETAILS);
if (admin != null) {
@@ -109,7 +112,27 @@
}
/**
- * Check if current user is profile or not
+ * Shows restricted setting dialog.
+ */
+ @RequiresApi(Build.VERSION_CODES.TIRAMISU)
+ public static void sendShowRestrictedSettingDialogIntent(Context context,
+ String packageName, int uid) {
+ final Intent intent = getShowRestrictedSettingsIntent(packageName, uid);
+ context.startActivity(intent);
+ }
+
+ /**
+ * Gets restricted settings dialog intent.
+ */
+ private static Intent getShowRestrictedSettingsIntent(String packageName, int uid) {
+ final Intent intent = new Intent(Settings.ACTION_SHOW_RESTRICTED_SETTING_DIALOG);
+ intent.putExtra(Intent.EXTRA_PACKAGE_NAME, packageName);
+ intent.putExtra(Intent.EXTRA_UID, uid);
+ return intent;
+ }
+
+ /**
+ * Checks if current user is profile or not
*/
@RequiresApi(Build.VERSION_CODES.M)
public static boolean isCurrentUserOrProfile(Context context, int userId) {
@@ -117,6 +140,9 @@
return um.getUserProfiles().contains(UserHandle.of(userId));
}
+ /**
+ * A admin for the restriction enforced.
+ */
public static class EnforcedAdmin {
@Nullable
public ComponentName component = null;
@@ -129,12 +155,17 @@
@Nullable
public UserHandle user = null;
- // We use this to represent the case where a policy is enforced by multiple admins.
- public final static EnforcedAdmin MULTIPLE_ENFORCED_ADMIN = new EnforcedAdmin();
+ /**
+ * We use this to represent the case where a policy is enforced by multiple admins.
+ */
+ public static final EnforcedAdmin MULTIPLE_ENFORCED_ADMIN = new EnforcedAdmin();
+ /**
+ * The restriction enforced by admin with restriction.
+ */
public static EnforcedAdmin createDefaultEnforcedAdminWithRestriction(
String enforcedRestriction) {
- EnforcedAdmin enforcedAdmin = new EnforcedAdmin();
+ final EnforcedAdmin enforcedAdmin = new EnforcedAdmin();
enforcedAdmin.enforcedRestriction = enforcedRestriction;
return enforcedAdmin;
}
@@ -159,8 +190,7 @@
this.user = other.user;
}
- public EnforcedAdmin() {
- }
+ public EnforcedAdmin() {}
/**
* Combines two {@link EnforcedAdmin} into one: if one of them is null, then just return
@@ -189,9 +219,9 @@
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
EnforcedAdmin that = (EnforcedAdmin) o;
- return Objects.equals(user, that.user) &&
- Objects.equals(component, that.component) &&
- Objects.equals(enforcedRestriction, that.enforcedRestriction);
+ return Objects.equals(user, that.user)
+ && Objects.equals(component, that.component)
+ && Objects.equals(enforcedRestriction, that.enforcedRestriction);
}
@Override
@@ -201,11 +231,11 @@
@Override
public String toString() {
- return "EnforcedAdmin{" +
- "component=" + component +
- ", enforcedRestriction='" + enforcedRestriction +
- ", user=" + user +
- '}';
+ return "EnforcedAdmin{"
+ + "component=" + component
+ + ", enforcedRestriction='" + enforcedRestriction
+ + ", user=" + user
+ + '}';
}
}
}
diff --git a/packages/SettingsLib/Spa/spa/build.gradle b/packages/SettingsLib/Spa/spa/build.gradle
index 73c1099..bf4ad75 100644
--- a/packages/SettingsLib/Spa/spa/build.gradle
+++ b/packages/SettingsLib/Spa/spa/build.gradle
@@ -88,6 +88,7 @@
implementation "com.airbnb.android:lottie-compose:5.2.0"
androidTestImplementation project(":testutils")
+ androidTestImplementation 'androidx.lifecycle:lifecycle-runtime-testing'
androidTestImplementation "com.linkedin.dexmaker:dexmaker-mockito:2.28.1"
}
diff --git a/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/framework/compose/LifecycleEffect.kt b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/framework/compose/LifecycleEffect.kt
new file mode 100644
index 0000000..e91fa65
--- /dev/null
+++ b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/framework/compose/LifecycleEffect.kt
@@ -0,0 +1,46 @@
+/*
+ * 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 com.android.settingslib.spa.framework.compose
+
+import androidx.compose.runtime.Composable
+import androidx.compose.runtime.DisposableEffect
+import androidx.compose.ui.platform.LocalLifecycleOwner
+import androidx.lifecycle.Lifecycle
+import androidx.lifecycle.LifecycleEventObserver
+
+@Composable
+fun LifecycleEffect(
+ onStart: () -> Unit = {},
+ onStop: () -> Unit = {},
+) {
+ val lifecycleOwner = LocalLifecycleOwner.current
+ DisposableEffect(lifecycleOwner) {
+ val observer = LifecycleEventObserver { _, event ->
+ if (event == Lifecycle.Event.ON_START) {
+ onStart()
+ } else if (event == Lifecycle.Event.ON_STOP) {
+ onStop()
+ }
+ }
+
+ lifecycleOwner.lifecycle.addObserver(observer)
+
+ onDispose {
+ lifecycleOwner.lifecycle.removeObserver(observer)
+ }
+ }
+}
\ No newline at end of file
diff --git a/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/framework/util/PageLogger.kt b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/framework/util/PageLogger.kt
index 271443e..73eae07 100644
--- a/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/framework/util/PageLogger.kt
+++ b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/framework/util/PageLogger.kt
@@ -18,55 +18,41 @@
import android.os.Bundle
import androidx.compose.runtime.Composable
-import androidx.compose.runtime.DisposableEffect
import androidx.compose.runtime.remember
-import androidx.compose.ui.platform.LocalLifecycleOwner
import androidx.core.os.bundleOf
-import androidx.lifecycle.Lifecycle
-import androidx.lifecycle.LifecycleEventObserver
import com.android.settingslib.spa.framework.common.LOG_DATA_DISPLAY_NAME
import com.android.settingslib.spa.framework.common.LOG_DATA_SESSION_NAME
import com.android.settingslib.spa.framework.common.LogCategory
import com.android.settingslib.spa.framework.common.LogEvent
+import com.android.settingslib.spa.framework.common.SettingsPage
import com.android.settingslib.spa.framework.common.SettingsPageProvider
import com.android.settingslib.spa.framework.common.SpaEnvironmentFactory
import com.android.settingslib.spa.framework.common.createSettingsPage
+import com.android.settingslib.spa.framework.compose.LifecycleEffect
import com.android.settingslib.spa.framework.compose.LocalNavController
+import com.android.settingslib.spa.framework.compose.NavControllerWrapper
@Composable
internal fun SettingsPageProvider.PageEvent(arguments: Bundle? = null) {
val page = remember(arguments) { createSettingsPage(arguments) }
- val lifecycleOwner = LocalLifecycleOwner.current
val navController = LocalNavController.current
- DisposableEffect(lifecycleOwner) {
- val observer = LifecycleEventObserver { _, event ->
- val logPageEvent: (event: LogEvent) -> Unit = {
- SpaEnvironmentFactory.instance.logger.event(
- id = page.id,
- event = it,
- category = LogCategory.FRAMEWORK,
- extraData = bundleOf(
- LOG_DATA_DISPLAY_NAME to page.displayName,
- LOG_DATA_SESSION_NAME to navController.sessionSourceName,
- ).apply {
- val normArguments = parameter.normalize(arguments)
- if (normArguments != null) putAll(normArguments)
- }
- )
- }
- if (event == Lifecycle.Event.ON_START) {
- logPageEvent(LogEvent.PAGE_ENTER)
- } else if (event == Lifecycle.Event.ON_STOP) {
- logPageEvent(LogEvent.PAGE_LEAVE)
- }
- }
-
- // Add the observer to the lifecycle
- lifecycleOwner.lifecycle.addObserver(observer)
-
- // When the effect leaves the Composition, remove the observer
- onDispose {
- lifecycleOwner.lifecycle.removeObserver(observer)
- }
- }
+ LifecycleEffect(
+ onStart = { page.logPageEvent(LogEvent.PAGE_ENTER, navController) },
+ onStop = { page.logPageEvent(LogEvent.PAGE_LEAVE, navController) },
+ )
}
+
+private fun SettingsPage.logPageEvent(event: LogEvent, navController: NavControllerWrapper) {
+ SpaEnvironmentFactory.instance.logger.event(
+ id = id,
+ event = event,
+ category = LogCategory.FRAMEWORK,
+ extraData = bundleOf(
+ LOG_DATA_DISPLAY_NAME to displayName,
+ LOG_DATA_SESSION_NAME to navController.sessionSourceName,
+ ).apply {
+ val normArguments = parameter.normalize(arguments)
+ if (normArguments != null) putAll(normArguments)
+ }
+ )
+}
\ No newline at end of file
diff --git a/packages/SettingsLib/Spa/tests/Android.bp b/packages/SettingsLib/Spa/tests/Android.bp
index f9e64ae..b4c67cc 100644
--- a/packages/SettingsLib/Spa/tests/Android.bp
+++ b/packages/SettingsLib/Spa/tests/Android.bp
@@ -31,6 +31,7 @@
"SpaLib",
"SpaLibTestUtils",
"androidx.compose.runtime_runtime",
+ "androidx.lifecycle_lifecycle-runtime-testing",
"androidx.test.ext.junit",
"androidx.test.runner",
"mockito-target-minus-junit4",
diff --git a/packages/SettingsLib/Spa/tests/src/com/android/settingslib/spa/framework/compose/LifecycleEffectTest.kt b/packages/SettingsLib/Spa/tests/src/com/android/settingslib/spa/framework/compose/LifecycleEffectTest.kt
new file mode 100644
index 0000000..fe7baff
--- /dev/null
+++ b/packages/SettingsLib/Spa/tests/src/com/android/settingslib/spa/framework/compose/LifecycleEffectTest.kt
@@ -0,0 +1,62 @@
+/*
+ * 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 com.android.settingslib.spa.framework.compose
+
+import androidx.compose.runtime.CompositionLocalProvider
+import androidx.compose.runtime.LaunchedEffect
+import androidx.compose.ui.platform.LocalLifecycleOwner
+import androidx.compose.ui.test.junit4.createComposeRule
+import androidx.lifecycle.Lifecycle
+import androidx.lifecycle.testing.TestLifecycleOwner
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import com.google.common.truth.Truth.assertThat
+import org.junit.Rule
+import org.junit.Test
+import org.junit.runner.RunWith
+
+@RunWith(AndroidJUnit4::class)
+class LifecycleEffectTest {
+ @get:Rule
+ val composeTestRule = createComposeRule()
+
+ @Test
+ fun onStart_isCalled() {
+ var onStartIsCalled = false
+ composeTestRule.setContent {
+ LifecycleEffect(onStart = { onStartIsCalled = true })
+ }
+
+ assertThat(onStartIsCalled).isTrue()
+ }
+
+ @Test
+ fun onStop_isCalled() {
+ var onStopIsCalled = false
+ val testLifecycleOwner = TestLifecycleOwner()
+
+ composeTestRule.setContent {
+ CompositionLocalProvider(LocalLifecycleOwner provides testLifecycleOwner) {
+ LifecycleEffect(onStop = { onStopIsCalled = true })
+ }
+ LaunchedEffect(Unit) {
+ testLifecycleOwner.currentState = Lifecycle.State.CREATED
+ }
+ }
+
+ assertThat(onStopIsCalled).isTrue()
+ }
+}
\ No newline at end of file
diff --git a/packages/SettingsLib/SpaPrivileged/AndroidManifest.xml b/packages/SettingsLib/SpaPrivileged/AndroidManifest.xml
index 2efa107..d1dceb3 100644
--- a/packages/SettingsLib/SpaPrivileged/AndroidManifest.xml
+++ b/packages/SettingsLib/SpaPrivileged/AndroidManifest.xml
@@ -15,4 +15,8 @@
limitations under the License.
-->
-<manifest package="com.android.settingslib.spaprivileged" />
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="com.android.settingslib.spaprivileged">
+<uses-permission android:name="android.permission.MANAGE_USERS" />
+</manifest>
+
diff --git a/packages/SettingsLib/SpaPrivileged/res/values/strings.xml b/packages/SettingsLib/SpaPrivileged/res/values/strings.xml
index 25dbe00..e1e7649 100644
--- a/packages/SettingsLib/SpaPrivileged/res/values/strings.xml
+++ b/packages/SettingsLib/SpaPrivileged/res/values/strings.xml
@@ -27,4 +27,6 @@
<string name="app_permission_summary_not_allowed">Not allowed</string>
<!-- Manage applications, version string displayed in app snippet -->
<string name="version_text">version <xliff:g id="version_num">%1$s</xliff:g></string>
+ <!-- Label of an app on App Info page of Cloned Apps menu [CHAR LIMIT=40] -->
+ <string name="cloned_app_info_label"><xliff:g id="package_label">%1$s</xliff:g> clone</string>
</resources>
diff --git a/packages/SettingsLib/SpaPrivileged/src/com/android/settingslib/spaprivileged/framework/compose/DisposableBroadcastReceiverAsUser.kt b/packages/SettingsLib/SpaPrivileged/src/com/android/settingslib/spaprivileged/framework/compose/DisposableBroadcastReceiverAsUser.kt
index b2ea4a0..a2fb101 100644
--- a/packages/SettingsLib/SpaPrivileged/src/com/android/settingslib/spaprivileged/framework/compose/DisposableBroadcastReceiverAsUser.kt
+++ b/packages/SettingsLib/SpaPrivileged/src/com/android/settingslib/spaprivileged/framework/compose/DisposableBroadcastReceiverAsUser.kt
@@ -22,11 +22,9 @@
import android.content.IntentFilter
import android.os.UserHandle
import androidx.compose.runtime.Composable
-import androidx.compose.runtime.DisposableEffect
+import androidx.compose.runtime.remember
import androidx.compose.ui.platform.LocalContext
-import androidx.compose.ui.platform.LocalLifecycleOwner
-import androidx.lifecycle.Lifecycle
-import androidx.lifecycle.LifecycleEventObserver
+import com.android.settingslib.spa.framework.compose.LifecycleEffect
/**
* A [BroadcastReceiver] which registered when on start and unregistered when on stop.
@@ -39,28 +37,22 @@
onReceive: (Intent) -> Unit,
) {
val context = LocalContext.current
- val lifecycleOwner = LocalLifecycleOwner.current
- DisposableEffect(lifecycleOwner) {
- val broadcastReceiver = object : BroadcastReceiver() {
+ val broadcastReceiver = remember {
+ object : BroadcastReceiver() {
override fun onReceive(context: Context, intent: Intent) {
onReceive(intent)
}
}
- val observer = LifecycleEventObserver { _, event ->
- if (event == Lifecycle.Event.ON_START) {
- context.registerReceiverAsUser(
- broadcastReceiver, userHandle, intentFilter, null, null
- )
- onStart()
- } else if (event == Lifecycle.Event.ON_STOP) {
- context.unregisterReceiver(broadcastReceiver)
- }
- }
-
- lifecycleOwner.lifecycle.addObserver(observer)
-
- onDispose {
- lifecycleOwner.lifecycle.removeObserver(observer)
- }
}
+ LifecycleEffect(
+ onStart = {
+ context.registerReceiverAsUser(
+ broadcastReceiver, userHandle, intentFilter, null, null
+ )
+ onStart()
+ },
+ onStop = {
+ context.unregisterReceiver(broadcastReceiver)
+ },
+ )
}
diff --git a/packages/SettingsLib/SpaPrivileged/src/com/android/settingslib/spaprivileged/model/app/AppOpsController.kt b/packages/SettingsLib/SpaPrivileged/src/com/android/settingslib/spaprivileged/model/app/AppOpsController.kt
index 6cd6e95..171903f 100644
--- a/packages/SettingsLib/SpaPrivileged/src/com/android/settingslib/spaprivileged/model/app/AppOpsController.kt
+++ b/packages/SettingsLib/SpaPrivileged/src/com/android/settingslib/spaprivileged/model/app/AppOpsController.kt
@@ -17,6 +17,7 @@
package com.android.settingslib.spaprivileged.model.app
import android.app.AppOpsManager.MODE_ALLOWED
+import android.app.AppOpsManager.MODE_ERRORED
import android.app.AppOpsManager.Mode
import android.content.Context
import android.content.pm.ApplicationInfo
@@ -39,7 +40,7 @@
context: Context,
private val app: ApplicationInfo,
private val op: Int,
- private val modeForNotAllowed: Int,
+ private val modeForNotAllowed: Int = MODE_ERRORED,
private val setModeByUid: Boolean = false,
) : IAppOpsController {
private val appOpsManager = context.appOpsManager
diff --git a/packages/SettingsLib/SpaPrivileged/src/com/android/settingslib/spaprivileged/model/app/AppRepository.kt b/packages/SettingsLib/SpaPrivileged/src/com/android/settingslib/spaprivileged/model/app/AppRepository.kt
index 90710db..18b20733 100644
--- a/packages/SettingsLib/SpaPrivileged/src/com/android/settingslib/spaprivileged/model/app/AppRepository.kt
+++ b/packages/SettingsLib/SpaPrivileged/src/com/android/settingslib/spaprivileged/model/app/AppRepository.kt
@@ -19,9 +19,11 @@
import android.content.Context
import android.content.pm.ApplicationInfo
import android.graphics.drawable.Drawable
+import android.os.UserManager
import androidx.compose.runtime.Composable
import androidx.compose.runtime.State
import androidx.compose.runtime.produceState
+import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.res.stringResource
import com.android.settingslib.Utils
import com.android.settingslib.spa.framework.compose.rememberContext
@@ -36,12 +38,24 @@
fun loadLabel(app: ApplicationInfo): String
@Composable
- fun produceLabel(app: ApplicationInfo) =
- produceState(initialValue = stringResource(R.string.summary_placeholder), app) {
+ fun produceLabel(app: ApplicationInfo, isClonedAppPage: Boolean = false): State<String> {
+ val context = LocalContext.current
+ return produceState(initialValue = stringResource(R.string.summary_placeholder), app) {
withContext(Dispatchers.IO) {
- value = loadLabel(app)
+ if (isClonedAppPage || isCloneApp(context, app)) {
+ value = context.getString(R.string.cloned_app_info_label, loadLabel(app))
+ } else {
+ value = loadLabel(app)
+ }
}
}
+ }
+
+ private fun isCloneApp(context: Context, app: ApplicationInfo): Boolean {
+ val userManager = context.getSystemService(UserManager::class.java)!!
+ val userInfo = userManager.getUserInfo(app.userId)
+ return userInfo != null && userInfo.isCloneProfile
+ }
@Composable
fun produceIcon(app: ApplicationInfo): State<Drawable?>
diff --git a/packages/SettingsLib/SpaPrivileged/src/com/android/settingslib/spaprivileged/template/app/AppInfo.kt b/packages/SettingsLib/SpaPrivileged/src/com/android/settingslib/spaprivileged/template/app/AppInfo.kt
index 16ca70f..602df54 100644
--- a/packages/SettingsLib/SpaPrivileged/src/com/android/settingslib/spaprivileged/template/app/AppInfo.kt
+++ b/packages/SettingsLib/SpaPrivileged/src/com/android/settingslib/spaprivileged/template/app/AppInfo.kt
@@ -43,7 +43,7 @@
class AppInfoProvider(private val packageInfo: PackageInfo) {
@Composable
- fun AppInfo(displayVersion: Boolean = false) {
+ fun AppInfo(displayVersion: Boolean = false, isClonedAppPage: Boolean = false) {
Column(
modifier = Modifier
.fillMaxWidth()
@@ -57,7 +57,7 @@
Box(modifier = Modifier.padding(SettingsDimension.itemPaddingAround)) {
AppIcon(app = app, size = SettingsDimension.appIconInfoSize)
}
- AppLabel(app)
+ AppLabel(app, isClonedAppPage)
InstallType(app)
if (displayVersion) AppVersion()
}
@@ -99,7 +99,7 @@
}
@Composable
-internal fun AppLabel(app: ApplicationInfo) {
+internal fun AppLabel(app: ApplicationInfo, isClonedAppPage: Boolean = false) {
val appRepository = rememberAppRepository()
- SettingsTitle(title = appRepository.produceLabel(app), useMediumWeight = true)
+ SettingsTitle(title = appRepository.produceLabel(app, isClonedAppPage), useMediumWeight = true)
}
diff --git a/packages/SettingsLib/SpaPrivileged/src/com/android/settingslib/spaprivileged/template/app/AppOpPermissionAppList.kt b/packages/SettingsLib/SpaPrivileged/src/com/android/settingslib/spaprivileged/template/app/AppOpPermissionAppList.kt
index 53af25b..338b16d 100644
--- a/packages/SettingsLib/SpaPrivileged/src/com/android/settingslib/spaprivileged/template/app/AppOpPermissionAppList.kt
+++ b/packages/SettingsLib/SpaPrivileged/src/com/android/settingslib/spaprivileged/template/app/AppOpPermissionAppList.kt
@@ -66,7 +66,7 @@
* If true, it uses getAppOpPermissionPackages() to fetch bits to decide whether the permission
* is requested.
*/
- open val permissionHasAppopFlag: Boolean = true
+ open val permissionHasAppOpFlag: Boolean = true
open val modeForNotAllowed: Int = MODE_ERRORED
@@ -105,7 +105,7 @@
}
override fun transform(userIdFlow: Flow<Int>, appListFlow: Flow<List<ApplicationInfo>>) =
- if (permissionHasAppopFlag) {
+ if (permissionHasAppOpFlag) {
userIdFlow
.map { userId -> packageManagers.getAppOpPermissionPackages(userId, permission) }
.combine(appListFlow) { packageNames, appList ->
diff --git a/packages/SettingsLib/SpaPrivileged/tests/src/com/android/settingslib/spaprivileged/model/app/AppOpsControllerTest.kt b/packages/SettingsLib/SpaPrivileged/tests/src/com/android/settingslib/spaprivileged/model/app/AppOpsControllerTest.kt
index 53e52d0..fd2ceb7 100644
--- a/packages/SettingsLib/SpaPrivileged/tests/src/com/android/settingslib/spaprivileged/model/app/AppOpsControllerTest.kt
+++ b/packages/SettingsLib/SpaPrivileged/tests/src/com/android/settingslib/spaprivileged/model/app/AppOpsControllerTest.kt
@@ -19,6 +19,7 @@
import android.app.AppOpsManager
import android.app.AppOpsManager.MODE_ALLOWED
import android.app.AppOpsManager.MODE_ERRORED
+import android.app.AppOpsManager.MODE_IGNORED
import android.content.Context
import android.content.pm.ApplicationInfo
import androidx.test.core.app.ApplicationProvider
@@ -56,7 +57,6 @@
context = context,
app = APP,
op = OP,
- modeForNotAllowed = MODE_ERRORED
)
controller.setAllowed(true)
@@ -71,7 +71,6 @@
context = context,
app = APP,
op = OP,
- modeForNotAllowed = MODE_ERRORED
)
controller.setAllowed(false)
@@ -80,14 +79,28 @@
}
@Test
+ fun setAllowed_setToFalseWithModeForNotAllowed() {
+ val controller =
+ AppOpsController(
+ context = context,
+ app = APP,
+ op = OP,
+ modeForNotAllowed = MODE_IGNORED,
+ )
+
+ controller.setAllowed(false)
+
+ verify(appOpsManager).setMode(OP, APP.uid, APP.packageName, MODE_IGNORED)
+ }
+
+ @Test
fun setAllowed_setToTrueByUid() {
val controller =
AppOpsController(
context = context,
app = APP,
op = OP,
- modeForNotAllowed = MODE_ERRORED,
- setModeByUid = true
+ setModeByUid = true,
)
controller.setAllowed(true)
@@ -102,8 +115,7 @@
context = context,
app = APP,
op = OP,
- modeForNotAllowed = MODE_ERRORED,
- setModeByUid = true
+ setModeByUid = true,
)
controller.setAllowed(false)
@@ -120,7 +132,6 @@
context = context,
app = APP,
op = OP,
- modeForNotAllowed = MODE_ERRORED
)
val mode = controller.getMode()
diff --git a/packages/SettingsLib/SpaPrivileged/tests/src/com/android/settingslib/spaprivileged/template/app/AppOpPermissionAppListTest.kt b/packages/SettingsLib/SpaPrivileged/tests/src/com/android/settingslib/spaprivileged/template/app/AppOpPermissionAppListTest.kt
index da765ba..af59a55 100644
--- a/packages/SettingsLib/SpaPrivileged/tests/src/com/android/settingslib/spaprivileged/template/app/AppOpPermissionAppListTest.kt
+++ b/packages/SettingsLib/SpaPrivileged/tests/src/com/android/settingslib/spaprivileged/template/app/AppOpPermissionAppListTest.kt
@@ -314,7 +314,6 @@
override val appOp = AppOpsManager.OP_MANAGE_MEDIA
override val permission = PERMISSION
- override val permissionHasAppopFlag = true
override var broaderPermission: String? = null
override var setModeByUid = false
diff --git a/packages/SettingsLib/src/com/android/settingslib/RestrictedLockUtilsInternal.java b/packages/SettingsLib/src/com/android/settingslib/RestrictedLockUtilsInternal.java
index 5610ac4..78b7810 100644
--- a/packages/SettingsLib/src/com/android/settingslib/RestrictedLockUtilsInternal.java
+++ b/packages/SettingsLib/src/com/android/settingslib/RestrictedLockUtilsInternal.java
@@ -27,7 +27,6 @@
import android.app.admin.DevicePolicyManager;
import android.content.ComponentName;
import android.content.Context;
-import android.content.Intent;
import android.content.pm.IPackageManager;
import android.content.pm.PackageManager;
import android.content.pm.UserInfo;
@@ -37,7 +36,6 @@
import android.os.RemoteException;
import android.os.UserHandle;
import android.os.UserManager;
-import android.provider.Settings;
import android.text.SpannableStringBuilder;
import android.text.Spanned;
import android.text.style.ForegroundColorSpan;
@@ -754,26 +752,6 @@
}
/**
- * Show restricted setting dialog.
- */
- @RequiresApi(Build.VERSION_CODES.TIRAMISU)
- public static void sendShowRestrictedSettingDialogIntent(Context context,
- String packageName, int uid) {
- final Intent intent = getShowRestrictedSettingsIntent(packageName, uid);
- context.startActivity(intent);
- }
-
- /**
- * Get restricted settings dialog intent.
- */
- private static Intent getShowRestrictedSettingsIntent(String packageName, int uid) {
- final Intent intent = new Intent(Settings.ACTION_SHOW_RESTRICTED_SETTING_DIALOG);
- intent.putExtra(Intent.EXTRA_PACKAGE_NAME, packageName);
- intent.putExtra(Intent.EXTRA_UID, uid);
- return intent;
- }
-
- /**
* Static {@link LockPatternUtils} and {@link DevicePolicyManager} wrapper for testing purposes.
* {@link LockPatternUtils} is an internal API not supported by robolectric.
* {@link DevicePolicyManager} has a {@code getProfileParent} not yet suppored by robolectric.
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/widget/IllustrationPreferenceTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/widget/IllustrationPreferenceTest.java
index 29549d9..103512d 100644
--- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/widget/IllustrationPreferenceTest.java
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/widget/IllustrationPreferenceTest.java
@@ -61,6 +61,8 @@
private PreferenceViewHolder mViewHolder;
private FrameLayout mMiddleGroundLayout;
private final Context mContext = ApplicationProvider.getApplicationContext();
+ private IllustrationPreference.OnBindListener mOnBindListener;
+ private LottieAnimationView mOnBindListenerAnimationView;
@Before
public void setUp() {
@@ -82,6 +84,12 @@
final AttributeSet attributeSet = Robolectric.buildAttributeSet().build();
mPreference = new IllustrationPreference(mContext, attributeSet);
+ mOnBindListener = new IllustrationPreference.OnBindListener() {
+ @Override
+ public void onBind(LottieAnimationView animationView) {
+ mOnBindListenerAnimationView = animationView;
+ }
+ };
}
@Test
@@ -186,4 +194,25 @@
assertThat(mBackgroundView.getMaxHeight()).isEqualTo(restrictedHeight);
assertThat(mAnimationView.getMaxHeight()).isEqualTo(restrictedHeight);
}
+
+ @Test
+ public void setOnBindListener_isNotified() {
+ mOnBindListenerAnimationView = null;
+ mPreference.setOnBindListener(mOnBindListener);
+
+ mPreference.onBindViewHolder(mViewHolder);
+
+ assertThat(mOnBindListenerAnimationView).isNotNull();
+ assertThat(mOnBindListenerAnimationView).isEqualTo(mAnimationView);
+ }
+
+ @Test
+ public void setOnBindListener_notNotified() {
+ mOnBindListenerAnimationView = null;
+ mPreference.setOnBindListener(null);
+
+ mPreference.onBindViewHolder(mViewHolder);
+
+ assertThat(mOnBindListenerAnimationView).isNull();
+ }
}
diff --git a/packages/SettingsProvider/src/android/provider/settings/backup/GlobalSettings.java b/packages/SettingsProvider/src/android/provider/settings/backup/GlobalSettings.java
index aa6aaaf..ae06193 100644
--- a/packages/SettingsProvider/src/android/provider/settings/backup/GlobalSettings.java
+++ b/packages/SettingsProvider/src/android/provider/settings/backup/GlobalSettings.java
@@ -97,6 +97,7 @@
Settings.Global.Wearable.GESTURE_TOUCH_AND_HOLD_WATCH_FACE_ENABLED,
Settings.Global.Wearable.BATTERY_SAVER_MODE,
Settings.Global.Wearable.WEAR_ACTIVITY_AUTO_RESUME_TIMEOUT_MS,
- Settings.Global.Wearable.WEAR_ACTIVITY_AUTO_RESUME_TIMEOUT_SET_BY_USER
+ Settings.Global.Wearable.WEAR_ACTIVITY_AUTO_RESUME_TIMEOUT_SET_BY_USER,
+ Settings.Global.Wearable.DYNAMIC_COLOR_THEME_ENABLED,
};
}
diff --git a/packages/SettingsProvider/src/android/provider/settings/backup/SecureSettings.java b/packages/SettingsProvider/src/android/provider/settings/backup/SecureSettings.java
index 90874bb..06c3476 100644
--- a/packages/SettingsProvider/src/android/provider/settings/backup/SecureSettings.java
+++ b/packages/SettingsProvider/src/android/provider/settings/backup/SecureSettings.java
@@ -123,7 +123,7 @@
Settings.Secure.FINGERPRINT_SIDE_FPS_BP_POWER_WINDOW,
Settings.Secure.FINGERPRINT_SIDE_FPS_ENROLL_TAP_WINDOW,
Settings.Secure.FINGERPRINT_SIDE_FPS_AUTH_DOWNTIME,
- Settings.Secure.SFPS_REQUIRE_SCREEN_ON_TO_AUTH_ENABLED,
+ Settings.Secure.SFPS_PERFORMANT_AUTH_ENABLED,
Settings.Secure.ACTIVE_UNLOCK_ON_WAKE,
Settings.Secure.ACTIVE_UNLOCK_ON_UNLOCK_INTENT,
Settings.Secure.ACTIVE_UNLOCK_ON_BIOMETRIC_FAIL,
diff --git a/packages/SettingsProvider/src/android/provider/settings/validators/GlobalSettingsValidators.java b/packages/SettingsProvider/src/android/provider/settings/validators/GlobalSettingsValidators.java
index 2b0d837..a1a9e8c 100644
--- a/packages/SettingsProvider/src/android/provider/settings/validators/GlobalSettingsValidators.java
+++ b/packages/SettingsProvider/src/android/provider/settings/validators/GlobalSettingsValidators.java
@@ -352,5 +352,6 @@
String.valueOf(Global.Wearable.EARLY_UPDATES_STATUS_SKIPPED),
String.valueOf(Global.Wearable.EARLY_UPDATES_STATUS_ABORTED),
}));
+ VALIDATORS.put(Global.Wearable.DYNAMIC_COLOR_THEME_ENABLED, BOOLEAN_VALIDATOR);
}
}
diff --git a/packages/SettingsProvider/src/android/provider/settings/validators/SecureSettingsValidators.java b/packages/SettingsProvider/src/android/provider/settings/validators/SecureSettingsValidators.java
index 62f4c41..d72d4d5 100644
--- a/packages/SettingsProvider/src/android/provider/settings/validators/SecureSettingsValidators.java
+++ b/packages/SettingsProvider/src/android/provider/settings/validators/SecureSettingsValidators.java
@@ -178,7 +178,7 @@
VALIDATORS.put(Secure.FINGERPRINT_SIDE_FPS_ENROLL_TAP_WINDOW,
NON_NEGATIVE_INTEGER_VALIDATOR);
VALIDATORS.put(Secure.FINGERPRINT_SIDE_FPS_AUTH_DOWNTIME, NON_NEGATIVE_INTEGER_VALIDATOR);
- VALIDATORS.put(Secure.SFPS_REQUIRE_SCREEN_ON_TO_AUTH_ENABLED, BOOLEAN_VALIDATOR);
+ VALIDATORS.put(Secure.SFPS_PERFORMANT_AUTH_ENABLED, BOOLEAN_VALIDATOR);
VALIDATORS.put(Secure.SHOW_MEDIA_WHEN_BYPASSING, BOOLEAN_VALIDATOR);
VALIDATORS.put(Secure.FACE_UNLOCK_APP_ENABLED, BOOLEAN_VALIDATOR);
VALIDATORS.put(Secure.FACE_UNLOCK_ALWAYS_REQUIRE_CONFIRMATION, BOOLEAN_VALIDATOR);
diff --git a/packages/Shell/AndroidManifest.xml b/packages/Shell/AndroidManifest.xml
index 75e59c7..d716b32 100644
--- a/packages/Shell/AndroidManifest.xml
+++ b/packages/Shell/AndroidManifest.xml
@@ -170,6 +170,7 @@
<uses-permission android:name="android.permission.SET_ORIENTATION" />
<uses-permission android:name="android.permission.INSTALL_PACKAGES" />
<uses-permission android:name="android.permission.INSTALL_PACKAGE_UPDATES" />
+ <uses-permission android:name="android.permission.ENFORCE_UPDATE_OWNERSHIP" />
<uses-permission android:name="android.permission.INSTALL_DPC_PACKAGES" />
<uses-permission android:name="com.android.permission.USE_INSTALLER_V2" />
<uses-permission android:name="android.permission.INSTALL_TEST_ONLY_PACKAGE" />
@@ -793,6 +794,9 @@
<uses-permission android:name="android.permission.FOREGROUND_SERVICE"/>
<uses-permission android:name="android.permission.FOREGROUND_SERVICE_SYSTEM_EXEMPTED"/>
+ <!-- Permissions required for CTS test - CtsBroadcastRadioTestCases -->
+ <uses-permission android:name="android.permission.ACCESS_BROADCAST_RADIO" />
+
<application android:label="@string/app_label"
android:theme="@android:style/Theme.DeviceDefault.DayNight"
android:defaultToDeviceProtectedStorage="true"
diff --git a/packages/SystemUI/AndroidManifest.xml b/packages/SystemUI/AndroidManifest.xml
index 2c9dad9..4e620cd1 100644
--- a/packages/SystemUI/AndroidManifest.xml
+++ b/packages/SystemUI/AndroidManifest.xml
@@ -180,6 +180,9 @@
<!-- Doze mode temp whitelisting for notification dispatching. -->
<uses-permission android:name="android.permission.CHANGE_DEVICE_IDLE_TEMP_WHITELIST" />
+ <!-- Tag user-initiated PendingIntent invocations as "interactive" when appropriate -->
+ <uses-permission android:name="android.permission.COMPONENT_OPTION_INTERACTIVE" />
+
<!-- Listen for keyboard attachment / detachment -->
<uses-permission android:name="android.permission.TABLET_MODE" />
@@ -293,7 +296,7 @@
<queries>
<intent>
- <action android:name="android.intent.action.NOTES" />
+ <action android:name="android.intent.action.CREATE_NOTE" />
</intent>
</queries>
@@ -412,7 +415,6 @@
<service android:name=".screenshot.ScreenshotCrossProfileService"
android:permission="com.android.systemui.permission.SELF"
- android:process=":screenshot_cross_profile"
android:exported="false" />
<service android:name=".screenrecord.RecordingService"
diff --git a/packages/SystemUI/TEST_MAPPING b/packages/SystemUI/TEST_MAPPING
index b22195a..f92625b 100644
--- a/packages/SystemUI/TEST_MAPPING
+++ b/packages/SystemUI/TEST_MAPPING
@@ -32,19 +32,18 @@
}
]
},
-// Disable until can pass: b/259124654
-// {
-// // TODO(b/251476085): Consider merging with SystemUIGoogleScreenshotTests (in U+)
-// "name": "SystemUIGoogleBiometricsScreenshotTests",
-// "options": [
-// {
-// "exclude-annotation": "org.junit.Ignore"
-// },
-// {
-// "exclude-annotation": "androidx.test.filters.FlakyTest"
-// }
-// ]
-// },
+ {
+ // TODO(b/251476085): Consider merging with SystemUIGoogleScreenshotTests (in U+)
+ "name": "SystemUIGoogleBiometricsScreenshotTests",
+ "options": [
+ {
+ "exclude-annotation": "org.junit.Ignore"
+ },
+ {
+ "exclude-annotation": "androidx.test.filters.FlakyTest"
+ }
+ ]
+ },
{
// Permission indicators
"name": "CtsPermission4TestCases",
diff --git a/packages/SystemUI/accessibility/accessibilitymenu/Android.bp b/packages/SystemUI/accessibility/accessibilitymenu/Android.bp
index a494f5e..0b1a3e2 100644
--- a/packages/SystemUI/accessibility/accessibilitymenu/Android.bp
+++ b/packages/SystemUI/accessibility/accessibilitymenu/Android.bp
@@ -20,6 +20,17 @@
android_app {
name: "AccessibilityMenu",
+
+ static_libs: [
+ "androidx.coordinatorlayout_coordinatorlayout",
+ "androidx.core_core",
+ "androidx.viewpager_viewpager",
+ ],
+
+ uses_libs: [
+ "org.apache.http.legacy",
+ ],
+
srcs: [
"src/**/*.java",
],
diff --git a/packages/SystemUI/accessibility/accessibilitymenu/res/color/footer_icon_tint_color.xml b/packages/SystemUI/accessibility/accessibilitymenu/res/color/footer_icon_tint_color.xml
new file mode 100644
index 0000000..c89e4c3
--- /dev/null
+++ b/packages/SystemUI/accessibility/accessibilitymenu/res/color/footer_icon_tint_color.xml
@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="utf-8"?>
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+ <item android:state_enabled="false"
+ android:color="@color/footer_icon_disabled_color" /> <!-- disabled -->
+ <item android:color="@color/footer_icon_enabled_color" /> <!-- default -->
+</selector>
\ No newline at end of file
diff --git a/packages/SystemUI/accessibility/accessibilitymenu/res/drawable/a11ymenu_intro.png b/packages/SystemUI/accessibility/accessibilitymenu/res/drawable/a11ymenu_intro.png
new file mode 100644
index 0000000..6149ee4
--- /dev/null
+++ b/packages/SystemUI/accessibility/accessibilitymenu/res/drawable/a11ymenu_intro.png
Binary files differ
diff --git a/packages/SystemUI/accessibility/accessibilitymenu/res/drawable/footer_button_background_left.xml b/packages/SystemUI/accessibility/accessibilitymenu/res/drawable/footer_button_background_left.xml
new file mode 100644
index 0000000..5ff245d
--- /dev/null
+++ b/packages/SystemUI/accessibility/accessibilitymenu/res/drawable/footer_button_background_left.xml
@@ -0,0 +1,13 @@
+<?xml version="1.0" encoding="utf-8"?>
+<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
+
+ <item>
+ <ripple
+ android:color="@color/ripple_material_color">
+ <item android:id="@android:id/mask">
+ <color android:color="@color/overlay_bg_color"/>
+ </item>
+ </ripple>
+ </item>
+
+</layer-list>
\ No newline at end of file
diff --git a/packages/SystemUI/accessibility/accessibilitymenu/res/drawable/footer_button_background_right.xml b/packages/SystemUI/accessibility/accessibilitymenu/res/drawable/footer_button_background_right.xml
new file mode 100644
index 0000000..5ff245d
--- /dev/null
+++ b/packages/SystemUI/accessibility/accessibilitymenu/res/drawable/footer_button_background_right.xml
@@ -0,0 +1,13 @@
+<?xml version="1.0" encoding="utf-8"?>
+<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
+
+ <item>
+ <ripple
+ android:color="@color/ripple_material_color">
+ <item android:id="@android:id/mask">
+ <color android:color="@color/overlay_bg_color"/>
+ </item>
+ </ripple>
+ </item>
+
+</layer-list>
\ No newline at end of file
diff --git a/packages/SystemUI/accessibility/accessibilitymenu/res/drawable/ic_a11y_menu_round.xml b/packages/SystemUI/accessibility/accessibilitymenu/res/drawable/ic_a11y_menu_round.xml
new file mode 100644
index 0000000..a2eaf95
--- /dev/null
+++ b/packages/SystemUI/accessibility/accessibilitymenu/res/drawable/ic_a11y_menu_round.xml
@@ -0,0 +1,20 @@
+<!--
+ ~ 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.
+ -->
+
+<vector android:height="108dp" android:viewportHeight="24"
+ android:viewportWidth="24" android:width="108dp" xmlns:android="http://schemas.android.com/apk/res/android">
+ <path android:fillColor="#ffffff" android:fillType="evenOdd" android:pathData="M7.875,10.625C7.1188,10.625 6.5,11.2437 6.5,12C6.5,12.7562 7.1188,13.375 7.875,13.375C8.6313,13.375 9.25,12.7562 9.25,12C9.25,11.2437 8.6313,10.625 7.875,10.625ZM16.125,10.625C15.3687,10.625 14.75,11.2437 14.75,12C14.75,12.7562 15.3687,13.375 16.125,13.375C16.8813,13.375 17.5,12.7562 17.5,12C17.5,11.2437 16.8813,10.625 16.125,10.625ZM10.625,12C10.625,11.2437 11.2438,10.625 12,10.625C12.7563,10.625 13.375,11.2437 13.375,12C13.375,12.7562 12.7563,13.375 12,13.375C11.2438,13.375 10.625,12.7562 10.625,12Z"/>
+</vector>
diff --git a/packages/SystemUI/accessibility/accessibilitymenu/res/drawable/ic_add_32dp.xml b/packages/SystemUI/accessibility/accessibilitymenu/res/drawable/ic_add_32dp.xml
new file mode 100644
index 0000000..7e1262c
--- /dev/null
+++ b/packages/SystemUI/accessibility/accessibilitymenu/res/drawable/ic_add_32dp.xml
@@ -0,0 +1,5 @@
+<vector android:height="32dp" android:tint="#FFFFFF"
+ android:viewportHeight="24.0" android:viewportWidth="24.0"
+ android:width="32dp" xmlns:android="http://schemas.android.com/apk/res/android">
+ <path android:fillColor="#FF000000" android:pathData="M19,13h-6v6h-2v-6H5v-2h6V5h2v6h6v2z"/>
+</vector>
diff --git a/packages/SystemUI/accessibility/accessibilitymenu/res/drawable/ic_arrow_back_24dp.xml b/packages/SystemUI/accessibility/accessibilitymenu/res/drawable/ic_arrow_back_24dp.xml
new file mode 100644
index 0000000..f6af270
--- /dev/null
+++ b/packages/SystemUI/accessibility/accessibilitymenu/res/drawable/ic_arrow_back_24dp.xml
@@ -0,0 +1,9 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="@dimen/footer_arrow_length"
+ android:height="@dimen/footer_arrow_length"
+ android:viewportWidth="24.0"
+ android:viewportHeight="24.0">
+ <path
+ android:fillColor="@color/footer_icon_color"
+ android:pathData="M20,11H7.83l5.59,-5.59L12,4l-8,8 8,8 1.41,-1.41L7.83,13H20v-2z"/>
+</vector>
diff --git a/packages/SystemUI/accessibility/accessibilitymenu/res/drawable/ic_arrow_forward_24dp.xml b/packages/SystemUI/accessibility/accessibilitymenu/res/drawable/ic_arrow_forward_24dp.xml
new file mode 100644
index 0000000..2f7b632
--- /dev/null
+++ b/packages/SystemUI/accessibility/accessibilitymenu/res/drawable/ic_arrow_forward_24dp.xml
@@ -0,0 +1,9 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="@dimen/footer_arrow_length"
+ android:height="@dimen/footer_arrow_length"
+ android:viewportWidth="24.0"
+ android:viewportHeight="24.0">
+ <path
+ android:fillColor="@color/footer_icon_color"
+ android:pathData="M12,4l-1.41,1.41L16.17,11H4v2h12.17l-5.58,5.59L12,20l8,-8z"/>
+</vector>
diff --git a/packages/SystemUI/accessibility/accessibilitymenu/res/drawable/ic_logo_a11y_menu.xml b/packages/SystemUI/accessibility/accessibilitymenu/res/drawable/ic_logo_a11y_menu.xml
new file mode 100644
index 0000000..79e0e08d
--- /dev/null
+++ b/packages/SystemUI/accessibility/accessibilitymenu/res/drawable/ic_logo_a11y_menu.xml
@@ -0,0 +1,33 @@
+<vector android:height="48dp" android:viewportHeight="192.0"
+ android:viewportWidth="192.0" android:width="48dp"
+ xmlns:aapt="http://schemas.android.com/aapt" xmlns:android="http://schemas.android.com/apk/res/android">
+ <path android:fillColor="#34a853" android:pathData="M37.14,173.74l-28.53,-90a14.53,14.53 0,0 1,5 -15.63L87.15,11a14.21,14.21 0,0 1,17.61 0.12l73.81,58.94a14.53,14.53 0,0 1,4.8 15.57l-28.48,88.18A14.32,14.32 0,0 1,141.22 184H50.84A14.33,14.33 0,0 1,37.14 173.74Z"/>
+ <path android:pathData="M137.61,94.07l-17,17 -17,-17 -17,17L70.3,94.72l-17,17L125.66,184h15.56a14.32,14.32 0,0 0,13.67 -10.19l15.25,-47.21Z">
+ <aapt:attr name="android:fillColor">
+ <gradient android:endX="27152.64"
+ android:endY="32745.600000000002"
+ android:startX="20910.72"
+ android:startY="21934.079999999998" android:type="linear">
+ <item android:color="#33263238" android:offset="0.0"/>
+ <item android:color="#11205432" android:offset="0.47"/>
+ <item android:color="#051E6130" android:offset="1.0"/>
+ </gradient>
+ </aapt:attr>
+ </path>
+ <path android:fillAlpha="0.2" android:fillColor="#263238" android:pathData="M50.14,100.11a12,12 0,1 1,11.39 15.77,11.72 11.72,0 0,1 -5,-1.1l-3.41,-3.4ZM129.4,91.88a12,12 0,1 1,-12 12A12,12 0,0 1,129.4 91.88ZM95.4,91.88a12,12 0,1 1,-12 12A12,12 0,0 1,95.42 91.88Z"/>
+ <path android:fillColor="#fff"
+ android:pathData="M61.53,90.88a12,12 0,1 1,-12 12A12,12 0,0 1,61.53 90.88ZM129.41,90.88a12,12 0,1 1,-12 12A12,12 0,0 1,129.41 90.88ZM95.41,90.88a12,12 0,1 1,-12 12A12,12 0,0 1,95.42 90.88Z"
+ android:strokeAlpha="0" android:strokeColor="#000"
+ android:strokeLineCap="round" android:strokeLineJoin="round" android:strokeWidth="0.5"/>
+ <path android:fillAlpha="0.2" android:fillColor="#263238" android:pathData="M184,80.91a14.33,14.33 0,0 1,-0.63 4.7l-28.48,88.18A14.33,14.33 0,0 1,141.21 184H50.84a14.33,14.33 0,0 1,-13.7 -10.26l-28.53,-90A14.49,14.49 0,0 1,8 79.11a14.3,14.3 0,0 0,0.61 3.64l28.53,90A14.33,14.33 0,0 0,50.84 183h90.37a14.33,14.33 0,0 0,13.67 -10.19l28.48,-88.18A14.79,14.79 0,0 0,184 80.91Z"/>
+ <path android:fillAlpha="0.2" android:fillColor="#fff" android:pathData="M184,81.89A14.46,14.46 0,0 0,178.57 71L104.76,12.1A14.21,14.21 0,0 0,87.15 12L13.58,69.12A14.5,14.5 0,0 0,8 80.09a14.5,14.5 0,0 1,5.57 -12L87.15,11a14.21,14.21 0,0 1,17.61 0.12L178.57,70A14.48,14.48 0,0 1,184 81.89Z"/>
+ <path android:pathData="M37.14,173.74l-28.53,-90a14.53,14.53 0,0 1,5 -15.63L87.15,11a14.21,14.21 0,0 1,17.61 0.12l73.81,58.94a14.53,14.53 0,0 1,4.8 15.57l-28.48,88.18A14.32,14.32 0,0 1,141.22 184H50.84A14.33,14.33 0,0 1,37.14 173.74Z"/>
+ <adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
+ <background android:drawable="@color/colorAccessibilityMenuIcon" />
+ <foreground>
+ <inset
+ android:drawable="@drawable/ic_a11y_menu_round"
+ android:inset="21.88%" />
+ </foreground>
+ </adaptive-icon>
+</vector>
diff --git a/packages/SystemUI/accessibility/accessibilitymenu/res/drawable/ic_logo_assistant_32dp.xml b/packages/SystemUI/accessibility/accessibilitymenu/res/drawable/ic_logo_assistant_32dp.xml
new file mode 100644
index 0000000..ebeebf8
--- /dev/null
+++ b/packages/SystemUI/accessibility/accessibilitymenu/res/drawable/ic_logo_assistant_32dp.xml
@@ -0,0 +1,8 @@
+<vector android:height="32dp"
+ android:viewportHeight="192.0" android:viewportWidth="192.0"
+ android:width="32dp" xmlns:android="http://schemas.android.com/apk/res/android">
+ <path android:fillColor="#34A853" android:pathData="M172,60m-12,0a12,12 0,1 1,24 0a12,12 0,1 1,-24 0"/>
+ <path android:fillColor="#EA4335" android:pathData="M136,88m-24,0a24,24 0,1 1,48 0a24,24 0,1 1,-48 0"/>
+ <path android:fillColor="#FBBC05" android:pathData="M136,148m-28,0a28,28 0,1 1,56 0a28,28 0,1 1,-56 0"/>
+ <path android:fillColor="#4285F4" android:pathData="M56,64m-48,0a48,48 0,1 1,96 0a48,48 0,1 1,-96 0"/>
+</vector>
diff --git a/packages/SystemUI/accessibility/accessibilitymenu/res/drawable/shadow_0deg.9.png b/packages/SystemUI/accessibility/accessibilitymenu/res/drawable/shadow_0deg.9.png
new file mode 100644
index 0000000..b0d1696
--- /dev/null
+++ b/packages/SystemUI/accessibility/accessibilitymenu/res/drawable/shadow_0deg.9.png
Binary files differ
diff --git a/packages/SystemUI/accessibility/accessibilitymenu/res/drawable/shadow_270deg.9.png b/packages/SystemUI/accessibility/accessibilitymenu/res/drawable/shadow_270deg.9.png
new file mode 100644
index 0000000..b777ffe
--- /dev/null
+++ b/packages/SystemUI/accessibility/accessibilitymenu/res/drawable/shadow_270deg.9.png
Binary files differ
diff --git a/packages/SystemUI/accessibility/accessibilitymenu/res/drawable/shadow_90deg.9.png b/packages/SystemUI/accessibility/accessibilitymenu/res/drawable/shadow_90deg.9.png
new file mode 100644
index 0000000..998bd90
--- /dev/null
+++ b/packages/SystemUI/accessibility/accessibilitymenu/res/drawable/shadow_90deg.9.png
Binary files differ
diff --git a/packages/SystemUI/accessibility/accessibilitymenu/res/drawable/view_background.xml b/packages/SystemUI/accessibility/accessibilitymenu/res/drawable/view_background.xml
new file mode 100644
index 0000000..c1f76f37
--- /dev/null
+++ b/packages/SystemUI/accessibility/accessibilitymenu/res/drawable/view_background.xml
@@ -0,0 +1,5 @@
+<shape
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:shape="rectangle">
+ <solid android:color="@color/overlay_bg_color" />
+</shape>
diff --git a/packages/SystemUI/accessibility/accessibilitymenu/res/layout/footerlayout_switch_page.xml b/packages/SystemUI/accessibility/accessibilitymenu/res/layout/footerlayout_switch_page.xml
new file mode 100644
index 0000000..658c03b
--- /dev/null
+++ b/packages/SystemUI/accessibility/accessibilitymenu/res/layout/footerlayout_switch_page.xml
@@ -0,0 +1,59 @@
+<?xml version="1.0" encoding="utf-8"?>
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:id="@+id/footerlayout"
+ android:layout_width="match_parent"
+ android:layout_height="@dimen/grid_item_btn_view_height"
+ android:layout_alignParentBottom="true"
+ android:layout_gravity="bottom"
+ android:layoutDirection="ltr"
+ android:orientation="vertical"
+ android:visibility="gone">
+
+ <View
+ android:id="@+id/top_listDivider"
+ android:layout_width="match_parent"
+ android:layout_height="1dp"
+ android:background="?android:attr/listDivider"/>
+
+ <LinearLayout
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:layout_weight="1"
+ android:orientation="horizontal">
+
+ <ImageButton
+ android:id="@+id/menu_prev_button"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:layout_weight="1"
+ android:background="@drawable/footer_button_background_left"
+ android:contentDescription="@string/previous_button_content_description"
+ android:scaleType="centerInside"
+ android:src="@drawable/ic_arrow_back_24dp"
+ android:tint="@color/footer_icon_tint_color"/>
+
+ <View
+ android:layout_width="1dp"
+ android:layout_height="match_parent"
+ android:background="?android:attr/listDivider"/>
+
+ <ImageButton
+ android:id="@+id/menu_next_button"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:layout_weight="1"
+ android:background="@drawable/footer_button_background_right"
+ android:contentDescription="@string/next_button_content_description"
+ android:scaleType="centerInside"
+ android:src="@drawable/ic_arrow_forward_24dp"
+ android:tint="@color/footer_icon_tint_color"/>
+
+ </LinearLayout>
+
+ <View
+ android:id="@+id/bottom_listDivider"
+ android:layout_width="match_parent"
+ android:layout_height="1dp"
+ android:background="?android:attr/listDivider"/>
+
+</LinearLayout>
diff --git a/packages/SystemUI/accessibility/accessibilitymenu/res/layout/grid_item.xml b/packages/SystemUI/accessibility/accessibilitymenu/res/layout/grid_item.xml
new file mode 100644
index 0000000..39e5a8c
--- /dev/null
+++ b/packages/SystemUI/accessibility/accessibilitymenu/res/layout/grid_item.xml
@@ -0,0 +1,32 @@
+<?xml version="1.0" encoding="utf-8"?>
+<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:paddingTop="@dimen/grid_item_padding"
+ android:paddingBottom="@dimen/grid_item_padding"
+ android:gravity="center">
+
+ <ImageButton
+ android:id="@+id/shortcutIconBtn"
+ android:layout_width="@dimen/image_button_width"
+ android:layout_height="@dimen/image_button_height"
+ android:layout_alignParentTop="true"
+ android:layout_centerHorizontal="true"
+ android:scaleType="fitCenter"></ImageButton>
+
+<TextView
+ android:id="@+id/shortcutLabel"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_marginTop="@dimen/grid_item_text_view_margin_top"
+ android:layout_below="@+id/shortcutIconBtn"
+ android:layout_centerHorizontal="true"
+ android:ellipsize="end"
+ android:gravity="center_horizontal"
+ android:importantForAccessibility="no"
+ android:lines="2"
+ android:textSize="@dimen/label_text_size"
+ android:textAlignment="center"
+ android:textAppearance="@android:style/TextAppearance.DeviceDefault.Widget.Button"/>
+
+</RelativeLayout>
diff --git a/packages/SystemUI/accessibility/accessibilitymenu/res/layout/grid_view.xml b/packages/SystemUI/accessibility/accessibilitymenu/res/layout/grid_view.xml
new file mode 100644
index 0000000..c198443
--- /dev/null
+++ b/packages/SystemUI/accessibility/accessibilitymenu/res/layout/grid_view.xml
@@ -0,0 +1,11 @@
+<?xml version="1.0" encoding="utf-8"?>
+<GridView xmlns:android="http://schemas.android.com/apk/res/android"
+ android:id="@+id/gridview"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:horizontalSpacing="@dimen/a11ymenu_grid_layout_margin"
+ android:listSelector="@android:color/transparent"
+ android:numColumns="3"
+ android:overScrollMode="never"
+ android:stretchMode="columnWidth">
+</GridView>
diff --git a/packages/SystemUI/accessibility/accessibilitymenu/res/layout/paged_menu.xml b/packages/SystemUI/accessibility/accessibilitymenu/res/layout/paged_menu.xml
new file mode 100644
index 0000000..28a633e
--- /dev/null
+++ b/packages/SystemUI/accessibility/accessibilitymenu/res/layout/paged_menu.xml
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="utf-8"?>
+<androidx.coordinatorlayout.widget.CoordinatorLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="@dimen/row_width"
+ android:layout_height="match_parent"
+ android:id="@+id/coordinatorLayout"
+ android:background="@drawable/view_background"
+ >
+ <LinearLayout
+ android:layout_width="@dimen/row_width"
+ android:layout_height="wrap_content"
+ android:orientation="vertical">
+
+ <androidx.viewpager.widget.ViewPager
+ android:id="@+id/view_pager"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:paddingTop="@dimen/table_margin_top"
+ android:paddingBottom="@dimen/a11ymenu_layout_margin"
+ android:paddingLeft="@dimen/a11ymenu_layout_margin"
+ android:paddingRight="@dimen/a11ymenu_layout_margin"
+ android:layout_gravity="center"
+ android:gravity="center"
+ />
+
+ <include layout="@layout/footerlayout_switch_page"/>
+ </LinearLayout>
+</androidx.coordinatorlayout.widget.CoordinatorLayout>
diff --git a/packages/SystemUI/accessibility/accessibilitymenu/res/values-land/dimens.xml b/packages/SystemUI/accessibility/accessibilitymenu/res/values-land/dimens.xml
new file mode 100644
index 0000000..69f0934
--- /dev/null
+++ b/packages/SystemUI/accessibility/accessibilitymenu/res/values-land/dimens.xml
@@ -0,0 +1,12 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+ <dimen name="table_margin_top">0dp</dimen>
+ <dimen name="row_width">388dp</dimen>
+ <dimen name="image_button_height">45dp</dimen>
+ <dimen name="image_button_width">45dp</dimen>
+ <dimen name="image_button_marginBottom">1dp</dimen>
+
+ <!-- dimens for gridview layout. -->
+ <dimen name="grid_item_padding">4dp</dimen>
+
+</resources>
diff --git a/packages/SystemUI/accessibility/accessibilitymenu/res/values-night/colors.xml b/packages/SystemUI/accessibility/accessibilitymenu/res/values-night/colors.xml
new file mode 100644
index 0000000..33c0cca
--- /dev/null
+++ b/packages/SystemUI/accessibility/accessibilitymenu/res/values-night/colors.xml
@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="utf-8"?>
+
+<resources>
+ <color name="power_color">#dadce0</color>
+ <color name="quick_settings_color">#78d9ec</color>
+ <color name="a11y_settings_color">#d9affe</color>
+ <color name="recent_apps_color">#f0a5dd</color>
+ <color name="lockscreen_color">#85e4a0</color>
+ <color name="volume_color">#7ae3d4</color>
+ <color name="notifications_color">#f496ac</color>
+ <color name="screenshot_color">#adcbff</color>
+ <color name="assistant_color">#F1F3F4</color>
+ <color name="brightness_color">#fdd663</color>
+
+ <color name="ripple_material_color">#10FFFFFF</color>
+
+ <color name="overlay_bg_color">#313235</color>
+ <color name="footer_icon_color">#E8EAED</color>
+ <color name="footer_icon_enabled_color">#E8EAED</color>
+ <color name="footer_icon_disabled_color">#5F6368</color>
+ <color name="colorControlNormal">#202124</color>
+
+</resources>
diff --git a/packages/SystemUI/accessibility/accessibilitymenu/res/values-night/styles.xml b/packages/SystemUI/accessibility/accessibilitymenu/res/values-night/styles.xml
new file mode 100644
index 0000000..81b3152
--- /dev/null
+++ b/packages/SystemUI/accessibility/accessibilitymenu/res/values-night/styles.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright (C) 2019 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+
+<resources>
+ <!--Adds the theme to support SnackBar component and user configurable theme. -->
+ <style name="ServiceTheme" parent="android:Theme.DeviceDefault.DayNight">
+ <item name="android:colorControlNormal">@color/colorControlNormal</item>
+ </style>
+
+</resources>
diff --git a/packages/SystemUI/accessibility/accessibilitymenu/res/values/bool.xml b/packages/SystemUI/accessibility/accessibilitymenu/res/values/bool.xml
new file mode 100644
index 0000000..2f9d6b5
--- /dev/null
+++ b/packages/SystemUI/accessibility/accessibilitymenu/res/values/bool.xml
@@ -0,0 +1,5 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+ <bool name="isAtLeastP">true</bool>
+
+</resources>
\ No newline at end of file
diff --git a/packages/SystemUI/accessibility/accessibilitymenu/res/values/colors.xml b/packages/SystemUI/accessibility/accessibilitymenu/res/values/colors.xml
new file mode 100644
index 0000000..36d1fc1
--- /dev/null
+++ b/packages/SystemUI/accessibility/accessibilitymenu/res/values/colors.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="utf-8"?>
+
+<resources>
+ <color name="power_color">#757575</color>
+ <color name="quick_settings_color">#2196F3</color>
+ <color name="a11y_settings_color">#5806C9</color>
+ <color name="recent_apps_color">#AD2EC6</color>
+ <color name="lockscreen_color">#0F9D58</color>
+ <color name="volume_color">#01A2A0</color>
+ <color name="notifications_color">#F15B8D</color>
+ <color name="screenshot_color">#26459C</color>
+ <color name="assistant_color">#F1F3F4</color>
+ <color name="brightness_color">#E59810</color>
+ <color name="colorAccent">#1a73e8</color>
+
+ <color name="ripple_material_color">#1f000000</color>
+
+ <color name="overlay_bg_color">@android:color/white</color>
+ <color name="footer_icon_color">@android:color/black</color>
+ <color name="footer_icon_enabled_color">@android:color/black</color>
+ <color name="footer_icon_disabled_color">#ddd</color>
+ <color name="colorControlNormal">@android:color/white</color>
+
+ <color name="colorAccessibilityMenuIcon">#3AA757</color>
+</resources>
diff --git a/packages/SystemUI/accessibility/accessibilitymenu/res/values/dimens.xml b/packages/SystemUI/accessibility/accessibilitymenu/res/values/dimens.xml
new file mode 100644
index 0000000..7ed1897
--- /dev/null
+++ b/packages/SystemUI/accessibility/accessibilitymenu/res/values/dimens.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+ <!-- the curve radius for the background of the complete layout -->
+ <dimen name="table_margin_top">22dp</dimen>
+ <dimen name="row_width">@dimen/custom_match_parent</dimen>
+ <dimen name="image_button_height">60dp</dimen>
+ <dimen name="image_button_width">60dp</dimen>
+ <dimen name="image_button_marginBottom">2dp</dimen>
+ <dimen name="a11ymenu_layout_margin">4dp</dimen>
+ <dimen name="custom_match_parent">-1px</dimen>
+
+ <!-- dimens for gridview layout. -->
+ <dimen name="grid_item_text_view_margin_top">2dp</dimen>
+ <dimen name="grid_item_padding">10dp</dimen>
+ <dimen name="grid_item_btn_view_height">48dp</dimen>
+ <dimen name="a11ymenu_grid_layout_margin">8dp</dimen>
+
+ <!-- dimens for a11y menu footer layout. -->
+ <dimen name="footer_arrow_length">24dp</dimen>
+
+ <!-- text size for shortcut label when large button settings in on. -->
+ <dimen name="large_label_text_size">18sp</dimen>
+ <dimen name="label_text_size">14sp</dimen>
+
+</resources>
diff --git a/packages/SystemUI/accessibility/accessibilitymenu/res/values/donottranslate.xml b/packages/SystemUI/accessibility/accessibilitymenu/res/values/donottranslate.xml
new file mode 100644
index 0000000..0c25ec4
--- /dev/null
+++ b/packages/SystemUI/accessibility/accessibilitymenu/res/values/donottranslate.xml
@@ -0,0 +1,17 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+ <!-- user customized shortcuts preference -->
+ <string name="pref_user_shortcuts">accessibility_menu_user_shortcuts</string>
+ <!-- key for user customized shortcuts -->
+ <string name="pref_user_shortcuts_key">pref_user_shortcuts_key</string>
+ <!-- value for empty shortcut -->
+ <string name="pref_user_shortcuts_value_empty">[]</string>
+ <!-- empty string for shortcut label -->
+ <string name="empty_content"></string>
+
+ <string name="pref_large_buttons">pref_large_buttons</string>
+
+ <!-- key for Help&feedback settings [CHAR_LIMIT=NONE] -->
+ <string name="pref_help">pref_help</string>
+
+</resources>
diff --git a/packages/SystemUI/accessibility/accessibilitymenu/res/values/strings.xml b/packages/SystemUI/accessibility/accessibilitymenu/res/values/strings.xml
new file mode 100644
index 0000000..30fd017
--- /dev/null
+++ b/packages/SystemUI/accessibility/accessibilitymenu/res/values/strings.xml
@@ -0,0 +1,73 @@
+<?xml version="1.0" encoding="utf-8"?>
+
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <!-- String defining the service name -->
+ <string name="accessibility_menu_service_name">Accessibility Menu</string>
+ <!-- Accessibility Menu detail intro. [CHAR_LIMIT=NONE] -->
+ <string name="accessibility_menu_intro">
+ The Accessibility Menu provides a large on-screen menu to control your device. You can lock your device, control volume and brightness, take screenshots, and more.
+ </string>
+ <!-- String defining the label for the assistant button -->
+ <string name="assistant_label">Assistant</string>
+ <!-- String defining utterance for the assistant button for screen readers -->
+ <string name="assistant_utterance">Google Assistant</string>
+ <!-- String defining the label for the accessibility settings button -->
+ <string name="a11y_settings_label">Accessibility Settings</string>
+ <!-- String defining the label for the volume button -->
+ <string name="volume_label">Volume</string>
+ <!-- String defining utterance for the volume button for screen readers -->
+ <string name="volume_utterance">Volume controls</string>
+ <!-- String defining the label for the power button -->
+ <string name="power_label">Power</string>
+ <!-- String defining utterance for the power button for screen readers -->
+ <string name="power_utterance">Power options</string>
+ <!-- String defining the label for the recent apps button -->
+ <string name="recent_apps_label">Recent apps</string>
+ <!-- String defining the label for the lockscreen button -->
+ <string name="lockscreen_label">Lock screen</string>
+ <!-- String defining the label for the quick settings button -->
+ <string name="quick_settings_label">Quick Settings</string>
+ <!-- String defining the label for the notifications button -->
+ <string name="notifications_label">Notifications</string>
+ <!-- String defining the label for the screenshot button -->
+ <string name="screenshot_label">Screenshot</string>
+ <!-- String defining the utterance for the screenshot button for screen readers -->
+ <string name="screenshot_utterance">Take screenshot</string>
+ <!-- String defining the label for the volume up/down button -->
+ <string name="volume_up_label">Volume up</string>
+ <string name="volume_down_label">Volume down</string>
+ <!-- String defining the label for the brightness up/down button -->
+ <string name="brightness_up_label">Brightness up</string>
+ <string name="brightness_down_label">Brightness down</string>
+ <!-- String defining the content description for the footer previous/next button -->
+ <string name="previous_button_content_description">Go to previous screen</string>
+ <string name="next_button_content_description">Go to next screen</string>
+
+ <string name="accessibility_menu_description">
+ The Accessibility Menu provides a large on-screen menu to control your device. You can lock your device, control volume and brightness, take screenshots, and more.
+ </string>
+ <!-- Short summary of app that appears as subtext on the service preference in Settings -->
+ <string name="accessibility_menu_summary">Control device via large menu</string>
+
+ <!-- TODO(b/113371047): string need to be reviewed -->
+ <!-- String defining the settings name -->
+ <string name="accessibility_menu_settings_name">Accessibility Menu Settings</string>
+
+ <!-- String defining the title of Large button setting -->
+ <string name="accessibility_menu_large_buttons_title">Large buttons</string>
+ <!-- String defining the summary of Large button setting -->
+ <string name="accessibility_menu_large_buttons_summary">Increase size of Accessibility Menu Buttons</string>
+ <!-- String defining the title of the preference to show help and feedback menu [CHAR LIMIT=40] -->
+ <string name="pref_help_and_feedback_title">Help & feedback</string>
+ <!-- String defining the title of the preference to show help menu [CHAR LIMIT=40] -->
+ <string name="pref_help_title">Help</string>
+
+ <!-- The percentage of the brightness, and double "%" is required to represent the symbol "%" -->
+ <string name="brightness_percentage_label">Brightness <xliff:g id="percentage">%1$s</xliff:g> %%</string>
+ <!-- The percentage of the music volume, and double "%" is required to represent the symbol "%" -->
+ <string name="music_volume_percentage_label">Music volume <xliff:g id="percentage">%1$s</xliff:g> %%</string>
+
+ <!-- The label of a settings item that displays legal information about the licenses used in this app. [CHAR LIMIT=NONE] -->
+ <string name="pref_item_licenses">Open Source Licenses</string>
+
+</resources>
diff --git a/packages/SystemUI/accessibility/accessibilitymenu/res/values/styles.xml b/packages/SystemUI/accessibility/accessibilitymenu/res/values/styles.xml
new file mode 100644
index 0000000..a2cf267
--- /dev/null
+++ b/packages/SystemUI/accessibility/accessibilitymenu/res/values/styles.xml
@@ -0,0 +1,31 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright (C) 2018 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+
+<resources>
+ <!--The theme is for preference CollapsingToolbarBaseActivity settings-->
+ <style name="AccessibilityMenuSettings" parent="android:Theme.DeviceDefault.Light" />
+
+ <!--Adds the theme to support SnackBar component and user configurable theme. -->
+ <style name="ServiceTheme" parent="android:Theme.DeviceDefault.Light">
+ <item name="android:colorControlNormal">@color/colorControlNormal</item>
+ </style>
+
+ <!--The basic theme for service and test case only-->
+ <style name="A11yMenuBaseTheme" parent="android:Theme.DeviceDefault.Light">
+ <item name="android:windowActionBar">false</item>
+ </style>
+</resources>
diff --git a/packages/SystemUI/accessibility/accessibilitymenu/res/xml/accessibilitymenu_service.xml b/packages/SystemUI/accessibility/accessibilitymenu/res/xml/accessibilitymenu_service.xml
index 96882d33..3dbbb1a 100644
--- a/packages/SystemUI/accessibility/accessibilitymenu/res/xml/accessibilitymenu_service.xml
+++ b/packages/SystemUI/accessibility/accessibilitymenu/res/xml/accessibilitymenu_service.xml
@@ -13,4 +13,12 @@
See the License for the specific language governing permissions and
limitations under the License.
-->
-<accessibility-service xmlns:android="http://schemas.android.com/apk/res/android"/>
\ No newline at end of file
+<accessibility-service xmlns:android="http://schemas.android.com/apk/res/android"
+ android:accessibilityFeedbackType="feedbackGeneric"
+ android:accessibilityFlags="flagRequestAccessibilityButton|flagRequestFilterKeyEvents"
+ android:canRequestFilterKeyEvents="true"
+ android:summary="@string/accessibility_menu_summary"
+ android:intro="@string/accessibility_menu_intro"
+ android:animatedImageDrawable="@drawable/a11ymenu_intro"
+ android:isAccessibilityTool="true"
+/>
\ No newline at end of file
diff --git a/packages/SystemUI/accessibility/accessibilitymenu/src/com/android/systemui/accessibility/accessibilitymenu/AccessibilityMenuService.java b/packages/SystemUI/accessibility/accessibilitymenu/src/com/android/systemui/accessibility/accessibilitymenu/AccessibilityMenuService.java
index 8b75900..5c4fdcc 100644
--- a/packages/SystemUI/accessibility/accessibilitymenu/src/com/android/systemui/accessibility/accessibilitymenu/AccessibilityMenuService.java
+++ b/packages/SystemUI/accessibility/accessibilitymenu/src/com/android/systemui/accessibility/accessibilitymenu/AccessibilityMenuService.java
@@ -17,16 +17,39 @@
package com.android.systemui.accessibility.accessibilitymenu;
import android.accessibilityservice.AccessibilityService;
+import android.view.MotionEvent;
+import android.view.View;
import android.view.accessibility.AccessibilityEvent;
+import com.android.systemui.accessibility.accessibilitymenu.view.A11yMenuOverlayLayout;
+
/** @hide */
-public class AccessibilityMenuService extends AccessibilityService {
+public class AccessibilityMenuService extends AccessibilityService implements View.OnTouchListener {
+ private static final String TAG = "A11yMenuService";
+
+ private A11yMenuOverlayLayout mA11yMenuLayout;
@Override
- public void onAccessibilityEvent(AccessibilityEvent event) {
+ public void onCreate() {
+ super.onCreate();
}
@Override
+ protected void onServiceConnected() {
+ mA11yMenuLayout = new A11yMenuOverlayLayout(this);
+ super.onServiceConnected();
+ mA11yMenuLayout.toggleVisibility();
+ }
+
+ @Override
+ public void onAccessibilityEvent(AccessibilityEvent event) {}
+
+ @Override
public void onInterrupt() {
}
+
+ @Override
+ public boolean onTouch(View v, MotionEvent event) {
+ return false;
+ }
}
diff --git a/packages/SystemUI/accessibility/accessibilitymenu/src/com/android/systemui/accessibility/accessibilitymenu/model/A11yMenuShortcut.java b/packages/SystemUI/accessibility/accessibilitymenu/src/com/android/systemui/accessibility/accessibilitymenu/model/A11yMenuShortcut.java
new file mode 100644
index 0000000..fa42e61
--- /dev/null
+++ b/packages/SystemUI/accessibility/accessibilitymenu/src/com/android/systemui/accessibility/accessibilitymenu/model/A11yMenuShortcut.java
@@ -0,0 +1,91 @@
+/*
+ * 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 com.android.systemui.accessibility.accessibilitymenu.model;
+
+import com.android.systemui.accessibility.accessibilitymenu.R;
+
+/** Provides a data structure for a11y menu shortcuts. */
+public class A11yMenuShortcut {
+
+ public enum ShortcutId {
+ UNSPECIFIED_ID_VALUE,
+ ID_ASSISTANT_VALUE,
+ ID_A11YSETTING_VALUE,
+ ID_POWER_VALUE,
+ ID_VOLUME_DOWN_VALUE,
+ ID_VOLUME_UP_VALUE,
+ ID_RECENT_VALUE,
+ ID_BRIGHTNESS_DOWN_VALUE,
+ ID_BRIGHTNESS_UP_VALUE,
+ ID_LOCKSCREEN_VALUE,
+ ID_QUICKSETTING_VALUE,
+ ID_NOTIFICATION_VALUE,
+ ID_SCREENSHOT_VALUE
+ }
+
+ private static final String TAG = "A11yMenuShortcut";
+
+ /** Shortcut id used to identify. */
+ private int mShortcutId = ShortcutId.UNSPECIFIED_ID_VALUE.ordinal();
+
+ // Resource IDs of shortcut button and label.
+ public int imageSrc;
+ public int imageColor;
+ public int imgContentDescription;
+ public int labelText;
+
+ public A11yMenuShortcut(int id) {
+ setId(id);
+ }
+
+ /**
+ * Sets Id to shortcut, checks the value first and updates shortcut resources. It will set id to
+ *
+ * @param id id set to shortcut
+ */
+ public void setId(int id) {
+ mShortcutId = id;
+
+ // TODO(jonesriley) load the proper resources based on id
+ imageSrc = R.drawable.ic_logo_assistant_32dp;
+ imageColor = android.R.color.darker_gray;
+ imgContentDescription = R.string.empty_content;
+ labelText = R.string.empty_content;
+ }
+
+ public int getId() {
+ return mShortcutId;
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) {
+ return true;
+ }
+ if (!(o instanceof A11yMenuShortcut)) {
+ return false;
+ }
+
+ A11yMenuShortcut targetObject = (A11yMenuShortcut) o;
+
+ return mShortcutId == targetObject.mShortcutId;
+ }
+
+ @Override
+ public int hashCode() {
+ return mShortcutId;
+ }
+}
diff --git a/packages/SystemUI/accessibility/accessibilitymenu/src/com/android/systemui/accessibility/accessibilitymenu/utils/ShortcutDrawableUtils.java b/packages/SystemUI/accessibility/accessibilitymenu/src/com/android/systemui/accessibility/accessibilitymenu/utils/ShortcutDrawableUtils.java
new file mode 100644
index 0000000..28ba4b5
--- /dev/null
+++ b/packages/SystemUI/accessibility/accessibilitymenu/src/com/android/systemui/accessibility/accessibilitymenu/utils/ShortcutDrawableUtils.java
@@ -0,0 +1,98 @@
+/*
+ * 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 com.android.systemui.accessibility.accessibilitymenu.utils;
+
+import android.content.Context;
+import android.content.res.ColorStateList;
+import android.graphics.Bitmap;
+import android.graphics.Bitmap.Config;
+import android.graphics.Canvas;
+import android.graphics.Color;
+import android.graphics.Paint;
+import android.graphics.Paint.Style;
+import android.graphics.drawable.AdaptiveIconDrawable;
+import android.graphics.drawable.BitmapDrawable;
+import android.graphics.drawable.ColorDrawable;
+import android.graphics.drawable.Drawable;
+import android.graphics.drawable.LayerDrawable;
+import android.graphics.drawable.RippleDrawable;
+
+import com.android.systemui.accessibility.accessibilitymenu.R;
+
+/** Creates background drawable for a11y menu shortcut. */
+public class ShortcutDrawableUtils {
+
+ /**
+ * To make the circular background of shortcut icons have higher resolution. The higher value of
+ * LENGTH is, the higher resolution of the circular background are.
+ */
+ private static final int LENGTH = 480;
+
+ private static final int RADIUS = LENGTH / 2;
+ private static final int COORDINATE = LENGTH / 2;
+ private static final int RIPPLE_COLOR_ID = R.color.ripple_material_color;
+
+ private final Context mContext;
+ private final ColorStateList mRippleColorStateList;
+
+ // Placeholder of drawable to prevent NullPointerException
+ private final ColorDrawable mTransparentDrawable = new ColorDrawable(Color.TRANSPARENT);
+
+ public ShortcutDrawableUtils(Context context) {
+ this.mContext = context;
+
+ int rippleColor = context.getColor(RIPPLE_COLOR_ID);
+ mRippleColorStateList = ColorStateList.valueOf(rippleColor);
+ }
+
+ /**
+ * Creates a circular drawable in specific color for shortcut.
+ *
+ * @param colorResId color resource ID
+ * @return drawable circular drawable
+ */
+ public Drawable createCircularDrawable(int colorResId) {
+ Bitmap output = Bitmap.createBitmap(LENGTH, LENGTH, Config.ARGB_8888);
+ Canvas canvas = new Canvas(output);
+ int color = mContext.getColor(colorResId);
+ Paint paint = new Paint();
+ paint.setColor(color);
+ paint.setStrokeCap(Paint.Cap.ROUND);
+ paint.setStyle(Style.FILL);
+ canvas.drawCircle(COORDINATE, COORDINATE, RADIUS, paint);
+
+ BitmapDrawable drawable = new BitmapDrawable(mContext.getResources(), output);
+ return drawable;
+ }
+
+ /**
+ * Creates an adaptive icon drawable in specific color for shortcut.
+ *
+ * @param colorResId color resource ID
+ * @return drawable for adaptive icon
+ */
+ public Drawable createAdaptiveIconDrawable(int colorResId) {
+ Drawable circleLayer = createCircularDrawable(colorResId);
+ RippleDrawable rippleLayer = new RippleDrawable(mRippleColorStateList, null, null);
+
+ AdaptiveIconDrawable adaptiveIconDrawable =
+ new AdaptiveIconDrawable(circleLayer, mTransparentDrawable);
+
+ Drawable[] layers = {adaptiveIconDrawable, rippleLayer};
+ LayerDrawable drawable = new LayerDrawable(layers);
+ return drawable;
+ }
+}
diff --git a/packages/SystemUI/accessibility/accessibilitymenu/src/com/android/systemui/accessibility/accessibilitymenu/view/A11yMenuAdapter.java b/packages/SystemUI/accessibility/accessibilitymenu/src/com/android/systemui/accessibility/accessibilitymenu/view/A11yMenuAdapter.java
new file mode 100644
index 0000000..e3401a9
--- /dev/null
+++ b/packages/SystemUI/accessibility/accessibilitymenu/src/com/android/systemui/accessibility/accessibilitymenu/view/A11yMenuAdapter.java
@@ -0,0 +1,145 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.accessibility.accessibilitymenu.view;
+
+import android.graphics.Rect;
+import android.view.LayoutInflater;
+import android.view.TouchDelegate;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.BaseAdapter;
+import android.widget.ImageButton;
+import android.widget.TextView;
+
+import com.android.systemui.accessibility.accessibilitymenu.AccessibilityMenuService;
+import com.android.systemui.accessibility.accessibilitymenu.R;
+import com.android.systemui.accessibility.accessibilitymenu.model.A11yMenuShortcut;
+import com.android.systemui.accessibility.accessibilitymenu.utils.ShortcutDrawableUtils;
+
+import java.util.List;
+
+/** GridView Adapter for a11y menu overlay. */
+public class A11yMenuAdapter extends BaseAdapter {
+
+ // The large scale of shortcut icon and label.
+ private static final float LARGE_BUTTON_SCALE = 1.5f;
+ private final int mLargeTextSize;
+
+ private final AccessibilityMenuService mService;
+ private final LayoutInflater mInflater;
+ private final List<A11yMenuShortcut> mShortcutDataList;
+ private final ShortcutDrawableUtils mShortcutDrawableUtils;
+
+ public A11yMenuAdapter(
+ AccessibilityMenuService service, List<A11yMenuShortcut> shortcutDataList) {
+ this.mService = service;
+ this.mShortcutDataList = shortcutDataList;
+ mInflater = LayoutInflater.from(service);
+
+ mShortcutDrawableUtils = new ShortcutDrawableUtils(service);
+
+ mLargeTextSize =
+ service.getResources().getDimensionPixelOffset(R.dimen.large_label_text_size);
+ }
+
+ @Override
+ public int getCount() {
+ return mShortcutDataList.size();
+ }
+
+ @Override
+ public Object getItem(int position) {
+ return mShortcutDataList.get(position);
+ }
+
+ @Override
+ public long getItemId(int position) {
+ return mShortcutDataList.get(position).getId();
+ }
+
+ @Override
+ public View getView(int position, View convertView, ViewGroup parent) {
+ convertView = mInflater.inflate(R.layout.grid_item, null);
+
+ A11yMenuShortcut shortcutItem = (A11yMenuShortcut) getItem(position);
+ // Sets shortcut icon and label resource.
+ configureShortcutView(convertView, shortcutItem);
+
+ expandIconTouchArea(convertView);
+ setActionForMenuShortcut(convertView);
+ return convertView;
+ }
+
+ /**
+ * Expand shortcut icon touch area to the border of grid item.
+ * The height is from the top of icon to the bottom of label.
+ * The width is from the left border of grid item to the right border of grid item.
+ */
+ private void expandIconTouchArea(View convertView) {
+ ImageButton shortcutIconButton = convertView.findViewById(R.id.shortcutIconBtn);
+ TextView shortcutLabel = convertView.findViewById(R.id.shortcutLabel);
+
+ shortcutIconButton.post(
+ () -> {
+ Rect iconHitRect = new Rect();
+ shortcutIconButton.getHitRect(iconHitRect);
+ Rect labelHitRect = new Rect();
+ shortcutLabel.getHitRect(labelHitRect);
+
+ final int widthAdjustment = iconHitRect.left;
+ iconHitRect.left = 0;
+ iconHitRect.right += widthAdjustment;
+ iconHitRect.top = 0;
+ iconHitRect.bottom = labelHitRect.bottom;
+ ((View) shortcutIconButton.getParent())
+ .setTouchDelegate(new TouchDelegate(iconHitRect, shortcutIconButton));
+ });
+ }
+
+ private void setActionForMenuShortcut(View convertView) {
+ ImageButton shortcutIconButton = convertView.findViewById(R.id.shortcutIconBtn);
+
+ shortcutIconButton.setOnClickListener(
+ (View v) -> {
+ // Handles shortcut click event by AccessibilityMenuService.
+ // service.handleClick(v);
+ });
+ }
+
+ private void configureShortcutView(View convertView, A11yMenuShortcut shortcutItem) {
+ ImageButton shortcutIconButton = convertView.findViewById(R.id.shortcutIconBtn);
+ TextView shortcutLabel = convertView.findViewById(R.id.shortcutLabel);
+
+ // TODO: Enlarge shortcut icon & label when large button setting is on.
+
+ if (shortcutItem.getId() == A11yMenuShortcut.ShortcutId.UNSPECIFIED_ID_VALUE.ordinal()) {
+ // Sets empty shortcut icon and label when the shortcut is ADD_ITEM.
+ shortcutIconButton.setImageResource(android.R.color.transparent);
+ shortcutIconButton.setBackground(null);
+ } else {
+ // Sets shortcut ID as tagId, to handle menu item click in AccessibilityMenuService.
+ shortcutIconButton.setTag(shortcutItem.getId());
+ shortcutIconButton.setContentDescription(
+ mService.getString(shortcutItem.imgContentDescription));
+ shortcutLabel.setText(shortcutItem.labelText);
+ shortcutIconButton.setImageResource(shortcutItem.imageSrc);
+
+ shortcutIconButton.setBackground(
+ mShortcutDrawableUtils.createAdaptiveIconDrawable(shortcutItem.imageColor));
+ }
+ }
+}
diff --git a/packages/SystemUI/accessibility/accessibilitymenu/src/com/android/systemui/accessibility/accessibilitymenu/view/A11yMenuFooter.java b/packages/SystemUI/accessibility/accessibilitymenu/src/com/android/systemui/accessibility/accessibilitymenu/view/A11yMenuFooter.java
new file mode 100644
index 0000000..20c63df
--- /dev/null
+++ b/packages/SystemUI/accessibility/accessibilitymenu/src/com/android/systemui/accessibility/accessibilitymenu/view/A11yMenuFooter.java
@@ -0,0 +1,125 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.accessibility.accessibilitymenu.view;
+
+import android.graphics.Rect;
+import android.view.TouchDelegate;
+import android.view.View;
+import android.view.View.OnClickListener;
+import android.view.ViewGroup;
+import android.view.ViewTreeObserver.OnGlobalLayoutListener;
+import android.widget.ImageButton;
+
+import androidx.annotation.Nullable;
+
+import com.android.systemui.accessibility.accessibilitymenu.R;
+
+/**
+ * This class is for Accessibility menu footer layout. Handles switching between a11y menu pages.
+ */
+public class A11yMenuFooter {
+
+ /** Provides an interface for footer of a11yMenu. */
+ public interface A11yMenuFooterCallBack {
+
+ /** Calls back when user clicks the left button. */
+ void onLeftButtonClicked();
+
+ /** Calls back when user clicks the right button. */
+ void onRightButtonClicked();
+ }
+
+ private final FooterButtonClickListener mFooterButtonClickListener;
+
+ private ImageButton mPreviousPageBtn;
+ private ImageButton mNextPageBtn;
+ private View mTopListDivider;
+ private View mBottomListDivider;
+ private final A11yMenuFooterCallBack mCallBack;
+
+ public A11yMenuFooter(ViewGroup menuLayout, A11yMenuFooterCallBack callBack) {
+ this.mCallBack = callBack;
+ mFooterButtonClickListener = new FooterButtonClickListener();
+ configureFooterLayout(menuLayout);
+ }
+
+ public @Nullable ImageButton getPreviousPageBtn() {
+ return mPreviousPageBtn;
+ }
+
+ public @Nullable ImageButton getNextPageBtn() {
+ return mNextPageBtn;
+ }
+
+ private void configureFooterLayout(ViewGroup menuLayout) {
+ ViewGroup footerContainer = menuLayout.findViewById(R.id.footerlayout);
+ footerContainer.setVisibility(View.VISIBLE);
+
+ mPreviousPageBtn = menuLayout.findViewById(R.id.menu_prev_button);
+ mNextPageBtn = menuLayout.findViewById(R.id.menu_next_button);
+ mTopListDivider = menuLayout.findViewById(R.id.top_listDivider);
+ mBottomListDivider = menuLayout.findViewById(R.id.bottom_listDivider);
+
+ // Registers listeners for footer buttons.
+ setListener(mPreviousPageBtn);
+ setListener(mNextPageBtn);
+
+ menuLayout
+ .getViewTreeObserver()
+ .addOnGlobalLayoutListener(
+ new OnGlobalLayoutListener() {
+ @Override
+ public void onGlobalLayout() {
+ menuLayout.getViewTreeObserver().removeOnGlobalLayoutListener(this);
+ expandBtnTouchArea(mPreviousPageBtn, menuLayout);
+ expandBtnTouchArea(mNextPageBtn, (View) mNextPageBtn.getParent());
+ }
+ });
+ }
+
+ private void expandBtnTouchArea(ImageButton btn, View btnParent) {
+ Rect btnRect = new Rect();
+ btn.getHitRect(btnRect);
+ btnRect.top -= getHitRectHeight(mTopListDivider);
+ btnRect.bottom += getHitRectHeight(mBottomListDivider);
+ btnParent.setTouchDelegate(new TouchDelegate(btnRect, btn));
+ }
+
+ private static int getHitRectHeight(View listDivider) {
+ Rect hitRect = new Rect();
+ listDivider.getHitRect(hitRect);
+ return hitRect.height();
+ }
+
+ private void setListener(@Nullable View view) {
+ if (view != null) {
+ view.setOnClickListener(mFooterButtonClickListener);
+ }
+ }
+
+ /** Handles click event for footer buttons. */
+ private class FooterButtonClickListener implements OnClickListener {
+ @Override
+ public void onClick(View view) {
+ if (view.getId() == R.id.menu_prev_button) {
+ mCallBack.onLeftButtonClicked();
+ } else if (view.getId() == R.id.menu_next_button) {
+ mCallBack.onRightButtonClicked();
+ }
+ }
+ }
+}
diff --git a/packages/SystemUI/accessibility/accessibilitymenu/src/com/android/systemui/accessibility/accessibilitymenu/view/A11yMenuOverlayLayout.java b/packages/SystemUI/accessibility/accessibilitymenu/src/com/android/systemui/accessibility/accessibilitymenu/view/A11yMenuOverlayLayout.java
new file mode 100644
index 0000000..740bc8a
--- /dev/null
+++ b/packages/SystemUI/accessibility/accessibilitymenu/src/com/android/systemui/accessibility/accessibilitymenu/view/A11yMenuOverlayLayout.java
@@ -0,0 +1,269 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.accessibility.accessibilitymenu.view;
+
+import static java.lang.Math.max;
+
+import android.content.res.Configuration;
+import android.graphics.Insets;
+import android.graphics.PixelFormat;
+import android.graphics.Rect;
+import android.view.Display;
+import android.view.Gravity;
+import android.view.LayoutInflater;
+import android.view.Surface;
+import android.view.View;
+import android.view.ViewGroup;
+import android.view.WindowInsets;
+import android.view.WindowManager;
+import android.view.WindowMetrics;
+import android.widget.FrameLayout;
+import android.widget.Toast;
+
+import com.android.systemui.accessibility.accessibilitymenu.AccessibilityMenuService;
+import com.android.systemui.accessibility.accessibilitymenu.R;
+import com.android.systemui.accessibility.accessibilitymenu.model.A11yMenuShortcut;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * Provides functionality for Accessibility menu layout in a11y menu overlay. There are functions to
+ * configure or update Accessibility menu layout when orientation and display size changed, and
+ * functions to toggle menu visibility when button clicked or screen off.
+ */
+public class A11yMenuOverlayLayout {
+
+ /** Predefined default shortcuts when large button setting is off. */
+ private static final int[] SHORTCUT_LIST_DEFAULT = {
+ A11yMenuShortcut.ShortcutId.ID_ASSISTANT_VALUE.ordinal(),
+ A11yMenuShortcut.ShortcutId.ID_A11YSETTING_VALUE.ordinal(),
+ A11yMenuShortcut.ShortcutId.ID_POWER_VALUE.ordinal(),
+ A11yMenuShortcut.ShortcutId.ID_VOLUME_DOWN_VALUE.ordinal(),
+ A11yMenuShortcut.ShortcutId.ID_VOLUME_UP_VALUE.ordinal(),
+ A11yMenuShortcut.ShortcutId.ID_RECENT_VALUE.ordinal(),
+ A11yMenuShortcut.ShortcutId.ID_BRIGHTNESS_DOWN_VALUE.ordinal(),
+ A11yMenuShortcut.ShortcutId.ID_BRIGHTNESS_UP_VALUE.ordinal(),
+ A11yMenuShortcut.ShortcutId.ID_LOCKSCREEN_VALUE.ordinal(),
+ A11yMenuShortcut.ShortcutId.ID_QUICKSETTING_VALUE.ordinal(),
+ A11yMenuShortcut.ShortcutId.ID_NOTIFICATION_VALUE.ordinal(),
+ A11yMenuShortcut.ShortcutId.ID_SCREENSHOT_VALUE.ordinal()
+ };
+
+ private final AccessibilityMenuService mService;
+ private final WindowManager mWindowManager;
+ private ViewGroup mLayout;
+ private WindowManager.LayoutParams mLayoutParameter;
+ private A11yMenuViewPager mA11yMenuViewPager;
+
+ public A11yMenuOverlayLayout(AccessibilityMenuService service) {
+ mService = service;
+ mWindowManager = mService.getSystemService(WindowManager.class);
+ configureLayout();
+ }
+
+ /** Creates Accessibility menu layout and configure layout parameters. */
+ public View configureLayout() {
+ return configureLayout(A11yMenuViewPager.DEFAULT_PAGE_INDEX);
+ }
+
+ // TODO(b/78292783): Find a better way to inflate layout in the test.
+ /**
+ * Creates Accessibility menu layout, configure layout parameters and apply index to ViewPager.
+ *
+ * @param pageIndex the index of the ViewPager to show.
+ */
+ public View configureLayout(int pageIndex) {
+
+ int lastVisibilityState = View.GONE;
+ if (mLayout != null) {
+ lastVisibilityState = mLayout.getVisibility();
+ mWindowManager.removeView(mLayout);
+ mLayout = null;
+ }
+
+ if (mLayoutParameter == null) {
+ initLayoutParams();
+ }
+
+ mLayout = new FrameLayout(mService);
+ updateLayoutPosition();
+ inflateLayoutAndSetOnTouchListener(mLayout);
+ mA11yMenuViewPager = new A11yMenuViewPager(mService);
+ mA11yMenuViewPager.configureViewPagerAndFooter(mLayout, createShortcutList(), pageIndex);
+ mWindowManager.addView(mLayout, mLayoutParameter);
+ mLayout.setVisibility(lastVisibilityState);
+
+ return mLayout;
+ }
+
+ /** Updates view layout with new layout parameters only. */
+ public void updateViewLayout() {
+ if (mLayout == null || mLayoutParameter == null) {
+ return;
+ }
+ updateLayoutPosition();
+ mWindowManager.updateViewLayout(mLayout, mLayoutParameter);
+ }
+
+ private void initLayoutParams() {
+ mLayoutParameter = new WindowManager.LayoutParams();
+ mLayoutParameter.type = WindowManager.LayoutParams.TYPE_ACCESSIBILITY_OVERLAY;
+ mLayoutParameter.format = PixelFormat.TRANSLUCENT;
+ mLayoutParameter.flags |= WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL;
+ mLayoutParameter.flags |= WindowManager.LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH;
+ mLayoutParameter.setTitle(mService.getString(R.string.accessibility_menu_service_name));
+ }
+
+ private void inflateLayoutAndSetOnTouchListener(ViewGroup view) {
+ LayoutInflater inflater = LayoutInflater.from(mService);
+ inflater.inflate(R.layout.paged_menu, view);
+ view.setOnTouchListener(mService);
+ }
+
+ /**
+ * Loads shortcut data from default shortcut ID array.
+ *
+ * @return A list of default shortcuts
+ */
+ private List<A11yMenuShortcut> createShortcutList() {
+ List<A11yMenuShortcut> shortcutList = new ArrayList<>();
+ for (int shortcutId : SHORTCUT_LIST_DEFAULT) {
+ shortcutList.add(new A11yMenuShortcut(shortcutId));
+ }
+ return shortcutList;
+ }
+
+ /** Updates a11y menu layout position by configuring layout params. */
+ private void updateLayoutPosition() {
+ Display display = mLayout.getDisplay();
+ final int orientation = mService.getResources().getConfiguration().orientation;
+ if (orientation == Configuration.ORIENTATION_LANDSCAPE) {
+ switch (display.getRotation()) {
+ case Surface.ROTATION_90:
+ case Surface.ROTATION_180:
+ mLayoutParameter.gravity =
+ Gravity.END | Gravity.BOTTOM
+ | Gravity.CENTER_VERTICAL | Gravity.CENTER_HORIZONTAL;
+ mLayoutParameter.width = WindowManager.LayoutParams.WRAP_CONTENT;
+ mLayoutParameter.height = WindowManager.LayoutParams.MATCH_PARENT;
+ mLayoutParameter.flags |= WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN;
+ mLayoutParameter.flags |= WindowManager.LayoutParams.FLAG_LAYOUT_INSET_DECOR;
+ mLayout.setBackgroundResource(R.drawable.shadow_90deg);
+ break;
+ case Surface.ROTATION_0:
+ case Surface.ROTATION_270:
+ mLayoutParameter.gravity =
+ Gravity.START | Gravity.BOTTOM
+ | Gravity.CENTER_VERTICAL | Gravity.CENTER_HORIZONTAL;
+ mLayoutParameter.width = WindowManager.LayoutParams.WRAP_CONTENT;
+ mLayoutParameter.height = WindowManager.LayoutParams.MATCH_PARENT;
+ mLayoutParameter.flags |= WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN;
+ mLayoutParameter.flags |= WindowManager.LayoutParams.FLAG_LAYOUT_INSET_DECOR;
+ mLayout.setBackgroundResource(R.drawable.shadow_270deg);
+ break;
+ default:
+ break;
+ }
+ } else {
+ mLayoutParameter.gravity = Gravity.BOTTOM;
+ mLayoutParameter.width = WindowManager.LayoutParams.MATCH_PARENT;
+ mLayoutParameter.height = WindowManager.LayoutParams.WRAP_CONTENT;
+ mLayout.setBackgroundResource(R.drawable.shadow_0deg);
+ }
+
+ // Adjusts the y position of a11y menu layout to make the layout not to overlap bottom
+ // navigation bar window.
+ updateLayoutByWindowInsetsIfNeeded();
+ mLayout.setOnApplyWindowInsetsListener(
+ (view, insets) -> {
+ if (updateLayoutByWindowInsetsIfNeeded()) {
+ mWindowManager.updateViewLayout(mLayout, mLayoutParameter);
+ }
+ return view.onApplyWindowInsets(insets);
+ });
+ }
+
+ /**
+ * Returns {@code true} if the a11y menu layout params
+ * should be updated by {@link WindowManager} immediately due to window insets change.
+ * This method adjusts the layout position and size to
+ * make a11y menu not to overlap navigation bar window.
+ */
+ private boolean updateLayoutByWindowInsetsIfNeeded() {
+ boolean shouldUpdateLayout = false;
+ WindowMetrics windowMetrics = mWindowManager.getCurrentWindowMetrics();
+ Insets windowInsets = windowMetrics.getWindowInsets().getInsetsIgnoringVisibility(
+ WindowInsets.Type.systemBars() | WindowInsets.Type.displayCutout());
+ int xOffset = max(windowInsets.left, windowInsets.right);
+ int yOffset = windowInsets.bottom;
+ Rect windowBound = windowMetrics.getBounds();
+ if (mLayoutParameter.x != xOffset || mLayoutParameter.y != yOffset) {
+ mLayoutParameter.x = xOffset;
+ mLayoutParameter.y = yOffset;
+ shouldUpdateLayout = true;
+ }
+ // for gestural navigation mode and the landscape mode,
+ // the layout height should be decreased by system bar
+ // and display cutout inset to fit the new
+ // frame size that doesn't overlap the navigation bar window.
+ int orientation = mService.getResources().getConfiguration().orientation;
+ if (mLayout.getHeight() != mLayoutParameter.height
+ && orientation == Configuration.ORIENTATION_LANDSCAPE) {
+ mLayoutParameter.height = windowBound.height() - yOffset;
+ shouldUpdateLayout = true;
+ }
+ return shouldUpdateLayout;
+ }
+
+ /**
+ * Gets the current page index when device configuration changed. {@link
+ * AccessibilityMenuService#onConfigurationChanged(Configuration)}
+ *
+ * @return the current index of the ViewPager.
+ */
+ public int getPageIndex() {
+ if (mA11yMenuViewPager != null) {
+ return mA11yMenuViewPager.mViewPager.getCurrentItem();
+ }
+ return A11yMenuViewPager.DEFAULT_PAGE_INDEX;
+ }
+
+ /**
+ * Hides a11y menu layout. And return if layout visibility has been changed.
+ *
+ * @return {@code true} layout visibility is toggled off; {@code false} is unchanged
+ */
+ public boolean hideMenu() {
+ if (mLayout.getVisibility() == View.VISIBLE) {
+ mLayout.setVisibility(View.GONE);
+ return true;
+ }
+ return false;
+ }
+
+ /** Toggles a11y menu layout visibility. */
+ public void toggleVisibility() {
+ mLayout.setVisibility((mLayout.getVisibility() == View.VISIBLE) ? View.GONE : View.VISIBLE);
+ }
+
+ /** Shows hint text on Toast. */
+ public void showToast(String text) {
+ final View viewPos = mLayout.findViewById(R.id.coordinatorLayout);
+ Toast.makeText(viewPos.getContext(), text, Toast.LENGTH_SHORT).show();
+ }
+}
diff --git a/packages/SystemUI/accessibility/accessibilitymenu/src/com/android/systemui/accessibility/accessibilitymenu/view/A11yMenuViewPager.java b/packages/SystemUI/accessibility/accessibilitymenu/src/com/android/systemui/accessibility/accessibilitymenu/view/A11yMenuViewPager.java
new file mode 100644
index 0000000..c510b87
--- /dev/null
+++ b/packages/SystemUI/accessibility/accessibilitymenu/src/com/android/systemui/accessibility/accessibilitymenu/view/A11yMenuViewPager.java
@@ -0,0 +1,356 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.accessibility.accessibilitymenu.view;
+
+import android.content.Context;
+import android.content.res.Configuration;
+import android.graphics.Insets;
+import android.util.DisplayMetrics;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.view.ViewTreeObserver.OnGlobalLayoutListener;
+import android.view.WindowInsets;
+import android.view.WindowManager;
+import android.view.WindowMetrics;
+import android.widget.GridView;
+
+import androidx.viewpager.widget.ViewPager;
+
+import com.android.systemui.accessibility.accessibilitymenu.AccessibilityMenuService;
+import com.android.systemui.accessibility.accessibilitymenu.R;
+import com.android.systemui.accessibility.accessibilitymenu.model.A11yMenuShortcut;
+import com.android.systemui.accessibility.accessibilitymenu.view.A11yMenuFooter.A11yMenuFooterCallBack;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * This class handles UI for viewPager and footer.
+ * It displays grid pages containing all shortcuts in viewPager,
+ * and handles the click events from footer to switch between pages.
+ */
+public class A11yMenuViewPager {
+
+ /** The default index of the ViewPager. */
+ public static final int DEFAULT_PAGE_INDEX = 0;
+
+ /**
+ * The class holds the static parameters for grid view when large button settings is on/off.
+ */
+ public static final class GridViewParams {
+ /** Total shortcuts count in the grid view when large button settings is off. */
+ public static final int GRID_ITEM_COUNT = 9;
+
+ /** The number of columns in the grid view when large button settings is off. */
+ public static final int GRID_COLUMN_COUNT = 3;
+
+ /** Total shortcuts count in the grid view when large button settings is on. */
+ public static final int LARGE_GRID_ITEM_COUNT = 4;
+
+ /** The number of columns in the grid view when large button settings is on. */
+ public static final int LARGE_GRID_COLUMN_COUNT = 2;
+
+ /** Temporary measure to test both item types. */
+ private static final boolean USE_LARGE_ITEMS = true;
+
+ /**
+ * Returns the number of items in the grid view.
+ *
+ * @param context The parent context
+ * @return Grid item count
+ */
+ public static int getGridItemCount(Context context) {
+ return USE_LARGE_ITEMS
+ ? LARGE_GRID_ITEM_COUNT
+ : GRID_ITEM_COUNT;
+ }
+
+ /**
+ * Returns the number of columns in the grid view.
+ *
+ * @param context The parent context
+ * @return Grid column count
+ */
+ public static int getGridColumnCount(Context context) {
+ return USE_LARGE_ITEMS
+ ? LARGE_GRID_COLUMN_COUNT
+ : GRID_COLUMN_COUNT;
+ }
+
+ /**
+ * Returns the number of rows in the grid view.
+ *
+ * @param context The parent context
+ * @return Grid row count
+ */
+ public static int getGridRowCount(Context context) {
+ return USE_LARGE_ITEMS
+ ? (LARGE_GRID_ITEM_COUNT / LARGE_GRID_COLUMN_COUNT)
+ : (GRID_ITEM_COUNT / GRID_COLUMN_COUNT);
+ }
+
+ /**
+ * Separates a provided list of accessibility shortcuts into multiple sub-lists.
+ * Does not modify the original list.
+ *
+ * @param pageItemCount The maximum size of an individual sub-list.
+ * @param shortcutList The list of shortcuts to be separated into sub-lists.
+ * @return A list of shortcut sub-lists.
+ */
+ public static List<List<A11yMenuShortcut>> generateShortcutSubLists(
+ int pageItemCount, List<A11yMenuShortcut> shortcutList) {
+ int start = 0;
+ int end;
+ int shortcutListSize = shortcutList.size();
+ List<List<A11yMenuShortcut>> subLists = new ArrayList<>();
+ while (start < shortcutListSize) {
+ end = Math.min(start + pageItemCount, shortcutListSize);
+ subLists.add(shortcutList.subList(start, end));
+ start = end;
+ }
+ return subLists;
+ }
+
+ private GridViewParams() {}
+ }
+
+ private final AccessibilityMenuService mService;
+
+ /**
+ * The pager widget, which handles animation and allows swiping horizontally to access previous
+ * and next gridView pages.
+ */
+ protected ViewPager mViewPager;
+
+ private ViewPagerAdapter<GridView> mViewPagerAdapter;
+ private final List<GridView> mGridPageList = new ArrayList<>();
+
+ /** The footer, which provides buttons to switch between pages */
+ protected A11yMenuFooter mA11yMenuFooter;
+
+ /** The shortcut list intended to show in grid pages of viewPager */
+ private List<A11yMenuShortcut> mA11yMenuShortcutList;
+
+ /** The container layout for a11y menu. */
+ private ViewGroup mA11yMenuLayout;
+
+ public A11yMenuViewPager(AccessibilityMenuService service) {
+ this.mService = service;
+ }
+
+ /**
+ * Configures UI for view pager and footer.
+ *
+ * @param a11yMenuLayout the container layout for a11y menu
+ * @param shortcutDataList the data list need to show in view pager
+ * @param pageIndex the index of ViewPager to show
+ */
+ public void configureViewPagerAndFooter(
+ ViewGroup a11yMenuLayout, List<A11yMenuShortcut> shortcutDataList, int pageIndex) {
+ this.mA11yMenuLayout = a11yMenuLayout;
+ mA11yMenuShortcutList = shortcutDataList;
+ initViewPager();
+ initChildPage();
+ mA11yMenuFooter = new A11yMenuFooter(a11yMenuLayout, mFooterCallbacks);
+ updateFooterState();
+ registerOnGlobalLayoutListener();
+ goToPage(pageIndex);
+ }
+
+ /** Initializes viewPager and its adapter. */
+ private void initViewPager() {
+ mViewPager = mA11yMenuLayout.findViewById(R.id.view_pager);
+ mViewPagerAdapter = new ViewPagerAdapter<>();
+ mViewPager.setAdapter(mViewPagerAdapter);
+ mViewPager.setOverScrollMode(View.OVER_SCROLL_NEVER);
+ mViewPager.addOnPageChangeListener(
+ new ViewPager.OnPageChangeListener() {
+ @Override
+ public void onPageScrollStateChanged(int state) {}
+
+ @Override
+ public void onPageScrolled(
+ int position, float positionOffset, int positionOffsetPixels) {}
+
+ @Override
+ public void onPageSelected(int position) {
+ updateFooterState();
+ }
+ });
+ }
+
+ /** Creates child pages of viewPager by the length of shortcuts and initializes them. */
+ private void initChildPage() {
+ if (mA11yMenuShortcutList == null || mA11yMenuShortcutList.isEmpty()) {
+ return;
+ }
+
+ if (!mGridPageList.isEmpty()) {
+ mGridPageList.clear();
+ }
+
+ // Generate pages by calculating # of items per grid.
+ for (List<A11yMenuShortcut> page : GridViewParams.generateShortcutSubLists(
+ GridViewParams.getGridItemCount(mService), mA11yMenuShortcutList)
+ ) {
+ addGridPage(page);
+ }
+
+ mViewPagerAdapter.set(mGridPageList);
+ }
+
+ private void addGridPage(List<A11yMenuShortcut> shortcutDataListInPage) {
+ LayoutInflater inflater = LayoutInflater.from(mService);
+ View view = inflater.inflate(R.layout.grid_view, null);
+ GridView gridView = view.findViewById(R.id.gridview);
+ A11yMenuAdapter adapter = new A11yMenuAdapter(mService, shortcutDataListInPage);
+ gridView.setNumColumns(GridViewParams.getGridColumnCount(mService));
+ gridView.setAdapter(adapter);
+ mGridPageList.add(gridView);
+ }
+
+ /** Updates footer's state by index of current page in view pager. */
+ private void updateFooterState() {
+ int currentPage = mViewPager.getCurrentItem();
+ int lastPage = mViewPager.getAdapter().getCount() - 1;
+ mA11yMenuFooter.getPreviousPageBtn().setEnabled(currentPage > 0);
+ mA11yMenuFooter.getNextPageBtn().setEnabled(currentPage < lastPage);
+ }
+
+ private void goToPage(int pageIndex) {
+ if (mViewPager == null) {
+ return;
+ }
+ if ((pageIndex >= 0) && (pageIndex < mViewPager.getAdapter().getCount())) {
+ mViewPager.setCurrentItem(pageIndex);
+ }
+ }
+
+ /** Registers OnGlobalLayoutListener to adjust menu UI by running callback at first time. */
+ private void registerOnGlobalLayoutListener() {
+ mA11yMenuLayout
+ .getViewTreeObserver()
+ .addOnGlobalLayoutListener(
+ new OnGlobalLayoutListener() {
+
+ boolean mIsFirstTime = true;
+
+ @Override
+ public void onGlobalLayout() {
+ if (!mIsFirstTime) {
+ return;
+ }
+
+ if (mGridPageList.isEmpty()) {
+ return;
+ }
+
+ GridView firstGridView = mGridPageList.get(0);
+ if (firstGridView == null
+ || firstGridView.getChildAt(0) == null) {
+ return;
+ }
+
+ mIsFirstTime = false;
+
+ int gridItemHeight = firstGridView.getChildAt(0)
+ .getMeasuredHeight();
+ adjustMenuUISize(gridItemHeight);
+ }
+ });
+ }
+
+ /**
+ * Adjusts menu UI to fit both landscape and portrait mode.
+ *
+ * <ol>
+ * <li>Adjust view pager's height.
+ * <li>Adjust vertical interval between grid items.
+ * <li>Adjust padding in view pager.
+ * </ol>
+ */
+ private void adjustMenuUISize(int gridItemHeight) {
+ final int rowsInGridView = GridViewParams.getGridRowCount(mService);
+ final int defaultMargin =
+ (int) mService.getResources().getDimension(R.dimen.a11ymenu_layout_margin);
+ final int topMargin = (int) mService.getResources().getDimension(R.dimen.table_margin_top);
+ final int displayMode = mService.getResources().getConfiguration().orientation;
+ int viewPagerHeight = mViewPager.getMeasuredHeight();
+
+ if (displayMode == Configuration.ORIENTATION_PORTRAIT) {
+ // In portrait mode, we only need to adjust view pager's height to match its
+ // child's height.
+ viewPagerHeight = gridItemHeight * rowsInGridView + defaultMargin + topMargin;
+ } else if (displayMode == Configuration.ORIENTATION_LANDSCAPE) {
+ // In landscape mode, we need to adjust view pager's height to match screen height
+ // and adjust its child too,
+ // because a11y menu layout height is limited by the screen height.
+ DisplayMetrics displayMetrics = mService.getResources().getDisplayMetrics();
+ float densityScale = (float) displayMetrics.densityDpi
+ / DisplayMetrics.DENSITY_DEVICE_STABLE;
+ View footerLayout = mA11yMenuLayout.findViewById(R.id.footerlayout);
+ // Keeps footer window height unchanged no matter the density is changed.
+ footerLayout.getLayoutParams().height =
+ (int) (footerLayout.getLayoutParams().height / densityScale);
+ // Adjust the view pager height for system bar and display cutout insets.
+ WindowManager windowManager = mService.getSystemService(WindowManager.class);
+ WindowMetrics windowMetric = windowManager.getCurrentWindowMetrics();
+ Insets windowInsets = windowMetric.getWindowInsets().getInsetsIgnoringVisibility(
+ WindowInsets.Type.systemBars() | WindowInsets.Type.displayCutout());
+ viewPagerHeight =
+ windowMetric.getBounds().height()
+ - footerLayout.getLayoutParams().height
+ - windowInsets.bottom;
+ // Sets vertical interval between grid items.
+ int interval =
+ (viewPagerHeight - topMargin - defaultMargin
+ - (rowsInGridView * gridItemHeight))
+ / (rowsInGridView + 1);
+ for (GridView gridView : mGridPageList) {
+ gridView.setVerticalSpacing(interval);
+ }
+
+ // Sets padding to view pager.
+ final int finalMarginTop = interval + topMargin;
+ mViewPager.setPadding(defaultMargin, finalMarginTop, defaultMargin, defaultMargin);
+ }
+ final ViewGroup.LayoutParams layoutParams = mViewPager.getLayoutParams();
+ layoutParams.height = viewPagerHeight;
+ mViewPager.setLayoutParams(layoutParams);
+ }
+
+ /** Callback object to handle click events from A11yMenuFooter */
+ protected A11yMenuFooterCallBack mFooterCallbacks =
+ new A11yMenuFooterCallBack() {
+ @Override
+ public void onLeftButtonClicked() {
+ // Moves to previous page.
+ int targetPage = mViewPager.getCurrentItem() - 1;
+ goToPage(targetPage);
+ updateFooterState();
+ }
+
+ @Override
+ public void onRightButtonClicked() {
+ // Moves to next page.
+ int targetPage = mViewPager.getCurrentItem() + 1;
+ goToPage(targetPage);
+ updateFooterState();
+ }
+ };
+}
diff --git a/packages/SystemUI/accessibility/accessibilitymenu/src/com/android/systemui/accessibility/accessibilitymenu/view/ViewPagerAdapter.java b/packages/SystemUI/accessibility/accessibilitymenu/src/com/android/systemui/accessibility/accessibilitymenu/view/ViewPagerAdapter.java
new file mode 100644
index 0000000..5670d72
--- /dev/null
+++ b/packages/SystemUI/accessibility/accessibilitymenu/src/com/android/systemui/accessibility/accessibilitymenu/view/ViewPagerAdapter.java
@@ -0,0 +1,70 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.accessibility.accessibilitymenu.view;
+
+import android.view.View;
+import android.view.ViewGroup;
+
+import androidx.viewpager.widget.PagerAdapter;
+
+import java.util.List;
+
+/** The pager adapter, which provides the pages to the view pager widget. */
+class ViewPagerAdapter<T extends View> extends PagerAdapter {
+
+ /** The widget list in each page of view pager. */
+ private List<T> mWidgetList;
+
+ ViewPagerAdapter() {}
+
+ public void set(List<T> tList) {
+ mWidgetList = tList;
+ notifyDataSetChanged();
+ }
+
+ @Override
+ public int getCount() {
+ if (mWidgetList == null) {
+ return 0;
+ }
+ return mWidgetList.size();
+ }
+
+ @Override
+ public int getItemPosition(Object object) {
+ return POSITION_NONE;
+ }
+
+ @Override
+ public boolean isViewFromObject(View view, Object object) {
+ return view == object;
+ }
+
+ @Override
+ public Object instantiateItem(ViewGroup container, int position) {
+ if (mWidgetList == null) {
+ return null;
+ }
+ container.addView(mWidgetList.get(position));
+ return mWidgetList.get(position);
+ }
+
+ @Override
+ public void destroyItem(ViewGroup container, int position, Object object) {
+ container.removeView((View) object);
+ }
+}
diff --git a/packages/SystemUI/animation/src/com/android/systemui/animation/ActivityLaunchAnimator.kt b/packages/SystemUI/animation/src/com/android/systemui/animation/ActivityLaunchAnimator.kt
index fe349f2..8f70dcc 100644
--- a/packages/SystemUI/animation/src/com/android/systemui/animation/ActivityLaunchAnimator.kt
+++ b/packages/SystemUI/animation/src/com/android/systemui/animation/ActivityLaunchAnimator.kt
@@ -37,6 +37,8 @@
import android.view.WindowManager
import android.view.animation.Interpolator
import android.view.animation.PathInterpolator
+import androidx.annotation.BinderThread
+import androidx.annotation.UiThread
import com.android.internal.annotations.VisibleForTesting
import com.android.internal.policy.ScreenDecorationsUtils
import kotlin.math.roundToInt
@@ -226,7 +228,7 @@
// If we expect an animation, post a timeout to cancel it in case the remote animation is
// never started.
if (willAnimate) {
- runner.postTimeout()
+ runner.delegate.postTimeout()
// Hide the keyguard using the launch animation instead of the default unlock animation.
if (hideKeyguardWithAnimation) {
@@ -389,14 +391,51 @@
fun onLaunchAnimationCancelled(newKeyguardOccludedState: Boolean? = null) {}
}
- class Runner(
+ @VisibleForTesting
+ inner class Runner(
+ controller: Controller,
+ callback: Callback,
+ /** The animator to use to animate the window launch. */
+ launchAnimator: LaunchAnimator = DEFAULT_LAUNCH_ANIMATOR,
+ /** Listener for animation lifecycle events. */
+ listener: Listener? = null
+ ) : IRemoteAnimationRunner.Stub() {
+ private val context = controller.launchContainer.context
+ internal val delegate: AnimationDelegate
+
+ init {
+ delegate = AnimationDelegate(controller, callback, launchAnimator, listener)
+ }
+
+ @BinderThread
+ override fun onAnimationStart(
+ transit: Int,
+ apps: Array<out RemoteAnimationTarget>?,
+ wallpapers: Array<out RemoteAnimationTarget>?,
+ nonApps: Array<out RemoteAnimationTarget>?,
+ finishedCallback: IRemoteAnimationFinishedCallback?
+ ) {
+ context.mainExecutor.execute {
+ delegate.onAnimationStart(transit, apps, wallpapers, nonApps, finishedCallback)
+ }
+ }
+
+ @BinderThread
+ override fun onAnimationCancelled(isKeyguardOccluded: Boolean) {
+ context.mainExecutor.execute { delegate.onAnimationCancelled(isKeyguardOccluded) }
+ }
+ }
+
+ class AnimationDelegate
+ @JvmOverloads
+ constructor(
private val controller: Controller,
private val callback: Callback,
/** The animator to use to animate the window launch. */
private val launchAnimator: LaunchAnimator = DEFAULT_LAUNCH_ANIMATOR,
/** Listener for animation lifecycle events. */
private val listener: Listener? = null
- ) : IRemoteAnimationRunner.Stub() {
+ ) : RemoteAnimationDelegate<IRemoteAnimationFinishedCallback> {
private val launchContainer = controller.launchContainer
private val context = launchContainer.context
private val transactionApplierView =
@@ -419,6 +458,7 @@
// posting it.
private var onTimeout = Runnable { onAnimationTimedOut() }
+ @UiThread
internal fun postTimeout() {
launchContainer.postDelayed(onTimeout, LAUNCH_TIMEOUT)
}
@@ -427,19 +467,20 @@
launchContainer.removeCallbacks(onTimeout)
}
+ @UiThread
override fun onAnimationStart(
@WindowManager.TransitionOldType transit: Int,
apps: Array<out RemoteAnimationTarget>?,
wallpapers: Array<out RemoteAnimationTarget>?,
nonApps: Array<out RemoteAnimationTarget>?,
- iCallback: IRemoteAnimationFinishedCallback?
+ callback: IRemoteAnimationFinishedCallback?
) {
removeTimeout()
// The animation was started too late and we already notified the controller that it
// timed out.
if (timedOut) {
- iCallback?.invoke()
+ callback?.invoke()
return
}
@@ -449,7 +490,7 @@
return
}
- context.mainExecutor.execute { startAnimation(apps, nonApps, iCallback) }
+ startAnimation(apps, nonApps, callback)
}
private fun startAnimation(
@@ -687,6 +728,7 @@
controller.onLaunchAnimationCancelled()
}
+ @UiThread
override fun onAnimationCancelled(isKeyguardOccluded: Boolean) {
if (timedOut) {
return
@@ -695,10 +737,9 @@
Log.i(TAG, "Remote animation was cancelled")
cancelled = true
removeTimeout()
- context.mainExecutor.execute {
- animation?.cancel()
- controller.onLaunchAnimationCancelled(newKeyguardOccludedState = isKeyguardOccluded)
- }
+
+ animation?.cancel()
+ controller.onLaunchAnimationCancelled(newKeyguardOccludedState = isKeyguardOccluded)
}
private fun IRemoteAnimationFinishedCallback.invoke() {
diff --git a/packages/SystemUI/animation/src/com/android/systemui/animation/FontInterpolator.kt b/packages/SystemUI/animation/src/com/android/systemui/animation/FontInterpolator.kt
index 2903288..3d341af 100644
--- a/packages/SystemUI/animation/src/com/android/systemui/animation/FontInterpolator.kt
+++ b/packages/SystemUI/animation/src/com/android/systemui/animation/FontInterpolator.kt
@@ -33,7 +33,9 @@
private const val FONT_ITALIC_ANIMATION_STEP = 0.1f
private const val FONT_ITALIC_DEFAULT_VALUE = 0f
-/** Provide interpolation of two fonts by adjusting font variation settings. */
+/**
+ * Provide interpolation of two fonts by adjusting font variation settings.
+ */
class FontInterpolator {
/**
@@ -59,14 +61,11 @@
var index: Int,
val sortedAxes: MutableList<FontVariationAxis>
) {
- constructor(
- font: Font,
- axes: List<FontVariationAxis>
- ) : this(
- font.sourceIdentifier,
- font.ttcIndex,
- axes.toMutableList().apply { sortBy { it.tag } }
- )
+ constructor(font: Font, axes: List<FontVariationAxis>) :
+ this(font.sourceIdentifier,
+ font.ttcIndex,
+ axes.toMutableList().apply { sortBy { it.tag } }
+ )
fun set(font: Font, axes: List<FontVariationAxis>) {
sourceId = font.sourceIdentifier
@@ -87,7 +86,9 @@
private val tmpInterpKey = InterpKey(null, null, 0f)
private val tmpVarFontKey = VarFontKey(0, 0, mutableListOf())
- /** Linear interpolate the font variation settings. */
+ /**
+ * Linear interpolate the font variation settings.
+ */
fun lerp(start: Font, end: Font, progress: Float): Font {
if (progress == 0f) {
return start
@@ -114,34 +115,27 @@
// this doesn't take much time since the variation axes is usually up to 5. If we need to
// support more number of axes, we may want to preprocess the font and store the sorted axes
// and also pre-fill the missing axes value with default value from 'fvar' table.
- val newAxes =
- lerp(startAxes, endAxes) { tag, startValue, endValue ->
- when (tag) {
- // TODO: Good to parse 'fvar' table for retrieving default value.
- TAG_WGHT ->
- adjustWeight(
- MathUtils.lerp(
+ val newAxes = lerp(startAxes, endAxes) { tag, startValue, endValue ->
+ when (tag) {
+ // TODO: Good to parse 'fvar' table for retrieving default value.
+ TAG_WGHT -> adjustWeight(
+ MathUtils.lerp(
startValue ?: FONT_WEIGHT_DEFAULT_VALUE,
endValue ?: FONT_WEIGHT_DEFAULT_VALUE,
- progress
- )
- )
- TAG_ITAL ->
- adjustItalic(
- MathUtils.lerp(
+ progress))
+ TAG_ITAL -> adjustItalic(
+ MathUtils.lerp(
startValue ?: FONT_ITALIC_DEFAULT_VALUE,
endValue ?: FONT_ITALIC_DEFAULT_VALUE,
- progress
- )
- )
- else -> {
- require(startValue != null && endValue != null) {
- "Unable to interpolate due to unknown default axes value : $tag"
- }
- MathUtils.lerp(startValue, endValue, progress)
+ progress))
+ else -> {
+ require(startValue != null && endValue != null) {
+ "Unable to interpolate due to unknown default axes value : $tag"
}
+ MathUtils.lerp(startValue, endValue, progress)
}
}
+ }
// Check if we already make font for this axes. This is typically happens if the animation
// happens backward.
@@ -155,7 +149,9 @@
// This is the first time to make the font for the axes. Build and store it to the cache.
// Font.Builder#build won't throw IOException since creating fonts from existing fonts will
// not do any IO work.
- val newFont = Font.Builder(start).setFontVariationSettings(newAxes.toTypedArray()).build()
+ val newFont = Font.Builder(start)
+ .setFontVariationSettings(newAxes.toTypedArray())
+ .build()
interpCache[InterpKey(start, end, progress)] = newFont
verFontCache[VarFontKey(start, newAxes)] = newFont
return newFont
@@ -177,28 +173,26 @@
val tagA = if (i < start.size) start[i].tag else null
val tagB = if (j < end.size) end[j].tag else null
- val comp =
- when {
- tagA == null -> 1
- tagB == null -> -1
- else -> tagA.compareTo(tagB)
- }
+ val comp = when {
+ tagA == null -> 1
+ tagB == null -> -1
+ else -> tagA.compareTo(tagB)
+ }
- val axis =
- when {
- comp == 0 -> {
- val v = filter(tagA!!, start[i++].styleValue, end[j++].styleValue)
- FontVariationAxis(tagA, v)
- }
- comp < 0 -> {
- val v = filter(tagA!!, start[i++].styleValue, null)
- FontVariationAxis(tagA, v)
- }
- else -> { // comp > 0
- val v = filter(tagB!!, null, end[j++].styleValue)
- FontVariationAxis(tagB, v)
- }
+ val axis = when {
+ comp == 0 -> {
+ val v = filter(tagA!!, start[i++].styleValue, end[j++].styleValue)
+ FontVariationAxis(tagA, v)
}
+ comp < 0 -> {
+ val v = filter(tagA!!, start[i++].styleValue, null)
+ FontVariationAxis(tagA, v)
+ }
+ else -> { // comp > 0
+ val v = filter(tagB!!, null, end[j++].styleValue)
+ FontVariationAxis(tagB, v)
+ }
+ }
result.add(axis)
}
@@ -208,21 +202,21 @@
// For the performance reasons, we animate weight with FONT_WEIGHT_ANIMATION_STEP. This helps
// Cache hit ratio in the Skia glyph cache.
private fun adjustWeight(value: Float) =
- coerceInWithStep(value, FONT_WEIGHT_MIN, FONT_WEIGHT_MAX, FONT_WEIGHT_ANIMATION_STEP)
+ coerceInWithStep(value, FONT_WEIGHT_MIN, FONT_WEIGHT_MAX, FONT_WEIGHT_ANIMATION_STEP)
// For the performance reasons, we animate italic with FONT_ITALIC_ANIMATION_STEP. This helps
// Cache hit ratio in the Skia glyph cache.
private fun adjustItalic(value: Float) =
- coerceInWithStep(value, FONT_ITALIC_MIN, FONT_ITALIC_MAX, FONT_ITALIC_ANIMATION_STEP)
+ coerceInWithStep(value, FONT_ITALIC_MIN, FONT_ITALIC_MAX, FONT_ITALIC_ANIMATION_STEP)
private fun coerceInWithStep(v: Float, min: Float, max: Float, step: Float) =
- (v.coerceIn(min, max) / step).toInt() * step
+ (v.coerceIn(min, max) / step).toInt() * step
companion object {
private val EMPTY_AXES = arrayOf<FontVariationAxis>()
// Returns true if given two font instance can be interpolated.
fun canInterpolate(start: Font, end: Font) =
- start.ttcIndex == end.ttcIndex && start.sourceIdentifier == end.sourceIdentifier
+ start.ttcIndex == end.ttcIndex && start.sourceIdentifier == end.sourceIdentifier
}
}
diff --git a/packages/SystemUI/animation/src/com/android/systemui/animation/RemoteAnimationDelegate.kt b/packages/SystemUI/animation/src/com/android/systemui/animation/RemoteAnimationDelegate.kt
new file mode 100644
index 0000000..337408b
--- /dev/null
+++ b/packages/SystemUI/animation/src/com/android/systemui/animation/RemoteAnimationDelegate.kt
@@ -0,0 +1,30 @@
+package com.android.systemui.animation
+
+import android.annotation.UiThread
+import android.view.IRemoteAnimationFinishedCallback
+import android.view.RemoteAnimationTarget
+import android.view.WindowManager
+
+/**
+ * A component capable of running remote animations.
+ *
+ * Expands the IRemoteAnimationRunner API by allowing for different types of more specialized
+ * callbacks.
+ */
+interface RemoteAnimationDelegate<in T : IRemoteAnimationFinishedCallback> {
+ /**
+ * Called on the UI thread when the animation targets are received. Sets up and kicks off the
+ * animation.
+ */
+ @UiThread
+ fun onAnimationStart(
+ @WindowManager.TransitionOldType transit: Int,
+ apps: Array<out RemoteAnimationTarget>?,
+ wallpapers: Array<out RemoteAnimationTarget>?,
+ nonApps: Array<out RemoteAnimationTarget>?,
+ callback: T?
+ )
+
+ /** Called on the UI thread when a signal is received to cancel the animation. */
+ @UiThread fun onAnimationCancelled(isKeyguardOccluded: Boolean)
+}
diff --git a/packages/SystemUI/animation/src/com/android/systemui/animation/TextAnimator.kt b/packages/SystemUI/animation/src/com/android/systemui/animation/TextAnimator.kt
index 65d6c83..5f1bb83 100644
--- a/packages/SystemUI/animation/src/com/android/systemui/animation/TextAnimator.kt
+++ b/packages/SystemUI/animation/src/com/android/systemui/animation/TextAnimator.kt
@@ -36,7 +36,8 @@
* Currently this class can provide text style animation for text weight and text size. For example
* the simple view that draws text with animating text size is like as follows:
*
- * ```
+ * <pre>
+ * <code>
* class SimpleTextAnimation : View {
* @JvmOverloads constructor(...)
*
@@ -52,34 +53,39 @@
* animator.setTextStyle(-1 /* unchanged weight */, sizePx, animate)
* }
* }
- * ```
+ * </code>
+ * </pre>
*/
-class TextAnimator(layout: Layout, private val invalidateCallback: () -> Unit) {
+class TextAnimator(
+ layout: Layout,
+ private val invalidateCallback: () -> Unit
+) {
// Following two members are for mutable for testing purposes.
public var textInterpolator: TextInterpolator = TextInterpolator(layout)
- public var animator: ValueAnimator =
- ValueAnimator.ofFloat(1f).apply {
- duration = DEFAULT_ANIMATION_DURATION
- addUpdateListener {
- textInterpolator.progress = it.animatedValue as Float
- invalidateCallback()
- }
- addListener(
- object : AnimatorListenerAdapter() {
- override fun onAnimationEnd(animation: Animator?) {
- textInterpolator.rebase()
- }
- override fun onAnimationCancel(animation: Animator?) = textInterpolator.rebase()
- }
- )
+ public var animator: ValueAnimator = ValueAnimator.ofFloat(1f).apply {
+ duration = DEFAULT_ANIMATION_DURATION
+ addUpdateListener {
+ textInterpolator.progress = it.animatedValue as Float
+ invalidateCallback()
}
+ addListener(object : AnimatorListenerAdapter() {
+ override fun onAnimationEnd(animation: Animator?) {
+ textInterpolator.rebase()
+ }
+ override fun onAnimationCancel(animation: Animator?) = textInterpolator.rebase()
+ })
+ }
sealed class PositionedGlyph {
- /** Mutable X coordinate of the glyph position relative from drawing offset. */
+ /**
+ * Mutable X coordinate of the glyph position relative from drawing offset.
+ */
var x: Float = 0f
- /** Mutable Y coordinate of the glyph position relative from the baseline. */
+ /**
+ * Mutable Y coordinate of the glyph position relative from the baseline.
+ */
var y: Float = 0f
/**
@@ -90,29 +96,40 @@
/**
* Mutable text size of the glyph in pixels.
*/
- /** Mutable text size of the glyph in pixels. */
var textSize: Float = 0f
- /** Mutable color of the glyph. */
+ /**
+ * Mutable color of the glyph.
+ */
var color: Int = 0
- /** Immutable character offset in the text that the current font run start. */
+ /**
+ * Immutable character offset in the text that the current font run start.
+ */
abstract var runStart: Int
protected set
- /** Immutable run length of the font run. */
+ /**
+ * Immutable run length of the font run.
+ */
abstract var runLength: Int
protected set
- /** Immutable glyph index of the font run. */
+ /**
+ * Immutable glyph index of the font run.
+ */
abstract var glyphIndex: Int
protected set
- /** Immutable font instance for this font run. */
+ /**
+ * Immutable font instance for this font run.
+ */
abstract var font: Font
protected set
- /** Immutable glyph ID for this glyph. */
+ /**
+ * Immutable glyph ID for this glyph.
+ */
abstract var glyphId: Int
protected set
}
@@ -130,30 +147,30 @@
/**
* GlyphFilter applied just before drawing to canvas for tweaking positions and text size.
*
- * This callback is called for each glyphs just before drawing the glyphs. This function will be
- * called with the intrinsic position, size, color, glyph ID and font instance. You can mutate
- * the position, size and color for tweaking animations. Do not keep the reference of passed
- * glyph object. The interpolator reuses that object for avoiding object allocations.
+ * This callback is called for each glyphs just before drawing the glyphs. This function will
+ * be called with the intrinsic position, size, color, glyph ID and font instance. You can
+ * mutate the position, size and color for tweaking animations.
+ * Do not keep the reference of passed glyph object. The interpolator reuses that object for
+ * avoiding object allocations.
*
- * Details: The text is drawn with font run units. The font run is a text segment that draws
- * with the same font. The {@code runStart} and {@code runLimit} is a range of the font run in
- * the text that current glyph is in. Once the font run is determined, the system will convert
- * characters into glyph IDs. The {@code glyphId} is the glyph identifier in the font and {@code
- * glyphIndex} is the offset of the converted glyph array. Please note that the {@code
- * glyphIndex} is not a character index, because the character will not be converted to glyph
- * one-by-one. If there are ligatures including emoji sequence, etc, the glyph ID may be
+ * Details:
+ * The text is drawn with font run units. The font run is a text segment that draws with the
+ * same font. The {@code runStart} and {@code runLimit} is a range of the font run in the text
+ * that current glyph is in. Once the font run is determined, the system will convert characters
+ * into glyph IDs. The {@code glyphId} is the glyph identifier in the font and
+ * {@code glyphIndex} is the offset of the converted glyph array. Please note that the
+ * {@code glyphIndex} is not a character index, because the character will not be converted to
+ * glyph one-by-one. If there are ligatures including emoji sequence, etc, the glyph ID may be
* composed from multiple characters.
*
* Here is an example of font runs: "fin. 終わり"
*
- * ```
* Characters : f i n . _ 終 わ り
* Code Points: \u0066 \u0069 \u006E \u002E \u0020 \u7D42 \u308F \u308A
* Font Runs : <-- Roboto-Regular.ttf --><-- NotoSans-CJK.otf -->
* runStart = 0, runLength = 5 runStart = 5, runLength = 3
* Glyph IDs : 194 48 7 8 4367 1039 1002
* Glyph Index: 0 1 2 3 0 1 2
- * ```
*
* In this example, the "fi" is converted into ligature form, thus the single glyph ID is
* assigned for two characters, f and i.
@@ -176,29 +193,28 @@
*/
var glyphFilter: GlyphCallback?
get() = textInterpolator.glyphFilter
- set(value) {
- textInterpolator.glyphFilter = value
- }
+ set(value) { textInterpolator.glyphFilter = value }
fun draw(c: Canvas) = textInterpolator.draw(c)
/**
* Set text style with animation.
*
- * By passing -1 to weight, the view preserve the current weight. By passing -1 to textSize, the
- * view preserve the current text size. Bu passing -1 to duration, the default text animation,
- * 1000ms, is used. By passing false to animate, the text will be updated without animation.
+ * By passing -1 to weight, the view preserve the current weight.
+ * By passing -1 to textSize, the view preserve the current text size.
+ * Bu passing -1 to duration, the default text animation, 1000ms, is used.
+ * By passing false to animate, the text will be updated without animation.
*
* @param weight an optional text weight.
* @param textSize an optional font size.
- * @param colors an optional colors array that must be the same size as numLines passed to the
- * TextInterpolator
+ * @param colors an optional colors array that must be the same size as numLines passed to
+ * the TextInterpolator
* @param animate an optional boolean indicating true for showing style transition as animation,
- * false for immediate style transition. True by default.
+ * false for immediate style transition. True by default.
* @param duration an optional animation duration in milliseconds. This is ignored if animate is
- * false.
+ * false.
* @param interpolator an optional time interpolator. If null is passed, last set interpolator
- * will be used. This is ignored if animate is false.
+ * will be used. This is ignored if animate is false.
*/
fun setTextStyle(
weight: Int = -1,
@@ -221,11 +237,10 @@
if (weight >= 0) {
// Paint#setFontVariationSettings creates Typeface instance from scratch. To reduce the
// memory impact, cache the typeface result.
- textInterpolator.targetPaint.typeface =
- typefaceCache.getOrElse(weight) {
- textInterpolator.targetPaint.fontVariationSettings = "'$TAG_WGHT' $weight"
- textInterpolator.targetPaint.typeface
- }
+ textInterpolator.targetPaint.typeface = typefaceCache.getOrElse(weight) {
+ textInterpolator.targetPaint.fontVariationSettings = "'$TAG_WGHT' $weight"
+ textInterpolator.targetPaint.typeface
+ }
}
if (color != null) {
textInterpolator.targetPaint.color = color
@@ -234,24 +249,22 @@
if (animate) {
animator.startDelay = delay
- animator.duration =
- if (duration == -1L) {
- DEFAULT_ANIMATION_DURATION
- } else {
- duration
- }
+ animator.duration = if (duration == -1L) {
+ DEFAULT_ANIMATION_DURATION
+ } else {
+ duration
+ }
interpolator?.let { animator.interpolator = it }
if (onAnimationEnd != null) {
- val listener =
- object : AnimatorListenerAdapter() {
- override fun onAnimationEnd(animation: Animator?) {
- onAnimationEnd.run()
- animator.removeListener(this)
- }
- override fun onAnimationCancel(animation: Animator?) {
- animator.removeListener(this)
- }
+ val listener = object : AnimatorListenerAdapter() {
+ override fun onAnimationEnd(animation: Animator?) {
+ onAnimationEnd.run()
+ animator.removeListener(this)
}
+ override fun onAnimationCancel(animation: Animator?) {
+ animator.removeListener(this)
+ }
+ }
animator.addListener(listener)
}
animator.start()
diff --git a/packages/SystemUI/animation/src/com/android/systemui/animation/TextInterpolator.kt b/packages/SystemUI/animation/src/com/android/systemui/animation/TextInterpolator.kt
index f9fb42c..0448c81 100644
--- a/packages/SystemUI/animation/src/com/android/systemui/animation/TextInterpolator.kt
+++ b/packages/SystemUI/animation/src/com/android/systemui/animation/TextInterpolator.kt
@@ -26,8 +26,12 @@
import com.android.internal.graphics.ColorUtils
import java.lang.Math.max
-/** Provide text style linear interpolation for plain text. */
-class TextInterpolator(layout: Layout) {
+/**
+ * Provide text style linear interpolation for plain text.
+ */
+class TextInterpolator(
+ layout: Layout
+) {
/**
* Returns base paint used for interpolation.
@@ -60,11 +64,12 @@
var baseFont: Font,
var targetFont: Font
) {
- val length: Int
- get() = end - start
+ val length: Int get() = end - start
}
- /** A class represents text layout of a single run. */
+ /**
+ * A class represents text layout of a single run.
+ */
private class Run(
val glyphIds: IntArray,
val baseX: FloatArray, // same length as glyphIds
@@ -74,8 +79,12 @@
val fontRuns: List<FontRun>
)
- /** A class represents text layout of a single line. */
- private class Line(val runs: List<Run>)
+ /**
+ * A class represents text layout of a single line.
+ */
+ private class Line(
+ val runs: List<Run>
+ )
private var lines = listOf<Line>()
private val fontInterpolator = FontInterpolator()
@@ -97,8 +106,8 @@
/**
* The layout used for drawing text.
*
- * Only non-styled text is supported. Even if the given layout is created from Spanned, the span
- * information is not used.
+ * Only non-styled text is supported. Even if the given layout is created from Spanned, the
+ * span information is not used.
*
* The paint objects used for interpolation are not changed by this method call.
*
@@ -121,8 +130,8 @@
/**
* Recalculate internal text layout for interpolation.
*
- * Whenever the target paint is modified, call this method to recalculate internal text layout
- * used for interpolation.
+ * Whenever the target paint is modified, call this method to recalculate internal
+ * text layout used for interpolation.
*/
fun onTargetPaintModified() {
updatePositionsAndFonts(shapeText(layout, targetPaint), updateBase = false)
@@ -131,8 +140,8 @@
/**
* Recalculate internal text layout for interpolation.
*
- * Whenever the base paint is modified, call this method to recalculate internal text layout
- * used for interpolation.
+ * Whenever the base paint is modified, call this method to recalculate internal
+ * text layout used for interpolation.
*/
fun onBasePaintModified() {
updatePositionsAndFonts(shapeText(layout, basePaint), updateBase = true)
@@ -143,11 +152,11 @@
*
* The text interpolator does not calculate all the text position by text shaper due to
* performance reasons. Instead, the text interpolator shape the start and end state and
- * calculate text position of the middle state by linear interpolation. Due to this trick, the
- * text positions of the middle state is likely different from the text shaper result. So, if
- * you want to start animation from the middle state, you will see the glyph jumps due to this
- * trick, i.e. the progress 0.5 of interpolation between weight 400 and 700 is different from
- * text shape result of weight 550.
+ * calculate text position of the middle state by linear interpolation. Due to this trick,
+ * the text positions of the middle state is likely different from the text shaper result.
+ * So, if you want to start animation from the middle state, you will see the glyph jumps due to
+ * this trick, i.e. the progress 0.5 of interpolation between weight 400 and 700 is different
+ * from text shape result of weight 550.
*
* After calling this method, do not call onBasePaintModified() since it reshape the text and
* update the base state. As in above notice, the text shaping result at current progress is
@@ -159,7 +168,8 @@
* animate weight from 200 to 400, then if you want to move back to 200 at the half of the
* animation, it will look like
*
- * ```
+ * <pre>
+ * <code>
* val interp = TextInterpolator(layout)
*
* // Interpolate between weight 200 to 400.
@@ -189,7 +199,9 @@
* // progress is 0.5
* animator.start()
* }
- * ```
+ * </code>
+ * </pre>
+ *
*/
fun rebase() {
if (progress == 0f) {
@@ -251,75 +263,69 @@
}
var maxRunLength = 0
- lines =
- baseLayout.zip(targetLayout) { baseLine, targetLine ->
- val runs =
- baseLine.zip(targetLine) { base, target ->
- require(base.glyphCount() == target.glyphCount()) {
- "Inconsistent glyph count at line ${lines.size}"
+ lines = baseLayout.zip(targetLayout) { baseLine, targetLine ->
+ val runs = baseLine.zip(targetLine) { base, target ->
+
+ require(base.glyphCount() == target.glyphCount()) {
+ "Inconsistent glyph count at line ${lines.size}"
+ }
+
+ val glyphCount = base.glyphCount()
+
+ // Good to recycle the array if the existing array can hold the new layout result.
+ val glyphIds = IntArray(glyphCount) {
+ base.getGlyphId(it).also { baseGlyphId ->
+ require(baseGlyphId == target.getGlyphId(it)) {
+ "Inconsistent glyph ID at $it in line ${lines.size}"
}
+ }
+ }
- val glyphCount = base.glyphCount()
+ val baseX = FloatArray(glyphCount) { base.getGlyphX(it) }
+ val baseY = FloatArray(glyphCount) { base.getGlyphY(it) }
+ val targetX = FloatArray(glyphCount) { target.getGlyphX(it) }
+ val targetY = FloatArray(glyphCount) { target.getGlyphY(it) }
- // Good to recycle the array if the existing array can hold the new layout
- // result.
- val glyphIds =
- IntArray(glyphCount) {
- base.getGlyphId(it).also { baseGlyphId ->
- require(baseGlyphId == target.getGlyphId(it)) {
- "Inconsistent glyph ID at $it in line ${lines.size}"
- }
- }
+ // Calculate font runs
+ val fontRun = mutableListOf<FontRun>()
+ if (glyphCount != 0) {
+ var start = 0
+ var baseFont = base.getFont(start)
+ var targetFont = target.getFont(start)
+ require(FontInterpolator.canInterpolate(baseFont, targetFont)) {
+ "Cannot interpolate font at $start ($baseFont vs $targetFont)"
+ }
+
+ for (i in 1 until glyphCount) {
+ val nextBaseFont = base.getFont(i)
+ val nextTargetFont = target.getFont(i)
+
+ if (baseFont !== nextBaseFont) {
+ require(targetFont !== nextTargetFont) {
+ "Base font has changed at $i but target font has not changed."
}
-
- val baseX = FloatArray(glyphCount) { base.getGlyphX(it) }
- val baseY = FloatArray(glyphCount) { base.getGlyphY(it) }
- val targetX = FloatArray(glyphCount) { target.getGlyphX(it) }
- val targetY = FloatArray(glyphCount) { target.getGlyphY(it) }
-
- // Calculate font runs
- val fontRun = mutableListOf<FontRun>()
- if (glyphCount != 0) {
- var start = 0
- var baseFont = base.getFont(start)
- var targetFont = target.getFont(start)
+ // Font transition point. push run and reset context.
+ fontRun.add(FontRun(start, i, baseFont, targetFont))
+ maxRunLength = max(maxRunLength, i - start)
+ baseFont = nextBaseFont
+ targetFont = nextTargetFont
+ start = i
require(FontInterpolator.canInterpolate(baseFont, targetFont)) {
"Cannot interpolate font at $start ($baseFont vs $targetFont)"
}
-
- for (i in 1 until glyphCount) {
- val nextBaseFont = base.getFont(i)
- val nextTargetFont = target.getFont(i)
-
- if (baseFont !== nextBaseFont) {
- require(targetFont !== nextTargetFont) {
- "Base font has changed at $i but target font has not " +
- "changed."
- }
- // Font transition point. push run and reset context.
- fontRun.add(FontRun(start, i, baseFont, targetFont))
- maxRunLength = max(maxRunLength, i - start)
- baseFont = nextBaseFont
- targetFont = nextTargetFont
- start = i
- require(FontInterpolator.canInterpolate(baseFont, targetFont)) {
- "Cannot interpolate font at $start ($baseFont vs " +
- "$targetFont)"
- }
- } else { // baseFont === nextBaseFont
- require(targetFont === nextTargetFont) {
- "Base font has not changed at $i but target font has " +
- "changed."
- }
- }
+ } else { // baseFont === nextBaseFont
+ require(targetFont === nextTargetFont) {
+ "Base font has not changed at $i but target font has changed."
}
- fontRun.add(FontRun(start, glyphCount, baseFont, targetFont))
- maxRunLength = max(maxRunLength, glyphCount - start)
}
- Run(glyphIds, baseX, baseY, targetX, targetY, fontRun)
}
- Line(runs)
+ fontRun.add(FontRun(start, glyphCount, baseFont, targetFont))
+ maxRunLength = max(maxRunLength, glyphCount - start)
+ }
+ Run(glyphIds, baseX, baseY, targetX, targetY, fontRun)
}
+ Line(runs)
+ }
// Update float array used for drawing.
if (tmpPositionArray.size < maxRunLength * 2) {
@@ -351,9 +357,9 @@
if (glyphFilter == null) {
for (i in run.start until run.end) {
tmpPositionArray[arrayIndex++] =
- MathUtils.lerp(line.baseX[i], line.targetX[i], progress)
+ MathUtils.lerp(line.baseX[i], line.targetX[i], progress)
tmpPositionArray[arrayIndex++] =
- MathUtils.lerp(line.baseY[i], line.targetY[i], progress)
+ MathUtils.lerp(line.baseY[i], line.targetY[i], progress)
}
c.drawGlyphs(line.glyphIds, run.start, tmpPositionArray, 0, run.length, font, paint)
return
@@ -382,14 +388,13 @@
tmpPaintForGlyph.color = tmpGlyph.color
c.drawGlyphs(
- line.glyphIds,
- prevStart,
- tmpPositionArray,
- 0,
- i - prevStart,
- font,
- tmpPaintForGlyph
- )
+ line.glyphIds,
+ prevStart,
+ tmpPositionArray,
+ 0,
+ i - prevStart,
+ font,
+ tmpPaintForGlyph)
prevStart = i
arrayIndex = 0
}
@@ -399,14 +404,13 @@
}
c.drawGlyphs(
- line.glyphIds,
- prevStart,
- tmpPositionArray,
- 0,
- run.end - prevStart,
- font,
- tmpPaintForGlyph
- )
+ line.glyphIds,
+ prevStart,
+ tmpPositionArray,
+ 0,
+ run.end - prevStart,
+ font,
+ tmpPaintForGlyph)
}
private fun updatePositionsAndFonts(
@@ -414,7 +418,9 @@
updateBase: Boolean
) {
// Update target positions with newly calculated text layout.
- check(layoutResult.size == lines.size) { "The new layout result has different line count." }
+ check(layoutResult.size == lines.size) {
+ "The new layout result has different line count."
+ }
lines.zip(layoutResult) { line, runs ->
line.runs.zip(runs) { lineRun, newGlyphs ->
@@ -430,7 +436,7 @@
}
require(newFont === newGlyphs.getFont(i)) {
"The new layout has different font run." +
- " $newFont vs ${newGlyphs.getFont(i)} at $i"
+ " $newFont vs ${newGlyphs.getFont(i)} at $i"
}
}
@@ -438,7 +444,7 @@
// check new font can be interpolatable with base font.
require(FontInterpolator.canInterpolate(newFont, run.baseFont)) {
"New font cannot be interpolated with existing font. $newFont," +
- " ${run.baseFont}"
+ " ${run.baseFont}"
}
if (updateBase) {
@@ -474,7 +480,10 @@
}
// Shape the text and stores the result to out argument.
- private fun shapeText(layout: Layout, paint: TextPaint): List<List<PositionedGlyphs>> {
+ private fun shapeText(
+ layout: Layout,
+ paint: TextPaint
+ ): List<List<PositionedGlyphs>> {
val out = mutableListOf<List<PositionedGlyphs>>()
for (lineNo in 0 until layout.lineCount) { // Shape all lines.
val lineStart = layout.getLineStart(lineNo)
@@ -486,13 +495,10 @@
}
val runs = mutableListOf<PositionedGlyphs>()
- TextShaper.shapeText(
- layout.text,
- lineStart,
- count,
- layout.textDirectionHeuristic,
- paint
- ) { _, _, glyphs, _ -> runs.add(glyphs) }
+ TextShaper.shapeText(layout.text, lineStart, count, layout.textDirectionHeuristic,
+ paint) { _, _, glyphs, _ ->
+ runs.add(glyphs)
+ }
out.add(runs)
}
return out
@@ -500,8 +506,8 @@
}
private fun Layout.getDrawOrigin(lineNo: Int) =
- if (getParagraphDirection(lineNo) == Layout.DIR_LEFT_TO_RIGHT) {
- getLineLeft(lineNo)
- } else {
- getLineRight(lineNo)
- }
+ if (getParagraphDirection(lineNo) == Layout.DIR_LEFT_TO_RIGHT) {
+ getLineLeft(lineNo)
+ } else {
+ getLineRight(lineNo)
+ }
diff --git a/packages/SystemUI/checks/Android.bp b/packages/SystemUI/checks/Android.bp
index 40580d2..d3f66e3 100644
--- a/packages/SystemUI/checks/Android.bp
+++ b/packages/SystemUI/checks/Android.bp
@@ -37,12 +37,6 @@
java_test_host {
name: "SystemUILintCheckerTest",
- // TODO(b/239881504): Since this test was written, Android
- // Lint was updated, and now includes classes that were
- // compiled for java 15. The soong build doesn't support
- // java 15 yet, so we can't compile against "lint". Disable
- // the test until java 15 is supported.
- enabled: false,
srcs: [
"tests/**/*.kt",
"tests/**/*.java",
@@ -59,5 +53,19 @@
],
test_options: {
unit_test: true,
+ tradefed_options: [
+ {
+ // lint bundles in some classes that were built with older versions
+ // of libraries, and no longer load. Since tradefed tries to load
+ // all classes in the jar to look for tests, it crashes loading them.
+ // Exclude these classes from tradefed's search.
+ name: "exclude-paths",
+ value: "org/apache",
+ },
+ {
+ name: "exclude-paths",
+ value: "META-INF",
+ },
+ ],
},
}
diff --git a/packages/SystemUI/customization/src/com/android/systemui/shared/clocks/AnimatableClockView.kt b/packages/SystemUI/customization/src/com/android/systemui/shared/clocks/AnimatableClockView.kt
index 462b90a..86bd5f2 100644
--- a/packages/SystemUI/customization/src/com/android/systemui/shared/clocks/AnimatableClockView.kt
+++ b/packages/SystemUI/customization/src/com/android/systemui/shared/clocks/AnimatableClockView.kt
@@ -54,7 +54,6 @@
defStyleAttr: Int = 0,
defStyleRes: Int = 0
) : TextView(context, attrs, defStyleAttr, defStyleRes) {
- var tag: String = "UnnamedClockView"
var logBuffer: LogBuffer? = null
private val time = Calendar.getInstance()
@@ -132,7 +131,7 @@
override fun onAttachedToWindow() {
super.onAttachedToWindow()
- logBuffer?.log(tag, DEBUG, "onAttachedToWindow")
+ logBuffer?.log(TAG, DEBUG, "onAttachedToWindow")
refreshFormat()
}
@@ -148,7 +147,7 @@
time.timeInMillis = timeOverrideInMillis ?: System.currentTimeMillis()
contentDescription = DateFormat.format(descFormat, time)
val formattedText = DateFormat.format(format, time)
- logBuffer?.log(tag, DEBUG,
+ logBuffer?.log(TAG, DEBUG,
{ str1 = formattedText?.toString() },
{ "refreshTime: new formattedText=$str1" }
)
@@ -157,7 +156,7 @@
// relayout if the text didn't actually change.
if (!TextUtils.equals(text, formattedText)) {
text = formattedText
- logBuffer?.log(tag, DEBUG,
+ logBuffer?.log(TAG, DEBUG,
{ str1 = formattedText?.toString() },
{ "refreshTime: done setting new time text to: $str1" }
)
@@ -167,17 +166,17 @@
// without being notified TextInterpolator being notified.
if (layout != null) {
textAnimator?.updateLayout(layout)
- logBuffer?.log(tag, DEBUG, "refreshTime: done updating textAnimator layout")
+ logBuffer?.log(TAG, DEBUG, "refreshTime: done updating textAnimator layout")
}
requestLayout()
- logBuffer?.log(tag, DEBUG, "refreshTime: after requestLayout")
+ logBuffer?.log(TAG, DEBUG, "refreshTime: after requestLayout")
}
}
fun onTimeZoneChanged(timeZone: TimeZone?) {
time.timeZone = timeZone
refreshFormat()
- logBuffer?.log(tag, DEBUG,
+ logBuffer?.log(TAG, DEBUG,
{ str1 = timeZone?.toString() },
{ "onTimeZoneChanged newTimeZone=$str1" }
)
@@ -194,7 +193,7 @@
} else {
animator.updateLayout(layout)
}
- logBuffer?.log(tag, DEBUG, "onMeasure")
+ logBuffer?.log(TAG, DEBUG, "onMeasure")
}
override fun onDraw(canvas: Canvas) {
@@ -206,12 +205,12 @@
} else {
super.onDraw(canvas)
}
- logBuffer?.log(tag, DEBUG, "onDraw lastDraw")
+ logBuffer?.log(TAG, DEBUG, "onDraw")
}
override fun invalidate() {
super.invalidate()
- logBuffer?.log(tag, DEBUG, "invalidate")
+ logBuffer?.log(TAG, DEBUG, "invalidate")
}
override fun onTextChanged(
@@ -221,7 +220,7 @@
lengthAfter: Int
) {
super.onTextChanged(text, start, lengthBefore, lengthAfter)
- logBuffer?.log(tag, DEBUG,
+ logBuffer?.log(TAG, DEBUG,
{ str1 = text.toString() },
{ "onTextChanged text=$str1" }
)
@@ -238,7 +237,7 @@
}
fun animateColorChange() {
- logBuffer?.log(tag, DEBUG, "animateColorChange")
+ logBuffer?.log(TAG, DEBUG, "animateColorChange")
setTextStyle(
weight = lockScreenWeight,
textSize = -1f,
@@ -260,7 +259,7 @@
}
fun animateAppearOnLockscreen() {
- logBuffer?.log(tag, DEBUG, "animateAppearOnLockscreen")
+ logBuffer?.log(TAG, DEBUG, "animateAppearOnLockscreen")
setTextStyle(
weight = dozingWeight,
textSize = -1f,
@@ -285,7 +284,7 @@
if (isAnimationEnabled && textAnimator == null) {
return
}
- logBuffer?.log(tag, DEBUG, "animateFoldAppear")
+ logBuffer?.log(TAG, DEBUG, "animateFoldAppear")
setTextStyle(
weight = lockScreenWeightInternal,
textSize = -1f,
@@ -312,7 +311,7 @@
// Skip charge animation if dozing animation is already playing.
return
}
- logBuffer?.log(tag, DEBUG, "animateCharge")
+ logBuffer?.log(TAG, DEBUG, "animateCharge")
val startAnimPhase2 = Runnable {
setTextStyle(
weight = if (isDozing()) dozingWeight else lockScreenWeight,
@@ -336,7 +335,7 @@
}
fun animateDoze(isDozing: Boolean, animate: Boolean) {
- logBuffer?.log(tag, DEBUG, "animateDoze")
+ logBuffer?.log(TAG, DEBUG, "animateDoze")
setTextStyle(
weight = if (isDozing) dozingWeight else lockScreenWeight,
textSize = -1f,
@@ -455,7 +454,7 @@
isSingleLineInternal && !use24HourFormat -> Patterns.sClockView12
else -> DOUBLE_LINE_FORMAT_12_HOUR
}
- logBuffer?.log(tag, DEBUG,
+ logBuffer?.log(TAG, DEBUG,
{ str1 = format?.toString() },
{ "refreshFormat format=$str1" }
)
@@ -466,6 +465,7 @@
fun dump(pw: PrintWriter) {
pw.println("$this")
+ pw.println(" alpha=$alpha")
pw.println(" measuredWidth=$measuredWidth")
pw.println(" measuredHeight=$measuredHeight")
pw.println(" singleLineInternal=$isSingleLineInternal")
@@ -626,7 +626,7 @@
}
companion object {
- private val TAG = AnimatableClockView::class.simpleName
+ private val TAG = AnimatableClockView::class.simpleName!!
const val ANIMATION_DURATION_FOLD_TO_AOD: Int = 600
private const val DOUBLE_LINE_FORMAT_12_HOUR = "hh\nmm"
private const val DOUBLE_LINE_FORMAT_24_HOUR = "HH\nmm"
diff --git a/packages/SystemUI/customization/src/com/android/systemui/shared/clocks/DefaultClockController.kt b/packages/SystemUI/customization/src/com/android/systemui/shared/clocks/DefaultClockController.kt
index e138ef8..7645dec 100644
--- a/packages/SystemUI/customization/src/com/android/systemui/shared/clocks/DefaultClockController.kt
+++ b/packages/SystemUI/customization/src/com/android/systemui/shared/clocks/DefaultClockController.kt
@@ -88,13 +88,6 @@
events.onTimeTick()
}
- override fun setLogBuffer(logBuffer: LogBuffer) {
- smallClock.view.tag = "smallClockView"
- largeClock.view.tag = "largeClockView"
- smallClock.view.logBuffer = logBuffer
- largeClock.view.logBuffer = logBuffer
- }
-
open inner class DefaultClockFaceController(
override val view: AnimatableClockView,
) : ClockFaceController {
@@ -104,6 +97,12 @@
private var isRegionDark = false
protected var targetRegion: Rect? = null
+ override var logBuffer: LogBuffer?
+ get() = view.logBuffer
+ set(value) {
+ view.logBuffer = value
+ }
+
init {
view.setColors(currentColor, currentColor)
}
diff --git a/packages/SystemUI/ktfmt_includes.txt b/packages/SystemUI/ktfmt_includes.txt
index 4c271ea..2148cb0 100644
--- a/packages/SystemUI/ktfmt_includes.txt
+++ b/packages/SystemUI/ktfmt_includes.txt
@@ -80,8 +80,8 @@
-packages/SystemUI/src/com/android/systemui/biometrics/UdfpsControllerOverlay.kt
-packages/SystemUI/src/com/android/systemui/biometrics/UdfpsDrawable.kt
-packages/SystemUI/src/com/android/systemui/biometrics/UdfpsFpDrawable.kt
--packages/SystemUI/src/com/android/systemui/biometrics/UdfpsFpmOtherView.kt
--packages/SystemUI/src/com/android/systemui/biometrics/UdfpsFpmOtherViewController.kt
+-packages/SystemUI/src/com/android/systemui/biometrics/UdfpsFpmEmptyView.kt
+-packages/SystemUI/src/com/android/systemui/biometrics/UdfpsFpmEmptyViewController.kt
-packages/SystemUI/src/com/android/systemui/biometrics/UdfpsHapticsSimulator.kt
-packages/SystemUI/src/com/android/systemui/biometrics/UdfpsOverlayParams.kt
-packages/SystemUI/src/com/android/systemui/biometrics/UdfpsShell.kt
diff --git a/packages/SystemUI/plugin/src/com/android/systemui/plugins/ClockProviderPlugin.kt b/packages/SystemUI/plugin/src/com/android/systemui/plugins/ClockProviderPlugin.kt
index 66e44b9..a2a0709 100644
--- a/packages/SystemUI/plugin/src/com/android/systemui/plugins/ClockProviderPlugin.kt
+++ b/packages/SystemUI/plugin/src/com/android/systemui/plugins/ClockProviderPlugin.kt
@@ -71,9 +71,6 @@
/** Optional method for dumping debug information */
fun dump(pw: PrintWriter) {}
-
- /** Optional method for debug logging */
- fun setLogBuffer(logBuffer: LogBuffer) {}
}
/** Interface for a specific clock face version rendered by the clock */
@@ -83,6 +80,9 @@
/** Events specific to this clock face */
val events: ClockFaceEvents
+
+ /** Some clocks may log debug information */
+ var logBuffer: LogBuffer?
}
/** Events that should call when various rendering parameters change */
diff --git a/packages/SystemUI/plugin/src/com/android/systemui/plugins/GlobalActionsPanelPlugin.java b/packages/SystemUI/plugin/src/com/android/systemui/plugins/GlobalActionsPanelPlugin.java
index d0694ab..429458f 100644
--- a/packages/SystemUI/plugin/src/com/android/systemui/plugins/GlobalActionsPanelPlugin.java
+++ b/packages/SystemUI/plugin/src/com/android/systemui/plugins/GlobalActionsPanelPlugin.java
@@ -17,6 +17,7 @@
package com.android.systemui.plugins;
import android.annotation.Nullable;
+import android.app.BroadcastOptions;
import android.app.PendingIntent;
import android.graphics.drawable.Drawable;
import android.view.View;
@@ -70,7 +71,9 @@
/** Starts a PendingIntent, dismissing the keyguard if necessary. */
default void startPendingIntentDismissingKeyguard(PendingIntent pendingIntent) {
try {
- pendingIntent.send();
+ BroadcastOptions options = BroadcastOptions.makeBasic();
+ options.setInteractive(true);
+ pendingIntent.send(options.toBundle());
} catch (PendingIntent.CanceledException e) {
// no-op
}
diff --git a/packages/SystemUI/plugin/src/com/android/systemui/plugins/log/LogBuffer.kt b/packages/SystemUI/plugin/src/com/android/systemui/plugins/log/LogBuffer.kt
index 6436dcb..e99b214 100644
--- a/packages/SystemUI/plugin/src/com/android/systemui/plugins/log/LogBuffer.kt
+++ b/packages/SystemUI/plugin/src/com/android/systemui/plugins/log/LogBuffer.kt
@@ -159,8 +159,13 @@
* bug report more actionable, so using the [log] with a messagePrinter to add more detail to
* every log may do more to improve overall logging than adding more logs with this method.
*/
- fun log(tag: String, level: LogLevel, @CompileTimeConstant message: String) =
- log(tag, level, { str1 = message }, { str1!! })
+ @JvmOverloads
+ fun log(
+ tag: String,
+ level: LogLevel,
+ @CompileTimeConstant message: String,
+ exception: Throwable? = null,
+ ) = log(tag, level, { str1 = message }, { str1!! }, exception)
/**
* You should call [log] instead of this method.
diff --git a/packages/SystemUI/proguard.flags b/packages/SystemUI/proguard.flags
index e598afe..a4ee62c 100644
--- a/packages/SystemUI/proguard.flags
+++ b/packages/SystemUI/proguard.flags
@@ -19,6 +19,18 @@
public <init>();
}
+# Needed to ensure callback field references are kept in their respective
+# owning classes when the downstream callback registrars only store weak refs.
+# TODO(b/264686688): Handle these cases with more targeted annotations.
+-keepclassmembers,allowaccessmodification class com.android.systemui.**, com.android.keyguard.** {
+ private com.android.keyguard.KeyguardUpdateMonitorCallback *;
+ private com.android.systemui.privacy.PrivacyItemController$Callback *;
+ private com.android.systemui.settings.UserTracker$Callback *;
+ private com.android.systemui.statusbar.phone.StatusBarWindowCallback *;
+ private com.android.systemui.util.service.Observer$Callback *;
+ private com.android.systemui.util.service.ObservableServiceConnection$Callback *;
+}
+
-keepclasseswithmembers class * {
public <init>(android.content.Context, android.util.AttributeSet);
}
diff --git a/packages/SystemUI/res/drawable/ic_media_explicit_indicator.xml b/packages/SystemUI/res/drawable/ic_media_explicit_indicator.xml
new file mode 100644
index 0000000..08c5aaf
--- /dev/null
+++ b/packages/SystemUI/res/drawable/ic_media_explicit_indicator.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ 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
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="13dp"
+ android:height="13dp"
+ android:viewportWidth="48"
+ android:viewportHeight="48"
+ android:tint="?attr/colorControlNormal">
+ <path
+ android:fillColor="@android:color/white"
+ android:pathData="M18.3,34H29.65V31H21.3V25.7H29.65V22.7H21.3V17.35H29.65V14.35H18.3ZM9,42Q7.8,42 6.9,41.1Q6,40.2 6,39V9Q6,7.8 6.9,6.9Q7.8,6 9,6H39Q40.2,6 41.1,6.9Q42,7.8 42,9V39Q42,40.2 41.1,41.1Q40.2,42 39,42ZM9,39H39Q39,39 39,39Q39,39 39,39V9Q39,9 39,9Q39,9 39,9H9Q9,9 9,9Q9,9 9,9V39Q9,39 9,39Q9,39 9,39ZM9,9Q9,9 9,9Q9,9 9,9V39Q9,39 9,39Q9,39 9,39Q9,39 9,39Q9,39 9,39V9Q9,9 9,9Q9,9 9,9Z"/>
+</vector>
diff --git a/packages/SystemUI/res/drawable/overlay_badge_background.xml b/packages/SystemUI/res/drawable/overlay_badge_background.xml
index 857632e..53122c1 100644
--- a/packages/SystemUI/res/drawable/overlay_badge_background.xml
+++ b/packages/SystemUI/res/drawable/overlay_badge_background.xml
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
- ~ Copyright (C) 2020 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,8 +14,11 @@
~ See the License for the specific language governing permissions and
~ limitations under the License.
-->
-<shape xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:androidprv="http://schemas.android.com/apk/prv/res/android"
- android:shape="oval">
- <solid android:color="?androidprv:attr/colorSurface"/>
-</shape>
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="48dp"
+ android:height="48dp"
+ android:viewportWidth="48.0"
+ android:viewportHeight="48.0">
+ <path
+ android:pathData="M0,0M48,48"/>
+</vector>
diff --git a/packages/SystemUI/res/layout/chipbar.xml b/packages/SystemUI/res/layout/chipbar.xml
index bc97e51..8cf4f4d 100644
--- a/packages/SystemUI/res/layout/chipbar.xml
+++ b/packages/SystemUI/res/layout/chipbar.xml
@@ -23,6 +23,7 @@
android:layout_width="wrap_content"
android:layout_height="wrap_content">
+ <!-- Extra marginBottom to give room for the drop shadow. -->
<LinearLayout
android:id="@+id/chipbar_inner"
android:orientation="horizontal"
@@ -33,6 +34,8 @@
android:layout_marginTop="20dp"
android:layout_marginStart="@dimen/notification_side_paddings"
android:layout_marginEnd="@dimen/notification_side_paddings"
+ android:translationZ="4dp"
+ android:layout_marginBottom="8dp"
android:clipToPadding="false"
android:gravity="center_vertical"
android:alpha="0.0"
diff --git a/packages/SystemUI/res/layout/clipboard_overlay.xml b/packages/SystemUI/res/layout/clipboard_overlay.xml
index 9134f96..eec3b11 100644
--- a/packages/SystemUI/res/layout/clipboard_overlay.xml
+++ b/packages/SystemUI/res/layout/clipboard_overlay.xml
@@ -32,26 +32,26 @@
android:elevation="4dp"
android:background="@drawable/action_chip_container_background"
android:layout_marginStart="@dimen/overlay_action_container_margin_horizontal"
- app:layout_constraintBottom_toBottomOf="@+id/actions_container"
+ android:layout_marginBottom="@dimen/overlay_action_container_margin_bottom"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="@+id/actions_container"
- app:layout_constraintEnd_toEndOf="@+id/actions_container"/>
+ app:layout_constraintEnd_toEndOf="@+id/actions_container"
+ app:layout_constraintBottom_toBottomOf="parent"/>
<HorizontalScrollView
android:id="@+id/actions_container"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginEnd="@dimen/overlay_action_container_margin_horizontal"
- android:paddingEnd="@dimen/overlay_action_container_padding_right"
+ android:paddingEnd="@dimen/overlay_action_container_padding_end"
android:paddingVertical="@dimen/overlay_action_container_padding_vertical"
android:elevation="4dp"
android:scrollbars="none"
- android:layout_marginBottom="4dp"
app:layout_constraintHorizontal_bias="0"
app:layout_constraintWidth_percent="1.0"
app:layout_constraintWidth_max="wrap"
- app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintStart_toEndOf="@+id/preview_border"
- app:layout_constraintEnd_toEndOf="parent">
+ app:layout_constraintEnd_toEndOf="parent"
+ app:layout_constraintBottom_toBottomOf="@id/actions_container_background">
<LinearLayout
android:id="@+id/actions"
android:layout_width="wrap_content"
@@ -69,44 +69,30 @@
android:id="@+id/preview_border"
android:layout_width="0dp"
android:layout_height="0dp"
- android:layout_marginStart="@dimen/overlay_offset_x"
- android:layout_marginBottom="12dp"
- app:layout_constraintStart_toStartOf="parent"
- app:layout_constraintBottom_toBottomOf="parent"
+ android:layout_marginStart="@dimen/overlay_preview_container_margin"
+ android:layout_marginTop="@dimen/overlay_border_width_neg"
+ android:layout_marginEnd="@dimen/overlay_border_width_neg"
+ android:layout_marginBottom="@dimen/overlay_preview_container_margin"
android:elevation="7dp"
- app:layout_constraintEnd_toEndOf="@id/clipboard_preview_end"
- app:layout_constraintTop_toTopOf="@id/clipboard_preview_top"
- android:background="@drawable/overlay_border"/>
- <androidx.constraintlayout.widget.Barrier
- android:id="@+id/clipboard_preview_end"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- app:barrierMargin="@dimen/overlay_border_width"
- app:barrierDirection="end"
- app:constraint_referenced_ids="clipboard_preview"/>
- <androidx.constraintlayout.widget.Barrier
- android:id="@+id/clipboard_preview_top"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- app:barrierDirection="top"
- app:barrierMargin="@dimen/overlay_border_width_neg"
- app:constraint_referenced_ids="clipboard_preview"/>
+ android:background="@drawable/overlay_border"
+ app:layout_constraintStart_toStartOf="@id/actions_container_background"
+ app:layout_constraintTop_toTopOf="@id/clipboard_preview"
+ app:layout_constraintEnd_toEndOf="@id/clipboard_preview"
+ app:layout_constraintBottom_toBottomOf="@id/actions_container_background"/>
<FrameLayout
android:id="@+id/clipboard_preview"
+ android:layout_width="@dimen/clipboard_preview_size"
+ android:layout_height="wrap_content"
+ android:layout_marginStart="@dimen/overlay_border_width"
+ android:layout_marginBottom="@dimen/overlay_border_width"
+ android:layout_gravity="center"
android:elevation="7dp"
android:background="@drawable/overlay_preview_background"
android:clipChildren="true"
android:clipToOutline="true"
android:clipToPadding="true"
- android:layout_width="@dimen/clipboard_preview_size"
- android:layout_margin="@dimen/overlay_border_width"
- android:layout_height="wrap_content"
- android:layout_gravity="center"
- app:layout_constraintHorizontal_bias="0"
- app:layout_constraintBottom_toBottomOf="@id/preview_border"
app:layout_constraintStart_toStartOf="@id/preview_border"
- app:layout_constraintEnd_toEndOf="@id/preview_border"
- app:layout_constraintTop_toTopOf="@id/preview_border">
+ app:layout_constraintBottom_toBottomOf="@id/preview_border">
<TextView android:id="@+id/text_preview"
android:textFontWeight="500"
android:padding="8dp"
diff --git a/packages/SystemUI/res/layout/combined_qs_header.xml b/packages/SystemUI/res/layout/combined_qs_header.xml
index a565988..d689828 100644
--- a/packages/SystemUI/res/layout/combined_qs_header.xml
+++ b/packages/SystemUI/res/layout/combined_qs_header.xml
@@ -148,9 +148,4 @@
<include layout="@layout/ongoing_privacy_chip"/>
</FrameLayout>
- <Space
- android:layout_width="0dp"
- android:layout_height="0dp"
- android:id="@+id/space"
- />
</com.android.systemui.util.NoRemeasureMotionLayout>
\ No newline at end of file
diff --git a/packages/SystemUI/res/layout/dream_overlay_status_bar_view.xml b/packages/SystemUI/res/layout/dream_overlay_status_bar_view.xml
index 9add32c..885e5e2 100644
--- a/packages/SystemUI/res/layout/dream_overlay_status_bar_view.xml
+++ b/packages/SystemUI/res/layout/dream_overlay_status_bar_view.xml
@@ -57,6 +57,7 @@
android:layout_width="@dimen/dream_overlay_status_bar_icon_size"
android:layout_height="match_parent"
android:layout_marginStart="@dimen/dream_overlay_status_icon_margin"
+ android:layout_marginTop="@dimen/dream_overlay_status_bar_marginTop"
android:src="@drawable/ic_alarm"
android:tint="@android:color/white"
android:visibility="gone"
@@ -67,6 +68,7 @@
android:layout_width="@dimen/dream_overlay_status_bar_icon_size"
android:layout_height="match_parent"
android:layout_marginStart="@dimen/dream_overlay_status_icon_margin"
+ android:layout_marginTop="@dimen/dream_overlay_status_bar_marginTop"
android:src="@drawable/ic_qs_dnd_on"
android:tint="@android:color/white"
android:visibility="gone"
@@ -77,6 +79,7 @@
android:layout_width="@dimen/dream_overlay_status_bar_icon_size"
android:layout_height="match_parent"
android:layout_marginStart="@dimen/dream_overlay_status_icon_margin"
+ android:layout_marginTop="@dimen/dream_overlay_status_bar_marginTop"
android:src="@drawable/ic_signal_wifi_off"
android:visibility="gone"
android:contentDescription="@string/dream_overlay_status_bar_wifi_off" />
diff --git a/packages/SystemUI/res/layout/media_session_view.xml b/packages/SystemUI/res/layout/media_session_view.xml
index 95aefab..abc8337 100644
--- a/packages/SystemUI/res/layout/media_session_view.xml
+++ b/packages/SystemUI/res/layout/media_session_view.xml
@@ -147,6 +147,14 @@
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
+ <!-- Explicit Indicator -->
+ <com.android.internal.widget.CachingIconView
+ android:id="@+id/media_explicit_indicator"
+ android:layout_width="@dimen/qs_media_explicit_indicator_icon_size"
+ android:layout_height="@dimen/qs_media_explicit_indicator_icon_size"
+ android:src="@drawable/ic_media_explicit_indicator"
+ />
+
<!-- Artist name -->
<TextView
android:id="@+id/header_artist"
diff --git a/packages/SystemUI/res/layout/screenshot_static.xml b/packages/SystemUI/res/layout/screenshot_static.xml
index e4e0bd4..496eb6e 100644
--- a/packages/SystemUI/res/layout/screenshot_static.xml
+++ b/packages/SystemUI/res/layout/screenshot_static.xml
@@ -27,26 +27,26 @@
android:elevation="4dp"
android:background="@drawable/action_chip_container_background"
android:layout_marginStart="@dimen/overlay_action_container_margin_horizontal"
- app:layout_constraintBottom_toBottomOf="@+id/actions_container"
+ android:layout_marginBottom="@dimen/overlay_action_container_margin_bottom"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="@+id/actions_container"
- app:layout_constraintEnd_toEndOf="@+id/actions_container"/>
+ app:layout_constraintEnd_toEndOf="@+id/actions_container"
+ app:layout_constraintBottom_toTopOf="@id/screenshot_message_container"/>
<HorizontalScrollView
android:id="@+id/actions_container"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginEnd="@dimen/overlay_action_container_margin_horizontal"
- android:layout_marginBottom="4dp"
- android:paddingEnd="@dimen/overlay_action_container_padding_right"
+ android:paddingEnd="@dimen/overlay_action_container_padding_end"
android:paddingVertical="@dimen/overlay_action_container_padding_vertical"
android:elevation="4dp"
android:scrollbars="none"
app:layout_constraintHorizontal_bias="0"
app:layout_constraintWidth_percent="1.0"
app:layout_constraintWidth_max="wrap"
- app:layout_constraintBottom_toTopOf="@id/screenshot_message_container"
app:layout_constraintStart_toEndOf="@+id/screenshot_preview_border"
- app:layout_constraintEnd_toEndOf="parent">
+ app:layout_constraintEnd_toEndOf="parent"
+ app:layout_constraintBottom_toBottomOf="@id/actions_container_background">
<LinearLayout
android:id="@+id/screenshot_actions"
android:layout_width="wrap_content"
@@ -64,35 +64,24 @@
android:id="@+id/screenshot_preview_border"
android:layout_width="0dp"
android:layout_height="0dp"
- android:layout_marginStart="@dimen/overlay_offset_x"
- android:layout_marginBottom="12dp"
+ android:layout_marginStart="@dimen/overlay_preview_container_margin"
+ android:layout_marginTop="@dimen/overlay_border_width_neg"
+ android:layout_marginEnd="@dimen/overlay_border_width_neg"
+ android:layout_marginBottom="@dimen/overlay_preview_container_margin"
android:elevation="7dp"
android:alpha="0"
android:background="@drawable/overlay_border"
- app:layout_constraintStart_toStartOf="parent"
- app:layout_constraintBottom_toTopOf="@id/screenshot_message_container"
- app:layout_constraintEnd_toEndOf="@id/screenshot_preview_end"
- app:layout_constraintTop_toTopOf="@id/screenshot_preview_top"/>
- <androidx.constraintlayout.widget.Barrier
- android:id="@+id/screenshot_preview_end"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- app:barrierMargin="@dimen/overlay_border_width"
- app:barrierDirection="end"
- app:constraint_referenced_ids="screenshot_preview"/>
- <androidx.constraintlayout.widget.Barrier
- android:id="@+id/screenshot_preview_top"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- app:barrierDirection="top"
- app:barrierMargin="@dimen/overlay_border_width_neg"
- app:constraint_referenced_ids="screenshot_preview"/>
+ app:layout_constraintStart_toStartOf="@id/actions_container_background"
+ app:layout_constraintTop_toTopOf="@id/screenshot_preview"
+ app:layout_constraintEnd_toEndOf="@id/screenshot_preview"
+ app:layout_constraintBottom_toBottomOf="@id/actions_container_background"/>
<ImageView
android:id="@+id/screenshot_preview"
android:visibility="invisible"
android:layout_width="@dimen/overlay_x_scale"
- android:layout_margin="@dimen/overlay_border_width"
android:layout_height="wrap_content"
+ android:layout_marginStart="@dimen/overlay_border_width"
+ android:layout_marginBottom="@dimen/overlay_border_width"
android:layout_gravity="center"
android:elevation="7dp"
android:contentDescription="@string/screenshot_edit_description"
@@ -100,20 +89,14 @@
android:background="@drawable/overlay_preview_background"
android:adjustViewBounds="true"
android:clickable="true"
- app:layout_constraintHorizontal_bias="0"
- app:layout_constraintBottom_toBottomOf="@id/screenshot_preview_border"
app:layout_constraintStart_toStartOf="@id/screenshot_preview_border"
- app:layout_constraintEnd_toEndOf="@id/screenshot_preview_border"
- app:layout_constraintTop_toTopOf="@id/screenshot_preview_border"/>
+ app:layout_constraintBottom_toBottomOf="@id/screenshot_preview_border"/>
<ImageView
android:id="@+id/screenshot_badge"
- android:layout_width="24dp"
- android:layout_height="24dp"
- android:padding="4dp"
+ android:layout_width="48dp"
+ android:layout_height="48dp"
android:visibility="gone"
- android:background="@drawable/overlay_badge_background"
android:elevation="8dp"
- android:src="@drawable/overlay_cancel"
app:layout_constraintBottom_toBottomOf="@id/screenshot_preview_border"
app:layout_constraintEnd_toEndOf="@id/screenshot_preview_border"/>
<FrameLayout
@@ -150,7 +133,7 @@
android:layout_height="wrap_content"
android:layout_marginHorizontal="@dimen/overlay_action_container_margin_horizontal"
android:layout_marginVertical="4dp"
- android:paddingHorizontal="@dimen/overlay_action_container_padding_right"
+ android:paddingHorizontal="@dimen/overlay_action_container_padding_end"
android:paddingVertical="@dimen/overlay_action_container_padding_vertical"
android:elevation="4dp"
android:background="@drawable/action_chip_container_background"
diff --git a/packages/SystemUI/res/layout/udfps_fpm_other_view.xml b/packages/SystemUI/res/layout/udfps_fpm_empty_view.xml
similarity index 75%
rename from packages/SystemUI/res/layout/udfps_fpm_other_view.xml
rename to packages/SystemUI/res/layout/udfps_fpm_empty_view.xml
index 6ecbb47..de43a5e 100644
--- a/packages/SystemUI/res/layout/udfps_fpm_other_view.xml
+++ b/packages/SystemUI/res/layout/udfps_fpm_empty_view.xml
@@ -14,15 +14,9 @@
~ See the License for the specific language governing permissions and
~ limitations under the License.
-->
-<com.android.systemui.biometrics.UdfpsFpmOtherView
+<com.android.systemui.biometrics.UdfpsFpmEmptyView
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/udfps_animation_view"
android:layout_width="match_parent"
android:layout_height="match_parent">
-
- <!-- Fingerprint -->
- <ImageView
- android:id="@+id/udfps_fpm_other_fp_view"
- android:layout_width="match_parent"
- android:layout_height="match_parent"/>
-</com.android.systemui.biometrics.UdfpsFpmOtherView>
+</com.android.systemui.biometrics.UdfpsFpmEmptyView>
diff --git a/packages/SystemUI/res/layout/user_switcher_fullscreen.xml b/packages/SystemUI/res/layout/user_switcher_fullscreen.xml
index fa9d739..7eaed43 100644
--- a/packages/SystemUI/res/layout/user_switcher_fullscreen.xml
+++ b/packages/SystemUI/res/layout/user_switcher_fullscreen.xml
@@ -46,7 +46,7 @@
app:layout_constraintEnd_toEndOf="parent"
app:flow_horizontalBias="0.5"
app:flow_verticalAlign="center"
- app:flow_wrapMode="chain"
+ app:flow_wrapMode="chain2"
app:flow_horizontalGap="@dimen/user_switcher_fullscreen_horizontal_gap"
app:flow_verticalGap="44dp"
app:flow_horizontalStyle="packed"/>
diff --git a/packages/SystemUI/res/values/config.xml b/packages/SystemUI/res/values/config.xml
index 7073f6a..3c2453e 100644
--- a/packages/SystemUI/res/values/config.xml
+++ b/packages/SystemUI/res/values/config.xml
@@ -440,6 +440,11 @@
This name is in the ComponentName flattened format (package/class) -->
<string name="config_screenshotEditor" translatable="false"></string>
+ <!-- ComponentName for the file browsing app that the system would expect to be used in work
+ profile. The icon for this app will be shown to the user when informing them that a
+ screenshot has been saved to work profile. If blank, a default icon will be shown. -->
+ <string name="config_sceenshotWorkProfileFilesApp" translatable="false"></string>
+
<!-- Remote copy default activity. Must handle REMOTE_COPY_ACTION intents.
This name is in the ComponentName flattened format (package/class) -->
<string name="config_remoteCopyPackage" translatable="false"></string>
@@ -666,6 +671,16 @@
<item>17</item> <!-- WAKE_REASON_BIOMETRIC -->
</integer-array>
+ <!-- Whether to support posture listening for face auth, default is 0(DEVICE_POSTURE_UNKNOWN)
+ means systemui will try listening on all postures.
+ 0 : DEVICE_POSTURE_UNKNOWN
+ 1 : DEVICE_POSTURE_CLOSED
+ 2 : DEVICE_POSTURE_HALF_OPENED
+ 3 : DEVICE_POSTURE_OPENED
+ 4 : DEVICE_POSTURE_FLIPPED
+ -->
+ <integer name="config_face_auth_supported_posture">0</integer>
+
<!-- Whether the communal service should be enabled -->
<bool name="config_communalServiceEnabled">false</bool>
diff --git a/packages/SystemUI/res/values/dimens.xml b/packages/SystemUI/res/values/dimens.xml
index 3b17bce..6d5eb6a 100644
--- a/packages/SystemUI/res/values/dimens.xml
+++ b/packages/SystemUI/res/values/dimens.xml
@@ -334,15 +334,22 @@
<dimen name="overlay_action_chip_spacing">8dp</dimen>
<dimen name="overlay_action_chip_text_size">14sp</dimen>
<dimen name="overlay_offset_x">16dp</dimen>
+ <!-- Used for both start and bottom margin of the preview, relative to the action container -->
+ <dimen name="overlay_preview_container_margin">8dp</dimen>
<dimen name="overlay_action_container_margin_horizontal">8dp</dimen>
+ <dimen name="overlay_action_container_margin_bottom">4dp</dimen>
<dimen name="overlay_bg_protection_height">242dp</dimen>
<dimen name="overlay_action_container_corner_radius">18dp</dimen>
<dimen name="overlay_action_container_padding_vertical">4dp</dimen>
<dimen name="overlay_action_container_padding_right">8dp</dimen>
+ <dimen name="overlay_action_container_padding_end">8dp</dimen>
<dimen name="overlay_dismiss_button_tappable_size">48dp</dimen>
<dimen name="overlay_dismiss_button_margin">8dp</dimen>
+ <!-- must be kept aligned with overlay_border_width_neg, below;
+ overlay_border_width = overlay_border_width_neg * -1 -->
<dimen name="overlay_border_width">4dp</dimen>
- <!-- need a negative margin for some of the constraints. should be overlay_border_width * -1 -->
+ <!-- some constraints use a negative margin. must be aligned with overlay_border_width, above;
+ overlay_border_width_neg = overlay_border_width * -1 -->
<dimen name="overlay_border_width_neg">-4dp</dimen>
<dimen name="clipboard_preview_size">@dimen/overlay_x_scale</dimen>
@@ -1034,8 +1041,6 @@
<dimen name="ongoing_appops_dialog_side_padding">16dp</dimen>
- <!-- Size of the RAT type for CellularTile -->
-
<!-- Size of media cards in the QSPanel carousel -->
<dimen name="qs_media_padding">16dp</dimen>
<dimen name="qs_media_album_radius">14dp</dimen>
@@ -1050,6 +1055,7 @@
<dimen name="qs_media_disabled_seekbar_height">1dp</dimen>
<dimen name="qs_media_enabled_seekbar_height">2dp</dimen>
<dimen name="qs_media_app_icon_size">24dp</dimen>
+ <dimen name="qs_media_explicit_indicator_icon_size">13dp</dimen>
<dimen name="qs_media_session_enabled_seekbar_vertical_padding">15dp</dimen>
<dimen name="qs_media_session_disabled_seekbar_vertical_padding">16dp</dimen>
@@ -1293,6 +1299,15 @@
<!-- OCCLUDED -> LOCKSCREEN transition: Amount to shift lockscreen content on entering -->
<dimen name="occluded_to_lockscreen_transition_lockscreen_translation_y">40dp</dimen>
+ <!-- LOCKSCREEN -> DREAMING transition: Amount to shift lockscreen content on entering -->
+ <dimen name="lockscreen_to_dreaming_transition_lockscreen_translation_y">-40dp</dimen>
+
+ <!-- GONE -> DREAMING transition: Amount to shift lockscreen content on entering -->
+ <dimen name="gone_to_dreaming_transition_lockscreen_translation_y">-40dp</dimen>
+
+ <!-- LOCKSCREEN -> OCCLUDED transition: Amount to shift lockscreen content on entering -->
+ <dimen name="lockscreen_to_occluded_transition_lockscreen_translation_y">-40dp</dimen>
+
<!-- The amount of vertical offset for the keyguard during the full shade transition. -->
<dimen name="lockscreen_shade_keyguard_transition_vertical_offset">0dp</dimen>
@@ -1640,6 +1655,8 @@
<dimen name="dream_overlay_status_bar_ambient_text_shadow_dx">0.5dp</dimen>
<dimen name="dream_overlay_status_bar_ambient_text_shadow_dy">0.5dp</dimen>
<dimen name="dream_overlay_status_bar_ambient_text_shadow_radius">2dp</dimen>
+ <dimen name="dream_overlay_icon_inset_dimen">0dp</dimen>
+ <dimen name="dream_overlay_status_bar_marginTop">22dp</dimen>
<!-- Default device corner radius, used for assist UI -->
<dimen name="config_rounded_mask_size">0px</dimen>
diff --git a/packages/SystemUI/res/values/strings.xml b/packages/SystemUI/res/values/strings.xml
index 45147ca..2745202 100644
--- a/packages/SystemUI/res/values/strings.xml
+++ b/packages/SystemUI/res/values/strings.xml
@@ -240,7 +240,9 @@
<!-- Content description for the right boundary of the screenshot being cropped, with the current position as a percentage. [CHAR LIMIT=NONE] -->
<string name="screenshot_right_boundary_pct">Right boundary <xliff:g id="percent" example="50">%1$d</xliff:g> percent</string>
<!-- Notification displayed when a screenshot is saved in a work profile. [CHAR LIMIT=NONE] -->
- <string name="screenshot_work_profile_notification" translatable="false">Work screenshots are saved in the work <xliff:g id="app" example="Files">%1$s</xliff:g> app</string>
+ <string name="screenshot_work_profile_notification">Work screenshots are saved in the <xliff:g id="app" example="Work Files">%1$s</xliff:g> app</string>
+ <!-- Default name referring to the app on the device that lets the user browse stored files. [CHAR LIMIT=NONE] -->
+ <string name="screenshot_default_files_app_name">Files</string>
<!-- Notification title displayed for screen recording [CHAR LIMIT=50]-->
<string name="screenrecord_name">Screen Recorder</string>
@@ -2461,13 +2463,15 @@
<!-- Text to ask the user to move their device closer to a different device (deviceName) in order to play media on the different device. [CHAR LIMIT=75] -->
<string name="media_move_closer_to_start_cast">Move closer to play on <xliff:g id="deviceName" example="My Tablet">%1$s</xliff:g></string>
<!-- Text to ask the user to move their device closer to a different device (deviceName) in order to transfer media from the different device and back onto the current device. [CHAR LIMIT=75] -->
- <string name="media_move_closer_to_end_cast">Move closer to <xliff:g id="deviceName" example="My Tablet">%1$s</xliff:g> to play here</string>
+ <string name="media_move_closer_to_end_cast">To play here, move closer to <xliff:g id="deviceName" example="tablet">%1$s</xliff:g></string>
<!-- Text informing the user that their media is now playing on a different device (deviceName). [CHAR LIMIT=50] -->
<string name="media_transfer_playing_different_device">Playing on <xliff:g id="deviceName" example="My Tablet">%1$s</xliff:g></string>
- <!-- Text informing the user that the media transfer has failed because something went wrong. [CHAR LIsMIT=50] -->
+ <!-- Text informing the user that the media transfer has failed because something went wrong. [CHAR LIMIT=50] -->
<string name="media_transfer_failed">Something went wrong. Try again.</string>
<!-- Text to indicate that a media transfer is currently in-progress, aka loading. [CHAR LIMIT=NONE] -->
<string name="media_transfer_loading">Loading</string>
+ <!-- Default name of the device. [CHAR LIMIT=30] -->
+ <string name="media_ttt_default_device_type">tablet</string>
<!-- Error message indicating that a control timed out while waiting for an update [CHAR_LIMIT=30] -->
<string name="controls_error_timeout">Inactive, check app</string>
@@ -2516,6 +2520,8 @@
<string name="media_output_dialog_volume_percentage"><xliff:g id="percentage" example="10">%1$d</xliff:g>%%</string>
<!-- Title for Speakers and Displays group. [CHAR LIMIT=NONE] -->
<string name="media_output_group_title_speakers_and_displays">Speakers & Displays</string>
+ <!-- Title for Suggested Devices group. [CHAR LIMIT=NONE] -->
+ <string name="media_output_group_title_suggested_device">Suggested Devices</string>
<!-- Media Output Broadcast Dialog -->
<!-- Title for Broadcast First Notify Dialog [CHAR LIMIT=60] -->
@@ -2885,6 +2891,9 @@
<!-- Text for education page content description for unfolded animation. [CHAR_LIMIT=NONE] -->
<string name="rear_display_accessibility_unfolded_animation">Foldable device being flipped around</string>
- <!-- Title for notification of low stylus battery. [CHAR_LIMIT=NONE] -->
- <string name="stylus_battery_low">Stylus battery low</string>
+ <!-- Title for notification of low stylus battery with percentage. "percentage" is
+ the value of the battery capacity remaining [CHAR LIMIT=none]-->
+ <string name="stylus_battery_low_percentage"><xliff:g id="percentage" example="16%">%s</xliff:g> battery remaining</string>
+ <!-- Subtitle for the notification sent when a stylus battery is low. [CHAR LIMIT=none]-->
+ <string name="stylus_battery_low_subtitle">Connect your stylus to a charger</string>
</resources>
diff --git a/packages/SystemUI/res/xml/media_session_collapsed.xml b/packages/SystemUI/res/xml/media_session_collapsed.xml
index 1eb621e..d9c81af 100644
--- a/packages/SystemUI/res/xml/media_session_collapsed.xml
+++ b/packages/SystemUI/res/xml/media_session_collapsed.xml
@@ -66,6 +66,21 @@
app:layout_constraintTop_toBottomOf="@id/icon"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintHorizontal_bias="0" />
+
+ <Constraint
+ android:id="@+id/media_explicit_indicator"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_marginEnd="@dimen/qs_media_info_spacing"
+ android:layout_marginBottom="@dimen/qs_media_padding"
+ android:layout_marginTop="0dp"
+ app:layout_constraintStart_toStartOf="@id/header_title"
+ app:layout_constraintEnd_toStartOf="@id/header_artist"
+ app:layout_constraintTop_toTopOf="@id/header_artist"
+ app:layout_constraintBottom_toTopOf="@id/media_action_barrier_top"
+ app:layout_constraintHorizontal_bias="0"
+ app:layout_constraintHorizontal_chainStyle="packed" />
+
<Constraint
android:id="@+id/header_artist"
android:layout_width="wrap_content"
@@ -75,9 +90,8 @@
app:layout_constraintEnd_toStartOf="@id/action_button_guideline"
app:layout_constrainedWidth="true"
app:layout_constraintTop_toBottomOf="@id/header_title"
- app:layout_constraintStart_toStartOf="@id/header_title"
- app:layout_constraintVertical_bias="0"
- app:layout_constraintHorizontal_bias="0" />
+ app:layout_constraintStart_toEndOf="@id/media_explicit_indicator"
+ app:layout_constraintVertical_bias="0" />
<Constraint
android:id="@+id/actionPlayPause"
diff --git a/packages/SystemUI/res/xml/media_session_expanded.xml b/packages/SystemUI/res/xml/media_session_expanded.xml
index 7de0a5e..0cdc0f9 100644
--- a/packages/SystemUI/res/xml/media_session_expanded.xml
+++ b/packages/SystemUI/res/xml/media_session_expanded.xml
@@ -58,6 +58,21 @@
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintBottom_toTopOf="@id/header_artist"
app:layout_constraintHorizontal_bias="0" />
+
+ <Constraint
+ android:id="@+id/media_explicit_indicator"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_marginEnd="@dimen/qs_media_info_spacing"
+ android:layout_marginBottom="@dimen/qs_media_padding"
+ android:layout_marginTop="0dp"
+ app:layout_constraintStart_toStartOf="@id/header_title"
+ app:layout_constraintEnd_toStartOf="@id/header_artist"
+ app:layout_constraintTop_toTopOf="@id/header_artist"
+ app:layout_constraintBottom_toTopOf="@id/media_action_barrier_top"
+ app:layout_constraintHorizontal_bias="0"
+ app:layout_constraintHorizontal_chainStyle="packed"/>
+
<Constraint
android:id="@+id/header_artist"
android:layout_width="wrap_content"
@@ -67,10 +82,9 @@
android:layout_marginTop="0dp"
app:layout_constrainedWidth="true"
app:layout_constraintEnd_toStartOf="@id/actionPlayPause"
- app:layout_constraintStart_toStartOf="@id/header_title"
+ app:layout_constraintStart_toEndOf="@id/media_explicit_indicator"
app:layout_constraintBottom_toTopOf="@id/media_action_barrier_top"
- app:layout_constraintVertical_bias="0"
- app:layout_constraintHorizontal_bias="0" />
+ app:layout_constraintVertical_bias="0" />
<Constraint
android:id="@+id/actionPlayPause"
diff --git a/packages/SystemUI/res/xml/qs_header.xml b/packages/SystemUI/res/xml/qs_header.xml
index eca2b2a..d97031f 100644
--- a/packages/SystemUI/res/xml/qs_header.xml
+++ b/packages/SystemUI/res/xml/qs_header.xml
@@ -56,13 +56,9 @@
<Layout
android:layout_width="wrap_content"
android:layout_height="@dimen/new_qs_header_non_clickable_element_height"
- app:layout_constrainedWidth="true"
app:layout_constraintStart_toStartOf="parent"
- app:layout_constraintEnd_toStartOf="@id/space"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintTop_toBottomOf="@id/carrier_group"
- app:layout_constraintHorizontal_bias="0"
- app:layout_constraintHorizontal_chainStyle="spread_inside"
/>
</Constraint>
@@ -87,39 +83,27 @@
<Constraint
android:id="@+id/statusIcons">
<Layout
- android:layout_width="wrap_content"
+ android:layout_width="0dp"
android:layout_height="@dimen/new_qs_header_non_clickable_element_height"
- app:layout_constraintStart_toEndOf="@id/space"
+ app:layout_constraintWidth_default="wrap"
+ app:layout_constraintStart_toEndOf="@id/date"
app:layout_constraintEnd_toStartOf="@id/batteryRemainingIcon"
app:layout_constraintTop_toTopOf="@id/date"
- app:layout_constraintBottom_toBottomOf="parent"
- app:layout_constraintHorizontal_bias="1"
+ app:layout_constraintBottom_toBottomOf="@id/date"
/>
</Constraint>
<Constraint
android:id="@+id/batteryRemainingIcon">
<Layout
- android:layout_width="wrap_content"
+ android:layout_width="0dp"
android:layout_height="@dimen/new_qs_header_non_clickable_element_height"
+ app:layout_constraintWidth_default="wrap"
app:layout_constraintHeight_min="@dimen/new_qs_header_non_clickable_element_height"
- app:layout_constraintStart_toEndOf="@id/statusIcons"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toTopOf="@id/date"
- app:layout_constraintBottom_toBottomOf="parent"
- app:layout_constraintHorizontal_bias="1"
- app:layout_constraintHorizontal_chainStyle="spread_inside"
+ app:layout_constraintBottom_toBottomOf="@id/date"
/>
</Constraint>
-
- <Constraint
- android:id="@id/space">
- <Layout
- android:layout_width="0dp"
- android:layout_height="0dp"
- app:layout_constraintStart_toEndOf="@id/date"
- app:layout_constraintEnd_toStartOf="@id/statusIcons"
- />
- </Constraint>
</ConstraintSet>
\ No newline at end of file
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/recents/IOverviewProxy.aidl b/packages/SystemUI/shared/src/com/android/systemui/shared/recents/IOverviewProxy.aidl
index a71fb56..fa484c7 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/shared/recents/IOverviewProxy.aidl
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/recents/IOverviewProxy.aidl
@@ -37,7 +37,7 @@
/**
* Sent when overview is to be shown.
*/
- void onOverviewShown(boolean triggeredFromAltTab) = 7;
+ void onOverviewShown(boolean triggeredFromAltTab, boolean forward) = 7;
/**
* Sent when overview is to be hidden.
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/shadow/DoubleShadowTextView.kt b/packages/SystemUI/shared/src/com/android/systemui/shared/shadow/DoubleShadowTextView.kt
index 25d2721..9b73cc3 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/shared/shadow/DoubleShadowTextView.kt
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/shadow/DoubleShadowTextView.kt
@@ -48,48 +48,28 @@
val drawableInsetSize: Int
try {
val keyShadowBlur =
- attributes.getDimensionPixelSize(R.styleable.DoubleShadowTextView_keyShadowBlur, 0)
+ attributes.getDimension(R.styleable.DoubleShadowTextView_keyShadowBlur, 0f)
val keyShadowOffsetX =
- attributes.getDimensionPixelSize(
- R.styleable.DoubleShadowTextView_keyShadowOffsetX,
- 0
- )
+ attributes.getDimension(R.styleable.DoubleShadowTextView_keyShadowOffsetX, 0f)
val keyShadowOffsetY =
- attributes.getDimensionPixelSize(
- R.styleable.DoubleShadowTextView_keyShadowOffsetY,
- 0
- )
+ attributes.getDimension(R.styleable.DoubleShadowTextView_keyShadowOffsetY, 0f)
val keyShadowAlpha =
attributes.getFloat(R.styleable.DoubleShadowTextView_keyShadowAlpha, 0f)
mKeyShadowInfo =
- ShadowInfo(
- keyShadowBlur.toFloat(),
- keyShadowOffsetX.toFloat(),
- keyShadowOffsetY.toFloat(),
- keyShadowAlpha
- )
+ ShadowInfo(keyShadowBlur, keyShadowOffsetX, keyShadowOffsetY, keyShadowAlpha)
val ambientShadowBlur =
- attributes.getDimensionPixelSize(
- R.styleable.DoubleShadowTextView_ambientShadowBlur,
- 0
- )
+ attributes.getDimension(R.styleable.DoubleShadowTextView_ambientShadowBlur, 0f)
val ambientShadowOffsetX =
- attributes.getDimensionPixelSize(
- R.styleable.DoubleShadowTextView_ambientShadowOffsetX,
- 0
- )
+ attributes.getDimension(R.styleable.DoubleShadowTextView_ambientShadowOffsetX, 0f)
val ambientShadowOffsetY =
- attributes.getDimensionPixelSize(
- R.styleable.DoubleShadowTextView_ambientShadowOffsetY,
- 0
- )
+ attributes.getDimension(R.styleable.DoubleShadowTextView_ambientShadowOffsetY, 0f)
val ambientShadowAlpha =
attributes.getFloat(R.styleable.DoubleShadowTextView_ambientShadowAlpha, 0f)
mAmbientShadowInfo =
ShadowInfo(
- ambientShadowBlur.toFloat(),
- ambientShadowOffsetX.toFloat(),
- ambientShadowOffsetY.toFloat(),
+ ambientShadowBlur,
+ ambientShadowOffsetX,
+ ambientShadowOffsetY,
ambientShadowAlpha
)
drawableSize =
diff --git a/packages/SystemUI/src/com/android/keyguard/ClockEventController.kt b/packages/SystemUI/src/com/android/keyguard/ClockEventController.kt
index 8f38e58..a45ce42 100644
--- a/packages/SystemUI/src/com/android/keyguard/ClockEventController.kt
+++ b/packages/SystemUI/src/com/android/keyguard/ClockEventController.kt
@@ -38,9 +38,11 @@
import com.android.systemui.keyguard.domain.interactor.KeyguardTransitionInteractor
import com.android.systemui.keyguard.shared.model.TransitionState
import com.android.systemui.lifecycle.repeatWhenAttached
-import com.android.systemui.log.dagger.KeyguardClockLog
+import com.android.systemui.log.dagger.KeyguardSmallClockLog
+import com.android.systemui.log.dagger.KeyguardLargeClockLog
import com.android.systemui.plugins.ClockController
import com.android.systemui.plugins.log.LogBuffer
+import com.android.systemui.plugins.log.LogLevel.DEBUG
import com.android.systemui.shared.regionsampling.RegionSampler
import com.android.systemui.statusbar.policy.BatteryController
import com.android.systemui.statusbar.policy.BatteryController.BatteryStateChangeCallback
@@ -73,16 +75,18 @@
private val context: Context,
@Main private val mainExecutor: Executor,
@Background private val bgExecutor: Executor,
- @KeyguardClockLog private val logBuffer: LogBuffer?,
+ @KeyguardSmallClockLog private val smallLogBuffer: LogBuffer?,
+ @KeyguardLargeClockLog private val largeLogBuffer: LogBuffer?,
private val featureFlags: FeatureFlags
) {
var clock: ClockController? = null
set(value) {
field = value
if (value != null) {
- if (logBuffer != null) {
- value.setLogBuffer(logBuffer)
- }
+ smallLogBuffer?.log(TAG, DEBUG, {}, { "New Clock" })
+ value.smallClock.logBuffer = smallLogBuffer
+ largeLogBuffer?.log(TAG, DEBUG, {}, { "New Clock" })
+ value.largeClock.logBuffer = largeLogBuffer
value.initialize(resources, dozeAmount, 0f)
updateRegionSamplers(value)
@@ -325,4 +329,8 @@
}
}
}
+
+ companion object {
+ private val TAG = ClockEventController::class.simpleName!!
+ }
}
diff --git a/packages/SystemUI/src/com/android/keyguard/FaceAuthReason.kt b/packages/SystemUI/src/com/android/keyguard/FaceAuthReason.kt
index 5bb9367..e0cf7b6 100644
--- a/packages/SystemUI/src/com/android/keyguard/FaceAuthReason.kt
+++ b/packages/SystemUI/src/com/android/keyguard/FaceAuthReason.kt
@@ -50,6 +50,7 @@
import com.android.keyguard.InternalFaceAuthReasons.KEYGUARD_VISIBILITY_CHANGED
import com.android.keyguard.InternalFaceAuthReasons.NON_STRONG_BIOMETRIC_ALLOWED_CHANGED
import com.android.keyguard.InternalFaceAuthReasons.OCCLUDING_APP_REQUESTED
+import com.android.keyguard.InternalFaceAuthReasons.POSTURE_CHANGED
import com.android.keyguard.InternalFaceAuthReasons.PRIMARY_BOUNCER_SHOWN
import com.android.keyguard.InternalFaceAuthReasons.PRIMARY_BOUNCER_SHOWN_OR_WILL_BE_SHOWN
import com.android.keyguard.InternalFaceAuthReasons.RETRY_AFTER_HW_UNAVAILABLE
@@ -126,6 +127,7 @@
const val STRONG_AUTH_ALLOWED_CHANGED = "Face auth stopped because strong auth allowed changed"
const val NON_STRONG_BIOMETRIC_ALLOWED_CHANGED =
"Face auth stopped because non strong biometric allowed changed"
+ const val POSTURE_CHANGED = "Face auth started/stopped due to device posture changed."
}
/**
@@ -173,6 +175,7 @@
return PowerManager.wakeReasonToString(extraInfo)
}
},
+ @UiEvent(doc = POSTURE_CHANGED) FACE_AUTH_UPDATED_POSTURE_CHANGED(1265, POSTURE_CHANGED),
@Deprecated(
"Not a face auth trigger.",
ReplaceWith(
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardClockSwitch.java b/packages/SystemUI/src/com/android/keyguard/KeyguardClockSwitch.java
index 62babad..4acbb0a 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardClockSwitch.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardClockSwitch.java
@@ -7,7 +7,6 @@
import android.content.Context;
import android.graphics.Rect;
import android.util.AttributeSet;
-import android.util.Log;
import android.view.View;
import android.view.ViewGroup;
import android.widget.FrameLayout;
@@ -20,11 +19,15 @@
import com.android.systemui.R;
import com.android.systemui.animation.Interpolators;
import com.android.systemui.plugins.ClockController;
+import com.android.systemui.plugins.log.LogBuffer;
+import com.android.systemui.plugins.log.LogLevel;
import java.io.PrintWriter;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
+import kotlin.Unit;
+
/**
* Switch to show plugin clock when plugin is connected, otherwise it will show default clock.
*/
@@ -87,6 +90,7 @@
private int mClockSwitchYAmount;
@VisibleForTesting boolean mChildrenAreLaidOut = false;
@VisibleForTesting boolean mAnimateOnLayout = true;
+ private LogBuffer mLogBuffer = null;
public KeyguardClockSwitch(Context context, AttributeSet attrs) {
super(context, attrs);
@@ -113,6 +117,14 @@
onDensityOrFontScaleChanged();
}
+ public void setLogBuffer(LogBuffer logBuffer) {
+ mLogBuffer = logBuffer;
+ }
+
+ public LogBuffer getLogBuffer() {
+ return mLogBuffer;
+ }
+
void setClock(ClockController clock, int statusBarState) {
mClock = clock;
@@ -121,12 +133,16 @@
mLargeClockFrame.removeAllViews();
if (clock == null) {
- Log.e(TAG, "No clock being shown");
+ if (mLogBuffer != null) {
+ mLogBuffer.log(TAG, LogLevel.ERROR, "No clock being shown");
+ }
return;
}
// Attach small and big clock views to hierarchy.
- Log.i(TAG, "Attached new clock views to switch");
+ if (mLogBuffer != null) {
+ mLogBuffer.log(TAG, LogLevel.INFO, "Attached new clock views to switch");
+ }
mSmallClockFrame.addView(clock.getSmallClock().getView());
mLargeClockFrame.addView(clock.getLargeClock().getView());
updateClockTargetRegions();
@@ -152,8 +168,18 @@
}
private void updateClockViews(boolean useLargeClock, boolean animate) {
- Log.i(TAG, "updateClockViews; useLargeClock=" + useLargeClock + "; animate=" + animate
- + "; mChildrenAreLaidOut=" + mChildrenAreLaidOut);
+ if (mLogBuffer != null) {
+ mLogBuffer.log(TAG, LogLevel.DEBUG, (msg) -> {
+ msg.setBool1(useLargeClock);
+ msg.setBool2(animate);
+ msg.setBool3(mChildrenAreLaidOut);
+ return Unit.INSTANCE;
+ }, (msg) -> "updateClockViews"
+ + "; useLargeClock=" + msg.getBool1()
+ + "; animate=" + msg.getBool2()
+ + "; mChildrenAreLaidOut=" + msg.getBool3());
+ }
+
if (mClockInAnim != null) mClockInAnim.cancel();
if (mClockOutAnim != null) mClockOutAnim.cancel();
if (mStatusAreaAnim != null) mStatusAreaAnim.cancel();
@@ -183,6 +209,7 @@
if (!animate) {
out.setAlpha(0f);
+ out.setVisibility(INVISIBLE);
in.setAlpha(1f);
in.setVisibility(VISIBLE);
mStatusArea.setTranslationY(statusAreaYTranslation);
@@ -198,7 +225,10 @@
direction * -mClockSwitchYAmount));
mClockOutAnim.addListener(new AnimatorListenerAdapter() {
public void onAnimationEnd(Animator animation) {
- mClockOutAnim = null;
+ if (mClockOutAnim == animation) {
+ out.setVisibility(INVISIBLE);
+ mClockOutAnim = null;
+ }
}
});
@@ -212,7 +242,9 @@
mClockInAnim.setStartDelay(CLOCK_OUT_MILLIS / 2);
mClockInAnim.addListener(new AnimatorListenerAdapter() {
public void onAnimationEnd(Animator animation) {
- mClockInAnim = null;
+ if (mClockInAnim == animation) {
+ mClockInAnim = null;
+ }
}
});
@@ -225,7 +257,9 @@
mStatusAreaAnim.setInterpolator(Interpolators.FAST_OUT_SLOW_IN);
mStatusAreaAnim.addListener(new AnimatorListenerAdapter() {
public void onAnimationEnd(Animator animation) {
- mStatusAreaAnim = null;
+ if (mStatusAreaAnim == animation) {
+ mStatusAreaAnim = null;
+ }
}
});
mStatusAreaAnim.start();
@@ -269,7 +303,9 @@
public void dump(PrintWriter pw, String[] args) {
pw.println("KeyguardClockSwitch:");
pw.println(" mSmallClockFrame: " + mSmallClockFrame);
+ pw.println(" mSmallClockFrame.alpha: " + mSmallClockFrame.getAlpha());
pw.println(" mLargeClockFrame: " + mLargeClockFrame);
+ pw.println(" mLargeClockFrame.alpha: " + mLargeClockFrame.getAlpha());
pw.println(" mStatusArea: " + mStatusArea);
pw.println(" mDisplayedClockSize: " + mDisplayedClockSize);
}
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardClockSwitchController.java b/packages/SystemUI/src/com/android/keyguard/KeyguardClockSwitchController.java
index 6ce84a9..08567a7 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardClockSwitchController.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardClockSwitchController.java
@@ -38,8 +38,11 @@
import com.android.systemui.dagger.qualifiers.Main;
import com.android.systemui.dump.DumpManager;
import com.android.systemui.keyguard.KeyguardUnlockAnimationController;
+import com.android.systemui.log.dagger.KeyguardClockLog;
import com.android.systemui.plugins.ClockAnimations;
import com.android.systemui.plugins.ClockController;
+import com.android.systemui.plugins.log.LogBuffer;
+import com.android.systemui.plugins.log.LogLevel;
import com.android.systemui.plugins.statusbar.StatusBarStateController;
import com.android.systemui.shared.clocks.ClockRegistry;
import com.android.systemui.statusbar.lockscreen.LockscreenSmartspaceController;
@@ -62,6 +65,8 @@
*/
public class KeyguardClockSwitchController extends ViewController<KeyguardClockSwitch>
implements Dumpable {
+ private static final String TAG = "KeyguardClockSwitchController";
+
private final StatusBarStateController mStatusBarStateController;
private final ClockRegistry mClockRegistry;
private final KeyguardSliceViewController mKeyguardSliceViewController;
@@ -70,6 +75,7 @@
private final SecureSettings mSecureSettings;
private final DumpManager mDumpManager;
private final ClockEventController mClockEventController;
+ private final LogBuffer mLogBuffer;
private FrameLayout mSmallClockFrame; // top aligned clock
private FrameLayout mLargeClockFrame; // centered clock
@@ -119,7 +125,8 @@
SecureSettings secureSettings,
@Main Executor uiExecutor,
DumpManager dumpManager,
- ClockEventController clockEventController) {
+ ClockEventController clockEventController,
+ @KeyguardClockLog LogBuffer logBuffer) {
super(keyguardClockSwitch);
mStatusBarStateController = statusBarStateController;
mClockRegistry = clockRegistry;
@@ -131,6 +138,8 @@
mKeyguardUnlockAnimationController = keyguardUnlockAnimationController;
mDumpManager = dumpManager;
mClockEventController = clockEventController;
+ mLogBuffer = logBuffer;
+ mView.setLogBuffer(mLogBuffer);
mClockChangedListener = () -> {
setClock(mClockRegistry.createCurrentClock());
@@ -337,10 +346,6 @@
int clockHeight = clock.getLargeClock().getView().getHeight();
return frameHeight / 2 + clockHeight / 2 + mKeyguardLargeClockTopMargin / -2;
} else {
- // This is only called if we've never shown the large clock as the frame is inflated
- // with 'gone', but then the visibility is never set when it is animated away by
- // KeyguardClockSwitch, instead it is removed from the view hierarchy.
- // TODO(b/261755021): Cleanup Large Frame Visibility
int clockHeight = clock.getSmallClock().getView().getHeight();
return clockHeight + statusBarHeaderHeight + mKeyguardSmallClockTopMargin;
}
@@ -358,15 +363,11 @@
if (mLargeClockFrame.getVisibility() == View.VISIBLE) {
return clock.getLargeClock().getView().getHeight();
} else {
- // Is not called except in certain edge cases, see comment in getClockBottom
- // TODO(b/261755021): Cleanup Large Frame Visibility
return clock.getSmallClock().getView().getHeight();
}
}
boolean isClockTopAligned() {
- // Returns false except certain edge cases, see comment in getClockBottom
- // TODO(b/261755021): Cleanup Large Frame Visibility
return mLargeClockFrame.getVisibility() != View.VISIBLE;
}
@@ -378,6 +379,10 @@
}
private void setClock(ClockController clock) {
+ if (clock != null && mLogBuffer != null) {
+ mLogBuffer.log(TAG, LogLevel.INFO, "New Clock");
+ }
+
mClockEventController.setClock(clock);
mView.setClock(clock, mStatusBarStateController.getState());
}
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardFaceListenModel.kt b/packages/SystemUI/src/com/android/keyguard/KeyguardFaceListenModel.kt
index deead19..1a06b5f 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardFaceListenModel.kt
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardFaceListenModel.kt
@@ -39,6 +39,7 @@
var keyguardGoingAway: Boolean = false,
var listeningForFaceAssistant: Boolean = false,
var occludingAppRequestingFaceAuth: Boolean = false,
+ val postureAllowsListening: Boolean = false,
var primaryUser: Boolean = false,
var secureCameraLaunched: Boolean = false,
var supportsDetect: Boolean = false,
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardStatusViewController.java b/packages/SystemUI/src/com/android/keyguard/KeyguardStatusViewController.java
index aec3063..b53b868 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardStatusViewController.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardStatusViewController.java
@@ -20,6 +20,7 @@
import android.util.Slog;
import com.android.keyguard.KeyguardClockSwitch.ClockSize;
+import com.android.keyguard.logging.KeyguardLogger;
import com.android.systemui.flags.FeatureFlags;
import com.android.systemui.flags.Flags;
import com.android.systemui.plugins.ClockAnimations;
@@ -62,14 +63,16 @@
ConfigurationController configurationController,
DozeParameters dozeParameters,
FeatureFlags featureFlags,
- ScreenOffAnimationController screenOffAnimationController) {
+ ScreenOffAnimationController screenOffAnimationController,
+ KeyguardLogger logger) {
super(keyguardStatusView);
mKeyguardSliceViewController = keyguardSliceViewController;
mKeyguardClockSwitchController = keyguardClockSwitchController;
mKeyguardUpdateMonitor = keyguardUpdateMonitor;
mConfigurationController = configurationController;
mKeyguardVisibilityHelper = new KeyguardVisibilityHelper(mView, keyguardStateController,
- dozeParameters, screenOffAnimationController, /* animateYPos= */ true);
+ dozeParameters, screenOffAnimationController, /* animateYPos= */ true,
+ logger.getBuffer());
mKeyguardVisibilityHelper.setOcclusionTransitionFlagEnabled(
featureFlags.isEnabled(Flags.UNOCCLUSION_TRANSITION));
}
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java b/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java
index 271fc7b..9d6bb08 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java
@@ -63,11 +63,13 @@
import static com.android.keyguard.FaceAuthUiEvent.FACE_AUTH_UPDATED_KEYGUARD_VISIBILITY_CHANGED;
import static com.android.keyguard.FaceAuthUiEvent.FACE_AUTH_UPDATED_ON_FACE_AUTHENTICATED;
import static com.android.keyguard.FaceAuthUiEvent.FACE_AUTH_UPDATED_ON_KEYGUARD_INIT;
+import static com.android.keyguard.FaceAuthUiEvent.FACE_AUTH_UPDATED_POSTURE_CHANGED;
import static com.android.keyguard.FaceAuthUiEvent.FACE_AUTH_UPDATED_PRIMARY_BOUNCER_SHOWN;
import static com.android.keyguard.FaceAuthUiEvent.FACE_AUTH_UPDATED_STARTED_WAKING_UP;
import static com.android.keyguard.FaceAuthUiEvent.FACE_AUTH_UPDATED_STRONG_AUTH_CHANGED;
import static com.android.keyguard.FaceAuthUiEvent.FACE_AUTH_UPDATED_USER_SWITCHING;
import static com.android.systemui.DejankUtils.whitelistIpcs;
+import static com.android.systemui.statusbar.policy.DevicePostureController.DEVICE_POSTURE_UNKNOWN;
import android.annotation.AnyThread;
import android.annotation.MainThread;
@@ -140,6 +142,7 @@
import com.android.systemui.Dumpable;
import com.android.systemui.R;
import com.android.systemui.biometrics.AuthController;
+import com.android.systemui.biometrics.FingerprintInteractiveToAuthProvider;
import com.android.systemui.broadcast.BroadcastDispatcher;
import com.android.systemui.dagger.SysUISingleton;
import com.android.systemui.dagger.qualifiers.Background;
@@ -153,6 +156,7 @@
import com.android.systemui.shared.system.TaskStackChangeListeners;
import com.android.systemui.statusbar.StatusBarState;
import com.android.systemui.statusbar.phone.KeyguardBypassController;
+import com.android.systemui.statusbar.policy.DevicePostureController;
import com.android.systemui.telephony.TelephonyListenerManager;
import com.android.systemui.util.Assert;
import com.android.systemui.util.settings.SecureSettings;
@@ -169,6 +173,7 @@
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
+import java.util.Optional;
import java.util.Set;
import java.util.TimeZone;
import java.util.concurrent.Executor;
@@ -329,18 +334,17 @@
private final ArrayList<WeakReference<KeyguardUpdateMonitorCallback>>
mCallbacks = Lists.newArrayList();
private ContentObserver mDeviceProvisionedObserver;
- private ContentObserver mSfpsRequireScreenOnToAuthPrefObserver;
private final ContentObserver mTimeFormatChangeObserver;
private boolean mSwitchingUser;
private boolean mDeviceInteractive;
- private boolean mSfpsRequireScreenOnToAuthPrefEnabled;
private final SubscriptionManager mSubscriptionManager;
private final TelephonyListenerManager mTelephonyListenerManager;
private final TrustManager mTrustManager;
private final UserManager mUserManager;
private final DevicePolicyManager mDevicePolicyManager;
+ private final DevicePostureController mPostureController;
private final BroadcastDispatcher mBroadcastDispatcher;
private final SecureSettings mSecureSettings;
private final InteractionJankMonitor mInteractionJankMonitor;
@@ -358,6 +362,9 @@
private final FaceManager mFaceManager;
private final LockPatternUtils mLockPatternUtils;
private final boolean mWakeOnFingerprintAcquiredStart;
+ @VisibleForTesting
+ @DevicePostureController.DevicePostureInt
+ protected int mConfigFaceAuthSupportedPosture;
private KeyguardBypassController mKeyguardBypassController;
private List<SubscriptionInfo> mSubscriptionInfo;
@@ -368,6 +375,8 @@
private boolean mLogoutEnabled;
private boolean mIsFaceEnrolled;
private int mActiveMobileDataSubscription = SubscriptionManager.INVALID_SUBSCRIPTION_ID;
+ private int mPostureState = DEVICE_POSTURE_UNKNOWN;
+ private FingerprintInteractiveToAuthProvider mFingerprintInteractiveToAuthProvider;
/**
* Short delay before restarting fingerprint authentication after a successful try. This should
@@ -695,8 +704,11 @@
*/
public void setKeyguardGoingAway(boolean goingAway) {
mKeyguardGoingAway = goingAway;
- // This is set specifically to stop face authentication from running.
- updateBiometricListeningState(BIOMETRIC_ACTION_STOP, FACE_AUTH_STOPPED_KEYGUARD_GOING_AWAY);
+ if (mKeyguardGoingAway) {
+ updateFaceListeningState(BIOMETRIC_ACTION_STOP,
+ FACE_AUTH_STOPPED_KEYGUARD_GOING_AWAY);
+ }
+ updateFingerprintListeningState(BIOMETRIC_ACTION_UPDATE);
}
/**
@@ -1775,6 +1787,17 @@
};
@VisibleForTesting
+ final DevicePostureController.Callback mPostureCallback =
+ new DevicePostureController.Callback() {
+ @Override
+ public void onPostureChanged(int posture) {
+ mPostureState = posture;
+ updateFaceListeningState(BIOMETRIC_ACTION_UPDATE,
+ FACE_AUTH_UPDATED_POSTURE_CHANGED);
+ }
+ };
+
+ @VisibleForTesting
CancellationSignal mFingerprintCancelSignal;
@VisibleForTesting
CancellationSignal mFaceCancelSignal;
@@ -1934,9 +1957,9 @@
cb.onFinishedGoingToSleep(arg1);
}
}
- // This is set specifically to stop face authentication from running.
- updateBiometricListeningState(BIOMETRIC_ACTION_STOP,
+ updateFaceListeningState(BIOMETRIC_ACTION_STOP,
FACE_AUTH_STOPPED_FINISHED_GOING_TO_SLEEP);
+ updateFingerprintListeningState(BIOMETRIC_ACTION_UPDATE);
}
private void handleScreenTurnedOff() {
@@ -2039,7 +2062,9 @@
@Nullable FaceManager faceManager,
@Nullable FingerprintManager fingerprintManager,
@Nullable BiometricManager biometricManager,
- FaceWakeUpTriggersConfig faceWakeUpTriggersConfig) {
+ FaceWakeUpTriggersConfig faceWakeUpTriggersConfig,
+ DevicePostureController devicePostureController,
+ Optional<FingerprintInteractiveToAuthProvider> interactiveToAuthProvider) {
mContext = context;
mSubscriptionManager = subscriptionManager;
mUserTracker = userTracker;
@@ -2068,6 +2093,7 @@
mDreamManager = dreamManager;
mTelephonyManager = telephonyManager;
mDevicePolicyManager = devicePolicyManager;
+ mPostureController = devicePostureController;
mPackageManager = packageManager;
mFpm = fingerprintManager;
mFaceManager = faceManager;
@@ -2079,6 +2105,8 @@
R.array.config_face_acquire_device_entry_ignorelist))
.boxed()
.collect(Collectors.toSet());
+ mConfigFaceAuthSupportedPosture = mContext.getResources().getInteger(
+ R.integer.config_face_auth_supported_posture);
mFaceWakeUpTriggersConfig = faceWakeUpTriggersConfig;
mHandler = new Handler(mainLooper) {
@@ -2270,6 +2298,9 @@
FACE_AUTH_TRIGGERED_ENROLLMENTS_CHANGED));
}
});
+ if (mConfigFaceAuthSupportedPosture != DEVICE_POSTURE_UNKNOWN) {
+ mPostureController.addCallback(mPostureCallback);
+ }
updateBiometricListeningState(BIOMETRIC_ACTION_UPDATE, FACE_AUTH_UPDATED_ON_KEYGUARD_INIT);
TaskStackChangeListeners.getInstance().registerTaskStackListener(mTaskStackListener);
@@ -2303,30 +2334,7 @@
Settings.System.getUriFor(Settings.System.TIME_12_24),
false, mTimeFormatChangeObserver, UserHandle.USER_ALL);
- updateSfpsRequireScreenOnToAuthPref();
- mSfpsRequireScreenOnToAuthPrefObserver = new ContentObserver(mHandler) {
- @Override
- public void onChange(boolean selfChange) {
- updateSfpsRequireScreenOnToAuthPref();
- }
- };
-
- mContext.getContentResolver().registerContentObserver(
- mSecureSettings.getUriFor(
- Settings.Secure.SFPS_REQUIRE_SCREEN_ON_TO_AUTH_ENABLED),
- false,
- mSfpsRequireScreenOnToAuthPrefObserver,
- getCurrentUser());
- }
-
- protected void updateSfpsRequireScreenOnToAuthPref() {
- final int defaultSfpsRequireScreenOnToAuthValue =
- mContext.getResources().getBoolean(
- com.android.internal.R.bool.config_requireScreenOnToAuthEnabled) ? 1 : 0;
- mSfpsRequireScreenOnToAuthPrefEnabled = mSecureSettings.getIntForUser(
- Settings.Secure.SFPS_REQUIRE_SCREEN_ON_TO_AUTH_ENABLED,
- defaultSfpsRequireScreenOnToAuthValue,
- getCurrentUser()) != 0;
+ mFingerprintInteractiveToAuthProvider = interactiveToAuthProvider.orElse(null);
}
private void initializeSimState() {
@@ -2721,8 +2729,11 @@
boolean shouldListenSideFpsState = true;
if (isSideFps) {
+ final boolean interactiveToAuthEnabled =
+ mFingerprintInteractiveToAuthProvider != null &&
+ mFingerprintInteractiveToAuthProvider.isEnabled(getCurrentUser());
shouldListenSideFpsState =
- mSfpsRequireScreenOnToAuthPrefEnabled ? isDeviceInteractive() : true;
+ interactiveToAuthEnabled ? isDeviceInteractive() && !mGoingToSleep : true;
}
boolean shouldListen = shouldListenKeyguardState && shouldListenUserState
@@ -2734,7 +2745,7 @@
user,
shouldListen,
biometricEnabledForUser,
- mPrimaryBouncerIsOrWillBeShowing,
+ mPrimaryBouncerIsOrWillBeShowing,
userCanSkipBouncer,
mCredentialAttempted,
mDeviceInteractive,
@@ -2794,6 +2805,9 @@
final boolean biometricEnabledForUser = mBiometricEnabledForUser.get(user);
final boolean shouldListenForFaceAssistant = shouldListenForFaceAssistant();
final boolean isUdfpsFingerDown = mAuthController.isUdfpsFingerDown();
+ final boolean isPostureAllowedForFaceAuth =
+ mConfigFaceAuthSupportedPosture == 0 /* DEVICE_POSTURE_UNKNOWN */ ? true
+ : (mPostureState == mConfigFaceAuthSupportedPosture);
// Only listen if this KeyguardUpdateMonitor belongs to the primary user. There is an
// instance of KeyguardUpdateMonitor for each user but KeyguardUpdateMonitor is user-aware.
@@ -2810,7 +2824,8 @@
&& faceAuthAllowedOrDetectionIsNeeded && mIsPrimaryUser
&& (!mSecureCameraLaunched || mOccludingAppRequestingFace)
&& faceAndFpNotAuthenticated
- && !mGoingToSleep;
+ && !mGoingToSleep
+ && isPostureAllowedForFaceAuth;
// Aggregate relevant fields for debug logging.
logListenerModelData(
@@ -2830,6 +2845,7 @@
mKeyguardGoingAway,
shouldListenForFaceAssistant,
mOccludingAppRequestingFace,
+ isPostureAllowedForFaceAuth,
mIsPrimaryUser,
mSecureCameraLaunched,
supportsDetect,
@@ -2915,7 +2931,7 @@
getKeyguardSessionId(),
faceAuthUiEvent.getExtraInfo()
);
-
+ mLogger.logFaceUnlockPossible(unlockPossible);
if (unlockPossible) {
mFaceCancelSignal = new CancellationSignal();
@@ -3837,11 +3853,6 @@
mContext.getContentResolver().unregisterContentObserver(mTimeFormatChangeObserver);
}
- if (mSfpsRequireScreenOnToAuthPrefObserver != null) {
- mContext.getContentResolver().unregisterContentObserver(
- mSfpsRequireScreenOnToAuthPrefObserver);
- }
-
try {
ActivityManager.getService().unregisterUserSwitchObserver(mUserSwitchObserver);
} catch (RemoteException e) {
@@ -3919,8 +3930,12 @@
pw.println(" sfpsEnrolled=" + isSfpsEnrolled());
pw.println(" shouldListenForSfps=" + shouldListenForFingerprint(false));
if (isSfpsEnrolled()) {
- pw.println(" mSfpsRequireScreenOnToAuthPrefEnabled="
- + mSfpsRequireScreenOnToAuthPrefEnabled);
+ final boolean interactiveToAuthEnabled =
+ mFingerprintInteractiveToAuthProvider != null &&
+ mFingerprintInteractiveToAuthProvider
+ .isEnabled(getCurrentUser());
+ pw.println(" interactiveToAuthEnabled="
+ + interactiveToAuthEnabled);
}
}
new DumpsysTableLogger(
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardVisibilityHelper.java b/packages/SystemUI/src/com/android/keyguard/KeyguardVisibilityHelper.java
index bde0692..7e48193 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardVisibilityHelper.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardVisibilityHelper.java
@@ -22,6 +22,8 @@
import android.view.ViewPropertyAnimator;
import com.android.systemui.animation.Interpolators;
+import com.android.systemui.plugins.log.LogBuffer;
+import com.android.systemui.plugins.log.LogLevel;
import com.android.systemui.statusbar.StatusBarState;
import com.android.systemui.statusbar.notification.AnimatableProperty;
import com.android.systemui.statusbar.notification.PropertyAnimator;
@@ -31,11 +33,14 @@
import com.android.systemui.statusbar.phone.ScreenOffAnimationController;
import com.android.systemui.statusbar.policy.KeyguardStateController;
+import com.google.errorprone.annotations.CompileTimeConstant;
+
/**
* Helper class for updating visibility of keyguard views based on keyguard and status bar state.
* This logic is shared by both the keyguard status view and the keyguard user switcher.
*/
public class KeyguardVisibilityHelper {
+ private static final String TAG = "KeyguardVisibilityHelper";
private View mView;
private final KeyguardStateController mKeyguardStateController;
@@ -46,17 +51,26 @@
private boolean mLastOccludedState = false;
private boolean mIsUnoccludeTransitionFlagEnabled = false;
private final AnimationProperties mAnimationProperties = new AnimationProperties();
+ private final LogBuffer mLogBuffer;
public KeyguardVisibilityHelper(View view,
KeyguardStateController keyguardStateController,
DozeParameters dozeParameters,
ScreenOffAnimationController screenOffAnimationController,
- boolean animateYPos) {
+ boolean animateYPos,
+ LogBuffer logBuffer) {
mView = view;
mKeyguardStateController = keyguardStateController;
mDozeParameters = dozeParameters;
mScreenOffAnimationController = screenOffAnimationController;
mAnimateYPos = animateYPos;
+ mLogBuffer = logBuffer;
+ }
+
+ private void log(@CompileTimeConstant String message) {
+ if (mLogBuffer != null) {
+ mLogBuffer.log(TAG, LogLevel.DEBUG, message);
+ }
}
public boolean isVisibilityAnimating() {
@@ -94,6 +108,9 @@
.setStartDelay(mKeyguardStateController.getKeyguardFadingAwayDelay())
.setDuration(mKeyguardStateController.getShortenedFadingAwayDuration())
.start();
+ log("goingToFullShade && keyguardFadingAway");
+ } else {
+ log("goingToFullShade && !keyguardFadingAway");
}
} else if (oldStatusBarState == StatusBarState.SHADE_LOCKED && statusBarState == KEYGUARD) {
mView.setVisibility(View.VISIBLE);
@@ -105,6 +122,7 @@
.setDuration(320)
.setInterpolator(Interpolators.ALPHA_IN)
.withEndAction(mAnimateKeyguardStatusViewVisibleEndRunnable);
+ log("keyguardFadingAway transition w/ Y Aniamtion");
} else if (statusBarState == KEYGUARD) {
if (keyguardFadingAway) {
mKeyguardViewVisibilityAnimating = true;
@@ -125,9 +143,13 @@
true /* animate */);
animator.setDuration(duration)
.setStartDelay(delay);
+ log("keyguardFadingAway transition w/ Y Aniamtion");
+ } else {
+ log("keyguardFadingAway transition w/o Y Animation");
}
animator.start();
} else if (mScreenOffAnimationController.shouldAnimateInKeyguard()) {
+ log("ScreenOff transition");
mKeyguardViewVisibilityAnimating = true;
// Ask the screen off animation controller to animate the keyguard visibility for us
@@ -136,6 +158,7 @@
mView, mAnimateKeyguardStatusViewVisibleEndRunnable);
} else if (!mIsUnoccludeTransitionFlagEnabled && mLastOccludedState && !isOccluded) {
// An activity was displayed over the lock screen, and has now gone away
+ log("Unoccluded transition");
mView.setVisibility(View.VISIBLE);
mView.setAlpha(0f);
@@ -146,12 +169,14 @@
.withEndAction(mAnimateKeyguardStatusViewVisibleEndRunnable)
.start();
} else {
+ log("Direct set Visibility to VISIBLE");
mView.setVisibility(View.VISIBLE);
if (!mIsUnoccludeTransitionFlagEnabled) {
mView.setAlpha(1f);
}
}
} else {
+ log("Direct set Visibility to GONE");
mView.setVisibility(View.GONE);
mView.setAlpha(1f);
}
@@ -162,14 +187,18 @@
private final Runnable mAnimateKeyguardStatusViewInvisibleEndRunnable = () -> {
mKeyguardViewVisibilityAnimating = false;
mView.setVisibility(View.INVISIBLE);
+ log("Callback Set Visibility to INVISIBLE");
};
private final Runnable mAnimateKeyguardStatusViewGoneEndRunnable = () -> {
mKeyguardViewVisibilityAnimating = false;
mView.setVisibility(View.GONE);
+ log("CallbackSet Visibility to GONE");
};
private final Runnable mAnimateKeyguardStatusViewVisibleEndRunnable = () -> {
mKeyguardViewVisibilityAnimating = false;
+ mView.setVisibility(View.VISIBLE);
+ log("Callback Set Visibility to VISIBLE");
};
}
diff --git a/packages/SystemUI/src/com/android/keyguard/logging/KeyguardLogger.kt b/packages/SystemUI/src/com/android/keyguard/logging/KeyguardLogger.kt
index b84fb08..2c7eceb 100644
--- a/packages/SystemUI/src/com/android/keyguard/logging/KeyguardLogger.kt
+++ b/packages/SystemUI/src/com/android/keyguard/logging/KeyguardLogger.kt
@@ -17,36 +17,46 @@
package com.android.keyguard.logging
import com.android.systemui.log.dagger.KeyguardLog
-import com.android.systemui.plugins.log.ConstantStringsLogger
-import com.android.systemui.plugins.log.ConstantStringsLoggerImpl
import com.android.systemui.plugins.log.LogBuffer
-import com.android.systemui.plugins.log.LogLevel.DEBUG
-import com.android.systemui.plugins.log.LogLevel.ERROR
-import com.android.systemui.plugins.log.LogLevel.INFO
-import com.android.systemui.plugins.log.LogLevel.VERBOSE
+import com.android.systemui.plugins.log.LogLevel
import com.google.errorprone.annotations.CompileTimeConstant
import javax.inject.Inject
-private const val TAG = "KeyguardLog"
+private const val BIO_TAG = "KeyguardLog"
/**
* Generic logger for keyguard that's wrapping [LogBuffer]. This class should be used for adding
* temporary logs or logs for smaller classes when creating whole new [LogBuffer] wrapper might be
* an overkill.
*/
-class KeyguardLogger @Inject constructor(@KeyguardLog private val buffer: LogBuffer) :
- ConstantStringsLogger by ConstantStringsLoggerImpl(buffer, TAG) {
+class KeyguardLogger
+@Inject
+constructor(
+ @KeyguardLog val buffer: LogBuffer,
+) {
+ @JvmOverloads
+ fun log(
+ tag: String,
+ level: LogLevel,
+ @CompileTimeConstant msg: String,
+ ex: Throwable? = null,
+ ) = buffer.log(tag, level, msg, ex)
- fun logException(ex: Exception, @CompileTimeConstant logMsg: String) {
- buffer.log(TAG, ERROR, {}, { logMsg }, exception = ex)
- }
-
- fun v(msg: String, arg: Any) {
- buffer.log(TAG, VERBOSE, { str1 = arg.toString() }, { "$msg: $str1" })
- }
-
- fun i(msg: String, arg: Any) {
- buffer.log(TAG, INFO, { str1 = arg.toString() }, { "$msg: $str1" })
+ fun log(
+ tag: String,
+ level: LogLevel,
+ @CompileTimeConstant msg: String,
+ arg: Any,
+ ) {
+ buffer.log(
+ tag,
+ level,
+ {
+ str1 = msg
+ str2 = arg.toString()
+ },
+ { "$str1: $str2" }
+ )
}
@JvmOverloads
@@ -56,8 +66,8 @@
msg: String? = null
) {
buffer.log(
- TAG,
- DEBUG,
+ BIO_TAG,
+ LogLevel.DEBUG,
{
str1 = context
str2 = "$msgId"
diff --git a/packages/SystemUI/src/com/android/keyguard/logging/KeyguardUpdateMonitorLogger.kt b/packages/SystemUI/src/com/android/keyguard/logging/KeyguardUpdateMonitorLogger.kt
index 21d3b24..5b42455 100644
--- a/packages/SystemUI/src/com/android/keyguard/logging/KeyguardUpdateMonitorLogger.kt
+++ b/packages/SystemUI/src/com/android/keyguard/logging/KeyguardUpdateMonitorLogger.kt
@@ -132,6 +132,12 @@
logBuffer.log(TAG, DEBUG, { int1 = faceRunningState }, { "faceRunningState: $int1" })
}
+ fun logFaceUnlockPossible(isFaceUnlockPossible: Boolean) {
+ logBuffer.log(TAG, DEBUG,
+ { bool1 = isFaceUnlockPossible },
+ {"isUnlockWithFacePossible: $bool1"})
+ }
+
fun logFingerprintAuthForWrongUser(authUserId: Int) {
logBuffer.log(TAG, DEBUG,
{ int1 = authUserId },
diff --git a/packages/SystemUI/src/com/android/systemui/SystemUIInitializer.java b/packages/SystemUI/src/com/android/systemui/SystemUIInitializer.java
index 0fc9ef9..632fcdc 100644
--- a/packages/SystemUI/src/com/android/systemui/SystemUIInitializer.java
+++ b/packages/SystemUI/src/com/android/systemui/SystemUIInitializer.java
@@ -22,8 +22,6 @@
import android.os.HandlerThread;
import android.util.Log;
-import androidx.annotation.Nullable;
-
import com.android.systemui.dagger.GlobalRootComponent;
import com.android.systemui.dagger.SysUIComponent;
import com.android.systemui.dagger.WMComponent;
@@ -55,7 +53,6 @@
mContext = context;
}
- @Nullable
protected abstract GlobalRootComponent.Builder getGlobalRootComponentBuilder();
/**
@@ -72,11 +69,6 @@
* Starts the initialization process. This stands up the Dagger graph.
*/
public void init(boolean fromTest) throws ExecutionException, InterruptedException {
- GlobalRootComponent.Builder globalBuilder = getGlobalRootComponentBuilder();
- if (globalBuilder == null) {
- return;
- }
-
mRootComponent = getGlobalRootComponentBuilder()
.context(mContext)
.instrumentationTest(fromTest)
@@ -127,7 +119,6 @@
.setBackAnimation(Optional.ofNullable(null))
.setDesktopMode(Optional.ofNullable(null));
}
-
mSysUIComponent = builder.build();
if (initializeComponents) {
mSysUIComponent.init();
diff --git a/packages/SystemUI/src/com/android/systemui/SystemUIInitializerImpl.kt b/packages/SystemUI/src/com/android/systemui/SystemUIInitializerImpl.kt
index 55c095b..8aa3040 100644
--- a/packages/SystemUI/src/com/android/systemui/SystemUIInitializerImpl.kt
+++ b/packages/SystemUI/src/com/android/systemui/SystemUIInitializerImpl.kt
@@ -16,7 +16,6 @@
package com.android.systemui
-import android.app.Application
import android.content.Context
import com.android.systemui.dagger.DaggerReferenceGlobalRootComponent
import com.android.systemui.dagger.GlobalRootComponent
@@ -25,17 +24,7 @@
* {@link SystemUIInitializer} that stands up AOSP SystemUI.
*/
class SystemUIInitializerImpl(context: Context) : SystemUIInitializer(context) {
-
- override fun getGlobalRootComponentBuilder(): GlobalRootComponent.Builder? {
- return when (Application.getProcessName()) {
- SCREENSHOT_CROSS_PROFILE_PROCESS -> null
- else -> DaggerReferenceGlobalRootComponent.builder()
- }
- }
-
- companion object {
- private const val SYSTEMUI_PROCESS = "com.android.systemui"
- private const val SCREENSHOT_CROSS_PROFILE_PROCESS =
- "$SYSTEMUI_PROCESS:screenshot_cross_profile"
+ override fun getGlobalRootComponentBuilder(): GlobalRootComponent.Builder {
+ return DaggerReferenceGlobalRootComponent.builder()
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/FingerprintInteractiveToAuthProvider.java b/packages/SystemUI/src/com/android/systemui/biometrics/FingerprintInteractiveToAuthProvider.java
new file mode 100644
index 0000000..902bb18
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/FingerprintInteractiveToAuthProvider.java
@@ -0,0 +1,27 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.biometrics;
+
+/** Provides the status of the interactive to auth feature. */
+public interface FingerprintInteractiveToAuthProvider {
+ /**
+ *
+ * @param userId the user Id.
+ * @return true if the InteractiveToAuthFeature is enabled, false if disabled.
+ */
+ boolean isEnabled(int userId);
+}
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsController.java b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsController.java
index cfbde15..199e630 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsController.java
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsController.java
@@ -182,8 +182,8 @@
private int mActivePointerId = -1;
// The timestamp of the most recent touch log.
private long mTouchLogTime;
- // The timestamp of the most recent log of the UNCHANGED interaction.
- private long mLastUnchangedInteractionTime;
+ // The timestamp of the most recent log of a touch InteractionEvent.
+ private long mLastTouchInteractionTime;
// Sensor has a capture (good or bad) for this touch. No need to enable the UDFPS display mode
// anymore for this particular touch event. In other words, do not enable the UDFPS mode until
// the user touches the sensor area again.
@@ -540,12 +540,12 @@
private void logBiometricTouch(InteractionEvent event, NormalizedTouchData data) {
if (event == InteractionEvent.UNCHANGED) {
- long sinceLastLog = mSystemClock.elapsedRealtime() - mLastUnchangedInteractionTime;
+ long sinceLastLog = mSystemClock.elapsedRealtime() - mLastTouchInteractionTime;
if (sinceLastLog < MIN_UNCHANGED_INTERACTION_LOG_INTERVAL) {
return;
}
- mLastUnchangedInteractionTime = mSystemClock.elapsedRealtime();
}
+ mLastTouchInteractionTime = mSystemClock.elapsedRealtime();
final int biometricTouchReportedTouchType = toBiometricTouchReportedTouchType(event);
final InstanceId sessionIdProvider = mSessionTracker.getSessionId(
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsControllerOverlay.kt b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsControllerOverlay.kt
index a3c4985..1b6c8c6 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsControllerOverlay.kt
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsControllerOverlay.kt
@@ -33,6 +33,7 @@
import android.os.Build
import android.os.RemoteException
import android.provider.Settings
+import android.util.FeatureFlagUtils
import android.util.Log
import android.util.RotationUtils
import android.view.LayoutInflater
@@ -232,18 +233,30 @@
return when (filteredRequestReason) {
REASON_ENROLL_FIND_SENSOR,
REASON_ENROLL_ENROLLING -> {
- UdfpsEnrollViewController(
- view.addUdfpsView(R.layout.udfps_enroll_view) {
- updateSensorLocation(sensorBounds)
- },
- enrollHelper ?: throw IllegalStateException("no enrollment helper"),
- statusBarStateController,
- shadeExpansionStateManager,
- dialogManager,
- dumpManager,
- featureFlags,
- overlayParams.scaleFactor
- )
+ if (FeatureFlagUtils.isEnabled(context,
+ FeatureFlagUtils.SETTINGS_SHOW_UDFPS_ENROLL_IN_SETTINGS)) {
+ // Enroll udfps UI is handled by settings, so use empty view here
+ UdfpsFpmEmptyViewController(
+ view.addUdfpsView(R.layout.udfps_fpm_empty_view),
+ statusBarStateController,
+ shadeExpansionStateManager,
+ dialogManager,
+ dumpManager
+ )
+ } else {
+ UdfpsEnrollViewController(
+ view.addUdfpsView(R.layout.udfps_enroll_view) {
+ updateSensorLocation(sensorBounds)
+ },
+ enrollHelper ?: throw IllegalStateException("no enrollment helper"),
+ statusBarStateController,
+ shadeExpansionStateManager,
+ dialogManager,
+ dumpManager,
+ featureFlags,
+ overlayParams.scaleFactor
+ )
+ }
}
REASON_AUTH_KEYGUARD -> {
UdfpsKeyguardViewController(
@@ -277,8 +290,8 @@
}
REASON_AUTH_OTHER,
REASON_AUTH_SETTINGS -> {
- UdfpsFpmOtherViewController(
- view.addUdfpsView(R.layout.udfps_fpm_other_view),
+ UdfpsFpmEmptyViewController(
+ view.addUdfpsView(R.layout.udfps_fpm_empty_view),
statusBarStateController,
shadeExpansionStateManager,
dialogManager,
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsFpmOtherView.kt b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsFpmEmptyView.kt
similarity index 72%
rename from packages/SystemUI/src/com/android/systemui/biometrics/UdfpsFpmOtherView.kt
rename to packages/SystemUI/src/com/android/systemui/biometrics/UdfpsFpmEmptyView.kt
index 4d6da8f..e8f041e 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsFpmOtherView.kt
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsFpmEmptyView.kt
@@ -17,24 +17,19 @@
import android.content.Context
import android.util.AttributeSet
-import android.widget.ImageView
-import com.android.systemui.R
/**
- * View corresponding with udfps_fpm_other_view.xml
+ * View corresponding with udfps_fpm_empty_view.xml
+ *
+ * Currently doesn't draw anything.
*/
-class UdfpsFpmOtherView(
+class UdfpsFpmEmptyView(
context: Context,
attrs: AttributeSet?
) : UdfpsAnimationView(context, attrs) {
+ // Drawable isn't ever added to the view, so we don't currently show anything
private val fingerprintDrawable: UdfpsFpDrawable = UdfpsFpDrawable(context)
- private lateinit var fingerprintView: ImageView
-
- override fun onFinishInflate() {
- fingerprintView = findViewById(R.id.udfps_fpm_other_fp_view)!!
- fingerprintView.setImageDrawable(fingerprintDrawable)
- }
override fun getDrawable(): UdfpsDrawable = fingerprintDrawable
}
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsFpmOtherViewController.kt b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsFpmEmptyViewController.kt
similarity index 82%
rename from packages/SystemUI/src/com/android/systemui/biometrics/UdfpsFpmOtherViewController.kt
rename to packages/SystemUI/src/com/android/systemui/biometrics/UdfpsFpmEmptyViewController.kt
index 7c23278..d122d64 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsFpmOtherViewController.kt
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsFpmEmptyViewController.kt
@@ -21,18 +21,17 @@
import com.android.systemui.statusbar.phone.SystemUIDialogManager
/**
- * Class that coordinates non-HBM animations for non keyguard, enrollment or biometric prompt
- * states.
+ * Class that coordinates non-HBM animations for non keyguard, or biometric prompt states.
*
- * Currently only shows the fp drawable.
+ * Currently doesn't draw anything.
*/
-class UdfpsFpmOtherViewController(
- view: UdfpsFpmOtherView,
+class UdfpsFpmEmptyViewController(
+ view: UdfpsFpmEmptyView,
statusBarStateController: StatusBarStateController,
shadeExpansionStateManager: ShadeExpansionStateManager,
systemUIDialogManager: SystemUIDialogManager,
dumpManager: DumpManager
-) : UdfpsAnimationViewController<UdfpsFpmOtherView>(
+) : UdfpsAnimationViewController<UdfpsFpmEmptyView>(
view,
statusBarStateController,
shadeExpansionStateManager,
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/udfps/EllipseOverlapDetector.kt b/packages/SystemUI/src/com/android/systemui/biometrics/udfps/EllipseOverlapDetector.kt
index 8572242..682d38a 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/udfps/EllipseOverlapDetector.kt
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/udfps/EllipseOverlapDetector.kt
@@ -18,6 +18,7 @@
import android.graphics.Point
import android.graphics.Rect
+import androidx.annotation.VisibleForTesting
import com.android.systemui.dagger.SysUISingleton
import kotlin.math.cos
import kotlin.math.pow
@@ -50,7 +51,8 @@
return result <= 1
}
- private fun calculateSensorPoints(sensorBounds: Rect): List<Point> {
+ @VisibleForTesting
+ fun calculateSensorPoints(sensorBounds: Rect): List<Point> {
val sensorX = sensorBounds.centerX()
val sensorY = sensorBounds.centerY()
val cornerOffset: Int = sensorBounds.width() / 4
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/udfps/SinglePointerTouchProcessor.kt b/packages/SystemUI/src/com/android/systemui/biometrics/udfps/SinglePointerTouchProcessor.kt
index 338bf66..693f64a 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/udfps/SinglePointerTouchProcessor.kt
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/udfps/SinglePointerTouchProcessor.kt
@@ -27,6 +27,8 @@
import com.android.systemui.dagger.SysUISingleton
import javax.inject.Inject
+private val SUPPORTED_ROTATIONS = setOf(Surface.ROTATION_90, Surface.ROTATION_270)
+
/**
* TODO(b/259140693): Consider using an object pool of TouchProcessorResult to avoid allocations.
*/
@@ -129,19 +131,27 @@
val nativeY = naturalTouch.y / overlayParams.scaleFactor
val nativeMinor: Float = getTouchMinor(pointerIndex) / overlayParams.scaleFactor
val nativeMajor: Float = getTouchMajor(pointerIndex) / overlayParams.scaleFactor
+ var nativeOrientation: Float = getOrientation(pointerIndex)
+ if (SUPPORTED_ROTATIONS.contains(overlayParams.rotation)) {
+ nativeOrientation = toRadVerticalFromRotated(nativeOrientation.toDouble()).toFloat()
+ }
return NormalizedTouchData(
pointerId = getPointerId(pointerIndex),
x = nativeX,
y = nativeY,
minor = nativeMinor,
major = nativeMajor,
- // TODO(b/259311354): touch orientation should be reported relative to Surface.ROTATION_O.
- orientation = getOrientation(pointerIndex),
+ orientation = nativeOrientation,
time = eventTime,
gestureStart = downTime,
)
}
+private fun toRadVerticalFromRotated(rad: Double): Double {
+ val piBound = ((rad % Math.PI) + Math.PI / 2) % Math.PI
+ return if (piBound < Math.PI / 2.0) piBound else piBound - Math.PI
+}
+
/**
* Returns the [MotionEvent.getRawX] and [MotionEvent.getRawY] of the given pointer as if the device
* is in the [Surface.ROTATION_0] orientation.
@@ -152,7 +162,7 @@
): PointF {
val touchPoint = PointF(getRawX(pointerIndex), getRawY(pointerIndex))
val rot = overlayParams.rotation
- if (rot == Surface.ROTATION_90 || rot == Surface.ROTATION_270) {
+ if (SUPPORTED_ROTATIONS.contains(rot)) {
RotationUtils.rotatePointF(
touchPoint,
RotationUtils.deltaRotation(rot, Surface.ROTATION_0),
diff --git a/packages/SystemUI/src/com/android/systemui/classifier/BrightLineFalsingManager.java b/packages/SystemUI/src/com/android/systemui/classifier/BrightLineFalsingManager.java
index e8e1f2e..e9ac840 100644
--- a/packages/SystemUI/src/com/android/systemui/classifier/BrightLineFalsingManager.java
+++ b/packages/SystemUI/src/com/android/systemui/classifier/BrightLineFalsingManager.java
@@ -176,7 +176,8 @@
private @Classifier.InteractionType int mPriorInteractionType = Classifier.GENERIC;
@Inject
- public BrightLineFalsingManager(FalsingDataProvider falsingDataProvider,
+ public BrightLineFalsingManager(
+ FalsingDataProvider falsingDataProvider,
MetricsLogger metricsLogger,
@Named(BRIGHT_LINE_GESTURE_CLASSIFERS) Set<FalsingClassifier> classifiers,
SingleTapClassifier singleTapClassifier, LongTapClassifier longTapClassifier,
@@ -399,7 +400,9 @@
|| mDataProvider.isJustUnlockedWithFace()
|| mDataProvider.isDocked()
|| mAccessibilityManager.isTouchExplorationEnabled()
- || mDataProvider.isA11yAction();
+ || mDataProvider.isA11yAction()
+ || (mFeatureFlags.isEnabled(Flags.FALSING_OFF_FOR_UNFOLDED)
+ && !mDataProvider.isFolded());
}
@Override
diff --git a/packages/SystemUI/src/com/android/systemui/classifier/FalsingDataProvider.java b/packages/SystemUI/src/com/android/systemui/classifier/FalsingDataProvider.java
index 09ebeea..5f347c1 100644
--- a/packages/SystemUI/src/com/android/systemui/classifier/FalsingDataProvider.java
+++ b/packages/SystemUI/src/com/android/systemui/classifier/FalsingDataProvider.java
@@ -16,6 +16,7 @@
package com.android.systemui.classifier;
+import android.hardware.devicestate.DeviceStateManager.FoldStateListener;
import android.util.DisplayMetrics;
import android.view.MotionEvent;
import android.view.MotionEvent.PointerCoords;
@@ -42,6 +43,7 @@
private final int mWidthPixels;
private final int mHeightPixels;
private BatteryController mBatteryController;
+ private final FoldStateListener mFoldStateListener;
private final DockManager mDockManager;
private final float mXdpi;
private final float mYdpi;
@@ -65,12 +67,14 @@
public FalsingDataProvider(
DisplayMetrics displayMetrics,
BatteryController batteryController,
+ FoldStateListener foldStateListener,
DockManager dockManager) {
mXdpi = displayMetrics.xdpi;
mYdpi = displayMetrics.ydpi;
mWidthPixels = displayMetrics.widthPixels;
mHeightPixels = displayMetrics.heightPixels;
mBatteryController = batteryController;
+ mFoldStateListener = foldStateListener;
mDockManager = dockManager;
FalsingClassifier.logInfo("xdpi, ydpi: " + getXdpi() + ", " + getYdpi());
@@ -376,6 +380,10 @@
return mBatteryController.isWirelessCharging() || mDockManager.isDocked();
}
+ public boolean isFolded() {
+ return Boolean.TRUE.equals(mFoldStateListener.getFolded());
+ }
+
/** Implement to be alerted abotu the beginning and ending of falsing tracking. */
public interface SessionListener {
/** Called when the lock screen is shown and falsing-tracking begins. */
diff --git a/packages/SystemUI/src/com/android/systemui/controls/controller/ControlsBindingController.kt b/packages/SystemUI/src/com/android/systemui/controls/controller/ControlsBindingController.kt
index eed5531..9b2a224 100644
--- a/packages/SystemUI/src/com/android/systemui/controls/controller/ControlsBindingController.kt
+++ b/packages/SystemUI/src/com/android/systemui/controls/controller/ControlsBindingController.kt
@@ -51,13 +51,22 @@
fun bindAndLoadSuggested(component: ComponentName, callback: LoadCallback)
/**
- * Request to bind to the given service.
+ * Request to bind to the given service. This should only be used for services using the full
+ * [ControlsProviderService] API, where SystemUI renders the devices' UI.
*
* @param component The [ComponentName] of the service to bind
*/
fun bindService(component: ComponentName)
/**
+ * Bind to a service that provides a Device Controls panel (embedded activity). This will allow
+ * the app to remain "warm", and reduce latency.
+ *
+ * @param component The [ComponentName] of the [ControlsProviderService] to bind.
+ */
+ fun bindServiceForPanel(component: ComponentName)
+
+ /**
* Send a subscribe message to retrieve status of a set of controls.
*
* @param structureInfo structure containing the controls to update
diff --git a/packages/SystemUI/src/com/android/systemui/controls/controller/ControlsBindingControllerImpl.kt b/packages/SystemUI/src/com/android/systemui/controls/controller/ControlsBindingControllerImpl.kt
index 2f0fd99..3d6d335 100644
--- a/packages/SystemUI/src/com/android/systemui/controls/controller/ControlsBindingControllerImpl.kt
+++ b/packages/SystemUI/src/com/android/systemui/controls/controller/ControlsBindingControllerImpl.kt
@@ -170,6 +170,10 @@
retrieveLifecycleManager(component).bindService()
}
+ override fun bindServiceForPanel(component: ComponentName) {
+ retrieveLifecycleManager(component).bindServiceForPanel()
+ }
+
override fun changeUser(newUser: UserHandle) {
if (newUser == currentUser) return
diff --git a/packages/SystemUI/src/com/android/systemui/controls/controller/ControlsController.kt b/packages/SystemUI/src/com/android/systemui/controls/controller/ControlsController.kt
index 2f49c3f..f29f6d0 100644
--- a/packages/SystemUI/src/com/android/systemui/controls/controller/ControlsController.kt
+++ b/packages/SystemUI/src/com/android/systemui/controls/controller/ControlsController.kt
@@ -189,6 +189,14 @@
fun getPreferredSelection(): SelectedItem
/**
+ * Bind to a service that provides a Device Controls panel (embedded activity). This will allow
+ * the app to remain "warm", and reduce latency.
+ *
+ * @param component The [ComponentName] of the [ControlsProviderService] to bind.
+ */
+ fun bindComponentForPanel(componentName: ComponentName)
+
+ /**
* Interface for structure to pass data to [ControlsFavoritingActivity].
*/
interface LoadData {
diff --git a/packages/SystemUI/src/com/android/systemui/controls/controller/ControlsControllerImpl.kt b/packages/SystemUI/src/com/android/systemui/controls/controller/ControlsControllerImpl.kt
index 7b1c623..49771dd 100644
--- a/packages/SystemUI/src/com/android/systemui/controls/controller/ControlsControllerImpl.kt
+++ b/packages/SystemUI/src/com/android/systemui/controls/controller/ControlsControllerImpl.kt
@@ -479,6 +479,10 @@
bindingController.unsubscribe()
}
+ override fun bindComponentForPanel(componentName: ComponentName) {
+ bindingController.bindServiceForPanel(componentName)
+ }
+
override fun addFavorite(
componentName: ComponentName,
structureName: CharSequence,
diff --git a/packages/SystemUI/src/com/android/systemui/controls/controller/ControlsProviderLifecycleManager.kt b/packages/SystemUI/src/com/android/systemui/controls/controller/ControlsProviderLifecycleManager.kt
index 5b38e5b..72c3a94 100644
--- a/packages/SystemUI/src/com/android/systemui/controls/controller/ControlsProviderLifecycleManager.kt
+++ b/packages/SystemUI/src/com/android/systemui/controls/controller/ControlsProviderLifecycleManager.kt
@@ -78,6 +78,10 @@
private const val DEBUG = true
private val BIND_FLAGS = Context.BIND_AUTO_CREATE or Context.BIND_FOREGROUND_SERVICE or
Context.BIND_NOT_PERCEPTIBLE
+ // Use BIND_NOT_PERCEPTIBLE so it will be at lower priority from SystemUI.
+ // However, don't use WAIVE_PRIORITY, as by itself, it will kill the app
+ // once the Task is finished in the device controls panel.
+ private val BIND_FLAGS_PANEL = Context.BIND_AUTO_CREATE or Context.BIND_NOT_PERCEPTIBLE
}
private val intent = Intent().apply {
@@ -87,18 +91,19 @@
})
}
- private fun bindService(bind: Boolean) {
+ private fun bindService(bind: Boolean, forPanel: Boolean = false) {
executor.execute {
requiresBound = bind
if (bind) {
- if (bindTryCount != MAX_BIND_RETRIES) {
+ if (bindTryCount != MAX_BIND_RETRIES && wrapper == null) {
if (DEBUG) {
Log.d(TAG, "Binding service $intent")
}
bindTryCount++
try {
+ val flags = if (forPanel) BIND_FLAGS_PANEL else BIND_FLAGS
val bound = context
- .bindServiceAsUser(intent, serviceConnection, BIND_FLAGS, user)
+ .bindServiceAsUser(intent, serviceConnection, flags, user)
if (!bound) {
context.unbindService(serviceConnection)
}
@@ -279,6 +284,10 @@
bindService(true)
}
+ fun bindServiceForPanel() {
+ bindService(bind = true, forPanel = true)
+ }
+
/**
* Request unbind from the service.
*/
diff --git a/packages/SystemUI/src/com/android/systemui/controls/ui/ControlsUiControllerImpl.kt b/packages/SystemUI/src/com/android/systemui/controls/ui/ControlsUiControllerImpl.kt
index 1e3e5cd..6289788 100644
--- a/packages/SystemUI/src/com/android/systemui/controls/ui/ControlsUiControllerImpl.kt
+++ b/packages/SystemUI/src/com/android/systemui/controls/ui/ControlsUiControllerImpl.kt
@@ -232,6 +232,8 @@
ControlKey(selected.structure.componentName, it.ci.controlId)
}
controlsController.get().subscribeToFavorites(selected.structure)
+ } else {
+ controlsController.get().bindComponentForPanel(selected.componentName)
}
listingCallback = createCallback(::showControlsView)
}
diff --git a/packages/SystemUI/src/com/android/systemui/controls/ui/DetailDialog.kt b/packages/SystemUI/src/com/android/systemui/controls/ui/DetailDialog.kt
index edd1c68..3d9eee4 100644
--- a/packages/SystemUI/src/com/android/systemui/controls/ui/DetailDialog.kt
+++ b/packages/SystemUI/src/com/android/systemui/controls/ui/DetailDialog.kt
@@ -156,6 +156,8 @@
// Remove the task explicitly, since onRelease() callback will be executed after
// startActivity() below is called.
broadcastSender.closeSystemDialogs()
+ // not sent as interactive, lest the higher-importance activity launch
+ // be impacted
pendingIntent.send()
false
}
diff --git a/packages/SystemUI/src/com/android/systemui/dagger/SystemUIModule.java b/packages/SystemUI/src/com/android/systemui/dagger/SystemUIModule.java
index 2465286..e38c89e 100644
--- a/packages/SystemUI/src/com/android/systemui/dagger/SystemUIModule.java
+++ b/packages/SystemUI/src/com/android/systemui/dagger/SystemUIModule.java
@@ -31,6 +31,7 @@
import com.android.systemui.appops.dagger.AppOpsModule;
import com.android.systemui.assist.AssistModule;
import com.android.systemui.biometrics.AlternateUdfpsTouchProvider;
+import com.android.systemui.biometrics.FingerprintInteractiveToAuthProvider;
import com.android.systemui.biometrics.UdfpsDisplayModeProvider;
import com.android.systemui.biometrics.dagger.BiometricsModule;
import com.android.systemui.biometrics.dagger.UdfpsModule;
@@ -221,6 +222,9 @@
@BindsOptionalOf
abstract AlternateUdfpsTouchProvider optionalUdfpsTouchProvider();
+ @BindsOptionalOf
+ abstract FingerprintInteractiveToAuthProvider optionalFingerprintInteractiveToAuthProvider();
+
@SysUISingleton
@Binds
abstract SystemClock bindSystemClock(SystemClockImpl systemClock);
diff --git a/packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayStatusBarView.java b/packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayStatusBarView.java
index f244cb0..96bce4c 100644
--- a/packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayStatusBarView.java
+++ b/packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayStatusBarView.java
@@ -19,6 +19,7 @@
import android.annotation.IntDef;
import android.annotation.Nullable;
import android.content.Context;
+import android.graphics.drawable.Drawable;
import android.util.AttributeSet;
import android.view.View;
import android.view.ViewGroup;
@@ -26,6 +27,9 @@
import androidx.constraintlayout.widget.ConstraintLayout;
import com.android.systemui.R;
+import com.android.systemui.shared.shadow.DoubleShadowIconDrawable;
+import com.android.systemui.shared.shadow.DoubleShadowTextHelper.ShadowInfo;
+import com.android.systemui.statusbar.AlphaOptimizedImageView;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
@@ -60,8 +64,15 @@
public static final int STATUS_ICON_PRIORITY_MODE_ON = 6;
private final Map<Integer, View> mStatusIcons = new HashMap<>();
+ private Context mContext;
private ViewGroup mSystemStatusViewGroup;
private ViewGroup mExtraSystemStatusViewGroup;
+ private ShadowInfo mKeyShadowInfo;
+ private ShadowInfo mAmbientShadowInfo;
+ private int mDrawableSize;
+ private int mDrawableInsetSize;
+ private static final float KEY_SHADOW_ALPHA = 0.35f;
+ private static final float AMBIENT_SHADOW_ALPHA = 0.4f;
public DreamOverlayStatusBarView(Context context) {
this(context, null);
@@ -73,6 +84,7 @@
public DreamOverlayStatusBarView(Context context, AttributeSet attrs, int defStyleAttr) {
this(context, attrs, defStyleAttr, 0);
+ mContext = context;
}
public DreamOverlayStatusBarView(
@@ -80,14 +92,36 @@
super(context, attrs, defStyleAttr, defStyleRes);
}
+
@Override
protected void onFinishInflate() {
super.onFinishInflate();
+ mKeyShadowInfo = createShadowInfo(
+ R.dimen.dream_overlay_status_bar_key_text_shadow_radius,
+ R.dimen.dream_overlay_status_bar_key_text_shadow_dx,
+ R.dimen.dream_overlay_status_bar_key_text_shadow_dy,
+ KEY_SHADOW_ALPHA
+ );
+
+ mAmbientShadowInfo = createShadowInfo(
+ R.dimen.dream_overlay_status_bar_ambient_text_shadow_radius,
+ R.dimen.dream_overlay_status_bar_ambient_text_shadow_dx,
+ R.dimen.dream_overlay_status_bar_ambient_text_shadow_dy,
+ AMBIENT_SHADOW_ALPHA
+ );
+
+ mDrawableSize = mContext
+ .getResources()
+ .getDimensionPixelSize(R.dimen.dream_overlay_status_bar_icon_size);
+ mDrawableInsetSize = mContext
+ .getResources()
+ .getDimensionPixelSize(R.dimen.dream_overlay_icon_inset_dimen);
+
mStatusIcons.put(STATUS_ICON_WIFI_UNAVAILABLE,
- fetchStatusIconForResId(R.id.dream_overlay_wifi_status));
+ addDoubleShadow(fetchStatusIconForResId(R.id.dream_overlay_wifi_status)));
mStatusIcons.put(STATUS_ICON_ALARM_SET,
- fetchStatusIconForResId(R.id.dream_overlay_alarm_set));
+ addDoubleShadow(fetchStatusIconForResId(R.id.dream_overlay_alarm_set)));
mStatusIcons.put(STATUS_ICON_CAMERA_DISABLED,
fetchStatusIconForResId(R.id.dream_overlay_camera_off));
mStatusIcons.put(STATUS_ICON_MIC_DISABLED,
@@ -97,7 +131,7 @@
mStatusIcons.put(STATUS_ICON_NOTIFICATIONS,
fetchStatusIconForResId(R.id.dream_overlay_notification_indicator));
mStatusIcons.put(STATUS_ICON_PRIORITY_MODE_ON,
- fetchStatusIconForResId(R.id.dream_overlay_priority_mode));
+ addDoubleShadow(fetchStatusIconForResId(R.id.dream_overlay_priority_mode)));
mSystemStatusViewGroup = findViewById(R.id.dream_overlay_system_status);
mExtraSystemStatusViewGroup = findViewById(R.id.dream_overlay_extra_items);
@@ -137,4 +171,34 @@
}
return false;
}
+
+ private View addDoubleShadow(View icon) {
+ if (icon instanceof AlphaOptimizedImageView) {
+ AlphaOptimizedImageView i = (AlphaOptimizedImageView) icon;
+ Drawable drawableIcon = i.getDrawable();
+ i.setImageDrawable(new DoubleShadowIconDrawable(
+ mKeyShadowInfo,
+ mAmbientShadowInfo,
+ drawableIcon,
+ mDrawableSize,
+ mDrawableInsetSize
+ ));
+ }
+ return icon;
+ }
+
+ private ShadowInfo createShadowInfo(int blurId, int offsetXId, int offsetYId, float alpha) {
+ return new ShadowInfo(
+ fetchDimensionForResId(blurId),
+ fetchDimensionForResId(offsetXId),
+ fetchDimensionForResId(offsetYId),
+ alpha
+ );
+ }
+
+ private Float fetchDimensionForResId(int resId) {
+ return mContext
+ .getResources()
+ .getDimension(resId);
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/flags/Flags.kt b/packages/SystemUI/src/com/android/systemui/flags/Flags.kt
index 7ae4d8a..c880c59 100644
--- a/packages/SystemUI/src/com/android/systemui/flags/Flags.kt
+++ b/packages/SystemUI/src/com/android/systemui/flags/Flags.kt
@@ -114,8 +114,6 @@
// ** Flag retired **
// public static final BooleanFlag KEYGUARD_LAYOUT =
// new BooleanFlag(200, true);
- // TODO(b/254512713): Tracking Bug
- @JvmField val LOCKSCREEN_ANIMATIONS = releasedFlag(201, "lockscreen_animations")
// TODO(b/254512750): Tracking Bug
val NEW_UNLOCK_SWIPE_ANIMATION = releasedFlag(202, "new_unlock_swipe_animation")
@@ -165,7 +163,7 @@
// TODO(b/255618149): Tracking Bug
@JvmField
val CUSTOMIZABLE_LOCK_SCREEN_QUICK_AFFORDANCES =
- unreleasedFlag(216, "customizable_lock_screen_quick_affordances", teamfood = false)
+ unreleasedFlag(216, "customizable_lock_screen_quick_affordances", teamfood = true)
/** Shows chipbar UI whenever the device is unlocked by ActiveUnlock (watch). */
// TODO(b/256513609): Tracking Bug
@@ -202,13 +200,16 @@
/** A different path for unocclusion transitions back to keyguard */
// TODO(b/262859270): Tracking Bug
@JvmField
- val UNOCCLUSION_TRANSITION = unreleasedFlag(223, "unocclusion_transition", teamfood = false)
+ val UNOCCLUSION_TRANSITION = unreleasedFlag(223, "unocclusion_transition", teamfood = true)
// flag for controlling auto pin confirmation and material u shapes in bouncer
@JvmField
val AUTO_PIN_CONFIRMATION =
unreleasedFlag(224, "auto_pin_confirmation", "auto_pin_confirmation")
+ // TODO(b/262859270): Tracking Bug
+ @JvmField val FALSING_OFF_FOR_UNFOLDED = releasedFlag(225, "falsing_off_for_unfolded")
+
// 300 - power menu
// TODO(b/254512600): Tracking Bug
@JvmField val POWER_MENU_LITE = releasedFlag(300, "power_menu_lite")
@@ -260,10 +261,11 @@
// TODO(b/256614751): Tracking Bug
val NEW_STATUS_BAR_MOBILE_ICONS_BACKEND =
- unreleasedFlag(608, "new_status_bar_mobile_icons_backend")
+ unreleasedFlag(608, "new_status_bar_mobile_icons_backend", teamfood = true)
// TODO(b/256613548): Tracking Bug
- val NEW_STATUS_BAR_WIFI_ICON_BACKEND = unreleasedFlag(609, "new_status_bar_wifi_icon_backend")
+ val NEW_STATUS_BAR_WIFI_ICON_BACKEND =
+ unreleasedFlag(609, "new_status_bar_wifi_icon_backend", teamfood = true)
// TODO(b/256623670): Tracking Bug
@JvmField
@@ -302,7 +304,7 @@
// 900 - media
// TODO(b/254512697): Tracking Bug
- val MEDIA_TAP_TO_TRANSFER = unreleasedFlag(900, "media_tap_to_transfer", teamfood = true)
+ val MEDIA_TAP_TO_TRANSFER = releasedFlag(900, "media_tap_to_transfer")
// TODO(b/254512502): Tracking Bug
val MEDIA_SESSION_ACTIONS = unreleasedFlag(901, "media_session_actions")
@@ -332,13 +334,17 @@
val MEDIA_TTT_RECEIVER_SUCCESS_RIPPLE =
unreleasedFlag(910, "media_ttt_receiver_success_ripple", teamfood = true)
+ // TODO(b/263512203): Tracking Bug
+ val MEDIA_EXPLICIT_INDICATOR = unreleasedFlag(911, "media_explicit_indicator", teamfood = true)
+
// 1000 - dock
val SIMULATE_DOCK_THROUGH_CHARGING = releasedFlag(1000, "simulate_dock_through_charging")
// TODO(b/254512758): Tracking Bug
@JvmField val ROUNDED_BOX_RIPPLE = releasedFlag(1002, "rounded_box_ripple")
- val SHOW_LOWLIGHT_ON_DIRECT_BOOT = unreleasedFlag(1003, "show_lowlight_on_direct_boot")
+ // TODO(b/265045965): Tracking Bug
+ val SHOW_LOWLIGHT_ON_DIRECT_BOOT = releasedFlag(1003, "show_lowlight_on_direct_boot")
// 1100 - windowing
@Keep
@@ -436,9 +442,6 @@
unreleasedFlag(1206, "persist.wm.debug.predictive_back_bouncer_anim", teamfood = true)
// 1300 - screenshots
- // TODO(b/254512719): Tracking Bug
- @JvmField val SCREENSHOT_REQUEST_PROCESSOR = releasedFlag(1300, "screenshot_request_processor")
-
// TODO(b/254513155): Tracking Bug
@JvmField
val SCREENSHOT_WORK_PROFILE_POLICY =
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
index 3d4347e..18854e5 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
@@ -34,12 +34,14 @@
import static com.android.internal.widget.LockPatternUtils.StrongAuthTracker.STRONG_AUTH_REQUIRED_FOR_UNATTENDED_UPDATE;
import static com.android.systemui.DejankUtils.whitelistIpcs;
import static com.android.systemui.keyguard.ui.viewmodel.DreamingToLockscreenTransitionViewModel.LOCKSCREEN_ANIMATION_DURATION_MS;
+import static com.android.systemui.keyguard.ui.viewmodel.LockscreenToDreamingTransitionViewModel.DREAMING_ANIMATION_DURATION_MS;
import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
import android.animation.ValueAnimator;
import android.app.ActivityTaskManager;
import android.app.AlarmManager;
+import android.app.BroadcastOptions;
import android.app.PendingIntent;
import android.app.StatusBarManager;
import android.app.WindowConfiguration;
@@ -122,6 +124,8 @@
import com.android.systemui.dagger.qualifiers.UiBackground;
import com.android.systemui.dreams.DreamOverlayStateController;
import com.android.systemui.dump.DumpManager;
+import com.android.systemui.flags.FeatureFlags;
+import com.android.systemui.flags.Flags;
import com.android.systemui.keyguard.dagger.KeyguardModule;
import com.android.systemui.navigationbar.NavigationModeController;
import com.android.systemui.plugins.statusbar.StatusBarStateController;
@@ -388,6 +392,12 @@
| Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT
| Intent.FLAG_RECEIVER_VISIBLE_TO_INSTANT_APPS);
+ private static final Bundle USER_PRESENT_INTENT_OPTIONS =
+ BroadcastOptions.makeBasic()
+ .setDeferUntilActive(true)
+ .setDeliveryGroupPolicy(BroadcastOptions.DELIVERY_GROUP_POLICY_MOST_RECENT)
+ .toBundle();
+
/**
* {@link #setKeyguardEnabled} waits on this condition when it re-enables
* the keyguard.
@@ -507,6 +517,8 @@
private CentralSurfaces mCentralSurfaces;
+ private boolean mUnocclusionTransitionFlagEnabled = false;
+
private final DeviceConfig.OnPropertiesChangedListener mOnPropertiesChangedListener =
new DeviceConfig.OnPropertiesChangedListener() {
@Override
@@ -959,8 +971,9 @@
public void onAnimationStart(int transit, RemoteAnimationTarget[] apps,
RemoteAnimationTarget[] wallpapers, RemoteAnimationTarget[] nonApps,
IRemoteAnimationFinishedCallback finishedCallback) throws RemoteException {
- setOccluded(true /* isOccluded */, true /* animate */);
-
+ if (!mUnocclusionTransitionFlagEnabled) {
+ setOccluded(true /* isOccluded */, true /* animate */);
+ }
if (apps == null || apps.length == 0 || apps[0] == null) {
if (DEBUG) {
Log.d(TAG, "No apps provided to the OccludeByDream runner; "
@@ -1002,9 +1015,20 @@
applier.scheduleApply(paramsBuilder.build());
});
mOccludeByDreamAnimator.addListener(new AnimatorListenerAdapter() {
+ private boolean mIsCancelled = false;
+ @Override
+ public void onAnimationCancel(Animator animation) {
+ mIsCancelled = true;
+ }
+
@Override
public void onAnimationEnd(Animator animation) {
try {
+ if (!mIsCancelled && mUnocclusionTransitionFlagEnabled) {
+ // We're already on the main thread, don't queue this call
+ handleSetOccluded(true /* isOccluded */,
+ false /* animate */);
+ }
finishedCallback.onAnimationFinished();
mOccludeByDreamAnimator = null;
} catch (RemoteException e) {
@@ -1177,6 +1201,7 @@
ScreenOnCoordinator screenOnCoordinator,
InteractionJankMonitor interactionJankMonitor,
DreamOverlayStateController dreamOverlayStateController,
+ FeatureFlags featureFlags,
Lazy<ShadeController> shadeControllerLazy,
Lazy<NotificationShadeWindowController> notificationShadeWindowControllerLazy,
Lazy<ActivityLaunchAnimator> activityLaunchAnimator,
@@ -1231,9 +1256,9 @@
R.dimen.physical_power_button_center_screen_location_y);
mWindowCornerRadius = ScreenDecorationsUtils.getWindowCornerRadius(context);
- mDreamOpenAnimationDuration = context.getResources().getInteger(
- com.android.internal.R.integer.config_dreamOpenAnimationDuration);
+ mDreamOpenAnimationDuration = (int) DREAMING_ANIMATION_DURATION_MS;
mDreamCloseAnimationDuration = (int) LOCKSCREEN_ANIMATION_DURATION_MS;
+ mUnocclusionTransitionFlagEnabled = featureFlags.isEnabled(Flags.UNOCCLUSION_TRANSITION);
}
public void userActivity() {
@@ -1793,7 +1818,6 @@
Trace.beginSection("KeyguardViewMediator#setOccluded");
if (DEBUG) Log.d(TAG, "setOccluded " + isOccluded);
- mInteractionJankMonitor.cancel(CUJ_LOCKSCREEN_TRANSITION_FROM_AOD);
mHandler.removeMessages(SET_OCCLUDED);
Message msg = mHandler.obtainMessage(SET_OCCLUDED, isOccluded ? 1 : 0, animate ? 1 : 0);
mHandler.sendMessage(msg);
@@ -1826,6 +1850,8 @@
private void handleSetOccluded(boolean isOccluded, boolean animate) {
Trace.beginSection("KeyguardViewMediator#handleSetOccluded");
Log.d(TAG, "handleSetOccluded(" + isOccluded + ")");
+ mInteractionJankMonitor.cancel(CUJ_LOCKSCREEN_TRANSITION_FROM_AOD);
+
synchronized (KeyguardViewMediator.this) {
if (mHiding && isOccluded) {
// We're in the process of going away but WindowManager wants to show a
@@ -1902,13 +1928,23 @@
return;
}
- // if the keyguard is already showing, don't bother. check flags in both files
- // to account for the hiding animation which results in a delay and discrepancy
- // between flags
+ // If the keyguard is already showing, see if we don't need to bother re-showing it. Check
+ // flags in both files to account for the hiding animation which results in a delay and
+ // discrepancy between flags.
if (mShowing && mKeyguardStateController.isShowing()) {
- if (DEBUG) Log.d(TAG, "doKeyguard: not showing because it is already showing");
- resetStateLocked();
- return;
+ if (mPM.isInteractive()) {
+ // It's already showing, and we're not trying to show it while the screen is off.
+ // We can simply reset all of the views.
+ if (DEBUG) Log.d(TAG, "doKeyguard: not showing because it is already showing");
+ resetStateLocked();
+ return;
+ } else {
+ // We are trying to show the keyguard while the screen is off - this results from
+ // race conditions involving locking while unlocking. Don't short-circuit here and
+ // ensure the keyguard is fully re-shown.
+ Log.e(TAG,
+ "doKeyguard: already showing, but re-showing since we're not interactive");
+ }
}
// In split system user mode, we never unlock system user.
@@ -2300,7 +2336,10 @@
Context.USER_SERVICE);
mUiBgExecutor.execute(() -> {
for (int profileId : um.getProfileIdsWithDisabled(currentUser.getIdentifier())) {
- mContext.sendBroadcastAsUser(USER_PRESENT_INTENT, UserHandle.of(profileId));
+ mContext.sendBroadcastAsUser(USER_PRESENT_INTENT,
+ UserHandle.of(profileId),
+ null,
+ USER_PRESENT_INTENT_OPTIONS);
}
mLockPatternUtils.userPresent(currentUserId);
});
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/WakefulnessLifecycle.java b/packages/SystemUI/src/com/android/systemui/keyguard/WakefulnessLifecycle.java
index 017b65a..ffd8a02 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/WakefulnessLifecycle.java
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/WakefulnessLifecycle.java
@@ -33,6 +33,7 @@
import com.android.systemui.R;
import com.android.systemui.dagger.SysUISingleton;
import com.android.systemui.dump.DumpManager;
+import com.android.systemui.util.time.SystemClock;
import java.io.PrintWriter;
import java.lang.annotation.Retention;
@@ -63,6 +64,7 @@
private final Context mContext;
private final DisplayMetrics mDisplayMetrics;
+ private final SystemClock mSystemClock;
@Nullable
private final IWallpaperManager mWallpaperManagerService;
@@ -71,6 +73,9 @@
private @PowerManager.WakeReason int mLastWakeReason = PowerManager.WAKE_REASON_UNKNOWN;
+ public static final long UNKNOWN_LAST_WAKE_TIME = -1;
+ private long mLastWakeTime = UNKNOWN_LAST_WAKE_TIME;
+
@Nullable
private Point mLastWakeOriginLocation = null;
@@ -84,10 +89,12 @@
public WakefulnessLifecycle(
Context context,
@Nullable IWallpaperManager wallpaperManagerService,
+ SystemClock systemClock,
DumpManager dumpManager) {
mContext = context;
mDisplayMetrics = context.getResources().getDisplayMetrics();
mWallpaperManagerService = wallpaperManagerService;
+ mSystemClock = systemClock;
dumpManager.registerDumpable(getClass().getSimpleName(), this);
}
@@ -104,6 +111,14 @@
}
/**
+ * Returns the most recent time (in device uptimeMillis) the display woke up.
+ * Returns {@link UNKNOWN_LAST_WAKE_TIME} if there hasn't been a wakeup yet.
+ */
+ public long getLastWakeTime() {
+ return mLastWakeTime;
+ }
+
+ /**
* Returns the most recent reason the device went to sleep up. This is one of
* PowerManager.GO_TO_SLEEP_REASON_*.
*/
@@ -117,6 +132,7 @@
}
setWakefulness(WAKEFULNESS_WAKING);
mLastWakeReason = pmWakeReason;
+ mLastWakeTime = mSystemClock.uptimeMillis();
updateLastWakeOriginLocation();
if (mWallpaperManagerService != null) {
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/dagger/KeyguardModule.java b/packages/SystemUI/src/com/android/systemui/keyguard/dagger/KeyguardModule.java
index 47ef0fa..98d3570 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/dagger/KeyguardModule.java
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/dagger/KeyguardModule.java
@@ -39,6 +39,7 @@
import com.android.systemui.dagger.qualifiers.UiBackground;
import com.android.systemui.dreams.DreamOverlayStateController;
import com.android.systemui.dump.DumpManager;
+import com.android.systemui.flags.FeatureFlags;
import com.android.systemui.keyguard.DismissCallbackRegistry;
import com.android.systemui.keyguard.KeyguardUnlockAnimationController;
import com.android.systemui.keyguard.KeyguardViewMediator;
@@ -112,6 +113,7 @@
ScreenOnCoordinator screenOnCoordinator,
InteractionJankMonitor interactionJankMonitor,
DreamOverlayStateController dreamOverlayStateController,
+ FeatureFlags featureFlags,
Lazy<ShadeController> shadeController,
Lazy<NotificationShadeWindowController> notificationShadeWindowController,
Lazy<ActivityLaunchAnimator> activityLaunchAnimator,
@@ -142,6 +144,7 @@
screenOnCoordinator,
interactionJankMonitor,
dreamOverlayStateController,
+ featureFlags,
shadeController,
notificationShadeWindowController,
activityLaunchAnimator,
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/KeyguardRepository.kt b/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/KeyguardRepository.kt
index a4fd087..d99af90 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/KeyguardRepository.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/KeyguardRepository.kt
@@ -40,6 +40,7 @@
import com.android.systemui.plugins.statusbar.StatusBarStateController
import com.android.systemui.statusbar.phone.BiometricUnlockController
import com.android.systemui.statusbar.phone.BiometricUnlockController.WakeAndUnlockMode
+import com.android.systemui.statusbar.phone.DozeParameters
import com.android.systemui.statusbar.policy.KeyguardStateController
import javax.inject.Inject
import kotlinx.coroutines.channels.awaitClose
@@ -88,6 +89,9 @@
/** Observable for whether the bouncer is showing. */
val isBouncerShowing: Flow<Boolean>
+ /** Is the always-on display available to be used? */
+ val isAodAvailable: Flow<Boolean>
+
/**
* Observable for whether we are in doze state.
*
@@ -182,6 +186,7 @@
private val keyguardStateController: KeyguardStateController,
private val keyguardUpdateMonitor: KeyguardUpdateMonitor,
private val dozeTransitionListener: DozeTransitionListener,
+ private val dozeParameters: DozeParameters,
private val authController: AuthController,
private val dreamOverlayCallbackController: DreamOverlayCallbackController,
) : KeyguardRepository {
@@ -220,6 +225,31 @@
}
.distinctUntilChanged()
+ override val isAodAvailable: Flow<Boolean> =
+ conflatedCallbackFlow {
+ val callback =
+ object : DozeParameters.Callback {
+ override fun onAlwaysOnChange() {
+ trySendWithFailureLogging(
+ dozeParameters.getAlwaysOn(),
+ TAG,
+ "updated isAodAvailable"
+ )
+ }
+ }
+
+ dozeParameters.addCallback(callback)
+ // Adding the callback does not send an initial update.
+ trySendWithFailureLogging(
+ dozeParameters.getAlwaysOn(),
+ TAG,
+ "initial isAodAvailable"
+ )
+
+ awaitClose { dozeParameters.removeCallback(callback) }
+ }
+ .distinctUntilChanged()
+
override val isKeyguardOccluded: Flow<Boolean> =
conflatedCallbackFlow {
val callback =
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/KeyguardTransitionRepository.kt b/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/KeyguardTransitionRepository.kt
index 343c2dc..0c4bca6 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/KeyguardTransitionRepository.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/KeyguardTransitionRepository.kt
@@ -135,11 +135,14 @@
Log.i(TAG, "Duplicate call to start the transition, rejecting: $info")
return null
}
- if (lastStep.transitionState != TransitionState.FINISHED) {
- Log.i(TAG, "Transition still active: $lastStep, canceling")
- }
+ val startingValue =
+ if (lastStep.transitionState != TransitionState.FINISHED) {
+ Log.i(TAG, "Transition still active: $lastStep, canceling")
+ lastStep.value
+ } else {
+ 0f
+ }
- val startingValue = 1f - lastStep.value
lastAnimator?.cancel()
lastAnimator = info.animator
@@ -206,7 +209,7 @@
return
}
- if (state == TransitionState.FINISHED) {
+ if (state == TransitionState.FINISHED || state == TransitionState.CANCELED) {
updateTransitionId = null
}
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromDozingTransitionInteractor.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromDozingTransitionInteractor.kt
index fd2d271..ce61f2f 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromDozingTransitionInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromDozingTransitionInteractor.kt
@@ -21,9 +21,9 @@
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.dagger.qualifiers.Application
import com.android.systemui.keyguard.data.repository.KeyguardTransitionRepository
-import com.android.systemui.keyguard.shared.model.DozeStateModel.Companion.isDozeOff
import com.android.systemui.keyguard.shared.model.KeyguardState
import com.android.systemui.keyguard.shared.model.TransitionInfo
+import com.android.systemui.keyguard.shared.model.WakefulnessModel.Companion.isWakingOrStartingToWake
import com.android.systemui.util.kotlin.sample
import javax.inject.Inject
import kotlin.time.Duration
@@ -48,12 +48,11 @@
private fun listenForDozingToLockscreen() {
scope.launch {
- keyguardInteractor.dozeTransitionModel
+ keyguardInteractor.wakefulnessModel
.sample(keyguardTransitionInteractor.startedKeyguardTransitionStep, ::Pair)
- .collect { pair ->
- val (dozeTransitionModel, lastStartedTransition) = pair
+ .collect { (wakefulnessModel, lastStartedTransition) ->
if (
- isDozeOff(dozeTransitionModel.to) &&
+ isWakingOrStartingToWake(wakefulnessModel) &&
lastStartedTransition.to == KeyguardState.DOZING
) {
keyguardTransitionRepository.startTransition(
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromDreamingTransitionInteractor.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromDreamingTransitionInteractor.kt
index 3b09ae7..7134ec0 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromDreamingTransitionInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromDreamingTransitionInteractor.kt
@@ -21,7 +21,7 @@
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.dagger.qualifiers.Application
import com.android.systemui.keyguard.data.repository.KeyguardTransitionRepository
-import com.android.systemui.keyguard.shared.model.BiometricUnlockModel.Companion.isWakeAndUnlock
+import com.android.systemui.keyguard.shared.model.BiometricUnlockModel
import com.android.systemui.keyguard.shared.model.DozeStateModel
import com.android.systemui.keyguard.shared.model.DozeStateModel.Companion.isDozeOff
import com.android.systemui.keyguard.shared.model.KeyguardState
@@ -56,7 +56,7 @@
scope.launch {
// Using isDreamingWithOverlay provides an optimized path to LOCKSCREEN state, which
// otherwise would have gone through OCCLUDED first
- keyguardInteractor.isDreamingWithOverlay
+ keyguardInteractor.isAbleToDream
.sample(
combine(
keyguardInteractor.dozeTransitionModel,
@@ -65,8 +65,7 @@
),
::toTriple
)
- .collect { triple ->
- val (isDreaming, dozeTransitionModel, lastStartedTransition) = triple
+ .collect { (isDreaming, dozeTransitionModel, lastStartedTransition) ->
if (
!isDreaming &&
isDozeOff(dozeTransitionModel.to) &&
@@ -96,8 +95,7 @@
),
::toTriple
)
- .collect { triple ->
- val (isDreaming, isOccluded, lastStartedTransition) = triple
+ .collect { (isDreaming, isOccluded, lastStartedTransition) ->
if (
isOccluded &&
!isDreaming &&
@@ -123,24 +121,18 @@
private fun listenForDreamingToGone() {
scope.launch {
- keyguardInteractor.biometricUnlockState
- .sample(keyguardTransitionInteractor.finishedKeyguardState, ::Pair)
- .collect { pair ->
- val (biometricUnlockState, keyguardState) = pair
- if (
- keyguardState == KeyguardState.DREAMING &&
- isWakeAndUnlock(biometricUnlockState)
- ) {
- keyguardTransitionRepository.startTransition(
- TransitionInfo(
- name,
- KeyguardState.DREAMING,
- KeyguardState.GONE,
- getAnimator(),
- )
+ keyguardInteractor.biometricUnlockState.collect { biometricUnlockState ->
+ if (biometricUnlockState == BiometricUnlockModel.WAKE_AND_UNLOCK_FROM_DREAM) {
+ keyguardTransitionRepository.startTransition(
+ TransitionInfo(
+ name,
+ KeyguardState.DREAMING,
+ KeyguardState.GONE,
+ getAnimator(),
)
- }
+ )
}
+ }
}
}
@@ -151,8 +143,7 @@
keyguardTransitionInteractor.finishedKeyguardState,
::Pair
)
- .collect { pair ->
- val (dozeTransitionModel, keyguardState) = pair
+ .collect { (dozeTransitionModel, keyguardState) ->
if (
dozeTransitionModel.to == DozeStateModel.DOZE &&
keyguardState == KeyguardState.DREAMING
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromGoneTransitionInteractor.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromGoneTransitionInteractor.kt
index 553fafe..9203a9b 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromGoneTransitionInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromGoneTransitionInteractor.kt
@@ -26,7 +26,10 @@
import com.android.systemui.keyguard.shared.model.WakefulnessState
import com.android.systemui.util.kotlin.sample
import javax.inject.Inject
+import kotlin.time.Duration
+import kotlin.time.Duration.Companion.milliseconds
import kotlinx.coroutines.CoroutineScope
+import kotlinx.coroutines.flow.combine
import kotlinx.coroutines.launch
@SysUISingleton
@@ -40,7 +43,7 @@
) : TransitionInteractor(FromGoneTransitionInteractor::class.simpleName!!) {
override fun start() {
- listenForGoneToAod()
+ listenForGoneToAodOrDozing()
listenForGoneToDreaming()
}
@@ -56,7 +59,7 @@
name,
KeyguardState.GONE,
KeyguardState.DREAMING,
- getAnimator(),
+ getAnimator(TO_DREAMING_DURATION),
)
)
}
@@ -64,12 +67,18 @@
}
}
- private fun listenForGoneToAod() {
+ private fun listenForGoneToAodOrDozing() {
scope.launch {
keyguardInteractor.wakefulnessModel
- .sample(keyguardTransitionInteractor.finishedKeyguardState, ::Pair)
- .collect { pair ->
- val (wakefulnessState, keyguardState) = pair
+ .sample(
+ combine(
+ keyguardTransitionInteractor.finishedKeyguardState,
+ keyguardInteractor.isAodAvailable,
+ ::Pair
+ ),
+ ::toTriple
+ )
+ .collect { (wakefulnessState, keyguardState, isAodAvailable) ->
if (
keyguardState == KeyguardState.GONE &&
wakefulnessState.state == WakefulnessState.STARTING_TO_SLEEP
@@ -78,7 +87,11 @@
TransitionInfo(
name,
KeyguardState.GONE,
- KeyguardState.AOD,
+ if (isAodAvailable) {
+ KeyguardState.AOD
+ } else {
+ KeyguardState.DOZING
+ },
getAnimator(),
)
)
@@ -87,14 +100,15 @@
}
}
- private fun getAnimator(): ValueAnimator {
+ private fun getAnimator(duration: Duration = DEFAULT_DURATION): ValueAnimator {
return ValueAnimator().apply {
setInterpolator(Interpolators.LINEAR)
- setDuration(TRANSITION_DURATION_MS)
+ setDuration(duration.inWholeMilliseconds)
}
}
companion object {
- private const val TRANSITION_DURATION_MS = 500L
+ private val DEFAULT_DURATION = 500.milliseconds
+ val TO_DREAMING_DURATION = 933.milliseconds
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromLockscreenTransitionInteractor.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromLockscreenTransitionInteractor.kt
index 326acc9..5674e2a 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromLockscreenTransitionInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromLockscreenTransitionInteractor.kt
@@ -21,15 +21,17 @@
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.dagger.qualifiers.Application
import com.android.systemui.keyguard.data.repository.KeyguardTransitionRepository
-import com.android.systemui.keyguard.shared.model.DozeStateModel
import com.android.systemui.keyguard.shared.model.KeyguardState
import com.android.systemui.keyguard.shared.model.StatusBarState.KEYGUARD
import com.android.systemui.keyguard.shared.model.TransitionInfo
import com.android.systemui.keyguard.shared.model.TransitionState
+import com.android.systemui.keyguard.shared.model.WakefulnessState
import com.android.systemui.shade.data.repository.ShadeRepository
import com.android.systemui.util.kotlin.sample
import java.util.UUID
import javax.inject.Inject
+import kotlin.time.Duration
+import kotlin.time.Duration.Companion.milliseconds
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.flow.collect
import kotlinx.coroutines.flow.combine
@@ -46,12 +48,11 @@
private val keyguardTransitionRepository: KeyguardTransitionRepository,
) : TransitionInteractor(FromLockscreenTransitionInteractor::class.simpleName!!) {
- private var transitionId: UUID? = null
-
override fun start() {
listenForLockscreenToGone()
listenForLockscreenToOccluded()
- listenForLockscreenToAod()
+ listenForLockscreenToCamera()
+ listenForLockscreenToAodOrDozing()
listenForLockscreenToBouncer()
listenForLockscreenToDreaming()
listenForLockscreenToBouncerDragging()
@@ -69,7 +70,7 @@
name,
KeyguardState.LOCKSCREEN,
KeyguardState.DREAMING,
- getAnimator(),
+ getAnimator(TO_DREAMING_DURATION),
)
)
}
@@ -101,6 +102,7 @@
/* Starts transitions when manually dragging up the bouncer from the lockscreen. */
private fun listenForLockscreenToBouncerDragging() {
+ var transitionId: UUID? = null
scope.launch {
shadeRepository.shadeModel
.sample(
@@ -111,25 +113,43 @@
),
::toTriple
)
- .collect { triple ->
- val (shadeModel, keyguardState, statusBarState) = triple
-
+ .collect { (shadeModel, keyguardState, statusBarState) ->
val id = transitionId
if (id != null) {
// An existing `id` means a transition is started, and calls to
- // `updateTransition` will control it until FINISHED
- keyguardTransitionRepository.updateTransition(
- id,
- 1f - shadeModel.expansionAmount,
- if (
- shadeModel.expansionAmount == 0f || shadeModel.expansionAmount == 1f
- ) {
- transitionId = null
+ // `updateTransition` will control it until FINISHED or CANCELED
+ var nextState =
+ if (shadeModel.expansionAmount == 0f) {
TransitionState.FINISHED
+ } else if (shadeModel.expansionAmount == 1f) {
+ TransitionState.CANCELED
} else {
TransitionState.RUNNING
}
+ keyguardTransitionRepository.updateTransition(
+ id,
+ 1f - shadeModel.expansionAmount,
+ nextState,
)
+
+ if (
+ nextState == TransitionState.CANCELED ||
+ nextState == TransitionState.FINISHED
+ ) {
+ transitionId = null
+ }
+
+ // If canceled, just put the state back
+ if (nextState == TransitionState.CANCELED) {
+ keyguardTransitionRepository.startTransition(
+ TransitionInfo(
+ ownerName = name,
+ from = KeyguardState.BOUNCER,
+ to = KeyguardState.LOCKSCREEN,
+ animator = getAnimator(0.milliseconds)
+ )
+ )
+ }
} else {
// TODO (b/251849525): Remove statusbarstate check when that state is
// integrated into KeyguardTransitionRepository
@@ -184,17 +204,14 @@
),
::toTriple
)
- .collect { triple ->
- val (isOccluded, keyguardState, isDreaming) = triple
- // Occlusion signals come from the framework, and should interrupt any
- // existing transition
- if (isOccluded && !isDreaming) {
+ .collect { (isOccluded, keyguardState, isDreaming) ->
+ if (isOccluded && !isDreaming && keyguardState == KeyguardState.LOCKSCREEN) {
keyguardTransitionRepository.startTransition(
TransitionInfo(
name,
keyguardState,
KeyguardState.OCCLUDED,
- getAnimator(),
+ getAnimator(TO_OCCLUDED_DURATION),
)
)
}
@@ -202,19 +219,59 @@
}
}
- private fun listenForLockscreenToAod() {
+ /** This signal may come in before the occlusion signal, and can provide a custom transition */
+ private fun listenForLockscreenToCamera() {
scope.launch {
- keyguardInteractor
- .dozeTransitionTo(DozeStateModel.DOZE_AOD)
+ keyguardInteractor.onCameraLaunchDetected
.sample(keyguardTransitionInteractor.startedKeyguardTransitionStep, ::Pair)
- .collect { pair ->
- val (dozeToAod, lastStartedStep) = pair
- if (lastStartedStep.to == KeyguardState.LOCKSCREEN) {
+ .collect { (_, lastStartedStep) ->
+ // DREAMING/AOD/OFF may trigger on the first power button push, so include this
+ // state in order to cancel and correct the transition
+ if (
+ lastStartedStep.to == KeyguardState.LOCKSCREEN ||
+ lastStartedStep.to == KeyguardState.DREAMING ||
+ lastStartedStep.to == KeyguardState.DOZING ||
+ lastStartedStep.to == KeyguardState.AOD ||
+ lastStartedStep.to == KeyguardState.OFF
+ ) {
keyguardTransitionRepository.startTransition(
TransitionInfo(
name,
KeyguardState.LOCKSCREEN,
- KeyguardState.AOD,
+ KeyguardState.OCCLUDED,
+ getAnimator(TO_OCCLUDED_DURATION),
+ )
+ )
+ }
+ }
+ }
+ }
+
+ private fun listenForLockscreenToAodOrDozing() {
+ scope.launch {
+ keyguardInteractor.wakefulnessModel
+ .sample(
+ combine(
+ keyguardTransitionInteractor.startedKeyguardTransitionStep,
+ keyguardInteractor.isAodAvailable,
+ ::Pair
+ ),
+ ::toTriple
+ )
+ .collect { (wakefulnessState, lastStartedStep, isAodAvailable) ->
+ if (
+ lastStartedStep.to == KeyguardState.LOCKSCREEN &&
+ wakefulnessState.state == WakefulnessState.STARTING_TO_SLEEP
+ ) {
+ keyguardTransitionRepository.startTransition(
+ TransitionInfo(
+ name,
+ KeyguardState.LOCKSCREEN,
+ if (isAodAvailable) {
+ KeyguardState.AOD
+ } else {
+ KeyguardState.DOZING
+ },
getAnimator(),
)
)
@@ -223,14 +280,16 @@
}
}
- private fun getAnimator(): ValueAnimator {
+ private fun getAnimator(duration: Duration = DEFAULT_DURATION): ValueAnimator {
return ValueAnimator().apply {
setInterpolator(Interpolators.LINEAR)
- setDuration(TRANSITION_DURATION_MS)
+ setDuration(duration.inWholeMilliseconds)
}
}
companion object {
- private const val TRANSITION_DURATION_MS = 500L
+ private val DEFAULT_DURATION = 500.milliseconds
+ val TO_DREAMING_DURATION = 933.milliseconds
+ val TO_OCCLUDED_DURATION = 450.milliseconds
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromOccludedTransitionInteractor.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromOccludedTransitionInteractor.kt
index 8878901..2dc8fee 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromOccludedTransitionInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromOccludedTransitionInteractor.kt
@@ -23,12 +23,14 @@
import com.android.systemui.keyguard.data.repository.KeyguardTransitionRepository
import com.android.systemui.keyguard.shared.model.KeyguardState
import com.android.systemui.keyguard.shared.model.TransitionInfo
+import com.android.systemui.keyguard.shared.model.WakefulnessState
import com.android.systemui.util.kotlin.sample
import javax.inject.Inject
import kotlin.time.Duration
import kotlin.time.Duration.Companion.milliseconds
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.flow.collect
+import kotlinx.coroutines.flow.combine
import kotlinx.coroutines.launch
@SysUISingleton
@@ -44,6 +46,7 @@
override fun start() {
listenForOccludedToLockscreen()
listenForOccludedToDreaming()
+ listenForOccludedToAodOrDozing()
}
private fun listenForOccludedToDreaming() {
@@ -70,8 +73,7 @@
scope.launch {
keyguardInteractor.isKeyguardOccluded
.sample(keyguardTransitionInteractor.startedKeyguardTransitionStep, ::Pair)
- .collect { pair ->
- val (isOccluded, lastStartedKeyguardState) = pair
+ .collect { (isOccluded, lastStartedKeyguardState) ->
// Occlusion signals come from the framework, and should interrupt any
// existing transition
if (!isOccluded && lastStartedKeyguardState.to == KeyguardState.OCCLUDED) {
@@ -88,6 +90,39 @@
}
}
+ private fun listenForOccludedToAodOrDozing() {
+ scope.launch {
+ keyguardInteractor.wakefulnessModel
+ .sample(
+ combine(
+ keyguardTransitionInteractor.startedKeyguardTransitionStep,
+ keyguardInteractor.isAodAvailable,
+ ::Pair
+ ),
+ ::toTriple
+ )
+ .collect { (wakefulnessState, lastStartedStep, isAodAvailable) ->
+ if (
+ lastStartedStep.to == KeyguardState.OCCLUDED &&
+ wakefulnessState.state == WakefulnessState.STARTING_TO_SLEEP
+ ) {
+ keyguardTransitionRepository.startTransition(
+ TransitionInfo(
+ name,
+ KeyguardState.OCCLUDED,
+ if (isAodAvailable) {
+ KeyguardState.AOD
+ } else {
+ KeyguardState.DOZING
+ },
+ getAnimator(),
+ )
+ )
+ }
+ }
+ }
+ }
+
private fun getAnimator(duration: Duration = DEFAULT_DURATION): ValueAnimator {
return ValueAnimator().apply {
setInterpolator(Interpolators.LINEAR)
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardInteractor.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardInteractor.kt
index 402c179..4cf56fe 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardInteractor.kt
@@ -17,20 +17,30 @@
package com.android.systemui.keyguard.domain.interactor
+import android.app.StatusBarManager
import android.graphics.Point
+import com.android.systemui.common.coroutine.ChannelExt.trySendWithFailureLogging
+import com.android.systemui.common.coroutine.ConflatedCallbackFlow.conflatedCallbackFlow
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.keyguard.data.repository.KeyguardRepository
import com.android.systemui.keyguard.shared.model.BiometricUnlockModel
+import com.android.systemui.keyguard.shared.model.CameraLaunchSourceModel
import com.android.systemui.keyguard.shared.model.DozeStateModel
import com.android.systemui.keyguard.shared.model.DozeStateModel.Companion.isDozeOff
import com.android.systemui.keyguard.shared.model.DozeTransitionModel
import com.android.systemui.keyguard.shared.model.StatusBarState
import com.android.systemui.keyguard.shared.model.WakefulnessModel
-import com.android.systemui.util.kotlin.sample
+import com.android.systemui.statusbar.CommandQueue
+import com.android.systemui.statusbar.CommandQueue.Callbacks
import javax.inject.Inject
+import kotlinx.coroutines.channels.awaitClose
+import kotlinx.coroutines.delay
import kotlinx.coroutines.flow.Flow
+import kotlinx.coroutines.flow.combine
import kotlinx.coroutines.flow.distinctUntilChanged
import kotlinx.coroutines.flow.filter
+import kotlinx.coroutines.flow.flatMapLatest
+import kotlinx.coroutines.flow.flow
import kotlinx.coroutines.flow.merge
/**
@@ -41,6 +51,7 @@
@Inject
constructor(
private val repository: KeyguardRepository,
+ private val commandQueue: CommandQueue,
) {
/**
* The amount of doze the system is in, where `1.0` is fully dozing and `0.0` is not dozing at
@@ -49,6 +60,8 @@
val dozeAmount: Flow<Float> = repository.linearDozeAmount
/** Whether the system is in doze mode. */
val isDozing: Flow<Boolean> = repository.isDozing
+ /** Whether Always-on Display mode is available. */
+ val isAodAvailable: Flow<Boolean> = repository.isAodAvailable
/** Doze transition information. */
val dozeTransitionModel: Flow<DozeTransitionModel> = repository.dozeTransitionModel
/**
@@ -58,19 +71,44 @@
val isDreaming: Flow<Boolean> = repository.isDreaming
/** Whether the system is dreaming with an overlay active */
val isDreamingWithOverlay: Flow<Boolean> = repository.isDreamingWithOverlay
+ /** Event for when the camera gesture is detected */
+ val onCameraLaunchDetected: Flow<CameraLaunchSourceModel> = conflatedCallbackFlow {
+ val callback =
+ object : CommandQueue.Callbacks {
+ override fun onCameraLaunchGestureDetected(source: Int) {
+ trySendWithFailureLogging(
+ cameraLaunchSourceIntToModel(source),
+ TAG,
+ "updated onCameraLaunchGestureDetected"
+ )
+ }
+ }
+
+ commandQueue.addCallback(callback)
+
+ awaitClose { commandQueue.removeCallback(callback) }
+ }
/**
* Dozing and dreaming have overlapping events. If the doze state remains in FINISH, it means
* that doze mode is not running and DREAMING is ok to commence.
+ *
+ * Allow a brief moment to prevent rapidly oscillating between true/false signals.
*/
val isAbleToDream: Flow<Boolean> =
merge(isDreaming, isDreamingWithOverlay)
- .sample(
+ .combine(
dozeTransitionModel,
{ isDreaming, dozeTransitionModel ->
isDreaming && isDozeOff(dozeTransitionModel.to)
}
)
+ .flatMapLatest { isAbleToDream ->
+ flow {
+ delay(50)
+ emit(isAbleToDream)
+ }
+ }
.distinctUntilChanged()
/** Whether the keyguard is showing or not. */
@@ -103,4 +141,21 @@
fun isKeyguardShowing(): Boolean {
return repository.isKeyguardShowing()
}
+
+ private fun cameraLaunchSourceIntToModel(value: Int): CameraLaunchSourceModel {
+ return when (value) {
+ StatusBarManager.CAMERA_LAUNCH_SOURCE_WIGGLE -> CameraLaunchSourceModel.WIGGLE
+ StatusBarManager.CAMERA_LAUNCH_SOURCE_POWER_DOUBLE_TAP ->
+ CameraLaunchSourceModel.POWER_DOUBLE_TAP
+ StatusBarManager.CAMERA_LAUNCH_SOURCE_LIFT_TRIGGER ->
+ CameraLaunchSourceModel.LIFT_TRIGGER
+ StatusBarManager.CAMERA_LAUNCH_SOURCE_QUICK_AFFORDANCE ->
+ CameraLaunchSourceModel.QUICK_AFFORDANCE
+ else -> throw IllegalArgumentException("Invalid CameraLaunchSourceModel value: $value")
+ }
+ }
+
+ companion object {
+ private const val TAG = "KeyguardInteractor"
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardTransitionAuditLogger.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardTransitionAuditLogger.kt
index a2661d7..d4e23499 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardTransitionAuditLogger.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardTransitionAuditLogger.kt
@@ -19,11 +19,14 @@
import com.android.keyguard.logging.KeyguardLogger
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.dagger.qualifiers.Application
+import com.android.systemui.plugins.log.LogLevel.VERBOSE
import javax.inject.Inject
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.flow.collect
import kotlinx.coroutines.launch
+private val TAG = KeyguardTransitionAuditLogger::class.simpleName!!
+
/** Collect flows of interest for auditing keyguard transitions. */
@SysUISingleton
class KeyguardTransitionAuditLogger
@@ -37,35 +40,47 @@
fun start() {
scope.launch {
- keyguardInteractor.wakefulnessModel.collect { logger.v("WakefulnessModel", it) }
+ keyguardInteractor.wakefulnessModel.collect {
+ logger.log(TAG, VERBOSE, "WakefulnessModel", it)
+ }
}
scope.launch {
- keyguardInteractor.isBouncerShowing.collect { logger.v("Bouncer showing", it) }
+ keyguardInteractor.isBouncerShowing.collect {
+ logger.log(TAG, VERBOSE, "Bouncer showing", it)
+ }
}
- scope.launch { keyguardInteractor.isDozing.collect { logger.v("isDozing", it) } }
+ scope.launch {
+ keyguardInteractor.isDozing.collect { logger.log(TAG, VERBOSE, "isDozing", it) }
+ }
- scope.launch { keyguardInteractor.isDreaming.collect { logger.v("isDreaming", it) } }
+ scope.launch {
+ keyguardInteractor.isDreaming.collect { logger.log(TAG, VERBOSE, "isDreaming", it) }
+ }
scope.launch {
interactor.finishedKeyguardTransitionStep.collect {
- logger.i("Finished transition", it)
+ logger.log(TAG, VERBOSE, "Finished transition", it)
}
}
scope.launch {
interactor.canceledKeyguardTransitionStep.collect {
- logger.i("Canceled transition", it)
+ logger.log(TAG, VERBOSE, "Canceled transition", it)
}
}
scope.launch {
- interactor.startedKeyguardTransitionStep.collect { logger.i("Started transition", it) }
+ interactor.startedKeyguardTransitionStep.collect {
+ logger.log(TAG, VERBOSE, "Started transition", it)
+ }
}
scope.launch {
- keyguardInteractor.dozeTransitionModel.collect { logger.i("Doze transition", it) }
+ keyguardInteractor.dozeTransitionModel.collect {
+ logger.log(TAG, VERBOSE, "Doze transition", it)
+ }
}
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardTransitionInteractor.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardTransitionInteractor.kt
index 04024be..ad6dbea 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardTransitionInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardTransitionInteractor.kt
@@ -22,13 +22,17 @@
import com.android.systemui.keyguard.shared.model.AnimationParams
import com.android.systemui.keyguard.shared.model.KeyguardState
import com.android.systemui.keyguard.shared.model.KeyguardState.AOD
+import com.android.systemui.keyguard.shared.model.KeyguardState.BOUNCER
import com.android.systemui.keyguard.shared.model.KeyguardState.DREAMING
+import com.android.systemui.keyguard.shared.model.KeyguardState.GONE
import com.android.systemui.keyguard.shared.model.KeyguardState.LOCKSCREEN
import com.android.systemui.keyguard.shared.model.KeyguardState.OCCLUDED
import com.android.systemui.keyguard.shared.model.TransitionState
import com.android.systemui.keyguard.shared.model.TransitionState.STARTED
import com.android.systemui.keyguard.shared.model.TransitionStep
import javax.inject.Inject
+import kotlin.math.max
+import kotlin.math.min
import kotlin.time.Duration
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.filter
@@ -42,24 +46,39 @@
constructor(
repository: KeyguardTransitionRepository,
) {
+ /** (any)->AOD transition information */
+ val anyStateToAodTransition: Flow<TransitionStep> =
+ repository.transitions.filter { step -> step.to == KeyguardState.AOD }
+
/** AOD->LOCKSCREEN transition information. */
val aodToLockscreenTransition: Flow<TransitionStep> = repository.transition(AOD, LOCKSCREEN)
- /** LOCKSCREEN->AOD transition information. */
- val lockscreenToAodTransition: Flow<TransitionStep> = repository.transition(LOCKSCREEN, AOD)
-
/** DREAMING->LOCKSCREEN transition information. */
val dreamingToLockscreenTransition: Flow<TransitionStep> =
repository.transition(DREAMING, LOCKSCREEN)
+ /** GONE->DREAMING transition information. */
+ val goneToDreamingTransition: Flow<TransitionStep> = repository.transition(GONE, DREAMING)
+
+ /** LOCKSCREEN->AOD transition information. */
+ val lockscreenToAodTransition: Flow<TransitionStep> = repository.transition(LOCKSCREEN, AOD)
+
+ /** LOCKSCREEN->BOUNCER transition information. */
+ val lockscreenToBouncerTransition: Flow<TransitionStep> =
+ repository.transition(LOCKSCREEN, BOUNCER)
+
+ /** LOCKSCREEN->DREAMING transition information. */
+ val lockscreenToDreamingTransition: Flow<TransitionStep> =
+ repository.transition(LOCKSCREEN, DREAMING)
+
+ /** LOCKSCREEN->OCCLUDED transition information. */
+ val lockscreenToOccludedTransition: Flow<TransitionStep> =
+ repository.transition(LOCKSCREEN, OCCLUDED)
+
/** OCCLUDED->LOCKSCREEN transition information. */
val occludedToLockscreenTransition: Flow<TransitionStep> =
repository.transition(OCCLUDED, LOCKSCREEN)
- /** (any)->AOD transition information */
- val anyStateToAodTransition: Flow<TransitionStep> =
- repository.transitions.filter { step -> step.to == KeyguardState.AOD }
-
/**
* AOD<->LOCKSCREEN transition information, mapped to dozeAmount range of AOD (1f) <->
* Lockscreen (0f).
@@ -98,13 +117,23 @@
): Flow<Float> {
val start = (params.startTime / totalDuration).toFloat()
val chunks = (totalDuration / params.duration).toFloat()
+ var isRunning = false
return flow
- // When starting, emit a value of 0f to give animations a chance to set initial state
.map { step ->
+ val value = (step.value - start) * chunks
if (step.transitionState == STARTED) {
- 0f
+ // When starting, make sure to always emit. If a transition is started from the
+ // middle, it is possible this animation is being skipped but we need to inform
+ // the ViewModels of the last update
+ isRunning = true
+ max(0f, min(1f, value))
+ } else if (isRunning && value >= 1f) {
+ // Always send a final value of 1. Because of rounding, [value] may never be
+ // exactly 1.
+ isRunning = false
+ 1f
} else {
- (step.value - start) * chunks
+ value
}
}
.filter { value -> value >= 0f && value <= 1f }
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/shared/model/CameraLaunchSourceModel.kt b/packages/SystemUI/src/com/android/systemui/keyguard/shared/model/CameraLaunchSourceModel.kt
new file mode 100644
index 0000000..19baf77
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/shared/model/CameraLaunchSourceModel.kt
@@ -0,0 +1,28 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+package com.android.systemui.keyguard.shared.model
+
+/** Camera launch sources */
+enum class CameraLaunchSourceModel {
+ /** Device is wiggled */
+ WIGGLE,
+ /** Power button has been double tapped */
+ POWER_DOUBLE_TAP,
+ /** Device has been lifted */
+ LIFT_TRIGGER,
+ /** Quick affordance button has been pressed */
+ QUICK_AFFORDANCE,
+}
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardBottomAreaViewBinder.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardBottomAreaViewBinder.kt
index 0e4058b..9d8bf7d 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardBottomAreaViewBinder.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardBottomAreaViewBinder.kt
@@ -45,7 +45,6 @@
import com.android.systemui.lifecycle.repeatWhenAttached
import com.android.systemui.plugins.FalsingManager
import com.android.systemui.statusbar.VibratorHelper
-import com.android.systemui.util.kotlin.pairwise
import kotlin.math.pow
import kotlin.math.sqrt
import kotlin.time.Duration.Companion.milliseconds
@@ -129,18 +128,6 @@
}
launch {
- viewModel.startButton
- .map { it.isActivated }
- .pairwise()
- .collect { (prev, next) ->
- when {
- !prev && next -> vibratorHelper?.vibrate(Vibrations.Activated)
- prev && !next -> vibratorHelper?.vibrate(Vibrations.Deactivated)
- }
- }
- }
-
- launch {
viewModel.endButton.collect { buttonModel ->
updateButton(
view = endButton,
@@ -153,18 +140,6 @@
}
launch {
- viewModel.endButton
- .map { it.isActivated }
- .pairwise()
- .collect { (prev, next) ->
- when {
- !prev && next -> vibratorHelper?.vibrate(Vibrations.Activated)
- prev && !next -> vibratorHelper?.vibrate(Vibrations.Deactivated)
- }
- }
- }
-
- launch {
viewModel.isOverlayContainerVisible.collect { isVisible ->
overlayContainer.visibility =
if (isVisible) {
@@ -383,6 +358,13 @@
.setDuration(longPressDurationMs)
.withEndAction {
view.setOnClickListener {
+ vibratorHelper?.vibrate(
+ if (viewModel.isActivated) {
+ Vibrations.Activated
+ } else {
+ Vibrations.Deactivated
+ }
+ )
viewModel.onClicked(
KeyguardQuickAffordanceViewModel.OnClickedParameters(
configKey = viewModel.configKey,
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/DreamingToLockscreenTransitionViewModel.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/DreamingToLockscreenTransitionViewModel.kt
index e164f5d..6627865 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/DreamingToLockscreenTransitionViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/DreamingToLockscreenTransitionViewModel.kt
@@ -22,10 +22,14 @@
import com.android.systemui.keyguard.domain.interactor.FromDreamingTransitionInteractor.Companion.TO_LOCKSCREEN_DURATION
import com.android.systemui.keyguard.domain.interactor.KeyguardTransitionInteractor
import com.android.systemui.keyguard.shared.model.AnimationParams
+import com.android.systemui.keyguard.shared.model.TransitionState.CANCELED
+import com.android.systemui.keyguard.shared.model.TransitionState.FINISHED
import javax.inject.Inject
import kotlin.time.Duration.Companion.milliseconds
import kotlinx.coroutines.flow.Flow
+import kotlinx.coroutines.flow.filter
import kotlinx.coroutines.flow.map
+import kotlinx.coroutines.flow.merge
/**
* Breaks down DREAMING->LOCKSCREEN transition into discrete steps for corresponding views to
@@ -49,9 +53,15 @@
/** Lockscreen views y-translation */
fun lockscreenTranslationY(translatePx: Int): Flow<Float> {
- return flowForAnimation(LOCKSCREEN_TRANSLATION_Y).map { value ->
- -translatePx + (EMPHASIZED_DECELERATE.getInterpolation(value) * translatePx)
- }
+ return merge(
+ flowForAnimation(LOCKSCREEN_TRANSLATION_Y).map { value ->
+ -translatePx + (EMPHASIZED_DECELERATE.getInterpolation(value) * translatePx)
+ },
+ // On end, reset the translation to 0
+ interactor.dreamingToLockscreenTransition
+ .filter { it.transitionState == FINISHED || it.transitionState == CANCELED }
+ .map { 0f }
+ )
}
/** Lockscreen views alpha */
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/GoneToDreamingTransitionViewModel.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/GoneToDreamingTransitionViewModel.kt
new file mode 100644
index 0000000..5a47960
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/GoneToDreamingTransitionViewModel.kt
@@ -0,0 +1,69 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.keyguard.ui.viewmodel
+
+import com.android.systemui.animation.Interpolators.EMPHASIZED_ACCELERATE
+import com.android.systemui.dagger.SysUISingleton
+import com.android.systemui.keyguard.domain.interactor.FromGoneTransitionInteractor.Companion.TO_DREAMING_DURATION
+import com.android.systemui.keyguard.domain.interactor.KeyguardTransitionInteractor
+import com.android.systemui.keyguard.shared.model.AnimationParams
+import com.android.systemui.keyguard.shared.model.TransitionState.CANCELED
+import com.android.systemui.keyguard.shared.model.TransitionState.FINISHED
+import javax.inject.Inject
+import kotlin.time.Duration.Companion.milliseconds
+import kotlinx.coroutines.flow.Flow
+import kotlinx.coroutines.flow.filter
+import kotlinx.coroutines.flow.map
+import kotlinx.coroutines.flow.merge
+
+/** Breaks down GONE->DREAMING transition into discrete steps for corresponding views to consume. */
+@SysUISingleton
+class GoneToDreamingTransitionViewModel
+@Inject
+constructor(
+ private val interactor: KeyguardTransitionInteractor,
+) {
+
+ /** Lockscreen views y-translation */
+ fun lockscreenTranslationY(translatePx: Int): Flow<Float> {
+ return merge(
+ flowForAnimation(LOCKSCREEN_TRANSLATION_Y).map { value ->
+ (EMPHASIZED_ACCELERATE.getInterpolation(value) * translatePx)
+ },
+ // On end, reset the translation to 0
+ interactor.goneToDreamingTransition
+ .filter { it.transitionState == FINISHED || it.transitionState == CANCELED }
+ .map { 0f }
+ )
+ }
+
+ /** Lockscreen views alpha */
+ val lockscreenAlpha: Flow<Float> = flowForAnimation(LOCKSCREEN_ALPHA).map { 1f - it }
+
+ private fun flowForAnimation(params: AnimationParams): Flow<Float> {
+ return interactor.transitionStepAnimation(
+ interactor.goneToDreamingTransition,
+ params,
+ totalDuration = TO_DREAMING_DURATION
+ )
+ }
+
+ companion object {
+ val LOCKSCREEN_TRANSLATION_Y = AnimationParams(duration = 500.milliseconds)
+ val LOCKSCREEN_ALPHA = AnimationParams(duration = 250.milliseconds)
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenToDreamingTransitionViewModel.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenToDreamingTransitionViewModel.kt
new file mode 100644
index 0000000..e05adbd
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenToDreamingTransitionViewModel.kt
@@ -0,0 +1,74 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.keyguard.ui.viewmodel
+
+import com.android.systemui.animation.Interpolators.EMPHASIZED_ACCELERATE
+import com.android.systemui.dagger.SysUISingleton
+import com.android.systemui.keyguard.domain.interactor.FromLockscreenTransitionInteractor.Companion.TO_DREAMING_DURATION
+import com.android.systemui.keyguard.domain.interactor.KeyguardTransitionInteractor
+import com.android.systemui.keyguard.shared.model.AnimationParams
+import com.android.systemui.keyguard.shared.model.TransitionState.CANCELED
+import com.android.systemui.keyguard.shared.model.TransitionState.FINISHED
+import javax.inject.Inject
+import kotlin.time.Duration.Companion.milliseconds
+import kotlinx.coroutines.flow.Flow
+import kotlinx.coroutines.flow.filter
+import kotlinx.coroutines.flow.map
+import kotlinx.coroutines.flow.merge
+
+/**
+ * Breaks down LOCKSCREEN->DREAMING transition into discrete steps for corresponding views to
+ * consume.
+ */
+@SysUISingleton
+class LockscreenToDreamingTransitionViewModel
+@Inject
+constructor(
+ private val interactor: KeyguardTransitionInteractor,
+) {
+
+ /** Lockscreen views y-translation */
+ fun lockscreenTranslationY(translatePx: Int): Flow<Float> {
+ return merge(
+ flowForAnimation(LOCKSCREEN_TRANSLATION_Y).map { value ->
+ (EMPHASIZED_ACCELERATE.getInterpolation(value) * translatePx)
+ },
+ // On end, reset the translation to 0
+ interactor.lockscreenToDreamingTransition
+ .filter { it.transitionState == FINISHED || it.transitionState == CANCELED }
+ .map { 0f }
+ )
+ }
+
+ /** Lockscreen views alpha */
+ val lockscreenAlpha: Flow<Float> = flowForAnimation(LOCKSCREEN_ALPHA).map { 1f - it }
+
+ private fun flowForAnimation(params: AnimationParams): Flow<Float> {
+ return interactor.transitionStepAnimation(
+ interactor.lockscreenToDreamingTransition,
+ params,
+ totalDuration = TO_DREAMING_DURATION
+ )
+ }
+
+ companion object {
+ @JvmField val DREAMING_ANIMATION_DURATION_MS = TO_DREAMING_DURATION.inWholeMilliseconds
+
+ val LOCKSCREEN_TRANSLATION_Y = AnimationParams(duration = 500.milliseconds)
+ val LOCKSCREEN_ALPHA = AnimationParams(duration = 250.milliseconds)
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenToOccludedTransitionViewModel.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenToOccludedTransitionViewModel.kt
new file mode 100644
index 0000000..22d292e
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenToOccludedTransitionViewModel.kt
@@ -0,0 +1,71 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.keyguard.ui.viewmodel
+
+import com.android.systemui.animation.Interpolators.EMPHASIZED_ACCELERATE
+import com.android.systemui.dagger.SysUISingleton
+import com.android.systemui.keyguard.domain.interactor.FromLockscreenTransitionInteractor.Companion.TO_OCCLUDED_DURATION
+import com.android.systemui.keyguard.domain.interactor.KeyguardTransitionInteractor
+import com.android.systemui.keyguard.shared.model.AnimationParams
+import com.android.systemui.keyguard.shared.model.TransitionState
+import javax.inject.Inject
+import kotlin.time.Duration.Companion.milliseconds
+import kotlinx.coroutines.flow.Flow
+import kotlinx.coroutines.flow.filter
+import kotlinx.coroutines.flow.map
+import kotlinx.coroutines.flow.merge
+
+/**
+ * Breaks down LOCKSCREEN->OCCLUDED transition into discrete steps for corresponding views to
+ * consume.
+ */
+@SysUISingleton
+class LockscreenToOccludedTransitionViewModel
+@Inject
+constructor(
+ private val interactor: KeyguardTransitionInteractor,
+) {
+
+ /** Lockscreen views y-translation */
+ fun lockscreenTranslationY(translatePx: Int): Flow<Float> {
+ return merge(
+ flowForAnimation(LOCKSCREEN_TRANSLATION_Y).map { value ->
+ (EMPHASIZED_ACCELERATE.getInterpolation(value) * translatePx)
+ },
+ // On end, reset the translation to 0
+ interactor.lockscreenToOccludedTransition
+ .filter { step -> step.transitionState == TransitionState.FINISHED }
+ .map { 0f }
+ )
+ }
+
+ /** Lockscreen views alpha */
+ val lockscreenAlpha: Flow<Float> = flowForAnimation(LOCKSCREEN_ALPHA).map { 1f - it }
+
+ private fun flowForAnimation(params: AnimationParams): Flow<Float> {
+ return interactor.transitionStepAnimation(
+ interactor.lockscreenToOccludedTransition,
+ params,
+ totalDuration = TO_OCCLUDED_DURATION
+ )
+ }
+
+ companion object {
+ val LOCKSCREEN_TRANSLATION_Y = AnimationParams(duration = TO_OCCLUDED_DURATION)
+ val LOCKSCREEN_ALPHA = AnimationParams(duration = 250.milliseconds)
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/log/dagger/KeyguardClockLog.kt b/packages/SystemUI/src/com/android/systemui/log/dagger/KeyguardClockLog.kt
index 0645236..9f563fe4 100644
--- a/packages/SystemUI/src/com/android/systemui/log/dagger/KeyguardClockLog.kt
+++ b/packages/SystemUI/src/com/android/systemui/log/dagger/KeyguardClockLog.kt
@@ -23,3 +23,15 @@
@MustBeDocumented
@Retention(AnnotationRetention.RUNTIME)
annotation class KeyguardClockLog
+
+/** A [com.android.systemui.plugins.log.LogBuffer] for small keyguard clock logs. */
+@Qualifier
+@MustBeDocumented
+@Retention(AnnotationRetention.RUNTIME)
+annotation class KeyguardSmallClockLog
+
+/** A [com.android.systemui.plugins.log.LogBuffer] for large keyguard clock logs. */
+@Qualifier
+@MustBeDocumented
+@Retention(AnnotationRetention.RUNTIME)
+annotation class KeyguardLargeClockLog
diff --git a/packages/SystemUI/src/com/android/systemui/log/dagger/LogModule.java b/packages/SystemUI/src/com/android/systemui/log/dagger/LogModule.java
index 711bca0..afbd8ed 100644
--- a/packages/SystemUI/src/com/android/systemui/log/dagger/LogModule.java
+++ b/packages/SystemUI/src/com/android/systemui/log/dagger/LogModule.java
@@ -335,13 +335,33 @@
}
/**
- * Provides a {@link LogBuffer} for keyguard clock logs.
+ * Provides a {@link LogBuffer} for general keyguard clock logs.
*/
@Provides
@SysUISingleton
@KeyguardClockLog
public static LogBuffer provideKeyguardClockLog(LogBufferFactory factory) {
- return factory.create("KeyguardClockLog", 500);
+ return factory.create("KeyguardClockLog", 100);
+ }
+
+ /**
+ * Provides a {@link LogBuffer} for keyguard small clock logs.
+ */
+ @Provides
+ @SysUISingleton
+ @KeyguardSmallClockLog
+ public static LogBuffer provideKeyguardSmallClockLog(LogBufferFactory factory) {
+ return factory.create("KeyguardSmallClockLog", 100);
+ }
+
+ /**
+ * Provides a {@link LogBuffer} for keyguard large clock logs.
+ */
+ @Provides
+ @SysUISingleton
+ @KeyguardLargeClockLog
+ public static LogBuffer provideKeyguardLargeClockLog(LogBufferFactory factory) {
+ return factory.create("KeyguardLargeClockLog", 100);
}
/**
diff --git a/packages/SystemUI/src/com/android/systemui/log/table/TableLogBufferFactory.kt b/packages/SystemUI/src/com/android/systemui/log/table/TableLogBufferFactory.kt
index 7a90a74..7ccc43c 100644
--- a/packages/SystemUI/src/com/android/systemui/log/table/TableLogBufferFactory.kt
+++ b/packages/SystemUI/src/com/android/systemui/log/table/TableLogBufferFactory.kt
@@ -29,6 +29,18 @@
private val dumpManager: DumpManager,
private val systemClock: SystemClock,
) {
+ private val existingBuffers = mutableMapOf<String, TableLogBuffer>()
+
+ /**
+ * Creates a new [TableLogBuffer]. This method should only be called from static contexts, where
+ * it is guaranteed only to be created one time. See [getOrCreate] for a cache-aware method of
+ * obtaining a buffer.
+ *
+ * @param name a unique table name
+ * @param maxSize the buffer max size. See [adjustMaxSize]
+ *
+ * @return a new [TableLogBuffer] registered with [DumpManager]
+ */
fun create(
name: String,
maxSize: Int,
@@ -37,4 +49,23 @@
dumpManager.registerNormalDumpable(name, tableBuffer)
return tableBuffer
}
+
+ /**
+ * Log buffers are retained indefinitely by [DumpManager], so that they can be represented in
+ * bugreports. Because of this, many of them are created statically in the Dagger graph.
+ *
+ * In the case where you have to create a logbuffer with a name only known at runtime, this
+ * method can be used to lazily create a table log buffer which is then cached for reuse.
+ *
+ * @return a [TableLogBuffer] suitable for reuse
+ */
+ fun getOrCreate(
+ name: String,
+ maxSize: Int,
+ ): TableLogBuffer =
+ existingBuffers.getOrElse(name) {
+ val buffer = create(name, maxSize)
+ existingBuffers[name] = buffer
+ buffer
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/media/controls/models/player/MediaData.kt b/packages/SystemUI/src/com/android/systemui/media/controls/models/player/MediaData.kt
index f006442..be18cbe 100644
--- a/packages/SystemUI/src/com/android/systemui/media/controls/models/player/MediaData.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/controls/models/player/MediaData.kt
@@ -88,7 +88,10 @@
val instanceId: InstanceId,
/** The UID of the app, used for logging */
- val appUid: Int
+ val appUid: Int,
+
+ /** Whether explicit indicator exists */
+ val isExplicit: Boolean = false,
) {
companion object {
/** Media is playing on the local device */
diff --git a/packages/SystemUI/src/com/android/systemui/media/controls/models/player/MediaViewHolder.kt b/packages/SystemUI/src/com/android/systemui/media/controls/models/player/MediaViewHolder.kt
index a8f39fa9a..1c8bfd1 100644
--- a/packages/SystemUI/src/com/android/systemui/media/controls/models/player/MediaViewHolder.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/controls/models/player/MediaViewHolder.kt
@@ -24,6 +24,7 @@
import android.widget.SeekBar
import android.widget.TextView
import androidx.constraintlayout.widget.Barrier
+import com.android.internal.widget.CachingIconView
import com.android.systemui.R
import com.android.systemui.media.controls.models.GutsViewHolder
import com.android.systemui.surfaceeffects.ripple.MultiRippleView
@@ -44,6 +45,7 @@
val appIcon = itemView.requireViewById<ImageView>(R.id.icon)
val titleText = itemView.requireViewById<TextView>(R.id.header_title)
val artistText = itemView.requireViewById<TextView>(R.id.header_artist)
+ val explicitIndicator = itemView.requireViewById<CachingIconView>(R.id.media_explicit_indicator)
// Output switcher
val seamless = itemView.requireViewById<ViewGroup>(R.id.media_seamless)
@@ -123,6 +125,7 @@
R.id.app_name,
R.id.header_title,
R.id.header_artist,
+ R.id.media_explicit_indicator,
R.id.media_seamless,
R.id.media_progress_bar,
R.id.actionPlayPause,
diff --git a/packages/SystemUI/src/com/android/systemui/media/controls/pipeline/MediaDataManager.kt b/packages/SystemUI/src/com/android/systemui/media/controls/pipeline/MediaDataManager.kt
index 2dd339d..9f28d46 100644
--- a/packages/SystemUI/src/com/android/systemui/media/controls/pipeline/MediaDataManager.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/controls/pipeline/MediaDataManager.kt
@@ -16,6 +16,7 @@
package com.android.systemui.media.controls.pipeline
+import android.app.BroadcastOptions
import android.app.Notification
import android.app.Notification.EXTRA_SUBSTITUTE_APP_NAME
import android.app.PendingIntent
@@ -45,6 +46,7 @@
import android.os.UserHandle
import android.provider.Settings
import android.service.notification.StatusBarNotification
+import android.support.v4.media.MediaMetadataCompat
import android.text.TextUtils
import android.util.Log
import androidx.media.utils.MediaConstants
@@ -660,6 +662,10 @@
val currentEntry = mediaEntries.get(packageName)
val instanceId = currentEntry?.instanceId ?: logger.getNewInstanceId()
val appUid = currentEntry?.appUid ?: Process.INVALID_UID
+ val isExplicit =
+ desc.extras?.getLong(MediaConstants.METADATA_KEY_IS_EXPLICIT) ==
+ MediaConstants.METADATA_VALUE_ATTRIBUTE_PRESENT &&
+ mediaFlags.isExplicitIndicatorEnabled()
val mediaAction = getResumeMediaAction(resumeAction)
val lastActive = systemClock.elapsedRealtime()
@@ -689,7 +695,8 @@
hasCheckedForResume = true,
lastActive = lastActive,
instanceId = instanceId,
- appUid = appUid
+ appUid = appUid,
+ isExplicit = isExplicit,
)
)
}
@@ -750,6 +757,15 @@
song = HybridGroupManager.resolveTitle(notif)
}
+ // Explicit Indicator
+ var isExplicit = false
+ if (mediaFlags.isExplicitIndicatorEnabled()) {
+ val mediaMetadataCompat = MediaMetadataCompat.fromMediaMetadata(metadata)
+ isExplicit =
+ mediaMetadataCompat?.getLong(MediaConstants.METADATA_KEY_IS_EXPLICIT) ==
+ MediaConstants.METADATA_VALUE_ATTRIBUTE_PRESENT
+ }
+
// Artist name
var artist: CharSequence? = metadata?.getString(MediaMetadata.METADATA_KEY_ARTIST)
if (artist == null) {
@@ -851,7 +867,8 @@
isClearable = sbn.isClearable(),
lastActive = lastActive,
instanceId = instanceId,
- appUid = appUid
+ appUid = appUid,
+ isExplicit = isExplicit,
)
)
}
@@ -1165,7 +1182,9 @@
private fun sendPendingIntent(intent: PendingIntent): Boolean {
return try {
- intent.send()
+ val options = BroadcastOptions.makeBasic()
+ options.setInteractive(true)
+ intent.send(options.toBundle())
true
} catch (e: PendingIntent.CanceledException) {
Log.d(TAG, "Intent canceled", e)
diff --git a/packages/SystemUI/src/com/android/systemui/media/controls/ui/KeyguardMediaController.kt b/packages/SystemUI/src/com/android/systemui/media/controls/ui/KeyguardMediaController.kt
index 899148b..8f1c904 100644
--- a/packages/SystemUI/src/com/android/systemui/media/controls/ui/KeyguardMediaController.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/controls/ui/KeyguardMediaController.kt
@@ -130,7 +130,12 @@
private var splitShadeContainer: ViewGroup? = null
/** Track the media player setting status on lock screen. */
- private var allowMediaPlayerOnLockScreen: Boolean = true
+ private var allowMediaPlayerOnLockScreen: Boolean =
+ secureSettings.getBoolForUser(
+ Settings.Secure.MEDIA_CONTROLS_LOCK_SCREEN,
+ true,
+ UserHandle.USER_CURRENT
+ )
private val lockScreenMediaPlayerUri =
secureSettings.getUriFor(Settings.Secure.MEDIA_CONTROLS_LOCK_SCREEN)
diff --git a/packages/SystemUI/src/com/android/systemui/media/controls/ui/MediaCarouselController.kt b/packages/SystemUI/src/com/android/systemui/media/controls/ui/MediaCarouselController.kt
index d5558b2..e7f7647 100644
--- a/packages/SystemUI/src/com/android/systemui/media/controls/ui/MediaCarouselController.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/controls/ui/MediaCarouselController.kt
@@ -94,7 +94,7 @@
private var currentCarouselWidth: Int = 0
/** The current height of the carousel */
- private var currentCarouselHeight: Int = 0
+ @VisibleForTesting var currentCarouselHeight: Int = 0
/** Are we currently showing only active players */
private var currentlyShowingOnlyActive: Boolean = false
@@ -128,14 +128,14 @@
/** The measured height of the carousel */
private var carouselMeasureHeight: Int = 0
private var desiredHostState: MediaHostState? = null
- private val mediaCarousel: MediaScrollView
+ @VisibleForTesting var mediaCarousel: MediaScrollView
val mediaCarouselScrollHandler: MediaCarouselScrollHandler
val mediaFrame: ViewGroup
@VisibleForTesting
lateinit var settingsButton: View
private set
private val mediaContent: ViewGroup
- @VisibleForTesting val pageIndicator: PageIndicator
+ @VisibleForTesting var pageIndicator: PageIndicator
private val visualStabilityCallback: OnReorderingAllowedListener
private var needsReordering: Boolean = false
private var keysNeedRemoval = mutableSetOf<String>()
@@ -160,25 +160,20 @@
}
companion object {
- const val ANIMATION_BASE_DURATION = 2200f
- const val DURATION = 167f
- const val DETAILS_DELAY = 1067f
- const val CONTROLS_DELAY = 1400f
- const val PAGINATION_DELAY = 1900f
- const val MEDIATITLES_DELAY = 1000f
- const val MEDIACONTAINERS_DELAY = 967f
val TRANSFORM_BEZIER = PathInterpolator(0.68F, 0F, 0F, 1F)
- val REVERSE_BEZIER = PathInterpolator(0F, 0.68F, 1F, 0F)
- fun calculateAlpha(squishinessFraction: Float, delay: Float, duration: Float): Float {
- val transformStartFraction = delay / ANIMATION_BASE_DURATION
- val transformDurationFraction = duration / ANIMATION_BASE_DURATION
- val squishinessToTime = REVERSE_BEZIER.getInterpolation(squishinessFraction)
- return MathUtils.constrain(
- (squishinessToTime - transformStartFraction) / transformDurationFraction,
- 0F,
- 1F
- )
+ fun calculateAlpha(
+ squishinessFraction: Float,
+ startPosition: Float,
+ endPosition: Float
+ ): Float {
+ val transformFraction =
+ MathUtils.constrain(
+ (squishinessFraction - startPosition) / (endPosition - startPosition),
+ 0F,
+ 1F
+ )
+ return TRANSFORM_BEZIER.getInterpolation(transformFraction)
}
}
@@ -813,7 +808,12 @@
val squishFraction = hostStates[currentEndLocation]?.squishFraction ?: 1.0F
val endAlpha =
(if (endIsVisible) 1.0f else 0.0f) *
- calculateAlpha(squishFraction, PAGINATION_DELAY, DURATION)
+ calculateAlpha(
+ squishFraction,
+ (pageIndicator.translationY + pageIndicator.height) /
+ mediaCarousel.measuredHeight,
+ 1F
+ )
var alpha = 1.0f
if (!endIsVisible || !startIsVisible) {
var progress = currentTransitionProgress
@@ -839,7 +839,8 @@
pageIndicator.translationX = translationX + mediaCarouselScrollHandler.contentTranslation
val layoutParams = pageIndicator.layoutParams as ViewGroup.MarginLayoutParams
pageIndicator.translationY =
- (currentCarouselHeight - pageIndicator.height - layoutParams.bottomMargin).toFloat()
+ (mediaCarousel.measuredHeight - pageIndicator.height - layoutParams.bottomMargin)
+ .toFloat()
}
/** Update the dimension of this carousel. */
diff --git a/packages/SystemUI/src/com/android/systemui/media/controls/ui/MediaControlPanel.java b/packages/SystemUI/src/com/android/systemui/media/controls/ui/MediaControlPanel.java
index 15c3443..9d1ebb6 100644
--- a/packages/SystemUI/src/com/android/systemui/media/controls/ui/MediaControlPanel.java
+++ b/packages/SystemUI/src/com/android/systemui/media/controls/ui/MediaControlPanel.java
@@ -23,6 +23,7 @@
import android.animation.Animator;
import android.animation.AnimatorInflater;
import android.animation.AnimatorSet;
+import android.app.BroadcastOptions;
import android.app.PendingIntent;
import android.app.WallpaperColors;
import android.app.smartspace.SmartspaceAction;
@@ -50,7 +51,6 @@
import android.os.Trace;
import android.text.TextUtils;
import android.util.Log;
-import android.util.Pair;
import android.view.Gravity;
import android.view.View;
import android.view.ViewGroup;
@@ -68,6 +68,7 @@
import com.android.internal.graphics.ColorUtils;
import com.android.internal.jank.InteractionJankMonitor;
import com.android.internal.logging.InstanceId;
+import com.android.internal.widget.CachingIconView;
import com.android.settingslib.widget.AdaptiveIcon;
import com.android.systemui.ActivityIntentHelper;
import com.android.systemui.R;
@@ -113,6 +114,8 @@
import com.android.systemui.util.animation.TransitionLayout;
import com.android.systemui.util.time.SystemClock;
+import dagger.Lazy;
+
import java.net.URISyntaxException;
import java.util.ArrayList;
import java.util.List;
@@ -120,7 +123,7 @@
import javax.inject.Inject;
-import dagger.Lazy;
+import kotlin.Triple;
import kotlin.Unit;
/**
@@ -398,10 +401,11 @@
TextView titleText = mMediaViewHolder.getTitleText();
TextView artistText = mMediaViewHolder.getArtistText();
+ CachingIconView explicitIndicator = mMediaViewHolder.getExplicitIndicator();
AnimatorSet enter = loadAnimator(R.anim.media_metadata_enter,
- Interpolators.EMPHASIZED_DECELERATE, titleText, artistText);
+ Interpolators.EMPHASIZED_DECELERATE, titleText, artistText, explicitIndicator);
AnimatorSet exit = loadAnimator(R.anim.media_metadata_exit,
- Interpolators.EMPHASIZED_ACCELERATE, titleText, artistText);
+ Interpolators.EMPHASIZED_ACCELERATE, titleText, artistText, explicitIndicator);
MultiRippleView multiRippleView = vh.getMultiRippleView();
mMultiRippleController = new MultiRippleController(multiRippleView);
@@ -625,7 +629,9 @@
device.getIntent().getIntent(), true);
} else {
try {
- device.getIntent().send();
+ BroadcastOptions options = BroadcastOptions.makeBasic();
+ options.setInteractive(true);
+ device.getIntent().send(options.toBundle());
} catch (PendingIntent.CanceledException e) {
Log.e(TAG, "Device pending intent was canceled");
}
@@ -664,11 +670,15 @@
private boolean bindSongMetadata(MediaData data) {
TextView titleText = mMediaViewHolder.getTitleText();
TextView artistText = mMediaViewHolder.getArtistText();
+ ConstraintSet expandedSet = mMediaViewController.getExpandedLayout();
+ ConstraintSet collapsedSet = mMediaViewController.getCollapsedLayout();
return mMetadataAnimationHandler.setNext(
- Pair.create(data.getSong(), data.getArtist()),
+ new Triple(data.getSong(), data.getArtist(), data.isExplicit()),
() -> {
titleText.setText(data.getSong());
artistText.setText(data.getArtist());
+ setVisibleAndAlpha(expandedSet, R.id.media_explicit_indicator, data.isExplicit());
+ setVisibleAndAlpha(collapsedSet, R.id.media_explicit_indicator, data.isExplicit());
// refreshState is required here to resize the text views (and prevent ellipsis)
mMediaViewController.refreshState();
diff --git a/packages/SystemUI/src/com/android/systemui/media/controls/ui/MediaHierarchyManager.kt b/packages/SystemUI/src/com/android/systemui/media/controls/ui/MediaHierarchyManager.kt
index f7a9bc7..66f12d6 100644
--- a/packages/SystemUI/src/com/android/systemui/media/controls/ui/MediaHierarchyManager.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/controls/ui/MediaHierarchyManager.kt
@@ -41,6 +41,7 @@
import com.android.systemui.dagger.qualifiers.Main
import com.android.systemui.dreams.DreamOverlayStateController
import com.android.systemui.keyguard.WakefulnessLifecycle
+import com.android.systemui.media.controls.pipeline.MediaDataManager
import com.android.systemui.media.dream.MediaDreamComplication
import com.android.systemui.plugins.statusbar.StatusBarStateController
import com.android.systemui.shade.ShadeStateEvents
@@ -93,6 +94,7 @@
private val keyguardStateController: KeyguardStateController,
private val bypassController: KeyguardBypassController,
private val mediaCarouselController: MediaCarouselController,
+ private val mediaManager: MediaDataManager,
private val keyguardViewController: KeyguardViewController,
private val dreamOverlayStateController: DreamOverlayStateController,
configurationController: ConfigurationController,
@@ -224,9 +226,9 @@
private var inSplitShade = false
- /** Is there any active media in the carousel? */
- private var hasActiveMedia: Boolean = false
- get() = mediaHosts.get(LOCATION_QQS)?.visible == true
+ /** Is there any active media or recommendation in the carousel? */
+ private var hasActiveMediaOrRecommendation: Boolean = false
+ get() = mediaManager.hasActiveMediaOrRecommendation()
/** Are we currently waiting on an animation to start? */
private var animationPending: Boolean = false
@@ -582,12 +584,8 @@
val viewHost = createUniqueObjectHost()
mediaObject.hostView = viewHost
mediaObject.addVisibilityChangeListener {
- // If QQS changes visibility, we need to force an update to ensure the transition
- // goes into the correct state
- val stateUpdate = mediaObject.location == LOCATION_QQS
-
// Never animate because of a visibility change, only state changes should do that
- updateDesiredLocation(forceNoAnimation = true, forceStateUpdate = stateUpdate)
+ updateDesiredLocation(forceNoAnimation = true)
}
mediaHosts[mediaObject.location] = mediaObject
if (mediaObject.location == desiredLocation) {
@@ -908,7 +906,7 @@
fun isCurrentlyInGuidedTransformation(): Boolean {
return hasValidStartAndEndLocations() &&
getTransformationProgress() >= 0 &&
- areGuidedTransitionHostsVisible()
+ (areGuidedTransitionHostsVisible() || !hasActiveMediaOrRecommendation)
}
private fun hasValidStartAndEndLocations(): Boolean {
@@ -965,7 +963,7 @@
private fun getQSTransformationProgress(): Float {
val currentHost = getHost(desiredLocation)
val previousHost = getHost(previousLocation)
- if (hasActiveMedia && (currentHost?.location == LOCATION_QS && !inSplitShade)) {
+ if (currentHost?.location == LOCATION_QS && !inSplitShade) {
if (previousHost?.location == LOCATION_QQS) {
if (previousHost.visible || statusbarState != StatusBarState.KEYGUARD) {
return qsExpansion
@@ -1028,7 +1026,8 @@
private fun updateHostAttachment() =
traceSection("MediaHierarchyManager#updateHostAttachment") {
var newLocation = resolveLocationForFading()
- var canUseOverlay = !isCurrentlyFading()
+ // Don't use the overlay when fading or when we don't have active media
+ var canUseOverlay = !isCurrentlyFading() && hasActiveMediaOrRecommendation
if (isCrossFadeAnimatorRunning) {
if (
getHost(newLocation)?.visible == true &&
@@ -1122,7 +1121,6 @@
dreamOverlayActive && dreamMediaComplicationActive -> LOCATION_DREAM_OVERLAY
(qsExpansion > 0.0f || inSplitShade) && !onLockscreen -> LOCATION_QS
qsExpansion > 0.4f && onLockscreen -> LOCATION_QS
- !hasActiveMedia -> LOCATION_QS
onLockscreen && isSplitShadeExpanding() -> LOCATION_QS
onLockscreen && isTransformingToFullShadeAndInQQS() -> LOCATION_QQS
onLockscreen && allowMediaPlayerOnLockScreen -> LOCATION_LOCKSCREEN
diff --git a/packages/SystemUI/src/com/android/systemui/media/controls/ui/MediaViewController.kt b/packages/SystemUI/src/com/android/systemui/media/controls/ui/MediaViewController.kt
index 3224213..2ec7be6 100644
--- a/packages/SystemUI/src/com/android/systemui/media/controls/ui/MediaViewController.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/controls/ui/MediaViewController.kt
@@ -24,11 +24,6 @@
import com.android.systemui.media.controls.models.GutsViewHolder
import com.android.systemui.media.controls.models.player.MediaViewHolder
import com.android.systemui.media.controls.models.recommendation.RecommendationViewHolder
-import com.android.systemui.media.controls.ui.MediaCarouselController.Companion.CONTROLS_DELAY
-import com.android.systemui.media.controls.ui.MediaCarouselController.Companion.DETAILS_DELAY
-import com.android.systemui.media.controls.ui.MediaCarouselController.Companion.DURATION
-import com.android.systemui.media.controls.ui.MediaCarouselController.Companion.MEDIACONTAINERS_DELAY
-import com.android.systemui.media.controls.ui.MediaCarouselController.Companion.MEDIATITLES_DELAY
import com.android.systemui.media.controls.ui.MediaCarouselController.Companion.calculateAlpha
import com.android.systemui.statusbar.policy.ConfigurationController
import com.android.systemui.util.animation.MeasurementOutput
@@ -36,6 +31,8 @@
import com.android.systemui.util.animation.TransitionLayoutController
import com.android.systemui.util.animation.TransitionViewState
import com.android.systemui.util.traceSection
+import java.lang.Float.max
+import java.lang.Float.min
import javax.inject.Inject
/**
@@ -80,6 +77,7 @@
setOf(
R.id.header_title,
R.id.header_artist,
+ R.id.media_explicit_indicator,
R.id.actionPlayPause,
)
@@ -304,42 +302,109 @@
val squishedViewState = viewState.copy()
val squishedHeight = (squishedViewState.measureHeight * squishFraction).toInt()
squishedViewState.height = squishedHeight
- controlIds.forEach { id ->
- squishedViewState.widgetStates.get(id)?.let { state ->
- state.alpha = calculateAlpha(squishFraction, CONTROLS_DELAY, DURATION)
- }
- }
-
- detailIds.forEach { id ->
- squishedViewState.widgetStates.get(id)?.let { state ->
- state.alpha = calculateAlpha(squishFraction, DETAILS_DELAY, DURATION)
- }
- }
-
// We are not overriding the squishedViewStates height but only the children to avoid
// them remeasuring the whole view. Instead it just remains as the original size
backgroundIds.forEach { id ->
- squishedViewState.widgetStates.get(id)?.let { state ->
- state.height = squishedHeight
- }
+ squishedViewState.widgetStates.get(id)?.let { state -> state.height = squishedHeight }
}
- RecommendationViewHolder.mediaContainersIds.forEach { id ->
- squishedViewState.widgetStates.get(id)?.let { state ->
- state.alpha = calculateAlpha(squishFraction, MEDIACONTAINERS_DELAY, DURATION)
- }
- }
-
- RecommendationViewHolder.mediaTitlesAndSubtitlesIds.forEach { id ->
- squishedViewState.widgetStates.get(id)?.let { state ->
- state.alpha = calculateAlpha(squishFraction, MEDIATITLES_DELAY, DURATION)
- }
- }
-
+ // media player
+ val controlsTop =
+ calculateWidgetGroupAlphaForSquishiness(
+ controlIds,
+ squishedViewState.measureHeight.toFloat(),
+ squishedViewState,
+ squishFraction
+ )
+ calculateWidgetGroupAlphaForSquishiness(
+ detailIds,
+ controlsTop,
+ squishedViewState,
+ squishFraction
+ )
+ // recommendation card
+ val titlesTop =
+ calculateWidgetGroupAlphaForSquishiness(
+ RecommendationViewHolder.mediaTitlesAndSubtitlesIds,
+ squishedViewState.measureHeight.toFloat(),
+ squishedViewState,
+ squishFraction
+ )
+ calculateWidgetGroupAlphaForSquishiness(
+ RecommendationViewHolder.mediaContainersIds,
+ titlesTop,
+ squishedViewState,
+ squishFraction
+ )
return squishedViewState
}
/**
+ * This function is to make each widget in UMO disappear before being clipped by squished UMO
+ *
+ * The general rule is that widgets in UMO has been divided into several groups, and widgets in
+ * one group have the same alpha during squishing It will change from alpha 0.0 when the visible
+ * bottom of UMO reach the bottom of this group It will change to alpha 1.0 when the visible
+ * bottom of UMO reach the top of the group below e.g.Album title, artist title and play-pause
+ * button will change alpha together.
+ * ```
+ * And their alpha becomes 1.0 when the visible bottom of UMO reach the top of controls,
+ * including progress bar, next button, previous button
+ * ```
+ * widgetGroupIds: a group of widgets have same state during UMO is squished,
+ * ```
+ * e.g. Album title, artist title and play-pause button
+ * ```
+ * groupEndPosition: the height of UMO, when the height reaches this value,
+ * ```
+ * widgets in this group should have 1.0 as alpha
+ * e.g., the group of album title, artist title and play-pause button will become fully
+ * visible when the height of UMO reaches the top of controls group
+ * (progress bar, previous button and next button)
+ * ```
+ * squishedViewState: hold the widgetState of each widget, which will be modified
+ * squishFraction: the squishFraction of UMO
+ */
+ private fun calculateWidgetGroupAlphaForSquishiness(
+ widgetGroupIds: Set<Int>,
+ groupEndPosition: Float,
+ squishedViewState: TransitionViewState,
+ squishFraction: Float
+ ): Float {
+ val nonsquishedHeight = squishedViewState.measureHeight
+ var groupTop = squishedViewState.measureHeight.toFloat()
+ var groupBottom = 0F
+ widgetGroupIds.forEach { id ->
+ squishedViewState.widgetStates.get(id)?.let { state ->
+ groupTop = min(groupTop, state.y)
+ groupBottom = max(groupBottom, state.y + state.height)
+ }
+ }
+ // startPosition means to the height of squished UMO where the widget alpha should start
+ // changing from 0.0
+ // generally, it equals to the bottom of widgets, so that we can meet the requirement that
+ // widget should not go beyond the bounds of background
+ // endPosition means to the height of squished UMO where the widget alpha should finish
+ // changing alpha to 1.0
+ var startPosition = groupBottom
+ val endPosition = groupEndPosition
+ if (startPosition == endPosition) {
+ startPosition = (endPosition - 0.2 * (groupBottom - groupTop)).toFloat()
+ }
+ widgetGroupIds.forEach { id ->
+ squishedViewState.widgetStates.get(id)?.let { state ->
+ state.alpha =
+ calculateAlpha(
+ squishFraction,
+ startPosition / nonsquishedHeight,
+ endPosition / nonsquishedHeight
+ )
+ }
+ }
+ return groupTop // used for the widget group above this group
+ }
+
+ /**
* Obtain a new viewState for a given media state. This usually returns a cached state, but if
* it's not available, it will recreate one by measuring, which may be expensive.
*/
@@ -544,11 +609,13 @@
overrideSize?.let {
// To be safe we're using a maximum here. The override size should always be set
// properly though.
- if (result.measureHeight != it.measuredHeight
- || result.measureWidth != it.measuredWidth) {
+ if (
+ result.measureHeight != it.measuredHeight || result.measureWidth != it.measuredWidth
+ ) {
result.measureHeight = Math.max(it.measuredHeight, result.measureHeight)
result.measureWidth = Math.max(it.measuredWidth, result.measureWidth)
- // The measureHeight and the shown height should both be set to the overridden height
+ // The measureHeight and the shown height should both be set to the overridden
+ // height
result.height = result.measureHeight
result.width = result.measureWidth
// Make sure all background views are also resized such that their size is correct
diff --git a/packages/SystemUI/src/com/android/systemui/media/controls/util/MediaFlags.kt b/packages/SystemUI/src/com/android/systemui/media/controls/util/MediaFlags.kt
index 8d4931a..5bc35ca 100644
--- a/packages/SystemUI/src/com/android/systemui/media/controls/util/MediaFlags.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/controls/util/MediaFlags.kt
@@ -42,4 +42,7 @@
* [android.app.StatusBarManager.registerNearbyMediaDevicesProvider] for more information.
*/
fun areNearbyMediaDevicesEnabled() = featureFlags.isEnabled(Flags.MEDIA_NEARBY_DEVICES)
+
+ /** Check whether we show explicit indicator on UMO */
+ fun isExplicitIndicatorEnabled() = featureFlags.isEnabled(Flags.MEDIA_EXPLICIT_INDICATOR)
}
diff --git a/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputController.java b/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputController.java
index 316b642..7bc0c0c 100644
--- a/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputController.java
+++ b/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputController.java
@@ -637,44 +637,21 @@
}
// For the first time building list, to make sure the top device is the connected
// device.
+ boolean needToHandleMutingExpectedDevice =
+ hasMutingExpectedDevice() && !isCurrentConnectedDeviceRemote();
+ final MediaDevice connectedMediaDevice =
+ needToHandleMutingExpectedDevice ? null
+ : getCurrentConnectedMediaDevice();
if (mMediaItemList.isEmpty()) {
- boolean needToHandleMutingExpectedDevice =
- hasMutingExpectedDevice() && !isCurrentConnectedDeviceRemote();
- final MediaDevice connectedMediaDevice =
- needToHandleMutingExpectedDevice ? null
- : getCurrentConnectedMediaDevice();
if (connectedMediaDevice == null) {
if (DEBUG) {
Log.d(TAG, "No connected media device or muting expected device exist.");
}
- if (needToHandleMutingExpectedDevice) {
- for (MediaDevice device : devices) {
- if (device.isMutingExpectedDevice()) {
- mMediaItemList.add(0, new MediaItem(device));
- mMediaItemList.add(1, new MediaItem(mContext.getString(
- R.string.media_output_group_title_speakers_and_displays),
- MediaItem.MediaItemType.TYPE_GROUP_DIVIDER));
- } else {
- mMediaItemList.add(new MediaItem(device));
- }
- }
- mMediaItemList.add(new MediaItem());
- } else {
- mMediaItemList.addAll(
- devices.stream().map(MediaItem::new).collect(Collectors.toList()));
- categorizeMediaItems(null);
- }
+ categorizeMediaItems(null, devices, needToHandleMutingExpectedDevice);
return;
}
// selected device exist
- for (MediaDevice device : devices) {
- if (TextUtils.equals(device.getId(), connectedMediaDevice.getId())) {
- mMediaItemList.add(0, new MediaItem(device));
- } else {
- mMediaItemList.add(new MediaItem(device));
- }
- }
- categorizeMediaItems(connectedMediaDevice);
+ categorizeMediaItems(connectedMediaDevice, devices, false);
return;
}
// To keep the same list order
@@ -708,31 +685,46 @@
}
}
- private void categorizeMediaItems(MediaDevice connectedMediaDevice) {
+ private void categorizeMediaItems(MediaDevice connectedMediaDevice, List<MediaDevice> devices,
+ boolean needToHandleMutingExpectedDevice) {
synchronized (mMediaDevicesLock) {
Set<String> selectedDevicesIds = getSelectedMediaDevice().stream().map(
MediaDevice::getId).collect(Collectors.toSet());
if (connectedMediaDevice != null) {
selectedDevicesIds.add(connectedMediaDevice.getId());
}
- int latestSelected = 1;
- for (MediaItem item : mMediaItemList) {
- if (item.getMediaDevice().isPresent()) {
- MediaDevice device = item.getMediaDevice().get();
- if (selectedDevicesIds.contains(device.getId())) {
- latestSelected = mMediaItemList.indexOf(item) + 1;
- } else {
- mMediaItemList.add(latestSelected, new MediaItem(mContext.getString(
- R.string.media_output_group_title_speakers_and_displays),
- MediaItem.MediaItemType.TYPE_GROUP_DIVIDER));
- break;
+ boolean suggestedDeviceAdded = false;
+ boolean displayGroupAdded = false;
+ for (MediaDevice device : devices) {
+ if (needToHandleMutingExpectedDevice && device.isMutingExpectedDevice()) {
+ mMediaItemList.add(0, new MediaItem(device));
+ } else if (!needToHandleMutingExpectedDevice && selectedDevicesIds.contains(
+ device.getId())) {
+ mMediaItemList.add(0, new MediaItem(device));
+ } else {
+ if (device.isSuggestedDevice() && !suggestedDeviceAdded) {
+ attachGroupDivider(mContext.getString(
+ R.string.media_output_group_title_suggested_device));
+ suggestedDeviceAdded = true;
+ } else if (!device.isSuggestedDevice() && !displayGroupAdded) {
+ attachGroupDivider(mContext.getString(
+ R.string.media_output_group_title_speakers_and_displays));
+ displayGroupAdded = true;
}
+ mMediaItemList.add(new MediaItem(device));
}
}
mMediaItemList.add(new MediaItem());
}
}
+ private void attachGroupDivider(String title) {
+ synchronized (mMediaDevicesLock) {
+ mMediaItemList.add(
+ new MediaItem(title, MediaItem.MediaItemType.TYPE_GROUP_DIVIDER));
+ }
+ }
+
private void attachRangeInfo(List<MediaDevice> devices) {
for (MediaDevice mediaDevice : devices) {
if (mNearbyDeviceInfoMap.containsKey(mediaDevice.getId())) {
diff --git a/packages/SystemUI/src/com/android/systemui/media/taptotransfer/sender/MediaTttSenderCoordinator.kt b/packages/SystemUI/src/com/android/systemui/media/taptotransfer/sender/MediaTttSenderCoordinator.kt
index 9f44d98..935f38d 100644
--- a/packages/SystemUI/src/com/android/systemui/media/taptotransfer/sender/MediaTttSenderCoordinator.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/taptotransfer/sender/MediaTttSenderCoordinator.kt
@@ -150,7 +150,12 @@
logger: MediaTttLogger<ChipbarInfo>,
): ChipbarInfo {
val packageName = routeInfo.clientPackageName
- val otherDeviceName = routeInfo.name.toString()
+ val otherDeviceName =
+ if (routeInfo.name.isBlank()) {
+ context.getString(R.string.media_ttt_default_device_type)
+ } else {
+ routeInfo.name.toString()
+ }
return ChipbarInfo(
// Display the app's icon as the start icon
diff --git a/packages/SystemUI/src/com/android/systemui/notetask/NoteTaskController.kt b/packages/SystemUI/src/com/android/systemui/notetask/NoteTaskController.kt
index 6dd60d0..08d1857 100644
--- a/packages/SystemUI/src/com/android/systemui/notetask/NoteTaskController.kt
+++ b/packages/SystemUI/src/com/android/systemui/notetask/NoteTaskController.kt
@@ -57,7 +57,9 @@
* If the keyguard is locked, notes will open as a full screen experience. A locked device has
* no contextual information which let us use the whole screen space available.
*
- * If no in multi-window or the keyguard is unlocked, notes will open as a floating experience.
+ * If no in multi-window or the keyguard is unlocked, notes will open as a bubble OR it will be
+ * collapsed if the notes bubble is already opened.
+ *
* That will let users open other apps in full screen, and take contextual notes.
*/
fun showNoteTask(isInMultiWindowMode: Boolean = false) {
@@ -75,7 +77,7 @@
context.startActivity(intent)
} else {
// TODO(b/254606432): Should include Intent.EXTRA_FLOATING_WINDOW_MODE parameter.
- bubbles.showAppBubble(intent)
+ bubbles.showOrHideAppBubble(intent)
}
}
@@ -102,4 +104,9 @@
PackageManager.DONT_KILL_APP,
)
}
+
+ companion object {
+ // TODO(b/254604589): Use final KeyEvent.KEYCODE_* instead.
+ const val NOTE_TASK_KEY_EVENT = 311
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/notetask/NoteTaskInitializer.kt b/packages/SystemUI/src/com/android/systemui/notetask/NoteTaskInitializer.kt
index d14b7a7..d5f4a5a 100644
--- a/packages/SystemUI/src/com/android/systemui/notetask/NoteTaskInitializer.kt
+++ b/packages/SystemUI/src/com/android/systemui/notetask/NoteTaskInitializer.kt
@@ -16,7 +16,6 @@
package com.android.systemui.notetask
-import android.view.KeyEvent
import androidx.annotation.VisibleForTesting
import com.android.systemui.statusbar.CommandQueue
import com.android.wm.shell.bubbles.Bubbles
@@ -37,7 +36,7 @@
val callbacks =
object : CommandQueue.Callbacks {
override fun handleSystemKey(keyCode: Int) {
- if (keyCode == KeyEvent.KEYCODE_VIDEO_APP_1) {
+ if (keyCode == NoteTaskController.NOTE_TASK_KEY_EVENT) {
noteTaskController.showNoteTask()
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/notetask/NoteTaskIntentResolver.kt b/packages/SystemUI/src/com/android/systemui/notetask/NoteTaskIntentResolver.kt
index 98d6991..26e3f49 100644
--- a/packages/SystemUI/src/com/android/systemui/notetask/NoteTaskIntentResolver.kt
+++ b/packages/SystemUI/src/com/android/systemui/notetask/NoteTaskIntentResolver.kt
@@ -21,12 +21,12 @@
import android.content.pm.ActivityInfo
import android.content.pm.PackageManager
import android.content.pm.PackageManager.ResolveInfoFlags
-import com.android.systemui.notetask.NoteTaskIntentResolver.Companion.NOTES_ACTION
+import com.android.systemui.notetask.NoteTaskIntentResolver.Companion.ACTION_CREATE_NOTE
import javax.inject.Inject
/**
- * Class responsible to query all apps and find one that can handle the [NOTES_ACTION]. If found, an
- * [Intent] ready for be launched will be returned. Otherwise, returns null.
+ * Class responsible to query all apps and find one that can handle the [ACTION_CREATE_NOTE]. If
+ * found, an [Intent] ready for be launched will be returned. Otherwise, returns null.
*
* TODO(b/248274123): should be revisited once the notes role is implemented.
*/
@@ -37,15 +37,16 @@
) {
fun resolveIntent(): Intent? {
- val intent = Intent(NOTES_ACTION)
+ val intent = Intent(ACTION_CREATE_NOTE)
val flags = ResolveInfoFlags.of(PackageManager.MATCH_DEFAULT_ONLY.toLong())
val infoList = packageManager.queryIntentActivities(intent, flags)
for (info in infoList) {
- val packageName = info.serviceInfo.applicationInfo.packageName ?: continue
+ val packageName = info.activityInfo.applicationInfo.packageName ?: continue
val activityName = resolveActivityNameForNotesAction(packageName) ?: continue
- return Intent(NOTES_ACTION)
+ return Intent(ACTION_CREATE_NOTE)
+ .setPackage(packageName)
.setComponent(ComponentName(packageName, activityName))
.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
}
@@ -54,7 +55,7 @@
}
private fun resolveActivityNameForNotesAction(packageName: String): String? {
- val intent = Intent(NOTES_ACTION).setPackage(packageName)
+ val intent = Intent(ACTION_CREATE_NOTE).setPackage(packageName)
val flags = ResolveInfoFlags.of(PackageManager.MATCH_DEFAULT_ONLY.toLong())
val resolveInfo = packageManager.resolveActivity(intent, flags)
@@ -69,8 +70,8 @@
}
companion object {
- // TODO(b/254606432): Use Intent.ACTION_NOTES and Intent.ACTION_NOTES_LOCKED instead.
- const val NOTES_ACTION = "android.intent.action.NOTES"
+ // TODO(b/254606432): Use Intent.ACTION_CREATE_NOTE instead.
+ const val ACTION_CREATE_NOTE = "android.intent.action.CREATE_NOTE"
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/notetask/shortcut/LaunchNoteTaskActivity.kt b/packages/SystemUI/src/com/android/systemui/notetask/shortcut/LaunchNoteTaskActivity.kt
index 47fe676..f203e7a 100644
--- a/packages/SystemUI/src/com/android/systemui/notetask/shortcut/LaunchNoteTaskActivity.kt
+++ b/packages/SystemUI/src/com/android/systemui/notetask/shortcut/LaunchNoteTaskActivity.kt
@@ -45,8 +45,8 @@
fun newIntent(context: Context): Intent {
return Intent(context, LaunchNoteTaskActivity::class.java).apply {
// Intent's action must be set in shortcuts, or an exception will be thrown.
- // TODO(b/254606432): Use Intent.ACTION_NOTES instead.
- action = NoteTaskIntentResolver.NOTES_ACTION
+ // TODO(b/254606432): Use Intent.ACTION_CREATE_NOTE instead.
+ action = NoteTaskIntentResolver.ACTION_CREATE_NOTE
}
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSFragment.java b/packages/SystemUI/src/com/android/systemui/qs/QSFragment.java
index da18b57..5ef7126 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSFragment.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSFragment.java
@@ -67,6 +67,7 @@
import com.android.systemui.statusbar.policy.BrightnessMirrorController;
import com.android.systemui.statusbar.policy.RemoteInputQuickSettingsDisabler;
import com.android.systemui.util.LifecycleFragment;
+import com.android.systemui.util.Utils;
import java.io.PrintWriter;
import java.util.Arrays;
@@ -682,7 +683,7 @@
} else {
mQsMediaHost.setSquishFraction(mSquishinessFraction);
}
-
+ updateMediaPositions();
}
private void setAlphaAnimationProgress(float progress) {
@@ -757,6 +758,22 @@
- mQSPanelController.getPaddingBottom());
}
+ private void updateMediaPositions() {
+ if (Utils.useQsMediaPlayer(getContext())) {
+ View hostView = mQsMediaHost.getHostView();
+ // Make sure the media appears a bit from the top to make it look nicer
+ if (mLastQSExpansion > 0 && !isKeyguardState() && !mQqsMediaHost.getVisible()
+ && !mQSPanelController.shouldUseHorizontalLayout() && !mInSplitShade) {
+ float interpolation = 1.0f - mLastQSExpansion;
+ interpolation = Interpolators.ACCELERATE.getInterpolation(interpolation);
+ float translationY = -hostView.getHeight() * 1.3f * interpolation;
+ hostView.setTranslationY(translationY);
+ } else {
+ hostView.setTranslationY(0);
+ }
+ }
+ }
+
private boolean headerWillBeAnimating() {
return mStatusBarState == KEYGUARD && mShowCollapsedOnKeyguard && !isKeyguardState();
}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSHost.java b/packages/SystemUI/src/com/android/systemui/qs/QSHost.java
index 7cf63f6..1da30ad 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSHost.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSHost.java
@@ -36,7 +36,6 @@
void removeCallback(Callback callback);
void removeTile(String tileSpec);
void removeTiles(Collection<String> specs);
- void unmarkTileAsAutoAdded(String tileSpec);
int indexOf(String tileSpec);
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSPanelControllerBase.java b/packages/SystemUI/src/com/android/systemui/qs/QSPanelControllerBase.java
index 7bb672c..e85d0a3 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSPanelControllerBase.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSPanelControllerBase.java
@@ -372,18 +372,18 @@
if (mUsingHorizontalLayout) {
// Only height remaining
parameters.getDisappearSize().set(0.0f, 0.4f);
- // Disappearing on the right side on the bottom
- parameters.getGonePivot().set(1.0f, 1.0f);
+ // Disappearing on the right side on the top
+ parameters.getGonePivot().set(1.0f, 0.0f);
// translating a bit horizontal
parameters.getContentTranslationFraction().set(0.25f, 1.0f);
parameters.setDisappearEnd(0.6f);
} else {
// Only width remaining
parameters.getDisappearSize().set(1.0f, 0.0f);
- // Disappearing on the bottom
- parameters.getGonePivot().set(0.0f, 1.0f);
+ // Disappearing on the top
+ parameters.getGonePivot().set(0.0f, 0.0f);
// translating a bit vertical
- parameters.getContentTranslationFraction().set(0.0f, 1.05f);
+ parameters.getContentTranslationFraction().set(0.0f, 1f);
parameters.setDisappearEnd(0.95f);
}
parameters.setFadeStartPosition(0.95f);
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSTileHost.java b/packages/SystemUI/src/com/android/systemui/qs/QSTileHost.java
index cad296b..100853c 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSTileHost.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSTileHost.java
@@ -427,11 +427,6 @@
mMainExecutor.execute(() -> changeTileSpecs(tileSpecs -> tileSpecs.removeAll(specs)));
}
- @Override
- public void unmarkTileAsAutoAdded(String spec) {
- if (mAutoTiles != null) mAutoTiles.unmarkTileAsAutoAdded(spec);
- }
-
/**
* Add a tile to the end
*
diff --git a/packages/SystemUI/src/com/android/systemui/qs/customize/QSCustomizer.java b/packages/SystemUI/src/com/android/systemui/qs/customize/QSCustomizer.java
index 79fcc7d..1712490 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/customize/QSCustomizer.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/customize/QSCustomizer.java
@@ -24,6 +24,7 @@
import android.util.TypedValue;
import android.view.LayoutInflater;
import android.view.Menu;
+import android.view.MenuItem;
import android.view.View;
import android.widget.LinearLayout;
import android.widget.Toolbar;
@@ -74,8 +75,8 @@
toolbar.setNavigationIcon(
getResources().getDrawable(value.resourceId, mContext.getTheme()));
- toolbar.getMenu().add(Menu.NONE, MENU_RESET, 0,
- mContext.getString(com.android.internal.R.string.reset));
+ toolbar.getMenu().add(Menu.NONE, MENU_RESET, 0, com.android.internal.R.string.reset)
+ .setShowAsAction(MenuItem.SHOW_AS_ACTION_IF_ROOM);
toolbar.setTitle(R.string.qs_edit);
mRecyclerView = findViewById(android.R.id.list);
mTransparentView = findViewById(R.id.customizer_transparent_view);
diff --git a/packages/SystemUI/src/com/android/systemui/qs/external/TileLifecycleManager.java b/packages/SystemUI/src/com/android/systemui/qs/external/TileLifecycleManager.java
index d393680..385e720 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/external/TileLifecycleManager.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/external/TileLifecycleManager.java
@@ -15,6 +15,9 @@
*/
package com.android.systemui.qs.external;
+import static android.service.quicksettings.TileService.START_ACTIVITY_NEEDS_PENDING_INTENT;
+
+import android.app.compat.CompatChanges;
import android.content.BroadcastReceiver;
import android.content.ComponentName;
import android.content.Context;
@@ -41,15 +44,15 @@
import com.android.systemui.broadcast.BroadcastDispatcher;
import com.android.systemui.dagger.qualifiers.Main;
+import dagger.assisted.Assisted;
+import dagger.assisted.AssistedFactory;
+import dagger.assisted.AssistedInject;
+
import java.util.NoSuchElementException;
import java.util.Objects;
import java.util.Set;
import java.util.concurrent.atomic.AtomicBoolean;
-import dagger.assisted.Assisted;
-import dagger.assisted.AssistedFactory;
-import dagger.assisted.AssistedInject;
-
/**
* Manages the lifecycle of a TileService.
* <p>
@@ -124,7 +127,9 @@
/** Injectable factory for TileLifecycleManager. */
@AssistedFactory
public interface Factory {
- /** */
+ /**
+ *
+ */
TileLifecycleManager create(Intent intent, UserHandle userHandle);
}
@@ -161,7 +166,7 @@
* Determines whether the associated TileService is a Boolean Tile.
*
* @return true if {@link TileService#META_DATA_TOGGLEABLE_TILE} is set to {@code true} for this
- * tile
+ * tile
* @see TileService#META_DATA_TOGGLEABLE_TILE
*/
public boolean isToggleableTile() {
@@ -207,12 +212,7 @@
if (DEBUG) Log.d(TAG, "Binding service " + mIntent + " " + mUser);
mBindTryCount++;
try {
- mIsBound = mContext.bindServiceAsUser(mIntent, this,
- Context.BIND_AUTO_CREATE
- | Context.BIND_FOREGROUND_SERVICE_WHILE_AWAKE
- | Context.BIND_ALLOW_BACKGROUND_ACTIVITY_STARTS
- | Context.BIND_WAIVE_PRIORITY,
- mUser);
+ mIsBound = bindServices();
if (!mIsBound) {
mContext.unbindService(this);
}
@@ -237,6 +237,24 @@
}
}
+ private boolean bindServices() {
+ String packageName = mIntent.getComponent().getPackageName();
+ if (CompatChanges.isChangeEnabled(START_ACTIVITY_NEEDS_PENDING_INTENT, packageName,
+ mUser)) {
+ return mContext.bindServiceAsUser(mIntent, this,
+ Context.BIND_AUTO_CREATE
+ | Context.BIND_FOREGROUND_SERVICE_WHILE_AWAKE
+ | Context.BIND_WAIVE_PRIORITY,
+ mUser);
+ }
+ return mContext.bindServiceAsUser(mIntent, this,
+ Context.BIND_AUTO_CREATE
+ | Context.BIND_FOREGROUND_SERVICE_WHILE_AWAKE
+ | Context.BIND_ALLOW_BACKGROUND_ACTIVITY_STARTS
+ | Context.BIND_WAIVE_PRIORITY,
+ mUser);
+ }
+
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
if (DEBUG) Log.d(TAG, "onServiceConnected " + name);
@@ -418,8 +436,11 @@
mPackageManagerAdapter.getPackageInfoAsUser(packageName, 0, mUser.getIdentifier());
return true;
} catch (PackageManager.NameNotFoundException e) {
- if (DEBUG) Log.d(TAG, "Package not available: " + packageName, e);
- else Log.d(TAG, "Package not available: " + packageName);
+ if (DEBUG) {
+ Log.d(TAG, "Package not available: " + packageName, e);
+ } else {
+ Log.d(TAG, "Package not available: " + packageName);
+ }
}
return false;
}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/footer/ui/binder/FooterActionsViewBinder.kt b/packages/SystemUI/src/com/android/systemui/qs/footer/ui/binder/FooterActionsViewBinder.kt
index 30f8124..1921586 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/footer/ui/binder/FooterActionsViewBinder.kt
+++ b/packages/SystemUI/src/com/android/systemui/qs/footer/ui/binder/FooterActionsViewBinder.kt
@@ -219,9 +219,9 @@
// Small button with the number only.
foregroundServicesWithTextView.isVisible = false
- foregroundServicesWithNumberView.visibility = View.VISIBLE
+ foregroundServicesWithNumberView.isVisible = true
foregroundServicesWithNumberView.setOnClickListener {
- foregroundServices.onClick(Expandable.fromView(foregroundServicesWithTextView))
+ foregroundServices.onClick(Expandable.fromView(foregroundServicesWithNumberView))
}
foregroundServicesWithNumberHolder.number.text = foregroundServicesCount.toString()
foregroundServicesWithNumberHolder.number.contentDescription = foregroundServices.text
diff --git a/packages/SystemUI/src/com/android/systemui/qs/logging/QSLogger.kt b/packages/SystemUI/src/com/android/systemui/qs/logging/QSLogger.kt
index 9f376ae..d32ef32 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/logging/QSLogger.kt
+++ b/packages/SystemUI/src/com/android/systemui/qs/logging/QSLogger.kt
@@ -49,109 +49,135 @@
}
fun logTileAdded(tileSpec: String) {
- log(DEBUG, {
- str1 = tileSpec
- }, {
- "[$str1] Tile added"
- })
+ buffer.log(TAG, DEBUG, { str1 = tileSpec }, { "[$str1] Tile added" })
}
fun logTileDestroyed(tileSpec: String, reason: String) {
- log(DEBUG, {
- str1 = tileSpec
- str2 = reason
- }, {
- "[$str1] Tile destroyed. Reason: $str2"
- })
+ buffer.log(
+ TAG,
+ DEBUG,
+ {
+ str1 = tileSpec
+ str2 = reason
+ },
+ { "[$str1] Tile destroyed. Reason: $str2" }
+ )
}
fun logTileChangeListening(tileSpec: String, listening: Boolean) {
- log(VERBOSE, {
- bool1 = listening
- str1 = tileSpec
- }, {
- "[$str1] Tile listening=$bool1"
- })
+ buffer.log(
+ TAG,
+ VERBOSE,
+ {
+ bool1 = listening
+ str1 = tileSpec
+ },
+ { "[$str1] Tile listening=$bool1" }
+ )
}
fun logAllTilesChangeListening(listening: Boolean, containerName: String, allSpecs: String) {
- log(DEBUG, {
- bool1 = listening
- str1 = containerName
- str2 = allSpecs
- }, {
- "Tiles listening=$bool1 in $str1. $str2"
- })
+ buffer.log(
+ TAG,
+ DEBUG,
+ {
+ bool1 = listening
+ str1 = containerName
+ str2 = allSpecs
+ },
+ { "Tiles listening=$bool1 in $str1. $str2" }
+ )
}
fun logTileClick(tileSpec: String, statusBarState: Int, state: Int, eventId: Int) {
- log(DEBUG, {
- str1 = tileSpec
- int1 = eventId
- str2 = StatusBarState.toString(statusBarState)
- str3 = toStateString(state)
- }, {
- "[$str1][$int1] Tile clicked. StatusBarState=$str2. TileState=$str3"
- })
+ buffer.log(
+ TAG,
+ DEBUG,
+ {
+ str1 = tileSpec
+ int1 = eventId
+ str2 = StatusBarState.toString(statusBarState)
+ str3 = toStateString(state)
+ },
+ { "[$str1][$int1] Tile clicked. StatusBarState=$str2. TileState=$str3" }
+ )
}
fun logHandleClick(tileSpec: String, eventId: Int) {
- log(DEBUG, {
- str1 = tileSpec
- int1 = eventId
- }, {
- "[$str1][$int1] Tile handling click."
- })
+ buffer.log(
+ TAG,
+ DEBUG,
+ {
+ str1 = tileSpec
+ int1 = eventId
+ },
+ { "[$str1][$int1] Tile handling click." }
+ )
}
fun logTileSecondaryClick(tileSpec: String, statusBarState: Int, state: Int, eventId: Int) {
- log(DEBUG, {
- str1 = tileSpec
- int1 = eventId
- str2 = StatusBarState.toString(statusBarState)
- str3 = toStateString(state)
- }, {
- "[$str1][$int1] Tile secondary clicked. StatusBarState=$str2. TileState=$str3"
- })
+ buffer.log(
+ TAG,
+ DEBUG,
+ {
+ str1 = tileSpec
+ int1 = eventId
+ str2 = StatusBarState.toString(statusBarState)
+ str3 = toStateString(state)
+ },
+ { "[$str1][$int1] Tile secondary clicked. StatusBarState=$str2. TileState=$str3" }
+ )
}
fun logHandleSecondaryClick(tileSpec: String, eventId: Int) {
- log(DEBUG, {
- str1 = tileSpec
- int1 = eventId
- }, {
- "[$str1][$int1] Tile handling secondary click."
- })
+ buffer.log(
+ TAG,
+ DEBUG,
+ {
+ str1 = tileSpec
+ int1 = eventId
+ },
+ { "[$str1][$int1] Tile handling secondary click." }
+ )
}
fun logTileLongClick(tileSpec: String, statusBarState: Int, state: Int, eventId: Int) {
- log(DEBUG, {
- str1 = tileSpec
- int1 = eventId
- str2 = StatusBarState.toString(statusBarState)
- str3 = toStateString(state)
- }, {
- "[$str1][$int1] Tile long clicked. StatusBarState=$str2. TileState=$str3"
- })
+ buffer.log(
+ TAG,
+ DEBUG,
+ {
+ str1 = tileSpec
+ int1 = eventId
+ str2 = StatusBarState.toString(statusBarState)
+ str3 = toStateString(state)
+ },
+ { "[$str1][$int1] Tile long clicked. StatusBarState=$str2. TileState=$str3" }
+ )
}
fun logHandleLongClick(tileSpec: String, eventId: Int) {
- log(DEBUG, {
- str1 = tileSpec
- int1 = eventId
- }, {
- "[$str1][$int1] Tile handling long click."
- })
+ buffer.log(
+ TAG,
+ DEBUG,
+ {
+ str1 = tileSpec
+ int1 = eventId
+ },
+ { "[$str1][$int1] Tile handling long click." }
+ )
}
fun logInternetTileUpdate(tileSpec: String, lastType: Int, callback: String) {
- log(VERBOSE, {
- str1 = tileSpec
- int1 = lastType
- str2 = callback
- }, {
- "[$str1] mLastTileState=$int1, Callback=$str2."
- })
+ buffer.log(
+ TAG,
+ VERBOSE,
+ {
+ str1 = tileSpec
+ int1 = lastType
+ str2 = callback
+ },
+ { "[$str1] mLastTileState=$int1, Callback=$str2." }
+ )
}
// TODO(b/250618218): Remove this method once we know the root cause of b/250618218.
@@ -167,58 +193,75 @@
if (tileSpec != "internet") {
return
}
- log(VERBOSE, {
- str1 = tileSpec
- int1 = state
- bool1 = disabledByPolicy
- int2 = color
- }, {
- "[$str1] state=$int1, disabledByPolicy=$bool1, color=$int2."
- })
+ buffer.log(
+ TAG,
+ VERBOSE,
+ {
+ str1 = tileSpec
+ int1 = state
+ bool1 = disabledByPolicy
+ int2 = color
+ },
+ { "[$str1] state=$int1, disabledByPolicy=$bool1, color=$int2." }
+ )
}
fun logTileUpdated(tileSpec: String, state: QSTile.State) {
- log(VERBOSE, {
- str1 = tileSpec
- str2 = state.label?.toString()
- str3 = state.icon?.toString()
- int1 = state.state
- if (state is QSTile.SignalState) {
- bool1 = true
- bool2 = state.activityIn
- bool3 = state.activityOut
+ buffer.log(
+ TAG,
+ VERBOSE,
+ {
+ str1 = tileSpec
+ str2 = state.label?.toString()
+ str3 = state.icon?.toString()
+ int1 = state.state
+ if (state is QSTile.SignalState) {
+ bool1 = true
+ bool2 = state.activityIn
+ bool3 = state.activityOut
+ }
+ },
+ {
+ "[$str1] Tile updated. Label=$str2. State=$int1. Icon=$str3." +
+ if (bool1) " Activity in/out=$bool2/$bool3" else ""
}
- }, {
- "[$str1] Tile updated. Label=$str2. State=$int1. Icon=$str3." +
- if (bool1) " Activity in/out=$bool2/$bool3" else ""
- })
+ )
}
fun logPanelExpanded(expanded: Boolean, containerName: String) {
- log(DEBUG, {
- str1 = containerName
- bool1 = expanded
- }, {
- "$str1 expanded=$bool1"
- })
+ buffer.log(
+ TAG,
+ DEBUG,
+ {
+ str1 = containerName
+ bool1 = expanded
+ },
+ { "$str1 expanded=$bool1" }
+ )
}
fun logOnViewAttached(orientation: Int, containerName: String) {
- log(DEBUG, {
- str1 = containerName
- int1 = orientation
- }, {
- "onViewAttached: $str1 orientation $int1"
- })
+ buffer.log(
+ TAG,
+ DEBUG,
+ {
+ str1 = containerName
+ int1 = orientation
+ },
+ { "onViewAttached: $str1 orientation $int1" }
+ )
}
fun logOnViewDetached(orientation: Int, containerName: String) {
- log(DEBUG, {
- str1 = containerName
- int1 = orientation
- }, {
- "onViewDetached: $str1 orientation $int1"
- })
+ buffer.log(
+ TAG,
+ DEBUG,
+ {
+ str1 = containerName
+ int1 = orientation
+ },
+ { "onViewDetached: $str1 orientation $int1" }
+ )
}
fun logOnConfigurationChanged(
@@ -226,13 +269,16 @@
newOrientation: Int,
containerName: String
) {
- log(DEBUG, {
- str1 = containerName
- int1 = lastOrientation
- int2 = newOrientation
- }, {
- "configuration change: $str1 orientation was $int1, now $int2"
- })
+ buffer.log(
+ TAG,
+ DEBUG,
+ {
+ str1 = containerName
+ int1 = lastOrientation
+ int2 = newOrientation
+ },
+ { "configuration change: $str1 orientation was $int1, now $int2" }
+ )
}
fun logSwitchTileLayout(
@@ -241,32 +287,41 @@
force: Boolean,
containerName: String
) {
- log(DEBUG, {
- str1 = containerName
- bool1 = after
- bool2 = before
- bool3 = force
- }, {
- "change tile layout: $str1 horizontal=$bool1 (was $bool2), force? $bool3"
- })
+ buffer.log(
+ TAG,
+ DEBUG,
+ {
+ str1 = containerName
+ bool1 = after
+ bool2 = before
+ bool3 = force
+ },
+ { "change tile layout: $str1 horizontal=$bool1 (was $bool2), force? $bool3" }
+ )
}
fun logTileDistributionInProgress(tilesPerPageCount: Int, totalTilesCount: Int) {
- log(DEBUG, {
- int1 = tilesPerPageCount
- int2 = totalTilesCount
- }, {
- "Distributing tiles: [tilesPerPageCount=$int1] [totalTilesCount=$int2]"
- })
+ buffer.log(
+ TAG,
+ DEBUG,
+ {
+ int1 = tilesPerPageCount
+ int2 = totalTilesCount
+ },
+ { "Distributing tiles: [tilesPerPageCount=$int1] [totalTilesCount=$int2]" }
+ )
}
fun logTileDistributed(tileName: String, pageIndex: Int) {
- log(DEBUG, {
- str1 = tileName
- int1 = pageIndex
- }, {
- "Adding $str1 to page number $int1"
- })
+ buffer.log(
+ TAG,
+ DEBUG,
+ {
+ str1 = tileName
+ int1 = pageIndex
+ },
+ { "Adding $str1 to page number $int1" }
+ )
}
private fun toStateString(state: Int): String {
@@ -277,12 +332,4 @@
else -> "wrong state"
}
}
-
- private inline fun log(
- logLevel: LogLevel,
- initializer: LogMessage.() -> Unit,
- noinline printer: LogMessage.() -> String
- ) {
- buffer.log(TAG, logLevel, initializer, printer)
- }
}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSFactoryImpl.java b/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSFactoryImpl.java
index a92c7e3..24a4f60b 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSFactoryImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSFactoryImpl.java
@@ -33,7 +33,6 @@
import com.android.systemui.qs.tiles.BluetoothTile;
import com.android.systemui.qs.tiles.CameraToggleTile;
import com.android.systemui.qs.tiles.CastTile;
-import com.android.systemui.qs.tiles.CellularTile;
import com.android.systemui.qs.tiles.ColorCorrectionTile;
import com.android.systemui.qs.tiles.ColorInversionTile;
import com.android.systemui.qs.tiles.DataSaverTile;
@@ -54,7 +53,6 @@
import com.android.systemui.qs.tiles.RotationLockTile;
import com.android.systemui.qs.tiles.ScreenRecordTile;
import com.android.systemui.qs.tiles.UiModeNightTile;
-import com.android.systemui.qs.tiles.WifiTile;
import com.android.systemui.qs.tiles.WorkModeTile;
import com.android.systemui.util.leak.GarbageMonitor;
@@ -68,10 +66,8 @@
private static final String TAG = "QSFactory";
- private final Provider<WifiTile> mWifiTileProvider;
private final Provider<InternetTile> mInternetTileProvider;
private final Provider<BluetoothTile> mBluetoothTileProvider;
- private final Provider<CellularTile> mCellularTileProvider;
private final Provider<DndTile> mDndTileProvider;
private final Provider<ColorCorrectionTile> mColorCorrectionTileProvider;
private final Provider<ColorInversionTile> mColorInversionTileProvider;
@@ -106,10 +102,8 @@
public QSFactoryImpl(
Lazy<QSHost> qsHostLazy,
Provider<CustomTile.Builder> customTileBuilderProvider,
- Provider<WifiTile> wifiTileProvider,
Provider<InternetTile> internetTileProvider,
Provider<BluetoothTile> bluetoothTileProvider,
- Provider<CellularTile> cellularTileProvider,
Provider<DndTile> dndTileProvider,
Provider<ColorInversionTile> colorInversionTileProvider,
Provider<AirplaneModeTile> airplaneModeTileProvider,
@@ -139,10 +133,8 @@
mQsHostLazy = qsHostLazy;
mCustomTileBuilderProvider = customTileBuilderProvider;
- mWifiTileProvider = wifiTileProvider;
mInternetTileProvider = internetTileProvider;
mBluetoothTileProvider = bluetoothTileProvider;
- mCellularTileProvider = cellularTileProvider;
mDndTileProvider = dndTileProvider;
mColorInversionTileProvider = colorInversionTileProvider;
mAirplaneModeTileProvider = airplaneModeTileProvider;
@@ -186,14 +178,10 @@
protected QSTileImpl createTileInternal(String tileSpec) {
// Stock tiles.
switch (tileSpec) {
- case "wifi":
- return mWifiTileProvider.get();
case "internet":
return mInternetTileProvider.get();
case "bt":
return mBluetoothTileProvider.get();
- case "cell":
- return mCellularTileProvider.get();
case "dnd":
return mDndTileProvider.get();
case "inversion":
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/CellularTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/CellularTile.java
deleted file mode 100644
index 04a25fc..0000000
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/CellularTile.java
+++ /dev/null
@@ -1,301 +0,0 @@
-/*
- * Copyright (C) 2014 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES 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.android.systemui.qs.tiles;
-
-import static com.android.systemui.Prefs.Key.QS_HAS_TURNED_OFF_MOBILE_DATA;
-
-import android.annotation.NonNull;
-import android.app.AlertDialog;
-import android.app.AlertDialog.Builder;
-import android.content.Context;
-import android.content.Intent;
-import android.content.res.Resources;
-import android.os.Handler;
-import android.os.Looper;
-import android.os.UserHandle;
-import android.provider.Settings;
-import android.service.quicksettings.Tile;
-import android.telephony.SubscriptionManager;
-import android.text.Html;
-import android.text.TextUtils;
-import android.view.View;
-import android.view.WindowManager.LayoutParams;
-import android.widget.Switch;
-
-import androidx.annotation.Nullable;
-
-import com.android.internal.logging.MetricsLogger;
-import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
-import com.android.settingslib.net.DataUsageController;
-import com.android.systemui.Prefs;
-import com.android.systemui.R;
-import com.android.systemui.dagger.qualifiers.Background;
-import com.android.systemui.dagger.qualifiers.Main;
-import com.android.systemui.plugins.ActivityStarter;
-import com.android.systemui.plugins.FalsingManager;
-import com.android.systemui.plugins.qs.QSIconView;
-import com.android.systemui.plugins.qs.QSTile.SignalState;
-import com.android.systemui.plugins.statusbar.StatusBarStateController;
-import com.android.systemui.qs.QSHost;
-import com.android.systemui.qs.SignalTileView;
-import com.android.systemui.qs.logging.QSLogger;
-import com.android.systemui.qs.tileimpl.QSTileImpl;
-import com.android.systemui.statusbar.connectivity.IconState;
-import com.android.systemui.statusbar.connectivity.MobileDataIndicators;
-import com.android.systemui.statusbar.connectivity.NetworkController;
-import com.android.systemui.statusbar.connectivity.SignalCallback;
-import com.android.systemui.statusbar.phone.SystemUIDialog;
-import com.android.systemui.statusbar.policy.KeyguardStateController;
-
-import javax.inject.Inject;
-
-/** Quick settings tile: Cellular **/
-public class CellularTile extends QSTileImpl<SignalState> {
- private static final String ENABLE_SETTINGS_DATA_PLAN = "enable.settings.data.plan";
-
- private final NetworkController mController;
- private final DataUsageController mDataController;
- private final KeyguardStateController mKeyguard;
- private final CellSignalCallback mSignalCallback = new CellSignalCallback();
-
- @Inject
- public CellularTile(
- QSHost host,
- @Background Looper backgroundLooper,
- @Main Handler mainHandler,
- FalsingManager falsingManager,
- MetricsLogger metricsLogger,
- StatusBarStateController statusBarStateController,
- ActivityStarter activityStarter,
- QSLogger qsLogger,
- NetworkController networkController,
- KeyguardStateController keyguardStateController
-
- ) {
- super(host, backgroundLooper, mainHandler, falsingManager, metricsLogger,
- statusBarStateController, activityStarter, qsLogger);
- mController = networkController;
- mKeyguard = keyguardStateController;
- mDataController = mController.getMobileDataController();
- mController.observe(getLifecycle(), mSignalCallback);
- }
-
- @Override
- public SignalState newTileState() {
- return new SignalState();
- }
-
- @Override
- public QSIconView createTileView(Context context) {
- return new SignalTileView(context);
- }
-
- @Override
- public Intent getLongClickIntent() {
- if (getState().state == Tile.STATE_UNAVAILABLE) {
- return new Intent(Settings.ACTION_WIRELESS_SETTINGS);
- }
- return getCellularSettingIntent();
- }
-
- @Override
- protected void handleClick(@Nullable View view) {
- if (getState().state == Tile.STATE_UNAVAILABLE) {
- return;
- }
- if (mDataController.isMobileDataEnabled()) {
- maybeShowDisableDialog();
- } else {
- mDataController.setMobileDataEnabled(true);
- }
- }
-
- private void maybeShowDisableDialog() {
- if (Prefs.getBoolean(mContext, QS_HAS_TURNED_OFF_MOBILE_DATA, false)) {
- // Directly turn off mobile data if the user has seen the dialog before.
- mDataController.setMobileDataEnabled(false);
- return;
- }
- String carrierName = mController.getMobileDataNetworkName();
- boolean isInService = mController.isMobileDataNetworkInService();
- if (TextUtils.isEmpty(carrierName) || !isInService) {
- carrierName = mContext.getString(R.string.mobile_data_disable_message_default_carrier);
- }
- AlertDialog dialog = new Builder(mContext)
- .setTitle(R.string.mobile_data_disable_title)
- .setMessage(mContext.getString(R.string.mobile_data_disable_message, carrierName))
- .setNegativeButton(android.R.string.cancel, null)
- .setPositiveButton(
- com.android.internal.R.string.alert_windows_notification_turn_off_action,
- (d, w) -> {
- mDataController.setMobileDataEnabled(false);
- Prefs.putBoolean(mContext, QS_HAS_TURNED_OFF_MOBILE_DATA, true);
- })
- .create();
- dialog.getWindow().setType(LayoutParams.TYPE_KEYGUARD_DIALOG);
- SystemUIDialog.setShowForAllUsers(dialog, true);
- SystemUIDialog.registerDismissListener(dialog);
- SystemUIDialog.setWindowOnTop(dialog, mKeyguard.isShowing());
- dialog.show();
- }
-
- @Override
- protected void handleSecondaryClick(@Nullable View view) {
- handleLongClick(view);
- }
-
- @Override
- public CharSequence getTileLabel() {
- return mContext.getString(R.string.quick_settings_cellular_detail_title);
- }
-
- @Override
- protected void handleUpdateState(SignalState state, Object arg) {
- CallbackInfo cb = (CallbackInfo) arg;
- if (cb == null) {
- cb = mSignalCallback.mInfo;
- }
-
- final Resources r = mContext.getResources();
- state.label = r.getString(R.string.mobile_data);
- boolean mobileDataEnabled = mDataController.isMobileDataSupported()
- && mDataController.isMobileDataEnabled();
- state.value = mobileDataEnabled;
- state.activityIn = mobileDataEnabled && cb.activityIn;
- state.activityOut = mobileDataEnabled && cb.activityOut;
- state.expandedAccessibilityClassName = Switch.class.getName();
- if (cb.noSim) {
- state.icon = ResourceIcon.get(R.drawable.ic_qs_no_sim);
- } else {
- state.icon = ResourceIcon.get(R.drawable.ic_swap_vert);
- }
-
- if (cb.noSim) {
- state.state = Tile.STATE_UNAVAILABLE;
- state.secondaryLabel = r.getString(R.string.keyguard_missing_sim_message_short);
- } else if (cb.airplaneModeEnabled) {
- state.state = Tile.STATE_UNAVAILABLE;
- state.secondaryLabel = r.getString(R.string.status_bar_airplane);
- } else if (mobileDataEnabled) {
- state.state = Tile.STATE_ACTIVE;
- state.secondaryLabel = appendMobileDataType(
- // Only show carrier name if there are more than 1 subscription
- cb.multipleSubs ? cb.dataSubscriptionName : "",
- getMobileDataContentName(cb));
- } else {
- state.state = Tile.STATE_INACTIVE;
- state.secondaryLabel = r.getString(R.string.cell_data_off);
- }
-
- state.contentDescription = state.label;
- if (state.state == Tile.STATE_INACTIVE) {
- // This information is appended later by converting the Tile.STATE_INACTIVE state.
- state.stateDescription = "";
- } else {
- state.stateDescription = state.secondaryLabel;
- }
- }
-
- private CharSequence appendMobileDataType(CharSequence current, CharSequence dataType) {
- if (TextUtils.isEmpty(dataType)) {
- return Html.fromHtml(current.toString(), 0);
- }
- if (TextUtils.isEmpty(current)) {
- return Html.fromHtml(dataType.toString(), 0);
- }
- String concat = mContext.getString(R.string.mobile_carrier_text_format, current, dataType);
- return Html.fromHtml(concat, 0);
- }
-
- private CharSequence getMobileDataContentName(CallbackInfo cb) {
- if (cb.roaming && !TextUtils.isEmpty(cb.dataContentDescription)) {
- String roaming = mContext.getString(R.string.data_connection_roaming);
- String dataDescription = cb.dataContentDescription.toString();
- return mContext.getString(R.string.mobile_data_text_format, roaming, dataDescription);
- }
- if (cb.roaming) {
- return mContext.getString(R.string.data_connection_roaming);
- }
- return cb.dataContentDescription;
- }
-
- @Override
- public int getMetricsCategory() {
- return MetricsEvent.QS_CELLULAR;
- }
-
- @Override
- public boolean isAvailable() {
- return mController.hasMobileDataFeature()
- && mHost.getUserContext().getUserId() == UserHandle.USER_SYSTEM;
- }
-
- private static final class CallbackInfo {
- boolean airplaneModeEnabled;
- @Nullable
- CharSequence dataSubscriptionName;
- @Nullable
- CharSequence dataContentDescription;
- boolean activityIn;
- boolean activityOut;
- boolean noSim;
- boolean roaming;
- boolean multipleSubs;
- }
-
- private final class CellSignalCallback implements SignalCallback {
- private final CallbackInfo mInfo = new CallbackInfo();
-
- @Override
- public void setMobileDataIndicators(@NonNull MobileDataIndicators indicators) {
- if (indicators.qsIcon == null) {
- // Not data sim, don't display.
- return;
- }
- mInfo.dataSubscriptionName = mController.getMobileDataNetworkName();
- mInfo.dataContentDescription = indicators.qsDescription != null
- ? indicators.typeContentDescriptionHtml : null;
- mInfo.activityIn = indicators.activityIn;
- mInfo.activityOut = indicators.activityOut;
- mInfo.roaming = indicators.roaming;
- mInfo.multipleSubs = mController.getNumberSubscriptions() > 1;
- refreshState(mInfo);
- }
-
- @Override
- public void setNoSims(boolean show, boolean simDetected) {
- mInfo.noSim = show;
- refreshState(mInfo);
- }
-
- @Override
- public void setIsAirplaneMode(@NonNull IconState icon) {
- mInfo.airplaneModeEnabled = icon.visible;
- refreshState(mInfo);
- }
- }
-
- static Intent getCellularSettingIntent() {
- Intent intent = new Intent(Settings.ACTION_NETWORK_OPERATOR_SETTINGS);
- int dataSub = SubscriptionManager.getDefaultDataSubscriptionId();
- if (dataSub != SubscriptionManager.INVALID_SUBSCRIPTION_ID) {
- intent.putExtra(Settings.EXTRA_SUB_ID,
- SubscriptionManager.getDefaultDataSubscriptionId());
- }
- return intent;
- }
-}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/WifiTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/WifiTile.java
deleted file mode 100644
index b2be56cc..0000000
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/WifiTile.java
+++ /dev/null
@@ -1,286 +0,0 @@
-/*
- * Copyright (C) 2014 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES 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.android.systemui.qs.tiles;
-
-import android.annotation.NonNull;
-import android.content.Context;
-import android.content.Intent;
-import android.content.pm.PackageManager;
-import android.content.res.Resources;
-import android.os.Handler;
-import android.os.Looper;
-import android.provider.Settings;
-import android.service.quicksettings.Tile;
-import android.text.TextUtils;
-import android.util.Log;
-import android.view.View;
-import android.widget.Switch;
-
-import androidx.annotation.Nullable;
-
-import com.android.internal.logging.MetricsLogger;
-import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
-import com.android.systemui.R;
-import com.android.systemui.dagger.qualifiers.Background;
-import com.android.systemui.dagger.qualifiers.Main;
-import com.android.systemui.plugins.ActivityStarter;
-import com.android.systemui.plugins.FalsingManager;
-import com.android.systemui.plugins.qs.QSIconView;
-import com.android.systemui.plugins.qs.QSTile;
-import com.android.systemui.plugins.qs.QSTile.SignalState;
-import com.android.systemui.plugins.statusbar.StatusBarStateController;
-import com.android.systemui.qs.AlphaControlledSignalTileView;
-import com.android.systemui.qs.QSHost;
-import com.android.systemui.qs.logging.QSLogger;
-import com.android.systemui.qs.tileimpl.QSIconViewImpl;
-import com.android.systemui.qs.tileimpl.QSTileImpl;
-import com.android.systemui.statusbar.connectivity.AccessPointController;
-import com.android.systemui.statusbar.connectivity.NetworkController;
-import com.android.systemui.statusbar.connectivity.SignalCallback;
-import com.android.systemui.statusbar.connectivity.WifiIcons;
-import com.android.systemui.statusbar.connectivity.WifiIndicators;
-
-import javax.inject.Inject;
-
-/** Quick settings tile: Wifi **/
-public class WifiTile extends QSTileImpl<SignalState> {
- private static final Intent WIFI_SETTINGS = new Intent(Settings.ACTION_WIFI_SETTINGS);
-
- protected final NetworkController mController;
- private final AccessPointController mWifiController;
- private final QSTile.SignalState mStateBeforeClick = newTileState();
-
- protected final WifiSignalCallback mSignalCallback = new WifiSignalCallback();
- private boolean mExpectDisabled;
-
- @Inject
- public WifiTile(
- QSHost host,
- @Background Looper backgroundLooper,
- @Main Handler mainHandler,
- FalsingManager falsingManager,
- MetricsLogger metricsLogger,
- StatusBarStateController statusBarStateController,
- ActivityStarter activityStarter,
- QSLogger qsLogger,
- NetworkController networkController,
- AccessPointController accessPointController
- ) {
- super(host, backgroundLooper, mainHandler, falsingManager, metricsLogger,
- statusBarStateController, activityStarter, qsLogger);
- mController = networkController;
- mWifiController = accessPointController;
- mController.observe(getLifecycle(), mSignalCallback);
- mStateBeforeClick.spec = "wifi";
- }
-
- @Override
- public SignalState newTileState() {
- return new SignalState();
- }
-
- @Override
- public QSIconView createTileView(Context context) {
- return new AlphaControlledSignalTileView(context);
- }
-
- @Override
- public Intent getLongClickIntent() {
- return WIFI_SETTINGS;
- }
-
- @Override
- protected void handleClick(@Nullable View view) {
- // Secondary clicks are header clicks, just toggle.
- mState.copyTo(mStateBeforeClick);
- boolean wifiEnabled = mState.value;
- // Immediately enter transient state when turning on wifi.
- refreshState(wifiEnabled ? null : ARG_SHOW_TRANSIENT_ENABLING);
- mController.setWifiEnabled(!wifiEnabled);
- mExpectDisabled = wifiEnabled;
- if (mExpectDisabled) {
- mHandler.postDelayed(() -> {
- if (mExpectDisabled) {
- mExpectDisabled = false;
- refreshState();
- }
- }, QSIconViewImpl.QS_ANIM_LENGTH);
- }
- }
-
- @Override
- protected void handleSecondaryClick(@Nullable View view) {
- if (!mWifiController.canConfigWifi()) {
- mActivityStarter.postStartActivityDismissingKeyguard(
- new Intent(Settings.ACTION_WIFI_SETTINGS), 0);
- return;
- }
- if (!mState.value) {
- mController.setWifiEnabled(true);
- }
- }
-
- @Override
- public CharSequence getTileLabel() {
- return mContext.getString(R.string.quick_settings_wifi_label);
- }
-
- @Override
- protected void handleUpdateState(SignalState state, Object arg) {
- if (DEBUG) Log.d(TAG, "handleUpdateState arg=" + arg);
- final CallbackInfo cb = mSignalCallback.mInfo;
- if (mExpectDisabled) {
- if (cb.enabled) {
- return; // Ignore updates until disabled event occurs.
- } else {
- mExpectDisabled = false;
- }
- }
- boolean transientEnabling = arg == ARG_SHOW_TRANSIENT_ENABLING;
- boolean wifiConnected = cb.enabled && (cb.wifiSignalIconId > 0)
- && (cb.ssid != null || cb.wifiSignalIconId != WifiIcons.QS_WIFI_NO_NETWORK);
- boolean wifiNotConnected = (cb.ssid == null)
- && (cb.wifiSignalIconId == WifiIcons.QS_WIFI_NO_NETWORK);
- if (state.slash == null) {
- state.slash = new SlashState();
- state.slash.rotation = 6;
- }
- state.slash.isSlashed = false;
- boolean isTransient = transientEnabling || cb.isTransient;
- state.secondaryLabel = getSecondaryLabel(isTransient, cb.statusLabel);
- state.state = Tile.STATE_ACTIVE;
- state.dualTarget = true;
- state.value = transientEnabling || cb.enabled;
- state.activityIn = cb.enabled && cb.activityIn;
- state.activityOut = cb.enabled && cb.activityOut;
- final StringBuffer minimalContentDescription = new StringBuffer();
- final StringBuffer minimalStateDescription = new StringBuffer();
- final Resources r = mContext.getResources();
- if (isTransient) {
- state.icon = ResourceIcon.get(
- com.android.internal.R.drawable.ic_signal_wifi_transient_animation);
- state.label = r.getString(R.string.quick_settings_wifi_label);
- } else if (!state.value) {
- state.slash.isSlashed = true;
- state.state = Tile.STATE_INACTIVE;
- state.icon = ResourceIcon.get(WifiIcons.QS_WIFI_DISABLED);
- state.label = r.getString(R.string.quick_settings_wifi_label);
- } else if (wifiConnected) {
- state.icon = ResourceIcon.get(cb.wifiSignalIconId);
- state.label = cb.ssid != null ? removeDoubleQuotes(cb.ssid) : getTileLabel();
- } else if (wifiNotConnected) {
- state.icon = ResourceIcon.get(WifiIcons.QS_WIFI_NO_NETWORK);
- state.label = r.getString(R.string.quick_settings_wifi_label);
- } else {
- state.icon = ResourceIcon.get(WifiIcons.QS_WIFI_NO_NETWORK);
- state.label = r.getString(R.string.quick_settings_wifi_label);
- }
- minimalContentDescription.append(
- mContext.getString(R.string.quick_settings_wifi_label)).append(",");
- if (state.value) {
- if (wifiConnected) {
- minimalStateDescription.append(cb.wifiSignalContentDescription);
- minimalContentDescription.append(removeDoubleQuotes(cb.ssid));
- if (!TextUtils.isEmpty(state.secondaryLabel)) {
- minimalContentDescription.append(",").append(state.secondaryLabel);
- }
- }
- }
- state.stateDescription = minimalStateDescription.toString();
- state.contentDescription = minimalContentDescription.toString();
- state.dualLabelContentDescription = r.getString(
- R.string.accessibility_quick_settings_open_settings, getTileLabel());
- state.expandedAccessibilityClassName = Switch.class.getName();
- }
-
- private CharSequence getSecondaryLabel(boolean isTransient, String statusLabel) {
- return isTransient
- ? mContext.getString(R.string.quick_settings_wifi_secondary_label_transient)
- : statusLabel;
- }
-
- @Override
- public int getMetricsCategory() {
- return MetricsEvent.QS_WIFI;
- }
-
- @Override
- public boolean isAvailable() {
- return mContext.getPackageManager().hasSystemFeature(PackageManager.FEATURE_WIFI);
- }
-
- @Nullable
- private static String removeDoubleQuotes(String string) {
- if (string == null) return null;
- final int length = string.length();
- if ((length > 1) && (string.charAt(0) == '"') && (string.charAt(length - 1) == '"')) {
- return string.substring(1, length - 1);
- }
- return string;
- }
-
- protected static final class CallbackInfo {
- boolean enabled;
- boolean connected;
- int wifiSignalIconId;
- @Nullable
- String ssid;
- boolean activityIn;
- boolean activityOut;
- @Nullable
- String wifiSignalContentDescription;
- boolean isTransient;
- @Nullable
- public String statusLabel;
-
- @Override
- public String toString() {
- return new StringBuilder("CallbackInfo[")
- .append("enabled=").append(enabled)
- .append(",connected=").append(connected)
- .append(",wifiSignalIconId=").append(wifiSignalIconId)
- .append(",ssid=").append(ssid)
- .append(",activityIn=").append(activityIn)
- .append(",activityOut=").append(activityOut)
- .append(",wifiSignalContentDescription=").append(wifiSignalContentDescription)
- .append(",isTransient=").append(isTransient)
- .append(']').toString();
- }
- }
-
- protected final class WifiSignalCallback implements SignalCallback {
- final CallbackInfo mInfo = new CallbackInfo();
-
- @Override
- public void setWifiIndicators(@NonNull WifiIndicators indicators) {
- if (DEBUG) Log.d(TAG, "onWifiSignalChanged enabled=" + indicators.enabled);
- if (indicators.qsIcon == null) {
- return;
- }
- mInfo.enabled = indicators.enabled;
- mInfo.connected = indicators.qsIcon.visible;
- mInfo.wifiSignalIconId = indicators.qsIcon.icon;
- mInfo.ssid = indicators.description;
- mInfo.activityIn = indicators.activityIn;
- mInfo.activityOut = indicators.activityOut;
- mInfo.wifiSignalContentDescription = indicators.qsIcon.contentDescription;
- mInfo.isTransient = indicators.isTransient;
- mInfo.statusLabel = indicators.statusLabel;
- refreshState();
- }
- }
-}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/WorkModeTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/WorkModeTile.java
index a6c7781..72c6bfe 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/WorkModeTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/WorkModeTile.java
@@ -101,7 +101,6 @@
@MainThread
public void onManagedProfileRemoved() {
mHost.removeTile(getTileSpec());
- mHost.unmarkTileAsAutoAdded(getTileSpec());
}
@Override
diff --git a/packages/SystemUI/src/com/android/systemui/recents/OverviewProxyRecentsImpl.java b/packages/SystemUI/src/com/android/systemui/recents/OverviewProxyRecentsImpl.java
index 5ea1c0b..c335a6d 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/OverviewProxyRecentsImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/OverviewProxyRecentsImpl.java
@@ -59,11 +59,11 @@
}
@Override
- public void showRecentApps(boolean triggeredFromAltTab) {
+ public void showRecentApps(boolean triggeredFromAltTab, boolean forward) {
IOverviewProxy overviewProxy = mOverviewProxyService.getProxy();
if (overviewProxy != null) {
try {
- overviewProxy.onOverviewShown(triggeredFromAltTab);
+ overviewProxy.onOverviewShown(triggeredFromAltTab, forward);
} catch (RemoteException e) {
Log.e(TAG, "Failed to send overview show event to launcher.", e);
}
diff --git a/packages/SystemUI/src/com/android/systemui/recents/Recents.java b/packages/SystemUI/src/com/android/systemui/recents/Recents.java
index b041f95..95d6c18 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/Recents.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/Recents.java
@@ -65,14 +65,14 @@
}
@Override
- public void showRecentApps(boolean triggeredFromAltTab) {
+ public void showRecentApps(boolean triggeredFromAltTab, boolean forward) {
// Ensure the device has been provisioned before allowing the user to interact with
// recents
if (!isUserSetup()) {
return;
}
- mImpl.showRecentApps(triggeredFromAltTab);
+ mImpl.showRecentApps(triggeredFromAltTab, forward);
}
@Override
diff --git a/packages/SystemUI/src/com/android/systemui/recents/RecentsImplementation.java b/packages/SystemUI/src/com/android/systemui/recents/RecentsImplementation.java
index 8848dbb..010ceda 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/RecentsImplementation.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/RecentsImplementation.java
@@ -31,7 +31,7 @@
default void preloadRecentApps() {}
default void cancelPreloadRecentApps() {}
- default void showRecentApps(boolean triggeredFromAltTab) {}
+ default void showRecentApps(boolean triggeredFromAltTab, boolean forward) {}
default void hideRecentApps(boolean triggeredFromAltTab, boolean triggeredFromHomeKey) {}
default void toggleRecentApps() {}
diff --git a/packages/SystemUI/src/com/android/systemui/screenrecord/RecordingController.java b/packages/SystemUI/src/com/android/systemui/screenrecord/RecordingController.java
index b8684ee..431b28f 100644
--- a/packages/SystemUI/src/com/android/systemui/screenrecord/RecordingController.java
+++ b/packages/SystemUI/src/com/android/systemui/screenrecord/RecordingController.java
@@ -16,12 +16,14 @@
package com.android.systemui.screenrecord;
+import android.app.BroadcastOptions;
import android.app.Dialog;
import android.app.PendingIntent;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
+import android.os.Bundle;
import android.os.CountDownTimer;
import android.os.UserHandle;
import android.util.Log;
@@ -57,6 +59,7 @@
private boolean mIsStarting;
private boolean mIsRecording;
private PendingIntent mStopIntent;
+ private final Bundle mInteractiveBroadcastOption;
private CountDownTimer mCountDownTimer = null;
private final Executor mMainExecutor;
private final BroadcastDispatcher mBroadcastDispatcher;
@@ -106,6 +109,10 @@
mBroadcastDispatcher = broadcastDispatcher;
mUserContextProvider = userContextProvider;
mUserTracker = userTracker;
+
+ BroadcastOptions options = BroadcastOptions.makeBasic();
+ options.setInteractive(true);
+ mInteractiveBroadcastOption = options.toBundle();
}
/** Create a dialog to show screen recording options to the user. */
@@ -148,7 +155,7 @@
cb.onCountdownEnd();
}
try {
- startIntent.send();
+ startIntent.send(mInteractiveBroadcastOption);
mUserTracker.addCallback(mUserChangedCallback, mMainExecutor);
IntentFilter stateFilter = new IntentFilter(INTENT_UPDATE_STATE);
@@ -202,7 +209,7 @@
public void stopRecording() {
try {
if (mStopIntent != null) {
- mStopIntent.send();
+ mStopIntent.send(mInteractiveBroadcastOption);
} else {
Log.e(TAG, "Stop intent was null");
}
diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/OverlayActionChip.java b/packages/SystemUI/src/com/android/systemui/screenshot/OverlayActionChip.java
index c4ea67e..860bfe37 100644
--- a/packages/SystemUI/src/com/android/systemui/screenshot/OverlayActionChip.java
+++ b/packages/SystemUI/src/com/android/systemui/screenshot/OverlayActionChip.java
@@ -18,6 +18,7 @@
import static java.util.Objects.requireNonNull;
+import android.app.BroadcastOptions;
import android.app.PendingIntent;
import android.content.Context;
import android.graphics.drawable.Icon;
@@ -96,7 +97,9 @@
public void setPendingIntent(PendingIntent intent, Runnable finisher) {
setOnClickListener(v -> {
try {
- intent.send();
+ BroadcastOptions options = BroadcastOptions.makeBasic();
+ options.setInteractive(true);
+ intent.send(options.toBundle());
finisher.run();
} catch (PendingIntent.CanceledException e) {
Log.e(TAG, "Intent cancelled", e);
diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/SaveImageInBackgroundTask.java b/packages/SystemUI/src/com/android/systemui/screenshot/SaveImageInBackgroundTask.java
index b4934cf..bf5fbd2 100644
--- a/packages/SystemUI/src/com/android/systemui/screenshot/SaveImageInBackgroundTask.java
+++ b/packages/SystemUI/src/com/android/systemui/screenshot/SaveImageInBackgroundTask.java
@@ -20,8 +20,7 @@
import static com.android.systemui.screenshot.LogConfig.DEBUG_CALLBACK;
import static com.android.systemui.screenshot.LogConfig.DEBUG_STORAGE;
import static com.android.systemui.screenshot.LogConfig.logTag;
-import static com.android.systemui.screenshot.ScreenshotNotificationSmartActionsProvider.ScreenshotSmartActionType.QUICK_SHARE_ACTION;
-import static com.android.systemui.screenshot.ScreenshotNotificationSmartActionsProvider.ScreenshotSmartActionType.REGULAR_SMART_ACTIONS;
+import static com.android.systemui.screenshot.ScreenshotNotificationSmartActionsProvider.ScreenshotSmartActionType;
import android.app.ActivityTaskManager;
import android.app.Notification;
@@ -155,7 +154,8 @@
CompletableFuture<List<Notification.Action>> smartActionsFuture =
mScreenshotSmartActions.getSmartActionsFuture(
- mScreenshotId, uri, image, mSmartActionsProvider, REGULAR_SMART_ACTIONS,
+ mScreenshotId, uri, image, mSmartActionsProvider,
+ ScreenshotSmartActionType.REGULAR_SMART_ACTIONS,
smartActionsEnabled, user);
List<Notification.Action> smartActions = new ArrayList<>();
if (smartActionsEnabled) {
@@ -166,7 +166,8 @@
smartActions.addAll(buildSmartActions(
mScreenshotSmartActions.getSmartActions(
mScreenshotId, smartActionsFuture, timeoutMs,
- mSmartActionsProvider, REGULAR_SMART_ACTIONS),
+ mSmartActionsProvider,
+ ScreenshotSmartActionType.REGULAR_SMART_ACTIONS),
mContext));
}
@@ -476,7 +477,7 @@
CompletableFuture<List<Notification.Action>> quickShareActionsFuture =
mScreenshotSmartActions.getSmartActionsFuture(
mScreenshotId, null, image, mSmartActionsProvider,
- QUICK_SHARE_ACTION,
+ ScreenshotSmartActionType.QUICK_SHARE_ACTION,
true /* smartActionsEnabled */, user);
int timeoutMs = DeviceConfig.getInt(
DeviceConfig.NAMESPACE_SYSTEMUI,
@@ -485,7 +486,8 @@
List<Notification.Action> quickShareActions =
mScreenshotSmartActions.getSmartActions(
mScreenshotId, quickShareActionsFuture, timeoutMs,
- mSmartActionsProvider, QUICK_SHARE_ACTION);
+ mSmartActionsProvider,
+ ScreenshotSmartActionType.QUICK_SHARE_ACTION);
if (!quickShareActions.isEmpty()) {
mQuickShareData.quickShareAction = quickShareActions.get(0);
mParams.mQuickShareActionsReadyListener.onActionsReady(mQuickShareData);
diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotController.java b/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotController.java
index 5716a1d72..b21a485 100644
--- a/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotController.java
+++ b/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotController.java
@@ -280,6 +280,7 @@
private final TimeoutHandler mScreenshotHandler;
private final ActionIntentExecutor mActionExecutor;
private final UserManager mUserManager;
+ private final WorkProfileMessageController mWorkProfileMessageController;
private final OnBackInvokedCallback mOnBackInvokedCallback = () -> {
if (DEBUG_INPUT) {
@@ -326,7 +327,8 @@
BroadcastSender broadcastSender,
ScreenshotNotificationSmartActionsProvider screenshotNotificationSmartActionsProvider,
ActionIntentExecutor actionExecutor,
- UserManager userManager
+ UserManager userManager,
+ WorkProfileMessageController workProfileMessageController
) {
mScreenshotSmartActions = screenshotSmartActions;
mNotificationsController = screenshotNotificationsController;
@@ -358,6 +360,7 @@
mFlags = flags;
mActionExecutor = actionExecutor;
mUserManager = userManager;
+ mWorkProfileMessageController = workProfileMessageController;
mAccessibilityManager = AccessibilityManager.getInstance(mContext);
@@ -683,10 +686,9 @@
return true;
}
});
-
if (mFlags.isEnabled(SCREENSHOT_WORK_PROFILE_POLICY)) {
- mScreenshotView.badgeScreenshot(
- mContext.getPackageManager().getUserBadgeForDensity(owner, 0));
+ mScreenshotView.badgeScreenshot(mContext.getPackageManager().getUserBadgedIcon(
+ mContext.getDrawable(R.drawable.overlay_badge_background), owner));
}
mScreenshotView.setScreenshot(mScreenBitmap, screenInsets);
if (DEBUG_WINDOW) {
@@ -784,9 +786,9 @@
mLongScreenshotHolder.setLongScreenshot(longScreenshot);
mLongScreenshotHolder.setTransitionDestinationCallback(
(transitionDestination, onTransitionEnd) -> {
- mScreenshotView.startLongScreenshotTransition(
- transitionDestination, onTransitionEnd,
- longScreenshot);
+ mScreenshotView.startLongScreenshotTransition(
+ transitionDestination, onTransitionEnd,
+ longScreenshot);
// TODO: Do this via ActionIntentExecutor instead.
mContext.sendBroadcast(new Intent(Intent.ACTION_CLOSE_SYSTEM_DIALOGS));
}
@@ -1037,10 +1039,8 @@
private void doPostAnimation(ScreenshotController.SavedImageData imageData) {
mScreenshotView.setChipIntents(imageData);
- if (mFlags.isEnabled(SCREENSHOT_WORK_PROFILE_POLICY)
- && mUserManager.isManagedProfile(imageData.owner.getIdentifier())) {
- // TODO: Read app from configuration
- mScreenshotView.showWorkProfileMessage("Files");
+ if (mFlags.isEnabled(SCREENSHOT_WORK_PROFILE_POLICY)) {
+ mWorkProfileMessageController.onScreenshotTaken(imageData.owner, mScreenshotView);
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotView.java b/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotView.java
index e8ceb52..7c013a8 100644
--- a/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotView.java
+++ b/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotView.java
@@ -33,7 +33,9 @@
import android.animation.AnimatorListenerAdapter;
import android.animation.AnimatorSet;
import android.animation.ValueAnimator;
+import android.annotation.Nullable;
import android.app.ActivityManager;
+import android.app.BroadcastOptions;
import android.app.Notification;
import android.app.PendingIntent;
import android.content.Context;
@@ -53,6 +55,7 @@
import android.graphics.drawable.Icon;
import android.graphics.drawable.InsetDrawable;
import android.graphics.drawable.LayerDrawable;
+import android.os.Bundle;
import android.os.Looper;
import android.os.RemoteException;
import android.util.AttributeSet;
@@ -100,7 +103,8 @@
* Handles the visual elements and animations for the screenshot flow.
*/
public class ScreenshotView extends FrameLayout implements
- ViewTreeObserver.OnComputeInternalInsetsListener {
+ ViewTreeObserver.OnComputeInternalInsetsListener,
+ WorkProfileMessageController.WorkProfileMessageDisplay {
interface ScreenshotViewCallback {
void onUserInteraction();
@@ -169,6 +173,7 @@
private long mDefaultTimeoutOfTimeoutHandler;
private ActionIntentExecutor mActionExecutor;
private FeatureFlags mFlags;
+ private final Bundle mInteractiveBroadcastOption;
private enum PendingInteraction {
PREVIEW,
@@ -195,6 +200,10 @@
mResources = mContext.getResources();
mInteractionJankMonitor = getInteractionJankMonitorInstance();
+ BroadcastOptions options = BroadcastOptions.makeBasic();
+ options.setInteractive(true);
+ mInteractiveBroadcastOption = options.toBundle();
+
mFixedSize = mResources.getDimensionPixelSize(R.dimen.overlay_x_scale);
// standard material ease
@@ -351,13 +360,23 @@
* been taken and which app can be used to view it.
*
* @param appName The name of the app to use to view screenshots
+ * @param appIcon Optional icon for the relevant files app
+ * @param onDismiss Runnable to be run when the user dismisses this message
*/
- void showWorkProfileMessage(String appName) {
+ @Override
+ public void showWorkProfileMessage(CharSequence appName, @Nullable Drawable appIcon,
+ Runnable onDismiss) {
+ if (appIcon != null) {
+ // Replace the default icon if one is provided.
+ ImageView imageView = mMessageContainer.findViewById(R.id.screenshot_message_icon);
+ imageView.setImageDrawable(appIcon);
+ }
mMessageContent.setText(
mContext.getString(R.string.screenshot_work_profile_notification, appName));
mMessageContainer.setVisibility(VISIBLE);
mMessageContainer.findViewById(R.id.message_dismiss_button).setOnClickListener((v) -> {
mMessageContainer.setVisibility(View.GONE);
+ onDismiss.run();
});
}
@@ -1078,7 +1097,7 @@
mScreenshotBadge.setVisibility(View.GONE);
mScreenshotBadge.setImageDrawable(null);
mPendingSharedTransition = false;
- mActionsContainerBackground.setVisibility(View.GONE);
+ mActionsContainerBackground.setVisibility(View.INVISIBLE);
mActionsContainer.setVisibility(View.GONE);
mDismissButton.setVisibility(View.GONE);
mScrollingScrim.setVisibility(View.GONE);
@@ -1105,7 +1124,7 @@
private void startSharedTransition(ActionTransition transition) {
try {
mPendingSharedTransition = true;
- transition.action.actionIntent.send();
+ transition.action.actionIntent.send(mInteractiveBroadcastOption);
// fade out non-preview UI
createScreenshotFadeDismissAnimation().start();
diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/TakeScreenshotService.java b/packages/SystemUI/src/com/android/systemui/screenshot/TakeScreenshotService.java
index 2176825..35e9f3e 100644
--- a/packages/SystemUI/src/com/android/systemui/screenshot/TakeScreenshotService.java
+++ b/packages/SystemUI/src/com/android/systemui/screenshot/TakeScreenshotService.java
@@ -21,7 +21,6 @@
import static com.android.internal.util.ScreenshotHelper.SCREENSHOT_MSG_PROCESS_COMPLETE;
import static com.android.internal.util.ScreenshotHelper.SCREENSHOT_MSG_URI;
-import static com.android.systemui.flags.Flags.SCREENSHOT_REQUEST_PROCESSOR;
import static com.android.systemui.flags.Flags.SCREENSHOT_WORK_PROFILE_POLICY;
import static com.android.systemui.screenshot.LogConfig.DEBUG_CALLBACK;
import static com.android.systemui.screenshot.LogConfig.DEBUG_DISMISS;
@@ -122,7 +121,6 @@
mContext = context;
mBgExecutor = bgExecutor;
mFeatureFlags = featureFlags;
- mFeatureFlags.addListener(SCREENSHOT_REQUEST_PROCESSOR, FlagEvent::requestNoRestart);
mFeatureFlags.addListener(SCREENSHOT_WORK_PROFILE_POLICY, FlagEvent::requestNoRestart);
mProcessor = processor;
}
@@ -224,14 +222,8 @@
return;
}
- if (mFeatureFlags.isEnabled(SCREENSHOT_REQUEST_PROCESSOR)) {
- Log.d(TAG, "handleMessage: Using request processor");
- mProcessor.processAsync(request,
- (r) -> dispatchToController(r, onSaved, callback));
- return;
- }
-
- dispatchToController(request, onSaved, callback);
+ mProcessor.processAsync(request,
+ (r) -> dispatchToController(r, onSaved, callback));
}
private void dispatchToController(ScreenshotHelper.ScreenshotRequest request,
diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/WorkProfileMessageController.kt b/packages/SystemUI/src/com/android/systemui/screenshot/WorkProfileMessageController.kt
new file mode 100644
index 0000000..5d7e56f
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/screenshot/WorkProfileMessageController.kt
@@ -0,0 +1,106 @@
+/*
+ * 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 com.android.systemui.screenshot
+
+import android.content.ComponentName
+import android.content.Context
+import android.content.pm.PackageManager
+import android.graphics.drawable.Drawable
+import android.os.UserHandle
+import android.os.UserManager
+import android.util.Log
+import com.android.systemui.R
+import javax.inject.Inject
+
+/**
+ * Handles all the non-UI portions of the work profile first run:
+ * - Track whether the user has already dismissed it.
+ * - Load the proper icon and app name.
+ */
+class WorkProfileMessageController
+@Inject
+constructor(
+ private val context: Context,
+ private val userManager: UserManager,
+ private val packageManager: PackageManager,
+) {
+
+ /**
+ * Determine if a message should be shown to the user, send message details to messageDisplay if
+ * appropriate.
+ */
+ fun onScreenshotTaken(userHandle: UserHandle, messageDisplay: WorkProfileMessageDisplay) {
+ if (userManager.isManagedProfile(userHandle.identifier) && !messageAlreadyDismissed()) {
+ var badgedIcon: Drawable? = null
+ var label: CharSequence? = null
+ val fileManager = fileManagerComponentName()
+ try {
+ val info =
+ packageManager.getActivityInfo(
+ fileManager,
+ PackageManager.ComponentInfoFlags.of(0)
+ )
+ val icon = packageManager.getActivityIcon(fileManager)
+ badgedIcon = packageManager.getUserBadgedIcon(icon, userHandle)
+ label = info.loadLabel(packageManager)
+ } catch (e: PackageManager.NameNotFoundException) {
+ Log.w(TAG, "Component $fileManager not found")
+ }
+
+ // If label wasn't loaded, use a default
+ val badgedLabel =
+ packageManager.getUserBadgedLabel(label ?: defaultFileAppName(), userHandle)
+
+ messageDisplay.showWorkProfileMessage(badgedLabel, badgedIcon) { onMessageDismissed() }
+ }
+ }
+
+ private fun messageAlreadyDismissed(): Boolean {
+ return sharedPreference().getBoolean(PREFERENCE_KEY, false)
+ }
+
+ private fun onMessageDismissed() {
+ val editor = sharedPreference().edit()
+ editor.putBoolean(PREFERENCE_KEY, true)
+ editor.apply()
+ }
+
+ private fun sharedPreference() =
+ context.getSharedPreferences(SHARED_PREFERENCES_NAME, Context.MODE_PRIVATE)
+
+ private fun fileManagerComponentName() =
+ ComponentName.unflattenFromString(
+ context.getString(R.string.config_sceenshotWorkProfileFilesApp)
+ )
+
+ private fun defaultFileAppName() = context.getString(R.string.screenshot_default_files_app_name)
+
+ /** UI that can show work profile messages (ScreenshotView in practice) */
+ interface WorkProfileMessageDisplay {
+ /**
+ * Show the given message and icon, calling onDismiss if the user explicitly dismisses the
+ * message.
+ */
+ fun showWorkProfileMessage(text: CharSequence, icon: Drawable?, onDismiss: Runnable)
+ }
+
+ companion object {
+ const val TAG = "WorkProfileMessageCtrl"
+ const val SHARED_PREFERENCES_NAME = "com.android.systemui.screenshot"
+ const val PREFERENCE_KEY = "work_profile_first_run"
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/settings/UserTrackerImpl.kt b/packages/SystemUI/src/com/android/systemui/settings/UserTrackerImpl.kt
index 200288b..4dbe099 100644
--- a/packages/SystemUI/src/com/android/systemui/settings/UserTrackerImpl.kt
+++ b/packages/SystemUI/src/com/android/systemui/settings/UserTrackerImpl.kt
@@ -111,7 +111,7 @@
// These get called when a managed profile goes in or out of quiet mode.
addAction(Intent.ACTION_MANAGED_PROFILE_AVAILABLE)
addAction(Intent.ACTION_MANAGED_PROFILE_UNAVAILABLE)
-
+ addAction(Intent.ACTION_MANAGED_PROFILE_ADDED)
addAction(Intent.ACTION_MANAGED_PROFILE_REMOVED)
addAction(Intent.ACTION_MANAGED_PROFILE_UNLOCKED)
}
@@ -128,6 +128,7 @@
Intent.ACTION_USER_INFO_CHANGED,
Intent.ACTION_MANAGED_PROFILE_AVAILABLE,
Intent.ACTION_MANAGED_PROFILE_UNAVAILABLE,
+ Intent.ACTION_MANAGED_PROFILE_ADDED,
Intent.ACTION_MANAGED_PROFILE_REMOVED,
Intent.ACTION_MANAGED_PROFILE_UNLOCKED -> {
handleProfilesChanged()
diff --git a/packages/SystemUI/src/com/android/systemui/shade/LargeScreenShadeHeaderController.kt b/packages/SystemUI/src/com/android/systemui/shade/LargeScreenShadeHeaderController.kt
index 7fc0a5f..e406be1 100644
--- a/packages/SystemUI/src/com/android/systemui/shade/LargeScreenShadeHeaderController.kt
+++ b/packages/SystemUI/src/com/android/systemui/shade/LargeScreenShadeHeaderController.kt
@@ -175,9 +175,10 @@
*/
var shadeExpandedFraction = -1f
set(value) {
- if (visible && field != value) {
+ if (field != value) {
header.alpha = ShadeInterpolation.getContentAlpha(value)
field = value
+ updateVisibility()
}
}
@@ -331,6 +332,9 @@
.setDuration(duration)
.alpha(if (show) 0f else 1f)
.setInterpolator(if (show) Interpolators.ALPHA_OUT else Interpolators.ALPHA_IN)
+ .setUpdateListener {
+ updateVisibility()
+ }
.start()
}
@@ -414,7 +418,7 @@
private fun updateVisibility() {
val visibility = if (!largeScreenActive && !combinedHeaders || qsDisabled) {
View.GONE
- } else if (qsVisible) {
+ } else if (qsVisible && header.alpha > 0f) {
View.VISIBLE
} else {
View.INVISIBLE
diff --git a/packages/SystemUI/src/com/android/systemui/shade/NotificationPanelViewController.java b/packages/SystemUI/src/com/android/systemui/shade/NotificationPanelViewController.java
index d711d15..964d0b2 100644
--- a/packages/SystemUI/src/com/android/systemui/shade/NotificationPanelViewController.java
+++ b/packages/SystemUI/src/com/android/systemui/shade/NotificationPanelViewController.java
@@ -144,7 +144,10 @@
import com.android.systemui.keyguard.shared.model.TransitionState;
import com.android.systemui.keyguard.shared.model.TransitionStep;
import com.android.systemui.keyguard.ui.viewmodel.DreamingToLockscreenTransitionViewModel;
+import com.android.systemui.keyguard.ui.viewmodel.GoneToDreamingTransitionViewModel;
import com.android.systemui.keyguard.ui.viewmodel.KeyguardBottomAreaViewModel;
+import com.android.systemui.keyguard.ui.viewmodel.LockscreenToDreamingTransitionViewModel;
+import com.android.systemui.keyguard.ui.viewmodel.LockscreenToOccludedTransitionViewModel;
import com.android.systemui.keyguard.ui.viewmodel.OccludedToLockscreenTransitionViewModel;
import com.android.systemui.media.controls.pipeline.MediaDataManager;
import com.android.systemui.media.controls.ui.KeyguardMediaController;
@@ -689,12 +692,18 @@
private boolean mExpandLatencyTracking;
private DreamingToLockscreenTransitionViewModel mDreamingToLockscreenTransitionViewModel;
private OccludedToLockscreenTransitionViewModel mOccludedToLockscreenTransitionViewModel;
+ private LockscreenToDreamingTransitionViewModel mLockscreenToDreamingTransitionViewModel;
+ private GoneToDreamingTransitionViewModel mGoneToDreamingTransitionViewModel;
+ private LockscreenToOccludedTransitionViewModel mLockscreenToOccludedTransitionViewModel;
private KeyguardTransitionInteractor mKeyguardTransitionInteractor;
private CoroutineDispatcher mMainDispatcher;
- private boolean mIsToLockscreenTransitionRunning = false;
+ private boolean mIsOcclusionTransitionRunning = false;
private int mDreamingToLockscreenTransitionTranslationY;
private int mOccludedToLockscreenTransitionTranslationY;
+ private int mLockscreenToDreamingTransitionTranslationY;
+ private int mGoneToDreamingTransitionTranslationY;
+ private int mLockscreenToOccludedTransitionTranslationY;
private boolean mUnocclusionTransitionFlagEnabled = false;
private final Runnable mFlingCollapseRunnable = () -> fling(0, false /* expand */,
@@ -713,13 +722,31 @@
private final Consumer<TransitionStep> mDreamingToLockscreenTransition =
(TransitionStep step) -> {
- mIsToLockscreenTransitionRunning =
+ mIsOcclusionTransitionRunning =
step.getTransitionState() == TransitionState.RUNNING;
};
private final Consumer<TransitionStep> mOccludedToLockscreenTransition =
(TransitionStep step) -> {
- mIsToLockscreenTransitionRunning =
+ mIsOcclusionTransitionRunning =
+ step.getTransitionState() == TransitionState.RUNNING;
+ };
+
+ private final Consumer<TransitionStep> mLockscreenToDreamingTransition =
+ (TransitionStep step) -> {
+ mIsOcclusionTransitionRunning =
+ step.getTransitionState() == TransitionState.RUNNING;
+ };
+
+ private final Consumer<TransitionStep> mGoneToDreamingTransition =
+ (TransitionStep step) -> {
+ mIsOcclusionTransitionRunning =
+ step.getTransitionState() == TransitionState.RUNNING;
+ };
+
+ private final Consumer<TransitionStep> mLockscreenToOccludedTransition =
+ (TransitionStep step) -> {
+ mIsOcclusionTransitionRunning =
step.getTransitionState() == TransitionState.RUNNING;
};
@@ -794,6 +821,9 @@
AlternateBouncerInteractor alternateBouncerInteractor,
DreamingToLockscreenTransitionViewModel dreamingToLockscreenTransitionViewModel,
OccludedToLockscreenTransitionViewModel occludedToLockscreenTransitionViewModel,
+ LockscreenToDreamingTransitionViewModel lockscreenToDreamingTransitionViewModel,
+ GoneToDreamingTransitionViewModel goneToDreamingTransitionViewModel,
+ LockscreenToOccludedTransitionViewModel lockscreenToOccludedTransitionViewModel,
@Main CoroutineDispatcher mainDispatcher,
KeyguardTransitionInteractor keyguardTransitionInteractor,
DumpManager dumpManager) {
@@ -813,6 +843,9 @@
mGutsManager = gutsManager;
mDreamingToLockscreenTransitionViewModel = dreamingToLockscreenTransitionViewModel;
mOccludedToLockscreenTransitionViewModel = occludedToLockscreenTransitionViewModel;
+ mLockscreenToDreamingTransitionViewModel = lockscreenToDreamingTransitionViewModel;
+ mGoneToDreamingTransitionViewModel = goneToDreamingTransitionViewModel;
+ mLockscreenToOccludedTransitionViewModel = lockscreenToOccludedTransitionViewModel;
mKeyguardTransitionInteractor = keyguardTransitionInteractor;
mView.addOnAttachStateChangeListener(new View.OnAttachStateChangeListener() {
@Override
@@ -1121,22 +1154,55 @@
collectFlow(mView, mKeyguardTransitionInteractor.getDreamingToLockscreenTransition(),
mDreamingToLockscreenTransition, mMainDispatcher);
collectFlow(mView, mDreamingToLockscreenTransitionViewModel.getLockscreenAlpha(),
- toLockscreenTransitionAlpha(mNotificationStackScrollLayoutController),
+ setTransitionAlpha(mNotificationStackScrollLayoutController),
mMainDispatcher);
collectFlow(mView, mDreamingToLockscreenTransitionViewModel.lockscreenTranslationY(
mDreamingToLockscreenTransitionTranslationY),
- toLockscreenTransitionY(mNotificationStackScrollLayoutController),
+ setTransitionY(mNotificationStackScrollLayoutController),
mMainDispatcher);
// Occluded->Lockscreen
collectFlow(mView, mKeyguardTransitionInteractor.getOccludedToLockscreenTransition(),
mOccludedToLockscreenTransition, mMainDispatcher);
collectFlow(mView, mOccludedToLockscreenTransitionViewModel.getLockscreenAlpha(),
- toLockscreenTransitionAlpha(mNotificationStackScrollLayoutController),
+ setTransitionAlpha(mNotificationStackScrollLayoutController),
mMainDispatcher);
collectFlow(mView, mOccludedToLockscreenTransitionViewModel.lockscreenTranslationY(
mOccludedToLockscreenTransitionTranslationY),
- toLockscreenTransitionY(mNotificationStackScrollLayoutController),
+ setTransitionY(mNotificationStackScrollLayoutController),
+ mMainDispatcher);
+
+ // Lockscreen->Dreaming
+ collectFlow(mView, mKeyguardTransitionInteractor.getLockscreenToDreamingTransition(),
+ mLockscreenToDreamingTransition, mMainDispatcher);
+ collectFlow(mView, mLockscreenToDreamingTransitionViewModel.getLockscreenAlpha(),
+ setTransitionAlpha(mNotificationStackScrollLayoutController),
+ mMainDispatcher);
+ collectFlow(mView, mLockscreenToDreamingTransitionViewModel.lockscreenTranslationY(
+ mLockscreenToDreamingTransitionTranslationY),
+ setTransitionY(mNotificationStackScrollLayoutController),
+ mMainDispatcher);
+
+ // Gone->Dreaming
+ collectFlow(mView, mKeyguardTransitionInteractor.getGoneToDreamingTransition(),
+ mGoneToDreamingTransition, mMainDispatcher);
+ collectFlow(mView, mGoneToDreamingTransitionViewModel.getLockscreenAlpha(),
+ setTransitionAlpha(mNotificationStackScrollLayoutController),
+ mMainDispatcher);
+ collectFlow(mView, mGoneToDreamingTransitionViewModel.lockscreenTranslationY(
+ mGoneToDreamingTransitionTranslationY),
+ setTransitionY(mNotificationStackScrollLayoutController),
+ mMainDispatcher);
+
+ // Lockscreen->Occluded
+ collectFlow(mView, mKeyguardTransitionInteractor.getLockscreenToOccludedTransition(),
+ mLockscreenToOccludedTransition, mMainDispatcher);
+ collectFlow(mView, mLockscreenToOccludedTransitionViewModel.getLockscreenAlpha(),
+ setTransitionAlpha(mNotificationStackScrollLayoutController),
+ mMainDispatcher);
+ collectFlow(mView, mLockscreenToOccludedTransitionViewModel.lockscreenTranslationY(
+ mLockscreenToOccludedTransitionTranslationY),
+ setTransitionY(mNotificationStackScrollLayoutController),
mMainDispatcher);
}
}
@@ -1177,6 +1243,12 @@
R.dimen.dreaming_to_lockscreen_transition_lockscreen_translation_y);
mOccludedToLockscreenTransitionTranslationY = mResources.getDimensionPixelSize(
R.dimen.occluded_to_lockscreen_transition_lockscreen_translation_y);
+ mLockscreenToDreamingTransitionTranslationY = mResources.getDimensionPixelSize(
+ R.dimen.lockscreen_to_dreaming_transition_lockscreen_translation_y);
+ mGoneToDreamingTransitionTranslationY = mResources.getDimensionPixelSize(
+ R.dimen.gone_to_dreaming_transition_lockscreen_translation_y);
+ mLockscreenToOccludedTransitionTranslationY = mResources.getDimensionPixelSize(
+ R.dimen.lockscreen_to_occluded_transition_lockscreen_translation_y);
}
private void updateViewControllers(KeyguardStatusView keyguardStatusView,
@@ -1840,7 +1912,7 @@
}
private void updateClock() {
- if (mIsToLockscreenTransitionRunning) {
+ if (mIsOcclusionTransitionRunning) {
return;
}
float alpha = mClockPositionResult.clockAlpha * mKeyguardOnlyContentAlpha;
@@ -2292,7 +2364,7 @@
// When false, down but not synthesized motion event.
mLastEventSynthesizedDown = mExpectingSynthesizedDown;
mLastDownEvents.insert(
- mSystemClock.currentTimeMillis(),
+ event.getEventTime(),
mDownX,
mDownY,
mQsTouchAboveFalsingThreshold,
@@ -2425,7 +2497,7 @@
mInitialTouchY = event.getY();
mInitialTouchX = event.getX();
}
- if (!isFullyCollapsed()) {
+ if (!isFullyCollapsed() && !isShadeOrQsHeightAnimationRunning()) {
handleQsDown(event);
}
// defer touches on QQS to shade while shade is collapsing. Added margin for error
@@ -2731,7 +2803,7 @@
} else if (statusBarState == KEYGUARD
|| statusBarState == StatusBarState.SHADE_LOCKED) {
mKeyguardBottomArea.setVisibility(View.VISIBLE);
- if (!mIsToLockscreenTransitionRunning) {
+ if (!mIsOcclusionTransitionRunning) {
mKeyguardBottomArea.setAlpha(1f);
}
} else {
@@ -3600,7 +3672,7 @@
}
private void updateNotificationTranslucency() {
- if (mIsToLockscreenTransitionRunning) {
+ if (mIsOcclusionTransitionRunning) {
return;
}
float alpha = 1f;
@@ -3658,7 +3730,7 @@
}
private void updateKeyguardBottomAreaAlpha() {
- if (mIsToLockscreenTransitionRunning) {
+ if (mIsOcclusionTransitionRunning) {
return;
}
// There are two possible panel expansion behaviors:
@@ -5215,6 +5287,11 @@
}
}
+ /** Returns whether a shade or QS expansion animation is running */
+ private boolean isShadeOrQsHeightAnimationRunning() {
+ return mHeightAnimator != null && !mHintAnimationRunning && !mIsSpringBackAnimation;
+ }
+
/**
* Phase 2: Bounce down.
*/
@@ -5890,7 +5967,7 @@
mCurrentPanelState = state;
}
- private Consumer<Float> toLockscreenTransitionAlpha(
+ private Consumer<Float> setTransitionAlpha(
NotificationStackScrollLayoutController stackScroller) {
return (Float alpha) -> {
mKeyguardStatusViewController.setAlpha(alpha);
@@ -5908,7 +5985,7 @@
};
}
- private Consumer<Float> toLockscreenTransitionY(
+ private Consumer<Float> setTransitionY(
NotificationStackScrollLayoutController stackScroller) {
return (Float translationY) -> {
mKeyguardStatusViewController.setTranslationY(translationY, /* excludeMedia= */false);
@@ -6232,8 +6309,7 @@
mCollapsedAndHeadsUpOnDown =
isFullyCollapsed() && mHeadsUpManager.hasPinnedHeadsUp();
addMovement(event);
- boolean regularHeightAnimationRunning = mHeightAnimator != null
- && !mHintAnimationRunning && !mIsSpringBackAnimation;
+ boolean regularHeightAnimationRunning = isShadeOrQsHeightAnimationRunning();
if (!mGestureWaitForTouchSlop || regularHeightAnimationRunning) {
mTouchSlopExceeded = regularHeightAnimationRunning
|| mTouchSlopExceededBeforeDown;
diff --git a/packages/SystemUI/src/com/android/systemui/shade/NotificationShadeWindowControllerImpl.java b/packages/SystemUI/src/com/android/systemui/shade/NotificationShadeWindowControllerImpl.java
index 8314ec7..26f8b62 100644
--- a/packages/SystemUI/src/com/android/systemui/shade/NotificationShadeWindowControllerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/shade/NotificationShadeWindowControllerImpl.java
@@ -321,9 +321,12 @@
&& !state.mKeyguardFadingAway && !state.mKeyguardGoingAway;
if (onKeyguard
&& mAuthController.isUdfpsEnrolled(KeyguardUpdateMonitor.getCurrentUser())) {
+ // both max and min display refresh rate must be set to take effect:
mLpChanged.preferredMaxDisplayRefreshRate = mKeyguardPreferredRefreshRate;
+ mLpChanged.preferredMinDisplayRefreshRate = mKeyguardPreferredRefreshRate;
} else {
mLpChanged.preferredMaxDisplayRefreshRate = 0;
+ mLpChanged.preferredMinDisplayRefreshRate = 0;
}
Trace.setCounter("display_set_preferred_refresh_rate",
(long) mKeyguardPreferredRefreshRate);
diff --git a/packages/SystemUI/src/com/android/systemui/shade/NotificationShadeWindowViewController.java b/packages/SystemUI/src/com/android/systemui/shade/NotificationShadeWindowViewController.java
index 64b6e61..7ed6e3e 100644
--- a/packages/SystemUI/src/com/android/systemui/shade/NotificationShadeWindowViewController.java
+++ b/packages/SystemUI/src/com/android/systemui/shade/NotificationShadeWindowViewController.java
@@ -16,6 +16,8 @@
package com.android.systemui.shade;
+import static com.android.systemui.util.kotlin.JavaAdapterKt.collectFlow;
+
import android.app.StatusBarManager;
import android.media.AudioManager;
import android.media.session.MediaSessionLegacyHelper;
@@ -40,6 +42,9 @@
import com.android.systemui.flags.Flags;
import com.android.systemui.keyguard.KeyguardUnlockAnimationController;
import com.android.systemui.keyguard.domain.interactor.AlternateBouncerInteractor;
+import com.android.systemui.keyguard.domain.interactor.KeyguardTransitionInteractor;
+import com.android.systemui.keyguard.shared.model.TransitionState;
+import com.android.systemui.keyguard.shared.model.TransitionStep;
import com.android.systemui.keyguard.ui.binder.KeyguardBouncerViewBinder;
import com.android.systemui.keyguard.ui.viewmodel.KeyguardBouncerViewModel;
import com.android.systemui.statusbar.DragDownHelper;
@@ -58,6 +63,7 @@
import com.android.systemui.statusbar.window.StatusBarWindowStateController;
import java.io.PrintWriter;
+import java.util.function.Consumer;
import javax.inject.Inject;
@@ -98,6 +104,13 @@
private final ShadeExpansionStateManager mShadeExpansionStateManager;
private boolean mIsTrackingBarGesture = false;
+ private boolean mIsOcclusionTransitionRunning = false;
+
+ private final Consumer<TransitionStep> mLockscreenToDreamingTransition =
+ (TransitionStep step) -> {
+ mIsOcclusionTransitionRunning =
+ step.getTransitionState() == TransitionState.RUNNING;
+ };
@Inject
public NotificationShadeWindowViewController(
@@ -122,7 +135,8 @@
FeatureFlags featureFlags,
KeyguardBouncerViewModel keyguardBouncerViewModel,
KeyguardBouncerComponent.Factory keyguardBouncerComponentFactory,
- AlternateBouncerInteractor alternateBouncerInteractor
+ AlternateBouncerInteractor alternateBouncerInteractor,
+ KeyguardTransitionInteractor keyguardTransitionInteractor
) {
mLockscreenShadeTransitionController = transitionController;
mFalsingCollector = falsingCollector;
@@ -152,6 +166,11 @@
keyguardBouncerViewModel,
keyguardBouncerComponentFactory);
}
+
+ if (featureFlags.isEnabled(Flags.UNOCCLUSION_TRANSITION)) {
+ collectFlow(mView, keyguardTransitionInteractor.getLockscreenToDreamingTransition(),
+ mLockscreenToDreamingTransition);
+ }
}
/**
@@ -219,6 +238,10 @@
return true;
}
+ if (mIsOcclusionTransitionRunning) {
+ return false;
+ }
+
mFalsingCollector.onTouchEvent(ev);
mPulsingWakeupGestureHandler.onTouchEvent(ev);
mStatusBarKeyguardViewManager.onTouch(ev);
diff --git a/packages/SystemUI/src/com/android/systemui/shade/ShadeLogger.kt b/packages/SystemUI/src/com/android/systemui/shade/ShadeLogger.kt
index 5fedbeb..11617be 100644
--- a/packages/SystemUI/src/com/android/systemui/shade/ShadeLogger.kt
+++ b/packages/SystemUI/src/com/android/systemui/shade/ShadeLogger.kt
@@ -36,16 +36,9 @@
buffer.log(TAG, LogLevel.DEBUG, msg)
}
- private inline fun log(
- logLevel: LogLevel,
- initializer: LogMessage.() -> Unit,
- noinline printer: LogMessage.() -> String
- ) {
- buffer.log(TAG, logLevel, initializer, printer)
- }
-
fun onQsInterceptMoveQsTrackingEnabled(h: Float) {
- log(
+ buffer.log(
+ TAG,
LogLevel.VERBOSE,
{ double1 = h.toDouble() },
{ "onQsIntercept: move action, QS tracking enabled. h = $double1" }
@@ -62,7 +55,8 @@
keyguardShowing: Boolean,
qsExpansionEnabled: Boolean
) {
- log(
+ buffer.log(
+ TAG,
LogLevel.VERBOSE,
{
int1 = initialTouchY.toInt()
@@ -82,7 +76,8 @@
}
fun logMotionEvent(event: MotionEvent, message: String) {
- log(
+ buffer.log(
+ TAG,
LogLevel.VERBOSE,
{
str1 = message
@@ -99,7 +94,8 @@
}
fun logMotionEventStatusBarState(event: MotionEvent, statusBarState: Int, message: String) {
- log(
+ buffer.log(
+ TAG,
LogLevel.VERBOSE,
{
str1 = message
@@ -128,25 +124,33 @@
tracking: Boolean,
dragDownPxAmount: Float,
) {
- log(LogLevel.VERBOSE, {
- str1 = message
- double1 = fraction.toDouble()
- bool1 = expanded
- bool2 = tracking
- long1 = dragDownPxAmount.toLong()
- }, {
- "$str1 fraction=$double1,expanded=$bool1," +
+ buffer.log(
+ TAG,
+ LogLevel.VERBOSE,
+ {
+ str1 = message
+ double1 = fraction.toDouble()
+ bool1 = expanded
+ bool2 = tracking
+ long1 = dragDownPxAmount.toLong()
+ },
+ {
+ "$str1 fraction=$double1,expanded=$bool1," +
"tracking=$bool2," + "dragDownPxAmount=$dragDownPxAmount"
- })
+ }
+ )
}
fun logHasVibrated(hasVibratedOnOpen: Boolean, fraction: Float) {
- log(LogLevel.VERBOSE, {
- bool1 = hasVibratedOnOpen
- double1 = fraction.toDouble()
- }, {
- "hasVibratedOnOpen=$bool1, expansionFraction=$double1"
- })
+ buffer.log(
+ TAG,
+ LogLevel.VERBOSE,
+ {
+ bool1 = hasVibratedOnOpen
+ double1 = fraction.toDouble()
+ },
+ { "hasVibratedOnOpen=$bool1, expansionFraction=$double1" }
+ )
}
fun logQsExpansionChanged(
@@ -159,42 +163,56 @@
qsAnimatorExpand: Boolean,
animatingQs: Boolean
) {
- log(LogLevel.VERBOSE, {
- str1 = message
- bool1 = qsExpanded
- int1 = qsMinExpansionHeight
- int2 = qsMaxExpansionHeight
- bool2 = stackScrollerOverscrolling
- bool3 = dozing
- bool4 = qsAnimatorExpand
- // 0 = false, 1 = true
- long1 = animatingQs.compareTo(false).toLong()
- }, {
- "$str1 qsExpanded=$bool1,qsMinExpansionHeight=$int1,qsMaxExpansionHeight=$int2," +
+ buffer.log(
+ TAG,
+ LogLevel.VERBOSE,
+ {
+ str1 = message
+ bool1 = qsExpanded
+ int1 = qsMinExpansionHeight
+ int2 = qsMaxExpansionHeight
+ bool2 = stackScrollerOverscrolling
+ bool3 = dozing
+ bool4 = qsAnimatorExpand
+ // 0 = false, 1 = true
+ long1 = animatingQs.compareTo(false).toLong()
+ },
+ {
+ "$str1 qsExpanded=$bool1,qsMinExpansionHeight=$int1,qsMaxExpansionHeight=$int2," +
"stackScrollerOverscrolling=$bool2,dozing=$bool3,qsAnimatorExpand=$bool4," +
"animatingQs=$long1"
- })
+ }
+ )
}
fun logSingleTapUp(isDozing: Boolean, singleTapEnabled: Boolean, isNotDocked: Boolean) {
- log(LogLevel.DEBUG, {
- bool1 = isDozing
- bool2 = singleTapEnabled
- bool3 = isNotDocked
- }, {
- "PulsingGestureListener#onSingleTapUp all of this must true for single " +
- "tap to be detected: isDozing: $bool1, singleTapEnabled: $bool2, isNotDocked: $bool3"
+ buffer.log(
+ TAG,
+ LogLevel.DEBUG,
+ {
+ bool1 = isDozing
+ bool2 = singleTapEnabled
+ bool3 = isNotDocked
+ },
+ {
+ "PulsingGestureListener#onSingleTapUp all of this must true for single " +
+ "tap to be detected: isDozing: $bool1, singleTapEnabled: $bool2, isNotDocked: $bool3"
})
}
fun logSingleTapUpFalsingState(proximityIsNotNear: Boolean, isNotFalseTap: Boolean) {
- log(LogLevel.DEBUG, {
- bool1 = proximityIsNotNear
- bool2 = isNotFalseTap
- }, {
- "PulsingGestureListener#onSingleTapUp all of this must true for single " +
+ buffer.log(
+ TAG,
+ LogLevel.DEBUG,
+ {
+ bool1 = proximityIsNotNear
+ bool2 = isNotFalseTap
+ },
+ {
+ "PulsingGestureListener#onSingleTapUp all of this must true for single " +
"tap to be detected: proximityIsNotNear: $bool1, isNotFalseTap: $bool2"
- })
+ }
+ )
}
fun logNotInterceptingTouchInstantExpanding(
@@ -202,13 +220,18 @@
notificationsDragEnabled: Boolean,
touchDisabled: Boolean
) {
- log(LogLevel.VERBOSE, {
- bool1 = instantExpanding
- bool2 = notificationsDragEnabled
- bool3 = touchDisabled
- }, {
- "NPVC not intercepting touch, instantExpanding: $bool1, " +
+ buffer.log(
+ TAG,
+ LogLevel.VERBOSE,
+ {
+ bool1 = instantExpanding
+ bool2 = notificationsDragEnabled
+ bool3 = touchDisabled
+ },
+ {
+ "NPVC not intercepting touch, instantExpanding: $bool1, " +
"!notificationsDragEnabled: $bool2, touchDisabled: $bool3"
- })
+ }
+ )
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/shade/ShadeWindowLogger.kt b/packages/SystemUI/src/com/android/systemui/shade/ShadeWindowLogger.kt
index c6a6e87..9851625 100644
--- a/packages/SystemUI/src/com/android/systemui/shade/ShadeWindowLogger.kt
+++ b/packages/SystemUI/src/com/android/systemui/shade/ShadeWindowLogger.kt
@@ -32,11 +32,21 @@
ConstantStringsLogger by ConstantStringsLoggerImpl(buffer, TAG) {
fun logApplyingWindowLayoutParams(lp: WindowManager.LayoutParams) {
- log(DEBUG, { str1 = lp.toString() }, { "Applying new window layout params: $str1" })
+ buffer.log(
+ TAG,
+ DEBUG,
+ { str1 = lp.toString() },
+ { "Applying new window layout params: $str1" }
+ )
}
fun logNewState(state: Any) {
- log(DEBUG, { str1 = state.toString() }, { "Applying new state: $str1" })
+ buffer.log(
+ TAG,
+ DEBUG,
+ { str1 = state.toString() },
+ { "Applying new state: $str1" }
+ )
}
private inline fun log(
@@ -48,11 +58,16 @@
}
fun logApplyVisibility(visible: Boolean) {
- log(DEBUG, { bool1 = visible }, { "Updating visibility, should be visible : $bool1" })
+ buffer.log(
+ TAG,
+ DEBUG,
+ { bool1 = visible },
+ { "Updating visibility, should be visible : $bool1" })
}
fun logShadeVisibleAndFocusable(visible: Boolean) {
- log(
+ buffer.log(
+ TAG,
DEBUG,
{ bool1 = visible },
{ "Updating shade, should be visible and focusable: $bool1" }
@@ -60,6 +75,11 @@
}
fun logShadeFocusable(focusable: Boolean) {
- log(DEBUG, { bool1 = focusable }, { "Updating shade, should be focusable : $bool1" })
+ buffer.log(
+ TAG,
+ DEBUG,
+ { bool1 = focusable },
+ { "Updating shade, should be focusable : $bool1" }
+ )
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java b/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java
index bad942f..04adaae 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java
@@ -224,7 +224,7 @@
*/
default void setImeWindowStatus(int displayId, IBinder token, int vis,
@BackDispositionMode int backDisposition, boolean showImeSwitcher) { }
- default void showRecentApps(boolean triggeredFromAltTab) { }
+ default void showRecentApps(boolean triggeredFromAltTab, boolean forward) { }
default void hideRecentApps(boolean triggeredFromAltTab, boolean triggeredFromHomeKey) { }
default void toggleRecentApps() { }
default void toggleSplitScreen() { }
@@ -686,11 +686,11 @@
}
}
- public void showRecentApps(boolean triggeredFromAltTab) {
+ public void showRecentApps(boolean triggeredFromAltTab, boolean forward) {
synchronized (mLock) {
mHandler.removeMessages(MSG_SHOW_RECENT_APPS);
- mHandler.obtainMessage(MSG_SHOW_RECENT_APPS, triggeredFromAltTab ? 1 : 0, 0,
- null).sendToTarget();
+ mHandler.obtainMessage(MSG_SHOW_RECENT_APPS, triggeredFromAltTab ? 1 : 0,
+ forward ? 1 : 0, null).sendToTarget();
}
}
@@ -1384,7 +1384,7 @@
break;
case MSG_SHOW_RECENT_APPS:
for (int i = 0; i < mCallbacks.size(); i++) {
- mCallbacks.get(i).showRecentApps(msg.arg1 != 0);
+ mCallbacks.get(i).showRecentApps(msg.arg1 != 0, msg.arg2 != 0);
}
break;
case MSG_HIDE_RECENT_APPS:
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardIndicationController.java b/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardIndicationController.java
index 96a6169..0f52133 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardIndicationController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardIndicationController.java
@@ -41,6 +41,7 @@
import static com.android.systemui.keyguard.KeyguardIndicationRotateTextViewController.INDICATION_TYPE_USER_LOCKED;
import static com.android.systemui.keyguard.ScreenLifecycle.SCREEN_ON;
import static com.android.systemui.plugins.FalsingManager.LOW_PENALTY;
+import static com.android.systemui.plugins.log.LogLevel.ERROR;
import android.app.admin.DevicePolicyManager;
import android.content.BroadcastReceiver;
@@ -1044,7 +1045,7 @@
mChargingTimeRemaining = mPowerPluggedIn
? mBatteryInfo.computeChargeTimeRemaining() : -1;
} catch (RemoteException e) {
- mKeyguardLogger.logException(e, "Error calling IBatteryStats");
+ mKeyguardLogger.log(TAG, ERROR, "Error calling IBatteryStats", e);
mChargingTimeRemaining = -1;
}
updateDeviceEntryIndication(!wasPluggedIn && mPowerPluggedInWired);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationRemoteInputManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationRemoteInputManager.java
index 8f9365c..99081e9 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationRemoteInputManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationRemoteInputManager.java
@@ -65,8 +65,6 @@
import com.android.systemui.util.DumpUtilsKt;
import com.android.systemui.util.ListenerSet;
-import dagger.Lazy;
-
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.List;
@@ -74,6 +72,8 @@
import java.util.Optional;
import java.util.function.Consumer;
+import dagger.Lazy;
+
/**
* Class for handling remote input state over a set of notifications. This class handles things
* like keeping notifications temporarily that were cancelled as a response to a remote input
@@ -465,8 +465,7 @@
riv.getController().setRemoteInput(input);
riv.getController().setRemoteInputs(inputs);
riv.getController().setEditedSuggestionInfo(editedSuggestionInfo);
- ViewGroup parent = view.getParent() != null ? (ViewGroup) view.getParent() : null;
- riv.focusAnimated(parent);
+ riv.focusAnimated();
if (userMessageContent != null) {
riv.setEditTextContent(userMessageContent);
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/ImageTransformState.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/ImageTransformState.java
index 76025ab7..0446165 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/ImageTransformState.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/ImageTransformState.java
@@ -53,7 +53,9 @@
return true;
}
if (otherState instanceof ImageTransformState) {
- return mIcon != null && mIcon.sameAs(((ImageTransformState) otherState).getIcon());
+ final Icon otherIcon = ((ImageTransformState) otherState).mIcon;
+ return mIcon == otherIcon || (mIcon != null && otherIcon != null && mIcon.sameAs(
+ otherIcon));
}
return false;
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ActivatableNotificationViewController.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ActivatableNotificationViewController.java
index c496102..b084a76 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ActivatableNotificationViewController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ActivatableNotificationViewController.java
@@ -109,7 +109,7 @@
return true;
}
if (ev.getAction() == MotionEvent.ACTION_UP) {
- mView.setLastActionUpTime(SystemClock.uptimeMillis());
+ mView.setLastActionUpTime(ev.getEventTime());
}
// With a11y, just do nothing.
if (mAccessibilityManager.isTouchExplorationEnabled()) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationChildrenContainer.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationChildrenContainer.java
index 8d48d73..9b93d7b 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationChildrenContainer.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationChildrenContainer.java
@@ -1431,6 +1431,22 @@
@Override
public void applyRoundnessAndInvalidate() {
boolean last = true;
+ if (mUseRoundnessSourceTypes) {
+ if (mNotificationHeaderWrapper != null) {
+ mNotificationHeaderWrapper.requestTopRoundness(
+ /* value = */ getTopRoundness(),
+ /* sourceType = */ FROM_PARENT,
+ /* animate = */ false
+ );
+ }
+ if (mNotificationHeaderWrapperLowPriority != null) {
+ mNotificationHeaderWrapperLowPriority.requestTopRoundness(
+ /* value = */ getTopRoundness(),
+ /* sourceType = */ FROM_PARENT,
+ /* animate = */ false
+ );
+ }
+ }
for (int i = mAttachedChildren.size() - 1; i >= 0; i--) {
ExpandableNotificationRow child = mAttachedChildren.get(i);
if (child.getVisibility() == View.GONE) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java
index ca1e397..356ddfa 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java
@@ -1811,9 +1811,7 @@
@Override
@ShadeViewRefactor(RefactorComponent.COORDINATOR)
public WindowInsets onApplyWindowInsets(WindowInsets insets) {
- mBottomInset = insets.getSystemWindowInsetBottom()
- + insets.getInsets(WindowInsets.Type.ime()).bottom;
-
+ mBottomInset = insets.getInsets(WindowInsets.Type.ime()).bottom;
mWaterfallTopInset = 0;
final DisplayCutout cutout = insets.getDisplayCutout();
if (cutout != null) {
@@ -2262,7 +2260,11 @@
@ShadeViewRefactor(RefactorComponent.COORDINATOR)
private int getImeInset() {
- return Math.max(0, mBottomInset - (getRootView().getHeight() - getHeight()));
+ // The NotificationStackScrollLayout does not extend all the way to the bottom of the
+ // display. Therefore, subtract that space from the mBottomInset, in order to only include
+ // the portion of the bottom inset that actually overlaps the NotificationStackScrollLayout.
+ return Math.max(0, mBottomInset
+ - (getRootView().getHeight() - getHeight() - getLocationOnScreen()[1]));
}
/**
@@ -2970,12 +2972,19 @@
childInGroup = (ExpandableNotificationRow) requestedView;
requestedView = requestedRow = childInGroup.getNotificationParent();
}
- int position = 0;
+ final float scrimTopPadding = mAmbientState.isOnKeyguard() ? 0 : mMinimumPaddings;
+ int position = (int) scrimTopPadding;
+ int visibleIndex = -1;
+ ExpandableView lastVisibleChild = null;
for (int i = 0; i < getChildCount(); i++) {
ExpandableView child = getChildAtIndex(i);
boolean notGone = child.getVisibility() != View.GONE;
+ if (notGone) visibleIndex++;
if (notGone && !child.hasNoContentHeight()) {
- if (position != 0) {
+ if (position != scrimTopPadding) {
+ if (lastVisibleChild != null) {
+ position += calculateGapHeight(lastVisibleChild, child, visibleIndex);
+ }
position += mPaddingBetweenElements;
}
}
@@ -2987,6 +2996,7 @@
}
if (notGone) {
position += getIntrinsicHeight(child);
+ lastVisibleChild = child;
}
}
return 0;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/AutoTileManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/AutoTileManager.java
index 9070ead..149ec54 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/AutoTileManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/AutoTileManager.java
@@ -154,9 +154,7 @@
if (!mAutoTracker.isAdded(SAVER)) {
mDataSaverController.addCallback(mDataSaverListener);
}
- if (!mAutoTracker.isAdded(WORK)) {
- mManagedProfileController.addCallback(mProfileCallback);
- }
+ mManagedProfileController.addCallback(mProfileCallback);
if (!mAutoTracker.isAdded(NIGHT)
&& ColorDisplayManager.isNightDisplayAvailable(mContext)) {
mNightDisplayListener.setCallback(mNightDisplayCallback);
@@ -275,18 +273,18 @@
return mCurrentUser.getIdentifier();
}
- public void unmarkTileAsAutoAdded(String tabSpec) {
- mAutoTracker.setTileRemoved(tabSpec);
- }
-
private final ManagedProfileController.Callback mProfileCallback =
new ManagedProfileController.Callback() {
@Override
public void onManagedProfileChanged() {
- if (mAutoTracker.isAdded(WORK)) return;
if (mManagedProfileController.hasActiveProfile()) {
+ if (mAutoTracker.isAdded(WORK)) return;
mHost.addTile(WORK);
mAutoTracker.setTileAdded(WORK);
+ } else {
+ if (!mAutoTracker.isAdded(WORK)) return;
+ mHost.removeTile(WORK);
+ mAutoTracker.setTileRemoved(WORK);
}
}
@@ -429,7 +427,7 @@
initSafetyTile();
} else if (!isSafetyCenterEnabled && mAutoTracker.isAdded(mSafetySpec)) {
mHost.removeTile(mSafetySpec);
- mHost.unmarkTileAsAutoAdded(mSafetySpec);
+ mAutoTracker.setTileRemoved(mSafetySpec);
}
}
};
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/BiometricUnlockController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/BiometricUnlockController.java
index 9a8c5d7..9f38361 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/BiometricUnlockController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/BiometricUnlockController.java
@@ -18,6 +18,8 @@
import static android.app.StatusBarManager.SESSION_KEYGUARD;
+import static com.android.systemui.keyguard.WakefulnessLifecycle.UNKNOWN_LAST_WAKE_TIME;
+
import android.annotation.IntDef;
import android.content.res.Resources;
import android.hardware.biometrics.BiometricFaceConstants;
@@ -27,7 +29,6 @@
import android.metrics.LogMaker;
import android.os.Handler;
import android.os.PowerManager;
-import android.os.SystemClock;
import android.os.Trace;
import androidx.annotation.Nullable;
@@ -59,6 +60,7 @@
import com.android.systemui.statusbar.NotificationShadeWindowController;
import com.android.systemui.statusbar.VibratorHelper;
import com.android.systemui.statusbar.policy.KeyguardStateController;
+import com.android.systemui.util.time.SystemClock;
import java.io.PrintWriter;
import java.lang.annotation.Retention;
@@ -75,6 +77,7 @@
*/
@SysUISingleton
public class BiometricUnlockController extends KeyguardUpdateMonitorCallback implements Dumpable {
+ private static final long RECENT_POWER_BUTTON_PRESS_THRESHOLD_MS = 400L;
private static final long BIOMETRIC_WAKELOCK_TIMEOUT_MS = 15 * 1000;
private static final String BIOMETRIC_WAKE_LOCK_NAME = "wake-and-unlock:wakelock";
private static final UiEventLogger UI_EVENT_LOGGER = new UiEventLoggerImpl();
@@ -165,9 +168,11 @@
private final MetricsLogger mMetricsLogger;
private final AuthController mAuthController;
private final StatusBarStateController mStatusBarStateController;
+ private final WakefulnessLifecycle mWakefulnessLifecycle;
private final LatencyTracker mLatencyTracker;
private final VibratorHelper mVibratorHelper;
private final BiometricUnlockLogger mLogger;
+ private final SystemClock mSystemClock;
private long mLastFpFailureUptimeMillis;
private int mNumConsecutiveFpFailures;
@@ -272,13 +277,16 @@
SessionTracker sessionTracker,
LatencyTracker latencyTracker,
ScreenOffAnimationController screenOffAnimationController,
- VibratorHelper vibrator) {
+ VibratorHelper vibrator,
+ SystemClock systemClock
+ ) {
mPowerManager = powerManager;
mUpdateMonitor = keyguardUpdateMonitor;
mUpdateMonitor.registerCallback(this);
mMediaManager = notificationMediaManager;
mLatencyTracker = latencyTracker;
- wakefulnessLifecycle.addObserver(mWakefulnessObserver);
+ mWakefulnessLifecycle = wakefulnessLifecycle;
+ mWakefulnessLifecycle.addObserver(mWakefulnessObserver);
screenLifecycle.addObserver(mScreenObserver);
mNotificationShadeWindowController = notificationShadeWindowController;
@@ -297,6 +305,7 @@
mScreenOffAnimationController = screenOffAnimationController;
mVibratorHelper = vibrator;
mLogger = biometricUnlockLogger;
+ mSystemClock = systemClock;
dumpManager.registerDumpable(getClass().getName(), this);
}
@@ -420,8 +429,11 @@
Runnable wakeUp = ()-> {
if (!wasDeviceInteractive || mUpdateMonitor.isDreaming()) {
mLogger.i("bio wakelock: Authenticated, waking up...");
- mPowerManager.wakeUp(SystemClock.uptimeMillis(), PowerManager.WAKE_REASON_BIOMETRIC,
- "android.policy:BIOMETRIC");
+ mPowerManager.wakeUp(
+ mSystemClock.uptimeMillis(),
+ PowerManager.WAKE_REASON_BIOMETRIC,
+ "android.policy:BIOMETRIC"
+ );
}
Trace.beginSection("release wake-and-unlock");
releaseBiometricWakeLock();
@@ -652,7 +664,7 @@
startWakeAndUnlock(MODE_ONLY_WAKE);
} else if (biometricSourceType == BiometricSourceType.FINGERPRINT
&& mUpdateMonitor.isUdfpsSupported()) {
- long currUptimeMillis = SystemClock.uptimeMillis();
+ long currUptimeMillis = mSystemClock.uptimeMillis();
if (currUptimeMillis - mLastFpFailureUptimeMillis < mConsecutiveFpFailureThreshold) {
mNumConsecutiveFpFailures += 1;
} else {
@@ -700,12 +712,26 @@
cleanup();
}
- //these haptics are for device-entry only
+ // these haptics are for device-entry only
private void vibrateSuccess(BiometricSourceType type) {
+ if (mAuthController.isSfpsEnrolled(KeyguardUpdateMonitor.getCurrentUser())
+ && lastWakeupFromPowerButtonWithinHapticThreshold()) {
+ mLogger.d("Skip auth success haptic. Power button was recently pressed.");
+ return;
+ }
mVibratorHelper.vibrateAuthSuccess(
getClass().getSimpleName() + ", type =" + type + "device-entry::success");
}
+ private boolean lastWakeupFromPowerButtonWithinHapticThreshold() {
+ final boolean lastWakeupFromPowerButton = mWakefulnessLifecycle.getLastWakeReason()
+ == PowerManager.WAKE_REASON_POWER_BUTTON;
+ return lastWakeupFromPowerButton
+ && mWakefulnessLifecycle.getLastWakeTime() != UNKNOWN_LAST_WAKE_TIME
+ && mSystemClock.uptimeMillis() - mWakefulnessLifecycle.getLastWakeTime()
+ < RECENT_POWER_BUTTON_PRESS_THRESHOLD_MS;
+ }
+
private void vibrateError(BiometricSourceType type) {
mVibratorHelper.vibrateAuthError(
getClass().getSimpleName() + ", type =" + type + "device-entry::error");
@@ -798,7 +824,7 @@
if (mUpdateMonitor.isUdfpsSupported()) {
pw.print(" mNumConsecutiveFpFailures="); pw.println(mNumConsecutiveFpFailures);
pw.print(" time since last failure=");
- pw.println(SystemClock.uptimeMillis() - mLastFpFailureUptimeMillis);
+ pw.println(mSystemClock.uptimeMillis() - mLastFpFailureUptimeMillis);
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfaces.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfaces.java
index cf2f7742..8dcfec7 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfaces.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfaces.java
@@ -122,6 +122,7 @@
options.setLaunchDisplayId(displayId);
options.setCallerDisplayId(displayId);
options.setPendingIntentBackgroundActivityLaunchAllowed(true);
+ options.setInteractive(true);
return options.toBundle();
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfacesImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfacesImpl.java
index 22ebcab..4b56594 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfacesImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfacesImpl.java
@@ -4247,8 +4247,7 @@
@Override
public void onDozeAmountChanged(float linear, float eased) {
- if (mFeatureFlags.isEnabled(Flags.LOCKSCREEN_ANIMATIONS)
- && !mFeatureFlags.isEnabled(Flags.LIGHT_REVEAL_MIGRATION)
+ if (!mFeatureFlags.isEnabled(Flags.LIGHT_REVEAL_MIGRATION)
&& !(mLightRevealScrim.getRevealEffect() instanceof CircleReveal)) {
mLightRevealScrim.setRevealAmount(1f - linear);
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/DozeParameters.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/DozeParameters.java
index de7b152..0446cef 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/DozeParameters.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/DozeParameters.java
@@ -44,10 +44,9 @@
import com.android.systemui.doze.AlwaysOnDisplayPolicy;
import com.android.systemui.doze.DozeScreenState;
import com.android.systemui.dump.DumpManager;
-import com.android.systemui.flags.FeatureFlags;
-import com.android.systemui.flags.Flags;
import com.android.systemui.plugins.statusbar.StatusBarStateController;
import com.android.systemui.statusbar.policy.BatteryController;
+import com.android.systemui.statusbar.policy.BatteryController.BatteryStateChangeCallback;
import com.android.systemui.statusbar.policy.ConfigurationController;
import com.android.systemui.statusbar.policy.DevicePostureController;
import com.android.systemui.tuner.TunerService;
@@ -82,7 +81,6 @@
private final AlwaysOnDisplayPolicy mAlwaysOnPolicy;
private final Resources mResources;
private final BatteryController mBatteryController;
- private final FeatureFlags mFeatureFlags;
private final ScreenOffAnimationController mScreenOffAnimationController;
private final FoldAodAnimationController mFoldAodAnimationController;
private final UnlockedScreenOffAnimationController mUnlockedScreenOffAnimationController;
@@ -125,7 +123,6 @@
BatteryController batteryController,
TunerService tunerService,
DumpManager dumpManager,
- FeatureFlags featureFlags,
ScreenOffAnimationController screenOffAnimationController,
Optional<SysUIUnfoldComponent> sysUiUnfoldComponent,
UnlockedScreenOffAnimationController unlockedScreenOffAnimationController,
@@ -141,7 +138,6 @@
mControlScreenOffAnimation = !getDisplayNeedsBlanking();
mPowerManager = powerManager;
mPowerManager.setDozeAfterScreenOff(!mControlScreenOffAnimation);
- mFeatureFlags = featureFlags;
mScreenOffAnimationController = screenOffAnimationController;
mUnlockedScreenOffAnimationController = unlockedScreenOffAnimationController;
@@ -162,6 +158,13 @@
SettingsObserver quickPickupSettingsObserver = new SettingsObserver(context, handler);
quickPickupSettingsObserver.observe();
+
+ batteryController.addCallback(new BatteryStateChangeCallback() {
+ @Override
+ public void onPowerSaveChanged(boolean isPowerSave) {
+ dispatchAlwaysOnEvent();
+ }
+ });
}
private void updateQuickPickupEnabled() {
@@ -300,13 +303,10 @@
/**
* Whether we're capable of controlling the screen off animation if we want to. This isn't
- * possible if AOD isn't even enabled or if the flag is disabled, or if the display needs
- * blanking.
+ * possible if AOD isn't even enabled or if the display needs blanking.
*/
public boolean canControlUnlockedScreenOff() {
- return getAlwaysOn()
- && mFeatureFlags.isEnabled(Flags.LOCKSCREEN_ANIMATIONS)
- && !getDisplayNeedsBlanking();
+ return getAlwaysOn() && !getDisplayNeedsBlanking();
}
/**
@@ -424,9 +424,7 @@
updateControlScreenOff();
}
- for (Callback callback : mCallbacks) {
- callback.onAlwaysOnChange();
- }
+ dispatchAlwaysOnEvent();
mScreenOffAnimationController.onAlwaysOnChanged(getAlwaysOn());
}
@@ -463,6 +461,12 @@
pw.print("isQuickPickupEnabled(): "); pw.println(isQuickPickupEnabled());
}
+ private void dispatchAlwaysOnEvent() {
+ for (Callback callback : mCallbacks) {
+ callback.onAlwaysOnChange();
+ }
+ }
+
private boolean getPostureSpecificBool(
int[] postureMapping,
boolean defaultSensorBool,
@@ -477,7 +481,8 @@
return bool;
}
- interface Callback {
+ /** Callbacks for doze parameter related information */
+ public interface Callback {
/**
* Invoked when the value of getAlwaysOn may have changed.
*/
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardStatusBarViewController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardStatusBarViewController.java
index 3483574..4ad3199 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardStatusBarViewController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardStatusBarViewController.java
@@ -45,6 +45,7 @@
import com.android.systemui.animation.Interpolators;
import com.android.systemui.battery.BatteryMeterViewController;
import com.android.systemui.dagger.qualifiers.Main;
+import com.android.systemui.plugins.log.LogLevel;
import com.android.systemui.plugins.statusbar.StatusBarStateController;
import com.android.systemui.shade.NotificationPanelViewController;
import com.android.systemui.statusbar.CommandQueue;
@@ -76,6 +77,7 @@
/** View Controller for {@link com.android.systemui.statusbar.phone.KeyguardStatusBarView}. */
public class KeyguardStatusBarViewController extends ViewController<KeyguardStatusBarView> {
+ private static final String TAG = "KeyguardStatusBarViewController";
private static final AnimationProperties KEYGUARD_HUN_PROPERTIES =
new AnimationProperties().setDuration(StackStateAnimator.ANIMATION_DURATION_STANDARD);
@@ -422,7 +424,7 @@
/** Animate the keyguard status bar in. */
public void animateKeyguardStatusBarIn() {
- mLogger.d("animating status bar in");
+ mLogger.log(TAG, LogLevel.DEBUG, "animating status bar in");
if (mDisableStateTracker.isDisabled()) {
// If our view is disabled, don't allow us to animate in.
return;
@@ -438,7 +440,7 @@
/** Animate the keyguard status bar out. */
public void animateKeyguardStatusBarOut(long startDelay, long duration) {
- mLogger.d("animating status bar out");
+ mLogger.log(TAG, LogLevel.DEBUG, "animating status bar out");
ValueAnimator anim = ValueAnimator.ofFloat(mView.getAlpha(), 0f);
anim.addUpdateListener(mAnimatorUpdateListener);
anim.setStartDelay(startDelay);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/SystemBarAttributesListener.kt b/packages/SystemUI/src/com/android/systemui/statusbar/phone/SystemBarAttributesListener.kt
index 08599c2..fbe374c 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/SystemBarAttributesListener.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/SystemBarAttributesListener.kt
@@ -16,6 +16,8 @@
package com.android.systemui.statusbar.phone
+import android.view.InsetsFlags
+import android.view.ViewDebug
import android.view.WindowInsets.Type.InsetsType
import android.view.WindowInsetsController.Appearance
import android.view.WindowInsetsController.Behavior
@@ -148,4 +150,20 @@
) {
val letterboxesArray = letterboxes.toTypedArray()
val appearanceRegionsArray = appearanceRegions.toTypedArray()
+ override fun toString(): String {
+ val appearanceToString =
+ ViewDebug.flagsToString(InsetsFlags::class.java, "appearance", appearance)
+ return """SystemBarAttributesParams(
+ displayId=$displayId,
+ appearance=$appearanceToString,
+ appearanceRegions=$appearanceRegions,
+ navbarColorManagedByIme=$navbarColorManagedByIme,
+ behavior=$behavior,
+ requestedVisibleTypes=$requestedVisibleTypes,
+ packageName='$packageName',
+ letterboxes=$letterboxes,
+ letterboxesArray=${letterboxesArray.contentToString()},
+ appearanceRegionsArray=${appearanceRegionsArray.contentToString()}
+ )""".trimMargin()
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/model/ResolvedNetworkType.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/model/ResolvedNetworkType.kt
index 5960387..5562e73 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/model/ResolvedNetworkType.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/model/ResolvedNetworkType.kt
@@ -17,6 +17,8 @@
package com.android.systemui.statusbar.pipeline.mobile.data.model
import android.telephony.Annotation.NetworkType
+import com.android.settingslib.SignalIcon
+import com.android.settingslib.mobile.TelephonyIcons
import com.android.systemui.statusbar.pipeline.mobile.util.MobileMappingsProxy
/**
@@ -38,4 +40,12 @@
data class OverrideNetworkType(
override val lookupKey: String,
) : ResolvedNetworkType
+
+ /** Represents the carrier merged network. See [CarrierMergedConnectionRepository]. */
+ object CarrierMergedNetworkType : ResolvedNetworkType {
+ // Effectively unused since [iconGroupOverride] is used instead.
+ override val lookupKey: String = "cwf"
+
+ val iconGroupOverride: SignalIcon.MobileIconGroup = TelephonyIcons.CARRIER_MERGED_WIFI
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/MobileConnectionRepository.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/MobileConnectionRepository.kt
index d04996b..6187f64 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/MobileConnectionRepository.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/MobileConnectionRepository.kt
@@ -22,7 +22,6 @@
import com.android.systemui.log.table.TableLogBuffer
import com.android.systemui.statusbar.pipeline.mobile.data.model.MobileConnectionModel
import com.android.systemui.statusbar.pipeline.mobile.data.model.NetworkNameModel
-import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.StateFlow
/**
@@ -50,7 +49,7 @@
* A flow that aggregates all necessary callbacks from [TelephonyCallback] into a single
* listener + model.
*/
- val connectionInfo: Flow<MobileConnectionModel>
+ val connectionInfo: StateFlow<MobileConnectionModel>
/** The total number of levels. Used with [SignalDrawable]. */
val numberOfLevels: StateFlow<Int>
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/demo/DemoMobileConnectionsRepository.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/demo/DemoMobileConnectionsRepository.kt
index 0e164e7..22aca0a 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/demo/DemoMobileConnectionsRepository.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/demo/DemoMobileConnectionsRepository.kt
@@ -39,7 +39,11 @@
import com.android.systemui.statusbar.pipeline.mobile.data.repository.demo.model.FakeNetworkEventModel
import com.android.systemui.statusbar.pipeline.mobile.data.repository.demo.model.FakeNetworkEventModel.Mobile
import com.android.systemui.statusbar.pipeline.mobile.data.repository.demo.model.FakeNetworkEventModel.MobileDisabled
+import com.android.systemui.statusbar.pipeline.mobile.data.repository.prod.CarrierMergedConnectionRepository.Companion.createCarrierMergedConnectionModel
+import com.android.systemui.statusbar.pipeline.mobile.data.repository.prod.FullMobileConnectionRepository.Factory.Companion.MOBILE_CONNECTION_BUFFER_SIZE
import com.android.systemui.statusbar.pipeline.shared.data.model.toMobileDataActivityModel
+import com.android.systemui.statusbar.pipeline.wifi.data.repository.demo.DemoModeWifiDataSource
+import com.android.systemui.statusbar.pipeline.wifi.data.repository.demo.model.FakeWifiEventModel
import javax.inject.Inject
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.ExperimentalCoroutinesApi
@@ -60,15 +64,19 @@
class DemoMobileConnectionsRepository
@Inject
constructor(
- private val dataSource: DemoModeMobileConnectionDataSource,
+ private val mobileDataSource: DemoModeMobileConnectionDataSource,
+ private val wifiDataSource: DemoModeWifiDataSource,
@Application private val scope: CoroutineScope,
context: Context,
private val logFactory: TableLogBufferFactory,
) : MobileConnectionsRepository {
- private var demoCommandJob: Job? = null
+ private var mobileDemoCommandJob: Job? = null
+ private var wifiDemoCommandJob: Job? = null
- private var connectionRepoCache = mutableMapOf<Int, DemoMobileConnectionRepository>()
+ private var carrierMergedSubId: Int? = null
+
+ private var connectionRepoCache = mutableMapOf<Int, CacheContainer>()
private val subscriptionInfoCache = mutableMapOf<Int, SubscriptionModel>()
val demoModeFinishedEvent = MutableSharedFlow<Unit>(extraBufferCapacity = 1)
@@ -144,52 +152,83 @@
override val defaultMobileNetworkConnectivity = MutableStateFlow(MobileConnectivityModel())
override fun getRepoForSubId(subId: Int): DemoMobileConnectionRepository {
- return connectionRepoCache[subId]
- ?: createDemoMobileConnectionRepo(subId).also { connectionRepoCache[subId] = it }
+ val current = connectionRepoCache[subId]?.repo
+ if (current != null) {
+ return current
+ }
+
+ val new = createDemoMobileConnectionRepo(subId)
+ connectionRepoCache[subId] = new
+ return new.repo
}
- private fun createDemoMobileConnectionRepo(subId: Int): DemoMobileConnectionRepository {
- val tableLogBuffer = logFactory.create("DemoMobileConnectionLog [$subId]", 100)
+ private fun createDemoMobileConnectionRepo(subId: Int): CacheContainer {
+ val tableLogBuffer =
+ logFactory.getOrCreate(
+ "DemoMobileConnectionLog [$subId]",
+ MOBILE_CONNECTION_BUFFER_SIZE,
+ )
- return DemoMobileConnectionRepository(
- subId,
- tableLogBuffer,
- )
+ val repo =
+ DemoMobileConnectionRepository(
+ subId,
+ tableLogBuffer,
+ )
+ return CacheContainer(repo, lastMobileState = null)
}
override val globalMobileDataSettingChangedEvent = MutableStateFlow(Unit)
fun startProcessingCommands() {
- demoCommandJob =
+ mobileDemoCommandJob =
scope.launch {
- dataSource.mobileEvents.filterNotNull().collect { event -> processEvent(event) }
+ mobileDataSource.mobileEvents.filterNotNull().collect { event ->
+ processMobileEvent(event)
+ }
+ }
+ wifiDemoCommandJob =
+ scope.launch {
+ wifiDataSource.wifiEvents.filterNotNull().collect { event ->
+ processWifiEvent(event)
+ }
}
}
fun stopProcessingCommands() {
- demoCommandJob?.cancel()
+ mobileDemoCommandJob?.cancel()
+ wifiDemoCommandJob?.cancel()
_subscriptions.value = listOf()
connectionRepoCache.clear()
subscriptionInfoCache.clear()
}
- private fun processEvent(event: FakeNetworkEventModel) {
+ private fun processMobileEvent(event: FakeNetworkEventModel) {
when (event) {
is Mobile -> {
processEnabledMobileState(event)
}
is MobileDisabled -> {
- processDisabledMobileState(event)
+ maybeRemoveSubscription(event.subId)
}
}
}
+ private fun processWifiEvent(event: FakeWifiEventModel) {
+ when (event) {
+ is FakeWifiEventModel.WifiDisabled -> disableCarrierMerged()
+ is FakeWifiEventModel.Wifi -> disableCarrierMerged()
+ is FakeWifiEventModel.CarrierMerged -> processCarrierMergedWifiState(event)
+ }
+ }
+
private fun processEnabledMobileState(state: Mobile) {
// get or create the connection repo, and set its values
val subId = state.subId ?: DEFAULT_SUB_ID
maybeCreateSubscription(subId)
val connection = getRepoForSubId(subId)
+ connectionRepoCache[subId]?.lastMobileState = state
+
// This is always true here, because we split out disabled states at the data-source level
connection.dataEnabled.value = true
connection.networkName.value = NetworkNameModel.Derived(state.name)
@@ -198,14 +237,36 @@
connection.connectionInfo.value = state.toMobileConnectionModel()
}
- private fun processDisabledMobileState(state: MobileDisabled) {
+ private fun processCarrierMergedWifiState(event: FakeWifiEventModel.CarrierMerged) {
+ // The new carrier merged connection is for a different sub ID, so disable carrier merged
+ // for the current (now old) sub
+ if (carrierMergedSubId != event.subscriptionId) {
+ disableCarrierMerged()
+ }
+
+ // get or create the connection repo, and set its values
+ val subId = event.subscriptionId
+ maybeCreateSubscription(subId)
+ carrierMergedSubId = subId
+
+ val connection = getRepoForSubId(subId)
+ // This is always true here, because we split out disabled states at the data-source level
+ connection.dataEnabled.value = true
+ connection.networkName.value = NetworkNameModel.Derived(CARRIER_MERGED_NAME)
+ connection.numberOfLevels.value = event.numberOfLevels
+ connection.cdmaRoaming.value = false
+ connection.connectionInfo.value = event.toMobileConnectionModel()
+ Log.e("CCS", "output connection info = ${connection.connectionInfo.value}")
+ }
+
+ private fun maybeRemoveSubscription(subId: Int?) {
if (_subscriptions.value.isEmpty()) {
// Nothing to do here
return
}
- val subId =
- state.subId
+ val finalSubId =
+ subId
?: run {
// For sake of usability, we can allow for no subId arg if there is only one
// subscription
@@ -223,7 +284,21 @@
_subscriptions.value[0].subscriptionId
}
- removeSubscription(subId)
+ removeSubscription(finalSubId)
+ }
+
+ private fun disableCarrierMerged() {
+ val currentCarrierMergedSubId = carrierMergedSubId ?: return
+
+ // If this sub ID was previously not carrier merged, we should reset it to its previous
+ // connection.
+ val lastMobileState = connectionRepoCache[carrierMergedSubId]?.lastMobileState
+ if (lastMobileState != null) {
+ processEnabledMobileState(lastMobileState)
+ } else {
+ // Otherwise, just remove the subscription entirely
+ removeSubscription(currentCarrierMergedSubId)
+ }
}
private fun removeSubscription(subId: Int) {
@@ -251,6 +326,10 @@
)
}
+ private fun FakeWifiEventModel.CarrierMerged.toMobileConnectionModel(): MobileConnectionModel {
+ return createCarrierMergedConnectionModel(this.level)
+ }
+
private fun SignalIcon.MobileIconGroup?.toResolvedNetworkType(): ResolvedNetworkType {
val key = mobileMappingsReverseLookup.value[this] ?: "dis"
return DefaultNetworkType(key)
@@ -260,9 +339,17 @@
private const val TAG = "DemoMobileConnectionsRepo"
private const val DEFAULT_SUB_ID = 1
+
+ private const val CARRIER_MERGED_NAME = "Carrier Merged Network"
}
}
+class CacheContainer(
+ var repo: DemoMobileConnectionRepository,
+ /** The last received [Mobile] event. Used when switching from carrier merged back to mobile. */
+ var lastMobileState: Mobile?,
+)
+
class DemoMobileConnectionRepository(
override val subId: Int,
override val tableLogBuffer: TableLogBuffer,
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/CarrierMergedConnectionRepository.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/CarrierMergedConnectionRepository.kt
new file mode 100644
index 0000000..c783b12
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/CarrierMergedConnectionRepository.kt
@@ -0,0 +1,181 @@
+/*
+ * 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 com.android.systemui.statusbar.pipeline.mobile.data.repository.prod
+
+import android.util.Log
+import com.android.systemui.dagger.SysUISingleton
+import com.android.systemui.dagger.qualifiers.Application
+import com.android.systemui.log.table.TableLogBuffer
+import com.android.systemui.statusbar.pipeline.mobile.data.model.DataConnectionState
+import com.android.systemui.statusbar.pipeline.mobile.data.model.MobileConnectionModel
+import com.android.systemui.statusbar.pipeline.mobile.data.model.NetworkNameModel
+import com.android.systemui.statusbar.pipeline.mobile.data.model.ResolvedNetworkType
+import com.android.systemui.statusbar.pipeline.mobile.data.repository.MobileConnectionRepository
+import com.android.systemui.statusbar.pipeline.mobile.data.repository.MobileConnectionRepository.Companion.DEFAULT_NUM_LEVELS
+import com.android.systemui.statusbar.pipeline.shared.data.model.DataActivityModel
+import com.android.systemui.statusbar.pipeline.wifi.data.model.WifiNetworkModel
+import com.android.systemui.statusbar.pipeline.wifi.data.repository.WifiRepository
+import javax.inject.Inject
+import kotlinx.coroutines.CoroutineScope
+import kotlinx.coroutines.flow.Flow
+import kotlinx.coroutines.flow.MutableStateFlow
+import kotlinx.coroutines.flow.SharingStarted
+import kotlinx.coroutines.flow.StateFlow
+import kotlinx.coroutines.flow.asStateFlow
+import kotlinx.coroutines.flow.combine
+import kotlinx.coroutines.flow.flowOf
+import kotlinx.coroutines.flow.map
+import kotlinx.coroutines.flow.stateIn
+
+/**
+ * A repository implementation for a carrier merged (aka VCN) network. A carrier merged network is
+ * delivered to SysUI as a wifi network (see [WifiNetworkModel.CarrierMerged], but is visually
+ * displayed as a mobile network triangle.
+ *
+ * See [android.net.wifi.WifiInfo.isCarrierMerged] for more information.
+ *
+ * See [MobileConnectionRepositoryImpl] for a repository implementation of a typical mobile
+ * connection.
+ */
+class CarrierMergedConnectionRepository(
+ override val subId: Int,
+ override val tableLogBuffer: TableLogBuffer,
+ defaultNetworkName: NetworkNameModel,
+ @Application private val scope: CoroutineScope,
+ val wifiRepository: WifiRepository,
+) : MobileConnectionRepository {
+
+ /**
+ * Outputs the carrier merged network to use, or null if we don't have a valid carrier merged
+ * network.
+ */
+ private val network: Flow<WifiNetworkModel.CarrierMerged?> =
+ combine(
+ wifiRepository.isWifiEnabled,
+ wifiRepository.isWifiDefault,
+ wifiRepository.wifiNetwork,
+ ) { isEnabled, isDefault, network ->
+ when {
+ !isEnabled -> null
+ !isDefault -> null
+ network !is WifiNetworkModel.CarrierMerged -> null
+ network.subscriptionId != subId -> {
+ Log.w(
+ TAG,
+ "Connection repo subId=$subId " +
+ "does not equal wifi repo subId=${network.subscriptionId}; " +
+ "not showing carrier merged"
+ )
+ null
+ }
+ else -> network
+ }
+ }
+
+ override val connectionInfo: StateFlow<MobileConnectionModel> =
+ network
+ .map { it.toMobileConnectionModel() }
+ .stateIn(scope, SharingStarted.WhileSubscribed(), MobileConnectionModel())
+
+ // TODO(b/238425913): Add logging to this class.
+ // TODO(b/238425913): Make sure SignalStrength.getEmptyState is used when appropriate.
+
+ // Carrier merged is never roaming.
+ override val cdmaRoaming: StateFlow<Boolean> = MutableStateFlow(false).asStateFlow()
+
+ // TODO(b/238425913): Fetch the carrier merged network name.
+ override val networkName: StateFlow<NetworkNameModel> =
+ flowOf(defaultNetworkName)
+ .stateIn(scope, SharingStarted.WhileSubscribed(), defaultNetworkName)
+
+ override val numberOfLevels: StateFlow<Int> =
+ wifiRepository.wifiNetwork
+ .map {
+ if (it is WifiNetworkModel.CarrierMerged) {
+ it.numberOfLevels
+ } else {
+ DEFAULT_NUM_LEVELS
+ }
+ }
+ .stateIn(scope, SharingStarted.WhileSubscribed(), DEFAULT_NUM_LEVELS)
+
+ override val dataEnabled: StateFlow<Boolean> = wifiRepository.isWifiEnabled
+
+ private fun WifiNetworkModel.CarrierMerged?.toMobileConnectionModel(): MobileConnectionModel {
+ if (this == null) {
+ return MobileConnectionModel()
+ }
+
+ return createCarrierMergedConnectionModel(level)
+ }
+
+ companion object {
+ /**
+ * Creates an instance of [MobileConnectionModel] that represents a carrier merged network
+ * with the given [level].
+ */
+ fun createCarrierMergedConnectionModel(level: Int): MobileConnectionModel {
+ return MobileConnectionModel(
+ primaryLevel = level,
+ cdmaLevel = level,
+ // A [WifiNetworkModel.CarrierMerged] instance is always connected.
+ // (A [WifiNetworkModel.Inactive] represents a disconnected network.)
+ dataConnectionState = DataConnectionState.Connected,
+ // TODO(b/238425913): This should come from [WifiRepository.wifiActivity].
+ dataActivityDirection =
+ DataActivityModel(
+ hasActivityIn = false,
+ hasActivityOut = false,
+ ),
+ resolvedNetworkType = ResolvedNetworkType.CarrierMergedNetworkType,
+ // Carrier merged is never roaming
+ isRoaming = false,
+
+ // TODO(b/238425913): Verify that these fields never change for carrier merged.
+ isEmergencyOnly = false,
+ operatorAlphaShort = null,
+ isInService = true,
+ isGsm = false,
+ carrierNetworkChangeActive = false,
+ )
+ }
+ }
+
+ @SysUISingleton
+ class Factory
+ @Inject
+ constructor(
+ @Application private val scope: CoroutineScope,
+ private val wifiRepository: WifiRepository,
+ ) {
+ fun build(
+ subId: Int,
+ mobileLogger: TableLogBuffer,
+ defaultNetworkName: NetworkNameModel,
+ ): MobileConnectionRepository {
+ return CarrierMergedConnectionRepository(
+ subId,
+ mobileLogger,
+ defaultNetworkName,
+ scope,
+ wifiRepository,
+ )
+ }
+ }
+}
+
+private const val TAG = "CarrierMergedConnectionRepository"
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/FullMobileConnectionRepository.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/FullMobileConnectionRepository.kt
new file mode 100644
index 0000000..0f30ae2
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/FullMobileConnectionRepository.kt
@@ -0,0 +1,179 @@
+/*
+ * 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 com.android.systemui.statusbar.pipeline.mobile.data.repository.prod
+
+import androidx.annotation.VisibleForTesting
+import com.android.systemui.dagger.qualifiers.Application
+import com.android.systemui.log.table.TableLogBuffer
+import com.android.systemui.log.table.TableLogBufferFactory
+import com.android.systemui.log.table.logDiffsForTable
+import com.android.systemui.statusbar.pipeline.mobile.data.model.NetworkNameModel
+import com.android.systemui.statusbar.pipeline.mobile.data.repository.MobileConnectionRepository
+import javax.inject.Inject
+import kotlinx.coroutines.CoroutineScope
+import kotlinx.coroutines.ExperimentalCoroutinesApi
+import kotlinx.coroutines.flow.Flow
+import kotlinx.coroutines.flow.MutableStateFlow
+import kotlinx.coroutines.flow.SharingStarted
+import kotlinx.coroutines.flow.StateFlow
+import kotlinx.coroutines.flow.flatMapLatest
+import kotlinx.coroutines.flow.mapLatest
+import kotlinx.coroutines.flow.stateIn
+
+/**
+ * A repository that fully implements a mobile connection.
+ *
+ * This connection could either be a typical mobile connection (see [MobileConnectionRepositoryImpl]
+ * or a carrier merged connection (see [CarrierMergedConnectionRepository]). This repository
+ * switches between the two types of connections based on whether the connection is currently
+ * carrier merged (see [setIsCarrierMerged]).
+ */
+@Suppress("EXPERIMENTAL_IS_NOT_ENABLED")
+@OptIn(ExperimentalCoroutinesApi::class)
+class FullMobileConnectionRepository(
+ override val subId: Int,
+ startingIsCarrierMerged: Boolean,
+ override val tableLogBuffer: TableLogBuffer,
+ private val defaultNetworkName: NetworkNameModel,
+ private val networkNameSeparator: String,
+ private val globalMobileDataSettingChangedEvent: Flow<Unit>,
+ @Application scope: CoroutineScope,
+ private val mobileRepoFactory: MobileConnectionRepositoryImpl.Factory,
+ private val carrierMergedRepoFactory: CarrierMergedConnectionRepository.Factory,
+) : MobileConnectionRepository {
+ /**
+ * Sets whether this connection is a typical mobile connection or a carrier merged connection.
+ */
+ fun setIsCarrierMerged(isCarrierMerged: Boolean) {
+ _isCarrierMerged.value = isCarrierMerged
+ }
+
+ /**
+ * Returns true if this repo is currently for a carrier merged connection and false otherwise.
+ */
+ @VisibleForTesting fun getIsCarrierMerged() = _isCarrierMerged.value
+
+ private val _isCarrierMerged = MutableStateFlow(startingIsCarrierMerged)
+ private val isCarrierMerged: StateFlow<Boolean> =
+ _isCarrierMerged
+ .logDiffsForTable(
+ tableLogBuffer,
+ columnPrefix = "",
+ columnName = "isCarrierMerged",
+ initialValue = startingIsCarrierMerged,
+ )
+ .stateIn(scope, SharingStarted.WhileSubscribed(), startingIsCarrierMerged)
+
+ private val mobileRepo: MobileConnectionRepository by lazy {
+ mobileRepoFactory.build(
+ subId,
+ tableLogBuffer,
+ defaultNetworkName,
+ networkNameSeparator,
+ globalMobileDataSettingChangedEvent,
+ )
+ }
+
+ private val carrierMergedRepo: MobileConnectionRepository by lazy {
+ carrierMergedRepoFactory.build(subId, tableLogBuffer, defaultNetworkName)
+ }
+
+ @VisibleForTesting
+ internal val activeRepo: StateFlow<MobileConnectionRepository> = run {
+ val initial =
+ if (startingIsCarrierMerged) {
+ carrierMergedRepo
+ } else {
+ mobileRepo
+ }
+
+ this.isCarrierMerged
+ .mapLatest { isCarrierMerged ->
+ if (isCarrierMerged) {
+ carrierMergedRepo
+ } else {
+ mobileRepo
+ }
+ }
+ .stateIn(scope, SharingStarted.WhileSubscribed(), initial)
+ }
+
+ override val cdmaRoaming =
+ activeRepo
+ .flatMapLatest { it.cdmaRoaming }
+ .stateIn(scope, SharingStarted.WhileSubscribed(), activeRepo.value.cdmaRoaming.value)
+
+ override val connectionInfo =
+ activeRepo
+ .flatMapLatest { it.connectionInfo }
+ .stateIn(scope, SharingStarted.WhileSubscribed(), activeRepo.value.connectionInfo.value)
+
+ override val dataEnabled =
+ activeRepo
+ .flatMapLatest { it.dataEnabled }
+ .stateIn(scope, SharingStarted.WhileSubscribed(), activeRepo.value.dataEnabled.value)
+
+ override val numberOfLevels =
+ activeRepo
+ .flatMapLatest { it.numberOfLevels }
+ .stateIn(scope, SharingStarted.WhileSubscribed(), activeRepo.value.numberOfLevels.value)
+
+ override val networkName =
+ activeRepo
+ .flatMapLatest { it.networkName }
+ .stateIn(scope, SharingStarted.WhileSubscribed(), activeRepo.value.networkName.value)
+
+ class Factory
+ @Inject
+ constructor(
+ @Application private val scope: CoroutineScope,
+ private val logFactory: TableLogBufferFactory,
+ private val mobileRepoFactory: MobileConnectionRepositoryImpl.Factory,
+ private val carrierMergedRepoFactory: CarrierMergedConnectionRepository.Factory,
+ ) {
+ fun build(
+ subId: Int,
+ startingIsCarrierMerged: Boolean,
+ defaultNetworkName: NetworkNameModel,
+ networkNameSeparator: String,
+ globalMobileDataSettingChangedEvent: Flow<Unit>,
+ ): FullMobileConnectionRepository {
+ val mobileLogger =
+ logFactory.getOrCreate(tableBufferLogName(subId), MOBILE_CONNECTION_BUFFER_SIZE)
+
+ return FullMobileConnectionRepository(
+ subId,
+ startingIsCarrierMerged,
+ mobileLogger,
+ defaultNetworkName,
+ networkNameSeparator,
+ globalMobileDataSettingChangedEvent,
+ scope,
+ mobileRepoFactory,
+ carrierMergedRepoFactory,
+ )
+ }
+
+ companion object {
+ /** The buffer size to use for logging. */
+ const val MOBILE_CONNECTION_BUFFER_SIZE = 100
+
+ /** Returns a log buffer name for a mobile connection with the given [subId]. */
+ fun tableBufferLogName(subId: Int): String = "MobileConnectionLog [$subId]"
+ }
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/MobileConnectionRepositoryImpl.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/MobileConnectionRepositoryImpl.kt
index 0fa0fea..3f2ce40 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/MobileConnectionRepositoryImpl.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/MobileConnectionRepositoryImpl.kt
@@ -38,7 +38,6 @@
import com.android.systemui.dagger.qualifiers.Application
import com.android.systemui.dagger.qualifiers.Background
import com.android.systemui.log.table.TableLogBuffer
-import com.android.systemui.log.table.TableLogBufferFactory
import com.android.systemui.log.table.logDiffsForTable
import com.android.systemui.statusbar.pipeline.mobile.data.model.MobileConnectionModel
import com.android.systemui.statusbar.pipeline.mobile.data.model.NetworkNameModel
@@ -70,6 +69,10 @@
import kotlinx.coroutines.flow.onEach
import kotlinx.coroutines.flow.stateIn
+/**
+ * A repository implementation for a typical mobile connection (as opposed to a carrier merged
+ * connection -- see [CarrierMergedConnectionRepository]).
+ */
@Suppress("EXPERIMENTAL_IS_NOT_ENABLED")
@OptIn(ExperimentalCoroutinesApi::class)
class MobileConnectionRepositoryImpl(
@@ -298,18 +301,16 @@
private val logger: ConnectivityPipelineLogger,
private val globalSettings: GlobalSettings,
private val mobileMappingsProxy: MobileMappingsProxy,
- private val logFactory: TableLogBufferFactory,
@Background private val bgDispatcher: CoroutineDispatcher,
@Application private val scope: CoroutineScope,
) {
fun build(
subId: Int,
+ mobileLogger: TableLogBuffer,
defaultNetworkName: NetworkNameModel,
networkNameSeparator: String,
globalMobileDataSettingChangedEvent: Flow<Unit>,
): MobileConnectionRepository {
- val mobileLogger = logFactory.create(tableBufferLogName(subId), 100)
-
return MobileConnectionRepositoryImpl(
context,
subId,
@@ -327,8 +328,4 @@
)
}
}
-
- companion object {
- fun tableBufferLogName(subId: Int): String = "MobileConnectionLog [$subId]"
- }
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/MobileConnectionsRepositoryImpl.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/MobileConnectionsRepositoryImpl.kt
index c88c700..4472e09 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/MobileConnectionsRepositoryImpl.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/MobileConnectionsRepositoryImpl.kt
@@ -46,11 +46,12 @@
import com.android.systemui.statusbar.pipeline.mobile.data.model.MobileConnectivityModel
import com.android.systemui.statusbar.pipeline.mobile.data.model.NetworkNameModel
import com.android.systemui.statusbar.pipeline.mobile.data.model.SubscriptionModel
-import com.android.systemui.statusbar.pipeline.mobile.data.repository.MobileConnectionRepository
import com.android.systemui.statusbar.pipeline.mobile.data.repository.MobileConnectionsRepository
import com.android.systemui.statusbar.pipeline.mobile.util.MobileMappingsProxy
import com.android.systemui.statusbar.pipeline.shared.ConnectivityPipelineLogger
import com.android.systemui.statusbar.pipeline.shared.ConnectivityPipelineLogger.Companion.logInputChange
+import com.android.systemui.statusbar.pipeline.wifi.data.model.WifiNetworkModel
+import com.android.systemui.statusbar.pipeline.wifi.data.repository.WifiRepository
import com.android.systemui.util.settings.GlobalSettings
import javax.inject.Inject
import kotlinx.coroutines.CoroutineDispatcher
@@ -85,9 +86,14 @@
private val context: Context,
@Background private val bgDispatcher: CoroutineDispatcher,
@Application private val scope: CoroutineScope,
- private val mobileConnectionRepositoryFactory: MobileConnectionRepositoryImpl.Factory
+ // Some "wifi networks" should be rendered as a mobile connection, which is why the wifi
+ // repository is an input to the mobile repository.
+ // See [CarrierMergedConnectionRepository] for details.
+ wifiRepository: WifiRepository,
+ private val fullMobileRepoFactory: FullMobileConnectionRepository.Factory,
) : MobileConnectionsRepository {
- private var subIdRepositoryCache: MutableMap<Int, MobileConnectionRepository> = mutableMapOf()
+ private var subIdRepositoryCache: MutableMap<Int, FullMobileConnectionRepository> =
+ mutableMapOf()
private val defaultNetworkName =
NetworkNameModel.Default(
@@ -97,30 +103,43 @@
private val networkNameSeparator: String =
context.getString(R.string.status_bar_network_name_separator)
+ private val carrierMergedSubId: StateFlow<Int?> =
+ wifiRepository.wifiNetwork
+ .mapLatest {
+ if (it is WifiNetworkModel.CarrierMerged) {
+ it.subscriptionId
+ } else {
+ null
+ }
+ }
+ .distinctUntilChanged()
+ .stateIn(scope, started = SharingStarted.WhileSubscribed(), null)
+
+ private val mobileSubscriptionsChangeEvent: Flow<Unit> = conflatedCallbackFlow {
+ val callback =
+ object : SubscriptionManager.OnSubscriptionsChangedListener() {
+ override fun onSubscriptionsChanged() {
+ trySend(Unit)
+ }
+ }
+
+ subscriptionManager.addOnSubscriptionsChangedListener(
+ bgDispatcher.asExecutor(),
+ callback,
+ )
+
+ awaitClose { subscriptionManager.removeOnSubscriptionsChangedListener(callback) }
+ }
+
/**
* State flow that emits the set of mobile data subscriptions, each represented by its own
- * [SubscriptionInfo]. We probably only need the [SubscriptionInfo.getSubscriptionId] of each
- * info object, but for now we keep track of the infos themselves.
+ * [SubscriptionModel].
*/
override val subscriptions: StateFlow<List<SubscriptionModel>> =
- conflatedCallbackFlow {
- val callback =
- object : SubscriptionManager.OnSubscriptionsChangedListener() {
- override fun onSubscriptionsChanged() {
- trySend(Unit)
- }
- }
-
- subscriptionManager.addOnSubscriptionsChangedListener(
- bgDispatcher.asExecutor(),
- callback,
- )
-
- awaitClose { subscriptionManager.removeOnSubscriptionsChangedListener(callback) }
- }
+ merge(mobileSubscriptionsChangeEvent, carrierMergedSubId)
.mapLatest { fetchSubscriptionsList().map { it.toSubscriptionModel() } }
.logInputChange(logger, "onSubscriptionsChanged")
- .onEach { infos -> dropUnusedReposFromCache(infos) }
+ .onEach { infos -> updateRepos(infos) }
.stateIn(scope, started = SharingStarted.WhileSubscribed(), listOf())
/** StateFlow that keeps track of the current active mobile data subscription */
@@ -173,7 +192,7 @@
.distinctUntilChanged()
.logInputChange(logger, "defaultMobileIconGroup")
- override fun getRepoForSubId(subId: Int): MobileConnectionRepository {
+ override fun getRepoForSubId(subId: Int): FullMobileConnectionRepository {
if (!isValidSubId(subId)) {
throw IllegalArgumentException(
"subscriptionId $subId is not in the list of valid subscriptions"
@@ -251,15 +270,27 @@
@VisibleForTesting fun getSubIdRepoCache() = subIdRepositoryCache
- private fun createRepositoryForSubId(subId: Int): MobileConnectionRepository {
- return mobileConnectionRepositoryFactory.build(
+ private fun createRepositoryForSubId(subId: Int): FullMobileConnectionRepository {
+ return fullMobileRepoFactory.build(
subId,
+ isCarrierMerged(subId),
defaultNetworkName,
networkNameSeparator,
globalMobileDataSettingChangedEvent,
)
}
+ private fun updateRepos(newInfos: List<SubscriptionModel>) {
+ dropUnusedReposFromCache(newInfos)
+ subIdRepositoryCache.forEach { (subId, repo) ->
+ repo.setIsCarrierMerged(isCarrierMerged(subId))
+ }
+ }
+
+ private fun isCarrierMerged(subId: Int): Boolean {
+ return subId == carrierMergedSubId.value
+ }
+
private fun dropUnusedReposFromCache(newInfos: List<SubscriptionModel>) {
// Remove any connection repository from the cache that isn't in the new set of IDs. They
// will get garbage collected once their subscribers go away
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/domain/interactor/MobileIconInteractor.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/domain/interactor/MobileIconInteractor.kt
index 9427c6b..003df24 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/domain/interactor/MobileIconInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/domain/interactor/MobileIconInteractor.kt
@@ -22,8 +22,8 @@
import com.android.systemui.log.table.TableLogBuffer
import com.android.systemui.statusbar.pipeline.mobile.data.model.DataConnectionState.Connected
import com.android.systemui.statusbar.pipeline.mobile.data.model.NetworkNameModel
+import com.android.systemui.statusbar.pipeline.mobile.data.model.ResolvedNetworkType
import com.android.systemui.statusbar.pipeline.mobile.data.repository.MobileConnectionRepository
-import com.android.systemui.statusbar.pipeline.mobile.data.repository.MobileConnectionRepository.Companion.DEFAULT_NUM_LEVELS
import com.android.systemui.statusbar.pipeline.shared.data.model.DataActivityModel
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.ExperimentalCoroutinesApi
@@ -138,7 +138,11 @@
defaultMobileIconMapping,
defaultMobileIconGroup,
) { info, mapping, defaultGroup ->
- mapping[info.resolvedNetworkType.lookupKey] ?: defaultGroup
+ when (info.resolvedNetworkType) {
+ is ResolvedNetworkType.CarrierMergedNetworkType ->
+ info.resolvedNetworkType.iconGroupOverride
+ else -> mapping[info.resolvedNetworkType.lookupKey] ?: defaultGroup
+ }
}
.stateIn(scope, SharingStarted.WhileSubscribed(), defaultMobileIconGroup.value)
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/wifi/data/model/WifiNetworkModel.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/wifi/data/model/WifiNetworkModel.kt
index 4251d18..da2daf2 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/wifi/data/model/WifiNetworkModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/wifi/data/model/WifiNetworkModel.kt
@@ -16,13 +16,18 @@
package com.android.systemui.statusbar.pipeline.wifi.data.model
+import android.telephony.SubscriptionManager.INVALID_SUBSCRIPTION_ID
import androidx.annotation.VisibleForTesting
import com.android.systemui.log.table.TableRowLogger
import com.android.systemui.log.table.Diffable
+import com.android.systemui.statusbar.pipeline.mobile.data.repository.MobileConnectionRepository.Companion.DEFAULT_NUM_LEVELS
/** Provides information about the current wifi network. */
sealed class WifiNetworkModel : Diffable<WifiNetworkModel> {
+ // TODO(b/238425913): Have a better, more unified strategy for diff-logging instead of
+ // copy-pasting the column names for each sub-object.
+
/**
* A model representing that we couldn't fetch any wifi information.
*
@@ -41,8 +46,43 @@
override fun logFull(row: TableRowLogger) {
row.logChange(COL_NETWORK_TYPE, TYPE_UNAVAILABLE)
row.logChange(COL_NETWORK_ID, NETWORK_ID_DEFAULT)
+ row.logChange(COL_SUB_ID, SUB_ID_DEFAULT)
row.logChange(COL_VALIDATED, false)
row.logChange(COL_LEVEL, LEVEL_DEFAULT)
+ row.logChange(COL_NUM_LEVELS, NUM_LEVELS_DEFAULT)
+ row.logChange(COL_SSID, null)
+ row.logChange(COL_PASSPOINT_ACCESS_POINT, false)
+ row.logChange(COL_ONLINE_SIGN_UP, false)
+ row.logChange(COL_PASSPOINT_NAME, null)
+ }
+ }
+
+ /**
+ * A model representing that the wifi information we received was invalid in some way.
+ */
+ data class Invalid(
+ /** A description of why the wifi information was invalid. */
+ val invalidReason: String,
+ ) : WifiNetworkModel() {
+ override fun toString() = "WifiNetwork.Invalid[$invalidReason]"
+ override fun logDiffs(prevVal: WifiNetworkModel, row: TableRowLogger) {
+ if (prevVal !is Invalid) {
+ logFull(row)
+ return
+ }
+
+ if (invalidReason != prevVal.invalidReason) {
+ row.logChange(COL_NETWORK_TYPE, "$TYPE_UNAVAILABLE $invalidReason")
+ }
+ }
+
+ override fun logFull(row: TableRowLogger) {
+ row.logChange(COL_NETWORK_TYPE, "$TYPE_UNAVAILABLE $invalidReason")
+ row.logChange(COL_NETWORK_ID, NETWORK_ID_DEFAULT)
+ row.logChange(COL_SUB_ID, SUB_ID_DEFAULT)
+ row.logChange(COL_VALIDATED, false)
+ row.logChange(COL_LEVEL, LEVEL_DEFAULT)
+ row.logChange(COL_NUM_LEVELS, NUM_LEVELS_DEFAULT)
row.logChange(COL_SSID, null)
row.logChange(COL_PASSPOINT_ACCESS_POINT, false)
row.logChange(COL_ONLINE_SIGN_UP, false)
@@ -59,18 +99,21 @@
return
}
- if (prevVal is CarrierMerged) {
- // The only difference between CarrierMerged and Inactive is the type
- row.logChange(COL_NETWORK_TYPE, TYPE_INACTIVE)
- return
- }
-
- // When changing from Active to Inactive, we need to log diffs to all the fields.
- logFullNonActiveNetwork(TYPE_INACTIVE, row)
+ // When changing to Inactive, we need to log diffs to all the fields.
+ logFull(row)
}
override fun logFull(row: TableRowLogger) {
- logFullNonActiveNetwork(TYPE_INACTIVE, row)
+ row.logChange(COL_NETWORK_TYPE, TYPE_INACTIVE)
+ row.logChange(COL_NETWORK_ID, NETWORK_ID_DEFAULT)
+ row.logChange(COL_SUB_ID, SUB_ID_DEFAULT)
+ row.logChange(COL_VALIDATED, false)
+ row.logChange(COL_LEVEL, LEVEL_DEFAULT)
+ row.logChange(COL_NUM_LEVELS, NUM_LEVELS_DEFAULT)
+ row.logChange(COL_SSID, null)
+ row.logChange(COL_PASSPOINT_ACCESS_POINT, false)
+ row.logChange(COL_ONLINE_SIGN_UP, false)
+ row.logChange(COL_PASSPOINT_NAME, null)
}
}
@@ -80,22 +123,75 @@
*
* See [android.net.wifi.WifiInfo.isCarrierMerged] for more information.
*/
- object CarrierMerged : WifiNetworkModel() {
- override fun toString() = "WifiNetwork.CarrierMerged"
+ data class CarrierMerged(
+ /**
+ * The [android.net.Network.netId] we received from
+ * [android.net.ConnectivityManager.NetworkCallback] in association with this wifi network.
+ *
+ * Importantly, **not** [android.net.wifi.WifiInfo.getNetworkId].
+ */
+ val networkId: Int,
+
+ /**
+ * The subscription ID that this connection represents.
+ *
+ * Comes from [android.net.wifi.WifiInfo.getSubscriptionId].
+ *
+ * Per that method, this value must not be [INVALID_SUBSCRIPTION_ID] (if it was invalid,
+ * then this is *not* a carrier merged network).
+ */
+ val subscriptionId: Int,
+
+ /**
+ * The signal level, guaranteed to be 0 <= level <= numberOfLevels.
+ */
+ val level: Int,
+
+ /**
+ * The maximum possible level.
+ */
+ val numberOfLevels: Int = DEFAULT_NUM_LEVELS,
+ ) : WifiNetworkModel() {
+ init {
+ require(level in MIN_VALID_LEVEL..numberOfLevels) {
+ "0 <= wifi level <= $numberOfLevels required; level was $level"
+ }
+ require(subscriptionId != INVALID_SUBSCRIPTION_ID) {
+ "subscription ID cannot be invalid"
+ }
+ }
override fun logDiffs(prevVal: WifiNetworkModel, row: TableRowLogger) {
- if (prevVal is CarrierMerged) {
+ if (prevVal !is CarrierMerged) {
+ logFull(row)
return
}
- if (prevVal is Inactive) {
- // The only difference between CarrierMerged and Inactive is the type.
- row.logChange(COL_NETWORK_TYPE, TYPE_CARRIER_MERGED)
- return
+ if (prevVal.networkId != networkId) {
+ row.logChange(COL_NETWORK_ID, networkId)
}
+ if (prevVal.subscriptionId != subscriptionId) {
+ row.logChange(COL_SUB_ID, subscriptionId)
+ }
+ if (prevVal.level != level) {
+ row.logChange(COL_LEVEL, level)
+ }
+ if (prevVal.numberOfLevels != numberOfLevels) {
+ row.logChange(COL_NUM_LEVELS, numberOfLevels)
+ }
+ }
- // When changing from Active to CarrierMerged, we need to log diffs to all the fields.
- logFullNonActiveNetwork(TYPE_CARRIER_MERGED, row)
+ override fun logFull(row: TableRowLogger) {
+ row.logChange(COL_NETWORK_TYPE, TYPE_CARRIER_MERGED)
+ row.logChange(COL_NETWORK_ID, networkId)
+ row.logChange(COL_SUB_ID, subscriptionId)
+ row.logChange(COL_VALIDATED, true)
+ row.logChange(COL_LEVEL, level)
+ row.logChange(COL_NUM_LEVELS, numberOfLevels)
+ row.logChange(COL_SSID, null)
+ row.logChange(COL_PASSPOINT_ACCESS_POINT, false)
+ row.logChange(COL_ONLINE_SIGN_UP, false)
+ row.logChange(COL_PASSPOINT_NAME, null)
}
}
@@ -137,38 +233,50 @@
override fun logDiffs(prevVal: WifiNetworkModel, row: TableRowLogger) {
if (prevVal !is Active) {
- row.logChange(COL_NETWORK_TYPE, TYPE_ACTIVE)
+ logFull(row)
+ return
}
- if (prevVal !is Active || prevVal.networkId != networkId) {
+ if (prevVal.networkId != networkId) {
row.logChange(COL_NETWORK_ID, networkId)
}
- if (prevVal !is Active || prevVal.isValidated != isValidated) {
+ if (prevVal.isValidated != isValidated) {
row.logChange(COL_VALIDATED, isValidated)
}
- if (prevVal !is Active || prevVal.level != level) {
+ if (prevVal.level != level) {
row.logChange(COL_LEVEL, level)
}
- if (prevVal !is Active || prevVal.ssid != ssid) {
+ if (prevVal.ssid != ssid) {
row.logChange(COL_SSID, ssid)
}
// TODO(b/238425913): The passpoint-related values are frequently never used, so it
// would be great to not log them when they're not used.
- if (prevVal !is Active || prevVal.isPasspointAccessPoint != isPasspointAccessPoint) {
+ if (prevVal.isPasspointAccessPoint != isPasspointAccessPoint) {
row.logChange(COL_PASSPOINT_ACCESS_POINT, isPasspointAccessPoint)
}
- if (prevVal !is Active ||
- prevVal.isOnlineSignUpForPasspointAccessPoint !=
+ if (prevVal.isOnlineSignUpForPasspointAccessPoint !=
isOnlineSignUpForPasspointAccessPoint) {
row.logChange(COL_ONLINE_SIGN_UP, isOnlineSignUpForPasspointAccessPoint)
}
- if (prevVal !is Active ||
- prevVal.passpointProviderFriendlyName != passpointProviderFriendlyName) {
+ if (prevVal.passpointProviderFriendlyName != passpointProviderFriendlyName) {
row.logChange(COL_PASSPOINT_NAME, passpointProviderFriendlyName)
}
}
+ override fun logFull(row: TableRowLogger) {
+ row.logChange(COL_NETWORK_TYPE, TYPE_ACTIVE)
+ row.logChange(COL_NETWORK_ID, networkId)
+ row.logChange(COL_SUB_ID, null)
+ row.logChange(COL_VALIDATED, isValidated)
+ row.logChange(COL_LEVEL, level)
+ row.logChange(COL_NUM_LEVELS, null)
+ row.logChange(COL_SSID, ssid)
+ row.logChange(COL_PASSPOINT_ACCESS_POINT, isPasspointAccessPoint)
+ row.logChange(COL_ONLINE_SIGN_UP, isOnlineSignUpForPasspointAccessPoint)
+ row.logChange(COL_PASSPOINT_NAME, passpointProviderFriendlyName)
+ }
+
override fun toString(): String {
// Only include the passpoint-related values in the string if we have them. (Most
// networks won't have them so they'll be mostly clutter.)
@@ -189,21 +297,13 @@
companion object {
@VisibleForTesting
- internal const val MIN_VALID_LEVEL = 0
- @VisibleForTesting
internal const val MAX_VALID_LEVEL = 4
}
}
- internal fun logFullNonActiveNetwork(type: String, row: TableRowLogger) {
- row.logChange(COL_NETWORK_TYPE, type)
- row.logChange(COL_NETWORK_ID, NETWORK_ID_DEFAULT)
- row.logChange(COL_VALIDATED, false)
- row.logChange(COL_LEVEL, LEVEL_DEFAULT)
- row.logChange(COL_SSID, null)
- row.logChange(COL_PASSPOINT_ACCESS_POINT, false)
- row.logChange(COL_ONLINE_SIGN_UP, false)
- row.logChange(COL_PASSPOINT_NAME, null)
+ companion object {
+ @VisibleForTesting
+ internal const val MIN_VALID_LEVEL = 0
}
}
@@ -214,12 +314,16 @@
const val COL_NETWORK_TYPE = "type"
const val COL_NETWORK_ID = "networkId"
+const val COL_SUB_ID = "subscriptionId"
const val COL_VALIDATED = "isValidated"
const val COL_LEVEL = "level"
+const val COL_NUM_LEVELS = "maxLevel"
const val COL_SSID = "ssid"
const val COL_PASSPOINT_ACCESS_POINT = "isPasspointAccessPoint"
const val COL_ONLINE_SIGN_UP = "isOnlineSignUpForPasspointAccessPoint"
const val COL_PASSPOINT_NAME = "passpointProviderFriendlyName"
val LEVEL_DEFAULT: String? = null
+val NUM_LEVELS_DEFAULT: String? = null
val NETWORK_ID_DEFAULT: String? = null
+val SUB_ID_DEFAULT: String? = null
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/wifi/data/repository/demo/DemoModeWifiDataSource.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/wifi/data/repository/demo/DemoModeWifiDataSource.kt
index c588945..caac8fa 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/wifi/data/repository/demo/DemoModeWifiDataSource.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/wifi/data/repository/demo/DemoModeWifiDataSource.kt
@@ -22,6 +22,7 @@
import com.android.systemui.dagger.qualifiers.Application
import com.android.systemui.demomode.DemoMode.COMMAND_NETWORK
import com.android.systemui.demomode.DemoModeController
+import com.android.systemui.statusbar.pipeline.mobile.data.repository.MobileConnectionRepository.Companion.DEFAULT_NUM_LEVELS
import com.android.systemui.statusbar.pipeline.wifi.data.repository.demo.model.FakeWifiEventModel
import javax.inject.Inject
import kotlinx.coroutines.CoroutineScope
@@ -43,10 +44,10 @@
private fun Bundle.toWifiEvent(): FakeWifiEventModel? {
val wifi = getString("wifi") ?: return null
- return if (wifi == "show") {
- activeWifiEvent()
- } else {
- FakeWifiEventModel.WifiDisabled
+ return when (wifi) {
+ "show" -> activeWifiEvent()
+ "carriermerged" -> carrierMergedWifiEvent()
+ else -> FakeWifiEventModel.WifiDisabled
}
}
@@ -64,6 +65,14 @@
)
}
+ private fun Bundle.carrierMergedWifiEvent(): FakeWifiEventModel.CarrierMerged {
+ val subId = getString("slot")?.toInt() ?: DEFAULT_CARRIER_MERGED_SUB_ID
+ val level = getString("level")?.toInt() ?: 0
+ val numberOfLevels = getString("numlevels")?.toInt() ?: DEFAULT_NUM_LEVELS
+
+ return FakeWifiEventModel.CarrierMerged(subId, level, numberOfLevels)
+ }
+
private fun String.toActivity(): Int =
when (this) {
"inout" -> WifiManager.TrafficStateCallback.DATA_ACTIVITY_INOUT
@@ -71,4 +80,8 @@
"out" -> WifiManager.TrafficStateCallback.DATA_ACTIVITY_OUT
else -> WifiManager.TrafficStateCallback.DATA_ACTIVITY_NONE
}
+
+ companion object {
+ const val DEFAULT_CARRIER_MERGED_SUB_ID = 10
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/wifi/data/repository/demo/DemoWifiRepository.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/wifi/data/repository/demo/DemoWifiRepository.kt
index be3d7d4..e161b3e 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/wifi/data/repository/demo/DemoWifiRepository.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/wifi/data/repository/demo/DemoWifiRepository.kt
@@ -66,6 +66,7 @@
private fun processEvent(event: FakeWifiEventModel) =
when (event) {
is FakeWifiEventModel.Wifi -> processEnabledWifiState(event)
+ is FakeWifiEventModel.CarrierMerged -> processCarrierMergedWifiState(event)
is FakeWifiEventModel.WifiDisabled -> processDisabledWifiState()
}
@@ -85,6 +86,14 @@
_wifiNetwork.value = event.toWifiNetworkModel()
}
+ private fun processCarrierMergedWifiState(event: FakeWifiEventModel.CarrierMerged) {
+ _isWifiEnabled.value = true
+ _isWifiDefault.value = true
+ // TODO(b/238425913): Support activity in demo mode.
+ _wifiActivity.value = DataActivityModel(hasActivityIn = false, hasActivityOut = false)
+ _wifiNetwork.value = event.toCarrierMergedModel()
+ }
+
private fun FakeWifiEventModel.Wifi.toWifiNetworkModel(): WifiNetworkModel =
WifiNetworkModel.Active(
networkId = DEMO_NET_ID,
@@ -99,6 +108,14 @@
passpointProviderFriendlyName = null,
)
+ private fun FakeWifiEventModel.CarrierMerged.toCarrierMergedModel(): WifiNetworkModel =
+ WifiNetworkModel.CarrierMerged(
+ networkId = DEMO_NET_ID,
+ subscriptionId = subscriptionId,
+ level = level,
+ numberOfLevels = numberOfLevels,
+ )
+
companion object {
private const val DEMO_NET_ID = 1234
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/wifi/data/repository/demo/model/FakeWifiEventModel.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/wifi/data/repository/demo/model/FakeWifiEventModel.kt
index 2353fb8..518f8ce 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/wifi/data/repository/demo/model/FakeWifiEventModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/wifi/data/repository/demo/model/FakeWifiEventModel.kt
@@ -29,5 +29,11 @@
val validated: Boolean?,
) : FakeWifiEventModel
+ data class CarrierMerged(
+ val subscriptionId: Int,
+ val level: Int,
+ val numberOfLevels: Int,
+ ) : FakeWifiEventModel
+
object WifiDisabled : FakeWifiEventModel
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/wifi/data/repository/prod/WifiRepositoryImpl.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/wifi/data/repository/prod/WifiRepositoryImpl.kt
index c47c20d..d26499c 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/wifi/data/repository/prod/WifiRepositoryImpl.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/wifi/data/repository/prod/WifiRepositoryImpl.kt
@@ -29,6 +29,7 @@
import android.net.wifi.WifiInfo
import android.net.wifi.WifiManager
import android.net.wifi.WifiManager.TrafficStateCallback
+import android.telephony.SubscriptionManager.INVALID_SUBSCRIPTION_ID
import com.android.settingslib.Utils
import com.android.systemui.broadcast.BroadcastDispatcher
import com.android.systemui.common.coroutine.ConflatedCallbackFlow.conflatedCallbackFlow
@@ -269,7 +270,19 @@
wifiManager: WifiManager,
): WifiNetworkModel {
return if (wifiInfo.isCarrierMerged) {
- WifiNetworkModel.CarrierMerged
+ if (wifiInfo.subscriptionId == INVALID_SUBSCRIPTION_ID) {
+ WifiNetworkModel.Invalid(CARRIER_MERGED_INVALID_SUB_ID_REASON)
+ } else {
+ WifiNetworkModel.CarrierMerged(
+ networkId = network.getNetId(),
+ subscriptionId = wifiInfo.subscriptionId,
+ level = wifiManager.calculateSignalLevel(wifiInfo.rssi),
+ // The WiFi signal level returned by WifiManager#calculateSignalLevel start
+ // from 0, so WifiManager#getMaxSignalLevel + 1 represents the total level
+ // buckets count.
+ numberOfLevels = wifiManager.maxSignalLevel + 1,
+ )
+ }
} else {
WifiNetworkModel.Active(
network.getNetId(),
@@ -302,6 +315,9 @@
.build()
private const val WIFI_NETWORK_CALLBACK_NAME = "wifiNetworkModel"
+
+ private const val CARRIER_MERGED_INVALID_SUB_ID_REASON =
+ "Wifi network was carrier merged but had invalid sub ID"
}
@SysUISingleton
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/wifi/domain/interactor/WifiInteractor.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/wifi/domain/interactor/WifiInteractor.kt
index 980560a..86dcd18 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/wifi/domain/interactor/WifiInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/wifi/domain/interactor/WifiInteractor.kt
@@ -66,6 +66,7 @@
override val ssid: Flow<String?> = wifiRepository.wifiNetwork.map { info ->
when (info) {
is WifiNetworkModel.Unavailable -> null
+ is WifiNetworkModel.Invalid -> null
is WifiNetworkModel.Inactive -> null
is WifiNetworkModel.CarrierMerged -> null
is WifiNetworkModel.Active -> when {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/wifi/ui/viewmodel/WifiViewModel.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/wifi/ui/viewmodel/WifiViewModel.kt
index 824b597..95431af 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/wifi/ui/viewmodel/WifiViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/wifi/ui/viewmodel/WifiViewModel.kt
@@ -83,6 +83,7 @@
private fun WifiNetworkModel.icon(): WifiIcon {
return when (this) {
is WifiNetworkModel.Unavailable -> WifiIcon.Hidden
+ is WifiNetworkModel.Invalid -> WifiIcon.Hidden
is WifiNetworkModel.CarrierMerged -> WifiIcon.Hidden
is WifiNetworkModel.Inactive -> WifiIcon.Visible(
res = WIFI_NO_NETWORK,
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardQsUserSwitchController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardQsUserSwitchController.java
index f63d652..c8ee647 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardQsUserSwitchController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardQsUserSwitchController.java
@@ -160,7 +160,7 @@
mStatusBarStateController = statusBarStateController;
mKeyguardVisibilityHelper = new KeyguardVisibilityHelper(mView,
keyguardStateController, dozeParameters,
- screenOffAnimationController, /* animateYPos= */ false);
+ screenOffAnimationController, /* animateYPos= */ false, /* logBuffer= */ null);
mUserSwitchDialogController = userSwitchDialogController;
mUiEventLogger = uiEventLogger;
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardUserSwitcherController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardUserSwitcherController.java
index c150654..e9f0dcb 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardUserSwitcherController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardUserSwitcherController.java
@@ -173,7 +173,7 @@
mUserSwitcherController, this);
mKeyguardVisibilityHelper = new KeyguardVisibilityHelper(mView,
keyguardStateController, dozeParameters,
- screenOffAnimationController, /* animateYPos= */ false);
+ screenOffAnimationController, /* animateYPos= */ false, /* logBuffer= */ null);
mBackground = new KeyguardUserSwitcherScrim(context);
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/RemoteInputView.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/RemoteInputView.java
index c9ed0cb..f8c17e8 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/RemoteInputView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/RemoteInputView.java
@@ -109,6 +109,8 @@
private static final long FOCUS_ANIMATION_FADE_IN_DELAY = 33;
private static final long FOCUS_ANIMATION_FADE_IN_DURATION = 83;
private static final float FOCUS_ANIMATION_MIN_SCALE = 0.5f;
+ private static final long DEFOCUS_ANIMATION_FADE_OUT_DELAY = 120;
+ private static final long DEFOCUS_ANIMATION_CROSSFADE_DELAY = 180;
public final Object mToken = new Object();
@@ -421,7 +423,7 @@
}
@VisibleForTesting
- void onDefocus(boolean animate, boolean logClose) {
+ void onDefocus(boolean animate, boolean logClose, @Nullable Runnable doAfterDefocus) {
mController.removeRemoteInput(mEntry, mToken);
mEntry.remoteInputText = mEditText.getText();
@@ -431,18 +433,20 @@
ViewGroup parent = (ViewGroup) getParent();
if (animate && parent != null && mIsFocusAnimationFlagActive) {
-
ViewGroup grandParent = (ViewGroup) parent.getParent();
ViewGroupOverlay overlay = parent.getOverlay();
+ View actionsContainer = getActionsContainerLayout();
+ int actionsContainerHeight =
+ actionsContainer != null ? actionsContainer.getHeight() : 0;
// After adding this RemoteInputView to the overlay of the parent (and thus removing
// it from the parent itself), the parent will shrink in height. This causes the
// overlay to be moved. To correct the position of the overlay we need to offset it.
- int overlayOffsetY = getMaxSiblingHeight() - getHeight();
+ int overlayOffsetY = actionsContainerHeight - getHeight();
overlay.add(this);
if (grandParent != null) grandParent.setClipChildren(false);
- Animator animator = getDefocusAnimator(overlayOffsetY);
+ Animator animator = getDefocusAnimator(actionsContainer, overlayOffsetY);
View self = this;
animator.addListener(new AnimatorListenerAdapter() {
@Override
@@ -454,8 +458,12 @@
if (mWrapper != null) {
mWrapper.setRemoteInputVisible(false);
}
+ if (doAfterDefocus != null) {
+ doAfterDefocus.run();
+ }
}
});
+ if (actionsContainer != null) actionsContainer.setAlpha(0f);
animator.start();
} else if (animate && mRevealParams != null && mRevealParams.radius > 0) {
@@ -474,6 +482,7 @@
reveal.start();
} else {
setVisibility(GONE);
+ if (doAfterDefocus != null) doAfterDefocus.run();
if (mWrapper != null) {
mWrapper.setRemoteInputVisible(false);
}
@@ -596,10 +605,8 @@
/**
* Focuses the RemoteInputView and animates its appearance
- *
- * @param crossFadeView view that will be crossfaded during the appearance animation
*/
- public void focusAnimated(View crossFadeView) {
+ public void focusAnimated() {
if (!mIsFocusAnimationFlagActive && getVisibility() != VISIBLE
&& mRevealParams != null) {
android.animation.Animator animator = mRevealParams.createCircularRevealAnimator(this);
@@ -609,7 +616,7 @@
} else if (mIsFocusAnimationFlagActive && getVisibility() != VISIBLE) {
mIsAnimatingAppearance = true;
setAlpha(0f);
- Animator focusAnimator = getFocusAnimator(crossFadeView);
+ Animator focusAnimator = getFocusAnimator(getActionsContainerLayout());
focusAnimator.addListener(new AnimatorListenerAdapter() {
@Override
public void onAnimationEnd(Animator animation, boolean isReverse) {
@@ -661,6 +668,23 @@
}
private void reset() {
+ if (mIsFocusAnimationFlagActive) {
+ mProgressBar.setVisibility(INVISIBLE);
+ mResetting = true;
+ mSending = false;
+ onDefocus(true /* animate */, false /* logClose */, () -> {
+ mEntry.remoteInputTextWhenReset = SpannedString.valueOf(mEditText.getText());
+ mEditText.getText().clear();
+ mEditText.setEnabled(isAggregatedVisible());
+ mSendButton.setVisibility(VISIBLE);
+ mController.removeSpinning(mEntry.getKey(), mToken);
+ updateSendButton();
+ setAttachment(null);
+ mResetting = false;
+ });
+ return;
+ }
+
mResetting = true;
mSending = false;
mEntry.remoteInputTextWhenReset = SpannedString.valueOf(mEditText.getText());
@@ -671,7 +695,7 @@
mProgressBar.setVisibility(INVISIBLE);
mController.removeSpinning(mEntry.getKey(), mToken);
updateSendButton();
- onDefocus(false /* animate */, false /* logClose */);
+ onDefocus(false /* animate */, false /* logClose */, null /* doAfterDefocus */);
setAttachment(null);
mResetting = false;
@@ -825,23 +849,22 @@
}
/**
- * @return max sibling height (0 in case of no siblings)
+ * @return action button container view (i.e. ViewGroup containing Reply button etc.)
*/
- public int getMaxSiblingHeight() {
+ public View getActionsContainerLayout() {
ViewGroup parentView = (ViewGroup) getParent();
- int maxHeight = 0;
- if (parentView == null) return 0;
- for (int i = 0; i < parentView.getChildCount(); i++) {
- View siblingView = parentView.getChildAt(i);
- if (siblingView != this) maxHeight = Math.max(maxHeight, siblingView.getHeight());
- }
- return maxHeight;
+ if (parentView == null) return null;
+ return parentView.findViewById(com.android.internal.R.id.actions_container_layout);
}
/**
* Creates an animator for the focus animation.
+ *
+ * @param fadeOutView View that will be faded out during the focus animation.
*/
- private Animator getFocusAnimator(View crossFadeView) {
+ private Animator getFocusAnimator(@Nullable View fadeOutView) {
+ final AnimatorSet animatorSet = new AnimatorSet();
+
final Animator alphaAnimator = ObjectAnimator.ofFloat(this, View.ALPHA, 0f, 1f);
alphaAnimator.setStartDelay(FOCUS_ANIMATION_FADE_IN_DELAY);
alphaAnimator.setDuration(FOCUS_ANIMATION_FADE_IN_DURATION);
@@ -854,30 +877,36 @@
scaleAnimator.setDuration(FOCUS_ANIMATION_TOTAL_DURATION);
scaleAnimator.setInterpolator(InterpolatorsAndroidX.FAST_OUT_SLOW_IN);
- final Animator crossFadeViewAlphaAnimator =
- ObjectAnimator.ofFloat(crossFadeView, View.ALPHA, 1f, 0f);
- crossFadeViewAlphaAnimator.setDuration(FOCUS_ANIMATION_CROSSFADE_DURATION);
- crossFadeViewAlphaAnimator.setInterpolator(InterpolatorsAndroidX.LINEAR);
- alphaAnimator.addListener(new AnimatorListenerAdapter() {
- @Override
- public void onAnimationEnd(Animator animation, boolean isReverse) {
- crossFadeView.setAlpha(1f);
- }
- });
-
- final AnimatorSet animatorSet = new AnimatorSet();
- animatorSet.playTogether(alphaAnimator, scaleAnimator, crossFadeViewAlphaAnimator);
+ if (fadeOutView == null) {
+ animatorSet.playTogether(alphaAnimator, scaleAnimator);
+ } else {
+ final Animator fadeOutViewAlphaAnimator =
+ ObjectAnimator.ofFloat(fadeOutView, View.ALPHA, 1f, 0f);
+ fadeOutViewAlphaAnimator.setDuration(FOCUS_ANIMATION_CROSSFADE_DURATION);
+ fadeOutViewAlphaAnimator.setInterpolator(InterpolatorsAndroidX.LINEAR);
+ animatorSet.addListener(new AnimatorListenerAdapter() {
+ @Override
+ public void onAnimationEnd(Animator animation, boolean isReverse) {
+ fadeOutView.setAlpha(1f);
+ }
+ });
+ animatorSet.playTogether(alphaAnimator, scaleAnimator, fadeOutViewAlphaAnimator);
+ }
return animatorSet;
}
/**
* Creates an animator for the defocus animation.
*
- * @param offsetY The RemoteInputView will be offset by offsetY during the animation
+ * @param fadeInView View that will be faded in during the defocus animation.
+ * @param offsetY The RemoteInputView will be offset by offsetY during the animation
*/
- private Animator getDefocusAnimator(int offsetY) {
+ private Animator getDefocusAnimator(@Nullable View fadeInView, int offsetY) {
+ final AnimatorSet animatorSet = new AnimatorSet();
+
final Animator alphaAnimator = ObjectAnimator.ofFloat(this, View.ALPHA, 1f, 0f);
- alphaAnimator.setDuration(FOCUS_ANIMATION_CROSSFADE_DURATION);
+ alphaAnimator.setDuration(FOCUS_ANIMATION_FADE_IN_DURATION);
+ alphaAnimator.setStartDelay(DEFOCUS_ANIMATION_FADE_OUT_DELAY);
alphaAnimator.setInterpolator(InterpolatorsAndroidX.LINEAR);
ValueAnimator scaleAnimator = ValueAnimator.ofFloat(1f, FOCUS_ANIMATION_MIN_SCALE);
@@ -893,8 +922,17 @@
}
});
- final AnimatorSet animatorSet = new AnimatorSet();
- animatorSet.playTogether(alphaAnimator, scaleAnimator);
+ if (fadeInView == null) {
+ animatorSet.playTogether(alphaAnimator, scaleAnimator);
+ } else {
+ fadeInView.forceHasOverlappingRendering(false);
+ Animator fadeInViewAlphaAnimator =
+ ObjectAnimator.ofFloat(fadeInView, View.ALPHA, 0f, 1f);
+ fadeInViewAlphaAnimator.setDuration(FOCUS_ANIMATION_FADE_IN_DURATION);
+ fadeInViewAlphaAnimator.setInterpolator(InterpolatorsAndroidX.LINEAR);
+ fadeInViewAlphaAnimator.setStartDelay(DEFOCUS_ANIMATION_CROSSFADE_DELAY);
+ animatorSet.playTogether(alphaAnimator, scaleAnimator, fadeInViewAlphaAnimator);
+ }
return animatorSet;
}
@@ -1011,7 +1049,8 @@
if (isFocusable() && isEnabled()) {
setInnerFocusable(false);
if (mRemoteInputView != null) {
- mRemoteInputView.onDefocus(animate, true /* logClose */);
+ mRemoteInputView
+ .onDefocus(animate, true /* logClose */, null /* doAfterDefocus */);
}
mShowImeOnInputConnection = false;
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/tv/notifications/TvNotificationAdapter.java b/packages/SystemUI/src/com/android/systemui/statusbar/tv/notifications/TvNotificationAdapter.java
index 3b1a4db..3362097 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/tv/notifications/TvNotificationAdapter.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/tv/notifications/TvNotificationAdapter.java
@@ -16,6 +16,7 @@
package com.android.systemui.statusbar.tv.notifications;
+import android.app.BroadcastOptions;
import android.app.Notification;
import android.app.PendingIntent;
import android.service.notification.StatusBarNotification;
@@ -100,7 +101,9 @@
public void onClick(View v) {
try {
if (mPendingIntent != null) {
- mPendingIntent.send();
+ BroadcastOptions options = BroadcastOptions.makeBasic();
+ options.setInteractive(true);
+ mPendingIntent.send(options.toBundle());
}
} catch (PendingIntent.CanceledException e) {
Log.d(TAG, "Pending intent canceled for : " + mPendingIntent);
diff --git a/packages/SystemUI/src/com/android/systemui/stylus/StylusFirstUsageListener.kt b/packages/SystemUI/src/com/android/systemui/stylus/StylusFirstUsageListener.kt
deleted file mode 100644
index 154c6e2..0000000
--- a/packages/SystemUI/src/com/android/systemui/stylus/StylusFirstUsageListener.kt
+++ /dev/null
@@ -1,136 +0,0 @@
-/*
- * 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 com.android.systemui.stylus
-
-import android.content.Context
-import android.hardware.BatteryState
-import android.hardware.input.InputManager
-import android.os.Handler
-import android.util.Log
-import android.view.InputDevice
-import androidx.annotation.VisibleForTesting
-import com.android.systemui.CoreStartable
-import com.android.systemui.dagger.SysUISingleton
-import com.android.systemui.dagger.qualifiers.Background
-import com.android.systemui.flags.FeatureFlags
-import com.android.systemui.flags.Flags
-import java.util.concurrent.Executor
-import javax.inject.Inject
-
-/**
- * A listener that detects when a stylus has first been used, by detecting 1) the presence of an
- * internal SOURCE_STYLUS with a battery, or 2) any added SOURCE_STYLUS device with a bluetooth
- * address.
- */
-@SysUISingleton
-class StylusFirstUsageListener
-@Inject
-constructor(
- private val context: Context,
- private val inputManager: InputManager,
- private val stylusManager: StylusManager,
- private val featureFlags: FeatureFlags,
- @Background private val executor: Executor,
- @Background private val handler: Handler,
-) : CoreStartable, StylusManager.StylusCallback, InputManager.InputDeviceBatteryListener {
-
- // Set must be only accessed from the background handler, which is the same handler that
- // runs the StylusManager callbacks.
- private val internalStylusDeviceIds: MutableSet<Int> = mutableSetOf()
- @VisibleForTesting var hasStarted = false
-
- override fun start() {
- if (true) return // TODO(b/261826950): remove on main
- if (hasStarted) return
- if (!featureFlags.isEnabled(Flags.TRACK_STYLUS_EVER_USED)) return
- if (inputManager.isStylusEverUsed(context)) return
- if (!hostDeviceSupportsStylusInput()) return
-
- hasStarted = true
- inputManager.inputDeviceIds.forEach(this::onStylusAdded)
- stylusManager.registerCallback(this)
- stylusManager.startListener()
- }
-
- override fun onStylusAdded(deviceId: Int) {
- if (!hasStarted) return
-
- val device = inputManager.getInputDevice(deviceId) ?: return
- if (device.isExternal || !device.supportsSource(InputDevice.SOURCE_STYLUS)) return
-
- try {
- inputManager.addInputDeviceBatteryListener(deviceId, executor, this)
- internalStylusDeviceIds += deviceId
- } catch (e: SecurityException) {
- Log.e(TAG, "$e: Failed to register battery listener for $deviceId ${device.name}.")
- }
- }
-
- override fun onStylusRemoved(deviceId: Int) {
- if (!hasStarted) return
-
- if (!internalStylusDeviceIds.contains(deviceId)) return
- try {
- inputManager.removeInputDeviceBatteryListener(deviceId, this)
- internalStylusDeviceIds.remove(deviceId)
- } catch (e: SecurityException) {
- Log.e(TAG, "$e: Failed to remove registered battery listener for $deviceId.")
- }
- }
-
- override fun onStylusBluetoothConnected(deviceId: Int, btAddress: String) {
- if (!hasStarted) return
-
- onRemoteDeviceFound()
- }
-
- override fun onBatteryStateChanged(
- deviceId: Int,
- eventTimeMillis: Long,
- batteryState: BatteryState
- ) {
- if (!hasStarted) return
-
- if (batteryState.isPresent) {
- onRemoteDeviceFound()
- }
- }
-
- private fun onRemoteDeviceFound() {
- inputManager.setStylusEverUsed(context, true)
- cleanupListeners()
- }
-
- private fun cleanupListeners() {
- stylusManager.unregisterCallback(this)
- handler.post {
- internalStylusDeviceIds.forEach {
- inputManager.removeInputDeviceBatteryListener(it, this)
- }
- }
- }
-
- private fun hostDeviceSupportsStylusInput(): Boolean {
- return inputManager.inputDeviceIds
- .asSequence()
- .mapNotNull { inputManager.getInputDevice(it) }
- .any { it.supportsSource(InputDevice.SOURCE_STYLUS) && !it.isExternal }
- }
-
- companion object {
- private val TAG = StylusFirstUsageListener::class.simpleName.orEmpty()
- }
-}
diff --git a/packages/SystemUI/src/com/android/systemui/stylus/StylusManager.kt b/packages/SystemUI/src/com/android/systemui/stylus/StylusManager.kt
index 302d6a9..b22af3b 100644
--- a/packages/SystemUI/src/com/android/systemui/stylus/StylusManager.kt
+++ b/packages/SystemUI/src/com/android/systemui/stylus/StylusManager.kt
@@ -18,6 +18,8 @@
import android.bluetooth.BluetoothAdapter
import android.bluetooth.BluetoothDevice
+import android.content.Context
+import android.hardware.BatteryState
import android.hardware.input.InputManager
import android.os.Handler
import android.util.ArrayMap
@@ -25,6 +27,8 @@
import android.view.InputDevice
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.dagger.qualifiers.Background
+import com.android.systemui.flags.FeatureFlags
+import com.android.systemui.flags.Flags
import java.util.concurrent.CopyOnWriteArrayList
import java.util.concurrent.Executor
import javax.inject.Inject
@@ -37,25 +41,37 @@
class StylusManager
@Inject
constructor(
+ private val context: Context,
private val inputManager: InputManager,
private val bluetoothAdapter: BluetoothAdapter?,
@Background private val handler: Handler,
@Background private val executor: Executor,
-) : InputManager.InputDeviceListener, BluetoothAdapter.OnMetadataChangedListener {
+ private val featureFlags: FeatureFlags,
+) :
+ InputManager.InputDeviceListener,
+ InputManager.InputDeviceBatteryListener,
+ BluetoothAdapter.OnMetadataChangedListener {
private val stylusCallbacks: CopyOnWriteArrayList<StylusCallback> = CopyOnWriteArrayList()
private val stylusBatteryCallbacks: CopyOnWriteArrayList<StylusBatteryCallback> =
CopyOnWriteArrayList()
// This map should only be accessed on the handler
private val inputDeviceAddressMap: MutableMap<Int, String?> = ArrayMap()
+ // This variable should only be accessed on the handler
+ private var hasStarted: Boolean = false
/**
* Starts listening to InputManager InputDevice events. Will also load the InputManager snapshot
* at time of starting.
*/
fun startListener() {
- addExistingStylusToMap()
- inputManager.registerInputDeviceListener(this, handler)
+ handler.post {
+ if (hasStarted) return@post
+ hasStarted = true
+ addExistingStylusToMap()
+
+ inputManager.registerInputDeviceListener(this, handler)
+ }
}
/** Registers a StylusCallback to listen to stylus events. */
@@ -77,26 +93,33 @@
}
override fun onInputDeviceAdded(deviceId: Int) {
+ if (!hasStarted) return
+
val device: InputDevice = inputManager.getInputDevice(deviceId) ?: return
if (!device.supportsSource(InputDevice.SOURCE_STYLUS)) return
- // TODO(b/257936830): get address once input api available
- val btAddress: String? = null
+ if (!device.isExternal) {
+ registerBatteryListener(deviceId)
+ }
+
+ val btAddress: String? = device.bluetoothAddress
inputDeviceAddressMap[deviceId] = btAddress
executeStylusCallbacks { cb -> cb.onStylusAdded(deviceId) }
if (btAddress != null) {
+ onStylusUsed()
onStylusBluetoothConnected(btAddress)
executeStylusCallbacks { cb -> cb.onStylusBluetoothConnected(deviceId, btAddress) }
}
}
override fun onInputDeviceChanged(deviceId: Int) {
+ if (!hasStarted) return
+
val device: InputDevice = inputManager.getInputDevice(deviceId) ?: return
if (!device.supportsSource(InputDevice.SOURCE_STYLUS)) return
- // TODO(b/257936830): get address once input api available
- val currAddress: String? = null
+ val currAddress: String? = device.bluetoothAddress
val prevAddress: String? = inputDeviceAddressMap[deviceId]
inputDeviceAddressMap[deviceId] = currAddress
@@ -112,7 +135,10 @@
}
override fun onInputDeviceRemoved(deviceId: Int) {
+ if (!hasStarted) return
+
if (!inputDeviceAddressMap.contains(deviceId)) return
+ unregisterBatteryListener(deviceId)
val btAddress: String? = inputDeviceAddressMap[deviceId]
inputDeviceAddressMap.remove(deviceId)
@@ -124,13 +150,14 @@
}
override fun onMetadataChanged(device: BluetoothDevice, key: Int, value: ByteArray?) {
- handler.post executeMetadataChanged@{
- if (key != BluetoothDevice.METADATA_MAIN_CHARGING || value == null)
- return@executeMetadataChanged
+ handler.post {
+ if (!hasStarted) return@post
+
+ if (key != BluetoothDevice.METADATA_MAIN_CHARGING || value == null) return@post
val inputDeviceId: Int =
inputDeviceAddressMap.filterValues { it == device.address }.keys.firstOrNull()
- ?: return@executeMetadataChanged
+ ?: return@post
val isCharging = String(value) == "true"
@@ -140,6 +167,24 @@
}
}
+ override fun onBatteryStateChanged(
+ deviceId: Int,
+ eventTimeMillis: Long,
+ batteryState: BatteryState
+ ) {
+ handler.post {
+ if (!hasStarted) return@post
+
+ if (batteryState.isPresent) {
+ onStylusUsed()
+ }
+
+ executeStylusBatteryCallbacks { cb ->
+ cb.onStylusUsiBatteryStateChanged(deviceId, eventTimeMillis, batteryState)
+ }
+ }
+ }
+
private fun onStylusBluetoothConnected(btAddress: String) {
val device: BluetoothDevice = bluetoothAdapter?.getRemoteDevice(btAddress) ?: return
try {
@@ -158,6 +203,20 @@
}
}
+ /**
+ * An InputDevice that supports [InputDevice.SOURCE_STYLUS] may still be present even when a
+ * physical stylus device has never been used. This method is run when 1) a USI stylus battery
+ * event happens, or 2) a bluetooth stylus is connected, as they are both indicators that a
+ * physical stylus device has actually been used.
+ */
+ private fun onStylusUsed() {
+ if (!featureFlags.isEnabled(Flags.TRACK_STYLUS_EVER_USED)) return
+ if (inputManager.isStylusEverUsed(context)) return
+
+ inputManager.setStylusEverUsed(context, true)
+ executeStylusCallbacks { cb -> cb.onStylusFirstUsed() }
+ }
+
private fun executeStylusCallbacks(run: (cb: StylusCallback) -> Unit) {
stylusCallbacks.forEach(run)
}
@@ -166,31 +225,68 @@
stylusBatteryCallbacks.forEach(run)
}
+ private fun registerBatteryListener(deviceId: Int) {
+ try {
+ inputManager.addInputDeviceBatteryListener(deviceId, executor, this)
+ } catch (e: SecurityException) {
+ Log.e(TAG, "$e: Failed to register battery listener for $deviceId.")
+ }
+ }
+
+ private fun unregisterBatteryListener(deviceId: Int) {
+ // If deviceId wasn't registered, the result is a no-op, so an "is registered"
+ // check is not needed.
+ try {
+ inputManager.removeInputDeviceBatteryListener(deviceId, this)
+ } catch (e: SecurityException) {
+ Log.e(TAG, "$e: Failed to remove registered battery listener for $deviceId.")
+ }
+ }
+
private fun addExistingStylusToMap() {
for (deviceId: Int in inputManager.inputDeviceIds) {
val device: InputDevice = inputManager.getInputDevice(deviceId) ?: continue
if (device.supportsSource(InputDevice.SOURCE_STYLUS)) {
- // TODO(b/257936830): get address once input api available
- inputDeviceAddressMap[deviceId] = null
+ inputDeviceAddressMap[deviceId] = device.bluetoothAddress
+
+ if (!device.isExternal) { // TODO(b/263556967): add supportsUsi check once available
+ // For most devices, an active (non-bluetooth) stylus is represented by an
+ // internal InputDevice. This InputDevice will be present in InputManager
+ // before CoreStartables run, and will not be removed.
+ // In many cases, it reports the battery level of the stylus.
+ registerBatteryListener(deviceId)
+ }
}
}
}
- /** Callback interface to receive events from the StylusManager. */
+ /**
+ * Callback interface to receive events from the StylusManager. All callbacks are run on the
+ * same background handler.
+ */
interface StylusCallback {
fun onStylusAdded(deviceId: Int) {}
fun onStylusRemoved(deviceId: Int) {}
fun onStylusBluetoothConnected(deviceId: Int, btAddress: String) {}
fun onStylusBluetoothDisconnected(deviceId: Int, btAddress: String) {}
+ fun onStylusFirstUsed() {}
}
- /** Callback interface to receive stylus battery events from the StylusManager. */
+ /**
+ * Callback interface to receive stylus battery events from the StylusManager. All callbacks are
+ * runs on the same background handler.
+ */
interface StylusBatteryCallback {
fun onStylusBluetoothChargingStateChanged(
inputDeviceId: Int,
btDevice: BluetoothDevice,
isCharging: Boolean
) {}
+ fun onStylusUsiBatteryStateChanged(
+ deviceId: Int,
+ eventTimeMillis: Long,
+ batteryState: BatteryState,
+ ) {}
}
companion object {
diff --git a/packages/SystemUI/src/com/android/systemui/stylus/StylusUsiPowerStartable.kt b/packages/SystemUI/src/com/android/systemui/stylus/StylusUsiPowerStartable.kt
index 11233dd..5a8850a 100644
--- a/packages/SystemUI/src/com/android/systemui/stylus/StylusUsiPowerStartable.kt
+++ b/packages/SystemUI/src/com/android/systemui/stylus/StylusUsiPowerStartable.kt
@@ -18,14 +18,11 @@
import android.hardware.BatteryState
import android.hardware.input.InputManager
-import android.util.Log
import android.view.InputDevice
import com.android.systemui.CoreStartable
import com.android.systemui.dagger.SysUISingleton
-import com.android.systemui.dagger.qualifiers.Background
import com.android.systemui.flags.FeatureFlags
import com.android.systemui.flags.Flags
-import java.util.concurrent.Executor
import javax.inject.Inject
/**
@@ -40,16 +37,7 @@
private val inputManager: InputManager,
private val stylusUsiPowerUi: StylusUsiPowerUI,
private val featureFlags: FeatureFlags,
- @Background private val executor: Executor,
-) : CoreStartable, StylusManager.StylusCallback, InputManager.InputDeviceBatteryListener {
-
- override fun onStylusAdded(deviceId: Int) {
- val device = inputManager.getInputDevice(deviceId) ?: return
-
- if (!device.isExternal) {
- registerBatteryListener(deviceId)
- }
- }
+) : CoreStartable, StylusManager.StylusCallback, StylusManager.StylusBatteryCallback {
override fun onStylusBluetoothConnected(deviceId: Int, btAddress: String) {
stylusUsiPowerUi.refresh()
@@ -59,57 +47,30 @@
stylusUsiPowerUi.refresh()
}
- override fun onStylusRemoved(deviceId: Int) {
- val device = inputManager.getInputDevice(deviceId) ?: return
-
- if (!device.isExternal) {
- unregisterBatteryListener(deviceId)
- }
- }
-
- override fun onBatteryStateChanged(
+ override fun onStylusUsiBatteryStateChanged(
deviceId: Int,
eventTimeMillis: Long,
batteryState: BatteryState
) {
- if (batteryState.isPresent) {
- stylusUsiPowerUi.updateBatteryState(batteryState)
- }
- }
-
- private fun registerBatteryListener(deviceId: Int) {
- try {
- inputManager.addInputDeviceBatteryListener(deviceId, executor, this)
- } catch (e: SecurityException) {
- Log.e(TAG, "$e: Failed to register battery listener for $deviceId.")
- }
- }
-
- private fun unregisterBatteryListener(deviceId: Int) {
- try {
- inputManager.removeInputDeviceBatteryListener(deviceId, this)
- } catch (e: SecurityException) {
- Log.e(TAG, "$e: Failed to unregister battery listener for $deviceId.")
+ if (batteryState.isPresent && batteryState.capacity > 0f) {
+ stylusUsiPowerUi.updateBatteryState(deviceId, batteryState)
}
}
override fun start() {
if (!featureFlags.isEnabled(Flags.ENABLE_USI_BATTERY_NOTIFICATIONS)) return
- addBatteryListenerForInternalStyluses()
+ if (!hostDeviceSupportsStylusInput()) return
+ stylusUsiPowerUi.init()
stylusManager.registerCallback(this)
stylusManager.startListener()
}
- private fun addBatteryListenerForInternalStyluses() {
- // For most devices, an active stylus is represented by an internal InputDevice.
- // This InputDevice will be present in InputManager before CoreStartables run,
- // and will not be removed. In many cases, it reports the battery level of the stylus.
- inputManager.inputDeviceIds
+ private fun hostDeviceSupportsStylusInput(): Boolean {
+ return inputManager.inputDeviceIds
.asSequence()
.mapNotNull { inputManager.getInputDevice(it) }
- .filter { it.supportsSource(InputDevice.SOURCE_STYLUS) }
- .forEach { onStylusAdded(it.id) }
+ .any { it.supportsSource(InputDevice.SOURCE_STYLUS) && !it.isExternal }
}
companion object {
diff --git a/packages/SystemUI/src/com/android/systemui/stylus/StylusUsiPowerUI.kt b/packages/SystemUI/src/com/android/systemui/stylus/StylusUsiPowerUI.kt
index 70a5b36..8d5e01c 100644
--- a/packages/SystemUI/src/com/android/systemui/stylus/StylusUsiPowerUI.kt
+++ b/packages/SystemUI/src/com/android/systemui/stylus/StylusUsiPowerUI.kt
@@ -18,17 +18,21 @@
import android.Manifest
import android.app.PendingIntent
+import android.content.ActivityNotFoundException
import android.content.BroadcastReceiver
import android.content.Context
import android.content.Intent
import android.content.IntentFilter
import android.hardware.BatteryState
import android.hardware.input.InputManager
+import android.os.Bundle
import android.os.Handler
import android.os.UserHandle
+import android.util.Log
import android.view.InputDevice
import androidx.core.app.NotificationCompat
import androidx.core.app.NotificationManagerCompat
+import com.android.internal.annotations.VisibleForTesting
import com.android.systemui.R
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.dagger.qualifiers.Background
@@ -53,6 +57,7 @@
// These values must only be accessed on the handler.
private var batteryCapacity = 1.0f
private var suppressed = false
+ private var inputDeviceId: Int? = null
fun init() {
val filter =
@@ -87,10 +92,12 @@
}
}
- fun updateBatteryState(batteryState: BatteryState) {
+ fun updateBatteryState(deviceId: Int, batteryState: BatteryState) {
handler.post updateBattery@{
- if (batteryState.capacity == batteryCapacity) return@updateBattery
+ if (batteryState.capacity == batteryCapacity || batteryState.capacity <= 0f)
+ return@updateBattery
+ inputDeviceId = deviceId
batteryCapacity = batteryState.capacity
refresh()
}
@@ -123,13 +130,13 @@
.setSmallIcon(R.drawable.ic_power_low)
.setDeleteIntent(getPendingBroadcast(ACTION_DISMISSED_LOW_BATTERY))
.setContentIntent(getPendingBroadcast(ACTION_CLICKED_LOW_BATTERY))
- .setContentTitle(context.getString(R.string.stylus_battery_low))
- .setContentText(
+ .setContentTitle(
context.getString(
- R.string.battery_low_percent_format,
+ R.string.stylus_battery_low_percentage,
NumberFormat.getPercentInstance().format(batteryCapacity)
)
)
+ .setContentText(context.getString(R.string.stylus_battery_low_subtitle))
.setPriority(NotificationCompat.PRIORITY_DEFAULT)
.setLocalOnly(true)
.setAutoCancel(true)
@@ -150,23 +157,41 @@
}
private fun getPendingBroadcast(action: String): PendingIntent? {
- return PendingIntent.getBroadcastAsUser(
+ return PendingIntent.getBroadcast(
context,
0,
- Intent(action),
+ Intent(action).setPackage(context.packageName),
PendingIntent.FLAG_IMMUTABLE,
- UserHandle.CURRENT
)
}
- private val receiver: BroadcastReceiver =
+ @VisibleForTesting
+ internal val receiver: BroadcastReceiver =
object : BroadcastReceiver() {
override fun onReceive(context: Context, intent: Intent) {
when (intent.action) {
ACTION_DISMISSED_LOW_BATTERY -> updateSuppression(true)
ACTION_CLICKED_LOW_BATTERY -> {
updateSuppression(true)
- // TODO(b/261584943): open USI device details page
+ if (inputDeviceId == null) return
+
+ val args = Bundle()
+ args.putInt(KEY_DEVICE_INPUT_ID, inputDeviceId!!)
+ try {
+ context.startActivity(
+ Intent(ACTION_STYLUS_USI_DETAILS)
+ .putExtra(KEY_SETTINGS_FRAGMENT_ARGS, args)
+ .addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP)
+ .addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
+ )
+ } catch (e: ActivityNotFoundException) {
+ // In the rare scenario where the Settings app manifest doesn't contain
+ // the USI details activity, ignore the intent.
+ Log.e(
+ StylusUsiPowerUI::class.java.simpleName,
+ "Cannot open USI details page."
+ )
+ }
}
}
}
@@ -177,9 +202,13 @@
// https://source.chromium.org/chromium/chromium/src/+/main:ash/system/power/peripheral_battery_notifier.cc;l=41
private const val LOW_BATTERY_THRESHOLD = 0.16f
- private val USI_NOTIFICATION_ID = R.string.stylus_battery_low
+ private val USI_NOTIFICATION_ID = R.string.stylus_battery_low_percentage
- private const val ACTION_DISMISSED_LOW_BATTERY = "StylusUsiPowerUI.dismiss"
- private const val ACTION_CLICKED_LOW_BATTERY = "StylusUsiPowerUI.click"
+ @VisibleForTesting const val ACTION_DISMISSED_LOW_BATTERY = "StylusUsiPowerUI.dismiss"
+ @VisibleForTesting const val ACTION_CLICKED_LOW_BATTERY = "StylusUsiPowerUI.click"
+ @VisibleForTesting
+ const val ACTION_STYLUS_USI_DETAILS = "com.android.settings.STYLUS_USI_DETAILS_SETTINGS"
+ @VisibleForTesting const val KEY_DEVICE_INPUT_ID = "device_input_id"
+ @VisibleForTesting const val KEY_SETTINGS_FRAGMENT_ARGS = ":settings:show_fragment_args"
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/unfold/UnfoldTransitionModule.kt b/packages/SystemUI/src/com/android/systemui/unfold/UnfoldTransitionModule.kt
index 59ad24a..2709da3 100644
--- a/packages/SystemUI/src/com/android/systemui/unfold/UnfoldTransitionModule.kt
+++ b/packages/SystemUI/src/com/android/systemui/unfold/UnfoldTransitionModule.kt
@@ -17,6 +17,9 @@
package com.android.systemui.unfold
import android.content.Context
+import android.hardware.devicestate.DeviceStateManager
+import com.android.systemui.dagger.qualifiers.Application
+import com.android.systemui.dagger.qualifiers.Main
import com.android.systemui.keyguard.LifecycleScreenStatusProvider
import com.android.systemui.unfold.config.UnfoldTransitionConfig
import com.android.systemui.unfold.system.SystemUnfoldSharedModule
@@ -32,6 +35,7 @@
import dagger.Module
import dagger.Provides
import java.util.Optional
+import java.util.concurrent.Executor
import javax.inject.Named
import javax.inject.Singleton
@@ -40,6 +44,20 @@
@Provides @UnfoldTransitionATracePrefix fun tracingTagPrefix() = "systemui"
+ /** A globally available FoldStateListener that allows one to query the fold state. */
+ @Provides
+ @Singleton
+ fun providesFoldStateListener(
+ deviceStateManager: DeviceStateManager,
+ @Application context: Context,
+ @Main executor: Executor
+ ): DeviceStateManager.FoldStateListener {
+ val listener = DeviceStateManager.FoldStateListener(context)
+ deviceStateManager.registerCallback(executor, listener)
+
+ return listener
+ }
+
@Provides
@Singleton
fun providesFoldStateLoggingProvider(
diff --git a/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogImpl.java b/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogImpl.java
index 7d23399..0f9ae39 100644
--- a/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogImpl.java
@@ -1522,6 +1522,7 @@
.setDuration(mDialogHideAnimationDurationMs)
.setInterpolator(new SystemUIInterpolators.LogAccelerateInterpolator())
.withEndAction(() -> mHandler.postDelayed(() -> {
+ mController.notifyVisible(false);
mDialog.dismiss();
tryToRemoveCaptionsTooltip();
mIsAnimatingDismiss = false;
@@ -1535,7 +1536,6 @@
animator.setListener(getJankListener(getDialogView(), TYPE_DISMISS,
mDialogHideAnimationDurationMs)).start();
checkODICaptionsTooltip(true);
- mController.notifyVisible(false);
synchronized (mSafetyWarningLock) {
if (mSafetyWarning != null) {
if (D.BUG) Log.d(TAG, "SafetyWarning dismissed");
diff --git a/packages/SystemUI/src/com/android/systemui/wallet/ui/WalletView.java b/packages/SystemUI/src/com/android/systemui/wallet/ui/WalletView.java
index 1243c47..dfc6392 100644
--- a/packages/SystemUI/src/com/android/systemui/wallet/ui/WalletView.java
+++ b/packages/SystemUI/src/com/android/systemui/wallet/ui/WalletView.java
@@ -20,6 +20,7 @@
import static com.android.systemui.wallet.ui.WalletCardCarousel.CARD_ANIM_ALPHA_DURATION;
import android.annotation.Nullable;
+import android.app.BroadcastOptions;
import android.app.PendingIntent;
import android.content.Context;
import android.content.res.Configuration;
@@ -303,7 +304,10 @@
? mDeviceLockedActionOnClickListener
: v -> {
try {
- walletCard.getPendingIntent().send();
+
+ BroadcastOptions options = BroadcastOptions.makeBasic();
+ options.setInteractive(true);
+ walletCard.getPendingIntent().send(options.toBundle());
} catch (PendingIntent.CanceledException e) {
Log.w(TAG, "Error sending pending intent for wallet card.");
}
diff --git a/packages/SystemUI/tests/src/com/android/keyguard/ClockEventControllerTest.kt b/packages/SystemUI/tests/src/com/android/keyguard/ClockEventControllerTest.kt
index e8f8e25..c76b127 100644
--- a/packages/SystemUI/tests/src/com/android/keyguard/ClockEventControllerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/keyguard/ClockEventControllerTest.kt
@@ -15,6 +15,7 @@
*/
package com.android.keyguard
+import com.android.systemui.statusbar.CommandQueue
import android.content.BroadcastReceiver
import android.testing.AndroidTestingRunner
import android.view.View
@@ -81,8 +82,10 @@
@Mock private lateinit var largeClockEvents: ClockFaceEvents
@Mock private lateinit var parentView: View
@Mock private lateinit var transitionRepository: KeyguardTransitionRepository
+ @Mock private lateinit var commandQueue: CommandQueue
private lateinit var repository: FakeKeyguardRepository
- @Mock private lateinit var logBuffer: LogBuffer
+ @Mock private lateinit var smallLogBuffer: LogBuffer
+ @Mock private lateinit var largeLogBuffer: LogBuffer
private lateinit var underTest: ClockEventController
@Before
@@ -99,7 +102,7 @@
repository = FakeKeyguardRepository()
underTest = ClockEventController(
- KeyguardInteractor(repository = repository),
+ KeyguardInteractor(repository = repository, commandQueue = commandQueue),
KeyguardTransitionInteractor(repository = transitionRepository),
broadcastDispatcher,
batteryController,
@@ -109,7 +112,8 @@
context,
mainExecutor,
bgExecutor,
- logBuffer,
+ smallLogBuffer,
+ largeLogBuffer,
featureFlags
)
underTest.clock = clock
diff --git a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardClockSwitchControllerTest.java b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardClockSwitchControllerTest.java
index c8e7538..9a9acf3 100644
--- a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardClockSwitchControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardClockSwitchControllerTest.java
@@ -48,6 +48,7 @@
import com.android.systemui.plugins.ClockController;
import com.android.systemui.plugins.ClockEvents;
import com.android.systemui.plugins.ClockFaceController;
+import com.android.systemui.plugins.log.LogBuffer;
import com.android.systemui.plugins.statusbar.StatusBarStateController;
import com.android.systemui.shared.clocks.AnimatableClockView;
import com.android.systemui.shared.clocks.ClockRegistry;
@@ -115,6 +116,8 @@
private FrameLayout mLargeClockFrame;
@Mock
private SecureSettings mSecureSettings;
+ @Mock
+ private LogBuffer mLogBuffer;
private final View mFakeSmartspaceView = new View(mContext);
@@ -156,7 +159,8 @@
mSecureSettings,
mExecutor,
mDumpManager,
- mClockEventController
+ mClockEventController,
+ mLogBuffer
);
when(mStatusBarStateController.getState()).thenReturn(StatusBarState.SHADE);
diff --git a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardClockSwitchTest.java b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardClockSwitchTest.java
index 254f953..8dc1e8f 100644
--- a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardClockSwitchTest.java
+++ b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardClockSwitchTest.java
@@ -16,6 +16,7 @@
package com.android.keyguard;
+import static android.view.View.INVISIBLE;
import static android.view.View.VISIBLE;
import static com.android.keyguard.KeyguardClockSwitch.LARGE;
@@ -189,6 +190,7 @@
assertThat(mLargeClockFrame.getAlpha()).isEqualTo(1);
assertThat(mLargeClockFrame.getVisibility()).isEqualTo(VISIBLE);
assertThat(mSmallClockFrame.getAlpha()).isEqualTo(0);
+ assertThat(mSmallClockFrame.getVisibility()).isEqualTo(INVISIBLE);
}
@Test
@@ -198,6 +200,7 @@
assertThat(mLargeClockFrame.getAlpha()).isEqualTo(1);
assertThat(mLargeClockFrame.getVisibility()).isEqualTo(VISIBLE);
assertThat(mSmallClockFrame.getAlpha()).isEqualTo(0);
+ assertThat(mSmallClockFrame.getVisibility()).isEqualTo(INVISIBLE);
}
@Test
@@ -212,6 +215,7 @@
// only big clock is removed at switch
assertThat(mLargeClockFrame.getParent()).isNull();
assertThat(mLargeClockFrame.getAlpha()).isEqualTo(0);
+ assertThat(mLargeClockFrame.getVisibility()).isEqualTo(INVISIBLE);
}
@Test
@@ -223,6 +227,7 @@
// only big clock is removed at switch
assertThat(mLargeClockFrame.getParent()).isNull();
assertThat(mLargeClockFrame.getAlpha()).isEqualTo(0);
+ assertThat(mLargeClockFrame.getVisibility()).isEqualTo(INVISIBLE);
}
@Test
diff --git a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardStatusViewControllerTest.java b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardStatusViewControllerTest.java
index be4bbdf..dfad15d 100644
--- a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardStatusViewControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardStatusViewControllerTest.java
@@ -24,6 +24,7 @@
import android.test.suitebuilder.annotation.SmallTest;
import android.testing.AndroidTestingRunner;
+import com.android.keyguard.logging.KeyguardLogger;
import com.android.systemui.SysuiTestCase;
import com.android.systemui.flags.FeatureFlags;
import com.android.systemui.plugins.ClockAnimations;
@@ -65,6 +66,8 @@
ScreenOffAnimationController mScreenOffAnimationController;
@Captor
private ArgumentCaptor<KeyguardUpdateMonitorCallback> mKeyguardUpdateMonitorCallbackCaptor;
+ @Mock
+ KeyguardLogger mKeyguardLogger;
private KeyguardStatusViewController mController;
@@ -81,7 +84,8 @@
mConfigurationController,
mDozeParameters,
mFeatureFlags,
- mScreenOffAnimationController);
+ mScreenOffAnimationController,
+ mKeyguardLogger);
}
@Test
diff --git a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardUpdateMonitorTest.java b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardUpdateMonitorTest.java
index 539dc55..87dd6a4 100644
--- a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardUpdateMonitorTest.java
+++ b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardUpdateMonitorTest.java
@@ -33,6 +33,9 @@
import static com.android.keyguard.KeyguardUpdateMonitor.DEFAULT_CANCEL_SIGNAL_TIMEOUT;
import static com.android.keyguard.KeyguardUpdateMonitor.HAL_POWER_PRESS_TIMEOUT;
import static com.android.keyguard.KeyguardUpdateMonitor.getCurrentUser;
+import static com.android.systemui.statusbar.policy.DevicePostureController.DEVICE_POSTURE_CLOSED;
+import static com.android.systemui.statusbar.policy.DevicePostureController.DEVICE_POSTURE_OPENED;
+import static com.android.systemui.statusbar.policy.DevicePostureController.DEVICE_POSTURE_UNKNOWN;
import static com.google.common.truth.Truth.assertThat;
@@ -93,6 +96,7 @@
import android.os.RemoteException;
import android.os.UserHandle;
import android.os.UserManager;
+import android.provider.Settings;
import android.service.dreams.IDreamManager;
import android.service.trust.TrustAgentService;
import android.telephony.ServiceState;
@@ -117,6 +121,7 @@
import com.android.keyguard.logging.KeyguardUpdateMonitorLogger;
import com.android.systemui.SysuiTestCase;
import com.android.systemui.biometrics.AuthController;
+import com.android.systemui.biometrics.FingerprintInteractiveToAuthProvider;
import com.android.systemui.broadcast.BroadcastDispatcher;
import com.android.systemui.dump.DumpManager;
import com.android.systemui.log.SessionTracker;
@@ -124,6 +129,7 @@
import com.android.systemui.settings.UserTracker;
import com.android.systemui.statusbar.StatusBarState;
import com.android.systemui.statusbar.phone.KeyguardBypassController;
+import com.android.systemui.statusbar.policy.DevicePostureController;
import com.android.systemui.telephony.TelephonyListenerManager;
import com.android.systemui.util.settings.GlobalSettings;
import com.android.systemui.util.settings.SecureSettings;
@@ -143,6 +149,7 @@
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
+import java.util.Optional;
import java.util.concurrent.Executor;
import java.util.concurrent.atomic.AtomicBoolean;
@@ -192,6 +199,8 @@
@Mock
private DevicePolicyManager mDevicePolicyManager;
@Mock
+ private DevicePostureController mDevicePostureController;
+ @Mock
private IDreamManager mDreamManager;
@Mock
private KeyguardBypassController mKeyguardBypassController;
@@ -234,6 +243,8 @@
@Mock
private GlobalSettings mGlobalSettings;
private FaceWakeUpTriggersConfig mFaceWakeUpTriggersConfig;
+ @Mock
+ private FingerprintInteractiveToAuthProvider mInteractiveToAuthProvider;
private final int mCurrentUserId = 100;
@@ -296,6 +307,7 @@
.thenReturn(new ServiceState());
when(mLockPatternUtils.getLockSettings()).thenReturn(mLockSettings);
when(mAuthController.isUdfpsEnrolled(anyInt())).thenReturn(false);
+ when(mDevicePostureController.getDevicePosture()).thenReturn(DEVICE_POSTURE_UNKNOWN);
mMockitoSession = ExtendedMockito.mockitoSession()
.spyStatic(SubscriptionManager.class)
@@ -307,6 +319,9 @@
when(mUserTracker.getUserId()).thenReturn(mCurrentUserId);
ExtendedMockito.doReturn(mActivityService).when(ActivityManager::getService);
+ mContext.getOrCreateTestableResources().addOverride(
+ com.android.systemui.R.integer.config_face_auth_supported_posture,
+ DEVICE_POSTURE_UNKNOWN);
mFaceWakeUpTriggersConfig = new FaceWakeUpTriggersConfig(
mContext.getResources(),
mGlobalSettings,
@@ -1250,7 +1265,7 @@
}
@Test
- public void testStartsListeningForSfps_whenKeyguardIsVisible_ifRequireScreenOnToAuthEnabled()
+ public void startsListeningForSfps_whenKeyguardIsVisible_ifRequireInteractiveToAuthEnabled()
throws RemoteException {
// SFPS supported and enrolled
final ArrayList<FingerprintSensorPropertiesInternal> props = new ArrayList<>();
@@ -1258,12 +1273,8 @@
when(mAuthController.getSfpsProps()).thenReturn(props);
when(mAuthController.isSfpsEnrolled(anyInt())).thenReturn(true);
- // WHEN require screen on to auth is disabled, and keyguard is not awake
- when(mSecureSettings.getIntForUser(anyString(), anyInt(), anyInt())).thenReturn(0);
- mKeyguardUpdateMonitor.updateSfpsRequireScreenOnToAuthPref();
-
- mContext.getOrCreateTestableResources().addOverride(
- com.android.internal.R.bool.config_requireScreenOnToAuthEnabled, true);
+ // WHEN require interactive to auth is disabled, and keyguard is not awake
+ when(mInteractiveToAuthProvider.isEnabled(anyInt())).thenReturn(false);
// Preconditions for sfps auth to run
keyguardNotGoingAway();
@@ -1279,9 +1290,8 @@
// THEN we should listen for sfps when screen off, because require screen on is disabled
assertThat(mKeyguardUpdateMonitor.shouldListenForFingerprint(false)).isTrue();
- // WHEN require screen on to auth is enabled, and keyguard is not awake
- when(mSecureSettings.getIntForUser(anyString(), anyInt(), anyInt())).thenReturn(1);
- mKeyguardUpdateMonitor.updateSfpsRequireScreenOnToAuthPref();
+ // WHEN require interactive to auth is enabled, and keyguard is not awake
+ when(mInteractiveToAuthProvider.isEnabled(anyInt())).thenReturn(true);
// THEN we shouldn't listen for sfps when screen off, because require screen on is enabled
assertThat(mKeyguardUpdateMonitor.shouldListenForFingerprint(false)).isFalse();
@@ -1295,6 +1305,62 @@
assertThat(mKeyguardUpdateMonitor.shouldListenForFingerprint(false)).isTrue();
}
+ @Test
+ public void notListeningForSfps_whenGoingToSleep_ifRequireInteractiveToAuthEnabled()
+ throws RemoteException {
+ // GIVEN SFPS supported and enrolled
+ final ArrayList<FingerprintSensorPropertiesInternal> props = new ArrayList<>();
+ props.add(newFingerprintSensorPropertiesInternal(TYPE_POWER_BUTTON));
+ when(mAuthController.getSfpsProps()).thenReturn(props);
+ when(mAuthController.isSfpsEnrolled(anyInt())).thenReturn(true);
+
+ // GIVEN Preconditions for sfps auth to run
+ keyguardNotGoingAway();
+ currentUserIsPrimary();
+ currentUserDoesNotHaveTrust();
+ biometricsNotDisabledThroughDevicePolicyManager();
+ biometricsEnabledForCurrentUser();
+ userNotCurrentlySwitching();
+ statusBarShadeIsLocked();
+
+ // WHEN require interactive to auth is enabled & keyguard is going to sleep
+ when(mInteractiveToAuthProvider.isEnabled(anyInt())).thenReturn(true);
+ deviceGoingToSleep();
+
+ mTestableLooper.processAllMessages();
+
+ // THEN we should NOT listen for sfps because device is going to sleep
+ assertThat(mKeyguardUpdateMonitor.shouldListenForFingerprint(false)).isFalse();
+ }
+
+ @Test
+ public void listeningForSfps_whenGoingToSleep_ifRequireInteractiveToAuthDisabled()
+ throws RemoteException {
+ // GIVEN SFPS supported and enrolled
+ final ArrayList<FingerprintSensorPropertiesInternal> props = new ArrayList<>();
+ props.add(newFingerprintSensorPropertiesInternal(TYPE_POWER_BUTTON));
+ when(mAuthController.getSfpsProps()).thenReturn(props);
+ when(mAuthController.isSfpsEnrolled(anyInt())).thenReturn(true);
+
+ // GIVEN Preconditions for sfps auth to run
+ keyguardNotGoingAway();
+ currentUserIsPrimary();
+ currentUserDoesNotHaveTrust();
+ biometricsNotDisabledThroughDevicePolicyManager();
+ biometricsEnabledForCurrentUser();
+ userNotCurrentlySwitching();
+ statusBarShadeIsLocked();
+
+ // WHEN require interactive to auth is disabled & keyguard is going to sleep
+ when(mInteractiveToAuthProvider.isEnabled(anyInt())).thenReturn(false);
+ deviceGoingToSleep();
+
+ mTestableLooper.processAllMessages();
+
+ // THEN we should listen for sfps because screen on to auth is disabled
+ assertThat(mKeyguardUpdateMonitor.shouldListenForFingerprint(false)).isTrue();
+ }
+
private FingerprintSensorPropertiesInternal newFingerprintSensorPropertiesInternal(
@FingerprintSensorProperties.SensorType int sensorType) {
return new FingerprintSensorPropertiesInternal(
@@ -2186,6 +2252,54 @@
eq(true));
}
+ @Test
+ public void testShouldListenForFace_withAuthSupportPostureConfig_returnsTrue()
+ throws RemoteException {
+ mKeyguardUpdateMonitor.mConfigFaceAuthSupportedPosture = DEVICE_POSTURE_CLOSED;
+ keyguardNotGoingAway();
+ bouncerFullyVisibleAndNotGoingToSleep();
+ currentUserIsPrimary();
+ currentUserDoesNotHaveTrust();
+ biometricsNotDisabledThroughDevicePolicyManager();
+ biometricsEnabledForCurrentUser();
+ userNotCurrentlySwitching();
+ supportsFaceDetection();
+
+ deviceInPostureStateOpened();
+ mTestableLooper.processAllMessages();
+ // Should not listen for face when posture state in DEVICE_POSTURE_OPENED
+ assertThat(mKeyguardUpdateMonitor.shouldListenForFace()).isFalse();
+
+ deviceInPostureStateClosed();
+ mTestableLooper.processAllMessages();
+ // Should listen for face when posture state in DEVICE_POSTURE_CLOSED
+ assertThat(mKeyguardUpdateMonitor.shouldListenForFace()).isTrue();
+ }
+
+ @Test
+ public void testShouldListenForFace_withoutAuthSupportPostureConfig_returnsTrue()
+ throws RemoteException {
+ mKeyguardUpdateMonitor.mConfigFaceAuthSupportedPosture = DEVICE_POSTURE_UNKNOWN;
+ keyguardNotGoingAway();
+ bouncerFullyVisibleAndNotGoingToSleep();
+ currentUserIsPrimary();
+ currentUserDoesNotHaveTrust();
+ biometricsNotDisabledThroughDevicePolicyManager();
+ biometricsEnabledForCurrentUser();
+ userNotCurrentlySwitching();
+ supportsFaceDetection();
+
+ deviceInPostureStateClosed();
+ mTestableLooper.processAllMessages();
+ // Whether device in any posture state, always listen for face
+ assertThat(mKeyguardUpdateMonitor.shouldListenForFace()).isTrue();
+
+ deviceInPostureStateOpened();
+ mTestableLooper.processAllMessages();
+ // Whether device in any posture state, always listen for face
+ assertThat(mKeyguardUpdateMonitor.shouldListenForFace()).isTrue();
+ }
+
private void userDeviceLockDown() {
when(mStrongAuthTracker.isUnlockingWithBiometricAllowed(anyBoolean())).thenReturn(false);
when(mStrongAuthTracker.getStrongAuthForUser(mCurrentUserId))
@@ -2265,6 +2379,14 @@
.onAuthenticationAcquired(FINGERPRINT_ACQUIRED_START);
}
+ private void deviceInPostureStateOpened() {
+ mKeyguardUpdateMonitor.mPostureCallback.onPostureChanged(DEVICE_POSTURE_OPENED);
+ }
+
+ private void deviceInPostureStateClosed() {
+ mKeyguardUpdateMonitor.mPostureCallback.onPostureChanged(DEVICE_POSTURE_CLOSED);
+ }
+
private void successfulFingerprintAuth() {
mKeyguardUpdateMonitor.mFingerprintAuthenticationCallback
.onAuthenticationSucceeded(
@@ -2406,7 +2528,8 @@
mPowerManager, mTrustManager, mSubscriptionManager, mUserManager,
mDreamManager, mDevicePolicyManager, mSensorPrivacyManager, mTelephonyManager,
mPackageManager, mFaceManager, mFingerprintManager, mBiometricManager,
- mFaceWakeUpTriggersConfig);
+ mFaceWakeUpTriggersConfig, mDevicePostureController,
+ Optional.of(mInteractiveToAuthProvider));
setStrongAuthTracker(KeyguardUpdateMonitorTest.this.mStrongAuthTracker);
}
diff --git a/packages/SystemUI/tests/src/com/android/keyguard/LockIconViewControllerBaseTest.java b/packages/SystemUI/tests/src/com/android/keyguard/LockIconViewControllerBaseTest.java
index e4c41a7..05bd1e4 100644
--- a/packages/SystemUI/tests/src/com/android/keyguard/LockIconViewControllerBaseTest.java
+++ b/packages/SystemUI/tests/src/com/android/keyguard/LockIconViewControllerBaseTest.java
@@ -49,6 +49,7 @@
import com.android.systemui.keyguard.domain.interactor.KeyguardTransitionInteractor;
import com.android.systemui.plugins.FalsingManager;
import com.android.systemui.plugins.statusbar.StatusBarStateController;
+import com.android.systemui.statusbar.CommandQueue;
import com.android.systemui.statusbar.StatusBarState;
import com.android.systemui.statusbar.VibratorHelper;
import com.android.systemui.statusbar.policy.ConfigurationController;
@@ -91,6 +92,7 @@
protected @Mock AuthRippleController mAuthRippleController;
protected @Mock FeatureFlags mFeatureFlags;
protected @Mock KeyguardTransitionRepository mTransitionRepository;
+ protected @Mock CommandQueue mCommandQueue;
protected FakeExecutor mDelayableExecutor = new FakeExecutor(new FakeSystemClock());
protected LockIconViewController mUnderTest;
@@ -157,7 +159,7 @@
mAuthRippleController,
mResources,
new KeyguardTransitionInteractor(mTransitionRepository),
- new KeyguardInteractor(new FakeKeyguardRepository()),
+ new KeyguardInteractor(new FakeKeyguardRepository(), mCommandQueue),
mFeatureFlags
);
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsControllerOverlayTest.kt b/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsControllerOverlayTest.kt
index c6fa983..7c9d22f 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsControllerOverlayTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsControllerOverlayTest.kt
@@ -124,8 +124,8 @@
.thenReturn(mock(UdfpsBpView::class.java))
whenever(inflater.inflate(R.layout.udfps_keyguard_view, null))
.thenReturn(mock(UdfpsKeyguardView::class.java))
- whenever(inflater.inflate(R.layout.udfps_fpm_other_view, null))
- .thenReturn(mock(UdfpsFpmOtherView::class.java))
+ whenever(inflater.inflate(R.layout.udfps_fpm_empty_view, null))
+ .thenReturn(mock(UdfpsFpmEmptyView::class.java))
whenever(udfpsEnrollView.context).thenReturn(context)
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsControllerTest.java
index 83a6db0..d7b7a7d 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsControllerTest.java
@@ -190,7 +190,7 @@
@Mock
private UdfpsBpView mBpView;
@Mock
- private UdfpsFpmOtherView mFpmOtherView;
+ private UdfpsFpmEmptyView mFpmEmptyView;
@Mock
private UdfpsKeyguardView mKeyguardView;
private final UdfpsAnimationViewController mUdfpsKeyguardViewController =
@@ -240,8 +240,8 @@
.thenReturn(mKeyguardView); // for showOverlay REASON_AUTH_FPM_KEYGUARD
when(mLayoutInflater.inflate(R.layout.udfps_bp_view, null))
.thenReturn(mBpView);
- when(mLayoutInflater.inflate(R.layout.udfps_fpm_other_view, null))
- .thenReturn(mFpmOtherView);
+ when(mLayoutInflater.inflate(R.layout.udfps_fpm_empty_view, null))
+ .thenReturn(mFpmEmptyView);
when(mEnrollView.getContext()).thenReturn(mContext);
when(mKeyguardUpdateMonitor.isFingerprintDetectionRunning()).thenReturn(true);
when(mSessionTracker.getSessionId(anyInt())).thenReturn(
diff --git a/packages/SystemUI/tests/src/com/android/systemui/biometrics/udfps/EllipseOverlapDetectorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/biometrics/udfps/EllipseOverlapDetectorTest.kt
new file mode 100644
index 0000000..af46d9b
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/biometrics/udfps/EllipseOverlapDetectorTest.kt
@@ -0,0 +1,131 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.biometrics.udfps
+
+import android.graphics.Point
+import android.graphics.Rect
+import androidx.test.filters.SmallTest
+import com.android.systemui.SysuiTestCase
+import com.google.common.truth.Truth.assertThat
+import org.junit.Before
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.junit.runners.Parameterized
+import org.junit.runners.Parameterized.Parameters
+import org.mockito.Mockito.spy
+import org.mockito.Mockito.`when` as whenEver
+
+@SmallTest
+@RunWith(Parameterized::class)
+class EllipseOverlapDetectorTest(val testCase: TestCase) : SysuiTestCase() {
+ val underTest = spy(EllipseOverlapDetector(neededPoints = 1))
+
+ @Before
+ fun setUp() {
+ // Use one single center point for testing, required or total number of points may change
+ whenEver(underTest.calculateSensorPoints(SENSOR))
+ .thenReturn(listOf(Point(SENSOR.centerX(), SENSOR.centerY())))
+ }
+
+ @Test
+ fun isGoodOverlap() {
+ val touchData =
+ TOUCH_DATA.copy(
+ x = testCase.x.toFloat(),
+ y = testCase.y.toFloat(),
+ minor = testCase.minor,
+ major = testCase.major
+ )
+ val actual = underTest.isGoodOverlap(touchData, SENSOR)
+
+ assertThat(actual).isEqualTo(testCase.expected)
+ }
+
+ data class TestCase(
+ val x: Int,
+ val y: Int,
+ val minor: Float,
+ val major: Float,
+ val expected: Boolean
+ )
+
+ companion object {
+ @Parameters(name = "{0}")
+ @JvmStatic
+ fun data(): List<TestCase> =
+ listOf(
+ genTestCases(
+ innerXs = listOf(SENSOR.left, SENSOR.right, SENSOR.centerX()),
+ innerYs = listOf(SENSOR.top, SENSOR.bottom, SENSOR.centerY()),
+ outerXs = listOf(SENSOR.left - 1, SENSOR.right + 1),
+ outerYs = listOf(SENSOR.top - 1, SENSOR.bottom + 1),
+ minor = 300f,
+ major = 300f,
+ expected = true
+ ),
+ genTestCases(
+ innerXs = listOf(SENSOR.left, SENSOR.right),
+ innerYs = listOf(SENSOR.top, SENSOR.bottom),
+ outerXs = listOf(SENSOR.left - 1, SENSOR.right + 1),
+ outerYs = listOf(SENSOR.top - 1, SENSOR.bottom + 1),
+ minor = 100f,
+ major = 100f,
+ expected = false
+ )
+ )
+ .flatten()
+ }
+}
+
+/* Placeholder touch parameters. */
+private const val POINTER_ID = 42
+private const val NATIVE_MINOR = 2.71828f
+private const val NATIVE_MAJOR = 3.14f
+private const val ORIENTATION = 0f // used for perfect circles
+private const val TIME = 12345699L
+private const val GESTURE_START = 12345600L
+
+/* Template [NormalizedTouchData]. */
+private val TOUCH_DATA =
+ NormalizedTouchData(
+ POINTER_ID,
+ x = 0f,
+ y = 0f,
+ NATIVE_MINOR,
+ NATIVE_MAJOR,
+ ORIENTATION,
+ TIME,
+ GESTURE_START
+ )
+
+private val SENSOR = Rect(100 /* left */, 200 /* top */, 300 /* right */, 400 /* bottom */)
+
+private fun genTestCases(
+ innerXs: List<Int>,
+ innerYs: List<Int>,
+ outerXs: List<Int>,
+ outerYs: List<Int>,
+ minor: Float,
+ major: Float,
+ expected: Boolean
+): List<EllipseOverlapDetectorTest.TestCase> {
+ return (innerXs + outerXs).flatMap { x ->
+ (innerYs + outerYs).map { y ->
+ EllipseOverlapDetectorTest.TestCase(x, y, minor, major, expected)
+ }
+ }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/biometrics/udfps/SinglePointerTouchProcessorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/biometrics/udfps/SinglePointerTouchProcessorTest.kt
index 95c53b4..56043e30 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/biometrics/udfps/SinglePointerTouchProcessorTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/biometrics/udfps/SinglePointerTouchProcessorTest.kt
@@ -221,6 +221,14 @@
private const val ROTATION_0_NATIVE_DISPLAY_WIDTH = 400
private const val ROTATION_0_NATIVE_DISPLAY_HEIGHT = 600
+/* Placeholder touch parameters. */
+private const val POINTER_ID = 42
+private const val NATIVE_MINOR = 2.71828f
+private const val NATIVE_MAJOR = 3.14f
+private const val ORIENTATION = 1.2345f
+private const val TIME = 12345699L
+private const val GESTURE_START = 12345600L
+
/*
* ROTATION_0 map:
* _ _ _ _
@@ -244,6 +252,7 @@
private val ROTATION_0_INPUTS =
OrientationBasedInputs(
rotation = Surface.ROTATION_0,
+ nativeOrientation = ORIENTATION,
nativeXWithinSensor = ROTATION_0_NATIVE_SENSOR_BOUNDS.exactCenterX(),
nativeYWithinSensor = ROTATION_0_NATIVE_SENSOR_BOUNDS.exactCenterY(),
nativeXOutsideSensor = 250f,
@@ -271,6 +280,7 @@
private val ROTATION_90_INPUTS =
OrientationBasedInputs(
rotation = Surface.ROTATION_90,
+ nativeOrientation = (ORIENTATION - Math.PI.toFloat() / 2),
nativeXWithinSensor = ROTATION_90_NATIVE_SENSOR_BOUNDS.exactCenterX(),
nativeYWithinSensor = ROTATION_90_NATIVE_SENSOR_BOUNDS.exactCenterY(),
nativeXOutsideSensor = 150f,
@@ -304,20 +314,13 @@
private val ROTATION_270_INPUTS =
OrientationBasedInputs(
rotation = Surface.ROTATION_270,
+ nativeOrientation = (ORIENTATION + Math.PI.toFloat() / 2),
nativeXWithinSensor = ROTATION_270_NATIVE_SENSOR_BOUNDS.exactCenterX(),
nativeYWithinSensor = ROTATION_270_NATIVE_SENSOR_BOUNDS.exactCenterY(),
nativeXOutsideSensor = 450f,
nativeYOutsideSensor = 250f,
)
-/* Placeholder touch parameters. */
-private const val POINTER_ID = 42
-private const val NATIVE_MINOR = 2.71828f
-private const val NATIVE_MAJOR = 3.14f
-private const val ORIENTATION = 1.23f
-private const val TIME = 12345699L
-private const val GESTURE_START = 12345600L
-
/* Template [MotionEvent]. */
private val MOTION_EVENT =
obtainMotionEvent(
@@ -352,6 +355,7 @@
*/
private data class OrientationBasedInputs(
@Rotation val rotation: Int,
+ val nativeOrientation: Float,
val nativeXWithinSensor: Float,
val nativeYWithinSensor: Float,
val nativeXOutsideSensor: Float,
@@ -404,6 +408,7 @@
y = nativeY * scaleFactor,
minor = NATIVE_MINOR * scaleFactor,
major = NATIVE_MAJOR * scaleFactor,
+ orientation = orientation.nativeOrientation
)
val expectedTouchData =
NORMALIZED_TOUCH_DATA.copy(
diff --git a/packages/SystemUI/tests/src/com/android/systemui/classifier/BrightLineClassifierTest.java b/packages/SystemUI/tests/src/com/android/systemui/classifier/BrightLineClassifierTest.java
index 0fadc13..e4df754 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/classifier/BrightLineClassifierTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/classifier/BrightLineClassifierTest.java
@@ -106,6 +106,7 @@
mClassifiers.add(mClassifierB);
when(mFalsingDataProvider.getRecentMotionEvents()).thenReturn(mMotionEventList);
when(mKeyguardStateController.isShowing()).thenReturn(true);
+ when(mFalsingDataProvider.isFolded()).thenReturn(true);
mBrightLineFalsingManager = new BrightLineFalsingManager(mFalsingDataProvider,
mMetricsLogger, mClassifiers, mSingleTapClassfier, mLongTapClassifier,
mDoubleTapClassifier, mHistoryTracker, mKeyguardStateController,
@@ -121,6 +122,7 @@
mGestureFinalizedListener = gestureCompleteListenerCaptor.getValue();
mFakeFeatureFlags.set(Flags.FALSING_FOR_LONG_TAPS, true);
mFakeFeatureFlags.set(Flags.MEDIA_FALSING_PENALTY, true);
+ mFakeFeatureFlags.set(Flags.FALSING_OFF_FOR_UNFOLDED, true);
}
@Test
diff --git a/packages/SystemUI/tests/src/com/android/systemui/classifier/BrightLineFalsingManagerTest.java b/packages/SystemUI/tests/src/com/android/systemui/classifier/BrightLineFalsingManagerTest.java
index 4281ee0..ae38eb6 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/classifier/BrightLineFalsingManagerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/classifier/BrightLineFalsingManagerTest.java
@@ -89,25 +89,27 @@
mClassifiers.add(mClassifierA);
when(mFalsingDataProvider.getRecentMotionEvents()).thenReturn(mMotionEventList);
when(mKeyguardStateController.isShowing()).thenReturn(true);
+ when(mFalsingDataProvider.isFolded()).thenReturn(true);
mBrightLineFalsingManager = new BrightLineFalsingManager(mFalsingDataProvider,
mMetricsLogger, mClassifiers, mSingleTapClassifier, mLongTapClassifier,
mDoubleTapClassifier, mHistoryTracker, mKeyguardStateController,
mAccessibilityManager, false, mFakeFeatureFlags);
mFakeFeatureFlags.set(Flags.FALSING_FOR_LONG_TAPS, true);
+ mFakeFeatureFlags.set(Flags.FALSING_OFF_FOR_UNFOLDED, true);
}
@Test
public void testA11yDisablesGesture() {
- assertThat(mBrightLineFalsingManager.isFalseTap(1)).isTrue();
+ assertThat(mBrightLineFalsingManager.isFalseTouch(Classifier.GENERIC)).isTrue();
when(mAccessibilityManager.isTouchExplorationEnabled()).thenReturn(true);
- assertThat(mBrightLineFalsingManager.isFalseTap(1)).isFalse();
+ assertThat(mBrightLineFalsingManager.isFalseTouch(Classifier.GENERIC)).isFalse();
}
@Test
public void testA11yDisablesTap() {
- assertThat(mBrightLineFalsingManager.isFalseTouch(Classifier.GENERIC)).isTrue();
+ assertThat(mBrightLineFalsingManager.isFalseTap(1)).isTrue();
when(mAccessibilityManager.isTouchExplorationEnabled()).thenReturn(true);
- assertThat(mBrightLineFalsingManager.isFalseTouch(Classifier.GENERIC)).isFalse();
+ assertThat(mBrightLineFalsingManager.isFalseTap(1)).isFalse();
}
@@ -179,4 +181,11 @@
when(mFalsingDataProvider.isA11yAction()).thenReturn(true);
assertThat(mBrightLineFalsingManager.isFalseTap(1)).isFalse();
}
+
+ @Test
+ public void testSkipUnfolded() {
+ assertThat(mBrightLineFalsingManager.isFalseTouch(Classifier.GENERIC)).isTrue();
+ when(mFalsingDataProvider.isFolded()).thenReturn(false);
+ assertThat(mBrightLineFalsingManager.isFalseTouch(Classifier.GENERIC)).isFalse();
+ }
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/classifier/ClassifierTest.java b/packages/SystemUI/tests/src/com/android/systemui/classifier/ClassifierTest.java
index 5fa7214..94cf384 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/classifier/ClassifierTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/classifier/ClassifierTest.java
@@ -16,6 +16,7 @@
package com.android.systemui.classifier;
+import android.hardware.devicestate.DeviceStateManager.FoldStateListener;
import android.util.DisplayMetrics;
import android.view.MotionEvent;
@@ -38,6 +39,7 @@
private float mOffsetY = 0;
@Mock
private BatteryController mBatteryController;
+ private FoldStateListener mFoldStateListener = new FoldStateListener(mContext);
private final DockManagerFake mDockManager = new DockManagerFake();
public void setup() {
@@ -47,7 +49,8 @@
displayMetrics.ydpi = 100;
displayMetrics.widthPixels = 1000;
displayMetrics.heightPixels = 1000;
- mDataProvider = new FalsingDataProvider(displayMetrics, mBatteryController, mDockManager);
+ mDataProvider = new FalsingDataProvider(
+ displayMetrics, mBatteryController, mFoldStateListener, mDockManager);
}
@After
diff --git a/packages/SystemUI/tests/src/com/android/systemui/classifier/FalsingDataProviderTest.java b/packages/SystemUI/tests/src/com/android/systemui/classifier/FalsingDataProviderTest.java
index d315c2d..c451a1e7 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/classifier/FalsingDataProviderTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/classifier/FalsingDataProviderTest.java
@@ -24,6 +24,7 @@
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
+import android.hardware.devicestate.DeviceStateManager.FoldStateListener;
import android.testing.AndroidTestingRunner;
import android.util.DisplayMetrics;
import android.view.MotionEvent;
@@ -50,6 +51,8 @@
private FalsingDataProvider mDataProvider;
@Mock
private BatteryController mBatteryController;
+ @Mock
+ private FoldStateListener mFoldStateListener;
private final DockManagerFake mDockManager = new DockManagerFake();
@Before
@@ -61,7 +64,8 @@
displayMetrics.ydpi = 100;
displayMetrics.widthPixels = 1000;
displayMetrics.heightPixels = 1000;
- mDataProvider = new FalsingDataProvider(displayMetrics, mBatteryController, mDockManager);
+ mDataProvider = new FalsingDataProvider(
+ displayMetrics, mBatteryController, mFoldStateListener, mDockManager);
}
@After
@@ -316,4 +320,16 @@
mDataProvider.onA11yAction();
assertThat(mDataProvider.isA11yAction()).isTrue();
}
+
+ @Test
+ public void test_FoldedState_Folded() {
+ when(mFoldStateListener.getFolded()).thenReturn(true);
+ assertThat(mDataProvider.isFolded()).isTrue();
+ }
+
+ @Test
+ public void test_FoldedState_Unfolded() {
+ when(mFoldStateListener.getFolded()).thenReturn(false);
+ assertThat(mDataProvider.isFolded()).isFalse();
+ }
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/controls/controller/ControlsBindingControllerImplTest.kt b/packages/SystemUI/tests/src/com/android/systemui/controls/controller/ControlsBindingControllerImplTest.kt
index 0a81c38..ebbe096 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/controls/controller/ControlsBindingControllerImplTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/controls/controller/ControlsBindingControllerImplTest.kt
@@ -269,6 +269,14 @@
}
@Test
+ fun testBindServiceForPanel() {
+ controller.bindServiceForPanel(TEST_COMPONENT_NAME_1)
+ executor.runAllReady()
+
+ verify(providers[0]).bindServiceForPanel()
+ }
+
+ @Test
fun testSubscribe() {
val controlInfo1 = ControlInfo("id_1", "", "", DeviceTypes.TYPE_UNKNOWN)
val controlInfo2 = ControlInfo("id_2", "", "", DeviceTypes.TYPE_UNKNOWN)
diff --git a/packages/SystemUI/tests/src/com/android/systemui/controls/controller/ControlsControllerImplTest.kt b/packages/SystemUI/tests/src/com/android/systemui/controls/controller/ControlsControllerImplTest.kt
index 1b34706..25f471b 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/controls/controller/ControlsControllerImplTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/controls/controller/ControlsControllerImplTest.kt
@@ -919,6 +919,12 @@
.getFile(ControlsFavoritePersistenceWrapper.FILE_NAME, context.user.identifier)
assertThat(userStructure.file).isNotNull()
}
+
+ @Test
+ fun testBindForPanel() {
+ controller.bindComponentForPanel(TEST_COMPONENT)
+ verify(bindingController).bindServiceForPanel(TEST_COMPONENT)
+ }
}
private class DidRunRunnable() : Runnable {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/controls/controller/ControlsProviderLifecycleManagerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/controls/controller/ControlsProviderLifecycleManagerTest.kt
index af3f24a..da548f7 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/controls/controller/ControlsProviderLifecycleManagerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/controls/controller/ControlsProviderLifecycleManagerTest.kt
@@ -105,6 +105,22 @@
}
@Test
+ fun testBindForPanel() {
+ manager.bindServiceForPanel()
+ executor.runAllReady()
+ assertTrue(context.isBound(componentName))
+ }
+
+ @Test
+ fun testUnbindPanelIsUnbound() {
+ manager.bindServiceForPanel()
+ executor.runAllReady()
+ manager.unbindService()
+ executor.runAllReady()
+ assertFalse(context.isBound(componentName))
+ }
+
+ @Test
fun testNullBinding() {
val mockContext = mock(Context::class.java)
lateinit var serviceConnection: ServiceConnection
diff --git a/packages/SystemUI/tests/src/com/android/systemui/controls/ui/ControlsUiControllerImplTest.kt b/packages/SystemUI/tests/src/com/android/systemui/controls/ui/ControlsUiControllerImplTest.kt
index d172c9a..edc6882 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/controls/ui/ControlsUiControllerImplTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/controls/ui/ControlsUiControllerImplTest.kt
@@ -229,6 +229,15 @@
}
@Test
+ fun testPanelBindsForPanel() {
+ val panel = SelectedItem.PanelItem("App name", ComponentName("pkg", "cls"))
+ setUpPanel(panel)
+
+ underTest.show(parent, {}, context)
+ verify(controlsController).bindComponentForPanel(panel.componentName)
+ }
+
+ @Test
fun testPanelCallsTaskViewFactoryCreate() {
mockLayoutInflater()
val panel = SelectedItem.PanelItem("App name", ComponentName("pkg", "cls"))
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/CustomizationProviderTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/CustomizationProviderTest.kt
index 4659766..0a03b2c 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/CustomizationProviderTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/CustomizationProviderTest.kt
@@ -51,6 +51,7 @@
import com.android.systemui.settings.UserTracker
import com.android.systemui.shared.customization.data.content.CustomizationProviderContract as Contract
import com.android.systemui.shared.keyguard.shared.model.KeyguardQuickAffordanceSlots
+import com.android.systemui.statusbar.CommandQueue
import com.android.systemui.statusbar.policy.KeyguardStateController
import com.android.systemui.util.FakeSharedPreferences
import com.android.systemui.util.mockito.any
@@ -86,9 +87,9 @@
@Mock private lateinit var backgroundHandler: Handler
@Mock private lateinit var previewSurfacePackage: SurfaceControlViewHost.SurfacePackage
@Mock private lateinit var launchAnimator: DialogLaunchAnimator
+ @Mock private lateinit var commandQueue: CommandQueue
private lateinit var underTest: CustomizationProvider
-
private lateinit var testScope: TestScope
@Before
@@ -160,6 +161,7 @@
keyguardInteractor =
KeyguardInteractor(
repository = FakeKeyguardRepository(),
+ commandQueue = commandQueue,
),
registry = mock(),
lockPatternUtils = lockPatternUtils,
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/KeyguardViewMediatorTest.java b/packages/SystemUI/tests/src/com/android/systemui/keyguard/KeyguardViewMediatorTest.java
index 9b0d8db..7c20e3c 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/KeyguardViewMediatorTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/KeyguardViewMediatorTest.java
@@ -29,6 +29,7 @@
import static org.mockito.ArgumentMatchers.anyBoolean;
import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.Mockito.atLeast;
+import static org.mockito.Mockito.clearInvocations;
import static org.mockito.Mockito.eq;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.never;
@@ -66,6 +67,7 @@
import com.android.systemui.colorextraction.SysuiColorExtractor;
import com.android.systemui.dreams.DreamOverlayStateController;
import com.android.systemui.dump.DumpManager;
+import com.android.systemui.flags.FeatureFlags;
import com.android.systemui.navigationbar.NavigationModeController;
import com.android.systemui.settings.UserTracker;
import com.android.systemui.shade.NotificationShadeWindowControllerImpl;
@@ -134,6 +136,7 @@
private @Mock SysuiColorExtractor mColorExtractor;
private @Mock AuthController mAuthController;
private @Mock ShadeExpansionStateManager mShadeExpansionStateManager;
+ private @Mock FeatureFlags mFeatureFlags;
private @Mock ShadeWindowLogger mShadeWindowLogger;
private DeviceConfigProxy mDeviceConfig = new DeviceConfigProxyFake();
private FakeExecutor mUiBgExecutor = new FakeExecutor(new FakeSystemClock());
@@ -483,6 +486,38 @@
assertTrue(mViewMediator.isShowingAndNotOccluded());
}
+ @Test
+ @TestableLooper.RunWithLooper(setAsMainLooper = true)
+ public void testDoKeyguardWhileInteractive_resets() {
+ mViewMediator.setShowingLocked(true);
+ when(mKeyguardStateController.isShowing()).thenReturn(true);
+ TestableLooper.get(this).processAllMessages();
+
+ when(mPowerManager.isInteractive()).thenReturn(true);
+
+ mViewMediator.onSystemReady();
+ TestableLooper.get(this).processAllMessages();
+
+ assertTrue(mViewMediator.isShowingAndNotOccluded());
+ verify(mStatusBarKeyguardViewManager).reset(anyBoolean());
+ }
+
+ @Test
+ @TestableLooper.RunWithLooper(setAsMainLooper = true)
+ public void testDoKeyguardWhileNotInteractive_showsInsteadOfResetting() {
+ mViewMediator.setShowingLocked(true);
+ when(mKeyguardStateController.isShowing()).thenReturn(true);
+ TestableLooper.get(this).processAllMessages();
+
+ when(mPowerManager.isInteractive()).thenReturn(false);
+
+ mViewMediator.onSystemReady();
+ TestableLooper.get(this).processAllMessages();
+
+ assertTrue(mViewMediator.isShowingAndNotOccluded());
+ verify(mStatusBarKeyguardViewManager, never()).reset(anyBoolean());
+ }
+
private void createAndStartViewMediator() {
mViewMediator = new KeyguardViewMediator(
mContext,
@@ -510,6 +545,7 @@
mScreenOnCoordinator,
mInteractionJankMonitor,
mDreamOverlayStateController,
+ mFeatureFlags,
() -> mShadeController,
() -> mNotificationShadeWindowController,
() -> mActivityLaunchAnimator,
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/WakefulnessLifecycleTest.java b/packages/SystemUI/tests/src/com/android/systemui/keyguard/WakefulnessLifecycleTest.java
index f32d76b..39a453d 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/WakefulnessLifecycleTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/WakefulnessLifecycleTest.java
@@ -30,6 +30,7 @@
import com.android.systemui.SysuiTestCase;
import com.android.systemui.dump.DumpManager;
+import com.android.systemui.util.time.FakeSystemClock;
import org.junit.Before;
import org.junit.Test;
@@ -51,7 +52,12 @@
public void setUp() throws Exception {
mWallpaperManager = mock(IWallpaperManager.class);
mWakefulness =
- new WakefulnessLifecycle(mContext, mWallpaperManager, mock(DumpManager.class));
+ new WakefulnessLifecycle(
+ mContext,
+ mWallpaperManager,
+ new FakeSystemClock(),
+ mock(DumpManager.class)
+ );
mWakefulnessObserver = mock(WakefulnessLifecycle.Observer.class);
mWakefulness.addObserver(mWakefulnessObserver);
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/repository/KeyguardRepositoryImplTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/repository/KeyguardRepositoryImplTest.kt
index be712f6..f997d18 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/repository/KeyguardRepositoryImplTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/repository/KeyguardRepositoryImplTest.kt
@@ -24,6 +24,7 @@
import com.android.systemui.SysuiTestCase
import com.android.systemui.biometrics.AuthController
import com.android.systemui.common.shared.model.Position
+import com.android.systemui.coroutines.collectLastValue
import com.android.systemui.doze.DozeHost
import com.android.systemui.doze.DozeMachine
import com.android.systemui.doze.DozeTransitionCallback
@@ -38,14 +39,17 @@
import com.android.systemui.keyguard.shared.model.WakefulnessState
import com.android.systemui.plugins.statusbar.StatusBarStateController
import com.android.systemui.statusbar.phone.BiometricUnlockController
+import com.android.systemui.statusbar.phone.DozeParameters
import com.android.systemui.statusbar.policy.KeyguardStateController
import com.android.systemui.util.mockito.argumentCaptor
import com.android.systemui.util.mockito.whenever
import com.android.systemui.util.mockito.withArgCaptor
import com.google.common.truth.Truth.assertThat
import kotlinx.coroutines.flow.launchIn
+import kotlinx.coroutines.flow.onCompletion
import kotlinx.coroutines.flow.onEach
import kotlinx.coroutines.test.UnconfinedTestDispatcher
+import kotlinx.coroutines.test.runCurrent
import kotlinx.coroutines.test.runTest
import org.junit.Before
import org.junit.Test
@@ -68,6 +72,7 @@
@Mock private lateinit var authController: AuthController
@Mock private lateinit var keyguardUpdateMonitor: KeyguardUpdateMonitor
@Mock private lateinit var dreamOverlayCallbackController: DreamOverlayCallbackController
+ @Mock private lateinit var dozeParameters: DozeParameters
private lateinit var underTest: KeyguardRepositoryImpl
@@ -84,6 +89,7 @@
keyguardStateController,
keyguardUpdateMonitor,
dozeTransitionListener,
+ dozeParameters,
authController,
dreamOverlayCallbackController,
)
@@ -170,6 +176,26 @@
}
@Test
+ fun isAodAvailable() = runTest {
+ val flow = underTest.isAodAvailable
+ var isAodAvailable = collectLastValue(flow)
+ runCurrent()
+
+ val callback =
+ withArgCaptor<DozeParameters.Callback> { verify(dozeParameters).addCallback(capture()) }
+
+ whenever(dozeParameters.getAlwaysOn()).thenReturn(false)
+ callback.onAlwaysOnChange()
+ assertThat(isAodAvailable()).isEqualTo(false)
+
+ whenever(dozeParameters.getAlwaysOn()).thenReturn(true)
+ callback.onAlwaysOnChange()
+ assertThat(isAodAvailable()).isEqualTo(true)
+
+ flow.onCompletion { verify(dozeParameters).removeCallback(callback) }
+ }
+
+ @Test
fun isKeyguardOccluded() =
runTest(UnconfinedTestDispatcher()) {
whenever(keyguardStateController.isOccluded).thenReturn(false)
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/repository/KeyguardTransitionRepositoryTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/repository/KeyguardTransitionRepositoryTest.kt
index 5d2f0eb..32cec09 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/repository/KeyguardTransitionRepositoryTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/repository/KeyguardTransitionRepositoryTest.kt
@@ -104,7 +104,7 @@
val firstTransitionSteps = listWithStep(step = BigDecimal(.1), stop = BigDecimal(.1))
assertSteps(steps.subList(0, 4), firstTransitionSteps, AOD, LOCKSCREEN)
- val secondTransitionSteps = listWithStep(step = BigDecimal(.1), start = BigDecimal(.9))
+ val secondTransitionSteps = listWithStep(step = BigDecimal(.1), start = BigDecimal(.1))
assertSteps(steps.subList(4, steps.size), secondTransitionSteps, LOCKSCREEN, AOD)
job.cancel()
@@ -168,6 +168,25 @@
assertThat(wtfHandler.failed).isTrue()
}
+ @Test
+ fun `Attempt to manually update transition after CANCELED state throws exception`() {
+ val uuid =
+ underTest.startTransition(
+ TransitionInfo(
+ ownerName = OWNER_NAME,
+ from = AOD,
+ to = LOCKSCREEN,
+ animator = null,
+ )
+ )
+
+ checkNotNull(uuid).let {
+ underTest.updateTransition(it, 0.2f, TransitionState.CANCELED)
+ underTest.updateTransition(it, 0.5f, TransitionState.RUNNING)
+ }
+ assertThat(wtfHandler.failed).isTrue()
+ }
+
private fun listWithStep(
step: BigDecimal,
start: BigDecimal = BigDecimal.ZERO,
@@ -201,7 +220,10 @@
)
)
fractions.forEachIndexed { index, fraction ->
- assertThat(steps[index + 1])
+ val step = steps[index + 1]
+ val truncatedValue =
+ BigDecimal(step.value.toDouble()).setScale(2, RoundingMode.HALF_UP).toFloat()
+ assertThat(step.copy(value = truncatedValue))
.isEqualTo(
TransitionStep(
from,
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardInteractorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardInteractorTest.kt
new file mode 100644
index 0000000..68d13d3
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardInteractorTest.kt
@@ -0,0 +1,86 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+package com.android.systemui.keyguard.domain.interactor
+
+import android.app.StatusBarManager
+import androidx.test.filters.SmallTest
+import com.android.systemui.SysuiTestCase
+import com.android.systemui.coroutines.collectLastValue
+import com.android.systemui.keyguard.data.repository.FakeKeyguardRepository
+import com.android.systemui.keyguard.shared.model.CameraLaunchSourceModel
+import com.android.systemui.statusbar.CommandQueue
+import com.android.systemui.statusbar.CommandQueue.Callbacks
+import com.android.systemui.util.mockito.argumentCaptor
+import com.google.common.truth.Truth.assertThat
+import kotlinx.coroutines.flow.onCompletion
+import kotlinx.coroutines.test.runCurrent
+import kotlinx.coroutines.test.runTest
+import org.junit.Before
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.junit.runners.JUnit4
+import org.mockito.Mock
+import org.mockito.Mockito.verify
+import org.mockito.MockitoAnnotations
+
+@SmallTest
+@RunWith(JUnit4::class)
+class KeyguardInteractorTest : SysuiTestCase() {
+ @Mock private lateinit var commandQueue: CommandQueue
+
+ private lateinit var underTest: KeyguardInteractor
+ private lateinit var repository: FakeKeyguardRepository
+
+ @Before
+ fun setUp() {
+ MockitoAnnotations.initMocks(this)
+
+ repository = FakeKeyguardRepository()
+ underTest = KeyguardInteractor(repository, commandQueue)
+ }
+
+ @Test
+ fun onCameraLaunchDetected() = runTest {
+ val flow = underTest.onCameraLaunchDetected
+ var cameraLaunchSource = collectLastValue(flow)
+ runCurrent()
+
+ val captor = argumentCaptor<CommandQueue.Callbacks>()
+ verify(commandQueue).addCallback(captor.capture())
+
+ captor.value.onCameraLaunchGestureDetected(StatusBarManager.CAMERA_LAUNCH_SOURCE_WIGGLE)
+ assertThat(cameraLaunchSource()).isEqualTo(CameraLaunchSourceModel.WIGGLE)
+
+ captor.value.onCameraLaunchGestureDetected(
+ StatusBarManager.CAMERA_LAUNCH_SOURCE_POWER_DOUBLE_TAP
+ )
+ assertThat(cameraLaunchSource()).isEqualTo(CameraLaunchSourceModel.POWER_DOUBLE_TAP)
+
+ captor.value.onCameraLaunchGestureDetected(
+ StatusBarManager.CAMERA_LAUNCH_SOURCE_LIFT_TRIGGER
+ )
+ assertThat(cameraLaunchSource()).isEqualTo(CameraLaunchSourceModel.LIFT_TRIGGER)
+
+ captor.value.onCameraLaunchGestureDetected(
+ StatusBarManager.CAMERA_LAUNCH_SOURCE_QUICK_AFFORDANCE
+ )
+ assertThat(cameraLaunchSource()).isEqualTo(CameraLaunchSourceModel.QUICK_AFFORDANCE)
+
+ flow.onCompletion { verify(commandQueue).removeCallback(captor.value) }
+ }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardQuickAffordanceInteractorParameterizedTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardQuickAffordanceInteractorParameterizedTest.kt
index 14b7c31..43287b0 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardQuickAffordanceInteractorParameterizedTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardQuickAffordanceInteractorParameterizedTest.kt
@@ -44,6 +44,7 @@
import com.android.systemui.settings.FakeUserTracker
import com.android.systemui.settings.UserFileManager
import com.android.systemui.settings.UserTracker
+import com.android.systemui.statusbar.CommandQueue
import com.android.systemui.statusbar.policy.KeyguardStateController
import com.android.systemui.util.FakeSharedPreferences
import com.android.systemui.util.mockito.any
@@ -216,6 +217,7 @@
@Mock private lateinit var animationController: ActivityLaunchAnimator.Controller
@Mock private lateinit var expandable: Expandable
@Mock private lateinit var launchAnimator: DialogLaunchAnimator
+ @Mock private lateinit var commandQueue: CommandQueue
private lateinit var underTest: KeyguardQuickAffordanceInteractor
@@ -286,7 +288,11 @@
)
underTest =
KeyguardQuickAffordanceInteractor(
- keyguardInteractor = KeyguardInteractor(repository = FakeKeyguardRepository()),
+ keyguardInteractor =
+ KeyguardInteractor(
+ repository = FakeKeyguardRepository(),
+ commandQueue = commandQueue
+ ),
registry =
FakeKeyguardQuickAffordanceRegistry(
mapOf(
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardQuickAffordanceInteractorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardQuickAffordanceInteractorTest.kt
index 972919a..b75a15d 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardQuickAffordanceInteractorTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardQuickAffordanceInteractorTest.kt
@@ -46,6 +46,7 @@
import com.android.systemui.settings.UserFileManager
import com.android.systemui.settings.UserTracker
import com.android.systemui.shared.keyguard.shared.model.KeyguardQuickAffordanceSlots
+import com.android.systemui.statusbar.CommandQueue
import com.android.systemui.statusbar.policy.KeyguardStateController
import com.android.systemui.util.FakeSharedPreferences
import com.android.systemui.util.mockito.mock
@@ -75,6 +76,7 @@
@Mock private lateinit var userTracker: UserTracker
@Mock private lateinit var activityStarter: ActivityStarter
@Mock private lateinit var launchAnimator: DialogLaunchAnimator
+ @Mock private lateinit var commandQueue: CommandQueue
private lateinit var underTest: KeyguardQuickAffordanceInteractor
@@ -152,7 +154,8 @@
underTest =
KeyguardQuickAffordanceInteractor(
- keyguardInteractor = KeyguardInteractor(repository = repository),
+ keyguardInteractor =
+ KeyguardInteractor(repository = repository, commandQueue = commandQueue),
registry =
FakeKeyguardQuickAffordanceRegistry(
mapOf(
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardTransitionScenariosTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardTransitionScenariosTest.kt
index d2b7838..a1b6d47 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardTransitionScenariosTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardTransitionScenariosTest.kt
@@ -33,10 +33,12 @@
import com.android.systemui.keyguard.util.KeyguardTransitionRunner
import com.android.systemui.shade.data.repository.FakeShadeRepository
import com.android.systemui.shade.data.repository.ShadeRepository
+import com.android.systemui.statusbar.CommandQueue
import com.android.systemui.util.mockito.withArgCaptor
import com.google.common.truth.Truth.assertThat
import kotlinx.coroutines.cancelChildren
import kotlinx.coroutines.test.TestScope
+import kotlinx.coroutines.test.advanceUntilIdle
import kotlinx.coroutines.test.runCurrent
import kotlinx.coroutines.test.runTest
import org.junit.Before
@@ -66,9 +68,14 @@
// Used to verify transition requests for test output
@Mock private lateinit var mockTransitionRepository: KeyguardTransitionRepository
+ @Mock private lateinit var commandQueue: CommandQueue
private lateinit var fromLockscreenTransitionInteractor: FromLockscreenTransitionInteractor
private lateinit var fromDreamingTransitionInteractor: FromDreamingTransitionInteractor
+ private lateinit var fromDozingTransitionInteractor: FromDozingTransitionInteractor
+ private lateinit var fromOccludedTransitionInteractor: FromOccludedTransitionInteractor
+ private lateinit var fromGoneTransitionInteractor: FromGoneTransitionInteractor
+ private lateinit var fromAodTransitionInteractor: FromAodTransitionInteractor
@Before
fun setUp() {
@@ -85,7 +92,7 @@
fromLockscreenTransitionInteractor =
FromLockscreenTransitionInteractor(
scope = testScope,
- keyguardInteractor = KeyguardInteractor(keyguardRepository),
+ keyguardInteractor = KeyguardInteractor(keyguardRepository, commandQueue),
shadeRepository = shadeRepository,
keyguardTransitionRepository = mockTransitionRepository,
keyguardTransitionInteractor = KeyguardTransitionInteractor(transitionRepository),
@@ -95,11 +102,47 @@
fromDreamingTransitionInteractor =
FromDreamingTransitionInteractor(
scope = testScope,
- keyguardInteractor = KeyguardInteractor(keyguardRepository),
+ keyguardInteractor = KeyguardInteractor(keyguardRepository, commandQueue),
keyguardTransitionRepository = mockTransitionRepository,
keyguardTransitionInteractor = KeyguardTransitionInteractor(transitionRepository),
)
fromDreamingTransitionInteractor.start()
+
+ fromAodTransitionInteractor =
+ FromAodTransitionInteractor(
+ scope = testScope,
+ keyguardInteractor = KeyguardInteractor(keyguardRepository, commandQueue),
+ keyguardTransitionRepository = mockTransitionRepository,
+ keyguardTransitionInteractor = KeyguardTransitionInteractor(transitionRepository),
+ )
+ fromAodTransitionInteractor.start()
+
+ fromGoneTransitionInteractor =
+ FromGoneTransitionInteractor(
+ scope = testScope,
+ keyguardInteractor = KeyguardInteractor(keyguardRepository, commandQueue),
+ keyguardTransitionRepository = mockTransitionRepository,
+ keyguardTransitionInteractor = KeyguardTransitionInteractor(transitionRepository),
+ )
+ fromGoneTransitionInteractor.start()
+
+ fromDozingTransitionInteractor =
+ FromDozingTransitionInteractor(
+ scope = testScope,
+ keyguardInteractor = KeyguardInteractor(keyguardRepository, commandQueue),
+ keyguardTransitionRepository = mockTransitionRepository,
+ keyguardTransitionInteractor = KeyguardTransitionInteractor(transitionRepository),
+ )
+ fromDozingTransitionInteractor.start()
+
+ fromOccludedTransitionInteractor =
+ FromOccludedTransitionInteractor(
+ scope = testScope,
+ keyguardInteractor = KeyguardInteractor(keyguardRepository, commandQueue),
+ keyguardTransitionRepository = mockTransitionRepository,
+ keyguardTransitionInteractor = KeyguardTransitionInteractor(transitionRepository),
+ )
+ fromOccludedTransitionInteractor.start()
}
@Test
@@ -135,7 +178,7 @@
keyguardRepository.setDreamingWithOverlay(false)
// AND occluded has stopped
keyguardRepository.setKeyguardOccluded(false)
- runCurrent()
+ advanceUntilIdle()
val info =
withArgCaptor<TransitionInfo> {
@@ -190,6 +233,332 @@
coroutineContext.cancelChildren()
}
+ @Test
+ fun `OCCLUDED to DOZING`() =
+ testScope.runTest {
+ // GIVEN a device with AOD not available
+ keyguardRepository.setAodAvailable(false)
+ runCurrent()
+
+ // GIVEN a prior transition has run to OCCLUDED
+ runner.startTransition(
+ testScope,
+ TransitionInfo(
+ ownerName = "",
+ from = KeyguardState.LOCKSCREEN,
+ to = KeyguardState.OCCLUDED,
+ animator =
+ ValueAnimator().apply {
+ duration = 10
+ interpolator = Interpolators.LINEAR
+ },
+ )
+ )
+ runCurrent()
+ reset(mockTransitionRepository)
+
+ // WHEN the device begins to sleep
+ keyguardRepository.setWakefulnessModel(startingToSleep())
+ runCurrent()
+
+ val info =
+ withArgCaptor<TransitionInfo> {
+ verify(mockTransitionRepository).startTransition(capture())
+ }
+ // THEN a transition to DOZING should occur
+ assertThat(info.ownerName).isEqualTo("FromOccludedTransitionInteractor")
+ assertThat(info.from).isEqualTo(KeyguardState.OCCLUDED)
+ assertThat(info.to).isEqualTo(KeyguardState.DOZING)
+ assertThat(info.animator).isNotNull()
+
+ coroutineContext.cancelChildren()
+ }
+
+ @Test
+ fun `OCCLUDED to AOD`() =
+ testScope.runTest {
+ // GIVEN a device with AOD available
+ keyguardRepository.setAodAvailable(true)
+ runCurrent()
+
+ // GIVEN a prior transition has run to OCCLUDED
+ runner.startTransition(
+ testScope,
+ TransitionInfo(
+ ownerName = "",
+ from = KeyguardState.LOCKSCREEN,
+ to = KeyguardState.OCCLUDED,
+ animator =
+ ValueAnimator().apply {
+ duration = 10
+ interpolator = Interpolators.LINEAR
+ },
+ )
+ )
+ runCurrent()
+ reset(mockTransitionRepository)
+
+ // WHEN the device begins to sleep
+ keyguardRepository.setWakefulnessModel(startingToSleep())
+ runCurrent()
+
+ val info =
+ withArgCaptor<TransitionInfo> {
+ verify(mockTransitionRepository).startTransition(capture())
+ }
+ // THEN a transition to DOZING should occur
+ assertThat(info.ownerName).isEqualTo("FromOccludedTransitionInteractor")
+ assertThat(info.from).isEqualTo(KeyguardState.OCCLUDED)
+ assertThat(info.to).isEqualTo(KeyguardState.AOD)
+ assertThat(info.animator).isNotNull()
+
+ coroutineContext.cancelChildren()
+ }
+
+ @Test
+ fun `LOCKSCREEN to DOZING`() =
+ testScope.runTest {
+ // GIVEN a device with AOD not available
+ keyguardRepository.setAodAvailable(false)
+ runCurrent()
+
+ // GIVEN a prior transition has run to LOCKSCREEN
+ runner.startTransition(
+ testScope,
+ TransitionInfo(
+ ownerName = "",
+ from = KeyguardState.GONE,
+ to = KeyguardState.LOCKSCREEN,
+ animator =
+ ValueAnimator().apply {
+ duration = 10
+ interpolator = Interpolators.LINEAR
+ },
+ )
+ )
+ runCurrent()
+ reset(mockTransitionRepository)
+
+ // WHEN the device begins to sleep
+ keyguardRepository.setWakefulnessModel(startingToSleep())
+ runCurrent()
+
+ val info =
+ withArgCaptor<TransitionInfo> {
+ verify(mockTransitionRepository).startTransition(capture())
+ }
+ // THEN a transition to DOZING should occur
+ assertThat(info.ownerName).isEqualTo("FromLockscreenTransitionInteractor")
+ assertThat(info.from).isEqualTo(KeyguardState.LOCKSCREEN)
+ assertThat(info.to).isEqualTo(KeyguardState.DOZING)
+ assertThat(info.animator).isNotNull()
+
+ coroutineContext.cancelChildren()
+ }
+
+ @Test
+ fun `LOCKSCREEN to AOD`() =
+ testScope.runTest {
+ // GIVEN a device with AOD available
+ keyguardRepository.setAodAvailable(true)
+ runCurrent()
+
+ // GIVEN a prior transition has run to LOCKSCREEN
+ runner.startTransition(
+ testScope,
+ TransitionInfo(
+ ownerName = "",
+ from = KeyguardState.GONE,
+ to = KeyguardState.LOCKSCREEN,
+ animator =
+ ValueAnimator().apply {
+ duration = 10
+ interpolator = Interpolators.LINEAR
+ },
+ )
+ )
+ runCurrent()
+ reset(mockTransitionRepository)
+
+ // WHEN the device begins to sleep
+ keyguardRepository.setWakefulnessModel(startingToSleep())
+ runCurrent()
+
+ val info =
+ withArgCaptor<TransitionInfo> {
+ verify(mockTransitionRepository).startTransition(capture())
+ }
+ // THEN a transition to DOZING should occur
+ assertThat(info.ownerName).isEqualTo("FromLockscreenTransitionInteractor")
+ assertThat(info.from).isEqualTo(KeyguardState.LOCKSCREEN)
+ assertThat(info.to).isEqualTo(KeyguardState.AOD)
+ assertThat(info.animator).isNotNull()
+
+ coroutineContext.cancelChildren()
+ }
+
+ @Test
+ fun `DOZING to LOCKSCREEN`() =
+ testScope.runTest {
+ // GIVEN a prior transition has run to DOZING
+ runner.startTransition(
+ testScope,
+ TransitionInfo(
+ ownerName = "",
+ from = KeyguardState.LOCKSCREEN,
+ to = KeyguardState.DOZING,
+ animator =
+ ValueAnimator().apply {
+ duration = 10
+ interpolator = Interpolators.LINEAR
+ },
+ )
+ )
+ runCurrent()
+ reset(mockTransitionRepository)
+
+ // WHEN the device begins to wake
+ keyguardRepository.setWakefulnessModel(startingToWake())
+ runCurrent()
+
+ val info =
+ withArgCaptor<TransitionInfo> {
+ verify(mockTransitionRepository).startTransition(capture())
+ }
+ // THEN a transition to DOZING should occur
+ assertThat(info.ownerName).isEqualTo("FromDozingTransitionInteractor")
+ assertThat(info.from).isEqualTo(KeyguardState.DOZING)
+ assertThat(info.to).isEqualTo(KeyguardState.LOCKSCREEN)
+ assertThat(info.animator).isNotNull()
+
+ coroutineContext.cancelChildren()
+ }
+
+ @Test
+ fun `GONE to DOZING`() =
+ testScope.runTest {
+ // GIVEN a device with AOD not available
+ keyguardRepository.setAodAvailable(false)
+ runCurrent()
+
+ // GIVEN a prior transition has run to GONE
+ runner.startTransition(
+ testScope,
+ TransitionInfo(
+ ownerName = "",
+ from = KeyguardState.LOCKSCREEN,
+ to = KeyguardState.GONE,
+ animator =
+ ValueAnimator().apply {
+ duration = 10
+ interpolator = Interpolators.LINEAR
+ },
+ )
+ )
+ runCurrent()
+ reset(mockTransitionRepository)
+
+ // WHEN the device begins to sleep
+ keyguardRepository.setWakefulnessModel(startingToSleep())
+ runCurrent()
+
+ val info =
+ withArgCaptor<TransitionInfo> {
+ verify(mockTransitionRepository).startTransition(capture())
+ }
+ // THEN a transition to DOZING should occur
+ assertThat(info.ownerName).isEqualTo("FromGoneTransitionInteractor")
+ assertThat(info.from).isEqualTo(KeyguardState.GONE)
+ assertThat(info.to).isEqualTo(KeyguardState.DOZING)
+ assertThat(info.animator).isNotNull()
+
+ coroutineContext.cancelChildren()
+ }
+
+ @Test
+ fun `GONE to AOD`() =
+ testScope.runTest {
+ // GIVEN a device with AOD available
+ keyguardRepository.setAodAvailable(true)
+ runCurrent()
+
+ // GIVEN a prior transition has run to GONE
+ runner.startTransition(
+ testScope,
+ TransitionInfo(
+ ownerName = "",
+ from = KeyguardState.LOCKSCREEN,
+ to = KeyguardState.GONE,
+ animator =
+ ValueAnimator().apply {
+ duration = 10
+ interpolator = Interpolators.LINEAR
+ },
+ )
+ )
+ runCurrent()
+ reset(mockTransitionRepository)
+
+ // WHEN the device begins to sleep
+ keyguardRepository.setWakefulnessModel(startingToSleep())
+ runCurrent()
+
+ val info =
+ withArgCaptor<TransitionInfo> {
+ verify(mockTransitionRepository).startTransition(capture())
+ }
+ // THEN a transition to AOD should occur
+ assertThat(info.ownerName).isEqualTo("FromGoneTransitionInteractor")
+ assertThat(info.from).isEqualTo(KeyguardState.GONE)
+ assertThat(info.to).isEqualTo(KeyguardState.AOD)
+ assertThat(info.animator).isNotNull()
+
+ coroutineContext.cancelChildren()
+ }
+
+ @Test
+ fun `GONE to DREAMING`() =
+ testScope.runTest {
+ // GIVEN a device that is not dreaming or dozing
+ keyguardRepository.setDreamingWithOverlay(false)
+ keyguardRepository.setDozeTransitionModel(
+ DozeTransitionModel(from = DozeStateModel.DOZE, to = DozeStateModel.FINISH)
+ )
+ runCurrent()
+
+ // GIVEN a prior transition has run to GONE
+ runner.startTransition(
+ testScope,
+ TransitionInfo(
+ ownerName = "",
+ from = KeyguardState.LOCKSCREEN,
+ to = KeyguardState.GONE,
+ animator =
+ ValueAnimator().apply {
+ duration = 10
+ interpolator = Interpolators.LINEAR
+ },
+ )
+ )
+ reset(mockTransitionRepository)
+
+ // WHEN the device begins to dream
+ keyguardRepository.setDreamingWithOverlay(true)
+ advanceUntilIdle()
+
+ val info =
+ withArgCaptor<TransitionInfo> {
+ verify(mockTransitionRepository).startTransition(capture())
+ }
+ // THEN a transition to DREAMING should occur
+ assertThat(info.ownerName).isEqualTo("FromGoneTransitionInteractor")
+ assertThat(info.from).isEqualTo(KeyguardState.GONE)
+ assertThat(info.to).isEqualTo(KeyguardState.DREAMING)
+ assertThat(info.animator).isNotNull()
+
+ coroutineContext.cancelChildren()
+ }
+
private fun startingToWake() =
WakefulnessModel(
WakefulnessState.STARTING_TO_WAKE,
@@ -197,4 +566,12 @@
WakeSleepReason.OTHER,
WakeSleepReason.OTHER
)
+
+ private fun startingToSleep() =
+ WakefulnessModel(
+ WakefulnessState.STARTING_TO_SLEEP,
+ true,
+ WakeSleepReason.OTHER,
+ WakeSleepReason.OTHER
+ )
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/GoneToDreamingTransitionViewModelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/GoneToDreamingTransitionViewModelTest.kt
new file mode 100644
index 0000000..7fa204b
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/GoneToDreamingTransitionViewModelTest.kt
@@ -0,0 +1,141 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.keyguard.ui.viewmodel
+
+import androidx.test.filters.SmallTest
+import com.android.systemui.SysuiTestCase
+import com.android.systemui.animation.Interpolators.EMPHASIZED_ACCELERATE
+import com.android.systemui.keyguard.data.repository.FakeKeyguardTransitionRepository
+import com.android.systemui.keyguard.domain.interactor.FromGoneTransitionInteractor.Companion.TO_DREAMING_DURATION
+import com.android.systemui.keyguard.domain.interactor.KeyguardTransitionInteractor
+import com.android.systemui.keyguard.shared.model.AnimationParams
+import com.android.systemui.keyguard.shared.model.KeyguardState
+import com.android.systemui.keyguard.shared.model.TransitionState
+import com.android.systemui.keyguard.shared.model.TransitionStep
+import com.android.systemui.keyguard.ui.viewmodel.GoneToDreamingTransitionViewModel.Companion.LOCKSCREEN_ALPHA
+import com.android.systemui.keyguard.ui.viewmodel.GoneToDreamingTransitionViewModel.Companion.LOCKSCREEN_TRANSLATION_Y
+import com.google.common.truth.Truth.assertThat
+import kotlinx.coroutines.flow.launchIn
+import kotlinx.coroutines.flow.onEach
+import kotlinx.coroutines.test.UnconfinedTestDispatcher
+import kotlinx.coroutines.test.runTest
+import org.junit.Before
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.junit.runners.JUnit4
+
+@SmallTest
+@RunWith(JUnit4::class)
+class GoneToDreamingTransitionViewModelTest : SysuiTestCase() {
+ private lateinit var underTest: GoneToDreamingTransitionViewModel
+ private lateinit var repository: FakeKeyguardTransitionRepository
+
+ @Before
+ fun setUp() {
+ repository = FakeKeyguardTransitionRepository()
+ val interactor = KeyguardTransitionInteractor(repository)
+ underTest = GoneToDreamingTransitionViewModel(interactor)
+ }
+
+ @Test
+ fun lockscreenFadeOut() =
+ runTest(UnconfinedTestDispatcher()) {
+ val values = mutableListOf<Float>()
+
+ val job = underTest.lockscreenAlpha.onEach { values.add(it) }.launchIn(this)
+
+ // Should start running here...
+ repository.sendTransitionStep(step(0f))
+ repository.sendTransitionStep(step(0.1f))
+ repository.sendTransitionStep(step(0.2f))
+ // ...up to here
+ repository.sendTransitionStep(step(0.3f))
+ repository.sendTransitionStep(step(1f))
+
+ // Only three values should be present, since the dream overlay runs for a small
+ // fraction
+ // of the overall animation time
+ assertThat(values.size).isEqualTo(3)
+ assertThat(values[0]).isEqualTo(1f - animValue(0f, LOCKSCREEN_ALPHA))
+ assertThat(values[1]).isEqualTo(1f - animValue(0.1f, LOCKSCREEN_ALPHA))
+ assertThat(values[2]).isEqualTo(1f - animValue(0.2f, LOCKSCREEN_ALPHA))
+
+ job.cancel()
+ }
+
+ @Test
+ fun lockscreenTranslationY() =
+ runTest(UnconfinedTestDispatcher()) {
+ val values = mutableListOf<Float>()
+
+ val pixels = 100
+ val job =
+ underTest.lockscreenTranslationY(pixels).onEach { values.add(it) }.launchIn(this)
+
+ // Should start running here...
+ repository.sendTransitionStep(step(0f))
+ repository.sendTransitionStep(step(0.3f))
+ repository.sendTransitionStep(step(0.5f))
+ // ...up to here
+ repository.sendTransitionStep(step(1f))
+ // And a final reset event on CANCEL
+ repository.sendTransitionStep(step(0.8f, TransitionState.CANCELED))
+
+ assertThat(values.size).isEqualTo(4)
+ assertThat(values[0])
+ .isEqualTo(
+ EMPHASIZED_ACCELERATE.getInterpolation(
+ animValue(0f, LOCKSCREEN_TRANSLATION_Y)
+ ) * pixels
+ )
+ assertThat(values[1])
+ .isEqualTo(
+ EMPHASIZED_ACCELERATE.getInterpolation(
+ animValue(0.3f, LOCKSCREEN_TRANSLATION_Y)
+ ) * pixels
+ )
+ assertThat(values[2])
+ .isEqualTo(
+ EMPHASIZED_ACCELERATE.getInterpolation(
+ animValue(0.5f, LOCKSCREEN_TRANSLATION_Y)
+ ) * pixels
+ )
+ assertThat(values[3]).isEqualTo(0f)
+ job.cancel()
+ }
+
+ private fun animValue(stepValue: Float, params: AnimationParams): Float {
+ val totalDuration = TO_DREAMING_DURATION
+ val startValue = (params.startTime / totalDuration).toFloat()
+
+ val multiplier = (totalDuration / params.duration).toFloat()
+ return (stepValue - startValue) * multiplier
+ }
+
+ private fun step(
+ value: Float,
+ state: TransitionState = TransitionState.RUNNING
+ ): TransitionStep {
+ return TransitionStep(
+ from = KeyguardState.GONE,
+ to = KeyguardState.DREAMING,
+ value = value,
+ transitionState = state,
+ ownerName = "GoneToDreamingTransitionViewModelTest"
+ )
+ }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardBottomAreaViewModelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardBottomAreaViewModelTest.kt
index a2c2f71..022afdd 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardBottomAreaViewModelTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardBottomAreaViewModelTest.kt
@@ -47,6 +47,7 @@
import com.android.systemui.settings.UserFileManager
import com.android.systemui.settings.UserTracker
import com.android.systemui.shared.keyguard.shared.model.KeyguardQuickAffordanceSlots
+import com.android.systemui.statusbar.CommandQueue
import com.android.systemui.statusbar.policy.KeyguardStateController
import com.android.systemui.util.FakeSharedPreferences
import com.android.systemui.util.mockito.any
@@ -84,6 +85,7 @@
@Mock private lateinit var userTracker: UserTracker
@Mock private lateinit var activityStarter: ActivityStarter
@Mock private lateinit var launchAnimator: DialogLaunchAnimator
+ @Mock private lateinit var commandQueue: CommandQueue
private lateinit var underTest: KeyguardBottomAreaViewModel
@@ -124,7 +126,8 @@
)
repository = FakeKeyguardRepository()
- val keyguardInteractor = KeyguardInteractor(repository = repository)
+ val keyguardInteractor =
+ KeyguardInteractor(repository = repository, commandQueue = commandQueue)
whenever(userTracker.userHandle).thenReturn(mock())
whenever(lockPatternUtils.getStrongAuthForUser(anyInt()))
.thenReturn(LockPatternUtils.StrongAuthTracker.STRONG_AUTH_NOT_REQUIRED)
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenToDreamingTransitionViewModelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenToDreamingTransitionViewModelTest.kt
new file mode 100644
index 0000000..539fc2c
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenToDreamingTransitionViewModelTest.kt
@@ -0,0 +1,141 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.keyguard.ui.viewmodel
+
+import androidx.test.filters.SmallTest
+import com.android.systemui.SysuiTestCase
+import com.android.systemui.animation.Interpolators.EMPHASIZED_ACCELERATE
+import com.android.systemui.keyguard.data.repository.FakeKeyguardTransitionRepository
+import com.android.systemui.keyguard.domain.interactor.FromLockscreenTransitionInteractor.Companion.TO_DREAMING_DURATION
+import com.android.systemui.keyguard.domain.interactor.KeyguardTransitionInteractor
+import com.android.systemui.keyguard.shared.model.AnimationParams
+import com.android.systemui.keyguard.shared.model.KeyguardState
+import com.android.systemui.keyguard.shared.model.TransitionState
+import com.android.systemui.keyguard.shared.model.TransitionStep
+import com.android.systemui.keyguard.ui.viewmodel.LockscreenToDreamingTransitionViewModel.Companion.LOCKSCREEN_ALPHA
+import com.android.systemui.keyguard.ui.viewmodel.LockscreenToDreamingTransitionViewModel.Companion.LOCKSCREEN_TRANSLATION_Y
+import com.google.common.truth.Truth.assertThat
+import kotlinx.coroutines.flow.launchIn
+import kotlinx.coroutines.flow.onEach
+import kotlinx.coroutines.test.UnconfinedTestDispatcher
+import kotlinx.coroutines.test.runTest
+import org.junit.Before
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.junit.runners.JUnit4
+
+@SmallTest
+@RunWith(JUnit4::class)
+class LockscreenToDreamingTransitionViewModelTest : SysuiTestCase() {
+ private lateinit var underTest: LockscreenToDreamingTransitionViewModel
+ private lateinit var repository: FakeKeyguardTransitionRepository
+
+ @Before
+ fun setUp() {
+ repository = FakeKeyguardTransitionRepository()
+ val interactor = KeyguardTransitionInteractor(repository)
+ underTest = LockscreenToDreamingTransitionViewModel(interactor)
+ }
+
+ @Test
+ fun lockscreenFadeOut() =
+ runTest(UnconfinedTestDispatcher()) {
+ val values = mutableListOf<Float>()
+
+ val job = underTest.lockscreenAlpha.onEach { values.add(it) }.launchIn(this)
+
+ // Should start running here...
+ repository.sendTransitionStep(step(0f))
+ repository.sendTransitionStep(step(0.1f))
+ repository.sendTransitionStep(step(0.2f))
+ // ...up to here
+ repository.sendTransitionStep(step(0.3f))
+ repository.sendTransitionStep(step(1f))
+
+ // Only three values should be present, since the dream overlay runs for a small
+ // fraction of the overall animation time
+ assertThat(values.size).isEqualTo(3)
+ assertThat(values[0]).isEqualTo(1f - animValue(0f, LOCKSCREEN_ALPHA))
+ assertThat(values[1]).isEqualTo(1f - animValue(0.1f, LOCKSCREEN_ALPHA))
+ assertThat(values[2]).isEqualTo(1f - animValue(0.2f, LOCKSCREEN_ALPHA))
+
+ job.cancel()
+ }
+
+ @Test
+ fun lockscreenTranslationY() =
+ runTest(UnconfinedTestDispatcher()) {
+ val values = mutableListOf<Float>()
+
+ val pixels = 100
+ val job =
+ underTest.lockscreenTranslationY(pixels).onEach { values.add(it) }.launchIn(this)
+
+ // Should start running here...
+ repository.sendTransitionStep(step(0f))
+ repository.sendTransitionStep(step(0.3f))
+ repository.sendTransitionStep(step(0.5f))
+ // ...up to here
+ repository.sendTransitionStep(step(1f))
+ // And a final reset event on FINISHED
+ repository.sendTransitionStep(step(1f, TransitionState.FINISHED))
+
+ assertThat(values.size).isEqualTo(4)
+ assertThat(values[0])
+ .isEqualTo(
+ EMPHASIZED_ACCELERATE.getInterpolation(
+ animValue(0f, LOCKSCREEN_TRANSLATION_Y)
+ ) * pixels
+ )
+ assertThat(values[1])
+ .isEqualTo(
+ EMPHASIZED_ACCELERATE.getInterpolation(
+ animValue(0.3f, LOCKSCREEN_TRANSLATION_Y)
+ ) * pixels
+ )
+ assertThat(values[2])
+ .isEqualTo(
+ EMPHASIZED_ACCELERATE.getInterpolation(
+ animValue(0.5f, LOCKSCREEN_TRANSLATION_Y)
+ ) * pixels
+ )
+ assertThat(values[3]).isEqualTo(0f)
+
+ job.cancel()
+ }
+
+ private fun animValue(stepValue: Float, params: AnimationParams): Float {
+ val totalDuration = TO_DREAMING_DURATION
+ val startValue = (params.startTime / totalDuration).toFloat()
+
+ val multiplier = (totalDuration / params.duration).toFloat()
+ return (stepValue - startValue) * multiplier
+ }
+
+ private fun step(
+ value: Float,
+ state: TransitionState = TransitionState.RUNNING
+ ): TransitionStep {
+ return TransitionStep(
+ from = KeyguardState.LOCKSCREEN,
+ to = KeyguardState.DREAMING,
+ value = value,
+ transitionState = state,
+ ownerName = "LockscreenToDreamingTransitionViewModelTest"
+ )
+ }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenToOccludedTransitionViewModelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenToOccludedTransitionViewModelTest.kt
new file mode 100644
index 0000000..759345f
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenToOccludedTransitionViewModelTest.kt
@@ -0,0 +1,140 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.keyguard.ui.viewmodel
+
+import androidx.test.filters.SmallTest
+import com.android.systemui.SysuiTestCase
+import com.android.systemui.animation.Interpolators.EMPHASIZED_ACCELERATE
+import com.android.systemui.keyguard.data.repository.FakeKeyguardTransitionRepository
+import com.android.systemui.keyguard.domain.interactor.FromLockscreenTransitionInteractor.Companion.TO_OCCLUDED_DURATION
+import com.android.systemui.keyguard.domain.interactor.KeyguardTransitionInteractor
+import com.android.systemui.keyguard.shared.model.AnimationParams
+import com.android.systemui.keyguard.shared.model.KeyguardState
+import com.android.systemui.keyguard.shared.model.TransitionState
+import com.android.systemui.keyguard.shared.model.TransitionStep
+import com.android.systemui.keyguard.ui.viewmodel.LockscreenToOccludedTransitionViewModel.Companion.LOCKSCREEN_ALPHA
+import com.android.systemui.keyguard.ui.viewmodel.LockscreenToOccludedTransitionViewModel.Companion.LOCKSCREEN_TRANSLATION_Y
+import com.google.common.truth.Truth.assertThat
+import kotlinx.coroutines.flow.launchIn
+import kotlinx.coroutines.flow.onEach
+import kotlinx.coroutines.test.UnconfinedTestDispatcher
+import kotlinx.coroutines.test.runTest
+import org.junit.Before
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.junit.runners.JUnit4
+
+@SmallTest
+@RunWith(JUnit4::class)
+class LockscreenToOccludedTransitionViewModelTest : SysuiTestCase() {
+ private lateinit var underTest: LockscreenToOccludedTransitionViewModel
+ private lateinit var repository: FakeKeyguardTransitionRepository
+
+ @Before
+ fun setUp() {
+ repository = FakeKeyguardTransitionRepository()
+ val interactor = KeyguardTransitionInteractor(repository)
+ underTest = LockscreenToOccludedTransitionViewModel(interactor)
+ }
+
+ @Test
+ fun lockscreenFadeOut() =
+ runTest(UnconfinedTestDispatcher()) {
+ val values = mutableListOf<Float>()
+
+ val job = underTest.lockscreenAlpha.onEach { values.add(it) }.launchIn(this)
+
+ // Should start running here...
+ repository.sendTransitionStep(step(0f))
+ repository.sendTransitionStep(step(0.1f))
+ repository.sendTransitionStep(step(0.4f))
+ // ...up to here
+ repository.sendTransitionStep(step(0.7f))
+ repository.sendTransitionStep(step(1f))
+
+ // Only 3 values should be present, since the dream overlay runs for a small fraction
+ // of the overall animation time
+ assertThat(values.size).isEqualTo(3)
+ assertThat(values[0]).isEqualTo(1f - animValue(0f, LOCKSCREEN_ALPHA))
+ assertThat(values[1]).isEqualTo(1f - animValue(0.1f, LOCKSCREEN_ALPHA))
+ assertThat(values[2]).isEqualTo(1f - animValue(0.4f, LOCKSCREEN_ALPHA))
+
+ job.cancel()
+ }
+
+ @Test
+ fun lockscreenTranslationY() =
+ runTest(UnconfinedTestDispatcher()) {
+ val values = mutableListOf<Float>()
+
+ val pixels = 100
+ val job =
+ underTest.lockscreenTranslationY(pixels).onEach { values.add(it) }.launchIn(this)
+
+ // Should start running here...
+ repository.sendTransitionStep(step(0f))
+ repository.sendTransitionStep(step(0.3f))
+ repository.sendTransitionStep(step(0.5f))
+ repository.sendTransitionStep(step(1f))
+ // ...up to here
+
+ assertThat(values.size).isEqualTo(4)
+ assertThat(values[0])
+ .isEqualTo(
+ EMPHASIZED_ACCELERATE.getInterpolation(
+ animValue(0f, LOCKSCREEN_TRANSLATION_Y)
+ ) * pixels
+ )
+ assertThat(values[1])
+ .isEqualTo(
+ EMPHASIZED_ACCELERATE.getInterpolation(
+ animValue(0.3f, LOCKSCREEN_TRANSLATION_Y)
+ ) * pixels
+ )
+ assertThat(values[2])
+ .isEqualTo(
+ EMPHASIZED_ACCELERATE.getInterpolation(
+ animValue(0.5f, LOCKSCREEN_TRANSLATION_Y)
+ ) * pixels
+ )
+ assertThat(values[3])
+ .isEqualTo(
+ EMPHASIZED_ACCELERATE.getInterpolation(
+ animValue(1f, LOCKSCREEN_TRANSLATION_Y)
+ ) * pixels
+ )
+ job.cancel()
+ }
+
+ private fun animValue(stepValue: Float, params: AnimationParams): Float {
+ val totalDuration = TO_OCCLUDED_DURATION
+ val startValue = (params.startTime / totalDuration).toFloat()
+
+ val multiplier = (totalDuration / params.duration).toFloat()
+ return (stepValue - startValue) * multiplier
+ }
+
+ private fun step(value: Float): TransitionStep {
+ return TransitionStep(
+ from = KeyguardState.LOCKSCREEN,
+ to = KeyguardState.OCCLUDED,
+ value = value,
+ transitionState = TransitionState.RUNNING,
+ ownerName = "LockscreenToOccludedTransitionViewModelTest"
+ )
+ }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/log/table/TableLogBufferFactoryTest.kt b/packages/SystemUI/tests/src/com/android/systemui/log/table/TableLogBufferFactoryTest.kt
new file mode 100644
index 0000000..411b1bd
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/log/table/TableLogBufferFactoryTest.kt
@@ -0,0 +1,64 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.log.table
+
+import androidx.test.filters.SmallTest
+import com.android.systemui.SysuiTestCase
+import com.android.systemui.dump.DumpManager
+import com.android.systemui.util.mockito.mock
+import com.android.systemui.util.time.FakeSystemClock
+import com.google.common.truth.Truth.assertThat
+import org.junit.Test
+
+@SmallTest
+class TableLogBufferFactoryTest : SysuiTestCase() {
+ private val dumpManager: DumpManager = mock()
+ private val systemClock = FakeSystemClock()
+ private val underTest = TableLogBufferFactory(dumpManager, systemClock)
+
+ @Test
+ fun `create - always creates new instance`() {
+ val b1 = underTest.create(NAME_1, SIZE)
+ val b1_copy = underTest.create(NAME_1, SIZE)
+ val b2 = underTest.create(NAME_2, SIZE)
+ val b2_copy = underTest.create(NAME_2, SIZE)
+
+ assertThat(b1).isNotSameInstanceAs(b1_copy)
+ assertThat(b1).isNotSameInstanceAs(b2)
+ assertThat(b2).isNotSameInstanceAs(b2_copy)
+ }
+
+ @Test
+ fun `getOrCreate - reuses instance`() {
+ val b1 = underTest.getOrCreate(NAME_1, SIZE)
+ val b1_copy = underTest.getOrCreate(NAME_1, SIZE)
+ val b2 = underTest.getOrCreate(NAME_2, SIZE)
+ val b2_copy = underTest.getOrCreate(NAME_2, SIZE)
+
+ assertThat(b1).isSameInstanceAs(b1_copy)
+ assertThat(b2).isSameInstanceAs(b2_copy)
+ assertThat(b1).isNotSameInstanceAs(b2)
+ assertThat(b1_copy).isNotSameInstanceAs(b2_copy)
+ }
+
+ companion object {
+ const val NAME_1 = "name 1"
+ const val NAME_2 = "name 2"
+
+ const val SIZE = 8
+ }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/media/controls/pipeline/MediaDataCombineLatestTest.java b/packages/SystemUI/tests/src/com/android/systemui/media/controls/pipeline/MediaDataCombineLatestTest.java
index 4d2d0f0..c0639f3 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/media/controls/pipeline/MediaDataCombineLatestTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/media/controls/pipeline/MediaDataCombineLatestTest.java
@@ -79,7 +79,7 @@
USER_ID, true, APP, null, ARTIST, TITLE, null,
new ArrayList<>(), new ArrayList<>(), null, PACKAGE, null, null, null, true, null,
MediaData.PLAYBACK_LOCAL, false, KEY, false, false, false, 0L,
- InstanceId.fakeInstanceId(-1), -1);
+ InstanceId.fakeInstanceId(-1), -1, false);
mDeviceData = new MediaDeviceData(true, null, DEVICE_NAME, null, false);
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/media/controls/pipeline/MediaDataManagerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/media/controls/pipeline/MediaDataManagerTest.kt
index 52b694f..c24c8c7 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/media/controls/pipeline/MediaDataManagerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/media/controls/pipeline/MediaDataManagerTest.kt
@@ -228,6 +228,7 @@
whenever(mediaSmartspaceTarget.iconGrid).thenReturn(validRecommendationList)
whenever(mediaSmartspaceTarget.creationTimeMillis).thenReturn(1234L)
whenever(mediaFlags.areMediaSessionActionsEnabled(any(), any())).thenReturn(false)
+ whenever(mediaFlags.isExplicitIndicatorEnabled()).thenReturn(true)
whenever(logger.getNewInstanceId()).thenReturn(instanceIdSequence.newInstanceId())
}
@@ -300,6 +301,60 @@
}
@Test
+ fun testLoadMetadata_withExplicitIndicator() {
+ val metadata =
+ MediaMetadata.Builder().run {
+ putString(MediaMetadata.METADATA_KEY_ARTIST, SESSION_ARTIST)
+ putString(MediaMetadata.METADATA_KEY_TITLE, SESSION_TITLE)
+ putLong(
+ MediaConstants.METADATA_KEY_IS_EXPLICIT,
+ MediaConstants.METADATA_VALUE_ATTRIBUTE_PRESENT
+ )
+ build()
+ }
+ whenever(mediaControllerFactory.create(anyObject())).thenReturn(controller)
+ whenever(controller.metadata).thenReturn(metadata)
+
+ mediaDataManager.addListener(listener)
+ mediaDataManager.onNotificationAdded(KEY, mediaNotification)
+
+ assertThat(backgroundExecutor.runAllReady()).isEqualTo(1)
+ assertThat(foregroundExecutor.runAllReady()).isEqualTo(1)
+ verify(listener)
+ .onMediaDataLoaded(
+ eq(KEY),
+ eq(null),
+ capture(mediaDataCaptor),
+ eq(true),
+ eq(0),
+ eq(false)
+ )
+ assertThat(mediaDataCaptor.value!!.isExplicit).isTrue()
+ }
+
+ @Test
+ fun testOnMetaDataLoaded_withoutExplicitIndicator() {
+ whenever(mediaControllerFactory.create(anyObject())).thenReturn(controller)
+ whenever(controller.metadata).thenReturn(metadataBuilder.build())
+
+ mediaDataManager.addListener(listener)
+ mediaDataManager.onNotificationAdded(KEY, mediaNotification)
+
+ assertThat(backgroundExecutor.runAllReady()).isEqualTo(1)
+ assertThat(foregroundExecutor.runAllReady()).isEqualTo(1)
+ verify(listener)
+ .onMediaDataLoaded(
+ eq(KEY),
+ eq(null),
+ capture(mediaDataCaptor),
+ eq(true),
+ eq(0),
+ eq(false)
+ )
+ assertThat(mediaDataCaptor.value!!.isExplicit).isFalse()
+ }
+
+ @Test
fun testOnMetaDataLoaded_callsListener() {
addNotificationAndLoad()
verify(logger)
@@ -603,6 +658,53 @@
}
@Test
+ fun testAddResumptionControls_withExplicitIndicator() {
+ val bundle = Bundle()
+ // WHEN resumption controls are added with explicit indicator
+ bundle.putLong(
+ MediaConstants.METADATA_KEY_IS_EXPLICIT,
+ MediaConstants.METADATA_VALUE_ATTRIBUTE_PRESENT
+ )
+ val desc =
+ MediaDescription.Builder().run {
+ setTitle(SESSION_TITLE)
+ setExtras(bundle)
+ build()
+ }
+ val currentTime = clock.elapsedRealtime()
+ mediaDataManager.addResumptionControls(
+ USER_ID,
+ desc,
+ Runnable {},
+ session.sessionToken,
+ APP_NAME,
+ pendingIntent,
+ PACKAGE_NAME
+ )
+ assertThat(backgroundExecutor.runAllReady()).isEqualTo(1)
+ assertThat(foregroundExecutor.runAllReady()).isEqualTo(1)
+ // THEN the media data indicates that it is for resumption
+ verify(listener)
+ .onMediaDataLoaded(
+ eq(PACKAGE_NAME),
+ eq(null),
+ capture(mediaDataCaptor),
+ eq(true),
+ eq(0),
+ eq(false)
+ )
+ val data = mediaDataCaptor.value
+ assertThat(data.resumption).isTrue()
+ assertThat(data.song).isEqualTo(SESSION_TITLE)
+ assertThat(data.app).isEqualTo(APP_NAME)
+ assertThat(data.actions).hasSize(1)
+ assertThat(data.semanticActions!!.playOrPause).isNotNull()
+ assertThat(data.lastActive).isAtLeast(currentTime)
+ assertThat(data.isExplicit).isTrue()
+ verify(logger).logResumeMediaAdded(anyInt(), eq(PACKAGE_NAME), eq(data.instanceId))
+ }
+
+ @Test
fun testResumptionDisabled_dismissesResumeControls() {
// WHEN there are resume controls and resumption is switched off
val desc =
diff --git a/packages/SystemUI/tests/src/com/android/systemui/media/controls/ui/MediaCarouselControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/media/controls/ui/MediaCarouselControllerTest.kt
index 039dd4d..e4e95e5 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/media/controls/ui/MediaCarouselControllerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/media/controls/ui/MediaCarouselControllerTest.kt
@@ -20,6 +20,7 @@
import android.content.res.Configuration
import android.testing.AndroidTestingRunner
import android.testing.TestableLooper
+import android.util.MathUtils.abs
import androidx.test.filters.SmallTest
import com.android.internal.logging.InstanceId
import com.android.systemui.SysuiTestCase
@@ -31,14 +32,11 @@
import com.android.systemui.media.controls.models.recommendation.SmartspaceMediaData
import com.android.systemui.media.controls.pipeline.EMPTY_SMARTSPACE_MEDIA_DATA
import com.android.systemui.media.controls.pipeline.MediaDataManager
-import com.android.systemui.media.controls.ui.MediaCarouselController.Companion.ANIMATION_BASE_DURATION
-import com.android.systemui.media.controls.ui.MediaCarouselController.Companion.DURATION
-import com.android.systemui.media.controls.ui.MediaCarouselController.Companion.PAGINATION_DELAY
-import com.android.systemui.media.controls.ui.MediaCarouselController.Companion.TRANSFORM_BEZIER
import com.android.systemui.media.controls.ui.MediaHierarchyManager.Companion.LOCATION_QS
import com.android.systemui.media.controls.util.MediaUiEventLogger
import com.android.systemui.plugins.ActivityStarter
import com.android.systemui.plugins.FalsingManager
+import com.android.systemui.qs.PageIndicator
import com.android.systemui.statusbar.notification.collection.provider.OnReorderingAllowedListener
import com.android.systemui.statusbar.notification.collection.provider.VisualStabilityProvider
import com.android.systemui.statusbar.policy.ConfigurationController
@@ -56,6 +54,7 @@
import org.mockito.ArgumentCaptor
import org.mockito.Captor
import org.mockito.Mock
+import org.mockito.Mockito.floatThat
import org.mockito.Mockito.mock
import org.mockito.Mockito.verify
import org.mockito.Mockito.`when` as whenever
@@ -86,6 +85,8 @@
@Mock lateinit var debugLogger: MediaCarouselControllerLogger
@Mock lateinit var mediaViewController: MediaViewController
@Mock lateinit var smartspaceMediaData: SmartspaceMediaData
+ @Mock lateinit var mediaCarousel: MediaScrollView
+ @Mock lateinit var pageIndicator: PageIndicator
@Captor lateinit var listener: ArgumentCaptor<MediaDataManager.Listener>
@Captor
lateinit var configListener: ArgumentCaptor<ConfigurationController.ConfigurationListener>
@@ -647,25 +648,22 @@
@Test
fun testSetCurrentState_UpdatePageIndicatorAlphaWhenSquish() {
val delta = 0.0001F
- val paginationSquishMiddle =
- TRANSFORM_BEZIER.getInterpolation(
- (PAGINATION_DELAY + DURATION / 2) / ANIMATION_BASE_DURATION
- )
- val paginationSquishEnd =
- TRANSFORM_BEZIER.getInterpolation(
- (PAGINATION_DELAY + DURATION) / ANIMATION_BASE_DURATION
- )
+ mediaCarouselController.mediaCarousel = mediaCarousel
+ mediaCarouselController.pageIndicator = pageIndicator
+ whenever(mediaCarousel.measuredHeight).thenReturn(100)
+ whenever(pageIndicator.translationY).thenReturn(80F)
+ whenever(pageIndicator.height).thenReturn(10)
whenever(mediaHostStatesManager.mediaHostStates)
.thenReturn(mutableMapOf(LOCATION_QS to mediaHostState))
whenever(mediaHostState.visible).thenReturn(true)
mediaCarouselController.currentEndLocation = LOCATION_QS
- whenever(mediaHostState.squishFraction).thenReturn(paginationSquishMiddle)
+ whenever(mediaHostState.squishFraction).thenReturn(0.938F)
mediaCarouselController.updatePageIndicatorAlpha()
- assertEquals(mediaCarouselController.pageIndicator.alpha, 0.5F, delta)
+ verify(pageIndicator).alpha = floatThat { abs(it - 0.5F) < delta }
- whenever(mediaHostState.squishFraction).thenReturn(paginationSquishEnd)
+ whenever(mediaHostState.squishFraction).thenReturn(1.0F)
mediaCarouselController.updatePageIndicatorAlpha()
- assertEquals(mediaCarouselController.pageIndicator.alpha, 1.0F, delta)
+ verify(pageIndicator).alpha = floatThat { abs(it - 1.0F) < delta }
}
@Ignore("b/253229241")
diff --git a/packages/SystemUI/tests/src/com/android/systemui/media/controls/ui/MediaControlPanelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/media/controls/ui/MediaControlPanelTest.kt
index b65f5cb..cfb19fc 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/media/controls/ui/MediaControlPanelTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/media/controls/ui/MediaControlPanelTest.kt
@@ -54,6 +54,7 @@
import androidx.lifecycle.LiveData
import androidx.test.filters.SmallTest
import com.android.internal.logging.InstanceId
+import com.android.internal.widget.CachingIconView
import com.android.systemui.ActivityIntentHelper
import com.android.systemui.R
import com.android.systemui.SysuiTestCase
@@ -154,6 +155,7 @@
@Mock private lateinit var albumView: ImageView
private lateinit var titleText: TextView
private lateinit var artistText: TextView
+ private lateinit var explicitIndicator: CachingIconView
private lateinit var seamless: ViewGroup
private lateinit var seamlessButton: View
@Mock private lateinit var seamlessBackground: RippleDrawable
@@ -216,6 +218,7 @@
this.set(Flags.UMO_SURFACE_RIPPLE, false)
this.set(Flags.UMO_TURBULENCE_NOISE, false)
this.set(Flags.MEDIA_FALSING_PENALTY, true)
+ this.set(Flags.MEDIA_EXPLICIT_INDICATOR, true)
}
@JvmField @Rule val mockito = MockitoJUnit.rule()
@@ -350,6 +353,7 @@
appIcon = ImageView(context)
titleText = TextView(context)
artistText = TextView(context)
+ explicitIndicator = CachingIconView(context).also { it.id = R.id.media_explicit_indicator }
seamless = FrameLayout(context)
seamless.foreground = seamlessBackground
seamlessButton = View(context)
@@ -396,6 +400,7 @@
whenever(albumView.foreground).thenReturn(mock(Drawable::class.java))
whenever(viewHolder.titleText).thenReturn(titleText)
whenever(viewHolder.artistText).thenReturn(artistText)
+ whenever(viewHolder.explicitIndicator).thenReturn(explicitIndicator)
whenever(seamlessBackground.getDrawable(0)).thenReturn(mock(GradientDrawable::class.java))
whenever(viewHolder.seamless).thenReturn(seamless)
whenever(viewHolder.seamlessButton).thenReturn(seamlessButton)
@@ -1019,6 +1024,7 @@
@Test
fun bindText() {
+ useRealConstraintSets()
player.attachPlayer(viewHolder)
player.bindPlayer(mediaData, PACKAGE)
@@ -1036,6 +1042,8 @@
handler.onAnimationEnd(mockAnimator)
assertThat(titleText.getText()).isEqualTo(TITLE)
assertThat(artistText.getText()).isEqualTo(ARTIST)
+ assertThat(expandedSet.getVisibility(explicitIndicator.id)).isEqualTo(ConstraintSet.GONE)
+ assertThat(collapsedSet.getVisibility(explicitIndicator.id)).isEqualTo(ConstraintSet.GONE)
// Rebinding should not trigger animation
player.bindPlayer(mediaData, PACKAGE)
@@ -1043,6 +1051,36 @@
}
@Test
+ fun bindTextWithExplicitIndicator() {
+ useRealConstraintSets()
+ val mediaDataWitExp = mediaData.copy(isExplicit = true)
+ player.attachPlayer(viewHolder)
+ player.bindPlayer(mediaDataWitExp, PACKAGE)
+
+ // Capture animation handler
+ val captor = argumentCaptor<Animator.AnimatorListener>()
+ verify(mockAnimator, times(2)).addListener(captor.capture())
+ val handler = captor.value
+
+ // Validate text views unchanged but animation started
+ assertThat(titleText.getText()).isEqualTo("")
+ assertThat(artistText.getText()).isEqualTo("")
+ verify(mockAnimator, times(1)).start()
+
+ // Binding only after animator runs
+ handler.onAnimationEnd(mockAnimator)
+ assertThat(titleText.getText()).isEqualTo(TITLE)
+ assertThat(artistText.getText()).isEqualTo(ARTIST)
+ assertThat(expandedSet.getVisibility(explicitIndicator.id)).isEqualTo(ConstraintSet.VISIBLE)
+ assertThat(collapsedSet.getVisibility(explicitIndicator.id))
+ .isEqualTo(ConstraintSet.VISIBLE)
+
+ // Rebinding should not trigger animation
+ player.bindPlayer(mediaData, PACKAGE)
+ verify(mockAnimator, times(3)).start()
+ }
+
+ @Test
fun bindTextInterrupted() {
val data0 = mediaData.copy(artist = "ARTIST_0")
val data1 = mediaData.copy(artist = "ARTIST_1")
diff --git a/packages/SystemUI/tests/src/com/android/systemui/media/controls/ui/MediaHierarchyManagerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/media/controls/ui/MediaHierarchyManagerTest.kt
index 920801f..a579518 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/media/controls/ui/MediaHierarchyManagerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/media/controls/ui/MediaHierarchyManagerTest.kt
@@ -29,6 +29,7 @@
import com.android.systemui.controls.controller.ControlsControllerImplTest.Companion.eq
import com.android.systemui.dreams.DreamOverlayStateController
import com.android.systemui.keyguard.WakefulnessLifecycle
+import com.android.systemui.media.controls.pipeline.MediaDataManager
import com.android.systemui.media.dream.MediaDreamComplication
import com.android.systemui.plugins.statusbar.StatusBarStateController
import com.android.systemui.shade.ShadeExpansionStateManager
@@ -76,6 +77,7 @@
@Mock private lateinit var mediaCarouselScrollHandler: MediaCarouselScrollHandler
@Mock private lateinit var wakefulnessLifecycle: WakefulnessLifecycle
@Mock private lateinit var keyguardViewController: KeyguardViewController
+ @Mock private lateinit var mediaDataManager: MediaDataManager
@Mock private lateinit var uniqueObjectHostView: UniqueObjectHostView
@Mock private lateinit var dreamOverlayStateController: DreamOverlayStateController
@Captor
@@ -110,6 +112,7 @@
keyguardStateController,
bypassController,
mediaCarouselController,
+ mediaDataManager,
keyguardViewController,
dreamOverlayStateController,
configurationController,
@@ -125,6 +128,7 @@
setupHost(qsHost, MediaHierarchyManager.LOCATION_QS, QS_TOP)
setupHost(qqsHost, MediaHierarchyManager.LOCATION_QQS, QQS_TOP)
whenever(statusBarStateController.state).thenReturn(StatusBarState.SHADE)
+ whenever(mediaDataManager.hasActiveMedia()).thenReturn(true)
whenever(mediaCarouselController.mediaCarouselScrollHandler)
.thenReturn(mediaCarouselScrollHandler)
val observer = wakefullnessObserver.value
@@ -357,17 +361,31 @@
}
@Test
- fun isCurrentlyInGuidedTransformation_hostNotVisible_returnsTrue() {
+ fun isCurrentlyInGuidedTransformation_hostNotVisible_returnsFalse_with_active() {
goToLockscreen()
enterGuidedTransformation()
whenever(lockHost.visible).thenReturn(false)
whenever(qsHost.visible).thenReturn(true)
whenever(qqsHost.visible).thenReturn(true)
+ whenever(mediaDataManager.hasActiveMediaOrRecommendation()).thenReturn(true)
assertThat(mediaHierarchyManager.isCurrentlyInGuidedTransformation()).isFalse()
}
@Test
+ fun isCurrentlyInGuidedTransformation_hostNotVisible_returnsTrue_without_active() {
+ // To keep the appearing behavior, we need to be in a guided transition
+ goToLockscreen()
+ enterGuidedTransformation()
+ whenever(lockHost.visible).thenReturn(false)
+ whenever(qsHost.visible).thenReturn(true)
+ whenever(qqsHost.visible).thenReturn(true)
+ whenever(mediaDataManager.hasActiveMediaOrRecommendation()).thenReturn(false)
+
+ assertThat(mediaHierarchyManager.isCurrentlyInGuidedTransformation()).isTrue()
+ }
+
+ @Test
fun testDream() {
goToDream()
setMediaDreamComplicationEnabled(true)
diff --git a/packages/SystemUI/tests/src/com/android/systemui/media/controls/ui/MediaViewControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/media/controls/ui/MediaViewControllerTest.kt
index 35b0eb6..4ed6d7c 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/media/controls/ui/MediaViewControllerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/media/controls/ui/MediaViewControllerTest.kt
@@ -22,13 +22,6 @@
import androidx.test.filters.SmallTest
import com.android.systemui.R
import com.android.systemui.SysuiTestCase
-import com.android.systemui.media.controls.ui.MediaCarouselController.Companion.ANIMATION_BASE_DURATION
-import com.android.systemui.media.controls.ui.MediaCarouselController.Companion.CONTROLS_DELAY
-import com.android.systemui.media.controls.ui.MediaCarouselController.Companion.DETAILS_DELAY
-import com.android.systemui.media.controls.ui.MediaCarouselController.Companion.DURATION
-import com.android.systemui.media.controls.ui.MediaCarouselController.Companion.MEDIACONTAINERS_DELAY
-import com.android.systemui.media.controls.ui.MediaCarouselController.Companion.MEDIATITLES_DELAY
-import com.android.systemui.media.controls.ui.MediaCarouselController.Companion.TRANSFORM_BEZIER
import com.android.systemui.util.animation.MeasurementInput
import com.android.systemui.util.animation.TransitionLayout
import com.android.systemui.util.animation.TransitionViewState
@@ -60,9 +53,10 @@
@Mock private lateinit var controlWidgetState: WidgetState
@Mock private lateinit var bgWidgetState: WidgetState
@Mock private lateinit var mediaTitleWidgetState: WidgetState
+ @Mock private lateinit var mediaSubTitleWidgetState: WidgetState
@Mock private lateinit var mediaContainerWidgetState: WidgetState
- val delta = 0.0001F
+ val delta = 0.1F
private lateinit var mediaViewController: MediaViewController
@@ -76,10 +70,11 @@
@Test
fun testObtainViewState_applySquishFraction_toPlayerTransitionViewState_height() {
mediaViewController.attach(player, MediaViewController.TYPE.PLAYER)
- player.measureState = TransitionViewState().apply {
- this.height = 100
- this.measureHeight = 100
- }
+ player.measureState =
+ TransitionViewState().apply {
+ this.height = 100
+ this.measureHeight = 100
+ }
mediaHostStateHolder.expansion = 1f
val widthMeasureSpec = View.MeasureSpec.makeMeasureSpec(100, View.MeasureSpec.EXACTLY)
val heightMeasureSpec = View.MeasureSpec.makeMeasureSpec(100, View.MeasureSpec.EXACTLY)
@@ -128,29 +123,21 @@
R.id.header_artist to detailWidgetState
)
)
-
- val detailSquishMiddle =
- TRANSFORM_BEZIER.getInterpolation(
- (DETAILS_DELAY + DURATION / 2) / ANIMATION_BASE_DURATION
- )
- mediaViewController.squishViewState(mockViewState, detailSquishMiddle)
+ whenever(mockCopiedState.measureHeight).thenReturn(200)
+ // detail widgets occupy [90, 100]
+ whenever(detailWidgetState.y).thenReturn(90F)
+ whenever(detailWidgetState.height).thenReturn(10)
+ // control widgets occupy [150, 170]
+ whenever(controlWidgetState.y).thenReturn(150F)
+ whenever(controlWidgetState.height).thenReturn(20)
+ // in current beizer, when the progress reach 0.38, the result will be 0.5
+ mediaViewController.squishViewState(mockViewState, 119F / 200F)
verify(detailWidgetState).alpha = floatThat { kotlin.math.abs(it - 0.5F) < delta }
-
- val detailSquishEnd =
- TRANSFORM_BEZIER.getInterpolation((DETAILS_DELAY + DURATION) / ANIMATION_BASE_DURATION)
- mediaViewController.squishViewState(mockViewState, detailSquishEnd)
+ mediaViewController.squishViewState(mockViewState, 150F / 200F)
verify(detailWidgetState).alpha = floatThat { kotlin.math.abs(it - 1.0F) < delta }
-
- val controlSquishMiddle =
- TRANSFORM_BEZIER.getInterpolation(
- (CONTROLS_DELAY + DURATION / 2) / ANIMATION_BASE_DURATION
- )
- mediaViewController.squishViewState(mockViewState, controlSquishMiddle)
+ mediaViewController.squishViewState(mockViewState, 181.4F / 200F)
verify(controlWidgetState).alpha = floatThat { kotlin.math.abs(it - 0.5F) < delta }
-
- val controlSquishEnd =
- TRANSFORM_BEZIER.getInterpolation((CONTROLS_DELAY + DURATION) / ANIMATION_BASE_DURATION)
- mediaViewController.squishViewState(mockViewState, controlSquishEnd)
+ mediaViewController.squishViewState(mockViewState, 200F / 200F)
verify(controlWidgetState).alpha = floatThat { kotlin.math.abs(it - 1.0F) < delta }
}
@@ -161,36 +148,33 @@
.thenReturn(
mutableMapOf(
R.id.media_title1 to mediaTitleWidgetState,
+ R.id.media_subtitle1 to mediaSubTitleWidgetState,
R.id.media_cover1_container to mediaContainerWidgetState
)
)
+ whenever(mockCopiedState.measureHeight).thenReturn(360)
+ // media container widgets occupy [20, 300]
+ whenever(mediaContainerWidgetState.y).thenReturn(20F)
+ whenever(mediaContainerWidgetState.height).thenReturn(280)
+ // media title widgets occupy [320, 330]
+ whenever(mediaTitleWidgetState.y).thenReturn(320F)
+ whenever(mediaTitleWidgetState.height).thenReturn(10)
+ // media subtitle widgets occupy [340, 350]
+ whenever(mediaSubTitleWidgetState.y).thenReturn(340F)
+ whenever(mediaSubTitleWidgetState.height).thenReturn(10)
- val containerSquishMiddle =
- TRANSFORM_BEZIER.getInterpolation(
- (MEDIACONTAINERS_DELAY + DURATION / 2) / ANIMATION_BASE_DURATION
- )
- mediaViewController.squishViewState(mockViewState, containerSquishMiddle)
+ // in current beizer, when the progress reach 0.38, the result will be 0.5
+ mediaViewController.squishViewState(mockViewState, 307.6F / 360F)
verify(mediaContainerWidgetState).alpha = floatThat { kotlin.math.abs(it - 0.5F) < delta }
-
- val containerSquishEnd =
- TRANSFORM_BEZIER.getInterpolation(
- (MEDIACONTAINERS_DELAY + DURATION) / ANIMATION_BASE_DURATION
- )
- mediaViewController.squishViewState(mockViewState, containerSquishEnd)
+ mediaViewController.squishViewState(mockViewState, 320F / 360F)
verify(mediaContainerWidgetState).alpha = floatThat { kotlin.math.abs(it - 1.0F) < delta }
-
- val titleSquishMiddle =
- TRANSFORM_BEZIER.getInterpolation(
- (MEDIATITLES_DELAY + DURATION / 2) / ANIMATION_BASE_DURATION
- )
- mediaViewController.squishViewState(mockViewState, titleSquishMiddle)
+ // media title and media subtitle are in same widget group, should be calculate together and
+ // have same alpha
+ mediaViewController.squishViewState(mockViewState, 353.8F / 360F)
verify(mediaTitleWidgetState).alpha = floatThat { kotlin.math.abs(it - 0.5F) < delta }
-
- val titleSquishEnd =
- TRANSFORM_BEZIER.getInterpolation(
- (MEDIATITLES_DELAY + DURATION) / ANIMATION_BASE_DURATION
- )
- mediaViewController.squishViewState(mockViewState, titleSquishEnd)
+ verify(mediaSubTitleWidgetState).alpha = floatThat { kotlin.math.abs(it - 0.5F) < delta }
+ mediaViewController.squishViewState(mockViewState, 360F / 360F)
verify(mediaTitleWidgetState).alpha = floatThat { kotlin.math.abs(it - 1.0F) < delta }
+ verify(mediaSubTitleWidgetState).alpha = floatThat { kotlin.math.abs(it - 1.0F) < delta }
}
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/media/dialog/MediaOutputControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/media/dialog/MediaOutputControllerTest.java
index b16a39f..f5432e2 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/media/dialog/MediaOutputControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/media/dialog/MediaOutputControllerTest.java
@@ -102,8 +102,6 @@
private MediaOutputController.Callback mCb = mock(MediaOutputController.Callback.class);
private MediaDevice mMediaDevice1 = mock(MediaDevice.class);
private MediaDevice mMediaDevice2 = mock(MediaDevice.class);
- private MediaItem mMediaItem1 = mock(MediaItem.class);
- private MediaItem mMediaItem2 = mock(MediaItem.class);
private NearbyDevice mNearbyDevice1 = mock(NearbyDevice.class);
private NearbyDevice mNearbyDevice2 = mock(NearbyDevice.class);
private MediaMetadata mMediaMetadata = mock(MediaMetadata.class);
@@ -127,7 +125,6 @@
private LocalMediaManager mLocalMediaManager;
private List<MediaController> mMediaControllers = new ArrayList<>();
private List<MediaDevice> mMediaDevices = new ArrayList<>();
- private List<MediaItem> mMediaItemList = new ArrayList<>();
private List<NearbyDevice> mNearbyDevices = new ArrayList<>();
private MediaDescription mMediaDescription;
private List<RoutingSessionInfo> mRoutingSessionInfos = new ArrayList<>();
@@ -149,7 +146,9 @@
Optional.of(mNearbyMediaDevicesManager), mAudioManager, mPowerExemptionManager,
mKeyguardManager, mFlags);
when(mFlags.isEnabled(Flags.OUTPUT_SWITCHER_ADVANCED_LAYOUT)).thenReturn(false);
+ when(mFlags.isEnabled(Flags.OUTPUT_SWITCHER_ROUTES_PROCESSING)).thenReturn(false);
mLocalMediaManager = spy(mMediaOutputController.mLocalMediaManager);
+ when(mLocalMediaManager.isPreferenceRouteListingExist()).thenReturn(false);
mMediaOutputController.mLocalMediaManager = mLocalMediaManager;
MediaDescription.Builder builder = new MediaDescription.Builder();
builder.setTitle(TEST_SONG);
@@ -160,16 +159,12 @@
when(mMediaDevice2.getId()).thenReturn(TEST_DEVICE_2_ID);
mMediaDevices.add(mMediaDevice1);
mMediaDevices.add(mMediaDevice2);
- when(mMediaItem1.getMediaDevice()).thenReturn(Optional.of(mMediaDevice1));
- when(mMediaItem2.getMediaDevice()).thenReturn(Optional.of(mMediaDevice2));
- mMediaItemList.add(mMediaItem1);
- mMediaItemList.add(mMediaItem2);
when(mNearbyDevice1.getMediaRoute2Id()).thenReturn(TEST_DEVICE_1_ID);
- when(mNearbyDevice1.getRangeZone()).thenReturn(NearbyDevice.RANGE_CLOSE);
+ when(mNearbyDevice1.getRangeZone()).thenReturn(NearbyDevice.RANGE_FAR);
when(mNearbyDevice2.getMediaRoute2Id()).thenReturn(TEST_DEVICE_2_ID);
- when(mNearbyDevice2.getRangeZone()).thenReturn(NearbyDevice.RANGE_FAR);
+ when(mNearbyDevice2.getRangeZone()).thenReturn(NearbyDevice.RANGE_CLOSE);
mNearbyDevices.add(mNearbyDevice1);
mNearbyDevices.add(mNearbyDevice2);
}
@@ -274,8 +269,20 @@
mMediaOutputController.onDevicesUpdated(mNearbyDevices);
mMediaOutputController.onDeviceListUpdate(mMediaDevices);
- verify(mMediaDevice1).setRangeZone(NearbyDevice.RANGE_CLOSE);
- verify(mMediaDevice2).setRangeZone(NearbyDevice.RANGE_FAR);
+ verify(mMediaDevice1).setRangeZone(NearbyDevice.RANGE_FAR);
+ verify(mMediaDevice2).setRangeZone(NearbyDevice.RANGE_CLOSE);
+ }
+
+ @Test
+ public void onDeviceListUpdate_withNearbyDevices_rankByRangeInformation()
+ throws RemoteException {
+ mMediaOutputController.start(mCb);
+ reset(mCb);
+
+ mMediaOutputController.onDevicesUpdated(mNearbyDevices);
+ mMediaOutputController.onDeviceListUpdate(mMediaDevices);
+
+ assertThat(mMediaDevices.get(0).getId()).isEqualTo(TEST_DEVICE_1_ID);
}
@Test
@@ -292,6 +299,22 @@
}
@Test
+ public void routeProcessSupport_onDeviceListUpdate_preferenceExist_NotUpdatesRangeInformation()
+ throws RemoteException {
+ when(mLocalMediaManager.isPreferenceRouteListingExist()).thenReturn(true);
+ when(mFlags.isEnabled(Flags.OUTPUT_SWITCHER_ROUTES_PROCESSING)).thenReturn(true);
+ when(mFlags.isEnabled(Flags.OUTPUT_SWITCHER_ADVANCED_LAYOUT)).thenReturn(true);
+ mMediaOutputController.start(mCb);
+ reset(mCb);
+
+ mMediaOutputController.onDevicesUpdated(mNearbyDevices);
+ mMediaOutputController.onDeviceListUpdate(mMediaDevices);
+
+ verify(mMediaDevice1, never()).setRangeZone(anyInt());
+ verify(mMediaDevice2, never()).setRangeZone(anyInt());
+ }
+
+ @Test
public void advanced_onDeviceListUpdate_verifyDeviceListCallback() {
when(mFlags.isEnabled(Flags.OUTPUT_SWITCHER_ADVANCED_LAYOUT)).thenReturn(true);
mMediaOutputController.start(mCb);
@@ -307,6 +330,35 @@
assertThat(devices.containsAll(mMediaDevices)).isTrue();
assertThat(devices.size()).isEqualTo(mMediaDevices.size());
+ assertThat(mMediaOutputController.getMediaItemList().size()).isEqualTo(
+ mMediaDevices.size() + 2);
+ verify(mCb).onDeviceListChanged();
+ }
+
+ @Test
+ public void advanced_categorizeMediaItems_withSuggestedDevice_verifyDeviceListSize() {
+ when(mFlags.isEnabled(Flags.OUTPUT_SWITCHER_ADVANCED_LAYOUT)).thenReturn(true);
+ when(mMediaDevice1.isSuggestedDevice()).thenReturn(true);
+ when(mMediaDevice2.isSuggestedDevice()).thenReturn(false);
+
+ mMediaOutputController.start(mCb);
+ reset(mCb);
+ mMediaOutputController.getMediaItemList().clear();
+ mMediaOutputController.onDeviceListUpdate(mMediaDevices);
+ final List<MediaDevice> devices = new ArrayList<>();
+ int dividerSize = 0;
+ for (MediaItem item : mMediaOutputController.getMediaItemList()) {
+ if (item.getMediaDevice().isPresent()) {
+ devices.add(item.getMediaDevice().get());
+ }
+ if (item.getMediaItemType() == MediaItem.MediaItemType.TYPE_GROUP_DIVIDER) {
+ dividerSize++;
+ }
+ }
+
+ assertThat(devices.containsAll(mMediaDevices)).isTrue();
+ assertThat(devices.size()).isEqualTo(mMediaDevices.size());
+ assertThat(dividerSize).isEqualTo(2);
verify(mCb).onDeviceListChanged();
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/media/taptotransfer/sender/MediaTttSenderCoordinatorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/media/taptotransfer/sender/MediaTttSenderCoordinatorTest.kt
index 4cc12c7..f5b3959 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/media/taptotransfer/sender/MediaTttSenderCoordinatorTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/media/taptotransfer/sender/MediaTttSenderCoordinatorTest.kt
@@ -206,6 +206,21 @@
}
@Test
+ fun commandQueueCallback_almostCloseToStartCast_deviceNameBlank_showsDefaultDeviceName() {
+ commandQueueCallback.updateMediaTapToTransferSenderDisplay(
+ StatusBarManager.MEDIA_TRANSFER_SENDER_STATE_ALMOST_CLOSE_TO_START_CAST,
+ routeInfoWithBlankDeviceName,
+ null,
+ )
+
+ val chipbarView = getChipbarView()
+ assertThat(chipbarView.getChipText())
+ .contains(context.getString(R.string.media_ttt_default_device_type))
+ assertThat(chipbarView.getChipText())
+ .isNotEqualTo(ChipStateSender.ALMOST_CLOSE_TO_START_CAST.getExpectedStateText())
+ }
+
+ @Test
fun commandQueueCallback_almostCloseToEndCast_triggersCorrectChip() {
commandQueueCallback.updateMediaTapToTransferSenderDisplay(
StatusBarManager.MEDIA_TRANSFER_SENDER_STATE_ALMOST_CLOSE_TO_END_CAST,
@@ -248,6 +263,21 @@
}
@Test
+ fun commandQueueCallback_transferToReceiverTriggered_deviceNameBlank_showsDefaultDeviceName() {
+ commandQueueCallback.updateMediaTapToTransferSenderDisplay(
+ StatusBarManager.MEDIA_TRANSFER_SENDER_STATE_TRANSFER_TO_RECEIVER_TRIGGERED,
+ routeInfoWithBlankDeviceName,
+ null,
+ )
+
+ val chipbarView = getChipbarView()
+ assertThat(chipbarView.getChipText())
+ .contains(context.getString(R.string.media_ttt_default_device_type))
+ assertThat(chipbarView.getChipText())
+ .isNotEqualTo(ChipStateSender.TRANSFER_TO_RECEIVER_TRIGGERED.getExpectedStateText())
+ }
+
+ @Test
fun commandQueueCallback_transferToThisDeviceTriggered_triggersCorrectChip() {
commandQueueCallback.updateMediaTapToTransferSenderDisplay(
StatusBarManager.MEDIA_TRANSFER_SENDER_STATE_TRANSFER_TO_THIS_DEVICE_TRIGGERED,
@@ -934,6 +964,7 @@
private const val APP_NAME = "Fake app name"
private const val OTHER_DEVICE_NAME = "My Tablet"
+private const val BLANK_DEVICE_NAME = " "
private const val PACKAGE_NAME = "com.android.systemui"
private const val TIMEOUT = 10000
@@ -942,3 +973,9 @@
.addFeature("feature")
.setClientPackageName(PACKAGE_NAME)
.build()
+
+private val routeInfoWithBlankDeviceName =
+ MediaRoute2Info.Builder("id", BLANK_DEVICE_NAME)
+ .addFeature("feature")
+ .setClientPackageName(PACKAGE_NAME)
+ .build()
diff --git a/packages/SystemUI/tests/src/com/android/systemui/notetask/NoteTaskControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/notetask/NoteTaskControllerTest.kt
index 4a9c750..8440455 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/notetask/NoteTaskControllerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/notetask/NoteTaskControllerTest.kt
@@ -24,7 +24,7 @@
import android.test.suitebuilder.annotation.SmallTest
import androidx.test.runner.AndroidJUnit4
import com.android.systemui.SysuiTestCase
-import com.android.systemui.notetask.NoteTaskIntentResolver.Companion.NOTES_ACTION
+import com.android.systemui.notetask.NoteTaskIntentResolver.Companion.ACTION_CREATE_NOTE
import com.android.systemui.notetask.shortcut.CreateNoteTaskShortcutActivity
import com.android.systemui.util.mockito.argumentCaptor
import com.android.systemui.util.mockito.eq
@@ -50,7 +50,7 @@
@RunWith(AndroidJUnit4::class)
internal class NoteTaskControllerTest : SysuiTestCase() {
- private val notesIntent = Intent(NOTES_ACTION)
+ private val notesIntent = Intent(ACTION_CREATE_NOTE)
@Mock lateinit var context: Context
@Mock lateinit var packageManager: PackageManager
@@ -93,7 +93,7 @@
createNoteTaskController().showNoteTask(isInMultiWindowMode = false)
verify(context).startActivity(notesIntent)
- verify(bubbles, never()).showAppBubble(notesIntent)
+ verify(bubbles, never()).showOrHideAppBubble(notesIntent)
}
@Test
@@ -102,7 +102,7 @@
createNoteTaskController().showNoteTask(isInMultiWindowMode = false)
- verify(bubbles).showAppBubble(notesIntent)
+ verify(bubbles).showOrHideAppBubble(notesIntent)
verify(context, never()).startActivity(notesIntent)
}
@@ -113,7 +113,7 @@
createNoteTaskController().showNoteTask(isInMultiWindowMode = true)
verify(context).startActivity(notesIntent)
- verify(bubbles, never()).showAppBubble(notesIntent)
+ verify(bubbles, never()).showOrHideAppBubble(notesIntent)
}
@Test
@@ -123,7 +123,7 @@
createNoteTaskController().showNoteTask(isInMultiWindowMode = false)
verify(context, never()).startActivity(notesIntent)
- verify(bubbles, never()).showAppBubble(notesIntent)
+ verify(bubbles, never()).showOrHideAppBubble(notesIntent)
}
@Test
@@ -133,7 +133,7 @@
createNoteTaskController().showNoteTask(isInMultiWindowMode = false)
verify(context, never()).startActivity(notesIntent)
- verify(bubbles, never()).showAppBubble(notesIntent)
+ verify(bubbles, never()).showOrHideAppBubble(notesIntent)
}
@Test
@@ -143,7 +143,7 @@
createNoteTaskController().showNoteTask(isInMultiWindowMode = false)
verify(context, never()).startActivity(notesIntent)
- verify(bubbles, never()).showAppBubble(notesIntent)
+ verify(bubbles, never()).showOrHideAppBubble(notesIntent)
}
@Test
@@ -153,7 +153,7 @@
createNoteTaskController().showNoteTask(isInMultiWindowMode = false)
verify(context, never()).startActivity(notesIntent)
- verify(bubbles, never()).showAppBubble(notesIntent)
+ verify(bubbles, never()).showOrHideAppBubble(notesIntent)
}
@Test
@@ -161,7 +161,7 @@
createNoteTaskController(isEnabled = false).showNoteTask()
verify(context, never()).startActivity(notesIntent)
- verify(bubbles, never()).showAppBubble(notesIntent)
+ verify(bubbles, never()).showOrHideAppBubble(notesIntent)
}
@Test
@@ -171,7 +171,7 @@
createNoteTaskController().showNoteTask(isInMultiWindowMode = false)
verify(context, never()).startActivity(notesIntent)
- verify(bubbles, never()).showAppBubble(notesIntent)
+ verify(bubbles, never()).showOrHideAppBubble(notesIntent)
}
// endregion
diff --git a/packages/SystemUI/tests/src/com/android/systemui/notetask/NoteTaskInitializerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/notetask/NoteTaskInitializerTest.kt
index 538131a..010ac5b 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/notetask/NoteTaskInitializerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/notetask/NoteTaskInitializerTest.kt
@@ -106,7 +106,9 @@
// region handleSystemKey
@Test
fun handleSystemKey_receiveValidSystemKey_shouldShowNoteTask() {
- createNoteTaskInitializer().callbacks.handleSystemKey(KeyEvent.KEYCODE_VIDEO_APP_1)
+ createNoteTaskInitializer()
+ .callbacks
+ .handleSystemKey(NoteTaskController.NOTE_TASK_KEY_EVENT)
verify(noteTaskController).showNoteTask()
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/notetask/NoteTaskIntentResolverTest.kt b/packages/SystemUI/tests/src/com/android/systemui/notetask/NoteTaskIntentResolverTest.kt
index dd2cc2f..bbe60f4 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/notetask/NoteTaskIntentResolverTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/notetask/NoteTaskIntentResolverTest.kt
@@ -23,11 +23,10 @@
import android.content.pm.PackageManager
import android.content.pm.PackageManager.ResolveInfoFlags
import android.content.pm.ResolveInfo
-import android.content.pm.ServiceInfo
import android.test.suitebuilder.annotation.SmallTest
import androidx.test.runner.AndroidJUnit4
import com.android.systemui.SysuiTestCase
-import com.android.systemui.notetask.NoteTaskIntentResolver.Companion.NOTES_ACTION
+import com.android.systemui.notetask.NoteTaskIntentResolver.Companion.ACTION_CREATE_NOTE
import com.android.systemui.util.mockito.whenever
import com.google.common.truth.Truth.assertThat
import org.junit.Before
@@ -58,19 +57,13 @@
}
private fun createResolveInfo(
- packageName: String = "PackageName",
- activityInfo: ActivityInfo? = null,
+ activityInfo: ActivityInfo? = createActivityInfo(),
): ResolveInfo {
- return ResolveInfo().apply {
- serviceInfo =
- ServiceInfo().apply {
- applicationInfo = ApplicationInfo().apply { this.packageName = packageName }
- }
- this.activityInfo = activityInfo
- }
+ return ResolveInfo().apply { this.activityInfo = activityInfo }
}
private fun createActivityInfo(
+ packageName: String = "PackageName",
name: String? = "ActivityName",
exported: Boolean = true,
enabled: Boolean = true,
@@ -87,6 +80,7 @@
if (turnScreenOn) {
flags = flags or ActivityInfo.FLAG_TURN_SCREEN_ON
}
+ this.applicationInfo = ApplicationInfo().apply { this.packageName = packageName }
}
}
@@ -107,7 +101,8 @@
val actual = resolver.resolveIntent()
val expected =
- Intent(NOTES_ACTION)
+ Intent(ACTION_CREATE_NOTE)
+ .setPackage("PackageName")
.setComponent(ComponentName("PackageName", "ActivityName"))
.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
// Compares the string representation of both intents, as they are different instances.
@@ -204,7 +199,9 @@
@Test
fun resolveIntent_packageNameIsBlank_shouldReturnNull() {
- givenQueryIntentActivities { listOf(createResolveInfo(packageName = "")) }
+ givenQueryIntentActivities {
+ listOf(createResolveInfo(createActivityInfo(packageName = "")))
+ }
val actual = resolver.resolveIntent()
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/external/TileLifecycleManagerTest.java b/packages/SystemUI/tests/src/com/android/systemui/qs/external/TileLifecycleManagerTest.java
index 04b50d8..2e6b0cf 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/external/TileLifecycleManagerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/external/TileLifecycleManagerTest.java
@@ -15,11 +15,17 @@
*/
package com.android.systemui.qs.external;
+import static android.service.quicksettings.TileService.START_ACTIVITY_NEEDS_PENDING_INTENT;
+
+import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn;
+import static com.android.dx.mockito.inline.extended.ExtendedMockito.mockitoSession;
+
import static junit.framework.Assert.assertFalse;
import static junit.framework.Assert.assertTrue;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotEquals;
+import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.any;
import static org.mockito.Mockito.anyInt;
import static org.mockito.Mockito.anyString;
@@ -29,6 +35,7 @@
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
+import android.app.compat.CompatChanges;
import android.content.BroadcastReceiver;
import android.content.ComponentName;
import android.content.Context;
@@ -59,6 +66,7 @@
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.ArgumentCaptor;
+import org.mockito.MockitoSession;
@SmallTest
@RunWith(AndroidJUnit4.class)
@@ -77,11 +85,16 @@
private Handler mHandler;
private TileLifecycleManager mStateManager;
private TestContextWrapper mWrappedContext;
+ private MockitoSession mMockitoSession;
@Before
public void setUp() throws Exception {
setPackageEnabled(true);
mTileServiceComponentName = new ComponentName(mContext, "FakeTileService.class");
+ mMockitoSession = mockitoSession()
+ .initMocks(this)
+ .mockStatic(CompatChanges.class)
+ .startMocking();
// Stub.asInterface will just return itself.
when(mMockTileService.queryLocalInterface(anyString())).thenReturn(mMockTileService);
@@ -106,7 +119,13 @@
@After
public void tearDown() throws Exception {
- mThread.quit();
+ if (mMockitoSession != null) {
+ mMockitoSession.finishMocking();
+ }
+ if (mThread != null) {
+ mThread.quit();
+ }
+
mStateManager.handleDestroy();
}
@@ -290,6 +309,50 @@
verify(falseContext).unbindService(captor.getValue());
}
+ @Test
+ public void testVersionUDoesNotBindsAllowBackgroundActivity() {
+ mockChangeEnabled(START_ACTIVITY_NEEDS_PENDING_INTENT, true);
+ Context falseContext = mock(Context.class);
+ TileLifecycleManager manager = new TileLifecycleManager(mHandler, falseContext,
+ mock(IQSService.class),
+ mMockPackageManagerAdapter,
+ mMockBroadcastDispatcher,
+ mTileServiceIntent,
+ mUser);
+
+ manager.setBindService(true);
+ int flags = Context.BIND_AUTO_CREATE
+ | Context.BIND_FOREGROUND_SERVICE_WHILE_AWAKE
+ | Context.BIND_WAIVE_PRIORITY;
+
+ verify(falseContext).bindServiceAsUser(any(), any(), eq(flags), any());
+ }
+
+ @Test
+ public void testVersionLessThanUBindsAllowBackgroundActivity() {
+ mockChangeEnabled(START_ACTIVITY_NEEDS_PENDING_INTENT, false);
+ Context falseContext = mock(Context.class);
+ TileLifecycleManager manager = new TileLifecycleManager(mHandler, falseContext,
+ mock(IQSService.class),
+ mMockPackageManagerAdapter,
+ mMockBroadcastDispatcher,
+ mTileServiceIntent,
+ mUser);
+
+ manager.setBindService(true);
+ int flags = Context.BIND_AUTO_CREATE
+ | Context.BIND_FOREGROUND_SERVICE_WHILE_AWAKE
+ | Context.BIND_ALLOW_BACKGROUND_ACTIVITY_STARTS
+ | Context.BIND_WAIVE_PRIORITY;
+
+ verify(falseContext).bindServiceAsUser(any(), any(), eq(flags), any());
+ }
+
+ private void mockChangeEnabled(long changeId, boolean enabled) {
+ doReturn(enabled).when(() -> CompatChanges.isChangeEnabled(eq(changeId), anyString(),
+ any(UserHandle.class)));
+ }
+
private static class TestContextWrapper extends ContextWrapper {
private IntentFilter mLastIntentFilter;
private int mLastFlag;
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/tileimpl/QSFactoryImplTest.kt b/packages/SystemUI/tests/src/com/android/systemui/qs/tileimpl/QSFactoryImplTest.kt
index ca3182a..3281fa9 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/tileimpl/QSFactoryImplTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/tileimpl/QSFactoryImplTest.kt
@@ -28,7 +28,6 @@
import com.android.systemui.qs.tiles.BluetoothTile
import com.android.systemui.qs.tiles.CameraToggleTile
import com.android.systemui.qs.tiles.CastTile
-import com.android.systemui.qs.tiles.CellularTile
import com.android.systemui.qs.tiles.ColorCorrectionTile
import com.android.systemui.qs.tiles.ColorInversionTile
import com.android.systemui.qs.tiles.DataSaverTile
@@ -49,7 +48,6 @@
import com.android.systemui.qs.tiles.RotationLockTile
import com.android.systemui.qs.tiles.ScreenRecordTile
import com.android.systemui.qs.tiles.UiModeNightTile
-import com.android.systemui.qs.tiles.WifiTile
import com.android.systemui.qs.tiles.WorkModeTile
import com.android.systemui.util.leak.GarbageMonitor
import com.google.common.truth.Truth.assertThat
@@ -63,10 +61,8 @@
import org.mockito.Mockito.`when` as whenever
private val specMap = mapOf(
- "wifi" to WifiTile::class.java,
"internet" to InternetTile::class.java,
"bt" to BluetoothTile::class.java,
- "cell" to CellularTile::class.java,
"dnd" to DndTile::class.java,
"inversion" to ColorInversionTile::class.java,
"airplane" to AirplaneModeTile::class.java,
@@ -102,10 +98,8 @@
@Mock(answer = Answers.RETURNS_SELF) private lateinit var customTileBuilder: CustomTile.Builder
@Mock private lateinit var customTile: CustomTile
- @Mock private lateinit var wifiTile: WifiTile
@Mock private lateinit var internetTile: InternetTile
@Mock private lateinit var bluetoothTile: BluetoothTile
- @Mock private lateinit var cellularTile: CellularTile
@Mock private lateinit var dndTile: DndTile
@Mock private lateinit var colorInversionTile: ColorInversionTile
@Mock private lateinit var airplaneTile: AirplaneModeTile
@@ -146,10 +140,8 @@
factory = QSFactoryImpl(
{ qsHost },
{ customTileBuilder },
- { wifiTile },
{ internetTile },
{ bluetoothTile },
- { cellularTile },
{ dndTile },
{ colorInversionTile },
{ airplaneTile },
diff --git a/packages/SystemUI/tests/src/com/android/systemui/screenrecord/RecordingControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/screenrecord/RecordingControllerTest.java
index 69f3e987..8127ccc 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/screenrecord/RecordingControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/screenrecord/RecordingControllerTest.java
@@ -107,7 +107,7 @@
mController.startCountdown(0, 0, startIntent, null);
verify(mCallback).onCountdownEnd();
- verify(startIntent).send();
+ verify(startIntent).send(any());
}
// Test that when recording is stopped, the stop intent is sent and listeners are notified.
@@ -125,7 +125,7 @@
assertFalse(mController.isStarting());
assertFalse(mController.isRecording());
- verify(stopIntent).send();
+ verify(stopIntent).send(any());
verify(mCallback).onRecordingEnd();
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/screenshot/TakeScreenshotServiceTest.kt b/packages/SystemUI/tests/src/com/android/systemui/screenshot/TakeScreenshotServiceTest.kt
index fa1fedb..99c79b0 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/screenshot/TakeScreenshotServiceTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/screenshot/TakeScreenshotServiceTest.kt
@@ -39,7 +39,6 @@
import com.android.internal.util.ScreenshotHelper.ScreenshotRequest
import com.android.systemui.SysuiTestCase
import com.android.systemui.flags.FakeFeatureFlags
-import com.android.systemui.flags.Flags.SCREENSHOT_REQUEST_PROCESSOR
import com.android.systemui.flags.Flags.SCREENSHOT_WORK_PROFILE_POLICY
import com.android.systemui.screenshot.ScreenshotEvent.SCREENSHOT_REQUESTED_KEY_CHORD
import com.android.systemui.screenshot.ScreenshotEvent.SCREENSHOT_REQUESTED_OVERVIEW
@@ -101,7 +100,6 @@
}.`when`(requestProcessor).processAsync(/* request= */ any(), /* callback= */ any())
// Flipped in selected test cases
- flags.set(SCREENSHOT_REQUEST_PROCESSOR, false)
flags.set(SCREENSHOT_WORK_PROFILE_POLICY, false)
service.attach(
@@ -149,31 +147,6 @@
}
@Test
- fun takeScreenshot_requestProcessorEnabled() {
- flags.set(SCREENSHOT_REQUEST_PROCESSOR, true)
-
- val request = ScreenshotRequest(
- TAKE_SCREENSHOT_FULLSCREEN,
- SCREENSHOT_KEY_CHORD,
- topComponent)
-
- service.handleRequest(request, { /* onSaved */ }, callback)
-
- verify(controller, times(1)).takeScreenshotFullscreen(
- eq(topComponent),
- /* onSavedListener = */ any(),
- /* requestCallback = */ any())
-
- assertEquals("Expected one UiEvent", eventLogger.numLogs(), 1)
- val logEvent = eventLogger.get(0)
-
- assertEquals("Expected SCREENSHOT_REQUESTED UiEvent",
- logEvent.eventId, SCREENSHOT_REQUESTED_KEY_CHORD.id)
- assertEquals("Expected supplied package name",
- topComponent.packageName, eventLogger.get(0).packageName)
- }
-
- @Test
fun takeScreenshotProvidedImage() {
val bounds = Rect(50, 50, 150, 150)
val bitmap = makeHardwareBitmap(100, 100)
diff --git a/packages/SystemUI/tests/src/com/android/systemui/screenshot/WorkProfileMessageControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/screenshot/WorkProfileMessageControllerTest.java
new file mode 100644
index 0000000..bd04b3c
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/screenshot/WorkProfileMessageControllerTest.java
@@ -0,0 +1,160 @@
+/*
+ * 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 com.android.systemui.screenshot;
+
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.ArgumentMatchers.nullable;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.pm.ActivityInfo;
+import android.content.pm.PackageManager;
+import android.graphics.drawable.Drawable;
+import android.os.UserHandle;
+import android.os.UserManager;
+import android.testing.AndroidTestingRunner;
+
+import androidx.test.filters.SmallTest;
+
+import com.android.systemui.util.FakeSharedPreferences;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.ArgumentCaptor;
+import org.mockito.ArgumentMatchers;
+import org.mockito.Captor;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+
+
+@SmallTest
+@RunWith(AndroidTestingRunner.class)
+public class WorkProfileMessageControllerTest {
+ private static final String DEFAULT_LABEL = "default label";
+ private static final String BADGED_DEFAULT_LABEL = "badged default label";
+ private static final String APP_LABEL = "app label";
+ private static final String BADGED_APP_LABEL = "badged app label";
+ private static final UserHandle NON_WORK_USER = UserHandle.of(0);
+ private static final UserHandle WORK_USER = UserHandle.of(10);
+
+ @Mock
+ private UserManager mUserManager;
+ @Mock
+ private PackageManager mPackageManager;
+ @Mock
+ private Context mContext;
+ @Mock
+ private WorkProfileMessageController.WorkProfileMessageDisplay mMessageDisplay;
+ @Mock
+ private Drawable mActivityIcon;
+ @Mock
+ private Drawable mBadgedActivityIcon;
+ @Mock
+ private ActivityInfo mActivityInfo;
+ @Captor
+ private ArgumentCaptor<Runnable> mRunnableArgumentCaptor;
+
+ private FakeSharedPreferences mSharedPreferences = new FakeSharedPreferences();
+
+ private WorkProfileMessageController mMessageController;
+
+ @Before
+ public void setup() throws PackageManager.NameNotFoundException {
+ MockitoAnnotations.initMocks(this);
+
+ when(mUserManager.isManagedProfile(eq(WORK_USER.getIdentifier()))).thenReturn(true);
+ when(mContext.getSharedPreferences(
+ eq(WorkProfileMessageController.SHARED_PREFERENCES_NAME),
+ eq(Context.MODE_PRIVATE))).thenReturn(mSharedPreferences);
+ when(mContext.getString(ArgumentMatchers.anyInt())).thenReturn(DEFAULT_LABEL);
+ when(mPackageManager.getUserBadgedLabel(eq(DEFAULT_LABEL), any()))
+ .thenReturn(BADGED_DEFAULT_LABEL);
+ when(mPackageManager.getUserBadgedLabel(eq(APP_LABEL), any()))
+ .thenReturn(BADGED_APP_LABEL);
+ when(mPackageManager.getActivityIcon(any(ComponentName.class)))
+ .thenReturn(mActivityIcon);
+ when(mPackageManager.getUserBadgedIcon(
+ any(), any())).thenReturn(mBadgedActivityIcon);
+ when(mPackageManager.getActivityInfo(any(),
+ any(PackageManager.ComponentInfoFlags.class))).thenReturn(mActivityInfo);
+ when(mActivityInfo.loadLabel(eq(mPackageManager))).thenReturn(APP_LABEL);
+
+ mSharedPreferences.edit().putBoolean(
+ WorkProfileMessageController.PREFERENCE_KEY, false).apply();
+
+ mMessageController = new WorkProfileMessageController(mContext, mUserManager,
+ mPackageManager);
+ }
+
+ @Test
+ public void testOnScreenshotTaken_notManaged() {
+ mMessageController.onScreenshotTaken(NON_WORK_USER, mMessageDisplay);
+
+ verify(mMessageDisplay, never())
+ .showWorkProfileMessage(any(), nullable(Drawable.class), any());
+ }
+
+ @Test
+ public void testOnScreenshotTaken_alreadyDismissed() {
+ mSharedPreferences.edit().putBoolean(
+ WorkProfileMessageController.PREFERENCE_KEY, true).apply();
+
+ mMessageController.onScreenshotTaken(WORK_USER, mMessageDisplay);
+
+ verify(mMessageDisplay, never())
+ .showWorkProfileMessage(any(), nullable(Drawable.class), any());
+ }
+
+ @Test
+ public void testOnScreenshotTaken_packageNotFound()
+ throws PackageManager.NameNotFoundException {
+ when(mPackageManager.getActivityInfo(any(),
+ any(PackageManager.ComponentInfoFlags.class))).thenThrow(
+ new PackageManager.NameNotFoundException());
+
+ mMessageController.onScreenshotTaken(WORK_USER, mMessageDisplay);
+
+ verify(mMessageDisplay).showWorkProfileMessage(
+ eq(BADGED_DEFAULT_LABEL), eq(null), any());
+ }
+
+ @Test
+ public void testOnScreenshotTaken() {
+ mMessageController.onScreenshotTaken(WORK_USER, mMessageDisplay);
+
+ verify(mMessageDisplay).showWorkProfileMessage(
+ eq(BADGED_APP_LABEL), eq(mBadgedActivityIcon), mRunnableArgumentCaptor.capture());
+
+ // Dismiss hasn't been tapped, preference untouched.
+ assertFalse(
+ mSharedPreferences.getBoolean(WorkProfileMessageController.PREFERENCE_KEY, false));
+
+ mRunnableArgumentCaptor.getValue().run();
+
+ // After dismiss has been tapped, the setting should be updated.
+ assertTrue(
+ mSharedPreferences.getBoolean(WorkProfileMessageController.PREFERENCE_KEY, false));
+ }
+}
+
diff --git a/packages/SystemUI/tests/src/com/android/systemui/settings/UserTrackerImplReceiveTest.kt b/packages/SystemUI/tests/src/com/android/systemui/settings/UserTrackerImplReceiveTest.kt
new file mode 100644
index 0000000..3710281
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/settings/UserTrackerImplReceiveTest.kt
@@ -0,0 +1,100 @@
+package com.android.systemui.settings
+
+import android.content.Context
+import android.content.Intent
+import android.content.pm.UserInfo
+import android.os.Handler
+import android.os.UserHandle
+import android.os.UserManager
+import androidx.concurrent.futures.DirectExecutor
+import androidx.test.filters.SmallTest
+import com.android.systemui.SysuiTestCase
+import com.android.systemui.dump.DumpManager
+import com.android.systemui.util.mockito.any
+import com.android.systemui.util.mockito.capture
+import com.google.common.truth.Truth.assertThat
+import java.util.concurrent.Executor
+import org.junit.Before
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.junit.runners.Parameterized
+import org.mockito.ArgumentCaptor
+import org.mockito.ArgumentMatchers
+import org.mockito.ArgumentMatchers.anyInt
+import org.mockito.Captor
+import org.mockito.Mock
+import org.mockito.Mockito.times
+import org.mockito.Mockito.verify
+import org.mockito.Mockito.`when`
+import org.mockito.MockitoAnnotations
+
+@SmallTest
+@RunWith(Parameterized::class)
+class UserTrackerImplReceiveTest : SysuiTestCase() {
+
+ companion object {
+
+ @JvmStatic
+ @Parameterized.Parameters
+ fun data(): Iterable<String> =
+ listOf(
+ Intent.ACTION_USER_INFO_CHANGED,
+ Intent.ACTION_MANAGED_PROFILE_AVAILABLE,
+ Intent.ACTION_MANAGED_PROFILE_UNAVAILABLE,
+ Intent.ACTION_MANAGED_PROFILE_ADDED,
+ Intent.ACTION_MANAGED_PROFILE_REMOVED,
+ Intent.ACTION_MANAGED_PROFILE_UNLOCKED
+ )
+ }
+
+ private val executor: Executor = DirectExecutor.INSTANCE
+
+ @Mock private lateinit var context: Context
+ @Mock private lateinit var userManager: UserManager
+ @Mock(stubOnly = true) private lateinit var dumpManager: DumpManager
+ @Mock(stubOnly = true) private lateinit var handler: Handler
+
+ @Parameterized.Parameter lateinit var intentAction: String
+ @Mock private lateinit var callback: UserTracker.Callback
+ @Captor private lateinit var captor: ArgumentCaptor<List<UserInfo>>
+
+ private lateinit var tracker: UserTrackerImpl
+
+ @Before
+ fun setUp() {
+ MockitoAnnotations.initMocks(this)
+
+ `when`(context.user).thenReturn(UserHandle.SYSTEM)
+ `when`(context.createContextAsUser(ArgumentMatchers.any(), anyInt())).thenReturn(context)
+
+ tracker = UserTrackerImpl(context, userManager, dumpManager, handler)
+ }
+
+ @Test
+ fun `calls callback and updates profiles when an intent received`() {
+ tracker.initialize(0)
+ tracker.addCallback(callback, executor)
+ val profileID = tracker.userId + 10
+
+ `when`(userManager.getProfiles(anyInt())).thenAnswer { invocation ->
+ val id = invocation.getArgument<Int>(0)
+ val info = UserInfo(id, "", UserInfo.FLAG_FULL)
+ val infoProfile =
+ UserInfo(
+ id + 10,
+ "",
+ "",
+ UserInfo.FLAG_MANAGED_PROFILE,
+ UserManager.USER_TYPE_PROFILE_MANAGED
+ )
+ infoProfile.profileGroupId = id
+ listOf(info, infoProfile)
+ }
+
+ tracker.onReceive(context, Intent(intentAction))
+
+ verify(callback, times(0)).onUserChanged(anyInt(), any())
+ verify(callback, times(1)).onProfilesChanged(capture(captor))
+ assertThat(captor.value.map { it.id }).containsExactly(0, profileID)
+ }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/settings/UserTrackerImplTest.kt b/packages/SystemUI/tests/src/com/android/systemui/settings/UserTrackerImplTest.kt
index 52462c7..e65bbb1 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/settings/UserTrackerImplTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/settings/UserTrackerImplTest.kt
@@ -124,6 +124,16 @@
verify(context).registerReceiverForAllUsers(
eq(tracker), capture(captor), isNull(), eq(handler))
+ with(captor.value) {
+ assertThat(countActions()).isEqualTo(7)
+ assertThat(hasAction(Intent.ACTION_USER_SWITCHED)).isTrue()
+ assertThat(hasAction(Intent.ACTION_USER_INFO_CHANGED)).isTrue()
+ assertThat(hasAction(Intent.ACTION_MANAGED_PROFILE_AVAILABLE)).isTrue()
+ assertThat(hasAction(Intent.ACTION_MANAGED_PROFILE_UNAVAILABLE)).isTrue()
+ assertThat(hasAction(Intent.ACTION_MANAGED_PROFILE_ADDED)).isTrue()
+ assertThat(hasAction(Intent.ACTION_MANAGED_PROFILE_REMOVED)).isTrue()
+ assertThat(hasAction(Intent.ACTION_MANAGED_PROFILE_UNLOCKED)).isTrue()
+ }
}
@Test
@@ -280,37 +290,6 @@
}
@Test
- fun testCallbackCalledOnProfileChanged() {
- tracker.initialize(0)
- val callback = TestCallback()
- tracker.addCallback(callback, executor)
- val profileID = tracker.userId + 10
-
- `when`(userManager.getProfiles(anyInt())).thenAnswer { invocation ->
- val id = invocation.getArgument<Int>(0)
- val info = UserInfo(id, "", UserInfo.FLAG_FULL)
- val infoProfile = UserInfo(
- id + 10,
- "",
- "",
- UserInfo.FLAG_MANAGED_PROFILE,
- UserManager.USER_TYPE_PROFILE_MANAGED
- )
- infoProfile.profileGroupId = id
- listOf(info, infoProfile)
- }
-
- val intent = Intent(Intent.ACTION_MANAGED_PROFILE_AVAILABLE)
- .putExtra(Intent.EXTRA_USER, UserHandle.of(profileID))
-
- tracker.onReceive(context, intent)
-
- assertThat(callback.calledOnUserChanged).isEqualTo(0)
- assertThat(callback.calledOnProfilesChanged).isEqualTo(1)
- assertThat(callback.lastUserProfiles.map { it.id }).containsExactly(0, profileID)
- }
-
- @Test
fun testCallbackCalledOnUserInfoChanged() {
tracker.initialize(0)
val callback = TestCallback()
diff --git a/packages/SystemUI/tests/src/com/android/systemui/shade/CombinedShadeHeaderConstraintsTest.kt b/packages/SystemUI/tests/src/com/android/systemui/shade/CombinedShadeHeaderConstraintsTest.kt
index 88651c1..f802a5e 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/shade/CombinedShadeHeaderConstraintsTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/shade/CombinedShadeHeaderConstraintsTest.kt
@@ -17,6 +17,7 @@
package com.android.systemui.shade
import android.testing.AndroidTestingRunner
+import android.view.ViewGroup
import androidx.constraintlayout.widget.ConstraintSet
import androidx.constraintlayout.widget.ConstraintSet.PARENT_ID
import androidx.constraintlayout.widget.ConstraintSet.START
@@ -92,12 +93,12 @@
assertThat(getConstraint(R.id.clock).layout.horizontalBias).isEqualTo(0f)
assertThat(getConstraint(R.id.date).layout.startToStart).isEqualTo(PARENT_ID)
- assertThat(getConstraint(R.id.date).layout.horizontalBias).isEqualTo(0f)
+ assertThat(getConstraint(R.id.date).layout.horizontalBias).isEqualTo(0.5f)
assertThat(getConstraint(R.id.batteryRemainingIcon).layout.endToEnd)
.isEqualTo(PARENT_ID)
assertThat(getConstraint(R.id.batteryRemainingIcon).layout.horizontalBias)
- .isEqualTo(1f)
+ .isEqualTo(0.5f)
assertThat(getConstraint(R.id.privacy_container).layout.endToEnd)
.isEqualTo(R.id.end_guide)
@@ -331,10 +332,8 @@
val views = mapOf(
R.id.clock to "clock",
R.id.date to "date",
- R.id.statusIcons to "icons",
R.id.privacy_container to "privacy",
R.id.carrier_group to "carriers",
- R.id.batteryRemainingIcon to "battery",
)
views.forEach { (id, name) ->
assertWithMessage("$name has 0 height in qqs")
@@ -352,11 +351,8 @@
fun testCheckViewsDontChangeSizeBetweenAnimationConstraints() {
val views = mapOf(
R.id.clock to "clock",
- R.id.date to "date",
- R.id.statusIcons to "icons",
R.id.privacy_container to "privacy",
R.id.carrier_group to "carriers",
- R.id.batteryRemainingIcon to "battery",
)
views.forEach { (id, name) ->
expect.withMessage("$name changes height")
@@ -369,8 +365,8 @@
}
private fun Int.fromConstraint() = when (this) {
- -1 -> "MATCH_PARENT"
- -2 -> "WRAP_CONTENT"
+ ViewGroup.LayoutParams.MATCH_PARENT -> "MATCH_PARENT"
+ ViewGroup.LayoutParams.WRAP_CONTENT -> "WRAP_CONTENT"
else -> toString()
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/shade/LargeScreenShadeHeaderControllerCombinedTest.kt b/packages/SystemUI/tests/src/com/android/systemui/shade/LargeScreenShadeHeaderControllerCombinedTest.kt
index 1d30ad9..f580f5e 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/shade/LargeScreenShadeHeaderControllerCombinedTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/shade/LargeScreenShadeHeaderControllerCombinedTest.kt
@@ -182,6 +182,7 @@
null
}
whenever(view.visibility).thenAnswer { _ -> viewVisibility }
+ whenever(view.alpha).thenReturn(1f)
whenever(iconManagerFactory.create(any(), any())).thenReturn(iconManager)
diff --git a/packages/SystemUI/tests/src/com/android/systemui/shade/LargeScreenShadeHeaderControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/shade/LargeScreenShadeHeaderControllerTest.kt
index b4c8f98..b568122 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/shade/LargeScreenShadeHeaderControllerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/shade/LargeScreenShadeHeaderControllerTest.kt
@@ -1,5 +1,6 @@
package com.android.systemui.shade
+import android.animation.ValueAnimator
import android.app.StatusBarManager
import android.content.Context
import android.testing.AndroidTestingRunner
@@ -30,6 +31,7 @@
import com.android.systemui.util.mockito.any
import com.android.systemui.util.mockito.argumentCaptor
import com.android.systemui.util.mockito.capture
+import com.android.systemui.util.mockito.mock
import com.google.common.truth.Truth.assertThat
import org.junit.After
import org.junit.Before
@@ -37,6 +39,7 @@
import org.junit.Test
import org.junit.runner.RunWith
import org.mockito.Answers
+import org.mockito.ArgumentMatchers.anyFloat
import org.mockito.ArgumentMatchers.anyInt
import org.mockito.Mock
import org.mockito.Mockito.mock
@@ -75,6 +78,7 @@
@JvmField @Rule val mockitoRule = MockitoJUnit.rule()
var viewVisibility = View.GONE
+ var viewAlpha = 1f
private lateinit var mLargeScreenShadeHeaderController: LargeScreenShadeHeaderController
private lateinit var carrierIconSlots: List<String>
@@ -101,6 +105,13 @@
null
}
whenever(view.visibility).thenAnswer { _ -> viewVisibility }
+
+ whenever(view.setAlpha(anyFloat())).then {
+ viewAlpha = it.arguments[0] as Float
+ null
+ }
+ whenever(view.alpha).thenAnswer { _ -> viewAlpha }
+
whenever(variableDateViewControllerFactory.create(any()))
.thenReturn(variableDateViewController)
whenever(iconManagerFactory.create(any(), any())).thenReturn(iconManager)
@@ -155,6 +166,16 @@
}
@Test
+ fun alphaChangesUpdateVisibility() {
+ makeShadeVisible()
+ mLargeScreenShadeHeaderController.shadeExpandedFraction = 0f
+ assertThat(viewVisibility).isEqualTo(View.INVISIBLE)
+
+ mLargeScreenShadeHeaderController.shadeExpandedFraction = 1f
+ assertThat(viewVisibility).isEqualTo(View.VISIBLE)
+ }
+
+ @Test
fun singleCarrier_enablesCarrierIconsInStatusIcons() {
whenever(qsCarrierGroupController.isSingleCarrier).thenReturn(true)
@@ -239,6 +260,39 @@
}
@Test
+ fun testShadeExpanded_true_alpha_zero_invisible() {
+ view.alpha = 0f
+ mLargeScreenShadeHeaderController.largeScreenActive = true
+ mLargeScreenShadeHeaderController.qsVisible = true
+
+ assertThat(viewVisibility).isEqualTo(View.INVISIBLE)
+ }
+
+ @Test
+ fun animatorCallsUpdateVisibilityOnUpdate() {
+ val animator = mock(ViewPropertyAnimator::class.java, Answers.RETURNS_SELF)
+ whenever(view.animate()).thenReturn(animator)
+
+ mLargeScreenShadeHeaderController.startCustomizingAnimation(show = false, 0L)
+
+ val updateCaptor = argumentCaptor<ValueAnimator.AnimatorUpdateListener>()
+ verify(animator).setUpdateListener(capture(updateCaptor))
+
+ mLargeScreenShadeHeaderController.largeScreenActive = true
+ mLargeScreenShadeHeaderController.qsVisible = true
+
+ view.alpha = 1f
+ updateCaptor.value.onAnimationUpdate(mock())
+
+ assertThat(viewVisibility).isEqualTo(View.VISIBLE)
+
+ view.alpha = 0f
+ updateCaptor.value.onAnimationUpdate(mock())
+
+ assertThat(viewVisibility).isEqualTo(View.INVISIBLE)
+ }
+
+ @Test
fun demoMode_attachDemoMode() {
val cb = argumentCaptor<DemoMode>()
verify(demoModeController).addCallback(capture(cb))
diff --git a/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationPanelViewControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationPanelViewControllerTest.java
index 53ab19c..6dd2d61 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationPanelViewControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationPanelViewControllerTest.java
@@ -107,7 +107,10 @@
import com.android.systemui.keyguard.domain.interactor.KeyguardBottomAreaInteractor;
import com.android.systemui.keyguard.domain.interactor.KeyguardTransitionInteractor;
import com.android.systemui.keyguard.ui.viewmodel.DreamingToLockscreenTransitionViewModel;
+import com.android.systemui.keyguard.ui.viewmodel.GoneToDreamingTransitionViewModel;
import com.android.systemui.keyguard.ui.viewmodel.KeyguardBottomAreaViewModel;
+import com.android.systemui.keyguard.ui.viewmodel.LockscreenToDreamingTransitionViewModel;
+import com.android.systemui.keyguard.ui.viewmodel.LockscreenToOccludedTransitionViewModel;
import com.android.systemui.keyguard.ui.viewmodel.OccludedToLockscreenTransitionViewModel;
import com.android.systemui.media.controls.pipeline.MediaDataManager;
import com.android.systemui.media.controls.ui.KeyguardMediaController;
@@ -295,6 +298,10 @@
@Mock private AlternateBouncerInteractor mAlternateBouncerInteractor;
@Mock private DreamingToLockscreenTransitionViewModel mDreamingToLockscreenTransitionViewModel;
@Mock private OccludedToLockscreenTransitionViewModel mOccludedToLockscreenTransitionViewModel;
+ @Mock private LockscreenToDreamingTransitionViewModel mLockscreenToDreamingTransitionViewModel;
+ @Mock private LockscreenToOccludedTransitionViewModel mLockscreenToOccludedTransitionViewModel;
+ @Mock private GoneToDreamingTransitionViewModel mGoneToDreamingTransitionViewModel;
+
@Mock private KeyguardTransitionInteractor mKeyguardTransitionInteractor;
@Mock private CoroutineDispatcher mMainDispatcher;
@Mock private MotionEvent mDownMotionEvent;
@@ -516,6 +523,9 @@
mAlternateBouncerInteractor,
mDreamingToLockscreenTransitionViewModel,
mOccludedToLockscreenTransitionViewModel,
+ mLockscreenToDreamingTransitionViewModel,
+ mGoneToDreamingTransitionViewModel,
+ mLockscreenToOccludedTransitionViewModel,
mMainDispatcher,
mKeyguardTransitionInteractor,
mDumpManager);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationShadeWindowControllerImplTest.java b/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationShadeWindowControllerImplTest.java
index 08a9c96..526dc8d 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationShadeWindowControllerImplTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationShadeWindowControllerImplTest.java
@@ -46,11 +46,14 @@
import androidx.test.filters.SmallTest;
import com.android.internal.colorextraction.ColorExtractor;
+import com.android.systemui.R;
import com.android.systemui.SysuiTestCase;
import com.android.systemui.biometrics.AuthController;
import com.android.systemui.colorextraction.SysuiColorExtractor;
import com.android.systemui.dump.DumpManager;
import com.android.systemui.keyguard.KeyguardViewMediator;
+import com.android.systemui.plugins.statusbar.StatusBarStateController;
+import com.android.systemui.statusbar.StatusBarState;
import com.android.systemui.statusbar.SysuiStatusBarStateController;
import com.android.systemui.statusbar.phone.DozeParameters;
import com.android.systemui.statusbar.phone.KeyguardBypassController;
@@ -68,6 +71,8 @@
import org.mockito.MockitoAnnotations;
import org.mockito.Spy;
+import java.util.List;
+
@RunWith(AndroidTestingRunner.class)
@RunWithLooper
@SmallTest
@@ -91,13 +96,21 @@
@Mock private ShadeExpansionStateManager mShadeExpansionStateManager;
@Mock private ShadeWindowLogger mShadeWindowLogger;
@Captor private ArgumentCaptor<WindowManager.LayoutParams> mLayoutParameters;
+ @Captor private ArgumentCaptor<StatusBarStateController.StateListener> mStateListener;
private NotificationShadeWindowControllerImpl mNotificationShadeWindowController;
-
+ private float mPreferredRefreshRate = -1;
@Before
public void setUp() {
MockitoAnnotations.initMocks(this);
+ // Preferred refresh rate is equal to the first displayMode's refresh rate
+ mPreferredRefreshRate = mContext.getDisplay().getSupportedModes()[0].getRefreshRate();
+ overrideResource(
+ R.integer.config_keyguardRefreshRate,
+ (int) mPreferredRefreshRate
+ );
+
when(mDozeParameters.getAlwaysOn()).thenReturn(true);
when(mColorExtractor.getNeutralColors()).thenReturn(mGradientColors);
@@ -117,6 +130,7 @@
mNotificationShadeWindowController.attach();
verify(mWindowManager).addView(eq(mNotificationShadeWindowView), any());
+ verify(mStatusBarStateController).addCallback(mStateListener.capture(), anyInt());
}
@Test
@@ -334,4 +348,59 @@
assertThat(mLayoutParameters.getValue().screenOrientation)
.isEqualTo(ActivityInfo.SCREEN_ORIENTATION_NOSENSOR);
}
+
+ @Test
+ public void udfpsEnrolled_minAndMaxRefreshRateSetToPreferredRefreshRate() {
+ // GIVEN udfps is enrolled
+ when(mAuthController.isUdfpsEnrolled(anyInt())).thenReturn(true);
+
+ // WHEN keyguard is showing
+ setKeyguardShowing();
+
+ // THEN min and max refresh rate is set to the preferredRefreshRate
+ verify(mWindowManager, atLeastOnce()).updateViewLayout(any(), mLayoutParameters.capture());
+ final List<WindowManager.LayoutParams> lpList = mLayoutParameters.getAllValues();
+ final WindowManager.LayoutParams lp = lpList.get(lpList.size() - 1);
+ assertThat(lp.preferredMaxDisplayRefreshRate).isEqualTo(mPreferredRefreshRate);
+ assertThat(lp.preferredMinDisplayRefreshRate).isEqualTo(mPreferredRefreshRate);
+ }
+
+ @Test
+ public void udfpsNotEnrolled_refreshRateUnset() {
+ // GIVEN udfps is NOT enrolled
+ when(mAuthController.isUdfpsEnrolled(anyInt())).thenReturn(false);
+
+ // WHEN keyguard is showing
+ setKeyguardShowing();
+
+ // THEN min and max refresh rate aren't set (set to 0)
+ verify(mWindowManager, atLeastOnce()).updateViewLayout(any(), mLayoutParameters.capture());
+ final List<WindowManager.LayoutParams> lpList = mLayoutParameters.getAllValues();
+ final WindowManager.LayoutParams lp = lpList.get(lpList.size() - 1);
+ assertThat(lp.preferredMaxDisplayRefreshRate).isEqualTo(0);
+ assertThat(lp.preferredMinDisplayRefreshRate).isEqualTo(0);
+ }
+
+ @Test
+ public void keyguardNotShowing_refreshRateUnset() {
+ // GIVEN UDFPS is enrolled
+ when(mAuthController.isUdfpsEnrolled(anyInt())).thenReturn(true);
+
+ // WHEN keyguard is NOT showing
+ mNotificationShadeWindowController.setKeyguardShowing(false);
+
+ // THEN min and max refresh rate aren't set (set to 0)
+ verify(mWindowManager, atLeastOnce()).updateViewLayout(any(), mLayoutParameters.capture());
+ final List<WindowManager.LayoutParams> lpList = mLayoutParameters.getAllValues();
+ final WindowManager.LayoutParams lp = lpList.get(lpList.size() - 1);
+ assertThat(lp.preferredMaxDisplayRefreshRate).isEqualTo(0);
+ assertThat(lp.preferredMinDisplayRefreshRate).isEqualTo(0);
+ }
+
+ private void setKeyguardShowing() {
+ mNotificationShadeWindowController.setKeyguardShowing(true);
+ mNotificationShadeWindowController.setKeyguardGoingAway(false);
+ mNotificationShadeWindowController.setKeyguardFadingAway(false);
+ mStateListener.getValue().onStateChanged(StatusBarState.KEYGUARD);
+ }
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationShadeWindowViewControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationShadeWindowViewControllerTest.kt
index 3137aa5..4c76825 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationShadeWindowViewControllerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationShadeWindowViewControllerTest.kt
@@ -31,6 +31,7 @@
import com.android.systemui.flags.FeatureFlags
import com.android.systemui.keyguard.KeyguardUnlockAnimationController
import com.android.systemui.keyguard.domain.interactor.AlternateBouncerInteractor
+import com.android.systemui.keyguard.domain.interactor.KeyguardTransitionInteractor
import com.android.systemui.keyguard.ui.viewmodel.KeyguardBouncerViewModel
import com.android.systemui.shade.NotificationShadeWindowView.InteractionEventHandler
import com.android.systemui.statusbar.LockscreenShadeTransitionController
@@ -104,6 +105,7 @@
@Mock lateinit var keyguardBouncerContainer: ViewGroup
@Mock lateinit var keyguardBouncerComponent: KeyguardBouncerComponent
@Mock lateinit var keyguardHostViewController: KeyguardHostViewController
+ @Mock lateinit var keyguardTransitionInteractor: KeyguardTransitionInteractor
private lateinit var interactionEventHandlerCaptor: ArgumentCaptor<InteractionEventHandler>
private lateinit var interactionEventHandler: InteractionEventHandler
@@ -136,7 +138,8 @@
featureFlags,
keyguardBouncerViewModel,
keyguardBouncerComponentFactory,
- alternateBouncerInteractor
+ alternateBouncerInteractor,
+ keyguardTransitionInteractor,
)
underTest.setupExpandedStatusBar()
diff --git a/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationShadeWindowViewTest.java b/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationShadeWindowViewTest.java
index 544b00e..d435624 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationShadeWindowViewTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationShadeWindowViewTest.java
@@ -41,6 +41,7 @@
import com.android.systemui.flags.FeatureFlags;
import com.android.systemui.keyguard.KeyguardUnlockAnimationController;
import com.android.systemui.keyguard.domain.interactor.AlternateBouncerInteractor;
+import com.android.systemui.keyguard.domain.interactor.KeyguardTransitionInteractor;
import com.android.systemui.keyguard.ui.viewmodel.KeyguardBouncerViewModel;
import com.android.systemui.statusbar.DragDownHelper;
import com.android.systemui.statusbar.LockscreenShadeTransitionController;
@@ -95,6 +96,7 @@
@Mock private KeyguardBouncerComponent.Factory mKeyguardBouncerComponentFactory;
@Mock private NotificationInsetsController mNotificationInsetsController;
@Mock private AlternateBouncerInteractor mAlternateBouncerInteractor;
+ @Mock private KeyguardTransitionInteractor mKeyguardTransitionInteractor;
@Captor private ArgumentCaptor<NotificationShadeWindowView.InteractionEventHandler>
mInteractionEventHandlerCaptor;
@@ -135,7 +137,8 @@
mFeatureFlags,
mKeyguardBouncerViewModel,
mKeyguardBouncerComponentFactory,
- mAlternateBouncerInteractor
+ mAlternateBouncerInteractor,
+ mKeyguardTransitionInteractor
);
mController.setupExpandedStatusBar();
mController.setDragDownHelper(mDragDownHelper);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/CommandQueueTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/CommandQueueTest.java
index 0000c32..fc7cd89 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/CommandQueueTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/CommandQueueTest.java
@@ -209,9 +209,9 @@
@Test
public void testShowRecentApps() {
- mCommandQueue.showRecentApps(true);
+ mCommandQueue.showRecentApps(true, false);
waitForIdleSync();
- verify(mCallbacks).showRecentApps(eq(true));
+ verify(mCallbacks).showRecentApps(eq(true), eq(false));
}
@Test
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationChildrenContainerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationChildrenContainerTest.java
index ca99e24..e41929f 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationChildrenContainerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationChildrenContainerTest.java
@@ -29,6 +29,7 @@
import com.android.systemui.statusbar.notification.SourceType;
import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow;
import com.android.systemui.statusbar.notification.row.NotificationTestHelper;
+import com.android.systemui.statusbar.notification.row.wrapper.NotificationHeaderViewWrapper;
import org.junit.Assert;
import org.junit.Before;
@@ -216,4 +217,29 @@
Assert.assertEquals(1f, mChildrenContainer.getBottomRoundness(), 0.001f);
Assert.assertEquals(1f, notificationRow.getBottomRoundness(), 0.001f);
}
+
+ @Test
+ public void applyRoundnessAndInvalidate_should_be_immediately_applied_on_header() {
+ mChildrenContainer.useRoundnessSourceTypes(true);
+
+ NotificationHeaderViewWrapper header = mChildrenContainer.getNotificationHeaderWrapper();
+ Assert.assertEquals(0f, header.getTopRoundness(), 0.001f);
+
+ mChildrenContainer.requestTopRoundness(1f, SourceType.from(""), false);
+
+ Assert.assertEquals(1f, header.getTopRoundness(), 0.001f);
+ }
+
+ @Test
+ public void applyRoundnessAndInvalidate_should_be_immediately_applied_on_headerLowPriority() {
+ mChildrenContainer.useRoundnessSourceTypes(true);
+ mChildrenContainer.setIsLowPriority(true);
+
+ NotificationHeaderViewWrapper header = mChildrenContainer.getNotificationHeaderWrapper();
+ Assert.assertEquals(0f, header.getTopRoundness(), 0.001f);
+
+ mChildrenContainer.requestTopRoundness(1f, SourceType.from(""), false);
+
+ Assert.assertEquals(1f, header.getTopRoundness(), 0.001f);
+ }
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/AutoTileManagerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/AutoTileManagerTest.java
index 4ccbc6d..091bb54 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/AutoTileManagerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/AutoTileManagerTest.java
@@ -24,6 +24,7 @@
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.ArgumentMatchers.isNotNull;
import static org.mockito.ArgumentMatchers.isNull;
import static org.mockito.Mockito.doReturn;
@@ -74,6 +75,7 @@
import org.mockito.Mockito;
import org.mockito.MockitoAnnotations;
import org.mockito.Spy;
+import org.mockito.stubbing.Answer;
import java.util.Collections;
import java.util.List;
@@ -115,8 +117,10 @@
@Spy private PackageManager mPackageManager;
private final boolean mIsReduceBrightColorsAvailable = true;
- private AutoTileManager mAutoTileManager;
+ private AutoTileManager mAutoTileManager; // under test
+
private SecureSettings mSecureSettings;
+ private ManagedProfileController.Callback mManagedProfileCallback;
@Before
public void setUp() throws Exception {
@@ -303,7 +307,7 @@
InOrder inOrderManagedProfile = inOrder(mManagedProfileController);
inOrderManagedProfile.verify(mManagedProfileController).removeCallback(any());
- inOrderManagedProfile.verify(mManagedProfileController, never()).addCallback(any());
+ inOrderManagedProfile.verify(mManagedProfileController).addCallback(any());
if (ColorDisplayManager.isNightDisplayAvailable(mContext)) {
InOrder inOrderNightDisplay = inOrder(mNightDisplayListener);
@@ -504,6 +508,40 @@
}
@Test
+ public void managedProfileAdded_tileAdded() {
+ when(mAutoAddTracker.isAdded(eq("work"))).thenReturn(false);
+ mAutoTileManager = createAutoTileManager(mContext);
+ Mockito.doAnswer((Answer<Object>) invocation -> {
+ mManagedProfileCallback = invocation.getArgument(0);
+ return null;
+ }).when(mManagedProfileController).addCallback(any());
+ mAutoTileManager.init();
+ when(mManagedProfileController.hasActiveProfile()).thenReturn(true);
+
+ mManagedProfileCallback.onManagedProfileChanged();
+
+ verify(mQsTileHost, times(1)).addTile(eq("work"));
+ verify(mAutoAddTracker, times(1)).setTileAdded(eq("work"));
+ }
+
+ @Test
+ public void managedProfileRemoved_tileRemoved() {
+ when(mAutoAddTracker.isAdded(eq("work"))).thenReturn(true);
+ mAutoTileManager = createAutoTileManager(mContext);
+ Mockito.doAnswer((Answer<Object>) invocation -> {
+ mManagedProfileCallback = invocation.getArgument(0);
+ return null;
+ }).when(mManagedProfileController).addCallback(any());
+ mAutoTileManager.init();
+ when(mManagedProfileController.hasActiveProfile()).thenReturn(false);
+
+ mManagedProfileCallback.onManagedProfileChanged();
+
+ verify(mQsTileHost, times(1)).removeTile(eq("work"));
+ verify(mAutoAddTracker, times(1)).setTileRemoved(eq("work"));
+ }
+
+ @Test
public void testEmptyArray_doesNotCrash() {
mContext.getOrCreateTestableResources().addOverride(
R.array.config_quickSettingsAutoAdd, new String[0]);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/BiometricsUnlockControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/BiometricsUnlockControllerTest.java
index 9695000..ec294b1 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/BiometricsUnlockControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/BiometricsUnlockControllerTest.java
@@ -16,6 +16,8 @@
package com.android.systemui.statusbar.phone;
+import static com.android.systemui.statusbar.phone.BiometricUnlockController.MODE_WAKE_AND_UNLOCK;
+
import static com.google.common.truth.Truth.assertThat;
import static org.mockito.ArgumentMatchers.any;
@@ -54,6 +56,7 @@
import com.android.systemui.statusbar.NotificationShadeWindowController;
import com.android.systemui.statusbar.VibratorHelper;
import com.android.systemui.statusbar.policy.KeyguardStateController;
+import com.android.systemui.util.time.FakeSystemClock;
import org.junit.Before;
import org.junit.Test;
@@ -115,6 +118,7 @@
private VibratorHelper mVibratorHelper;
@Mock
private BiometricUnlockLogger mLogger;
+ private final FakeSystemClock mSystemClock = new FakeSystemClock();
private BiometricUnlockController mBiometricUnlockController;
@Before
@@ -137,7 +141,9 @@
mMetricsLogger, mDumpManager, mPowerManager, mLogger,
mNotificationMediaManager, mWakefulnessLifecycle, mScreenLifecycle,
mAuthController, mStatusBarStateController,
- mSessionTracker, mLatencyTracker, mScreenOffAnimationController, mVibratorHelper);
+ mSessionTracker, mLatencyTracker, mScreenOffAnimationController, mVibratorHelper,
+ mSystemClock
+ );
mBiometricUnlockController.setKeyguardViewController(mStatusBarKeyguardViewManager);
mBiometricUnlockController.addBiometricModeListener(mBiometricModeListener);
when(mUpdateMonitor.getStrongAuthTracker()).thenReturn(mStrongAuthTracker);
@@ -200,7 +206,7 @@
verify(mKeyguardViewMediator).onWakeAndUnlocking();
assertThat(mBiometricUnlockController.getMode())
- .isEqualTo(BiometricUnlockController.MODE_WAKE_AND_UNLOCK);
+ .isEqualTo(MODE_WAKE_AND_UNLOCK);
}
@Test
@@ -437,4 +443,83 @@
// THEN wakeup the device
verify(mPowerManager).wakeUp(anyLong(), anyInt(), anyString());
}
+
+ @Test
+ public void onSideFingerprintSuccess_recentPowerButtonPress_noHaptic() {
+ // GIVEN side fingerprint enrolled, last wake reason was power button
+ when(mAuthController.isSfpsEnrolled(anyInt())).thenReturn(true);
+ when(mWakefulnessLifecycle.getLastWakeReason())
+ .thenReturn(PowerManager.WAKE_REASON_POWER_BUTTON);
+
+ // GIVEN last wake time just occurred
+ when(mWakefulnessLifecycle.getLastWakeTime()).thenReturn(mSystemClock.uptimeMillis());
+
+ // WHEN biometric fingerprint succeeds
+ givenFingerprintModeUnlockCollapsing();
+ mBiometricUnlockController.startWakeAndUnlock(BiometricSourceType.FINGERPRINT,
+ true);
+
+ // THEN DO NOT vibrate the device
+ verify(mVibratorHelper, never()).vibrateAuthSuccess(anyString());
+ }
+
+ @Test
+ public void onSideFingerprintSuccess_oldPowerButtonPress_playHaptic() {
+ // GIVEN side fingerprint enrolled, last wake reason was power button
+ when(mAuthController.isSfpsEnrolled(anyInt())).thenReturn(true);
+ when(mWakefulnessLifecycle.getLastWakeReason())
+ .thenReturn(PowerManager.WAKE_REASON_POWER_BUTTON);
+
+ // GIVEN last wake time was 500ms ago
+ when(mWakefulnessLifecycle.getLastWakeTime()).thenReturn(mSystemClock.uptimeMillis());
+ mSystemClock.advanceTime(500);
+
+ // WHEN biometric fingerprint succeeds
+ givenFingerprintModeUnlockCollapsing();
+ mBiometricUnlockController.startWakeAndUnlock(BiometricSourceType.FINGERPRINT,
+ true);
+
+ // THEN vibrate the device
+ verify(mVibratorHelper).vibrateAuthSuccess(anyString());
+ }
+
+ @Test
+ public void onSideFingerprintSuccess_recentGestureWakeUp_playHaptic() {
+ // GIVEN side fingerprint enrolled, wakeup just happened
+ when(mAuthController.isSfpsEnrolled(anyInt())).thenReturn(true);
+ when(mWakefulnessLifecycle.getLastWakeTime()).thenReturn(mSystemClock.uptimeMillis());
+
+ // GIVEN last wake reason was from a gesture
+ when(mWakefulnessLifecycle.getLastWakeReason())
+ .thenReturn(PowerManager.WAKE_REASON_GESTURE);
+
+ // WHEN biometric fingerprint succeeds
+ givenFingerprintModeUnlockCollapsing();
+ mBiometricUnlockController.startWakeAndUnlock(BiometricSourceType.FINGERPRINT,
+ true);
+
+ // THEN vibrate the device
+ verify(mVibratorHelper).vibrateAuthSuccess(anyString());
+ }
+
+ @Test
+ public void onSideFingerprintFail_alwaysPlaysHaptic() {
+ // GIVEN side fingerprint enrolled, last wake reason was recent power button
+ when(mAuthController.isSfpsEnrolled(anyInt())).thenReturn(true);
+ when(mWakefulnessLifecycle.getLastWakeReason())
+ .thenReturn(PowerManager.WAKE_REASON_POWER_BUTTON);
+ when(mWakefulnessLifecycle.getLastWakeTime()).thenReturn(mSystemClock.uptimeMillis());
+
+ // WHEN biometric fingerprint fails
+ mBiometricUnlockController.onBiometricAuthFailed(BiometricSourceType.FINGERPRINT);
+
+ // THEN always vibrate the device
+ verify(mVibratorHelper).vibrateAuthError(anyString());
+ }
+
+ private void givenFingerprintModeUnlockCollapsing() {
+ when(mUpdateMonitor.isUnlockingWithBiometricAllowed(anyBoolean())).thenReturn(true);
+ when(mUpdateMonitor.isDeviceInteractive()).thenReturn(true);
+ when(mKeyguardStateController.isShowing()).thenReturn(true);
+ }
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/CentralSurfacesImplTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/CentralSurfacesImplTest.java
index 3a1f9b7..c8157cc 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/CentralSurfacesImplTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/CentralSurfacesImplTest.java
@@ -178,8 +178,6 @@
import com.android.wm.shell.bubbles.Bubbles;
import com.android.wm.shell.startingsurface.StartingSurface;
-import dagger.Lazy;
-
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -192,6 +190,8 @@
import java.io.PrintWriter;
import java.util.Optional;
+import dagger.Lazy;
+
@SmallTest
@RunWith(AndroidTestingRunner.class)
@RunWithLooper(setAsMainLooper = true)
@@ -380,7 +380,8 @@
}).when(mStatusBarKeyguardViewManager).addAfterKeyguardGoneRunnable(any());
mWakefulnessLifecycle =
- new WakefulnessLifecycle(mContext, mIWallpaperManager, mDumpManager);
+ new WakefulnessLifecycle(mContext, mIWallpaperManager, mFakeSystemClock,
+ mDumpManager);
mWakefulnessLifecycle.dispatchStartedWakingUp(PowerManager.WAKE_REASON_UNKNOWN);
mWakefulnessLifecycle.dispatchFinishedWakingUp();
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/DozeParametersTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/DozeParametersTest.java
index 077b41a..c843850 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/DozeParametersTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/DozeParametersTest.java
@@ -23,6 +23,10 @@
import static org.mockito.ArgumentMatchers.anyBoolean;
import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.Mockito.doAnswer;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.reset;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import android.content.res.Resources;
@@ -39,10 +43,9 @@
import com.android.systemui.doze.AlwaysOnDisplayPolicy;
import com.android.systemui.doze.DozeScreenState;
import com.android.systemui.dump.DumpManager;
-import com.android.systemui.flags.FeatureFlags;
-import com.android.systemui.flags.Flags;
import com.android.systemui.plugins.statusbar.StatusBarStateController;
import com.android.systemui.statusbar.policy.BatteryController;
+import com.android.systemui.statusbar.policy.BatteryController.BatteryStateChangeCallback;
import com.android.systemui.statusbar.policy.ConfigurationController;
import com.android.systemui.tuner.TunerService;
import com.android.systemui.unfold.FoldAodAnimationController;
@@ -52,6 +55,8 @@
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
+import org.mockito.ArgumentCaptor;
+import org.mockito.Captor;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
@@ -69,7 +74,6 @@
@Mock private PowerManager mPowerManager;
@Mock private TunerService mTunerService;
@Mock private BatteryController mBatteryController;
- @Mock private FeatureFlags mFeatureFlags;
@Mock private DumpManager mDumpManager;
@Mock private ScreenOffAnimationController mScreenOffAnimationController;
@Mock private FoldAodAnimationController mFoldAodAnimationController;
@@ -78,6 +82,7 @@
@Mock private KeyguardUpdateMonitor mKeyguardUpdateMonitor;
@Mock private StatusBarStateController mStatusBarStateController;
@Mock private ConfigurationController mConfigurationController;
+ @Captor private ArgumentCaptor<BatteryStateChangeCallback> mBatteryStateChangeCallback;
/**
* The current value of PowerManager's dozeAfterScreenOff property.
@@ -113,7 +118,6 @@
mBatteryController,
mTunerService,
mDumpManager,
- mFeatureFlags,
mScreenOffAnimationController,
Optional.of(mSysUIUnfoldComponent),
mUnlockedScreenOffAnimationController,
@@ -122,7 +126,8 @@
mStatusBarStateController
);
- when(mFeatureFlags.isEnabled(Flags.LOCKSCREEN_ANIMATIONS)).thenReturn(true);
+ verify(mBatteryController).addCallback(mBatteryStateChangeCallback.capture());
+
setAodEnabledForTest(true);
setShouldControlUnlockedScreenOffForTest(true);
setDisplayNeedsBlankingForTest(false);
@@ -173,6 +178,29 @@
assertThat(mDozeParameters.getAlwaysOn()).isFalse();
}
+ @Test
+ public void testGetAlwaysOn_whenBatterySaverCallback() {
+ DozeParameters.Callback callback = mock(DozeParameters.Callback.class);
+ mDozeParameters.addCallback(callback);
+
+ when(mAmbientDisplayConfiguration.alwaysOnEnabled(anyInt())).thenReturn(true);
+ when(mBatteryController.isAodPowerSave()).thenReturn(true);
+
+ // Both lines should trigger an event
+ mDozeParameters.onTuningChanged(Settings.Secure.DOZE_ALWAYS_ON, "1");
+ mBatteryStateChangeCallback.getValue().onPowerSaveChanged(true);
+
+ verify(callback, times(2)).onAlwaysOnChange();
+ assertThat(mDozeParameters.getAlwaysOn()).isFalse();
+
+ reset(callback);
+ when(mBatteryController.isAodPowerSave()).thenReturn(false);
+ mBatteryStateChangeCallback.getValue().onPowerSaveChanged(true);
+
+ verify(callback).onAlwaysOnChange();
+ assertThat(mDozeParameters.getAlwaysOn()).isTrue();
+ }
+
/**
* PowerManager.setDozeAfterScreenOff(true) means we are not controlling screen off, and calling
* it with false means we are. Confusing, but sure - make sure that we call PowerManager with
@@ -196,17 +224,6 @@
}
@Test
- public void testControlUnlockedScreenOffAnimationDisabled_dozeAfterScreenOff() {
- when(mFeatureFlags.isEnabled(Flags.LOCKSCREEN_ANIMATIONS)).thenReturn(false);
-
- assertFalse(mDozeParameters.shouldControlUnlockedScreenOff());
-
- // Trigger the setter for the current value.
- mDozeParameters.setControlScreenOffAnimation(mDozeParameters.shouldControlScreenOff());
- assertFalse(mDozeParameters.shouldControlScreenOff());
- }
-
- @Test
public void propagatesAnimateScreenOff_noAlwaysOn() {
setAodEnabledForTest(false);
setDisplayNeedsBlankingForTest(false);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/MobileRepositorySwitcherTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/MobileRepositorySwitcherTest.kt
index 5d377a8..0859d14 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/MobileRepositorySwitcherTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/MobileRepositorySwitcherTest.kt
@@ -34,6 +34,8 @@
import com.android.systemui.statusbar.pipeline.mobile.data.repository.prod.MobileConnectionsRepositoryImpl
import com.android.systemui.statusbar.pipeline.mobile.util.FakeMobileMappingsProxy
import com.android.systemui.statusbar.pipeline.shared.ConnectivityPipelineLogger
+import com.android.systemui.statusbar.pipeline.wifi.data.repository.FakeWifiRepository
+import com.android.systemui.statusbar.pipeline.wifi.data.repository.demo.DemoModeWifiDataSource
import com.android.systemui.util.mockito.any
import com.android.systemui.util.mockito.kotlinArgumentCaptor
import com.android.systemui.util.mockito.mock
@@ -71,8 +73,10 @@
private lateinit var underTest: MobileRepositorySwitcher
private lateinit var realRepo: MobileConnectionsRepositoryImpl
private lateinit var demoRepo: DemoMobileConnectionsRepository
- private lateinit var mockDataSource: DemoModeMobileConnectionDataSource
+ private lateinit var mobileDataSource: DemoModeMobileConnectionDataSource
+ private lateinit var wifiDataSource: DemoModeWifiDataSource
private lateinit var logFactory: TableLogBufferFactory
+ private lateinit var wifiRepository: FakeWifiRepository
@Mock private lateinit var connectivityManager: ConnectivityManager
@Mock private lateinit var subscriptionManager: SubscriptionManager
@@ -96,10 +100,15 @@
// Never start in demo mode
whenever(demoModeController.isInDemoMode).thenReturn(false)
- mockDataSource =
+ mobileDataSource =
mock<DemoModeMobileConnectionDataSource>().also {
whenever(it.mobileEvents).thenReturn(fakeNetworkEventsFlow)
}
+ wifiDataSource =
+ mock<DemoModeWifiDataSource>().also {
+ whenever(it.wifiEvents).thenReturn(MutableStateFlow(null))
+ }
+ wifiRepository = FakeWifiRepository()
realRepo =
MobileConnectionsRepositoryImpl(
@@ -113,12 +122,14 @@
context,
IMMEDIATE,
scope,
+ wifiRepository,
mock(),
)
demoRepo =
DemoMobileConnectionsRepository(
- dataSource = mockDataSource,
+ mobileDataSource = mobileDataSource,
+ wifiDataSource = wifiDataSource,
scope = scope,
context = context,
logFactory = logFactory,
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/demo/DemoMobileConnectionParameterizedTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/demo/DemoMobileConnectionParameterizedTest.kt
index 2102085..6989b514 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/demo/DemoMobileConnectionParameterizedTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/demo/DemoMobileConnectionParameterizedTest.kt
@@ -29,6 +29,8 @@
import com.android.systemui.statusbar.pipeline.mobile.data.model.NetworkNameModel
import com.android.systemui.statusbar.pipeline.mobile.data.repository.demo.model.FakeNetworkEventModel
import com.android.systemui.statusbar.pipeline.shared.data.model.toMobileDataActivityModel
+import com.android.systemui.statusbar.pipeline.wifi.data.repository.demo.DemoModeWifiDataSource
+import com.android.systemui.statusbar.pipeline.wifi.data.repository.demo.model.FakeWifiEventModel
import com.android.systemui.util.mockito.mock
import com.android.systemui.util.mockito.whenever
import com.android.systemui.util.time.FakeSystemClock
@@ -63,10 +65,12 @@
private val testScope = TestScope(testDispatcher)
private val fakeNetworkEventFlow = MutableStateFlow<FakeNetworkEventModel?>(null)
+ private val fakeWifiEventFlow = MutableStateFlow<FakeWifiEventModel?>(null)
private lateinit var connectionsRepo: DemoMobileConnectionsRepository
private lateinit var underTest: DemoMobileConnectionRepository
private lateinit var mockDataSource: DemoModeMobileConnectionDataSource
+ private lateinit var mockWifiDataSource: DemoModeWifiDataSource
@Before
fun setUp() {
@@ -75,10 +79,15 @@
mock<DemoModeMobileConnectionDataSource>().also {
whenever(it.mobileEvents).thenReturn(fakeNetworkEventFlow)
}
+ mockWifiDataSource =
+ mock<DemoModeWifiDataSource>().also {
+ whenever(it.wifiEvents).thenReturn(fakeWifiEventFlow)
+ }
connectionsRepo =
DemoMobileConnectionsRepository(
- dataSource = mockDataSource,
+ mobileDataSource = mockDataSource,
+ wifiDataSource = mockWifiDataSource,
scope = testScope.backgroundScope,
context = context,
logFactory = logFactory,
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/demo/DemoMobileConnectionsRepositoryTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/demo/DemoMobileConnectionsRepositoryTest.kt
index cdbe75e..9d16b7fe 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/demo/DemoMobileConnectionsRepositoryTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/demo/DemoMobileConnectionsRepositoryTest.kt
@@ -32,6 +32,8 @@
import com.android.systemui.statusbar.pipeline.mobile.data.repository.demo.model.FakeNetworkEventModel
import com.android.systemui.statusbar.pipeline.mobile.data.repository.demo.model.FakeNetworkEventModel.MobileDisabled
import com.android.systemui.statusbar.pipeline.shared.data.model.toMobileDataActivityModel
+import com.android.systemui.statusbar.pipeline.wifi.data.repository.demo.DemoModeWifiDataSource
+import com.android.systemui.statusbar.pipeline.wifi.data.repository.demo.model.FakeWifiEventModel
import com.android.systemui.util.mockito.mock
import com.android.systemui.util.mockito.whenever
import com.android.systemui.util.time.FakeSystemClock
@@ -57,21 +59,28 @@
private val testScope = TestScope(testDispatcher)
private val fakeNetworkEventFlow = MutableStateFlow<FakeNetworkEventModel?>(null)
+ private val fakeWifiEventFlow = MutableStateFlow<FakeWifiEventModel?>(null)
private lateinit var underTest: DemoMobileConnectionsRepository
- private lateinit var mockDataSource: DemoModeMobileConnectionDataSource
+ private lateinit var mobileDataSource: DemoModeMobileConnectionDataSource
+ private lateinit var wifiDataSource: DemoModeWifiDataSource
@Before
fun setUp() {
// The data source only provides one API, so we can mock it with a flow here for convenience
- mockDataSource =
+ mobileDataSource =
mock<DemoModeMobileConnectionDataSource>().also {
whenever(it.mobileEvents).thenReturn(fakeNetworkEventFlow)
}
+ wifiDataSource =
+ mock<DemoModeWifiDataSource>().also {
+ whenever(it.wifiEvents).thenReturn(fakeWifiEventFlow)
+ }
underTest =
DemoMobileConnectionsRepository(
- dataSource = mockDataSource,
+ mobileDataSource = mobileDataSource,
+ wifiDataSource = wifiDataSource,
scope = testScope.backgroundScope,
context = context,
logFactory = logFactory,
@@ -97,6 +106,22 @@
}
@Test
+ fun `wifi carrier merged event - create new subscription`() =
+ testScope.runTest {
+ var latest: List<SubscriptionModel>? = null
+ val job = underTest.subscriptions.onEach { latest = it }.launchIn(this)
+
+ assertThat(latest).isEmpty()
+
+ fakeWifiEventFlow.value = validCarrierMergedEvent(subId = 5)
+
+ assertThat(latest).hasSize(1)
+ assertThat(latest!![0].subscriptionId).isEqualTo(5)
+
+ job.cancel()
+ }
+
+ @Test
fun `network event - reuses subscription when same Id`() =
testScope.runTest {
var latest: List<SubscriptionModel>? = null
@@ -119,6 +144,28 @@
}
@Test
+ fun `wifi carrier merged event - reuses subscription when same Id`() =
+ testScope.runTest {
+ var latest: List<SubscriptionModel>? = null
+ val job = underTest.subscriptions.onEach { latest = it }.launchIn(this)
+
+ assertThat(latest).isEmpty()
+
+ fakeWifiEventFlow.value = validCarrierMergedEvent(subId = 5, level = 1)
+
+ assertThat(latest).hasSize(1)
+ assertThat(latest!![0].subscriptionId).isEqualTo(5)
+
+ // Second network event comes in with the same subId, does not create a new subscription
+ fakeWifiEventFlow.value = validCarrierMergedEvent(subId = 5, level = 2)
+
+ assertThat(latest).hasSize(1)
+ assertThat(latest!![0].subscriptionId).isEqualTo(5)
+
+ job.cancel()
+ }
+
+ @Test
fun `multiple subscriptions`() =
testScope.runTest {
var latest: List<SubscriptionModel>? = null
@@ -133,6 +180,35 @@
}
@Test
+ fun `mobile subscription and carrier merged subscription`() =
+ testScope.runTest {
+ var latest: List<SubscriptionModel>? = null
+ val job = underTest.subscriptions.onEach { latest = it }.launchIn(this)
+
+ fakeNetworkEventFlow.value = validMobileEvent(subId = 1)
+ fakeWifiEventFlow.value = validCarrierMergedEvent(subId = 5)
+
+ assertThat(latest).hasSize(2)
+
+ job.cancel()
+ }
+
+ @Test
+ fun `multiple mobile subscriptions and carrier merged subscription`() =
+ testScope.runTest {
+ var latest: List<SubscriptionModel>? = null
+ val job = underTest.subscriptions.onEach { latest = it }.launchIn(this)
+
+ fakeNetworkEventFlow.value = validMobileEvent(subId = 1)
+ fakeNetworkEventFlow.value = validMobileEvent(subId = 2)
+ fakeWifiEventFlow.value = validCarrierMergedEvent(subId = 3)
+
+ assertThat(latest).hasSize(3)
+
+ job.cancel()
+ }
+
+ @Test
fun `mobile disabled event - disables connection - subId specified - single conn`() =
testScope.runTest {
var latest: List<SubscriptionModel>? = null
@@ -194,6 +270,112 @@
job.cancel()
}
+ @Test
+ fun `wifi network updates to disabled - carrier merged connection removed`() =
+ testScope.runTest {
+ var latest: List<SubscriptionModel>? = null
+ val job = underTest.subscriptions.onEach { latest = it }.launchIn(this)
+
+ fakeWifiEventFlow.value = validCarrierMergedEvent(subId = 1)
+
+ assertThat(latest).hasSize(1)
+
+ fakeWifiEventFlow.value = FakeWifiEventModel.WifiDisabled
+
+ assertThat(latest).isEmpty()
+
+ job.cancel()
+ }
+
+ @Test
+ fun `wifi network updates to active - carrier merged connection removed`() =
+ testScope.runTest {
+ var latest: List<SubscriptionModel>? = null
+ val job = underTest.subscriptions.onEach { latest = it }.launchIn(this)
+
+ fakeWifiEventFlow.value = validCarrierMergedEvent(subId = 1)
+
+ assertThat(latest).hasSize(1)
+
+ fakeWifiEventFlow.value =
+ FakeWifiEventModel.Wifi(
+ level = 1,
+ activity = 0,
+ ssid = null,
+ validated = true,
+ )
+
+ assertThat(latest).isEmpty()
+
+ job.cancel()
+ }
+
+ @Test
+ fun `mobile sub updates to carrier merged - only one connection`() =
+ testScope.runTest {
+ var latestSubsList: List<SubscriptionModel>? = null
+ var connections: List<DemoMobileConnectionRepository>? = null
+ val job =
+ underTest.subscriptions
+ .onEach { latestSubsList = it }
+ .onEach { infos ->
+ connections =
+ infos.map { info -> underTest.getRepoForSubId(info.subscriptionId) }
+ }
+ .launchIn(this)
+
+ fakeNetworkEventFlow.value = validMobileEvent(subId = 3, level = 2)
+ assertThat(latestSubsList).hasSize(1)
+
+ val carrierMergedEvent = validCarrierMergedEvent(subId = 3, level = 1)
+ fakeWifiEventFlow.value = carrierMergedEvent
+ assertThat(latestSubsList).hasSize(1)
+ val connection = connections!!.find { it.subId == 3 }!!
+ assertCarrierMergedConnection(connection, carrierMergedEvent)
+
+ job.cancel()
+ }
+
+ @Test
+ fun `mobile sub updates to carrier merged then back - has old mobile data`() =
+ testScope.runTest {
+ var latestSubsList: List<SubscriptionModel>? = null
+ var connections: List<DemoMobileConnectionRepository>? = null
+ val job =
+ underTest.subscriptions
+ .onEach { latestSubsList = it }
+ .onEach { infos ->
+ connections =
+ infos.map { info -> underTest.getRepoForSubId(info.subscriptionId) }
+ }
+ .launchIn(this)
+
+ val mobileEvent = validMobileEvent(subId = 3, level = 2)
+ fakeNetworkEventFlow.value = mobileEvent
+ assertThat(latestSubsList).hasSize(1)
+
+ val carrierMergedEvent = validCarrierMergedEvent(subId = 3, level = 1)
+ fakeWifiEventFlow.value = carrierMergedEvent
+ assertThat(latestSubsList).hasSize(1)
+ var connection = connections!!.find { it.subId == 3 }!!
+ assertCarrierMergedConnection(connection, carrierMergedEvent)
+
+ // WHEN the carrier merged is removed
+ fakeWifiEventFlow.value =
+ FakeWifiEventModel.Wifi(
+ level = 4,
+ activity = 0,
+ ssid = null,
+ validated = true,
+ )
+
+ // THEN the subId=3 connection goes back to the mobile information
+ connection = connections!!.find { it.subId == 3 }!!
+ assertConnection(connection, mobileEvent)
+
+ job.cancel()
+ }
+
/** Regression test for b/261706421 */
@Test
fun `multiple connections - remove all - does not throw`() =
@@ -289,6 +471,51 @@
job.cancel()
}
+ @Test
+ fun `demo connection - two connections - update carrier merged - no affect on first`() =
+ testScope.runTest {
+ var currentEvent1 = validMobileEvent(subId = 1)
+ var connection1: DemoMobileConnectionRepository? = null
+ var currentEvent2 = validCarrierMergedEvent(subId = 2)
+ var connection2: DemoMobileConnectionRepository? = null
+ var connections: List<DemoMobileConnectionRepository>? = null
+ val job =
+ underTest.subscriptions
+ .onEach { infos ->
+ connections =
+ infos.map { info -> underTest.getRepoForSubId(info.subscriptionId) }
+ }
+ .launchIn(this)
+
+ fakeNetworkEventFlow.value = currentEvent1
+ fakeWifiEventFlow.value = currentEvent2
+ assertThat(connections).hasSize(2)
+ connections!!.forEach {
+ when (it.subId) {
+ 1 -> connection1 = it
+ 2 -> connection2 = it
+ else -> Assert.fail("Unexpected subscription")
+ }
+ }
+
+ assertConnection(connection1!!, currentEvent1)
+ assertCarrierMergedConnection(connection2!!, currentEvent2)
+
+ // WHEN the event changes for connection 2, it updates, and connection 1 stays the same
+ currentEvent2 = validCarrierMergedEvent(subId = 2, level = 4)
+ fakeWifiEventFlow.value = currentEvent2
+ assertConnection(connection1!!, currentEvent1)
+ assertCarrierMergedConnection(connection2!!, currentEvent2)
+
+ // and vice versa
+ currentEvent1 = validMobileEvent(subId = 1, inflateStrength = true)
+ fakeNetworkEventFlow.value = currentEvent1
+ assertConnection(connection1!!, currentEvent1)
+ assertCarrierMergedConnection(connection2!!, currentEvent2)
+
+ job.cancel()
+ }
+
private fun assertConnection(
conn: DemoMobileConnectionRepository,
model: FakeNetworkEventModel
@@ -315,6 +542,21 @@
else -> {}
}
}
+
+ private fun assertCarrierMergedConnection(
+ conn: DemoMobileConnectionRepository,
+ model: FakeWifiEventModel.CarrierMerged,
+ ) {
+ val connectionInfo: MobileConnectionModel = conn.connectionInfo.value
+ assertThat(conn.subId).isEqualTo(model.subscriptionId)
+ assertThat(connectionInfo.cdmaLevel).isEqualTo(model.level)
+ assertThat(connectionInfo.primaryLevel).isEqualTo(model.level)
+ assertThat(connectionInfo.carrierNetworkChangeActive).isEqualTo(false)
+ assertThat(connectionInfo.isRoaming).isEqualTo(false)
+ assertThat(connectionInfo.isEmergencyOnly).isFalse()
+ assertThat(connectionInfo.isGsm).isFalse()
+ assertThat(connectionInfo.dataConnectionState).isEqualTo(DataConnectionState.Connected)
+ }
}
/** Convenience to create a valid fake network event with minimal params */
@@ -339,3 +581,14 @@
roaming = roaming,
name = "demo name",
)
+
+fun validCarrierMergedEvent(
+ subId: Int = 1,
+ level: Int = 1,
+ numberOfLevels: Int = 4,
+): FakeWifiEventModel.CarrierMerged =
+ FakeWifiEventModel.CarrierMerged(
+ subscriptionId = subId,
+ level = level,
+ numberOfLevels = numberOfLevels,
+ )
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/CarrierMergedConnectionRepositoryTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/CarrierMergedConnectionRepositoryTest.kt
new file mode 100644
index 0000000..ea90150
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/CarrierMergedConnectionRepositoryTest.kt
@@ -0,0 +1,251 @@
+/*
+ * 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 com.android.systemui.statusbar.pipeline.mobile.data.repository.prod
+
+import android.testing.AndroidTestingRunner
+import androidx.test.filters.SmallTest
+import com.android.systemui.SysuiTestCase
+import com.android.systemui.log.table.TableLogBuffer
+import com.android.systemui.statusbar.pipeline.mobile.data.model.DataConnectionState
+import com.android.systemui.statusbar.pipeline.mobile.data.model.MobileConnectionModel
+import com.android.systemui.statusbar.pipeline.mobile.data.model.NetworkNameModel
+import com.android.systemui.statusbar.pipeline.mobile.data.model.ResolvedNetworkType
+import com.android.systemui.statusbar.pipeline.shared.data.model.DataActivityModel
+import com.android.systemui.statusbar.pipeline.wifi.data.model.WifiNetworkModel
+import com.android.systemui.statusbar.pipeline.wifi.data.repository.FakeWifiRepository
+import com.google.common.truth.Truth.assertThat
+import kotlinx.coroutines.ExperimentalCoroutinesApi
+import kotlinx.coroutines.flow.launchIn
+import kotlinx.coroutines.flow.onEach
+import kotlinx.coroutines.test.TestScope
+import kotlinx.coroutines.test.UnconfinedTestDispatcher
+import kotlinx.coroutines.test.runTest
+import org.junit.Before
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.mockito.Mock
+import org.mockito.MockitoAnnotations
+
+@SmallTest
+@OptIn(ExperimentalCoroutinesApi::class)
+@RunWith(AndroidTestingRunner::class)
+class CarrierMergedConnectionRepositoryTest : SysuiTestCase() {
+
+ private lateinit var underTest: CarrierMergedConnectionRepository
+
+ private lateinit var wifiRepository: FakeWifiRepository
+ @Mock private lateinit var logger: TableLogBuffer
+
+ private val testDispatcher = UnconfinedTestDispatcher()
+ private val testScope = TestScope(testDispatcher)
+
+ @Before
+ fun setUp() {
+ MockitoAnnotations.initMocks(this)
+ wifiRepository = FakeWifiRepository()
+
+ underTest =
+ CarrierMergedConnectionRepository(
+ SUB_ID,
+ logger,
+ NetworkNameModel.Default("name"),
+ testScope.backgroundScope,
+ wifiRepository,
+ )
+ }
+
+ @Test
+ fun connectionInfo_inactiveWifi_isDefault() =
+ testScope.runTest {
+ var latest: MobileConnectionModel? = null
+ val job = underTest.connectionInfo.onEach { latest = it }.launchIn(this)
+
+ wifiRepository.setWifiNetwork(WifiNetworkModel.Inactive)
+
+ assertThat(latest).isEqualTo(MobileConnectionModel())
+
+ job.cancel()
+ }
+
+ @Test
+ fun connectionInfo_activeWifi_isDefault() =
+ testScope.runTest {
+ var latest: MobileConnectionModel? = null
+ val job = underTest.connectionInfo.onEach { latest = it }.launchIn(this)
+
+ wifiRepository.setWifiNetwork(WifiNetworkModel.Active(networkId = NET_ID, level = 1))
+
+ assertThat(latest).isEqualTo(MobileConnectionModel())
+
+ job.cancel()
+ }
+
+ @Test
+ fun connectionInfo_carrierMergedWifi_isValidAndFieldsComeFromWifiNetwork() =
+ testScope.runTest {
+ var latest: MobileConnectionModel? = null
+ val job = underTest.connectionInfo.onEach { latest = it }.launchIn(this)
+
+ wifiRepository.setIsWifiEnabled(true)
+ wifiRepository.setIsWifiDefault(true)
+
+ wifiRepository.setWifiNetwork(
+ WifiNetworkModel.CarrierMerged(
+ networkId = NET_ID,
+ subscriptionId = SUB_ID,
+ level = 3,
+ )
+ )
+
+ val expected =
+ MobileConnectionModel(
+ primaryLevel = 3,
+ cdmaLevel = 3,
+ dataConnectionState = DataConnectionState.Connected,
+ dataActivityDirection =
+ DataActivityModel(
+ hasActivityIn = false,
+ hasActivityOut = false,
+ ),
+ resolvedNetworkType = ResolvedNetworkType.CarrierMergedNetworkType,
+ isRoaming = false,
+ isEmergencyOnly = false,
+ operatorAlphaShort = null,
+ isInService = true,
+ isGsm = false,
+ carrierNetworkChangeActive = false,
+ )
+ assertThat(latest).isEqualTo(expected)
+
+ job.cancel()
+ }
+
+ @Test
+ fun connectionInfo_carrierMergedWifi_wrongSubId_isDefault() =
+ testScope.runTest {
+ var latest: MobileConnectionModel? = null
+ val job = underTest.connectionInfo.onEach { latest = it }.launchIn(this)
+
+ wifiRepository.setWifiNetwork(
+ WifiNetworkModel.CarrierMerged(
+ networkId = NET_ID,
+ subscriptionId = SUB_ID + 10,
+ level = 3,
+ )
+ )
+
+ assertThat(latest).isEqualTo(MobileConnectionModel())
+ assertThat(latest!!.primaryLevel).isNotEqualTo(3)
+ assertThat(latest!!.resolvedNetworkType)
+ .isNotEqualTo(ResolvedNetworkType.CarrierMergedNetworkType)
+
+ job.cancel()
+ }
+
+ // This scenario likely isn't possible, but write a test for it anyway
+ @Test
+ fun connectionInfo_carrierMergedButNotEnabled_isDefault() =
+ testScope.runTest {
+ var latest: MobileConnectionModel? = null
+ val job = underTest.connectionInfo.onEach { latest = it }.launchIn(this)
+
+ wifiRepository.setWifiNetwork(
+ WifiNetworkModel.CarrierMerged(
+ networkId = NET_ID,
+ subscriptionId = SUB_ID,
+ level = 3,
+ )
+ )
+ wifiRepository.setIsWifiEnabled(false)
+
+ assertThat(latest).isEqualTo(MobileConnectionModel())
+
+ job.cancel()
+ }
+
+ // This scenario likely isn't possible, but write a test for it anyway
+ @Test
+ fun connectionInfo_carrierMergedButWifiNotDefault_isDefault() =
+ testScope.runTest {
+ var latest: MobileConnectionModel? = null
+ val job = underTest.connectionInfo.onEach { latest = it }.launchIn(this)
+
+ wifiRepository.setWifiNetwork(
+ WifiNetworkModel.CarrierMerged(
+ networkId = NET_ID,
+ subscriptionId = SUB_ID,
+ level = 3,
+ )
+ )
+ wifiRepository.setIsWifiDefault(false)
+
+ assertThat(latest).isEqualTo(MobileConnectionModel())
+
+ job.cancel()
+ }
+
+ @Test
+ fun numberOfLevels_comesFromCarrierMerged() =
+ testScope.runTest {
+ var latest: Int? = null
+ val job = underTest.numberOfLevels.onEach { latest = it }.launchIn(this)
+
+ wifiRepository.setWifiNetwork(
+ WifiNetworkModel.CarrierMerged(
+ networkId = NET_ID,
+ subscriptionId = SUB_ID,
+ level = 1,
+ numberOfLevels = 6,
+ )
+ )
+
+ assertThat(latest).isEqualTo(6)
+
+ job.cancel()
+ }
+
+ @Test
+ fun dataEnabled_matchesWifiEnabled() =
+ testScope.runTest {
+ var latest: Boolean? = null
+ val job = underTest.dataEnabled.onEach { latest = it }.launchIn(this)
+
+ wifiRepository.setIsWifiEnabled(true)
+ assertThat(latest).isTrue()
+
+ wifiRepository.setIsWifiEnabled(false)
+ assertThat(latest).isFalse()
+
+ job.cancel()
+ }
+
+ @Test
+ fun cdmaRoaming_alwaysFalse() =
+ testScope.runTest {
+ var latest: Boolean? = null
+ val job = underTest.cdmaRoaming.onEach { latest = it }.launchIn(this)
+
+ assertThat(latest).isFalse()
+
+ job.cancel()
+ }
+
+ private companion object {
+ const val SUB_ID = 123
+ const val NET_ID = 456
+ }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/FullMobileConnectionRepositoryTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/FullMobileConnectionRepositoryTest.kt
new file mode 100644
index 0000000..c02a4df
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/FullMobileConnectionRepositoryTest.kt
@@ -0,0 +1,389 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.statusbar.pipeline.mobile.data.repository.prod
+
+import androidx.test.filters.SmallTest
+import com.android.systemui.SysuiTestCase
+import com.android.systemui.log.table.TableLogBuffer
+import com.android.systemui.log.table.TableLogBufferFactory
+import com.android.systemui.statusbar.pipeline.mobile.data.model.MobileConnectionModel
+import com.android.systemui.statusbar.pipeline.mobile.data.model.NetworkNameModel
+import com.android.systemui.statusbar.pipeline.mobile.data.repository.FakeMobileConnectionRepository
+import com.android.systemui.statusbar.pipeline.mobile.data.repository.FakeMobileConnectionsRepository
+import com.android.systemui.statusbar.pipeline.mobile.data.repository.MobileConnectionRepository
+import com.android.systemui.statusbar.pipeline.mobile.util.FakeMobileMappingsProxy
+import com.android.systemui.util.mockito.any
+import com.android.systemui.util.mockito.eq
+import com.android.systemui.util.mockito.mock
+import com.android.systemui.util.mockito.whenever
+import com.android.systemui.util.time.FakeSystemClock
+import com.google.common.truth.Truth.assertThat
+import kotlinx.coroutines.ExperimentalCoroutinesApi
+import kotlinx.coroutines.flow.Flow
+import kotlinx.coroutines.flow.launchIn
+import kotlinx.coroutines.flow.onEach
+import kotlinx.coroutines.test.TestScope
+import kotlinx.coroutines.test.UnconfinedTestDispatcher
+import kotlinx.coroutines.test.runTest
+import org.junit.Before
+import org.junit.Test
+import org.mockito.Mockito.never
+import org.mockito.Mockito.verify
+
+/**
+ * This repo acts as a dispatcher to either the `typical` or `carrier merged` versions of the
+ * repository interface it's switching on. These tests just need to verify that the entire interface
+ * properly switches over when the value of `isCarrierMerged` changes.
+ */
+@Suppress("EXPERIMENTAL_IS_NOT_ENABLED")
+@OptIn(ExperimentalCoroutinesApi::class)
+@SmallTest
+class FullMobileConnectionRepositoryTest : SysuiTestCase() {
+ private lateinit var underTest: FullMobileConnectionRepository
+
+ private val testDispatcher = UnconfinedTestDispatcher()
+ private val testScope = TestScope(testDispatcher)
+ private val mobileMappings = FakeMobileMappingsProxy()
+ private val tableLogBuffer = mock<TableLogBuffer>()
+ private val mobileFactory = mock<MobileConnectionRepositoryImpl.Factory>()
+ private val carrierMergedFactory = mock<CarrierMergedConnectionRepository.Factory>()
+
+ private lateinit var connectionsRepo: FakeMobileConnectionsRepository
+ private val globalMobileDataSettingChangedEvent: Flow<Unit>
+ get() = connectionsRepo.globalMobileDataSettingChangedEvent
+
+ private lateinit var mobileRepo: FakeMobileConnectionRepository
+ private lateinit var carrierMergedRepo: FakeMobileConnectionRepository
+
+ @Before
+ fun setUp() {
+ connectionsRepo = FakeMobileConnectionsRepository(mobileMappings, tableLogBuffer)
+
+ mobileRepo = FakeMobileConnectionRepository(SUB_ID, tableLogBuffer)
+ carrierMergedRepo = FakeMobileConnectionRepository(SUB_ID, tableLogBuffer)
+
+ whenever(
+ mobileFactory.build(
+ eq(SUB_ID),
+ any(),
+ eq(DEFAULT_NAME),
+ eq(SEP),
+ eq(globalMobileDataSettingChangedEvent),
+ )
+ )
+ .thenReturn(mobileRepo)
+ whenever(carrierMergedFactory.build(eq(SUB_ID), any(), eq(DEFAULT_NAME)))
+ .thenReturn(carrierMergedRepo)
+ }
+
+ @Test
+ fun startingIsCarrierMerged_usesCarrierMergedInitially() =
+ testScope.runTest {
+ val carrierMergedConnectionInfo =
+ MobileConnectionModel(
+ operatorAlphaShort = "Carrier Merged Operator",
+ )
+ carrierMergedRepo.setConnectionInfo(carrierMergedConnectionInfo)
+
+ initializeRepo(startingIsCarrierMerged = true)
+
+ assertThat(underTest.activeRepo.value).isEqualTo(carrierMergedRepo)
+ assertThat(underTest.connectionInfo.value).isEqualTo(carrierMergedConnectionInfo)
+ verify(mobileFactory, never())
+ .build(
+ SUB_ID,
+ tableLogBuffer,
+ DEFAULT_NAME,
+ SEP,
+ globalMobileDataSettingChangedEvent
+ )
+ }
+
+ @Test
+ fun startingNotCarrierMerged_usesTypicalInitially() =
+ testScope.runTest {
+ val mobileConnectionInfo =
+ MobileConnectionModel(
+ operatorAlphaShort = "Typical Operator",
+ )
+ mobileRepo.setConnectionInfo(mobileConnectionInfo)
+
+ initializeRepo(startingIsCarrierMerged = false)
+
+ assertThat(underTest.activeRepo.value).isEqualTo(mobileRepo)
+ assertThat(underTest.connectionInfo.value).isEqualTo(mobileConnectionInfo)
+ verify(carrierMergedFactory, never()).build(SUB_ID, tableLogBuffer, DEFAULT_NAME)
+ }
+
+ @Test
+ fun activeRepo_matchesIsCarrierMerged() =
+ testScope.runTest {
+ initializeRepo(startingIsCarrierMerged = false)
+ var latest: MobileConnectionRepository? = null
+ val job = underTest.activeRepo.onEach { latest = it }.launchIn(this)
+
+ underTest.setIsCarrierMerged(true)
+
+ assertThat(latest).isEqualTo(carrierMergedRepo)
+
+ underTest.setIsCarrierMerged(false)
+
+ assertThat(latest).isEqualTo(mobileRepo)
+
+ underTest.setIsCarrierMerged(true)
+
+ assertThat(latest).isEqualTo(carrierMergedRepo)
+
+ job.cancel()
+ }
+
+ @Test
+ fun connectionInfo_getsUpdatesFromRepo_carrierMerged() =
+ testScope.runTest {
+ initializeRepo(startingIsCarrierMerged = false)
+
+ var latest: MobileConnectionModel? = null
+ val job = underTest.connectionInfo.onEach { latest = it }.launchIn(this)
+
+ underTest.setIsCarrierMerged(true)
+
+ val info1 =
+ MobileConnectionModel(
+ operatorAlphaShort = "Carrier Merged Operator",
+ primaryLevel = 1,
+ )
+ carrierMergedRepo.setConnectionInfo(info1)
+
+ assertThat(latest).isEqualTo(info1)
+
+ val info2 =
+ MobileConnectionModel(
+ operatorAlphaShort = "Carrier Merged Operator #2",
+ primaryLevel = 2,
+ )
+ carrierMergedRepo.setConnectionInfo(info2)
+
+ assertThat(latest).isEqualTo(info2)
+
+ val info3 =
+ MobileConnectionModel(
+ operatorAlphaShort = "Carrier Merged Operator #3",
+ primaryLevel = 3,
+ )
+ carrierMergedRepo.setConnectionInfo(info3)
+
+ assertThat(latest).isEqualTo(info3)
+
+ job.cancel()
+ }
+
+ @Test
+ fun connectionInfo_getsUpdatesFromRepo_mobile() =
+ testScope.runTest {
+ initializeRepo(startingIsCarrierMerged = false)
+
+ var latest: MobileConnectionModel? = null
+ val job = underTest.connectionInfo.onEach { latest = it }.launchIn(this)
+
+ underTest.setIsCarrierMerged(false)
+
+ val info1 =
+ MobileConnectionModel(
+ operatorAlphaShort = "Typical Merged Operator",
+ primaryLevel = 1,
+ )
+ mobileRepo.setConnectionInfo(info1)
+
+ assertThat(latest).isEqualTo(info1)
+
+ val info2 =
+ MobileConnectionModel(
+ operatorAlphaShort = "Typical Merged Operator #2",
+ primaryLevel = 2,
+ )
+ mobileRepo.setConnectionInfo(info2)
+
+ assertThat(latest).isEqualTo(info2)
+
+ val info3 =
+ MobileConnectionModel(
+ operatorAlphaShort = "Typical Merged Operator #3",
+ primaryLevel = 3,
+ )
+ mobileRepo.setConnectionInfo(info3)
+
+ assertThat(latest).isEqualTo(info3)
+
+ job.cancel()
+ }
+
+ @Test
+ fun connectionInfo_updatesWhenCarrierMergedUpdates() =
+ testScope.runTest {
+ initializeRepo(startingIsCarrierMerged = false)
+
+ var latest: MobileConnectionModel? = null
+ val job = underTest.connectionInfo.onEach { latest = it }.launchIn(this)
+
+ val carrierMergedInfo =
+ MobileConnectionModel(
+ operatorAlphaShort = "Carrier Merged Operator",
+ primaryLevel = 4,
+ )
+ carrierMergedRepo.setConnectionInfo(carrierMergedInfo)
+
+ val mobileInfo =
+ MobileConnectionModel(
+ operatorAlphaShort = "Typical Operator",
+ primaryLevel = 2,
+ )
+ mobileRepo.setConnectionInfo(mobileInfo)
+
+ // Start with the mobile info
+ assertThat(latest).isEqualTo(mobileInfo)
+
+ // WHEN isCarrierMerged is set to true
+ underTest.setIsCarrierMerged(true)
+
+ // THEN the carrier merged info is used
+ assertThat(latest).isEqualTo(carrierMergedInfo)
+
+ val newCarrierMergedInfo =
+ MobileConnectionModel(
+ operatorAlphaShort = "New CM Operator",
+ primaryLevel = 0,
+ )
+ carrierMergedRepo.setConnectionInfo(newCarrierMergedInfo)
+
+ assertThat(latest).isEqualTo(newCarrierMergedInfo)
+
+ // WHEN isCarrierMerged is set to false
+ underTest.setIsCarrierMerged(false)
+
+ // THEN the typical info is used
+ assertThat(latest).isEqualTo(mobileInfo)
+
+ val newMobileInfo =
+ MobileConnectionModel(
+ operatorAlphaShort = "New Mobile Operator",
+ primaryLevel = 3,
+ )
+ mobileRepo.setConnectionInfo(newMobileInfo)
+
+ assertThat(latest).isEqualTo(newMobileInfo)
+
+ job.cancel()
+ }
+
+ @Test
+ fun `factory - reuses log buffers for same connection`() =
+ testScope.runTest {
+ val realLoggerFactory = TableLogBufferFactory(mock(), FakeSystemClock())
+
+ val factory =
+ FullMobileConnectionRepository.Factory(
+ scope = testScope.backgroundScope,
+ realLoggerFactory,
+ mobileFactory,
+ carrierMergedFactory,
+ )
+
+ // Create two connections for the same subId. Similar to if the connection appeared
+ // and disappeared from the connectionFactory's perspective
+ val connection1 =
+ factory.build(
+ SUB_ID,
+ startingIsCarrierMerged = false,
+ DEFAULT_NAME,
+ SEP,
+ globalMobileDataSettingChangedEvent,
+ )
+
+ val connection1Repeat =
+ factory.build(
+ SUB_ID,
+ startingIsCarrierMerged = false,
+ DEFAULT_NAME,
+ SEP,
+ globalMobileDataSettingChangedEvent,
+ )
+
+ assertThat(connection1.tableLogBuffer)
+ .isSameInstanceAs(connection1Repeat.tableLogBuffer)
+ }
+
+ @Test
+ fun `factory - reuses log buffers for same sub ID even if carrier merged`() =
+ testScope.runTest {
+ val realLoggerFactory = TableLogBufferFactory(mock(), FakeSystemClock())
+
+ val factory =
+ FullMobileConnectionRepository.Factory(
+ scope = testScope.backgroundScope,
+ realLoggerFactory,
+ mobileFactory,
+ carrierMergedFactory,
+ )
+
+ val connection1 =
+ factory.build(
+ SUB_ID,
+ startingIsCarrierMerged = false,
+ DEFAULT_NAME,
+ SEP,
+ globalMobileDataSettingChangedEvent,
+ )
+
+ // WHEN a connection with the same sub ID but carrierMerged = true is created
+ val connection1Repeat =
+ factory.build(
+ SUB_ID,
+ startingIsCarrierMerged = true,
+ DEFAULT_NAME,
+ SEP,
+ globalMobileDataSettingChangedEvent,
+ )
+
+ // THEN the same table is re-used
+ assertThat(connection1.tableLogBuffer)
+ .isSameInstanceAs(connection1Repeat.tableLogBuffer)
+ }
+
+ // TODO(b/238425913): Verify that the logging switches correctly (once the carrier merged repo
+ // implements logging).
+
+ private fun initializeRepo(startingIsCarrierMerged: Boolean) {
+ underTest =
+ FullMobileConnectionRepository(
+ SUB_ID,
+ startingIsCarrierMerged,
+ tableLogBuffer,
+ DEFAULT_NAME,
+ SEP,
+ globalMobileDataSettingChangedEvent,
+ testScope.backgroundScope,
+ mobileFactory,
+ carrierMergedFactory,
+ )
+ }
+
+ private companion object {
+ const val SUB_ID = 42
+ private val DEFAULT_NAME = NetworkNameModel.Default("default name")
+ private const val SEP = "-"
+ }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/MobileConnectionsRepositoryTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/MobileConnectionsRepositoryTest.kt
index 0da15e2..813b0ed 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/MobileConnectionsRepositoryTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/MobileConnectionsRepositoryTest.kt
@@ -38,8 +38,11 @@
import com.android.systemui.log.table.TableLogBufferFactory
import com.android.systemui.statusbar.pipeline.mobile.data.model.MobileConnectivityModel
import com.android.systemui.statusbar.pipeline.mobile.data.model.SubscriptionModel
+import com.android.systemui.statusbar.pipeline.mobile.data.repository.prod.FullMobileConnectionRepository.Factory.Companion.tableBufferLogName
import com.android.systemui.statusbar.pipeline.mobile.util.FakeMobileMappingsProxy
import com.android.systemui.statusbar.pipeline.shared.ConnectivityPipelineLogger
+import com.android.systemui.statusbar.pipeline.wifi.data.model.WifiNetworkModel
+import com.android.systemui.statusbar.pipeline.wifi.data.repository.FakeWifiRepository
import com.android.systemui.util.mockito.any
import com.android.systemui.util.mockito.argumentCaptor
import com.android.systemui.util.mockito.eq
@@ -72,6 +75,9 @@
private lateinit var underTest: MobileConnectionsRepositoryImpl
private lateinit var connectionFactory: MobileConnectionRepositoryImpl.Factory
+ private lateinit var carrierMergedFactory: CarrierMergedConnectionRepository.Factory
+ private lateinit var fullConnectionFactory: FullMobileConnectionRepository.Factory
+ private lateinit var wifiRepository: FakeWifiRepository
@Mock private lateinit var connectivityManager: ConnectivityManager
@Mock private lateinit var subscriptionManager: SubscriptionManager
@Mock private lateinit var telephonyManager: TelephonyManager
@@ -94,10 +100,12 @@
}
}
- whenever(logBufferFactory.create(anyString(), anyInt())).thenAnswer { _ ->
+ whenever(logBufferFactory.getOrCreate(anyString(), anyInt())).thenAnswer { _ ->
mock<TableLogBuffer>()
}
+ wifiRepository = FakeWifiRepository()
+
connectionFactory =
MobileConnectionRepositoryImpl.Factory(
fakeBroadcastDispatcher,
@@ -108,7 +116,18 @@
logger = logger,
mobileMappingsProxy = mobileMappings,
scope = scope,
+ )
+ carrierMergedFactory =
+ CarrierMergedConnectionRepository.Factory(
+ scope,
+ wifiRepository,
+ )
+ fullConnectionFactory =
+ FullMobileConnectionRepository.Factory(
+ scope = scope,
logFactory = logBufferFactory,
+ mobileRepoFactory = connectionFactory,
+ carrierMergedRepoFactory = carrierMergedFactory,
)
underTest =
@@ -123,7 +142,8 @@
context,
IMMEDIATE,
scope,
- connectionFactory,
+ wifiRepository,
+ fullConnectionFactory,
)
}
@@ -178,6 +198,40 @@
}
@Test
+ fun testSubscriptions_carrierMergedOnly_listHasCarrierMerged() =
+ runBlocking(IMMEDIATE) {
+ var latest: List<SubscriptionModel>? = null
+
+ val job = underTest.subscriptions.onEach { latest = it }.launchIn(this)
+
+ wifiRepository.setWifiNetwork(WIFI_NETWORK_CM)
+ whenever(subscriptionManager.completeActiveSubscriptionInfoList)
+ .thenReturn(listOf(SUB_CM))
+ getSubscriptionCallback().onSubscriptionsChanged()
+
+ assertThat(latest).isEqualTo(listOf(MODEL_CM))
+
+ job.cancel()
+ }
+
+ @Test
+ fun testSubscriptions_carrierMergedAndOther_listHasBothWithCarrierMergedLast() =
+ runBlocking(IMMEDIATE) {
+ var latest: List<SubscriptionModel>? = null
+
+ val job = underTest.subscriptions.onEach { latest = it }.launchIn(this)
+
+ wifiRepository.setWifiNetwork(WIFI_NETWORK_CM)
+ whenever(subscriptionManager.completeActiveSubscriptionInfoList)
+ .thenReturn(listOf(SUB_1, SUB_2, SUB_CM))
+ getSubscriptionCallback().onSubscriptionsChanged()
+
+ assertThat(latest).isEqualTo(listOf(MODEL_1, MODEL_2, MODEL_CM))
+
+ job.cancel()
+ }
+
+ @Test
fun testActiveDataSubscriptionId_initialValueIsInvalidId() =
runBlocking(IMMEDIATE) {
assertThat(underTest.activeMobileDataSubscriptionId.value)
@@ -217,6 +271,96 @@
}
@Test
+ fun testConnectionRepository_carrierMergedSubId_isCached() =
+ runBlocking(IMMEDIATE) {
+ val job = underTest.subscriptions.launchIn(this)
+
+ wifiRepository.setWifiNetwork(WIFI_NETWORK_CM)
+ whenever(subscriptionManager.completeActiveSubscriptionInfoList)
+ .thenReturn(listOf(SUB_CM))
+ getSubscriptionCallback().onSubscriptionsChanged()
+
+ val repo1 = underTest.getRepoForSubId(SUB_CM_ID)
+ val repo2 = underTest.getRepoForSubId(SUB_CM_ID)
+
+ assertThat(repo1).isSameInstanceAs(repo2)
+
+ job.cancel()
+ }
+
+ @Test
+ fun testConnectionRepository_carrierMergedAndMobileSubs_usesCorrectRepos() =
+ runBlocking(IMMEDIATE) {
+ val job = underTest.subscriptions.launchIn(this)
+
+ wifiRepository.setWifiNetwork(WIFI_NETWORK_CM)
+ whenever(subscriptionManager.completeActiveSubscriptionInfoList)
+ .thenReturn(listOf(SUB_1, SUB_CM))
+ getSubscriptionCallback().onSubscriptionsChanged()
+
+ val carrierMergedRepo = underTest.getRepoForSubId(SUB_CM_ID)
+ val mobileRepo = underTest.getRepoForSubId(SUB_1_ID)
+ assertThat(carrierMergedRepo.getIsCarrierMerged()).isTrue()
+ assertThat(mobileRepo.getIsCarrierMerged()).isFalse()
+
+ job.cancel()
+ }
+
+ @Test
+ fun testSubscriptions_subNoLongerCarrierMerged_repoUpdates() =
+ runBlocking(IMMEDIATE) {
+ val job = underTest.subscriptions.launchIn(this)
+
+ wifiRepository.setWifiNetwork(WIFI_NETWORK_CM)
+ whenever(subscriptionManager.completeActiveSubscriptionInfoList)
+ .thenReturn(listOf(SUB_1, SUB_CM))
+ getSubscriptionCallback().onSubscriptionsChanged()
+
+ val carrierMergedRepo = underTest.getRepoForSubId(SUB_CM_ID)
+ var mobileRepo = underTest.getRepoForSubId(SUB_1_ID)
+ assertThat(carrierMergedRepo.getIsCarrierMerged()).isTrue()
+ assertThat(mobileRepo.getIsCarrierMerged()).isFalse()
+
+ // WHEN the wifi network updates to be not carrier merged
+ wifiRepository.setWifiNetwork(WifiNetworkModel.Active(networkId = 4, level = 1))
+
+ // THEN the repos update
+ val noLongerCarrierMergedRepo = underTest.getRepoForSubId(SUB_CM_ID)
+ mobileRepo = underTest.getRepoForSubId(SUB_1_ID)
+ assertThat(noLongerCarrierMergedRepo.getIsCarrierMerged()).isFalse()
+ assertThat(mobileRepo.getIsCarrierMerged()).isFalse()
+
+ job.cancel()
+ }
+
+ @Test
+ fun testSubscriptions_subBecomesCarrierMerged_repoUpdates() =
+ runBlocking(IMMEDIATE) {
+ val job = underTest.subscriptions.launchIn(this)
+
+ wifiRepository.setWifiNetwork(WifiNetworkModel.Inactive)
+ whenever(subscriptionManager.completeActiveSubscriptionInfoList)
+ .thenReturn(listOf(SUB_1, SUB_CM))
+ getSubscriptionCallback().onSubscriptionsChanged()
+
+ val notYetCarrierMergedRepo = underTest.getRepoForSubId(SUB_CM_ID)
+ var mobileRepo = underTest.getRepoForSubId(SUB_1_ID)
+ assertThat(notYetCarrierMergedRepo.getIsCarrierMerged()).isFalse()
+ assertThat(mobileRepo.getIsCarrierMerged()).isFalse()
+
+ // WHEN the wifi network updates to be carrier merged
+ wifiRepository.setWifiNetwork(WIFI_NETWORK_CM)
+
+ // THEN the repos update
+ val carrierMergedRepo = underTest.getRepoForSubId(SUB_CM_ID)
+ mobileRepo = underTest.getRepoForSubId(SUB_1_ID)
+ assertThat(carrierMergedRepo.getIsCarrierMerged()).isTrue()
+ assertThat(mobileRepo.getIsCarrierMerged()).isFalse()
+
+ job.cancel()
+ }
+
+ @Test
fun testConnectionCache_clearsInvalidSubscriptions() =
runBlocking(IMMEDIATE) {
val job = underTest.subscriptions.launchIn(this)
@@ -242,6 +386,34 @@
job.cancel()
}
+ @Test
+ fun testConnectionCache_clearsInvalidSubscriptions_includingCarrierMerged() =
+ runBlocking(IMMEDIATE) {
+ val job = underTest.subscriptions.launchIn(this)
+
+ wifiRepository.setWifiNetwork(WIFI_NETWORK_CM)
+ whenever(subscriptionManager.completeActiveSubscriptionInfoList)
+ .thenReturn(listOf(SUB_1, SUB_2, SUB_CM))
+ getSubscriptionCallback().onSubscriptionsChanged()
+
+ // Get repos to trigger caching
+ val repo1 = underTest.getRepoForSubId(SUB_1_ID)
+ val repo2 = underTest.getRepoForSubId(SUB_2_ID)
+ val repoCarrierMerged = underTest.getRepoForSubId(SUB_CM_ID)
+
+ assertThat(underTest.getSubIdRepoCache())
+ .containsExactly(SUB_1_ID, repo1, SUB_2_ID, repo2, SUB_CM_ID, repoCarrierMerged)
+
+ // SUB_2 and SUB_CM disappear
+ whenever(subscriptionManager.completeActiveSubscriptionInfoList)
+ .thenReturn(listOf(SUB_1))
+ getSubscriptionCallback().onSubscriptionsChanged()
+
+ assertThat(underTest.getSubIdRepoCache()).containsExactly(SUB_1_ID, repo1)
+
+ job.cancel()
+ }
+
/** Regression test for b/261706421 */
@Test
fun testConnectionsCache_clearMultipleSubscriptionsAtOnce_doesNotThrow() =
@@ -292,14 +464,14 @@
// Get repos to trigger creation
underTest.getRepoForSubId(SUB_1_ID)
verify(logBufferFactory)
- .create(
- eq(MobileConnectionRepositoryImpl.tableBufferLogName(SUB_1_ID)),
+ .getOrCreate(
+ eq(tableBufferLogName(SUB_1_ID)),
anyInt(),
)
underTest.getRepoForSubId(SUB_2_ID)
verify(logBufferFactory)
- .create(
- eq(MobileConnectionRepositoryImpl.tableBufferLogName(SUB_2_ID)),
+ .getOrCreate(
+ eq(tableBufferLogName(SUB_2_ID)),
anyInt(),
)
@@ -419,7 +591,8 @@
context,
IMMEDIATE,
scope,
- connectionFactory,
+ wifiRepository,
+ fullConnectionFactory,
)
var latest: MobileMappings.Config? = null
@@ -529,5 +702,16 @@
private const val NET_ID = 123
private val NETWORK = mock<Network>().apply { whenever(getNetId()).thenReturn(NET_ID) }
+
+ private const val SUB_CM_ID = 5
+ private val SUB_CM =
+ mock<SubscriptionInfo>().also { whenever(it.subscriptionId).thenReturn(SUB_CM_ID) }
+ private val MODEL_CM = SubscriptionModel(subscriptionId = SUB_CM_ID)
+ private val WIFI_NETWORK_CM =
+ WifiNetworkModel.CarrierMerged(
+ networkId = 3,
+ subscriptionId = SUB_CM_ID,
+ level = 1,
+ )
}
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/domain/interactor/MobileIconInteractorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/domain/interactor/MobileIconInteractorTest.kt
index 61e13b8..e6be7f1 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/domain/interactor/MobileIconInteractorTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/domain/interactor/MobileIconInteractorTest.kt
@@ -25,6 +25,7 @@
import com.android.systemui.statusbar.pipeline.mobile.data.model.DataConnectionState
import com.android.systemui.statusbar.pipeline.mobile.data.model.MobileConnectionModel
import com.android.systemui.statusbar.pipeline.mobile.data.model.NetworkNameModel
+import com.android.systemui.statusbar.pipeline.mobile.data.model.ResolvedNetworkType.CarrierMergedNetworkType
import com.android.systemui.statusbar.pipeline.mobile.data.model.ResolvedNetworkType.DefaultNetworkType
import com.android.systemui.statusbar.pipeline.mobile.data.model.ResolvedNetworkType.OverrideNetworkType
import com.android.systemui.statusbar.pipeline.mobile.data.repository.FakeMobileConnectionRepository
@@ -271,6 +272,23 @@
}
@Test
+ fun iconGroup_carrierMerged_usesOverride() =
+ runBlocking(IMMEDIATE) {
+ connectionRepository.setConnectionInfo(
+ MobileConnectionModel(
+ resolvedNetworkType = CarrierMergedNetworkType,
+ ),
+ )
+
+ var latest: MobileIconGroup? = null
+ val job = underTest.networkTypeIconGroup.onEach { latest = it }.launchIn(this)
+
+ assertThat(latest).isEqualTo(CarrierMergedNetworkType.iconGroupOverride)
+
+ job.cancel()
+ }
+
+ @Test
fun alwaysShowDataRatIcon_matchesParent() =
runBlocking(IMMEDIATE) {
var latest: Boolean? = null
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/wifi/data/model/WifiNetworkModelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/wifi/data/model/WifiNetworkModelTest.kt
index 30ac8d4..824cebd 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/wifi/data/model/WifiNetworkModelTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/wifi/data/model/WifiNetworkModelTest.kt
@@ -16,11 +16,12 @@
package com.android.systemui.statusbar.pipeline.wifi.data.model
+import android.telephony.SubscriptionManager.INVALID_SUBSCRIPTION_ID
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
import com.android.systemui.log.table.TableRowLogger
import com.android.systemui.statusbar.pipeline.wifi.data.model.WifiNetworkModel.Active.Companion.MAX_VALID_LEVEL
-import com.android.systemui.statusbar.pipeline.wifi.data.model.WifiNetworkModel.Active.Companion.MIN_VALID_LEVEL
+import com.android.systemui.statusbar.pipeline.wifi.data.model.WifiNetworkModel.Companion.MIN_VALID_LEVEL
import com.google.common.truth.Truth.assertThat
import org.junit.Test
@@ -44,9 +45,53 @@
WifiNetworkModel.Active(NETWORK_ID, level = MAX_VALID_LEVEL + 1)
}
+ @Test(expected = IllegalArgumentException::class)
+ fun carrierMerged_invalidSubId_exceptionThrown() {
+ WifiNetworkModel.CarrierMerged(NETWORK_ID, INVALID_SUBSCRIPTION_ID, 1)
+ }
+
// Non-exhaustive logDiffs test -- just want to make sure the logging logic isn't totally broken
@Test
+ fun logDiffs_carrierMergedToInactive_resetsAllFields() {
+ val logger = TestLogger()
+ val prevVal =
+ WifiNetworkModel.CarrierMerged(
+ networkId = 5,
+ subscriptionId = 3,
+ level = 1,
+ )
+
+ WifiNetworkModel.Inactive.logDiffs(prevVal, logger)
+
+ assertThat(logger.changes).contains(Pair(COL_NETWORK_TYPE, TYPE_INACTIVE))
+ assertThat(logger.changes).contains(Pair(COL_NETWORK_ID, NETWORK_ID_DEFAULT.toString()))
+ assertThat(logger.changes).contains(Pair(COL_VALIDATED, "false"))
+ assertThat(logger.changes).contains(Pair(COL_LEVEL, LEVEL_DEFAULT.toString()))
+ assertThat(logger.changes).contains(Pair(COL_SSID, "null"))
+ }
+
+ @Test
+ fun logDiffs_inactiveToCarrierMerged_logsAllFields() {
+ val logger = TestLogger()
+ val carrierMerged =
+ WifiNetworkModel.CarrierMerged(
+ networkId = 6,
+ subscriptionId = 3,
+ level = 2,
+ )
+
+ carrierMerged.logDiffs(prevVal = WifiNetworkModel.Inactive, logger)
+
+ assertThat(logger.changes).contains(Pair(COL_NETWORK_TYPE, TYPE_CARRIER_MERGED))
+ assertThat(logger.changes).contains(Pair(COL_NETWORK_ID, "6"))
+ assertThat(logger.changes).contains(Pair(COL_SUB_ID, "3"))
+ assertThat(logger.changes).contains(Pair(COL_VALIDATED, "true"))
+ assertThat(logger.changes).contains(Pair(COL_LEVEL, "2"))
+ assertThat(logger.changes).contains(Pair(COL_SSID, "null"))
+ }
+
+ @Test
fun logDiffs_inactiveToActive_logsAllActiveFields() {
val logger = TestLogger()
val activeNetwork =
@@ -95,8 +140,14 @@
level = 3,
ssid = "Test SSID"
)
+ val prevVal =
+ WifiNetworkModel.CarrierMerged(
+ networkId = 5,
+ subscriptionId = 3,
+ level = 1,
+ )
- activeNetwork.logDiffs(prevVal = WifiNetworkModel.CarrierMerged, logger)
+ activeNetwork.logDiffs(prevVal, logger)
assertThat(logger.changes).contains(Pair(COL_NETWORK_TYPE, TYPE_ACTIVE))
assertThat(logger.changes).contains(Pair(COL_NETWORK_ID, "5"))
@@ -105,7 +156,7 @@
assertThat(logger.changes).contains(Pair(COL_SSID, "Test SSID"))
}
@Test
- fun logDiffs_activeToCarrierMerged_resetsAllActiveFields() {
+ fun logDiffs_activeToCarrierMerged_logsAllFields() {
val logger = TestLogger()
val activeNetwork =
WifiNetworkModel.Active(
@@ -114,13 +165,20 @@
level = 3,
ssid = "Test SSID"
)
+ val carrierMerged =
+ WifiNetworkModel.CarrierMerged(
+ networkId = 6,
+ subscriptionId = 3,
+ level = 2,
+ )
- WifiNetworkModel.CarrierMerged.logDiffs(prevVal = activeNetwork, logger)
+ carrierMerged.logDiffs(prevVal = activeNetwork, logger)
assertThat(logger.changes).contains(Pair(COL_NETWORK_TYPE, TYPE_CARRIER_MERGED))
- assertThat(logger.changes).contains(Pair(COL_NETWORK_ID, NETWORK_ID_DEFAULT.toString()))
- assertThat(logger.changes).contains(Pair(COL_VALIDATED, "false"))
- assertThat(logger.changes).contains(Pair(COL_LEVEL, LEVEL_DEFAULT.toString()))
+ assertThat(logger.changes).contains(Pair(COL_NETWORK_ID, "6"))
+ assertThat(logger.changes).contains(Pair(COL_SUB_ID, "3"))
+ assertThat(logger.changes).contains(Pair(COL_VALIDATED, "true"))
+ assertThat(logger.changes).contains(Pair(COL_LEVEL, "2"))
assertThat(logger.changes).contains(Pair(COL_SSID, "null"))
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/wifi/data/repository/prod/WifiRepositoryImplTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/wifi/data/repository/prod/WifiRepositoryImplTest.kt
index 8f07615..87ce8fa 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/wifi/data/repository/prod/WifiRepositoryImplTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/wifi/data/repository/prod/WifiRepositoryImplTest.kt
@@ -26,6 +26,7 @@
import android.net.wifi.WifiInfo
import android.net.wifi.WifiManager
import android.net.wifi.WifiManager.TrafficStateCallback
+import android.telephony.SubscriptionManager.INVALID_SUBSCRIPTION_ID
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
import com.android.systemui.broadcast.BroadcastDispatcher
@@ -340,7 +341,6 @@
.launchIn(this)
val wifiInfo = mock<WifiInfo>().apply {
- whenever(this.ssid).thenReturn(SSID)
whenever(this.isPrimary).thenReturn(true)
whenever(this.isCarrierMerged).thenReturn(true)
}
@@ -353,6 +353,67 @@
}
@Test
+ fun wifiNetwork_carrierMergedButInvalidSubId_flowHasInvalid() =
+ runBlocking(IMMEDIATE) {
+ var latest: WifiNetworkModel? = null
+ val job = underTest
+ .wifiNetwork
+ .onEach { latest = it }
+ .launchIn(this)
+
+ val wifiInfo = mock<WifiInfo>().apply {
+ whenever(this.isPrimary).thenReturn(true)
+ whenever(this.isCarrierMerged).thenReturn(true)
+ whenever(this.subscriptionId).thenReturn(INVALID_SUBSCRIPTION_ID)
+ }
+
+ getNetworkCallback().onCapabilitiesChanged(
+ NETWORK,
+ createWifiNetworkCapabilities(wifiInfo),
+ )
+
+ assertThat(latest).isInstanceOf(WifiNetworkModel.Invalid::class.java)
+
+ job.cancel()
+ }
+
+ @Test
+ fun wifiNetwork_isCarrierMerged_getsCorrectValues() =
+ runBlocking(IMMEDIATE) {
+ var latest: WifiNetworkModel? = null
+ val job = underTest
+ .wifiNetwork
+ .onEach { latest = it }
+ .launchIn(this)
+
+ val rssi = -57
+ val wifiInfo = mock<WifiInfo>().apply {
+ whenever(this.isPrimary).thenReturn(true)
+ whenever(this.isCarrierMerged).thenReturn(true)
+ whenever(this.rssi).thenReturn(rssi)
+ whenever(this.subscriptionId).thenReturn(567)
+ }
+
+ whenever(wifiManager.calculateSignalLevel(rssi)).thenReturn(2)
+ whenever(wifiManager.maxSignalLevel).thenReturn(5)
+
+ getNetworkCallback().onCapabilitiesChanged(
+ NETWORK,
+ createWifiNetworkCapabilities(wifiInfo),
+ )
+
+ assertThat(latest is WifiNetworkModel.CarrierMerged).isTrue()
+ val latestCarrierMerged = latest as WifiNetworkModel.CarrierMerged
+ assertThat(latestCarrierMerged.networkId).isEqualTo(NETWORK_ID)
+ assertThat(latestCarrierMerged.subscriptionId).isEqualTo(567)
+ assertThat(latestCarrierMerged.level).isEqualTo(2)
+ // numberOfLevels = maxSignalLevel + 1
+ assertThat(latestCarrierMerged.numberOfLevels).isEqualTo(6)
+
+ job.cancel()
+ }
+
+ @Test
fun wifiNetwork_notValidated_networkNotValidated() = runBlocking(IMMEDIATE) {
var latest: WifiNetworkModel? = null
val job = underTest
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/wifi/domain/interactor/WifiInteractorImplTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/wifi/domain/interactor/WifiInteractorImplTest.kt
index 01d59f9..089a170 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/wifi/domain/interactor/WifiInteractorImplTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/wifi/domain/interactor/WifiInteractorImplTest.kt
@@ -84,7 +84,9 @@
@Test
fun ssid_carrierMergedNetwork_outputsNull() = runBlocking(IMMEDIATE) {
- wifiRepository.setWifiNetwork(WifiNetworkModel.CarrierMerged)
+ wifiRepository.setWifiNetwork(
+ WifiNetworkModel.CarrierMerged(networkId = 1, subscriptionId = 2, level = 1)
+ )
var latest: String? = "default"
val job = underTest
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/wifi/ui/viewmodel/WifiViewModelIconParameterizedTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/wifi/ui/viewmodel/WifiViewModelIconParameterizedTest.kt
index 726e813..b932837 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/wifi/ui/viewmodel/WifiViewModelIconParameterizedTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/wifi/ui/viewmodel/WifiViewModelIconParameterizedTest.kt
@@ -206,7 +206,8 @@
// Enabled = false => no networks shown
TestCase(
enabled = false,
- network = WifiNetworkModel.CarrierMerged,
+ network =
+ WifiNetworkModel.CarrierMerged(NETWORK_ID, subscriptionId = 1, level = 1),
expected = null,
),
TestCase(
@@ -228,7 +229,8 @@
// forceHidden = true => no networks shown
TestCase(
forceHidden = true,
- network = WifiNetworkModel.CarrierMerged,
+ network =
+ WifiNetworkModel.CarrierMerged(NETWORK_ID, subscriptionId = 1, level = 1),
expected = null,
),
TestCase(
@@ -369,7 +371,8 @@
// network = CarrierMerged => not shown
TestCase(
- network = WifiNetworkModel.CarrierMerged,
+ network =
+ WifiNetworkModel.CarrierMerged(NETWORK_ID, subscriptionId = 1, level = 1),
expected = null,
),
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/RemoteInputViewTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/RemoteInputViewTest.java
index 4b32ee2..0cca7b2 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/RemoteInputViewTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/RemoteInputViewTest.java
@@ -390,19 +390,27 @@
bindController(view, row.getEntry());
view.setVisibility(View.GONE);
- View crossFadeView = new View(mContext);
+ View fadeOutView = new View(mContext);
+ fadeOutView.setId(com.android.internal.R.id.actions_container_layout);
+
+ FrameLayout parent = new FrameLayout(mContext);
+ parent.addView(view);
+ parent.addView(fadeOutView);
// Start focus animation
- view.focusAnimated(crossFadeView);
-
+ view.focusAnimated();
assertTrue(view.isAnimatingAppearance());
- // fast forward to end of animation
- mAnimatorTestRule.advanceTimeBy(ANIMATION_DURATION_STANDARD);
+ // fast forward to 1 ms before end of animation and verify fadeOutView has alpha set to 0f
+ mAnimatorTestRule.advanceTimeBy(ANIMATION_DURATION_STANDARD - 1);
+ assertEquals(0f, fadeOutView.getAlpha());
- // assert that crossFadeView's alpha is reset to 1f after the animation (hidden behind
+ // fast forward to end of animation
+ mAnimatorTestRule.advanceTimeBy(1);
+
+ // assert that fadeOutView's alpha is reset to 1f after the animation (hidden behind
// RemoteInputView)
- assertEquals(1f, crossFadeView.getAlpha());
+ assertEquals(1f, fadeOutView.getAlpha());
assertFalse(view.isAnimatingAppearance());
assertEquals(View.VISIBLE, view.getVisibility());
assertEquals(1f, view.getAlpha());
@@ -415,20 +423,27 @@
mDependency,
TestableLooper.get(this));
ExpandableNotificationRow row = helper.createRow();
- FrameLayout remoteInputViewParent = new FrameLayout(mContext);
RemoteInputView view = RemoteInputView.inflate(mContext, null, row.getEntry(), mController);
- remoteInputViewParent.addView(view);
bindController(view, row.getEntry());
+ View fadeInView = new View(mContext);
+ fadeInView.setId(com.android.internal.R.id.actions_container_layout);
+
+ FrameLayout parent = new FrameLayout(mContext);
+ parent.addView(view);
+ parent.addView(fadeInView);
+
// Start defocus animation
- view.onDefocus(true, false);
+ view.onDefocus(true /* animate */, false /* logClose */, null /* doAfterDefocus */);
assertEquals(View.VISIBLE, view.getVisibility());
+ assertEquals(0f, fadeInView.getAlpha());
// fast forward to end of animation
mAnimatorTestRule.advanceTimeBy(ANIMATION_DURATION_STANDARD);
// assert that RemoteInputView is no longer visible
assertEquals(View.GONE, view.getVisibility());
+ assertEquals(1f, fadeInView.getAlpha());
}
// NOTE: because we're refactoring the RemoteInputView and moving logic into the
diff --git a/packages/SystemUI/tests/src/com/android/systemui/stylus/FixedCapacityBatteryState.kt b/packages/SystemUI/tests/src/com/android/systemui/stylus/FixedCapacityBatteryState.kt
new file mode 100644
index 0000000..7e01088
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/stylus/FixedCapacityBatteryState.kt
@@ -0,0 +1,25 @@
+/*
+ * 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 com.android.systemui.stylus
+
+import android.hardware.BatteryState
+
+class FixedCapacityBatteryState(private val capacity: Float) : BatteryState() {
+ override fun getCapacity() = capacity
+ override fun getStatus() = 0
+ override fun isPresent() = true
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/stylus/StylusFirstUsageListenerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/stylus/StylusFirstUsageListenerTest.kt
deleted file mode 100644
index 8dd088f..0000000
--- a/packages/SystemUI/tests/src/com/android/systemui/stylus/StylusFirstUsageListenerTest.kt
+++ /dev/null
@@ -1,289 +0,0 @@
-/*
- * 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 com.android.systemui.stylus
-
-import android.content.Context
-import android.hardware.BatteryState
-import android.hardware.input.InputManager
-import android.os.Handler
-import android.testing.AndroidTestingRunner
-import android.view.InputDevice
-import androidx.test.filters.SmallTest
-import com.android.systemui.SysuiTestCase
-import com.android.systemui.flags.FeatureFlags
-import com.android.systemui.flags.Flags
-import com.android.systemui.util.concurrency.FakeExecutor
-import com.android.systemui.util.mockito.any
-import com.android.systemui.util.mockito.whenever
-import com.android.systemui.util.time.FakeSystemClock
-import org.junit.Before
-import org.junit.Ignore
-import org.junit.Test
-import org.junit.runner.RunWith
-import org.mockito.Mock
-import org.mockito.Mockito.never
-import org.mockito.Mockito.times
-import org.mockito.Mockito.verify
-import org.mockito.Mockito.verifyNoMoreInteractions
-import org.mockito.Mockito.verifyZeroInteractions
-import org.mockito.MockitoAnnotations
-
-@RunWith(AndroidTestingRunner::class)
-@SmallTest
-@Ignore("TODO(b/20579491): unignore on main")
-class StylusFirstUsageListenerTest : SysuiTestCase() {
- @Mock lateinit var context: Context
- @Mock lateinit var inputManager: InputManager
- @Mock lateinit var stylusManager: StylusManager
- @Mock lateinit var featureFlags: FeatureFlags
- @Mock lateinit var internalStylusDevice: InputDevice
- @Mock lateinit var otherDevice: InputDevice
- @Mock lateinit var externalStylusDevice: InputDevice
- @Mock lateinit var batteryState: BatteryState
- @Mock lateinit var handler: Handler
-
- private lateinit var stylusListener: StylusFirstUsageListener
-
- @Before
- fun setUp() {
- MockitoAnnotations.initMocks(this)
- whenever(featureFlags.isEnabled(Flags.TRACK_STYLUS_EVER_USED)).thenReturn(true)
- whenever(inputManager.isStylusEverUsed(context)).thenReturn(false)
-
- stylusListener =
- StylusFirstUsageListener(
- context,
- inputManager,
- stylusManager,
- featureFlags,
- EXECUTOR,
- handler
- )
- stylusListener.hasStarted = false
-
- whenever(handler.post(any())).thenAnswer {
- (it.arguments[0] as Runnable).run()
- true
- }
-
- whenever(otherDevice.supportsSource(InputDevice.SOURCE_STYLUS)).thenReturn(false)
- whenever(internalStylusDevice.supportsSource(InputDevice.SOURCE_STYLUS)).thenReturn(true)
- whenever(internalStylusDevice.isExternal).thenReturn(false)
- whenever(externalStylusDevice.supportsSource(InputDevice.SOURCE_STYLUS)).thenReturn(true)
- whenever(externalStylusDevice.isExternal).thenReturn(true)
-
- whenever(inputManager.inputDeviceIds).thenReturn(intArrayOf())
- whenever(inputManager.getInputDevice(OTHER_DEVICE_ID)).thenReturn(otherDevice)
- whenever(inputManager.getInputDevice(INTERNAL_STYLUS_DEVICE_ID))
- .thenReturn(internalStylusDevice)
- whenever(inputManager.getInputDevice(EXTERNAL_STYLUS_DEVICE_ID))
- .thenReturn(externalStylusDevice)
- }
-
- @Test
- fun start_flagDisabled_doesNotRegister() {
- whenever(featureFlags.isEnabled(Flags.TRACK_STYLUS_EVER_USED)).thenReturn(false)
-
- stylusListener.start()
-
- verify(stylusManager, never()).registerCallback(any())
- verify(inputManager, never()).setStylusEverUsed(context, true)
- }
-
- @Test
- fun start_toggleHasStarted() {
- stylusListener.start()
-
- assert(stylusListener.hasStarted)
- }
-
- @Test
- fun start_hasStarted_doesNotRegister() {
- stylusListener.hasStarted = true
-
- stylusListener.start()
-
- verify(stylusManager, never()).registerCallback(any())
- }
-
- @Test
- fun start_hostDeviceDoesNotSupportStylus_doesNotRegister() {
- whenever(inputManager.inputDeviceIds).thenReturn(intArrayOf(OTHER_DEVICE_ID))
-
- stylusListener.start()
-
- verify(stylusManager, never()).registerCallback(any())
- verify(inputManager, never()).setStylusEverUsed(context, true)
- }
-
- @Test
- fun start_stylusEverUsed_doesNotRegister() {
- whenever(inputManager.inputDeviceIds)
- .thenReturn(intArrayOf(OTHER_DEVICE_ID, INTERNAL_STYLUS_DEVICE_ID))
- whenever(inputManager.isStylusEverUsed(context)).thenReturn(true)
-
- stylusListener.start()
-
- verify(stylusManager, never()).registerCallback(any())
- verify(inputManager, never()).setStylusEverUsed(context, true)
- }
-
- @Test
- fun start_hostDeviceSupportsStylus_registersListener() {
- whenever(inputManager.inputDeviceIds)
- .thenReturn(intArrayOf(OTHER_DEVICE_ID, INTERNAL_STYLUS_DEVICE_ID))
-
- stylusListener.start()
-
- verify(stylusManager).registerCallback(any())
- verify(inputManager, never()).setStylusEverUsed(context, true)
- }
-
- @Test
- fun onStylusAdded_hasNotStarted_doesNotRegisterListener() {
- stylusListener.hasStarted = false
-
- stylusListener.onStylusAdded(INTERNAL_STYLUS_DEVICE_ID)
-
- verifyZeroInteractions(inputManager)
- }
-
- @Test
- fun onStylusAdded_internalStylus_registersListener() {
- stylusListener.hasStarted = true
-
- stylusListener.onStylusAdded(INTERNAL_STYLUS_DEVICE_ID)
-
- verify(inputManager, times(1))
- .addInputDeviceBatteryListener(INTERNAL_STYLUS_DEVICE_ID, EXECUTOR, stylusListener)
- }
-
- @Test
- fun onStylusAdded_externalStylus_doesNotRegisterListener() {
- stylusListener.hasStarted = true
-
- stylusListener.onStylusAdded(EXTERNAL_STYLUS_DEVICE_ID)
-
- verify(inputManager, never()).addInputDeviceBatteryListener(any(), any(), any())
- }
-
- @Test
- fun onStylusAdded_otherDevice_doesNotRegisterListener() {
- stylusListener.onStylusAdded(OTHER_DEVICE_ID)
-
- verify(inputManager, never()).addInputDeviceBatteryListener(any(), any(), any())
- }
-
- @Test
- fun onStylusRemoved_registeredDevice_unregistersListener() {
- stylusListener.hasStarted = true
- stylusListener.onStylusAdded(INTERNAL_STYLUS_DEVICE_ID)
-
- stylusListener.onStylusRemoved(INTERNAL_STYLUS_DEVICE_ID)
-
- verify(inputManager, times(1))
- .removeInputDeviceBatteryListener(INTERNAL_STYLUS_DEVICE_ID, stylusListener)
- }
-
- @Test
- fun onStylusRemoved_hasNotStarted_doesNotUnregisterListener() {
- stylusListener.hasStarted = false
- stylusListener.onStylusAdded(INTERNAL_STYLUS_DEVICE_ID)
-
- stylusListener.onStylusRemoved(INTERNAL_STYLUS_DEVICE_ID)
-
- verifyZeroInteractions(inputManager)
- }
-
- @Test
- fun onStylusRemoved_unregisteredDevice_doesNotUnregisterListener() {
- stylusListener.hasStarted = true
-
- stylusListener.onStylusRemoved(INTERNAL_STYLUS_DEVICE_ID)
-
- verifyNoMoreInteractions(inputManager)
- }
-
- @Test
- fun onStylusBluetoothConnected_updateStylusFlagAndUnregisters() {
- stylusListener.hasStarted = true
- stylusListener.onStylusAdded(INTERNAL_STYLUS_DEVICE_ID)
-
- stylusListener.onStylusBluetoothConnected(EXTERNAL_STYLUS_DEVICE_ID, "ANY")
-
- verify(inputManager).setStylusEverUsed(context, true)
- verify(inputManager, times(1))
- .removeInputDeviceBatteryListener(INTERNAL_STYLUS_DEVICE_ID, stylusListener)
- verify(stylusManager).unregisterCallback(stylusListener)
- }
-
- @Test
- fun onStylusBluetoothConnected_hasNotStarted_doesNoting() {
- stylusListener.hasStarted = false
- stylusListener.onStylusAdded(INTERNAL_STYLUS_DEVICE_ID)
-
- stylusListener.onStylusBluetoothConnected(EXTERNAL_STYLUS_DEVICE_ID, "ANY")
-
- verifyZeroInteractions(inputManager)
- verifyZeroInteractions(stylusManager)
- }
-
- @Test
- fun onBatteryStateChanged_batteryPresent_updateStylusFlagAndUnregisters() {
- stylusListener.hasStarted = true
- stylusListener.onStylusAdded(INTERNAL_STYLUS_DEVICE_ID)
- whenever(batteryState.isPresent).thenReturn(true)
-
- stylusListener.onBatteryStateChanged(0, 1, batteryState)
-
- verify(inputManager).setStylusEverUsed(context, true)
- verify(inputManager, times(1))
- .removeInputDeviceBatteryListener(INTERNAL_STYLUS_DEVICE_ID, stylusListener)
- verify(stylusManager).unregisterCallback(stylusListener)
- }
-
- @Test
- fun onBatteryStateChanged_batteryNotPresent_doesNotUpdateFlagOrUnregister() {
- stylusListener.hasStarted = true
- stylusListener.onStylusAdded(INTERNAL_STYLUS_DEVICE_ID)
- whenever(batteryState.isPresent).thenReturn(false)
-
- stylusListener.onBatteryStateChanged(0, 1, batteryState)
-
- verifyZeroInteractions(stylusManager)
- verify(inputManager, never())
- .removeInputDeviceBatteryListener(INTERNAL_STYLUS_DEVICE_ID, stylusListener)
- }
-
- @Test
- fun onBatteryStateChanged_hasNotStarted_doesNothing() {
- stylusListener.hasStarted = false
- stylusListener.onStylusAdded(INTERNAL_STYLUS_DEVICE_ID)
- whenever(batteryState.isPresent).thenReturn(false)
-
- stylusListener.onBatteryStateChanged(0, 1, batteryState)
-
- verifyZeroInteractions(inputManager)
- verifyZeroInteractions(stylusManager)
- }
-
- companion object {
- private const val OTHER_DEVICE_ID = 0
- private const val INTERNAL_STYLUS_DEVICE_ID = 1
- private const val EXTERNAL_STYLUS_DEVICE_ID = 2
- private val EXECUTOR = FakeExecutor(FakeSystemClock())
- }
-}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/stylus/StylusManagerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/stylus/StylusManagerTest.kt
index 984de5b..a08e002 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/stylus/StylusManagerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/stylus/StylusManagerTest.kt
@@ -17,44 +17,43 @@
import android.bluetooth.BluetoothAdapter
import android.bluetooth.BluetoothDevice
+import android.hardware.BatteryState
import android.hardware.input.InputManager
import android.os.Handler
import android.testing.AndroidTestingRunner
import android.view.InputDevice
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
+import com.android.systemui.flags.FeatureFlags
+import com.android.systemui.flags.Flags
import com.android.systemui.util.mockito.any
import com.android.systemui.util.mockito.whenever
import java.util.concurrent.Executor
import org.junit.Before
-import org.junit.Ignore
import org.junit.Test
import org.junit.runner.RunWith
import org.mockito.Mock
+import org.mockito.Mockito.clearInvocations
import org.mockito.Mockito.inOrder
import org.mockito.Mockito.never
import org.mockito.Mockito.times
import org.mockito.Mockito.verify
import org.mockito.Mockito.verifyNoMoreInteractions
+import org.mockito.Mockito.verifyZeroInteractions
import org.mockito.MockitoAnnotations
@RunWith(AndroidTestingRunner::class)
@SmallTest
-@Ignore("b/257936830 until bt APIs")
class StylusManagerTest : SysuiTestCase() {
@Mock lateinit var inputManager: InputManager
-
@Mock lateinit var stylusDevice: InputDevice
-
@Mock lateinit var btStylusDevice: InputDevice
-
@Mock lateinit var otherDevice: InputDevice
-
+ @Mock lateinit var batteryState: BatteryState
@Mock lateinit var bluetoothAdapter: BluetoothAdapter
-
@Mock lateinit var bluetoothDevice: BluetoothDevice
-
@Mock lateinit var handler: Handler
+ @Mock lateinit var featureFlags: FeatureFlags
@Mock lateinit var stylusCallback: StylusManager.StylusCallback
@@ -75,36 +74,61 @@
true
}
- stylusManager = StylusManager(inputManager, bluetoothAdapter, handler, EXECUTOR)
-
- stylusManager.registerCallback(stylusCallback)
-
- stylusManager.registerBatteryCallback(stylusBatteryCallback)
+ stylusManager =
+ StylusManager(mContext, inputManager, bluetoothAdapter, handler, EXECUTOR, featureFlags)
whenever(otherDevice.supportsSource(InputDevice.SOURCE_STYLUS)).thenReturn(false)
whenever(stylusDevice.supportsSource(InputDevice.SOURCE_STYLUS)).thenReturn(true)
whenever(btStylusDevice.supportsSource(InputDevice.SOURCE_STYLUS)).thenReturn(true)
- // whenever(stylusDevice.bluetoothAddress).thenReturn(null)
- // whenever(btStylusDevice.bluetoothAddress).thenReturn(STYLUS_BT_ADDRESS)
+ whenever(stylusDevice.bluetoothAddress).thenReturn(null)
+ whenever(btStylusDevice.bluetoothAddress).thenReturn(STYLUS_BT_ADDRESS)
whenever(inputManager.getInputDevice(OTHER_DEVICE_ID)).thenReturn(otherDevice)
whenever(inputManager.getInputDevice(STYLUS_DEVICE_ID)).thenReturn(stylusDevice)
whenever(inputManager.getInputDevice(BT_STYLUS_DEVICE_ID)).thenReturn(btStylusDevice)
whenever(inputManager.inputDeviceIds).thenReturn(intArrayOf(STYLUS_DEVICE_ID))
+ whenever(inputManager.isStylusEverUsed(mContext)).thenReturn(false)
whenever(bluetoothAdapter.getRemoteDevice(STYLUS_BT_ADDRESS)).thenReturn(bluetoothDevice)
whenever(bluetoothDevice.address).thenReturn(STYLUS_BT_ADDRESS)
+
+ whenever(featureFlags.isEnabled(Flags.TRACK_STYLUS_EVER_USED)).thenReturn(true)
+
+ stylusManager.startListener()
+ stylusManager.registerCallback(stylusCallback)
+ stylusManager.registerBatteryCallback(stylusBatteryCallback)
+ clearInvocations(inputManager)
}
@Test
- fun startListener_registersInputDeviceListener() {
+ fun startListener_hasNotStarted_registersInputDeviceListener() {
+ stylusManager =
+ StylusManager(mContext, inputManager, bluetoothAdapter, handler, EXECUTOR, featureFlags)
+
stylusManager.startListener()
verify(inputManager, times(1)).registerInputDeviceListener(any(), any())
}
@Test
+ fun startListener_hasStarted_doesNothing() {
+ stylusManager.startListener()
+
+ verifyZeroInteractions(inputManager)
+ }
+
+ @Test
+ fun onInputDeviceAdded_hasNotStarted_doesNothing() {
+ stylusManager =
+ StylusManager(mContext, inputManager, bluetoothAdapter, handler, EXECUTOR, featureFlags)
+
+ stylusManager.onInputDeviceAdded(STYLUS_DEVICE_ID)
+
+ verifyZeroInteractions(stylusCallback)
+ }
+
+ @Test
fun onInputDeviceAdded_multipleRegisteredCallbacks_callsAll() {
stylusManager.registerCallback(otherStylusCallback)
@@ -117,6 +141,26 @@
}
@Test
+ fun onInputDeviceAdded_internalStylus_registersBatteryListener() {
+ whenever(stylusDevice.isExternal).thenReturn(false)
+
+ stylusManager.onInputDeviceAdded(STYLUS_DEVICE_ID)
+
+ verify(inputManager, times(1))
+ .addInputDeviceBatteryListener(STYLUS_DEVICE_ID, EXECUTOR, stylusManager)
+ }
+
+ @Test
+ fun onInputDeviceAdded_externalStylus_doesNotRegisterbatteryListener() {
+ whenever(stylusDevice.isExternal).thenReturn(true)
+
+ stylusManager.onInputDeviceAdded(STYLUS_DEVICE_ID)
+
+ verify(inputManager, never())
+ .addInputDeviceBatteryListener(STYLUS_DEVICE_ID, EXECUTOR, stylusManager)
+ }
+
+ @Test
fun onInputDeviceAdded_stylus_callsCallbacksOnStylusAdded() {
stylusManager.onInputDeviceAdded(STYLUS_DEVICE_ID)
@@ -125,6 +169,20 @@
}
@Test
+ fun onInputDeviceAdded_btStylus_firstUsed_callsCallbacksOnStylusFirstUsed() {
+ stylusManager.onInputDeviceAdded(BT_STYLUS_DEVICE_ID)
+
+ verify(stylusCallback, times(1)).onStylusFirstUsed()
+ }
+
+ @Test
+ fun onInputDeviceAdded_btStylus_firstUsed_setsFlag() {
+ stylusManager.onInputDeviceAdded(BT_STYLUS_DEVICE_ID)
+
+ verify(inputManager, times(1)).setStylusEverUsed(mContext, true)
+ }
+
+ @Test
fun onInputDeviceAdded_btStylus_callsCallbacksWithAddress() {
stylusManager.onInputDeviceAdded(BT_STYLUS_DEVICE_ID)
@@ -143,9 +201,19 @@
}
@Test
+ fun onInputDeviceChanged_hasNotStarted_doesNothing() {
+ stylusManager =
+ StylusManager(mContext, inputManager, bluetoothAdapter, handler, EXECUTOR, featureFlags)
+
+ stylusManager.onInputDeviceChanged(STYLUS_DEVICE_ID)
+
+ verifyZeroInteractions(stylusCallback)
+ }
+
+ @Test
fun onInputDeviceChanged_multipleRegisteredCallbacks_callsAll() {
stylusManager.onInputDeviceAdded(STYLUS_DEVICE_ID)
- // whenever(stylusDevice.bluetoothAddress).thenReturn(STYLUS_BT_ADDRESS)
+ whenever(stylusDevice.bluetoothAddress).thenReturn(STYLUS_BT_ADDRESS)
stylusManager.registerCallback(otherStylusCallback)
stylusManager.onInputDeviceChanged(STYLUS_DEVICE_ID)
@@ -159,7 +227,7 @@
@Test
fun onInputDeviceChanged_stylusNewBtConnection_callsCallbacks() {
stylusManager.onInputDeviceAdded(STYLUS_DEVICE_ID)
- // whenever(stylusDevice.bluetoothAddress).thenReturn(STYLUS_BT_ADDRESS)
+ whenever(stylusDevice.bluetoothAddress).thenReturn(STYLUS_BT_ADDRESS)
stylusManager.onInputDeviceChanged(STYLUS_DEVICE_ID)
@@ -170,7 +238,7 @@
@Test
fun onInputDeviceChanged_stylusLostBtConnection_callsCallbacks() {
stylusManager.onInputDeviceAdded(BT_STYLUS_DEVICE_ID)
- // whenever(btStylusDevice.bluetoothAddress).thenReturn(null)
+ whenever(btStylusDevice.bluetoothAddress).thenReturn(null)
stylusManager.onInputDeviceChanged(BT_STYLUS_DEVICE_ID)
@@ -198,6 +266,17 @@
}
@Test
+ fun onInputDeviceRemoved_hasNotStarted_doesNothing() {
+ stylusManager =
+ StylusManager(mContext, inputManager, bluetoothAdapter, handler, EXECUTOR, featureFlags)
+ stylusManager.onInputDeviceAdded(STYLUS_DEVICE_ID)
+
+ stylusManager.onInputDeviceRemoved(STYLUS_DEVICE_ID)
+
+ verifyZeroInteractions(stylusCallback)
+ }
+
+ @Test
fun onInputDeviceRemoved_multipleRegisteredCallbacks_callsAll() {
stylusManager.onInputDeviceAdded(STYLUS_DEVICE_ID)
stylusManager.registerCallback(otherStylusCallback)
@@ -219,6 +298,16 @@
}
@Test
+ fun onInputDeviceRemoved_unregistersBatteryListener() {
+ stylusManager.onInputDeviceAdded(STYLUS_DEVICE_ID)
+
+ stylusManager.onInputDeviceRemoved(STYLUS_DEVICE_ID)
+
+ verify(inputManager, times(1))
+ .removeInputDeviceBatteryListener(STYLUS_DEVICE_ID, stylusManager)
+ }
+
+ @Test
fun onInputDeviceRemoved_btStylus_callsCallbacks() {
stylusManager.onInputDeviceAdded(BT_STYLUS_DEVICE_ID)
@@ -326,6 +415,59 @@
.onStylusBluetoothChargingStateChanged(any(), any(), any())
}
+ @Test
+ fun onBatteryStateChanged_batteryPresent_stylusNeverUsed_updateEverUsedFlag() {
+ whenever(batteryState.isPresent).thenReturn(true)
+
+ stylusManager.onBatteryStateChanged(STYLUS_DEVICE_ID, 1, batteryState)
+
+ verify(inputManager).setStylusEverUsed(mContext, true)
+ }
+
+ @Test
+ fun onBatteryStateChanged_batteryPresent_stylusNeverUsed_executesStylusFirstUsed() {
+ whenever(batteryState.isPresent).thenReturn(true)
+
+ stylusManager.onBatteryStateChanged(STYLUS_DEVICE_ID, 1, batteryState)
+
+ verify(stylusCallback, times(1)).onStylusFirstUsed()
+ }
+
+ @Test
+ fun onBatteryStateChanged_batteryPresent_stylusUsed_doesNotUpdateEverUsedFlag() {
+ whenever(inputManager.isStylusEverUsed(mContext)).thenReturn(true)
+ whenever(batteryState.isPresent).thenReturn(true)
+
+ stylusManager.onBatteryStateChanged(STYLUS_DEVICE_ID, 1, batteryState)
+
+ verify(inputManager, never()).setStylusEverUsed(mContext, true)
+ }
+
+ @Test
+ fun onBatteryStateChanged_batteryNotPresent_doesNotUpdateEverUsedFlag() {
+ whenever(batteryState.isPresent).thenReturn(false)
+
+ stylusManager.onBatteryStateChanged(STYLUS_DEVICE_ID, 1, batteryState)
+
+ verify(inputManager, never())
+ .removeInputDeviceBatteryListener(STYLUS_DEVICE_ID, stylusManager)
+ }
+
+ @Test
+ fun onBatteryStateChanged_hasNotStarted_doesNothing() {
+ stylusManager.onBatteryStateChanged(STYLUS_DEVICE_ID, 1, batteryState)
+
+ verifyZeroInteractions(inputManager)
+ }
+
+ @Test
+ fun onBatteryStateChanged_executesBatteryCallbacks() {
+ stylusManager.onBatteryStateChanged(STYLUS_DEVICE_ID, 1, batteryState)
+
+ verify(stylusBatteryCallback, times(1))
+ .onStylusUsiBatteryStateChanged(STYLUS_DEVICE_ID, 1, batteryState)
+ }
+
companion object {
private val EXECUTOR = Executor { r -> r.run() }
diff --git a/packages/SystemUI/tests/src/com/android/systemui/stylus/StylusUsiPowerStartableTest.kt b/packages/SystemUI/tests/src/com/android/systemui/stylus/StylusUsiPowerStartableTest.kt
index ff382a3..1cccd65c8 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/stylus/StylusUsiPowerStartableTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/stylus/StylusUsiPowerStartableTest.kt
@@ -25,17 +25,15 @@
import com.android.systemui.flags.FeatureFlags
import com.android.systemui.flags.Flags
import com.android.systemui.util.mockito.whenever
-import java.util.concurrent.Executor
import org.junit.Before
import org.junit.Test
import org.junit.runner.RunWith
import org.mockito.Mock
-import org.mockito.Mockito.inOrder
import org.mockito.Mockito.mock
-import org.mockito.Mockito.never
import org.mockito.Mockito.times
import org.mockito.Mockito.verify
import org.mockito.Mockito.verifyNoMoreInteractions
+import org.mockito.Mockito.verifyZeroInteractions
import org.mockito.MockitoAnnotations
@RunWith(AndroidTestingRunner::class)
@@ -60,7 +58,6 @@
inputManager,
stylusUsiPowerUi,
featureFlags,
- DIRECT_EXECUTOR,
)
whenever(featureFlags.isEnabled(Flags.ENABLE_USI_BATTERY_NOTIFICATIONS)).thenReturn(true)
@@ -79,40 +76,19 @@
}
@Test
- fun start_addsBatteryListenerForInternalStylus() {
+ fun start_hostDeviceDoesNotSupportStylus_doesNotRegister() {
+ whenever(inputManager.inputDeviceIds).thenReturn(intArrayOf(EXTERNAL_DEVICE_ID))
+
startable.start()
- verify(inputManager, times(1))
- .addInputDeviceBatteryListener(STYLUS_DEVICE_ID, DIRECT_EXECUTOR, startable)
+ verifyZeroInteractions(stylusManager)
}
@Test
- fun onStylusAdded_internalStylus_addsBatteryListener() {
- startable.onStylusAdded(STYLUS_DEVICE_ID)
+ fun start_initStylusUsiPowerUi() {
+ startable.start()
- verify(inputManager, times(1))
- .addInputDeviceBatteryListener(STYLUS_DEVICE_ID, DIRECT_EXECUTOR, startable)
- }
-
- @Test
- fun onStylusAdded_externalStylus_doesNotAddBatteryListener() {
- startable.onStylusAdded(EXTERNAL_DEVICE_ID)
-
- verify(inputManager, never())
- .addInputDeviceBatteryListener(EXTERNAL_DEVICE_ID, DIRECT_EXECUTOR, startable)
- }
-
- @Test
- fun onStylusRemoved_registeredStylus_removesBatteryListener() {
- startable.onStylusAdded(STYLUS_DEVICE_ID)
- startable.onStylusRemoved(STYLUS_DEVICE_ID)
-
- inOrder(inputManager).let {
- it.verify(inputManager, times(1))
- .addInputDeviceBatteryListener(STYLUS_DEVICE_ID, DIRECT_EXECUTOR, startable)
- it.verify(inputManager, times(1))
- .removeInputDeviceBatteryListener(STYLUS_DEVICE_ID, startable)
- }
+ verify(stylusUsiPowerUi, times(1)).init()
}
@Test
@@ -130,28 +106,34 @@
}
@Test
- fun onBatteryStateChanged_batteryPresent_refreshesNotification() {
- val batteryState = mock(BatteryState::class.java)
- whenever(batteryState.isPresent).thenReturn(true)
+ fun onStylusUsiBatteryStateChanged_batteryPresentValidCapacity_refreshesNotification() {
+ val batteryState = FixedCapacityBatteryState(0.1f)
- startable.onBatteryStateChanged(STYLUS_DEVICE_ID, 123, batteryState)
+ startable.onStylusUsiBatteryStateChanged(STYLUS_DEVICE_ID, 123, batteryState)
- verify(stylusUsiPowerUi, times(1)).updateBatteryState(batteryState)
+ verify(stylusUsiPowerUi, times(1)).updateBatteryState(STYLUS_DEVICE_ID, batteryState)
}
@Test
- fun onBatteryStateChanged_batteryNotPresent_noop() {
+ fun onStylusUsiBatteryStateChanged_batteryPresentInvalidCapacity_noop() {
+ val batteryState = FixedCapacityBatteryState(0f)
+
+ startable.onStylusUsiBatteryStateChanged(STYLUS_DEVICE_ID, 123, batteryState)
+
+ verifyNoMoreInteractions(stylusUsiPowerUi)
+ }
+
+ @Test
+ fun onStylusUsiBatteryStateChanged_batteryNotPresent_noop() {
val batteryState = mock(BatteryState::class.java)
whenever(batteryState.isPresent).thenReturn(false)
- startable.onBatteryStateChanged(STYLUS_DEVICE_ID, 123, batteryState)
+ startable.onStylusUsiBatteryStateChanged(STYLUS_DEVICE_ID, 123, batteryState)
verifyNoMoreInteractions(stylusUsiPowerUi)
}
companion object {
- private val DIRECT_EXECUTOR = Executor { r -> r.run() }
-
private const val EXTERNAL_DEVICE_ID = 0
private const val STYLUS_DEVICE_ID = 1
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/stylus/StylusUsiPowerUiTest.kt b/packages/SystemUI/tests/src/com/android/systemui/stylus/StylusUsiPowerUiTest.kt
index 5987550..1e81dc7 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/stylus/StylusUsiPowerUiTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/stylus/StylusUsiPowerUiTest.kt
@@ -16,8 +16,12 @@
package com.android.systemui.stylus
-import android.hardware.BatteryState
+import android.app.Notification
+import android.content.BroadcastReceiver
+import android.content.Context
+import android.content.Intent
import android.hardware.input.InputManager
+import android.os.Bundle
import android.os.Handler
import android.testing.AndroidTestingRunner
import android.view.InputDevice
@@ -26,14 +30,22 @@
import com.android.systemui.R
import com.android.systemui.SysuiTestCase
import com.android.systemui.util.mockito.any
+import com.android.systemui.util.mockito.argumentCaptor
import com.android.systemui.util.mockito.eq
import com.android.systemui.util.mockito.whenever
+import com.google.common.truth.Truth.assertThat
+import junit.framework.Assert.assertEquals
import org.junit.Before
import org.junit.Ignore
import org.junit.Test
import org.junit.runner.RunWith
+import org.mockito.ArgumentCaptor
+import org.mockito.Captor
import org.mockito.Mock
+import org.mockito.Mockito.doNothing
import org.mockito.Mockito.inOrder
+import org.mockito.Mockito.never
+import org.mockito.Mockito.spy
import org.mockito.Mockito.times
import org.mockito.Mockito.verify
import org.mockito.Mockito.verifyNoMoreInteractions
@@ -46,13 +58,19 @@
@Mock lateinit var inputManager: InputManager
@Mock lateinit var handler: Handler
@Mock lateinit var btStylusDevice: InputDevice
+ @Captor lateinit var notificationCaptor: ArgumentCaptor<Notification>
private lateinit var stylusUsiPowerUi: StylusUsiPowerUI
+ private lateinit var broadcastReceiver: BroadcastReceiver
+ private lateinit var contextSpy: Context
@Before
fun setUp() {
MockitoAnnotations.initMocks(this)
+ contextSpy = spy(mContext)
+ doNothing().whenever(contextSpy).startActivity(any())
+
whenever(handler.post(any())).thenAnswer {
(it.arguments[0] as Runnable).run()
true
@@ -63,56 +81,77 @@
whenever(btStylusDevice.supportsSource(InputDevice.SOURCE_STYLUS)).thenReturn(true)
// whenever(btStylusDevice.bluetoothAddress).thenReturn("SO:ME:AD:DR:ES")
- stylusUsiPowerUi = StylusUsiPowerUI(mContext, notificationManager, inputManager, handler)
+ stylusUsiPowerUi = StylusUsiPowerUI(contextSpy, notificationManager, inputManager, handler)
+ broadcastReceiver = stylusUsiPowerUi.receiver
+ }
+
+ @Test
+ fun updateBatteryState_capacityZero_noop() {
+ stylusUsiPowerUi.updateBatteryState(0, FixedCapacityBatteryState(0f))
+
+ verifyNoMoreInteractions(notificationManager)
}
@Test
fun updateBatteryState_capacityBelowThreshold_notifies() {
- stylusUsiPowerUi.updateBatteryState(FixedCapacityBatteryState(0.1f))
+ stylusUsiPowerUi.updateBatteryState(0, FixedCapacityBatteryState(0.1f))
- verify(notificationManager, times(1)).notify(eq(R.string.stylus_battery_low), any())
+ verify(notificationManager, times(1))
+ .notify(eq(R.string.stylus_battery_low_percentage), any())
verifyNoMoreInteractions(notificationManager)
}
@Test
fun updateBatteryState_capacityAboveThreshold_cancelsNotificattion() {
- stylusUsiPowerUi.updateBatteryState(FixedCapacityBatteryState(0.8f))
+ stylusUsiPowerUi.updateBatteryState(0, FixedCapacityBatteryState(0.8f))
- verify(notificationManager, times(1)).cancel(R.string.stylus_battery_low)
+ verify(notificationManager, times(1)).cancel(R.string.stylus_battery_low_percentage)
verifyNoMoreInteractions(notificationManager)
}
@Test
fun updateBatteryState_existingNotification_capacityAboveThreshold_cancelsNotification() {
- stylusUsiPowerUi.updateBatteryState(FixedCapacityBatteryState(0.1f))
- stylusUsiPowerUi.updateBatteryState(FixedCapacityBatteryState(0.8f))
+ stylusUsiPowerUi.updateBatteryState(0, FixedCapacityBatteryState(0.1f))
+ stylusUsiPowerUi.updateBatteryState(0, FixedCapacityBatteryState(0.8f))
inOrder(notificationManager).let {
- it.verify(notificationManager, times(1)).notify(eq(R.string.stylus_battery_low), any())
- it.verify(notificationManager, times(1)).cancel(R.string.stylus_battery_low)
+ it.verify(notificationManager, times(1))
+ .notify(eq(R.string.stylus_battery_low_percentage), any())
+ it.verify(notificationManager, times(1)).cancel(R.string.stylus_battery_low_percentage)
it.verifyNoMoreInteractions()
}
}
@Test
fun updateBatteryState_existingNotification_capacityBelowThreshold_updatesNotification() {
- stylusUsiPowerUi.updateBatteryState(FixedCapacityBatteryState(0.1f))
- stylusUsiPowerUi.updateBatteryState(FixedCapacityBatteryState(0.15f))
+ stylusUsiPowerUi.updateBatteryState(0, FixedCapacityBatteryState(0.1f))
+ stylusUsiPowerUi.updateBatteryState(0, FixedCapacityBatteryState(0.15f))
- verify(notificationManager, times(2)).notify(eq(R.string.stylus_battery_low), any())
+ verify(notificationManager, times(2))
+ .notify(eq(R.string.stylus_battery_low_percentage), notificationCaptor.capture())
+ assertEquals(
+ notificationCaptor.value.extras.getString(Notification.EXTRA_TITLE),
+ context.getString(R.string.stylus_battery_low_percentage, "15%")
+ )
+ assertEquals(
+ notificationCaptor.value.extras.getString(Notification.EXTRA_TEXT),
+ context.getString(R.string.stylus_battery_low_subtitle)
+ )
verifyNoMoreInteractions(notificationManager)
}
@Test
fun updateBatteryState_capacityAboveThenBelowThreshold_hidesThenShowsNotification() {
- stylusUsiPowerUi.updateBatteryState(FixedCapacityBatteryState(0.1f))
- stylusUsiPowerUi.updateBatteryState(FixedCapacityBatteryState(0.5f))
- stylusUsiPowerUi.updateBatteryState(FixedCapacityBatteryState(0.1f))
+ stylusUsiPowerUi.updateBatteryState(0, FixedCapacityBatteryState(0.1f))
+ stylusUsiPowerUi.updateBatteryState(0, FixedCapacityBatteryState(0.5f))
+ stylusUsiPowerUi.updateBatteryState(0, FixedCapacityBatteryState(0.1f))
inOrder(notificationManager).let {
- it.verify(notificationManager, times(1)).notify(eq(R.string.stylus_battery_low), any())
- it.verify(notificationManager, times(1)).cancel(R.string.stylus_battery_low)
- it.verify(notificationManager, times(1)).notify(eq(R.string.stylus_battery_low), any())
+ it.verify(notificationManager, times(1))
+ .notify(eq(R.string.stylus_battery_low_percentage), any())
+ it.verify(notificationManager, times(1)).cancel(R.string.stylus_battery_low_percentage)
+ it.verify(notificationManager, times(1))
+ .notify(eq(R.string.stylus_battery_low_percentage), any())
it.verifyNoMoreInteractions()
}
}
@@ -121,47 +160,66 @@
fun updateSuppression_noExistingNotification_cancelsNotification() {
stylusUsiPowerUi.updateSuppression(true)
- verify(notificationManager, times(1)).cancel(R.string.stylus_battery_low)
+ verify(notificationManager, times(1)).cancel(R.string.stylus_battery_low_percentage)
verifyNoMoreInteractions(notificationManager)
}
@Test
fun updateSuppression_existingNotification_cancelsNotification() {
- stylusUsiPowerUi.updateBatteryState(FixedCapacityBatteryState(0.1f))
+ stylusUsiPowerUi.updateBatteryState(0, FixedCapacityBatteryState(0.1f))
stylusUsiPowerUi.updateSuppression(true)
inOrder(notificationManager).let {
- it.verify(notificationManager, times(1)).notify(eq(R.string.stylus_battery_low), any())
- it.verify(notificationManager, times(1)).cancel(R.string.stylus_battery_low)
+ it.verify(notificationManager, times(1))
+ .notify(eq(R.string.stylus_battery_low_percentage), any())
+ it.verify(notificationManager, times(1)).cancel(R.string.stylus_battery_low_percentage)
it.verifyNoMoreInteractions()
}
}
@Test
@Ignore("TODO(b/257936830): get bt address once input api available")
- fun refresh_hasConnectedBluetoothStylus_doesNotNotify() {
+ fun refresh_hasConnectedBluetoothStylus_cancelsNotification() {
whenever(inputManager.inputDeviceIds).thenReturn(intArrayOf(0))
stylusUsiPowerUi.refresh()
- verifyNoMoreInteractions(notificationManager)
+ verify(notificationManager).cancel(R.string.stylus_battery_low_percentage)
}
@Test
@Ignore("TODO(b/257936830): get bt address once input api available")
fun refresh_hasConnectedBluetoothStylus_existingNotification_cancelsNotification() {
- stylusUsiPowerUi.updateBatteryState(FixedCapacityBatteryState(0.1f))
+ stylusUsiPowerUi.updateBatteryState(0, FixedCapacityBatteryState(0.1f))
whenever(inputManager.inputDeviceIds).thenReturn(intArrayOf(0))
stylusUsiPowerUi.refresh()
- verify(notificationManager).cancel(R.string.stylus_battery_low)
+ verify(notificationManager).cancel(R.string.stylus_battery_low_percentage)
}
- class FixedCapacityBatteryState(private val capacity: Float) : BatteryState() {
- override fun getCapacity() = capacity
- override fun getStatus() = 0
- override fun isPresent() = true
+ @Test
+ fun broadcastReceiver_clicked_hasInputDeviceId_startsUsiDetailsActivity() {
+ val intent = Intent(StylusUsiPowerUI.ACTION_CLICKED_LOW_BATTERY)
+ val activityIntentCaptor = argumentCaptor<Intent>()
+ stylusUsiPowerUi.updateBatteryState(1, FixedCapacityBatteryState(0.15f))
+ broadcastReceiver.onReceive(contextSpy, intent)
+
+ verify(contextSpy, times(1)).startActivity(activityIntentCaptor.capture())
+ assertThat(activityIntentCaptor.value.action)
+ .isEqualTo(StylusUsiPowerUI.ACTION_STYLUS_USI_DETAILS)
+ val args =
+ activityIntentCaptor.value.getExtra(StylusUsiPowerUI.KEY_SETTINGS_FRAGMENT_ARGS)
+ as Bundle
+ assertThat(args.getInt(StylusUsiPowerUI.KEY_DEVICE_INPUT_ID)).isEqualTo(1)
+ }
+
+ @Test
+ fun broadcastReceiver_clicked_nullInputDeviceId_doesNotStartActivity() {
+ val intent = Intent(StylusUsiPowerUI.ACTION_CLICKED_LOW_BATTERY)
+ broadcastReceiver.onReceive(contextSpy, intent)
+
+ verify(contextSpy, never()).startActivity(any())
}
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/unfold/FoldAodAnimationControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/unfold/FoldAodAnimationControllerTest.kt
index 89402de..30c4f97 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/unfold/FoldAodAnimationControllerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/unfold/FoldAodAnimationControllerTest.kt
@@ -29,6 +29,7 @@
import com.android.systemui.keyguard.data.repository.FakeKeyguardRepository
import com.android.systemui.keyguard.domain.interactor.KeyguardInteractor
import com.android.systemui.shade.NotificationPanelViewController
+import com.android.systemui.statusbar.CommandQueue
import com.android.systemui.statusbar.LightRevealScrim
import com.android.systemui.statusbar.phone.CentralSurfaces
import com.android.systemui.unfold.util.FoldableDeviceStates
@@ -73,6 +74,8 @@
@Mock lateinit var viewTreeObserver: ViewTreeObserver
+ @Mock private lateinit var commandQueue: CommandQueue
+
@Captor private lateinit var foldStateListenerCaptor: ArgumentCaptor<FoldStateListener>
private lateinit var deviceStates: FoldableDeviceStates
@@ -102,7 +105,8 @@
}
keyguardRepository = FakeKeyguardRepository()
- val keyguardInteractor = KeyguardInteractor(repository = keyguardRepository)
+ val keyguardInteractor =
+ KeyguardInteractor(repository = keyguardRepository, commandQueue = commandQueue)
// Needs to be run on the main thread
runBlocking(IMMEDIATE) {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/user/domain/interactor/UserInteractorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/user/domain/interactor/UserInteractorTest.kt
index 1a2ee18..7380ca4 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/user/domain/interactor/UserInteractorTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/user/domain/interactor/UserInteractorTest.kt
@@ -43,6 +43,7 @@
import com.android.systemui.keyguard.domain.interactor.KeyguardInteractor
import com.android.systemui.plugins.ActivityStarter
import com.android.systemui.qs.user.UserSwitchDialogController
+import com.android.systemui.statusbar.CommandQueue
import com.android.systemui.statusbar.policy.DeviceProvisionedController
import com.android.systemui.telephony.data.repository.FakeTelephonyRepository
import com.android.systemui.telephony.domain.interactor.TelephonyInteractor
@@ -95,6 +96,7 @@
@Mock private lateinit var dialogShower: UserSwitchDialogController.DialogShower
@Mock private lateinit var resumeSessionReceiver: GuestResumeSessionReceiver
@Mock private lateinit var resetOrExitSessionReceiver: GuestResetOrExitSessionReceiver
+ @Mock private lateinit var commandQueue: CommandQueue
private lateinit var underTest: UserInteractor
@@ -138,6 +140,7 @@
keyguardInteractor =
KeyguardInteractor(
repository = keyguardRepository,
+ commandQueue = commandQueue,
),
manager = manager,
applicationScope = testScope.backgroundScope,
diff --git a/packages/SystemUI/tests/src/com/android/systemui/user/ui/viewmodel/StatusBarUserChipViewModelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/user/ui/viewmodel/StatusBarUserChipViewModelTest.kt
index 5d4c1cc..46f38ed 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/user/ui/viewmodel/StatusBarUserChipViewModelTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/user/ui/viewmodel/StatusBarUserChipViewModelTest.kt
@@ -34,6 +34,7 @@
import com.android.systemui.keyguard.data.repository.FakeKeyguardRepository
import com.android.systemui.keyguard.domain.interactor.KeyguardInteractor
import com.android.systemui.plugins.ActivityStarter
+import com.android.systemui.statusbar.CommandQueue
import com.android.systemui.statusbar.policy.DeviceProvisionedController
import com.android.systemui.telephony.data.repository.FakeTelephonyRepository
import com.android.systemui.telephony.domain.interactor.TelephonyInteractor
@@ -75,6 +76,7 @@
@Mock private lateinit var uiEventLogger: UiEventLogger
@Mock private lateinit var resumeSessionReceiver: GuestResumeSessionReceiver
@Mock private lateinit var resetOrExitSessionReceiver: GuestResetOrExitSessionReceiver
+ @Mock private lateinit var commandQueue: CommandQueue
private lateinit var underTest: StatusBarUserChipViewModel
@@ -241,6 +243,7 @@
keyguardInteractor =
KeyguardInteractor(
repository = keyguardRepository,
+ commandQueue = commandQueue,
),
featureFlags =
FakeFeatureFlags().apply { set(Flags.FULL_SCREEN_USER_SWITCHER, false) },
diff --git a/packages/SystemUI/tests/src/com/android/systemui/user/ui/viewmodel/UserSwitcherViewModelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/user/ui/viewmodel/UserSwitcherViewModelTest.kt
index 0efede1..1d57d0b 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/user/ui/viewmodel/UserSwitcherViewModelTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/user/ui/viewmodel/UserSwitcherViewModelTest.kt
@@ -34,6 +34,7 @@
import com.android.systemui.plugins.ActivityStarter
import com.android.systemui.power.data.repository.FakePowerRepository
import com.android.systemui.power.domain.interactor.PowerInteractor
+import com.android.systemui.statusbar.CommandQueue
import com.android.systemui.statusbar.policy.DeviceProvisionedController
import com.android.systemui.telephony.data.repository.FakeTelephonyRepository
import com.android.systemui.telephony.domain.interactor.TelephonyInteractor
@@ -76,6 +77,7 @@
@Mock private lateinit var uiEventLogger: UiEventLogger
@Mock private lateinit var resumeSessionReceiver: GuestResumeSessionReceiver
@Mock private lateinit var resetOrExitSessionReceiver: GuestResetOrExitSessionReceiver
+ @Mock private lateinit var commandQueue: CommandQueue
private lateinit var underTest: UserSwitcherViewModel
@@ -142,6 +144,7 @@
keyguardInteractor =
KeyguardInteractor(
repository = keyguardRepository,
+ commandQueue = commandQueue,
),
featureFlags =
FakeFeatureFlags().apply {
@@ -170,273 +173,295 @@
}
@Test
- fun users() = testScope.runTest {
- val userInfos =
- listOf(
- UserInfo(
- /* id= */ 0,
- /* name= */ "zero",
- /* iconPath= */ "",
- /* flags= */ UserInfo.FLAG_PRIMARY or UserInfo.FLAG_ADMIN or UserInfo.FLAG_FULL,
- UserManager.USER_TYPE_FULL_SYSTEM,
- ),
- UserInfo(
- /* id= */ 1,
- /* name= */ "one",
- /* iconPath= */ "",
- /* flags= */ UserInfo.FLAG_FULL,
- UserManager.USER_TYPE_FULL_SYSTEM,
- ),
- UserInfo(
- /* id= */ 2,
- /* name= */ "two",
- /* iconPath= */ "",
- /* flags= */ UserInfo.FLAG_FULL,
- UserManager.USER_TYPE_FULL_SYSTEM,
- ),
- )
- userRepository.setUserInfos(userInfos)
- userRepository.setSelectedUserInfo(userInfos[0])
-
- val userViewModels = mutableListOf<List<UserViewModel>>()
- val job = launch(testDispatcher) { underTest.users.toList(userViewModels) }
-
- assertThat(userViewModels.last()).hasSize(3)
- assertUserViewModel(
- viewModel = userViewModels.last()[0],
- viewKey = 0,
- name = Text.Loaded("zero"),
- isSelectionMarkerVisible = true,
- )
- assertUserViewModel(
- viewModel = userViewModels.last()[1],
- viewKey = 1,
- name = Text.Loaded("one"),
- isSelectionMarkerVisible = false,
- )
- assertUserViewModel(
- viewModel = userViewModels.last()[2],
- viewKey = 2,
- name = Text.Loaded("two"),
- isSelectionMarkerVisible = false,
- )
- job.cancel()
- }
-
- @Test
- fun `maximumUserColumns - few users`() = testScope.runTest {
- setUsers(count = 2)
- val values = mutableListOf<Int>()
- val job = launch(testDispatcher) { underTest.maximumUserColumns.toList(values) }
-
- assertThat(values.last()).isEqualTo(4)
-
- job.cancel()
- }
-
- @Test
- fun `maximumUserColumns - many users`() = testScope.runTest {
- setUsers(count = 5)
- val values = mutableListOf<Int>()
- val job = launch(testDispatcher) { underTest.maximumUserColumns.toList(values) }
-
- assertThat(values.last()).isEqualTo(3)
- job.cancel()
- }
-
- @Test
- fun `isOpenMenuButtonVisible - has actions - true`() = testScope.runTest {
- setUsers(2)
-
- val isVisible = mutableListOf<Boolean>()
- val job = launch(testDispatcher) { underTest.isOpenMenuButtonVisible.toList(isVisible) }
-
- assertThat(isVisible.last()).isTrue()
- job.cancel()
- }
-
- @Test
- fun `isOpenMenuButtonVisible - no actions - false`() = testScope.runTest {
- val userInfos = setUsers(2)
- userRepository.setSelectedUserInfo(userInfos[1])
- keyguardRepository.setKeyguardShowing(true)
- whenever(manager.canAddMoreUsers(any())).thenReturn(false)
-
- val isVisible = mutableListOf<Boolean>()
- val job = launch(testDispatcher) { underTest.isOpenMenuButtonVisible.toList(isVisible) }
-
- assertThat(isVisible.last()).isFalse()
- job.cancel()
- }
-
- @Test
- fun menu() = testScope.runTest {
- val isMenuVisible = mutableListOf<Boolean>()
- val job = launch(testDispatcher) { underTest.isMenuVisible.toList(isMenuVisible) }
- assertThat(isMenuVisible.last()).isFalse()
-
- underTest.onOpenMenuButtonClicked()
- assertThat(isMenuVisible.last()).isTrue()
-
- underTest.onMenuClosed()
- assertThat(isMenuVisible.last()).isFalse()
-
- job.cancel()
- }
-
- @Test
- fun `menu actions`() = testScope.runTest {
- setUsers(2)
- val actions = mutableListOf<List<UserActionViewModel>>()
- val job = launch(testDispatcher) { underTest.menu.toList(actions) }
-
- assertThat(actions.last().map { it.viewKey })
- .isEqualTo(
+ fun users() =
+ testScope.runTest {
+ val userInfos =
listOf(
- UserActionModel.ENTER_GUEST_MODE.ordinal.toLong(),
- UserActionModel.ADD_USER.ordinal.toLong(),
- UserActionModel.ADD_SUPERVISED_USER.ordinal.toLong(),
- UserActionModel.NAVIGATE_TO_USER_MANAGEMENT.ordinal.toLong(),
+ UserInfo(
+ /* id= */ 0,
+ /* name= */ "zero",
+ /* iconPath= */ "",
+ /* flags= */ UserInfo.FLAG_PRIMARY or
+ UserInfo.FLAG_ADMIN or
+ UserInfo.FLAG_FULL,
+ UserManager.USER_TYPE_FULL_SYSTEM,
+ ),
+ UserInfo(
+ /* id= */ 1,
+ /* name= */ "one",
+ /* iconPath= */ "",
+ /* flags= */ UserInfo.FLAG_FULL,
+ UserManager.USER_TYPE_FULL_SYSTEM,
+ ),
+ UserInfo(
+ /* id= */ 2,
+ /* name= */ "two",
+ /* iconPath= */ "",
+ /* flags= */ UserInfo.FLAG_FULL,
+ UserManager.USER_TYPE_FULL_SYSTEM,
+ ),
)
- )
+ userRepository.setUserInfos(userInfos)
+ userRepository.setSelectedUserInfo(userInfos[0])
- job.cancel()
- }
+ val userViewModels = mutableListOf<List<UserViewModel>>()
+ val job = launch(testDispatcher) { underTest.users.toList(userViewModels) }
- @Test
- fun `isFinishRequested - finishes when user is switched`() = testScope.runTest {
- val userInfos = setUsers(count = 2)
- val isFinishRequested = mutableListOf<Boolean>()
- val job = launch(testDispatcher) { underTest.isFinishRequested.toList(isFinishRequested) }
- assertThat(isFinishRequested.last()).isFalse()
-
- userRepository.setSelectedUserInfo(userInfos[1])
-
- assertThat(isFinishRequested.last()).isTrue()
-
- job.cancel()
- }
-
- @Test
- fun `isFinishRequested - finishes when the screen turns off`() = testScope.runTest {
- setUsers(count = 2)
- powerRepository.setInteractive(true)
- val isFinishRequested = mutableListOf<Boolean>()
- val job = launch(testDispatcher) { underTest.isFinishRequested.toList(isFinishRequested) }
- assertThat(isFinishRequested.last()).isFalse()
-
- powerRepository.setInteractive(false)
-
- assertThat(isFinishRequested.last()).isTrue()
-
- job.cancel()
- }
-
- @Test
- fun `isFinishRequested - finishes when cancel button is clicked`() = testScope.runTest {
- setUsers(count = 2)
- powerRepository.setInteractive(true)
- val isFinishRequested = mutableListOf<Boolean>()
- val job = launch(testDispatcher) { underTest.isFinishRequested.toList(isFinishRequested) }
- assertThat(isFinishRequested.last()).isFalse()
-
- underTest.onCancelButtonClicked()
-
- assertThat(isFinishRequested.last()).isTrue()
-
- underTest.onFinished()
-
- assertThat(isFinishRequested.last()).isFalse()
-
- job.cancel()
- }
-
- @Test
- fun `guest selected -- name is exit guest`() = testScope.runTest {
- val userInfos =
- listOf(
- UserInfo(
- /* id= */ 0,
- /* name= */ "zero",
- /* iconPath= */ "",
- /* flags= */ UserInfo.FLAG_PRIMARY or UserInfo.FLAG_ADMIN or UserInfo.FLAG_FULL,
- UserManager.USER_TYPE_FULL_SYSTEM,
- ),
- UserInfo(
- /* id= */ 1,
- /* name= */ "one",
- /* iconPath= */ "",
- /* flags= */ UserInfo.FLAG_FULL,
- UserManager.USER_TYPE_FULL_GUEST,
- ),
- )
-
- userRepository.setUserInfos(userInfos)
- userRepository.setSelectedUserInfo(userInfos[1])
-
- val userViewModels = mutableListOf<List<UserViewModel>>()
- val job = launch(testDispatcher) { underTest.users.toList(userViewModels) }
-
- assertThat(userViewModels.last()).hasSize(2)
- assertUserViewModel(
- viewModel = userViewModels.last()[0],
- viewKey = 0,
- name = Text.Loaded("zero"),
- isSelectionMarkerVisible = false,
- )
- assertUserViewModel(
- viewModel = userViewModels.last()[1],
- viewKey = 1,
- name = Text.Resource(
- com.android.settingslib.R.string.guest_exit_quick_settings_button
- ),
- isSelectionMarkerVisible = true,
- )
- job.cancel()
- }
-
- @Test
- fun `guest not selected -- name is guest`() = testScope.runTest {
- val userInfos =
- listOf(
- UserInfo(
- /* id= */ 0,
- /* name= */ "zero",
- /* iconPath= */ "",
- /* flags= */ UserInfo.FLAG_PRIMARY or UserInfo.FLAG_ADMIN or UserInfo.FLAG_FULL,
- UserManager.USER_TYPE_FULL_SYSTEM,
- ),
- UserInfo(
- /* id= */ 1,
- /* name= */ "one",
- /* iconPath= */ "",
- /* flags= */ UserInfo.FLAG_FULL,
- UserManager.USER_TYPE_FULL_GUEST,
- ),
- )
-
- userRepository.setUserInfos(userInfos)
- userRepository.setSelectedUserInfo(userInfos[0])
- runCurrent()
-
- val userViewModels = mutableListOf<List<UserViewModel>>()
- val job = launch(testDispatcher) { underTest.users.toList(userViewModels) }
-
- assertThat(userViewModels.last()).hasSize(2)
- assertUserViewModel(
+ assertThat(userViewModels.last()).hasSize(3)
+ assertUserViewModel(
viewModel = userViewModels.last()[0],
viewKey = 0,
name = Text.Loaded("zero"),
isSelectionMarkerVisible = true,
- )
- assertUserViewModel(
+ )
+ assertUserViewModel(
viewModel = userViewModels.last()[1],
viewKey = 1,
name = Text.Loaded("one"),
isSelectionMarkerVisible = false,
- )
- job.cancel()
- }
+ )
+ assertUserViewModel(
+ viewModel = userViewModels.last()[2],
+ viewKey = 2,
+ name = Text.Loaded("two"),
+ isSelectionMarkerVisible = false,
+ )
+ job.cancel()
+ }
+
+ @Test
+ fun `maximumUserColumns - few users`() =
+ testScope.runTest {
+ setUsers(count = 2)
+ val values = mutableListOf<Int>()
+ val job = launch(testDispatcher) { underTest.maximumUserColumns.toList(values) }
+
+ assertThat(values.last()).isEqualTo(4)
+
+ job.cancel()
+ }
+
+ @Test
+ fun `maximumUserColumns - many users`() =
+ testScope.runTest {
+ setUsers(count = 5)
+ val values = mutableListOf<Int>()
+ val job = launch(testDispatcher) { underTest.maximumUserColumns.toList(values) }
+
+ assertThat(values.last()).isEqualTo(3)
+ job.cancel()
+ }
+
+ @Test
+ fun `isOpenMenuButtonVisible - has actions - true`() =
+ testScope.runTest {
+ setUsers(2)
+
+ val isVisible = mutableListOf<Boolean>()
+ val job = launch(testDispatcher) { underTest.isOpenMenuButtonVisible.toList(isVisible) }
+
+ assertThat(isVisible.last()).isTrue()
+ job.cancel()
+ }
+
+ @Test
+ fun `isOpenMenuButtonVisible - no actions - false`() =
+ testScope.runTest {
+ val userInfos = setUsers(2)
+ userRepository.setSelectedUserInfo(userInfos[1])
+ keyguardRepository.setKeyguardShowing(true)
+ whenever(manager.canAddMoreUsers(any())).thenReturn(false)
+
+ val isVisible = mutableListOf<Boolean>()
+ val job = launch(testDispatcher) { underTest.isOpenMenuButtonVisible.toList(isVisible) }
+
+ assertThat(isVisible.last()).isFalse()
+ job.cancel()
+ }
+
+ @Test
+ fun menu() =
+ testScope.runTest {
+ val isMenuVisible = mutableListOf<Boolean>()
+ val job = launch(testDispatcher) { underTest.isMenuVisible.toList(isMenuVisible) }
+ assertThat(isMenuVisible.last()).isFalse()
+
+ underTest.onOpenMenuButtonClicked()
+ assertThat(isMenuVisible.last()).isTrue()
+
+ underTest.onMenuClosed()
+ assertThat(isMenuVisible.last()).isFalse()
+
+ job.cancel()
+ }
+
+ @Test
+ fun `menu actions`() =
+ testScope.runTest {
+ setUsers(2)
+ val actions = mutableListOf<List<UserActionViewModel>>()
+ val job = launch(testDispatcher) { underTest.menu.toList(actions) }
+
+ assertThat(actions.last().map { it.viewKey })
+ .isEqualTo(
+ listOf(
+ UserActionModel.ENTER_GUEST_MODE.ordinal.toLong(),
+ UserActionModel.ADD_USER.ordinal.toLong(),
+ UserActionModel.ADD_SUPERVISED_USER.ordinal.toLong(),
+ UserActionModel.NAVIGATE_TO_USER_MANAGEMENT.ordinal.toLong(),
+ )
+ )
+
+ job.cancel()
+ }
+
+ @Test
+ fun `isFinishRequested - finishes when user is switched`() =
+ testScope.runTest {
+ val userInfos = setUsers(count = 2)
+ val isFinishRequested = mutableListOf<Boolean>()
+ val job =
+ launch(testDispatcher) { underTest.isFinishRequested.toList(isFinishRequested) }
+ assertThat(isFinishRequested.last()).isFalse()
+
+ userRepository.setSelectedUserInfo(userInfos[1])
+
+ assertThat(isFinishRequested.last()).isTrue()
+
+ job.cancel()
+ }
+
+ @Test
+ fun `isFinishRequested - finishes when the screen turns off`() =
+ testScope.runTest {
+ setUsers(count = 2)
+ powerRepository.setInteractive(true)
+ val isFinishRequested = mutableListOf<Boolean>()
+ val job =
+ launch(testDispatcher) { underTest.isFinishRequested.toList(isFinishRequested) }
+ assertThat(isFinishRequested.last()).isFalse()
+
+ powerRepository.setInteractive(false)
+
+ assertThat(isFinishRequested.last()).isTrue()
+
+ job.cancel()
+ }
+
+ @Test
+ fun `isFinishRequested - finishes when cancel button is clicked`() =
+ testScope.runTest {
+ setUsers(count = 2)
+ powerRepository.setInteractive(true)
+ val isFinishRequested = mutableListOf<Boolean>()
+ val job =
+ launch(testDispatcher) { underTest.isFinishRequested.toList(isFinishRequested) }
+ assertThat(isFinishRequested.last()).isFalse()
+
+ underTest.onCancelButtonClicked()
+
+ assertThat(isFinishRequested.last()).isTrue()
+
+ underTest.onFinished()
+
+ assertThat(isFinishRequested.last()).isFalse()
+
+ job.cancel()
+ }
+
+ @Test
+ fun `guest selected -- name is exit guest`() =
+ testScope.runTest {
+ val userInfos =
+ listOf(
+ UserInfo(
+ /* id= */ 0,
+ /* name= */ "zero",
+ /* iconPath= */ "",
+ /* flags= */ UserInfo.FLAG_PRIMARY or
+ UserInfo.FLAG_ADMIN or
+ UserInfo.FLAG_FULL,
+ UserManager.USER_TYPE_FULL_SYSTEM,
+ ),
+ UserInfo(
+ /* id= */ 1,
+ /* name= */ "one",
+ /* iconPath= */ "",
+ /* flags= */ UserInfo.FLAG_FULL,
+ UserManager.USER_TYPE_FULL_GUEST,
+ ),
+ )
+
+ userRepository.setUserInfos(userInfos)
+ userRepository.setSelectedUserInfo(userInfos[1])
+
+ val userViewModels = mutableListOf<List<UserViewModel>>()
+ val job = launch(testDispatcher) { underTest.users.toList(userViewModels) }
+
+ assertThat(userViewModels.last()).hasSize(2)
+ assertUserViewModel(
+ viewModel = userViewModels.last()[0],
+ viewKey = 0,
+ name = Text.Loaded("zero"),
+ isSelectionMarkerVisible = false,
+ )
+ assertUserViewModel(
+ viewModel = userViewModels.last()[1],
+ viewKey = 1,
+ name =
+ Text.Resource(
+ com.android.settingslib.R.string.guest_exit_quick_settings_button
+ ),
+ isSelectionMarkerVisible = true,
+ )
+ job.cancel()
+ }
+
+ @Test
+ fun `guest not selected -- name is guest`() =
+ testScope.runTest {
+ val userInfos =
+ listOf(
+ UserInfo(
+ /* id= */ 0,
+ /* name= */ "zero",
+ /* iconPath= */ "",
+ /* flags= */ UserInfo.FLAG_PRIMARY or
+ UserInfo.FLAG_ADMIN or
+ UserInfo.FLAG_FULL,
+ UserManager.USER_TYPE_FULL_SYSTEM,
+ ),
+ UserInfo(
+ /* id= */ 1,
+ /* name= */ "one",
+ /* iconPath= */ "",
+ /* flags= */ UserInfo.FLAG_FULL,
+ UserManager.USER_TYPE_FULL_GUEST,
+ ),
+ )
+
+ userRepository.setUserInfos(userInfos)
+ userRepository.setSelectedUserInfo(userInfos[0])
+ runCurrent()
+
+ val userViewModels = mutableListOf<List<UserViewModel>>()
+ val job = launch(testDispatcher) { underTest.users.toList(userViewModels) }
+
+ assertThat(userViewModels.last()).hasSize(2)
+ assertUserViewModel(
+ viewModel = userViewModels.last()[0],
+ viewKey = 0,
+ name = Text.Loaded("zero"),
+ isSelectionMarkerVisible = true,
+ )
+ assertUserViewModel(
+ viewModel = userViewModels.last()[1],
+ viewKey = 1,
+ name = Text.Loaded("one"),
+ isSelectionMarkerVisible = false,
+ )
+ job.cancel()
+ }
private suspend fun setUsers(count: Int): List<UserInfo> {
val userInfos =
diff --git a/packages/SystemUI/tests/src/com/android/systemui/volume/VolumeDialogImplTest.java b/packages/SystemUI/tests/src/com/android/systemui/volume/VolumeDialogImplTest.java
index c3c6975..d419095 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/volume/VolumeDialogImplTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/volume/VolumeDialogImplTest.java
@@ -16,6 +16,7 @@
package com.android.systemui.volume;
+import static com.android.systemui.volume.Events.DISMISS_REASON_UNKNOWN;
import static com.android.systemui.volume.VolumeDialogControllerImpl.STREAMS;
import static junit.framework.Assert.assertEquals;
@@ -342,6 +343,15 @@
assertEquals(mDialog.mVolumeRingerMuteIconDrawableId, R.drawable.ic_volume_ringer_mute);
}
+ @Test
+ public void testDialogDismissAnimation_notifyVisibleIsNotCalledBeforeAnimation() {
+ mDialog.dismissH(DISMISS_REASON_UNKNOWN);
+ // notifyVisible(false) should not be called immediately but only after the dismiss
+ // animation has ended.
+ verify(mVolumeDialogController, times(0)).notifyVisible(false);
+ mDialog.getDialogView().animate().cancel();
+ }
+
/*
@Test
public void testContentDescriptions() {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/wmshell/BubblesTest.java b/packages/SystemUI/tests/src/com/android/systemui/wmshell/BubblesTest.java
index 5b424a3..a537848 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/wmshell/BubblesTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/wmshell/BubblesTest.java
@@ -24,6 +24,7 @@
import static android.service.notification.NotificationListenerService.REASON_GROUP_SUMMARY_CANCELED;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.spyOn;
+import static com.android.wm.shell.bubbles.Bubble.KEY_APP_BUBBLE;
import static com.google.common.truth.Truth.assertThat;
@@ -228,6 +229,8 @@
private BubbleEntry mBubbleEntryUser11;
private BubbleEntry mBubbleEntry2User11;
+ private Intent mAppBubbleIntent;
+
@Mock
private ShellInit mShellInit;
@Mock
@@ -323,6 +326,9 @@
mBubbleEntry2User11 = BubblesManager.notifToBubbleEntry(
mNotificationTestHelper.createBubble(handle));
+ mAppBubbleIntent = new Intent(mContext, BubblesTestActivity.class);
+ mAppBubbleIntent.setPackage(mContext.getPackageName());
+
mZenModeConfig.suppressedVisualEffects = 0;
when(mZenModeController.getConfig()).thenReturn(mZenModeConfig);
@@ -1630,6 +1636,62 @@
any(Bubble.class), anyBoolean(), anyBoolean());
}
+ @Test
+ public void testShowOrHideAppBubble_addsAndExpand() {
+ assertThat(mBubbleController.isStackExpanded()).isFalse();
+ assertThat(mBubbleData.getBubbleInStackWithKey(KEY_APP_BUBBLE)).isNull();
+
+ mBubbleController.showOrHideAppBubble(mAppBubbleIntent);
+
+ verify(mBubbleController).inflateAndAdd(any(Bubble.class), /* suppressFlyout= */ eq(true),
+ /* showInShade= */ eq(false));
+ assertThat(mBubbleData.getSelectedBubble().getKey()).isEqualTo(KEY_APP_BUBBLE);
+ assertThat(mBubbleController.isStackExpanded()).isTrue();
+ }
+
+ @Test
+ public void testShowOrHideAppBubble_expandIfCollapsed() {
+ mBubbleController.showOrHideAppBubble(mAppBubbleIntent);
+ mBubbleController.updateBubble(mBubbleEntry);
+ mBubbleController.collapseStack();
+ assertThat(mBubbleController.isStackExpanded()).isFalse();
+
+ // Calling this while collapsed will expand the app bubble
+ mBubbleController.showOrHideAppBubble(mAppBubbleIntent);
+
+ assertThat(mBubbleData.getSelectedBubble().getKey()).isEqualTo(KEY_APP_BUBBLE);
+ assertThat(mBubbleController.isStackExpanded()).isTrue();
+ assertThat(mBubbleData.getBubbles().size()).isEqualTo(2);
+ }
+
+ @Test
+ public void testShowOrHideAppBubble_collapseIfSelected() {
+ mBubbleController.showOrHideAppBubble(mAppBubbleIntent);
+ assertThat(mBubbleData.getSelectedBubble().getKey()).isEqualTo(KEY_APP_BUBBLE);
+ assertThat(mBubbleController.isStackExpanded()).isTrue();
+
+ // Calling this while the app bubble is expanded should collapse the stack
+ mBubbleController.showOrHideAppBubble(mAppBubbleIntent);
+
+ assertThat(mBubbleData.getSelectedBubble().getKey()).isEqualTo(KEY_APP_BUBBLE);
+ assertThat(mBubbleController.isStackExpanded()).isFalse();
+ assertThat(mBubbleData.getBubbles().size()).isEqualTo(1);
+ }
+
+ @Test
+ public void testShowOrHideAppBubble_selectIfNotSelected() {
+ mBubbleController.showOrHideAppBubble(mAppBubbleIntent);
+ mBubbleController.updateBubble(mBubbleEntry);
+ mBubbleController.expandStackAndSelectBubble(mBubbleEntry);
+ assertThat(mBubbleData.getSelectedBubble().getKey()).isEqualTo(mBubbleEntry.getKey());
+ assertThat(mBubbleController.isStackExpanded()).isTrue();
+
+ mBubbleController.showOrHideAppBubble(mAppBubbleIntent);
+ assertThat(mBubbleData.getSelectedBubble().getKey()).isEqualTo(KEY_APP_BUBBLE);
+ assertThat(mBubbleController.isStackExpanded()).isTrue();
+ assertThat(mBubbleData.getBubbles().size()).isEqualTo(2);
+ }
+
/** Creates a bubble using the userId and package. */
private Bubble createBubble(int userId, String pkg) {
final UserHandle userHandle = new UserHandle(userId);
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/MemoryTrackingTestCase.java b/packages/SystemUI/tests/utils/src/com/android/systemui/MemoryTrackingTestCase.java
index 3767fbe..3428553 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/MemoryTrackingTestCase.java
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/MemoryTrackingTestCase.java
@@ -40,24 +40,49 @@
public class MemoryTrackingTestCase extends SysuiTestCase {
private static File sFilesDir = null;
private static String sLatestTestClassName = null;
+ private static int sHeapCount = 0;
+ private static File sLatestBaselineHeapFile = null;
- @Before public void grabFilesDir() {
+ // Ideally, we would do this in @BeforeClass just once, but we need mContext to get the files
+ // dir, and that does not exist until @Before on each test method.
+ @Before
+ public void grabFilesDir() throws IOException {
+ // This should happen only once per suite
if (sFilesDir == null) {
sFilesDir = mContext.getFilesDir();
}
- sLatestTestClassName = getClass().getName();
+
+ // This will happen before the first test method in each class
+ if (sLatestTestClassName == null) {
+ sLatestTestClassName = getClass().getName();
+ sLatestBaselineHeapFile = dump("baseline" + (++sHeapCount), "before-test");
+ }
}
@AfterClass
public static void dumpHeap() throws IOException {
+ File afterTestHeap = dump(sLatestTestClassName, "after-test");
+ if (sLatestBaselineHeapFile != null && afterTestHeap != null) {
+ Log.w("MEMORY", "To compare heap to baseline (use go/ahat):");
+ Log.w("MEMORY", " adb pull " + sLatestBaselineHeapFile);
+ Log.w("MEMORY", " adb pull " + afterTestHeap);
+ Log.w("MEMORY",
+ " java -jar ahat.jar --baseline " + sLatestBaselineHeapFile.getName() + " "
+ + afterTestHeap.getName());
+ }
+ sLatestTestClassName = null;
+ }
+
+ private static File dump(String basename, String heapKind) throws IOException {
if (sFilesDir == null) {
Log.e("MEMORY", "Somehow no test cases??");
- return;
+ return null;
}
mockitoTearDown();
- Log.w("MEMORY", "about to dump heap");
- File path = new File(sFilesDir, sLatestTestClassName + ".ahprof");
+ Log.w("MEMORY", "about to dump " + heapKind + " heap");
+ File path = new File(sFilesDir, basename + ".ahprof");
Debug.dumpHprofData(path.getPath());
- Log.w("MEMORY", "did it! Location: " + path);
+ Log.w("MEMORY", "Success! Location: " + path);
+ return path;
}
}
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/data/repository/FakeKeyguardRepository.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/data/repository/FakeKeyguardRepository.kt
index 39d2eca..15b4736 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/data/repository/FakeKeyguardRepository.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/data/repository/FakeKeyguardRepository.kt
@@ -52,6 +52,9 @@
private val _isDozing = MutableStateFlow(false)
override val isDozing: Flow<Boolean> = _isDozing
+ private val _isAodAvailable = MutableStateFlow(false)
+ override val isAodAvailable: Flow<Boolean> = _isAodAvailable
+
private val _isDreaming = MutableStateFlow(false)
override val isDreaming: Flow<Boolean> = _isDreaming
@@ -126,6 +129,10 @@
_isDozing.value = isDozing
}
+ fun setAodAvailable(isAodAvailable: Boolean) {
+ _isAodAvailable.value = isAodAvailable
+ }
+
fun setDreamingWithOverlay(isDreaming: Boolean) {
_isDreamingWithOverlay.value = isDreaming
}
diff --git a/services/accessibility/java/com/android/server/accessibility/AbstractAccessibilityServiceConnection.java b/services/accessibility/java/com/android/server/accessibility/AbstractAccessibilityServiceConnection.java
index 05e305c..f4c6cc3 100644
--- a/services/accessibility/java/com/android/server/accessibility/AbstractAccessibilityServiceConnection.java
+++ b/services/accessibility/java/com/android/server/accessibility/AbstractAccessibilityServiceConnection.java
@@ -132,7 +132,7 @@
private static final String TRACE_WM = "WindowManagerInternal";
private static final int WAIT_WINDOWS_TIMEOUT_MILLIS = 5000;
- /** Display type for displays associated with the default user of th device. */
+ /** Display type for displays associated with the default user of the device. */
public static final int DISPLAY_TYPE_DEFAULT = 1 << 0;
/** Display type for displays associated with an AccessibilityDisplayProxy user. */
public static final int DISPLAY_TYPE_PROXY = 1 << 1;
@@ -1993,17 +1993,29 @@
private int resolveAccessibilityWindowIdLocked(int accessibilityWindowId) {
if (accessibilityWindowId == AccessibilityWindowInfo.ACTIVE_WINDOW_ID) {
- return mA11yWindowManager.getActiveWindowId(mSystemSupport.getCurrentUserIdLocked());
+ final int focusedWindowId =
+ mA11yWindowManager.getActiveWindowId(mSystemSupport.getCurrentUserIdLocked());
+ if (!mA11yWindowManager.windowIdBelongsToDisplayType(focusedWindowId, mDisplayTypes)) {
+ return AccessibilityWindowInfo.UNDEFINED_WINDOW_ID;
+ }
+ return focusedWindowId;
}
return accessibilityWindowId;
}
private int resolveAccessibilityWindowIdForFindFocusLocked(int windowId, int focusType) {
- if (windowId == AccessibilityWindowInfo.ACTIVE_WINDOW_ID) {
- return mA11yWindowManager.getActiveWindowId(mSystemSupport.getCurrentUserIdLocked());
- }
if (windowId == AccessibilityWindowInfo.ANY_WINDOW_ID) {
- return mA11yWindowManager.getFocusedWindowId(focusType);
+ final int focusedWindowId = mA11yWindowManager.getFocusedWindowId(focusType);
+ // If the caller is a proxy and the found window doesn't belong to a proxy display
+ // (or vice versa), then return null. This doesn't work if there are multiple active
+ // proxys, but in the future this code shouldn't be needed if input and a11y focus are
+ // properly split. (so we will deal with the issues if we see them).
+ //TODO(254545943): Remove this when there is user and proxy separation of input and a11y
+ // focus
+ if (!mA11yWindowManager.windowIdBelongsToDisplayType(focusedWindowId, mDisplayTypes)) {
+ return AccessibilityWindowInfo.UNDEFINED_WINDOW_ID;
+ }
+ return focusedWindowId;
}
return windowId;
}
diff --git a/services/accessibility/java/com/android/server/accessibility/AccessibilityWindowManager.java b/services/accessibility/java/com/android/server/accessibility/AccessibilityWindowManager.java
index c050449e0..f0c6c4f 100644
--- a/services/accessibility/java/com/android/server/accessibility/AccessibilityWindowManager.java
+++ b/services/accessibility/java/com/android/server/accessibility/AccessibilityWindowManager.java
@@ -156,6 +156,30 @@
}
/**
+ * Returns {@code true} if the window belongs to a display of {@code displayTypes}.
+ */
+ public boolean windowIdBelongsToDisplayType(int focusedWindowId, int displayTypes) {
+ // UIAutomation wants focus from any display type.
+ final int displayTypeMask = DISPLAY_TYPE_PROXY | DISPLAY_TYPE_DEFAULT;
+ if ((displayTypes & displayTypeMask) == displayTypeMask) {
+ return true;
+ }
+ synchronized (mLock) {
+ final int count = mDisplayWindowsObservers.size();
+ for (int i = 0; i < count; i++) {
+ final DisplayWindowsObserver observer = mDisplayWindowsObservers.valueAt(i);
+ if (observer != null
+ && observer.findA11yWindowInfoByIdLocked(focusedWindowId) != null) {
+ return observer.mIsProxy
+ ? ((displayTypes & DISPLAY_TYPE_PROXY) != 0)
+ : (displayTypes & DISPLAY_TYPE_DEFAULT) != 0;
+ }
+ }
+ }
+ return false;
+ }
+
+ /**
* This class implements {@link WindowManagerInternal.WindowsForAccessibilityCallback} to
* receive {@link WindowInfo}s from window manager when there's an accessibility change in
* window and holds window lists information per display.
@@ -430,6 +454,7 @@
return;
}
windowInfo.title = attributes.getWindowTitle();
+ windowInfo.locales = attributes.getLocales();
}
private boolean shouldUpdateWindowsLocked(boolean forceSend,
@@ -756,6 +781,7 @@
reportedWindow.setPictureInPicture(window.inPictureInPicture);
reportedWindow.setDisplayId(window.displayId);
reportedWindow.setTaskId(window.taskId);
+ reportedWindow.setLocales(window.locales);
final int parentId = findWindowIdLocked(userId, window.parentToken);
if (parentId >= 0) {
diff --git a/services/accessibility/java/com/android/server/accessibility/magnification/MagnificationController.java b/services/accessibility/java/com/android/server/accessibility/magnification/MagnificationController.java
index bb286e6..02e810f 100644
--- a/services/accessibility/java/com/android/server/accessibility/magnification/MagnificationController.java
+++ b/services/accessibility/java/com/android/server/accessibility/magnification/MagnificationController.java
@@ -410,9 +410,6 @@
public void onRequestMagnificationSpec(int displayId, int serviceId) {
final WindowMagnificationManager windowMagnificationManager;
synchronized (mLock) {
- if (serviceId == MAGNIFICATION_GESTURE_HANDLER_ID) {
- return;
- }
updateMagnificationButton(displayId, ACCESSIBILITY_MAGNIFICATION_MODE_FULLSCREEN);
windowMagnificationManager = mWindowMagnificationMgr;
}
diff --git a/services/api/current.txt b/services/api/current.txt
index aab6a6c..3926b39 100644
--- a/services/api/current.txt
+++ b/services/api/current.txt
@@ -38,7 +38,8 @@
package com.android.server.am {
public interface ActivityManagerLocal {
- method public boolean bindSdkSandboxService(@NonNull android.content.Intent, @NonNull android.content.ServiceConnection, int, @NonNull String, @NonNull String, int) throws android.os.RemoteException;
+ method public boolean bindSdkSandboxService(@NonNull android.content.Intent, @NonNull android.content.ServiceConnection, int, @NonNull android.os.IBinder, @NonNull String, @NonNull String, int) throws android.os.RemoteException;
+ method @Deprecated public boolean bindSdkSandboxService(@NonNull android.content.Intent, @NonNull android.content.ServiceConnection, int, @NonNull String, @NonNull String, int) throws android.os.RemoteException;
method public boolean canStartForegroundService(int, int, @NonNull String);
method public void killSdkSandboxClientAppProcess(@NonNull android.os.IBinder);
}
diff --git a/services/appwidget/java/com/android/server/appwidget/AppWidgetServiceImpl.java b/services/appwidget/java/com/android/server/appwidget/AppWidgetServiceImpl.java
index bce8812..7df4899 100644
--- a/services/appwidget/java/com/android/server/appwidget/AppWidgetServiceImpl.java
+++ b/services/appwidget/java/com/android/server/appwidget/AppWidgetServiceImpl.java
@@ -826,7 +826,8 @@
if (host != null) {
host.callbacks = null;
pruneHostLocked(host);
- mAppOpsManagerInternal.updateAppWidgetVisibility(host.getWidgetUids(), false);
+ mAppOpsManagerInternal.updateAppWidgetVisibility(host.getWidgetUidsIfBound(),
+ false);
}
}
}
@@ -897,12 +898,8 @@
Host host = lookupHostLocked(id);
if (host != null) {
- try {
- mAppOpsManagerInternal.updateAppWidgetVisibility(host.getWidgetUids(), false);
- } catch (NullPointerException e) {
- Slog.e(TAG, "setAppWidgetHidden(): Getting host uids: " + host.toString(), e);
- throw e;
- }
+ mAppOpsManagerInternal.updateAppWidgetVisibility(host.getWidgetUidsIfBound(),
+ false);
}
}
}
@@ -4370,14 +4367,15 @@
PendingHostUpdate.appWidgetRemoved(appWidgetId));
}
- public SparseArray<String> getWidgetUids() {
+ public SparseArray<String> getWidgetUidsIfBound() {
final SparseArray<String> uids = new SparseArray<>();
for (int i = widgets.size() - 1; i >= 0; i--) {
final Widget widget = widgets.get(i);
if (widget.provider == null) {
if (DEBUG) {
- Slog.e(TAG, "Widget with no provider " + widget.toString());
+ Slog.d(TAG, "Widget with no provider " + widget.toString());
}
+ continue;
}
final ProviderId providerId = widget.provider.id;
uids.put(providerId.uid, providerId.componentName.getPackageName());
diff --git a/services/autofill/java/com/android/server/autofill/AutofillManagerService.java b/services/autofill/java/com/android/server/autofill/AutofillManagerService.java
index 54f77b1..6b61e97 100644
--- a/services/autofill/java/com/android/server/autofill/AutofillManagerService.java
+++ b/services/autofill/java/com/android/server/autofill/AutofillManagerService.java
@@ -67,6 +67,7 @@
import android.util.SparseArray;
import android.util.SparseBooleanArray;
import android.util.TimeUtils;
+import android.view.autofill.AutofillFeatureFlags;
import android.view.autofill.AutofillId;
import android.view.autofill.AutofillManager;
import android.view.autofill.AutofillManager.AutofillCommitReason;
@@ -298,12 +299,12 @@
private void onDeviceConfigChange(@NonNull Set<String> keys) {
for (String key : keys) {
switch (key) {
- case AutofillManager.DEVICE_CONFIG_AUTOFILL_SMART_SUGGESTION_SUPPORTED_MODES:
- case AutofillManager.DEVICE_CONFIG_AUGMENTED_SERVICE_IDLE_UNBIND_TIMEOUT:
- case AutofillManager.DEVICE_CONFIG_AUGMENTED_SERVICE_REQUEST_TIMEOUT:
+ case AutofillFeatureFlags.DEVICE_CONFIG_AUTOFILL_SMART_SUGGESTION_SUPPORTED_MODES:
+ case AutofillFeatureFlags.DEVICE_CONFIG_AUGMENTED_SERVICE_IDLE_UNBIND_TIMEOUT:
+ case AutofillFeatureFlags.DEVICE_CONFIG_AUGMENTED_SERVICE_REQUEST_TIMEOUT:
setDeviceConfigProperties();
break;
- case AutofillManager.DEVICE_CONFIG_AUTOFILL_COMPAT_MODE_ALLOWED_PACKAGES:
+ case AutofillFeatureFlags.DEVICE_CONFIG_AUTOFILL_COMPAT_MODE_ALLOWED_PACKAGES:
updateCachedServices();
break;
default:
@@ -567,15 +568,15 @@
synchronized (mLock) {
mAugmentedServiceIdleUnbindTimeoutMs = DeviceConfig.getInt(
DeviceConfig.NAMESPACE_AUTOFILL,
- AutofillManager.DEVICE_CONFIG_AUGMENTED_SERVICE_IDLE_UNBIND_TIMEOUT,
+ AutofillFeatureFlags.DEVICE_CONFIG_AUGMENTED_SERVICE_IDLE_UNBIND_TIMEOUT,
(int) AbstractRemoteService.PERMANENT_BOUND_TIMEOUT_MS);
mAugmentedServiceRequestTimeoutMs = DeviceConfig.getInt(
DeviceConfig.NAMESPACE_AUTOFILL,
- AutofillManager.DEVICE_CONFIG_AUGMENTED_SERVICE_REQUEST_TIMEOUT,
+ AutofillFeatureFlags.DEVICE_CONFIG_AUGMENTED_SERVICE_REQUEST_TIMEOUT,
DEFAULT_AUGMENTED_AUTOFILL_REQUEST_TIMEOUT_MILLIS);
mSupportedSmartSuggestionModes = DeviceConfig.getInt(
DeviceConfig.NAMESPACE_AUTOFILL,
- AutofillManager.DEVICE_CONFIG_AUTOFILL_SMART_SUGGESTION_SUPPORTED_MODES,
+ AutofillFeatureFlags.DEVICE_CONFIG_AUTOFILL_SMART_SUGGESTION_SUPPORTED_MODES,
AutofillManager.FLAG_SMART_SUGGESTION_SYSTEM);
if (verbose) {
Slog.v(mTag, "setDeviceConfigProperties(): "
@@ -729,7 +730,7 @@
private String getAllowedCompatModePackagesFromDeviceConfig() {
String config = DeviceConfig.getString(
DeviceConfig.NAMESPACE_AUTOFILL,
- AutofillManager.DEVICE_CONFIG_AUTOFILL_COMPAT_MODE_ALLOWED_PACKAGES,
+ AutofillFeatureFlags.DEVICE_CONFIG_AUTOFILL_COMPAT_MODE_ALLOWED_PACKAGES,
/* defaultValue */ null);
if (!TextUtils.isEmpty(config)) {
return config;
diff --git a/services/autofill/java/com/android/server/autofill/ui/SaveUi.java b/services/autofill/java/com/android/server/autofill/ui/SaveUi.java
index 677871f..8c2c964 100644
--- a/services/autofill/java/com/android/server/autofill/ui/SaveUi.java
+++ b/services/autofill/java/com/android/server/autofill/ui/SaveUi.java
@@ -357,6 +357,7 @@
params.width = WindowManager.LayoutParams.MATCH_PARENT;
params.accessibilityTitle = context.getString(R.string.autofill_save_accessibility_title);
params.windowAnimations = R.style.AutofillSaveAnimation;
+ params.setTrustedOverlay();
show();
}
diff --git a/services/companion/java/com/android/server/companion/virtual/TEST_MAPPING b/services/companion/java/com/android/server/companion/virtual/TEST_MAPPING
new file mode 100644
index 0000000..279981b
--- /dev/null
+++ b/services/companion/java/com/android/server/companion/virtual/TEST_MAPPING
@@ -0,0 +1,24 @@
+{
+ "presubmit": [
+ {
+ "name": "CtsVirtualDevicesTestCases",
+ "options": [
+ {
+ "exclude-annotation": "androidx.test.filters.FlakyTest"
+ }
+ ]
+ },
+ {
+ "name": "CtsVirtualDevicesTestCases",
+ "options": [
+ {
+ "include-filter": "android.hardware.input.cts.tests"
+ },
+ {
+ "exclude-annotation": "androidx.test.filters.FlakyTest"
+ }
+ ],
+ "file_patterns": ["Virtual[^/]*\\.java"]
+ }
+ ]
+}
diff --git a/services/companion/java/com/android/server/companion/virtual/VirtualDeviceManagerService.java b/services/companion/java/com/android/server/companion/virtual/VirtualDeviceManagerService.java
index 758345f..b0f2464 100644
--- a/services/companion/java/com/android/server/companion/virtual/VirtualDeviceManagerService.java
+++ b/services/companion/java/com/android/server/companion/virtual/VirtualDeviceManagerService.java
@@ -139,15 +139,6 @@
mActivityInterceptorCallback);
}
- @GuardedBy("mVirtualDeviceManagerLock")
- private boolean isValidVirtualDeviceLocked(IVirtualDevice virtualDevice) {
- try {
- return mVirtualDevices.contains(virtualDevice.getDeviceId());
- } catch (RemoteException e) {
- throw e.rethrowFromSystemServer();
- }
- }
-
void onCameraAccessBlocked(int appUid) {
synchronized (mVirtualDeviceManagerLock) {
for (int i = 0; i < mVirtualDevices.size(); i++) {
@@ -347,6 +338,14 @@
return VirtualDeviceManager.DEVICE_ID_DEFAULT;
}
+ // Binder call
+ @Override
+ public boolean isValidVirtualDeviceId(int deviceId) {
+ synchronized (mVirtualDeviceManagerLock) {
+ return mVirtualDevices.contains(deviceId);
+ }
+ }
+
@Override // Binder call
public int getAudioPlaybackSessionId(int deviceId) {
synchronized (mVirtualDeviceManagerLock) {
@@ -445,13 +444,6 @@
private final ArraySet<Integer> mAllUidsOnVirtualDevice = new ArraySet<>();
@Override
- public boolean isValidVirtualDevice(IVirtualDevice virtualDevice) {
- synchronized (mVirtualDeviceManagerLock) {
- return isValidVirtualDeviceLocked(virtualDevice);
- }
- }
-
- @Override
public int getDeviceOwnerUid(int deviceId) {
synchronized (mVirtualDeviceManagerLock) {
VirtualDeviceImpl virtualDevice = mVirtualDevices.get(deviceId);
diff --git a/services/core/Android.bp b/services/core/Android.bp
index 4d53b48..17b6f5d 100644
--- a/services/core/Android.bp
+++ b/services/core/Android.bp
@@ -158,8 +158,8 @@
"android.hardware.health-translate-java",
"android.hardware.light-V1-java",
"android.hardware.tv.cec-V1.1-java",
- "android.hardware.tv.cec-V1-java",
- "android.hardware.tv.hdmi-V1-java",
+ "android.hardware.tv.hdmi.cec-V1-java",
+ "android.hardware.tv.hdmi.connection-V1-java",
"android.hardware.weaver-V1.0-java",
"android.hardware.weaver-V2-java",
"android.hardware.biometrics.face-V1.0-java",
diff --git a/services/core/java/com/android/server/BatteryService.java b/services/core/java/com/android/server/BatteryService.java
index 71a4c73..b41664f 100644
--- a/services/core/java/com/android/server/BatteryService.java
+++ b/services/core/java/com/android/server/BatteryService.java
@@ -189,15 +189,20 @@
private long mLastBatteryLevelChangedSentMs;
private Bundle mBatteryChangedOptions = BroadcastOptions.makeRemovingMatchingFilter(
- new IntentFilter(Intent.ACTION_BATTERY_CHANGED)).toBundle();
+ new IntentFilter(Intent.ACTION_BATTERY_CHANGED)).setDeferUntilActive(true)
+ .toBundle();
private Bundle mPowerConnectedOptions = BroadcastOptions.makeRemovingMatchingFilter(
- new IntentFilter(Intent.ACTION_POWER_DISCONNECTED)).toBundle();
+ new IntentFilter(Intent.ACTION_POWER_DISCONNECTED)).setDeferUntilActive(true)
+ .toBundle();
private Bundle mPowerDisconnectedOptions = BroadcastOptions.makeRemovingMatchingFilter(
- new IntentFilter(Intent.ACTION_POWER_CONNECTED)).toBundle();
+ new IntentFilter(Intent.ACTION_POWER_CONNECTED)).setDeferUntilActive(true)
+ .toBundle();
private Bundle mBatteryLowOptions = BroadcastOptions.makeRemovingMatchingFilter(
- new IntentFilter(Intent.ACTION_BATTERY_OKAY)).toBundle();
+ new IntentFilter(Intent.ACTION_BATTERY_OKAY)).setDeferUntilActive(true)
+ .toBundle();
private Bundle mBatteryOkayOptions = BroadcastOptions.makeRemovingMatchingFilter(
- new IntentFilter(Intent.ACTION_BATTERY_LOW)).toBundle();
+ new IntentFilter(Intent.ACTION_BATTERY_LOW)).setDeferUntilActive(true)
+ .toBundle();
private MetricsLogger mMetricsLogger;
diff --git a/services/core/java/com/android/server/BinaryTransparencyService.java b/services/core/java/com/android/server/BinaryTransparencyService.java
index 9977c1a..68722d2 100644
--- a/services/core/java/com/android/server/BinaryTransparencyService.java
+++ b/services/core/java/com/android/server/BinaryTransparencyService.java
@@ -531,27 +531,30 @@
pw.println("|--> Pre-installed package install location: "
+ origPackageFilepath);
- if (useSha256) {
- String sha256Digest = PackageUtils.computeSha256DigestForLargeFile(
- origPackageFilepath, PackageUtils.createLargeFileBuffer());
- pw.println("|--> Pre-installed package SHA-256 digest: "
- + sha256Digest);
- }
+ if (!origPackageFilepath.equals(APEX_PRELOAD_LOCATION_ERROR)) {
+ if (useSha256) {
+ String sha256Digest = PackageUtils.computeSha256DigestForLargeFile(
+ origPackageFilepath, PackageUtils.createLargeFileBuffer());
+ pw.println("|--> Pre-installed package SHA-256 digest: "
+ + sha256Digest);
+ }
-
- Map<Integer, byte[]> contentDigests = computeApkContentDigest(
- origPackageFilepath);
- if (contentDigests == null) {
- pw.println("ERROR: Failed to compute package content digest for "
- + origPackageFilepath);
- } else {
- for (Map.Entry<Integer, byte[]> entry : contentDigests.entrySet()) {
- Integer algorithmId = entry.getKey();
- byte[] contentDigest = entry.getValue();
- pw.println("|--> Pre-installed package content digest: "
- + HexEncoding.encodeToString(contentDigest, false));
- pw.println("|--> Pre-installed package content digest algorithm: "
- + translateContentDigestAlgorithmIdToString(algorithmId));
+ Map<Integer, byte[]> contentDigests = computeApkContentDigest(
+ origPackageFilepath);
+ if (contentDigests == null) {
+ pw.println("|--> ERROR: Failed to compute package content digest "
+ + "for " + origPackageFilepath);
+ } else {
+ for (Map.Entry<Integer, byte[]> entry : contentDigests.entrySet()) {
+ Integer algorithmId = entry.getKey();
+ byte[] contentDigest = entry.getValue();
+ pw.println("|--> Pre-installed package content digest: "
+ + HexEncoding.encodeToString(contentDigest, false));
+ pw.println("|--> Pre-installed package content digest "
+ + "algorithm: "
+ + translateContentDigestAlgorithmIdToString(
+ algorithmId));
+ }
}
}
}
@@ -865,6 +868,7 @@
boolean printLibraries = false;
boolean useSha256 = false;
boolean printHeaders = true;
+ boolean preloadsOnly = false;
String opt;
while ((opt = getNextOption()) != null) {
switch (opt) {
@@ -882,6 +886,9 @@
case "--no-headers":
printHeaders = false;
break;
+ case "--preloads-only":
+ preloadsOnly = true;
+ break;
default:
pw.println("ERROR: Unknown option: " + opt);
return 1;
@@ -889,7 +896,47 @@
}
if (!verbose && printHeaders) {
- printHeadersHelper("MBA", useSha256, pw);
+ if (preloadsOnly) {
+ printHeadersHelper("Preload", useSha256, pw);
+ } else {
+ printHeadersHelper("MBA", useSha256, pw);
+ }
+ }
+
+ PackageManager pm = mContext.getPackageManager();
+ for (PackageInfo packageInfo : pm.getInstalledPackages(
+ PackageManager.PackageInfoFlags.of(PackageManager.MATCH_FACTORY_ONLY
+ | PackageManager.GET_SIGNING_CERTIFICATES))) {
+ if (packageInfo.signingInfo == null) {
+ PackageInfo origPackageInfo = packageInfo;
+ try {
+ pm.getPackageInfo(packageInfo.packageName,
+ PackageManager.PackageInfoFlags.of(PackageManager.MATCH_ALL
+ | PackageManager.GET_SIGNING_CERTIFICATES));
+ } catch (PackageManager.NameNotFoundException e) {
+ Slog.e(TAG, "Failed to obtain an updated PackageInfo of "
+ + origPackageInfo.packageName);
+ packageInfo = origPackageInfo;
+ }
+ }
+
+ if (verbose && printHeaders) {
+ printHeadersHelper("Preload", useSha256, pw);
+ }
+ pw.print(packageInfo.packageName + ",");
+ pw.print(packageInfo.getLongVersionCode() + ",");
+ printPackageMeasurements(packageInfo, useSha256, pw);
+
+ if (verbose) {
+ printAppDetails(packageInfo, printLibraries, pw);
+ printPackageInstallationInfo(packageInfo, useSha256, pw);
+ printPackageSignerDetails(packageInfo.signingInfo, pw);
+ pw.println("");
+ }
+ }
+
+ if (preloadsOnly) {
+ return 0;
}
for (PackageInfo packageInfo : getNewlyInstalledMbas()) {
if (verbose && printHeaders) {
@@ -909,25 +956,6 @@
return 0;
}
- // TODO(b/259347186): add option handling full file-based SHA256 digest
- private int printAllPreloads() {
- final PrintWriter pw = getOutPrintWriter();
-
- PackageManager pm = mContext.getPackageManager();
- if (pm == null) {
- Slog.e(TAG, "Failed to obtain PackageManager.");
- return -1;
- }
- List<PackageInfo> factoryApps = pm.getInstalledPackages(
- PackageManager.PackageInfoFlags.of(PackageManager.MATCH_FACTORY_ONLY));
-
- pw.println("Preload Info [Format: package_name]");
- for (PackageInfo packageInfo : factoryApps) {
- pw.println(packageInfo.packageName);
- }
- return 0;
- }
-
@Override
public int onCommand(String cmd) {
if (cmd == null) {
@@ -952,8 +980,6 @@
return printAllModules();
case "mba_info":
return printAllMbas();
- case "preload_info":
- return printAllPreloads();
default:
pw.println(String.format("ERROR: Unknown info type '%s'",
infoType));
@@ -981,7 +1007,7 @@
+ "APEX hashes. WARNING: This can be a very slow and CPU-intensive "
+ "computation.");
pw.println(" -v: lists more verbose information about each APEX.");
- pw.println(" --no-headers: does not print the header if specified");
+ pw.println(" --no-headers: does not print the header if specified.");
pw.println("");
pw.println(" get module_info [-o] [-v] [--no-headers]");
pw.println(" Print information about installed modules on device.");
@@ -989,9 +1015,9 @@
+ "module hashes. WARNING: This can be a very slow and "
+ "CPU-intensive computation.");
pw.println(" -v: lists more verbose information about each module.");
- pw.println(" --no-headers: does not print the header if specified");
+ pw.println(" --no-headers: does not print the header if specified.");
pw.println("");
- pw.println(" get mba_info [-o] [-v] [-l] [--no-headers]");
+ pw.println(" get mba_info [-o] [-v] [-l] [--no-headers] [--preloads-only]");
pw.println(" Print information about installed mobile bundle apps "
+ "(MBAs on device).");
pw.println(" -o: also uses the old digest scheme (SHA256) to compute "
@@ -1000,7 +1026,9 @@
pw.println(" -v: lists more verbose information about each app.");
pw.println(" -l: lists shared library info. (This option only works "
+ "when -v option is also specified)");
- pw.println(" --no-headers: does not print the header if specified");
+ pw.println(" --no-headers: does not print the header if specified.");
+ pw.println(" --preloads-only: lists only preloaded apps. This options can "
+ + "also be combined with others.");
pw.println("");
}
diff --git a/services/core/java/com/android/server/am/ActiveServices.java b/services/core/java/com/android/server/am/ActiveServices.java
index bcea40e5..ece7254 100644
--- a/services/core/java/com/android/server/am/ActiveServices.java
+++ b/services/core/java/com/android/server/am/ActiveServices.java
@@ -3181,7 +3181,8 @@
int bindServiceLocked(IApplicationThread caller, IBinder token, Intent service,
String resolvedType, final IServiceConnection connection, int flags,
String instanceName, boolean isSdkSandboxService, int sdkSandboxClientAppUid,
- String sdkSandboxClientAppPackage, String callingPackage, final int userId)
+ String sdkSandboxClientAppPackage, IApplicationThread sdkSandboxClientApplicationThread,
+ String callingPackage, final int userId)
throws TransactionTooLargeException {
if (DEBUG_SERVICE) Slog.v(TAG_SERVICE, "bindService: " + service
+ " type=" + resolvedType + " conn=" + connection.asBinder()
@@ -3271,6 +3272,10 @@
final boolean allowInstant = (flags & Context.BIND_ALLOW_INSTANT) != 0;
final boolean inSharedIsolatedProcess = (flags & Context.BIND_SHARED_ISOLATED_PROCESS) != 0;
+ ProcessRecord attributedApp = null;
+ if (sdkSandboxClientAppUid > 0) {
+ attributedApp = mAm.getRecordForAppLOSP(sdkSandboxClientApplicationThread);
+ }
ServiceLookupResult res = retrieveServiceLocked(service, instanceName,
isSdkSandboxService, sdkSandboxClientAppUid, sdkSandboxClientAppPackage,
resolvedType, callingPackage, callingPid, callingUid, userId, true, callerFg,
@@ -3283,7 +3288,7 @@
return -1;
}
ServiceRecord s = res.record;
- final AppBindRecord b = s.retrieveAppBindingLocked(service, callerApp);
+ final AppBindRecord b = s.retrieveAppBindingLocked(service, callerApp, attributedApp);
final ProcessServiceRecord clientPsr = b.client.mServices;
if (clientPsr.numberOfConnections() >= mAm.mConstants.mMaxServiceConnectionsPerProcess) {
Slog.w(TAG, "bindService exceeded max service connection number per process, "
diff --git a/services/core/java/com/android/server/am/ActivityManagerLocal.java b/services/core/java/com/android/server/am/ActivityManagerLocal.java
index 5175a31..fa0972a 100644
--- a/services/core/java/com/android/server/am/ActivityManagerLocal.java
+++ b/services/core/java/com/android/server/am/ActivityManagerLocal.java
@@ -76,6 +76,8 @@
* @param conn Receives information as the service is started and stopped.
* This must be a valid ServiceConnection object; it must not be null.
* @param clientAppUid Uid of the app for which the sdk sandbox process needs to be spawned.
+ * @param clientApplicationThread ApplicationThread object of the app for which the sdk sandboox
+ * is spawned.
* @param clientAppPackage Package of the app for which the sdk sandbox process needs to
* be spawned. This package must belong to the clientAppUid.
* @param processName Unique identifier for the service instance. Each unique name here will
@@ -91,6 +93,19 @@
*/
@SuppressLint("RethrowRemoteException")
boolean bindSdkSandboxService(@NonNull Intent service, @NonNull ServiceConnection conn,
+ int clientAppUid, @NonNull IBinder clientApplicationThread,
+ @NonNull String clientAppPackage, @NonNull String processName,
+ @Context.BindServiceFlags int flags)
+ throws RemoteException;
+
+ /**
+ * @deprecated Please use
+ * {@link #bindSdkSandboxService(Intent, ServiceConnection, int, IBinder, String, String, int)}
+ *
+ * This API can't be deleted yet because it can be used by early AdService module versions.
+ */
+ @SuppressLint("RethrowRemoteException")
+ boolean bindSdkSandboxService(@NonNull Intent service, @NonNull ServiceConnection conn,
int clientAppUid, @NonNull String clientAppPackage, @NonNull String processName,
@Context.BindServiceFlags int flags)
throws RemoteException;
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index fc6d30b..a386baf 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -159,6 +159,8 @@
import android.Manifest.permission;
import android.annotation.NonNull;
import android.annotation.Nullable;
+import android.annotation.PermissionMethod;
+import android.annotation.PermissionName;
import android.annotation.UserIdInt;
import android.app.Activity;
import android.app.ActivityClient;
@@ -251,8 +253,6 @@
import android.content.pm.PackageManagerInternal;
import android.content.pm.ParceledListSlice;
import android.content.pm.PermissionInfo;
-import android.content.pm.PermissionMethod;
-import android.content.pm.PermissionName;
import android.content.pm.ProcessInfo;
import android.content.pm.ProviderInfo;
import android.content.pm.ProviderInfoList;
@@ -399,7 +399,6 @@
import com.android.server.LocalManagerRegistry;
import com.android.server.LocalServices;
import com.android.server.LockGuard;
-import com.android.server.NetworkManagementInternal;
import com.android.server.PackageWatchdog;
import com.android.server.ServiceThread;
import com.android.server.SystemConfig;
@@ -417,6 +416,7 @@
import com.android.server.firewall.IntentFirewall;
import com.android.server.graphics.fonts.FontManagerInternal;
import com.android.server.job.JobSchedulerInternal;
+import com.android.server.net.NetworkManagementInternal;
import com.android.server.os.NativeTombstoneManager;
import com.android.server.pm.Computer;
import com.android.server.pm.Installer;
@@ -13107,13 +13107,15 @@
String resolvedType, IServiceConnection connection, int flags, String instanceName,
String callingPackage, int userId) throws TransactionTooLargeException {
return bindServiceInstance(caller, token, service, resolvedType, connection, flags,
- instanceName, false, INVALID_UID, null, callingPackage, userId);
+ instanceName, false, INVALID_UID, null, null, callingPackage, userId);
}
private int bindServiceInstance(IApplicationThread caller, IBinder token, Intent service,
String resolvedType, IServiceConnection connection, int flags, String instanceName,
boolean isSdkSandboxService, int sdkSandboxClientAppUid,
- String sdkSandboxClientAppPackage, String callingPackage, int userId)
+ String sdkSandboxClientAppPackage,
+ IApplicationThread sdkSandboxClientApplicationThread,
+ String callingPackage, int userId)
throws TransactionTooLargeException {
enforceNotIsolatedCaller("bindService");
enforceAllowedToStartOrBindServiceIfSdkSandbox(service);
@@ -13152,7 +13154,8 @@
synchronized (this) {
return mServices.bindServiceLocked(caller, token, service, resolvedType, connection,
flags, instanceName, isSdkSandboxService, sdkSandboxClientAppUid,
- sdkSandboxClientAppPackage, callingPackage, userId);
+ sdkSandboxClientAppPackage, sdkSandboxClientApplicationThread,
+ callingPackage, userId);
}
} finally {
Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
@@ -13517,12 +13520,17 @@
public Intent registerReceiverWithFeature(IApplicationThread caller, String callerPackage,
String callerFeatureId, String receiverId, IIntentReceiver receiver,
IntentFilter filter, String permission, int userId, int flags) {
+ enforceNotIsolatedCaller("registerReceiver");
+
// Allow Sandbox process to register only unexported receivers.
- if ((flags & Context.RECEIVER_NOT_EXPORTED) != 0) {
- enforceNotIsolatedCaller("registerReceiver");
- } else if (mSdkSandboxSettings.isBroadcastReceiverRestrictionsEnforced()) {
- enforceNotIsolatedOrSdkSandboxCaller("registerReceiver");
+ boolean unexported = (flags & Context.RECEIVER_NOT_EXPORTED) != 0;
+ if (mSdkSandboxSettings.isBroadcastReceiverRestrictionsEnforced()
+ && Process.isSdkSandboxUid(Binder.getCallingUid())
+ && !unexported) {
+ throw new SecurityException("SDK sandbox process not allowed to call "
+ + "registerReceiver");
}
+
ArrayList<Intent> stickyIntents = null;
ProcessRecord callerApp = null;
final boolean visibleToInstantApps
@@ -14108,8 +14116,16 @@
if (DEBUG_BROADCAST_LIGHT) Slog.v(TAG_BROADCAST,
(sticky ? "Broadcast sticky: ": "Broadcast: ") + intent
+ " ordered=" + ordered + " userid=" + userId);
- if ((resultTo != null) && !ordered && !mEnableModernQueue) {
- Slog.w(TAG, "Broadcast " + intent + " not ordered but result callback requested!");
+ if ((resultTo != null) && !ordered) {
+ if (!mEnableModernQueue) {
+ Slog.w(TAG, "Broadcast " + intent + " not ordered but result callback requested!");
+ }
+ if (!UserHandle.isCore(callingUid)) {
+ String msg = "Unauthorized unordered resultTo broadcast "
+ + intent + " sent from uid " + callingUid;
+ Slog.w(TAG, msg);
+ throw new SecurityException(msg);
+ }
}
userId = mUserController.handleIncomingUser(callingPid, callingUid, userId, true,
@@ -14190,6 +14206,18 @@
}
}
+ // resultTo broadcasts are always infinitely deferrable.
+ if ((resultTo != null) && !ordered && mEnableModernQueue) {
+ if (brOptions == null) {
+ brOptions = BroadcastOptions.makeBasic();
+ }
+ brOptions.setDeferUntilActive(true);
+ }
+
+ if (ordered && brOptions != null && brOptions.isDeferUntilActive()) {
+ throw new IllegalArgumentException("Ordered broadcasts can't be deferred until active");
+ }
+
// Verify that protected broadcasts are only being sent by system code,
// and that system code is only sending protected broadcasts.
final boolean isProtectedBroadcast;
@@ -16939,7 +16967,8 @@
@Override
public boolean bindSdkSandboxService(Intent service, ServiceConnection conn,
- int clientAppUid, String clientAppPackage, String processName, int flags)
+ int clientAppUid, IBinder clientApplicationThread, String clientAppPackage,
+ String processName, int flags)
throws RemoteException {
if (service == null) {
throw new IllegalArgumentException("intent is null");
@@ -16964,14 +16993,40 @@
}
Handler handler = mContext.getMainThreadHandler();
-
+ IApplicationThread clientApplicationThreadVerified = null;
+ if (clientApplicationThread != null) {
+ // Make sure this is a valid application process
+ synchronized (this) {
+ final ProcessRecord rec = getRecordForAppLOSP(clientApplicationThread);
+ if (rec == null) {
+ // This could happen if the calling process has disappeared; no need for the
+ // sandbox to be even started in this case.
+ Slog.i(TAG, "clientApplicationThread process not found.");
+ return false;
+ }
+ if (rec.info.uid != clientAppUid) {
+ throw new IllegalArgumentException("clientApplicationThread does not match "
+ + " client uid");
+ }
+ clientApplicationThreadVerified = rec.getThread();
+ }
+ }
final IServiceConnection sd = mContext.getServiceDispatcher(conn, handler, flags);
service.prepareToLeaveProcess(mContext);
return ActivityManagerService.this.bindServiceInstance(
mContext.getIApplicationThread(), mContext.getActivityToken(), service,
service.resolveTypeIfNeeded(mContext.getContentResolver()), sd, flags,
processName, /*isSdkSandboxService*/ true, clientAppUid, clientAppPackage,
- mContext.getOpPackageName(), UserHandle.getUserId(clientAppUid)) != 0;
+ clientApplicationThreadVerified, mContext.getOpPackageName(),
+ UserHandle.getUserId(clientAppUid)) != 0;
+ }
+
+ @Override
+ public boolean bindSdkSandboxService(Intent service, ServiceConnection conn,
+ int clientAppUid, String clientAppPackage, String processName, int flags)
+ throws RemoteException {
+ return bindSdkSandboxService(service, conn, clientAppUid,
+ null /* clientApplicationThread */, clientAppPackage, processName, flags);
}
@Override
diff --git a/services/core/java/com/android/server/am/ActivityManagerShellCommand.java b/services/core/java/com/android/server/am/ActivityManagerShellCommand.java
index 80684bf..788c81c 100644
--- a/services/core/java/com/android/server/am/ActivityManagerShellCommand.java
+++ b/services/core/java/com/android/server/am/ActivityManagerShellCommand.java
@@ -2153,19 +2153,24 @@
boolean success;
String displaySuffix;
- if (displayId == Display.INVALID_DISPLAY) {
- success = mInterface.startUserInBackgroundWithListener(userId, waiter);
- displaySuffix = "";
- } else {
- if (!UserManager.isVisibleBackgroundUsersEnabled()) {
- pw.println("Not supported");
- return -1;
+ Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "shell_runStartUser" + userId);
+ try {
+ if (displayId == Display.INVALID_DISPLAY) {
+ success = mInterface.startUserInBackgroundWithListener(userId, waiter);
+ displaySuffix = "";
+ } else {
+ if (!UserManager.isVisibleBackgroundUsersEnabled()) {
+ pw.println("Not supported");
+ return -1;
+ }
+ success = mInterface.startUserInBackgroundVisibleOnDisplay(userId, displayId);
+ displaySuffix = " on display " + displayId;
}
- success = mInterface.startUserInBackgroundVisibleOnDisplay(userId, displayId);
- displaySuffix = " on display " + displayId;
- }
- if (wait && success) {
- success = waiter.waitForFinish(USER_OPERATION_TIMEOUT_MS);
+ if (wait && success) {
+ success = waiter.waitForFinish(USER_OPERATION_TIMEOUT_MS);
+ }
+ } finally {
+ Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
}
if (success) {
diff --git a/services/core/java/com/android/server/am/AppBindRecord.java b/services/core/java/com/android/server/am/AppBindRecord.java
index 28756a4..f7b3d3a 100644
--- a/services/core/java/com/android/server/am/AppBindRecord.java
+++ b/services/core/java/com/android/server/am/AppBindRecord.java
@@ -28,13 +28,15 @@
final ServiceRecord service; // The running service.
final IntentBindRecord intent; // The intent we are bound to.
final ProcessRecord client; // Who has started/bound the service.
-
+ final ProcessRecord attributedClient; // The binding was done by the system on behalf
+ // of 'attributedClient'
final ArraySet<ConnectionRecord> connections = new ArraySet<>();
// All ConnectionRecord for this client.
void dump(PrintWriter pw, String prefix) {
pw.println(prefix + "service=" + service);
pw.println(prefix + "client=" + client);
+ pw.println(prefix + "attributedClient=" + attributedClient);
dumpInIntentBind(pw, prefix);
}
@@ -50,10 +52,11 @@
}
AppBindRecord(ServiceRecord _service, IntentBindRecord _intent,
- ProcessRecord _client) {
+ ProcessRecord _client, ProcessRecord _attributedClient) {
service = _service;
intent = _intent;
client = _client;
+ attributedClient = _attributedClient;
}
public String toString() {
diff --git a/services/core/java/com/android/server/am/BroadcastProcessQueue.java b/services/core/java/com/android/server/am/BroadcastProcessQueue.java
index fa7748b..41d9a11 100644
--- a/services/core/java/com/android/server/am/BroadcastProcessQueue.java
+++ b/services/core/java/com/android/server/am/BroadcastProcessQueue.java
@@ -62,6 +62,7 @@
*/
// @NotThreadSafe
class BroadcastProcessQueue {
+ static final boolean VERBOSE = false;
final @NonNull BroadcastConstants constants;
final @NonNull String processName;
final int uid;
@@ -168,10 +169,14 @@
/**
* Count of pending broadcasts of these various flavors.
*/
+ private int mCountEnqueued;
+ private int mCountDeferred;
private int mCountForeground;
+ private int mCountForegroundDeferred;
private int mCountOrdered;
private int mCountAlarm;
private int mCountPrioritized;
+ private int mCountPrioritizedDeferred;
private int mCountInteractive;
private int mCountResultTo;
private int mCountInstrumented;
@@ -226,10 +231,10 @@
* used for ordered broadcasts and priority traunches.
*/
public void enqueueOrReplaceBroadcast(@NonNull BroadcastRecord record, int recordIndex,
- @NonNull BroadcastConsumer replacedBroadcastConsumer) {
+ @NonNull BroadcastConsumer replacedBroadcastConsumer, boolean wouldBeSkipped) {
if (record.isReplacePending()) {
final boolean didReplace = replaceBroadcast(record, recordIndex,
- replacedBroadcastConsumer);
+ replacedBroadcastConsumer, wouldBeSkipped);
if (didReplace) {
return;
}
@@ -240,13 +245,14 @@
SomeArgs newBroadcastArgs = SomeArgs.obtain();
newBroadcastArgs.arg1 = record;
newBroadcastArgs.argi1 = recordIndex;
+ newBroadcastArgs.argi2 = (wouldBeSkipped ? 1 : 0);
// Cross-broadcast prioritization policy: some broadcasts might warrant being
// issued ahead of others that are already pending, for example if this new
// broadcast is in a different delivery class or is tied to a direct user interaction
// with implicit responsiveness expectations.
getQueueForBroadcast(record).addLast(newBroadcastArgs);
- onBroadcastEnqueued(record, recordIndex);
+ onBroadcastEnqueued(record, recordIndex, wouldBeSkipped);
}
/**
@@ -258,11 +264,12 @@
* {@code false} otherwise.
*/
private boolean replaceBroadcast(@NonNull BroadcastRecord record, int recordIndex,
- @NonNull BroadcastConsumer replacedBroadcastConsumer) {
+ @NonNull BroadcastConsumer replacedBroadcastConsumer, boolean wouldBeSkipped) {
final int count = mPendingQueues.size();
for (int i = 0; i < count; ++i) {
final ArrayDeque<SomeArgs> queue = mPendingQueues.get(i);
- if (replaceBroadcastInQueue(queue, record, recordIndex, replacedBroadcastConsumer)) {
+ if (replaceBroadcastInQueue(queue, record, recordIndex,
+ replacedBroadcastConsumer, wouldBeSkipped)) {
return true;
}
}
@@ -279,13 +286,15 @@
*/
private boolean replaceBroadcastInQueue(@NonNull ArrayDeque<SomeArgs> queue,
@NonNull BroadcastRecord record, int recordIndex,
- @NonNull BroadcastConsumer replacedBroadcastConsumer) {
+ @NonNull BroadcastConsumer replacedBroadcastConsumer,
+ boolean wouldBeSkipped) {
final Iterator<SomeArgs> it = queue.descendingIterator();
final Object receiver = record.receivers.get(recordIndex);
while (it.hasNext()) {
final SomeArgs args = it.next();
final BroadcastRecord testRecord = (BroadcastRecord) args.arg1;
final int testRecordIndex = args.argi1;
+ final boolean testWouldBeSkipped = (args.argi2 == 1);
final Object testReceiver = testRecord.receivers.get(testRecordIndex);
if ((record.callingUid == testRecord.callingUid)
&& (record.userId == testRecord.userId)
@@ -295,9 +304,10 @@
// Exact match found; perform in-place swap
args.arg1 = record;
args.argi1 = recordIndex;
+ args.argi2 = (wouldBeSkipped ? 1 : 0);
record.copyEnqueueTimeFrom(testRecord);
- onBroadcastDequeued(testRecord, testRecordIndex);
- onBroadcastEnqueued(record, recordIndex);
+ onBroadcastDequeued(testRecord, testRecordIndex, testWouldBeSkipped);
+ onBroadcastEnqueued(record, recordIndex, wouldBeSkipped);
replacedBroadcastConsumer.accept(testRecord, testRecordIndex);
return true;
}
@@ -352,12 +362,13 @@
final SomeArgs args = it.next();
final BroadcastRecord record = (BroadcastRecord) args.arg1;
final int recordIndex = args.argi1;
+ final boolean recordWouldBeSkipped = (args.argi2 == 1);
if (predicate.test(record, recordIndex)) {
consumer.accept(record, recordIndex);
if (andRemove) {
args.recycle();
it.remove();
- onBroadcastDequeued(record, recordIndex);
+ onBroadcastDequeued(record, recordIndex, recordWouldBeSkipped);
}
didSomething = true;
}
@@ -423,7 +434,7 @@
}
public int getPreferredSchedulingGroupLocked() {
- if (mCountForeground > 0) {
+ if (mCountForeground > mCountForegroundDeferred) {
// We have a foreground broadcast somewhere down the queue, so
// boost priority until we drain them all
return ProcessList.SCHED_GROUP_DEFAULT;
@@ -469,10 +480,11 @@
final SomeArgs next = removeNextBroadcast();
mActive = (BroadcastRecord) next.arg1;
mActiveIndex = next.argi1;
+ final boolean wouldBeSkipped = (next.argi2 == 1);
mActiveCountSinceIdle++;
mActiveViaColdStart = false;
next.recycle();
- onBroadcastDequeued(mActive, mActiveIndex);
+ onBroadcastDequeued(mActive, mActiveIndex, wouldBeSkipped);
}
/**
@@ -489,8 +501,16 @@
/**
* Update summary statistics when the given record has been enqueued.
*/
- private void onBroadcastEnqueued(@NonNull BroadcastRecord record, int recordIndex) {
+ private void onBroadcastEnqueued(@NonNull BroadcastRecord record, int recordIndex,
+ boolean wouldBeSkipped) {
+ mCountEnqueued++;
+ if (record.deferUntilActive) {
+ mCountDeferred++;
+ }
if (record.isForeground()) {
+ if (record.deferUntilActive) {
+ mCountForegroundDeferred++;
+ }
mCountForeground++;
}
if (record.ordered) {
@@ -500,6 +520,9 @@
mCountAlarm++;
}
if (record.prioritized) {
+ if (record.deferUntilActive) {
+ mCountPrioritizedDeferred++;
+ }
mCountPrioritized++;
}
if (record.interactive) {
@@ -511,7 +534,8 @@
if (record.callerInstrumented) {
mCountInstrumented++;
}
- if (record.receivers.get(recordIndex) instanceof ResolveInfo) {
+ if (!wouldBeSkipped
+ && (record.receivers.get(recordIndex) instanceof ResolveInfo)) {
mCountManifest++;
}
invalidateRunnableAt();
@@ -520,8 +544,16 @@
/**
* Update summary statistics when the given record has been dequeued.
*/
- private void onBroadcastDequeued(@NonNull BroadcastRecord record, int recordIndex) {
+ private void onBroadcastDequeued(@NonNull BroadcastRecord record, int recordIndex,
+ boolean wouldBeSkipped) {
+ mCountEnqueued--;
+ if (record.deferUntilActive) {
+ mCountDeferred--;
+ }
if (record.isForeground()) {
+ if (record.deferUntilActive) {
+ mCountForegroundDeferred--;
+ }
mCountForeground--;
}
if (record.ordered) {
@@ -531,6 +563,9 @@
mCountAlarm--;
}
if (record.prioritized) {
+ if (record.deferUntilActive) {
+ mCountPrioritizedDeferred--;
+ }
mCountPrioritized--;
}
if (record.interactive) {
@@ -542,7 +577,8 @@
if (record.callerInstrumented) {
mCountInstrumented--;
}
- if (record.receivers.get(recordIndex) instanceof ResolveInfo) {
+ if (!wouldBeSkipped
+ && (record.receivers.get(recordIndex) instanceof ResolveInfo)) {
mCountManifest--;
}
invalidateRunnableAt();
@@ -741,6 +777,15 @@
return mRunnableAt != Long.MAX_VALUE;
}
+ public boolean isDeferredUntilActive() {
+ if (mRunnableAtInvalidated) updateRunnableAt();
+ return mRunnableAtReason == BroadcastProcessQueue.REASON_CACHED_INFINITE_DEFER;
+ }
+
+ public boolean hasDeferredBroadcasts() {
+ return (mCountDeferred > 0);
+ }
+
/**
* Return time at which this process is considered runnable. This is
* typically the time at which the next pending broadcast was first
@@ -776,6 +821,7 @@
static final int REASON_INSTRUMENTED = 5;
static final int REASON_PERSISTENT = 6;
static final int REASON_FORCE_DELAYED = 7;
+ static final int REASON_CACHED_INFINITE_DEFER = 8;
static final int REASON_CONTAINS_FOREGROUND = 10;
static final int REASON_CONTAINS_ORDERED = 11;
static final int REASON_CONTAINS_ALARM = 12;
@@ -794,6 +840,7 @@
REASON_INSTRUMENTED,
REASON_PERSISTENT,
REASON_FORCE_DELAYED,
+ REASON_CACHED_INFINITE_DEFER,
REASON_CONTAINS_FOREGROUND,
REASON_CONTAINS_ORDERED,
REASON_CONTAINS_ALARM,
@@ -816,6 +863,7 @@
case REASON_INSTRUMENTED: return "INSTRUMENTED";
case REASON_PERSISTENT: return "PERSISTENT";
case REASON_FORCE_DELAYED: return "FORCE_DELAYED";
+ case REASON_CACHED_INFINITE_DEFER: return "INFINITE_DEFER";
case REASON_CONTAINS_FOREGROUND: return "CONTAINS_FOREGROUND";
case REASON_CONTAINS_ORDERED: return "CONTAINS_ORDERED";
case REASON_CONTAINS_ALARM: return "CONTAINS_ALARM";
@@ -831,9 +879,16 @@
private boolean blockedOnOrderedDispatch(BroadcastRecord r, int index) {
final int blockedUntilTerminalCount = r.blockedUntilTerminalCount[index];
+ int existingDeferredCount = 0;
+ if (r.deferUntilActive) {
+ for (int i = 0; i < index; i++) {
+ if (r.deferredUntilActive[i]) existingDeferredCount++;
+ }
+ }
+
// We might be blocked waiting for other receivers to finish,
// typically for an ordered broadcast or priority traunches
- if (r.terminalCount < blockedUntilTerminalCount
+ if ((r.terminalCount + existingDeferredCount) < blockedUntilTerminalCount
&& !isDeliveryStateTerminal(r.getDeliveryState(index))) {
return true;
}
@@ -862,7 +917,7 @@
if (mForcedDelayedDurationMs > 0) {
mRunnableAt = runnableAt + mForcedDelayedDurationMs;
mRunnableAtReason = REASON_FORCE_DELAYED;
- } else if (mCountForeground > 0) {
+ } else if (mCountForeground > mCountForegroundDeferred) {
mRunnableAt = runnableAt + constants.DELAY_URGENT_MILLIS;
mRunnableAtReason = REASON_CONTAINS_FOREGROUND;
} else if (mCountInteractive > 0) {
@@ -880,12 +935,9 @@
} else if (mCountAlarm > 0) {
mRunnableAt = runnableAt;
mRunnableAtReason = REASON_CONTAINS_ALARM;
- } else if (mCountPrioritized > 0) {
+ } else if (mCountPrioritized > mCountPrioritizedDeferred) {
mRunnableAt = runnableAt;
mRunnableAtReason = REASON_CONTAINS_PRIORITIZED;
- } else if (mCountResultTo > 0) {
- mRunnableAt = runnableAt;
- mRunnableAtReason = REASON_CONTAINS_RESULT_TO;
} else if (mCountManifest > 0) {
mRunnableAt = runnableAt;
mRunnableAtReason = REASON_CONTAINS_MANIFEST;
@@ -893,8 +945,39 @@
mRunnableAt = runnableAt;
mRunnableAtReason = REASON_PERSISTENT;
} else if (mProcessCached) {
- mRunnableAt = runnableAt + constants.DELAY_CACHED_MILLIS;
- mRunnableAtReason = REASON_CACHED;
+ if (r.deferUntilActive) {
+ // All enqueued broadcasts are deferrable, defer
+ if (mCountDeferred == mCountEnqueued) {
+ mRunnableAt = Long.MAX_VALUE;
+ mRunnableAtReason = REASON_CACHED_INFINITE_DEFER;
+ } else {
+ // At least one enqueued broadcast isn't deferrable, repick time and reason
+ // for this record. If a later record is not deferrable and is one of these
+ // special cases, one of the cases above would have already caught that.
+ if (r.isForeground()) {
+ mRunnableAt = runnableAt + constants.DELAY_URGENT_MILLIS;
+ mRunnableAtReason = REASON_CONTAINS_FOREGROUND;
+ } else if (r.prioritized) {
+ mRunnableAt = runnableAt;
+ mRunnableAtReason = REASON_CONTAINS_PRIORITIZED;
+ } else if (r.resultTo != null) {
+ mRunnableAt = runnableAt;
+ mRunnableAtReason = REASON_CONTAINS_RESULT_TO;
+ } else {
+ mRunnableAt = runnableAt + constants.DELAY_CACHED_MILLIS;
+ mRunnableAtReason = REASON_CACHED;
+ }
+ }
+ } else {
+ // This record isn't deferrable
+ mRunnableAt = runnableAt + constants.DELAY_CACHED_MILLIS;
+ mRunnableAtReason = REASON_CACHED;
+ }
+ } else if (mCountResultTo > 0) {
+ // All resultTo broadcasts are infinitely deferrable, so if the app
+ // is already cached, they'll be deferred on the line above
+ mRunnableAt = runnableAt;
+ mRunnableAtReason = REASON_CONTAINS_RESULT_TO;
} else {
mRunnableAt = runnableAt + constants.DELAY_NORMAL_MILLIS;
mRunnableAtReason = REASON_NORMAL;
@@ -907,6 +990,15 @@
mRunnableAt = Math.min(mRunnableAt, runnableAt);
mRunnableAtReason = REASON_MAX_PENDING;
}
+
+ if (VERBOSE) {
+ Trace.instantForTrack(Trace.TRACE_TAG_ACTIVITY_MANAGER, "BroadcastQueue",
+ ((app != null) ? app.processName : "(null)")
+ + ":" + r.intent.toString() + ":"
+ + r.deferUntilActive
+ + ":" + mRunnableAt + " " + reasonToString(mRunnableAtReason)
+ + ":" + ((app != null) ? app.isCached() : "false"));
+ }
} else {
mRunnableAt = Long.MAX_VALUE;
mRunnableAtReason = REASON_EMPTY;
diff --git a/services/core/java/com/android/server/am/BroadcastQueueModernImpl.java b/services/core/java/com/android/server/am/BroadcastQueueModernImpl.java
index a994b1d..d819bfc 100644
--- a/services/core/java/com/android/server/am/BroadcastQueueModernImpl.java
+++ b/services/core/java/com/android/server/am/BroadcastQueueModernImpl.java
@@ -385,6 +385,8 @@
// If app isn't running, and there's nothing in the queue, clean up
if (queue.isEmpty() && !queue.isActive() && !queue.isProcessWarm()) {
removeProcessQueue(queue.processName, queue.uid);
+ } else {
+ updateQueueDeferred(queue);
}
}
@@ -637,11 +639,34 @@
final ArraySet<BroadcastRecord> replacedBroadcasts = new ArraySet<>();
final BroadcastConsumer replacedBroadcastConsumer =
(record, i) -> replacedBroadcasts.add(record);
+ boolean enqueuedBroadcast = false;
+
for (int i = 0; i < r.receivers.size(); i++) {
final Object receiver = r.receivers.get(i);
final BroadcastProcessQueue queue = getOrCreateProcessQueue(
getReceiverProcessName(receiver), getReceiverUid(receiver));
- queue.enqueueOrReplaceBroadcast(r, i, replacedBroadcastConsumer);
+
+ boolean wouldBeSkipped = false;
+ if (receiver instanceof ResolveInfo) {
+ // If the app is running but would not have been started if the process weren't
+ // running, we're going to deliver the broadcast but mark that it's not a manifest
+ // broadcast that would have started the app. This allows BroadcastProcessQueue to
+ // defer the broadcast as though it were a normal runtime receiver.
+ wouldBeSkipped = (mSkipPolicy.shouldSkipMessage(r, receiver) != null);
+ if (wouldBeSkipped && queue.app == null && !queue.getActiveViaColdStart()) {
+ // Skip receiver if there's no running app, the app is not being started, and
+ // the app wouldn't be launched for this broadcast
+ setDeliveryState(null, null, r, i, receiver, BroadcastRecord.DELIVERY_SKIPPED,
+ "skipped by policy to avoid cold start");
+ continue;
+ }
+ }
+ enqueuedBroadcast = true;
+ queue.enqueueOrReplaceBroadcast(r, i, replacedBroadcastConsumer, wouldBeSkipped);
+ if (r.isDeferUntilActive() && queue.isDeferredUntilActive()) {
+ setDeliveryState(queue, null, r, i, receiver, BroadcastRecord.DELIVERY_DEFERRED,
+ "deferred at enqueue time");
+ }
updateRunnableList(queue);
enqueueUpdateRunningList();
}
@@ -651,7 +676,7 @@
skipAndCancelReplacedBroadcasts(replacedBroadcasts);
// If nothing to dispatch, send any pending result immediately
- if (r.receivers.isEmpty()) {
+ if (r.receivers.isEmpty() || !enqueuedBroadcast) {
scheduleResultTo(r);
notifyFinishBroadcast(r);
}
@@ -1195,11 +1220,19 @@
@NonNull Object receiver, @DeliveryState int newDeliveryState, String reason) {
final int cookie = traceBegin("setDeliveryState");
final int oldDeliveryState = getDeliveryState(r, index);
+ boolean checkFinished = false;
// Only apply state when we haven't already reached a terminal state;
// this is how we ignore racing timeout messages
if (!isDeliveryStateTerminal(oldDeliveryState)) {
r.setDeliveryState(index, newDeliveryState);
+ if (oldDeliveryState == BroadcastRecord.DELIVERY_DEFERRED) {
+ r.deferredCount--;
+ } else if (newDeliveryState == BroadcastRecord.DELIVERY_DEFERRED) {
+ // If we're deferring a broadcast, maybe that's enough to unblock the final callback
+ r.deferredCount++;
+ checkFinished = true;
+ }
}
// Emit any relevant tracing results when we're changing the delivery
@@ -1217,7 +1250,8 @@
// bookkeeping to update for ordered broadcasts
if (!isDeliveryStateTerminal(oldDeliveryState)
&& isDeliveryStateTerminal(newDeliveryState)) {
- if (newDeliveryState != BroadcastRecord.DELIVERY_DELIVERED) {
+ if (DEBUG_BROADCAST
+ && newDeliveryState != BroadcastRecord.DELIVERY_DELIVERED) {
logw("Delivery state of " + r + " to " + receiver
+ " via " + app + " changed from "
+ deliveryStateToString(oldDeliveryState) + " to "
@@ -1226,9 +1260,12 @@
r.terminalCount++;
notifyFinishReceiver(queue, r, index, receiver);
-
- // When entire ordered broadcast finished, deliver final result
- final boolean recordFinished = (r.terminalCount == r.receivers.size());
+ checkFinished = true;
+ }
+ // When entire ordered broadcast finished, deliver final result
+ if (checkFinished) {
+ final boolean recordFinished =
+ ((r.terminalCount + r.deferredCount) == r.receivers.size());
if (recordFinished) {
scheduleResultTo(r);
}
@@ -1329,6 +1366,16 @@
r.resultExtras = null;
};
+ private final BroadcastConsumer mBroadcastConsumerDefer = (r, i) -> {
+ setDeliveryState(null, null, r, i, r.receivers.get(i), BroadcastRecord.DELIVERY_DEFERRED,
+ "mBroadcastConsumerDefer");
+ };
+
+ private final BroadcastConsumer mBroadcastConsumerUndoDefer = (r, i) -> {
+ setDeliveryState(null, null, r, i, r.receivers.get(i), BroadcastRecord.DELIVERY_PENDING,
+ "mBroadcastConsumerUndoDefer");
+ };
+
/**
* Verify that all known {@link #mProcessQueues} are in the state tested by
* the given {@link Predicate}.
@@ -1392,6 +1439,21 @@
}
}
+ private void updateQueueDeferred(
+ @NonNull BroadcastProcessQueue leaf) {
+ if (leaf.isDeferredUntilActive()) {
+ leaf.forEachMatchingBroadcast((r, i) -> {
+ return r.deferUntilActive && (r.getDeliveryState(i)
+ == BroadcastRecord.DELIVERY_PENDING);
+ }, mBroadcastConsumerDefer, false);
+ } else if (leaf.hasDeferredBroadcasts()) {
+ leaf.forEachMatchingBroadcast((r, i) -> {
+ return r.deferUntilActive && (r.getDeliveryState(i)
+ == BroadcastRecord.DELIVERY_DEFERRED);
+ }, mBroadcastConsumerUndoDefer, false);
+ }
+ }
+
@Override
public void start(@NonNull ContentResolver resolver) {
mFgConstants.startObserving(mHandler, resolver);
@@ -1404,6 +1466,7 @@
BroadcastProcessQueue leaf = mProcessQueues.get(uid);
while (leaf != null) {
leaf.setProcessCached(cached);
+ updateQueueDeferred(leaf);
updateRunnableList(leaf);
leaf = leaf.processNameNext;
}
diff --git a/services/core/java/com/android/server/am/BroadcastRecord.java b/services/core/java/com/android/server/am/BroadcastRecord.java
index 1d4d425..9679fb8 100644
--- a/services/core/java/com/android/server/am/BroadcastRecord.java
+++ b/services/core/java/com/android/server/am/BroadcastRecord.java
@@ -88,6 +88,7 @@
final boolean interactive; // originated from user interaction?
final boolean initialSticky; // initial broadcast from register to sticky?
final boolean prioritized; // contains more than one priority tranche
+ final boolean deferUntilActive; // infinitely deferrable broadcast
final int userId; // user id this broadcast was for
final @Nullable String resolvedType; // the resolved data type
final @Nullable String[] requiredPermissions; // permissions the caller has required
@@ -97,6 +98,7 @@
final @Nullable BroadcastOptions options; // BroadcastOptions supplied by caller
final @NonNull List<Object> receivers; // contains BroadcastFilter and ResolveInfo
final @DeliveryState int[] delivery; // delivery state of each receiver
+ final boolean[] deferredUntilActive; // whether each receiver is infinitely deferred
final int[] blockedUntilTerminalCount; // blocked until count of each receiver
@Nullable ProcessRecord resultToApp; // who receives final result if non-null
@Nullable IIntentReceiver resultTo; // who receives final result if non-null
@@ -130,6 +132,7 @@
int manifestCount; // number of manifest receivers dispatched.
int manifestSkipCount; // number of manifest receivers skipped.
int terminalCount; // number of receivers in terminal state.
+ int deferredCount; // number of receivers in deferred state.
@Nullable BroadcastQueue queue; // the outbound queue handling this broadcast
// if set to true, app's process will be temporarily allowed to start activities from background
@@ -168,6 +171,8 @@
static final int DELIVERY_SCHEDULED = 4;
/** Terminal state: failure to dispatch */
static final int DELIVERY_FAILURE = 5;
+ /** Intermediate state: currently deferred while app is cached */
+ static final int DELIVERY_DEFERRED = 6;
@IntDef(flag = false, prefix = { "DELIVERY_" }, value = {
DELIVERY_PENDING,
@@ -176,6 +181,7 @@
DELIVERY_TIMEOUT,
DELIVERY_SCHEDULED,
DELIVERY_FAILURE,
+ DELIVERY_DEFERRED,
})
@Retention(RetentionPolicy.SOURCE)
public @interface DeliveryState {}
@@ -188,6 +194,7 @@
case DELIVERY_TIMEOUT: return "TIMEOUT";
case DELIVERY_SCHEDULED: return "SCHEDULED";
case DELIVERY_FAILURE: return "FAILURE";
+ case DELIVERY_DEFERRED: return "DEFERRED";
default: return Integer.toString(deliveryState);
}
}
@@ -388,6 +395,8 @@
options = _options;
receivers = (_receivers != null) ? _receivers : EMPTY_RECEIVERS;
delivery = new int[_receivers != null ? _receivers.size() : 0];
+ deferUntilActive = options != null ? options.isDeferUntilActive() : false;
+ deferredUntilActive = new boolean[deferUntilActive ? delivery.length : 0];
blockedUntilTerminalCount = calculateBlockedUntilTerminalCount(receivers, _serialized);
scheduledTime = new long[delivery.length];
terminalTime = new long[delivery.length];
@@ -443,6 +452,8 @@
options = from.options;
receivers = from.receivers;
delivery = from.delivery;
+ deferUntilActive = from.deferUntilActive;
+ deferredUntilActive = from.deferredUntilActive;
blockedUntilTerminalCount = from.blockedUntilTerminalCount;
scheduledTime = from.scheduledTime;
terminalTime = from.terminalTime;
@@ -606,7 +617,7 @@
*/
void setDeliveryState(int index, @DeliveryState int deliveryState) {
delivery[index] = deliveryState;
-
+ if (deferUntilActive) deferredUntilActive[index] = false;
switch (deliveryState) {
case DELIVERY_DELIVERED:
case DELIVERY_SKIPPED:
@@ -617,6 +628,9 @@
case DELIVERY_SCHEDULED:
scheduledTime[index] = SystemClock.uptimeMillis();
break;
+ case DELIVERY_DEFERRED:
+ if (deferUntilActive) deferredUntilActive[index] = true;
+ break;
}
}
@@ -647,6 +661,10 @@
return (intent.getFlags() & Intent.FLAG_RECEIVER_OFFLOAD) != 0;
}
+ boolean isDeferUntilActive() {
+ return deferUntilActive;
+ }
+
/**
* Core policy determination about this broadcast's delivery prioritization
*/
diff --git a/services/core/java/com/android/server/am/BroadcastSkipPolicy.java b/services/core/java/com/android/server/am/BroadcastSkipPolicy.java
index 481ab17..6718319 100644
--- a/services/core/java/com/android/server/am/BroadcastSkipPolicy.java
+++ b/services/core/java/com/android/server/am/BroadcastSkipPolicy.java
@@ -229,12 +229,7 @@
return "Background execution disabled: receiving "
+ r.intent + " to "
+ component.flattenToShortString();
- } else if (((r.intent.getFlags()&Intent.FLAG_RECEIVER_EXCLUDE_BACKGROUND) != 0)
- || (r.intent.getComponent() == null
- && r.intent.getPackage() == null
- && ((r.intent.getFlags()
- & Intent.FLAG_RECEIVER_INCLUDE_BACKGROUND) == 0)
- && !isSignaturePerm(r.requiredPermissions))) {
+ } else if (disallowBackgroundStart(r)) {
mService.addBackgroundCheckViolationLocked(r.intent.getAction(),
component.getPackageName());
return "Background execution not allowed: receiving "
@@ -341,6 +336,18 @@
}
/**
+ * Determine if the given {@link BroadcastRecord} is eligible to launch processes.
+ */
+ public boolean disallowBackgroundStart(@NonNull BroadcastRecord r) {
+ return ((r.intent.getFlags() & Intent.FLAG_RECEIVER_EXCLUDE_BACKGROUND) != 0)
+ || (r.intent.getComponent() == null
+ && r.intent.getPackage() == null
+ && ((r.intent.getFlags()
+ & Intent.FLAG_RECEIVER_INCLUDE_BACKGROUND) == 0)
+ && !isSignaturePerm(r.requiredPermissions));
+ }
+
+ /**
* Determine if the given {@link BroadcastRecord} is eligible to be sent to
* the given {@link BroadcastFilter}.
*
@@ -624,7 +631,7 @@
/**
* Return true if all given permissions are signature-only perms.
*/
- private boolean isSignaturePerm(String[] perms) {
+ private static boolean isSignaturePerm(String[] perms) {
if (perms == null) {
return false;
}
diff --git a/services/core/java/com/android/server/am/CachedAppOptimizer.java b/services/core/java/com/android/server/am/CachedAppOptimizer.java
index 4c10d58b..f54e2b0 100644
--- a/services/core/java/com/android/server/am/CachedAppOptimizer.java
+++ b/services/core/java/com/android/server/am/CachedAppOptimizer.java
@@ -1860,7 +1860,10 @@
mLastCompactionStats.remove(pid);
mLastCompactionStats.put(pid, memStats);
mCompactionStatsHistory.add(memStats);
- memStats.sendStat();
+ if (!forceCompaction) {
+ // Avoid polluting field metrics with forced compactions.
+ memStats.sendStat();
+ }
break;
default:
// We likely missed adding this category, it needs to be added
diff --git a/services/core/java/com/android/server/am/ServiceRecord.java b/services/core/java/com/android/server/am/ServiceRecord.java
index 8c242743..def51b0 100644
--- a/services/core/java/com/android/server/am/ServiceRecord.java
+++ b/services/core/java/com/android/server/am/ServiceRecord.java
@@ -1063,7 +1063,7 @@
}
public AppBindRecord retrieveAppBindingLocked(Intent intent,
- ProcessRecord app) {
+ ProcessRecord app, ProcessRecord attributedApp) {
Intent.FilterComparison filter = new Intent.FilterComparison(intent);
IntentBindRecord i = bindings.get(filter);
if (i == null) {
@@ -1074,7 +1074,7 @@
if (a != null) {
return a;
}
- a = new AppBindRecord(this, i, app);
+ a = new AppBindRecord(this, i, app, attributedApp);
i.apps.put(app, a);
return a;
}
diff --git a/services/core/java/com/android/server/ambientcontext/AmbientContextManagerService.java b/services/core/java/com/android/server/ambientcontext/AmbientContextManagerService.java
index 5c18827..7d9b272 100644
--- a/services/core/java/com/android/server/ambientcontext/AmbientContextManagerService.java
+++ b/services/core/java/com/android/server/ambientcontext/AmbientContextManagerService.java
@@ -50,6 +50,8 @@
import com.android.server.infra.FrameworkResourcesServiceNameResolver;
import com.android.server.pm.KnownPackages;
+import com.google.android.collect.Sets;
+
import java.io.FileDescriptor;
import java.io.PrintWriter;
import java.util.ArrayList;
@@ -67,12 +69,10 @@
AmbientContextManagerPerUserService> {
private static final String TAG = AmbientContextManagerService.class.getSimpleName();
private static final String KEY_SERVICE_ENABLED = "service_enabled";
- private static final Set<Integer> DEFAULT_EVENT_SET = new HashSet<>(){{
- add(AmbientContextEvent.EVENT_COUGH);
- add(AmbientContextEvent.EVENT_SNORE);
- add(AmbientContextEvent.EVENT_BACK_DOUBLE_TAP);
- }
- };
+ private static final Set<Integer> DEFAULT_EVENT_SET = Sets.newHashSet(
+ AmbientContextEvent.EVENT_COUGH,
+ AmbientContextEvent.EVENT_SNORE,
+ AmbientContextEvent.EVENT_BACK_DOUBLE_TAP);
/** Default value in absence of {@link DeviceConfig} override. */
private static final boolean DEFAULT_SERVICE_ENABLED = true;
@@ -409,14 +409,6 @@
}
}
- private Set<Integer> intArrayToIntegerSet(int[] eventTypes) {
- Set<Integer> types = new HashSet<>();
- for (Integer i : eventTypes) {
- types.add(i);
- }
- return types;
- }
-
private AmbientContextManagerPerUserService.ServiceType getServiceType(String serviceName) {
final String wearableService = mContext.getResources()
.getString(R.string.config_defaultWearableSensingService);
@@ -513,6 +505,14 @@
return intArray;
}
+ private Set<Integer> intArrayToIntegerSet(int[] eventTypes) {
+ Set<Integer> types = new HashSet<>();
+ for (Integer i : eventTypes) {
+ types.add(i);
+ }
+ return types;
+ }
+
@NonNull
private static Integer[] intArrayToIntegerArray(@NonNull int[] integerSet) {
Integer[] intArray = new Integer[integerSet.length];
@@ -567,37 +567,24 @@
mContext.enforceCallingOrSelfPermission(
Manifest.permission.ACCESS_AMBIENT_CONTEXT_EVENT, TAG);
assertCalledByPackageOwner(packageName);
+
AmbientContextManagerPerUserService service =
getAmbientContextManagerPerUserServiceForEventTypes(
UserHandle.getCallingUserId(),
request.getEventTypes());
-
if (service == null) {
Slog.w(TAG, "onRegisterObserver unavailable user_id: "
+ UserHandle.getCallingUserId());
- }
-
- if (service.getServiceType() == ServiceType.DEFAULT && !mIsServiceEnabled) {
- Slog.d(TAG, "Service not available.");
- service.completeRegistration(observer,
- AmbientContextManager.STATUS_SERVICE_UNAVAILABLE);
- return;
- }
- if (service.getServiceType() == ServiceType.WEARABLE && !mIsWearableServiceEnabled) {
- Slog.d(TAG, "Wearable Service not available.");
- service.completeRegistration(observer,
- AmbientContextManager.STATUS_SERVICE_UNAVAILABLE);
- return;
- }
- if (containsMixedEvents(integerSetToIntArray(request.getEventTypes()))) {
- Slog.d(TAG, "AmbientContextEventRequest contains mixed events,"
- + " this is not supported.");
- service.completeRegistration(observer,
- AmbientContextManager.STATUS_NOT_SUPPORTED);
return;
}
- service.onRegisterObserver(request, packageName, observer);
+ int statusCode = checkStatusCode(
+ service, integerSetToIntArray(request.getEventTypes()));
+ if (statusCode == AmbientContextManager.STATUS_SUCCESS) {
+ service.onRegisterObserver(request, packageName, observer);
+ } else {
+ service.completeRegistration(observer, statusCode);
+ }
}
@Override
@@ -606,10 +593,10 @@
Manifest.permission.ACCESS_AMBIENT_CONTEXT_EVENT, TAG);
assertCalledByPackageOwner(callingPackage);
- AmbientContextManagerPerUserService service = null;
for (ClientRequest cr : mExistingClientRequests) {
if (cr.getPackageName().equals(callingPackage)) {
- service = getAmbientContextManagerPerUserServiceForEventTypes(
+ AmbientContextManagerPerUserService service =
+ getAmbientContextManagerPerUserServiceForEventTypes(
UserHandle.getCallingUserId(), cr.getRequest().getEventTypes());
if (service != null) {
service.onUnregisterObserver(callingPackage);
@@ -635,34 +622,18 @@
getAmbientContextManagerPerUserServiceForEventTypes(
UserHandle.getCallingUserId(), intArrayToIntegerSet(eventTypes));
if (service == null) {
- Slog.w(TAG, "onQueryServiceStatus unavailable user_id: "
+ Slog.w(TAG, "queryServiceStatus unavailable user_id: "
+ UserHandle.getCallingUserId());
- }
-
- if (service.getServiceType() == ServiceType.DEFAULT && !mIsServiceEnabled) {
- Slog.d(TAG, "Service not available.");
- service.sendStatusCallback(statusCallback,
- AmbientContextManager.STATUS_SERVICE_UNAVAILABLE);
- return;
- }
- if (service.getServiceType() == ServiceType.WEARABLE
- && !mIsWearableServiceEnabled) {
- Slog.d(TAG, "Wearable Service not available.");
- service.sendStatusCallback(statusCallback,
- AmbientContextManager.STATUS_SERVICE_UNAVAILABLE);
return;
}
- if (containsMixedEvents(eventTypes)) {
- Slog.d(TAG, "AmbientContextEventRequest contains mixed events,"
- + " this is not supported.");
- service.sendStatusCallback(statusCallback,
- AmbientContextManager.STATUS_NOT_SUPPORTED);
- return;
+ int statusCode = checkStatusCode(service, eventTypes);
+ if (statusCode == AmbientContextManager.STATUS_SUCCESS) {
+ service.onQueryServiceStatus(eventTypes, callingPackage,
+ statusCallback);
+ } else {
+ service.sendStatusCallback(statusCallback, statusCode);
}
-
- service.onQueryServiceStatus(eventTypes, callingPackage,
- statusCallback);
}
}
@@ -708,5 +679,22 @@
new AmbientContextShellCommand(AmbientContextManagerService.this).exec(
this, in, out, err, args, callback, resultReceiver);
}
+
+ private int checkStatusCode(AmbientContextManagerPerUserService service, int[] eventTypes) {
+ if (service.getServiceType() == ServiceType.DEFAULT && !mIsServiceEnabled) {
+ Slog.d(TAG, "Service not enabled.");
+ return AmbientContextManager.STATUS_SERVICE_UNAVAILABLE;
+ }
+ if (service.getServiceType() == ServiceType.WEARABLE && !mIsWearableServiceEnabled) {
+ Slog.d(TAG, "Wearable Service not available.");
+ return AmbientContextManager.STATUS_SERVICE_UNAVAILABLE;
+ }
+ if (containsMixedEvents(eventTypes)) {
+ Slog.d(TAG, "AmbientContextEventRequest contains mixed events,"
+ + " this is not supported.");
+ return AmbientContextManager.STATUS_NOT_SUPPORTED;
+ }
+ return AmbientContextManager.STATUS_SUCCESS;
+ }
}
}
diff --git a/services/core/java/com/android/server/audio/AudioService.java b/services/core/java/com/android/server/audio/AudioService.java
index 78bff95..58ddd9c 100644
--- a/services/core/java/com/android/server/audio/AudioService.java
+++ b/services/core/java/com/android/server/audio/AudioService.java
@@ -3717,9 +3717,11 @@
setRingerMode(getNewRingerMode(stream, index, flags),
TAG + ".onSetStreamVolume", false /*external*/);
}
- // setting non-zero volume for a muted stream unmutes the stream and vice versa,
+ // setting non-zero volume for a muted stream unmutes the stream and vice versa
+ // (only when changing volume for the current device),
// except for BT SCO stream where only explicit mute is allowed to comply to BT requirements
- if (streamType != AudioSystem.STREAM_BLUETOOTH_SCO) {
+ if ((streamType != AudioSystem.STREAM_BLUETOOTH_SCO)
+ && (getDeviceForStream(stream) == device)) {
mStreamStates[stream].mute(index == 0);
}
}
diff --git a/services/core/java/com/android/server/audio/PlaybackActivityMonitor.java b/services/core/java/com/android/server/audio/PlaybackActivityMonitor.java
index 99d6228..9fc0038 100644
--- a/services/core/java/com/android/server/audio/PlaybackActivityMonitor.java
+++ b/services/core/java/com/android/server/audio/PlaybackActivityMonitor.java
@@ -82,7 +82,9 @@
/*package*/ static final int VOLUME_SHAPER_SYSTEM_DUCK_ID = 1;
/*package*/ static final int VOLUME_SHAPER_SYSTEM_FADEOUT_ID = 2;
/*package*/ static final int VOLUME_SHAPER_SYSTEM_MUTE_AWAIT_CONNECTION_ID = 3;
+ /*package*/ static final int VOLUME_SHAPER_SYSTEM_STRONG_DUCK_ID = 4;
+ // ducking settings for a "normal duck" at -14dB
private static final VolumeShaper.Configuration DUCK_VSHAPE =
new VolumeShaper.Configuration.Builder()
.setId(VOLUME_SHAPER_SYSTEM_DUCK_ID)
@@ -96,6 +98,22 @@
.build();
private static final VolumeShaper.Configuration DUCK_ID =
new VolumeShaper.Configuration(VOLUME_SHAPER_SYSTEM_DUCK_ID);
+
+ // ducking settings for a "strong duck" at -35dB (attenuation factor of 0.017783)
+ private static final VolumeShaper.Configuration STRONG_DUCK_VSHAPE =
+ new VolumeShaper.Configuration.Builder()
+ .setId(VOLUME_SHAPER_SYSTEM_STRONG_DUCK_ID)
+ .setCurve(new float[] { 0.f, 1.f } /* times */,
+ new float[] { 1.f, 0.017783f } /* volumes */)
+ .setOptionFlags(VolumeShaper.Configuration.OPTION_FLAG_CLOCK_TIME)
+ .setDuration(MediaFocusControl.getFocusRampTimeMs(
+ AudioManager.AUDIOFOCUS_GAIN_TRANSIENT_MAY_DUCK,
+ new AudioAttributes.Builder().setUsage(AudioAttributes.USAGE_NOTIFICATION)
+ .build()))
+ .build();
+ private static final VolumeShaper.Configuration STRONG_DUCK_ID =
+ new VolumeShaper.Configuration(VOLUME_SHAPER_SYSTEM_STRONG_DUCK_ID);
+
private static final VolumeShaper.Operation PLAY_CREATE_IF_NEEDED =
new VolumeShaper.Operation.Builder(VolumeShaper.Operation.PLAY)
.createIfNeeded()
@@ -784,11 +802,23 @@
// add the players eligible for ducking to the list, and duck them
// (if apcsToDuck is empty, this will at least mark this uid as ducked, so when
// players of the same uid start, they will be ducked by DuckingManager.checkDuck())
- mDuckingManager.duckUid(loser.getClientUid(), apcsToDuck);
+ mDuckingManager.duckUid(loser.getClientUid(), apcsToDuck, reqCausesStrongDuck(winner));
}
return true;
}
+ private boolean reqCausesStrongDuck(FocusRequester requester) {
+ if (requester.getGainRequest() != AudioManager.AUDIOFOCUS_GAIN_TRANSIENT_MAY_DUCK) {
+ return false;
+ }
+ final int reqUsage = requester.getAudioAttributes().getUsage();
+ if ((reqUsage == AudioAttributes.USAGE_ASSISTANT)
+ || (reqUsage == AudioAttributes.USAGE_ASSISTANCE_NAVIGATION_GUIDANCE)) {
+ return true;
+ }
+ return false;
+ }
+
@Override
public void restoreVShapedPlayers(@NonNull FocusRequester winner) {
if (DEBUG) { Log.v(TAG, "unduckPlayers: uids winner=" + winner.getClientUid()); }
@@ -1064,10 +1094,11 @@
private static final class DuckingManager {
private final HashMap<Integer, DuckedApp> mDuckers = new HashMap<Integer, DuckedApp>();
- synchronized void duckUid(int uid, ArrayList<AudioPlaybackConfiguration> apcsToDuck) {
+ synchronized void duckUid(int uid, ArrayList<AudioPlaybackConfiguration> apcsToDuck,
+ boolean requestCausesStrongDuck) {
if (DEBUG) { Log.v(TAG, "DuckingManager: duckUid() uid:"+ uid); }
if (!mDuckers.containsKey(uid)) {
- mDuckers.put(uid, new DuckedApp(uid));
+ mDuckers.put(uid, new DuckedApp(uid, requestCausesStrongDuck));
}
final DuckedApp da = mDuckers.get(uid);
for (AudioPlaybackConfiguration apc : apcsToDuck) {
@@ -1114,10 +1145,13 @@
private static final class DuckedApp {
private final int mUid;
+ /** determines whether ducking is done with DUCK_VSHAPE or STRONG_DUCK_VSHAPE */
+ private final boolean mUseStrongDuck;
private final ArrayList<Integer> mDuckedPlayers = new ArrayList<Integer>();
- DuckedApp(int uid) {
+ DuckedApp(int uid, boolean useStrongDuck) {
mUid = uid;
+ mUseStrongDuck = useStrongDuck;
}
void dump(PrintWriter pw) {
@@ -1138,9 +1172,10 @@
return;
}
try {
- sEventLogger.enqueue((new DuckEvent(apc, skipRamp)).printLog(TAG));
+ sEventLogger.enqueue((new DuckEvent(apc, skipRamp, mUseStrongDuck))
+ .printLog(TAG));
apc.getPlayerProxy().applyVolumeShaper(
- DUCK_VSHAPE,
+ mUseStrongDuck ? STRONG_DUCK_VSHAPE : DUCK_VSHAPE,
skipRamp ? PLAY_SKIP_RAMP : PLAY_CREATE_IF_NEEDED);
mDuckedPlayers.add(piid);
} catch (Exception e) {
@@ -1156,7 +1191,7 @@
sEventLogger.enqueue((new EventLogger.StringEvent("unducking piid:"
+ piid)).printLog(TAG));
apc.getPlayerProxy().applyVolumeShaper(
- DUCK_ID,
+ mUseStrongDuck ? STRONG_DUCK_ID : DUCK_ID,
VolumeShaper.Operation.REVERSE);
} catch (Exception e) {
Log.e(TAG, "Error unducking player piid:" + piid + " uid:" + mUid, e);
@@ -1309,13 +1344,17 @@
}
static final class DuckEvent extends VolumeShaperEvent {
+ final boolean mUseStrongDuck;
+
@Override
String getVSAction() {
- return "ducking";
+ return mUseStrongDuck ? "ducking (strong)" : "ducking";
}
- DuckEvent(@NonNull AudioPlaybackConfiguration apc, boolean skipRamp) {
+ DuckEvent(@NonNull AudioPlaybackConfiguration apc, boolean skipRamp, boolean useStrongDuck)
+ {
super(apc, skipRamp);
+ mUseStrongDuck = useStrongDuck;
}
}
diff --git a/services/core/java/com/android/server/audio/SoundDoseHelper.java b/services/core/java/com/android/server/audio/SoundDoseHelper.java
index 7edd911..919b850 100644
--- a/services/core/java/com/android/server/audio/SoundDoseHelper.java
+++ b/services/core/java/com/android/server/audio/SoundDoseHelper.java
@@ -202,15 +202,7 @@
}
}
mCurrentCsd = currentCsd;
- mDoseRecords.addAll(Arrays.asList(records));
- long totalDuration = 0;
- for (SoundDoseRecord record : records) {
- Log.i(TAG, " new record: csd=" + record.value
- + " averageMel=" + record.averageMel + " timestamp=" + record.timestamp
- + " duration=" + record.duration);
- totalDuration += record.duration;
- }
- mLogger.enqueue(SoundDoseEvent.getDoseUpdateEvent(currentCsd, totalDuration));
+ updateSoundDoseRecords(records, currentCsd);
}
};
@@ -626,6 +618,29 @@
return null;
}
+ private void updateSoundDoseRecords(SoundDoseRecord[] newRecords, float currentCsd) {
+ long totalDuration = 0;
+ for (SoundDoseRecord record : newRecords) {
+ Log.i(TAG, " new record: " + record);
+ totalDuration += record.duration;
+
+ if (record.value < 0) {
+ // Negative value means the record timestamp exceeded the CSD rolling window size
+ // and needs to be removed
+ if (!mDoseRecords.removeIf(
+ r -> r.value == -record.value && r.timestamp == record.timestamp
+ && r.averageMel == record.averageMel
+ && r.duration == record.duration)) {
+ Log.w(TAG, "Could not find cached record to remove: " + record);
+ }
+ } else {
+ mDoseRecords.add(record);
+ }
+ }
+
+ mLogger.enqueue(SoundDoseEvent.getDoseUpdateEvent(currentCsd, totalDuration));
+ }
+
// StreamVolumeCommand contains the information needed to defer the process of
// setStreamVolume() in case the user has to acknowledge the safe volume warning message.
private static class StreamVolumeCommand {
diff --git a/services/core/java/com/android/server/biometrics/sensors/face/FaceService.java b/services/core/java/com/android/server/biometrics/sensors/face/FaceService.java
index cb409fe..0248010 100644
--- a/services/core/java/com/android/server/biometrics/sensors/face/FaceService.java
+++ b/services/core/java/com/android/server/biometrics/sensors/face/FaceService.java
@@ -125,7 +125,7 @@
return proto.getBytes();
}
- @android.annotation.EnforcePermission(android.Manifest.permission.MANAGE_BIOMETRIC)
+ @android.annotation.EnforcePermission(android.Manifest.permission.USE_BIOMETRIC_INTERNAL)
@Override // Binder call
public List<FaceSensorPropertiesInternal> getSensorPropertiesInternal(
String opPackageName) {
diff --git a/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintAuthenticationClient.java b/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintAuthenticationClient.java
index 9669950..a90679e 100644
--- a/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintAuthenticationClient.java
+++ b/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintAuthenticationClient.java
@@ -16,15 +16,11 @@
package com.android.server.biometrics.sensors.fingerprint.aidl;
-import static android.hardware.biometrics.BiometricFingerprintConstants.FINGERPRINT_ACQUIRED_START;
-import static android.hardware.biometrics.BiometricFingerprintConstants.FINGERPRINT_ACQUIRED_VENDOR;
-
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.app.TaskStackListener;
import android.content.Context;
import android.hardware.biometrics.BiometricAuthenticator;
-import android.hardware.biometrics.BiometricConstants;
import android.hardware.biometrics.BiometricFingerprintConstants;
import android.hardware.biometrics.BiometricFingerprintConstants.FingerprintAcquired;
import android.hardware.biometrics.BiometricManager.Authenticators;
@@ -94,7 +90,6 @@
private long mSideFpsLastAcquireStartTime;
private Runnable mAuthSuccessRunnable;
private final Clock mClock;
- private boolean mDidFinishSfps;
FingerprintAuthenticationClient(
@NonNull Context context,
@@ -204,9 +199,8 @@
@Override
protected void handleLifecycleAfterAuth(boolean authenticated) {
- if (authenticated && !mDidFinishSfps) {
+ if (authenticated) {
mCallback.onClientFinished(this, true /* success */);
- mDidFinishSfps = true;
}
}
@@ -216,13 +210,11 @@
return false;
}
- public void handleAuthenticate(
+ @Override
+ public void onAuthenticated(
BiometricAuthenticator.Identifier identifier,
boolean authenticated,
ArrayList<Byte> token) {
- if (authenticated && mSensorProps.isAnySidefpsType()) {
- Slog.i(TAG, "(sideFPS): No power press detected, sending auth");
- }
super.onAuthenticated(identifier, authenticated, token);
if (authenticated) {
mState = STATE_STOPPED;
@@ -233,74 +225,13 @@
}
@Override
- public void onAuthenticated(
- BiometricAuthenticator.Identifier identifier,
- boolean authenticated,
- ArrayList<Byte> token) {
-
- mHandler.post(
- () -> {
- long delay = 0;
- if (authenticated && mSensorProps.isAnySidefpsType()) {
- delay = isKeyguard() ? mWaitForAuthKeyguard : mWaitForAuthBp;
-
- if (mSideFpsLastAcquireStartTime != -1) {
- delay = Math.max(0,
- delay - (mClock.millis() - mSideFpsLastAcquireStartTime));
- }
-
- Slog.i(TAG, "(sideFPS) Auth succeeded, sideFps "
- + "waiting for power until: " + delay + "ms");
- }
-
- if (mHandler.hasMessages(MESSAGE_FINGER_UP)) {
- Slog.i(TAG, "Finger up detected, sending auth");
- delay = 0;
- }
-
- mAuthSuccessRunnable =
- () -> handleAuthenticate(identifier, authenticated, token);
- mHandler.postDelayed(
- mAuthSuccessRunnable,
- MESSAGE_AUTH_SUCCESS,
- delay);
- });
- }
-
- @Override
public void onAcquired(@FingerprintAcquired int acquiredInfo, int vendorCode) {
// For UDFPS, notify SysUI with acquiredInfo, so that the illumination can be turned off
// for most ACQUIRED messages. See BiometricFingerprintConstants#FingerprintAcquired
mSensorOverlays.ifUdfps(controller -> controller.onAcquired(getSensorId(), acquiredInfo));
super.onAcquired(acquiredInfo, vendorCode);
- if (mSensorProps.isAnySidefpsType()) {
- if (acquiredInfo == FINGERPRINT_ACQUIRED_START) {
- mSideFpsLastAcquireStartTime = mClock.millis();
- }
- final boolean shouldLookForVendor =
- mSkipWaitForPowerAcquireMessage == FINGERPRINT_ACQUIRED_VENDOR;
- final boolean acquireMessageMatch = acquiredInfo == mSkipWaitForPowerAcquireMessage;
- final boolean vendorMessageMatch = vendorCode == mSkipWaitForPowerVendorAcquireMessage;
- final boolean ignorePowerPress =
- acquireMessageMatch && (!shouldLookForVendor || vendorMessageMatch);
-
- if (ignorePowerPress) {
- Slog.d(TAG, "(sideFPS) onFingerUp");
- mHandler.post(() -> {
- if (mHandler.hasMessages(MESSAGE_AUTH_SUCCESS)) {
- Slog.d(TAG, "(sideFPS) skipping wait for power");
- mHandler.removeMessages(MESSAGE_AUTH_SUCCESS);
- mHandler.post(mAuthSuccessRunnable);
- } else {
- mHandler.postDelayed(() -> {
- }, MESSAGE_FINGER_UP, mFingerUpIgnoresPower);
- }
- });
- }
- }
PerformanceTracker pt = PerformanceTracker.getInstanceForSensorId(getSensorId());
pt.incrementAcquireForUser(getTargetUserId(), isCryptoOperation());
-
}
@Override
@@ -495,22 +426,5 @@
}
@Override
- public void onPowerPressed() {
- if (mSensorProps.isAnySidefpsType()) {
- Slog.i(TAG, "(sideFPS): onPowerPressed");
- mHandler.post(() -> {
- if (mDidFinishSfps) {
- return;
- }
- Slog.i(TAG, "(sideFPS): finishing auth");
- // Ignore auths after a power has been detected
- mHandler.removeMessages(MESSAGE_AUTH_SUCCESS);
- // Do not call onError() as that will send an additional callback to coex.
- mDidFinishSfps = true;
- onErrorInternal(BiometricConstants.BIOMETRIC_ERROR_POWER_PRESSED, 0, true);
- stopHalOperation();
- mSensorOverlays.hide(getSensorId());
- });
- }
- }
+ public void onPowerPressed() { }
}
diff --git a/services/core/java/com/android/server/broadcastradio/aidl/ProgramInfoCache.java b/services/core/java/com/android/server/broadcastradio/aidl/ProgramInfoCache.java
index 39b1354..c9ae735 100644
--- a/services/core/java/com/android/server/broadcastradio/aidl/ProgramInfoCache.java
+++ b/services/core/java/com/android/server/broadcastradio/aidl/ProgramInfoCache.java
@@ -86,12 +86,8 @@
}
@VisibleForTesting
- boolean programInfosAreExactly(RadioManager.ProgramInfo... programInfos) {
- Map<ProgramSelector.Identifier, RadioManager.ProgramInfo> expectedMap = new ArrayMap<>();
- for (int i = 0; i < programInfos.length; i++) {
- expectedMap.put(programInfos[i].getSelector().getPrimaryId(), programInfos[i]);
- }
- return expectedMap.equals(mProgramInfoMap);
+ List<RadioManager.ProgramInfo> toProgramInfoList() {
+ return new ArrayList<>(mProgramInfoMap.values());
}
@Override
diff --git a/services/core/java/com/android/server/companion/virtual/VirtualDeviceManagerInternal.java b/services/core/java/com/android/server/companion/virtual/VirtualDeviceManagerInternal.java
index e3ea1a6..974c04b 100644
--- a/services/core/java/com/android/server/companion/virtual/VirtualDeviceManagerInternal.java
+++ b/services/core/java/com/android/server/companion/virtual/VirtualDeviceManagerInternal.java
@@ -68,11 +68,6 @@
public abstract void onAppsOnVirtualDeviceChanged();
/**
- * Validate the virtual device.
- */
- public abstract boolean isValidVirtualDevice(IVirtualDevice virtualDevice);
-
- /**
* Gets the owner uid for a deviceId.
*
* @param deviceId which device we're asking about
diff --git a/services/core/java/com/android/server/display/DisplayManagerService.java b/services/core/java/com/android/server/display/DisplayManagerService.java
index 110eb1e..06b99f8 100644
--- a/services/core/java/com/android/server/display/DisplayManagerService.java
+++ b/services/core/java/com/android/server/display/DisplayManagerService.java
@@ -47,6 +47,7 @@
import android.app.AppOpsManager;
import android.app.compat.CompatChanges;
import android.companion.virtual.IVirtualDevice;
+import android.companion.virtual.VirtualDeviceManager;
import android.compat.annotation.ChangeId;
import android.compat.annotation.EnabledSince;
import android.content.BroadcastReceiver;
@@ -108,6 +109,7 @@
import android.provider.DeviceConfig;
import android.provider.Settings;
import android.text.TextUtils;
+import android.util.ArrayMap;
import android.util.ArraySet;
import android.util.EventLog;
import android.util.IntArray;
@@ -259,6 +261,13 @@
final SparseArray<Pair<IVirtualDevice, DisplayWindowPolicyController>>
mDisplayWindowPolicyControllers = new SparseArray<>();
+ /**
+ * Map of every internal primary display device {@link HighBrightnessModeMetadata}s indexed by
+ * {@link DisplayDevice#mUniqueId}.
+ */
+ public final ArrayMap<String, HighBrightnessModeMetadata> mHighBrightnessModeMetadataMap =
+ new ArrayMap<>();
+
// List of all currently registered display adapters.
private final ArrayList<DisplayAdapter> mDisplayAdapters = new ArrayList<DisplayAdapter>();
@@ -1273,12 +1282,17 @@
final Surface surface = virtualDisplayConfig.getSurface();
int flags = virtualDisplayConfig.getFlags();
if (virtualDevice != null) {
- final VirtualDeviceManagerInternal vdm =
- getLocalService(VirtualDeviceManagerInternal.class);
- if (!vdm.isValidVirtualDevice(virtualDevice)) {
- throw new SecurityException("Invalid virtual device");
+ final VirtualDeviceManager vdm = mContext.getSystemService(VirtualDeviceManager.class);
+ try {
+ if (!vdm.isValidVirtualDeviceId(virtualDevice.getDeviceId())) {
+ throw new SecurityException("Invalid virtual device");
+ }
+ } catch (RemoteException ex) {
+ throw new SecurityException("Unable to validate virtual device");
}
- flags |= vdm.getBaseVirtualDisplayFlags(virtualDevice);
+ final VirtualDeviceManagerInternal localVdm =
+ getLocalService(VirtualDeviceManagerInternal.class);
+ flags |= localVdm.getBaseVirtualDisplayFlags(virtualDevice);
}
if (surface != null && surface.isSingleBuffered()) {
@@ -1634,7 +1648,16 @@
DisplayPowerControllerInterface dpc = mDisplayPowerControllers.get(displayId);
if (dpc != null) {
- dpc.onDisplayChanged();
+ final DisplayDevice device = display.getPrimaryDisplayDeviceLocked();
+ if (device == null) {
+ Slog.wtf(TAG, "Display Device is null in DisplayManagerService for display: "
+ + display.getDisplayIdLocked());
+ return;
+ }
+
+ final String uniqueId = device.getUniqueId();
+ HighBrightnessModeMetadata hbmMetadata = mHighBrightnessModeMetadataMap.get(uniqueId);
+ dpc.onDisplayChanged(hbmMetadata);
}
}
@@ -1692,7 +1715,15 @@
final int displayId = display.getDisplayIdLocked();
final DisplayPowerControllerInterface dpc = mDisplayPowerControllers.get(displayId);
if (dpc != null) {
- dpc.onDisplayChanged();
+ final DisplayDevice device = display.getPrimaryDisplayDeviceLocked();
+ if (device == null) {
+ Slog.wtf(TAG, "Display Device is null in DisplayManagerService for display: "
+ + display.getDisplayIdLocked());
+ return;
+ }
+ final String uniqueId = device.getUniqueId();
+ HighBrightnessModeMetadata hbmMetadata = mHighBrightnessModeMetadataMap.get(uniqueId);
+ dpc.onDisplayChanged(hbmMetadata);
}
}
@@ -2645,6 +2676,31 @@
mLogicalDisplayMapper.forEachLocked(this::addDisplayPowerControllerLocked);
}
+ private HighBrightnessModeMetadata getHighBrightnessModeMetadata(LogicalDisplay display) {
+ final DisplayDevice device = display.getPrimaryDisplayDeviceLocked();
+ if (device == null) {
+ Slog.wtf(TAG, "Display Device is null in DisplayPowerController for display: "
+ + display.getDisplayIdLocked());
+ return null;
+ }
+
+ // HBM brightness mode is only applicable to internal physical displays.
+ if (display.getDisplayInfoLocked().type != Display.TYPE_INTERNAL) {
+ return null;
+ }
+
+ final String uniqueId = device.getUniqueId();
+
+ if (mHighBrightnessModeMetadataMap.containsKey(uniqueId)) {
+ return mHighBrightnessModeMetadataMap.get(uniqueId);
+ }
+
+ // HBM Time info not present. Create a new one for this physical display.
+ HighBrightnessModeMetadata hbmInfo = new HighBrightnessModeMetadata();
+ mHighBrightnessModeMetadataMap.put(uniqueId, hbmInfo);
+ return hbmInfo;
+ }
+
@RequiresPermission(Manifest.permission.READ_DEVICE_CONFIG)
private void addDisplayPowerControllerLocked(LogicalDisplay display) {
if (mPowerHandler == null) {
@@ -2660,17 +2716,23 @@
display, mSyncRoot);
final DisplayPowerControllerInterface displayPowerController;
+ // If display is internal and has a HighBrightnessModeMetadata mapping, use that.
+ // Or create a new one and use that.
+ // We also need to pass a mapping of the HighBrightnessModeTimeInfoMap to
+ // displayPowerController, so the hbm info can be correctly associated
+ // with the corresponding displaydevice.
+ HighBrightnessModeMetadata hbmMetadata = getHighBrightnessModeMetadata(display);
if (DeviceConfig.getBoolean("display_manager",
"use_newly_structured_display_power_controller", true)) {
displayPowerController = new DisplayPowerController2(
mContext, /* injector= */ null, mDisplayPowerCallbacks, mPowerHandler,
mSensorManager, mDisplayBlanker, display, mBrightnessTracker, brightnessSetting,
- () -> handleBrightnessChange(display));
+ () -> handleBrightnessChange(display), hbmMetadata);
} else {
displayPowerController = new DisplayPowerController(
mContext, /* injector= */ null, mDisplayPowerCallbacks, mPowerHandler,
mSensorManager, mDisplayBlanker, display, mBrightnessTracker, brightnessSetting,
- () -> handleBrightnessChange(display));
+ () -> handleBrightnessChange(display), hbmMetadata);
}
mDisplayPowerControllers.append(display.getDisplayIdLocked(), displayPowerController);
}
diff --git a/services/core/java/com/android/server/display/DisplayPowerController.java b/services/core/java/com/android/server/display/DisplayPowerController.java
index 1b8f6e3..142ec68 100644
--- a/services/core/java/com/android/server/display/DisplayPowerController.java
+++ b/services/core/java/com/android/server/display/DisplayPowerController.java
@@ -388,6 +388,7 @@
private float[] mNitsRange;
private final HighBrightnessModeController mHbmController;
+ private final HighBrightnessModeMetadata mHighBrightnessModeMetadata;
private final BrightnessThrottler mBrightnessThrottler;
@@ -505,13 +506,14 @@
DisplayPowerCallbacks callbacks, Handler handler,
SensorManager sensorManager, DisplayBlanker blanker, LogicalDisplay logicalDisplay,
BrightnessTracker brightnessTracker, BrightnessSetting brightnessSetting,
- Runnable onBrightnessChangeRunnable) {
+ Runnable onBrightnessChangeRunnable, HighBrightnessModeMetadata hbmMetadata) {
mInjector = injector != null ? injector : new Injector();
mClock = mInjector.getClock();
mLogicalDisplay = logicalDisplay;
mDisplayId = mLogicalDisplay.getDisplayIdLocked();
mTag = "DisplayPowerController[" + mDisplayId + "]";
+ mHighBrightnessModeMetadata = hbmMetadata;
mSuspendBlockerIdUnfinishedBusiness = getSuspendBlockerUnfinishedBusinessId(mDisplayId);
mSuspendBlockerIdOnStateChanged = getSuspendBlockerOnStateChangedId(mDisplayId);
mSuspendBlockerIdProxPositive = getSuspendBlockerProxPositiveId(mDisplayId);
@@ -790,7 +792,7 @@
* Make sure DisplayManagerService.mSyncRoot is held when this is called
*/
@Override
- public void onDisplayChanged() {
+ public void onDisplayChanged(HighBrightnessModeMetadata hbmMetadata) {
final DisplayDevice device = mLogicalDisplay.getPrimaryDisplayDeviceLocked();
if (device == null) {
Slog.wtf(mTag, "Display Device is null in DisplayPowerController for display: "
@@ -812,11 +814,11 @@
mUniqueDisplayId = uniqueId;
mDisplayStatsId = mUniqueDisplayId.hashCode();
mDisplayDeviceConfig = config;
- loadFromDisplayDeviceConfig(token, info);
+ loadFromDisplayDeviceConfig(token, info, hbmMetadata);
- // Since the underlying display-device changed, we really don't know the
- // last command that was sent to change it's state. Lets assume it is off and we
- // trigger a change immediately.
+ /// Since the underlying display-device changed, we really don't know the
+ // last command that was sent to change it's state. Lets assume it is unknown so
+ // that we trigger a change immediately.
mPowerState.resetScreenState();
}
if (mIsEnabled != isEnabled || mIsInTransition != isInTransition) {
@@ -864,7 +866,8 @@
}
}
- private void loadFromDisplayDeviceConfig(IBinder token, DisplayDeviceInfo info) {
+ private void loadFromDisplayDeviceConfig(IBinder token, DisplayDeviceInfo info,
+ HighBrightnessModeMetadata hbmMetadata) {
// All properties that depend on the associated DisplayDevice and the DDC must be
// updated here.
loadBrightnessRampRates();
@@ -877,6 +880,7 @@
mBrightnessRampIncreaseMaxTimeMillis,
mBrightnessRampDecreaseMaxTimeMillis);
}
+ mHbmController.setHighBrightnessModeMetadata(hbmMetadata);
mHbmController.resetHbmData(info.width, info.height, token, info.uniqueId,
mDisplayDeviceConfig.getHighBrightnessModeData(),
new HighBrightnessModeController.HdrBrightnessDeviceConfig() {
@@ -1961,7 +1965,7 @@
if (mAutomaticBrightnessController != null) {
mAutomaticBrightnessController.update();
}
- }, mContext);
+ }, mHighBrightnessModeMetadata, mContext);
}
private BrightnessThrottler createBrightnessThrottlerLocked() {
diff --git a/services/core/java/com/android/server/display/DisplayPowerController2.java b/services/core/java/com/android/server/display/DisplayPowerController2.java
index bb8132f3..96342f3 100644
--- a/services/core/java/com/android/server/display/DisplayPowerController2.java
+++ b/services/core/java/com/android/server/display/DisplayPowerController2.java
@@ -328,6 +328,7 @@
private float[] mNitsRange;
private final HighBrightnessModeController mHbmController;
+ private final HighBrightnessModeMetadata mHighBrightnessModeMetadata;
private final BrightnessThrottler mBrightnessThrottler;
@@ -432,7 +433,7 @@
DisplayPowerCallbacks callbacks, Handler handler,
SensorManager sensorManager, DisplayBlanker blanker, LogicalDisplay logicalDisplay,
BrightnessTracker brightnessTracker, BrightnessSetting brightnessSetting,
- Runnable onBrightnessChangeRunnable) {
+ Runnable onBrightnessChangeRunnable, HighBrightnessModeMetadata hbmMetadata) {
mInjector = injector != null ? injector : new Injector();
mClock = mInjector.getClock();
@@ -448,6 +449,7 @@
mDisplayPowerProximityStateController = mInjector.getDisplayPowerProximityStateController(
mWakelockController, mDisplayDeviceConfig, mHandler.getLooper(),
() -> updatePowerState(), mDisplayId, mSensorManager);
+ mHighBrightnessModeMetadata = hbmMetadata;
mDisplayStateController = new DisplayStateController(mDisplayPowerProximityStateController);
mTag = "DisplayPowerController2[" + mDisplayId + "]";
@@ -707,7 +709,7 @@
* Make sure DisplayManagerService.mSyncRoot lock is held when this is called
*/
@Override
- public void onDisplayChanged() {
+ public void onDisplayChanged(HighBrightnessModeMetadata hbmMetadata) {
final DisplayDevice device = mLogicalDisplay.getPrimaryDisplayDeviceLocked();
if (device == null) {
Slog.wtf(mTag, "Display Device is null in DisplayPowerController2 for display: "
@@ -721,6 +723,7 @@
final DisplayDeviceInfo info = device.getDisplayDeviceInfoLocked();
final boolean isEnabled = mLogicalDisplay.isEnabledLocked();
final boolean isInTransition = mLogicalDisplay.isInTransitionLocked();
+
mHandler.post(() -> {
boolean changed = false;
if (mDisplayDevice != device) {
@@ -729,7 +732,7 @@
mUniqueDisplayId = uniqueId;
mDisplayStatsId = mUniqueDisplayId.hashCode();
mDisplayDeviceConfig = config;
- loadFromDisplayDeviceConfig(token, info);
+ loadFromDisplayDeviceConfig(token, info, hbmMetadata);
mDisplayPowerProximityStateController.notifyDisplayDeviceChanged(config);
// Since the underlying display-device changed, we really don't know the
@@ -778,7 +781,8 @@
}
}
- private void loadFromDisplayDeviceConfig(IBinder token, DisplayDeviceInfo info) {
+ private void loadFromDisplayDeviceConfig(IBinder token, DisplayDeviceInfo info,
+ HighBrightnessModeMetadata hbmMetadata) {
// All properties that depend on the associated DisplayDevice and the DDC must be
// updated here.
loadBrightnessRampRates();
@@ -790,6 +794,7 @@
mBrightnessRampIncreaseMaxTimeMillis,
mBrightnessRampDecreaseMaxTimeMillis);
}
+ mHbmController.setHighBrightnessModeMetadata(hbmMetadata);
mHbmController.resetHbmData(info.width, info.height, token, info.uniqueId,
mDisplayDeviceConfig.getHighBrightnessModeData(),
new HighBrightnessModeController.HdrBrightnessDeviceConfig() {
@@ -1192,7 +1197,9 @@
&& Display.isDozeState(state);
final boolean autoBrightnessEnabled = mUseAutoBrightness
&& (state == Display.STATE_ON || autoBrightnessEnabledInDoze)
- && Float.isNaN(brightnessState)
+ && (Float.isNaN(brightnessState)
+ || mBrightnessReasonTemp.getReason() == BrightnessReason.REASON_TEMPORARY
+ || mBrightnessReasonTemp.getReason() == BrightnessReason.REASON_BOOST)
&& mAutomaticBrightnessController != null;
final boolean autoBrightnessDisabledDueToDisplayOff = mUseAutoBrightness
&& !(state == Display.STATE_ON || autoBrightnessEnabledInDoze);
@@ -1740,7 +1747,7 @@
if (mAutomaticBrightnessController != null) {
mAutomaticBrightnessController.update();
}
- }, mContext);
+ }, mHighBrightnessModeMetadata, mContext);
}
private BrightnessThrottler createBrightnessThrottlerLocked() {
diff --git a/services/core/java/com/android/server/display/DisplayPowerControllerInterface.java b/services/core/java/com/android/server/display/DisplayPowerControllerInterface.java
index e750ee2..7b019846 100644
--- a/services/core/java/com/android/server/display/DisplayPowerControllerInterface.java
+++ b/services/core/java/com/android/server/display/DisplayPowerControllerInterface.java
@@ -31,10 +31,14 @@
public interface DisplayPowerControllerInterface {
/**
- * Notified when the display is changed. We use this to apply any changes that might be needed
+ * Notified when the display is changed.
+ * We use this to apply any changes that might be needed
* when displays get swapped on foldable devices.
+ * We also pass the High brightness mode metadata like
+ * remaining time and hbm events for the corresponding
+ * physical display, to update the values correctly.
*/
- void onDisplayChanged();
+ void onDisplayChanged(HighBrightnessModeMetadata hbmInfo);
/**
* Unregisters all listeners and interrupts all running threads; halting future work.
diff --git a/services/core/java/com/android/server/display/DisplayPowerState.java b/services/core/java/com/android/server/display/DisplayPowerState.java
index 7d1396d..2c257a1 100644
--- a/services/core/java/com/android/server/display/DisplayPowerState.java
+++ b/services/core/java/com/android/server/display/DisplayPowerState.java
@@ -340,20 +340,12 @@
}
/**
- * Resets the screen state to {@link Display#STATE_OFF}. Even though we do not know the last
- * state that was sent to the underlying display-device, we assume it is off.
- *
- * We do not set the screen state to {@link Display#STATE_UNKNOWN} to avoid getting in the state
- * where PhotonicModulator holds onto the lock. This happens because we currently try to keep
- * the mScreenState and mPendingState in sync, however if the screenState is set to
- * {@link Display#STATE_UNKNOWN} here, mPendingState will get progressed to this, which will
- * force the PhotonicModulator thread to wait onto the lock to take it out of that state.
- * b/262294651 for more info.
+ * Resets the screen state to unknown. Useful when the underlying display-device changes for the
+ * LogicalDisplay and we do not know the last state that was sent to it.
*/
void resetScreenState() {
- mScreenState = Display.STATE_OFF;
+ mScreenState = Display.STATE_UNKNOWN;
mScreenReady = false;
- scheduleScreenUpdate();
}
private void scheduleScreenUpdate() {
@@ -514,6 +506,8 @@
boolean valid = state != Display.STATE_UNKNOWN && !Float.isNaN(brightnessState);
boolean changed = stateChanged || backlightChanged;
if (!valid || !changed) {
+ mStateChangeInProgress = false;
+ mBacklightChangeInProgress = false;
try {
mLock.wait();
} catch (InterruptedException ex) {
diff --git a/services/core/java/com/android/server/display/HbmEvent.java b/services/core/java/com/android/server/display/HbmEvent.java
new file mode 100644
index 0000000..5675e2f
--- /dev/null
+++ b/services/core/java/com/android/server/display/HbmEvent.java
@@ -0,0 +1,46 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.display;
+
+
+/**
+ * Represents an event in which High Brightness Mode was enabled.
+ */
+class HbmEvent {
+ private long mStartTimeMillis;
+ private long mEndTimeMillis;
+
+ HbmEvent(long startTimeMillis, long endTimeMillis) {
+ this.mStartTimeMillis = startTimeMillis;
+ this.mEndTimeMillis = endTimeMillis;
+ }
+
+ public long getStartTimeMillis() {
+ return mStartTimeMillis;
+ }
+
+ public long getEndTimeMillis() {
+ return mEndTimeMillis;
+ }
+
+ @Override
+ public String toString() {
+ return "HbmEvent: {startTimeMillis:" + mStartTimeMillis + ", endTimeMillis: "
+ + mEndTimeMillis + "}, total: "
+ + ((mEndTimeMillis - mStartTimeMillis) / 1000) + "]";
+ }
+}
diff --git a/services/core/java/com/android/server/display/HighBrightnessModeController.java b/services/core/java/com/android/server/display/HighBrightnessModeController.java
index f98c7df..2c843a4 100644
--- a/services/core/java/com/android/server/display/HighBrightnessModeController.java
+++ b/services/core/java/com/android/server/display/HighBrightnessModeController.java
@@ -105,30 +105,23 @@
private int mHbmStatsState = FrameworkStatsLog.DISPLAY_HBM_STATE_CHANGED__STATE__HBM_OFF;
/**
- * If HBM is currently running, this is the start time for the current HBM session.
+ * If HBM is currently running, this is the start time and set of all events,
+ * for the current HBM session.
*/
- private long mRunningStartTimeMillis = -1;
-
- /**
- * Queue of previous HBM-events ordered from most recent to least recent.
- * Meant to store only the events that fall into the most recent
- * {@link HighBrightnessModeData#timeWindowMillis mHbmData.timeWindowMillis}.
- */
- private final ArrayDeque<HbmEvent> mEvents = new ArrayDeque<>();
-
+ private HighBrightnessModeMetadata mHighBrightnessModeMetadata = null;
HighBrightnessModeController(Handler handler, int width, int height, IBinder displayToken,
String displayUniqueId, float brightnessMin, float brightnessMax,
HighBrightnessModeData hbmData, HdrBrightnessDeviceConfig hdrBrightnessCfg,
- Runnable hbmChangeCallback, Context context) {
+ Runnable hbmChangeCallback, HighBrightnessModeMetadata hbmMetadata, Context context) {
this(new Injector(), handler, width, height, displayToken, displayUniqueId, brightnessMin,
- brightnessMax, hbmData, hdrBrightnessCfg, hbmChangeCallback, context);
+ brightnessMax, hbmData, hdrBrightnessCfg, hbmChangeCallback, hbmMetadata, context);
}
@VisibleForTesting
HighBrightnessModeController(Injector injector, Handler handler, int width, int height,
IBinder displayToken, String displayUniqueId, float brightnessMin, float brightnessMax,
HighBrightnessModeData hbmData, HdrBrightnessDeviceConfig hdrBrightnessCfg,
- Runnable hbmChangeCallback, Context context) {
+ Runnable hbmChangeCallback, HighBrightnessModeMetadata hbmMetadata, Context context) {
mInjector = injector;
mContext = context;
mClock = injector.getClock();
@@ -137,6 +130,7 @@
mBrightnessMin = brightnessMin;
mBrightnessMax = brightnessMax;
mHbmChangeCallback = hbmChangeCallback;
+ mHighBrightnessModeMetadata = hbmMetadata;
mSkinThermalStatusObserver = new SkinThermalStatusObserver(mInjector, mHandler);
mSettingsObserver = new SettingsObserver(mHandler);
mRecalcRunnable = this::recalculateTimeAllowance;
@@ -222,19 +216,22 @@
// If we are starting or ending a high brightness mode session, store the current
// session in mRunningStartTimeMillis, or the old one in mEvents.
- final boolean wasHbmDrainingAvailableTime = mRunningStartTimeMillis != -1;
+ final long runningStartTime = mHighBrightnessModeMetadata.getRunningStartTimeMillis();
+ final boolean wasHbmDrainingAvailableTime = runningStartTime != -1;
final boolean shouldHbmDrainAvailableTime = mBrightness > mHbmData.transitionPoint
&& !mIsHdrLayerPresent;
if (wasHbmDrainingAvailableTime != shouldHbmDrainAvailableTime) {
final long currentTime = mClock.uptimeMillis();
if (shouldHbmDrainAvailableTime) {
- mRunningStartTimeMillis = currentTime;
+ mHighBrightnessModeMetadata.setRunningStartTimeMillis(currentTime);
} else {
- mEvents.addFirst(new HbmEvent(mRunningStartTimeMillis, currentTime));
- mRunningStartTimeMillis = -1;
+ final HbmEvent hbmEvent = new HbmEvent(runningStartTime, currentTime);
+ mHighBrightnessModeMetadata.addHbmEvent(hbmEvent);
+ mHighBrightnessModeMetadata.setRunningStartTimeMillis(-1);
if (DEBUG) {
- Slog.d(TAG, "New HBM event: " + mEvents.peekFirst());
+ Slog.d(TAG, "New HBM event: "
+ + mHighBrightnessModeMetadata.getHbmEventQueue().peekFirst());
}
}
}
@@ -260,6 +257,10 @@
mSettingsObserver.stopObserving();
}
+ void setHighBrightnessModeMetadata(HighBrightnessModeMetadata hbmInfo) {
+ mHighBrightnessModeMetadata = hbmInfo;
+ }
+
void resetHbmData(int width, int height, IBinder displayToken, String displayUniqueId,
HighBrightnessModeData hbmData, HdrBrightnessDeviceConfig hdrBrightnessCfg) {
mWidth = width;
@@ -316,20 +317,22 @@
pw.println(" mBrightnessMax=" + mBrightnessMax);
pw.println(" remainingTime=" + calculateRemainingTime(mClock.uptimeMillis()));
pw.println(" mIsTimeAvailable= " + mIsTimeAvailable);
- pw.println(" mRunningStartTimeMillis=" + TimeUtils.formatUptime(mRunningStartTimeMillis));
+ pw.println(" mRunningStartTimeMillis="
+ + TimeUtils.formatUptime(mHighBrightnessModeMetadata.getRunningStartTimeMillis()));
pw.println(" mIsThermalStatusWithinLimit=" + mIsThermalStatusWithinLimit);
pw.println(" mIsBlockedByLowPowerMode=" + mIsBlockedByLowPowerMode);
pw.println(" width*height=" + mWidth + "*" + mHeight);
pw.println(" mEvents=");
final long currentTime = mClock.uptimeMillis();
long lastStartTime = currentTime;
- if (mRunningStartTimeMillis != -1) {
- lastStartTime = dumpHbmEvent(pw, new HbmEvent(mRunningStartTimeMillis, currentTime));
+ long runningStartTimeMillis = mHighBrightnessModeMetadata.getRunningStartTimeMillis();
+ if (runningStartTimeMillis != -1) {
+ lastStartTime = dumpHbmEvent(pw, new HbmEvent(runningStartTimeMillis, currentTime));
}
- for (HbmEvent event : mEvents) {
- if (lastStartTime > event.endTimeMillis) {
+ for (HbmEvent event : mHighBrightnessModeMetadata.getHbmEventQueue()) {
+ if (lastStartTime > event.getEndTimeMillis()) {
pw.println(" event: [normal brightness]: "
- + TimeUtils.formatDuration(lastStartTime - event.endTimeMillis));
+ + TimeUtils.formatDuration(lastStartTime - event.getEndTimeMillis()));
}
lastStartTime = dumpHbmEvent(pw, event);
}
@@ -338,12 +341,12 @@
}
private long dumpHbmEvent(PrintWriter pw, HbmEvent event) {
- final long duration = event.endTimeMillis - event.startTimeMillis;
+ final long duration = event.getEndTimeMillis() - event.getStartTimeMillis();
pw.println(" event: ["
- + TimeUtils.formatUptime(event.startTimeMillis) + ", "
- + TimeUtils.formatUptime(event.endTimeMillis) + "] ("
+ + TimeUtils.formatUptime(event.getStartTimeMillis()) + ", "
+ + TimeUtils.formatUptime(event.getEndTimeMillis()) + "] ("
+ TimeUtils.formatDuration(duration) + ")");
- return event.startTimeMillis;
+ return event.getStartTimeMillis();
}
private boolean isCurrentlyAllowed() {
@@ -372,13 +375,15 @@
// First, lets see how much time we've taken for any currently running
// session of HBM.
- if (mRunningStartTimeMillis > 0) {
- if (mRunningStartTimeMillis > currentTime) {
+ long runningStartTimeMillis = mHighBrightnessModeMetadata.getRunningStartTimeMillis();
+ if (runningStartTimeMillis > 0) {
+ if (runningStartTimeMillis > currentTime) {
Slog.e(TAG, "Start time set to the future. curr: " + currentTime
- + ", start: " + mRunningStartTimeMillis);
- mRunningStartTimeMillis = currentTime;
+ + ", start: " + runningStartTimeMillis);
+ mHighBrightnessModeMetadata.setRunningStartTimeMillis(currentTime);
+ runningStartTimeMillis = currentTime;
}
- timeAlreadyUsed = currentTime - mRunningStartTimeMillis;
+ timeAlreadyUsed = currentTime - runningStartTimeMillis;
}
if (DEBUG) {
@@ -387,18 +392,19 @@
// Next, lets iterate through the history of previous sessions and add those times.
final long windowstartTimeMillis = currentTime - mHbmData.timeWindowMillis;
- Iterator<HbmEvent> it = mEvents.iterator();
+ Iterator<HbmEvent> it = mHighBrightnessModeMetadata.getHbmEventQueue().iterator();
while (it.hasNext()) {
final HbmEvent event = it.next();
// If this event ended before the current Timing window, discard forever and ever.
- if (event.endTimeMillis < windowstartTimeMillis) {
+ if (event.getEndTimeMillis() < windowstartTimeMillis) {
it.remove();
continue;
}
- final long startTimeMillis = Math.max(event.startTimeMillis, windowstartTimeMillis);
- timeAlreadyUsed += event.endTimeMillis - startTimeMillis;
+ final long startTimeMillis = Math.max(event.getStartTimeMillis(),
+ windowstartTimeMillis);
+ timeAlreadyUsed += event.getEndTimeMillis() - startTimeMillis;
}
if (DEBUG) {
@@ -425,17 +431,18 @@
// Calculate the time at which we want to recalculate mIsTimeAvailable in case a lux or
// brightness change doesn't happen before then.
long nextTimeout = -1;
+ final ArrayDeque<HbmEvent> hbmEvents = mHighBrightnessModeMetadata.getHbmEventQueue();
if (mBrightness > mHbmData.transitionPoint) {
// if we're in high-lux now, timeout when we run out of allowed time.
nextTimeout = currentTime + remainingTime;
- } else if (!mIsTimeAvailable && mEvents.size() > 0) {
+ } else if (!mIsTimeAvailable && hbmEvents.size() > 0) {
// If we are not allowed...timeout when the oldest event moved outside of the timing
// window by at least minTime. Basically, we're calculating the soonest time we can
// get {@code timeMinMillis} back to us.
final long windowstartTimeMillis = currentTime - mHbmData.timeWindowMillis;
- final HbmEvent lastEvent = mEvents.peekLast();
+ final HbmEvent lastEvent = hbmEvents.peekLast();
final long startTimePlusMinMillis =
- Math.max(windowstartTimeMillis, lastEvent.startTimeMillis)
+ Math.max(windowstartTimeMillis, lastEvent.getStartTimeMillis())
+ mHbmData.timeMinMillis;
final long timeWhenMinIsGainedBack =
currentTime + (startTimePlusMinMillis - windowstartTimeMillis) - remainingTime;
@@ -459,9 +466,10 @@
+ ", mUnthrottledBrightness: " + mUnthrottledBrightness
+ ", mThrottlingReason: "
+ BrightnessInfo.briMaxReasonToString(mThrottlingReason)
- + ", RunningStartTimeMillis: " + mRunningStartTimeMillis
+ + ", RunningStartTimeMillis: "
+ + mHighBrightnessModeMetadata.getRunningStartTimeMillis()
+ ", nextTimeout: " + (nextTimeout != -1 ? (nextTimeout - currentTime) : -1)
- + ", events: " + mEvents);
+ + ", events: " + hbmEvents);
}
if (nextTimeout != -1) {
@@ -588,25 +596,6 @@
}
}
- /**
- * Represents an event in which High Brightness Mode was enabled.
- */
- private static class HbmEvent {
- public long startTimeMillis;
- public long endTimeMillis;
-
- HbmEvent(long startTimeMillis, long endTimeMillis) {
- this.startTimeMillis = startTimeMillis;
- this.endTimeMillis = endTimeMillis;
- }
-
- @Override
- public String toString() {
- return "[Event: {" + startTimeMillis + ", " + endTimeMillis + "}, total: "
- + ((endTimeMillis - startTimeMillis) / 1000) + "]";
- }
- }
-
@VisibleForTesting
class HdrListener extends SurfaceControlHdrLayerInfoListener {
@Override
diff --git a/services/core/java/com/android/server/display/HighBrightnessModeMetadata.java b/services/core/java/com/android/server/display/HighBrightnessModeMetadata.java
new file mode 100644
index 0000000..37234ff
--- /dev/null
+++ b/services/core/java/com/android/server/display/HighBrightnessModeMetadata.java
@@ -0,0 +1,58 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.display;
+
+import java.util.ArrayDeque;
+
+
+/**
+ * Represents High Brightness Mode metadata associated
+ * with a specific internal physical display.
+ * Required for separately storing data like time information,
+ * and related events when display was in HBM mode per
+ * physical internal display.
+ */
+class HighBrightnessModeMetadata {
+ /**
+ * Queue of previous HBM-events ordered from most recent to least recent.
+ * Meant to store only the events that fall into the most recent
+ * {@link HighBrightnessModeData#timeWindowMillis mHbmData.timeWindowMillis}.
+ */
+ private final ArrayDeque<HbmEvent> mEvents = new ArrayDeque<>();
+
+ /**
+ * If HBM is currently running, this is the start time for the current HBM session.
+ */
+ private long mRunningStartTimeMillis = -1;
+
+ public long getRunningStartTimeMillis() {
+ return mRunningStartTimeMillis;
+ }
+
+ public void setRunningStartTimeMillis(long setTime) {
+ mRunningStartTimeMillis = setTime;
+ }
+
+ public ArrayDeque<HbmEvent> getHbmEventQueue() {
+ return mEvents;
+ }
+
+ public void addHbmEvent(HbmEvent hbmEvent) {
+ mEvents.addFirst(hbmEvent);
+ }
+}
+
diff --git a/services/core/java/com/android/server/display/LogicalDisplayMapper.java b/services/core/java/com/android/server/display/LogicalDisplayMapper.java
index a66cbb8..bb342ff 100644
--- a/services/core/java/com/android/server/display/LogicalDisplayMapper.java
+++ b/services/core/java/com/android/server/display/LogicalDisplayMapper.java
@@ -469,7 +469,7 @@
synchronized (mSyncRoot) {
mBootCompleted = true;
if (mPendingDeviceState != DeviceStateManager.INVALID_DEVICE_STATE) {
- setDeviceStateLocked(mPendingDeviceState, false);
+ setDeviceStateLocked(mPendingDeviceState, /* isOverrideActive= */ false);
}
}
}
diff --git a/services/core/java/com/android/server/display/brightness/strategy/TemporaryBrightnessStrategy.java b/services/core/java/com/android/server/display/brightness/strategy/TemporaryBrightnessStrategy.java
index f8063f3..7d759ca 100644
--- a/services/core/java/com/android/server/display/brightness/strategy/TemporaryBrightnessStrategy.java
+++ b/services/core/java/com/android/server/display/brightness/strategy/TemporaryBrightnessStrategy.java
@@ -48,7 +48,6 @@
BrightnessUtils.constructDisplayBrightnessState(BrightnessReason.REASON_TEMPORARY,
mTemporaryScreenBrightness,
mTemporaryScreenBrightness);
- mTemporaryScreenBrightness = Float.NaN;
return displayBrightnessState;
}
diff --git a/services/core/java/com/android/server/grammaticalinflection/GrammaticalInflectionService.java b/services/core/java/com/android/server/grammaticalinflection/GrammaticalInflectionService.java
index 11a4294..6cfe921 100644
--- a/services/core/java/com/android/server/grammaticalinflection/GrammaticalInflectionService.java
+++ b/services/core/java/com/android/server/grammaticalinflection/GrammaticalInflectionService.java
@@ -21,6 +21,7 @@
import android.app.IGrammaticalInflectionManager;
import android.content.Context;
import android.os.IBinder;
+import android.os.SystemProperties;
import com.android.server.LocalServices;
import com.android.server.SystemService;
@@ -34,6 +35,8 @@
public class GrammaticalInflectionService extends SystemService {
private final ActivityTaskManagerInternal mActivityTaskManagerInternal;
+ private static final String GRAMMATICAL_INFLECTION_ENABLED =
+ "i18n.grammatical_Inflection.enabled";
/**
* Initializes the system service.
@@ -67,6 +70,10 @@
private void setRequestedApplicationGrammaticalGender(
String appPackageName, int userId, int gender) {
+ if (!SystemProperties.getBoolean(GRAMMATICAL_INFLECTION_ENABLED, true)) {
+ return;
+ }
+
final ActivityTaskManagerInternal.PackageConfigurationUpdater updater =
mActivityTaskManagerInternal.createPackageConfigurationUpdater(appPackageName,
userId);
diff --git a/services/core/java/com/android/server/hdmi/Constants.java b/services/core/java/com/android/server/hdmi/Constants.java
index 5353092..59aa3f9 100644
--- a/services/core/java/com/android/server/hdmi/Constants.java
+++ b/services/core/java/com/android/server/hdmi/Constants.java
@@ -619,6 +619,14 @@
})
@interface HpdSignalType {}
+ static final String DEVICE_CONFIG_FEATURE_FLAG_SOUNDBAR_MODE = "soundbar_mode";
+ static final String DEVICE_CONFIG_FEATURE_FLAG_ENABLE_EARC_TX = "enable_earc_tx";
+ @StringDef({
+ DEVICE_CONFIG_FEATURE_FLAG_SOUNDBAR_MODE,
+ DEVICE_CONFIG_FEATURE_FLAG_ENABLE_EARC_TX
+ })
+ @interface FeatureFlag {}
+
private Constants() {
/* cannot be instantiated */
}
diff --git a/services/core/java/com/android/server/hdmi/DeviceConfigWrapper.java b/services/core/java/com/android/server/hdmi/DeviceConfigWrapper.java
new file mode 100644
index 0000000..f391897
--- /dev/null
+++ b/services/core/java/com/android/server/hdmi/DeviceConfigWrapper.java
@@ -0,0 +1,38 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.hdmi;
+
+import android.provider.DeviceConfig;
+
+import java.util.concurrent.Executor;
+
+/**
+ * Abstraction around {@link DeviceConfig} to allow faking DeviceConfig in tests.
+ */
+public class DeviceConfigWrapper {
+ private static final String TAG = "DeviceConfigWrapper";
+
+ boolean getBoolean(String name, boolean defaultValue) {
+ return DeviceConfig.getBoolean(DeviceConfig.NAMESPACE_HDMI_CONTROL, name, defaultValue);
+ }
+
+ void addOnPropertiesChangedListener(Executor mainExecutor,
+ DeviceConfig.OnPropertiesChangedListener onPropertiesChangedListener) {
+ DeviceConfig.addOnPropertiesChangedListener(
+ DeviceConfig.NAMESPACE_HDMI_CONTROL, mainExecutor, onPropertiesChangedListener);
+ }
+}
diff --git a/services/core/java/com/android/server/hdmi/HdmiCecController.java b/services/core/java/com/android/server/hdmi/HdmiCecController.java
index d1354d1..ceb8785 100644
--- a/services/core/java/com/android/server/hdmi/HdmiCecController.java
+++ b/services/core/java/com/android/server/hdmi/HdmiCecController.java
@@ -19,16 +19,16 @@
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.hardware.hdmi.HdmiPortInfo;
-import android.hardware.tv.cec.CecMessage;
-import android.hardware.tv.cec.IHdmiCec;
-import android.hardware.tv.cec.IHdmiCecCallback;
import android.hardware.tv.cec.V1_0.HotplugEvent;
import android.hardware.tv.cec.V1_0.IHdmiCec.getPhysicalAddressCallback;
import android.hardware.tv.cec.V1_0.OptionKey;
import android.hardware.tv.cec.V1_0.Result;
import android.hardware.tv.cec.V1_0.SendMessageResult;
-import android.hardware.tv.hdmi.IHdmi;
-import android.hardware.tv.hdmi.IHdmiCallback;
+import android.hardware.tv.hdmi.cec.CecMessage;
+import android.hardware.tv.hdmi.cec.IHdmiCec;
+import android.hardware.tv.hdmi.cec.IHdmiCecCallback;
+import android.hardware.tv.hdmi.connection.IHdmiConnection;
+import android.hardware.tv.hdmi.connection.IHdmiConnectionCallback;
import android.icu.util.IllformedLocaleException;
import android.icu.util.ULocale;
import android.os.Binder;
@@ -184,7 +184,7 @@
if (controller != null) {
return controller;
}
- HdmiLogger.warning("Unable to use CEC and HDMI AIDL HALs");
+ HdmiLogger.warning("Unable to use CEC and HDMI Connection AIDL HALs");
controller = createWithNativeWrapper(service, new NativeWrapperImpl11(), atomWriter);
if (controller != null) {
@@ -911,14 +911,14 @@
private static final class NativeWrapperImplAidl
implements NativeWrapper, IBinder.DeathRecipient {
private IHdmiCec mHdmiCec;
- private IHdmi mHdmi;
+ private IHdmiConnection mHdmiConnection;
@Nullable private HdmiCecCallback mCallback;
private final Object mLock = new Object();
@Override
public String nativeInit() {
- return connectToHal() ? mHdmiCec.toString() + " " + mHdmi.toString() : null;
+ return connectToHal() ? mHdmiCec.toString() + " " + mHdmiConnection.toString() : null;
}
boolean connectToHal() {
@@ -935,15 +935,15 @@
HdmiLogger.error("Couldn't link to death : ", e);
}
- mHdmi =
- IHdmi.Stub.asInterface(
- ServiceManager.getService(IHdmi.DESCRIPTOR + "/default"));
- if (mHdmi == null) {
- HdmiLogger.error("Could not initialize HDMI AIDL HAL");
+ mHdmiConnection =
+ IHdmiConnection.Stub.asInterface(
+ ServiceManager.getService(IHdmiConnection.DESCRIPTOR + "/default"));
+ if (mHdmiConnection == null) {
+ HdmiLogger.error("Could not initialize HDMI Connection AIDL HAL");
return false;
}
try {
- mHdmi.asBinder().linkToDeath(this, 0);
+ mHdmiConnection.asBinder().linkToDeath(this, 0);
} catch (RemoteException e) {
HdmiLogger.error("Couldn't link to death : ", e);
}
@@ -954,8 +954,8 @@
public void binderDied() {
// One of the services died, try to reconnect to both.
mHdmiCec.asBinder().unlinkToDeath(this, 0);
- mHdmi.asBinder().unlinkToDeath(this, 0);
- HdmiLogger.error("HDMI or CEC service died, reconnecting");
+ mHdmiConnection.asBinder().unlinkToDeath(this, 0);
+ HdmiLogger.error("HDMI Connection or CEC service died, reconnecting");
connectToHal();
// Reconnect the callback
if (mCallback != null) {
@@ -974,7 +974,7 @@
}
try {
// Create an AIDL callback that can callback onHotplugEvent
- mHdmi.setCallback(new HdmiCallbackAidl(callback));
+ mHdmiConnection.setCallback(new HdmiConnectionCallbackAidl(callback));
} catch (RemoteException e) {
HdmiLogger.error("Couldn't initialise tv.hdmi callback : ", e);
}
@@ -1091,10 +1091,11 @@
@Override
public HdmiPortInfo[] nativeGetPortInfos() {
try {
- android.hardware.tv.hdmi.HdmiPortInfo[] hdmiPortInfos = mHdmi.getPortInfo();
+ android.hardware.tv.hdmi.connection.HdmiPortInfo[] hdmiPortInfos =
+ mHdmiConnection.getPortInfo();
HdmiPortInfo[] hdmiPortInfo = new HdmiPortInfo[hdmiPortInfos.length];
int i = 0;
- for (android.hardware.tv.hdmi.HdmiPortInfo portInfo : hdmiPortInfos) {
+ for (android.hardware.tv.hdmi.connection.HdmiPortInfo portInfo : hdmiPortInfos) {
hdmiPortInfo[i] =
new HdmiPortInfo(
portInfo.portId,
@@ -1116,7 +1117,7 @@
@Override
public boolean nativeIsConnected(int port) {
try {
- return mHdmi.isConnected(port);
+ return mHdmiConnection.isConnected(port);
} catch (RemoteException e) {
HdmiLogger.error("Failed to get connection info : ", e);
return false;
@@ -1624,10 +1625,10 @@
}
}
- private static final class HdmiCallbackAidl extends IHdmiCallback.Stub {
+ private static final class HdmiConnectionCallbackAidl extends IHdmiConnectionCallback.Stub {
private final HdmiCecCallback mHdmiCecCallback;
- HdmiCallbackAidl(HdmiCecCallback hdmiCecCallback) {
+ HdmiConnectionCallbackAidl(HdmiCecCallback hdmiCecCallback) {
mHdmiCecCallback = hdmiCecCallback;
}
@@ -1638,12 +1639,12 @@
@Override
public synchronized String getInterfaceHash() throws android.os.RemoteException {
- return IHdmiCallback.Stub.HASH;
+ return IHdmiConnectionCallback.Stub.HASH;
}
@Override
public int getInterfaceVersion() throws android.os.RemoteException {
- return IHdmiCallback.Stub.VERSION;
+ return IHdmiConnectionCallback.Stub.VERSION;
}
}
diff --git a/services/core/java/com/android/server/hdmi/HdmiControlService.java b/services/core/java/com/android/server/hdmi/HdmiControlService.java
index f66f8ea..7ac8fd0 100644
--- a/services/core/java/com/android/server/hdmi/HdmiControlService.java
+++ b/services/core/java/com/android/server/hdmi/HdmiControlService.java
@@ -18,6 +18,7 @@
import static android.hardware.hdmi.HdmiControlManager.DEVICE_EVENT_ADD_DEVICE;
import static android.hardware.hdmi.HdmiControlManager.DEVICE_EVENT_REMOVE_DEVICE;
+import static android.hardware.hdmi.HdmiControlManager.EARC_FEATURE_DISABLED;
import static android.hardware.hdmi.HdmiControlManager.EARC_FEATURE_ENABLED;
import static android.hardware.hdmi.HdmiControlManager.HDMI_CEC_CONTROL_ENABLED;
import static android.hardware.hdmi.HdmiControlManager.SOUNDBAR_MODE_DISABLED;
@@ -86,6 +87,7 @@
import android.os.SystemClock;
import android.os.SystemProperties;
import android.os.UserHandle;
+import android.provider.DeviceConfig;
import android.provider.Settings.Global;
import android.sysprop.HdmiProperties;
import android.text.TextUtils;
@@ -450,6 +452,12 @@
private boolean mWakeUpMessageReceived = false;
@ServiceThreadOnly
+ private boolean mSoundbarModeFeatureFlagEnabled = false;
+
+ @ServiceThreadOnly
+ private boolean mEarcTxFeatureFlagEnabled = false;
+
+ @ServiceThreadOnly
private int mActivePortId = Constants.INVALID_PORT_ID;
// Set to true while the input change by MHL is allowed.
@@ -471,6 +479,9 @@
private TvInputManager mTvInputManager;
@Nullable
+ private DeviceConfigWrapper mDeviceConfig;
+
+ @Nullable
private PowerManagerWrapper mPowerManager;
@Nullable
@@ -525,6 +536,7 @@
mCecLocalDevices = deviceTypes;
mSettingsObserver = new SettingsObserver(mHandler);
mHdmiCecConfig = new HdmiCecConfig(context);
+ mDeviceConfig = new DeviceConfigWrapper();
mAudioDeviceVolumeManager = audioDeviceVolumeManager;
}
@@ -533,6 +545,7 @@
mCecLocalDevices = readDeviceTypes();
mSettingsObserver = new SettingsObserver(mHandler);
mHdmiCecConfig = new HdmiCecConfig(context);
+ mDeviceConfig = new DeviceConfigWrapper();
}
@VisibleForTesting
@@ -657,9 +670,18 @@
setProhibitMode(false);
mHdmiControlEnabled = mHdmiCecConfig.getIntValue(
HdmiControlManager.CEC_SETTING_NAME_HDMI_CEC_ENABLED);
+
+ mSoundbarModeFeatureFlagEnabled = mDeviceConfig.getBoolean(
+ Constants.DEVICE_CONFIG_FEATURE_FLAG_SOUNDBAR_MODE, false);
+ mEarcTxFeatureFlagEnabled = mDeviceConfig.getBoolean(
+ Constants.DEVICE_CONFIG_FEATURE_FLAG_ENABLE_EARC_TX, false);
+
synchronized (mLock) {
mEarcEnabled = (mHdmiCecConfig.getIntValue(
HdmiControlManager.SETTING_NAME_EARC_ENABLED) == EARC_FEATURE_ENABLED);
+ if (isTvDevice()) {
+ mEarcEnabled &= mEarcTxFeatureFlagEnabled;
+ }
}
setHdmiCecVolumeControlEnabledInternal(getHdmiCecConfig().getIntValue(
HdmiControlManager.CEC_SETTING_NAME_VOLUME_CONTROL_MODE));
@@ -763,14 +785,6 @@
}
}
}, mServiceThreadExecutor);
- mHdmiCecConfig.registerChangeListener(HdmiControlManager.CEC_SETTING_NAME_SOUNDBAR_MODE,
- new HdmiCecConfig.SettingChangeListener() {
- @Override
- public void onChange(String setting) {
- setSoundbarMode(mHdmiCecConfig.getIntValue(
- HdmiControlManager.CEC_SETTING_NAME_SOUNDBAR_MODE));
- }
- }, mServiceThreadExecutor);
mHdmiCecConfig.registerChangeListener(
HdmiControlManager.CEC_SETTING_NAME_SYSTEM_AUDIO_CONTROL,
new HdmiCecConfig.SettingChangeListener() {
@@ -811,17 +825,68 @@
}
}
}, mServiceThreadExecutor);
+
+ if (isTvDevice()) {
+ mDeviceConfig.addOnPropertiesChangedListener(getContext().getMainExecutor(),
+ new DeviceConfig.OnPropertiesChangedListener() {
+ @Override
+ public void onPropertiesChanged(DeviceConfig.Properties properties) {
+ mEarcTxFeatureFlagEnabled = properties.getBoolean(
+ Constants.DEVICE_CONFIG_FEATURE_FLAG_ENABLE_EARC_TX,
+ false);
+ boolean earcEnabledSetting = mHdmiCecConfig.getIntValue(
+ HdmiControlManager.SETTING_NAME_EARC_ENABLED)
+ == EARC_FEATURE_ENABLED;
+ setEarcEnabled(earcEnabledSetting && mEarcTxFeatureFlagEnabled
+ ? EARC_FEATURE_ENABLED : EARC_FEATURE_DISABLED);
+ }
+ });
+ }
+
mHdmiCecConfig.registerChangeListener(HdmiControlManager.SETTING_NAME_EARC_ENABLED,
new HdmiCecConfig.SettingChangeListener() {
@Override
public void onChange(String setting) {
- @HdmiControlManager.HdmiCecControl int enabled = mHdmiCecConfig.getIntValue(
- HdmiControlManager.SETTING_NAME_EARC_ENABLED);
- setEarcEnabled(enabled);
+ if (isTvDevice()) {
+ boolean earcEnabledSetting = mHdmiCecConfig.getIntValue(
+ HdmiControlManager.SETTING_NAME_EARC_ENABLED)
+ == EARC_FEATURE_ENABLED;
+ setEarcEnabled(earcEnabledSetting && mEarcTxFeatureFlagEnabled
+ ? EARC_FEATURE_ENABLED : EARC_FEATURE_DISABLED);
+ } else {
+ setEarcEnabled(mHdmiCecConfig.getIntValue(
+ HdmiControlManager.SETTING_NAME_EARC_ENABLED));
+ }
+ }
+ },
+ mServiceThreadExecutor);
+
+ mDeviceConfig.addOnPropertiesChangedListener(getContext().getMainExecutor(),
+ new DeviceConfig.OnPropertiesChangedListener() {
+ @Override
+ public void onPropertiesChanged(DeviceConfig.Properties properties) {
+ mSoundbarModeFeatureFlagEnabled = properties.getBoolean(
+ Constants.DEVICE_CONFIG_FEATURE_FLAG_SOUNDBAR_MODE,
+ false);
+ boolean soundbarModeSetting = mHdmiCecConfig.getIntValue(
+ HdmiControlManager.CEC_SETTING_NAME_SOUNDBAR_MODE)
+ == SOUNDBAR_MODE_ENABLED;
+ setSoundbarMode(soundbarModeSetting && mSoundbarModeFeatureFlagEnabled
+ ? SOUNDBAR_MODE_ENABLED : SOUNDBAR_MODE_DISABLED);
+ }
+ });
+ mHdmiCecConfig.registerChangeListener(HdmiControlManager.CEC_SETTING_NAME_SOUNDBAR_MODE,
+ new HdmiCecConfig.SettingChangeListener() {
+ @Override
+ public void onChange(String setting) {
+ boolean soundbarModeSetting = mHdmiCecConfig.getIntValue(
+ HdmiControlManager.CEC_SETTING_NAME_SOUNDBAR_MODE)
+ == SOUNDBAR_MODE_ENABLED;
+ setSoundbarMode(soundbarModeSetting && mSoundbarModeFeatureFlagEnabled
+ ? SOUNDBAR_MODE_ENABLED : SOUNDBAR_MODE_DISABLED);
}
}, mServiceThreadExecutor);
}
-
/** Returns true if the device screen is off */
boolean isScreenOff() {
return mDisplayManager.getDisplay(Display.DEFAULT_DISPLAY).getState() == Display.STATE_OFF;
@@ -920,6 +985,11 @@
}
@VisibleForTesting
+ void setDeviceConfig(DeviceConfigWrapper deviceConfig) {
+ mDeviceConfig = deviceConfig;
+ }
+
+ @VisibleForTesting
void setPowerManager(PowerManagerWrapper powerManager) {
mPowerManager = powerManager;
}
@@ -929,6 +999,10 @@
mPowerManagerInternal = powerManagerInternal;
}
+ DeviceConfigWrapper getDeviceConfig() {
+ return mDeviceConfig;
+ }
+
PowerManagerWrapper getPowerManager() {
return mPowerManager;
}
@@ -1151,7 +1225,8 @@
if (mHdmiCecConfig.getIntValue(HdmiControlManager.CEC_SETTING_NAME_SOUNDBAR_MODE)
== SOUNDBAR_MODE_ENABLED
&& !allLocalDeviceTypes.contains(HdmiDeviceInfo.DEVICE_AUDIO_SYSTEM)
- && SystemProperties.getBoolean(Constants.PROPERTY_ARC_SUPPORT, true)) {
+ && SystemProperties.getBoolean(Constants.PROPERTY_ARC_SUPPORT, true)
+ && mSoundbarModeFeatureFlagEnabled) {
allLocalDeviceTypes.add(HdmiDeviceInfo.DEVICE_AUDIO_SYSTEM);
}
return allLocalDeviceTypes;
@@ -4524,6 +4599,11 @@
startArcAction(false, new IHdmiControlCallback.Stub() {
@Override
public void onComplete(int result) throws RemoteException {
+ if (result != HdmiControlManager.RESULT_SUCCESS) {
+ Slog.w(TAG,
+ "ARC termination before enabling eARC in the HAL failed with "
+ + "result: " + result);
+ }
// Independently of the result (i.e. independently of whether the ARC RX device
// responded with <Terminate ARC> or not), we always end up terminating ARC in
// the HAL. As soon as we do that, we can enable eARC in the HAL.
diff --git a/services/core/java/com/android/server/input/BatteryController.java b/services/core/java/com/android/server/input/BatteryController.java
index c99a7a0..993b4fd 100644
--- a/services/core/java/com/android/server/input/BatteryController.java
+++ b/services/core/java/com/android/server/input/BatteryController.java
@@ -31,6 +31,7 @@
import android.hardware.input.IInputDeviceBatteryState;
import android.hardware.input.InputManager;
import android.os.Handler;
+import android.os.HandlerExecutor;
import android.os.IBinder;
import android.os.Looper;
import android.os.RemoteException;
@@ -51,6 +52,7 @@
import java.util.Arrays;
import java.util.Objects;
import java.util.Set;
+import java.util.concurrent.Executor;
import java.util.function.Consumer;
import java.util.function.Function;
import java.util.function.Predicate;
@@ -102,7 +104,7 @@
BatteryController(Context context, NativeInputManagerService nativeService, Looper looper) {
this(context, nativeService, looper, new UEventManager() {},
- new LocalBluetoothBatteryManager(context));
+ new LocalBluetoothBatteryManager(context, looper));
}
@VisibleForTesting
@@ -163,7 +165,7 @@
// This is the first listener that is monitoring this device.
monitor = new DeviceMonitor(deviceId);
mDeviceMonitors.put(deviceId, monitor);
- updateBluetoothMonitoring();
+ updateBluetoothBatteryMonitoring();
}
if (DEBUG) {
@@ -378,13 +380,26 @@
}
}
- private void handleBluetoothBatteryLevelChange(long eventTime, String address) {
+ private void handleBluetoothBatteryLevelChange(long eventTime, String address,
+ int batteryLevel) {
synchronized (mLock) {
final DeviceMonitor monitor = findIf(mDeviceMonitors, (m) ->
(m.mBluetoothDevice != null
&& address.equals(m.mBluetoothDevice.getAddress())));
if (monitor != null) {
- monitor.onBluetoothBatteryChanged(eventTime);
+ monitor.onBluetoothBatteryChanged(eventTime, batteryLevel);
+ }
+ }
+ }
+
+ private void handleBluetoothMetadataChange(@NonNull BluetoothDevice device, int key,
+ @Nullable byte[] value) {
+ synchronized (mLock) {
+ final DeviceMonitor monitor =
+ findIf(mDeviceMonitors, (m) -> device.equals(m.mBluetoothDevice));
+ if (monitor != null) {
+ final long eventTime = SystemClock.uptimeMillis();
+ monitor.onBluetoothMetadataChanged(eventTime, key, value);
}
}
}
@@ -514,31 +529,19 @@
isPresent ? mNative.getBatteryCapacity(deviceId) / 100.f : Float.NaN);
}
- // Queries the battery state of an input device from Bluetooth.
- private State queryBatteryStateFromBluetooth(int deviceId, long updateTime,
- @NonNull BluetoothDevice bluetoothDevice) {
- final int level = mBluetoothBatteryManager.getBatteryLevel(bluetoothDevice.getAddress());
- if (level == BluetoothDevice.BATTERY_LEVEL_BLUETOOTH_OFF
- || level == BluetoothDevice.BATTERY_LEVEL_UNKNOWN) {
- return new State(deviceId);
- }
- return new State(deviceId, updateTime, true /*isPresent*/, BatteryState.STATUS_UNKNOWN,
- level / 100.f);
- }
-
- private void updateBluetoothMonitoring() {
+ private void updateBluetoothBatteryMonitoring() {
synchronized (mLock) {
if (anyOf(mDeviceMonitors, (m) -> m.mBluetoothDevice != null)) {
// At least one input device being monitored is connected over Bluetooth.
if (mBluetoothBatteryListener == null) {
if (DEBUG) Slog.d(TAG, "Registering bluetooth battery listener");
mBluetoothBatteryListener = this::handleBluetoothBatteryLevelChange;
- mBluetoothBatteryManager.addListener(mBluetoothBatteryListener);
+ mBluetoothBatteryManager.addBatteryListener(mBluetoothBatteryListener);
}
} else if (mBluetoothBatteryListener != null) {
// No Bluetooth input devices are monitored, so remove the registered listener.
if (DEBUG) Slog.d(TAG, "Unregistering bluetooth battery listener");
- mBluetoothBatteryManager.removeListener(mBluetoothBatteryListener);
+ mBluetoothBatteryManager.removeBatteryListener(mBluetoothBatteryListener);
mBluetoothBatteryListener = null;
}
}
@@ -550,16 +553,23 @@
// Represents whether the input device has a sysfs battery node.
protected boolean mHasBattery = false;
- protected final State mBluetoothState;
@Nullable
private BluetoothDevice mBluetoothDevice;
+ long mBluetoothEventTime = 0;
+ // The battery level reported by the Bluetooth Hands-Free Profile (HPF) obtained through
+ // BluetoothDevice#getBatteryLevel().
+ int mBluetoothBatteryLevel = BluetoothDevice.BATTERY_LEVEL_UNKNOWN;
+ // The battery level and status reported through the Bluetooth device's metadata.
+ int mBluetoothMetadataBatteryLevel = BluetoothDevice.BATTERY_LEVEL_UNKNOWN;
+ int mBluetoothMetadataBatteryStatus = BatteryState.STATUS_UNKNOWN;
+ @Nullable
+ private BluetoothAdapter.OnMetadataChangedListener mBluetoothMetadataListener;
@Nullable
private UEventBatteryListener mUEventBatteryListener;
DeviceMonitor(int deviceId) {
mState = new State(deviceId);
- mBluetoothState = new State(deviceId);
// Load the initial battery state and start monitoring.
final long eventTime = SystemClock.uptimeMillis();
@@ -570,7 +580,7 @@
final State oldState = getBatteryStateForReporting();
changes.accept(eventTime);
final State newState = getBatteryStateForReporting();
- if (!oldState.equals(newState)) {
+ if (!oldState.equalsIgnoringUpdateTime(newState)) {
notifyAllListenersForDevice(newState);
}
}
@@ -594,13 +604,22 @@
final BluetoothDevice bluetoothDevice = getBluetoothDevice(deviceId);
if (!Objects.equals(mBluetoothDevice, bluetoothDevice)) {
if (DEBUG) {
- Slog.d(TAG, "Bluetooth device "
- + ((bluetoothDevice != null) ? "is" : "is not")
- + " now present for deviceId " + deviceId);
+ Slog.d(TAG, "Bluetooth device is now "
+ + ((bluetoothDevice != null) ? "" : "not")
+ + " present for deviceId " + deviceId);
}
+
+ mBluetoothBatteryLevel = BluetoothDevice.BATTERY_LEVEL_UNKNOWN;
+ stopBluetoothMetadataMonitoring();
+
mBluetoothDevice = bluetoothDevice;
- updateBluetoothMonitoring();
- updateBatteryStateFromBluetooth(eventTime);
+ updateBluetoothBatteryMonitoring();
+
+ if (mBluetoothDevice != null) {
+ mBluetoothBatteryLevel = mBluetoothBatteryManager.getBatteryLevel(
+ mBluetoothDevice.getAddress());
+ startBluetoothMetadataMonitoring(eventTime);
+ }
}
}
@@ -632,11 +651,39 @@
}
}
+ private void startBluetoothMetadataMonitoring(long eventTime) {
+ Objects.requireNonNull(mBluetoothDevice);
+
+ mBluetoothMetadataListener = BatteryController.this::handleBluetoothMetadataChange;
+ mBluetoothBatteryManager.addMetadataListener(mBluetoothDevice.getAddress(),
+ mBluetoothMetadataListener);
+ updateBluetoothMetadataState(eventTime, BluetoothDevice.METADATA_MAIN_BATTERY,
+ mBluetoothBatteryManager.getMetadata(mBluetoothDevice.getAddress(),
+ BluetoothDevice.METADATA_MAIN_BATTERY));
+ updateBluetoothMetadataState(eventTime, BluetoothDevice.METADATA_MAIN_CHARGING,
+ mBluetoothBatteryManager.getMetadata(mBluetoothDevice.getAddress(),
+ BluetoothDevice.METADATA_MAIN_CHARGING));
+ }
+
+ private void stopBluetoothMetadataMonitoring() {
+ if (mBluetoothMetadataListener == null) {
+ return;
+ }
+ Objects.requireNonNull(mBluetoothDevice);
+
+ mBluetoothBatteryManager.removeMetadataListener(
+ mBluetoothDevice.getAddress(), mBluetoothMetadataListener);
+ mBluetoothMetadataListener = null;
+ mBluetoothMetadataBatteryLevel = BluetoothDevice.BATTERY_LEVEL_UNKNOWN;
+ mBluetoothMetadataBatteryStatus = BatteryState.STATUS_UNKNOWN;
+ }
+
// This must be called when the device is no longer being monitored.
public void onMonitorDestroy() {
stopNativeMonitoring();
+ stopBluetoothMetadataMonitoring();
mBluetoothDevice = null;
- updateBluetoothMonitoring();
+ updateBluetoothBatteryMonitoring();
}
protected void updateBatteryStateFromNative(long eventTime) {
@@ -644,13 +691,6 @@
queryBatteryStateFromNative(mState.deviceId, eventTime, mHasBattery));
}
- protected void updateBatteryStateFromBluetooth(long eventTime) {
- final State bluetoothState = mBluetoothDevice == null ? new State(mState.deviceId)
- : queryBatteryStateFromBluetooth(mState.deviceId, eventTime,
- mBluetoothDevice);
- mBluetoothState.updateIfChanged(bluetoothState);
- }
-
public void onPoll(long eventTime) {
processChangesAndNotify(eventTime, this::updateBatteryStateFromNative);
}
@@ -659,8 +699,51 @@
processChangesAndNotify(eventTime, this::updateBatteryStateFromNative);
}
- public void onBluetoothBatteryChanged(long eventTime) {
- processChangesAndNotify(eventTime, this::updateBatteryStateFromBluetooth);
+ public void onBluetoothBatteryChanged(long eventTime, int bluetoothBatteryLevel) {
+ processChangesAndNotify(eventTime, (time) -> {
+ mBluetoothBatteryLevel = bluetoothBatteryLevel;
+ mBluetoothEventTime = time;
+ });
+ }
+
+ public void onBluetoothMetadataChanged(long eventTime, int key, @Nullable byte[] value) {
+ processChangesAndNotify(eventTime,
+ (time) -> updateBluetoothMetadataState(time, key, value));
+ }
+
+ private void updateBluetoothMetadataState(long eventTime, int key,
+ @Nullable byte[] value) {
+ switch (key) {
+ case BluetoothDevice.METADATA_MAIN_BATTERY:
+ mBluetoothEventTime = eventTime;
+ mBluetoothMetadataBatteryLevel = BluetoothDevice.BATTERY_LEVEL_UNKNOWN;
+ if (value != null) {
+ try {
+ mBluetoothMetadataBatteryLevel = Integer.parseInt(
+ new String(value));
+ } catch (NumberFormatException e) {
+ Slog.wtf(TAG,
+ "Failed to parse bluetooth METADATA_MAIN_BATTERY with "
+ + "value '"
+ + new String(value) + "' for device "
+ + mBluetoothDevice);
+ }
+ }
+ break;
+ case BluetoothDevice.METADATA_MAIN_CHARGING:
+ mBluetoothEventTime = eventTime;
+ if (value != null) {
+ mBluetoothMetadataBatteryStatus = Boolean.parseBoolean(
+ new String(value))
+ ? BatteryState.STATUS_CHARGING
+ : BatteryState.STATUS_DISCHARGING;
+ } else {
+ mBluetoothMetadataBatteryStatus = BatteryState.STATUS_UNKNOWN;
+ }
+ break;
+ default:
+ break;
+ }
}
public boolean requiresPolling() {
@@ -677,11 +760,25 @@
// Returns the current battery state that can be used to notify listeners BatteryController.
public State getBatteryStateForReporting() {
- // Give precedence to the Bluetooth battery state if it's present.
- if (mBluetoothState.isPresent) {
- return new State(mBluetoothState);
+ // Give precedence to the Bluetooth battery state, and fall back to the native state.
+ return Objects.requireNonNullElseGet(resolveBluetoothBatteryState(),
+ () -> new State(mState));
+ }
+
+ @Nullable
+ protected State resolveBluetoothBatteryState() {
+ final int level;
+ // Prefer battery level obtained from the metadata over the Bluetooth Hands-Free
+ // Profile (HFP).
+ if (mBluetoothMetadataBatteryLevel >= 0 && mBluetoothMetadataBatteryLevel <= 100) {
+ level = mBluetoothMetadataBatteryLevel;
+ } else if (mBluetoothBatteryLevel >= 0 && mBluetoothBatteryLevel <= 100) {
+ level = mBluetoothBatteryLevel;
+ } else {
+ return null;
}
- return new State(mState);
+ return new State(mState.deviceId, mBluetoothEventTime, true,
+ mBluetoothMetadataBatteryStatus, level / 100.f);
}
@Override
@@ -690,7 +787,7 @@
+ ", Name='" + getInputDeviceName(mState.deviceId) + "'"
+ ", NativeBattery=" + mState
+ ", UEventListener=" + (mUEventBatteryListener != null ? "added" : "none")
- + ", BluetoothBattery=" + mBluetoothState;
+ + ", BluetoothState=" + resolveBluetoothBatteryState();
}
}
@@ -775,12 +872,10 @@
@Override
public State getBatteryStateForReporting() {
- // Give precedence to the Bluetooth battery state if it's present.
- if (mBluetoothState.isPresent) {
- return new State(mBluetoothState);
- }
- return mValidityTimeoutCallback != null
- ? new State(mState) : new State(mState.deviceId);
+ // Give precedence to the Bluetooth battery state, and fall back to the native state.
+ return Objects.requireNonNullElseGet(resolveBluetoothBatteryState(),
+ () -> mValidityTimeoutCallback != null
+ ? new State(mState) : new State(mState.deviceId));
}
@Override
@@ -844,15 +939,24 @@
interface BluetoothBatteryManager {
@VisibleForTesting
interface BluetoothBatteryListener {
- void onBluetoothBatteryChanged(long eventTime, String address);
+ void onBluetoothBatteryChanged(long eventTime, String address, int batteryLevel);
}
- void addListener(BluetoothBatteryListener listener);
- void removeListener(BluetoothBatteryListener listener);
+ // Methods used for obtaining the Bluetooth battery level through Bluetooth HFP.
+ void addBatteryListener(BluetoothBatteryListener listener);
+ void removeBatteryListener(BluetoothBatteryListener listener);
int getBatteryLevel(String address);
+
+ // Methods used for obtaining the battery level through Bluetooth metadata.
+ void addMetadataListener(String address,
+ BluetoothAdapter.OnMetadataChangedListener listener);
+ void removeMetadataListener(String address,
+ BluetoothAdapter.OnMetadataChangedListener listener);
+ byte[] getMetadata(String address, int key);
}
private static class LocalBluetoothBatteryManager implements BluetoothBatteryManager {
private final Context mContext;
+ private final Executor mExecutor;
@Nullable
@GuardedBy("mBroadcastReceiver")
private BluetoothBatteryListener mRegisteredListener;
@@ -868,24 +972,25 @@
if (bluetoothDevice == null) {
return;
}
- // We do not use the EXTRA_LEVEL value. Instead, the battery level will be queried
- // from BluetoothDevice later so that we use a single source for the battery level.
+ final int batteryLevel = intent.getIntExtra(BluetoothDevice.EXTRA_BATTERY_LEVEL,
+ BluetoothDevice.BATTERY_LEVEL_UNKNOWN);
synchronized (mBroadcastReceiver) {
if (mRegisteredListener != null) {
final long eventTime = SystemClock.uptimeMillis();
mRegisteredListener.onBluetoothBatteryChanged(
- eventTime, bluetoothDevice.getAddress());
+ eventTime, bluetoothDevice.getAddress(), batteryLevel);
}
}
}
};
- LocalBluetoothBatteryManager(Context context) {
+ LocalBluetoothBatteryManager(Context context, Looper looper) {
mContext = context;
+ mExecutor = new HandlerExecutor(new Handler(looper));
}
@Override
- public void addListener(BluetoothBatteryListener listener) {
+ public void addBatteryListener(BluetoothBatteryListener listener) {
synchronized (mBroadcastReceiver) {
if (mRegisteredListener != null) {
throw new IllegalStateException(
@@ -898,7 +1003,7 @@
}
@Override
- public void removeListener(BluetoothBatteryListener listener) {
+ public void removeBatteryListener(BluetoothBatteryListener listener) {
synchronized (mBroadcastReceiver) {
if (!listener.equals(mRegisteredListener)) {
throw new IllegalStateException("Listener is not registered.");
@@ -912,6 +1017,28 @@
public int getBatteryLevel(String address) {
return getBluetoothDevice(mContext, address).getBatteryLevel();
}
+
+ @Override
+ public void addMetadataListener(String address,
+ BluetoothAdapter.OnMetadataChangedListener listener) {
+ Objects.requireNonNull(mContext.getSystemService(BluetoothManager.class))
+ .getAdapter().addOnMetadataChangedListener(
+ getBluetoothDevice(mContext, address), mExecutor,
+ listener);
+ }
+
+ @Override
+ public void removeMetadataListener(String address,
+ BluetoothAdapter.OnMetadataChangedListener listener) {
+ Objects.requireNonNull(mContext.getSystemService(BluetoothManager.class))
+ .getAdapter().removeOnMetadataChangedListener(
+ getBluetoothDevice(mContext, address), listener);
+ }
+
+ @Override
+ public byte[] getMetadata(String address, int key) {
+ return getBluetoothDevice(mContext, address).getMetadata(key);
+ }
}
// Helper class that adds copying and printing functionality to IInputDeviceBatteryState.
@@ -954,7 +1081,7 @@
this.capacity = capacity;
}
- private boolean equalsIgnoringUpdateTime(IInputDeviceBatteryState other) {
+ public boolean equalsIgnoringUpdateTime(IInputDeviceBatteryState other) {
long updateTime = this.updateTime;
this.updateTime = other.updateTime;
boolean eq = this.equals(other);
diff --git a/services/core/java/com/android/server/input/KeyRemapper.java b/services/core/java/com/android/server/input/KeyRemapper.java
index 950e094..7ba7769 100644
--- a/services/core/java/com/android/server/input/KeyRemapper.java
+++ b/services/core/java/com/android/server/input/KeyRemapper.java
@@ -21,6 +21,8 @@
import android.os.Handler;
import android.os.Looper;
import android.os.Message;
+import android.util.ArrayMap;
+import android.util.FeatureFlagUtils;
import android.view.InputDevice;
import com.android.internal.annotations.GuardedBy;
@@ -65,16 +67,25 @@
}
public void remapKey(int fromKey, int toKey) {
+ if (!supportRemapping()) {
+ return;
+ }
Message msg = Message.obtain(mHandler, MSG_REMAP_KEY, fromKey, toKey);
mHandler.sendMessage(msg);
}
public void clearAllKeyRemappings() {
+ if (!supportRemapping()) {
+ return;
+ }
Message msg = Message.obtain(mHandler, MSG_CLEAR_ALL_REMAPPING);
mHandler.sendMessage(msg);
}
public Map<Integer, Integer> getKeyRemapping() {
+ if (!supportRemapping()) {
+ return new ArrayMap<>();
+ }
synchronized (mDataStore) {
return mDataStore.getKeyRemapping();
}
@@ -124,6 +135,9 @@
@Override
public void onInputDeviceAdded(int deviceId) {
+ if (!supportRemapping()) {
+ return;
+ }
InputManager inputManager = Objects.requireNonNull(
mContext.getSystemService(InputManager.class));
InputDevice inputDevice = inputManager.getInputDevice(deviceId);
@@ -158,4 +172,9 @@
}
return false;
}
+
+ private boolean supportRemapping() {
+ return FeatureFlagUtils.isEnabled(mContext,
+ FeatureFlagUtils.SETTINGS_NEW_KEYBOARD_MODIFIER_KEY);
+ }
}
diff --git a/services/core/java/com/android/server/inputmethod/DefaultImeVisibilityApplier.java b/services/core/java/com/android/server/inputmethod/DefaultImeVisibilityApplier.java
new file mode 100644
index 0000000..86a0857
--- /dev/null
+++ b/services/core/java/com/android/server/inputmethod/DefaultImeVisibilityApplier.java
@@ -0,0 +1,155 @@
+/*
+ * 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 com.android.server.inputmethod;
+
+import static android.view.inputmethod.ImeTracker.DEBUG_IME_VISIBILITY;
+
+import static com.android.server.EventLogTags.IMF_HIDE_IME;
+import static com.android.server.EventLogTags.IMF_SHOW_IME;
+import static com.android.server.inputmethod.ImeVisibilityStateComputer.STATE_HIDE_IME;
+import static com.android.server.inputmethod.ImeVisibilityStateComputer.STATE_SHOW_IME;
+
+import android.annotation.Nullable;
+import android.os.Binder;
+import android.os.IBinder;
+import android.os.ResultReceiver;
+import android.util.EventLog;
+import android.util.Slog;
+import android.view.inputmethod.ImeTracker;
+
+import com.android.internal.annotations.GuardedBy;
+import com.android.internal.inputmethod.InputMethodDebug;
+import com.android.internal.inputmethod.SoftInputShowHideReason;
+import com.android.server.LocalServices;
+import com.android.server.wm.WindowManagerInternal;
+
+import java.util.Objects;
+
+/**
+ * The default implementation of {@link ImeVisibilityApplier} used in
+ * {@link InputMethodManagerService}.
+ */
+final class DefaultImeVisibilityApplier implements ImeVisibilityApplier {
+
+ private static final String TAG = "DefaultImeVisibilityApplier";
+
+ private static final boolean DEBUG = InputMethodManagerService.DEBUG;
+
+ private InputMethodManagerService mService;
+
+ private final WindowManagerInternal mWindowManagerInternal;
+
+
+ DefaultImeVisibilityApplier(InputMethodManagerService service) {
+ mService = service;
+ mWindowManagerInternal = LocalServices.getService(WindowManagerInternal.class);
+ }
+
+ @GuardedBy("ImfLock.class")
+ @Override
+ public void performShowIme(IBinder windowToken, @Nullable ImeTracker.Token statsToken,
+ int showFlags, ResultReceiver resultReceiver, @SoftInputShowHideReason int reason) {
+ final IInputMethodInvoker curMethod = mService.getCurMethodLocked();
+ if (curMethod != null) {
+ // create a placeholder token for IMS so that IMS cannot inject windows into client app.
+ final IBinder showInputToken = new Binder();
+ mService.setRequestImeTokenToWindow(windowToken, showInputToken);
+ if (DEBUG) {
+ Slog.v(TAG, "Calling " + curMethod + ".showSoftInput(" + showInputToken
+ + ", " + showFlags + ", " + resultReceiver + ") for reason: "
+ + InputMethodDebug.softInputDisplayReasonToString(reason));
+ }
+ // TODO(b/192412909): Check if we can always call onShowHideSoftInputRequested() or not.
+ if (curMethod.showSoftInput(showInputToken, statsToken, showFlags, resultReceiver)) {
+ if (DEBUG_IME_VISIBILITY) {
+ EventLog.writeEvent(IMF_SHOW_IME, statsToken.getTag(),
+ Objects.toString(mService.mCurFocusedWindow),
+ InputMethodDebug.softInputDisplayReasonToString(reason),
+ InputMethodDebug.softInputModeToString(
+ mService.mCurFocusedWindowSoftInputMode));
+ }
+ mService.onShowHideSoftInputRequested(true /* show */, windowToken, reason,
+ statsToken);
+ }
+ }
+ }
+
+ @GuardedBy("ImfLock.class")
+ @Override
+ public void performHideIme(IBinder windowToken, @Nullable ImeTracker.Token statsToken,
+ ResultReceiver resultReceiver, @SoftInputShowHideReason int reason) {
+ final IInputMethodInvoker curMethod = mService.getCurMethodLocked();
+ if (curMethod != null) {
+ final Binder hideInputToken = new Binder();
+ mService.setRequestImeTokenToWindow(windowToken, hideInputToken);
+ // The IME will report its visible state again after the following message finally
+ // delivered to the IME process as an IPC. Hence the inconsistency between
+ // IMMS#mInputShown and IMMS#mImeWindowVis should be resolved spontaneously in
+ // the final state.
+ if (DEBUG) {
+ Slog.v(TAG, "Calling " + curMethod + ".hideSoftInput(0, " + hideInputToken
+ + ", " + resultReceiver + ") for reason: "
+ + InputMethodDebug.softInputDisplayReasonToString(reason));
+ }
+ // TODO(b/192412909): Check if we can always call onShowHideSoftInputRequested() or not.
+ if (curMethod.hideSoftInput(hideInputToken, statsToken, 0, resultReceiver)) {
+ if (DEBUG_IME_VISIBILITY) {
+ EventLog.writeEvent(IMF_HIDE_IME, statsToken.getTag(),
+ Objects.toString(mService.mCurFocusedWindow),
+ InputMethodDebug.softInputDisplayReasonToString(reason),
+ InputMethodDebug.softInputModeToString(
+ mService.mCurFocusedWindowSoftInputMode));
+ }
+ mService.onShowHideSoftInputRequested(false /* show */, windowToken, reason,
+ statsToken);
+ }
+ }
+ }
+
+ @GuardedBy("ImfLock.class")
+ @Override
+ public void applyImeVisibility(IBinder windowToken, @Nullable ImeTracker.Token statsToken,
+ @ImeVisibilityStateComputer.VisibilityState int state) {
+ switch (state) {
+ case STATE_SHOW_IME:
+ ImeTracker.get().onProgress(statsToken,
+ ImeTracker.PHASE_SERVER_APPLY_IME_VISIBILITY);
+ // Send to window manager to show IME after IME layout finishes.
+ mWindowManagerInternal.showImePostLayout(windowToken, statsToken);
+ break;
+ case STATE_HIDE_IME:
+ if (mService.mCurFocusedWindowClient != null) {
+ ImeTracker.get().onProgress(statsToken,
+ ImeTracker.PHASE_SERVER_APPLY_IME_VISIBILITY);
+ // IMMS only knows of focused window, not the actual IME target.
+ // e.g. it isn't aware of any window that has both
+ // NOT_FOCUSABLE, ALT_FOCUSABLE_IM flags set and can the IME target.
+ // Send it to window manager to hide IME from IME target window.
+ // TODO(b/139861270): send to mCurClient.client once IMMS is aware of
+ // actual IME target.
+ mWindowManagerInternal.hideIme(windowToken,
+ mService.mCurFocusedWindowClient.mSelfReportedDisplayId, statsToken);
+ } else {
+ ImeTracker.get().onFailed(statsToken,
+ ImeTracker.PHASE_SERVER_APPLY_IME_VISIBILITY);
+ }
+ break;
+ default:
+ throw new IllegalArgumentException("Invalid IME visibility state: " + state);
+ }
+ }
+}
diff --git a/services/core/java/com/android/server/inputmethod/ImeVisibilityApplier.java b/services/core/java/com/android/server/inputmethod/ImeVisibilityApplier.java
new file mode 100644
index 0000000..e97ec93
--- /dev/null
+++ b/services/core/java/com/android/server/inputmethod/ImeVisibilityApplier.java
@@ -0,0 +1,79 @@
+/*
+ * 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 com.android.server.inputmethod;
+
+import android.annotation.Nullable;
+import android.os.IBinder;
+import android.os.ResultReceiver;
+import android.view.inputmethod.ImeTracker;
+
+import com.android.internal.inputmethod.SoftInputShowHideReason;
+
+/**
+ * Interface for IME visibility operations like show/hide and update Z-ordering relative to the IME
+ * targeted window.
+ */
+interface ImeVisibilityApplier {
+ /**
+ * Performs showing IME on top of the given window.
+ *
+ * @param windowToken The token of a window that currently has focus.
+ * @param statsToken A token that tracks the progress of an IME request.
+ * @param showFlags Provides additional operating flags to show IME.
+ * @param resultReceiver If non-null, this will be called back to the caller when
+ * it has processed request to tell what it has done.
+ * @param reason The reason for requesting to show IME.
+ */
+ default void performShowIme(IBinder windowToken, @Nullable ImeTracker.Token statsToken,
+ int showFlags, ResultReceiver resultReceiver, @SoftInputShowHideReason int reason) {}
+
+ /**
+ * Performs hiding IME to the given window
+ *
+ * @param windowToken The token of a window that currently has focus.
+ * @param statsToken A token that tracks the progress of an IME request.
+ * @param resultReceiver If non-null, this will be called back to the caller when
+ * it has processed request to tell what it has done.
+ * @param reason The reason for requesting to hide IME.
+ */
+ default void performHideIme(IBinder windowToken, @Nullable ImeTracker.Token statsToken,
+ ResultReceiver resultReceiver, @SoftInputShowHideReason int reason) {}
+
+ /**
+ * Applies the IME visibility from {@link android.inputmethodservice.InputMethodService} with
+ * according to the given visibility state.
+ *
+ * @param windowToken The token of a window for applying the IME visibility
+ * @param statsToken A token that tracks the progress of an IME request.
+ * @param state The new IME visibility state for the applier to handle
+ */
+ default void applyImeVisibility(IBinder windowToken, @Nullable ImeTracker.Token statsToken,
+ @ImeVisibilityStateComputer.VisibilityState int state) {}
+
+ /**
+ * Updates the IME Z-ordering relative to the given window.
+ *
+ * This used to adjust the IME relative layer of the window during
+ * {@link InputMethodManagerService} is in switching IME clients.
+ *
+ * @param windowToken The token of a window to update the Z-ordering relative to the IME.
+ */
+ default void updateImeLayeringByTarget(IBinder windowToken) {
+ // TODO: add a method in WindowManagerInternal to call DC#updateImeInputAndControlTarget
+ // here to end up updating IME layering after IMMS#attachNewInputLocked called.
+ }
+}
diff --git a/services/core/java/com/android/server/inputmethod/ImeVisibilityStateComputer.java b/services/core/java/com/android/server/inputmethod/ImeVisibilityStateComputer.java
new file mode 100644
index 0000000..a2655f4
--- /dev/null
+++ b/services/core/java/com/android/server/inputmethod/ImeVisibilityStateComputer.java
@@ -0,0 +1,424 @@
+/*
+ * 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 com.android.server.inputmethod;
+
+import static android.accessibilityservice.AccessibilityService.SHOW_MODE_HIDDEN;
+import static android.server.inputmethod.InputMethodManagerServiceProto.ACCESSIBILITY_REQUESTING_NO_SOFT_KEYBOARD;
+import static android.server.inputmethod.InputMethodManagerServiceProto.SHOW_EXPLICITLY_REQUESTED;
+import static android.server.inputmethod.InputMethodManagerServiceProto.SHOW_FORCED;
+import static android.view.Display.DEFAULT_DISPLAY;
+import static android.view.Display.INVALID_DISPLAY;
+import static android.view.WindowManager.LayoutParams.SOFT_INPUT_IS_FORWARD_NAVIGATION;
+import static android.view.WindowManager.LayoutParams.SOFT_INPUT_STATE_UNSPECIFIED;
+import static android.view.WindowManager.LayoutParams.SoftInputModeFlags;
+
+import static com.android.internal.inputmethod.InputMethodDebug.softInputModeToString;
+import static com.android.server.inputmethod.InputMethodManagerService.computeImeDisplayIdForTarget;
+
+import android.accessibilityservice.AccessibilityService;
+import android.annotation.IntDef;
+import android.annotation.NonNull;
+import android.os.IBinder;
+import android.util.PrintWriterPrinter;
+import android.util.Printer;
+import android.util.Slog;
+import android.util.proto.ProtoOutputStream;
+import android.view.WindowManager;
+import android.view.inputmethod.ImeTracker;
+import android.view.inputmethod.InputMethod;
+import android.view.inputmethod.InputMethodManager;
+
+import com.android.server.LocalServices;
+import com.android.server.wm.WindowManagerInternal;
+
+import java.io.PrintWriter;
+import java.util.WeakHashMap;
+
+/**
+ * A computer used by {@link InputMethodManagerService} that computes the IME visibility state
+ * according the given {@link ImeTargetWindowState} from the focused window or the app requested IME
+ * visibility from {@link InputMethodManager}.
+ */
+public final class ImeVisibilityStateComputer {
+
+ private static final String TAG = "ImeVisibilityStateComputer";
+
+ private static final boolean DEBUG = InputMethodManagerService.DEBUG;
+
+ private final InputMethodManagerService mService;
+ private final WindowManagerInternal mWindowManagerInternal;
+
+ final InputMethodManagerService.ImeDisplayValidator mImeDisplayValidator;
+
+ /**
+ * A map used to track the requested IME target window and its state. The key represents the
+ * token of the window and the value is the corresponding IME window state.
+ */
+ private final WeakHashMap<IBinder, ImeTargetWindowState> mRequestWindowStateMap =
+ new WeakHashMap<>();
+
+ /**
+ * Set if IME was explicitly told to show the input method.
+ *
+ * @see InputMethodManager#SHOW_IMPLICIT that we set the value is {@code false}.
+ * @see InputMethodManager#HIDE_IMPLICIT_ONLY that system will not hide IME when the value is
+ * {@code true}.
+ */
+ boolean mRequestedShowExplicitly;
+
+ /**
+ * Set if we were forced to be shown.
+ *
+ * @see InputMethodManager#SHOW_FORCED
+ * @see InputMethodManager#HIDE_NOT_ALWAYS
+ */
+ boolean mShowForced;
+
+ /** Represent the invalid IME visibility state */
+ public static final int STATE_INVALID = -1;
+
+ /** State to handle hiding the IME window requested by the app. */
+ public static final int STATE_HIDE_IME = 0;
+
+ /** State to handle showing the IME window requested by the app. */
+ public static final int STATE_SHOW_IME = 1;
+
+ /** State to handle showing the IME window with making the overlay window above it. */
+ public static final int STATE_SHOW_IME_ABOVE_OVERLAY = 2;
+
+ /** State to handle showing the IME window with making the overlay window behind it. */
+ public static final int STATE_SHOW_IME_BEHIND_OVERLAY = 3;
+
+ /** State to handle showing an IME preview surface during the app was loosing the IME focus */
+ public static final int STATE_SHOW_IME_SNAPSHOT = 4;
+ @IntDef({
+ STATE_INVALID,
+ STATE_HIDE_IME,
+ STATE_SHOW_IME,
+ STATE_SHOW_IME_ABOVE_OVERLAY,
+ STATE_SHOW_IME_BEHIND_OVERLAY,
+ STATE_SHOW_IME_SNAPSHOT,
+ })
+ @interface VisibilityState {}
+
+ /**
+ * The policy to configure the IME visibility.
+ */
+ private final ImeVisibilityPolicy mPolicy;
+
+ public ImeVisibilityStateComputer(InputMethodManagerService service) {
+ mService = service;
+ mWindowManagerInternal = LocalServices.getService(WindowManagerInternal.class);
+ mImeDisplayValidator = mWindowManagerInternal::getDisplayImePolicy;
+ mPolicy = new ImeVisibilityPolicy();
+ }
+
+ /**
+ * Called when {@link InputMethodManagerService} is processing the show IME request.
+ * @param statsToken The token for tracking this show request
+ * @param showFlags The additional operation flags to indicate whether this show request mode is
+ * implicit or explicit.
+ * @return {@code true} when the computer has proceed this show request operation.
+ */
+ boolean onImeShowFlags(@NonNull ImeTracker.Token statsToken, int showFlags) {
+ if (mPolicy.mA11yRequestingNoSoftKeyboard || mPolicy.mImeHiddenByDisplayPolicy) {
+ ImeTracker.get().onFailed(statsToken, ImeTracker.PHASE_SERVER_ACCESSIBILITY);
+ return false;
+ }
+ ImeTracker.get().onProgress(statsToken, ImeTracker.PHASE_SERVER_ACCESSIBILITY);
+ if ((showFlags & InputMethodManager.SHOW_FORCED) != 0) {
+ mRequestedShowExplicitly = true;
+ mShowForced = true;
+ } else if ((showFlags & InputMethodManager.SHOW_IMPLICIT) == 0) {
+ mRequestedShowExplicitly = true;
+ }
+ return true;
+ }
+
+ /**
+ * Called when {@link InputMethodManagerService} is processing the hide IME request.
+ * @param statsToken The token for tracking this hide request
+ * @param hideFlags The additional operation flags to indicate whether this hide request mode is
+ * implicit or explicit.
+ * @return {@code true} when the computer has proceed this hide request operations.
+ */
+ boolean canHideIme(@NonNull ImeTracker.Token statsToken, int hideFlags) {
+ if ((hideFlags & InputMethodManager.HIDE_IMPLICIT_ONLY) != 0
+ && (mRequestedShowExplicitly || mShowForced)) {
+ if (DEBUG) Slog.v(TAG, "Not hiding: explicit show not cancelled by non-explicit hide");
+ ImeTracker.get().onFailed(statsToken, ImeTracker.PHASE_SERVER_HIDE_IMPLICIT);
+ return false;
+ }
+ if (mShowForced && (hideFlags & InputMethodManager.HIDE_NOT_ALWAYS) != 0) {
+ if (DEBUG) Slog.v(TAG, "Not hiding: forced show not cancelled by not-always hide");
+ ImeTracker.get().onFailed(statsToken, ImeTracker.PHASE_SERVER_HIDE_NOT_ALWAYS);
+ return false;
+ }
+ ImeTracker.get().onProgress(statsToken, ImeTracker.PHASE_SERVER_HIDE_NOT_ALWAYS);
+ return true;
+ }
+
+ int getImeShowFlags() {
+ int flags = 0;
+ if (mShowForced) {
+ flags |= InputMethod.SHOW_FORCED | InputMethod.SHOW_EXPLICIT;
+ } else if (mRequestedShowExplicitly) {
+ flags |= InputMethod.SHOW_EXPLICIT;
+ } else {
+ flags |= InputMethodManager.SHOW_IMPLICIT;
+ }
+ return flags;
+ }
+
+ void clearImeShowFlags() {
+ mRequestedShowExplicitly = false;
+ mShowForced = false;
+ }
+
+ int computeImeDisplayId(@NonNull ImeTargetWindowState state, int displayId) {
+ final int displayToShowIme = computeImeDisplayIdForTarget(displayId, mImeDisplayValidator);
+ state.setImeDisplayId(displayToShowIme);
+ final boolean imeHiddenByPolicy = displayToShowIme == INVALID_DISPLAY;
+ mPolicy.setImeHiddenByDisplayPolicy(imeHiddenByPolicy);
+ return displayToShowIme;
+ }
+
+ /**
+ * Request to show/hide IME from the given window.
+ *
+ * @param windowToken The window which requests to show/hide IME.
+ * @param showIme {@code true} means to show IME, {@code false} otherwise.
+ * Note that in the computer will take this option to compute the
+ * visibility state, it could be {@link #STATE_SHOW_IME} or
+ * {@link #STATE_HIDE_IME}.
+ */
+ void requestImeVisibility(IBinder windowToken, boolean showIme) {
+ final ImeTargetWindowState state = getOrCreateWindowState(windowToken);
+ state.setRequestedImeVisible(showIme);
+ setWindowState(windowToken, state);
+ }
+
+ ImeTargetWindowState getOrCreateWindowState(IBinder windowToken) {
+ ImeTargetWindowState state = mRequestWindowStateMap.get(windowToken);
+ if (state == null) {
+ state = new ImeTargetWindowState(SOFT_INPUT_STATE_UNSPECIFIED, false, false);
+ }
+ return state;
+ }
+
+ ImeTargetWindowState getWindowStateOrNull(IBinder windowToken) {
+ ImeTargetWindowState state = mRequestWindowStateMap.get(windowToken);
+ return state;
+ }
+
+ void setRequestImeTokenToWindow(IBinder windowToken, IBinder token) {
+ ImeTargetWindowState state = getWindowStateOrNull(windowToken);
+ if (state != null) {
+ state.setRequestImeToken(token);
+ setWindowState(windowToken, state);
+ }
+ }
+
+ void setWindowState(IBinder windowToken, ImeTargetWindowState newState) {
+ if (DEBUG) Slog.d(TAG, "setWindowState, windowToken=" + windowToken
+ + ", state=" + newState);
+ mRequestWindowStateMap.put(windowToken, newState);
+ }
+
+ IBinder getWindowTokenFrom(IBinder requestImeToken) {
+ for (IBinder windowToken : mRequestWindowStateMap.keySet()) {
+ final ImeTargetWindowState state = mRequestWindowStateMap.get(windowToken);
+ if (state.getRequestImeToken() == requestImeToken) {
+ return windowToken;
+ }
+ }
+ // Fallback to the focused window for some edge cases (e.g. relaunching the activity)
+ return mService.mCurFocusedWindow;
+ }
+
+ IBinder getWindowTokenFrom(ImeTargetWindowState windowState) {
+ for (IBinder windowToken : mRequestWindowStateMap.keySet()) {
+ final ImeTargetWindowState state = mRequestWindowStateMap.get(windowToken);
+ if (state == windowState) {
+ return windowToken;
+ }
+ }
+ return null;
+ }
+
+ boolean shouldRestoreImeVisibility(@NonNull ImeTargetWindowState state) {
+ final int softInputMode = state.getSoftInputModeState();
+ switch (softInputMode & WindowManager.LayoutParams.SOFT_INPUT_MASK_STATE) {
+ case WindowManager.LayoutParams.SOFT_INPUT_STATE_ALWAYS_HIDDEN:
+ return false;
+ case WindowManager.LayoutParams.SOFT_INPUT_STATE_HIDDEN:
+ if ((softInputMode & SOFT_INPUT_IS_FORWARD_NAVIGATION) != 0) {
+ return false;
+ }
+ }
+ return mWindowManagerInternal.shouldRestoreImeVisibility(getWindowTokenFrom(state));
+ }
+
+ void dumpDebug(ProtoOutputStream proto, long fieldId) {
+ proto.write(SHOW_EXPLICITLY_REQUESTED, mRequestedShowExplicitly);
+ proto.write(SHOW_FORCED, mShowForced);
+ proto.write(ACCESSIBILITY_REQUESTING_NO_SOFT_KEYBOARD,
+ mPolicy.isA11yRequestNoSoftKeyboard());
+ }
+
+ void dump(PrintWriter pw) {
+ final Printer p = new PrintWriterPrinter(pw);
+ p.println(" mRequestedShowExplicitly=" + mRequestedShowExplicitly
+ + " mShowForced=" + mShowForced);
+ p.println(" mImeHiddenByDisplayPolicy=" + mPolicy.isImeHiddenByDisplayPolicy());
+ }
+
+ /**
+ * A settings class to manage all IME related visibility policies or settings.
+ *
+ * This is used for the visibility computer to manage and tell
+ * {@link InputMethodManagerService} if the requested IME visibility is valid from
+ * application call or the focus window.
+ */
+ static class ImeVisibilityPolicy {
+ /**
+ * {@code true} if the Ime policy has been set to
+ * {@link WindowManager#DISPLAY_IME_POLICY_HIDE}.
+ *
+ * This prevents the IME from showing when it otherwise may have shown.
+ */
+ private boolean mImeHiddenByDisplayPolicy;
+
+ /**
+ * Set when the accessibility service requests to hide IME by
+ * {@link AccessibilityService.SoftKeyboardController#setShowMode}
+ */
+ private boolean mA11yRequestingNoSoftKeyboard;
+
+ void setImeHiddenByDisplayPolicy(boolean hideIme) {
+ mImeHiddenByDisplayPolicy = hideIme;
+ }
+
+ boolean isImeHiddenByDisplayPolicy() {
+ return mImeHiddenByDisplayPolicy;
+ }
+
+ void setA11yRequestNoSoftKeyboard(int keyboardShowMode) {
+ mA11yRequestingNoSoftKeyboard =
+ (keyboardShowMode & AccessibilityService.SHOW_MODE_MASK) == SHOW_MODE_HIDDEN;
+ }
+
+ boolean isA11yRequestNoSoftKeyboard() {
+ return mA11yRequestingNoSoftKeyboard;
+ }
+ }
+
+ ImeVisibilityPolicy getImePolicy() {
+ return mPolicy;
+ }
+
+ /**
+ * A class that represents the current state of the IME target window.
+ */
+ static class ImeTargetWindowState {
+ ImeTargetWindowState(@SoftInputModeFlags int softInputModeState, boolean imeFocusChanged,
+ boolean hasFocusedEditor) {
+ mSoftInputModeState = softInputModeState;
+ mImeFocusChanged = imeFocusChanged;
+ mHasFocusedEditor = hasFocusedEditor;
+ }
+
+ /**
+ * Visibility state for this window. By default no state has been specified.
+ */
+ private final @SoftInputModeFlags int mSoftInputModeState;
+
+ /**
+ * {@code true} means the IME focus changed from the previous window, {@code false}
+ * otherwise.
+ */
+ private final boolean mImeFocusChanged;
+
+ /**
+ * {@code true} when the window has focused an editor, {@code false} otherwise.
+ */
+ private final boolean mHasFocusedEditor;
+
+ /**
+ * Set if the client has asked for the input method to be shown.
+ */
+ private boolean mRequestedImeVisible;
+
+ /**
+ * A identifier for knowing the requester of {@link InputMethodManager#showSoftInput} or
+ * {@link InputMethodManager#hideSoftInputFromWindow}.
+ */
+ private IBinder mRequestImeToken;
+
+ /**
+ * The IME target display id for which the latest startInput was called.
+ */
+ private int mImeDisplayId = DEFAULT_DISPLAY;
+
+ boolean hasImeFocusChanged() {
+ return mImeFocusChanged;
+ }
+
+ boolean hasEdiorFocused() {
+ return mHasFocusedEditor;
+ }
+
+ int getSoftInputModeState() {
+ return mSoftInputModeState;
+ }
+
+ private void setImeDisplayId(int imeDisplayId) {
+ mImeDisplayId = imeDisplayId;
+ }
+
+ int getImeDisplayId() {
+ return mImeDisplayId;
+ }
+
+ private void setRequestedImeVisible(boolean requestedImeVisible) {
+ mRequestedImeVisible = requestedImeVisible;
+ }
+
+ boolean isRequestedImeVisible() {
+ return mRequestedImeVisible;
+ }
+
+ void setRequestImeToken(IBinder token) {
+ mRequestImeToken = token;
+ }
+
+ IBinder getRequestImeToken() {
+ return mRequestImeToken;
+ }
+
+ @Override
+ public String toString() {
+ return "ImeTargetWindowState{ imeToken " + mRequestImeToken
+ + " imeFocusChanged " + mImeFocusChanged
+ + " hasEditorFocused " + mHasFocusedEditor
+ + " requestedImeVisible " + mRequestedImeVisible
+ + " imeDisplayId " + mImeDisplayId
+ + " softInputModeState " + softInputModeToString(mSoftInputModeState)
+ + "}";
+ }
+ }
+}
diff --git a/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java b/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java
index 5b9a663..2dbbb10 100644
--- a/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java
+++ b/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java
@@ -20,7 +20,6 @@
import static android.os.IServiceManager.DUMP_FLAG_PRIORITY_NORMAL;
import static android.os.IServiceManager.DUMP_FLAG_PROTO;
import static android.os.Trace.TRACE_TAG_WINDOW_MANAGER;
-import static android.server.inputmethod.InputMethodManagerServiceProto.ACCESSIBILITY_REQUESTING_NO_SOFT_KEYBOARD;
import static android.server.inputmethod.InputMethodManagerServiceProto.BACK_DISPOSITION;
import static android.server.inputmethod.InputMethodManagerServiceProto.BOUND_TO_METHOD;
import static android.server.inputmethod.InputMethodManagerServiceProto.CUR_ATTRIBUTE;
@@ -39,8 +38,6 @@
import static android.server.inputmethod.InputMethodManagerServiceProto.IS_INTERACTIVE;
import static android.server.inputmethod.InputMethodManagerServiceProto.LAST_IME_TARGET_WINDOW_NAME;
import static android.server.inputmethod.InputMethodManagerServiceProto.LAST_SWITCH_USER_ID;
-import static android.server.inputmethod.InputMethodManagerServiceProto.SHOW_EXPLICITLY_REQUESTED;
-import static android.server.inputmethod.InputMethodManagerServiceProto.SHOW_FORCED;
import static android.server.inputmethod.InputMethodManagerServiceProto.SHOW_IME_WITH_HARD_KEYBOARD;
import static android.server.inputmethod.InputMethodManagerServiceProto.SHOW_REQUESTED;
import static android.server.inputmethod.InputMethodManagerServiceProto.SYSTEM_READY;
@@ -48,17 +45,14 @@
import static android.view.Display.INVALID_DISPLAY;
import static android.view.WindowManager.DISPLAY_IME_POLICY_HIDE;
import static android.view.WindowManager.DISPLAY_IME_POLICY_LOCAL;
-import static android.view.inputmethod.ImeTracker.DEBUG_IME_VISIBILITY;
-import static com.android.server.EventLogTags.IMF_HIDE_IME;
-import static com.android.server.EventLogTags.IMF_SHOW_IME;
+import static com.android.server.inputmethod.ImeVisibilityStateComputer.ImeTargetWindowState;
import static com.android.server.inputmethod.InputMethodBindingController.TIME_TO_RECONNECT;
import static com.android.server.inputmethod.InputMethodUtils.isSoftInputModeStateVisibleAllowed;
import static java.lang.annotation.RetentionPolicy.SOURCE;
import android.Manifest;
-import android.accessibilityservice.AccessibilityService;
import android.annotation.AnyThread;
import android.annotation.BinderThread;
import android.annotation.DrawableRes;
@@ -126,7 +120,6 @@
import android.view.InputChannel;
import android.view.InputDevice;
import android.view.MotionEvent;
-import android.view.View;
import android.view.WindowManager;
import android.view.WindowManager.DisplayImePolicy;
import android.view.WindowManager.LayoutParams;
@@ -299,6 +292,12 @@
@NonNull private final InputMethodBindingController mBindingController;
@NonNull private final AutofillSuggestionsController mAutofillController;
+ @GuardedBy("ImfLock.class")
+ @NonNull private final ImeVisibilityStateComputer mVisibilityStateComputer;
+
+ @GuardedBy("ImfLock.class")
+ @NonNull private final DefaultImeVisibilityApplier mVisibilityApplier;
+
/**
* Cache the result of {@code LocalServices.getService(AudioManagerInternal.class)}.
*
@@ -530,13 +529,6 @@
}
/**
- * {@code true} if the Ime policy has been set to {@link WindowManager#DISPLAY_IME_POLICY_HIDE}.
- *
- * This prevents the IME from showing when it otherwise may have shown.
- */
- boolean mImeHiddenByDisplayPolicy;
-
- /**
* The client that is currently bound to an input method.
*/
private ClientState mCurClient;
@@ -638,16 +630,6 @@
private boolean mShowRequested;
/**
- * Set if we were explicitly told to show the input method.
- */
- boolean mShowExplicitlyRequested;
-
- /**
- * Set if we were forced to be shown.
- */
- boolean mShowForced;
-
- /**
* Set if we last told the input method to show itself.
*/
private boolean mInputShown;
@@ -709,8 +691,6 @@
*/
private static final int FALLBACK_DISPLAY_ID = DEFAULT_DISPLAY;
- final ImeDisplayValidator mImeDisplayValidator;
-
/**
* If non-null, this is the input method service we are currently connected
* to.
@@ -786,7 +766,6 @@
int mImeWindowVis;
private LocaleList mLastSystemLocales;
- private boolean mAccessibilityRequestingNoSoftKeyboard;
private final MyPackageMonitor mMyPackageMonitor = new MyPackageMonitor();
private final String mSlotIme;
@@ -974,22 +953,6 @@
}
/**
- * Map of generated token to windowToken that is requesting
- * {@link InputMethodManager#showSoftInput(View, int)}.
- * This map tracks origin of showSoftInput requests.
- */
- @GuardedBy("ImfLock.class")
- private final WeakHashMap<IBinder, IBinder> mShowRequestWindowMap = new WeakHashMap<>();
-
- /**
- * Map of generated token to windowToken that is requesting
- * {@link InputMethodManager#hideSoftInputFromWindow(IBinder, int)}.
- * This map tracks origin of hideSoftInput requests.
- */
- @GuardedBy("ImfLock.class")
- private final WeakHashMap<IBinder, IBinder> mHideRequestWindowMap = new WeakHashMap<>();
-
- /**
* A ring buffer to store the history of {@link StartInputInfo}.
*/
private static final class StartInputHistory {
@@ -1207,11 +1170,10 @@
} else if (accessibilityRequestingNoImeUri.equals(uri)) {
final int accessibilitySoftKeyboardSetting = Settings.Secure.getIntForUser(
mContext.getContentResolver(),
- Settings.Secure.ACCESSIBILITY_SOFT_KEYBOARD_MODE, 0 /* def */, mUserId);
- mAccessibilityRequestingNoSoftKeyboard =
- (accessibilitySoftKeyboardSetting & AccessibilityService.SHOW_MODE_MASK)
- == AccessibilityService.SHOW_MODE_HIDDEN;
- if (mAccessibilityRequestingNoSoftKeyboard) {
+ Settings.Secure.ACCESSIBILITY_SOFT_KEYBOARD_MODE, 0, mUserId);
+ mVisibilityStateComputer.getImePolicy().setA11yRequestNoSoftKeyboard(
+ accessibilitySoftKeyboardSetting);
+ if (mVisibilityStateComputer.getImePolicy().isA11yRequestNoSoftKeyboard()) {
final boolean showRequested = mShowRequested;
hideCurrentInputLocked(mCurFocusedWindow, null /* statsToken */,
0 /* flags */, null /* resultReceiver */,
@@ -1722,7 +1684,6 @@
mInputManagerInternal = LocalServices.getService(InputManagerInternal.class);
mImePlatformCompatUtils = new ImePlatformCompatUtils();
mInputMethodDeviceConfigs = new InputMethodDeviceConfigs();
- mImeDisplayValidator = mWindowManagerInternal::getDisplayImePolicy;
mDisplayManagerInternal = LocalServices.getService(DisplayManagerInternal.class);
mUserManagerInternal = LocalServices.getService(UserManagerInternal.class);
@@ -1747,6 +1708,10 @@
? bindingControllerForTesting
: new InputMethodBindingController(this);
mAutofillController = new AutofillSuggestionsController(this);
+
+ mVisibilityStateComputer = new ImeVisibilityStateComputer(this);
+ mVisibilityApplier = new DefaultImeVisibilityApplier(this);
+
mPreventImeStartupUnlessTextEditor = mRes.getBoolean(
com.android.internal.R.bool.config_preventImeStartupUnlessTextEditor);
mNonPreemptibleInputMethods = mRes.getStringArray(
@@ -2340,29 +2305,6 @@
}
@GuardedBy("ImfLock.class")
- private int getImeShowFlagsLocked() {
- int flags = 0;
- if (mShowForced) {
- flags |= InputMethod.SHOW_FORCED
- | InputMethod.SHOW_EXPLICIT;
- } else if (mShowExplicitlyRequested) {
- flags |= InputMethod.SHOW_EXPLICIT;
- }
- return flags;
- }
-
- @GuardedBy("ImfLock.class")
- private int getAppShowFlagsLocked() {
- int flags = 0;
- if (mShowForced) {
- flags |= InputMethodManager.SHOW_FORCED;
- } else if (!mShowExplicitlyRequested) {
- flags |= InputMethodManager.SHOW_IMPLICIT;
- }
- return flags;
- }
-
- @GuardedBy("ImfLock.class")
@NonNull
InputBindResult attachNewInputLocked(@StartInputReason int startInputReason, boolean initial) {
if (!mBoundToMethod) {
@@ -2403,7 +2345,8 @@
// Re-use current statsToken, if it exists.
final ImeTracker.Token statsToken = mCurStatsToken;
mCurStatsToken = null;
- showCurrentInputLocked(mCurFocusedWindow, statsToken, getAppShowFlagsLocked(),
+ showCurrentInputLocked(mCurFocusedWindow, statsToken,
+ mVisibilityStateComputer.getImeShowFlags(),
null /* resultReceiver */, SoftInputShowHideReason.ATTACH_NEW_INPUT);
}
@@ -2518,17 +2461,20 @@
// Compute the final shown display ID with validated cs.selfReportedDisplayId for this
// session & other conditions.
- mDisplayIdToShowIme = computeImeDisplayIdForTarget(cs.mSelfReportedDisplayId,
- mImeDisplayValidator);
+ ImeTargetWindowState winState = mVisibilityStateComputer.getWindowStateOrNull(
+ mCurFocusedWindow);
+ if (winState == null) {
+ return InputBindResult.NOT_IME_TARGET_WINDOW;
+ }
+ final int csDisplayId = cs.mSelfReportedDisplayId;
+ mDisplayIdToShowIme = mVisibilityStateComputer.computeImeDisplayId(winState, csDisplayId);
- if (mDisplayIdToShowIme == INVALID_DISPLAY) {
- mImeHiddenByDisplayPolicy = true;
+ if (mVisibilityStateComputer.getImePolicy().isImeHiddenByDisplayPolicy()) {
hideCurrentInputLocked(mCurFocusedWindow, null /* statsToken */, 0 /* flags */,
null /* resultReceiver */,
SoftInputShowHideReason.HIDE_DISPLAY_IME_POLICY_HIDE);
return InputBindResult.NO_IME;
}
- mImeHiddenByDisplayPolicy = false;
if (mCurClient != cs) {
prepareClientSwitchLocked(cs);
@@ -3385,6 +3331,11 @@
}
}
+ @GuardedBy("ImfLock.class")
+ void setRequestImeTokenToWindow(IBinder windowToken, IBinder token) {
+ mVisibilityStateComputer.setRequestImeTokenToWindow(windowToken, token);
+ }
+
@BinderThread
@Override
public void reportPerceptibleAsync(IBinder windowToken, boolean perceptible) {
@@ -3419,18 +3370,11 @@
ImeTracker.ORIGIN_SERVER_START_INPUT, reason);
}
+ // TODO(b/246309664): make mShowRequested as per-window state.
mShowRequested = true;
- if (mAccessibilityRequestingNoSoftKeyboard || mImeHiddenByDisplayPolicy) {
- ImeTracker.get().onFailed(statsToken, ImeTracker.PHASE_SERVER_ACCESSIBILITY);
- return false;
- }
- ImeTracker.get().onProgress(statsToken, ImeTracker.PHASE_SERVER_ACCESSIBILITY);
- if ((flags & InputMethodManager.SHOW_FORCED) != 0) {
- mShowExplicitlyRequested = true;
- mShowForced = true;
- } else if ((flags & InputMethodManager.SHOW_IMPLICIT) == 0) {
- mShowExplicitlyRequested = true;
+ if (!mVisibilityStateComputer.onImeShowFlags(statsToken, flags)) {
+ return false;
}
if (!mSystemReady) {
@@ -3439,39 +3383,25 @@
}
ImeTracker.get().onProgress(statsToken, ImeTracker.PHASE_SERVER_SYSTEM_READY);
+ mVisibilityStateComputer.requestImeVisibility(windowToken, true);
+
+ // Ensure binding the connection when IME is going to show.
mBindingController.setCurrentMethodVisible();
final IInputMethodInvoker curMethod = getCurMethodLocked();
+ ImeTracker.get().onCancelled(mCurStatsToken, ImeTracker.PHASE_SERVER_WAIT_IME);
if (curMethod != null) {
- // create a placeholder token for IMS so that IMS cannot inject windows into client app.
- Binder showInputToken = new Binder();
- mShowRequestWindowMap.put(showInputToken, windowToken);
- ImeTracker.get().onCancelled(mCurStatsToken, ImeTracker.PHASE_SERVER_WAIT_IME);
ImeTracker.get().onProgress(statsToken, ImeTracker.PHASE_SERVER_HAS_IME);
mCurStatsToken = null;
- final int showFlags = getImeShowFlagsLocked();
- if (DEBUG) {
- Slog.v(TAG, "Calling " + curMethod + ".showSoftInput(" + showInputToken
- + ", " + showFlags + ", " + resultReceiver + ") for reason: "
- + InputMethodDebug.softInputDisplayReasonToString(reason));
- }
if (lastClickToolType != MotionEvent.TOOL_TYPE_UNKNOWN) {
curMethod.updateEditorToolType(lastClickToolType);
}
- // TODO(b/192412909): Check if we can always call onShowHideSoftInputRequested() or not.
- if (curMethod.showSoftInput(showInputToken, statsToken, showFlags, resultReceiver)) {
- if (DEBUG_IME_VISIBILITY) {
- EventLog.writeEvent(IMF_SHOW_IME, statsToken.getTag(),
- Objects.toString(mCurFocusedWindow),
- InputMethodDebug.softInputDisplayReasonToString(reason),
- InputMethodDebug.softInputModeToString(mCurFocusedWindowSoftInputMode));
- }
- onShowHideSoftInputRequested(true /* show */, windowToken, reason, statsToken);
- }
+ mVisibilityApplier.performShowIme(windowToken, statsToken,
+ mVisibilityStateComputer.getImeShowFlags(), resultReceiver, reason);
+ // TODO(b/246309664): make mInputShown tracked by the Ime visibility computer.
mInputShown = true;
return true;
} else {
- ImeTracker.get().onCancelled(mCurStatsToken, ImeTracker.PHASE_SERVER_WAIT_IME);
ImeTracker.get().onProgress(statsToken, ImeTracker.PHASE_SERVER_WAIT_IME);
mCurStatsToken = statsToken;
}
@@ -3527,20 +3457,9 @@
ImeTracker.ORIGIN_SERVER_HIDE_INPUT, reason);
}
- if ((flags & InputMethodManager.HIDE_IMPLICIT_ONLY) != 0
- && (mShowExplicitlyRequested || mShowForced)) {
- if (DEBUG) Slog.v(TAG, "Not hiding: explicit show not cancelled by non-explicit hide");
- ImeTracker.get().onFailed(statsToken, ImeTracker.PHASE_SERVER_HIDE_IMPLICIT);
+ if (!mVisibilityStateComputer.canHideIme(statsToken, flags)) {
return false;
}
- ImeTracker.get().onProgress(statsToken, ImeTracker.PHASE_SERVER_HIDE_IMPLICIT);
-
- if (mShowForced && (flags & InputMethodManager.HIDE_NOT_ALWAYS) != 0) {
- if (DEBUG) Slog.v(TAG, "Not hiding: forced show not cancelled by not-always hide");
- ImeTracker.get().onFailed(statsToken, ImeTracker.PHASE_SERVER_HIDE_NOT_ALWAYS);
- return false;
- }
- ImeTracker.get().onProgress(statsToken, ImeTracker.PHASE_SERVER_HIDE_NOT_ALWAYS);
// There is a chance that IMM#hideSoftInput() is called in a transient state where
// IMMS#InputShown is already updated to be true whereas IMMS#mImeWindowVis is still waiting
@@ -3549,49 +3468,30 @@
// application process as a valid request, and have even promised such a behavior with CTS
// since Android Eclair. That's why we need to accept IMM#hideSoftInput() even when only
// IMMS#InputShown indicates that the software keyboard is shown.
- // TODO: Clean up, IMMS#mInputShown, IMMS#mImeWindowVis and mShowRequested.
+ // TODO(b/246309664): Clean up, IMMS#mInputShown, IMMS#mImeWindowVis and mShowRequested.
IInputMethodInvoker curMethod = getCurMethodLocked();
final boolean shouldHideSoftInput = (curMethod != null)
&& (mInputShown || (mImeWindowVis & InputMethodService.IME_ACTIVE) != 0);
- boolean res;
+
+ mVisibilityStateComputer.requestImeVisibility(windowToken, false);
if (shouldHideSoftInput) {
- final Binder hideInputToken = new Binder();
- mHideRequestWindowMap.put(hideInputToken, windowToken);
// The IME will report its visible state again after the following message finally
// delivered to the IME process as an IPC. Hence the inconsistency between
// IMMS#mInputShown and IMMS#mImeWindowVis should be resolved spontaneously in
// the final state.
ImeTracker.get().onProgress(statsToken, ImeTracker.PHASE_SERVER_SHOULD_HIDE);
- if (DEBUG) {
- Slog.v(TAG, "Calling " + curMethod + ".hideSoftInput(0, " + hideInputToken
- + ", " + resultReceiver + ") for reason: "
- + InputMethodDebug.softInputDisplayReasonToString(reason));
- }
- // TODO(b/192412909): Check if we can always call onShowHideSoftInputRequested() or not.
- if (curMethod.hideSoftInput(hideInputToken, statsToken, 0 /* flags */,
- resultReceiver)) {
- if (DEBUG_IME_VISIBILITY) {
- EventLog.writeEvent(IMF_HIDE_IME, statsToken.getTag(),
- Objects.toString(mCurFocusedWindow),
- InputMethodDebug.softInputDisplayReasonToString(reason),
- InputMethodDebug.softInputModeToString(mCurFocusedWindowSoftInputMode));
- }
- onShowHideSoftInputRequested(false /* show */, windowToken, reason, statsToken);
- }
- res = true;
+ mVisibilityApplier.performHideIme(windowToken, statsToken, resultReceiver, reason);
} else {
ImeTracker.get().onCancelled(statsToken, ImeTracker.PHASE_SERVER_SHOULD_HIDE);
- res = false;
}
mBindingController.setCurrentMethodNotVisible();
+ mVisibilityStateComputer.clearImeShowFlags();
mInputShown = false;
mShowRequested = false;
- mShowExplicitlyRequested = false;
- mShowForced = false;
// Cancel existing statsToken for show IME as we got a hide request.
ImeTracker.get().onCancelled(mCurStatsToken, ImeTracker.PHASE_SERVER_WAIT_IME);
mCurStatsToken = null;
- return res;
+ return shouldHideSoftInput;
}
private boolean isImeClientFocused(IBinder windowToken, ClientState cs) {
@@ -3738,8 +3638,9 @@
// In case mShowForced flag affects the next client to keep IME visible, when the current
// client is leaving due to the next focused client, we clear mShowForced flag when the
// next client's targetSdkVersion is T or higher.
- if (mCurFocusedWindow != windowToken && mShowForced && shouldClearFlag) {
- mShowForced = false;
+ final boolean showForced = mVisibilityStateComputer.mShowForced;
+ if (mCurFocusedWindow != windowToken && showForced && shouldClearFlag) {
+ mVisibilityStateComputer.mShowForced = false;
}
// cross-profile access is always allowed here to allow profile-switching.
@@ -3763,6 +3664,12 @@
final boolean startInputByWinGainedFocus =
(startInputFlags & StartInputFlags.WINDOW_GAINED_FOCUS) != 0;
+ // Init the focused window state (e.g. whether the editor has focused or IME focus has
+ // changed from another window).
+ final ImeTargetWindowState windowState = new ImeTargetWindowState(
+ softInputMode, !sameWindowFocused, isTextEditor);
+ mVisibilityStateComputer.setWindowState(windowToken, windowState);
+
if (sameWindowFocused && isTextEditor) {
if (DEBUG) {
Slog.w(TAG, "Window already focused, ignoring focus gain of: " + client
@@ -3812,7 +3719,7 @@
// Because the app might leverage these flags to hide soft-keyboard with showing their own
// UI for input.
if (isTextEditor && editorInfo != null
- && shouldRestoreImeVisibility(windowToken, softInputMode)) {
+ && mVisibilityStateComputer.shouldRestoreImeVisibility(windowState)) {
if (DEBUG) Slog.v(TAG, "Will show input to restore visibility");
res = startInputUncheckedLocked(cs, inputContext, remoteAccessibilityInputConnection,
editorInfo, startInputFlags, startInputReason, unverifiedTargetSdkVersion,
@@ -4001,19 +3908,6 @@
return true;
}
- private boolean shouldRestoreImeVisibility(IBinder windowToken,
- @SoftInputModeFlags int softInputMode) {
- switch (softInputMode & LayoutParams.SOFT_INPUT_MASK_STATE) {
- case LayoutParams.SOFT_INPUT_STATE_ALWAYS_HIDDEN:
- return false;
- case LayoutParams.SOFT_INPUT_STATE_HIDDEN:
- if ((softInputMode & LayoutParams.SOFT_INPUT_IS_FORWARD_NAVIGATION) != 0) {
- return false;
- }
- }
- return mWindowManagerInternal.shouldRestoreImeVisibility(windowToken);
- }
-
@GuardedBy("ImfLock.class")
private boolean canShowInputMethodPickerLocked(IInputMethodClient client) {
final int uid = Binder.getCallingUid();
@@ -4746,8 +4640,7 @@
}
proto.write(CUR_ID, getCurIdLocked());
proto.write(SHOW_REQUESTED, mShowRequested);
- proto.write(SHOW_EXPLICITLY_REQUESTED, mShowExplicitlyRequested);
- proto.write(SHOW_FORCED, mShowForced);
+ mVisibilityStateComputer.dumpDebug(proto, fieldId);
proto.write(INPUT_SHOWN, mInputShown);
proto.write(IN_FULLSCREEN_MODE, mInFullscreenMode);
proto.write(CUR_TOKEN, Objects.toString(getCurTokenLocked()));
@@ -4760,8 +4653,6 @@
proto.write(BACK_DISPOSITION, mBackDisposition);
proto.write(IME_WINDOW_VISIBILITY, mImeWindowVis);
proto.write(SHOW_IME_WITH_HARD_KEYBOARD, mMenuController.getShowImeWithHardKeyboard());
- proto.write(ACCESSIBILITY_REQUESTING_NO_SOFT_KEYBOARD,
- mAccessibilityRequestingNoSoftKeyboard);
proto.end(token);
}
}
@@ -4795,25 +4686,10 @@
ImeTracker.get().onFailed(statsToken, ImeTracker.PHASE_SERVER_APPLY_IME_VISIBILITY);
return;
}
- if (!setVisible) {
- if (mCurClient != null) {
- ImeTracker.get().onProgress(statsToken,
- ImeTracker.PHASE_SERVER_APPLY_IME_VISIBILITY);
-
- mWindowManagerInternal.hideIme(
- mHideRequestWindowMap.get(windowToken),
- mCurClient.mSelfReportedDisplayId, statsToken);
- } else {
- ImeTracker.get().onFailed(statsToken,
- ImeTracker.PHASE_SERVER_APPLY_IME_VISIBILITY);
- }
- } else {
- ImeTracker.get().onProgress(statsToken,
- ImeTracker.PHASE_SERVER_APPLY_IME_VISIBILITY);
- // Send to window manager to show IME after IME layout finishes.
- mWindowManagerInternal.showImePostLayout(mShowRequestWindowMap.get(windowToken),
- statsToken);
- }
+ final IBinder requestToken = mVisibilityStateComputer.getWindowTokenFrom(windowToken);
+ mVisibilityApplier.applyImeVisibility(requestToken, statsToken,
+ setVisible ? ImeVisibilityStateComputer.STATE_SHOW_IME
+ : ImeVisibilityStateComputer.STATE_HIDE_IME);
}
Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER);
}
@@ -4857,7 +4733,7 @@
/** Called right after {@link com.android.internal.inputmethod.IInputMethod#showSoftInput}. */
@GuardedBy("ImfLock.class")
- private void onShowHideSoftInputRequested(boolean show, IBinder requestToken,
+ void onShowHideSoftInputRequested(boolean show, IBinder requestToken,
@SoftInputShowHideReason int reason, @Nullable ImeTracker.Token statsToken) {
final WindowManagerInternal.ImeTargetInfo info =
mWindowManagerInternal.onToggleImeRequested(
@@ -5988,14 +5864,11 @@
method = getCurMethodLocked();
p.println(" mCurMethod=" + getCurMethodLocked());
p.println(" mEnabledSession=" + mEnabledSession);
- p.println(" mShowRequested=" + mShowRequested
- + " mShowExplicitlyRequested=" + mShowExplicitlyRequested
- + " mShowForced=" + mShowForced
- + " mInputShown=" + mInputShown);
+ p.println(" mShowRequested=" + mShowRequested + " mInputShown=" + mInputShown);
+ mVisibilityStateComputer.dump(pw);
p.println(" mInFullscreenMode=" + mInFullscreenMode);
p.println(" mSystemReady=" + mSystemReady + " mInteractive=" + mIsInteractive);
p.println(" mSettingsObserver=" + mSettingsObserver);
- p.println(" mImeHiddenByDisplayPolicy=" + mImeHiddenByDisplayPolicy);
p.println(" mStylusIds=" + (mStylusIds != null
? Arrays.toString(mStylusIds.toArray()) : ""));
p.println(" mSwitchingController:");
diff --git a/services/core/java/com/android/server/locksettings/RebootEscrowManager.java b/services/core/java/com/android/server/locksettings/RebootEscrowManager.java
index 4d525da..9b42cfc 100644
--- a/services/core/java/com/android/server/locksettings/RebootEscrowManager.java
+++ b/services/core/java/com/android/server/locksettings/RebootEscrowManager.java
@@ -36,6 +36,7 @@
import android.net.ConnectivityManager;
import android.net.Network;
import android.net.NetworkCapabilities;
+import android.net.NetworkRequest;
import android.os.Handler;
import android.os.PowerManager;
import android.os.SystemClock;
@@ -103,12 +104,12 @@
/**
* Number of boots until we consider the escrow data to be stale for the purposes of metrics.
- * <p>
- * If the delta between the current boot number and the boot number stored when the mechanism
+ *
+ * <p>If the delta between the current boot number and the boot number stored when the mechanism
* was armed is under this number and the escrow mechanism fails, we report it as a failure of
* the mechanism.
- * <p>
- * If the delta over this number and escrow fails, we will not report the metric as failed
+ *
+ * <p>If the delta over this number and escrow fails, we will not report the metric as failed
* since there most likely was some other issue if the device rebooted several times before
* getting to the escrow restore code.
*/
@@ -120,8 +121,11 @@
*/
private static final int DEFAULT_LOAD_ESCROW_DATA_RETRY_COUNT = 3;
private static final int DEFAULT_LOAD_ESCROW_DATA_RETRY_INTERVAL_SECONDS = 30;
+
// 3 minutes. It's enough for the default 3 retries with 30 seconds interval
- private static final int DEFAULT_WAKE_LOCK_TIMEOUT_MILLIS = 180_000;
+ private static final int DEFAULT_LOAD_ESCROW_BASE_TIMEOUT_MILLIS = 180_000;
+ // 5 seconds. An extension of the overall RoR timeout to account for overhead.
+ private static final int DEFAULT_LOAD_ESCROW_TIMEOUT_EXTENSION_MILLIS = 5000;
@IntDef(prefix = {"ERROR_"}, value = {
ERROR_NONE,
@@ -133,6 +137,7 @@
ERROR_PROVIDER_MISMATCH,
ERROR_KEYSTORE_FAILURE,
ERROR_NO_NETWORK,
+ ERROR_TIMEOUT_EXHAUSTED,
})
@Retention(RetentionPolicy.SOURCE)
@interface RebootEscrowErrorCode {
@@ -147,6 +152,7 @@
static final int ERROR_PROVIDER_MISMATCH = 6;
static final int ERROR_KEYSTORE_FAILURE = 7;
static final int ERROR_NO_NETWORK = 8;
+ static final int ERROR_TIMEOUT_EXHAUSTED = 9;
private @RebootEscrowErrorCode int mLoadEscrowDataErrorCode = ERROR_NONE;
@@ -168,6 +174,15 @@
/** Notified when mRebootEscrowReady changes. */
private RebootEscrowListener mRebootEscrowListener;
+ /** Set when unlocking reboot escrow times out. */
+ private boolean mRebootEscrowTimedOut = false;
+
+ /**
+ * Set when {@link #loadRebootEscrowDataWithRetry} is called to ensure the function is only
+ * called once.
+ */
+ private boolean mLoadEscrowDataWithRetry = false;
+
/**
* Hold this lock when checking or generating the reboot escrow key.
*/
@@ -192,6 +207,7 @@
PowerManager.WakeLock mWakeLock;
+ private ConnectivityManager.NetworkCallback mNetworkCallback;
interface Callbacks {
boolean isUserSecure(int userId);
@@ -246,6 +262,11 @@
"server_based_ror_enabled", false);
}
+ public boolean waitForInternet() {
+ return DeviceConfig.getBoolean(
+ DeviceConfig.NAMESPACE_OTA, "wait_for_internet_ror", false);
+ }
+
public boolean isNetworkConnected() {
final ConnectivityManager connectivityManager =
mContext.getSystemService(ConnectivityManager.class);
@@ -263,6 +284,38 @@
NetworkCapabilities.NET_CAPABILITY_VALIDATED);
}
+ /**
+ * Request network with internet connectivity with timeout.
+ *
+ * @param networkCallback callback to be executed if connectivity manager exists.
+ * @return true if success
+ */
+ public boolean requestNetworkWithInternet(
+ ConnectivityManager.NetworkCallback networkCallback) {
+ final ConnectivityManager connectivityManager =
+ mContext.getSystemService(ConnectivityManager.class);
+ if (connectivityManager == null) {
+ return false;
+ }
+ NetworkRequest request =
+ new NetworkRequest.Builder()
+ .addCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET)
+ .build();
+
+ connectivityManager.requestNetwork(
+ request, networkCallback, getLoadEscrowTimeoutMillis());
+ return true;
+ }
+
+ public void stopRequestingNetwork(ConnectivityManager.NetworkCallback networkCallback) {
+ final ConnectivityManager connectivityManager =
+ mContext.getSystemService(ConnectivityManager.class);
+ if (connectivityManager == null) {
+ return;
+ }
+ connectivityManager.unregisterNetworkCallback(networkCallback);
+ }
+
public Context getContext() {
return mContext;
}
@@ -318,6 +371,16 @@
DEFAULT_LOAD_ESCROW_DATA_RETRY_INTERVAL_SECONDS);
}
+ @VisibleForTesting
+ public int getLoadEscrowTimeoutMillis() {
+ return DEFAULT_LOAD_ESCROW_BASE_TIMEOUT_MILLIS;
+ }
+
+ @VisibleForTesting
+ public int getWakeLockTimeoutMillis() {
+ return getLoadEscrowTimeoutMillis() + DEFAULT_LOAD_ESCROW_TIMEOUT_EXTENSION_MILLIS;
+ }
+
public void reportMetric(boolean success, int errorCode, int serviceType, int attemptCount,
int escrowDurationInSeconds, int vbmetaDigestStatus,
int durationSinceBootCompleteInSeconds) {
@@ -351,13 +414,37 @@
mKeyStoreManager = injector.getKeyStoreManager();
}
- private void onGetRebootEscrowKeyFailed(List<UserInfo> users, int attemptCount) {
+ /** Wrapper function to set error code serialized through handler, */
+ private void setLoadEscrowDataErrorCode(@RebootEscrowErrorCode int value, Handler handler) {
+ if (mInjector.waitForInternet()) {
+ mInjector.post(
+ handler,
+ () -> {
+ mLoadEscrowDataErrorCode = value;
+ });
+ } else {
+ mLoadEscrowDataErrorCode = value;
+ }
+ }
+
+ /** Wrapper function to compare and set error code serialized through handler. */
+ private void compareAndSetLoadEscrowDataErrorCode(
+ @RebootEscrowErrorCode int expectedValue,
+ @RebootEscrowErrorCode int newValue,
+ Handler handler) {
+ if (expectedValue == mLoadEscrowDataErrorCode) {
+ setLoadEscrowDataErrorCode(newValue, handler);
+ }
+ }
+
+ private void onGetRebootEscrowKeyFailed(
+ List<UserInfo> users, int attemptCount, Handler retryHandler) {
Slog.w(TAG, "Had reboot escrow data for users, but no key; removing escrow storage.");
for (UserInfo user : users) {
mStorage.removeRebootEscrow(user.id);
}
- onEscrowRestoreComplete(false, attemptCount);
+ onEscrowRestoreComplete(false, attemptCount, retryHandler);
}
void loadRebootEscrowDataIfAvailable(Handler retryHandler) {
@@ -380,39 +467,130 @@
mWakeLock = mInjector.getWakeLock();
if (mWakeLock != null) {
mWakeLock.setReferenceCounted(false);
- mWakeLock.acquire(DEFAULT_WAKE_LOCK_TIMEOUT_MILLIS);
+ mWakeLock.acquire(mInjector.getWakeLockTimeoutMillis());
+ }
+
+ if (mInjector.waitForInternet()) {
+ // Timeout to stop retrying same as the wake lock timeout.
+ mInjector.postDelayed(
+ retryHandler,
+ () -> {
+ mRebootEscrowTimedOut = true;
+ },
+ mInjector.getLoadEscrowTimeoutMillis());
+
+ mInjector.post(
+ retryHandler,
+ () -> loadRebootEscrowDataOnInternet(retryHandler, users, rebootEscrowUsers));
+ return;
}
mInjector.post(retryHandler, () -> loadRebootEscrowDataWithRetry(
retryHandler, 0, users, rebootEscrowUsers));
}
- void scheduleLoadRebootEscrowDataOrFail(Handler retryHandler, int attemptNumber,
- List<UserInfo> users, List<UserInfo> rebootEscrowUsers) {
+ void scheduleLoadRebootEscrowDataOrFail(
+ Handler retryHandler,
+ int attemptNumber,
+ List<UserInfo> users,
+ List<UserInfo> rebootEscrowUsers) {
Objects.requireNonNull(retryHandler);
final int retryLimit = mInjector.getLoadEscrowDataRetryLimit();
final int retryIntervalInSeconds = mInjector.getLoadEscrowDataRetryIntervalSeconds();
- if (attemptNumber < retryLimit) {
+ if (attemptNumber < retryLimit && !mRebootEscrowTimedOut) {
Slog.i(TAG, "Scheduling loadRebootEscrowData retry number: " + attemptNumber);
mInjector.postDelayed(retryHandler, () -> loadRebootEscrowDataWithRetry(
- retryHandler, attemptNumber, users, rebootEscrowUsers),
+ retryHandler, attemptNumber, users, rebootEscrowUsers),
retryIntervalInSeconds * 1000);
return;
}
+ if (mInjector.waitForInternet()) {
+ if (mRebootEscrowTimedOut) {
+ Slog.w(TAG, "Failed to load reboot escrow data within timeout");
+ compareAndSetLoadEscrowDataErrorCode(
+ ERROR_NONE, ERROR_TIMEOUT_EXHAUSTED, retryHandler);
+ } else {
+ Slog.w(
+ TAG,
+ "Failed to load reboot escrow data after " + attemptNumber + " attempts");
+ compareAndSetLoadEscrowDataErrorCode(
+ ERROR_NONE, ERROR_RETRY_COUNT_EXHAUSTED, retryHandler);
+ }
+ onGetRebootEscrowKeyFailed(users, attemptNumber, retryHandler);
+ return;
+ }
+
Slog.w(TAG, "Failed to load reboot escrow data after " + attemptNumber + " attempts");
if (mInjector.serverBasedResumeOnReboot() && !mInjector.isNetworkConnected()) {
mLoadEscrowDataErrorCode = ERROR_NO_NETWORK;
} else {
mLoadEscrowDataErrorCode = ERROR_RETRY_COUNT_EXHAUSTED;
}
- onGetRebootEscrowKeyFailed(users, attemptNumber);
+ onGetRebootEscrowKeyFailed(users, attemptNumber, retryHandler);
}
- void loadRebootEscrowDataWithRetry(Handler retryHandler, int attemptNumber,
- List<UserInfo> users, List<UserInfo> rebootEscrowUsers) {
+ void loadRebootEscrowDataOnInternet(
+ Handler retryHandler, List<UserInfo> users, List<UserInfo> rebootEscrowUsers) {
+
+ // HAL-Based RoR does not require network connectivity.
+ if (!mInjector.serverBasedResumeOnReboot()) {
+ loadRebootEscrowDataWithRetry(
+ retryHandler, /* attemptNumber = */ 0, users, rebootEscrowUsers);
+ return;
+ }
+
+ mNetworkCallback =
+ new ConnectivityManager.NetworkCallback() {
+ @Override
+ public void onAvailable(Network network) {
+ compareAndSetLoadEscrowDataErrorCode(
+ ERROR_NO_NETWORK, ERROR_NONE, retryHandler);
+
+ if (!mLoadEscrowDataWithRetry) {
+ mLoadEscrowDataWithRetry = true;
+ // Only kickoff retry mechanism on first onAvailable call.
+ loadRebootEscrowDataWithRetry(
+ retryHandler,
+ /* attemptNumber = */ 0,
+ users,
+ rebootEscrowUsers);
+ }
+ }
+
+ @Override
+ public void onUnavailable() {
+ Slog.w(TAG, "Failed to connect to network within timeout");
+ compareAndSetLoadEscrowDataErrorCode(
+ ERROR_NONE, ERROR_NO_NETWORK, retryHandler);
+ onGetRebootEscrowKeyFailed(users, /* attemptCount= */ 0, retryHandler);
+ }
+
+ @Override
+ public void onLost(Network lostNetwork) {
+ // TODO(b/231660348): If network is lost, wait for network to become
+ // available again.
+ Slog.w(TAG, "Network lost, still attempting to load escrow key.");
+ compareAndSetLoadEscrowDataErrorCode(
+ ERROR_NONE, ERROR_NO_NETWORK, retryHandler);
+ }
+ };
+
+ // Fallback to retrying without waiting for internet on failure.
+ boolean success = mInjector.requestNetworkWithInternet(mNetworkCallback);
+ if (!success) {
+ loadRebootEscrowDataWithRetry(
+ retryHandler, /* attemptNumber = */ 0, users, rebootEscrowUsers);
+ }
+ }
+
+ void loadRebootEscrowDataWithRetry(
+ Handler retryHandler,
+ int attemptNumber,
+ List<UserInfo> users,
+ List<UserInfo> rebootEscrowUsers) {
// Fetch the key from keystore to decrypt the escrow data & escrow key; this key is
// generated before reboot. Note that we will clear the escrow key even if the keystore key
// is null.
@@ -423,7 +601,7 @@
RebootEscrowKey escrowKey;
try {
- escrowKey = getAndClearRebootEscrowKey(kk);
+ escrowKey = getAndClearRebootEscrowKey(kk, retryHandler);
} catch (IOException e) {
Slog.i(TAG, "Failed to load escrow key, scheduling retry.", e);
scheduleLoadRebootEscrowDataOrFail(retryHandler, attemptNumber + 1, users,
@@ -438,12 +616,12 @@
? RebootEscrowProviderInterface.TYPE_SERVER_BASED
: RebootEscrowProviderInterface.TYPE_HAL;
if (providerType != mStorage.getInt(REBOOT_ESCROW_KEY_PROVIDER, -1, USER_SYSTEM)) {
- mLoadEscrowDataErrorCode = ERROR_PROVIDER_MISMATCH;
+ setLoadEscrowDataErrorCode(ERROR_PROVIDER_MISMATCH, retryHandler);
} else {
- mLoadEscrowDataErrorCode = ERROR_LOAD_ESCROW_KEY;
+ setLoadEscrowDataErrorCode(ERROR_LOAD_ESCROW_KEY, retryHandler);
}
}
- onGetRebootEscrowKeyFailed(users, attemptNumber + 1);
+ onGetRebootEscrowKeyFailed(users, attemptNumber + 1, retryHandler);
return;
}
@@ -454,10 +632,10 @@
allUsersUnlocked &= restoreRebootEscrowForUser(user.id, escrowKey, kk);
}
- if (!allUsersUnlocked && mLoadEscrowDataErrorCode == ERROR_NONE) {
- mLoadEscrowDataErrorCode = ERROR_UNLOCK_ALL_USERS;
+ if (!allUsersUnlocked) {
+ compareAndSetLoadEscrowDataErrorCode(ERROR_NONE, ERROR_UNLOCK_ALL_USERS, retryHandler);
}
- onEscrowRestoreComplete(allUsersUnlocked, attemptNumber + 1);
+ onEscrowRestoreComplete(allUsersUnlocked, attemptNumber + 1, retryHandler);
}
private void clearMetricsStorage() {
@@ -497,7 +675,8 @@
.REBOOT_ESCROW_RECOVERY_REPORTED__VBMETA_DIGEST_STATUS__MISMATCH;
}
- private void reportMetricOnRestoreComplete(boolean success, int attemptCount) {
+ private void reportMetricOnRestoreComplete(
+ boolean success, int attemptCount, Handler retryHandler) {
int serviceType = mInjector.serverBasedResumeOnReboot()
? FrameworkStatsLog.REBOOT_ESCROW_RECOVERY_REPORTED__TYPE__SERVER_BASED
: FrameworkStatsLog.REBOOT_ESCROW_RECOVERY_REPORTED__TYPE__HAL;
@@ -511,52 +690,69 @@
}
int vbmetaDigestStatus = getVbmetaDigestStatusOnRestoreComplete();
- if (!success && mLoadEscrowDataErrorCode == ERROR_NONE) {
- mLoadEscrowDataErrorCode = ERROR_UNKNOWN;
+ if (!success) {
+ compareAndSetLoadEscrowDataErrorCode(ERROR_NONE, ERROR_UNKNOWN, retryHandler);
}
- Slog.i(TAG, "Reporting RoR recovery metrics, success: " + success + ", service type: "
- + serviceType + ", error code: " + mLoadEscrowDataErrorCode);
+ Slog.i(
+ TAG,
+ "Reporting RoR recovery metrics, success: "
+ + success
+ + ", service type: "
+ + serviceType
+ + ", error code: "
+ + mLoadEscrowDataErrorCode);
// TODO(179105110) report the duration since boot complete.
- mInjector.reportMetric(success, mLoadEscrowDataErrorCode, serviceType, attemptCount,
- escrowDurationInSeconds, vbmetaDigestStatus, -1);
+ mInjector.reportMetric(
+ success,
+ mLoadEscrowDataErrorCode,
+ serviceType,
+ attemptCount,
+ escrowDurationInSeconds,
+ vbmetaDigestStatus,
+ -1);
- mLoadEscrowDataErrorCode = ERROR_NONE;
+ setLoadEscrowDataErrorCode(ERROR_NONE, retryHandler);
}
- private void onEscrowRestoreComplete(boolean success, int attemptCount) {
+ private void onEscrowRestoreComplete(boolean success, int attemptCount, Handler retryHandler) {
int previousBootCount = mStorage.getInt(REBOOT_ESCROW_ARMED_KEY, -1, USER_SYSTEM);
int bootCountDelta = mInjector.getBootCount() - previousBootCount;
if (success || (previousBootCount != -1 && bootCountDelta <= BOOT_COUNT_TOLERANCE)) {
- reportMetricOnRestoreComplete(success, attemptCount);
+ reportMetricOnRestoreComplete(success, attemptCount, retryHandler);
}
-
// Clear the old key in keystore. A new key will be generated by new RoR requests.
mKeyStoreManager.clearKeyStoreEncryptionKey();
// Clear the saved reboot escrow provider
mInjector.clearRebootEscrowProvider();
clearMetricsStorage();
+ if (mNetworkCallback != null) {
+ mInjector.stopRequestingNetwork(mNetworkCallback);
+ }
+
if (mWakeLock != null) {
mWakeLock.release();
}
}
- private RebootEscrowKey getAndClearRebootEscrowKey(SecretKey kk) throws IOException {
+ private RebootEscrowKey getAndClearRebootEscrowKey(SecretKey kk, Handler retryHandler)
+ throws IOException {
RebootEscrowProviderInterface rebootEscrowProvider =
mInjector.createRebootEscrowProviderIfNeeded();
if (rebootEscrowProvider == null) {
- Slog.w(TAG,
+ Slog.w(
+ TAG,
"Had reboot escrow data for users, but RebootEscrowProvider is unavailable");
- mLoadEscrowDataErrorCode = ERROR_NO_PROVIDER;
+ setLoadEscrowDataErrorCode(ERROR_NO_PROVIDER, retryHandler);
return null;
}
// Server based RoR always need the decryption key from keystore.
if (rebootEscrowProvider.getType() == RebootEscrowProviderInterface.TYPE_SERVER_BASED
&& kk == null) {
- mLoadEscrowDataErrorCode = ERROR_KEYSTORE_FAILURE;
+ setLoadEscrowDataErrorCode(ERROR_KEYSTORE_FAILURE, retryHandler);
return null;
}
@@ -870,6 +1066,9 @@
pw.print("mRebootEscrowListener=");
pw.println(mRebootEscrowListener);
+ pw.print("mLoadEscrowDataErrorCode=");
+ pw.println(mLoadEscrowDataErrorCode);
+
boolean keySet;
synchronized (mKeyGenerationLock) {
keySet = mPendingRebootEscrowKey != null;
diff --git a/services/core/java/com/android/server/media/BluetoothRouteProvider.java b/services/core/java/com/android/server/media/BluetoothRouteProvider.java
index e1a990d..c90554d 100644
--- a/services/core/java/com/android/server/media/BluetoothRouteProvider.java
+++ b/services/core/java/com/android/server/media/BluetoothRouteProvider.java
@@ -59,17 +59,9 @@
private static final String HEARING_AID_ROUTE_ID_PREFIX = "HEARING_AID_";
private static final String LE_AUDIO_ROUTE_ID_PREFIX = "LE_AUDIO_";
- @SuppressWarnings("WeakerAccess") /* synthetic access */
// Maps hardware address to BluetoothRouteInfo
- final Map<String, BluetoothRouteInfo> mBluetoothRoutes = new HashMap<>();
- @SuppressWarnings("WeakerAccess") /* synthetic access */
- final List<BluetoothRouteInfo> mActiveRoutes = new ArrayList<>();
- @SuppressWarnings("WeakerAccess") /* synthetic access */
- BluetoothA2dp mA2dpProfile;
- @SuppressWarnings("WeakerAccess") /* synthetic access */
- BluetoothHearingAid mHearingAidProfile;
- @SuppressWarnings("WeakerAccess") /* synthetic access */
- BluetoothLeAudio mLeAudioProfile;
+ private final Map<String, BluetoothRouteInfo> mBluetoothRoutes = new HashMap<>();
+ private final List<BluetoothRouteInfo> mActiveRoutes = new ArrayList<>();
// Route type -> volume map
private final SparseIntArray mVolumeMap = new SparseIntArray();
@@ -83,6 +75,10 @@
private final BroadcastReceiver mBroadcastReceiver = new BluetoothBroadcastReceiver();
private final BluetoothProfileListener mProfileListener = new BluetoothProfileListener();
+ private BluetoothA2dp mA2dpProfile;
+ private BluetoothHearingAid mHearingAidProfile;
+ private BluetoothLeAudio mLeAudioProfile;
+
/**
* Create an instance of {@link BluetoothRouteProvider}.
* It may return {@code null} if Bluetooth is not supported on this hardware platform.
@@ -109,7 +105,7 @@
buildBluetoothRoutes();
}
- public void start(UserHandle user) {
+ void start(UserHandle user) {
mBluetoothAdapter.getProfileProxy(mContext, mProfileListener, BluetoothProfile.A2DP);
mBluetoothAdapter.getProfileProxy(mContext, mProfileListener, BluetoothProfile.HEARING_AID);
mBluetoothAdapter.getProfileProxy(mContext, mProfileListener, BluetoothProfile.LE_AUDIO);
@@ -133,7 +129,7 @@
mIntentFilter, null, null);
}
- public void stop() {
+ void stop() {
mContext.unregisterReceiver(mBroadcastReceiver);
}
@@ -144,7 +140,7 @@
* @param routeId the id of the Bluetooth device. {@code null} denotes to clear the use of
* BT routes.
*/
- public void transferTo(@Nullable String routeId) {
+ void transferTo(@Nullable String routeId) {
if (routeId == null) {
clearActiveDevices();
return;
@@ -158,7 +154,7 @@
}
if (mBluetoothAdapter != null) {
- mBluetoothAdapter.setActiveDevice(btRouteInfo.btDevice, ACTIVE_DEVICE_AUDIO);
+ mBluetoothAdapter.setActiveDevice(btRouteInfo.mBtDevice, ACTIVE_DEVICE_AUDIO);
}
}
@@ -183,7 +179,7 @@
for (BluetoothDevice device : bondedDevices) {
if (device.isConnected()) {
BluetoothRouteInfo newBtRoute = createBluetoothRoute(device);
- if (newBtRoute.connectedProfiles.size() > 0) {
+ if (newBtRoute.mConnectedProfiles.size() > 0) {
mBluetoothRoutes.put(device.getAddress(), newBtRoute);
}
}
@@ -195,14 +191,14 @@
MediaRoute2Info getSelectedRoute() {
// For now, active routes can be multiple only when a pair of hearing aid devices is active.
// Let the first active device represent them.
- return (mActiveRoutes.isEmpty() ? null : mActiveRoutes.get(0).route);
+ return (mActiveRoutes.isEmpty() ? null : mActiveRoutes.get(0).mRoute);
}
@NonNull
List<MediaRoute2Info> getTransferableRoutes() {
List<MediaRoute2Info> routes = getAllBluetoothRoutes();
for (BluetoothRouteInfo btRoute : mActiveRoutes) {
- routes.remove(btRoute.route);
+ routes.remove(btRoute.mRoute);
}
return routes;
}
@@ -220,11 +216,11 @@
for (BluetoothRouteInfo btRoute : mBluetoothRoutes.values()) {
// A pair of hearing aid devices or having the same hardware address
- if (routeIds.contains(btRoute.route.getId())) {
+ if (routeIds.contains(btRoute.mRoute.getId())) {
continue;
}
- routes.add(btRoute.route);
- routeIds.add(btRoute.route.getId());
+ routes.add(btRoute.mRoute);
+ routeIds.add(btRoute.mRoute.getId());
}
return routes;
}
@@ -234,7 +230,7 @@
return null;
}
for (BluetoothRouteInfo btRouteInfo : mBluetoothRoutes.values()) {
- if (TextUtils.equals(btRouteInfo.route.getId(), routeId)) {
+ if (TextUtils.equals(btRouteInfo.mRoute.getId(), routeId)) {
return btRouteInfo;
}
}
@@ -246,7 +242,7 @@
*
* @return true if devices can be handled by the provider.
*/
- public boolean updateVolumeForDevices(int devices, int volume) {
+ boolean updateVolumeForDevices(int devices, int volume) {
int routeType;
if ((devices & (AudioSystem.DEVICE_OUT_HEARING_AID)) != 0) {
routeType = MediaRoute2Info.TYPE_HEARING_AID;
@@ -263,10 +259,10 @@
boolean shouldNotify = false;
for (BluetoothRouteInfo btRoute : mActiveRoutes) {
- if (btRoute.route.getType() != routeType) {
+ if (btRoute.mRoute.getType() != routeType) {
continue;
}
- btRoute.route = new MediaRoute2Info.Builder(btRoute.route)
+ btRoute.mRoute = new MediaRoute2Info.Builder(btRoute.mRoute)
.setVolume(volume)
.build();
shouldNotify = true;
@@ -285,7 +281,7 @@
private BluetoothRouteInfo createBluetoothRoute(BluetoothDevice device) {
BluetoothRouteInfo newBtRoute = new BluetoothRouteInfo();
- newBtRoute.btDevice = device;
+ newBtRoute.mBtDevice = device;
String routeId = device.getAddress();
String deviceName = device.getName();
@@ -293,26 +289,26 @@
deviceName = mContext.getResources().getText(R.string.unknownName).toString();
}
int type = MediaRoute2Info.TYPE_BLUETOOTH_A2DP;
- newBtRoute.connectedProfiles = new SparseBooleanArray();
+ newBtRoute.mConnectedProfiles = new SparseBooleanArray();
if (mA2dpProfile != null && mA2dpProfile.getConnectedDevices().contains(device)) {
- newBtRoute.connectedProfiles.put(BluetoothProfile.A2DP, true);
+ newBtRoute.mConnectedProfiles.put(BluetoothProfile.A2DP, true);
}
if (mHearingAidProfile != null
&& mHearingAidProfile.getConnectedDevices().contains(device)) {
- newBtRoute.connectedProfiles.put(BluetoothProfile.HEARING_AID, true);
+ newBtRoute.mConnectedProfiles.put(BluetoothProfile.HEARING_AID, true);
// Intentionally assign the same ID for a pair of devices to publish only one of them.
routeId = HEARING_AID_ROUTE_ID_PREFIX + mHearingAidProfile.getHiSyncId(device);
type = MediaRoute2Info.TYPE_HEARING_AID;
}
if (mLeAudioProfile != null
&& mLeAudioProfile.getConnectedDevices().contains(device)) {
- newBtRoute.connectedProfiles.put(BluetoothProfile.LE_AUDIO, true);
+ newBtRoute.mConnectedProfiles.put(BluetoothProfile.LE_AUDIO, true);
routeId = LE_AUDIO_ROUTE_ID_PREFIX + mLeAudioProfile.getGroupId(device);
type = MediaRoute2Info.TYPE_BLE_HEADSET;
}
// Current volume will be set when connected.
- newBtRoute.route = new MediaRoute2Info.Builder(routeId, deviceName)
+ newBtRoute.mRoute = new MediaRoute2Info.Builder(routeId, deviceName)
.addFeature(MediaRoute2Info.FEATURE_LIVE_AUDIO)
.addFeature(MediaRoute2Info.FEATURE_LOCAL_PLAYBACK)
.setConnectionState(MediaRoute2Info.CONNECTION_STATE_DISCONNECTED)
@@ -332,18 +328,18 @@
Slog.w(TAG, "setRouteConnectionState: route shouldn't be null");
return;
}
- if (btRoute.route.getConnectionState() == state) {
+ if (btRoute.mRoute.getConnectionState() == state) {
return;
}
- MediaRoute2Info.Builder builder = new MediaRoute2Info.Builder(btRoute.route)
+ MediaRoute2Info.Builder builder = new MediaRoute2Info.Builder(btRoute.mRoute)
.setConnectionState(state);
builder.setType(btRoute.getRouteType());
if (state == MediaRoute2Info.CONNECTION_STATE_CONNECTED) {
builder.setVolume(mVolumeMap.get(btRoute.getRouteType(), 0));
}
- btRoute.route = builder.build();
+ btRoute.mRoute = builder.build();
}
private void addActiveRoute(BluetoothRouteInfo btRoute) {
@@ -352,7 +348,7 @@
return;
}
if (DEBUG) {
- Log.d(TAG, "Adding active route: " + btRoute.route);
+ Log.d(TAG, "Adding active route: " + btRoute.mRoute);
}
if (mActiveRoutes.contains(btRoute)) {
Slog.w(TAG, "addActiveRoute: btRoute is already added.");
@@ -364,7 +360,7 @@
private void removeActiveRoute(BluetoothRouteInfo btRoute) {
if (DEBUG) {
- Log.d(TAG, "Removing active route: " + btRoute.route);
+ Log.d(TAG, "Removing active route: " + btRoute.mRoute);
}
if (mActiveRoutes.remove(btRoute)) {
setRouteConnectionState(btRoute, STATE_DISCONNECTED);
@@ -378,7 +374,7 @@
Iterator<BluetoothRouteInfo> iter = mActiveRoutes.iterator();
while (iter.hasNext()) {
BluetoothRouteInfo btRoute = iter.next();
- if (btRoute.route.getType() == type) {
+ if (btRoute.mRoute.getType() == type) {
iter.remove();
setRouteConnectionState(btRoute, STATE_DISCONNECTED);
}
@@ -398,9 +394,9 @@
// A bluetooth route with the same route ID should be added.
for (BluetoothRouteInfo btRoute : mBluetoothRoutes.values()) {
- if (TextUtils.equals(btRoute.route.getId(), activeBtRoute.route.getId())
- && !TextUtils.equals(btRoute.btDevice.getAddress(),
- activeBtRoute.btDevice.getAddress())) {
+ if (TextUtils.equals(btRoute.mRoute.getId(), activeBtRoute.mRoute.getId())
+ && !TextUtils.equals(btRoute.mBtDevice.getAddress(),
+ activeBtRoute.mBtDevice.getAddress())) {
addActiveRoute(btRoute);
}
}
@@ -425,19 +421,19 @@
void onBluetoothRoutesUpdated(@NonNull List<MediaRoute2Info> routes);
}
- private class BluetoothRouteInfo {
- public BluetoothDevice btDevice;
- public MediaRoute2Info route;
- public SparseBooleanArray connectedProfiles;
+ private static class BluetoothRouteInfo {
+ private BluetoothDevice mBtDevice;
+ private MediaRoute2Info mRoute;
+ private SparseBooleanArray mConnectedProfiles;
@MediaRoute2Info.Type
int getRouteType() {
// Let hearing aid profile have a priority.
- if (connectedProfiles.get(BluetoothProfile.HEARING_AID, false)) {
+ if (mConnectedProfiles.get(BluetoothProfile.HEARING_AID, false)) {
return MediaRoute2Info.TYPE_HEARING_AID;
}
- if (connectedProfiles.get(BluetoothProfile.LE_AUDIO, false)) {
+ if (mConnectedProfiles.get(BluetoothProfile.LE_AUDIO, false)) {
return MediaRoute2Info.TYPE_BLE_HEADSET;
}
@@ -447,6 +443,7 @@
// These callbacks run on the main thread.
private final class BluetoothProfileListener implements BluetoothProfile.ServiceListener {
+ @Override
public void onServiceConnected(int profile, BluetoothProfile proxy) {
List<BluetoothDevice> activeDevices;
switch (profile) {
@@ -480,6 +477,7 @@
notifyBluetoothRoutesUpdated();
}
+ @Override
public void onServiceDisconnected(int profile) {
switch (profile) {
case BluetoothProfile.A2DP:
@@ -496,6 +494,7 @@
}
}
}
+
private class BluetoothBroadcastReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
@@ -514,6 +513,7 @@
}
private class AdapterStateChangedReceiver implements BluetoothEventReceiver {
+ @Override
public void onReceive(Context context, Intent intent, BluetoothDevice device) {
int state = intent.getIntExtra(BluetoothAdapter.EXTRA_STATE, -1);
if (state == BluetoothAdapter.STATE_OFF
@@ -573,18 +573,18 @@
if (state == BluetoothProfile.STATE_CONNECTED) {
if (btRoute == null) {
btRoute = createBluetoothRoute(device);
- if (btRoute.connectedProfiles.size() > 0) {
+ if (btRoute.mConnectedProfiles.size() > 0) {
mBluetoothRoutes.put(device.getAddress(), btRoute);
notifyBluetoothRoutesUpdated();
}
} else {
- btRoute.connectedProfiles.put(profile, true);
+ btRoute.mConnectedProfiles.put(profile, true);
}
} else if (state == BluetoothProfile.STATE_DISCONNECTING
|| state == BluetoothProfile.STATE_DISCONNECTED) {
if (btRoute != null) {
- btRoute.connectedProfiles.delete(profile);
- if (btRoute.connectedProfiles.size() == 0) {
+ btRoute.mConnectedProfiles.delete(profile);
+ if (btRoute.mConnectedProfiles.size() == 0) {
removeActiveRoute(mBluetoothRoutes.remove(device.getAddress()));
notifyBluetoothRoutesUpdated();
}
diff --git a/services/core/java/com/android/server/NetworkManagementInternal.java b/services/core/java/com/android/server/net/NetworkManagementInternal.java
similarity index 96%
rename from services/core/java/com/android/server/NetworkManagementInternal.java
rename to services/core/java/com/android/server/net/NetworkManagementInternal.java
index f53c454..4926960 100644
--- a/services/core/java/com/android/server/NetworkManagementInternal.java
+++ b/services/core/java/com/android/server/net/NetworkManagementInternal.java
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package com.android.server;
+package com.android.server.net;
/**
* NetworkManagement local system service interface.
diff --git a/services/core/java/com/android/server/NetworkManagementService.java b/services/core/java/com/android/server/net/NetworkManagementService.java
similarity index 99%
rename from services/core/java/com/android/server/NetworkManagementService.java
rename to services/core/java/com/android/server/net/NetworkManagementService.java
index fc26f09..acfa665 100644
--- a/services/core/java/com/android/server/NetworkManagementService.java
+++ b/services/core/java/com/android/server/net/NetworkManagementService.java
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package com.android.server;
+package com.android.server.net;
import static android.Manifest.permission.CONNECTIVITY_INTERNAL;
import static android.net.ConnectivityManager.FIREWALL_CHAIN_DOZABLE;
@@ -82,6 +82,8 @@
import com.android.internal.util.Preconditions;
import com.android.net.module.util.NetdUtils;
import com.android.net.module.util.NetdUtils.ModifyOperation;
+import com.android.server.FgThread;
+import com.android.server.LocalServices;
import com.google.android.collect.Maps;
diff --git a/services/core/java/com/android/server/net/TEST_MAPPING b/services/core/java/com/android/server/net/TEST_MAPPING
index 4ccf09e..e0376ed 100644
--- a/services/core/java/com/android/server/net/TEST_MAPPING
+++ b/services/core/java/com/android/server/net/TEST_MAPPING
@@ -15,7 +15,7 @@
"presubmit": [
{
"name": "FrameworksServicesTests",
- "file_patterns": ["(/|^)NetworkPolicy[^/]*\\.java"],
+ "file_patterns": ["(/|^)Network(Policy|Management)[^/]*\\.java"],
"options": [
{
"include-filter": "com.android.server.net."
diff --git a/services/core/java/com/android/server/notification/NotificationShellCmd.java b/services/core/java/com/android/server/notification/NotificationShellCmd.java
index 628a322..dc0cf4e 100644
--- a/services/core/java/com/android/server/notification/NotificationShellCmd.java
+++ b/services/core/java/com/android/server/notification/NotificationShellCmd.java
@@ -540,16 +540,16 @@
if ("broadcast".equals(intentKind)) {
pi = PendingIntent.getBroadcastAsUser(
context, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT
- | PendingIntent.FLAG_MUTABLE_UNAUDITED,
+ | PendingIntent.FLAG_IMMUTABLE,
UserHandle.CURRENT);
} else if ("service".equals(intentKind)) {
pi = PendingIntent.getService(
context, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT
- | PendingIntent.FLAG_MUTABLE_UNAUDITED);
+ | PendingIntent.FLAG_IMMUTABLE);
} else {
pi = PendingIntent.getActivityAsUser(
context, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT
- | PendingIntent.FLAG_MUTABLE_UNAUDITED, null,
+ | PendingIntent.FLAG_IMMUTABLE, null,
UserHandle.CURRENT);
}
builder.setContentIntent(pi);
diff --git a/services/core/java/com/android/server/notification/PreferencesHelper.java b/services/core/java/com/android/server/notification/PreferencesHelper.java
index 1bbcc83..5ab9f38 100644
--- a/services/core/java/com/android/server/notification/PreferencesHelper.java
+++ b/services/core/java/com/android/server/notification/PreferencesHelper.java
@@ -1007,6 +1007,7 @@
channel.setAllowBubbles(existing != null
? existing.getAllowBubbles()
: NotificationChannel.DEFAULT_ALLOW_BUBBLE);
+ channel.setImportantConversation(false);
}
clearLockedFieldsLocked(channel);
diff --git a/services/core/java/com/android/server/pm/AppDataHelper.java b/services/core/java/com/android/server/pm/AppDataHelper.java
index abaff4a..d252d40 100644
--- a/services/core/java/com/android/server/pm/AppDataHelper.java
+++ b/services/core/java/com/android/server/pm/AppDataHelper.java
@@ -616,6 +616,7 @@
Slog.w(TAG, String.valueOf(e));
}
mPm.getDexManager().notifyPackageDataDestroyed(pkg.getPackageName(), userId);
+ mPm.getDynamicCodeLogger().notifyPackageDataDestroyed(pkg.getPackageName(), userId);
}
}
diff --git a/services/core/java/com/android/server/pm/AppsFilterImpl.java b/services/core/java/com/android/server/pm/AppsFilterImpl.java
index 5ff1909b..ac8ff21 100644
--- a/services/core/java/com/android/server/pm/AppsFilterImpl.java
+++ b/services/core/java/com/android/server/pm/AppsFilterImpl.java
@@ -32,6 +32,7 @@
import static com.android.internal.util.FrameworkStatsLog.PACKAGE_MANAGER_APPS_FILTER_CACHE_UPDATE_REPORTED__EVENT_TYPE__PACKAGE_DELETED;
import static com.android.internal.util.FrameworkStatsLog.PACKAGE_MANAGER_APPS_FILTER_CACHE_UPDATE_REPORTED__EVENT_TYPE__PACKAGE_REPLACED;
import static com.android.server.pm.AppsFilterUtils.canQueryAsInstaller;
+import static com.android.server.pm.AppsFilterUtils.canQueryAsUpdateOwner;
import static com.android.server.pm.AppsFilterUtils.canQueryViaComponents;
import static com.android.server.pm.AppsFilterUtils.canQueryViaPackage;
import static com.android.server.pm.AppsFilterUtils.canQueryViaUsesLibrary;
@@ -670,7 +671,8 @@
}
}
if (canQueryViaPackage(existingPkg, newPkg)
- || canQueryAsInstaller(existingSetting, newPkg)) {
+ || canQueryAsInstaller(existingSetting, newPkg)
+ || canQueryAsUpdateOwner(existingSetting, newPkg)) {
synchronized (mQueriesViaPackageLock) {
mQueriesViaPackage.add(existingSetting.getAppId(),
newPkgSetting.getAppId());
@@ -697,7 +699,8 @@
}
}
if (canQueryViaPackage(newPkg, existingPkg)
- || canQueryAsInstaller(newPkgSetting, existingPkg)) {
+ || canQueryAsInstaller(newPkgSetting, existingPkg)
+ || canQueryAsUpdateOwner(newPkgSetting, existingPkg)) {
synchronized (mQueriesViaPackageLock) {
mQueriesViaPackage.add(newPkgSetting.getAppId(),
existingSetting.getAppId());
diff --git a/services/core/java/com/android/server/pm/AppsFilterUtils.java b/services/core/java/com/android/server/pm/AppsFilterUtils.java
index 8da1d21..d38b83f 100644
--- a/services/core/java/com/android/server/pm/AppsFilterUtils.java
+++ b/services/core/java/com/android/server/pm/AppsFilterUtils.java
@@ -91,6 +91,15 @@
return false;
}
+ public static boolean canQueryAsUpdateOwner(PackageStateInternal querying,
+ AndroidPackage potentialTarget) {
+ final InstallSource installSource = querying.getInstallSource();
+ if (potentialTarget.getPackageName().equals(installSource.mUpdateOwnerPackageName)) {
+ return true;
+ }
+ return false;
+ }
+
public static boolean canQueryViaUsesLibrary(AndroidPackage querying,
AndroidPackage potentialTarget) {
if (potentialTarget.getLibraryNames().isEmpty()) {
diff --git a/services/core/java/com/android/server/pm/BroadcastHelper.java b/services/core/java/com/android/server/pm/BroadcastHelper.java
index d6233c7..98d6081 100644
--- a/services/core/java/com/android/server/pm/BroadcastHelper.java
+++ b/services/core/java/com/android/server/pm/BroadcastHelper.java
@@ -51,7 +51,6 @@
import com.android.internal.util.ArrayUtils;
import java.util.ArrayList;
-import java.util.List;
import java.util.function.BiFunction;
import java.util.function.Supplier;
@@ -334,6 +333,13 @@
sendPackageBroadcast(Intent.ACTION_PACKAGE_ADDED,
packageName, extras, 0, null, null, userIds, instantUserIds,
broadcastAllowlist, null /* filterExtrasForReceiver */, null);
+ // Send to PermissionController for all new users, even if it may not be running for some
+ // users
+ sendPackageBroadcast(Intent.ACTION_PACKAGE_ADDED,
+ packageName, extras, 0,
+ mContext.getPackageManager().getPermissionControllerPackageName(),
+ null, userIds, instantUserIds,
+ broadcastAllowlist, null /* filterExtrasForReceiver */, null);
}
public void sendFirstLaunchBroadcast(String pkgName, String installerPkg,
diff --git a/services/core/java/com/android/server/pm/ComputerEngine.java b/services/core/java/com/android/server/pm/ComputerEngine.java
index 0eac9ef..c6700e6 100644
--- a/services/core/java/com/android/server/pm/ComputerEngine.java
+++ b/services/core/java/com/android/server/pm/ComputerEngine.java
@@ -4981,6 +4981,7 @@
String installerPackageName;
String initiatingPackageName;
String originatingPackageName;
+ String updateOwnerPackageName;
final InstallSource installSource = getInstallSource(packageName, callingUid, userId);
if (installSource == null) {
@@ -4996,6 +4997,15 @@
}
}
+ updateOwnerPackageName = installSource.mUpdateOwnerPackageName;
+ if (updateOwnerPackageName != null) {
+ final PackageStateInternal ps = mSettings.getPackage(updateOwnerPackageName);
+ if (ps == null
+ || shouldFilterApplicationIncludingUninstalled(ps, callingUid, userId)) {
+ updateOwnerPackageName = null;
+ }
+ }
+
if (installSource.mIsInitiatingPackageUninstalled) {
// We can't check visibility in the usual way, since the initiating package is no
// longer present. So we apply simpler rules to whether to expose the info:
@@ -5052,7 +5062,8 @@
}
return new InstallSourceInfo(initiatingPackageName, initiatingPackageSigningInfo,
- originatingPackageName, installerPackageName, installSource.mPackageSource);
+ originatingPackageName, installerPackageName, updateOwnerPackageName,
+ installSource.mPackageSource);
}
@PackageManager.EnabledState
diff --git a/services/core/java/com/android/server/pm/CrossProfileIntentResolverEngine.java b/services/core/java/com/android/server/pm/CrossProfileIntentResolverEngine.java
index 1e0822d..397fdd8 100644
--- a/services/core/java/com/android/server/pm/CrossProfileIntentResolverEngine.java
+++ b/services/core/java/com/android/server/pm/CrossProfileIntentResolverEngine.java
@@ -30,6 +30,7 @@
import android.content.pm.PackageManager;
import android.content.pm.ResolveInfo;
import android.content.pm.UserInfo;
+import android.content.pm.UserProperties;
import android.os.Process;
import android.text.TextUtils;
import android.util.Pair;
@@ -147,8 +148,6 @@
return crossProfileDomainInfos;
}
- UserInfo userInfo = mUserManagerInternal.getUserInfo(userId);
-
// Grouping the CrossProfileIntentFilters based on targerId
SparseArray<List<CrossProfileIntentFilter>> crossProfileIntentFiltersByUser =
new SparseArray<>();
@@ -183,11 +182,9 @@
continue;
}
- UserInfo targetUserInfo = mUserManagerInternal.getUserInfo(targetUserId);
-
// Choosing strategy based on source and target user
CrossProfileResolver crossProfileResolver =
- chooseCrossProfileResolver(computer, userInfo, targetUserInfo);
+ chooseCrossProfileResolver(computer, userId, targetUserId);
/*
If {@link CrossProfileResolver} is available for source,target pair we will call it to
@@ -234,23 +231,21 @@
/**
* Returns {@link CrossProfileResolver} strategy based on source and target user
* @param computer {@link Computer} instance used for resolution by {@link ComponentResolverApi}
- * @param sourceUserInfo source user
- * @param targetUserInfo target user
+ * @param sourceUserId source user
+ * @param targetUserId target user
* @return {@code CrossProfileResolver} which has value if source and target have
* strategy configured otherwise null.
*/
@SuppressWarnings("unused")
private CrossProfileResolver chooseCrossProfileResolver(@NonNull Computer computer,
- UserInfo sourceUserInfo, UserInfo targetUserInfo) {
- //todo change isCloneProfile to user properties b/241532322
+ @UserIdInt int sourceUserId, @UserIdInt int targetUserId) {
/**
- * If source or target user is clone profile, using {@link CloneProfileResolver}
- * We would allow CloneProfileResolver only if flag
- * SETTINGS_ALLOW_INTENT_REDIRECTION_FOR_CLONE_PROFILE is enabled
+ * If source or target user is clone profile, using {@link NoFilteringResolver}
+ * We would return NoFilteringResolver only if it is allowed(feature flag is set).
*/
- if (sourceUserInfo.isCloneProfile() || targetUserInfo.isCloneProfile()) {
- if (CloneProfileResolver.isIntentRedirectionForCloneProfileAllowed()) {
- return new CloneProfileResolver(computer.getComponentResolver(),
+ if (shouldUseNoFilteringResolver(sourceUserId, targetUserId)) {
+ if (NoFilteringResolver.isIntentRedirectionAllowed()) {
+ return new NoFilteringResolver(computer.getComponentResolver(),
mUserManager);
} else {
return null;
@@ -624,7 +619,6 @@
categorizeResolveInfoByTargetUser, int sourceUserId, int highestApprovalLevel) {
List<CrossProfileDomainInfo> crossProfileDomainInfos = new ArrayList<>();
- UserInfo sourceUserInfo = mUserManagerInternal.getUserInfo(sourceUserId);
for (int index = 0; index < categorizeResolveInfoByTargetUser.size(); index++) {
@@ -634,8 +628,8 @@
} else {
// finding cross profile strategy based on source and target user
CrossProfileResolver crossProfileIntentResolver =
- chooseCrossProfileResolver(computer, sourceUserInfo, mUserManagerInternal
- .getUserInfo(categorizeResolveInfoByTargetUser.keyAt(index)));
+ chooseCrossProfileResolver(computer, sourceUserId,
+ categorizeResolveInfoByTargetUser.keyAt(index));
// if strategy is available call it and add its filtered results
if (crossProfileIntentResolver != null) {
crossProfileDomainInfos.addAll(crossProfileIntentResolver
@@ -678,4 +672,32 @@
&& crossProfileDomainInfos.get(0).mResolveInfo != null
&& crossProfileDomainInfos.get(0).mResolveInfo.priority >= 0;
}
+
+ /**
+ * Deciding if we need to user {@link NoFilteringResolver} based on source and target user
+ * @param sourceUserId id of initiating user
+ * @param targetUserId id of cross profile linked user
+ * @return true if {@link NoFilteringResolver} is applicable in this case.
+ */
+ private boolean shouldUseNoFilteringResolver(@UserIdInt int sourceUserId,
+ @UserIdInt int targetUserId) {
+ return isNoFilteringPropertyConfiguredForUser(sourceUserId)
+ || isNoFilteringPropertyConfiguredForUser(targetUserId);
+ }
+
+ /**
+ * Check if configure property for cross profile intent resolution strategy for user is
+ * {@link UserProperties#CROSS_PROFILE_INTENT_RESOLUTION_STRATEGY_NO_FILTERING}
+ * @param userId id of user to check for property
+ * @return true if user have property set to
+ * {@link UserProperties#CROSS_PROFILE_INTENT_RESOLUTION_STRATEGY_NO_FILTERING}
+ */
+ private boolean isNoFilteringPropertyConfiguredForUser(@UserIdInt int userId) {
+ if (!mUserManager.isProfile(userId)) return false;
+ UserProperties userProperties = mUserManagerInternal.getUserProperties(userId);
+ if (userProperties == null) return false;
+
+ return userProperties.getCrossProfileIntentResolutionStrategy()
+ == UserProperties.CROSS_PROFILE_INTENT_RESOLUTION_STRATEGY_NO_FILTERING;
+ }
}
diff --git a/services/core/java/com/android/server/pm/DexOptHelper.java b/services/core/java/com/android/server/pm/DexOptHelper.java
index 39aa9c1..cf447a7 100644
--- a/services/core/java/com/android/server/pm/DexOptHelper.java
+++ b/services/core/java/com/android/server/pm/DexOptHelper.java
@@ -41,6 +41,7 @@
import android.annotation.RequiresPermission;
import android.app.ActivityManager;
import android.app.AppGlobals;
+import android.content.Context;
import android.content.Intent;
import android.content.pm.ResolveInfo;
import android.content.pm.SharedLibraryInfo;
@@ -84,8 +85,10 @@
import java.util.Comparator;
import java.util.HashSet;
import java.util.List;
+import java.util.Objects;
import java.util.Optional;
import java.util.Set;
+import java.util.concurrent.Executor;
import java.util.concurrent.TimeUnit;
import java.util.function.Predicate;
@@ -416,17 +419,22 @@
return true;
}
+ @DexOptResult int dexoptStatus;
if (options.isDexoptOnlySecondaryDex()) {
- // TODO(b/251903639): Call into ART Service.
- try {
- return mPm.getDexManager().dexoptSecondaryDex(options);
- } catch (LegacyDexoptDisabledException e) {
- throw new RuntimeException(e);
+ Optional<Integer> artSrvRes = performDexOptWithArtService(options, 0 /* extraFlags */);
+ if (artSrvRes.isPresent()) {
+ dexoptStatus = artSrvRes.get();
+ } else {
+ try {
+ return mPm.getDexManager().dexoptSecondaryDex(options);
+ } catch (LegacyDexoptDisabledException e) {
+ throw new RuntimeException(e);
+ }
}
} else {
- int dexoptStatus = performDexOptWithStatus(options);
- return dexoptStatus != PackageDexOptimizer.DEX_OPT_FAILED;
+ dexoptStatus = performDexOptWithStatus(options);
}
+ return dexoptStatus != PackageDexOptimizer.DEX_OPT_FAILED;
}
/**
@@ -455,7 +463,8 @@
// if the package can now be considered up to date for the given filter.
@DexOptResult
private int performDexOptInternal(DexoptOptions options) {
- Optional<Integer> artSrvRes = performDexOptWithArtService(options);
+ Optional<Integer> artSrvRes =
+ performDexOptWithArtService(options, ArtFlags.FLAG_SHOULD_INCLUDE_DEPENDENCIES);
if (artSrvRes.isPresent()) {
return artSrvRes.get();
}
@@ -492,7 +501,8 @@
* @return a {@link DexOptResult}, or empty if the request isn't supported so that it is
* necessary to fall back to the legacy code paths.
*/
- private Optional<Integer> performDexOptWithArtService(DexoptOptions options) {
+ private Optional<Integer> performDexOptWithArtService(DexoptOptions options,
+ /*@OptimizeFlags*/ int extraFlags) {
ArtManagerLocal artManager = getArtManagerLocal();
if (artManager == null) {
return Optional.empty();
@@ -512,18 +522,11 @@
return Optional.of(PackageDexOptimizer.DEX_OPT_SKIPPED);
}
- // TODO(b/245301593): Delete the conditional when ART Service supports
- // FLAG_SHOULD_INCLUDE_DEPENDENCIES and we can just set it unconditionally.
- /*@OptimizeFlags*/ int extraFlags = ops.getUsesLibraries().isEmpty()
- ? 0
- : ArtFlags.FLAG_SHOULD_INCLUDE_DEPENDENCIES;
-
OptimizeParams params = options.convertToOptimizeParams(extraFlags);
if (params == null) {
return Optional.empty();
}
- // TODO(b/251903639): Either remove controlDexOptBlocking, or don't ignore it here.
OptimizeResult result;
try {
result = artManager.optimizePackage(snapshot, options.getPackageName(), params);
@@ -532,21 +535,6 @@
return Optional.empty();
}
- // TODO(b/251903639): Move this to ArtManagerLocal.addOptimizePackageDoneCallback when
- // it is implemented.
- for (OptimizeResult.PackageOptimizeResult pkgRes : result.getPackageOptimizeResults()) {
- PackageState ps = snapshot.getPackageState(pkgRes.getPackageName());
- AndroidPackage ap = ps != null ? ps.getAndroidPackage() : null;
- if (ap != null) {
- CompilerStats.PackageStats stats = mPm.getOrCreateCompilerPackageStats(ap);
- for (OptimizeResult.DexContainerFileOptimizeResult dexRes :
- pkgRes.getDexContainerFileOptimizeResults()) {
- stats.setCompileTime(
- dexRes.getDexContainerFile(), dexRes.getDex2oatWallTimeMillis());
- }
- }
- }
-
return Optional.of(convertToDexOptResult(result));
}
}
@@ -555,9 +543,9 @@
private int performDexOptInternalWithDependenciesLI(
AndroidPackage p, @NonNull PackageStateInternal pkgSetting, DexoptOptions options)
throws LegacyDexoptDisabledException {
- // System server gets a special path.
if (PLATFORM_PACKAGE_NAME.equals(p.getPackageName())) {
- return mPm.getDexManager().dexoptSystemServer(options);
+ // This needs to be done in odrefresh in early boot, for security reasons.
+ throw new IllegalArgumentException("Cannot dexopt the system server");
}
// Select the dex optimizer based on the force parameter.
@@ -628,7 +616,8 @@
// performDexOptWithArtService ignores the snapshot and takes its own, so it can race with
// the package checks above, but at worst the effect is only a bit less friendly error
// below.
- Optional<Integer> artSrvRes = performDexOptWithArtService(options);
+ Optional<Integer> artSrvRes =
+ performDexOptWithArtService(options, ArtFlags.FLAG_SHOULD_INCLUDE_DEPENDENCIES);
int res;
if (artSrvRes.isPresent()) {
res = artSrvRes.get();
@@ -965,6 +954,51 @@
}
}
+ private static class OptimizePackageDoneHandler
+ implements ArtManagerLocal.OptimizePackageDoneCallback {
+ @NonNull private final PackageManagerService mPm;
+
+ OptimizePackageDoneHandler(@NonNull PackageManagerService pm) { mPm = pm; }
+
+ /**
+ * Called after every package optimization operation done by {@link ArtManagerLocal}.
+ */
+ @Override
+ public void onOptimizePackageDone(@NonNull OptimizeResult result) {
+ for (OptimizeResult.PackageOptimizeResult pkgRes : result.getPackageOptimizeResults()) {
+ CompilerStats.PackageStats stats =
+ mPm.getOrCreateCompilerPackageStats(pkgRes.getPackageName());
+ for (OptimizeResult.DexContainerFileOptimizeResult dexRes :
+ pkgRes.getDexContainerFileOptimizeResults()) {
+ stats.setCompileTime(
+ dexRes.getDexContainerFile(), dexRes.getDex2oatWallTimeMillis());
+ }
+ }
+
+ synchronized (mPm.mLock) {
+ mPm.getPackageUsage().maybeWriteAsync(mPm.mSettings.getPackagesLocked());
+ mPm.mCompilerStats.maybeWriteAsync();
+ }
+ }
+ }
+
+ /**
+ * Initializes {@link ArtManagerLocal} before {@link getArtManagerLocal} is called.
+ */
+ public static void initializeArtManagerLocal(
+ @NonNull Context systemContext, @NonNull PackageManagerService pm) {
+ if (!useArtService()) {
+ return;
+ }
+
+ ArtManagerLocal artManager = new ArtManagerLocal(systemContext);
+ // There doesn't appear to be any checks that @NonNull is heeded, so use requireNonNull
+ // below to ensure we don't store away a null that we'll fail on later.
+ artManager.addOptimizePackageDoneCallback(false /* onlyIncludeUpdates */,
+ Runnable::run, new OptimizePackageDoneHandler(Objects.requireNonNull(pm)));
+ LocalManagerRegistry.addManager(ArtManagerLocal.class, artManager);
+ }
+
/**
* Returns {@link ArtManagerLocal} if ART Service should be used for package optimization.
*/
diff --git a/services/core/java/com/android/server/pm/DynamicCodeLoggingService.java b/services/core/java/com/android/server/pm/DynamicCodeLoggingService.java
index b4bcd5b..cae7079 100644
--- a/services/core/java/com/android/server/pm/DynamicCodeLoggingService.java
+++ b/services/core/java/com/android/server/pm/DynamicCodeLoggingService.java
@@ -27,13 +27,17 @@
import android.util.EventLog;
import android.util.Log;
+import com.android.server.LocalManagerRegistry;
import com.android.server.LocalServices;
+import com.android.server.art.DexUseManagerLocal;
+import com.android.server.art.model.DexContainerFileUseInfo;
import com.android.server.pm.dex.DynamicCodeLogger;
import libcore.util.HexEncoding;
import java.util.ArrayList;
import java.util.List;
+import java.util.Objects;
import java.util.concurrent.TimeUnit;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
@@ -137,6 +141,28 @@
return LocalServices.getService(PackageManagerInternal.class).getDynamicCodeLogger();
}
+ private static void syncDataFromArtService(DynamicCodeLogger dynamicCodeLogger) {
+ DexUseManagerLocal dexUseManagerLocal = DexOptHelper.getDexUseManagerLocal();
+ if (dexUseManagerLocal == null) {
+ // ART Service is not enabled.
+ return;
+ }
+ PackageManagerLocal packageManagerLocal =
+ Objects.requireNonNull(LocalManagerRegistry.getManager(PackageManagerLocal.class));
+ try (PackageManagerLocal.UnfilteredSnapshot snapshot =
+ packageManagerLocal.withUnfilteredSnapshot()) {
+ for (String owningPackageName : snapshot.getPackageStates().keySet()) {
+ for (DexContainerFileUseInfo info :
+ dexUseManagerLocal.getSecondaryDexContainerFileUseInfo(owningPackageName)) {
+ for (String loadingPackageName : info.getLoadingPackages()) {
+ dynamicCodeLogger.recordDex(info.getUserHandle().getIdentifier(),
+ info.getDexContainerFile(), owningPackageName, loadingPackageName);
+ }
+ }
+ }
+ }
+ }
+
private class IdleLoggingThread extends Thread {
private final JobParameters mParams;
@@ -152,6 +178,7 @@
}
DynamicCodeLogger dynamicCodeLogger = getDynamicCodeLogger();
+ syncDataFromArtService(dynamicCodeLogger);
for (String packageName : dynamicCodeLogger.getAllPackagesWithDynamicCodeLoading()) {
if (mIdleLoggingStopRequested) {
Log.w(TAG, "Stopping IdleLoggingJob run at scheduler request");
diff --git a/services/core/java/com/android/server/pm/InstallPackageHelper.java b/services/core/java/com/android/server/pm/InstallPackageHelper.java
index 6f7484e..28a074b 100644
--- a/services/core/java/com/android/server/pm/InstallPackageHelper.java
+++ b/services/core/java/com/android/server/pm/InstallPackageHelper.java
@@ -311,10 +311,15 @@
pkgSetting.setForceQueryableOverride(true);
}
- // If this is part of a standard install, set the initiating package name, else rely on
- // previous device state.
InstallSource installSource = request.getInstallSource();
+ final boolean isApex = (scanFlags & SCAN_AS_APEX) != 0;
+ final String updateOwnerFromSysconfig = isApex || !pkgSetting.isSystem() ? null
+ : mPm.mInjector.getSystemConfig().getSystemAppUpdateOwnerPackageName(
+ parsedPackage.getPackageName());
+ // For new install (standard install), the installSource isn't null.
if (installSource != null) {
+ // If this is part of a standard install, set the initiating package name, else rely on
+ // previous device state.
if (installSource.mInitiatingPackageName != null) {
final PackageSetting ips = mPm.mSettings.getPackageLPr(
installSource.mInitiatingPackageName);
@@ -323,7 +328,41 @@
ips.getSignatures());
}
}
+
+ // Handle the update ownership enforcement for APK
+ if (updateOwnerFromSysconfig != null) {
+ // For system app, we always use the update owner from sysconfig if presented.
+ installSource = installSource.setUpdateOwnerPackageName(updateOwnerFromSysconfig);
+ } else if (!parsedPackage.isAllowUpdateOwnership()) {
+ // If the app wants to opt-out of the update ownership enforcement via manifest,
+ // it overrides the installer's use of #setRequestUpdateOwnership.
+ installSource = installSource.setUpdateOwnerPackageName(null);
+ } else if (!isApex) {
+ final boolean isUpdate = oldPkgSetting != null;
+ final String oldUpdateOwner =
+ isUpdate ? oldPkgSetting.getInstallSource().mUpdateOwnerPackageName : null;
+ final boolean isUpdateOwnershipEnabled = oldUpdateOwner != null;
+ final boolean isRequestUpdateOwnership = (request.getInstallFlags()
+ & PackageManager.INSTALL_REQUEST_UPDATE_OWNERSHIP) != 0;
+
+ // Here we assign the update owner for the package, and the rules are:
+ // -. If the installer doesn't request update ownership on initial installation,
+ // keep the update owner as null.
+ // -. If the installer doesn't want to be the owner to provide the subsequent
+ // update (doesn't request to be the update owner), e.g., non-store installer
+ // (file manager), ADB, or DO/PO, we should not update the owner.
+ // -. Else, the installer requests update ownership on initial installation or
+ // update, we use installSource.mUpdateOwnerPackageName as the update owner.
+ if (!isRequestUpdateOwnership || (isUpdate && !isUpdateOwnershipEnabled)) {
+ installSource = installSource.setUpdateOwnerPackageName(oldUpdateOwner);
+ }
+ }
+
pkgSetting.setInstallSource(installSource);
+ // non-standard install (addForInit and install existing packages), installSource is null.
+ } else if (updateOwnerFromSysconfig != null) {
+ // For system app, we always use the update owner from sysconfig if presented.
+ pkgSetting.setUpdateOwnerPackage(updateOwnerFromSysconfig);
}
if ((scanFlags & SCAN_AS_APK_IN_APEX) != 0) {
@@ -1039,15 +1078,48 @@
DeviceConfig.getInt(DeviceConfig.NAMESPACE_PACKAGE_MANAGER_SERVICE,
"MinInstallableTargetSdk__min_installable_target_sdk",
0);
- if (parsedPackage.getTargetSdkVersion() < minInstallableTargetSdk) {
+
+ // Skip enforcement when the bypass flag is set
+ boolean bypassLowTargetSdkBlock =
+ ((installFlags & PackageManager.INSTALL_BYPASS_LOW_TARGET_SDK_BLOCK) != 0);
+
+ // Skip enforcement for tests that were installed from adb
+ if (!bypassLowTargetSdkBlock
+ && ((installFlags & PackageManager.INSTALL_FROM_ADB) != 0)) {
+ bypassLowTargetSdkBlock = true;
+ }
+
+ // Skip enforcement if the installer package name is not set
+ // (e.g. "pm install" from shell)
+ if (!bypassLowTargetSdkBlock) {
+ if (request.getInstallerPackageName() == null) {
+ bypassLowTargetSdkBlock = true;
+ } else {
+ // Also skip if the install is occurring from an app that was installed from adb
+ if (mContext
+ .getPackageManager()
+ .getInstallerPackageName(request.getInstallerPackageName()) == null) {
+ bypassLowTargetSdkBlock = true;
+ }
+ }
+ }
+
+ // Skip enforcement when the testOnly flag is set
+ if (!bypassLowTargetSdkBlock && parsedPackage.isTestOnly()) {
+ bypassLowTargetSdkBlock = true;
+ }
+
+ // Enforce the low target sdk install block except when
+ // the --bypass-low-target-sdk-block is set for the install
+ if (!bypassLowTargetSdkBlock
+ && parsedPackage.getTargetSdkVersion() < minInstallableTargetSdk) {
Slog.w(TAG, "App " + parsedPackage.getPackageName()
+ " targets deprecated sdk version");
throw new PrepareFailure(INSTALL_FAILED_DEPRECATED_SDK_VERSION,
- "App package must target at least version "
- + minInstallableTargetSdk);
+ "App package must target at least SDK version "
+ + minInstallableTargetSdk + ", but found "
+ + parsedPackage.getTargetSdkVersion());
}
- } else {
- Slog.i(TAG, "Minimum installable target sdk enforcement not enabled");
}
// Instant apps have several additional install-time checks.
@@ -1074,7 +1146,7 @@
if (onExternal) {
Slog.i(TAG, "Static shared libs can only be installed on internal storage.");
throw new PrepareFailure(INSTALL_FAILED_INVALID_INSTALL_LOCATION,
- "Packages declaring static-shared libs cannot be updated");
+ "Static shared libs can only be installed on internal storage.");
}
}
@@ -2219,7 +2291,7 @@
}
}
installRequest.setName(pkgName);
- installRequest.setUid(pkg.getUid());
+ installRequest.setAppId(pkg.getUid());
installRequest.setPkg(pkg);
installRequest.setReturnCode(PackageManager.INSTALL_SUCCEEDED);
//to update install status
@@ -2704,7 +2776,7 @@
}
Bundle extras = new Bundle();
- extras.putInt(Intent.EXTRA_UID, request.getUid());
+ extras.putInt(Intent.EXTRA_UID, request.getAppId());
if (update) {
extras.putBoolean(Intent.EXTRA_REPLACING, true);
}
@@ -2727,7 +2799,7 @@
// Send PACKAGE_ADDED broadcast for users that see the package for the first time
// sendPackageAddedForNewUsers also deals with system apps
- int appId = UserHandle.getAppId(request.getUid());
+ int appId = UserHandle.getAppId(request.getAppId());
boolean isSystem = request.isInstallSystem();
mPm.sendPackageAddedForNewUsers(mPm.snapshotComputer(), packageName,
isSystem || virtualPreload, virtualPreload /*startReceiver*/, appId,
@@ -2755,6 +2827,12 @@
installerPackageName, null /*finishedReceiver*/,
updateUserIds, instantUserIds, null /* broadcastAllowList */, null);
}
+ // Send to PermissionController for all update users, even if it may not be running
+ // for some users
+ mPm.sendPackageBroadcast(Intent.ACTION_PACKAGE_ADDED, packageName,
+ extras, 0 /*flags*/,
+ mPm.mRequiredPermissionControllerPackage, null /*finishedReceiver*/,
+ updateUserIds, instantUserIds, null /* broadcastAllowList */, null);
// Notify required verifier(s) that are not the installer of record for the package.
for (String verifierPackageName : mPm.mRequiredVerifierPackages) {
if (verifierPackageName != null && !verifierPackageName.equals(
@@ -2866,9 +2944,9 @@
}
if (allNewUsers && !update) {
- mPm.notifyPackageAdded(packageName, request.getUid());
+ mPm.notifyPackageAdded(packageName, request.getAppId());
} else {
- mPm.notifyPackageChanged(packageName, request.getUid());
+ mPm.notifyPackageChanged(packageName, request.getAppId());
}
// Log current value of "unknown sources" setting
diff --git a/services/core/java/com/android/server/pm/InstallRequest.java b/services/core/java/com/android/server/pm/InstallRequest.java
index c6cdc4c..878c1c1 100644
--- a/services/core/java/com/android/server/pm/InstallRequest.java
+++ b/services/core/java/com/android/server/pm/InstallRequest.java
@@ -81,7 +81,7 @@
/** Package Installed Info */
@Nullable
private String mName;
- private int mUid = INVALID_UID;
+ private int mAppId = INVALID_UID;
// The set of users that originally had this package installed.
@Nullable
private int[] mOrigUsers;
@@ -158,7 +158,7 @@
mUserId = user.getIdentifier();
} else {
// APEX
- mUserId = INVALID_UID;
+ mUserId = UserHandle.USER_SYSTEM;
}
mInstallArgs = null;
mParsedPackage = parsedPackage;
@@ -367,8 +367,8 @@
return mOrigUsers;
}
- public int getUid() {
- return mUid;
+ public int getAppId() {
+ return mAppId;
}
@Nullable
@@ -648,8 +648,8 @@
mPkg = pkg;
}
- public void setUid(int uid) {
- mUid = uid;
+ public void setAppId(int appId) {
+ mAppId = appId;
}
public void setNewUsers(int[] newUsers) {
@@ -773,10 +773,10 @@
}
}
- public void onInstallCompleted(int userId) {
+ public void onInstallCompleted() {
if (getReturnCode() == INSTALL_SUCCEEDED) {
if (mPackageMetrics != null) {
- mPackageMetrics.onInstallSucceed(userId);
+ mPackageMetrics.onInstallSucceed();
}
}
}
diff --git a/services/core/java/com/android/server/pm/InstallSource.java b/services/core/java/com/android/server/pm/InstallSource.java
index dde9905..65bde51 100644
--- a/services/core/java/com/android/server/pm/InstallSource.java
+++ b/services/core/java/com/android/server/pm/InstallSource.java
@@ -34,12 +34,18 @@
* An instance of InstallSource representing an absence of knowledge of the source of
* a package. Used in preference to null.
*/
- static final InstallSource EMPTY = new InstallSource(null, null, null, INVALID_UID, null,
- false, false, null, PackageInstaller.PACKAGE_SOURCE_UNSPECIFIED);
+ static final InstallSource EMPTY = new InstallSource(null /* initiatingPackageName */,
+ null /* originatingPackageName */, null /* installerPackageName */, INVALID_UID,
+ null /* updateOwnerPackageName */, null /* installerAttributionTag */,
+ false /* isOrphaned */, false /* isInitiatingPackageUninstalled */,
+ null /* initiatingPackageSignatures */, PackageInstaller.PACKAGE_SOURCE_UNSPECIFIED);
/** We also memoize this case because it is common - all un-updated system apps. */
private static final InstallSource EMPTY_ORPHANED = new InstallSource(
- null, null, null, INVALID_UID, null, true, false, null,
+ null /* initiatingPackageName */, null /* originatingPackageName */,
+ null /* installerPackageName */, INVALID_UID, null /* updateOwnerPackageName */,
+ null /* installerAttributionTag */, true /* isOrphaned */,
+ false /* isInitiatingPackageUninstalled */, null /* initiatingPackageSignatures */,
PackageInstaller.PACKAGE_SOURCE_UNSPECIFIED);
/**
@@ -73,6 +79,13 @@
final String mInstallerPackageName;
/**
+ * Package name of the app that requested the installer ownership. Note that this may be
+ * modified.
+ */
+ @Nullable
+ final String mUpdateOwnerPackageName;
+
+ /**
* UID of the installer package, corresponding to the {@link #mInstallerPackageName}.
*/
final int mInstallerPackageUid;
@@ -96,55 +109,64 @@
static InstallSource create(@Nullable String initiatingPackageName,
@Nullable String originatingPackageName, @Nullable String installerPackageName,
- int installerPackageUid, @Nullable String installerAttributionTag, boolean isOrphaned,
+ int installerPackageUid, @Nullable String updateOwnerPackageName,
+ @Nullable String installerAttributionTag, boolean isOrphaned,
boolean isInitiatingPackageUninstalled) {
return create(initiatingPackageName, originatingPackageName, installerPackageName,
- installerPackageUid, installerAttributionTag,
+ installerPackageUid, updateOwnerPackageName, installerAttributionTag,
PackageInstaller.PACKAGE_SOURCE_UNSPECIFIED, isOrphaned,
isInitiatingPackageUninstalled);
}
static InstallSource create(@Nullable String initiatingPackageName,
@Nullable String originatingPackageName, @Nullable String installerPackageName,
- int installerPackageUid, @Nullable String installerAttributionTag, int packageSource) {
+ int installerPackageUid, @Nullable String updateOwnerPackageName,
+ @Nullable String installerAttributionTag, int packageSource) {
return create(initiatingPackageName, originatingPackageName, installerPackageName,
- installerPackageUid, installerAttributionTag, packageSource, false, false);
+ installerPackageUid, updateOwnerPackageName, installerAttributionTag,
+ packageSource, false /* isOrphaned */, false /* isInitiatingPackageUninstalled */);
}
static InstallSource create(@Nullable String initiatingPackageName,
@Nullable String originatingPackageName, @Nullable String installerPackageName,
- int installerPackageUid, @Nullable String installerAttributionTag, int packageSource,
- boolean isOrphaned, boolean isInitiatingPackageUninstalled) {
+ int installerPackageUid, @Nullable String updateOwnerPackageName,
+ @Nullable String installerAttributionTag, int packageSource, boolean isOrphaned,
+ boolean isInitiatingPackageUninstalled) {
return createInternal(
intern(initiatingPackageName),
intern(originatingPackageName),
intern(installerPackageName),
installerPackageUid,
+ intern(updateOwnerPackageName),
installerAttributionTag,
packageSource,
- isOrphaned, isInitiatingPackageUninstalled, null);
+ isOrphaned, isInitiatingPackageUninstalled,
+ null /* initiatingPackageSignatures */);
}
private static InstallSource createInternal(@Nullable String initiatingPackageName,
@Nullable String originatingPackageName, @Nullable String installerPackageName,
- int installerPackageUid, @Nullable String installerAttributionTag, int packageSource,
- boolean isOrphaned, boolean isInitiatingPackageUninstalled,
+ int installerPackageUid, @Nullable String updateOwnerPackageName,
+ @Nullable String installerAttributionTag, int packageSource, boolean isOrphaned,
+ boolean isInitiatingPackageUninstalled,
@Nullable PackageSignatures initiatingPackageSignatures) {
if (initiatingPackageName == null && originatingPackageName == null
- && installerPackageName == null && initiatingPackageSignatures == null
+ && installerPackageName == null && updateOwnerPackageName == null
+ && initiatingPackageSignatures == null
&& !isInitiatingPackageUninstalled
&& packageSource == PackageInstaller.PACKAGE_SOURCE_UNSPECIFIED) {
return isOrphaned ? EMPTY_ORPHANED : EMPTY;
}
return new InstallSource(initiatingPackageName, originatingPackageName,
- installerPackageName, installerPackageUid, installerAttributionTag, isOrphaned,
- isInitiatingPackageUninstalled, initiatingPackageSignatures, packageSource
+ installerPackageName, installerPackageUid, updateOwnerPackageName,
+ installerAttributionTag, isOrphaned, isInitiatingPackageUninstalled,
+ initiatingPackageSignatures, packageSource
);
}
private InstallSource(@Nullable String initiatingPackageName,
@Nullable String originatingPackageName, @Nullable String installerPackageName,
- int installerPackageUid,
+ int installerPackageUid, @Nullable String updateOwnerPackageName,
@Nullable String installerAttributionTag, boolean isOrphaned,
boolean isInitiatingPackageUninstalled,
@Nullable PackageSignatures initiatingPackageSignatures,
@@ -157,6 +179,7 @@
mOriginatingPackageName = originatingPackageName;
mInstallerPackageName = installerPackageName;
mInstallerPackageUid = installerPackageUid;
+ mUpdateOwnerPackageName = updateOwnerPackageName;
mInstallerAttributionTag = installerAttributionTag;
mIsOrphaned = isOrphaned;
mIsInitiatingPackageUninstalled = isInitiatingPackageUninstalled;
@@ -174,9 +197,23 @@
return this;
}
return createInternal(mInitiatingPackageName, mOriginatingPackageName,
- intern(installerPackageName), installerPackageUid, mInstallerAttributionTag,
- mPackageSource, mIsOrphaned, mIsInitiatingPackageUninstalled,
- mInitiatingPackageSignatures);
+ intern(installerPackageName), installerPackageUid, mUpdateOwnerPackageName,
+ mInstallerAttributionTag, mPackageSource, mIsOrphaned,
+ mIsInitiatingPackageUninstalled, mInitiatingPackageSignatures);
+ }
+
+ /**
+ * Return an InstallSource the same as this one except with the specified
+ * {@link #mUpdateOwnerPackageName}.
+ */
+ InstallSource setUpdateOwnerPackageName(@Nullable String updateOwnerPackageName) {
+ if (Objects.equals(updateOwnerPackageName, mUpdateOwnerPackageName)) {
+ return this;
+ }
+ return createInternal(mInitiatingPackageName, mOriginatingPackageName,
+ mInstallerPackageName, mInstallerPackageUid, intern(updateOwnerPackageName),
+ mInstallerAttributionTag, mPackageSource, mIsOrphaned,
+ mIsInitiatingPackageUninstalled, mInitiatingPackageSignatures);
}
/**
@@ -188,8 +225,8 @@
return this;
}
return createInternal(mInitiatingPackageName, mOriginatingPackageName,
- mInstallerPackageName,
- mInstallerPackageUid, mInstallerAttributionTag, mPackageSource, isOrphaned,
+ mInstallerPackageName, mInstallerPackageUid, mUpdateOwnerPackageName,
+ mInstallerAttributionTag, mPackageSource, isOrphaned,
mIsInitiatingPackageUninstalled, mInitiatingPackageSignatures);
}
@@ -202,8 +239,8 @@
return this;
}
return createInternal(mInitiatingPackageName, mOriginatingPackageName,
- mInstallerPackageName,
- mInstallerPackageUid, mInstallerAttributionTag, mPackageSource, mIsOrphaned,
+ mInstallerPackageName, mInstallerPackageUid, mUpdateOwnerPackageName,
+ mInstallerAttributionTag, mPackageSource, mIsOrphaned,
mIsInitiatingPackageUninstalled, signatures);
}
@@ -220,6 +257,7 @@
boolean isInitiatingPackageUninstalled = mIsInitiatingPackageUninstalled;
String originatingPackageName = mOriginatingPackageName;
String installerPackageName = mInstallerPackageName;
+ String updateOwnerPackageName = mUpdateOwnerPackageName;
int installerPackageUid = mInstallerPackageUid;
boolean isOrphaned = mIsOrphaned;
@@ -242,13 +280,18 @@
isOrphaned = true;
modified = true;
}
+ if (packageName.equals(updateOwnerPackageName)) {
+ updateOwnerPackageName = null;
+ modified = true;
+ }
if (!modified) {
return this;
}
return createInternal(mInitiatingPackageName, originatingPackageName, installerPackageName,
- installerPackageUid, null, mPackageSource, isOrphaned,
+ installerPackageUid, updateOwnerPackageName,
+ null /* installerAttributionTag */, mPackageSource, isOrphaned,
isInitiatingPackageUninstalled, mInitiatingPackageSignatures);
}
diff --git a/services/core/java/com/android/server/pm/InstallingSession.java b/services/core/java/com/android/server/pm/InstallingSession.java
index eb3b29c..439b5425 100644
--- a/services/core/java/com/android/server/pm/InstallingSession.java
+++ b/services/core/java/com/android/server/pm/InstallingSession.java
@@ -535,7 +535,7 @@
mInstallPackageHelper.installPackagesTraced(installRequests);
for (InstallRequest request : installRequests) {
- request.onInstallCompleted(mUser.getIdentifier());
+ request.onInstallCompleted();
doPostInstall(request);
}
}
diff --git a/services/core/java/com/android/server/pm/CloneProfileResolver.java b/services/core/java/com/android/server/pm/NoFilteringResolver.java
similarity index 89%
rename from services/core/java/com/android/server/pm/CloneProfileResolver.java
rename to services/core/java/com/android/server/pm/NoFilteringResolver.java
index 73036f1..492f915 100644
--- a/services/core/java/com/android/server/pm/CloneProfileResolver.java
+++ b/services/core/java/com/android/server/pm/NoFilteringResolver.java
@@ -30,9 +30,10 @@
import java.util.function.Function;
/**
- * Cross Profile intent resolution strategy used for and to clone profile.
+ * Intent resolution strategy used when no filtering is required. As of now, the known use-case is
+ * clone profile.
*/
-public class CloneProfileResolver extends CrossProfileResolver {
+public class NoFilteringResolver extends CrossProfileResolver {
/**
* Feature flag to allow/restrict intent redirection from/to clone profile.
@@ -48,7 +49,7 @@
* Returns true if intent redirection for clone profile feature flag is set
* @return value of flag allow_intent_redirection_for_clone_profile
*/
- public static boolean isIntentRedirectionForCloneProfileAllowed() {
+ public static boolean isIntentRedirectionAllowed() {
final long token = Binder.clearCallingIdentity();
try {
return DeviceConfig.getBoolean(DeviceConfig.NAMESPACE_APP_CLONING,
@@ -58,13 +59,13 @@
}
}
- public CloneProfileResolver(ComponentResolverApi componentResolver,
+ public NoFilteringResolver(ComponentResolverApi componentResolver,
UserManagerService userManagerService) {
super(componentResolver, userManagerService);
}
/**
- * This is resolution strategy for Clone Profile.
+ * This is resolution strategy for when no filtering is required.
* In case of clone profile, the profile is supposed to be transparent to end user. To end user
* clone and owner profile should be part of same user space. Hence, the resolution strategy
* would resolve intent in both profile and return combined result without any filtering of the
@@ -105,8 +106,8 @@
}
/**
- * As clone and owner profile are going to be part of the same userspace, we need no filtering
- * out of any clone profile's result
+ * In case of Clone profile, the clone and owner profile are going to be part of the same
+ * userspace, we need no filtering out of any clone profile's result.
* @param intent request
* @param crossProfileDomainInfos resolved in target user
* @param flags for intent resolution
@@ -119,7 +120,7 @@
public List<CrossProfileDomainInfo> filterResolveInfoWithDomainPreferredActivity(Intent intent,
List<CrossProfileDomainInfo> crossProfileDomainInfos, long flags, int sourceUserId,
int targetUserId, int highestApprovalLevel) {
- // no filtering for clone profile
+ // no filtering
return crossProfileDomainInfos;
}
}
diff --git a/services/core/java/com/android/server/pm/PackageDexOptimizer.java b/services/core/java/com/android/server/pm/PackageDexOptimizer.java
index 0a71892..f708fbb 100644
--- a/services/core/java/com/android/server/pm/PackageDexOptimizer.java
+++ b/services/core/java/com/android/server/pm/PackageDexOptimizer.java
@@ -59,7 +59,6 @@
import android.os.Trace;
import android.os.UserHandle;
import android.os.WorkSource;
-import android.os.storage.StorageManager;
import android.util.Log;
import android.util.Slog;
import android.util.SparseArray;
@@ -184,10 +183,13 @@
}
boolean canOptimizePackage(@NonNull AndroidPackage pkg) {
+ // The system package has to be optimized during early boot by odrefresh instead.
+ if (PLATFORM_PACKAGE_NAME.equals(pkg.getPackageName())) {
+ return false;
+ }
+
// We do not dexopt a package with no code.
- // Note that the system package is marked as having no code, however we can
- // still optimize it via dexoptSystemServerPath.
- if (!PLATFORM_PACKAGE_NAME.equals(pkg.getPackageName()) && !pkg.isHasCode()) {
+ if (!pkg.isHasCode()) {
return false;
}
@@ -223,8 +225,8 @@
PackageDexUsage.PackageUseInfo packageUseInfo, DexoptOptions options)
throws LegacyDexoptDisabledException {
if (PLATFORM_PACKAGE_NAME.equals(pkg.getPackageName())) {
- throw new IllegalArgumentException("System server dexopting should be done via "
- + " DexManager and PackageDexOptimizer#dexoptSystemServerPath");
+ throw new IllegalArgumentException(
+ "System server dexopting should be done via odrefresh");
}
if (pkg.getUid() == -1) {
throw new IllegalArgumentException("Dexopt for " + pkg.getPackageName()
@@ -523,65 +525,6 @@
}
}
- /**
- * Perform dexopt (if needed) on a system server code path).
- */
- @GuardedBy("mInstallLock")
- @DexOptResult
- public int dexoptSystemServerPath(String dexPath, PackageDexUsage.DexUseInfo dexUseInfo,
- DexoptOptions options) throws LegacyDexoptDisabledException {
- int dexoptFlags = DEXOPT_PUBLIC
- | (options.isBootComplete() ? DEXOPT_BOOTCOMPLETE : 0)
- | (options.isDexoptIdleBackgroundJob() ? DEXOPT_IDLE_BACKGROUND_JOB : 0);
-
- int result = DEX_OPT_SKIPPED;
- for (String isa : dexUseInfo.getLoaderIsas()) {
- int dexoptNeeded = getDexoptNeeded(
- PackageManagerService.PLATFORM_PACKAGE_NAME,
- dexPath,
- isa,
- options.getCompilerFilter(),
- dexUseInfo.getClassLoaderContext(),
- PROFILE_ANALYSIS_DONT_OPTIMIZE_EMPTY_PROFILES,
- /* downgrade= */ false,
- dexoptFlags,
- /* oatDir= */ null);
-
- if (dexoptNeeded == DexFile.NO_DEXOPT_NEEDED) {
- continue;
- }
- try {
- synchronized (mInstallLock) {
- boolean completed = getInstallerLI().dexopt(
- dexPath,
- android.os.Process.SYSTEM_UID,
- /* pkgName= */ "android",
- isa,
- dexoptNeeded,
- /* outputPath= */ null,
- dexoptFlags,
- options.getCompilerFilter(),
- StorageManager.UUID_PRIVATE_INTERNAL,
- dexUseInfo.getClassLoaderContext(),
- /* seInfo= */ null,
- /* downgrade= */ false,
- /* targetSdkVersion= */ 0,
- /* profileName= */ null,
- /* dexMetadataPath= */ null,
- getReasonName(options.getCompilationReason()));
- if (!completed) {
- return DEX_OPT_CANCELLED;
- }
- }
- } catch (InstallerException e) {
- Slog.w(TAG, "Failed to dexopt", e);
- return DEX_OPT_FAILED;
- }
- result = DEX_OPT_PERFORMED;
- }
- return result;
- }
-
private String getAugmentedReasonName(int compilationReason, boolean useDexMetadata) {
String annotation = useDexMetadata
? ArtManagerService.DEXOPT_REASON_WITH_DEX_METADATA_ANNOTATION : "";
diff --git a/services/core/java/com/android/server/pm/PackageInstallerService.java b/services/core/java/com/android/server/pm/PackageInstallerService.java
index 8c5bab6..239853c 100644
--- a/services/core/java/com/android/server/pm/PackageInstallerService.java
+++ b/services/core/java/com/android/server/pm/PackageInstallerService.java
@@ -878,9 +878,14 @@
requestedInstallerPackageName = null;
}
+ if (isApex || mContext.checkCallingOrSelfPermission(
+ Manifest.permission.ENFORCE_UPDATE_OWNERSHIP) == PackageManager.PERMISSION_DENIED) {
+ params.installFlags &= ~PackageManager.INSTALL_REQUEST_UPDATE_OWNERSHIP;
+ }
+
InstallSource installSource = InstallSource.create(installerPackageName,
originatingPackageName, requestedInstallerPackageName, requestedInstallerPackageUid,
- installerAttributionTag, params.packageSource);
+ requestedInstallerPackageName, installerAttributionTag, params.packageSource);
session = new PackageInstallerSession(mInternalCallback, mContext, mPm, this,
mSilentUpdatePolicy, mInstallThread.getLooper(), mStagingManager, sessionId,
userId, callingUid, installSource, params, createdMillis, 0L, stageDir, stageCid,
diff --git a/services/core/java/com/android/server/pm/PackageInstallerSession.java b/services/core/java/com/android/server/pm/PackageInstallerSession.java
index 0556c3b..350f5ef 100644
--- a/services/core/java/com/android/server/pm/PackageInstallerSession.java
+++ b/services/core/java/com/android/server/pm/PackageInstallerSession.java
@@ -89,6 +89,7 @@
import android.content.pm.PackageInstaller.PreapprovalDetails;
import android.content.pm.PackageInstaller.SessionInfo;
import android.content.pm.PackageInstaller.SessionParams;
+import android.content.pm.PackageInstaller.UserActionReason;
import android.content.pm.PackageManager;
import android.content.pm.PackageManager.PackageInfoFlags;
import android.content.pm.PackageManagerInternal;
@@ -226,6 +227,7 @@
private static final String ATTR_USER_ID = "userId";
private static final String ATTR_INSTALLER_PACKAGE_NAME = "installerPackageName";
private static final String ATTR_INSTALLER_PACKAGE_UID = "installerPackageUid";
+ private static final String ATTR_UPDATE_OWNER_PACKAGE_NAME = "updateOwnererPackageName";
private static final String ATTR_INSTALLER_ATTRIBUTION_TAG = "installerAttributionTag";
private static final String ATTR_INSTALLER_UID = "installerUid";
private static final String ATTR_INITIATING_PACKAGE_NAME =
@@ -446,6 +448,9 @@
@GuardedBy("mLock")
private boolean mHasDeviceAdminReceiver;
+ @GuardedBy("mLock")
+ private int mUserActionRequirement;
+
static class FileEntry {
private final int mIndex;
private final InstallationFile mFile;
@@ -842,10 +847,17 @@
private static final int USER_ACTION_NOT_NEEDED = 0;
private static final int USER_ACTION_REQUIRED = 1;
private static final int USER_ACTION_PENDING_APK_PARSING = 2;
+ private static final int USER_ACTION_REQUIRED_UPDATE_OWNER_CHANGED = 3;
+ private static final int USER_ACTION_REQUIRED_UPDATE_OWNER_RETAINED = 4;
- @IntDef({USER_ACTION_NOT_NEEDED, USER_ACTION_REQUIRED, USER_ACTION_PENDING_APK_PARSING})
- @interface
- UserActionRequirement {}
+ @IntDef({
+ USER_ACTION_NOT_NEEDED,
+ USER_ACTION_REQUIRED,
+ USER_ACTION_PENDING_APK_PARSING,
+ USER_ACTION_REQUIRED_UPDATE_OWNER_CHANGED,
+ USER_ACTION_REQUIRED_UPDATE_OWNER_RETAINED
+ })
+ @interface UserActionRequirement {}
/**
* Checks if the permissions still need to be confirmed.
@@ -899,8 +911,13 @@
final String existingInstallerPackageName = existingInstallSourceInfo != null
? existingInstallSourceInfo.getInstallingPackageName()
: null;
+ final String existingUpdateOwnerPackageName = existingInstallSourceInfo != null
+ ? existingInstallSourceInfo.getUpdateOwnerPackageName()
+ : null;
final boolean isInstallerOfRecord = isUpdate
&& Objects.equals(existingInstallerPackageName, getInstallerPackageName());
+ final boolean isUpdateOwner = Objects.equals(existingUpdateOwnerPackageName,
+ getInstallerPackageName());
final boolean isSelfUpdate = targetPackageUid == mInstallerUid;
final boolean isPermissionGranted = isInstallPermissionGranted
|| (isUpdatePermissionGranted && isUpdate)
@@ -908,16 +925,35 @@
|| (isInstallDpcPackagesPermissionGranted && hasDeviceAdminReceiver);
final boolean isInstallerRoot = (mInstallerUid == Process.ROOT_UID);
final boolean isInstallerSystem = (mInstallerUid == Process.SYSTEM_UID);
+ final boolean isInstallerShell = (mInstallerUid == Process.SHELL_UID);
+ final boolean isUpdateOwnershipEnforcementEnabled =
+ mPm.isUpdateOwnershipEnforcementAvailable()
+ && existingUpdateOwnerPackageName != null;
- // Device owners and affiliated profile owners are allowed to silently install packages, so
+ // Device owners and affiliated profile owners are allowed to silently install packages, so
// the permission check is waived if the installer is the device owner.
- final boolean noUserActionNecessary = isPermissionGranted || isInstallerRoot
- || isInstallerSystem || isInstallerDeviceOwnerOrAffiliatedProfileOwner();
+ final boolean noUserActionNecessary = isInstallerRoot || isInstallerSystem
+ || isInstallerDeviceOwnerOrAffiliatedProfileOwner();
if (noUserActionNecessary) {
return USER_ACTION_NOT_NEEDED;
}
+ if (isUpdateOwnershipEnforcementEnabled
+ && !isApexSession()
+ && !isUpdateOwner
+ && !isInstallerShell) {
+ final boolean isRequestUpdateOwner =
+ (params.installFlags & PackageManager.INSTALL_REQUEST_UPDATE_OWNERSHIP) != 0;
+
+ return isRequestUpdateOwner ? USER_ACTION_REQUIRED_UPDATE_OWNER_CHANGED
+ : USER_ACTION_REQUIRED_UPDATE_OWNER_RETAINED;
+ }
+
+ if (isPermissionGranted) {
+ return USER_ACTION_NOT_NEEDED;
+ }
+
if (snapshot.isInstallDisabledForPackage(getInstallerPackageName(), mInstallerUid,
userId)) {
// show the installer to account for device policy or unknown sources use cases
@@ -926,13 +962,20 @@
if (params.requireUserAction == SessionParams.USER_ACTION_NOT_REQUIRED
&& isUpdateWithoutUserActionPermissionGranted
- && (isInstallerOfRecord || isSelfUpdate)) {
+ && ((isUpdateOwnershipEnforcementEnabled ? isUpdateOwner
+ : isInstallerOfRecord) || isSelfUpdate)) {
return USER_ACTION_PENDING_APK_PARSING;
}
return USER_ACTION_REQUIRED;
}
+ private void updateUserActionRequirement(int requirement) {
+ synchronized (mLock) {
+ mUserActionRequirement = requirement;
+ }
+ }
+
@SuppressWarnings("GuardedBy" /*mPm.mInstaller is {@code final} field*/)
public PackageInstallerSession(PackageInstallerService.InternalCallback callback,
Context context, PackageManagerService pm,
@@ -1121,6 +1164,7 @@
info.installerUid = mInstallerUid;
info.packageSource = params.packageSource;
info.keepApplicationEnabledSetting = params.keepApplicationEnabledSetting;
+ info.pendingUserActionReason = userActionRequirementToReason(mUserActionRequirement);
}
return info;
}
@@ -1798,6 +1842,60 @@
dispatchSessionSealed();
}
+ @Override
+ public void seal() {
+ assertNotChild("seal");
+ assertCallerIsOwnerOrRoot();
+ try {
+ sealInternal();
+ for (var child : getChildSessions()) {
+ child.sealInternal();
+ }
+ } catch (PackageManagerException e) {
+ throw new IllegalStateException("Package is not valid", e);
+ }
+ }
+
+ private void sealInternal() throws PackageManagerException {
+ synchronized (mLock) {
+ sealLocked();
+ }
+ }
+
+ @Override
+ public List<String> fetchPackageNames() {
+ assertNotChild("fetchPackageNames");
+ assertCallerIsOwnerOrRoot();
+ var sessions = getSelfOrChildSessions();
+ var result = new ArrayList<String>(sessions.size());
+ for (var s : sessions) {
+ result.add(s.fetchPackageName());
+ }
+ return result;
+ }
+
+ private String fetchPackageName() {
+ assertSealed("fetchPackageName");
+ synchronized (mLock) {
+ final ParseTypeImpl input = ParseTypeImpl.forDefaultParsing();
+ final List<File> addedFiles = getAddedApksLocked();
+ for (File addedFile : addedFiles) {
+ final ParseResult<ApkLite> result =
+ ApkLiteParseUtils.parseApkLite(input.reset(), addedFile, 0);
+ if (result.isError()) {
+ throw new IllegalStateException(
+ "Can't parse package for session=" + sessionId, result.getException());
+ }
+ final ApkLite apk = result.getResult();
+ var packageName = apk.getPackageName();
+ if (packageName != null) {
+ return packageName;
+ }
+ }
+ throw new IllegalStateException("Can't fetch package name for session=" + sessionId);
+ }
+ }
+
/**
* Kicks off the install flow. The first step is to persist 'sealed' flags
* to prevent mutations of hard links created later.
@@ -2051,6 +2149,11 @@
}
}
+ @NonNull
+ private List<PackageInstallerSession> getSelfOrChildSessions() {
+ return isMultiPackage() ? getChildSessions() : Collections.singletonList(this);
+ }
+
/**
* Seal the session to prevent further modification.
*
@@ -2205,8 +2308,9 @@
}
mInstallerUid = newOwnerAppInfo.uid;
- mInstallSource = InstallSource.create(packageName, null, packageName,
- mInstallerUid, null, params.packageSource);
+ mInstallSource = InstallSource.create(packageName, null /* originatingPackageName */,
+ packageName, mInstallerUid, packageName, null /* installerAttributionTag */,
+ params.packageSource);
}
}
@@ -2220,7 +2324,10 @@
@UserActionRequirement int userActionRequirement = USER_ACTION_NOT_NEEDED;
// TODO(b/159331446): Move this to makeSessionActiveForInstall and update javadoc
userActionRequirement = session.computeUserActionRequirement();
- if (userActionRequirement == USER_ACTION_REQUIRED) {
+ session.updateUserActionRequirement(userActionRequirement);
+ if (userActionRequirement == USER_ACTION_REQUIRED
+ || userActionRequirement == USER_ACTION_REQUIRED_UPDATE_OWNER_CHANGED
+ || userActionRequirement == USER_ACTION_REQUIRED_UPDATE_OWNER_RETAINED) {
session.sendPendingUserActionIntent(target);
return true;
}
@@ -2253,6 +2360,18 @@
return false;
}
+ private static @UserActionReason int userActionRequirementToReason(
+ @UserActionRequirement int requirement) {
+ switch (requirement) {
+ case USER_ACTION_REQUIRED_UPDATE_OWNER_CHANGED:
+ return PackageInstaller.REASON_OWNERSHIP_CHANGED;
+ case USER_ACTION_REQUIRED_UPDATE_OWNER_RETAINED:
+ return PackageInstaller.REASON_REMIND_OWNERSHIP;
+ default:
+ return PackageInstaller.REASON_CONFIRM_PACKAGE_CHANGE;
+ }
+ }
+
/**
* Find out any session needs user action.
*
@@ -4438,6 +4557,11 @@
return params.keepApplicationEnabledSetting;
}
+ @Override
+ public boolean isRequestUpdateOwnership() {
+ return (params.installFlags & PackageManager.INSTALL_REQUEST_UPDATE_OWNERSHIP) != 0;
+ }
+
void setSessionReady() {
synchronized (mLock) {
// Do not allow destroyed/failed session to change state
@@ -4774,6 +4898,8 @@
writeStringAttribute(out, ATTR_INSTALLER_PACKAGE_NAME,
mInstallSource.mInstallerPackageName);
out.attributeInt(null, ATTR_INSTALLER_PACKAGE_UID, mInstallSource.mInstallerPackageUid);
+ writeStringAttribute(out, ATTR_UPDATE_OWNER_PACKAGE_NAME,
+ mInstallSource.mUpdateOwnerPackageName);
writeStringAttribute(out, ATTR_INSTALLER_ATTRIBUTION_TAG,
mInstallSource.mInstallerAttributionTag);
out.attributeInt(null, ATTR_INSTALLER_UID, mInstallerUid);
@@ -4941,6 +5067,8 @@
final String installerPackageName = readStringAttribute(in, ATTR_INSTALLER_PACKAGE_NAME);
final int installPackageUid = in.getAttributeInt(null, ATTR_INSTALLER_PACKAGE_UID,
INVALID_UID);
+ final String updateOwnerPackageName = readStringAttribute(in,
+ ATTR_UPDATE_OWNER_PACKAGE_NAME);
final String installerAttributionTag = readStringAttribute(in,
ATTR_INSTALLER_ATTRIBUTION_TAG);
final int installerUid = in.getAttributeInt(null, ATTR_INSTALLER_UID, pm.snapshotComputer()
@@ -5113,7 +5241,7 @@
InstallSource installSource = InstallSource.create(installInitiatingPackageName,
installOriginatingPackageName, installerPackageName, installPackageUid,
- installerAttributionTag, params.packageSource);
+ updateOwnerPackageName, installerAttributionTag, params.packageSource);
return new PackageInstallerSession(callback, context, pm, sessionProvider,
silentUpdatePolicy, installerThread, stagingManager, sessionId, userId,
installerUid, installSource, params, createdMillis, committedMillis, stageDir,
diff --git a/services/core/java/com/android/server/pm/PackageManagerInternalBase.java b/services/core/java/com/android/server/pm/PackageManagerInternalBase.java
index 04f5e56..99fff72 100644
--- a/services/core/java/com/android/server/pm/PackageManagerInternalBase.java
+++ b/services/core/java/com/android/server/pm/PackageManagerInternalBase.java
@@ -49,7 +49,6 @@
import com.android.server.pm.Installer.LegacyDexoptDisabledException;
import com.android.server.pm.dex.DexManager;
-import com.android.server.pm.dex.DynamicCodeLogger;
import com.android.server.pm.permission.PermissionManagerServiceInternal;
import com.android.server.pm.pkg.AndroidPackage;
import com.android.server.pm.pkg.PackageStateInternal;
@@ -773,10 +772,4 @@
public final void shutdown() {
mService.shutdown();
}
-
- @Override
- @Deprecated
- public final DynamicCodeLogger getDynamicCodeLogger() {
- return getDexManager().getDynamicCodeLogger();
- }
}
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index 399e32a..92bbb7e 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -204,6 +204,7 @@
import com.android.server.pm.dex.ArtManagerService;
import com.android.server.pm.dex.ArtUtils;
import com.android.server.pm.dex.DexManager;
+import com.android.server.pm.dex.DynamicCodeLogger;
import com.android.server.pm.dex.ViewCompiler;
import com.android.server.pm.local.PackageManagerLocalImpl;
import com.android.server.pm.parsing.PackageInfoUtils;
@@ -793,6 +794,7 @@
// DexManager handles the usage of dex files (e.g. secondary files, whether or not a package
// is used by other apps).
private final DexManager mDexManager;
+ private final DynamicCodeLogger mDynamicCodeLogger;
final ViewCompiler mViewCompiler;
@@ -1529,7 +1531,8 @@
(i, pm) -> new PackageDexOptimizer(i.getInstaller(), i.getInstallLock(),
i.getContext(), "*dexopt*"),
(i, pm) -> new DexManager(i.getContext(), i.getPackageDexOptimizer(),
- i.getInstaller(), i.getInstallLock()),
+ i.getInstaller(), i.getInstallLock(), i.getDynamicCodeLogger()),
+ (i, pm) -> new DynamicCodeLogger(i.getInstaller()),
(i, pm) -> new ArtManagerService(i.getContext(), i.getInstaller(),
i.getInstallLock()),
(i, pm) -> ApexManager.getInstance(),
@@ -1711,6 +1714,7 @@
mDefaultAppProvider = testParams.defaultAppProvider;
mLegacyPermissionManager = testParams.legacyPermissionManagerInternal;
mDexManager = testParams.dexManager;
+ mDynamicCodeLogger = testParams.dynamicCodeLogger;
mFactoryTest = testParams.factoryTest;
mIncrementalManager = testParams.incrementalManager;
mInstallerService = testParams.installerService;
@@ -1889,6 +1893,7 @@
mPackageDexOptimizer = injector.getPackageDexOptimizer();
mDexManager = injector.getDexManager();
+ mDynamicCodeLogger = injector.getDynamicCodeLogger();
mBackgroundDexOptService = injector.getBackgroundDexOptService();
mArtManagerService = injector.getArtManagerService();
mMoveCallbacks = new MovePackageHelper.MoveCallbacks(FgThread.get().getLooper());
@@ -2316,6 +2321,7 @@
.getList());
}
mDexManager.load(userPackages);
+ mDynamicCodeLogger.load(userPackages);
if (mIsUpgrade) {
FrameworkStatsLog.write(
FrameworkStatsLog.BOOT_TIME_EVENT_DURATION_REPORTED,
@@ -2980,9 +2986,14 @@
return mDexManager;
}
+ /*package*/ DynamicCodeLogger getDynamicCodeLogger() {
+ return mDynamicCodeLogger;
+ }
+
public void shutdown() {
mCompilerStats.writeNow();
mDexManager.writePackageDexUsageNow();
+ mDynamicCodeLogger.writeNow();
PackageWatchdog.getInstance(mContext).writeNow();
synchronized (mLock) {
@@ -4285,6 +4296,11 @@
// Prune unused static shared libraries which have been cached a period of time
schedulePruneUnusedStaticSharedLibraries(false /* delay */);
+
+ DexUseManagerLocal dexUseManager = DexOptHelper.getDexUseManagerLocal();
+ if (dexUseManager != null) {
+ dexUseManager.systemReady();
+ }
}
//TODO: b/111402650
@@ -6008,6 +6024,42 @@
}
@Override
+ public void relinquishUpdateOwnership(String targetPackage) {
+ final int callingUid = Binder.getCallingUid();
+ final int callingUserId = UserHandle.getUserId(callingUid);
+ final Computer snapshot = snapshotComputer();
+
+ final PackageStateInternal targetPackageState =
+ snapshot.getPackageStateForInstalledAndFiltered(targetPackage, callingUid,
+ callingUserId);
+ if (targetPackageState == null) {
+ throw new IllegalArgumentException("Unknown target package: " + targetPackage);
+ }
+
+ final String targetUpdateOwnerPackageName =
+ targetPackageState.getInstallSource().mUpdateOwnerPackageName;
+ final PackageStateInternal targetUpdateOwnerPkgSetting =
+ targetUpdateOwnerPackageName == null ? null
+ : snapshot.getPackageStateInternal(targetUpdateOwnerPackageName);
+
+ if (targetUpdateOwnerPkgSetting == null) {
+ return;
+ }
+
+ final int callingAppId = UserHandle.getAppId(callingUid);
+ final int targetUpdateOwnerAppId = targetUpdateOwnerPkgSetting.getAppId();
+ if (callingAppId != Process.SYSTEM_UID
+ && callingAppId != Process.SHELL_UID
+ && callingAppId != targetUpdateOwnerAppId) {
+ throw new SecurityException("Caller is not the current update owner.");
+ }
+
+ commitPackageStateMutation(null /* initialState */, targetPackage,
+ state -> state.setUpdateOwner(null /* updateOwnerPackageName */));
+ scheduleWriteSettings();
+ }
+
+ @Override
public boolean setInstantAppCookie(String packageName, byte[] cookie, int userId) {
if (HIDE_EPHEMERAL_APIS) {
return true;
@@ -6341,6 +6393,12 @@
return mDexManager;
}
+ @NonNull
+ @Override
+ public DynamicCodeLogger getDynamicCodeLogger() {
+ return mDynamicCodeLogger;
+ }
+
@Override
public boolean isPlatformSigned(String packageName) {
PackageStateInternal packageState = snapshot().getPackageStateInternal(packageName);
diff --git a/services/core/java/com/android/server/pm/PackageManagerServiceInjector.java b/services/core/java/com/android/server/pm/PackageManagerServiceInjector.java
index 76e6e45f..eb033cb 100644
--- a/services/core/java/com/android/server/pm/PackageManagerServiceInjector.java
+++ b/services/core/java/com/android/server/pm/PackageManagerServiceInjector.java
@@ -30,6 +30,7 @@
import com.android.server.compat.PlatformCompat;
import com.android.server.pm.dex.ArtManagerService;
import com.android.server.pm.dex.DexManager;
+import com.android.server.pm.dex.DynamicCodeLogger;
import com.android.server.pm.dex.ViewCompiler;
import com.android.server.pm.parsing.PackageParser2;
import com.android.server.pm.permission.LegacyPermissionManagerInternal;
@@ -106,6 +107,7 @@
private final Singleton<PackageDexOptimizer>
mPackageDexOptimizerProducer;
private final Singleton<DexManager> mDexManagerProducer;
+ private final Singleton<DynamicCodeLogger> mDynamicCodeLoggerProducer;
private final Singleton<ArtManagerService>
mArtManagerServiceProducer;
private final Singleton<ApexManager> mApexManagerProducer;
@@ -154,6 +156,7 @@
Producer<SystemConfig> systemConfigProducer,
Producer<PackageDexOptimizer> packageDexOptimizerProducer,
Producer<DexManager> dexManagerProducer,
+ Producer<DynamicCodeLogger> dynamicCodeLoggerProducer,
Producer<ArtManagerService> artManagerServiceProducer,
Producer<ApexManager> apexManagerProducer,
Producer<ViewCompiler> viewCompilerProducer,
@@ -200,6 +203,7 @@
mPackageDexOptimizerProducer = new Singleton<>(
packageDexOptimizerProducer);
mDexManagerProducer = new Singleton<>(dexManagerProducer);
+ mDynamicCodeLoggerProducer = new Singleton<>(dynamicCodeLoggerProducer);
mArtManagerServiceProducer = new Singleton<>(
artManagerServiceProducer);
mApexManagerProducer = new Singleton<>(apexManagerProducer);
@@ -314,6 +318,10 @@
return mDexManagerProducer.get(this, mPackageManager);
}
+ public DynamicCodeLogger getDynamicCodeLogger() {
+ return mDynamicCodeLoggerProducer.get(this, mPackageManager);
+ }
+
public ArtManagerService getArtManagerService() {
return mArtManagerServiceProducer.get(this, mPackageManager);
}
diff --git a/services/core/java/com/android/server/pm/PackageManagerServiceTestParams.java b/services/core/java/com/android/server/pm/PackageManagerServiceTestParams.java
index bffbb84..0c617ae 100644
--- a/services/core/java/com/android/server/pm/PackageManagerServiceTestParams.java
+++ b/services/core/java/com/android/server/pm/PackageManagerServiceTestParams.java
@@ -32,6 +32,7 @@
import com.android.internal.content.om.OverlayConfig;
import com.android.server.pm.dex.ArtManagerService;
import com.android.server.pm.dex.DexManager;
+import com.android.server.pm.dex.DynamicCodeLogger;
import com.android.server.pm.dex.ViewCompiler;
import com.android.server.pm.parsing.PackageParser2;
import com.android.server.pm.permission.LegacyPermissionManagerInternal;
@@ -49,6 +50,7 @@
public int defParseFlags;
public DefaultAppProvider defaultAppProvider;
public DexManager dexManager;
+ public DynamicCodeLogger dynamicCodeLogger;
public List<ScanPartition> dirsToScanAsSystem;
public boolean factoryTest;
public ArrayMap<String, FeatureInfo> availableFeatures;
diff --git a/services/core/java/com/android/server/pm/PackageManagerServiceUtils.java b/services/core/java/com/android/server/pm/PackageManagerServiceUtils.java
index a72ae56..0de1a4e 100644
--- a/services/core/java/com/android/server/pm/PackageManagerServiceUtils.java
+++ b/services/core/java/com/android/server/pm/PackageManagerServiceUtils.java
@@ -33,6 +33,7 @@
import static com.android.server.pm.PackageManagerService.STUB_SUFFIX;
import static com.android.server.pm.PackageManagerService.TAG;
+import android.annotation.IntDef;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.UserIdInt;
@@ -113,6 +114,8 @@
import java.io.IOException;
import java.io.InputStream;
import java.io.PrintWriter;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
import java.nio.file.Path;
import java.security.SecureRandom;
import java.security.cert.CertificateEncodingException;
@@ -148,6 +151,29 @@
ThreadLocal.withInitial(() -> false);
/**
+ * Type used with {@link #canJoinSharedUserId(String, SigningDetails, SharedUserSetting, int)}
+ * when the package attempting to join the sharedUserId is a new install.
+ */
+ public static final int SHARED_USER_ID_JOIN_TYPE_INSTALL = 0;
+ /**
+ * Type used with {@link #canJoinSharedUserId(String, SigningDetails, SharedUserSetting, int)}
+ * when the package attempting to join the sharedUserId is an update.
+ */
+ public static final int SHARED_USER_ID_JOIN_TYPE_UPDATE = 1;
+ /**
+ * Type used with {@link #canJoinSharedUserId(String, SigningDetails, SharedUserSetting, int)}
+ * when the package attempting to join the sharedUserId is a part of the system image.
+ */
+ public static final int SHARED_USER_ID_JOIN_TYPE_SYSTEM = 2;
+ @IntDef(prefix = { "TYPE_" }, value = {
+ SHARED_USER_ID_JOIN_TYPE_INSTALL,
+ SHARED_USER_ID_JOIN_TYPE_UPDATE,
+ SHARED_USER_ID_JOIN_TYPE_SYSTEM,
+ })
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface SharedUserIdJoinType {}
+
+ /**
* Components of apps targeting Android T and above will stop receiving intents from
* external callers that do not match its declared intent filters.
*
@@ -575,17 +601,9 @@
// the older ones. We check to see if either the new package is signed by an older cert
// with which the current sharedUser is ok, or if it is signed by a newer one, and is ok
// with being sharedUser with the existing signing cert.
- boolean match = canJoinSharedUserId(parsedSignatures,
- sharedUserSetting.getSigningDetails());
- // Special case: if the sharedUserId capability check failed it could be due to this
- // being the only package in the sharedUserId so far and the lineage being updated to
- // deny the sharedUserId capability of the previous key in the lineage.
- final ArraySet<PackageStateInternal> susPackageStates =
- (ArraySet<PackageStateInternal>) sharedUserSetting.getPackageStates();
- if (!match && susPackageStates.size() == 1
- && susPackageStates.valueAt(0).getPackageName().equals(packageName)) {
- match = true;
- }
+ boolean match = canJoinSharedUserId(packageName, parsedSignatures, sharedUserSetting,
+ pkgSetting.getSigningDetails().getSignatures() != null
+ ? SHARED_USER_ID_JOIN_TYPE_UPDATE : SHARED_USER_ID_JOIN_TYPE_INSTALL);
if (!match && compareCompat) {
match = matchSignaturesCompat(
packageName, sharedUserSetting.signatures, parsedSignatures);
@@ -608,36 +626,6 @@
+ " has no signatures that match those in shared user "
+ sharedUserSetting.name + "; ignoring!");
}
- // It is possible that this package contains a lineage that blocks sharedUserId access
- // to an already installed package in the sharedUserId signed with a previous key.
- // Iterate over all of the packages in the sharedUserId and ensure any that are signed
- // with a key in this package's lineage have the SHARED_USER_ID capability granted.
- if (parsedSignatures.hasPastSigningCertificates()) {
- for (int i = 0; i < susPackageStates.size(); i++) {
- PackageStateInternal shUidPkgSetting = susPackageStates.valueAt(i);
- // if the current package in the sharedUserId is the package being updated then
- // skip this check as the update may revoke the sharedUserId capability from
- // the key with which this app was previously signed.
- if (packageName.equals(shUidPkgSetting.getPackageName())) {
- continue;
- }
- SigningDetails shUidSigningDetails =
- shUidPkgSetting.getSigningDetails();
- // The capability check only needs to be performed against the package if it is
- // signed with a key that is in the lineage of the package being installed.
- if (parsedSignatures.hasAncestor(shUidSigningDetails)) {
- if (!parsedSignatures.checkCapability(shUidSigningDetails,
- SigningDetails.CertCapabilities.SHARED_USER_ID)) {
- throw new PackageManagerException(
- INSTALL_FAILED_SHARED_USER_INCOMPATIBLE,
- "Package " + packageName
- + " revoked the sharedUserId capability from the"
- + " signing key used to sign "
- + shUidPkgSetting.getPackageName());
- }
- }
- }
- }
// If the lineage of this package diverges from the lineage of the sharedUserId then
// do not allow the installation to proceed.
if (!parsedSignatures.hasCommonAncestor(
@@ -651,25 +639,97 @@
}
/**
- * Returns whether the package with {@code packageSigningDetails} can join the sharedUserId
- * with {@code sharedUserSigningDetails}.
+ * Returns whether the package {@code packageName} can join the sharedUserId based on the
+ * settings in {@code sharedUserSetting}.
* <p>
* A sharedUserId maintains a shared {@link SigningDetails} containing the full lineage and
* capabilities for each package in the sharedUserId. A package can join the sharedUserId if
* its current signer is the same as the shared signer, or if the current signer of either
* is in the signing lineage of the other with the {@link
* SigningDetails.CertCapabilities#SHARED_USER_ID} capability granted to that previous signer
- * in the lineage.
+ * in the lineage. In the case of a key compromise, an app signed with a lineage revoking
+ * this capability from a previous signing key can still join the sharedUserId with another
+ * app signed with this previous key if the joining app is being updated; however, a new
+ * install will not be allowed until all apps have rotated off the key with the capability
+ * revoked.
*
+ * @param packageName the name of the package seeking to join the sharedUserId
* @param packageSigningDetails the {@code SigningDetails} of the package seeking to join the
- * sharedUserId
- * @param sharedUserSigningDetails the {@code SigningDetails} of the sharedUserId
+ * sharedUserId
+ * @param sharedUserSetting the {@code SharedUserSetting} for the sharedUserId {@code
+ * packageName} is seeking to join
+ * @param joinType the type of join (install, update, system, etc)
* @return true if the package seeking to join the sharedUserId meets the requirements
*/
- public static boolean canJoinSharedUserId(@NonNull SigningDetails packageSigningDetails,
- @NonNull SigningDetails sharedUserSigningDetails) {
- return packageSigningDetails.checkCapability(sharedUserSigningDetails, SHARED_USER_ID)
- || sharedUserSigningDetails.checkCapability(packageSigningDetails, SHARED_USER_ID);
+ public static boolean canJoinSharedUserId(@NonNull String packageName,
+ @NonNull SigningDetails packageSigningDetails,
+ @NonNull SharedUserSetting sharedUserSetting, @SharedUserIdJoinType int joinType) {
+ SigningDetails sharedUserSigningDetails = sharedUserSetting.getSigningDetails();
+ boolean capabilityGranted =
+ packageSigningDetails.checkCapability(sharedUserSigningDetails, SHARED_USER_ID)
+ || sharedUserSigningDetails.checkCapability(packageSigningDetails,
+ SHARED_USER_ID);
+
+ // If the current signer for either the package or the sharedUserId is the current signer
+ // of the other or in the lineage of the other with the SHARED_USER_ID capability granted,
+ // then a system and update join type can proceed; an install join type is not allowed here
+ // since the sharedUserId may contain packages that are signed with a key untrusted by
+ // the new package.
+ if (capabilityGranted && joinType != SHARED_USER_ID_JOIN_TYPE_INSTALL) {
+ return true;
+ }
+
+ // If the package is signed with a key that is no longer trusted by the sharedUserId, then
+ // the join should not be allowed unless this is a system join type; system packages can
+ // join the sharedUserId as long as they share a common lineage.
+ if (!capabilityGranted && sharedUserSigningDetails.hasAncestor(packageSigningDetails)) {
+ if (joinType == SHARED_USER_ID_JOIN_TYPE_SYSTEM) {
+ return true;
+ }
+ return false;
+ }
+
+ // If the package is signed with a rotated key that no longer trusts the sharedUserId key,
+ // then allow system and update join types to rotate away from an untrusted key; install
+ // join types are not allowed since a new package that doesn't trust a previous key
+ // shouldn't be allowed to join until all packages in the sharedUserId have rotated off the
+ // untrusted key.
+ if (!capabilityGranted && packageSigningDetails.hasAncestor(sharedUserSigningDetails)) {
+ if (joinType != SHARED_USER_ID_JOIN_TYPE_INSTALL) {
+ return true;
+ }
+ return false;
+ }
+
+ // If the capability is not granted and the package signatures are not an ancestor
+ // or descendant of the sharedUserId signatures, then do not allow any join type to join
+ // the sharedUserId since there are no common signatures.
+ if (!capabilityGranted) {
+ return false;
+ }
+
+ // At this point this is a new install with the capability granted; ensure the current
+ // packages in the sharedUserId are all signed by a key trusted by the new package.
+ final ArraySet<PackageStateInternal> susPackageStates =
+ (ArraySet<PackageStateInternal>) sharedUserSetting.getPackageStates();
+ if (packageSigningDetails.hasPastSigningCertificates()) {
+ for (PackageStateInternal shUidPkgSetting : susPackageStates) {
+ SigningDetails shUidSigningDetails = shUidPkgSetting.getSigningDetails();
+ // The capability check only needs to be performed against the package if it is
+ // signed with a key that is in the lineage of the package being installed.
+ if (packageSigningDetails.hasAncestor(shUidSigningDetails)) {
+ if (!packageSigningDetails.checkCapability(shUidSigningDetails,
+ SigningDetails.CertCapabilities.SHARED_USER_ID)) {
+ Slog.d(TAG, "Package " + packageName
+ + " revoked the sharedUserId capability from the"
+ + " signing key used to sign "
+ + shUidPkgSetting.getPackageName());
+ return false;
+ }
+ }
+ }
+ }
+ return true;
}
/**
diff --git a/services/core/java/com/android/server/pm/PackageManagerShellCommand.java b/services/core/java/com/android/server/pm/PackageManagerShellCommand.java
index 6af1d0f..849cbeb 100644
--- a/services/core/java/com/android/server/pm/PackageManagerShellCommand.java
+++ b/services/core/java/com/android/server/pm/PackageManagerShellCommand.java
@@ -172,6 +172,11 @@
SUPPORTED_PERMISSION_FLAGS.put("revoke-when-requested",
FLAG_PERMISSION_REVOKE_WHEN_REQUESTED);
}
+ // For backward compatibility. DO NOT add new commands here. New ART Service commands should be
+ // added under the "art" namespace.
+ private static final Set<String> ART_SERVICE_COMMANDS = Set.of("compile",
+ "reconcile-secondary-dex-files", "force-dex-opt", "bg-dexopt-job",
+ "cancel-bg-dexopt-job", "delete-dexopt", "dump-profiles", "snapshot-profile", "art");
final IPackageManager mInterface;
final LegacyPermissionManagerInternal mLegacyPermissionManager;
@@ -250,22 +255,6 @@
return runMovePackage();
case "move-primary-storage":
return runMovePrimaryStorage();
- case "compile":
- return runCompile();
- case "reconcile-secondary-dex-files":
- return runreconcileSecondaryDexFiles();
- case "force-dex-opt":
- return runForceDexOpt();
- case "bg-dexopt-job":
- return runBgDexOpt();
- case "cancel-bg-dexopt-job":
- return cancelBgDexOptJob();
- case "delete-dexopt":
- return runDeleteDexOpt();
- case "dump-profiles":
- return runDumpProfiles();
- case "snapshot-profile":
- return runSnapshotProfile();
case "uninstall":
return runUninstall();
case "clear":
@@ -355,9 +344,19 @@
return runBypassAllowedApexUpdateCheck();
case "set-silent-updates-policy":
return runSetSilentUpdatesPolicy();
- case "art":
- return runArtSubCommand();
default: {
+ if (ART_SERVICE_COMMANDS.contains(cmd)) {
+ if (DexOptHelper.useArtService()) {
+ return runArtServiceCommand();
+ } else {
+ try {
+ return runLegacyDexoptCommand(cmd);
+ } catch (LegacyDexoptDisabledException e) {
+ throw new RuntimeException(e);
+ }
+ }
+ }
+
Boolean domainVerificationResult =
mDomainVerificationShell.runCommand(this, cmd);
if (domainVerificationResult != null) {
@@ -381,12 +380,39 @@
}
} catch (RemoteException e) {
pw.println("Remote exception: " + e);
- } catch (ManagerNotFoundException e) {
- pw.println(e);
}
return -1;
}
+ private int runLegacyDexoptCommand(@NonNull String cmd)
+ throws RemoteException, LegacyDexoptDisabledException {
+ Installer.checkLegacyDexoptDisabled();
+ switch (cmd) {
+ case "compile":
+ return runCompile();
+ case "reconcile-secondary-dex-files":
+ return runreconcileSecondaryDexFiles();
+ case "force-dex-opt":
+ return runForceDexOpt();
+ case "bg-dexopt-job":
+ return runBgDexOpt();
+ case "cancel-bg-dexopt-job":
+ return cancelBgDexOptJob();
+ case "delete-dexopt":
+ return runDeleteDexOpt();
+ case "dump-profiles":
+ return runDumpProfiles();
+ case "snapshot-profile":
+ return runSnapshotProfile();
+ case "art":
+ getOutPrintWriter().println("ART Service not enabled");
+ return -1;
+ default:
+ // Can't happen.
+ throw new IllegalArgumentException();
+ }
+ }
+
/**
* Shows module info
*
@@ -3023,6 +3049,10 @@
case UserManager.REMOVE_RESULT_ALREADY_BEING_REMOVED:
getOutPrintWriter().printf("Success: user %d is already being removed\n", userId);
return 0;
+ case UserManager.REMOVE_RESULT_ERROR_MAIN_USER_PERMANENT_ADMIN:
+ getOutPrintWriter().printf("Error: user %d is a permanent admin main user\n",
+ userId);
+ return 1;
default:
getErrPrintWriter().printf("Error: couldn't remove or mark ephemeral user id %d\n",
userId);
@@ -3207,6 +3237,15 @@
case "--install-reason":
sessionParams.installReason = Integer.parseInt(getNextArg());
break;
+ case "--update-ownership":
+ if (params.installerPackageName == null) {
+ // Enabling update ownership enforcement needs an installer. Since the
+ // default installer is null when using adb install, that effectively
+ // disable this enforcement.
+ params.installerPackageName = "com.android.shell";
+ }
+ sessionParams.installFlags |= PackageManager.INSTALL_REQUEST_UPDATE_OWNERSHIP;
+ break;
case "--force-uuid":
sessionParams.installFlags |= PackageManager.INSTALL_FORCE_VOLUME_UUID;
sessionParams.volumeUuid = getNextArg();
@@ -3254,6 +3293,10 @@
case "--skip-enable":
sessionParams.setKeepApplicationEnabledSetting();
break;
+ case "--bypass-low-target-sdk-block":
+ sessionParams.installFlags |=
+ PackageManager.INSTALL_BYPASS_LOW_TARGET_SDK_BLOCK;
+ break;
default:
throw new IllegalArgumentException("Unknown option " + opt);
}
@@ -3475,17 +3518,18 @@
return 1;
}
- private int runArtSubCommand() throws ManagerNotFoundException {
- // Remove the first arg "art" and forward to ART module.
- String[] args = getAllArgs();
- args = Arrays.copyOfRange(args, 1, args.length);
+ private int runArtServiceCommand() {
try (var in = ParcelFileDescriptor.dup(getInFileDescriptor());
var out = ParcelFileDescriptor.dup(getOutFileDescriptor());
var err = ParcelFileDescriptor.dup(getErrFileDescriptor())) {
return LocalManagerRegistry.getManagerOrThrow(ArtManagerLocal.class)
- .handleShellCommand(getTarget(), in, out, err, args);
+ .handleShellCommand(getTarget(), in, out, err, getAllArgs());
} catch (IOException e) {
throw new IllegalStateException(e);
+ } catch (ManagerNotFoundException e) {
+ PrintWriter epw = getErrPrintWriter();
+ epw.println("ART Service is not ready. Please try again later");
+ return -1;
}
}
@@ -4091,6 +4135,7 @@
pw.println(" --install-reason: indicates why the app is being installed:");
pw.println(" 0=unknown, 1=admin policy, 2=device restore,");
pw.println(" 3=device setup, 4=user request");
+ pw.println(" --update-ownership: request the update ownership enforcement");
pw.println(" --force-uuid: force install on to disk volume with given UUID");
pw.println(" --apex: install an .apex file, not an .apk");
pw.println(" --staged-ready-timeout: By default, staged sessions wait "
@@ -4114,7 +4159,7 @@
pw.println(" [--referrer URI] [--abi ABI_NAME] [--force-sdk]");
pw.println(" [--preload] [--instant] [--full] [--dont-kill]");
pw.println(" [--force-uuid internal|UUID] [--pkg PACKAGE] [--apex] [-S BYTES]");
- pw.println(" [--multi-package] [--staged]");
+ pw.println(" [--multi-package] [--staged] [--update-ownership]");
pw.println(" Like \"install\", but starts an install session. Use \"install-write\"");
pw.println(" to push data into the session, and \"install-commit\" to finish.");
pw.println("");
@@ -4253,6 +4298,76 @@
pw.println("");
pw.println(" get-max-running-users");
pw.println("");
+ pw.println(" set-home-activity [--user USER_ID] TARGET-COMPONENT");
+ pw.println(" Set the default home activity (aka launcher).");
+ pw.println(" TARGET-COMPONENT can be a package name (com.package.my) or a full");
+ pw.println(" component (com.package.my/component.name). However, only the package name");
+ pw.println(" matters: the actual component used will be determined automatically from");
+ pw.println(" the package.");
+ pw.println("");
+ pw.println(" set-installer PACKAGE INSTALLER");
+ pw.println(" Set installer package name");
+ pw.println("");
+ pw.println(" get-instantapp-resolver");
+ pw.println(
+ " Return the name of the component that is the current instant app installer.");
+ pw.println("");
+ pw.println(" set-harmful-app-warning [--user <USER_ID>] <PACKAGE> [<WARNING>]");
+ pw.println(" Mark the app as harmful with the given warning message.");
+ pw.println("");
+ pw.println(" get-harmful-app-warning [--user <USER_ID>] <PACKAGE>");
+ pw.println(" Return the harmful app warning message for the given app, if present");
+ pw.println();
+ pw.println(" uninstall-system-updates [<PACKAGE>]");
+ pw.println(" Removes updates to the given system application and falls back to its");
+ pw.println(" /system version. Does nothing if the given package is not a system app.");
+ pw.println(" If no package is specified, removes updates to all system applications.");
+ pw.println("");
+ pw.println(" get-moduleinfo [--all | --installed] [module-name]");
+ pw.println(" Displays module info. If module-name is specified only that info is shown");
+ pw.println(" By default, without any argument only installed modules are shown.");
+ pw.println(" --all: show all module info");
+ pw.println(" --installed: show only installed modules");
+ pw.println("");
+ pw.println(" log-visibility [--enable|--disable] <PACKAGE>");
+ pw.println(" Turns on debug logging when visibility is blocked for the given package.");
+ pw.println(" --enable: turn on debug logging (default)");
+ pw.println(" --disable: turn off debug logging");
+ pw.println("");
+ pw.println(" set-silent-updates-policy [--allow-unlimited-silent-updates <INSTALLER>]");
+ pw.println(" [--throttle-time <SECONDS>] [--reset]");
+ pw.println(" Sets the policies of the silent updates.");
+ pw.println(" --allow-unlimited-silent-updates: allows unlimited silent updated");
+ pw.println(" installation requests from the installer without the throttle time.");
+ pw.println(" --throttle-time: update the silent updates throttle time in seconds.");
+ pw.println(" --reset: restore the installer and throttle time to the default, and");
+ pw.println(" clear tracks of silent updates in the system.");
+ pw.println("");
+ if (DexOptHelper.useArtService()) {
+ printArtServiceHelp();
+ } else {
+ printLegacyDexoptHelp();
+ }
+ pw.println("");
+ mDomainVerificationShell.printHelp(pw);
+ pw.println("");
+ Intent.printIntentArgsHelp(pw, "");
+ }
+
+ private void printArtServiceHelp() {
+ final var ipw = new IndentingPrintWriter(getOutPrintWriter(), " " /* singleIndent */);
+ ipw.increaseIndent();
+ try {
+ LocalManagerRegistry.getManagerOrThrow(ArtManagerLocal.class)
+ .printShellCommandHelp(ipw);
+ } catch (ManagerNotFoundException e) {
+ ipw.println("ART Service is not ready. Please try again later");
+ }
+ ipw.decreaseIndent();
+ }
+
+ private void printLegacyDexoptHelp() {
+ final PrintWriter pw = getOutPrintWriter();
pw.println(" compile [-m MODE | -r REASON] [-f] [-c] [--split SPLIT_NAME]");
pw.println(" [--reset] [--check-prof (true | false)] (-a | TARGET-PACKAGE)");
pw.println(" Trigger compilation of TARGET-PACKAGE or all packages if \"-a\". Options are:");
@@ -4325,57 +4440,6 @@
pw.println(" " + ART_PROFILE_SNAPSHOT_DEBUG_LOCATION
+ "TARGET-PACKAGE[-code-path].prof");
pw.println(" If TARGET-PACKAGE=android it will take a snapshot of the boot image");
- pw.println("");
- pw.println(" set-home-activity [--user USER_ID] TARGET-COMPONENT");
- pw.println(" Set the default home activity (aka launcher).");
- pw.println(" TARGET-COMPONENT can be a package name (com.package.my) or a full");
- pw.println(" component (com.package.my/component.name). However, only the package name");
- pw.println(" matters: the actual component used will be determined automatically from");
- pw.println(" the package.");
- pw.println("");
- pw.println(" set-installer PACKAGE INSTALLER");
- pw.println(" Set installer package name");
- pw.println("");
- pw.println(" get-instantapp-resolver");
- pw.println(" Return the name of the component that is the current instant app installer.");
- pw.println("");
- pw.println(" set-harmful-app-warning [--user <USER_ID>] <PACKAGE> [<WARNING>]");
- pw.println(" Mark the app as harmful with the given warning message.");
- pw.println("");
- pw.println(" get-harmful-app-warning [--user <USER_ID>] <PACKAGE>");
- pw.println(" Return the harmful app warning message for the given app, if present");
- pw.println();
- pw.println(" uninstall-system-updates [<PACKAGE>]");
- pw.println(" Removes updates to the given system application and falls back to its");
- pw.println(" /system version. Does nothing if the given package is not a system app.");
- pw.println(" If no package is specified, removes updates to all system applications.");
- pw.println("");
- pw.println(" get-moduleinfo [--all | --installed] [module-name]");
- pw.println(" Displays module info. If module-name is specified only that info is shown");
- pw.println(" By default, without any argument only installed modules are shown.");
- pw.println(" --all: show all module info");
- pw.println(" --installed: show only installed modules");
- pw.println("");
- pw.println(" log-visibility [--enable|--disable] <PACKAGE>");
- pw.println(" Turns on debug logging when visibility is blocked for the given package.");
- pw.println(" --enable: turn on debug logging (default)");
- pw.println(" --disable: turn off debug logging");
- pw.println("");
- pw.println(" set-silent-updates-policy [--allow-unlimited-silent-updates <INSTALLER>]");
- pw.println(" [--throttle-time <SECONDS>] [--reset]");
- pw.println(" Sets the policies of the silent updates.");
- pw.println(" --allow-unlimited-silent-updates: allows unlimited silent updated");
- pw.println(" installation requests from the installer without the throttle time.");
- pw.println(" --throttle-time: update the silent updates throttle time in seconds.");
- pw.println(" --reset: restore the installer and throttle time to the default, and");
- pw.println(" clear tracks of silent updates in the system.");
- pw.println("");
- pw.println(" art [<SUB-COMMANDS>]");
- pw.println(" Invokes ART services commands. (Run `pm art help` for details.)");
- pw.println("");
- mDomainVerificationShell.printHelp(pw);
- pw.println("");
- Intent.printIntentArgsHelp(pw , "");
}
private static class LocalIntentReceiver {
diff --git a/services/core/java/com/android/server/pm/PackageMetrics.java b/services/core/java/com/android/server/pm/PackageMetrics.java
index 8252a9fa..d4c1256 100644
--- a/services/core/java/com/android/server/pm/PackageMetrics.java
+++ b/services/core/java/com/android/server/pm/PackageMetrics.java
@@ -19,9 +19,11 @@
import static android.os.Process.INVALID_UID;
import android.annotation.IntDef;
+import android.app.ActivityManager;
import android.app.admin.SecurityLog;
import android.content.pm.PackageManager;
import android.content.pm.parsing.ApkLiteParseUtils;
+import android.os.UserHandle;
import android.util.Pair;
import android.util.SparseArray;
@@ -68,8 +70,8 @@
mInstallRequest = installRequest;
}
- public void onInstallSucceed(int userId) {
- reportInstallationToSecurityLog(userId);
+ public void onInstallSucceed() {
+ reportInstallationToSecurityLog(mInstallRequest.getUserId());
reportInstallationStats(true /* success */);
}
@@ -110,10 +112,11 @@
}
}
+
FrameworkStatsLog.write(FrameworkStatsLog.PACKAGE_INSTALLATION_SESSION_REPORTED,
mInstallRequest.getSessionId() /* session_id */,
packageName /* package_name */,
- mInstallRequest.getUid() /* uid */,
+ getUid(mInstallRequest.getAppId(), mInstallRequest.getUserId()) /* uid */,
newUsers /* user_ids */,
userManagerInternal.getUserTypesForStatsd(newUsers) /* user_types */,
originalUsers /* original_user_ids */,
@@ -140,6 +143,13 @@
);
}
+ private static int getUid(int appId, int userId) {
+ if (userId == UserHandle.USER_ALL) {
+ userId = ActivityManager.getCurrentUser();
+ }
+ return UserHandle.getUid(userId, appId);
+ }
+
private long getApksSize(File apkDir) {
// TODO(b/249294752): also count apk sizes for failed installs
final AtomicLong apksSize = new AtomicLong();
@@ -218,9 +228,9 @@
final int[] originalUsers = info.mOrigUsers;
final int[] originalUserTypes = userManagerInternal.getUserTypesForStatsd(originalUsers);
FrameworkStatsLog.write(FrameworkStatsLog.PACKAGE_UNINSTALLATION_REPORTED,
- info.mUid, removedUsers, removedUserTypes, originalUsers, originalUserTypes,
- deleteFlags, PackageManager.DELETE_SUCCEEDED, info.mIsRemovedPackageSystemUpdate,
- !info.mRemovedForAllUsers);
+ getUid(info.mUid, userId), removedUsers, removedUserTypes, originalUsers,
+ originalUserTypes, deleteFlags, PackageManager.DELETE_SUCCEEDED,
+ info.mIsRemovedPackageSystemUpdate, !info.mRemovedForAllUsers);
final String packageName = info.mRemovedPackage;
final long versionCode = info.mRemovedPackageVersionCode;
reportUninstallationToSecurityLog(packageName, versionCode, userId);
diff --git a/services/core/java/com/android/server/pm/PackageSetting.java b/services/core/java/com/android/server/pm/PackageSetting.java
index 877b112..6562de96 100644
--- a/services/core/java/com/android/server/pm/PackageSetting.java
+++ b/services/core/java/com/android/server/pm/PackageSetting.java
@@ -300,6 +300,8 @@
installSource.mInitiatingPackageName);
proto.write(PackageProto.InstallSourceProto.ORIGINATING_PACKAGE_NAME,
installSource.mOriginatingPackageName);
+ proto.write(PackageProto.InstallSourceProto.UPDATE_OWNER_PACKAGE_NAME,
+ installSource.mUpdateOwnerPackageName);
proto.end(sourceToken);
}
proto.write(PackageProto.StatesProto.IS_LOADING, isLoading());
@@ -368,6 +370,12 @@
return this;
}
+ public PackageSetting setUpdateOwnerPackage(@Nullable String updateOwnerPackageName) {
+ installSource = installSource.setUpdateOwnerPackageName(updateOwnerPackageName);
+ onChanged();
+ return this;
+ }
+
public PackageSetting setInstallSource(InstallSource installSource) {
this.installSource = Objects.requireNonNull(installSource);
onChanged();
diff --git a/services/core/java/com/android/server/pm/ReconcilePackageUtils.java b/services/core/java/com/android/server/pm/ReconcilePackageUtils.java
index 99bcbc9..58dcb02 100644
--- a/services/core/java/com/android/server/pm/ReconcilePackageUtils.java
+++ b/services/core/java/com/android/server/pm/ReconcilePackageUtils.java
@@ -213,8 +213,9 @@
if (sharedUserSetting != null) {
if (sharedUserSetting.signaturesChanged != null
&& !PackageManagerServiceUtils.canJoinSharedUserId(
- parsedPackage.getSigningDetails(),
- sharedUserSetting.getSigningDetails())) {
+ parsedPackage.getPackageName(), parsedPackage.getSigningDetails(),
+ sharedUserSetting,
+ PackageManagerServiceUtils.SHARED_USER_ID_JOIN_TYPE_SYSTEM)) {
if (SystemProperties.getInt("ro.product.first_api_level", 0) <= 29) {
// Mismatched signatures is an error and silently skipping system
// packages will likely break the device in unforeseen ways.
diff --git a/services/core/java/com/android/server/pm/Settings.java b/services/core/java/com/android/server/pm/Settings.java
index 6ebef20..97fb0c2 100644
--- a/services/core/java/com/android/server/pm/Settings.java
+++ b/services/core/java/com/android/server/pm/Settings.java
@@ -3050,6 +3050,9 @@
if (installSource.mInstallerPackageUid != INVALID_UID) {
serializer.attributeInt(null, "installerUid", installSource.mInstallerPackageUid);
}
+ if (installSource.mUpdateOwnerPackageName != null) {
+ serializer.attribute(null, "updateOwner", installSource.mUpdateOwnerPackageName);
+ }
if (installSource.mInstallerAttributionTag != null) {
serializer.attribute(null, "installerAttributionTag",
installSource.mInstallerAttributionTag);
@@ -3880,6 +3883,7 @@
String systemStr = null;
String installerPackageName = null;
int installerPackageUid = INVALID_UID;
+ String updateOwnerPackageName = null;
String installerAttributionTag = null;
int packageSource = PackageInstaller.PACKAGE_SOURCE_UNSPECIFIED;
boolean isOrphaned = false;
@@ -3923,6 +3927,7 @@
versionCode = parser.getAttributeLong(null, "version", 0);
installerPackageName = parser.getAttributeValue(null, "installer");
installerPackageUid = parser.getAttributeInt(null, "installerUid", INVALID_UID);
+ updateOwnerPackageName = parser.getAttributeValue(null, "updateOwner");
installerAttributionTag = parser.getAttributeValue(null, "installerAttributionTag");
packageSource = parser.getAttributeInt(null, "packageSource",
PackageInstaller.PACKAGE_SOURCE_UNSPECIFIED);
@@ -4065,8 +4070,9 @@
if (packageSetting != null) {
InstallSource installSource = InstallSource.create(
installInitiatingPackageName, installOriginatingPackageName,
- installerPackageName, installerPackageUid, installerAttributionTag,
- packageSource, isOrphaned, installInitiatorUninstalled);
+ installerPackageName, installerPackageUid, updateOwnerPackageName,
+ installerAttributionTag, packageSource, isOrphaned,
+ installInitiatorUninstalled);
packageSetting.setInstallSource(installSource)
.setVolumeUuid(volumeUuid)
.setCategoryOverride(categoryHint)
@@ -4734,6 +4740,8 @@
pw.print(ps.getInstallSource().mInstallerPackageName != null
? ps.getInstallSource().mInstallerPackageName : "?");
pw.print(ps.getInstallSource().mInstallerPackageUid);
+ pw.print(ps.getInstallSource().mUpdateOwnerPackageName != null
+ ? ps.getInstallSource().mUpdateOwnerPackageName : "?");
pw.print(ps.getInstallSource().mInstallerAttributionTag != null
? "(" + ps.getInstallSource().mInstallerAttributionTag + ")" : "");
pw.print(",");
@@ -5017,6 +5025,10 @@
pw.print(prefix); pw.print(" installerPackageUid=");
pw.println(ps.getInstallSource().mInstallerPackageUid);
}
+ if (ps.getInstallSource().mUpdateOwnerPackageName != null) {
+ pw.print(prefix); pw.print(" updateOwnerPackageName=");
+ pw.println(ps.getInstallSource().mUpdateOwnerPackageName);
+ }
if (ps.getInstallSource().mInstallerAttributionTag != null) {
pw.print(prefix); pw.print(" installerAttributionTag=");
pw.println(ps.getInstallSource().mInstallerAttributionTag);
diff --git a/services/core/java/com/android/server/pm/SharedLibrariesImpl.java b/services/core/java/com/android/server/pm/SharedLibrariesImpl.java
index d2ce23e..9987867 100644
--- a/services/core/java/com/android/server/pm/SharedLibrariesImpl.java
+++ b/services/core/java/com/android/server/pm/SharedLibrariesImpl.java
@@ -17,6 +17,7 @@
package com.android.server.pm;
import static android.content.pm.PackageManager.INSTALL_FAILED_MISSING_SHARED_LIBRARY;
+import static android.content.pm.PackageManager.INSTALL_FAILED_SHARED_LIBRARY_BAD_CERTIFICATE_DIGEST;
import static com.android.server.pm.PackageManagerService.PLATFORM_PACKAGE_NAME;
import static com.android.server.pm.PackageManagerService.SCAN_BOOTING;
@@ -1035,8 +1036,17 @@
} else {
// lib signing cert could have rotated beyond the one expected, check to see
// if the new one has been blessed by the old
- byte[] digestBytes = HexEncoding.decode(
- expectedCertDigests[0], false /* allowSingleChar */);
+ final byte[] digestBytes;
+ try {
+ digestBytes = HexEncoding.decode(
+ expectedCertDigests[0], false /* allowSingleChar */);
+ } catch (IllegalArgumentException e) {
+ throw new PackageManagerException(
+ INSTALL_FAILED_SHARED_LIBRARY_BAD_CERTIFICATE_DIGEST,
+ "Package " + packageName + " declares bad certificate digest "
+ + "for " + libraryType + " library " + libName
+ + "; failing!");
+ }
if (!libPkg.hasSha256Certificate(digestBytes)) {
throw new PackageManagerException(INSTALL_FAILED_MISSING_SHARED_LIBRARY,
"Package " + packageName + " requires differently signed "
diff --git a/services/core/java/com/android/server/pm/UserManagerInternal.java b/services/core/java/com/android/server/pm/UserManagerInternal.java
index 2ae8b52..7b15e76 100644
--- a/services/core/java/com/android/server/pm/UserManagerInternal.java
+++ b/services/core/java/com/android/server/pm/UserManagerInternal.java
@@ -388,8 +388,8 @@
* and the user is {@link UserManager#isUserVisible() visible}.
*
* <p><b>NOTE: </b>this method is meant to be used only by {@code UserController} (when a user
- * is started). If other clients (like {@code CarService} need to explicitly change the user /
- * display assignment, we'll need to provide other APIs.
+ * is started); for extra unassignments, callers should call {@link
+ * #assignUserToExtraDisplay(int, int)} instead.
*
* <p><b>NOTE: </b>this method doesn't validate if the display exists, it's up to the caller to
* pass a valid display id.
@@ -398,15 +398,43 @@
@UserIdInt int profileGroupId, @UserStartMode int userStartMode, int displayId);
/**
+ * Assigns an extra display to the given user, so the user is visible on that display.
+ *
+ * <p>This method is meant to be used on automotive builds where a passenger zone has more than
+ * one display (for example, the "main" display and a smaller display used for input).
+ *
+ * <p><b>NOTE: </b>this call will be ignored on devices that do not
+ * {@link UserManager#isVisibleBackgroundUsersSupported() support visible background users}.
+ *
+ * @return whether the operation succeeded, in which case the user would be visible on the
+ * display.
+ */
+ public abstract boolean assignUserToExtraDisplay(@UserIdInt int userId, int displayId);
+
+ /**
* Unassigns a user from its current display when it's stopping.
*
* <p><b>NOTE: </b>this method is meant to be used only by {@code UserController} (when a user
- * is stopped). If other clients (like {@code CarService} need to explicitly change the user /
- * display assignment, we'll need to provide other APIs.
+ * is stopped); for extra unassignments, callers should call
+ * {@link #unassignUserFromExtraDisplay(int, int)} instead.
*/
public abstract void unassignUserFromDisplayOnStop(@UserIdInt int userId);
/**
+ * Unassigns the extra display from the given user.
+ *
+ * <p>This method is meant to be used on automotive builds where a passenger zone has more than
+ * one display (for example, the "main" display and a smaller display used for input).
+ *
+ * <p><b>NOTE: </b>this call will be ignored on devices that do not
+ * {@link UserManager#isVisibleBackgroundUsersSupported() support visible background users}.
+ *
+ * @return whether the operation succeeded, i.e., the user was previously
+ * {@link #assignUserToExtraDisplay(int, int) assigned to an extra display}.
+ */
+ public abstract boolean unassignUserFromExtraDisplay(@UserIdInt int userId, int displayId);
+
+ /**
* Returns {@code true} if the user is visible (as defined by
* {@link UserManager#isUserVisible()}.
*/
diff --git a/services/core/java/com/android/server/pm/UserManagerService.java b/services/core/java/com/android/server/pm/UserManagerService.java
index 6bac905..a8cf8cb 100644
--- a/services/core/java/com/android/server/pm/UserManagerService.java
+++ b/services/core/java/com/android/server/pm/UserManagerService.java
@@ -1476,20 +1476,15 @@
@Override
public void revokeUserAdmin(@UserIdInt int userId) {
checkManageUserAndAcrossUsersFullPermission("revoke admin privileges");
-
synchronized (mPackagesLock) {
- UserInfo info;
synchronized (mUsersLock) {
- info = getUserInfoLU(userId);
- }
- if (info == null || !info.isAdmin()) {
- // Exit if no user found with that id, or the user is not an Admin.
- return;
- }
-
- info.flags ^= UserInfo.FLAG_ADMIN;
- synchronized (mUsersLock) {
- writeUserLP(getUserDataLU(info.id));
+ UserData user = getUserDataLU(userId);
+ if (user == null || !user.info.isAdmin()) {
+ // Exit if no user found with that id, or the user is not an Admin.
+ return;
+ }
+ user.info.flags ^= UserInfo.FLAG_ADMIN;
+ writeUserLP(user);
}
}
}
@@ -5426,6 +5421,12 @@
return false;
}
+ if (isNonRemovableMainUser(userData.info)) {
+ Slog.e(LOG_TAG, "Main user cannot be removed when "
+ + "it's a permanent admin user.");
+ return false;
+ }
+
if (mRemovingUserIds.get(userId)) {
Slog.e(LOG_TAG, TextUtils.formatSimple(
"User %d is already scheduled for removal.", userId));
@@ -5530,6 +5531,12 @@
return UserManager.REMOVE_RESULT_ERROR_USER_NOT_FOUND;
}
+ if (isNonRemovableMainUser(userData.info)) {
+ Slog.e(LOG_TAG, "Main user cannot be removed when "
+ + "it's a permanent admin user.");
+ return UserManager.REMOVE_RESULT_ERROR_MAIN_USER_PERMANENT_ADMIN;
+ }
+
if (mRemovingUserIds.get(userId)) {
Slog.e(LOG_TAG, "User " + userId + " is already scheduled for removal.");
return UserManager.REMOVE_RESULT_ALREADY_BEING_REMOVED;
@@ -6748,7 +6755,7 @@
public void removeAllUsers() {
if (UserHandle.USER_SYSTEM == getCurrentUserId()) {
// Remove the non-system users straight away.
- removeNonSystemUsers();
+ removeAllUsersExceptSystemAndPermanentAdminMain();
} else {
// Switch to the system user first and then remove the other users.
BroadcastReceiver userSwitchedReceiver = new BroadcastReceiver() {
@@ -6760,7 +6767,7 @@
return;
}
mContext.unregisterReceiver(this);
- removeNonSystemUsers();
+ removeAllUsersExceptSystemAndPermanentAdminMain();
}
};
IntentFilter userSwitchedFilter = new IntentFilter();
@@ -7015,6 +7022,16 @@
}
@Override
+ public boolean assignUserToExtraDisplay(int userId, int displayId) {
+ return mUserVisibilityMediator.assignUserToExtraDisplay(userId, displayId);
+ }
+
+ @Override
+ public boolean unassignUserFromExtraDisplay(int userId, int displayId) {
+ return mUserVisibilityMediator.unassignUserFromExtraDisplay(userId, displayId);
+ }
+
+ @Override
public void unassignUserFromDisplayOnStop(@UserIdInt int userId) {
mUserVisibilityMediator.unassignUserFromDisplayOnStop(userId);
}
@@ -7113,14 +7130,14 @@
throw new UserManager.CheckedUserOperationException(message, userOperationResult);
}
- /* Remove all the users except of the system one. */
- private void removeNonSystemUsers() {
+ /* Remove all the users except the system and permanent admin main.*/
+ private void removeAllUsersExceptSystemAndPermanentAdminMain() {
ArrayList<UserInfo> usersToRemove = new ArrayList<>();
synchronized (mUsersLock) {
final int userSize = mUsers.size();
for (int i = 0; i < userSize; i++) {
UserInfo ui = mUsers.valueAt(i).info;
- if (ui.id != UserHandle.USER_SYSTEM) {
+ if (ui.id != UserHandle.USER_SYSTEM && !isNonRemovableMainUser(ui)) {
usersToRemove.add(ui);
}
}
@@ -7249,4 +7266,22 @@
return mAmInternal;
}
+ /**
+ * Returns true, when user has {@link UserInfo#FLAG_MAIN} and system property
+ * {@link com.android.internal.R.bool.isMainUserPermanentAdmin} is true.
+ */
+ private boolean isNonRemovableMainUser(UserInfo userInfo) {
+ return userInfo.isMain() && isMainUserPermanentAdmin();
+ }
+
+ /**
+ * Returns true, when {@link com.android.internal.R.bool.isMainUserPermanentAdmin} is true.
+ * If the main user is a permanent admin user it can't be deleted
+ * or downgraded to non-admin status.
+ */
+ private static boolean isMainUserPermanentAdmin() {
+ return Resources.getSystem()
+ .getBoolean(com.android.internal.R.bool.config_isMainUserPermanentAdmin);
+ }
+
}
diff --git a/services/core/java/com/android/server/pm/UserRestrictionsUtils.java b/services/core/java/com/android/server/pm/UserRestrictionsUtils.java
index 27d74d5..214fd61 100644
--- a/services/core/java/com/android/server/pm/UserRestrictionsUtils.java
+++ b/services/core/java/com/android/server/pm/UserRestrictionsUtils.java
@@ -149,7 +149,8 @@
UserManager.DISALLOW_WIFI_DIRECT,
UserManager.DISALLOW_ADD_WIFI_CONFIG,
UserManager.DISALLOW_CELLULAR_2G,
- UserManager.DISALLOW_ULTRA_WIDEBAND_RADIO
+ UserManager.DISALLOW_ULTRA_WIDEBAND_RADIO,
+ UserManager.DISALLOW_CONFIG_DEFAULT_APPS
});
public static final Set<String> DEPRECATED_USER_RESTRICTIONS = Sets.newArraySet(
diff --git a/services/core/java/com/android/server/pm/UserTypeFactory.java b/services/core/java/com/android/server/pm/UserTypeFactory.java
index 9b337adf..edb2a4be3b 100644
--- a/services/core/java/com/android/server/pm/UserTypeFactory.java
+++ b/services/core/java/com/android/server/pm/UserTypeFactory.java
@@ -133,7 +133,9 @@
.setUseParentsContacts(true)
.setUpdateCrossProfileIntentFiltersOnOTA(true)
.setCrossProfileIntentFilterAccessControl(
- UserProperties.CROSS_PROFILE_INTENT_FILTER_ACCESS_LEVEL_SYSTEM));
+ UserProperties.CROSS_PROFILE_INTENT_FILTER_ACCESS_LEVEL_SYSTEM)
+ .setCrossProfileIntentResolutionStrategy(UserProperties
+ .CROSS_PROFILE_INTENT_RESOLUTION_STRATEGY_NO_FILTERING));
}
/**
diff --git a/services/core/java/com/android/server/pm/UserVisibilityMediator.java b/services/core/java/com/android/server/pm/UserVisibilityMediator.java
index d8e4dac..66d390f 100644
--- a/services/core/java/com/android/server/pm/UserVisibilityMediator.java
+++ b/services/core/java/com/android/server/pm/UserVisibilityMediator.java
@@ -19,6 +19,7 @@
import static android.os.UserHandle.USER_NULL;
import static android.os.UserHandle.USER_SYSTEM;
import static android.view.Display.DEFAULT_DISPLAY;
+import static android.view.Display.INVALID_DISPLAY;
import static com.android.server.pm.UserManagerInternal.USER_ASSIGNMENT_RESULT_FAILURE;
import static com.android.server.pm.UserManagerInternal.USER_ASSIGNMENT_RESULT_SUCCESS_INVISIBLE;
@@ -113,7 +114,18 @@
*/
@Nullable
@GuardedBy("mLock")
- private final SparseIntArray mUsersOnDisplaysMap;
+ private final SparseIntArray mUsersAssignedToDisplayOnStart;
+
+ /**
+ * Map of extra (i.e., not assigned on start, but by explicit calls to
+ * {@link #assignUserToExtraDisplay(int, int)}) displays assigned to user (key is display id,
+ * value is user id).
+ *
+ * <p>Only set when {@code mUsersOnSecondaryDisplaysEnabled} is {@code true}.
+ */
+ @Nullable
+ @GuardedBy("mLock")
+ private final SparseIntArray mExtraDisplaysAssignedToUsers;
/**
* Mapping from each started user to its profile group.
@@ -137,7 +149,13 @@
@VisibleForTesting
UserVisibilityMediator(boolean backgroundUsersOnDisplaysEnabled, Handler handler) {
mVisibleBackgroundUsersEnabled = backgroundUsersOnDisplaysEnabled;
- mUsersOnDisplaysMap = mVisibleBackgroundUsersEnabled ? new SparseIntArray() : null;
+ if (mVisibleBackgroundUsersEnabled) {
+ mUsersAssignedToDisplayOnStart = new SparseIntArray();
+ mExtraDisplaysAssignedToUsers = new SparseIntArray();
+ } else {
+ mUsersAssignedToDisplayOnStart = null;
+ mExtraDisplaysAssignedToUsers = null;
+ }
mHandler = handler;
// TODO(b/242195409): might need to change this if boot logic is refactored for HSUM devices
mStartedProfileGroupIds.put(INITIAL_CURRENT_USER_ID, INITIAL_CURRENT_USER_ID);
@@ -207,7 +225,7 @@
if (DBG) {
Slogf.d(TAG, "adding user / display mapping (%d -> %d)", userId, displayId);
}
- mUsersOnDisplaysMap.put(userId, displayId);
+ mUsersAssignedToDisplayOnStart.put(userId, displayId);
break;
case SECONDARY_DISPLAY_MAPPING_NOT_NEEDED:
if (DBG) {
@@ -341,9 +359,9 @@
}
// Check if display is available
- for (int i = 0; i < mUsersOnDisplaysMap.size(); i++) {
- int assignedUserId = mUsersOnDisplaysMap.keyAt(i);
- int assignedDisplayId = mUsersOnDisplaysMap.valueAt(i);
+ for (int i = 0; i < mUsersAssignedToDisplayOnStart.size(); i++) {
+ int assignedUserId = mUsersAssignedToDisplayOnStart.keyAt(i);
+ int assignedDisplayId = mUsersAssignedToDisplayOnStart.valueAt(i);
if (DBG) {
Slogf.d(TAG, "%d: assignedUserId=%d, assignedDisplayId=%d",
i, assignedUserId, assignedDisplayId);
@@ -363,6 +381,100 @@
}
/**
+ * See {@link UserManagerInternal#assignUserToExtraDisplay(int, int)}.
+ */
+ public boolean assignUserToExtraDisplay(@UserIdInt int userId, int displayId) {
+ if (DBG) {
+ Slogf.d(TAG, "assignUserToExtraDisplay(%d, %d)", userId, displayId);
+ }
+ if (!mVisibleBackgroundUsersEnabled) {
+ Slogf.w(TAG, "assignUserToExtraDisplay(%d, %d): called when not supported", userId,
+ displayId);
+ return false;
+ }
+ if (displayId == INVALID_DISPLAY) {
+ Slogf.w(TAG, "assignUserToExtraDisplay(%d, %d): called with INVALID_DISPLAY", userId,
+ displayId);
+ return false;
+ }
+ if (displayId == DEFAULT_DISPLAY) {
+ Slogf.w(TAG, "assignUserToExtraDisplay(%d, %d): DEFAULT_DISPLAY is automatically "
+ + "assigned to current user", userId, displayId);
+ return false;
+ }
+
+ synchronized (mLock) {
+ if (!isUserVisible(userId)) {
+ Slogf.w(TAG, "assignUserToExtraDisplay(%d, %d): failed because user is not visible",
+ userId, displayId);
+ return false;
+ }
+ if (isStartedProfile(userId)) {
+ Slogf.w(TAG, "assignUserToExtraDisplay(%d, %d): failed because user is a profile",
+ userId, displayId);
+ return false;
+ }
+
+ if (mExtraDisplaysAssignedToUsers.get(displayId, USER_NULL) == userId) {
+ Slogf.w(TAG, "assignUserToExtraDisplay(%d, %d): failed because user is already "
+ + "assigned to that display", userId, displayId);
+ return false;
+ }
+
+ int userAssignedToDisplay = getUserAssignedToDisplay(displayId,
+ /* returnCurrentUserByDefault= */ false);
+ if (userAssignedToDisplay != USER_NULL) {
+ Slogf.w(TAG, "assignUserToExtraDisplay(%d, %d): failed because display was assigned"
+ + " to user %d on start", userId, displayId, userAssignedToDisplay);
+ return false;
+ }
+ userAssignedToDisplay = mExtraDisplaysAssignedToUsers.get(userId, USER_NULL);
+ if (userAssignedToDisplay != USER_NULL) {
+ Slogf.w(TAG, "assignUserToExtraDisplay(%d, %d): failed because user %d was already "
+ + "assigned that extra display", userId, displayId, userAssignedToDisplay);
+ return false;
+ }
+ if (DBG) {
+ Slogf.d(TAG, "addding %d -> %d to map", displayId, userId);
+ }
+ mExtraDisplaysAssignedToUsers.put(displayId, userId);
+ }
+ return true;
+ }
+
+ /**
+ * See {@link UserManagerInternal#unassignUserFromExtraDisplay(int, int)}.
+ */
+ public boolean unassignUserFromExtraDisplay(@UserIdInt int userId, int displayId) {
+ if (DBG) {
+ Slogf.d(TAG, "unassignUserFromExtraDisplay(%d, %d)", userId, displayId);
+ }
+ if (!mVisibleBackgroundUsersEnabled) {
+ Slogf.w(TAG, "unassignUserFromExtraDisplay(%d, %d): called when not supported",
+ userId, displayId);
+ return false;
+ }
+ synchronized (mLock) {
+ int assignedUserId = mExtraDisplaysAssignedToUsers.get(displayId, USER_NULL);
+ if (assignedUserId == USER_NULL) {
+ Slogf.w(TAG, "unassignUserFromExtraDisplay(%d, %d): not assigned to any user",
+ userId, displayId);
+ return false;
+ }
+ if (assignedUserId != userId) {
+ Slogf.w(TAG, "unassignUserFromExtraDisplay(%d, %d): was assigned to user %d",
+ userId, displayId, assignedUserId);
+ return false;
+ }
+ if (DBG) {
+ Slogf.d(TAG, "removing %d from map", displayId);
+ }
+ mExtraDisplaysAssignedToUsers.delete(displayId);
+ }
+ return true;
+ }
+
+ /**
* See {@link UserManagerInternal#unassignUserFromDisplayOnStop(int)}.
*/
public void unassignUserFromDisplayOnStop(@UserIdInt int userId) {
@@ -373,7 +485,7 @@
synchronized (mLock) {
visibleUsersBefore = getVisibleUsers();
- unassignUserFromDisplayOnStopLocked(userId);
+ unassignUserFromAllDisplaysOnStopLocked(userId);
visibleUsersAfter = getVisibleUsers();
}
@@ -381,7 +493,7 @@
}
@GuardedBy("mLock")
- private void unassignUserFromDisplayOnStopLocked(@UserIdInt int userId) {
+ private void unassignUserFromAllDisplaysOnStopLocked(@UserIdInt int userId) {
if (DBG) {
Slogf.d(TAG, "Removing %d from mStartedProfileGroupIds (%s)", userId,
mStartedProfileGroupIds);
@@ -395,10 +507,21 @@
return;
}
if (DBG) {
- Slogf.d(TAG, "Removing %d from mUsersOnSecondaryDisplays (%s)", userId,
- mUsersOnDisplaysMap);
+ Slogf.d(TAG, "Removing user %d from mUsersOnDisplaysMap (%s)", userId,
+ mUsersAssignedToDisplayOnStart);
}
- mUsersOnDisplaysMap.delete(userId);
+ mUsersAssignedToDisplayOnStart.delete(userId);
+
+ // Remove extra displays as well
+ for (int i = mExtraDisplaysAssignedToUsers.size() - 1; i >= 0; i--) {
+ if (mExtraDisplaysAssignedToUsers.valueAt(i) == userId) {
+ if (DBG) {
+ Slogf.d(TAG, "Removing display %d from mExtraDisplaysAssignedToUsers (%s)",
+ mExtraDisplaysAssignedToUsers.keyAt(i), mExtraDisplaysAssignedToUsers);
+ }
+ mExtraDisplaysAssignedToUsers.removeAt(i);
+ }
+ }
}
/**
@@ -424,7 +547,7 @@
boolean visible;
synchronized (mLock) {
- visible = mUsersOnDisplaysMap.indexOfKey(userId) >= 0;
+ visible = mUsersAssignedToDisplayOnStart.indexOfKey(userId) >= 0;
}
if (DBG) {
Slogf.d(TAG, "isUserVisible(%d): %b from mapping", userId, visible);
@@ -448,7 +571,12 @@
}
synchronized (mLock) {
- return mUsersOnDisplaysMap.get(userId, Display.INVALID_DISPLAY) == displayId;
+ if (mUsersAssignedToDisplayOnStart.get(userId, Display.INVALID_DISPLAY) == displayId) {
+ // User assigned to display on start
+ return true;
+ }
+ // Check for extra assignment
+ return mExtraDisplaysAssignedToUsers.get(displayId, USER_NULL) == userId;
}
}
@@ -465,24 +593,34 @@
}
synchronized (mLock) {
- return mUsersOnDisplaysMap.get(userId, Display.INVALID_DISPLAY);
+ return mUsersAssignedToDisplayOnStart.get(userId, Display.INVALID_DISPLAY);
}
}
/**
* See {@link UserManagerInternal#getUserAssignedToDisplay(int)}.
*/
- public int getUserAssignedToDisplay(@UserIdInt int displayId) {
- if (displayId == Display.DEFAULT_DISPLAY || !mVisibleBackgroundUsersEnabled) {
+ public @UserIdInt int getUserAssignedToDisplay(@UserIdInt int displayId) {
+ return getUserAssignedToDisplay(displayId, /* returnCurrentUserByDefault= */ true);
+ }
+
+ /**
+ * Gets the user explicitly assigned to a display, or the current user when no user is assigned
+ * to it (and {@code returnCurrentUserByDefault} is {@code true}).
+ */
+ private @UserIdInt int getUserAssignedToDisplay(@UserIdInt int displayId,
+ boolean returnCurrentUserByDefault) {
+ if (returnCurrentUserByDefault
+ && (displayId == Display.DEFAULT_DISPLAY || !mVisibleBackgroundUsersEnabled)) {
return getCurrentUserId();
}
synchronized (mLock) {
- for (int i = 0; i < mUsersOnDisplaysMap.size(); i++) {
- if (mUsersOnDisplaysMap.valueAt(i) != displayId) {
+ for (int i = 0; i < mUsersAssignedToDisplayOnStart.size(); i++) {
+ if (mUsersAssignedToDisplayOnStart.valueAt(i) != displayId) {
continue;
}
- int userId = mUsersOnDisplaysMap.keyAt(i);
+ int userId = mUsersAssignedToDisplayOnStart.keyAt(i);
if (!isStartedProfile(userId)) {
return userId;
} else if (DBG) {
@@ -491,6 +629,13 @@
}
}
}
+ if (!returnCurrentUserByDefault) {
+ if (DBG) {
+ Slogf.d(TAG, "getUserAssignedToDisplay(%d): no user assigned to display, returning "
+ + "USER_NULL instead", displayId);
+ }
+ return USER_NULL;
+ }
int currentUserId = getCurrentUserId();
if (DBG) {
@@ -618,9 +763,11 @@
ipw.print("Supports visible background users on displays: ");
ipw.println(mVisibleBackgroundUsersEnabled);
- if (mUsersOnDisplaysMap != null) {
- dumpSparseIntArray(ipw, mUsersOnDisplaysMap, "user / display", "u", "d");
- }
+ dumpSparseIntArray(ipw, mUsersAssignedToDisplayOnStart, "user / display", "u", "d");
+
+ dumpSparseIntArray(ipw, mExtraDisplaysAssignedToUsers, "extra display / user",
+ "d", "u");
+
int numberListeners = mListeners.size();
ipw.print("Number of listeners: ");
ipw.println(numberListeners);
@@ -638,8 +785,14 @@
ipw.decreaseIndent();
}
- private static void dumpSparseIntArray(IndentingPrintWriter ipw, SparseIntArray array,
+ private static void dumpSparseIntArray(IndentingPrintWriter ipw, @Nullable SparseIntArray array,
String arrayDescription, String keyName, String valueName) {
+ if (array == null) {
+ ipw.print("No ");
+ ipw.print(arrayDescription);
+ ipw.println(" mappings");
+ return;
+ }
ipw.print("Number of ");
ipw.print(arrayDescription);
ipw.print(" mappings: ");
diff --git a/services/core/java/com/android/server/pm/dex/DexManager.java b/services/core/java/com/android/server/pm/dex/DexManager.java
index fbf7409..7f0c3f9 100644
--- a/services/core/java/com/android/server/pm/dex/DexManager.java
+++ b/services/core/java/com/android/server/pm/dex/DexManager.java
@@ -126,20 +126,21 @@
private static int DEX_SEARCH_FOUND_SECONDARY = 3; // dex file is a secondary dex
public DexManager(Context context, PackageDexOptimizer pdo, Installer installer,
- Object installLock) {
- this(context, pdo, installer, installLock, null);
+ Object installLock, DynamicCodeLogger dynamicCodeLogger) {
+ this(context, pdo, installer, installLock, dynamicCodeLogger, null);
}
@VisibleForTesting
public DexManager(Context context, PackageDexOptimizer pdo, Installer installer,
- Object installLock, @Nullable IPackageManager packageManager) {
+ Object installLock, DynamicCodeLogger dynamicCodeLogger,
+ @Nullable IPackageManager packageManager) {
mContext = context;
mPackageCodeLocationsCache = new HashMap<>();
mPackageDexUsage = new PackageDexUsage();
mPackageDexOptimizer = pdo;
mInstaller = installer;
mInstallLock = installLock;
- mDynamicCodeLogger = new DynamicCodeLogger(installer);
+ mDynamicCodeLogger = dynamicCodeLogger;
mPackageManager = packageManager;
// This is currently checked to handle tests that pass in a null context.
@@ -169,10 +170,6 @@
return mPackageManager;
}
- public DynamicCodeLogger getDynamicCodeLogger() {
- return mDynamicCodeLogger;
- }
-
/**
* Notify about dex files loads.
* Note that this method is invoked when apps load dex files and it should
@@ -328,7 +325,6 @@
loadInternal(existingPackages);
} catch (RuntimeException e) {
mPackageDexUsage.clear();
- mDynamicCodeLogger.clear();
Slog.w(TAG, "Exception while loading. Starting with a fresh state.", e);
}
}
@@ -379,12 +375,10 @@
if (mPackageDexUsage.removePackage(packageName)) {
mPackageDexUsage.maybeWriteAsync();
}
- mDynamicCodeLogger.removePackage(packageName);
} else {
if (mPackageDexUsage.removeUserPackage(packageName, userId)) {
mPackageDexUsage.maybeWriteAsync();
}
- mDynamicCodeLogger.removeUserPackage(packageName, userId);
}
}
@@ -463,14 +457,6 @@
Slog.w(TAG, "Exception while loading package dex usage. "
+ "Starting with a fresh state.", e);
}
-
- try {
- mDynamicCodeLogger.readAndSync(packageToUsersMap);
- } catch (RuntimeException e) {
- mDynamicCodeLogger.clear();
- Slog.w(TAG, "Exception while loading package dynamic code usage. "
- + "Starting with a fresh state.", e);
- }
}
/**
@@ -565,89 +551,6 @@
}
/**
- * Performs dexopt on system server dex files.
- *
- * <p>Verfifies that the package name is {@link PackageManagerService#PLATFORM_PACKAGE_NAME}.
- *
- * @return
- * <p>PackageDexOptimizer.DEX_OPT_SKIPPED if dexopt was skipped because no system server
- * files were recorded or if no dexopt was needed.
- * <p>PackageDexOptimizer.DEX_OPT_FAILED if any dexopt operation failed.
- * <p>PackageDexOptimizer.DEX_OPT_PERFORMED if all dexopt operations succeeded.
- */
- public int dexoptSystemServer(DexoptOptions options) throws LegacyDexoptDisabledException {
- // TODO(b/254043366): Clean this up.
- if (!isPlatformPackage(options.getPackageName())) {
- Slog.wtf(TAG, "Non system server package used when trying to dexopt system server:"
- + options.getPackageName());
- return PackageDexOptimizer.DEX_OPT_FAILED;
- }
-
- // Override compiler filter for system server to the expected one.
- //
- // We could let the caller do this every time the invoke PackageManagerServer#dexopt.
- // However, there are a few places were this will need to be done which creates
- // redundancy and the danger of overlooking the config (and thus generating code that will
- // waste storage and time).
- DexoptOptions overriddenOptions = options.overrideCompilerFilter(
- SYSTEM_SERVER_COMPILER_FILTER);
-
- PackageDexOptimizer pdo = getPackageDexOptimizer(overriddenOptions);
- String packageName = overriddenOptions.getPackageName();
- PackageUseInfo useInfo = getPackageUseInfoOrDefault(packageName);
- if (useInfo.getDexUseInfoMap().isEmpty()) {
- if (DEBUG) {
- Slog.d(TAG, "No dex files recorded for system server");
- }
- // Nothing to compile, return true.
- return PackageDexOptimizer.DEX_OPT_SKIPPED;
- }
-
- boolean usageUpdated = false;
- int result = PackageDexOptimizer.DEX_OPT_SKIPPED;
- for (Map.Entry<String, DexUseInfo> entry : useInfo.getDexUseInfoMap().entrySet()) {
- String dexPath = entry.getKey();
- DexUseInfo dexUseInfo = entry.getValue();
- if (!Files.exists(Paths.get(dexPath))) {
- if (DEBUG) {
- Slog.w(TAG, "A dex file previously loaded by System Server does not exist "
- + " anymore: " + dexPath);
- }
- usageUpdated = mPackageDexUsage.removeDexFile(
- packageName, dexPath, dexUseInfo.getOwnerUserId()) || usageUpdated;
- continue;
- }
-
- if (dexUseInfo.isUnsupportedClassLoaderContext()
- || dexUseInfo.isVariableClassLoaderContext()) {
- String debugMsg = dexUseInfo.isUnsupportedClassLoaderContext()
- ? "unsupported"
- : "variable";
- Slog.w(TAG, "Skipping dexopt for system server path loaded with " + debugMsg
- + " class loader context: " + dexPath);
- continue;
- }
-
- int newResult = pdo.dexoptSystemServerPath(dexPath, dexUseInfo, overriddenOptions);
-
- // The end result is:
- // - FAILED if any path failed,
- // - PERFORMED if at least one path needed compilation,
- // - SKIPPED when all paths are up to date
- if ((result != PackageDexOptimizer.DEX_OPT_FAILED)
- && (newResult != PackageDexOptimizer.DEX_OPT_SKIPPED)) {
- result = newResult;
- }
- }
-
- if (usageUpdated) {
- mPackageDexUsage.maybeWriteAsync();
- }
-
- return result;
- }
-
- /**
* Select the dex optimizer based on the force parameter.
* Forced compilation is done through ForcedUpdatePackageDexOptimizer which will adjust
* the necessary dexopt flags to make sure that compilation is not skipped. This avoid
@@ -902,7 +805,6 @@
*/
public void writePackageDexUsageNow() {
mPackageDexUsage.writeNow();
- mDynamicCodeLogger.writeNow();
}
/**
diff --git a/services/core/java/com/android/server/pm/dex/DynamicCodeLogger.java b/services/core/java/com/android/server/pm/dex/DynamicCodeLogger.java
index 9b94e99..da8fafa 100644
--- a/services/core/java/com/android/server/pm/dex/DynamicCodeLogger.java
+++ b/services/core/java/com/android/server/pm/dex/DynamicCodeLogger.java
@@ -43,6 +43,9 @@
import java.io.File;
import java.io.IOException;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
import java.util.Map;
import java.util.Set;
@@ -64,7 +67,7 @@
private final PackageDynamicCodeLoading mPackageDynamicCodeLoading;
private final Installer mInstaller;
- DynamicCodeLogger(Installer installer) {
+ public DynamicCodeLogger(Installer installer) {
mInstaller = installer;
mPackageDynamicCodeLoading = new PackageDynamicCodeLoading();
}
@@ -220,8 +223,12 @@
EventLog.writeEvent(SNET_TAG, subtag, uid, message);
}
- void recordDex(int loaderUserId, String dexPath, String owningPackageName,
- String loadingPackageName) {
+ /**
+ * Records that an app running in the specified uid has executed dex code from the file at
+ * {@code path}.
+ */
+ public void recordDex(
+ int loaderUserId, String dexPath, String owningPackageName, String loadingPackageName) {
if (mPackageDynamicCodeLoading.record(owningPackageName, dexPath,
FILE_TYPE_DEX, loaderUserId, loadingPackageName)) {
mPackageDynamicCodeLoading.maybeWriteAsync();
@@ -229,8 +236,8 @@
}
/**
- * Record that an app running in the specified uid has executed native code from the file at
- * {@param path}.
+ * Records that an app running in the specified uid has executed native code from the file at
+ * {@code path}.
*/
public void recordNative(int loadingUid, String path) {
String[] packages;
@@ -274,7 +281,39 @@
mPackageDynamicCodeLoading.syncData(packageToUsersMap);
}
- void writeNow() {
+ /** Writes the in-memory dynamic code information to disk right away. */
+ public void writeNow() {
mPackageDynamicCodeLoading.writeNow();
}
+
+ /** Reads the dynamic code information from disk. */
+ public void load(Map<Integer, List<PackageInfo>> userToPackagesMap) {
+ // Compute a reverse map.
+ Map<String, Set<Integer>> packageToUsersMap = new HashMap<>();
+ for (Map.Entry<Integer, List<PackageInfo>> entry : userToPackagesMap.entrySet()) {
+ List<PackageInfo> packageInfoList = entry.getValue();
+ int userId = entry.getKey();
+ for (PackageInfo pi : packageInfoList) {
+ Set<Integer> users =
+ packageToUsersMap.computeIfAbsent(pi.packageName, k -> new HashSet<>());
+ users.add(userId);
+ }
+ }
+
+ readAndSync(packageToUsersMap);
+ }
+
+ /**
+ * Notifies that the user {@code userId} data for package {@code packageName} was destroyed.
+ * This will remove all dynamic code information associated with the package for the given user.
+ * {@code userId} is allowed to be {@code UserHandle.USER_ALL} in which case
+ * all dynamic code information for the package will be removed.
+ */
+ public void notifyPackageDataDestroyed(String packageName, int userId) {
+ if (userId == UserHandle.USER_ALL) {
+ removePackage(packageName);
+ } else {
+ removeUserPackage(packageName, userId);
+ }
+ }
}
diff --git a/services/core/java/com/android/server/pm/parsing/pkg/PackageImpl.java b/services/core/java/com/android/server/pm/parsing/pkg/PackageImpl.java
index 1778e57..d7c4a09 100644
--- a/services/core/java/com/android/server/pm/parsing/pkg/PackageImpl.java
+++ b/services/core/java/com/android/server/pm/parsing/pkg/PackageImpl.java
@@ -1810,6 +1810,11 @@
}
@Override
+ public boolean isAllowUpdateOwnership() {
+ return getBoolean2(Booleans2.ALLOW_UPDATE_OWNERSHIP);
+ }
+
+ @Override
public boolean isVmSafeMode() {
return getBoolean(Booleans.VM_SAFE_MODE);
}
@@ -2513,6 +2518,11 @@
}
@Override
+ public PackageImpl setAllowUpdateOwnership(boolean value) {
+ return setBoolean2(Booleans2.ALLOW_UPDATE_OWNERSHIP, value);
+ }
+
+ @Override
public PackageImpl sortActivities() {
Collections.sort(this.activities, ORDER_COMPARATOR);
return this;
@@ -3726,5 +3736,6 @@
private static final long STUB = 1L;
private static final long APEX = 1L << 1;
+ private static final long ALLOW_UPDATE_OWNERSHIP = 1L << 2;
}
}
diff --git a/services/core/java/com/android/server/pm/permission/Permission.java b/services/core/java/com/android/server/pm/permission/Permission.java
index f3b9246..c81d6d7 100644
--- a/services/core/java/com/android/server/pm/permission/Permission.java
+++ b/services/core/java/com/android/server/pm/permission/Permission.java
@@ -105,6 +105,15 @@
mType = type;
}
+ public Permission(@NonNull PermissionInfo permissionInfo, @PermissionType int type,
+ boolean reconciled, int uid, int[] gids, boolean gidsPerUser) {
+ this(permissionInfo, type);
+ mReconciled = reconciled;
+ mUid = uid;
+ mGids = gids;
+ mGidsPerUser = gidsPerUser;
+ }
+
@NonNull
public PermissionInfo getPermissionInfo() {
return mPermissionInfo;
diff --git a/services/core/java/com/android/server/pm/pkg/AndroidPackage.java b/services/core/java/com/android/server/pm/pkg/AndroidPackage.java
index 78091bc..ad73873 100644
--- a/services/core/java/com/android/server/pm/pkg/AndroidPackage.java
+++ b/services/core/java/com/android/server/pm/pkg/AndroidPackage.java
@@ -1483,4 +1483,10 @@
* @hide
*/
boolean isVisibleToInstantApps();
+
+ /**
+ * @see R.styleable#AndroidManifest_allowUpdateOwnership
+ * @hide
+ */
+ boolean isAllowUpdateOwnership();
}
diff --git a/services/core/java/com/android/server/pm/pkg/mutate/PackageStateMutator.java b/services/core/java/com/android/server/pm/pkg/mutate/PackageStateMutator.java
index 4a8ef96..5947d47 100644
--- a/services/core/java/com/android/server/pm/pkg/mutate/PackageStateMutator.java
+++ b/services/core/java/com/android/server/pm/pkg/mutate/PackageStateMutator.java
@@ -291,6 +291,15 @@
return this;
}
+ @NonNull
+ @Override
+ public PackageStateWrite setUpdateOwner(@NonNull String updateOwnerPackageName) {
+ if (mState != null) {
+ mState.setUpdateOwnerPackage(updateOwnerPackageName);
+ }
+ return this;
+ }
+
private static class UserStateWriteWrapper implements PackageUserStateWrite {
@Nullable
diff --git a/services/core/java/com/android/server/pm/pkg/mutate/PackageStateWrite.java b/services/core/java/com/android/server/pm/pkg/mutate/PackageStateWrite.java
index dc9cd3b..c610c02 100644
--- a/services/core/java/com/android/server/pm/pkg/mutate/PackageStateWrite.java
+++ b/services/core/java/com/android/server/pm/pkg/mutate/PackageStateWrite.java
@@ -57,4 +57,7 @@
@NonNull
PackageStateWrite setInstaller(@Nullable String installerPackageName, int installerPackageUid);
+
+ @NonNull
+ PackageStateWrite setUpdateOwner(@Nullable String updateOwnerPackageName);
}
diff --git a/services/core/java/com/android/server/pm/pkg/parsing/ParsingPackage.java b/services/core/java/com/android/server/pm/pkg/parsing/ParsingPackage.java
index 69f2716..bb36758 100644
--- a/services/core/java/com/android/server/pm/pkg/parsing/ParsingPackage.java
+++ b/services/core/java/com/android/server/pm/pkg/parsing/ParsingPackage.java
@@ -387,6 +387,8 @@
ParsingPackage setLocaleConfigRes(int localeConfigRes);
+ ParsingPackage setAllowUpdateOwnership(boolean value);
+
/**
* Sets the trusted host certificates of apps that are allowed to embed activities of this
* application.
diff --git a/services/core/java/com/android/server/pm/pkg/parsing/ParsingPackageUtils.java b/services/core/java/com/android/server/pm/pkg/parsing/ParsingPackageUtils.java
index 995b9e5..31f291f 100644
--- a/services/core/java/com/android/server/pm/pkg/parsing/ParsingPackageUtils.java
+++ b/services/core/java/com/android/server/pm/pkg/parsing/ParsingPackageUtils.java
@@ -219,6 +219,7 @@
public static final int PARSE_DEFAULT_INSTALL_LOCATION =
PackageInfo.INSTALL_LOCATION_UNSPECIFIED;
public static final int PARSE_DEFAULT_TARGET_SANDBOX = 1;
+ public static final boolean PARSE_DEFAULT_ALLOW_UPDATE_OWNERSHIP = true;
/**
* If set to true, we will only allow package files that exactly match the DTD. Otherwise, we
@@ -247,6 +248,9 @@
private static final String MAX_NUM_COMPONENTS_ERR_MSG =
"Total number of components has exceeded the maximum number: " + MAX_NUM_COMPONENTS;
+ /** The maximum permission name length. */
+ private static final int MAX_PERMISSION_NAME_LENGTH = 512;
+
@IntDef(flag = true, prefix = { "PARSE_" }, value = {
PARSE_CHATTY,
PARSE_COLLECT_CERTIFICATES,
@@ -883,7 +887,9 @@
.setTargetSandboxVersion(anInteger(PARSE_DEFAULT_TARGET_SANDBOX,
R.styleable.AndroidManifest_targetSandboxVersion, sa))
/* Set the global "on SD card" flag */
- .setExternalStorage((flags & PARSE_EXTERNAL_STORAGE) != 0);
+ .setExternalStorage((flags & PARSE_EXTERNAL_STORAGE) != 0)
+ .setAllowUpdateOwnership(bool(PARSE_DEFAULT_ALLOW_UPDATE_OWNERSHIP,
+ R.styleable.AndroidManifest_allowUpdateOwnership, sa));
boolean foundApp = false;
final int depth = parser.getDepth();
@@ -1260,6 +1266,11 @@
// that may change.
String name = sa.getNonResourceString(
R.styleable.AndroidManifestUsesPermission_name);
+ if (TextUtils.length(name) > MAX_PERMISSION_NAME_LENGTH) {
+ return input.error(INSTALL_PARSE_FAILED_MANIFEST_MALFORMED,
+ "The name in the <uses-permission> is greater than "
+ + MAX_PERMISSION_NAME_LENGTH);
+ }
int minSdkVersion = parseMinOrMaxSdkVersion(sa,
R.styleable.AndroidManifestUsesPermission_minSdkVersion,
diff --git a/services/core/java/com/android/server/policy/PhoneWindowManager.java b/services/core/java/com/android/server/policy/PhoneWindowManager.java
index 65acdc1..a099e72 100644
--- a/services/core/java/com/android/server/policy/PhoneWindowManager.java
+++ b/services/core/java/com/android/server/policy/PhoneWindowManager.java
@@ -661,7 +661,7 @@
dispatchMediaKeyRepeatWithWakeLock((KeyEvent)msg.obj);
break;
case MSG_DISPATCH_SHOW_RECENTS:
- showRecentApps(false);
+ showRecents();
break;
case MSG_DISPATCH_SHOW_GLOBAL_ACTIONS:
showGlobalActionsInternal();
@@ -2910,7 +2910,7 @@
break;
case KeyEvent.KEYCODE_RECENT_APPS:
if (down && repeatCount == 0) {
- showRecentApps(false /* triggeredFromAltTab */);
+ showRecents();
}
return key_consumed;
case KeyEvent.KEYCODE_APP_SWITCH:
@@ -3094,22 +3094,23 @@
}
break;
case KeyEvent.KEYCODE_TAB:
- if (down && event.isMetaPressed()) {
- if (!keyguardOn && isUserSetupComplete()) {
- showRecentApps(false);
- return key_consumed;
- }
- } else if (down && repeatCount == 0) {
- // Display task switcher for ALT-TAB.
- if (mRecentAppsHeldModifiers == 0 && !keyguardOn && isUserSetupComplete()) {
- final int shiftlessModifiers =
- event.getModifiers() & ~KeyEvent.META_SHIFT_MASK;
- if (KeyEvent.metaStateHasModifiers(
- shiftlessModifiers, KeyEvent.META_ALT_ON)) {
- mRecentAppsHeldModifiers = shiftlessModifiers;
- showRecentApps(true);
+ if (down) {
+ if (event.isMetaPressed()) {
+ if (!keyguardOn && isUserSetupComplete()) {
+ showRecents();
return key_consumed;
}
+ } else {
+ // Display task switcher for ALT-TAB.
+ if (mRecentAppsHeldModifiers == 0 && !keyguardOn && isUserSetupComplete()) {
+ final int modifiers = event.getModifiers();
+ if (KeyEvent.metaStateHasModifiers(modifiers, KeyEvent.META_ALT_ON)) {
+ mRecentAppsHeldModifiers = modifiers;
+ showRecentsFromAltTab(KeyEvent.metaStateHasModifiers(modifiers,
+ KeyEvent.META_SHIFT_ON));
+ return key_consumed;
+ }
+ }
}
}
break;
@@ -3646,11 +3647,19 @@
mHandler.obtainMessage(MSG_DISPATCH_SHOW_RECENTS).sendToTarget();
}
- private void showRecentApps(boolean triggeredFromAltTab) {
+ private void showRecents() {
mPreloadedRecentApps = false; // preloading no longer needs to be canceled
StatusBarManagerInternal statusbar = getStatusBarManagerInternal();
if (statusbar != null) {
- statusbar.showRecentApps(triggeredFromAltTab);
+ statusbar.showRecentApps(false /* triggeredFromAltTab */, false /* forward */);
+ }
+ }
+
+ private void showRecentsFromAltTab(boolean forward) {
+ mPreloadedRecentApps = false; // preloading no longer needs to be canceled
+ StatusBarManagerInternal statusbar = getStatusBarManagerInternal();
+ if (statusbar != null) {
+ statusbar.showRecentApps(true /* triggeredFromAltTab */, forward);
}
}
@@ -4299,9 +4308,6 @@
case KeyEvent.KEYCODE_DEMO_APP_2:
case KeyEvent.KEYCODE_DEMO_APP_3:
case KeyEvent.KEYCODE_DEMO_APP_4: {
- // TODO(b/254604589): Dispatch KeyEvent to System UI.
- sendSystemKeyToStatusBarAsync(keyCode);
-
// Just drop if keys are not intercepted for direct key.
result &= ~ACTION_PASS_TO_USER;
break;
diff --git a/services/core/java/com/android/server/power/PowerManagerService.java b/services/core/java/com/android/server/power/PowerManagerService.java
index 884d5d6..c29ab09 100644
--- a/services/core/java/com/android/server/power/PowerManagerService.java
+++ b/services/core/java/com/android/server/power/PowerManagerService.java
@@ -3229,8 +3229,7 @@
}
final PowerGroup powerGroup = mPowerGroups.get(groupId);
wakefulness = powerGroup.getWakefulnessLocked();
- if ((wakefulness == WAKEFULNESS_DREAMING || wakefulness == WAKEFULNESS_DOZING) &&
- powerGroup.isSandmanSummonedLocked() && powerGroup.isReadyLocked()) {
+ if (powerGroup.isSandmanSummonedLocked() && powerGroup.isReadyLocked()) {
startDreaming = canDreamLocked(powerGroup) || canDozeLocked(powerGroup);
powerGroup.setSandmanSummonedLocked(/* isSandmanSummoned= */ false);
} else {
diff --git a/services/core/java/com/android/server/security/rkp/RemoteProvisioningRegistration.java b/services/core/java/com/android/server/security/rkp/RemoteProvisioningRegistration.java
index 868f34b..0e92709 100644
--- a/services/core/java/com/android/server/security/rkp/RemoteProvisioningRegistration.java
+++ b/services/core/java/com/android/server/security/rkp/RemoteProvisioningRegistration.java
@@ -21,10 +21,12 @@
import android.os.OutcomeReceiver;
import android.security.rkp.IGetKeyCallback;
import android.security.rkp.IRegistration;
+import android.security.rkp.IStoreUpgradedKeyCallback;
import android.security.rkp.service.RegistrationProxy;
import android.security.rkp.service.RemotelyProvisionedKey;
import android.util.Log;
+import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.Executor;
@@ -36,8 +38,10 @@
*/
final class RemoteProvisioningRegistration extends IRegistration.Stub {
static final String TAG = RemoteProvisioningService.TAG;
- private final ConcurrentHashMap<IGetKeyCallback, CancellationSignal> mOperations =
+ private final ConcurrentHashMap<IGetKeyCallback, CancellationSignal> mGetKeyOperations =
new ConcurrentHashMap<>();
+ private final Set<IStoreUpgradedKeyCallback> mStoreUpgradedKeyOperations =
+ ConcurrentHashMap.newKeySet();
private final RegistrationProxy mRegistration;
private final Executor mExecutor;
@@ -49,7 +53,7 @@
@Override
public void onResult(RemotelyProvisionedKey result) {
- mOperations.remove(mCallback);
+ mGetKeyOperations.remove(mCallback);
Log.i(TAG, "Successfully fetched key for client " + mCallback.hashCode());
android.security.rkp.RemotelyProvisionedKey parcelable =
new android.security.rkp.RemotelyProvisionedKey();
@@ -60,7 +64,7 @@
@Override
public void onError(Exception e) {
- mOperations.remove(mCallback);
+ mGetKeyOperations.remove(mCallback);
if (e instanceof OperationCanceledException) {
Log.i(TAG, "Operation cancelled for client " + mCallback.hashCode());
wrapCallback(mCallback::onCancel);
@@ -79,7 +83,7 @@
@Override
public void getKey(int keyId, IGetKeyCallback callback) {
CancellationSignal cancellationSignal = new CancellationSignal();
- if (mOperations.putIfAbsent(callback, cancellationSignal) != null) {
+ if (mGetKeyOperations.putIfAbsent(callback, cancellationSignal) != null) {
Log.e(TAG, "Client can only request one call at a time " + callback.hashCode());
throw new IllegalArgumentException(
"Callback is already associated with an existing operation: "
@@ -92,14 +96,14 @@
new GetKeyReceiver(callback));
} catch (Exception e) {
Log.e(TAG, "getKeyAsync threw an exception for client " + callback.hashCode(), e);
- mOperations.remove(callback);
+ mGetKeyOperations.remove(callback);
wrapCallback(() -> callback.onError(e.getMessage()));
}
}
@Override
public void cancelGetKey(IGetKeyCallback callback) {
- CancellationSignal cancellationSignal = mOperations.remove(callback);
+ CancellationSignal cancellationSignal = mGetKeyOperations.remove(callback);
if (cancellationSignal == null) {
throw new IllegalArgumentException(
"Invalid client in cancelGetKey: " + callback.hashCode());
@@ -110,9 +114,35 @@
}
@Override
- public void storeUpgradedKey(byte[] oldKeyBlob, byte[] newKeyBlob) {
- // TODO(b/262748535)
- Log.e(TAG, "RegistrationBinder.storeUpgradedKey NOT YET IMPLEMENTED");
+ public void storeUpgradedKeyAsync(byte[] oldKeyBlob, byte[] newKeyBlob,
+ IStoreUpgradedKeyCallback callback) {
+ if (!mStoreUpgradedKeyOperations.add(callback)) {
+ throw new IllegalArgumentException(
+ "Callback is already associated with an existing operation: "
+ + callback.hashCode());
+ }
+
+ try {
+ mRegistration.storeUpgradedKeyAsync(oldKeyBlob, newKeyBlob, mExecutor,
+ new OutcomeReceiver<>() {
+ @Override
+ public void onResult(Void result) {
+ mStoreUpgradedKeyOperations.remove(callback);
+ wrapCallback(callback::onSuccess);
+ }
+
+ @Override
+ public void onError(Exception e) {
+ mStoreUpgradedKeyOperations.remove(callback);
+ wrapCallback(() -> callback.onError(e.getMessage()));
+ }
+ });
+ } catch (Exception e) {
+ Log.e(TAG, "storeUpgradedKeyAsync threw an exception for client "
+ + callback.hashCode(), e);
+ mStoreUpgradedKeyOperations.remove(callback);
+ wrapCallback(() -> callback.onError(e.getMessage()));
+ }
}
interface CallbackRunner {
diff --git a/services/core/java/com/android/server/statusbar/StatusBarManagerInternal.java b/services/core/java/com/android/server/statusbar/StatusBarManagerInternal.java
index 392fda9..0fd6d9b 100644
--- a/services/core/java/com/android/server/statusbar/StatusBarManagerInternal.java
+++ b/services/core/java/com/android/server/statusbar/StatusBarManagerInternal.java
@@ -39,7 +39,7 @@
void cancelPreloadRecentApps();
- void showRecentApps(boolean triggeredFromAltTab);
+ void showRecentApps(boolean triggeredFromAltTab, boolean forward);
void hideRecentApps(boolean triggeredFromAltTab, boolean triggeredFromHomeKey);
diff --git a/services/core/java/com/android/server/statusbar/StatusBarManagerService.java b/services/core/java/com/android/server/statusbar/StatusBarManagerService.java
index 8d71d9c..97ca8df 100644
--- a/services/core/java/com/android/server/statusbar/StatusBarManagerService.java
+++ b/services/core/java/com/android/server/statusbar/StatusBarManagerService.java
@@ -454,10 +454,10 @@
}
@Override
- public void showRecentApps(boolean triggeredFromAltTab) {
+ public void showRecentApps(boolean triggeredFromAltTab, boolean forward) {
if (mBar != null) {
try {
- mBar.showRecentApps(triggeredFromAltTab);
+ mBar.showRecentApps(triggeredFromAltTab, forward);
} catch (RemoteException ex) {}
}
}
diff --git a/services/core/java/com/android/server/timedetector/NetworkTimeUpdateService.java b/services/core/java/com/android/server/timedetector/NetworkTimeUpdateService.java
index b96af89..0809297 100644
--- a/services/core/java/com/android/server/timedetector/NetworkTimeUpdateService.java
+++ b/services/core/java/com/android/server/timedetector/NetworkTimeUpdateService.java
@@ -16,8 +16,10 @@
package com.android.server.timedetector;
+import android.annotation.ElapsedRealtimeLong;
import android.annotation.NonNull;
import android.annotation.Nullable;
+import android.annotation.RequiresPermission;
import android.app.AlarmManager;
import android.app.PendingIntent;
import android.app.time.UnixEpochTime;
@@ -33,18 +35,19 @@
import android.os.Binder;
import android.os.Handler;
import android.os.HandlerThread;
-import android.os.Looper;
-import android.os.Message;
import android.os.PowerManager;
import android.os.ResultReceiver;
import android.os.ShellCallback;
import android.os.SystemClock;
import android.provider.Settings;
+import android.util.IndentingPrintWriter;
import android.util.LocalLog;
import android.util.Log;
import android.util.NtpTrustedTime;
import android.util.NtpTrustedTime.TimeResult;
+import com.android.internal.annotations.GuardedBy;
+import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.util.DumpUtils;
import com.android.server.LocalServices;
@@ -52,12 +55,17 @@
import java.io.PrintWriter;
import java.time.Duration;
import java.util.Objects;
+import java.util.function.Supplier;
/**
- * Monitors the network time. If looking up the network time fails for some reason, it tries a few
- * times with a short interval and then resets to checking on longer intervals.
+ * Refreshes network time periodically, when network connectivity becomes available and when the
+ * user enables automatic time detection.
*
- * <p>When available, the time is always suggested to the {@link
+ * <p>For periodic requests, this service attempts to leave an interval between successful requests.
+ * If a request fails, it retries a number of times with a "short" interval and then resets to the
+ * normal interval. The process then repeats.
+ *
+ * <p>When a valid network time is available, the time is always suggested to the {@link
* com.android.server.timedetector.TimeDetectorService} where it may be used to set the device
* system clock, depending on user settings and what other signals are available.
*/
@@ -66,101 +74,110 @@
private static final String TAG = "NetworkTimeUpdateService";
private static final boolean DBG = false;
- private static final int EVENT_AUTO_TIME_ENABLED = 1;
- private static final int EVENT_POLL_NETWORK_TIME = 2;
- private static final int EVENT_NETWORK_CHANGED = 3;
-
private static final String ACTION_POLL =
"com.android.server.timedetector.NetworkTimeUpdateService.action.POLL";
-
private static final int POLL_REQUEST = 0;
+ private final Object mLock = new Object();
private final Context mContext;
- private final NtpTrustedTime mTime;
- private final AlarmManager mAlarmManager;
- private final TimeDetectorInternal mTimeDetectorInternal;
private final ConnectivityManager mCM;
- private final PendingIntent mPendingPollIntent;
private final PowerManager.WakeLock mWakeLock;
+ private final NtpTrustedTime mNtpTrustedTime;
+ private final Engine.RefreshCallbacks mRefreshCallbacks;
+ private final Engine mEngine;
- // Normal polling frequency
- private final long mPollingIntervalMs;
- // Try-again polling interval, in case the network request failed
- private final long mPollingIntervalShorterMs;
- // Number of times to try again
- private final int mTryAgainTimesMax;
-
- /**
- * A log that records the decisions to fetch a network time update.
- * This is logged in bug reports to assist with debugging issues with network time suggestions.
- */
- @NonNull
- private final LocalLog mLocalLog = new LocalLog(30, false /* useLocalTimestamps */);
-
- // NTP lookup is done on this thread and handler
- // @NonNull after systemRunning()
- private Handler mHandler;
- // @NonNull after systemRunning()
- private AutoTimeSettingObserver mAutoTimeSettingObserver;
- // @NonNull after systemRunning()
- private NetworkTimeUpdateCallback mNetworkTimeUpdateCallback;
+ // Blocking NTP lookup is done using this handler
+ private final Handler mHandler;
// This field is only updated and accessed by the mHandler thread (except dump()).
+ @GuardedBy("mLock")
@Nullable
private Network mDefaultNetwork = null;
- // Keeps track of how many quick attempts were made to fetch NTP time.
- // During bootup, the network may not have been up yet, or it's taking time for the
- // connection to happen.
- // This field is only updated and accessed by the mHandler thread (except dump()).
- private int mTryAgainCounter;
-
public NetworkTimeUpdateService(@NonNull Context context) {
mContext = Objects.requireNonNull(context);
- mTime = NtpTrustedTime.getInstance(context);
- mAlarmManager = mContext.getSystemService(AlarmManager.class);
- mTimeDetectorInternal = LocalServices.getService(TimeDetectorInternal.class);
mCM = mContext.getSystemService(ConnectivityManager.class);
-
- Intent pollIntent = new Intent(ACTION_POLL, null);
- // Broadcast alarms sent by system are immutable
- mPendingPollIntent = PendingIntent.getBroadcast(mContext, POLL_REQUEST, pollIntent,
- PendingIntent.FLAG_IMMUTABLE);
-
- mPollingIntervalMs = mContext.getResources().getInteger(
- com.android.internal.R.integer.config_ntpPollingInterval);
- mPollingIntervalShorterMs = mContext.getResources().getInteger(
- com.android.internal.R.integer.config_ntpPollingIntervalShorter);
- mTryAgainTimesMax = mContext.getResources().getInteger(
- com.android.internal.R.integer.config_ntpRetry);
-
mWakeLock = context.getSystemService(PowerManager.class).newWakeLock(
PowerManager.PARTIAL_WAKE_LOCK, TAG);
+ mNtpTrustedTime = NtpTrustedTime.getInstance(context);
+
+ Supplier<Long> elapsedRealtimeMillisSupplier = SystemClock::elapsedRealtime;
+ int tryAgainTimesMax = mContext.getResources().getInteger(
+ com.android.internal.R.integer.config_ntpRetry);
+ int normalPollingIntervalMillis = mContext.getResources().getInteger(
+ com.android.internal.R.integer.config_ntpPollingInterval);
+ int shortPollingIntervalMillis = mContext.getResources().getInteger(
+ com.android.internal.R.integer.config_ntpPollingIntervalShorter);
+ mEngine = new EngineImpl(elapsedRealtimeMillisSupplier, normalPollingIntervalMillis,
+ shortPollingIntervalMillis, tryAgainTimesMax, mNtpTrustedTime);
+
+ AlarmManager alarmManager = mContext.getSystemService(AlarmManager.class);
+ TimeDetectorInternal timeDetectorInternal =
+ LocalServices.getService(TimeDetectorInternal.class);
+ // Broadcast alarms sent by system are immutable
+ Intent pollIntent = new Intent(ACTION_POLL, null);
+ PendingIntent pendingPollIntent = PendingIntent.getBroadcast(mContext, POLL_REQUEST,
+ pollIntent, PendingIntent.FLAG_IMMUTABLE);
+ mRefreshCallbacks = new Engine.RefreshCallbacks() {
+ @Override
+ public void scheduleNextRefresh(@ElapsedRealtimeLong long elapsedRealtimeMillis) {
+ alarmManager.cancel(pendingPollIntent);
+ alarmManager.set(
+ AlarmManager.ELAPSED_REALTIME, elapsedRealtimeMillis, pendingPollIntent);
+ }
+
+ @Override
+ public void submitSuggestion(NetworkTimeSuggestion suggestion) {
+ timeDetectorInternal.suggestNetworkTime(suggestion);
+ }
+ };
+
+ HandlerThread thread = new HandlerThread(TAG);
+ thread.start();
+ mHandler = thread.getThreadHandler();
}
/** Initialize the receivers and initiate the first NTP request */
public void systemRunning() {
- registerForAlarms();
-
- HandlerThread thread = new HandlerThread(TAG);
- thread.start();
- mHandler = new MyHandler(thread.getLooper());
- mNetworkTimeUpdateCallback = new NetworkTimeUpdateCallback();
- mCM.registerDefaultNetworkCallback(mNetworkTimeUpdateCallback, mHandler);
-
- mAutoTimeSettingObserver = new AutoTimeSettingObserver(mContext, mHandler,
- EVENT_AUTO_TIME_ENABLED);
- mAutoTimeSettingObserver.observe();
- }
-
- private void registerForAlarms() {
+ // Listen for scheduled refreshes.
mContext.registerReceiver(
new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
- mHandler.obtainMessage(EVENT_POLL_NETWORK_TIME).sendToTarget();
+ onPollNetworkTime("scheduled refresh");
}
- }, new IntentFilter(ACTION_POLL));
+ },
+ new IntentFilter(ACTION_POLL),
+ /*broadcastPermission=*/ null,
+ mHandler);
+
+ // Listen for network connectivity changes.
+ NetworkTimeUpdateCallback networkTimeUpdateCallback = new NetworkTimeUpdateCallback();
+ mCM.registerDefaultNetworkCallback(networkTimeUpdateCallback, mHandler);
+
+ // Listen for user settings changes.
+ ContentResolver resolver = mContext.getContentResolver();
+ AutoTimeSettingObserver autoTimeSettingObserver =
+ new AutoTimeSettingObserver(mHandler, mContext);
+ resolver.registerContentObserver(Settings.Global.getUriFor(Settings.Global.AUTO_TIME),
+ false, autoTimeSettingObserver);
+ }
+
+ /**
+ * Overrides the NTP server config for tests. Passing {@code null} to a parameter clears the
+ * test value, i.e. so the normal value will be used next time.
+ */
+ @RequiresPermission(android.Manifest.permission.SET_TIME)
+ void setServerConfigForTests(@Nullable NtpTrustedTime.NtpConfig ntpConfig) {
+ mContext.enforceCallingPermission(
+ android.Manifest.permission.SET_TIME, "set NTP server config for tests");
+
+ final long token = Binder.clearCallingIdentity();
+ try {
+ mNtpTrustedTime.setServerConfigForTests(ntpConfig);
+ } finally {
+ Binder.restoreCallingIdentity(token);
+ }
}
/**
@@ -168,15 +185,14 @@
*
* <p>This operation takes place in the calling thread rather than the service's handler thread.
*/
+ @RequiresPermission(android.Manifest.permission.SET_TIME)
void clearTimeForTests() {
mContext.enforceCallingPermission(
android.Manifest.permission.SET_TIME, "clear latest network time");
final long token = Binder.clearCallingIdentity();
try {
- mTime.clearCachedTimeResult();
-
- mLocalLog.log("clearTimeForTests");
+ mNtpTrustedTime.clearCachedTimeResult();
} finally {
Binder.restoreCallingIdentity(token);
}
@@ -186,164 +202,67 @@
* Forces the service to refresh the NTP time.
*
* <p>This operation takes place in the calling thread rather than the service's handler thread.
- * This method does not affect currently scheduled refreshes. If the NTP request is successful
- * it will make an (asynchronously handled) suggestion to the time detector.
+ * This method does not affect currently scheduled refreshes.
+ *
+ * <p>If the NTP request is successful it will synchronously make a suggestion to the time
+ * detector, which will be asynchronously handled; therefore the effects are not guaranteed to
+ * be visible when this call returns.
*/
+ @RequiresPermission(android.Manifest.permission.SET_TIME)
boolean forceRefreshForTests() {
mContext.enforceCallingPermission(
android.Manifest.permission.SET_TIME, "force network time refresh");
final long token = Binder.clearCallingIdentity();
try {
- boolean success = mTime.forceRefresh();
- mLocalLog.log("forceRefreshForTests: success=" + success);
-
- if (success) {
- makeNetworkTimeSuggestion(mTime.getCachedTimeResult(),
- "Origin: NetworkTimeUpdateService: forceRefreshForTests");
+ Network network;
+ synchronized (mLock) {
+ network = mDefaultNetwork;
}
- return success;
+ if (network == null) return false;
+
+ return mEngine.forceRefreshForTests(network, mRefreshCallbacks);
} finally {
Binder.restoreCallingIdentity(token);
}
}
- /**
- * Overrides the NTP server config for tests. Passing {@code null} to a parameter clears the
- * test value, i.e. so the normal value will be used next time.
- */
- void setServerConfigForTests(@Nullable NtpTrustedTime.NtpConfig ntpConfig) {
- mContext.enforceCallingPermission(
- android.Manifest.permission.SET_TIME, "set NTP server config for tests");
-
- final long token = Binder.clearCallingIdentity();
- try {
- mLocalLog.log("Setting server config for tests: ntpConnectionInfo=" + ntpConfig);
- mTime.setServerConfigForTests(ntpConfig);
- } finally {
- Binder.restoreCallingIdentity(token);
- }
- }
-
- private void onPollNetworkTime(int event) {
+ private void onPollNetworkTime(@NonNull String reason) {
// If we don't have any default network, don't bother.
- Network network = mDefaultNetwork;
+ Network network;
+ synchronized (mLock) {
+ network = mDefaultNetwork;
+ }
if (network == null) return;
mWakeLock.acquire();
try {
- onPollNetworkTimeUnderWakeLock(network, event);
+ mEngine.refreshIfRequiredAndReschedule(network, reason, mRefreshCallbacks);
} finally {
mWakeLock.release();
}
}
- private void onPollNetworkTimeUnderWakeLock(@NonNull Network network, int event) {
- long currentElapsedRealtimeMillis = SystemClock.elapsedRealtime();
-
- // Force an NTP fix when outdated
- NtpTrustedTime.TimeResult cachedNtpResult = mTime.getCachedTimeResult();
- if (cachedNtpResult == null || cachedNtpResult.getAgeMillis(currentElapsedRealtimeMillis)
- >= mPollingIntervalMs) {
- if (DBG) Log.d(TAG, "Stale NTP fix; forcing refresh using network=" + network);
- boolean isSuccessful = mTime.forceRefresh(network);
- if (isSuccessful) {
- mTryAgainCounter = 0;
- } else {
- String logMsg = "forceRefresh() returned false: cachedNtpResult=" + cachedNtpResult
- + ", currentElapsedRealtimeMillis=" + currentElapsedRealtimeMillis;
-
- if (DBG) {
- Log.d(TAG, logMsg);
- }
- mLocalLog.log(logMsg);
- }
-
- cachedNtpResult = mTime.getCachedTimeResult();
- }
-
- if (cachedNtpResult != null
- && cachedNtpResult.getAgeMillis(currentElapsedRealtimeMillis)
- < mPollingIntervalMs) {
- // Obtained fresh fix; schedule next normal update
- resetAlarm(mPollingIntervalMs
- - cachedNtpResult.getAgeMillis(currentElapsedRealtimeMillis));
-
- makeNetworkTimeSuggestion(cachedNtpResult,
- "Origin: NetworkTimeUpdateService. event=" + event);
- } else {
- // No fresh fix; schedule retry
- mTryAgainCounter++;
- if (mTryAgainTimesMax < 0 || mTryAgainCounter <= mTryAgainTimesMax) {
- resetAlarm(mPollingIntervalShorterMs);
- } else {
- // Try much later
- String logMsg = "mTryAgainTimesMax exceeded, cachedNtpResult=" + cachedNtpResult;
- if (DBG) {
- Log.d(TAG, logMsg);
- }
- mLocalLog.log(logMsg);
- mTryAgainCounter = 0;
- resetAlarm(mPollingIntervalMs);
- }
- }
- }
-
- /** Suggests the time to the time detector. It may choose use it to set the system clock. */
- private void makeNetworkTimeSuggestion(
- @NonNull TimeResult ntpResult, @NonNull String debugInfo) {
- UnixEpochTime timeSignal = new UnixEpochTime(
- ntpResult.getElapsedRealtimeMillis(), ntpResult.getTimeMillis());
- NetworkTimeSuggestion timeSuggestion =
- new NetworkTimeSuggestion(timeSignal, ntpResult.getUncertaintyMillis());
- timeSuggestion.addDebugInfo(debugInfo);
- timeSuggestion.addDebugInfo(ntpResult.toString());
- mTimeDetectorInternal.suggestNetworkTime(timeSuggestion);
- }
-
- /**
- * Cancel old alarm and starts a new one for the specified interval.
- *
- * @param interval when to trigger the alarm, starting from now.
- */
- private void resetAlarm(long interval) {
- mAlarmManager.cancel(mPendingPollIntent);
- long now = SystemClock.elapsedRealtime();
- long next = now + interval;
- mAlarmManager.set(AlarmManager.ELAPSED_REALTIME, next, mPendingPollIntent);
- }
-
- /** Handler to do the network accesses on */
- private class MyHandler extends Handler {
-
- MyHandler(Looper l) {
- super(l);
- }
-
- @Override
- public void handleMessage(@NonNull Message msg) {
- switch (msg.what) {
- case EVENT_AUTO_TIME_ENABLED:
- case EVENT_POLL_NETWORK_TIME:
- case EVENT_NETWORK_CHANGED:
- onPollNetworkTime(msg.what);
- break;
- }
- }
- }
-
+ // All callbacks will be invoked using mHandler because of how the callback is registered.
private class NetworkTimeUpdateCallback extends NetworkCallback {
@Override
public void onAvailable(@NonNull Network network) {
Log.d(TAG, String.format("New default network %s; checking time.", network));
- mDefaultNetwork = network;
+ synchronized (mLock) {
+ mDefaultNetwork = network;
+ }
+
// Running on mHandler so invoke directly.
- onPollNetworkTime(EVENT_NETWORK_CHANGED);
+ onPollNetworkTime("network available");
}
@Override
public void onLost(@NonNull Network network) {
- if (network.equals(mDefaultNetwork)) mDefaultNetwork = null;
+ synchronized (mLock) {
+ if (network.equals(mDefaultNetwork)) {
+ mDefaultNetwork = null;
+ }
+ }
}
}
@@ -351,29 +270,20 @@
* Observer to watch for changes to the AUTO_TIME setting. It only triggers when the setting
* is enabled.
*/
- private static class AutoTimeSettingObserver extends ContentObserver {
+ private class AutoTimeSettingObserver extends ContentObserver {
private final Context mContext;
- private final int mMsg;
- private final Handler mHandler;
- AutoTimeSettingObserver(@NonNull Context context, @NonNull Handler handler, int msg) {
+ AutoTimeSettingObserver(@NonNull Handler handler, @NonNull Context context) {
super(handler);
mContext = Objects.requireNonNull(context);
- mHandler = Objects.requireNonNull(handler);
- mMsg = msg;
- }
-
- void observe() {
- ContentResolver resolver = mContext.getContentResolver();
- resolver.registerContentObserver(Settings.Global.getUriFor(Settings.Global.AUTO_TIME),
- false, this);
}
@Override
public void onChange(boolean selfChange) {
+ // onChange() will be invoked using handler, see the constructor.
if (isAutomaticTimeEnabled()) {
- mHandler.obtainMessage(mMsg).sendToTarget();
+ onPollNetworkTime("automatic time enabled");
}
}
@@ -389,17 +299,11 @@
@Override
protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
if (!DumpUtils.checkDumpPermission(mContext, TAG, pw)) return;
- pw.println("mPollingIntervalMs=" + Duration.ofMillis(mPollingIntervalMs));
- pw.println("mPollingIntervalShorterMs=" + Duration.ofMillis(mPollingIntervalShorterMs));
- pw.println("mTryAgainTimesMax=" + mTryAgainTimesMax);
- pw.println("mDefaultNetwork=" + mDefaultNetwork);
- pw.println("mTryAgainCounter=" + mTryAgainCounter);
- pw.println();
- pw.println("NtpTrustedTime:");
- mTime.dump(pw);
- pw.println();
- pw.println("Local logs:");
- mLocalLog.dump(fd, pw, args);
+
+ synchronized (mLock) {
+ pw.println("mDefaultNetwork=" + mDefaultNetwork);
+ }
+ mEngine.dump(pw);
pw.println();
}
@@ -409,4 +313,331 @@
new NetworkTimeUpdateServiceShellCommand(this).exec(
this, in, out, err, args, callback, resultReceiver);
}
+
+ /**
+ * The interface the service uses to interact with the time refresh logic.
+ * Extracted for testing.
+ */
+ @VisibleForTesting
+ interface Engine {
+ interface RefreshCallbacks {
+ void scheduleNextRefresh(@ElapsedRealtimeLong long elapsedRealtimeMillis);
+
+ void submitSuggestion(@NonNull NetworkTimeSuggestion suggestion);
+ }
+
+ /**
+ * Forces the engine to refresh the network time (for tests). See {@link
+ * NetworkTimeUpdateService#forceRefreshForTests()}. This is a blocking call. This method
+ * must not schedule any calls.
+ */
+ boolean forceRefreshForTests(
+ @NonNull Network network, @NonNull RefreshCallbacks refreshCallbacks);
+
+ /**
+ * Attempts to refresh the network time if required, i.e. if there isn't a recent-enough
+ * network time available. It must also schedule the next call. This is a blocking call.
+ *
+ * @param network the network to use
+ * @param reason the reason for the refresh (for logging)
+ */
+ void refreshIfRequiredAndReschedule(@NonNull Network network, @NonNull String reason,
+ @NonNull RefreshCallbacks refreshCallbacks);
+
+ void dump(@NonNull PrintWriter pw);
+ }
+
+ @VisibleForTesting
+ static class EngineImpl implements Engine {
+
+ /**
+ * A log that records the decisions to fetch a network time update.
+ * This is logged in bug reports to assist with debugging issues with network time
+ * suggestions.
+ */
+ @NonNull
+ private final LocalLog mLocalDebugLog = new LocalLog(30, false /* useLocalTimestamps */);
+
+ /**
+ * The usual interval between refresh attempts. Always used after a successful request.
+ *
+ * <p>The value also determines whether a network time result is considered fresh.
+ * Refreshes only take place from this class when the latest time result is considered too
+ * old.
+ */
+ private final int mNormalPollingIntervalMillis;
+
+ /**
+ * A shortened interval between refresh attempts used after a failure to refresh.
+ * Always shorter than {@link #mNormalPollingIntervalMillis} and only used when {@link
+ * #mTryAgainTimesMax} != 0.
+ *
+ * <p>This value is also the lower bound for the interval allowed between successive
+ * refreshes when the latest time result is missing or too old, e.g. a refresh may not be
+ * triggered when network connectivity is restored if the last attempt was too recent.
+ */
+ private final int mShortPollingIntervalMillis;
+
+ /**
+ * The number of times {@link #mShortPollingIntervalMillis} can be used after successive
+ * failures before switching back to using {@link #mNormalPollingIntervalMillis} once before
+ * repeating. When this value is negative, the refresh algorithm will continue to use {@link
+ * #mShortPollingIntervalMillis} until a successful refresh.
+ */
+ private final int mTryAgainTimesMax;
+
+ private final NtpTrustedTime mNtpTrustedTime;
+
+ /**
+ * Records the time of the last refresh attempt (successful or otherwise) by this service.
+ * This is used when scheduling the next refresh attempt. In cases where {@link
+ * #refreshIfRequiredAndReschedule} is called too frequently, this will prevent each call
+ * resulting in a network request. See also {@link #mShortPollingIntervalMillis}.
+ *
+ * <p>Time servers are a shared resource and so Android should avoid loading them.
+ * Generally, a refresh attempt will succeed and the service won't need to make further
+ * requests and this field will not limit requests.
+ */
+ // This field is only updated and accessed by the mHandler thread (except dump()).
+ @GuardedBy("this")
+ @ElapsedRealtimeLong
+ private Long mLastRefreshAttemptElapsedRealtimeMillis;
+
+ /**
+ * Keeps track of successive time refresh failures have occurred. This is reset to zero when
+ * time refresh is successful or if the number exceeds (a non-negative) {@link
+ * #mTryAgainTimesMax}.
+ */
+ @GuardedBy("this")
+ private int mTryAgainCounter;
+
+ private final Supplier<Long> mElapsedRealtimeMillisSupplier;
+
+ @VisibleForTesting
+ EngineImpl(@NonNull Supplier<Long> elapsedRealtimeMillisSupplier,
+ int normalPollingIntervalMillis, int shortPollingIntervalMillis,
+ int tryAgainTimesMax, @NonNull NtpTrustedTime ntpTrustedTime) {
+ mElapsedRealtimeMillisSupplier = Objects.requireNonNull(elapsedRealtimeMillisSupplier);
+ if (shortPollingIntervalMillis > normalPollingIntervalMillis) {
+ throw new IllegalArgumentException(String.format(
+ "shortPollingIntervalMillis (%s) > normalPollingIntervalMillis (%s)",
+ shortPollingIntervalMillis, normalPollingIntervalMillis));
+ }
+ mNormalPollingIntervalMillis = normalPollingIntervalMillis;
+ mShortPollingIntervalMillis = shortPollingIntervalMillis;
+ mTryAgainTimesMax = tryAgainTimesMax;
+ mNtpTrustedTime = Objects.requireNonNull(ntpTrustedTime);
+ }
+
+ @Override
+ public boolean forceRefreshForTests(
+ @NonNull Network network, @NonNull RefreshCallbacks refreshCallbacks) {
+ boolean refreshSuccessful = tryRefresh(network);
+ logToDebugAndDumpsys("forceRefreshForTests: refreshSuccessful=" + refreshSuccessful);
+
+ if (refreshSuccessful) {
+ makeNetworkTimeSuggestion(mNtpTrustedTime.getCachedTimeResult(),
+ "EngineImpl.forceRefreshForTests()", refreshCallbacks);
+ }
+ return refreshSuccessful;
+ }
+
+ @Override
+ public void refreshIfRequiredAndReschedule(
+ @NonNull Network network, @NonNull String reason,
+ @NonNull RefreshCallbacks refreshCallbacks) {
+ // Attempt to refresh the network time if there is no latest time result, or if the
+ // latest time result is considered too old.
+ NtpTrustedTime.TimeResult initialTimeResult = mNtpTrustedTime.getCachedTimeResult();
+ boolean shouldAttemptRefresh;
+ synchronized (this) {
+ long currentElapsedRealtimeMillis = mElapsedRealtimeMillisSupplier.get();
+
+ // calculateTimeResultAgeMillis() safely handles a null initialTimeResult.
+ long timeResultAgeMillis = calculateTimeResultAgeMillis(
+ initialTimeResult, currentElapsedRealtimeMillis);
+ shouldAttemptRefresh =
+ timeResultAgeMillis >= mNormalPollingIntervalMillis
+ && isRefreshAllowed(currentElapsedRealtimeMillis);
+ }
+
+ boolean refreshSuccessful = false;
+ if (shouldAttemptRefresh) {
+ // This is a blocking call. Deliberately invoked without holding the "this" monitor
+ // to avoid blocking logic that wants to use the "this" monitor.
+ refreshSuccessful = tryRefresh(network);
+ }
+
+ synchronized (this) {
+ // Manage mTryAgainCounter.
+ if (shouldAttemptRefresh) {
+ if (refreshSuccessful) {
+ // Reset failure tracking.
+ mTryAgainCounter = 0;
+ } else {
+ if (mTryAgainTimesMax < 0) {
+ // When mTryAgainTimesMax is negative there's no enforced maximum and
+ // short intervals should be used until a successful refresh. Setting
+ // mTryAgainCounter to 1 is sufficient for the interval calculations
+ // below. There's no need to increment.
+ mTryAgainCounter = 1;
+ } else {
+ mTryAgainCounter++;
+ if (mTryAgainCounter > mTryAgainTimesMax) {
+ mTryAgainCounter = 0;
+ }
+ }
+ }
+ }
+
+ // currentElapsedRealtimeMillis is used to evaluate ages and refresh scheduling
+ // below. Capturing this after a possible successful refresh ensures that latest
+ // time result ages will be >= 0.
+ long currentElapsedRealtimeMillis = mElapsedRealtimeMillisSupplier.get();
+
+ // This section of code deliberately doesn't assume it is the only component using
+ // mNtpTrustedTime to obtain NTP times: another component in the same process could
+ // be gathering NTP signals (which then won't have been suggested to the time
+ // detector).
+ // TODO(b/222295093): Make this class the sole owner of mNtpTrustedTime and
+ // simplify / reduce duplicate suggestions.
+ NtpTrustedTime.TimeResult latestTimeResult = mNtpTrustedTime.getCachedTimeResult();
+ long latestTimeResultAgeMillis = calculateTimeResultAgeMillis(
+ latestTimeResult, currentElapsedRealtimeMillis);
+
+ // Suggest the latest time result to the time detector if it is fresh regardless of
+ // whether refresh happened above.
+ if (latestTimeResultAgeMillis < mNormalPollingIntervalMillis) {
+ // We assume the time detector service will detect duplicate suggestions and not
+ // do more work than it has to, so no need to avoid making duplicate
+ // suggestions.
+ makeNetworkTimeSuggestion(latestTimeResult, reason, refreshCallbacks);
+ }
+
+ // (Re)schedule the next refresh based on the latest state.
+ // Determine which refresh delay to use by using the current value of
+ // mTryAgainCounter. The refresh delay is applied to a different point in time
+ // depending on whether the latest available time result (if any) is still
+ // considered fresh to ensure the delay acts correctly.
+ long refreshDelayMillis = mTryAgainCounter > 0
+ ? mShortPollingIntervalMillis : mNormalPollingIntervalMillis;
+ long nextRefreshElapsedRealtimeMillis;
+ if (latestTimeResultAgeMillis < mNormalPollingIntervalMillis) {
+ // The latest time result is fresh, use it to determine when next to refresh.
+ nextRefreshElapsedRealtimeMillis =
+ latestTimeResult.getElapsedRealtimeMillis() + refreshDelayMillis;
+ } else if (mLastRefreshAttemptElapsedRealtimeMillis != null) {
+ // The latest time result is missing or old and still needs to be refreshed.
+ // mLastRefreshAttemptElapsedRealtimeMillis, which should always be set by this
+ // point because there's no fresh time result, should be very close to
+ // currentElapsedRealtimeMillis unless the refresh was not allowed.
+ nextRefreshElapsedRealtimeMillis =
+ mLastRefreshAttemptElapsedRealtimeMillis + refreshDelayMillis;
+ } else {
+ // This should not happen: mLastRefreshAttemptElapsedRealtimeMillis should
+ // always be non-null by this point.
+ logToDebugAndDumpsys(
+ "mLastRefreshAttemptElapsedRealtimeMillis unexpectedly missing."
+ + " Scheduling using currentElapsedRealtimeMillis");
+ nextRefreshElapsedRealtimeMillis =
+ currentElapsedRealtimeMillis + refreshDelayMillis;
+ }
+ refreshCallbacks.scheduleNextRefresh(nextRefreshElapsedRealtimeMillis);
+
+ logToDebugAndDumpsys("refreshIfRequiredAndReschedule:"
+ + " network=" + network
+ + ", reason=" + reason
+ + ", initialTimeResult=" + initialTimeResult
+ + ", shouldAttemptRefresh=" + shouldAttemptRefresh
+ + ", refreshSuccessful=" + refreshSuccessful
+ + ", currentElapsedRealtimeMillis="
+ + formatElapsedRealtimeMillis(currentElapsedRealtimeMillis)
+ + ", latestTimeResult=" + latestTimeResult
+ + ", mTryAgainCounter=" + mTryAgainCounter
+ + ", refreshDelayMillis=" + refreshDelayMillis
+ + ", nextRefreshElapsedRealtimeMillis="
+ + formatElapsedRealtimeMillis(nextRefreshElapsedRealtimeMillis));
+ }
+ }
+
+ private static String formatElapsedRealtimeMillis(
+ @ElapsedRealtimeLong long elapsedRealtimeMillis) {
+ return Duration.ofMillis(elapsedRealtimeMillis) + " (" + elapsedRealtimeMillis + ")";
+ }
+
+ private static long calculateTimeResultAgeMillis(
+ @Nullable TimeResult timeResult,
+ @ElapsedRealtimeLong long currentElapsedRealtimeMillis) {
+ return timeResult == null ? Long.MAX_VALUE
+ : timeResult.getAgeMillis(currentElapsedRealtimeMillis);
+ }
+
+ @GuardedBy("this")
+ private boolean isRefreshAllowed(@ElapsedRealtimeLong long currentElapsedRealtimeMillis) {
+ if (mLastRefreshAttemptElapsedRealtimeMillis == null) {
+ return true;
+ }
+ // Use the second meaning of mShortPollingIntervalMillis: to determine the minimum time
+ // allowed after an unsuccessful refresh before another can be attempted.
+ long nextRefreshAllowedElapsedRealtimeMillis =
+ mLastRefreshAttemptElapsedRealtimeMillis + mShortPollingIntervalMillis;
+ return currentElapsedRealtimeMillis >= nextRefreshAllowedElapsedRealtimeMillis;
+ }
+
+ private boolean tryRefresh(@NonNull Network network) {
+ long currentElapsedRealtimeMillis = mElapsedRealtimeMillisSupplier.get();
+ synchronized (this) {
+ mLastRefreshAttemptElapsedRealtimeMillis = currentElapsedRealtimeMillis;
+ }
+ return mNtpTrustedTime.forceRefresh(network);
+ }
+
+ /** Suggests the time to the time detector. It may choose use it to set the system clock. */
+ private void makeNetworkTimeSuggestion(@NonNull TimeResult ntpResult,
+ @NonNull String debugInfo, @NonNull RefreshCallbacks refreshCallbacks) {
+ UnixEpochTime timeSignal = new UnixEpochTime(
+ ntpResult.getElapsedRealtimeMillis(), ntpResult.getTimeMillis());
+ NetworkTimeSuggestion timeSuggestion =
+ new NetworkTimeSuggestion(timeSignal, ntpResult.getUncertaintyMillis());
+ timeSuggestion.addDebugInfo(debugInfo);
+ timeSuggestion.addDebugInfo(ntpResult.toString());
+ refreshCallbacks.submitSuggestion(timeSuggestion);
+ }
+
+ @Override
+ public void dump(PrintWriter pw) {
+ IndentingPrintWriter ipw = new IndentingPrintWriter(pw);
+ ipw.println("mNormalPollingIntervalMillis=" + mNormalPollingIntervalMillis);
+ ipw.println("mShortPollingIntervalMillis=" + mShortPollingIntervalMillis);
+ ipw.println("mTryAgainTimesMax=" + mTryAgainTimesMax);
+
+ synchronized (this) {
+ String lastRefreshAttemptValue = mLastRefreshAttemptElapsedRealtimeMillis == null
+ ? "null"
+ : formatElapsedRealtimeMillis(mLastRefreshAttemptElapsedRealtimeMillis);
+ ipw.println("mLastRefreshAttemptElapsedRealtimeMillis=" + lastRefreshAttemptValue);
+ ipw.println("mTryAgainCounter=" + mTryAgainCounter);
+ }
+ ipw.println();
+
+ ipw.println("NtpTrustedTime:");
+ ipw.increaseIndent();
+ mNtpTrustedTime.dump(ipw);
+ ipw.decreaseIndent();
+ ipw.println();
+
+ ipw.println("Debug log:");
+ ipw.increaseIndent();
+ mLocalDebugLog.dump(ipw);
+ ipw.decreaseIndent();
+ ipw.println();
+ }
+
+ private void logToDebugAndDumpsys(String logMsg) {
+ if (DBG) {
+ Log.d(TAG, logMsg);
+ }
+ mLocalDebugLog.log(logMsg);
+ }
+ }
}
diff --git a/services/core/java/com/android/server/timedetector/TimeDetectorService.java b/services/core/java/com/android/server/timedetector/TimeDetectorService.java
index 1be9074..3e23953 100644
--- a/services/core/java/com/android/server/timedetector/TimeDetectorService.java
+++ b/services/core/java/com/android/server/timedetector/TimeDetectorService.java
@@ -143,7 +143,7 @@
return getTimeCapabilitiesAndConfig(userId);
}
- TimeCapabilitiesAndConfig getTimeCapabilitiesAndConfig(@UserIdInt int userId) {
+ private TimeCapabilitiesAndConfig getTimeCapabilitiesAndConfig(@UserIdInt int userId) {
enforceManageTimeDetectorPermission();
final long token = mCallerIdentityInjector.clearCallingIdentity();
@@ -163,6 +163,9 @@
return updateConfiguration(callingUserId, configuration);
}
+ /**
+ * Updates the user's configuration. Exposed for use by {@link TimeDetectorShellCommand}.
+ */
boolean updateConfiguration(@UserIdInt int userId, @NonNull TimeConfiguration configuration) {
// Resolve constants like USER_CURRENT to the true user ID as needed.
int resolvedUserId = ActivityManager.handleIncomingUser(Binder.getCallingPid(),
@@ -256,7 +259,7 @@
}
}
- void handleConfigurationInternalChangedOnHandlerThread() {
+ private void handleConfigurationInternalChangedOnHandlerThread() {
// Configuration has changed, but each user may have a different view of the configuration.
// It's possible that this will cause unnecessary notifications but that shouldn't be a
// problem.
@@ -287,6 +290,10 @@
}
}
+ /**
+ * Sets the system time state. See {@link TimeState} for details. For use by {@link
+ * TimeDetectorShellCommand}.
+ */
void setTimeState(@NonNull TimeState timeState) {
enforceManageTimeDetectorPermission();
@@ -353,6 +360,9 @@
}
}
+ /**
+ * Suggests network time with permission checks. For use by {@link TimeDetectorShellCommand}.
+ */
void suggestNetworkTime(@NonNull NetworkTimeSuggestion timeSignal) {
enforceSuggestNetworkTimePermission();
Objects.requireNonNull(timeSignal);
@@ -360,6 +370,23 @@
mHandler.post(() -> mTimeDetectorStrategy.suggestNetworkTime(timeSignal));
}
+ /**
+ * Clears the cached network time information. For use during tests to simulate when no network
+ * time has been made available. For use by {@link TimeDetectorShellCommand}.
+ *
+ * <p>This operation takes place in the calling thread.
+ */
+ void clearNetworkTime() {
+ enforceSuggestNetworkTimePermission();
+
+ final long token = Binder.clearCallingIdentity();
+ try {
+ mTimeDetectorStrategy.clearLatestNetworkSuggestion();
+ } finally {
+ Binder.restoreCallingIdentity(token);
+ }
+ }
+
@Override
public UnixEpochTime latestNetworkTime() {
NetworkTimeSuggestion suggestion = getLatestNetworkSuggestion();
@@ -388,6 +415,9 @@
}
}
+ /**
+ * Suggests GNSS time with permission checks. For use by {@link TimeDetectorShellCommand}.
+ */
void suggestGnssTime(@NonNull GnssTimeSuggestion timeSignal) {
enforceSuggestGnssTimePermission();
Objects.requireNonNull(timeSignal);
diff --git a/services/core/java/com/android/server/timedetector/TimeDetectorShellCommand.java b/services/core/java/com/android/server/timedetector/TimeDetectorShellCommand.java
index 990c00f..cce5709 100644
--- a/services/core/java/com/android/server/timedetector/TimeDetectorShellCommand.java
+++ b/services/core/java/com/android/server/timedetector/TimeDetectorShellCommand.java
@@ -15,7 +15,9 @@
*/
package com.android.server.timedetector;
+import static android.app.timedetector.TimeDetector.SHELL_COMMAND_CLEAR_NETWORK_TIME;
import static android.app.timedetector.TimeDetector.SHELL_COMMAND_CONFIRM_TIME;
+import static android.app.timedetector.TimeDetector.SHELL_COMMAND_GET_NETWORK_TIME;
import static android.app.timedetector.TimeDetector.SHELL_COMMAND_GET_TIME_STATE;
import static android.app.timedetector.TimeDetector.SHELL_COMMAND_IS_AUTO_DETECTION_ENABLED;
import static android.app.timedetector.TimeDetector.SHELL_COMMAND_SERVICE_NAME;
@@ -70,6 +72,10 @@
return runSuggestTelephonyTime();
case SHELL_COMMAND_SUGGEST_NETWORK_TIME:
return runSuggestNetworkTime();
+ case SHELL_COMMAND_GET_NETWORK_TIME:
+ return runGetNetworkTime();
+ case SHELL_COMMAND_CLEAR_NETWORK_TIME:
+ return runClearNetworkTime();
case SHELL_COMMAND_SUGGEST_GNSS_TIME:
return runSuggestGnssTime();
case SHELL_COMMAND_SUGGEST_EXTERNAL_TIME:
@@ -122,6 +128,18 @@
mInterface::suggestNetworkTime);
}
+ private int runGetNetworkTime() {
+ NetworkTimeSuggestion networkTimeSuggestion = mInterface.getLatestNetworkSuggestion();
+ final PrintWriter pw = getOutPrintWriter();
+ pw.println(networkTimeSuggestion);
+ return 0;
+ }
+
+ private int runClearNetworkTime() {
+ mInterface.clearNetworkTime();
+ return 0;
+ }
+
private int runSuggestGnssTime() {
return runSuggestTime(
() -> GnssTimeSuggestion.parseCommandLineArg(this),
@@ -196,6 +214,10 @@
pw.printf(" Sets the current time state for tests.\n");
pw.printf(" %s <unix epoch time options>\n", SHELL_COMMAND_CONFIRM_TIME);
pw.printf(" Tries to confirms the time, raising the confidence.\n");
+ pw.printf(" %s\n", SHELL_COMMAND_GET_NETWORK_TIME);
+ pw.printf(" Prints the network time information held by the detector.\n");
+ pw.printf(" %s\n", SHELL_COMMAND_CLEAR_NETWORK_TIME);
+ pw.printf(" Clears the network time information held by the detector.\n");
pw.println();
ManualTimeSuggestion.printCommandLineOpts(pw);
pw.println();
diff --git a/services/core/java/com/android/server/timedetector/TimeDetectorStrategy.java b/services/core/java/com/android/server/timedetector/TimeDetectorStrategy.java
index 03f236d..9dca6ec 100644
--- a/services/core/java/com/android/server/timedetector/TimeDetectorStrategy.java
+++ b/services/core/java/com/android/server/timedetector/TimeDetectorStrategy.java
@@ -18,6 +18,7 @@
import android.annotation.IntDef;
import android.annotation.NonNull;
+import android.annotation.Nullable;
import android.annotation.UserIdInt;
import android.app.time.ExternalTimeSuggestion;
import android.app.time.TimeState;
@@ -103,6 +104,20 @@
/** Processes the suggested time from network sources. */
void suggestNetworkTime(@NonNull NetworkTimeSuggestion timeSuggestion);
+ /**
+ * Returns the latest (accepted) network time suggestion. Returns {@code null} if there isn't
+ * one.
+ */
+ @Nullable
+ NetworkTimeSuggestion getLatestNetworkSuggestion();
+
+ /**
+ * Clears the latest network time suggestion, leaving none. The remaining time signals from
+ * other sources will be reassessed causing the device's time to be updated if config and
+ * settings allow.
+ */
+ void clearLatestNetworkSuggestion();
+
/** Processes the suggested time from gnss sources. */
void suggestGnssTime(@NonNull GnssTimeSuggestion timeSuggestion);
diff --git a/services/core/java/com/android/server/timedetector/TimeDetectorStrategyImpl.java b/services/core/java/com/android/server/timedetector/TimeDetectorStrategyImpl.java
index 13ec753..09bb803 100644
--- a/services/core/java/com/android/server/timedetector/TimeDetectorStrategyImpl.java
+++ b/services/core/java/com/android/server/timedetector/TimeDetectorStrategyImpl.java
@@ -316,6 +316,21 @@
}
@Override
+ @Nullable
+ public synchronized NetworkTimeSuggestion getLatestNetworkSuggestion() {
+ return mLastNetworkSuggestion.get();
+ }
+
+ @Override
+ public synchronized void clearLatestNetworkSuggestion() {
+ mLastNetworkSuggestion.set(null);
+
+ // The loss of network time may change the time signal to use to set the system clock.
+ String reason = "Network time cleared";
+ doAutoTimeDetection(reason);
+ }
+
+ @Override
@NonNull
public synchronized TimeState getTimeState() {
boolean userShouldConfirmTime = mEnvironment.systemClockConfidence() < TIME_CONFIDENCE_HIGH;
@@ -1068,15 +1083,6 @@
*/
@VisibleForTesting
@Nullable
- public synchronized NetworkTimeSuggestion getLatestNetworkSuggestion() {
- return mLastNetworkSuggestion.get();
- }
-
- /**
- * A method used to inspect state during tests. Not intended for general use.
- */
- @VisibleForTesting
- @Nullable
public synchronized GnssTimeSuggestion getLatestGnssSuggestion() {
return mLastGnssSuggestion.get();
}
diff --git a/services/core/java/com/android/server/tv/TvInputManagerService.java b/services/core/java/com/android/server/tv/TvInputManagerService.java
index 863ee75..73b2238 100755
--- a/services/core/java/com/android/server/tv/TvInputManagerService.java
+++ b/services/core/java/com/android/server/tv/TvInputManagerService.java
@@ -3610,6 +3610,23 @@
}
}
+ @Override
+ public void onTvMessage(String type, Bundle data) {
+ synchronized (mLock) {
+ if (DEBUG) {
+ Slog.d(TAG, "onTvMessage(type=" + type + ", data=" + data + ")");
+ }
+ if (mSessionState.session == null || mSessionState.client == null) {
+ return;
+ }
+ try {
+ mSessionState.client.onTvMessage(type, data, mSessionState.seq);
+ } catch (RemoteException e) {
+ Slog.e(TAG, "error in onTvMessage", e);
+ }
+ }
+ }
+
// For the recording session only
@Override
public void onRecordingStopped(Uri recordedProgramUri) {
diff --git a/services/core/java/com/android/server/tv/interactive/TvInteractiveAppManagerService.java b/services/core/java/com/android/server/tv/interactive/TvInteractiveAppManagerService.java
index 966e883..6dc4b73 100644
--- a/services/core/java/com/android/server/tv/interactive/TvInteractiveAppManagerService.java
+++ b/services/core/java/com/android/server/tv/interactive/TvInteractiveAppManagerService.java
@@ -29,6 +29,7 @@
import android.content.pm.ServiceInfo;
import android.content.pm.UserInfo;
import android.graphics.Rect;
+import android.media.PlaybackParams;
import android.media.tv.AdBuffer;
import android.media.tv.AdRequest;
import android.media.tv.AdResponse;
@@ -1049,6 +1050,29 @@
}
@Override
+ public void notifyTvMessage(IBinder sessionToken, String type, Bundle data, int userId) {
+ final int callingUid = Binder.getCallingUid();
+ final int callingPid = Binder.getCallingPid();
+ final int resolvedUserId = resolveCallingUserId(callingPid, callingUid, userId,
+ "notifyTvMessage");
+ final long identity = Binder.clearCallingIdentity();
+ try {
+ synchronized (mLock) {
+ try {
+ SessionState sessionState = getSessionStateLocked(sessionToken, callingUid,
+ resolvedUserId);
+ getSessionLocked(sessionState).notifyTvMessage(type, data);
+ } catch (RemoteException | SessionNotFoundException e) {
+ Slogf.e(TAG, "error in notifyTvMessage", e);
+ }
+ }
+ } finally {
+ Binder.restoreCallingIdentity(identity);
+ }
+ }
+
+
+ @Override
public void notifyRecordingStarted(IBinder sessionToken, String recordingId, int userId) {
final int callingUid = Binder.getCallingUid();
final int callingPid = Binder.getCallingPid();
@@ -1473,6 +1497,118 @@
}
@Override
+ public void notifyTimeShiftPlaybackParams(
+ IBinder sessionToken, PlaybackParams params, int userId) {
+ if (DEBUG) {
+ Slogf.d(TAG, "notifyTimeShiftPlaybackParams(params=%s)", params);
+ }
+ final int callingUid = Binder.getCallingUid();
+ final int resolvedUserId = resolveCallingUserId(
+ Binder.getCallingPid(), callingUid, userId, "notifyTimeShiftPlaybackParams");
+ SessionState sessionState = null;
+ final long identity = Binder.clearCallingIdentity();
+ try {
+ synchronized (mLock) {
+ try {
+ sessionState =
+ getSessionStateLocked(sessionToken, callingUid, resolvedUserId);
+ getSessionLocked(sessionState).notifyTimeShiftPlaybackParams(params);
+ } catch (RemoteException | SessionNotFoundException e) {
+ Slogf.e(TAG, "error in notifyTimeShiftPlaybackParams", e);
+ }
+ }
+ } finally {
+ Binder.restoreCallingIdentity(identity);
+ }
+ }
+
+ @Override
+ public void notifyTimeShiftStatusChanged(
+ IBinder sessionToken, String inputId, int status, int userId) {
+ if (DEBUG) {
+ Slogf.d(TAG, "notifyTimeShiftStatusChanged(inputId=%s, status=%d)",
+ inputId, status);
+ }
+ final int callingUid = Binder.getCallingUid();
+ final int resolvedUserId = resolveCallingUserId(
+ Binder.getCallingPid(), callingUid, userId, "notifyTimeShiftStatusChanged");
+ SessionState sessionState = null;
+ final long identity = Binder.clearCallingIdentity();
+ try {
+ synchronized (mLock) {
+ try {
+ sessionState =
+ getSessionStateLocked(sessionToken, callingUid, resolvedUserId);
+ getSessionLocked(sessionState).notifyTimeShiftStatusChanged(
+ inputId, status);
+ } catch (RemoteException | SessionNotFoundException e) {
+ Slogf.e(TAG, "error in notifyTimeShiftStatusChanged", e);
+ }
+ }
+ } finally {
+ Binder.restoreCallingIdentity(identity);
+ }
+ }
+
+ @Override
+ public void notifyTimeShiftStartPositionChanged(
+ IBinder sessionToken, String inputId, long timeMs, int userId) {
+ if (DEBUG) {
+ Slogf.d(TAG, "notifyTimeShiftStartPositionChanged(inputId=%s, timeMs=%d)",
+ inputId, timeMs);
+ }
+ final int callingUid = Binder.getCallingUid();
+ final int resolvedUserId = resolveCallingUserId(
+ Binder.getCallingPid(), callingUid, userId,
+ "notifyTimeShiftStartPositionChanged");
+ SessionState sessionState = null;
+ final long identity = Binder.clearCallingIdentity();
+ try {
+ synchronized (mLock) {
+ try {
+ sessionState =
+ getSessionStateLocked(sessionToken, callingUid, resolvedUserId);
+ getSessionLocked(sessionState).notifyTimeShiftStartPositionChanged(
+ inputId, timeMs);
+ } catch (RemoteException | SessionNotFoundException e) {
+ Slogf.e(TAG, "error in notifyTimeShiftStartPositionChanged", e);
+ }
+ }
+ } finally {
+ Binder.restoreCallingIdentity(identity);
+ }
+ }
+
+ @Override
+ public void notifyTimeShiftCurrentPositionChanged(
+ IBinder sessionToken, String inputId, long timeMs, int userId) {
+ if (DEBUG) {
+ Slogf.d(TAG, "notifyTimeShiftCurrentPositionChanged(inputId=%s, timeMs=%d)",
+ inputId, timeMs);
+ }
+ final int callingUid = Binder.getCallingUid();
+ final int resolvedUserId = resolveCallingUserId(
+ Binder.getCallingPid(), callingUid, userId,
+ "notifyTimeShiftCurrentPositionChanged");
+ SessionState sessionState = null;
+ final long identity = Binder.clearCallingIdentity();
+ try {
+ synchronized (mLock) {
+ try {
+ sessionState =
+ getSessionStateLocked(sessionToken, callingUid, resolvedUserId);
+ getSessionLocked(sessionState).notifyTimeShiftCurrentPositionChanged(
+ inputId, timeMs);
+ } catch (RemoteException | SessionNotFoundException e) {
+ Slogf.e(TAG, "error in notifyTimeShiftCurrentPositionChanged", e);
+ }
+ }
+ } finally {
+ Binder.restoreCallingIdentity(identity);
+ }
+ }
+
+ @Override
public void setSurface(IBinder sessionToken, Surface surface, int userId) {
final int callingUid = Binder.getCallingUid();
final int resolvedUserId = resolveCallingUserId(Binder.getCallingPid(), callingUid,
@@ -2232,6 +2368,27 @@
}
@Override
+ public void onTimeShiftCommandRequest(
+ @TvInteractiveAppService.TimeShiftCommandType String cmdType,
+ Bundle parameters) {
+ synchronized (mLock) {
+ if (DEBUG) {
+ Slogf.d(TAG, "onTimeShiftCommandRequest (cmdType=" + cmdType
+ + ", parameters=" + parameters.toString() + ")");
+ }
+ if (mSessionState.mSession == null || mSessionState.mClient == null) {
+ return;
+ }
+ try {
+ mSessionState.mClient.onTimeShiftCommandRequest(
+ cmdType, parameters, mSessionState.mSeq);
+ } catch (RemoteException e) {
+ Slogf.e(TAG, "error in onTimeShiftCommandRequest", e);
+ }
+ }
+ }
+
+ @Override
public void onSetVideoBounds(Rect rect) {
synchronized (mLock) {
if (DEBUG) {
diff --git a/services/core/java/com/android/server/wallpaper/WallpaperData.java b/services/core/java/com/android/server/wallpaper/WallpaperData.java
new file mode 100644
index 0000000..25ce280
--- /dev/null
+++ b/services/core/java/com/android/server/wallpaper/WallpaperData.java
@@ -0,0 +1,150 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.wallpaper;
+
+import static android.app.WallpaperManager.FLAG_LOCK;
+
+import static com.android.server.wallpaper.WallpaperUtils.WALLPAPER;
+import static com.android.server.wallpaper.WallpaperUtils.WALLPAPER_CROP;
+import static com.android.server.wallpaper.WallpaperUtils.WALLPAPER_LOCK_CROP;
+import static com.android.server.wallpaper.WallpaperUtils.WALLPAPER_LOCK_ORIG;
+import static com.android.server.wallpaper.WallpaperUtils.getWallpaperDir;
+
+import android.app.IWallpaperManagerCallback;
+import android.app.WallpaperColors;
+import android.app.WallpaperManager.SetWallpaperFlags;
+import android.content.ComponentName;
+import android.graphics.Rect;
+import android.os.RemoteCallbackList;
+import android.util.ArrayMap;
+
+import java.io.File;
+
+/**
+ * The main wallpaper data model, used internally by the {@link WallpaperManagerService}. <br>
+ * An instance of this class contains all the information about a wallpaper.
+ */
+class WallpaperData {
+
+ int userId;
+
+ final File wallpaperFile; // source image
+ final File cropFile; // eventual destination
+
+ /**
+ * True while the client is writing a new wallpaper
+ */
+ boolean imageWallpaperPending;
+
+ /**
+ * Which wallpaper is set. Flag values are from {@link SetWallpaperFlags}.
+ */
+ int mWhich;
+
+ /**
+ * Callback once the set + crop is finished
+ */
+ IWallpaperManagerCallback setComplete;
+
+ /**
+ * Is the OS allowed to back up this wallpaper imagery?
+ */
+ boolean allowBackup;
+
+ /**
+ * Resource name if using a picture from the wallpaper gallery
+ */
+ String name = "";
+
+ /**
+ * The component name of the currently set live wallpaper.
+ */
+ ComponentName wallpaperComponent;
+
+ /**
+ * The component name of the wallpaper that should be set next.
+ */
+ ComponentName nextWallpaperComponent;
+
+ /**
+ * The ID of this wallpaper
+ */
+ int wallpaperId;
+
+ /**
+ * Primary colors histogram
+ */
+ WallpaperColors primaryColors;
+
+ /**
+ * If the wallpaper was set from a foreground app (instead of from a background service).
+ */
+ public boolean fromForegroundApp;
+
+ WallpaperManagerService.WallpaperConnection connection;
+ long lastDiedTime;
+ boolean wallpaperUpdating;
+ WallpaperManagerService.WallpaperObserver wallpaperObserver;
+
+ /**
+ * The dim amount to be applied to the wallpaper.
+ */
+ float mWallpaperDimAmount = 0.0f;
+
+ /**
+ * A map to keep track of the dimming set by different applications. The key is the calling
+ * UID and the value is the dim amount.
+ */
+ ArrayMap<Integer, Float> mUidToDimAmount = new ArrayMap<>();
+
+ /**
+ * Whether we need to extract the wallpaper colors again to calculate the dark hints
+ * after dimming is applied.
+ */
+ boolean mIsColorExtractedFromDim;
+
+ /**
+ * List of callbacks registered they should each be notified when the wallpaper is changed.
+ */
+ RemoteCallbackList<IWallpaperManagerCallback> callbacks = new RemoteCallbackList<>();
+
+ /**
+ * The crop hint supplied for displaying a subset of the source image
+ */
+ final Rect cropHint = new Rect(0, 0, 0, 0);
+
+ WallpaperData(int userId, File wallpaperDir, String inputFileName, String cropFileName) {
+ this.userId = userId;
+ wallpaperFile = new File(wallpaperDir, inputFileName);
+ cropFile = new File(wallpaperDir, cropFileName);
+ }
+
+ WallpaperData(int userId, @SetWallpaperFlags int wallpaperType) {
+ this(userId, getWallpaperDir(userId),
+ (wallpaperType == FLAG_LOCK) ? WALLPAPER_LOCK_ORIG : WALLPAPER,
+ (wallpaperType == FLAG_LOCK) ? WALLPAPER_LOCK_CROP : WALLPAPER_CROP);
+ }
+
+ // Called during initialization of a given user's wallpaper bookkeeping
+ boolean cropExists() {
+ return cropFile.exists();
+ }
+
+ boolean sourceExists() {
+ return wallpaperFile.exists();
+ }
+}
diff --git a/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java b/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java
index cee7864..8c58e15 100644
--- a/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java
+++ b/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java
@@ -32,6 +32,15 @@
import static android.view.Display.DEFAULT_DISPLAY;
import static android.view.WindowManager.LayoutParams.TYPE_WALLPAPER;
+import static com.android.server.wallpaper.WallpaperUtils.RECORD_FILE;
+import static com.android.server.wallpaper.WallpaperUtils.RECORD_LOCK_FILE;
+import static com.android.server.wallpaper.WallpaperUtils.WALLPAPER;
+import static com.android.server.wallpaper.WallpaperUtils.WALLPAPER_CROP;
+import static com.android.server.wallpaper.WallpaperUtils.WALLPAPER_INFO;
+import static com.android.server.wallpaper.WallpaperUtils.WALLPAPER_LOCK_ORIG;
+import static com.android.server.wallpaper.WallpaperUtils.getWallpaperDir;
+import static com.android.server.wallpaper.WallpaperUtils.makeWallpaperIdLocked;
+
import android.annotation.NonNull;
import android.app.ActivityManager;
import android.app.ActivityOptions;
@@ -71,7 +80,6 @@
import android.os.Binder;
import android.os.Bundle;
import android.os.Debug;
-import android.os.Environment;
import android.os.FileObserver;
import android.os.FileUtils;
import android.os.Handler;
@@ -149,6 +157,7 @@
private static final boolean DEBUG = false;
private static final boolean DEBUG_LIVE = true;
private static final boolean DEBUG_CROP = true;
+
private static final @NonNull RectF LOCAL_COLOR_BOUNDS =
new RectF(0, 0, 1, 1);
@@ -197,20 +206,6 @@
*/
private static final long MIN_WALLPAPER_CRASH_TIME = 10000;
private static final int MAX_WALLPAPER_COMPONENT_LOG_LENGTH = 128;
- static final String WALLPAPER = "wallpaper_orig";
- static final String WALLPAPER_CROP = "wallpaper";
- static final String WALLPAPER_LOCK_ORIG = "wallpaper_lock_orig";
- static final String WALLPAPER_LOCK_CROP = "wallpaper_lock";
- static final String WALLPAPER_INFO = "wallpaper_info.xml";
- private static final String RECORD_FILE = "decode_record";
- private static final String RECORD_LOCK_FILE = "decode_lock_record";
-
- // All the various per-user state files we need to be aware of
- private static final String[] sPerUserFiles = new String[] {
- WALLPAPER, WALLPAPER_CROP,
- WALLPAPER_LOCK_ORIG, WALLPAPER_LOCK_CROP,
- WALLPAPER_INFO
- };
/**
* Observes the wallpaper for changes and notifies all IWallpaperServiceCallbacks
@@ -881,18 +876,15 @@
*/
private final SparseArray<SparseArray<RemoteCallbackList<IWallpaperManagerCallback>>>
mColorsChangedListeners;
+ // The currently bound home or home+lock wallpaper
protected WallpaperData mLastWallpaper;
+ // The currently bound lock screen only wallpaper, or null if none
+ protected WallpaperData mLastLockWallpaper;
private IWallpaperManagerCallback mKeyguardListener;
private boolean mWaitingForUnlock;
private boolean mShuttingDown;
/**
- * ID of the current wallpaper, changed every time anything sets a wallpaper.
- * This is used for external detection of wallpaper update activity.
- */
- private int mWallpaperId;
-
- /**
* Name of the component used to display bitmap wallpapers from either the gallery or
* built-in wallpapers.
*/
@@ -921,112 +913,6 @@
private boolean mInAmbientMode;
private LocalColorRepository mLocalColorRepo = new LocalColorRepository();
- static class WallpaperData {
-
- int userId;
-
- final File wallpaperFile; // source image
- final File cropFile; // eventual destination
-
- /**
- * True while the client is writing a new wallpaper
- */
- boolean imageWallpaperPending;
-
- /**
- * Which wallpaper is set. Flag values are from {@link SetWallpaperFlags}.
- */
- int mWhich;
-
- /**
- * Callback once the set + crop is finished
- */
- IWallpaperManagerCallback setComplete;
-
- /**
- * Is the OS allowed to back up this wallpaper imagery?
- */
- boolean allowBackup;
-
- /**
- * Resource name if using a picture from the wallpaper gallery
- */
- String name = "";
-
- /**
- * The component name of the currently set live wallpaper.
- */
- ComponentName wallpaperComponent;
-
- /**
- * The component name of the wallpaper that should be set next.
- */
- ComponentName nextWallpaperComponent;
-
- /**
- * The ID of this wallpaper
- */
- int wallpaperId;
-
- /**
- * Primary colors histogram
- */
- WallpaperColors primaryColors;
-
- /**
- * If the wallpaper was set from a foreground app (instead of from a background service).
- */
- public boolean fromForegroundApp;
-
- WallpaperConnection connection;
- long lastDiedTime;
- boolean wallpaperUpdating;
- WallpaperObserver wallpaperObserver;
-
- /**
- * The dim amount to be applied to the wallpaper.
- */
- float mWallpaperDimAmount = 0.0f;
-
- /**
- * A map to keep track of the dimming set by different applications. The key is the calling
- * UID and the value is the dim amount.
- */
- ArrayMap<Integer, Float> mUidToDimAmount = new ArrayMap<>();
-
- /**
- * Whether we need to extract the wallpaper colors again to calculate the dark hints
- * after dimming is applied.
- */
- boolean mIsColorExtractedFromDim;
-
- /**
- * List of callbacks registered they should each be notified when the wallpaper is changed.
- */
- private RemoteCallbackList<IWallpaperManagerCallback> callbacks
- = new RemoteCallbackList<IWallpaperManagerCallback>();
-
- /**
- * The crop hint supplied for displaying a subset of the source image
- */
- final Rect cropHint = new Rect(0, 0, 0, 0);
-
- WallpaperData(int userId, File wallpaperDir, String inputFileName, String cropFileName) {
- this.userId = userId;
- wallpaperFile = new File(wallpaperDir, inputFileName);
- cropFile = new File(wallpaperDir, cropFileName);
- }
-
- // Called during initialization of a given user's wallpaper bookkeeping
- boolean cropExists() {
- return cropFile.exists();
- }
-
- boolean sourceExists() {
- return wallpaperFile.exists();
- }
- }
-
@VisibleForTesting
static final class DisplayData {
int mWidth = -1;
@@ -1080,13 +966,6 @@
}
}
- int makeWallpaperIdLocked() {
- do {
- ++mWallpaperId;
- } while (mWallpaperId == 0);
- return mWallpaperId;
- }
-
private boolean supportsMultiDisplay(WallpaperConnection connection) {
if (connection != null) {
return connection.mInfo == null // This is image wallpaper
@@ -1784,10 +1663,6 @@
getWallpaperSafeLocked(UserHandle.USER_SYSTEM, FLAG_SYSTEM);
}
- File getWallpaperDir(int userId) {
- return Environment.getUserSystemDirectory(userId);
- }
-
@Override
protected void finalize() throws Throwable {
super.finalize();
@@ -1928,9 +1803,7 @@
}
private void clearWallpaperData(int userID, int wallpaperType) {
- final WallpaperData wallpaper = new WallpaperData(userID, getWallpaperDir(userID),
- (wallpaperType == FLAG_LOCK) ? WALLPAPER_LOCK_ORIG : WALLPAPER,
- (wallpaperType == FLAG_LOCK) ? WALLPAPER_LOCK_CROP : WALLPAPER_CROP);
+ final WallpaperData wallpaper = new WallpaperData(userID, wallpaperType);
if (wallpaper.sourceExists()) {
wallpaper.wallpaperFile.delete();
}
@@ -1962,11 +1835,9 @@
final TimingsTraceAndSlog t = new TimingsTraceAndSlog(TAG);
t.traceBegin("Wallpaper_selinux_restorecon-" + userId);
try {
- final File wallpaperDir = getWallpaperDir(userId);
- for (String filename : sPerUserFiles) {
- File f = new File(wallpaperDir, filename);
- if (f.exists()) {
- SELinux.restorecon(f);
+ for (File file: WallpaperUtils.getWallpaperFiles(userId)) {
+ if (file.exists()) {
+ SELinux.restorecon(file);
}
}
} finally {
@@ -1982,12 +1853,9 @@
void onRemoveUser(int userId) {
if (userId < 1) return;
- final File wallpaperDir = getWallpaperDir(userId);
synchronized (mLock) {
stopObserversLocked(userId);
- for (String filename : sPerUserFiles) {
- new File(wallpaperDir, filename).delete();
- }
+ WallpaperUtils.getWallpaperFiles(userId).forEach(File::delete);
mUserRestorecon.delete(userId);
}
}
@@ -2050,9 +1918,7 @@
// while locked, so pretend like the component was actually
// bound into place
wallpaper.wallpaperComponent = wallpaper.nextWallpaperComponent;
- final WallpaperData fallback =
- new WallpaperData(wallpaper.userId, getWallpaperDir(wallpaper.userId),
- WALLPAPER_LOCK_ORIG, WALLPAPER_LOCK_CROP);
+ final WallpaperData fallback = new WallpaperData(wallpaper.userId, FLAG_LOCK);
ensureSaneWallpaperData(fallback);
bindWallpaperComponentLocked(mImageWallpaper, true, false, fallback, reply);
mWaitingForUnlock = true;
@@ -2914,8 +2780,7 @@
}
// We know a-priori that there is no lock-only wallpaper currently
- WallpaperData lockWP = new WallpaperData(userId, getWallpaperDir(userId),
- WALLPAPER_LOCK_ORIG, WALLPAPER_LOCK_CROP);
+ WallpaperData lockWP = new WallpaperData(userId, FLAG_LOCK);
lockWP.wallpaperId = sysWP.wallpaperId;
lockWP.cropHint.set(sysWP.cropHint);
lockWP.allowBackup = sysWP.allowBackup;
@@ -3209,14 +3074,19 @@
Slog.w(TAG, msg);
return false;
}
- if (wallpaper.userId == mCurrentUserId && mLastWallpaper != null
+ if (mEnableSeparateLockScreenEngine) {
+ maybeDetachLastWallpapers(wallpaper);
+ } else if (wallpaper.userId == mCurrentUserId && mLastWallpaper != null
&& !wallpaper.equals(mFallbackWallpaper)) {
detachWallpaperLocked(mLastWallpaper);
}
wallpaper.wallpaperComponent = componentName;
wallpaper.connection = newConn;
newConn.mReply = reply;
- if (wallpaper.userId == mCurrentUserId && !wallpaper.equals(mFallbackWallpaper)) {
+ if (mEnableSeparateLockScreenEngine) {
+ updateCurrentWallpapers(wallpaper);
+ } else if (wallpaper.userId == mCurrentUserId && !wallpaper.equals(
+ mFallbackWallpaper)) {
mLastWallpaper = wallpaper;
}
updateFallbackConnection();
@@ -3233,6 +3103,40 @@
return true;
}
+ // Updates tracking of the currently bound wallpapers. Assumes mEnableSeparateLockScreenEngine
+ // is true.
+ private void updateCurrentWallpapers(WallpaperData newWallpaper) {
+ if (newWallpaper.userId == mCurrentUserId && !newWallpaper.equals(mFallbackWallpaper)) {
+ if (newWallpaper.mWhich == (FLAG_SYSTEM | FLAG_LOCK)) {
+ mLastWallpaper = newWallpaper;
+ mLastLockWallpaper = null;
+ } else if (newWallpaper.mWhich == FLAG_SYSTEM) {
+ mLastWallpaper = newWallpaper;
+ } else if (newWallpaper.mWhich == FLAG_LOCK) {
+ mLastLockWallpaper = newWallpaper;
+ }
+ }
+ }
+
+ // Detaches previously bound wallpapers if no longer in use. Assumes
+ // mEnableSeparateLockScreenEngine is true.
+ private void maybeDetachLastWallpapers(WallpaperData newWallpaper) {
+ if (newWallpaper.userId != mCurrentUserId || newWallpaper.equals(mFallbackWallpaper)) {
+ return;
+ }
+ boolean homeUpdated = (newWallpaper.mWhich & FLAG_SYSTEM) != 0;
+ boolean lockUpdated = (newWallpaper.mWhich & FLAG_LOCK) != 0;
+ // This is the case where a home+lock wallpaper was changed to home-only, and the old
+ // home+lock became (static) or will become (live) lock-only.
+ boolean lockNeedsHomeWallpaper = mLastLockWallpaper == null && !lockUpdated;
+ if (mLastWallpaper != null && homeUpdated && !lockNeedsHomeWallpaper) {
+ detachWallpaperLocked(mLastWallpaper);
+ }
+ if (mLastLockWallpaper != null && lockUpdated) {
+ detachWallpaperLocked(mLastLockWallpaper);
+ }
+ }
+
private void detachWallpaperLocked(WallpaperData wallpaper) {
if (wallpaper.connection != null) {
if (wallpaper.connection.mReply != null) {
@@ -3263,7 +3167,12 @@
wallpaper.connection.mTryToRebindRunnable);
wallpaper.connection = null;
- if (wallpaper == mLastWallpaper) mLastWallpaper = null;
+ if (wallpaper == mLastWallpaper) {
+ mLastWallpaper = null;
+ }
+ if (wallpaper == mLastLockWallpaper) {
+ mLastLockWallpaper = null;
+ }
}
}
@@ -3588,16 +3497,14 @@
// it now.
if (wallpaper == null) {
if (which == FLAG_LOCK) {
- wallpaper = new WallpaperData(userId, getWallpaperDir(userId),
- WALLPAPER_LOCK_ORIG, WALLPAPER_LOCK_CROP);
+ wallpaper = new WallpaperData(userId, FLAG_LOCK);
mLockWallpaperMap.put(userId, wallpaper);
ensureSaneWallpaperData(wallpaper);
} else {
// rationality fallback: we're in bad shape, but establishing a known
// valid system+lock WallpaperData will keep us from dying.
Slog.wtf(TAG, "Didn't find wallpaper in non-lock case!");
- wallpaper = new WallpaperData(userId, getWallpaperDir(userId),
- WALLPAPER, WALLPAPER_CROP);
+ wallpaper = new WallpaperData(userId, FLAG_SYSTEM);
mWallpaperMap.put(userId, wallpaper);
ensureSaneWallpaperData(wallpaper);
}
@@ -3616,8 +3523,7 @@
// Do this once per boot
migrateFromOld();
- wallpaper = new WallpaperData(userId, getWallpaperDir(userId),
- WALLPAPER, WALLPAPER_CROP);
+ wallpaper = new WallpaperData(userId, FLAG_SYSTEM);
wallpaper.allowBackup = true;
mWallpaperMap.put(userId, wallpaper);
if (!wallpaper.cropExists()) {
@@ -3668,8 +3574,7 @@
// keyguard-specific wallpaper for this user
WallpaperData lockWallpaper = mLockWallpaperMap.get(userId);
if (lockWallpaper == null) {
- lockWallpaper = new WallpaperData(userId, getWallpaperDir(userId),
- WALLPAPER_LOCK_ORIG, WALLPAPER_LOCK_CROP);
+ lockWallpaper = new WallpaperData(userId, FLAG_LOCK);
mLockWallpaperMap.put(userId, lockWallpaper);
}
parseWallpaperAttributes(parser, lockWallpaper, false);
@@ -3720,8 +3625,7 @@
if (mFallbackWallpaper == null) {
if (DEBUG) Slog.d(TAG, "Initialize fallback wallpaper");
final int systemUserId = UserHandle.USER_SYSTEM;
- mFallbackWallpaper = new WallpaperData(systemUserId, getWallpaperDir(systemUserId),
- WALLPAPER, WALLPAPER_CROP);
+ mFallbackWallpaper = new WallpaperData(systemUserId, FLAG_SYSTEM);
mFallbackWallpaper.allowBackup = false;
mFallbackWallpaper.wallpaperId = makeWallpaperIdLocked();
bindWallpaperComponentLocked(mImageWallpaper, true, false, mFallbackWallpaper, null);
@@ -3742,8 +3646,8 @@
final int id = parser.getAttributeInt(null, "id", -1);
if (id != -1) {
wallpaper.wallpaperId = id;
- if (id > mWallpaperId) {
- mWallpaperId = id;
+ if (id > WallpaperUtils.getCurrentWallpaperId()) {
+ WallpaperUtils.setCurrentWallpaperId(id);
}
} else {
wallpaper.wallpaperId = makeWallpaperIdLocked();
diff --git a/services/core/java/com/android/server/wallpaper/WallpaperUtils.java b/services/core/java/com/android/server/wallpaper/WallpaperUtils.java
new file mode 100644
index 0000000..d0311e3
--- /dev/null
+++ b/services/core/java/com/android/server/wallpaper/WallpaperUtils.java
@@ -0,0 +1,86 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.wallpaper;
+
+import android.os.Environment;
+
+import java.io.File;
+import java.util.ArrayList;
+import java.util.List;
+
+class WallpaperUtils {
+
+ static final String WALLPAPER = "wallpaper_orig";
+ static final String WALLPAPER_CROP = "wallpaper";
+ static final String WALLPAPER_LOCK_ORIG = "wallpaper_lock_orig";
+ static final String WALLPAPER_LOCK_CROP = "wallpaper_lock";
+ static final String WALLPAPER_INFO = "wallpaper_info.xml";
+ static final String RECORD_FILE = "decode_record";
+ static final String RECORD_LOCK_FILE = "decode_lock_record";
+
+ // All the various per-user state files we need to be aware of
+ private static final String[] sPerUserFiles = new String[] {
+ WALLPAPER, WALLPAPER_CROP,
+ WALLPAPER_LOCK_ORIG, WALLPAPER_LOCK_CROP,
+ WALLPAPER_INFO
+ };
+
+ /**
+ * ID of the current wallpaper, incremented every time anything sets a wallpaper.
+ * This is used for external detection of wallpaper update activity.
+ */
+ private static int sWallpaperId;
+
+ static File getWallpaperDir(int userId) {
+ return Environment.getUserSystemDirectory(userId);
+ }
+
+ /**
+ * generate a new wallpaper id
+ * should be called with the {@link WallpaperManagerService} lock held
+ */
+ static int makeWallpaperIdLocked() {
+ do {
+ ++sWallpaperId;
+ } while (sWallpaperId == 0);
+ return sWallpaperId;
+ }
+
+ /**
+ * returns the id of the current wallpaper (the last one that has been set)
+ */
+ static int getCurrentWallpaperId() {
+ return sWallpaperId;
+ }
+
+ /**
+ * sets the id of the current wallpaper
+ * used when a wallpaper with higher id than current is loaded from settings
+ */
+ static void setCurrentWallpaperId(int id) {
+ sWallpaperId = id;
+ }
+
+ static List<File> getWallpaperFiles(int userId) {
+ File wallpaperDir = getWallpaperDir(userId);
+ List<File> result = new ArrayList<File>();
+ for (int i = 0; i < sPerUserFiles.length; i++) {
+ result.add(new File(wallpaperDir, sPerUserFiles[i]));
+ }
+ return result;
+ }
+}
diff --git a/services/core/java/com/android/server/wm/ActivityClientController.java b/services/core/java/com/android/server/wm/ActivityClientController.java
index a16e659..4428be7 100644
--- a/services/core/java/com/android/server/wm/ActivityClientController.java
+++ b/services/core/java/com/android/server/wm/ActivityClientController.java
@@ -1644,4 +1644,19 @@
}
return false;
}
+
+ @Override
+ public void enableTaskLocaleOverride(IBinder token) {
+ if (UserHandle.getAppId(Binder.getCallingUid()) != SYSTEM_UID) {
+ // Only allow system to align locale.
+ return;
+ }
+
+ synchronized (mGlobalLock) {
+ final ActivityRecord r = ActivityRecord.forTokenLocked(token);
+ if (r != null) {
+ r.getTask().mAlignActivityLocaleWithTask = true;
+ }
+ }
+ }
}
diff --git a/services/core/java/com/android/server/wm/ActivityRecord.java b/services/core/java/com/android/server/wm/ActivityRecord.java
index 8410942..45ae3d8 100644
--- a/services/core/java/com/android/server/wm/ActivityRecord.java
+++ b/services/core/java/com/android/server/wm/ActivityRecord.java
@@ -298,6 +298,7 @@
import android.os.Debug;
import android.os.IBinder;
import android.os.IRemoteCallback;
+import android.os.LocaleList;
import android.os.PersistableBundle;
import android.os.Process;
import android.os.RemoteException;
@@ -726,6 +727,7 @@
/**
* When set to true, the IME insets will be frozen until the next app becomes IME input target.
* @see InsetsPolicy#adjustVisibilityForIme
+ * @see ImeInsetsSourceProvider#updateClientVisibility
*/
boolean mImeInsetsFrozenUntilStartInput;
@@ -1575,7 +1577,6 @@
if (newParent != null) {
if (isState(RESUMED)) {
newParent.setResumedActivity(this, "onParentChanged");
- mImeInsetsFrozenUntilStartInput = false;
}
mLetterboxUiController.onActivityParentChanged(newParent);
}
@@ -7998,6 +7999,9 @@
}
super.resolveOverrideConfiguration(newParentConfiguration);
final Configuration resolvedConfig = getResolvedOverrideConfiguration();
+
+ applyLocaleOverrideIfNeeded(resolvedConfig);
+
if (isFixedRotationTransforming()) {
// The resolved configuration is applied with rotated display configuration. If this
// activity matches its parent (the following resolving procedures are no-op), then it
@@ -8870,13 +8874,6 @@
}
}
- @Override
- void onResize() {
- // Reset freezing IME insets flag when the activity resized.
- mImeInsetsFrozenUntilStartInput = false;
- super.onResize();
- }
-
private boolean applyAspectRatio(Rect outBounds, Rect containingAppBounds,
Rect containingBounds) {
return applyAspectRatio(outBounds, containingAppBounds, containingBounds,
@@ -10160,6 +10157,35 @@
}
}
+ private void applyLocaleOverrideIfNeeded(Configuration resolvedConfig) {
+ // We always align the locale for ActivityEmbedding apps. System apps or some apps which
+ // has set known cert apps can embed across different uid activity.
+ boolean shouldAlignLocale = isEmbedded()
+ || (task != null && task.mAlignActivityLocaleWithTask);
+ if (!shouldAlignLocale) {
+ return;
+ }
+
+ boolean differentPackage = task != null
+ && task.realActivity != null
+ && !task.realActivity.getPackageName().equals(packageName);
+ if (!differentPackage) {
+ return;
+ }
+
+ LocaleList locale;
+ final ActivityTaskManagerInternal.PackageConfig appConfig =
+ mAtmService.mPackageConfigPersister.findPackageConfiguration(
+ task.realActivity.getPackageName(), mUserId);
+ // if there is no app locale for the package, clear the target activity's locale.
+ if (appConfig == null || appConfig.mLocales == null || appConfig.mLocales.isEmpty()) {
+ locale = LocaleList.getEmptyLocaleList();
+ } else {
+ locale = appConfig.mLocales;
+ }
+ resolvedConfig.setLocales(locale);
+ }
+
/**
* Whether we should send fake focus when the activity is resumed. This is done because some
* game engines wait to get focus before drawing the content of the app.
diff --git a/services/core/java/com/android/server/wm/ActivitySecurityModelFeatureFlags.java b/services/core/java/com/android/server/wm/ActivitySecurityModelFeatureFlags.java
new file mode 100644
index 0000000..64af9dd
--- /dev/null
+++ b/services/core/java/com/android/server/wm/ActivitySecurityModelFeatureFlags.java
@@ -0,0 +1,114 @@
+/*
+ * 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 com.android.server.wm;
+
+import static android.provider.DeviceConfig.NAMESPACE_WINDOW_MANAGER;
+
+import static com.android.server.wm.ActivityStarter.ASM_RESTRICTIONS;
+
+import android.annotation.NonNull;
+import android.app.compat.CompatChanges;
+import android.content.pm.PackageManager;
+import android.provider.DeviceConfig;
+
+import com.android.internal.annotations.GuardedBy;
+
+import java.util.HashSet;
+import java.util.concurrent.Executor;
+
+/**
+ * Contains utility methods to query whether or not go/activity-security should be enabled
+ * asm_start_rules_enabled - Enable rule enforcement in ActivityStarter.java
+ * asm_start_rules_toasts_enabled - Show toasts when rules would block from ActivityStarter.java
+ * asm_start_rules_exception_list - Comma separated list of packages to exclude from the above
+ * 2 rules.
+ * TODO(b/258792202) Cleanup once ASM is ready to launch
+ */
+class ActivitySecurityModelFeatureFlags {
+ // TODO(b/230590090): Replace with public documentation once ready
+ static final String DOC_LINK = "go/android-asm";
+
+ private static final String NAMESPACE = NAMESPACE_WINDOW_MANAGER;
+ private static final String KEY_ASM_RESTRICTIONS_ENABLED = "asm_restrictions_enabled";
+ private static final String KEY_ASM_TOASTS_ENABLED = "asm_toasts_enabled";
+ private static final String KEY_ASM_EXEMPTED_PACKAGES = "asm_exempted_packages";
+ private static final int VALUE_DISABLE = 0;
+ private static final int VALUE_ENABLE_FOR_U = 1;
+ private static final int VALUE_ENABLE_FOR_ALL = 2;
+
+ private static final int DEFAULT_VALUE = VALUE_DISABLE;
+ private static final String DEFAULT_EXCEPTION_LIST = "";
+
+ private static int sAsmToastsEnabled;
+ private static int sAsmRestrictionsEnabled;
+ private static final HashSet<String> sExcludedPackageNames = new HashSet<>();
+ private static PackageManager sPm;
+
+ @GuardedBy("ActivityTaskManagerService.mGlobalLock")
+ static void initialize(@NonNull Executor executor, @NonNull PackageManager pm) {
+ updateFromDeviceConfig();
+ DeviceConfig.addOnPropertiesChangedListener(NAMESPACE, executor,
+ properties -> updateFromDeviceConfig());
+ sPm = pm;
+ }
+
+ @GuardedBy("ActivityTaskManagerService.mGlobalLock")
+ static boolean shouldShowToast(int uid) {
+ return flagEnabledForUid(sAsmToastsEnabled, uid);
+ }
+
+ @GuardedBy("ActivityTaskManagerService.mGlobalLock")
+ static boolean shouldBlockActivityStart(int uid) {
+ return flagEnabledForUid(sAsmRestrictionsEnabled, uid);
+ }
+
+ private static boolean flagEnabledForUid(int flag, int uid) {
+ boolean flagEnabled = flag == VALUE_ENABLE_FOR_ALL
+ || (flag == VALUE_ENABLE_FOR_U
+ && CompatChanges.isChangeEnabled(ASM_RESTRICTIONS, uid));
+
+ if (flagEnabled) {
+ String[] packageNames = sPm.getPackagesForUid(uid);
+ for (int i = 0; i < packageNames.length; i++) {
+ if (sExcludedPackageNames.contains(packageNames[i])) {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ return false;
+ }
+
+ private static void updateFromDeviceConfig() {
+ sAsmToastsEnabled = DeviceConfig.getInt(NAMESPACE, KEY_ASM_TOASTS_ENABLED,
+ DEFAULT_VALUE);
+ sAsmRestrictionsEnabled = DeviceConfig.getInt(NAMESPACE, KEY_ASM_RESTRICTIONS_ENABLED,
+ DEFAULT_VALUE);
+
+ String rawExceptionList = DeviceConfig.getString(NAMESPACE,
+ KEY_ASM_EXEMPTED_PACKAGES, DEFAULT_EXCEPTION_LIST);
+ sExcludedPackageNames.clear();
+ String[] packages = rawExceptionList.split(",");
+ for (String packageName : packages) {
+ String packageNameTrimmed = packageName.trim();
+ if (!packageNameTrimmed.isEmpty()) {
+ sExcludedPackageNames.add(packageNameTrimmed);
+ }
+ }
+ }
+}
diff --git a/services/core/java/com/android/server/wm/ActivityStartInterceptor.java b/services/core/java/com/android/server/wm/ActivityStartInterceptor.java
index b40aa3c..1944b3f 100644
--- a/services/core/java/com/android/server/wm/ActivityStartInterceptor.java
+++ b/services/core/java/com/android/server/wm/ActivityStartInterceptor.java
@@ -284,7 +284,7 @@
IntentSender target = createIntentSenderForOriginalIntent(mCallingUid,
FLAG_CANCEL_CURRENT | FLAG_ONE_SHOT);
- mIntent = UnlaunchableAppActivity.createInQuietModeDialogIntent(mUserId, target);
+ mIntent = UnlaunchableAppActivity.createInQuietModeDialogIntent(mUserId, target, mRInfo);
mCallingPid = mRealCallingPid;
mCallingUid = mRealCallingUid;
mResolvedType = null;
diff --git a/services/core/java/com/android/server/wm/ActivityStarter.java b/services/core/java/com/android/server/wm/ActivityStarter.java
index 034f5c8..40432dc 100644
--- a/services/core/java/com/android/server/wm/ActivityStarter.java
+++ b/services/core/java/com/android/server/wm/ActivityStarter.java
@@ -56,10 +56,11 @@
import static android.view.WindowManager.TRANSIT_NONE;
import static android.view.WindowManager.TRANSIT_OPEN;
import static android.view.WindowManager.TRANSIT_TO_FRONT;
-import static android.window.WindowContainerTransaction.HierarchyOp.HIERARCHY_OP_TYPE_START_ACTIVITY_IN_TASK_FRAGMENT;
+import static android.window.TaskFragmentOperation.OP_TYPE_START_ACTIVITY_IN_TASK_FRAGMENT;
import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_CONFIGURATION;
import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_TASKS;
+import static com.android.server.wm.ActivityRecord.State.FINISHING;
import static com.android.server.wm.ActivityRecord.State.RESUMED;
import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_PERMISSIONS_REVIEW;
import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_RESULTS;
@@ -74,7 +75,12 @@
import static com.android.server.wm.ActivityTaskSupervisor.DEFER_RESUME;
import static com.android.server.wm.ActivityTaskSupervisor.ON_TOP;
import static com.android.server.wm.ActivityTaskSupervisor.PRESERVE_WINDOWS;
+import static com.android.server.wm.BackgroundActivityStartController.BAL_ALLOW_ALLOWLISTED_COMPONENT;
+import static com.android.server.wm.BackgroundActivityStartController.BAL_ALLOW_ALLOWLISTED_UID;
+import static com.android.server.wm.BackgroundActivityStartController.BAL_ALLOW_BAL_PERMISSION;
import static com.android.server.wm.BackgroundActivityStartController.BAL_ALLOW_DEFAULT;
+import static com.android.server.wm.BackgroundActivityStartController.BAL_ALLOW_PENDING_INTENT;
+import static com.android.server.wm.BackgroundActivityStartController.BAL_ALLOW_VISIBLE_WINDOW;
import static com.android.server.wm.BackgroundActivityStartController.BAL_BLOCK;
import static com.android.server.wm.LaunchParamsController.LaunchParamsModifier.PHASE_BOUNDS;
import static com.android.server.wm.LaunchParamsController.LaunchParamsModifier.PHASE_DISPLAY;
@@ -119,6 +125,7 @@
import android.text.TextUtils;
import android.util.Pools.SynchronizedPool;
import android.util.Slog;
+import android.widget.Toast;
import android.window.RemoteTransition;
import com.android.internal.annotations.VisibleForTesting;
@@ -126,6 +133,7 @@
import com.android.internal.app.IVoiceInteractor;
import com.android.internal.protolog.common.ProtoLog;
import com.android.internal.util.FrameworkStatsLog;
+import com.android.server.UiThread;
import com.android.server.am.PendingIntentRecord;
import com.android.server.pm.InstantAppResolver;
import com.android.server.power.ShutdownCheckPoints;
@@ -152,6 +160,7 @@
private static final String TAG_FOCUS = TAG + POSTFIX_FOCUS;
private static final String TAG_CONFIGURATION = TAG + POSTFIX_CONFIGURATION;
private static final String TAG_USER_LEAVING = TAG + POSTFIX_USER_LEAVING;
+
private static final int INVALID_LAUNCH_MODE = -1;
/**
@@ -161,6 +170,13 @@
@EnabledSince(targetSdkVersion = Build.VERSION_CODES.TIRAMISU)
static final long ENABLE_PENDING_INTENT_BAL_OPTION = 192341120L;
+ /**
+ * Feature flag for go/activity-security rules
+ */
+ @ChangeId
+ @EnabledSince(targetSdkVersion = Build.VERSION_CODES.UPSIDE_DOWN_CAKE)
+ static final long ASM_RESTRICTIONS = 230590090L;
+
private final ActivityTaskManagerService mService;
private final RootWindowContainer mRootWindowContainer;
private final ActivityTaskSupervisor mSupervisor;
@@ -1851,65 +1867,134 @@
}
}
- // Log activity starts which violate one of the following rules of the
- // activity security model (ASM):
- // 1. Only the top activity on a task can start activities on that task
- // 2. Only the top activity on the top task can create new (top) tasks
- // We don't currently block, but these checks may later become blocks
- // TODO(b/236234252): Shift to BackgroundActivityStartController once
- // class is ready
- if (mSourceRecord != null) {
- int callerUid = mSourceRecord.getUid();
- ActivityRecord targetTopActivity =
- targetTask != null ? targetTask.getTopNonFinishingActivity() : null;
- boolean passesAsmChecks = newTask
- ? mService.mVisibleActivityProcessTracker.hasResumedActivity(callerUid)
- : targetTopActivity != null && targetTopActivity.getUid() == callerUid;
-
- if (!passesAsmChecks) {
- Slog.i(TAG, "Launching r: " + r
- + " from background: " + mSourceRecord
- + ". New task: " + newTask);
- boolean newOrEmptyTask = newTask || (targetTopActivity == null);
- int action = newTask
- ? FrameworkStatsLog.ACTIVITY_ACTION_BLOCKED__ACTION__ACTIVITY_START_NEW_TASK
- : (mSourceRecord.getTask().equals(targetTask)
- ? FrameworkStatsLog.ACTIVITY_ACTION_BLOCKED__ACTION__ACTIVITY_START_SAME_TASK
- : FrameworkStatsLog.ACTIVITY_ACTION_BLOCKED__ACTION__ACTIVITY_START_DIFFERENT_TASK);
- FrameworkStatsLog.write(FrameworkStatsLog.ACTIVITY_ACTION_BLOCKED,
- /* caller_uid */
- callerUid,
- /* caller_activity_class_name */
- mSourceRecord.info.name,
- /* target_task_top_activity_uid */
- newOrEmptyTask ? -1 : targetTopActivity.getUid(),
- /* target_task_top_activity_class_name */
- newOrEmptyTask ? null : targetTopActivity.info.name,
- /* target_task_is_different */
- newTask || !mSourceRecord.getTask().equals(targetTask),
- /* target_activity_uid */
- r.getUid(),
- /* target_activity_class_name */
- r.info.name,
- /* target_intent_action */
- r.intent.getAction(),
- /* target_intent_flags */
- r.intent.getFlags(),
- /* action */
- action,
- /* version */
- 1,
- /* multi_window */
- targetTask != null && !targetTask.equals(mSourceRecord.getTask())
- && targetTask.isVisible()
- );
- }
+ if (!checkActivitySecurityModel(r, newTask, targetTask)) {
+ return START_ABORTED;
}
return START_SUCCESS;
}
/**
+ * TODO(b/263368846): Shift to BackgroundActivityStartController once class is ready
+ * Log activity starts which violate one of the following rules of the
+ * activity security model (ASM):
+ * See go/activity-security for rationale behind the rules.
+ * We don't currently block, but these checks may later become blocks
+ * 1. Within a task, only an activity matching a top UID of the task can start activities
+ * 2. Only activities within a foreground task, which match a top UID of the task, can
+ * create a new task or bring an existing one into the foreground
+ */
+ private boolean checkActivitySecurityModel(ActivityRecord r, boolean newTask, Task targetTask) {
+ // Intents with FLAG_ACTIVITY_NEW_TASK will always be considered as creating a new task
+ // even if the intent is delivered to an existing task.
+ boolean taskToFront = newTask
+ || (mLaunchFlags & FLAG_ACTIVITY_NEW_TASK) == FLAG_ACTIVITY_NEW_TASK;
+
+ if (mSourceRecord != null) {
+ boolean passesAsmChecks = true;
+ Task sourceTask = mSourceRecord.getTask();
+
+ // Don't allow launches into a new task if the current task is not foreground.
+ if (taskToFront) {
+ passesAsmChecks = sourceTask != null && sourceTask.isVisible();
+ }
+
+ Task taskToCheck = taskToFront ? sourceTask : targetTask;
+ passesAsmChecks = passesAsmChecks && ActivityTaskSupervisor
+ .doesTopActivityMatchingUidExistForAsm(taskToCheck, mSourceRecord.getUid(),
+ mSourceRecord);
+
+ if (passesAsmChecks) {
+ return true;
+ }
+ }
+
+ // BAL exception only allowed for new tasks
+ if (taskToFront) {
+ if (mBalCode == BAL_ALLOW_ALLOWLISTED_COMPONENT
+ || mBalCode == BAL_ALLOW_BAL_PERMISSION
+ || mBalCode == BAL_ALLOW_PENDING_INTENT) {
+ return true;
+ }
+ }
+
+ // BAL Exception allowed in all cases
+ if (mBalCode == BAL_ALLOW_ALLOWLISTED_UID) {
+ return true;
+ }
+
+ // TODO(b/230590090): Revisit this - ideally we would not rely on visibility, but rather
+ // have an explicit api for activities to opt-out of ASM protection if they need to.
+ if (mBalCode == BAL_ALLOW_VISIBLE_WINDOW) {
+ return true;
+ }
+
+ // ASM rules have failed. Log why
+ ActivityRecord targetTopActivity = targetTask == null ? null
+ : targetTask.getActivity(ar ->
+ !ar.isState(FINISHING) && !ar.isAlwaysOnTop());
+
+ int action = newTask || mSourceRecord == null
+ ? FrameworkStatsLog.ACTIVITY_ACTION_BLOCKED__ACTION__ACTIVITY_START_NEW_TASK
+ : (mSourceRecord.getTask().equals(targetTask)
+ ? FrameworkStatsLog.ACTIVITY_ACTION_BLOCKED__ACTION__ACTIVITY_START_SAME_TASK
+ : FrameworkStatsLog.ACTIVITY_ACTION_BLOCKED__ACTION__ACTIVITY_START_DIFFERENT_TASK);
+
+ FrameworkStatsLog.write(FrameworkStatsLog.ACTIVITY_ACTION_BLOCKED,
+ /* caller_uid */
+ mSourceRecord != null ? mSourceRecord.getUid() : -1,
+ /* caller_activity_class_name */
+ mSourceRecord != null ? mSourceRecord.info.name : null,
+ /* target_task_top_activity_uid */
+ targetTopActivity != null ? targetTopActivity.getUid() : -1,
+ /* target_task_top_activity_class_name */
+ targetTopActivity != null ? targetTopActivity.info.name : null,
+ /* target_task_is_different */
+ newTask || mSourceRecord == null || targetTask == null
+ || !targetTask.equals(mSourceRecord.getTask()),
+ /* target_activity_uid */
+ r.getUid(),
+ /* target_activity_class_name */
+ r.info.name,
+ /* target_intent_action */
+ r.intent.getAction(),
+ /* target_intent_flags */
+ mLaunchFlags,
+ /* action */
+ action,
+ /* version */
+ 1,
+ /* multi_window - we have our source not in the target task, but both are visible */
+ targetTask != null && mSourceRecord != null
+ && !targetTask.equals(mSourceRecord.getTask()) && targetTask.isVisible()
+ );
+
+ boolean shouldBlockActivityStart =
+ ActivitySecurityModelFeatureFlags.shouldBlockActivityStart(mCallingUid);
+
+ if (ActivitySecurityModelFeatureFlags.shouldShowToast(mCallingUid)) {
+ UiThread.getHandler().post(() -> Toast.makeText(mService.mContext,
+ (shouldBlockActivityStart
+ ? "Activity start blocked by "
+ : "Activity start would be blocked by ")
+ + ActivitySecurityModelFeatureFlags.DOC_LINK,
+ Toast.LENGTH_SHORT).show());
+ }
+
+
+ if (shouldBlockActivityStart) {
+ Slog.e(TAG, "Abort Launching r: " + r
+ + " as source: " + mSourceRecord
+ + "is in background. New task: " + newTask
+ + ". Top activity: " + targetTopActivity);
+
+ return false;
+ }
+
+ return true;
+ }
+
+ /**
* Returns whether embedding of {@code starting} is allowed.
*
* @param taskFragment the TaskFragment for embedding.
@@ -2830,7 +2915,7 @@
if (taskFragment.isOrganized()) {
mService.mWindowOrganizerController.sendTaskFragmentOperationFailure(
taskFragment.getTaskFragmentOrganizer(), mRequest.errorCallbackToken,
- taskFragment, HIERARCHY_OP_TYPE_START_ACTIVITY_IN_TASK_FRAGMENT,
+ taskFragment, OP_TYPE_START_ACTIVITY_IN_TASK_FRAGMENT,
new SecurityException(errMsg));
} else {
// If the taskFragment is not organized, just dump error message as warning logs.
diff --git a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
index fd6d606..9a8ef19 100644
--- a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
+++ b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
@@ -859,6 +859,8 @@
mRecentTasks.onSystemReadyLocked();
mTaskSupervisor.onSystemReady();
mActivityClientController.onSystemReady();
+ // TODO(b/258792202) Cleanup once ASM is ready to launch
+ ActivitySecurityModelFeatureFlags.initialize(mContext.getMainExecutor(), pm);
}
}
@@ -1495,7 +1497,7 @@
a.persistableMode = ActivityInfo.PERSIST_NEVER;
a.screenOrientation = ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED;
a.colorMode = ActivityInfo.COLOR_MODE_DEFAULT;
- a.flags |= ActivityInfo.FLAG_EXCLUDE_FROM_RECENTS;
+ a.flags |= ActivityInfo.FLAG_EXCLUDE_FROM_RECENTS | ActivityInfo.FLAG_NO_HISTORY;
a.resizeMode = RESIZE_MODE_UNRESIZEABLE;
a.configChanges = 0xffffffff;
diff --git a/services/core/java/com/android/server/wm/ActivityTaskSupervisor.java b/services/core/java/com/android/server/wm/ActivityTaskSupervisor.java
index b1bc52a..407ffd0 100644
--- a/services/core/java/com/android/server/wm/ActivityTaskSupervisor.java
+++ b/services/core/java/com/android/server/wm/ActivityTaskSupervisor.java
@@ -51,6 +51,7 @@
import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_STATES;
import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_TASKS;
+import static com.android.server.wm.ActivityRecord.State.FINISHING;
import static com.android.server.wm.ActivityRecord.State.PAUSED;
import static com.android.server.wm.ActivityRecord.State.PAUSING;
import static com.android.server.wm.ActivityRecord.State.RESTARTING_PROCESS;
@@ -157,6 +158,7 @@
import java.util.ArrayList;
import java.util.List;
import java.util.function.Consumer;
+import java.util.function.Predicate;
// TODO: This class has become a dumping ground. Let's
// - Move things relating to the hierarchy to RootWindowContainer
@@ -1629,10 +1631,11 @@
// cleared the calling identify. If so, we infer we do not need further restrictions here.
// TODO(b/263368846) Move to live with the rest of the ASM logic.
if (callingUid != SYSTEM_UID) {
- ActivityRecord topActivity = task.getTopNonFinishingActivity();
- boolean passesAsmChecks = topActivity != null
- && topActivity.getUid() == callingUid;
+ boolean passesAsmChecks = doesTopActivityMatchingUidExistForAsm(task, callingUid,
+ null);
if (!passesAsmChecks) {
+ ActivityRecord topActivity = task.getActivity(ar ->
+ !ar.isState(FINISHING) && !ar.isAlwaysOnTop());
Slog.i(TAG, "Finishing task from background. t: " + task);
FrameworkStatsLog.write(FrameworkStatsLog.ACTIVITY_ACTION_BLOCKED,
/* caller_uid */
@@ -1677,6 +1680,57 @@
}
}
+ /**
+ * For the purpose of ASM, ‘Top UID” for a task is defined as an activity UID
+ * 1. Which is top of the stack in z-order
+ * a. Excluding any activities with the flag ‘isAlwaysOnTop’ and
+ * b. Excluding any activities which are `finishing`
+ * 2. Or top of an adjacent task fragment to (1)
+ *
+ * The 'sourceRecord' can be considered top even if it is 'finishing'
+ *
+ * TODO(b/263368846) Shift to BackgroundActivityStartController once class is ready
+ */
+ @Nullable
+ static boolean doesTopActivityMatchingUidExistForAsm(@Nullable Task task,
+ int uid, @Nullable ActivityRecord sourceRecord) {
+ // If the source is visible, consider it 'top'.
+ if (sourceRecord != null && sourceRecord.isVisible()) {
+ return true;
+ }
+
+ // Consider the source activity, whether or not it is finishing. Do not consider any other
+ // finishing activity.
+ Predicate<ActivityRecord> topOfStackPredicate = (ar) -> ar.equals(sourceRecord)
+ || (!ar.isState(FINISHING) && !ar.isAlwaysOnTop());
+
+ // Check top of stack (or the first task fragment for embedding).
+ ActivityRecord topActivity = task.getActivity(topOfStackPredicate);
+ if (topActivity == null) {
+ return false;
+ }
+
+ if (topActivity.getUid() == uid) {
+ return true;
+ }
+
+ // Even if the top activity is not a match, we may be in an embedded activity scenario with
+ // an adjacent task fragment. Get the second fragment.
+ TaskFragment taskFragment = topActivity.getTaskFragment();
+ if (taskFragment == null) {
+ return false;
+ }
+
+ TaskFragment adjacentTaskFragment = taskFragment.getAdjacentTaskFragment();
+ if (adjacentTaskFragment == null) {
+ return false;
+ }
+
+ // Check the second fragment.
+ topActivity = adjacentTaskFragment.getActivity(topOfStackPredicate);
+ return topActivity != null && topActivity.getUid() == uid;
+ }
+
void cleanUpRemovedTaskLocked(Task task, boolean killProcess, boolean removeFromRecents) {
if (removeFromRecents) {
mRecentTasks.remove(task);
diff --git a/services/core/java/com/android/server/wm/AppTaskImpl.java b/services/core/java/com/android/server/wm/AppTaskImpl.java
index 6b5f068..7bd8c53 100644
--- a/services/core/java/com/android/server/wm/AppTaskImpl.java
+++ b/services/core/java/com/android/server/wm/AppTaskImpl.java
@@ -99,7 +99,7 @@
throw new IllegalArgumentException("Unable to find task ID " + mTaskId);
}
return mService.getRecentTasks().createRecentTaskInfo(task,
- false /* stripExtras */);
+ false /* stripExtras */, true /* getTasksAllowed */);
} finally {
Binder.restoreCallingIdentity(origId);
}
diff --git a/services/core/java/com/android/server/wm/AppTransitionController.java b/services/core/java/com/android/server/wm/AppTransitionController.java
index 74d52b2..d65c2f9 100644
--- a/services/core/java/com/android/server/wm/AppTransitionController.java
+++ b/services/core/java/com/android/server/wm/AppTransitionController.java
@@ -900,7 +900,7 @@
*
* TODO(b/213312721): Remove this predicate and its callers once ShellTransition is enabled.
*/
- private static boolean isTaskViewTask(WindowContainer wc) {
+ static boolean isTaskViewTask(WindowContainer wc) {
// We use Task#mRemoveWithTaskOrganizer to identify an embedded Task, but this is a hack and
// it is not guaranteed to work this logic in the future version.
return wc instanceof Task && ((Task) wc).mRemoveWithTaskOrganizer;
diff --git a/services/core/java/com/android/server/wm/DisplayContent.java b/services/core/java/com/android/server/wm/DisplayContent.java
index e7a5ee7..eadb11e 100644
--- a/services/core/java/com/android/server/wm/DisplayContent.java
+++ b/services/core/java/com/android/server/wm/DisplayContent.java
@@ -4509,11 +4509,35 @@
mImeWindowsContainer.getParent().mSurfaceControl));
updateImeControlTarget(forceUpdateImeParent);
}
- // Unfreeze IME insets after the new target updated, in case updateAboveInsetsState may
- // deliver unrelated IME insets change to the non-IME requester.
- if (target != null) {
- target.unfreezeInsetsAfterStartInput();
+ }
+
+ /**
+ * Callback from {@link ImeInsetsSourceProvider#updateClientVisibility} for the system to
+ * judge whether or not to notify the IME insets provider to dispatch this reported IME client
+ * visibility state to the app clients when needed.
+ */
+ boolean onImeInsetsClientVisibilityUpdate() {
+ boolean[] changed = new boolean[1];
+
+ // Unlike the IME layering target or the control target can be updated during the layout
+ // change, the IME input target requires to be changed after gaining the input focus.
+ // In case unfreezing IME insets state may too early during IME focus switching, we unfreeze
+ // when activities going to be visible until the input target changed, or the
+ // activity was the current input target that has to unfreeze after updating the IME
+ // client visibility.
+ final ActivityRecord inputTargetActivity =
+ mImeInputTarget != null ? mImeInputTarget.getActivityRecord() : null;
+ final boolean targetChanged = mImeInputTarget != mLastImeInputTarget;
+ if (targetChanged || inputTargetActivity != null && inputTargetActivity.isVisibleRequested()
+ && inputTargetActivity.mImeInsetsFrozenUntilStartInput) {
+ forAllActivities(r -> {
+ if (r.mImeInsetsFrozenUntilStartInput && r.isVisibleRequested()) {
+ r.mImeInsetsFrozenUntilStartInput = false;
+ changed[0] = true;
+ }
+ });
}
+ return changed[0];
}
void updateImeControlTarget() {
diff --git a/services/core/java/com/android/server/wm/DisplayRotationCompatPolicy.java b/services/core/java/com/android/server/wm/DisplayRotationCompatPolicy.java
index ba0413d..c6037da 100644
--- a/services/core/java/com/android/server/wm/DisplayRotationCompatPolicy.java
+++ b/services/core/java/com/android/server/wm/DisplayRotationCompatPolicy.java
@@ -203,8 +203,11 @@
|| !shouldRefreshActivity(activity, newConfig, lastReportedConfig)) {
return;
}
- boolean cycleThroughStop = mWmService.mLetterboxConfiguration
- .isCameraCompatRefreshCycleThroughStopEnabled();
+ boolean cycleThroughStop =
+ mWmService.mLetterboxConfiguration
+ .isCameraCompatRefreshCycleThroughStopEnabled()
+ && !activity.mLetterboxUiController
+ .shouldRefreshActivityViaPauseForCameraCompat();
try {
activity.mLetterboxUiController.setIsRefreshAfterRotationRequested(true);
ProtoLog.v(WM_DEBUG_STATES,
@@ -255,7 +258,8 @@
Configuration lastReportedConfig) {
return newConfig.windowConfiguration.getDisplayRotation()
!= lastReportedConfig.windowConfiguration.getDisplayRotation()
- && isTreatmentEnabledForActivity(activity);
+ && isTreatmentEnabledForActivity(activity)
+ && activity.mLetterboxUiController.shouldRefreshActivityForCameraCompat();
}
/**
@@ -294,7 +298,8 @@
// handle dynamic changes so we shouldn't force rotate them.
&& activity.getRequestedOrientation() != SCREEN_ORIENTATION_NOSENSOR
&& activity.getRequestedOrientation() != SCREEN_ORIENTATION_LOCKED
- && mCameraIdPackageBiMap.containsPackageName(activity.packageName);
+ && mCameraIdPackageBiMap.containsPackageName(activity.packageName)
+ && activity.mLetterboxUiController.shouldForceRotateForCameraCompat();
}
private synchronized void notifyCameraOpened(
diff --git a/services/core/java/com/android/server/wm/EmbeddedWindowController.java b/services/core/java/com/android/server/wm/EmbeddedWindowController.java
index d54f77a..c3c727a 100644
--- a/services/core/java/com/android/server/wm/EmbeddedWindowController.java
+++ b/services/core/java/com/android/server/wm/EmbeddedWindowController.java
@@ -335,10 +335,6 @@
}
@Override
- public void unfreezeInsetsAfterStartInput() {
- }
-
- @Override
public InsetsControlTarget getImeControlTarget() {
return mWmService.getDefaultDisplayContentLocked().mRemoteInsetsControlTarget;
}
diff --git a/services/core/java/com/android/server/wm/ImeInsetsSourceProvider.java b/services/core/java/com/android/server/wm/ImeInsetsSourceProvider.java
index 90d0f16..85938e3 100644
--- a/services/core/java/com/android/server/wm/ImeInsetsSourceProvider.java
+++ b/services/core/java/com/android/server/wm/ImeInsetsSourceProvider.java
@@ -140,10 +140,14 @@
@Override
protected boolean updateClientVisibility(InsetsControlTarget caller) {
+ if (caller != getControlTarget()) {
+ return false;
+ }
boolean changed = super.updateClientVisibility(caller);
if (changed && caller.isRequestedVisible(mSource.getType())) {
reportImeDrawnForOrganizer(caller);
}
+ changed |= mDisplayContent.onImeInsetsClientVisibilityUpdate();
return changed;
}
diff --git a/services/core/java/com/android/server/wm/InputTarget.java b/services/core/java/com/android/server/wm/InputTarget.java
index b5ab62b..653f5f5 100644
--- a/services/core/java/com/android/server/wm/InputTarget.java
+++ b/services/core/java/com/android/server/wm/InputTarget.java
@@ -16,8 +16,8 @@
package com.android.server.wm;
-import android.view.IWindow;
import android.util.proto.ProtoOutputStream;
+import android.view.IWindow;
/**
* Common interface between focusable objects.
@@ -58,7 +58,6 @@
boolean canScreenshotIme();
ActivityRecord getActivityRecord();
- void unfreezeInsetsAfterStartInput();
boolean isInputMethodClientFocus(int uid, int pid);
diff --git a/services/core/java/com/android/server/wm/InsetsSourceProvider.java b/services/core/java/com/android/server/wm/InsetsSourceProvider.java
index 659f8d7..49eaea2 100644
--- a/services/core/java/com/android/server/wm/InsetsSourceProvider.java
+++ b/services/core/java/com/android/server/wm/InsetsSourceProvider.java
@@ -508,6 +508,9 @@
}
mClientVisible = clientVisible;
updateVisibility();
+ // The visibility change needs a traversal to apply.
+ mDisplayContent.setLayoutNeeded();
+ mDisplayContent.mWmService.mWindowPlacerLocked.requestTraversal();
}
@VisibleForTesting
diff --git a/services/core/java/com/android/server/wm/LetterboxUiController.java b/services/core/java/com/android/server/wm/LetterboxUiController.java
index 0c8a645..75ba214 100644
--- a/services/core/java/com/android/server/wm/LetterboxUiController.java
+++ b/services/core/java/com/android/server/wm/LetterboxUiController.java
@@ -17,12 +17,18 @@
package com.android.server.wm;
import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
+import static android.content.pm.ActivityInfo.OVERRIDE_CAMERA_COMPAT_DISABLE_FORCE_ROTATION;
+import static android.content.pm.ActivityInfo.OVERRIDE_CAMERA_COMPAT_DISABLE_REFRESH;
+import static android.content.pm.ActivityInfo.OVERRIDE_CAMERA_COMPAT_ENABLE_REFRESH_VIA_PAUSE;
import static android.content.pm.ActivityInfo.OVERRIDE_ENABLE_COMPAT_IGNORE_REQUESTED_ORIENTATION;
import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED;
import static android.content.pm.ActivityInfo.screenOrientationToString;
import static android.content.res.Configuration.ORIENTATION_LANDSCAPE;
import static android.content.res.Configuration.ORIENTATION_PORTRAIT;
import static android.view.WindowManager.LayoutParams.FLAG_SHOW_WALLPAPER;
+import static android.view.WindowManager.PROPERTY_CAMERA_COMPAT_ALLOW_FORCE_ROTATION;
+import static android.view.WindowManager.PROPERTY_CAMERA_COMPAT_ALLOW_REFRESH;
+import static android.view.WindowManager.PROPERTY_CAMERA_COMPAT_ENABLE_REFRESH_VIA_PAUSE;
import static android.view.WindowManager.PROPERTY_COMPAT_IGNORE_REQUESTED_ORIENTATION;
import static com.android.internal.util.FrameworkStatsLog.APP_COMPAT_STATE_CHANGED__LETTERBOX_POSITION__BOTTOM;
@@ -132,6 +138,15 @@
@Nullable
private Letterbox mLetterbox;
+ @Nullable
+ private final Boolean mBooleanPropertyCameraCompatAllowForceRotation;
+
+ @Nullable
+ private final Boolean mBooleanPropertyCameraCompatAllowRefresh;
+
+ @Nullable
+ private final Boolean mBooleanPropertyCameraCompatEnableRefreshViaPause;
+
// Whether activity "refresh" was requested but not finished in
// ActivityRecord#activityResumedLocked following the camera compat force rotation in
// DisplayRotationCompatPolicy.
@@ -154,8 +169,33 @@
readComponentProperty(packageManager, mActivityRecord.packageName,
mLetterboxConfiguration::isPolicyForIgnoringRequestedOrientationEnabled,
PROPERTY_COMPAT_IGNORE_REQUESTED_ORIENTATION);
+ mBooleanPropertyCameraCompatAllowForceRotation =
+ readComponentProperty(packageManager, mActivityRecord.packageName,
+ () -> mLetterboxConfiguration.isCameraCompatTreatmentEnabled(
+ /* checkDeviceConfig */ true),
+ PROPERTY_CAMERA_COMPAT_ALLOW_FORCE_ROTATION);
+ mBooleanPropertyCameraCompatAllowRefresh =
+ readComponentProperty(packageManager, mActivityRecord.packageName,
+ () -> mLetterboxConfiguration.isCameraCompatTreatmentEnabled(
+ /* checkDeviceConfig */ true),
+ PROPERTY_CAMERA_COMPAT_ALLOW_REFRESH);
+ mBooleanPropertyCameraCompatEnableRefreshViaPause =
+ readComponentProperty(packageManager, mActivityRecord.packageName,
+ () -> mLetterboxConfiguration.isCameraCompatTreatmentEnabled(
+ /* checkDeviceConfig */ true),
+ PROPERTY_CAMERA_COMPAT_ENABLE_REFRESH_VIA_PAUSE);
}
+ /**
+ * Reads a {@link Boolean} component property fot a given {@code packageName} and a {@code
+ * propertyName}. Returns {@code null} if {@code gatingCondition} is {@code false} or if the
+ * property isn't specified for the package.
+ *
+ * <p>Return value is {@link Boolean} rather than {@code boolean} so we can know when the
+ * property is unset. Particularly, when this returns {@code null}, {@link
+ * #shouldEnableWithOverrideAndProperty} will check the value of override for the final
+ * decision.
+ */
@Nullable
private static Boolean readComponentProperty(PackageManager packageManager, String packageName,
BooleanSupplier gatingCondition, String propertyName) {
@@ -210,15 +250,11 @@
* </ul>
*/
boolean shouldIgnoreRequestedOrientation(@ScreenOrientation int requestedOrientation) {
- if (!mLetterboxConfiguration.isPolicyForIgnoringRequestedOrientationEnabled()) {
- return false;
- }
- if (Boolean.FALSE.equals(mBooleanPropertyIgnoreRequestedOrientation)) {
- return false;
- }
- if (!Boolean.TRUE.equals(mBooleanPropertyIgnoreRequestedOrientation)
- && !mActivityRecord.info.isChangeEnabled(
- OVERRIDE_ENABLE_COMPAT_IGNORE_REQUESTED_ORIENTATION)) {
+ if (!shouldEnableWithOverrideAndProperty(
+ /* gatingCondition */ mLetterboxConfiguration
+ ::isPolicyForIgnoringRequestedOrientationEnabled,
+ OVERRIDE_ENABLE_COMPAT_IGNORE_REQUESTED_ORIENTATION,
+ mBooleanPropertyIgnoreRequestedOrientation)) {
return false;
}
if (mIsRelauchingAfterRequestedOrientationChanged) {
@@ -262,6 +298,109 @@
mIsRefreshAfterRotationRequested = isRequested;
}
+ /**
+ * Whether activity is eligible for activity "refresh" after camera compat force rotation
+ * treatment. See {@link DisplayRotationCompatPolicy} for context.
+ *
+ * <p>This treatment is enabled when the following conditions are met:
+ * <ul>
+ * <li>Flag gating the camera compat treatment is enabled.
+ * <li>Activity isn't opted out by the device manufacturer with override or by the app
+ * developers with the component property.
+ * </ul>
+ */
+ boolean shouldRefreshActivityForCameraCompat() {
+ return shouldEnableWithOptOutOverrideAndProperty(
+ /* gatingCondition */ () -> mLetterboxConfiguration
+ .isCameraCompatTreatmentEnabled(/* checkDeviceConfig */ true),
+ OVERRIDE_CAMERA_COMPAT_DISABLE_REFRESH,
+ mBooleanPropertyCameraCompatAllowRefresh);
+ }
+
+ /**
+ * Whether activity should be "refreshed" after the camera compat force rotation treatment
+ * using the "resumed -> paused -> resumed" cycle rather than the "resumed -> ... -> stopped
+ * -> ... -> resumed" cycle. See {@link DisplayRotationCompatPolicy} for context.
+ *
+ * <p>This treatment is enabled when the following conditions are met:
+ * <ul>
+ * <li>Flag gating the camera compat treatment is enabled.
+ * <li>Activity "refresh" via "resumed -> paused -> resumed" cycle isn't disabled with the
+ * component property by the app developers.
+ * <li>Activity "refresh" via "resumed -> paused -> resumed" cycle is enabled by the device
+ * manufacturer with override / by the app developers with the component property.
+ * </ul>
+ */
+ boolean shouldRefreshActivityViaPauseForCameraCompat() {
+ return shouldEnableWithOverrideAndProperty(
+ /* gatingCondition */ () -> mLetterboxConfiguration
+ .isCameraCompatTreatmentEnabled(/* checkDeviceConfig */ true),
+ OVERRIDE_CAMERA_COMPAT_ENABLE_REFRESH_VIA_PAUSE,
+ mBooleanPropertyCameraCompatEnableRefreshViaPause);
+ }
+
+ /**
+ * Whether activity is eligible for camera compat force rotation treatment. See {@link
+ * DisplayRotationCompatPolicy} for context.
+ *
+ * <p>This treatment is enabled when the following conditions are met:
+ * <ul>
+ * <li>Flag gating the camera compat treatment is enabled.
+ * <li>Activity isn't opted out by the device manufacturer with override or by the app
+ * developers with the component property.
+ * </ul>
+ */
+ boolean shouldForceRotateForCameraCompat() {
+ return shouldEnableWithOptOutOverrideAndProperty(
+ /* gatingCondition */ () -> mLetterboxConfiguration
+ .isCameraCompatTreatmentEnabled(/* checkDeviceConfig */ true),
+ OVERRIDE_CAMERA_COMPAT_DISABLE_FORCE_ROTATION,
+ mBooleanPropertyCameraCompatAllowForceRotation);
+ }
+
+ /**
+ * Returns {@code true} when the following conditions are met:
+ * <ul>
+ * <li>{@code gatingCondition} isn't {@code false}
+ * <li>OEM didn't opt out with a {@code overrideChangeId} override
+ * <li>App developers didn't opt out with a component {@code property}
+ * </ul>
+ *
+ * <p>This is used for the treatments that are enabled based with the heuristic but can be
+ * disabled on per-app basis by OEMs or app developers.
+ */
+ private boolean shouldEnableWithOptOutOverrideAndProperty(BooleanSupplier gatingCondition,
+ long overrideChangeId, Boolean property) {
+ if (!gatingCondition.getAsBoolean()) {
+ return false;
+ }
+ return !Boolean.FALSE.equals(property)
+ && !mActivityRecord.info.isChangeEnabled(overrideChangeId);
+ }
+
+ /**
+ * Returns {@code true} when the following conditions are met:
+ * <ul>
+ * <li>{@code gatingCondition} isn't {@code false}
+ * <li>App developers didn't opt out with a component {@code property}
+ * <li>App developers opted in with a component {@code property} or an OEM opted in with a
+ * component {@code property}
+ * </ul>
+ *
+ * <p>This is used for the treatments that are enabled only on per-app basis.
+ */
+ private boolean shouldEnableWithOverrideAndProperty(BooleanSupplier gatingCondition,
+ long overrideChangeId, Boolean property) {
+ if (!gatingCondition.getAsBoolean()) {
+ return false;
+ }
+ if (Boolean.FALSE.equals(property)) {
+ return false;
+ }
+ return Boolean.TRUE.equals(property)
+ || mActivityRecord.info.isChangeEnabled(overrideChangeId);
+ }
+
boolean hasWallpaperBackgroundForLetterbox() {
return mShowWallpaperForLetterboxBackground;
}
diff --git a/services/core/java/com/android/server/wm/RecentTasks.java b/services/core/java/com/android/server/wm/RecentTasks.java
index 9e95918..4be1c83 100644
--- a/services/core/java/com/android/server/wm/RecentTasks.java
+++ b/services/core/java/com/android/server/wm/RecentTasks.java
@@ -976,7 +976,7 @@
continue;
}
- res.add(createRecentTaskInfo(task, true /* stripExtras */));
+ res.add(createRecentTaskInfo(task, true /* stripExtras */, getTasksAllowed));
}
return res;
}
@@ -1889,7 +1889,8 @@
/**
* Creates a new RecentTaskInfo from a Task.
*/
- ActivityManager.RecentTaskInfo createRecentTaskInfo(Task tr, boolean stripExtras) {
+ ActivityManager.RecentTaskInfo createRecentTaskInfo(Task tr, boolean stripExtras,
+ boolean getTasksAllowed) {
final ActivityManager.RecentTaskInfo rti = new ActivityManager.RecentTaskInfo();
// If the recent Task is detached, we consider it will be re-attached to the default
// TaskDisplayArea because we currently only support recent overview in the default TDA.
@@ -1901,6 +1902,9 @@
rti.id = rti.isRunning ? rti.taskId : INVALID_TASK_ID;
rti.persistentId = rti.taskId;
rti.lastSnapshotData.set(tr.mLastTaskSnapshotData);
+ if (!getTasksAllowed) {
+ Task.trimIneffectiveInfo(tr, rti);
+ }
// Fill in organized child task info for the task created by organizer.
if (tr.mCreatedByOrganizer) {
diff --git a/services/core/java/com/android/server/wm/RunningTasks.java b/services/core/java/com/android/server/wm/RunningTasks.java
index 614b405..1cc1a57 100644
--- a/services/core/java/com/android/server/wm/RunningTasks.java
+++ b/services/core/java/com/android/server/wm/RunningTasks.java
@@ -173,6 +173,10 @@
}
// Fill in some deprecated values
rti.id = rti.taskId;
+
+ if (!mAllowed) {
+ Task.trimIneffectiveInfo(task, rti);
+ }
return rti;
}
}
diff --git a/services/core/java/com/android/server/wm/SurfaceSyncGroupController.java b/services/core/java/com/android/server/wm/SurfaceSyncGroupController.java
new file mode 100644
index 0000000..75691ca
--- /dev/null
+++ b/services/core/java/com/android/server/wm/SurfaceSyncGroupController.java
@@ -0,0 +1,101 @@
+/*
+ * 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 com.android.server.wm;
+
+import android.annotation.Nullable;
+import android.os.Binder;
+import android.os.IBinder;
+import android.os.RemoteException;
+import android.util.ArrayMap;
+import android.window.AddToSurfaceSyncGroupResult;
+import android.window.ISurfaceSyncGroupCompletedListener;
+import android.window.ITransactionReadyCallback;
+import android.window.SurfaceSyncGroup;
+
+import com.android.internal.annotations.GuardedBy;
+
+class SurfaceSyncGroupController {
+ private static final String TAG = "SurfaceSyncGroupController";
+ private final Object mLock = new Object();
+
+ @GuardedBy("mLock")
+ private final ArrayMap<IBinder, SurfaceSyncGroupData> mSurfaceSyncGroups = new ArrayMap<>();
+
+ boolean addToSyncGroup(IBinder syncGroupToken, boolean parentSyncGroupMerge,
+ @Nullable ISurfaceSyncGroupCompletedListener completedListener,
+ AddToSurfaceSyncGroupResult outAddToSyncGroupResult) {
+ SurfaceSyncGroup root;
+ synchronized (mLock) {
+ SurfaceSyncGroupData syncGroupData = mSurfaceSyncGroups.get(syncGroupToken);
+ if (syncGroupData == null) {
+ root = new SurfaceSyncGroup(TAG + "-" + syncGroupToken.hashCode());
+ if (completedListener != null) {
+ root.addSyncCompleteCallback(Runnable::run, () -> {
+ try {
+ completedListener.onSurfaceSyncGroupComplete();
+ } catch (RemoteException e) {
+ }
+ });
+ }
+ mSurfaceSyncGroups.put(syncGroupToken,
+ new SurfaceSyncGroupData(Binder.getCallingUid(), root));
+ } else {
+ root = syncGroupData.mSurfaceSyncGroup;
+ }
+ }
+
+ ITransactionReadyCallback callback =
+ root.createTransactionReadyCallback(parentSyncGroupMerge);
+ if (callback == null) {
+ return false;
+ }
+ outAddToSyncGroupResult.mParentSyncGroup = root;
+ outAddToSyncGroupResult.mTransactionReadyCallback = callback;
+ return true;
+ }
+
+ void markSyncGroupReady(IBinder syncGroupToken) {
+ final SurfaceSyncGroup root;
+ synchronized (mLock) {
+ SurfaceSyncGroupData syncGroupData = mSurfaceSyncGroups.get(syncGroupToken);
+ if (syncGroupData == null) {
+ throw new IllegalArgumentException(
+ "SurfaceSyncGroup Token has not been set up or has already been marked as"
+ + " ready");
+ }
+ if (syncGroupData.mOwningUid != Binder.getCallingUid()) {
+ throw new IllegalArgumentException(
+ "Only process that created the SurfaceSyncGroup can call "
+ + "markSyncGroupReady");
+ }
+ root = syncGroupData.mSurfaceSyncGroup;
+ mSurfaceSyncGroups.remove(syncGroupToken);
+ }
+
+ root.markSyncReady();
+ }
+
+ private static class SurfaceSyncGroupData {
+ final int mOwningUid;
+ final SurfaceSyncGroup mSurfaceSyncGroup;
+
+ private SurfaceSyncGroupData(int owningUid, SurfaceSyncGroup surfaceSyncGroup) {
+ mOwningUid = owningUid;
+ mSurfaceSyncGroup = surfaceSyncGroup;
+ }
+ }
+}
diff --git a/services/core/java/com/android/server/wm/Task.java b/services/core/java/com/android/server/wm/Task.java
index 3b5b5a9..e253ce0 100644
--- a/services/core/java/com/android/server/wm/Task.java
+++ b/services/core/java/com/android/server/wm/Task.java
@@ -612,6 +612,8 @@
boolean mLastSurfaceShowing = true;
+ boolean mAlignActivityLocaleWithTask = false;
+
private Task(ActivityTaskManagerService atmService, int _taskId, Intent _intent,
Intent _affinityIntent, String _affinity, String _rootAffinity,
ComponentName _realActivity, ComponentName _origActivity, boolean _rootWasReset,
@@ -3402,6 +3404,54 @@
info.isSleeping = shouldSleepActivities();
}
+ /**
+ * Removes the activity info if the activity belongs to a different uid, which is
+ * different from the app that hosts the task.
+ */
+ static void trimIneffectiveInfo(Task task, TaskInfo info) {
+ final ActivityRecord baseActivity = task.getActivity(r -> !r.finishing,
+ false /* traverseTopToBottom */);
+ final int baseActivityUid =
+ baseActivity != null ? baseActivity.getUid() : task.effectiveUid;
+
+ if (info.topActivityInfo != null
+ && task.effectiveUid != info.topActivityInfo.applicationInfo.uid) {
+ // Making a copy to prevent eliminating the info in the original ActivityRecord.
+ info.topActivityInfo = new ActivityInfo(info.topActivityInfo);
+ info.topActivityInfo.applicationInfo =
+ new ApplicationInfo(info.topActivityInfo.applicationInfo);
+
+ // Strip the sensitive info.
+ info.topActivity = new ComponentName("", "");
+ info.topActivityInfo.packageName = "";
+ info.topActivityInfo.taskAffinity = "";
+ info.topActivityInfo.processName = "";
+ info.topActivityInfo.name = "";
+ info.topActivityInfo.parentActivityName = "";
+ info.topActivityInfo.targetActivity = "";
+ info.topActivityInfo.splitName = "";
+ info.topActivityInfo.applicationInfo.className = "";
+ info.topActivityInfo.applicationInfo.credentialProtectedDataDir = "";
+ info.topActivityInfo.applicationInfo.dataDir = "";
+ info.topActivityInfo.applicationInfo.deviceProtectedDataDir = "";
+ info.topActivityInfo.applicationInfo.manageSpaceActivityName = "";
+ info.topActivityInfo.applicationInfo.nativeLibraryDir = "";
+ info.topActivityInfo.applicationInfo.nativeLibraryRootDir = "";
+ info.topActivityInfo.applicationInfo.processName = "";
+ info.topActivityInfo.applicationInfo.publicSourceDir = "";
+ info.topActivityInfo.applicationInfo.scanPublicSourceDir = "";
+ info.topActivityInfo.applicationInfo.scanSourceDir = "";
+ info.topActivityInfo.applicationInfo.sourceDir = "";
+ info.topActivityInfo.applicationInfo.taskAffinity = "";
+ info.topActivityInfo.applicationInfo.name = "";
+ info.topActivityInfo.applicationInfo.packageName = "";
+ }
+
+ if (task.effectiveUid != baseActivityUid) {
+ info.baseActivity = new ComponentName("", "");
+ }
+ }
+
@Nullable PictureInPictureParams getPictureInPictureParams() {
final Task topTask = getTopMostTask();
if (topTask == null) return null;
@@ -6215,6 +6265,11 @@
return this;
}
+ Builder setRemoveWithTaskOrganizer(boolean removeWithTaskOrganizer) {
+ mRemoveWithTaskOrganizer = removeWithTaskOrganizer;
+ return this;
+ }
+
private Builder setUserId(int userId) {
mUserId = userId;
return this;
@@ -6412,7 +6467,7 @@
mCallingPackage = mActivityInfo.packageName;
mResizeMode = mActivityInfo.resizeMode;
mSupportsPictureInPicture = mActivityInfo.supportsPictureInPicture();
- if (mActivityOptions != null) {
+ if (!mRemoveWithTaskOrganizer && mActivityOptions != null) {
mRemoveWithTaskOrganizer = mActivityOptions.getRemoveWithTaskOranizer();
}
diff --git a/services/core/java/com/android/server/wm/TaskFragmentOrganizerController.java b/services/core/java/com/android/server/wm/TaskFragmentOrganizerController.java
index 90a0dff..5f186a1 100644
--- a/services/core/java/com/android/server/wm/TaskFragmentOrganizerController.java
+++ b/services/core/java/com/android/server/wm/TaskFragmentOrganizerController.java
@@ -49,6 +49,7 @@
import android.window.ITaskFragmentOrganizer;
import android.window.ITaskFragmentOrganizerController;
import android.window.TaskFragmentInfo;
+import android.window.TaskFragmentOperation;
import android.window.TaskFragmentParentInfo;
import android.window.TaskFragmentTransaction;
import android.window.WindowContainerTransaction;
@@ -297,7 +298,7 @@
@NonNull
TaskFragmentTransaction.Change prepareTaskFragmentError(
@Nullable IBinder errorCallbackToken, @Nullable TaskFragment taskFragment,
- int opType, @NonNull Throwable exception) {
+ @TaskFragmentOperation.OperationType int opType, @NonNull Throwable exception) {
ProtoLog.v(WM_DEBUG_WINDOW_ORGANIZER,
"Sending TaskFragment error exception=%s", exception.toString());
final TaskFragmentInfo info =
@@ -629,7 +630,7 @@
void onTaskFragmentError(@NonNull ITaskFragmentOrganizer organizer,
@Nullable IBinder errorCallbackToken, @Nullable TaskFragment taskFragment,
- int opType, @NonNull Throwable exception) {
+ @TaskFragmentOperation.OperationType int opType, @NonNull Throwable exception) {
if (taskFragment != null && taskFragment.mTaskFragmentVanishedSent) {
return;
}
@@ -803,6 +804,7 @@
// Set when the event is deferred due to the host task is invisible. The defer time will
// be the last active time of the host task.
private long mDeferTime;
+ @TaskFragmentOperation.OperationType
private int mOpType;
private PendingTaskFragmentEvent(@EventType int eventType,
@@ -812,7 +814,7 @@
@Nullable Throwable exception,
@Nullable ActivityRecord activity,
@Nullable Task task,
- int opType) {
+ @TaskFragmentOperation.OperationType int opType) {
mEventType = eventType;
mTaskFragmentOrg = taskFragmentOrg;
mTaskFragment = taskFragment;
@@ -853,6 +855,7 @@
private ActivityRecord mActivity;
@Nullable
private Task mTask;
+ @TaskFragmentOperation.OperationType
private int mOpType;
Builder(@EventType int eventType, @NonNull ITaskFragmentOrganizer taskFragmentOrg) {
@@ -885,7 +888,7 @@
return this;
}
- Builder setOpType(int opType) {
+ Builder setOpType(@TaskFragmentOperation.OperationType int opType) {
mOpType = opType;
return this;
}
diff --git a/services/core/java/com/android/server/wm/TaskOrganizerController.java b/services/core/java/com/android/server/wm/TaskOrganizerController.java
index 274d7ff..8570db2 100644
--- a/services/core/java/com/android/server/wm/TaskOrganizerController.java
+++ b/services/core/java/com/android/server/wm/TaskOrganizerController.java
@@ -783,7 +783,8 @@
}
@Override
- public void createRootTask(int displayId, int windowingMode, @Nullable IBinder launchCookie) {
+ public void createRootTask(int displayId, int windowingMode, @Nullable IBinder launchCookie,
+ boolean removeWithTaskOrganizer) {
enforceTaskPermission("createRootTask()");
final long origId = Binder.clearCallingIdentity();
try {
@@ -795,7 +796,7 @@
return;
}
- createRootTask(display, windowingMode, launchCookie);
+ createRootTask(display, windowingMode, launchCookie, removeWithTaskOrganizer);
}
} finally {
Binder.restoreCallingIdentity(origId);
@@ -804,6 +805,12 @@
@VisibleForTesting
Task createRootTask(DisplayContent display, int windowingMode, @Nullable IBinder launchCookie) {
+ return createRootTask(display, windowingMode, launchCookie,
+ false /* removeWithTaskOrganizer */);
+ }
+
+ Task createRootTask(DisplayContent display, int windowingMode, @Nullable IBinder launchCookie,
+ boolean removeWithTaskOrganizer) {
ProtoLog.v(WM_DEBUG_WINDOW_ORGANIZER, "Create root task displayId=%d winMode=%d",
display.mDisplayId, windowingMode);
// We want to defer the task appear signal until the task is fully created and attached to
@@ -816,6 +823,7 @@
.setDeferTaskAppear(true)
.setLaunchCookie(launchCookie)
.setParent(display.getDefaultTaskDisplayArea())
+ .setRemoveWithTaskOrganizer(removeWithTaskOrganizer)
.build();
task.setDeferTaskAppear(false /* deferTaskAppear */);
return task;
diff --git a/services/core/java/com/android/server/wm/WallpaperController.java b/services/core/java/com/android/server/wm/WallpaperController.java
index 7f9e808..16541c1 100644
--- a/services/core/java/com/android/server/wm/WallpaperController.java
+++ b/services/core/java/com/android/server/wm/WallpaperController.java
@@ -370,7 +370,7 @@
boolean updateWallpaperOffset(WindowState wallpaperWin, boolean sync) {
// Size of the display the wallpaper is rendered on.
- final Rect lastWallpaperBounds = wallpaperWin.getLastReportedBounds();
+ final Rect lastWallpaperBounds = wallpaperWin.getParentFrame();
// Full size of the wallpaper (usually larger than bounds above to parallax scroll when
// swiping through Launcher pages).
final Rect wallpaperFrame = wallpaperWin.getFrame();
diff --git a/services/core/java/com/android/server/wm/WindowContainer.java b/services/core/java/com/android/server/wm/WindowContainer.java
index 0ab4faf..63bb5c3 100644
--- a/services/core/java/com/android/server/wm/WindowContainer.java
+++ b/services/core/java/com/android/server/wm/WindowContainer.java
@@ -3237,11 +3237,11 @@
private Animation loadAnimation(WindowManager.LayoutParams lp, int transit, boolean enter,
boolean isVoiceInteraction) {
- if (isOrganized()
+ if (AppTransitionController.isTaskViewTask(this) || (isOrganized()
// TODO(b/161711458): Clean-up when moved to shell.
&& getWindowingMode() != WINDOWING_MODE_FULLSCREEN
&& getWindowingMode() != WINDOWING_MODE_FREEFORM
- && getWindowingMode() != WINDOWING_MODE_MULTI_WINDOW) {
+ && getWindowingMode() != WINDOWING_MODE_MULTI_WINDOW)) {
return null;
}
diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java
index 9b09d94..4e7613b 100644
--- a/services/core/java/com/android/server/wm/WindowManagerService.java
+++ b/services/core/java/com/android/server/wm/WindowManagerService.java
@@ -292,7 +292,9 @@
import android.view.displayhash.DisplayHash;
import android.view.displayhash.VerifiedDisplayHash;
import android.view.inputmethod.ImeTracker;
+import android.window.AddToSurfaceSyncGroupResult;
import android.window.ClientWindowFrames;
+import android.window.ISurfaceSyncGroupCompletedListener;
import android.window.ITaskFpsCallback;
import android.window.ScreenCapture;
import android.window.TaskSnapshot;
@@ -746,6 +748,10 @@
@VisibleForTesting
final ContentRecordingController mContentRecordingController = new ContentRecordingController();
+
+ private final SurfaceSyncGroupController mSurfaceSyncGroupController =
+ new SurfaceSyncGroupController();
+
@VisibleForTesting
final class SettingsObserver extends ContentObserver {
private final Uri mDisplayInversionEnabledUri =
@@ -9416,4 +9422,16 @@
}
return type;
}
+ @Override
+ public boolean addToSurfaceSyncGroup(IBinder syncGroupToken, boolean parentSyncGroupMerge,
+ @Nullable ISurfaceSyncGroupCompletedListener completedListener,
+ AddToSurfaceSyncGroupResult outAddToSyncGroupResult) {
+ return mSurfaceSyncGroupController.addToSyncGroup(syncGroupToken, parentSyncGroupMerge,
+ completedListener, outAddToSyncGroupResult);
+ }
+
+ @Override
+ public void markSurfaceSyncGroupReady(IBinder syncGroupToken) {
+ mSurfaceSyncGroupController.markSyncGroupReady(syncGroupToken);
+ }
}
diff --git a/services/core/java/com/android/server/wm/WindowOrganizerController.java b/services/core/java/com/android/server/wm/WindowOrganizerController.java
index 7d15902..0a5e0b7 100644
--- a/services/core/java/com/android/server/wm/WindowOrganizerController.java
+++ b/services/core/java/com/android/server/wm/WindowOrganizerController.java
@@ -21,12 +21,20 @@
import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED;
import static android.app.WindowConfiguration.WINDOW_CONFIG_BOUNDS;
import static android.view.Display.DEFAULT_DISPLAY;
+import static android.window.TaskFragmentOperation.OP_TYPE_CLEAR_ADJACENT_TASK_FRAGMENTS;
+import static android.window.TaskFragmentOperation.OP_TYPE_CREATE_TASK_FRAGMENT;
+import static android.window.TaskFragmentOperation.OP_TYPE_DELETE_TASK_FRAGMENT;
+import static android.window.TaskFragmentOperation.OP_TYPE_REPARENT_ACTIVITY_TO_TASK_FRAGMENT;
+import static android.window.TaskFragmentOperation.OP_TYPE_REQUEST_FOCUS_ON_TASK_FRAGMENT;
+import static android.window.TaskFragmentOperation.OP_TYPE_SET_ADJACENT_TASK_FRAGMENTS;
import static android.window.TaskFragmentOperation.OP_TYPE_SET_ANIMATION_PARAMS;
+import static android.window.TaskFragmentOperation.OP_TYPE_SET_COMPANION_TASK_FRAGMENT;
+import static android.window.TaskFragmentOperation.OP_TYPE_START_ACTIVITY_IN_TASK_FRAGMENT;
+import static android.window.TaskFragmentOperation.OP_TYPE_UNKNOWN;
import static android.window.WindowContainerTransaction.HierarchyOp.HIERARCHY_OP_TYPE_ADD_RECT_INSETS_PROVIDER;
+import static android.window.WindowContainerTransaction.HierarchyOp.HIERARCHY_OP_TYPE_ADD_TASK_FRAGMENT_OPERATION;
import static android.window.WindowContainerTransaction.HierarchyOp.HIERARCHY_OP_TYPE_CHILDREN_TASKS_REPARENT;
import static android.window.WindowContainerTransaction.HierarchyOp.HIERARCHY_OP_TYPE_CLEAR_ADJACENT_ROOTS;
-import static android.window.WindowContainerTransaction.HierarchyOp.HIERARCHY_OP_TYPE_CREATE_TASK_FRAGMENT;
-import static android.window.WindowContainerTransaction.HierarchyOp.HIERARCHY_OP_TYPE_DELETE_TASK_FRAGMENT;
import static android.window.WindowContainerTransaction.HierarchyOp.HIERARCHY_OP_TYPE_FINISH_ACTIVITY;
import static android.window.WindowContainerTransaction.HierarchyOp.HIERARCHY_OP_TYPE_LAUNCH_TASK;
import static android.window.WindowContainerTransaction.HierarchyOp.HIERARCHY_OP_TYPE_PENDING_INTENT;
@@ -34,19 +42,12 @@
import static android.window.WindowContainerTransaction.HierarchyOp.HIERARCHY_OP_TYPE_REMOVE_TASK;
import static android.window.WindowContainerTransaction.HierarchyOp.HIERARCHY_OP_TYPE_REORDER;
import static android.window.WindowContainerTransaction.HierarchyOp.HIERARCHY_OP_TYPE_REPARENT;
-import static android.window.WindowContainerTransaction.HierarchyOp.HIERARCHY_OP_TYPE_REPARENT_ACTIVITY_TO_TASK_FRAGMENT;
-import static android.window.WindowContainerTransaction.HierarchyOp.HIERARCHY_OP_TYPE_REPARENT_CHILDREN;
-import static android.window.WindowContainerTransaction.HierarchyOp.HIERARCHY_OP_TYPE_REQUEST_FOCUS_ON_TASK_FRAGMENT;
import static android.window.WindowContainerTransaction.HierarchyOp.HIERARCHY_OP_TYPE_RESTORE_TRANSIENT_ORDER;
import static android.window.WindowContainerTransaction.HierarchyOp.HIERARCHY_OP_TYPE_SET_ADJACENT_ROOTS;
-import static android.window.WindowContainerTransaction.HierarchyOp.HIERARCHY_OP_TYPE_SET_ADJACENT_TASK_FRAGMENTS;
import static android.window.WindowContainerTransaction.HierarchyOp.HIERARCHY_OP_TYPE_SET_ALWAYS_ON_TOP;
-import static android.window.WindowContainerTransaction.HierarchyOp.HIERARCHY_OP_TYPE_SET_COMPANION_TASK_FRAGMENT;
import static android.window.WindowContainerTransaction.HierarchyOp.HIERARCHY_OP_TYPE_SET_LAUNCH_ADJACENT_FLAG_ROOT;
import static android.window.WindowContainerTransaction.HierarchyOp.HIERARCHY_OP_TYPE_SET_LAUNCH_ROOT;
import static android.window.WindowContainerTransaction.HierarchyOp.HIERARCHY_OP_TYPE_SET_REPARENT_LEAF_TASK_IF_RELAUNCH;
-import static android.window.WindowContainerTransaction.HierarchyOp.HIERARCHY_OP_TYPE_SET_TASK_FRAGMENT_OPERATION;
-import static android.window.WindowContainerTransaction.HierarchyOp.HIERARCHY_OP_TYPE_START_ACTIVITY_IN_TASK_FRAGMENT;
import static android.window.WindowContainerTransaction.HierarchyOp.HIERARCHY_OP_TYPE_START_SHORTCUT;
import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_WINDOW_ORGANIZER;
@@ -119,6 +120,7 @@
private static final String TAG = "WindowOrganizerController";
+ private static final int TRANSACT_EFFECTS_NONE = 0;
/** Flag indicating that an applied transaction may have effected lifecycle */
private static final int TRANSACT_EFFECTS_CLIENT_CONFIG = 1;
private static final int TRANSACT_EFFECTS_LIFECYCLE = 1 << 1;
@@ -488,7 +490,7 @@
private void applyTransaction(@NonNull WindowContainerTransaction t, int syncId,
@Nullable Transition transition, @NonNull CallerInfo caller,
@Nullable Transition finishTransition) {
- int effects = 0;
+ int effects = TRANSACT_EFFECTS_NONE;
ProtoLog.v(WM_DEBUG_WINDOW_ORGANIZER, "Apply window transaction, syncId=%d", syncId);
mService.deferWindowLayout();
mService.mTaskSupervisor.setDeferRootVisibilityUpdate(true /* deferUpdate */);
@@ -630,7 +632,7 @@
// masks here.
final int configMask = change.getConfigSetMask() & CONTROLLABLE_CONFIGS;
final int windowMask = change.getWindowSetMask() & CONTROLLABLE_WINDOW_CONFIGS;
- int effects = 0;
+ int effects = TRANSACT_EFFECTS_NONE;
final int windowingMode = change.getWindowingMode();
if (configMask != 0) {
@@ -795,7 +797,7 @@
@NonNull WindowContainerTransaction.Change c, @Nullable IBinder errorCallbackToken) {
if (taskFragment.isEmbeddedTaskFragmentInPip()) {
// No override from organizer for embedded TaskFragment in a PIP Task.
- return 0;
+ return TRANSACT_EFFECTS_NONE;
}
// When the TaskFragment is resized, we may want to create a change transition for it, for
@@ -861,197 +863,6 @@
effects |= clearAdjacentRootsHierarchyOp(hop);
break;
}
- case HIERARCHY_OP_TYPE_CREATE_TASK_FRAGMENT: {
- final TaskFragmentCreationParams taskFragmentCreationOptions =
- hop.getTaskFragmentCreationOptions();
- createTaskFragment(taskFragmentCreationOptions, errorCallbackToken, caller,
- transition);
- break;
- }
- case HIERARCHY_OP_TYPE_DELETE_TASK_FRAGMENT: {
- final WindowContainer wc = WindowContainer.fromBinder(hop.getContainer());
- if (wc == null || !wc.isAttached()) {
- Slog.e(TAG, "Attempt to operate on unknown or detached container: " + wc);
- break;
- }
- final TaskFragment taskFragment = wc.asTaskFragment();
- if (taskFragment == null || taskFragment.asTask() != null) {
- throw new IllegalArgumentException(
- "Can only delete organized TaskFragment, but not Task.");
- }
- if (isInLockTaskMode) {
- final ActivityRecord bottomActivity = taskFragment.getActivity(
- a -> !a.finishing, false /* traverseTopToBottom */);
- if (bottomActivity != null
- && mService.getLockTaskController().activityBlockedFromFinish(
- bottomActivity)) {
- Slog.w(TAG, "Skip removing TaskFragment due in lock task mode.");
- sendTaskFragmentOperationFailure(organizer, errorCallbackToken,
- taskFragment, type, new IllegalStateException(
- "Not allow to delete task fragment in lock task mode."));
- break;
- }
- }
- effects |= deleteTaskFragment(taskFragment, organizer, errorCallbackToken,
- transition);
- break;
- }
- case HIERARCHY_OP_TYPE_START_ACTIVITY_IN_TASK_FRAGMENT: {
- final IBinder fragmentToken = hop.getContainer();
- final TaskFragment tf = mLaunchTaskFragments.get(fragmentToken);
- if (tf == null) {
- final Throwable exception = new IllegalArgumentException(
- "Not allowed to operate with invalid fragment token");
- sendTaskFragmentOperationFailure(organizer, errorCallbackToken, tf, type,
- exception);
- break;
- }
- if (tf.isEmbeddedTaskFragmentInPip()) {
- final Throwable exception = new IllegalArgumentException(
- "Not allowed to start activity in PIP TaskFragment");
- sendTaskFragmentOperationFailure(organizer, errorCallbackToken, tf, type,
- exception);
- break;
- }
- final Intent activityIntent = hop.getActivityIntent();
- final Bundle activityOptions = hop.getLaunchOptions();
- final int result = mService.getActivityStartController()
- .startActivityInTaskFragment(tf, activityIntent, activityOptions,
- hop.getCallingActivity(), caller.mUid, caller.mPid,
- errorCallbackToken);
- if (!isStartResultSuccessful(result)) {
- sendTaskFragmentOperationFailure(organizer, errorCallbackToken, tf, type,
- convertStartFailureToThrowable(result, activityIntent));
- } else {
- effects |= TRANSACT_EFFECTS_LIFECYCLE;
- }
- break;
- }
- case HIERARCHY_OP_TYPE_REPARENT_ACTIVITY_TO_TASK_FRAGMENT: {
- final IBinder fragmentToken = hop.getNewParent();
- final IBinder activityToken = hop.getContainer();
- ActivityRecord activity = ActivityRecord.forTokenLocked(activityToken);
- if (activity == null) {
- // The token may be a temporary token if the activity doesn't belong to
- // the organizer process.
- activity = mTaskFragmentOrganizerController
- .getReparentActivityFromTemporaryToken(organizer, activityToken);
- }
- final TaskFragment parent = mLaunchTaskFragments.get(fragmentToken);
- if (parent == null || activity == null) {
- final Throwable exception = new IllegalArgumentException(
- "Not allowed to operate with invalid fragment token or activity.");
- sendTaskFragmentOperationFailure(organizer, errorCallbackToken, parent, type,
- exception);
- break;
- }
- if (parent.isEmbeddedTaskFragmentInPip()) {
- final Throwable exception = new IllegalArgumentException(
- "Not allowed to reparent activity to PIP TaskFragment");
- sendTaskFragmentOperationFailure(organizer, errorCallbackToken, parent, type,
- exception);
- break;
- }
- if (parent.isAllowedToEmbedActivity(activity) != EMBEDDING_ALLOWED) {
- final Throwable exception = new SecurityException(
- "The task fragment is not allowed to embed the given activity.");
- sendTaskFragmentOperationFailure(organizer, errorCallbackToken, parent, type,
- exception);
- break;
- }
- if (parent.getTask() != activity.getTask()) {
- final Throwable exception = new SecurityException("The reparented activity is"
- + " not in the same Task as the target TaskFragment.");
- sendTaskFragmentOperationFailure(organizer, errorCallbackToken, parent, type,
- exception);
- break;
- }
-
- if (transition != null) {
- transition.collect(activity);
- if (activity.getParent() != null) {
- // Collect the current parent. Its visibility may change as a result of
- // this reparenting.
- transition.collect(activity.getParent());
- }
- transition.collect(parent);
- }
- activity.reparent(parent, POSITION_TOP);
- effects |= TRANSACT_EFFECTS_LIFECYCLE;
- break;
- }
- case HIERARCHY_OP_TYPE_SET_ADJACENT_TASK_FRAGMENTS: {
- final IBinder fragmentToken = hop.getContainer();
- final IBinder adjacentFragmentToken = hop.getAdjacentRoot();
- final TaskFragment tf1 = mLaunchTaskFragments.get(fragmentToken);
- final TaskFragment tf2 = adjacentFragmentToken != null
- ? mLaunchTaskFragments.get(adjacentFragmentToken)
- : null;
- if (tf1 == null || (adjacentFragmentToken != null && tf2 == null)) {
- final Throwable exception = new IllegalArgumentException(
- "Not allowed to set adjacent on invalid fragment tokens");
- sendTaskFragmentOperationFailure(organizer, errorCallbackToken, tf1, type,
- exception);
- break;
- }
- if (tf1.isEmbeddedTaskFragmentInPip()
- || (tf2 != null && tf2.isEmbeddedTaskFragmentInPip())) {
- final Throwable exception = new IllegalArgumentException(
- "Not allowed to set adjacent on TaskFragment in PIP Task");
- sendTaskFragmentOperationFailure(organizer, errorCallbackToken, tf1, type,
- exception);
- break;
- }
- tf1.setAdjacentTaskFragment(tf2);
- effects |= TRANSACT_EFFECTS_LIFECYCLE;
-
- // Clear the focused app if the focused app is no longer visible after reset the
- // adjacent TaskFragments.
- if (tf2 == null && tf1.getDisplayContent().mFocusedApp != null
- && tf1.hasChild(tf1.getDisplayContent().mFocusedApp)
- && !tf1.shouldBeVisible(null /* starting */)) {
- tf1.getDisplayContent().setFocusedApp(null);
- }
-
- final Bundle bundle = hop.getLaunchOptions();
- final WindowContainerTransaction.TaskFragmentAdjacentParams adjacentParams =
- bundle != null ? new WindowContainerTransaction.TaskFragmentAdjacentParams(
- bundle) : null;
- if (adjacentParams == null) {
- break;
- }
-
- tf1.setDelayLastActivityRemoval(
- adjacentParams.shouldDelayPrimaryLastActivityRemoval());
- if (tf2 != null) {
- tf2.setDelayLastActivityRemoval(
- adjacentParams.shouldDelaySecondaryLastActivityRemoval());
- }
- break;
- }
- case HIERARCHY_OP_TYPE_REQUEST_FOCUS_ON_TASK_FRAGMENT: {
- final TaskFragment tf = mLaunchTaskFragments.get(hop.getContainer());
- if (tf == null || !tf.isAttached()) {
- Slog.e(TAG, "Attempt to operate on detached container: " + tf);
- break;
- }
- final ActivityRecord curFocus = tf.getDisplayContent().mFocusedApp;
- if (curFocus != null && curFocus.getTaskFragment() == tf) {
- Slog.d(TAG, "The requested TaskFragment already has the focus.");
- break;
- }
- if (curFocus != null && curFocus.getTask() != tf.getTask()) {
- Slog.d(TAG, "The Task of the requested TaskFragment doesn't have focus.");
- break;
- }
- final ActivityRecord targetFocus = tf.getTopResumedActivity();
- if (targetFocus == null) {
- Slog.d(TAG, "There is no resumed activity in the requested TaskFragment.");
- break;
- }
- tf.getDisplayContent().setFocusedApp(targetFocus);
- break;
- }
case HIERARCHY_OP_TYPE_CHILDREN_TASKS_REPARENT: {
effects |= reparentChildrenTasksHierarchyOp(hop, transition, syncId,
isInLockTaskMode);
@@ -1126,24 +937,9 @@
effects |= sanitizeAndApplyHierarchyOp(wc, hop);
break;
}
- case HIERARCHY_OP_TYPE_SET_COMPANION_TASK_FRAGMENT: {
- final IBinder fragmentToken = hop.getContainer();
- final IBinder companionToken = hop.getCompanionContainer();
- final TaskFragment fragment = mLaunchTaskFragments.get(fragmentToken);
- final TaskFragment companion = companionToken != null ? mLaunchTaskFragments.get(
- companionToken) : null;
- if (fragment == null || !fragment.isAttached()) {
- final Throwable exception = new IllegalArgumentException(
- "Not allowed to set companion on invalid fragment tokens");
- sendTaskFragmentOperationFailure(organizer, errorCallbackToken, fragment, type,
- exception);
- break;
- }
- fragment.setCompanionTaskFragment(companion);
- break;
- }
- case HIERARCHY_OP_TYPE_SET_TASK_FRAGMENT_OPERATION: {
- effects |= applyTaskFragmentOperation(hop, errorCallbackToken, organizer);
+ case HIERARCHY_OP_TYPE_ADD_TASK_FRAGMENT_OPERATION: {
+ effects |= applyTaskFragmentOperation(hop, transition, isInLockTaskMode, caller,
+ errorCallbackToken, organizer);
break;
}
default: {
@@ -1203,22 +999,6 @@
}
break;
}
- case HIERARCHY_OP_TYPE_REPARENT_CHILDREN: {
- final WindowContainer oldParent = WindowContainer.fromBinder(hop.getContainer());
- final WindowContainer newParent = hop.getNewParent() != null
- ? WindowContainer.fromBinder(hop.getNewParent())
- : null;
- if (oldParent == null || oldParent.asTaskFragment() == null
- || !oldParent.isAttached()) {
- Slog.e(TAG, "Attempt to operate on unknown or detached container: "
- + oldParent);
- break;
- }
- reparentTaskFragment(oldParent.asTaskFragment(), newParent, organizer,
- errorCallbackToken, transition);
- effects |= TRANSACT_EFFECTS_LIFECYCLE;
- break;
- }
case HIERARCHY_OP_TYPE_RESTORE_TRANSIENT_ORDER: {
if (finishTransition == null) break;
final WindowContainer container = WindowContainer.fromBinder(hop.getContainer());
@@ -1278,45 +1058,257 @@
return effects;
}
- /** Applies change set through {@link WindowContainerTransaction#setTaskFragmentOperation}. */
+ /**
+ * Applies change set through {@link WindowContainerTransaction#addTaskFragmentOperation}.
+ * @return an int to represent the transaction effects, such as {@link #TRANSACT_EFFECTS_NONE},
+ * {@link #TRANSACT_EFFECTS_LIFECYCLE} or {@link #TRANSACT_EFFECTS_CLIENT_CONFIG}.
+ */
private int applyTaskFragmentOperation(@NonNull WindowContainerTransaction.HierarchyOp hop,
+ @Nullable Transition transition, boolean isInLockTaskMode, @NonNull CallerInfo caller,
@Nullable IBinder errorCallbackToken, @Nullable ITaskFragmentOrganizer organizer) {
+ if (!validateTaskFragmentOperation(hop, errorCallbackToken, organizer)) {
+ return TRANSACT_EFFECTS_NONE;
+ }
final IBinder fragmentToken = hop.getContainer();
final TaskFragment taskFragment = mLaunchTaskFragments.get(fragmentToken);
final TaskFragmentOperation operation = hop.getTaskFragmentOperation();
- if (operation == null) {
- final Throwable exception = new IllegalArgumentException(
- "TaskFragmentOperation must be non-null");
- sendTaskFragmentOperationFailure(organizer, errorCallbackToken, taskFragment,
- HIERARCHY_OP_TYPE_SET_TASK_FRAGMENT_OPERATION, exception);
- return 0;
- }
final int opType = operation.getOpType();
- if (taskFragment == null || !taskFragment.isAttached()) {
- final Throwable exception = new IllegalArgumentException(
- "Not allowed to apply operation on invalid fragment tokens opType=" + opType);
- sendTaskFragmentOperationFailure(organizer, errorCallbackToken, taskFragment,
- HIERARCHY_OP_TYPE_SET_TASK_FRAGMENT_OPERATION, exception);
- return 0;
- }
- int effect = 0;
+ int effects = TRANSACT_EFFECTS_NONE;
switch (opType) {
+ case OP_TYPE_CREATE_TASK_FRAGMENT: {
+ final TaskFragmentCreationParams taskFragmentCreationParams =
+ operation.getTaskFragmentCreationParams();
+ if (taskFragmentCreationParams == null) {
+ final Throwable exception = new IllegalArgumentException(
+ "TaskFragmentCreationParams must be non-null");
+ sendTaskFragmentOperationFailure(organizer, errorCallbackToken, taskFragment,
+ opType, exception);
+ break;
+ }
+ createTaskFragment(taskFragmentCreationParams, errorCallbackToken, caller,
+ transition);
+ break;
+ }
+ case OP_TYPE_DELETE_TASK_FRAGMENT: {
+ if (isInLockTaskMode) {
+ final ActivityRecord bottomActivity = taskFragment.getActivity(
+ a -> !a.finishing, false /* traverseTopToBottom */);
+ if (bottomActivity != null
+ && mService.getLockTaskController().activityBlockedFromFinish(
+ bottomActivity)) {
+ Slog.w(TAG, "Skip removing TaskFragment due in lock task mode.");
+ sendTaskFragmentOperationFailure(organizer, errorCallbackToken,
+ taskFragment, opType, new IllegalStateException(
+ "Not allow to delete task fragment in lock task mode."));
+ break;
+ }
+ }
+ effects |= deleteTaskFragment(taskFragment, transition);
+ break;
+ }
+ case OP_TYPE_START_ACTIVITY_IN_TASK_FRAGMENT: {
+ final IBinder callerActivityToken = operation.getActivityToken();
+ final Intent activityIntent = operation.getActivityIntent();
+ final Bundle activityOptions = operation.getBundle();
+ final int result = mService.getActivityStartController()
+ .startActivityInTaskFragment(taskFragment, activityIntent, activityOptions,
+ callerActivityToken, caller.mUid, caller.mPid,
+ errorCallbackToken);
+ if (!isStartResultSuccessful(result)) {
+ sendTaskFragmentOperationFailure(organizer, errorCallbackToken, taskFragment,
+ opType, convertStartFailureToThrowable(result, activityIntent));
+ } else {
+ effects |= TRANSACT_EFFECTS_LIFECYCLE;
+ }
+ break;
+ }
+ case OP_TYPE_REPARENT_ACTIVITY_TO_TASK_FRAGMENT: {
+ final IBinder activityToken = operation.getActivityToken();
+ ActivityRecord activity = ActivityRecord.forTokenLocked(activityToken);
+ if (activity == null) {
+ // The token may be a temporary token if the activity doesn't belong to
+ // the organizer process.
+ activity = mTaskFragmentOrganizerController
+ .getReparentActivityFromTemporaryToken(organizer, activityToken);
+ }
+ if (activity == null) {
+ final Throwable exception = new IllegalArgumentException(
+ "Not allowed to operate with invalid activity.");
+ sendTaskFragmentOperationFailure(organizer, errorCallbackToken, taskFragment,
+ opType, exception);
+ break;
+ }
+ if (taskFragment.isAllowedToEmbedActivity(activity) != EMBEDDING_ALLOWED) {
+ final Throwable exception = new SecurityException(
+ "The task fragment is not allowed to embed the given activity.");
+ sendTaskFragmentOperationFailure(organizer, errorCallbackToken, taskFragment,
+ opType, exception);
+ break;
+ }
+ if (taskFragment.getTask() != activity.getTask()) {
+ final Throwable exception = new SecurityException("The reparented activity is"
+ + " not in the same Task as the target TaskFragment.");
+ sendTaskFragmentOperationFailure(organizer, errorCallbackToken, taskFragment,
+ opType, exception);
+ break;
+ }
+ if (transition != null) {
+ transition.collect(activity);
+ if (activity.getParent() != null) {
+ // Collect the current parent. Its visibility may change as a result of
+ // this reparenting.
+ transition.collect(activity.getParent());
+ }
+ transition.collect(taskFragment);
+ }
+ activity.reparent(taskFragment, POSITION_TOP);
+ effects |= TRANSACT_EFFECTS_LIFECYCLE;
+ break;
+ }
+ case OP_TYPE_SET_ADJACENT_TASK_FRAGMENTS: {
+ final IBinder secondaryFragmentToken = operation.getSecondaryFragmentToken();
+ final TaskFragment secondaryTaskFragment =
+ mLaunchTaskFragments.get(secondaryFragmentToken);
+ if (secondaryTaskFragment == null) {
+ final Throwable exception = new IllegalArgumentException(
+ "SecondaryFragmentToken must be set for setAdjacentTaskFragments.");
+ sendTaskFragmentOperationFailure(organizer, errorCallbackToken, taskFragment,
+ opType, exception);
+ break;
+ }
+ if (taskFragment.getAdjacentTaskFragment() != secondaryTaskFragment) {
+ // Only have lifecycle effect if the adjacent changed.
+ taskFragment.setAdjacentTaskFragment(secondaryTaskFragment);
+ effects |= TRANSACT_EFFECTS_LIFECYCLE;
+ }
+
+ final Bundle bundle = hop.getLaunchOptions();
+ final WindowContainerTransaction.TaskFragmentAdjacentParams adjacentParams =
+ bundle != null
+ ? new WindowContainerTransaction.TaskFragmentAdjacentParams(bundle)
+ : null;
+ taskFragment.setDelayLastActivityRemoval(adjacentParams != null
+ && adjacentParams.shouldDelayPrimaryLastActivityRemoval());
+ secondaryTaskFragment.setDelayLastActivityRemoval(adjacentParams != null
+ && adjacentParams.shouldDelaySecondaryLastActivityRemoval());
+ break;
+ }
+ case OP_TYPE_CLEAR_ADJACENT_TASK_FRAGMENTS: {
+ final TaskFragment adjacentTaskFragment = taskFragment.getAdjacentTaskFragment();
+ if (adjacentTaskFragment == null) {
+ break;
+ }
+ taskFragment.resetAdjacentTaskFragment();
+ effects |= TRANSACT_EFFECTS_LIFECYCLE;
+
+ // Clear the focused app if the focused app is no longer visible after reset the
+ // adjacent TaskFragments.
+ final ActivityRecord focusedApp = taskFragment.getDisplayContent().mFocusedApp;
+ final TaskFragment focusedTaskFragment = focusedApp != null
+ ? focusedApp.getTaskFragment()
+ : null;
+ if ((focusedTaskFragment == taskFragment
+ || focusedTaskFragment == adjacentTaskFragment)
+ && !focusedTaskFragment.shouldBeVisible(null /* starting */)) {
+ focusedTaskFragment.getDisplayContent().setFocusedApp(null /* newFocus */);
+ }
+ break;
+ }
+ case OP_TYPE_REQUEST_FOCUS_ON_TASK_FRAGMENT: {
+ final ActivityRecord curFocus = taskFragment.getDisplayContent().mFocusedApp;
+ if (curFocus != null && curFocus.getTaskFragment() == taskFragment) {
+ Slog.d(TAG, "The requested TaskFragment already has the focus.");
+ break;
+ }
+ if (curFocus != null && curFocus.getTask() != taskFragment.getTask()) {
+ Slog.d(TAG, "The Task of the requested TaskFragment doesn't have focus.");
+ break;
+ }
+ final ActivityRecord targetFocus = taskFragment.getTopResumedActivity();
+ if (targetFocus == null) {
+ Slog.d(TAG, "There is no resumed activity in the requested TaskFragment.");
+ break;
+ }
+ taskFragment.getDisplayContent().setFocusedApp(targetFocus);
+ break;
+ }
+ case OP_TYPE_SET_COMPANION_TASK_FRAGMENT: {
+ final IBinder companionFragmentToken = operation.getSecondaryFragmentToken();
+ final TaskFragment companionTaskFragment = companionFragmentToken != null
+ ? mLaunchTaskFragments.get(companionFragmentToken)
+ : null;
+ taskFragment.setCompanionTaskFragment(companionTaskFragment);
+ break;
+ }
case OP_TYPE_SET_ANIMATION_PARAMS: {
final TaskFragmentAnimationParams animationParams = operation.getAnimationParams();
if (animationParams == null) {
final Throwable exception = new IllegalArgumentException(
"TaskFragmentAnimationParams must be non-null");
sendTaskFragmentOperationFailure(organizer, errorCallbackToken, taskFragment,
- HIERARCHY_OP_TYPE_SET_TASK_FRAGMENT_OPERATION, exception);
+ opType, exception);
break;
}
taskFragment.setAnimationParams(animationParams);
break;
}
- // TODO(b/263436063): move other TaskFragment related operation here.
}
- return effect;
+ return effects;
+ }
+
+ private boolean validateTaskFragmentOperation(
+ @NonNull WindowContainerTransaction.HierarchyOp hop,
+ @Nullable IBinder errorCallbackToken, @Nullable ITaskFragmentOrganizer organizer) {
+ final TaskFragmentOperation operation = hop.getTaskFragmentOperation();
+ final IBinder fragmentToken = hop.getContainer();
+ final TaskFragment taskFragment = mLaunchTaskFragments.get(fragmentToken);
+ if (operation == null) {
+ final Throwable exception = new IllegalArgumentException(
+ "TaskFragmentOperation must be non-null");
+ sendTaskFragmentOperationFailure(organizer, errorCallbackToken, taskFragment,
+ OP_TYPE_UNKNOWN, exception);
+ return false;
+ }
+ final int opType = operation.getOpType();
+ if (opType == OP_TYPE_CREATE_TASK_FRAGMENT) {
+ // No need to check TaskFragment.
+ return true;
+ }
+
+ if (!validateTaskFragment(taskFragment, opType, errorCallbackToken, organizer)) {
+ return false;
+ }
+
+ final IBinder secondaryFragmentToken = operation.getSecondaryFragmentToken();
+ return secondaryFragmentToken == null
+ || validateTaskFragment(mLaunchTaskFragments.get(secondaryFragmentToken), opType,
+ errorCallbackToken, organizer);
+ }
+
+ private boolean validateTaskFragment(@Nullable TaskFragment taskFragment,
+ @TaskFragmentOperation.OperationType int opType, @Nullable IBinder errorCallbackToken,
+ @Nullable ITaskFragmentOrganizer organizer) {
+ if (taskFragment == null || !taskFragment.isAttached()) {
+ // TaskFragment doesn't exist.
+ final Throwable exception = new IllegalArgumentException(
+ "Not allowed to apply operation on invalid fragment tokens opType=" + opType);
+ sendTaskFragmentOperationFailure(organizer, errorCallbackToken, taskFragment,
+ opType, exception);
+ return false;
+ }
+ if (taskFragment.isEmbeddedTaskFragmentInPip()
+ && (opType != OP_TYPE_DELETE_TASK_FRAGMENT
+ // When the Task enters PiP before the organizer removes the empty TaskFragment, we
+ // should allow it to delete the TaskFragment for cleanup.
+ || taskFragment.getTopNonFinishingActivity() != null)) {
+ final Throwable exception = new IllegalArgumentException(
+ "Not allowed to apply operation on PIP TaskFragment");
+ sendTaskFragmentOperationFailure(organizer, errorCallbackToken, taskFragment,
+ opType, exception);
+ return false;
+ }
+ return true;
}
/** A helper method to send minimum dimension violation error to the client. */
@@ -1329,7 +1321,7 @@
+ taskFragment.getBounds() + " does not satisfy minimum dimensions:"
+ minDimensions + " " + reason);
sendTaskFragmentOperationFailure(taskFragment.getTaskFragmentOrganizer(),
- errorCallbackToken, taskFragment, -1 /* opType */, exception);
+ errorCallbackToken, taskFragment, OP_TYPE_UNKNOWN, exception);
}
/**
@@ -1366,7 +1358,7 @@
final DisplayContent dc = task.getDisplayContent();
if (dc == null) {
Slog.w(TAG, "Container is no longer attached: " + task);
- return 0;
+ return TRANSACT_EFFECTS_NONE;
}
final Task as = task;
@@ -1379,7 +1371,7 @@
: WindowContainer.fromBinder(hop.getNewParent());
if (newParent == null) {
Slog.e(TAG, "Can't resolve parent window from token");
- return 0;
+ return TRANSACT_EFFECTS_NONE;
}
if (task.getParent() != newParent) {
if (newParent.asTaskDisplayArea() != null) {
@@ -1390,14 +1382,14 @@
if (newParent.inPinnedWindowingMode()) {
Slog.w(TAG, "Can't support moving a task to another PIP window..."
+ " newParent=" + newParent + " task=" + task);
- return 0;
+ return TRANSACT_EFFECTS_NONE;
}
if (!task.supportsMultiWindowInDisplayArea(
newParent.asTask().getDisplayArea())) {
Slog.w(TAG, "Can't support task that doesn't support multi-window"
+ " mode in multi-window mode... newParent=" + newParent
+ " task=" + task);
- return 0;
+ return TRANSACT_EFFECTS_NONE;
}
}
task.reparent((Task) newParent,
@@ -1459,22 +1451,22 @@
if (currentParent == newParent) {
Slog.e(TAG, "reparentChildrenTasksHierarchyOp parent not changing: " + hop);
- return 0;
+ return TRANSACT_EFFECTS_NONE;
}
if (!currentParent.isAttached()) {
Slog.e(TAG, "reparentChildrenTasksHierarchyOp currentParent detached="
+ currentParent + " hop=" + hop);
- return 0;
+ return TRANSACT_EFFECTS_NONE;
}
if (!newParent.isAttached()) {
Slog.e(TAG, "reparentChildrenTasksHierarchyOp newParent detached="
+ newParent + " hop=" + hop);
- return 0;
+ return TRANSACT_EFFECTS_NONE;
}
if (newParent.inPinnedWindowingMode()) {
Slog.e(TAG, "reparentChildrenTasksHierarchyOp newParent in PIP="
+ newParent + " hop=" + hop);
- return 0;
+ return TRANSACT_EFFECTS_NONE;
}
final boolean newParentInMultiWindow = newParent.inMultiWindowMode();
@@ -1553,9 +1545,8 @@
throw new IllegalArgumentException("setAdjacentRootsHierarchyOp: Not created by"
+ " organizer root1=" + root1 + " root2=" + root2);
}
- if (root1.isEmbeddedTaskFragmentInPip() || root2.isEmbeddedTaskFragmentInPip()) {
- Slog.e(TAG, "Attempt to set adjacent TaskFragment in PIP Task");
- return 0;
+ if (root1.getAdjacentTaskFragment() == root2) {
+ return TRANSACT_EFFECTS_NONE;
}
root1.setAdjacentTaskFragment(root2);
return TRANSACT_EFFECTS_LIFECYCLE;
@@ -1567,7 +1558,9 @@
throw new IllegalArgumentException("clearAdjacentRootsHierarchyOp: Not created by"
+ " organizer root=" + root);
}
-
+ if (root.getAdjacentTaskFragment() == null) {
+ return TRANSACT_EFFECTS_NONE;
+ }
root.resetAdjacentTaskFragment();
return TRANSACT_EFFECTS_LIFECYCLE;
}
@@ -1725,52 +1718,12 @@
final int type = hop.getType();
// Check for each type of the operations that are allowed for TaskFragmentOrganizer.
switch (type) {
- case HIERARCHY_OP_TYPE_DELETE_TASK_FRAGMENT:
- enforceTaskFragmentOrganized(func,
- WindowContainer.fromBinder(hop.getContainer()), organizer);
- break;
- case HIERARCHY_OP_TYPE_SET_ADJACENT_ROOTS:
- enforceTaskFragmentOrganized(func,
- WindowContainer.fromBinder(hop.getContainer()), organizer);
- enforceTaskFragmentOrganized(func,
- WindowContainer.fromBinder(hop.getAdjacentRoot()),
- organizer);
- break;
- case HIERARCHY_OP_TYPE_CLEAR_ADJACENT_ROOTS:
- enforceTaskFragmentOrganized(func,
- WindowContainer.fromBinder(hop.getContainer()), organizer);
- break;
- case HIERARCHY_OP_TYPE_CREATE_TASK_FRAGMENT:
- // We are allowing organizer to create TaskFragment. We will check the
- // ownerToken in #createTaskFragment, and trigger error callback if that is not
- // valid.
- break;
- case HIERARCHY_OP_TYPE_START_ACTIVITY_IN_TASK_FRAGMENT:
- case HIERARCHY_OP_TYPE_REQUEST_FOCUS_ON_TASK_FRAGMENT:
- case HIERARCHY_OP_TYPE_SET_TASK_FRAGMENT_OPERATION:
+ case HIERARCHY_OP_TYPE_ADD_TASK_FRAGMENT_OPERATION:
enforceTaskFragmentOrganized(func, hop.getContainer(), organizer);
- break;
- case HIERARCHY_OP_TYPE_REPARENT_ACTIVITY_TO_TASK_FRAGMENT:
- enforceTaskFragmentOrganized(func, hop.getNewParent(), organizer);
- break;
- case HIERARCHY_OP_TYPE_SET_COMPANION_TASK_FRAGMENT:
- enforceTaskFragmentOrganized(func, hop.getContainer(), organizer);
- if (hop.getCompanionContainer() != null) {
- enforceTaskFragmentOrganized(func, hop.getCompanionContainer(), organizer);
- }
- break;
- case HIERARCHY_OP_TYPE_SET_ADJACENT_TASK_FRAGMENTS:
- enforceTaskFragmentOrganized(func, hop.getContainer(), organizer);
- if (hop.getAdjacentRoot() != null) {
- enforceTaskFragmentOrganized(func, hop.getAdjacentRoot(), organizer);
- }
- break;
- case HIERARCHY_OP_TYPE_REPARENT_CHILDREN:
- enforceTaskFragmentOrganized(func,
- WindowContainer.fromBinder(hop.getContainer()), organizer);
- if (hop.getNewParent() != null) {
+ if (hop.getTaskFragmentOperation() != null
+ && hop.getTaskFragmentOperation().getSecondaryFragmentToken() != null) {
enforceTaskFragmentOrganized(func,
- WindowContainer.fromBinder(hop.getNewParent()),
+ hop.getTaskFragmentOperation().getSecondaryFragmentToken(),
organizer);
}
break;
@@ -1917,21 +1870,21 @@
final Throwable exception =
new IllegalArgumentException("TaskFragment token must be unique");
sendTaskFragmentOperationFailure(organizer, errorCallbackToken, null /* taskFragment */,
- HIERARCHY_OP_TYPE_CREATE_TASK_FRAGMENT, exception);
+ OP_TYPE_CREATE_TASK_FRAGMENT, exception);
return;
}
if (ownerActivity == null || ownerActivity.getTask() == null) {
final Throwable exception =
new IllegalArgumentException("Not allowed to operate with invalid ownerToken");
sendTaskFragmentOperationFailure(organizer, errorCallbackToken, null /* taskFragment */,
- HIERARCHY_OP_TYPE_CREATE_TASK_FRAGMENT, exception);
+ OP_TYPE_CREATE_TASK_FRAGMENT, exception);
return;
}
if (!ownerActivity.isResizeable()) {
final IllegalArgumentException exception = new IllegalArgumentException("Not allowed"
+ " to operate with non-resizable owner Activity");
sendTaskFragmentOperationFailure(organizer, errorCallbackToken, null /* taskFragment */,
- HIERARCHY_OP_TYPE_CREATE_TASK_FRAGMENT, exception);
+ OP_TYPE_CREATE_TASK_FRAGMENT, exception);
return;
}
// The ownerActivity has to belong to the same app as the target Task.
@@ -1942,14 +1895,14 @@
new SecurityException("Not allowed to operate with the ownerToken while "
+ "the root activity of the target task belong to the different app");
sendTaskFragmentOperationFailure(organizer, errorCallbackToken, null /* taskFragment */,
- HIERARCHY_OP_TYPE_CREATE_TASK_FRAGMENT, exception);
+ OP_TYPE_CREATE_TASK_FRAGMENT, exception);
return;
}
if (ownerTask.inPinnedWindowingMode()) {
final Throwable exception = new IllegalArgumentException(
"Not allowed to create TaskFragment in PIP Task");
sendTaskFragmentOperationFailure(organizer, errorCallbackToken, null /* taskFragment */,
- HIERARCHY_OP_TYPE_CREATE_TASK_FRAGMENT, exception);
+ OP_TYPE_CREATE_TASK_FRAGMENT, exception);
return;
}
final TaskFragment taskFragment = new TaskFragment(mService,
@@ -1966,6 +1919,13 @@
creationParams.getPairedPrimaryFragmentToken());
final int pairedPosition = ownerTask.mChildren.indexOf(pairedPrimaryTaskFragment);
position = pairedPosition != -1 ? pairedPosition + 1 : POSITION_TOP;
+ } else if (creationParams.getPairedActivityToken() != null) {
+ // When there is a paired Activity, we want to place the new TaskFragment right above
+ // the paired Activity to make sure the Activity position is not changed after reparent.
+ final ActivityRecord pairedActivity = ActivityRecord.forTokenLocked(
+ creationParams.getPairedActivityToken());
+ final int pairedPosition = ownerTask.mChildren.indexOf(pairedActivity);
+ position = pairedPosition != -1 ? pairedPosition + 1 : POSITION_TOP;
} else {
position = POSITION_TOP;
}
@@ -1977,91 +1937,11 @@
if (transition != null) transition.collectExistenceChange(taskFragment);
}
- private void reparentTaskFragment(@NonNull TaskFragment oldParent,
- @Nullable WindowContainer<?> newParent, @Nullable ITaskFragmentOrganizer organizer,
- @Nullable IBinder errorCallbackToken, @Nullable Transition transition) {
- final TaskFragment newParentTF;
- if (newParent == null) {
- // Use the old parent's parent if the caller doesn't specify the new parent.
- newParentTF = oldParent.getTask();
- } else {
- newParentTF = newParent.asTaskFragment();
- }
- if (newParentTF == null) {
- final Throwable exception =
- new IllegalArgumentException("Not allowed to operate with invalid container");
- sendTaskFragmentOperationFailure(organizer, errorCallbackToken, newParentTF,
- HIERARCHY_OP_TYPE_REPARENT_CHILDREN, exception);
- return;
- }
- if (newParentTF.getTaskFragmentOrganizer() != null) {
- // We are reparenting activities to a new embedded TaskFragment, this operation is only
- // allowed if the new parent is trusted by all reparent activities.
- final boolean isEmbeddingDisallowed = oldParent.forAllActivities(activity ->
- newParentTF.isAllowedToEmbedActivity(activity) != EMBEDDING_ALLOWED);
- if (isEmbeddingDisallowed) {
- final Throwable exception = new SecurityException(
- "The new parent is not allowed to embed the activities.");
- sendTaskFragmentOperationFailure(organizer, errorCallbackToken, newParentTF,
- HIERARCHY_OP_TYPE_REPARENT_CHILDREN, exception);
- return;
- }
- }
- if (newParentTF.isEmbeddedTaskFragmentInPip() || oldParent.isEmbeddedTaskFragmentInPip()) {
- final Throwable exception = new SecurityException(
- "Not allow to reparent in TaskFragment in PIP Task.");
- sendTaskFragmentOperationFailure(organizer, errorCallbackToken, newParentTF,
- HIERARCHY_OP_TYPE_REPARENT_CHILDREN, exception);
- return;
- }
- if (newParentTF.getTask() != oldParent.getTask()) {
- final Throwable exception = new SecurityException(
- "The new parent is not in the same Task as the old parent.");
- sendTaskFragmentOperationFailure(organizer, errorCallbackToken, newParentTF,
- HIERARCHY_OP_TYPE_REPARENT_CHILDREN, exception);
- return;
- }
- if (transition != null) {
- // Collect the current parent. It's visibility may change as a result of this
- // reparenting.
- transition.collect(oldParent);
- transition.collect(newParentTF);
- }
- while (oldParent.hasChild()) {
- final WindowContainer child = oldParent.getChildAt(0);
- if (transition != null) {
- transition.collect(child);
- }
- child.reparent(newParentTF, POSITION_TOP);
- }
- }
-
private int deleteTaskFragment(@NonNull TaskFragment taskFragment,
- @Nullable ITaskFragmentOrganizer organizer, @Nullable IBinder errorCallbackToken,
@Nullable Transition transition) {
- final int index = mLaunchTaskFragments.indexOfValue(taskFragment);
- if (index < 0) {
- final Throwable exception =
- new IllegalArgumentException("Not allowed to operate with invalid "
- + "taskFragment");
- sendTaskFragmentOperationFailure(organizer, errorCallbackToken, taskFragment,
- HIERARCHY_OP_TYPE_DELETE_TASK_FRAGMENT, exception);
- return 0;
- }
- if (taskFragment.isEmbeddedTaskFragmentInPip()
- // When the Task enters PiP before the organizer removes the empty TaskFragment, we
- // should allow it to do the cleanup.
- && taskFragment.getTopNonFinishingActivity() != null) {
- final Throwable exception = new IllegalArgumentException(
- "Not allowed to delete TaskFragment in PIP Task");
- sendTaskFragmentOperationFailure(organizer, errorCallbackToken, taskFragment,
- HIERARCHY_OP_TYPE_DELETE_TASK_FRAGMENT, exception);
- return 0;
- }
-
if (transition != null) transition.collectExistenceChange(taskFragment);
- mLaunchTaskFragments.removeAt(index);
+ mLaunchTaskFragments.remove(taskFragment.getFragmentToken());
taskFragment.remove(true /* withTransition */, "deleteTaskFragment");
return TRANSACT_EFFECTS_LIFECYCLE;
}
@@ -2086,8 +1966,8 @@
}
void sendTaskFragmentOperationFailure(@NonNull ITaskFragmentOrganizer organizer,
- @Nullable IBinder errorCallbackToken, @Nullable TaskFragment taskFragment, int opType,
- @NonNull Throwable exception) {
+ @Nullable IBinder errorCallbackToken, @Nullable TaskFragment taskFragment,
+ @TaskFragmentOperation.OperationType int opType, @NonNull Throwable exception) {
if (organizer == null) {
throw new IllegalArgumentException("Not allowed to operate with invalid organizer");
}
diff --git a/services/core/java/com/android/server/wm/WindowState.java b/services/core/java/com/android/server/wm/WindowState.java
index 096f8f6..e08bacc 100644
--- a/services/core/java/com/android/server/wm/WindowState.java
+++ b/services/core/java/com/android/server/wm/WindowState.java
@@ -3068,12 +3068,6 @@
return mLastReportedConfiguration.getMergedConfiguration();
}
- /** Returns the last window configuration bounds reported to the client. */
- Rect getLastReportedBounds() {
- final Rect bounds = getLastReportedConfiguration().windowConfiguration.getBounds();
- return !bounds.isEmpty() ? bounds : getBounds();
- }
-
void adjustStartingWindowFlags() {
if (mAttrs.type == TYPE_BASE_APPLICATION && mActivityRecord != null
&& mActivityRecord.mStartingWindow != null) {
@@ -4390,6 +4384,9 @@
pw.print("null");
}
+ if (mXOffset != 0 || mYOffset != 0) {
+ pw.println(prefix + "mXOffset=" + mXOffset + " mYOffset=" + mYOffset);
+ }
if (mHScale != 1 || mVScale != 1) {
pw.println(prefix + "mHScale=" + mHScale
+ " mVScale=" + mVScale);
@@ -5527,7 +5524,7 @@
mSurfacePosition);
if (mWallpaperScale != 1f) {
- final Rect bounds = getLastReportedBounds();
+ final Rect bounds = getParentFrame();
Matrix matrix = mTmpMatrix;
matrix.setTranslate(mXOffset, mYOffset);
matrix.postScale(mWallpaperScale, mWallpaperScale, bounds.exactCenterX(),
@@ -5640,6 +5637,14 @@
&& imeTarget.compareTo(this) <= 0;
return inTokenWithAndAboveImeTarget;
}
+
+ // The condition is for the system dialog not belonging to any Activity.
+ // (^FLAG_NOT_FOCUSABLE & FLAG_ALT_FOCUSABLE_IM) means the dialog is still focusable but
+ // should be placed above the IME window.
+ if ((mAttrs.flags & (FLAG_NOT_FOCUSABLE | FLAG_ALT_FOCUSABLE_IM))
+ == FLAG_ALT_FOCUSABLE_IM && isTrustedOverlay() && canAddInternalSystemWindow()) {
+ return true;
+ }
return false;
}
@@ -6262,13 +6267,6 @@
}
@Override
- public void unfreezeInsetsAfterStartInput() {
- if (mActivityRecord != null) {
- mActivityRecord.mImeInsetsFrozenUntilStartInput = false;
- }
- }
-
- @Override
public boolean isInputMethodClientFocus(int uid, int pid) {
return getDisplayContent().isInputMethodClientFocus(uid, pid);
}
diff --git a/services/core/jni/com_android_server_companion_virtual_InputController.cpp b/services/core/jni/com_android_server_companion_virtual_InputController.cpp
index b7a4fd1..4cb7a8f 100644
--- a/services/core/jni/com_android_server_companion_virtual_InputController.cpp
+++ b/services/core/jni/com_android_server_companion_virtual_InputController.cpp
@@ -81,7 +81,7 @@
static std::map<int, int> DPAD_KEY_CODE_MAPPING = {
{AKEYCODE_DPAD_DOWN, KEY_DOWN}, {AKEYCODE_DPAD_UP, KEY_UP},
{AKEYCODE_DPAD_LEFT, KEY_LEFT}, {AKEYCODE_DPAD_RIGHT, KEY_RIGHT},
- {AKEYCODE_DPAD_CENTER, KEY_SELECT},
+ {AKEYCODE_DPAD_CENTER, KEY_SELECT}, {AKEYCODE_BACK, KEY_BACK},
};
// Keycode mapping from https://source.android.com/devices/input/keyboard-devices
@@ -378,7 +378,7 @@
const std::map<int, int>& keyCodeMapping) {
auto keyCodeIterator = keyCodeMapping.find(androidKeyCode);
if (keyCodeIterator == keyCodeMapping.end()) {
- ALOGE("No supportive native keycode for androidKeyCode %d", androidKeyCode);
+ ALOGE("Unsupported native keycode for androidKeyCode %d", androidKeyCode);
return false;
}
auto actionIterator = KEY_ACTION_MAPPING.find(action);
@@ -512,4 +512,4 @@
methods, NELEM(methods));
}
-} // namespace android
\ No newline at end of file
+} // namespace android
diff --git a/services/credentials/java/com/android/server/credentials/ClearRequestSession.java b/services/credentials/java/com/android/server/credentials/ClearRequestSession.java
index 2141d51..595d03d 100644
--- a/services/credentials/java/com/android/server/credentials/ClearRequestSession.java
+++ b/services/credentials/java/com/android/server/credentials/ClearRequestSession.java
@@ -84,14 +84,12 @@
respondToClientWithResponseAndFinish();
}
- @Override
protected void onProviderResponseComplete(ComponentName componentName) {
if (!isAnyProviderPending()) {
onFinalResponseReceived(componentName, null);
}
}
- @Override
protected void onProviderTerminated(ComponentName componentName) {
if (!isAnyProviderPending()) {
processResponses();
@@ -138,6 +136,6 @@
}
}
// TODO: Replace with properly defined error type
- respondToClientWithErrorAndFinish("unknown", "All providers failed");
+ respondToClientWithErrorAndFinish("UNKNOWN", "All providers failed");
}
}
diff --git a/services/credentials/java/com/android/server/credentials/CreateRequestSession.java b/services/credentials/java/com/android/server/credentials/CreateRequestSession.java
index 3091c0a..4b26ccd 100644
--- a/services/credentials/java/com/android/server/credentials/CreateRequestSession.java
+++ b/services/credentials/java/com/android/server/credentials/CreateRequestSession.java
@@ -20,6 +20,7 @@
import android.annotation.Nullable;
import android.content.ComponentName;
import android.content.Context;
+import android.credentials.CreateCredentialException;
import android.credentials.CreateCredentialRequest;
import android.credentials.CreateCredentialResponse;
import android.credentials.CredentialManager;
@@ -80,26 +81,20 @@
mClientAppInfo.getPackageName()),
providerDataList));
} catch (RemoteException e) {
- Log.i(TAG, "Issue with invoking pending intent: " + e.getMessage());
- // TODO: Propagate failure
+ respondToClientWithErrorAndFinish(
+ CreateCredentialException.TYPE_UNKNOWN,
+ "Unable to invoke selector");
}
}
@Override
- public void onProviderStatusChanged(ProviderSession.Status status,
- ComponentName componentName) {
- super.onProviderStatusChanged(status, componentName);
- }
-
- @Override
public void onFinalResponseReceived(ComponentName componentName,
@Nullable CreateCredentialResponse response) {
Log.i(TAG, "onFinalCredentialReceived from: " + componentName.flattenToString());
if (response != null) {
respondToClientWithResponseAndFinish(response);
} else {
- // TODO("Replace with properly defined error type)
- respondToClientWithErrorAndFinish("unknown_type",
+ respondToClientWithErrorAndFinish(CreateCredentialException.TYPE_NO_CREDENTIAL,
"Invalid response");
}
}
@@ -112,8 +107,7 @@
@Override
public void onUiCancellation() {
- // TODO("Replace with properly defined error type")
- respondToClientWithErrorAndFinish("user_cancelled",
+ respondToClientWithErrorAndFinish(CreateCredentialException.TYPE_USER_CANCELED,
"User cancelled the selector");
}
@@ -136,4 +130,22 @@
}
finishSession();
}
+
+ @Override
+ public void onProviderStatusChanged(ProviderSession.Status status,
+ ComponentName componentName) {
+ Log.i(TAG, "in onProviderStatusChanged with status: " + status);
+ // If all provider responses have been received, we can either need the UI,
+ // or we need to respond with error. The only other case is the entry being
+ // selected after the UI has been invoked which has a separate code path.
+ if (!isAnyProviderPending()) {
+ if (isUiInvocationNeeded()) {
+ Log.i(TAG, "in onProviderStatusChanged - isUiInvocationNeeded");
+ getProviderDataAndInitiateUi();
+ } else {
+ respondToClientWithErrorAndFinish(CreateCredentialException.TYPE_NO_CREDENTIAL,
+ "No credentials available");
+ }
+ }
+ }
}
diff --git a/services/credentials/java/com/android/server/credentials/CredentialManagerService.java b/services/credentials/java/com/android/server/credentials/CredentialManagerService.java
index 50ce1c3..aefd300 100644
--- a/services/credentials/java/com/android/server/credentials/CredentialManagerService.java
+++ b/services/credentials/java/com/android/server/credentials/CredentialManagerService.java
@@ -26,7 +26,9 @@
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.credentials.ClearCredentialStateRequest;
+import android.credentials.CreateCredentialException;
import android.credentials.CreateCredentialRequest;
+import android.credentials.GetCredentialException;
import android.credentials.GetCredentialOption;
import android.credentials.GetCredentialRequest;
import android.credentials.IClearCredentialStateCallback;
@@ -50,6 +52,7 @@
import android.text.TextUtils;
import android.util.Log;
import android.util.Slog;
+import android.util.SparseArray;
import com.android.internal.annotations.GuardedBy;
import com.android.server.infra.AbstractMasterSystemService;
@@ -73,6 +76,16 @@
private static final String TAG = "CredManSysService";
+ private final Context mContext;
+
+ /**
+ * Cache of system service list per user id.
+ */
+ @GuardedBy("mLock")
+ private final SparseArray<List<CredentialManagerServiceImpl>> mSystemServicesCacheList =
+ new SparseArray<>();
+
+
public CredentialManagerService(@NonNull Context context) {
super(
context,
@@ -80,6 +93,20 @@
context, Settings.Secure.CREDENTIAL_SERVICE, /* isMultipleMode= */ true),
null,
PACKAGE_UPDATE_POLICY_REFRESH_EAGER);
+ mContext = context;
+ }
+
+ @NonNull
+ @GuardedBy("mLock")
+ private List<CredentialManagerServiceImpl> constructSystemServiceListLocked(
+ int resolvedUserId) {
+ List<CredentialManagerServiceImpl> services = new ArrayList<>();
+ List<CredentialProviderInfo> credentialProviderInfos =
+ CredentialProviderInfo.getAvailableSystemServices(mContext, resolvedUserId);
+ credentialProviderInfos.forEach(info -> {
+ services.add(new CredentialManagerServiceImpl(this, mLock, resolvedUserId, info));
+ });
+ return services;
}
@Override
@@ -105,8 +132,10 @@
}
@Override // from AbstractMasterSystemService
+ @GuardedBy("mLock")
protected List<CredentialManagerServiceImpl> newServiceListLocked(
int resolvedUserId, boolean disabled, String[] serviceNames) {
+ getOrConstructSystemServiceListLock(resolvedUserId);
if (serviceNames == null || serviceNames.length == 0) {
Slog.i(TAG, "serviceNames sent in newServiceListLocked is null, or empty");
return new ArrayList<>();
@@ -155,13 +184,24 @@
// TODO("Iterate over system services and remove if needed")
}
+ @GuardedBy("mLock")
+ private List<CredentialManagerServiceImpl> getOrConstructSystemServiceListLock(
+ int resolvedUserId) {
+ List<CredentialManagerServiceImpl> services = mSystemServicesCacheList.get(resolvedUserId);
+ if (services == null || services.size() == 0) {
+ services = constructSystemServiceListLocked(resolvedUserId);
+ mSystemServicesCacheList.put(resolvedUserId, services);
+ }
+ return services;
+ }
+
private void runForUser(@NonNull final Consumer<CredentialManagerServiceImpl> c) {
final int userId = UserHandle.getCallingUserId();
final long origId = Binder.clearCallingIdentity();
try {
synchronized (mLock) {
final List<CredentialManagerServiceImpl> services =
- getServiceListForUserLocked(userId);
+ getAllCredentialProviderServicesLocked(userId);
for (CredentialManagerServiceImpl s : services) {
c.accept(s);
}
@@ -171,6 +211,19 @@
}
}
+ @GuardedBy("mLock")
+ private List<CredentialManagerServiceImpl> getAllCredentialProviderServicesLocked(
+ int userId) {
+ List<CredentialManagerServiceImpl> concatenatedServices = new ArrayList<>();
+ List<CredentialManagerServiceImpl> userConfigurableServices =
+ getServiceListForUserLocked(userId);
+ if (userConfigurableServices != null && !userConfigurableServices.isEmpty()) {
+ concatenatedServices.addAll(userConfigurableServices);
+ }
+ concatenatedServices.addAll(getOrConstructSystemServiceListLock(userId));
+ return concatenatedServices;
+ }
+
@SuppressWarnings("GuardedBy") // ErrorProne requires initiateProviderSessionForRequestLocked
// to be guarded by 'service.mLock', which is the same as mLock.
private List<ProviderSession> initiateProviderSessions(
@@ -235,8 +288,8 @@
if (providerSessions.isEmpty()) {
try {
- // TODO("Replace with properly defined error type")
- callback.onError("unknown_type", "No providers available to fulfill request.");
+ callback.onError(GetCredentialException.TYPE_NO_CREDENTIAL,
+ "No credentials available on this device.");
} catch (RemoteException e) {
Log.i(
TAG,
@@ -248,14 +301,10 @@
// Iterate over all provider sessions and invoke the request
providerSessions.forEach(
- providerGetSession -> {
- providerGetSession
- .getRemoteCredentialService()
- .onBeginGetCredential(
- (BeginGetCredentialRequest)
- providerGetSession.getProviderRequest(),
- /* callback= */ providerGetSession);
- });
+ providerGetSession -> providerGetSession
+ .getRemoteCredentialService().onBeginGetCredential(
+ (BeginGetCredentialRequest) providerGetSession.getProviderRequest(),
+ /*callback=*/providerGetSession));
return cancelTransport;
}
@@ -284,8 +333,8 @@
if (providerSessions.isEmpty()) {
try {
- // TODO("Replace with properly defined error type")
- callback.onError("unknown_type", "No providers available to fulfill request.");
+ callback.onError(CreateCredentialException.TYPE_NO_CREDENTIAL,
+ "No credentials available on this device.");
} catch (RemoteException e) {
Log.i(
TAG,
@@ -297,14 +346,12 @@
// Iterate over all provider sessions and invoke the request
providerSessions.forEach(
- providerCreateSession -> {
- providerCreateSession
- .getRemoteCredentialService()
- .onCreateCredential(
- (BeginCreateCredentialRequest)
- providerCreateSession.getProviderRequest(),
- /* callback= */ providerCreateSession);
- });
+ providerCreateSession -> providerCreateSession
+ .getRemoteCredentialService()
+ .onCreateCredential(
+ (BeginCreateCredentialRequest)
+ providerCreateSession.getProviderRequest(),
+ /* callback= */ providerCreateSession));
return cancelTransport;
}
@@ -402,7 +449,8 @@
if (providerSessions.isEmpty()) {
try {
// TODO("Replace with properly defined error type")
- callback.onError("unknown_type", "No providers available to fulfill request.");
+ callback.onError("UNKNOWN", "No crdentials available on this "
+ + "device");
} catch (RemoteException e) {
Log.i(
TAG,
diff --git a/services/credentials/java/com/android/server/credentials/CredentialManagerServiceImpl.java b/services/credentials/java/com/android/server/credentials/CredentialManagerServiceImpl.java
index 0fd1f19..546c48f 100644
--- a/services/credentials/java/com/android/server/credentials/CredentialManagerServiceImpl.java
+++ b/services/credentials/java/com/android/server/credentials/CredentialManagerServiceImpl.java
@@ -58,7 +58,18 @@
return mInfo.getServiceInfo().getComponentName();
}
- @Override // from PerUserSystemService
+ CredentialManagerServiceImpl(
+ @NonNull CredentialManagerService master,
+ @NonNull Object lock, int userId, CredentialProviderInfo providerInfo) {
+ super(master, lock, userId);
+ Log.i(TAG, "in CredentialManagerServiceImpl constructed with system constructor: "
+ + providerInfo.isSystemProvider()
+ + " , " + providerInfo.getServiceInfo() == null ? "" :
+ providerInfo.getServiceInfo().getComponentName().flattenToString());
+ mInfo = providerInfo;
+ }
+
+ @Override // from PerUserSystemService when a new setting based service is to be created
@GuardedBy("mLock")
protected ServiceInfo newServiceInfoLocked(@NonNull ComponentName serviceComponent)
throws PackageManager.NameNotFoundException {
@@ -71,7 +82,9 @@
Log.i(TAG, "newServiceInfoLocked with null mInfo , "
+ serviceComponent.getPackageName());
}
- mInfo = new CredentialProviderInfo(getContext(), serviceComponent, mUserId);
+ mInfo = new CredentialProviderInfo(
+ getContext(), serviceComponent,
+ mUserId, /*isSystemProvider=*/false);
return mInfo.getServiceInfo();
}
diff --git a/services/credentials/java/com/android/server/credentials/GetRequestSession.java b/services/credentials/java/com/android/server/credentials/GetRequestSession.java
index 06396e0..bbd0376 100644
--- a/services/credentials/java/com/android/server/credentials/GetRequestSession.java
+++ b/services/credentials/java/com/android/server/credentials/GetRequestSession.java
@@ -19,6 +19,7 @@
import android.annotation.Nullable;
import android.content.ComponentName;
import android.content.Context;
+import android.credentials.GetCredentialException;
import android.credentials.GetCredentialRequest;
import android.credentials.GetCredentialResponse;
import android.credentials.IGetCredentialCallback;
@@ -75,17 +76,11 @@
mRequestId, mClientRequest, mClientAppInfo.getPackageName()),
providerDataList));
} catch (RemoteException e) {
- Log.i(TAG, "Issue with invoking pending intent: " + e.getMessage());
- // TODO: Propagate failure
+ respondToClientWithErrorAndFinish(
+ GetCredentialException.TYPE_UNKNOWN, "Unable to instantiate selector");
}
}
- @Override // from provider session
- public void onProviderStatusChanged(ProviderSession.Status status,
- ComponentName componentName) {
- super.onProviderStatusChanged(status, componentName);
- }
-
@Override
public void onFinalResponseReceived(ComponentName componentName,
@Nullable GetCredentialResponse response) {
@@ -93,8 +88,7 @@
if (response != null) {
respondToClientWithResponseAndFinish(response);
} else {
- // TODO("Replace with no credentials/unknown type when ready)
- respondToClientWithErrorAndFinish("unknown_type",
+ respondToClientWithErrorAndFinish(GetCredentialException.TYPE_NO_CREDENTIAL,
"Invalid response from provider");
}
}
@@ -108,29 +102,45 @@
}
private void respondToClientWithResponseAndFinish(GetCredentialResponse response) {
- Log.i(TAG, "respondToClientWithResponseAndFinish");
try {
mClientCallback.onResponse(response);
} catch (RemoteException e) {
- e.printStackTrace();
+ Log.i(TAG, "Issue while responding to client with a response : " + e.getMessage());
}
finishSession();
}
private void respondToClientWithErrorAndFinish(String errorType, String errorMsg) {
- Log.i(TAG, "respondToClientWithErrorAndFinish");
try {
mClientCallback.onError(errorType, errorMsg);
} catch (RemoteException e) {
- e.printStackTrace();
+ Log.i(TAG, "Issue while responding to client with error : " + e.getMessage());
+
}
finishSession();
}
@Override
public void onUiCancellation() {
- // TODO("Replace with properly defined error type")
- respondToClientWithErrorAndFinish("user_canceled",
+ respondToClientWithErrorAndFinish(GetCredentialException.TYPE_USER_CANCELED,
"User cancelled the selector");
}
+
+ @Override
+ public void onProviderStatusChanged(ProviderSession.Status status,
+ ComponentName componentName) {
+ Log.i(TAG, "in onStatusChanged with status: " + status);
+ if (!isAnyProviderPending()) {
+ // If all provider responses have been received, we can either need the UI,
+ // or we need to respond with error. The only other case is the entry being
+ // selected after the UI has been invoked which has a separate code path.
+ if (isUiInvocationNeeded()) {
+ Log.i(TAG, "in onProviderStatusChanged - isUiInvocationNeeded");
+ getProviderDataAndInitiateUi();
+ } else {
+ respondToClientWithErrorAndFinish(GetCredentialException.TYPE_NO_CREDENTIAL,
+ "No credentials available");
+ }
+ }
+ }
}
diff --git a/services/credentials/java/com/android/server/credentials/PendingIntentResultHandler.java b/services/credentials/java/com/android/server/credentials/PendingIntentResultHandler.java
index 8796314..c2b346f 100644
--- a/services/credentials/java/com/android/server/credentials/PendingIntentResultHandler.java
+++ b/services/credentials/java/com/android/server/credentials/PendingIntentResultHandler.java
@@ -39,6 +39,12 @@
return pendingIntentResponse.getResultCode() == Activity.RESULT_OK;
}
+ /** Returns true if the pending intent was cancelled by the user. */
+ public static boolean isCancelledResponse(
+ ProviderPendingIntentResponse pendingIntentResponse) {
+ return pendingIntentResponse.getResultCode() == Activity.RESULT_CANCELED;
+ }
+
/** Extracts the {@link CredentialsResponseContent} object added to the result data. */
public static CredentialsResponseContent extractResponseContent(Intent resultData) {
if (resultData == null) {
diff --git a/services/credentials/java/com/android/server/credentials/ProviderCreateSession.java b/services/credentials/java/com/android/server/credentials/ProviderCreateSession.java
index 9163b8e..7a24a22 100644
--- a/services/credentials/java/com/android/server/credentials/ProviderCreateSession.java
+++ b/services/credentials/java/com/android/server/credentials/ProviderCreateSession.java
@@ -22,6 +22,7 @@
import android.content.Context;
import android.content.Intent;
import android.credentials.CreateCredentialException;
+import android.credentials.CreateCredentialResponse;
import android.credentials.ui.CreateCredentialProviderData;
import android.credentials.ui.Entry;
import android.credentials.ui.ProviderPendingIntentResponse;
@@ -98,7 +99,7 @@
private ProviderCreateSession(
@NonNull Context context,
@NonNull CredentialProviderInfo info,
- @NonNull ProviderInternalCallback callbacks,
+ @NonNull ProviderInternalCallback<CreateCredentialResponse> callbacks,
@UserIdInt int userId,
@NonNull RemoteCredentialService remoteCredentialService,
@NonNull BeginCreateCredentialRequest beginCreateRequest,
@@ -180,9 +181,7 @@
onSaveEntrySelected(providerPendingIntentResponse);
} else {
Log.i(TAG, "Unexpected save entry key");
- // TODO("Replace with no credentials error type");
- invokeCallbackWithError("unknown_type",
- "Issue while retrieving credential");
+ invokeCallbackOnInternalInvalidState();
}
break;
case REMOTE_ENTRY_KEY:
@@ -190,9 +189,7 @@
onRemoteEntrySelected(providerPendingIntentResponse);
} else {
Log.i(TAG, "Unexpected remote entry key");
- // TODO("Replace with unknown/no credentials exception")
- invokeCallbackWithError("unknown_type",
- "Issue while retrieving credential");
+ invokeCallbackOnInternalInvalidState();
}
break;
default:
@@ -248,23 +245,16 @@
} else {
Log.i(TAG, "onSaveEntrySelected - no response or error found in pending "
+ "intent response");
- invokeCallbackWithError(
- // TODO("Replace with unknown/no credentials exception")
- "unknown",
- "Issue encountered while retrieving the credential");
+ invokeCallbackOnInternalInvalidState();
}
}
- private void invokeCallbackWithError(String errorType, @Nullable String message) {
- mCallbacks.onFinalErrorReceived(mComponentName, errorType, message);
- }
-
@Nullable
private CreateCredentialException maybeGetPendingIntentException(
ProviderPendingIntentResponse pendingIntentResponse) {
if (pendingIntentResponse == null) {
Log.i(TAG, "pendingIntentResponse is null");
- return null;
+ return new CreateCredentialException(CreateCredentialException.TYPE_NO_CREDENTIAL);
}
if (PendingIntentResultHandler.isValidResponse(pendingIntentResponse)) {
CreateCredentialException exception = PendingIntentResultHandler
@@ -273,11 +263,21 @@
Log.i(TAG, "Pending intent contains provider exception");
return exception;
}
+ } else if (PendingIntentResultHandler.isCancelledResponse(pendingIntentResponse)) {
+ return new CreateCredentialException(CreateCredentialException.TYPE_USER_CANCELED);
} else {
- Log.i(TAG, "Pending intent result code not Activity.RESULT_OK");
- // TODO("Update with unknown exception when ready")
- return new CreateCredentialException("unknown");
+ return new CreateCredentialException(CreateCredentialException.TYPE_NO_CREDENTIAL);
}
return null;
}
+
+ /**
+ * When an invalid state occurs, e.g. entry mismatch or no response from provider,
+ * we send back a TYPE_UNKNOWN error as to the developer.
+ */
+ private void invokeCallbackOnInternalInvalidState() {
+ mCallbacks.onFinalErrorReceived(mComponentName,
+ CreateCredentialException.TYPE_UNKNOWN,
+ null);
+ }
}
diff --git a/services/credentials/java/com/android/server/credentials/ProviderGetSession.java b/services/credentials/java/com/android/server/credentials/ProviderGetSession.java
index 9846d83..9a99e34 100644
--- a/services/credentials/java/com/android/server/credentials/ProviderGetSession.java
+++ b/services/credentials/java/com/android/server/credentials/ProviderGetSession.java
@@ -144,7 +144,7 @@
public ProviderGetSession(Context context,
CredentialProviderInfo info,
- ProviderInternalCallback callbacks,
+ ProviderInternalCallback<GetCredentialResponse> callbacks,
int userId, RemoteCredentialService remoteCredentialService,
BeginGetCredentialRequest beginGetRequest,
android.credentials.GetCredentialRequest completeGetRequest) {
@@ -195,9 +195,7 @@
CredentialEntry credentialEntry = mUiCredentialEntries.get(entryKey);
if (credentialEntry == null) {
Log.i(TAG, "Unexpected credential entry key");
- // TODO("Replace with no credentials/unknown exception")
- invokeCallbackWithError("unknown_type",
- "Issue while retrieving credential");
+ invokeCallbackOnInternalInvalidState();
return;
}
onCredentialEntrySelected(credentialEntry, providerPendingIntentResponse);
@@ -206,9 +204,7 @@
Action actionEntry = mUiActionsEntries.get(entryKey);
if (actionEntry == null) {
Log.i(TAG, "Unexpected action entry key");
- // TODO("Replace with no credentials/unknown exception")
- invokeCallbackWithError("unknown_type",
- "Issue while retrieving credential");
+ invokeCallbackOnInternalInvalidState();
return;
}
onActionEntrySelected(providerPendingIntentResponse);
@@ -218,9 +214,7 @@
onAuthenticationEntrySelected(providerPendingIntentResponse);
} else {
Log.i(TAG, "Unexpected authentication entry key");
- // TODO("Replace with no credentials/unknown exception")
- invokeCallbackWithError("unknown_type",
- "Issue while retrieving credential");
+ invokeCallbackOnInternalInvalidState();
}
break;
case REMOTE_ENTRY_KEY:
@@ -228,9 +222,7 @@
onRemoteEntrySelected(providerPendingIntentResponse);
} else {
Log.i(TAG, "Unexpected remote entry key");
- // TODO("Replace with no credentials/unknown exception")
- invokeCallbackWithError("unknown_type",
- "Issue while retrieving credential");
+ invokeCallbackOnInternalInvalidState();
}
break;
default:
@@ -238,11 +230,6 @@
}
}
- private void invokeCallbackWithError(String errorType, @Nullable String errorMessage) {
- // TODO: Determine what the error message should be
- mCallbacks.onFinalErrorReceived(mComponentName, errorType, errorMessage);
- }
-
@Override // Call from request session to data to be shown on the UI
@Nullable protected GetCredentialProviderData prepareUiData() throws IllegalArgumentException {
Log.i(TAG, "In prepareUiData");
@@ -288,7 +275,8 @@
String entryId = generateEntryId();
Entry authEntry = new Entry(
AUTHENTICATION_ACTION_ENTRY_KEY, entryId,
- authenticationAction.getSlice());
+ authenticationAction.getSlice(),
+ setUpFillInIntentForAuthentication());
mUiAuthenticationAction = new Pair<>(entryId, authenticationAction);
return authEntry;
}
@@ -324,6 +312,15 @@
return intent;
}
+ private Intent setUpFillInIntentForAuthentication() {
+ Intent intent = new Intent();
+ intent.putExtra(
+ CredentialProviderService
+ .EXTRA_BEGIN_GET_CREDENTIAL_REQUEST,
+ mProviderRequest);
+ return intent;
+ }
+
private List<Entry> prepareUiActionEntries(@Nullable List<Action> actions) {
List<Entry> actionEntries = new ArrayList<>();
for (Action action : actions) {
@@ -369,20 +366,15 @@
}
Log.i(TAG, "Pending intent response contains no credential, or error");
- // TODO("Replace with no credentials/unknown error when ready)
- invokeCallbackWithError("unknown_type",
- "Issue while retrieving credential");
+ invokeCallbackOnInternalInvalidState();
}
Log.i(TAG, "CredentialEntry does not have a credential or a pending intent result");
- // TODO("Replace with no credentials/unknown error when ready)
- invokeCallbackWithError("unknown_type",
- "Error encountered while retrieving the credential");
+ invokeCallbackOnInternalInvalidState();
}
private void onAuthenticationEntrySelected(
@Nullable ProviderPendingIntentResponse providerPendingIntentResponse) {
//TODO: Other provider intent statuses
- // Check if pending intent has an error
GetCredentialException exception = maybeGetPendingIntentException(
providerPendingIntentResponse);
if (exception != null) {
@@ -401,9 +393,7 @@
}
Log.i(TAG, "No error or respond found in pending intent response");
- // TODO("Replace with no credentials/unknown error when ready)
- invokeCallbackWithError("unknown type", "Issue"
- + " while retrieving credential");
+ invokeCallbackOnInternalInvalidState();
}
private void onActionEntrySelected(ProviderPendingIntentResponse
@@ -430,7 +420,7 @@
ProviderPendingIntentResponse pendingIntentResponse) {
if (pendingIntentResponse == null) {
Log.i(TAG, "pendingIntentResponse is null");
- return null;
+ return new GetCredentialException(GetCredentialException.TYPE_NO_CREDENTIAL);
}
if (PendingIntentResultHandler.isValidResponse(pendingIntentResponse)) {
GetCredentialException exception = PendingIntentResultHandler
@@ -439,11 +429,20 @@
Log.i(TAG, "Pending intent contains provider exception");
return exception;
}
+ } else if (PendingIntentResultHandler.isCancelledResponse(pendingIntentResponse)) {
+ return new GetCredentialException(GetCredentialException.TYPE_USER_CANCELED);
} else {
- Log.i(TAG, "Pending intent result code not Activity.RESULT_OK");
- // TODO("Update with unknown exception when ready")
- return new GetCredentialException("unknown");
+ return new GetCredentialException(GetCredentialException.TYPE_NO_CREDENTIAL);
}
return null;
}
+
+ /**
+ * When an invalid state occurs, e.g. entry mismatch or no response from provider,
+ * we send back a TYPE_UNKNOWN error as to the developer.
+ */
+ private void invokeCallbackOnInternalInvalidState() {
+ mCallbacks.onFinalErrorReceived(mComponentName,
+ GetCredentialException.TYPE_UNKNOWN, null);
+ }
}
diff --git a/services/credentials/java/com/android/server/credentials/ProviderSession.java b/services/credentials/java/com/android/server/credentials/ProviderSession.java
index 93e816a..7036dfb 100644
--- a/services/credentials/java/com/android/server/credentials/ProviderSession.java
+++ b/services/credentials/java/com/android/server/credentials/ProviderSession.java
@@ -191,6 +191,11 @@
return mProviderResponse != null || mProviderResponseSet;
}
+ protected void invokeCallbackWithError(String errorType, @Nullable String errorMessage) {
+ // TODO: Determine what the error message should be
+ mCallbacks.onFinalErrorReceived(mComponentName, errorType, errorMessage);
+ }
+
/** Update the response state stored with the provider session. */
@Nullable protected R getProviderResponse() {
return mProviderResponse;
diff --git a/services/credentials/java/com/android/server/credentials/RequestSession.java b/services/credentials/java/com/android/server/credentials/RequestSession.java
index f59a0ef..0c3c34e 100644
--- a/services/credentials/java/com/android/server/credentials/RequestSession.java
+++ b/services/credentials/java/com/android/server/credentials/RequestSession.java
@@ -18,7 +18,6 @@
import android.annotation.NonNull;
import android.annotation.UserIdInt;
-import android.content.ComponentName;
import android.content.Context;
import android.credentials.ui.ProviderData;
import android.credentials.ui.UserSelectionDialogResult;
@@ -98,41 +97,6 @@
finishSession();
}
- protected void onProviderStatusChanged(ProviderSession.Status status,
- ComponentName componentName) {
- Log.i(TAG, "in onStatusChanged with status: " + status);
- if (ProviderSession.isTerminatingStatus(status)) {
- Log.i(TAG, "in onStatusChanged terminating status");
- onProviderTerminated(componentName);
- //TODO: Check if this was the provider we were waiting for and can invoke the UI now
- } else if (ProviderSession.isCompletionStatus(status)) {
- Log.i(TAG, "in onStatusChanged isCompletionStatus status");
- onProviderResponseComplete(componentName);
- } else if (ProviderSession.isUiInvokingStatus(status)) {
- Log.i(TAG, "in onStatusChanged isUiInvokingStatus status");
- onProviderResponseRequiresUi();
- }
- }
-
- protected void onProviderTerminated(ComponentName componentName) {
- //TODO: Implement
- }
-
- protected void onProviderResponseComplete(ComponentName componentName) {
- //TODO: Implement
- }
-
- protected void onProviderResponseRequiresUi() {
- Log.i(TAG, "in onProviderResponseComplete");
- // TODO: Determine whether UI has already been invoked, and deal accordingly
- if (!isAnyProviderPending()) {
- Log.i(TAG, "in onProviderResponseComplete - isResponseCompleteAcrossProviders");
- getProviderDataAndInitiateUi();
- } else {
- Log.i(TAG, "Can't invoke UI - waiting on some providers");
- }
- }
-
protected void finishSession() {
Log.i(TAG, "finishing session");
clearProviderSessions();
@@ -144,7 +108,7 @@
mProviders.clear();
}
- boolean isAnyProviderPending() {
+ protected boolean isAnyProviderPending() {
for (ProviderSession session : mProviders.values()) {
if (ProviderSession.isStatusWaitingForRemoteResponse(session.getStatus())) {
return true;
@@ -153,7 +117,22 @@
return false;
}
- private void getProviderDataAndInitiateUi() {
+ /**
+ * Returns true if at least one provider is ready for UI invocation, and no
+ * provider is pending a response.
+ */
+ boolean isUiInvocationNeeded() {
+ for (ProviderSession session : mProviders.values()) {
+ if (ProviderSession.isUiInvokingStatus(session.getStatus())) {
+ return true;
+ } else if (ProviderSession.isStatusWaitingForRemoteResponse(session.getStatus())) {
+ return false;
+ }
+ }
+ return false;
+ }
+
+ void getProviderDataAndInitiateUi() {
Log.i(TAG, "In getProviderDataAndInitiateUi");
Log.i(TAG, "In getProviderDataAndInitiateUi providers size: " + mProviders.size());
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
index cdb2e08..8be3df4 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
@@ -8742,21 +8742,6 @@
}
}
- private boolean isDeviceOwnerPackage(String packageName, int userId) {
- synchronized (getLockObject()) {
- return mOwners.hasDeviceOwner()
- && mOwners.getDeviceOwnerUserId() == userId
- && mOwners.getDeviceOwnerPackageName().equals(packageName);
- }
- }
-
- private boolean isProfileOwnerPackage(String packageName, int userId) {
- synchronized (getLockObject()) {
- return mOwners.hasProfileOwner(userId)
- && mOwners.getProfileOwnerPackage(userId).equals(packageName);
- }
- }
-
public boolean isProfileOwner(ComponentName who, int userId) {
final ComponentName profileOwner = mInjector.binderWithCleanCallingIdentity(() ->
getProfileOwnerAsUser(userId));
@@ -9315,7 +9300,7 @@
boolean hasProfileOwner = mOwners.hasProfileOwner(userId);
if (!hasProfileOwner) {
int managedUserId = getManagedUserId(userId);
- if (managedUserId == -1 && newState != STATE_USER_UNMANAGED) {
+ if (managedUserId < 0 && newState != STATE_USER_UNMANAGED) {
// No managed device, user or profile, so setting provisioning state makes
// no sense.
String error = "Not allowed to change provisioning state unless a "
@@ -12524,7 +12509,7 @@
/**
* @return the user ID of the managed user that is linked to the current user, if any.
- * Otherwise -1.
+ * Otherwise UserHandle.USER_NULL (-10000).
*/
public int getManagedUserId(@UserIdInt int callingUserId) {
if (VERBOSE_LOG) Slogf.v(LOG_TAG, "getManagedUserId: callingUserId=%d", callingUserId);
@@ -12537,7 +12522,26 @@
return ui.id;
}
if (VERBOSE_LOG) Slogf.v(LOG_TAG, "Managed user not found.");
- return -1;
+ return UserHandle.USER_NULL;
+ }
+
+ /**
+ * Returns the userId of the managed profile on the device.
+ * If none exists, return {@link UserHandle#USER_NULL}.
+ *
+ * We assume there is only one managed profile across all users
+ * on the device, which is true for now (HSUM or not) but could
+ * change in future.
+ */
+ private @UserIdInt int getManagedUserId() {
+ // On HSUM, there is only one main user and only the main user
+ // can have a managed profile (for now). On non-HSUM, only user 0
+ // can host the managed profile and user 0 is the main user.
+ // So in both cases, we could just get the main user and
+ // search for the profile user under it.
+ UserHandle mainUser = mUserManager.getMainUser();
+ if (mainUser == null) return UserHandle.USER_NULL;
+ return getManagedUserId(mainUser.getIdentifier());
}
@Override
@@ -16187,7 +16191,7 @@
return mOwners.getDeviceOwnerUserId();
} else {
return mInjector.binderWithCleanCallingIdentity(
- () -> getManagedUserId(UserHandle.USER_SYSTEM));
+ () -> getManagedUserId());
}
}
}
diff --git a/services/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java
index 5b9460a..5c5442d 100644
--- a/services/java/com/android/server/SystemServer.java
+++ b/services/java/com/android/server/SystemServer.java
@@ -108,7 +108,6 @@
import com.android.server.am.ActivityManagerService;
import com.android.server.ambientcontext.AmbientContextManagerService;
import com.android.server.appbinding.AppBindingService;
-import com.android.server.art.ArtManagerLocal;
import com.android.server.art.ArtModuleServiceInitializer;
import com.android.server.art.DexUseManagerLocal;
import com.android.server.attention.AttentionManagerService;
@@ -132,8 +131,8 @@
import com.android.server.display.color.ColorDisplayService;
import com.android.server.dreams.DreamManagerService;
import com.android.server.emergency.EmergencyAffordanceService;
-import com.android.server.grammaticalinflection.GrammaticalInflectionService;
import com.android.server.gpu.GpuService;
+import com.android.server.grammaticalinflection.GrammaticalInflectionService;
import com.android.server.graphics.fonts.FontManagerService;
import com.android.server.hdmi.HdmiControlService;
import com.android.server.incident.IncidentCompanionService;
@@ -147,6 +146,7 @@
import com.android.server.media.MediaRouterService;
import com.android.server.media.metrics.MediaMetricsManagerService;
import com.android.server.media.projection.MediaProjectionManagerService;
+import com.android.server.net.NetworkManagementService;
import com.android.server.net.NetworkPolicyManagerService;
import com.android.server.net.watchlist.NetworkWatchlistService;
import com.android.server.notification.NotificationManagerService;
@@ -163,6 +163,7 @@
import com.android.server.pm.BackgroundInstallControlService;
import com.android.server.pm.CrossProfileAppsService;
import com.android.server.pm.DataLoaderManagerService;
+import com.android.server.pm.DexOptHelper;
import com.android.server.pm.DynamicCodeLoggingService;
import com.android.server.pm.Installer;
import com.android.server.pm.LauncherAppsService;
@@ -1250,7 +1251,7 @@
// DexUseManagerLocal needs to be loaded after PackageManagerLocal has been registered, but
// before PackageManagerService starts processing binder calls to notifyDexLoad.
LocalManagerRegistry.addManager(
- DexUseManagerLocal.class, DexUseManagerLocal.createInstance());
+ DexUseManagerLocal.class, DexUseManagerLocal.createInstance(mSystemContext));
t.traceEnd();
if (!mRuntimeRestart && !isFirstBootOrUpgrade()) {
@@ -2770,7 +2771,7 @@
t.traceEnd();
t.traceBegin("ArtManagerLocal");
- LocalManagerRegistry.addManager(ArtManagerLocal.class, new ArtManagerLocal(context));
+ DexOptHelper.initializeArtManagerLocal(context, mPackageManagerService);
t.traceEnd();
if (context.getPackageManager().hasSystemFeature(PackageManager.FEATURE_UWB)) {
diff --git a/services/permission/java/com/android/server/permission/access/collection/IndexedMap.kt b/services/permission/java/com/android/server/permission/access/collection/IndexedMap.kt
index f4e362c..998d206 100644
--- a/services/permission/java/com/android/server/permission/access/collection/IndexedMap.kt
+++ b/services/permission/java/com/android/server/permission/access/collection/IndexedMap.kt
@@ -148,6 +148,13 @@
return isChanged
}
+inline fun <K, V, R> IndexedMap<K, V>.mapIndexed(transform: (Int, K, V) -> R): IndexedList<R> =
+ IndexedList<R>().also { destination ->
+ forEachIndexed { index, key, value ->
+ transform(index, key, value).let { destination += it }
+ }
+ }
+
inline fun <K, V, R> IndexedMap<K, V>.mapNotNullIndexed(
transform: (Int, K, V) -> R?
): IndexedList<R> =
diff --git a/services/permission/java/com/android/server/permission/access/permission/PermissionService.kt b/services/permission/java/com/android/server/permission/access/permission/PermissionService.kt
index b8c0376..c7e9371 100644
--- a/services/permission/java/com/android/server/permission/access/permission/PermissionService.kt
+++ b/services/permission/java/com/android/server/permission/access/permission/PermissionService.kt
@@ -73,6 +73,7 @@
import com.android.server.pm.UserManagerService
import com.android.server.pm.parsing.pkg.AndroidPackageUtils
import com.android.server.pm.permission.LegacyPermission
+import com.android.server.pm.permission.Permission as LegacyPermission2
import com.android.server.pm.permission.LegacyPermissionSettings
import com.android.server.pm.permission.LegacyPermissionState
import com.android.server.pm.permission.PermissionManagerServiceInterface
@@ -1673,40 +1674,77 @@
context.getSystemService(PermissionControllerManager::class.java)!!.dump(fd, args)
}
- override fun getPermissionTEMP(
- permissionName: String
- ): com.android.server.pm.permission.Permission? {
- // TODO("Not yet implemented")
- return null
+ override fun getPermissionTEMP(permissionName: String): LegacyPermission2? {
+ val permission = service.getState {
+ with(policy) { getPermissions()[permissionName] }
+ } ?: return null
+
+ return LegacyPermission2(
+ permission.permissionInfo, permission.type, permission.isReconciled, permission.appId,
+ permission.gids, permission.areGidsPerUser
+ )
}
- override fun getLegacyPermissions(): List<LegacyPermission> {
- // TODO("Not yet implemented")
- return emptyList()
- }
+ override fun getLegacyPermissions(): List<LegacyPermission> =
+ service.getState {
+ with(policy) { getPermissions() }
+ }.mapIndexed { _, _, permission ->
+ LegacyPermission(
+ permission.permissionInfo, permission.type, permission.appId, permission.gids
+ )
+ }
override fun readLegacyPermissionsTEMP(legacyPermissionSettings: LegacyPermissionSettings) {
// Package settings has been read when this method is called.
service.initialize()
- // TODO("Not yet implemented")
}
override fun writeLegacyPermissionsTEMP(legacyPermissionSettings: LegacyPermissionSettings) {
- // TODO("Not yet implemented")
+ service.getState {
+ val permissions = with(policy) { getPermissions() }
+ legacyPermissionSettings.replacePermissions(toLegacyPermissions(permissions))
+ val permissionTrees = with(policy) { getPermissionTrees() }
+ legacyPermissionSettings.replacePermissionTrees(toLegacyPermissions(permissionTrees))
+ }
}
+ private fun toLegacyPermissions(
+ permissions: IndexedMap<String, Permission>
+ ): List<LegacyPermission> =
+ permissions.mapIndexed { _, _, permission ->
+ // We don't need to provide UID and GIDs, which are only retrieved when dumping.
+ LegacyPermission(
+ permission.permissionInfo, permission.type, 0, EmptyArray.INT
+ )
+ }
+
override fun getLegacyPermissionState(appId: Int): LegacyPermissionState {
- // TODO("Not yet implemented")
- return LegacyPermissionState()
+ val legacyState = LegacyPermissionState()
+ val userIds = userManagerService.userIdsIncludingPreCreated
+ service.getState {
+ val permissions = with(policy) { getPermissions() }
+ userIds.forEachIndexed { _, userId ->
+ val permissionFlags = with(policy) { getUidPermissionFlags(appId, userId) }
+ ?: return@forEachIndexed
+
+ permissionFlags.forEachIndexed permissionFlags@{ _, permissionName, flags ->
+ val permission = permissions[permissionName] ?: return@permissionFlags
+ val legacyPermissionState = LegacyPermissionState.PermissionState(
+ permissionName,
+ permission.isRuntime,
+ PermissionFlags.isPermissionGranted(flags),
+ PermissionFlags.toApiFlags(flags)
+ )
+ legacyState.putPermissionState(legacyPermissionState, userId)
+ }
+ }
+ }
+ return legacyState
}
- override fun readLegacyPermissionStateTEMP() {
- // TODO("Not yet implemented")
- }
+ override fun readLegacyPermissionStateTEMP() {}
- override fun writeLegacyPermissionStateTEMP() {
- // TODO("Not yet implemented")
- }
+ override fun writeLegacyPermissionStateTEMP() {}
override fun onSystemReady() {
service.onSystemReady()
diff --git a/services/tests/PackageManagerServiceTests/server/src/com/android/server/pm/AppsFilterImplTest.java b/services/tests/PackageManagerServiceTests/server/src/com/android/server/pm/AppsFilterImplTest.java
index 5e5e7e3..7909ba4 100644
--- a/services/tests/PackageManagerServiceTests/server/src/com/android/server/pm/AppsFilterImplTest.java
+++ b/services/tests/PackageManagerServiceTests/server/src/com/android/server/pm/AppsFilterImplTest.java
@@ -283,7 +283,7 @@
assertFalse(
appsFilter.shouldFilterApplication(mSnapshot, DUMMY_CALLING_APPID, calling, target,
SYSTEM_USER));
- watcher.verifyNoChangeReported("shouldFilterAplication");
+ watcher.verifyNoChangeReported("shouldFilterApplication");
}
@Test
@@ -1024,7 +1024,10 @@
DUMMY_TARGET_APPID);
PackageSetting calling = simulateAddPackage(appsFilter, pkg("com.some.other.package"),
DUMMY_CALLING_APPID,
- withInstallSource(target.getPackageName(), null, null, INVALID_UID, null, false));
+ withInstallSource(target.getPackageName(), null /* originatingPackageName */,
+ null /* installerPackageName */, INVALID_UID,
+ null /* updateOwnerPackageName */, null /* installerAttributionTag */,
+ false /* isInitiatingPackageUninstalled */));
assertFalse(
appsFilter.shouldFilterApplication(mSnapshot, DUMMY_CALLING_APPID, calling, target,
@@ -1043,7 +1046,10 @@
DUMMY_TARGET_APPID);
PackageSetting calling = simulateAddPackage(appsFilter, pkg("com.some.other.package"),
DUMMY_CALLING_APPID,
- withInstallSource(target.getPackageName(), null, null, INVALID_UID, null, true));
+ withInstallSource(target.getPackageName(), null /* originatingPackageName */,
+ null /* installerPackageName */, INVALID_UID,
+ null /* updateOwnerPackageName */, null /* installerAttributionTag */,
+ true /* isInitiatingPackageUninstalled */));
assertTrue(
appsFilter.shouldFilterApplication(mSnapshot, DUMMY_CALLING_APPID, calling, target,
@@ -1066,14 +1072,16 @@
DUMMY_TARGET_APPID);
watcher.verifyChangeReported("add package");
PackageSetting calling = simulateAddPackage(appsFilter, pkg("com.some.other.package"),
- DUMMY_CALLING_APPID, withInstallSource(null, target.getPackageName(), null,
- INVALID_UID, null, false));
+ DUMMY_CALLING_APPID, withInstallSource(null /* initiatingPackageName */,
+ target.getPackageName(), null /* installerPackageName */, INVALID_UID,
+ null /* updateOwnerPackageName */, null /* installerAttributionTag */,
+ false /* isInitiatingPackageUninstalled */));
watcher.verifyChangeReported("add package");
assertTrue(
appsFilter.shouldFilterApplication(mSnapshot, DUMMY_CALLING_APPID, calling, target,
SYSTEM_USER));
- watcher.verifyNoChangeReported("shouldFilterAplication");
+ watcher.verifyNoChangeReported("shouldFilterApplication");
}
@Test
@@ -1092,14 +1100,46 @@
DUMMY_TARGET_APPID);
watcher.verifyChangeReported("add package");
PackageSetting calling = simulateAddPackage(appsFilter, pkg("com.some.other.package"),
- DUMMY_CALLING_APPID, withInstallSource(null, null, target.getPackageName(),
- DUMMY_TARGET_APPID, null, false));
+ DUMMY_CALLING_APPID, withInstallSource(null /* initiatingPackageName */,
+ null /* originatingPackageName */, target.getPackageName(),
+ DUMMY_TARGET_APPID, null /* updateOwnerPackageName */,
+ null /* installerAttributionTag */,
+ false /* isInitiatingPackageUninstalled */));
watcher.verifyChangeReported("add package");
assertFalse(
appsFilter.shouldFilterApplication(mSnapshot, DUMMY_CALLING_APPID, calling, target,
SYSTEM_USER));
- watcher.verifyNoChangeReported("shouldFilterAplication");
+ watcher.verifyNoChangeReported("shouldFilterApplication");
+ }
+
+ @Test
+ public void testUpdateOwner_DoesntFilter() throws Exception {
+ final AppsFilterImpl appsFilter =
+ new AppsFilterImpl(mFeatureConfigMock, new String[]{}, /* systemAppsQueryable */
+ false, /* overlayProvider */ null, mMockHandler);
+ final WatchableTester watcher = new WatchableTester(appsFilter, "onChange");
+ watcher.register();
+ simulateAddBasicAndroid(appsFilter);
+ watcher.verifyChangeReported("addBasicAndroid");
+ appsFilter.onSystemReady(mPmInternal);
+ watcher.verifyChangeReported("systemReady");
+
+ PackageSetting target = simulateAddPackage(appsFilter, pkg("com.some.package"),
+ DUMMY_TARGET_APPID);
+ watcher.verifyChangeReported("add package");
+ PackageSetting calling = simulateAddPackage(appsFilter, pkg("com.some.other.package"),
+ DUMMY_CALLING_APPID, withInstallSource(null /* initiatingPackageName */,
+ null /* originatingPackageName */, null /* installerPackageName */,
+ INVALID_UID, target.getPackageName(),
+ null /* installerAttributionTag */,
+ false /* isInitiatingPackageUninstalled */));
+ watcher.verifyChangeReported("add package");
+
+ assertFalse(
+ appsFilter.shouldFilterApplication(mSnapshot, DUMMY_CALLING_APPID, calling, target,
+ SYSTEM_USER));
+ watcher.verifyNoChangeReported("shouldFilterApplication");
}
@Test
@@ -1128,7 +1168,7 @@
assertFalse(
appsFilter.shouldFilterApplication(mSnapshot, DUMMY_TARGET_APPID, target,
instrumentation, SYSTEM_USER));
- watcher.verifyNoChangeReported("shouldFilterAplication");
+ watcher.verifyNoChangeReported("shouldFilterApplication");
}
@Test
@@ -1679,10 +1719,12 @@
private WithSettingBuilder withInstallSource(String initiatingPackageName,
String originatingPackageName, String installerPackageName, int installerPackageUid,
- String installerAttributionTag, boolean isInitiatingPackageUninstalled) {
+ String updateOwnerPackageName, String installerAttributionTag,
+ boolean isInitiatingPackageUninstalled) {
final InstallSource installSource = InstallSource.create(initiatingPackageName,
originatingPackageName, installerPackageName, installerPackageUid,
- installerAttributionTag, /* isOrphaned= */ false, isInitiatingPackageUninstalled);
+ updateOwnerPackageName, installerAttributionTag, /* isOrphaned= */ false,
+ isInitiatingPackageUninstalled);
return setting -> setting.setInstallSource(installSource);
}
}
diff --git a/services/tests/PackageManagerServiceTests/server/src/com/android/server/pm/PackageInstallerSessionTest.java b/services/tests/PackageManagerServiceTests/server/src/com/android/server/pm/PackageInstallerSessionTest.java
index 4da082e..98655c8 100644
--- a/services/tests/PackageManagerServiceTests/server/src/com/android/server/pm/PackageInstallerSessionTest.java
+++ b/services/tests/PackageManagerServiceTests/server/src/com/android/server/pm/PackageInstallerSessionTest.java
@@ -167,8 +167,8 @@
params.isMultiPackage = true;
}
InstallSource installSource = InstallSource.create("testInstallInitiator",
- "testInstallOriginator", "testInstaller", -1, "testAttributionTag",
- PackageInstaller.PACKAGE_SOURCE_UNSPECIFIED);
+ "testInstallOriginator", "testInstaller", -1, "testUpdateOwner",
+ "testAttributionTag", PackageInstaller.PACKAGE_SOURCE_UNSPECIFIED);
return new PackageInstallerSession(
/* callback */ null,
/* context */null,
diff --git a/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/parsing/parcelling/AndroidPackageTest.kt b/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/parsing/parcelling/AndroidPackageTest.kt
index 8e1ca3c..0b7020c7 100644
--- a/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/parsing/parcelling/AndroidPackageTest.kt
+++ b/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/parsing/parcelling/AndroidPackageTest.kt
@@ -218,6 +218,7 @@
AndroidPackage::isAllowClearUserDataOnFailedRestore,
AndroidPackage::isAllowNativeHeapPointerTagging,
AndroidPackage::isAllowTaskReparenting,
+ AndroidPackage::isAllowUpdateOwnership,
AndroidPackage::isBackupInForeground,
AndroidPackage::isHardwareAccelerated,
AndroidPackage::isCantSaveState,
diff --git a/services/tests/RemoteProvisioningServiceTests/src/com/android/server/security/rkp/RemoteProvisioningRegistrationTest.java b/services/tests/RemoteProvisioningServiceTests/src/com/android/server/security/rkp/RemoteProvisioningRegistrationTest.java
index 470f2be..7b361d3 100644
--- a/services/tests/RemoteProvisioningServiceTests/src/com/android/server/security/rkp/RemoteProvisioningRegistrationTest.java
+++ b/services/tests/RemoteProvisioningServiceTests/src/com/android/server/security/rkp/RemoteProvisioningRegistrationTest.java
@@ -34,7 +34,9 @@
import android.os.CancellationSignal;
import android.os.OperationCanceledException;
import android.os.OutcomeReceiver;
+import android.os.RemoteException;
import android.security.rkp.IGetKeyCallback;
+import android.security.rkp.IStoreUpgradedKeyCallback;
import android.security.rkp.service.RegistrationProxy;
import android.security.rkp.service.RemotelyProvisionedKey;
@@ -72,6 +74,12 @@
return answerVoid(answer);
}
+ // answerVoid wrapper for mocking storeUpgradeKeyAsync.
+ static Answer<Void> answerStoreUpgradedKeyAsync(
+ VoidAnswer4<byte[], byte[], Executor, OutcomeReceiver<Void, Exception>> answer) {
+ return answerVoid(answer);
+ }
+
// matcher helper, making it easier to match the different key types
private android.security.rkp.RemotelyProvisionedKey matches(
RemotelyProvisionedKey expectedKey) {
@@ -178,16 +186,63 @@
@Test
public void storeUpgradedKeySuccess() throws Exception {
- // TODO(b/262748535)
+ doAnswer(
+ answerStoreUpgradedKeyAsync((oldBlob, newBlob, executor, receiver) ->
+ executor.execute(() -> receiver.onResult(null))))
+ .when(mRegistrationProxy)
+ .storeUpgradedKeyAsync(any(), any(), any(), any());
+
+ IStoreUpgradedKeyCallback callback = mock(IStoreUpgradedKeyCallback.class);
+ mRegistration.storeUpgradedKeyAsync(new byte[0], new byte[0], callback);
+ verify(callback).onSuccess();
+ verifyNoMoreInteractions(callback);
}
@Test
public void storeUpgradedKeyFails() throws Exception {
- // TODO(b/262748535)
+ final String errorString = "this is a failure";
+ doAnswer(
+ answerStoreUpgradedKeyAsync((oldBlob, newBlob, executor, receiver) ->
+ executor.execute(() -> receiver.onError(new RemoteException(errorString)))))
+ .when(mRegistrationProxy)
+ .storeUpgradedKeyAsync(any(), any(), any(), any());
+
+ IStoreUpgradedKeyCallback callback = mock(IStoreUpgradedKeyCallback.class);
+ mRegistration.storeUpgradedKeyAsync(new byte[0], new byte[0], callback);
+ verify(callback).onError(errorString);
+ verifyNoMoreInteractions(callback);
}
@Test
- public void storeUpgradedCatchesExceptionFromProxy() throws Exception {
- // TODO(b/262748535)
+ public void storeUpgradedKeyHandlesException() throws Exception {
+ final String errorString = "all aboard the failboat, toot toot";
+ doThrow(new IllegalArgumentException(errorString))
+ .when(mRegistrationProxy)
+ .storeUpgradedKeyAsync(any(), any(), any(), any());
+
+ IStoreUpgradedKeyCallback callback = mock(IStoreUpgradedKeyCallback.class);
+ mRegistration.storeUpgradedKeyAsync(new byte[0], new byte[0], callback);
+ verify(callback).onError(errorString);
+ verifyNoMoreInteractions(callback);
}
+
+ @Test
+ public void storeUpgradedKeyDuplicateCallback() throws Exception {
+ IStoreUpgradedKeyCallback callback = mock(IStoreUpgradedKeyCallback.class);
+
+ doAnswer(
+ answerStoreUpgradedKeyAsync((oldBlob, newBlob, executor, receiver) -> {
+ assertThrows(IllegalArgumentException.class,
+ () -> mRegistration.storeUpgradedKeyAsync(new byte[0], new byte[0],
+ callback));
+ executor.execute(() -> receiver.onResult(null));
+ }))
+ .when(mRegistrationProxy)
+ .storeUpgradedKeyAsync(any(), any(), any(), any());
+
+ mRegistration.storeUpgradedKeyAsync(new byte[0], new byte[0], callback);
+ verify(callback).onSuccess();
+ verifyNoMoreInteractions(callback);
+ }
+
}
diff --git a/services/tests/mockingservicestests/src/com/android/server/am/BroadcastQueueModernImplTest.java b/services/tests/mockingservicestests/src/com/android/server/am/BroadcastQueueModernImplTest.java
index 77127c5..92570aa 100644
--- a/services/tests/mockingservicestests/src/com/android/server/am/BroadcastQueueModernImplTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/am/BroadcastQueueModernImplTest.java
@@ -22,7 +22,6 @@
import static com.android.server.am.BroadcastProcessQueue.REASON_CONTAINS_MANIFEST;
import static com.android.server.am.BroadcastProcessQueue.REASON_CONTAINS_ORDERED;
import static com.android.server.am.BroadcastProcessQueue.REASON_CONTAINS_PRIORITIZED;
-import static com.android.server.am.BroadcastProcessQueue.REASON_CONTAINS_RESULT_TO;
import static com.android.server.am.BroadcastProcessQueue.insertIntoRunnableList;
import static com.android.server.am.BroadcastProcessQueue.removeFromRunnableList;
import static com.android.server.am.BroadcastQueueTest.CLASS_BLUE;
@@ -115,8 +114,29 @@
mConstants.DELAY_NORMAL_MILLIS = 10_000;
mConstants.DELAY_CACHED_MILLIS = 120_000;
+ final BroadcastSkipPolicy emptySkipPolicy = new BroadcastSkipPolicy(mAms) {
+ public boolean shouldSkip(BroadcastRecord r, Object o) {
+ // Ignored
+ return false;
+ }
+ public String shouldSkipMessage(BroadcastRecord r, Object o) {
+ // Ignored
+ return null;
+ }
+ public boolean disallowBackgroundStart(BroadcastRecord r) {
+ // Ignored
+ return false;
+ }
+ };
+ final BroadcastHistory emptyHistory = new BroadcastHistory(mConstants) {
+ public void addBroadcastToHistoryLocked(BroadcastRecord original) {
+ // Ignored
+ }
+ };
+
+
mImpl = new BroadcastQueueModernImpl(mAms, mHandlerThread.getThreadHandler(),
- mConstants, mConstants);
+ mConstants, mConstants, emptySkipPolicy, emptyHistory);
doReturn(1L).when(mQueue1).getRunnableAt();
doReturn(2L).when(mQueue2).getRunnableAt();
@@ -200,7 +220,8 @@
private void enqueueOrReplaceBroadcast(BroadcastProcessQueue queue,
BroadcastRecord record, int recordIndex, long enqueueTime) {
- queue.enqueueOrReplaceBroadcast(record, recordIndex, null /* replacedBroadcastConsumer */);
+ queue.enqueueOrReplaceBroadcast(record, recordIndex,
+ null /* replacedBroadcastConsumer */, false);
record.enqueueTime = enqueueTime;
}
@@ -330,7 +351,8 @@
final Intent airplane = new Intent(Intent.ACTION_AIRPLANE_MODE_CHANGED);
final BroadcastRecord airplaneRecord = makeBroadcastRecord(airplane,
List.of(makeMockRegisteredReceiver()));
- queue.enqueueOrReplaceBroadcast(airplaneRecord, 0, null /* replacedBroadcastConsumer */);
+ queue.enqueueOrReplaceBroadcast(airplaneRecord, 0,
+ null /* replacedBroadcastConsumer */, false);
queue.setProcessCached(false);
final long notCachedRunnableAt = queue.getRunnableAt();
@@ -352,12 +374,14 @@
// enqueue a bg-priority broadcast then a fg-priority one
final Intent timezone = new Intent(Intent.ACTION_TIMEZONE_CHANGED);
final BroadcastRecord timezoneRecord = makeBroadcastRecord(timezone);
- queue.enqueueOrReplaceBroadcast(timezoneRecord, 0, null /* replacedBroadcastConsumer */);
+ queue.enqueueOrReplaceBroadcast(timezoneRecord, 0,
+ null /* replacedBroadcastConsumer */, false);
final Intent airplane = new Intent(Intent.ACTION_AIRPLANE_MODE_CHANGED);
airplane.addFlags(Intent.FLAG_RECEIVER_FOREGROUND);
final BroadcastRecord airplaneRecord = makeBroadcastRecord(airplane);
- queue.enqueueOrReplaceBroadcast(airplaneRecord, 0, null /* replacedBroadcastConsumer */);
+ queue.enqueueOrReplaceBroadcast(airplaneRecord, 0,
+ null /* replacedBroadcastConsumer */, false);
// verify that:
// (a) the queue is immediately runnable by existence of a fg-priority broadcast
@@ -388,7 +412,8 @@
final BroadcastRecord airplaneRecord = makeBroadcastRecord(airplane, null,
List.of(withPriority(makeManifestReceiver(PACKAGE_GREEN, CLASS_GREEN), 10),
withPriority(makeManifestReceiver(PACKAGE_GREEN, CLASS_GREEN), 0)), true);
- queue.enqueueOrReplaceBroadcast(airplaneRecord, 1, null /* replacedBroadcastConsumer */);
+ queue.enqueueOrReplaceBroadcast(airplaneRecord, 1,
+ null /* replacedBroadcastConsumer */, false);
assertFalse(queue.isRunnable());
assertEquals(BroadcastProcessQueue.REASON_BLOCKED, queue.getRunnableAtReason());
@@ -411,7 +436,8 @@
final Intent airplane = new Intent(Intent.ACTION_AIRPLANE_MODE_CHANGED);
final BroadcastRecord airplaneRecord = makeBroadcastRecord(airplane,
List.of(makeMockRegisteredReceiver()));
- queue.enqueueOrReplaceBroadcast(airplaneRecord, 0, null /* replacedBroadcastConsumer */);
+ queue.enqueueOrReplaceBroadcast(airplaneRecord, 0,
+ null /* replacedBroadcastConsumer */, false);
mConstants.MAX_PENDING_BROADCASTS = 128;
queue.invalidateRunnableAt();
@@ -437,11 +463,13 @@
new Intent(Intent.ACTION_AIRPLANE_MODE_CHANGED),
List.of(makeMockRegisteredReceiver()));
- queue.enqueueOrReplaceBroadcast(lazyRecord, 0, null /* replacedBroadcastConsumer */);
+ queue.enqueueOrReplaceBroadcast(lazyRecord, 0,
+ null /* replacedBroadcastConsumer */, false);
assertThat(queue.getRunnableAt()).isGreaterThan(lazyRecord.enqueueTime);
assertThat(queue.getRunnableAtReason()).isNotEqualTo(testRunnableAtReason);
- queue.enqueueOrReplaceBroadcast(testRecord, 0, null /* replacedBroadcastConsumer */);
+ queue.enqueueOrReplaceBroadcast(testRecord, 0,
+ null /* replacedBroadcastConsumer */, false);
assertThat(queue.getRunnableAt()).isAtMost(testRecord.enqueueTime);
assertThat(queue.getRunnableAtReason()).isEqualTo(testRunnableAtReason);
}
@@ -459,13 +487,6 @@
}
@Test
- public void testRunnableAt_Cached_ResultTo() {
- final IIntentReceiver resultTo = mock(IIntentReceiver.class);
- doRunnableAt_Cached(makeBroadcastRecord(makeMockIntent(), null,
- List.of(makeMockRegisteredReceiver()), resultTo, false), REASON_CONTAINS_RESULT_TO);
- }
-
- @Test
public void testRunnableAt_Cached_Foreground() {
final Intent foregroundIntent = new Intent();
foregroundIntent.addFlags(Intent.FLAG_RECEIVER_FOREGROUND);
@@ -511,25 +532,25 @@
queue.enqueueOrReplaceBroadcast(
makeBroadcastRecord(new Intent(Intent.ACTION_AIRPLANE_MODE_CHANGED)
.addFlags(Intent.FLAG_RECEIVER_OFFLOAD)), 0,
- null /* replacedBroadcastConsumer */);
+ null /* replacedBroadcastConsumer */, false);
queue.enqueueOrReplaceBroadcast(
makeBroadcastRecord(new Intent(Intent.ACTION_TIMEZONE_CHANGED)), 0,
- null /* replacedBroadcastConsumer */);
+ null /* replacedBroadcastConsumer */, false);
queue.enqueueOrReplaceBroadcast(
makeBroadcastRecord(new Intent(Intent.ACTION_LOCKED_BOOT_COMPLETED)
.addFlags(Intent.FLAG_RECEIVER_FOREGROUND)), 0,
- null /* replacedBroadcastConsumer */);
+ null /* replacedBroadcastConsumer */, false);
queue.enqueueOrReplaceBroadcast(
makeBroadcastRecord(new Intent(Intent.ACTION_ALARM_CHANGED)
.addFlags(Intent.FLAG_RECEIVER_OFFLOAD)), 0,
- null /* replacedBroadcastConsumer */);
+ null /* replacedBroadcastConsumer */, false);
queue.enqueueOrReplaceBroadcast(
makeBroadcastRecord(new Intent(Intent.ACTION_TIME_TICK)), 0,
- null /* replacedBroadcastConsumer */);
+ null /* replacedBroadcastConsumer */, false);
queue.enqueueOrReplaceBroadcast(
makeBroadcastRecord(new Intent(Intent.ACTION_LOCALE_CHANGED)
.addFlags(Intent.FLAG_RECEIVER_FOREGROUND)), 0,
- null /* replacedBroadcastConsumer */);
+ null /* replacedBroadcastConsumer */, false);
queue.makeActiveNextPending();
assertEquals(Intent.ACTION_LOCKED_BOOT_COMPLETED, queue.getActive().intent.getAction());
diff --git a/services/tests/mockingservicestests/src/com/android/server/am/BroadcastQueueTest.java b/services/tests/mockingservicestests/src/com/android/server/am/BroadcastQueueTest.java
index 8d9dda08..64be0f7 100644
--- a/services/tests/mockingservicestests/src/com/android/server/am/BroadcastQueueTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/am/BroadcastQueueTest.java
@@ -357,6 +357,11 @@
}
receiversToSkip.add(o);
}
+ public boolean disallowBackgroundStart(BroadcastRecord r) {
+ // Ignored
+ return false;
+ }
+
}
private class TestInjector extends Injector {
diff --git a/services/tests/mockingservicestests/src/com/android/server/am/MockingOomAdjusterTests.java b/services/tests/mockingservicestests/src/com/android/server/am/MockingOomAdjusterTests.java
index 9234431..c40017a 100644
--- a/services/tests/mockingservicestests/src/com/android/server/am/MockingOomAdjusterTests.java
+++ b/services/tests/mockingservicestests/src/com/android/server/am/MockingOomAdjusterTests.java
@@ -2452,7 +2452,7 @@
if (record == null) {
record = makeServiceRecord(service);
}
- AppBindRecord binding = new AppBindRecord(record, null, client);
+ AppBindRecord binding = new AppBindRecord(record, null, client, null);
ConnectionRecord cr = spy(new ConnectionRecord(binding,
mock(ActivityServiceConnectionsHolder.class),
mock(IServiceConnection.class), bindFlags,
diff --git a/services/tests/mockingservicestests/src/com/android/server/companion/virtual/CameraAccessControllerTest.java b/services/tests/mockingservicestests/src/com/android/server/companion/virtual/CameraAccessControllerTest.java
index 757d27b..f6566a0d 100644
--- a/services/tests/mockingservicestests/src/com/android/server/companion/virtual/CameraAccessControllerTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/companion/virtual/CameraAccessControllerTest.java
@@ -39,6 +39,7 @@
import android.hardware.camera2.CameraManager;
import android.os.Process;
import android.os.UserManager;
+import android.platform.test.annotations.Presubmit;
import android.testing.TestableContext;
import android.util.ArraySet;
@@ -59,6 +60,7 @@
import java.util.ArrayList;
import java.util.List;
+@Presubmit
@RunWith(AndroidJUnit4.class)
public class CameraAccessControllerTest {
private static final String FRONT_CAMERA = "0";
diff --git a/services/tests/mockingservicestests/src/com/android/server/display/DisplayPowerController2Test.java b/services/tests/mockingservicestests/src/com/android/server/display/DisplayPowerController2Test.java
index f2cba40..2a790a1 100644
--- a/services/tests/mockingservicestests/src/com/android/server/display/DisplayPowerController2Test.java
+++ b/services/tests/mockingservicestests/src/com/android/server/display/DisplayPowerController2Test.java
@@ -80,6 +80,8 @@
@Mock
private DisplayBlanker mDisplayBlankerMock;
@Mock
+ private HighBrightnessModeMetadata mHighBrightnessModeMetadataMock;
+ @Mock
private LogicalDisplay mLogicalDisplayMock;
@Mock
private DisplayDevice mDisplayDeviceMock;
@@ -169,7 +171,7 @@
mContextSpy, mInjector, mDisplayPowerCallbacksMock, mHandler,
mSensorManagerMock, mDisplayBlankerMock, mLogicalDisplayMock,
mBrightnessTrackerMock, mBrightnessSettingMock, () -> {
- });
+ }, mHighBrightnessModeMetadataMock);
when(mDisplayPowerStateMock.getScreenState()).thenReturn(Display.STATE_ON);
// send a display power request
diff --git a/services/tests/mockingservicestests/src/com/android/server/display/DisplayPowerControllerTest.java b/services/tests/mockingservicestests/src/com/android/server/display/DisplayPowerControllerTest.java
index 4f8cb88..d99ed78 100644
--- a/services/tests/mockingservicestests/src/com/android/server/display/DisplayPowerControllerTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/display/DisplayPowerControllerTest.java
@@ -84,6 +84,8 @@
@Mock
private DisplayDevice mDisplayDeviceMock;
@Mock
+ private HighBrightnessModeMetadata mHighBrightnessModeMetadataMock;
+ @Mock
private BrightnessTracker mBrightnessTrackerMock;
@Mock
private BrightnessSetting mBrightnessSettingMock;
@@ -151,7 +153,7 @@
mContextSpy, mInjector, mDisplayPowerCallbacksMock, mHandler,
mSensorManagerMock, mDisplayBlankerMock, mLogicalDisplayMock,
mBrightnessTrackerMock, mBrightnessSettingMock, () -> {
- });
+ }, mHighBrightnessModeMetadataMock);
when(mDisplayPowerStateMock.getScreenState()).thenReturn(Display.STATE_ON);
// send a display power request
diff --git a/services/tests/mockingservicestests/src/com/android/server/job/JobConcurrencyManagerTest.java b/services/tests/mockingservicestests/src/com/android/server/job/JobConcurrencyManagerTest.java
index 79fbc87..7e1a42b 100644
--- a/services/tests/mockingservicestests/src/com/android/server/job/JobConcurrencyManagerTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/job/JobConcurrencyManagerTest.java
@@ -213,7 +213,7 @@
mJobConcurrencyManager.prepareForAssignmentDeterminationLocked(
idle, preferredUidOnly, stoppable, assignmentInfo);
- assertEquals(JobConcurrencyManager.STANDARD_CONCURRENCY_LIMIT, idle.size());
+ assertEquals(JobConcurrencyManager.DEFAULT_CONCURRENCY_LIMIT, idle.size());
assertEquals(0, preferredUidOnly.size());
assertEquals(0, stoppable.size());
assertEquals(0, assignmentInfo.minPreferredUidOnlyWaitingTimeMs);
@@ -222,7 +222,7 @@
@Test
public void testPrepareForAssignmentDetermination_onlyPendingJobs() {
- for (int i = 0; i < JobConcurrencyManager.STANDARD_CONCURRENCY_LIMIT; ++i) {
+ for (int i = 0; i < JobConcurrencyManager.DEFAULT_CONCURRENCY_LIMIT; ++i) {
JobStatus job = createJob(mDefaultUserId * UserHandle.PER_USER_RANGE + i);
mPendingJobQueue.add(job);
}
@@ -235,7 +235,7 @@
mJobConcurrencyManager.prepareForAssignmentDeterminationLocked(
idle, preferredUidOnly, stoppable, assignmentInfo);
- assertEquals(JobConcurrencyManager.STANDARD_CONCURRENCY_LIMIT, idle.size());
+ assertEquals(JobConcurrencyManager.DEFAULT_CONCURRENCY_LIMIT, idle.size());
assertEquals(0, preferredUidOnly.size());
assertEquals(0, stoppable.size());
assertEquals(0, assignmentInfo.minPreferredUidOnlyWaitingTimeMs);
@@ -244,7 +244,7 @@
@Test
public void testPrepareForAssignmentDetermination_onlyPreferredUidOnly() {
- for (int i = 0; i < JobConcurrencyManager.STANDARD_CONCURRENCY_LIMIT; ++i) {
+ for (int i = 0; i < JobConcurrencyManager.DEFAULT_CONCURRENCY_LIMIT; ++i) {
JobStatus job = createJob(mDefaultUserId * UserHandle.PER_USER_RANGE + i);
mJobConcurrencyManager.addRunningJobForTesting(job);
}
@@ -262,7 +262,7 @@
idle, preferredUidOnly, stoppable, assignmentInfo);
assertEquals(0, idle.size());
- assertEquals(JobConcurrencyManager.STANDARD_CONCURRENCY_LIMIT, preferredUidOnly.size());
+ assertEquals(JobConcurrencyManager.DEFAULT_CONCURRENCY_LIMIT, preferredUidOnly.size());
assertEquals(0, stoppable.size());
assertEquals(0, assignmentInfo.minPreferredUidOnlyWaitingTimeMs);
assertEquals(0, assignmentInfo.numRunningImmediacyPrivileged);
@@ -270,7 +270,7 @@
@Test
public void testPrepareForAssignmentDetermination_onlyStartedWithImmediacyPrivilege() {
- for (int i = 0; i < JobConcurrencyManager.STANDARD_CONCURRENCY_LIMIT; ++i) {
+ for (int i = 0; i < JobConcurrencyManager.DEFAULT_CONCURRENCY_LIMIT; ++i) {
JobStatus job = createJob(mDefaultUserId * UserHandle.PER_USER_RANGE + i);
job.startedWithImmediacyPrivilege = true;
mJobConcurrencyManager.addRunningJobForTesting(job);
@@ -289,19 +289,19 @@
idle, preferredUidOnly, stoppable, assignmentInfo);
assertEquals(0, idle.size());
- assertEquals(JobConcurrencyManager.STANDARD_CONCURRENCY_LIMIT / 2, preferredUidOnly.size());
- assertEquals(JobConcurrencyManager.STANDARD_CONCURRENCY_LIMIT / 2, stoppable.size());
+ assertEquals(JobConcurrencyManager.DEFAULT_CONCURRENCY_LIMIT / 2, preferredUidOnly.size());
+ assertEquals(JobConcurrencyManager.DEFAULT_CONCURRENCY_LIMIT / 2, stoppable.size());
assertEquals(0, assignmentInfo.minPreferredUidOnlyWaitingTimeMs);
- assertEquals(JobConcurrencyManager.STANDARD_CONCURRENCY_LIMIT,
+ assertEquals(JobConcurrencyManager.DEFAULT_CONCURRENCY_LIMIT,
assignmentInfo.numRunningImmediacyPrivileged);
}
@Test
public void testDetermineAssignments_allRegular() throws Exception {
- setConcurrencyConfig(JobConcurrencyManager.STANDARD_CONCURRENCY_LIMIT,
- new TypeConfig(WORK_TYPE_BG, 0, JobConcurrencyManager.STANDARD_CONCURRENCY_LIMIT));
+ setConcurrencyConfig(JobConcurrencyManager.DEFAULT_CONCURRENCY_LIMIT,
+ new TypeConfig(WORK_TYPE_BG, 0, JobConcurrencyManager.DEFAULT_CONCURRENCY_LIMIT));
final ArraySet<JobStatus> jobs = new ArraySet<>();
- for (int i = 0; i < JobConcurrencyManager.STANDARD_CONCURRENCY_LIMIT; ++i) {
+ for (int i = 0; i < JobConcurrencyManager.DEFAULT_CONCURRENCY_LIMIT; ++i) {
final int uid = mDefaultUserId * UserHandle.PER_USER_RANGE + i;
final String sourcePkgName = "com.source.package." + UserHandle.getAppId(uid);
setPackageUid(sourcePkgName, uid);
@@ -322,7 +322,7 @@
.determineAssignmentsLocked(changed, idle, preferredUidOnly, stoppable,
assignmentInfo);
- assertEquals(JobConcurrencyManager.STANDARD_CONCURRENCY_LIMIT, changed.size());
+ assertEquals(JobConcurrencyManager.DEFAULT_CONCURRENCY_LIMIT, changed.size());
for (int i = changed.size() - 1; i >= 0; --i) {
jobs.remove(changed.valueAt(i).newJob);
}
@@ -332,16 +332,16 @@
@Test
public void testDetermineAssignments_allPreferredUidOnly_shortTimeLeft() throws Exception {
mConfigBuilder.setBoolean(JobConcurrencyManager.KEY_ENABLE_MAX_WAIT_TIME_BYPASS, true);
- setConcurrencyConfig(JobConcurrencyManager.STANDARD_CONCURRENCY_LIMIT,
- new TypeConfig(WORK_TYPE_BG, 0, JobConcurrencyManager.STANDARD_CONCURRENCY_LIMIT));
- for (int i = 0; i < JobConcurrencyManager.STANDARD_CONCURRENCY_LIMIT * 2; ++i) {
+ setConcurrencyConfig(JobConcurrencyManager.DEFAULT_CONCURRENCY_LIMIT,
+ new TypeConfig(WORK_TYPE_BG, 0, JobConcurrencyManager.DEFAULT_CONCURRENCY_LIMIT));
+ for (int i = 0; i < JobConcurrencyManager.DEFAULT_CONCURRENCY_LIMIT * 2; ++i) {
final int uid = mDefaultUserId * UserHandle.PER_USER_RANGE + i;
final String sourcePkgName = "com.source.package." + UserHandle.getAppId(uid);
setPackageUid(sourcePkgName, uid);
final JobStatus job = createJob(uid, sourcePkgName);
spyOn(job);
doReturn(i % 2 == 0).when(job).shouldTreatAsExpeditedJob();
- if (i < JobConcurrencyManager.STANDARD_CONCURRENCY_LIMIT) {
+ if (i < JobConcurrencyManager.DEFAULT_CONCURRENCY_LIMIT) {
mJobConcurrencyManager.addRunningJobForTesting(job);
} else {
mPendingJobQueue.add(job);
@@ -366,30 +366,30 @@
mJobConcurrencyManager.prepareForAssignmentDeterminationLocked(
idle, preferredUidOnly, stoppable, assignmentInfo);
assertEquals(remainingTimeMs, assignmentInfo.minPreferredUidOnlyWaitingTimeMs);
- assertEquals(JobConcurrencyManager.STANDARD_CONCURRENCY_LIMIT, preferredUidOnly.size());
+ assertEquals(JobConcurrencyManager.DEFAULT_CONCURRENCY_LIMIT, preferredUidOnly.size());
mJobConcurrencyManager
.determineAssignmentsLocked(changed, idle, preferredUidOnly, stoppable,
assignmentInfo);
- assertEquals(JobConcurrencyManager.STANDARD_CONCURRENCY_LIMIT, preferredUidOnly.size());
+ assertEquals(JobConcurrencyManager.DEFAULT_CONCURRENCY_LIMIT, preferredUidOnly.size());
assertEquals(0, changed.size());
}
@Test
public void testDetermineAssignments_allPreferredUidOnly_mediumTimeLeft() throws Exception {
mConfigBuilder.setBoolean(JobConcurrencyManager.KEY_ENABLE_MAX_WAIT_TIME_BYPASS, true);
- setConcurrencyConfig(JobConcurrencyManager.STANDARD_CONCURRENCY_LIMIT,
- new TypeConfig(WORK_TYPE_BG, 0, JobConcurrencyManager.STANDARD_CONCURRENCY_LIMIT));
+ setConcurrencyConfig(JobConcurrencyManager.DEFAULT_CONCURRENCY_LIMIT,
+ new TypeConfig(WORK_TYPE_BG, 0, JobConcurrencyManager.DEFAULT_CONCURRENCY_LIMIT));
final ArraySet<JobStatus> jobs = new ArraySet<>();
- for (int i = 0; i < JobConcurrencyManager.STANDARD_CONCURRENCY_LIMIT * 2; ++i) {
+ for (int i = 0; i < JobConcurrencyManager.DEFAULT_CONCURRENCY_LIMIT * 2; ++i) {
final int uid = mDefaultUserId * UserHandle.PER_USER_RANGE + i;
final String sourcePkgName = "com.source.package." + UserHandle.getAppId(uid);
setPackageUid(sourcePkgName, uid);
final JobStatus job = createJob(uid, sourcePkgName);
spyOn(job);
doReturn(i % 2 == 0).when(job).shouldTreatAsExpeditedJob();
- if (i < JobConcurrencyManager.STANDARD_CONCURRENCY_LIMIT) {
+ if (i < JobConcurrencyManager.DEFAULT_CONCURRENCY_LIMIT) {
mJobConcurrencyManager.addRunningJobForTesting(job);
} else {
mPendingJobQueue.add(job);
@@ -417,17 +417,17 @@
mJobConcurrencyManager.prepareForAssignmentDeterminationLocked(
idle, preferredUidOnly, stoppable, assignmentInfo);
assertEquals(remainingTimeMs, assignmentInfo.minPreferredUidOnlyWaitingTimeMs);
- assertEquals(JobConcurrencyManager.STANDARD_CONCURRENCY_LIMIT, preferredUidOnly.size());
+ assertEquals(JobConcurrencyManager.DEFAULT_CONCURRENCY_LIMIT, preferredUidOnly.size());
mJobConcurrencyManager
.determineAssignmentsLocked(changed, idle, preferredUidOnly, stoppable,
assignmentInfo);
- assertEquals(JobConcurrencyManager.STANDARD_CONCURRENCY_LIMIT, preferredUidOnly.size());
+ assertEquals(JobConcurrencyManager.DEFAULT_CONCURRENCY_LIMIT, preferredUidOnly.size());
for (int i = changed.size() - 1; i >= 0; --i) {
jobs.remove(changed.valueAt(i).newJob);
}
- assertEquals(JobConcurrencyManager.STANDARD_CONCURRENCY_LIMIT - 1, jobs.size());
+ assertEquals(JobConcurrencyManager.DEFAULT_CONCURRENCY_LIMIT - 1, jobs.size());
assertEquals(1, changed.size());
JobStatus assignedJob = changed.valueAt(0).newJob;
assertTrue(assignedJob.shouldTreatAsExpeditedJob());
@@ -436,17 +436,17 @@
@Test
public void testDetermineAssignments_allPreferredUidOnly_longTimeLeft() throws Exception {
mConfigBuilder.setBoolean(JobConcurrencyManager.KEY_ENABLE_MAX_WAIT_TIME_BYPASS, true);
- setConcurrencyConfig(JobConcurrencyManager.STANDARD_CONCURRENCY_LIMIT,
- new TypeConfig(WORK_TYPE_BG, 0, JobConcurrencyManager.STANDARD_CONCURRENCY_LIMIT));
+ setConcurrencyConfig(JobConcurrencyManager.DEFAULT_CONCURRENCY_LIMIT,
+ new TypeConfig(WORK_TYPE_BG, 0, JobConcurrencyManager.DEFAULT_CONCURRENCY_LIMIT));
final ArraySet<JobStatus> jobs = new ArraySet<>();
- for (int i = 0; i < JobConcurrencyManager.STANDARD_CONCURRENCY_LIMIT * 2; ++i) {
+ for (int i = 0; i < JobConcurrencyManager.DEFAULT_CONCURRENCY_LIMIT * 2; ++i) {
final int uid = mDefaultUserId * UserHandle.PER_USER_RANGE + i;
final String sourcePkgName = "com.source.package." + UserHandle.getAppId(uid);
setPackageUid(sourcePkgName, uid);
final JobStatus job = createJob(uid, sourcePkgName);
spyOn(job);
doReturn(i % 2 == 0).when(job).shouldTreatAsExpeditedJob();
- if (i < JobConcurrencyManager.STANDARD_CONCURRENCY_LIMIT) {
+ if (i < JobConcurrencyManager.DEFAULT_CONCURRENCY_LIMIT) {
mJobConcurrencyManager.addRunningJobForTesting(job);
} else {
mPendingJobQueue.add(job);
@@ -473,13 +473,13 @@
mJobConcurrencyManager.prepareForAssignmentDeterminationLocked(
idle, preferredUidOnly, stoppable, assignmentInfo);
assertEquals(remainingTimeMs, assignmentInfo.minPreferredUidOnlyWaitingTimeMs);
- assertEquals(JobConcurrencyManager.STANDARD_CONCURRENCY_LIMIT, preferredUidOnly.size());
+ assertEquals(JobConcurrencyManager.DEFAULT_CONCURRENCY_LIMIT, preferredUidOnly.size());
mJobConcurrencyManager
.determineAssignmentsLocked(changed, idle, preferredUidOnly, stoppable,
assignmentInfo);
- assertEquals(JobConcurrencyManager.STANDARD_CONCURRENCY_LIMIT, preferredUidOnly.size());
+ assertEquals(JobConcurrencyManager.DEFAULT_CONCURRENCY_LIMIT, preferredUidOnly.size());
// Depending on iteration order, we may create 1 or 2 contexts.
final long numAssignedJobs = changed.size();
assertTrue(numAssignedJobs > 0);
@@ -488,7 +488,7 @@
jobs.remove(changed.valueAt(i).newJob);
}
assertEquals(numAssignedJobs,
- JobConcurrencyManager.STANDARD_CONCURRENCY_LIMIT - jobs.size());
+ JobConcurrencyManager.DEFAULT_CONCURRENCY_LIMIT - jobs.size());
JobStatus firstAssignedJob = changed.valueAt(0).newJob;
if (!firstAssignedJob.shouldTreatAsExpeditedJob()) {
assertEquals(2, numAssignedJobs);
@@ -538,14 +538,14 @@
assertFalse(mJobConcurrencyManager.isPkgConcurrencyLimitedLocked(topJob));
// Pending jobs shouldn't affect TOP job's status.
- for (int i = 1; i <= JobConcurrencyManager.STANDARD_CONCURRENCY_LIMIT; ++i) {
+ for (int i = 1; i <= JobConcurrencyManager.DEFAULT_CONCURRENCY_LIMIT; ++i) {
final JobStatus job = createJob(mDefaultUserId * UserHandle.PER_USER_RANGE + i);
mPendingJobQueue.add(job);
}
assertFalse(mJobConcurrencyManager.isPkgConcurrencyLimitedLocked(topJob));
// Already running jobs shouldn't affect TOP job's status.
- for (int i = 1; i <= JobConcurrencyManager.STANDARD_CONCURRENCY_LIMIT; ++i) {
+ for (int i = 1; i <= JobConcurrencyManager.DEFAULT_CONCURRENCY_LIMIT; ++i) {
final JobStatus job = createJob(mDefaultUserId * UserHandle.PER_USER_RANGE, i);
mJobConcurrencyManager.addRunningJobForTesting(job);
}
@@ -605,9 +605,9 @@
spyOn(testEj);
doReturn(true).when(testEj).shouldTreatAsExpeditedJob();
- setConcurrencyConfig(JobConcurrencyManager.STANDARD_CONCURRENCY_LIMIT);
+ setConcurrencyConfig(JobConcurrencyManager.DEFAULT_CONCURRENCY_LIMIT);
- for (int i = 0; i < JobConcurrencyManager.STANDARD_CONCURRENCY_LIMIT; ++i) {
+ for (int i = 0; i < JobConcurrencyManager.DEFAULT_CONCURRENCY_LIMIT; ++i) {
final JobStatus job = createJob(mDefaultUserId * UserHandle.PER_USER_RANGE + i, i + 1);
mPendingJobQueue.add(job);
}
@@ -887,12 +887,14 @@
mConfigBuilder
.setInt(WorkTypeConfig.KEY_PREFIX_MAX_TOTAL + identifier, total);
for (TypeConfig config : typeConfigs) {
- mConfigBuilder.setInt(
- WorkTypeConfig.KEY_PREFIX_MAX + config.workTypeString + "_" + identifier,
- config.max);
- mConfigBuilder.setInt(
- WorkTypeConfig.KEY_PREFIX_MIN + config.workTypeString + "_" + identifier,
- config.min);
+ mConfigBuilder.setFloat(
+ WorkTypeConfig.KEY_PREFIX_MAX_RATIO + config.workTypeString + "_"
+ + identifier,
+ (float) config.max / total);
+ mConfigBuilder.setFloat(
+ WorkTypeConfig.KEY_PREFIX_MIN_RATIO + config.workTypeString + "_"
+ + identifier,
+ (float) config.min / total);
}
}
updateDeviceConfig();
diff --git a/services/tests/mockingservicestests/src/com/android/server/pm/MockSystem.kt b/services/tests/mockingservicestests/src/com/android/server/pm/MockSystem.kt
index 9935a2f..06ba5dd 100644
--- a/services/tests/mockingservicestests/src/com/android/server/pm/MockSystem.kt
+++ b/services/tests/mockingservicestests/src/com/android/server/pm/MockSystem.kt
@@ -63,6 +63,7 @@
import com.android.server.compat.PlatformCompat
import com.android.server.extendedtestutils.wheneverStatic
import com.android.server.pm.dex.DexManager
+import com.android.server.pm.dex.DynamicCodeLogger
import com.android.server.pm.parsing.PackageParser2
import com.android.server.pm.parsing.pkg.PackageImpl
import com.android.server.pm.parsing.pkg.ParsedPackage
@@ -208,6 +209,7 @@
whenever(snapshot()) { appsFilterSnapshot }
}
val dexManager: DexManager = mock()
+ val dynamicCodeLogger: DynamicCodeLogger = mock()
val installer: Installer = mock()
val displayMetrics: DisplayMetrics = mock()
val domainVerificationManagerInternal: DomainVerificationManagerInternal = mock()
@@ -285,6 +287,7 @@
whenever(mocks.injector.crossProfileIntentFilterHelper)
.thenReturn(mocks.crossProfileIntentFilterHelper)
whenever(mocks.injector.dexManager).thenReturn(mocks.dexManager)
+ whenever(mocks.injector.dynamicCodeLogger).thenReturn(mocks.dynamicCodeLogger)
whenever(mocks.injector.systemConfig).thenReturn(mocks.systemConfig)
whenever(mocks.injector.apexManager).thenReturn(mocks.apexManager)
whenever(mocks.injector.scanningCachingPackageParser).thenReturn(mocks.packageParser)
diff --git a/services/tests/mockingservicestests/src/com/android/server/pm/StagingManagerTest.java b/services/tests/mockingservicestests/src/com/android/server/pm/StagingManagerTest.java
index cfd5279..d2547a3 100644
--- a/services/tests/mockingservicestests/src/com/android/server/pm/StagingManagerTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/pm/StagingManagerTest.java
@@ -723,8 +723,8 @@
params.isStaged = true;
InstallSource installSource = InstallSource.create("testInstallInitiator",
- "testInstallOriginator", "testInstaller", 100, "testAttributionTag",
- PackageInstaller.PACKAGE_SOURCE_UNSPECIFIED);
+ "testInstallOriginator", "testInstaller", 100, "testUpdateOwner",
+ "testAttributionTag", PackageInstaller.PACKAGE_SOURCE_UNSPECIFIED);
PackageInstallerSession session = new PackageInstallerSession(
/* callback */ null,
diff --git a/services/tests/mockingservicestests/src/com/android/server/pm/UserVisibilityMediatorSUSDTest.java b/services/tests/mockingservicestests/src/com/android/server/pm/UserVisibilityMediatorSUSDTest.java
index 88709e1..b9ba780 100644
--- a/services/tests/mockingservicestests/src/com/android/server/pm/UserVisibilityMediatorSUSDTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/pm/UserVisibilityMediatorSUSDTest.java
@@ -49,6 +49,7 @@
int result = mMediator.assignUserToDisplayOnStart(USER_ID, USER_ID, FG,
DEFAULT_DISPLAY);
assertStartUserResult(result, USER_ASSIGNMENT_RESULT_SUCCESS_VISIBLE);
+ expectUserCannotBeUnassignedFromDisplay(USER_ID, DEFAULT_DISPLAY);
expectUserIsVisible(USER_ID);
expectUserIsNotVisibleOnDisplay(USER_ID, INVALID_DISPLAY);
@@ -80,6 +81,7 @@
int result = mMediator.assignUserToDisplayOnStart(currentUserId, currentUserId, FG,
DEFAULT_DISPLAY);
assertStartUserResult(result, USER_ASSIGNMENT_RESULT_SUCCESS_VISIBLE);
+ expectUserCannotBeUnassignedFromDisplay(currentUserId, DEFAULT_DISPLAY);
expectUserIsVisible(currentUserId);
expectUserIsNotVisibleOnDisplay(currentUserId, INVALID_DISPLAY);
@@ -110,6 +112,7 @@
int result = mMediator.assignUserToDisplayOnStart(PROFILE_USER_ID, PARENT_USER_ID,
BG_VISIBLE, DEFAULT_DISPLAY);
assertStartUserResult(result, USER_ASSIGNMENT_RESULT_SUCCESS_VISIBLE);
+ expectUserCannotBeUnassignedFromDisplay(PROFILE_USER_ID, DEFAULT_DISPLAY);
expectUserIsVisible(PROFILE_USER_ID);
expectUserIsNotVisibleOnDisplay(PROFILE_USER_ID, INVALID_DISPLAY);
diff --git a/services/tests/mockingservicestests/src/com/android/server/pm/UserVisibilityMediatorTestCase.java b/services/tests/mockingservicestests/src/com/android/server/pm/UserVisibilityMediatorTestCase.java
index e4664d2..c59834b 100644
--- a/services/tests/mockingservicestests/src/com/android/server/pm/UserVisibilityMediatorTestCase.java
+++ b/services/tests/mockingservicestests/src/com/android/server/pm/UserVisibilityMediatorTestCase.java
@@ -165,12 +165,16 @@
expectNoDisplayAssignedToUser(USER_ID);
expectInitialCurrentUserAssignedToDisplay(DEFAULT_DISPLAY);
+ assertInvisibleUserCannotBeAssignedExtraDisplay(USER_ID, SECONDARY_DISPLAY_ID);
+
listener.verify();
}
@Test
public final void testStartVisibleBgUser_onDefaultDisplay() throws Exception {
visibleBgUserCannotBeStartedOnDefaultDisplayTest();
+
+ assertInvisibleUserCannotBeAssignedExtraDisplay(USER_ID, SECONDARY_DISPLAY_ID);
}
protected final void visibleBgUserCannotBeStartedOnDefaultDisplayTest() throws Exception {
@@ -180,8 +184,8 @@
DEFAULT_DISPLAY);
assertStartUserResult(result, USER_ASSIGNMENT_RESULT_FAILURE);
- expectUserIsNotVisibleAtAll(PROFILE_USER_ID);
- expectNoDisplayAssignedToUser(PROFILE_USER_ID);
+ expectUserIsNotVisibleAtAll(USER_ID);
+ expectNoDisplayAssignedToUser(USER_ID);
listener.verify();
}
@@ -194,8 +198,11 @@
SECONDARY_DISPLAY_ID);
assertStartUserResult(result, USER_ASSIGNMENT_RESULT_FAILURE);
- expectUserIsNotVisibleAtAll(PROFILE_USER_ID);
- expectNoDisplayAssignedToUser(PROFILE_USER_ID);
+ expectUserIsNotVisibleAtAll(USER_ID);
+ expectNoDisplayAssignedToUser(USER_ID);
+
+ assertInvisibleUserCannotBeAssignedExtraDisplay(USER_ID, SECONDARY_DISPLAY_ID);
+ assertInvisibleUserCannotBeAssignedExtraDisplay(USER_ID, OTHER_SECONDARY_DISPLAY_ID);
listener.verify();
}
@@ -217,6 +224,9 @@
expectNoDisplayAssignedToUser(USER_SYSTEM);
expectUserAssignedToDisplay(SECONDARY_DISPLAY_ID, USER_ID);
+ assertUserCannotBeAssignedExtraDisplay(USER_SYSTEM, SECONDARY_DISPLAY_ID);
+ assertUserCannotBeAssignedExtraDisplay(USER_SYSTEM, OTHER_SECONDARY_DISPLAY_ID);
+
listener.verify();
}
@@ -256,6 +266,8 @@
expectNoDisplayAssignedToUser(PROFILE_USER_ID);
expectUserAssignedToDisplay(DEFAULT_DISPLAY, OTHER_USER_ID);
+ assertUserCannotBeAssignedExtraDisplay(PROFILE_USER_ID, SECONDARY_DISPLAY_ID);
+
listener.verify();
}
@@ -289,6 +301,8 @@
expectNoDisplayAssignedToUser(PROFILE_USER_ID);
expectInitialCurrentUserAssignedToDisplay(DEFAULT_DISPLAY);
+ assertUserCannotBeAssignedExtraDisplay(PROFILE_USER_ID, SECONDARY_DISPLAY_ID);
+
listener.verify();
}
@@ -305,6 +319,10 @@
expectNoDisplayAssignedToUser(PROFILE_USER_ID);
expectInitialCurrentUserAssignedToDisplay(SECONDARY_DISPLAY_ID);
+ assertInvisibleUserCannotBeAssignedExtraDisplay(PROFILE_USER_ID, SECONDARY_DISPLAY_ID);
+ assertInvisibleUserCannotBeAssignedExtraDisplay(PROFILE_USER_ID,
+ OTHER_SECONDARY_DISPLAY_ID);
+
listener.verify();
}
@@ -320,6 +338,10 @@
expectNoDisplayAssignedToUser(PROFILE_USER_ID);
expectInitialCurrentUserAssignedToDisplay(SECONDARY_DISPLAY_ID);
+ assertInvisibleUserCannotBeAssignedExtraDisplay(PROFILE_USER_ID, SECONDARY_DISPLAY_ID);
+ assertInvisibleUserCannotBeAssignedExtraDisplay(PROFILE_USER_ID,
+ OTHER_SECONDARY_DISPLAY_ID);
+
listener.verify();
}
@@ -336,6 +358,9 @@
expectNoDisplayAssignedToUser(PROFILE_USER_ID);
expectInitialCurrentUserAssignedToDisplay(DEFAULT_DISPLAY);
+ assertInvisibleUserCannotBeAssignedExtraDisplay(PROFILE_USER_ID, DEFAULT_DISPLAY);
+ assertInvisibleUserCannotBeAssignedExtraDisplay(PROFILE_USER_ID, SECONDARY_DISPLAY_ID);
+
listener.verify();
}
@@ -351,6 +376,10 @@
expectNoDisplayAssignedToUser(PROFILE_USER_ID);
expectInitialCurrentUserAssignedToDisplay(SECONDARY_DISPLAY_ID);
+ assertInvisibleUserCannotBeAssignedExtraDisplay(PROFILE_USER_ID, SECONDARY_DISPLAY_ID);
+ assertInvisibleUserCannotBeAssignedExtraDisplay(PROFILE_USER_ID,
+ OTHER_SECONDARY_DISPLAY_ID);
+
listener.verify();
}
@@ -481,6 +510,63 @@
.that(actualResult).isEqualTo(expectedResult);
}
+ protected void assertBgUserBecomesInvisibleOnStop(@UserIdInt int userId) {
+ Log.d(TAG, "Stopping user " + userId);
+ mMediator.unassignUserFromDisplayOnStop(userId);
+ expectUserIsNotVisibleAtAll(userId);
+ }
+
+ /**
+ * Assigns and unassigns the user to / from an extra display, asserting the visibility state in
+ * between.
+ *
+ * <p>It assumes the user was not visible in the display beforehand.
+ */
+ protected void assertUserCanBeAssignedExtraDisplay(@UserIdInt int userId, int displayId) {
+ assertUserCanBeAssignedExtraDisplay(userId, displayId, /* unassign= */ true);
+ }
+
+ protected void assertUserCanBeAssignedExtraDisplay(@UserIdInt int userId, int displayId,
+ boolean unassign) {
+
+ expectUserIsNotVisibleOnDisplay(userId, displayId);
+
+ Log.d(TAG, "Calling assignUserToExtraDisplay(" + userId + ", " + displayId + ")");
+ assertWithMessage("assignUserToExtraDisplay(%s, %s)", userId, displayId)
+ .that(mMediator.assignUserToExtraDisplay(userId, displayId))
+ .isTrue();
+ expectUserIsVisibleOnDisplay(userId, displayId);
+
+ if (unassign) {
+ Log.d(TAG, "Calling unassignUserFromExtraDisplay(" + userId + ", " + displayId + ")");
+ assertWithMessage("unassignUserFromExtraDisplay(%s, %s)", userId, displayId)
+ .that(mMediator.unassignUserFromExtraDisplay(userId, displayId))
+ .isTrue();
+ expectUserIsNotVisibleOnDisplay(userId, displayId);
+ }
+ }
+
+ /**
+ * Asserts that a user (already visible or not) cannot be assigned to an extra display (and
+ * hence won't be visible on that display).
+ */
+ protected void assertUserCannotBeAssignedExtraDisplay(@UserIdInt int userId, int displayId) {
+ expectWithMessage("assignUserToExtraDisplay(%s, %s)", userId, displayId)
+ .that(mMediator.assignUserToExtraDisplay(userId, displayId))
+ .isFalse();
+ expectUserIsNotVisibleOnDisplay(userId, displayId);
+ }
+
+ /**
+ * Asserts that an invisible user cannot be assigned to an extra display.
+ */
+ protected void assertInvisibleUserCannotBeAssignedExtraDisplay(@UserIdInt int userId,
+ int displayId) {
+ assertUserCannotBeAssignedExtraDisplay(userId, displayId);
+ expectNoDisplayAssignedToUser(userId);
+ expectInitialCurrentUserAssignedToDisplay(displayId);
+ }
+
protected void expectUserIsVisible(@UserIdInt int userId) {
expectWithMessage("isUserVisible(%s)", userId)
.that(mMediator.isUserVisible(userId))
@@ -534,6 +620,11 @@
.that(mMediator.getDisplayAssignedToUser(userId)).isEqualTo(INVALID_DISPLAY);
}
+ protected void expectUserCannotBeUnassignedFromDisplay(@UserIdInt int userId, int displayId) {
+ expectWithMessage("unassignUserFromExtraDisplay(%s, %s)", userId, displayId)
+ .that(mMediator.unassignUserFromExtraDisplay(userId, displayId)).isFalse();
+ }
+
protected void expectUserAssignedToDisplay(int displayId, @UserIdInt int userId) {
expectWithMessage("getUserAssignedToDisplay(%s)", displayId)
.that(mMediator.getUserAssignedToDisplay(displayId)).isEqualTo(userId);
diff --git a/services/tests/mockingservicestests/src/com/android/server/pm/UserVisibilityMediatorVisibleBackgroundUserTestCase.java b/services/tests/mockingservicestests/src/com/android/server/pm/UserVisibilityMediatorVisibleBackgroundUserTestCase.java
index 66d7eb6..627553b 100644
--- a/services/tests/mockingservicestests/src/com/android/server/pm/UserVisibilityMediatorVisibleBackgroundUserTestCase.java
+++ b/services/tests/mockingservicestests/src/com/android/server/pm/UserVisibilityMediatorVisibleBackgroundUserTestCase.java
@@ -52,6 +52,7 @@
int result = mMediator.assignUserToDisplayOnStart(USER_ID, USER_ID, FG,
DEFAULT_DISPLAY);
assertStartUserResult(result, USER_ASSIGNMENT_RESULT_SUCCESS_VISIBLE);
+ expectUserCannotBeUnassignedFromDisplay(USER_ID, DEFAULT_DISPLAY);
expectUserIsVisible(USER_ID);
expectUserIsVisibleOnDisplay(USER_ID, DEFAULT_DISPLAY);
@@ -64,7 +65,9 @@
expectUserAssignedToDisplay(INVALID_DISPLAY, USER_ID);
expectUserAssignedToDisplay(SECONDARY_DISPLAY_ID, USER_ID);
- expectDisplayAssignedToUser(USER_NULL, INVALID_DISPLAY);
+ expectNoDisplayAssignedToUser(USER_NULL);
+
+ assertUserCanBeAssignedExtraDisplay(USER_ID, SECONDARY_DISPLAY_ID);
listener.verify();
}
@@ -83,6 +86,7 @@
int result = mMediator.assignUserToDisplayOnStart(currentUserId, currentUserId, FG,
DEFAULT_DISPLAY);
assertStartUserResult(result, USER_ASSIGNMENT_RESULT_SUCCESS_VISIBLE);
+ expectUserCannotBeUnassignedFromDisplay(currentUserId, DEFAULT_DISPLAY);
expectUserIsVisible(currentUserId);
expectUserIsVisibleOnDisplay(currentUserId, DEFAULT_DISPLAY);
@@ -98,6 +102,8 @@
expectUserIsNotVisibleAtAll(previousCurrentUserId);
expectNoDisplayAssignedToUser(previousCurrentUserId);
+ assertUserCanBeAssignedExtraDisplay(USER_ID, SECONDARY_DISPLAY_ID);
+
listener.verify();
}
@@ -113,6 +119,7 @@
int result = mMediator.assignUserToDisplayOnStart(PROFILE_USER_ID, PARENT_USER_ID,
BG_VISIBLE, DEFAULT_DISPLAY);
assertStartUserResult(result, USER_ASSIGNMENT_RESULT_SUCCESS_VISIBLE);
+ expectUserCannotBeUnassignedFromDisplay(PROFILE_USER_ID, DEFAULT_DISPLAY);
expectUserIsVisible(PROFILE_USER_ID);
expectUserIsNotVisibleOnDisplay(PROFILE_USER_ID, INVALID_DISPLAY);
@@ -123,6 +130,8 @@
expectDisplayAssignedToUser(PROFILE_USER_ID, DEFAULT_DISPLAY);
expectUserAssignedToDisplay(DEFAULT_DISPLAY, PARENT_USER_ID);
+ assertUserCannotBeAssignedExtraDisplay(PROFILE_USER_ID, SECONDARY_DISPLAY_ID);
+
listener.verify();
}
@@ -134,6 +143,9 @@
assertStartUserResult(result, USER_ASSIGNMENT_RESULT_FAILURE);
+ assertInvisibleUserCannotBeAssignedExtraDisplay(USER_ID, DEFAULT_DISPLAY);
+ assertInvisibleUserCannotBeAssignedExtraDisplay(USER_ID, SECONDARY_DISPLAY_ID);
+
listener.verify();
}
@@ -148,6 +160,9 @@
expectUserIsNotVisibleAtAll(USER_ID);
+ assertInvisibleUserCannotBeAssignedExtraDisplay(USER_ID, DEFAULT_DISPLAY);
+ assertInvisibleUserCannotBeAssignedExtraDisplay(USER_ID, SECONDARY_DISPLAY_ID);
+
listener.verify();
}
@@ -159,6 +174,7 @@
int result = mMediator.assignUserToDisplayOnStart(USER_ID, USER_ID, BG_VISIBLE,
SECONDARY_DISPLAY_ID);
assertStartUserResult(result, USER_ASSIGNMENT_RESULT_SUCCESS_VISIBLE);
+ expectUserCannotBeUnassignedFromDisplay(USER_ID, SECONDARY_DISPLAY_ID);
expectUserIsVisible(USER_ID);
expectUserIsVisibleOnDisplay(USER_ID, SECONDARY_DISPLAY_ID);
@@ -169,7 +185,16 @@
expectDisplayAssignedToUser(USER_ID, SECONDARY_DISPLAY_ID);
expectUserAssignedToDisplay(SECONDARY_DISPLAY_ID, USER_ID);
- listener.verify();
+ assertUserCanBeAssignedExtraDisplay(USER_ID, OTHER_SECONDARY_DISPLAY_ID);
+
+ // Assign again, without unassigning (to make sure it becomes invisible on stop)
+ AsyncUserVisibilityListener listener2 = addListenerForEvents(onInvisible(USER_ID));
+ assertUserCanBeAssignedExtraDisplay(USER_ID, OTHER_SECONDARY_DISPLAY_ID,
+ /* unassign= */ false);
+
+ assertBgUserBecomesInvisibleOnStop(USER_ID);
+
+ listener2.verify();
}
@Test
@@ -203,6 +228,8 @@
expectNoDisplayAssignedToUser(USER_ID);
expectUserAssignedToDisplay(SECONDARY_DISPLAY_ID, OTHER_USER_ID);
+ assertUserCannotBeAssignedExtraDisplay(USER_ID, SECONDARY_DISPLAY_ID);
+
listener.verify();
}
@@ -226,7 +253,18 @@
expectDisplayAssignedToUser(USER_ID, OTHER_SECONDARY_DISPLAY_ID);
expectUserAssignedToDisplay(OTHER_SECONDARY_DISPLAY_ID, USER_ID);
+ assertUserCanBeAssignedExtraDisplay(USER_ID, SECONDARY_DISPLAY_ID);
+
listener.verify();
+
+ // Assign again, without unassigning (to make sure it becomes invisible on stop)
+ AsyncUserVisibilityListener listener2 = addListenerForEvents(onInvisible(USER_ID));
+ assertUserCanBeAssignedExtraDisplay(USER_ID, SECONDARY_DISPLAY_ID,
+ /* unassign= */ false);
+
+ assertBgUserBecomesInvisibleOnStop(USER_ID);
+
+ listener2.verify();
}
@Test
@@ -244,12 +282,14 @@
expectNoDisplayAssignedToUser(PROFILE_USER_ID);
expectUserAssignedToDisplay(OTHER_SECONDARY_DISPLAY_ID, PARENT_USER_ID);
+ assertInvisibleUserCannotBeAssignedExtraDisplay(PROFILE_USER_ID, SECONDARY_DISPLAY_ID);
+
listener.verify();
}
+ // Conditions below are asserted on other tests, but they're explicitly checked in the 2
+ // tests below (which call this method) as well
private void currentUserVisibilityWhenNoDisplayIsAssignedTest(@UserIdInt int currentUserId) {
- // Conditions below are asserted on other tests, but they're explicitly checked in the 2
- // tests below as well
expectUserIsVisible(currentUserId);
expectUserIsVisibleOnDisplay(currentUserId, DEFAULT_DISPLAY);
expectUserIsNotVisibleOnDisplay(currentUserId, SECONDARY_DISPLAY_ID);
@@ -277,4 +317,13 @@
expectUserIsNotVisibleAtAll(INITIAL_CURRENT_USER_ID);
expectDisplayAssignedToUser(INITIAL_CURRENT_USER_ID, INVALID_DISPLAY);
}
+
+ @Test
+ public final void testAssignUserToExtraDisplay_invalidDisplays() throws Exception {
+ expectWithMessage("assignUserToExtraDisplay(%s, %s)", USER_ID, INVALID_DISPLAY)
+ .that(mMediator.assignUserToExtraDisplay(USER_ID, INVALID_DISPLAY)).isFalse();
+ // DEFAULT_DISPLAY is always assigned to the current user
+ expectWithMessage("assignUserToExtraDisplay(%s, %s)", USER_ID, DEFAULT_DISPLAY)
+ .that(mMediator.assignUserToExtraDisplay(USER_ID, DEFAULT_DISPLAY)).isFalse();
+ }
}
diff --git a/services/tests/mockingservicestests/src/com/android/server/pm/dex/DexManagerTests.java b/services/tests/mockingservicestests/src/com/android/server/pm/dex/DexManagerTests.java
index fb9cbb0..7dae235 100644
--- a/services/tests/mockingservicestests/src/com/android/server/pm/dex/DexManagerTests.java
+++ b/services/tests/mockingservicestests/src/com/android/server/pm/dex/DexManagerTests.java
@@ -85,6 +85,7 @@
private final Object mInstallLock = new Object();
+ private DynamicCodeLogger mDynamicCodeLogger;
private DexManager mDexManager;
private TestData mFooUser0;
@@ -158,8 +159,9 @@
.when(mockContext)
.getSystemService(PowerManager.class);
- mDexManager = new DexManager(mockContext, /*PackageDexOptimizer*/ null,
- mInstaller, mInstallLock, mPM);
+ mDynamicCodeLogger = new DynamicCodeLogger(mInstaller);
+ mDexManager = new DexManager(mockContext, /*PackageDexOptimizer*/ null, mInstaller,
+ mInstallLock, mDynamicCodeLogger, mPM);
// Foo and Bar are available to user0.
// Only Bar is available to user1;
@@ -452,6 +454,7 @@
notifyDexLoad(mBarUser1, mBarUser1.getSecondaryDexPaths(), mUser1);
mDexManager.notifyPackageDataDestroyed(mBarUser0.getPackageName(), mUser0);
+ mDynamicCodeLogger.notifyPackageDataDestroyed(mBarUser0.getPackageName(), mUser0);
// Data for user 1 should still be present
PackageUseInfo pui = getPackageUseInfo(mBarUser1);
@@ -474,6 +477,7 @@
notifyDexLoad(mBarUser0, mFooUser0.getBaseAndSplitDexPaths(), mUser0);
mDexManager.notifyPackageDataDestroyed(mFooUser0.getPackageName(), mUser0);
+ mDynamicCodeLogger.notifyPackageDataDestroyed(mFooUser0.getPackageName(), mUser0);
// Foo should still be around since it's used by other apps but with no
// secondary dex info.
@@ -491,6 +495,7 @@
notifyDexLoad(mFooUser0, fooSecondaries, mUser0);
mDexManager.notifyPackageDataDestroyed(mFooUser0.getPackageName(), mUser0);
+ mDynamicCodeLogger.notifyPackageDataDestroyed(mFooUser0.getPackageName(), mUser0);
// Foo should not be around since all its secondary dex info were deleted
// and it is not used by other apps.
@@ -505,6 +510,8 @@
notifyDexLoad(mBarUser1, mBarUser1.getSecondaryDexPaths(), mUser1);
mDexManager.notifyPackageDataDestroyed(mBarUser0.getPackageName(), UserHandle.USER_ALL);
+ mDynamicCodeLogger.notifyPackageDataDestroyed(
+ mBarUser0.getPackageName(), UserHandle.USER_ALL);
// Bar should not be around since it was removed for all users.
assertNoUseInfo(mBarUser0);
@@ -906,8 +913,7 @@
}
private PackageDynamicCode getPackageDynamicCodeInfo(TestData testData) {
- return mDexManager.getDynamicCodeLogger()
- .getPackageDynamicCodeInfo(testData.getPackageName());
+ return mDynamicCodeLogger.getPackageDynamicCodeInfo(testData.getPackageName());
}
private void assertNoUseInfo(TestData testData) {
diff --git a/services/tests/mockingservicestests/src/com/android/server/wallpaper/WallpaperManagerServiceTests.java b/services/tests/mockingservicestests/src/com/android/server/wallpaper/WallpaperManagerServiceTests.java
index 7fd1ddb..52ed3bc 100644
--- a/services/tests/mockingservicestests/src/com/android/server/wallpaper/WallpaperManagerServiceTests.java
+++ b/services/tests/mockingservicestests/src/com/android/server/wallpaper/WallpaperManagerServiceTests.java
@@ -28,8 +28,7 @@
import static com.android.dx.mockito.inline.extended.ExtendedMockito.mock;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.mockitoSession;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.spyOn;
-import static com.android.server.wallpaper.WallpaperManagerService.WALLPAPER;
-import static com.android.server.wallpaper.WallpaperManagerService.WALLPAPER_CROP;
+import static com.android.server.wallpaper.WallpaperUtils.WALLPAPER;
import static org.hamcrest.core.IsNot.not;
import static org.junit.Assert.assertEquals;
@@ -76,12 +75,12 @@
import androidx.test.platform.app.InstrumentationRegistry;
import androidx.test.runner.AndroidJUnit4;
+import com.android.dx.mockito.inline.extended.ExtendedMockito;
import com.android.dx.mockito.inline.extended.StaticMockitoSession;
import com.android.internal.R;
import com.android.modules.utils.TypedXmlPullParser;
import com.android.modules.utils.TypedXmlSerializer;
import com.android.server.LocalServices;
-import com.android.server.wallpaper.WallpaperManagerService.WallpaperData;
import com.android.server.wm.WindowManagerInternal;
import org.hamcrest.CoreMatchers;
@@ -114,6 +113,8 @@
@FlakyTest(bugId = 129797242)
@RunWith(AndroidJUnit4.class)
public class WallpaperManagerServiceTests {
+
+ private static final String TAG = "WallpaperManagerServiceTests";
private static final int DISPLAY_SIZE_DIMENSION = 100;
private static StaticMockitoSession sMockitoSession;
@@ -138,6 +139,7 @@
public static void setUpClass() {
sMockitoSession = mockitoSession()
.strictness(Strictness.LENIENT)
+ .spyStatic(WallpaperUtils.class)
.spyStatic(LocalServices.class)
.spyStatic(WallpaperManager.class)
.startMocking();
@@ -193,6 +195,11 @@
public void setUp() {
MockitoAnnotations.initMocks(this);
+ ExtendedMockito.doAnswer(invocation -> {
+ int userId = (invocation.getArgument(0));
+ return getWallpaperTestDir(userId);
+ }).when(() -> WallpaperUtils.getWallpaperDir(anyInt()));
+
sContext.addMockSystemService(DisplayManager.class, mDisplayManager);
final Display mockDisplay = mock(Display.class);
@@ -217,27 +224,25 @@
mService = null;
}
+ private File getWallpaperTestDir(int userId) {
+ File tempDir = mTempDirs.get(userId);
+ if (tempDir == null) {
+ try {
+ tempDir = mFolder.newFolder(String.valueOf(userId));
+ mTempDirs.append(userId, tempDir);
+ } catch (IOException e) {
+ Log.e(TAG, "getWallpaperTestDir failed at userId= " + userId);
+ }
+ }
+ return tempDir;
+ }
+
protected class TestWallpaperManagerService extends WallpaperManagerService {
- private static final String TAG = "TestWallpaperManagerService";
TestWallpaperManagerService(Context context) {
super(context);
}
- @Override
- File getWallpaperDir(int userId) {
- File tempDir = mTempDirs.get(userId);
- if (tempDir == null) {
- try {
- tempDir = mFolder.newFolder(String.valueOf(userId));
- mTempDirs.append(userId, tempDir);
- } catch (IOException e) {
- Log.e(TAG, "getWallpaperDir failed at userId= " + userId);
- }
- }
- return tempDir;
- }
-
// Always return true for test
@Override
public boolean isWallpaperSupported(String callingPackage) {
@@ -403,8 +408,7 @@
@Test
public void testWallpaperManagerCallbackInRightOrder() throws RemoteException {
- WallpaperData wallpaper = new WallpaperData(
- USER_SYSTEM, mService.getWallpaperDir(USER_SYSTEM), WALLPAPER, WALLPAPER_CROP);
+ WallpaperData wallpaper = new WallpaperData(USER_SYSTEM, FLAG_SYSTEM);
wallpaper.primaryColors = new WallpaperColors(Color.valueOf(Color.RED),
Color.valueOf(Color.BLUE), null);
diff --git a/services/tests/servicestests/res/xml/usertypes_test_profile.xml b/services/tests/servicestests/res/xml/usertypes_test_profile.xml
index f3ad6d8..450cc40 100644
--- a/services/tests/servicestests/res/xml/usertypes_test_profile.xml
+++ b/services/tests/servicestests/res/xml/usertypes_test_profile.xml
@@ -35,6 +35,7 @@
startWithParent='false'
useParentsContacts='false'
crossProfileIntentFilterAccessControl='20'
+ crossProfileIntentResolutionStrategy='0'
/>
</profile-type>
<profile-type name='custom.test.1' max-allowed-per-parent='14' />
diff --git a/services/tests/servicestests/src/com/android/server/accessibility/AccessibilityManagerServiceTest.java b/services/tests/servicestests/src/com/android/server/accessibility/AccessibilityManagerServiceTest.java
index d056348..448ffe5 100644
--- a/services/tests/servicestests/src/com/android/server/accessibility/AccessibilityManagerServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/accessibility/AccessibilityManagerServiceTest.java
@@ -55,6 +55,7 @@
import android.hardware.display.DisplayManagerGlobal;
import android.os.Bundle;
import android.os.IBinder;
+import android.os.LocaleList;
import android.os.UserHandle;
import android.provider.Settings;
import android.testing.TestableContext;
@@ -106,7 +107,8 @@
private static final String INTENT_ACTION = "TESTACTION";
private static final String DESCRIPTION = "description";
private static final PendingIntent TEST_PENDING_INTENT = PendingIntent.getBroadcast(
- ApplicationProvider.getApplicationContext(), 0, new Intent(INTENT_ACTION),
+ ApplicationProvider.getApplicationContext(), 0, new Intent(INTENT_ACTION)
+ .setPackage(ApplicationProvider.getApplicationContext().getPackageName()),
PendingIntent.FLAG_MUTABLE_UNAUDITED);
private static final RemoteAction TEST_ACTION = new RemoteAction(
Icon.createWithContentUri("content://test"),
@@ -487,7 +489,7 @@
final int userid = 10;
final int windowId = 100;
final AccessibilityWindowAttributes attributes = new AccessibilityWindowAttributes(
- new WindowManager.LayoutParams());
+ new WindowManager.LayoutParams(), LocaleList.getEmptyLocaleList());
mA11yms.setAccessibilityWindowAttributes(displayId, windowId, userid, attributes);
diff --git a/services/tests/servicestests/src/com/android/server/accessibility/AccessibilityWindowManagerTest.java b/services/tests/servicestests/src/com/android/server/accessibility/AccessibilityWindowManagerTest.java
index 7b7e1e0..2dfabd0 100644
--- a/services/tests/servicestests/src/com/android/server/accessibility/AccessibilityWindowManagerTest.java
+++ b/services/tests/servicestests/src/com/android/server/accessibility/AccessibilityWindowManagerTest.java
@@ -43,6 +43,7 @@
import android.graphics.Region;
import android.os.IBinder;
+import android.os.LocaleList;
import android.os.RemoteException;
import android.os.UserHandle;
import android.text.TextUtils;
@@ -909,7 +910,7 @@
final WindowManager.LayoutParams layoutParams = new WindowManager.LayoutParams();
layoutParams.accessibilityTitle = "accessibility window title";
final AccessibilityWindowAttributes attributes = new AccessibilityWindowAttributes(
- layoutParams);
+ layoutParams, new LocaleList());
mA11yWindowManager.setAccessibilityWindowAttributes(Display.DEFAULT_DISPLAY, windowId,
USER_SYSTEM_ID, attributes);
diff --git a/services/tests/servicestests/src/com/android/server/accessibility/SystemActionPerformerTest.java b/services/tests/servicestests/src/com/android/server/accessibility/SystemActionPerformerTest.java
index bbcf77b..13d93cb 100644
--- a/services/tests/servicestests/src/com/android/server/accessibility/SystemActionPerformerTest.java
+++ b/services/tests/servicestests/src/com/android/server/accessibility/SystemActionPerformerTest.java
@@ -76,14 +76,18 @@
private static final String DESCRIPTION1 = "description1";
private static final String DESCRIPTION2 = "description2";
private static final PendingIntent TEST_PENDING_INTENT_1 = PendingIntent.getBroadcast(
- InstrumentationRegistry.getTargetContext(), 0, new Intent(INTENT_ACTION1), PendingIntent.FLAG_MUTABLE_UNAUDITED);
+ InstrumentationRegistry.getTargetContext(), 0, new Intent(INTENT_ACTION1)
+ .setPackage(InstrumentationRegistry.getTargetContext().getPackageName()),
+ PendingIntent.FLAG_MUTABLE_UNAUDITED);
private static final RemoteAction NEW_TEST_ACTION_1 = new RemoteAction(
Icon.createWithContentUri("content://test"),
LABEL_1,
DESCRIPTION1,
TEST_PENDING_INTENT_1);
private static final PendingIntent TEST_PENDING_INTENT_2 = PendingIntent.getBroadcast(
- InstrumentationRegistry.getTargetContext(), 0, new Intent(INTENT_ACTION2), PendingIntent.FLAG_MUTABLE_UNAUDITED);
+ InstrumentationRegistry.getTargetContext(), 0, new Intent(INTENT_ACTION2)
+ .setPackage(InstrumentationRegistry.getTargetContext().getPackageName()),
+ PendingIntent.FLAG_MUTABLE_UNAUDITED);
private static final RemoteAction NEW_TEST_ACTION_2 = new RemoteAction(
Icon.createWithContentUri("content://test"),
LABEL_2,
diff --git a/services/tests/servicestests/src/com/android/server/accessibility/magnification/MagnificationControllerTest.java b/services/tests/servicestests/src/com/android/server/accessibility/magnification/MagnificationControllerTest.java
index eac8671..2a80ce0 100644
--- a/services/tests/servicestests/src/com/android/server/accessibility/magnification/MagnificationControllerTest.java
+++ b/services/tests/servicestests/src/com/android/server/accessibility/magnification/MagnificationControllerTest.java
@@ -26,13 +26,13 @@
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
import static org.mockito.ArgumentMatchers.any;
-import static org.mockito.ArgumentMatchers.anyBoolean;
import static org.mockito.ArgumentMatchers.anyFloat;
import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.ArgumentMatchers.anyLong;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.ArgumentMatchers.nullable;
import static org.mockito.Mockito.doAnswer;
+import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.times;
@@ -40,26 +40,33 @@
import static org.mockito.Mockito.when;
import android.accessibilityservice.MagnificationConfig;
+import android.animation.ValueAnimator;
import android.content.Context;
import android.content.pm.PackageManager;
import android.graphics.PointF;
import android.graphics.Rect;
import android.graphics.Region;
+import android.hardware.display.DisplayManagerInternal;
+import android.os.Looper;
import android.os.RemoteException;
import android.os.UserHandle;
import android.provider.Settings;
import android.test.mock.MockContentResolver;
import android.testing.DexmakerShareClassLoaderRule;
import android.view.Display;
+import android.view.DisplayInfo;
import android.view.accessibility.IRemoteMagnificationAnimationCallback;
import android.view.accessibility.MagnificationAnimationCallback;
+import androidx.annotation.NonNull;
+import androidx.test.InstrumentationRegistry;
import androidx.test.runner.AndroidJUnit4;
import com.android.internal.util.test.FakeSettingsProvider;
import com.android.server.LocalServices;
import com.android.server.accessibility.AccessibilityManagerService;
import com.android.server.accessibility.AccessibilityTraceManager;
+import com.android.server.accessibility.test.MessageCapturingHandler;
import com.android.server.wm.WindowManagerInternal;
import org.junit.After;
@@ -70,7 +77,6 @@
import org.mockito.ArgumentCaptor;
import org.mockito.Captor;
import org.mockito.Mock;
-import org.mockito.Mockito;
import org.mockito.MockitoAnnotations;
import org.mockito.stubbing.Answer;
@@ -82,6 +88,8 @@
private static final int TEST_DISPLAY = Display.DEFAULT_DISPLAY;
private static final int TEST_SERVICE_ID = 1;
+ private static final Region INITIAL_SCREEN_MAGNIFICATION_REGION =
+ new Region(0, 0, 500, 600);
private static final Rect TEST_RECT = new Rect(0, 50, 100, 51);
private static final float MAGNIFIED_CENTER_X = 100;
private static final float MAGNIFIED_CENTER_Y = 200;
@@ -101,9 +109,20 @@
@Mock
private Context mContext;
@Mock
- PackageManager mPackageManager;
+ private PackageManager mPackageManager;
+
@Mock
+ private FullScreenMagnificationController.ControllerContext mControllerCtx;
+ @Mock
+ private ValueAnimator mValueAnimator;
+ @Mock
+ private MessageCapturingHandler mMessageCapturingHandler;
+
private FullScreenMagnificationController mScreenMagnificationController;
+ private final FullScreenMagnificationCtrInfoChangedCallbackDelegate
+ mScreenMagnificationInfoChangedCallbackDelegate =
+ new FullScreenMagnificationCtrInfoChangedCallbackDelegate();
+
private MagnificationScaleProvider mScaleProvider;
@Captor
private ArgumentCaptor<MagnificationAnimationCallback> mCallbackArgumentCaptor;
@@ -112,13 +131,17 @@
private WindowMagnificationManager mWindowMagnificationManager;
private MockContentResolver mMockResolver;
private MagnificationController mMagnificationController;
- private final WindowMagnificationMgrCallbackDelegate mCallbackDelegate =
+ private final WindowMagnificationMgrCallbackDelegate
+ mWindowMagnificationCallbackDelegate =
new WindowMagnificationMgrCallbackDelegate();
@Mock
- private WindowManagerInternal mMockWindowManagerInternal;
+ private WindowManagerInternal mWindowManagerInternal;
@Mock
- private WindowManagerInternal.AccessibilityControllerInternal mMockA11yController;
+ private WindowManagerInternal.AccessibilityControllerInternal mA11yController;
+
+ @Mock
+ private DisplayManagerInternal mDisplayManagerInternal;
// To mock package-private class
@Rule
@@ -132,31 +155,60 @@
final Object globalLock = new Object();
LocalServices.removeServiceForTest(WindowManagerInternal.class);
- LocalServices.addService(WindowManagerInternal.class, mMockWindowManagerInternal);
- when(mMockWindowManagerInternal.getAccessibilityController()).thenReturn(
- mMockA11yController);
+ LocalServices.addService(WindowManagerInternal.class, mWindowManagerInternal);
+ when(mWindowManagerInternal.getAccessibilityController()).thenReturn(
+ mA11yController);
+ when(mWindowManagerInternal.setMagnificationCallbacks(eq(TEST_DISPLAY), any()))
+ .thenReturn(true);
+ doAnswer((Answer<Void>) invocationOnMock -> {
+ Object[] args = invocationOnMock.getArguments();
+ Region regionArg = (Region) args[1];
+ regionArg.set(INITIAL_SCREEN_MAGNIFICATION_REGION);
+ return null;
+ }).when(mWindowManagerInternal).getMagnificationRegion(anyInt(), any(Region.class));
mMockResolver = new MockContentResolver();
mMockResolver.addProvider(Settings.AUTHORITY, new FakeSettingsProvider());
+ Looper looper = InstrumentationRegistry.getContext().getMainLooper();
+ // Pretending ID of the Thread associated with looper as main thread ID in controller
+ when(mContext.getMainLooper()).thenReturn(looper);
when(mContext.getContentResolver()).thenReturn(mMockResolver);
when(mContext.getPackageManager()).thenReturn(mPackageManager);
Settings.Secure.putFloatForUser(mMockResolver,
Settings.Secure.ACCESSIBILITY_DISPLAY_MAGNIFICATION_SCALE, DEFAULT_SCALE,
CURRENT_USER_ID);
mScaleProvider = spy(new MagnificationScaleProvider(mContext));
- mWindowMagnificationManager = Mockito.spy(
- new WindowMagnificationManager(mContext, globalLock,
- mCallbackDelegate, mTraceManager, mScaleProvider));
+
+ when(mControllerCtx.getContext()).thenReturn(mContext);
+ when(mControllerCtx.getTraceManager()).thenReturn(mTraceManager);
+ when(mControllerCtx.getWindowManager()).thenReturn(mWindowManagerInternal);
+ when(mControllerCtx.getHandler()).thenReturn(mMessageCapturingHandler);
+ when(mControllerCtx.getAnimationDuration()).thenReturn(1000L);
+ when(mControllerCtx.newValueAnimator()).thenReturn(mValueAnimator);
+
+ final DisplayInfo displayInfo = new DisplayInfo();
+ displayInfo.logicalDensityDpi = 300;
+ doReturn(displayInfo).when(mDisplayManagerInternal).getDisplayInfo(anyInt());
+ LocalServices.removeServiceForTest(DisplayManagerInternal.class);
+ LocalServices.addService(DisplayManagerInternal.class, mDisplayManagerInternal);
+
+ mScreenMagnificationController = spy(new FullScreenMagnificationController(
+ mControllerCtx, new Object(),
+ mScreenMagnificationInfoChangedCallbackDelegate, mScaleProvider));
+ mScreenMagnificationController.register(TEST_DISPLAY);
+
+ mWindowMagnificationManager = spy(new WindowMagnificationManager(mContext, globalLock,
+ mWindowMagnificationCallbackDelegate, mTraceManager, mScaleProvider));
mMockConnection = new MockWindowMagnificationConnection(true);
mWindowMagnificationManager.setConnection(mMockConnection.getConnection());
+
mMagnificationController = new MagnificationController(mService, globalLock, mContext,
mScreenMagnificationController, mWindowMagnificationManager, mScaleProvider);
- new FullScreenMagnificationControllerStubber(mScreenMagnificationController,
- mMagnificationController);
-
mMagnificationController.setMagnificationCapabilities(
Settings.Secure.ACCESSIBILITY_MAGNIFICATION_MODE_ALL);
- mCallbackDelegate.setDelegate(mMagnificationController);
+
+ mScreenMagnificationInfoChangedCallbackDelegate.setDelegate(mMagnificationController);
+ mWindowMagnificationCallbackDelegate.setDelegate(mMagnificationController);
}
@After
@@ -213,8 +265,8 @@
verify(mTransitionCallBack).onResult(TEST_DISPLAY, false);
final ArgumentCaptor<MagnificationConfig> configCaptor = ArgumentCaptor.forClass(
MagnificationConfig.class);
- // The first time is for notifying full-screen enabled and the second time is for notifying
- // the target mode transitions failed.
+ // The first time is for notifying full-screen enabled.
+ // The second time is for notifying the target mode transitions failed.
verify(mService, times(2)).notifyMagnificationChanged(eq(TEST_DISPLAY), any(Region.class),
configCaptor.capture());
final MagnificationConfig actualConfig = configCaptor.getValue();
@@ -252,9 +304,9 @@
MODE_WINDOW,
mTransitionCallBack);
- // The first time is triggered when window mode is activated, the second time is triggered
- // when activating the window mode again. The third time is triggered when the transition is
- // completed.
+ // The first time is triggered when window mode is activated.
+ // The second time is triggered when activating the window mode again.
+ // The third time is triggered when the transition is completed.
verify(mWindowMagnificationManager, times(3)).showMagnificationButton(eq(TEST_DISPLAY),
eq(MODE_WINDOW));
}
@@ -279,8 +331,7 @@
@Test
public void transitionToFullScreen_centerNotInTheBounds_magnifyBoundsCenter()
throws RemoteException {
- final Rect magnificationBounds =
- FullScreenMagnificationControllerStubber.MAGNIFICATION_REGION.getBounds();
+ final Rect magnificationBounds = INITIAL_SCREEN_MAGNIFICATION_REGION.getBounds();
final PointF magnifiedCenter = new PointF(magnificationBounds.right + 100,
magnificationBounds.bottom + 100);
setMagnificationEnabled(MODE_WINDOW, magnifiedCenter.x, magnifiedCenter.y);
@@ -436,17 +487,19 @@
public void magnifyThroughExternalRequest_showMagnificationButton() {
mScreenMagnificationController.setScaleAndCenter(TEST_DISPLAY, DEFAULT_SCALE,
MAGNIFIED_CENTER_X, MAGNIFIED_CENTER_Y, false, TEST_SERVICE_ID);
- mMagnificationController.onRequestMagnificationSpec(TEST_DISPLAY, TEST_SERVICE_ID);
- verify(mWindowMagnificationManager).showMagnificationButton(eq(TEST_DISPLAY),
+ // The first time is trigger when fullscreen mode is activated.
+ // The second time is triggered when magnification spec is changed.
+ verify(mWindowMagnificationManager, times(2)).showMagnificationButton(eq(TEST_DISPLAY),
eq(MODE_FULLSCREEN));
}
@Test
- public void setScaleOneThroughExternalRequest_removeMagnificationButton() {
+ public void setScaleOneThroughExternalRequest_fullScreenEnabled_removeMagnificationButton()
+ throws RemoteException {
+ setMagnificationEnabled(MODE_FULLSCREEN);
mScreenMagnificationController.setScaleAndCenter(TEST_DISPLAY, 1.0f,
MAGNIFIED_CENTER_X, MAGNIFIED_CENTER_Y, false, TEST_SERVICE_ID);
- mMagnificationController.onRequestMagnificationSpec(TEST_DISPLAY, TEST_SERVICE_ID);
verify(mWindowMagnificationManager).removeMagnificationButton(eq(TEST_DISPLAY));
}
@@ -490,12 +543,12 @@
config.getScale(), config.getCenterX(), config.getCenterY(),
true, TEST_SERVICE_ID);
- // The first time is triggered when setting magnification enabled. And the second time is
- // triggered when calling setScaleAndCenter.
+ // The notify method is triggered when setting magnification enabled.
+ // The setScaleAndCenter call should not trigger notify method due to same scale and center.
final ArgumentCaptor<MagnificationConfig> configCaptor = ArgumentCaptor.forClass(
MagnificationConfig.class);
- verify(mService, times(2)).notifyMagnificationChanged(eq(TEST_DISPLAY),
- eq(FullScreenMagnificationControllerStubber.MAGNIFICATION_REGION),
+ verify(mService).notifyMagnificationChanged(eq(TEST_DISPLAY),
+ eq(INITIAL_SCREEN_MAGNIFICATION_REGION),
configCaptor.capture());
final MagnificationConfig actualConfig = configCaptor.getValue();
assertEquals(config.getCenterX(), actualConfig.getCenterX(), 0);
@@ -514,8 +567,8 @@
final ArgumentCaptor<MagnificationConfig> configCaptor = ArgumentCaptor.forClass(
MagnificationConfig.class);
- // The first time is for notifying window enabled and the second time is for notifying
- // the target mode transitions.
+ // The first time is for notifying window enabled.
+ // The second time is for notifying the target mode transitions.
verify(mService, times(2)).notifyMagnificationChanged(eq(TEST_DISPLAY), any(Region.class),
configCaptor.capture());
final MagnificationConfig actualConfig = configCaptor.getValue();
@@ -534,8 +587,8 @@
final ArgumentCaptor<MagnificationConfig> configCaptor = ArgumentCaptor.forClass(
MagnificationConfig.class);
- // The first time is for notifying window enabled and the second time is for notifying
- // the target mode transitions.
+ // The first time is for notifying window enabled.
+ // The second time is for notifying the target mode transitions.
verify(mService, times(2)).notifyMagnificationChanged(eq(TEST_DISPLAY), any(Region.class),
configCaptor.capture());
final MagnificationConfig actualConfig = configCaptor.getValue();
@@ -558,8 +611,8 @@
final ArgumentCaptor<MagnificationConfig> configCaptor = ArgumentCaptor.forClass(
MagnificationConfig.class);
- // The first time is for notifying full-screen enabled and the second time is for notifying
- // the target mode transitions.
+ // The first time is for notifying full-screen enabled.
+ // The second time is for notifying the target mode transitions.
verify(mService, times(2)).notifyMagnificationChanged(eq(TEST_DISPLAY), any(Region.class),
configCaptor.capture());
final MagnificationConfig actualConfig = configCaptor.getValue();
@@ -578,8 +631,8 @@
final ArgumentCaptor<MagnificationConfig> configCaptor = ArgumentCaptor.forClass(
MagnificationConfig.class);
- // The first time is for notifying full-screen enabled and the second time is for notifying
- // the target mode transitions.
+ // The first time is for notifying full-screen enabled.
+ // The second time is for notifying the target mode transitions.
verify(mService, times(2)).notifyMagnificationChanged(eq(TEST_DISPLAY), any(Region.class),
configCaptor.capture());
final MagnificationConfig actualConfig = configCaptor.getValue();
@@ -597,6 +650,7 @@
mMagnificationController.onAccessibilityActionPerformed(TEST_DISPLAY);
// The first time is triggered when window mode is activated.
+ // The second time is triggered when accessibility action performed.
verify(mWindowMagnificationManager, times(2)).showMagnificationButton(eq(TEST_DISPLAY),
eq(MODE_WINDOW));
}
@@ -611,6 +665,7 @@
mMagnificationController.onAccessibilityActionPerformed(TEST_DISPLAY);
// The first time is triggered when window mode is activated.
+ // The second time is triggered when accessibility action performed.
verify(mWindowMagnificationManager, times(2)).removeMagnificationButton(eq(TEST_DISPLAY));
}
@@ -767,7 +822,10 @@
mMagnificationController.onTouchInteractionStart(TEST_DISPLAY, MODE_FULLSCREEN);
- verify(mWindowMagnificationManager).showMagnificationButton(eq(TEST_DISPLAY),
+ // The first time is triggered when fullscreen mode is activated.
+ // The second time is triggered when magnification spec is changed.
+ // The third time is triggered when user interaction changed.
+ verify(mWindowMagnificationManager, times(3)).showMagnificationButton(eq(TEST_DISPLAY),
eq(MODE_FULLSCREEN));
}
@@ -778,7 +836,10 @@
mMagnificationController.onTouchInteractionEnd(TEST_DISPLAY, MODE_FULLSCREEN);
- verify(mWindowMagnificationManager).showMagnificationButton(eq(TEST_DISPLAY),
+ // The first time is triggered when fullscreen mode is activated.
+ // The second time is triggered when magnification spec is changed.
+ // The third time is triggered when user interaction changed.
+ verify(mWindowMagnificationManager, times(3)).showMagnificationButton(eq(TEST_DISPLAY),
eq(MODE_FULLSCREEN));
}
@@ -790,6 +851,7 @@
mMagnificationController.onTouchInteractionStart(TEST_DISPLAY, MODE_WINDOW);
// The first time is triggered when the window mode is activated.
+ // The second time is triggered when user interaction changed.
verify(mWindowMagnificationManager, times(2)).showMagnificationButton(eq(TEST_DISPLAY),
eq(MODE_WINDOW));
}
@@ -802,6 +864,7 @@
mMagnificationController.onTouchInteractionEnd(TEST_DISPLAY, MODE_WINDOW);
// The first time is triggered when the window mode is activated.
+ // The second time is triggered when user interaction changed.
verify(mWindowMagnificationManager, times(2)).showMagnificationButton(eq(TEST_DISPLAY),
eq(MODE_WINDOW));
}
@@ -849,7 +912,10 @@
mMagnificationController.onFullScreenMagnificationActivationState(TEST_DISPLAY, true);
- verify(mWindowMagnificationManager).showMagnificationButton(eq(TEST_DISPLAY),
+ // The first time is triggered when fullscreen mode is activated.
+ // The second time is triggered when magnification spec is changed.
+ // The third time is triggered when fullscreen mode activation state is updated.
+ verify(mWindowMagnificationManager, times(3)).showMagnificationButton(eq(TEST_DISPLAY),
eq(MODE_FULLSCREEN));
}
@@ -867,11 +933,7 @@
public void onFullScreenDeactivated_fullScreenEnabled_removeMagnificationButton()
throws RemoteException {
setMagnificationEnabled(MODE_FULLSCREEN);
- mScreenMagnificationController.setScaleAndCenter(TEST_DISPLAY,
- /* scale= */ 1, MAGNIFIED_CENTER_X, MAGNIFIED_CENTER_Y,
- true, TEST_SERVICE_ID);
-
- mMagnificationController.onFullScreenMagnificationActivationState(TEST_DISPLAY, false);
+ mScreenMagnificationController.reset(TEST_DISPLAY, /* animate= */ true);
verify(mWindowMagnificationManager).removeMagnificationButton(eq(TEST_DISPLAY));
}
@@ -885,7 +947,10 @@
MODE_FULLSCREEN, mTransitionCallBack);
mMockConnection.invokeCallbacks();
- verify(mWindowMagnificationManager).showMagnificationButton(eq(TEST_DISPLAY),
+ // The first time is triggered when fullscreen mode is activated.
+ // The second time is triggered when magnification spec is changed.
+ // The third time is triggered when the disable-magnification callback is triggered.
+ verify(mWindowMagnificationManager, times(3)).showMagnificationButton(eq(TEST_DISPLAY),
eq(MODE_FULLSCREEN));
}
@@ -902,8 +967,8 @@
mCallbackArgumentCaptor.getValue().onResult(true);
mMockConnection.invokeCallbacks();
- // The first time is triggered when window mode is activated, the second time is triggered
- // when the disable-magnification callback is triggered.
+ // The first time is triggered when window mode is activated.
+ // The second time is triggered when the disable-magnification callback is triggered.
verify(mWindowMagnificationManager, times(2)).showMagnificationButton(eq(TEST_DISPLAY),
eq(MODE_WINDOW));
}
@@ -1023,8 +1088,7 @@
.UiChangesForAccessibilityCallbacks> captor = ArgumentCaptor.forClass(
WindowManagerInternal.AccessibilityControllerInternal
.UiChangesForAccessibilityCallbacks.class);
- verify(mMockWindowManagerInternal.getAccessibilityController())
- .setUiChangesForAccessibilityCallbacks(captor.capture());
+ verify(mA11yController).setUiChangesForAccessibilityCallbacks(captor.capture());
return captor.getValue();
}
@@ -1072,95 +1136,42 @@
}
}
- /**
- * Stubs public methods to simulate the real behaviours.
- */
- private static class FullScreenMagnificationControllerStubber {
- private static final Region MAGNIFICATION_REGION = new Region(0, 0, 500, 600);
- private final FullScreenMagnificationController mScreenMagnificationController;
- private final FullScreenMagnificationController.MagnificationInfoChangedCallback
- mMagnificationChangedCallback;
- private boolean mIsMagnifying = false;
- private float mScale = 1.0f;
- private float mCenterX = MAGNIFICATION_REGION.getBounds().exactCenterX();
- private float mCenterY = MAGNIFICATION_REGION.getBounds().exactCenterY();
- private int mServiceId = -1;
+ private static class FullScreenMagnificationCtrInfoChangedCallbackDelegate implements
+ FullScreenMagnificationController.MagnificationInfoChangedCallback {
+ private FullScreenMagnificationController.MagnificationInfoChangedCallback mCallback;
- FullScreenMagnificationControllerStubber(
- FullScreenMagnificationController screenMagnificationController,
+ public void setDelegate(
FullScreenMagnificationController.MagnificationInfoChangedCallback callback) {
- mScreenMagnificationController = screenMagnificationController;
- mMagnificationChangedCallback = callback;
- stubMethods();
+ mCallback = callback;
}
- private void stubMethods() {
- doAnswer(invocation -> mIsMagnifying).when(mScreenMagnificationController).isMagnifying(
- TEST_DISPLAY);
- doAnswer(invocation -> mIsMagnifying).when(
- mScreenMagnificationController).isForceShowMagnifiableBounds(TEST_DISPLAY);
- doAnswer(invocation -> mScale).when(mScreenMagnificationController).getPersistedScale(
- TEST_DISPLAY);
- doAnswer(invocation -> mScale).when(mScreenMagnificationController).getScale(
- TEST_DISPLAY);
- doAnswer(invocation -> mCenterX).when(mScreenMagnificationController).getCenterX(
- TEST_DISPLAY);
- doAnswer(invocation -> mCenterY).when(mScreenMagnificationController).getCenterY(
- TEST_DISPLAY);
- doAnswer(invocation -> mServiceId).when(
- mScreenMagnificationController).getIdOfLastServiceToMagnify(TEST_DISPLAY);
-
- doAnswer(invocation -> {
- final Region outRegion = invocation.getArgument(1);
- outRegion.set(MAGNIFICATION_REGION);
- return null;
- }).when(mScreenMagnificationController).getMagnificationRegion(anyInt(),
- any(Region.class));
-
- Answer setScaleAndCenterStubAnswer = invocation -> {
- final float scale = invocation.getArgument(1);
- mScale = Float.isNaN(scale) ? mScale : scale;
- mIsMagnifying = mScale > 1.0f;
- if (mIsMagnifying) {
- mCenterX = invocation.getArgument(2);
- mCenterY = invocation.getArgument(3);
- mServiceId = invocation.getArgument(5);
- } else {
- reset();
- }
-
- final MagnificationConfig config = new MagnificationConfig.Builder().setMode(
- MODE_FULLSCREEN).setScale(mScale).setCenterX(mCenterX).setCenterY(
- mCenterY).build();
- mMagnificationChangedCallback.onFullScreenMagnificationChanged(TEST_DISPLAY,
- FullScreenMagnificationControllerStubber.MAGNIFICATION_REGION,
- config);
- return true;
- };
- doAnswer(setScaleAndCenterStubAnswer).when(
- mScreenMagnificationController).setScaleAndCenter(eq(TEST_DISPLAY),
- anyFloat(), anyFloat(), anyFloat(), any(), anyInt());
-
- doAnswer(setScaleAndCenterStubAnswer).when(
- mScreenMagnificationController).setScaleAndCenter(eq(TEST_DISPLAY),
- anyFloat(), anyFloat(), anyFloat(), anyBoolean(), anyInt());
-
- Answer resetStubAnswer = invocation -> {
- reset();
- return true;
- };
- doAnswer(resetStubAnswer).when(mScreenMagnificationController).reset(eq(TEST_DISPLAY),
- any(MagnificationAnimationCallback.class));
- doAnswer(resetStubAnswer).when(mScreenMagnificationController).reset(eq(TEST_DISPLAY),
- anyBoolean());
+ @Override
+ public void onRequestMagnificationSpec(int displayId, int serviceId) {
+ if (mCallback != null) {
+ mCallback.onRequestMagnificationSpec(displayId, serviceId);
+ }
}
- private void reset() {
- mScale = 1.0f;
- mIsMagnifying = false;
- mServiceId = -1;
- mCenterX = MAGNIFICATION_REGION.getBounds().exactCenterX();
- mCenterY = MAGNIFICATION_REGION.getBounds().exactCenterY();
+ @Override
+ public void onFullScreenMagnificationActivationState(int displayId, boolean activated) {
+ if (mCallback != null) {
+ mCallback.onFullScreenMagnificationActivationState(displayId, activated);
+ }
+ }
+
+ @Override
+ public void onImeWindowVisibilityChanged(int displayId, boolean shown) {
+ if (mCallback != null) {
+ mCallback.onImeWindowVisibilityChanged(displayId, shown);
+ }
+ }
+
+ @Override
+ public void onFullScreenMagnificationChanged(int displayId, @NonNull Region region,
+ @NonNull MagnificationConfig config) {
+ if (mCallback != null) {
+ mCallback.onFullScreenMagnificationChanged(displayId, region, config);
+ }
}
}
}
diff --git a/services/tests/servicestests/src/com/android/server/am/CoreSettingsObserverTest.java b/services/tests/servicestests/src/com/android/server/am/CoreSettingsObserverTest.java
index 574aaf0..5f55f09 100644
--- a/services/tests/servicestests/src/com/android/server/am/CoreSettingsObserverTest.java
+++ b/services/tests/servicestests/src/com/android/server/am/CoreSettingsObserverTest.java
@@ -97,6 +97,8 @@
mContentResolver = new MockContentResolver(mContext);
mContentResolver.addProvider(Settings.AUTHORITY, new FakeSettingsProvider());
when(mContext.getContentResolver()).thenReturn(mContentResolver);
+ when(mContext.getCacheDir()).thenReturn(originalContext.getCacheDir());
+ when(mContext.getAttributionSource()).thenReturn(originalContext.getAttributionSource());
when(mContext.getResources()).thenReturn(mResources);
// To prevent NullPointerException at the constructor of ActivityManagerConstants.
when(mResources.getStringArray(anyInt())).thenReturn(new String[0]);
diff --git a/services/tests/servicestests/src/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintAuthenticationClientTest.java b/services/tests/servicestests/src/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintAuthenticationClientTest.java
index 20beed0..99f7905 100644
--- a/services/tests/servicestests/src/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintAuthenticationClientTest.java
+++ b/services/tests/servicestests/src/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintAuthenticationClientTest.java
@@ -41,7 +41,6 @@
import android.hardware.biometrics.fingerprint.ISession;
import android.hardware.biometrics.fingerprint.PointerContext;
import android.hardware.fingerprint.Fingerprint;
-import android.hardware.fingerprint.FingerprintManager;
import android.hardware.fingerprint.FingerprintSensorPropertiesInternal;
import android.hardware.fingerprint.ISidefpsController;
import android.hardware.fingerprint.IUdfpsOverlayController;
@@ -55,7 +54,6 @@
import androidx.test.filters.SmallTest;
import androidx.test.platform.app.InstrumentationRegistry;
-import com.android.internal.R;
import com.android.server.biometrics.log.BiometricContext;
import com.android.server.biometrics.log.BiometricLogger;
import com.android.server.biometrics.log.CallbackWithProbe;
@@ -398,274 +396,6 @@
verify(mCancellationSignal).cancel();
}
- @Test
- public void fingerprintPowerIgnoresAuthInWindow() throws Exception {
- when(mSensorProps.isAnySidefpsType()).thenReturn(true);
- when(mHal.authenticate(anyLong())).thenReturn(mCancellationSignal);
-
- final FingerprintAuthenticationClient client = createClient(1);
- client.start(mCallback);
- client.onPowerPressed();
- client.onAuthenticated(new Fingerprint("friendly", 1 /* fingerId */, 2 /* deviceId */),
- true /* authenticated */, new ArrayList<>());
- mLooper.moveTimeForward(1000);
- mLooper.dispatchAll();
-
- verify(mCallback).onClientFinished(any(), eq(false));
- verify(mCancellationSignal).cancel();
- }
-
- @Test
- public void fingerprintAuthIgnoredWaitingForPower() throws Exception {
- when(mSensorProps.isAnySidefpsType()).thenReturn(true);
- when(mHal.authenticate(anyLong())).thenReturn(mCancellationSignal);
-
- final FingerprintAuthenticationClient client = createClient(1);
- client.start(mCallback);
- client.onAuthenticated(new Fingerprint("friendly", 3 /* fingerId */, 4 /* deviceId */),
- true /* authenticated */, new ArrayList<>());
- client.onPowerPressed();
- mLooper.moveTimeForward(1000);
- mLooper.dispatchAll();
-
- verify(mCallback).onClientFinished(any(), eq(false));
- verify(mCancellationSignal).cancel();
- }
-
- @Test
- public void fingerprintAuthFailsWhenAuthAfterPower() throws Exception {
- when(mSensorProps.isAnySidefpsType()).thenReturn(true);
- when(mHal.authenticate(anyLong())).thenReturn(mCancellationSignal);
-
- final FingerprintAuthenticationClient client = createClient(1);
- client.start(mCallback);
- client.onPowerPressed();
- mLooper.dispatchAll();
- mLooper.moveTimeForward(1000);
- mLooper.dispatchAll();
- client.onAuthenticated(new Fingerprint("friendly", 4 /* fingerId */, 5 /* deviceId */),
- true /* authenticated */, new ArrayList<>());
- mLooper.dispatchAll();
- mLooper.moveTimeForward(1000);
- mLooper.dispatchAll();
-
- verify(mCallback, never()).onClientFinished(any(), eq(true));
- verify(mCallback).onClientFinished(any(), eq(false));
- when(mHal.authenticateWithContext(anyLong(), any())).thenReturn(mCancellationSignal);
- }
-
- @Test
- public void sideFingerprintDoesntSendAuthImmediately() throws Exception {
- when(mSensorProps.isAnySidefpsType()).thenReturn(true);
-
- final FingerprintAuthenticationClient client = createClient(1);
- client.start(mCallback);
- mLooper.dispatchAll();
- client.onAuthenticated(new Fingerprint("friendly", 4 /* fingerId */, 5 /* deviceId */),
- true /* authenticated */, new ArrayList<>());
- mLooper.dispatchAll();
-
- verify(mCallback, never()).onClientFinished(any(), anyBoolean());
- }
-
- @Test
- public void sideFingerprintSkipsWindowIfFingerUp() throws Exception {
- when(mSensorProps.isAnySidefpsType()).thenReturn(true);
-
- mContext.getOrCreateTestableResources().addOverride(
- R.integer.config_sidefpsSkipWaitForPowerAcquireMessage, FINGER_UP);
-
- final FingerprintAuthenticationClient client = createClient(1);
- client.start(mCallback);
- mLooper.dispatchAll();
- client.onAuthenticated(new Fingerprint("friendly", 4 /* fingerId */, 5 /* deviceId */),
- true /* authenticated */, new ArrayList<>());
- client.onAcquired(FINGER_UP, 0);
- mLooper.dispatchAll();
-
- verify(mCallback).onClientFinished(any(), eq(true));
- }
-
- @Test
- public void sideFingerprintSkipsWindowIfVendorMessageMatch() throws Exception {
- when(mSensorProps.isAnySidefpsType()).thenReturn(true);
- final int vendorAcquireMessage = 1234;
-
- mContext.getOrCreateTestableResources().addOverride(
- R.integer.config_sidefpsSkipWaitForPowerAcquireMessage,
- FingerprintManager.FINGERPRINT_ACQUIRED_VENDOR);
- mContext.getOrCreateTestableResources().addOverride(
- R.integer.config_sidefpsSkipWaitForPowerVendorAcquireMessage,
- vendorAcquireMessage);
-
- final FingerprintAuthenticationClient client = createClient(1);
- client.start(mCallback);
- mLooper.dispatchAll();
- client.onAuthenticated(new Fingerprint("friendly", 4 /* fingerId */, 5 /* deviceId */),
- true /* authenticated */, new ArrayList<>());
- client.onAcquired(FingerprintManager.FINGERPRINT_ACQUIRED_VENDOR, vendorAcquireMessage);
- mLooper.dispatchAll();
-
- verify(mCallback).onClientFinished(any(), eq(true));
- }
-
- @Test
- public void sideFingerprintDoesNotSkipWindowOnVendorErrorMismatch() throws Exception {
- when(mSensorProps.isAnySidefpsType()).thenReturn(true);
- final int vendorAcquireMessage = 1234;
-
- mContext.getOrCreateTestableResources().addOverride(
- R.integer.config_sidefpsSkipWaitForPowerAcquireMessage,
- FingerprintManager.FINGERPRINT_ACQUIRED_VENDOR);
- mContext.getOrCreateTestableResources().addOverride(
- R.integer.config_sidefpsSkipWaitForPowerVendorAcquireMessage,
- vendorAcquireMessage);
-
- final FingerprintAuthenticationClient client = createClient(1);
- client.start(mCallback);
- mLooper.dispatchAll();
- client.onAuthenticated(new Fingerprint("friendly", 4 /* fingerId */, 5 /* deviceId */),
- true /* authenticated */, new ArrayList<>());
- client.onAcquired(FingerprintManager.FINGERPRINT_ACQUIRED_VENDOR, 1);
- mLooper.dispatchAll();
-
- verify(mCallback, never()).onClientFinished(any(), anyBoolean());
- }
-
- @Test
- public void sideFingerprintSendsAuthIfFingerUp() throws Exception {
- when(mSensorProps.isAnySidefpsType()).thenReturn(true);
-
- mContext.getOrCreateTestableResources().addOverride(
- R.integer.config_sidefpsSkipWaitForPowerAcquireMessage, FINGER_UP);
-
- final FingerprintAuthenticationClient client = createClient(1);
- client.start(mCallback);
- mLooper.dispatchAll();
- client.onAcquired(FINGER_UP, 0);
- client.onAuthenticated(new Fingerprint("friendly", 4 /* fingerId */, 5 /* deviceId */),
- true /* authenticated */, new ArrayList<>());
- mLooper.dispatchAll();
-
- verify(mCallback).onClientFinished(any(), eq(true));
- }
-
- @Test
- public void sideFingerprintShortCircuitExpires() throws Exception {
- when(mSensorProps.isAnySidefpsType()).thenReturn(true);
-
- final int timeBeforeAuthSent = 500;
-
- mContext.getOrCreateTestableResources().addOverride(
- R.integer.config_sidefpsKeyguardPowerPressWindow, timeBeforeAuthSent);
- mContext.getOrCreateTestableResources().addOverride(
- R.integer.config_sidefpsSkipWaitForPowerAcquireMessage, FINGER_UP);
-
- final FingerprintAuthenticationClient client = createClient(1);
- client.start(mCallback);
- mLooper.dispatchAll();
- client.onAcquired(FINGER_UP, 0);
- mLooper.dispatchAll();
-
- mLooper.moveTimeForward(500);
- mLooper.dispatchAll();
- client.onAuthenticated(new Fingerprint("friendly", 4 /* fingerId */, 5 /* deviceId */),
- true /* authenticated */, new ArrayList<>());
- mLooper.dispatchAll();
- verify(mCallback, never()).onClientFinished(any(), anyBoolean());
-
- mLooper.moveTimeForward(500);
- mLooper.dispatchAll();
- verify(mCallback).onClientFinished(any(), eq(true));
- }
-
- @Test
- public void sideFingerprintPowerWindowStartsOnAcquireStart() throws Exception {
- final int powerWindow = 500;
- final long authStart = 300;
-
- when(mSensorProps.isAnySidefpsType()).thenReturn(true);
- mContext.getOrCreateTestableResources().addOverride(
- R.integer.config_sidefpsBpPowerPressWindow, powerWindow);
-
- final FingerprintAuthenticationClient client = createClient(1);
- client.start(mCallback);
-
- // Acquire start occurs at time = 0ms
- when(mClock.millis()).thenReturn(0L);
- client.onAcquired(FingerprintManager.FINGERPRINT_ACQUIRED_START, 0 /* vendorCode */);
-
- // Auth occurs at time = 300
- when(mClock.millis()).thenReturn(authStart);
- // At this point the delay should be 500 - (300 - 0) == 200 milliseconds.
- client.onAuthenticated(new Fingerprint("friendly", 4 /* fingerId */, 5 /* deviceId */),
- true /* authenticated */, new ArrayList<>());
- mLooper.dispatchAll();
- verify(mCallback, never()).onClientFinished(any(), anyBoolean());
-
- // After waiting 200 milliseconds, auth should succeed.
- mLooper.moveTimeForward(powerWindow - authStart);
- mLooper.dispatchAll();
- verify(mCallback).onClientFinished(any(), eq(true));
- }
-
- @Test
- public void sideFingerprintPowerWindowStartsOnLastAcquireStart() throws Exception {
- final int powerWindow = 500;
-
- when(mSensorProps.isAnySidefpsType()).thenReturn(true);
- mContext.getOrCreateTestableResources().addOverride(
- R.integer.config_sidefpsBpPowerPressWindow, powerWindow);
-
- final FingerprintAuthenticationClient client = createClient(1);
- client.start(mCallback);
- // Acquire start occurs at time = 0ms
- when(mClock.millis()).thenReturn(0L);
- client.onAcquired(FingerprintManager.FINGERPRINT_ACQUIRED_START, 0 /* vendorCode */);
-
- // Auth reject occurs at time = 300ms
- when(mClock.millis()).thenReturn(300L);
- client.onAuthenticated(new Fingerprint("friendly", 4 /* fingerId */, 5 /* deviceId */),
- false /* authenticated */, new ArrayList<>());
- mLooper.dispatchAll();
-
- mLooper.moveTimeForward(300);
- mLooper.dispatchAll();
- verify(mCallback, never()).onClientFinished(any(), anyBoolean());
-
- when(mClock.millis()).thenReturn(1300L);
- client.onAcquired(FingerprintManager.FINGERPRINT_ACQUIRED_START, 0 /* vendorCode */);
-
- // If code is correct, the new acquired start timestamp should be used
- // and the code should only have to wait 500 - (1500-1300)ms.
- when(mClock.millis()).thenReturn(1500L);
- client.onAuthenticated(new Fingerprint("friendly", 4 /* fingerId */, 5 /* deviceId */),
- true /* authenticated */, new ArrayList<>());
- mLooper.dispatchAll();
-
- mLooper.moveTimeForward(299);
- mLooper.dispatchAll();
- verify(mCallback, never()).onClientFinished(any(), anyBoolean());
-
- mLooper.moveTimeForward(1);
- mLooper.dispatchAll();
- verify(mCallback).onClientFinished(any(), eq(true));
- }
-
- @Test
- public void sideFpsPowerPressCancelsIsntantly() throws Exception {
- when(mSensorProps.isAnySidefpsType()).thenReturn(true);
-
- final FingerprintAuthenticationClient client = createClient(1);
- client.start(mCallback);
-
- client.onPowerPressed();
- mLooper.dispatchAll();
-
- verify(mCallback, never()).onClientFinished(any(), eq(true));
- verify(mCallback).onClientFinished(any(), eq(false));
- }
-
private FingerprintAuthenticationClient createClient() throws RemoteException {
return createClient(100 /* version */, true /* allowBackgroundAuthentication */);
}
diff --git a/services/tests/servicestests/src/com/android/server/companion/datatransfer/contextsync/OWNERS b/services/tests/servicestests/src/com/android/server/companion/datatransfer/contextsync/OWNERS
new file mode 100644
index 0000000..008a53f
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/companion/datatransfer/contextsync/OWNERS
@@ -0,0 +1 @@
+include /services/companion/java/com/android/server/companion/OWNERS
\ No newline at end of file
diff --git a/services/tests/servicestests/src/com/android/server/companion/virtual/VirtualDeviceManagerServiceTest.java b/services/tests/servicestests/src/com/android/server/companion/virtual/VirtualDeviceManagerServiceTest.java
index 759b049..eb99e30 100644
--- a/services/tests/servicestests/src/com/android/server/companion/virtual/VirtualDeviceManagerServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/companion/virtual/VirtualDeviceManagerServiceTest.java
@@ -369,6 +369,21 @@
}
@Test
+ public void isDeviceIdValid_defaultDeviceId_returnsFalse() {
+ assertThat(mVdm.isValidVirtualDeviceId(DEVICE_ID_DEFAULT)).isFalse();
+ }
+
+ @Test
+ public void isDeviceIdValid_validVirtualDeviceId_returnsTrue() {
+ assertThat(mVdm.isValidVirtualDeviceId(mDeviceImpl.getDeviceId())).isTrue();
+ }
+
+ @Test
+ public void isDeviceIdValid_nonExistentDeviceId_returnsFalse() {
+ assertThat(mVdm.isValidVirtualDeviceId(mDeviceImpl.getDeviceId() + 1)).isFalse();
+ }
+
+ @Test
public void getDevicePolicy_invalidDeviceId_returnsDefault() {
assertThat(mVdm.getDevicePolicy(DEVICE_ID_INVALID, POLICY_TYPE_SENSORS))
.isEqualTo(DEVICE_POLICY_DEFAULT);
diff --git a/services/tests/servicestests/src/com/android/server/companion/virtual/VirtualDeviceParamsTest.java b/services/tests/servicestests/src/com/android/server/companion/virtual/VirtualDeviceParamsTest.java
index 3a27e3b..798650d 100644
--- a/services/tests/servicestests/src/com/android/server/companion/virtual/VirtualDeviceParamsTest.java
+++ b/services/tests/servicestests/src/com/android/server/companion/virtual/VirtualDeviceParamsTest.java
@@ -27,6 +27,7 @@
import android.companion.virtual.sensor.VirtualSensorConfig;
import android.os.Parcel;
import android.os.UserHandle;
+import android.platform.test.annotations.Presubmit;
import androidx.test.ext.junit.runners.AndroidJUnit4;
@@ -36,6 +37,7 @@
import java.util.List;
import java.util.Set;
+@Presubmit
@RunWith(AndroidJUnit4.class)
public class VirtualDeviceParamsTest {
diff --git a/services/tests/servicestests/src/com/android/server/companion/virtual/VirtualDeviceTest.java b/services/tests/servicestests/src/com/android/server/companion/virtual/VirtualDeviceTest.java
index f473086..bb28a36 100644
--- a/services/tests/servicestests/src/com/android/server/companion/virtual/VirtualDeviceTest.java
+++ b/services/tests/servicestests/src/com/android/server/companion/virtual/VirtualDeviceTest.java
@@ -25,12 +25,14 @@
import android.companion.virtual.VirtualDevice;
import android.os.Parcel;
+import android.platform.test.annotations.Presubmit;
import androidx.test.ext.junit.runners.AndroidJUnit4;
import org.junit.Test;
import org.junit.runner.RunWith;
+@Presubmit
@RunWith(AndroidJUnit4.class)
public class VirtualDeviceTest {
diff --git a/services/tests/servicestests/src/com/android/server/companion/virtual/audio/VirtualAudioControllerTest.java b/services/tests/servicestests/src/com/android/server/companion/virtual/audio/VirtualAudioControllerTest.java
index c270435..7b5af1e 100644
--- a/services/tests/servicestests/src/com/android/server/companion/virtual/audio/VirtualAudioControllerTest.java
+++ b/services/tests/servicestests/src/com/android/server/companion/virtual/audio/VirtualAudioControllerTest.java
@@ -36,9 +36,11 @@
import android.media.PlayerBase;
import android.os.Parcel;
import android.os.RemoteException;
+import android.platform.test.annotations.Presubmit;
import android.util.ArraySet;
import androidx.test.InstrumentationRegistry;
+import androidx.test.filters.FlakyTest;
import androidx.test.runner.AndroidJUnit4;
import com.android.server.companion.virtual.GenericWindowPolicyController;
@@ -53,6 +55,7 @@
import java.util.ArrayList;
import java.util.List;
+@Presubmit
@RunWith(AndroidJUnit4.class)
public class VirtualAudioControllerTest {
private static final int APP1_UID = 100;
@@ -92,6 +95,7 @@
}
+ @FlakyTest(bugId = 265155135)
@Test
public void startListening_receivesCallback() throws RemoteException {
ArraySet<Integer> runningUids = new ArraySet<>();
diff --git a/services/tests/servicestests/src/com/android/server/devicepolicy/MockSystemServices.java b/services/tests/servicestests/src/com/android/server/devicepolicy/MockSystemServices.java
index 2a6a979..4163f33 100644
--- a/services/tests/servicestests/src/com/android/server/devicepolicy/MockSystemServices.java
+++ b/services/tests/servicestests/src/com/android/server/devicepolicy/MockSystemServices.java
@@ -219,8 +219,10 @@
// Add the system user with a fake profile group already set up (this can happen in the real
// world if a managed profile is added and then removed).
- systemUserDataDir = addUser(UserHandle.USER_SYSTEM, UserInfo.FLAG_PRIMARY,
+ systemUserDataDir = addUser(UserHandle.USER_SYSTEM,
+ UserInfo.FLAG_PRIMARY | UserInfo.FLAG_MAIN,
UserManager.USER_TYPE_FULL_SYSTEM, UserHandle.USER_SYSTEM);
+ when(userManager.getMainUser()).thenReturn(UserHandle.SYSTEM);
// System user is always running.
setUserRunning(UserHandle.USER_SYSTEM, true);
diff --git a/services/tests/servicestests/src/com/android/server/display/DisplayManagerServiceTest.java b/services/tests/servicestests/src/com/android/server/display/DisplayManagerServiceTest.java
index f676a3f..2d252cb 100644
--- a/services/tests/servicestests/src/com/android/server/display/DisplayManagerServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/display/DisplayManagerServiceTest.java
@@ -39,6 +39,8 @@
import android.app.PropertyInvalidatedCache;
import android.companion.virtual.IVirtualDevice;
+import android.companion.virtual.IVirtualDeviceManager;
+import android.companion.virtual.VirtualDeviceManager;
import android.compat.testing.PlatformCompatChangeRule;
import android.content.Context;
import android.content.ContextWrapper;
@@ -173,6 +175,7 @@
private final DisplayManagerService.Injector mBasicInjector = new BasicInjector();
+ @Mock IVirtualDeviceManager mIVirtualDeviceManager;
@Mock InputManagerInternal mMockInputManagerInternal;
@Mock VirtualDeviceManagerInternal mMockVirtualDeviceManagerInternal;
@Mock IVirtualDisplayCallback.Stub mMockAppToken;
@@ -202,6 +205,8 @@
mContext = spy(new ContextWrapper(ApplicationProvider.getApplicationContext()));
+ VirtualDeviceManager vdm = new VirtualDeviceManager(mIVirtualDeviceManager, mContext);
+ when(mContext.getSystemService(VirtualDeviceManager.class)).thenReturn(vdm);
// Disable binder caches in this process.
PropertyInvalidatedCache.disableForTestMode();
setUpDisplay();
@@ -727,10 +732,8 @@
when(mMockAppToken.asBinder()).thenReturn(mMockAppToken);
IVirtualDevice virtualDevice = mock(IVirtualDevice.class);
- when(mMockVirtualDeviceManagerInternal.isValidVirtualDevice(virtualDevice))
- .thenReturn(true);
when(virtualDevice.getDeviceId()).thenReturn(1);
-
+ when(mIVirtualDeviceManager.isValidVirtualDeviceId(1)).thenReturn(true);
// Create a first virtual display. A display group should be created for this display on the
// virtual device.
final VirtualDisplayConfig.Builder builder1 =
@@ -780,9 +783,8 @@
when(mMockAppToken.asBinder()).thenReturn(mMockAppToken);
IVirtualDevice virtualDevice = mock(IVirtualDevice.class);
- when(mMockVirtualDeviceManagerInternal.isValidVirtualDevice(virtualDevice))
- .thenReturn(true);
when(virtualDevice.getDeviceId()).thenReturn(1);
+ when(mIVirtualDeviceManager.isValidVirtualDeviceId(1)).thenReturn(true);
// Create a first virtual display. A display group should be created for this display on the
// virtual device.
@@ -806,6 +808,8 @@
.setFlags(VIRTUAL_DISPLAY_FLAG_OWN_DISPLAY_GROUP)
.setUniqueId("uniqueId --- own display group");
+ when(mIVirtualDeviceManager.isValidVirtualDeviceId(1)).thenReturn(true);
+
int displayId2 =
localService.createVirtualDisplay(
builder2.build(),
@@ -832,9 +836,8 @@
when(mMockAppToken.asBinder()).thenReturn(mMockAppToken);
IVirtualDevice virtualDevice = mock(IVirtualDevice.class);
- when(mMockVirtualDeviceManagerInternal.isValidVirtualDevice(virtualDevice))
- .thenReturn(true);
when(virtualDevice.getDeviceId()).thenReturn(1);
+ when(mIVirtualDeviceManager.isValidVirtualDeviceId(1)).thenReturn(true);
// Allow an ALWAYS_UNLOCKED display to be created.
when(mContext.checkCallingPermission(ADD_TRUSTED_DISPLAY))
@@ -1062,7 +1065,7 @@
* a virtual device, even if ADD_TRUSTED_DISPLAY is not granted.
*/
@Test
- public void testOwnDisplayGroup_allowCreationWithVirtualDevice() {
+ public void testOwnDisplayGroup_allowCreationWithVirtualDevice() throws Exception {
DisplayManagerService displayManager =
new DisplayManagerService(mContext, mBasicInjector);
DisplayManagerInternal localService = displayManager.new LocalService();
@@ -1081,8 +1084,8 @@
builder.setUniqueId("uniqueId --- OWN_DISPLAY_GROUP");
IVirtualDevice virtualDevice = mock(IVirtualDevice.class);
- when(mMockVirtualDeviceManagerInternal.isValidVirtualDevice(virtualDevice))
- .thenReturn(true);
+ when(virtualDevice.getDeviceId()).thenReturn(1);
+ when(mIVirtualDeviceManager.isValidVirtualDeviceId(1)).thenReturn(true);
int displayId = localService.createVirtualDisplay(builder.build(),
mMockAppToken /* callback */, virtualDevice /* virtualDeviceToken */,
diff --git a/services/tests/servicestests/src/com/android/server/display/HbmEventTest.java b/services/tests/servicestests/src/com/android/server/display/HbmEventTest.java
new file mode 100644
index 0000000..24fc348
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/display/HbmEventTest.java
@@ -0,0 +1,57 @@
+/*
+ * 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 com.android.server.display;
+
+import static org.junit.Assert.assertEquals;
+
+
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public final class HbmEventTest {
+ private long mStartTimeMillis;
+ private long mEndTimeMillis;
+ private HbmEvent mHbmEvent;
+
+ @Before
+ public void setUp() {
+ mStartTimeMillis = 10;
+ mEndTimeMillis = 20;
+ mHbmEvent = new HbmEvent(mStartTimeMillis, mEndTimeMillis);
+ }
+
+ @Test
+ public void getCorrectValues() {
+ assertEquals(mHbmEvent.getStartTimeMillis(), mStartTimeMillis);
+ assertEquals(mHbmEvent.getEndTimeMillis(), mEndTimeMillis);
+ }
+
+ @Test
+ public void toStringGeneratesExpectedString() {
+ String actualString = mHbmEvent.toString();
+ String expectedString = "HbmEvent: {startTimeMillis:" + mStartTimeMillis
+ + ", endTimeMillis: " + mEndTimeMillis + "}, total: "
+ + ((mEndTimeMillis - mStartTimeMillis) / 1000) + "]";
+ assertEquals(actualString, expectedString);
+ }
+}
diff --git a/services/tests/servicestests/src/com/android/server/display/HighBrightnessModeControllerTest.java b/services/tests/servicestests/src/com/android/server/display/HighBrightnessModeControllerTest.java
index a1e5ce7..2655c3f 100644
--- a/services/tests/servicestests/src/com/android/server/display/HighBrightnessModeControllerTest.java
+++ b/services/tests/servicestests/src/com/android/server/display/HighBrightnessModeControllerTest.java
@@ -96,6 +96,7 @@
private Binder mDisplayToken;
private String mDisplayUniqueId;
private Context mContextSpy;
+ private HighBrightnessModeMetadata mHighBrightnessModeMetadata;
@Rule
public FakeSettingsProviderRule mSettingsProviderRule = FakeSettingsProvider.rule();
@@ -118,6 +119,7 @@
mTestLooper = new TestLooper(mClock::now);
mDisplayToken = null;
mDisplayUniqueId = "unique_id";
+
mContextSpy = spy(new ContextWrapper(ApplicationProvider.getApplicationContext()));
final MockContentResolver resolver = mSettingsProviderRule.mockContentResolver(mContextSpy);
when(mContextSpy.getContentResolver()).thenReturn(resolver);
@@ -134,7 +136,8 @@
initHandler(null);
final HighBrightnessModeController hbmc = new HighBrightnessModeController(
mInjectorMock, mHandler, DISPLAY_WIDTH, DISPLAY_HEIGHT, mDisplayToken,
- mDisplayUniqueId, DEFAULT_MIN, DEFAULT_MAX, null, null, () -> {}, mContextSpy);
+ mDisplayUniqueId, DEFAULT_MIN, DEFAULT_MAX, null, null, () -> {},
+ null, mContextSpy);
assertState(hbmc, DEFAULT_MIN, DEFAULT_MAX, HIGH_BRIGHTNESS_MODE_OFF);
assertEquals(hbmc.getTransitionPoint(), HBM_TRANSITION_POINT_INVALID, 0.0f);
}
@@ -144,7 +147,8 @@
initHandler(null);
final HighBrightnessModeController hbmc = new HighBrightnessModeController(
mInjectorMock, mHandler, DISPLAY_WIDTH, DISPLAY_HEIGHT, mDisplayToken,
- mDisplayUniqueId, DEFAULT_MIN, DEFAULT_MAX, null, null, () -> {}, mContextSpy);
+ mDisplayUniqueId, DEFAULT_MIN, DEFAULT_MAX, null, null, () -> {},
+ null, mContextSpy);
hbmc.setAutoBrightnessEnabled(AUTO_BRIGHTNESS_ENABLED);
hbmc.onAmbientLuxChange(MINIMUM_LUX - 1); // below allowed range
assertState(hbmc, DEFAULT_MIN, DEFAULT_MAX, HIGH_BRIGHTNESS_MODE_OFF);
@@ -699,9 +703,12 @@
// Creates instance with standard initialization values.
private HighBrightnessModeController createDefaultHbm(OffsettableClock clock) {
initHandler(clock);
+ if (mHighBrightnessModeMetadata == null) {
+ mHighBrightnessModeMetadata = new HighBrightnessModeMetadata();
+ }
return new HighBrightnessModeController(mInjectorMock, mHandler, DISPLAY_WIDTH,
DISPLAY_HEIGHT, mDisplayToken, mDisplayUniqueId, DEFAULT_MIN, DEFAULT_MAX,
- DEFAULT_HBM_DATA, null, () -> {}, mContextSpy);
+ DEFAULT_HBM_DATA, null, () -> {}, mHighBrightnessModeMetadata, mContextSpy);
}
private void initHandler(OffsettableClock clock) {
diff --git a/services/tests/servicestests/src/com/android/server/display/HighBrightnessModeMetadataTest.java b/services/tests/servicestests/src/com/android/server/display/HighBrightnessModeMetadataTest.java
new file mode 100644
index 0000000..ede54e0
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/display/HighBrightnessModeMetadataTest.java
@@ -0,0 +1,59 @@
+/*
+ * 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 com.android.server.display;
+
+import static org.junit.Assert.assertEquals;
+
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public final class HighBrightnessModeMetadataTest {
+ private HighBrightnessModeMetadata mHighBrightnessModeMetadata;
+
+ private long mRunningStartTimeMillis = -1;
+
+ @Before
+ public void setUp() {
+ mHighBrightnessModeMetadata = new HighBrightnessModeMetadata();
+ }
+
+ @Test
+ public void checkDefaultValues() {
+ assertEquals(mHighBrightnessModeMetadata.getRunningStartTimeMillis(),
+ mRunningStartTimeMillis);
+ assertEquals(mHighBrightnessModeMetadata.getHbmEventQueue().size(), 0);
+ }
+
+ @Test
+ public void checkSetValues() {
+ mRunningStartTimeMillis = 10;
+ mHighBrightnessModeMetadata.setRunningStartTimeMillis(mRunningStartTimeMillis);
+ assertEquals(mHighBrightnessModeMetadata.getRunningStartTimeMillis(),
+ mRunningStartTimeMillis);
+ HbmEvent expectedHbmEvent = new HbmEvent(10, 20);
+ mHighBrightnessModeMetadata.addHbmEvent(expectedHbmEvent);
+ HbmEvent actualHbmEvent = mHighBrightnessModeMetadata.getHbmEventQueue().peekFirst();
+ assertEquals(expectedHbmEvent.toString(), actualHbmEvent.toString());
+ }
+}
diff --git a/services/tests/servicestests/src/com/android/server/display/brightness/strategy/TemporaryBrightnessStrategyTest.java b/services/tests/servicestests/src/com/android/server/display/brightness/strategy/TemporaryBrightnessStrategyTest.java
index 4a32796..b92aa9c 100644
--- a/services/tests/servicestests/src/com/android/server/display/brightness/strategy/TemporaryBrightnessStrategyTest.java
+++ b/services/tests/servicestests/src/com/android/server/display/brightness/strategy/TemporaryBrightnessStrategyTest.java
@@ -59,8 +59,6 @@
DisplayBrightnessState updatedDisplayBrightnessState =
mTemporaryBrightnessStrategy.updateBrightness(displayPowerRequest);
assertEquals(updatedDisplayBrightnessState, expectedDisplayBrightnessState);
- assertEquals(mTemporaryBrightnessStrategy.getTemporaryScreenBrightness(),
- Float.NaN, 0.0f);
}
}
diff --git a/services/tests/servicestests/src/com/android/server/hdmi/ActiveSourceActionTest.java b/services/tests/servicestests/src/com/android/server/hdmi/ActiveSourceActionTest.java
index 112db76..ad1ecf1 100644
--- a/services/tests/servicestests/src/com/android/server/hdmi/ActiveSourceActionTest.java
+++ b/services/tests/servicestests/src/com/android/server/hdmi/ActiveSourceActionTest.java
@@ -88,6 +88,7 @@
Looper looper = mTestLooper.getLooper();
mHdmiControlService.setIoLooper(looper);
mHdmiControlService.setHdmiCecConfig(new FakeHdmiCecConfig(mContextSpy));
+ mHdmiControlService.setDeviceConfig(new FakeDeviceConfigWrapper());
mNativeWrapper = new FakeNativeWrapper();
HdmiCecController hdmiCecController = HdmiCecController.createWithNativeWrapper(
this.mHdmiControlService, mNativeWrapper, mHdmiControlService.getAtomWriter());
diff --git a/services/tests/servicestests/src/com/android/server/hdmi/ArcInitiationActionFromAvrTest.java b/services/tests/servicestests/src/com/android/server/hdmi/ArcInitiationActionFromAvrTest.java
index e4eecc6..3df0449 100644
--- a/services/tests/servicestests/src/com/android/server/hdmi/ArcInitiationActionFromAvrTest.java
+++ b/services/tests/servicestests/src/com/android/server/hdmi/ArcInitiationActionFromAvrTest.java
@@ -105,6 +105,7 @@
Looper looper = mTestLooper.getLooper();
hdmiControlService.setIoLooper(looper);
hdmiControlService.setHdmiCecConfig(new FakeHdmiCecConfig(mContextSpy));
+ hdmiControlService.setDeviceConfig(new FakeDeviceConfigWrapper());
mNativeWrapper = new FakeNativeWrapper();
HdmiCecController hdmiCecController = HdmiCecController.createWithNativeWrapper(
hdmiControlService, mNativeWrapper, hdmiControlService.getAtomWriter());
diff --git a/services/tests/servicestests/src/com/android/server/hdmi/ArcTerminationActionFromAvrTest.java b/services/tests/servicestests/src/com/android/server/hdmi/ArcTerminationActionFromAvrTest.java
index 2cb46da..61ab99b 100644
--- a/services/tests/servicestests/src/com/android/server/hdmi/ArcTerminationActionFromAvrTest.java
+++ b/services/tests/servicestests/src/com/android/server/hdmi/ArcTerminationActionFromAvrTest.java
@@ -101,6 +101,7 @@
Looper looper = mTestLooper.getLooper();
hdmiControlService.setIoLooper(looper);
hdmiControlService.setHdmiCecConfig(new FakeHdmiCecConfig(mContextSpy));
+ hdmiControlService.setDeviceConfig(new FakeDeviceConfigWrapper());
mNativeWrapper = new FakeNativeWrapper();
HdmiCecController hdmiCecController = HdmiCecController.createWithNativeWrapper(
hdmiControlService, mNativeWrapper, hdmiControlService.getAtomWriter());
diff --git a/services/tests/servicestests/src/com/android/server/hdmi/BaseAbsoluteVolumeControlTest.java b/services/tests/servicestests/src/com/android/server/hdmi/BaseAbsoluteVolumeControlTest.java
index 8ff87e3..93b151e 100644
--- a/services/tests/servicestests/src/com/android/server/hdmi/BaseAbsoluteVolumeControlTest.java
+++ b/services/tests/servicestests/src/com/android/server/hdmi/BaseAbsoluteVolumeControlTest.java
@@ -154,6 +154,7 @@
HdmiControlManager.CEC_SETTING_NAME_VOLUME_CONTROL_MODE,
HdmiControlManager.VOLUME_CONTROL_DISABLED);
mHdmiControlService.setHdmiCecConfig(mHdmiCecConfig);
+ mHdmiControlService.setDeviceConfig(new FakeDeviceConfigWrapper());
mNativeWrapper = new FakeNativeWrapper();
mNativeWrapper.setPhysicalAddress(getPhysicalAddress());
diff --git a/services/tests/servicestests/src/com/android/server/hdmi/DevicePowerStatusActionTest.java b/services/tests/servicestests/src/com/android/server/hdmi/DevicePowerStatusActionTest.java
index 3a57db9..c4c5c2a 100644
--- a/services/tests/servicestests/src/com/android/server/hdmi/DevicePowerStatusActionTest.java
+++ b/services/tests/servicestests/src/com/android/server/hdmi/DevicePowerStatusActionTest.java
@@ -104,6 +104,7 @@
Looper looper = mTestLooper.getLooper();
mHdmiControlService.setIoLooper(looper);
mHdmiControlService.setHdmiCecConfig(new FakeHdmiCecConfig(mContextSpy));
+ mHdmiControlService.setDeviceConfig(new FakeDeviceConfigWrapper());
mNativeWrapper = new FakeNativeWrapper();
HdmiCecController hdmiCecController = HdmiCecController.createWithNativeWrapper(
this.mHdmiControlService, mNativeWrapper, mHdmiControlService.getAtomWriter());
diff --git a/services/tests/servicestests/src/com/android/server/hdmi/DeviceSelectActionFromPlaybackTest.java b/services/tests/servicestests/src/com/android/server/hdmi/DeviceSelectActionFromPlaybackTest.java
index 6a899e8..b571f43 100644
--- a/services/tests/servicestests/src/com/android/server/hdmi/DeviceSelectActionFromPlaybackTest.java
+++ b/services/tests/servicestests/src/com/android/server/hdmi/DeviceSelectActionFromPlaybackTest.java
@@ -120,6 +120,7 @@
mHdmiControlService.setIoLooper(mMyLooper);
mHdmiControlService.setHdmiCecConfig(new FakeHdmiCecConfig(context));
+ mHdmiControlService.setDeviceConfig(new FakeDeviceConfigWrapper());
mNativeWrapper = new FakeNativeWrapper();
mHdmiCecController = HdmiCecController.createWithNativeWrapper(
mHdmiControlService, mNativeWrapper, mHdmiControlService.getAtomWriter());
diff --git a/services/tests/servicestests/src/com/android/server/hdmi/DeviceSelectActionFromTvTest.java b/services/tests/servicestests/src/com/android/server/hdmi/DeviceSelectActionFromTvTest.java
index 0419768..4d8d25a 100644
--- a/services/tests/servicestests/src/com/android/server/hdmi/DeviceSelectActionFromTvTest.java
+++ b/services/tests/servicestests/src/com/android/server/hdmi/DeviceSelectActionFromTvTest.java
@@ -129,6 +129,7 @@
mHdmiControlService.setIoLooper(mMyLooper);
mHdmiControlService.setHdmiCecConfig(new FakeHdmiCecConfig(context));
+ mHdmiControlService.setDeviceConfig(new FakeDeviceConfigWrapper());
mNativeWrapper = new FakeNativeWrapper();
mHdmiCecController = HdmiCecController.createWithNativeWrapper(
mHdmiControlService, mNativeWrapper, mHdmiControlService.getAtomWriter());
diff --git a/services/tests/servicestests/src/com/android/server/hdmi/FakeDeviceConfigWrapper.java b/services/tests/servicestests/src/com/android/server/hdmi/FakeDeviceConfigWrapper.java
new file mode 100644
index 0000000..8780329
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/hdmi/FakeDeviceConfigWrapper.java
@@ -0,0 +1,38 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.hdmi;
+
+import android.provider.DeviceConfig;
+
+import java.util.concurrent.Executor;
+
+/**
+ * Fake class which stubs DeviceConfigWrapper (useful for testing).
+ */
+public class FakeDeviceConfigWrapper extends DeviceConfigWrapper {
+
+ // Set all boolean flags to true such that all unit tests are running with enabled features.
+ @Override
+ boolean getBoolean(String name, boolean defaultValue) {
+ return true;
+ }
+
+ @Override
+ void addOnPropertiesChangedListener(Executor mainExecutor,
+ DeviceConfig.OnPropertiesChangedListener onPropertiesChangedListener) {
+ }
+}
diff --git a/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecAtomLoggingTest.java b/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecAtomLoggingTest.java
index d2fe6da..f27587e 100644
--- a/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecAtomLoggingTest.java
+++ b/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecAtomLoggingTest.java
@@ -114,6 +114,7 @@
mHdmiCecNetwork = new HdmiCecNetwork(mHdmiControlServiceSpy,
mHdmiCecController, mHdmiMhlControllerStub);
mHdmiControlServiceSpy.setHdmiCecNetwork(mHdmiCecNetwork);
+ mHdmiControlServiceSpy.setDeviceConfig(new FakeDeviceConfigWrapper());
HdmiPortInfo[] hdmiPortInfos = new HdmiPortInfo[1];
hdmiPortInfos[0] =
diff --git a/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecControllerTest.java b/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecControllerTest.java
index 367f41d..a7232fe 100644
--- a/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecControllerTest.java
+++ b/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecControllerTest.java
@@ -108,6 +108,7 @@
doAnswer(__ -> mCecVersion).when(mHdmiControlServiceSpy).getCecVersion();
doNothing().when(mHdmiControlServiceSpy)
.writeStringSystemProperty(anyString(), anyString());
+ mHdmiControlServiceSpy.setDeviceConfig(new FakeDeviceConfigWrapper());
mNativeWrapper = new FakeNativeWrapper();
mHdmiCecController = HdmiCecController.createWithNativeWrapper(
diff --git a/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecLocalDeviceAudioSystemTest.java b/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecLocalDeviceAudioSystemTest.java
index de2c218..90acc99 100644
--- a/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecLocalDeviceAudioSystemTest.java
+++ b/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecLocalDeviceAudioSystemTest.java
@@ -175,6 +175,7 @@
HdmiControlManager.VOLUME_CONTROL_ENABLED);
mMyLooper = mTestLooper.getLooper();
mHdmiControlService.setHdmiCecConfig(new FakeHdmiCecConfig(context));
+ mHdmiControlService.setDeviceConfig(new FakeDeviceConfigWrapper());
mHdmiCecLocalDeviceAudioSystem = new HdmiCecLocalDeviceAudioSystem(mHdmiControlService);
mHdmiCecLocalDevicePlayback = new HdmiCecLocalDevicePlayback(mHdmiControlService) {
@Override
diff --git a/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecLocalDevicePlaybackTest.java b/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecLocalDevicePlaybackTest.java
index 3ed8983..dfab207 100644
--- a/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecLocalDevicePlaybackTest.java
+++ b/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecLocalDevicePlaybackTest.java
@@ -141,6 +141,7 @@
};
mHdmiControlService.setHdmiCecConfig(new FakeHdmiCecConfig(context));
+ mHdmiControlService.setDeviceConfig(new FakeDeviceConfigWrapper());
mHdmiControlService.setIoLooper(mMyLooper);
mNativeWrapper = new FakeNativeWrapper();
mHdmiCecController = HdmiCecController.createWithNativeWrapper(
diff --git a/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecLocalDeviceTest.java b/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecLocalDeviceTest.java
index b30118c..3796ce9 100644
--- a/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecLocalDeviceTest.java
+++ b/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecLocalDeviceTest.java
@@ -179,6 +179,7 @@
};
mHdmiControlService.setIoLooper(mTestLooper.getLooper());
mHdmiControlService.setHdmiCecConfig(new FakeHdmiCecConfig(context));
+ mHdmiControlService.setDeviceConfig(new FakeDeviceConfigWrapper());
mNativeWrapper = new FakeNativeWrapper();
mHdmiCecController = HdmiCecController.createWithNativeWrapper(
mHdmiControlService, mNativeWrapper, mHdmiControlService.getAtomWriter());
diff --git a/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecLocalDeviceTvTest.java b/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecLocalDeviceTvTest.java
index 5dd29fd..233fd6e 100644
--- a/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecLocalDeviceTvTest.java
+++ b/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecLocalDeviceTvTest.java
@@ -180,6 +180,7 @@
mHdmiControlService.setIoLooper(mMyLooper);
mHdmiControlService.setHdmiCecConfig(new FakeHdmiCecConfig(context));
+ mHdmiControlService.setDeviceConfig(new FakeDeviceConfigWrapper());
mNativeWrapper = new FakeNativeWrapper();
mHdmiCecController = HdmiCecController.createWithNativeWrapper(
mHdmiControlService, mNativeWrapper, mHdmiControlService.getAtomWriter());
diff --git a/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecPowerStatusControllerTest.java b/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecPowerStatusControllerTest.java
index 4e5336e..8e5bb13 100644
--- a/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecPowerStatusControllerTest.java
+++ b/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecPowerStatusControllerTest.java
@@ -91,6 +91,7 @@
mHdmiControlService.setIoLooper(myLooper);
mHdmiControlService.setHdmiCecConfig(new FakeHdmiCecConfig(contextSpy));
+ mHdmiControlService.setDeviceConfig(new FakeDeviceConfigWrapper());
mNativeWrapper = new FakeNativeWrapper();
HdmiCecController hdmiCecController = HdmiCecController.createWithNativeWrapper(
mHdmiControlService, mNativeWrapper, mHdmiControlService.getAtomWriter());
diff --git a/services/tests/servicestests/src/com/android/server/hdmi/HdmiControlServiceTest.java b/services/tests/servicestests/src/com/android/server/hdmi/HdmiControlServiceTest.java
index aa49a62..6c77405 100644
--- a/services/tests/servicestests/src/com/android/server/hdmi/HdmiControlServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/hdmi/HdmiControlServiceTest.java
@@ -119,6 +119,7 @@
mHdmiControlServiceSpy.setIoLooper(mMyLooper);
mHdmiControlServiceSpy.setHdmiCecConfig(hdmiCecConfig);
+ mHdmiControlServiceSpy.setDeviceConfig(new FakeDeviceConfigWrapper());
mHdmiControlServiceSpy.onBootPhase(PHASE_SYSTEM_SERVICES_READY);
mNativeWrapper = new FakeNativeWrapper();
diff --git a/services/tests/servicestests/src/com/android/server/hdmi/HdmiEarcLocalDeviceTxTest.java b/services/tests/servicestests/src/com/android/server/hdmi/HdmiEarcLocalDeviceTxTest.java
index bf44e09..c79e219 100644
--- a/services/tests/servicestests/src/com/android/server/hdmi/HdmiEarcLocalDeviceTxTest.java
+++ b/services/tests/servicestests/src/com/android/server/hdmi/HdmiEarcLocalDeviceTxTest.java
@@ -121,6 +121,7 @@
mHdmiControlService.setIoLooper(mMyLooper);
mHdmiControlService.setHdmiCecConfig(new FakeHdmiCecConfig(context));
+ mHdmiControlService.setDeviceConfig(new FakeDeviceConfigWrapper());
mNativeWrapper = new FakeNativeWrapper();
mHdmiCecController = HdmiCecController.createWithNativeWrapper(
mHdmiControlService, mNativeWrapper, mHdmiControlService.getAtomWriter());
diff --git a/services/tests/servicestests/src/com/android/server/hdmi/OneTouchPlayActionTest.java b/services/tests/servicestests/src/com/android/server/hdmi/OneTouchPlayActionTest.java
index 9b8cedf..b0e8ca7 100644
--- a/services/tests/servicestests/src/com/android/server/hdmi/OneTouchPlayActionTest.java
+++ b/services/tests/servicestests/src/com/android/server/hdmi/OneTouchPlayActionTest.java
@@ -120,6 +120,7 @@
mNativeWrapper = new FakeNativeWrapper();
HdmiCecController hdmiCecController = HdmiCecController.createWithNativeWrapper(
this.mHdmiControlService, mNativeWrapper, mHdmiControlService.getAtomWriter());
+ mHdmiControlService.setDeviceConfig(new FakeDeviceConfigWrapper());
mHdmiControlService.setCecController(hdmiCecController);
mHdmiControlService.setHdmiMhlController(HdmiMhlControllerStub.create(mHdmiControlService));
mHdmiControlService.initService();
diff --git a/services/tests/servicestests/src/com/android/server/hdmi/PowerStatusMonitorActionTest.java b/services/tests/servicestests/src/com/android/server/hdmi/PowerStatusMonitorActionTest.java
index f72ac71..a623841 100644
--- a/services/tests/servicestests/src/com/android/server/hdmi/PowerStatusMonitorActionTest.java
+++ b/services/tests/servicestests/src/com/android/server/hdmi/PowerStatusMonitorActionTest.java
@@ -93,6 +93,7 @@
Looper looper = mTestLooper.getLooper();
mHdmiControlService.setIoLooper(looper);
mHdmiControlService.setHdmiCecConfig(new FakeHdmiCecConfig(mContextSpy));
+ mHdmiControlService.setDeviceConfig(new FakeDeviceConfigWrapper());
mNativeWrapper = new FakeNativeWrapper();
HdmiCecController hdmiCecController = HdmiCecController.createWithNativeWrapper(
this.mHdmiControlService, mNativeWrapper, mHdmiControlService.getAtomWriter());
diff --git a/services/tests/servicestests/src/com/android/server/hdmi/RequestSadActionTest.java b/services/tests/servicestests/src/com/android/server/hdmi/RequestSadActionTest.java
index f719ca1..1c19341 100644
--- a/services/tests/servicestests/src/com/android/server/hdmi/RequestSadActionTest.java
+++ b/services/tests/servicestests/src/com/android/server/hdmi/RequestSadActionTest.java
@@ -116,6 +116,7 @@
mHdmiControlService.setIoLooper(mMyLooper);
mHdmiControlService.setHdmiCecConfig(new FakeHdmiCecConfig(context));
+ mHdmiControlService.setDeviceConfig(new FakeDeviceConfigWrapper());
mNativeWrapper = new FakeNativeWrapper();
mHdmiCecController = HdmiCecController.createWithNativeWrapper(
mHdmiControlService, mNativeWrapper, mHdmiControlService.getAtomWriter());
diff --git a/services/tests/servicestests/src/com/android/server/hdmi/RoutingControlActionTest.java b/services/tests/servicestests/src/com/android/server/hdmi/RoutingControlActionTest.java
index be62df8..4e8cf4a 100644
--- a/services/tests/servicestests/src/com/android/server/hdmi/RoutingControlActionTest.java
+++ b/services/tests/servicestests/src/com/android/server/hdmi/RoutingControlActionTest.java
@@ -175,6 +175,7 @@
mNativeWrapper = new FakeNativeWrapper();
mHdmiCecController = HdmiCecController.createWithNativeWrapper(
mHdmiControlService, mNativeWrapper, mHdmiControlService.getAtomWriter());
+ mHdmiControlService.setDeviceConfig(new FakeDeviceConfigWrapper());
mHdmiControlService.setCecController(mHdmiCecController);
mHdmiControlService.setHdmiMhlController(HdmiMhlControllerStub.create(mHdmiControlService));
HdmiPortInfo[] hdmiPortInfos = new HdmiPortInfo[1];
diff --git a/services/tests/servicestests/src/com/android/server/hdmi/SetAudioVolumeLevelDiscoveryActionTest.java b/services/tests/servicestests/src/com/android/server/hdmi/SetAudioVolumeLevelDiscoveryActionTest.java
index e3c8939..cac7815 100644
--- a/services/tests/servicestests/src/com/android/server/hdmi/SetAudioVolumeLevelDiscoveryActionTest.java
+++ b/services/tests/servicestests/src/com/android/server/hdmi/SetAudioVolumeLevelDiscoveryActionTest.java
@@ -89,6 +89,7 @@
mLooper = mTestLooper.getLooper();
mHdmiControlServiceSpy.setIoLooper(mLooper);
mHdmiControlServiceSpy.setHdmiCecConfig(new FakeHdmiCecConfig(mContextSpy));
+ mHdmiControlServiceSpy.setDeviceConfig(new FakeDeviceConfigWrapper());
mNativeWrapper = new FakeNativeWrapper();
mNativeWrapper.setPhysicalAddress(mPhysicalAddress);
diff --git a/services/tests/servicestests/src/com/android/server/hdmi/SystemAudioAutoInitiationActionTest.java b/services/tests/servicestests/src/com/android/server/hdmi/SystemAudioAutoInitiationActionTest.java
index e7557fe..70f9e5c 100644
--- a/services/tests/servicestests/src/com/android/server/hdmi/SystemAudioAutoInitiationActionTest.java
+++ b/services/tests/servicestests/src/com/android/server/hdmi/SystemAudioAutoInitiationActionTest.java
@@ -97,6 +97,7 @@
mNativeWrapper = new FakeNativeWrapper();
HdmiCecController hdmiCecController = HdmiCecController.createWithNativeWrapper(
mHdmiControlService, mNativeWrapper, mHdmiControlService.getAtomWriter());
+ mHdmiControlService.setDeviceConfig(new FakeDeviceConfigWrapper());
mHdmiControlService.setCecController(hdmiCecController);
mHdmiControlService.setHdmiMhlController(HdmiMhlControllerStub.create(mHdmiControlService));
HdmiPortInfo[] hdmiPortInfos = new HdmiPortInfo[2];
diff --git a/services/tests/servicestests/src/com/android/server/hdmi/SystemAudioInitiationActionFromAvrTest.java b/services/tests/servicestests/src/com/android/server/hdmi/SystemAudioInitiationActionFromAvrTest.java
index c2f706a..b13ef4f 100644
--- a/services/tests/servicestests/src/com/android/server/hdmi/SystemAudioInitiationActionFromAvrTest.java
+++ b/services/tests/servicestests/src/com/android/server/hdmi/SystemAudioInitiationActionFromAvrTest.java
@@ -168,6 +168,7 @@
Looper looper = mTestLooper.getLooper();
hdmiControlService.setIoLooper(looper);
hdmiControlService.setHdmiCecConfig(new FakeHdmiCecConfig(context));
+ hdmiControlService.setDeviceConfig(new FakeDeviceConfigWrapper());
HdmiCecController.NativeWrapper nativeWrapper = new FakeNativeWrapper();
HdmiCecController hdmiCecController = HdmiCecController.createWithNativeWrapper(
hdmiControlService, nativeWrapper, hdmiControlService.getAtomWriter());
diff --git a/services/tests/servicestests/src/com/android/server/input/BatteryControllerTests.kt b/services/tests/servicestests/src/com/android/server/input/BatteryControllerTests.kt
index ecd9d89..3ce747f 100644
--- a/services/tests/servicestests/src/com/android/server/input/BatteryControllerTests.kt
+++ b/services/tests/servicestests/src/com/android/server/input/BatteryControllerTests.kt
@@ -16,7 +16,9 @@
package com.android.server.input
+import android.bluetooth.BluetoothAdapter
import android.bluetooth.BluetoothDevice
+import android.bluetooth.BluetoothManager
import android.content.Context
import android.content.ContextWrapper
import android.hardware.BatteryState.STATUS_CHARGING
@@ -246,6 +248,11 @@
notifyDeviceChanged(deviceId, hasBattery, supportsUsi)
}
+ private fun createBluetoothDevice(address: String): BluetoothDevice {
+ return context.getSystemService(BluetoothManager::class.java)!!
+ .adapter.getRemoteDevice(address)
+ }
+
@After
fun tearDown() {
InputManager.clearInstance()
@@ -656,29 +663,31 @@
addInputDevice(SECOND_BT_DEVICE_ID)
testLooper.dispatchNext()
- // Ensure that a BT battery listener is not added when there are no monitored BT devices.
- verify(bluetoothBatteryManager, never()).addListener(any())
+ // Listen to a non-Bluetooth device and ensure that the BT battery listener is not added
+ // when there are no monitored BT devices.
+ val listener = createMockListener()
+ batteryController.registerBatteryListener(DEVICE_ID, listener, PID)
+ verify(bluetoothBatteryManager, never()).addBatteryListener(any())
val bluetoothListener = ArgumentCaptor.forClass(BluetoothBatteryListener::class.java)
- val listener = createMockListener()
// The BT battery listener is added when the first BT input device is monitored.
batteryController.registerBatteryListener(BT_DEVICE_ID, listener, PID)
- verify(bluetoothBatteryManager).addListener(bluetoothListener.capture())
+ verify(bluetoothBatteryManager).addBatteryListener(bluetoothListener.capture())
// The BT listener is only added once for all BT devices.
batteryController.registerBatteryListener(SECOND_BT_DEVICE_ID, listener, PID)
- verify(bluetoothBatteryManager, times(1)).addListener(any())
+ verify(bluetoothBatteryManager, times(1)).addBatteryListener(any())
// The BT listener is only removed when there are no monitored BT devices.
batteryController.unregisterBatteryListener(BT_DEVICE_ID, listener, PID)
- verify(bluetoothBatteryManager, never()).removeListener(any())
+ verify(bluetoothBatteryManager, never()).removeBatteryListener(any())
`when`(iInputManager.getInputDeviceBluetoothAddress(SECOND_BT_DEVICE_ID))
.thenReturn(null)
notifyDeviceChanged(SECOND_BT_DEVICE_ID)
testLooper.dispatchNext()
- verify(bluetoothBatteryManager).removeListener(bluetoothListener.value)
+ verify(bluetoothBatteryManager).removeBatteryListener(bluetoothListener.value)
}
@Test
@@ -690,15 +699,14 @@
val bluetoothListener = ArgumentCaptor.forClass(BluetoothBatteryListener::class.java)
val listener = createMockListener()
batteryController.registerBatteryListener(BT_DEVICE_ID, listener, PID)
- verify(bluetoothBatteryManager).addListener(bluetoothListener.capture())
+ verify(bluetoothBatteryManager).addBatteryListener(bluetoothListener.capture())
listener.verifyNotified(BT_DEVICE_ID, capacity = 0.21f)
// When the state has not changed, the listener is not notified again.
- bluetoothListener.value!!.onBluetoothBatteryChanged(TIMESTAMP, "AA:BB:CC:DD:EE:FF")
+ bluetoothListener.value!!.onBluetoothBatteryChanged(TIMESTAMP, "AA:BB:CC:DD:EE:FF", 21)
listener.verifyNotified(BT_DEVICE_ID, mode = times(1), capacity = 0.21f)
- `when`(bluetoothBatteryManager.getBatteryLevel(eq("AA:BB:CC:DD:EE:FF"))).thenReturn(25)
- bluetoothListener.value!!.onBluetoothBatteryChanged(TIMESTAMP, "AA:BB:CC:DD:EE:FF")
+ bluetoothListener.value!!.onBluetoothBatteryChanged(TIMESTAMP, "AA:BB:CC:DD:EE:FF", 25)
listener.verifyNotified(BT_DEVICE_ID, capacity = 0.25f)
}
@@ -717,7 +725,7 @@
// When the device is first monitored and both native and BT battery is available,
// the latter is used.
batteryController.registerBatteryListener(BT_DEVICE_ID, listener, PID)
- verify(bluetoothBatteryManager).addListener(bluetoothListener.capture())
+ verify(bluetoothBatteryManager).addBatteryListener(bluetoothListener.capture())
verify(uEventManager).addListener(uEventListener.capture(), any())
listener.verifyNotified(BT_DEVICE_ID, capacity = 0.21f)
assertThat("battery state matches", batteryController.getBatteryState(BT_DEVICE_ID),
@@ -744,25 +752,144 @@
val uEventListener = ArgumentCaptor.forClass(UEventBatteryListener::class.java)
batteryController.registerBatteryListener(BT_DEVICE_ID, listener, PID)
- verify(bluetoothBatteryManager).addListener(bluetoothListener.capture())
+ verify(bluetoothBatteryManager).addBatteryListener(bluetoothListener.capture())
verify(uEventManager).addListener(uEventListener.capture(), any())
listener.verifyNotified(BT_DEVICE_ID, capacity = 0.21f)
// Fall back to the native state when BT is off.
- `when`(bluetoothBatteryManager.getBatteryLevel(eq("AA:BB:CC:DD:EE:FF")))
- .thenReturn(BluetoothDevice.BATTERY_LEVEL_BLUETOOTH_OFF)
- bluetoothListener.value!!.onBluetoothBatteryChanged(TIMESTAMP, "AA:BB:CC:DD:EE:FF")
+ bluetoothListener.value!!.onBluetoothBatteryChanged(TIMESTAMP, "AA:BB:CC:DD:EE:FF",
+ BluetoothDevice.BATTERY_LEVEL_BLUETOOTH_OFF)
listener.verifyNotified(BT_DEVICE_ID, capacity = 0.98f)
- `when`(bluetoothBatteryManager.getBatteryLevel(eq("AA:BB:CC:DD:EE:FF"))).thenReturn(22)
- bluetoothListener.value!!.onBluetoothBatteryChanged(TIMESTAMP, "AA:BB:CC:DD:EE:FF")
- verify(bluetoothBatteryManager).addListener(bluetoothListener.capture())
+ bluetoothListener.value!!.onBluetoothBatteryChanged(TIMESTAMP, "AA:BB:CC:DD:EE:FF", 22)
+ verify(bluetoothBatteryManager).addBatteryListener(bluetoothListener.capture())
listener.verifyNotified(BT_DEVICE_ID, capacity = 0.22f)
// Fall back to the native state when BT battery is unknown.
- `when`(bluetoothBatteryManager.getBatteryLevel(eq("AA:BB:CC:DD:EE:FF")))
- .thenReturn(BluetoothDevice.BATTERY_LEVEL_UNKNOWN)
- bluetoothListener.value!!.onBluetoothBatteryChanged(TIMESTAMP, "AA:BB:CC:DD:EE:FF")
+ bluetoothListener.value!!.onBluetoothBatteryChanged(TIMESTAMP, "AA:BB:CC:DD:EE:FF",
+ BluetoothDevice.BATTERY_LEVEL_UNKNOWN)
listener.verifyNotified(BT_DEVICE_ID, mode = times(2), capacity = 0.98f)
}
+
+ @Test
+ fun testRegisterBluetoothMetadataListenerForMonitoredBluetoothDevices() {
+ `when`(iInputManager.getInputDeviceBluetoothAddress(BT_DEVICE_ID))
+ .thenReturn("AA:BB:CC:DD:EE:FF")
+ `when`(iInputManager.getInputDeviceBluetoothAddress(SECOND_BT_DEVICE_ID))
+ .thenReturn("11:22:33:44:55:66")
+ addInputDevice(BT_DEVICE_ID)
+ testLooper.dispatchNext()
+ addInputDevice(SECOND_BT_DEVICE_ID)
+ testLooper.dispatchNext()
+
+ // Listen to a non-Bluetooth device and ensure that the metadata listener is not added when
+ // there are no monitored BT devices.
+ val listener = createMockListener()
+ batteryController.registerBatteryListener(DEVICE_ID, listener, PID)
+ verify(bluetoothBatteryManager, never()).addMetadataListener(any(), any())
+
+ val metadataListener1 = ArgumentCaptor.forClass(
+ BluetoothAdapter.OnMetadataChangedListener::class.java)
+ val metadataListener2 = ArgumentCaptor.forClass(
+ BluetoothAdapter.OnMetadataChangedListener::class.java)
+
+ // The metadata listener is added when the first BT input device is monitored.
+ batteryController.registerBatteryListener(BT_DEVICE_ID, listener, PID)
+ verify(bluetoothBatteryManager)
+ .addMetadataListener(eq("AA:BB:CC:DD:EE:FF"), metadataListener1.capture())
+
+ // There is one metadata listener added for each BT device.
+ batteryController.registerBatteryListener(SECOND_BT_DEVICE_ID, listener, PID)
+ verify(bluetoothBatteryManager)
+ .addMetadataListener(eq("11:22:33:44:55:66"), metadataListener2.capture())
+
+ // The metadata listener is removed when the device is no longer monitored.
+ batteryController.unregisterBatteryListener(BT_DEVICE_ID, listener, PID)
+ verify(bluetoothBatteryManager)
+ .removeMetadataListener("AA:BB:CC:DD:EE:FF", metadataListener1.value)
+
+ `when`(iInputManager.getInputDeviceBluetoothAddress(SECOND_BT_DEVICE_ID))
+ .thenReturn(null)
+ notifyDeviceChanged(SECOND_BT_DEVICE_ID)
+ testLooper.dispatchNext()
+ verify(bluetoothBatteryManager)
+ .removeMetadataListener("11:22:33:44:55:66", metadataListener2.value)
+ }
+
+ @Test
+ fun testNotifiesBluetoothMetadataBatteryChanges() {
+ `when`(iInputManager.getInputDeviceBluetoothAddress(BT_DEVICE_ID))
+ .thenReturn("AA:BB:CC:DD:EE:FF")
+ `when`(bluetoothBatteryManager.getMetadata("AA:BB:CC:DD:EE:FF",
+ BluetoothDevice.METADATA_MAIN_BATTERY))
+ .thenReturn("21".toByteArray())
+ addInputDevice(BT_DEVICE_ID)
+ val metadataListener = ArgumentCaptor.forClass(
+ BluetoothAdapter.OnMetadataChangedListener::class.java)
+ val listener = createMockListener()
+ val bluetoothDevice = createBluetoothDevice("AA:BB:CC:DD:EE:FF")
+ batteryController.registerBatteryListener(BT_DEVICE_ID, listener, PID)
+ verify(bluetoothBatteryManager)
+ .addMetadataListener(eq("AA:BB:CC:DD:EE:FF"), metadataListener.capture())
+ listener.verifyNotified(BT_DEVICE_ID, capacity = 0.21f, status = STATUS_UNKNOWN)
+
+ // When the state has not changed, the listener is not notified again.
+ metadataListener.value!!.onMetadataChanged(
+ bluetoothDevice, BluetoothDevice.METADATA_MAIN_BATTERY, "21".toByteArray())
+ listener.verifyNotified(BT_DEVICE_ID, mode = times(1), capacity = 0.21f)
+
+ metadataListener.value!!.onMetadataChanged(
+ bluetoothDevice, BluetoothDevice.METADATA_MAIN_BATTERY, "25".toByteArray())
+ listener.verifyNotified(BT_DEVICE_ID, capacity = 0.25f, status = STATUS_UNKNOWN)
+
+ metadataListener.value!!.onMetadataChanged(
+ bluetoothDevice, BluetoothDevice.METADATA_MAIN_CHARGING, "true".toByteArray())
+ listener.verifyNotified(BT_DEVICE_ID, capacity = 0.25f, status = STATUS_CHARGING)
+
+ metadataListener.value!!.onMetadataChanged(
+ bluetoothDevice, BluetoothDevice.METADATA_MAIN_CHARGING, "false".toByteArray())
+ listener.verifyNotified(BT_DEVICE_ID, capacity = 0.25f, status = STATUS_DISCHARGING)
+
+ metadataListener.value!!.onMetadataChanged(
+ bluetoothDevice, BluetoothDevice.METADATA_MAIN_CHARGING, null)
+ listener.verifyNotified(BT_DEVICE_ID, mode = times(2), capacity = 0.25f,
+ status = STATUS_UNKNOWN)
+ }
+
+ @Test
+ fun testBluetoothMetadataBatteryIsPrioritized() {
+ `when`(iInputManager.getInputDeviceBluetoothAddress(BT_DEVICE_ID))
+ .thenReturn("AA:BB:CC:DD:EE:FF")
+ `when`(bluetoothBatteryManager.getBatteryLevel(eq("AA:BB:CC:DD:EE:FF"))).thenReturn(21)
+ `when`(bluetoothBatteryManager.getMetadata("AA:BB:CC:DD:EE:FF",
+ BluetoothDevice.METADATA_MAIN_BATTERY))
+ .thenReturn("22".toByteArray())
+ addInputDevice(BT_DEVICE_ID)
+ val bluetoothListener = ArgumentCaptor.forClass(BluetoothBatteryListener::class.java)
+ val metadataListener = ArgumentCaptor.forClass(
+ BluetoothAdapter.OnMetadataChangedListener::class.java)
+ val listener = createMockListener()
+ val bluetoothDevice = createBluetoothDevice("AA:BB:CC:DD:EE:FF")
+ batteryController.registerBatteryListener(BT_DEVICE_ID, listener, PID)
+
+ verify(bluetoothBatteryManager).addBatteryListener(bluetoothListener.capture())
+ verify(bluetoothBatteryManager)
+ .addMetadataListener(eq("AA:BB:CC:DD:EE:FF"), metadataListener.capture())
+ listener.verifyNotified(BT_DEVICE_ID, capacity = 0.22f)
+
+ // A change in the Bluetooth battery level has no effect while there is a valid battery
+ // level obtained through the metadata.
+ bluetoothListener.value!!.onBluetoothBatteryChanged(TIMESTAMP, "AA:BB:CC:DD:EE:FF", 23)
+ listener.verifyNotified(BT_DEVICE_ID, mode = never(), capacity = 0.23f)
+
+ metadataListener.value!!.onMetadataChanged(
+ bluetoothDevice, BluetoothDevice.METADATA_MAIN_BATTERY, "24".toByteArray())
+ listener.verifyNotified(BT_DEVICE_ID, capacity = 0.24f)
+
+ // When the battery level from the metadata is no longer valid, we fall back to using the
+ // Bluetooth battery level.
+ metadataListener.value!!.onMetadataChanged(
+ bluetoothDevice, BluetoothDevice.METADATA_MAIN_BATTERY, null)
+ listener.verifyNotified(BT_DEVICE_ID, capacity = 0.23f)
+ }
}
diff --git a/services/tests/servicestests/src/com/android/server/input/KeyRemapperTests.kt b/services/tests/servicestests/src/com/android/server/input/KeyRemapperTests.kt
index c22782c..705a5da 100644
--- a/services/tests/servicestests/src/com/android/server/input/KeyRemapperTests.kt
+++ b/services/tests/servicestests/src/com/android/server/input/KeyRemapperTests.kt
@@ -22,6 +22,7 @@
import android.hardware.input.InputManager
import android.os.test.TestLooper
import android.platform.test.annotations.Presubmit
+import android.provider.Settings
import android.view.InputDevice
import android.view.KeyEvent
import androidx.test.core.app.ApplicationProvider
@@ -113,38 +114,75 @@
}
@Test
- fun testKeyRemapping() {
- val keyboard = createKeyboard(DEVICE_ID)
- Mockito.`when`(iInputManager.getInputDevice(DEVICE_ID)).thenReturn(keyboard)
+ fun testKeyRemapping_whenRemappingEnabled() {
+ ModifierRemappingFlag(true).use {
+ val keyboard = createKeyboard(DEVICE_ID)
+ Mockito.`when`(iInputManager.getInputDevice(DEVICE_ID)).thenReturn(keyboard)
- for (i in REMAPPABLE_KEYS.indices) {
- val fromKeyCode = REMAPPABLE_KEYS[i]
- val toKeyCode = REMAPPABLE_KEYS[(i + 1) % REMAPPABLE_KEYS.size]
- mKeyRemapper.remapKey(fromKeyCode, toKeyCode)
+ for (i in REMAPPABLE_KEYS.indices) {
+ val fromKeyCode = REMAPPABLE_KEYS[i]
+ val toKeyCode = REMAPPABLE_KEYS[(i + 1) % REMAPPABLE_KEYS.size]
+ mKeyRemapper.remapKey(fromKeyCode, toKeyCode)
+ testLooper.dispatchNext()
+ }
+
+ val remapping = mKeyRemapper.keyRemapping
+ val expectedSize = REMAPPABLE_KEYS.size
+ assertEquals("Remapping size should be $expectedSize", expectedSize, remapping.size)
+
+ for (i in REMAPPABLE_KEYS.indices) {
+ val fromKeyCode = REMAPPABLE_KEYS[i]
+ val toKeyCode = REMAPPABLE_KEYS[(i + 1) % REMAPPABLE_KEYS.size]
+ assertEquals(
+ "Remapping should include mapping from $fromKeyCode to $toKeyCode",
+ toKeyCode,
+ remapping.getOrDefault(fromKeyCode, -1)
+ )
+ }
+
+ mKeyRemapper.clearAllKeyRemappings()
testLooper.dispatchNext()
- }
- val remapping = mKeyRemapper.keyRemapping
- val expectedSize = REMAPPABLE_KEYS.size
- assertEquals("Remapping size should be $expectedSize", expectedSize, remapping.size)
-
- for (i in REMAPPABLE_KEYS.indices) {
- val fromKeyCode = REMAPPABLE_KEYS[i]
- val toKeyCode = REMAPPABLE_KEYS[(i + 1) % REMAPPABLE_KEYS.size]
assertEquals(
- "Remapping should include mapping from $fromKeyCode to $toKeyCode",
- toKeyCode,
- remapping.getOrDefault(fromKeyCode, -1)
+ "Remapping size should be 0 after clearAllModifierKeyRemappings",
+ 0,
+ mKeyRemapper.keyRemapping.size
+ )
+ }
+ }
+
+ @Test
+ fun testKeyRemapping_whenRemappingDisabled() {
+ ModifierRemappingFlag(false).use {
+ val keyboard = createKeyboard(DEVICE_ID)
+ Mockito.`when`(iInputManager.getInputDevice(DEVICE_ID)).thenReturn(keyboard)
+
+ mKeyRemapper.remapKey(REMAPPABLE_KEYS[0], REMAPPABLE_KEYS[1])
+ testLooper.dispatchAll()
+
+ val remapping = mKeyRemapper.keyRemapping
+ assertEquals(
+ "Remapping should not be done if modifier key remapping is disabled",
+ 0,
+ remapping.size
+ )
+ }
+ }
+
+ private inner class ModifierRemappingFlag constructor(enabled: Boolean) : AutoCloseable {
+ init {
+ Settings.Global.putString(
+ context.contentResolver,
+ "settings_new_keyboard_modifier_key", enabled.toString()
)
}
- mKeyRemapper.clearAllKeyRemappings()
- testLooper.dispatchNext()
-
- assertEquals(
- "Remapping size should be 0 after clearAllModifierKeyRemappings",
- 0,
- mKeyRemapper.keyRemapping.size
- )
+ override fun close() {
+ Settings.Global.putString(
+ context.contentResolver,
+ "settings_new_keyboard_modifier_key",
+ ""
+ )
+ }
}
}
\ No newline at end of file
diff --git a/services/tests/servicestests/src/com/android/server/job/BiasSchedulingTest.java b/services/tests/servicestests/src/com/android/server/job/BiasSchedulingTest.java
index e886e7d..56d01b0 100644
--- a/services/tests/servicestests/src/com/android/server/job/BiasSchedulingTest.java
+++ b/services/tests/servicestests/src/com/android/server/job/BiasSchedulingTest.java
@@ -57,14 +57,14 @@
}
public void testLowerBiasJobPreempted() throws Exception {
- for (int i = 0; i < JobConcurrencyManager.STANDARD_CONCURRENCY_LIMIT; ++i) {
+ for (int i = 0; i < JobConcurrencyManager.MAX_CONCURRENCY_LIMIT; ++i) {
JobInfo job = new JobInfo.Builder(100 + i, sJobServiceComponent)
.setBias(LOW_BIAS)
.setOverrideDeadline(0)
.build();
mJobScheduler.schedule(job);
}
- final int higherBiasJobId = 100 + JobConcurrencyManager.STANDARD_CONCURRENCY_LIMIT;
+ final int higherBiasJobId = 100 + JobConcurrencyManager.MAX_CONCURRENCY_LIMIT;
JobInfo jobHigher = new JobInfo.Builder(higherBiasJobId, sJobServiceComponent)
.setBias(HIGH_BIAS)
.setMinimumLatency(2000)
@@ -88,14 +88,14 @@
}
public void testHigherBiasJobNotPreempted() throws Exception {
- for (int i = 0; i < JobConcurrencyManager.STANDARD_CONCURRENCY_LIMIT; ++i) {
+ for (int i = 0; i < JobConcurrencyManager.DEFAULT_CONCURRENCY_LIMIT; ++i) {
JobInfo job = new JobInfo.Builder(100 + i, sJobServiceComponent)
.setBias(HIGH_BIAS)
.setOverrideDeadline(0)
.build();
mJobScheduler.schedule(job);
}
- final int lowerBiasJobId = 100 + JobConcurrencyManager.STANDARD_CONCURRENCY_LIMIT;
+ final int lowerBiasJobId = 100 + JobConcurrencyManager.DEFAULT_CONCURRENCY_LIMIT;
JobInfo jobLower = new JobInfo.Builder(lowerBiasJobId, sJobServiceComponent)
.setBias(LOW_BIAS)
.setMinimumLatency(2000)
diff --git a/services/tests/servicestests/src/com/android/server/job/WorkCountTrackerTest.java b/services/tests/servicestests/src/com/android/server/job/WorkCountTrackerTest.java
index dd9ae65..0fd6a9e 100644
--- a/services/tests/servicestests/src/com/android/server/job/WorkCountTrackerTest.java
+++ b/services/tests/servicestests/src/com/android/server/job/WorkCountTrackerTest.java
@@ -16,6 +16,7 @@
package com.android.server.job;
+import static com.android.server.job.JobConcurrencyManager.MAX_CONCURRENCY_LIMIT;
import static com.android.server.job.JobConcurrencyManager.NUM_WORK_TYPES;
import static com.android.server.job.JobConcurrencyManager.WORK_TYPE_BG;
import static com.android.server.job.JobConcurrencyManager.WORK_TYPE_BGUSER;
@@ -191,10 +192,10 @@
}
private void recount(Jobs jobs, int totalMax,
- @NonNull List<Pair<Integer, Integer>> minLimits,
- @NonNull List<Pair<Integer, Integer>> maxLimits) {
+ @NonNull List<Pair<Integer, Float>> minLimitRatios,
+ @NonNull List<Pair<Integer, Float>> maxLimitRatios) {
mWorkCountTracker.setConfig(new JobConcurrencyManager.WorkTypeConfig(
- "test", totalMax, minLimits, maxLimits));
+ "test", MAX_CONCURRENCY_LIMIT, totalMax, minLimitRatios, maxLimitRatios));
mWorkCountTracker.resetCounts();
for (int i = 0; i < jobs.running.size(); ++i) {
@@ -259,18 +260,18 @@
* Used by the following testRandom* tests.
*/
private void checkRandom(Jobs jobs, int numTests, int totalMax,
- @NonNull List<Pair<Integer, Integer>> minLimits,
- @NonNull List<Pair<Integer, Integer>> maxLimits,
+ @NonNull List<Pair<Integer, Float>> minLimitRatios,
+ @NonNull List<Pair<Integer, Float>> maxLimitRatios,
double probStart, double[] typeCdf, double[] numTypesCdf, double probStop) {
int minExpected = 0;
- for (Pair<Integer, Integer> minLimit : minLimits) {
- minExpected = Math.min(minLimit.second, minExpected);
+ for (Pair<Integer, Float> minLimit : minLimitRatios) {
+ minExpected = Math.min((int) (minLimit.second * MAX_CONCURRENCY_LIMIT), minExpected);
}
for (int i = 0; i < numTests; i++) {
jobs.maybeFinishJobs(probStop);
jobs.maybeEnqueueJobs(probStart, typeCdf, numTypesCdf);
- recount(jobs, totalMax, minLimits, maxLimits);
+ recount(jobs, totalMax, minLimitRatios, maxLimitRatios);
final int numPending = jobs.pendingMultiTypes.size();
startPendingJobs(jobs);
@@ -284,9 +285,11 @@
}
assertThat(totalRunning).isAtMost(totalMax);
assertThat(totalRunning).isAtLeast(Math.min(minExpected, numPending));
- for (Pair<Integer, Integer> maxLimit : maxLimits) {
- assertWithMessage("Work type " + maxLimit.first + " is running too many jobs")
- .that(jobs.running.get(maxLimit.first)).isAtMost(maxLimit.second);
+ for (Pair<Integer, Float> maxLimitRatio : maxLimitRatios) {
+ final int workType = maxLimitRatio.first;
+ final int maxLimit = (int) (maxLimitRatio.second * MAX_CONCURRENCY_LIMIT);
+ assertWithMessage("Work type " + workType + " is running too many jobs")
+ .that(jobs.running.get(workType)).isAtMost(maxLimit);
}
}
}
@@ -302,12 +305,14 @@
final int numTests = 5000;
final int totalMax = 6;
- final List<Pair<Integer, Integer>> maxLimits = List.of(Pair.create(WORK_TYPE_BG, 4));
- final List<Pair<Integer, Integer>> minLimits = List.of(Pair.create(WORK_TYPE_BG, 2));
+ final List<Pair<Integer, Float>> minLimitRatios =
+ List.of(Pair.create(WORK_TYPE_BG, 1.0f / 3));
+ final List<Pair<Integer, Float>> maxLimitRatios =
+ List.of(Pair.create(WORK_TYPE_BG, 2.0f / 3));
final double probStop = 0.1;
final double probStart = 0.1;
- checkRandom(jobs, numTests, totalMax, minLimits, maxLimits, probStart,
+ checkRandom(jobs, numTests, totalMax, minLimitRatios, maxLimitRatios, probStart,
EQUAL_PROBABILITY_CDF, EQUAL_PROBABILITY_CDF, probStop);
}
@@ -317,15 +322,15 @@
final int numTests = 5000;
final int totalMax = 2;
- final List<Pair<Integer, Integer>> maxLimits =
- List.of(Pair.create(WORK_TYPE_BG, 2), Pair.create(WORK_TYPE_BGUSER, 1));
- final List<Pair<Integer, Integer>> minLimits = List.of();
+ final List<Pair<Integer, Float>> minLimitRatios = List.of();
+ final List<Pair<Integer, Float>> maxLimitRatios =
+ List.of(Pair.create(WORK_TYPE_BG, 1f), Pair.create(WORK_TYPE_BGUSER, .5f));
final double probStop = 0.5;
final double[] cdf = buildWorkTypeCdf(0.5, 0, 0, 0.5, 0, 0);
final double[] numTypesCdf = buildCdf(.5, .3, .15, .05);
final double probStart = 0.5;
- checkRandom(jobs, numTests, totalMax, minLimits, maxLimits, probStart,
+ checkRandom(jobs, numTests, totalMax, minLimitRatios, maxLimitRatios, probStart,
cdf, numTypesCdf, probStop);
}
@@ -335,15 +340,15 @@
final int numTests = 5000;
final int totalMax = 2;
- final List<Pair<Integer, Integer>> maxLimits =
- List.of(Pair.create(WORK_TYPE_BG, 2), Pair.create(WORK_TYPE_BGUSER, 1));
- final List<Pair<Integer, Integer>> minLimits = List.of(Pair.create(WORK_TYPE_BG, 2));
+ final List<Pair<Integer, Float>> minLimitRatios = List.of(Pair.create(WORK_TYPE_BG, .99f));
+ final List<Pair<Integer, Float>> maxLimitRatios =
+ List.of(Pair.create(WORK_TYPE_BG, 1f), Pair.create(WORK_TYPE_BGUSER, .5f));
final double probStop = 0.5;
final double[] cdf = buildWorkTypeCdf(1.0 / 3, 0, 0, 1.0 / 3, 0, 1.0 / 3);
final double[] numTypesCdf = buildCdf(.75, .2, .05);
final double probStart = 0.5;
- checkRandom(jobs, numTests, totalMax, minLimits, maxLimits, probStart,
+ checkRandom(jobs, numTests, totalMax, minLimitRatios, maxLimitRatios, probStart,
cdf, numTypesCdf, probStop);
}
@@ -353,15 +358,15 @@
final int numTests = 5000;
final int totalMax = 10;
- final List<Pair<Integer, Integer>> maxLimits =
- List.of(Pair.create(WORK_TYPE_BG, 2), Pair.create(WORK_TYPE_BGUSER, 1));
- final List<Pair<Integer, Integer>> minLimits = List.of();
+ final List<Pair<Integer, Float>> minLimitRatios = List.of();
+ final List<Pair<Integer, Float>> maxLimitRatios =
+ List.of(Pair.create(WORK_TYPE_BG, .2f), Pair.create(WORK_TYPE_BGUSER, .1f));
final double probStop = 0.5;
final double[] cdf = buildWorkTypeCdf(1.0 / 3, 0, 0, 1.0 / 3, 0, 1.0 / 3);
final double[] numTypesCdf = buildCdf(.05, .95);
final double probStart = 0.5;
- checkRandom(jobs, numTests, totalMax, minLimits, maxLimits, probStart,
+ checkRandom(jobs, numTests, totalMax, minLimitRatios, maxLimitRatios, probStart,
cdf, numTypesCdf, probStop);
}
@@ -371,15 +376,17 @@
final int numTests = 5000;
final int totalMax = 6;
- final List<Pair<Integer, Integer>> maxLimits =
- List.of(Pair.create(WORK_TYPE_BG, 4), Pair.create(WORK_TYPE_BGUSER, 2));
- final List<Pair<Integer, Integer>> minLimits = List.of(Pair.create(WORK_TYPE_BG, 2));
+ final List<Pair<Integer, Float>> minLimitRatios =
+ List.of(Pair.create(WORK_TYPE_BG, 1.0f / 3));
+ final List<Pair<Integer, Float>> maxLimitRatios =
+ List.of(Pair.create(WORK_TYPE_BG, 2.0f / 3),
+ Pair.create(WORK_TYPE_BGUSER, 2.0f / 3));
final double probStop = 0.5;
final double[] cdf = buildWorkTypeCdf(0.1, 0, 0, 0.8, 0.02, .08);
final double[] numTypesCdf = buildCdf(.5, .3, .15, .05);
final double probStart = 0.5;
- checkRandom(jobs, numTests, totalMax, minLimits, maxLimits, probStart,
+ checkRandom(jobs, numTests, totalMax, minLimitRatios, maxLimitRatios, probStart,
cdf, numTypesCdf, probStop);
}
@@ -389,15 +396,17 @@
final int numTests = 5000;
final int totalMax = 6;
- final List<Pair<Integer, Integer>> maxLimits =
- List.of(Pair.create(WORK_TYPE_BG, 4), Pair.create(WORK_TYPE_BGUSER, 2));
- final List<Pair<Integer, Integer>> minLimits = List.of(Pair.create(WORK_TYPE_BG, 2));
+ final List<Pair<Integer, Float>> minLimitRatios =
+ List.of(Pair.create(WORK_TYPE_BG, 1.0f / 3));
+ final List<Pair<Integer, Float>> maxLimitRatios =
+ List.of(Pair.create(WORK_TYPE_BG, 2.0f / 3),
+ Pair.create(WORK_TYPE_BGUSER, 1.0f / 3));
final double probStop = 0.5;
final double[] cdf = buildWorkTypeCdf(0.85, 0.05, 0, 0.1, 0, 0);
final double[] numTypesCdf = buildCdf(1);
final double probStart = 0.5;
- checkRandom(jobs, numTests, totalMax, minLimits, maxLimits, probStart,
+ checkRandom(jobs, numTests, totalMax, minLimitRatios, maxLimitRatios, probStart,
cdf, numTypesCdf, probStop);
}
@@ -407,15 +416,17 @@
final int numTests = 5000;
final int totalMax = 6;
- final List<Pair<Integer, Integer>> maxLimits =
- List.of(Pair.create(WORK_TYPE_BG, 4), Pair.create(WORK_TYPE_BGUSER, 2));
- final List<Pair<Integer, Integer>> minLimits = List.of(Pair.create(WORK_TYPE_BG, 2));
+ final List<Pair<Integer, Float>> minLimitRatios =
+ List.of(Pair.create(WORK_TYPE_BG, 1.0f / 3));
+ final List<Pair<Integer, Float>> maxLimitRatios =
+ List.of(Pair.create(WORK_TYPE_BG, 2.0f / 3),
+ Pair.create(WORK_TYPE_BGUSER, 1.0f / 3));
final double probStop = 0.4;
final double[] cdf = buildWorkTypeCdf(0.1, 0, 0, 0.1, 0.05, .75);
final double[] numTypesCdf = buildCdf(0.5, 0.5);
final double probStart = 0.5;
- checkRandom(jobs, numTests, totalMax, minLimits, maxLimits, probStart,
+ checkRandom(jobs, numTests, totalMax, minLimitRatios, maxLimitRatios, probStart,
cdf, numTypesCdf, probStop);
}
@@ -425,16 +436,18 @@
final int numTests = 5000;
final int totalMax = 6;
- final List<Pair<Integer, Integer>> maxLimits =
- List.of(Pair.create(WORK_TYPE_BG, 4), Pair.create(WORK_TYPE_BGUSER, 2));
- final List<Pair<Integer, Integer>> minLimits =
- List.of(Pair.create(WORK_TYPE_BG, 2), Pair.create(WORK_TYPE_BGUSER, 1));
+ final List<Pair<Integer, Float>> minLimitRatios =
+ List.of(Pair.create(WORK_TYPE_BG, 1.0f / 3),
+ Pair.create(WORK_TYPE_BGUSER, 1.0f / 6));
+ final List<Pair<Integer, Float>> maxLimitRatios =
+ List.of(Pair.create(WORK_TYPE_BG, 2.0f / 3),
+ Pair.create(WORK_TYPE_BGUSER, 1.0f / 3));
final double probStop = 0.4;
final double[] cdf = buildWorkTypeCdf(0.8, 0.1, 0, 0.05, 0, 0.05);
final double[] numTypesCdf = buildCdf(1);
final double probStart = 0.5;
- checkRandom(jobs, numTests, totalMax, minLimits, maxLimits, probStart,
+ checkRandom(jobs, numTests, totalMax, minLimitRatios, maxLimitRatios, probStart,
cdf, numTypesCdf, probStop);
}
@@ -444,16 +457,18 @@
final int numTests = 5000;
final int totalMax = 6;
- final List<Pair<Integer, Integer>> maxLimits =
- List.of(Pair.create(WORK_TYPE_BG, 4), Pair.create(WORK_TYPE_BGUSER, 2));
- final List<Pair<Integer, Integer>> minLimits =
- List.of(Pair.create(WORK_TYPE_BG, 2), Pair.create(WORK_TYPE_BGUSER, 1));
+ final List<Pair<Integer, Float>> minLimitRatios =
+ List.of(Pair.create(WORK_TYPE_BG, 1.0f / 3),
+ Pair.create(WORK_TYPE_BGUSER, 1.0f / 6));
+ final List<Pair<Integer, Float>> maxLimitRatios =
+ List.of(Pair.create(WORK_TYPE_BG, 2.0f / 3),
+ Pair.create(WORK_TYPE_BGUSER, 1.0f / 3));
final double probStop = 0.5;
final double[] cdf = buildWorkTypeCdf(0, 0, 0, 0.5, 0, 0.5);
final double[] numTypesCdf = buildCdf(1);
final double probStart = 0.5;
- checkRandom(jobs, numTests, totalMax, minLimits, maxLimits, probStart,
+ checkRandom(jobs, numTests, totalMax, minLimitRatios, maxLimitRatios, probStart,
cdf, numTypesCdf, probStop);
}
@@ -463,16 +478,18 @@
final int numTests = 5000;
final int totalMax = 6;
- final List<Pair<Integer, Integer>> maxLimits =
- List.of(Pair.create(WORK_TYPE_BG, 4), Pair.create(WORK_TYPE_BGUSER, 2));
- final List<Pair<Integer, Integer>> minLimits =
- List.of(Pair.create(WORK_TYPE_BG, 2), Pair.create(WORK_TYPE_BGUSER, 1));
+ final List<Pair<Integer, Float>> minLimitRatios =
+ List.of(Pair.create(WORK_TYPE_BG, 1.0f / 3),
+ Pair.create(WORK_TYPE_BGUSER, 1.0f / 6));
+ final List<Pair<Integer, Float>> maxLimitRatios =
+ List.of(Pair.create(WORK_TYPE_BG, 2.0f / 3),
+ Pair.create(WORK_TYPE_BGUSER, 1.0f / 3));
final double probStop = 0.5;
final double[] cdf = buildWorkTypeCdf(0, 0, 0, 0.1, 0, 0.9);
final double[] numTypesCdf = buildCdf(0.9, 0.1);
final double probStart = 0.5;
- checkRandom(jobs, numTests, totalMax, minLimits, maxLimits, probStart,
+ checkRandom(jobs, numTests, totalMax, minLimitRatios, maxLimitRatios, probStart,
cdf, numTypesCdf, probStop);
}
@@ -482,16 +499,18 @@
final int numTests = 5000;
final int totalMax = 6;
- final List<Pair<Integer, Integer>> maxLimits =
- List.of(Pair.create(WORK_TYPE_BG, 4), Pair.create(WORK_TYPE_BGUSER, 2));
- final List<Pair<Integer, Integer>> minLimits =
- List.of(Pair.create(WORK_TYPE_BG, 2), Pair.create(WORK_TYPE_BGUSER, 1));
+ final List<Pair<Integer, Float>> minLimitRatios =
+ List.of(Pair.create(WORK_TYPE_BG, 1.0f / 3),
+ Pair.create(WORK_TYPE_BGUSER, 1.0f / 6));
+ final List<Pair<Integer, Float>> maxLimitRatios =
+ List.of(Pair.create(WORK_TYPE_BG, 2.0f / 3),
+ Pair.create(WORK_TYPE_BGUSER, 1.0f / 3));
final double probStop = 0.5;
final double[] cdf = buildWorkTypeCdf(0, 0, 0, 0.9, 0, 0.1);
final double[] numTypesCdf = buildCdf(1);
final double probStart = 0.5;
- checkRandom(jobs, numTests, totalMax, minLimits, maxLimits, probStart,
+ checkRandom(jobs, numTests, totalMax, minLimitRatios, maxLimitRatios, probStart,
cdf, numTypesCdf, probStop);
}
@@ -501,15 +520,16 @@
final int numTests = 5000;
final int totalMax = 6;
- final List<Pair<Integer, Integer>> maxLimits = List.of(Pair.create(WORK_TYPE_BG, 4));
- final List<Pair<Integer, Integer>> minLimits =
- List.of(Pair.create(WORK_TYPE_EJ, 2), Pair.create(WORK_TYPE_BG, 2));
+ final List<Pair<Integer, Float>> minLimitRatios =
+ List.of(Pair.create(WORK_TYPE_EJ, 1.0f / 3), Pair.create(WORK_TYPE_BG, 1.0f / 3));
+ final List<Pair<Integer, Float>> maxLimitRatios =
+ List.of(Pair.create(WORK_TYPE_BG, 2.0f / 3));
final double probStop = 0.4;
final double[] cdf = buildWorkTypeCdf(0.5, 0, 0.5, 0, 0, 0);
final double[] numTypesCdf = buildCdf(0.1, 0.7, 0.2);
final double probStart = 0.5;
- checkRandom(jobs, numTests, totalMax, minLimits, maxLimits, probStart,
+ checkRandom(jobs, numTests, totalMax, minLimitRatios, maxLimitRatios, probStart,
cdf, numTypesCdf, probStop);
}
@@ -522,16 +542,16 @@
final int numTests = 5000;
final int totalMax = 13;
- final List<Pair<Integer, Integer>> maxLimits = List.of(
- Pair.create(WORK_TYPE_EJ, 5), Pair.create(WORK_TYPE_BG, 4),
- Pair.create(WORK_TYPE_BGUSER, 3));
- final List<Pair<Integer, Integer>> minLimits =
- List.of(Pair.create(WORK_TYPE_EJ, 2), Pair.create(WORK_TYPE_BG, 1));
+ final List<Pair<Integer, Float>> minLimitRatios =
+ List.of(Pair.create(WORK_TYPE_EJ, 2.0f / 13), Pair.create(WORK_TYPE_BG, 1.0f / 13));
+ final List<Pair<Integer, Float>> maxLimitRatios = List.of(
+ Pair.create(WORK_TYPE_EJ, 5.0f / 13), Pair.create(WORK_TYPE_BG, 4.0f / 13),
+ Pair.create(WORK_TYPE_BGUSER, 3.0f / 13));
final double probStop = 0.13;
final double[] numTypesCdf = buildCdf(0, 0.05, 0.1, 0.7, 0.1, 0.05);
final double probStart = 0.87;
- checkRandom(jobs, numTests, totalMax, minLimits, maxLimits, probStart,
+ checkRandom(jobs, numTests, totalMax, minLimitRatios, maxLimitRatios, probStart,
EQUAL_PROBABILITY_CDF, numTypesCdf, probStop);
}
@@ -541,15 +561,16 @@
final int numTests = 5000;
final int totalMax = 6;
- final List<Pair<Integer, Integer>> maxLimits =
- List.of(Pair.create(WORK_TYPE_EJ, 5), Pair.create(WORK_TYPE_BG, 4));
- final List<Pair<Integer, Integer>> minLimits = List.of(Pair.create(WORK_TYPE_BG, 2));
+ final List<Pair<Integer, Float>> minLimitRatios =
+ List.of(Pair.create(WORK_TYPE_BG, 1.0f / 3));
+ final List<Pair<Integer, Float>> maxLimitRatios =
+ List.of(Pair.create(WORK_TYPE_EJ, 5.0f / 6), Pair.create(WORK_TYPE_BG, 2.0f / 3));
final double probStop = 0.4;
final double[] cdf = buildWorkTypeCdf(.1, 0, 0.5, 0.35, 0, 0.05);
final double[] numTypesCdf = buildCdf(1);
final double probStart = 0.5;
- checkRandom(jobs, numTests, totalMax, minLimits, maxLimits, probStart,
+ checkRandom(jobs, numTests, totalMax, minLimitRatios, maxLimitRatios, probStart,
cdf, numTypesCdf, probStop);
}
@@ -559,17 +580,17 @@
final int numTests = 5000;
final int totalMax = 6;
- final List<Pair<Integer, Integer>> maxLimits =
- List.of(Pair.create(WORK_TYPE_EJ, 5), Pair.create(WORK_TYPE_BG, 4),
- Pair.create(WORK_TYPE_BGUSER, 1));
- final List<Pair<Integer, Integer>> minLimits =
- List.of(Pair.create(WORK_TYPE_EJ, 3), Pair.create(WORK_TYPE_BG, 2));
+ final List<Pair<Integer, Float>> minLimitRatios =
+ List.of(Pair.create(WORK_TYPE_EJ, .5f), Pair.create(WORK_TYPE_BG, 1.0f / 3));
+ final List<Pair<Integer, Float>> maxLimitRatios =
+ List.of(Pair.create(WORK_TYPE_EJ, 5.0f / 6), Pair.create(WORK_TYPE_BG, 2.0f / 3),
+ Pair.create(WORK_TYPE_BGUSER, 1.0f / 6));
final double probStop = 0.4;
final double[] cdf = buildWorkTypeCdf(0.01, 0.09, 0.4, 0.1, 0, 0.4);
final double[] numTypesCdf = buildCdf(0.7, 0.3);
final double probStart = 0.5;
- checkRandom(jobs, numTests, totalMax, minLimits, maxLimits, probStart,
+ checkRandom(jobs, numTests, totalMax, minLimitRatios, maxLimitRatios, probStart,
cdf, numTypesCdf, probStop);
}
@@ -579,25 +600,25 @@
final int numTests = 5000;
final int totalMax = 7;
- final List<Pair<Integer, Integer>> maxLimits =
- List.of(Pair.create(WORK_TYPE_EJ, 5), Pair.create(WORK_TYPE_BG, 4),
- Pair.create(WORK_TYPE_BGUSER_IMPORTANT, 1),
- Pair.create(WORK_TYPE_BGUSER, 1));
- final List<Pair<Integer, Integer>> minLimits =
- List.of(Pair.create(WORK_TYPE_EJ, 3), Pair.create(WORK_TYPE_BG, 2));
+ final List<Pair<Integer, Float>> minLimitRatios =
+ List.of(Pair.create(WORK_TYPE_EJ, 3.0f / 7), Pair.create(WORK_TYPE_BG, 2.0f / 7));
+ final List<Pair<Integer, Float>> maxLimitRatios =
+ List.of(Pair.create(WORK_TYPE_EJ, 5.0f / 7), Pair.create(WORK_TYPE_BG, 4.0f / 7),
+ Pair.create(WORK_TYPE_BGUSER_IMPORTANT, 1.0f / 7),
+ Pair.create(WORK_TYPE_BGUSER, 1.0f / 7));
final double probStop = 0.4;
final double[] cdf = buildWorkTypeCdf(0.01, 0.09, 0.25, 0.05, 0.3, 0.3);
final double[] numTypesCdf = buildCdf(0.7, 0.3);
final double probStart = 0.5;
- checkRandom(jobs, numTests, totalMax, minLimits, maxLimits, probStart,
+ checkRandom(jobs, numTests, totalMax, minLimitRatios, maxLimitRatios, probStart,
cdf, numTypesCdf, probStop);
}
/** Used by the following tests */
private void checkSimple(int totalMax,
- @NonNull List<Pair<Integer, Integer>> minLimits,
- @NonNull List<Pair<Integer, Integer>> maxLimits,
+ @NonNull List<Pair<Integer, Float>> minLimitRatios,
+ @NonNull List<Pair<Integer, Float>> maxLimitRatios,
@NonNull List<Pair<Integer, Integer>> running,
@NonNull List<Pair<Integer, Integer>> pending,
@NonNull List<Pair<Integer, Integer>> resultRunning,
@@ -610,17 +631,19 @@
jobs.addPending(pend.first, pend.second);
}
- recount(jobs, totalMax, minLimits, maxLimits);
+ recount(jobs, totalMax, minLimitRatios, maxLimitRatios);
startPendingJobs(jobs);
for (Pair<Integer, Integer> run : resultRunning) {
assertWithMessage(
- "Incorrect running result for work type " + workTypeToString(run.first))
+ "Incorrect running result for work type " + workTypeToString(run.first)
+ + " wanted " + run.second + ", got " + jobs.running.get(run.first))
.that(jobs.running.get(run.first)).isEqualTo(run.second);
}
for (Pair<Integer, Integer> pend : resultPending) {
assertWithMessage(
- "Incorrect pending result for work type " + workTypeToString(pend.first))
+ "Incorrect pending result for work type " + workTypeToString(pend.first)
+ + " wanted " + pend.second + ", got " + jobs.pending.get(pend.first))
.that(jobs.pending.get(pend.first)).isEqualTo(pend.second);
}
}
@@ -628,16 +651,18 @@
@Test
public void testBasic() {
checkSimple(6,
- /* min */ List.of(Pair.create(WORK_TYPE_BG, 2)),
- /* max */ List.of(Pair.create(WORK_TYPE_BG, 4), Pair.create(WORK_TYPE_BGUSER, 2)),
+ /* min */ List.of(Pair.create(WORK_TYPE_BG, 1.0f / 3)),
+ /* max */List.of(Pair.create(WORK_TYPE_BG, 2.0f / 3),
+ Pair.create(WORK_TYPE_BGUSER, 1.0f / 3)),
/* run */ List.of(),
/* pen */ List.of(Pair.create(WORK_TYPE_TOP, 1)),
/* resRun */ List.of(Pair.create(WORK_TYPE_TOP, 1)),
/* resPen */ List.of());
checkSimple(6,
- /* min */ List.of(Pair.create(WORK_TYPE_BG, 2)),
- /* max */ List.of(Pair.create(WORK_TYPE_BG, 4), Pair.create(WORK_TYPE_BGUSER, 2)),
+ /* min */ List.of(Pair.create(WORK_TYPE_BG, 1.0f / 3)),
+ /* max */ List.of(Pair.create(WORK_TYPE_BG, 2.0f / 3),
+ Pair.create(WORK_TYPE_BGUSER, 1.0f / 3)),
/* run */ List.of(),
/* pen */ List.of(Pair.create(WORK_TYPE_TOP, 10)),
/* resRun */ List.of(Pair.create(WORK_TYPE_TOP, 6)),
@@ -645,39 +670,40 @@
// When there are BG jobs pending, 2 (min-BG) jobs should run.
checkSimple(6,
- /* min */ List.of(Pair.create(WORK_TYPE_BG, 2)),
- /* max */ List.of(Pair.create(WORK_TYPE_BG, 4), Pair.create(WORK_TYPE_BGUSER, 2)),
+ /* min */ List.of(Pair.create(WORK_TYPE_BG, 1.0f / 3)),
+ /* max */ List.of(Pair.create(WORK_TYPE_BG, 2.0f / 3),
+ Pair.create(WORK_TYPE_BGUSER, 1.0f / 3)),
/* run */ List.of(),
/* pen */ List.of(Pair.create(WORK_TYPE_TOP, 10), Pair.create(WORK_TYPE_BG, 1)),
/* resRun */ List.of(Pair.create(WORK_TYPE_TOP, 5), Pair.create(WORK_TYPE_BG, 1)),
/* resPen */ List.of(Pair.create(WORK_TYPE_TOP, 5)));
checkSimple(6,
- /* min */ List.of(Pair.create(WORK_TYPE_BG, 2)),
- /* max */ List.of(Pair.create(WORK_TYPE_BG, 4)),
+ /* min */ List.of(Pair.create(WORK_TYPE_BG, 1.0f / 3)),
+ /* max */ List.of(Pair.create(WORK_TYPE_BG, 2.0f / 3)),
/* run */ List.of(),
/* pen */ List.of(Pair.create(WORK_TYPE_TOP, 10), Pair.create(WORK_TYPE_BG, 3)),
/* resRun */ List.of(Pair.create(WORK_TYPE_TOP, 4), Pair.create(WORK_TYPE_BG, 2)),
/* resPen */ List.of(Pair.create(WORK_TYPE_TOP, 6), Pair.create(WORK_TYPE_BG, 1)));
checkSimple(8,
- /* min */ List.of(Pair.create(WORK_TYPE_BG, 2)),
- /* max */ List.of(Pair.create(WORK_TYPE_BG, 6)),
+ /* min */ List.of(Pair.create(WORK_TYPE_BG, .25f)),
+ /* max */ List.of(Pair.create(WORK_TYPE_BG, .75f)),
/* run */ List.of(),
/* pen */ List.of(Pair.create(WORK_TYPE_BG, 49)),
/* resRun */ List.of(Pair.create(WORK_TYPE_BG, 6)),
/* resPen */ List.of(Pair.create(WORK_TYPE_BG, 43)));
checkSimple(8,
- /* min */ List.of(Pair.create(WORK_TYPE_BG, 2)),
- /* max */ List.of(Pair.create(WORK_TYPE_BG, 6)),
+ /* min */ List.of(Pair.create(WORK_TYPE_BG, .25f)),
+ /* max */ List.of(Pair.create(WORK_TYPE_BG, .75f)),
/* run */ List.of(Pair.create(WORK_TYPE_TOP, 2), Pair.create(WORK_TYPE_BG, 4)),
/* pen */ List.of(Pair.create(WORK_TYPE_BG, 49)),
/* resRun */ List.of(Pair.create(WORK_TYPE_TOP, 2), Pair.create(WORK_TYPE_BG, 6)),
/* resPen */ List.of(Pair.create(WORK_TYPE_BG, 47)));
checkSimple(8,
- /* min */ List.of(Pair.create(WORK_TYPE_BG, 2)),
- /* max */ List.of(Pair.create(WORK_TYPE_BG, 6)),
+ /* min */ List.of(Pair.create(WORK_TYPE_BG, .25f)),
+ /* max */ List.of(Pair.create(WORK_TYPE_BG, .75f)),
/* run */ List.of(Pair.create(WORK_TYPE_TOP, 2), Pair.create(WORK_TYPE_BG, 4)),
/* pen */ List.of(Pair.create(WORK_TYPE_TOP, 49), Pair.create(WORK_TYPE_BG, 49)),
/* resRun */ List.of(Pair.create(WORK_TYPE_TOP, 4), Pair.create(WORK_TYPE_BG, 4)),
@@ -686,48 +712,52 @@
checkSimple(8,
- /* min */ List.of(Pair.create(WORK_TYPE_BG, 2)),
- /* max */ List.of(Pair.create(WORK_TYPE_TOP, 6), Pair.create(WORK_TYPE_BG, 6)),
+ /* min */ List.of(Pair.create(WORK_TYPE_BG, .25f)),
+ /* max */
+ List.of(Pair.create(WORK_TYPE_TOP, .75f), Pair.create(WORK_TYPE_BG, .75f)),
/* run */ List.of(Pair.create(WORK_TYPE_TOP, 2), Pair.create(WORK_TYPE_BG, 4)),
/* pen */ List.of(Pair.create(WORK_TYPE_TOP, 10), Pair.create(WORK_TYPE_BG, 49)),
/* resRun */ List.of(Pair.create(WORK_TYPE_TOP, 4), Pair.create(WORK_TYPE_BG, 4)),
/* resPen */ List.of(Pair.create(WORK_TYPE_TOP, 8), Pair.create(WORK_TYPE_BG, 49)));
checkSimple(8,
- /* min */ List.of(Pair.create(WORK_TYPE_BG, 2)),
- /* max */ List.of(Pair.create(WORK_TYPE_TOP, 6), Pair.create(WORK_TYPE_BG, 6)),
+ /* min */ List.of(Pair.create(WORK_TYPE_BG, .25f)),
+ /* max */ List.of(
+ Pair.create(WORK_TYPE_TOP, .75f), Pair.create(WORK_TYPE_BG, .75f)),
/* run */ List.of(Pair.create(WORK_TYPE_TOP, 2), Pair.create(WORK_TYPE_BG, 1)),
/* pen */ List.of(Pair.create(WORK_TYPE_TOP, 10), Pair.create(WORK_TYPE_BG, 49)),
/* resRun */ List.of(Pair.create(WORK_TYPE_TOP, 6), Pair.create(WORK_TYPE_BG, 2)),
/* resPen */ List.of(Pair.create(WORK_TYPE_TOP, 6), Pair.create(WORK_TYPE_BG, 48)));
checkSimple(8,
- /* min */ List.of(Pair.create(WORK_TYPE_BG, 1)),
- /* max */ List.of(Pair.create(WORK_TYPE_TOP, 6), Pair.create(WORK_TYPE_BG, 2)),
+ /* min */ List.of(Pair.create(WORK_TYPE_BG, 1.0f / 8)),
+ /* max */ List.of(
+ Pair.create(WORK_TYPE_TOP, .75f), Pair.create(WORK_TYPE_BG, .25f)),
/* run */ List.of(Pair.create(WORK_TYPE_BG, 6)),
/* pen */ List.of(Pair.create(WORK_TYPE_TOP, 10), Pair.create(WORK_TYPE_BG, 49)),
/* resRun */ List.of(Pair.create(WORK_TYPE_TOP, 2), Pair.create(WORK_TYPE_BG, 6)),
/* resPen */ List.of(Pair.create(WORK_TYPE_TOP, 8), Pair.create(WORK_TYPE_BG, 49)));
checkSimple(8,
- /* min */ List.of(Pair.create(WORK_TYPE_BG, 1)),
- /* max */ List.of(Pair.create(WORK_TYPE_TOP, 6), Pair.create(WORK_TYPE_BG, 2)),
+ /* min */ List.of(Pair.create(WORK_TYPE_BG, 1.0f / 8)),
+ /* max */
+ List.of(Pair.create(WORK_TYPE_TOP, .75f), Pair.create(WORK_TYPE_BG, .25f)),
/* run */ List.of(Pair.create(WORK_TYPE_BG, 6)),
/* pen */ List.of(Pair.create(WORK_TYPE_TOP, 10), Pair.create(WORK_TYPE_BG, 49)),
/* resRun */ List.of(Pair.create(WORK_TYPE_TOP, 2), Pair.create(WORK_TYPE_BG, 6)),
/* resPen */ List.of(Pair.create(WORK_TYPE_TOP, 8), Pair.create(WORK_TYPE_BG, 49)));
checkSimple(6,
- /* min */ List.of(Pair.create(WORK_TYPE_BG, 2)),
- /* max */ List.of(Pair.create(WORK_TYPE_BG, 4)),
+ /* min */ List.of(Pair.create(WORK_TYPE_BG, 1.0f / 3)),
+ /* max */ List.of(Pair.create(WORK_TYPE_BG, 2.0f / 3)),
/* run */ List.of(Pair.create(WORK_TYPE_TOP, 6)),
/* pen */ List.of(Pair.create(WORK_TYPE_TOP, 10), Pair.create(WORK_TYPE_BG, 3)),
/* resRun */ List.of(Pair.create(WORK_TYPE_TOP, 6)),
/* resPen */ List.of(Pair.create(WORK_TYPE_TOP, 10), Pair.create(WORK_TYPE_BG, 3)));
checkSimple(8,
- /* min */ List.of(Pair.create(WORK_TYPE_EJ, 2), Pair.create(WORK_TYPE_BG, 2)),
- /* max */ List.of(Pair.create(WORK_TYPE_BG, 4)),
+ /* min */ List.of(Pair.create(WORK_TYPE_EJ, .25f), Pair.create(WORK_TYPE_BG, .25f)),
+ /* max */ List.of(Pair.create(WORK_TYPE_BG, .75f)),
/* run */ List.of(Pair.create(WORK_TYPE_TOP, 6)),
/* pen */ List.of(Pair.create(WORK_TYPE_TOP, 10), Pair.create(WORK_TYPE_EJ, 5),
Pair.create(WORK_TYPE_BG, 3)),
@@ -740,15 +770,16 @@
// shouldn't start new ones.
checkSimple(5,
/* min */ List.of(),
- /* max */ List.of(Pair.create(WORK_TYPE_BG, 1)),
+ /* max */ List.of(Pair.create(WORK_TYPE_BG, .2f)),
/* run */ List.of(Pair.create(WORK_TYPE_BG, 6)),
/* pen */ List.of(Pair.create(WORK_TYPE_TOP, 10), Pair.create(WORK_TYPE_BG, 3)),
/* resRun */ List.of(Pair.create(WORK_TYPE_BG, 6)),
/* resPen */ List.of(Pair.create(WORK_TYPE_TOP, 10), Pair.create(WORK_TYPE_BG, 3)));
checkSimple(6,
- /* min */ List.of(Pair.create(WORK_TYPE_BG, 2)),
- /* max */ List.of(Pair.create(WORK_TYPE_BG, 4), Pair.create(WORK_TYPE_BGUSER, 2)),
+ /* min */ List.of(Pair.create(WORK_TYPE_BG, 1.0f / 3)),
+ /* max */ List.of(Pair.create(WORK_TYPE_BG, 2.0f / 3),
+ Pair.create(WORK_TYPE_BGUSER, 1.0f / 3)),
/* run */ List.of(Pair.create(WORK_TYPE_BG, 2)),
/* pen */ List.of(Pair.create(WORK_TYPE_TOP, 10),
Pair.create(WORK_TYPE_BG, 3),
@@ -759,8 +790,9 @@
Pair.create(WORK_TYPE_BGUSER, 3)));
checkSimple(6,
- /* min */ List.of(Pair.create(WORK_TYPE_BG, 2)),
- /* max */ List.of(Pair.create(WORK_TYPE_BG, 4), Pair.create(WORK_TYPE_BGUSER, 3)),
+ /* min */ List.of(Pair.create(WORK_TYPE_BG, 1.0f / 3)),
+ /* max */ List.of(
+ Pair.create(WORK_TYPE_BG, 2.0f / 3), Pair.create(WORK_TYPE_BGUSER, .5f)),
/* run */ List.of(Pair.create(WORK_TYPE_BG, 2)),
/* pen */ List.of(Pair.create(WORK_TYPE_BG, 3), Pair.create(WORK_TYPE_BGUSER, 3)),
/* resRun */ List.of(
@@ -769,8 +801,9 @@
Pair.create(WORK_TYPE_BG, 1), Pair.create(WORK_TYPE_BGUSER, 1)));
checkSimple(6,
- /* min */ List.of(Pair.create(WORK_TYPE_BG, 2)),
- /* max */ List.of(Pair.create(WORK_TYPE_BG, 4), Pair.create(WORK_TYPE_BGUSER, 1)),
+ /* min */ List.of(Pair.create(WORK_TYPE_BG, 1.0f / 3)),
+ /* max */ List.of(Pair.create(WORK_TYPE_BG, 2.0f / 3),
+ Pair.create(WORK_TYPE_BGUSER, 1.0f / 6)),
/* run */ List.of(Pair.create(WORK_TYPE_BG, 2)),
/* pen */ List.of(Pair.create(WORK_TYPE_BG, 3), Pair.create(WORK_TYPE_BGUSER, 3)),
/* resRun */ List.of(
@@ -778,12 +811,13 @@
/* resPen */ List.of(
Pair.create(WORK_TYPE_BG, 1), Pair.create(WORK_TYPE_BGUSER, 2)));
- Log.d(TAG, "START***#*#*#*#*#*#**#*");
// Test multi-types
checkSimple(6,
- /* min */ List.of(Pair.create(WORK_TYPE_EJ, 2), Pair.create(WORK_TYPE_BG, 2)),
+ /* min */
+ List.of(Pair.create(WORK_TYPE_EJ, 1.0f / 3), Pair.create(WORK_TYPE_BG, 1.0f / 3)),
/* max */ List.of(
- Pair.create(WORK_TYPE_BG, 4), Pair.create(WORK_TYPE_BGUSER, 1)),
+ Pair.create(WORK_TYPE_BG, 2.0f / 3),
+ Pair.create(WORK_TYPE_BGUSER, 1.0f / 6)),
/* run */ List.of(),
/* pen */ List.of(
// 2 of these as TOP, 1 as EJ
@@ -809,10 +843,12 @@
jobs.addPending(WORK_TYPE_BG, 10);
final int totalMax = 6;
- final List<Pair<Integer, Integer>> minLimits = List.of(Pair.create(WORK_TYPE_BG, 1));
- final List<Pair<Integer, Integer>> maxLimits = List.of(Pair.create(WORK_TYPE_BG, 5));
+ final List<Pair<Integer, Float>> minLimitRatios =
+ List.of(Pair.create(WORK_TYPE_BG, 1.0f / totalMax));
+ final List<Pair<Integer, Float>> maxLimitRatios =
+ List.of(Pair.create(WORK_TYPE_BG, 5.0f / totalMax));
- recount(jobs, totalMax, minLimits, maxLimits);
+ recount(jobs, totalMax, minLimitRatios, maxLimitRatios);
startPendingJobs(jobs);
@@ -887,11 +923,12 @@
jobs.addPending(WORK_TYPE_BG, 10); // c
final int totalMax = 8;
- final List<Pair<Integer, Integer>> minLimits =
- List.of(Pair.create(WORK_TYPE_EJ, 1), Pair.create(WORK_TYPE_BG, 1));
- final List<Pair<Integer, Integer>> maxLimits = List.of(Pair.create(WORK_TYPE_BG, 5));
+ final List<Pair<Integer, Float>> minLimitRatios =
+ List.of(Pair.create(WORK_TYPE_EJ, 1.0f / 8), Pair.create(WORK_TYPE_BG, 1.0f / 8));
+ final List<Pair<Integer, Float>> maxLimitRatios =
+ List.of(Pair.create(WORK_TYPE_BG, 5.0f / 8));
- recount(jobs, totalMax, minLimits, maxLimits);
+ recount(jobs, totalMax, minLimitRatios, maxLimitRatios);
assertThat(jobs.pending.get(WORK_TYPE_TOP)).isEqualTo(11);
assertThat(jobs.pending.get(WORK_TYPE_EJ)).isEqualTo(5);
@@ -966,11 +1003,12 @@
}
final int totalMax = 8;
- final List<Pair<Integer, Integer>> minLimits =
- List.of(Pair.create(WORK_TYPE_EJ, 1), Pair.create(WORK_TYPE_BG, 1));
- final List<Pair<Integer, Integer>> maxLimits = List.of(Pair.create(WORK_TYPE_BG, 5));
+ final List<Pair<Integer, Float>> minLimitRatios =
+ List.of(Pair.create(WORK_TYPE_EJ, 1.0f / 8), Pair.create(WORK_TYPE_BG, 1.0f / 8));
+ final List<Pair<Integer, Float>> maxLimitRatios =
+ List.of(Pair.create(WORK_TYPE_BG, 5.0f / 8));
- recount(jobs, totalMax, minLimits, maxLimits);
+ recount(jobs, totalMax, minLimitRatios, maxLimitRatios);
assertThat(jobs.pending.get(WORK_TYPE_TOP)).isEqualTo(11);
assertThat(jobs.pending.get(WORK_TYPE_EJ)).isEqualTo(10);
diff --git a/services/tests/servicestests/src/com/android/server/job/WorkTypeConfigTest.java b/services/tests/servicestests/src/com/android/server/job/WorkTypeConfigTest.java
index 21d2784..bd5a063 100644
--- a/services/tests/servicestests/src/com/android/server/job/WorkTypeConfigTest.java
+++ b/services/tests/servicestests/src/com/android/server/job/WorkTypeConfigTest.java
@@ -45,23 +45,26 @@
@SmallTest
public class WorkTypeConfigTest {
private static final String KEY_MAX_TOTAL = "concurrency_max_total_test";
- private static final String KEY_MAX_TOP = "concurrency_max_top_test";
- private static final String KEY_MAX_FGS = "concurrency_max_fgs_test";
- private static final String KEY_MAX_EJ = "concurrency_max_ej_test";
- private static final String KEY_MAX_BG = "concurrency_max_bg_test";
- private static final String KEY_MAX_BGUSER_IMPORTANT = "concurrency_max_bguser_important_test";
- private static final String KEY_MAX_BGUSER = "concurrency_max_bguser_test";
- private static final String KEY_MIN_TOP = "concurrency_min_top_test";
- private static final String KEY_MIN_FGS = "concurrency_min_fgs_test";
- private static final String KEY_MIN_EJ = "concurrency_min_ej_test";
- private static final String KEY_MIN_BG = "concurrency_min_bg_test";
- private static final String KEY_MIN_BGUSER_IMPORTANT = "concurrency_min_bguser_important_test";
- private static final String KEY_MIN_BGUSER = "concurrency_min_bguser_test";
+ private static final String KEY_MAX_RATIO_TOP = "concurrency_max_ratio_top_test";
+ private static final String KEY_MAX_RATIO_FGS = "concurrency_max_ratio_fgs_test";
+ private static final String KEY_MAX_RATIO_EJ = "concurrency_max_ratio_ej_test";
+ private static final String KEY_MAX_RATIO_BG = "concurrency_max_ratio_bg_test";
+ private static final String KEY_MAX_RATIO_BGUSER_IMPORTANT =
+ "concurrency_max_ratio_bguser_important_test";
+ private static final String KEY_MAX_RATIO_BGUSER = "concurrency_max_ratio_bguser_test";
+ private static final String KEY_MIN_RATIO_TOP = "concurrency_min_ratio_top_test";
+ private static final String KEY_MIN_RATIO_FGS = "concurrency_min_ratio_fgs_test";
+ private static final String KEY_MIN_RATIO_EJ = "concurrency_min_ratio_ej_test";
+ private static final String KEY_MIN_RATIO_BG = "concurrency_min_ratio_bg_test";
+ private static final String KEY_MIN_RATIO_BGUSER_IMPORTANT =
+ "concurrency_min_ratio_bguser_important_test";
+ private static final String KEY_MIN_RATIO_BGUSER = "concurrency_min_ratio_bguser_test";
private void check(@Nullable DeviceConfig.Properties config,
+ int defaultLimit,
int defaultTotal,
- @NonNull List<Pair<Integer, Integer>> defaultMin,
- @NonNull List<Pair<Integer, Integer>> defaultMax,
+ @NonNull List<Pair<Integer, Float>> defaultMinRatios,
+ @NonNull List<Pair<Integer, Float>> defaultMaxRatios,
boolean expectedValid, int expectedTotal,
@NonNull List<Pair<Integer, Integer>> expectedMinLimits,
@NonNull List<Pair<Integer, Integer>> expectedMaxLimits) throws Exception {
@@ -69,7 +72,7 @@
final WorkTypeConfig counts;
try {
counts = new WorkTypeConfig("test",
- defaultTotal, defaultMin, defaultMax);
+ defaultLimit, defaultTotal, defaultMinRatios, defaultMaxRatios);
if (!expectedValid) {
fail("Invalid config successfully created");
return;
@@ -84,7 +87,7 @@
}
if (config != null) {
- counts.update(config);
+ counts.update(config, defaultLimit);
}
assertEquals(expectedTotal, counts.getMaxTotal());
@@ -101,7 +104,7 @@
@Test
public void test() throws Exception {
// Tests with various combinations.
- check(null, /*default*/ 13,
+ check(null, /* limit */ 16, /*default*/ 13,
/* min */ List.of(),
/* max */ List.of(),
/*expected*/ true, 13,
@@ -109,111 +112,141 @@
Pair.create(WORK_TYPE_BG, 0), Pair.create(WORK_TYPE_BGUSER, 0)),
/* max */ List.of(Pair.create(WORK_TYPE_TOP, 13), Pair.create(WORK_TYPE_EJ, 13),
Pair.create(WORK_TYPE_BG, 13), Pair.create(WORK_TYPE_BGUSER, 13)));
- check(null, /*default*/ 5,
- /* min */ List.of(Pair.create(WORK_TYPE_TOP, 4), Pair.create(WORK_TYPE_BG, 0)),
- /* max */ List.of(Pair.create(WORK_TYPE_BG, 1)),
+ check(null, /* limit */ 16, /*default*/ 5,
+ /* min */ List.of(Pair.create(WORK_TYPE_TOP, .8f), Pair.create(WORK_TYPE_BG, 0f)),
+ /* max */ List.of(Pair.create(WORK_TYPE_BG, .2f)),
/*expected*/ true, 5,
/* min */ List.of(Pair.create(WORK_TYPE_TOP, 4), Pair.create(WORK_TYPE_BG, 0)),
/* max */ List.of(Pair.create(WORK_TYPE_TOP, 5), Pair.create(WORK_TYPE_BG, 1)));
- check(null, /*default*/ 5,
- /* min */ List.of(Pair.create(WORK_TYPE_TOP, 5),
- Pair.create(WORK_TYPE_BG, 0), Pair.create(WORK_TYPE_BGUSER, 0)),
+ check(null, /* limit */ 16, /*default*/ 5,
+ /* min */ List.of(Pair.create(WORK_TYPE_TOP, 1f),
+ Pair.create(WORK_TYPE_BG, 0f), Pair.create(WORK_TYPE_BGUSER, 0f)),
/* max */ List.of(
- Pair.create(WORK_TYPE_BG, 0), Pair.create(WORK_TYPE_BGUSER, 1)),
- /*expected*/ true, 5,
+ Pair.create(WORK_TYPE_BG, 0f), Pair.create(WORK_TYPE_BGUSER, .2f)),
+ /*expected*/ false, 5,
/* min */ List.of(Pair.create(WORK_TYPE_TOP, 5),
Pair.create(WORK_TYPE_BG, 0), Pair.create(WORK_TYPE_BGUSER, 0)),
/* max */ List.of(Pair.create(WORK_TYPE_TOP, 5),
Pair.create(WORK_TYPE_BG, 1), Pair.create(WORK_TYPE_BGUSER, 1)));
- check(null, /*default*/ 0,
- /* min */ List.of(Pair.create(WORK_TYPE_TOP, 5), Pair.create(WORK_TYPE_BG, 0)),
- /* max */ List.of(Pair.create(WORK_TYPE_BG, 0)),
- /*expected*/ false, 1,
- /* min */ List.of(Pair.create(WORK_TYPE_TOP, 1), Pair.create(WORK_TYPE_BG, 0)),
- /* max */ List.of(Pair.create(WORK_TYPE_TOP, 1), Pair.create(WORK_TYPE_BG, 1)));
- check(null, /*default*/ -1,
- /* min */ List.of(Pair.create(WORK_TYPE_BG, -1)),
- /* max */ List.of(Pair.create(WORK_TYPE_BG, -1)),
- /*expected*/ false, 1,
- /* min */ List.of(Pair.create(WORK_TYPE_TOP, 1), Pair.create(WORK_TYPE_BG, 0)),
- /* max */ List.of(Pair.create(WORK_TYPE_TOP, 1), Pair.create(WORK_TYPE_BG, 1)));
- check(null, /*default*/ 5,
- /* min */ List.of(
- Pair.create(WORK_TYPE_BG, 5), Pair.create(WORK_TYPE_BGUSER, 0)),
+ check(null, /* limit */ 16, /*default*/ 5,
+ /* min */ List.of(Pair.create(WORK_TYPE_TOP, .99f),
+ Pair.create(WORK_TYPE_BG, 0f), Pair.create(WORK_TYPE_BGUSER, 0f)),
/* max */ List.of(
- Pair.create(WORK_TYPE_BG, 5), Pair.create(WORK_TYPE_BGUSER, 5)),
+ Pair.create(WORK_TYPE_BG, .01f), Pair.create(WORK_TYPE_BGUSER, .2f)),
+ /*expected*/ true, 5,
+ /* min */ List.of(Pair.create(WORK_TYPE_TOP, 4),
+ Pair.create(WORK_TYPE_BG, 0), Pair.create(WORK_TYPE_BGUSER, 0)),
+ /* max */ List.of(Pair.create(WORK_TYPE_TOP, 5),
+ Pair.create(WORK_TYPE_BG, 1), Pair.create(WORK_TYPE_BGUSER, 1)));
+ check(null, /* limit */ 16, /*default*/ 0,
+ /* min */ List.of(Pair.create(WORK_TYPE_TOP, 1f), Pair.create(WORK_TYPE_BG, 0f)),
+ /* max */ List.of(Pair.create(WORK_TYPE_BG, 0f)),
+ /*expected*/ false, 1,
+ /* min */ List.of(Pair.create(WORK_TYPE_TOP, 1), Pair.create(WORK_TYPE_BG, 0)),
+ /* max */ List.of(Pair.create(WORK_TYPE_TOP, 1), Pair.create(WORK_TYPE_BG, 1)));
+ check(null, /* limit */ 16, /*default*/ -1,
+ /* min */ List.of(Pair.create(WORK_TYPE_BG, -1f)),
+ /* max */ List.of(Pair.create(WORK_TYPE_BG, -1f)),
+ /*expected*/ false, 1,
+ /* min */ List.of(Pair.create(WORK_TYPE_TOP, 1), Pair.create(WORK_TYPE_BG, 0)),
+ /* max */ List.of(Pair.create(WORK_TYPE_TOP, 1), Pair.create(WORK_TYPE_BG, 1)));
+ check(null, /* limit */ 16, /*default*/ 5,
+ /* min */ List.of(
+ Pair.create(WORK_TYPE_BG, 1f), Pair.create(WORK_TYPE_BGUSER, 0f)),
+ /* max */ List.of(
+ Pair.create(WORK_TYPE_BG, 1f), Pair.create(WORK_TYPE_BGUSER, 1f)),
+ /*expected*/ false, 5,
+ /* min */ List.of(Pair.create(WORK_TYPE_TOP, 1),
+ Pair.create(WORK_TYPE_BG, 4), Pair.create(WORK_TYPE_BGUSER, 0)),
+ /* max */ List.of(Pair.create(WORK_TYPE_TOP, 5),
+ Pair.create(WORK_TYPE_BG, 5), Pair.create(WORK_TYPE_BGUSER, 5)));
+ check(null, /* limit */ 16, /*default*/ 5,
+ /* min */ List.of(
+ Pair.create(WORK_TYPE_BG, .99f), Pair.create(WORK_TYPE_BGUSER, 0f)),
+ /* max */ List.of(
+ Pair.create(WORK_TYPE_BG, 1f), Pair.create(WORK_TYPE_BGUSER, 1f)),
/*expected*/ true, 5,
/* min */ List.of(Pair.create(WORK_TYPE_TOP, 1),
Pair.create(WORK_TYPE_BG, 4), Pair.create(WORK_TYPE_BGUSER, 0)),
/* max */ List.of(Pair.create(WORK_TYPE_TOP, 5),
Pair.create(WORK_TYPE_BG, 5), Pair.create(WORK_TYPE_BGUSER, 5)));
- check(null, /*default*/ 6,
- /* min */ List.of(Pair.create(WORK_TYPE_TOP, 1),
- Pair.create(WORK_TYPE_BG, 6), Pair.create(WORK_TYPE_BGUSER, 2)),
+ check(null, /* limit */ 16, /*default*/ 6,
+ /* min */ List.of(Pair.create(WORK_TYPE_TOP, 1.0f / 6),
+ Pair.create(WORK_TYPE_BG, 1f), Pair.create(WORK_TYPE_BGUSER, 1.0f / 3)),
/* max */ List.of(
- Pair.create(WORK_TYPE_BG, 5), Pair.create(WORK_TYPE_BGUSER, 1)),
+ Pair.create(WORK_TYPE_BG, 1f), Pair.create(WORK_TYPE_BGUSER, 1.0f / 6)),
/*expected*/ false, 6,
/* min */ List.of(Pair.create(WORK_TYPE_TOP, 1),
Pair.create(WORK_TYPE_BG, 5), Pair.create(WORK_TYPE_BGUSER, 0)),
/* max */ List.of(Pair.create(WORK_TYPE_TOP, 6),
Pair.create(WORK_TYPE_BG, 5), Pair.create(WORK_TYPE_BGUSER, 1)));
- check(null, /*default*/ 4,
+ check(null, /* limit */ 16, /*default*/ 4,
/* min */ List.of(
- Pair.create(WORK_TYPE_BG, 6), Pair.create(WORK_TYPE_BGUSER, 6)),
+ Pair.create(WORK_TYPE_BG, 1.5f), Pair.create(WORK_TYPE_BGUSER, 1.5f)),
/* max */ List.of(
- Pair.create(WORK_TYPE_BG, 5), Pair.create(WORK_TYPE_BGUSER, 5)),
+ Pair.create(WORK_TYPE_BG, 1.25f), Pair.create(WORK_TYPE_BGUSER, 1.25f)),
/*expected*/ false, 4,
/* min */ List.of(Pair.create(WORK_TYPE_TOP, 1),
Pair.create(WORK_TYPE_BG, 3), Pair.create(WORK_TYPE_BGUSER, 0)),
/* max */ List.of(Pair.create(WORK_TYPE_TOP, 4),
Pair.create(WORK_TYPE_BG, 4), Pair.create(WORK_TYPE_BGUSER, 4)));
- check(null, /*default*/ 5,
- /* min */ List.of(Pair.create(WORK_TYPE_TOP, 4), Pair.create(WORK_TYPE_BG, 1)),
- /* max */ List.of(Pair.create(WORK_TYPE_BG, 1)),
+ check(null, /* limit */ 16, /*default*/ 5,
+ /* min */ List.of(Pair.create(WORK_TYPE_TOP, .8f), Pair.create(WORK_TYPE_BG, .2f)),
+ /* max */ List.of(Pair.create(WORK_TYPE_BG, .2f)),
/*expected*/ true, 5,
/* min */ List.of(Pair.create(WORK_TYPE_TOP, 4), Pair.create(WORK_TYPE_BG, 1)),
/* max */ List.of(Pair.create(WORK_TYPE_TOP, 5), Pair.create(WORK_TYPE_BG, 1)));
- check(null, /*default*/ 10,
- /* min */ List.of(Pair.create(WORK_TYPE_TOP, 4), Pair.create(WORK_TYPE_EJ, 3),
- Pair.create(WORK_TYPE_BG, 1)),
- /* max */ List.of(Pair.create(WORK_TYPE_BG, 1)),
+ check(null, /* limit */ 16, /*default*/ 10,
+ /* min */ List.of(Pair.create(WORK_TYPE_TOP, .4f), Pair.create(WORK_TYPE_EJ, .3f),
+ Pair.create(WORK_TYPE_BG, .1f)),
+ /* max */ List.of(Pair.create(WORK_TYPE_BG, .1f)),
/*expected*/ true, 10,
/* min */ List.of(Pair.create(WORK_TYPE_TOP, 4), Pair.create(WORK_TYPE_EJ, 3),
Pair.create(WORK_TYPE_BG, 1)),
/* max */ List.of(Pair.create(WORK_TYPE_TOP, 10), Pair.create(WORK_TYPE_BG, 1)));
- check(null, /*default*/ 10,
- /* min */ List.of(Pair.create(WORK_TYPE_TOP, 3), Pair.create(WORK_TYPE_FGS, 2),
- Pair.create(WORK_TYPE_EJ, 1), Pair.create(WORK_TYPE_BG, 1)),
- /* max */ List.of(Pair.create(WORK_TYPE_FGS, 3)),
+ check(null, /* limit */ 16, /*default*/ 10,
+ /* min */ List.of(Pair.create(WORK_TYPE_TOP, .3f), Pair.create(WORK_TYPE_FGS, .2f),
+ Pair.create(WORK_TYPE_EJ, .1f), Pair.create(WORK_TYPE_BG, .1f)),
+ /* max */ List.of(Pair.create(WORK_TYPE_FGS, .3f)),
/*expected*/ true, 10,
/* min */ List.of(Pair.create(WORK_TYPE_TOP, 3), Pair.create(WORK_TYPE_FGS, 2),
Pair.create(WORK_TYPE_EJ, 1), Pair.create(WORK_TYPE_BG, 1)),
/* max */ List.of(Pair.create(WORK_TYPE_FGS, 3)));
- check(null, /*default*/ 15,
- /* min */ List.of(Pair.create(WORK_TYPE_BG, 15)),
- /* max */ List.of(Pair.create(WORK_TYPE_BG, 15)),
+ check(null, /* limit */ 16, /*default*/ 15,
+ /* min */ List.of(Pair.create(WORK_TYPE_BG, .95f)),
+ /* max */ List.of(Pair.create(WORK_TYPE_BG, 1f)),
/*expected*/ true, 15,
/* min */ List.of(Pair.create(WORK_TYPE_TOP, 1), Pair.create(WORK_TYPE_BG, 14)),
/* max */ List.of(Pair.create(WORK_TYPE_TOP, 15), Pair.create(WORK_TYPE_BG, 15)));
- check(null, /*default*/ 16,
- /* min */ List.of(Pair.create(WORK_TYPE_BG, 16)),
- /* max */ List.of(Pair.create(WORK_TYPE_BG, 16)),
+ check(null, /* limit */ 16, /*default*/ 16,
+ /* min */ List.of(Pair.create(WORK_TYPE_BG, .99f)),
+ /* max */ List.of(Pair.create(WORK_TYPE_BG, 1f)),
/*expected*/ true, 16,
/* min */ List.of(Pair.create(WORK_TYPE_TOP, 1), Pair.create(WORK_TYPE_BG, 15)),
/* max */ List.of(Pair.create(WORK_TYPE_TOP, 16), Pair.create(WORK_TYPE_BG, 16)));
- check(null, /*default*/ 20,
+ check(null, /* limit */ 16, /*default*/ 20,
/* min */ List.of(
- Pair.create(WORK_TYPE_BG, 20), Pair.create(WORK_TYPE_BGUSER, 10)),
+ Pair.create(WORK_TYPE_BG, .99f), Pair.create(WORK_TYPE_BGUSER, .5f)),
/* max */ List.of(
- Pair.create(WORK_TYPE_BG, 20), Pair.create(WORK_TYPE_BGUSER, 20)),
+ Pair.create(WORK_TYPE_BG, 1f), Pair.create(WORK_TYPE_BGUSER, 1f)),
/*expected*/ false, 16,
/* min */ List.of(Pair.create(WORK_TYPE_TOP, 1),
Pair.create(WORK_TYPE_BG, 15), Pair.create(WORK_TYPE_BGUSER, 0)),
/* max */ List.of(Pair.create(WORK_TYPE_TOP, 16),
Pair.create(WORK_TYPE_BG, 16), Pair.create(WORK_TYPE_BGUSER, 16)));
- check(null, /*default*/ 20,
- /* min */ List.of(Pair.create(WORK_TYPE_BG, 16)),
- /* max */ List.of(Pair.create(WORK_TYPE_BG, 16)),
+ check(null, /* limit */ 76, /*default*/ 80,
+ /* min */ List.of(
+ Pair.create(WORK_TYPE_BG, .98f), Pair.create(WORK_TYPE_BGUSER, .9f)),
+ /* max */ List.of(
+ Pair.create(WORK_TYPE_BG, 1f), Pair.create(WORK_TYPE_BGUSER, 1f)),
+ /*expected*/ false, 64,
+ /* min */ List.of(Pair.create(WORK_TYPE_TOP, 1),
+ Pair.create(WORK_TYPE_BG, 63), Pair.create(WORK_TYPE_BGUSER, 0)),
+ /* max */ List.of(Pair.create(WORK_TYPE_TOP, 64),
+ Pair.create(WORK_TYPE_BG, 64), Pair.create(WORK_TYPE_BGUSER, 64)));
+ check(null, /* limit */ 16, /*default*/ 20,
+ /* min */ List.of(Pair.create(WORK_TYPE_BG, .99f)),
+ /* max */ List.of(Pair.create(WORK_TYPE_BG, 1f)),
/*expected*/ true, 16,
/* min */ List.of(Pair.create(WORK_TYPE_TOP, 1), Pair.create(WORK_TYPE_BG, 15)),
/* max */ List.of(Pair.create(WORK_TYPE_TOP, 16), Pair.create(WORK_TYPE_BG, 16)));
@@ -221,94 +254,101 @@
// Test for overriding with a setting string.
check(new DeviceConfig.Properties.Builder(DeviceConfig.NAMESPACE_JOB_SCHEDULER)
.setInt(KEY_MAX_TOTAL, 5)
- .setInt(KEY_MAX_BG, 4)
- .setInt(KEY_MIN_BG, 3)
+ .setFloat(KEY_MAX_RATIO_BG, .8f)
+ .setFloat(KEY_MIN_RATIO_BG, .6f)
.build(),
+ /* limit */ 16,
/*default*/ 9,
- /* min */ List.of(Pair.create(WORK_TYPE_BG, 9)),
+ /* min */ List.of(Pair.create(WORK_TYPE_BG, .99f)),
/* max */ List.of(
- Pair.create(WORK_TYPE_BG, 9), Pair.create(WORK_TYPE_BGUSER, 2)),
+ Pair.create(WORK_TYPE_BG, 1f), Pair.create(WORK_TYPE_BGUSER, .4f)),
/*expected*/ true, 5,
/* min */ List.of(Pair.create(WORK_TYPE_TOP, 1), Pair.create(WORK_TYPE_BG, 3)),
/* max */ List.of(Pair.create(WORK_TYPE_TOP, 5),
Pair.create(WORK_TYPE_BG, 4), Pair.create(WORK_TYPE_BGUSER, 2)));
check(new DeviceConfig.Properties.Builder(DeviceConfig.NAMESPACE_JOB_SCHEDULER)
.setInt(KEY_MAX_TOTAL, 5).build(),
+ /* limit */ 16,
/*default*/ 9,
- /* min */ List.of(Pair.create(WORK_TYPE_BG, 9)),
- /* max */ List.of(Pair.create(WORK_TYPE_BG, 9)),
+ /* min */ List.of(Pair.create(WORK_TYPE_BG, .99f)),
+ /* max */ List.of(Pair.create(WORK_TYPE_BG, 1f)),
/*expected*/ true, 5,
/* min */ List.of(Pair.create(WORK_TYPE_TOP, 1), Pair.create(WORK_TYPE_BG, 4)),
/* max */ List.of(Pair.create(WORK_TYPE_TOP, 5), Pair.create(WORK_TYPE_BG, 5)));
check(new DeviceConfig.Properties.Builder(DeviceConfig.NAMESPACE_JOB_SCHEDULER)
- .setInt(KEY_MAX_BG, 4).build(),
+ .setFloat(KEY_MAX_RATIO_BG, 4.0f / 9).build(),
+ /* limit */ 16,
/*default*/ 9,
- /* min */ List.of(Pair.create(WORK_TYPE_BG, 9)),
- /* max */ List.of(Pair.create(WORK_TYPE_BG, 9)),
+ /* min */ List.of(Pair.create(WORK_TYPE_BG, .99f)),
+ /* max */ List.of(Pair.create(WORK_TYPE_BG, 1f)),
/*expected*/ true, 9,
/* min */ List.of(Pair.create(WORK_TYPE_TOP, 1), Pair.create(WORK_TYPE_BG, 4)),
/* max */ List.of(Pair.create(WORK_TYPE_TOP, 9), Pair.create(WORK_TYPE_BG, 4)));
check(new DeviceConfig.Properties.Builder(DeviceConfig.NAMESPACE_JOB_SCHEDULER)
- .setInt(KEY_MIN_BG, 3).build(),
+ .setFloat(KEY_MIN_RATIO_BG, 1.0f / 3).build(),
+ /* limit */ 16,
/*default*/ 9,
- /* min */ List.of(Pair.create(WORK_TYPE_BG, 9)),
- /* max */ List.of(Pair.create(WORK_TYPE_BG, 9)),
+ /* min */ List.of(Pair.create(WORK_TYPE_BG, .99f)),
+ /* max */ List.of(Pair.create(WORK_TYPE_BG, 1f)),
/*expected*/ true, 9,
/* min */ List.of(Pair.create(WORK_TYPE_TOP, 1), Pair.create(WORK_TYPE_BG, 3)),
/* max */ List.of(Pair.create(WORK_TYPE_TOP, 9), Pair.create(WORK_TYPE_BG, 9)));
check(new DeviceConfig.Properties.Builder(DeviceConfig.NAMESPACE_JOB_SCHEDULER)
.setInt(KEY_MAX_TOTAL, 20)
- .setInt(KEY_MAX_EJ, 5)
- .setInt(KEY_MIN_EJ, 2)
- .setInt(KEY_MAX_BG, 16)
- .setInt(KEY_MIN_BG, 8)
+ .setFloat(KEY_MAX_RATIO_EJ, .25f)
+ .setFloat(KEY_MIN_RATIO_EJ, .1f)
+ .setFloat(KEY_MAX_RATIO_BG, .8f)
+ .setFloat(KEY_MIN_RATIO_BG, .4f)
.build(),
+ /* limit */ 16,
/*default*/ 9,
- /* min */ List.of(Pair.create(WORK_TYPE_BG, 9)),
- /* max */ List.of(Pair.create(WORK_TYPE_BG, 9)),
+ /* min */ List.of(Pair.create(WORK_TYPE_BG, .99f)),
+ /* max */ List.of(Pair.create(WORK_TYPE_BG, 1f)),
/*expected*/ true, 16,
- /* min */ List.of(Pair.create(WORK_TYPE_TOP, 1), Pair.create(WORK_TYPE_EJ, 2),
- Pair.create(WORK_TYPE_BG, 8)),
+ /* min */ List.of(Pair.create(WORK_TYPE_TOP, 1), Pair.create(WORK_TYPE_EJ, 1),
+ Pair.create(WORK_TYPE_BG, 6)),
/* max */
- List.of(Pair.create(WORK_TYPE_TOP, 16), Pair.create(WORK_TYPE_EJ, 5),
- Pair.create(WORK_TYPE_BG, 16)));
+ List.of(Pair.create(WORK_TYPE_TOP, 16), Pair.create(WORK_TYPE_EJ, 4),
+ Pair.create(WORK_TYPE_BG, 12)));
check(new DeviceConfig.Properties.Builder(DeviceConfig.NAMESPACE_JOB_SCHEDULER)
.setInt(KEY_MAX_TOTAL, 20)
- .setInt(KEY_MAX_BG, 20)
- .setInt(KEY_MIN_BG, 8)
+ .setFloat(KEY_MAX_RATIO_BG, 1f)
+ .setFloat(KEY_MIN_RATIO_BG, .4f)
.build(),
+ /* limit */ 16,
/*default*/ 9,
- /* min */ List.of(Pair.create(WORK_TYPE_BG, 9)),
- /* max */ List.of(Pair.create(WORK_TYPE_BG, 9)),
+ /* min */ List.of(Pair.create(WORK_TYPE_BG, .99f)),
+ /* max */ List.of(Pair.create(WORK_TYPE_BG, 1f)),
/*expected*/ true, 16,
- /* min */ List.of(Pair.create(WORK_TYPE_TOP, 1), Pair.create(WORK_TYPE_BG, 8)),
+ /* min */ List.of(Pair.create(WORK_TYPE_TOP, 1), Pair.create(WORK_TYPE_BG, 6)),
/* max */ List.of(Pair.create(WORK_TYPE_TOP, 16), Pair.create(WORK_TYPE_BG, 16)));
check(new DeviceConfig.Properties.Builder(DeviceConfig.NAMESPACE_JOB_SCHEDULER)
.setInt(KEY_MAX_TOTAL, 16)
- .setInt(KEY_MAX_TOP, 16)
- .setInt(KEY_MIN_TOP, 1)
- .setInt(KEY_MAX_FGS, 15)
- .setInt(KEY_MIN_FGS, 2)
- .setInt(KEY_MAX_EJ, 14)
- .setInt(KEY_MIN_EJ, 3)
- .setInt(KEY_MAX_BG, 13)
- .setInt(KEY_MIN_BG, 4)
- .setInt(KEY_MAX_BGUSER_IMPORTANT, 12)
- .setInt(KEY_MIN_BGUSER_IMPORTANT, 5)
- .setInt(KEY_MAX_BGUSER, 11)
- .setInt(KEY_MIN_BGUSER, 6)
+ .setFloat(KEY_MAX_RATIO_TOP, 1f)
+ .setFloat(KEY_MIN_RATIO_TOP, 1.0f / 16)
+ .setFloat(KEY_MAX_RATIO_FGS, 15.0f / 16)
+ .setFloat(KEY_MIN_RATIO_FGS, 2.0f / 16)
+ .setFloat(KEY_MAX_RATIO_EJ, 14.0f / 16)
+ .setFloat(KEY_MIN_RATIO_EJ, 3.0f / 16)
+ .setFloat(KEY_MAX_RATIO_BG, 13.0f / 16)
+ .setFloat(KEY_MIN_RATIO_BG, 3.0f / 16)
+ .setFloat(KEY_MAX_RATIO_BGUSER_IMPORTANT, 12.0f / 16)
+ .setFloat(KEY_MIN_RATIO_BGUSER_IMPORTANT, 2.0f / 16)
+ .setFloat(KEY_MAX_RATIO_BGUSER, 11.0f / 16)
+ .setFloat(KEY_MIN_RATIO_BGUSER, 2.0f / 16)
.build(),
+ /* limit */ 16,
/*default*/ 9,
- /* min */ List.of(Pair.create(WORK_TYPE_BG, 9)),
- /* max */ List.of(Pair.create(WORK_TYPE_BG, 9)),
+ /* min */ List.of(Pair.create(WORK_TYPE_BG, .99f)),
+ /* max */ List.of(Pair.create(WORK_TYPE_BG, 1f)),
/*expected*/ true, 16,
/* min */ List.of(Pair.create(WORK_TYPE_TOP, 1), Pair.create(WORK_TYPE_FGS, 2),
- Pair.create(WORK_TYPE_EJ, 3), Pair.create(WORK_TYPE_BG, 4),
- Pair.create(WORK_TYPE_BGUSER_IMPORTANT, 5),
- Pair.create(WORK_TYPE_BGUSER, 6)),
+ Pair.create(WORK_TYPE_EJ, 3), Pair.create(WORK_TYPE_BG, 3),
+ Pair.create(WORK_TYPE_BGUSER_IMPORTANT, 2),
+ Pair.create(WORK_TYPE_BGUSER, 2)),
/* max */
List.of(Pair.create(WORK_TYPE_TOP, 16), Pair.create(WORK_TYPE_FGS, 15),
Pair.create(WORK_TYPE_EJ, 14), Pair.create(WORK_TYPE_BG, 13),
diff --git a/services/tests/servicestests/src/com/android/server/locales/LocaleManagerServiceTest.java b/services/tests/servicestests/src/com/android/server/locales/LocaleManagerServiceTest.java
index 065aec5..07fda30 100644
--- a/services/tests/servicestests/src/com/android/server/locales/LocaleManagerServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/locales/LocaleManagerServiceTest.java
@@ -77,6 +77,7 @@
/* initiatingPackageName = */ null, /* initiatingPackageSigningInfo = */ null,
/* originatingPackageName = */ null,
/* installingPackageName = */ DEFAULT_INSTALLER_PACKAGE_NAME,
+ /* updateOwnerPackageName = */ null,
/* packageSource = */ PackageInstaller.PACKAGE_SOURCE_UNSPECIFIED);
private LocaleManagerService mLocaleManagerService;
diff --git a/services/tests/servicestests/src/com/android/server/locales/SystemAppUpdateTrackerTest.java b/services/tests/servicestests/src/com/android/server/locales/SystemAppUpdateTrackerTest.java
index 494796e..9429462 100644
--- a/services/tests/servicestests/src/com/android/server/locales/SystemAppUpdateTrackerTest.java
+++ b/services/tests/servicestests/src/com/android/server/locales/SystemAppUpdateTrackerTest.java
@@ -89,6 +89,7 @@
/* initiatingPackageName = */ null, /* initiatingPackageSigningInfo = */ null,
/* originatingPackageName = */ null,
/* installingPackageName = */ DEFAULT_INSTALLER_PACKAGE_NAME,
+ /* updateOwnerPackageName = */ null,
/* packageSource = */ PackageInstaller.PACKAGE_SOURCE_UNSPECIFIED);
@Mock
diff --git a/services/tests/servicestests/src/com/android/server/locksettings/RebootEscrowManagerTests.java b/services/tests/servicestests/src/com/android/server/locksettings/RebootEscrowManagerTests.java
index 858f658..d9d0715 100644
--- a/services/tests/servicestests/src/com/android/server/locksettings/RebootEscrowManagerTests.java
+++ b/services/tests/servicestests/src/com/android/server/locksettings/RebootEscrowManagerTests.java
@@ -50,6 +50,8 @@
import android.content.ContextWrapper;
import android.content.pm.UserInfo;
import android.hardware.rebootescrow.IRebootEscrow;
+import android.net.ConnectivityManager;
+import android.net.Network;
import android.os.Handler;
import android.os.HandlerThread;
import android.os.RemoteException;
@@ -72,6 +74,7 @@
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
+import java.util.function.Consumer;
import javax.crypto.SecretKey;
import javax.crypto.spec.SecretKeySpec;
@@ -113,6 +116,7 @@
private RebootEscrowManager mService;
private SecretKey mAesKey;
private MockInjector mMockInjector;
+ private Handler mHandler;
public interface MockableRebootEscrowInjected {
int getBootCount();
@@ -131,6 +135,9 @@
private final RebootEscrowKeyStoreManager mKeyStoreManager;
private boolean mServerBased;
private RebootEscrowProviderInterface mRebootEscrowProviderInUse;
+ private ConnectivityManager.NetworkCallback mNetworkCallback;
+ private Consumer<ConnectivityManager.NetworkCallback> mNetworkConsumer;
+ private boolean mWaitForInternet;
MockInjector(Context context, UserManager userManager,
IRebootEscrow rebootEscrow,
@@ -140,6 +147,7 @@
super(context, storage);
mRebootEscrow = rebootEscrow;
mServerBased = false;
+ mWaitForInternet = false;
RebootEscrowProviderHalImpl.Injector halInjector =
new RebootEscrowProviderHalImpl.Injector() {
@Override
@@ -161,6 +169,7 @@
super(context, storage);
mRebootEscrow = null;
mServerBased = true;
+ mWaitForInternet = false;
RebootEscrowProviderServerBasedImpl.Injector injector =
new RebootEscrowProviderServerBasedImpl.Injector(serviceConnection) {
@Override
@@ -196,11 +205,33 @@
}
@Override
+ public boolean waitForInternet() {
+ return mWaitForInternet;
+ }
+
+ public void setWaitForNetwork(boolean waitForNetworkEnabled) {
+ mWaitForInternet = waitForNetworkEnabled;
+ }
+
+ @Override
public boolean isNetworkConnected() {
return false;
}
@Override
+ public boolean requestNetworkWithInternet(
+ ConnectivityManager.NetworkCallback networkCallback) {
+ mNetworkCallback = networkCallback;
+ mNetworkConsumer.accept(networkCallback);
+ return true;
+ }
+
+ @Override
+ public void stopRequestingNetwork(ConnectivityManager.NetworkCallback networkCallback) {
+ mNetworkCallback = null;
+ }
+
+ @Override
public RebootEscrowProviderInterface createRebootEscrowProviderIfNeeded() {
mRebootEscrowProviderInUse = mDefaultRebootEscrowProvider;
return mRebootEscrowProviderInUse;
@@ -239,6 +270,12 @@
}
@Override
+ public int getLoadEscrowTimeoutMillis() {
+ // Timeout in 3 seconds.
+ return 3000;
+ }
+
+ @Override
public String getVbmetaDigest(boolean other) {
return other ? "" : "fake digest";
}
@@ -288,6 +325,9 @@
mMockInjector = new MockInjector(mContext, mUserManager, mRebootEscrow,
mKeyStoreManager, mStorage, mInjected);
mService = new RebootEscrowManager(mMockInjector, mCallbacks, mStorage);
+ HandlerThread thread = new HandlerThread("RebootEscrowManagerTest");
+ thread.start();
+ mHandler = new Handler(thread.getLooper());
}
private void setServerBasedRebootEscrowProvider() throws Exception {
@@ -459,7 +499,7 @@
@Test
public void loadRebootEscrowDataIfAvailable_NothingAvailable_Success() throws Exception {
- mService.loadRebootEscrowDataIfAvailable(null);
+ mService.loadRebootEscrowDataIfAvailable(mHandler);
}
@Test
@@ -496,7 +536,7 @@
eq(20), eq(0) /* vbmeta status */, anyInt());
when(mRebootEscrow.retrieveKey()).thenAnswer(invocation -> keyByteCaptor.getValue());
- mService.loadRebootEscrowDataIfAvailable(null);
+ mService.loadRebootEscrowDataIfAvailable(mHandler);
verify(mRebootEscrow).retrieveKey();
assertTrue(metricsSuccessCaptor.getValue());
verify(mKeyStoreManager).clearKeyStoreEncryptionKey();
@@ -528,9 +568,16 @@
// pretend reboot happens here
when(mInjected.getBootCount()).thenReturn(1);
ArgumentCaptor<Boolean> metricsSuccessCaptor = ArgumentCaptor.forClass(Boolean.class);
- doNothing().when(mInjected).reportMetric(metricsSuccessCaptor.capture(),
- eq(0) /* error code */, eq(2) /* Server based */, eq(1) /* attempt count */,
- anyInt(), eq(0) /* vbmeta status */, anyInt());
+ doNothing()
+ .when(mInjected)
+ .reportMetric(
+ metricsSuccessCaptor.capture(),
+ eq(0) /* error code */,
+ eq(2) /* Server based */,
+ eq(1) /* attempt count */,
+ anyInt(),
+ eq(0) /* vbmeta status */,
+ anyInt());
when(mServiceConnection.unwrap(any(), anyLong()))
.thenAnswer(invocation -> invocation.getArgument(0));
@@ -566,15 +613,23 @@
when(mInjected.getBootCount()).thenReturn(1);
ArgumentCaptor<Boolean> metricsSuccessCaptor = ArgumentCaptor.forClass(Boolean.class);
ArgumentCaptor<Integer> metricsErrorCodeCaptor = ArgumentCaptor.forClass(Integer.class);
- doNothing().when(mInjected).reportMetric(metricsSuccessCaptor.capture(),
- metricsErrorCodeCaptor.capture(), eq(2) /* Server based */,
- eq(1) /* attempt count */, anyInt(), eq(0) /* vbmeta status */, anyInt());
+ doNothing()
+ .when(mInjected)
+ .reportMetric(
+ metricsSuccessCaptor.capture(),
+ metricsErrorCodeCaptor.capture(),
+ eq(2) /* Server based */,
+ eq(1) /* attempt count */,
+ anyInt(),
+ eq(0) /* vbmeta status */,
+ anyInt());
when(mServiceConnection.unwrap(any(), anyLong())).thenThrow(RemoteException.class);
mService.loadRebootEscrowDataIfAvailable(null);
verify(mServiceConnection).unwrap(any(), anyLong());
assertFalse(metricsSuccessCaptor.getValue());
- assertEquals(Integer.valueOf(RebootEscrowManager.ERROR_LOAD_ESCROW_KEY),
+ assertEquals(
+ Integer.valueOf(RebootEscrowManager.ERROR_LOAD_ESCROW_KEY),
metricsErrorCodeCaptor.getValue());
}
@@ -603,18 +658,24 @@
when(mInjected.getBootCount()).thenReturn(1);
ArgumentCaptor<Boolean> metricsSuccessCaptor = ArgumentCaptor.forClass(Boolean.class);
ArgumentCaptor<Integer> metricsErrorCodeCaptor = ArgumentCaptor.forClass(Integer.class);
- doNothing().when(mInjected).reportMetric(metricsSuccessCaptor.capture(),
- metricsErrorCodeCaptor.capture(), eq(2) /* Server based */,
- eq(2) /* attempt count */, anyInt(), eq(0) /* vbmeta status */, anyInt());
+ doNothing()
+ .when(mInjected)
+ .reportMetric(
+ metricsSuccessCaptor.capture(),
+ metricsErrorCodeCaptor.capture(),
+ eq(2) /* Server based */,
+ eq(2) /* attempt count */,
+ anyInt(),
+ eq(0) /* vbmeta status */,
+ anyInt());
when(mServiceConnection.unwrap(any(), anyLong())).thenThrow(IOException.class);
- HandlerThread thread = new HandlerThread("RebootEscrowManagerTest");
- thread.start();
- mService.loadRebootEscrowDataIfAvailable(new Handler(thread.getLooper()));
+ mService.loadRebootEscrowDataIfAvailable(mHandler);
// Sleep 5s for the retry to complete
Thread.sleep(5 * 1000);
assertFalse(metricsSuccessCaptor.getValue());
- assertEquals(Integer.valueOf(RebootEscrowManager.ERROR_NO_NETWORK),
+ assertEquals(
+ Integer.valueOf(RebootEscrowManager.ERROR_NO_NETWORK),
metricsErrorCodeCaptor.getValue());
}
@@ -642,16 +703,22 @@
// pretend reboot happens here
when(mInjected.getBootCount()).thenReturn(1);
ArgumentCaptor<Boolean> metricsSuccessCaptor = ArgumentCaptor.forClass(Boolean.class);
- doNothing().when(mInjected).reportMetric(metricsSuccessCaptor.capture(),
- anyInt(), anyInt(), eq(2) /* attempt count */, anyInt(), anyInt(), anyInt());
+ doNothing()
+ .when(mInjected)
+ .reportMetric(
+ metricsSuccessCaptor.capture(),
+ anyInt(),
+ anyInt(),
+ eq(2) /* attempt count */,
+ anyInt(),
+ anyInt(),
+ anyInt());
when(mServiceConnection.unwrap(any(), anyLong()))
.thenThrow(new IOException())
.thenAnswer(invocation -> invocation.getArgument(0));
- HandlerThread thread = new HandlerThread("RebootEscrowManagerTest");
- thread.start();
- mService.loadRebootEscrowDataIfAvailable(new Handler(thread.getLooper()));
+ mService.loadRebootEscrowDataIfAvailable(mHandler);
// Sleep 5s for the retry to complete
Thread.sleep(5 * 1000);
verify(mServiceConnection, times(2)).unwrap(any(), anyLong());
@@ -660,6 +727,447 @@
}
@Test
+ public void loadRebootEscrowDataIfAvailable_serverBasedWaitForInternet_success()
+ throws Exception {
+ setServerBasedRebootEscrowProvider();
+ mMockInjector.setWaitForNetwork(true);
+
+ when(mInjected.getBootCount()).thenReturn(0);
+ RebootEscrowListener mockListener = mock(RebootEscrowListener.class);
+ mService.setRebootEscrowListener(mockListener);
+ mService.prepareRebootEscrow();
+
+ clearInvocations(mServiceConnection);
+ mService.callToRebootEscrowIfNeeded(PRIMARY_USER_ID, FAKE_SP_VERSION, FAKE_AUTH_TOKEN);
+ verify(mockListener).onPreparedForReboot(eq(true));
+ verify(mServiceConnection, never()).wrapBlob(any(), anyLong(), anyLong());
+
+ // Use x -> x for both wrap & unwrap functions.
+ when(mServiceConnection.wrapBlob(any(), anyLong(), anyLong()))
+ .thenAnswer(invocation -> invocation.getArgument(0));
+ assertEquals(ARM_REBOOT_ERROR_NONE, mService.armRebootEscrowIfNeeded());
+ verify(mServiceConnection).wrapBlob(any(), anyLong(), anyLong());
+ assertTrue(mStorage.hasRebootEscrowServerBlob());
+
+ // pretend reboot happens here
+ when(mInjected.getBootCount()).thenReturn(1);
+ ArgumentCaptor<Boolean> metricsSuccessCaptor = ArgumentCaptor.forClass(Boolean.class);
+ doNothing()
+ .when(mInjected)
+ .reportMetric(
+ metricsSuccessCaptor.capture(),
+ eq(0) /* error code */,
+ eq(2) /* Server based */,
+ eq(1) /* attempt count */,
+ anyInt(),
+ eq(0) /* vbmeta status */,
+ anyInt());
+
+ // load escrow data
+ when(mServiceConnection.unwrap(any(), anyLong()))
+ .thenAnswer(invocation -> invocation.getArgument(0));
+ Network mockNetwork = mock(Network.class);
+ mMockInjector.mNetworkConsumer =
+ (callback) -> {
+ callback.onAvailable(mockNetwork);
+ };
+
+ mService.loadRebootEscrowDataIfAvailable(mHandler);
+ verify(mServiceConnection).unwrap(any(), anyLong());
+ assertTrue(metricsSuccessCaptor.getValue());
+ verify(mKeyStoreManager).clearKeyStoreEncryptionKey();
+ assertNull(mMockInjector.mNetworkCallback);
+ }
+
+ @Test
+ public void loadRebootEscrowDataIfAvailable_serverBasedWaitForInternetRemoteException_Failure()
+ throws Exception {
+ setServerBasedRebootEscrowProvider();
+ mMockInjector.setWaitForNetwork(true);
+
+ when(mInjected.getBootCount()).thenReturn(0);
+ RebootEscrowListener mockListener = mock(RebootEscrowListener.class);
+ mService.setRebootEscrowListener(mockListener);
+ mService.prepareRebootEscrow();
+
+ clearInvocations(mServiceConnection);
+ mService.callToRebootEscrowIfNeeded(PRIMARY_USER_ID, FAKE_SP_VERSION, FAKE_AUTH_TOKEN);
+ verify(mockListener).onPreparedForReboot(eq(true));
+ verify(mServiceConnection, never()).wrapBlob(any(), anyLong(), anyLong());
+
+ // Use x -> x for both wrap & unwrap functions.
+ when(mServiceConnection.wrapBlob(any(), anyLong(), anyLong()))
+ .thenAnswer(invocation -> invocation.getArgument(0));
+ assertEquals(ARM_REBOOT_ERROR_NONE, mService.armRebootEscrowIfNeeded());
+ verify(mServiceConnection).wrapBlob(any(), anyLong(), anyLong());
+ assertTrue(mStorage.hasRebootEscrowServerBlob());
+
+ // pretend reboot happens here
+ when(mInjected.getBootCount()).thenReturn(1);
+ ArgumentCaptor<Boolean> metricsSuccessCaptor = ArgumentCaptor.forClass(Boolean.class);
+ ArgumentCaptor<Integer> metricsErrorCodeCaptor = ArgumentCaptor.forClass(Integer.class);
+ doNothing()
+ .when(mInjected)
+ .reportMetric(
+ metricsSuccessCaptor.capture(),
+ metricsErrorCodeCaptor.capture(),
+ eq(2) /* Server based */,
+ eq(1) /* attempt count */,
+ anyInt(),
+ eq(0) /* vbmeta status */,
+ anyInt());
+
+ // load escrow data
+ when(mServiceConnection.unwrap(any(), anyLong())).thenThrow(RemoteException.class);
+ Network mockNetwork = mock(Network.class);
+ mMockInjector.mNetworkConsumer =
+ (callback) -> {
+ callback.onAvailable(mockNetwork);
+ };
+
+ mService.loadRebootEscrowDataIfAvailable(mHandler);
+ verify(mServiceConnection).unwrap(any(), anyLong());
+ assertFalse(metricsSuccessCaptor.getValue());
+ assertEquals(
+ Integer.valueOf(RebootEscrowManager.ERROR_LOAD_ESCROW_KEY),
+ metricsErrorCodeCaptor.getValue());
+ assertNull(mMockInjector.mNetworkCallback);
+ }
+
+ @Test
+ public void loadRebootEscrowDataIfAvailable_waitForInternet_networkUnavailable()
+ throws Exception {
+ setServerBasedRebootEscrowProvider();
+ mMockInjector.setWaitForNetwork(true);
+
+ when(mInjected.getBootCount()).thenReturn(0);
+ RebootEscrowListener mockListener = mock(RebootEscrowListener.class);
+ mService.setRebootEscrowListener(mockListener);
+ mService.prepareRebootEscrow();
+
+ clearInvocations(mServiceConnection);
+ mService.callToRebootEscrowIfNeeded(PRIMARY_USER_ID, FAKE_SP_VERSION, FAKE_AUTH_TOKEN);
+ verify(mockListener).onPreparedForReboot(eq(true));
+ verify(mServiceConnection, never()).wrapBlob(any(), anyLong(), anyLong());
+
+ // Use x -> x for both wrap & unwrap functions.
+ when(mServiceConnection.wrapBlob(any(), anyLong(), anyLong()))
+ .thenAnswer(invocation -> invocation.getArgument(0));
+ assertEquals(ARM_REBOOT_ERROR_NONE, mService.armRebootEscrowIfNeeded());
+ verify(mServiceConnection).wrapBlob(any(), anyLong(), anyLong());
+ assertTrue(mStorage.hasRebootEscrowServerBlob());
+
+ // pretend reboot happens here
+ when(mInjected.getBootCount()).thenReturn(1);
+ ArgumentCaptor<Boolean> metricsSuccessCaptor = ArgumentCaptor.forClass(Boolean.class);
+ ArgumentCaptor<Integer> metricsErrorCodeCaptor = ArgumentCaptor.forClass(Integer.class);
+ doNothing()
+ .when(mInjected)
+ .reportMetric(
+ metricsSuccessCaptor.capture(),
+ metricsErrorCodeCaptor.capture(),
+ eq(2) /* Server based */,
+ eq(0) /* attempt count */,
+ anyInt(),
+ eq(0) /* vbmeta status */,
+ anyInt());
+
+ // Network is not available within timeout.
+ mMockInjector.mNetworkConsumer = ConnectivityManager.NetworkCallback::onUnavailable;
+ mService.loadRebootEscrowDataIfAvailable(mHandler);
+ assertFalse(metricsSuccessCaptor.getValue());
+ assertEquals(
+ Integer.valueOf(RebootEscrowManager.ERROR_NO_NETWORK),
+ metricsErrorCodeCaptor.getValue());
+ assertNull(mMockInjector.mNetworkCallback);
+ }
+
+ @Test
+ public void loadRebootEscrowDataIfAvailable_waitForInternet_networkLost() throws Exception {
+ setServerBasedRebootEscrowProvider();
+ mMockInjector.setWaitForNetwork(true);
+
+ when(mInjected.getBootCount()).thenReturn(0);
+ RebootEscrowListener mockListener = mock(RebootEscrowListener.class);
+ mService.setRebootEscrowListener(mockListener);
+ mService.prepareRebootEscrow();
+
+ clearInvocations(mServiceConnection);
+ mService.callToRebootEscrowIfNeeded(PRIMARY_USER_ID, FAKE_SP_VERSION, FAKE_AUTH_TOKEN);
+ verify(mockListener).onPreparedForReboot(eq(true));
+ verify(mServiceConnection, never()).wrapBlob(any(), anyLong(), anyLong());
+
+ // Use x -> x for both wrap & unwrap functions.
+ when(mServiceConnection.wrapBlob(any(), anyLong(), anyLong()))
+ .thenAnswer(invocation -> invocation.getArgument(0));
+ assertEquals(ARM_REBOOT_ERROR_NONE, mService.armRebootEscrowIfNeeded());
+ verify(mServiceConnection).wrapBlob(any(), anyLong(), anyLong());
+ assertTrue(mStorage.hasRebootEscrowServerBlob());
+
+ // pretend reboot happens here
+ when(mInjected.getBootCount()).thenReturn(1);
+ ArgumentCaptor<Boolean> metricsSuccessCaptor = ArgumentCaptor.forClass(Boolean.class);
+ ArgumentCaptor<Integer> metricsErrorCodeCaptor = ArgumentCaptor.forClass(Integer.class);
+ doNothing()
+ .when(mInjected)
+ .reportMetric(
+ metricsSuccessCaptor.capture(),
+ metricsErrorCodeCaptor.capture(),
+ eq(2) /* Server based */,
+ eq(2) /* attempt count */,
+ anyInt(),
+ eq(0) /* vbmeta status */,
+ anyInt());
+
+ // Network is available, then lost.
+ when(mServiceConnection.unwrap(any(), anyLong())).thenThrow(new IOException());
+ Network mockNetwork = mock(Network.class);
+ mMockInjector.mNetworkConsumer =
+ (callback) -> {
+ callback.onAvailable(mockNetwork);
+ callback.onLost(mockNetwork);
+ };
+ mService.loadRebootEscrowDataIfAvailable(mHandler);
+ // Sleep 5s for the retry to complete
+ Thread.sleep(5 * 1000);
+ assertFalse(metricsSuccessCaptor.getValue());
+ assertEquals(
+ Integer.valueOf(RebootEscrowManager.ERROR_NO_NETWORK),
+ metricsErrorCodeCaptor.getValue());
+ assertNull(mMockInjector.mNetworkCallback);
+ }
+
+ @Test
+ public void loadRebootEscrowDataIfAvailable_waitForInternet_networkAvailableWithDelay()
+ throws Exception {
+ setServerBasedRebootEscrowProvider();
+ mMockInjector.setWaitForNetwork(true);
+
+ when(mInjected.getBootCount()).thenReturn(0);
+ RebootEscrowListener mockListener = mock(RebootEscrowListener.class);
+ mService.setRebootEscrowListener(mockListener);
+ mService.prepareRebootEscrow();
+
+ clearInvocations(mServiceConnection);
+ mService.callToRebootEscrowIfNeeded(PRIMARY_USER_ID, FAKE_SP_VERSION, FAKE_AUTH_TOKEN);
+ verify(mockListener).onPreparedForReboot(eq(true));
+ verify(mServiceConnection, never()).wrapBlob(any(), anyLong(), anyLong());
+
+ // Use x -> x for both wrap & unwrap functions.
+ when(mServiceConnection.wrapBlob(any(), anyLong(), anyLong()))
+ .thenAnswer(invocation -> invocation.getArgument(0));
+ assertEquals(ARM_REBOOT_ERROR_NONE, mService.armRebootEscrowIfNeeded());
+ verify(mServiceConnection).wrapBlob(any(), anyLong(), anyLong());
+ assertTrue(mStorage.hasRebootEscrowServerBlob());
+
+ // pretend reboot happens here
+ when(mInjected.getBootCount()).thenReturn(1);
+ ArgumentCaptor<Boolean> metricsSuccessCaptor = ArgumentCaptor.forClass(Boolean.class);
+ ArgumentCaptor<Integer> metricsErrorCodeCaptor = ArgumentCaptor.forClass(Integer.class);
+ doNothing()
+ .when(mInjected)
+ .reportMetric(
+ metricsSuccessCaptor.capture(),
+ metricsErrorCodeCaptor.capture(),
+ eq(2) /* Server based */,
+ eq(1) /* attempt count */,
+ anyInt(),
+ eq(0) /* vbmeta status */,
+ anyInt());
+
+ // load escrow data
+ when(mServiceConnection.unwrap(any(), anyLong()))
+ .thenAnswer(invocation -> invocation.getArgument(0));
+ // network available after 1 sec
+ Network mockNetwork = mock(Network.class);
+ mMockInjector.mNetworkConsumer =
+ (callback) -> {
+ try {
+ Thread.sleep(1000);
+ } catch (InterruptedException e) {
+ throw new RuntimeException(e);
+ }
+ callback.onAvailable(mockNetwork);
+ };
+ mService.loadRebootEscrowDataIfAvailable(mHandler);
+ verify(mServiceConnection).unwrap(any(), anyLong());
+ assertTrue(metricsSuccessCaptor.getValue());
+ verify(mKeyStoreManager).clearKeyStoreEncryptionKey();
+ assertNull(mMockInjector.mNetworkCallback);
+ }
+
+ @Test
+ public void loadRebootEscrowDataIfAvailable_waitForInternet_timeoutExhausted()
+ throws Exception {
+ setServerBasedRebootEscrowProvider();
+ mMockInjector.setWaitForNetwork(true);
+
+ when(mInjected.getBootCount()).thenReturn(0);
+ RebootEscrowListener mockListener = mock(RebootEscrowListener.class);
+ mService.setRebootEscrowListener(mockListener);
+ mService.prepareRebootEscrow();
+
+ clearInvocations(mServiceConnection);
+ mService.callToRebootEscrowIfNeeded(PRIMARY_USER_ID, FAKE_SP_VERSION, FAKE_AUTH_TOKEN);
+ verify(mockListener).onPreparedForReboot(eq(true));
+ verify(mServiceConnection, never()).wrapBlob(any(), anyLong(), anyLong());
+
+ // Use x -> x for both wrap & unwrap functions.
+ when(mServiceConnection.wrapBlob(any(), anyLong(), anyLong()))
+ .thenAnswer(invocation -> invocation.getArgument(0));
+ assertEquals(ARM_REBOOT_ERROR_NONE, mService.armRebootEscrowIfNeeded());
+ verify(mServiceConnection).wrapBlob(any(), anyLong(), anyLong());
+ assertTrue(mStorage.hasRebootEscrowServerBlob());
+
+ // pretend reboot happens here
+ when(mInjected.getBootCount()).thenReturn(1);
+ ArgumentCaptor<Boolean> metricsSuccessCaptor = ArgumentCaptor.forClass(Boolean.class);
+ ArgumentCaptor<Integer> metricsErrorCodeCaptor = ArgumentCaptor.forClass(Integer.class);
+ doNothing()
+ .when(mInjected)
+ .reportMetric(
+ metricsSuccessCaptor.capture(),
+ metricsErrorCodeCaptor.capture(),
+ eq(2) /* Server based */,
+ eq(1) /* attempt count */,
+ anyInt(),
+ eq(0) /* vbmeta status */,
+ anyInt());
+
+ // load reboot escrow data
+ when(mServiceConnection.unwrap(any(), anyLong())).thenThrow(IOException.class);
+ Network mockNetwork = mock(Network.class);
+ // wait past timeout
+ mMockInjector.mNetworkConsumer =
+ (callback) -> {
+ try {
+ Thread.sleep(3500);
+ } catch (InterruptedException e) {
+ throw new RuntimeException(e);
+ }
+ callback.onAvailable(mockNetwork);
+ };
+ mService.loadRebootEscrowDataIfAvailable(mHandler);
+ verify(mServiceConnection).unwrap(any(), anyLong());
+ assertFalse(metricsSuccessCaptor.getValue());
+ assertEquals(
+ Integer.valueOf(RebootEscrowManager.ERROR_TIMEOUT_EXHAUSTED),
+ metricsErrorCodeCaptor.getValue());
+ assertNull(mMockInjector.mNetworkCallback);
+ }
+
+ @Test
+ public void loadRebootEscrowDataIfAvailable_serverBasedWaitForNetwork_retryCountExhausted()
+ throws Exception {
+ setServerBasedRebootEscrowProvider();
+ mMockInjector.setWaitForNetwork(true);
+
+ when(mInjected.getBootCount()).thenReturn(0);
+ RebootEscrowListener mockListener = mock(RebootEscrowListener.class);
+ mService.setRebootEscrowListener(mockListener);
+ mService.prepareRebootEscrow();
+
+ clearInvocations(mServiceConnection);
+ mService.callToRebootEscrowIfNeeded(PRIMARY_USER_ID, FAKE_SP_VERSION, FAKE_AUTH_TOKEN);
+ verify(mockListener).onPreparedForReboot(eq(true));
+ verify(mServiceConnection, never()).wrapBlob(any(), anyLong(), anyLong());
+
+ // Use x -> x for both wrap & unwrap functions.
+ when(mServiceConnection.wrapBlob(any(), anyLong(), anyLong()))
+ .thenAnswer(invocation -> invocation.getArgument(0));
+ assertEquals(ARM_REBOOT_ERROR_NONE, mService.armRebootEscrowIfNeeded());
+ verify(mServiceConnection).wrapBlob(any(), anyLong(), anyLong());
+ assertTrue(mStorage.hasRebootEscrowServerBlob());
+
+ // pretend reboot happens here
+ when(mInjected.getBootCount()).thenReturn(1);
+ ArgumentCaptor<Boolean> metricsSuccessCaptor = ArgumentCaptor.forClass(Boolean.class);
+ ArgumentCaptor<Integer> metricsErrorCodeCaptor = ArgumentCaptor.forClass(Integer.class);
+ doNothing()
+ .when(mInjected)
+ .reportMetric(
+ metricsSuccessCaptor.capture(),
+ metricsErrorCodeCaptor.capture(),
+ eq(2) /* Server based */,
+ eq(2) /* attempt count */,
+ anyInt(),
+ eq(0) /* vbmeta status */,
+ anyInt());
+
+ when(mServiceConnection.unwrap(any(), anyLong())).thenThrow(new IOException());
+ Network mockNetwork = mock(Network.class);
+ mMockInjector.mNetworkConsumer =
+ (callback) -> {
+ callback.onAvailable(mockNetwork);
+ };
+
+ mService.loadRebootEscrowDataIfAvailable(mHandler);
+ // Sleep 5s for the retry to complete
+ Thread.sleep(5 * 1000);
+ verify(mServiceConnection, times(2)).unwrap(any(), anyLong());
+ assertFalse(metricsSuccessCaptor.getValue());
+ assertEquals(
+ Integer.valueOf(RebootEscrowManager.ERROR_RETRY_COUNT_EXHAUSTED),
+ metricsErrorCodeCaptor.getValue());
+ assertNull(mMockInjector.mNetworkCallback);
+ }
+
+ @Test
+ public void loadRebootEscrowDataIfAvailable_ServerBasedWaitForInternet_RetrySuccess()
+ throws Exception {
+ setServerBasedRebootEscrowProvider();
+ mMockInjector.setWaitForNetwork(true);
+
+ when(mInjected.getBootCount()).thenReturn(0);
+ RebootEscrowListener mockListener = mock(RebootEscrowListener.class);
+ mService.setRebootEscrowListener(mockListener);
+ mService.prepareRebootEscrow();
+
+ clearInvocations(mServiceConnection);
+ mService.callToRebootEscrowIfNeeded(PRIMARY_USER_ID, FAKE_SP_VERSION, FAKE_AUTH_TOKEN);
+ verify(mockListener).onPreparedForReboot(eq(true));
+ verify(mServiceConnection, never()).wrapBlob(any(), anyLong(), anyLong());
+
+ // Use x -> x for both wrap & unwrap functions.
+ when(mServiceConnection.wrapBlob(any(), anyLong(), anyLong()))
+ .thenAnswer(invocation -> invocation.getArgument(0));
+ assertEquals(ARM_REBOOT_ERROR_NONE, mService.armRebootEscrowIfNeeded());
+ verify(mServiceConnection).wrapBlob(any(), anyLong(), anyLong());
+ assertTrue(mStorage.hasRebootEscrowServerBlob());
+
+ // pretend reboot happens here
+ when(mInjected.getBootCount()).thenReturn(1);
+ ArgumentCaptor<Boolean> metricsSuccessCaptor = ArgumentCaptor.forClass(Boolean.class);
+ doNothing()
+ .when(mInjected)
+ .reportMetric(
+ metricsSuccessCaptor.capture(),
+ anyInt(),
+ anyInt(),
+ eq(2) /* attempt count */,
+ anyInt(),
+ anyInt(),
+ anyInt());
+
+ when(mServiceConnection.unwrap(any(), anyLong()))
+ .thenThrow(new IOException())
+ .thenAnswer(invocation -> invocation.getArgument(0));
+ Network mockNetwork = mock(Network.class);
+ mMockInjector.mNetworkConsumer =
+ (callback) -> {
+ callback.onAvailable(mockNetwork);
+ };
+
+ mService.loadRebootEscrowDataIfAvailable(mHandler);
+ // Sleep 5s for the retry to complete
+ Thread.sleep(5 * 1000);
+ verify(mServiceConnection, times(2)).unwrap(any(), anyLong());
+ assertTrue(metricsSuccessCaptor.getValue());
+ verify(mKeyStoreManager).clearKeyStoreEncryptionKey();
+ assertNull(mMockInjector.mNetworkCallback);
+ }
+
+ @Test
public void loadRebootEscrowDataIfAvailable_TooManyBootsInBetween_NoMetrics() throws Exception {
when(mInjected.getBootCount()).thenReturn(0);
@@ -684,7 +1192,7 @@
when(mInjected.getBootCount()).thenReturn(10);
when(mRebootEscrow.retrieveKey()).thenReturn(new byte[32]);
- mService.loadRebootEscrowDataIfAvailable(null);
+ mService.loadRebootEscrowDataIfAvailable(mHandler);
verify(mRebootEscrow).retrieveKey();
verify(mInjected, never()).reportMetric(anyBoolean(), anyInt(), anyInt(), anyInt(),
anyInt(), anyInt(), anyInt());
@@ -712,7 +1220,7 @@
when(mInjected.getBootCount()).thenReturn(10);
when(mRebootEscrow.retrieveKey()).thenReturn(new byte[32]);
- mService.loadRebootEscrowDataIfAvailable(null);
+ mService.loadRebootEscrowDataIfAvailable(mHandler);
verify(mInjected, never()).reportMetric(anyBoolean(), anyInt(), anyInt(), anyInt(),
anyInt(), anyInt(), anyInt());
}
@@ -750,7 +1258,7 @@
// Trigger a vbmeta digest mismatch
mStorage.setString(RebootEscrowManager.REBOOT_ESCROW_KEY_VBMETA_DIGEST,
"non sense value", USER_SYSTEM);
- mService.loadRebootEscrowDataIfAvailable(null);
+ mService.loadRebootEscrowDataIfAvailable(mHandler);
verify(mInjected).reportMetric(eq(true), eq(0) /* error code */, eq(1) /* HAL based */,
eq(1) /* attempt count */, anyInt(), eq(2) /* vbmeta status */, anyInt());
assertEquals(mStorage.getString(RebootEscrowManager.REBOOT_ESCROW_KEY_VBMETA_DIGEST,
@@ -787,7 +1295,7 @@
eq(1) /* attempt count */, anyInt(), anyInt(), anyInt());
when(mRebootEscrow.retrieveKey()).thenAnswer(invocation -> null);
- mService.loadRebootEscrowDataIfAvailable(null);
+ mService.loadRebootEscrowDataIfAvailable(mHandler);
verify(mRebootEscrow).retrieveKey();
assertFalse(metricsSuccessCaptor.getValue());
assertEquals(Integer.valueOf(RebootEscrowManager.ERROR_LOAD_ESCROW_KEY),
diff --git a/services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/RecoverableKeyStoreManagerTest.java b/services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/RecoverableKeyStoreManagerTest.java
index 281195d..1b983f0b 100644
--- a/services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/RecoverableKeyStoreManagerTest.java
+++ b/services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/RecoverableKeyStoreManagerTest.java
@@ -1073,7 +1073,9 @@
int uid = Binder.getCallingUid();
PendingIntent intent = PendingIntent.getBroadcast(
InstrumentationRegistry.getTargetContext(), /*requestCode=*/1,
- new Intent(), /*flags=*/ PendingIntent.FLAG_MUTABLE_UNAUDITED);
+ new Intent()
+ .setPackage(InstrumentationRegistry.getTargetContext().getPackageName()),
+ /*flags=*/ PendingIntent.FLAG_MUTABLE);
mRecoverableKeyStoreManager.setSnapshotCreatedPendingIntent(intent);
verify(mMockListenersStorage).setSnapshotListener(eq(uid), any(PendingIntent.class));
}
diff --git a/services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/RecoverySnapshotListenersStorageTest.java b/services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/RecoverySnapshotListenersStorageTest.java
index d9ebb4c..418d474 100644
--- a/services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/RecoverySnapshotListenersStorageTest.java
+++ b/services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/RecoverySnapshotListenersStorageTest.java
@@ -41,7 +41,9 @@
int recoveryAgentUid = 1000;
PendingIntent intent = PendingIntent.getBroadcast(
InstrumentationRegistry.getTargetContext(), /*requestCode=*/ 1,
- new Intent(), /*flags=*/ PendingIntent.FLAG_MUTABLE_UNAUDITED);
+ new Intent()
+ .setPackage(InstrumentationRegistry.getTargetContext().getPackageName()),
+ /*flags=*/ PendingIntent.FLAG_MUTABLE);
mStorage.setSnapshotListener(recoveryAgentUid, intent);
assertTrue(mStorage.hasListener(recoveryAgentUid));
@@ -54,7 +56,9 @@
int recoveryAgentUid = 1000;
mStorage.recoverySnapshotAvailable(recoveryAgentUid);
PendingIntent intent = PendingIntent.getBroadcast(
- context, /*requestCode=*/ 0, new Intent(TEST_INTENT_ACTION), /*flags=*/PendingIntent.FLAG_MUTABLE_UNAUDITED);
+ context, /*requestCode=*/ 0,
+ new Intent(TEST_INTENT_ACTION).setPackage(context.getPackageName()),
+ /*flags=*/PendingIntent.FLAG_MUTABLE);
CountDownLatch latch = new CountDownLatch(1);
context.registerReceiver(new BroadcastReceiver() {
@Override
@@ -75,7 +79,9 @@
int recoveryAgentUid = 1000;
mStorage.recoverySnapshotAvailable(recoveryAgentUid);
PendingIntent intent = PendingIntent.getBroadcast(
- context, /*requestCode=*/ 0, new Intent(TEST_INTENT_ACTION), /*flags=*/PendingIntent.FLAG_MUTABLE_UNAUDITED);
+ context, /*requestCode=*/ 0,
+ new Intent(TEST_INTENT_ACTION).setPackage(context.getPackageName()),
+ /*flags=*/PendingIntent.FLAG_MUTABLE);
CountDownLatch latch = new CountDownLatch(2);
BroadcastReceiver broadcastReceiver = new BroadcastReceiver() {
@Override
diff --git a/services/tests/servicestests/src/com/android/server/NetworkManagementServiceTest.java b/services/tests/servicestests/src/com/android/server/net/NetworkManagementServiceTest.java
similarity index 98%
rename from services/tests/servicestests/src/com/android/server/NetworkManagementServiceTest.java
rename to services/tests/servicestests/src/com/android/server/net/NetworkManagementServiceTest.java
index 17a5876..d9cd77d 100644
--- a/services/tests/servicestests/src/com/android/server/NetworkManagementServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/net/NetworkManagementServiceTest.java
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package com.android.server;
+package com.android.server.net;
import static android.net.ConnectivityManager.FIREWALL_CHAIN_DOZABLE;
import static android.net.ConnectivityManager.FIREWALL_CHAIN_LOW_POWER_STANDBY;
@@ -51,14 +51,13 @@
import android.os.Process;
import android.os.RemoteException;
import android.permission.PermissionCheckerManager;
+import android.platform.test.annotations.Presubmit;
import android.test.suitebuilder.annotation.SmallTest;
import android.util.ArrayMap;
import androidx.test.runner.AndroidJUnit4;
import com.android.internal.app.IBatteryStats;
-import com.android.server.NetworkManagementService.Dependencies;
-import com.android.server.net.BaseNetworkObserver;
import org.junit.After;
import org.junit.Before;
@@ -76,6 +75,7 @@
*/
@RunWith(AndroidJUnit4.class)
@SmallTest
+@Presubmit
public class NetworkManagementServiceTest {
private NetworkManagementService mNMService;
@Mock private Context mContext;
@@ -92,7 +92,7 @@
private final MockDependencies mDeps = new MockDependencies();
private final MockPermissionEnforcer mPermissionEnforcer = new MockPermissionEnforcer();
- private final class MockDependencies extends Dependencies {
+ private final class MockDependencies extends NetworkManagementService.Dependencies {
@Override
public IBinder getService(String name) {
switch (name) {
diff --git a/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest8.java b/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest8.java
index 2293808..a85c722 100644
--- a/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest8.java
+++ b/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest8.java
@@ -327,7 +327,9 @@
}
private IntentSender makeResultIntent() {
- return PendingIntent.getActivity(getTestContext(), 0, new Intent(), PendingIntent.FLAG_MUTABLE_UNAUDITED).getIntentSender();
+ return PendingIntent.getActivity(getTestContext(), 0,
+ new Intent().setPackage(getTestContext().getPackageName()),
+ PendingIntent.FLAG_MUTABLE).getIntentSender();
}
public void testRequestPinShortcut_withCallback() {
diff --git a/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest9.java b/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest9.java
index a47a8df..2fca3d0 100644
--- a/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest9.java
+++ b/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest9.java
@@ -150,7 +150,9 @@
public void testRequestPinAppWidget_withCallback() {
final PendingIntent resultIntent =
- PendingIntent.getActivity(getTestContext(), 0, new Intent(), PendingIntent.FLAG_MUTABLE_UNAUDITED);
+ PendingIntent.getActivity(getTestContext(), 0,
+ new Intent().setPackage(getTestContext().getPackageName()),
+ PendingIntent.FLAG_MUTABLE);
checkRequestPinAppWidget(resultIntent);
}
diff --git a/services/tests/servicestests/src/com/android/server/pm/UserManagerServiceUserPropertiesTest.java b/services/tests/servicestests/src/com/android/server/pm/UserManagerServiceUserPropertiesTest.java
index 9625188..26d0ddf 100644
--- a/services/tests/servicestests/src/com/android/server/pm/UserManagerServiceUserPropertiesTest.java
+++ b/services/tests/servicestests/src/com/android/server/pm/UserManagerServiceUserPropertiesTest.java
@@ -63,6 +63,7 @@
.setInheritDevicePolicy(67)
.setUseParentsContacts(false)
.setCrossProfileIntentFilterAccessControl(10)
+ .setCrossProfileIntentResolutionStrategy(0)
.build();
final UserProperties actualProps = new UserProperties(defaultProps);
actualProps.setShowInLauncher(14);
@@ -70,6 +71,7 @@
actualProps.setInheritDevicePolicy(51);
actualProps.setUseParentsContacts(true);
actualProps.setCrossProfileIntentFilterAccessControl(20);
+ actualProps.setCrossProfileIntentResolutionStrategy(1);
// Write the properties to xml.
final ByteArrayOutputStream baos = new ByteArrayOutputStream();
@@ -154,6 +156,8 @@
copy::getInheritDevicePolicy, exposeAll);
assertEqualGetterOrThrows(orig::getCrossProfileIntentFilterAccessControl,
copy::getCrossProfileIntentFilterAccessControl, exposeAll);
+ assertEqualGetterOrThrows(orig::getCrossProfileIntentResolutionStrategy,
+ copy::getCrossProfileIntentResolutionStrategy, exposeAll);
// Items requiring hasManagePermission - put them here using hasManagePermission.
assertEqualGetterOrThrows(orig::getShowInSettings, copy::getShowInSettings,
@@ -209,5 +213,7 @@
assertThat(expected.getUseParentsContacts()).isEqualTo(actual.getUseParentsContacts());
assertThat(expected.getCrossProfileIntentFilterAccessControl())
.isEqualTo(actual.getCrossProfileIntentFilterAccessControl());
+ assertThat(expected.getCrossProfileIntentResolutionStrategy())
+ .isEqualTo(actual.getCrossProfileIntentResolutionStrategy());
}
}
diff --git a/services/tests/servicestests/src/com/android/server/pm/UserManagerServiceUserTypeTest.java b/services/tests/servicestests/src/com/android/server/pm/UserManagerServiceUserTypeTest.java
index 1151222..928c6ef 100644
--- a/services/tests/servicestests/src/com/android/server/pm/UserManagerServiceUserTypeTest.java
+++ b/services/tests/servicestests/src/com/android/server/pm/UserManagerServiceUserTypeTest.java
@@ -85,7 +85,8 @@
final UserProperties.Builder userProps = new UserProperties.Builder()
.setShowInLauncher(17)
.setUseParentsContacts(true)
- .setCrossProfileIntentFilterAccessControl(10);
+ .setCrossProfileIntentFilterAccessControl(10)
+ .setCrossProfileIntentResolutionStrategy(1);
final UserTypeDetails type = new UserTypeDetails.Builder()
.setName("a.name")
.setEnabled(1)
@@ -145,6 +146,8 @@
assertTrue(type.getDefaultUserPropertiesReference().getUseParentsContacts());
assertEquals(10, type.getDefaultUserPropertiesReference()
.getCrossProfileIntentFilterAccessControl());
+ assertEquals(1, type.getDefaultUserPropertiesReference()
+ .getCrossProfileIntentResolutionStrategy());
assertEquals(23, type.getBadgeLabel(0));
assertEquals(24, type.getBadgeLabel(1));
@@ -191,6 +194,8 @@
assertEquals(UserProperties.CROSS_PROFILE_INTENT_FILTER_ACCESS_LEVEL_ALL,
props.getCrossProfileIntentFilterAccessControl());
assertEquals(UserProperties.SHOW_IN_LAUNCHER_WITH_PARENT, props.getShowInLauncher());
+ assertEquals(UserProperties.CROSS_PROFILE_INTENT_RESOLUTION_STRATEGY_DEFAULT,
+ props.getCrossProfileIntentResolutionStrategy());
assertFalse(type.hasBadge());
}
@@ -273,7 +278,8 @@
.setShowInLauncher(19)
.setStartWithParent(true)
.setUseParentsContacts(true)
- .setCrossProfileIntentFilterAccessControl(10);
+ .setCrossProfileIntentFilterAccessControl(10)
+ .setCrossProfileIntentResolutionStrategy(1);
final ArrayMap<String, UserTypeDetails.Builder> builders = new ArrayMap<>();
builders.put(userTypeAosp1, new UserTypeDetails.Builder()
.setName(userTypeAosp1)
@@ -301,6 +307,8 @@
assertEquals(19, aospType.getDefaultUserPropertiesReference().getShowInLauncher());
assertEquals(10, aospType.getDefaultUserPropertiesReference()
.getCrossProfileIntentFilterAccessControl());
+ assertEquals(1, aospType.getDefaultUserPropertiesReference()
+ .getCrossProfileIntentResolutionStrategy());
assertTrue(aospType.getDefaultUserPropertiesReference().getStartWithParent());
assertTrue(aospType.getDefaultUserPropertiesReference()
.getUseParentsContacts());
@@ -335,6 +343,8 @@
assertEquals(2020, aospType.getDefaultUserPropertiesReference().getShowInLauncher());
assertEquals(20, aospType.getDefaultUserPropertiesReference()
.getCrossProfileIntentFilterAccessControl());
+ assertEquals(0, aospType.getDefaultUserPropertiesReference()
+ .getCrossProfileIntentResolutionStrategy());
assertFalse(aospType.getDefaultUserPropertiesReference().getStartWithParent());
assertFalse(aospType.getDefaultUserPropertiesReference()
.getUseParentsContacts());
diff --git a/services/tests/servicestests/src/com/android/server/pm/UserManagerTest.java b/services/tests/servicestests/src/com/android/server/pm/UserManagerTest.java
index 5059ef3..1889d9a 100644
--- a/services/tests/servicestests/src/com/android/server/pm/UserManagerTest.java
+++ b/services/tests/servicestests/src/com/android/server/pm/UserManagerTest.java
@@ -175,14 +175,14 @@
final UserProperties typeProps = userTypeDetails.getDefaultUserPropertiesReference();
// Test that only one clone user can be created
- final int primaryUserId = mUserManager.getPrimaryUser().id;
+ final int mainUserId = mUserManager.getMainUser().getIdentifier();
UserInfo userInfo = createProfileForUser("Clone user1",
UserManager.USER_TYPE_PROFILE_CLONE,
- primaryUserId);
+ mainUserId);
assertThat(userInfo).isNotNull();
UserInfo userInfo2 = createProfileForUser("Clone user2",
UserManager.USER_TYPE_PROFILE_CLONE,
- primaryUserId);
+ mainUserId);
assertThat(userInfo2).isNull();
final Context userContext = mContext.createPackageContextAsUser("system", 0,
@@ -208,14 +208,16 @@
assertThrows(SecurityException.class, cloneUserProperties::getStartWithParent);
assertThrows(SecurityException.class,
cloneUserProperties::getCrossProfileIntentFilterAccessControl);
+ assertThrows(SecurityException.class,
+ cloneUserProperties::getCrossProfileIntentResolutionStrategy);
// Verify clone user parent
- assertThat(mUserManager.getProfileParent(primaryUserId)).isNull();
+ assertThat(mUserManager.getProfileParent(mainUserId)).isNull();
UserInfo parentProfileInfo = mUserManager.getProfileParent(userInfo.id);
assertThat(parentProfileInfo).isNotNull();
- assertThat(primaryUserId).isEqualTo(parentProfileInfo.id);
+ assertThat(mainUserId).isEqualTo(parentProfileInfo.id);
removeUser(userInfo.id);
- assertThat(mUserManager.getProfileParent(primaryUserId)).isNull();
+ assertThat(mUserManager.getProfileParent(mainUserId)).isNull();
}
@MediumTest
@@ -373,6 +375,29 @@
@MediumTest
@Test
+ public void testRemoveUserWhenPossible_permanentAdminMainUserReturnsError() throws Exception {
+ assumeHeadlessModeEnabled();
+ assumeTrue("Main user is not permanent admin", isMainUserPermanentAdmin());
+
+ int currentUser = ActivityManager.getCurrentUser();
+ final UserInfo otherUser = createUser("User 1", /* flags= */ UserInfo.FLAG_ADMIN);
+ UserHandle mainUser = mUserManager.getMainUser();
+
+ switchUser(otherUser.id, null, true);
+
+ assertThat(mUserManager.removeUserWhenPossible(mainUser,
+ /* overrideDevicePolicy= */ false))
+ .isEqualTo(UserManager.REMOVE_RESULT_ERROR_MAIN_USER_PERMANENT_ADMIN);
+
+
+ assertThat(hasUser(mainUser.getIdentifier())).isTrue();
+
+ // Switch back to the starting user.
+ switchUser(currentUser, null, true);
+ }
+
+ @MediumTest
+ @Test
public void testRemoveUserWhenPossible_invalidUserReturnsError() throws Exception {
assertThat(hasUser(Integer.MAX_VALUE)).isFalse();
assertThat(mUserManager.removeUserWhenPossible(UserHandle.of(Integer.MAX_VALUE),
@@ -645,17 +670,16 @@
@Test
public void testGetProfileParent() throws Exception {
assumeManagedUsersSupported();
- final int primaryUserId = mUserManager.getPrimaryUser().id;
-
+ int mainUserId = mUserManager.getMainUser().getIdentifier();
UserInfo userInfo = createProfileForUser("Profile",
- UserManager.USER_TYPE_PROFILE_MANAGED, primaryUserId);
+ UserManager.USER_TYPE_PROFILE_MANAGED, mainUserId);
assertThat(userInfo).isNotNull();
- assertThat(mUserManager.getProfileParent(primaryUserId)).isNull();
+ assertThat(mUserManager.getProfileParent(mainUserId)).isNull();
UserInfo parentProfileInfo = mUserManager.getProfileParent(userInfo.id);
assertThat(parentProfileInfo).isNotNull();
- assertThat(primaryUserId).isEqualTo(parentProfileInfo.id);
+ assertThat(mainUserId).isEqualTo(parentProfileInfo.id);
removeUser(userInfo.id);
- assertThat(mUserManager.getProfileParent(primaryUserId)).isNull();
+ assertThat(mUserManager.getProfileParent(mainUserId)).isNull();
}
/** Test that UserManager returns the correct badge information for a managed profile. */
@@ -669,9 +693,9 @@
.that(userTypeDetails).isNotNull();
assertThat(userTypeDetails.getName()).isEqualTo(UserManager.USER_TYPE_PROFILE_MANAGED);
- final int primaryUserId = mUserManager.getPrimaryUser().id;
+ int mainUserId = mUserManager.getMainUser().getIdentifier();
UserInfo userInfo = createProfileForUser("Managed",
- UserManager.USER_TYPE_PROFILE_MANAGED, primaryUserId);
+ UserManager.USER_TYPE_PROFILE_MANAGED, mainUserId);
assertThat(userInfo).isNotNull();
final int userId = userInfo.id;
@@ -714,9 +738,9 @@
final UserProperties typeProps = userTypeDetails.getDefaultUserPropertiesReference();
// Create an actual user (of this user type) and get its properties.
- final int primaryUserId = mUserManager.getPrimaryUser().id;
+ int mainUserId = mUserManager.getMainUser().getIdentifier();
final UserInfo userInfo = createProfileForUser("Managed",
- UserManager.USER_TYPE_PROFILE_MANAGED, primaryUserId);
+ UserManager.USER_TYPE_PROFILE_MANAGED, mainUserId);
assertThat(userInfo).isNotNull();
final int userId = userInfo.id;
final UserProperties userProps = mUserManager.getUserProperties(UserHandle.of(userId));
@@ -727,6 +751,7 @@
assertThat(userProps.getShowInSettings()).isEqualTo(typeProps.getShowInSettings());
assertFalse(userProps.getUseParentsContacts());
assertThrows(SecurityException.class, userProps::getCrossProfileIntentFilterAccessControl);
+ assertThrows(SecurityException.class, userProps::getCrossProfileIntentResolutionStrategy);
assertThrows(SecurityException.class, userProps::getStartWithParent);
assertThrows(SecurityException.class, userProps::getInheritDevicePolicy);
}
@@ -736,11 +761,11 @@
@Test
public void testAddManagedProfile() throws Exception {
assumeManagedUsersSupported();
- final int primaryUserId = mUserManager.getPrimaryUser().id;
+ int mainUserId = mUserManager.getMainUser().getIdentifier();
UserInfo userInfo1 = createProfileForUser("Managed 1",
- UserManager.USER_TYPE_PROFILE_MANAGED, primaryUserId);
+ UserManager.USER_TYPE_PROFILE_MANAGED, mainUserId);
UserInfo userInfo2 = createProfileForUser("Managed 2",
- UserManager.USER_TYPE_PROFILE_MANAGED, primaryUserId);
+ UserManager.USER_TYPE_PROFILE_MANAGED, mainUserId);
assertThat(userInfo1).isNotNull();
assertThat(userInfo2).isNull();
@@ -759,9 +784,9 @@
@Test
public void testAddManagedProfile_withDisallowedPackages() throws Exception {
assumeManagedUsersSupported();
- final int primaryUserId = mUserManager.getPrimaryUser().id;
+ int mainUserId = mUserManager.getMainUser().getIdentifier();
UserInfo userInfo1 = createProfileForUser("Managed1",
- UserManager.USER_TYPE_PROFILE_MANAGED, primaryUserId);
+ UserManager.USER_TYPE_PROFILE_MANAGED, mainUserId);
// Verify that the packagesToVerify are installed by default.
for (String pkg : PACKAGES) {
if (!mPackageManager.isPackageAvailable(pkg)) {
@@ -775,7 +800,7 @@
removeUser(userInfo1.id);
UserInfo userInfo2 = createProfileForUser("Managed2",
- UserManager.USER_TYPE_PROFILE_MANAGED, primaryUserId, PACKAGES);
+ UserManager.USER_TYPE_PROFILE_MANAGED, mainUserId, PACKAGES);
// Verify that the packagesToVerify are not installed by default.
for (String pkg : PACKAGES) {
if (!mPackageManager.isPackageAvailable(pkg)) {
@@ -795,9 +820,9 @@
@Test
public void testAddManagedProfile_disallowedPackagesInstalledLater() throws Exception {
assumeManagedUsersSupported();
- final int primaryUserId = mUserManager.getPrimaryUser().id;
+ final int mainUserId = mUserManager.getMainUser().getIdentifier();
UserInfo userInfo = createProfileForUser("Managed",
- UserManager.USER_TYPE_PROFILE_MANAGED, primaryUserId, PACKAGES);
+ UserManager.USER_TYPE_PROFILE_MANAGED, mainUserId, PACKAGES);
// Verify that the packagesToVerify are not installed by default.
for (String pkg : PACKAGES) {
if (!mPackageManager.isPackageAvailable(pkg)) {
@@ -842,17 +867,17 @@
@MediumTest
@Test
public void testCreateUser_disallowAddClonedUserProfile() throws Exception {
- final int primaryUserId = ActivityManager.getCurrentUser();
- final UserHandle primaryUserHandle = asHandle(primaryUserId);
+ final int mainUserId = ActivityManager.getCurrentUser();
+ final UserHandle mainUserHandle = asHandle(mainUserId);
mUserManager.setUserRestriction(UserManager.DISALLOW_ADD_CLONE_PROFILE,
- true, primaryUserHandle);
+ true, mainUserHandle);
try {
UserInfo cloneProfileUserInfo = createProfileForUser("Clone",
- UserManager.USER_TYPE_PROFILE_CLONE, primaryUserId);
+ UserManager.USER_TYPE_PROFILE_CLONE, mainUserId);
assertThat(cloneProfileUserInfo).isNull();
} finally {
mUserManager.setUserRestriction(UserManager.DISALLOW_ADD_CLONE_PROFILE, false,
- primaryUserHandle);
+ mainUserHandle);
}
}
@@ -861,17 +886,17 @@
@Test
public void testCreateProfileForUser_disallowAddManagedProfile() throws Exception {
assumeManagedUsersSupported();
- final int primaryUserId = mUserManager.getPrimaryUser().id;
- final UserHandle primaryUserHandle = asHandle(primaryUserId);
+ final int mainUserId = mUserManager.getMainUser().getIdentifier();
+ final UserHandle mainUserHandle = asHandle(mainUserId);
mUserManager.setUserRestriction(UserManager.DISALLOW_ADD_MANAGED_PROFILE, true,
- primaryUserHandle);
+ mainUserHandle);
try {
UserInfo userInfo = createProfileForUser("Managed",
- UserManager.USER_TYPE_PROFILE_MANAGED, primaryUserId);
+ UserManager.USER_TYPE_PROFILE_MANAGED, mainUserId);
assertThat(userInfo).isNull();
} finally {
mUserManager.setUserRestriction(UserManager.DISALLOW_ADD_MANAGED_PROFILE, false,
- primaryUserHandle);
+ mainUserHandle);
}
}
@@ -880,17 +905,17 @@
@Test
public void testCreateProfileForUserEvenWhenDisallowed() throws Exception {
assumeManagedUsersSupported();
- final int primaryUserId = mUserManager.getPrimaryUser().id;
- final UserHandle primaryUserHandle = asHandle(primaryUserId);
+ final int mainUserId = mUserManager.getMainUser().getIdentifier();
+ final UserHandle mainUserHandle = asHandle(mainUserId);
mUserManager.setUserRestriction(UserManager.DISALLOW_ADD_MANAGED_PROFILE, true,
- primaryUserHandle);
+ mainUserHandle);
try {
UserInfo userInfo = createProfileEvenWhenDisallowedForUser("Managed",
- UserManager.USER_TYPE_PROFILE_MANAGED, primaryUserId);
+ UserManager.USER_TYPE_PROFILE_MANAGED, mainUserId);
assertThat(userInfo).isNotNull();
} finally {
mUserManager.setUserRestriction(UserManager.DISALLOW_ADD_MANAGED_PROFILE, false,
- primaryUserHandle);
+ mainUserHandle);
}
}
@@ -899,23 +924,23 @@
@Test
public void testCreateProfileForUser_disallowAddUser() throws Exception {
assumeManagedUsersSupported();
- final int primaryUserId = mUserManager.getPrimaryUser().id;
- final UserHandle primaryUserHandle = asHandle(primaryUserId);
- mUserManager.setUserRestriction(UserManager.DISALLOW_ADD_USER, true, primaryUserHandle);
+ final int mainUserId = mUserManager.getMainUser().getIdentifier();
+ final UserHandle mainUserHandle = asHandle(mainUserId);
+ mUserManager.setUserRestriction(UserManager.DISALLOW_ADD_USER, true, mainUserHandle);
try {
UserInfo userInfo = createProfileForUser("Managed",
- UserManager.USER_TYPE_PROFILE_MANAGED, primaryUserId);
+ UserManager.USER_TYPE_PROFILE_MANAGED, mainUserId);
assertThat(userInfo).isNotNull();
} finally {
mUserManager.setUserRestriction(UserManager.DISALLOW_ADD_USER, false,
- primaryUserHandle);
+ mainUserHandle);
}
}
@MediumTest
@Test
public void testAddRestrictedProfile() throws Exception {
- if (isAutomotive()) return;
+ if (isAutomotive() || UserManager.isHeadlessSystemUserMode()) return;
assertWithMessage("There should be no associated restricted profiles before the test")
.that(mUserManager.hasRestrictedProfiles()).isFalse();
UserInfo userInfo = createRestrictedProfile("Profile");
@@ -947,10 +972,10 @@
@Test
public void testGetManagedProfileCreationTime() throws Exception {
assumeManagedUsersSupported();
- final int primaryUserId = mUserManager.getPrimaryUser().id;
+ final int mainUserId = mUserManager.getMainUser().getIdentifier();
final long startTime = System.currentTimeMillis();
UserInfo profile = createProfileForUser("Managed 1",
- UserManager.USER_TYPE_PROFILE_MANAGED, primaryUserId);
+ UserManager.USER_TYPE_PROFILE_MANAGED, mainUserId);
final long endTime = System.currentTimeMillis();
assertThat(profile).isNotNull();
if (System.currentTimeMillis() > EPOCH_PLUS_30_YEARS) {
@@ -963,8 +988,8 @@
assertThat(mUserManager.getUserCreationTime(asHandle(profile.id)))
.isEqualTo(profile.creationTime);
- long ownerCreationTime = mUserManager.getUserInfo(primaryUserId).creationTime;
- assertThat(mUserManager.getUserCreationTime(asHandle(primaryUserId)))
+ long ownerCreationTime = mUserManager.getUserInfo(mainUserId).creationTime;
+ assertThat(mUserManager.getUserCreationTime(asHandle(mainUserId)))
.isEqualTo(ownerCreationTime);
}
@@ -1200,14 +1225,14 @@
@Test
public void testCreateProfile_withContextUserId() throws Exception {
assumeManagedUsersSupported();
- final int primaryUserId = mUserManager.getPrimaryUser().id;
+ final int mainUserId = mUserManager.getMainUser().getIdentifier();
UserInfo userProfile = createProfileForUser("Managed 1",
- UserManager.USER_TYPE_PROFILE_MANAGED, primaryUserId);
+ UserManager.USER_TYPE_PROFILE_MANAGED, mainUserId);
assertThat(userProfile).isNotNull();
UserManager um = (UserManager) mContext.createPackageContextAsUser(
- "android", 0, mUserManager.getPrimaryUser().getUserHandle())
+ "android", 0, mUserManager.getMainUser())
.getSystemService(Context.USER_SERVICE);
List<UserHandle> profiles = um.getAllProfiles();
@@ -1219,10 +1244,10 @@
@Test
public void testSetUserName_withContextUserId() throws Exception {
assumeManagedUsersSupported();
- final int primaryUserId = mUserManager.getPrimaryUser().id;
+ final int mainUserId = mUserManager.getMainUser().getIdentifier();
UserInfo userInfo1 = createProfileForUser("Managed 1",
- UserManager.USER_TYPE_PROFILE_MANAGED, primaryUserId);
+ UserManager.USER_TYPE_PROFILE_MANAGED, mainUserId);
assertThat(userInfo1).isNotNull();
UserManager um = (UserManager) mContext.createPackageContextAsUser(
@@ -1268,10 +1293,10 @@
@Test
public void testGetUserIcon_withContextUserId() throws Exception {
assumeManagedUsersSupported();
- final int primaryUserId = mUserManager.getPrimaryUser().id;
+ final int mainUserId = mUserManager.getMainUser().getIdentifier();
UserInfo userInfo1 = createProfileForUser("Managed 1",
- UserManager.USER_TYPE_PROFILE_MANAGED, primaryUserId);
+ UserManager.USER_TYPE_PROFILE_MANAGED, mainUserId);
assertThat(userInfo1).isNotNull();
UserManager um = (UserManager) mContext.createPackageContextAsUser(
@@ -1420,4 +1445,10 @@
private static UserHandle asHandle(int userId) {
return new UserHandle(userId);
}
+
+ private boolean isMainUserPermanentAdmin() {
+ return Resources.getSystem()
+ .getBoolean(com.android.internal.R.bool.config_isMainUserPermanentAdmin);
+ }
+
}
diff --git a/services/tests/servicestests/src/com/android/server/timedetector/FakeTimeDetectorStrategy.java b/services/tests/servicestests/src/com/android/server/timedetector/FakeTimeDetectorStrategy.java
index 856df359..50040b7 100644
--- a/services/tests/servicestests/src/com/android/server/timedetector/FakeTimeDetectorStrategy.java
+++ b/services/tests/servicestests/src/com/android/server/timedetector/FakeTimeDetectorStrategy.java
@@ -62,6 +62,15 @@
}
@Override
+ public NetworkTimeSuggestion getLatestNetworkSuggestion() {
+ return null;
+ }
+
+ @Override
+ public void clearLatestNetworkSuggestion() {
+ }
+
+ @Override
public void suggestGnssTime(GnssTimeSuggestion timeSuggestion) {
}
diff --git a/services/tests/servicestests/src/com/android/server/timedetector/NetworkTimeUpdateServiceTest.java b/services/tests/servicestests/src/com/android/server/timedetector/NetworkTimeUpdateServiceTest.java
new file mode 100644
index 0000000..1001422
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/timedetector/NetworkTimeUpdateServiceTest.java
@@ -0,0 +1,678 @@
+/*
+ * 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 com.android.server.timedetector;
+
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.reset;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import android.app.time.UnixEpochTime;
+import android.net.Network;
+import android.util.NtpTrustedTime;
+
+import androidx.test.runner.AndroidJUnit4;
+
+import com.android.server.timedetector.NetworkTimeUpdateService.Engine.RefreshCallbacks;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.net.InetSocketAddress;
+import java.util.function.Supplier;
+
+@RunWith(AndroidJUnit4.class)
+public class NetworkTimeUpdateServiceTest {
+
+ private static final InetSocketAddress FAKE_SERVER_ADDRESS =
+ InetSocketAddress.createUnresolved("test", 123);
+ private static final long ARBITRARY_ELAPSED_REALTIME_MILLIS = 100000000L;
+ private static final long ARBITRARY_UNIX_EPOCH_TIME_MILLIS = 5555555555L;
+ private static final int ARBITRARY_UNCERTAINTY_MILLIS = 999;
+
+ private FakeElapsedRealtimeClock mFakeElapsedRealtimeClock;
+ private NtpTrustedTime mMockNtpTrustedTime;
+ private Network mDummyNetwork;
+
+ @Before
+ public void setUp() {
+ mFakeElapsedRealtimeClock = new FakeElapsedRealtimeClock();
+ mMockNtpTrustedTime = mock(NtpTrustedTime.class);
+ mDummyNetwork = mock(Network.class);
+ }
+
+ @Test
+ public void engineImpl_refreshIfRequiredAndReschedule_success() {
+ mFakeElapsedRealtimeClock.setElapsedRealtimeMillis(ARBITRARY_ELAPSED_REALTIME_MILLIS);
+
+ int normalPollingIntervalMillis = 7777777;
+ int shortPollingIntervalMillis = 3333;
+ int tryAgainTimesMax = 5;
+ NetworkTimeUpdateService.Engine engine = new NetworkTimeUpdateService.EngineImpl(
+ mFakeElapsedRealtimeClock,
+ normalPollingIntervalMillis, shortPollingIntervalMillis, tryAgainTimesMax,
+ mMockNtpTrustedTime);
+
+ // Simulated NTP client behavior: No cached time value available initially, then a
+ // successful refresh.
+ NtpTrustedTime.TimeResult timeResult = createNtpTimeResult(
+ mFakeElapsedRealtimeClock.getElapsedRealtimeMillis());
+ when(mMockNtpTrustedTime.getCachedTimeResult()).thenReturn(null, timeResult);
+ when(mMockNtpTrustedTime.forceRefresh(mDummyNetwork)).thenReturn(true);
+
+ // Simulate the passage of time for realism.
+ mFakeElapsedRealtimeClock.incrementMillis(5000);
+
+ RefreshCallbacks mockCallback = mock(RefreshCallbacks.class);
+ // Trigger the engine's logic.
+ engine.refreshIfRequiredAndReschedule(mDummyNetwork, "Test", mockCallback);
+
+ // Expect the refresh attempt to have been made.
+ verify(mMockNtpTrustedTime).forceRefresh(mDummyNetwork);
+
+ // Check everything happened that was supposed to.
+ long expectedDelayMillis = normalPollingIntervalMillis;
+ verify(mockCallback).scheduleNextRefresh(
+ timeResult.getElapsedRealtimeMillis() + expectedDelayMillis);
+
+ NetworkTimeSuggestion expectedSuggestion = createExpectedSuggestion(timeResult);
+ verify(mockCallback).submitSuggestion(expectedSuggestion);
+ }
+
+ @Test
+ public void engineImpl_refreshIfRequiredAndReschedule_failThenFailRepeatedly() {
+ mFakeElapsedRealtimeClock.setElapsedRealtimeMillis(ARBITRARY_ELAPSED_REALTIME_MILLIS);
+
+ int normalPollingIntervalMillis = 7777777;
+ int shortPollingIntervalMillis = 3333;
+ int tryAgainTimesMax = 5;
+ NetworkTimeUpdateService.Engine engine = new NetworkTimeUpdateService.EngineImpl(
+ mFakeElapsedRealtimeClock,
+ normalPollingIntervalMillis, shortPollingIntervalMillis, tryAgainTimesMax,
+ mMockNtpTrustedTime);
+
+ for (int i = 0; i < tryAgainTimesMax + 1; i++) {
+ // Simulate the passage of time for realism.
+ mFakeElapsedRealtimeClock.incrementMillis(5000);
+
+ // Simulated NTP client behavior: No cached time value available and failure to refresh.
+ when(mMockNtpTrustedTime.getCachedTimeResult()).thenReturn(null);
+ when(mMockNtpTrustedTime.forceRefresh(mDummyNetwork)).thenReturn(false);
+
+ RefreshCallbacks mockCallback = mock(RefreshCallbacks.class);
+
+ // Trigger the engine's logic.
+ engine.refreshIfRequiredAndReschedule(mDummyNetwork, "Test", mockCallback);
+
+ // Expect a refresh attempt each time: there's no currently cached result.
+ verify(mMockNtpTrustedTime).forceRefresh(mDummyNetwork);
+
+ // Check everything happened that was supposed to.
+ long expectedDelayMillis;
+ if (i < tryAgainTimesMax) {
+ expectedDelayMillis = shortPollingIntervalMillis;
+ } else {
+ expectedDelayMillis = normalPollingIntervalMillis;
+ }
+ verify(mockCallback).scheduleNextRefresh(
+ mFakeElapsedRealtimeClock.getElapsedRealtimeMillis() + expectedDelayMillis);
+ verify(mockCallback, never()).submitSuggestion(any());
+
+ reset(mMockNtpTrustedTime);
+ }
+ }
+
+ @Test
+ public void engineImpl_refreshIfRequiredAndReschedule_successThenFailRepeatedly() {
+ mFakeElapsedRealtimeClock.setElapsedRealtimeMillis(ARBITRARY_ELAPSED_REALTIME_MILLIS);
+
+ int normalPollingIntervalMillis = 7777777;
+ int shortPollingIntervalMillis = 3333;
+ int tryAgainTimesMax = 5;
+ NetworkTimeUpdateService.Engine engine = new NetworkTimeUpdateService.EngineImpl(
+ mFakeElapsedRealtimeClock,
+ normalPollingIntervalMillis, shortPollingIntervalMillis, tryAgainTimesMax,
+ mMockNtpTrustedTime);
+
+ NtpTrustedTime.TimeResult timeResult = createNtpTimeResult(
+ mFakeElapsedRealtimeClock.getElapsedRealtimeMillis());
+ NetworkTimeSuggestion expectedSuggestion = createExpectedSuggestion(timeResult);
+
+ {
+ // Simulated NTP client behavior: No cached time value available initially, with a
+ // successful refresh.
+ when(mMockNtpTrustedTime.getCachedTimeResult()).thenReturn(null, timeResult);
+ when(mMockNtpTrustedTime.forceRefresh(mDummyNetwork)).thenReturn(true);
+
+ // Simulate the passage of time for realism.
+ mFakeElapsedRealtimeClock.incrementMillis(5000);
+
+ RefreshCallbacks mockCallback = mock(RefreshCallbacks.class);
+
+ // Trigger the engine's logic.
+ engine.refreshIfRequiredAndReschedule(mDummyNetwork, "Test", mockCallback);
+
+ // Expect the refresh attempt to have been made: there is no cached network time
+ // initially.
+ verify(mMockNtpTrustedTime).forceRefresh(mDummyNetwork);
+
+ long expectedDelayMillis = normalPollingIntervalMillis;
+ verify(mockCallback).scheduleNextRefresh(
+ timeResult.getElapsedRealtimeMillis() + expectedDelayMillis);
+ verify(mockCallback, times(1)).submitSuggestion(expectedSuggestion);
+ reset(mMockNtpTrustedTime);
+ }
+
+ // Increment the current time by enough so that an attempt to refresh the time should be
+ // made every time refreshIfRequiredAndReschedule() is called.
+ mFakeElapsedRealtimeClock.incrementMillis(normalPollingIntervalMillis);
+
+ // Test multiple follow-up calls.
+ for (int i = 0; i < tryAgainTimesMax + 1; i++) {
+ // Simulated NTP client behavior: (Too old) cached time value available, unsuccessful
+ // refresh.
+ when(mMockNtpTrustedTime.getCachedTimeResult()).thenReturn(timeResult);
+ when(mMockNtpTrustedTime.forceRefresh(mDummyNetwork)).thenReturn(false);
+
+ RefreshCallbacks mockCallback = mock(RefreshCallbacks.class);
+
+ // Trigger the engine's logic.
+ engine.refreshIfRequiredAndReschedule(mDummyNetwork, "Test", mockCallback);
+
+ // Expect a refresh attempt each time as the cached network time is too old.
+ verify(mMockNtpTrustedTime).forceRefresh(mDummyNetwork);
+
+ // Check the scheduling.
+ long expectedDelayMillis;
+ if (i < tryAgainTimesMax) {
+ expectedDelayMillis = shortPollingIntervalMillis;
+ } else {
+ expectedDelayMillis = normalPollingIntervalMillis;
+ }
+ verify(mockCallback).scheduleNextRefresh(
+ mFakeElapsedRealtimeClock.getElapsedRealtimeMillis() + expectedDelayMillis);
+
+ // No valid time, no suggestion.
+ verify(mockCallback, never()).submitSuggestion(any());
+
+ reset(mMockNtpTrustedTime);
+
+ // Simulate the passage of time for realism.
+ mFakeElapsedRealtimeClock.incrementMillis(5000);
+ }
+ }
+
+ @Test
+ public void engineImpl_refreshIfRequiredAndReschedule_successThenFail_tryAgainTimesZero() {
+ mFakeElapsedRealtimeClock.setElapsedRealtimeMillis(ARBITRARY_ELAPSED_REALTIME_MILLIS);
+
+ int normalPollingIntervalMillis = 7777777;
+ int shortPollingIntervalMillis = 3333;
+ int tryAgainTimesMax = 0;
+ NetworkTimeUpdateService.Engine engine = new NetworkTimeUpdateService.EngineImpl(
+ mFakeElapsedRealtimeClock,
+ normalPollingIntervalMillis, shortPollingIntervalMillis, tryAgainTimesMax,
+ mMockNtpTrustedTime);
+
+ NtpTrustedTime.TimeResult timeResult = createNtpTimeResult(
+ mFakeElapsedRealtimeClock.getElapsedRealtimeMillis());
+ NetworkTimeSuggestion expectedSuggestion = createExpectedSuggestion(timeResult);
+
+ {
+ // Simulated NTP client behavior: No cached time value available initially, with a
+ // successful refresh.
+ when(mMockNtpTrustedTime.getCachedTimeResult()).thenReturn(null, timeResult);
+ when(mMockNtpTrustedTime.forceRefresh(mDummyNetwork)).thenReturn(true);
+
+ // Simulate the passage of time for realism.
+ mFakeElapsedRealtimeClock.incrementMillis(5000);
+
+ RefreshCallbacks mockCallback = mock(RefreshCallbacks.class);
+
+ // Trigger the engine's logic.
+ engine.refreshIfRequiredAndReschedule(mDummyNetwork, "Test", mockCallback);
+
+ // Expect the refresh attempt to have been made: there is no cached network time
+ // initially.
+ verify(mMockNtpTrustedTime).forceRefresh(mDummyNetwork);
+
+ long expectedDelayMillis = normalPollingIntervalMillis;
+ verify(mockCallback).scheduleNextRefresh(
+ timeResult.getElapsedRealtimeMillis() + expectedDelayMillis);
+ verify(mockCallback, times(1)).submitSuggestion(expectedSuggestion);
+ reset(mMockNtpTrustedTime);
+ }
+
+ // Increment the current time by enough so that an attempt to refresh the time should be
+ // made every time refreshIfRequiredAndReschedule() is called.
+ mFakeElapsedRealtimeClock.incrementMillis(normalPollingIntervalMillis);
+
+ // Test multiple follow-up calls.
+ for (int i = 0; i < 3; i++) {
+ // Simulated NTP client behavior: (Too old) cached time value available, unsuccessful
+ // refresh.
+ when(mMockNtpTrustedTime.getCachedTimeResult()).thenReturn(timeResult);
+ when(mMockNtpTrustedTime.forceRefresh(mDummyNetwork)).thenReturn(false);
+
+ RefreshCallbacks mockCallback = mock(RefreshCallbacks.class);
+
+ // Trigger the engine's logic.
+ engine.refreshIfRequiredAndReschedule(mDummyNetwork, "Test", mockCallback);
+
+ // Expect a refresh attempt each time as the cached network time is too old.
+ verify(mMockNtpTrustedTime).forceRefresh(mDummyNetwork);
+
+ // Check the scheduling. tryAgainTimesMax == 0, so the algorithm should start with
+
+ long expectedDelayMillis = normalPollingIntervalMillis;
+ verify(mockCallback).scheduleNextRefresh(
+ mFakeElapsedRealtimeClock.getElapsedRealtimeMillis() + expectedDelayMillis);
+
+ // No valid time, no suggestion.
+ verify(mockCallback, never()).submitSuggestion(any());
+
+ reset(mMockNtpTrustedTime);
+
+ // Simulate the passage of time for realism.
+ mFakeElapsedRealtimeClock.incrementMillis(5000);
+ }
+ }
+
+ @Test
+ public void engineImpl_refreshIfRequiredAndReschedule_successThenFail_tryAgainTimesNegative() {
+ mFakeElapsedRealtimeClock.setElapsedRealtimeMillis(ARBITRARY_ELAPSED_REALTIME_MILLIS);
+
+ int normalPollingIntervalMillis = 7777777;
+ int shortPollingIntervalMillis = 3333;
+ int tryAgainTimesMax = -1;
+ NetworkTimeUpdateService.Engine engine = new NetworkTimeUpdateService.EngineImpl(
+ mFakeElapsedRealtimeClock,
+ normalPollingIntervalMillis, shortPollingIntervalMillis, tryAgainTimesMax,
+ mMockNtpTrustedTime);
+
+ NtpTrustedTime.TimeResult timeResult = createNtpTimeResult(
+ mFakeElapsedRealtimeClock.getElapsedRealtimeMillis());
+ NetworkTimeSuggestion expectedSuggestion = createExpectedSuggestion(timeResult);
+
+ {
+ // Simulated NTP client behavior: No cached time value available initially, with a
+ // successful refresh.
+ when(mMockNtpTrustedTime.getCachedTimeResult()).thenReturn(null, timeResult);
+ when(mMockNtpTrustedTime.forceRefresh(mDummyNetwork)).thenReturn(true);
+
+ // Simulate the passage of time for realism.
+ mFakeElapsedRealtimeClock.incrementMillis(5000);
+
+ RefreshCallbacks mockCallback = mock(RefreshCallbacks.class);
+
+ // Trigger the engine's logic.
+ engine.refreshIfRequiredAndReschedule(mDummyNetwork, "Test", mockCallback);
+
+ // Expect the refresh attempt to have been made: there is no cached network time
+ // initially.
+ verify(mMockNtpTrustedTime).forceRefresh(mDummyNetwork);
+
+ long expectedDelayMillis = normalPollingIntervalMillis;
+ verify(mockCallback).scheduleNextRefresh(
+ timeResult.getElapsedRealtimeMillis() + expectedDelayMillis);
+ verify(mockCallback, times(1)).submitSuggestion(expectedSuggestion);
+ reset(mMockNtpTrustedTime);
+ }
+
+ // Increment the current time by enough so that an attempt to refresh the time should be
+ // made every time refreshIfRequiredAndReschedule() is called.
+ mFakeElapsedRealtimeClock.incrementMillis(normalPollingIntervalMillis);
+
+ // Test multiple follow-up calls.
+ for (int i = 0; i < 3; i++) {
+ // Simulated NTP client behavior: (Too old) cached time value available, unsuccessful
+ // refresh.
+ when(mMockNtpTrustedTime.getCachedTimeResult()).thenReturn(timeResult);
+ when(mMockNtpTrustedTime.forceRefresh(mDummyNetwork)).thenReturn(false);
+
+ RefreshCallbacks mockCallback = mock(RefreshCallbacks.class);
+
+ // Trigger the engine's logic.
+ engine.refreshIfRequiredAndReschedule(mDummyNetwork, "Test", mockCallback);
+
+ // Expect a refresh attempt each time as the cached network time is too old.
+ verify(mMockNtpTrustedTime).forceRefresh(mDummyNetwork);
+
+ // Check the scheduling. tryAgainTimesMax == -1, so it should always be
+ // shortPollingIntervalMillis.
+ long expectedDelayMillis = shortPollingIntervalMillis;
+ verify(mockCallback).scheduleNextRefresh(
+ mFakeElapsedRealtimeClock.getElapsedRealtimeMillis() + expectedDelayMillis);
+
+ // No valid time, no suggestion.
+ verify(mockCallback, never()).submitSuggestion(any());
+
+ reset(mMockNtpTrustedTime);
+
+ // Simulate the passage of time for realism.
+ mFakeElapsedRealtimeClock.incrementMillis(5000);
+ }
+ }
+
+ @Test
+ public void engineImpl_refreshIfRequiredAndReschedule_successFailSuccess() {
+ mFakeElapsedRealtimeClock.setElapsedRealtimeMillis(ARBITRARY_ELAPSED_REALTIME_MILLIS);
+
+ int normalPollingIntervalMillis = 7777777;
+ int shortPollingIntervalMillis = 3333;
+ int tryAgainTimesMax = 5;
+ NetworkTimeUpdateService.Engine engine = new NetworkTimeUpdateService.EngineImpl(
+ mFakeElapsedRealtimeClock,
+ normalPollingIntervalMillis, shortPollingIntervalMillis, tryAgainTimesMax,
+ mMockNtpTrustedTime);
+
+ NtpTrustedTime.TimeResult timeResult1 = createNtpTimeResult(
+ mFakeElapsedRealtimeClock.getElapsedRealtimeMillis());
+ {
+ // Simulated NTP client behavior: No cached time value available initially, with a
+ // successful refresh.
+ when(mMockNtpTrustedTime.getCachedTimeResult()).thenReturn(null, timeResult1);
+ when(mMockNtpTrustedTime.forceRefresh(mDummyNetwork)).thenReturn(true);
+
+ // Simulate the passage of time for realism.
+ mFakeElapsedRealtimeClock.incrementMillis(5000);
+
+ RefreshCallbacks mockCallback = mock(RefreshCallbacks.class);
+
+ // Trigger the engine's logic.
+ engine.refreshIfRequiredAndReschedule(mDummyNetwork, "Test", mockCallback);
+
+ // Expect the refresh attempt to have been made: there is no cached network time
+ // initially.
+ verify(mMockNtpTrustedTime).forceRefresh(mDummyNetwork);
+
+ long expectedDelayMillis = normalPollingIntervalMillis;
+ verify(mockCallback).scheduleNextRefresh(
+ timeResult1.getElapsedRealtimeMillis() + expectedDelayMillis);
+ NetworkTimeSuggestion expectedSuggestion = createExpectedSuggestion(timeResult1);
+ verify(mockCallback, times(1)).submitSuggestion(expectedSuggestion);
+ reset(mMockNtpTrustedTime);
+ }
+
+ // Increment the current time by enough so that the cached time result is too old and an
+ // attempt to refresh the time should be made every time refreshIfRequiredAndReschedule() is
+ // called.
+ mFakeElapsedRealtimeClock.incrementMillis(normalPollingIntervalMillis);
+
+ {
+ // Simulated NTP client behavior: (Old) cached time value available initially, with an
+ // unsuccessful refresh.
+ when(mMockNtpTrustedTime.getCachedTimeResult()).thenReturn(timeResult1);
+ when(mMockNtpTrustedTime.forceRefresh(mDummyNetwork)).thenReturn(false);
+
+ RefreshCallbacks mockCallback = mock(RefreshCallbacks.class);
+
+ // Trigger the engine's logic.
+ engine.refreshIfRequiredAndReschedule(mDummyNetwork, "Test", mockCallback);
+
+ // Expect the refresh attempt to have been made: the timeResult is too old.
+ verify(mMockNtpTrustedTime).forceRefresh(mDummyNetwork);
+
+ long expectedDelayMillis = shortPollingIntervalMillis;
+ verify(mockCallback).scheduleNextRefresh(
+ mFakeElapsedRealtimeClock.getElapsedRealtimeMillis() + expectedDelayMillis);
+
+ // No valid time, no suggestion.
+ verify(mockCallback, never()).submitSuggestion(any());
+ reset(mMockNtpTrustedTime);
+ }
+
+ // Increment time enough to avoid the minimum refresh interval protection.
+ mFakeElapsedRealtimeClock.incrementMillis(shortPollingIntervalMillis);
+
+ NtpTrustedTime.TimeResult timeResult2 = createNtpTimeResult(
+ mFakeElapsedRealtimeClock.getElapsedRealtimeMillis());
+
+ {
+ // Simulated NTP client behavior: (Old) cached time value available initially, with a
+ // successful refresh and a new cached time value.
+ when(mMockNtpTrustedTime.getCachedTimeResult()).thenReturn(timeResult1, timeResult2);
+ when(mMockNtpTrustedTime.forceRefresh(mDummyNetwork)).thenReturn(true);
+
+ // Simulate the passage of time for realism.
+ mFakeElapsedRealtimeClock.incrementMillis(5000);
+
+ RefreshCallbacks mockCallback = mock(RefreshCallbacks.class);
+
+ // Trigger the engine's logic.
+ engine.refreshIfRequiredAndReschedule(mDummyNetwork, "Test", mockCallback);
+
+ // Expect the refresh attempt to have been made: the timeResult is too old.
+ verify(mMockNtpTrustedTime).forceRefresh(mDummyNetwork);
+
+ long expectedDelayMillis = normalPollingIntervalMillis;
+ verify(mockCallback).scheduleNextRefresh(
+ timeResult2.getElapsedRealtimeMillis() + expectedDelayMillis);
+ NetworkTimeSuggestion expectedSuggestion = createExpectedSuggestion(timeResult2);
+ verify(mockCallback, times(1)).submitSuggestion(expectedSuggestion);
+ reset(mMockNtpTrustedTime);
+ }
+ }
+
+ /**
+ * Confirms that if a refreshIfRequiredAndReschedule() call is made, e.g. for reasons besides
+ * scheduled alerts, and the latest time is not too old, then an NTP refresh won't be attempted.
+ * A suggestion will still be made.
+ */
+ @Test
+ public void engineImpl_refreshIfRequiredAndReschedule_noRefreshIfLatestIsFresh() {
+ mFakeElapsedRealtimeClock.setElapsedRealtimeMillis(ARBITRARY_ELAPSED_REALTIME_MILLIS);
+
+ int normalPollingIntervalMillis = 7777777;
+ int shortPollingIntervalMillis = 3333;
+ int tryAgainTimesMax = 5;
+ NetworkTimeUpdateService.Engine engine = new NetworkTimeUpdateService.EngineImpl(
+ mFakeElapsedRealtimeClock,
+ normalPollingIntervalMillis, shortPollingIntervalMillis, tryAgainTimesMax,
+ mMockNtpTrustedTime);
+
+ // Simulated NTP client behavior: A cached time value is available.
+ NtpTrustedTime.TimeResult timeResult = createNtpTimeResult(
+ mFakeElapsedRealtimeClock.getElapsedRealtimeMillis());
+ when(mMockNtpTrustedTime.getCachedTimeResult()).thenReturn(timeResult);
+ // Increment the clock, but not enough to consider the cached value too old.
+ mFakeElapsedRealtimeClock.incrementMillis(normalPollingIntervalMillis - 1);
+
+ RefreshCallbacks mockCallback = mock(RefreshCallbacks.class);
+ // Trigger the engine's logic.
+ engine.refreshIfRequiredAndReschedule(mDummyNetwork, "Test", mockCallback);
+
+ // Expect no refresh attempt to have been made.
+ verify(mMockNtpTrustedTime, never()).forceRefresh(any());
+
+ // The next wake-up should be rescheduled for when the cached time value will become too
+ // old.
+ long expectedDelayMillis = normalPollingIntervalMillis;
+ verify(mockCallback).scheduleNextRefresh(
+ timeResult.getElapsedRealtimeMillis() + expectedDelayMillis);
+
+ // Suggestions must be made every time if the cached time value is not too old in case it
+ // was refreshed by a different component.
+ NetworkTimeSuggestion expectedSuggestion = createExpectedSuggestion(timeResult);
+ verify(mockCallback, times(1)).submitSuggestion(expectedSuggestion);
+ }
+
+ /**
+ * Confirms that if a refreshIfRequiredAndReschedule() call is made, e.g. for reasons besides
+ * scheduled alerts, and the latest time is too old, then an NTP refresh will be attempted.
+ */
+ @Test
+ public void engineImpl_refreshIfRequiredAndReschedule_failureHandlingAfterLatestIsTooOld() {
+ mFakeElapsedRealtimeClock.setElapsedRealtimeMillis(ARBITRARY_ELAPSED_REALTIME_MILLIS);
+
+ int normalPollingIntervalMillis = 7777777;
+ int shortPollingIntervalMillis = 3333;
+ int tryAgainTimesMax = 5;
+ NetworkTimeUpdateService.Engine engine = new NetworkTimeUpdateService.EngineImpl(
+ mFakeElapsedRealtimeClock,
+ normalPollingIntervalMillis, shortPollingIntervalMillis, tryAgainTimesMax,
+ mMockNtpTrustedTime);
+
+ // Simulated NTP client behavior: A cached time value is available, increment the clock,
+ // enough to consider the cached value too old. The refresh attempt will fail.
+ NtpTrustedTime.TimeResult timeResult = createNtpTimeResult(
+ mFakeElapsedRealtimeClock.getElapsedRealtimeMillis());
+ when(mMockNtpTrustedTime.getCachedTimeResult()).thenReturn(timeResult);
+ mFakeElapsedRealtimeClock.incrementMillis(normalPollingIntervalMillis);
+ when(mMockNtpTrustedTime.forceRefresh(mDummyNetwork)).thenReturn(false);
+
+ RefreshCallbacks mockCallback = mock(RefreshCallbacks.class);
+ // Trigger the engine's logic.
+ engine.refreshIfRequiredAndReschedule(mDummyNetwork, "Test", mockCallback);
+
+ // Expect a refresh attempt to have been made.
+ verify(mMockNtpTrustedTime, times(1)).forceRefresh(mDummyNetwork);
+
+ // The next wake-up should be rescheduled using the short polling interval.
+ long expectedDelayMillis = shortPollingIntervalMillis;
+ verify(mockCallback).scheduleNextRefresh(
+ mFakeElapsedRealtimeClock.getElapsedRealtimeMillis() + expectedDelayMillis);
+
+ // Suggestions should not be made if the cached time value is too old.
+ verify(mockCallback, never()).submitSuggestion(any());
+ }
+
+ /**
+ * Confirms that if a refreshIfRequiredAndReschedule() call is made and there was a recently
+ * failed refresh, then another won't be scheduled too soon.
+ */
+ @Test
+ public void engineImpl_refreshIfRequiredAndReschedule_minimumRefreshTimeEnforced() {
+ mFakeElapsedRealtimeClock.setElapsedRealtimeMillis(ARBITRARY_ELAPSED_REALTIME_MILLIS);
+
+ int normalPollingIntervalMillis = 7777777;
+ int shortPollingIntervalMillis = 3333;
+ int tryAgainTimesMax = 0;
+ NetworkTimeUpdateService.Engine engine = new NetworkTimeUpdateService.EngineImpl(
+ mFakeElapsedRealtimeClock,
+ normalPollingIntervalMillis, shortPollingIntervalMillis, tryAgainTimesMax,
+ mMockNtpTrustedTime);
+
+ NtpTrustedTime.TimeResult timeResult = createNtpTimeResult(
+ mFakeElapsedRealtimeClock.getElapsedRealtimeMillis());
+
+ // Simulate an initial call to refreshIfRequiredAndReschedule() prime the "last refresh
+ // attempt" time. A cached time value is available, but it's too old but the refresh
+ // attempt will fail.
+ long lastRefreshAttemptElapsedMillis;
+ {
+ // Increment the clock, enough to consider the cached value too old.
+ mFakeElapsedRealtimeClock.incrementMillis(normalPollingIntervalMillis);
+ when(mMockNtpTrustedTime.getCachedTimeResult()).thenReturn(timeResult);
+ when(mMockNtpTrustedTime.forceRefresh(mDummyNetwork)).thenReturn(false);
+
+ RefreshCallbacks mockCallback = mock(RefreshCallbacks.class);
+ // Trigger the engine's logic.
+ engine.refreshIfRequiredAndReschedule(mDummyNetwork, "Test", mockCallback);
+
+ // Expect a refresh attempt to have been made.
+ verify(mMockNtpTrustedTime, times(1)).forceRefresh(mDummyNetwork);
+ lastRefreshAttemptElapsedMillis = mFakeElapsedRealtimeClock.getElapsedRealtimeMillis();
+
+ // The next wake-up should be rescheduled using the normalPollingIntervalMillis.
+ // Because the time signal age > normalPollingIntervalMillis, the last refresh attempt
+ // time will be used.
+ long expectedDelayMillis = normalPollingIntervalMillis;
+ long expectedNextRefreshElapsedMillis =
+ lastRefreshAttemptElapsedMillis + expectedDelayMillis;
+ verify(mockCallback).scheduleNextRefresh(expectedNextRefreshElapsedMillis);
+
+ // Suggestions should not be made if the cached time value is too old.
+ verify(mockCallback, never()).submitSuggestion(any());
+
+ reset(mMockNtpTrustedTime);
+ }
+
+ // Simulate a second call to refreshIfRequiredAndReschedule() very soon after the first, as
+ // might happen if there were a network state change.
+ // The cached time value is available, but it's still too old. Because the last call was so
+ // recent, no refresh should take place and the next scheduled refresh time should be
+ // set appropriately based on the last attempt.
+ {
+ // Increment the clock by a relatively small amount so that it's considered "too soon".
+ mFakeElapsedRealtimeClock.incrementMillis(shortPollingIntervalMillis / 2);
+
+ when(mMockNtpTrustedTime.getCachedTimeResult()).thenReturn(timeResult);
+
+ RefreshCallbacks mockCallback = mock(RefreshCallbacks.class);
+ // Trigger the engine's logic.
+ engine.refreshIfRequiredAndReschedule(mDummyNetwork, "Test", mockCallback);
+
+ // Expect no refresh attempt to have been made: time elapsed isn't enough.
+ verify(mMockNtpTrustedTime, never()).forceRefresh(any());
+
+ // The next wake-up should be rescheduled using the normal polling interval and the last
+ // refresh attempt time.
+ long expectedDelayMillis = normalPollingIntervalMillis;
+ long expectedNextRefreshElapsedMillis =
+ lastRefreshAttemptElapsedMillis + expectedDelayMillis;
+ verify(mockCallback).scheduleNextRefresh(expectedNextRefreshElapsedMillis);
+
+ // Suggestions should not be made if the cached time value is too old.
+ verify(mockCallback, never()).submitSuggestion(any());
+
+ reset(mMockNtpTrustedTime);
+ }
+ }
+
+ private static NetworkTimeSuggestion createExpectedSuggestion(
+ NtpTrustedTime.TimeResult timeResult) {
+ UnixEpochTime unixEpochTime = new UnixEpochTime(
+ timeResult.getElapsedRealtimeMillis(), timeResult.getTimeMillis());
+ return new NetworkTimeSuggestion(unixEpochTime, timeResult.getUncertaintyMillis());
+ }
+
+ private static NtpTrustedTime.TimeResult createNtpTimeResult(long elapsedRealtimeMillis) {
+ return new NtpTrustedTime.TimeResult(
+ ARBITRARY_UNIX_EPOCH_TIME_MILLIS,
+ elapsedRealtimeMillis,
+ ARBITRARY_UNCERTAINTY_MILLIS,
+ FAKE_SERVER_ADDRESS);
+ }
+
+ private static class FakeElapsedRealtimeClock implements Supplier<Long> {
+
+ private long mElapsedRealtimeMillis;
+
+ public void setElapsedRealtimeMillis(long elapsedRealtimeMillis) {
+ mElapsedRealtimeMillis = elapsedRealtimeMillis;
+ }
+
+ public long getElapsedRealtimeMillis() {
+ return mElapsedRealtimeMillis;
+ }
+
+ public long incrementMillis(int millis) {
+ mElapsedRealtimeMillis += millis;
+ return mElapsedRealtimeMillis;
+ }
+
+ @Override
+ public Long get() {
+ return getElapsedRealtimeMillis();
+ }
+ }
+}
diff --git a/services/tests/servicestests/src/com/android/server/timedetector/TimeDetectorServiceTest.java b/services/tests/servicestests/src/com/android/server/timedetector/TimeDetectorServiceTest.java
index a857238..0b339ad 100644
--- a/services/tests/servicestests/src/com/android/server/timedetector/TimeDetectorServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/timedetector/TimeDetectorServiceTest.java
@@ -380,6 +380,28 @@
}
@Test
+ public void testClearNetworkTime_withoutPermission() {
+ doThrow(new SecurityException("Mock"))
+ .when(mMockContext).enforceCallingPermission(anyString(), any());
+
+ assertThrows(SecurityException.class,
+ () -> mTimeDetectorService.clearNetworkTime());
+ verify(mMockContext).enforceCallingPermission(
+ eq(android.Manifest.permission.SET_TIME), anyString());
+ }
+
+ @Test
+ public void testClearNetworkTime() throws Exception {
+ doNothing().when(mMockContext).enforceCallingPermission(anyString(), any());
+
+ mTimeDetectorService.clearNetworkTime();
+
+ verify(mMockContext).enforceCallingPermission(
+ eq(android.Manifest.permission.SET_TIME), anyString());
+ verify(mFakeTimeDetectorStrategySpy).clearLatestNetworkSuggestion();
+ }
+
+ @Test
public void testLatestNetworkTime() {
NtpTrustedTime.TimeResult latestNetworkTime = new NtpTrustedTime.TimeResult(
1234L, 54321L, 999, InetSocketAddress.createUnresolved("test.timeserver", 123));
diff --git a/services/tests/servicestests/src/com/android/server/timedetector/TimeDetectorStrategyImplTest.java b/services/tests/servicestests/src/com/android/server/timedetector/TimeDetectorStrategyImplTest.java
index caef494..37da2a2 100644
--- a/services/tests/servicestests/src/com/android/server/timedetector/TimeDetectorStrategyImplTest.java
+++ b/services/tests/servicestests/src/com/android/server/timedetector/TimeDetectorStrategyImplTest.java
@@ -874,6 +874,7 @@
long expectedSystemClockMillis =
script.calculateTimeInMillisForNow(timeSuggestion.getUnixEpochTime());
script.simulateNetworkTimeSuggestion(timeSuggestion)
+ .assertLatestNetworkSuggestion(timeSuggestion)
.verifySystemClockConfidence(TIME_CONFIDENCE_HIGH)
.verifySystemClockWasSetAndResetCallTracking(expectedSystemClockMillis);
}
@@ -891,10 +892,55 @@
script.simulateTimePassing()
.simulateNetworkTimeSuggestion(timeSuggestion)
+ .assertLatestNetworkSuggestion(timeSuggestion)
.verifySystemClockWasNotSetAndResetCallTracking();
}
@Test
+ public void testClearLatestNetworkSuggestion() {
+ ConfigurationInternal configInternal =
+ new ConfigurationInternal.Builder(CONFIG_AUTO_ENABLED)
+ .setOriginPriorities(ORIGIN_NETWORK, ORIGIN_EXTERNAL)
+ .build();
+ Script script = new Script().simulateConfigurationInternalChange(configInternal);
+
+ // Create two different time suggestions for the current elapsedRealtimeMillis.
+ ExternalTimeSuggestion externalTimeSuggestion =
+ script.generateExternalTimeSuggestion(ARBITRARY_TEST_TIME);
+ NetworkTimeSuggestion networkTimeSuggestion =
+ script.generateNetworkTimeSuggestion(ARBITRARY_TEST_TIME.plus(Duration.ofHours(5)));
+ script.simulateTimePassing();
+
+ // Suggest an external time: This should cause the device to change time.
+ {
+ long expectedSystemClockMillis =
+ script.calculateTimeInMillisForNow(externalTimeSuggestion.getUnixEpochTime());
+ script.simulateExternalTimeSuggestion(externalTimeSuggestion)
+ .verifySystemClockWasSetAndResetCallTracking(expectedSystemClockMillis);
+ }
+
+ // Suggest a network time: This should cause the device to change time because
+ // network > external.
+ {
+ long expectedSystemClockMillis =
+ script.calculateTimeInMillisForNow(networkTimeSuggestion.getUnixEpochTime());
+ script.simulateNetworkTimeSuggestion(networkTimeSuggestion)
+ .assertLatestNetworkSuggestion(networkTimeSuggestion)
+ .verifySystemClockWasSetAndResetCallTracking(expectedSystemClockMillis);
+ }
+
+ // Clear the network time. This should cause the device to change back to the external time,
+ // which is now the best time available.
+ {
+ long expectedSystemClockMillis =
+ script.calculateTimeInMillisForNow(externalTimeSuggestion.getUnixEpochTime());
+ script.simulateClearLatestNetworkSuggestion()
+ .assertLatestNetworkSuggestion(null)
+ .verifySystemClockWasSetAndResetCallTracking(expectedSystemClockMillis);
+ }
+ }
+
+ @Test
public void testSuggestNetworkTime_rejectedBelowLowerBound() {
ConfigurationInternal configInternal =
new ConfigurationInternal.Builder(CONFIG_AUTO_ENABLED)
@@ -908,6 +954,7 @@
NetworkTimeSuggestion timeSuggestion =
script.generateNetworkTimeSuggestion(belowLowerBound);
script.simulateNetworkTimeSuggestion(timeSuggestion)
+ .assertLatestNetworkSuggestion(null)
.verifySystemClockConfidence(TIME_CONFIDENCE_LOW)
.verifySystemClockWasNotSetAndResetCallTracking();
}
@@ -926,6 +973,7 @@
NetworkTimeSuggestion timeSuggestion =
script.generateNetworkTimeSuggestion(aboveLowerBound);
script.simulateNetworkTimeSuggestion(timeSuggestion)
+ .assertLatestNetworkSuggestion(timeSuggestion)
.verifySystemClockConfidence(TIME_CONFIDENCE_HIGH)
.verifySystemClockWasSetAndResetCallTracking(aboveLowerBound.toEpochMilli());
}
@@ -944,6 +992,7 @@
NetworkTimeSuggestion timeSuggestion =
script.generateNetworkTimeSuggestion(aboveUpperBound);
script.simulateNetworkTimeSuggestion(timeSuggestion)
+ .assertLatestNetworkSuggestion(null)
.verifySystemClockConfidence(TIME_CONFIDENCE_LOW)
.verifySystemClockWasNotSetAndResetCallTracking();
}
@@ -962,6 +1011,7 @@
NetworkTimeSuggestion timeSuggestion =
script.generateNetworkTimeSuggestion(belowUpperBound);
script.simulateNetworkTimeSuggestion(timeSuggestion)
+ .assertLatestNetworkSuggestion(timeSuggestion)
.verifySystemClockConfidence(TIME_CONFIDENCE_HIGH)
.verifySystemClockWasSetAndResetCallTracking(belowUpperBound.toEpochMilli());
}
@@ -1745,7 +1795,7 @@
}
@Test
- public void suggestionsFromNetworkOriginNotInPriorityList_areIgnored() {
+ public void suggestionsFromNetworkOriginNotInPriorityList_areNotUsed() {
ConfigurationInternal configInternal =
new ConfigurationInternal.Builder(CONFIG_AUTO_ENABLED)
.setOriginPriorities(ORIGIN_TELEPHONY)
@@ -1757,11 +1807,12 @@
script.simulateNetworkTimeSuggestion(timeSuggestion)
.assertLatestNetworkSuggestion(timeSuggestion)
+ .assertLatestNetworkSuggestion(timeSuggestion)
.verifySystemClockWasNotSetAndResetCallTracking();
}
@Test
- public void suggestionsFromGnssOriginNotInPriorityList_areIgnored() {
+ public void suggestionsFromGnssOriginNotInPriorityList_areNotUsed() {
ConfigurationInternal configInternal =
new ConfigurationInternal.Builder(CONFIG_AUTO_ENABLED)
.setOriginPriorities(ORIGIN_TELEPHONY)
@@ -1777,7 +1828,7 @@
}
@Test
- public void suggestionsFromExternalOriginNotInPriorityList_areIgnored() {
+ public void suggestionsFromExternalOriginNotInPriorityList_areNotUsed() {
ConfigurationInternal configInternal =
new ConfigurationInternal.Builder(CONFIG_AUTO_ENABLED)
.setOriginPriorities(ORIGIN_TELEPHONY)
@@ -2015,6 +2066,11 @@
return this;
}
+ Script simulateClearLatestNetworkSuggestion() {
+ mTimeDetectorStrategy.clearLatestNetworkSuggestion();
+ return this;
+ }
+
Script simulateGnssTimeSuggestion(GnssTimeSuggestion timeSuggestion) {
mTimeDetectorStrategy.suggestGnssTime(timeSuggestion);
return this;
@@ -2056,6 +2112,12 @@
return this;
}
+ /** Calls {@link TimeDetectorStrategy#confirmTime(UnixEpochTime)}. */
+ Script simulateConfirmTime(UnixEpochTime confirmationTime, boolean expectedReturnValue) {
+ assertEquals(expectedReturnValue, mTimeDetectorStrategy.confirmTime(confirmationTime));
+ return this;
+ }
+
Script verifySystemClockWasNotSetAndResetCallTracking() {
mFakeEnvironment.verifySystemClockNotSet();
mFakeEnvironment.resetCallTracking();
@@ -2218,11 +2280,6 @@
long calculateTimeInMillisForNow(UnixEpochTime unixEpochTime) {
return unixEpochTime.at(peekElapsedRealtimeMillis()).getUnixEpochTimeMillis();
}
-
- Script simulateConfirmTime(UnixEpochTime confirmationTime, boolean expectedReturnValue) {
- assertEquals(expectedReturnValue, mTimeDetectorStrategy.confirmTime(confirmationTime));
- return this;
- }
}
private static TelephonyTimeSuggestion createTelephonyTimeSuggestion(int slotIndex,
diff --git a/services/tests/uiservicestests/src/com/android/server/notification/PreferencesHelperTest.java b/services/tests/uiservicestests/src/com/android/server/notification/PreferencesHelperTest.java
index b64b281..19f3189 100644
--- a/services/tests/uiservicestests/src/com/android/server/notification/PreferencesHelperTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/PreferencesHelperTest.java
@@ -1703,6 +1703,7 @@
channel.setLockscreenVisibility(Notification.VISIBILITY_SECRET);
channel.setShowBadge(true);
channel.setAllowBubbles(false);
+ channel.setImportantConversation(true);
int lockMask = 0;
for (int i = 0; i < NotificationChannel.LOCKABLE_FIELDS.length; i++) {
lockMask |= NotificationChannel.LOCKABLE_FIELDS[i];
@@ -1718,6 +1719,7 @@
assertEquals(channel.shouldShowLights(), savedChannel.shouldShowLights());
assertFalse(savedChannel.canBypassDnd());
assertFalse(Notification.VISIBILITY_SECRET == savedChannel.getLockscreenVisibility());
+ assertFalse(channel.isImportantConversation());
assertEquals(channel.canShowBadge(), savedChannel.canShowBadge());
assertEquals(channel.canBubble(), savedChannel.canBubble());
@@ -4396,7 +4398,7 @@
new NotificationChannel("A person calls", "calls from A", IMPORTANCE_DEFAULT);
channel2.setConversationId(calls.getId(), convoId);
channel2.setImportantConversation(true);
- mHelper.createNotificationChannel(PKG_O, UID_O, channel2, true, false);
+ mHelper.createNotificationChannel(PKG_O, UID_O, channel2, false, false);
List<ConversationChannelWrapper> convos =
mHelper.getConversations(IntArray.wrap(new int[] {0}), false);
@@ -4473,7 +4475,7 @@
new NotificationChannel("A person calls", "calls from A", IMPORTANCE_DEFAULT);
channel2.setConversationId(calls.getId(), convoId);
channel2.setImportantConversation(true);
- mHelper.createNotificationChannel(PKG_O, UID_O, channel2, true, false);
+ mHelper.createNotificationChannel(PKG_O, UID_O, channel2, false, false);
List<ConversationChannelWrapper> convos =
mHelper.getConversations(IntArray.wrap(new int[] {0}), false);
@@ -4501,13 +4503,13 @@
new NotificationChannel("A person msgs", "messages from A", IMPORTANCE_DEFAULT);
channel.setConversationId(messages.getId(), convoId);
channel.setImportantConversation(true);
- mHelper.createNotificationChannel(PKG_O, UID_O, channel, true, false);
+ mHelper.createNotificationChannel(PKG_O, UID_O, channel, false, false);
NotificationChannel diffConvo =
new NotificationChannel("B person msgs", "messages from B", IMPORTANCE_DEFAULT);
diffConvo.setConversationId(p.getId(), "different convo");
diffConvo.setImportantConversation(true);
- mHelper.createNotificationChannel(PKG_P, UID_P, diffConvo, true, false);
+ mHelper.createNotificationChannel(PKG_P, UID_P, diffConvo, false, false);
NotificationChannel channel2 =
new NotificationChannel("A person calls", "calls from A", IMPORTANCE_DEFAULT);
@@ -4534,7 +4536,7 @@
new NotificationChannel("A person msgs", "messages from A", IMPORTANCE_DEFAULT);
channel.setConversationId(messages.getId(), convoId);
channel.setImportantConversation(true);
- mHelper.createNotificationChannel(PKG_O, UID_O, channel, true, false);
+ mHelper.createNotificationChannel(PKG_O, UID_O, channel, false, false);
mHelper.permanentlyDeleteNotificationChannel(PKG_O, UID_O, "messages");
@@ -4935,7 +4937,7 @@
"conversation", IMPORTANCE_DEFAULT);
friend.setConversationId(parent.getId(), "friend");
friend.setImportantConversation(true);
- mHelper.createNotificationChannel(PKG_O, UID_O, friend, true, false);
+ mHelper.createNotificationChannel(PKG_O, UID_O, friend, false, false);
ArrayList<StatsEvent> events = new ArrayList<>();
mHelper.pullPackageChannelPreferencesStats(events);
diff --git a/services/tests/wmtests/Android.bp b/services/tests/wmtests/Android.bp
index 2ce7cea..e5371975 100644
--- a/services/tests/wmtests/Android.bp
+++ b/services/tests/wmtests/Android.bp
@@ -27,13 +27,13 @@
],
tools: ["protologtool"],
cmd: "$(location protologtool) transform-protolog-calls " +
- "--protolog-class com.android.internal.protolog.common.ProtoLog " +
- "--protolog-impl-class com.android.internal.protolog.ProtoLogImpl " +
- "--protolog-cache-class 'com.android.server.wm.ProtoLogCache' " +
- "--loggroups-class com.android.internal.protolog.ProtoLogGroup " +
- "--loggroups-jar $(location :protolog-groups) " +
- "--output-srcjar $(out) " +
- "$(locations :wmtests-sources)",
+ "--protolog-class com.android.internal.protolog.common.ProtoLog " +
+ "--protolog-impl-class com.android.internal.protolog.ProtoLogImpl " +
+ "--protolog-cache-class 'com.android.server.wm.ProtoLogCache' " +
+ "--loggroups-class com.android.internal.protolog.ProtoLogGroup " +
+ "--loggroups-jar $(location :protolog-groups) " +
+ "--output-srcjar $(out) " +
+ "$(locations :wmtests-sources)",
out: ["wmtests.protolog.srcjar"],
}
@@ -41,7 +41,10 @@
name: "WmTests",
// We only want this apk build for tests.
- srcs: [":wmtests.protologsrc"],
+ srcs: [
+ ":wmtests.protologsrc",
+ "src/**/*.aidl",
+ ],
static_libs: [
"frameworks-base-testutils",
diff --git a/services/tests/wmtests/AndroidManifest.xml b/services/tests/wmtests/AndroidManifest.xml
index 593ee4a..b51feb3 100644
--- a/services/tests/wmtests/AndroidManifest.xml
+++ b/services/tests/wmtests/AndroidManifest.xml
@@ -90,6 +90,9 @@
android:foregroundServiceType="mediaProjection"
android:enabled="true">
</service>
+
+ <service android:name="com.android.server.wm.scvh.EmbeddedSCVHService"
+ android:process="com.android.server.wm.scvh.embedded_process" />
</application>
<instrumentation
diff --git a/services/tests/wmtests/src/com/android/server/policy/TestPhoneWindowManager.java b/services/tests/wmtests/src/com/android/server/policy/TestPhoneWindowManager.java
index a76b82b..fd1ca68 100644
--- a/services/tests/wmtests/src/com/android/server/policy/TestPhoneWindowManager.java
+++ b/services/tests/wmtests/src/com/android/server/policy/TestPhoneWindowManager.java
@@ -407,7 +407,7 @@
void assertShowRecentApps() {
waitForIdle();
- verify(mStatusBarManagerInternal).showRecentApps(anyBoolean());
+ verify(mStatusBarManagerInternal).showRecentApps(anyBoolean(), anyBoolean());
}
void assertSwitchKeyboardLayout() {
diff --git a/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java b/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java
index 4ee87d4..e02863e 100644
--- a/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java
@@ -58,6 +58,7 @@
import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION;
import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_STARTING;
import static android.view.WindowManager.LayoutParams.TYPE_BASE_APPLICATION;
+import static android.view.WindowManager.LayoutParams.TYPE_INPUT_METHOD;
import static android.view.WindowManager.TRANSIT_CLOSE;
import static android.view.WindowManager.TRANSIT_OLD_ACTIVITY_OPEN;
import static android.view.WindowManager.TRANSIT_PIP;
@@ -3143,46 +3144,6 @@
assertFalse(activity.mDisplayContent.mClosingApps.contains(activity));
}
- @Test
- public void testImeInsetsFrozenFlag_resetWhenReparented() {
- final ActivityRecord activity = createActivityWithTask();
- final WindowState app = createWindow(null, TYPE_APPLICATION, activity, "app");
- final WindowState imeWindow = createWindow(null, TYPE_APPLICATION, "imeWindow");
- final Task newTask = new TaskBuilder(mSupervisor).build();
- makeWindowVisible(app, imeWindow);
- mDisplayContent.mInputMethodWindow = imeWindow;
- mDisplayContent.setImeLayeringTarget(app);
- mDisplayContent.setImeInputTarget(app);
-
- // Simulate app is closing and expect the last IME is shown and IME insets is frozen.
- app.mActivityRecord.commitVisibility(false, false);
- assertTrue(app.mActivityRecord.mLastImeShown);
- assertTrue(app.mActivityRecord.mImeInsetsFrozenUntilStartInput);
-
- // Expect IME insets frozen state will reset when the activity is reparent to the new task.
- activity.setState(RESUMED, "test");
- activity.reparent(newTask, 0 /* top */, "test");
- assertFalse(app.mActivityRecord.mImeInsetsFrozenUntilStartInput);
- }
-
- @SetupWindows(addWindows = W_INPUT_METHOD)
- @Test
- public void testImeInsetsFrozenFlag_resetWhenResized() {
- final WindowState app = createWindow(null, TYPE_APPLICATION, "app");
- makeWindowVisibleAndDrawn(app, mImeWindow);
- mDisplayContent.setImeLayeringTarget(app);
- mDisplayContent.setImeInputTarget(app);
-
- // Simulate app is closing and expect the last IME is shown and IME insets is frozen.
- app.mActivityRecord.commitVisibility(false, false);
- assertTrue(app.mActivityRecord.mLastImeShown);
- assertTrue(app.mActivityRecord.mImeInsetsFrozenUntilStartInput);
-
- // Expect IME insets frozen state will reset when the activity is reparent to the new task.
- app.mActivityRecord.onResize();
- assertFalse(app.mActivityRecord.mImeInsetsFrozenUntilStartInput);
- }
-
@SetupWindows(addWindows = W_INPUT_METHOD)
@Test
public void testImeInsetsFrozenFlag_resetWhenNoImeFocusableInActivity() {
@@ -3216,6 +3177,10 @@
public void testImeInsetsFrozenFlag_resetWhenReportedToBeImeInputTarget() {
final WindowState app = createWindow(null, TYPE_APPLICATION, "app");
+ mDisplayContent.getInsetsStateController().getSourceProvider(ITYPE_IME).setWindowContainer(
+ mImeWindow, null, null);
+ mImeWindow.getControllableInsetProvider().setServerVisible(true);
+
InsetsSource imeSource = new InsetsSource(ITYPE_IME, ime());
app.mAboveInsetsState.addSource(imeSource);
mDisplayContent.setImeLayeringTarget(app);
@@ -3233,8 +3198,10 @@
// Simulate app re-start input or turning screen off/on then unlocked by un-secure
// keyguard to back to the app, expect IME insets is not frozen
- mDisplayContent.updateImeInputAndControlTarget(app);
app.mActivityRecord.commitVisibility(true, false);
+ mDisplayContent.updateImeInputAndControlTarget(app);
+ mDisplayContent.mWmService.mRoot.performSurfacePlacement();
+
assertFalse(app.mActivityRecord.mImeInsetsFrozenUntilStartInput);
imeSource.setVisible(true);
@@ -3274,12 +3241,12 @@
assertTrue(app2.mActivityRecord.mImeInsetsFrozenUntilStartInput);
// Simulate switching to app2 to make it visible to be IME targets.
- makeWindowVisibleAndDrawn(app2);
spyOn(app2);
spyOn(app2.mClient);
ArgumentCaptor<InsetsState> insetsStateCaptor = ArgumentCaptor.forClass(InsetsState.class);
doReturn(true).when(app2).isReadyToDispatchInsetsState();
mDisplayContent.setImeLayeringTarget(app2);
+ app2.mActivityRecord.commitVisibility(true, false);
mDisplayContent.updateImeInputAndControlTarget(app2);
mDisplayContent.mWmService.mRoot.performSurfacePlacement();
@@ -3293,6 +3260,57 @@
}
@Test
+ public void testImeInsetsFrozenFlag_multiWindowActivities() {
+ final WindowToken imeToken = createTestWindowToken(TYPE_INPUT_METHOD, mDisplayContent);
+ final WindowState ime = createWindow(null, TYPE_INPUT_METHOD, imeToken, "ime");
+ makeWindowVisibleAndDrawn(ime);
+
+ // Create a split-screen root task with activity1 and activity 2.
+ final Task task = new TaskBuilder(mSupervisor)
+ .setCreateParentTask(true).setCreateActivity(true).build();
+ task.getRootTask().setWindowingMode(WINDOWING_MODE_MULTI_WINDOW);
+ final ActivityRecord activity1 = task.getTopNonFinishingActivity();
+ activity1.getTask().setResumedActivity(activity1, "testApp1");
+
+ final ActivityRecord activity2 = new TaskBuilder(mSupervisor)
+ .setWindowingMode(WINDOWING_MODE_MULTI_WINDOW)
+ .setCreateActivity(true).build().getTopMostActivity();
+ activity2.getTask().setResumedActivity(activity2, "testApp2");
+ activity2.getTask().setParent(task.getRootTask());
+
+ // Simulate activity1 and activity2 both have set mImeInsetsFrozenUntilStartInput when
+ // invisible to user.
+ activity1.mImeInsetsFrozenUntilStartInput = true;
+ activity2.mImeInsetsFrozenUntilStartInput = true;
+
+ final WindowState app1 = createWindow(null, TYPE_APPLICATION, activity1, "app1");
+ final WindowState app2 = createWindow(null, TYPE_APPLICATION, activity2, "app2");
+ makeWindowVisibleAndDrawn(app1, app2);
+
+ final InsetsStateController controller = mDisplayContent.getInsetsStateController();
+ controller.getSourceProvider(ITYPE_IME).setWindowContainer(
+ ime, null, null);
+ ime.getControllableInsetProvider().setServerVisible(true);
+
+ // app1 starts input and expect IME insets for all activities in split-screen will be
+ // frozen until the input started.
+ mDisplayContent.setImeLayeringTarget(app1);
+ mDisplayContent.updateImeInputAndControlTarget(app1);
+ mDisplayContent.mWmService.mRoot.performSurfacePlacement();
+
+ assertEquals(app1, mDisplayContent.getImeInputTarget());
+ assertFalse(activity1.mImeInsetsFrozenUntilStartInput);
+ assertFalse(activity2.mImeInsetsFrozenUntilStartInput);
+
+ app1.setRequestedVisibleTypes(ime());
+ controller.onInsetsModified(app1);
+
+ // Expect all activities in split-screen will get IME insets visible state
+ assertTrue(app1.getInsetsState().peekSource(ITYPE_IME).isVisible());
+ assertTrue(app2.getInsetsState().peekSource(ITYPE_IME).isVisible());
+ }
+
+ @Test
public void testInClosingAnimation_visibilityNotCommitted_doNotHideSurface() {
final WindowState app = createWindow(null, TYPE_APPLICATION, "app");
makeWindowVisibleAndDrawn(app);
diff --git a/services/tests/wmtests/src/com/android/server/wm/DisplayRotationCompatPolicyTests.java b/services/tests/wmtests/src/com/android/server/wm/DisplayRotationCompatPolicyTests.java
index 8bb79e3..45b30b2 100644
--- a/services/tests/wmtests/src/com/android/server/wm/DisplayRotationCompatPolicyTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/DisplayRotationCompatPolicyTests.java
@@ -155,6 +155,18 @@
}
@Test
+ public void testTreatmentDisabledPerApp_noForceRotationOrRefresh()
+ throws Exception {
+ configureActivity(SCREEN_ORIENTATION_PORTRAIT);
+ when(mActivity.mLetterboxUiController.shouldForceRotateForCameraCompat())
+ .thenReturn(false);
+
+ mCameraAvailabilityCallback.onCameraOpened(CAMERA_ID_1, TEST_PACKAGE_1);
+
+ assertNoForceRotationOrRefresh();
+ }
+
+ @Test
public void testMultiWindowMode_returnUnspecified_noForceRotationOrRefresh() throws Exception {
configureActivity(SCREEN_ORIENTATION_PORTRAIT);
final TestSplitOrganizer organizer = new TestSplitOrganizer(mAtm, mDisplayContent);
@@ -327,7 +339,21 @@
}
@Test
- public void testOnActivityConfigurationChanging_refreshDisabled_noRefresh() throws Exception {
+ public void testOnActivityConfigurationChanging_refreshDisabledViaFlag_noRefresh()
+ throws Exception {
+ configureActivity(SCREEN_ORIENTATION_PORTRAIT);
+ when(mActivity.mLetterboxUiController.shouldRefreshActivityForCameraCompat())
+ .thenReturn(false);
+
+ mCameraAvailabilityCallback.onCameraOpened(CAMERA_ID_1, TEST_PACKAGE_1);
+ callOnActivityConfigurationChanging(mActivity, /* isDisplayRotationChanging */ true);
+
+ assertActivityRefreshRequested(/* refreshRequested */ false);
+ }
+
+ @Test
+ public void testOnActivityConfigurationChanging_refreshDisabledPerApp_noRefresh()
+ throws Exception {
when(mLetterboxConfiguration.isCameraCompatRefreshEnabled()).thenReturn(false);
configureActivity(SCREEN_ORIENTATION_PORTRAIT);
@@ -362,6 +388,19 @@
assertActivityRefreshRequested(/* refreshRequested */ true, /* cycleThroughStop */ false);
}
+ @Test
+ public void testOnActivityConfigurationChanging_cycleThroughStopDisabledForApp()
+ throws Exception {
+ configureActivity(SCREEN_ORIENTATION_PORTRAIT);
+ when(mActivity.mLetterboxUiController.shouldRefreshActivityViaPauseForCameraCompat())
+ .thenReturn(true);
+
+ mCameraAvailabilityCallback.onCameraOpened(CAMERA_ID_1, TEST_PACKAGE_1);
+ callOnActivityConfigurationChanging(mActivity, /* isDisplayRotationChanging */ true);
+
+ assertActivityRefreshRequested(/* refreshRequested */ true, /* cycleThroughStop */ false);
+ }
+
private void configureActivity(@ScreenOrientation int activityOrientation) {
configureActivityAndDisplay(activityOrientation, ORIENTATION_PORTRAIT);
}
diff --git a/services/tests/wmtests/src/com/android/server/wm/InsetsStateControllerTest.java b/services/tests/wmtests/src/com/android/server/wm/InsetsStateControllerTest.java
index cdb2642..4d69979 100644
--- a/services/tests/wmtests/src/com/android/server/wm/InsetsStateControllerTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/InsetsStateControllerTest.java
@@ -39,6 +39,7 @@
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;
+import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.atLeastOnce;
import static org.mockito.Mockito.clearInvocations;
import static org.mockito.Mockito.spy;
@@ -411,7 +412,14 @@
final WindowState navBar = createTestWindow("navBar");
getController().getSourceProvider(ITYPE_IME).setWindowContainer(ime, null, null);
+
+ waitUntilHandlersIdle();
+ clearInvocations(mDisplayContent);
getController().getSourceProvider(ITYPE_IME).setClientVisible(true);
+ waitUntilHandlersIdle();
+ // The visibility change should trigger a traversal to notify the change.
+ verify(mDisplayContent).notifyInsetsChanged(any());
+
getController().getSourceProvider(ITYPE_STATUS_BAR).setWindowContainer(statusBar, null,
null);
getController().getSourceProvider(ITYPE_NAVIGATION_BAR).setWindowContainer(navBar, null,
diff --git a/services/tests/wmtests/src/com/android/server/wm/LetterboxUiControllerTest.java b/services/tests/wmtests/src/com/android/server/wm/LetterboxUiControllerTest.java
index 6d778afe..5e087f0 100644
--- a/services/tests/wmtests/src/com/android/server/wm/LetterboxUiControllerTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/LetterboxUiControllerTest.java
@@ -16,8 +16,14 @@
package com.android.server.wm;
+import static android.content.pm.ActivityInfo.OVERRIDE_CAMERA_COMPAT_DISABLE_FORCE_ROTATION;
+import static android.content.pm.ActivityInfo.OVERRIDE_CAMERA_COMPAT_DISABLE_REFRESH;
+import static android.content.pm.ActivityInfo.OVERRIDE_CAMERA_COMPAT_ENABLE_REFRESH_VIA_PAUSE;
import static android.content.pm.ActivityInfo.OVERRIDE_ENABLE_COMPAT_IGNORE_REQUESTED_ORIENTATION;
import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED;
+import static android.view.WindowManager.PROPERTY_CAMERA_COMPAT_ALLOW_FORCE_ROTATION;
+import static android.view.WindowManager.PROPERTY_CAMERA_COMPAT_ALLOW_REFRESH;
+import static android.view.WindowManager.PROPERTY_CAMERA_COMPAT_ENABLE_REFRESH_VIA_PAUSE;
import static android.view.WindowManager.PROPERTY_COMPAT_IGNORE_REQUESTED_ORIENTATION;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn;
@@ -74,6 +80,8 @@
mController = new LetterboxUiController(mWm, mActivity);
}
+ // shouldIgnoreRequestedOrientation
+
@Test
@EnableCompatChanges({OVERRIDE_ENABLE_COMPAT_IGNORE_REQUESTED_ORIENTATION})
public void testShouldIgnoreRequestedOrientation_activityRelaunching_returnsTrue() {
@@ -134,7 +142,7 @@
}
@Test
- @EnableCompatChanges({OVERRIDE_ENABLE_COMPAT_IGNORE_REQUESTED_ORIENTATION})
+ @EnableCompatChanges({OVERRIDE_CAMERA_COMPAT_DISABLE_REFRESH})
public void testShouldIgnoreRequestedOrientation_flagIsDisabled_returnsFalse() {
prepareActivityThatShouldIgnoreRequestedOrientationDuringRelaunch();
doReturn(false).when(mLetterboxConfiguration)
@@ -143,6 +151,163 @@
assertFalse(mController.shouldIgnoreRequestedOrientation(SCREEN_ORIENTATION_UNSPECIFIED));
}
+ // shouldRefreshActivityForCameraCompat
+
+ @Test
+ public void testShouldRefreshActivityForCameraCompat_flagIsDisabled_returnsFalse() {
+ doReturn(false).when(mLetterboxConfiguration)
+ .isCameraCompatTreatmentEnabled(/* checkDeviceConfig */ true);
+
+ assertFalse(mController.shouldRefreshActivityForCameraCompat());
+ }
+
+ @Test
+ @EnableCompatChanges({OVERRIDE_CAMERA_COMPAT_DISABLE_REFRESH})
+ public void testShouldRefreshActivityForCameraCompat_overrideEnabled_returnsFalse() {
+ doReturn(true).when(mLetterboxConfiguration)
+ .isCameraCompatTreatmentEnabled(/* checkDeviceConfig */ true);
+
+ assertFalse(mController.shouldRefreshActivityForCameraCompat());
+ }
+
+ @Test
+ @EnableCompatChanges({OVERRIDE_CAMERA_COMPAT_DISABLE_REFRESH})
+ public void testShouldRefreshActivityForCameraCompat_propertyIsTrueAndOverride_returnsFalse()
+ throws Exception {
+ doReturn(true).when(mLetterboxConfiguration)
+ .isCameraCompatTreatmentEnabled(/* checkDeviceConfig */ true);
+ mockThatProperty(PROPERTY_CAMERA_COMPAT_ALLOW_REFRESH, /* value */ true);
+
+ mController = new LetterboxUiController(mWm, mActivity);
+
+ assertFalse(mController.shouldRefreshActivityForCameraCompat());
+ }
+
+ @Test
+ public void testShouldRefreshActivityForCameraCompat_propertyIsFalse_returnsFalse()
+ throws Exception {
+ doReturn(true).when(mLetterboxConfiguration)
+ .isCameraCompatTreatmentEnabled(/* checkDeviceConfig */ true);
+ mockThatProperty(PROPERTY_CAMERA_COMPAT_ALLOW_REFRESH, /* value */ false);
+
+ mController = new LetterboxUiController(mWm, mActivity);
+
+ assertFalse(mController.shouldRefreshActivityForCameraCompat());
+ }
+
+ @Test
+ public void testShouldRefreshActivityForCameraCompat_propertyIsTrue_returnsTrue()
+ throws Exception {
+ doReturn(true).when(mLetterboxConfiguration)
+ .isCameraCompatTreatmentEnabled(/* checkDeviceConfig */ true);
+ mockThatProperty(PROPERTY_CAMERA_COMPAT_ALLOW_REFRESH, /* value */ true);
+
+ mController = new LetterboxUiController(mWm, mActivity);
+
+ assertTrue(mController.shouldRefreshActivityForCameraCompat());
+ }
+
+ // shouldRefreshActivityViaPauseForCameraCompat
+
+ @Test
+ @EnableCompatChanges({OVERRIDE_CAMERA_COMPAT_ENABLE_REFRESH_VIA_PAUSE})
+ public void testShouldRefreshActivityViaPauseForCameraCompat_flagIsDisabled_returnsFalse() {
+ doReturn(false).when(mLetterboxConfiguration)
+ .isCameraCompatTreatmentEnabled(/* checkDeviceConfig */ true);
+
+ assertFalse(mController.shouldRefreshActivityViaPauseForCameraCompat());
+ }
+
+ @Test
+ @EnableCompatChanges({OVERRIDE_CAMERA_COMPAT_ENABLE_REFRESH_VIA_PAUSE})
+ public void testShouldRefreshActivityViaPauseForCameraCompat_overrideEnabled_returnsTrue() {
+ doReturn(true).when(mLetterboxConfiguration)
+ .isCameraCompatTreatmentEnabled(/* checkDeviceConfig */ true);
+
+ assertTrue(mController.shouldRefreshActivityViaPauseForCameraCompat());
+ }
+
+ @Test
+ @EnableCompatChanges({OVERRIDE_CAMERA_COMPAT_ENABLE_REFRESH_VIA_PAUSE})
+ public void testShouldRefreshActivityViaPauseForCameraCompat_propertyIsFalseAndOverride_returnFalse()
+ throws Exception {
+ doReturn(true).when(mLetterboxConfiguration)
+ .isCameraCompatTreatmentEnabled(/* checkDeviceConfig */ true);
+ mockThatProperty(PROPERTY_CAMERA_COMPAT_ENABLE_REFRESH_VIA_PAUSE, /* value */ false);
+
+ mController = new LetterboxUiController(mWm, mActivity);
+
+ assertFalse(mController.shouldRefreshActivityViaPauseForCameraCompat());
+ }
+
+ @Test
+ public void testShouldRefreshActivityViaPauseForCameraCompat_propertyIsTrue_returnsTrue()
+ throws Exception {
+ doReturn(true).when(mLetterboxConfiguration)
+ .isCameraCompatTreatmentEnabled(/* checkDeviceConfig */ true);
+ mockThatProperty(PROPERTY_CAMERA_COMPAT_ENABLE_REFRESH_VIA_PAUSE, /* value */ true);
+
+ mController = new LetterboxUiController(mWm, mActivity);
+
+ assertTrue(mController.shouldRefreshActivityViaPauseForCameraCompat());
+ }
+
+ // shouldForceRotateForCameraCompat
+
+ @Test
+ public void testShouldForceRotateForCameraCompat_flagIsDisabled_returnsFalse() {
+ doReturn(false).when(mLetterboxConfiguration)
+ .isCameraCompatTreatmentEnabled(/* checkDeviceConfig */ true);
+
+ assertFalse(mController.shouldForceRotateForCameraCompat());
+ }
+
+ @Test
+ @EnableCompatChanges({OVERRIDE_CAMERA_COMPAT_DISABLE_FORCE_ROTATION})
+ public void testShouldForceRotateForCameraCompat_overrideEnabled_returnsFalse() {
+ doReturn(true).when(mLetterboxConfiguration)
+ .isCameraCompatTreatmentEnabled(/* checkDeviceConfig */ true);
+
+ assertFalse(mController.shouldForceRotateForCameraCompat());
+ }
+
+ @Test
+ @EnableCompatChanges({OVERRIDE_CAMERA_COMPAT_DISABLE_FORCE_ROTATION})
+ public void testShouldForceRotateForCameraCompat_propertyIsTrueAndOverride_returnsFalse()
+ throws Exception {
+ doReturn(true).when(mLetterboxConfiguration)
+ .isCameraCompatTreatmentEnabled(/* checkDeviceConfig */ true);
+ mockThatProperty(PROPERTY_CAMERA_COMPAT_ALLOW_FORCE_ROTATION, /* value */ true);
+
+ mController = new LetterboxUiController(mWm, mActivity);
+
+ assertFalse(mController.shouldForceRotateForCameraCompat());
+ }
+
+ @Test
+ public void testShouldForceRotateForCameraCompat_propertyIsFalse_returnsFalse()
+ throws Exception {
+ doReturn(true).when(mLetterboxConfiguration)
+ .isCameraCompatTreatmentEnabled(/* checkDeviceConfig */ true);
+ mockThatProperty(PROPERTY_CAMERA_COMPAT_ALLOW_FORCE_ROTATION, /* value */ false);
+
+ mController = new LetterboxUiController(mWm, mActivity);
+
+ assertFalse(mController.shouldForceRotateForCameraCompat());
+ }
+
+ @Test
+ public void testShouldForceRotateForCameraCompat_propertyIsTrue_returnsTrue()
+ throws Exception {
+ doReturn(true).when(mLetterboxConfiguration)
+ .isCameraCompatTreatmentEnabled(/* checkDeviceConfig */ true);
+ mockThatProperty(PROPERTY_CAMERA_COMPAT_ALLOW_FORCE_ROTATION, /* value */ true);
+
+ mController = new LetterboxUiController(mWm, mActivity);
+
+ assertTrue(mController.shouldForceRotateForCameraCompat());
+ }
+
private void mockThatProperty(String propertyName, boolean value) throws Exception {
Property property = new Property(propertyName, /* value */ value, /* packageName */ "",
/* className */ "");
diff --git a/services/tests/wmtests/src/com/android/server/wm/RecentTasksTest.java b/services/tests/wmtests/src/com/android/server/wm/RecentTasksTest.java
index d364dbb..74dd361 100644
--- a/services/tests/wmtests/src/com/android/server/wm/RecentTasksTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/RecentTasksTest.java
@@ -30,6 +30,7 @@
import static android.content.pm.ActivityInfo.LAUNCH_MULTIPLE;
import static android.content.pm.ActivityInfo.LAUNCH_SINGLE_INSTANCE;
import static android.content.res.Configuration.ORIENTATION_PORTRAIT;
+import static android.os.Process.NOBODY_UID;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.doNothing;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn;
@@ -1207,20 +1208,35 @@
@Test
public void testCreateRecentTaskInfo_detachedTask() {
- final Task task = createTaskBuilder(".Task").setCreateActivity(true).build();
+ final Task task = createTaskBuilder(".Task").build();
+ final ComponentName componentName = getUniqueComponentName();
+ new ActivityBuilder(mSupervisor.mService)
+ .setTask(task)
+ .setUid(NOBODY_UID)
+ .setComponent(componentName)
+ .build();
final TaskDisplayArea tda = task.getDisplayArea();
assertTrue(task.isAttached());
assertTrue(task.supportsMultiWindow());
- RecentTaskInfo info = mRecentTasks.createRecentTaskInfo(task, true);
+ RecentTaskInfo info = mRecentTasks.createRecentTaskInfo(task, true /* stripExtras */,
+ true /* getTasksAllowed */);
assertTrue(info.supportsMultiWindow);
+ info = mRecentTasks.createRecentTaskInfo(task, true /* stripExtras */,
+ false /* getTasksAllowed */);
+
+ assertFalse(info.topActivity.equals(componentName));
+ assertFalse(info.topActivityInfo.packageName.equals(componentName.getPackageName()));
+ assertFalse(info.baseActivity.equals(componentName));
+
// The task can be put in split screen even if it is not attached now.
task.removeImmediately();
- info = mRecentTasks.createRecentTaskInfo(task, true);
+ info = mRecentTasks.createRecentTaskInfo(task, true /* stripExtras */,
+ true /* getTasksAllowed */);
assertTrue(info.supportsMultiWindow);
@@ -1229,7 +1245,8 @@
doReturn(false).when(tda).supportsNonResizableMultiWindow();
doReturn(false).when(task).isResizeable();
- info = mRecentTasks.createRecentTaskInfo(task, true);
+ info = mRecentTasks.createRecentTaskInfo(task, true /* stripExtras */,
+ true /* getTasksAllowed */);
assertFalse(info.supportsMultiWindow);
@@ -1237,7 +1254,8 @@
// the device supports it.
doReturn(true).when(tda).supportsNonResizableMultiWindow();
- info = mRecentTasks.createRecentTaskInfo(task, true);
+ info = mRecentTasks.createRecentTaskInfo(task, true /* stripExtras */,
+ true /* getTasksAllowed */);
assertTrue(info.supportsMultiWindow);
}
diff --git a/services/tests/wmtests/src/com/android/server/wm/SurfaceSyncGroupContinuousTest.java b/services/tests/wmtests/src/com/android/server/wm/SurfaceSyncGroupContinuousTest.java
index 8c49c26..e6f47a1 100644
--- a/services/tests/wmtests/src/com/android/server/wm/SurfaceSyncGroupContinuousTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/SurfaceSyncGroupContinuousTest.java
@@ -28,6 +28,8 @@
import androidx.test.rule.ActivityTestRule;
+import com.android.server.wm.scvh.SyncValidatorSCVHTestCase;
+
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
@@ -56,11 +58,21 @@
pressWakeupButton();
pressUnlockButton();
}
+ SurfaceSyncGroup.setTransactionFactory(SurfaceControl.Transaction::new);
}
@Test
public void testSurfaceViewSyncDuringResize() throws Throwable {
- SurfaceSyncGroup.setTransactionFactory(SurfaceControl.Transaction::new);
mCapturedActivity.verifyTest(new SurfaceSyncGroupValidatorTestCase(), mName);
}
+
+ @Test
+ public void testSurfaceControlViewHostIPCSync_Fast() throws Throwable {
+ mCapturedActivity.verifyTest(new SyncValidatorSCVHTestCase(0 /* delayMs */), mName);
+ }
+
+ @Test
+ public void testSurfaceControlViewHostIPCSync_Slow() throws Throwable {
+ mCapturedActivity.verifyTest(new SyncValidatorSCVHTestCase(100 /* delayMs */), mName);
+ }
}
diff --git a/services/tests/wmtests/src/com/android/server/wm/SurfaceSyncGroupTest.java b/services/tests/wmtests/src/com/android/server/wm/SurfaceSyncGroupTest.java
index d2cca9f..f655242 100644
--- a/services/tests/wmtests/src/com/android/server/wm/SurfaceSyncGroupTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/SurfaceSyncGroupTest.java
@@ -56,7 +56,7 @@
syncGroup.addSyncCompleteCallback(mExecutor, finishedLatch::countDown);
SyncTarget syncTarget = new SyncTarget();
syncGroup.addToSync(syncTarget, false /* parentSyncGroupMerge */);
- syncGroup.onTransactionReady(null);
+ syncGroup.markSyncReady();
syncTarget.onBufferReady();
@@ -76,7 +76,7 @@
syncGroup.addToSync(syncTarget1, false /* parentSyncGroupMerge */);
syncGroup.addToSync(syncTarget2, false /* parentSyncGroupMerge */);
syncGroup.addToSync(syncTarget3, false /* parentSyncGroupMerge */);
- syncGroup.onTransactionReady(null);
+ syncGroup.markSyncReady();
syncTarget1.onBufferReady();
assertNotEquals(0, finishedLatch.getCount());
@@ -98,7 +98,7 @@
SyncTarget syncTarget2 = new SyncTarget();
assertTrue(syncGroup.addToSync(syncTarget1, false /* parentSyncGroupMerge */));
- syncGroup.onTransactionReady(null);
+ syncGroup.markSyncReady();
// Adding to a sync that has been completed is also invalid since the sync id has been
// cleared.
assertFalse(syncGroup.addToSync(syncTarget2, false /* parentSyncGroupMerge */));
@@ -119,8 +119,8 @@
assertTrue(syncGroup1.addToSync(syncTarget1, false /* parentSyncGroupMerge */));
assertTrue(syncGroup2.addToSync(syncTarget2, false /* parentSyncGroupMerge */));
- syncGroup1.onTransactionReady(null);
- syncGroup2.onTransactionReady(null);
+ syncGroup1.markSyncReady();
+ syncGroup2.markSyncReady();
syncTarget1.onBufferReady();
@@ -149,9 +149,9 @@
assertTrue(syncGroup1.addToSync(syncTarget1, false /* parentSyncGroupMerge */));
assertTrue(syncGroup2.addToSync(syncTarget2, false /* parentSyncGroupMerge */));
- syncGroup1.onTransactionReady(null);
+ syncGroup1.markSyncReady();
syncGroup2.addToSync(syncGroup1, false /* parentSyncGroupMerge */);
- syncGroup2.onTransactionReady(null);
+ syncGroup2.markSyncReady();
// Finish syncTarget2 first to test that the syncGroup is not complete until the merged sync
// is also done.
@@ -185,7 +185,7 @@
assertTrue(syncGroup1.addToSync(syncTarget1, false /* parentSyncGroupMerge */));
assertTrue(syncGroup2.addToSync(syncTarget2, false /* parentSyncGroupMerge */));
- syncGroup1.onTransactionReady(null);
+ syncGroup1.markSyncReady();
syncTarget1.onBufferReady();
// The first sync will still get a callback when it's sync requirements are done.
@@ -193,7 +193,7 @@
assertEquals(0, finishedLatch1.getCount());
syncGroup2.addToSync(syncGroup1, false /* parentSyncGroupMerge */);
- syncGroup2.onTransactionReady(null);
+ syncGroup2.markSyncReady();
syncTarget2.onBufferReady();
// Verify that the second sync will receive complete since the merged sync was already
@@ -223,8 +223,8 @@
assertTrue(syncGroup2.addToSync(syncTarget1, false /* parentSyncGroupMerge */));
assertTrue(syncGroup2.addToSync(syncTarget3, false /* parentSyncGroupMerge */));
- syncGroup1.onTransactionReady(null);
- syncGroup2.onTransactionReady(null);
+ syncGroup1.markSyncReady();
+ syncGroup2.markSyncReady();
// Make target1 and target3 ready, but not target2. SyncGroup2 should not be ready since
// SyncGroup2 also waits for all of SyncGroup1 to finish, which includes target2
@@ -269,8 +269,8 @@
assertTrue(syncGroup2.addToSync(syncTarget1, false /* parentSyncGroupMerge */));
assertTrue(syncGroup2.addToSync(syncTarget3, false /* parentSyncGroupMerge */));
- syncGroup1.onTransactionReady(null);
- syncGroup2.onTransactionReady(null);
+ syncGroup1.markSyncReady();
+ syncGroup2.markSyncReady();
syncTarget1.onBufferReady();
@@ -304,7 +304,7 @@
SyncTarget syncTarget = new SyncTarget();
assertTrue(syncGroup.addToSync(syncTarget, true /* parentSyncGroupMerge */));
- syncTarget.onTransactionReady(null);
+ syncTarget.markSyncReady();
// When parentSyncGroupMerge is true, the transaction passed in merges the main SyncGroup
// transaction first because it knows the previous parentSyncGroup is older so it should
@@ -329,7 +329,7 @@
SyncTarget syncTarget = new SyncTarget();
assertTrue(syncGroup.addToSync(syncTarget, false /* parentSyncGroupMerge */));
- syncTarget.onTransactionReady(null);
+ syncTarget.markSyncReady();
// When parentSyncGroupMerge is false, the transaction passed in should not merge
// the main SyncGroup since we don't need to change the transaction order
@@ -346,7 +346,7 @@
syncGroup.addToSync(syncTarget, false /* parentSyncGroupMerge */);
// Add the syncTarget to the same syncGroup and ensure it doesn't crash.
syncGroup.addToSync(syncTarget, false /* parentSyncGroupMerge */);
- syncGroup.onTransactionReady(null);
+ syncGroup.markSyncReady();
syncTarget.onBufferReady();
@@ -364,8 +364,7 @@
}
void onBufferReady() {
- SurfaceControl.Transaction t = new StubTransaction();
- onTransactionReady(t);
+ markSyncReady();
}
}
}
diff --git a/services/tests/wmtests/src/com/android/server/wm/TaskFragmentOrganizerControllerTest.java b/services/tests/wmtests/src/com/android/server/wm/TaskFragmentOrganizerControllerTest.java
index b70d8bd..035d73d 100644
--- a/services/tests/wmtests/src/com/android/server/wm/TaskFragmentOrganizerControllerTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/TaskFragmentOrganizerControllerTest.java
@@ -23,7 +23,12 @@
import static android.view.WindowManager.TRANSIT_CLOSE;
import static android.view.WindowManager.TRANSIT_NONE;
import static android.view.WindowManager.TRANSIT_OPEN;
+import static android.window.TaskFragmentOperation.OP_TYPE_CREATE_TASK_FRAGMENT;
+import static android.window.TaskFragmentOperation.OP_TYPE_DELETE_TASK_FRAGMENT;
+import static android.window.TaskFragmentOperation.OP_TYPE_REPARENT_ACTIVITY_TO_TASK_FRAGMENT;
+import static android.window.TaskFragmentOperation.OP_TYPE_SET_ADJACENT_TASK_FRAGMENTS;
import static android.window.TaskFragmentOperation.OP_TYPE_SET_ANIMATION_PARAMS;
+import static android.window.TaskFragmentOperation.OP_TYPE_START_ACTIVITY_IN_TASK_FRAGMENT;
import static android.window.TaskFragmentOrganizer.KEY_ERROR_CALLBACK_OP_TYPE;
import static android.window.TaskFragmentOrganizer.KEY_ERROR_CALLBACK_THROWABLE;
import static android.window.TaskFragmentOrganizer.TASK_FRAGMENT_TRANSIT_CHANGE;
@@ -36,13 +41,6 @@
import static android.window.TaskFragmentTransaction.TYPE_TASK_FRAGMENT_INFO_CHANGED;
import static android.window.TaskFragmentTransaction.TYPE_TASK_FRAGMENT_PARENT_INFO_CHANGED;
import static android.window.TaskFragmentTransaction.TYPE_TASK_FRAGMENT_VANISHED;
-import static android.window.WindowContainerTransaction.HierarchyOp.HIERARCHY_OP_TYPE_CREATE_TASK_FRAGMENT;
-import static android.window.WindowContainerTransaction.HierarchyOp.HIERARCHY_OP_TYPE_DELETE_TASK_FRAGMENT;
-import static android.window.WindowContainerTransaction.HierarchyOp.HIERARCHY_OP_TYPE_REPARENT_ACTIVITY_TO_TASK_FRAGMENT;
-import static android.window.WindowContainerTransaction.HierarchyOp.HIERARCHY_OP_TYPE_REPARENT_CHILDREN;
-import static android.window.WindowContainerTransaction.HierarchyOp.HIERARCHY_OP_TYPE_SET_ADJACENT_ROOTS;
-import static android.window.WindowContainerTransaction.HierarchyOp.HIERARCHY_OP_TYPE_SET_ADJACENT_TASK_FRAGMENTS;
-import static android.window.WindowContainerTransaction.HierarchyOp.HIERARCHY_OP_TYPE_START_ACTIVITY_IN_TASK_FRAGMENT;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.doNothing;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn;
@@ -339,11 +337,11 @@
final Throwable exception = new IllegalArgumentException("Test exception");
mController.onTaskFragmentError(mTaskFragment.getTaskFragmentOrganizer(),
- mErrorToken, null /* taskFragment */, HIERARCHY_OP_TYPE_SET_ADJACENT_ROOTS,
+ mErrorToken, null /* taskFragment */, OP_TYPE_SET_ADJACENT_TASK_FRAGMENTS,
exception);
mController.dispatchPendingEvents();
- assertTaskFragmentErrorTransaction(HIERARCHY_OP_TYPE_SET_ADJACENT_ROOTS,
+ assertTaskFragmentErrorTransaction(OP_TYPE_SET_ADJACENT_TASK_FRAGMENTS,
exception.getClass());
}
@@ -519,50 +517,20 @@
@Test
public void testApplyTransaction_enforceHierarchyChange_deleteTaskFragment() {
doReturn(true).when(mTaskFragment).isAttached();
-
- // Throw exception if the transaction is trying to change a window that is not organized by
- // the organizer.
- mTransaction.deleteTaskFragment(mFragmentWindowToken);
-
- assertApplyTransactionDisallowed(mTransaction);
-
- // Allow transaction to change a TaskFragment created by the organizer.
- mTaskFragment.setTaskFragmentOrganizer(mOrganizerToken, 10 /* uid */,
- "Test:TaskFragmentOrganizer" /* processName */);
- clearInvocations(mAtm.mRootWindowContainer);
-
- assertApplyTransactionAllowed(mTransaction);
-
- // No lifecycle update when the TaskFragment is not recorded.
- verify(mAtm.mRootWindowContainer, never()).resumeFocusedTasksTopActivities();
-
mWindowOrganizerController.mLaunchTaskFragments.put(mFragmentToken, mTaskFragment);
- assertApplyTransactionAllowed(mTransaction);
-
- verify(mAtm.mRootWindowContainer).resumeFocusedTasksTopActivities();
- }
-
- @Test
- public void testApplyTransaction_enforceHierarchyChange_setAdjacentRoots() {
- final TaskFragment taskFragment2 =
- new TaskFragment(mAtm, new Binder(), true /* createdByOrganizer */);
- final WindowContainerToken token2 = taskFragment2.mRemoteToken.toWindowContainerToken();
// Throw exception if the transaction is trying to change a window that is not organized by
// the organizer.
- mTransaction.setAdjacentRoots(mFragmentWindowToken, token2);
+ mTransaction.deleteTaskFragment(mFragmentToken);
assertApplyTransactionDisallowed(mTransaction);
// Allow transaction to change a TaskFragment created by the organizer.
mTaskFragment.setTaskFragmentOrganizer(mOrganizerToken, 10 /* uid */,
"Test:TaskFragmentOrganizer" /* processName */);
- taskFragment2.setTaskFragmentOrganizer(mOrganizerToken, 10 /* uid */,
- "Test:TaskFragmentOrganizer" /* processName */);
clearInvocations(mAtm.mRootWindowContainer);
assertApplyTransactionAllowed(mTransaction);
-
verify(mAtm.mRootWindowContainer).resumeFocusedTasksTopActivities();
}
@@ -577,6 +545,7 @@
mTransaction.reparentActivityToTaskFragment(mFragmentToken, mock(IBinder.class));
mTransaction.setAdjacentTaskFragments(mFragmentToken, mock(IBinder.class),
null /* options */);
+ mTransaction.clearAdjacentTaskFragments(mFragmentToken);
assertApplyTransactionAllowed(mTransaction);
// Successfully created a TaskFragment.
@@ -651,12 +620,16 @@
// Not allowed because TaskFragments are not organized by the caller organizer.
assertApplyTransactionDisallowed(mTransaction);
+ assertNull(mTaskFragment.getAdjacentTaskFragment());
+ assertNull(taskFragment2.getAdjacentTaskFragment());
mTaskFragment.setTaskFragmentOrganizer(mOrganizerToken, 10 /* uid */,
"Test:TaskFragmentOrganizer" /* processName */);
// Not allowed because TaskFragment2 is not organized by the caller organizer.
assertApplyTransactionDisallowed(mTransaction);
+ assertNull(mTaskFragment.getAdjacentTaskFragment());
+ assertNull(taskFragment2.getAdjacentTaskFragment());
mTaskFragment.onTaskFragmentOrganizerRemoved();
taskFragment2.setTaskFragmentOrganizer(mOrganizerToken, 10 /* uid */,
@@ -664,11 +637,46 @@
// Not allowed because mTaskFragment is not organized by the caller organizer.
assertApplyTransactionDisallowed(mTransaction);
+ assertNull(mTaskFragment.getAdjacentTaskFragment());
+ assertNull(taskFragment2.getAdjacentTaskFragment());
mTaskFragment.setTaskFragmentOrganizer(mOrganizerToken, 10 /* uid */,
"Test:TaskFragmentOrganizer" /* processName */);
assertApplyTransactionAllowed(mTransaction);
+ assertEquals(taskFragment2, mTaskFragment.getAdjacentTaskFragment());
+ }
+
+ @Test
+ public void testApplyTransaction_enforceTaskFragmentOrganized_clearAdjacentTaskFragments() {
+ final Task task = createTask(mDisplayContent);
+ mTaskFragment = new TaskFragmentBuilder(mAtm)
+ .setParentTask(task)
+ .setFragmentToken(mFragmentToken)
+ .build();
+ mWindowOrganizerController.mLaunchTaskFragments.put(mFragmentToken, mTaskFragment);
+ final IBinder fragmentToken2 = new Binder();
+ final TaskFragment taskFragment2 = new TaskFragmentBuilder(mAtm)
+ .setParentTask(task)
+ .setFragmentToken(fragmentToken2)
+ .build();
+ mWindowOrganizerController.mLaunchTaskFragments.put(fragmentToken2, taskFragment2);
+ mTaskFragment.setAdjacentTaskFragment(taskFragment2);
+
+ mTransaction.clearAdjacentTaskFragments(mFragmentToken);
+ mOrganizer.applyTransaction(mTransaction, TASK_FRAGMENT_TRANSIT_CHANGE,
+ false /* shouldApplyIndependently */);
+
+ // Not allowed because TaskFragment is not organized by the caller organizer.
+ assertApplyTransactionDisallowed(mTransaction);
+ assertEquals(taskFragment2, mTaskFragment.getAdjacentTaskFragment());
+
+ mTaskFragment.setTaskFragmentOrganizer(mOrganizerToken, 10 /* uid */,
+ "Test:TaskFragmentOrganizer" /* processName */);
+
+ assertApplyTransactionAllowed(mTransaction);
+ assertNull(mTaskFragment.getAdjacentTaskFragment());
+ assertNull(taskFragment2.getAdjacentTaskFragment());
}
@Test
@@ -693,7 +701,7 @@
}
@Test
- public void testApplyTransaction_enforceTaskFragmentOrganized_setTaskFragmentOperation() {
+ public void testApplyTransaction_enforceTaskFragmentOrganized_addTaskFragmentOperation() {
final Task task = createTask(mDisplayContent);
mTaskFragment = new TaskFragmentBuilder(mAtm)
.setParentTask(task)
@@ -704,7 +712,7 @@
OP_TYPE_SET_ANIMATION_PARAMS)
.setAnimationParams(TaskFragmentAnimationParams.DEFAULT)
.build();
- mTransaction.setTaskFragmentOperation(mFragmentToken, operation);
+ mTransaction.addTaskFragmentOperation(mFragmentToken, operation);
mOrganizer.applyTransaction(mTransaction, TASK_FRAGMENT_TRANSIT_CHANGE,
false /* shouldApplyIndependently */);
@@ -718,7 +726,7 @@
}
@Test
- public void testSetTaskFragmentOperation() {
+ public void testAddTaskFragmentOperation() {
final Task task = createTask(mDisplayContent);
mTaskFragment = new TaskFragmentBuilder(mAtm)
.setParentTask(task)
@@ -736,7 +744,7 @@
OP_TYPE_SET_ANIMATION_PARAMS)
.setAnimationParams(animationParams)
.build();
- mTransaction.setTaskFragmentOperation(mFragmentToken, operation);
+ mTransaction.addTaskFragmentOperation(mFragmentToken, operation);
mOrganizer.applyTransaction(mTransaction, TASK_FRAGMENT_TRANSIT_CHANGE,
false /* shouldApplyIndependently */);
assertApplyTransactionAllowed(mTransaction);
@@ -811,23 +819,37 @@
}
@Test
- public void testApplyTransaction_enforceHierarchyChange_reparentChildren() {
- doReturn(true).when(mTaskFragment).isAttached();
-
- // Throw exception if the transaction is trying to change a window that is not organized by
- // the organizer.
- mTransaction.reparentChildren(mFragmentWindowToken, null /* newParent */);
-
- assertApplyTransactionDisallowed(mTransaction);
-
- // Allow transaction to change a TaskFragment created by the organizer.
- mTaskFragment.setTaskFragmentOrganizer(mOrganizerToken, 10 /* uid */,
- "Test:TaskFragmentOrganizer" /* processName */);
- clearInvocations(mAtm.mRootWindowContainer);
-
+ public void testApplyTransaction_createTaskFragment_withPairedActivityToken() {
+ final Task task = createTask(mDisplayContent);
+ final ActivityRecord activityAtBottom = createActivityRecord(task);
+ final int uid = Binder.getCallingUid();
+ activityAtBottom.info.applicationInfo.uid = uid;
+ activityAtBottom.getTask().effectiveUid = uid;
+ mTaskFragment = new TaskFragmentBuilder(mAtm)
+ .setParentTask(task)
+ .setFragmentToken(mFragmentToken)
+ .createActivityCount(1)
+ .build();
+ mWindowOrganizerController.mLaunchTaskFragments.put(mFragmentToken, mTaskFragment);
+ final IBinder fragmentToken1 = new Binder();
+ final TaskFragmentCreationParams params = new TaskFragmentCreationParams.Builder(
+ mOrganizerToken, fragmentToken1, activityAtBottom.token)
+ .setPairedActivityToken(activityAtBottom.token)
+ .build();
+ mTransaction.setTaskFragmentOrganizer(mIOrganizer);
+ mTransaction.createTaskFragment(params);
assertApplyTransactionAllowed(mTransaction);
- verify(mAtm.mRootWindowContainer).resumeFocusedTasksTopActivities();
+ // Successfully created a TaskFragment.
+ final TaskFragment taskFragment = mWindowOrganizerController.getTaskFragment(
+ fragmentToken1);
+ assertNotNull(taskFragment);
+ // The new TaskFragment should be positioned right above the paired activity.
+ assertEquals(task.mChildren.indexOf(activityAtBottom) + 1,
+ task.mChildren.indexOf(taskFragment));
+ // The top TaskFragment should remain on top.
+ assertEquals(task.mChildren.indexOf(taskFragment) + 1,
+ task.mChildren.indexOf(mTaskFragment));
}
@Test
@@ -1006,7 +1028,7 @@
any(), any(), anyInt(), anyInt(), any());
verify(mWindowOrganizerController).sendTaskFragmentOperationFailure(eq(mIOrganizer),
eq(mErrorToken), eq(mTaskFragment),
- eq(HIERARCHY_OP_TYPE_START_ACTIVITY_IN_TASK_FRAGMENT),
+ eq(OP_TYPE_START_ACTIVITY_IN_TASK_FRAGMENT),
any(IllegalArgumentException.class));
}
@@ -1023,7 +1045,7 @@
verify(mWindowOrganizerController).sendTaskFragmentOperationFailure(eq(mIOrganizer),
eq(mErrorToken), eq(mTaskFragment),
- eq(HIERARCHY_OP_TYPE_REPARENT_ACTIVITY_TO_TASK_FRAGMENT),
+ eq(OP_TYPE_REPARENT_ACTIVITY_TO_TASK_FRAGMENT),
any(IllegalArgumentException.class));
assertNull(activity.getOrganizedTaskFragment());
}
@@ -1034,14 +1056,12 @@
spyOn(mWindowOrganizerController);
// Not allow to set adjacent on a TaskFragment that is in a PIP Task.
- mTransaction.setAdjacentTaskFragments(mFragmentToken, null /* fragmentToken2 */,
- null /* options */)
+ mTransaction.setAdjacentTaskFragments(mFragmentToken, new Binder(), null /* options */)
.setErrorCallbackToken(mErrorToken);
assertApplyTransactionAllowed(mTransaction);
verify(mWindowOrganizerController).sendTaskFragmentOperationFailure(eq(mIOrganizer),
- eq(mErrorToken), eq(mTaskFragment),
- eq(HIERARCHY_OP_TYPE_SET_ADJACENT_TASK_FRAGMENTS),
+ eq(mErrorToken), eq(mTaskFragment), eq(OP_TYPE_SET_ADJACENT_TASK_FRAGMENTS),
any(IllegalArgumentException.class));
verify(mTaskFragment, never()).setAdjacentTaskFragment(any());
}
@@ -1060,7 +1080,7 @@
assertApplyTransactionAllowed(mTransaction);
verify(mWindowOrganizerController).sendTaskFragmentOperationFailure(eq(mIOrganizer),
- eq(mErrorToken), eq(null), eq(HIERARCHY_OP_TYPE_CREATE_TASK_FRAGMENT),
+ eq(mErrorToken), eq(null), eq(OP_TYPE_CREATE_TASK_FRAGMENT),
any(IllegalArgumentException.class));
assertNull(mWindowOrganizerController.getTaskFragment(fragmentToken));
}
@@ -1071,12 +1091,12 @@
spyOn(mWindowOrganizerController);
// Not allow to delete a TaskFragment that is in a PIP Task.
- mTransaction.deleteTaskFragment(mFragmentWindowToken)
+ mTransaction.deleteTaskFragment(mFragmentToken)
.setErrorCallbackToken(mErrorToken);
assertApplyTransactionAllowed(mTransaction);
verify(mWindowOrganizerController).sendTaskFragmentOperationFailure(eq(mIOrganizer),
- eq(mErrorToken), eq(mTaskFragment), eq(HIERARCHY_OP_TYPE_DELETE_TASK_FRAGMENT),
+ eq(mErrorToken), eq(mTaskFragment), eq(OP_TYPE_DELETE_TASK_FRAGMENT),
any(IllegalArgumentException.class));
assertNotNull(mWindowOrganizerController.getTaskFragment(mFragmentToken));
@@ -1389,43 +1409,7 @@
// The pending event will be dispatched on the handler (from requestTraversal).
waitHandlerIdle(mWm.mAnimationHandler);
- assertTaskFragmentErrorTransaction(HIERARCHY_OP_TYPE_REPARENT_ACTIVITY_TO_TASK_FRAGMENT,
- SecurityException.class);
- }
-
- @Test
- public void testMinDimensionViolation_ReparentChildren() {
- final Task task = createTask(mDisplayContent);
- final IBinder oldFragToken = new Binder();
- final TaskFragment oldTaskFrag = new TaskFragmentBuilder(mAtm)
- .setParentTask(task)
- .createActivityCount(1)
- .setFragmentToken(oldFragToken)
- .setOrganizer(mOrganizer)
- .build();
- final ActivityRecord activity = oldTaskFrag.getTopMostActivity();
- // Make minWidth/minHeight exceeds mTaskFragment bounds.
- activity.info.windowLayout = new ActivityInfo.WindowLayout(
- 0, 0, 0, 0, 0, mTaskFragBounds.width() + 10, mTaskFragBounds.height() + 10);
- mTaskFragment = new TaskFragmentBuilder(mAtm)
- .setParentTask(task)
- .setFragmentToken(mFragmentToken)
- .setOrganizer(mOrganizer)
- .setBounds(mTaskFragBounds)
- .build();
- mWindowOrganizerController.mLaunchTaskFragments.put(oldFragToken, oldTaskFrag);
- mWindowOrganizerController.mLaunchTaskFragments.put(mFragmentToken, mTaskFragment);
-
- // Reparent oldTaskFrag's children to mTaskFragment, which is smaller than activity's
- // minimum dimensions.
- mTransaction.reparentChildren(oldTaskFrag.mRemoteToken.toWindowContainerToken(),
- mTaskFragment.mRemoteToken.toWindowContainerToken())
- .setErrorCallbackToken(mErrorToken);
- assertApplyTransactionAllowed(mTransaction);
- // The pending event will be dispatched on the handler (from requestTraversal).
- waitHandlerIdle(mWm.mAnimationHandler);
-
- assertTaskFragmentErrorTransaction(HIERARCHY_OP_TYPE_REPARENT_CHILDREN,
+ assertTaskFragmentErrorTransaction(OP_TYPE_REPARENT_ACTIVITY_TO_TASK_FRAGMENT,
SecurityException.class);
}
@@ -1600,7 +1584,8 @@
}
/** Asserts that there will be a transaction for TaskFragment error. */
- private void assertTaskFragmentErrorTransaction(int opType, @NonNull Class<?> exceptionClass) {
+ private void assertTaskFragmentErrorTransaction(@TaskFragmentOperation.OperationType int opType,
+ @NonNull Class<?> exceptionClass) {
verify(mOrganizer).onTransactionReady(mTransactionCaptor.capture());
final TaskFragmentTransaction transaction = mTransactionCaptor.getValue();
final List<TaskFragmentTransaction.Change> changes = transaction.getChanges();
diff --git a/services/tests/wmtests/src/com/android/server/wm/WallpaperControllerTests.java b/services/tests/wmtests/src/com/android/server/wm/WallpaperControllerTests.java
index a100b9a..ef2b691 100644
--- a/services/tests/wmtests/src/com/android/server/wm/WallpaperControllerTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/WallpaperControllerTests.java
@@ -393,7 +393,7 @@
dc.updateOrientation();
dc.sendNewConfiguration();
spyOn(wallpaperWindow);
- doReturn(new Rect(0, 0, width, height)).when(wallpaperWindow).getLastReportedBounds();
+ doReturn(new Rect(0, 0, width, height)).when(wallpaperWindow).getParentFrame();
}
@Test
diff --git a/services/tests/wmtests/src/com/android/server/wm/WindowStateTests.java b/services/tests/wmtests/src/com/android/server/wm/WindowStateTests.java
index 5e0e209..6bce959 100644
--- a/services/tests/wmtests/src/com/android/server/wm/WindowStateTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/WindowStateTests.java
@@ -45,6 +45,7 @@
import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_SUB_PANEL;
import static android.view.WindowManager.LayoutParams.TYPE_BASE_APPLICATION;
import static android.view.WindowManager.LayoutParams.TYPE_INPUT_METHOD;
+import static android.view.WindowManager.LayoutParams.TYPE_SECURE_SYSTEM_OVERLAY;
import static android.view.WindowManager.LayoutParams.TYPE_TOAST;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.doNothing;
@@ -980,6 +981,19 @@
assertFalse(sameTokenWindow.needsRelativeLayeringToIme());
}
+ @UseTestDisplay(addWindows = {W_ACTIVITY, W_INPUT_METHOD})
+ @Test
+ public void testNeedsRelativeLayeringToIme_systemDialog() {
+ WindowState systemDialogWindow = createWindow(null, TYPE_SECURE_SYSTEM_OVERLAY,
+ mDisplayContent,
+ "SystemDialog", true);
+ mDisplayContent.setImeLayeringTarget(mAppWindow);
+ mAppWindow.getRootTask().setWindowingMode(WINDOWING_MODE_MULTI_WINDOW);
+ makeWindowVisible(mImeWindow);
+ systemDialogWindow.mAttrs.flags |= FLAG_ALT_FOCUSABLE_IM;
+ assertTrue(systemDialogWindow.needsRelativeLayeringToIme());
+ }
+
@Test
public void testSetFreezeInsetsState() {
final WindowState app = createWindow(null, TYPE_APPLICATION, "app");
diff --git a/services/tests/wmtests/src/com/android/server/wm/ZOrderingTests.java b/services/tests/wmtests/src/com/android/server/wm/ZOrderingTests.java
index a95fa5a..8c58158 100644
--- a/services/tests/wmtests/src/com/android/server/wm/ZOrderingTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/ZOrderingTests.java
@@ -22,6 +22,7 @@
import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
import static android.app.WindowConfiguration.WINDOWING_MODE_MULTI_WINDOW;
import static android.app.WindowConfiguration.WINDOWING_MODE_PINNED;
+import static android.view.WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM;
import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION;
import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_ABOVE_SUB_PANEL;
import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_ATTACHED_DIALOG;
@@ -31,6 +32,7 @@
import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_SUB_PANEL;
import static android.view.WindowManager.LayoutParams.TYPE_BASE_APPLICATION;
import static android.view.WindowManager.LayoutParams.TYPE_NAVIGATION_BAR_PANEL;
+import static android.view.WindowManager.LayoutParams.TYPE_SECURE_SYSTEM_OVERLAY;
import static android.view.WindowManager.LayoutParams.TYPE_STATUS_BAR_ADDITIONAL;
import static android.view.WindowManager.LayoutParams.TYPE_STATUS_BAR_SUB_PANEL;
import static android.view.WindowManager.LayoutParams.TYPE_SYSTEM_OVERLAY;
@@ -543,4 +545,28 @@
assertZOrderGreaterThan(mTransaction, popupWindow.getSurfaceControl(),
mDisplayContent.getImeContainer().getSurfaceControl());
}
+
+ @Test
+ public void testSystemDialogWindow_expectHigherThanIme_inMultiWindow() {
+ // Simulate the app window is in multi windowing mode and being IME target
+ mAppWindow.getConfiguration().windowConfiguration.setWindowingMode(
+ WINDOWING_MODE_MULTI_WINDOW);
+ mDisplayContent.setImeLayeringTarget(mAppWindow);
+ mDisplayContent.setImeInputTarget(mAppWindow);
+ makeWindowVisible(mImeWindow);
+
+ // Create a popupWindow
+ final WindowState systemDialogWindow = createWindow(null, TYPE_SECURE_SYSTEM_OVERLAY,
+ mDisplayContent, "SystemDialog", true);
+ systemDialogWindow.mAttrs.flags |= FLAG_ALT_FOCUSABLE_IM;
+ spyOn(systemDialogWindow);
+
+ mDisplayContent.assignChildLayers(mTransaction);
+
+ // Verify the surface layer of the popupWindow should higher than IME
+ verify(systemDialogWindow).needsRelativeLayeringToIme();
+ assertThat(systemDialogWindow.needsRelativeLayeringToIme()).isTrue();
+ assertZOrderGreaterThan(mTransaction, systemDialogWindow.getSurfaceControl(),
+ mDisplayContent.getImeContainer().getSurfaceControl());
+ }
}
diff --git a/services/tests/wmtests/src/com/android/server/wm/scvh/EmbeddedSCVHService.java b/services/tests/wmtests/src/com/android/server/wm/scvh/EmbeddedSCVHService.java
new file mode 100644
index 0000000..3bd577c
--- /dev/null
+++ b/services/tests/wmtests/src/com/android/server/wm/scvh/EmbeddedSCVHService.java
@@ -0,0 +1,127 @@
+/*
+ * 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 com.android.server.wm.scvh;
+
+import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION;
+
+import android.annotation.Nullable;
+import android.app.Service;
+import android.content.Context;
+import android.content.Intent;
+import android.graphics.Color;
+import android.graphics.PixelFormat;
+import android.hardware.display.DisplayManager;
+import android.os.Handler;
+import android.os.IBinder;
+import android.os.Looper;
+import android.os.RemoteException;
+import android.view.Display;
+import android.view.SurfaceControl.Transaction;
+import android.view.SurfaceControlViewHost;
+import android.view.View;
+import android.view.WindowManager;
+import android.widget.FrameLayout;
+
+import androidx.annotation.NonNull;
+
+public class EmbeddedSCVHService extends Service {
+ private static final String TAG = "SCVHEmbeddedService";
+ private SurfaceControlViewHost mVr;
+
+ private Handler mHandler;
+
+ @Override
+ public void onCreate() {
+ super.onCreate();
+ mHandler = new Handler(Looper.getMainLooper());
+ }
+
+ @Nullable
+ @Override
+ public IBinder onBind(Intent intent) {
+ // Return the interface
+ return new AttachEmbeddedWindow();
+ }
+
+ public static class SlowView extends View {
+ private long mDelayMs;
+ public SlowView(Context context) {
+ super(context);
+ }
+
+ @Override
+ protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
+ super.onMeasure(widthMeasureSpec, heightMeasureSpec);
+ try {
+ Thread.sleep(mDelayMs);
+ } catch (InterruptedException e) {
+ }
+ }
+
+ public void setDelay(long delayMs) {
+ mDelayMs = delayMs;
+ }
+ }
+
+ private class AttachEmbeddedWindow extends IAttachEmbeddedWindow.Stub {
+ @Override
+ public void attachEmbedded(IBinder hostToken, int width,
+ int height, int displayId, long delayMs, IAttachEmbeddedWindowCallback callback) {
+ mHandler.post(() -> {
+ Context context = EmbeddedSCVHService.this;
+ Display display = getApplicationContext().getSystemService(
+ DisplayManager.class).getDisplay(displayId);
+ mVr = new SurfaceControlViewHost(context, display, hostToken);
+ FrameLayout content = new FrameLayout(context);
+
+ SlowView slowView = new SlowView(context);
+ slowView.setDelay(delayMs);
+ slowView.setBackgroundColor(Color.BLUE);
+ content.addView(slowView);
+ WindowManager.LayoutParams lp = new WindowManager.LayoutParams(width, height,
+ TYPE_APPLICATION, 0, PixelFormat.OPAQUE);
+ lp.setTitle("EmbeddedWindow");
+ mVr.setView(content, lp);
+
+ content.addOnAttachStateChangeListener(new View.OnAttachStateChangeListener() {
+ @Override
+ public void onViewAttachedToWindow(@NonNull View v) {
+ // First frame isn't included in the sync so don't notify the host about the
+ // surface package until the first draw has completed.
+ Transaction transaction = new Transaction().addTransactionCommittedListener(
+ getMainExecutor(), () -> {
+ try {
+ callback.onEmbeddedWindowAttached(mVr.getSurfacePackage());
+ } catch (RemoteException e) {
+ }
+ });
+ v.getRootSurfaceControl().applyTransactionOnDraw(transaction);
+ }
+
+ @Override
+ public void onViewDetachedFromWindow(@NonNull View v) {
+ }
+ });
+ });
+ }
+
+ @Override
+ public void relayout(WindowManager.LayoutParams lp) {
+ mHandler.post(() -> mVr.relayout(lp));
+ }
+ }
+}
diff --git a/services/tests/wmtests/src/com/android/server/wm/scvh/IAttachEmbeddedWindow.aidl b/services/tests/wmtests/src/com/android/server/wm/scvh/IAttachEmbeddedWindow.aidl
new file mode 100644
index 0000000..3439567
--- /dev/null
+++ b/services/tests/wmtests/src/com/android/server/wm/scvh/IAttachEmbeddedWindow.aidl
@@ -0,0 +1,27 @@
+/*
+ * 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 com.android.server.wm.scvh;
+
+import android.view.SurfaceControlViewHost.SurfacePackage;
+import android.os.IBinder;
+import com.android.server.wm.scvh.IAttachEmbeddedWindowCallback;
+import android.view.WindowManager.LayoutParams;
+
+interface IAttachEmbeddedWindow {
+ void attachEmbedded(IBinder hostToken, int width, int height, int displayId, long delayMs, IAttachEmbeddedWindowCallback callback);
+ void relayout(in LayoutParams lp);
+}
\ No newline at end of file
diff --git a/services/tests/wmtests/src/com/android/server/wm/scvh/IAttachEmbeddedWindowCallback.aidl b/services/tests/wmtests/src/com/android/server/wm/scvh/IAttachEmbeddedWindowCallback.aidl
new file mode 100644
index 0000000..92abfc8
--- /dev/null
+++ b/services/tests/wmtests/src/com/android/server/wm/scvh/IAttachEmbeddedWindowCallback.aidl
@@ -0,0 +1,23 @@
+/*
+ * 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 com.android.server.wm.scvh;
+
+import android.view.SurfaceControlViewHost.SurfacePackage;
+
+interface IAttachEmbeddedWindowCallback {
+ void onEmbeddedWindowAttached(in SurfacePackage surfacePackage);
+}
\ No newline at end of file
diff --git a/services/tests/wmtests/src/com/android/server/wm/scvh/SyncValidatorSCVHTestCase.java b/services/tests/wmtests/src/com/android/server/wm/scvh/SyncValidatorSCVHTestCase.java
new file mode 100644
index 0000000..af4c683c
--- /dev/null
+++ b/services/tests/wmtests/src/com/android/server/wm/scvh/SyncValidatorSCVHTestCase.java
@@ -0,0 +1,234 @@
+/*
+ * 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 com.android.server.wm.scvh;
+
+import static junit.framework.Assert.assertEquals;
+import static junit.framework.Assert.assertNotNull;
+
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.Intent;
+import android.content.ServiceConnection;
+import android.graphics.Color;
+import android.graphics.PixelFormat;
+import android.graphics.Point;
+import android.os.Handler;
+import android.os.IBinder;
+import android.os.Looper;
+import android.os.RemoteException;
+import android.util.Log;
+import android.view.Gravity;
+import android.view.SurfaceControlViewHost.SurfacePackage;
+import android.view.SurfaceHolder;
+import android.view.SurfaceView;
+import android.view.ViewGroup;
+import android.view.WindowManager;
+import android.view.cts.surfacevalidator.ISurfaceValidatorTestCase;
+import android.view.cts.surfacevalidator.PixelChecker;
+import android.widget.FrameLayout;
+import android.window.SurfaceSyncGroup;
+
+import androidx.annotation.NonNull;
+
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
+
+public class SyncValidatorSCVHTestCase implements ISurfaceValidatorTestCase {
+ private static final String TAG = "SCVHSyncValidatorTestCase";
+
+ private final Point[] mSizes = new Point[]{new Point(500, 500), new Point(700, 400),
+ new Point(300, 800), new Point(200, 200)};
+ private int mLastSizeIndex = 1;
+
+ private long mDelayMs;
+
+ public SyncValidatorSCVHTestCase(long delayMs) {
+ mDelayMs = delayMs;
+ }
+
+ private final Runnable mRunnable = new Runnable() {
+ @Override
+ public void run() {
+ Point size = mSizes[mLastSizeIndex % mSizes.length];
+ Runnable svResizeRunnable = () -> {
+ ViewGroup.LayoutParams svParams = mSurfaceView.getLayoutParams();
+ svParams.width = size.x;
+ svParams.height = size.y;
+ mSurfaceView.setLayoutParams(svParams);
+ };
+ Runnable resizeRunnable = () -> {
+ try {
+ final WindowManager.LayoutParams lp = new WindowManager.LayoutParams(size.x,
+ size.y,
+ WindowManager.LayoutParams.TYPE_APPLICATION, 0,
+ PixelFormat.TRANSPARENT);
+ mIAttachEmbeddedWindow.relayout(lp);
+ } catch (RemoteException e) {
+ }
+ };
+
+ SurfaceSyncGroup syncGroup = new SurfaceSyncGroup(TAG);
+ syncGroup.addToSync(mSurfaceView.getRootSurfaceControl(), svResizeRunnable);
+ syncGroup.addToSync(mSurfacePackage, resizeRunnable);
+ syncGroup.markSyncReady();
+
+ mLastSizeIndex++;
+
+ mHandler.postDelayed(this, mDelayMs + 50);
+ }
+ };
+
+ private Handler mHandler;
+ private SurfaceView mSurfaceView;
+
+ private final CountDownLatch mReadyLatch = new CountDownLatch(1);
+ private boolean mSurfaceCreated;
+ private boolean mIsAttached;
+ private final Object mLock = new Object();
+ private int mDisplayId;
+ private IAttachEmbeddedWindow mIAttachEmbeddedWindow;
+ private SurfacePackage mSurfacePackage;
+
+ final SurfaceHolder.Callback mCallback = new SurfaceHolder.Callback() {
+ @Override
+ public void surfaceCreated(@NonNull SurfaceHolder holder) {
+ synchronized (mLock) {
+ mSurfaceCreated = true;
+ }
+ if (isReadyToAttach()) {
+ attachEmbedded();
+ }
+ }
+
+ @Override
+ public void surfaceChanged(@NonNull SurfaceHolder holder, int format, int width,
+ int height) {
+ }
+
+ @Override
+ public void surfaceDestroyed(@NonNull SurfaceHolder holder) {
+ }
+ };
+
+ @Override
+ public PixelChecker getChecker() {
+ return new PixelChecker(Color.BLACK) {
+ @Override
+ public boolean checkPixels(int matchingPixelCount, int width, int height) {
+ // Content has been set up yet.
+ if (mReadyLatch.getCount() > 0) {
+ return true;
+ }
+ return matchingPixelCount == 0;
+ }
+ };
+ }
+
+ private final ServiceConnection mConnection = new ServiceConnection() {
+ // Called when the connection with the service is established
+ public void onServiceConnected(ComponentName className, IBinder service) {
+ Log.d(TAG, "Service Connected");
+ synchronized (mLock) {
+ mIAttachEmbeddedWindow = IAttachEmbeddedWindow.Stub.asInterface(service);
+ }
+ if (isReadyToAttach()) {
+ attachEmbedded();
+ }
+ }
+
+ public void onServiceDisconnected(ComponentName className) {
+ Log.d(TAG, "Service Disconnected");
+ mIAttachEmbeddedWindow = null;
+ synchronized (mLock) {
+ mIsAttached = false;
+ }
+ }
+ };
+
+ private boolean isReadyToAttach() {
+ synchronized (mLock) {
+ if (!mSurfaceCreated) {
+ Log.d(TAG, "surface is not created");
+ }
+ if (mIAttachEmbeddedWindow == null) {
+ Log.d(TAG, "Service is not attached");
+ }
+ if (mIsAttached) {
+ Log.d(TAG, "Already attached");
+ }
+
+ return mSurfaceCreated && mIAttachEmbeddedWindow != null && !mIsAttached;
+ }
+ }
+
+ private void attachEmbedded() {
+ synchronized (mLock) {
+ mIsAttached = true;
+ }
+ try {
+ mIAttachEmbeddedWindow.attachEmbedded(mSurfaceView.getHostToken(), mSizes[0].x,
+ mSizes[0].y, mDisplayId, mDelayMs, new IAttachEmbeddedWindowCallback.Stub() {
+ @Override
+ public void onEmbeddedWindowAttached(SurfacePackage surfacePackage) {
+ mHandler.post(() -> {
+ mSurfacePackage = surfacePackage;
+ mSurfaceView.setChildSurfacePackage(surfacePackage);
+ mReadyLatch.countDown();
+ });
+ }
+ });
+ } catch (RemoteException e) {
+ }
+ }
+
+ @Override
+ public void start(Context context, FrameLayout parent) {
+ mDisplayId = context.getDisplayId();
+ mHandler = new Handler(Looper.getMainLooper());
+
+ Intent intent = new Intent(context, EmbeddedSCVHService.class);
+ intent.setAction(EmbeddedSCVHService.class.getName());
+ context.bindService(intent, mConnection, Context.BIND_AUTO_CREATE);
+
+ mSurfaceView = new SurfaceView(context);
+ mSurfaceView.getHolder().addCallback(mCallback);
+
+ FrameLayout.LayoutParams layoutParams = new FrameLayout.LayoutParams(mSizes[0].x,
+ mSizes[0].y);
+ layoutParams.gravity = Gravity.CENTER;
+ parent.addView(mSurfaceView, layoutParams);
+ }
+
+ @Override
+ public void waitForReady() {
+
+ try {
+ mReadyLatch.await(5, TimeUnit.SECONDS);
+ } catch (InterruptedException e) {
+ }
+
+ assertEquals("Timed out waiting for setup", 0, mReadyLatch.getCount());
+ assertNotNull("SurfacePackage is null", mSurfacePackage);
+
+ mHandler.post(mRunnable);
+ }
+
+ @Override
+ public void end() {
+ mHandler.removeCallbacks(mRunnable);
+ }
+}
diff --git a/services/usb/java/com/android/server/usb/UsbPortManager.java b/services/usb/java/com/android/server/usb/UsbPortManager.java
index f920f0f..28d726e 100644
--- a/services/usb/java/com/android/server/usb/UsbPortManager.java
+++ b/services/usb/java/com/android/server/usb/UsbPortManager.java
@@ -46,11 +46,13 @@
import android.content.Context;
import android.content.Intent;
import android.content.res.Resources;
+import android.hardware.usb.IDisplayPortAltModeInfoListener;
import android.hardware.usb.IUsbOperationInternal;
import android.hardware.usb.ParcelableUsbPort;
import android.hardware.usb.UsbManager;
import android.hardware.usb.UsbPort;
import android.hardware.usb.UsbPortStatus;
+import android.hardware.usb.DisplayPortAltModeInfo;
import android.hardware.usb.V1_0.IUsb;
import android.hardware.usb.V1_0.PortRole;
import android.hardware.usb.V1_0.PortRoleType;
@@ -63,6 +65,8 @@
import android.os.Bundle;
import android.os.Handler;
import android.os.HwBinder;
+import android.os.IBinder;
+import android.os.IInterface;
import android.os.Message;
import android.os.Parcel;
import android.os.Parcelable;
@@ -90,8 +94,10 @@
import java.util.Arrays;
import java.util.ArrayList;
+import java.util.LinkedList;
import java.util.NoSuchElementException;
import java.util.Objects;
+import java.util.concurrent.Executor;
/**
* Allows trusted components to control the properties of physical USB ports
@@ -105,7 +111,7 @@
* (but we don't care today).
* </p>
*/
-public class UsbPortManager {
+public class UsbPortManager implements IBinder.DeathRecipient {
private static final String TAG = "UsbPortManager";
private static final int MSG_UPDATE_PORTS = 1;
@@ -158,6 +164,12 @@
private NotificationManager mNotificationManager;
+ // Maintains a list of DisplayPortAltModeInfo Event listeners,
+ // protected by mDisplayPortListenerLock for broadcasts/register/unregister events
+ private final Object mDisplayPortListenerLock = new Object();
+ private final ArrayMap<IBinder, IDisplayPortAltModeInfoListener> mDisplayPortListeners =
+ new ArrayMap<IBinder, IDisplayPortAltModeInfoListener>();
+
/**
* If there currently is a notification related to contaminated USB port management
* shown the id of the notification, or 0 if there is none.
@@ -673,6 +685,46 @@
}
}
+ @Override
+ public void binderDied() {
+ // All calls should go to binderDied(IBinder deadBinder)
+ Slog.wtf(TAG, "binderDied() called unexpectedly");
+ }
+
+ public void binderDied(IBinder deadBinder) {
+ synchronized (mDisplayPortListenerLock) {
+ mDisplayPortListeners.remove(deadBinder);
+ Slog.d(TAG, "DisplayPortEventDispatcherListener died at " + deadBinder);
+ }
+ }
+
+ public boolean registerForDisplayPortEvents(
+ @NonNull IDisplayPortAltModeInfoListener listener) {
+ synchronized (mDisplayPortListenerLock) {
+ if (!mDisplayPortListeners.containsKey(listener.asBinder())) {
+ try {
+ listener.asBinder().linkToDeath(this, 0);
+ } catch (RemoteException e) {
+ logAndPrintException(null, "Caught RemoteException in " +
+ "registerForDisplayPortEvents: ", e);
+ return false;
+ }
+ mDisplayPortListeners.put(listener.asBinder(), listener);
+ return true;
+ }
+ }
+ return false;
+ }
+
+ public void unregisterForDisplayPortEvents(
+ @NonNull IDisplayPortAltModeInfoListener listener) {
+ synchronized (mDisplayPortListenerLock) {
+ if (mDisplayPortListeners.remove(listener.asBinder()) != null) {
+ listener.asBinder().unlinkToDeath(this, 0);
+ }
+ }
+ }
+
public void updatePorts(ArrayList<RawPortInfo> newPortInfo) {
Message message = mHandler.obtainMessage();
Bundle bundle = new Bundle();
@@ -683,8 +735,15 @@
}
public void addSimulatedPort(String portId, int supportedModes,
- boolean supportsComplianceWarnings,
- IndentingPrintWriter pw) {
+ boolean supportsComplianceWarnings, boolean supportsDisplayPortAltMode,
+ IndentingPrintWriter pw) {
+ int supportedAltModes = supportsDisplayPortAltMode ?
+ UsbPort.FLAG_ALT_MODE_TYPE_DISPLAYPORT : 0;
+ DisplayPortAltModeInfo displayPortAltModeInfo = null;
+
+ if (supportsDisplayPortAltMode) {
+ displayPortAltModeInfo = new DisplayPortAltModeInfo();
+ }
synchronized (mLock) {
if (mSimulatedPorts.containsKey(portId)) {
@@ -713,7 +772,10 @@
false,
UsbPortStatus.POWER_BRICK_STATUS_UNKNOWN,
supportsComplianceWarnings,
- new int[] {}));
+ new int[] {},
+ UsbPortStatus.PLUG_STATE_UNKNOWN,
+ supportedAltModes,
+ displayPortAltModeInfo));
updatePortsLocked(pw, null);
}
}
@@ -802,6 +864,25 @@
}
}
+
+ public void simulateDisplayPortAltModeInfo(String portId, int partnerSinkStatus,
+ int cableStatus, int numLanes, IndentingPrintWriter pw) {
+ synchronized (mLock) {
+ final RawPortInfo portInfo = mSimulatedPorts.get(portId);
+ if (portInfo == null) {
+ pw.println("Simulated port not found");
+ return;
+ }
+
+ DisplayPortAltModeInfo displayPortAltModeInfo =
+ new DisplayPortAltModeInfo(partnerSinkStatus, cableStatus, numLanes);
+ portInfo.displayPortAltModeInfo = displayPortAltModeInfo;
+ pw.println("Simulating DisplayPort Info: " + displayPortAltModeInfo);
+ updatePortsLocked(pw, null);
+ }
+
+ }
+
public void disconnectSimulatedPort(String portId, IndentingPrintWriter pw) {
synchronized (mLock) {
final RawPortInfo portInfo = mSimulatedPorts.get(portId);
@@ -893,6 +974,9 @@
portInfo.powerBrickConnectionStatus,
portInfo.supportsComplianceWarnings,
portInfo.complianceWarnings,
+ portInfo.plugState,
+ portInfo.supportedAltModes,
+ portInfo.displayPortAltModeInfo,
pw);
}
} else {
@@ -911,6 +995,9 @@
currentPortInfo.powerBrickConnectionStatus,
currentPortInfo.supportsComplianceWarnings,
currentPortInfo.complianceWarnings,
+ currentPortInfo.plugState,
+ currentPortInfo.supportedAltModes,
+ currentPortInfo.displayPortAltModeInfo,
pw);
}
}
@@ -937,6 +1024,9 @@
if (portInfo.mComplianceWarningChange == portInfo.COMPLIANCE_WARNING_CHANGED) {
handlePortComplianceWarningLocked(portInfo, pw);
}
+ if (portInfo.mDisplayPortAltModeChange == portInfo.ALTMODE_INFO_CHANGED) {
+ handleDpAltModeLocked(portInfo, pw);
+ }
}
}
@@ -955,6 +1045,9 @@
int powerBrickConnectionStatus,
boolean supportsComplianceWarnings,
@NonNull int[] complianceWarnings,
+ int plugState,
+ int supportedAltModes,
+ DisplayPortAltModeInfo displayPortAltModeInfo,
IndentingPrintWriter pw) {
// Only allow mode switch capability for dual role ports.
// Validate that the current mode matches the supported modes we expect.
@@ -1009,14 +1102,15 @@
portId, supportedModes, supportedContaminantProtectionModes,
supportsEnableContaminantPresenceProtection,
supportsEnableContaminantPresenceDetection,
- supportsComplianceWarnings);
+ supportsComplianceWarnings,
+ supportedAltModes);
portInfo.setStatus(currentMode, canChangeMode,
currentPowerRole, canChangePowerRole,
currentDataRole, canChangeDataRole,
supportedRoleCombinations, contaminantProtectionStatus,
contaminantDetectionStatus, usbDataStatus,
powerTransferLimited, powerBrickConnectionStatus,
- complianceWarnings);
+ complianceWarnings, plugState, displayPortAltModeInfo);
mPorts.put(portId, portInfo);
} else {
// Validate that ports aren't changing definition out from under us.
@@ -1054,7 +1148,7 @@
supportedRoleCombinations, contaminantProtectionStatus,
contaminantDetectionStatus, usbDataStatus,
powerTransferLimited, powerBrickConnectionStatus,
- complianceWarnings)) {
+ complianceWarnings, plugState, displayPortAltModeInfo)) {
portInfo.mDisposition = PortInfo.DISPOSITION_CHANGED;
} else {
portInfo.mDisposition = PortInfo.DISPOSITION_READY;
@@ -1086,6 +1180,11 @@
sendComplianceWarningBroadcastLocked(portInfo);
}
+ private void handleDpAltModeLocked(PortInfo portInfo, IndentingPrintWriter pw) {
+ logAndPrint(Log.INFO, pw, "USB port DisplayPort Alt Mode Status Changed: " + portInfo);
+ sendDpAltModeCallbackLocked(portInfo, pw);
+ }
+
private void handlePortRemovedLocked(PortInfo portInfo, IndentingPrintWriter pw) {
logAndPrint(Log.INFO, pw, "USB port removed: " + portInfo);
handlePortLocked(portInfo, pw);
@@ -1135,7 +1234,6 @@
return complianceWarningsProto.toArray();
}
-
private void sendPortChangedBroadcastLocked(PortInfo portInfo) {
final Intent intent = new Intent(UsbManager.ACTION_USB_PORT_CHANGED);
intent.addFlags(
@@ -1167,6 +1265,21 @@
Manifest.permission.MANAGE_USB));
}
+ private void sendDpAltModeCallbackLocked(PortInfo portInfo, IndentingPrintWriter pw) {
+ String portId = portInfo.mUsbPort.getId();
+ synchronized (mDisplayPortListenerLock) {
+ for (IDisplayPortAltModeInfoListener mListener : mDisplayPortListeners.values()) {
+ try {
+ mListener.onDisplayPortAltModeInfoChanged(portId,
+ portInfo.mUsbPortStatus.getDisplayPortAltModeInfo());
+ } catch (RemoteException e) {
+ logAndPrintException(pw, "Caught RemoteException at "
+ + "sendDpAltModeCallbackLocked", e);
+ }
+ }
+ }
+ }
+
private void enableContaminantDetectionIfNeeded(PortInfo portInfo, IndentingPrintWriter pw) {
if (!mConnected.containsKey(portInfo.mUsbPort.getId())) {
return;
@@ -1308,6 +1421,9 @@
public static final int COMPLIANCE_WARNING_UNCHANGED = 0;
public static final int COMPLIANCE_WARNING_CHANGED = 1;
+ public static final int ALTMODE_INFO_UNCHANGED = 0;
+ public static final int ALTMODE_INFO_CHANGED = 1;
+
public final UsbPort mUsbPort;
public UsbPortStatus mUsbPortStatus;
public boolean mCanChangeMode;
@@ -1321,18 +1437,23 @@
public long mLastConnectDurationMillis;
// default initialized to 0 which means no changes reported
public int mComplianceWarningChange;
+ // default initialized to 0 which means unchanged
+ public int mDisplayPortAltModeChange;
PortInfo(@NonNull UsbManager usbManager, @NonNull String portId, int supportedModes,
int supportedContaminantProtectionModes,
boolean supportsEnableContaminantPresenceDetection,
boolean supportsEnableContaminantPresenceProtection,
- boolean supportsComplianceWarnings) {
+ boolean supportsComplianceWarnings,
+ int supportedAltModes) {
mUsbPort = new UsbPort(usbManager, portId, supportedModes,
supportedContaminantProtectionModes,
supportsEnableContaminantPresenceDetection,
supportsEnableContaminantPresenceProtection,
- supportsComplianceWarnings);
+ supportsComplianceWarnings,
+ supportedAltModes);
mComplianceWarningChange = COMPLIANCE_WARNING_UNCHANGED;
+ mDisplayPortAltModeChange = ALTMODE_INFO_UNCHANGED;
}
public boolean complianceWarningsChanged(@NonNull int[] complianceWarnings) {
@@ -1344,6 +1465,34 @@
return true;
}
+ public boolean displayPortAltModeChanged(DisplayPortAltModeInfo
+ displayPortAltModeInfo) {
+ DisplayPortAltModeInfo currentDisplayPortAltModeInfo =
+ mUsbPortStatus.getDisplayPortAltModeInfo();
+
+ mDisplayPortAltModeChange = ALTMODE_INFO_UNCHANGED;
+
+ if (displayPortAltModeInfo == null
+ && currentDisplayPortAltModeInfo != null) {
+ mDisplayPortAltModeChange = ALTMODE_INFO_CHANGED;
+ return true;
+ }
+
+ if (currentDisplayPortAltModeInfo == null) {
+ if (displayPortAltModeInfo != null) {
+ mDisplayPortAltModeChange = ALTMODE_INFO_CHANGED;
+ return true;
+ }
+ return false;
+ }
+
+ if (!(currentDisplayPortAltModeInfo.equals(displayPortAltModeInfo))) {
+ mDisplayPortAltModeChange = ALTMODE_INFO_CHANGED;
+ return true;
+ }
+ return false;
+ }
+
public boolean setStatus(int currentMode, boolean canChangeMode,
int currentPowerRole, boolean canChangePowerRole,
int currentDataRole, boolean canChangeDataRole,
@@ -1364,7 +1513,7 @@
UsbPortStatus.CONTAMINANT_DETECTION_NOT_SUPPORTED,
UsbPortStatus.DATA_STATUS_UNKNOWN, false,
UsbPortStatus.POWER_BRICK_STATUS_UNKNOWN,
- new int[] {});
+ new int[] {}, 0, null);
dispositionChanged = true;
}
@@ -1410,7 +1559,7 @@
supportedRoleCombinations, contaminantProtectionStatus,
contaminantDetectionStatus, usbDataStatus,
powerTransferLimited, powerBrickConnectionStatus,
- new int[] {});
+ new int[] {}, 0, null);
dispositionChanged = true;
}
@@ -1431,8 +1580,16 @@
int supportedRoleCombinations, int contaminantProtectionStatus,
int contaminantDetectionStatus, int usbDataStatus,
boolean powerTransferLimited, int powerBrickConnectionStatus,
- @NonNull int[] complianceWarnings) {
+ @NonNull int[] complianceWarnings,
+ int plugState, DisplayPortAltModeInfo displayPortAltModeInfo) {
boolean dispositionChanged = false;
+ boolean complianceChanged = false;
+ boolean displayPortChanged = false;
+
+ if (mUsbPortStatus != null) {
+ complianceChanged = complianceWarningsChanged(complianceWarnings);
+ displayPortChanged = displayPortAltModeChanged(displayPortAltModeInfo);
+ }
mCanChangeMode = canChangeMode;
mCanChangePowerRole = canChangePowerRole;
@@ -1452,7 +1609,9 @@
|| mUsbPortStatus.isPowerTransferLimited()
!= powerTransferLimited
|| mUsbPortStatus.getPowerBrickConnectionStatus()
- != powerBrickConnectionStatus) {
+ != powerBrickConnectionStatus
+ || mUsbPortStatus.getPlugState()
+ != plugState) {
if (mUsbPortStatus == null && complianceWarnings.length > 0) {
mComplianceWarningChange = COMPLIANCE_WARNING_CHANGED;
}
@@ -1460,14 +1619,17 @@
supportedRoleCombinations, contaminantProtectionStatus,
contaminantDetectionStatus, usbDataStatus,
powerTransferLimited, powerBrickConnectionStatus,
- complianceWarnings);
+ complianceWarnings, plugState, displayPortAltModeInfo);
dispositionChanged = true;
- } else if (complianceWarningsChanged(complianceWarnings)) {
- mUsbPortStatus = new UsbPortStatus(currentMode, currentPowerRole, currentDataRole,
- supportedRoleCombinations, contaminantProtectionStatus,
- contaminantDetectionStatus, usbDataStatus,
- powerTransferLimited, powerBrickConnectionStatus,
- complianceWarnings);
+ // Case used in order to send compliance warning broadcast or signal DisplayPort
+ // listeners. These targeted broadcasts don't use dispositionChanged to broadcast to
+ // general ACTION_USB_PORT_CHANGED.
+ } else if (complianceChanged || displayPortChanged) {
+ mUsbPortStatus = new UsbPortStatus(currentMode, currentPowerRole,
+ currentDataRole, supportedRoleCombinations,
+ contaminantProtectionStatus, contaminantDetectionStatus,
+ usbDataStatus, powerTransferLimited, powerBrickConnectionStatus,
+ complianceWarnings, plugState, displayPortAltModeInfo);
}
if (mUsbPortStatus.isConnected() && mConnectedAtMillis == 0) {
diff --git a/services/usb/java/com/android/server/usb/UsbService.java b/services/usb/java/com/android/server/usb/UsbService.java
index 6eb04d9..7d84222 100644
--- a/services/usb/java/com/android/server/usb/UsbService.java
+++ b/services/usb/java/com/android/server/usb/UsbService.java
@@ -36,6 +36,7 @@
import android.content.IntentFilter;
import android.content.pm.PackageManager;
import android.hardware.usb.IUsbManager;
+import android.hardware.usb.IDisplayPortAltModeInfoListener;
import android.hardware.usb.IUsbOperationInternal;
import android.hardware.usb.ParcelableUsbPort;
import android.hardware.usb.UsbAccessory;
@@ -43,6 +44,7 @@
import android.hardware.usb.UsbManager;
import android.hardware.usb.UsbPort;
import android.hardware.usb.UsbPortStatus;
+import android.hardware.usb.DisplayPortAltModeInfo;
import android.os.Binder;
import android.os.Bundle;
import android.os.ParcelFileDescriptor;
@@ -902,6 +904,45 @@
}
}
+ @Override
+ public boolean registerForDisplayPortEvents(
+ @NonNull IDisplayPortAltModeInfoListener listener) {
+ Objects.requireNonNull(listener, "registerForDisplayPortEvents: listener " +
+ "must not be null.");
+
+ mContext.enforceCallingOrSelfPermission(android.Manifest.permission.MANAGE_USB, null);
+
+ final long ident = Binder.clearCallingIdentity();
+ try {
+ if (mPortManager != null) {
+ return mPortManager.registerForDisplayPortEvents(listener);
+ }
+ } finally {
+ Binder.restoreCallingIdentity(ident);
+ }
+
+ return false;
+ }
+
+ @Override
+ public void unregisterForDisplayPortEvents(
+ @NonNull IDisplayPortAltModeInfoListener listener) {
+ Objects.requireNonNull(listener, "unregisterForDisplayPortEvents: listener " +
+ "must not be null.");
+
+ mContext.enforceCallingOrSelfPermission(android.Manifest.permission.MANAGE_USB, null);
+
+ final long ident = Binder.clearCallingIdentity();
+ try {
+ if (mPortManager != null) {
+ mPortManager.unregisterForDisplayPortEvents(listener);
+ }
+ } finally {
+ Binder.restoreCallingIdentity(ident);
+ }
+ }
+
+
@NeverCompile // Avoid size overhead of debugging code.
@Override
public void dump(FileDescriptor fd, PrintWriter writer, String[] args) {
@@ -993,6 +1034,7 @@
int i;
boolean supportsComplianceWarnings = false;
+ boolean supportsDisplayPortAltMode = false;
switch (args[2]) {
case "ufp":
supportedModes = MODE_UFP;
@@ -1015,14 +1057,17 @@
case "--compliance-warnings":
supportsComplianceWarnings = true;
continue;
+ case "--displayport":
+ supportsDisplayPortAltMode = true;
+ continue;
default:
pw.println("Invalid Identifier: " + args[i]);
}
}
if (mPortManager != null) {
mPortManager.addSimulatedPort(portId, supportedModes,
- supportsComplianceWarnings,
- pw);
+ supportsComplianceWarnings, supportsDisplayPortAltMode,
+ pw);
pw.println();
mPortManager.dump(new DualDumpOutputStream(new IndentingPrintWriter(pw, " ")),
"", 0);
@@ -1124,6 +1169,29 @@
mPortManager.dump(new DualDumpOutputStream(new IndentingPrintWriter(pw, " ")),
"", 0);
}
+ } else if ("set-displayport-status".equals(args[0]) && args.length == 5) {
+ final String portId = args[1];
+ final int partnerSinkStatus = Integer.parseInt(args[2]);
+ final int cableStatus = Integer.parseInt(args[3]);
+ final int displayPortNumLanes = Integer.parseInt(args[4]);
+ if (mPortManager != null) {
+ mPortManager.simulateDisplayPortAltModeInfo(portId,
+ partnerSinkStatus, cableStatus, displayPortNumLanes, pw);
+ pw.println();
+ mPortManager.dump(new DualDumpOutputStream(new IndentingPrintWriter(pw, " ")),
+ "", 0);
+ }
+ } else if ("reset-displayport-status".equals(args[0]) && args.length == 2) {
+ final String portId = args[1];
+ if (mPortManager != null) {
+ mPortManager.simulateDisplayPortAltModeInfo(portId,
+ DisplayPortAltModeInfo.DISPLAYPORT_ALT_MODE_STATUS_UNKNOWN,
+ DisplayPortAltModeInfo.DISPLAYPORT_ALT_MODE_STATUS_UNKNOWN,
+ 0, pw);
+ pw.println();
+ mPortManager.dump(new DualDumpOutputStream(new IndentingPrintWriter(pw, " ")),
+ "", 0);
+ }
} else if ("ports".equals(args[0]) && args.length == 1) {
if (mPortManager != null) {
mPortManager.dump(new DualDumpOutputStream(new IndentingPrintWriter(pw, " ")),
@@ -1138,6 +1206,7 @@
pw.println(" add-port <id> <ufp|dfp|dual|none> <optional args>");
pw.println(" <optional args> include:");
pw.println(" --compliance-warnings: enables compliance warnings on port");
+ pw.println(" --displayport: enables DisplayPort Alt Mode on port");
pw.println(" connect-port <id> <ufp|dfp><?> <source|sink><?> <host|device><?>");
pw.println(" (add ? suffix if mode, power role, or data role can be changed)");
pw.println(" disconnect-port <id>");
@@ -1148,7 +1217,8 @@
pw.println(" dumpsys usb set-port-roles \"default\" source device");
pw.println();
pw.println("Example USB type C port simulation with full capabilities:");
- pw.println(" dumpsys usb add-port \"matrix\" dual --compliance-warnings");
+ pw.println(" dumpsys usb add-port \"matrix\" dual --compliance-warnings "
+ + "--displayport");
pw.println(" dumpsys usb connect-port \"matrix\" ufp? sink? device?");
pw.println(" dumpsys usb ports");
pw.println(" dumpsys usb disconnect-port \"matrix\"");
@@ -1186,6 +1256,14 @@
pw.println(" 3: bc12");
pw.println(" 4: missing rp");
pw.println();
+ pw.println("Example simulate DisplayPort Alt Mode Changes:");
+ pw.println(" dumpsys usb add-port \"matrix\" dual --displayport");
+ pw.println(" dumpsys usb set-displayport-status \"matrix\" <partner-sink>"
+ + " <cable> <num-lanes>");
+ pw.println(" dumpsys usb reset-displayport-status \"matrix\"");
+ pw.println("reset-displayport-status can also be used in order to set");
+ pw.println("the DisplayPortInfo to default values.");
+ pw.println();
pw.println("Example USB device descriptors:");
pw.println(" dumpsys usb dump-descriptors -dump-short");
pw.println(" dumpsys usb dump-descriptors -dump-tree");
diff --git a/services/usb/java/com/android/server/usb/hal/port/RawPortInfo.java b/services/usb/java/com/android/server/usb/hal/port/RawPortInfo.java
index e6a3e53..ef32e93 100644
--- a/services/usb/java/com/android/server/usb/hal/port/RawPortInfo.java
+++ b/services/usb/java/com/android/server/usb/hal/port/RawPortInfo.java
@@ -15,7 +15,9 @@
*/
package com.android.server.usb.hal.port;
+import android.hardware.usb.UsbPort;
import android.hardware.usb.UsbPortStatus;
+import android.hardware.usb.DisplayPortAltModeInfo;
import android.os.Parcel;
import android.os.Parcelable;
@@ -42,6 +44,9 @@
public int powerBrickConnectionStatus;
public final boolean supportsComplianceWarnings;
public int[] complianceWarnings;
+ public int plugState;
+ public int supportedAltModes;
+ public DisplayPortAltModeInfo displayPortAltModeInfo;
public RawPortInfo(String portId, int supportedModes) {
this.portId = portId;
@@ -56,6 +61,9 @@
this.powerBrickConnectionStatus = UsbPortStatus.POWER_BRICK_STATUS_UNKNOWN;
this.supportsComplianceWarnings = false;
this.complianceWarnings = new int[] {};
+ this.plugState = UsbPortStatus.PLUG_STATE_UNKNOWN;
+ this.supportedAltModes = 0;
+ this.displayPortAltModeInfo = null;
}
public RawPortInfo(String portId, int supportedModes, int supportedContaminantProtectionModes,
@@ -76,7 +84,8 @@
supportsEnableContaminantPresenceProtection, contaminantProtectionStatus,
supportsEnableContaminantPresenceDetection, contaminantDetectionStatus,
usbDataStatus, powerTransferLimited, powerBrickConnectionStatus,
- false, new int[] {});
+ false, new int[] {}, UsbPortStatus.PLUG_STATE_UNKNOWN,
+ 0, null);
}
public RawPortInfo(String portId, int supportedModes, int supportedContaminantProtectionModes,
@@ -91,7 +100,10 @@
boolean powerTransferLimited,
int powerBrickConnectionStatus,
boolean supportsComplianceWarnings,
- int[] complianceWarnings) {
+ int[] complianceWarnings,
+ int plugState,
+ int supportedAltModes,
+ DisplayPortAltModeInfo displayPortAltModeInfo) {
this.portId = portId;
this.supportedModes = supportedModes;
this.supportedContaminantProtectionModes = supportedContaminantProtectionModes;
@@ -112,6 +124,9 @@
this.powerBrickConnectionStatus = powerBrickConnectionStatus;
this.supportsComplianceWarnings = supportsComplianceWarnings;
this.complianceWarnings = complianceWarnings;
+ this.plugState = plugState;
+ this.supportedAltModes = supportedAltModes;
+ this.displayPortAltModeInfo = displayPortAltModeInfo;
}
@Override
@@ -139,12 +154,19 @@
dest.writeInt(powerBrickConnectionStatus);
dest.writeBoolean(supportsComplianceWarnings);
dest.writeIntArray(complianceWarnings);
+ dest.writeInt(plugState);
+ dest.writeInt(supportedAltModes);
+ if ((supportedAltModes & UsbPort.FLAG_ALT_MODE_TYPE_DISPLAYPORT) != 0) {
+ displayPortAltModeInfo.writeToParcel(dest, 0);
+ }
}
public static final Parcelable.Creator<RawPortInfo> CREATOR =
new Parcelable.Creator<RawPortInfo>() {
@Override
public RawPortInfo createFromParcel(Parcel in) {
+ DisplayPortAltModeInfo displayPortAltModeInfo;
+
String id = in.readString();
int supportedModes = in.readInt();
int supportedContaminantProtectionModes = in.readInt();
@@ -163,6 +185,13 @@
int powerBrickConnectionStatus = in.readInt();
boolean supportsComplianceWarnings = in.readBoolean();
int[] complianceWarnings = in.createIntArray();
+ int plugState = in.readInt();
+ int supportedAltModes = in.readInt();
+ if ((supportedAltModes & UsbPort.FLAG_ALT_MODE_TYPE_DISPLAYPORT) != 0) {
+ displayPortAltModeInfo = DisplayPortAltModeInfo.CREATOR.createFromParcel(in);
+ } else {
+ displayPortAltModeInfo = null;
+ }
return new RawPortInfo(id, supportedModes,
supportedContaminantProtectionModes, currentMode, canChangeMode,
currentPowerRole, canChangePowerRole,
@@ -172,7 +201,8 @@
supportsEnableContaminantPresenceDetection,
contaminantDetectionStatus, usbDataStatus,
powerTransferLimited, powerBrickConnectionStatus,
- supportsComplianceWarnings, complianceWarnings);
+ supportsComplianceWarnings, complianceWarnings,
+ plugState, supportedAltModes, displayPortAltModeInfo);
}
@Override
diff --git a/services/usb/java/com/android/server/usb/hal/port/UsbPortAidl.java b/services/usb/java/com/android/server/usb/hal/port/UsbPortAidl.java
index ff4268f..b9ccace 100644
--- a/services/usb/java/com/android/server/usb/hal/port/UsbPortAidl.java
+++ b/services/usb/java/com/android/server/usb/hal/port/UsbPortAidl.java
@@ -35,6 +35,10 @@
import android.hardware.usb.PortRole;
import android.hardware.usb.PortStatus;
import android.hardware.usb.ComplianceWarning;
+import android.hardware.usb.DisplayPortAltModeInfo;
+import android.hardware.usb.AltModeData;
+import android.hardware.usb.AltModeData.DisplayPortAltModeData;
+import android.hardware.usb.DisplayPortAltModePinAssignment;
import android.os.Build;
import android.os.ServiceManager;
import android.os.IBinder;
@@ -600,6 +604,47 @@
return newComplianceWarnings.toArray();
}
+ private int toSupportedAltModesInt(android.hardware.usb.AltModeData[] supportedAltModes) {
+ int supportedAltModesInt = 0;
+ for (android.hardware.usb.AltModeData altModeData : supportedAltModes) {
+ switch (altModeData.getTag()) {
+ case AltModeData.displayPortAltModeData:
+ supportedAltModesInt |= UsbPort.FLAG_ALT_MODE_TYPE_DISPLAYPORT;
+ break;
+ }
+ }
+ return supportedAltModesInt;
+ }
+
+ private int toDisplayPortAltModeNumLanesInt(int pinAssignment) {
+ switch (pinAssignment) {
+ case DisplayPortAltModePinAssignment.A:
+ case DisplayPortAltModePinAssignment.C:
+ case DisplayPortAltModePinAssignment.E:
+ return 4;
+ case DisplayPortAltModePinAssignment.B:
+ case DisplayPortAltModePinAssignment.D:
+ case DisplayPortAltModePinAssignment.F:
+ return 2;
+ default:
+ return 0;
+ }
+ }
+
+ private DisplayPortAltModeInfo formatDisplayPortAltModeInfo(
+ android.hardware.usb.AltModeData[] supportedAltModes) {
+ for (android.hardware.usb.AltModeData altModeData : supportedAltModes) {
+ if (altModeData.getTag() == AltModeData.displayPortAltModeData) {
+ DisplayPortAltModeData displayPortData =
+ altModeData.getDisplayPortAltModeData();
+ return new DisplayPortAltModeInfo(displayPortData.partnerSinkStatus,
+ displayPortData.cableStatus,
+ toDisplayPortAltModeNumLanesInt(displayPortData.pinAssignment));
+ }
+ }
+ return null;
+ }
+
@Override
public void notifyPortStatusChange(
android.hardware.usb.PortStatus[] currentPortStatus, int retval) {
@@ -635,7 +680,10 @@
current.powerTransferLimited,
current.powerBrickStatus,
current.supportsComplianceWarnings,
- formatComplianceWarnings(current.complianceWarnings));
+ formatComplianceWarnings(current.complianceWarnings),
+ current.plugOrientation,
+ toSupportedAltModesInt(current.supportedAltModes),
+ formatDisplayPortAltModeInfo(current.supportedAltModes));
newPortInfo.add(temp);
UsbPortManager.logAndPrint(Log.INFO, mPw, "ClientCallback AIDL V1: "
+ current.portName);
diff --git a/services/usb/java/com/android/server/usb/hal/port/UsbPortHidl.java b/services/usb/java/com/android/server/usb/hal/port/UsbPortHidl.java
index 10403c1..a7ecabb 100644
--- a/services/usb/java/com/android/server/usb/hal/port/UsbPortHidl.java
+++ b/services/usb/java/com/android/server/usb/hal/port/UsbPortHidl.java
@@ -35,7 +35,8 @@
import static android.hardware.usb.UsbPortStatus.POWER_ROLE_SOURCE;
import static android.hardware.usb.UsbPortStatus.DATA_STATUS_DISABLED_FORCE;
import static android.hardware.usb.UsbPortStatus.DATA_STATUS_UNKNOWN;
-
+import static android.hardware.usb.UsbPortStatus.PLUG_STATE_UNKNOWN;
+import static android.hardware.usb.DisplayPortAltModeInfo.DISPLAYPORT_ALT_MODE_STATUS_UNKNOWN;
import static com.android.server.usb.UsbPortManager.logAndPrint;
import static com.android.server.usb.UsbPortManager.logAndPrintException;
@@ -422,7 +423,10 @@
false, CONTAMINANT_PROTECTION_NONE,
false, CONTAMINANT_DETECTION_NOT_SUPPORTED, sUsbDataStatus,
false, POWER_BRICK_STATUS_UNKNOWN,
- false, new int[] {});
+ false, new int[] {},
+ PLUG_STATE_UNKNOWN,
+ 0,
+ null);
newPortInfo.add(temp);
UsbPortManager.logAndPrint(Log.INFO, mPw, "ClientCallback V1_0: "
+ current.portName);
@@ -457,7 +461,10 @@
false, CONTAMINANT_PROTECTION_NONE,
false, CONTAMINANT_DETECTION_NOT_SUPPORTED, sUsbDataStatus,
false, POWER_BRICK_STATUS_UNKNOWN,
- false, new int[] {});
+ false, new int[] {},
+ PLUG_STATE_UNKNOWN,
+ 0,
+ null);
newPortInfo.add(temp);
UsbPortManager.logAndPrint(Log.INFO, mPw, "ClientCallback V1_1: "
+ current.status.portName);
@@ -496,7 +503,10 @@
current.contaminantDetectionStatus,
sUsbDataStatus,
false, POWER_BRICK_STATUS_UNKNOWN,
- false, new int[] {});
+ false, new int[] {},
+ PLUG_STATE_UNKNOWN,
+ 0,
+ null);
newPortInfo.add(temp);
UsbPortManager.logAndPrint(Log.INFO, mPw, "ClientCallback V1_2: "
+ current.status_1_1.status.portName);
diff --git a/telecomm/java/android/telecom/Call.java b/telecomm/java/android/telecom/Call.java
index bbdc890..95c9061 100644
--- a/telecomm/java/android/telecom/Call.java
+++ b/telecomm/java/android/telecom/Call.java
@@ -2123,6 +2123,14 @@
* <p>
* No assumptions should be made as to how an In-Call UI or service will handle these
* extras. Keys should be fully qualified (e.g., com.example.MY_EXTRA) to avoid conflicts.
+ * <p>
+ * Extras added using this method will be made available to the {@link ConnectionService}
+ * associated with this {@link Call} and notified via
+ * {@link Connection#onExtrasChanged(Bundle)}.
+ * <p>
+ * Extras added using this method will also be available to other running {@link InCallService}s
+ * and notified via {@link Call.Callback#onDetailsChanged(Call, Details)}. The extras can be
+ * accessed via {@link Details#getExtras()}.
*
* @param extras The extras to add.
*/
diff --git a/telecomm/java/android/telecom/CallControl.java b/telecomm/java/android/telecom/CallControl.java
index 867bcc7..770a374 100644
--- a/telecomm/java/android/telecom/CallControl.java
+++ b/telecomm/java/android/telecom/CallControl.java
@@ -31,6 +31,8 @@
import com.android.internal.telecom.ClientTransactionalServiceRepository;
import com.android.internal.telecom.ICallControl;
+import java.util.List;
+import java.util.Objects;
import java.util.concurrent.Executor;
/**
@@ -223,6 +225,42 @@
}
/**
+ * Request a CallEndpoint change. Clients should not define their own CallEndpoint when
+ * requesting a change. Instead, the new endpoint should be one of the valid endpoints provided
+ * by {@link CallEventCallback#onAvailableCallEndpointsChanged(List)}.
+ *
+ * @param callEndpoint ; The {@link CallEndpoint} to change to.
+ * @param executor ; The {@link Executor} on which the {@link OutcomeReceiver} callback
+ * will be called on.
+ * @param callback ; The {@link OutcomeReceiver} that will be completed on the Telecom side
+ * that details success or failure of the requested operation.
+ *
+ * {@link OutcomeReceiver#onResult} will be called if Telecom has
+ * successfully changed the CallEndpoint that was requested.
+ *
+ * {@link OutcomeReceiver#onError} will be called if Telecom has failed to
+ * switch to the requested CallEndpoint. A {@link CallException} will be
+ * passed that details why the operation failed.
+ */
+ public void requestCallEndpointChange(@NonNull CallEndpoint callEndpoint,
+ @CallbackExecutor @NonNull Executor executor,
+ @NonNull OutcomeReceiver<Void, CallException> callback) {
+ Objects.requireNonNull(callEndpoint);
+ Objects.requireNonNull(executor);
+ Objects.requireNonNull(callback);
+ if (mServerInterface != null) {
+ try {
+ mServerInterface.requestCallEndpointChange(callEndpoint,
+ new CallControlResultReceiver("endpointChange", executor, callback));
+ } catch (RemoteException e) {
+ throw e.rethrowAsRuntimeException();
+ }
+ } else {
+ throw new IllegalStateException(INTERFACE_ERROR_MSG);
+ }
+ }
+
+ /**
* This method should be called after
* {@link CallControl#disconnect(DisconnectCause, Executor, OutcomeReceiver)} or
* {@link CallControl#rejectCall(Executor, OutcomeReceiver)}
diff --git a/telecomm/java/android/telecom/CallEventCallback.java b/telecomm/java/android/telecom/CallEventCallback.java
index fd7e101..806febd 100644
--- a/telecomm/java/android/telecom/CallEventCallback.java
+++ b/telecomm/java/android/telecom/CallEventCallback.java
@@ -19,6 +19,7 @@
import android.annotation.NonNull;
+import java.util.List;
import java.util.function.Consumer;
/**
@@ -95,13 +96,6 @@
void onDisconnect(@NonNull Consumer<Boolean> wasCompleted);
/**
- * update the client on the new {@link CallAudioState}
- *
- * @param callAudioState that is currently being used
- */
- void onCallAudioStateChanged(@NonNull CallAudioState callAudioState);
-
- /**
* Telecom is informing the client to set the call in streaming.
*
* @param wasCompleted The {@link Consumer} to be completed. If the client can stream the
@@ -118,4 +112,26 @@
* @param reason Code to indicate the reason of this failure
*/
void onCallStreamingFailed(@CallStreamingService.StreamingFailedReason int reason);
+
+ /**
+ * Telecom is informing the client the current {@link CallEndpoint} changed.
+ *
+ * @param newCallEndpoint The new {@link CallEndpoint} through which call media flows
+ * (i.e. speaker, bluetooth, etc.).
+ */
+ void onCallEndpointChanged(@NonNull CallEndpoint newCallEndpoint);
+
+ /**
+ * Telecom is informing the client that the available {@link CallEndpoint}s have changed.
+ *
+ * @param availableEndpoints The set of available {@link CallEndpoint}s reported by Telecom.
+ */
+ void onAvailableCallEndpointsChanged(@NonNull List<CallEndpoint> availableEndpoints);
+
+ /**
+ * Called when the mute state changes.
+ *
+ * @param isMuted The current mute state.
+ */
+ void onMuteStateChanged(boolean isMuted);
}
diff --git a/telecomm/java/android/telecom/PhoneAccount.java b/telecomm/java/android/telecom/PhoneAccount.java
index b8c056e..ca15422 100644
--- a/telecomm/java/android/telecom/PhoneAccount.java
+++ b/telecomm/java/android/telecom/PhoneAccount.java
@@ -540,6 +540,11 @@
/**
* Creates a builder with the specified {@link PhoneAccountHandle} and label.
+ * <p>
+ * Note: each CharSequence or String field is limited to 256 characters. This check is
+ * enforced when registering the PhoneAccount via
+ * {@link TelecomManager#registerPhoneAccount(PhoneAccount)} and will cause an
+ * {@link IllegalArgumentException} to be thrown if the character field limit is over 256.
*/
public Builder(PhoneAccountHandle accountHandle, CharSequence label) {
this.mAccountHandle = accountHandle;
@@ -570,6 +575,11 @@
/**
* Sets the label. See {@link PhoneAccount#getLabel()}.
+ * <p>
+ * Note: Each CharSequence or String field is limited to 256 characters. This check is
+ * enforced when registering the PhoneAccount via
+ * {@link TelecomManager#registerPhoneAccount(PhoneAccount)} and will cause an
+ * {@link IllegalArgumentException} to be thrown if the character field limit is over 256.
*
* @param label The label of the phone account.
* @return The builder.
@@ -636,6 +646,11 @@
/**
* Sets the short description. See {@link PhoneAccount#getShortDescription}.
+ * <p>
+ * Note: Each CharSequence or String field is limited to 256 characters. This check is
+ * enforced when registering the PhoneAccount via
+ * {@link TelecomManager#registerPhoneAccount(PhoneAccount)} and will cause an
+ * {@link IllegalArgumentException} to be thrown if the character field limit is over 256.
*
* @param value The short description.
* @return The builder.
@@ -680,6 +695,13 @@
* <p>
* {@code PhoneAccount}s only support extra values of type: {@link String}, {@link Integer},
* and {@link Boolean}. Extras which are not of these types are ignored.
+ * <p>
+ * Note: Each Bundle (Key, Value) String field is limited to 256 characters. Additionally,
+ * the bundle is limited to 100 (Key, Value) pairs total. This check is
+ * enforced when registering the PhoneAccount via
+ * {@link TelecomManager#registerPhoneAccount(PhoneAccount)} and will cause an
+ * {@link IllegalArgumentException} to be thrown if the character field limit is over 256
+ * or more than 100 (Key, Value) pairs are in the Bundle.
*
* @param extras
* @return
@@ -711,6 +733,11 @@
* <p>
* Note: This is an API specific to the Telephony stack; the group Id will be ignored for
* callers not holding the correct permission.
+ * <p>
+ * Additionally, each CharSequence or String field is limited to 256 characters.
+ * This check is enforced when registering the PhoneAccount via
+ * {@link TelecomManager#registerPhoneAccount(PhoneAccount)} and will cause an
+ * {@link IllegalArgumentException} to be thrown if the character field limit is over 256.
*
* @param groupId The group Id of the {@link PhoneAccount} that will replace any other
* registered {@link PhoneAccount} in Telecom with the same Group Id.
diff --git a/telecomm/java/android/telecom/PhoneAccountHandle.java b/telecomm/java/android/telecom/PhoneAccountHandle.java
index ec94f8a..e5db8cf 100644
--- a/telecomm/java/android/telecom/PhoneAccountHandle.java
+++ b/telecomm/java/android/telecom/PhoneAccountHandle.java
@@ -70,6 +70,12 @@
* ID provided does not expose personally identifying information. A
* {@link ConnectionService} should use an opaque token as the
* {@link PhoneAccountHandle} identifier.
+ * <p>
+ * Note: Each String field is limited to 256 characters. This check is enforced when
+ * registering the PhoneAccount via
+ * {@link TelecomManager#registerPhoneAccount(PhoneAccount)} and will cause an
+ * {@link IllegalArgumentException} to be thrown if the character field limit is
+ * over 256.
*/
public PhoneAccountHandle(
@NonNull ComponentName componentName,
@@ -88,6 +94,13 @@
* {@link ConnectionService} should use an opaque token as the
* {@link PhoneAccountHandle} identifier.
* @param userHandle The {@link UserHandle} associated with this {@link PhoneAccountHandle}.
+ *
+ * <p>
+ * Note: Each String field is limited to 256 characters. This check is enforced when
+ * registering the PhoneAccount via
+ * {@link TelecomManager#registerPhoneAccount(PhoneAccount)} and will cause an
+ * {@link IllegalArgumentException} to be thrown if the character field limit is
+ * over 256.
*/
public PhoneAccountHandle(
@NonNull ComponentName componentName,
diff --git a/telecomm/java/com/android/internal/telecom/ClientTransactionalServiceWrapper.java b/telecomm/java/com/android/internal/telecom/ClientTransactionalServiceWrapper.java
index 16816ff..b2e921b 100644
--- a/telecomm/java/com/android/internal/telecom/ClientTransactionalServiceWrapper.java
+++ b/telecomm/java/com/android/internal/telecom/ClientTransactionalServiceWrapper.java
@@ -22,14 +22,15 @@
import android.os.OutcomeReceiver;
import android.os.ResultReceiver;
import android.telecom.CallAttributes;
-import android.telecom.CallAudioState;
import android.telecom.CallControl;
+import android.telecom.CallEndpoint;
import android.telecom.CallEventCallback;
import android.telecom.CallException;
import android.telecom.PhoneAccountHandle;
import android.text.TextUtils;
import android.util.Log;
+import java.util.List;
import java.util.UUID;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.Executor;
@@ -140,6 +141,9 @@
private static final String ON_REJECT = "onReject";
private static final String ON_DISCONNECT = "onDisconnect";
private static final String ON_STREAMING_STARTED = "onStreamingStarted";
+ private static final String ON_REQ_ENDPOINT_CHANGE = "onRequestEndpointChange";
+ private static final String ON_AVAILABLE_CALL_ENDPOINTS = "onAvailableCallEndpointsChanged";
+ private static final String ON_MUTE_STATE_CHANGED = "onMuteStateChanged";
private void handleCallEventCallback(String action, String callId, int code,
ResultReceiver ackResultReceiver) {
@@ -246,14 +250,45 @@
}
@Override
- public void onCallAudioStateChanged(String callId, CallAudioState callAudioState) {
- Log.i(TAG, TextUtils.formatSimple("onCallAudioStateChanged: callId=[%s]", callId));
+ public void onCallEndpointChanged(String callId, CallEndpoint endpoint) {
+ handleEndpointUpdate(callId, ON_REQ_ENDPOINT_CHANGE, endpoint);
+ }
+
+ @Override
+ public void onAvailableCallEndpointsChanged(String callId, List<CallEndpoint> endpoints) {
+ handleEndpointUpdate(callId, ON_AVAILABLE_CALL_ENDPOINTS, endpoints);
+ }
+
+ @Override
+ public void onMuteStateChanged(String callId, boolean isMuted) {
+ handleEndpointUpdate(callId, ON_MUTE_STATE_CHANGED, isMuted);
+ }
+
+ public void handleEndpointUpdate(String callId, String action, Object arg) {
+ Log.d(TAG, TextUtils.formatSimple("[%s], callId=[%s]", action, callId));
// lookup the callEventCallback associated with the particular call
TransactionalCall call = mCallIdToTransactionalCall.get(callId);
if (call != null) {
CallEventCallback callback = call.getCallEventCallback();
Executor executor = call.getExecutor();
- executor.execute(() -> callback.onCallAudioStateChanged(callAudioState));
+ final long identity = Binder.clearCallingIdentity();
+ try {
+ executor.execute(() -> {
+ switch (action) {
+ case ON_REQ_ENDPOINT_CHANGE:
+ callback.onCallEndpointChanged((CallEndpoint) arg);
+ break;
+ case ON_AVAILABLE_CALL_ENDPOINTS:
+ callback.onAvailableCallEndpointsChanged((List<CallEndpoint>) arg);
+ break;
+ case ON_MUTE_STATE_CHANGED:
+ callback.onMuteStateChanged((boolean) arg);
+ break;
+ }
+ });
+ } finally {
+ Binder.restoreCallingIdentity(identity);
+ }
}
}
diff --git a/telecomm/java/com/android/internal/telecom/ICallControl.aidl b/telecomm/java/com/android/internal/telecom/ICallControl.aidl
index dc0aeac..a5c6e44 100644
--- a/telecomm/java/com/android/internal/telecom/ICallControl.aidl
+++ b/telecomm/java/com/android/internal/telecom/ICallControl.aidl
@@ -17,6 +17,7 @@
package com.android.internal.telecom;
import android.telecom.CallControl;
+import android.telecom.CallEndpoint;
import android.telecom.DisconnectCause;
import android.os.ResultReceiver;
@@ -29,4 +30,5 @@
void disconnect(String callId, in DisconnectCause disconnectCause, in ResultReceiver callback);
void rejectCall(String callId, in ResultReceiver callback);
void startCallStreaming(String callId, in ResultReceiver callback);
+ void requestCallEndpointChange(in CallEndpoint callEndpoint, in ResultReceiver callback);
}
\ No newline at end of file
diff --git a/telecomm/java/com/android/internal/telecom/ICallEventCallback.aidl b/telecomm/java/com/android/internal/telecom/ICallEventCallback.aidl
index c45ef97..fef5e9e 100644
--- a/telecomm/java/com/android/internal/telecom/ICallEventCallback.aidl
+++ b/telecomm/java/com/android/internal/telecom/ICallEventCallback.aidl
@@ -17,10 +17,12 @@
package com.android.internal.telecom;
import android.telecom.CallControl;
+import android.telecom.CallEndpoint;
import com.android.internal.telecom.ICallControl;
import android.os.ResultReceiver;
import android.telecom.CallAudioState;
import android.telecom.CallException;
+import java.util.List;
/**
* {@hide}
@@ -29,15 +31,19 @@
// publicly exposed. Client should override
void onAddCallControl(String callId, int resultCode, in ICallControl callControl,
in CallException exception);
+ // -- Call Event Actions / Call State Transitions
void onSetActive(String callId, in ResultReceiver callback);
void onSetInactive(String callId, in ResultReceiver callback);
void onAnswer(String callId, int videoState, in ResultReceiver callback);
void onReject(String callId, in ResultReceiver callback);
void onDisconnect(String callId, in ResultReceiver callback);
- void onCallAudioStateChanged(String callId, in CallAudioState callAudioState);
- // Streaming related. Client registered call streaming capabilities should override
+ // -- Streaming related. Client registered call streaming capabilities should override
void onCallStreamingStarted(String callId, in ResultReceiver callback);
void onCallStreamingFailed(String callId, int reason);
+ // -- Audio related.
+ void onCallEndpointChanged(String callId, in CallEndpoint endpoint);
+ void onAvailableCallEndpointsChanged(String callId, in List<CallEndpoint> endpoint);
+ void onMuteStateChanged(String callId, boolean isMuted);
// hidden methods that help with cleanup
void removeCallFromTransactionalServiceWrapper(String callId);
}
\ No newline at end of file
diff --git a/telephony/java/android/service/euicc/EuiccService.java b/telephony/java/android/service/euicc/EuiccService.java
index e19117b..2c0087e 100644
--- a/telephony/java/android/service/euicc/EuiccService.java
+++ b/telephony/java/android/service/euicc/EuiccService.java
@@ -490,6 +490,28 @@
int slotId, DownloadableSubscription subscription, boolean forceDeactivateSim);
/**
+ * Populate {@link DownloadableSubscription} metadata for the given downloadable subscription.
+ *
+ * @param slotId ID of the SIM slot to use for the operation.
+ * @param portIndex Index of the port from the slot. portIndex is used if the eUICC must
+ * be activated to perform the operation.
+ * @param subscription A subscription whose metadata needs to be populated.
+ * @param forceDeactivateSim If true, and if an active SIM must be deactivated to access the
+ * eUICC, perform this action automatically. Otherwise, {@link #RESULT_MUST_DEACTIVATE_SIM}
+ * should be returned to allow the user to consent to this operation first.
+ * @return The result of the operation.
+ * @see android.telephony.euicc.EuiccManager#getDownloadableSubscriptionMetadata
+ */
+ @NonNull
+ public GetDownloadableSubscriptionMetadataResult onGetDownloadableSubscriptionMetadata(
+ int slotId, int portIndex, @NonNull DownloadableSubscription subscription,
+ boolean forceDeactivateSim) {
+ // stub implementation, LPA needs to implement this
+ throw new UnsupportedOperationException(
+ "LPA must override onGetDownloadableSubscriptionMetadata");
+ }
+
+ /**
* Return metadata for subscriptions which are available for download for this device.
*
* @param slotId ID of the SIM slot to use for the operation.
@@ -833,16 +855,31 @@
}
@Override
- public void getDownloadableSubscriptionMetadata(int slotId,
+ public void getDownloadableSubscriptionMetadata(int slotId, int portIndex,
DownloadableSubscription subscription,
- boolean forceDeactivateSim,
+ boolean switchAfterDownload, boolean forceDeactivateSim,
IGetDownloadableSubscriptionMetadataCallback callback) {
mExecutor.execute(new Runnable() {
@Override
public void run() {
- GetDownloadableSubscriptionMetadataResult result =
- EuiccService.this.onGetDownloadableSubscriptionMetadata(
+ GetDownloadableSubscriptionMetadataResult result;
+ if (switchAfterDownload) {
+ try {
+ result = EuiccService.this.onGetDownloadableSubscriptionMetadata(
+ slotId, portIndex, subscription, forceDeactivateSim);
+ } catch (UnsupportedOperationException | AbstractMethodError e) {
+ Log.w(TAG, "The new onGetDownloadableSubscriptionMetadata(int, int, "
+ + "DownloadableSubscription, boolean) is not implemented."
+ + " Fall back to the old one.", e);
+ result = EuiccService.this.onGetDownloadableSubscriptionMetadata(
slotId, subscription, forceDeactivateSim);
+ }
+ } else {
+ // When switchAfterDownload is false, this operation is port agnostic.
+ // Call API without portIndex.
+ result = EuiccService.this.onGetDownloadableSubscriptionMetadata(
+ slotId, subscription, forceDeactivateSim);
+ }
try {
callback.onComplete(result);
} catch (RemoteException e) {
diff --git a/telephony/java/android/service/euicc/IEuiccService.aidl b/telephony/java/android/service/euicc/IEuiccService.aidl
index 6b0397d..f8d5ae9 100644
--- a/telephony/java/android/service/euicc/IEuiccService.aidl
+++ b/telephony/java/android/service/euicc/IEuiccService.aidl
@@ -38,8 +38,10 @@
void downloadSubscription(int slotId, int portIndex, in DownloadableSubscription subscription,
boolean switchAfterDownload, boolean forceDeactivateSim, in Bundle resolvedBundle,
in IDownloadSubscriptionCallback callback);
- void getDownloadableSubscriptionMetadata(int slotId, in DownloadableSubscription subscription,
- boolean forceDeactivateSim, in IGetDownloadableSubscriptionMetadataCallback callback);
+ void getDownloadableSubscriptionMetadata(
+ int slotId, int portIndex, in DownloadableSubscription subscription,
+ boolean switchAfterDownload, boolean forceDeactivateSim,
+ in IGetDownloadableSubscriptionMetadataCallback callback);
void getEid(int slotId, in IGetEidCallback callback);
void getOtaStatus(int slotId, in IGetOtaStatusCallback callback);
void startOtaIfNecessary(int slotId, in IOtaStatusChangedCallback statusChangedCallback);
diff --git a/telephony/java/android/telephony/ModemActivityInfo.java b/telephony/java/android/telephony/ModemActivityInfo.java
index 2d0135a..64b3c0a 100644
--- a/telephony/java/android/telephony/ModemActivityInfo.java
+++ b/telephony/java/android/telephony/ModemActivityInfo.java
@@ -567,14 +567,14 @@
/** @hide */
@TestApi
public boolean isEmpty() {
- boolean isTxPowerEmpty = false;
- boolean isRxPowerEmpty = false;
+ boolean isTxPowerEmpty = true;
+ boolean isRxPowerEmpty = true;
for (int i = 0; i < getSpecificInfoLength(); i++) {
- if (mActivityStatsTechSpecificInfo[i].isTxPowerEmpty()) {
- isTxPowerEmpty = true;
+ if (!mActivityStatsTechSpecificInfo[i].isTxPowerEmpty()) {
+ isTxPowerEmpty = false;
}
- if (mActivityStatsTechSpecificInfo[i].isRxPowerEmpty()) {
- isRxPowerEmpty = true;
+ if (!mActivityStatsTechSpecificInfo[i].isRxPowerEmpty()) {
+ isRxPowerEmpty = false;
}
}
return isTxPowerEmpty
diff --git a/telephony/java/android/telephony/NetworkScanRequest.java b/telephony/java/android/telephony/NetworkScanRequest.java
index 326f417..65c2146 100644
--- a/telephony/java/android/telephony/NetworkScanRequest.java
+++ b/telephony/java/android/telephony/NetworkScanRequest.java
@@ -26,7 +26,7 @@
import java.util.Arrays;
/**
- * Defines a request to peform a network scan.
+ * Defines a request to perform a network scan.
*
* This class defines whether the network scan will be performed only once or periodically until
* cancelled, when the scan is performed periodically, the time interval is not controlled by the
diff --git a/telephony/java/android/telephony/emergency/EmergencyNumber.java b/telephony/java/android/telephony/emergency/EmergencyNumber.java
index e78a1e1..64bcf71 100644
--- a/telephony/java/android/telephony/emergency/EmergencyNumber.java
+++ b/telephony/java/android/telephony/emergency/EmergencyNumber.java
@@ -25,6 +25,8 @@
import android.os.Parcelable;
import android.telephony.CarrierConfigManager;
import android.telephony.PhoneNumberUtils;
+import android.util.SparseArray;
+import android.util.SparseIntArray;
import com.android.telephony.Rlog;
@@ -247,6 +249,17 @@
private final List<String> mEmergencyUrns;
private final int mEmergencyNumberSourceBitmask;
private final int mEmergencyCallRouting;
+ /**
+ * The source of the EmergencyNumber in the order of precedence.
+ */
+ private static final int[] EMERGENCY_NUMBER_SOURCE_PRECEDENCE;
+ static {
+ EMERGENCY_NUMBER_SOURCE_PRECEDENCE = new int[4];
+ EMERGENCY_NUMBER_SOURCE_PRECEDENCE[0] = EMERGENCY_NUMBER_SOURCE_NETWORK_SIGNALING;
+ EMERGENCY_NUMBER_SOURCE_PRECEDENCE[1] = EMERGENCY_NUMBER_SOURCE_SIM;
+ EMERGENCY_NUMBER_SOURCE_PRECEDENCE[2] = EMERGENCY_NUMBER_SOURCE_DATABASE;
+ EMERGENCY_NUMBER_SOURCE_PRECEDENCE[3] = EMERGENCY_NUMBER_SOURCE_MODEM_CONFIG;
+ }
/** @hide */
public EmergencyNumber(@NonNull String number, @NonNull String countryIso, @NonNull String mnc,
@@ -601,19 +614,44 @@
*/
public static void mergeSameNumbersInEmergencyNumberList(
List<EmergencyNumber> emergencyNumberList) {
+ mergeSameNumbersInEmergencyNumberList(emergencyNumberList, false);
+ }
+
+ /**
+ * In-place merge same emergency numbers in the emergency number list.
+ *
+ * A unique EmergencyNumber has a unique combination of ‘number’, ‘mcc’ and 'mnc' fields.
+ * If mergeServiceCategoriesAndUrns is true ignore comparing of 'urns' and
+ * 'categories' fields and determine these fields from most precedent number. Else compare
+ * to get unique combination of EmergencyNumber.
+ * Multiple Emergency Number Sources should be merged into one bitfield for the
+ * same EmergencyNumber.
+ *
+ * @param emergencyNumberList the emergency number list to process
+ * @param mergeServiceCategoriesAndUrns {@code true} determine service category and urns
+ * from most precedent number. {@code false} compare those fields for determing duplicate.
+ *
+ * @hide
+ */
+ public static void mergeSameNumbersInEmergencyNumberList(
+ @NonNull List<EmergencyNumber> emergencyNumberList,
+ boolean mergeServiceCategoriesAndUrns) {
if (emergencyNumberList == null) {
return;
}
+
Set<Integer> duplicatedEmergencyNumberPosition = new HashSet<>();
for (int i = 0; i < emergencyNumberList.size(); i++) {
for (int j = 0; j < i; j++) {
- if (areSameEmergencyNumbers(
- emergencyNumberList.get(i), emergencyNumberList.get(j))) {
- Rlog.e(LOG_TAG, "Found unexpected duplicate numbers: "
- + emergencyNumberList.get(i) + " vs " + emergencyNumberList.get(j));
+ if (areSameEmergencyNumbers(emergencyNumberList.get(i),
+ emergencyNumberList.get(j), mergeServiceCategoriesAndUrns)) {
+ Rlog.e(LOG_TAG, "Found unexpected duplicate numbers "
+ + emergencyNumberList.get(i)
+ + " vs " + emergencyNumberList.get(j));
// Set the merged emergency number in the current position
- emergencyNumberList.set(i, mergeSameEmergencyNumbers(
- emergencyNumberList.get(i), emergencyNumberList.get(j)));
+ emergencyNumberList.set(i,
+ mergeSameEmergencyNumbers(emergencyNumberList.get(i),
+ emergencyNumberList.get(j), mergeServiceCategoriesAndUrns));
// Mark the emergency number has been merged
duplicatedEmergencyNumberPosition.add(j);
}
@@ -632,18 +670,24 @@
/**
* Check if two emergency numbers are the same.
*
- * A unique EmergencyNumber has a unique combination of ‘number’, ‘mcc’, 'mnc' and
- * 'categories', and 'routing' fields. Multiple Emergency Number Sources should be
+ * A unique EmergencyNumber has a unique combination of ‘number’, ‘mcc’, 'mnc' fields.
+ * If mergeServiceCategoriesAndUrns is true ignore comparing of 'urns' and
+ * 'categories' fields and determine these fields from most precedent number. Else compare
+ * to get unique combination of EmergencyNumber.
+ * Multiple Emergency Number Sources should be
* merged into one bitfield for the same EmergencyNumber.
*
* @param first first EmergencyNumber to compare
* @param second second EmergencyNumber to compare
+ * @param ignoreServiceCategoryAndUrns {@code true} Ignore comparing of service category
+ * and Urns so that they can be determined from most precedent number. {@code false} compare
+ * those fields for determing duplicate.
* @return true if they are the same EmergencyNumbers; false otherwise.
*
* @hide
*/
public static boolean areSameEmergencyNumbers(@NonNull EmergencyNumber first,
- @NonNull EmergencyNumber second) {
+ @NonNull EmergencyNumber second, boolean ignoreServiceCategoryAndUrns) {
if (!first.getNumber().equals(second.getNumber())) {
return false;
}
@@ -653,12 +697,14 @@
if (!first.getMnc().equals(second.getMnc())) {
return false;
}
- if (first.getEmergencyServiceCategoryBitmask()
- != second.getEmergencyServiceCategoryBitmask()) {
- return false;
- }
- if (!first.getEmergencyUrns().equals(second.getEmergencyUrns())) {
- return false;
+ if (!ignoreServiceCategoryAndUrns) {
+ if (first.getEmergencyServiceCategoryBitmask()
+ != second.getEmergencyServiceCategoryBitmask()) {
+ return false;
+ }
+ if (!first.getEmergencyUrns().equals(second.getEmergencyUrns())) {
+ return false;
+ }
}
// Never merge two numbers if one of them is from test mode but the other one is not;
// This supports to remove a number from the test mode.
@@ -681,7 +727,7 @@
*/
public static EmergencyNumber mergeSameEmergencyNumbers(@NonNull EmergencyNumber first,
@NonNull EmergencyNumber second) {
- if (areSameEmergencyNumbers(first, second)) {
+ if (areSameEmergencyNumbers(first, second, false)) {
int routing = first.getEmergencyCallRouting();
if (second.isFromSources(EMERGENCY_NUMBER_SOURCE_DATABASE)) {
@@ -699,6 +745,115 @@
}
/**
+ * Get merged EmergencyUrns list from two same emergency numbers.
+ * By giving priority to the urns from first number.
+ *
+ * @param firstEmergencyUrns first number's Urns
+ * @param secondEmergencyUrns second number's Urns
+ * @return a merged Urns
+ *
+ * @hide
+ */
+ private static List<String> mergeEmergencyUrns(@NonNull List<String> firstEmergencyUrns,
+ @NonNull List<String> secondEmergencyUrns) {
+ List<String> mergedUrns = new ArrayList<String>();
+ mergedUrns.addAll(firstEmergencyUrns);
+ for (String urn : secondEmergencyUrns) {
+ if (!firstEmergencyUrns.contains(urn)) {
+ mergedUrns.add(urn);
+ }
+ }
+ return mergedUrns;
+ }
+
+ /**
+ * Get the highest precedence source of the given Emergency number. Then get service catergory
+ * and urns list fill in the respective map with key as source.
+ *
+ * @param num EmergencyNumber to get the source, service category & urns
+ * @param serviceCategoryArray Array to store the category of the given EmergencyNumber
+ * with key as highest precedence source
+ * @param urnsArray Array to store the list of Urns of the given EmergencyNumber
+ * with key as highest precedence source
+ *
+ * @hide
+ */
+ private static void fillServiceCategoryAndUrns(@NonNull EmergencyNumber num,
+ @NonNull SparseIntArray serviceCategoryArray,
+ @NonNull SparseArray<List<String>> urnsArray) {
+ int numberSrc = num.getEmergencyNumberSourceBitmask();
+ for (Integer source : EMERGENCY_NUMBER_SOURCE_PRECEDENCE) {
+ if ((numberSrc & source) == source) {
+ if (!num.isInEmergencyServiceCategories(EMERGENCY_SERVICE_CATEGORY_UNSPECIFIED)) {
+ serviceCategoryArray.put(source, num.getEmergencyServiceCategoryBitmask());
+ }
+ urnsArray.put(source, num.getEmergencyUrns());
+ break;
+ }
+ }
+ }
+
+ /**
+ * Get a merged EmergencyNumber from two same emergency numbers from
+ * Emergency number list. Two emergency numbers are the same if
+ * {@link #areSameEmergencyNumbers} returns {@code true}.
+ *
+ * @param first first EmergencyNumber to compare
+ * @param second second EmergencyNumber to compare
+ * @param mergeServiceCategoriesAndUrns {@code true} then determine service category and urns
+ * Service catetory : set from most precedence source number(N/W, SIM, DB, modem_cfg)
+ * Urns : merge from both with first priority from most precedence source number
+ * {@code false} then call {@link #mergeSameEmergencyNumbers} to merge.
+ * @return a merged EmergencyNumber or null if they are not the same EmergencyNumber
+ *
+ * @hide
+ */
+ public static @NonNull EmergencyNumber mergeSameEmergencyNumbers(
+ @NonNull EmergencyNumber first, @NonNull EmergencyNumber second,
+ boolean mergeServiceCategoriesAndUrns) {
+ if (!mergeServiceCategoriesAndUrns) {
+ return mergeSameEmergencyNumbers(first, second);
+ }
+
+ int routing = first.getEmergencyCallRouting();
+ int serviceCategory = first.getEmergencyServiceCategoryBitmask();
+ List<String> mergedEmergencyUrns = new ArrayList<String>();
+ //Maps to store the service category and urns of both the first and second emergency number
+ // with key as most precedent source
+ SparseIntArray serviceCategoryArray = new SparseIntArray(2);
+ SparseArray<List<String>> urnsArray = new SparseArray(2);
+
+ fillServiceCategoryAndUrns(first, serviceCategoryArray, urnsArray);
+ fillServiceCategoryAndUrns(second, serviceCategoryArray, urnsArray);
+
+ if (second.isFromSources(EMERGENCY_NUMBER_SOURCE_DATABASE)) {
+ routing = second.getEmergencyCallRouting();
+ }
+
+ // Determine serviceCategory of most precedence number
+ for (int sourceOfCategory : EMERGENCY_NUMBER_SOURCE_PRECEDENCE) {
+ if (serviceCategoryArray.indexOfKey(sourceOfCategory) >= 0) {
+ serviceCategory = serviceCategoryArray.get(sourceOfCategory);
+ break;
+ }
+ }
+
+ // Merge Urns in precedence number
+ for (int sourceOfUrn : EMERGENCY_NUMBER_SOURCE_PRECEDENCE) {
+ if (urnsArray.contains(sourceOfUrn)) {
+ mergedEmergencyUrns = mergeEmergencyUrns(mergedEmergencyUrns,
+ urnsArray.get(sourceOfUrn));
+ }
+ }
+
+ return new EmergencyNumber(first.getNumber(), first.getCountryIso(), first.getMnc(),
+ serviceCategory, mergedEmergencyUrns,
+ first.getEmergencyNumberSourceBitmask()
+ | second.getEmergencyNumberSourceBitmask(),
+ routing);
+ }
+
+ /**
* Validate Emergency Number address that only contains the dialable character
* {@link PhoneNumberUtils#isDialable(char)}
*
diff --git a/telephony/java/android/telephony/ims/feature/MmTelFeature.java b/telephony/java/android/telephony/ims/feature/MmTelFeature.java
index 1686f38..153a951 100644
--- a/telephony/java/android/telephony/ims/feature/MmTelFeature.java
+++ b/telephony/java/android/telephony/ims/feature/MmTelFeature.java
@@ -894,11 +894,12 @@
"android.telephony.ims.feature.extra.IS_UNKNOWN_CALL";
/** @hide */
- @IntDef(flag = true,
- value = {
- AUDIO_HANDLER_ANDROID,
- AUDIO_HANDLER_BASEBAND
- })
+ @IntDef(
+ prefix = "AUDIO_HANDLER_",
+ value = {
+ AUDIO_HANDLER_ANDROID,
+ AUDIO_HANDLER_BASEBAND
+ })
@Retention(RetentionPolicy.SOURCE)
public @interface ImsAudioHandler {}
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/LaunchAppShowImeAndDialogThemeAppTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/LaunchAppShowImeAndDialogThemeAppTest.kt
index da3c62d..cb530da 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/LaunchAppShowImeAndDialogThemeAppTest.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/LaunchAppShowImeAndDialogThemeAppTest.kt
@@ -16,7 +16,6 @@
package com.android.server.wm.flicker.ime
-import android.platform.test.annotations.Postsubmit
import android.platform.test.annotations.Presubmit
import android.view.WindowInsets.Type.ime
import android.view.WindowInsets.Type.navigationBars
@@ -64,16 +63,6 @@
transitions { testApp.dismissDialog(wmHelper) }
}
- /** {@inheritDoc} */
- @Postsubmit
- @Test
- override fun taskBarWindowIsAlwaysVisible() = super.taskBarWindowIsAlwaysVisible()
-
- /** {@inheritDoc} */
- @Postsubmit
- @Test
- override fun taskBarLayerIsVisibleAtStartAndEnd() = super.taskBarLayerIsVisibleAtStartAndEnd()
-
/** Checks that [ComponentNameMatcher.IME] layer becomes visible during the transition */
@Presubmit @Test fun imeWindowIsAlwaysVisible() = flicker.imeWindowIsAlwaysVisible()
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/OpenImeWindowFromFixedOrientationAppTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/OpenImeWindowFromFixedOrientationAppTest.kt
index c2526d3..0e732b5 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/OpenImeWindowFromFixedOrientationAppTest.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/OpenImeWindowFromFixedOrientationAppTest.kt
@@ -16,7 +16,7 @@
package com.android.server.wm.flicker.ime
-import android.platform.test.annotations.Postsubmit
+import android.platform.test.annotations.FlakyTest
import android.platform.test.annotations.Presubmit
import androidx.test.filters.RequiresDevice
import com.android.server.wm.flicker.BaseTest
@@ -68,25 +68,11 @@
teardown { imeTestApp.exit(wmHelper) }
}
- /** {@inheritDoc} */
- @Postsubmit
- @Test
- override fun navBarLayerIsVisibleAtStartAndEnd() = super.navBarLayerIsVisibleAtStartAndEnd()
-
- @Postsubmit
- @Test
- override fun navBarLayerPositionAtStartAndEnd() = super.navBarLayerPositionAtStartAndEnd()
-
- /** {@inheritDoc} */
- @Postsubmit
- @Test
- override fun taskBarLayerIsVisibleAtStartAndEnd() = super.taskBarLayerIsVisibleAtStartAndEnd()
-
@Presubmit @Test fun imeWindowBecomesVisible() = flicker.imeWindowBecomesVisible()
@Presubmit @Test fun imeLayerBecomesVisible() = flicker.imeLayerBecomesVisible()
- @Postsubmit
+ @FlakyTest(bugId = 240918620)
@Test
fun snapshotStartingWindowLayerCoversExactlyOnApp() {
Assume.assumeFalse(isShellTransitionsEnabled)
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/SwitchImeWindowsFromGestureNavTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/SwitchImeWindowsFromGestureNavTest.kt
index a6bbf54..477ddb3 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/SwitchImeWindowsFromGestureNavTest.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/SwitchImeWindowsFromGestureNavTest.kt
@@ -17,7 +17,6 @@
package com.android.server.wm.flicker.ime
import android.platform.test.annotations.FlakyTest
-import android.platform.test.annotations.Postsubmit
import android.platform.test.annotations.Presubmit
import androidx.test.filters.RequiresDevice
import com.android.server.wm.flicker.BaseTest
@@ -92,52 +91,10 @@
wmHelper.StateSyncBuilder().withFullScreenApp(imeTestApp).waitForAndVerify()
}
}
-
/** {@inheritDoc} */
- @Postsubmit
+ @FlakyTest(bugId = 265016201)
@Test
- override fun statusBarWindowIsAlwaysVisible() = super.statusBarWindowIsAlwaysVisible()
-
- /** {@inheritDoc} */
- @Postsubmit @Test override fun entireScreenCovered() = super.entireScreenCovered()
-
- /** {@inheritDoc} */
- @Postsubmit
- @Test
- override fun navBarLayerPositionAtStartAndEnd() = super.navBarLayerPositionAtStartAndEnd()
-
- /** {@inheritDoc} */
- @Postsubmit
- @Test
- override fun statusBarLayerIsVisibleAtStartAndEnd() =
- super.statusBarLayerIsVisibleAtStartAndEnd()
-
- /** {@inheritDoc} */
- @Postsubmit
- @Test
- override fun navBarLayerIsVisibleAtStartAndEnd() = super.navBarLayerIsVisibleAtStartAndEnd()
-
- /** {@inheritDoc} */
- @Postsubmit
- @Test
- override fun taskBarLayerIsVisibleAtStartAndEnd() = super.taskBarLayerIsVisibleAtStartAndEnd()
-
- /** {@inheritDoc} */
- @Postsubmit
- @Test
- override fun statusBarLayerPositionAtStartAndEnd() = super.statusBarLayerPositionAtStartAndEnd()
-
- /** {@inheritDoc} */
- @Postsubmit
- @Test
- override fun visibleLayersShownMoreThanOneConsecutiveEntry() =
- super.visibleLayersShownMoreThanOneConsecutiveEntry()
-
- /** {@inheritDoc} */
- @Postsubmit
- @Test
- override fun visibleWindowsShownMoreThanOneConsecutiveEntry() =
- super.visibleWindowsShownMoreThanOneConsecutiveEntry()
+ override fun entireScreenCovered() = super.entireScreenCovered()
@Presubmit
@Test
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/quickswitch/QuickSwitchBetweenTwoAppsBackTestCfArm.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/quickswitch/QuickSwitchBetweenTwoAppsBackTestCfArm.kt
new file mode 100644
index 0000000..e6cdd1e
--- /dev/null
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/quickswitch/QuickSwitchBetweenTwoAppsBackTestCfArm.kt
@@ -0,0 +1,45 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.wm.flicker.quickswitch
+
+import com.android.server.wm.flicker.FlickerTest
+import com.android.server.wm.flicker.FlickerTestFactory
+import com.android.server.wm.flicker.junit.FlickerParametersRunnerFactory
+import com.android.server.wm.traces.common.Rect
+import com.android.server.wm.traces.common.service.PlatformConsts
+import org.junit.FixMethodOrder
+import org.junit.runner.RunWith
+import org.junit.runners.MethodSorters
+import org.junit.runners.Parameterized
+
+@RunWith(Parameterized::class)
+@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
+@FixMethodOrder(MethodSorters.NAME_ASCENDING)
+class QuickSwitchBetweenTwoAppsBackTestCfArm(flicker: FlickerTest) :
+ QuickSwitchBetweenTwoAppsBackTest(flicker) {
+ companion object {
+ private var startDisplayBounds = Rect.EMPTY
+
+ @Parameterized.Parameters(name = "{0}")
+ @JvmStatic
+ fun getParams(): Collection<FlickerTest> {
+ return FlickerTestFactory.nonRotationTests(
+ supportedNavigationModes = listOf(PlatformConsts.NavBar.MODE_GESTURAL)
+ )
+ }
+ }
+}
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/quickswitch/QuickSwitchBetweenTwoAppsForwardTestCfArm.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/quickswitch/QuickSwitchBetweenTwoAppsForwardTestCfArm.kt
new file mode 100644
index 0000000..aa9adf0
--- /dev/null
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/quickswitch/QuickSwitchBetweenTwoAppsForwardTestCfArm.kt
@@ -0,0 +1,45 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.wm.flicker.quickswitch
+
+import com.android.server.wm.flicker.FlickerTest
+import com.android.server.wm.flicker.FlickerTestFactory
+import com.android.server.wm.flicker.junit.FlickerParametersRunnerFactory
+import com.android.server.wm.traces.common.Rect
+import com.android.server.wm.traces.common.service.PlatformConsts
+import org.junit.FixMethodOrder
+import org.junit.runner.RunWith
+import org.junit.runners.MethodSorters
+import org.junit.runners.Parameterized
+
+@RunWith(Parameterized::class)
+@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
+@FixMethodOrder(MethodSorters.NAME_ASCENDING)
+class QuickSwitchBetweenTwoAppsForwardTestCfArm(flicker: FlickerTest) :
+ QuickSwitchBetweenTwoAppsForwardTest(flicker) {
+ companion object {
+ private var startDisplayBounds = Rect.EMPTY
+
+ @Parameterized.Parameters(name = "{0}")
+ @JvmStatic
+ fun getParams(): Collection<FlickerTest> {
+ return FlickerTestFactory.nonRotationTests(
+ supportedNavigationModes = listOf(PlatformConsts.NavBar.MODE_GESTURAL)
+ )
+ }
+ }
+}
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/quickswitch/QuickSwitchFromLauncherTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/quickswitch/QuickSwitchFromLauncherTest.kt
index df91754..e06a8d6 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/quickswitch/QuickSwitchFromLauncherTest.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/quickswitch/QuickSwitchFromLauncherTest.kt
@@ -53,7 +53,7 @@
@RunWith(Parameterized::class)
@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
-class QuickSwitchFromLauncherTest(flicker: FlickerTest) : BaseTest(flicker) {
+open class QuickSwitchFromLauncherTest(flicker: FlickerTest) : BaseTest(flicker) {
private val testApp = SimpleAppHelper(instrumentation)
/** {@inheritDoc} */
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/quickswitch/QuickSwitchFromLauncherTestCfArm.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/quickswitch/QuickSwitchFromLauncherTestCfArm.kt
new file mode 100644
index 0000000..8b21603
--- /dev/null
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/quickswitch/QuickSwitchFromLauncherTestCfArm.kt
@@ -0,0 +1,44 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.wm.flicker.quickswitch
+
+import com.android.server.wm.flicker.FlickerTest
+import com.android.server.wm.flicker.FlickerTestFactory
+import com.android.server.wm.flicker.junit.FlickerParametersRunnerFactory
+import com.android.server.wm.traces.common.service.PlatformConsts
+import org.junit.FixMethodOrder
+import org.junit.runner.RunWith
+import org.junit.runners.MethodSorters
+import org.junit.runners.Parameterized
+
+@RunWith(Parameterized::class)
+@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
+@FixMethodOrder(MethodSorters.NAME_ASCENDING)
+open class QuickSwitchFromLauncherTestCfArm(flicker: FlickerTest) :
+ QuickSwitchFromLauncherTest(flicker) {
+ companion object {
+ @Parameterized.Parameters(name = "{0}")
+ @JvmStatic
+ fun getParams(): Collection<FlickerTest> {
+ return FlickerTestFactory.nonRotationTests(
+ supportedNavigationModes = listOf(PlatformConsts.NavBar.MODE_GESTURAL),
+ // TODO: Test with 90 rotation
+ supportedRotations = listOf(PlatformConsts.Rotation.ROTATION_0)
+ )
+ }
+ }
+}
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/rotation/ChangeAppRotationTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/rotation/ChangeAppRotationTest.kt
index 1b23952..8b250c3 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/rotation/ChangeAppRotationTest.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/rotation/ChangeAppRotationTest.kt
@@ -16,7 +16,6 @@
package com.android.server.wm.flicker.rotation
-import android.platform.test.annotations.FlakyTest
import android.platform.test.annotations.IwTest
import android.platform.test.annotations.Presubmit
import androidx.test.filters.RequiresDevice
@@ -121,11 +120,6 @@
rotationLayerAppearsAndVanishesAssertion()
}
- /** {@inheritDoc} */
- @FlakyTest(bugId = 206753786)
- @Test
- override fun navBarLayerPositionAtStartAndEnd() = super.navBarLayerPositionAtStartAndEnd()
-
@Test
@IwTest(focusArea = "framework")
override fun cujCompleted() {
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/rotation/SeamlessAppRotationTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/rotation/SeamlessAppRotationTest.kt
index c26485b..d76c94d 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/rotation/SeamlessAppRotationTest.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/rotation/SeamlessAppRotationTest.kt
@@ -16,7 +16,6 @@
package com.android.server.wm.flicker.rotation
-import android.platform.test.annotations.FlakyTest
import android.platform.test.annotations.IwTest
import android.platform.test.annotations.Presubmit
import android.view.WindowManager
@@ -201,11 +200,6 @@
flicker.assertEventLog { this.focusDoesNotChange() }
}
- /** {@inheritDoc} */
- @FlakyTest
- @Test
- override fun navBarLayerPositionAtStartAndEnd() = super.navBarLayerPositionAtStartAndEnd()
-
@Test
@IwTest(focusArea = "framework")
override fun cujCompleted() {
@@ -224,6 +218,7 @@
runAndIgnoreAssumptionViolation { appLayerAlwaysVisible() }
runAndIgnoreAssumptionViolation { navBarLayerIsVisibleAtStartAndEnd() }
runAndIgnoreAssumptionViolation { navBarWindowIsAlwaysVisible() }
+ runAndIgnoreAssumptionViolation { navBarLayerPositionAtStartAndEnd() }
runAndIgnoreAssumptionViolation { taskBarLayerIsVisibleAtStartAndEnd() }
runAndIgnoreAssumptionViolation { taskBarWindowIsAlwaysVisible() }
}
diff --git a/tests/Input/Android.bp b/tests/Input/Android.bp
index de9bbb6..83893ba 100644
--- a/tests/Input/Android.bp
+++ b/tests/Input/Android.bp
@@ -18,6 +18,7 @@
static_libs: [
"androidx.test.ext.junit",
"androidx.test.rules",
+ "mockito-target-minus-junit4",
"services.core.unboosted",
"testables",
"truth-prebuilt",
diff --git a/tests/Input/src/com/android/test/input/InputDeviceTest.java b/tests/Input/src/com/android/test/input/InputDeviceTest.java
index 797e818..ddcc811 100644
--- a/tests/Input/src/com/android/test/input/InputDeviceTest.java
+++ b/tests/Input/src/com/android/test/input/InputDeviceTest.java
@@ -69,7 +69,7 @@
}
private void assertInputDeviceParcelUnparcel(KeyCharacterMap keyCharacterMap) {
- final InputDevice device = new InputDevice.Builder()
+ final InputDevice.Builder deviceBuilder = new InputDevice.Builder()
.setId(DEVICE_ID)
.setGeneration(42)
.setControllerNumber(43)
@@ -88,8 +88,20 @@
.setHasBattery(true)
.setKeyboardLanguageTag("en-US")
.setKeyboardLayoutType("qwerty")
- .setSupportsUsi(true)
- .build();
+ .setSupportsUsi(true);
+
+ for (int i = 0; i < 30; i++) {
+ deviceBuilder.addMotionRange(
+ MotionEvent.AXIS_GENERIC_1,
+ InputDevice.SOURCE_UNKNOWN,
+ i,
+ i + 1,
+ i + 2,
+ i + 3,
+ i + 4);
+ }
+
+ final InputDevice device = deviceBuilder.build();
Parcel parcel = Parcel.obtain();
device.writeToParcel(parcel, 0);
diff --git a/tests/Input/src/com/android/test/input/MotionPredictorTest.kt b/tests/Input/src/com/android/test/input/MotionPredictorTest.kt
new file mode 100644
index 0000000..46aad9f
--- /dev/null
+++ b/tests/Input/src/com/android/test/input/MotionPredictorTest.kt
@@ -0,0 +1,138 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+
+package com.android.test.input
+
+import android.content.Context
+import android.content.res.Resources
+import android.os.SystemProperties
+import android.view.InputDevice
+import android.view.MotionEvent
+import android.view.MotionEvent.ACTION_DOWN
+import android.view.MotionEvent.ACTION_MOVE
+import android.view.MotionEvent.PointerCoords
+import android.view.MotionEvent.PointerProperties
+import android.view.MotionPredictor
+
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import androidx.test.filters.SmallTest
+import androidx.test.platform.app.InstrumentationRegistry
+
+import org.mockito.Mockito.mock
+import org.mockito.Mockito.`when`
+
+import org.junit.After
+import org.junit.Assert.assertEquals
+import org.junit.Assert.assertNotNull
+import org.junit.Before
+import org.junit.Test
+import org.junit.runner.RunWith
+
+import java.time.Duration
+
+private fun getStylusMotionEvent(
+ eventTime: Duration,
+ action: Int,
+ x: Float,
+ y: Float,
+ ): MotionEvent{
+ // One-time: send a DOWN event
+ val pointerCount = 1
+ val properties = arrayOfNulls<MotionEvent.PointerProperties>(pointerCount)
+ val coords = arrayOfNulls<MotionEvent.PointerCoords>(pointerCount)
+
+ for (i in 0 until pointerCount) {
+ properties[i] = PointerProperties()
+ properties[i]!!.id = i
+ properties[i]!!.toolType = MotionEvent.TOOL_TYPE_STYLUS
+ coords[i] = PointerCoords()
+ coords[i]!!.x = x
+ coords[i]!!.y = y
+ }
+
+ return MotionEvent.obtain(/*downTime=*/0, eventTime.toMillis(), action, properties.size,
+ properties, coords, /*metaState=*/0, /*buttonState=*/0,
+ /*xPrecision=*/0f, /*yPrecision=*/0f, /*deviceId=*/0, /*edgeFlags=*/0,
+ InputDevice.SOURCE_STYLUS, /*flags=*/0)
+}
+
+private fun getPredictionContext(offset: Duration, enablePrediction: Boolean): Context {
+ val context = mock(Context::class.java)
+ val resources: Resources = mock(Resources::class.java)
+ `when`(context.getResources()).thenReturn(resources)
+ `when`(resources.getInteger(
+ com.android.internal.R.integer.config_motionPredictionOffsetNanos)).thenReturn(
+ offset.toNanos().toInt())
+ `when`(resources.getBoolean(
+ com.android.internal.R.bool.config_enableMotionPrediction)).thenReturn(enablePrediction)
+ return context
+}
+
+@RunWith(AndroidJUnit4::class)
+@SmallTest
+class MotionPredictorTest {
+ private val instrumentation = InstrumentationRegistry.getInstrumentation()
+ val initialPropertyValue = SystemProperties.get("persist.input.enable_motion_prediction")
+
+ @Before
+ fun setUp() {
+ instrumentation.uiAutomation.executeShellCommand(
+ "setprop persist.input.enable_motion_prediction true")
+ }
+
+ @After
+ fun tearDown() {
+ instrumentation.uiAutomation.executeShellCommand(
+ "setprop persist.input.enable_motion_prediction $initialPropertyValue")
+ }
+
+ /**
+ * In a typical usage, app will send the event to the predictor and then call .predict to draw
+ * a prediction. Here, we send 2 events to the predictor and check the returned event.
+ * Input:
+ * t = 0 x = 0 y = 0
+ * t = 1 x = 1 y = 2
+ * Output (expected):
+ * t = 3 x = 3 y = 6
+ *
+ * Historical data is ignored for simplicity.
+ */
+ @Test
+ fun testPredictedCoordinatesAndTime() {
+ val context = getPredictionContext(
+ /*offset=*/Duration.ofMillis(1), /*enablePrediction=*/true)
+ val predictor = MotionPredictor(context)
+ var eventTime = Duration.ofMillis(0)
+ val downEvent = getStylusMotionEvent(eventTime, ACTION_DOWN, /*x=*/0f, /*y=*/0f)
+ // ACTION_DOWN t=0 x=0 y=0
+ predictor.record(downEvent)
+
+ eventTime += Duration.ofMillis(1)
+ val moveEvent = getStylusMotionEvent(eventTime, ACTION_MOVE, /*x=*/1f, /*y=*/2f)
+ // ACTION_MOVE t=1 x=1 y=2
+ predictor.record(moveEvent)
+
+ val predicted = predictor.predict(Duration.ofMillis(2).toNanos())
+ assertEquals(1, predicted.size)
+ val event = predicted[0]
+ assertNotNull(event)
+
+ // Prediction will happen for t=3 (2 + 1, since offset is 1 and present time is 2)
+ assertEquals(3, event.eventTime)
+ assertEquals(3f, event.x, /*delta=*/0.001f)
+ assertEquals(6f, event.y, /*delta=*/0.001f)
+ }
+}
diff --git a/tests/Internal/src/com/android/internal/app/OWNERS b/tests/Internal/src/com/android/internal/app/OWNERS
new file mode 100644
index 0000000..d55dc78
--- /dev/null
+++ b/tests/Internal/src/com/android/internal/app/OWNERS
@@ -0,0 +1,2 @@
+# Locale related test
+per-file *Locale* = file:/services/core/java/com/android/server/locales/OWNERS
diff --git a/tests/MotionPrediction/Android.bp b/tests/MotionPrediction/Android.bp
new file mode 100644
index 0000000..b9d01da
--- /dev/null
+++ b/tests/MotionPrediction/Android.bp
@@ -0,0 +1,31 @@
+//
+// Copyright (C) 2023 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+package {
+ // See: http://go/android-license-faq
+ // A large-scale-change added 'default_applicable_licenses' to import
+ // all of the 'license_kinds' from "frameworks_base_license"
+ // to get the below license kinds:
+ // SPDX-license-identifier-Apache-2.0
+ default_applicable_licenses: ["frameworks_base_license"],
+}
+
+android_app {
+ name: "MotionPrediction",
+ srcs: ["**/*.kt"],
+ platform_apis: true,
+ certificate: "platform",
+}
diff --git a/tests/MotionPrediction/AndroidManifest.xml b/tests/MotionPrediction/AndroidManifest.xml
new file mode 100644
index 0000000..3f8c2f2
--- /dev/null
+++ b/tests/MotionPrediction/AndroidManifest.xml
@@ -0,0 +1,34 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2023 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="test.motionprediction">
+
+ <application android:allowBackup="false"
+ android:icon="@mipmap/ic_launcher"
+ android:label="@string/app_name"
+ android:supportsRtl="true"
+ android:theme="@style/AppTheme">
+ <activity android:name=".MainActivity"
+ android:exported="true">
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="android.intent.category.LAUNCHER"/>
+ </intent-filter>
+ </activity>
+ </application>
+
+</manifest>
diff --git a/tests/MotionPrediction/OWNERS b/tests/MotionPrediction/OWNERS
new file mode 100644
index 0000000..c88bfe9
--- /dev/null
+++ b/tests/MotionPrediction/OWNERS
@@ -0,0 +1 @@
+include platform/frameworks/base:/INPUT_OWNERS
diff --git a/tests/MotionPrediction/res/layout/activity_main.xml b/tests/MotionPrediction/res/layout/activity_main.xml
new file mode 100644
index 0000000..65dc325
--- /dev/null
+++ b/tests/MotionPrediction/res/layout/activity_main.xml
@@ -0,0 +1,32 @@
+<?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:tools="http://schemas.android.com/tools"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:orientation="vertical"
+ android:paddingBottom="@dimen/activity_vertical_margin"
+ android:paddingLeft="@dimen/activity_horizontal_margin"
+ android:paddingRight="@dimen/activity_horizontal_margin"
+ android:paddingTop="@dimen/activity_vertical_margin"
+ tools:context="test.motionprediction.MainActivity">
+
+ <test.motionprediction.DrawingView
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:id="@+id/output" />
+
+</LinearLayout>
diff --git a/tests/MotionPrediction/res/mipmap-hdpi/ic_launcher.png b/tests/MotionPrediction/res/mipmap-hdpi/ic_launcher.png
new file mode 100644
index 0000000..cde69bc
--- /dev/null
+++ b/tests/MotionPrediction/res/mipmap-hdpi/ic_launcher.png
Binary files differ
diff --git a/tests/MotionPrediction/res/mipmap-mdpi/ic_launcher.png b/tests/MotionPrediction/res/mipmap-mdpi/ic_launcher.png
new file mode 100644
index 0000000..c133a0c
--- /dev/null
+++ b/tests/MotionPrediction/res/mipmap-mdpi/ic_launcher.png
Binary files differ
diff --git a/tests/MotionPrediction/res/mipmap-xhdpi/ic_launcher.png b/tests/MotionPrediction/res/mipmap-xhdpi/ic_launcher.png
new file mode 100644
index 0000000..bfa42f0
--- /dev/null
+++ b/tests/MotionPrediction/res/mipmap-xhdpi/ic_launcher.png
Binary files differ
diff --git a/tests/MotionPrediction/res/mipmap-xxhdpi/ic_launcher.png b/tests/MotionPrediction/res/mipmap-xxhdpi/ic_launcher.png
new file mode 100644
index 0000000..324e72c
--- /dev/null
+++ b/tests/MotionPrediction/res/mipmap-xxhdpi/ic_launcher.png
Binary files differ
diff --git a/tests/MotionPrediction/res/mipmap-xxxhdpi/ic_launcher.png b/tests/MotionPrediction/res/mipmap-xxxhdpi/ic_launcher.png
new file mode 100644
index 0000000..aee44e1
--- /dev/null
+++ b/tests/MotionPrediction/res/mipmap-xxxhdpi/ic_launcher.png
Binary files differ
diff --git a/tests/MotionPrediction/res/values-w820dp/dimens.xml b/tests/MotionPrediction/res/values-w820dp/dimens.xml
new file mode 100644
index 0000000..95669e6
--- /dev/null
+++ b/tests/MotionPrediction/res/values-w820dp/dimens.xml
@@ -0,0 +1,20 @@
+<!-- Copyright (C) 2023 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<resources>
+ <!-- Example customization of dimensions originally defined in res/values/dimens.xml
+ (such as screen margins) for screens with more than 820dp of available width. This
+ would include 7" and 10" devices in landscape (~960dp and ~1280dp respectively). -->
+ <dimen name="activity_horizontal_margin">64dp</dimen>
+</resources>
diff --git a/tests/MotionPrediction/res/values/colors.xml b/tests/MotionPrediction/res/values/colors.xml
new file mode 100644
index 0000000..139eb1d
--- /dev/null
+++ b/tests/MotionPrediction/res/values/colors.xml
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2023 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<resources>
+ <color name="colorPrimary">#3F51B5</color>
+ <color name="colorPrimaryDark">#303F9F</color>
+ <color name="colorAccent">#FF4081</color>
+</resources>
diff --git a/tests/MotionPrediction/res/values/dimens.xml b/tests/MotionPrediction/res/values/dimens.xml
new file mode 100644
index 0000000..d26136f
--- /dev/null
+++ b/tests/MotionPrediction/res/values/dimens.xml
@@ -0,0 +1,19 @@
+<!-- Copyright (C) 2023 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<resources>
+ <!-- Default screen margins, per the Android Design guidelines. -->
+ <dimen name="activity_horizontal_margin">16dp</dimen>
+ <dimen name="activity_vertical_margin">16dp</dimen>
+</resources>
diff --git a/tests/MotionPrediction/res/values/strings.xml b/tests/MotionPrediction/res/values/strings.xml
new file mode 100644
index 0000000..16a2bdf
--- /dev/null
+++ b/tests/MotionPrediction/res/values/strings.xml
@@ -0,0 +1,17 @@
+<!-- Copyright (C) 2023 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<resources>
+ <string name="app_name">Motion Prediction</string>
+</resources>
diff --git a/tests/MotionPrediction/res/values/styles.xml b/tests/MotionPrediction/res/values/styles.xml
new file mode 100644
index 0000000..cfb5e3d
--- /dev/null
+++ b/tests/MotionPrediction/res/values/styles.xml
@@ -0,0 +1,23 @@
+<!-- Copyright (C) 2023 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<resources>
+ <!-- Base application theme. -->
+ <style name="AppTheme" parent="@android:style/Theme.Material.Light.DarkActionBar">
+ <!-- Customize your theme here. -->
+ <item name="android:colorPrimary">@color/colorPrimary</item>
+ <item name="android:colorPrimaryDark">@color/colorPrimaryDark</item>
+ <item name="android:colorAccent">@color/colorAccent</item>
+ </style>
+</resources>
diff --git a/tests/MotionPrediction/src/test/motionprediction/DrawingView.kt b/tests/MotionPrediction/src/test/motionprediction/DrawingView.kt
new file mode 100644
index 0000000..f529bf7
--- /dev/null
+++ b/tests/MotionPrediction/src/test/motionprediction/DrawingView.kt
@@ -0,0 +1,106 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package test.motionprediction
+
+import android.content.Context
+import android.graphics.Canvas
+import android.graphics.Color
+import android.graphics.Paint
+import android.util.AttributeSet
+import android.view.MotionEvent
+import android.view.MotionEvent.ACTION_DOWN
+import android.view.MotionPredictor
+import android.view.View
+
+import java.util.Vector
+
+private fun drawLine(canvas: Canvas, from: MotionEvent, to: MotionEvent, paint: Paint) {
+ canvas.apply {
+ val x0 = from.getX()
+ val y0 = from.getY()
+ val x1 = to.getX()
+ val y1 = to.getY()
+ // TODO: handle historical data
+ drawLine(x0, y0, x1, y1, paint)
+ }
+}
+
+/**
+ * Draw the current stroke and predicted values
+ */
+class DrawingView(context: Context, attrs: AttributeSet) : View(context, attrs) {
+ private val TAG = "DrawingView"
+
+ val events: MutableMap<Int, Vector<MotionEvent>> = mutableMapOf<Int, Vector<MotionEvent>>()
+
+ var isPredictionAvailable = false
+ private val predictor = MotionPredictor(getContext())
+
+ private var predictionPaint = Paint()
+ private var realPaint = Paint()
+
+ init {
+ setBackgroundColor(Color.WHITE)
+ predictionPaint.color = Color.BLACK
+ predictionPaint.setStrokeWidth(5f)
+ realPaint.color = Color.RED
+ realPaint.setStrokeWidth(5f)
+ }
+
+ private fun addEvent(event: MotionEvent) {
+ if (event.getActionMasked() == ACTION_DOWN) {
+ events.remove(event.deviceId)
+ }
+ var vec = events.getOrPut(event.deviceId) { Vector<MotionEvent>() }
+ vec.add(MotionEvent.obtain(event))
+ predictor.record(event)
+ invalidate()
+ }
+
+ public override fun onTouchEvent(event: MotionEvent): Boolean {
+ isPredictionAvailable = predictor.isPredictionAvailable(event.getDeviceId(),
+ event.getSource())
+ addEvent(event)
+ return true
+ }
+
+ public override fun onDraw(canvas: Canvas) {
+ super.onDraw(canvas)
+ if (!isPredictionAvailable) {
+ canvas.apply {
+ drawRect(0f, 0f, 200f, 200f, realPaint)
+ }
+ }
+
+ var eventTime = 0L
+
+ // Draw real events
+ for ((_, vec) in events ) {
+ for (i in 1 until vec.size) {
+ drawLine(canvas, vec[i - 1], vec[i], realPaint)
+ }
+ eventTime = vec.lastElement().eventTime
+ }
+
+ // Draw predictions. Convert to nanos and hardcode to +20ms into the future
+ val predictionList = predictor.predict(eventTime * 1000000 + 20000000)
+ for (prediction in predictionList) {
+ val realEvents = events.get(prediction.deviceId)!!
+ drawLine(canvas, realEvents[realEvents.size - 1], prediction, predictionPaint)
+ }
+ }
+}
diff --git a/tests/MotionPrediction/src/test/motionprediction/MainActivity.kt b/tests/MotionPrediction/src/test/motionprediction/MainActivity.kt
new file mode 100644
index 0000000..cec2c06
--- /dev/null
+++ b/tests/MotionPrediction/src/test/motionprediction/MainActivity.kt
@@ -0,0 +1,29 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package test.motionprediction
+
+import android.app.Activity
+import android.os.Bundle
+
+class MainActivity : Activity() {
+ val TAG = "MotionPrediction"
+
+ override fun onCreate(savedInstanceState: Bundle?) {
+ super.onCreate(savedInstanceState)
+ setContentView(R.layout.activity_main)
+ }
+}
diff --git a/tests/StatusBar/src/com/android/statusbartest/NotificationTestList.java b/tests/StatusBar/src/com/android/statusbartest/NotificationTestList.java
index ef324e7..6c89e49 100644
--- a/tests/StatusBar/src/com/android/statusbartest/NotificationTestList.java
+++ b/tests/StatusBar/src/com/android/statusbartest/NotificationTestList.java
@@ -1156,12 +1156,12 @@
private PendingIntent makeIntent() {
Intent intent = new Intent(Intent.ACTION_MAIN);
intent.addCategory(Intent.CATEGORY_HOME);
- return PendingIntent.getActivity(this, 0, intent, PendingIntent.FLAG_MUTABLE_UNAUDITED);
+ return PendingIntent.getActivity(this, 0, intent, PendingIntent.FLAG_IMMUTABLE);
}
private PendingIntent makeIntent2() {
Intent intent = new Intent(this, StatusBarTest.class);
- return PendingIntent.getActivity(this, 0, intent, PendingIntent.FLAG_MUTABLE_UNAUDITED);
+ return PendingIntent.getActivity(this, 0, intent, PendingIntent.FLAG_IMMUTABLE);
}
diff --git a/tests/SurfaceControlViewHostTest/Android.bp b/tests/SurfaceControlViewHostTest/Android.bp
index 0127ba5..99567b9 100644
--- a/tests/SurfaceControlViewHostTest/Android.bp
+++ b/tests/SurfaceControlViewHostTest/Android.bp
@@ -25,7 +25,10 @@
android_test {
name: "SurfaceControlViewHostTest",
- srcs: ["**/*.java"],
+ srcs: [
+ "**/*.aidl",
+ "**/*.java",
+ ],
platform_apis: true,
certificate: "platform",
}
diff --git a/tests/SurfaceControlViewHostTest/AndroidManifest.xml b/tests/SurfaceControlViewHostTest/AndroidManifest.xml
index 7e9a04d..e50cbc5 100644
--- a/tests/SurfaceControlViewHostTest/AndroidManifest.xml
+++ b/tests/SurfaceControlViewHostTest/AndroidManifest.xml
@@ -24,6 +24,16 @@
<category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
+ <activity android:name="SurfaceControlViewHostSyncTest"
+ android:label="View Embedding Test Sync"
+ android:exported="true">
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="android.intent.category.LAUNCHER"/>
+ </intent-filter>
+ </activity>
+ <service android:name=".EmbeddedWindowService"
+ android:process="com.android.test.viewembed.embedded_process"/>
</application>
diff --git a/tests/SurfaceControlViewHostTest/src/com/android/test/viewembed/EmbeddedWindowService.java b/tests/SurfaceControlViewHostTest/src/com/android/test/viewembed/EmbeddedWindowService.java
new file mode 100644
index 0000000..abc15b4
--- /dev/null
+++ b/tests/SurfaceControlViewHostTest/src/com/android/test/viewembed/EmbeddedWindowService.java
@@ -0,0 +1,109 @@
+/*
+ * 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 com.android.test.viewembed;
+
+import static android.view.Display.DEFAULT_DISPLAY;
+import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION;
+
+import android.annotation.Nullable;
+import android.app.Service;
+import android.content.Context;
+import android.content.Intent;
+import android.graphics.Color;
+import android.graphics.PixelFormat;
+import android.hardware.display.DisplayManager;
+import android.os.Handler;
+import android.os.IBinder;
+import android.os.Looper;
+import android.os.RemoteException;
+import android.view.Display;
+import android.view.Gravity;
+import android.view.SurfaceControlViewHost;
+import android.view.WindowManager;
+import android.widget.FrameLayout;
+import android.widget.TextView;
+
+public class EmbeddedWindowService extends Service {
+ private static final String TAG = "EmbeddedWindowService";
+ private SurfaceControlViewHost mVr;
+
+ private Handler mHandler;
+
+ @Override
+ public void onCreate() {
+ super.onCreate();
+ mHandler = new Handler(Looper.getMainLooper());
+ }
+
+ @Nullable
+ @Override
+ public IBinder onBind(Intent intent) {
+ // Return the interface
+ return new AttachEmbeddedWindow();
+ }
+
+ public static class SlowView extends TextView {
+
+ public SlowView(Context context) {
+ super(context);
+ }
+
+ @Override
+ protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
+ super.onMeasure(widthMeasureSpec, heightMeasureSpec);
+ try {
+ Thread.sleep(250);
+ } catch (InterruptedException e) {
+ }
+ }
+ }
+
+ private class AttachEmbeddedWindow extends IAttachEmbeddedWindow.Stub {
+ @Override
+ public void attachEmbedded(IBinder hostToken, int width, int height,
+ IAttachEmbeddedWindowCallback callback) {
+ mHandler.post(() -> {
+ Context context = EmbeddedWindowService.this;
+ Display display = getApplicationContext().getSystemService(
+ DisplayManager.class).getDisplay(DEFAULT_DISPLAY);
+ mVr = new SurfaceControlViewHost(context, display, hostToken);
+ FrameLayout content = new FrameLayout(context);
+
+ SlowView slowView = new SlowView(context);
+ slowView.setText("INSIDE TEXT");
+ slowView.setGravity(Gravity.CENTER);
+ slowView.setTextColor(Color.BLACK);
+ slowView.setBackgroundColor(Color.CYAN);
+ content.addView(slowView);
+ WindowManager.LayoutParams lp =
+ new WindowManager.LayoutParams(width, height, TYPE_APPLICATION,
+ 0, PixelFormat.OPAQUE);
+ lp.setTitle("EmbeddedWindow");
+
+ mVr.setView(content, lp);
+ try {
+ callback.onEmbeddedWindowAttached(mVr.getSurfacePackage());
+ } catch (RemoteException e) {
+ }
+ });
+ }
+ @Override
+ public void relayout(WindowManager.LayoutParams lp) {
+ mHandler.post(() -> mVr.relayout(lp));
+ }
+ }
+}
diff --git a/tests/SurfaceControlViewHostTest/src/com/android/test/viewembed/IAttachEmbeddedWindow.aidl b/tests/SurfaceControlViewHostTest/src/com/android/test/viewembed/IAttachEmbeddedWindow.aidl
new file mode 100644
index 0000000..9e9faf0
--- /dev/null
+++ b/tests/SurfaceControlViewHostTest/src/com/android/test/viewembed/IAttachEmbeddedWindow.aidl
@@ -0,0 +1,26 @@
+/*
+ * 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 com.android.test.viewembed;
+
+import android.os.IBinder;
+import com.android.test.viewembed.IAttachEmbeddedWindowCallback;
+import android.view.WindowManager.LayoutParams;
+
+interface IAttachEmbeddedWindow {
+ void attachEmbedded(IBinder hostToken, int width, int height, in IAttachEmbeddedWindowCallback callback);
+ void relayout(in LayoutParams lp);
+}
\ No newline at end of file
diff --git a/tests/SurfaceControlViewHostTest/src/com/android/test/viewembed/IAttachEmbeddedWindowCallback.aidl b/tests/SurfaceControlViewHostTest/src/com/android/test/viewembed/IAttachEmbeddedWindowCallback.aidl
new file mode 100644
index 0000000..c45c24d
--- /dev/null
+++ b/tests/SurfaceControlViewHostTest/src/com/android/test/viewembed/IAttachEmbeddedWindowCallback.aidl
@@ -0,0 +1,23 @@
+/*
+ * 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 com.android.test.viewembed;
+
+import android.view.SurfaceControlViewHost.SurfacePackage;
+
+interface IAttachEmbeddedWindowCallback {
+ void onEmbeddedWindowAttached(in SurfacePackage surfacePackage);
+}
\ No newline at end of file
diff --git a/tests/SurfaceControlViewHostTest/src/com/android/test/viewembed/SurfaceControlViewHostSyncTest.java b/tests/SurfaceControlViewHostTest/src/com/android/test/viewembed/SurfaceControlViewHostSyncTest.java
new file mode 100644
index 0000000..ea727b9
--- /dev/null
+++ b/tests/SurfaceControlViewHostTest/src/com/android/test/viewembed/SurfaceControlViewHostSyncTest.java
@@ -0,0 +1,215 @@
+/*
+ * 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 com.android.test.viewembed;
+
+import android.app.Activity;
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.Intent;
+import android.content.ServiceConnection;
+import android.graphics.PixelFormat;
+import android.graphics.Point;
+import android.os.Bundle;
+import android.os.IBinder;
+import android.os.RemoteException;
+import android.util.Log;
+import android.view.Gravity;
+import android.view.SurfaceControlViewHost.SurfacePackage;
+import android.view.SurfaceHolder;
+import android.view.SurfaceView;
+import android.view.ViewGroup;
+import android.view.WindowManager;
+import android.widget.Button;
+import android.widget.FrameLayout;
+import android.widget.Switch;
+import android.window.SurfaceSyncGroup;
+
+public class SurfaceControlViewHostSyncTest extends Activity implements SurfaceHolder.Callback {
+ private static final String TAG = "SurfaceControlViewHostSyncTest";
+ private SurfaceView mSv;
+
+ private final Object mLock = new Object();
+ private boolean mIsAttached;
+ private boolean mSurfaceCreated;
+
+ private IAttachEmbeddedWindow mIAttachEmbeddedWindow;
+ private SurfacePackage mSurfacePackage;
+
+ private final Point[] mSizes = new Point[]{new Point(500, 500), new Point(700, 400),
+ new Point(300, 800), new Point(200, 200)};
+ private int mLastSizeIndex = 0;
+
+ private boolean mSync = true;
+
+ private final ServiceConnection mConnection = new ServiceConnection() {
+ // Called when the connection with the service is established
+ public void onServiceConnected(ComponentName className, IBinder service) {
+ Log.d(TAG, "Service Connected");
+ synchronized (mLock) {
+ mIAttachEmbeddedWindow = IAttachEmbeddedWindow.Stub.asInterface(service);
+ }
+ loadEmbedded();
+ }
+
+ public void onServiceDisconnected(ComponentName className) {
+ Log.d(TAG, "Service Disconnected");
+ mIAttachEmbeddedWindow = null;
+ }
+ };
+
+ protected void onCreate(Bundle savedInstanceState) {
+ FrameLayout content = new FrameLayout(this);
+ super.onCreate(savedInstanceState);
+ mSv = new SurfaceView(this);
+ Button button = new Button(this);
+ Switch enableSyncButton = new Switch(this);
+ content.addView(mSv, new FrameLayout.LayoutParams(
+ mSizes[0].x, mSizes[0].y, Gravity.CENTER_HORIZONTAL | Gravity.TOP));
+ content.addView(button, new FrameLayout.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT,
+ ViewGroup.LayoutParams.WRAP_CONTENT, Gravity.LEFT | Gravity.BOTTOM));
+ content.addView(enableSyncButton,
+ new FrameLayout.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT,
+ ViewGroup.LayoutParams.WRAP_CONTENT, Gravity.RIGHT | Gravity.BOTTOM));
+ setContentView(content);
+
+ mSv.setZOrderOnTop(false);
+ mSv.getHolder().addCallback(this);
+
+ button.setText("Change Size");
+ enableSyncButton.setText("Enable Sync");
+ enableSyncButton.setChecked(true);
+ button.setOnClickListener(v -> {
+ resize();
+ });
+
+ enableSyncButton.setOnCheckedChangeListener((buttonView, isChecked) -> {
+ mSync = isChecked;
+ });
+
+ Intent intent = new Intent(this, EmbeddedWindowService.class);
+ intent.setAction(IAttachEmbeddedWindow.class.getName());
+ Log.d(TAG, "bindService");
+ bindService(intent, mConnection, Context.BIND_AUTO_CREATE);
+ }
+
+ private void resize() {
+ if (mSurfacePackage == null) {
+ return;
+ }
+ Point size = mSizes[mLastSizeIndex % mSizes.length];
+
+ Runnable svResizeRunnable = () -> {
+ mSv.getLayoutParams().width = size.x;
+ mSv.getLayoutParams().height = size.y;
+ mSv.requestLayout();
+ };
+
+ Runnable resizeRunnable = () -> {
+ try {
+ final WindowManager.LayoutParams lp =
+ new WindowManager.LayoutParams(size.x, size.y,
+ WindowManager.LayoutParams.TYPE_APPLICATION, 0,
+ PixelFormat.TRANSPARENT);
+ mIAttachEmbeddedWindow.relayout(lp);
+ } catch (RemoteException e) {
+ }
+ };
+
+ if (mSync) {
+ SurfaceSyncGroup syncGroup = new SurfaceSyncGroup(TAG);
+ syncGroup.addToSync(getWindow().getRootSurfaceControl(), svResizeRunnable);
+ syncGroup.addToSync(mSurfacePackage, resizeRunnable);
+ syncGroup.markSyncReady();
+ } else {
+ svResizeRunnable.run();
+ resizeRunnable.run();
+ }
+
+ mLastSizeIndex++;
+ }
+
+ @Override
+ public void surfaceCreated(SurfaceHolder holder) {
+ synchronized (mLock) {
+ mSurfaceCreated = true;
+ }
+ attachEmbedded();
+ }
+
+ private boolean isReadyToAttach() {
+ synchronized (mLock) {
+ if (!mSurfaceCreated) {
+ Log.d(TAG, "surface is not created");
+ }
+ if (mIAttachEmbeddedWindow == null) {
+ Log.d(TAG, "Service is not attached");
+ }
+ if (mIsAttached) {
+ Log.d(TAG, "Already attached");
+ }
+
+ return mSurfaceCreated && mIAttachEmbeddedWindow != null && !mIsAttached
+ && mSurfacePackage != null;
+ }
+ }
+
+ private void loadEmbedded() {
+ try {
+ mIAttachEmbeddedWindow.attachEmbedded(mSv.getHostToken(), mSizes[0].x, mSizes[0].y,
+ new IAttachEmbeddedWindowCallback.Stub() {
+ @Override
+ public void onEmbeddedWindowAttached(SurfacePackage surfacePackage) {
+ getMainThreadHandler().post(() -> {
+ mSurfacePackage = surfacePackage;
+ attachEmbedded();
+ });
+ }
+ });
+ mLastSizeIndex++;
+ } catch (RemoteException e) {
+ }
+ }
+
+ private void attachEmbedded() {
+ if (!isReadyToAttach()) {
+ return;
+ }
+
+ synchronized (mLock) {
+ mIsAttached = true;
+ }
+ mSv.setChildSurfacePackage(mSurfacePackage);
+ }
+
+ @Override
+ public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
+ }
+
+ @Override
+ public void surfaceDestroyed(SurfaceHolder holder) {
+ synchronized (mLock) {
+ mSurfaceCreated = false;
+ }
+ }
+
+ @Override
+ protected void onStart() {
+ super.onStart();
+ Log.d(TAG, "onStart");
+ resize();
+ }
+}
diff --git a/tests/VectorDrawableTest/Android.bp b/tests/VectorDrawableTest/Android.bp
index 9da7c5f..099d874 100644
--- a/tests/VectorDrawableTest/Android.bp
+++ b/tests/VectorDrawableTest/Android.bp
@@ -26,5 +26,7 @@
android_test {
name: "VectorDrawableTest",
srcs: ["**/*.java"],
+ // certificate set as platform to allow testing of @hidden APIs
+ certificate: "platform",
platform_apis: true,
}
diff --git a/tests/VectorDrawableTest/AndroidManifest.xml b/tests/VectorDrawableTest/AndroidManifest.xml
index 5334dac..163e438 100644
--- a/tests/VectorDrawableTest/AndroidManifest.xml
+++ b/tests/VectorDrawableTest/AndroidManifest.xml
@@ -158,6 +158,15 @@
<category android:name="com.android.test.dynamic.TEST"/>
</intent-filter>
</activity>
+ <activity android:name="LottieDrawableTest"
+ android:label="Lottie test bed"
+ android:exported="true">
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN" />
+
+ <category android:name="com.android.test.dynamic.TEST" />
+ </intent-filter>
+ </activity>
</application>
</manifest>
diff --git a/tests/VectorDrawableTest/res/raw/lottie.json b/tests/VectorDrawableTest/res/raw/lottie.json
new file mode 100644
index 0000000..fea571c
--- /dev/null
+++ b/tests/VectorDrawableTest/res/raw/lottie.json
@@ -0,0 +1,123 @@
+{
+ "v":"4.6.9",
+ "fr":60,
+ "ip":0,
+ "op":200,
+ "w":800,
+ "h":600,
+ "nm":"Loader 1 JSON",
+ "ddd":0,
+
+
+ "layers":[
+ {
+ "ddd":0,
+ "ind":1,
+ "ty":4,
+ "nm":"Custom Path 1",
+ "ao": 0,
+ "ip": 0,
+ "op": 300,
+ "st": 0,
+ "sr": 1,
+ "bm": 0,
+ "ks": {
+ "o": { "a":0, "k":100 },
+ "r": { "a":1, "k": [
+ { "s": [ 0 ], "e": [ 360], "i": { "x":0.5, "y":0.5 }, "o": { "x":0.5, "y":0.5 }, "t": 0 },
+ { "t": 200 }
+ ] },
+ "p": { "a":0, "k":[ 300, 300, 0 ] },
+ "a": { "a":0, "k":[ 100, 100, 0 ] },
+ "s": { "a":1, "k":[
+ { "s": [ 100, 100 ], "e": [ 200, 200 ], "i": { "x":0.5, "y":0.5 }, "o": { "x":0.5, "y":0.5 }, "t": 0 },
+ { "s": [ 200, 200 ], "e": [ 100, 100 ], "i": { "x":0.5, "y":0.5 }, "o": { "x":0.5, "y":0.5 }, "t": 100 },
+ { "t": 200 }
+ ] }
+ },
+
+ "shapes":[
+ {
+ "ty":"gr",
+ "it":[
+ {
+ "ty" : "sh",
+ "nm" : "Path 1",
+ "ks" : {
+ "a" : 1,
+ "k" : [
+ {
+ "s": [ {
+ "i": [ [ 0, 50 ], [ -50, 0 ], [ 0, -50 ], [ 50, 0 ] ],
+ "o": [ [ 0, -50 ], [ 50, 0 ], [ 0, 50 ], [ -50, 0 ] ],
+ "v": [ [ 0, 100 ], [ 100, 0 ], [ 200, 100 ], [ 100, 200 ] ],
+ "c": true
+ } ],
+ "e": [ {
+ "i": [ [ 50, 50 ], [ -50, 0 ], [ -50, -50 ], [ 50, 50 ] ],
+ "o": [ [ 50, -50 ], [ 50, 0 ], [ -50, 50 ], [ -50, 50 ] ],
+ "v": [ [ 0, 100 ], [ 100, 0 ], [ 200, 100 ], [ 100, 200 ] ],
+ "c": true
+ } ],
+ "i": { "x":0.5, "y":0.5 },
+ "o": { "x":0.5, "y":0.5 },
+ "t": 0
+ },
+ {
+ "s": [ {
+ "i": [ [ 50, 50 ], [ -50, 0 ], [ -50, -50 ], [ 50, 50 ] ],
+ "o": [ [ 50, -50 ], [ 50, 0 ], [ -50, 50 ], [ -50, 50 ] ],
+ "v": [ [ 0, 100 ], [ 100, 0 ], [ 200, 100 ], [ 100, 200 ] ],
+ "c": true
+ } ],
+ "e": [ {
+ "i": [ [ 0, 50 ], [ -50, 0 ], [ 0, -50 ], [ 50, 0 ] ],
+ "o": [ [ 0, -50 ], [ 50, 0 ], [ 0, 50 ], [ -50, 0 ] ],
+ "v": [ [ 0, 100 ], [ 100, 0 ], [ 200, 100 ], [ 100, 200 ] ],
+ "c": true
+ } ],
+ "i": { "x":0.5, "y":0.5 },
+ "o": { "x":0.5, "y":0.5 },
+ "t": 100
+ },
+ {
+ "t": 200
+ }
+ ]
+ }
+ },
+
+ {
+ "ty": "st",
+ "nm": "Stroke 1",
+ "lc": 1,
+ "lj": 1,
+ "ml": 4,
+ "w" : { "a": 1, "k": [
+ { "s": [ 30 ], "e": [ 50 ], "i": { "x":0.5, "y":0.5 }, "o": { "x":0.5, "y":0.5 }, "t": 0 },
+ { "s": [ 50 ], "e": [ 30 ], "i": { "x":0.5, "y":0.5 }, "o": { "x":0.5, "y":0.5 }, "t": 100 },
+ { "t": 200 }
+ ] },
+ "o" : { "a": 0, "k": 100 },
+ "c" : { "a": 1, "k": [
+ { "s": [ 0, 1, 0 ], "e": [ 1, 0, 0 ], "i": { "x":0.5, "y":0.5 }, "o": { "x":0.5, "y":0.5 }, "t": 0 },
+ { "s": [ 1, 0, 0 ], "e": [ 0, 1, 0 ], "i": { "x":0.5, "y":0.5 }, "o": { "x":0.5, "y":0.5 }, "t": 100 },
+ { "t": 200 }
+ ] }
+ },
+
+ {
+ "ty":"tr",
+ "p" : { "a":0, "k":[ 0, 0 ] },
+ "a" : { "a":0, "k":[ 0, 0 ] },
+ "s" : { "a":0, "k":[ 100, 100 ] },
+ "r" : { "a":0, "k": 0 },
+ "o" : { "a":0, "k":100 },
+ "nm": "Transform"
+ }
+ ]
+ }
+ ]
+ }
+ ]
+ }
diff --git a/tests/VectorDrawableTest/src/com/android/test/dynamic/LottieDrawableTest.java b/tests/VectorDrawableTest/src/com/android/test/dynamic/LottieDrawableTest.java
new file mode 100644
index 0000000..05eae7b
--- /dev/null
+++ b/tests/VectorDrawableTest/src/com/android/test/dynamic/LottieDrawableTest.java
@@ -0,0 +1,76 @@
+/*
+ * 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 com.android.test.dynamic;
+
+import android.app.Activity;
+import android.content.Context;
+import android.graphics.Canvas;
+import android.graphics.Rect;
+import android.graphics.drawable.LottieDrawable;
+import android.os.Bundle;
+import android.view.View;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.Scanner;
+
+@SuppressWarnings({"UnusedDeclaration"})
+public class LottieDrawableTest extends Activity {
+ private static final String TAG = "LottieDrawableTest";
+ static final int BACKGROUND = 0xFFF44336;
+
+ class LottieDrawableView extends View {
+ private Rect mLottieBounds;
+
+ private LottieDrawable mLottie;
+
+ LottieDrawableView(Context context, InputStream is) {
+ super(context);
+ Scanner s = new Scanner(is).useDelimiter("\\A");
+ String json = s.hasNext() ? s.next() : "";
+ try {
+ mLottie = LottieDrawable.makeLottieDrawable(json);
+ } catch (IOException e) {
+ throw new RuntimeException(TAG + ": error parsing test Lottie");
+ }
+ mLottie.start();
+ }
+
+ @Override
+ protected void onDraw(Canvas canvas) {
+ canvas.drawColor(BACKGROUND);
+
+ mLottie.setBounds(mLottieBounds);
+ mLottie.draw(canvas);
+ }
+
+ public void setLottieSize(Rect bounds) {
+ mLottieBounds = bounds;
+ }
+ }
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+
+ InputStream is = getResources().openRawResource(R.raw.lottie);
+
+ LottieDrawableView view = new LottieDrawableView(this, is);
+ view.setLottieSize(new Rect(0, 0, 900, 900));
+ setContentView(view);
+ }
+}
diff --git a/tools/lint/common/src/main/java/com/google/android/lint/Constants.kt b/tools/lint/common/src/main/java/com/google/android/lint/Constants.kt
index 3d5d01c..0ef165f 100644
--- a/tools/lint/common/src/main/java/com/google/android/lint/Constants.kt
+++ b/tools/lint/common/src/main/java/com/google/android/lint/Constants.kt
@@ -35,6 +35,6 @@
Method(CLASS_ACTIVITY_MANAGER_INTERNAL, "enforceCallingPermission")
)
-const val ANNOTATION_PERMISSION_METHOD = "android.content.pm.PermissionMethod"
-const val ANNOTATION_PERMISSION_NAME = "android.content.pm.PermissionName"
+const val ANNOTATION_PERMISSION_METHOD = "android.annotation.PermissionMethod"
+const val ANNOTATION_PERMISSION_NAME = "android.annotation.PermissionName"
const val ANNOTATION_PERMISSION_RESULT = "android.content.pm.PackageManager.PermissionResult"