diff --git a/AconfigFlags.bp b/AconfigFlags.bp index 7977d73599e8f618e5a6e880ba1d336aed18e070..45e33ce4b6e93c9096b56bc273c4b3cc7f62024a 100644 --- a/AconfigFlags.bp +++ b/AconfigFlags.bp @@ -56,7 +56,6 @@ aconfig_declarations_group { "android.media.tv.flags-aconfig-java", "android.multiuser.flags-aconfig-java", "android.net.platform.flags-aconfig-java", - "android.net.vcn.flags-aconfig-java-export", "android.net.wifi.flags-aconfig-java", "android.nfc.flags-aconfig-java", "android.os.flags-aconfig-java", @@ -96,6 +95,7 @@ aconfig_declarations_group { "com.android.internal.foldables.flags-aconfig-java", "com.android.internal.os.flags-aconfig-java", "com.android.internal.pm.pkg.component.flags-aconfig-java", + "com.android.internal.widget.flags-aconfig-java", "com.android.media.flags.bettertogether-aconfig-java", "com.android.media.flags.editing-aconfig-java", "com.android.media.flags.performance-aconfig-java", @@ -280,6 +280,19 @@ java_aconfig_library { defaults: ["framework-minus-apex-aconfig-java-defaults"], } +aconfig_declarations { + name: "com.android.internal.widget.flags-aconfig", + package: "com.android.internal.widget.flags", + container: "system", + srcs: ["core/java/com/android/internal/widget/*.aconfig"], +} + +java_aconfig_library { + name: "com.android.internal.widget.flags-aconfig-java", + aconfig_declarations: "com.android.internal.widget.flags-aconfig", + defaults: ["framework-minus-apex-aconfig-java-defaults"], +} + // Text aconfig_declarations { name: "com.android.text.flags-aconfig", @@ -623,6 +636,11 @@ java_aconfig_library { defaults: ["framework-minus-apex-aconfig-java-defaults"], } +cc_aconfig_library { + name: "aconfig_hardware_flags_c_lib", + aconfig_declarations: "android.hardware.flags-aconfig", +} + // Widget aconfig_declarations { name: "android.widget.flags-aconfig", @@ -790,21 +808,6 @@ java_aconfig_library { defaults: ["framework-minus-apex-aconfig-java-defaults"], } -// OnDeviceIntelligence -aconfig_declarations { - name: "android.app.ondeviceintelligence-aconfig", - exportable: true, - package: "android.app.ondeviceintelligence.flags", - container: "system", - srcs: ["core/java/android/app/ondeviceintelligence/flags/ondevice_intelligence.aconfig"], -} - -java_aconfig_library { - name: "android.app.ondeviceintelligence-aconfig-java", - aconfig_declarations: "android.app.ondeviceintelligence-aconfig", - defaults: ["framework-minus-apex-aconfig-java-defaults"], -} - // Permissions aconfig_declarations { name: "android.permission.flags-aconfig", @@ -986,6 +989,11 @@ aconfig_declarations { java_aconfig_library { name: "android.app.flags-aconfig-java", aconfig_declarations: "android.app.flags-aconfig", + min_sdk_version: "34", + apex_available: [ + "//apex_available:platform", + "com.android.nfcservices", + ], defaults: ["framework-minus-apex-aconfig-java-defaults"], } @@ -1204,25 +1212,6 @@ java_aconfig_library { defaults: ["framework-minus-apex-aconfig-java-defaults"], } -// VCN -// TODO:376339506 Move the VCN code, the flag declaration and -// java_aconfig_library to framework-connectivity-b -aconfig_declarations { - name: "android.net.vcn.flags-aconfig", - package: "android.net.vcn", - container: "com.android.tethering", - exportable: true, - srcs: ["core/java/android/net/vcn/*.aconfig"], -} - -java_aconfig_library { - name: "android.net.vcn.flags-aconfig-java-export", - aconfig_declarations: "android.net.vcn.flags-aconfig", - mode: "exported", - min_sdk_version: "35", - defaults: ["framework-minus-apex-aconfig-java-defaults"], -} - // DevicePolicy aconfig_declarations { name: "device_policy_aconfig_flags", @@ -1239,6 +1228,17 @@ java_aconfig_library { defaults: ["framework-minus-apex-aconfig-java-defaults"], } +java_aconfig_library { + name: "device_policy_aconfig_flags_java_export", + aconfig_declarations: "device_policy_aconfig_flags", + defaults: ["framework-minus-apex-aconfig-java-defaults"], + min_sdk_version: "30", + apex_available: [ + "//apex_available:platform", + "com.android.permission", + ], +} + java_aconfig_library { name: "device_policy_aconfig_flags_lib_host", aconfig_declarations: "device_policy_aconfig_flags", @@ -1467,6 +1467,13 @@ java_aconfig_library { defaults: ["framework-minus-apex-aconfig-java-defaults"], } +java_aconfig_library { + name: "android.appwidget.flags-aconfig-java-host", + aconfig_declarations: "android.appwidget.flags-aconfig", + host_supported: true, + defaults: ["framework-minus-apex-aconfig-java-defaults"], +} + // App aconfig_declarations { name: "android.server.app.flags-aconfig", diff --git a/Android.bp b/Android.bp index 42028e010e8432de5a5b0e534034c5a958758f6b..529da53e58f72a2ee3277e0b42c0e9301e382b66 100644 --- a/Android.bp +++ b/Android.bp @@ -87,6 +87,7 @@ filegroup { ":framework-wifi-non-updatable-sources", ":PacProcessor-aidl-sources", ":ProxyHandler-aidl-sources", + ":vcn-utils-platform-sources", ":net-utils-framework-common-srcs", // AIDL from frameworks/base/native/ @@ -314,6 +315,7 @@ java_defaults { ":framework-telephony-sources", ":framework-wifi-annotations", ":framework-wifi-non-updatable-sources", + ":vcn-utils-platform-sources", ":PacProcessor-aidl-sources", ":ProxyHandler-aidl-sources", ":net-utils-framework-common-srcs", @@ -444,6 +446,9 @@ java_library { default: [ "framework-platformcrashrecovery.impl", ], + }) + select(release_flag("RELEASE_ONDEVICE_INTELLIGENCE_MODULE"), { + true: [], + default: ["framework-ondeviceintelligence-platform.impl"], }), sdk_version: "core_platform", installable: false, @@ -487,6 +492,7 @@ java_library { apex_available: ["//apex_available:platform"], visibility: [ "//frameworks/base:__subpackages__", + "//packages/modules/NeuralNetworks:__subpackages__", ], compile_dex: false, headers_only: true, @@ -582,6 +588,9 @@ java_library { default: [ "framework-platformcrashrecovery-compat-config", ], + }) + select(release_flag("RELEASE_ONDEVICE_INTELLIGENCE_MODULE"), { + true: [], + default: ["framework-ondeviceintelligence-platform-compat-config"], }), } @@ -596,7 +605,7 @@ filegroup { srcs: [ "core/java/com/android/internal/util/HexDump.java", "core/java/com/android/internal/util/WakeupMessage.java", - "core/java/android/net/vcn/util/PersistableBundleUtils.java", + "packages/Vcn/framework-b/src/android/net/vcn/util/PersistableBundleUtils.java", "telephony/java/android/telephony/Annotation.java", ], } diff --git a/apex/jobscheduler/service/aconfig/job.aconfig b/apex/jobscheduler/service/aconfig/job.aconfig index 810be8fc4220ef40157f2871e2433e34c7846c1a..fe95a59622f46febcedfda77e640a2601874b618 100644 --- a/apex/jobscheduler/service/aconfig/job.aconfig +++ b/apex/jobscheduler/service/aconfig/job.aconfig @@ -63,7 +63,7 @@ flag { name: "remove_user_during_user_switch" namespace: "backstage_power" description: "Remove started user if user will be stopped due to user switch" - bug: "321598070" + bug: "337077643" } flag { diff --git a/apex/jobscheduler/service/java/com/android/server/job/JobSchedulerService.java b/apex/jobscheduler/service/java/com/android/server/job/JobSchedulerService.java index a5a08fb9997c926570ce440e06a9a3d450b938d6..8fad79a845b4f93daac5e625acbdeb5c6f91e7db 100644 --- a/apex/jobscheduler/service/java/com/android/server/job/JobSchedulerService.java +++ b/apex/jobscheduler/service/java/com/android/server/job/JobSchedulerService.java @@ -1981,7 +1981,12 @@ public class JobSchedulerService extends com.android.server.SystemService jobStatus.getNumAppliedFlexibleConstraints(), jobStatus.getNumDroppedFlexibleConstraints(), jobStatus.getFilteredTraceTag(), - jobStatus.getFilteredDebugTags()); + jobStatus.getFilteredDebugTags(), + jobStatus.getNumAbandonedFailures(), + /* 0 is reserved for UNKNOWN_POLICY */ + jobStatus.getJob().getBackoffPolicy() + 1, + shouldUseAggressiveBackoff(jobStatus.getNumAbandonedFailures())); + // If the job is immediately ready to run, then we can just immediately // put it in the pending list and try to schedule it. This is especially @@ -2422,7 +2427,11 @@ public class JobSchedulerService extends com.android.server.SystemService cancelled.getNumAppliedFlexibleConstraints(), cancelled.getNumDroppedFlexibleConstraints(), cancelled.getFilteredTraceTag(), - cancelled.getFilteredDebugTags()); + cancelled.getFilteredDebugTags(), + cancelled.getNumAbandonedFailures(), + /* 0 is reserved for UNKNOWN_POLICY */ + cancelled.getJob().getBackoffPolicy() + 1, + shouldUseAggressiveBackoff(cancelled.getNumAbandonedFailures())); } // If this is a replacement, bring in the new version of the job if (incomingJob != null) { @@ -5917,9 +5926,6 @@ public class JobSchedulerService extends com.android.server.SystemService pw.print(Flags.FLAG_DO_NOT_FORCE_RUSH_EXECUTION_AT_BOOT, Flags.doNotForceRushExecutionAtBoot()); pw.println(); - pw.print(android.app.job.Flags.FLAG_BACKUP_JOBS_EXEMPTION, - android.app.job.Flags.backupJobsExemption()); - pw.println(); pw.print(android.app.job.Flags.FLAG_IGNORE_IMPORTANT_WHILE_FOREGROUND, android.app.job.Flags.ignoreImportantWhileForeground()); pw.println(); diff --git a/apex/jobscheduler/service/java/com/android/server/job/JobSchedulerShellCommand.java b/apex/jobscheduler/service/java/com/android/server/job/JobSchedulerShellCommand.java index f3bc9c747f170a020f6968d6e12cdf03b7941fba..42c8250a6185f33479403d33ac5650ba8b956556 100644 --- a/apex/jobscheduler/service/java/com/android/server/job/JobSchedulerShellCommand.java +++ b/apex/jobscheduler/service/java/com/android/server/job/JobSchedulerShellCommand.java @@ -433,9 +433,6 @@ public final class JobSchedulerShellCommand extends BasicShellCommandHandler { case com.android.server.job.Flags.FLAG_DO_NOT_FORCE_RUSH_EXECUTION_AT_BOOT: pw.println(com.android.server.job.Flags.doNotForceRushExecutionAtBoot()); break; - case android.app.job.Flags.FLAG_BACKUP_JOBS_EXEMPTION: - pw.println(android.app.job.Flags.backupJobsExemption()); - break; case android.app.job.Flags.FLAG_IGNORE_IMPORTANT_WHILE_FOREGROUND: pw.println(android.app.job.Flags.ignoreImportantWhileForeground()); break; 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 909a9b30ada46e5a880abef20ff78c2c42dbc5eb..2b401c8ff6b1581a37c48f4c767b468ef87e54c6 100644 --- a/apex/jobscheduler/service/java/com/android/server/job/JobServiceContext.java +++ b/apex/jobscheduler/service/java/com/android/server/job/JobServiceContext.java @@ -546,7 +546,11 @@ public final class JobServiceContext implements ServiceConnection { job.getNumAppliedFlexibleConstraints(), job.getNumDroppedFlexibleConstraints(), job.getFilteredTraceTag(), - job.getFilteredDebugTags()); + job.getFilteredDebugTags(), + job.getNumAbandonedFailures(), + /* 0 is reserved for UNKNOWN_POLICY */ + job.getJob().getBackoffPolicy() + 1, + mService.shouldUseAggressiveBackoff(job.getNumAbandonedFailures())); sEnqueuedJwiAtJobStart.logSampleWithUid(job.getUid(), job.getWorkCount()); final String sourcePackage = job.getSourcePackageName(); if (Trace.isTagEnabled(Trace.TRACE_TAG_SYSTEM_SERVER)) { @@ -1681,7 +1685,11 @@ public final class JobServiceContext implements ServiceConnection { completedJob.getNumAppliedFlexibleConstraints(), completedJob.getNumDroppedFlexibleConstraints(), completedJob.getFilteredTraceTag(), - completedJob.getFilteredDebugTags()); + completedJob.getFilteredDebugTags(), + completedJob.getNumAbandonedFailures(), + /* 0 is reserved for UNKNOWN_POLICY */ + completedJob.getJob().getBackoffPolicy() + 1, + mService.shouldUseAggressiveBackoff(completedJob.getNumAbandonedFailures())); if (Trace.isTagEnabled(Trace.TRACE_TAG_SYSTEM_SERVER)) { Trace.asyncTraceForTrackEnd(Trace.TRACE_TAG_SYSTEM_SERVER, JobSchedulerService.TRACE_TRACK_NAME, getId()); diff --git a/api/Android.bp b/api/Android.bp index 73262030ee379d63a9111deb0d3740efafca938e..14c2766d8887e393c58b21597489995afc77a1d8 100644 --- a/api/Android.bp +++ b/api/Android.bp @@ -105,6 +105,13 @@ combined_apis { default: [ "framework-platformcrashrecovery", ], + }) + select(release_flag("RELEASE_ONDEVICE_INTELLIGENCE_MODULE"), { + true: [ + "framework-ondeviceintelligence", + ], + default: [ + "framework-ondeviceintelligence-platform", + ], }) + select(release_flag("RELEASE_RANGING_STACK"), { true: [ "framework-ranging", @@ -119,7 +126,12 @@ combined_apis { "service-permission", "service-rkp", "service-sdksandbox", - ] + select(soong_config_variable("ANDROID", "release_crashrecovery_module"), { + ] + select(release_flag("RELEASE_ONDEVICE_INTELLIGENCE_MODULE"), { + true: [ + "service-ondeviceintelligence", + ], + default: [], + }) + select(soong_config_variable("ANDROID", "release_crashrecovery_module"), { "true": [ "service-crashrecovery", ], @@ -478,6 +490,7 @@ java_defaults { "//frameworks/base/location", "//frameworks/base/packages/CrashRecovery/framework", "//frameworks/base/nfc", + "//packages/modules/NeuralNetworks:__subpackages__", ], plugins: ["error_prone_android_framework"], errorprone: { diff --git a/api/api.go b/api/api.go index 5ca24de1b46acb29603439978194363f411eaeb7..e4d783eba4c335fc5080894c2d789f5576d6b985 100644 --- a/api/api.go +++ b/api/api.go @@ -29,6 +29,7 @@ const i18n = "i18n.module.public.api" const virtualization = "framework-virtualization" const location = "framework-location" const platformCrashrecovery = "framework-platformcrashrecovery" +const ondeviceintelligence = "framework-ondeviceintelligence-platform" var core_libraries_modules = []string{art, conscrypt, i18n} @@ -40,7 +41,7 @@ var core_libraries_modules = []string{art, conscrypt, i18n} // APIs. // In addition, the modules in this list are allowed to contribute to test APIs // stubs. -var non_updatable_modules = []string{virtualization, location, platformCrashrecovery} +var non_updatable_modules = []string{virtualization, location, platformCrashrecovery, ondeviceintelligence} // The intention behind this soong plugin is to generate a number of "merged" // API-related modules that would otherwise require a large amount of very diff --git a/boot/Android.bp b/boot/Android.bp index 6eead42a4d30e631bd79263d57f7787aba44ba58..eaa984ac0cddd6b11837b2c254393cc3a578ca05 100644 --- a/boot/Android.bp +++ b/boot/Android.bp @@ -31,6 +31,7 @@ soong_config_module_type { "car_bootclasspath_fragment", "nfc_apex_bootclasspath_fragment", "release_crashrecovery_module", + "release_ondevice_intelligence_module", "release_package_profiling_module", ], properties: [ @@ -176,6 +177,15 @@ custom_platform_bootclasspath { }, ], }, + release_ondevice_intelligence_module: { + fragments: [ + // only used when ondeviceintelligence is moved to neuralnetworks module + { + apex: "com.android.neuralnetworks", + module: "com.android.ondeviceintelligence-bootclasspath-fragment", + }, + ], + }, release_package_profiling_module: { fragments: [ // only used if profiling is enabled. diff --git a/cmds/idmap2/Android.bp b/cmds/idmap2/Android.bp index 58763a7f9aca07a550be705e8541f91ff090c37f..d9ff19051de9fbe70ef6de239b3d53e3dac73490 100644 --- a/cmds/idmap2/Android.bp +++ b/cmds/idmap2/Android.bp @@ -165,6 +165,7 @@ cc_test { ], host_supported: true, test_suites: ["general-tests"], + require_root: true, srcs: [ "tests/BinaryStreamVisitorTests.cpp", "tests/CommandLineOptionsTests.cpp", diff --git a/cmds/idmap2/libidmap2/ResourceContainer.cpp b/cmds/idmap2/libidmap2/ResourceContainer.cpp index 57ae3548123b738971ff1c70394e40f244fdd52a..f22a481c1f28f29a355bacdcbc3da25e67350759 100644 --- a/cmds/idmap2/libidmap2/ResourceContainer.cpp +++ b/cmds/idmap2/libidmap2/ResourceContainer.cpp @@ -22,6 +22,7 @@ #include #include +#include "android-base/scopeguard.h" #include "androidfw/ApkAssets.h" #include "androidfw/AssetManager.h" #include "androidfw/Util.h" @@ -269,27 +270,40 @@ struct ResState { std::unique_ptr am; ZipAssetsProvider* zip_assets; - static Result Initialize(std::unique_ptr zip, + static Result Initialize(std::unique_ptr&& zip, package_property_t flags) { ResState state; state.zip_assets = zip.get(); if ((state.apk_assets = ApkAssets::Load(std::move(zip), flags)) == nullptr) { - return Error("failed to load apk asset"); + return Error("failed to load apk asset for '%s'", + state.zip_assets->GetDebugName().c_str()); } + // Make sure we put ZipAssetsProvider where we took it if initialization fails, so the + // original object stays valid for any next call it may get. + auto scoped_restore_zip_assets = android::base::ScopeGuard([&zip, &state]() { + zip = std::unique_ptr( + static_cast( + std::move(const_cast(*state.apk_assets)).TakeAssetsProvider().release())); + }); + if ((state.arsc = state.apk_assets->GetLoadedArsc()) == nullptr) { - return Error("failed to retrieve loaded arsc"); + return Error("failed to retrieve loaded arsc for '%s'", + state.zip_assets->GetDebugName().c_str()); } if ((state.package = GetPackageAtIndex0(state.arsc)) == nullptr) { - return Error("failed to retrieve loaded package at index 0"); + return Error("failed to retrieve loaded package at index 0 for '%s'", + state.zip_assets->GetDebugName().c_str()); } state.am = std::make_unique(); if (!state.am->SetApkAssets({state.apk_assets}, false)) { - return Error("failed to create asset manager"); + return Error("failed to create asset manager for '%s'", + state.zip_assets->GetDebugName().c_str()); } + scoped_restore_zip_assets.Disable(); return state; } }; diff --git a/cmds/idmap2/tests/IdmapTests.cpp b/cmds/idmap2/tests/IdmapTests.cpp index 1b656e8c2088f3480b7251a5783ddb813b6ca7e5..7093614f40472811e7f9af1895c49eea562fc569 100644 --- a/cmds/idmap2/tests/IdmapTests.cpp +++ b/cmds/idmap2/tests/IdmapTests.cpp @@ -214,6 +214,20 @@ TEST(IdmapTests, CreateIdmapHeaderFromApkAssets) { ASSERT_EQ(idmap->GetHeader()->GetOverlayName(), TestConstants::OVERLAY_NAME_ALL_POLICIES); } +TEST(IdmapTests, TargetContainerWorksAfterError) { + auto target = TargetResourceContainer::FromPath(GetTestDataPath() + "/target/target-bad.apk"); + ASSERT_TRUE(target); + + auto crc = target->get()->GetCrc(); + ASSERT_TRUE(crc); + + // This call tries to construct the full ApkAssets state, and fails. + ASSERT_FALSE(target->get()->DefinesOverlayable()); + auto crc2 = target->get()->GetCrc(); + ASSERT_TRUE(crc2); + EXPECT_EQ(*crc, *crc2); +} + TEST(IdmapTests, CreateIdmapDataFromApkAssets) { std::string target_apk_path = GetTestDataPath() + "/target/target.apk"; std::string overlay_apk_path = GetTestDataPath() + "/overlay/overlay.apk"; diff --git a/cmds/idmap2/tests/data/target/target-bad.apk b/cmds/idmap2/tests/data/target/target-bad.apk new file mode 100644 index 0000000000000000000000000000000000000000..fd8678238c4d53383d12536df34e1e448a2d1332 Binary files /dev/null and b/cmds/idmap2/tests/data/target/target-bad.apk differ diff --git a/core/api/current.txt b/core/api/current.txt index d9338a5798299d2d63aa0fec181ab3af956518b1..5efa74779c06908da025e5eb3ab6c827371d6a6f 100644 --- a/core/api/current.txt +++ b/core/api/current.txt @@ -140,6 +140,7 @@ package android { field public static final String MANAGE_DEVICE_POLICY_ACROSS_USERS_SECURITY_CRITICAL = "android.permission.MANAGE_DEVICE_POLICY_ACROSS_USERS_SECURITY_CRITICAL"; field public static final String MANAGE_DEVICE_POLICY_AIRPLANE_MODE = "android.permission.MANAGE_DEVICE_POLICY_AIRPLANE_MODE"; field public static final String MANAGE_DEVICE_POLICY_APPS_CONTROL = "android.permission.MANAGE_DEVICE_POLICY_APPS_CONTROL"; + field @FlaggedApi("android.app.appfunctions.flags.enable_app_function_manager") public static final String MANAGE_DEVICE_POLICY_APP_FUNCTIONS = "android.permission.MANAGE_DEVICE_POLICY_APP_FUNCTIONS"; field public static final String MANAGE_DEVICE_POLICY_APP_RESTRICTIONS = "android.permission.MANAGE_DEVICE_POLICY_APP_RESTRICTIONS"; field public static final String MANAGE_DEVICE_POLICY_APP_USER_DATA = "android.permission.MANAGE_DEVICE_POLICY_APP_USER_DATA"; field public static final String MANAGE_DEVICE_POLICY_ASSIST_CONTENT = "android.permission.MANAGE_DEVICE_POLICY_ASSIST_CONTENT"; @@ -247,6 +248,7 @@ package android { field public static final String READ_BASIC_PHONE_STATE = "android.permission.READ_BASIC_PHONE_STATE"; field public static final String READ_CALENDAR = "android.permission.READ_CALENDAR"; field public static final String READ_CALL_LOG = "android.permission.READ_CALL_LOG"; + field @FlaggedApi("android.media.tv.flags.media_quality_fw") public static final String READ_COLOR_ZONES = "android.permission.READ_COLOR_ZONES"; field public static final String READ_CONTACTS = "android.permission.READ_CONTACTS"; field @FlaggedApi("com.android.server.feature.flags.enable_read_dropbox_permission") public static final String READ_DROPBOX_DATA = "android.permission.READ_DROPBOX_DATA"; field public static final String READ_EXTERNAL_STORAGE = "android.permission.READ_EXTERNAL_STORAGE"; @@ -2199,6 +2201,11 @@ package android { field @FlaggedApi("android.os.material_motion_tokens") public static final int config_motionStandardFastSpatialDamping; field @FlaggedApi("android.os.material_motion_tokens") public static final int config_motionStandardSlowEffectDamping; field @FlaggedApi("android.os.material_motion_tokens") public static final int config_motionStandardSlowSpatialDamping; + field @FlaggedApi("android.os.material_shape_tokens") public static final int config_shapeCornerRadiusLarge; + field @FlaggedApi("android.os.material_shape_tokens") public static final int config_shapeCornerRadiusMedium; + field @FlaggedApi("android.os.material_shape_tokens") public static final int config_shapeCornerRadiusSmall; + field @FlaggedApi("android.os.material_shape_tokens") public static final int config_shapeCornerRadiusXlarge; + field @FlaggedApi("android.os.material_shape_tokens") public static final int config_shapeCornerRadiusXsmall; field public static final int dialog_min_width_major = 17104899; // 0x1050003 field public static final int dialog_min_width_minor = 17104900; // 0x1050004 field public static final int notification_large_icon_height = 17104902; // 0x1050006 @@ -6475,6 +6482,7 @@ package android.app { method public String getSortKey(); method public long getTimeoutAfter(); method public boolean hasImage(); + method @FlaggedApi("android.app.api_rich_ongoing") public boolean hasPromotableCharacteristics(); method public void writeToParcel(android.os.Parcel, int); field public static final android.media.AudioAttributes AUDIO_ATTRIBUTES_DEFAULT; field public static final int BADGE_ICON_LARGE = 2; // 0x2 @@ -8073,6 +8081,7 @@ package android.app.admin { field public static final String ACCOUNT_MANAGEMENT_DISABLED_POLICY = "accountManagementDisabled"; field public static final String APPLICATION_HIDDEN_POLICY = "applicationHidden"; field public static final String APPLICATION_RESTRICTIONS_POLICY = "applicationRestrictions"; + field @FlaggedApi("android.app.appfunctions.flags.enable_app_function_manager") public static final String APP_FUNCTIONS_POLICY = "appFunctions"; field public static final String AUTO_TIMEZONE_POLICY = "autoTimezone"; field public static final String AUTO_TIME_POLICY = "autoTime"; field public static final String BACKUP_SERVICE_POLICY = "backupService"; @@ -8122,6 +8131,7 @@ package android.app.admin { method @NonNull public java.util.Set getAffiliationIds(@NonNull android.content.ComponentName); method @Nullable public java.util.Set getAlwaysOnVpnLockdownWhitelist(@NonNull android.content.ComponentName); method @Nullable public String getAlwaysOnVpnPackage(@NonNull android.content.ComponentName); + method @FlaggedApi("android.app.appfunctions.flags.enable_app_function_manager") @RequiresPermission(value=android.Manifest.permission.MANAGE_DEVICE_POLICY_APP_FUNCTIONS, conditional=true) public int getAppFunctionsPolicy(); method @NonNull @WorkerThread public android.os.Bundle getApplicationRestrictions(@Nullable android.content.ComponentName, String); method @Deprecated @Nullable public String getApplicationRestrictionsManagingPackage(@NonNull android.content.ComponentName); method @RequiresPermission(anyOf={android.Manifest.permission.SET_TIME, "android.permission.QUERY_ADMIN_POLICY"}, conditional=true) public boolean getAutoTimeEnabled(@Nullable android.content.ComponentName); @@ -8280,6 +8290,7 @@ package android.app.admin { method public void setAffiliationIds(@NonNull android.content.ComponentName, @NonNull java.util.Set); method public void setAlwaysOnVpnPackage(@NonNull android.content.ComponentName, @Nullable String, boolean) throws android.content.pm.PackageManager.NameNotFoundException; method public void setAlwaysOnVpnPackage(@NonNull android.content.ComponentName, @Nullable String, boolean, @Nullable java.util.Set) throws android.content.pm.PackageManager.NameNotFoundException; + method @FlaggedApi("android.app.appfunctions.flags.enable_app_function_manager") @RequiresPermission(value=android.Manifest.permission.MANAGE_DEVICE_POLICY_APP_FUNCTIONS, conditional=true) public void setAppFunctionsPolicy(int); method @RequiresPermission(value=android.Manifest.permission.MANAGE_DEVICE_POLICY_PACKAGE_STATE, conditional=true) public boolean setApplicationHidden(@Nullable android.content.ComponentName, String, boolean); method @WorkerThread public void setApplicationRestrictions(@Nullable android.content.ComponentName, String, android.os.Bundle); method @Deprecated public void setApplicationRestrictionsManagingPackage(@NonNull android.content.ComponentName, @Nullable String) throws android.content.pm.PackageManager.NameNotFoundException; @@ -8406,6 +8417,9 @@ package android.app.admin { field public static final String ACTION_SET_NEW_PASSWORD = "android.app.action.SET_NEW_PASSWORD"; field public static final String ACTION_START_ENCRYPTION = "android.app.action.START_ENCRYPTION"; field public static final String ACTION_SYSTEM_UPDATE_POLICY_CHANGED = "android.app.action.SYSTEM_UPDATE_POLICY_CHANGED"; + field @FlaggedApi("android.app.appfunctions.flags.enable_app_function_manager") public static final int APP_FUNCTIONS_DISABLED = 1; // 0x1 + field @FlaggedApi("android.app.appfunctions.flags.enable_app_function_manager") public static final int APP_FUNCTIONS_DISABLED_CROSS_PROFILE = 2; // 0x2 + field @FlaggedApi("android.app.appfunctions.flags.enable_app_function_manager") public static final int APP_FUNCTIONS_NOT_CONTROLLED_BY_POLICY = 0; // 0x0 field @FlaggedApi("android.app.admin.flags.set_auto_time_enabled_coexistence") public static final int AUTO_TIME_DISABLED = 1; // 0x1 field @FlaggedApi("android.app.admin.flags.set_auto_time_enabled_coexistence") public static final int AUTO_TIME_ENABLED = 2; // 0x2 field @FlaggedApi("android.app.admin.flags.set_auto_time_enabled_coexistence") public static final int AUTO_TIME_NOT_CONTROLLED_BY_POLICY = 0; // 0x0 @@ -8870,6 +8884,7 @@ package android.app.appfunctions { field public static final int ERROR_CATEGORY_UNKNOWN = 0; // 0x0 field public static final int ERROR_DENIED = 1000; // 0x3e8 field public static final int ERROR_DISABLED = 1002; // 0x3ea + field public static final int ERROR_ENTERPRISE_POLICY_DISALLOWED = 2002; // 0x7d2 field public static final int ERROR_FUNCTION_NOT_FOUND = 1003; // 0x3eb field public static final int ERROR_INVALID_ARGUMENT = 1001; // 0x3e9 field public static final int ERROR_SYSTEM_ERROR = 2000; // 0x7d0 @@ -17082,7 +17097,7 @@ package android.graphics { method public void arcTo(@NonNull android.graphics.RectF, float, float); method public void arcTo(float, float, float, float, float, float, boolean); method public void close(); - method @Deprecated public void computeBounds(@NonNull android.graphics.RectF, boolean); + method public void computeBounds(@NonNull android.graphics.RectF, boolean); method @FlaggedApi("com.android.graphics.flags.exact_compute_bounds") public void computeBounds(@NonNull android.graphics.RectF); method public void conicTo(float, float, float, float, float); method public void cubicTo(float, float, float, float, float, float); @@ -20809,6 +20824,7 @@ package android.hardware.display { method public int describeContents(); method @FlaggedApi("android.companion.virtualdevice.flags.device_aware_display_power") @FloatRange(from=0.0f, to=1.0f) public float getDefaultBrightness(); method public int getDensityDpi(); + method @FlaggedApi("android.companion.virtualdevice.flags.device_aware_display_power") @FloatRange(from=0.0f, to=1.0f) public float getDimBrightness(); method @NonNull public java.util.Set getDisplayCategories(); method public int getFlags(); method public int getHeight(); @@ -20830,6 +20846,7 @@ package android.hardware.display { method @NonNull public android.hardware.display.VirtualDisplayConfig build(); method @FlaggedApi("android.companion.virtualdevice.flags.device_aware_display_power") @NonNull public android.hardware.display.VirtualDisplayConfig.Builder setBrightnessListener(@NonNull java.util.concurrent.Executor, @NonNull android.hardware.display.VirtualDisplayConfig.BrightnessListener); method @FlaggedApi("android.companion.virtualdevice.flags.device_aware_display_power") @NonNull public android.hardware.display.VirtualDisplayConfig.Builder setDefaultBrightness(@FloatRange(from=0.0f, to=1.0f) float); + method @FlaggedApi("android.companion.virtualdevice.flags.device_aware_display_power") @NonNull public android.hardware.display.VirtualDisplayConfig.Builder setDimBrightness(@FloatRange(from=0.0f, to=1.0f) float); method @NonNull public android.hardware.display.VirtualDisplayConfig.Builder setDisplayCategories(@NonNull java.util.Set); method @NonNull public android.hardware.display.VirtualDisplayConfig.Builder setFlags(int); method @NonNull public android.hardware.display.VirtualDisplayConfig.Builder setRequestedRefreshRate(@FloatRange(from=0.0f) float); @@ -21778,6 +21795,18 @@ package android.media { field public static final int ENCODING_DTS_UHD_P2 = 30; // 0x1e field public static final int ENCODING_E_AC3 = 6; // 0x6 field public static final int ENCODING_E_AC3_JOC = 18; // 0x12 + field @FlaggedApi("android.media.audio.iamf_definitions_api") public static final int ENCODING_IAMF_BASE_ENHANCED_PROFILE_AAC = 42; // 0x2a + field @FlaggedApi("android.media.audio.iamf_definitions_api") public static final int ENCODING_IAMF_BASE_ENHANCED_PROFILE_FLAC = 43; // 0x2b + field @FlaggedApi("android.media.audio.iamf_definitions_api") public static final int ENCODING_IAMF_BASE_ENHANCED_PROFILE_OPUS = 41; // 0x29 + field @FlaggedApi("android.media.audio.iamf_definitions_api") public static final int ENCODING_IAMF_BASE_ENHANCED_PROFILE_PCM = 44; // 0x2c + field @FlaggedApi("android.media.audio.iamf_definitions_api") public static final int ENCODING_IAMF_BASE_PROFILE_AAC = 38; // 0x26 + field @FlaggedApi("android.media.audio.iamf_definitions_api") public static final int ENCODING_IAMF_BASE_PROFILE_FLAC = 39; // 0x27 + field @FlaggedApi("android.media.audio.iamf_definitions_api") public static final int ENCODING_IAMF_BASE_PROFILE_OPUS = 37; // 0x25 + field @FlaggedApi("android.media.audio.iamf_definitions_api") public static final int ENCODING_IAMF_BASE_PROFILE_PCM = 40; // 0x28 + field @FlaggedApi("android.media.audio.iamf_definitions_api") public static final int ENCODING_IAMF_SIMPLE_PROFILE_AAC = 34; // 0x22 + field @FlaggedApi("android.media.audio.iamf_definitions_api") public static final int ENCODING_IAMF_SIMPLE_PROFILE_FLAC = 35; // 0x23 + field @FlaggedApi("android.media.audio.iamf_definitions_api") public static final int ENCODING_IAMF_SIMPLE_PROFILE_OPUS = 33; // 0x21 + field @FlaggedApi("android.media.audio.iamf_definitions_api") public static final int ENCODING_IAMF_SIMPLE_PROFILE_PCM = 36; // 0x24 field public static final int ENCODING_IEC61937 = 13; // 0xd field public static final int ENCODING_INVALID = 0; // 0x0 field public static final int ENCODING_MP3 = 9; // 0x9 @@ -24899,7 +24928,7 @@ package android.media { method @Nullable public android.net.Uri getIconUri(); method @NonNull public String getId(); method @NonNull public CharSequence getName(); - method @FlaggedApi("com.android.media.flags.enable_route_visibility_control_api") @NonNull public java.util.Set getRequiredPermissions(); + method @FlaggedApi("com.android.media.flags.enable_route_visibility_control_api") @NonNull public java.util.List> getRequiredPermissions(); method @FlaggedApi("com.android.media.flags.enable_built_in_speaker_route_suitability_statuses") public int getSuitabilityStatus(); method @FlaggedApi("com.android.media.flags.enable_mirroring_in_media_router_2") public int getSupportedRoutingTypes(); method public int getType(); @@ -24969,6 +24998,7 @@ package android.media { method @NonNull public android.media.MediaRoute2Info.Builder setExtras(@Nullable android.os.Bundle); method @NonNull public android.media.MediaRoute2Info.Builder setIconUri(@Nullable android.net.Uri); method @FlaggedApi("com.android.media.flags.enable_route_visibility_control_api") @NonNull public android.media.MediaRoute2Info.Builder setRequiredPermissions(@NonNull java.util.Set); + method @FlaggedApi("com.android.media.flags.enable_route_visibility_control_api") @NonNull public android.media.MediaRoute2Info.Builder setRequiredPermissions(@NonNull java.util.List>); method @FlaggedApi("com.android.media.flags.enable_built_in_speaker_route_suitability_statuses") @NonNull public android.media.MediaRoute2Info.Builder setSuitabilityStatus(int); method @FlaggedApi("com.android.media.flags.enable_mirroring_in_media_router_2") @NonNull public android.media.MediaRoute2Info.Builder setSupportedRoutingTypes(int); method @NonNull public android.media.MediaRoute2Info.Builder setType(int); @@ -27140,6 +27170,15 @@ package android.media.projection { package android.media.quality { + @FlaggedApi("android.media.tv.flags.media_quality_fw") public final class ActiveProcessingPicture implements android.os.Parcelable { + ctor public ActiveProcessingPicture(int, @NonNull String); + method public int describeContents(); + method public int getId(); + method @NonNull public String getProfileId(); + method public void writeToParcel(@NonNull android.os.Parcel, int); + field @NonNull public static final android.os.Parcelable.Creator CREATOR; + } + @FlaggedApi("android.media.tv.flags.media_quality_fw") public final class AmbientBacklightEvent implements android.os.Parcelable { ctor public AmbientBacklightEvent(int, @Nullable android.media.quality.AmbientBacklightMetadata); method public int describeContents(); @@ -27158,10 +27197,10 @@ package android.media.quality { method public int describeContents(); method public int getColorFormat(); method public int getCompressAlgorithm(); - method @IntRange(from=0) public int getHorizontalZonesNumber(); + method @IntRange(from=0, to=128) public int getHorizontalZonesNumber(); method @NonNull public String getPackageName(); method public int getSource(); - method @IntRange(from=0) public int getVerticalZonesNumber(); + method @IntRange(from=0, to=80) public int getVerticalZonesNumber(); method @NonNull public int[] getZonesColors(); method public void writeToParcel(@NonNull android.os.Parcel, int); field @NonNull public static final android.os.Parcelable.Creator CREATOR; @@ -27191,8 +27230,30 @@ package android.media.quality { } public static final class MediaQualityContract.PictureQuality { + field public static final String PARAMETER_AUTO_PICTURE_QUALITY_ENABLED = "auto_picture_quality_enabled"; + field public static final String PARAMETER_AUTO_SUPER_RESOLUTION_ENABLED = "auto_super_resolution_enabled"; + field public static final String PARAMETER_BLUE_STRETCH = "blue_stretch"; field public static final String PARAMETER_BRIGHTNESS = "brightness"; + field public static final String PARAMETER_COLOR_TEMPERATURE = "color_temperature"; + field public static final String PARAMETER_COLOR_TUNE = "color_tune"; + field public static final String PARAMETER_COLOR_TUNER_BLUE_GAIN = "color_tuner_blue_gain"; + field public static final String PARAMETER_COLOR_TUNER_BLUE_OFFSET = "color_tuner_blue_offset"; + field public static final String PARAMETER_COLOR_TUNER_BRIGHTNESS = "color_tuner_brightness"; + field public static final String PARAMETER_COLOR_TUNER_GREEN_GAIN = "color_tuner_green_gain"; + field public static final String PARAMETER_COLOR_TUNER_GREEN_OFFSET = "color_tuner_green_offset"; + field public static final String PARAMETER_COLOR_TUNER_HUE = "color_tuner_hue"; + field public static final String PARAMETER_COLOR_TUNER_RED_GAIN = "color_tuner_red_gain"; + field public static final String PARAMETER_COLOR_TUNER_RED_OFFSET = "color_tuner_red_offset"; + field public static final String PARAMETER_COLOR_TUNER_SATURATION = "color_tuner_saturation"; field public static final String PARAMETER_CONTRAST = "contrast"; + field public static final String PARAMETER_DECONTOUR = "decontour"; + field public static final String PARAMETER_DYNAMIC_LUMA_CONTROL = "dynamic_luma_control"; + field public static final String PARAMETER_FILM_MODE = "film_mode"; + field public static final String PARAMETER_FLESH_TONE = "flesh_tone"; + field public static final String PARAMETER_GLOBAL_DIMMING = "global_dimming"; + field public static final String PARAMETER_HUE = "hue"; + field public static final String PARAMETER_MPEG_NOISE_REDUCTION = "mpeg_noise_reduction"; + field public static final String PARAMETER_NOISE_REDUCTION = "noise_reduction"; field public static final String PARAMETER_SATURATION = "saturation"; field public static final String PARAMETER_SHARPNESS = "sharpness"; } @@ -27204,13 +27265,14 @@ package android.media.quality { } @FlaggedApi("android.media.tv.flags.media_quality_fw") public final class MediaQualityManager { + method public void addActiveProcessingPictureListener(@NonNull java.util.concurrent.Executor, @NonNull android.media.quality.MediaQualityManager.ActiveProcessingPictureListener); method public void createPictureProfile(@NonNull android.media.quality.PictureProfile); method public void createSoundProfile(@NonNull android.media.quality.SoundProfile); - method @NonNull public java.util.List getAvailablePictureProfiles(); - method @NonNull public java.util.List getAvailableSoundProfiles(); + method @NonNull public java.util.List getAvailablePictureProfiles(boolean); + method @NonNull public java.util.List getAvailableSoundProfiles(boolean); method @NonNull public java.util.List getParamCapabilities(@NonNull java.util.List); - method @Nullable public android.media.quality.PictureProfile getPictureProfile(int, @NonNull String); - method @Nullable public android.media.quality.SoundProfile getSoundProfile(int, @NonNull String); + method @Nullable public android.media.quality.PictureProfile getPictureProfile(int, @NonNull String, boolean); + method @Nullable public android.media.quality.SoundProfile getSoundProfile(int, @NonNull String, boolean); method public boolean isAmbientBacklightEnabled(); method public boolean isAutoPictureQualityEnabled(); method public boolean isAutoSoundQualityEnabled(); @@ -27218,6 +27280,7 @@ package android.media.quality { method public void registerAmbientBacklightCallback(@NonNull java.util.concurrent.Executor, @NonNull android.media.quality.MediaQualityManager.AmbientBacklightCallback); method public void registerPictureProfileCallback(@NonNull java.util.concurrent.Executor, @NonNull android.media.quality.MediaQualityManager.PictureProfileCallback); method public void registerSoundProfileCallback(@NonNull java.util.concurrent.Executor, @NonNull android.media.quality.MediaQualityManager.SoundProfileCallback); + method public void removeActiveProcessingPictureListener(@NonNull android.media.quality.MediaQualityManager.ActiveProcessingPictureListener); method public void removePictureProfile(@NonNull String); method public void removeSoundProfile(@NonNull String); method public void setAmbientBacklightEnabled(boolean); @@ -27229,6 +27292,10 @@ package android.media.quality { method public void updateSoundProfile(@NonNull String, @NonNull android.media.quality.SoundProfile); } + public static interface MediaQualityManager.ActiveProcessingPictureListener { + method public void onActiveProcessingPicturesChanged(@NonNull java.util.List); + } + public abstract static class MediaQualityManager.AmbientBacklightCallback { ctor public MediaQualityManager.AmbientBacklightCallback(); method public void onAmbientBacklightEvent(@NonNull android.media.quality.AmbientBacklightEvent); @@ -27236,7 +27303,7 @@ package android.media.quality { public abstract static class MediaQualityManager.PictureProfileCallback { ctor public MediaQualityManager.PictureProfileCallback(); - method public void onError(int); + method public void onError(@Nullable String, int); method public void onParamCapabilitiesChanged(@Nullable String, @NonNull java.util.List); method public void onPictureProfileAdded(@NonNull String, @NonNull android.media.quality.PictureProfile); method public void onPictureProfileRemoved(@NonNull String, @NonNull android.media.quality.PictureProfile); @@ -27245,7 +27312,7 @@ package android.media.quality { public abstract static class MediaQualityManager.SoundProfileCallback { ctor public MediaQualityManager.SoundProfileCallback(); - method public void onError(int); + method public void onError(@Nullable String, int); method public void onParamCapabilitiesChanged(@Nullable String, @NonNull java.util.List); method public void onSoundProfileAdded(@NonNull String, @NonNull android.media.quality.SoundProfile); method public void onSoundProfileRemoved(@NonNull String, @NonNull android.media.quality.SoundProfile); @@ -30132,128 +30199,6 @@ package android.net.sip { } -package android.net.vcn { - - public final class VcnCellUnderlyingNetworkTemplate extends android.net.vcn.VcnUnderlyingNetworkTemplate { - method public int getCbs(); - method public int getDun(); - method public int getIms(); - method public int getInternet(); - method public int getMms(); - method @NonNull public java.util.Set getOperatorPlmnIds(); - method public int getOpportunistic(); - method public int getRcs(); - method public int getRoaming(); - method @NonNull public java.util.Set getSimSpecificCarrierIds(); - } - - public static final class VcnCellUnderlyingNetworkTemplate.Builder { - ctor public VcnCellUnderlyingNetworkTemplate.Builder(); - method @NonNull public android.net.vcn.VcnCellUnderlyingNetworkTemplate build(); - method @NonNull public android.net.vcn.VcnCellUnderlyingNetworkTemplate.Builder setCbs(int); - method @NonNull public android.net.vcn.VcnCellUnderlyingNetworkTemplate.Builder setDun(int); - method @NonNull public android.net.vcn.VcnCellUnderlyingNetworkTemplate.Builder setIms(int); - method @NonNull public android.net.vcn.VcnCellUnderlyingNetworkTemplate.Builder setInternet(int); - method @NonNull public android.net.vcn.VcnCellUnderlyingNetworkTemplate.Builder setMetered(int); - method @NonNull public android.net.vcn.VcnCellUnderlyingNetworkTemplate.Builder setMinDownstreamBandwidthKbps(int, int); - method @NonNull public android.net.vcn.VcnCellUnderlyingNetworkTemplate.Builder setMinUpstreamBandwidthKbps(int, int); - method @NonNull public android.net.vcn.VcnCellUnderlyingNetworkTemplate.Builder setMms(int); - method @NonNull public android.net.vcn.VcnCellUnderlyingNetworkTemplate.Builder setOperatorPlmnIds(@NonNull java.util.Set); - method @NonNull public android.net.vcn.VcnCellUnderlyingNetworkTemplate.Builder setOpportunistic(int); - method @NonNull public android.net.vcn.VcnCellUnderlyingNetworkTemplate.Builder setRcs(int); - method @NonNull public android.net.vcn.VcnCellUnderlyingNetworkTemplate.Builder setRoaming(int); - method @NonNull public android.net.vcn.VcnCellUnderlyingNetworkTemplate.Builder setSimSpecificCarrierIds(@NonNull java.util.Set); - } - - public final class VcnConfig implements android.os.Parcelable { - method public int describeContents(); - method @NonNull public java.util.Set getGatewayConnectionConfigs(); - method @NonNull public java.util.Set getRestrictedUnderlyingNetworkTransports(); - method public void writeToParcel(@NonNull android.os.Parcel, int); - field @NonNull public static final android.os.Parcelable.Creator CREATOR; - } - - public static final class VcnConfig.Builder { - ctor public VcnConfig.Builder(@NonNull android.content.Context); - method @NonNull public android.net.vcn.VcnConfig.Builder addGatewayConnectionConfig(@NonNull android.net.vcn.VcnGatewayConnectionConfig); - method @NonNull public android.net.vcn.VcnConfig build(); - method @NonNull public android.net.vcn.VcnConfig.Builder setRestrictedUnderlyingNetworkTransports(@NonNull java.util.Set); - } - - public final class VcnGatewayConnectionConfig { - method @NonNull public int[] getExposedCapabilities(); - method @NonNull public String getGatewayConnectionName(); - method @IntRange(from=0x500) public int getMaxMtu(); - method public int getMinUdpPort4500NatTimeoutSeconds(); - method @NonNull public long[] getRetryIntervalsMillis(); - method @NonNull public java.util.List getVcnUnderlyingNetworkPriorities(); - method public boolean hasGatewayOption(int); - method @FlaggedApi("android.net.vcn.safe_mode_config") public boolean isSafeModeEnabled(); - field @FlaggedApi("android.net.vcn.mainline_vcn_module_api") public static final int MIN_UDP_PORT_4500_NAT_TIMEOUT_UNSET = -1; // 0xffffffff - field public static final int VCN_GATEWAY_OPTION_ENABLE_DATA_STALL_RECOVERY_WITH_MOBILITY = 0; // 0x0 - } - - public static final class VcnGatewayConnectionConfig.Builder { - ctor public VcnGatewayConnectionConfig.Builder(@NonNull String, @NonNull android.net.ipsec.ike.IkeTunnelConnectionParams); - method @NonNull public android.net.vcn.VcnGatewayConnectionConfig.Builder addExposedCapability(int); - method @NonNull public android.net.vcn.VcnGatewayConnectionConfig.Builder addGatewayOption(int); - method @NonNull public android.net.vcn.VcnGatewayConnectionConfig build(); - method @NonNull public android.net.vcn.VcnGatewayConnectionConfig.Builder removeExposedCapability(int); - method @NonNull public android.net.vcn.VcnGatewayConnectionConfig.Builder removeGatewayOption(int); - method @NonNull public android.net.vcn.VcnGatewayConnectionConfig.Builder setMaxMtu(@IntRange(from=0x500) int); - method @NonNull public android.net.vcn.VcnGatewayConnectionConfig.Builder setMinUdpPort4500NatTimeoutSeconds(@IntRange(from=0x78) int); - method @NonNull public android.net.vcn.VcnGatewayConnectionConfig.Builder setRetryIntervalsMillis(@NonNull long[]); - method @FlaggedApi("android.net.vcn.safe_mode_config") @NonNull public android.net.vcn.VcnGatewayConnectionConfig.Builder setSafeModeEnabled(boolean); - method @NonNull public android.net.vcn.VcnGatewayConnectionConfig.Builder setVcnUnderlyingNetworkPriorities(@NonNull java.util.List); - } - - public class VcnManager { - method @RequiresPermission("carrier privileges") public void clearVcnConfig(@NonNull android.os.ParcelUuid) throws java.io.IOException; - method @NonNull public java.util.List getConfiguredSubscriptionGroups(); - method public void registerVcnStatusCallback(@NonNull android.os.ParcelUuid, @NonNull java.util.concurrent.Executor, @NonNull android.net.vcn.VcnManager.VcnStatusCallback); - method @RequiresPermission("carrier privileges") public void setVcnConfig(@NonNull android.os.ParcelUuid, @NonNull android.net.vcn.VcnConfig) throws java.io.IOException; - method public void unregisterVcnStatusCallback(@NonNull android.net.vcn.VcnManager.VcnStatusCallback); - field public static final int VCN_ERROR_CODE_CONFIG_ERROR = 1; // 0x1 - field public static final int VCN_ERROR_CODE_INTERNAL_ERROR = 0; // 0x0 - field public static final int VCN_ERROR_CODE_NETWORK_ERROR = 2; // 0x2 - field public static final int VCN_STATUS_CODE_ACTIVE = 2; // 0x2 - field public static final int VCN_STATUS_CODE_INACTIVE = 1; // 0x1 - field public static final int VCN_STATUS_CODE_NOT_CONFIGURED = 0; // 0x0 - field public static final int VCN_STATUS_CODE_SAFE_MODE = 3; // 0x3 - } - - public abstract static class VcnManager.VcnStatusCallback { - ctor public VcnManager.VcnStatusCallback(); - method public abstract void onGatewayConnectionError(@NonNull String, int, @Nullable Throwable); - method public abstract void onStatusChanged(int); - } - - public abstract class VcnUnderlyingNetworkTemplate { - method public int getMetered(); - method public int getMinEntryDownstreamBandwidthKbps(); - method public int getMinEntryUpstreamBandwidthKbps(); - method public int getMinExitDownstreamBandwidthKbps(); - method public int getMinExitUpstreamBandwidthKbps(); - field public static final int MATCH_ANY = 0; // 0x0 - field public static final int MATCH_FORBIDDEN = 2; // 0x2 - field public static final int MATCH_REQUIRED = 1; // 0x1 - } - - public final class VcnWifiUnderlyingNetworkTemplate extends android.net.vcn.VcnUnderlyingNetworkTemplate { - method @NonNull public java.util.Set getSsids(); - } - - public static final class VcnWifiUnderlyingNetworkTemplate.Builder { - ctor public VcnWifiUnderlyingNetworkTemplate.Builder(); - method @NonNull public android.net.vcn.VcnWifiUnderlyingNetworkTemplate build(); - method @NonNull public android.net.vcn.VcnWifiUnderlyingNetworkTemplate.Builder setMetered(int); - method @NonNull public android.net.vcn.VcnWifiUnderlyingNetworkTemplate.Builder setMinDownstreamBandwidthKbps(int, int); - method @NonNull public android.net.vcn.VcnWifiUnderlyingNetworkTemplate.Builder setMinUpstreamBandwidthKbps(int, int); - method @NonNull public android.net.vcn.VcnWifiUnderlyingNetworkTemplate.Builder setSsids(@NonNull java.util.Set); - } - -} - package android.opengl { public class EGL14 { @@ -34820,7 +34765,10 @@ package android.os { method public android.os.MessageQueue getMessageQueue(); method public boolean hasMessages(android.os.Handler, Object, int); method public boolean hasMessages(android.os.Handler, Object, Runnable); + method @FlaggedApi("android.os.message_queue_testability") public boolean isBlockedOnSyncBarrier(); method public android.os.Message next(); + method @FlaggedApi("android.os.message_queue_testability") @Nullable public Long peekWhen(); + method @FlaggedApi("android.os.message_queue_testability") @Nullable public android.os.Message poll(); method public void recycle(android.os.Message); method public void release(); } @@ -40873,8 +40821,10 @@ package android.security.keystore { method @NonNull public java.util.List getGrantedCertificateChainFromId(long) throws android.security.keystore.KeyPermanentlyInvalidatedException, java.security.UnrecoverableKeyException; method @NonNull public java.security.Key getGrantedKeyFromId(long) throws android.security.keystore.KeyPermanentlyInvalidatedException, java.security.UnrecoverableKeyException; method @NonNull public java.security.KeyPair getGrantedKeyPairFromId(long) throws android.security.keystore.KeyPermanentlyInvalidatedException, java.security.UnrecoverableKeyException; + method @FlaggedApi("android.security.keystore2.attest_modules") @NonNull public byte[] getSupplementaryAttestationInfo(int) throws android.security.KeyStoreException; method public long grantKeyAccess(@NonNull String, int) throws android.security.KeyStoreException, java.security.UnrecoverableKeyException; method public void revokeKeyAccess(@NonNull String, int) throws android.security.KeyStoreException, java.security.UnrecoverableKeyException; + field public static final int MODULE_HASH = -1879047468; // 0x900002d4 } public class SecureKeyImportUnavailableException extends java.security.ProviderException { @@ -40930,13 +40880,14 @@ package android.service.autofill { public abstract class AutofillService extends android.app.Service { ctor public AutofillService(); - method @Nullable public final android.service.autofill.FillEventHistory getFillEventHistory(); + method @Deprecated @FlaggedApi("android.service.autofill.autofill_session_destroyed") @Nullable public final android.service.autofill.FillEventHistory getFillEventHistory(); method public final android.os.IBinder onBind(android.content.Intent); method public void onConnected(); method public void onDisconnected(); method public abstract void onFillRequest(@NonNull android.service.autofill.FillRequest, @NonNull android.os.CancellationSignal, @NonNull android.service.autofill.FillCallback); method public abstract void onSaveRequest(@NonNull android.service.autofill.SaveRequest, @NonNull android.service.autofill.SaveCallback); method public void onSavedDatasetsInfoRequest(@NonNull android.service.autofill.SavedDatasetsInfoCallback); + method @FlaggedApi("android.service.autofill.autofill_session_destroyed") public void onSessionDestroyed(@Nullable android.service.autofill.FillEventHistory); field public static final String EXTRA_FILL_RESPONSE = "android.service.autofill.extra.FILL_RESPONSE"; field public static final String SERVICE_INTERFACE = "android.service.autofill.AutofillService"; field public static final String SERVICE_META_DATA = "android.autofill"; @@ -41097,7 +41048,7 @@ package android.service.autofill { field public static final int TYPE_DATASET_SELECTED = 0; // 0x0 field public static final int TYPE_SAVE_SHOWN = 3; // 0x3 field public static final int TYPE_VIEW_REQUESTED_AUTOFILL = 6; // 0x6 - field @FlaggedApi("android.service.autofill.autofill_w_metrics") public static final int UI_TYPE_CREDMAN = 4; // 0x4 + field @FlaggedApi("android.service.autofill.autofill_w_metrics") public static final int UI_TYPE_CREDENTIAL_MANAGER = 4; // 0x4 field public static final int UI_TYPE_DIALOG = 3; // 0x3 field public static final int UI_TYPE_INLINE = 2; // 0x2 field public static final int UI_TYPE_MENU = 1; // 0x1 @@ -42666,9 +42617,10 @@ package android.service.settings.preferences { method public boolean isWritable(); method public void writeToParcel(@NonNull android.os.Parcel, int); field @NonNull public static final android.os.Parcelable.Creator CREATOR; - field public static final int INTENT_ONLY = 2; // 0x2 - field public static final int NOT_SENSITIVE = 0; // 0x0 - field public static final int SENSITIVE = 1; // 0x1 + field public static final int EXPECT_POST_CONFIRMATION = 1; // 0x1 + field public static final int EXPECT_PRE_CONFIRMATION = 2; // 0x2 + field public static final int NO_DIRECT_ACCESS = 3; // 0x3 + field public static final int NO_SENSITIVITY = 0; // 0x0 } public static final class SettingsPreferenceMetadata.Builder { @@ -44936,11 +44888,11 @@ package android.telephony { field public static final String KEY_CARRIER_VVM_PACKAGE_NAME_STRING_ARRAY = "carrier_vvm_package_name_string_array"; field public static final String KEY_CARRIER_WFC_IMS_AVAILABLE_BOOL = "carrier_wfc_ims_available_bool"; field public static final String KEY_CARRIER_WFC_SUPPORTS_WIFI_ONLY_BOOL = "carrier_wfc_supports_wifi_only_bool"; - field public static final String KEY_CDMA_3WAYCALL_FLASH_DELAY_INT = "cdma_3waycall_flash_delay_int"; - field public static final String KEY_CDMA_DTMF_TONE_DELAY_INT = "cdma_dtmf_tone_delay_int"; - field public static final String KEY_CDMA_NONROAMING_NETWORKS_STRING_ARRAY = "cdma_nonroaming_networks_string_array"; - field public static final String KEY_CDMA_ROAMING_MODE_INT = "cdma_roaming_mode_int"; - field public static final String KEY_CDMA_ROAMING_NETWORKS_STRING_ARRAY = "cdma_roaming_networks_string_array"; + field @Deprecated @FlaggedApi("com.android.internal.telephony.flags.deprecate_cdma") public static final String KEY_CDMA_3WAYCALL_FLASH_DELAY_INT = "cdma_3waycall_flash_delay_int"; + field @Deprecated @FlaggedApi("com.android.internal.telephony.flags.deprecate_cdma") public static final String KEY_CDMA_DTMF_TONE_DELAY_INT = "cdma_dtmf_tone_delay_int"; + field @Deprecated @FlaggedApi("com.android.internal.telephony.flags.deprecate_cdma") public static final String KEY_CDMA_NONROAMING_NETWORKS_STRING_ARRAY = "cdma_nonroaming_networks_string_array"; + field @Deprecated @FlaggedApi("com.android.internal.telephony.flags.deprecate_cdma") public static final String KEY_CDMA_ROAMING_MODE_INT = "cdma_roaming_mode_int"; + field @Deprecated @FlaggedApi("com.android.internal.telephony.flags.deprecate_cdma") public static final String KEY_CDMA_ROAMING_NETWORKS_STRING_ARRAY = "cdma_roaming_networks_string_array"; field public static final String KEY_CELLULAR_SERVICE_CAPABILITIES_INT_ARRAY = "cellular_service_capabilities_int_array"; field public static final String KEY_CELLULAR_USAGE_SETTING_INT = "cellular_usage_setting_int"; field public static final String KEY_CHECK_PRICING_WITH_CARRIER_FOR_DATA_ROAMING_BOOL = "check_pricing_with_carrier_data_roaming_bool"; @@ -44967,7 +44919,7 @@ package android.telephony { field public static final String KEY_DEFAULT_VM_NUMBER_ROAMING_AND_IMS_UNREGISTERED_STRING = "default_vm_number_roaming_and_ims_unregistered_string"; field public static final String KEY_DEFAULT_VM_NUMBER_STRING = "default_vm_number_string"; field public static final String KEY_DIAL_STRING_REPLACE_STRING_ARRAY = "dial_string_replace_string_array"; - field public static final String KEY_DISABLE_CDMA_ACTIVATION_CODE_BOOL = "disable_cdma_activation_code_bool"; + field @Deprecated @FlaggedApi("com.android.internal.telephony.flags.deprecate_cdma") public static final String KEY_DISABLE_CDMA_ACTIVATION_CODE_BOOL = "disable_cdma_activation_code_bool"; field public static final String KEY_DISABLE_CHARGE_INDICATION_BOOL = "disable_charge_indication_bool"; field @FlaggedApi("com.android.internal.telephony.flags.satellite_system_apis") public static final String KEY_DISABLE_DUN_APN_WHILE_ROAMING_WITH_PRESET_APN_BOOL = "disable_dun_apn_while_roaming_with_preset_apn_bool"; field public static final String KEY_DISABLE_SUPPLEMENTARY_SERVICES_IN_AIRPLANE_MODE_BOOL = "disable_supplementary_services_in_airplane_mode_bool"; @@ -45088,6 +45040,7 @@ package android.telephony { field public static final String KEY_RCS_CONFIG_SERVER_URL_STRING = "rcs_config_server_url_string"; field public static final String KEY_READ_ONLY_APN_FIELDS_STRING_ARRAY = "read_only_apn_fields_string_array"; field public static final String KEY_READ_ONLY_APN_TYPES_STRING_ARRAY = "read_only_apn_types_string_array"; + field @FlaggedApi("com.android.internal.telephony.flags.satellite_system_apis") public static final String KEY_REGIONAL_SATELLITE_EARFCN_BUNDLE = "regional_satellite_earfcn_bundle"; field @FlaggedApi("com.android.internal.telephony.flags.satellite_system_apis") public static final String KEY_REMOVE_SATELLITE_PLMN_IN_MANUAL_NETWORK_SCAN_BOOL = "remove_satellite_plmn_in_manual_network_scan_bool"; field public static final String KEY_REQUIRE_ENTITLEMENT_CHECKS_BOOL = "require_entitlement_checks_bool"; field @Deprecated public static final String KEY_RESTART_RADIO_ON_PDP_FAIL_REGULAR_DEACTIVATION_BOOL = "restart_radio_on_pdp_fail_regular_deactivation_bool"; @@ -45101,6 +45054,7 @@ package android.telephony { field @FlaggedApi("com.android.internal.telephony.flags.carrier_enabled_satellite_flag") public static final String KEY_SATELLITE_ATTACH_SUPPORTED_BOOL = "satellite_attach_supported_bool"; field @FlaggedApi("com.android.internal.telephony.flags.carrier_enabled_satellite_flag") public static final String KEY_SATELLITE_CONNECTION_HYSTERESIS_SEC_INT = "satellite_connection_hysteresis_sec_int"; field @FlaggedApi("com.android.internal.telephony.flags.satellite_system_apis") public static final String KEY_SATELLITE_DATA_SUPPORT_MODE_INT = "satellite_data_support_mode_int"; + field @FlaggedApi("com.android.internal.telephony.flags.satellite_system_apis") public static final String KEY_SATELLITE_DISPLAY_NAME_STRING = "satellite_display_name_string"; field @FlaggedApi("com.android.internal.telephony.flags.satellite_system_apis") public static final String KEY_SATELLITE_ENTITLEMENT_APP_NAME_STRING = "satellite_entitlement_app_name_string"; field @FlaggedApi("com.android.internal.telephony.flags.carrier_enabled_satellite_flag") public static final String KEY_SATELLITE_ENTITLEMENT_STATUS_REFRESH_DAYS_INT = "satellite_entitlement_status_refresh_days_int"; field @FlaggedApi("com.android.internal.telephony.flags.carrier_enabled_satellite_flag") public static final String KEY_SATELLITE_ENTITLEMENT_SUPPORTED_BOOL = "satellite_entitlement_supported_bool"; @@ -45112,12 +45066,14 @@ package android.telephony { field @FlaggedApi("com.android.internal.telephony.flags.carrier_roaming_nb_iot_ntn") public static final String KEY_SATELLITE_ROAMING_P2P_SMS_SUPPORTED_BOOL = "satellite_roaming_p2p_sms_supported_bool"; field @FlaggedApi("com.android.internal.telephony.flags.carrier_roaming_nb_iot_ntn") public static final String KEY_SATELLITE_ROAMING_SCREEN_OFF_INACTIVITY_TIMEOUT_SEC_INT = "satellite_roaming_screen_off_inactivity_timeout_sec_int"; field @FlaggedApi("com.android.internal.telephony.flags.satellite_system_apis") public static final String KEY_SATELLITE_ROAMING_TURN_OFF_SESSION_FOR_EMERGENCY_CALL_BOOL = "satellite_roaming_turn_off_session_for_emergency_call_bool"; + field @FlaggedApi("com.android.internal.telephony.flags.satellite_system_apis") public static final String KEY_SATELLITE_SOS_MAX_DATAGRAM_SIZE_BYTES_INT = "satellite_sos_max_datagram_size_bytes_int"; + field @FlaggedApi("com.android.internal.telephony.flags.satellite_system_apis") public static final String KEY_SATELLITE_SUPPORTED_MSG_APPS_STRING_ARRAY = "satellite_supported_msg_apps_string_array"; field public static final String KEY_SHOW_4G_FOR_3G_DATA_ICON_BOOL = "show_4g_for_3g_data_icon_bool"; field public static final String KEY_SHOW_4G_FOR_LTE_DATA_ICON_BOOL = "show_4g_for_lte_data_icon_bool"; - field public static final String KEY_SHOW_APN_SETTING_CDMA_BOOL = "show_apn_setting_cdma_bool"; + field @Deprecated @FlaggedApi("com.android.internal.telephony.flags.deprecate_cdma") public static final String KEY_SHOW_APN_SETTING_CDMA_BOOL = "show_apn_setting_cdma_bool"; field public static final String KEY_SHOW_BLOCKING_PAY_PHONE_OPTION_BOOL = "show_blocking_pay_phone_option_bool"; field public static final String KEY_SHOW_CALL_BLOCKING_DISABLED_NOTIFICATION_ALWAYS_BOOL = "show_call_blocking_disabled_notification_always_bool"; - field public static final String KEY_SHOW_CDMA_CHOICES_BOOL = "show_cdma_choices_bool"; + field @Deprecated @FlaggedApi("com.android.internal.telephony.flags.deprecate_cdma") public static final String KEY_SHOW_CDMA_CHOICES_BOOL = "show_cdma_choices_bool"; field public static final String KEY_SHOW_FORWARDED_NUMBER_BOOL = "show_forwarded_number_bool"; field public static final String KEY_SHOW_ICCID_IN_SIM_STATUS_BOOL = "show_iccid_in_sim_status_bool"; field public static final String KEY_SHOW_IMS_REGISTRATION_STATUS_BOOL = "show_ims_registration_status_bool"; @@ -45147,7 +45103,7 @@ package android.telephony { field public static final String KEY_SUPPORT_ENHANCED_CALL_BLOCKING_BOOL = "support_enhanced_call_blocking_bool"; field public static final String KEY_SUPPORT_IMS_CONFERENCE_EVENT_PACKAGE_BOOL = "support_ims_conference_event_package_bool"; field public static final String KEY_SUPPORT_PAUSE_IMS_VIDEO_CALLS_BOOL = "support_pause_ims_video_calls_bool"; - field public static final String KEY_SUPPORT_SWAP_AFTER_MERGE_BOOL = "support_swap_after_merge_bool"; + field @Deprecated @FlaggedApi("com.android.internal.telephony.flags.deprecate_cdma") public static final String KEY_SUPPORT_SWAP_AFTER_MERGE_BOOL = "support_swap_after_merge_bool"; field public static final String KEY_SUPPORT_TDSCDMA_BOOL = "support_tdscdma_bool"; field public static final String KEY_SUPPORT_TDSCDMA_ROAMING_NETWORKS_STRING_ARRAY = "support_tdscdma_roaming_networks_string_array"; field public static final String KEY_SWITCH_DATA_TO_PRIMARY_IF_PRIMARY_IS_OOS_BOOL = "switch_data_to_primary_if_primary_is_oos_bool"; @@ -45157,7 +45113,7 @@ package android.telephony { field public static final String KEY_USE_ACS_FOR_RCS_BOOL = "use_acs_for_rcs_bool"; field public static final String KEY_USE_HFA_FOR_PROVISIONING_BOOL = "use_hfa_for_provisioning_bool"; field public static final String KEY_USE_IP_FOR_CALLING_INDICATOR_BOOL = "use_ip_for_calling_indicator_bool"; - field public static final String KEY_USE_OTASP_FOR_PROVISIONING_BOOL = "use_otasp_for_provisioning_bool"; + field @Deprecated @FlaggedApi("com.android.internal.telephony.flags.deprecate_cdma") public static final String KEY_USE_OTASP_FOR_PROVISIONING_BOOL = "use_otasp_for_provisioning_bool"; field @Deprecated public static final String KEY_USE_RCS_PRESENCE_BOOL = "use_rcs_presence_bool"; field public static final String KEY_USE_RCS_SIP_OPTIONS_BOOL = "use_rcs_sip_options_bool"; field public static final String KEY_USE_WFC_HOME_NETWORK_MODE_IN_ROAMING_NETWORK_BOOL = "use_wfc_home_network_mode_in_roaming_network_bool"; @@ -45593,13 +45549,13 @@ package android.telephony { field @NonNull public static final android.os.Parcelable.Creator CREATOR; } - public final class CellIdentityCdma extends android.telephony.CellIdentity { - method public int getBasestationId(); - method public int getLatitude(); - method public int getLongitude(); - method public int getNetworkId(); - method public int getSystemId(); - field @NonNull public static final android.os.Parcelable.Creator CREATOR; + @Deprecated @FlaggedApi("com.android.internal.telephony.flags.deprecate_cdma") public final class CellIdentityCdma extends android.telephony.CellIdentity { + method @Deprecated @FlaggedApi("com.android.internal.telephony.flags.deprecate_cdma") public int getBasestationId(); + method @Deprecated @FlaggedApi("com.android.internal.telephony.flags.deprecate_cdma") public int getLatitude(); + method @Deprecated @FlaggedApi("com.android.internal.telephony.flags.deprecate_cdma") public int getLongitude(); + method @Deprecated @FlaggedApi("com.android.internal.telephony.flags.deprecate_cdma") public int getNetworkId(); + method @Deprecated @FlaggedApi("com.android.internal.telephony.flags.deprecate_cdma") public int getSystemId(); + field @Deprecated @FlaggedApi("com.android.internal.telephony.flags.deprecate_cdma") @NonNull public static final android.os.Parcelable.Creator CREATOR; } public final class CellIdentityGsm extends android.telephony.CellIdentity { @@ -45691,11 +45647,11 @@ package android.telephony { field public static final long UNAVAILABLE_LONG = 9223372036854775807L; // 0x7fffffffffffffffL } - public final class CellInfoCdma extends android.telephony.CellInfo implements android.os.Parcelable { - method @NonNull public android.telephony.CellIdentityCdma getCellIdentity(); - method @NonNull public android.telephony.CellSignalStrengthCdma getCellSignalStrength(); - method public void writeToParcel(android.os.Parcel, int); - field @NonNull public static final android.os.Parcelable.Creator CREATOR; + @Deprecated @FlaggedApi("com.android.internal.telephony.flags.deprecate_cdma") public final class CellInfoCdma extends android.telephony.CellInfo implements android.os.Parcelable { + method @Deprecated @FlaggedApi("com.android.internal.telephony.flags.deprecate_cdma") @NonNull public android.telephony.CellIdentityCdma getCellIdentity(); + method @Deprecated @FlaggedApi("com.android.internal.telephony.flags.deprecate_cdma") @NonNull public android.telephony.CellSignalStrengthCdma getCellSignalStrength(); + method @Deprecated @FlaggedApi("com.android.internal.telephony.flags.deprecate_cdma") public void writeToParcel(android.os.Parcel, int); + field @Deprecated @FlaggedApi("com.android.internal.telephony.flags.deprecate_cdma") @NonNull public static final android.os.Parcelable.Creator CREATOR; } public final class CellInfoGsm extends android.telephony.CellInfo implements android.os.Parcelable { @@ -47274,11 +47230,11 @@ package android.telephony { method @RequiresPermission("android.permission.READ_PRIVILEGED_PHONE_STATE") public String getImei(int); method @Deprecated @RequiresPermission(anyOf={android.Manifest.permission.READ_PHONE_STATE, android.Manifest.permission.READ_SMS, android.Manifest.permission.READ_PHONE_NUMBERS}) public String getLine1Number(); method @NonNull @RequiresPermission(android.Manifest.permission.READ_PRECISE_PHONE_STATE) public String getManualNetworkSelectionPlmn(); - method @Nullable public String getManufacturerCode(); - method @Nullable public String getManufacturerCode(int); + method @Deprecated @FlaggedApi("com.android.internal.telephony.flags.deprecate_cdma") @Nullable public String getManufacturerCode(); + method @Deprecated @FlaggedApi("com.android.internal.telephony.flags.deprecate_cdma") @Nullable public String getManufacturerCode(int); method public static long getMaximumCallComposerPictureSize(); - method @RequiresPermission("android.permission.READ_PRIVILEGED_PHONE_STATE") public String getMeid(); - method @RequiresPermission("android.permission.READ_PRIVILEGED_PHONE_STATE") public String getMeid(int); + method @Deprecated @FlaggedApi("com.android.internal.telephony.flags.deprecate_cdma") @RequiresPermission("android.permission.READ_PRIVILEGED_PHONE_STATE") public String getMeid(); + method @Deprecated @FlaggedApi("com.android.internal.telephony.flags.deprecate_cdma") @RequiresPermission("android.permission.READ_PRIVILEGED_PHONE_STATE") public String getMeid(int); method public String getMmsUAProfUrl(); method public String getMmsUserAgent(); method @RequiresPermission("android.permission.READ_PRIVILEGED_PHONE_STATE") public String getNai(); @@ -47424,10 +47380,10 @@ package android.telephony { field public static final int CARRIER_RESTRICTION_STATUS_RESTRICTED = 2; // 0x2 field public static final int CARRIER_RESTRICTION_STATUS_RESTRICTED_TO_CALLER = 3; // 0x3 field public static final int CARRIER_RESTRICTION_STATUS_UNKNOWN = 0; // 0x0 - field public static final int CDMA_ROAMING_MODE_AFFILIATED = 1; // 0x1 - field public static final int CDMA_ROAMING_MODE_ANY = 2; // 0x2 - field public static final int CDMA_ROAMING_MODE_HOME = 0; // 0x0 - field public static final int CDMA_ROAMING_MODE_RADIO_DEFAULT = -1; // 0xffffffff + field @Deprecated @FlaggedApi("com.android.internal.telephony.flags.deprecate_cdma") public static final int CDMA_ROAMING_MODE_AFFILIATED = 1; // 0x1 + field @Deprecated @FlaggedApi("com.android.internal.telephony.flags.deprecate_cdma") public static final int CDMA_ROAMING_MODE_ANY = 2; // 0x2 + field @Deprecated @FlaggedApi("com.android.internal.telephony.flags.deprecate_cdma") public static final int CDMA_ROAMING_MODE_HOME = 0; // 0x0 + field @Deprecated @FlaggedApi("com.android.internal.telephony.flags.deprecate_cdma") public static final int CDMA_ROAMING_MODE_RADIO_DEFAULT = -1; // 0xffffffff field public static final int DATA_ACTIVITY_DORMANT = 4; // 0x4 field public static final int DATA_ACTIVITY_IN = 1; // 0x1 field public static final int DATA_ACTIVITY_INOUT = 3; // 0x3 @@ -47447,9 +47403,9 @@ package android.telephony { field public static final int DATA_SUSPENDED = 3; // 0x3 field public static final int DATA_UNKNOWN = -1; // 0xffffffff field public static final int DEFAULT_PORT_INDEX = 0; // 0x0 - field public static final int ERI_FLASH = 2; // 0x2 - field public static final int ERI_OFF = 1; // 0x1 - field public static final int ERI_ON = 0; // 0x0 + field @Deprecated @FlaggedApi("com.android.internal.telephony.flags.deprecate_cdma") public static final int ERI_FLASH = 2; // 0x2 + field @Deprecated @FlaggedApi("com.android.internal.telephony.flags.deprecate_cdma") public static final int ERI_OFF = 1; // 0x1 + field @Deprecated @FlaggedApi("com.android.internal.telephony.flags.deprecate_cdma") public static final int ERI_ON = 0; // 0x0 field @FlaggedApi("com.android.internal.telephony.flags.oem_enabled_satellite_flag") public static final String EVENT_DISPLAY_EMERGENCY_MESSAGE = "android.telephony.event.DISPLAY_EMERGENCY_MESSAGE"; field public static final String EXTRA_ACTIVE_SIM_SUPPORTED_COUNT = "android.telephony.extra.ACTIVE_SIM_SUPPORTED_COUNT"; field public static final String EXTRA_APN_PROTOCOL = "android.telephony.extra.APN_PROTOCOL"; @@ -47490,11 +47446,11 @@ package android.telephony { field public static final int NETWORK_SELECTION_MODE_AUTO = 1; // 0x1 field public static final int NETWORK_SELECTION_MODE_MANUAL = 2; // 0x2 field public static final int NETWORK_SELECTION_MODE_UNKNOWN = 0; // 0x0 - field public static final int NETWORK_TYPE_1xRTT = 7; // 0x7 + field @Deprecated @FlaggedApi("com.android.internal.telephony.flags.deprecate_cdma") public static final int NETWORK_TYPE_1xRTT = 7; // 0x7 field public static final long NETWORK_TYPE_BITMASK_1xRTT = 64L; // 0x40L - field public static final long NETWORK_TYPE_BITMASK_CDMA = 8L; // 0x8L + field @Deprecated @FlaggedApi("com.android.internal.telephony.flags.deprecate_cdma") public static final long NETWORK_TYPE_BITMASK_CDMA = 8L; // 0x8L field public static final long NETWORK_TYPE_BITMASK_EDGE = 2L; // 0x2L - field public static final long NETWORK_TYPE_BITMASK_EHRPD = 8192L; // 0x2000L + field @Deprecated @FlaggedApi("com.android.internal.telephony.flags.deprecate_cdma") public static final long NETWORK_TYPE_BITMASK_EHRPD = 8192L; // 0x2000L field public static final long NETWORK_TYPE_BITMASK_EVDO_0 = 16L; // 0x10L field public static final long NETWORK_TYPE_BITMASK_EVDO_A = 32L; // 0x20L field public static final long NETWORK_TYPE_BITMASK_EVDO_B = 2048L; // 0x800L @@ -47507,16 +47463,17 @@ package android.telephony { field public static final long NETWORK_TYPE_BITMASK_IWLAN = 131072L; // 0x20000L field public static final long NETWORK_TYPE_BITMASK_LTE = 4096L; // 0x1000L field @Deprecated public static final long NETWORK_TYPE_BITMASK_LTE_CA = 262144L; // 0x40000L + field @FlaggedApi("com.android.internal.telephony.flags.satellite_system_apis") public static final long NETWORK_TYPE_BITMASK_NB_IOT_NTN = 1048576L; // 0x100000L field public static final long NETWORK_TYPE_BITMASK_NR = 524288L; // 0x80000L field public static final long NETWORK_TYPE_BITMASK_TD_SCDMA = 65536L; // 0x10000L field public static final long NETWORK_TYPE_BITMASK_UMTS = 4L; // 0x4L field public static final long NETWORK_TYPE_BITMASK_UNKNOWN = 0L; // 0x0L - field public static final int NETWORK_TYPE_CDMA = 4; // 0x4 + field @Deprecated @FlaggedApi("com.android.internal.telephony.flags.deprecate_cdma") public static final int NETWORK_TYPE_CDMA = 4; // 0x4 field public static final int NETWORK_TYPE_EDGE = 2; // 0x2 - field public static final int NETWORK_TYPE_EHRPD = 14; // 0xe - field public static final int NETWORK_TYPE_EVDO_0 = 5; // 0x5 - field public static final int NETWORK_TYPE_EVDO_A = 6; // 0x6 - field public static final int NETWORK_TYPE_EVDO_B = 12; // 0xc + field @Deprecated @FlaggedApi("com.android.internal.telephony.flags.deprecate_cdma") public static final int NETWORK_TYPE_EHRPD = 14; // 0xe + field @Deprecated @FlaggedApi("com.android.internal.telephony.flags.deprecate_cdma") public static final int NETWORK_TYPE_EVDO_0 = 5; // 0x5 + field @Deprecated @FlaggedApi("com.android.internal.telephony.flags.deprecate_cdma") public static final int NETWORK_TYPE_EVDO_A = 6; // 0x6 + field @Deprecated @FlaggedApi("com.android.internal.telephony.flags.deprecate_cdma") public static final int NETWORK_TYPE_EVDO_B = 12; // 0xc field public static final int NETWORK_TYPE_GPRS = 1; // 0x1 field public static final int NETWORK_TYPE_GSM = 16; // 0x10 field public static final int NETWORK_TYPE_HSDPA = 8; // 0x8 @@ -47526,11 +47483,12 @@ package android.telephony { field @Deprecated public static final int NETWORK_TYPE_IDEN = 11; // 0xb field public static final int NETWORK_TYPE_IWLAN = 18; // 0x12 field public static final int NETWORK_TYPE_LTE = 13; // 0xd + field @FlaggedApi("com.android.internal.telephony.flags.satellite_system_apis") public static final int NETWORK_TYPE_NB_IOT_NTN = 21; // 0x15 field public static final int NETWORK_TYPE_NR = 20; // 0x14 field public static final int NETWORK_TYPE_TD_SCDMA = 17; // 0x11 field public static final int NETWORK_TYPE_UMTS = 3; // 0x3 field public static final int NETWORK_TYPE_UNKNOWN = 0; // 0x0 - field public static final int PHONE_TYPE_CDMA = 2; // 0x2 + field @Deprecated @FlaggedApi("com.android.internal.telephony.flags.deprecate_cdma") public static final int PHONE_TYPE_CDMA = 2; // 0x2 field public static final int PHONE_TYPE_GSM = 1; // 0x1 field public static final int PHONE_TYPE_NONE = 0; // 0x0 field public static final int PHONE_TYPE_SIP = 3; // 0x3 @@ -53515,6 +53473,7 @@ package android.view { field @NonNull public static final android.os.Parcelable.Creator CREATOR; field public static final int FRAME_RATE_COMPATIBILITY_DEFAULT = 0; // 0x0 field public static final int FRAME_RATE_COMPATIBILITY_FIXED_SOURCE = 1; // 0x1 + field @FlaggedApi("com.android.graphics.surfaceflinger.flags.arr_setframerate_gte_enum") public static final int FRAME_RATE_COMPATIBILITY_GTE = 2; // 0x2 field public static final int ROTATION_0 = 0; // 0x0 field public static final int ROTATION_180 = 2; // 0x2 field public static final int ROTATION_270 = 3; // 0x3 @@ -55293,8 +55252,8 @@ package android.view { method public abstract void setTransformation(android.graphics.Matrix); method public abstract void setVisibility(int); method public abstract void setWebDomain(@Nullable String); - field @FlaggedApi("android.service.autofill.autofill_w_metrics") public static final String EXTRA_VIRTUAL_STRUCTURE_TYPE = "android.view.ViewStructure.extra.VIRTUAL_STRUCTURE_TYPE"; - field @FlaggedApi("android.service.autofill.autofill_w_metrics") public static final String EXTRA_VIRTUAL_STRUCTURE_VERSION_NUMBER = "android.view.ViewStructure.extra.VIRTUAL_STRUCTURE_VERSION_NUMBER"; + field @FlaggedApi("android.service.autofill.autofill_w_metrics") public static final String EXTRA_VIRTUAL_STRUCTURE_TYPE = "android.view.extra.VIRTUAL_STRUCTURE_TYPE"; + field @FlaggedApi("android.service.autofill.autofill_w_metrics") public static final String EXTRA_VIRTUAL_STRUCTURE_VERSION_NUMBER = "android.view.extra.VIRTUAL_STRUCTURE_VERSION_NUMBER"; } public abstract static class ViewStructure.HtmlInfo { @@ -58407,6 +58366,7 @@ package android.view.textclassifier { method @NonNull @WorkerThread public default android.view.textclassifier.TextSelection suggestSelection(@NonNull android.view.textclassifier.TextSelection.Request); method @NonNull @WorkerThread public default android.view.textclassifier.TextSelection suggestSelection(@NonNull CharSequence, @IntRange(from=0) int, @IntRange(from=0) int, @Nullable android.os.LocaleList); field public static final String EXTRA_FROM_TEXT_CLASSIFIER = "android.view.textclassifier.extra.FROM_TEXT_CLASSIFIER"; + field @FlaggedApi("android.permission.flags.text_classifier_choice_api_enabled") public static final String EXTRA_TEXT_ORIGIN_PACKAGE = "android.view.textclassifier.extra.TEXT_ORIGIN_PACKAGE"; field public static final String HINT_TEXT_IS_EDITABLE = "android.text_is_editable"; field public static final String HINT_TEXT_IS_NOT_EDITABLE = "android.text_is_not_editable"; field public static final android.view.textclassifier.TextClassifier NO_OP; @@ -58416,6 +58376,7 @@ package android.view.textclassifier { field public static final String TYPE_EMAIL = "email"; field public static final String TYPE_FLIGHT_NUMBER = "flight"; field public static final String TYPE_OTHER = "other"; + field @FlaggedApi("android.permission.flags.text_classifier_choice_api_enabled") public static final String TYPE_OTP = "otp"; field public static final String TYPE_PHONE = "phone"; field public static final String TYPE_UNKNOWN = ""; field public static final String TYPE_URL = "url"; diff --git a/core/api/lint-baseline.txt b/core/api/lint-baseline.txt index ad5bd31828e030f0a9d97b242b02ebd7766c5e0d..e71dffaf152d4ff00878f4275081f459a9754166 100644 --- a/core/api/lint-baseline.txt +++ b/core/api/lint-baseline.txt @@ -1,10 +1,4 @@ // Baseline format: 1.0 -ActionValue: android.view.ViewStructure#EXTRA_VIRTUAL_STRUCTURE_TYPE: - Inconsistent extra value; expected `android.view.extra.VIRTUAL_STRUCTURE_TYPE`, was `android.view.ViewStructure.extra.VIRTUAL_STRUCTURE_TYPE` -ActionValue: android.view.ViewStructure#EXTRA_VIRTUAL_STRUCTURE_VERSION_NUMBER: - Inconsistent extra value; expected `android.view.extra.VIRTUAL_STRUCTURE_VERSION_NUMBER`, was `android.view.ViewStructure.extra.VIRTUAL_STRUCTURE_VERSION_NUMBER` - - BroadcastBehavior: android.app.AlarmManager#ACTION_NEXT_ALARM_CLOCK_CHANGED: Field 'ACTION_NEXT_ALARM_CLOCK_CHANGED' is missing @BroadcastBehavior BroadcastBehavior: android.app.AlarmManager#ACTION_SCHEDULE_EXACT_ALARM_PERMISSION_STATE_CHANGED: @@ -1191,10 +1185,6 @@ UnflaggedApi: android.R.dimen#system_corner_radius_xlarge: New API must be flagged with @FlaggedApi: field android.R.dimen.system_corner_radius_xlarge UnflaggedApi: android.R.dimen#system_corner_radius_xsmall: New API must be flagged with @FlaggedApi: field android.R.dimen.system_corner_radius_xsmall -UnflaggedApi: android.R.integer#status_bar_notification_info_maxnum: - Changes from not deprecated to deprecated must be flagged with @FlaggedApi: field android.R.integer.status_bar_notification_info_maxnum -UnflaggedApi: android.R.string#status_bar_notification_info_overflow: - Changes from not deprecated to deprecated must be flagged with @FlaggedApi: field android.R.string.status_bar_notification_info_overflow UnflaggedApi: android.accessibilityservice.AccessibilityService#OVERLAY_RESULT_INTERNAL_ERROR: New API must be flagged with @FlaggedApi: field android.accessibilityservice.AccessibilityService.OVERLAY_RESULT_INTERNAL_ERROR UnflaggedApi: android.accessibilityservice.AccessibilityService#OVERLAY_RESULT_INVALID: diff --git a/core/api/module-lib-current.txt b/core/api/module-lib-current.txt index 804210fe3bb5b44d39899517e9908180d3a17b72..bca2ce2473c5989014012c4e4d39f55606dd5193 100644 --- a/core/api/module-lib-current.txt +++ b/core/api/module-lib-current.txt @@ -265,10 +265,6 @@ package android.media.session { package android.net { - @FlaggedApi("android.net.vcn.mainline_vcn_module_api") public final class ConnectivityFrameworkInitializerBaklava { - method @FlaggedApi("android.net.vcn.mainline_vcn_module_api") public static void registerServiceWrappers(); - } - public class LocalSocket implements java.io.Closeable { ctor public LocalSocket(@NonNull java.io.FileDescriptor); } @@ -328,25 +324,6 @@ package android.net.netstats { } -package android.net.vcn { - - @FlaggedApi("android.net.vcn.mainline_vcn_module_api") public final class VcnTransportInfo implements android.os.Parcelable android.net.TransportInfo { - method @FlaggedApi("android.net.vcn.mainline_vcn_module_api") public int describeContents(); - method @FlaggedApi("android.net.vcn.mainline_vcn_module_api") public long getApplicableRedactions(); - method @FlaggedApi("android.net.vcn.mainline_vcn_module_api") public int getMinUdpPort4500NatTimeoutSeconds(); - method @FlaggedApi("android.net.vcn.mainline_vcn_module_api") @NonNull public android.net.TransportInfo makeCopy(long); - method @FlaggedApi("android.net.vcn.mainline_vcn_module_api") public void writeToParcel(@NonNull android.os.Parcel, int); - field @FlaggedApi("android.net.vcn.mainline_vcn_module_api") @NonNull public static final android.os.Parcelable.Creator CREATOR; - } - - @FlaggedApi("android.net.vcn.mainline_vcn_module_api") public static final class VcnTransportInfo.Builder { - ctor @FlaggedApi("android.net.vcn.mainline_vcn_module_api") public VcnTransportInfo.Builder(); - method @FlaggedApi("android.net.vcn.mainline_vcn_module_api") @NonNull public android.net.vcn.VcnTransportInfo build(); - method @FlaggedApi("android.net.vcn.mainline_vcn_module_api") @NonNull public android.net.vcn.VcnTransportInfo.Builder setMinUdpPort4500NatTimeoutSeconds(@IntRange(from=0x78) int); - } - -} - package android.net.wifi { public final class WifiMigration { @@ -505,6 +482,10 @@ package android.os { field public static final long TRACE_TAG_NETWORK = 2097152L; // 0x200000L } + public class UpdateEngine { + method @FlaggedApi("android.os.update_engine_api") public void triggerPostinstall(@NonNull String); + } + } package android.os.storage { diff --git a/core/api/system-current.txt b/core/api/system-current.txt index 612a48ac00a7bb57f2d219bde85fb4ebe9ae3949..9590e1ab19c90ccb1d53f88ca5c2d9cb16b3eb7a 100644 --- a/core/api/system-current.txt +++ b/core/api/system-current.txt @@ -10,6 +10,7 @@ package android { field @FlaggedApi("android.app.contextualsearch.flags.enable_service") public static final String ACCESS_CONTEXTUAL_SEARCH = "android.permission.ACCESS_CONTEXTUAL_SEARCH"; field public static final String ACCESS_CONTEXT_HUB = "android.permission.ACCESS_CONTEXT_HUB"; field public static final String ACCESS_DRM_CERTIFICATES = "android.permission.ACCESS_DRM_CERTIFICATES"; + field @FlaggedApi("android.permission.flags.fine_power_monitor_permission") public static final String ACCESS_FINE_POWER_MONITORS = "android.permission.ACCESS_FINE_POWER_MONITORS"; field @Deprecated public static final String ACCESS_FM_RADIO = "android.permission.ACCESS_FM_RADIO"; field public static final String ACCESS_FPS_COUNTER = "android.permission.ACCESS_FPS_COUNTER"; field @FlaggedApi("android.multiuser.enable_permission_to_access_hidden_profiles") public static final String ACCESS_HIDDEN_PROFILES_FULL = "android.permission.ACCESS_HIDDEN_PROFILES_FULL"; @@ -26,6 +27,7 @@ package android { field public static final String ACCESS_SHORTCUTS = "android.permission.ACCESS_SHORTCUTS"; field @FlaggedApi("android.app.smartspace.flags.access_smartspace") public static final String ACCESS_SMARTSPACE = "android.permission.ACCESS_SMARTSPACE"; field public static final String ACCESS_SURFACE_FLINGER = "android.permission.ACCESS_SURFACE_FLINGER"; + field @FlaggedApi("android.permission.flags.text_classifier_choice_api_enabled") public static final String ACCESS_TEXT_CLASSIFIER_BY_TYPE = "android.permission.ACCESS_TEXT_CLASSIFIER_BY_TYPE"; field public static final String ACCESS_TUNED_INFO = "android.permission.ACCESS_TUNED_INFO"; field public static final String ACCESS_TV_DESCRAMBLER = "android.permission.ACCESS_TV_DESCRAMBLER"; field public static final String ACCESS_TV_SHARED_FILTER = "android.permission.ACCESS_TV_SHARED_FILTER"; @@ -78,6 +80,7 @@ package android { field @FlaggedApi("android.app.ondeviceintelligence.flags.enable_on_device_intelligence") public static final String BIND_ON_DEVICE_INTELLIGENCE_SERVICE = "android.permission.BIND_ON_DEVICE_INTELLIGENCE_SERVICE"; field @FlaggedApi("android.app.ondeviceintelligence.flags.enable_on_device_intelligence") public static final String BIND_ON_DEVICE_SANDBOXED_INFERENCE_SERVICE = "android.permission.BIND_ON_DEVICE_SANDBOXED_INFERENCE_SERVICE"; field public static final String BIND_PHONE_ACCOUNT_SUGGESTION_SERVICE = "android.permission.BIND_PHONE_ACCOUNT_SUGGESTION_SERVICE"; + field @FlaggedApi("android.location.flags.population_density_provider") public static final String BIND_POPULATION_DENSITY_PROVIDER_SERVICE = "android.permission.BIND_POPULATION_DENSITY_PROVIDER_SERVICE"; field public static final String BIND_PRINT_RECOMMENDATION_SERVICE = "android.permission.BIND_PRINT_RECOMMENDATION_SERVICE"; field public static final String BIND_REMOTE_LOCKSCREEN_VALIDATION_SERVICE = "android.permission.BIND_REMOTE_LOCKSCREEN_VALIDATION_SERVICE"; field public static final String BIND_RESOLVER_RANKER_SERVICE = "android.permission.BIND_RESOLVER_RANKER_SERVICE"; @@ -327,6 +330,7 @@ package android { field public static final String READ_RUNTIME_PROFILES = "android.permission.READ_RUNTIME_PROFILES"; field public static final String READ_SAFETY_CENTER_STATUS = "android.permission.READ_SAFETY_CENTER_STATUS"; field public static final String READ_SEARCH_INDEXABLES = "android.permission.READ_SEARCH_INDEXABLES"; + field @FlaggedApi("com.android.internal.telephony.flags.subscription_plan_allow_status_and_end_date") public static final String READ_SUBSCRIPTION_PLANS = "android.permission.READ_SUBSCRIPTION_PLANS"; field @FlaggedApi("android.app.system_terms_of_address_enabled") public static final String READ_SYSTEM_GRAMMATICAL_GENDER = "android.permission.READ_SYSTEM_GRAMMATICAL_GENDER"; field public static final String READ_SYSTEM_UPDATE_INFO = "android.permission.READ_SYSTEM_UPDATE_INFO"; field public static final String READ_WALLPAPER_INTERNAL = "android.permission.READ_WALLPAPER_INTERNAL"; @@ -549,6 +553,7 @@ package android { field public static final int config_systemTextIntelligence = 17039414; // 0x1040036 field public static final int config_systemUi = 17039418; // 0x104003a field public static final int config_systemUiIntelligence = 17039410; // 0x1040032 + field @FlaggedApi("android.permission.flags.system_vendor_intelligence_role_enabled") public static final int config_systemVendorIntelligence; field public static final int config_systemVisualIntelligence = 17039415; // 0x1040037 field public static final int config_systemWearHealthService = 17039428; // 0x1040044 field public static final int config_systemWellbeing = 17039408; // 0x1040030 @@ -1290,6 +1295,7 @@ package android.app { method @FlaggedApi("android.app.live_wallpaper_content_handling") @Nullable @RequiresPermission(android.Manifest.permission.READ_WALLPAPER_INTERNAL) public android.app.wallpaper.WallpaperInstance getWallpaperInstance(int); method public void setDisplayOffset(android.os.IBinder, int, int); method @FlaggedApi("com.android.window.flags.multi_crop") @RequiresPermission(android.Manifest.permission.SET_WALLPAPER) public int setStreamWithCrops(@NonNull java.io.InputStream, @NonNull android.util.SparseArray, boolean, int) throws java.io.IOException; + method @FlaggedApi("android.app.live_wallpaper_content_handling") @RequiresPermission(android.Manifest.permission.SET_WALLPAPER) public int setStreamWithDescription(@NonNull java.io.InputStream, @NonNull android.app.wallpaper.WallpaperDescription, boolean, int) throws java.io.IOException; method @RequiresPermission(android.Manifest.permission.SET_WALLPAPER_COMPONENT) public boolean setWallpaperComponent(android.content.ComponentName); method @FlaggedApi("android.app.live_wallpaper_content_handling") @RequiresPermission(allOf={android.Manifest.permission.SET_WALLPAPER_COMPONENT, android.Manifest.permission.INTERACT_ACROSS_USERS_FULL}, conditional=true) public boolean setWallpaperComponentWithDescription(@NonNull android.app.wallpaper.WallpaperDescription, int); method @RequiresPermission(android.Manifest.permission.SET_WALLPAPER_COMPONENT) public boolean setWallpaperComponentWithFlags(@NonNull android.content.ComponentName, int); @@ -2273,149 +2279,6 @@ package android.app.job { } -package android.app.ondeviceintelligence { - - @FlaggedApi("android.app.ondeviceintelligence.flags.enable_on_device_intelligence") public interface DownloadCallback { - method public void onDownloadCompleted(@NonNull android.os.PersistableBundle); - method public void onDownloadFailed(int, @Nullable String, @NonNull android.os.PersistableBundle); - method public default void onDownloadProgress(long); - method public default void onDownloadStarted(long); - field public static final int DOWNLOAD_FAILURE_STATUS_DOWNLOADING = 3; // 0x3 - field public static final int DOWNLOAD_FAILURE_STATUS_NETWORK_FAILURE = 2; // 0x2 - field public static final int DOWNLOAD_FAILURE_STATUS_NOT_ENOUGH_DISK_SPACE = 1; // 0x1 - field public static final int DOWNLOAD_FAILURE_STATUS_UNAVAILABLE = 4; // 0x4 - field public static final int DOWNLOAD_FAILURE_STATUS_UNKNOWN = 0; // 0x0 - } - - @FlaggedApi("android.app.ondeviceintelligence.flags.enable_on_device_intelligence") public final class Feature implements android.os.Parcelable { - method public int describeContents(); - method @NonNull public android.os.PersistableBundle getFeatureParams(); - method public int getId(); - method @Nullable public String getModelName(); - method @Nullable public String getName(); - method public int getType(); - method public int getVariant(); - method public void writeToParcel(@NonNull android.os.Parcel, int); - field @NonNull public static final android.os.Parcelable.Creator CREATOR; - } - - public static final class Feature.Builder { - ctor public Feature.Builder(int); - method @NonNull public android.app.ondeviceintelligence.Feature build(); - method @NonNull public android.app.ondeviceintelligence.Feature.Builder setFeatureParams(@NonNull android.os.PersistableBundle); - method @NonNull public android.app.ondeviceintelligence.Feature.Builder setModelName(@NonNull String); - method @NonNull public android.app.ondeviceintelligence.Feature.Builder setName(@NonNull String); - method @NonNull public android.app.ondeviceintelligence.Feature.Builder setType(int); - method @NonNull public android.app.ondeviceintelligence.Feature.Builder setVariant(int); - } - - @FlaggedApi("android.app.ondeviceintelligence.flags.enable_on_device_intelligence") public final class FeatureDetails implements android.os.Parcelable { - ctor public FeatureDetails(int, @NonNull android.os.PersistableBundle); - ctor public FeatureDetails(int); - method public int describeContents(); - method @NonNull public android.os.PersistableBundle getFeatureDetailParams(); - method public int getFeatureStatus(); - method public void writeToParcel(@NonNull android.os.Parcel, int); - field @NonNull public static final android.os.Parcelable.Creator CREATOR; - field public static final int FEATURE_STATUS_AVAILABLE = 3; // 0x3 - field public static final int FEATURE_STATUS_DOWNLOADABLE = 1; // 0x1 - field public static final int FEATURE_STATUS_DOWNLOADING = 2; // 0x2 - field public static final int FEATURE_STATUS_SERVICE_UNAVAILABLE = 4; // 0x4 - field public static final int FEATURE_STATUS_UNAVAILABLE = 0; // 0x0 - } - - @FlaggedApi("android.app.ondeviceintelligence.flags.enable_on_device_intelligence_module") public final class InferenceInfo implements android.os.Parcelable { - method public int describeContents(); - method public long getEndTimeMillis(); - method public long getStartTimeMillis(); - method public long getSuspendedTimeMillis(); - method public int getUid(); - method public void writeToParcel(@NonNull android.os.Parcel, int); - field @NonNull public static final android.os.Parcelable.Creator CREATOR; - } - - public static final class InferenceInfo.Builder { - ctor public InferenceInfo.Builder(int); - method @NonNull public android.app.ondeviceintelligence.InferenceInfo build(); - method @NonNull public android.app.ondeviceintelligence.InferenceInfo.Builder setEndTimeMillis(long); - method @NonNull public android.app.ondeviceintelligence.InferenceInfo.Builder setStartTimeMillis(long); - method @NonNull public android.app.ondeviceintelligence.InferenceInfo.Builder setSuspendedTimeMillis(long); - } - - @FlaggedApi("android.app.ondeviceintelligence.flags.enable_on_device_intelligence") public class OnDeviceIntelligenceException extends java.lang.Exception { - ctor public OnDeviceIntelligenceException(int, @NonNull String, @NonNull android.os.PersistableBundle); - ctor public OnDeviceIntelligenceException(int, @NonNull android.os.PersistableBundle); - ctor public OnDeviceIntelligenceException(int, @NonNull String); - ctor public OnDeviceIntelligenceException(int); - method public int getErrorCode(); - method @NonNull public android.os.PersistableBundle getErrorParams(); - field public static final int ON_DEVICE_INTELLIGENCE_SERVICE_UNAVAILABLE = 100; // 0x64 - field public static final int PROCESSING_ERROR_BAD_DATA = 2; // 0x2 - field public static final int PROCESSING_ERROR_BAD_REQUEST = 3; // 0x3 - field public static final int PROCESSING_ERROR_BUSY = 9; // 0x9 - field public static final int PROCESSING_ERROR_CANCELLED = 7; // 0x7 - field public static final int PROCESSING_ERROR_COMPUTE_ERROR = 5; // 0x5 - field public static final int PROCESSING_ERROR_INTERNAL = 14; // 0xe - field public static final int PROCESSING_ERROR_IPC_ERROR = 6; // 0x6 - field public static final int PROCESSING_ERROR_NOT_AVAILABLE = 8; // 0x8 - field public static final int PROCESSING_ERROR_REQUEST_NOT_SAFE = 4; // 0x4 - field public static final int PROCESSING_ERROR_REQUEST_TOO_LARGE = 12; // 0xc - field public static final int PROCESSING_ERROR_RESPONSE_NOT_SAFE = 11; // 0xb - field public static final int PROCESSING_ERROR_SAFETY_ERROR = 10; // 0xa - field public static final int PROCESSING_ERROR_SERVICE_UNAVAILABLE = 15; // 0xf - field public static final int PROCESSING_ERROR_SUSPENDED = 13; // 0xd - field public static final int PROCESSING_ERROR_UNKNOWN = 1; // 0x1 - field public static final int PROCESSING_UPDATE_STATUS_CONNECTION_FAILED = 200; // 0xc8 - } - - @FlaggedApi("android.app.ondeviceintelligence.flags.enable_on_device_intelligence") public final class OnDeviceIntelligenceManager { - method @RequiresPermission(android.Manifest.permission.USE_ON_DEVICE_INTELLIGENCE) public void getFeature(int, @NonNull java.util.concurrent.Executor, @NonNull android.os.OutcomeReceiver); - method @RequiresPermission(android.Manifest.permission.USE_ON_DEVICE_INTELLIGENCE) public void getFeatureDetails(@NonNull android.app.ondeviceintelligence.Feature, @NonNull java.util.concurrent.Executor, @NonNull android.os.OutcomeReceiver); - method @FlaggedApi("android.app.ondeviceintelligence.flags.enable_on_device_intelligence_module") @NonNull @RequiresPermission(android.Manifest.permission.DUMP) public java.util.List getLatestInferenceInfo(long); - method @Nullable @RequiresPermission(android.Manifest.permission.USE_ON_DEVICE_INTELLIGENCE) public String getRemoteServicePackageName(); - method @RequiresPermission(android.Manifest.permission.USE_ON_DEVICE_INTELLIGENCE) public void getVersion(@NonNull java.util.concurrent.Executor, @NonNull java.util.function.LongConsumer); - method @RequiresPermission(android.Manifest.permission.USE_ON_DEVICE_INTELLIGENCE) public void listFeatures(@NonNull java.util.concurrent.Executor, @NonNull android.os.OutcomeReceiver,android.app.ondeviceintelligence.OnDeviceIntelligenceException>); - method @RequiresPermission(android.Manifest.permission.USE_ON_DEVICE_INTELLIGENCE) public void processRequest(@NonNull android.app.ondeviceintelligence.Feature, @NonNull android.os.Bundle, int, @Nullable android.os.CancellationSignal, @Nullable android.app.ondeviceintelligence.ProcessingSignal, @NonNull java.util.concurrent.Executor, @NonNull android.app.ondeviceintelligence.ProcessingCallback); - method @RequiresPermission(android.Manifest.permission.USE_ON_DEVICE_INTELLIGENCE) public void processRequestStreaming(@NonNull android.app.ondeviceintelligence.Feature, @NonNull android.os.Bundle, int, @Nullable android.os.CancellationSignal, @Nullable android.app.ondeviceintelligence.ProcessingSignal, @NonNull java.util.concurrent.Executor, @NonNull android.app.ondeviceintelligence.StreamingProcessingCallback); - method @RequiresPermission(android.Manifest.permission.USE_ON_DEVICE_INTELLIGENCE) public void requestFeatureDownload(@NonNull android.app.ondeviceintelligence.Feature, @Nullable android.os.CancellationSignal, @NonNull java.util.concurrent.Executor, @NonNull android.app.ondeviceintelligence.DownloadCallback); - method @RequiresPermission(android.Manifest.permission.USE_ON_DEVICE_INTELLIGENCE) public void requestTokenInfo(@NonNull android.app.ondeviceintelligence.Feature, @NonNull android.os.Bundle, @Nullable android.os.CancellationSignal, @NonNull java.util.concurrent.Executor, @NonNull android.os.OutcomeReceiver); - field public static final int REQUEST_TYPE_EMBEDDINGS = 2; // 0x2 - field public static final int REQUEST_TYPE_INFERENCE = 0; // 0x0 - field public static final int REQUEST_TYPE_PREPARE = 1; // 0x1 - } - - @FlaggedApi("android.app.ondeviceintelligence.flags.enable_on_device_intelligence") public interface ProcessingCallback { - method public default void onDataAugmentRequest(@NonNull android.os.Bundle, @NonNull java.util.function.Consumer); - method public void onError(@NonNull android.app.ondeviceintelligence.OnDeviceIntelligenceException); - method public void onResult(@NonNull android.os.Bundle); - } - - @FlaggedApi("android.app.ondeviceintelligence.flags.enable_on_device_intelligence") public final class ProcessingSignal { - ctor public ProcessingSignal(); - method public void sendSignal(@NonNull android.os.PersistableBundle); - method public void setOnProcessingSignalCallback(@NonNull java.util.concurrent.Executor, @Nullable android.app.ondeviceintelligence.ProcessingSignal.OnProcessingSignalCallback); - } - - public static interface ProcessingSignal.OnProcessingSignalCallback { - method public void onSignalReceived(@NonNull android.os.PersistableBundle); - } - - @FlaggedApi("android.app.ondeviceintelligence.flags.enable_on_device_intelligence") public interface StreamingProcessingCallback extends android.app.ondeviceintelligence.ProcessingCallback { - method public void onPartialResult(@NonNull android.os.Bundle); - } - - @FlaggedApi("android.app.ondeviceintelligence.flags.enable_on_device_intelligence") public final class TokenInfo implements android.os.Parcelable { - ctor public TokenInfo(long, @NonNull android.os.PersistableBundle); - ctor public TokenInfo(long); - method public int describeContents(); - method public long getCount(); - method @NonNull public android.os.PersistableBundle getInfoParams(); - method public void writeToParcel(@NonNull android.os.Parcel, int); - field @NonNull public static final android.os.Parcelable.Creator CREATOR; - } - -} - package android.app.people { public final class PeopleManager { @@ -3301,6 +3164,14 @@ package android.app.usage { } +package android.app.wallpaper { + + @FlaggedApi("android.app.live_wallpaper_content_handling") public final class WallpaperDescription implements android.os.Parcelable { + method @NonNull public android.util.SparseArray getCropHints(); + } + +} + package android.app.wallpapereffectsgeneration { public final class CameraAttributes implements android.os.Parcelable { @@ -5254,9 +5125,9 @@ package android.hardware.contexthub { } @FlaggedApi("android.chre.flags.offload_api") public class HubEndpointSession implements java.lang.AutoCloseable { - method public void close(); - method @Nullable public android.hardware.contexthub.HubServiceInfo getServiceInfo(); - method @NonNull public android.hardware.location.ContextHubTransaction sendMessage(@NonNull android.hardware.contexthub.HubMessage); + method @RequiresPermission(android.Manifest.permission.ACCESS_CONTEXT_HUB) public void close(); + method @Nullable public String getServiceDescriptor(); + method @NonNull @RequiresPermission(android.Manifest.permission.ACCESS_CONTEXT_HUB) public android.hardware.location.ContextHubTransaction sendMessage(@NonNull android.hardware.contexthub.HubMessage); } @FlaggedApi("android.chre.flags.offload_api") public class HubEndpointSessionResult { @@ -5308,7 +5179,7 @@ package android.hardware.contexthub { @FlaggedApi("android.chre.flags.offload_api") public interface IHubEndpointLifecycleCallback { method public void onSessionClosed(@NonNull android.hardware.contexthub.HubEndpointSession, int); - method @NonNull public android.hardware.contexthub.HubEndpointSessionResult onSessionOpenRequest(@NonNull android.hardware.contexthub.HubEndpointInfo, @Nullable android.hardware.contexthub.HubServiceInfo); + method @NonNull public android.hardware.contexthub.HubEndpointSessionResult onSessionOpenRequest(@NonNull android.hardware.contexthub.HubEndpointInfo, @Nullable String); method public void onSessionOpened(@NonNull android.hardware.contexthub.HubEndpointSession); } @@ -6314,7 +6185,7 @@ package android.hardware.location { method @Deprecated @RequiresPermission(android.Manifest.permission.ACCESS_CONTEXT_HUB) public int loadNanoApp(int, @NonNull android.hardware.location.NanoApp); method @NonNull @RequiresPermission(android.Manifest.permission.ACCESS_CONTEXT_HUB) public android.hardware.location.ContextHubTransaction loadNanoApp(@NonNull android.hardware.location.ContextHubInfo, @NonNull android.hardware.location.NanoAppBinary); method @FlaggedApi("android.chre.flags.offload_api") @RequiresPermission(android.Manifest.permission.ACCESS_CONTEXT_HUB) public void openSession(@NonNull android.hardware.contexthub.HubEndpoint, @NonNull android.hardware.contexthub.HubEndpointInfo); - method @FlaggedApi("android.chre.flags.offload_api") @RequiresPermission(android.Manifest.permission.ACCESS_CONTEXT_HUB) public void openSession(@NonNull android.hardware.contexthub.HubEndpoint, @NonNull android.hardware.contexthub.HubEndpointInfo, @NonNull android.hardware.contexthub.HubServiceInfo); + method @FlaggedApi("android.chre.flags.offload_api") @RequiresPermission(android.Manifest.permission.ACCESS_CONTEXT_HUB) public void openSession(@NonNull android.hardware.contexthub.HubEndpoint, @NonNull android.hardware.contexthub.HubEndpointInfo, @NonNull String); method @NonNull @RequiresPermission(android.Manifest.permission.ACCESS_CONTEXT_HUB) public android.hardware.location.ContextHubTransaction> queryNanoApps(@NonNull android.hardware.location.ContextHubInfo); method @Deprecated public int registerCallback(@NonNull android.hardware.location.ContextHubManager.Callback); method @Deprecated public int registerCallback(android.hardware.location.ContextHubManager.Callback, android.os.Handler); @@ -8118,14 +7989,17 @@ package android.media.musicrecognition { package android.media.quality { @FlaggedApi("android.media.tv.flags.media_quality_fw") public final class MediaQualityManager { + method public void addGlobalActiveProcessingPictureListener(@NonNull java.util.concurrent.Executor, @NonNull android.media.quality.MediaQualityManager.ActiveProcessingPictureListener); method @NonNull public java.util.List getPictureProfileAllowList(); method @NonNull public java.util.List getPictureProfilePackageNames(); - method @NonNull public java.util.List getPictureProfilesByPackage(@NonNull String); + method @NonNull public java.util.List getPictureProfilesByPackage(@NonNull String, boolean); method @NonNull public java.util.List getSoundProfileAllowList(); method @NonNull public java.util.List getSoundProfilePackageNames(); - method @NonNull public java.util.List getSoundProfilesByPackage(@NonNull String); + method @NonNull public java.util.List getSoundProfilesByPackage(@NonNull String, boolean); method public void setAutoPictureQualityEnabled(boolean); method public void setAutoSoundQualityEnabled(boolean); + method public boolean setDefaultPictureProfile(@Nullable String); + method public boolean setDefaultSoundProfile(@Nullable String); method public void setPictureProfileAllowList(@NonNull java.util.List); method public void setSoundProfileAllowList(@NonNull java.util.List); method public void setSuperResolutionEnabled(boolean); @@ -10614,28 +10488,6 @@ package android.net.util { } -package android.net.vcn { - - public class VcnManager { - method @RequiresPermission(android.Manifest.permission.NETWORK_FACTORY) public void addVcnNetworkPolicyChangeListener(@NonNull java.util.concurrent.Executor, @NonNull android.net.vcn.VcnManager.VcnNetworkPolicyChangeListener); - method @NonNull @RequiresPermission(android.Manifest.permission.NETWORK_FACTORY) public android.net.vcn.VcnNetworkPolicyResult applyVcnNetworkPolicy(@NonNull android.net.NetworkCapabilities, @NonNull android.net.LinkProperties); - method @RequiresPermission(android.Manifest.permission.NETWORK_FACTORY) public void removeVcnNetworkPolicyChangeListener(@NonNull android.net.vcn.VcnManager.VcnNetworkPolicyChangeListener); - } - - public static interface VcnManager.VcnNetworkPolicyChangeListener { - method public void onPolicyChanged(); - } - - public final class VcnNetworkPolicyResult implements android.os.Parcelable { - method public int describeContents(); - method @NonNull public android.net.NetworkCapabilities getNetworkCapabilities(); - method public boolean isTeardownRequested(); - method public void writeToParcel(@NonNull android.os.Parcel, int); - field @NonNull public static final android.os.Parcelable.Creator CREATOR; - } - -} - package android.net.wifi { public final class WifiKeystore { @@ -12625,6 +12477,7 @@ package android.provider { 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 @FlaggedApi("com.android.internal.telephony.flags.action_sim_preference_settings") public static final String ACTION_SIM_PREFERENCE_SETTINGS = "android.settings.SIM_PREFERENCE_SETTINGS"; 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"; @@ -12860,14 +12713,14 @@ package android.security.authenticationpolicy { } @FlaggedApi("android.security.secure_lockdown") public final class DisableSecureLockDeviceParams implements android.os.Parcelable { - ctor public DisableSecureLockDeviceParams(@NonNull String); + ctor public DisableSecureLockDeviceParams(@NonNull CharSequence); method public int describeContents(); method public void writeToParcel(@NonNull android.os.Parcel, int); field @NonNull public static final android.os.Parcelable.Creator CREATOR; } @FlaggedApi("android.security.secure_lockdown") public final class EnableSecureLockDeviceParams implements android.os.Parcelable { - ctor public EnableSecureLockDeviceParams(@NonNull String); + ctor public EnableSecureLockDeviceParams(@NonNull CharSequence); method public int describeContents(); method public void writeToParcel(@NonNull android.os.Parcel, int); field @NonNull public static final android.os.Parcelable.Creator CREATOR; @@ -13799,39 +13652,6 @@ package android.service.oemlock { } -package android.service.ondeviceintelligence { - - @FlaggedApi("android.app.ondeviceintelligence.flags.enable_on_device_intelligence") public abstract class OnDeviceIntelligenceService extends android.app.Service { - ctor public OnDeviceIntelligenceService(); - method @Nullable public final android.os.IBinder onBind(@NonNull android.content.Intent); - method public abstract void onDownloadFeature(int, @NonNull android.app.ondeviceintelligence.Feature, @Nullable android.os.CancellationSignal, @NonNull android.app.ondeviceintelligence.DownloadCallback); - method public abstract void onGetFeature(int, int, @NonNull android.os.OutcomeReceiver); - method public abstract void onGetFeatureDetails(int, @NonNull android.app.ondeviceintelligence.Feature, @NonNull android.os.OutcomeReceiver); - method public abstract void onGetReadOnlyFeatureFileDescriptorMap(@NonNull android.app.ondeviceintelligence.Feature, @NonNull java.util.function.Consumer>); - method public abstract void onGetVersion(@NonNull java.util.function.LongConsumer); - method public abstract void onInferenceServiceConnected(); - method public abstract void onInferenceServiceDisconnected(); - method public abstract void onListFeatures(int, @NonNull android.os.OutcomeReceiver,android.app.ondeviceintelligence.OnDeviceIntelligenceException>); - method public final void updateProcessingState(@NonNull android.os.Bundle, @NonNull java.util.concurrent.Executor, @NonNull android.os.OutcomeReceiver); - field public static final String SERVICE_INTERFACE = "android.service.ondeviceintelligence.OnDeviceIntelligenceService"; - } - - @FlaggedApi("android.app.ondeviceintelligence.flags.enable_on_device_intelligence") public abstract class OnDeviceSandboxedInferenceService extends android.app.Service { - ctor public OnDeviceSandboxedInferenceService(); - method public final void fetchFeatureFileDescriptorMap(@NonNull android.app.ondeviceintelligence.Feature, @NonNull java.util.concurrent.Executor, @NonNull java.util.function.Consumer>); - method @NonNull public java.util.concurrent.Executor getCallbackExecutor(); - method public final void getReadOnlyFileDescriptor(@NonNull String, @NonNull java.util.concurrent.Executor, @NonNull java.util.function.Consumer) throws java.io.FileNotFoundException; - method @Nullable public final android.os.IBinder onBind(@NonNull android.content.Intent); - method @NonNull public abstract void onProcessRequest(int, @NonNull android.app.ondeviceintelligence.Feature, @NonNull android.os.Bundle, int, @Nullable android.os.CancellationSignal, @Nullable android.app.ondeviceintelligence.ProcessingSignal, @NonNull android.app.ondeviceintelligence.ProcessingCallback); - method @NonNull public abstract void onProcessRequestStreaming(int, @NonNull android.app.ondeviceintelligence.Feature, @NonNull android.os.Bundle, int, @Nullable android.os.CancellationSignal, @Nullable android.app.ondeviceintelligence.ProcessingSignal, @NonNull android.app.ondeviceintelligence.StreamingProcessingCallback); - method @NonNull public abstract void onTokenInfoRequest(int, @NonNull android.app.ondeviceintelligence.Feature, @NonNull android.os.Bundle, @Nullable android.os.CancellationSignal, @NonNull android.os.OutcomeReceiver); - method public abstract void onUpdateProcessingState(@NonNull android.os.Bundle, @NonNull android.os.OutcomeReceiver); - method public final java.io.FileInputStream openFileInput(@NonNull String) throws java.io.FileNotFoundException; - field public static final String SERVICE_INTERFACE = "android.service.ondeviceintelligence.OnDeviceSandboxedInferenceService"; - } - -} - package android.service.persistentdata { @FlaggedApi("android.security.frp_enforcement") public class PersistentDataBlockManager { @@ -14812,7 +14632,7 @@ package android.telecom { field public static final int CALLTYPE_INCOMING = 1; // 0x1 field public static final int CALLTYPE_OUTGOING = 2; // 0x2 field public static final int CALLTYPE_UNKNOWN = 0; // 0x0 - field public static final int CDMA_PHONE = 1; // 0x1 + field @Deprecated @FlaggedApi("com.android.internal.telephony.flags.deprecate_cdma") public static final int CDMA_PHONE = 1; // 0x1 field @NonNull public static final android.os.Parcelable.Creator CREATOR; field public static final int GSM_PHONE = 2; // 0x2 field public static final int IMS_PHONE = 4; // 0x4 @@ -15193,7 +15013,7 @@ package android.telephony { field public static final String KEY_GBA_UA_SECURITY_ORGANIZATION_INT = "gba_ua_security_organization_int"; field public static final String KEY_GBA_UA_SECURITY_PROTOCOL_INT = "gba_ua_security_protocol_int"; field public static final String KEY_GBA_UA_TLS_CIPHER_SUITE_INT = "gba_ua_tls_cipher_suite_int"; - field public static final String KEY_SUPPORT_CDMA_1X_VOICE_CALLS_BOOL = "support_cdma_1x_voice_calls_bool"; + field @Deprecated @FlaggedApi("com.android.internal.telephony.flags.deprecate_cdma") public static final String KEY_SUPPORT_CDMA_1X_VOICE_CALLS_BOOL = "support_cdma_1x_voice_calls_bool"; } public static final class CarrierConfigManager.Wifi { @@ -15280,8 +15100,8 @@ package android.telephony { ctor public CellBroadcastService(); method @NonNull @WorkerThread public abstract CharSequence getCellBroadcastAreaInfo(int); method @CallSuper public android.os.IBinder onBind(@Nullable android.content.Intent); - method public abstract void onCdmaCellBroadcastSms(int, @NonNull byte[], int); - method public abstract void onCdmaScpMessage(int, @NonNull java.util.List, @NonNull String, @NonNull java.util.function.Consumer); + method @Deprecated @FlaggedApi("com.android.internal.telephony.flags.deprecate_cdma") public void onCdmaCellBroadcastSms(int, @NonNull byte[], int); + method @Deprecated @FlaggedApi("com.android.internal.telephony.flags.deprecate_cdma") public void onCdmaScpMessage(int, @NonNull java.util.List, @NonNull String, @NonNull java.util.function.Consumer); method public abstract void onGsmCellBroadcastSms(int, @NonNull byte[]); field public static final String CELL_BROADCAST_SERVICE_INTERFACE = "android.telephony.CellBroadcastService"; } @@ -15291,9 +15111,9 @@ package android.telephony { method @NonNull public abstract android.telephony.CellIdentity sanitizeLocationInfo(); } - public final class CellIdentityCdma extends android.telephony.CellIdentity { - method @NonNull public android.telephony.cdma.CdmaCellLocation asCellLocation(); - method @NonNull public android.telephony.CellIdentityCdma sanitizeLocationInfo(); + @Deprecated @FlaggedApi("com.android.internal.telephony.flags.deprecate_cdma") public final class CellIdentityCdma extends android.telephony.CellIdentity { + method @Deprecated @FlaggedApi("com.android.internal.telephony.flags.deprecate_cdma") @NonNull public android.telephony.cdma.CdmaCellLocation asCellLocation(); + method @Deprecated @FlaggedApi("com.android.internal.telephony.flags.deprecate_cdma") @NonNull public android.telephony.CellIdentityCdma sanitizeLocationInfo(); } public final class CellIdentityGsm extends android.telephony.CellIdentity { @@ -15709,16 +15529,16 @@ package android.telephony { field public static final int BUSY = 17; // 0x11 field public static final int CALL_BARRED = 240; // 0xf0 field public static final int CALL_REJECTED = 21; // 0x15 - field public static final int CDMA_ACCESS_BLOCKED = 1009; // 0x3f1 - field public static final int CDMA_ACCESS_FAILURE = 1006; // 0x3ee - field public static final int CDMA_DROP = 1001; // 0x3e9 - field public static final int CDMA_INTERCEPT = 1002; // 0x3ea - field public static final int CDMA_LOCKED_UNTIL_POWER_CYCLE = 1000; // 0x3e8 - field public static final int CDMA_NOT_EMERGENCY = 1008; // 0x3f0 - field public static final int CDMA_PREEMPTED = 1007; // 0x3ef - field public static final int CDMA_REORDER = 1003; // 0x3eb - field public static final int CDMA_RETRY_ORDER = 1005; // 0x3ed - field public static final int CDMA_SO_REJECT = 1004; // 0x3ec + field @Deprecated @FlaggedApi("com.android.internal.telephony.flags.deprecate_cdma") public static final int CDMA_ACCESS_BLOCKED = 1009; // 0x3f1 + field @Deprecated @FlaggedApi("com.android.internal.telephony.flags.deprecate_cdma") public static final int CDMA_ACCESS_FAILURE = 1006; // 0x3ee + field @Deprecated @FlaggedApi("com.android.internal.telephony.flags.deprecate_cdma") public static final int CDMA_DROP = 1001; // 0x3e9 + field @Deprecated @FlaggedApi("com.android.internal.telephony.flags.deprecate_cdma") public static final int CDMA_INTERCEPT = 1002; // 0x3ea + field @Deprecated @FlaggedApi("com.android.internal.telephony.flags.deprecate_cdma") public static final int CDMA_LOCKED_UNTIL_POWER_CYCLE = 1000; // 0x3e8 + field @Deprecated @FlaggedApi("com.android.internal.telephony.flags.deprecate_cdma") public static final int CDMA_NOT_EMERGENCY = 1008; // 0x3f0 + field @Deprecated @FlaggedApi("com.android.internal.telephony.flags.deprecate_cdma") public static final int CDMA_PREEMPTED = 1007; // 0x3ef + field @Deprecated @FlaggedApi("com.android.internal.telephony.flags.deprecate_cdma") public static final int CDMA_REORDER = 1003; // 0x3eb + field @Deprecated @FlaggedApi("com.android.internal.telephony.flags.deprecate_cdma") public static final int CDMA_RETRY_ORDER = 1005; // 0x3ed + field @Deprecated @FlaggedApi("com.android.internal.telephony.flags.deprecate_cdma") public static final int CDMA_SO_REJECT = 1004; // 0x3ec field public static final int CHANNEL_NOT_AVAIL = 44; // 0x2c field public static final int CHANNEL_UNACCEPTABLE = 6; // 0x6 field public static final int CONDITIONAL_IE_ERROR = 100; // 0x64 @@ -16252,14 +16072,14 @@ package android.telephony { method @Nullable @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public android.telephony.CarrierRestrictionRules getCarrierRestrictionRules(); method @Nullable @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public String getCarrierServicePackageName(); method @Nullable @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public String getCarrierServicePackageNameForLogicalSlot(int); - method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public int getCdmaEnhancedRoamingIndicatorDisplayNumber(); - method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public String getCdmaMdn(); - method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public String getCdmaMdn(int); - method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public String getCdmaMin(); - method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public String getCdmaMin(int); - method public String getCdmaPrlVersion(); - method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public int getCdmaRoamingMode(); - method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public int getCdmaSubscriptionMode(); + method @Deprecated @FlaggedApi("com.android.internal.telephony.flags.deprecate_cdma") @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public int getCdmaEnhancedRoamingIndicatorDisplayNumber(); + method @Deprecated @FlaggedApi("com.android.internal.telephony.flags.deprecate_cdma") @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public String getCdmaMdn(); + method @Deprecated @FlaggedApi("com.android.internal.telephony.flags.deprecate_cdma") @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public String getCdmaMdn(int); + method @Deprecated @FlaggedApi("com.android.internal.telephony.flags.deprecate_cdma") @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public String getCdmaMin(); + method @Deprecated @FlaggedApi("com.android.internal.telephony.flags.deprecate_cdma") @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public String getCdmaMin(int); + method @Deprecated @FlaggedApi("com.android.internal.telephony.flags.deprecate_cdma") public String getCdmaPrlVersion(); + method @Deprecated @FlaggedApi("com.android.internal.telephony.flags.deprecate_cdma") @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public int getCdmaRoamingMode(); + method @Deprecated @FlaggedApi("com.android.internal.telephony.flags.deprecate_cdma") @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public int getCdmaSubscriptionMode(); method @NonNull @RequiresPermission(android.Manifest.permission.MODIFY_CELL_BROADCASTS) public java.util.List getCellBroadcastIdRanges(); method public int getCurrentPhoneType(); method public int getCurrentPhoneType(int); @@ -16349,7 +16169,7 @@ package android.telephony { method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void resetCarrierKeysForImsiEncryption(); method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) @WorkerThread public void resetIms(int); method @RequiresPermission(android.Manifest.permission.READ_ACTIVE_EMERGENCY_SESSION) public void resetOtaEmergencyNumberDbFilePath(); - method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public boolean resetRadioConfig(); + method @Deprecated @FlaggedApi("com.android.internal.telephony.flags.deprecate_cdma") @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public boolean resetRadioConfig(); method @RequiresPermission(android.Manifest.permission.CONNECTIVITY_INTERNAL) public void resetSettings(); method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public int sendThermalMitigationRequest(@NonNull android.telephony.ThermalMitigationRequest); method @Deprecated @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public int setAllowedCarriers(int, java.util.List); @@ -16358,8 +16178,8 @@ package android.telephony { method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void setCallWaitingEnabled(boolean, @Nullable java.util.concurrent.Executor, @Nullable java.util.function.Consumer); method @Deprecated @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void setCarrierDataEnabled(boolean); method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public int setCarrierRestrictionRules(@NonNull android.telephony.CarrierRestrictionRules); - method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void setCdmaRoamingMode(int); - method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void setCdmaSubscriptionMode(int); + method @Deprecated @FlaggedApi("com.android.internal.telephony.flags.deprecate_cdma") @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void setCdmaRoamingMode(int); + method @Deprecated @FlaggedApi("com.android.internal.telephony.flags.deprecate_cdma") @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void setCdmaSubscriptionMode(int); method @RequiresPermission(android.Manifest.permission.MODIFY_CELL_BROADCASTS) public void setCellBroadcastIdRanges(@NonNull java.util.List, @NonNull java.util.concurrent.Executor, @NonNull java.util.function.Consumer); method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void setDataActivationState(int); method @Deprecated @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void setDataEnabled(int, boolean); @@ -16423,9 +16243,9 @@ package android.telephony { field public static final int CARRIER_PRIVILEGE_STATUS_HAS_ACCESS = 1; // 0x1 field public static final int CARRIER_PRIVILEGE_STATUS_NO_ACCESS = 0; // 0x0 field public static final int CARRIER_PRIVILEGE_STATUS_RULES_NOT_LOADED = -1; // 0xffffffff - field public static final int CDMA_SUBSCRIPTION_NV = 1; // 0x1 - field public static final int CDMA_SUBSCRIPTION_RUIM_SIM = 0; // 0x0 - field public static final int CDMA_SUBSCRIPTION_UNKNOWN = -1; // 0xffffffff + field @Deprecated @FlaggedApi("com.android.internal.telephony.flags.deprecate_cdma") public static final int CDMA_SUBSCRIPTION_NV = 1; // 0x1 + field @Deprecated @FlaggedApi("com.android.internal.telephony.flags.deprecate_cdma") public static final int CDMA_SUBSCRIPTION_RUIM_SIM = 0; // 0x0 + field @Deprecated @FlaggedApi("com.android.internal.telephony.flags.deprecate_cdma") public static final int CDMA_SUBSCRIPTION_UNKNOWN = -1; // 0xffffffff field public static final int CELL_BROADCAST_RESULT_FAIL_ACTIVATION = 3; // 0x3 field public static final int CELL_BROADCAST_RESULT_FAIL_CONFIG = 2; // 0x2 field public static final int CELL_BROADCAST_RESULT_SUCCESS = 0; // 0x0 @@ -16642,21 +16462,21 @@ package android.telephony { package android.telephony.cdma { - public final class CdmaSmsCbProgramData implements android.os.Parcelable { - method public int describeContents(); - method public int getCategory(); - method public int getOperation(); - method public void writeToParcel(android.os.Parcel, int); - field public static final int CATEGORY_CMAS_CHILD_ABDUCTION_EMERGENCY = 4099; // 0x1003 - field public static final int CATEGORY_CMAS_EXTREME_THREAT = 4097; // 0x1001 - field public static final int CATEGORY_CMAS_LAST_RESERVED_VALUE = 4351; // 0x10ff - field public static final int CATEGORY_CMAS_PRESIDENTIAL_LEVEL_ALERT = 4096; // 0x1000 - field public static final int CATEGORY_CMAS_SEVERE_THREAT = 4098; // 0x1002 - field public static final int CATEGORY_CMAS_TEST_MESSAGE = 4100; // 0x1004 - field @NonNull public static final android.os.Parcelable.Creator CREATOR; - field public static final int OPERATION_ADD_CATEGORY = 1; // 0x1 - field public static final int OPERATION_CLEAR_CATEGORIES = 2; // 0x2 - field public static final int OPERATION_DELETE_CATEGORY = 0; // 0x0 + @Deprecated @FlaggedApi("com.android.internal.telephony.flags.deprecate_cdma") public final class CdmaSmsCbProgramData implements android.os.Parcelable { + method @Deprecated @FlaggedApi("com.android.internal.telephony.flags.deprecate_cdma") public int describeContents(); + method @Deprecated @FlaggedApi("com.android.internal.telephony.flags.deprecate_cdma") public int getCategory(); + method @Deprecated @FlaggedApi("com.android.internal.telephony.flags.deprecate_cdma") public int getOperation(); + method @Deprecated @FlaggedApi("com.android.internal.telephony.flags.deprecate_cdma") public void writeToParcel(android.os.Parcel, int); + field @Deprecated @FlaggedApi("com.android.internal.telephony.flags.deprecate_cdma") public static final int CATEGORY_CMAS_CHILD_ABDUCTION_EMERGENCY = 4099; // 0x1003 + field @Deprecated @FlaggedApi("com.android.internal.telephony.flags.deprecate_cdma") public static final int CATEGORY_CMAS_EXTREME_THREAT = 4097; // 0x1001 + field @Deprecated @FlaggedApi("com.android.internal.telephony.flags.deprecate_cdma") public static final int CATEGORY_CMAS_LAST_RESERVED_VALUE = 4351; // 0x10ff + field @Deprecated @FlaggedApi("com.android.internal.telephony.flags.deprecate_cdma") public static final int CATEGORY_CMAS_PRESIDENTIAL_LEVEL_ALERT = 4096; // 0x1000 + field @Deprecated @FlaggedApi("com.android.internal.telephony.flags.deprecate_cdma") public static final int CATEGORY_CMAS_SEVERE_THREAT = 4098; // 0x1002 + field @Deprecated @FlaggedApi("com.android.internal.telephony.flags.deprecate_cdma") public static final int CATEGORY_CMAS_TEST_MESSAGE = 4100; // 0x1004 + field @Deprecated @FlaggedApi("com.android.internal.telephony.flags.deprecate_cdma") @NonNull public static final android.os.Parcelable.Creator CREATOR; + field @Deprecated @FlaggedApi("com.android.internal.telephony.flags.deprecate_cdma") public static final int OPERATION_ADD_CATEGORY = 1; // 0x1 + field @Deprecated @FlaggedApi("com.android.internal.telephony.flags.deprecate_cdma") public static final int OPERATION_CLEAR_CATEGORIES = 2; // 0x2 + field @Deprecated @FlaggedApi("com.android.internal.telephony.flags.deprecate_cdma") public static final int OPERATION_DELETE_CATEGORY = 0; // 0x0 } } @@ -17984,7 +17804,7 @@ package android.telephony.ims { field public static final int CAPABILITY_UPDATE_TRIGGER_ETAG_EXPIRED = 1; // 0x1 field public static final int CAPABILITY_UPDATE_TRIGGER_MOVE_TO_2G = 7; // 0x7 field public static final int CAPABILITY_UPDATE_TRIGGER_MOVE_TO_3G = 6; // 0x6 - field public static final int CAPABILITY_UPDATE_TRIGGER_MOVE_TO_EHRPD = 4; // 0x4 + field @Deprecated @FlaggedApi("com.android.internal.telephony.flags.deprecate_cdma") public static final int CAPABILITY_UPDATE_TRIGGER_MOVE_TO_EHRPD = 4; // 0x4 field public static final int CAPABILITY_UPDATE_TRIGGER_MOVE_TO_HSPAPLUS = 5; // 0x5 field public static final int CAPABILITY_UPDATE_TRIGGER_MOVE_TO_INTERNET_PDN = 12; // 0xc field public static final int CAPABILITY_UPDATE_TRIGGER_MOVE_TO_IWLAN = 9; // 0x9 @@ -18833,6 +18653,10 @@ package android.telephony.satellite { method @FlaggedApi("com.android.internal.telephony.flags.oem_enabled_satellite_flag") public void onSatelliteDatagramReceived(long, @NonNull android.telephony.satellite.SatelliteDatagram, int, @NonNull java.util.function.Consumer); } + @FlaggedApi("com.android.internal.telephony.flags.satellite_system_apis") public interface SatelliteDisallowedReasonsCallback { + method public void onSatelliteDisallowedReasonsChanged(@NonNull int[]); + } + @FlaggedApi("com.android.internal.telephony.flags.satellite_system_apis") public final class SatelliteInfo implements android.os.Parcelable { method public int describeContents(); method @NonNull public java.util.List getBands(); @@ -18848,6 +18672,7 @@ package android.telephony.satellite { method @FlaggedApi("com.android.internal.telephony.flags.satellite_system_apis") @RequiresPermission(android.Manifest.permission.SATELLITE_COMMUNICATION) public void deprovisionSatellite(@NonNull java.util.List, @NonNull java.util.concurrent.Executor, @NonNull android.os.OutcomeReceiver); method @FlaggedApi("com.android.internal.telephony.flags.oem_enabled_satellite_flag") @RequiresPermission(android.Manifest.permission.SATELLITE_COMMUNICATION) public void deprovisionService(@NonNull String, @NonNull java.util.concurrent.Executor, @NonNull java.util.function.Consumer); method @FlaggedApi("com.android.internal.telephony.flags.carrier_enabled_satellite_flag") @NonNull @RequiresPermission(android.Manifest.permission.SATELLITE_COMMUNICATION) public java.util.Set getAttachRestrictionReasonsForCarrier(int); + method @FlaggedApi("com.android.internal.telephony.flags.satellite_system_apis") @NonNull @RequiresPermission(android.Manifest.permission.SATELLITE_COMMUNICATION) public int[] getSatelliteDisallowedReasons(); method @FlaggedApi("com.android.internal.telephony.flags.carrier_enabled_satellite_flag") @NonNull @RequiresPermission(android.Manifest.permission.SATELLITE_COMMUNICATION) public java.util.List getSatellitePlmnsForCarrier(int); method @FlaggedApi("com.android.internal.telephony.flags.oem_enabled_satellite_flag") @RequiresPermission(android.Manifest.permission.SATELLITE_COMMUNICATION) public void pollPendingDatagrams(@NonNull java.util.concurrent.Executor, @NonNull java.util.function.Consumer); method @FlaggedApi("com.android.internal.telephony.flags.satellite_system_apis") @RequiresPermission(android.Manifest.permission.SATELLITE_COMMUNICATION) public void provisionSatellite(@NonNull java.util.List, @NonNull java.util.concurrent.Executor, @NonNull android.os.OutcomeReceiver); @@ -18858,6 +18683,8 @@ package android.telephony.satellite { method @FlaggedApi("com.android.internal.telephony.flags.oem_enabled_satellite_flag") @RequiresPermission(android.Manifest.permission.SATELLITE_COMMUNICATION) public int registerForModemStateChanged(@NonNull java.util.concurrent.Executor, @NonNull android.telephony.satellite.SatelliteModemStateCallback); method @FlaggedApi("com.android.internal.telephony.flags.oem_enabled_satellite_flag") @RequiresPermission(android.Manifest.permission.SATELLITE_COMMUNICATION) public void registerForNtnSignalStrengthChanged(@NonNull java.util.concurrent.Executor, @NonNull android.telephony.satellite.NtnSignalStrengthCallback); method @FlaggedApi("com.android.internal.telephony.flags.oem_enabled_satellite_flag") @RequiresPermission(android.Manifest.permission.SATELLITE_COMMUNICATION) public int registerForProvisionStateChanged(@NonNull java.util.concurrent.Executor, @NonNull android.telephony.satellite.SatelliteProvisionStateCallback); + method @FlaggedApi("com.android.internal.telephony.flags.satellite_system_apis") @RequiresPermission(android.Manifest.permission.SATELLITE_COMMUNICATION) public void registerForSatelliteDisallowedReasonsChanged(@NonNull java.util.concurrent.Executor, @NonNull android.telephony.satellite.SatelliteDisallowedReasonsCallback); + method @FlaggedApi("com.android.internal.telephony.flags.satellite_system_apis") @RequiresPermission(android.Manifest.permission.SATELLITE_COMMUNICATION) public int registerForSelectedNbIotSatelliteSubscriptionChanged(@NonNull java.util.concurrent.Executor, @NonNull android.telephony.satellite.SelectedNbIotSatelliteSubscriptionCallback); method @FlaggedApi("com.android.internal.telephony.flags.satellite_system_apis") @RequiresPermission(android.Manifest.permission.SATELLITE_COMMUNICATION) public int registerForSupportedStateChanged(@NonNull java.util.concurrent.Executor, @NonNull android.telephony.satellite.SatelliteSupportedStateCallback); method @FlaggedApi("com.android.internal.telephony.flags.carrier_enabled_satellite_flag") @RequiresPermission(android.Manifest.permission.SATELLITE_COMMUNICATION) public void removeAttachRestrictionForCarrier(int, int, @NonNull java.util.concurrent.Executor, @NonNull java.util.function.Consumer); method @FlaggedApi("com.android.internal.telephony.flags.carrier_enabled_satellite_flag") @RequiresPermission(android.Manifest.permission.SATELLITE_COMMUNICATION) public void requestAttachEnabledForCarrier(int, boolean, @NonNull java.util.concurrent.Executor, @NonNull java.util.function.Consumer); @@ -18871,7 +18698,10 @@ package android.telephony.satellite { method @FlaggedApi("com.android.internal.telephony.flags.oem_enabled_satellite_flag") @RequiresPermission(android.Manifest.permission.SATELLITE_COMMUNICATION) public void requestIsProvisioned(@NonNull java.util.concurrent.Executor, @NonNull android.os.OutcomeReceiver); method @FlaggedApi("com.android.internal.telephony.flags.oem_enabled_satellite_flag") public void requestIsSupported(@NonNull java.util.concurrent.Executor, @NonNull android.os.OutcomeReceiver); method @FlaggedApi("com.android.internal.telephony.flags.oem_enabled_satellite_flag") @RequiresPermission(android.Manifest.permission.SATELLITE_COMMUNICATION) public void requestNtnSignalStrength(@NonNull java.util.concurrent.Executor, @NonNull android.os.OutcomeReceiver); + method @FlaggedApi("com.android.internal.telephony.flags.satellite_system_apis") @RequiresPermission(android.Manifest.permission.SATELLITE_COMMUNICATION) public void requestSatelliteAccessConfigurationForCurrentLocation(@NonNull java.util.concurrent.Executor, @NonNull android.os.OutcomeReceiver); + method @FlaggedApi("com.android.internal.telephony.flags.satellite_system_apis") @RequiresPermission(android.Manifest.permission.SATELLITE_COMMUNICATION) public void requestSatelliteDisplayName(@NonNull java.util.concurrent.Executor, @NonNull android.os.OutcomeReceiver); method @FlaggedApi("com.android.internal.telephony.flags.satellite_system_apis") @RequiresPermission(android.Manifest.permission.SATELLITE_COMMUNICATION) public void requestSatelliteSubscriberProvisionStatus(@NonNull java.util.concurrent.Executor, @NonNull android.os.OutcomeReceiver,android.telephony.satellite.SatelliteManager.SatelliteException>); + method @FlaggedApi("com.android.internal.telephony.flags.satellite_system_apis") @RequiresPermission(android.Manifest.permission.SATELLITE_COMMUNICATION) public void requestSelectedNbIotSatelliteSubscriptionId(@NonNull java.util.concurrent.Executor, @NonNull android.os.OutcomeReceiver); method @FlaggedApi("com.android.internal.telephony.flags.oem_enabled_satellite_flag") @RequiresPermission(android.Manifest.permission.SATELLITE_COMMUNICATION) public void requestTimeForNextSatelliteVisibility(@NonNull java.util.concurrent.Executor, @NonNull android.os.OutcomeReceiver); method @FlaggedApi("com.android.internal.telephony.flags.oem_enabled_satellite_flag") @RequiresPermission(android.Manifest.permission.SATELLITE_COMMUNICATION) public void sendDatagram(int, @NonNull android.telephony.satellite.SatelliteDatagram, boolean, @NonNull java.util.concurrent.Executor, @NonNull java.util.function.Consumer); method @FlaggedApi("com.android.internal.telephony.flags.oem_enabled_satellite_flag") @RequiresPermission(android.Manifest.permission.SATELLITE_COMMUNICATION) public void setDeviceAlignedWithSatellite(boolean); @@ -18883,6 +18713,8 @@ package android.telephony.satellite { method @FlaggedApi("com.android.internal.telephony.flags.oem_enabled_satellite_flag") @RequiresPermission(android.Manifest.permission.SATELLITE_COMMUNICATION) public void unregisterForModemStateChanged(@NonNull android.telephony.satellite.SatelliteModemStateCallback); method @FlaggedApi("com.android.internal.telephony.flags.oem_enabled_satellite_flag") @RequiresPermission(android.Manifest.permission.SATELLITE_COMMUNICATION) public void unregisterForNtnSignalStrengthChanged(@NonNull android.telephony.satellite.NtnSignalStrengthCallback); method @FlaggedApi("com.android.internal.telephony.flags.oem_enabled_satellite_flag") @RequiresPermission(android.Manifest.permission.SATELLITE_COMMUNICATION) public void unregisterForProvisionStateChanged(@NonNull android.telephony.satellite.SatelliteProvisionStateCallback); + method @FlaggedApi("com.android.internal.telephony.flags.satellite_system_apis") @RequiresPermission(android.Manifest.permission.SATELLITE_COMMUNICATION) public void unregisterForSatelliteDisallowedReasonsChanged(@NonNull android.telephony.satellite.SatelliteDisallowedReasonsCallback); + method @FlaggedApi("com.android.internal.telephony.flags.satellite_system_apis") @RequiresPermission(android.Manifest.permission.SATELLITE_COMMUNICATION) public void unregisterForSelectedNbIotSatelliteSubscriptionChanged(@NonNull android.telephony.satellite.SelectedNbIotSatelliteSubscriptionCallback); method @FlaggedApi("com.android.internal.telephony.flags.satellite_system_apis") @RequiresPermission(android.Manifest.permission.SATELLITE_COMMUNICATION) public void unregisterForSupportedStateChanged(@NonNull android.telephony.satellite.SatelliteSupportedStateCallback); field @FlaggedApi("com.android.internal.telephony.flags.satellite_system_apis") public static final String ACTION_SATELLITE_START_NON_EMERGENCY_SESSION = "android.telephony.satellite.action.SATELLITE_START_NON_EMERGENCY_SESSION"; field @FlaggedApi("com.android.internal.telephony.flags.satellite_system_apis") public static final String ACTION_SATELLITE_SUBSCRIBER_ID_LIST_CHANGED = "android.telephony.satellite.action.SATELLITE_SUBSCRIBER_ID_LIST_CHANGED"; @@ -18954,6 +18786,7 @@ package android.telephony.satellite { field @FlaggedApi("com.android.internal.telephony.flags.oem_enabled_satellite_flag") public static final int SATELLITE_RESULT_NOT_REACHABLE = 18; // 0x12 field @FlaggedApi("com.android.internal.telephony.flags.oem_enabled_satellite_flag") public static final int SATELLITE_RESULT_NOT_SUPPORTED = 20; // 0x14 field @FlaggedApi("com.android.internal.telephony.flags.oem_enabled_satellite_flag") public static final int SATELLITE_RESULT_NO_RESOURCES = 12; // 0xc + field @FlaggedApi("com.android.internal.telephony.flags.satellite_system_apis") public static final int SATELLITE_RESULT_NO_VALID_SATELLITE_SUBSCRIPTION = 30; // 0x1e field @FlaggedApi("com.android.internal.telephony.flags.oem_enabled_satellite_flag") public static final int SATELLITE_RESULT_RADIO_NOT_AVAILABLE = 10; // 0xa field @FlaggedApi("com.android.internal.telephony.flags.oem_enabled_satellite_flag") public static final int SATELLITE_RESULT_REQUEST_ABORTED = 15; // 0xf field @FlaggedApi("com.android.internal.telephony.flags.oem_enabled_satellite_flag") public static final int SATELLITE_RESULT_REQUEST_FAILED = 9; // 0x9 @@ -19056,6 +18889,10 @@ package android.telephony.satellite { method @FlaggedApi("com.android.internal.telephony.flags.satellite_system_apis") public default void onSendDatagramStateChanged(int, int, int, int); } + @FlaggedApi("com.android.internal.telephony.flags.satellite_system_apis") public interface SelectedNbIotSatelliteSubscriptionCallback { + method public void onSelectedNbIotSatelliteSubscriptionChanged(int); + } + @FlaggedApi("com.android.internal.telephony.flags.satellite_system_apis") public final class SystemSelectionSpecifier implements android.os.Parcelable { method public int describeContents(); method @NonNull public int[] getBands(); @@ -19172,8 +19009,10 @@ package android.view { public static class WindowManager.LayoutParams extends android.view.ViewGroup.LayoutParams implements android.os.Parcelable { method public final long getUserActivityTimeout(); + method @FlaggedApi("com.android.hardware.input.override_power_key_behavior_in_focused_window") @RequiresPermission(android.Manifest.permission.OVERRIDE_SYSTEM_KEY_BEHAVIOR_IN_FOCUSED_WINDOW) public boolean isReceivePowerKeyDoublePressEnabled(); method public boolean isSystemApplicationOverlay(); method @FlaggedApi("android.companion.virtualdevice.flags.status_bar_and_insets") public void setInsetsParams(@NonNull java.util.List); + method @FlaggedApi("com.android.hardware.input.override_power_key_behavior_in_focused_window") @RequiresPermission(android.Manifest.permission.OVERRIDE_SYSTEM_KEY_BEHAVIOR_IN_FOCUSED_WINDOW) public void setReceivePowerKeyDoublePressEnabled(boolean); method @RequiresPermission(android.Manifest.permission.SYSTEM_APPLICATION_OVERLAY) public void setSystemApplicationOverlay(boolean); method public final void setUserActivityTimeout(long); field @RequiresPermission(android.Manifest.permission.HIDE_NON_SYSTEM_OVERLAY_WINDOWS) public static final int SYSTEM_FLAG_HIDE_NON_SYSTEM_OVERLAY_WINDOWS = 524288; // 0x80000 @@ -19299,6 +19138,20 @@ package android.view.inputmethod { } +package android.view.textclassifier { + + public final class TextClassificationManager { + method @FlaggedApi("android.permission.flags.text_classifier_choice_api_enabled") @NonNull @RequiresPermission(android.Manifest.permission.ACCESS_TEXT_CLASSIFIER_BY_TYPE) public android.view.textclassifier.TextClassifier getClassifier(int); + } + + public interface TextClassifier { + field @FlaggedApi("android.permission.flags.text_classifier_choice_api_enabled") public static final int CLASSIFIER_TYPE_ANDROID_DEFAULT = 2; // 0x2 + field @FlaggedApi("android.permission.flags.text_classifier_choice_api_enabled") public static final int CLASSIFIER_TYPE_DEVICE_DEFAULT = 1; // 0x1 + field @FlaggedApi("android.permission.flags.text_classifier_choice_api_enabled") public static final int CLASSIFIER_TYPE_SELF_PROVIDED = 0; // 0x0 + } + +} + package android.view.translation { public final class TranslationCapability implements android.os.Parcelable { diff --git a/core/api/system-lint-baseline.txt b/core/api/system-lint-baseline.txt index 7c43891f13f28527f0abe7841497ea8cdaeab004..3b9ef959e797d1d3a07417b9435e095edbeef5c9 100644 --- a/core/api/system-lint-baseline.txt +++ b/core/api/system-lint-baseline.txt @@ -505,6 +505,8 @@ DeprecationMismatch: javax.microedition.khronos.egl.EGL10#eglCreatePixmapSurface FlaggedApiLiteral: android.Manifest.permission#ACCESS_LAST_KNOWN_CELL_ID: @FlaggedApi contains a string literal, but should reference the field generated by aconfig (com.android.server.telecom.flags.Flags.FLAG_TELECOM_RESOLVE_HIDDEN_DEPENDENCIES). +FlaggedApiLiteral: android.Manifest.permission#ACCESS_TEXT_CLASSIFIER_BY_TYPE: + @FlaggedApi contains a string literal, but should reference the field generated by aconfig (android.permission.flags.Flags.FLAG_TEXT_CLASSIFIER_CHOICE_API_ENABLED). FlaggedApiLiteral: android.Manifest.permission#BACKUP_HEALTH_CONNECT_DATA_AND_SETTINGS: @FlaggedApi contains a string literal, but should reference the field generated by aconfig (android.permission.flags.Flags.FLAG_HEALTH_CONNECT_BACKUP_RESTORE_PERMISSION_ENABLED). FlaggedApiLiteral: android.Manifest.permission#BIND_VERIFICATION_AGENT: diff --git a/core/api/test-current.txt b/core/api/test-current.txt index 603677e89240a5a0cf66db070875ac5d17b75d64..6230a59a62c0b1f1b77ef5863145efb1e700237f 100644 --- a/core/api/test-current.txt +++ b/core/api/test-current.txt @@ -543,7 +543,6 @@ package android.app { method @FlaggedApi("com.android.window.flags.multi_crop") @RequiresPermission(android.Manifest.permission.SET_WALLPAPER) public int setBitmapWithCrops(@Nullable android.graphics.Bitmap, @NonNull java.util.Map, boolean, int) throws java.io.IOException; method @FlaggedApi("android.app.live_wallpaper_content_handling") @RequiresPermission(android.Manifest.permission.SET_WALLPAPER) public int setBitmapWithDescription(@Nullable android.graphics.Bitmap, @NonNull android.app.wallpaper.WallpaperDescription, boolean, int) throws java.io.IOException; method @FlaggedApi("com.android.window.flags.multi_crop") @RequiresPermission(android.Manifest.permission.SET_WALLPAPER) public int setStreamWithCrops(@NonNull java.io.InputStream, @NonNull java.util.Map, boolean, int) throws java.io.IOException; - method @FlaggedApi("android.app.live_wallpaper_content_handling") @RequiresPermission(android.Manifest.permission.SET_WALLPAPER) public int setStreamWithDescription(@NonNull java.io.InputStream, @NonNull android.app.wallpaper.WallpaperDescription, boolean, int) throws java.io.IOException; method public void setWallpaperZoomOut(@NonNull android.os.IBinder, float); method public boolean shouldEnableWideColorGamut(); method public boolean wallpaperSupportsWcg(int); @@ -658,6 +657,7 @@ package android.app.admin { field public static final int OPERATION_SET_ALWAYS_ON_VPN_PACKAGE = 30; // 0x1e field public static final int OPERATION_SET_APPLICATION_HIDDEN = 15; // 0xf field public static final int OPERATION_SET_APPLICATION_RESTRICTIONS = 16; // 0x10 + field @FlaggedApi("android.app.appfunctions.flags.enable_app_function_manager") public static final int OPERATION_SET_APP_FUNCTIONS_POLICY = 42; // 0x2a field public static final int OPERATION_SET_CAMERA_DISABLED = 31; // 0x1f field @FlaggedApi("android.view.contentprotection.flags.manage_device_policy_enabled") public static final int OPERATION_SET_CONTENT_PROTECTION_POLICY = 41; // 0x29 field public static final int OPERATION_SET_FACTORY_RESET_PROTECTION_POLICY = 32; // 0x20 @@ -3247,14 +3247,6 @@ package android.service.notification { } -package android.service.ondeviceintelligence { - - @FlaggedApi("android.app.ondeviceintelligence.flags.enable_on_device_intelligence") public abstract class OnDeviceIntelligenceService extends android.app.Service { - method public void onReady(); - } - -} - package android.service.quickaccesswallet { public interface QuickAccessWalletClient extends java.io.Closeable { diff --git a/core/api/test-lint-baseline.txt b/core/api/test-lint-baseline.txt index 9140bdf4fba790251139e9e4424fbec60acde3e6..349b4edffc32e2b07c53b9bf60bd1149b3a4c007 100644 --- a/core/api/test-lint-baseline.txt +++ b/core/api/test-lint-baseline.txt @@ -1,10 +1,4 @@ // Baseline format: 1.0 -ActionValue: android.view.contentcapture.ViewNode.ViewStructureImpl#EXTRA_VIRTUAL_STRUCTURE_TYPE: - Inconsistent extra value; expected `android.view.contentcapture.extra.VIRTUAL_STRUCTURE_TYPE`, was `android.view.ViewStructure.extra.VIRTUAL_STRUCTURE_TYPE` -ActionValue: android.view.contentcapture.ViewNode.ViewStructureImpl#EXTRA_VIRTUAL_STRUCTURE_VERSION_NUMBER: - Inconsistent extra value; expected `android.view.contentcapture.extra.VIRTUAL_STRUCTURE_VERSION_NUMBER`, was `android.view.ViewStructure.extra.VIRTUAL_STRUCTURE_VERSION_NUMBER` - - BannedThrow: android.os.vibrator.persistence.VibrationXmlSerializer#serialize(android.os.VibrationEffect, java.io.Writer): Methods must not throw unchecked exceptions diff --git a/core/java/android/app/Activity.java b/core/java/android/app/Activity.java index 38aea64386a0e32b32f400afeda298df8b63d6f8..03ef669c067520b6d7841cb97a21d4ddac5a5f4c 100644 --- a/core/java/android/app/Activity.java +++ b/core/java/android/app/Activity.java @@ -1279,7 +1279,24 @@ public class Activity extends ContextThemeWrapper * *

This method should be utilized when an activity wants to nudge the user to switch * to the web application in cases where the web may provide the user with a better - * experience. Note that this method does not guarantee that the education will be shown.

+ * experience. Note that this method does not guarantee that the education will be shown. + * + *

The number of times that the "Open in browser" education can be triggered by this method + * is limited per application, and, when shown, the education appears above the app's content. + * For these reasons, developers should use this method sparingly when it is least + * disruptive to the user to show the education and when it is optimal to switch the user to a + * browser session. Before requesting to show the education, developers should assert that they + * have set a link that can be used by the "Open in browser" feature through either + * {@link AssistContent#EXTRA_AUTHENTICATING_USER_WEB_URI} or + * {@link AssistContent#setWebUri} so that users are navigated to a relevant page if they choose + * to switch to the browser. If a URI is not set using either method, "Open in browser" will + * utilize a generic link if available which will direct users to the homepage of the site + * associated with the app. The generic link is provided for a limited number of applications by + * the system and cannot be edited by developers. If none of these options contains a valid URI, + * the user will not be provided with the option to switch to the browser and the education will + * not be shown if requested. + * + * @see android.app.assist.AssistContent#EXTRA_SESSION_TRANSFER_WEB_URI */ @FlaggedApi(com.android.window.flags.Flags.FLAG_ENABLE_DESKTOP_WINDOWING_APP_TO_WEB_EDUCATION) public final void requestOpenInBrowserEducation() { diff --git a/core/java/android/app/ActivityManager.java b/core/java/android/app/ActivityManager.java index 33ba0586504243a3fee4fd5bdc7f5ea2390565a9..69d3e8d4c0d2ef693984473fc4997993460c1a45 100644 --- a/core/java/android/app/ActivityManager.java +++ b/core/java/android/app/ActivityManager.java @@ -1189,6 +1189,18 @@ public class ActivityManager { return procState == PROCESS_STATE_FOREGROUND_SERVICE; } + /** @hide Should this process state be considered jank perceptible? */ + public static final boolean isProcStateJankPerceptible(int procState) { + if (Flags.jankPerceptibleNarrow()) { + return procState == PROCESS_STATE_PERSISTENT_UI + || procState == PROCESS_STATE_TOP + || procState == PROCESS_STATE_IMPORTANT_FOREGROUND + || procState == PROCESS_STATE_TOP_SLEEPING; + } else { + return !isProcStateCached(procState); + } + } + /** @hide requestType for assist context: only basic information. */ public static final int ASSIST_CONTEXT_BASIC = 0; diff --git a/core/java/android/app/ActivityManagerInternal.java b/core/java/android/app/ActivityManagerInternal.java index eccb6ffb281c34866fa8c8efe34c78fbdbf6f969..abdfb53537f89e1eb3046fff140ae2da44548256 100644 --- a/core/java/android/app/ActivityManagerInternal.java +++ b/core/java/android/app/ActivityManagerInternal.java @@ -44,6 +44,8 @@ import android.os.PowerExemptionManager.ReasonCode; import android.os.PowerExemptionManager.TempAllowListType; import android.os.TransactionTooLargeException; import android.os.WorkSource; +import android.os.instrumentation.IOffsetCallback; +import android.os.instrumentation.MethodDescriptor; import android.util.ArraySet; import android.util.Pair; @@ -1351,6 +1353,14 @@ public abstract class ActivityManagerInternal { public abstract void killApplicationSync(String pkgName, int appId, int userId, String reason, int exitInfoReason); + /** + * Queries the offset data for a given method on a process. + * @hide + */ + public abstract void getExecutableMethodFileOffsets(@NonNull String processName, + int pid, int uid, @NonNull MethodDescriptor methodDescriptor, + @NonNull IOffsetCallback callback); + /** * Add a creator token for all embedded intents (stored as extra) of the given intent. * diff --git a/core/java/android/app/ActivityThread.java b/core/java/android/app/ActivityThread.java index 3c1cce973b3a2fc5617505e0b7c8abcc960b7ad5..48b74f2d07767eeaf43893f028028f6caa3d2ab8 100644 --- a/core/java/android/app/ActivityThread.java +++ b/core/java/android/app/ActivityThread.java @@ -165,6 +165,10 @@ import android.os.TelephonyServiceManager; import android.os.Trace; import android.os.UserHandle; import android.os.UserManager; +import android.os.instrumentation.ExecutableMethodFileOffsets; +import android.os.instrumentation.IOffsetCallback; +import android.os.instrumentation.MethodDescriptor; +import android.os.instrumentation.MethodDescriptorParser; import android.permission.IPermissionManager; import android.provider.BlockedNumberContract; import android.provider.CalendarContract; @@ -1372,7 +1376,8 @@ public final class ActivityThread extends ClientTransactionHandler data.startRequestedElapsedTime = startRequestedElapsedTime; data.startRequestedUptime = startRequestedUptime; updateCompatOverrideScale(compatInfo); - CompatibilityInfo.applyOverrideScaleIfNeeded(config); + updateCompatOverrideDisplayRotation(compatInfo); + CompatibilityInfo.applyOverrideIfNeeded(config); sendMessage(H.BIND_APPLICATION, data); } @@ -1386,6 +1391,15 @@ public final class ActivityThread extends ClientTransactionHandler } } + private void updateCompatOverrideDisplayRotation(@NonNull CompatibilityInfo info) { + if (info.isOverrideDisplayRotationRequired()) { + CompatibilityInfo.setOverrideDisplayRotation(info.applicationDisplayRotation); + } else { + CompatibilityInfo.setOverrideDisplayRotation( + WindowConfiguration.ROTATION_UNDEFINED); + } + } + public final void runIsolatedEntryPoint(String entryPoint, String[] entryPointArgs) { SomeArgs args = SomeArgs.obtain(); args.arg1 = entryPoint; @@ -2036,6 +2050,7 @@ public final class ActivityThread extends ClientTransactionHandler ucd.pkg = pkg; ucd.info = info; updateCompatOverrideScale(info); + updateCompatOverrideDisplayRotation(info); sendMessage(H.UPDATE_PACKAGE_COMPATIBILITY_INFO, ucd); } @@ -2225,6 +2240,29 @@ public final class ActivityThread extends ClientTransactionHandler args.arg6 = uiTranslationSpec; sendMessage(H.UPDATE_UI_TRANSLATION_STATE, args); } + + @Override + public void getExecutableMethodFileOffsets( + @NonNull MethodDescriptor methodDescriptor, + @NonNull IOffsetCallback resultCallback) { + Method method = MethodDescriptorParser.parseMethodDescriptor( + getClass().getClassLoader(), methodDescriptor); + VMDebug.ExecutableMethodFileOffsets location = + VMDebug.getExecutableMethodFileOffsets(method); + try { + if (location == null) { + resultCallback.onResult(null); + return; + } + ExecutableMethodFileOffsets ret = new ExecutableMethodFileOffsets(); + ret.containerPath = location.getContainerPath(); + ret.containerOffset = location.getContainerOffset(); + ret.methodOffset = location.getMethodOffset(); + resultCallback.onResult(ret); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + } } private @NonNull SafeCancellationTransport createSafeCancellationTransport( @@ -3907,12 +3945,7 @@ public final class ActivityThread extends ClientTransactionHandler if (mLastProcessState == processState) { return; } - // Do not issue a transitional GC if we are transitioning between 2 cached states. - // Only update if the state flips between cached and uncached or vice versa - if (ActivityManager.isProcStateCached(mLastProcessState) - != ActivityManager.isProcStateCached(processState)) { - updateVmProcessState(processState); - } + updateVmProcessState(mLastProcessState, processState); mLastProcessState = processState; if (localLOGV) { Slog.i(TAG, "******************* PROCESS STATE CHANGED TO: " + processState @@ -3921,18 +3954,21 @@ public final class ActivityThread extends ClientTransactionHandler } } + /** Converts a process state to a VM process state. */ + private static int toVmProcessState(int processState) { + final int state = ActivityManager.isProcStateJankPerceptible(processState) + ? VM_PROCESS_STATE_JANK_PERCEPTIBLE + : VM_PROCESS_STATE_JANK_IMPERCEPTIBLE; + return state; + } + /** Update VM state based on ActivityManager.PROCESS_STATE_* constants. */ - // Currently ART VM only uses state updates for Transitional GC, and thus - // this function initiates a Transitional GC for transitions into Cached apps states. - private void updateVmProcessState(int processState) { - // Only a transition into Cached state should result in a Transitional GC request - // to the ART runtime. Update VM state to JANK_IMPERCEPTIBLE in that case. - // Note that there are 4 possible cached states currently, all of which are - // JANK_IMPERCEPTIBLE from GC point of view. - final int state = ActivityManager.isProcStateCached(processState) - ? VM_PROCESS_STATE_JANK_IMPERCEPTIBLE - : VM_PROCESS_STATE_JANK_PERCEPTIBLE; - VMRuntime.getRuntime().updateProcessState(state); + private void updateVmProcessState(int lastProcessState, int newProcessState) { + final int state = toVmProcessState(newProcessState); + if (lastProcessState == PROCESS_STATE_UNKNOWN + || state != toVmProcessState(lastProcessState)) { + VMRuntime.getRuntime().updateProcessState(state); + } } @Override @@ -5159,7 +5195,7 @@ public final class ActivityThread extends ClientTransactionHandler try { if (doRebind) { ActivityManager.getService().unbindFinished( - data.token, data.intent, doRebind); + data.token, data.intent); } else { ActivityManager.getService().serviceDoneExecuting( data.token, SERVICE_DONE_EXECUTING_UNBIND, 0, 0, data.intent); diff --git a/core/java/android/app/BroadcastStickyCache.java b/core/java/android/app/BroadcastStickyCache.java index fe2e1075235545c504d5e160383b5913df3a8f6c..1f627794a0f46a4e6628c524c1ab80d5fa17c0c8 100644 --- a/core/java/android/app/BroadcastStickyCache.java +++ b/core/java/android/app/BroadcastStickyCache.java @@ -35,6 +35,7 @@ import android.telephony.TelephonyManager; import android.util.ArrayMap; import android.view.WindowManagerPolicyConstants; +import com.android.internal.annotations.GuardedBy; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.util.ArrayUtils; @@ -71,8 +72,10 @@ public class BroadcastStickyCache { @VisibleForTesting public static final ArrayMap sActionApiNameMap = new ArrayMap<>(); + @GuardedBy("BroadcastStickyCache.class") private static final ArrayMap sActionConfigMap = new ArrayMap<>(); + @GuardedBy("BroadcastStickyCache.class") private static final ArrayMap> sFilterCacheMap = new ArrayMap<>(); @@ -154,37 +157,44 @@ public class BroadcastStickyCache { @Nullable String broadcastPermission, @UserIdInt int userId, @RegisterReceiverFlags int flags) { - IpcDataCache intentDataCache = findIpcDataCache(filter); - - if (intentDataCache == null) { - final String action = filter.getAction(0); - final StickyBroadcastFilter stickyBroadcastFilter = - new StickyBroadcastFilter(filter, action); - final Config config = getConfig(action); - - intentDataCache = - new IpcDataCache<>(config, - (query) -> ActivityManager.getService().registerReceiverWithFeature( - applicationThread, - mBasePackageName, - attributionTag, - /* receiverId= */ "null", - /* receiver= */ null, - filter, - broadcastPermission, - userId, - flags)); - sFilterCacheMap.put(stickyBroadcastFilter, intentDataCache); + IpcDataCache intentDataCache; + + synchronized (BroadcastStickyCache.class) { + intentDataCache = findIpcDataCache(filter); + + if (intentDataCache == null) { + final String action = filter.getAction(0); + final StickyBroadcastFilter stickyBroadcastFilter = + new StickyBroadcastFilter(filter, action); + final Config config = getConfig(action); + + intentDataCache = + new IpcDataCache<>(config, + (query) -> ActivityManager.getService().registerReceiverWithFeature( + applicationThread, + mBasePackageName, + attributionTag, + /* receiverId= */ "null", + /* receiver= */ null, + filter, + broadcastPermission, + userId, + flags)); + sFilterCacheMap.put(stickyBroadcastFilter, intentDataCache); + } } return intentDataCache.query(null); } @VisibleForTesting public static void clearCacheForTest() { - sFilterCacheMap.clear(); + synchronized (BroadcastStickyCache.class) { + sFilterCacheMap.clear(); + } } @Nullable + @GuardedBy("BroadcastStickyCache.class") private static IpcDataCache findIpcDataCache( @NonNull IntentFilter filter) { for (int i = sFilterCacheMap.size() - 1; i >= 0; i--) { @@ -198,12 +208,14 @@ public class BroadcastStickyCache { } @NonNull + @GuardedBy("BroadcastStickyCache.class") private static IpcDataCache.Config getConfig(@NonNull String action) { if (!sActionConfigMap.containsKey(action)) { // We only need 1 entry per cache but just to be on the safer side we are choosing 32 // although we don't expect more than 1. sActionConfigMap.put(action, - new Config(32, IpcDataCache.MODULE_SYSTEM, sActionApiNameMap.get(action))); + new Config(32, IpcDataCache.MODULE_SYSTEM, + sActionApiNameMap.get(action)).cacheNulls(true)); } return sActionConfigMap.get(action); diff --git a/core/java/android/app/CameraCompatTaskInfo.java b/core/java/android/app/CameraCompatTaskInfo.java index 432a0da15a47289f040b04c7ece9be1f8749fcb1..845d2acbaf9d05b36f80528fcccc5c4d0aa8ca10 100644 --- a/core/java/android/app/CameraCompatTaskInfo.java +++ b/core/java/android/app/CameraCompatTaskInfo.java @@ -16,11 +16,16 @@ package android.app; +import static android.app.WindowConfiguration.ROTATION_UNDEFINED; +import static android.view.Surface.ROTATION_0; +import static android.view.Surface.ROTATION_90; + import android.annotation.IntDef; import android.annotation.NonNull; import android.annotation.Nullable; import android.os.Parcel; import android.os.Parcelable; +import android.view.Surface; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; @@ -153,6 +158,27 @@ public class CameraCompatTaskInfo implements Parcelable { + "}"; } + /** + * Returns the sandboxed display rotation based on the given {@code cameraCompatMode}. + * + *

This will be what the app likely expects in its requested orientation while running on a + * device with portrait natural orientation: `CAMERA_COMPAT_FREEFORM_PORTRAIT_*` is 0, and + * `CAMERA_COMPAT_FREEFORM_LANDSCAPE_*` is 90. + * + * @return {@link WindowConfiguration#ROTATION_UNDEFINED} if not in camera compat mode. + */ + @Surface.Rotation + public static int getDisplayRotationFromCameraCompatMode(@FreeformCameraCompatMode int + cameraCompatMode) { + return switch (cameraCompatMode) { + case CAMERA_COMPAT_FREEFORM_PORTRAIT_DEVICE_IN_LANDSCAPE, + CAMERA_COMPAT_FREEFORM_PORTRAIT_DEVICE_IN_PORTRAIT -> ROTATION_0; + case CAMERA_COMPAT_FREEFORM_LANDSCAPE_DEVICE_IN_LANDSCAPE, + CAMERA_COMPAT_FREEFORM_LANDSCAPE_DEVICE_IN_PORTRAIT -> ROTATION_90; + default -> ROTATION_UNDEFINED; + }; + } + /** Human readable version of the freeform camera compat mode. */ @NonNull public static String freeformCameraCompatModeToString( diff --git a/core/java/android/app/IActivityManager.aidl b/core/java/android/app/IActivityManager.aidl index 50486611a5a9553678c8749930ffc927077b62a9..ad01ad57b2d880238f385b2f50418f7d6ba4ae82 100644 --- a/core/java/android/app/IActivityManager.aidl +++ b/core/java/android/app/IActivityManager.aidl @@ -321,7 +321,7 @@ interface IActivityManager { oneway void removeContentProvider(in IBinder connection, boolean stable); @UnsupportedAppUsage void setRequestedOrientation(in IBinder token, int requestedOrientation); - void unbindFinished(in IBinder token, in Intent service, boolean doRebind); + void unbindFinished(in IBinder token, in Intent service); @UnsupportedAppUsage void setProcessImportant(in IBinder token, int pid, boolean isForeground, String reason); void setServiceForeground(in ComponentName className, in IBinder token, diff --git a/core/java/android/app/IApplicationThread.aidl b/core/java/android/app/IApplicationThread.aidl index 06d01ecfcf06c0a2b4a63a7e4c3b0a53c074eda1..063501bf82a20874670877dbe0833704a240639e 100644 --- a/core/java/android/app/IApplicationThread.aidl +++ b/core/java/android/app/IApplicationThread.aidl @@ -46,6 +46,8 @@ import android.os.ParcelFileDescriptor; import android.os.PersistableBundle; import android.os.RemoteCallback; import android.os.SharedMemory; +import android.os.instrumentation.IOffsetCallback; +import android.os.instrumentation.MethodDescriptor; import android.view.autofill.AutofillId; import android.view.translation.TranslationSpec; import android.view.translation.UiTranslationSpec; @@ -183,4 +185,6 @@ oneway interface IApplicationThread { void scheduleTimeoutService(IBinder token, int startId); void scheduleTimeoutServiceForType(IBinder token, int startId, int fgsType); void schedulePing(in RemoteCallback pong); + void getExecutableMethodFileOffsets(in MethodDescriptor methodDescriptor, + in IOffsetCallback resultCallback); } diff --git a/core/java/android/app/Notification.java b/core/java/android/app/Notification.java index a4d8a5cd4673834e27f63dc2858a1fffd087d9af..f2d6c6ad81e5c6b6a2672007018997495c40e19c 100644 --- a/core/java/android/app/Notification.java +++ b/core/java/android/app/Notification.java @@ -3221,7 +3221,6 @@ public class Notification implements Parcelable /** * @hide */ - @FlaggedApi(Flags.FLAG_UI_RICH_ONGOING) public boolean containsCustomViews() { return contentView != null || bigContentView != null @@ -3235,7 +3234,6 @@ public class Notification implements Parcelable /** * @hide */ - @FlaggedApi(Flags.FLAG_UI_RICH_ONGOING) public boolean hasTitle() { return extras != null && (!TextUtils.isEmpty(extras.getCharSequence(EXTRA_TITLE)) @@ -3245,7 +3243,7 @@ public class Notification implements Parcelable /** * @hide */ - @FlaggedApi(Flags.FLAG_UI_RICH_ONGOING) + @FlaggedApi(Flags.FLAG_API_RICH_ONGOING) public boolean hasPromotableStyle() { final Class notificationStyle = getNotificationStyle(); @@ -3257,11 +3255,16 @@ public class Notification implements Parcelable } /** - * @hide + * Returns whether the notification has all the characteristics that make it eligible for + * {@link #FLAG_PROMOTED_ONGOING}. This method does not factor in other criteria such user + * preferences for the app or channel. If this returns true, it does not guarantee that the + * notification will be assigned FLAG_PROMOTED_ONGOING by the system, but if this returns false, + * it will not. */ - @FlaggedApi(Flags.FLAG_UI_RICH_ONGOING) + @FlaggedApi(Flags.FLAG_API_RICH_ONGOING) public boolean hasPromotableCharacteristics() { return isColorizedRequested() + && isOngoingEvent() && hasTitle() && !isGroupSummary() && !containsCustomViews() @@ -4155,6 +4158,13 @@ public class Notification implements Parcelable return extras.getString(EXTRA_SHORT_CRITICAL_TEXT); } + /** + * @hide + */ + public boolean isOngoingEvent() { + return (flags & FLAG_ONGOING_EVENT) != 0; + } + /** * @hide */ @@ -14829,10 +14839,7 @@ public class Notification implements Parcelable if (isColorized) { if (rawColor == COLOR_DEFAULT) { - int[] attrs = {R.attr.materialColorSecondary}; - try (TypedArray ta = obtainDayNightAttributes(ctx, attrs)) { - mBackgroundColor = getColor(ta, 0, Color.WHITE); - } + mBackgroundColor = ctx.getColor(R.color.materialColorSecondary); } else { mBackgroundColor = rawColor; } @@ -14864,30 +14871,25 @@ public class Notification implements Parcelable mRippleAlpha = 0x33; } else { int[] attrs = { - R.attr.materialColorSurfaceContainerHigh, - R.attr.materialColorOnSurface, - R.attr.materialColorOnSurfaceVariant, - R.attr.materialColorPrimary, - R.attr.materialColorSecondary, - R.attr.materialColorTertiary, - R.attr.materialColorOnTertiary, - R.attr.materialColorTertiaryFixedDim, - R.attr.materialColorOnTertiaryFixed, R.attr.colorError, R.attr.colorControlHighlight }; + + mBackgroundColor = ctx.getColor(R.color.materialColorSurfaceContainerHigh); + mPrimaryTextColor = ctx.getColor(R.color.materialColorOnSurface); + mSecondaryTextColor = ctx.getColor(R.color.materialColorOnSurfaceVariant); + mPrimaryAccentColor = ctx.getColor(R.color.materialColorPrimary); + mSecondaryAccentColor = ctx.getColor(R.color.materialColorSecondary); + mTertiaryAccentColor = ctx.getColor(R.color.materialColorTertiary); + mOnTertiaryAccentTextColor = ctx.getColor(R.color.materialColorOnTertiary); + mTertiaryFixedDimAccentColor = ctx.getColor( + R.color.materialColorTertiaryFixedDim); + mOnTertiaryFixedAccentTextColor = ctx.getColor( + R.color.materialColorOnTertiaryFixed); + try (TypedArray ta = obtainDayNightAttributes(ctx, attrs)) { - mBackgroundColor = getColor(ta, 0, nightMode ? Color.BLACK : Color.WHITE); - mPrimaryTextColor = getColor(ta, 1, COLOR_INVALID); - mSecondaryTextColor = getColor(ta, 2, COLOR_INVALID); - mPrimaryAccentColor = getColor(ta, 3, COLOR_INVALID); - mSecondaryAccentColor = getColor(ta, 4, COLOR_INVALID); - mTertiaryAccentColor = getColor(ta, 5, COLOR_INVALID); - mOnTertiaryAccentTextColor = getColor(ta, 6, COLOR_INVALID); - mTertiaryFixedDimAccentColor = getColor(ta, 7, COLOR_INVALID); - mOnTertiaryFixedAccentTextColor = getColor(ta, 8, COLOR_INVALID); - mErrorColor = getColor(ta, 9, COLOR_INVALID); - mRippleAlpha = Color.alpha(getColor(ta, 10, 0x33ffffff)); + mErrorColor = getColor(ta, 0, COLOR_INVALID); + mRippleAlpha = Color.alpha(getColor(ta, 1, 0x33ffffff)); } mContrastColor = calculateContrastColor(ctx, rawColor, mPrimaryAccentColor, mBackgroundColor, nightMode); diff --git a/core/java/android/app/NotificationManager.java b/core/java/android/app/NotificationManager.java index 87c86191203671df6699433524dd187930f70009..8ed66eb7e6c0fb206ea9570bf42269a45234b1be 100644 --- a/core/java/android/app/NotificationManager.java +++ b/core/java/android/app/NotificationManager.java @@ -49,7 +49,6 @@ import android.net.Uri; import android.os.Binder; import android.os.Build; import android.os.Bundle; -import android.os.Handler; import android.os.IBinder; import android.os.Parcel; import android.os.Parcelable; @@ -61,15 +60,18 @@ import android.provider.Settings; import android.provider.Settings.Global; import android.service.notification.Adjustment; import android.service.notification.Condition; +import android.service.notification.RateEstimator; import android.service.notification.StatusBarNotification; import android.service.notification.ZenDeviceEffects; import android.service.notification.ZenModeConfig; import android.service.notification.ZenPolicy; import android.util.Log; +import android.util.LruCache; import android.util.proto.ProtoOutputStream; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; +import java.time.InstantSource; import java.util.ArrayList; import java.util.Arrays; import java.util.HashMap; @@ -643,9 +645,17 @@ public class NotificationManager { */ public static int MAX_SERVICE_COMPONENT_NAME_LENGTH = 500; + private static final float MAX_NOTIFICATION_ENQUEUE_RATE = 5f; + + private final Context mContext; private final Map mCallNotificationEventCallbacks = new HashMap<>(); + private final InstantSource mClock; + private final RateEstimator mEnqueueRateEstimator = new RateEstimator(); + private final LruCache mEnqueuedNotificationKeys = new LruCache<>(10); + private final Object mEnqueueThrottleLock = new Object(); + @UnsupportedAppUsage private static INotificationManager sService; @@ -661,10 +671,17 @@ public class NotificationManager { return sService; } + /** @hide */ + protected INotificationManager service() { + return getService(); + } + + /** {@hide} */ @UnsupportedAppUsage - /*package*/ NotificationManager(Context context, Handler handler) + public NotificationManager(Context context, InstantSource clock) { mContext = context; + mClock = clock; } /** {@hide} */ @@ -736,7 +753,7 @@ public class NotificationManager { */ public void notifyAsPackage(@NonNull String targetPackage, @Nullable String tag, int id, @NonNull Notification notification) { - INotificationManager service = getService(); + INotificationManager service = service(); String sender = mContext.getPackageName(); try { @@ -752,13 +769,12 @@ public class NotificationManager { * @hide */ @UnsupportedAppUsage - public void notifyAsUser(String tag, int id, Notification notification, UserHandle user) + public void notifyAsUser(@Nullable String tag, int id, Notification notification, + UserHandle user) { - INotificationManager service = getService(); + INotificationManager service = service(); String pkg = mContext.getPackageName(); - - if (notificationClassification() - && NotificationChannel.SYSTEM_RESERVED_IDS.contains(notification.getChannelId())) { + if (discardNotify(tag, id, notification)) { return; } @@ -771,6 +787,37 @@ public class NotificationManager { } } + /** + * Determines whether a {@link #notify} call should be skipped. If the notification is not + * skipped, updates tracking metadata to use in future decisions. + */ + private boolean discardNotify(@Nullable String tag, int id, Notification notification) { + if (notificationClassification() + && NotificationChannel.SYSTEM_RESERVED_IDS.contains(notification.getChannelId())) { + return true; + } + + if (Flags.nmBinderPerfThrottleNotify()) { + String key = toEnqueuedNotificationKey(tag, id); + long now = mClock.millis(); + synchronized (mEnqueueThrottleLock) { + if (mEnqueuedNotificationKeys.get(key) != null + && !notification.hasCompletedProgress() + && mEnqueueRateEstimator.getRate(now) > MAX_NOTIFICATION_ENQUEUE_RATE) { + return true; + } + + mEnqueueRateEstimator.update(now); + mEnqueuedNotificationKeys.put(key, Boolean.TRUE); + } + } + + return false; + } + private static String toEnqueuedNotificationKey(@Nullable String tag, int id) { + return tag + "," + id; + } + private Notification fixNotification(Notification notification) { String pkg = mContext.getPackageName(); // Fix the notification as best we can. @@ -852,7 +899,7 @@ public class NotificationManager { * @param id An identifier for this notification. */ public void cancelAsPackage(@NonNull String targetPackage, @Nullable String tag, int id) { - INotificationManager service = getService(); + INotificationManager service = service(); try { service.cancelNotificationWithTag(targetPackage, mContext.getOpPackageName(), tag, id, mContext.getUser().getIdentifier()); @@ -865,9 +912,15 @@ public class NotificationManager { * @hide */ @UnsupportedAppUsage - public void cancelAsUser(String tag, int id, UserHandle user) + public void cancelAsUser(@Nullable String tag, int id, UserHandle user) { - INotificationManager service = getService(); + if (Flags.nmBinderPerfThrottleNotify()) { + synchronized (mEnqueueThrottleLock) { + mEnqueuedNotificationKeys.remove(toEnqueuedNotificationKey(tag, id)); + } + } + + INotificationManager service = service(); String pkg = mContext.getPackageName(); if (localLOGV) Log.v(TAG, pkg + ": cancel(" + id + ")"); try { @@ -884,7 +937,13 @@ public class NotificationManager { */ public void cancelAll() { - INotificationManager service = getService(); + if (Flags.nmBinderPerfThrottleNotify()) { + synchronized (mEnqueueThrottleLock) { + mEnqueuedNotificationKeys.evictAll(); + } + } + + INotificationManager service = service(); String pkg = mContext.getPackageName(); if (localLOGV) Log.v(TAG, pkg + ": cancelAll()"); try { @@ -907,7 +966,7 @@ public class NotificationManager { * @param delegate Package name of the app which can send notifications on your behalf. */ public void setNotificationDelegate(@Nullable String delegate) { - INotificationManager service = getService(); + INotificationManager service = service(); String pkg = mContext.getPackageName(); if (localLOGV) Log.v(TAG, pkg + ": cancelAll()"); try { @@ -922,7 +981,7 @@ public class NotificationManager { * your behalf, if there currently is one. */ public @Nullable String getNotificationDelegate() { - INotificationManager service = getService(); + INotificationManager service = service(); String pkg = mContext.getPackageName(); try { return service.getNotificationDelegate(pkg); @@ -938,7 +997,7 @@ public class NotificationManager { * See {@link #setNotificationDelegate(String)}. */ public boolean canNotifyAsPackage(@NonNull String pkg) { - INotificationManager service = getService(); + INotificationManager service = service(); try { return service.canNotifyAsPackage(mContext.getPackageName(), pkg, mContext.getUserId()); } catch (RemoteException e) { @@ -956,7 +1015,7 @@ public class NotificationManager { * {@link android.provider.Settings#ACTION_MANAGE_APP_USE_FULL_SCREEN_INTENT}. */ public boolean canUseFullScreenIntent() { - INotificationManager service = getService(); + INotificationManager service = service(); try { return service.canUseFullScreenIntent(mContext.getAttributionSource()); } catch (RemoteException e) { @@ -974,7 +1033,7 @@ public class NotificationManager { */ @FlaggedApi(android.app.Flags.FLAG_API_RICH_ONGOING) public boolean canPostPromotedNotifications() { - INotificationManager service = getService(); + INotificationManager service = service(); try { return service.canBePromoted(mContext.getPackageName()); } catch (RemoteException e) { @@ -989,7 +1048,7 @@ public class NotificationManager { @TestApi @FlaggedApi(android.app.Flags.FLAG_API_RICH_ONGOING) public void setCanPostPromotedNotifications(@NonNull String pkg, int uid, boolean allowed) { - INotificationManager service = getService(); + INotificationManager service = service(); try { service.setCanBePromoted(pkg, uid, allowed, true); } catch (RemoteException e) { @@ -1024,7 +1083,7 @@ public class NotificationManager { * @param groups The list of groups to create */ public void createNotificationChannelGroups(@NonNull List groups) { - INotificationManager service = getService(); + INotificationManager service = service(); try { service.createNotificationChannelGroups(mContext.getPackageName(), new ParceledListSlice(groups)); @@ -1067,7 +1126,7 @@ public class NotificationManager { * @param channels the list of channels to attempt to create. */ public void createNotificationChannels(@NonNull List channels) { - INotificationManager service = getService(); + INotificationManager service = service(); try { service.createNotificationChannels(mContext.getPackageName(), new ParceledListSlice(channels)); @@ -1085,7 +1144,7 @@ public class NotificationManager { * package (see {@link Context#createPackageContext(String, int)}).

*/ public NotificationChannel getNotificationChannel(String channelId) { - INotificationManager service = getService(); + INotificationManager service = service(); try { return service.getNotificationChannel(mContext.getOpPackageName(), mContext.getUserId(), mContext.getPackageName(), channelId); @@ -1105,7 +1164,7 @@ public class NotificationManager { */ public @Nullable NotificationChannel getNotificationChannel(@NonNull String channelId, @NonNull String conversationId) { - INotificationManager service = getService(); + INotificationManager service = service(); try { return service.getConversationNotificationChannel(mContext.getOpPackageName(), mContext.getUserId(), mContext.getPackageName(), channelId, true, @@ -1124,7 +1183,7 @@ public class NotificationManager { * {@link Context#createPackageContext(String, int)}).

*/ public List getNotificationChannels() { - INotificationManager service = getService(); + INotificationManager service = service(); try { return service.getNotificationChannels(mContext.getOpPackageName(), mContext.getPackageName(), mContext.getUserId()).getList(); @@ -1145,7 +1204,7 @@ public class NotificationManager { && NotificationChannel.SYSTEM_RESERVED_IDS.contains(channelId)) { return; } - INotificationManager service = getService(); + INotificationManager service = service(); try { service.deleteNotificationChannel(mContext.getPackageName(), channelId); } catch (RemoteException e) { @@ -1159,7 +1218,7 @@ public class NotificationManager { * The channel group must belong to your package, or null will be returned. */ public NotificationChannelGroup getNotificationChannelGroup(String channelGroupId) { - INotificationManager service = getService(); + INotificationManager service = service(); try { return service.getNotificationChannelGroup(mContext.getPackageName(), channelGroupId); } catch (RemoteException e) { @@ -1171,7 +1230,7 @@ public class NotificationManager { * Returns all notification channel groups belonging to the calling app. */ public List getNotificationChannelGroups() { - INotificationManager service = getService(); + INotificationManager service = service(); try { final ParceledListSlice parceledList = service.getNotificationChannelGroups(mContext.getPackageName()); @@ -1189,7 +1248,7 @@ public class NotificationManager { * belong to it. */ public void deleteNotificationChannelGroup(String groupId) { - INotificationManager service = getService(); + INotificationManager service = service(); try { service.deleteNotificationChannelGroup(mContext.getPackageName(), groupId); } catch (RemoteException e) { @@ -1203,7 +1262,7 @@ public class NotificationManager { @TestApi public void updateNotificationChannel(@NonNull String pkg, int uid, @NonNull NotificationChannel channel) { - INotificationManager service = getService(); + INotificationManager service = service(); try { service.updateNotificationChannelForPackage(pkg, uid, channel); } catch (RemoteException e) { @@ -1216,7 +1275,7 @@ public class NotificationManager { */ @TestApi public ComponentName getEffectsSuppressor() { - INotificationManager service = getService(); + INotificationManager service = service(); try { return service.getEffectsSuppressor(); } catch (RemoteException e) { @@ -1228,7 +1287,7 @@ public class NotificationManager { * @hide */ public boolean matchesCallFilter(Bundle extras) { - INotificationManager service = getService(); + INotificationManager service = service(); try { return service.matchesCallFilter(extras); } catch (RemoteException e) { @@ -1241,7 +1300,7 @@ public class NotificationManager { */ @TestApi public void cleanUpCallersAfter(long timeThreshold) { - INotificationManager service = getService(); + INotificationManager service = service(); try { service.cleanUpCallersAfter(timeThreshold); } catch (RemoteException e) { @@ -1253,7 +1312,7 @@ public class NotificationManager { * @hide */ public boolean isSystemConditionProviderEnabled(String path) { - INotificationManager service = getService(); + INotificationManager service = service(); try { return service.isSystemConditionProviderEnabled(path); } catch (RemoteException e) { @@ -1271,7 +1330,7 @@ public class NotificationManager { /** @hide */ public void setZenMode(int mode, Uri conditionId, String reason, boolean fromUser) { - INotificationManager service = getService(); + INotificationManager service = service(); try { service.setZenMode(mode, conditionId, reason, fromUser); } catch (RemoteException e) { @@ -1284,7 +1343,7 @@ public class NotificationManager { * @hide */ public int getZenMode() { - INotificationManager service = getService(); + INotificationManager service = service(); try { return service.getZenMode(); } catch (RemoteException e) { @@ -1297,7 +1356,7 @@ public class NotificationManager { */ @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) public ZenModeConfig getZenModeConfig() { - INotificationManager service = getService(); + INotificationManager service = service(); try { return service.getZenModeConfig(); } catch (RemoteException e) { @@ -1315,7 +1374,7 @@ public class NotificationManager { *

*/ public @NonNull NotificationManager.Policy getConsolidatedNotificationPolicy() { - INotificationManager service = getService(); + INotificationManager service = service(); try { return service.getConsolidatedNotificationPolicy(); } catch (RemoteException e) { @@ -1327,7 +1386,7 @@ public class NotificationManager { * @hide */ public int getRuleInstanceCount(ComponentName owner) { - INotificationManager service = getService(); + INotificationManager service = service(); try { return service.getRuleInstanceCount(owner); } catch (RemoteException e) { @@ -1364,7 +1423,7 @@ public class NotificationManager { * See {@link #isNotificationPolicyAccessGranted}. */ public Map getAutomaticZenRules() { - INotificationManager service = getService(); + INotificationManager service = service(); try { if (Flags.modesApi()) { return service.getAutomaticZenRules(); @@ -1398,7 +1457,7 @@ public class NotificationManager { * doesn't own the matching rule. See {@link AutomaticZenRule#getOwner}. */ public AutomaticZenRule getAutomaticZenRule(String id) { - INotificationManager service = getService(); + INotificationManager service = service(); try { return service.getAutomaticZenRule(id); } catch (RemoteException e) { @@ -1426,7 +1485,7 @@ public class NotificationManager { @NonNull public String addAutomaticZenRule(@NonNull AutomaticZenRule automaticZenRule, boolean fromUser) { - INotificationManager service = getService(); + INotificationManager service = service(); try { return service.addAutomaticZenRule(automaticZenRule, mContext.getPackageName(), fromUser); @@ -1461,7 +1520,7 @@ public class NotificationManager { @FlaggedApi(Flags.FLAG_MODES_API) public boolean updateAutomaticZenRule(@NonNull String id, @NonNull AutomaticZenRule automaticZenRule, boolean fromUser) { - INotificationManager service = getService(); + INotificationManager service = service(); try { return service.updateAutomaticZenRule(id, automaticZenRule, fromUser); } catch (RemoteException e) { @@ -1481,7 +1540,7 @@ public class NotificationManager { @FlaggedApi(Flags.FLAG_MODES_API) @Condition.State public int getAutomaticZenRuleState(@NonNull String id) { - INotificationManager service = getService(); + INotificationManager service = service(); try { return service.getAutomaticZenRuleState(id); } catch (RemoteException e) { @@ -1527,7 +1586,7 @@ public class NotificationManager { * @param condition The new state of this rule */ public void setAutomaticZenRuleState(@NonNull String id, @NonNull Condition condition) { - INotificationManager service = getService(); + INotificationManager service = service(); try { service.setAutomaticZenRuleState(id, condition); } catch (RemoteException e) { @@ -1555,7 +1614,7 @@ public class NotificationManager { @TestApi @FlaggedApi(Flags.FLAG_MODES_API) public boolean removeAutomaticZenRule(@NonNull String id, boolean fromUser) { - INotificationManager service = getService(); + INotificationManager service = service(); try { return service.removeAutomaticZenRule(id, fromUser); } catch (RemoteException e) { @@ -1574,7 +1633,7 @@ public class NotificationManager { /** @hide */ public boolean removeAutomaticZenRules(String packageName, boolean fromUser) { - INotificationManager service = getService(); + INotificationManager service = service(); try { return service.removeAutomaticZenRules(packageName, fromUser); } catch (RemoteException e) { @@ -1587,7 +1646,7 @@ public class NotificationManager { * package. */ public @Importance int getImportance() { - INotificationManager service = getService(); + INotificationManager service = service(); try { return service.getPackageImportance(mContext.getPackageName()); } catch (RemoteException e) { @@ -1602,7 +1661,7 @@ public class NotificationManager { if (Flags.nmBinderPerfPermissionCheck()) { return mContext.checkSelfPermission(POST_NOTIFICATIONS) == PERMISSION_GRANTED; } else { - INotificationManager service = getService(); + INotificationManager service = service(); try { return service.areNotificationsEnabled(mContext.getPackageName()); } catch (RemoteException e) { @@ -1623,7 +1682,7 @@ public class NotificationManager { */ @Deprecated public boolean areBubblesAllowed() { - INotificationManager service = getService(); + INotificationManager service = service(); try { return service.areBubblesAllowed(mContext.getPackageName()); } catch (RemoteException e) { @@ -1638,7 +1697,7 @@ public class NotificationManager { * @see Notification.Builder#setBubbleMetadata(Notification.BubbleMetadata) */ public boolean areBubblesEnabled() { - INotificationManager service = getService(); + INotificationManager service = service(); try { return service.areBubblesEnabled(mContext.getUser()); } catch (RemoteException e) { @@ -1665,7 +1724,7 @@ public class NotificationManager { * @return the users' bubble preference for the app. */ public @BubblePreference int getBubblePreference() { - INotificationManager service = getService(); + INotificationManager service = service(); try { return service.getBubblePreferenceForPackage(mContext.getPackageName(), Binder.getCallingUid()); @@ -1685,7 +1744,7 @@ public class NotificationManager { * @hide */ public void silenceNotificationSound() { - INotificationManager service = getService(); + INotificationManager service = service(); try { service.silenceNotificationSound(); } catch (RemoteException e) { @@ -1701,7 +1760,7 @@ public class NotificationManager { * PersistableBundle, SuspendDialogInfo) suspended}. */ public boolean areNotificationsPaused() { - INotificationManager service = getService(); + INotificationManager service = service(); try { return service.isPackagePaused(mContext.getPackageName()); } catch (RemoteException e) { @@ -1724,7 +1783,7 @@ public class NotificationManager { * user grant or denial of this access. */ public boolean isNotificationPolicyAccessGranted() { - INotificationManager service = getService(); + INotificationManager service = service(); try { return service.isNotificationPolicyAccessGranted(mContext.getOpPackageName()); } catch (RemoteException e) { @@ -1745,7 +1804,7 @@ public class NotificationManager { * {@link android.provider.Settings#ACTION_NOTIFICATION_LISTENER_SETTINGS}. */ public boolean isNotificationListenerAccessGranted(ComponentName listener) { - INotificationManager service = getService(); + INotificationManager service = service(); try { return service.isNotificationListenerAccessGranted(listener); } catch (RemoteException e) { @@ -1769,7 +1828,7 @@ public class NotificationManager { */ @SystemApi public boolean isNotificationAssistantAccessGranted(@NonNull ComponentName assistant) { - INotificationManager service = getService(); + INotificationManager service = service(); try { return service.isNotificationAssistantAccessGranted(assistant); } catch (RemoteException e) { @@ -1785,7 +1844,7 @@ public class NotificationManager { * listeners}. */ public boolean shouldHideSilentStatusBarIcons() { - INotificationManager service = getService(); + INotificationManager service = service(); try { return service.shouldHideSilentStatusIcons(mContext.getOpPackageName()); } catch (RemoteException e) { @@ -1804,7 +1863,7 @@ public class NotificationManager { */ @SystemApi public @NonNull @Adjustment.Keys List getAllowedAssistantAdjustments() { - INotificationManager service = getService(); + INotificationManager service = service(); try { return service.getAllowedAssistantAdjustments(mContext.getOpPackageName()); } catch (RemoteException e) { @@ -1818,7 +1877,7 @@ public class NotificationManager { @TestApi @FlaggedApi(android.service.notification.Flags.FLAG_NOTIFICATION_CLASSIFICATION) public void allowAssistantAdjustment(@NonNull String capability) { - INotificationManager service = getService(); + INotificationManager service = service(); try { service.allowAssistantAdjustment(capability); } catch (RemoteException e) { @@ -1832,7 +1891,7 @@ public class NotificationManager { @TestApi @FlaggedApi(android.service.notification.Flags.FLAG_NOTIFICATION_CLASSIFICATION) public void disallowAssistantAdjustment(@NonNull String capability) { - INotificationManager service = getService(); + INotificationManager service = service(); try { service.disallowAssistantAdjustment(capability); } catch (RemoteException e) { @@ -1843,7 +1902,7 @@ public class NotificationManager { /** @hide */ @TestApi public boolean isNotificationPolicyAccessGrantedForPackage(@NonNull String pkg) { - INotificationManager service = getService(); + INotificationManager service = service(); try { return service.isNotificationPolicyAccessGrantedForPackage(pkg); } catch (RemoteException e) { @@ -1857,7 +1916,7 @@ public class NotificationManager { @TestApi @FlaggedApi(android.service.notification.Flags.FLAG_NOTIFICATION_CLASSIFICATION) public void setAssistantAdjustmentKeyTypeState(@Adjustment.Types int type, boolean enabled) { - INotificationManager service = getService(); + INotificationManager service = service(); try { service.setAssistantAdjustmentKeyTypeState(type, enabled); } catch (RemoteException e) { @@ -1870,7 +1929,7 @@ public class NotificationManager { */ @FlaggedApi(android.app.Flags.FLAG_NOTIFICATION_CLASSIFICATION_UI) public void setTypeAdjustmentForPackageState(@NonNull String pkg, boolean enabled) { - INotificationManager service = getService(); + INotificationManager service = service(); try { service.setTypeAdjustmentForPackageState(pkg, enabled); } catch (RemoteException e) { @@ -1882,7 +1941,7 @@ public class NotificationManager { * @hide */ public List getEnabledNotificationListenerPackages() { - INotificationManager service = getService(); + INotificationManager service = service(); try { return service.getEnabledNotificationListenerPackages(); } catch (RemoteException e) { @@ -1899,7 +1958,7 @@ public class NotificationManager { * {@link #setNotificationPolicy(Policy)}. */ public Policy getNotificationPolicy() { - INotificationManager service = getService(); + INotificationManager service = service(); try { return service.getNotificationPolicy(mContext.getOpPackageName()); } catch (RemoteException e) { @@ -1929,7 +1988,7 @@ public class NotificationManager { /** @hide */ public void setNotificationPolicy(@NonNull Policy policy, boolean fromUser) { checkRequired("policy", policy); - INotificationManager service = getService(); + INotificationManager service = service(); try { service.setNotificationPolicy(mContext.getOpPackageName(), policy, fromUser); } catch (RemoteException e) { @@ -1939,7 +1998,7 @@ public class NotificationManager { /** @hide */ public void setNotificationPolicyAccessGranted(String pkg, boolean granted) { - INotificationManager service = getService(); + INotificationManager service = service(); try { service.setNotificationPolicyAccessGranted(pkg, granted); } catch (RemoteException e) { @@ -1959,7 +2018,7 @@ public class NotificationManager { @TestApi @FlaggedApi(Flags.FLAG_MODES_API) public @NonNull ZenPolicy getDefaultZenPolicy() { - INotificationManager service = getService(); + INotificationManager service = service(); try { return service.getDefaultZenPolicy(); } catch (RemoteException e) { @@ -1971,7 +2030,7 @@ public class NotificationManager { */ @FlaggedApi(Flags.FLAG_MODES_UI) public void setManualZenRuleDeviceEffects(@NonNull ZenDeviceEffects effects) { - INotificationManager service = getService(); + INotificationManager service = service(); try { service.setManualZenRuleDeviceEffects(effects); } catch (RemoteException e) { @@ -2008,7 +2067,7 @@ public class NotificationManager { @RequiresPermission(android.Manifest.permission.MANAGE_NOTIFICATION_LISTENERS) public void setNotificationListenerAccessGranted( @NonNull ComponentName listener, boolean granted, boolean userSet) { - INotificationManager service = getService(); + INotificationManager service = service(); try { if (CompatChanges.isChangeEnabled(SET_LISTENER_ACCESS_GRANTED_IS_USER_AWARE)) { service.setNotificationListenerAccessGrantedForUser(listener, mContext.getUserId(), @@ -2024,7 +2083,7 @@ public class NotificationManager { /** @hide */ public void setNotificationListenerAccessGrantedForUser(ComponentName listener, int userId, boolean granted) { - INotificationManager service = getService(); + INotificationManager service = service(); try { service.setNotificationListenerAccessGrantedForUser(listener, userId, granted, true); } catch (RemoteException e) { @@ -2045,7 +2104,7 @@ public class NotificationManager { @SystemApi public void setNotificationAssistantAccessGranted(@Nullable ComponentName assistant, boolean granted) { - INotificationManager service = getService(); + INotificationManager service = service(); try { service.setNotificationAssistantAccessGranted(assistant, granted); } catch (RemoteException e) { @@ -2069,7 +2128,7 @@ public class NotificationManager { /** @hide */ public List getEnabledNotificationListeners(int userId) { - INotificationManager service = getService(); + INotificationManager service = service(); try { return service.getEnabledNotificationListeners(userId); } catch (RemoteException e) { @@ -2080,7 +2139,7 @@ public class NotificationManager { /** @hide */ @SystemApi public @Nullable ComponentName getAllowedNotificationAssistant() { - INotificationManager service = getService(); + INotificationManager service = service(); try { return service.getAllowedNotificationAssistant(); } catch (RemoteException e) { @@ -2100,16 +2159,13 @@ public class NotificationManager { @SuppressLint("UserHandle") public boolean hasEnabledNotificationListener(@NonNull String packageName, @NonNull UserHandle userHandle) { - INotificationManager service = getService(); + INotificationManager service = service(); try { return service.hasEnabledNotificationListener(packageName, userHandle.getIdentifier()); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } } - - private Context mContext; - private static void checkRequired(String name, Object value) { if (value == null) { throw new IllegalArgumentException(name + " is required"); @@ -2125,7 +2181,7 @@ public class NotificationManager { @TestApi @RequiresPermission(android.Manifest.permission.MANAGE_TOAST_RATE_LIMITING) public void setToastRateLimitingEnabled(boolean enable) { - INotificationManager service = getService(); + INotificationManager service = service(); try { service.setToastRateLimitingEnabled(enable); } catch (RemoteException e) { @@ -2917,7 +2973,7 @@ public class NotificationManager { * @return An array of {@link StatusBarNotification}. */ public StatusBarNotification[] getActiveNotifications() { - final INotificationManager service = getService(); + final INotificationManager service = service(); final String pkg = mContext.getPackageName(); try { final ParceledListSlice parceledList @@ -2940,7 +2996,7 @@ public class NotificationManager { * globally. */ public final @InterruptionFilter int getCurrentInterruptionFilter() { - final INotificationManager service = getService(); + final INotificationManager service = service(); try { return zenModeToInterruptionFilter(service.getZenMode()); } catch (RemoteException e) { @@ -2972,7 +3028,7 @@ public class NotificationManager { /** @hide */ public final void setInterruptionFilter(@InterruptionFilter int interruptionFilter, boolean fromUser) { - final INotificationManager service = getService(); + final INotificationManager service = service(); try { service.setInterruptionFilter(mContext.getOpPackageName(), interruptionFilter, fromUser); @@ -3130,7 +3186,7 @@ public class NotificationManager { checkRequired("userHandle", userHandle); checkRequired("executor", executor); checkRequired("listener", listener); - INotificationManager service = getService(); + INotificationManager service = service(); try { synchronized (mCallNotificationEventCallbacks) { CallNotificationEventCallbackStub callbackStub = @@ -3161,7 +3217,7 @@ public class NotificationManager { public void unregisterCallNotificationEventListener( @NonNull CallNotificationEventListener listener) { checkRequired("listener", listener); - INotificationManager service = getService(); + INotificationManager service = service(); try { synchronized (mCallNotificationEventCallbacks) { CallNotificationEventCallbackStub callbackStub = @@ -3184,7 +3240,7 @@ public class NotificationManager { @TestApi @FlaggedApi(android.service.notification.Flags.FLAG_NOTIFICATION_CLASSIFICATION) public @NonNull Set getUnsupportedAdjustmentTypes() { - INotificationManager service = getService(); + INotificationManager service = service(); try { return new HashSet<>(service.getUnsupportedAdjustmentTypes()); } catch (RemoteException e) { diff --git a/core/java/android/app/PropertyInvalidatedCache.java b/core/java/android/app/PropertyInvalidatedCache.java index 3973c58c070841d1952633606edb29e0551243fb..1e971a5c736a8f2053fd8f4ed122afbfc230889a 100644 --- a/core/java/android/app/PropertyInvalidatedCache.java +++ b/core/java/android/app/PropertyInvalidatedCache.java @@ -79,6 +79,17 @@ import java.util.concurrent.atomic.AtomicLong; @TestApi @android.ravenwood.annotation.RavenwoodKeepWholeClass public class PropertyInvalidatedCache { + /** + * A method to report if the PermissionManager notifications can be separated from cache + * invalidation. The feature relies on a series of flags; the dependency is captured in this + * method. + * @hide + */ + public static boolean separatePermissionNotificationsEnabled() { + return isSharedMemoryAvailable() + && Flags.picSeparatePermissionNotifications(); + } + /** * This is a configuration class that customizes a cache instance. * @hide @@ -1283,6 +1294,13 @@ public class PropertyInvalidatedCache { public static record Args(@NonNull String mModule, @Nullable String mApi, int mMaxEntries, boolean mIsolateUids, boolean mTestMode, boolean mCacheNulls) { + /** + * Default values for fields. + */ + public static final int DEFAULT_MAX_ENTRIES = 32; + public static final boolean DEFAULT_ISOLATE_UIDS = true; + public static final boolean DEFAULT_CACHE_NULLS = false; + // Validation: the module must be one of the known module strings and the maxEntries must // be positive. public Args { @@ -1297,10 +1315,10 @@ public class PropertyInvalidatedCache { public Args(@NonNull String module) { this(module, null, // api - 32, // maxEntries - true, // isolateUids + DEFAULT_MAX_ENTRIES, + DEFAULT_ISOLATE_UIDS, false, // testMode - true // allowNulls + DEFAULT_CACHE_NULLS ); } @@ -1350,7 +1368,7 @@ public class PropertyInvalidatedCache { * Burst a property name into module and api. Throw if the key is invalid. This method is * used in to transition legacy cache constructors to the args constructor. */ - private static Args parseProperty(@NonNull String name) { + private static Args argsFromProperty(@NonNull String name) { throwIfInvalidCacheKey(name); // Strip off the leading well-known prefix. String base = name.substring(CACHE_KEY_PREFIX.length() + 1); @@ -1373,8 +1391,9 @@ public class PropertyInvalidatedCache { * * @hide */ + @Deprecated public PropertyInvalidatedCache(int maxEntries, @NonNull String propertyName) { - this(parseProperty(propertyName).maxEntries(maxEntries), propertyName, null); + this(argsFromProperty(propertyName).maxEntries(maxEntries), propertyName, null); } /** @@ -1388,9 +1407,10 @@ public class PropertyInvalidatedCache { * @param cacheName Name of this cache in debug and dumpsys * @hide */ + @Deprecated public PropertyInvalidatedCache(int maxEntries, @NonNull String propertyName, @NonNull String cacheName) { - this(parseProperty(propertyName).maxEntries(maxEntries), cacheName, null); + this(argsFromProperty(propertyName).maxEntries(maxEntries), cacheName, null); } /** @@ -1845,6 +1865,14 @@ public class PropertyInvalidatedCache { invalidateCache(createPropertyName(module, api)); } + /** + * Invalidate caches in all processes that have the module and api specified in the args. + * @hide + */ + public static void invalidateCache(@NonNull Args args) { + invalidateCache(createPropertyName(args.mModule, args.mApi)); + } + /** * Invalidate PropertyInvalidatedCache caches in all processes that are keyed on * {@var name}. This function is synchronous: caches are invalidated upon return. @@ -1921,6 +1949,10 @@ public class PropertyInvalidatedCache { } public AutoCorker(@NonNull String propertyName, int autoCorkDelayMs) { + if (separatePermissionNotificationsEnabled()) { + throw new IllegalStateException("AutoCorking is unavailable"); + } + mPropertyName = propertyName; mAutoCorkDelayMs = autoCorkDelayMs; // We can't initialize mHandler here: when we're created, the main loop might not diff --git a/core/java/android/app/ResourcesManager.java b/core/java/android/app/ResourcesManager.java index 3cffca796680f98c418928306e7f62b2d486ecff..51d0b18467f4efb44731522b42c2eb65087fefb8 100644 --- a/core/java/android/app/ResourcesManager.java +++ b/core/java/android/app/ResourcesManager.java @@ -1517,10 +1517,8 @@ public class ResourcesManager { int changes = mResConfiguration.updateFrom(config); if (compat != null && (mResCompatibilityInfo == null || !mResCompatibilityInfo.equals(compat))) { + changes |= compat.getCompatibilityChangesForConfig(mResCompatibilityInfo); mResCompatibilityInfo = compat; - changes |= ActivityInfo.CONFIG_SCREEN_LAYOUT - | ActivityInfo.CONFIG_SCREEN_SIZE - | ActivityInfo.CONFIG_SMALLEST_SCREEN_SIZE; } // If a application info update was scheduled to occur in this process but has not diff --git a/core/java/android/app/SystemServiceRegistry.java b/core/java/android/app/SystemServiceRegistry.java index 2bd2d34d54a24d923277f6519f9c31c647aefa34..920b19cd8f78ffe51fbadb3d0d22274597da88f3 100644 --- a/core/java/android/app/SystemServiceRegistry.java +++ b/core/java/android/app/SystemServiceRegistry.java @@ -42,8 +42,7 @@ import android.app.contentsuggestions.IContentSuggestionsManager; import android.app.contextualsearch.ContextualSearchManager; import android.app.ecm.EnhancedConfirmationFrameworkInitializer; import android.app.job.JobSchedulerFrameworkInitializer; -import android.app.ondeviceintelligence.IOnDeviceIntelligenceManager; -import android.app.ondeviceintelligence.OnDeviceIntelligenceManager; +import android.app.ondeviceintelligence.OnDeviceIntelligenceFrameworkInitializer; import android.app.people.PeopleManager; import android.app.prediction.AppPredictionManager; import android.app.role.RoleFrameworkInitializer; @@ -82,8 +81,6 @@ import android.content.ContentCaptureOptions; import android.content.Context; import android.content.IRestrictionsManager; import android.content.RestrictionsManager; -import android.content.integrity.AppIntegrityManager; -import android.content.integrity.IAppIntegrityManager; import android.content.om.IOverlayManager; import android.content.om.OverlayManager; import android.content.pm.ApplicationInfo; @@ -292,6 +289,7 @@ import com.android.internal.os.IDropBoxManagerService; import com.android.internal.policy.PhoneLayoutInflater; import com.android.internal.util.Preconditions; +import java.time.InstantSource; import java.util.Map; import java.util.Objects; @@ -628,7 +626,7 @@ public final class SystemServiceRegistry { com.android.internal.R.style.Theme_Holo_Dialog, com.android.internal.R.style.Theme_DeviceDefault_Dialog, com.android.internal.R.style.Theme_DeviceDefault_Light_Dialog)), - ctx.mMainThread.getHandler()); + InstantSource.system()); }}); registerService(Context.PEOPLE_SERVICE, PeopleManager.class, @@ -1581,16 +1579,6 @@ public final class SystemServiceRegistry { return new AttestationVerificationManager(ctx.getOuterContext(), IAttestationVerificationManagerService.Stub.asInterface(b)); }}); - - //CHECKSTYLE:ON IndentationCheck - registerService(Context.APP_INTEGRITY_SERVICE, AppIntegrityManager.class, - new CachedServiceFetcher() { - @Override - public AppIntegrityManager createService(ContextImpl ctx) - throws ServiceNotFoundException { - IBinder b = ServiceManager.getServiceOrThrow(Context.APP_INTEGRITY_SERVICE); - return new AppIntegrityManager(IAppIntegrityManager.Stub.asInterface(b)); - }}); registerService(Context.APP_HIBERNATION_SERVICE, AppHibernationManager.class, new CachedServiceFetcher() { @Override @@ -1704,19 +1692,6 @@ public final class SystemServiceRegistry { throw new ServiceNotFoundException(Context.WEARABLE_SENSING_SERVICE); }}); - registerService(Context.ON_DEVICE_INTELLIGENCE_SERVICE, OnDeviceIntelligenceManager.class, - new CachedServiceFetcher() { - @Override - public OnDeviceIntelligenceManager createService(ContextImpl ctx) - throws ServiceNotFoundException { - IBinder iBinder = ServiceManager.getServiceOrThrow( - Context.ON_DEVICE_INTELLIGENCE_SERVICE); - IOnDeviceIntelligenceManager manager = - IOnDeviceIntelligenceManager.Stub.asInterface(iBinder); - return new OnDeviceIntelligenceManager(ctx.getOuterContext(), manager); - } - }); - registerService(Context.GRAMMATICAL_INFLECTION_SERVICE, GrammaticalInflectionManager.class, new CachedServiceFetcher() { @Override @@ -1861,6 +1836,7 @@ public final class SystemServiceRegistry { ConnectivityFrameworkInitializerTiramisu.registerServiceWrappers(); NearbyFrameworkInitializer.registerServiceWrappers(); OnDevicePersonalizationFrameworkInitializer.registerServiceWrappers(); + OnDeviceIntelligenceFrameworkInitializer.registerServiceWrappers(); DeviceLockFrameworkInitializer.registerServiceWrappers(); VirtualizationFrameworkInitializer.registerServiceWrappers(); ConnectivityFrameworkInitializerBaklava.registerServiceWrappers(); diff --git a/core/java/android/app/TaskInfo.java b/core/java/android/app/TaskInfo.java index 01cc9d82d56d591be11a141ea6d6d10edda7ba45..76705dcdd3d2a0ebbe8104ba73970b5629068489 100644 --- a/core/java/android/app/TaskInfo.java +++ b/core/java/android/app/TaskInfo.java @@ -308,11 +308,17 @@ public class TaskInfo { public boolean isSleeping; /** - * Whether the top activity fillsParent() is false + * Whether the top activity fillsParent() is false. * @hide */ public boolean isTopActivityTransparent; + /** + * Whether fillsParent() is false for every activity in the tasks stack. + * @hide + */ + public boolean isActivityStackTransparent; + /** * The last non-fullscreen bounds the task was launched in or resized to. * @hide @@ -489,6 +495,7 @@ public class TaskInfo { && parentTaskId == that.parentTaskId && Objects.equals(topActivity, that.topActivity) && isTopActivityTransparent == that.isTopActivityTransparent + && isActivityStackTransparent == that.isActivityStackTransparent && Objects.equals(lastNonFullscreenBounds, that.lastNonFullscreenBounds) && Objects.equals(capturedLink, that.capturedLink) && capturedLinkTimestamp == that.capturedLinkTimestamp @@ -567,6 +574,7 @@ public class TaskInfo { mTopActivityLocusId = source.readTypedObject(LocusId.CREATOR); displayAreaFeatureId = source.readInt(); isTopActivityTransparent = source.readBoolean(); + isActivityStackTransparent = source.readBoolean(); lastNonFullscreenBounds = source.readTypedObject(Rect.CREATOR); capturedLink = source.readTypedObject(Uri.CREATOR); capturedLinkTimestamp = source.readLong(); @@ -623,6 +631,7 @@ public class TaskInfo { dest.writeTypedObject(mTopActivityLocusId, flags); dest.writeInt(displayAreaFeatureId); dest.writeBoolean(isTopActivityTransparent); + dest.writeBoolean(isActivityStackTransparent); dest.writeTypedObject(lastNonFullscreenBounds, flags); dest.writeTypedObject(capturedLink, flags); dest.writeLong(capturedLinkTimestamp); @@ -668,6 +677,7 @@ public class TaskInfo { + " locusId=" + mTopActivityLocusId + " displayAreaFeatureId=" + displayAreaFeatureId + " isTopActivityTransparent=" + isTopActivityTransparent + + " isActivityStackTransparent=" + isActivityStackTransparent + " lastNonFullscreenBounds=" + lastNonFullscreenBounds + " capturedLink=" + capturedLink + " capturedLinkTimestamp=" + capturedLinkTimestamp diff --git a/core/java/android/app/WallpaperManager.java b/core/java/android/app/WallpaperManager.java index a8671cf746193d9bd00848477bfb9b334436e2e9..89e25e7d1b4f37b76edce334fec4165ca1844217 100644 --- a/core/java/android/app/WallpaperManager.java +++ b/core/java/android/app/WallpaperManager.java @@ -2092,7 +2092,7 @@ public class WallpaperManager { /** * Returns the description of the designated wallpaper. Returns null if the lock screen - * wallpaper is requested lock screen wallpaper is not set. + * wallpaper is requested and lock screen wallpaper is not set. * @param which Specifies wallpaper to request (home or lock). * @throws IllegalArgumentException if {@code which} is not exactly one of @@ -2733,7 +2733,7 @@ public class WallpaperManager { * @hide */ @FlaggedApi(FLAG_LIVE_WALLPAPER_CONTENT_HANDLING) - @TestApi + @SystemApi @RequiresPermission(android.Manifest.permission.SET_WALLPAPER) public int setStreamWithDescription(@NonNull InputStream bitmapData, @NonNull WallpaperDescription description, boolean allowBackup, diff --git a/core/java/android/app/activity_manager.aconfig b/core/java/android/app/activity_manager.aconfig index 44940aee6a49c58b8acb7937d78b986427b43d0b..720e045dc9440c10647d09ad4772de4a3104b0fd 100644 --- a/core/java/android/app/activity_manager.aconfig +++ b/core/java/android/app/activity_manager.aconfig @@ -51,16 +51,6 @@ flag { } } -flag { - namespace: "backstage_power" - name: "gate_fgs_timeout_anr_behavior" - description: "Gate the new behavior where an ANR is thrown once an FGS times out." - bug: "339315145" - metadata { - purpose: PURPOSE_BUGFIX - } -} - flag { namespace: "backstage_power" name: "enable_fgs_timeout_crash_behavior" @@ -166,3 +156,10 @@ flag { bug: "362537357" is_exported: true } + +flag { + name: "jank_perceptible_narrow" + namespace: "system_performance" + description: "Narrow the scope of Jank Perceptible" + bug: "304837972" +} diff --git a/core/java/android/app/admin/DevicePolicyIdentifiers.java b/core/java/android/app/admin/DevicePolicyIdentifiers.java index 35149b5a31357f9497538dbecdfdac4c72066129..89261a4f85ee4f7d39cd6cc67c093a4f243bf6c9 100644 --- a/core/java/android/app/admin/DevicePolicyIdentifiers.java +++ b/core/java/android/app/admin/DevicePolicyIdentifiers.java @@ -20,6 +20,7 @@ import android.annotation.FlaggedApi; import android.annotation.NonNull; import android.annotation.SystemApi; import android.annotation.TestApi; +import android.app.appfunctions.flags.Flags; import android.os.UserManager; import java.util.Objects; @@ -180,6 +181,12 @@ public final class DevicePolicyIdentifiers { @FlaggedApi(android.view.contentprotection.flags.Flags.FLAG_MANAGE_DEVICE_POLICY_ENABLED) public static final String CONTENT_PROTECTION_POLICY = "contentProtection"; + /** + * String identifier for {@link DevicePolicyManager#setAppFunctionsPolicy(int)}. + */ + @FlaggedApi(Flags.FLAG_ENABLE_APP_FUNCTION_MANAGER) + public static final String APP_FUNCTIONS_POLICY = "appFunctions"; + /** * String identifier for {@link DevicePolicyManager#setUsbDataSignalingEnabled}. */ diff --git a/core/java/android/app/admin/DevicePolicyManager.java b/core/java/android/app/admin/DevicePolicyManager.java index 8372078b46a59ba6534ca2d299a3cd1fe03d2527..9ddc729850c4cb2d32b18187d41190891465f6d6 100644 --- a/core/java/android/app/admin/DevicePolicyManager.java +++ b/core/java/android/app/admin/DevicePolicyManager.java @@ -23,6 +23,7 @@ import static android.Manifest.permission.LOCK_DEVICE; import static android.Manifest.permission.MANAGE_DEVICE_ADMINS; import static android.Manifest.permission.MANAGE_DEVICE_POLICY_ACCOUNT_MANAGEMENT; import static android.Manifest.permission.MANAGE_DEVICE_POLICY_APPS_CONTROL; +import static android.Manifest.permission.MANAGE_DEVICE_POLICY_APP_FUNCTIONS; import static android.Manifest.permission.MANAGE_DEVICE_POLICY_CAMERA; import static android.Manifest.permission.MANAGE_DEVICE_POLICY_CERTIFICATES; import static android.Manifest.permission.MANAGE_DEVICE_POLICY_COMMON_CRITERIA_MODE; @@ -3931,6 +3932,11 @@ public class DevicePolicyManager { @FlaggedApi(android.view.contentprotection.flags.Flags.FLAG_MANAGE_DEVICE_POLICY_ENABLED) public static final int OPERATION_SET_CONTENT_PROTECTION_POLICY = 41; + /** @hide */ + @TestApi + @FlaggedApi(android.app.appfunctions.flags.Flags.FLAG_ENABLE_APP_FUNCTION_MANAGER) + public static final int OPERATION_SET_APP_FUNCTIONS_POLICY = 42; + private static final String PREFIX_OPERATION = "OPERATION_"; /** @hide */ @@ -3975,7 +3981,8 @@ public class DevicePolicyManager { OPERATION_SET_PERMISSION_POLICY, OPERATION_SET_RESTRICTIONS_PROVIDER, OPERATION_UNINSTALL_CA_CERT, - OPERATION_SET_CONTENT_PROTECTION_POLICY + OPERATION_SET_CONTENT_PROTECTION_POLICY, + OPERATION_SET_APP_FUNCTIONS_POLICY }) @Retention(RetentionPolicy.SOURCE) public static @interface DevicePolicyOperation { @@ -4346,6 +4353,90 @@ public class DevicePolicyManager { return CONTENT_PROTECTION_DISABLED; } + /** + * Indicates that app functions are not controlled by policy. + * + *

If no admin set this policy, it means appfunctions are enabled. + */ + @FlaggedApi(android.app.appfunctions.flags.Flags.FLAG_ENABLE_APP_FUNCTION_MANAGER) + public static final int APP_FUNCTIONS_NOT_CONTROLLED_BY_POLICY = 0; + + /** Indicates that app functions are controlled and disabled by a policy. */ + @FlaggedApi(android.app.appfunctions.flags.Flags.FLAG_ENABLE_APP_FUNCTION_MANAGER) + public static final int APP_FUNCTIONS_DISABLED = 1; + + /** + * Indicates that app functions are controlled and disabled by a policy for cross profile + * interactions only. + * + *

This is different from {@link #APP_FUNCTIONS_DISABLED} in that it only disables cross + * profile interactions (even if the caller has permissions required to interact across users). + * appfunctions can still be used within the a user profile boundary. + */ + @FlaggedApi(android.app.appfunctions.flags.Flags.FLAG_ENABLE_APP_FUNCTION_MANAGER) + public static final int APP_FUNCTIONS_DISABLED_CROSS_PROFILE = 2; + + /** @hide */ + @IntDef( + prefix = {"APP_FUNCTIONS_"}, + value = { + APP_FUNCTIONS_NOT_CONTROLLED_BY_POLICY, + APP_FUNCTIONS_DISABLED, + APP_FUNCTIONS_DISABLED_CROSS_PROFILE + }) + @Retention(RetentionPolicy.SOURCE) + public @interface AppFunctionsPolicy {} + + /** + * Sets the app functions policy which controls app functions operations on the device. + * + *

This function can only be called by a device owner, a profile owner or holders of the + * permission {@link android.Manifest.permission#MANAGE_DEVICE_POLICY_APP_FUNCTIONS}. + * + * @param policy The app functions policy to set. One of {@link + * #APP_FUNCTIONS_NOT_CONTROLLED_BY_POLICY}, + * {@link #APP_FUNCTIONS_DISABLED} or + * {@link #APP_FUNCTIONS_DISABLED_CROSS_PROFILE} + * @throws SecurityException if caller is not a device owner, a profile owner or a holder + * of the permission {@link android.Manifest.permission#MANAGE_DEVICE_POLICY_APP_FUNCTIONS}. + */ + @RequiresPermission(value = MANAGE_DEVICE_POLICY_APP_FUNCTIONS, conditional = true) + @FlaggedApi(android.app.appfunctions.flags.Flags.FLAG_ENABLE_APP_FUNCTION_MANAGER) + public void setAppFunctionsPolicy(@AppFunctionsPolicy int policy) { + throwIfParentInstance("setAppFunctionsPolicy"); + if (mService != null) { + try { + mService.setAppFunctionsPolicy(mContext.getPackageName(), policy); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + } + } + + /** + * Returns the current app functions policy. + * + *

The returned policy will be the current resolved policy rather than the policy set by the + * calling admin. + * + * @throws SecurityException if caller is not a device owner, a profile owner or a holder + * of the permission {@link android.Manifest.permission#MANAGE_DEVICE_POLICY_APP_FUNCTIONS}. + */ + @RequiresPermission(value = MANAGE_DEVICE_POLICY_APP_FUNCTIONS, conditional = true) + @FlaggedApi(android.app.appfunctions.flags.Flags.FLAG_ENABLE_APP_FUNCTION_MANAGER) + public @AppFunctionsPolicy int getAppFunctionsPolicy() { + throwIfParentInstance("getAppFunctionsPolicy"); + if (mService != null) { + try { + return mService.getAppFunctionsPolicy(mContext.getPackageName(), + myUserId()); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + } + return APP_FUNCTIONS_NOT_CONTROLLED_BY_POLICY; + } + /** * This object is a single place to tack on invalidation and disable calls. All * binder caches in this class derive from this Config, so all can be invalidated or diff --git a/core/java/android/app/admin/IDevicePolicyManager.aidl b/core/java/android/app/admin/IDevicePolicyManager.aidl index 03a9f99550864e8df1ba335e7565cdcfc77c5694..f304c1bf0a8821cf3ecec98f12f6db89bde67366 100644 --- a/core/java/android/app/admin/IDevicePolicyManager.aidl +++ b/core/java/android/app/admin/IDevicePolicyManager.aidl @@ -644,4 +644,7 @@ interface IDevicePolicyManager { int getPolicySizeForAdmin(String callerPackageName, in EnforcingAdmin admin); int getHeadlessDeviceOwnerMode(String callerPackageName); + + void setAppFunctionsPolicy(String callerPackageName, int policy); + int getAppFunctionsPolicy(String callerPackageName, int userId); } diff --git a/core/java/android/app/admin/UnknownAuthority.java b/core/java/android/app/admin/UnknownAuthority.java index 82dcf7e1a115514a0d63a684c20883ce377ea057..bebffdea5f02abc580560a8c2b52f7539900cc43 100644 --- a/core/java/android/app/admin/UnknownAuthority.java +++ b/core/java/android/app/admin/UnknownAuthority.java @@ -74,14 +74,14 @@ public final class UnknownAuthority extends Authority { @Override public boolean equals(@Nullable Object o) { if (this == o) return true; - if (o != null && getClass() == o.getClass()) return false; + if (o == null || getClass() != o.getClass()) return false; UnknownAuthority other = (UnknownAuthority) o; return Objects.equals(mName, other.mName); } @Override public int hashCode() { - return mName.hashCode(); + return Objects.hashCode(mName); } @Override diff --git a/core/java/android/app/admin/flags/flags.aconfig b/core/java/android/app/admin/flags/flags.aconfig index 22bc356899f4c262ec201f86d574f002e0d15d49..af035cb630dcf05414374237f17478c5ce8b4053 100644 --- a/core/java/android/app/admin/flags/flags.aconfig +++ b/core/java/android/app/admin/flags/flags.aconfig @@ -342,16 +342,6 @@ flag { } } -flag { - name: "dont_write_policy_definition" - namespace: "enterprise" - description: "Don't write redundant policy-definition-entry tags" - bug: "335663055" - metadata { - purpose: PURPOSE_BUGFIX - } -} - flag { name: "active_admin_cleanup" namespace: "enterprise" @@ -398,6 +388,7 @@ flag { flag { name: "split_create_managed_profile_enabled" + is_exported: true namespace: "enterprise" description: "Split up existing create and provision managed profile API." bug: "375382324" diff --git a/core/java/android/app/appfunctions/AppFunctionException.java b/core/java/android/app/appfunctions/AppFunctionException.java index c8d80d3afe43ad33be727f1780bcdd840a75c8ad..d8179c7540d949e1cdd31d732aa4c1117e842c3d 100644 --- a/core/java/android/app/appfunctions/AppFunctionException.java +++ b/core/java/android/app/appfunctions/AppFunctionException.java @@ -32,8 +32,8 @@ import java.util.Objects; /** * Represents an app function related error. * - *

This exception may include an {@link AppFunctionException#getExtras() Bundle} - * containing additional error-specific metadata. + *

This exception may include an {@link AppFunctionException#getExtras() Bundle} containing + * additional error-specific metadata. * *

The AppFunction SDK can expose structured APIs by packing and unpacking this Bundle. */ @@ -84,6 +84,13 @@ public final class AppFunctionException extends Exception implements Parcelable */ public static final int ERROR_CANCELLED = 2001; + /** + * The operation was disallowed by enterprise policy. + * + *

This error is in the {@link #ERROR_CATEGORY_SYSTEM} category. + */ + public static final int ERROR_ENTERPRISE_POLICY_DISALLOWED = 2002; + /** * An unknown error occurred while processing the call in the AppFunctionService. * @@ -231,7 +238,8 @@ public final class AppFunctionException extends Exception implements Parcelable ERROR_SYSTEM_ERROR, ERROR_INVALID_ARGUMENT, ERROR_DISABLED, - ERROR_CANCELLED + ERROR_CANCELLED, + ERROR_ENTERPRISE_POLICY_DISALLOWED }) @Retention(RetentionPolicy.SOURCE) public @interface ErrorCode {} diff --git a/core/java/android/app/appfunctions/AppFunctionManager.java b/core/java/android/app/appfunctions/AppFunctionManager.java index ed088fed41c292aabb68efac071aca757ae49f80..a731e50854660ba0b25c68b5a2959f9bd6058939 100644 --- a/core/java/android/app/appfunctions/AppFunctionManager.java +++ b/core/java/android/app/appfunctions/AppFunctionManager.java @@ -34,6 +34,7 @@ import android.os.ICancellationSignal; import android.os.OutcomeReceiver; import android.os.ParcelableException; import android.os.RemoteException; +import android.os.SystemClock; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; @@ -179,7 +180,8 @@ public final class AppFunctionManager { ExecuteAppFunctionAidlRequest aidlRequest = new ExecuteAppFunctionAidlRequest( - request, mContext.getUser(), mContext.getPackageName()); + request, mContext.getUser(), mContext.getPackageName(), + /* requestTime= */ SystemClock.elapsedRealtime()); try { ICancellationSignal cancellationTransport = diff --git a/core/java/android/app/appfunctions/ExecuteAppFunctionAidlRequest.java b/core/java/android/app/appfunctions/ExecuteAppFunctionAidlRequest.java index e623fa10f4748dc7298b3168d518f4f8d091c296..707d1fc0473edb3aaf1e12cc0fc4817e4638c23f 100644 --- a/core/java/android/app/appfunctions/ExecuteAppFunctionAidlRequest.java +++ b/core/java/android/app/appfunctions/ExecuteAppFunctionAidlRequest.java @@ -41,8 +41,9 @@ public final class ExecuteAppFunctionAidlRequest implements Parcelable { ExecuteAppFunctionRequest.CREATOR.createFromParcel(in); UserHandle userHandle = UserHandle.CREATOR.createFromParcel(in); String callingPackage = in.readString8(); + long requestTime = in.readLong(); return new ExecuteAppFunctionAidlRequest( - clientRequest, userHandle, callingPackage); + clientRequest, userHandle, callingPackage, requestTime); } @Override @@ -60,11 +61,15 @@ public final class ExecuteAppFunctionAidlRequest implements Parcelable { /** The package name of the app that is requesting to execute the app function. */ private final String mCallingPackage; - public ExecuteAppFunctionAidlRequest( - ExecuteAppFunctionRequest clientRequest, UserHandle userHandle, String callingPackage) { + /** The time of calling executeAppFunction(). */ + private final long mRequestTime; + + public ExecuteAppFunctionAidlRequest(ExecuteAppFunctionRequest clientRequest, + UserHandle userHandle, String callingPackage, long requestTime) { this.mClientRequest = Objects.requireNonNull(clientRequest); this.mUserHandle = Objects.requireNonNull(userHandle); this.mCallingPackage = Objects.requireNonNull(callingPackage); + this.mRequestTime = requestTime; } @Override @@ -77,6 +82,7 @@ public final class ExecuteAppFunctionAidlRequest implements Parcelable { mClientRequest.writeToParcel(dest, flags); mUserHandle.writeToParcel(dest, flags); dest.writeString8(mCallingPackage); + dest.writeLong(mRequestTime); } /** Returns the client request to execute an app function. */ @@ -96,4 +102,9 @@ public final class ExecuteAppFunctionAidlRequest implements Parcelable { public String getCallingPackage() { return mCallingPackage; } + + /** Returns the time of calling executeAppFunction(). */ + public long getRequestTime() { + return mRequestTime; + } } diff --git a/core/java/android/app/appfunctions/ExecuteAppFunctionRequest.java b/core/java/android/app/appfunctions/ExecuteAppFunctionRequest.java index a88198a4ec7cf04a93a8f83cbca2bc854070a546..bdc6ce5c73e81f498a4defe99bb157b302affcf4 100644 --- a/core/java/android/app/appfunctions/ExecuteAppFunctionRequest.java +++ b/core/java/android/app/appfunctions/ExecuteAppFunctionRequest.java @@ -136,6 +136,16 @@ public final class ExecuteAppFunctionRequest implements Parcelable { return mExtras; } + /** + * Returns the size of the request in bytes. + * + * @hide + */ + public int getRequestDataSize() { + return mTargetPackageName.getBytes().length + mFunctionIdentifier.getBytes().length + + mParameters.getDataSize() + mExtras.getSize(); + } + @Override public void writeToParcel(@NonNull Parcel dest, int flags) { dest.writeString8(mTargetPackageName); diff --git a/core/java/android/app/appfunctions/ExecuteAppFunctionResponse.java b/core/java/android/app/appfunctions/ExecuteAppFunctionResponse.java index a4952f48605934ba163ad9b4df540c1e3f03a969..618cc1ca48f904a687e6948aff6f93858816f97f 100644 --- a/core/java/android/app/appfunctions/ExecuteAppFunctionResponse.java +++ b/core/java/android/app/appfunctions/ExecuteAppFunctionResponse.java @@ -135,6 +135,15 @@ public final class ExecuteAppFunctionResponse implements Parcelable { return mExtras; } + /** + * Returns the size of the response in bytes. + * + * @hide + */ + public int getResponseDataSize() { + return mResultDocumentWrapper.getDataSize() + mExtras.getSize(); + } + @Override public int describeContents() { return 0; diff --git a/core/java/android/app/appfunctions/GenericDocumentWrapper.java b/core/java/android/app/appfunctions/GenericDocumentWrapper.java index 541ca7458efe47bcea4a7d819318ce26717221ae..02133b475ec21c98d42ee1c618bfa17514cc923d 100644 --- a/core/java/android/app/appfunctions/GenericDocumentWrapper.java +++ b/core/java/android/app/appfunctions/GenericDocumentWrapper.java @@ -50,6 +50,10 @@ public final class GenericDocumentWrapper implements Parcelable { @Nullable private Parcel mParcel; + @GuardedBy("mLock") + @Nullable + private Integer mDataSize; + private final Object mLock = new Object(); public static final Creator CREATOR = @@ -75,11 +79,13 @@ public final class GenericDocumentWrapper implements Parcelable { public GenericDocumentWrapper(@NonNull GenericDocument genericDocument) { mGenericDocument = Objects.requireNonNull(genericDocument); mParcel = null; + mDataSize = null; } public GenericDocumentWrapper(@NonNull Parcel parcel) { mGenericDocument = null; mParcel = Objects.requireNonNull(parcel); + mDataSize = mParcel.dataSize(); } /** Returns the wrapped {@link android.app.appsearch.GenericDocument} */ @@ -109,6 +115,21 @@ public final class GenericDocumentWrapper implements Parcelable { } } + /** Returns the size of the parcelled document. */ + + int getDataSize() { + synchronized (mLock) { + if (mDataSize != null) { + return mDataSize; + } + Parcel tempParcel = Parcel.obtain(); + writeToParcel(tempParcel, 0); + mDataSize = tempParcel.dataSize(); + tempParcel.recycle(); + return mDataSize; + } + } + @Override public int describeContents() { return 0; diff --git a/core/java/android/app/appfunctions/SafeOneTimeExecuteAppFunctionCallback.java b/core/java/android/app/appfunctions/SafeOneTimeExecuteAppFunctionCallback.java index 2426daf5c9f299df511952b0f436971aa2280c8f..e290169bdea87dceed91901b54b3e215565e2245 100644 --- a/core/java/android/app/appfunctions/SafeOneTimeExecuteAppFunctionCallback.java +++ b/core/java/android/app/appfunctions/SafeOneTimeExecuteAppFunctionCallback.java @@ -17,6 +17,7 @@ package android.app.appfunctions; import android.annotation.NonNull; +import android.annotation.Nullable; import android.os.RemoteException; import android.util.Log; @@ -37,8 +38,16 @@ public class SafeOneTimeExecuteAppFunctionCallback { @NonNull private final IExecuteAppFunctionCallback mCallback; + @Nullable CompletionCallback mCompletionCallback; + public SafeOneTimeExecuteAppFunctionCallback(@NonNull IExecuteAppFunctionCallback callback) { + this(callback, /* completionCallback= */ null); + } + + public SafeOneTimeExecuteAppFunctionCallback(@NonNull IExecuteAppFunctionCallback callback, + @Nullable CompletionCallback completionCallback) { mCallback = Objects.requireNonNull(callback); + mCompletionCallback = completionCallback; } /** Invoke wrapped callback with the result. */ @@ -49,6 +58,9 @@ public class SafeOneTimeExecuteAppFunctionCallback { } try { mCallback.onSuccess(result); + if (mCompletionCallback != null) { + mCompletionCallback.finalizeOnSuccess(result); + } } catch (RemoteException ex) { // Failed to notify the other end. Ignore. Log.w(TAG, "Failed to invoke the callback", ex); @@ -63,6 +75,9 @@ public class SafeOneTimeExecuteAppFunctionCallback { } try { mCallback.onError(error); + if (mCompletionCallback != null) { + mCompletionCallback.finalizeOnError(error); + } } catch (RemoteException ex) { // Failed to notify the other end. Ignore. Log.w(TAG, "Failed to invoke the callback", ex); @@ -76,4 +91,16 @@ public class SafeOneTimeExecuteAppFunctionCallback { public void disable() { mOnResultCalled.set(true); } + + /** + * Provides a hook to execute additional actions after the {@link IExecuteAppFunctionCallback} + * has been invoked. + */ + public interface CompletionCallback { + /** Called after {@link IExecuteAppFunctionCallback#onSuccess}. */ + void finalizeOnSuccess(@NonNull ExecuteAppFunctionResponse result); + + /** Called after {@link IExecuteAppFunctionCallback#onError}. */ + void finalizeOnError(@NonNull AppFunctionException error); + } } diff --git a/core/java/android/app/contextualsearch/flags.aconfig b/core/java/android/app/contextualsearch/flags.aconfig index 529b59ac424dbda645bdfb805db48ffdab7963f6..e8cfd79c9cc798d00fef06bab150b29a2a4deda7 100644 --- a/core/java/android/app/contextualsearch/flags.aconfig +++ b/core/java/android/app/contextualsearch/flags.aconfig @@ -17,14 +17,14 @@ flag { flag { name: "multi_window_screen_context" - namespace: "machine_learning" + namespace: "sysui_integrations" description: "Report screen context and positions for all windows." bug: "371065456" } flag { name: "contextual_search_window_layer" - namespace: "machine_learning" + namespace: "sysui_integrations" description: "Identify live contextual search UI to exclude from contextual search screenshot." bug: "372510690" } \ No newline at end of file diff --git a/core/java/android/app/jank/JankDataProcessor.java b/core/java/android/app/jank/JankDataProcessor.java index 7ceaeb3fb07059ca589b3f23cbd74fcba3d08f41..c9472598b35296b3c95ea854b5b994099acc49dd 100644 --- a/core/java/android/app/jank/JankDataProcessor.java +++ b/core/java/android/app/jank/JankDataProcessor.java @@ -215,7 +215,8 @@ public class JankDataProcessor { try { mPendingJankStats.values().forEach(stat -> { - FrameworkStatsLog.write(FrameworkStatsLog.JANK_FRAME_COUNT_BY_WIDGET, + FrameworkStatsLog.write( + FrameworkStatsLog.JANK_FRAME_COUNT_BY_WIDGET_REPORTED, /*app uid*/ stat.getUid(), /*activity name*/ stat.getActivityName(), /*widget id*/ stat.getWidgetId(), diff --git a/core/java/android/app/jank/JankTracker.java b/core/java/android/app/jank/JankTracker.java index 469521668d2546c4d6902322faab0a34bad6c9e4..a04f96a9f6e3563bbbf45b3acd0f7781b8765386 100644 --- a/core/java/android/app/jank/JankTracker.java +++ b/core/java/android/app/jank/JankTracker.java @@ -29,6 +29,7 @@ import android.view.ViewTreeObserver; import com.android.internal.annotations.VisibleForTesting; import java.util.ArrayList; +import java.util.HashMap; /** * This class is responsible for registering callbacks that will receive JankData batches. @@ -173,6 +174,15 @@ public class JankTracker { mStateTracker.retrieveAllStates(stateDataList); } + /** + * Retrieve all pending jank stats before they are logged, this is intended for testing + * purposes only. + */ + @VisibleForTesting + public HashMap getPendingJankStats() { + return mJankDataProcessor.getPendingJankStats(); + } + /** * Only intended to be used by tests, the runnable that registers the listeners may not run * in time for tests to pass. This forces them to run immediately. @@ -192,7 +202,11 @@ public class JankTracker { */ } - private boolean shouldTrack() { + /** + * Returns whether jank tracking is enabled or not. + */ + @VisibleForTesting + public boolean shouldTrack() { return mTrackingEnabled && mListenersRegistered; } diff --git a/core/java/android/app/notification.aconfig b/core/java/android/app/notification.aconfig index 8b6840c1b552b3e2ee8e8d81dfa2ff613cc49ef9..b1db1379e4006d7a496035f926a115a796bc311f 100644 --- a/core/java/android/app/notification.aconfig +++ b/core/java/android/app/notification.aconfig @@ -283,6 +283,20 @@ flag { bug: "362981561" } +flag { + name: "nm_binder_perf_cache_channels" + namespace: "systemui" + description: "Use IpcDataCache for notification channel/group lookups" + bug: "362981561" +} + +flag { + name: "nm_binder_perf_throttle_notify" + namespace: "systemui" + description: "Rate-limit calls to enqueueNotificationWithTag client-side" + bug: "362981561" +} + flag { name: "no_sbnholder" namespace: "systemui" diff --git a/core/java/android/app/ondeviceintelligence/OWNERS b/core/java/android/app/ondeviceintelligence/OWNERS deleted file mode 100644 index 85e9e653e6fb58470a50f6708343a8eb7412dd64..0000000000000000000000000000000000000000 --- a/core/java/android/app/ondeviceintelligence/OWNERS +++ /dev/null @@ -1,6 +0,0 @@ -# Bug component: 1363385 - -sandeepbandaru@google.com -shivanker@google.com -hackz@google.com -volnov@google.com diff --git a/core/java/android/app/ondeviceintelligence/flags/ondevice_intelligence.aconfig b/core/java/android/app/ondeviceintelligence/flags/ondevice_intelligence.aconfig deleted file mode 100644 index 74a96c864167cad125d9feaaec0906fd50a20050..0000000000000000000000000000000000000000 --- a/core/java/android/app/ondeviceintelligence/flags/ondevice_intelligence.aconfig +++ /dev/null @@ -1,17 +0,0 @@ -package: "android.app.ondeviceintelligence.flags" -container: "system" - -flag { - name: "enable_on_device_intelligence" - is_exported: true - namespace: "ondeviceintelligence" - description: "Make methods on OnDeviceIntelligenceManager available for local inference." - bug: "304755128" -} -flag { - name: "enable_on_device_intelligence_module" - is_exported: true - namespace: "ondeviceintelligence" - description: "Enable migration to mainline module and related changes." - bug: "376427781" -} \ No newline at end of file diff --git a/core/java/android/app/performance.aconfig b/core/java/android/app/performance.aconfig index 359c84eeb55923847dfd62bc476d0c5b1b934c0a..238f1cb1220831a1769ac99e7df30c4416d14978 100644 --- a/core/java/android/app/performance.aconfig +++ b/core/java/android/app/performance.aconfig @@ -35,6 +35,14 @@ flag { bug: "373752556" } +flag { + namespace: "system_performance" + name: "pic_separate_permission_notifications" + is_fixed_read_only: true + description: "Seperate PermissionManager notifications from cache udpates" + bug: "379699402" +} + flag { namespace: "system_performance" name: "pic_cache_nulls" diff --git a/core/java/android/app/servertransaction/ActivityConfigurationChangeItem.java b/core/java/android/app/servertransaction/ActivityConfigurationChangeItem.java index 2b52681d1be81b52d57ce90d7291859b8b657bf8..75ecabd8ddb0b4e08cd95fb88e16d3996bbf1738 100644 --- a/core/java/android/app/servertransaction/ActivityConfigurationChangeItem.java +++ b/core/java/android/app/servertransaction/ActivityConfigurationChangeItem.java @@ -56,7 +56,7 @@ public class ActivityConfigurationChangeItem extends ActivityTransactionItem { @Override public void preExecute(@NonNull ClientTransactionHandler client) { - CompatibilityInfo.applyOverrideScaleIfNeeded(mConfiguration); + CompatibilityInfo.applyOverrideIfNeeded(mConfiguration); // Notify the client of an upcoming change in the token configuration. This ensures that // batches of config change items only process the newest configuration. client.updatePendingActivityConfiguration(getActivityToken(), mConfiguration); diff --git a/core/java/android/app/servertransaction/ActivityRelaunchItem.java b/core/java/android/app/servertransaction/ActivityRelaunchItem.java index cecf7013c79c28550cdc6529011d2698a2150d00..bb881908d10f4fe1355b30e167ca062549b4675a 100644 --- a/core/java/android/app/servertransaction/ActivityRelaunchItem.java +++ b/core/java/android/app/servertransaction/ActivityRelaunchItem.java @@ -89,7 +89,7 @@ public class ActivityRelaunchItem extends ActivityTransactionItem { public void preExecute(@NonNull ClientTransactionHandler client) { // The local config is already scaled so only apply if this item is from server side. if (!client.isExecutingLocalTransaction()) { - CompatibilityInfo.applyOverrideScaleIfNeeded(mConfig); + CompatibilityInfo.applyOverrideIfNeeded(mConfig); } mActivityClientRecord = client.prepareRelaunchActivity(getActivityToken(), mPendingResults, mPendingNewIntents, mConfigChanges, mConfig, mPreserveWindow, mActivityWindowInfo); diff --git a/core/java/android/app/servertransaction/ConfigurationChangeItem.java b/core/java/android/app/servertransaction/ConfigurationChangeItem.java index 123d7926160ca2ed21d3b749d708daace061183f..e42005bdd595de8e99f2e1720574b66d8ad65a4f 100644 --- a/core/java/android/app/servertransaction/ConfigurationChangeItem.java +++ b/core/java/android/app/servertransaction/ConfigurationChangeItem.java @@ -46,7 +46,7 @@ public class ConfigurationChangeItem extends ClientTransactionItem { @Override public void preExecute(@NonNull ClientTransactionHandler client) { - CompatibilityInfo.applyOverrideScaleIfNeeded(mConfiguration); + CompatibilityInfo.applyOverrideIfNeeded(mConfiguration); client.updatePendingConfiguration(mConfiguration); } diff --git a/core/java/android/app/servertransaction/LaunchActivityItem.java b/core/java/android/app/servertransaction/LaunchActivityItem.java index 235a9f7aeb4c9fdb9538dfdcad2ea4e63c867031..f2e7a4fcd50bce468ae6ea46a254bec842926098 100644 --- a/core/java/android/app/servertransaction/LaunchActivityItem.java +++ b/core/java/android/app/servertransaction/LaunchActivityItem.java @@ -202,8 +202,8 @@ public class LaunchActivityItem extends ClientTransactionItem { public void preExecute(@NonNull ClientTransactionHandler client) { client.countLaunchingActivities(1); client.updateProcessState(mProcState, false); - CompatibilityInfo.applyOverrideScaleIfNeeded(mCurConfig); - CompatibilityInfo.applyOverrideScaleIfNeeded(mOverrideConfig); + CompatibilityInfo.applyOverrideIfNeeded(mCurConfig); + CompatibilityInfo.applyOverrideIfNeeded(mOverrideConfig); client.updatePendingConfiguration(mCurConfig); if (mActivityClientController != null) { ActivityClient.setActivityClientController(mActivityClientController); diff --git a/core/java/android/app/servertransaction/MoveToDisplayItem.java b/core/java/android/app/servertransaction/MoveToDisplayItem.java index 1aa563aa63633a0cb232b84ff5d892393097b601..72d1f491f2c6e4f6e77a833f019b59ba45c65021 100644 --- a/core/java/android/app/servertransaction/MoveToDisplayItem.java +++ b/core/java/android/app/servertransaction/MoveToDisplayItem.java @@ -58,7 +58,7 @@ public class MoveToDisplayItem extends ActivityTransactionItem { @Override public void preExecute(@NonNull ClientTransactionHandler client) { - CompatibilityInfo.applyOverrideScaleIfNeeded(mConfiguration); + CompatibilityInfo.applyOverrideIfNeeded(mConfiguration); // Notify the client of an upcoming change in the token configuration. This ensures that // batches of config change items only process the newest configuration. client.updatePendingActivityConfiguration(getActivityToken(), mConfiguration); diff --git a/core/java/android/app/supervision/SupervisionManagerInternal.java b/core/java/android/app/supervision/SupervisionManagerInternal.java index d571e14ff5faacd7ae49b6f819f24072b514eabf..2cf6ae6f9d01a80230ee234cffb31984c867da64 100644 --- a/core/java/android/app/supervision/SupervisionManagerInternal.java +++ b/core/java/android/app/supervision/SupervisionManagerInternal.java @@ -27,32 +27,41 @@ import android.os.PersistableBundle; */ public abstract class SupervisionManagerInternal { /** - * Returns whether supervision is enabled for the specified user + * Returns whether the app with given process uid is the active supervision app. * - * @param userId The user to retrieve the supervision state for - * @return whether the user is supervised + *

Supervision app is considered active when supervision is enabled for the user running the + * given process uid. + * + * @param uid App process uid. + * @return Whether the app is the active supervision app. */ - public abstract boolean isSupervisionEnabledForUser(@UserIdInt int userId); + public abstract boolean isActiveSupervisionApp(int uid); /** - * Returns whether the supervision lock screen needs to be shown. + * Returns whether supervision is enabled for the specified user. + * + * @param userId The user to retrieve the supervision state for. + * @return Whether the user is supervised. */ + public abstract boolean isSupervisionEnabledForUser(@UserIdInt int userId); + + /** Returns whether the supervision lock screen needs to be shown. */ public abstract boolean isSupervisionLockscreenEnabledForUser(@UserIdInt int userId); /** * Set whether supervision is enabled for the specified user. * - * @param userId The user to set the supervision state for - * @param enabled Whether or not the user should be supervised + * @param userId The user to set the supervision state for. + * @param enabled Whether or not the user should be supervised. */ public abstract void setSupervisionEnabledForUser(@UserIdInt int userId, boolean enabled); /** - * Sets whether the supervision lock screen should be shown for the specified user + * Sets whether the supervision lock screen should be shown for the specified user. * - * @param userId The user set the superivision state for - * @param enabled Whether or not the superivision lock screen needs to be shown - * @param options Optional configuration parameters for the supervision lock screen + * @param userId The user set the superivision state for. + * @param enabled Whether or not the superivision lock screen needs to be shown. + * @param options Optional configuration parameters for the supervision lock screen. */ public abstract void setSupervisionLockscreenEnabledForUser( @UserIdInt int userId, boolean enabled, @Nullable PersistableBundle options); diff --git a/core/java/android/app/supervision/flags.aconfig b/core/java/android/app/supervision/flags.aconfig index d4f82f665fd418fa13995451897abfd4f419e549..1b0353274fb9b05fc1cb14997d7a9d227d9f0e7a 100644 --- a/core/java/android/app/supervision/flags.aconfig +++ b/core/java/android/app/supervision/flags.aconfig @@ -24,3 +24,11 @@ flag { description: "Flag that enables supervision when the supervision app is the profile owner" bug: "377261590" } + +flag { + name: "deprecate_dpm_supervision_apis" + is_exported: true + namespace: "supervision" + description: "Flag that deprecates supervision methods in DPM" + bug: "382034839" +} diff --git a/core/java/android/app/wallpaper/WallpaperDescription.java b/core/java/android/app/wallpaper/WallpaperDescription.java index 3ee00ca3d9412c389393ad41ac212e6dd32976d1..ca2d9e676a022ef52de685382eab1eacd14eac6f 100644 --- a/core/java/android/app/wallpaper/WallpaperDescription.java +++ b/core/java/android/app/wallpaper/WallpaperDescription.java @@ -20,6 +20,7 @@ import static android.app.Flags.FLAG_LIVE_WALLPAPER_CONTENT_HANDLING; import android.annotation.FlaggedApi; import android.annotation.SuppressLint; +import android.annotation.SystemApi; import android.annotation.TestApi; import android.app.WallpaperInfo; import android.app.WallpaperManager; @@ -153,6 +154,7 @@ public final class WallpaperDescription implements Parcelable { * {@link Builder#setCropHints(SparseArray)} * @hide */ + @SystemApi @NonNull public SparseArray getCropHints() { return mCropHints; diff --git a/core/java/android/appwidget/AppWidgetManager.java b/core/java/android/appwidget/AppWidgetManager.java index 40de2985f68a133e4c6753969554098a3ac35295..67ad4594599fe59583ac6f1652fb2ab8271456e1 100644 --- a/core/java/android/appwidget/AppWidgetManager.java +++ b/core/java/android/appwidget/AppWidgetManager.java @@ -37,36 +37,44 @@ import android.compat.annotation.UnsupportedAppUsage; import android.content.ComponentName; import android.content.Context; import android.content.Intent; +import android.content.Intent.FilterComparison; import android.content.IntentSender; import android.content.ServiceConnection; import android.content.pm.PackageManager; import android.content.pm.ParceledListSlice; import android.content.pm.ShortcutInfo; import android.graphics.Rect; +import android.os.Binder; import android.os.Build; import android.os.Bundle; import android.os.Handler; import android.os.HandlerExecutor; import android.os.HandlerThread; +import android.os.IBinder; import android.os.Looper; import android.os.PersistableBundle; import android.os.Process; import android.os.RemoteException; import android.os.UserHandle; +import android.util.ArrayMap; import android.util.DisplayMetrics; import android.util.Log; +import android.util.Pair; import android.widget.RemoteViews; import com.android.internal.appwidget.IAppWidgetService; import com.android.internal.os.BackgroundThread; import com.android.internal.util.FunctionalUtils; +import java.util.ArrayDeque; import java.util.ArrayList; import java.util.Collections; import java.util.List; +import java.util.Map; import java.util.Objects; import java.util.concurrent.CompletableFuture; import java.util.concurrent.Executor; +import java.util.function.Consumer; /** * Updates AppWidget state; gets information about installed AppWidget providers and other @@ -592,6 +600,8 @@ public class AppWidgetManager { private boolean mHasPostedLegacyLists = false; + private @NonNull ServiceCollectionCache mServiceCollectionCache; + /** * Get the AppWidgetManager instance to use for the supplied {@link android.content.Context * Context} object. @@ -612,6 +622,7 @@ public class AppWidgetManager { mPackageName = context.getOpPackageName(); mService = service; mDisplayMetrics = context.getResources().getDisplayMetrics(); + mServiceCollectionCache = new ServiceCollectionCache(context, /* timeout= */ 5000L); if (mService == null) { return; } @@ -649,7 +660,7 @@ public class AppWidgetManager { final RemoteViews viewsCopy = new RemoteViews(original); Runnable updateWidgetWithTask = () -> { try { - viewsCopy.collectAllIntents(mMaxBitmapMemory).get(); + viewsCopy.collectAllIntents(mMaxBitmapMemory, mServiceCollectionCache).get(); action.acceptOrThrow(viewsCopy); } catch (Exception e) { Log.e(TAG, failureMsg, e); @@ -1629,4 +1640,106 @@ public class AppWidgetManager { thread.start(); return thread.getThreadHandler(); } + + /** + * @hide + */ + public static class ServiceCollectionCache { + + private final Context mContext; + private final Handler mHandler; + private final long mTimeOut; + + private final Map mActiveConnections = + new ArrayMap<>(); + + public ServiceCollectionCache(Context context, long timeOut) { + mContext = context; + mHandler = new Handler(BackgroundThread.getHandler().getLooper()); + mTimeOut = timeOut; + } + + /** + * Connect to the service indicated by the {@code Intent}, and consume the binder on the + * specified executor + */ + public void connectAndConsume(Intent intent, Consumer task, Executor executor) { + mHandler.post(() -> connectAndConsumeInner(intent, task, executor)); + } + + private void connectAndConsumeInner(Intent intent, Consumer task, + Executor executor) { + ConnectionTask activeConnection = mActiveConnections.computeIfAbsent( + new FilterComparison(intent), ConnectionTask::new); + activeConnection.add(task, executor); + } + + private class ConnectionTask implements ServiceConnection { + + private final Runnable mDestroyAfterTimeout = this::onDestroyTimeout; + private final ArrayDeque, Executor>> mTaskQueue = + new ArrayDeque<>(); + + private boolean mOnDestroyTimeout = false; + private IBinder mIBinder; + + ConnectionTask(@NonNull FilterComparison filter) { + mContext.bindService(filter.getIntent(), + Context.BindServiceFlags.of(Context.BIND_AUTO_CREATE), + mHandler::post, + this); + } + + @Override + public void onServiceConnected(ComponentName componentName, IBinder iBinder) { + mIBinder = iBinder; + mHandler.post(this::handleNext); + } + + @Override + public void onNullBinding(ComponentName name) { + // Use an empty binder, follow up tasks will handle the failure + onServiceConnected(name, new Binder()); + } + + @Override + public void onServiceDisconnected(ComponentName componentName) { } + + void add(Consumer task, Executor executor) { + mTaskQueue.add(Pair.create(task, executor)); + if (mOnDestroyTimeout) { + // If we are waiting for timeout, cancel it and execute the next task + handleNext(); + } + } + + private void handleNext() { + mHandler.removeCallbacks(mDestroyAfterTimeout); + Pair, Executor> next = mTaskQueue.pollFirst(); + if (next != null) { + mOnDestroyTimeout = false; + next.second.execute(() -> { + next.first.accept(mIBinder); + mHandler.post(this::handleNext); + }); + } else { + // Finished all tasks, start a timeout to unbind this service + mOnDestroyTimeout = true; + mHandler.postDelayed(mDestroyAfterTimeout, mTimeOut); + } + } + + /** + * Called after we have waited for {@link #mTimeOut} after the last task is finished + */ + private void onDestroyTimeout() { + if (!mTaskQueue.isEmpty()) { + handleNext(); + return; + } + mContext.unbindService(this); + mActiveConnections.values().remove(this); + } + } + } } diff --git a/core/java/android/companion/DeviceId.java b/core/java/android/companion/DeviceId.java index f66a1ae5c1758b68ff9d092a2af6a82c478dfb5c..2f19eb49ad4383fb6cc0f9b6a371b6063452b4fe 100644 --- a/core/java/android/companion/DeviceId.java +++ b/core/java/android/companion/DeviceId.java @@ -22,7 +22,6 @@ import android.annotation.Nullable; import android.net.MacAddress; import android.os.Parcel; import android.os.Parcelable; -import android.provider.OneTimeUseBuilder; import java.util.Locale; import java.util.Objects; @@ -154,8 +153,12 @@ public final class DeviceId implements Parcelable { /** * A builder for {@link DeviceId} + * + *

Calling apps must provide at least one of the following to identify + * the device: a custom ID using {@link #setCustomId(String)}, or a MAC address using + * {@link #setMacAddress(MacAddress)}.

*/ - public static final class Builder extends OneTimeUseBuilder { + public static final class Builder { private String mCustomId; private MacAddress mMacAddress; @@ -171,7 +174,6 @@ public final class DeviceId implements Parcelable { */ @NonNull public Builder setCustomId(@Nullable String customId) { - checkNotUsed(); if (customId != null && customId.length() > CUSTOM_ID_LENGTH_LIMIT) { throw new IllegalArgumentException("Length of the custom id must be at most " @@ -191,15 +193,12 @@ public final class DeviceId implements Parcelable { */ @NonNull public Builder setMacAddress(@Nullable MacAddress macAddress) { - checkNotUsed(); mMacAddress = macAddress; return this; } @NonNull - @Override public DeviceId build() { - markUsed(); if (mCustomId == null && mMacAddress == null) { throw new IllegalArgumentException("At least one device id property must be" + "non-null to build a DeviceId."); diff --git a/core/java/android/content/Intent.java b/core/java/android/content/Intent.java index d7660172a2f13dbb220b2cb9f5c50129fbfb6765..3d75423edfa904d4377a10e599e6c2f0308eaeec 100644 --- a/core/java/android/content/Intent.java +++ b/core/java/android/content/Intent.java @@ -55,6 +55,7 @@ import android.content.res.Resources; import android.content.res.TypedArray; import android.graphics.Rect; import android.net.Uri; +import android.os.BadParcelableException; import android.os.Build; import android.os.Bundle; import android.os.BundleMerger; @@ -6187,7 +6188,8 @@ public class Intent implements Parcelable, Cloneable { * {@link #EXTRA_CHOOSER_MODIFY_SHARE_ACTION}, * {@link #EXTRA_METADATA_TEXT}, * {@link #EXTRA_CHOOSER_REFINEMENT_INTENT_SENDER}, - * {@link #EXTRA_CHOOSER_RESULT_INTENT_SENDER}. + * {@link #EXTRA_CHOOSER_RESULT_INTENT_SENDER}, + * {@link #EXTRA_EXCLUDE_COMPONENTS}. *

*/ public static final String EXTRA_CHOOSER_ADDITIONAL_CONTENT_URI = @@ -7856,6 +7858,10 @@ public class Intent implements Parcelable, Cloneable { */ public static final int URI_ALLOW_UNSAFE = 1<<2; + static { + Bundle.intentClass = Intent.class; + } + // --------------------------------------------------------------------- private String mAction; @@ -12285,7 +12291,6 @@ public class Intent implements Parcelable, Cloneable { private IBinder mCreatorToken; // Stores all extra keys whose values are intents for a top level intent. private ArraySet mNestedIntentKeys; - } /** @@ -12347,6 +12352,7 @@ public class Intent implements Parcelable, Cloneable { public int hashCode() { return Objects.hash(mType, mKey, mIndex); } + } private @Nullable CreatorTokenInfo mCreatorTokenInfo; @@ -12397,9 +12403,20 @@ public class Intent implements Parcelable, Cloneable { addExtendedFlags(EXTENDED_FLAG_NESTED_INTENT_KEYS_COLLECTED); if (mExtras != null && !mExtras.isEmpty()) { for (String key : mExtras.keySet()) { - Object value = mExtras.get(key); - - if (value instanceof Intent intent && !visited.contains(intent)) { + Object value; + try { + value = mExtras.get(key); + } catch (BadParcelableException e) { + // This could happen when the key points to a LazyValue whose class cannot be + // found by the classLoader - A nested object more than 1 level deeper who is + // of type of a custom class could trigger this situation. In such case, we + // ignore it since it is not an intent. However, it could be a custom type that + // extends from Intent. If such an object is retrieved later in another + // component, then trying to launch such a custom class object will fail unless + // removeLaunchSecurityProtection() is called before it is launched. + value = null; + } + if (value instanceof Intent intent) { handleNestedIntent(intent, visited, new NestedIntentKey( NestedIntentKey.NESTED_INTENT_KEY_TYPE_EXTRA_PARCEL, key, 0)); } else if (value instanceof Parcelable[] parcelables) { @@ -12422,7 +12439,6 @@ public class Intent implements Parcelable, Cloneable { } private void handleNestedIntent(Intent intent, Set visited, NestedIntentKey key) { - visited.add(intent); if (mCreatorTokenInfo == null) { mCreatorTokenInfo = new CreatorTokenInfo(); } @@ -12430,7 +12446,10 @@ public class Intent implements Parcelable, Cloneable { mCreatorTokenInfo.mNestedIntentKeys = new ArraySet<>(); } mCreatorTokenInfo.mNestedIntentKeys.add(key); - intent.collectNestedIntentKeysRecur(visited); + if (!visited.contains(intent)) { + visited.add(intent); + intent.collectNestedIntentKeysRecur(visited); + } } private void handleParcelableArray(Parcelable[] parcelables, String key, Set visited) { diff --git a/core/java/android/content/pm/PackageManager.java b/core/java/android/content/pm/PackageManager.java index a06eb1c5b4ad83fe14f2fe6ddacd9330badc5357..7e0805137d0b1f8b8c6f67c6edefc705a6beffd0 100644 --- a/core/java/android/content/pm/PackageManager.java +++ b/core/java/android/content/pm/PackageManager.java @@ -11651,7 +11651,7 @@ public abstract class PackageManager { private static final PropertyInvalidatedCache sApplicationInfoCache = new PropertyInvalidatedCache( - 2048, PermissionManager.CACHE_KEY_PACKAGE_INFO, + 2048, PermissionManager.CACHE_KEY_PACKAGE_INFO_CACHE, "getApplicationInfo") { @Override public ApplicationInfo recompute(ApplicationInfoQuery query) { @@ -11682,18 +11682,6 @@ public abstract class PackageManager { sApplicationInfoCache.disableLocal(); } - private static final PropertyInvalidatedCache.AutoCorker sCacheAutoCorker = - new PropertyInvalidatedCache.AutoCorker(PermissionManager.CACHE_KEY_PACKAGE_INFO); - - /** - * Invalidate caches of package and permission information system-wide. - * - * @hide - */ - public static void invalidatePackageInfoCache() { - sCacheAutoCorker.autoCork(); - } - // Some of the flags don't affect the query result, but let's be conservative and cache // each combination of flags separately. @@ -11752,7 +11740,7 @@ public abstract class PackageManager { private static final PropertyInvalidatedCache sPackageInfoCache = new PropertyInvalidatedCache( - 2048, PermissionManager.CACHE_KEY_PACKAGE_INFO, + 2048, PermissionManager.CACHE_KEY_PACKAGE_INFO_CACHE, "getPackageInfo") { @Override public PackageInfo recompute(PackageInfoQuery query) { @@ -11784,17 +11772,40 @@ public abstract class PackageManager { /** * Inhibit package info cache invalidations when correct. * - * @hide */ + * @hide + */ public static void corkPackageInfoCache() { - PropertyInvalidatedCache.corkInvalidations(PermissionManager.CACHE_KEY_PACKAGE_INFO); + sPackageInfoCache.corkInvalidations(); } /** * Enable package info cache invalidations. * - * @hide */ + * @hide + */ public static void uncorkPackageInfoCache() { - PropertyInvalidatedCache.uncorkInvalidations(PermissionManager.CACHE_KEY_PACKAGE_INFO); + sPackageInfoCache.uncorkInvalidations(); + } + + // This auto-corker is obsolete once the separate permission notifications feature is + // committed. + private static final PropertyInvalidatedCache.AutoCorker sCacheAutoCorker = + PropertyInvalidatedCache.separatePermissionNotificationsEnabled() + ? null + : new PropertyInvalidatedCache + .AutoCorker(PermissionManager.CACHE_KEY_PACKAGE_INFO_CACHE); + + /** + * Invalidate caches of package and permission information system-wide. + * + * @hide + */ + public static void invalidatePackageInfoCache() { + if (PropertyInvalidatedCache.separatePermissionNotificationsEnabled()) { + sPackageInfoCache.invalidateCache(); + } else { + sCacheAutoCorker.autoCork(); + } } /** diff --git a/core/java/android/content/pm/TEST_MAPPING b/core/java/android/content/pm/TEST_MAPPING index 44f2a4ca38e247c7380a8dcd07af617f7763a0c2..23f1ff8926df31e17d63c7e781fa0e69deb9b532 100644 --- a/core/java/android/content/pm/TEST_MAPPING +++ b/core/java/android/content/pm/TEST_MAPPING @@ -157,6 +157,17 @@ } ] }, + { + "name": "CtsPackageInstallerCUJUpdateOwnerShipTestCases", + "options":[ + { + "exclude-annotation":"androidx.test.filters.FlakyTest" + }, + { + "exclude-annotation":"org.junit.Ignore" + } + ] + }, { "name": "CtsPackageInstallerCUJUpdateSelfTestCases", "options":[ diff --git a/core/java/android/content/pm/flags.aconfig b/core/java/android/content/pm/flags.aconfig index 8ba2dcc2a7cf41643d13ebdcc70a4fa19c0aacc4..dfeee2a2335f76d3f6080c5b29b9170c25864cc2 100644 --- a/core/java/android/content/pm/flags.aconfig +++ b/core/java/android/content/pm/flags.aconfig @@ -353,14 +353,6 @@ flag { is_fixed_read_only: true } -flag { - name: "support_minor_versions_in_minsdkversion" - namespace: "package_manager_service" - description: "Block app installations that specify an incompatible minor SDK version" - bug: "377302905" - is_exported: true -} - flag { name: "app_compat_option_16kb" is_exported: true diff --git a/core/java/android/content/pm/parsing/ApkLiteParseUtils.java b/core/java/android/content/pm/parsing/ApkLiteParseUtils.java index 18a45d8d442e0179dbb737a64bcd885e47b8052c..53813012b4b3c6d8e5910b8a6b7f1127b397300b 100644 --- a/core/java/android/content/pm/parsing/ApkLiteParseUtils.java +++ b/core/java/android/content/pm/parsing/ApkLiteParseUtils.java @@ -539,9 +539,6 @@ public class ApkLiteParseUtils { hasBindDeviceAdminPermission); break; case TAG_USES_SDK_LIBRARY: - if (!android.content.pm.Flags.sdkDependencyInstaller()) { - break; - } String usesSdkLibName = parser.getAttributeValue( ANDROID_RES_NAMESPACE, "name"); // TODO(b/379219371): Due to a bug in bundletool, some apps can use diff --git a/core/java/android/content/res/CompatibilityInfo.java b/core/java/android/content/res/CompatibilityInfo.java index d6620d19ccf0b73e863d34afed60136383829769..afcdcb0fbcad36788758adf57062083a3daae62d 100644 --- a/core/java/android/content/res/CompatibilityInfo.java +++ b/core/java/android/content/res/CompatibilityInfo.java @@ -17,7 +17,9 @@ package android.content.res; import android.annotation.Nullable; +import android.app.WindowConfiguration; import android.compat.annotation.UnsupportedAppUsage; +import android.content.pm.ActivityInfo; import android.content.pm.ApplicationInfo; import android.graphics.Canvas; import android.graphics.Insets; @@ -34,14 +36,17 @@ import android.util.MergedConfiguration; import android.view.InsetsSourceControl; import android.view.InsetsState; import android.view.MotionEvent; +import android.view.Surface; import android.view.WindowManager; import android.view.WindowManager.LayoutParams; +import com.android.aconfig.annotations.VisibleForTesting; + /** * CompatibilityInfo class keeps the information about the screen compatibility mode that the * application is running under. - * - * {@hide} + * + * {@hide} */ @RavenwoodKeepWholeClass public class CompatibilityInfo implements Parcelable { @@ -129,12 +134,37 @@ public class CompatibilityInfo implements Parcelable { */ public final float applicationDensityInvertedScale; + /** + * Application's display rotation. + * + *

This field is used to sandbox fixed-orientation activities on displays or display areas + * with ignoreOrientationRequest, where the display orientation is more likely to be different + * from the orientation the activity requested (e.g. in desktop windowing, or letterboxed). + * Mainly set for activities which use the display rotation to orient their content, for example + * camera previews. + * + *

In the case of camera activities, assuming the wrong posture + * can lead to sideways or stretched previews. As part of camera compat treatment for desktop + * windowing, the app is sandboxed to believe that the app and the device are in the posture the + * app requested. For example for portrait fixed-orientation apps, the app is letterboxed to + * portrait, camera feed is cropped to portrait, and the display rotation is changed via this + * field, for example to {@link Surface.Rotation#ROTATION_0} on devices with portrait natural + * orientation. All of these parameters factor in common calculations for setting up the camera + * preview. + */ + @Surface.Rotation + public int applicationDisplayRotation = WindowConfiguration.ROTATION_UNDEFINED; + /** The process level override inverted scale. See {@link #HAS_OVERRIDE_SCALING}. */ private static float sOverrideInvertedScale = 1f; /** The process level override inverted density scale. See {@link #HAS_OVERRIDE_SCALING}. */ private static float sOverrideDensityInvertScale = 1f; + /** The process level override display rotation. */ + @Surface.Rotation + private static int sOverrideDisplayRotation = WindowConfiguration.ROTATION_UNDEFINED; + @UnsupportedAppUsage @Deprecated public CompatibilityInfo(ApplicationInfo appInfo, int screenLayout, int sw, @@ -346,11 +376,16 @@ public class CompatibilityInfo implements Parcelable { return (mCompatibilityFlags & HAS_OVERRIDE_SCALING) != 0; } + /** Returns {@code true} if {@link #sOverrideDisplayRotation} should be set. */ + public boolean isOverrideDisplayRotationRequired() { + return applicationDisplayRotation != WindowConfiguration.ROTATION_UNDEFINED; + } + @UnsupportedAppUsage public boolean supportsScreen() { return (mCompatibilityFlags&NEEDS_SCREEN_COMPAT) == 0; } - + public boolean neverSupportsScreen() { return (mCompatibilityFlags&ALWAYS_NEEDS_COMPAT) != 0; } @@ -618,6 +653,9 @@ public class CompatibilityInfo implements Parcelable { } public void applyToConfiguration(int displayDensity, Configuration inoutConfig) { + if (hasOverrideDisplayRotation()) { + applyDisplayRotationConfiguration(sOverrideDisplayRotation, inoutConfig); + } if (hasOverrideScale()) return; if (!supportsScreen()) { // This is a larger screen device and the app is not @@ -650,21 +688,42 @@ public class CompatibilityInfo implements Parcelable { inoutConfig.windowConfiguration.scale(invertScale); } - /** @see #sOverrideInvertedScale */ - public static void applyOverrideScaleIfNeeded(Configuration config) { - if (!hasOverrideScale()) return; - scaleConfiguration(sOverrideInvertedScale, sOverrideDensityInvertScale, config); + /** Changes the WindowConfiguration display rotation for the given configuration. */ + public static void applyDisplayRotationConfiguration(@Surface.Rotation int displayRotation, + Configuration inoutConfig) { + if (displayRotation != WindowConfiguration.ROTATION_UNDEFINED) { + inoutConfig.windowConfiguration.setDisplayRotation(displayRotation); + } } - /** @see #sOverrideInvertedScale */ - public static void applyOverrideScaleIfNeeded(MergedConfiguration mergedConfig) { - if (!hasOverrideScale()) return; - scaleConfiguration(sOverrideInvertedScale, sOverrideDensityInvertScale, - mergedConfig.getGlobalConfiguration()); - scaleConfiguration(sOverrideInvertedScale, sOverrideDensityInvertScale, - mergedConfig.getOverrideConfiguration()); - scaleConfiguration(sOverrideInvertedScale, sOverrideDensityInvertScale, - mergedConfig.getMergedConfiguration()); + /** @see #sOverrideInvertedScale and #sOverrideDisplayRotation. */ + public static void applyOverrideIfNeeded(Configuration config) { + if (hasOverrideDisplayRotation()) { + applyDisplayRotationConfiguration(sOverrideDisplayRotation, config); + } + if (hasOverrideScale()) { + scaleConfiguration(sOverrideInvertedScale, sOverrideDensityInvertScale, config); + } + } + + /** @see #sOverrideInvertedScale and #sOverrideDisplayRotation. */ + public static void applyOverrideIfNeeded(MergedConfiguration mergedConfig) { + if (hasOverrideDisplayRotation()) { + applyDisplayRotationConfiguration(sOverrideDisplayRotation, + mergedConfig.getGlobalConfiguration()); + applyDisplayRotationConfiguration(sOverrideDisplayRotation, + mergedConfig.getOverrideConfiguration()); + applyDisplayRotationConfiguration(sOverrideDisplayRotation, + mergedConfig.getMergedConfiguration()); + } + if (hasOverrideScale()) { + scaleConfiguration(sOverrideInvertedScale, sOverrideDensityInvertScale, + mergedConfig.getGlobalConfiguration()); + scaleConfiguration(sOverrideInvertedScale, sOverrideDensityInvertScale, + mergedConfig.getOverrideConfiguration()); + scaleConfiguration(sOverrideInvertedScale, sOverrideDensityInvertScale, + mergedConfig.getMergedConfiguration()); + } } /** Returns {@code true} if this process is in a environment with override scale. */ @@ -693,6 +752,22 @@ public class CompatibilityInfo implements Parcelable { return sOverrideDensityInvertScale; } + /** Returns {@code true} if this process is in a environment with override display rotation. */ + private static boolean hasOverrideDisplayRotation() { + return sOverrideDisplayRotation != WindowConfiguration.ROTATION_UNDEFINED; + } + + /** @see #sOverrideInvertedScale */ + public static void setOverrideDisplayRotation(@Surface.Rotation int displayRotation) { + sOverrideDisplayRotation = displayRotation; + } + + /** @see #sOverrideDisplayRotation */ + @VisibleForTesting + public static int getOverrideDisplayRotation() { + return sOverrideDisplayRotation; + } + /** * Compute the frame Rect for applications runs under compatibility mode. * @@ -747,18 +822,50 @@ public class CompatibilityInfo implements Parcelable { if (this == o) { return true; } - try { - CompatibilityInfo oc = (CompatibilityInfo)o; - if (mCompatibilityFlags != oc.mCompatibilityFlags) return false; - if (applicationDensity != oc.applicationDensity) return false; - if (applicationScale != oc.applicationScale) return false; - if (applicationInvertedScale != oc.applicationInvertedScale) return false; - if (applicationDensityScale != oc.applicationDensityScale) return false; - if (applicationDensityInvertedScale != oc.applicationDensityInvertedScale) return false; - return true; - } catch (ClassCastException e) { + + if (!(o instanceof CompatibilityInfo oc)) { return false; } + + if (!isCompatibilityFlagsEqual(oc)) return false; + if (!isScaleEqual(oc)) return false; + if (!isDisplayRotationEqual(oc)) return false; + return true; + } + + /** + * Checks the difference between this and given {@link CompatibilityInfo} o, and returns the + * combination of {@link ActivityInfo}.CONFIG_* changes that this difference should trigger. + */ + public int getCompatibilityChangesForConfig(@Nullable CompatibilityInfo o) { + int changes = 0; + if (!isDisplayRotationEqual(o)) { + changes |= ActivityInfo.CONFIG_WINDOW_CONFIGURATION; + } + if (!isScaleEqual(o) || !isCompatibilityFlagsEqual(o)) { + changes |= ActivityInfo.CONFIG_SCREEN_LAYOUT + | ActivityInfo.CONFIG_SCREEN_SIZE + | ActivityInfo.CONFIG_SMALLEST_SCREEN_SIZE; + } + return changes; + } + + private boolean isScaleEqual(@Nullable CompatibilityInfo oc) { + if (oc == null) return false; + if (applicationDensity != oc.applicationDensity) return false; + if (applicationScale != oc.applicationScale) return false; + if (applicationInvertedScale != oc.applicationInvertedScale) return false; + if (applicationDensityScale != oc.applicationDensityScale) return false; + if (applicationDensityInvertedScale != oc.applicationDensityInvertedScale) return false; + return true; + } + + private boolean isDisplayRotationEqual(@Nullable CompatibilityInfo oc) { + return oc != null && oc.applicationDisplayRotation == applicationDisplayRotation; + } + + private boolean isCompatibilityFlagsEqual(@Nullable CompatibilityInfo oc) { + return oc != null && oc.mCompatibilityFlags == mCompatibilityFlags; } @Override @@ -778,6 +885,10 @@ public class CompatibilityInfo implements Parcelable { sb.append(" overrideDensityInvScale="); sb.append(applicationDensityInvertedScale); } + if (isOverrideDisplayRotationRequired()) { + sb.append(" overrideDisplayRotation="); + sb.append(applicationDisplayRotation); + } if (!supportsScreen()) { sb.append(" resizing"); } @@ -800,6 +911,7 @@ public class CompatibilityInfo implements Parcelable { result = 31 * result + Float.floatToIntBits(applicationInvertedScale); result = 31 * result + Float.floatToIntBits(applicationDensityScale); result = 31 * result + Float.floatToIntBits(applicationDensityInvertedScale); + result = 31 * result + applicationDisplayRotation; return result; } @@ -816,6 +928,7 @@ public class CompatibilityInfo implements Parcelable { dest.writeFloat(applicationInvertedScale); dest.writeFloat(applicationDensityScale); dest.writeFloat(applicationDensityInvertedScale); + dest.writeInt(applicationDisplayRotation); } @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023) @@ -839,6 +952,7 @@ public class CompatibilityInfo implements Parcelable { applicationInvertedScale = source.readFloat(); applicationDensityScale = source.readFloat(); applicationDensityInvertedScale = source.readFloat(); + applicationDisplayRotation = source.readInt(); } /** diff --git a/core/java/android/credentials/flags.aconfig b/core/java/android/credentials/flags.aconfig index 6c35d106bfb7e7e5f4e8a158800c8054e19cb2c9..d8d4e161006cbfff4ad6af9ec0cd3afeba9246fb 100644 --- a/core/java/android/credentials/flags.aconfig +++ b/core/java/android/credentials/flags.aconfig @@ -85,6 +85,16 @@ flag { bug: "324291187" } +flag { + namespace: "credential_manager" + name: "framework_session_id_metric_bundle" + description: "Enables the session_id to be passed across to the UI logs" + bug: "379880133" + metadata { + purpose: PURPOSE_BUGFIX + } +} + flag { namespace: "credential_manager" name: "clear_credentials_fix_enabled" @@ -104,3 +114,13 @@ flag { purpose: PURPOSE_BUGFIX } } + +flag { + namespace: "credential_manager" + name: "propagate_user_context_for_intent_creation" + description: "Propagates the user ID in which to find the right OEM UI component to launch" + bug: "373711451" + metadata { + purpose: PURPOSE_BUGFIX + } +} diff --git a/core/java/android/database/sqlite/SQLiteRawStatement.java b/core/java/android/database/sqlite/SQLiteRawStatement.java index c59d3cea04147059a887967383ec773e547cf6b6..3f3e46b4334c22a58f00c8f5afe2727262bf498f 100644 --- a/core/java/android/database/sqlite/SQLiteRawStatement.java +++ b/core/java/android/database/sqlite/SQLiteRawStatement.java @@ -554,10 +554,16 @@ public final class SQLiteRawStatement implements Closeable { * * @see sqlite3_column_type * + * If the row has no data then a {@link SQLiteMisuseException} is thrown. This condition can + * occur the last call to {@link #step()} returned false or if {@link #step()} was not called + * before the statement was created or after the last call to {@link #reset()}. Note that + * {@link SQLiteMisuseException} may be thrown for other reasons. + * * @param columnIndex The index of a column in the result row. It is zero-based. * @return The type of the value in the column of the result row. * @throws IllegalStateException if the statement is closed or this is a foreign thread. * @throws SQLiteBindOrColumnIndexOutOfRangeException if the column is out of range. + * @throws SQLiteMisuseException if the row has no data. * @throws SQLiteException if a native error occurs. */ @SQLiteDataType @@ -580,6 +586,7 @@ public final class SQLiteRawStatement implements Closeable { * @return The name of the column in the result row. * @throws IllegalStateException if the statement is closed or this is a foreign thread. * @throws SQLiteBindOrColumnIndexOutOfRangeException if the column is out of range. + * @throws SQLiteMisuseException if the row has no data. See {@link #getColumnType()}. * @throws SQLiteOutOfMemoryException if the database cannot allocate memory for the name. */ @NonNull @@ -606,6 +613,7 @@ public final class SQLiteRawStatement implements Closeable { * @return The length, in bytes, of the value in the column. * @throws IllegalStateException if the statement is closed or this is a foreign thread. * @throws SQLiteBindOrColumnIndexOutOfRangeException if the column is out of range. + * @throws SQLiteMisuseException if the row has no data. See {@link #getColumnType()}. * @throws SQLiteException if a native error occurs. */ public int getColumnLength(int columnIndex) { @@ -631,6 +639,7 @@ public final class SQLiteRawStatement implements Closeable { * @return The value of the column as a blob, or null if the column is NULL. * @throws IllegalStateException if the statement is closed or this is a foreign thread. * @throws SQLiteBindOrColumnIndexOutOfRangeException if the column is out of range. + * @throws SQLiteMisuseException if the row has no data. See {@link #getColumnType()}. * @throws SQLiteException if a native error occurs. */ @Nullable @@ -664,6 +673,7 @@ public final class SQLiteRawStatement implements Closeable { * @throws IllegalStateException if the statement is closed or this is a foreign thread. * @throws IllegalArgumentException if the buffer is too small for offset+length. * @throws SQLiteBindOrColumnIndexOutOfRangeException if the column is out of range. + * @throws SQLiteMisuseException if the row has no data. See {@link #getColumnType()}. * @throws SQLiteException if a native error occurs. */ public int readColumnBlob(int columnIndex, @NonNull byte[] buffer, int offset, @@ -691,6 +701,7 @@ public final class SQLiteRawStatement implements Closeable { * @return The value of a column as a double. * @throws IllegalStateException if the statement is closed or this is a foreign thread. * @throws SQLiteBindOrColumnIndexOutOfRangeException if the column is out of range. + * @throws SQLiteMisuseException if the row has no data. See {@link #getColumnType()}. * @throws SQLiteException if a native error occurs. */ public double getColumnDouble(int columnIndex) { @@ -715,6 +726,7 @@ public final class SQLiteRawStatement implements Closeable { * @return The value of the column as an int. * @throws IllegalStateException if the statement is closed or this is a foreign thread. * @throws SQLiteBindOrColumnIndexOutOfRangeException if the column is out of range. + * @throws SQLiteMisuseException if the row has no data. See {@link #getColumnType()}. * @throws SQLiteException if a native error occurs. */ public int getColumnInt(int columnIndex) { @@ -739,6 +751,7 @@ public final class SQLiteRawStatement implements Closeable { * @return The value of the column as an long. * @throws IllegalStateException if the statement is closed or this is a foreign thread. * @throws SQLiteBindOrColumnIndexOutOfRangeException if the column is out of range. + * @throws SQLiteMisuseException if the row has no data. See {@link #getColumnType()}. * @throws SQLiteException if a native error occurs. */ public long getColumnLong(int columnIndex) { @@ -763,6 +776,7 @@ public final class SQLiteRawStatement implements Closeable { * @return The value of the column as a string. * @throws IllegalStateException if the statement is closed or this is a foreign thread. * @throws SQLiteBindOrColumnIndexOutOfRangeException if the column is out of range. + * @throws SQLiteMisuseException if the row has no data. See {@link #getColumnType()}. * @throws SQLiteException if a native error occurs. */ @NonNull diff --git a/core/java/android/hardware/contexthub/HubEndpoint.java b/core/java/android/hardware/contexthub/HubEndpoint.java index 7efdd6dbdf4196c7f4ddf40929c3fb8563bb4409..1f12bbf4d074f3450e3aeafdd560983bc10791a2 100644 --- a/core/java/android/hardware/contexthub/HubEndpoint.java +++ b/core/java/android/hardware/contexthub/HubEndpoint.java @@ -107,7 +107,7 @@ public class HubEndpoint { public void onSessionOpenRequest( int sessionId, HubEndpointInfo initiator, - @Nullable HubServiceInfo serviceInfo) + @Nullable String serviceDescriptor) throws RemoteException { HubEndpointSession activeSession; synchronized (mLock) { @@ -128,16 +128,16 @@ public class HubEndpoint { processSessionOpenRequestResult( sessionId, initiator, - serviceInfo, + serviceDescriptor, mLifecycleCallback.onSessionOpenRequest( - initiator, serviceInfo))); + initiator, serviceDescriptor))); } } private void processSessionOpenRequestResult( int sessionId, HubEndpointInfo initiator, - @Nullable HubServiceInfo serviceInfo, + @Nullable String serviceDescriptor, HubEndpointSessionResult result) { if (result == null) { throw new IllegalArgumentException( @@ -145,7 +145,7 @@ public class HubEndpoint { } if (result.isAccepted()) { - acceptSession(sessionId, initiator, serviceInfo); + acceptSession(sessionId, initiator, serviceDescriptor); } else { Log.i( TAG, @@ -162,7 +162,7 @@ public class HubEndpoint { private void acceptSession( int sessionId, HubEndpointInfo initiator, - @Nullable HubServiceInfo serviceInfo) { + @Nullable String serviceDescriptor) { if (mServiceToken == null || mAssignedHubEndpointInfo == null) { // No longer registered? return; @@ -187,7 +187,7 @@ public class HubEndpoint { HubEndpoint.this, mAssignedHubEndpointInfo, initiator, - serviceInfo); + serviceDescriptor); try { // oneway call to notify system service that the request is completed mServiceToken.openSessionRequestComplete(sessionId); @@ -334,7 +334,6 @@ public class HubEndpoint { @Nullable IHubEndpointMessageCallback endpointMessageCallback, @NonNull Executor messageCallbackExecutor) { mPendingHubEndpointInfo = pendingEndpointInfo; - mLifecycleCallback = endpointLifecycleCallback; mLifecycleCallbackExecutor = lifecycleCallbackExecutor; mMessageCallback = endpointMessageCallback; @@ -387,7 +386,7 @@ public class HubEndpoint { } /** @hide */ - public void openSession(HubEndpointInfo destinationInfo, @Nullable HubServiceInfo serviceInfo) { + public void openSession(HubEndpointInfo destinationInfo, @Nullable String serviceDescriptor) { // TODO(b/378974199): Consider refactor these assertions if (mServiceToken == null || mAssignedHubEndpointInfo == null) { // No longer registered? @@ -397,7 +396,7 @@ public class HubEndpoint { HubEndpointSession newSession; try { // Request system service to assign session id. - int sessionId = mServiceToken.openSession(destinationInfo, serviceInfo); + int sessionId = mServiceToken.openSession(destinationInfo, serviceDescriptor); // Save the newly created session synchronized (mLock) { @@ -407,7 +406,7 @@ public class HubEndpoint { HubEndpoint.this, destinationInfo, mAssignedHubEndpointInfo, - serviceInfo); + serviceDescriptor); mActiveSessions.put(sessionId, newSession); } } catch (RemoteException e) { diff --git a/core/java/android/hardware/contexthub/HubEndpointSession.java b/core/java/android/hardware/contexthub/HubEndpointSession.java index cf952cbdbfdc54864b9d9c8d18ad9696391ade16..77f937ebeabc2025b5988470549d8ef01f2fd895 100644 --- a/core/java/android/hardware/contexthub/HubEndpointSession.java +++ b/core/java/android/hardware/contexthub/HubEndpointSession.java @@ -19,6 +19,7 @@ package android.hardware.contexthub; import android.annotation.FlaggedApi; import android.annotation.NonNull; import android.annotation.Nullable; +import android.annotation.RequiresPermission; import android.annotation.SystemApi; import android.chre.flags.Flags; import android.hardware.location.ContextHubTransaction; @@ -43,7 +44,7 @@ public class HubEndpointSession implements AutoCloseable { @NonNull private final HubEndpoint mHubEndpoint; @NonNull private final HubEndpointInfo mInitiator; @NonNull private final HubEndpointInfo mDestination; - @Nullable private final HubServiceInfo mServiceInfo; + @Nullable private final String mServiceDescriptor; private final AtomicBoolean mIsClosed = new AtomicBoolean(true); @@ -53,12 +54,12 @@ public class HubEndpointSession implements AutoCloseable { @NonNull HubEndpoint hubEndpoint, @NonNull HubEndpointInfo destination, @NonNull HubEndpointInfo initiator, - @Nullable HubServiceInfo serviceInfo) { + @Nullable String serviceDescriptor) { mId = id; mHubEndpoint = hubEndpoint; mDestination = destination; mInitiator = initiator; - mServiceInfo = serviceInfo; + mServiceDescriptor = serviceDescriptor; } /** @@ -68,8 +69,11 @@ public class HubEndpointSession implements AutoCloseable { * @return For messages that does not require a response, the transaction will immediately * complete. For messages that requires a response, the transaction will complete after * receiving the response for the message. + * @throws SecurityException if the application doesn't have the right permissions to send this + * message. */ @NonNull + @RequiresPermission(android.Manifest.permission.ACCESS_CONTEXT_HUB) public ContextHubTransaction sendMessage(@NonNull HubMessage message) { if (mIsClosed.get()) { throw new IllegalStateException("Session is already closed."); @@ -120,6 +124,7 @@ public class HubEndpointSession implements AutoCloseable { *

When this function is invoked, the messaging associated with this session is invalidated. * All futures messages targeted for this client are dropped. */ + @RequiresPermission(android.Manifest.permission.ACCESS_CONTEXT_HUB) public void close() { if (!mIsClosed.getAndSet(true)) { mCloseGuard.close(); @@ -128,8 +133,8 @@ public class HubEndpointSession implements AutoCloseable { } /** - * Get the {@link HubServiceInfo} associated with this session. Null value indicates that there - * is no service associated to this session. + * Get the service descriptor associated with this session. Null value indicates that there is + * no service associated to this session. * *

For hub initiated sessions, the object was previously used in as an argument for open * request in {@link IHubEndpointLifecycleCallback#onSessionOpenRequest}. @@ -138,8 +143,8 @@ public class HubEndpointSession implements AutoCloseable { * android.hardware.location.ContextHubManager#openSession} */ @Nullable - public HubServiceInfo getServiceInfo() { - return mServiceInfo; + public String getServiceDescriptor() { + return mServiceDescriptor; } @Override diff --git a/core/java/android/hardware/contexthub/IContextHubEndpoint.aidl b/core/java/android/hardware/contexthub/IContextHubEndpoint.aidl index 1c98b4b3f4f569d6e56d25de180d9001a12b5eec..b76b2271fe5762a74742299630306978e78314bb 100644 --- a/core/java/android/hardware/contexthub/IContextHubEndpoint.aidl +++ b/core/java/android/hardware/contexthub/IContextHubEndpoint.aidl @@ -34,11 +34,12 @@ interface IContextHubEndpoint { * Request system service to open a session with a specific destination. * * @param destination A valid HubEndpointInfo representing the destination. + * @param serviceDescriptor An optional descriptor of the service to scope this session to. * * @throws IllegalArgumentException If the HubEndpointInfo is not valid. * @throws IllegalStateException If there are too many opened sessions. */ - int openSession(in HubEndpointInfo destination, in @nullable HubServiceInfo serviceInfo); + int openSession(in HubEndpointInfo destination, in @nullable String serviceDescriptor); /** * Request system service to close a specific session diff --git a/core/java/android/hardware/contexthub/IContextHubEndpointCallback.aidl b/core/java/android/hardware/contexthub/IContextHubEndpointCallback.aidl index 1ae5fb9d28c1a2d989ed1f41a629dff648f67c49..63edda84bde552a78263d9d2a7f9ea416630e2ea 100644 --- a/core/java/android/hardware/contexthub/IContextHubEndpointCallback.aidl +++ b/core/java/android/hardware/contexthub/IContextHubEndpointCallback.aidl @@ -29,9 +29,9 @@ oneway interface IContextHubEndpointCallback { * * @param sessionId An integer identifying the session, assigned by the initiator * @param initiator HubEndpointInfo representing the requester - * @param serviceInfo Nullable HubServiceInfo representing the service associated with this session + * @param serviceDescriptor Nullable string representing the service associated with this session */ - void onSessionOpenRequest(int sessionId, in HubEndpointInfo initiator, in @nullable HubServiceInfo serviceInfo); + void onSessionOpenRequest(int sessionId, in HubEndpointInfo initiator, in @nullable String serviceDescriptor); /** * Request from system service to close a specific session diff --git a/core/java/android/hardware/contexthub/IHubEndpointLifecycleCallback.java b/core/java/android/hardware/contexthub/IHubEndpointLifecycleCallback.java index fe449bb5ce0e92d13a91b8e774bdd54a54bbc18f..698ed0adfd804c4f447648ad7acf98aa98f44e17 100644 --- a/core/java/android/hardware/contexthub/IHubEndpointLifecycleCallback.java +++ b/core/java/android/hardware/contexthub/IHubEndpointLifecycleCallback.java @@ -34,12 +34,12 @@ public interface IHubEndpointLifecycleCallback { * Called when an endpoint is requesting a session be opened with another endpoint. * * @param requester The {@link HubEndpointInfo} object representing the requester - * @param serviceInfo The {@link HubServiceInfo} object representing the service associated with - * this session. Null indicates that there is no service associated with this session. + * @param serviceDescriptor A string describing the service associated with this session. Null + * indicates that there is no service associated with this session. */ @NonNull HubEndpointSessionResult onSessionOpenRequest( - @NonNull HubEndpointInfo requester, @Nullable HubServiceInfo serviceInfo); + @NonNull HubEndpointInfo requester, @Nullable String serviceDescriptor); /** * Called when a communication session is opened and ready to be used. diff --git a/core/java/android/hardware/display/DisplayTopology.java b/core/java/android/hardware/display/DisplayTopology.java index 54d0dd0eb8f8e1c59bf1bb8064796422b29805d5..211aefffa34c3b05b00e6a45abccbffab8f759c3 100644 --- a/core/java/android/hardware/display/DisplayTopology.java +++ b/core/java/android/hardware/display/DisplayTopology.java @@ -91,6 +91,15 @@ public final class DisplayTopology implements Parcelable { @VisibleForTesting public DisplayTopology(TreeNode root, int primaryDisplayId) { mRoot = root; + if (mRoot != null) { + // Set mRoot's position and offset to predictable values, just so we don't leak state + // from some previous arrangement the node was used in, or leak arbitrary values passed + // to the TreeNode constructor. The position and offset don't mean anything because + // mRoot doesn't have a parent. + mRoot.mPosition = POSITION_LEFT; + mRoot.mOffset = 0f; + } + mPrimaryDisplayId = primaryDisplayId; } @@ -422,6 +431,14 @@ public final class DisplayTopology implements Parcelable { } } } + + // Sort children lists by display ID. + final Comparator idComparator = (d1, d2) -> { + return Integer.compare(d1.mDisplayId, d2.mDisplayId); + }; + for (TreeNode display : displays) { + display.mChildren.sort(idComparator); + } } /** @@ -582,6 +599,15 @@ public final class DisplayTopology implements Parcelable { } } + /** Returns the graph representation of the topology */ + public DisplayTopologyGraph getGraph() { + // TODO(b/364907904): implement + return new DisplayTopologyGraph(mPrimaryDisplayId, + new DisplayTopologyGraph.DisplayNode[] { new DisplayTopologyGraph.DisplayNode( + mRoot == null ? Display.DEFAULT_DISPLAY : mRoot.mDisplayId, + new DisplayTopologyGraph.AdjacentDisplay[0])}); + } + /** * Tests whether two brightness float values are within a small enough tolerance * of each other. diff --git a/core/java/android/hardware/display/DisplayTopologyGraph.java b/core/java/android/hardware/display/DisplayTopologyGraph.java new file mode 100644 index 0000000000000000000000000000000000000000..938e6d108f5dca2b2ffb34a50bec6b7ce1e9a300 --- /dev/null +++ b/core/java/android/hardware/display/DisplayTopologyGraph.java @@ -0,0 +1,43 @@ +/* + * Copyright 2024 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES 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.display; + +/** + * Graph of the displays in {@link android.hardware.display.DisplayTopology} tree. + * + * @hide + */ +public record DisplayTopologyGraph(int primaryDisplayId, DisplayNode[] displayNodes) { + /** + * Display in the topology + */ + public record DisplayNode( + int displayId, + AdjacentDisplay[] adjacentDisplays) {} + + /** + * Edge to adjacent display + */ + public record AdjacentDisplay( + // The logical Id of this adjacent display + int displayId, + // Side of the other display which touches this adjacent display. + @DisplayTopology.TreeNode.Position + int position, + // How many px this display is shifted along the touchingSide, can be negative. + float offsetPx) {} +} diff --git a/core/java/android/hardware/display/VirtualDisplayConfig.java b/core/java/android/hardware/display/VirtualDisplayConfig.java index eceaa8ff4c952268ee7bbf01baba9fe87f04ec9e..72570553f78a25732e09ccfa71fc2dfa9362b31f 100644 --- a/core/java/android/hardware/display/VirtualDisplayConfig.java +++ b/core/java/android/hardware/display/VirtualDisplayConfig.java @@ -66,6 +66,7 @@ public final class VirtualDisplayConfig implements Parcelable { private final DisplayCutout mDisplayCutout; private final boolean mIgnoreActivitySizeRestrictions; private final float mDefaultBrightness; + private final float mDimBrightness; private final IBrightnessListener mBrightnessListener; private VirtualDisplayConfig( @@ -84,6 +85,7 @@ public final class VirtualDisplayConfig implements Parcelable { @Nullable DisplayCutout displayCutout, boolean ignoreActivitySizeRestrictions, @FloatRange(from = 0.0f, to = 1.0f) float defaultBrightness, + @FloatRange(from = 0.0f, to = 1.0f) float dimBrightness, IBrightnessListener brightnessListener) { mName = name; mWidth = width; @@ -100,6 +102,7 @@ public final class VirtualDisplayConfig implements Parcelable { mDisplayCutout = displayCutout; mIgnoreActivitySizeRestrictions = ignoreActivitySizeRestrictions; mDefaultBrightness = defaultBrightness; + mDimBrightness = dimBrightness; mBrightnessListener = brightnessListener; } @@ -179,6 +182,19 @@ public final class VirtualDisplayConfig implements Parcelable { return mDefaultBrightness; } + /** + * Returns the dim brightness of the display. + * + *

Value of {@code 0.0} indicates the minimum supported brightness and value of {@code 1.0} + * indicates the maximum supported brightness.

+ * + * @see Builder#setDimBrightness(float) + */ + @FlaggedApi(android.companion.virtualdevice.flags.Flags.FLAG_DEVICE_AWARE_DISPLAY_POWER) + public @FloatRange(from = 0.0f, to = 1.0f) float getDimBrightness() { + return mDimBrightness; + } + /** * Returns the listener to get notified about changes in the display brightness. * @hide @@ -278,6 +294,7 @@ public final class VirtualDisplayConfig implements Parcelable { DisplayCutout.ParcelableWrapper.writeCutoutToParcel(mDisplayCutout, dest, flags); dest.writeBoolean(mIgnoreActivitySizeRestrictions); dest.writeFloat(mDefaultBrightness); + dest.writeFloat(mDimBrightness); dest.writeStrongBinder(mBrightnessListener != null ? mBrightnessListener.asBinder() : null); } @@ -308,8 +325,8 @@ public final class VirtualDisplayConfig implements Parcelable { && mIgnoreActivitySizeRestrictions == that.mIgnoreActivitySizeRestrictions && Objects.equals(mDisplayCutout, that.mDisplayCutout) && mDefaultBrightness == that.mDefaultBrightness + && mDimBrightness == that.mDimBrightness && Objects.equals(mBrightnessListener, that.mBrightnessListener); - } @Override @@ -318,7 +335,8 @@ public final class VirtualDisplayConfig implements Parcelable { mName, mWidth, mHeight, mDensityDpi, mFlags, mSurface, mUniqueId, mDisplayIdToMirror, mWindowManagerMirroringEnabled, mDisplayCategories, mRequestedRefreshRate, mIsHomeSupported, mDisplayCutout, - mIgnoreActivitySizeRestrictions, mDefaultBrightness, mBrightnessListener); + mIgnoreActivitySizeRestrictions, mDefaultBrightness, mDimBrightness, + mBrightnessListener); return hashCode; } @@ -341,6 +359,7 @@ public final class VirtualDisplayConfig implements Parcelable { + " mDisplayCutout=" + mDisplayCutout + " mIgnoreActivitySizeRestrictions=" + mIgnoreActivitySizeRestrictions + " mDefaultBrightness=" + mDefaultBrightness + + " mDimBrightness=" + mDimBrightness + ")"; } @@ -360,8 +379,8 @@ public final class VirtualDisplayConfig implements Parcelable { mDisplayCutout = DisplayCutout.ParcelableWrapper.readCutoutFromParcel(in); mIgnoreActivitySizeRestrictions = in.readBoolean(); mDefaultBrightness = in.readFloat(); + mDimBrightness = in.readFloat(); mBrightnessListener = IBrightnessListener.Stub.asInterface(in.readStrongBinder()); - } /** @@ -432,6 +451,7 @@ public final class VirtualDisplayConfig implements Parcelable { private DisplayCutout mDisplayCutout = null; private boolean mIgnoreActivitySizeRestrictions = false; private float mDefaultBrightness = 0.0f; + private float mDimBrightness = PowerManager.BRIGHTNESS_INVALID; private IBrightnessListener mBrightnessListener = null; /** @@ -635,14 +655,14 @@ public final class VirtualDisplayConfig implements Parcelable { * *

If unset, defaults to {@code 0.0}

* + * @throws IllegalArgumentException if the brightness is outside the valid range [0.0, 1.0] * @see android.view.View#setKeepScreenOn(boolean) * @see #setBrightnessListener(Executor, BrightnessListener) */ @FlaggedApi(android.companion.virtualdevice.flags.Flags.FLAG_DEVICE_AWARE_DISPLAY_POWER) @NonNull public Builder setDefaultBrightness(@FloatRange(from = 0.0f, to = 1.0f) float brightness) { - if (brightness < PowerManager.BRIGHTNESS_MIN - || brightness > PowerManager.BRIGHTNESS_MAX) { + if (!isValidBrightness(brightness)) { throw new IllegalArgumentException( "Virtual display default brightness must be in range [0.0, 1.0]"); } @@ -650,6 +670,33 @@ public final class VirtualDisplayConfig implements Parcelable { return this; } + /** + * Sets the dim brightness of the display. + * + *

The system will use this brightness value whenever the display should be dim, i.e. + * it is powered on and dimmed due to user activity or app activity.

+ * + *

Value of {@code 0.0} indicates the minimum supported brightness and value of + * {@code 1.0} indicates the maximum supported brightness.

+ * + *

If set, the default brightness must also be set to a value greater or equal to the + * dim brightness. If unset, defaults to the system default.

+ * + * @throws IllegalArgumentException if the brightness is outside the valid range [0.0, 1.0] + * @see Builder#setDefaultBrightness(float) + * @see #setBrightnessListener(Executor, BrightnessListener) + */ + @FlaggedApi(android.companion.virtualdevice.flags.Flags.FLAG_DEVICE_AWARE_DISPLAY_POWER) + @NonNull + public Builder setDimBrightness(@FloatRange(from = 0.0f, to = 1.0f) float brightness) { + if (!isValidBrightness(brightness)) { + throw new IllegalArgumentException( + "Virtual display dim brightness must be in range [0.0, 1.0]"); + } + mDimBrightness = brightness; + return this; + } + /** * Sets the listener to get notified about changes in the display brightness. * @@ -666,11 +713,23 @@ public final class VirtualDisplayConfig implements Parcelable { return this; } + private boolean isValidBrightness(float brightness) { + return !Float.isNaN(brightness) && PowerManager.BRIGHTNESS_MIN <= brightness + && brightness <= PowerManager.BRIGHTNESS_MAX; + } + /** * Builds the {@link VirtualDisplayConfig} instance. + * + * @throws IllegalArgumentException if the dim brightness is set to a value greater than + * the default brightness. */ @NonNull public VirtualDisplayConfig build() { + if (isValidBrightness(mDimBrightness) && mDimBrightness > mDefaultBrightness) { + throw new IllegalArgumentException( + "The dim brightness must not be greater than the default brightness"); + } return new VirtualDisplayConfig( mName, mWidth, @@ -687,6 +746,7 @@ public final class VirtualDisplayConfig implements Parcelable { mDisplayCutout, mIgnoreActivitySizeRestrictions, mDefaultBrightness, + mDimBrightness, mBrightnessListener); } } diff --git a/core/java/android/hardware/input/InputSettings.java b/core/java/android/hardware/input/InputSettings.java index 3f9317aa24f124e7a64a062efb7d36067d952118..f8f7f5e0586e2453305d46d446ba9e39d2d5b5b8 100644 --- a/core/java/android/hardware/input/InputSettings.java +++ b/core/java/android/hardware/input/InputSettings.java @@ -28,7 +28,6 @@ import static com.android.hardware.input.Flags.keyboardA11yStickyKeysFlag; import static com.android.hardware.input.Flags.mouseReverseVerticalScrolling; import static com.android.hardware.input.Flags.mouseSwapPrimaryButton; import static com.android.hardware.input.Flags.touchpadSystemGestureDisable; -import static com.android.hardware.input.Flags.touchpadTapDragging; import static com.android.hardware.input.Flags.touchpadThreeFingerTapShortcut; import static com.android.hardware.input.Flags.touchpadVisualizer; import static com.android.hardware.input.Flags.useKeyGestureEventHandler; @@ -365,15 +364,6 @@ public class InputSettings { UserHandle.USER_CURRENT); } - /** - * Returns true if the feature flag for touchpad tap dragging is enabled. - * - * @hide - */ - public static boolean isTouchpadTapDraggingFeatureFlagEnabled() { - return touchpadTapDragging(); - } - /** * Returns true if the feature flag for disabling system gestures on touchpads is enabled. * @@ -461,9 +451,6 @@ public class InputSettings { * @hide */ public static boolean useTouchpadTapDragging(@NonNull Context context) { - if (!isTouchpadTapDraggingFeatureFlagEnabled()) { - return false; - } return Settings.System.getIntForUser(context.getContentResolver(), Settings.System.TOUCHPAD_TAP_DRAGGING, 0, UserHandle.USER_CURRENT) == 1; } @@ -480,9 +467,6 @@ public class InputSettings { */ @RequiresPermission(Manifest.permission.WRITE_SETTINGS) public static void setTouchpadTapDragging(@NonNull Context context, boolean enabled) { - if (!isTouchpadTapDraggingFeatureFlagEnabled()) { - return; - } Settings.System.putIntForUser(context.getContentResolver(), Settings.System.TOUCHPAD_TAP_DRAGGING, enabled ? 1 : 0, UserHandle.USER_CURRENT); diff --git a/core/java/android/hardware/input/KeyGestureEvent.java b/core/java/android/hardware/input/KeyGestureEvent.java index 711dc3a2cf7c49ce86c0b96b9cbcf1900d249c1c..af756b9217d39121e4bd48661cf2d159749731c6 100644 --- a/core/java/android/hardware/input/KeyGestureEvent.java +++ b/core/java/android/hardware/input/KeyGestureEvent.java @@ -43,6 +43,8 @@ public final class KeyGestureEvent { private static final int LOG_EVENT_UNSPECIFIED = FrameworkStatsLog.KEYBOARD_SYSTEMS_EVENT_REPORTED__KEYBOARD_SYSTEM_EVENT__UNSPECIFIED; + // These values should not change and values should not be re-used as this data is persisted to + // long term storage and must be kept backwards compatible. public static final int KEY_GESTURE_TYPE_UNSPECIFIED = 0; public static final int KEY_GESTURE_TYPE_HOME = 1; public static final int KEY_GESTURE_TYPE_RECENT_APPS = 2; diff --git a/core/java/android/hardware/input/input_framework.aconfig b/core/java/android/hardware/input/input_framework.aconfig index ebb617249993e54f61706ee08fbbe89e0a6b54bd..aaa78aa0916a3a6730e2e81c66871149110d8912 100644 --- a/core/java/android/hardware/input/input_framework.aconfig +++ b/core/java/android/hardware/input/input_framework.aconfig @@ -35,13 +35,6 @@ flag { bug: "294546335" } -flag { - namespace: "input_native" - name: "touchpad_tap_dragging" - description: "Offers a setting to enable touchpad tap dragging" - bug: "321978150" -} - flag { namespace: "input_native" name: "keyboard_glyph_map" @@ -196,4 +189,11 @@ flag { namespace: "wallet_integration" description: "Adds new API in WindowManager class to check if the window can override the power key double tap behavior." bug: "378736024" - } \ No newline at end of file + } + +flag { + name: "pointer_acceleration" + namespace: "input" + description: "Allows the user to disable pointer acceleration for mouse and touchpads." + bug: "349006858" +} \ No newline at end of file diff --git a/core/java/android/hardware/location/ContextHubManager.java b/core/java/android/hardware/location/ContextHubManager.java index 3a74130d5e831c78ebe4300147d9b1bc9e3eb999..d9888ad6cd8d736b4e92e840076383b2053f49f1 100644 --- a/core/java/android/hardware/location/ContextHubManager.java +++ b/core/java/android/hardware/location/ContextHubManager.java @@ -841,6 +841,7 @@ public final class ContextHubManager { * @param endpointId The identifier of the hub endpoint. * @param callback The callback to be invoked. * @param executor The executor to invoke the callback on. + * @throws UnsupportedOperationException If the operation is not supported. */ @RequiresPermission(android.Manifest.permission.ACCESS_CONTEXT_HUB) @FlaggedApi(Flags.FLAG_OFFLOAD_API) @@ -881,6 +882,7 @@ public final class ContextHubManager { * @param callback The callback to be invoked. * @param executor The executor to invoke the callback on. * @throws IllegalArgumentException if the serviceDescriptor is empty. + * @throws UnsupportedOperationException If the operation is not supported. */ @RequiresPermission(android.Manifest.permission.ACCESS_CONTEXT_HUB) @FlaggedApi(Flags.FLAG_OFFLOAD_API) @@ -911,6 +913,7 @@ public final class ContextHubManager { * * @param callback The callback previously registered. * @throws IllegalArgumentException If the callback was not previously registered. + * @throws UnsupportedOperationException If the operation is not supported. */ @RequiresPermission(android.Manifest.permission.ACCESS_CONTEXT_HUB) @FlaggedApi(Flags.FLAG_OFFLOAD_API) @@ -1309,16 +1312,18 @@ public final class ContextHubManager { * ContextHubManager#registerEndpoint(HubEndpoint)}. * @param destination {@link HubEndpointInfo} object that represents an endpoint from previous * endpoint discovery results (e.g. from {@link ContextHubManager#findEndpoints(long)}). - * @param serviceInfo {@link HubServiceInfo} object that describes the service associated with - * this session. The information will be sent to the destination as part of open request. + * @param serviceDescriptor A string that describes the service associated with this session. + * The information will be sent to the destination as part of open request. + * @throws IllegalStateException if hubEndpoint was not successfully registered, or if there is + * insufficient capacity for creating a session. */ @RequiresPermission(android.Manifest.permission.ACCESS_CONTEXT_HUB) @FlaggedApi(Flags.FLAG_OFFLOAD_API) public void openSession( @NonNull HubEndpoint hubEndpoint, @NonNull HubEndpointInfo destination, - @NonNull HubServiceInfo serviceInfo) { - hubEndpoint.openSession(destination, serviceInfo); + @NonNull String serviceDescriptor) { + hubEndpoint.openSession(destination, serviceDescriptor); } /** diff --git a/core/java/android/hardware/radio/ProgramSelector.java b/core/java/android/hardware/radio/ProgramSelector.java index 42028f67f4005e0fb6bdf8ab2a1597ed7df1fb8a..e5717ac87d88d0faf11441b2faacc5ff33616e02 100644 --- a/core/java/android/hardware/radio/ProgramSelector.java +++ b/core/java/android/hardware/radio/ProgramSelector.java @@ -43,22 +43,20 @@ import java.util.stream.Stream; *
  • DAB channel info
  • * * - *

    The primary ID uniquely identifies a station and can be used for equality - * check. The secondary IDs are supplementary and can speed up tuning process, - * but the primary ID is sufficient (ie. after a full band scan). - * - *

    Two selectors with different secondary IDs, but the same primary ID are - * considered equal. In particular, secondary IDs vector may get updated for + *

    Except for DAB radio, two selectors with different secondary IDs, but the same primary + * ID are considered equal. In particular, secondary IDs vector may get updated for * an entry on the program list (ie. when a better frequency for a given - * station is found). + * station is found). For DAB radio, two selectors with the same primary ID and the same + * DAB frequency and DAB ensemble secondary IDs (if exist) are considered equal. * *

    The primaryId of a given programType MUST be of a specific type: * - *

  • AM, FM: RDS_PI if the station broadcasts RDS, AMFM_FREQUENCY otherwise;
  • - *
  • AM_HD, FM_HD: HD_STATION_ID_EXT;
  • - *
  • DAB: DAB_SIDECC;
  • - *
  • DRMO: DRMO_SERVICE_ID;
  • - *
  • SXM: SXM_SERVICE_ID;
  • + *
  • AM, FM: {@link #IDENTIFIER_TYPE_RDS_PI} if the station broadcasts RDS, + * {@link #IDENTIFIER_TYPE_AMFM_FREQUENCY} otherwise;
  • + *
  • AM_HD, FM_HD: {@link #IDENTIFIER_TYPE_HD_STATION_ID_EXT};
  • + *
  • DAB: {@link #IDENTIFIER_TYPE_DAB_SID_EXT} or + * {@link #IDENTIFIER_TYPE_DAB_DMB_SID_EXT};
  • + *
  • DRMO: {@link #IDENTIFIER_TYPE_DRMO_SERVICE_ID};
  • *
  • VENDOR: VENDOR_PRIMARY.
  • * * @hide @@ -597,9 +595,9 @@ public final class ProgramSelector implements Parcelable { * negatives. In particular, it may be way off for certain regions. * The main purpose is to avoid passing improper units, ie. MHz instead of kHz. * - * @param isAm true, if AM, false if FM. + * @param isAm {@code true}, if AM, {@code false} if FM. * @param frequencyKhz the frequency in kHz. - * @return true, if the frequency is roughly valid. + * @return {@code true}, if the frequency is roughly valid. */ private static boolean isValidAmFmFrequency(boolean isAm, int frequencyKhz) { if (isAm) { @@ -785,8 +783,8 @@ public final class ProgramSelector implements Parcelable { * ProgramLists for category entries. * * @see ProgramList.Filter#areCategoriesIncluded - * @return False if this identifier's type is not tunable (e.g. DAB ensemble or - * vendor-specified type). True otherwise. + * @return {@link false} if this identifier's type is not tunable (e.g. DAB ensemble or + * vendor-specified type). {@link true} otherwise. */ public boolean isCategoryType() { return (mType >= IDENTIFIER_TYPE_VENDOR_START && mType <= IDENTIFIER_TYPE_VENDOR_END) diff --git a/core/java/android/inputmethodservice/IInputMethodSessionWrapper.java b/core/java/android/inputmethodservice/IInputMethodSessionWrapper.java index 9b37533f5b02dcf5899e9a46fd3b6a52760e29c8..9badbf8e2a1b7d3dcee4d6f8862ce0f39e450d40 100644 --- a/core/java/android/inputmethodservice/IInputMethodSessionWrapper.java +++ b/core/java/android/inputmethodservice/IInputMethodSessionWrapper.java @@ -299,9 +299,10 @@ class IInputMethodSessionWrapper extends IInputMethodSession.Stub if (event.hasNoModifiers()) { return false; } - return event.hasModifiers(KeyEvent.META_CTRL_ON) - || event.hasModifiers(KeyEvent.META_ALT_ON) - || event.hasModifiers(KeyEvent.KEYCODE_FUNCTION); + return event.isCtrlPressed() + || event.isAltPressed() + || event.isFunctionPressed() + || event.isMetaPressed(); } private boolean needsVerification(KeyEvent event) { diff --git a/core/java/android/net/EventLogTags.logtags b/core/java/android/net/EventLogTags.logtags index d5ed01496eba669df1a3a0d10bab218aa6c6e013..32953c92d1203c39a36e4fa070e630451510a25c 100644 --- a/core/java/android/net/EventLogTags.logtags +++ b/core/java/android/net/EventLogTags.logtags @@ -1,4 +1,4 @@ -# See system/core/logcat/event.logtags for a description of the format of this file. +# See system/logging/logcat/event.logtags for a description of the format of this file. option java_package android.net diff --git a/core/java/android/net/metrics/DnsEvent.java b/core/java/android/net/metrics/DnsEvent.java index bf351ce07fe8109970a8350c2e88e3c8c9e5dee8..f53d1c4d191dcc36d031cfcaa3acecd5222f9b51 100644 --- a/core/java/android/net/metrics/DnsEvent.java +++ b/core/java/android/net/metrics/DnsEvent.java @@ -62,7 +62,11 @@ final public class DnsEvent { return isSuccess; } if (eventCount == eventTypes.length) { - resize((int) (1.4 * eventCount)); + int resizeLength = (int) (1.4 * eventCount); + if (eventCount == resizeLength) { + resizeLength++; + } + resize(resizeLength); } eventTypes[eventCount] = eventType; returnCodes[eventCount] = returnCode; diff --git a/core/java/android/os/Build.java b/core/java/android/os/Build.java index 8b6da7e0ae58f5a0bc6e8dc52e1b7caa100d34aa..84ca5ed4ab1024fbbc53ab3b4a23b4d1661dcae0 100644 --- a/core/java/android/os/Build.java +++ b/core/java/android/os/Build.java @@ -403,7 +403,7 @@ public class Build { * increase when the hardware manufacturer provides an OTA update. *

    * This constant records the major version of Android. Use {@link - * SDK_INT_FULL} if you need to consider the minor version of Android + * #SDK_INT_FULL} if you need to consider the minor version of Android * as well. *

    * Possible values are defined in {@link Build.VERSION_CODES}. diff --git a/core/java/android/os/Bundle.java b/core/java/android/os/Bundle.java index 05bd10b053fe92096c1760a61eca1e5676b5e6a2..819d58d9f0598294b755e62e47ff4108aa8a6367 100644 --- a/core/java/android/os/Bundle.java +++ b/core/java/android/os/Bundle.java @@ -70,6 +70,11 @@ public final class Bundle extends BaseBundle implements Cloneable, Parcelable { */ static final int FLAG_VERIFY_TOKENS_PRESENT = 1 << 13; + /** + * Indicates the bundle definitely contains an Intent. + */ + static final int FLAG_HAS_INTENT = 1 << 14; + /** * Status when the Bundle can assert that the underlying Parcel DOES NOT contain @@ -117,6 +122,11 @@ public final class Bundle extends BaseBundle implements Cloneable, Parcelable { /** An unmodifiable {@code Bundle} that is always {@link #isEmpty() empty}. */ public static final Bundle EMPTY; + /** + * @hide + */ + public static Class intentClass; + /** * Special extras used to denote extras have been stripped off. * @hide @@ -388,6 +398,7 @@ public final class Bundle extends BaseBundle implements Cloneable, Parcelable { if ((bundle.mFlags & FLAG_HAS_BINDERS_KNOWN) == 0) { mFlags &= ~FLAG_HAS_BINDERS_KNOWN; } + mFlags |= bundle.mFlags & FLAG_HAS_INTENT; } /** @@ -447,6 +458,16 @@ public final class Bundle extends BaseBundle implements Cloneable, Parcelable { } } + /** + * Returns if the bundle definitely contains at least an intent. This method returns false does + * not guarantee the bundle does not contain a nested intent. An intent could still exist in a + * ParcelableArrayList, ParcelableArray, ParcelableList, a bundle in this bundle, etc. + * @hide + */ + public boolean hasIntent() { + return (mFlags & FLAG_HAS_INTENT) != 0; + } + /** {@hide} */ @Override public void putObject(@Nullable String key, @Nullable Object value) { @@ -569,6 +590,9 @@ public final class Bundle extends BaseBundle implements Cloneable, Parcelable { mMap.put(key, value); mFlags &= ~FLAG_HAS_FDS_KNOWN; mFlags &= ~FLAG_HAS_BINDERS_KNOWN; + if (intentClass != null && intentClass.isInstance(value)) { + mFlags |= FLAG_HAS_INTENT; + } } /** diff --git a/core/java/android/os/CombinedMessageQueue/MessageQueue.java b/core/java/android/os/CombinedMessageQueue/MessageQueue.java index 23114c4318c72bc7c6197846c59e5a978ca8e98c..b509c7a441d338eae4a0aadc99abb9d8c4be9135 100644 --- a/core/java/android/os/CombinedMessageQueue/MessageQueue.java +++ b/core/java/android/os/CombinedMessageQueue/MessageQueue.java @@ -18,18 +18,25 @@ package android.os; import android.annotation.IntDef; import android.annotation.NonNull; +import android.annotation.Nullable; +import android.annotation.SuppressLint; import android.annotation.TestApi; +import android.app.ActivityThread; +import android.app.Instrumentation; import android.compat.annotation.UnsupportedAppUsage; import android.os.Process; import android.os.UserHandle; import android.ravenwood.annotation.RavenwoodKeepWholeClass; import android.ravenwood.annotation.RavenwoodRedirect; import android.ravenwood.annotation.RavenwoodRedirectionClass; +import android.ravenwood.annotation.RavenwoodReplace; +import android.ravenwood.annotation.RavenwoodThrow; import android.util.Log; import android.util.Printer; import android.util.SparseArray; import android.util.proto.ProtoOutputStream; +import com.android.internal.annotations.GuardedBy; import com.android.internal.ravenwood.RavenwoodEnvironment; import dalvik.annotation.optimization.NeverCompile; @@ -119,7 +126,7 @@ public final class MessageQueue { MessageQueue(boolean quitAllowed) { initIsProcessAllowedToUseConcurrent(); - mUseConcurrent = sIsProcessAllowedToUseConcurrent; + mUseConcurrent = sIsProcessAllowedToUseConcurrent && !isInstrumenting(); mQuitAllowed = quitAllowed; mPtr = nativeInit(); } @@ -172,6 +179,37 @@ public final class MessageQueue { } } + @RavenwoodReplace + private static void throwIfNotTest() { + final ActivityThread activityThread = ActivityThread.currentActivityThread(); + if (activityThread == null) { + // Only tests can reach here. + return; + } + final Instrumentation instrumentation = activityThread.getInstrumentation(); + if (instrumentation == null) { + // Only tests can reach here. + return; + } + if (instrumentation.isInstrumenting()) { + return; + } + throw new IllegalStateException("Test-only API called not from a test!"); + } + + private static void throwIfNotTest$ravenwood() { + return; + } + + private static boolean isInstrumenting() { + final ActivityThread activityThread = ActivityThread.currentActivityThread(); + if (activityThread == null) { + return false; + } + final Instrumentation instrumentation = activityThread.getInstrumentation(); + return instrumentation != null && instrumentation.isInstrumenting(); + } + @Override protected void finalize() throws Throwable { try { @@ -192,12 +230,9 @@ public final class MessageQueue { private static final class MatchDeliverableMessages extends MessageCompare { @Override - public boolean compareMessage(Message m, Handler h, int what, Object object, Runnable r, + public boolean compareMessage(MessageNode n, Handler h, int what, Object object, Runnable r, long when) { - if (m.when <= when) { - return true; - } - return false; + return n.mMessage.when <= when; } } private final MatchDeliverableMessages mMatchDeliverableMessages = @@ -344,7 +379,7 @@ public final class MessageQueue { * @see OnFileDescriptorEventListener * @see #removeOnFileDescriptorEventListener */ - @android.ravenwood.annotation.RavenwoodThrow(blockedBy = android.os.ParcelFileDescriptor.class) + @RavenwoodThrow(blockedBy = android.os.ParcelFileDescriptor.class) public void addOnFileDescriptorEventListener(@NonNull FileDescriptor fd, @OnFileDescriptorEventListener.Events int events, @NonNull OnFileDescriptorEventListener listener) { @@ -378,7 +413,7 @@ public final class MessageQueue { * @see OnFileDescriptorEventListener * @see #addOnFileDescriptorEventListener */ - @android.ravenwood.annotation.RavenwoodThrow(blockedBy = android.os.ParcelFileDescriptor.class) + @RavenwoodThrow(blockedBy = android.os.ParcelFileDescriptor.class) public void removeOnFileDescriptorEventListener(@NonNull FileDescriptor fd) { if (fd == null) { throw new IllegalArgumentException("fd must not be null"); @@ -394,7 +429,7 @@ public final class MessageQueue { } } - @android.ravenwood.annotation.RavenwoodThrow(blockedBy = android.os.ParcelFileDescriptor.class) + @RavenwoodThrow(blockedBy = android.os.ParcelFileDescriptor.class) private void updateOnFileDescriptorEventListenerLocked(FileDescriptor fd, int events, OnFileDescriptorEventListener listener) { final int fdNum = fd.getInt$(); @@ -517,7 +552,7 @@ public final class MessageQueue { /* This is only read/written from the Looper thread. For use with Concurrent MQ */ private int mNextPollTimeoutMillis; private boolean mMessageDirectlyQueued; - private Message nextMessage() { + private Message nextMessage(boolean peek) { int i = 0; while (true) { @@ -679,7 +714,7 @@ public final class MessageQueue { if (sState.compareAndSet(this, sStackStateActive, nextOp)) { mMessageCounts.clearCounts(); if (found != null) { - if (!removeFromPriorityQueue(found)) { + if (!peek && !removeFromPriorityQueue(found)) { /* * RemoveMessages() might be able to pull messages out from under us * However we can detect that here and just loop around if it happens. @@ -713,7 +748,7 @@ public final class MessageQueue { mMessageDirectlyQueued = false; nativePollOnce(ptr, mNextPollTimeoutMillis); - Message msg = nextMessage(); + Message msg = nextMessage(false); if (msg != null) { msg.markInUse(); return msg; @@ -1032,8 +1067,9 @@ public final class MessageQueue { } @Override - public boolean compareMessage(Message m, Handler h, int what, Object object, Runnable r, + public boolean compareMessage(MessageNode n, Handler h, int what, Object object, Runnable r, long when) { + final Message m = n.mMessage; if (m.target == null && m.arg1 == mBarrierToken) { return true; } @@ -1236,10 +1272,155 @@ public final class MessageQueue { return true; } + private Message legacyPeekOrPoll(boolean peek) { + synchronized (this) { + // Try to retrieve the next message. Return if found. + final long now = SystemClock.uptimeMillis(); + Message prevMsg = null; + Message msg = mMessages; + if (msg != null && msg.target == null) { + // Stalled by a barrier. Find the next asynchronous message in the queue. + do { + prevMsg = msg; + msg = msg.next; + } while (msg != null && !msg.isAsynchronous()); + } + if (msg != null) { + if (now >= msg.when) { + // Got a message. + mBlocked = false; + if (peek) { + return msg; + } + if (prevMsg != null) { + prevMsg.next = msg.next; + if (prevMsg.next == null) { + mLast = prevMsg; + } + } else { + mMessages = msg.next; + if (msg.next == null) { + mLast = null; + } + } + msg.next = null; + msg.markInUse(); + if (msg.isAsynchronous()) { + mAsyncMessageCount--; + } + if (TRACE) { + Trace.setCounter("MQ.Delivered", mMessagesDelivered.incrementAndGet()); + } + return msg; + } + } + } + return null; + } + + /** + * Get the timestamp of the next executable message in our priority queue. + * Returns null if there are no messages ready for delivery. + * + * Caller must ensure that this doesn't race 'next' from the Looper thread. + */ + @SuppressLint("VisiblySynchronized") // Legacy MessageQueue synchronizes on this + Long peekWhenForTest() { + throwIfNotTest(); + Message ret; + if (mUseConcurrent) { + ret = nextMessage(true); + } else { + ret = legacyPeekOrPoll(true); + } + return ret != null ? ret.when : null; + } + + /** + * Return the next executable message in our priority queue. + * Returns null if there are no messages ready for delivery + * + * Caller must ensure that this doesn't race 'next' from the Looper thread. + */ + @SuppressLint("VisiblySynchronized") // Legacy MessageQueue synchronizes on this + @Nullable + Message pollForTest() { + throwIfNotTest(); + if (mUseConcurrent) { + return nextMessage(false); + } else { + return legacyPeekOrPoll(false); + } + } + + /** + * @return true if we are blocked on a sync barrier + */ + boolean isBlockedOnSyncBarrier() { + throwIfNotTest(); + if (mUseConcurrent) { + Iterator queueIter = mPriorityQueue.iterator(); + MessageNode queueNode = iterateNext(queueIter); + + if (queueNode.isBarrier()) { + long now = SystemClock.uptimeMillis(); + + /* Look for a deliverable async node. If one exists we are not blocked. */ + Iterator asyncQueueIter = mAsyncPriorityQueue.iterator(); + MessageNode asyncNode = iterateNext(asyncQueueIter); + if (asyncNode != null && now >= asyncNode.getWhen()) { + return false; + } + /* + * Look for a deliverable sync node. In this case, if one exists we are blocked + * since the barrier prevents delivery of the Message. + */ + while (queueNode.isBarrier()) { + queueNode = iterateNext(queueIter); + } + if (queueNode != null && now >= queueNode.getWhen()) { + return true; + } + + return false; + } + } else { + Message msg = mMessages; + if (msg != null && msg.target == null) { + Message iter = msg; + /* Look for a deliverable async node */ + do { + iter = iter.next; + } while (iter != null && !iter.isAsynchronous()); + + long now = SystemClock.uptimeMillis(); + if (iter != null && now >= iter.when) { + return false; + } + /* + * Look for a deliverable sync node. In this case, if one exists we are blocked + * since the barrier prevents delivery of the Message. + */ + iter = msg; + do { + iter = iter.next; + } while (iter != null && (iter.target == null || iter.isAsynchronous())); + + if (iter != null && now >= iter.when) { + return true; + } + return false; + } + } + /* No barrier was found. */ + return false; + } + private static final class MatchHandlerWhatAndObject extends MessageCompare { @Override - public boolean compareMessage(Message m, Handler h, int what, Object object, Runnable r, + public boolean compareMessage(MessageNode n, Handler h, int what, Object object, Runnable r, long when) { + final Message m = n.mMessage; if (m.target == h && m.what == what && (object == null || m.obj == object)) { return true; } @@ -1270,8 +1451,9 @@ public final class MessageQueue { private static final class MatchHandlerWhatAndObjectEquals extends MessageCompare { @Override - public boolean compareMessage(Message m, Handler h, int what, Object object, Runnable r, + public boolean compareMessage(MessageNode n, Handler h, int what, Object object, Runnable r, long when) { + final Message m = n.mMessage; if (m.target == h && m.what == what && (object == null || object.equals(m.obj))) { return true; } @@ -1303,8 +1485,9 @@ public final class MessageQueue { private static final class MatchHandlerRunnableAndObject extends MessageCompare { @Override - public boolean compareMessage(Message m, Handler h, int what, Object object, Runnable r, + public boolean compareMessage(MessageNode n, Handler h, int what, Object object, Runnable r, long when) { + final Message m = n.mMessage; if (m.target == h && m.callback == r && (object == null || m.obj == object)) { return true; } @@ -1337,12 +1520,9 @@ public final class MessageQueue { private static final class MatchHandler extends MessageCompare { @Override - public boolean compareMessage(Message m, Handler h, int what, Object object, Runnable r, + public boolean compareMessage(MessageNode n, Handler h, int what, Object object, Runnable r, long when) { - if (m.target == h) { - return true; - } - return false; + return n.mMessage.target == h; } } private final MatchHandler mMatchHandler = new MatchHandler(); @@ -1520,8 +1700,9 @@ public final class MessageQueue { private static final class MatchHandlerRunnableAndObjectEquals extends MessageCompare { @Override - public boolean compareMessage(Message m, Handler h, int what, Object object, Runnable r, + public boolean compareMessage(MessageNode n, Handler h, int what, Object object, Runnable r, long when) { + final Message m = n.mMessage; if (m.target == h && m.callback == r && (object == null || object.equals(m.obj))) { return true; } @@ -1583,8 +1764,9 @@ public final class MessageQueue { private static final class MatchHandlerAndObject extends MessageCompare { @Override - public boolean compareMessage(Message m, Handler h, int what, Object object, Runnable r, + public boolean compareMessage(MessageNode n, Handler h, int what, Object object, Runnable r, long when) { + final Message m = n.mMessage; if (m.target == h && (object == null || m.obj == object)) { return true; } @@ -1644,8 +1826,9 @@ public final class MessageQueue { private static final class MatchHandlerAndObjectEquals extends MessageCompare { @Override - public boolean compareMessage(Message m, Handler h, int what, Object object, Runnable r, + public boolean compareMessage(MessageNode n, Handler h, int what, Object object, Runnable r, long when) { + final Message m = n.mMessage; if (m.target == h && (object == null || object.equals(m.obj))) { return true; } @@ -1751,7 +1934,7 @@ public final class MessageQueue { private static final class MatchAllMessages extends MessageCompare { @Override - public boolean compareMessage(Message m, Handler h, int what, Object object, Runnable r, + public boolean compareMessage(MessageNode n, Handler h, int what, Object object, Runnable r, long when) { return true; } @@ -1763,9 +1946,10 @@ public final class MessageQueue { private static final class MatchAllFutureMessages extends MessageCompare { @Override - public boolean compareMessage(Message m, Handler h, int what, Object object, Runnable r, + public boolean compareMessage(MessageNode n, Handler h, int what, Object object, Runnable r, long when) { - if (m.when > when) { + final Message m = n.mMessage; + if (m.when > when) { return true; } return false; @@ -2471,7 +2655,7 @@ public final class MessageQueue { * This class is used to find matches for hasMessages() and removeMessages() */ private abstract static class MessageCompare { - public abstract boolean compareMessage(Message m, Handler h, int what, Object object, + public abstract boolean compareMessage(MessageNode n, Handler h, int what, Object object, Runnable r, long when); } @@ -2506,7 +2690,7 @@ public final class MessageQueue { MessageNode p = (MessageNode) top; while (true) { - if (compare.compareMessage(p.mMessage, h, what, object, r, when)) { + if (compare.compareMessage(p, h, what, object, r, when)) { found = true; if (DEBUG) { Log.d(TAG_C, "stackHasMessages node matches"); @@ -2551,7 +2735,7 @@ public final class MessageQueue { while (iterator.hasNext()) { MessageNode msg = iterator.next(); - if (compare.compareMessage(msg.mMessage, h, what, object, r, when)) { + if (compare.compareMessage(msg, h, what, object, r, when)) { if (removeMatches) { found = true; if (queue.remove(msg)) { diff --git a/core/java/android/os/ConcurrentMessageQueue/MessageQueue.java b/core/java/android/os/ConcurrentMessageQueue/MessageQueue.java index c2a47d7678014c4246cec15409f08d6a04a51f17..de0259eb1e36c946bf1cdccd343c3802819c6f8b 100644 --- a/core/java/android/os/ConcurrentMessageQueue/MessageQueue.java +++ b/core/java/android/os/ConcurrentMessageQueue/MessageQueue.java @@ -16,9 +16,12 @@ package android.os; +import android.annotation.FlaggedApi; import android.annotation.IntDef; import android.annotation.NonNull; import android.annotation.TestApi; +import android.app.ActivityThread; +import android.app.Instrumentation; import android.ravenwood.annotation.RavenwoodKeepWholeClass; import android.ravenwood.annotation.RavenwoodRedirect; import android.ravenwood.annotation.RavenwoodRedirectionClass; @@ -364,6 +367,28 @@ public final class MessageQueue { mPtr = nativeInit(); } + @android.ravenwood.annotation.RavenwoodReplace + private static void throwIfNotTest() { + final ActivityThread activityThread = ActivityThread.currentActivityThread(); + if (activityThread == null) { + // Only tests can reach here. + return; + } + final Instrumentation instrumentation = activityThread.getInstrumentation(); + if (instrumentation == null) { + // Only tests can reach here. + return; + } + if (instrumentation.isInstrumenting()) { + return; + } + throw new IllegalStateException("Test-only API called not from a test!"); + } + + private static void throwIfNotTest$ravenwood() { + return; + } + @Override protected void finalize() throws Throwable { try { @@ -384,8 +409,9 @@ public final class MessageQueue { private static final class MatchDeliverableMessages extends MessageCompare { @Override - public boolean compareMessage(Message m, Handler h, int what, Object object, Runnable r, - long when) { + public boolean compareMessage(MessageNode n, Handler h, int what, Object object, + Runnable r, long when) { + final Message m = n.mMessage; if (m.when <= when) { return true; } @@ -562,7 +588,7 @@ public final class MessageQueue { private static final AtomicLong mMessagesDelivered = new AtomicLong(); private boolean mMessageDirectlyQueued; - private Message nextMessage() { + private Message nextMessage(boolean peek) { int i = 0; while (true) { @@ -724,7 +750,7 @@ public final class MessageQueue { if (sState.compareAndSet(this, sStackStateActive, nextOp)) { mMessageCounts.clearCounts(); if (found != null) { - if (!removeFromPriorityQueue(found)) { + if (!peek && !removeFromPriorityQueue(found)) { /* * RemoveMessages() might be able to pull messages out from under us * However we can detect that here and just loop around if it happens. @@ -993,8 +1019,9 @@ public final class MessageQueue { } @Override - public boolean compareMessage(Message m, Handler h, int what, Object object, Runnable r, - long when) { + public boolean compareMessage(MessageNode n, Handler h, int what, Object object, + Runnable r, long when) { + final Message m = n.mMessage; if (m.target == null && m.arg1 == mBarrierToken) { return true; } @@ -1039,6 +1066,79 @@ public final class MessageQueue { } } + private static final class MatchEarliestMessage extends MessageCompare { + MessageNode mEarliest = null; + + @Override + public boolean compareMessage(MessageNode n, Handler h, int what, Object object, + Runnable r, long when) { + final Message m = n.mMessage; + if (mEarliest == null || mEarliest.mMessage.when > m.when) { + mEarliest = n; + } + + return false; + } + } + + /** + * Get the timestamp of the next executable message in our priority queue. + * Returns null if there are no messages ready for delivery. + * + * Caller must ensure that this doesn't race 'next' from the Looper thread. + */ + @SuppressLint("VisiblySynchronized") // Legacy MessageQueue synchronizes on this + Long peekWhenForTest() { + throwIfNotTest(); + Message ret = nextMessage(true); + return ret != null ? ret.when : null; + } + + /** + * Return the next executable message in our priority queue. + * Returns null if there are no messages ready for delivery + * + * Caller must ensure that this doesn't race 'next' from the Looper thread. + */ + @SuppressLint("VisiblySynchronized") // Legacy MessageQueue synchronizes on this + @Nullable + Message pollForTest() { + throwIfNotTest(); + return nextMessage(false); + } + + /** + * @return true if we are blocked on a sync barrier + */ + boolean isBlockedOnSyncBarrier() { + throwIfNotTest(); + Iterator queueIter = mPriorityQueue.iterator(); + MessageNode queueNode = iterateNext(queueIter); + + if (queueNode.isBarrier()) { + long now = SystemClock.uptimeMillis(); + + /* Look for a deliverable async node. If one exists we are not blocked. */ + Iterator asyncQueueIter = mAsyncPriorityQueue.iterator(); + MessageNode asyncNode = iterateNext(asyncQueueIter); + if (asyncNode != null && now >= asyncNode.getWhen()) { + return false; + } + /* + * Look for a deliverable sync node. In this case, if one exists we are blocked + * since the barrier prevents delivery of the Message. + */ + while (queueNode.isBarrier()) { + queueNode = iterateNext(queueIter); + } + if (queueNode != null && now >= queueNode.getWhen()) { + return true; + } + + return false; + } + } + private StateNode getStateNode(StackNode node) { if (node.isMessageNode()) { return ((MessageNode) node).mBottomOfStack; @@ -1058,7 +1158,7 @@ public final class MessageQueue { * This class is used to find matches for hasMessages() and removeMessages() */ private abstract static class MessageCompare { - public abstract boolean compareMessage(Message m, Handler h, int what, Object object, + public abstract boolean compareMessage(MessageNode n, Handler h, int what, Object object, Runnable r, long when); } @@ -1167,8 +1267,9 @@ public final class MessageQueue { private static final class MatchHandlerWhatAndObject extends MessageCompare { @Override - public boolean compareMessage(Message m, Handler h, int what, Object object, Runnable r, - long when) { + public boolean compareMessage(MessageNode n, Handler h, int what, Object object, + Runnable r, long when) { + final Message m = n.mMessage; if (m.target == h && m.what == what && (object == null || m.obj == object)) { return true; } @@ -1187,8 +1288,9 @@ public final class MessageQueue { private static final class MatchHandlerWhatAndObjectEquals extends MessageCompare { @Override - public boolean compareMessage(Message m, Handler h, int what, Object object, Runnable r, + public boolean compareMessage(MessageNode n, Handler h, int what, Object object, Runnable r, long when) { + final Message m = n.mMessage; if (m.target == h && m.what == what && (object == null || object.equals(m.obj))) { return true; } @@ -1208,8 +1310,9 @@ public final class MessageQueue { private static final class MatchHandlerRunnableAndObject extends MessageCompare { @Override - public boolean compareMessage(Message m, Handler h, int what, Object object, Runnable r, - long when) { + public boolean compareMessage(MessageNode n, Handler h, int what, Object object, + Runnable r, long when) { + final Message m = n.mMessage; if (m.target == h && m.callback == r && (object == null || m.obj == object)) { return true; } @@ -1229,8 +1332,9 @@ public final class MessageQueue { private static final class MatchHandler extends MessageCompare { @Override - public boolean compareMessage(Message m, Handler h, int what, Object object, Runnable r, - long when) { + public boolean compareMessage(MessageNode n, Handler h, int what, Object object, + Runnable r, long when) { + final Message m = n.mMessage; if (m.target == h) { return true; } @@ -1268,8 +1372,9 @@ public final class MessageQueue { private static final class MatchHandlerRunnableAndObjectEquals extends MessageCompare { @Override - public boolean compareMessage(Message m, Handler h, int what, Object object, Runnable r, - long when) { + public boolean compareMessage(MessageNode n, Handler h, int what, Object object, + Runnable r, long when) { + final Message m = n.mMessage; if (m.target == h && m.callback == r && (object == null || object.equals(m.obj))) { return true; } @@ -1287,8 +1392,9 @@ public final class MessageQueue { private static final class MatchHandlerAndObject extends MessageCompare { @Override - public boolean compareMessage(Message m, Handler h, int what, Object object, Runnable r, - long when) { + public boolean compareMessage(MessageNode n, Handler h, int what, Object object, + Runnable r, long when) { + final Message m = n.mMessage; if (m.target == h && (object == null || m.obj == object)) { return true; } @@ -1305,8 +1411,9 @@ public final class MessageQueue { private static final class MatchHandlerAndObjectEquals extends MessageCompare { @Override - public boolean compareMessage(Message m, Handler h, int what, Object object, Runnable r, - long when) { + public boolean compareMessage(MessageNode n, Handler h, int what, Object object, + Runnable r, long when) { + final Message m = n.mMessage; if (m.target == h && (object == null || object.equals(m.obj))) { return true; } @@ -1324,8 +1431,8 @@ public final class MessageQueue { private static final class MatchAllMessages extends MessageCompare { @Override - public boolean compareMessage(Message m, Handler h, int what, Object object, Runnable r, - long when) { + public boolean compareMessage(MessageNode n, Handler h, int what, Object object, + Runnable r, long when) { return true; } } @@ -1336,8 +1443,9 @@ public final class MessageQueue { private static final class MatchAllFutureMessages extends MessageCompare { @Override - public boolean compareMessage(Message m, Handler h, int what, Object object, Runnable r, - long when) { + public boolean compareMessage(MessageNode n, Handler h, int what, Object object, + Runnable r, long when) { + final Message m = n.mMessage; if (m.when > when) { return true; } diff --git a/core/java/android/os/CpuHeadroomParamsInternal.aidl b/core/java/android/os/CpuHeadroomParamsInternal.aidl index d572f965579b71dcff174a645b48b0797b42623c..12b209357d9cc33666c15cda535062c09349a930 100644 --- a/core/java/android/os/CpuHeadroomParamsInternal.aidl +++ b/core/java/android/os/CpuHeadroomParamsInternal.aidl @@ -28,6 +28,5 @@ parcelable CpuHeadroomParamsInternal { int[] tids; int calculationWindowMillis = 1000; CpuHeadroomParams.CalculationType calculationType = CpuHeadroomParams.CalculationType.MIN; - CpuHeadroomParams.SelectionType selectionType = CpuHeadroomParams.SelectionType.ALL; } diff --git a/core/java/android/os/IHintManager.aidl b/core/java/android/os/IHintManager.aidl index 4a14a8d0faf8b3bb84ca649b2eb47555cfeb924e..56a089aff78a47fb1d2959f4dde296eedb78db5f 100644 --- a/core/java/android/os/IHintManager.aidl +++ b/core/java/android/os/IHintManager.aidl @@ -21,11 +21,13 @@ import android.os.CpuHeadroomParamsInternal; import android.os.GpuHeadroomParamsInternal; import android.os.IHintSession; import android.os.SessionCreationConfig; -import android.hardware.power.CpuHeadroomResult; + import android.hardware.power.ChannelConfig; +import android.hardware.power.CpuHeadroomResult; import android.hardware.power.GpuHeadroomResult; import android.hardware.power.SessionConfig; import android.hardware.power.SessionTag; +import android.hardware.power.SupportInfo; /** {@hide} */ interface IHintManager { @@ -40,11 +42,6 @@ interface IHintManager { IHintSession createHintSessionWithConfig(in IBinder token, in SessionTag tag, in SessionCreationConfig creationConfig, out SessionConfig config); - /** - * Get preferred rate limit in nanoseconds. - */ - long getHintSessionPreferredRate(); - void setHintSessionThreads(in IHintSession hintSession, in int[] tids); int[] getHintSessionThreadIds(in IHintSession hintSession); @@ -60,14 +57,29 @@ interface IHintManager { @nullable GpuHeadroomResult getGpuHeadroom(in GpuHeadroomParamsInternal params); long getGpuHeadroomMinIntervalMillis(); - /** - * Get Maximum number of graphics pipeline threads allowed per-app. - */ - int getMaxGraphicsPipelineThreadsCount(); - /** * Used by the JNI to pass an interface to the SessionManager; * for internal use only. */ oneway void passSessionManagerBinder(in IBinder sessionManager); + + parcelable HintManagerClientData { + int powerHalVersion; + int maxGraphicsPipelineThreads; + long preferredRateNanos; + SupportInfo supportInfo; + } + + interface IHintManagerClient { + /** + * Returns FMQ channel information for the caller, which it associates to the callback binder lifespan. + */ + oneway void receiveChannelConfig(in ChannelConfig config); + } + + /** + * Set up an ADPF client, receiving a remote client binder interface and + * passing back a bundle of support and configuration information. + */ + HintManagerClientData registerClient(in IHintManagerClient client); } diff --git a/core/java/android/os/IPowerManager.aidl b/core/java/android/os/IPowerManager.aidl index e85e58039828fd2d10d8fc15ca9392680c492a22..4cac4dee0bea8745a8efff62e7592695ff2ef3d8 100644 --- a/core/java/android/os/IPowerManager.aidl +++ b/core/java/android/os/IPowerManager.aidl @@ -55,7 +55,7 @@ interface IPowerManager void goToSleepWithDisplayId(int displayId, long time, int reason, int flags); @UnsupportedAppUsage(maxTargetSdk = 28) void nap(long time); - float getBrightnessConstraint(int constraint); + float getBrightnessConstraint(int displayId, int constraint); @UnsupportedAppUsage boolean isInteractive(); boolean isDisplayInteractive(int displayId); diff --git a/core/java/android/os/IpcDataCache.java b/core/java/android/os/IpcDataCache.java index 8db1567336d3ddb9f4154a92b0499fb16cb5b384..a2e9314f6436f9c39ef94d831688f53681297b60 100644 --- a/core/java/android/os/IpcDataCache.java +++ b/core/java/android/os/IpcDataCache.java @@ -400,10 +400,11 @@ public class IpcDataCache extends PropertyInvalidatedCache extends PropertyInvalidatedCache extends PropertyInvalidatedCache extends PropertyInvalidatedCache extends PropertyInvalidatedCache extends PropertyInvalidatedCache extends PropertyInvalidatedCache extends PropertyInvalidatedCache computer) { - super(new Args(config.module()).maxEntries(config.maxEntries()).api(config.api()), - config.name(), computer); + super(config.mArgs, config.mName, computer); } /** diff --git a/core/java/android/os/LegacyMessageQueue/MessageQueue.java b/core/java/android/os/LegacyMessageQueue/MessageQueue.java index cae82d010132f646e999256edc5c28ecb39fbddb..5e1e1fdca5c86b21cf99844ed399c46c2b190f84 100644 --- a/core/java/android/os/LegacyMessageQueue/MessageQueue.java +++ b/core/java/android/os/LegacyMessageQueue/MessageQueue.java @@ -16,9 +16,14 @@ package android.os; +import android.annotation.FlaggedApi; import android.annotation.IntDef; import android.annotation.NonNull; +import android.annotation.Nullable; +import android.annotation.SuppressLint; import android.annotation.TestApi; +import android.app.ActivityThread; +import android.app.Instrumentation; import android.compat.annotation.UnsupportedAppUsage; import android.ravenwood.annotation.RavenwoodKeepWholeClass; import android.ravenwood.annotation.RavenwoodRedirect; @@ -99,6 +104,28 @@ public final class MessageQueue { mPtr = nativeInit(); } + @android.ravenwood.annotation.RavenwoodReplace + private static void throwIfNotTest() { + final ActivityThread activityThread = ActivityThread.currentActivityThread(); + if (activityThread == null) { + // Only tests can reach here. + return; + } + final Instrumentation instrumentation = activityThread.getInstrumentation(); + if (instrumentation == null) { + // Only tests can reach here. + return; + } + if (instrumentation.isInstrumenting()) { + return; + } + throw new IllegalStateException("Test-only API called not from a test!"); + } + + private static void throwIfNotTest$ravenwood() { + return; + } + @Override protected void finalize() throws Throwable { try { @@ -713,6 +740,112 @@ public final class MessageQueue { return true; } + private Message legacyPeekOrPoll(boolean peek) { + synchronized (this) { + // Try to retrieve the next message. Return if found. + final long now = SystemClock.uptimeMillis(); + Message prevMsg = null; + Message msg = mMessages; + if (msg != null && msg.target == null) { + // Stalled by a barrier. Find the next asynchronous message in the queue. + do { + prevMsg = msg; + msg = msg.next; + } while (msg != null && !msg.isAsynchronous()); + } + if (msg != null) { + if (now >= msg.when) { + // Got a message. + mBlocked = false; + if (peek) { + return msg; + } + if (prevMsg != null) { + prevMsg.next = msg.next; + if (prevMsg.next == null) { + mLast = prevMsg; + } + } else { + mMessages = msg.next; + if (msg.next == null) { + mLast = null; + } + } + msg.next = null; + msg.markInUse(); + if (msg.isAsynchronous()) { + mAsyncMessageCount--; + } + if (TRACE) { + Trace.setCounter("MQ.Delivered", mMessagesDelivered.incrementAndGet()); + } + return msg; + } + } + } + return null; + } + + /** + * Get the timestamp of the next executable message in our priority queue. + * Returns null if there are no messages ready for delivery. + * + * Caller must ensure that this doesn't race 'next' from the Looper thread. + */ + @SuppressLint("VisiblySynchronized") // Legacy MessageQueue synchronizes on this + Long peekWhenForTest() { + throwIfNotTest(); + Message ret = legacyPeekOrPoll(true); + return ret != null ? ret.when : null; + } + + /** + * Return the next executable message in our priority queue. + * Returns null if there are no messages ready for delivery + * + * Caller must ensure that this doesn't race 'next' from the Looper thread. + */ + @SuppressLint("VisiblySynchronized") // Legacy MessageQueue synchronizes on this + @Nullable + Message pollForTest() { + throwIfNotTest(); + return legacyPeekOrPoll(false); + } + + /** + * @return true if we are blocked on a sync barrier + */ + boolean isBlockedOnSyncBarrier() { + throwIfNotTest(); + Message msg = mMessages; + if (msg != null && msg.target == null) { + Message iter = msg; + /* Look for a deliverable async node */ + do { + iter = iter.next; + } while (iter != null && !iter.isAsynchronous()); + + long now = SystemClock.uptimeMillis(); + if (iter != null && now >= iter.when) { + return false; + } + /* + * Look for a deliverable sync node. In this case, if one exists we are blocked + * since the barrier prevents delivery of the Message. + */ + iter = msg; + do { + iter = iter.next; + } while (iter != null && (iter.target == null || iter.isAsynchronous())); + + if (iter != null && now >= iter.when) { + return true; + } + return false; + } + return false; + } + boolean hasMessages(Handler h, int what, Object object) { if (h == null) { return false; diff --git a/core/java/android/os/OWNERS b/core/java/android/os/OWNERS index bfcc5cc6f18eae3b1839f7be5d591141b50875fa..8d353384f1e2f0ae04c575f1c37d8ec7b990e9da 100644 --- a/core/java/android/os/OWNERS +++ b/core/java/android/os/OWNERS @@ -118,9 +118,10 @@ per-file IpcDataCache.java = file:/PERFORMANCE_OWNERS # Memory per-file OomKillRecord.java = file:/MEMORY_OWNERS -# MessageQueue +# MessageQueue and related classes per-file MessageQueue.java = mfasheh@google.com, shayba@google.com per-file Message.java = mfasheh@google.com, shayba@google.com +per-file TestLooperManager.java = mfasheh@google.com, shayba@google.com # Stats per-file IStatsBootstrapAtomService.aidl = file:/services/core/java/com/android/server/stats/OWNERS diff --git a/core/java/android/os/Parcel.java b/core/java/android/os/Parcel.java index bf7116d6a05bc8564e7c15238e169f8599059545..cf473ec9c3eac392ab9f11741d154651cd9be3c1 100644 --- a/core/java/android/os/Parcel.java +++ b/core/java/android/os/Parcel.java @@ -892,6 +892,12 @@ public final class Parcel { /** * Report whether the parcel contains any marshalled file descriptors. + * + * WARNING: Parcelable definitions change over time. Unless you define + * a Parcelable yourself OR the Parcelable explicitly guarantees that + * it would never include such objects, you should not expect the return + * value to stay the same, and your code should continue to work even + * if the return value changes. */ public boolean hasFileDescriptors() { return nativeHasFileDescriptors(mNativePtr); @@ -901,6 +907,12 @@ public final class Parcel { * Report whether the parcel contains any marshalled file descriptors in the range defined by * {@code offset} and {@code length}. * + * WARNING: Parcelable definitions change over time. Unless you define + * a Parcelable yourself OR the Parcelable explicitly guarantees that + * it would never include such objects, you should not expect the return + * value to stay the same, and your code should continue to work even + * if the return value changes. + * * @param offset The offset from which the range starts. Should be between 0 and * {@link #dataSize()}. * @param length The length of the range. Should be between 0 and {@link #dataSize()} - {@code @@ -921,6 +933,12 @@ public final class Parcel { *

    For most cases, it will use the self-reported {@link Parcelable#describeContents()} method * for that. * + * WARNING: Parcelable definitions change over time. Unless you define + * a Parcelable yourself OR the Parcelable explicitly guarantees that + * it would never include such objects, you should not expect the return + * value to stay the same, and your code should continue to work even + * if the return value changes. + * * @throws IllegalArgumentException if you provide any object not supported by above methods * (including if the unsupported object is inside a nested container). * @@ -990,6 +1008,13 @@ public final class Parcel { * * @throws UnsupportedOperationException if binder kernel driver was disabled or if method was * invoked in case of Binder RPC protocol. + * + * WARNING: Parcelable definitions change over time. Unless you define + * a Parcelable yourself OR the Parcelable explicitly guarantees that + * it would never include such objects, you should not expect the return + * value to stay the same, and your code should continue to work even + * if the return value changes. + * * @hide */ public boolean hasBinders() { @@ -1000,6 +1025,12 @@ public final class Parcel { * Report whether the parcel contains any marshalled {@link IBinder} objects in the range * defined by {@code offset} and {@code length}. * + * WARNING: Parcelable definitions change over time. Unless you define + * a Parcelable yourself OR the Parcelable explicitly guarantees that + * it would never include such objects, you should not expect the return + * value to stay the same, and your code should continue to work even + * if the return value changes. + * * @param offset The offset from which the range starts. Should be between 0 and * {@link #dataSize()}. * @param length The length of the range. Should be between 0 and {@link #dataSize()} - {@code diff --git a/core/java/android/os/PowerManager.java b/core/java/android/os/PowerManager.java index 9e7bf47ae83f1ab307a03568cfe0d031541a2b7b..cd48f0847f8d81099b3037e6b7d116b07db3aefb 100644 --- a/core/java/android/os/PowerManager.java +++ b/core/java/android/os/PowerManager.java @@ -1266,9 +1266,17 @@ public final class PowerManager { * @hide */ @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) - public float getBrightnessConstraint(int constraint) { + public float getBrightnessConstraint(@BrightnessConstraint int constraint) { + return getBrightnessConstraint(Display.DEFAULT_DISPLAY, constraint); + } + + /** + * Gets a float screen brightness setting for a specific display. + * @hide + */ + public float getBrightnessConstraint(int displayId, @BrightnessConstraint int constraint) { try { - return mService.getBrightnessConstraint(constraint); + return mService.getBrightnessConstraint(displayId, constraint); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } diff --git a/core/java/android/os/SELinux.java b/core/java/android/os/SELinux.java index f64a81177ce2b44b9a0ba24fbb7c58b05c197344..11c54ef802fec4595fd449e401b1fe4b4c19dac6 100644 --- a/core/java/android/os/SELinux.java +++ b/core/java/android/os/SELinux.java @@ -193,4 +193,31 @@ public class SELinux { return false; } } + + /** + * Gets the genfs labels version of the vendor. The genfs labels version is + * specified in {@code /vendor/etc/selinux/genfs_labels_version.txt}. The + * version follows the VINTF version format "YYYYMM" and affects how {@code + * genfs_contexts} entries are applied. + * + *

    The genfs labels version indicates changes in the SELinux labeling + * scheme over time. For example: + *

      + *
    • For version 202504 and later, {@code /sys/class/udc} is labeled as + * {@code sysfs_udc}. + *
    • For version 202404 and earlier, {@code /sys/class/udc} is labeled + * as {@code sysfs}. + *
    + * Check {@code /system/etc/selinux/plat_sepolicy_genfs_{version}.cil} to + * see which labels are new in {version}. + * + *

    Older vendors may override {@code genfs_contexts} with vendor-specific + * extensions. The framework must not break such labellings to maintain + * compatibility with such vendors, by checking the genfs labels version and + * implementing a fallback mechanism. + * + * @return an integer representing the genfs labels version of /vendor, in + * the format YYYYMM. + */ + public static final native int getGenfsLabelsVersion(); } diff --git a/core/java/android/os/ServiceManager.java b/core/java/android/os/ServiceManager.java index 8aec7eb59e9151c0ae42b20b034c9a58012661e8..9085fe09bdaa5c1a29c81f7482a70a3a633922a5 100644 --- a/core/java/android/os/ServiceManager.java +++ b/core/java/android/os/ServiceManager.java @@ -277,7 +277,8 @@ public final class ServiceManager { if (service != null) { return service; } else { - return Binder.allowBlocking(getIServiceManager().checkService(name).getBinder()); + return Binder.allowBlocking( + getIServiceManager().checkService(name).getServiceWithMetadata().service); } } catch (RemoteException e) { Log.e(TAG, "error in checkService", e); @@ -425,7 +426,8 @@ public final class ServiceManager { private static IBinder rawGetService(String name) throws RemoteException { final long start = sStatLogger.getTime(); - final IBinder binder = getIServiceManager().getService2(name).getBinder(); + final IBinder binder = + getIServiceManager().getService2(name).getServiceWithMetadata().service; final int time = (int) sStatLogger.logDurationStat(Stats.GET_SERVICE, start); diff --git a/core/java/android/os/ServiceManagerNative.java b/core/java/android/os/ServiceManagerNative.java index 5a9c8787ee3be30632c53e0b862e31aa0c89c5a8..49b696d95723f3decabc7cd833d3a08c51afaa66 100644 --- a/core/java/android/os/ServiceManagerNative.java +++ b/core/java/android/os/ServiceManagerNative.java @@ -61,7 +61,7 @@ class ServiceManagerProxy implements IServiceManager { @UnsupportedAppUsage public IBinder getService(String name) throws RemoteException { // Same as checkService (old versions of servicemanager had both methods). - return checkService(name).getBinder(); + return checkService(name).getServiceWithMetadata().service; } public Service getService2(String name) throws RemoteException { diff --git a/core/java/android/os/TestLooperManager.java b/core/java/android/os/TestLooperManager.java index 4b16c1dce463bce369790783063548e6093e4864..e2169925fdd35ce3042b6856f9f0838378b8b649 100644 --- a/core/java/android/os/TestLooperManager.java +++ b/core/java/android/os/TestLooperManager.java @@ -14,6 +14,8 @@ package android.os; +import android.annotation.FlaggedApi; +import android.annotation.Nullable; import android.util.ArraySet; import java.util.concurrent.LinkedBlockingQueue; @@ -93,9 +95,52 @@ public class TestLooperManager { } /** - * Releases the looper to continue standard looping and processing of messages, - * no further interactions with TestLooperManager will be allowed after - * release() has been called. + * Retrieves and removes the next message that should be executed by this queue. + * If the queue is empty or no messages are deliverable, returns null. + * This method never blocks. + * + *

    Callers should always call {@link #recycle(Message)} on the message when all interactions + * with it have completed. + */ + @FlaggedApi(Flags.FLAG_MESSAGE_QUEUE_TESTABILITY) + @Nullable + public Message poll() { + checkReleased(); + return mQueue.pollForTest(); + } + + /** + * Retrieves, but does not remove, the values of {@link Message#when} of next message that + * should be executed by this queue. + * If the queue is empty or no messages are deliverable, returns null. + * This method never blocks. + * + *

    Callers should always call {@link #recycle(Message)} on the message when all interactions + * with it have completed. + */ + @FlaggedApi(Flags.FLAG_MESSAGE_QUEUE_TESTABILITY) + @SuppressWarnings("AutoBoxing") // box the primitive long, or return null to indicate no value + @Nullable + public Long peekWhen() { + checkReleased(); + return mQueue.peekWhenForTest(); + } + + /** + * Checks whether the Looper is currently blocked on a sync barrier. + * + * A Looper is blocked on a sync barrier if there is a Message in the Looper's + * queue that is ready for execution but is behind a sync barrier + */ + @FlaggedApi(Flags.FLAG_MESSAGE_QUEUE_TESTABILITY) + public boolean isBlockedOnSyncBarrier() { + checkReleased(); + return mQueue.isBlockedOnSyncBarrier(); + } + + /** + * Releases the looper to continue standard looping and processing of messages, no further + * interactions with TestLooperManager will be allowed after release() has been called. */ public void release() { synchronized (sHeldLoopers) { diff --git a/core/java/android/os/UpdateEngine.java b/core/java/android/os/UpdateEngine.java index 0a8f62fd56d849a47982ad4051d59287f2a1f6dd..81e4549c78d1eca57061cb503bd530e72c7c64f1 100644 --- a/core/java/android/os/UpdateEngine.java +++ b/core/java/android/os/UpdateEngine.java @@ -16,6 +16,7 @@ package android.os; +import android.annotation.FlaggedApi; import android.annotation.IntDef; import android.annotation.NonNull; import android.annotation.SystemApi; @@ -667,4 +668,23 @@ public class UpdateEngine { throw e.rethrowFromSystemServer(); } } + + /** + * Run postinstall script for specified partition |partition| + * + * @param partition The partition to trigger postinstall runs + * + * @throws ServiceSpecificException error code of this exception would be one of + * https://cs.android.com/android/platform/superproject/main/+/main:system/update_engine/common/error_code.h + * @hide + */ + @FlaggedApi(Flags.FLAG_UPDATE_ENGINE_API) + @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES) + public void triggerPostinstall(@NonNull String partition) { + try { + mUpdateEngine.triggerPostinstall(partition); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + } } diff --git a/core/java/android/os/flags.aconfig b/core/java/android/os/flags.aconfig index 6357baa1922699c0f6ac06726d7020fc09b10a78..2a467386569df51d8998980702a10bdc285f63fe 100644 --- a/core/java/android/os/flags.aconfig +++ b/core/java/android/os/flags.aconfig @@ -232,6 +232,14 @@ flag { is_exported: true } +flag { + name: "material_shape_tokens" + namespace: "systemui" + description: "Adding new Material Tokens for M3 Shape (corner radius) Spec" + bug: "324928718" + is_exported: true +} + flag { name: "message_queue_tail_tracking" namespace: "system_performance" diff --git a/core/java/android/os/instrumentation/IDynamicInstrumentationManager.aidl b/core/java/android/os/instrumentation/IDynamicInstrumentationManager.aidl index c45c51d15cc96a61483c5e68ebbc73d12a166809..af56bfe5038197ce95a81e6a842c109bb823f1f4 100644 --- a/core/java/android/os/instrumentation/IDynamicInstrumentationManager.aidl +++ b/core/java/android/os/instrumentation/IDynamicInstrumentationManager.aidl @@ -16,7 +16,7 @@ package android.os.instrumentation; -import android.os.instrumentation.ExecutableMethodFileOffsets; +import android.os.instrumentation.IOffsetCallback; import android.os.instrumentation.MethodDescriptor; import android.os.instrumentation.TargetProcess; @@ -28,6 +28,7 @@ import android.os.instrumentation.TargetProcess; interface IDynamicInstrumentationManager { /** Provides ART metadata about the described compiled method within the target process */ @PermissionManuallyEnforced - @nullable ExecutableMethodFileOffsets getExecutableMethodFileOffsets( - in TargetProcess targetProcess, in MethodDescriptor methodDescriptor); + void getExecutableMethodFileOffsets( + in TargetProcess targetProcess, in MethodDescriptor methodDescriptor, + in IOffsetCallback callback); } diff --git a/core/java/android/os/instrumentation/IOffsetCallback.aidl b/core/java/android/os/instrumentation/IOffsetCallback.aidl new file mode 100644 index 0000000000000000000000000000000000000000..a28c93f5353a905667324ddfadb694bf47ca6dab --- /dev/null +++ b/core/java/android/os/instrumentation/IOffsetCallback.aidl @@ -0,0 +1,28 @@ +/* + * Copyright (C) 2024 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES 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.os.instrumentation; + +import android.os.instrumentation.ExecutableMethodFileOffsets; + +/** + * System private API for providing dynamic instrumentation offset results. + * + * {@hide} + */ +oneway interface IOffsetCallback { + void onResult(in @nullable ExecutableMethodFileOffsets offsets); +} diff --git a/core/java/android/os/instrumentation/MethodDescriptorParser.java b/core/java/android/os/instrumentation/MethodDescriptorParser.java new file mode 100644 index 0000000000000000000000000000000000000000..57fc44ff623ecdd6c8570fe0a6fa0a18001fd420 --- /dev/null +++ b/core/java/android/os/instrumentation/MethodDescriptorParser.java @@ -0,0 +1,82 @@ +/* + * Copyright (C) 2024 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES 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.os.instrumentation; + +import android.annotation.NonNull; + +import java.lang.reflect.Method; + +/** + * A utility class for dynamic instrumentation / uprobestats. + * + * @hide + */ +public final class MethodDescriptorParser { + + /** + * Parses a {@link MethodDescriptor} (in string representation) into a {@link Method}. + */ + public static Method parseMethodDescriptor(ClassLoader classLoader, + @NonNull MethodDescriptor descriptor) { + try { + Class javaClass = classLoader.loadClass(descriptor.fullyQualifiedClassName); + Class[] parameters = new Class[descriptor.fullyQualifiedParameters.length]; + for (int i = 0; i < descriptor.fullyQualifiedParameters.length; i++) { + String typeName = descriptor.fullyQualifiedParameters[i]; + boolean isArrayType = typeName.endsWith("[]"); + if (isArrayType) { + typeName = typeName.substring(0, typeName.length() - 2); + } + switch (typeName) { + case "boolean": + parameters[i] = isArrayType ? boolean.class.arrayType() : boolean.class; + break; + case "byte": + parameters[i] = isArrayType ? byte.class.arrayType() : byte.class; + break; + case "char": + parameters[i] = isArrayType ? char.class.arrayType() : char.class; + break; + case "short": + parameters[i] = isArrayType ? short.class.arrayType() : short.class; + break; + case "int": + parameters[i] = isArrayType ? int.class.arrayType() : int.class; + break; + case "long": + parameters[i] = isArrayType ? long.class.arrayType() : long.class; + break; + case "float": + parameters[i] = isArrayType ? float.class.arrayType() : float.class; + break; + case "double": + parameters[i] = isArrayType ? double.class.arrayType() : double.class; + break; + default: + parameters[i] = isArrayType ? classLoader.loadClass(typeName).arrayType() + : classLoader.loadClass(typeName); + } + } + + return javaClass.getDeclaredMethod(descriptor.methodName, parameters); + } catch (ClassNotFoundException | NoSuchMethodException e) { + throw new IllegalArgumentException( + "The specified method cannot be found. Is this descriptor valid? " + + descriptor, e); + } + } +} diff --git a/core/java/android/permission/PermissionManager.java b/core/java/android/permission/PermissionManager.java index e98397d104d6ac816e1699cc5869c6635bcddbab..2473de4ff6d710e7f1bf9a8f6d863317fb3f5983 100644 --- a/core/java/android/permission/PermissionManager.java +++ b/core/java/android/permission/PermissionManager.java @@ -1795,14 +1795,45 @@ public final class PermissionManager { } } - /** @hide */ - public static final String CACHE_KEY_PACKAGE_INFO = + // The legacy system property "package_info" had two purposes: to invalidate PIC caches and to + // signal that package information, and therefore permissions, might have changed. + // AudioSystem is the only client of the signaling behavior. The "separate permissions + // notification" feature splits the two behaviors into two system property names. + // + // If the feature is disabled (legacy behavior) then the two system property names have the + // same value. This means there is only one system property in use. + // + // If the feature is enabled, then the two system property names have different values, which + // means there is a system property used by PIC and a system property used for signaling. The + // legacy value is hard-coded in native code that relies on the signaling behavior, so the + // system property name for signaling is the legacy property name, and the system property + // name for PIC is new. + private static String getPackageInfoCacheKey() { + if (PropertyInvalidatedCache.separatePermissionNotificationsEnabled()) { + return PropertyInvalidatedCache.createSystemCacheKey("package_info_cache"); + } else { + return CACHE_KEY_PACKAGE_INFO_NOTIFY; + } + } + + /** + * The system property that is used to notify clients that package information, and therefore + * permissions, may have changed. + * @hide + */ + public static final String CACHE_KEY_PACKAGE_INFO_NOTIFY = PropertyInvalidatedCache.createSystemCacheKey("package_info"); + /** + * The system property that is used to invalidate PIC caches. + * @hide + */ + public static final String CACHE_KEY_PACKAGE_INFO_CACHE = getPackageInfoCacheKey(); + /** @hide */ private static final PropertyInvalidatedCache sPermissionCache = new PropertyInvalidatedCache( - 2048, CACHE_KEY_PACKAGE_INFO, "checkPermission") { + 2048, CACHE_KEY_PACKAGE_INFO_CACHE, "checkPermission") { @Override public Integer recompute(PermissionQuery query) { return checkPermissionUncached(query.permission, query.pid, query.uid, @@ -1920,7 +1951,7 @@ public final class PermissionManager { private static PropertyInvalidatedCache sPackageNamePermissionCache = new PropertyInvalidatedCache( - 16, CACHE_KEY_PACKAGE_INFO, "checkPackageNamePermission") { + 16, CACHE_KEY_PACKAGE_INFO_CACHE, "checkPackageNamePermission") { @Override public Integer recompute(PackageNamePermissionQuery query) { return checkPackageNamePermissionUncached( diff --git a/core/java/android/permission/flags.aconfig b/core/java/android/permission/flags.aconfig index c2b8157de416f6013ce3134b9ef0e2d859589645..aacc6e2a31562f84c56411099bfdf04ac4265c65 100644 --- a/core/java/android/permission/flags.aconfig +++ b/core/java/android/permission/flags.aconfig @@ -474,3 +474,31 @@ flag { description: "Enable cross-user roles platform API" bug: "367732307" } + +flag { + name: "rate_limit_batched_note_op_async_callbacks_enabled" + is_fixed_read_only: true + is_exported: true + namespace: "permissions" + description: "Rate limit async noteOp callbacks for batched noteOperation binder call" + bug: "366013082" +} + +flag { + name: "system_vendor_intelligence_role_enabled" + is_exported: true + is_fixed_read_only: true + namespace: "permissions" + description: "This flag is used to enable the role system_vendor_intelligence" + bug: "377553620" +} + +flag { + name: "fine_power_monitor_permission" + is_fixed_read_only: true + is_exported: true + namespace: "permissions" + description: "Add support for fine-grained PowerMonitor readings" + bug: "341941666" +} + diff --git a/core/java/android/preference/PreferenceActivity.java b/core/java/android/preference/PreferenceActivity.java index e4a3c9fa7741627bc3f0ca42e0d8f1bb94619308..25e8a4ddffcd5842eb7be29a96de7c63e585ed40 100644 --- a/core/java/android/preference/PreferenceActivity.java +++ b/core/java/android/preference/PreferenceActivity.java @@ -213,7 +213,10 @@ public abstract class PreferenceActivity extends ListActivity implements private int mPreferenceHeaderItemResId = 0; private boolean mPreferenceHeaderRemoveEmptyIcon = false; + private boolean mIsBackCallbackRegistered = false; private final OnBackInvokedCallback mOnBackInvokedCallback = this::onBackInvoked; + private final FragmentManager.OnBackStackChangedListener mOnBackStackChangedListener = + this::updateBackCallbackRegistrationState; /** * The starting request code given out to preference framework. @@ -706,6 +709,7 @@ public abstract class PreferenceActivity extends ListActivity implements } } updateBackCallbackRegistrationState(); + getFragmentManager().addOnBackStackChangedListener(mOnBackStackChangedListener); } @Override @@ -715,17 +719,25 @@ public abstract class PreferenceActivity extends ListActivity implements private void updateBackCallbackRegistrationState() { if (!WindowOnBackInvokedDispatcher.isOnBackInvokedCallbackEnabled(this)) return; - if (mCurHeader != null && mSinglePane && getFragmentManager().getBackStackEntryCount() == 0 - && getIntent().getStringExtra(EXTRA_SHOW_FRAGMENT) == null) { - getOnBackInvokedDispatcher() - .registerOnBackInvokedCallback(PRIORITY_DEFAULT, mOnBackInvokedCallback); - } else { + if ((mCurHeader != null && getIntent().getStringExtra(EXTRA_SHOW_FRAGMENT) == null + && mSinglePane) || getFragmentManager().getBackStackEntryCount() != 0) { + if (!mIsBackCallbackRegistered) { + getOnBackInvokedDispatcher() + .registerOnBackInvokedCallback(PRIORITY_DEFAULT, mOnBackInvokedCallback); + mIsBackCallbackRegistered = true; + } + } else if (mIsBackCallbackRegistered) { getOnBackInvokedDispatcher().unregisterOnBackInvokedCallback(mOnBackInvokedCallback); + mIsBackCallbackRegistered = false; } } private void onBackInvoked() { - if (mCurHeader != null && mSinglePane && getFragmentManager().getBackStackEntryCount() == 0 + if (WindowOnBackInvokedDispatcher.isOnBackInvokedCallbackEnabled(this) + && getFragmentManager().getBackStackEntryCount() != 0) { + getFragmentManager().popBackStackImmediate(); + } else if (mCurHeader != null && mSinglePane + && getFragmentManager().getBackStackEntryCount() == 0 && getIntent().getStringExtra(EXTRA_SHOW_FRAGMENT) == null) { mCurHeader = null; @@ -1012,6 +1024,7 @@ public abstract class PreferenceActivity extends ListActivity implements @Override protected void onDestroy() { + getFragmentManager().removeOnBackStackChangedListener(mOnBackStackChangedListener); mHandler.removeMessages(MSG_BIND_PREFERENCES); mHandler.removeMessages(MSG_BUILD_HEADERS); super.onDestroy(); diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java index 0ae9ffa655cd6b00988207eb596bcaae4ac45e57..4acb6312f90dc29cabe7941c543af0267467fa64 100644 --- a/core/java/android/provider/Settings.java +++ b/core/java/android/provider/Settings.java @@ -2468,6 +2468,25 @@ public final class Settings { public static final String ACTION_APP_NOTIFICATION_BUBBLE_SETTINGS = "android.settings.APP_NOTIFICATION_BUBBLE_SETTINGS"; + /** + * Activity Action: Show the settings for users to select their preferred SIM subscription + * when a new SIM subscription has become available. + *

    + * This Activity will only launch successfully if the newly active subscription ID is set as the + * value of {@link EXTRA_SUB_ID} and the value corresponds with an active SIM subscription. + *

    + * Input: {@link #EXTRA_SUB_ID}: the subscription ID of the newly active SIM subscription. + *

    + * Output: Nothing. + * + * @hide + */ + @FlaggedApi(com.android.internal.telephony.flags.Flags.FLAG_ACTION_SIM_PREFERENCE_SETTINGS) + @SystemApi + @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION) + public static final String ACTION_SIM_PREFERENCE_SETTINGS = + "android.settings.SIM_PREFERENCE_SETTINGS"; + /** * Intent Extra: The value of {@link android.app.settings.SettingsEnums#EntryPointType} for * settings metrics that logs the entry point about physical keyboard settings. @@ -10022,6 +10041,12 @@ public final class Settings { public static final String MINIMAL_POST_PROCESSING_ALLOWED = "minimal_post_processing_allowed"; + /** + * Whether to mirror the built-in display on all connected displays. + * @hide + */ + public static final String MIRROR_BUILT_IN_DISPLAY = "mirror_built_in_display"; + /** * No mode switching will happen. * diff --git a/core/java/android/security/authenticationpolicy/DisableSecureLockDeviceParams.java b/core/java/android/security/authenticationpolicy/DisableSecureLockDeviceParams.java index 64a3f0f60f961c0e732b4907608c75232854c7ee..568a6d7cb923203d8cfbe21c5d8b4b7a89f6e714 100644 --- a/core/java/android/security/authenticationpolicy/DisableSecureLockDeviceParams.java +++ b/core/java/android/security/authenticationpolicy/DisableSecureLockDeviceParams.java @@ -38,23 +38,30 @@ public final class DisableSecureLockDeviceParams implements Parcelable { /** * Client message associated with the request to disable secure lock on the device. This message * will be shown on the device when secure lock mode is disabled. + * + * Since this text is shown in a restricted lockscreen state, typeface properties such as color, + * font weight, or other formatting may not be honored. */ - private final @NonNull String mMessage; + private final @NonNull CharSequence mMessage; /** * Creates DisableSecureLockDeviceParams with the given params. * * @param message Allows clients to pass in a message with information about the request to * disable secure lock on the device. This message will be shown to the user when - * secure lock mode is disabled. If an empty string is provided, it will default - * to a system-defined string (e.g. "Secure lock mode has been disabled.") + * secure lock mode is disabled. If an empty CharSequence is provided, it will + * default to a system-defined CharSequence (e.g. "Secure lock mode has been + * disabled.") + * + * Since this text is shown in a restricted lockscreen state, typeface properties + * such as color, font weight, or other formatting may not be honored. */ - public DisableSecureLockDeviceParams(@NonNull String message) { + public DisableSecureLockDeviceParams(@NonNull CharSequence message) { mMessage = message; } private DisableSecureLockDeviceParams(@NonNull Parcel in) { - mMessage = Objects.requireNonNull(in.readString8()); + mMessage = Objects.requireNonNull(in.readCharSequence()); } public static final @NonNull Creator CREATOR = @@ -77,6 +84,6 @@ public final class DisableSecureLockDeviceParams implements Parcelable { @Override public void writeToParcel(@NonNull Parcel dest, int flags) { - dest.writeString8(mMessage); + dest.writeCharSequence(mMessage); } } diff --git a/core/java/android/security/authenticationpolicy/EnableSecureLockDeviceParams.java b/core/java/android/security/authenticationpolicy/EnableSecureLockDeviceParams.java index 1d727727ce37dce3a15b4f223d08fc0550feaf11..dfa391fcc85d0b5fe242c9519df692a4035aa7b8 100644 --- a/core/java/android/security/authenticationpolicy/EnableSecureLockDeviceParams.java +++ b/core/java/android/security/authenticationpolicy/EnableSecureLockDeviceParams.java @@ -38,23 +38,30 @@ public final class EnableSecureLockDeviceParams implements Parcelable { /** * Client message associated with the request to enable secure lock on the device. This message * will be shown on the device when secure lock mode is enabled. + * + * Since this text is shown in a restricted lockscreen state, typeface properties such as color, + * font weight, or other formatting may not be honored. */ - private final @NonNull String mMessage; + private final @NonNull CharSequence mMessage; /** * Creates EnableSecureLockDeviceParams with the given params. * * @param message Allows clients to pass in a message with information about the request to * enable secure lock on the device. This message will be shown to the user when - * secure lock mode is enabled. If an empty string is provided, it will default - * to a system-defined string (e.g. "Device is securely locked remotely.") + * secure lock mode is enabled. If an empty CharSequence is provided, it will + * default to a system-defined CharSequence (e.g. "Device is securely locked + * remotely.") + * + * Since this text is shown in a restricted lockscreen state, typeface properties + * such as color, font weight, or other formatting may not be honored. */ - public EnableSecureLockDeviceParams(@NonNull String message) { + public EnableSecureLockDeviceParams(@NonNull CharSequence message) { mMessage = message; } private EnableSecureLockDeviceParams(@NonNull Parcel in) { - mMessage = Objects.requireNonNull(in.readString8()); + mMessage = Objects.requireNonNull(in.readCharSequence()); } public static final @NonNull Creator CREATOR = @@ -77,6 +84,6 @@ public final class EnableSecureLockDeviceParams implements Parcelable { @Override public void writeToParcel(@NonNull Parcel dest, int flags) { - dest.writeString8(mMessage); + dest.writeCharSequence(mMessage); } } diff --git a/core/java/android/security/net/config/CertificatesEntryRef.java b/core/java/android/security/net/config/CertificatesEntryRef.java index 45cd0f0112995dad338067b5ebf5e08d551c2cb1..a46049fb2f6dfeae04a26b381bca09e14473bfd5 100644 --- a/core/java/android/security/net/config/CertificatesEntryRef.java +++ b/core/java/android/security/net/config/CertificatesEntryRef.java @@ -17,6 +17,7 @@ package android.security.net.config; import android.util.ArraySet; + import java.security.cert.X509Certificate; import java.util.Set; @@ -24,16 +25,23 @@ import java.util.Set; public final class CertificatesEntryRef { private final CertificateSource mSource; private final boolean mOverridesPins; + private final boolean mDisableCT; - public CertificatesEntryRef(CertificateSource source, boolean overridesPins) { + public CertificatesEntryRef(CertificateSource source, boolean overridesPins, + boolean disableCT) { mSource = source; mOverridesPins = overridesPins; + mDisableCT = disableCT; } boolean overridesPins() { return mOverridesPins; } + boolean disableCT() { + return mDisableCT; + } + public Set getTrustAnchors() { // TODO: cache this [but handle mutable sources] Set anchors = new ArraySet(); diff --git a/core/java/android/security/net/config/KeyStoreConfigSource.java b/core/java/android/security/net/config/KeyStoreConfigSource.java index 8d4f098bcb37a2a97d38a0529e21e969d5814b08..a54d8d0499cbfb4922b739376d2711b99916c86a 100644 --- a/core/java/android/security/net/config/KeyStoreConfigSource.java +++ b/core/java/android/security/net/config/KeyStoreConfigSource.java @@ -17,8 +17,8 @@ package android.security.net.config; import android.util.Pair; + import java.security.KeyStore; -import java.security.KeyStoreException; import java.util.Set; /** @@ -32,7 +32,7 @@ class KeyStoreConfigSource implements ConfigSource { mConfig = new NetworkSecurityConfig.Builder() .addCertificatesEntryRef( // Use the KeyStore and do not override pins (of which there are none). - new CertificatesEntryRef(new KeyStoreCertificateSource(ks), false)) + new CertificatesEntryRef(new KeyStoreCertificateSource(ks), false, false)) .build(); } diff --git a/core/java/android/security/net/config/NetworkSecurityConfig.java b/core/java/android/security/net/config/NetworkSecurityConfig.java index 129ae63ec9c003594deaccf7c274c2bf8183aaa6..410c68b8d04d8328701c52f1846c9ccdbd6794eb 100644 --- a/core/java/android/security/net/config/NetworkSecurityConfig.java +++ b/core/java/android/security/net/config/NetworkSecurityConfig.java @@ -112,7 +112,6 @@ public final class NetworkSecurityConfig { return mHstsEnforced; } - // TODO(b/28746284): add exceptions for user-added certificates and enterprise overrides. public boolean isCertificateTransparencyVerificationRequired() { return mCertificateTransparencyVerificationRequired; } @@ -192,20 +191,21 @@ public final class NetworkSecurityConfig { * @hide */ public static Builder getDefaultBuilder(ApplicationInfo info) { + // System certificate store, does not bypass static pins, does not disable CT. + CertificatesEntryRef systemRef = new CertificatesEntryRef( + SystemCertificateSource.getInstance(), false, false); Builder builder = new Builder() .setHstsEnforced(DEFAULT_HSTS_ENFORCED) - // System certificate store, does not bypass static pins. - .addCertificatesEntryRef( - new CertificatesEntryRef(SystemCertificateSource.getInstance(), false)); + .addCertificatesEntryRef(systemRef); final boolean cleartextTrafficPermitted = info.targetSdkVersion < Build.VERSION_CODES.P && !info.isInstantApp(); builder.setCleartextTrafficPermitted(cleartextTrafficPermitted); // Applications targeting N and above must opt in into trusting the user added certificate // store. if (info.targetSdkVersion <= Build.VERSION_CODES.M && !info.isPrivilegedApp()) { - // User certificate store, does not bypass static pins. + // User certificate store, does not bypass static pins. CT is disabled. builder.addCertificatesEntryRef( - new CertificatesEntryRef(UserCertificateSource.getInstance(), false)); + new CertificatesEntryRef(UserCertificateSource.getInstance(), false, true)); } return builder; } @@ -339,6 +339,16 @@ public final class NetworkSecurityConfig { if (mCertificateTransparencyVerificationRequiredSet) { return mCertificateTransparencyVerificationRequired; } + // CT verification has not been set explicitly. Before deferring to + // the parent, check if any of the CertificatesEntryRef requires it + // to be disabled (i.e., user store or inline certificate). + if (hasCertificatesEntryRefs()) { + for (CertificatesEntryRef ref : getCertificatesEntryRefs()) { + if (ref.disableCT()) { + return false; + } + } + } if (mParentBuilder != null) { return mParentBuilder.getCertificateTransparencyVerificationRequired(); } diff --git a/core/java/android/security/net/config/XmlConfigSource.java b/core/java/android/security/net/config/XmlConfigSource.java index b1c14793bbbd359bcb9f52dd7417a228b273435d..95e579fc538b889e7a8bdc4510b6788c2ddf2200 100644 --- a/core/java/android/security/net/config/XmlConfigSource.java +++ b/core/java/android/security/net/config/XmlConfigSource.java @@ -182,6 +182,7 @@ public class XmlConfigSource implements ConfigSource { boolean overridePins = parser.getAttributeBooleanValue(null, "overridePins", defaultOverridePins); int sourceId = parser.getAttributeResourceValue(null, "src", -1); + boolean disableCT = false; String sourceString = parser.getAttributeValue(null, "src"); CertificateSource source = null; if (sourceString == null) { @@ -190,10 +191,12 @@ public class XmlConfigSource implements ConfigSource { if (sourceId != -1) { // TODO: Cache ResourceCertificateSources by sourceId source = new ResourceCertificateSource(sourceId, mContext); + disableCT = true; } else if ("system".equals(sourceString)) { source = SystemCertificateSource.getInstance(); } else if ("user".equals(sourceString)) { source = UserCertificateSource.getInstance(); + disableCT = true; } else if ("wfa".equals(sourceString)) { source = WfaCertificateSource.getInstance(); } else { @@ -201,7 +204,7 @@ public class XmlConfigSource implements ConfigSource { + "Should be one of system|user|@resourceVal"); } XmlUtils.skipCurrentTag(parser); - return new CertificatesEntryRef(source, overridePins); + return new CertificatesEntryRef(source, overridePins, disableCT); } private Collection parseTrustAnchors(XmlResourceParser parser, diff --git a/core/java/android/security/responsible_apis_flags.aconfig b/core/java/android/security/responsible_apis_flags.aconfig index 42dbd37860017ef08cb135b61d07e2876eb72ee1..8add9f7c63cc26bd221c3971d6f7831f26c05334 100644 --- a/core/java/android/security/responsible_apis_flags.aconfig +++ b/core/java/android/security/responsible_apis_flags.aconfig @@ -96,14 +96,6 @@ flag { is_fixed_read_only: true } -flag { - name: "prevent_intent_redirect_show_toast_if_nested_keys_not_collected" - namespace: "responsible_apis" - description: "Prevent intent redirect attacks by showing a toast if not yet collected" - bug: "361143368" - is_fixed_read_only: true -} - flag { name: "prevent_intent_redirect_show_toast_if_nested_keys_not_collected_r_w" namespace: "responsible_apis" diff --git a/core/java/android/service/autofill/AutofillService.java b/core/java/android/service/autofill/AutofillService.java index 269839b61befe278a05d11d4a2da33e65eb1bcf4..2d922b4c09ee94b5ebf54de84c85cbf4cc11035c 100644 --- a/core/java/android/service/autofill/AutofillService.java +++ b/core/java/android/service/autofill/AutofillService.java @@ -15,9 +15,12 @@ */ package android.service.autofill; +import static android.service.autofill.Flags.FLAG_AUTOFILL_SESSION_DESTROYED; + import static com.android.internal.util.function.pooled.PooledLambda.obtainMessage; import android.annotation.CallSuper; +import android.annotation.FlaggedApi; import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.SdkConstant; @@ -669,6 +672,14 @@ public abstract class AutofillService extends Service { AutofillService.this, new SavedDatasetsInfoCallbackImpl(receiver, SavedDatasetsInfo.TYPE_PASSWORDS))); } + + @Override + public void onSessionDestroyed(@Nullable FillEventHistory history) { + mHandler.sendMessage(obtainMessage( + AutofillService::onSessionDestroyed, + AutofillService.this, + history)); + } }; private Handler mHandler; @@ -783,26 +794,42 @@ public abstract class AutofillService extends Service { } /** - * Gets the events that happened after the last - * {@link AutofillService#onFillRequest(FillRequest, android.os.CancellationSignal, FillCallback)} + * Called when an Autofill context has ended and the Autofill session is finished. This will be + * called as the last step of the Autofill lifecycle described in {@link AutofillManager}. + * + *

    This will also contain the finished Session's FillEventHistory, so providers do not need + * to explicitly call {@link #getFillEventHistory()} + * + *

    This will usually happens whenever {@link AutofillManager#commit()} or {@link + * AutofillManager#cancel()} is called. + */ + @FlaggedApi(FLAG_AUTOFILL_SESSION_DESTROYED) + public void onSessionDestroyed(@Nullable FillEventHistory history) {} + + /** + * Gets the events that happened after the last {@link + * AutofillService#onFillRequest(FillRequest, android.os.CancellationSignal, FillCallback)} * call. * *

    This method is typically used to keep track of previous user actions to optimize further * requests. For example, the service might return email addresses in alphabetical order by * default, but change that order based on the address the user picked on previous requests. * - *

    The history is not persisted over reboots, and it's cleared every time the service - * replies to a {@link #onFillRequest(FillRequest, CancellationSignal, FillCallback)} by calling - * {@link FillCallback#onSuccess(FillResponse)} or {@link FillCallback#onFailure(CharSequence)} - * (if the service doesn't call any of these methods, the history will clear out after some - * pre-defined time). Hence, the service should call {@link #getFillEventHistory()} before - * finishing the {@link FillCallback}. + *

    The history is not persisted over reboots, and it's cleared every time the service replies + * to a {@link #onFillRequest(FillRequest, CancellationSignal, FillCallback)} by calling {@link + * FillCallback#onSuccess(FillResponse)} or {@link FillCallback#onFailure(CharSequence)} (if the + * service doesn't call any of these methods, the history will clear out after some pre-defined + * time). Hence, the service should call {@link #getFillEventHistory()} before finishing the + * {@link FillCallback}. * * @return The history or {@code null} if there are no events. - * * @throws RuntimeException if the event history could not be retrieved. + * @deprecated Use {@link #onSessionDestroyed(FillEventHistory) instead} */ - @Nullable public final FillEventHistory getFillEventHistory() { + @FlaggedApi(FLAG_AUTOFILL_SESSION_DESTROYED) + @Deprecated + @Nullable + public final FillEventHistory getFillEventHistory() { final AutofillManager afm = getSystemService(AutofillManager.class); if (afm == null) { diff --git a/core/java/android/service/autofill/FillEventHistory.java b/core/java/android/service/autofill/FillEventHistory.java index fba8e42cc673ecbf4827e27191b5e67796e41dcb..6d62a2c7db2eb920d70d6937588bf2cbdae06663 100644 --- a/core/java/android/service/autofill/FillEventHistory.java +++ b/core/java/android/service/autofill/FillEventHistory.java @@ -341,7 +341,7 @@ public final class FillEventHistory implements Parcelable { /** Credential Manager suggestions are shown instead of Autofill suggestion */ @FlaggedApi(FLAG_AUTOFILL_W_METRICS) - public static final int UI_TYPE_CREDMAN = 4; + public static final int UI_TYPE_CREDENTIAL_MANAGER = 4; /** @hide */ @IntDef(prefix = { "UI_TYPE_" }, value = { diff --git a/core/java/android/service/autofill/IAutoFillService.aidl b/core/java/android/service/autofill/IAutoFillService.aidl index 3b64b8a0ec5e47854737e704e8a5b80fed2ac17a..71b75e7789c241f9d0ae93d56d5be2e09257fb90 100644 --- a/core/java/android/service/autofill/IAutoFillService.aidl +++ b/core/java/android/service/autofill/IAutoFillService.aidl @@ -25,6 +25,8 @@ import android.service.autofill.ISaveCallback; import android.service.autofill.SaveRequest; import com.android.internal.os.IResultReceiver; +parcelable FillEventHistory; + /** * Interface from the system to an auto fill service. * @@ -38,4 +40,5 @@ oneway interface IAutoFillService { void onSaveRequest(in SaveRequest request, in ISaveCallback callback); void onSavedPasswordCountRequest(in IResultReceiver receiver); void onConvertCredentialRequest(in ConvertCredentialRequest convertCredentialRequest, in IConvertCredentialCallback convertCredentialCallback); + void onSessionDestroyed(in FillEventHistory history); } diff --git a/services/core/java/com/android/server/notification/RateEstimator.java b/core/java/android/service/notification/RateEstimator.java similarity index 92% rename from services/core/java/com/android/server/notification/RateEstimator.java rename to core/java/android/service/notification/RateEstimator.java index eda96ac84b1657112c0e163cf6f35c76d51f15fa..04789c18ffe4cc3c9ac293a8181de79e91062bba 100644 --- a/services/core/java/com/android/server/notification/RateEstimator.java +++ b/core/java/android/service/notification/RateEstimator.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2016 The Android Open Source Project + * Copyright (C) 2024 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -11,10 +11,10 @@ * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and - * limitations under the License + * limitations under the License. */ -package com.android.server.notification; +package android.service.notification; /** @@ -22,7 +22,7 @@ package com.android.server.notification; * * {@hide} */ -class RateEstimator { +public class RateEstimator { private static final double RATE_ALPHA = 0.7; private static final double MINIMUM_DT = 0.0005; diff --git a/core/java/android/service/ondeviceintelligence/OWNERS b/core/java/android/service/ondeviceintelligence/OWNERS deleted file mode 100644 index 09774f78d71273cf3ae9de7ef4efc4a2de979e7e..0000000000000000000000000000000000000000 --- a/core/java/android/service/ondeviceintelligence/OWNERS +++ /dev/null @@ -1 +0,0 @@ -file:/core/java/android/app/ondeviceintelligence/OWNERS diff --git a/core/java/android/service/settings/preferences/SettingsPreferenceMetadata.java b/core/java/android/service/settings/preferences/SettingsPreferenceMetadata.java index 1acb7b8460cf1992d129f2bc67ca34d5cf65ed6a..ea7d4a675713655eca8143df344175073df35381 100644 --- a/core/java/android/service/settings/preferences/SettingsPreferenceMetadata.java +++ b/core/java/android/service/settings/preferences/SettingsPreferenceMetadata.java @@ -187,27 +187,39 @@ public final class SettingsPreferenceMetadata implements Parcelable { /** @hide */ @IntDef(value = { - NOT_SENSITIVE, - SENSITIVE, - INTENT_ONLY + NO_SENSITIVITY, + EXPECT_POST_CONFIRMATION, + EXPECT_PRE_CONFIRMATION, + NO_DIRECT_ACCESS, }) @Retention(RetentionPolicy.SOURCE) public @interface WriteSensitivity {} /** - * Preference is not sensitive, thus its value is writable without explicit consent, assuming - * all necessary permissions are granted. + * Indicates preference is not sensitive. + *

    Its value is writable without explicit consent, assuming all necessary permissions are + * granted. */ - public static final int NOT_SENSITIVE = 0; + public static final int NO_SENSITIVITY = 0; /** - * Preference is sensitive, meaning that in addition to necessary permissions, writing its value - * will also request explicit user consent. + * Indicates preference is mildly sensitive. + *

    In addition to necessary permissions, after writing its value the user should be + * given the option to revert back. */ - public static final int SENSITIVE = 1; + public static final int EXPECT_POST_CONFIRMATION = 1; /** - * Preference is not permitted for write-access via API and must be changed via Settings page. + * Indicates preference is sensitive. + *

    In addition to necessary permissions, the user should be prompted for confirmation prior + * to making a change. Otherwise it is suggested to provide a deeplink to the Preference's page + * instead, accessible via {@link #getLaunchIntent}. */ - public static final int INTENT_ONLY = 2; + public static final int EXPECT_PRE_CONFIRMATION = 2; + /** + * Indicates preference is highly sensitivity and carries significant user-risk. + *

    This Preference cannot be changed through this API and no direct deeplink is available. + * Other Metadata is still available. + */ + public static final int NO_DIRECT_ACCESS = 3; private SettingsPreferenceMetadata(@NonNull Builder builder) { mKey = builder.mKey; @@ -303,7 +315,7 @@ public final class SettingsPreferenceMetadata implements Parcelable { private boolean mAvailable = false; private boolean mWritable = false; private boolean mRestricted = false; - @WriteSensitivity private int mSensitivity = INTENT_ONLY; + @WriteSensitivity private int mSensitivity = NO_DIRECT_ACCESS; private Intent mLaunchIntent; private Bundle mExtras; @@ -436,6 +448,9 @@ public final class SettingsPreferenceMetadata implements Parcelable { */ @NonNull public SettingsPreferenceMetadata build() { + if (mSensitivity == NO_DIRECT_ACCESS) { + mLaunchIntent = null; + } return new SettingsPreferenceMetadata(this); } } diff --git a/core/java/android/speech/tts/EventLogTags.logtags b/core/java/android/speech/tts/EventLogTags.logtags index e209a286966aa8aad8597c83e2f1c5d12df0b89f..5ba2baec6fcfee1ed6737676c833b56dac00f960 100644 --- a/core/java/android/speech/tts/EventLogTags.logtags +++ b/core/java/android/speech/tts/EventLogTags.logtags @@ -1,4 +1,4 @@ -# See system/core/logcat/event.logtags for a description of the format of this file. +# See system/logging/logcat/event.logtags for a description of the format of this file. option java_package android.speech.tts; diff --git a/core/java/android/view/Display.java b/core/java/android/view/Display.java index c9d560c3424bc63d890dba0cf5dedb2df841363a..802bddd76e30de63ea7c2fb4b84f31c762b38a4d 100644 --- a/core/java/android/view/Display.java +++ b/core/java/android/view/Display.java @@ -1301,17 +1301,23 @@ public final class Display { } /** - * Represents the {@link FrameRateCategory} for the Normal frame rate + * Normal category determines the framework's recommended normal frame rate. + * Opt for this normal rate unless a higher frame rate significantly enhances + * the user experience. * - * @see FrameRateCategory + * @see #getSuggestedFrameRate(int) + * @see #FRAME_RATE_CATEGORY_HIGH */ @FlaggedApi(FLAG_ENABLE_GET_SUGGESTED_FRAME_RATE) public static final int FRAME_RATE_CATEGORY_NORMAL = 0; /** - * Represents the {@link FrameRateCategory} for the High frame rate + * High category determines the framework's recommended high frame rate. + * Opt for this high rate when a higher frame rate significantly enhances + * the user experience. * - * @see FrameRateCategory + * @see #getSuggestedFrameRate(int) + * @see #FRAME_RATE_CATEGORY_NORMAL */ @FlaggedApi(FLAG_ENABLE_GET_SUGGESTED_FRAME_RATE) public static final int FRAME_RATE_CATEGORY_HIGH = 1; @@ -1332,22 +1338,17 @@ public final class Display { * *

    For example, an animation that does not require fast render rates can use * the {@link #FRAME_RATE_CATEGORY_NORMAL} to get the suggested frame rate. - * The suggested frame rate then can be used in the - * {@link Surface.FrameRateParams.Builder#setDesiredRateRange} for desiredMinRate. * *

    {@code
          *  float desiredMinRate = display.getSuggestedFrameRate(FRAME_RATE_CATEGORY_NORMAL);
    -     *  Surface.FrameRateParams params = new Surface.FrameRateParams.Builder().
    -     *                                      setDesiredRateRange(desiredMinRate, Float.MAX).build();
    -     *  surface.setFrameRate(params);
    +     *  surface.setFrameRate(desiredMinRate, Surface.FRAME_RATE_COMPATIBILITY_DEFAULT);
          * }
    *

    * * @param category either {@link #FRAME_RATE_CATEGORY_NORMAL} * or {@link #FRAME_RATE_CATEGORY_HIGH} * - * @see Surface#setFrameRate(Surface.FrameRateParams) - * @see SurfaceControl.Transaction#setFrameRate(SurfaceControl, Surface.FrameRateParams) + * @see Surface#setFrameRate(float, int) * @throws IllegalArgumentException when category is not {@link #FRAME_RATE_CATEGORY_NORMAL} * or {@link #FRAME_RATE_CATEGORY_HIGH} */ diff --git a/core/java/android/view/DisplayEventReceiver.java b/core/java/android/view/DisplayEventReceiver.java index bb233d2711de05ab0f41a53e27c36a1ff9f1be81..3ff5f95cd71f5791c00c71379a69f683e5435fed 100644 --- a/core/java/android/view/DisplayEventReceiver.java +++ b/core/java/android/view/DisplayEventReceiver.java @@ -286,13 +286,22 @@ public abstract class DisplayEventReceiver { * @param timestampNanos The timestamp of the event, in the {@link System#nanoTime()} * timebase. * @param physicalDisplayId Stable display ID that uniquely describes a (display, port) pair. - * @param modeId The new mode Id + * @param modeId The new mode ID * @param renderPeriod The render frame period, which is a multiple of the mode's vsync period */ public void onModeChanged(long timestampNanos, long physicalDisplayId, int modeId, long renderPeriod) { } + /** + * Called when a display mode rejection event is received. + * + * @param physicalDisplayId Stable display ID that uniquely describes a (display, port) pair. + * @param modeId The mode ID of the mode that was rejected + */ + public void onModeRejected(long physicalDisplayId, int modeId) { + } + /** * Called when a display hdcp levels change event is received. * @@ -384,6 +393,12 @@ public abstract class DisplayEventReceiver { onModeChanged(timestampNanos, physicalDisplayId, modeId, renderPeriod); } + // Called from native code. + @SuppressWarnings("unused") + private void dispatchModeRejected(long physicalDisplayId, int modeId) { + onModeRejected(physicalDisplayId, modeId); + } + // Called from native code. @SuppressWarnings("unused") private void dispatchFrameRateOverrides(long timestampNanos, long physicalDisplayId, diff --git a/core/java/android/view/DisplayInfo.java b/core/java/android/view/DisplayInfo.java index 8b6458a54c43c3ff44ff8d4967500c6b0ebb073a..43078847326cb1e2c074c2d006be20bf7c6fb9a3 100644 --- a/core/java/android/view/DisplayInfo.java +++ b/core/java/android/view/DisplayInfo.java @@ -360,6 +360,12 @@ public final class DisplayInfo implements Parcelable { */ public float brightnessDefault; + /** + * The current dim brightness of the display. Value between 0.0 and 1.0, + * derived from the configuration of the display device of this logical display. + */ + public float brightnessDim; + /** * The {@link RoundedCorners} if present, otherwise {@code null}. */ @@ -479,6 +485,7 @@ public final class DisplayInfo implements Parcelable { && brightnessMinimum == other.brightnessMinimum && brightnessMaximum == other.brightnessMaximum && brightnessDefault == other.brightnessDefault + && brightnessDim == other.brightnessDim && Objects.equals(roundedCorners, other.roundedCorners) && installOrientation == other.installOrientation && Objects.equals(displayShape, other.displayShape) @@ -546,6 +553,7 @@ public final class DisplayInfo implements Parcelable { brightnessMinimum = other.brightnessMinimum; brightnessMaximum = other.brightnessMaximum; brightnessDefault = other.brightnessDefault; + brightnessDim = other.brightnessDim; roundedCorners = other.roundedCorners; installOrientation = other.installOrientation; displayShape = other.displayShape; @@ -620,6 +628,7 @@ public final class DisplayInfo implements Parcelable { brightnessMinimum = source.readFloat(); brightnessMaximum = source.readFloat(); brightnessDefault = source.readFloat(); + brightnessDim = source.readFloat(); roundedCorners = source.readTypedObject(RoundedCorners.CREATOR); int numUserDisabledFormats = source.readInt(); userDisabledHdrTypes = new int[numUserDisabledFormats]; @@ -696,6 +705,7 @@ public final class DisplayInfo implements Parcelable { dest.writeFloat(brightnessMinimum); dest.writeFloat(brightnessMaximum); dest.writeFloat(brightnessDefault); + dest.writeFloat(brightnessDim); dest.writeTypedObject(roundedCorners, flags); dest.writeInt(userDisabledHdrTypes.length); for (int i = 0; i < userDisabledHdrTypes.length; i++) { @@ -994,6 +1004,8 @@ public final class DisplayInfo implements Parcelable { sb.append(brightnessMaximum); sb.append(", brightnessDefault "); sb.append(brightnessDefault); + sb.append(", brightnessDim "); + sb.append(brightnessDim); sb.append(", installOrientation "); sb.append(Surface.rotationToString(installOrientation)); sb.append(", layoutLimitedRefreshRate "); diff --git a/core/java/android/view/IWindowManager.aidl b/core/java/android/view/IWindowManager.aidl index 6d85e7589c482992e0682cbfa272fae04a282c68..072a037aa84afbce29386e8b8bb1439e050f9467 100644 --- a/core/java/android/view/IWindowManager.aidl +++ b/core/java/android/view/IWindowManager.aidl @@ -766,7 +766,7 @@ interface IWindowManager * container. */ @EnforcePermission("MANAGE_APP_TOKENS") - void updateDisplayWindowRequestedVisibleTypes(int displayId, int requestedVisibleTypes, + void updateDisplayWindowRequestedVisibleTypes(int displayId, int visibleTypes, int mask, in @nullable ImeTracker.Token statsToken); /** @@ -932,6 +932,27 @@ interface IWindowManager */ void detachWindowContext(IBinder clientToken); + /** + * Reparents the {@link android.window.WindowContext} to the + * {@link com.android.server.wm.DisplayArea} on another display. + * This method also reparent the WindowContext associated WindowToken to another display if + * necessary. + *

    + * {@code type} and {@code options} must be the same as the previous call of + * {@link #attachWindowContextToDisplayArea} on the same Context otherwise this will fail + * silently. + * + * @param appThread the process that the window context is on. + * @param clientToken the window context's token + * @param type The window type of the WindowContext + * @param displayId The new display id this context windows should be parented to + * @param options Bundle the context was created with + * + * @return True if the operation was successful, False otherwise. + */ + boolean reparentWindowContextToDisplayArea(in IApplicationThread appThread, + IBinder clientToken, int displayId); + /** * Registers a listener, which is to be called whenever cross-window blur is enabled/disabled. * diff --git a/core/java/android/view/InsetsSource.java b/core/java/android/view/InsetsSource.java index b796e0b1c4292a570c28d2b0ed3d762cc0863620..ba208390c8b7db8d4be4431b29e3793fc4df105d 100644 --- a/core/java/android/view/InsetsSource.java +++ b/core/java/android/view/InsetsSource.java @@ -357,6 +357,31 @@ public class InsetsSource implements Parcelable { } else if (mTmpFrame.right == relativeFrame.right) { return Insets.of(0, 0, mTmpFrame.width(), 0); } + } else { + // The source doesn't cover the width or the height of relativeFrame, but just parts of + // them. Here uses mSideHint to decide which side should be inset. + switch (mSideHint) { + case SIDE_LEFT: + if (mTmpFrame.left == relativeFrame.left) { + return Insets.of(mTmpFrame.width(), 0, 0, 0); + } + break; + case SIDE_TOP: + if (mTmpFrame.top == relativeFrame.top) { + return Insets.of(0, mTmpFrame.height(), 0, 0); + } + break; + case SIDE_RIGHT: + if (mTmpFrame.right == relativeFrame.right) { + return Insets.of(0, 0, mTmpFrame.width(), 0); + } + break; + case SIDE_BOTTOM: + if (mTmpFrame.bottom == relativeFrame.bottom) { + return Insets.of(0, 0, 0, mTmpFrame.height()); + } + break; + } } return Insets.NONE; } diff --git a/core/java/android/view/InsetsState.java b/core/java/android/view/InsetsState.java index 67050e01b5915a4bdda9fc7698146a2a4f551eb8..213ece09da227b20ba4b91f5194af1f9b81a5fcd 100644 --- a/core/java/android/view/InsetsState.java +++ b/core/java/android/view/InsetsState.java @@ -296,8 +296,8 @@ public class InsetsState implements Parcelable { @SoftInputModeFlags int softInputMode, int windowFlags) { final int softInputAdjustMode = softInputMode & SOFT_INPUT_MASK_ADJUST; final int visibleInsetsTypes = softInputAdjustMode != SOFT_INPUT_ADJUST_NOTHING - ? systemBars() | ime() - : systemBars(); + ? systemBars() | displayCutout() | ime() + : systemBars() | displayCutout(); @InsetsType int forceConsumingTypes = 0; Insets insets = Insets.NONE; for (int i = mSources.size() - 1; i >= 0; i--) { diff --git a/core/java/android/view/Surface.java b/core/java/android/view/Surface.java index 03f9d9814b4317197c614e3e61529cf5b55873b5..6e6e87bb9403f39d9a0d0316df2c062ed489596a 100644 --- a/core/java/android/view/Surface.java +++ b/core/java/android/view/Surface.java @@ -205,7 +205,8 @@ public class Surface implements Parcelable { /** @hide */ @Retention(RetentionPolicy.SOURCE) @IntDef(prefix = {"FRAME_RATE_COMPATIBILITY_"}, - value = {FRAME_RATE_COMPATIBILITY_DEFAULT, FRAME_RATE_COMPATIBILITY_FIXED_SOURCE}) + value = {FRAME_RATE_COMPATIBILITY_DEFAULT, FRAME_RATE_COMPATIBILITY_FIXED_SOURCE, + FRAME_RATE_COMPATIBILITY_GTE}) public @interface FrameRateCompatibility {} // From native_window.h. Keep these in sync. @@ -214,6 +215,11 @@ public class Surface implements Parcelable { * system selects a frame rate other than what the app requested, the app will be able * to run at the system frame rate without requiring pull down. This value should be * used when displaying game content, UIs, and anything that isn't video. + * + * In Android version {@link Build.VERSION_CODES#BAKLAVA} and above, use + * {@link FRAME_RATE_COMPATIBILITY_DEFAULT} for game content. + * For other cases, see {@link FRAME_RATE_COMPATIBILITY_FIXED_SOURCE} and + * {@link FRAME_RATE_COMPATIBILITY_GTE}. */ public static final int FRAME_RATE_COMPATIBILITY_DEFAULT = 0; @@ -227,6 +233,17 @@ public class Surface implements Parcelable { */ public static final int FRAME_RATE_COMPATIBILITY_FIXED_SOURCE = 1; + /** + * The surface requests a frame rate that is greater than or equal to the specified frame rate. + * This value should be used for UIs, animations, scrolling and fling, and anything that is not + * a game or video. + * + * For video, use {@link FRAME_RATE_COMPATIBILITY_FIXED_SOURCE} instead. For game content, use + * {@link FRAME_RATE_COMPATIBILITY_DEFAULT}. + */ + @FlaggedApi(com.android.graphics.surfaceflinger.flags.Flags.FLAG_ARR_SETFRAMERATE_GTE_ENUM) + public static final int FRAME_RATE_COMPATIBILITY_GTE = 2; + /** * This surface belongs to an app on the High Refresh Rate Deny list, and needs the display * to operate at the exact frame rate. @@ -250,13 +267,6 @@ public class Surface implements Parcelable { */ public static final int FRAME_RATE_COMPATIBILITY_MIN = 102; - // From window.h. Keep these in sync. - /** - * The surface requests a frame rate that is greater than or equal to {@code frameRate}. - * @hide - */ - public static final int FRAME_RATE_COMPATIBILITY_GTE = 103; - /** @hide */ @Retention(RetentionPolicy.SOURCE) @IntDef(prefix = {"CHANGE_FRAME_RATE_"}, diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java index 02c79015fab237adc74bdc30a943aa9816219adc..d13f0e21bf8059779c9330a5993907ec88c8e781 100644 --- a/core/java/android/view/View.java +++ b/core/java/android/view/View.java @@ -17184,7 +17184,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback, final WindowManager windowManager = mContext.getSystemService(WindowManager.class); final WindowMetrics metrics = windowManager.getMaximumWindowMetrics(); final Insets insets = metrics.getWindowInsets().getInsets( - WindowInsets.Type.navigationBars() | WindowInsets.Type.displayCutout()); + WindowInsets.Type.systemBars() | WindowInsets.Type.displayCutout()); outRect.set(metrics.getBounds()); outRect.inset(insets); outRect.offsetTo(0, 0); @@ -28277,7 +28277,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback, mPrivateFlags |= PFLAG_FORCE_LAYOUT; mPrivateFlags |= PFLAG_INVALIDATED; - if (mParent != null) { + if (mParent != null && !mParent.isLayoutRequested()) { mParent.requestLayout(); } if (mAttachInfo != null && mAttachInfo.mViewRequestingLayout == this) { diff --git a/core/java/android/view/ViewConfiguration.java b/core/java/android/view/ViewConfiguration.java index 63bf392b5ef15a9992fdc7e16c9421f17531f2ba..9e97a8eb58aa99eef967f991367655bc2e6b6f2e 100644 --- a/core/java/android/view/ViewConfiguration.java +++ b/core/java/android/view/ViewConfiguration.java @@ -591,7 +591,7 @@ public class ViewConfiguration { res.getBoolean( com.android.internal.R.bool.config_viewBasedRotaryEncoderHapticsEnabled); mViewTouchScreenHapticScrollFeedbackEnabled = - Flags.enableTouchScrollFeedback() + Flags.enableScrollFeedbackForTouch() ? res.getBoolean( com.android.internal.R.bool .config_viewTouchScreenHapticScrollFeedbackEnabled) diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java index 31330204e8c60906babc0e1c56bd6df6121f30eb..c1b92ee3f74e905ac9ab934f8ab1eaaca45e40f3 100644 --- a/core/java/android/view/ViewRootImpl.java +++ b/core/java/android/view/ViewRootImpl.java @@ -17,8 +17,8 @@ package android.view; import static android.adpf.Flags.adpfViewrootimplActionDownBoost; -import static android.app.WindowConfiguration.WINDOWING_MODE_MULTI_WINDOW; import static android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM; +import static android.app.WindowConfiguration.WINDOWING_MODE_MULTI_WINDOW; import static android.content.pm.ActivityInfo.OVERRIDE_SANDBOX_VIEW_BOUNDS_APIS; import static android.graphics.HardwareRenderer.SYNC_CONTEXT_IS_STOPPED; import static android.graphics.HardwareRenderer.SYNC_LOST_SURFACE_REWARD_IF_FOUND; @@ -2255,7 +2255,7 @@ public final class ViewRootImpl implements ViewParent, onClientWindowFramesChanged(frames); - CompatibilityInfo.applyOverrideScaleIfNeeded(mergedConfiguration); + CompatibilityInfo.applyOverrideIfNeeded(mergedConfiguration); final Rect frame = frames.frame; final Rect displayFrame = frames.displayFrame; final Rect attachedFrame = frames.attachedFrame; @@ -2653,8 +2653,7 @@ public final class ViewRootImpl implements ViewParent, mStopped = stopped; final ThreadedRenderer renderer = mAttachInfo.mThreadedRenderer; if (renderer != null) { - if (DEBUG_DRAW) - Log.d(mTag, "WindowStopped on " + getTitle() + " set to " + mStopped); + if (DEBUG_DRAW) Log.d(mTag, "WindowStopped on " + getTitle() + " set to " + mStopped); renderer.setStopped(mStopped); } if (!mStopped) { @@ -7980,8 +7979,8 @@ public final class ViewRootImpl implements ViewParent, private boolean moveFocusToAdjacentWindow(@FocusDirection int direction) { final int windowingMode = getConfiguration().windowConfiguration.getWindowingMode(); - if (!(windowingMode == WINDOWING_MODE_MULTI_WINDOW - || windowingMode == WINDOWING_MODE_FREEFORM)) { + if (windowingMode != WINDOWING_MODE_MULTI_WINDOW + && windowingMode != WINDOWING_MODE_FREEFORM) { return false; } try { @@ -9461,7 +9460,7 @@ public final class ViewRootImpl implements ViewParent, mTranslator.translateRectInScreenToAppWindow(mTmpFrames.attachedFrame); } mInvCompatScale = 1f / mTmpFrames.compatScale; - CompatibilityInfo.applyOverrideScaleIfNeeded(mPendingMergedConfiguration); + CompatibilityInfo.applyOverrideIfNeeded(mPendingMergedConfiguration); handleInsetsControlChanged(mTempInsets, mTempControls); mPendingAlwaysConsumeSystemBars = diff --git a/core/java/android/view/ViewStructure.java b/core/java/android/view/ViewStructure.java index 1be7f4849f07a1b7291191643b82219ca5a528fa..43a946a234babe4ed6ab7055a43bc0cdd5e7e275 100644 --- a/core/java/android/view/ViewStructure.java +++ b/core/java/android/view/ViewStructure.java @@ -87,8 +87,12 @@ public abstract class ViewStructure { *

    This value is added to mainly help with debugging purpose. */ @FlaggedApi(FLAG_AUTOFILL_W_METRICS) + @SuppressWarnings( + "ActionValue") // Lint expects this as + // android.view.contentcapture.extra.VIRTUAL_STRUCTURE_VERSION_NUMBER + // but should not have contentcapture public static final String EXTRA_VIRTUAL_STRUCTURE_TYPE = - "android.view.ViewStructure.extra.VIRTUAL_STRUCTURE_TYPE"; + "android.view.extra.VIRTUAL_STRUCTURE_TYPE"; /** * Key used for specifying the version of the view that generated the virtual structure for @@ -98,8 +102,12 @@ public abstract class ViewStructure { * "104.0.5112.69", then the value should be "104.0.5112.69" */ @FlaggedApi(FLAG_AUTOFILL_W_METRICS) + @SuppressWarnings( + "ActionValue") // Lint expects this as + // android.view.contentcapture.extra.VIRTUAL_STRUCTURE_TYPE + // but should not have contentcapture public static final String EXTRA_VIRTUAL_STRUCTURE_VERSION_NUMBER = - "android.view.ViewStructure.extra.VIRTUAL_STRUCTURE_VERSION_NUMBER"; + "android.view.extra.VIRTUAL_STRUCTURE_VERSION_NUMBER"; /** * Set the identifier for this view. diff --git a/core/java/android/view/WindowManager.java b/core/java/android/view/WindowManager.java index 1e8cad61381c257d87a451fc4670d5c126d6ebb1..101d5c950b71344017d72112c759401185a88b80 100644 --- a/core/java/android/view/WindowManager.java +++ b/core/java/android/view/WindowManager.java @@ -80,6 +80,9 @@ import static android.view.WindowLayoutParamsProto.WINDOW_ANIMATIONS; import static android.view.WindowLayoutParamsProto.X; import static android.view.WindowLayoutParamsProto.Y; +import static com.android.hardware.input.Flags.FLAG_OVERRIDE_POWER_KEY_BEHAVIOR_IN_FOCUSED_WINDOW; +import static com.android.hardware.input.Flags.overridePowerKeyBehaviorInFocusedWindow; + import android.Manifest.permission; import android.annotation.CallbackExecutor; import android.annotation.FlaggedApi; @@ -4464,6 +4467,29 @@ public interface WindowManager extends ViewManager { */ public static final int INPUT_FEATURE_SENSITIVE_FOR_PRIVACY = 1 << 3; + /** + * Input feature used to indicate that the system should send power key events to this + * window when it's in the foreground. The window can override the double press power key + * gesture behavior. + * + * A double press gesture is defined as two + * {@link KeyEvent.Callback#onKeyDown(int, KeyEvent)} events within a time span defined by + * {@link ViewConfiguration#getMultiPressTimeout()}. + * + * Note: While the window may receive all power key {@link KeyEvent}s, it can only + * override the double press gesture behavior. The system will perform default behavior for + * single, long-press and other multi-press gestures, regardless of if the app handles the + * key or not. + * + * To override the default behavior for double press, the app must return true for the + * second {@link KeyEvent.Callback#onKeyDown(int, KeyEvent)}. If the app returns false, the + * system behavior will be performed for double press. + * @hide + */ + @RequiresPermission(permission.OVERRIDE_SYSTEM_KEY_BEHAVIOR_IN_FOCUSED_WINDOW) + public static final int + INPUT_FEATURE_RECEIVE_POWER_KEY_DOUBLE_PRESS = 1 << 4; + /** * An internal annotation for flags that can be specified to {@link #inputFeatures}. * @@ -4477,6 +4503,7 @@ public interface WindowManager extends ViewManager { INPUT_FEATURE_DISABLE_USER_ACTIVITY, INPUT_FEATURE_SPY, INPUT_FEATURE_SENSITIVE_FOR_PRIVACY, + INPUT_FEATURE_RECEIVE_POWER_KEY_DOUBLE_PRESS }) public @interface InputFeatureFlags { } @@ -4765,6 +4792,44 @@ public interface WindowManager extends ViewManager { privateFlags |= PRIVATE_FLAG_FIT_INSETS_CONTROLLED; } + /** + * Specifies if the system should send power key events to this window when it's in the + * foreground, with only the double tap gesture behavior being overrideable. + * + * @param enabled if true, the system should send power key events to this window when it's + * in the foreground, with only the power key double tap gesture being + * overrideable. + * @hide + */ + @SystemApi + @RequiresPermission(permission.OVERRIDE_SYSTEM_KEY_BEHAVIOR_IN_FOCUSED_WINDOW) + @FlaggedApi(FLAG_OVERRIDE_POWER_KEY_BEHAVIOR_IN_FOCUSED_WINDOW) + public void setReceivePowerKeyDoublePressEnabled(boolean enabled) { + if (enabled) { + inputFeatures + |= INPUT_FEATURE_RECEIVE_POWER_KEY_DOUBLE_PRESS; + } else { + inputFeatures + &= ~INPUT_FEATURE_RECEIVE_POWER_KEY_DOUBLE_PRESS; + } + } + + /** + * Returns whether or not the system should send power key events to this window when it's + * in the foreground, with only the double tap gesture being overrideable. + * + * @return if the system should send power key events to this window when it's in the + * foreground, with only the double tap gesture being overrideable. + * @hide + */ + @SystemApi + @RequiresPermission(permission.OVERRIDE_SYSTEM_KEY_BEHAVIOR_IN_FOCUSED_WINDOW) + @FlaggedApi(FLAG_OVERRIDE_POWER_KEY_BEHAVIOR_IN_FOCUSED_WINDOW) + public boolean isReceivePowerKeyDoublePressEnabled() { + return (inputFeatures + & INPUT_FEATURE_RECEIVE_POWER_KEY_DOUBLE_PRESS) != 0; + } + /** * Specifies that the window should be considered a trusted system overlay. Trusted system * overlays are ignored when considering whether windows are obscured during input @@ -6157,6 +6222,16 @@ public interface WindowManager extends ViewManager { inputFeatures &= ~INPUT_FEATURE_SPY; features.add("INPUT_FEATURE_SPY"); } + if (overridePowerKeyBehaviorInFocusedWindow()) { + if ((inputFeatures + & INPUT_FEATURE_RECEIVE_POWER_KEY_DOUBLE_PRESS) + != 0) { + inputFeatures + &= + ~INPUT_FEATURE_RECEIVE_POWER_KEY_DOUBLE_PRESS; + features.add("INPUT_FEATURE_RECEIVE_POWER_KEY_DOUBLE_PRESS"); + } + } if (inputFeatures != 0) { features.add(Integer.toHexString(inputFeatures)); } diff --git a/core/java/android/view/accessibility/AccessibilityNodeInfo.java b/core/java/android/view/accessibility/AccessibilityNodeInfo.java index df0c5a34e9923d60bfd374e8ba7ffab62a63e870..8a10979eb3c9f03d5d87bf09b1476fabe3980b5f 100644 --- a/core/java/android/view/accessibility/AccessibilityNodeInfo.java +++ b/core/java/android/view/accessibility/AccessibilityNodeInfo.java @@ -6540,6 +6540,15 @@ public class AccessibilityNodeInfo implements Parcelable { * Class with information if a node is a range. */ public static final class RangeInfo { + /** @hide */ + @IntDef(prefix = { "RANGE_TYPE_" }, value = { + RANGE_TYPE_INT, + RANGE_TYPE_FLOAT, + RANGE_TYPE_PERCENT, + RANGE_TYPE_INDETERMINATE + }) + @Retention(RetentionPolicy.SOURCE) + public @interface RangeType {} /** Range type: integer. */ public static final int RANGE_TYPE_INT = 0; @@ -6588,7 +6597,7 @@ public class AccessibilityNodeInfo implements Parcelable { * @param current The current value. */ @Deprecated - public static RangeInfo obtain(int type, float min, float max, float current) { + public static RangeInfo obtain(@RangeType int type, float min, float max, float current) { return new RangeInfo(type, min, max, current); } @@ -6602,7 +6611,7 @@ public class AccessibilityNodeInfo implements Parcelable { * maximum. * @param current The current value. */ - public RangeInfo(int type, float min, float max, float current) { + public RangeInfo(@RangeType int type, float min, float max, float current) { mType = type; mMin = min; mMax = max; @@ -6618,6 +6627,7 @@ public class AccessibilityNodeInfo implements Parcelable { * @see #RANGE_TYPE_FLOAT * @see #RANGE_TYPE_PERCENT */ + @RangeType public int getType() { return mType; } diff --git a/core/java/android/view/autofill/AutofillManager.java b/core/java/android/view/autofill/AutofillManager.java index 1de0474182dd3a4a9df452a1482070fd953fc3c4..60e528c5fb5875224ca7e3f8298425bcf9419f60 100644 --- a/core/java/android/view/autofill/AutofillManager.java +++ b/core/java/android/view/autofill/AutofillManager.java @@ -26,6 +26,7 @@ import static android.service.autofill.FillRequest.FLAG_SUPPORTS_FILL_DIALOG; import static android.service.autofill.FillRequest.FLAG_VIEW_NOT_FOCUSED; import static android.service.autofill.FillRequest.FLAG_VIEW_REQUESTS_CREDMAN_SERVICE; import static android.service.autofill.Flags.FLAG_FILL_DIALOG_IMPROVEMENTS; +import static android.service.autofill.Flags.improveFillDialogAconfig; import static android.service.autofill.Flags.relayoutFix; import static android.view.ContentInfo.SOURCE_AUTOFILL; import static android.view.autofill.Helper.sDebug; @@ -787,6 +788,11 @@ public final class AutofillManager { private AutofillStateFingerprint mAutofillStateFingerprint; + /** + * Whether improveFillDialog feature is enabled or not. + */ + private boolean mImproveFillDialogEnabled; + /** @hide */ public interface AutofillClient { /** @@ -1017,6 +1023,17 @@ public final class AutofillManager { mRelayoutFix = relayoutFix() && AutofillFeatureFlags.enableRelayoutFixes(); mRelativePositionForRelayout = AutofillFeatureFlags.enableRelativeLocationForRelayout(); mIsCredmanIntegrationEnabled = Flags.autofillCredmanIntegration(); + mImproveFillDialogEnabled = + improveFillDialogAconfig() && AutofillFeatureFlags.isImproveFillDialogEnabled(); + } + + /** + * Whether improvement to fill dialog is enabled. + * + * @hide + */ + public boolean isImproveFillDialogEnabled() { + return mImproveFillDialogEnabled; } /** @@ -1679,6 +1696,11 @@ public final class AutofillManager { private void notifyViewReadyInner(AutofillId id, @Nullable String[] autofillHints, boolean isCredmanRequested) { + if (isImproveFillDialogEnabled() && !isCredmanRequested) { + // We do not want to send pre-trigger request. + // TODO(b/377868687): verify if we can remove the flow for isCredmanRequested too. + return; + } if (sDebug) { Log.d(TAG, "notifyViewReadyInner:" + id); } @@ -2045,6 +2067,34 @@ public final class AutofillManager { mEnteredIds.add(id); } + /** + * Notify autofill system that IME animation has started + * @param startTimeMs start time as measured by SystemClock.elapsedRealtime() + */ + void notifyImeAnimationStart(long startTimeMs) { + try { + mService.notifyImeAnimationStart(mSessionId, startTimeMs, mContext.getUserId()); + } catch (RemoteException e) { + // The failure could be a consequence of something going wrong on the + // server side. Just log the exception and move-on. + Log.w(TAG, "notifyImeAnimationStart(): RemoteException caught but ignored " + e); + } + } + + /** + * Notify autofill system that IME animation has ended + * @param endTimeMs end time as measured by SystemClock.elapsedRealtime() + */ + void notifyImeAnimationEnd(long endTimeMs) { + try { + mService.notifyImeAnimationEnd(mSessionId, endTimeMs, mContext.getUserId()); + } catch (RemoteException e) { + // The failure could be a consequence of something going wrong on the + // server side. Just log the exception and move-on. + Log.w(TAG, "notifyImeAnimationStart(): RemoteException caught but ignored " + e); + } + } + /** * Called when a virtual view that supports autofill is exited. * @@ -4050,6 +4100,10 @@ public final class AutofillManager { @FlaggedApi(FLAG_FILL_DIALOG_IMPROVEMENTS) @Deprecated public boolean showAutofillDialog(@NonNull View view) { + if (isImproveFillDialogEnabled()) { + Log.i(TAG, "showAutofillDialog() return false due to improve fill dialog"); + return false; + } Objects.requireNonNull(view); if (shouldShowAutofillDialog(view, view.getAutofillId())) { mShowAutofillDialogCalled = true; @@ -4093,6 +4147,10 @@ public final class AutofillManager { @FlaggedApi(FLAG_FILL_DIALOG_IMPROVEMENTS) @Deprecated public boolean showAutofillDialog(@NonNull View view, int virtualId) { + if (isImproveFillDialogEnabled()) { + Log.i(TAG, "showAutofillDialog() return false due to improve fill dialog"); + return false; + } Objects.requireNonNull(view); if (shouldShowAutofillDialog(view, getAutofillId(view, virtualId))) { mShowAutofillDialogCalled = true; @@ -4117,7 +4175,7 @@ public final class AutofillManager { return false; } - if (getImeStateFlag(view) == FLAG_IME_SHOWING) { + if (getImeStateFlag(view) == FLAG_IME_SHOWING && !isImproveFillDialogEnabled()) { // IME is showing return false; } diff --git a/core/java/android/view/autofill/IAutoFillManager.aidl b/core/java/android/view/autofill/IAutoFillManager.aidl index f67405f7c1e421e137fee7f7ebeb85be9267df5e..28f8577beed79fe5ca435a48b3649e74c7b7bbad 100644 --- a/core/java/android/view/autofill/IAutoFillManager.aidl +++ b/core/java/android/view/autofill/IAutoFillManager.aidl @@ -70,4 +70,6 @@ oneway interface IAutoFillManager { void notifyNotExpiringResponseDuringAuth(int sessionId, int userId); void notifyViewEnteredIgnoredDuringAuthCount(int sessionId, int userId); void setAutofillIdsAttemptedForRefill(int sessionId, in List ids, int userId); + void notifyImeAnimationStart(int sessionId, long startTimeMs, int userId); + void notifyImeAnimationEnd(int sessionId, long endTimeMs, int userId); } diff --git a/core/java/android/view/flags/scroll_capture.aconfig b/core/java/android/view/flags/scroll_capture.aconfig index 9080b1669ed5c487c85b0e0b0218bf962501fea9..6dccbad3b6a98aa29da9a681d1e3a5e5a36f5eb4 100644 --- a/core/java/android/view/flags/scroll_capture.aconfig +++ b/core/java/android/view/flags/scroll_capture.aconfig @@ -11,3 +11,12 @@ flag { } } +flag { + name: "scroll_capture_relax_scroll_view_criteria" + namespace: "systemui" + description: "Treat all custom ViewGroups which support scrollTo as ScrollView" + bug: "189827634" + metadata { + purpose: PURPOSE_BUGFIX + } +} diff --git a/core/java/android/view/flags/scroll_feedback_flags.aconfig b/core/java/android/view/flags/scroll_feedback_flags.aconfig index ebda4d472b0d91b739c6d199d7aafceaf4cc2fdb..ddf6ff11a83a0ca08f9aaa3710d7db7f66354872 100644 --- a/core/java/android/view/flags/scroll_feedback_flags.aconfig +++ b/core/java/android/view/flags/scroll_feedback_flags.aconfig @@ -17,10 +17,10 @@ flag { } flag { - namespace: "toolkit" - name: "enable_touch_scroll_feedback" + namespace: "wear_frameworks" + name: "enable_scroll_feedback_for_touch" description: "Enables touchscreen haptic scroll feedback" - bug: "331830899" + bug: "382135785" is_fixed_read_only: true } diff --git a/core/java/android/view/flags/view_flags.aconfig b/core/java/android/view/flags/view_flags.aconfig index 641b01054acb28e0aa26a730f63731296222f989..f6fdec94c33252d986be7615baa31e4d8a956e3b 100644 --- a/core/java/android/view/flags/view_flags.aconfig +++ b/core/java/android/view/flags/view_flags.aconfig @@ -142,4 +142,12 @@ flag { description: "Recover from buffer stuffing when SurfaceFlinger misses a frame" bug: "294922229" is_fixed_read_only: true -} \ No newline at end of file +} + +flag { + name: "date_time_view_relative_time_display_configs" + namespace: "systemui" + description: "Enables DateTimeView to use additional display configurations for relative time" + bug: "364653005" + is_fixed_read_only: true +} diff --git a/core/java/android/view/inputmethod/InputMethodManager.java b/core/java/android/view/inputmethod/InputMethodManager.java index 5dd29b26730de085ed7e1b80d7bad1b2dc1c94fa..6d89f3d89077881247b5e1adfd119b5b5d3e5fba 100644 --- a/core/java/android/view/inputmethod/InputMethodManager.java +++ b/core/java/android/view/inputmethod/InputMethodManager.java @@ -946,11 +946,16 @@ public final class InputMethodManager { if (state == WindowManager.LayoutParams.SOFT_INPUT_STATE_ALWAYS_HIDDEN) { // when losing focus (e.g., by going to another window), we reset the // requestedVisibleTypes of WindowInsetsController by hiding the IME + final var statsToken = ImeTracker.forLogging().onStart( + ImeTracker.TYPE_HIDE, ImeTracker.ORIGIN_CLIENT, + SoftInputShowHideReason.REASON_HIDE_WINDOW_LOST_FOCUS, + false /* fromUser */); if (DEBUG) { Log.d(TAG, "onWindowLostFocus, hiding IME because " + "of STATE_ALWAYS_HIDDEN"); } - mCurRootView.getInsetsController().hide(WindowInsets.Type.ime()); + mCurRootView.getInsetsController().hide(WindowInsets.Type.ime(), + false /* fromIme */, statsToken); } } diff --git a/core/java/android/view/textclassifier/TextClassificationManager.java b/core/java/android/view/textclassifier/TextClassificationManager.java index b606340b77a748e1eb23f636070031b2c031ee80..b9293242e4ff52c44eedf49b4b6b0d027e9706d2 100644 --- a/core/java/android/view/textclassifier/TextClassificationManager.java +++ b/core/java/android/view/textclassifier/TextClassificationManager.java @@ -16,13 +16,20 @@ package android.view.textclassifier; +import static android.Manifest.permission.ACCESS_TEXT_CLASSIFIER_BY_TYPE; + +import android.annotation.FlaggedApi; import android.annotation.NonNull; import android.annotation.Nullable; +import android.annotation.RequiresPermission; +import android.annotation.SystemApi; import android.annotation.SystemService; import android.compat.annotation.UnsupportedAppUsage; import android.content.Context; +import android.content.pm.PackageManager; import android.os.Build; import android.os.ServiceManager; +import android.permission.flags.Flags; import android.view.textclassifier.TextClassifier.TextClassifierType; import com.android.internal.annotations.GuardedBy; @@ -115,6 +122,29 @@ public final class TextClassificationManager { } } + /** + * Returns a specific type of text classifier. + * If the specified text classifier cannot be found, this returns {@link TextClassifier#NO_OP}. + *

    + * + * @see TextClassifier#CLASSIFIER_TYPE_SELF_PROVIDED + * @see TextClassifier#CLASSIFIER_TYPE_DEVICE_DEFAULT + * @see TextClassifier#CLASSIFIER_TYPE_ANDROID_DEFAULT + * @hide + */ + @SystemApi + @NonNull + @FlaggedApi(Flags.FLAG_TEXT_CLASSIFIER_CHOICE_API_ENABLED) + @RequiresPermission(ACCESS_TEXT_CLASSIFIER_BY_TYPE) + public TextClassifier getClassifier(@TextClassifierType int type) { + if (mContext.checkCallingOrSelfPermission(ACCESS_TEXT_CLASSIFIER_BY_TYPE) + != PackageManager.PERMISSION_GRANTED) { + throw new SecurityException( + "Caller does not have permission " + ACCESS_TEXT_CLASSIFIER_BY_TYPE); + } + return getTextClassifier(type); + } + private TextClassificationConstants getSettings() { synchronized (mLock) { if (mSettings == null) { diff --git a/core/java/android/view/textclassifier/TextClassifier.java b/core/java/android/view/textclassifier/TextClassifier.java index ef5004536354044aa60297481671db8b6adc6fa1..59afdac1bfd702763a58354516db347e0f68816a 100644 --- a/core/java/android/view/textclassifier/TextClassifier.java +++ b/core/java/android/view/textclassifier/TextClassifier.java @@ -16,16 +16,20 @@ package android.view.textclassifier; +import android.annotation.FlaggedApi; import android.annotation.IntDef; import android.annotation.IntRange; import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.StringDef; +import android.annotation.SuppressLint; +import android.annotation.SystemApi; import android.annotation.WorkerThread; import android.os.LocaleList; import android.os.Looper; import android.os.Parcel; import android.os.Parcelable; +import android.permission.flags.Flags; import android.text.Spannable; import android.text.SpannableString; import android.text.style.URLSpan; @@ -63,11 +67,6 @@ public interface TextClassifier { /** @hide */ String LOG_TAG = "androidtc"; - - /** @hide */ - @Retention(RetentionPolicy.SOURCE) - @IntDef(value = {LOCAL, SYSTEM, DEFAULT_SYSTEM}) - @interface TextClassifierType {} // TODO: Expose as system APIs. /** Specifies a TextClassifier that runs locally in the app's process. @hide */ int LOCAL = 0; /** Specifies a TextClassifier that runs in the system process and serves all apps. @hide */ @@ -76,8 +75,33 @@ public interface TextClassifier { int DEFAULT_SYSTEM = 2; /** @hide */ + @Retention(RetentionPolicy.SOURCE) + @IntDef(value = {CLASSIFIER_TYPE_SELF_PROVIDED, CLASSIFIER_TYPE_DEVICE_DEFAULT, + CLASSIFIER_TYPE_ANDROID_DEFAULT}) + @interface TextClassifierType { + } + /** Specifies a TextClassifier that runs locally in the app's process. @hide */ + @FlaggedApi(Flags.FLAG_TEXT_CLASSIFIER_CHOICE_API_ENABLED) + @SystemApi + int CLASSIFIER_TYPE_SELF_PROVIDED = LOCAL; + /** + * Specifies a TextClassifier that is set as the default on this particular device. This may be + * the same as CLASSIFIER_TYPE_DEVICE_DEFAULT, unless set otherwise by the device manufacturer. + * @hide + */ + @FlaggedApi(Flags.FLAG_TEXT_CLASSIFIER_CHOICE_API_ENABLED) + @SystemApi + int CLASSIFIER_TYPE_DEVICE_DEFAULT = SYSTEM; + /** Specifies the TextClassifier that is provided by Android. @hide */ + @FlaggedApi(Flags.FLAG_TEXT_CLASSIFIER_CHOICE_API_ENABLED) + @SystemApi + int CLASSIFIER_TYPE_ANDROID_DEFAULT = DEFAULT_SYSTEM; + + /** @hide */ + @SuppressLint("SwitchIntDef") static String typeToString(@TextClassifierType int type) { - switch (type) { + int unflaggedType = type; + switch (unflaggedType) { case LOCAL: return "Local"; case SYSTEM: @@ -108,6 +132,9 @@ public interface TextClassifier { String TYPE_DATE_TIME = "datetime"; /** Flight number in IATA format. */ String TYPE_FLIGHT_NUMBER = "flight"; + /** Onetime password. */ + @FlaggedApi(Flags.FLAG_TEXT_CLASSIFIER_CHOICE_API_ENABLED) + String TYPE_OTP = "otp"; /** * Word that users may be interested to look up for meaning. * @hide @@ -126,7 +153,8 @@ public interface TextClassifier { TYPE_DATE, TYPE_DATE_TIME, TYPE_FLIGHT_NUMBER, - TYPE_DICTIONARY + TYPE_DICTIONARY, + TYPE_OTP }) @interface EntityType {} @@ -197,6 +225,16 @@ public interface TextClassifier { */ String EXTRA_FROM_TEXT_CLASSIFIER = "android.view.textclassifier.extra.FROM_TEXT_CLASSIFIER"; + /** + * Extra specifying the package name of the app from which the text to be classified originated. + * + * For example, a notification assistant might use TextClassifier, but the notification + * content could originate from a different app. This key allows you to provide + * the package name of that source app. + */ + @FlaggedApi(Flags.FLAG_TEXT_CLASSIFIER_CHOICE_API_ENABLED) + String EXTRA_TEXT_ORIGIN_PACKAGE = "android.view.textclassifier.extra.TEXT_ORIGIN_PACKAGE"; + /** * Returns suggested text selection start and end indices, recognized entity types, and their * associated confidence scores. The entity types are ordered from highest to lowest scoring. diff --git a/core/java/android/webkit/EventLogTags.logtags b/core/java/android/webkit/EventLogTags.logtags index a90aebd71716202dfe2678c5e26894629eb59fa7..8bbd5a9d0246a1bd95080f070d3705bdb995f889 100644 --- a/core/java/android/webkit/EventLogTags.logtags +++ b/core/java/android/webkit/EventLogTags.logtags @@ -1,4 +1,4 @@ -# See system/core/logcat/event.logtags for a description of the format of this file. +# See system/logging/logcat/event.logtags for a description of the format of this file. option java_package android.webkit; diff --git a/core/java/android/widget/AbsListView.java b/core/java/android/widget/AbsListView.java index 3c854ea4fad4a089173e0fada4a5a2d24ec805fe..fc3014a0eaec21d2a73712de981d2d8304b92d83 100644 --- a/core/java/android/widget/AbsListView.java +++ b/core/java/android/widget/AbsListView.java @@ -16,7 +16,7 @@ package android.widget; -import static android.view.flags.Flags.enableTouchScrollFeedback; +import static android.view.flags.Flags.enableScrollFeedbackForTouch; import static android.view.flags.Flags.scrollFeedbackApi; import static android.view.flags.Flags.viewVelocityApi; @@ -3737,7 +3737,7 @@ public abstract class AbsListView extends AdapterView implements Te atEdge = trackMotionScroll(deltaY, incrementalDeltaY); // TODO: b/360198915 - Add unit testing for using ScrollFeedbackProvider - if (enableTouchScrollFeedback()) { + if (vtev != null && enableScrollFeedbackForTouch()) { initHapticScrollFeedbackProviderIfNotExists(); mHapticScrollFeedbackProvider.onScrollProgress( vtev.getDeviceId(), vtev.getSource(), MotionEvent.AXIS_Y, @@ -3779,7 +3779,7 @@ public abstract class AbsListView extends AdapterView implements Te mTouchMode = TOUCH_MODE_OVERSCROLL; } - if (enableTouchScrollFeedback()) { + if (vtev != null && enableScrollFeedbackForTouch()) { initHapticScrollFeedbackProviderIfNotExists(); mHapticScrollFeedbackProvider.onScrollLimit( vtev.getDeviceId(), vtev.getSource(), diff --git a/core/java/android/widget/DateTimeView.java b/core/java/android/widget/DateTimeView.java index 41ff69d6fb5f8a1f9d7c24fb9aee9bf6cbb1baf3..143b4b770984e6179750b11b439f056e32e0f8e1 100644 --- a/core/java/android/widget/DateTimeView.java +++ b/core/java/android/widget/DateTimeView.java @@ -21,6 +21,7 @@ import static android.text.format.DateUtils.HOUR_IN_MILLIS; import static android.text.format.DateUtils.MINUTE_IN_MILLIS; import static android.text.format.DateUtils.YEAR_IN_MILLIS; +import android.annotation.IntDef; import android.app.ActivityThread; import android.compat.annotation.UnsupportedAppUsage; import android.content.BroadcastReceiver; @@ -41,6 +42,8 @@ import android.widget.RemoteViews.RemoteView; import com.android.internal.R; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; import java.text.DateFormat; import java.time.Instant; import java.time.LocalDate; @@ -70,6 +73,23 @@ public class DateTimeView extends TextView { private static final int SHOW_TIME = 0; private static final int SHOW_MONTH_DAY_YEAR = 1; + /** @hide */ + @IntDef(value = {UNIT_DISPLAY_LENGTH_SHORTEST, UNIT_DISPLAY_LENGTH_MEDIUM}) + @Retention(RetentionPolicy.SOURCE) + public @interface UnitDisplayLength {} + public static final int UNIT_DISPLAY_LENGTH_SHORTEST = 0; + public static final int UNIT_DISPLAY_LENGTH_MEDIUM = 1; + + /** @hide */ + @IntDef(flag = true, value = {DISAMBIGUATION_TEXT_PAST, DISAMBIGUATION_TEXT_FUTURE}) + @Retention(RetentionPolicy.SOURCE) + public @interface DisambiguationTextMask {} + public static final int DISAMBIGUATION_TEXT_PAST = 0x01; + public static final int DISAMBIGUATION_TEXT_FUTURE = 0x02; + + private final boolean mCanUseRelativeTimeDisplayConfigs = + android.view.flags.Flags.dateTimeViewRelativeTimeDisplayConfigs(); + private long mTimeMillis; // The LocalDateTime equivalent of mTimeMillis but truncated to minute, i.e. no seconds / nanos. private LocalDateTime mLocalTime; @@ -81,6 +101,8 @@ public class DateTimeView extends TextView { private static final ThreadLocal sReceiverInfo = new ThreadLocal(); private String mNowText; private boolean mShowRelativeTime; + private int mRelativeTimeDisambiguationTextMask; + private int mRelativeTimeUnitDisplayLength = UNIT_DISPLAY_LENGTH_SHORTEST; public DateTimeView(Context context) { this(context, null); @@ -89,20 +111,23 @@ public class DateTimeView extends TextView { @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) public DateTimeView(Context context, AttributeSet attrs) { super(context, attrs); - final TypedArray a = context.obtainStyledAttributes(attrs, - com.android.internal.R.styleable.DateTimeView, 0, - 0); - - final int N = a.getIndexCount(); - for (int i = 0; i < N; i++) { - int attr = a.getIndex(i); - switch (attr) { - case R.styleable.DateTimeView_showRelative: - boolean relative = a.getBoolean(i, false); - setShowRelativeTime(relative); - break; - } + final TypedArray a = context.obtainStyledAttributes( + attrs, R.styleable.DateTimeView, 0, 0); + + setShowRelativeTime(a.getBoolean(R.styleable.DateTimeView_showRelative, false)); + if (mCanUseRelativeTimeDisplayConfigs) { + setRelativeTimeDisambiguationTextMask( + a.getInt( + R.styleable.DateTimeView_relativeTimeDisambiguationText, + // The original implementation showed disambiguation text for future + // times only, so continue with that default. + DISAMBIGUATION_TEXT_FUTURE)); + setRelativeTimeUnitDisplayLength( + a.getInt( + R.styleable.DateTimeView_relativeTimeUnitDisplayLength, + UNIT_DISPLAY_LENGTH_SHORTEST)); } + a.recycle(); } @@ -150,6 +175,29 @@ public class DateTimeView extends TextView { update(); } + /** See {@link R.styleable.DateTimeView_relativeTimeDisambiguationText}. */ + @android.view.RemotableViewMethod + public void setRelativeTimeDisambiguationTextMask( + @DisambiguationTextMask int disambiguationTextMask) { + if (!mCanUseRelativeTimeDisplayConfigs) { + return; + } + mRelativeTimeDisambiguationTextMask = disambiguationTextMask; + updateNowText(); + update(); + } + + /** See {@link R.styleable.DateTimeView_relativeTimeUnitDisplayLength}. */ + @android.view.RemotableViewMethod + public void setRelativeTimeUnitDisplayLength(@UnitDisplayLength int unitDisplayLength) { + if (!mCanUseRelativeTimeDisplayConfigs) { + return; + } + mRelativeTimeUnitDisplayLength = unitDisplayLength; + updateNowText(); + update(); + } + /** * Returns whether this view shows relative time * @@ -264,17 +312,11 @@ public class DateTimeView extends TextView { return; } else if (duration < HOUR_IN_MILLIS) { count = (int)(duration / MINUTE_IN_MILLIS); - result = getContext().getResources().getString(past - ? com.android.internal.R.string.duration_minutes_shortest - : com.android.internal.R.string.duration_minutes_shortest_future, - count); + result = getContext().getResources().getString(getMinutesStringId(past), count); millisIncrease = MINUTE_IN_MILLIS; } else if (duration < DAY_IN_MILLIS) { count = (int)(duration / HOUR_IN_MILLIS); - result = getContext().getResources().getString(past - ? com.android.internal.R.string.duration_hours_shortest - : com.android.internal.R.string.duration_hours_shortest_future, - count); + result = getContext().getResources().getString(getHoursStringId(past), count); millisIncrease = HOUR_IN_MILLIS; } else if (duration < YEAR_IN_MILLIS) { // In weird cases it can become 0 because of daylight savings @@ -283,10 +325,7 @@ public class DateTimeView extends TextView { LocalDateTime localNow = toLocalDateTime(now, zoneId); count = Math.max(Math.abs(dayDistance(localDateTime, localNow)), 1); - result = getContext().getResources().getString(past - ? com.android.internal.R.string.duration_days_shortest - : com.android.internal.R.string.duration_days_shortest_future, - count); + result = getContext().getResources().getString(getDaysStringId(past), count); if (past || count != 1) { mUpdateTimeMillis = computeNextMidnight(localNow, zoneId); millisIncrease = -1; @@ -296,10 +335,7 @@ public class DateTimeView extends TextView { } else { count = (int)(duration / YEAR_IN_MILLIS); - result = getContext().getResources().getString(past - ? com.android.internal.R.string.duration_years_shortest - : com.android.internal.R.string.duration_years_shortest_future, - count); + result = getContext().getResources().getString(getYearsStringId(past), count); millisIncrease = YEAR_IN_MILLIS; } if (millisIncrease != -1) { @@ -312,6 +348,139 @@ public class DateTimeView extends TextView { maybeSetText(result); } + private int getMinutesStringId(boolean past) { + if (!mCanUseRelativeTimeDisplayConfigs) { + return past + ? com.android.internal.R.string.duration_minutes_shortest + : com.android.internal.R.string.duration_minutes_shortest_future; + } + + if (mRelativeTimeUnitDisplayLength == UNIT_DISPLAY_LENGTH_SHORTEST) { + if (past && (mRelativeTimeDisambiguationTextMask & DISAMBIGUATION_TEXT_PAST) != 0) { + // "1m ago" + return com.android.internal.R.string.duration_minutes_shortest_past; + } else if (!past + && (mRelativeTimeDisambiguationTextMask & DISAMBIGUATION_TEXT_FUTURE) != 0) { + // "in 1m" + return com.android.internal.R.string.duration_minutes_shortest_future; + } else { + // "1m" + return com.android.internal.R.string.duration_minutes_shortest; + } + } else { // UNIT_DISPLAY_LENGTH_MEDIUM + if (past && (mRelativeTimeDisambiguationTextMask & DISAMBIGUATION_TEXT_PAST) != 0) { + // "1min ago" + return com.android.internal.R.string.duration_minutes_medium_past; + } else if (!past + && (mRelativeTimeDisambiguationTextMask & DISAMBIGUATION_TEXT_FUTURE) != 0) { + // "in 1min" + return com.android.internal.R.string.duration_minutes_medium_future; + } else { + // "1min" + return com.android.internal.R.string.duration_minutes_medium; + } + } + } + + private int getHoursStringId(boolean past) { + if (!mCanUseRelativeTimeDisplayConfigs) { + return past + ? com.android.internal.R.string.duration_hours_shortest + : com.android.internal.R.string.duration_hours_shortest_future; + } + if (mRelativeTimeUnitDisplayLength == UNIT_DISPLAY_LENGTH_SHORTEST) { + if (past && (mRelativeTimeDisambiguationTextMask & DISAMBIGUATION_TEXT_PAST) != 0) { + // "1h ago" + return com.android.internal.R.string.duration_hours_shortest_past; + } else if (!past + && (mRelativeTimeDisambiguationTextMask & DISAMBIGUATION_TEXT_FUTURE) != 0) { + // "in 1h" + return com.android.internal.R.string.duration_hours_shortest_future; + } else { + // "1h" + return com.android.internal.R.string.duration_hours_shortest; + } + } else { // UNIT_DISPLAY_LENGTH_MEDIUM + if (past && (mRelativeTimeDisambiguationTextMask & DISAMBIGUATION_TEXT_PAST) != 0) { + // "1hr ago" + return com.android.internal.R.string.duration_hours_medium_past; + } else if (!past + && (mRelativeTimeDisambiguationTextMask & DISAMBIGUATION_TEXT_FUTURE) != 0) { + // "in 1hr" + return com.android.internal.R.string.duration_hours_medium_future; + } else { + // "1hr" + return com.android.internal.R.string.duration_hours_medium; + } + } + } + + private int getDaysStringId(boolean past) { + if (!mCanUseRelativeTimeDisplayConfigs) { + return past + ? com.android.internal.R.string.duration_days_shortest + : com.android.internal.R.string.duration_days_shortest_future; + } + if (mRelativeTimeUnitDisplayLength == UNIT_DISPLAY_LENGTH_SHORTEST) { + if (past && (mRelativeTimeDisambiguationTextMask & DISAMBIGUATION_TEXT_PAST) != 0) { + // "1d ago" + return com.android.internal.R.string.duration_days_shortest_past; + } else if (!past + && (mRelativeTimeDisambiguationTextMask & DISAMBIGUATION_TEXT_FUTURE) != 0) { + // "in 1d" + return com.android.internal.R.string.duration_days_shortest_future; + } else { + // "1d" + return com.android.internal.R.string.duration_days_shortest; + } + } else { // UNIT_DISPLAY_LENGTH_MEDIUM + if (past && (mRelativeTimeDisambiguationTextMask & DISAMBIGUATION_TEXT_PAST) != 0) { + // "1d ago" + return com.android.internal.R.string.duration_days_medium_past; + } else if (!past + && (mRelativeTimeDisambiguationTextMask & DISAMBIGUATION_TEXT_FUTURE) != 0) { + // "in 1d" + return com.android.internal.R.string.duration_days_medium_future; + } else { + // "1d" + return com.android.internal.R.string.duration_days_medium; + } + } + } + + private int getYearsStringId(boolean past) { + if (!mCanUseRelativeTimeDisplayConfigs) { + return past + ? com.android.internal.R.string.duration_years_shortest + : com.android.internal.R.string.duration_years_shortest_future; + } + if (mRelativeTimeUnitDisplayLength == UNIT_DISPLAY_LENGTH_SHORTEST) { + if (past && (mRelativeTimeDisambiguationTextMask & DISAMBIGUATION_TEXT_PAST) != 0) { + // "1y ago" + return com.android.internal.R.string.duration_years_shortest_past; + } else if (!past + && (mRelativeTimeDisambiguationTextMask & DISAMBIGUATION_TEXT_FUTURE) != 0) { + // "in 1y" + return com.android.internal.R.string.duration_years_shortest_future; + } else { + // "1y" + return com.android.internal.R.string.duration_years_shortest; + } + } else { // UNIT_DISPLAY_LENGTH_MEDIUM + if (past && (mRelativeTimeDisambiguationTextMask & DISAMBIGUATION_TEXT_PAST) != 0) { + // "1y ago" + return com.android.internal.R.string.duration_years_medium_past; + } else if (!past + && (mRelativeTimeDisambiguationTextMask & DISAMBIGUATION_TEXT_FUTURE) != 0) { + // "in 1y" + return com.android.internal.R.string.duration_years_medium_future; + } else { + // "1y" + return com.android.internal.R.string.duration_years_medium; + } + } + } + /** * Sets text only if the text has actually changed. This prevents needles relayouts of this * view when set to wrap_content. diff --git a/core/java/android/widget/RemoteViews.java b/core/java/android/widget/RemoteViews.java index 7e3b904444292ac97eadffa861c77794d9fe94ae..9c2833b91a2b85f01ae4342aed5aeed33e6a0c57 100644 --- a/core/java/android/widget/RemoteViews.java +++ b/core/java/android/widget/RemoteViews.java @@ -47,6 +47,7 @@ import android.app.LoadedApk; import android.app.PendingIntent; import android.app.RemoteInput; import android.appwidget.AppWidgetHostView; +import android.appwidget.AppWidgetManager.ServiceCollectionCache; import android.appwidget.flags.Flags; import android.compat.annotation.UnsupportedAppUsage; import android.content.ComponentName; @@ -54,7 +55,6 @@ import android.content.Context; import android.content.ContextWrapper; import android.content.Intent; import android.content.IntentSender; -import android.content.ServiceConnection; import android.content.om.FabricatedOverlay; import android.content.om.OverlayInfo; import android.content.om.OverlayManager; @@ -82,7 +82,6 @@ import android.os.Binder; import android.os.Build; import android.os.Bundle; import android.os.CancellationSignal; -import android.os.IBinder; import android.os.Parcel; import android.os.ParcelFileDescriptor; import android.os.Parcelable; @@ -127,6 +126,7 @@ import android.widget.CompoundButton.OnCheckedChangeListener; import com.android.internal.R; import com.android.internal.util.Preconditions; import com.android.internal.widget.IRemoteViewsFactory; +import com.android.internal.widget.remotecompose.core.CoreDocument; import com.android.internal.widget.remotecompose.core.operations.Theme; import com.android.internal.widget.remotecompose.player.RemoteComposeDocument; import com.android.internal.widget.remotecompose.player.RemoteComposePlayer; @@ -1390,8 +1390,10 @@ public class RemoteViews implements Parcelable, Filter { /** * @hide */ - public CompletableFuture collectAllIntents(int bitmapSizeLimit) { - return mCollectionCache.collectAllIntentsNoComplete(this, bitmapSizeLimit); + public CompletableFuture collectAllIntents(int bitmapSizeLimit, + @NonNull ServiceCollectionCache collectionCache) { + return mCollectionCache.collectAllIntentsNoComplete(this, bitmapSizeLimit, + collectionCache); } private class RemoteCollectionCache { @@ -1445,7 +1447,8 @@ public class RemoteViews implements Parcelable, Filter { } public @NonNull CompletableFuture collectAllIntentsNoComplete( - @NonNull RemoteViews inViews, int bitmapSizeLimit) { + @NonNull RemoteViews inViews, int bitmapSizeLimit, + @NonNull ServiceCollectionCache collectionCache) { SparseArray idToIntentMapping = new SparseArray<>(); // Collect the number of uinque Intent (which is equal to the number of new connections // to make) for size allocation and exclude certain collections from being written to @@ -1477,7 +1480,7 @@ public class RemoteViews implements Parcelable, Filter { / numOfIntents; return connectAllUniqueIntents(individualSize, individualBitmapSizeLimit, - idToIntentMapping); + idToIntentMapping, collectionCache); } private void collectAllIntentsInternal(@NonNull RemoteViews inViews, @@ -1543,13 +1546,14 @@ public class RemoteViews implements Parcelable, Filter { } private @NonNull CompletableFuture connectAllUniqueIntents(int individualSize, - int individualBitmapSize, @NonNull SparseArray idToIntentMapping) { + int individualBitmapSize, @NonNull SparseArray idToIntentMapping, + @NonNull ServiceCollectionCache collectionCache) { List> intentFutureList = new ArrayList<>(); for (int i = 0; i < idToIntentMapping.size(); i++) { String currentIntentUri = mIdToUriMapping.get(idToIntentMapping.keyAt(i)); Intent currentIntent = idToIntentMapping.valueAt(i); intentFutureList.add(getItemsFutureFromIntentWithTimeout(currentIntent, - individualSize, individualBitmapSize) + individualSize, individualBitmapSize, collectionCache) .thenAccept(items -> { items.setHierarchyRootData(getHierarchyRootData()); mUriToCollectionMapping.put(currentIntentUri, items); @@ -1560,7 +1564,8 @@ public class RemoteViews implements Parcelable, Filter { } private static CompletableFuture getItemsFutureFromIntentWithTimeout( - Intent intent, int individualSize, int individualBitmapSize) { + Intent intent, int individualSize, int individualBitmapSize, + @NonNull ServiceCollectionCache collectionCache) { if (intent == null) { Log.e(LOG_TAG, "Null intent received when generating adapter future"); return CompletableFuture.completedFuture(new RemoteCollectionItems @@ -1580,39 +1585,24 @@ public class RemoteViews implements Parcelable, Filter { return result; } - context.bindService(intent, Context.BindServiceFlags.of(Context.BIND_AUTO_CREATE), - result.defaultExecutor(), new ServiceConnection() { - @Override - public void onServiceConnected(ComponentName componentName, - IBinder iBinder) { - RemoteCollectionItems items; - try { - items = IRemoteViewsFactory.Stub.asInterface(iBinder) - .getRemoteCollectionItems(individualSize, - individualBitmapSize); - } catch (RemoteException re) { - items = new RemoteCollectionItems.Builder().build(); - Log.e(LOG_TAG, "Error getting collection items from the" - + " factory", re); - } finally { - context.unbindService(this); - } - - if (items == null) { - items = new RemoteCollectionItems.Builder().build(); - } - - result.complete(items); - } + collectionCache.connectAndConsume(intent, iBinder -> { + RemoteCollectionItems items; + try { + items = IRemoteViewsFactory.Stub.asInterface(iBinder) + .getRemoteCollectionItems(individualSize, + individualBitmapSize); + } catch (RemoteException re) { + items = new RemoteCollectionItems.Builder().build(); + Log.e(LOG_TAG, "Error getting collection items from the" + + " factory", re); + } - @Override - public void onNullBinding(ComponentName name) { - context.unbindService(this); - } + if (items == null) { + items = new RemoteCollectionItems.Builder().build(); + } - @Override - public void onServiceDisconnected(ComponentName componentName) { } - }); + result.complete(items); + }, result.defaultExecutor()); result.completeOnTimeout( new RemoteCollectionItems.Builder().build(), @@ -5825,7 +5815,7 @@ public class RemoteViews implements Parcelable, Filter { } try (ByteArrayInputStream is = new ByteArrayInputStream(bytes.get(0))) { player.setDocument(new RemoteComposeDocument(is)); - player.addClickListener((viewId, metadata) -> { + player.addIdActionListener((viewId, metadata) -> { mActions.forEach(action -> { if (viewId == action.mViewId && action instanceof SetOnClickResponse setOnClickResponse) { @@ -9829,7 +9819,7 @@ public class RemoteViews implements Parcelable, Filter { */ @FlaggedApi(FLAG_DRAW_DATA_PARCEL) public static long getSupportedVersion() { - return VERSION; + return (long) CoreDocument.getDocumentApiLevel(); } /** diff --git a/core/java/android/widget/ScrollView.java b/core/java/android/widget/ScrollView.java index 511c832a4876ff7e71652fe1b85d2a19967315b7..184933fb8288bb081e863a5883702ee49fe7d46c 100644 --- a/core/java/android/widget/ScrollView.java +++ b/core/java/android/widget/ScrollView.java @@ -16,7 +16,7 @@ package android.widget; -import static android.view.flags.Flags.enableTouchScrollFeedback; +import static android.view.flags.Flags.enableScrollFeedbackForTouch; import static android.view.flags.Flags.viewVelocityApi; import android.annotation.ColorInt; @@ -909,7 +909,7 @@ public class ScrollView extends FrameLayout { } // TODO: b/360198915 - Add unit tests. - if (enableTouchScrollFeedback()) { + if (enableScrollFeedbackForTouch()) { if (hitTopLimit || hitBottomLimit) { initHapticScrollFeedbackProviderIfNotExists(); mHapticScrollFeedbackProvider.onScrollLimit(vtev.getDeviceId(), diff --git a/core/java/android/widget/TextView.java b/core/java/android/widget/TextView.java index d7750bd412a3790dce7a04f3eb9009a1d4518dbe..71a832d84f08a9be1543e166c6a715806eddba75 100644 --- a/core/java/android/widget/TextView.java +++ b/core/java/android/widget/TextView.java @@ -18,6 +18,7 @@ package android.widget; import static android.Manifest.permission.INTERACT_ACROSS_USERS_FULL; import static android.content.res.Configuration.ORIENTATION_PORTRAIT; +import static android.graphics.Paint.NEW_FONT_VARIATION_MANAGEMENT; import static android.view.ContentInfo.FLAG_CONVERT_TO_PLAIN_TEXT; import static android.view.ContentInfo.SOURCE_AUTOFILL; import static android.view.ContentInfo.SOURCE_CLIPBOARD; @@ -5542,7 +5543,21 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener && fontVariationSettings.equals(existingSettings))) { return true; } - boolean effective = mTextPaint.setFontVariationSettings(fontVariationSettings); + + final boolean useFontVariationStore = Flags.typefaceRedesignReadonly() + && CompatChanges.isChangeEnabled(NEW_FONT_VARIATION_MANAGEMENT); + boolean effective; + if (useFontVariationStore) { + if (mFontWeightAdjustment != 0 + && mFontWeightAdjustment != Configuration.FONT_WEIGHT_ADJUSTMENT_UNDEFINED) { + mTextPaint.setFontVariationSettings(fontVariationSettings, mFontWeightAdjustment); + } else { + mTextPaint.setFontVariationSettings(fontVariationSettings); + } + effective = true; + } else { + effective = mTextPaint.setFontVariationSettings(fontVariationSettings); + } if (effective && mLayout != null) { nullLayouts(); @@ -10114,6 +10129,10 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener outAttrs.extras.putBoolean( STYLUS_HANDWRITING_ENABLED_ANDROIDX_EXTRAS_KEY, handwritingEnabled); } + if (android.view.inputmethod.Flags.writingTools()) { + // default to same behavior as isSuggestionsEnabled(). + outAttrs.setWritingToolsEnabled(isSuggestionsEnabled()); + } ArrayList> gestures = new ArrayList<>(); gestures.add(SelectGesture.class); gestures.add(SelectRangeGesture.class); diff --git a/core/java/android/window/SystemPerformanceHinter.java b/core/java/android/window/SystemPerformanceHinter.java index cc2329fc47cb475e907462c1c190c4a43bee6a1c..f8899c5764aa83a0f2eabe990f0da6557db4cba1 100644 --- a/core/java/android/window/SystemPerformanceHinter.java +++ b/core/java/android/window/SystemPerformanceHinter.java @@ -163,7 +163,6 @@ public class SystemPerformanceHinter { // The active sessions private final ArrayList mActiveSessions = new ArrayList<>(); private final SurfaceControl.Transaction mTransaction; - private final PerformanceHintManager mPerfHintManager; private @Nullable PerformanceHintManager.Session mAdpfSession; private @Nullable DisplayRootProvider mDisplayRootProvider; @@ -184,7 +183,6 @@ public class SystemPerformanceHinter { @Nullable DisplayRootProvider displayRootProvider, @Nullable Supplier transactionSupplier) { mDisplayRootProvider = displayRootProvider; - mPerfHintManager = context.getSystemService(PerformanceHintManager.class); mTransaction = transactionSupplier != null ? transactionSupplier.get() : new SurfaceControl.Transaction(); @@ -273,7 +271,7 @@ public class SystemPerformanceHinter { asyncTraceBegin(HINT_SF_EARLY_WAKEUP, Display.INVALID_DISPLAY); } } - if (nowEnabled(oldGlobalFlags, newGlobalFlags, HINT_ADPF)) { + if (mAdpfSession != null && nowEnabled(oldGlobalFlags, newGlobalFlags, HINT_ADPF)) { mAdpfSession.sendHint(PerformanceHintManager.Session.CPU_LOAD_UP); if (isTraceEnabled) { asyncTraceBegin(HINT_ADPF, Display.INVALID_DISPLAY); @@ -323,7 +321,7 @@ public class SystemPerformanceHinter { asyncTraceEnd(HINT_SF_EARLY_WAKEUP); } } - if (nowDisabled(oldGlobalFlags, newGlobalFlags, HINT_ADPF)) { + if (mAdpfSession != null && nowDisabled(oldGlobalFlags, newGlobalFlags, HINT_ADPF)) { mAdpfSession.sendHint(PerformanceHintManager.Session.CPU_LOAD_RESET); if (isTraceEnabled) { asyncTraceEnd(HINT_ADPF); diff --git a/core/java/android/window/TransitionRequestInfo.java b/core/java/android/window/TransitionRequestInfo.java index fe936f77de073109322be43c5bcd18be60f8a993..f42c0ec5ee7c0d54e01425bb4c85bfd7239adc6e 100644 --- a/core/java/android/window/TransitionRequestInfo.java +++ b/core/java/android/window/TransitionRequestInfo.java @@ -44,10 +44,10 @@ public final class TransitionRequestInfo implements Parcelable { private @Nullable ActivityManager.RunningTaskInfo mTriggerTask; /** - * If non-null, the task containing the pip activity that participates in this - * transition. + * If non-null, this request might lead to a PiP transition; {@code PipChange} caches both + * {@code TaskFragment} token and the {@code TaskInfo} of the task with PiP candidate activity. */ - private @Nullable ActivityManager.RunningTaskInfo mPipTask; + private @Nullable TransitionRequestInfo.PipChange mPipChange; /** If non-null, a remote-transition associated with the source of this transition. */ private @Nullable RemoteTransition mRemoteTransition; @@ -70,7 +70,7 @@ public final class TransitionRequestInfo implements Parcelable { @WindowManager.TransitionType int type, @Nullable ActivityManager.RunningTaskInfo triggerTask, @Nullable RemoteTransition remoteTransition) { - this(type, triggerTask, null /* pipTask */, + this(type, triggerTask, null /* pipChange */, remoteTransition, null /* displayChange */, 0 /* flags */, -1 /* debugId */); } @@ -80,7 +80,7 @@ public final class TransitionRequestInfo implements Parcelable { @Nullable ActivityManager.RunningTaskInfo triggerTask, @Nullable RemoteTransition remoteTransition, int flags) { - this(type, triggerTask, null /* pipTask */, + this(type, triggerTask, null /* pipChange */, remoteTransition, null /* displayChange */, flags, -1 /* debugId */); } @@ -91,7 +91,7 @@ public final class TransitionRequestInfo implements Parcelable { @Nullable RemoteTransition remoteTransition, @Nullable TransitionRequestInfo.DisplayChange displayChange, int flags) { - this(type, triggerTask, null /* pipTask */, remoteTransition, displayChange, flags, + this(type, triggerTask, null /* pipChange */, remoteTransition, displayChange, flags, -1 /* debugId */); } @@ -103,7 +103,9 @@ public final class TransitionRequestInfo implements Parcelable { @Nullable RemoteTransition remoteTransition, @Nullable TransitionRequestInfo.DisplayChange displayChange, int flags) { - this(type, triggerTask, pipTask, remoteTransition, displayChange, flags, -1 /* debugId */); + this(type, triggerTask, + pipTask != null ? new TransitionRequestInfo.PipChange(pipTask) : null, + remoteTransition, displayChange, flags, -1 /* debugId */); } /** @hide */ @@ -252,7 +254,7 @@ public final class TransitionRequestInfo implements Parcelable { /** @hide */ @SuppressWarnings({"unchecked", "RedundantCast"}) @DataClass.Generated.Member - protected DisplayChange(@android.annotation.NonNull android.os.Parcel in) { + /* package-private */ DisplayChange(@android.annotation.NonNull android.os.Parcel in) { // You can override field unparcelling by defining methods like: // static FieldType unparcelFieldName(Parcel in) { ... } @@ -289,7 +291,7 @@ public final class TransitionRequestInfo implements Parcelable { }; @DataClass.Generated( - time = 1697564781403L, + time = 1733334462577L, codegenVersion = "1.0.23", sourceFile = "frameworks/base/core/java/android/window/TransitionRequestInfo.java", inputSignatures = "private final int mDisplayId\nprivate @android.annotation.Nullable android.graphics.Rect mStartAbsBounds\nprivate @android.annotation.Nullable android.graphics.Rect mEndAbsBounds\nprivate int mStartRotation\nprivate int mEndRotation\nprivate boolean mPhysicalDisplayChanged\nclass DisplayChange extends java.lang.Object implements [android.os.Parcelable]\n@com.android.internal.util.DataClass(genToString=true, genSetters=true, genBuilder=false, genConstructor=false)") @@ -302,6 +304,143 @@ public final class TransitionRequestInfo implements Parcelable { } + @DataClass(genToString = true, genSetters = true, genBuilder = false, genConstructor = false) + public static final class PipChange implements Parcelable { + // In AE case, we might care about the TF token instead of the task token. + @android.annotation.NonNull + private WindowContainerToken mTaskFragmentToken; + + @android.annotation.NonNull + private ActivityManager.RunningTaskInfo mTaskInfo; + + /** Create empty display-change. */ + public PipChange(ActivityManager.RunningTaskInfo taskInfo) { + mTaskFragmentToken = taskInfo.token; + mTaskInfo = taskInfo; + } + + /** Create a display-change representing a rotation. */ + public PipChange(WindowContainerToken taskFragmentToken, + ActivityManager.RunningTaskInfo taskInfo) { + mTaskFragmentToken = taskFragmentToken; + mTaskInfo = taskInfo; + } + + + + // Code below generated by codegen v1.0.23. + // + // DO NOT MODIFY! + // CHECKSTYLE:OFF Generated code + // + // To regenerate run: + // $ codegen $ANDROID_BUILD_TOP/frameworks/base/core/java/android/window/TransitionRequestInfo.java + // + // To exclude the generated code from IntelliJ auto-formatting enable (one-time): + // Settings > Editor > Code Style > Formatter Control + //@formatter:off + + + @DataClass.Generated.Member + public @android.annotation.NonNull WindowContainerToken getTaskFragmentToken() { + return mTaskFragmentToken; + } + + @DataClass.Generated.Member + public @android.annotation.NonNull ActivityManager.RunningTaskInfo getTaskInfo() { + return mTaskInfo; + } + + @DataClass.Generated.Member + public @android.annotation.NonNull PipChange setTaskFragmentToken(@android.annotation.NonNull WindowContainerToken value) { + mTaskFragmentToken = value; + com.android.internal.util.AnnotationValidations.validate( + android.annotation.NonNull.class, null, mTaskFragmentToken); + return this; + } + + @DataClass.Generated.Member + public @android.annotation.NonNull PipChange setTaskInfo(@android.annotation.NonNull ActivityManager.RunningTaskInfo value) { + mTaskInfo = value; + com.android.internal.util.AnnotationValidations.validate( + android.annotation.NonNull.class, null, mTaskInfo); + return this; + } + + @Override + @DataClass.Generated.Member + public String toString() { + // You can override field toString logic by defining methods like: + // String fieldNameToString() { ... } + + return "PipChange { " + + "taskFragmentToken = " + mTaskFragmentToken + ", " + + "taskInfo = " + mTaskInfo + + " }"; + } + + @Override + @DataClass.Generated.Member + public void writeToParcel(@android.annotation.NonNull android.os.Parcel dest, int flags) { + // You can override field parcelling by defining methods like: + // void parcelFieldName(Parcel dest, int flags) { ... } + + dest.writeTypedObject(mTaskFragmentToken, flags); + dest.writeTypedObject(mTaskInfo, flags); + } + + @Override + @DataClass.Generated.Member + public int describeContents() { return 0; } + + /** @hide */ + @SuppressWarnings({"unchecked", "RedundantCast"}) + @DataClass.Generated.Member + /* package-private */ PipChange(@android.annotation.NonNull android.os.Parcel in) { + // You can override field unparcelling by defining methods like: + // static FieldType unparcelFieldName(Parcel in) { ... } + + WindowContainerToken taskFragmentToken = (WindowContainerToken) in.readTypedObject(WindowContainerToken.CREATOR); + ActivityManager.RunningTaskInfo taskInfo = (ActivityManager.RunningTaskInfo) in.readTypedObject(ActivityManager.RunningTaskInfo.CREATOR); + + this.mTaskFragmentToken = taskFragmentToken; + com.android.internal.util.AnnotationValidations.validate( + android.annotation.NonNull.class, null, mTaskFragmentToken); + this.mTaskInfo = taskInfo; + com.android.internal.util.AnnotationValidations.validate( + android.annotation.NonNull.class, null, mTaskInfo); + + // onConstructed(); // You can define this method to get a callback + } + + @DataClass.Generated.Member + public static final @android.annotation.NonNull Parcelable.Creator CREATOR + = new Parcelable.Creator() { + @Override + public PipChange[] newArray(int size) { + return new PipChange[size]; + } + + @Override + public PipChange createFromParcel(@android.annotation.NonNull android.os.Parcel in) { + return new PipChange(in); + } + }; + + @DataClass.Generated( + time = 1733334462588L, + codegenVersion = "1.0.23", + sourceFile = "frameworks/base/core/java/android/window/TransitionRequestInfo.java", + inputSignatures = "private @android.annotation.NonNull android.window.WindowContainerToken mTaskFragmentToken\nprivate @android.annotation.NonNull android.app.ActivityManager.RunningTaskInfo mTaskInfo\nclass PipChange extends java.lang.Object implements [android.os.Parcelable]\n@com.android.internal.util.DataClass(genToString=true, genSetters=true, genBuilder=false, genConstructor=false)") + @Deprecated + private void __metadata() {} + + + //@formatter:on + // End of generated code + + } + @@ -326,9 +465,9 @@ public final class TransitionRequestInfo implements Parcelable { * @param triggerTask * If non-null, the task containing the activity whose lifecycle change (start or * finish) has caused this transition to occur. - * @param pipTask - * If non-null, the task containing the pip activity that participates in this - * transition. + * @param pipChange + * If non-null, this request might lead to a PiP transition; {@code PipChange} caches both + * {@code TaskFragment} token and the {@code TaskInfo} of the task with PiP candidate activity. * @param remoteTransition * If non-null, a remote-transition associated with the source of this transition. * @param displayChange @@ -344,7 +483,7 @@ public final class TransitionRequestInfo implements Parcelable { public TransitionRequestInfo( @WindowManager.TransitionType int type, @Nullable ActivityManager.RunningTaskInfo triggerTask, - @Nullable ActivityManager.RunningTaskInfo pipTask, + @Nullable TransitionRequestInfo.PipChange pipChange, @Nullable RemoteTransition remoteTransition, @Nullable TransitionRequestInfo.DisplayChange displayChange, int flags, @@ -353,7 +492,7 @@ public final class TransitionRequestInfo implements Parcelable { com.android.internal.util.AnnotationValidations.validate( WindowManager.TransitionType.class, null, mType); this.mTriggerTask = triggerTask; - this.mPipTask = pipTask; + this.mPipChange = pipChange; this.mRemoteTransition = remoteTransition; this.mDisplayChange = displayChange; this.mFlags = flags; @@ -380,12 +519,12 @@ public final class TransitionRequestInfo implements Parcelable { } /** - * If non-null, the task containing the pip activity that participates in this - * transition. + * If non-null, this request might lead to a PiP transition; {@code PipChange} caches both + * {@code TaskFragment} token and the {@code TaskInfo} of the task with PiP candidate activity. */ @DataClass.Generated.Member - public @Nullable ActivityManager.RunningTaskInfo getPipTask() { - return mPipTask; + public @Nullable TransitionRequestInfo.PipChange getPipChange() { + return mPipChange; } /** @@ -433,12 +572,12 @@ public final class TransitionRequestInfo implements Parcelable { } /** - * If non-null, the task containing the pip activity that participates in this - * transition. + * If non-null, this request might lead to a PiP transition; {@code PipChange} caches both + * {@code TaskFragment} token and the {@code TaskInfo} of the task with PiP candidate activity. */ @DataClass.Generated.Member - public @android.annotation.NonNull TransitionRequestInfo setPipTask(@android.annotation.NonNull ActivityManager.RunningTaskInfo value) { - mPipTask = value; + public @android.annotation.NonNull TransitionRequestInfo setPipChange(@android.annotation.NonNull TransitionRequestInfo.PipChange value) { + mPipChange = value; return this; } @@ -471,10 +610,10 @@ public final class TransitionRequestInfo implements Parcelable { return "TransitionRequestInfo { " + "type = " + typeToString() + ", " + "triggerTask = " + mTriggerTask + ", " + - "pipTask = " + mPipTask + ", " + + "pipChange = " + mPipChange + ", " + "remoteTransition = " + mRemoteTransition + ", " + "displayChange = " + mDisplayChange + ", " + - "flags = " + Integer.toHexString(mFlags) + ", " + + "flags = " + mFlags + ", " + "debugId = " + mDebugId + " }"; } @@ -487,13 +626,13 @@ public final class TransitionRequestInfo implements Parcelable { byte flg = 0; if (mTriggerTask != null) flg |= 0x2; - if (mPipTask != null) flg |= 0x4; + if (mPipChange != null) flg |= 0x4; if (mRemoteTransition != null) flg |= 0x8; if (mDisplayChange != null) flg |= 0x10; dest.writeByte(flg); dest.writeInt(mType); if (mTriggerTask != null) dest.writeTypedObject(mTriggerTask, flags); - if (mPipTask != null) dest.writeTypedObject(mPipTask, flags); + if (mPipChange != null) dest.writeTypedObject(mPipChange, flags); if (mRemoteTransition != null) dest.writeTypedObject(mRemoteTransition, flags); if (mDisplayChange != null) dest.writeTypedObject(mDisplayChange, flags); dest.writeInt(mFlags); @@ -514,7 +653,7 @@ public final class TransitionRequestInfo implements Parcelable { byte flg = in.readByte(); int type = in.readInt(); ActivityManager.RunningTaskInfo triggerTask = (flg & 0x2) == 0 ? null : (ActivityManager.RunningTaskInfo) in.readTypedObject(ActivityManager.RunningTaskInfo.CREATOR); - ActivityManager.RunningTaskInfo pipTask = (flg & 0x4) == 0 ? null : (ActivityManager.RunningTaskInfo) in.readTypedObject(ActivityManager.RunningTaskInfo.CREATOR); + TransitionRequestInfo.PipChange pipChange = (flg & 0x4) == 0 ? null : (TransitionRequestInfo.PipChange) in.readTypedObject(TransitionRequestInfo.PipChange.CREATOR); RemoteTransition remoteTransition = (flg & 0x8) == 0 ? null : (RemoteTransition) in.readTypedObject(RemoteTransition.CREATOR); TransitionRequestInfo.DisplayChange displayChange = (flg & 0x10) == 0 ? null : (TransitionRequestInfo.DisplayChange) in.readTypedObject(TransitionRequestInfo.DisplayChange.CREATOR); int flags = in.readInt(); @@ -524,7 +663,7 @@ public final class TransitionRequestInfo implements Parcelable { com.android.internal.util.AnnotationValidations.validate( WindowManager.TransitionType.class, null, mType); this.mTriggerTask = triggerTask; - this.mPipTask = pipTask; + this.mPipChange = pipChange; this.mRemoteTransition = remoteTransition; this.mDisplayChange = displayChange; this.mFlags = flags; @@ -548,10 +687,10 @@ public final class TransitionRequestInfo implements Parcelable { }; @DataClass.Generated( - time = 1697564781438L, + time = 1733334462604L, codegenVersion = "1.0.23", sourceFile = "frameworks/base/core/java/android/window/TransitionRequestInfo.java", - inputSignatures = "private final @android.view.WindowManager.TransitionType int mType\nprivate @android.annotation.Nullable android.app.ActivityManager.RunningTaskInfo mTriggerTask\nprivate @android.annotation.Nullable android.app.ActivityManager.RunningTaskInfo mPipTask\nprivate @android.annotation.Nullable android.window.RemoteTransition mRemoteTransition\nprivate @android.annotation.Nullable android.window.TransitionRequestInfo.DisplayChange mDisplayChange\nprivate final int mFlags\nprivate final int mDebugId\n java.lang.String typeToString()\nclass TransitionRequestInfo extends java.lang.Object implements [android.os.Parcelable]\n@com.android.internal.util.DataClass(genToString=true, genSetters=true, genAidl=true)") + inputSignatures = "private final @android.view.WindowManager.TransitionType int mType\nprivate @android.annotation.Nullable android.app.ActivityManager.RunningTaskInfo mTriggerTask\nprivate @android.annotation.Nullable android.window.TransitionRequestInfo.PipChange mPipChange\nprivate @android.annotation.Nullable android.window.RemoteTransition mRemoteTransition\nprivate @android.annotation.Nullable android.window.TransitionRequestInfo.DisplayChange mDisplayChange\nprivate final int mFlags\nprivate final int mDebugId\n java.lang.String typeToString()\nclass TransitionRequestInfo extends java.lang.Object implements [android.os.Parcelable]\n@com.android.internal.util.DataClass(genToString=true, genSetters=true, genAidl=true)") @Deprecated private void __metadata() {} diff --git a/core/java/android/window/WindowContext.java b/core/java/android/window/WindowContext.java index 2b370b9797e572245874f9296d87ee136da44b78..84a8b8f5b5b0173a6675ae4623341559f9f8afc8 100644 --- a/core/java/android/window/WindowContext.java +++ b/core/java/android/window/WindowContext.java @@ -32,6 +32,7 @@ import android.view.Display; import android.view.WindowManager; import com.android.internal.annotations.VisibleForTesting; +import com.android.window.flags.Flags; import java.lang.ref.Reference; @@ -95,20 +96,20 @@ public class WindowContext extends ContextWrapper implements WindowProvider { } /** - * Updates this context to a new displayId. + * Moves this context to another display. *

    - * Note that this doesn't re-parent previously attached windows (they should be removed and - * re-added manually after this is called). Resources associated with this context will have - * the correct value and configuration for the new display after this is called. + * Note that this re-parents all the previously attached windows. Resources associated with this + * context will have the correct value and configuration for the new display after this is + * called. */ - @Override - public void updateDisplay(int displayId) { - if (displayId == getDisplayId()) { - return; + public void reparentToDisplay(int displayId) { + if (Flags.reparentWindowTokenApi()) { + if (displayId == getDisplayId()) { + return; + } + super.updateDisplay(displayId); + mController.reparentToDisplayArea(mType, displayId, mOptions); } - super.updateDisplay(displayId); - mController.detachIfNeeded(); - mController.attachToDisplayArea(mType, displayId, mOptions); } @Override diff --git a/core/java/android/window/WindowContextController.java b/core/java/android/window/WindowContextController.java index c9ac245bc36f3ca45bf1b09c071b49a504853f45..1e2f454adeefdd3bdd2cd964cd7e3ba219b6f62b 100644 --- a/core/java/android/window/WindowContextController.java +++ b/core/java/android/window/WindowContextController.java @@ -158,6 +158,21 @@ public class WindowContextController { } } + /** + * Reparents the window context from the current attached display to another. {@code type} and + * {@code options} must be the same as the previous attach call, otherwise this will fail + * silently. + */ + public void reparentToDisplayArea( + @WindowType int type, int displayId, @Nullable Bundle options) { + if (mAttachedToDisplayArea != AttachStatus.STATUS_ATTACHED) { + attachToDisplayArea(type, displayId, options); + return; + } + // No need to propagate type and options as this is already attached and they can't change. + getWindowTokenClientController().reparentToDisplayArea(mToken, displayId); + } + /** Gets the {@link WindowTokenClientController}. */ @VisibleForTesting @NonNull diff --git a/core/java/android/window/WindowTokenClient.java b/core/java/android/window/WindowTokenClient.java index 6e76d8d345b2cb6b975f2a70a3cb06f96ccb4550..a551fe701c5b34e62ecaf64bd1ef2c897b4dbfa9 100644 --- a/core/java/android/window/WindowTokenClient.java +++ b/core/java/android/window/WindowTokenClient.java @@ -166,7 +166,7 @@ public class WindowTokenClient extends Binder { @VisibleForTesting public void onConfigurationChangedInner(@NonNull Context context, @NonNull Configuration newConfig, int newDisplayId, boolean shouldReportConfigChange) { - CompatibilityInfo.applyOverrideScaleIfNeeded(newConfig); + CompatibilityInfo.applyOverrideIfNeeded(newConfig); final boolean displayChanged; final boolean shouldUpdateResources; final int diff; diff --git a/core/java/android/window/WindowTokenClientController.java b/core/java/android/window/WindowTokenClientController.java index fa345956ec4d120c9bd1db299645e8fdca7811bf..1ec05b65861d3235c482a4742ad37b37c900a3a0 100644 --- a/core/java/android/window/WindowTokenClientController.java +++ b/core/java/android/window/WindowTokenClientController.java @@ -197,6 +197,21 @@ public class WindowTokenClientController { } } + /** + * Reparents a {@link WindowTokenClient} and its associated WindowContainer if there's one. + */ + public void reparentToDisplayArea(@NonNull WindowTokenClient client, int displayId) { + try { + if (!getWindowManagerService().reparentWindowContextToDisplayArea(mAppThread, client, + displayId)) { + Log.e(TAG, + "Didn't succeed reparenting of " + client + " to displayId=" + displayId); + } + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + } + private void onWindowContextTokenAttached(@NonNull WindowTokenClient client, @NonNull WindowContextInfo info, boolean shouldReportConfigChange) { recordWindowContextToken(client); diff --git a/core/java/android/window/flags/lse_desktop_experience.aconfig b/core/java/android/window/flags/lse_desktop_experience.aconfig index 4fb5fa70c0830e6442f60cdd4e0e3ac09916de64..a05d003b2faf5c06b500b004384df1f83580cc95 100644 --- a/core/java/android/window/flags/lse_desktop_experience.aconfig +++ b/core/java/android/window/flags/lse_desktop_experience.aconfig @@ -448,6 +448,14 @@ flag { bug: "350475854" } +flag { + name: "reparent_window_token_api" + namespace: "lse_desktop_experience" + description: "Allows to reparent a window token to a different display" + is_fixed_read_only: true + bug: "381258683" +} + flag { name: "enable_desktop_windowing_hsum" namespace: "lse_desktop_experience" @@ -460,4 +468,36 @@ flag { namespace: "lse_desktop_experience" description: "Enable multiple desktop sessions for desktop windowing." bug: "379158791" +} + +flag { + name: "enable_connected_displays_dnd" + namespace: "lse_desktop_experience" + description: "Enable drag-and-drop between connected displays." + bug: "381793841" +} + +flag { + name: "enable_connected_displays_window_drag" + namespace: "lse_desktop_experience" + description: "Enable window drag between connected displays." + bug: "381172172" +} + +flag { + name: "enable_bug_fixes_for_secondary_display" + namespace: "lse_desktop_experience" + description: "Bugfixes / papercuts to bring Desktop Windowing to secondary displays." + bug: "382023296" +} + +flag { + name: "enable_top_visible_root_task_per_user_tracking" + namespace: "lse_desktop_experience" + description: "Enables tracking the top visible root tasks for a user." + bug: "381038076" + is_fixed_read_only: true + metadata { + purpose: PURPOSE_BUGFIX + } } \ No newline at end of file diff --git a/core/java/android/window/flags/windowing_frontend.aconfig b/core/java/android/window/flags/windowing_frontend.aconfig index 0b034b61c72e9e9f2c03989acfea56614bdbda3e..30f0c7371270fdaecdf6aaaaa50af1ed28db8b2e 100644 --- a/core/java/android/window/flags/windowing_frontend.aconfig +++ b/core/java/android/window/flags/windowing_frontend.aconfig @@ -453,3 +453,11 @@ flag { is_fixed_read_only: true bug: "376407910" } + +flag { + name: "relative_insets" + namespace: "windowing_frontend" + description: "Support insets definition and calculation relative to task bounds." + bug: "277292497" + is_fixed_read_only: true +} \ No newline at end of file diff --git a/core/java/android/window/flags/windowing_sdk.aconfig b/core/java/android/window/flags/windowing_sdk.aconfig index 81734a3e2115c14de52a782bd59d4185db3d98bf..d0d4af6ea598448b3f7d7959008a4398114bb2e5 100644 --- a/core/java/android/window/flags/windowing_sdk.aconfig +++ b/core/java/android/window/flags/windowing_sdk.aconfig @@ -116,3 +116,14 @@ flag { description: "Relax the assumption of non-match parent activity" bug: "356277166" } + +flag { + namespace: "windowing_sdk" + name: "allow_multiple_adjacent_task_fragments" + description: "Refactor to allow more than 2 adjacent TaskFragments" + bug: "373709676" + is_fixed_read_only: true + metadata { + purpose: PURPOSE_BUGFIX + } +} diff --git a/core/java/com/android/internal/accessibility/AccessibilityShortcutController.java b/core/java/com/android/internal/accessibility/AccessibilityShortcutController.java index e2be1f57b1fba2556f5276418a828ce44871cf35..a27eeb8fdd6340d2a387fb1f7464c11b713aa53b 100644 --- a/core/java/com/android/internal/accessibility/AccessibilityShortcutController.java +++ b/core/java/com/android/internal/accessibility/AccessibilityShortcutController.java @@ -58,7 +58,6 @@ import android.util.Slog; import android.view.Window; import android.view.WindowManager; import android.view.accessibility.AccessibilityManager; -import android.view.accessibility.Flags; import android.widget.Toast; import com.android.internal.R; @@ -289,9 +288,7 @@ public class AccessibilityShortcutController { cr, Settings.Secure.ACCESSIBILITY_SHORTCUT_DIALOG_SHOWN, DialogStatus.SHOWN, userId); } else { - if (Flags.restoreA11yShortcutTargetService()) { - enableDefaultHardwareShortcut(userId); - } + enableDefaultHardwareShortcut(userId); playNotificationTone(); if (mAlertDialog != null) { mAlertDialog.dismiss(); diff --git a/core/java/com/android/internal/accessibility/dialog/AccessibilityServiceWarning.java b/core/java/com/android/internal/accessibility/dialog/AccessibilityServiceWarning.java index 3557633f87c577e55f118a7374094e6c4609099b..2e1a0bff3cd3a4b688e4d41b934e6cb5d020c693 100644 --- a/core/java/com/android/internal/accessibility/dialog/AccessibilityServiceWarning.java +++ b/core/java/com/android/internal/accessibility/dialog/AccessibilityServiceWarning.java @@ -29,7 +29,6 @@ import android.view.MotionEvent; import android.view.View; import android.view.Window; import android.view.WindowManager; -import android.view.accessibility.Flags; import android.widget.Button; import android.widget.ImageView; import android.widget.TextView; @@ -65,9 +64,6 @@ public class AccessibilityServiceWarning { Window window = ad.getWindow(); WindowManager.LayoutParams params = window.getAttributes(); params.privateFlags |= SYSTEM_FLAG_HIDE_NON_SYSTEM_OVERLAY_WINDOWS; - if (!Flags.warningUseDefaultDialogType()) { - params.type = WindowManager.LayoutParams.TYPE_SYSTEM_DIALOG; - } window.setAttributes(params); return ad; } diff --git a/core/java/com/android/internal/app/AlertController.java b/core/java/com/android/internal/app/AlertController.java index 92f9e6014107f5c61d461320cadaedd45d2a1708..5d4c40853009807063042b80a8a96c24f5639561 100644 --- a/core/java/com/android/internal/app/AlertController.java +++ b/core/java/com/android/internal/app/AlertController.java @@ -267,7 +267,9 @@ public class AlertController { return Flags.useWearMaterial3Ui() && CompatChanges.isChangeEnabled(WEAR_MATERIAL3_ALERTDIALOG) && context.getPackageManager().hasSystemFeature(PackageManager.FEATURE_WATCH) - && context.getThemeResId() == com.android.internal.R.style.Theme_DeviceDefault; + && (context.getThemeResId() == com.android.internal.R.style.Theme_DeviceDefault + || context.getThemeResId() + == com.android.internal.R.style.Theme_DeviceDefault_Dialog_Alert); } static boolean canTextInput(View v) { diff --git a/core/java/com/android/internal/app/IntentForwarderActivity.java b/core/java/com/android/internal/app/IntentForwarderActivity.java index ee5bd65e76ded0af273534a13252ac425ee5d646..644d699199985d909b8c35baa3887e5da9293ed6 100644 --- a/core/java/com/android/internal/app/IntentForwarderActivity.java +++ b/core/java/com/android/internal/app/IntentForwarderActivity.java @@ -70,6 +70,7 @@ import android.widget.Toast; import com.android.internal.R; import com.android.internal.annotations.VisibleForTesting; +import com.android.internal.app.chooser.TargetInfo; import com.android.internal.logging.MetricsLogger; import com.android.internal.logging.nano.MetricsProto.MetricsEvent; @@ -352,6 +353,7 @@ public class IntentForwarderActivity extends Activity { findViewById(R.id.use_same_profile_browser).setOnClickListener(v -> finish()); findViewById(R.id.button_open).setOnClickListener(v -> { + TargetInfo.refreshIntentCreatorToken(launchIntent); startActivityAsCaller( launchIntent, ActivityOptions.makeCustomAnimation( @@ -476,6 +478,7 @@ public class IntentForwarderActivity extends Activity { private void startActivityAsCaller(Intent newIntent, int userId) { try { + TargetInfo.refreshIntentCreatorToken(newIntent); startActivityAsCaller( newIntent, /* options= */ null, @@ -502,6 +505,7 @@ public class IntentForwarderActivity extends Activity { return; } sanitizeIntent(innerIntent); + TargetInfo.refreshIntentCreatorToken(intentReceived); startActivityAsCaller(intentReceived, null, false, getUserId()); finish(); } @@ -525,6 +529,7 @@ public class IntentForwarderActivity extends Activity { if (singleTabOnly) { intentReceived.putExtra(EXTRA_RESTRICT_TO_SINGLE_USER, true); } + TargetInfo.refreshIntentCreatorToken(intentReceived); startActivityAsCaller(intentReceived, null, false, userId); finish(); } diff --git a/core/java/com/android/internal/app/chooser/DisplayResolveInfo.java b/core/java/com/android/internal/app/chooser/DisplayResolveInfo.java index 473134ea46f3f41387a157d5dc2c5f2a7f171ff8..0c650774105ec67d95b9c3b65f4eb80498754bec 100644 --- a/core/java/com/android/internal/app/chooser/DisplayResolveInfo.java +++ b/core/java/com/android/internal/app/chooser/DisplayResolveInfo.java @@ -173,6 +173,7 @@ public class DisplayResolveInfo implements TargetInfo, Parcelable { @Override public boolean startAsCaller(ResolverActivity activity, Bundle options, int userId) { TargetInfo.prepareIntentForCrossProfileLaunch(mResolvedIntent, userId); + TargetInfo.refreshIntentCreatorToken(mResolvedIntent); activity.startActivityAsCaller(mResolvedIntent, options, false, userId); return true; } @@ -180,6 +181,7 @@ public class DisplayResolveInfo implements TargetInfo, Parcelable { @Override public boolean startAsUser(Activity activity, Bundle options, UserHandle user) { TargetInfo.prepareIntentForCrossProfileLaunch(mResolvedIntent, user.getIdentifier()); + TargetInfo.refreshIntentCreatorToken(mResolvedIntent); activity.startActivityAsUser(mResolvedIntent, options, user); return false; } diff --git a/core/java/com/android/internal/app/chooser/SelectableTargetInfo.java b/core/java/com/android/internal/app/chooser/SelectableTargetInfo.java index d7f3a76c61e0aabde31ef7033ec13a8de626c74e..0eaa43d2c6e8d6a19e3a152e053dc662c60af7f1 100644 --- a/core/java/com/android/internal/app/chooser/SelectableTargetInfo.java +++ b/core/java/com/android/internal/app/chooser/SelectableTargetInfo.java @@ -260,6 +260,7 @@ public final class SelectableTargetInfo implements ChooserTargetInfo { intent.setComponent(mChooserTarget.getComponentName()); intent.putExtras(mChooserTarget.getIntentExtras()); TargetInfo.prepareIntentForCrossProfileLaunch(intent, userId); + TargetInfo.refreshIntentCreatorToken(intent); // Important: we will ignore the target security checks in ActivityManager // if and only if the ChooserTarget's target package is the same package diff --git a/core/java/com/android/internal/app/chooser/TargetInfo.java b/core/java/com/android/internal/app/chooser/TargetInfo.java index 7bb7ddc65c6dbfababbebc026bd0f54fb88ab6f4..fcf5883cc84b9dafbb3a4901073ded97a032112d 100644 --- a/core/java/com/android/internal/app/chooser/TargetInfo.java +++ b/core/java/com/android/internal/app/chooser/TargetInfo.java @@ -17,13 +17,17 @@ package com.android.internal.app.chooser; +import static android.security.Flags.preventIntentRedirect; + import android.app.Activity; +import android.app.ActivityManager; import android.content.ComponentName; import android.content.Context; import android.content.Intent; import android.content.pm.ResolveInfo; import android.graphics.drawable.Drawable; import android.os.Bundle; +import android.os.RemoteException; import android.os.UserHandle; import com.android.internal.app.ResolverActivity; @@ -141,4 +145,20 @@ public interface TargetInfo { intent.fixUris(currentUserId); } } + + /** + * refreshes intent's creatorToken with its current intent key fields. This allows + * ChooserActivity to still keep original creatorToken's creator uid after making changes to + * the intent and still keep it valid. + * @param intent the intent's creatorToken needs to up refreshed. + */ + static void refreshIntentCreatorToken(Intent intent) { + if (!preventIntentRedirect()) return; + try { + intent.setCreatorToken(ActivityManager.getService().refreshIntentCreatorToken( + intent.cloneForCreatorToken())); + } catch (RemoteException e) { + throw new RuntimeException("Failure from system", e); + } + } } diff --git a/core/java/com/android/internal/inputmethod/SoftInputShowHideReason.java b/core/java/com/android/internal/inputmethod/SoftInputShowHideReason.java index 429a6a267bb1abe33cc57a6e27c85a90b3a0eed9..592ea9e5e60083429dcfe0fa24348d0461305edf 100644 --- a/core/java/com/android/internal/inputmethod/SoftInputShowHideReason.java +++ b/core/java/com/android/internal/inputmethod/SoftInputShowHideReason.java @@ -91,6 +91,7 @@ import java.lang.annotation.Retention; SoftInputShowHideReason.CONTROL_WINDOW_INSETS_ANIMATION, SoftInputShowHideReason.SHOW_INPUT_TARGET_CHANGED, SoftInputShowHideReason.HIDE_INPUT_TARGET_CHANGED, + SoftInputShowHideReason.REASON_HIDE_WINDOW_LOST_FOCUS, }) public @interface SoftInputShowHideReason { /** Default, undefined reason. */ @@ -418,4 +419,7 @@ public @interface SoftInputShowHideReason { * {@link android.view.InsetsController#controlWindowInsetsAnimation}. */ int CONTROL_WINDOW_INSETS_ANIMATION = ImeProtoEnums.REASON_CONTROL_WINDOW_INSETS_ANIMATION; + + /** Hide soft input when the window lost focus. */ + int REASON_HIDE_WINDOW_LOST_FOCUS = ImeProtoEnums.REASON_HIDE_WINDOW_LOST_FOCUS; } diff --git a/core/java/com/android/internal/jank/EventLogTags.logtags b/core/java/com/android/internal/jank/EventLogTags.logtags index 66ee131badacabde48eebbd49dbca21115fc5324..dfec49907c69eb989d154e1398045b5f71ca8940 100644 --- a/core/java/com/android/internal/jank/EventLogTags.logtags +++ b/core/java/com/android/internal/jank/EventLogTags.logtags @@ -1,4 +1,4 @@ -# See system/core/logcat/event.logtags for a description of the format of this file. +# See system/logging/logcat/event.logtags for a description of the format of this file. option java_package com.android.internal.jank; diff --git a/core/java/com/android/internal/os/TEST_MAPPING b/core/java/com/android/internal/os/TEST_MAPPING index 4400ed11772126331531887e509c7a374fd164db..1923c5fb9186f87a9e3ef78e8e451feb9b6698df 100644 --- a/core/java/com/android/internal/os/TEST_MAPPING +++ b/core/java/com/android/internal/os/TEST_MAPPING @@ -20,7 +20,7 @@ "file_patterns": [ "BinderDeathDispatcher\\.java" ], - "name": "FrameworksCoreTests_internal_os_binder" + "name": "FrameworksCoreTests_all_binder" }, { "file_patterns": [ diff --git a/core/java/com/android/internal/pm/pkg/component/AconfigFlags.java b/core/java/com/android/internal/pm/pkg/component/AconfigFlags.java index c953d88c94828a690a803de8d9a49884bb26a4d7..445dac7411daa6f150a151447dc60631984adf1f 100644 --- a/core/java/com/android/internal/pm/pkg/component/AconfigFlags.java +++ b/core/java/com/android/internal/pm/pkg/component/AconfigFlags.java @@ -25,7 +25,6 @@ import android.aconfig.nano.Aconfig.parsed_flags; import android.annotation.NonNull; import android.annotation.Nullable; import android.content.res.Flags; -import android.content.res.XmlResourceParser; import android.os.Environment; import android.os.Process; import android.util.ArrayMap; @@ -247,20 +246,23 @@ public class AconfigFlags { negated = true; featureFlag = featureFlag.substring(1).strip(); } - final Boolean flagValue = getFlagValue(featureFlag); - boolean shouldSkip = false; + Boolean flagValue = getFlagValue(featureFlag); + boolean isUndefined = false; if (flagValue == null) { - Slog.w(LOG_TAG, "Skipping element " + parser.getName() - + " due to unknown feature flag " + featureFlag); - shouldSkip = true; - } else if (flagValue == negated) { + isUndefined = true; + flagValue = false; + } + boolean shouldSkip = false; + if (flagValue == negated) { // Skip if flag==false && attr=="flag" OR flag==true && attr=="!flag" (negated) - Slog.i(LOG_TAG, "Skipping element " + parser.getName() - + " behind feature flag " + featureFlag + " = " + flagValue); shouldSkip = true; } if (pkg != null && android.content.pm.Flags.includeFeatureFlagsInPackageCacher()) { - pkg.addFeatureFlag(featureFlag, flagValue); + if (isUndefined) { + pkg.addFeatureFlag(featureFlag, null); + } else { + pkg.addFeatureFlag(featureFlag, flagValue); + } } return shouldSkip; } diff --git a/core/java/com/android/internal/statusbar/IStatusBarService.aidl b/core/java/com/android/internal/statusbar/IStatusBarService.aidl index ff08dd27225ff52f829fef801cbde5a6d5bcb3fa..3e2f30118b2a2b0d1a50bdbc26539ad09ab0242c 100644 --- a/core/java/com/android/internal/statusbar/IStatusBarService.aidl +++ b/core/java/com/android/internal/statusbar/IStatusBarService.aidl @@ -67,6 +67,13 @@ interface IStatusBarService // ---- Methods below are for use by the status bar policy services ---- // You need the STATUS_BAR_SERVICE permission RegisterStatusBarResult registerStatusBar(IStatusBar callbacks); + /** + * Registers the status bar for all displays. + * + * Returns a map of all display IDs (as strings) to their corresponding RegisterStatusBarResult + * objects. + */ + Map registerStatusBarForAllDisplays(IStatusBar callbacks); void onPanelRevealed(boolean clearNotificationEffects, int numItems); void onPanelHidden(); // Mark current notifications as "seen" and stop ringing, vibrating, blinking. diff --git a/core/java/com/android/internal/util/ArrayUtils.java b/core/java/com/android/internal/util/ArrayUtils.java index 1e965c5db7ae0158fc09eb3ef66a571913bc29fa..bda7547087ae536a2f1e04c881c06c4b3977d7f1 100644 --- a/core/java/com/android/internal/util/ArrayUtils.java +++ b/core/java/com/android/internal/util/ArrayUtils.java @@ -20,6 +20,7 @@ import android.annotation.NonNull; import android.annotation.Nullable; import android.compat.annotation.UnsupportedAppUsage; import android.os.Build; +import android.ravenwood.annotation.RavenwoodReplace; import android.util.ArraySet; import android.util.EmptyArray; @@ -39,6 +40,10 @@ import java.util.function.IntFunction; /** * Static utility methods for arrays that aren't already included in {@link java.util.Arrays}. + *

    + * Test with: + * atest FrameworksUtilTests:com.android.internal.util.ArrayUtilsTest + * atest FrameworksUtilTestsRavenwood:com.android.internal.util.ArrayUtilsTest */ @android.ravenwood.annotation.RavenwoodKeepWholeClass public class ArrayUtils { @@ -84,6 +89,69 @@ public class ArrayUtils { return (T[])VMRuntime.getRuntime().newUnpaddedArray(clazz, minLen); } + /** + * This is like new byte[length], but it allocates the array as non-movable. This + * prevents copies of the data from being left on the Java heap as a result of heap compaction. + * Use this when the array will contain sensitive data such as a password or cryptographic key + * that needs to be wiped from memory when no longer needed. The owner of the array is still + * responsible for the zeroization; {@link #zeroize(byte[])} should be used to do so. + * + * @param length the length of the array to allocate + * @return the new array + */ + public static byte[] newNonMovableByteArray(int length) { + return (byte[]) VMRuntime.getRuntime().newNonMovableArray(byte.class, length); + } + + /** + * Like {@link #newNonMovableByteArray(int)}, but allocates a char array. + * + * @param length the length of the array to allocate + * @return the new array + */ + public static char[] newNonMovableCharArray(int length) { + return (char[]) VMRuntime.getRuntime().newNonMovableArray(char.class, length); + } + + /** + * Zeroizes a byte array as securely as possible. Use this when the array contains sensitive + * data such as a password or cryptographic key. + *

    + * This zeroizes the array in a way that is guaranteed to not be optimized out by the compiler. + * If supported by the architecture, it zeroizes the data not just in the L1 data cache but also + * in other levels of the memory hierarchy up to and including main memory (but not above that). + *

    + * This works on any byte[], but to ensure that copies of the array aren't left on + * the Java heap the array should have been allocated with {@link #newNonMovableByteArray(int)}. + * Use on other arrays might also introduce performance anomalies. + * + * @param array the array to zeroize. If null, this method has no effect. + */ + @RavenwoodReplace public static native void zeroize(byte[] array); + + /** + * Replacement of the above method for host-side unit testing that doesn't support JNI yet. + */ + public static void zeroize$ravenwood(byte[] array) { + if (array != null) { + Arrays.fill(array, (byte) 0); + } + } + + /** + * Like {@link #zeroize(byte[])}, but for char arrays. + */ + @RavenwoodReplace public static native void zeroize(char[] array); + + /** + * Replacement of the above method for host-side unit testing that doesn't support JNI yet. + */ + public static void zeroize$ravenwood(char[] array) { + if (array != null) { + Arrays.fill(array, (char) 0); + } + } + /** * Checks if the beginnings of two byte arrays are equal. * diff --git a/core/java/com/android/internal/util/LatencyTracker.java b/core/java/com/android/internal/util/LatencyTracker.java index 754f77e72f8a38fea58e879d9a64547ef5484ec4..d49afa7356464d6f7af1e7f525adc46ef436e275 100644 --- a/core/java/com/android/internal/util/LatencyTracker.java +++ b/core/java/com/android/internal/util/LatencyTracker.java @@ -435,9 +435,11 @@ public class LatencyTracker { public void startListeningForLatencyTrackerConfigChanges() { final Context context = ActivityThread.currentApplication(); if (context == null) { - if (DEBUG) { - Log.d(TAG, "No application for package: " + ActivityThread.currentPackageName()); - } + Log.e( + TAG, + String.format( + "No application for package: %s. Latency Tracker Disabled", + ActivityThread.currentPackageName())); return; } if (context.checkCallingOrSelfPermission(READ_DEVICE_CONFIG) != PERMISSION_GRANTED) { diff --git a/core/java/com/android/internal/vibrator/persistence/SerializedBasicEnvelopeEffect.java b/core/java/com/android/internal/vibrator/persistence/SerializedBasicEnvelopeEffect.java new file mode 100644 index 0000000000000000000000000000000000000000..a090c7abc2dbbad2614ae227db898a60bccb23cf --- /dev/null +++ b/core/java/com/android/internal/vibrator/persistence/SerializedBasicEnvelopeEffect.java @@ -0,0 +1,184 @@ +/* + * Copyright (C) 2024 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES 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.vibrator.persistence; + +import static com.android.internal.vibrator.persistence.XmlConstants.ATTRIBUTE_DURATION_MS; +import static com.android.internal.vibrator.persistence.XmlConstants.ATTRIBUTE_INITIAL_SHARPNESS; +import static com.android.internal.vibrator.persistence.XmlConstants.ATTRIBUTE_INTENSITY; +import static com.android.internal.vibrator.persistence.XmlConstants.ATTRIBUTE_SHARPNESS; +import static com.android.internal.vibrator.persistence.XmlConstants.NAMESPACE; +import static com.android.internal.vibrator.persistence.XmlConstants.TAG_BASIC_ENVELOPE_EFFECT; +import static com.android.internal.vibrator.persistence.XmlConstants.TAG_CONTROL_POINT; + +import android.annotation.NonNull; +import android.os.VibrationEffect; + +import com.android.modules.utils.TypedXmlPullParser; +import com.android.modules.utils.TypedXmlSerializer; + +import java.io.IOException; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; +import java.util.Locale; + +/** + * Serialized representation of a basic envelope effect created via + * {@link VibrationEffect.BasicEnvelopeBuilder}. + * + * @hide + */ +final class SerializedBasicEnvelopeEffect implements SerializedComposedEffect.SerializedSegment { + private final BasicControlPoint[] mControlPoints; + private final float mInitialSharpness; + + SerializedBasicEnvelopeEffect(BasicControlPoint[] controlPoints, float initialSharpness) { + mControlPoints = controlPoints; + mInitialSharpness = initialSharpness; + } + + @Override + public void write(@NonNull TypedXmlSerializer serializer) throws IOException { + serializer.startTag(NAMESPACE, TAG_BASIC_ENVELOPE_EFFECT); + + if (!Float.isNaN(mInitialSharpness)) { + serializer.attributeFloat(NAMESPACE, ATTRIBUTE_INITIAL_SHARPNESS, mInitialSharpness); + } + + for (BasicControlPoint point : mControlPoints) { + serializer.startTag(NAMESPACE, TAG_CONTROL_POINT); + serializer.attributeFloat(NAMESPACE, ATTRIBUTE_INTENSITY, point.mIntensity); + serializer.attributeFloat(NAMESPACE, ATTRIBUTE_SHARPNESS, point.mSharpness); + serializer.attributeLong(NAMESPACE, ATTRIBUTE_DURATION_MS, point.mDurationMs); + serializer.endTag(NAMESPACE, TAG_CONTROL_POINT); + } + + serializer.endTag(NAMESPACE, TAG_BASIC_ENVELOPE_EFFECT); + } + + @Override + public void deserializeIntoComposition(@NonNull VibrationEffect.Composition composition) { + VibrationEffect.BasicEnvelopeBuilder builder = new VibrationEffect.BasicEnvelopeBuilder(); + + if (!Float.isNaN(mInitialSharpness)) { + builder.setInitialSharpness(mInitialSharpness); + } + + for (BasicControlPoint point : mControlPoints) { + builder.addControlPoint(point.mIntensity, point.mSharpness, point.mDurationMs); + } + composition.addEffect(builder.build()); + } + + @Override + public String toString() { + return "SerializedBasicEnvelopeEffect{" + + "initialSharpness=" + (Float.isNaN(mInitialSharpness) ? "" : mInitialSharpness) + + ", controlPoints=" + Arrays.toString(mControlPoints) + + '}'; + } + + static final class Builder { + private final List mControlPoints; + private float mInitialSharpness = Float.NaN; + + Builder() { + mControlPoints = new ArrayList<>(); + } + + void setInitialSharpness(float sharpness) { + mInitialSharpness = sharpness; + } + + void addControlPoint(float intensity, float sharpness, long durationMs) { + mControlPoints.add(new BasicControlPoint(intensity, sharpness, durationMs)); + } + + SerializedBasicEnvelopeEffect build() { + return new SerializedBasicEnvelopeEffect( + mControlPoints.toArray(new BasicControlPoint[0]), mInitialSharpness); + } + } + + /** Parser implementation for {@link SerializedBasicEnvelopeEffect}. */ + static final class Parser { + + @NonNull + static SerializedBasicEnvelopeEffect parseNext(@NonNull TypedXmlPullParser parser, + @XmlConstants.Flags int flags) throws XmlParserException, IOException { + XmlValidator.checkStartTag(parser, TAG_BASIC_ENVELOPE_EFFECT); + XmlValidator.checkTagHasNoUnexpectedAttributes(parser, ATTRIBUTE_INITIAL_SHARPNESS); + + Builder builder = new Builder(); + builder.setInitialSharpness( + XmlReader.readAttributeFloatInRange(parser, ATTRIBUTE_INITIAL_SHARPNESS, 0f, 1f, + Float.NaN)); + + int outerDepth = parser.getDepth(); + + // Read all nested tags + while (XmlReader.readNextTagWithin(parser, outerDepth)) { + parseControlPoint(parser, builder); + // Consume tag + XmlReader.readEndTag(parser); + } + + // Check schema assertions about + XmlValidator.checkParserCondition(!builder.mControlPoints.isEmpty(), + "Expected tag %s to have at least one control point", + TAG_BASIC_ENVELOPE_EFFECT); + XmlValidator.checkParserCondition(builder.mControlPoints.getLast().mIntensity == 0, + "Basic envelope effects must end at a zero intensity control point"); + + return builder.build(); + } + + private static void parseControlPoint(TypedXmlPullParser parser, Builder builder) + throws XmlParserException { + XmlValidator.checkStartTag(parser, TAG_CONTROL_POINT); + XmlValidator.checkTagHasNoUnexpectedAttributes( + parser, ATTRIBUTE_DURATION_MS, ATTRIBUTE_INTENSITY, + ATTRIBUTE_SHARPNESS); + float intensity = XmlReader.readAttributeFloatInRange(parser, ATTRIBUTE_INTENSITY, 0, + 1); + float sharpness = XmlReader.readAttributeFloatInRange(parser, ATTRIBUTE_SHARPNESS, 0, + 1); + long durationMs = XmlReader.readAttributePositiveLong(parser, ATTRIBUTE_DURATION_MS); + + builder.addControlPoint(intensity, sharpness, durationMs); + } + } + + private static final class BasicControlPoint { + private final float mIntensity; + private final float mSharpness; + private final long mDurationMs; + + BasicControlPoint(float intensity, float sharpness, long durationMs) { + mIntensity = intensity; + mSharpness = sharpness; + mDurationMs = durationMs; + } + + @Override + public String toString() { + return String.format(Locale.ROOT, "(%.2f, %.2f, %dms)", mIntensity, mSharpness, + mDurationMs); + } + } +} + diff --git a/core/java/com/android/internal/vibrator/persistence/SerializedWaveformEnvelopeEffect.java b/core/java/com/android/internal/vibrator/persistence/SerializedWaveformEnvelopeEffect.java new file mode 100644 index 0000000000000000000000000000000000000000..6a893430d7ad427204ba93df84d7b901d822c2bd --- /dev/null +++ b/core/java/com/android/internal/vibrator/persistence/SerializedWaveformEnvelopeEffect.java @@ -0,0 +1,182 @@ +/* + * Copyright (C) 2024 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES 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.vibrator.persistence; + +import static com.android.internal.vibrator.persistence.XmlConstants.ATTRIBUTE_AMPLITUDE; +import static com.android.internal.vibrator.persistence.XmlConstants.ATTRIBUTE_DURATION_MS; +import static com.android.internal.vibrator.persistence.XmlConstants.ATTRIBUTE_FREQUENCY_HZ; +import static com.android.internal.vibrator.persistence.XmlConstants.ATTRIBUTE_INITIAL_FREQUENCY_HZ; +import static com.android.internal.vibrator.persistence.XmlConstants.NAMESPACE; +import static com.android.internal.vibrator.persistence.XmlConstants.TAG_CONTROL_POINT; +import static com.android.internal.vibrator.persistence.XmlConstants.TAG_WAVEFORM_ENVELOPE_EFFECT; + +import android.annotation.NonNull; +import android.os.VibrationEffect; + +import com.android.modules.utils.TypedXmlPullParser; +import com.android.modules.utils.TypedXmlSerializer; + +import java.io.IOException; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; +import java.util.Locale; + +/** + * Serialized representation of a waveform envelope effect created via + * {@link VibrationEffect.WaveformEnvelopeBuilder}. + * + * @hide + */ +final class SerializedWaveformEnvelopeEffect implements SerializedComposedEffect.SerializedSegment { + + private final WaveformControlPoint[] mControlPoints; + private final float mInitialFrequency; + + SerializedWaveformEnvelopeEffect(WaveformControlPoint[] controlPoints, float initialFrequency) { + mControlPoints = controlPoints; + mInitialFrequency = initialFrequency; + } + + @Override + public void write(@NonNull TypedXmlSerializer serializer) throws IOException { + serializer.startTag(NAMESPACE, TAG_WAVEFORM_ENVELOPE_EFFECT); + + if (!Float.isNaN(mInitialFrequency)) { + serializer.attributeFloat(NAMESPACE, ATTRIBUTE_INITIAL_FREQUENCY_HZ, mInitialFrequency); + } + + for (WaveformControlPoint point : mControlPoints) { + serializer.startTag(NAMESPACE, TAG_CONTROL_POINT); + serializer.attributeFloat(NAMESPACE, ATTRIBUTE_AMPLITUDE, point.mAmplitude); + serializer.attributeFloat(NAMESPACE, ATTRIBUTE_FREQUENCY_HZ, point.mFrequency); + serializer.attributeLong(NAMESPACE, ATTRIBUTE_DURATION_MS, point.mDurationMs); + serializer.endTag(NAMESPACE, TAG_CONTROL_POINT); + } + + serializer.endTag(NAMESPACE, TAG_WAVEFORM_ENVELOPE_EFFECT); + } + + @Override + public void deserializeIntoComposition(@NonNull VibrationEffect.Composition composition) { + VibrationEffect.WaveformEnvelopeBuilder builder = + new VibrationEffect.WaveformEnvelopeBuilder(); + + if (!Float.isNaN(mInitialFrequency)) { + builder.setInitialFrequencyHz(mInitialFrequency); + } + + for (WaveformControlPoint point : mControlPoints) { + builder.addControlPoint(point.mAmplitude, point.mFrequency, point.mDurationMs); + } + composition.addEffect(builder.build()); + } + + @Override + public String toString() { + return "SerializedWaveformEnvelopeEffect{" + + "InitialFrequency=" + (Float.isNaN(mInitialFrequency) ? "" : mInitialFrequency) + + ", controlPoints=" + Arrays.toString(mControlPoints) + + '}'; + } + + static final class Builder { + private final List mControlPoints; + private float mInitialFrequencyHz = Float.NaN; + + Builder() { + mControlPoints = new ArrayList<>(); + } + + void setInitialFrequencyHz(float frequencyHz) { + mInitialFrequencyHz = frequencyHz; + } + + void addControlPoint(float amplitude, float frequencyHz, long durationMs) { + mControlPoints.add(new WaveformControlPoint(amplitude, frequencyHz, durationMs)); + } + + SerializedWaveformEnvelopeEffect build() { + return new SerializedWaveformEnvelopeEffect( + mControlPoints.toArray(new WaveformControlPoint[0]), mInitialFrequencyHz); + } + } + + /** Parser implementation for {@link SerializedWaveformEnvelopeEffect}. */ + static final class Parser { + + @NonNull + static SerializedWaveformEnvelopeEffect parseNext(@NonNull TypedXmlPullParser parser, + @XmlConstants.Flags int flags) throws XmlParserException, IOException { + XmlValidator.checkStartTag(parser, TAG_WAVEFORM_ENVELOPE_EFFECT); + XmlValidator.checkTagHasNoUnexpectedAttributes(parser, ATTRIBUTE_INITIAL_FREQUENCY_HZ); + + Builder builder = new Builder(); + builder.setInitialFrequencyHz( + XmlReader.readAttributePositiveFloat(parser, ATTRIBUTE_INITIAL_FREQUENCY_HZ, + Float.NaN)); + + int outerDepth = parser.getDepth(); + + while (XmlReader.readNextTagWithin(parser, outerDepth)) { + parseControlPoint(parser, builder); + // Consume tag + XmlReader.readEndTag(parser); + } + + // Check schema assertions about + XmlValidator.checkParserCondition(!builder.mControlPoints.isEmpty(), + "Expected tag %s to have at least one control point", + TAG_WAVEFORM_ENVELOPE_EFFECT); + + return builder.build(); + } + + private static void parseControlPoint(TypedXmlPullParser parser, Builder builder) + throws XmlParserException { + XmlValidator.checkStartTag(parser, TAG_CONTROL_POINT); + XmlValidator.checkTagHasNoUnexpectedAttributes( + parser, ATTRIBUTE_DURATION_MS, ATTRIBUTE_AMPLITUDE, + ATTRIBUTE_FREQUENCY_HZ); + float amplitude = XmlReader.readAttributeFloatInRange(parser, ATTRIBUTE_AMPLITUDE, 0, + 1); + float frequencyHz = XmlReader.readAttributePositiveFloat(parser, + ATTRIBUTE_FREQUENCY_HZ); + long durationMs = XmlReader.readAttributePositiveLong(parser, ATTRIBUTE_DURATION_MS); + + builder.addControlPoint(amplitude, frequencyHz, durationMs); + } + } + + private static final class WaveformControlPoint { + private final float mAmplitude; + private final float mFrequency; + private final long mDurationMs; + + WaveformControlPoint(float amplitude, float frequency, long durationMs) { + mAmplitude = amplitude; + mFrequency = frequency; + mDurationMs = durationMs; + } + + @Override + public String toString() { + return String.format(Locale.ROOT, "(%.2f, %.2f, %dms)", mAmplitude, mFrequency, + mDurationMs); + } + } +} diff --git a/core/java/com/android/internal/vibrator/persistence/VibrationEffectXmlParser.java b/core/java/com/android/internal/vibrator/persistence/VibrationEffectXmlParser.java index a9fbcafa128d38bcd7997763cccbc1f44b99d7c4..314bfe40ee0b5da89f13bbd1e6047436b5d3a4d2 100644 --- a/core/java/com/android/internal/vibrator/persistence/VibrationEffectXmlParser.java +++ b/core/java/com/android/internal/vibrator/persistence/VibrationEffectXmlParser.java @@ -16,11 +16,13 @@ package com.android.internal.vibrator.persistence; +import static com.android.internal.vibrator.persistence.XmlConstants.TAG_BASIC_ENVELOPE_EFFECT; import static com.android.internal.vibrator.persistence.XmlConstants.TAG_PREDEFINED_EFFECT; import static com.android.internal.vibrator.persistence.XmlConstants.TAG_PRIMITIVE_EFFECT; import static com.android.internal.vibrator.persistence.XmlConstants.TAG_VENDOR_EFFECT; import static com.android.internal.vibrator.persistence.XmlConstants.TAG_VIBRATION_EFFECT; import static com.android.internal.vibrator.persistence.XmlConstants.TAG_WAVEFORM_EFFECT; +import static com.android.internal.vibrator.persistence.XmlConstants.TAG_WAVEFORM_ENVELOPE_EFFECT; import android.annotation.NonNull; import android.os.VibrationEffect; @@ -92,6 +94,32 @@ import java.util.List; * } * * + * * Waveform Envelope effects + * + *

    + *     {@code
    + *       
    + *         
    + *           
    + *           
    + *         
    + *       
    + *     }
    + * 
    + * + * * Basic Envelope effects + * + *
    + *     {@code
    + *       
    + *         
    + *            
    + *            
    + *          
    + *       
    + *     }
    + * 
    + * * @hide */ public class VibrationEffectXmlParser { @@ -151,6 +179,18 @@ public class VibrationEffectXmlParser { serializedVibration = new SerializedComposedEffect( SerializedAmplitudeStepWaveform.Parser.parseNext(parser)); break; + case TAG_WAVEFORM_ENVELOPE_EFFECT: + if (Flags.normalizedPwleEffects()) { + serializedVibration = new SerializedComposedEffect( + SerializedWaveformEnvelopeEffect.Parser.parseNext(parser, flags)); + break; + } // else fall through + case TAG_BASIC_ENVELOPE_EFFECT: + if (Flags.normalizedPwleEffects()) { + serializedVibration = new SerializedComposedEffect( + SerializedBasicEnvelopeEffect.Parser.parseNext(parser, flags)); + break; + } // else fall through default: throw new XmlParserException("Unexpected tag " + parser.getName() + " in vibration tag " + vibrationTagName); diff --git a/core/java/com/android/internal/vibrator/persistence/VibrationEffectXmlSerializer.java b/core/java/com/android/internal/vibrator/persistence/VibrationEffectXmlSerializer.java index cb834a5eac7e816eaaedabcc54e29eb633205116..ebe34344c6f54a8f58b41959c51c654a7afd72d4 100644 --- a/core/java/com/android/internal/vibrator/persistence/VibrationEffectXmlSerializer.java +++ b/core/java/com/android/internal/vibrator/persistence/VibrationEffectXmlSerializer.java @@ -19,9 +19,11 @@ package com.android.internal.vibrator.persistence; import android.annotation.NonNull; import android.os.PersistableBundle; import android.os.VibrationEffect; +import android.os.vibrator.BasicPwleSegment; import android.os.vibrator.Flags; import android.os.vibrator.PrebakedSegment; import android.os.vibrator.PrimitiveSegment; +import android.os.vibrator.PwleSegment; import android.os.vibrator.StepSegment; import android.os.vibrator.VibrationEffectSegment; @@ -45,6 +47,8 @@ import java.util.List; *
  • A composition created exclusively via * {@link VibrationEffect.Composition#addPrimitive(int, float, int)} *
  • {@link VibrationEffect#createVendorEffect(PersistableBundle)} + *
  • {@link VibrationEffect.WaveformEnvelopeBuilder} + *
  • {@link VibrationEffect.BasicEnvelopeBuilder} * * * @hide @@ -77,6 +81,12 @@ public final class VibrationEffectXmlSerializer { if (firstSegment instanceof PrimitiveSegment) { return serializePrimitiveEffect(composed); } + if (Flags.normalizedPwleEffects() && firstSegment instanceof PwleSegment) { + return serializeWaveformEnvelopeEffect(composed); + } + if (Flags.normalizedPwleEffects() && firstSegment instanceof BasicPwleSegment) { + return serializeBasicEnvelopeEffect(composed); + } return serializeWaveformEffect(composed); } @@ -110,6 +120,53 @@ public final class VibrationEffectXmlSerializer { return new SerializedComposedEffect(primitives); } + private static SerializedComposedEffect serializeWaveformEnvelopeEffect( + VibrationEffect.Composed effect) throws XmlSerializerException { + SerializedWaveformEnvelopeEffect.Builder builder = + new SerializedWaveformEnvelopeEffect.Builder(); + List segments = effect.getSegments(); + XmlValidator.checkSerializerCondition(effect.getRepeatIndex() == -1, + "Unsupported repeating waveform envelope effect %s", effect); + for (int i = 0; i < segments.size(); i++) { + XmlValidator.checkSerializerCondition(segments.get(i) instanceof PwleSegment, + "Unsupported segment for waveform envelope effect %s", segments.get(i)); + PwleSegment segment = (PwleSegment) segments.get(i); + + if (i == 0 && segment.getStartFrequencyHz() != segment.getEndFrequencyHz()) { + // Initial frequency explicitly defined. + builder.setInitialFrequencyHz(segment.getStartFrequencyHz()); + } + + builder.addControlPoint(segment.getEndAmplitude(), segment.getEndFrequencyHz(), + segment.getDuration()); + } + + return new SerializedComposedEffect(builder.build()); + } + + private static SerializedComposedEffect serializeBasicEnvelopeEffect( + VibrationEffect.Composed effect) throws XmlSerializerException { + SerializedBasicEnvelopeEffect.Builder builder = new SerializedBasicEnvelopeEffect.Builder(); + List segments = effect.getSegments(); + XmlValidator.checkSerializerCondition(effect.getRepeatIndex() == -1, + "Unsupported repeating basic envelope effect %s", effect); + for (int i = 0; i < segments.size(); i++) { + XmlValidator.checkSerializerCondition(segments.get(i) instanceof BasicPwleSegment, + "Unsupported segment for basic envelope effect %s", segments.get(i)); + BasicPwleSegment segment = (BasicPwleSegment) segments.get(i); + + if (i == 0 && segment.getStartSharpness() != segment.getEndSharpness()) { + // Initial sharpness explicitly defined. + builder.setInitialSharpness(segment.getStartSharpness()); + } + + builder.addControlPoint(segment.getEndIntensity(), segment.getEndSharpness(), + segment.getDuration()); + } + + return new SerializedComposedEffect(builder.build()); + } + private static SerializedComposedEffect serializeWaveformEffect( VibrationEffect.Composed effect) throws XmlSerializerException { SerializedAmplitudeStepWaveform.Builder serializedWaveformBuilder = diff --git a/core/java/com/android/internal/vibrator/persistence/XmlConstants.java b/core/java/com/android/internal/vibrator/persistence/XmlConstants.java index 4122215a2b04a5d197a0d26cb9f0b46cb28dff45..df262cfecd5ac472cbec621601973a62f3915e25 100644 --- a/core/java/com/android/internal/vibrator/persistence/XmlConstants.java +++ b/core/java/com/android/internal/vibrator/persistence/XmlConstants.java @@ -42,14 +42,22 @@ public final class XmlConstants { public static final String TAG_PREDEFINED_EFFECT = "predefined-effect"; public static final String TAG_PRIMITIVE_EFFECT = "primitive-effect"; public static final String TAG_VENDOR_EFFECT = "vendor-effect"; + public static final String TAG_WAVEFORM_ENVELOPE_EFFECT = "waveform-envelope-effect"; + public static final String TAG_BASIC_ENVELOPE_EFFECT = "basic-envelope-effect"; public static final String TAG_WAVEFORM_EFFECT = "waveform-effect"; public static final String TAG_WAVEFORM_ENTRY = "waveform-entry"; public static final String TAG_REPEATING = "repeating"; + public static final String TAG_CONTROL_POINT = "control-point"; public static final String ATTRIBUTE_NAME = "name"; public static final String ATTRIBUTE_FALLBACK = "fallback"; public static final String ATTRIBUTE_DURATION_MS = "durationMs"; public static final String ATTRIBUTE_AMPLITUDE = "amplitude"; + public static final String ATTRIBUTE_FREQUENCY_HZ = "frequencyHz"; + public static final String ATTRIBUTE_INITIAL_FREQUENCY_HZ = "initialFrequencyHz"; + public static final String ATTRIBUTE_INTENSITY = "intensity"; + public static final String ATTRIBUTE_SHARPNESS = "sharpness"; + public static final String ATTRIBUTE_INITIAL_SHARPNESS = "initialSharpness"; public static final String ATTRIBUTE_SCALE = "scale"; public static final String ATTRIBUTE_DELAY_MS = "delayMs"; public static final String ATTRIBUTE_DELAY_TYPE = "delayType"; diff --git a/core/java/com/android/internal/vibrator/persistence/XmlReader.java b/core/java/com/android/internal/vibrator/persistence/XmlReader.java index 0ac6fefc8cb2de37d260e3de9031ce45cd49fa7b..1c4a783f0fe47a8d6a1080d12dc996cb1ba938ef 100644 --- a/core/java/com/android/internal/vibrator/persistence/XmlReader.java +++ b/core/java/com/android/internal/vibrator/persistence/XmlReader.java @@ -221,12 +221,63 @@ public final class XmlReader { if (parser.getAttributeIndex(NAMESPACE, attrName) < 0) { return defaultValue; } + + return readAttributeFloatInRange(parser, attrName, lowerInclusive, upperInclusive); + } + + /** + * Read attribute from current tag as a float within given inclusive range. + */ + public static float readAttributeFloatInRange( + TypedXmlPullParser parser, String attrName, float lowerInclusive, + float upperInclusive) throws XmlParserException { String tagName = parser.getName(); float value = readAttributeFloat(parser, attrName); XmlValidator.checkParserCondition(value >= lowerInclusive && value <= upperInclusive, - "Unexpected %s = %f in tag %s, expected %s in [%f, %f]", - attrName, value, tagName, attrName, lowerInclusive, upperInclusive); + "Unexpected %s = %f in tag %s, expected %s in [%f, %f]", attrName, value, tagName, + attrName, lowerInclusive, upperInclusive); + return value; + } + + /** + * Read attribute from current tag as a positive float, returning default value if attribute + * is missing. + */ + public static float readAttributePositiveFloat(TypedXmlPullParser parser, String attrName, + float defaultValue) throws XmlParserException { + if (parser.getAttributeIndex(NAMESPACE, attrName) < 0) { + return defaultValue; + } + + return readAttributePositiveFloat(parser, attrName); + } + + /** + * Read attribute from current tag as a positive float. + */ + public static float readAttributePositiveFloat(TypedXmlPullParser parser, String attrName) + throws XmlParserException { + String tagName = parser.getName(); + float value = readAttributeFloat(parser, attrName); + + XmlValidator.checkParserCondition(value > 0, + "Unexpected %s = %d in tag %s, expected %s > 0", attrName, value, tagName, + attrName); + return value; + } + + /** + * Read attribute from current tag as a positive long. + */ + public static long readAttributePositiveLong(TypedXmlPullParser parser, String attrName) + throws XmlParserException { + String tagName = parser.getName(); + long value = readAttributeLong(parser, attrName); + + XmlValidator.checkParserCondition(value > 0, + "Unexpected %s = %d in tag %s, expected %s > 0", attrName, value, tagName, + attrName); return value; } @@ -251,4 +302,15 @@ public final class XmlReader { throw XmlParserException.createFromPullParserException(tagName, attrName, rawValue, e); } } + + private static long readAttributeLong(TypedXmlPullParser parser, String attrName) + throws XmlParserException { + String tagName = parser.getName(); + try { + return parser.getAttributeLong(NAMESPACE, attrName); + } catch (XmlPullParserException e) { + String rawValue = parser.getAttributeValue(NAMESPACE, attrName); + throw XmlParserException.createFromPullParserException(tagName, attrName, rawValue, e); + } + } } diff --git a/core/java/com/android/internal/view/ScrollCaptureInternal.java b/core/java/com/android/internal/view/ScrollCaptureInternal.java index 72b5488f4bac411bb5425dcc792ea256eff5b8d4..0ed0613d02e69f87a56376680e1802fc08907854 100644 --- a/core/java/com/android/internal/view/ScrollCaptureInternal.java +++ b/core/java/com/android/internal/view/ScrollCaptureInternal.java @@ -16,6 +16,8 @@ package com.android.internal.view; +import static android.view.flags.Flags.scrollCaptureRelaxScrollViewCriteria; + import android.annotation.Nullable; import android.content.Context; import android.content.res.Resources; @@ -49,7 +51,7 @@ public class ScrollCaptureInternal { public static final int TYPE_FIXED = 0; /** - * Slides a single child view using mScrollX/mScrollY. + * Moves the viewport across absolute positioned child views using the scrollY property. */ public static final int TYPE_SCROLLING = 1; @@ -63,7 +65,7 @@ public class ScrollCaptureInternal { /** * Unknown scrollable view with no child views (or not a subclass of ViewGroup). */ - private static final int TYPE_OPAQUE = 3; + public static final int TYPE_OPAQUE = 3; /** * Performs tests on the given View and determines: @@ -73,7 +75,7 @@ public class ScrollCaptureInternal { * This needs to be fast and not alloc memory. It's called on everything in the tree not marked * as excluded during scroll capture search. */ - private static int detectScrollingType(View view) { + public static int detectScrollingType(View view) { // Confirm that it can scroll. if (!(view.canScrollVertically(DOWN) || view.canScrollVertically(UP))) { // Nothing to scroll here, move along. @@ -95,25 +97,25 @@ public class ScrollCaptureInternal { if (DEBUG_VERBOSE) { Log.v(TAG, "hint: is a subclass of ViewGroup"); } - - // ScrollViews accept only a single child. - if (((ViewGroup) view).getChildCount() > 1) { - if (DEBUG_VERBOSE) { - Log.v(TAG, "hint: scrollable with multiple children"); + // Flag: Optionally allow ScrollView-like ViewGroups which have more than one child view. + if (!scrollCaptureRelaxScrollViewCriteria()) { + // ScrollViews accept only a single child. + if (((ViewGroup) view).getChildCount() > 1) { + if (DEBUG_VERBOSE) { + Log.v(TAG, "hint: scrollable with multiple children"); + } + return TYPE_RECYCLING; } - return TYPE_RECYCLING; } // At least one child view is required. - if (((ViewGroup) view).getChildCount() < 1) { - if (DEBUG_VERBOSE) { - Log.v(TAG, "scrollable with no children"); - } + if (((ViewGroup) view).getChildCount() == 0) { + Log.w(TAG, "scrollable but no children!"); return TYPE_OPAQUE; } if (DEBUG_VERBOSE) { Log.v(TAG, "hint: single child view"); } - //Because recycling containers don't use scrollY, a non-zero value means Scroll view. + // Because recycling containers don't use scrollY, a non-zero value means Scroll view. if (view.getScrollY() != 0) { if (DEBUG_VERBOSE) { Log.v(TAG, "hint: scrollY != 0"); @@ -132,7 +134,7 @@ public class ScrollCaptureInternal { Log.v(TAG, "hint: cannot be scrolled up"); } - // canScrollVertically(UP) == false, getScrollY() == 0, getChildCount() == 1. + // canScrollVertically(UP) == false, getScrollY() == 0, getChildCount() >= 1. // For Recycling containers, this should be a no-op (RecyclerView logs a warning) view.scrollTo(view.getScrollX(), 1); diff --git a/core/java/com/android/internal/widget/CallLayout.java b/core/java/com/android/internal/widget/CallLayout.java index c85257578492ee10df2489b4b2eb17835f106016..3a7c75afdd14402fe8a6020e442f932e0efa977d 100644 --- a/core/java/com/android/internal/widget/CallLayout.java +++ b/core/java/com/android/internal/widget/CallLayout.java @@ -30,7 +30,6 @@ import android.util.AttributeSet; import android.view.RemotableViewMethod; import android.widget.FrameLayout; import android.widget.RemoteViews; -import android.widget.TextView; import android.widget.flags.Flags; import com.android.internal.R; @@ -59,7 +58,6 @@ public class CallLayout extends FrameLayout { private CachingIconView mConversationIconView; private CachingIconView mIcon; private CachingIconView mConversationIconBadgeBg; - private TextView mConversationText; public CallLayout(@NonNull Context context) { super(context); @@ -83,7 +81,6 @@ public class CallLayout extends FrameLayout { protected void onFinishInflate() { super.onFinishInflate(); mPeopleHelper.init(getContext()); - mConversationText = findViewById(R.id.conversation_text); mConversationIconView = findViewById(R.id.conversation_icon); mIcon = findViewById(R.id.icon); mConversationIconBadgeBg = findViewById(R.id.conversation_icon_badge_bg); diff --git a/core/java/com/android/internal/widget/ConversationLayout.java b/core/java/com/android/internal/widget/ConversationLayout.java index 4b90420a75eecdaefccc2e0a98958aaaf69ea3ee..b3ab5d3cd258f4380cd977f7efe8517914447a5e 100644 --- a/core/java/com/android/internal/widget/ConversationLayout.java +++ b/core/java/com/android/internal/widget/ConversationLayout.java @@ -777,37 +777,40 @@ public class ConversationLayout extends FrameLayout } - int conversationAvatarSize; - int facepileAvatarSize; - int facePileBackgroundSize; - if (mIsCollapsed) { - conversationAvatarSize = mConversationAvatarSize; - facepileAvatarSize = mFacePileAvatarSize; - facePileBackgroundSize = facepileAvatarSize + 2 * mFacePileProtectionWidth; - } else { - conversationAvatarSize = mConversationAvatarSizeExpanded; - facepileAvatarSize = mFacePileAvatarSizeExpandedGroup; - facePileBackgroundSize = facepileAvatarSize + 2 * mFacePileProtectionWidthExpanded; - } - LayoutParams layoutParams = (LayoutParams) mConversationFacePile.getLayoutParams(); - layoutParams.width = conversationAvatarSize; - layoutParams.height = conversationAvatarSize; - mConversationFacePile.setLayoutParams(layoutParams); + if (!notificationsRedesignTemplates()) { + // We no longer need to update the size based on expansion state. + int conversationAvatarSize; + int facepileAvatarSize; + int facePileBackgroundSize; + if (mIsCollapsed) { + conversationAvatarSize = mConversationAvatarSize; + facepileAvatarSize = mFacePileAvatarSize; + facePileBackgroundSize = facepileAvatarSize + 2 * mFacePileProtectionWidth; + } else { + conversationAvatarSize = mConversationAvatarSizeExpanded; + facepileAvatarSize = mFacePileAvatarSizeExpandedGroup; + facePileBackgroundSize = facepileAvatarSize + 2 * mFacePileProtectionWidthExpanded; + } + LayoutParams layoutParams = (LayoutParams) mConversationFacePile.getLayoutParams(); + layoutParams.width = conversationAvatarSize; + layoutParams.height = conversationAvatarSize; + mConversationFacePile.setLayoutParams(layoutParams); - layoutParams = (LayoutParams) bottomView.getLayoutParams(); - layoutParams.width = facepileAvatarSize; - layoutParams.height = facepileAvatarSize; - bottomView.setLayoutParams(layoutParams); + layoutParams = (LayoutParams) bottomView.getLayoutParams(); + layoutParams.width = facepileAvatarSize; + layoutParams.height = facepileAvatarSize; + bottomView.setLayoutParams(layoutParams); - layoutParams = (LayoutParams) topView.getLayoutParams(); - layoutParams.width = facepileAvatarSize; - layoutParams.height = facepileAvatarSize; - topView.setLayoutParams(layoutParams); + layoutParams = (LayoutParams) topView.getLayoutParams(); + layoutParams.width = facepileAvatarSize; + layoutParams.height = facepileAvatarSize; + topView.setLayoutParams(layoutParams); - layoutParams = (LayoutParams) bottomBackground.getLayoutParams(); - layoutParams.width = facePileBackgroundSize; - layoutParams.height = facePileBackgroundSize; - bottomBackground.setLayoutParams(layoutParams); + layoutParams = (LayoutParams) bottomBackground.getLayoutParams(); + layoutParams.width = facePileBackgroundSize; + layoutParams.height = facePileBackgroundSize; + bottomBackground.setLayoutParams(layoutParams); + } } /** @@ -832,6 +835,11 @@ public class ConversationLayout extends FrameLayout * update the icon position and sizing */ private void updateIconPositionAndSize() { + if (notificationsRedesignTemplates()) { + // Icon size is fixed in the redesign. + return; + } + int badgeProtrusion; int conversationAvatarSize; if (mIsOneToOne || mIsCollapsed) { @@ -864,6 +872,11 @@ public class ConversationLayout extends FrameLayout } private void updatePaddingsBasedOnContentAvailability() { + if (notificationsRedesignTemplates()) { + // group icons have the same size as 1:1 conversations + return; + } + // groups have avatars that need more spacing mMessagingLinearLayout.setSpacing( mIsOneToOne ? mMessageSpacingStandard : mMessageSpacingGroup); diff --git a/core/java/com/android/internal/widget/flags.aconfig b/core/java/com/android/internal/widget/flags.aconfig new file mode 100644 index 0000000000000000000000000000000000000000..f05aa4f460a52719ada93942c29eb7e79f68c225 --- /dev/null +++ b/core/java/com/android/internal/widget/flags.aconfig @@ -0,0 +1,9 @@ +package: "com.android.internal.widget.flags" +container: "system" + +flag { + name: "hide_last_char_with_physical_input" + namespace: "input" + description: "Feature flag for changing the default of hiding the last interacted symbol when a physical input device is present" + bug: "339270220" +} diff --git a/core/java/com/android/internal/widget/floatingtoolbar/LocalFloatingToolbarPopup.java b/core/java/com/android/internal/widget/floatingtoolbar/LocalFloatingToolbarPopup.java index 38685b652c5081e5c576a03dfc9c1f2bda723ce7..5177a03600327eeeefef0a9707e0cb65b8ec5f49 100644 --- a/core/java/com/android/internal/widget/floatingtoolbar/LocalFloatingToolbarPopup.java +++ b/core/java/com/android/internal/widget/floatingtoolbar/LocalFloatingToolbarPopup.java @@ -435,10 +435,15 @@ public final class LocalFloatingToolbarPopup implements FloatingToolbarPopup { private void refreshCoordinatesAndOverflowDirection(Rect contentRectOnScreen) { refreshViewPort(); - // Initialize x ensuring that the toolbar isn't rendered behind the nav bar in - // landscape. - final int x = Math.clamp(contentRectOnScreen.centerX() - mPopupWindow.getWidth() / 2, - mViewPortOnScreen.left, mViewPortOnScreen.right - mPopupWindow.getWidth()); + final int x; + if (mPopupWindow.getWidth() > mViewPortOnScreen.width()) { + // Not enough space - prefer to position as far left as possible + x = mViewPortOnScreen.left; + } else { + // Initialize x ensuring that the toolbar isn't rendered behind the system bar insets + x = Math.clamp(contentRectOnScreen.centerX() - mPopupWindow.getWidth() / 2, + mViewPortOnScreen.left, mViewPortOnScreen.right - mPopupWindow.getWidth()); + } final int y; diff --git a/core/java/com/android/internal/widget/remotecompose/accessibility/AndroidPlatformSemanticNodeApplier.java b/core/java/com/android/internal/widget/remotecompose/accessibility/AndroidPlatformSemanticNodeApplier.java new file mode 100644 index 0000000000000000000000000000000000000000..1bdbaa48d18ca30debc46b05db23bb51cb3be044 --- /dev/null +++ b/core/java/com/android/internal/widget/remotecompose/accessibility/AndroidPlatformSemanticNodeApplier.java @@ -0,0 +1,86 @@ +/* + * Copyright (C) 2024 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES 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.widget.remotecompose.accessibility; + +import android.graphics.Rect; +import android.view.accessibility.AccessibilityNodeInfo; + +public class AndroidPlatformSemanticNodeApplier + extends BaseSemanticNodeApplier { + + private static final String ROLE_DESCRIPTION_KEY = "AccessibilityNodeInfo.roleDescription"; + + @Override + protected void setClickable(AccessibilityNodeInfo nodeInfo, boolean clickable) { + nodeInfo.setClickable(clickable); + if (clickable) { + nodeInfo.addAction(AccessibilityNodeInfo.AccessibilityAction.ACTION_CLICK); + } else { + nodeInfo.removeAction(AccessibilityNodeInfo.AccessibilityAction.ACTION_CLICK); + } + } + + @Override + protected void setEnabled(AccessibilityNodeInfo nodeInfo, boolean enabled) { + nodeInfo.setEnabled(enabled); + } + + @Override + protected CharSequence getStateDescription(AccessibilityNodeInfo nodeInfo) { + return nodeInfo.getStateDescription(); + } + + @Override + protected void setStateDescription(AccessibilityNodeInfo nodeInfo, CharSequence description) { + nodeInfo.setStateDescription(description); + } + + @Override + protected void setRoleDescription(AccessibilityNodeInfo nodeInfo, String description) { + nodeInfo.getExtras().putCharSequence(ROLE_DESCRIPTION_KEY, description); + } + + @Override + protected CharSequence getText(AccessibilityNodeInfo nodeInfo) { + return nodeInfo.getText(); + } + + @Override + protected void setText(AccessibilityNodeInfo nodeInfo, CharSequence text) { + nodeInfo.setText(text); + } + + @Override + protected CharSequence getContentDescription(AccessibilityNodeInfo nodeInfo) { + return nodeInfo.getContentDescription(); + } + + @Override + protected void setContentDescription(AccessibilityNodeInfo nodeInfo, CharSequence description) { + nodeInfo.setContentDescription(description); + } + + @Override + protected void setBoundsInScreen(AccessibilityNodeInfo nodeInfo, Rect bounds) { + nodeInfo.setBoundsInParent(bounds); + nodeInfo.setBoundsInScreen(bounds); + } + + @Override + protected void setUniqueId(AccessibilityNodeInfo nodeInfo, String id) { + nodeInfo.setUniqueId(id); + } +} diff --git a/core/java/com/android/internal/widget/remotecompose/accessibility/BaseSemanticNodeApplier.java b/core/java/com/android/internal/widget/remotecompose/accessibility/BaseSemanticNodeApplier.java new file mode 100644 index 0000000000000000000000000000000000000000..228afb88b5de8463920b04205f6b8036d1da4055 --- /dev/null +++ b/core/java/com/android/internal/widget/remotecompose/accessibility/BaseSemanticNodeApplier.java @@ -0,0 +1,208 @@ +/* + * Copyright (C) 2024 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES 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.widget.remotecompose.accessibility; + +import android.graphics.Rect; + +import com.android.internal.widget.remotecompose.core.operations.layout.Component; +import com.android.internal.widget.remotecompose.core.semantics.AccessibilitySemantics; +import com.android.internal.widget.remotecompose.core.semantics.AccessibleComponent; +import com.android.internal.widget.remotecompose.core.semantics.CoreSemantics; + +import java.util.List; + +/** + * Base class for applying semantic information to a node. + * + *

    This class provides common functionality for applying semantic information extracted from + * Compose UI components to a node representation used for accessibility purposes. It handles + * applying properties like content description, text, role, clickability, and bounds. + * + *

    Subclasses are responsible for implementing methods to actually set these properties on the + * specific node type they handle. + * + * @param The type of node this applier works with. + */ +public abstract class BaseSemanticNodeApplier implements SemanticNodeApplier { + @Override + public void applyComponent( + RemoteComposeDocumentAccessibility remoteComposeAccessibility, + N nodeInfo, + Component component, + List semantics) { + float[] locationInWindow = new float[2]; + component.getLocationInWindow(locationInWindow); + Rect bounds = + new Rect( + (int) locationInWindow[0], + (int) locationInWindow[1], + (int) (locationInWindow[0] + component.getWidth()), + (int) (locationInWindow[1] + component.getHeight())); + setBoundsInScreen(nodeInfo, bounds); + + setUniqueId(nodeInfo, String.valueOf(component.getComponentId())); + + if (component instanceof AccessibleComponent) { + applyContentDescription( + ((AccessibleComponent) component).getContentDescriptionId(), + nodeInfo, + remoteComposeAccessibility); + + applyText( + ((AccessibleComponent) component).getTextId(), + nodeInfo, + remoteComposeAccessibility); + + applyRole(((AccessibleComponent) component).getRole(), nodeInfo); + } + + applySemantics(remoteComposeAccessibility, nodeInfo, semantics); + + if (getText(nodeInfo) == null && getContentDescription(nodeInfo) == null) { + setContentDescription(nodeInfo, ""); + } + } + + protected void applySemantics( + RemoteComposeDocumentAccessibility remoteComposeAccessibility, + N nodeInfo, + List semantics) { + for (AccessibilitySemantics semantic : semantics) { + if (semantic.isInterestingForSemantics()) { + if (semantic instanceof CoreSemantics) { + CoreSemantics coreSemantics = (CoreSemantics) semantic; + applyCoreSemantics(remoteComposeAccessibility, nodeInfo, coreSemantics); + } else if (semantic instanceof AccessibleComponent) { + AccessibleComponent accessibleComponent = (AccessibleComponent) semantic; + if (accessibleComponent.isClickable()) { + setClickable(nodeInfo, true); + } + + if (accessibleComponent.getContentDescriptionId() != null) { + applyContentDescription( + accessibleComponent.getContentDescriptionId(), + nodeInfo, + remoteComposeAccessibility); + } + + if (accessibleComponent.getTextId() != null) { + applyText( + accessibleComponent.getTextId(), + nodeInfo, + remoteComposeAccessibility); + } + + applyRole(accessibleComponent.getRole(), nodeInfo); + } + } + } + } + + protected void applyCoreSemantics( + RemoteComposeDocumentAccessibility remoteComposeAccessibility, + N nodeInfo, + CoreSemantics coreSemantics) { + applyContentDescription( + coreSemantics.getContentDescriptionId(), nodeInfo, remoteComposeAccessibility); + + applyRole(coreSemantics.getRole(), nodeInfo); + + applyText(coreSemantics.getTextId(), nodeInfo, remoteComposeAccessibility); + + applyStateDescription( + coreSemantics.getStateDescriptionId(), nodeInfo, remoteComposeAccessibility); + + if (!coreSemantics.mEnabled) { + setEnabled(nodeInfo, false); + } + } + + protected void applyStateDescription( + Integer stateDescriptionId, + N nodeInfo, + RemoteComposeDocumentAccessibility remoteComposeAccessibility) { + if (stateDescriptionId != null) { + setStateDescription( + nodeInfo, + appendNullable( + getStateDescription(nodeInfo), + remoteComposeAccessibility.stringValue(stateDescriptionId))); + } + } + + protected void applyRole(AccessibleComponent.Role role, N nodeInfo) { + if (role != null) { + setRoleDescription(nodeInfo, role.getDescription()); + } + } + + protected void applyText( + Integer textId, + N nodeInfo, + RemoteComposeDocumentAccessibility remoteComposeAccessibility) { + if (textId != null) { + setText( + nodeInfo, + appendNullable( + getText(nodeInfo), remoteComposeAccessibility.stringValue(textId))); + } + } + + protected void applyContentDescription( + Integer contentDescriptionId, + N nodeInfo, + RemoteComposeDocumentAccessibility remoteComposeAccessibility) { + if (contentDescriptionId != null) { + setContentDescription( + nodeInfo, + appendNullable( + getContentDescription(nodeInfo), + remoteComposeAccessibility.stringValue(contentDescriptionId))); + } + } + + private CharSequence appendNullable(CharSequence contentDescription, String value) { + if (contentDescription == null) { + return value; + } else if (value == null) { + return contentDescription; + } else { + return contentDescription + " " + value; + } + } + + protected abstract void setClickable(N nodeInfo, boolean b); + + protected abstract void setEnabled(N nodeInfo, boolean b); + + protected abstract CharSequence getStateDescription(N nodeInfo); + + protected abstract void setStateDescription(N nodeInfo, CharSequence charSequence); + + protected abstract void setRoleDescription(N nodeInfo, String description); + + protected abstract CharSequence getText(N nodeInfo); + + protected abstract void setText(N nodeInfo, CharSequence charSequence); + + protected abstract CharSequence getContentDescription(N nodeInfo); + + protected abstract void setContentDescription(N nodeInfo, CharSequence charSequence); + + protected abstract void setBoundsInScreen(N nodeInfo, Rect bounds); + + protected abstract void setUniqueId(N nodeInfo, String s); +} diff --git a/core/java/com/android/internal/widget/remotecompose/accessibility/CoreDocumentAccessibility.java b/core/java/com/android/internal/widget/remotecompose/accessibility/CoreDocumentAccessibility.java new file mode 100644 index 0000000000000000000000000000000000000000..2cd4f0362306c0629f2434c5a5364c6219c76a38 --- /dev/null +++ b/core/java/com/android/internal/widget/remotecompose/accessibility/CoreDocumentAccessibility.java @@ -0,0 +1,210 @@ +/* + * Copyright (C) 2024 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES 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.widget.remotecompose.accessibility; + +import android.annotation.Nullable; +import android.graphics.PointF; +import android.os.Bundle; + +import com.android.internal.widget.remotecompose.core.CoreDocument; +import com.android.internal.widget.remotecompose.core.Operation; +import com.android.internal.widget.remotecompose.core.operations.layout.ClickModifierOperation; +import com.android.internal.widget.remotecompose.core.operations.layout.Component; +import com.android.internal.widget.remotecompose.core.operations.layout.LayoutComponent; +import com.android.internal.widget.remotecompose.core.operations.layout.RootLayoutComponent; +import com.android.internal.widget.remotecompose.core.operations.layout.modifiers.ComponentModifiers; +import com.android.internal.widget.remotecompose.core.operations.layout.modifiers.ModifierOperation; +import com.android.internal.widget.remotecompose.core.semantics.AccessibilitySemantics; +import com.android.internal.widget.remotecompose.core.semantics.AccessibleComponent; +import com.android.internal.widget.remotecompose.core.semantics.CoreSemantics; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import java.util.stream.Collectors; +import java.util.stream.Stream; + +/** + * Java Player implementation of the {@link RemoteComposeDocumentAccessibility} interface. Each item + * in the semantic tree is a {@link Component} from the remote Compose UI. Each Component can have a + * list of modifiers that must be tagged with {@link AccessibilitySemantics} either incidentally + * (see {@link ClickModifierOperation}) or explicitly (see {@link CoreSemantics}). + */ +public class CoreDocumentAccessibility implements RemoteComposeDocumentAccessibility { + private final CoreDocument mDocument; + + public CoreDocumentAccessibility(CoreDocument document) { + this.mDocument = document; + } + + @Nullable + @Override + public Integer getComponentIdAt(PointF point) { + return RootId; + } + + @Override + public @Nullable Component findComponentById(int virtualViewId) { + RootLayoutComponent root = mDocument.getRootLayoutComponent(); + + if (root == null || virtualViewId == -1) { + return root; + } + + return componentStream(root) + .filter(op -> op.getComponentId() == virtualViewId) + .findFirst() + .orElse(null); + } + + @Override + public CoreSemantics.Mode mergeMode(Component component) { + if (!(component instanceof LayoutComponent)) { + return CoreSemantics.Mode.SET; + } + + CoreSemantics.Mode result = CoreSemantics.Mode.SET; + + for (ModifierOperation modifier : + ((LayoutComponent) component).getComponentModifiers().getList()) { + if (modifier instanceof AccessibleComponent) { + AccessibleComponent semantics = (AccessibleComponent) modifier; + + if (semantics.getMode().ordinal() > result.ordinal()) { + result = semantics.getMode(); + } + } + } + + return result; + } + + @Override + public boolean performAction(Component component, int action, Bundle arguments) { + if (action == ACTION_CLICK) { + mDocument.performClick(component.getComponentId()); + return true; + } else { + return false; + } + } + + @Nullable + @Override + public String stringValue(int id) { + Object value = mDocument.getRemoteComposeState().getFromId(id); + + return value != null ? String.valueOf(value) : null; + } + + @Override + public List semanticModifiersForComponent(Component component) { + if (!(component instanceof LayoutComponent)) { + return Collections.emptyList(); + } + + List modifiers = + ((LayoutComponent) component).getComponentModifiers().getList(); + + return modifiers.stream() + .filter( + it -> + it instanceof AccessibilitySemantics + && ((AccessibilitySemantics) it) + .isInterestingForSemantics()) + .map(i -> (AccessibilitySemantics) i) + .collect(Collectors.toList()); + } + + @Override + public List semanticallyRelevantChildComponents( + Component component, boolean useUnmergedTree) { + if (!component.isVisible()) { + return Collections.emptyList(); + } + + CoreSemantics.Mode mergeMode = mergeMode(component); + if (mergeMode == CoreSemantics.Mode.CLEAR_AND_SET + || (!useUnmergedTree && mergeMode == CoreSemantics.Mode.MERGE)) { + return Collections.emptyList(); + } + + ArrayList result = new ArrayList<>(); + + for (Operation child : component.mList) { + if (child instanceof Component) { + if (isInteresting((Component) child)) { + result.add(((Component) child).getComponentId()); + } else { + result.addAll( + semanticallyRelevantChildComponents( + (Component) child, useUnmergedTree)); + } + } + } + + return result; + } + + static Stream componentStream(Component root) { + return Stream.concat( + Stream.of(root), + root.mList.stream() + .flatMap( + op -> { + if (op instanceof Component) { + return componentStream((Component) op); + } else { + return Stream.empty(); + } + })); + } + + static Stream modifiersStream(Component component) { + return component.mList.stream() + .filter(it -> it instanceof ComponentModifiers) + .flatMap(it -> ((ComponentModifiers) it).getList().stream()); + } + + static boolean isInteresting(Component component) { + if (!component.isVisible()) { + return false; + } + + return isContainerWithSemantics(component) + || modifiersStream(component) + .anyMatch(CoreDocumentAccessibility::isModifierWithSemantics); + } + + static boolean isModifierWithSemantics(ModifierOperation modifier) { + return modifier instanceof AccessibilitySemantics + && ((AccessibilitySemantics) modifier).isInterestingForSemantics(); + } + + static boolean isContainerWithSemantics(Component component) { + if (component instanceof AccessibilitySemantics) { + return ((AccessibilitySemantics) component).isInterestingForSemantics(); + } + + if (!(component instanceof LayoutComponent)) { + return false; + } + + return ((LayoutComponent) component) + .getComponentModifiers().getList().stream() + .anyMatch(CoreDocumentAccessibility::isModifierWithSemantics); + } +} diff --git a/core/java/com/android/internal/widget/remotecompose/accessibility/PlatformRemoteComposeAccessibilityRegistrar.java b/core/java/com/android/internal/widget/remotecompose/accessibility/PlatformRemoteComposeAccessibilityRegistrar.java new file mode 100644 index 0000000000000000000000000000000000000000..010253e9cb95b382e30cecc8c547555f87e9a8be --- /dev/null +++ b/core/java/com/android/internal/widget/remotecompose/accessibility/PlatformRemoteComposeAccessibilityRegistrar.java @@ -0,0 +1,46 @@ +/* + * Copyright (C) 2024 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES 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.widget.remotecompose.accessibility; + +import android.annotation.NonNull; +import android.view.View; + +import com.android.internal.widget.remotecompose.core.CoreDocument; + +/** + * Trivial wrapper for calling setAccessibilityDelegate on a View. This exists primarily because the + * RemoteDocumentPlayer is either running in the platform on a known API version, or outside in + * which case it must use the Androidx ViewCompat class. + */ +public class PlatformRemoteComposeAccessibilityRegistrar + implements RemoteComposeAccessibilityRegistrar { + public PlatformRemoteComposeTouchHelper forRemoteComposePlayer( + View player, @NonNull CoreDocument coreDocument) { + return new PlatformRemoteComposeTouchHelper( + player, + new CoreDocumentAccessibility(coreDocument), + new AndroidPlatformSemanticNodeApplier()); + } + + public void setAccessibilityDelegate(View remoteComposePlayer, CoreDocument document) { + remoteComposePlayer.setAccessibilityDelegate( + forRemoteComposePlayer(remoteComposePlayer, document)); + } + + public void clearAccessibilityDelegate(View remoteComposePlayer) { + remoteComposePlayer.setAccessibilityDelegate(null); + } +} diff --git a/core/java/com/android/internal/widget/remotecompose/accessibility/PlatformRemoteComposeTouchHelper.java b/core/java/com/android/internal/widget/remotecompose/accessibility/PlatformRemoteComposeTouchHelper.java new file mode 100644 index 0000000000000000000000000000000000000000..39a2ab3010acd9e89536241bf346129f74ef0c37 --- /dev/null +++ b/core/java/com/android/internal/widget/remotecompose/accessibility/PlatformRemoteComposeTouchHelper.java @@ -0,0 +1,167 @@ +/* + * Copyright (C) 2024 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES 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.widget.remotecompose.accessibility; + +import static com.android.internal.widget.remotecompose.accessibility.RemoteComposeDocumentAccessibility.RootId; + +import android.annotation.NonNull; +import android.annotation.Nullable; +import android.graphics.PointF; +import android.os.Bundle; +import android.util.IntArray; +import android.view.View; +import android.view.accessibility.AccessibilityEvent; +import android.view.accessibility.AccessibilityNodeInfo; + +import com.android.internal.widget.ExploreByTouchHelper; +import com.android.internal.widget.remotecompose.core.CoreDocument; +import com.android.internal.widget.remotecompose.core.operations.layout.Component; +import com.android.internal.widget.remotecompose.core.semantics.AccessibilitySemantics; +import com.android.internal.widget.remotecompose.core.semantics.CoreSemantics.Mode; + +import java.util.HashSet; +import java.util.List; +import java.util.Set; +import java.util.Stack; + +public class PlatformRemoteComposeTouchHelper extends ExploreByTouchHelper { + private final RemoteComposeDocumentAccessibility mRemoteDocA11y; + + private final SemanticNodeApplier mApplier; + + public PlatformRemoteComposeTouchHelper( + View host, + RemoteComposeDocumentAccessibility remoteDocA11y, + SemanticNodeApplier applier) { + super(host); + this.mRemoteDocA11y = remoteDocA11y; + this.mApplier = applier; + } + + public static PlatformRemoteComposeTouchHelper forRemoteComposePlayer( + View player, @NonNull CoreDocument coreDocument) { + return new PlatformRemoteComposeTouchHelper( + player, + new CoreDocumentAccessibility(coreDocument), + new AndroidPlatformSemanticNodeApplier()); + } + + /** + * Gets the virtual view ID at a given location on the screen. + * + *

    This method is called by the Accessibility framework to determine which virtual view, if + * any, is located at a specific point on the screen. It uses the {@link + * RemoteComposeDocumentAccessibility#getComponentIdAt(PointF)} method to find the ID of the + * component at the given coordinates. + * + * @param x The x-coordinate of the location in pixels. + * @param y The y-coordinate of the location in pixels. + * @return The ID of the virtual view at the given location, or {@link #INVALID_ID} if no + * virtual view is found at that location. + */ + @Override + protected int getVirtualViewAt(float x, float y) { + Integer root = mRemoteDocA11y.getComponentIdAt(new PointF(x, y)); + + if (root == null) { + return INVALID_ID; + } + + return root; + } + + /** + * Populates a list with the visible virtual view IDs. + * + *

    This method is called by the accessibility framework to retrieve the IDs of all visible + * virtual views in the accessibility hierarchy. It traverses the hierarchy starting from the + * root node (RootId) and adds the ID of each visible view to the provided list. + * + * @param virtualViewIds The list to be populated with the visible virtual view IDs. + */ + @Override + protected void getVisibleVirtualViews(IntArray virtualViewIds) { + Stack toVisit = new Stack<>(); + Set visited = new HashSet<>(); + + toVisit.push(RootId); + + while (!toVisit.isEmpty()) { + Integer componentId = toVisit.remove(0); + + if (visited.add(componentId)) { + Component component = mRemoteDocA11y.findComponentById(componentId); + + // Only include the root when it has semantics such as content description + if (!RootId.equals(componentId) + || !mRemoteDocA11y.semanticModifiersForComponent(component).isEmpty()) { + virtualViewIds.add(componentId); + } + + if (component != null) { + Mode mergeMode = mRemoteDocA11y.mergeMode(component); + + if (mergeMode == Mode.SET) { + List childViews = + mRemoteDocA11y.semanticallyRelevantChildComponents( + component, false); + + toVisit.addAll(childViews); + } + } + } + } + } + + @Override + public void onPopulateNodeForVirtualView( + int virtualViewId, @NonNull AccessibilityNodeInfo node) { + Component component = mRemoteDocA11y.findComponentById(virtualViewId); + + Mode mergeMode = mRemoteDocA11y.mergeMode(component); + + // default to enabled + node.setEnabled(true); + + if (mergeMode == Mode.MERGE) { + List childViews = + mRemoteDocA11y.semanticallyRelevantChildComponents(component, true); + + for (Integer childView : childViews) { + onPopulateNodeForVirtualView(childView, node); + } + } + + List semantics = + mRemoteDocA11y.semanticModifiersForComponent(component); + mApplier.applyComponent(mRemoteDocA11y, node, component, semantics); + } + + @Override + protected void onPopulateEventForVirtualView(int virtualViewId, AccessibilityEvent event) {} + + @Override + protected boolean onPerformActionForVirtualView( + int virtualViewId, int action, @Nullable Bundle arguments) { + Component component = mRemoteDocA11y.findComponentById(virtualViewId); + + if (component != null) { + return mRemoteDocA11y.performAction(component, action, arguments); + } else { + return false; + } + } +} diff --git a/core/java/com/android/internal/widget/remotecompose/accessibility/RemoteComposeAccessibilityRegistrar.java b/core/java/com/android/internal/widget/remotecompose/accessibility/RemoteComposeAccessibilityRegistrar.java new file mode 100644 index 0000000000000000000000000000000000000000..7e8236b35e9709a3bae1d6c3350787d308fca3ef --- /dev/null +++ b/core/java/com/android/internal/widget/remotecompose/accessibility/RemoteComposeAccessibilityRegistrar.java @@ -0,0 +1,33 @@ +/* + * Copyright (C) 2024 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES 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.widget.remotecompose.accessibility; + +import android.view.View; + +import com.android.internal.widget.remotecompose.core.CoreDocument; + +/** + * Interface for registering and clearing accessibility delegates for remote compose players. + * + *

    This interface is responsible for managing the accessibility delegate associated with a remote + * compose player view. It allows for setting and clearing the delegate, which is used to handle + * accessibility events and provide accessibility information for the remote compose content. + */ +public interface RemoteComposeAccessibilityRegistrar { + void setAccessibilityDelegate(View remoteComposePlayer, CoreDocument document); + + void clearAccessibilityDelegate(View remoteComposePlayer); +} diff --git a/core/java/com/android/internal/widget/remotecompose/accessibility/RemoteComposeDocumentAccessibility.java b/core/java/com/android/internal/widget/remotecompose/accessibility/RemoteComposeDocumentAccessibility.java new file mode 100644 index 0000000000000000000000000000000000000000..50f75e4889ddc7e1bb0dff1bfdc851ab2942eb2f --- /dev/null +++ b/core/java/com/android/internal/widget/remotecompose/accessibility/RemoteComposeDocumentAccessibility.java @@ -0,0 +1,100 @@ +/* + * Copyright (C) 2024 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES 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.widget.remotecompose.accessibility; + +import android.annotation.Nullable; +import android.graphics.PointF; +import android.os.Bundle; +import android.view.View; + +import com.android.internal.widget.remotecompose.core.operations.layout.Component; +import com.android.internal.widget.remotecompose.core.semantics.AccessibilitySemantics; +import com.android.internal.widget.remotecompose.core.semantics.CoreSemantics; + +import java.util.List; + +/** + * Interface for interacting with the accessibility features of a remote Compose UI. This interface + * provides methods to perform actions, retrieve state, and query the accessibility tree of the + * remote Compose UI. + */ +public interface RemoteComposeDocumentAccessibility { + // Matches ExploreByTouchHelper.HOST_ID + Integer RootId = View.NO_ID; + + // androidx.core.view.accessibility.AccessibilityNodeInfoCompat.ACTION_CLICK + int ACTION_CLICK = 0x00000010; + + /** + * Performs the specified action on the given component. + * + * @param component The component on which to perform the action. + * @param action The action to perform. + * @param arguments Optional arguments for the action. + * @return {@code true} if the action was performed successfully, {@code false} otherwise. + */ + boolean performAction(Component component, int action, Bundle arguments); + + /** + * Retrieves the string value associated with the given ID. + * + * @param id The ID to retrieve the string value for. + * @return The string value associated with the ID, or {@code null} if no such value exists. + */ + @Nullable + String stringValue(int id); + + /** + * Retrieves a list of child view IDs semantically contained within the given component/virtual + * view. These may later be hidden from accessibility services by properties, but should contain + * only possibly semantically relevant virtual views. + * + * @param component The component to retrieve child view IDs from, or [RootId] for the top + * level. + * @param useUnmergedTree Whether to include merged children + * @return A list of integer IDs representing the child views of the component. + */ + List semanticallyRelevantChildComponents(Component component, boolean useUnmergedTree); + + /** + * Retrieves the semantic modifiers associated with a given component. + * + * @param component The component for which to retrieve semantic modifiers. + * @return A list of semantic modifiers applicable to the component. + */ + List semanticModifiersForComponent(Component component); + + /** + * Gets all applied merge modes of the given component. A Merge mode is one of Set, Merge or + * Clear and describes how to apply and combine hierarchical semantics. + * + * @param component The component to merge the mode for. + * @return The effective merge modes, potentially conflicting but resolved to a single value. + */ + CoreSemantics.Mode mergeMode(Component component); + + /** + * Finds a component by its ID. + * + * @param id the ID of the component to find + * @return the component with the given ID, or {@code null} if no such component exists + */ + @Nullable + Component findComponentById(int id); + + @Nullable + Integer getComponentIdAt(PointF point); +} diff --git a/core/java/com/android/internal/widget/remotecompose/accessibility/RemoteComposeTouchHelper.java b/core/java/com/android/internal/widget/remotecompose/accessibility/RemoteComposeTouchHelper.java new file mode 100644 index 0000000000000000000000000000000000000000..13641025a33b1c37001ddfa48a5f3a20c3f6a879 --- /dev/null +++ b/core/java/com/android/internal/widget/remotecompose/accessibility/RemoteComposeTouchHelper.java @@ -0,0 +1,25 @@ +/* + * Copyright (C) 2024 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES 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.widget.remotecompose.accessibility; + +/** + * This class is the entry point for finding the AccessibilityDelegate for a RemoteCompose document. + */ +public class RemoteComposeTouchHelper { + /** Get the platform specific accessibility delegate registrar */ + public static final RemoteComposeAccessibilityRegistrar REGISTRAR = + new PlatformRemoteComposeAccessibilityRegistrar(); +} diff --git a/core/java/com/android/internal/widget/remotecompose/accessibility/SemanticNodeApplier.java b/core/java/com/android/internal/widget/remotecompose/accessibility/SemanticNodeApplier.java new file mode 100644 index 0000000000000000000000000000000000000000..832b5426f4767c25545fc327921b7d22ea62cfc1 --- /dev/null +++ b/core/java/com/android/internal/widget/remotecompose/accessibility/SemanticNodeApplier.java @@ -0,0 +1,44 @@ +/* + * Copyright (C) 2024 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES 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.widget.remotecompose.accessibility; + +import com.android.internal.widget.remotecompose.core.operations.layout.Component; +import com.android.internal.widget.remotecompose.core.semantics.AccessibilitySemantics; + +import java.util.List; + +/** + * An interface for applying semantic information to a semantics node. + * + *

    Implementations of this interface are responsible for taking a node represented by [nodeInfo] + * and applying a list of [semantics] (representing accessible actions and properties) to it. This + * process might involve: - Modifying the node's properties (e.g., content description, clickable + * state). - Adding a child node to represent a specific semantic element. - Performing any other + * action necessary to make the node semantically meaningful and accessible to assistive + * technologies. + * + * @param The type representing information about the node. This could be an Androidx + * `AccessibilityNodeInfoCompat`, or potentially a platform `AccessibilityNodeInfo`. + */ +public interface SemanticNodeApplier { + void applyComponent( + RemoteComposeDocumentAccessibility remoteComposeAccessibility, + N nodeInfo, + Component component, + List semantics); + + String VIRTUAL_VIEW_ID_KEY = "VirtualViewId"; +} diff --git a/core/java/com/android/internal/widget/remotecompose/core/CoreDocument.java b/core/java/com/android/internal/widget/remotecompose/core/CoreDocument.java index 370289a84502f24cdb33d0404046c0af9e9f40c5..33f93fccff5810fa31bf637bfd7c45316389bafc 100644 --- a/core/java/com/android/internal/widget/remotecompose/core/CoreDocument.java +++ b/core/java/com/android/internal/widget/remotecompose/core/CoreDocument.java @@ -18,17 +18,19 @@ package com.android.internal.widget.remotecompose.core; import android.annotation.NonNull; import android.annotation.Nullable; +import com.android.internal.annotations.VisibleForTesting; import com.android.internal.widget.remotecompose.core.operations.ComponentValue; import com.android.internal.widget.remotecompose.core.operations.FloatExpression; import com.android.internal.widget.remotecompose.core.operations.IntegerExpression; import com.android.internal.widget.remotecompose.core.operations.NamedVariable; import com.android.internal.widget.remotecompose.core.operations.RootContentBehavior; +import com.android.internal.widget.remotecompose.core.operations.ShaderData; +import com.android.internal.widget.remotecompose.core.operations.TextData; import com.android.internal.widget.remotecompose.core.operations.Theme; import com.android.internal.widget.remotecompose.core.operations.layout.ClickModifierOperation; import com.android.internal.widget.remotecompose.core.operations.layout.Component; import com.android.internal.widget.remotecompose.core.operations.layout.ComponentEnd; import com.android.internal.widget.remotecompose.core.operations.layout.ComponentStartOperation; -import com.android.internal.widget.remotecompose.core.operations.layout.LayoutComponent; import com.android.internal.widget.remotecompose.core.operations.layout.LoopEnd; import com.android.internal.widget.remotecompose.core.operations.layout.LoopOperation; import com.android.internal.widget.remotecompose.core.operations.layout.OperationsListEnd; @@ -38,12 +40,14 @@ import com.android.internal.widget.remotecompose.core.operations.layout.TouchDow import com.android.internal.widget.remotecompose.core.operations.layout.TouchUpModifierOperation; import com.android.internal.widget.remotecompose.core.operations.layout.modifiers.ComponentModifiers; import com.android.internal.widget.remotecompose.core.operations.layout.modifiers.ModifierOperation; +import com.android.internal.widget.remotecompose.core.operations.layout.modifiers.ScrollModifierOperation; import com.android.internal.widget.remotecompose.core.operations.utilities.StringSerializer; import java.util.ArrayList; import java.util.HashMap; import java.util.HashSet; import java.util.List; +import java.util.Objects; import java.util.Set; /** @@ -53,13 +57,14 @@ import java.util.Set; public class CoreDocument { private static final boolean DEBUG = false; + private static final int DOCUMENT_API_LEVEL = 2; @NonNull ArrayList mOperations = new ArrayList<>(); @Nullable RootLayoutComponent mRootLayoutComponent = null; @NonNull RemoteComposeState mRemoteComposeState = new RemoteComposeState(); - @NonNull TimeVariables mTimeVariables = new TimeVariables(); + @VisibleForTesting @NonNull public TimeVariables mTimeVariables = new TimeVariables(); // Semantic version of the document @NonNull Version mVersion = new Version(0, 1, 0); @@ -86,6 +91,11 @@ public class CoreDocument { private int mLastId = 1; // last component id when inflating the file + /** Returns a version number that is monotonically increasing. */ + public static int getDocumentApiLevel() { + return DOCUMENT_API_LEVEL; + } + @Nullable public String getContentDescription() { return mContentDescription; @@ -434,11 +444,11 @@ public class CoreDocument { mActionListeners.clear(); } - public interface ClickCallbacks { - void click(int id, @Nullable String metadata); + public interface IdActionCallback { + void onAction(int id, @Nullable String metadata); } - @NonNull HashSet mClickListeners = new HashSet<>(); + @NonNull HashSet mIdActionListeners = new HashSet<>(); @NonNull HashSet mTouchListeners = new HashSet<>(); @NonNull HashSet mClickAreas = new HashSet<>(); @@ -463,6 +473,21 @@ public class CoreDocument { float mBottom; @Nullable final String mMetadata; + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (!(o instanceof ClickAreaRepresentation)) return false; + ClickAreaRepresentation that = (ClickAreaRepresentation) o; + return mId == that.mId + && Objects.equals(mContentDescription, that.mContentDescription) + && Objects.equals(mMetadata, that.mMetadata); + } + + @Override + public int hashCode() { + return Objects.hash(mId, mContentDescription, mMetadata); + } + public ClickAreaRepresentation( int id, @Nullable String contentDescription, @@ -565,6 +590,7 @@ public class CoreDocument { TouchUpModifierOperation currentTouchUpModifier = null; TouchCancelModifierOperation currentTouchCancelModifier = null; LoopOperation currentLoop = null; + ScrollModifierOperation currentScrollModifier = null; mLastId = -1; for (Operation o : operations) { @@ -579,8 +605,8 @@ public class CoreDocument { mLastId = component.getComponentId(); } } else if (o instanceof ComponentEnd) { - if (currentComponent instanceof LayoutComponent) { - ((LayoutComponent) currentComponent).inflate(); + if (currentComponent != null) { + currentComponent.inflate(); } components.remove(components.size() - 1); if (!components.isEmpty()) { @@ -602,6 +628,9 @@ public class CoreDocument { } else if (o instanceof TouchCancelModifierOperation) { currentTouchCancelModifier = (TouchCancelModifierOperation) o; ops = currentTouchCancelModifier.getList(); + } else if (o instanceof ScrollModifierOperation) { + currentScrollModifier = (ScrollModifierOperation) o; + ops = currentScrollModifier.getList(); } else if (o instanceof OperationsListEnd) { ops = currentComponent.getList(); if (currentClickModifier != null) { @@ -616,6 +645,9 @@ public class CoreDocument { } else if (currentTouchCancelModifier != null) { ops.add(currentTouchCancelModifier); currentTouchCancelModifier = null; + } else if (currentScrollModifier != null) { + ops.add(currentScrollModifier); + currentScrollModifier = null; } } else if (o instanceof LoopOperation) { currentLoop = (LoopOperation) o; @@ -665,7 +697,9 @@ public class CoreDocument { } } } + op.markNotDirty(); op.apply(context); + context.incrementOpCount(); } } @@ -740,9 +774,13 @@ public class CoreDocument { float right, float bottom, @Nullable String metadata) { - mClickAreas.add( + + ClickAreaRepresentation car = new ClickAreaRepresentation( - id, contentDescription, left, top, right, bottom, metadata)); + id, contentDescription, left, top, right, bottom, metadata); + + boolean old = mClickAreas.remove(car); + mClickAreas.add(car); } /** @@ -755,12 +793,12 @@ public class CoreDocument { } /** - * Add a click listener. This will get called when a click is detected on the document + * Add an id action listener. This will get called when e.g. a click is detected on the document * - * @param callback called when a click area has been hit, passing the click are id and metadata. + * @param callback called when an action is executed, passing the id and metadata. */ - public void addClickListener(@NonNull ClickCallbacks callback) { - mClickListeners.add(callback); + public void addIdActionListener(@NonNull IdActionCallback callback) { + mIdActionListeners.add(callback); } /** @@ -769,8 +807,8 @@ public class CoreDocument { * @return set of click listeners */ @NonNull - public HashSet getClickListeners() { - return mClickListeners; + public HashSet getIdActionListeners() { + return mIdActionListeners; } /** @@ -799,15 +837,15 @@ public class CoreDocument { warnClickListeners(clickArea); } } - for (ClickCallbacks listener : mClickListeners) { - listener.click(id, ""); + for (IdActionCallback listener : mIdActionListeners) { + listener.onAction(id, ""); } } /** Warn click listeners when a click area is activated */ private void warnClickListeners(@NonNull ClickAreaRepresentation clickArea) { - for (ClickCallbacks listener : mClickListeners) { - listener.click(clickArea.mId, clickArea.mMetadata); + for (IdActionCallback listener : mIdActionListeners) { + listener.onAction(clickArea.mId, clickArea.mMetadata); } } @@ -881,7 +919,7 @@ public class CoreDocument { } if (mRootLayoutComponent != null) { for (Component component : mAppliedTouchOperations) { - component.onTouchUp(context, this, x, y, true); + component.onTouchUp(context, this, x, y, dx, dy, true); } mAppliedTouchOperations.clear(); } @@ -963,6 +1001,16 @@ public class CoreDocument { private final float[] mScaleOutput = new float[2]; private final float[] mTranslateOutput = new float[2]; private int mRepaintNext = -1; // delay to next repaint -1 = don't 1 = asap + private int mLastOpCount; + + /** + * This is the number of ops used to calculate the last frame. + * + * @return number of ops + */ + public int getOpsPerFrame() { + return mLastOpCount; + } /** * Returns > 0 if it needs to repaint @@ -980,6 +1028,7 @@ public class CoreDocument { * @param theme the theme we want to use for this document. */ public void paint(@NonNull RemoteContext context, int theme) { + context.getLastOpCount(); context.getPaintContext().clearNeedsRepaint(); context.loadFloat(RemoteContext.ID_DENSITY, context.getDensity()); context.mMode = RemoteContext.ContextMode.UNSET; @@ -990,21 +1039,24 @@ public class CoreDocument { context.mRemoteComposeState = mRemoteComposeState; context.mRemoteComposeState.setContext(context); + // If we have a content sizing set, we are going to take the original document + // dimension into account and apply scale+translate according to the RootContentBehavior + // rules. if (mContentSizing == RootContentBehavior.SIZING_SCALE) { // we need to add canvas transforms ops here computeScale(context.mWidth, context.mHeight, mScaleOutput); - computeTranslate( - context.mWidth, - context.mHeight, - mScaleOutput[0], - mScaleOutput[1], - mTranslateOutput); + float sw = mScaleOutput[0]; + float sh = mScaleOutput[1]; + computeTranslate(context.mWidth, context.mHeight, sw, sh, mTranslateOutput); context.mPaintContext.translate(mTranslateOutput[0], mTranslateOutput[1]); - context.mPaintContext.scale(mScaleOutput[0], mScaleOutput[1]); + context.mPaintContext.scale(sw, sh); + } else { + // If not, we set the document width and height to be the current context width and + // height. + setWidth((int) context.mWidth); + setHeight((int) context.mHeight); } mTimeVariables.updateTime(context); - context.loadFloat(RemoteContext.ID_WINDOW_WIDTH, context.mWidth); - context.loadFloat(RemoteContext.ID_WINDOW_HEIGHT, context.mHeight); mRepaintNext = context.updateOps(); if (mRootLayoutComponent != null) { if (context.mWidth != mRootLayoutComponent.getWidth() @@ -1014,11 +1066,11 @@ public class CoreDocument { if (mRootLayoutComponent.needsMeasure()) { mRootLayoutComponent.layout(context); } - // TODO -- this should be specifically about applying animation, not paint - mRootLayoutComponent.paint(context.getPaintContext()); - context.mPaintContext.reset(); - // TODO -- should be able to remove this - mRootLayoutComponent.updateVariables(context); + if (mRootLayoutComponent.needsBoundsAnimation()) { + mRepaintNext = 1; + mRootLayoutComponent.clearNeedsBoundsAnimation(); + mRootLayoutComponent.animatingBounds(context); + } if (DEBUG) { String hierarchy = mRootLayoutComponent.displayHierarchy(); System.out.println(hierarchy); @@ -1039,7 +1091,14 @@ public class CoreDocument { || context.getTheme() == Theme.UNSPECIFIED; } if (apply) { - op.apply(context); + if (op.isDirty() || op instanceof PaintOperation) { + if (op.isDirty() && op instanceof VariableSupport) { + op.markNotDirty(); + ((VariableSupport) op).updateVariables(context); + } + context.incrementOpCount(); + op.apply(context); + } } } if (context.getPaintContext().doesNeedsRepaint() @@ -1047,10 +1106,41 @@ public class CoreDocument { mRepaintNext = 1; } context.mMode = RemoteContext.ContextMode.UNSET; - // System.out.println(">> " + ( System.nanoTime() - time)*1E-6f+" ms"); if (DEBUG && mRootLayoutComponent != null) { System.out.println(mRootLayoutComponent.displayHierarchy()); } + mLastOpCount = context.getLastOpCount(); + } + + /** + * Get an estimated number of operations executed in a paint + * + * @return number of operations + */ + public int getNumberOfOps() { + int count = mOperations.size(); + + for (Operation mOperation : mOperations) { + if (mOperation instanceof Component) { + count += getChildOps((Component) mOperation); + } + } + return count; + } + + private int getChildOps(@NonNull Component base) { + int count = base.mList.size(); + for (Operation mOperation : base.mList) { + + if (mOperation instanceof Component) { + int mult = 1; + if (mOperation instanceof LoopOperation) { + mult = ((LoopOperation) mOperation).estimateIterations(); + } + count += mult * getChildOps((Component) mOperation); + } + } + return count; } @NonNull @@ -1074,6 +1164,9 @@ public class CoreDocument { if (mOperation instanceof Component) { Component com = (Component) mOperation; count += addChildren(com, map, buffer); + } else if (mOperation instanceof LoopOperation) { + LoopOperation com = (LoopOperation) mOperation; + count += addChildren(com, map, buffer); } } @@ -1111,6 +1204,35 @@ public class CoreDocument { if (mOperation instanceof Component) { count += addChildren((Component) mOperation, map, tmp); } + if (mOperation instanceof LoopOperation) { + count += addChildren((LoopOperation) mOperation, map, tmp); + } + } + return count; + } + + private int addChildren( + @NonNull LoopOperation base, + @NonNull HashMap map, + @NonNull WireBuffer tmp) { + int count = base.mList.size(); + for (Operation mOperation : base.mList) { + Class c = mOperation.getClass(); + int[] values; + if (map.containsKey(c.getSimpleName())) { + values = map.get(c.getSimpleName()); + } else { + values = new int[2]; + map.put(c.getSimpleName(), values); + } + values[0] += 1; + values[1] += sizeOfComponent(mOperation, tmp); + if (mOperation instanceof Component) { + count += addChildren((Component) mOperation, map, tmp); + } + if (mOperation instanceof LoopOperation) { + count += addChildren((LoopOperation) mOperation, map, tmp); + } } return count; } @@ -1143,4 +1265,29 @@ public class CoreDocument { public List getOperations() { return mOperations; } + + /** defines if a shader can be run */ + public interface ShaderControl { + boolean isShaderValid(String shader); + } + + /** + * validate the shaders + * + * @param context the remote context + * @param ctl the call back to allow evaluation of shaders + */ + public void checkShaders(RemoteContext context, ShaderControl ctl) { + for (Operation op : mOperations) { + if (op instanceof TextData) { + op.apply(context); + } + if (op instanceof ShaderData) { + ShaderData sd = (ShaderData) op; + int id = sd.getShaderTextId(); + String str = context.getText(id); + sd.enable(ctl.isShaderValid(str)); + } + } + } } diff --git a/core/java/com/android/internal/widget/remotecompose/core/Operation.java b/core/java/com/android/internal/widget/remotecompose/core/Operation.java index 6f6a0a89296455849f86877430976ba1ad573fa3..150ebd0d3dfc08254df33a84acfb8e19e812a5b0 100644 --- a/core/java/com/android/internal/widget/remotecompose/core/Operation.java +++ b/core/java/com/android/internal/widget/remotecompose/core/Operation.java @@ -20,6 +20,8 @@ import android.annotation.NonNull; /** Base interface for RemoteCompose operations */ public abstract class Operation { + private static final boolean ENABLE_DIRTY_FLAG_OPTIMIZATION = true; + /** add the operation to the buffer */ public abstract void write(@NonNull WireBuffer buffer); @@ -33,4 +35,30 @@ public abstract class Operation { /** Debug utility to display an operation + indentation */ @NonNull public abstract String deepToString(@NonNull String indent); + + private boolean mDirty = true; + + /** Mark the operation as "dirty" to indicate it will need to be re-executed. */ + public void markDirty() { + mDirty = true; + } + + /** Mark the operation as "not dirty" */ + public void markNotDirty() { + if (ENABLE_DIRTY_FLAG_OPTIMIZATION) { + mDirty = false; + } + } + + /** + * Returns true if the operation is marked as "dirty" + * + * @return true if dirty + */ + public boolean isDirty() { + if (ENABLE_DIRTY_FLAG_OPTIMIZATION) { + return mDirty; + } + return true; + } } diff --git a/core/java/com/android/internal/widget/remotecompose/core/OperationInterface.java b/core/java/com/android/internal/widget/remotecompose/core/OperationInterface.java index 741303a40bc918973cc906b5639025c755bcd58e..06beffcac0dea18ec271a0df81a9bd8e59d54005 100644 --- a/core/java/com/android/internal/widget/remotecompose/core/OperationInterface.java +++ b/core/java/com/android/internal/widget/remotecompose/core/OperationInterface.java @@ -33,4 +33,14 @@ public interface OperationInterface { /** Debug utility to display an operation + indentation */ @NonNull String deepToString(@NonNull String indent); + + /** + * Returns true if the operation is marked as "dirty" + * + * @return true if dirty + */ + boolean isDirty(); + + /** Mark the operation as "dirty" to indicate it will need to be re-executed. */ + void markNotDirty(); } diff --git a/core/java/com/android/internal/widget/remotecompose/core/Operations.java b/core/java/com/android/internal/widget/remotecompose/core/Operations.java index 006fe3afb4d81d45feabc1e518bfa186cd8ffa6a..04e490fa5214fd4ac0d7a22c223347338139cc37 100644 --- a/core/java/com/android/internal/widget/remotecompose/core/Operations.java +++ b/core/java/com/android/internal/widget/remotecompose/core/Operations.java @@ -98,8 +98,10 @@ import com.android.internal.widget.remotecompose.core.operations.layout.modifier import com.android.internal.widget.remotecompose.core.operations.layout.modifiers.HeightModifierOperation; import com.android.internal.widget.remotecompose.core.operations.layout.modifiers.HostActionOperation; import com.android.internal.widget.remotecompose.core.operations.layout.modifiers.HostNamedActionOperation; +import com.android.internal.widget.remotecompose.core.operations.layout.modifiers.MarqueeModifierOperation; import com.android.internal.widget.remotecompose.core.operations.layout.modifiers.OffsetModifierOperation; import com.android.internal.widget.remotecompose.core.operations.layout.modifiers.PaddingModifierOperation; +import com.android.internal.widget.remotecompose.core.operations.layout.modifiers.RippleModifierOperation; import com.android.internal.widget.remotecompose.core.operations.layout.modifiers.RoundedClipRectModifierOperation; import com.android.internal.widget.remotecompose.core.operations.layout.modifiers.ScrollModifierOperation; import com.android.internal.widget.remotecompose.core.operations.layout.modifiers.ValueFloatChangeActionOperation; @@ -110,6 +112,7 @@ import com.android.internal.widget.remotecompose.core.operations.layout.modifier import com.android.internal.widget.remotecompose.core.operations.layout.modifiers.WidthModifierOperation; import com.android.internal.widget.remotecompose.core.operations.layout.modifiers.ZIndexModifierOperation; import com.android.internal.widget.remotecompose.core.operations.utilities.IntMap; +import com.android.internal.widget.remotecompose.core.semantics.CoreSemantics; import com.android.internal.widget.remotecompose.core.types.BooleanConstant; import com.android.internal.widget.remotecompose.core.types.IntegerConstant; import com.android.internal.widget.remotecompose.core.types.LongConstant; @@ -126,6 +129,9 @@ public class Operations { public static final int CLICK_AREA = 64; public static final int ROOT_CONTENT_BEHAVIOR = 65; public static final int ROOT_CONTENT_DESCRIPTION = 103; + // TODO reorder before submitting + public static final int ACCESSIBILITY_SEMANTICS = 250; + // public static final int ACCESSIBILITY_CUSTOM_ACTION = 251; //////////////////////////////////////// // Draw commands @@ -223,6 +229,8 @@ public class Operations { public static final int MODIFIER_ZINDEX = 223; public static final int MODIFIER_GRAPHICS_LAYER = 224; public static final int MODIFIER_SCROLL = 226; + public static final int MODIFIER_MARQUEE = 228; + public static final int MODIFIER_RIPPLE = 229; public static final int LOOP_START = 215; public static final int LOOP_END = 216; @@ -327,6 +335,8 @@ public class Operations { map.put(MODIFIER_ZINDEX, ZIndexModifierOperation::read); map.put(MODIFIER_GRAPHICS_LAYER, GraphicsLayerModifierOperation::read); map.put(MODIFIER_SCROLL, ScrollModifierOperation::read); + map.put(MODIFIER_MARQUEE, MarqueeModifierOperation::read); + map.put(MODIFIER_RIPPLE, RippleModifierOperation::read); map.put(OPERATIONS_LIST_END, OperationsListEnd::read); @@ -362,5 +372,8 @@ public class Operations { map.put(PATH_TWEEN, PathTween::read); map.put(PATH_CREATE, PathCreate::read); map.put(PATH_ADD, PathAppend::read); + + map.put(ACCESSIBILITY_SEMANTICS, CoreSemantics::read); + // map.put(ACCESSIBILITY_CUSTOM_ACTION, CoreSemantics::read); } } diff --git a/core/java/com/android/internal/widget/remotecompose/core/RemoteComposeBuffer.java b/core/java/com/android/internal/widget/remotecompose/core/RemoteComposeBuffer.java index 3a5d68db8a3787f2c8b3e8453f297c07d348c594..0ae7a94b948d4abdd2420f8cd948233401c68867 100644 --- a/core/java/com/android/internal/widget/remotecompose/core/RemoteComposeBuffer.java +++ b/core/java/com/android/internal/widget/remotecompose/core/RemoteComposeBuffer.java @@ -15,7 +15,6 @@ */ package com.android.internal.widget.remotecompose.core; -import static com.android.internal.widget.remotecompose.core.operations.utilities.AnimatedFloatExpression.ADD; import static com.android.internal.widget.remotecompose.core.operations.utilities.AnimatedFloatExpression.MUL; import android.annotation.NonNull; @@ -81,6 +80,7 @@ import com.android.internal.widget.remotecompose.core.operations.layout.Componen import com.android.internal.widget.remotecompose.core.operations.layout.LayoutComponentContent; import com.android.internal.widget.remotecompose.core.operations.layout.LoopEnd; import com.android.internal.widget.remotecompose.core.operations.layout.LoopOperation; +import com.android.internal.widget.remotecompose.core.operations.layout.OperationsListEnd; import com.android.internal.widget.remotecompose.core.operations.layout.RootLayoutComponent; import com.android.internal.widget.remotecompose.core.operations.layout.managers.BoxLayout; import com.android.internal.widget.remotecompose.core.operations.layout.managers.CanvasLayout; @@ -92,8 +92,10 @@ import com.android.internal.widget.remotecompose.core.operations.layout.modifier import com.android.internal.widget.remotecompose.core.operations.layout.modifiers.BorderModifierOperation; import com.android.internal.widget.remotecompose.core.operations.layout.modifiers.ClipRectModifierOperation; import com.android.internal.widget.remotecompose.core.operations.layout.modifiers.GraphicsLayerModifierOperation; +import com.android.internal.widget.remotecompose.core.operations.layout.modifiers.MarqueeModifierOperation; import com.android.internal.widget.remotecompose.core.operations.layout.modifiers.OffsetModifierOperation; import com.android.internal.widget.remotecompose.core.operations.layout.modifiers.PaddingModifierOperation; +import com.android.internal.widget.remotecompose.core.operations.layout.modifiers.RippleModifierOperation; import com.android.internal.widget.remotecompose.core.operations.layout.modifiers.RoundedClipRectModifierOperation; import com.android.internal.widget.remotecompose.core.operations.layout.modifiers.ScrollModifierOperation; import com.android.internal.widget.remotecompose.core.operations.layout.modifiers.ZIndexModifierOperation; @@ -1610,7 +1612,7 @@ public class RemoteComposeBuffer { * create and animation based on description and return as an array of floats. see * addAnimatedFloat * - * @param duration the duration of the aimation + * @param duration the duration of the animation in seconds * @param type the type of animation * @param spec the parameters of the animation if any * @param initialValue the initial value if it animates to a start @@ -1699,6 +1701,9 @@ public class RemoteComposeBuffer { float notchMax = this.reserveFloatVariable(); float touchExpressionDirection = direction != 0 ? RemoteContext.FLOAT_TOUCH_POS_X : RemoteContext.FLOAT_TOUCH_POS_Y; + + ScrollModifierOperation.apply(mBuffer, direction, positionId, max, notchMax); + this.addTouchExpression( positionId, 0f, @@ -1707,20 +1712,13 @@ public class RemoteComposeBuffer { 0f, 3, new float[] { - touchExpressionDirection, - -1, - // TODO: remove this CONTINUOUS_SEC hack... - MUL, - RemoteContext.FLOAT_CONTINUOUS_SEC, - 0f, - MUL, - ADD + touchExpressionDirection, -1, MUL, }, TouchExpression.STOP_NOTCHES_EVEN, new float[] {notches, notchMax}, null); - ScrollModifierOperation.apply(mBuffer, direction, positionId, max, notchMax); + OperationsListEnd.apply(mBuffer); } /** @@ -1786,6 +1784,38 @@ public class RemoteComposeBuffer { ZIndexModifierOperation.apply(mBuffer, value); } + /** Add a ripple effect on touch down as a modifier */ + public void addModifierRipple() { + RippleModifierOperation.apply(mBuffer); + } + + /** + * Add a marquee modifier + * + * @param iterations + * @param animationMode + * @param repeatDelayMillis + * @param initialDelayMillis + * @param spacing + * @param velocity + */ + public void addModifierMarquee( + int iterations, + int animationMode, + float repeatDelayMillis, + float initialDelayMillis, + float spacing, + float velocity) { + MarqueeModifierOperation.apply( + mBuffer, + iterations, + animationMode, + repeatDelayMillis, + initialDelayMillis, + spacing, + velocity); + } + /** * Add a graphics layer * diff --git a/core/java/com/android/internal/widget/remotecompose/core/RemoteComposeState.java b/core/java/com/android/internal/widget/remotecompose/core/RemoteComposeState.java index f5f9e214723b8785f332763069a2fd2997244e70..5c3df7e95a1faa63e54aaf240ee6b104e481f060 100644 --- a/core/java/com/android/internal/widget/remotecompose/core/RemoteComposeState.java +++ b/core/java/com/android/internal/widget/remotecompose/core/RemoteComposeState.java @@ -48,6 +48,10 @@ public class RemoteComposeState implements CollectionsAccess { private final IntMap mDataMapMap = new IntMap<>(); private final IntMap mObjectMap = new IntMap<>(); + // path information + private final IntMap mPathMap = new IntMap<>(); + private final IntMap mPathData = new IntMap<>(); + private final boolean[] mColorOverride = new boolean[MAX_COLORS]; @NonNull private final IntMap mCollectionMap = new IntMap<>(); @@ -131,12 +135,44 @@ public class RemoteComposeState implements CollectionsAccess { } } - private final IntMap mPathData = new IntMap<>(); + /** + * Get the path asociated with the Data + * + * @param id + * @return + */ + public Object getPath(int id) { + return mPathMap.get(id); + } + + /** + * Cache a path object. Object will be cleared if you update path data. + * + * @param id number asociated with path + * @param path the path object typically Android Path + */ + public void putPath(int id, Object path) { + mPathMap.put(id, path); + } + /** + * The path data the Array of floats that is asoicated with the path It also removes the current + * path object. + * + * @param id the integer asociated with the data and path + * @param data the array of floats that represents the path + */ public void putPathData(int id, float[] data) { mPathData.put(id, data); + mPathMap.remove(id); } + /** + * Get the path data asociated with the id + * + * @param id number that represents the path + * @return path data + */ public float[] getPathData(int id) { return mPathData.get(id); } @@ -283,7 +319,7 @@ public class RemoteComposeState implements CollectionsAccess { ArrayList v = mVarListeners.get(id); if (v != null && mRemoteContext != null) { for (VariableSupport c : v) { - c.updateVariables(mRemoteContext); + c.markDirty(); } } } @@ -297,6 +333,7 @@ public class RemoteComposeState implements CollectionsAccess { public void overrideColor(int id, int color) { mColorOverride[id] = true; mColorMap.put(id, color); + updateListeners(id); } /** Clear the color Overrides */ @@ -426,9 +463,6 @@ public class RemoteComposeState implements CollectionsAccess { * @return */ public int getOpsToUpdate(@NonNull RemoteContext context) { - for (VariableSupport vs : mAllVarListeners) { - vs.updateVariables(context); - } if (mVarListeners.get(RemoteContext.ID_CONTINUOUS_SEC) != null) { return 1; } diff --git a/core/java/com/android/internal/widget/remotecompose/core/RemoteContext.java b/core/java/com/android/internal/widget/remotecompose/core/RemoteContext.java index 6eb8463ab308aa25f1340f322210b74fba7f4491..b5587ce095a24b1a459264d45851a0926e5c9871 100644 --- a/core/java/com/android/internal/widget/remotecompose/core/RemoteContext.java +++ b/core/java/com/android/internal/widget/remotecompose/core/RemoteContext.java @@ -40,6 +40,7 @@ import java.time.ZoneOffset; *

    We also contain a PaintContext, so that any operation can draw as needed. */ public abstract class RemoteContext { + private static final int MAX_OP_COUNT = 100_000; // Maximum cmds per frame protected @NonNull CoreDocument mDocument = new CoreDocument(); // todo: is this a valid way to initialize? bbade@ public @NonNull RemoteComposeState mRemoteComposeState = @@ -52,6 +53,7 @@ public abstract class RemoteContext { int mDebug = 0; + private int mOpCount; private int mTheme = Theme.UNSPECIFIED; public float mWidth = 0f; @@ -214,6 +216,13 @@ public abstract class RemoteContext { */ public abstract void hapticEffect(int type); + /** Set the repaint flag. This will trigger a repaint of the current document. */ + public void needsRepaint() { + if (mPaintContext != null) { + mPaintContext.needsRepaint(); + } + } + /** * The context can be used in a few different mode, allowing operations to skip being executed: * - UNSET : all operations will get executed - DATA : only operations dealing with DATA (eg @@ -486,6 +495,9 @@ public abstract class RemoteContext { public static final int ID_DENSITY = 27; + /** Defines when the last build was made */ + public static final int ID_API_LEVEL = 28; + public static final float FLOAT_DENSITY = Utils.asNan(ID_DENSITY); /** CONTINUOUS_SEC is seconds from midnight looping every hour 0-3600 */ @@ -559,6 +571,9 @@ public abstract class RemoteContext { /** Ambient light level in SI lux */ public static final float FLOAT_LIGHT = Utils.asNan(ID_LIGHT); + /** When was this player built */ + public static final float FLOAT_API_LEVEL = Utils.asNan(ID_API_LEVEL); + /////////////////////////////////////////////////////////////////////////////////////////////// // Click handling /////////////////////////////////////////////////////////////////////////////////////////////// @@ -618,4 +633,23 @@ public abstract class RemoteContext { float right, float bottom, int metadataId); + + /** increments the count of operations executed in a pass */ + public void incrementOpCount() { + mOpCount++; + if (mOpCount > MAX_OP_COUNT) { + throw new RuntimeException("Too many operations executed"); + } + } + + /** + * Get the last Op Count and clear the count. + * + * @return the number of ops executed. + */ + public int getLastOpCount() { + int count = mOpCount; + mOpCount = 0; + return count; + } } diff --git a/core/java/com/android/internal/widget/remotecompose/core/TimeVariables.java b/core/java/com/android/internal/widget/remotecompose/core/TimeVariables.java index 14aed2f0c17396041b67cf51b784722301d9c8ec..ea917db98e653b3c575fcc32777c326200074c07 100644 --- a/core/java/com/android/internal/widget/remotecompose/core/TimeVariables.java +++ b/core/java/com/android/internal/widget/remotecompose/core/TimeVariables.java @@ -24,14 +24,14 @@ import java.time.ZoneOffset; /** This generates the standard system variables for time. */ public class TimeVariables { + private static final float BUILD = 0.02f; + /** * This class populates all time variables in the system * * @param context */ - public void updateTime(@NonNull RemoteContext context) { - LocalDateTime dateTime = - LocalDateTime.now(ZoneId.systemDefault()); // TODO, pass in a timezone explicitly? + public void updateTime(@NonNull RemoteContext context, ZoneId zoneId, LocalDateTime dateTime) { // This define the time in the format // seconds run from Midnight=0 quantized to seconds hour 0..3599 // minutes run from Midnight=0 quantized to minutes 0..1439 @@ -48,8 +48,7 @@ public class TimeVariables { float sec = currentSeconds + dateTime.getNano() * 1E-9f; int day_week = dateTime.getDayOfWeek().getValue(); - ZoneId zone = ZoneId.systemDefault(); - OffsetDateTime offsetDateTime = dateTime.atZone(zone).toOffsetDateTime(); + OffsetDateTime offsetDateTime = dateTime.atZone(zoneId).toOffsetDateTime(); ZoneOffset offset = offsetDateTime.getOffset(); context.loadFloat(RemoteContext.ID_OFFSET_TO_UTC, offset.getTotalSeconds()); @@ -60,5 +59,18 @@ public class TimeVariables { context.loadFloat(RemoteContext.ID_CALENDAR_MONTH, month); context.loadFloat(RemoteContext.ID_DAY_OF_MONTH, month); context.loadFloat(RemoteContext.ID_WEEK_DAY, day_week); + context.loadFloat(RemoteContext.ID_API_LEVEL, CoreDocument.getDocumentApiLevel() + BUILD); + } + + /** + * This class populates all time variables in the system + * + * @param context + */ + public void updateTime(@NonNull RemoteContext context) { + ZoneId zone = ZoneId.systemDefault(); + LocalDateTime dateTime = LocalDateTime.now(zone); + + updateTime(context, zone, dateTime); } } diff --git a/core/java/com/android/internal/widget/remotecompose/core/TouchListener.java b/core/java/com/android/internal/widget/remotecompose/core/TouchListener.java index 3dda678c2a3a0331c04192e128ed757884284b3c..611ba97c10cb3d4e1b2f1a0e4311521d0ccf94cf 100644 --- a/core/java/com/android/internal/widget/remotecompose/core/TouchListener.java +++ b/core/java/com/android/internal/widget/remotecompose/core/TouchListener.java @@ -15,10 +15,34 @@ */ package com.android.internal.widget.remotecompose.core; +/** Interface used by objects to register for touch events */ public interface TouchListener { + /** + * Called when touch down happens + * + * @param context The players context + * @param x the x location of the down touch + * @param y the y location of the down touch + */ void touchDown(RemoteContext context, float x, float y); + /** + * called on touch up + * + * @param context the players context + * @param x the x location + * @param y the y location + * @param dx the x velocity when the touch up happened + * @param dy the y valocity when the touch up happened + */ void touchUp(RemoteContext context, float x, float y, float dx, float dy); + /** + * Drag event (occur between down and up) + * + * @param context the players context + * @param x the x coord of the drag + * @param y the y coord of the drag + */ void touchDrag(RemoteContext context, float x, float y); } diff --git a/core/java/com/android/internal/widget/remotecompose/core/VariableSupport.java b/core/java/com/android/internal/widget/remotecompose/core/VariableSupport.java index e9fa8976637e37f4be11dbe07a31632db19c8cc3..1f3e290a0f041608b96158cf7ec6f230a246b88c 100644 --- a/core/java/com/android/internal/widget/remotecompose/core/VariableSupport.java +++ b/core/java/com/android/internal/widget/remotecompose/core/VariableSupport.java @@ -36,4 +36,7 @@ public interface VariableSupport { * @param context */ void updateVariables(@NonNull RemoteContext context); + + /** Mark the operation as dirty to indicate that the variables it references are out of date. */ + void markDirty(); } diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/BitmapData.java b/core/java/com/android/internal/widget/remotecompose/core/operations/BitmapData.java index 27ba6528a703b94934348171bb04ccda8f9ebd24..784897b0499124f3195fb48f952668551fe83aa5 100644 --- a/core/java/com/android/internal/widget/remotecompose/core/operations/BitmapData.java +++ b/core/java/com/android/internal/widget/remotecompose/core/operations/BitmapData.java @@ -45,15 +45,39 @@ public class BitmapData extends Operation implements SerializableToString { short mType; short mEncoding; @NonNull final byte[] mBitmap; + + /** The max size of width or height */ public static final int MAX_IMAGE_DIMENSION = 8000; + + /** The data is encoded in the file (default) */ public static final short ENCODING_INLINE = 0; + + /** The data is encoded in the url */ public static final short ENCODING_URL = 1; + + /** The data is encoded as a reference to file */ public static final short ENCODING_FILE = 2; + + /** The data is encoded as PNG_8888 (default) */ public static final short TYPE_PNG_8888 = 0; + + /** The data is encoded as PNG */ public static final short TYPE_PNG = 1; + + /** The data is encoded as RAW 8 bit */ public static final short TYPE_RAW8 = 2; + + /** The data is encoded as RAW 8888 bit */ public static final short TYPE_RAW8888 = 3; + /** + * create a bitmap structure + * + * @param imageId the id to store the image + * @param width the width of the image + * @param height the height of the image + * @param bitmap the data + */ public BitmapData(int imageId, int width, int height, @NonNull byte[] bitmap) { this.mImageId = imageId; this.mImageWidth = width; @@ -61,10 +85,20 @@ public class BitmapData extends Operation implements SerializableToString { this.mBitmap = bitmap; } + /** + * The width of the image + * + * @return the width + */ public int getWidth() { return mImageWidth; } + /** + * The height of the image + * + * @return the height + */ public int getHeight() { return mImageHeight; } @@ -80,6 +114,11 @@ public class BitmapData extends Operation implements SerializableToString { return "BITMAP DATA " + mImageId; } + /** + * The name of the class + * + * @return the name + */ @NonNull public static String name() { return CLASS_NAME; @@ -94,6 +133,15 @@ public class BitmapData extends Operation implements SerializableToString { return OP_CODE; } + /** + * Add the image to the document + * + * @param buffer document to write to + * @param imageId the id the image will be stored under + * @param width the width of the image + * @param height the height of the image + * @param bitmap the data used to store/encode the image + */ public static void apply( @NonNull WireBuffer buffer, int imageId, @@ -107,6 +155,17 @@ public class BitmapData extends Operation implements SerializableToString { buffer.writeBuffer(bitmap); } + /** + * Add the image to the document (using the ehanced encoding) + * + * @param buffer document to write to + * @param imageId the id the image will be stored under + * @param type the type of image + * @param width the width of the image + * @param encoding the encoding + * @param height the height of the image + * @param bitmap the data used to store/encode the image + */ public static void apply( @NonNull WireBuffer buffer, int imageId, diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/ClickArea.java b/core/java/com/android/internal/widget/remotecompose/core/operations/ClickArea.java index 5e5e5653053fc5eecc192f8644869cc844f950eb..bb112d1cb7324c3dcff21aff44e0f8c625e733f5 100644 --- a/core/java/com/android/internal/widget/remotecompose/core/operations/ClickArea.java +++ b/core/java/com/android/internal/widget/remotecompose/core/operations/ClickArea.java @@ -21,14 +21,17 @@ import com.android.internal.widget.remotecompose.core.Operation; import com.android.internal.widget.remotecompose.core.Operations; import com.android.internal.widget.remotecompose.core.RemoteComposeOperation; import com.android.internal.widget.remotecompose.core.RemoteContext; +import com.android.internal.widget.remotecompose.core.VariableSupport; import com.android.internal.widget.remotecompose.core.WireBuffer; import com.android.internal.widget.remotecompose.core.documentation.DocumentationBuilder; import com.android.internal.widget.remotecompose.core.documentation.DocumentedOperation; +import com.android.internal.widget.remotecompose.core.semantics.AccessibleComponent; import java.util.List; /** Add a click area to the document */ -public class ClickArea extends Operation implements RemoteComposeOperation { +public class ClickArea extends Operation + implements RemoteComposeOperation, AccessibleComponent, VariableSupport { private static final int OP_CODE = Operations.CLICK_AREA; private static final String CLASS_NAME = "ClickArea"; int mId; @@ -37,6 +40,10 @@ public class ClickArea extends Operation implements RemoteComposeOperation { float mTop; float mRight; float mBottom; + float mOutLeft; + float mOutTop; + float mOutRight; + float mOutBottom; int mMetadata; /** @@ -61,11 +68,35 @@ public class ClickArea extends Operation implements RemoteComposeOperation { int metadata) { this.mId = id; this.mContentDescription = contentDescription; - this.mLeft = left; - this.mTop = top; - this.mRight = right; - this.mBottom = bottom; - this.mMetadata = metadata; + mOutLeft = mLeft = left; + mOutTop = mTop = top; + mOutRight = mRight = right; + mOutBottom = mBottom = bottom; + mMetadata = metadata; + } + + @Override + public void registerListening(@NonNull RemoteContext context) { + if (Float.isNaN(mLeft)) { + context.listensTo(Utils.idFromNan(mLeft), this); + } + if (Float.isNaN(mTop)) { + context.listensTo(Utils.idFromNan(mTop), this); + } + if (Float.isNaN(mRight)) { + context.listensTo(Utils.idFromNan(mRight), this); + } + if (Float.isNaN(mBottom)) { + context.listensTo(Utils.idFromNan(mBottom), this); + } + } + + @Override + public void updateVariables(@NonNull RemoteContext context) { + mOutLeft = Float.isNaN(mLeft) ? context.getFloat(Utils.idFromNan(mLeft)) : mLeft; + mOutTop = Float.isNaN(mTop) ? context.getFloat(Utils.idFromNan(mTop)) : mTop; + mRight = Float.isNaN(mRight) ? context.getFloat(Utils.idFromNan(mRight)) : mRight; + mOutBottom = Float.isNaN(mBottom) ? context.getFloat(Utils.idFromNan(mBottom)) : mBottom; } @Override @@ -101,10 +132,8 @@ public class ClickArea extends Operation implements RemoteComposeOperation { @Override public void apply(@NonNull RemoteContext context) { - if (context.getMode() != RemoteContext.ContextMode.DATA) { - return; - } - context.addClickArea(mId, mContentDescription, mLeft, mTop, mRight, mBottom, mMetadata); + context.addClickArea( + mId, mContentDescription, mOutLeft, mOutTop, mOutRight, mOutBottom, mMetadata); } @NonNull @@ -113,6 +142,11 @@ public class ClickArea extends Operation implements RemoteComposeOperation { return indent + toString(); } + /** + * The name of the class + * + * @return the name + */ @NonNull public static String name() { return CLASS_NAME; @@ -127,6 +161,21 @@ public class ClickArea extends Operation implements RemoteComposeOperation { return OP_CODE; } + @Override + public Integer getContentDescriptionId() { + return mContentDescription; + } + + /** + * @param buffer + * @param id + * @param contentDescription + * @param left + * @param top + * @param right + * @param bottom + * @param metadata + */ public static void apply( @NonNull WireBuffer buffer, int id, diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/ClipPath.java b/core/java/com/android/internal/widget/remotecompose/core/operations/ClipPath.java index 2fe56d3ec935a0510d2e95eaaac16a3f50b439f7..b55f25c911fed224384470012f1d20c59385dcd2 100644 --- a/core/java/com/android/internal/widget/remotecompose/core/operations/ClipPath.java +++ b/core/java/com/android/internal/widget/remotecompose/core/operations/ClipPath.java @@ -83,6 +83,11 @@ public class ClipPath extends PaintOperation { operations.add(op); } + /** + * The name of the class + * + * @return the name + */ @NonNull public static String name() { return CLASS_NAME; diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/ClipRect.java b/core/java/com/android/internal/widget/remotecompose/core/operations/ClipRect.java index defa656b44e6c79c8a6d6314d57ba34486d2fa66..5a495d54e8da67103b500b3bfedb13147f01edfe 100644 --- a/core/java/com/android/internal/widget/remotecompose/core/operations/ClipRect.java +++ b/core/java/com/android/internal/widget/remotecompose/core/operations/ClipRect.java @@ -28,8 +28,8 @@ import java.util.List; /** Support clip with a rectangle */ public class ClipRect extends DrawBase4 { - public static final int OP_CODE = Operations.CLIP_RECT; - public static final String CLASS_NAME = "ClipRect"; + private static final int OP_CODE = Operations.CLIP_RECT; + private static final String CLASS_NAME = "ClipRect"; /** * Read this operation and add it to the list of operations @@ -51,6 +51,11 @@ public class ClipRect extends DrawBase4 { return OP_CODE; } + /** + * The name of the class + * + * @return the name + */ @NonNull public static String name() { return CLASS_NAME; diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/ColorConstant.java b/core/java/com/android/internal/widget/remotecompose/core/operations/ColorConstant.java index d86576dd99f239a8a5778c6b599b9494b12b0934..68020157b8d164fcf8cfc9480d1b5802bbd79715 100644 --- a/core/java/com/android/internal/widget/remotecompose/core/operations/ColorConstant.java +++ b/core/java/com/android/internal/widget/remotecompose/core/operations/ColorConstant.java @@ -61,6 +61,11 @@ public class ColorConstant extends Operation { return "ColorConstant[" + mColorId + "] = " + Utils.colorInt(mColor) + ""; } + /** + * The name of the class + * + * @return the name + */ @NonNull public static String name() { return CLASS_NAME; diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/ColorExpression.java b/core/java/com/android/internal/widget/remotecompose/core/operations/ColorExpression.java index 66f128f8f478bc283be5a7d07df3a5a9a67593bf..b385ecd9e5f7f76d561b376e1f136232f982d788 100644 --- a/core/java/com/android/internal/widget/remotecompose/core/operations/ColorExpression.java +++ b/core/java/com/android/internal/widget/remotecompose/core/operations/ColorExpression.java @@ -199,6 +199,11 @@ public class ColorExpression extends Operation implements VariableSupport { + ")"; } + /** + * The name of the class + * + * @return the name + */ @NonNull public static String name() { return CLASS_NAME; diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/ComponentValue.java b/core/java/com/android/internal/widget/remotecompose/core/operations/ComponentValue.java index 19c219bc0121aef8fcdc11b8072c29dc4b5db23a..3e852364cfee65ae3fd0e4b06bf90250fcae1b6a 100644 --- a/core/java/com/android/internal/widget/remotecompose/core/operations/ComponentValue.java +++ b/core/java/com/android/internal/widget/remotecompose/core/operations/ComponentValue.java @@ -31,8 +31,8 @@ import com.android.internal.widget.remotecompose.core.operations.utilities.Strin import java.util.List; public class ComponentValue extends Operation implements SerializableToString { - public static final int OP_CODE = Operations.COMPONENT_VALUE; - public static final String CLASS_NAME = "ComponentValue"; + private static final int OP_CODE = Operations.COMPONENT_VALUE; + private static final String CLASS_NAME = "ComponentValue"; public static final int WIDTH = 0; public static final int HEIGHT = 1; @@ -50,6 +50,11 @@ public class ComponentValue extends Operation implements SerializableToString { return OP_CODE; } + /** + * The name of the class + * + * @return the name + */ @NonNull public static String name() { return CLASS_NAME; diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/DataMapIds.java b/core/java/com/android/internal/widget/remotecompose/core/operations/DataMapIds.java index e888074cda746e0cd28c14b073bd556849612e43..ff85721027f7d605036fac977d45d82b2a17f16b 100644 --- a/core/java/com/android/internal/widget/remotecompose/core/operations/DataMapIds.java +++ b/core/java/com/android/internal/widget/remotecompose/core/operations/DataMapIds.java @@ -129,6 +129,11 @@ public class DataMapIds extends Operation { operations.add(data); } + /** + * Populate the documentation with a description of this operation + * + * @param doc to append the description to. + */ public static void documentation(@NonNull DocumentationBuilder doc) { doc.operation("Data Operations", OP_CODE, CLASS_NAME) .description("Encode a collection of name id pairs") diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/DrawArc.java b/core/java/com/android/internal/widget/remotecompose/core/operations/DrawArc.java index 3f95f02747f900687f5f74eb6d1f31d040d795be..fd1f41065dd94fe340056b2a0531a427cd254055 100644 --- a/core/java/com/android/internal/widget/remotecompose/core/operations/DrawArc.java +++ b/core/java/com/android/internal/widget/remotecompose/core/operations/DrawArc.java @@ -26,8 +26,9 @@ import com.android.internal.widget.remotecompose.core.documentation.DocumentedOp import java.util.List; +/** Draw an Arc command the specified arc, will be scaled to fit inside the specified oval. */ public class DrawArc extends DrawBase6 { - public static final int OP_CODE = Operations.DRAW_ARC; + private static final int OP_CODE = Operations.DRAW_ARC; private static final String CLASS_NAME = "DrawArc"; /** @@ -114,8 +115,20 @@ public class DrawArc extends DrawBase6 { "Sweep angle (in degrees) measured clockwise"); } - public DrawArc(float v1, float v2, float v3, float v4, float v5, float v6) { - super(v1, v2, v3, v4, v5, v6); + /** + * Create Draw Arc command Draw the specified arc, which will be scaled to fit inside the + * specified oval. + * + * @param left the left side of the oval + * @param top the top of the oval + * @param right the right side of the oval + * @param bottom the bottom of the oval + * @param startAngle Starting angle (in degrees) where the arc begins + * @param sweepAngle Sweep angle (in degrees) measured clockwise + */ + public DrawArc( + float left, float top, float right, float bottom, float startAngle, float sweepAngle) { + super(left, top, right, bottom, startAngle, sweepAngle); mName = "DrawArc"; } diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/DrawBase6.java b/core/java/com/android/internal/widget/remotecompose/core/operations/DrawBase6.java index 6c288a35621db3da57ba394d0a7d9bbbbfeec69f..64c2730e5f9a212938d849da7f2549373d40f4eb 100644 --- a/core/java/com/android/internal/widget/remotecompose/core/operations/DrawBase6.java +++ b/core/java/com/android/internal/widget/remotecompose/core/operations/DrawBase6.java @@ -145,6 +145,11 @@ public abstract class DrawBase6 extends PaintOperation implements VariableSuppor return null; } + /** + * The name of the class + * + * @return the name + */ @NonNull public static String name() { return "DrawBase6"; diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/DrawBitmap.java b/core/java/com/android/internal/widget/remotecompose/core/operations/DrawBitmap.java index 69f5cc52a78af8e4b8215328f75fce76c430c493..cdb527dee4605f31f015b41862cbc6e24885a15b 100644 --- a/core/java/com/android/internal/widget/remotecompose/core/operations/DrawBitmap.java +++ b/core/java/com/android/internal/widget/remotecompose/core/operations/DrawBitmap.java @@ -118,6 +118,11 @@ public class DrawBitmap extends PaintOperation implements VariableSupport { operations.add(op); } + /** + * The name of the class + * + * @return the name + */ @NonNull public static String name() { return CLASS_NAME; diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/DrawBitmapInt.java b/core/java/com/android/internal/widget/remotecompose/core/operations/DrawBitmapInt.java index 66646d7c2faa50214e614f3f4ff7871290703c6c..638fe148d746f9ee0b2d0a91ffe2d9c05f088d1c 100644 --- a/core/java/com/android/internal/widget/remotecompose/core/operations/DrawBitmapInt.java +++ b/core/java/com/android/internal/widget/remotecompose/core/operations/DrawBitmapInt.java @@ -24,11 +24,12 @@ import com.android.internal.widget.remotecompose.core.PaintOperation; import com.android.internal.widget.remotecompose.core.WireBuffer; import com.android.internal.widget.remotecompose.core.documentation.DocumentationBuilder; import com.android.internal.widget.remotecompose.core.documentation.DocumentedOperation; +import com.android.internal.widget.remotecompose.core.semantics.AccessibleComponent; import java.util.List; /** Operation to draw a given cached bitmap */ -public class DrawBitmapInt extends PaintOperation { +public class DrawBitmapInt extends PaintOperation implements AccessibleComponent { private static final int OP_CODE = Operations.DRAW_BITMAP_INT; private static final String CLASS_NAME = "DrawBitmapInt"; int mImageId; @@ -106,6 +107,16 @@ public class DrawBitmapInt extends PaintOperation { + ";"; } + @Override + public Integer getContentDescriptionId() { + return mContentDescId; + } + + /** + * The name of the class + * + * @return the name + */ @NonNull public static String name() { return CLASS_NAME; @@ -170,6 +181,11 @@ public class DrawBitmapInt extends PaintOperation { operations.add(op); } + /** + * Populate the documentation with a description of this operation + * + * @param doc to append the description to. + */ public static void documentation(@NonNull DocumentationBuilder doc) { doc.operation("Draw Operations", OP_CODE, CLASS_NAME) .description("Draw a bitmap using integer coordinates") diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/DrawBitmapScaled.java b/core/java/com/android/internal/widget/remotecompose/core/operations/DrawBitmapScaled.java index 170148608ab357e6e78e2055167108c8e3e2b1c6..d6467c9267478f52223ff8e8bcd7fe79887306aa 100644 --- a/core/java/com/android/internal/widget/remotecompose/core/operations/DrawBitmapScaled.java +++ b/core/java/com/android/internal/widget/remotecompose/core/operations/DrawBitmapScaled.java @@ -27,11 +27,13 @@ import com.android.internal.widget.remotecompose.core.WireBuffer; import com.android.internal.widget.remotecompose.core.documentation.DocumentationBuilder; import com.android.internal.widget.remotecompose.core.documentation.DocumentedOperation; import com.android.internal.widget.remotecompose.core.operations.utilities.ImageScaling; +import com.android.internal.widget.remotecompose.core.semantics.AccessibleComponent; import java.util.List; /** Operation to draw a given cached bitmap */ -public class DrawBitmapScaled extends PaintOperation implements VariableSupport { +public class DrawBitmapScaled extends PaintOperation + implements VariableSupport, AccessibleComponent { private static final int OP_CODE = Operations.DRAW_BITMAP_SCALED; private static final String CLASS_NAME = "DrawBitmapScaled"; int mImageId; @@ -191,6 +193,16 @@ public class DrawBitmapScaled extends PaintOperation implements VariableSupport + Utils.floatToString(mScaleFactor, mOutScaleFactor); } + @Override + public Integer getContentDescriptionId() { + return mContentDescId; + } + + /** + * The name of the class + * + * @return the name + */ @NonNull public static String name() { return CLASS_NAME; diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/DrawCircle.java b/core/java/com/android/internal/widget/remotecompose/core/operations/DrawCircle.java index e6aecdbf8bbe4d723806b8e467c434d4830e532d..735e262ce94f8fce5c9a642edc4d98ba5150f3da 100644 --- a/core/java/com/android/internal/widget/remotecompose/core/operations/DrawCircle.java +++ b/core/java/com/android/internal/widget/remotecompose/core/operations/DrawCircle.java @@ -50,6 +50,11 @@ public class DrawCircle extends DrawBase3 { return OP_CODE; } + /** + * The name of the class + * + * @return the name + */ @NonNull public static String name() { return CLASS_NAME; diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/DrawLine.java b/core/java/com/android/internal/widget/remotecompose/core/operations/DrawLine.java index 04f32642d5fa85ef41798c38679cc715c4675531..f3a190d98960f3adf3f6469f2d8f37bfee9a1485 100644 --- a/core/java/com/android/internal/widget/remotecompose/core/operations/DrawLine.java +++ b/core/java/com/android/internal/widget/remotecompose/core/operations/DrawLine.java @@ -52,6 +52,11 @@ public class DrawLine extends DrawBase4 implements SerializableToString { return OP_CODE; } + /** + * The name of the class + * + * @return the name + */ @NonNull public static String name() { return CLASS_NAME; diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/DrawOval.java b/core/java/com/android/internal/widget/remotecompose/core/operations/DrawOval.java index 0a50042b11c7f1033c8ccd1436908500425fb30c..a009874302e01608b78413a9a67dbce0e7bcb09f 100644 --- a/core/java/com/android/internal/widget/remotecompose/core/operations/DrawOval.java +++ b/core/java/com/android/internal/widget/remotecompose/core/operations/DrawOval.java @@ -50,6 +50,11 @@ public class DrawOval extends DrawBase4 { return OP_CODE; } + /** + * The name of the class + * + * @return the name + */ @NonNull public static String name() { return CLASS_NAME; diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/DrawPath.java b/core/java/com/android/internal/widget/remotecompose/core/operations/DrawPath.java index 41b8243f070f94813717d8e9bac47b4f3383ffd4..398cf4892e127808000c244db417d797a2c2547d 100644 --- a/core/java/com/android/internal/widget/remotecompose/core/operations/DrawPath.java +++ b/core/java/com/android/internal/widget/remotecompose/core/operations/DrawPath.java @@ -62,6 +62,11 @@ public class DrawPath extends PaintOperation { operations.add(op); } + /** + * The name of the class + * + * @return the name + */ @NonNull public static String name() { return CLASS_NAME; diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/DrawRect.java b/core/java/com/android/internal/widget/remotecompose/core/operations/DrawRect.java index 7e22550d654465eac50693e47fa8fbfa7f247923..38477ad0deb60cf050c52a4f4da3410b39def869 100644 --- a/core/java/com/android/internal/widget/remotecompose/core/operations/DrawRect.java +++ b/core/java/com/android/internal/widget/remotecompose/core/operations/DrawRect.java @@ -51,6 +51,11 @@ public class DrawRect extends DrawBase4 { return OP_CODE; } + /** + * The name of the class + * + * @return the name + */ @NonNull public static String name() { return CLASS_NAME; diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/DrawSector.java b/core/java/com/android/internal/widget/remotecompose/core/operations/DrawSector.java index 7616df09b6cc03106fac085d0d0e9c2312bbceb9..51ece77a872a472d00cc629864d9cbeca1d49c5c 100644 --- a/core/java/com/android/internal/widget/remotecompose/core/operations/DrawSector.java +++ b/core/java/com/android/internal/widget/remotecompose/core/operations/DrawSector.java @@ -27,7 +27,7 @@ import com.android.internal.widget.remotecompose.core.documentation.DocumentedOp import java.util.List; public class DrawSector extends DrawBase6 { - public static final int OP_CODE = Operations.DRAW_SECTOR; + private static final int OP_CODE = Operations.DRAW_SECTOR; private static final String CLASS_NAME = "DrawSector"; /** diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/DrawText.java b/core/java/com/android/internal/widget/remotecompose/core/operations/DrawText.java index 2c5d790b2f2a1563131bb1f5b19b97958a391db5..8adba1d2616a1634e5e2276d26011ab48fe6416e 100644 --- a/core/java/com/android/internal/widget/remotecompose/core/operations/DrawText.java +++ b/core/java/com/android/internal/widget/remotecompose/core/operations/DrawText.java @@ -121,6 +121,11 @@ public class DrawText extends PaintOperation implements VariableSupport { operations.add(op); } + /** + * The name of the class + * + * @return the name + */ @NonNull public static String name() { return CLASS_NAME; diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/DrawTextAnchored.java b/core/java/com/android/internal/widget/remotecompose/core/operations/DrawTextAnchored.java index 7de52b8e5f3e9dd4955ccf973144e8ba077027a2..f839922b25e2b03be70f65bfaa13ccaa82b1a943 100644 --- a/core/java/com/android/internal/widget/remotecompose/core/operations/DrawTextAnchored.java +++ b/core/java/com/android/internal/widget/remotecompose/core/operations/DrawTextAnchored.java @@ -130,6 +130,11 @@ public class DrawTextAnchored extends PaintOperation implements VariableSupport operations.add(op); } + /** + * The name of the class + * + * @return the name + */ @NonNull public static String name() { return CLASS_NAME; diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/DrawTextOnPath.java b/core/java/com/android/internal/widget/remotecompose/core/operations/DrawTextOnPath.java index 18d9fdf1b671b775584662e1d88ef24583ede619..86f3c992f2fb90d2cd0f50405650d1102f9cb238 100644 --- a/core/java/com/android/internal/widget/remotecompose/core/operations/DrawTextOnPath.java +++ b/core/java/com/android/internal/widget/remotecompose/core/operations/DrawTextOnPath.java @@ -98,6 +98,11 @@ public class DrawTextOnPath extends PaintOperation implements VariableSupport { operations.add(op); } + /** + * The name of the class + * + * @return the name + */ @NonNull public static String name() { return "DrawTextOnPath"; diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/DrawTweenPath.java b/core/java/com/android/internal/widget/remotecompose/core/operations/DrawTweenPath.java index b83e4c2191b2d1cedc7f3cfe2c90fd8781aa021d..d4d4a5ecf6b9bc906b680b716fe4bb34856f5923 100644 --- a/core/java/com/android/internal/widget/remotecompose/core/operations/DrawTweenPath.java +++ b/core/java/com/android/internal/widget/remotecompose/core/operations/DrawTweenPath.java @@ -108,6 +108,11 @@ public class DrawTweenPath extends PaintOperation implements VariableSupport { operations.add(op); } + /** + * The name of the class + * + * @return the name + */ @NonNull public static String name() { return "DrawTweenPath"; diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/FloatConstant.java b/core/java/com/android/internal/widget/remotecompose/core/operations/FloatConstant.java index 7dd435a5c5b1d2d82191734ae1d8cccfe7d60bbb..e04e691c312c68eed5c7c9f20c8b19f4df9605a1 100644 --- a/core/java/com/android/internal/widget/remotecompose/core/operations/FloatConstant.java +++ b/core/java/com/android/internal/widget/remotecompose/core/operations/FloatConstant.java @@ -51,6 +51,11 @@ public class FloatConstant extends Operation { return "FloatConstant[" + mTextId + "] = " + mValue; } + /** + * The name of the class + * + * @return the name + */ @NonNull public static String name() { return CLASS_NAME; diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/FloatExpression.java b/core/java/com/android/internal/widget/remotecompose/core/operations/FloatExpression.java index 3d92e129a2367a6e29a6b7dac32ae118a2332530..c1872fd0fed0bf0c03aaaa3f66fa5a4633a1d21c 100644 --- a/core/java/com/android/internal/widget/remotecompose/core/operations/FloatExpression.java +++ b/core/java/com/android/internal/widget/remotecompose/core/operations/FloatExpression.java @@ -139,6 +139,11 @@ public class FloatExpression extends Operation implements VariableSupport { } } + // Keep track of the last computed value when we are animated, + // e.g. if FloatAnimation or Spring is used, so that we can + // ask for a repaint. + float mLastAnimatedValue = Float.NaN; + @Override public void apply(@NonNull RemoteContext context) { updateVariables(context); @@ -146,12 +151,23 @@ public class FloatExpression extends Operation implements VariableSupport { if (Float.isNaN(mLastChange)) { mLastChange = t; } + float lastComputedValue; if (mFloatAnimation != null && !Float.isNaN(mLastCalculatedValue)) { float f = mFloatAnimation.get(t - mLastChange); context.loadFloat(mId, f); + lastComputedValue = f; + if (lastComputedValue != mLastAnimatedValue) { + mLastAnimatedValue = lastComputedValue; + context.needsRepaint(); + } } else if (mSpring != null) { float f = mSpring.get(t - mLastChange); context.loadFloat(mId, f); + lastComputedValue = f; + if (lastComputedValue != mLastAnimatedValue) { + mLastAnimatedValue = lastComputedValue; + context.needsRepaint(); + } } else { float v = mExp.eval(context.getCollectionsAccess(), mPreCalcValue, mPreCalcValue.length); @@ -205,6 +221,11 @@ public class FloatExpression extends Operation implements VariableSupport { + ")"; } + /** + * The name of the class + * + * @return the name + */ @NonNull public static String name() { return CLASS_NAME; @@ -236,6 +257,9 @@ public class FloatExpression extends Operation implements VariableSupport { buffer.writeInt(id); int len = value.length; + if (len > MAX_EXPRESSION_SIZE) { + throw new RuntimeException(AnimatedFloatExpression.toString(value, null) + " to long"); + } if (animation != null) { len |= (animation.length << 16); } diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/Header.java b/core/java/com/android/internal/widget/remotecompose/core/operations/Header.java index 04e4346cf05d60f3e15cbb96ebdf8e1529beafb6..656dc09c396f3def8f317fcb02616cf7e7909290 100644 --- a/core/java/com/android/internal/widget/remotecompose/core/operations/Header.java +++ b/core/java/com/android/internal/widget/remotecompose/core/operations/Header.java @@ -39,7 +39,7 @@ public class Header extends Operation implements RemoteComposeOperation { private static final int OP_CODE = Operations.HEADER; private static final String CLASS_NAME = "Header"; public static final int MAJOR_VERSION = 0; - public static final int MINOR_VERSION = 1; + public static final int MINOR_VERSION = 2; public static final int PATCH_VERSION = 0; int mMajorVersion; @@ -115,6 +115,11 @@ public class Header extends Operation implements RemoteComposeOperation { return toString(); } + /** + * The name of the class + * + * @return the name + */ @NonNull public static String name() { return CLASS_NAME; diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/IntegerExpression.java b/core/java/com/android/internal/widget/remotecompose/core/operations/IntegerExpression.java index 67274af7c28330e56f980f467196f9fb24546fa0..f04f30dc62fb36e2cce594077438a5b4d5e4d438 100644 --- a/core/java/com/android/internal/widget/remotecompose/core/operations/IntegerExpression.java +++ b/core/java/com/android/internal/widget/remotecompose/core/operations/IntegerExpression.java @@ -136,6 +136,11 @@ public class IntegerExpression extends Operation implements VariableSupport { return "IntegerExpression[" + mId + "] = (" + s + ")"; } + /** + * The name of the class + * + * @return the name + */ @NonNull public static String name() { return CLASS_NAME; diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/MatrixRestore.java b/core/java/com/android/internal/widget/remotecompose/core/operations/MatrixRestore.java index aed597ae74940b389ca841196d4066b3f5affd41..044430d1e3c162409004ca3526351c666a0e54ad 100644 --- a/core/java/com/android/internal/widget/remotecompose/core/operations/MatrixRestore.java +++ b/core/java/com/android/internal/widget/remotecompose/core/operations/MatrixRestore.java @@ -26,6 +26,7 @@ import com.android.internal.widget.remotecompose.core.documentation.Documentatio import java.util.List; +/** The restore previous matrix command */ public class MatrixRestore extends PaintOperation { private static final int OP_CODE = Operations.MATRIX_RESTORE; private static final String CLASS_NAME = "MatrixRestore"; @@ -54,6 +55,11 @@ public class MatrixRestore extends PaintOperation { return "MatrixRestore"; } + /** + * The name of the class + * + * @return the name + */ @NonNull public static String name() { return CLASS_NAME; diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/MatrixRotate.java b/core/java/com/android/internal/widget/remotecompose/core/operations/MatrixRotate.java index fece143ebfa15365d5b8419061d0307448b6f5a0..57f5a0ebfab19535c60ead478b2e3e5be3af0675 100644 --- a/core/java/com/android/internal/widget/remotecompose/core/operations/MatrixRotate.java +++ b/core/java/com/android/internal/widget/remotecompose/core/operations/MatrixRotate.java @@ -26,8 +26,9 @@ import com.android.internal.widget.remotecompose.core.documentation.DocumentedOp import java.util.List; +/** The rotate the rendering command */ public class MatrixRotate extends DrawBase3 { - public static final int OP_CODE = Operations.MATRIX_ROTATE; + private static final int OP_CODE = Operations.MATRIX_ROTATE; private static final String CLASS_NAME = "MatrixRotate"; /** @@ -57,6 +58,11 @@ public class MatrixRotate extends DrawBase3 { return OP_CODE; } + /** + * The name of the class + * + * @return the name + */ @NonNull public static String name() { return CLASS_NAME; diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/MatrixSave.java b/core/java/com/android/internal/widget/remotecompose/core/operations/MatrixSave.java index 7eb7b3ffaf34a1b8edad1df6f07113e3e2370a78..aec316aea36157ba521c301472fa03fd073f6106 100644 --- a/core/java/com/android/internal/widget/remotecompose/core/operations/MatrixSave.java +++ b/core/java/com/android/internal/widget/remotecompose/core/operations/MatrixSave.java @@ -26,6 +26,7 @@ import com.android.internal.widget.remotecompose.core.documentation.Documentatio import java.util.List; +/** The save the matrix state command */ public class MatrixSave extends PaintOperation { private static final int OP_CODE = Operations.MATRIX_SAVE; private static final String CLASS_NAME = "MatrixSave"; @@ -52,6 +53,11 @@ public class MatrixSave extends PaintOperation { operations.add(op); } + /** + * The name of the class + * + * @return the name + */ @NonNull public static String name() { return CLASS_NAME; diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/MatrixScale.java b/core/java/com/android/internal/widget/remotecompose/core/operations/MatrixScale.java index 49bdd1b06eedbe6dc42105d2780cf561e77df6a6..07f965f7d72afe8f3417aaa9db53faffa3d5a080 100644 --- a/core/java/com/android/internal/widget/remotecompose/core/operations/MatrixScale.java +++ b/core/java/com/android/internal/widget/remotecompose/core/operations/MatrixScale.java @@ -26,9 +26,10 @@ import com.android.internal.widget.remotecompose.core.documentation.DocumentedOp import java.util.List; +/** Scale the rendering matrix command */ public class MatrixScale extends DrawBase4 { - public static final int OP_CODE = Operations.MATRIX_SCALE; - public static final String CLASS_NAME = "MatrixScale"; + private static final int OP_CODE = Operations.MATRIX_SCALE; + private static final String CLASS_NAME = "MatrixScale"; /** * Read this operation and add it to the list of operations @@ -50,6 +51,11 @@ public class MatrixScale extends DrawBase4 { return OP_CODE; } + /** + * The name of the class + * + * @return the name + */ @NonNull public static String name() { return CLASS_NAME; diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/MatrixSkew.java b/core/java/com/android/internal/widget/remotecompose/core/operations/MatrixSkew.java index 54b6fd1fa9ae370b7c2771cb1c1380fb44763a8e..b31492d2cb57cd6e3f57ae561448cac5f8170574 100644 --- a/core/java/com/android/internal/widget/remotecompose/core/operations/MatrixSkew.java +++ b/core/java/com/android/internal/widget/remotecompose/core/operations/MatrixSkew.java @@ -27,9 +27,10 @@ import com.android.internal.widget.remotecompose.core.documentation.Documentatio import java.util.List; +/** Skew the matrix command */ public class MatrixSkew extends DrawBase2 { - public static final int OP_CODE = Operations.MATRIX_SKEW; - public static final String CLASS_NAME = "MatrixSkew"; + private static final int OP_CODE = Operations.MATRIX_SKEW; + private static final String CLASS_NAME = "MatrixSkew"; /** * Read this operation and add it to the list of operations @@ -51,6 +52,11 @@ public class MatrixSkew extends DrawBase2 { return OP_CODE; } + /** + * The name of the class + * + * @return the name + */ @NonNull public static String name() { return CLASS_NAME; diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/MatrixTranslate.java b/core/java/com/android/internal/widget/remotecompose/core/operations/MatrixTranslate.java index b57d83b770b2c0b5fd8340323ec6133842e0d45c..11fa040183cedd077eda43bbf79e628ea803017e 100644 --- a/core/java/com/android/internal/widget/remotecompose/core/operations/MatrixTranslate.java +++ b/core/java/com/android/internal/widget/remotecompose/core/operations/MatrixTranslate.java @@ -26,9 +26,10 @@ import com.android.internal.widget.remotecompose.core.documentation.DocumentedOp import java.util.List; +/** translate the matrix command */ public class MatrixTranslate extends DrawBase2 { - public static final int OP_CODE = Operations.MATRIX_TRANSLATE; - public static final String CLASS_NAME = "MatrixTranslate"; + private static final int OP_CODE = Operations.MATRIX_TRANSLATE; + private static final String CLASS_NAME = "MatrixTranslate"; /** * Read this operation and add it to the list of operations @@ -50,6 +51,11 @@ public class MatrixTranslate extends DrawBase2 { return OP_CODE; } + /** + * The name of the class + * + * @return the name + */ @NonNull public static String name() { return CLASS_NAME; diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/NamedVariable.java b/core/java/com/android/internal/widget/remotecompose/core/operations/NamedVariable.java index 3c82f2b27ca68e97bb39ba4a0c9f439da4ec9983..dde632e0c346519ac7fa91746a151c097e0a4512 100644 --- a/core/java/com/android/internal/widget/remotecompose/core/operations/NamedVariable.java +++ b/core/java/com/android/internal/widget/remotecompose/core/operations/NamedVariable.java @@ -64,6 +64,11 @@ public class NamedVariable extends Operation { + mVarType; } + /** + * The name of the class + * + * @return the name + */ @NonNull public static String name() { return CLASS_NAME; diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/PaintData.java b/core/java/com/android/internal/widget/remotecompose/core/operations/PaintData.java index 3c0a842371c7c8af741f24314a2d29da8630b44d..daf2c5502c5de9a0dd1d50fcbac60b29f5e61db1 100644 --- a/core/java/com/android/internal/widget/remotecompose/core/operations/PaintData.java +++ b/core/java/com/android/internal/widget/remotecompose/core/operations/PaintData.java @@ -61,6 +61,11 @@ public class PaintData extends PaintOperation implements VariableSupport { return "PaintData " + "\"" + mPaintData + "\""; } + /** + * The name of the class + * + * @return the name + */ @NonNull public static String name() { return CLASS_NAME; @@ -92,6 +97,11 @@ public class PaintData extends PaintOperation implements VariableSupport { operations.add(data); } + /** + * Populate the documentation with a description of this operation + * + * @param doc to append the description to. + */ public static void documentation(@NonNull DocumentationBuilder doc) { doc.operation("Data Operations", OP_CODE, CLASS_NAME) .description("Encode a Paint ") diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/PathAppend.java b/core/java/com/android/internal/widget/remotecompose/core/operations/PathAppend.java index 2b00001a521e0e9b5c3447f6f42b74cc67ef9981..7ff879e41cacc3a8776852b111681481fc196520 100644 --- a/core/java/com/android/internal/widget/remotecompose/core/operations/PathAppend.java +++ b/core/java/com/android/internal/widget/remotecompose/core/operations/PathAppend.java @@ -109,6 +109,11 @@ public class PathAppend extends PaintOperation implements VariableSupport { public static final float CLOSE_NAN = Utils.asNan(CLOSE); public static final float DONE_NAN = Utils.asNan(DONE); + /** + * The name of the class + * + * @return the name + */ @NonNull public static String name() { return CLASS_NAME; @@ -162,11 +167,12 @@ public class PathAppend extends PaintOperation implements VariableSupport { } @Override - public void paint(PaintContext context) {} + public void paint(PaintContext context) { + apply(context.getContext()); + } @Override public void apply(@NonNull RemoteContext context) { - updateVariables(context); float[] data = context.getPathData(mInstanceId); float[] out = mOutputPath; if (data != null) { diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/PathCreate.java b/core/java/com/android/internal/widget/remotecompose/core/operations/PathCreate.java index b62f36b8db5f2d2fd07ed7b55d00f9d15d0804c7..75562cd8fb4c408ee71bfc0dfa4b5e187502b77b 100644 --- a/core/java/com/android/internal/widget/remotecompose/core/operations/PathCreate.java +++ b/core/java/com/android/internal/widget/remotecompose/core/operations/PathCreate.java @@ -48,6 +48,7 @@ public class PathCreate extends PaintOperation implements VariableSupport { @Override public void updateVariables(@NonNull RemoteContext context) { + for (int i = 0; i < mFloatPath.length; i++) { float v = mFloatPath[i]; if (Utils.isVariable(v)) { @@ -81,7 +82,19 @@ public class PathCreate extends PaintOperation implements VariableSupport { @NonNull @Override public String toString() { - return "PathCreate[" + mInstanceId + "] = " + "\"" + deepToString(" ") + "\""; + return "PathCreate[" + + mInstanceId + + "] = " + + "\"" + + deepToString(" ") + + "\"[" + + Utils.idStringFromNan(mFloatPath[1]) + + "] " + + mOutputPath[1] + + " [" + + Utils.idStringFromNan(mFloatPath[2]) + + "] " + + mOutputPath[2]; } public static final int MOVE = 10; @@ -99,6 +112,11 @@ public class PathCreate extends PaintOperation implements VariableSupport { public static final float CLOSE_NAN = Utils.asNan(CLOSE); public static final float DONE_NAN = Utils.asNan(DONE); + /** + * The name of the class + * + * @return the name + */ @NonNull public static String name() { return CLASS_NAME; @@ -197,7 +215,9 @@ public class PathCreate extends PaintOperation implements VariableSupport { } @Override - public void paint(PaintContext context) {} + public void paint(PaintContext context) { + apply(context.getContext()); + } @Override public void apply(@NonNull RemoteContext context) { diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/PathData.java b/core/java/com/android/internal/widget/remotecompose/core/operations/PathData.java index 4ec5436c8689ec6e3f3f27e478bb6b9609ec306b..85a01fc7cbc77143b7972e87816bfa6ad2322549 100644 --- a/core/java/com/android/internal/widget/remotecompose/core/operations/PathData.java +++ b/core/java/com/android/internal/widget/remotecompose/core/operations/PathData.java @@ -38,6 +38,7 @@ public class PathData extends Operation implements VariableSupport { int mInstanceId; float[] mFloatPath; float[] mOutputPath; + private boolean mPathChanged = true; PathData(int instanceId, float[] floatPath) { mInstanceId = instanceId; @@ -50,7 +51,11 @@ public class PathData extends Operation implements VariableSupport { for (int i = 0; i < mFloatPath.length; i++) { float v = mFloatPath[i]; if (Utils.isVariable(v)) { + float tmp = mOutputPath[i]; mOutputPath[i] = Float.isNaN(v) ? context.getFloat(Utils.idFromNan(v)) : v; + if (tmp != mOutputPath[i]) { + mPathChanged = true; + } } else { mOutputPath[i] = v; } @@ -107,6 +112,11 @@ public class PathData extends Operation implements VariableSupport { public static final float CLOSE_NAN = Utils.asNan(CLOSE); public static final float DONE_NAN = Utils.asNan(DONE); + /** + * The name of the class + * + * @return the name + */ @NonNull public static String name() { return CLASS_NAME; @@ -216,6 +226,9 @@ public class PathData extends Operation implements VariableSupport { @Override public void apply(@NonNull RemoteContext context) { - context.loadPathData(mInstanceId, mOutputPath); + if (mPathChanged) { + context.loadPathData(mInstanceId, mOutputPath); + } + mPathChanged = false; } } diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/PathTween.java b/core/java/com/android/internal/widget/remotecompose/core/operations/PathTween.java index a6fa680f647a5a05d9f3ad5142a0e22276a43ad6..65adfeabefa657fee45eb70c7c29bba695a2b5a3 100644 --- a/core/java/com/android/internal/widget/remotecompose/core/operations/PathTween.java +++ b/core/java/com/android/internal/widget/remotecompose/core/operations/PathTween.java @@ -80,6 +80,11 @@ public class PathTween extends PaintOperation implements VariableSupport { + floatToString(mTween, mTweenOut); } + /** + * The name of the class + * + * @return the name + */ @NonNull public static String name() { return CLASS_NAME; diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/RootContentBehavior.java b/core/java/com/android/internal/widget/remotecompose/core/operations/RootContentBehavior.java index aaa717629c2ef70f183790444b0a9ad656ea1d1e..55dd88233265b9df5621413f118158dfb1f6e23b 100644 --- a/core/java/com/android/internal/widget/remotecompose/core/operations/RootContentBehavior.java +++ b/core/java/com/android/internal/widget/remotecompose/core/operations/RootContentBehavior.java @@ -200,6 +200,11 @@ public class RootContentBehavior extends Operation implements RemoteComposeOpera return toString(); } + /** + * The name of the class + * + * @return the name + */ @NonNull public static String name() { return CLASS_NAME; @@ -239,6 +244,11 @@ public class RootContentBehavior extends Operation implements RemoteComposeOpera operations.add(rootContentBehavior); } + /** + * Populate the documentation with a description of this operation + * + * @param doc to append the description to. + */ public static void documentation(@NonNull DocumentationBuilder doc) { doc.operation("Protocol Operations", OP_CODE, CLASS_NAME) .description("Describes the behaviour of the root") diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/RootContentDescription.java b/core/java/com/android/internal/widget/remotecompose/core/operations/RootContentDescription.java index e92daa384dc3dbce33e7b120b15de7297c0459be..ad86e0f2b1f3168f5ee4959faff6aa50e4ed9457 100644 --- a/core/java/com/android/internal/widget/remotecompose/core/operations/RootContentDescription.java +++ b/core/java/com/android/internal/widget/remotecompose/core/operations/RootContentDescription.java @@ -24,11 +24,13 @@ import com.android.internal.widget.remotecompose.core.RemoteContext; import com.android.internal.widget.remotecompose.core.WireBuffer; import com.android.internal.widget.remotecompose.core.documentation.DocumentationBuilder; import com.android.internal.widget.remotecompose.core.documentation.DocumentedOperation; +import com.android.internal.widget.remotecompose.core.semantics.AccessibleComponent; import java.util.List; /** Describe a content description for the document */ -public class RootContentDescription extends Operation implements RemoteComposeOperation { +public class RootContentDescription extends Operation + implements RemoteComposeOperation, AccessibleComponent { private static final int OP_CODE = Operations.ROOT_CONTENT_DESCRIPTION; private static final String CLASS_NAME = "RootContentDescription"; int mContentDescription; @@ -42,6 +44,11 @@ public class RootContentDescription extends Operation implements RemoteComposeOp this.mContentDescription = contentDescription; } + @Override + public boolean isInterestingForSemantics() { + return mContentDescription != 0; + } + @Override public void write(@NonNull WireBuffer buffer) { apply(buffer, mContentDescription); @@ -64,6 +71,16 @@ public class RootContentDescription extends Operation implements RemoteComposeOp return toString(); } + @Override + public Integer getContentDescriptionId() { + return mContentDescription; + } + + /** + * The name of the class + * + * @return the name + */ @NonNull public static String name() { return CLASS_NAME; diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/ShaderData.java b/core/java/com/android/internal/widget/remotecompose/core/operations/ShaderData.java index e2502feb2bb154b6568f1fa0144f9d8a48fe6e6a..891367e33d87c88ae6bab82be1287e554cf913f9 100644 --- a/core/java/com/android/internal/widget/remotecompose/core/operations/ShaderData.java +++ b/core/java/com/android/internal/widget/remotecompose/core/operations/ShaderData.java @@ -50,6 +50,7 @@ public class ShaderData extends Operation implements VariableSupport { @Nullable HashMap mUniformFloatMap = null; @Nullable HashMap mUniformIntMap; @Nullable HashMap mUniformBitmapMap = null; + private boolean mShaderValid = false; public ShaderData( int shaderID, @@ -198,6 +199,11 @@ public class ShaderData extends Operation implements VariableSupport { } } + /** + * The name of the class + * + * @return the name + */ @NonNull public static String name() { return CLASS_NAME; @@ -353,7 +359,9 @@ public class ShaderData extends Operation implements VariableSupport { @Override public void apply(@NonNull RemoteContext context) { - context.loadShader(mShaderID, this); + if (mShaderValid) { + context.loadShader(mShaderID, this); + } } @NonNull @@ -361,4 +369,13 @@ public class ShaderData extends Operation implements VariableSupport { public String deepToString(@NonNull String indent) { return indent + toString(); } + + /** + * Enable or disable the shader + * + * @param shaderValid if true shader can be used + */ + public void enable(boolean shaderValid) { + mShaderValid = shaderValid; + } } diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/TextData.java b/core/java/com/android/internal/widget/remotecompose/core/operations/TextData.java index 3f679bf4758247b8a3a38d689b1f3350f716f1ff..d48de37996ee3f7862165b891a2724d17cca3a24 100644 --- a/core/java/com/android/internal/widget/remotecompose/core/operations/TextData.java +++ b/core/java/com/android/internal/widget/remotecompose/core/operations/TextData.java @@ -54,6 +54,11 @@ public class TextData extends Operation implements SerializableToString { return "TextData[" + mTextId + "] = \"" + Utils.trimString(mText, 10) + "\""; } + /** + * The name of the class + * + * @return the name + */ @NonNull public static String name() { return CLASS_NAME; diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/TextFromFloat.java b/core/java/com/android/internal/widget/remotecompose/core/operations/TextFromFloat.java index 4d01e0c3cbe4247eaf77a161361b12838aaa7083..cc0ff025f09b2aec5031d762de32dae7be4b44b9 100644 --- a/core/java/com/android/internal/widget/remotecompose/core/operations/TextFromFloat.java +++ b/core/java/com/android/internal/widget/remotecompose/core/operations/TextFromFloat.java @@ -122,6 +122,11 @@ public class TextFromFloat extends Operation implements VariableSupport { } } + /** + * The name of the class + * + * @return the name + */ @NonNull public static String name() { return CLASS_NAME; diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/TextLookup.java b/core/java/com/android/internal/widget/remotecompose/core/operations/TextLookup.java index 3ec6f019c3585777f4af97e53470f1584bc0730e..dceb8b67ec3a7aa57ca8b22de8c6b65c13f008cb 100644 --- a/core/java/com/android/internal/widget/remotecompose/core/operations/TextLookup.java +++ b/core/java/com/android/internal/widget/remotecompose/core/operations/TextLookup.java @@ -79,6 +79,11 @@ public class TextLookup extends Operation implements VariableSupport { } } + /** + * The name of the class + * + * @return the name + */ @NonNull public static String name() { return CLASS_NAME; diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/TextLookupInt.java b/core/java/com/android/internal/widget/remotecompose/core/operations/TextLookupInt.java index 9c0ee535f62a1604224208fe1924ed574aa0ca87..823b70656c8652678de4ef2037bb9a74d89e8b69 100644 --- a/core/java/com/android/internal/widget/remotecompose/core/operations/TextLookupInt.java +++ b/core/java/com/android/internal/widget/remotecompose/core/operations/TextLookupInt.java @@ -72,6 +72,11 @@ public class TextLookupInt extends Operation implements VariableSupport { context.listensTo(mIndex, this); } + /** + * The name of the class + * + * @return the name + */ @NonNull public static String name() { return CLASS_NAME; diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/TextMerge.java b/core/java/com/android/internal/widget/remotecompose/core/operations/TextMerge.java index 5b0c38fe996b49ce7a490345ca4e58ee82b11ee4..d69561566b562a52024283988ebfa66fb2afe773 100644 --- a/core/java/com/android/internal/widget/remotecompose/core/operations/TextMerge.java +++ b/core/java/com/android/internal/widget/remotecompose/core/operations/TextMerge.java @@ -53,6 +53,11 @@ public class TextMerge extends Operation { return "TextMerge[" + mTextId + "] = [" + mSrcId1 + " ] + [ " + mSrcId2 + "]"; } + /** + * The name of the class + * + * @return the name + */ @NonNull public static String name() { return CLASS_NAME; diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/Theme.java b/core/java/com/android/internal/widget/remotecompose/core/operations/Theme.java index e329c38daf20af490edf0689a9920aca02ab3975..e9aae1ebad455419ef31fc965bc40e7f48ab9477 100644 --- a/core/java/com/android/internal/widget/remotecompose/core/operations/Theme.java +++ b/core/java/com/android/internal/widget/remotecompose/core/operations/Theme.java @@ -64,6 +64,7 @@ public class Theme extends Operation implements RemoteComposeOperation { @Override public void apply(@NonNull RemoteContext context) { context.setTheme(mTheme); + markDirty(); } @NonNull @@ -72,6 +73,11 @@ public class Theme extends Operation implements RemoteComposeOperation { return indent + toString(); } + /** + * The name of the class + * + * @return the name + */ @NonNull public static String name() { return CLASS_NAME; diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/TouchExpression.java b/core/java/com/android/internal/widget/remotecompose/core/operations/TouchExpression.java index e2e20bc5e57f51fec3ae3e54f1dc6929fc8f92f2..14b72af84e66e123f8c3fd370981acab3f5557ee 100644 --- a/core/java/com/android/internal/widget/remotecompose/core/operations/TouchExpression.java +++ b/core/java/com/android/internal/widget/remotecompose/core/operations/TouchExpression.java @@ -21,6 +21,7 @@ import static com.android.internal.widget.remotecompose.core.documentation.Docum import static com.android.internal.widget.remotecompose.core.documentation.DocumentedOperation.SHORT; import android.annotation.NonNull; +import android.annotation.Nullable; import com.android.internal.widget.remotecompose.core.Operation; import com.android.internal.widget.remotecompose.core.Operations; @@ -30,6 +31,7 @@ import com.android.internal.widget.remotecompose.core.VariableSupport; import com.android.internal.widget.remotecompose.core.WireBuffer; import com.android.internal.widget.remotecompose.core.documentation.DocumentationBuilder; import com.android.internal.widget.remotecompose.core.operations.layout.Component; +import com.android.internal.widget.remotecompose.core.operations.layout.RootLayoutComponent; import com.android.internal.widget.remotecompose.core.operations.utilities.AnimatedFloatExpression; import com.android.internal.widget.remotecompose.core.operations.utilities.NanMap; import com.android.internal.widget.remotecompose.core.operations.utilities.touch.VelocityEasing; @@ -80,14 +82,41 @@ public class TouchExpression extends Operation implements VariableSupport, Touch int mTouchEffects; float mVelocityId; + /** Stop with some deceleration */ public static final int STOP_GENTLY = 0; + + /** Stop only at the start or end */ public static final int STOP_ENDS = 2; + + /** Stop on touch up */ public static final int STOP_INSTANTLY = 1; + + /** Stop at evenly spaced notches */ public static final int STOP_NOTCHES_EVEN = 3; + + /** Stop at a collection points described in percents of the range */ public static final int STOP_NOTCHES_PERCENTS = 4; + + /** Stop at a collectiond of point described in abslute cordnates */ public static final int STOP_NOTCHES_ABSOLUTE = 5; + + /** Jump to the absloute poition of the point */ public static final int STOP_ABSOLUTE_POS = 6; + /** + * create a touch expression + * + * @param id The float id the value is output to + * @param exp the expression (containing TOUCH_* ) + * @param defValue the default value + * @param min the minimum value + * @param max the maximum value + * @param touchEffects the type of touch mode + * @param velocityId the valocity (not used) + * @param stopMode the behavour on touch oup + * @param stopSpec the paraameters that affect the touch up behavour + * @param easingSpec the easing parameters for coming to a stop + */ public TouchExpression( int id, float[] exp, @@ -129,7 +158,6 @@ public class TouchExpression extends Operation implements VariableSupport, Touch @Override public void updateVariables(RemoteContext context) { - if (mPreCalcValue == null || mPreCalcValue.length != mSrcExp.length) { mPreCalcValue = new float[mSrcExp.length]; } @@ -192,7 +220,9 @@ public class TouchExpression extends Operation implements VariableSupport, Touch if (Float.isNaN(mDefValue)) { context.listensTo(Utils.idFromNan(mDefValue), this); } - context.addTouchListener(this); + if (mComponent == null) { + context.addTouchListener(this); + } for (float v : mSrcExp) { if (Float.isNaN(v) && !AnimatedFloatExpression.isMathOperator(v) @@ -332,9 +362,26 @@ public class TouchExpression extends Operation implements VariableSupport, Touch float mScrLeft, mScrRight, mScrTop, mScrBottom; - @Override - public void apply(RemoteContext context) { - Component comp = context.mLastComponent; + @Nullable Component mComponent; + + /** + * Set the component the touch expression is in (if any) + * + * @param component the component, or null if outside + */ + public void setComponent(@Nullable Component component) { + mComponent = component; + if (mComponent != null) { + try { + RootLayoutComponent root = mComponent.getRoot(); + root.setHasTouchListeners(true); + } catch (Exception e) { + } + } + } + + private void updateBounds() { + Component comp = mComponent; if (comp != null) { float x = comp.getX(); float y = comp.getY(); @@ -351,7 +398,11 @@ public class TouchExpression extends Operation implements VariableSupport, Touch mScrRight = w + x; mScrBottom = h + y; } - updateVariables(context); + } + + @Override + public void apply(RemoteContext context) { + updateBounds(); if (mUnmodified) { mCurrentValue = mOutDefValue; context.loadFloat(mId, wrap(mCurrentValue)); @@ -371,6 +422,7 @@ public class TouchExpression extends Operation implements VariableSupport, Touch mEasingToStop = false; } crossNotchCheck(context); + context.needsRepaint(); return; } if (mTouchDown) { @@ -395,11 +447,11 @@ public class TouchExpression extends Operation implements VariableSupport, Touch @Override public void touchDown(RemoteContext context, float x, float y) { - if (!(x >= mScrLeft && x <= mScrRight && y >= mScrTop && y <= mScrBottom)) { Utils.log("NOT IN WINDOW " + x + ", " + y + " " + mScrLeft + ", " + mScrTop); return; } + mEasingToStop = false; mTouchDown = true; mUnmodified = false; if (mMode == 0) { @@ -407,6 +459,7 @@ public class TouchExpression extends Operation implements VariableSupport, Touch mDownTouchValue = mExp.eval(context.getCollectionsAccess(), mPreCalcValue, mPreCalcValue.length); } + context.needsRepaint(); } @Override @@ -441,6 +494,7 @@ public class TouchExpression extends Operation implements VariableSupport, Touch float time = mMaxTime * Math.abs(dest - value) / (2 * mMaxVelocity); mEasyTouch.config(value, dest, slope, time, mMaxAcceleration, mMaxVelocity, null); mEasingToStop = true; + context.needsRepaint(); } @Override @@ -449,7 +503,7 @@ public class TouchExpression extends Operation implements VariableSupport, Touch return; } apply(context); - context.getDocument().getRootLayoutComponent().needsRepaint(); + context.needsRepaint(); } @Override @@ -494,6 +548,12 @@ public class TouchExpression extends Operation implements VariableSupport, Touch // ===================== static ====================== + /** + * The name of the class + * + * @return the name + */ + @NonNull public static String name() { return CLASS_NAME; } diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/layout/ActionOperation.java b/core/java/com/android/internal/widget/remotecompose/core/operations/layout/ActionOperation.java index 0f840597e3c6d67faa51a43947ef216c2b0f13d4..1c241601765b739955177349a3d435e486be8643 100644 --- a/core/java/com/android/internal/widget/remotecompose/core/operations/layout/ActionOperation.java +++ b/core/java/com/android/internal/widget/remotecompose/core/operations/layout/ActionOperation.java @@ -23,8 +23,23 @@ import com.android.internal.widget.remotecompose.core.operations.utilities.Strin /** Operations representing actions on the document */ public interface ActionOperation { + /** + * Serialize the string + * + * @param indent padding to display + * @param serializer append the string + */ void serializeToString(int indent, @NonNull StringSerializer serializer); + /** + * Run the action + * + * @param context remote context + * @param document document + * @param component component + * @param x the x location of the action + * @param y the y location of the action + */ void runAction( @NonNull RemoteContext context, @NonNull CoreDocument document, diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/layout/AnimatableValue.java b/core/java/com/android/internal/widget/remotecompose/core/operations/layout/AnimatableValue.java index 19f4c2b049565666f38795e63840c0b5915e8282..652ab2bc1cbc488a26f5446be6a742d021020822 100644 --- a/core/java/com/android/internal/widget/remotecompose/core/operations/layout/AnimatableValue.java +++ b/core/java/com/android/internal/widget/remotecompose/core/operations/layout/AnimatableValue.java @@ -20,6 +20,7 @@ import com.android.internal.widget.remotecompose.core.operations.Utils; import com.android.internal.widget.remotecompose.core.operations.utilities.easing.FloatAnimation; import com.android.internal.widget.remotecompose.core.operations.utilities.easing.GeneralEasing; +/** Value animation for layouts */ public class AnimatableValue { boolean mIsVariable = false; int mId = 0; @@ -34,6 +35,11 @@ public class AnimatableValue { int mMotionEasingType = GeneralEasing.CUBIC_STANDARD; FloatAnimation mMotionEasing; + /** + * Value to animate + * + * @param value value + */ public AnimatableValue(float value) { if (Utils.isVariable(value)) { mId = Utils.idFromNan(value); @@ -43,10 +49,21 @@ public class AnimatableValue { } } + /** + * Get the value + * + * @return the value + */ public float getValue() { return mValue; } + /** + * Evaluate going through FloatAnimation if needed + * + * @param context the paint context + * @return the current value + */ public float evaluate(PaintContext context) { if (!mIsVariable) { return mValue; diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/layout/CanvasContent.java b/core/java/com/android/internal/widget/remotecompose/core/operations/layout/CanvasContent.java index 121b18014a21805142fb6dd42c6bb22b51e3878a..34b7a2326a2132a9f4979e675c62e724b473b5c3 100644 --- a/core/java/com/android/internal/widget/remotecompose/core/operations/layout/CanvasContent.java +++ b/core/java/com/android/internal/widget/remotecompose/core/operations/layout/CanvasContent.java @@ -41,6 +41,11 @@ public class CanvasContent extends Component implements ComponentStartOperation super(parent, componentId, animationId, x, y, width, height); } + /** + * The name of the class + * + * @return the name + */ @NonNull public static String name() { return "CanvasContent"; @@ -77,6 +82,11 @@ public class CanvasContent extends Component implements ComponentStartOperation operations.add(new CanvasContent(componentId, 0, 0, 0, 0, null, -1)); } + /** + * Populate the documentation with a description of this operation + * + * @param doc to append the description to. + */ public static void documentation(@NonNull DocumentationBuilder doc) { doc.operation("Layout Operations", id(), name()) .field(INT, "COMPONENT_ID", "unique id for this component") diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/layout/ClickModifierOperation.java b/core/java/com/android/internal/widget/remotecompose/core/operations/layout/ClickModifierOperation.java index 34c42494d964b470e152d21c092ece9a9a223576..e05bdf2b824df6f6c40dcb2881000cafbc6bd328 100644 --- a/core/java/com/android/internal/widget/remotecompose/core/operations/layout/ClickModifierOperation.java +++ b/core/java/com/android/internal/widget/remotecompose/core/operations/layout/ClickModifierOperation.java @@ -16,6 +16,7 @@ package com.android.internal.widget.remotecompose.core.operations.layout; import android.annotation.NonNull; +import android.annotation.Nullable; import com.android.internal.widget.remotecompose.core.CoreDocument; import com.android.internal.widget.remotecompose.core.Operation; @@ -33,13 +34,15 @@ import com.android.internal.widget.remotecompose.core.operations.utilities.Color import com.android.internal.widget.remotecompose.core.operations.utilities.StringSerializer; import com.android.internal.widget.remotecompose.core.operations.utilities.easing.Easing; import com.android.internal.widget.remotecompose.core.operations.utilities.easing.FloatAnimation; +import com.android.internal.widget.remotecompose.core.semantics.AccessibleComponent; +import com.android.internal.widget.remotecompose.core.semantics.CoreSemantics; import java.util.ArrayList; import java.util.List; /** Represents a click modifier + actions */ public class ClickModifierOperation extends PaintOperation - implements ModifierOperation, DecoratorComponent, ClickHandler { + implements ModifierOperation, DecoratorComponent, ClickHandler, AccessibleComponent { private static final int OP_CODE = Operations.MODIFIER_CLICK; long mAnimateRippleStart = 0; @@ -54,6 +57,22 @@ public class ClickModifierOperation extends PaintOperation @NonNull PaintBundle mPaint = new PaintBundle(); + @Override + public boolean isClickable() { + return true; + } + + @Nullable + @Override + public Role getRole() { + return Role.BUTTON; + } + + @Override + public CoreSemantics.Mode getMode() { + return CoreSemantics.Mode.MERGE; + } + public void animateRipple(float x, float y) { mAnimateRippleStart = System.currentTimeMillis(); mAnimateRippleX = x; @@ -80,9 +99,14 @@ public class ClickModifierOperation extends PaintOperation @Override public void apply(@NonNull RemoteContext context) { + RootLayoutComponent root = context.getDocument().getRootLayoutComponent(); + if (root != null) { + root.setHasTouchListeners(true); + } for (Operation op : mList) { if (op instanceof TextData) { op.apply(context); + context.incrementOpCount(); } } } @@ -136,7 +160,8 @@ public class ClickModifierOperation extends PaintOperation } @Override - public void layout(@NonNull RemoteContext context, float width, float height) { + public void layout( + @NonNull RemoteContext context, Component component, float width, float height) { mWidth = width; mHeight = height; } @@ -173,6 +198,11 @@ public class ClickModifierOperation extends PaintOperation context.hapticEffect(3); } + /** + * The name of the class + * + * @return the name + */ @NonNull public static String name() { return "ClickModifier"; @@ -192,6 +222,11 @@ public class ClickModifierOperation extends PaintOperation operations.add(new ClickModifierOperation()); } + /** + * Populate the documentation with a description of this operation + * + * @param doc to append the description to. + */ public static void documentation(@NonNull DocumentationBuilder doc) { doc.operation("Layout Operations", OP_CODE, name()) .description( diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/layout/Component.java b/core/java/com/android/internal/widget/remotecompose/core/operations/layout/Component.java index faa259f6b8351b09301d46141a4ba63442c7869f..8a77dc3aafa5427d13ddf7bb911e691f86a6096b 100644 --- a/core/java/com/android/internal/widget/remotecompose/core/operations/layout/Component.java +++ b/core/java/com/android/internal/widget/remotecompose/core/operations/layout/Component.java @@ -28,6 +28,7 @@ import com.android.internal.widget.remotecompose.core.VariableSupport; import com.android.internal.widget.remotecompose.core.WireBuffer; import com.android.internal.widget.remotecompose.core.operations.ComponentValue; import com.android.internal.widget.remotecompose.core.operations.TextData; +import com.android.internal.widget.remotecompose.core.operations.TouchExpression; import com.android.internal.widget.remotecompose.core.operations.layout.animation.AnimateMeasure; import com.android.internal.widget.remotecompose.core.operations.layout.animation.AnimationSpec; import com.android.internal.widget.remotecompose.core.operations.layout.measure.ComponentMeasure; @@ -65,6 +66,34 @@ public class Component extends PaintOperation implements Measurable, Serializabl protected float mZIndex = 0f; + private boolean mNeedsBoundsAnimation = false; + + /** + * Mark the component as needing a bounds animation pass + */ + public void markNeedsBoundsAnimation() { + mNeedsBoundsAnimation = true; + if (mParent != null && !mParent.mNeedsBoundsAnimation) { + mParent.markNeedsBoundsAnimation(); + } + } + + /** + * Clear the bounds animation pass flag + */ + public void clearNeedsBoundsAnimation() { + mNeedsBoundsAnimation = false; + } + + /** + * True if needs a bounds animation + * + * @return true if needs a bounds animation pass + */ + public boolean needsBoundsAnimation() { + return mNeedsBoundsAnimation; + } + public float getZIndex() { return mZIndex; } @@ -119,6 +148,17 @@ public class Component extends PaintOperation implements Measurable, Serializabl mHeight = value; } + @Override + public void apply(@NonNull RemoteContext context) { + for (Operation op : mList) { + if (op instanceof VariableSupport && op.isDirty()) { + op.markNotDirty(); + ((VariableSupport) op).updateVariables(context); + } + } + super.apply(context); + } + /** * Utility function to update variables referencing this component dimensions * @@ -233,14 +273,6 @@ public class Component extends PaintOperation implements Measurable, Serializabl if (!mComponentValues.isEmpty()) { updateComponentValues(context); } - for (Operation o : mList) { - if (o instanceof Component) { - ((Component) o).updateVariables(context); - } - if (o instanceof VariableSupport) { - o.apply(context); - } - } context.mLastComponent = prev; } @@ -248,14 +280,40 @@ public class Component extends PaintOperation implements Measurable, Serializabl mComponentValues.add(v); } - public float intrinsicWidth() { + /** + * Returns the intrinsic width of the layout + * + * @param context + * @return the width in pixels + */ + public float intrinsicWidth(@Nullable RemoteContext context) { return getWidth(); } - public float intrinsicHeight() { + /** + * Returns the intrinsic height of the layout + * + * @param context + * @return the height in pixels + */ + public float intrinsicHeight(@Nullable RemoteContext context) { return getHeight(); } + /** + * This function is called after a component is created, with its mList initialized. This let + * the component a chance to do some post-initialization work on its children ops. + */ + public void inflate() { + for (Operation op : mList) { + if (op instanceof TouchExpression) { + // Make sure to set the component of a touch expression that belongs to us! + TouchExpression touchExpression = (TouchExpression) op; + touchExpression.setComponent(this); + } + } + } + public enum Visibility { GONE, VISIBLE, @@ -352,12 +410,40 @@ public class Component extends PaintOperation implements Measurable, Serializabl } else { mVisibility = m.getVisibility(); } - setWidth(m.getW()); - setHeight(m.getH()); - setLayoutPosition(m.getX(), m.getY()); + if (mAnimateMeasure == null) { + setWidth(m.getW()); + setHeight(m.getH()); + setLayoutPosition(m.getX(), m.getY()); + updateComponentValues(context); + clearNeedsBoundsAnimation(); + } else { + mAnimateMeasure.apply(context); + updateComponentValues(context); + markNeedsBoundsAnimation(); + } mFirstLayout = false; } + /** + * Animate the bounds of the component as needed + * @param context + */ + public void animatingBounds(@NonNull RemoteContext context) { + if (mAnimateMeasure != null) { + mAnimateMeasure.apply(context); + updateComponentValues(context); + markNeedsBoundsAnimation(); + } else { + clearNeedsBoundsAnimation(); + } + for (Operation op : mList) { + if (op instanceof Measurable) { + Measurable m = (Measurable) op; + m.animatingBounds(context); + } + } + } + @NonNull public float[] locationInWindow = new float[2]; public boolean contains(float x, float y) { @@ -409,11 +495,23 @@ public class Component extends PaintOperation implements Measurable, Serializabl if (op instanceof TouchHandler) { ((TouchHandler) op).onTouchDown(context, document, this, cx, cy); } + if (op instanceof TouchExpression) { + TouchExpression touchExpression = (TouchExpression) op; + touchExpression.updateVariables(context); + touchExpression.touchDown(context, cx, cy); + document.appliedTouchOperation(this); + } } } public void onTouchUp( - RemoteContext context, CoreDocument document, float x, float y, boolean force) { + RemoteContext context, + CoreDocument document, + float x, + float y, + float dx, + float dy, + boolean force) { if (!force && !contains(x, y)) { return; } @@ -421,10 +519,15 @@ public class Component extends PaintOperation implements Measurable, Serializabl float cy = y - getScrollY(); for (Operation op : mList) { if (op instanceof Component) { - ((Component) op).onTouchUp(context, document, cx, cy, force); + ((Component) op).onTouchUp(context, document, cx, cy, dx, dy, force); } if (op instanceof TouchHandler) { - ((TouchHandler) op).onTouchUp(context, document, this, cx, cy); + ((TouchHandler) op).onTouchUp(context, document, this, cx, cy, dx, dy); + } + if (op instanceof TouchExpression) { + TouchExpression touchExpression = (TouchExpression) op; + touchExpression.updateVariables(context); + touchExpression.touchUp(context, cx, cy, dx, dy); } } } @@ -443,6 +546,11 @@ public class Component extends PaintOperation implements Measurable, Serializabl if (op instanceof TouchHandler) { ((TouchHandler) op).onTouchCancel(context, document, this, cx, cy); } + if (op instanceof TouchExpression) { + TouchExpression touchExpression = (TouchExpression) op; + touchExpression.updateVariables(context); + touchExpression.touchUp(context, cx, cy, 0, 0); + } } } @@ -460,6 +568,11 @@ public class Component extends PaintOperation implements Measurable, Serializabl if (op instanceof TouchHandler) { ((TouchHandler) op).onTouchDrag(context, document, this, cx, cy); } + if (op instanceof TouchExpression) { + TouchExpression touchExpression = (TouchExpression) op; + touchExpression.updateVariables(context); + touchExpression.touchDrag(context, x, y); + } } } @@ -652,7 +765,17 @@ public class Component extends PaintOperation implements Measurable, Serializabl debugBox(this, context); } for (Operation op : mList) { - op.apply(context.getContext()); + if (op.isDirty() && op instanceof VariableSupport) { + ((VariableSupport) op).updateVariables(context.getContext()); + op.markNotDirty(); + } + if (op instanceof PaintOperation) { + ((PaintOperation) op).paint(context); + context.getContext().incrementOpCount(); + } else { + op.apply(context.getContext()); + context.getContext().incrementOpCount(); + } } context.restore(); context.getContext().mLastComponent = prev; @@ -660,8 +783,8 @@ public class Component extends PaintOperation implements Measurable, Serializabl public boolean applyAnimationAsNeeded(@NonNull PaintContext context) { if (context.isAnimationEnabled() && mAnimateMeasure != null) { - mAnimateMeasure.apply(context); - needsRepaint(); + mAnimateMeasure.paint(context); + context.needsRepaint(); return true; } return false; diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/layout/ComponentEnd.java b/core/java/com/android/internal/widget/remotecompose/core/operations/layout/ComponentEnd.java index 396644c45fa4ca938f4abe792c400016c6fe2d7a..5da06634d101f0780a1f07e4b921efcbcc0a29ac 100644 --- a/core/java/com/android/internal/widget/remotecompose/core/operations/layout/ComponentEnd.java +++ b/core/java/com/android/internal/widget/remotecompose/core/operations/layout/ComponentEnd.java @@ -49,6 +49,11 @@ public class ComponentEnd extends Operation { return (indent != null ? indent : "") + toString(); } + /** + * The name of the class + * + * @return the name + */ @NonNull public static String name() { return "ComponentEnd"; @@ -81,6 +86,11 @@ public class ComponentEnd extends Operation { operations.add(new ComponentEnd()); } + /** + * Populate the documentation with a description of this operation + * + * @param doc to append the description to. + */ public static void documentation(@NonNull DocumentationBuilder doc) { doc.operation("Layout Operations", id(), name()) .description( diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/layout/ComponentStart.java b/core/java/com/android/internal/widget/remotecompose/core/operations/layout/ComponentStart.java index a85ae270ffb126dbbfc2bfc7f637127d76a355db..4349b31d76e3709addfc363f4963d6ec62dde41d 100644 --- a/core/java/com/android/internal/widget/remotecompose/core/operations/layout/ComponentStart.java +++ b/core/java/com/android/internal/widget/remotecompose/core/operations/layout/ComponentStart.java @@ -157,6 +157,11 @@ public class ComponentStart extends Operation implements ComponentStartOperation } } + /** + * The name of the class + * + * @return the name + */ @NonNull public static String name() { return "ComponentStart"; @@ -198,6 +203,11 @@ public class ComponentStart extends Operation implements ComponentStartOperation operations.add(new ComponentStart(type, componentId, width, height)); } + /** + * Populate the documentation with a description of this operation + * + * @param doc to append the description to. + */ public static void documentation(@NonNull DocumentationBuilder doc) { doc.operation("Layout Operations", id(), name()) .description( diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/layout/DecoratorComponent.java b/core/java/com/android/internal/widget/remotecompose/core/operations/layout/DecoratorComponent.java index d6170074238a4ebc5e8d2a543d1c3a50b25a25e0..9ca2f2ed3ba790f0867419bec8e371032af8183f 100644 --- a/core/java/com/android/internal/widget/remotecompose/core/operations/layout/DecoratorComponent.java +++ b/core/java/com/android/internal/widget/remotecompose/core/operations/layout/DecoratorComponent.java @@ -24,5 +24,13 @@ import com.android.internal.widget.remotecompose.core.RemoteContext; * measured. Eg borders, background, clips, etc. */ public interface DecoratorComponent { - void layout(@NonNull RemoteContext context, float width, float height); + /** + * Layout the decorator + * + * @param context + * @param component the associated component + * @param width horizontal dimension in pixels + * @param height vertical dimension in pixels + */ + void layout(@NonNull RemoteContext context, Component component, float width, float height); } diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/layout/LayoutComponent.java b/core/java/com/android/internal/widget/remotecompose/core/operations/layout/LayoutComponent.java index 7b0e4a2e262705927ac854b4f3e3120fa6e6f6c9..91038852573eba2fb84d3e04508e35d44804222f 100644 --- a/core/java/com/android/internal/widget/remotecompose/core/operations/layout/LayoutComponent.java +++ b/core/java/com/android/internal/widget/remotecompose/core/operations/layout/LayoutComponent.java @@ -21,6 +21,8 @@ import android.annotation.Nullable; import com.android.internal.widget.remotecompose.core.Operation; import com.android.internal.widget.remotecompose.core.OperationInterface; import com.android.internal.widget.remotecompose.core.PaintContext; +import com.android.internal.widget.remotecompose.core.RemoteContext; +import com.android.internal.widget.remotecompose.core.VariableSupport; import com.android.internal.widget.remotecompose.core.operations.BitmapData; import com.android.internal.widget.remotecompose.core.operations.FloatExpression; import com.android.internal.widget.remotecompose.core.operations.MatrixRestore; @@ -36,6 +38,7 @@ import com.android.internal.widget.remotecompose.core.operations.layout.modifier import com.android.internal.widget.remotecompose.core.operations.layout.modifiers.HeightModifierOperation; import com.android.internal.widget.remotecompose.core.operations.layout.modifiers.ModifierOperation; import com.android.internal.widget.remotecompose.core.operations.layout.modifiers.PaddingModifierOperation; +import com.android.internal.widget.remotecompose.core.operations.layout.modifiers.ScrollModifierOperation; import com.android.internal.widget.remotecompose.core.operations.layout.modifiers.WidthModifierOperation; import com.android.internal.widget.remotecompose.core.operations.layout.modifiers.ZIndexModifierOperation; @@ -54,6 +57,12 @@ public class LayoutComponent extends Component { protected float mPaddingTop = 0f; protected float mPaddingBottom = 0f; + float mScrollX = 0f; + float mScrollY = 0f; + + @Nullable protected ScrollDelegate mHorizontalScrollDelegate = null; + @Nullable protected ScrollDelegate mVerticalScrollDelegate = null; + @NonNull protected ComponentModifiers mComponentModifiers = new ComponentModifiers(); @NonNull @@ -111,6 +120,7 @@ public class LayoutComponent extends Component { // Should be removed after ImageLayout is in private static final boolean USE_IMAGE_TEMP_FIX = true; + @Override public void inflate() { ArrayList data = new ArrayList<>(); ArrayList supportedOperations = new ArrayList<>(); @@ -144,6 +154,7 @@ public class LayoutComponent extends Component { if (!canvasContent.mList.isEmpty()) { mContent.mList.clear(); mChildrenComponents.add(canvasContent); + canvasContent.inflate(); } } else { content.getData(data); @@ -155,6 +166,9 @@ public class LayoutComponent extends Component { if (op instanceof ComponentVisibilityOperation) { ((ComponentVisibilityOperation) op).setParent(this); } + if (op instanceof ScrollModifierOperation) { + ((ScrollModifierOperation) op).inflate(this); + } mComponentModifiers.add((ModifierOperation) op); } else if (op instanceof TextData) { data.add((TextData) op); @@ -162,6 +176,9 @@ public class LayoutComponent extends Component { || (op instanceof PaintData) || (op instanceof FloatExpression)) { supportedOperations.add(op); + if (op instanceof TouchExpression) { + ((TouchExpression) op).setComponent(this); + } } else { // nothing } @@ -186,8 +203,6 @@ public class LayoutComponent extends Component { mPaddingRight = 0f; mPaddingBottom = 0f; - boolean applyHorizontalMargin = true; - boolean applyVerticalMargin = true; for (OperationInterface op : mComponentModifiers.getList()) { if (op instanceof PaddingModifierOperation) { // We are accumulating padding modifiers to compute the margin @@ -209,6 +224,14 @@ public class LayoutComponent extends Component { mZIndexModifier = (ZIndexModifierOperation) op; } else if (op instanceof GraphicsLayerModifierOperation) { mGraphicsLayerModifier = (GraphicsLayerModifierOperation) op; + } else if (op instanceof ScrollDelegate) { + ScrollDelegate scrollDelegate = (ScrollDelegate) op; + if (scrollDelegate.handlesHorizontalScroll()) { + mHorizontalScrollDelegate = scrollDelegate; + } + if (scrollDelegate.handlesVerticalScroll()) { + mVerticalScrollDelegate = scrollDelegate; + } } } if (mWidthModifier == null) { @@ -217,8 +240,8 @@ public class LayoutComponent extends Component { if (mHeightModifier == null) { mHeightModifier = new HeightModifierOperation(DimensionModifierOperation.Type.WRAP); } - setWidth(computeModifierDefinedWidth()); - setHeight(computeModifierDefinedHeight()); + setWidth(computeModifierDefinedWidth(null)); + setHeight(computeModifierDefinedHeight(null)); } @NonNull @@ -227,20 +250,45 @@ public class LayoutComponent extends Component { return "UNKNOWN LAYOUT_COMPONENT"; } + @Override + public void getLocationInWindow(@NonNull float[] value) { + value[0] += mX + mPaddingLeft; + value[1] += mY + mPaddingTop; + if (mParent != null) { + mParent.getLocationInWindow(value); + } + } + @Override public float getScrollX() { - return mComponentModifiers.getScrollX(); + if (mHorizontalScrollDelegate != null) { + return mHorizontalScrollDelegate.getScrollX(mScrollX); + } + return mScrollX; + } + + public void setScrollX(float value) { + mScrollX = value; } @Override public float getScrollY() { - return mComponentModifiers.getScrollY(); + if (mVerticalScrollDelegate != null) { + return mVerticalScrollDelegate.getScrollY(mScrollY); + } + return mScrollY; + } + + public void setScrollY(float value) { + mScrollY = value; } @Override public void paintingComponent(@NonNull PaintContext context) { Component prev = context.getContext().mLastComponent; - context.getContext().mLastComponent = this; + RemoteContext remoteContext = context.getContext(); + + remoteContext.mLastComponent = this; context.save(); context.translate(mX, mY); if (context.isVisualDebug()) { @@ -279,10 +327,20 @@ public class LayoutComponent extends Component { ArrayList sorted = new ArrayList(mChildrenComponents); sorted.sort((a, b) -> (int) (a.getZIndex() - b.getZIndex())); for (Component child : sorted) { + if (child.isDirty() && child instanceof VariableSupport) { + child.updateVariables(context.getContext()); + child.markNotDirty(); + } + remoteContext.incrementOpCount(); child.paint(context); } } else { for (Component child : mChildrenComponents) { + if (child.isDirty() && child instanceof VariableSupport) { + child.updateVariables(context.getContext()); + child.markNotDirty(); + } + remoteContext.incrementOpCount(); child.paint(context); } } @@ -295,11 +353,15 @@ public class LayoutComponent extends Component { } /** Traverse the modifiers to compute indicated dimension */ - public float computeModifierDefinedWidth() { + public float computeModifierDefinedWidth(@Nullable RemoteContext context) { float s = 0f; float e = 0f; float w = 0f; for (OperationInterface c : mComponentModifiers.getList()) { + if (context != null && c.isDirty() && c instanceof VariableSupport) { + ((VariableSupport) c).updateVariables(context); + c.markNotDirty(); + } if (c instanceof WidthModifierOperation) { WidthModifierOperation o = (WidthModifierOperation) c; if (o.getType() == DimensionModifierOperation.Type.EXACT @@ -339,11 +401,15 @@ public class LayoutComponent extends Component { } /** Traverse the modifiers to compute indicated dimension */ - public float computeModifierDefinedHeight() { + public float computeModifierDefinedHeight(@Nullable RemoteContext context) { float t = 0f; float b = 0f; float h = 0f; for (OperationInterface c : mComponentModifiers.getList()) { + if (context != null && c.isDirty() && c instanceof VariableSupport) { + ((VariableSupport) c).updateVariables(context); + c.markNotDirty(); + } if (c instanceof HeightModifierOperation) { HeightModifierOperation o = (HeightModifierOperation) c; if (o.getType() == DimensionModifierOperation.Type.EXACT @@ -382,6 +448,11 @@ public class LayoutComponent extends Component { return t + b; } + @NonNull + public ComponentModifiers getComponentModifiers() { + return mComponentModifiers; + } + @NonNull public ArrayList getChildrenComponents() { return mChildrenComponents; diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/layout/LayoutComponentContent.java b/core/java/com/android/internal/widget/remotecompose/core/operations/layout/LayoutComponentContent.java index 20e4688aaa323132a97b5edc8cda4ef084763dc9..9bfbe6a42a3713a0c3331bb23cc668d4b30828e7 100644 --- a/core/java/com/android/internal/widget/remotecompose/core/operations/layout/LayoutComponentContent.java +++ b/core/java/com/android/internal/widget/remotecompose/core/operations/layout/LayoutComponentContent.java @@ -41,6 +41,11 @@ public class LayoutComponentContent extends Component implements ComponentStartO super(parent, componentId, animationId, x, y, width, height); } + /** + * The name of the class + * + * @return the name + */ @NonNull public static String name() { return "LayoutContent"; @@ -77,6 +82,11 @@ public class LayoutComponentContent extends Component implements ComponentStartO operations.add(new LayoutComponentContent(componentId, 0, 0, 0, 0, null, -1)); } + /** + * Populate the documentation with a description of this operation + * + * @param doc to append the description to. + */ public static void documentation(@NonNull DocumentationBuilder doc) { doc.operation("Layout Operations", id(), name()) .field(INT, "COMPONENT_ID", "unique id for this component") diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/layout/ListActionsOperation.java b/core/java/com/android/internal/widget/remotecompose/core/operations/layout/ListActionsOperation.java index df960e45736ece2d24fb8157b0179eacfc30354d..9fc5da8320ba2b7544a5e1cfceb47738c1b1ad02 100644 --- a/core/java/com/android/internal/widget/remotecompose/core/operations/layout/ListActionsOperation.java +++ b/core/java/com/android/internal/widget/remotecompose/core/operations/layout/ListActionsOperation.java @@ -32,8 +32,8 @@ public abstract class ListActionsOperation extends PaintOperation implements ModifierOperation, DecoratorComponent { String mOperationName; - float mWidth = 0; - float mHeight = 0; + protected float mWidth = 0; + protected float mHeight = 0; private final float[] mLocationInWindow = new float[2]; @@ -57,6 +57,7 @@ public abstract class ListActionsOperation extends PaintOperation for (Operation op : mList) { if (op instanceof TextData) { op.apply(context); + context.incrementOpCount(); } } } @@ -71,7 +72,7 @@ public abstract class ListActionsOperation extends PaintOperation public void paint(PaintContext context) {} @Override - public void layout(RemoteContext context, float width, float height) { + public void layout(RemoteContext context, Component component, float width, float height) { mWidth = width; mHeight = height; } diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/layout/LoopEnd.java b/core/java/com/android/internal/widget/remotecompose/core/operations/layout/LoopEnd.java index d88f711c62c6e4c07141ccdc13c46b6c26a4169d..3d389e5badef63ab0c1e229e48f49a1fda6df692 100644 --- a/core/java/com/android/internal/widget/remotecompose/core/operations/layout/LoopEnd.java +++ b/core/java/com/android/internal/widget/remotecompose/core/operations/layout/LoopEnd.java @@ -49,6 +49,11 @@ public class LoopEnd extends Operation { return (indent != null ? indent : "") + toString(); } + /** + * The name of the class + * + * @return the name + */ @NonNull public static String name() { return "LoopEnd"; @@ -77,6 +82,11 @@ public class LoopEnd extends Operation { operations.add(new LoopEnd()); } + /** + * Populate the documentation with a description of this operation + * + * @param doc to append the description to. + */ public static void documentation(@NonNull DocumentationBuilder doc) { doc.operation("Operations", id(), name()).description("End tag for loops"); } diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/layout/LoopOperation.java b/core/java/com/android/internal/widget/remotecompose/core/operations/layout/LoopOperation.java index 83a2f0e1ffa367aadedbbd2593412db4f86cef66..ab1e0ac73368ce7dd438341e480d51629871b4ac 100644 --- a/core/java/com/android/internal/widget/remotecompose/core/operations/layout/LoopOperation.java +++ b/core/java/com/android/internal/widget/remotecompose/core/operations/layout/LoopOperation.java @@ -107,9 +107,11 @@ public class LoopOperation extends PaintOperation implements VariableSupport { @Override public void paint(@NonNull PaintContext context) { + RemoteContext remoteContext = context.getContext(); if (mIndexVariableId == 0) { for (float i = mFromOut; i < mUntilOut; i += mStepOut) { for (Operation op : mList) { + remoteContext.incrementOpCount(); op.apply(context.getContext()); } } @@ -117,15 +119,21 @@ public class LoopOperation extends PaintOperation implements VariableSupport { for (float i = mFromOut; i < mUntilOut; i += mStepOut) { context.getContext().loadFloat(mIndexVariableId, i); for (Operation op : mList) { - if (op instanceof VariableSupport) { + if (op instanceof VariableSupport && op.isDirty()) { ((VariableSupport) op).updateVariables(context.getContext()); } + remoteContext.incrementOpCount(); op.apply(context.getContext()); } } } } + /** + * The name of the class + * + * @return the name + */ @NonNull public static String name() { return "Loop"; @@ -154,6 +162,11 @@ public class LoopOperation extends PaintOperation implements VariableSupport { operations.add(new LoopOperation(indexId, from, step, until)); } + /** + * Populate the documentation with a description of this operation + * + * @param doc to append the description to. + */ public static void documentation(@NonNull DocumentationBuilder doc) { doc.operation("Operations", OP_CODE, name()) .description("Loop. This operation execute" + " a list of action in a loop") @@ -162,4 +175,16 @@ public class LoopOperation extends PaintOperation implements VariableSupport { .field(DocumentedOperation.FLOAT, "step", "value step") .field(DocumentedOperation.FLOAT, "until", "stops less than or equal"); } + + /** + * Calculate and estimate of the number of iterations + * + * @return number of loops or 10 if based on variables + */ + public int estimateIterations() { + if (!(Float.isNaN(mUntil) || Float.isNaN(mFrom) || Float.isNaN(mStep))) { + return (int) (0.5f + (mUntil - mFrom) / mStep); + } + return 10; // this is a generic estmate if the values are variables; + } } diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/layout/OperationsListEnd.java b/core/java/com/android/internal/widget/remotecompose/core/operations/layout/OperationsListEnd.java index 99b7e68786fb8c5d1825a440dba51ba9a7e4ab4d..12a673d7380fd00dc930b1adbdd11428ec817788 100644 --- a/core/java/com/android/internal/widget/remotecompose/core/operations/layout/OperationsListEnd.java +++ b/core/java/com/android/internal/widget/remotecompose/core/operations/layout/OperationsListEnd.java @@ -49,6 +49,11 @@ public class OperationsListEnd extends Operation { return (indent != null ? indent : "") + toString(); } + /** + * The name of the class + * + * @return the name + */ @NonNull public static String name() { return "ListEnd"; @@ -77,6 +82,11 @@ public class OperationsListEnd extends Operation { operations.add(new OperationsListEnd()); } + /** + * Populate the documentation with a description of this operation + * + * @param doc to append the description to. + */ public static void documentation(@NonNull DocumentationBuilder doc) { doc.operation("Layout Operations", id(), name()) .description("End tag for list of operations."); diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/layout/RootLayoutComponent.java b/core/java/com/android/internal/widget/remotecompose/core/operations/layout/RootLayoutComponent.java index fd1628729dd41a6fe7f1679828a4e263c119d95b..11fa7ee670ddbc95fa6d6324604fbdfec55b1a68 100644 --- a/core/java/com/android/internal/widget/remotecompose/core/operations/layout/RootLayoutComponent.java +++ b/core/java/com/android/internal/widget/remotecompose/core/operations/layout/RootLayoutComponent.java @@ -137,8 +137,8 @@ public class RootLayoutComponent extends Component implements ComponentStartOper return; } context.mLastComponent = this; - mWidth = context.mWidth; - mHeight = context.mHeight; + setWidth(context.mWidth); + setHeight(context.mHeight); // TODO: reuse MeasurePass MeasurePass measurePass = new MeasurePass(); @@ -155,7 +155,9 @@ public class RootLayoutComponent extends Component implements ComponentStartOper @Override public void paint(@NonNull PaintContext context) { mNeedsRepaint = false; - context.getContext().mLastComponent = this; + RemoteContext remoteContext = context.getContext(); + remoteContext.mLastComponent = this; + context.save(); if (mParent == null) { // root layout @@ -165,6 +167,7 @@ public class RootLayoutComponent extends Component implements ComponentStartOper for (Operation op : mList) { if (op instanceof PaintOperation) { ((PaintOperation) op).paint(context); + remoteContext.incrementOpCount(); } } @@ -192,6 +195,11 @@ public class RootLayoutComponent extends Component implements ComponentStartOper } } + /** + * The name of the class + * + * @return the name + */ @NonNull public static String name() { return "RootLayout"; @@ -222,6 +230,11 @@ public class RootLayoutComponent extends Component implements ComponentStartOper operations.add(new RootLayoutComponent(componentId, 0, 0, 0, 0, null, -1)); } + /** + * Populate the documentation with a description of this operation + * + * @param doc to append the description to. + */ public static void documentation(@NonNull DocumentationBuilder doc) { doc.operation("Layout Operations", id(), name()) .field(INT, "COMPONENT_ID", "unique id for this component") diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/layout/ScrollDelegate.java b/core/java/com/android/internal/widget/remotecompose/core/operations/layout/ScrollDelegate.java new file mode 100644 index 0000000000000000000000000000000000000000..7ef9766ba0777ca100d556b63ab8aae67829af3d --- /dev/null +++ b/core/java/com/android/internal/widget/remotecompose/core/operations/layout/ScrollDelegate.java @@ -0,0 +1,58 @@ +/* + * Copyright (C) 2024 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES 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.widget.remotecompose.core.operations.layout; + +/** + * Represent scroll delegates components. + * + *

    Components have scroll X & Y properties. We can inject a scroll delegate as a modifier (e.g. a + * scrollView, a marquee...) to control the value of those properties. + */ +public interface ScrollDelegate { + + /** + * Returns the horizontal scroll value + * + * @param currentValue the current value + * @return the value set by the delegate + */ + float getScrollX(float currentValue); + + /** + * Returns the vertical scroll value + * + * @param currentValue the current value + * @return the value set by the delegate + */ + float getScrollY(float currentValue); + + /** + * Returns true if the delegate can handle horizontal scroll + * + * @return true if the delegate handles horizontal scrolling + */ + boolean handlesHorizontalScroll(); + + /** + * Returns true if the delegate can handle vertical scroll + * + * @return true if the delegate handles vertical scrolling + */ + boolean handlesVerticalScroll(); + + /** Reset the delegate (e.g. the content of the component has changed) */ + void reset(); +} diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/layout/TouchCancelModifierOperation.java b/core/java/com/android/internal/widget/remotecompose/core/operations/layout/TouchCancelModifierOperation.java index 3185bb5f0f72e12f71355c95e467ee722e4a2927..4977a15e2dc1f3f9aec94255c1abad50c6b96e16 100644 --- a/core/java/com/android/internal/widget/remotecompose/core/operations/layout/TouchCancelModifierOperation.java +++ b/core/java/com/android/internal/widget/remotecompose/core/operations/layout/TouchCancelModifierOperation.java @@ -15,6 +15,8 @@ */ package com.android.internal.widget.remotecompose.core.operations.layout; +import android.annotation.NonNull; + import com.android.internal.widget.remotecompose.core.CoreDocument; import com.android.internal.widget.remotecompose.core.Operation; import com.android.internal.widget.remotecompose.core.Operations; @@ -60,7 +62,13 @@ public class TouchCancelModifierOperation extends ListActionsOperation implement @Override public void onTouchUp( - RemoteContext context, CoreDocument document, Component component, float x, float y) { + RemoteContext context, + CoreDocument document, + Component component, + float x, + float y, + float dx, + float dy) { // nothing } @@ -76,6 +84,12 @@ public class TouchCancelModifierOperation extends ListActionsOperation implement // nothing } + /** + * The name of the class + * + * @return the name + */ + @NonNull public static String name() { return "TouchCancelModifier"; } diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/layout/TouchDownModifierOperation.java b/core/java/com/android/internal/widget/remotecompose/core/operations/layout/TouchDownModifierOperation.java index d98911f82060c268dae3264be295e1189c54d3b9..8c51f2eac3831cd0ad22185adc4a2dc504de41e2 100644 --- a/core/java/com/android/internal/widget/remotecompose/core/operations/layout/TouchDownModifierOperation.java +++ b/core/java/com/android/internal/widget/remotecompose/core/operations/layout/TouchDownModifierOperation.java @@ -15,6 +15,8 @@ */ package com.android.internal.widget.remotecompose.core.operations.layout; +import android.annotation.NonNull; + import com.android.internal.widget.remotecompose.core.CoreDocument; import com.android.internal.widget.remotecompose.core.Operation; import com.android.internal.widget.remotecompose.core.Operations; @@ -62,7 +64,13 @@ public class TouchDownModifierOperation extends ListActionsOperation implements @Override public void onTouchUp( - RemoteContext context, CoreDocument document, Component component, float x, float y) { + RemoteContext context, + CoreDocument document, + Component component, + float x, + float y, + float dx, + float dy) { // nothing } @@ -78,6 +86,12 @@ public class TouchDownModifierOperation extends ListActionsOperation implements // nothing } + /** + * The name of the class + * + * @return the name + */ + @NonNull public static String name() { return "TouchModifier"; } diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/layout/TouchHandler.java b/core/java/com/android/internal/widget/remotecompose/core/operations/layout/TouchHandler.java index ac9dd908d6a400351b402b7ec29cd62c7247acbd..607060e5149600e4e64d43ebb5849099aa472250 100644 --- a/core/java/com/android/internal/widget/remotecompose/core/operations/layout/TouchHandler.java +++ b/core/java/com/android/internal/widget/remotecompose/core/operations/layout/TouchHandler.java @@ -41,9 +41,17 @@ public interface TouchHandler { * @param component the component on which the touch has been received * @param x the x position of the click in document coordinates * @param y the y position of the click in document coordinates + * @param dx + * @param dy */ void onTouchUp( - RemoteContext context, CoreDocument document, Component component, float x, float y); + RemoteContext context, + CoreDocument document, + Component component, + float x, + float y, + float dx, + float dy); /** * callback for a touch move event diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/layout/TouchUpModifierOperation.java b/core/java/com/android/internal/widget/remotecompose/core/operations/layout/TouchUpModifierOperation.java index f6cb3750906fbccd35d3b87873af42a5d7388861..a12c356f7c48af1fcdc2d64d736d6a7d4b9ae76a 100644 --- a/core/java/com/android/internal/widget/remotecompose/core/operations/layout/TouchUpModifierOperation.java +++ b/core/java/com/android/internal/widget/remotecompose/core/operations/layout/TouchUpModifierOperation.java @@ -15,6 +15,8 @@ */ package com.android.internal.widget.remotecompose.core.operations.layout; +import android.annotation.NonNull; + import com.android.internal.widget.remotecompose.core.CoreDocument; import com.android.internal.widget.remotecompose.core.Operation; import com.android.internal.widget.remotecompose.core.Operations; @@ -60,7 +62,13 @@ public class TouchUpModifierOperation extends ListActionsOperation implements To @Override public void onTouchUp( - RemoteContext context, CoreDocument document, Component component, float x, float y) { + RemoteContext context, + CoreDocument document, + Component component, + float x, + float y, + float dx, + float dy) { applyActions(context, document, component, x, y, true); } @@ -76,6 +84,12 @@ public class TouchUpModifierOperation extends ListActionsOperation implements To // nothing } + /** + * The name of the class + * + * @return the name + */ + @NonNull public static String name() { return "TouchUpModifier"; } diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/layout/animation/AnimateMeasure.java b/core/java/com/android/internal/widget/remotecompose/core/operations/layout/animation/AnimateMeasure.java index b3430998a5203dc09c985054917a5e64087b9787..1de956b7e5d7348e8afefda15661dd3fe69fb7ca 100644 --- a/core/java/com/android/internal/widget/remotecompose/core/operations/layout/animation/AnimateMeasure.java +++ b/core/java/com/android/internal/widget/remotecompose/core/operations/layout/animation/AnimateMeasure.java @@ -19,6 +19,7 @@ import android.annotation.NonNull; import com.android.internal.widget.remotecompose.core.Operation; import com.android.internal.widget.remotecompose.core.PaintContext; +import com.android.internal.widget.remotecompose.core.RemoteContext; import com.android.internal.widget.remotecompose.core.operations.layout.Component; import com.android.internal.widget.remotecompose.core.operations.layout.DecoratorComponent; import com.android.internal.widget.remotecompose.core.operations.layout.measure.ComponentMeasure; @@ -103,13 +104,18 @@ public class AnimateMeasure { @NonNull public PaintBundle paint = new PaintBundle(); - public void apply(@NonNull PaintContext context) { - update(context.getContext().currentTime); - + /** + * Apply the layout portion of the animation if any + * + * @param context + */ + public void apply(@NonNull RemoteContext context) { + update(context.currentTime); mComponent.setX(getX()); mComponent.setY(getY()); mComponent.setWidth(getWidth()); mComponent.setHeight(getHeight()); + mComponent.updateVariables(context); float w = mComponent.getWidth(); float h = mComponent.getHeight(); @@ -120,10 +126,17 @@ public class AnimateMeasure { h -= pop.getTop() + pop.getBottom(); } if (op instanceof DecoratorComponent) { - ((DecoratorComponent) op).layout(context.getContext(), w, h); + ((DecoratorComponent) op).layout(context, mComponent, w, h); } } + } + /** + * Paint the transition animation for the component owned + * + * @param context + */ + public void paint(@NonNull PaintContext context) { if (mOriginal.getVisibility() != mTarget.getVisibility()) { if (mTarget.getVisibility() == Component.Visibility.GONE) { switch (mExitAnimation) { diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/layout/animation/AnimationSpec.java b/core/java/com/android/internal/widget/remotecompose/core/operations/layout/animation/AnimationSpec.java index b230b09112b29f5a6a1c40878b9720f9a9f1d2bc..6dff4a87088b26c469b30f7d31418a5f6923844f 100644 --- a/core/java/com/android/internal/widget/remotecompose/core/operations/layout/animation/AnimationSpec.java +++ b/core/java/com/android/internal/widget/remotecompose/core/operations/layout/animation/AnimationSpec.java @@ -137,6 +137,11 @@ public class AnimationSpec extends Operation { return (indent != null ? indent : "") + toString(); } + /** + * The name of the class + * + * @return the name + */ @NonNull public static String name() { return "AnimationSpec"; @@ -224,6 +229,11 @@ public class AnimationSpec extends Operation { operations.add(op); } + /** + * Populate the documentation with a description of this operation + * + * @param doc to append the description to. + */ public static void documentation(@NonNull DocumentationBuilder doc) { doc.operation("Layout Operations", id(), name()) .description("define the animation") diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/layout/managers/BoxLayout.java b/core/java/com/android/internal/widget/remotecompose/core/operations/layout/managers/BoxLayout.java index 01cd7ccd0b947b7cd9619f91d5cb2ff809e8cb26..8076cb10ea0c01a6fc823a81f3030dae6afb92d1 100644 --- a/core/java/com/android/internal/widget/remotecompose/core/operations/layout/managers/BoxLayout.java +++ b/core/java/com/android/internal/widget/remotecompose/core/operations/layout/managers/BoxLayout.java @@ -119,8 +119,9 @@ public class BoxLayout extends LayoutManager implements ComponentStartOperation size.setHeight(Math.max(size.getHeight(), m.getH())); } // add padding - size.setWidth(Math.max(size.getWidth(), computeModifierDefinedWidth())); - size.setHeight(Math.max(size.getHeight(), computeModifierDefinedHeight())); + size.setWidth(Math.max(size.getWidth(), computeModifierDefinedWidth(context.getContext()))); + size.setHeight( + Math.max(size.getHeight(), computeModifierDefinedHeight(context.getContext()))); } @Override @@ -172,6 +173,11 @@ public class BoxLayout extends LayoutManager implements ComponentStartOperation } } + /** + * The name of the class + * + * @return the name + */ @NonNull public static String name() { return "BoxLayout"; @@ -219,6 +225,11 @@ public class BoxLayout extends LayoutManager implements ComponentStartOperation verticalPositioning)); } + /** + * Populate the documentation with a description of this operation + * + * @param doc to append the description to. + */ public static void documentation(@NonNull DocumentationBuilder doc) { doc.operation("Layout Operations", id(), name()) .description( diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/layout/managers/CanvasLayout.java b/core/java/com/android/internal/widget/remotecompose/core/operations/layout/managers/CanvasLayout.java index 665db263767486fbc758d29ac6249f283b3e268d..0091a47eebfbd738d247928e47ebcc0ef69fda3d 100644 --- a/core/java/com/android/internal/widget/remotecompose/core/operations/layout/managers/CanvasLayout.java +++ b/core/java/com/android/internal/widget/remotecompose/core/operations/layout/managers/CanvasLayout.java @@ -72,6 +72,11 @@ public class CanvasLayout extends BoxLayout { return "CANVAS"; } + /** + * The name of the class + * + * @return the name + */ @NonNull public static String name() { return "CanvasLayout"; @@ -104,6 +109,11 @@ public class CanvasLayout extends BoxLayout { operations.add(new CanvasLayout(null, componentId, animationId)); } + /** + * Populate the documentation with a description of this operation + * + * @param doc to append the description to. + */ public static void documentation(@NonNull DocumentationBuilder doc) { doc.operation("Layout Operations", id(), name()) .description("Canvas implementation. Encapsulate draw operations.\n\n") diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/layout/managers/ColumnLayout.java b/core/java/com/android/internal/widget/remotecompose/core/operations/layout/managers/ColumnLayout.java index 5b9ee0ff511fe2ad70c3487f97a1daad089f6ce8..249e84a1c1bcdb0665275435e9964adf8f7842c2 100644 --- a/core/java/com/android/internal/widget/remotecompose/core/operations/layout/managers/ColumnLayout.java +++ b/core/java/com/android/internal/widget/remotecompose/core/operations/layout/managers/ColumnLayout.java @@ -24,6 +24,7 @@ import android.annotation.Nullable; import com.android.internal.widget.remotecompose.core.Operation; import com.android.internal.widget.remotecompose.core.Operations; import com.android.internal.widget.remotecompose.core.PaintContext; +import com.android.internal.widget.remotecompose.core.RemoteContext; import com.android.internal.widget.remotecompose.core.WireBuffer; import com.android.internal.widget.remotecompose.core.documentation.DocumentationBuilder; import com.android.internal.widget.remotecompose.core.operations.layout.Component; @@ -169,11 +170,11 @@ public class ColumnLayout extends LayoutManager implements ComponentStartOperati } @Override - public float intrinsicHeight() { - float height = computeModifierDefinedHeight(); + public float intrinsicHeight(@NonNull RemoteContext context) { + float height = computeModifierDefinedHeight(context); float componentHeights = 0f; for (Component c : mChildrenComponents) { - componentHeights += c.intrinsicHeight(); + componentHeights += c.intrinsicHeight(context); } return Math.max(height, componentHeights); } @@ -341,6 +342,11 @@ public class ColumnLayout extends LayoutManager implements ComponentStartOperati DebugLog.e(); } + /** + * The name of the class + * + * @return the name + */ @NonNull public static String name() { return "ColumnLayout"; @@ -392,6 +398,11 @@ public class ColumnLayout extends LayoutManager implements ComponentStartOperati spacedBy)); } + /** + * Populate the documentation with a description of this operation + * + * @param doc to append the description to. + */ public static void documentation(@NonNull DocumentationBuilder doc) { doc.operation("Layout Operations", id(), name()) .description( diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/layout/managers/LayoutManager.java b/core/java/com/android/internal/widget/remotecompose/core/operations/layout/managers/LayoutManager.java index 6a15b7f1b17858ea27bc2849142ec37d4a08912f..a5edaa8de3af45d16648aa517f5352a9b58b8b30 100644 --- a/core/java/com/android/internal/widget/remotecompose/core/operations/layout/managers/LayoutManager.java +++ b/core/java/com/android/internal/widget/remotecompose/core/operations/layout/managers/LayoutManager.java @@ -61,19 +61,19 @@ public abstract class LayoutManager extends LayoutComponent implements Measurabl } @Override - public float intrinsicHeight() { - float height = computeModifierDefinedHeight(); + public float intrinsicHeight(@Nullable RemoteContext context) { + float height = computeModifierDefinedHeight(context); for (Component c : mChildrenComponents) { - height = Math.max(c.intrinsicHeight(), height); + height = Math.max(c.intrinsicHeight(context), height); } return height; } @Override - public float intrinsicWidth() { - float width = computeModifierDefinedWidth(); + public float intrinsicWidth(@Nullable RemoteContext context) { + float width = computeModifierDefinedWidth(context); for (Component c : mChildrenComponents) { - width = Math.max(c.intrinsicWidth(), width); + width = Math.max(c.intrinsicWidth(context), width); } return width; } @@ -132,16 +132,17 @@ public abstract class LayoutManager extends LayoutComponent implements Measurabl @NonNull MeasurePass measure) { boolean hasWrap = true; - float measuredWidth = Math.min(maxWidth, computeModifierDefinedWidth()); - float measuredHeight = Math.min(maxHeight, computeModifierDefinedHeight()); + float measuredWidth = Math.min(maxWidth, computeModifierDefinedWidth(context.getContext())); + float measuredHeight = + Math.min(maxHeight, computeModifierDefinedHeight(context.getContext())); float insetMaxWidth = maxWidth - mPaddingLeft - mPaddingRight; float insetMaxHeight = maxHeight - mPaddingTop - mPaddingBottom; if (mWidthModifier.isIntrinsicMin()) { - maxWidth = intrinsicWidth(); + maxWidth = intrinsicWidth(context.getContext()); } if (mHeightModifier.isIntrinsicMin()) { - maxHeight = intrinsicHeight(); + maxHeight = intrinsicHeight(context.getContext()); } boolean hasHorizontalWrap = mWidthModifier.isWrap(); @@ -180,7 +181,8 @@ public abstract class LayoutManager extends LayoutComponent implements Measurabl if (isInHorizontalFill()) { measuredWidth = maxWidth; } else if (mWidthModifier.hasWeight()) { - measuredWidth = Math.max(measuredWidth, computeModifierDefinedWidth()); + measuredWidth = + Math.max(measuredWidth, computeModifierDefinedWidth(context.getContext())); } else { measuredWidth = Math.max(measuredWidth, minWidth); measuredWidth = Math.min(measuredWidth, maxWidth); @@ -188,7 +190,8 @@ public abstract class LayoutManager extends LayoutComponent implements Measurabl if (isInVerticalFill()) { // todo: potential npe -- bbade@ measuredHeight = maxHeight; } else if (mHeightModifier.hasWeight()) { - measuredHeight = Math.max(measuredHeight, computeModifierDefinedHeight()); + measuredHeight = + Math.max(measuredHeight, computeModifierDefinedHeight(context.getContext())); } else { measuredHeight = Math.max(measuredHeight, minHeight); measuredHeight = Math.min(measuredHeight, maxHeight); @@ -224,7 +227,9 @@ public abstract class LayoutManager extends LayoutComponent implements Measurabl computeSize(context, 0f, measuredWidth, 0, h, measure); mComponentModifiers.setVerticalScrollDimension(measuredHeight, h); } else { - computeSize(context, 0f, measuredWidth, 0f, measuredHeight, measure); + float maxChildWidth = measuredWidth - mPaddingLeft - mPaddingRight; + float maxChildHeight = measuredHeight - mPaddingTop - mPaddingBottom; + computeSize(context, 0f, maxChildWidth, 0f, maxChildHeight, measure); } } @@ -258,7 +263,7 @@ public abstract class LayoutManager extends LayoutComponent implements Measurabl super.layout(context, measure); ComponentMeasure self = measure.get(this); - mComponentModifiers.layout(context, self.getW(), self.getH()); + mComponentModifiers.layout(context, this, self.getW(), self.getH()); for (Component c : mChildrenComponents) { c.layout(context, measure); } @@ -275,7 +280,7 @@ public abstract class LayoutManager extends LayoutComponent implements Measurabl super.layout(context, measure); ComponentMeasure self = measure.get(this); - mComponentModifiers.layout(context, self.getW(), self.getH()); + mComponentModifiers.layout(context, this, self.getW(), self.getH()); this.mNeedsMeasure = false; } } diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/layout/managers/RowLayout.java b/core/java/com/android/internal/widget/remotecompose/core/operations/layout/managers/RowLayout.java index 0ec820b859649de9781a56c61dbe7cd1d08df039..37b9a688af8b321070500007ee66a637128a62fc 100644 --- a/core/java/com/android/internal/widget/remotecompose/core/operations/layout/managers/RowLayout.java +++ b/core/java/com/android/internal/widget/remotecompose/core/operations/layout/managers/RowLayout.java @@ -24,6 +24,7 @@ import android.annotation.Nullable; import com.android.internal.widget.remotecompose.core.Operation; import com.android.internal.widget.remotecompose.core.Operations; import com.android.internal.widget.remotecompose.core.PaintContext; +import com.android.internal.widget.remotecompose.core.RemoteContext; import com.android.internal.widget.remotecompose.core.WireBuffer; import com.android.internal.widget.remotecompose.core.documentation.DocumentationBuilder; import com.android.internal.widget.remotecompose.core.operations.layout.Component; @@ -167,11 +168,11 @@ public class RowLayout extends LayoutManager implements ComponentStartOperation } @Override - public float intrinsicWidth() { - float width = computeModifierDefinedWidth(); + public float intrinsicWidth(@Nullable RemoteContext context) { + float width = computeModifierDefinedWidth(context); float componentWidths = 0f; for (Component c : mChildrenComponents) { - componentWidths += c.intrinsicWidth(); + componentWidths += c.intrinsicWidth(context); } return Math.max(width, componentWidths); } @@ -344,6 +345,11 @@ public class RowLayout extends LayoutManager implements ComponentStartOperation DebugLog.e(); } + /** + * The name of the class + * + * @return the name + */ @NonNull public static String name() { return "RowLayout"; @@ -395,6 +401,11 @@ public class RowLayout extends LayoutManager implements ComponentStartOperation spacedBy)); } + /** + * Populate the documentation with a description of this operation + * + * @param doc to append the description to. + */ public static void documentation(@NonNull DocumentationBuilder doc) { doc.operation("Layout Operations", id(), name()) .description( diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/layout/managers/TextLayout.java b/core/java/com/android/internal/widget/remotecompose/core/operations/layout/managers/TextLayout.java index 8e7f538d000489e7a35d943e530ea28828b37603..910205e8a7e2b913123a5844efeddbcfc4967be2 100644 --- a/core/java/com/android/internal/widget/remotecompose/core/operations/layout/managers/TextLayout.java +++ b/core/java/com/android/internal/widget/remotecompose/core/operations/layout/managers/TextLayout.java @@ -34,11 +34,13 @@ import com.android.internal.widget.remotecompose.core.operations.layout.measure. import com.android.internal.widget.remotecompose.core.operations.layout.measure.Size; import com.android.internal.widget.remotecompose.core.operations.paint.PaintBundle; import com.android.internal.widget.remotecompose.core.operations.utilities.StringSerializer; +import com.android.internal.widget.remotecompose.core.semantics.AccessibleComponent; import java.util.List; /** Text component, referencing a text id */ -public class TextLayout extends LayoutManager implements ComponentStartOperation, VariableSupport { +public class TextLayout extends LayoutManager + implements ComponentStartOperation, VariableSupport, AccessibleComponent { private static final boolean DEBUG = false; private int mTextId = -1; @@ -57,6 +59,12 @@ public class TextLayout extends LayoutManager implements ComponentStartOperation @Nullable private String mCachedString = ""; + @Nullable + @Override + public Integer getTextId() { + return mTextId; + } + @Override public void registerListening(@NonNull RemoteContext context) { if (mTextId != -1) { @@ -92,6 +100,13 @@ public class TextLayout extends LayoutManager implements ComponentStartOperation } mTextW = -1; mTextH = -1; + + if (mHorizontalScrollDelegate != null) { + mHorizontalScrollDelegate.reset(); + } + if (mVerticalScrollDelegate != null) { + mVerticalScrollDelegate.reset(); + } invalidateMeasure(); } @@ -175,6 +190,11 @@ public class TextLayout extends LayoutManager implements ComponentStartOperation int length = mCachedString.length(); if (mTextW > mWidth) { context.save(); + context.clipRect( + mPaddingLeft, + mPaddingTop, + mWidth - mPaddingLeft - mPaddingRight, + mHeight - mPaddingTop - mPaddingBottom); context.translate(getScrollX(), getScrollY()); context.drawTextRun(mTextId, 0, length, 0, 0, mTextX, mTextY, false); context.restore(); @@ -285,15 +305,20 @@ public class TextLayout extends LayoutManager implements ComponentStartOperation } @Override - public float intrinsicHeight() { + public float intrinsicHeight(@Nullable RemoteContext context) { return mTextH; } @Override - public float intrinsicWidth() { + public float intrinsicWidth(@Nullable RemoteContext context) { return mTextW; } + /** + * The name of the class + * + * @return the name + */ @NonNull public static String name() { return "TextLayout"; @@ -361,6 +386,11 @@ public class TextLayout extends LayoutManager implements ComponentStartOperation textAlign)); } + /** + * Populate the documentation with a description of this operation + * + * @param doc to append the description to. + */ public static void documentation(@NonNull DocumentationBuilder doc) { doc.operation("Layout Operations", id(), name()) .description("Text layout implementation.\n\n") diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/layout/measure/Measurable.java b/core/java/com/android/internal/widget/remotecompose/core/operations/layout/measure/Measurable.java index fbf2784be84357dfe5b21e2a506898400821c6b9..a9998745a5d677a120ff1bfa53bcc3c1c4d6b6f6 100644 --- a/core/java/com/android/internal/widget/remotecompose/core/operations/layout/measure/Measurable.java +++ b/core/java/com/android/internal/widget/remotecompose/core/operations/layout/measure/Measurable.java @@ -44,4 +44,11 @@ public interface Measurable { * @return true if need to remeasured, false otherwise */ boolean needsMeasure(); + + /** + * Animate bounds of the component + * + * @param context + */ + void animatingBounds(RemoteContext context); } diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/layout/modifiers/BackgroundModifierOperation.java b/core/java/com/android/internal/widget/remotecompose/core/operations/layout/modifiers/BackgroundModifierOperation.java index 5df16c5bc03a11443805a03fb9a27e59c1e7c189..b4240d0e08a7eaacbb14b1acb5cd0f26e09ee808 100644 --- a/core/java/com/android/internal/widget/remotecompose/core/operations/layout/modifiers/BackgroundModifierOperation.java +++ b/core/java/com/android/internal/widget/remotecompose/core/operations/layout/modifiers/BackgroundModifierOperation.java @@ -25,6 +25,7 @@ import com.android.internal.widget.remotecompose.core.PaintContext; import com.android.internal.widget.remotecompose.core.RemoteContext; import com.android.internal.widget.remotecompose.core.WireBuffer; import com.android.internal.widget.remotecompose.core.documentation.DocumentationBuilder; +import com.android.internal.widget.remotecompose.core.operations.layout.Component; import com.android.internal.widget.remotecompose.core.operations.paint.PaintBundle; import com.android.internal.widget.remotecompose.core.operations.utilities.StringSerializer; @@ -98,7 +99,8 @@ public class BackgroundModifierOperation extends DecoratorModifierOperation { } @Override - public void layout(@NonNull RemoteContext context, float width, float height) { + public void layout( + @NonNull RemoteContext context, Component component, float width, float height) { this.mWidth = width; this.mHeight = height; } @@ -109,6 +111,11 @@ public class BackgroundModifierOperation extends DecoratorModifierOperation { return "BackgroundModifierOperation(" + mWidth + " x " + mHeight + ")"; } + /** + * The name of the class + * + * @return the name + */ @NonNull public static String name() { return CLASS_NAME; @@ -182,6 +189,11 @@ public class BackgroundModifierOperation extends DecoratorModifierOperation { context.restorePaint(); } + /** + * Populate the documentation with a description of this operation + * + * @param doc to append the description to. + */ public static void documentation(@NonNull DocumentationBuilder doc) { doc.operation("Modifier Operations", OP_CODE, CLASS_NAME) .description("define the Background Modifier") diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/layout/modifiers/BorderModifierOperation.java b/core/java/com/android/internal/widget/remotecompose/core/operations/layout/modifiers/BorderModifierOperation.java index bfadd2f1ef9ce1062bd6f792538f72a15d0c8d7e..df30d9f615e5281e60b18329bbaf82119c33c009 100644 --- a/core/java/com/android/internal/widget/remotecompose/core/operations/layout/modifiers/BorderModifierOperation.java +++ b/core/java/com/android/internal/widget/remotecompose/core/operations/layout/modifiers/BorderModifierOperation.java @@ -25,6 +25,7 @@ import com.android.internal.widget.remotecompose.core.PaintContext; import com.android.internal.widget.remotecompose.core.RemoteContext; import com.android.internal.widget.remotecompose.core.WireBuffer; import com.android.internal.widget.remotecompose.core.documentation.DocumentationBuilder; +import com.android.internal.widget.remotecompose.core.operations.layout.Component; import com.android.internal.widget.remotecompose.core.operations.paint.PaintBundle; import com.android.internal.widget.remotecompose.core.operations.utilities.StringSerializer; @@ -124,7 +125,8 @@ public class BorderModifierOperation extends DecoratorModifierOperation { } @Override - public void layout(@NonNull RemoteContext context, float width, float height) { + public void layout( + @NonNull RemoteContext context, Component component, float width, float height) { this.mWidth = width; this.mHeight = height; } @@ -155,6 +157,11 @@ public class BorderModifierOperation extends DecoratorModifierOperation { + ")"; } + /** + * The name of the class + * + * @return the name + */ @NonNull public static String name() { return CLASS_NAME; @@ -240,6 +247,11 @@ public class BorderModifierOperation extends DecoratorModifierOperation { context.restorePaint(); } + /** + * Populate the documentation with a description of this operation + * + * @param doc to append the description to. + */ public static void documentation(@NonNull DocumentationBuilder doc) { doc.operation("Modifier Operations", OP_CODE, CLASS_NAME) .description("define the Border Modifier") diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/layout/modifiers/ClipRectModifierOperation.java b/core/java/com/android/internal/widget/remotecompose/core/operations/layout/modifiers/ClipRectModifierOperation.java index d0af872acc532e7c527a0c8999c2309bad5bb522..b27fb92003986b85aa1ced7005173bad418086bd 100644 --- a/core/java/com/android/internal/widget/remotecompose/core/operations/layout/modifiers/ClipRectModifierOperation.java +++ b/core/java/com/android/internal/widget/remotecompose/core/operations/layout/modifiers/ClipRectModifierOperation.java @@ -23,6 +23,7 @@ import com.android.internal.widget.remotecompose.core.PaintContext; import com.android.internal.widget.remotecompose.core.RemoteContext; import com.android.internal.widget.remotecompose.core.WireBuffer; import com.android.internal.widget.remotecompose.core.documentation.DocumentationBuilder; +import com.android.internal.widget.remotecompose.core.operations.layout.Component; import com.android.internal.widget.remotecompose.core.operations.utilities.StringSerializer; import java.util.List; @@ -40,7 +41,8 @@ public class ClipRectModifierOperation extends DecoratorModifierOperation { } @Override - public void layout(@NonNull RemoteContext context, float width, float height) { + public void layout( + @NonNull RemoteContext context, Component component, float width, float height) { this.mWidth = width; this.mHeight = height; } @@ -55,6 +57,11 @@ public class ClipRectModifierOperation extends DecoratorModifierOperation { apply(buffer); } + /** + * The name of the class + * + * @return the name + */ @NonNull public static String name() { return CLASS_NAME; @@ -83,6 +90,11 @@ public class ClipRectModifierOperation extends DecoratorModifierOperation { operations.add(new ClipRectModifierOperation()); } + /** + * Populate the documentation with a description of this operation + * + * @param doc to append the description to. + */ public static void documentation(@NonNull DocumentationBuilder doc) { doc.operation("Canvas Operations", OP_CODE, CLASS_NAME) .description("Draw the specified round-rect"); diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/layout/modifiers/ComponentModifiers.java b/core/java/com/android/internal/widget/remotecompose/core/operations/layout/modifiers/ComponentModifiers.java index d11f26f83ebd370bbb422947888d2d007414737f..a1609ace21386e8286ac4eed5636ea23b61f88bb 100644 --- a/core/java/com/android/internal/widget/remotecompose/core/operations/layout/modifiers/ComponentModifiers.java +++ b/core/java/com/android/internal/widget/remotecompose/core/operations/layout/modifiers/ComponentModifiers.java @@ -21,6 +21,7 @@ import com.android.internal.widget.remotecompose.core.CoreDocument; import com.android.internal.widget.remotecompose.core.PaintContext; import com.android.internal.widget.remotecompose.core.PaintOperation; import com.android.internal.widget.remotecompose.core.RemoteContext; +import com.android.internal.widget.remotecompose.core.VariableSupport; import com.android.internal.widget.remotecompose.core.WireBuffer; import com.android.internal.widget.remotecompose.core.operations.MatrixRestore; import com.android.internal.widget.remotecompose.core.operations.MatrixSave; @@ -48,6 +49,7 @@ public class ComponentModifiers extends PaintOperation super.apply(context); for (ModifierOperation op : mList) { op.apply(context); + context.incrementOpCount(); } } @@ -86,6 +88,10 @@ public class ComponentModifiers extends PaintOperation float tx = 0f; float ty = 0f; for (ModifierOperation op : mList) { + if (op.isDirty() && op instanceof VariableSupport) { + ((VariableSupport) op).updateVariables(context.getContext()); + op.markNotDirty(); + } if (op instanceof PaddingModifierOperation) { PaddingModifierOperation pop = (PaddingModifierOperation) op; context.translate(pop.getLeft(), pop.getTop()); @@ -109,7 +115,8 @@ public class ComponentModifiers extends PaintOperation } @Override - public void layout(@NonNull RemoteContext context, float width, float height) { + public void layout( + @NonNull RemoteContext context, Component component, float width, float height) { float w = width; float h = height; for (ModifierOperation op : mList) { @@ -119,9 +126,9 @@ public class ComponentModifiers extends PaintOperation h -= pop.getTop() + pop.getBottom(); } if (op instanceof ClickModifierOperation) { - ((DecoratorComponent) op).layout(context, width, height); + ((DecoratorComponent) op).layout(context, component, width, height); } else if (op instanceof DecoratorComponent) { - ((DecoratorComponent) op).layout(context, w, h); + ((DecoratorComponent) op).layout(context, component, w, h); } } } @@ -156,10 +163,16 @@ public class ComponentModifiers extends PaintOperation @Override public void onTouchUp( - RemoteContext context, CoreDocument document, Component component, float x, float y) { + RemoteContext context, + CoreDocument document, + Component component, + float x, + float y, + float dx, + float dy) { for (ModifierOperation op : mList) { if (op instanceof TouchHandler) { - ((TouchHandler) op).onTouchUp(context, document, component, x, y); + ((TouchHandler) op).onTouchUp(context, document, component, x, y, dx, dy); } } } @@ -208,32 +221,6 @@ public class ComponentModifiers extends PaintOperation return false; } - public float getScrollX() { - float scroll = 0; - for (ModifierOperation op : mList) { - if (op instanceof ScrollModifierOperation) { - ScrollModifierOperation scrollModifier = (ScrollModifierOperation) op; - if (scrollModifier.isHorizontalScroll()) { - scroll = Math.min(scroll, scrollModifier.getScrollX()); - } - } - } - return scroll; - } - - public float getScrollY() { - float scroll = 0; - for (ModifierOperation op : mList) { - if (op instanceof ScrollModifierOperation) { - ScrollModifierOperation scrollModifier = (ScrollModifierOperation) op; - if (scrollModifier.isVerticalScroll()) { - scroll = Math.min(scroll, scrollModifier.getScrollY()); - } - } - } - return scroll; - } - public void setHorizontalScrollDimension(float hostDimension, float contentDimension) { for (ModifierOperation op : mList) { if (op instanceof ScrollModifierOperation) { diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/layout/modifiers/ComponentVisibilityOperation.java b/core/java/com/android/internal/widget/remotecompose/core/operations/layout/modifiers/ComponentVisibilityOperation.java index 1e6ccfcb5d342bd8df865cdc24f7a102ef0c4377..c377b756ff38c403e977bf729bf5421297c3d943 100644 --- a/core/java/com/android/internal/widget/remotecompose/core/operations/layout/modifiers/ComponentVisibilityOperation.java +++ b/core/java/com/android/internal/widget/remotecompose/core/operations/layout/modifiers/ComponentVisibilityOperation.java @@ -90,6 +90,11 @@ public class ComponentVisibilityOperation extends Operation operations.add(new ComponentVisibilityOperation(valueId)); } + /** + * Populate the documentation with a description of this operation + * + * @param doc to append the description to. + */ public static void documentation(@NonNull DocumentationBuilder doc) { doc.operation("Layout Operations", OP_CODE, "ComponentVisibility") .description( @@ -125,5 +130,6 @@ public class ComponentVisibilityOperation extends Operation } @Override - public void layout(@NonNull RemoteContext context, float width, float height) {} + public void layout( + @NonNull RemoteContext context, Component component, float width, float height) {} } diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/layout/modifiers/GraphicsLayerModifierOperation.java b/core/java/com/android/internal/widget/remotecompose/core/operations/layout/modifiers/GraphicsLayerModifierOperation.java index 4252309b7e4c4f87e012a450479e33192bc46d99..15c2f46093d2259dfe6c7b515ebc7ffd15bc538f 100644 --- a/core/java/com/android/internal/widget/remotecompose/core/operations/layout/modifiers/GraphicsLayerModifierOperation.java +++ b/core/java/com/android/internal/widget/remotecompose/core/operations/layout/modifiers/GraphicsLayerModifierOperation.java @@ -27,6 +27,7 @@ import com.android.internal.widget.remotecompose.core.RemoteContext; import com.android.internal.widget.remotecompose.core.WireBuffer; import com.android.internal.widget.remotecompose.core.documentation.DocumentationBuilder; import com.android.internal.widget.remotecompose.core.operations.layout.AnimatableValue; +import com.android.internal.widget.remotecompose.core.operations.layout.Component; import com.android.internal.widget.remotecompose.core.operations.utilities.StringSerializer; import java.util.List; @@ -202,6 +203,12 @@ public class GraphicsLayerModifierOperation extends DecoratorModifierOperation { return "GraphicsLayerModifierOperation(" + mScaleX + ", " + mScaleY + ")"; } + /** + * The name of the class + * + * @return the name + */ + @NonNull public static String name() { return CLASS_NAME; } @@ -306,5 +313,5 @@ public class GraphicsLayerModifierOperation extends DecoratorModifierOperation { } @Override - public void layout(RemoteContext context, float width, float height) {} + public void layout(RemoteContext context, Component component, float width, float height) {} } diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/layout/modifiers/HeightModifierOperation.java b/core/java/com/android/internal/widget/remotecompose/core/operations/layout/modifiers/HeightModifierOperation.java index 692b5269954abbd0117592720333a4e7539fdbce..ec078a9e73eaaad22a5ce18cf9f41005342f2bee 100644 --- a/core/java/com/android/internal/widget/remotecompose/core/operations/layout/modifiers/HeightModifierOperation.java +++ b/core/java/com/android/internal/widget/remotecompose/core/operations/layout/modifiers/HeightModifierOperation.java @@ -32,6 +32,11 @@ public class HeightModifierOperation extends DimensionModifierOperation { private static final int OP_CODE = Operations.MODIFIER_HEIGHT; public static final String CLASS_NAME = "HeightModifierOperation"; + /** + * The name of the class + * + * @return the name + */ @NonNull public static String name() { return CLASS_NAME; @@ -94,6 +99,11 @@ public class HeightModifierOperation extends DimensionModifierOperation { return "HEIGHT"; } + /** + * Populate the documentation with a description of this operation + * + * @param doc to append the description to. + */ public static void documentation(@NonNull DocumentationBuilder doc) { doc.operation("Modifier Operations", OP_CODE, CLASS_NAME) .description("define the animation") diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/layout/modifiers/HostActionOperation.java b/core/java/com/android/internal/widget/remotecompose/core/operations/layout/modifiers/HostActionOperation.java index 333e281d4abbcd4ba80e4ebce28f97ae4110a700..2e9d6619d011e952b4b14aeabc0cc01c5db3726a 100644 --- a/core/java/com/android/internal/widget/remotecompose/core/operations/layout/modifiers/HostActionOperation.java +++ b/core/java/com/android/internal/widget/remotecompose/core/operations/layout/modifiers/HostActionOperation.java @@ -99,6 +99,11 @@ public class HostActionOperation extends Operation implements ActionOperation { operations.add(new HostActionOperation(actionId)); } + /** + * Populate the documentation with a description of this operation + * + * @param doc to append the description to. + */ public static void documentation(@NonNull DocumentationBuilder doc) { doc.operation("Layout Operations", OP_CODE, "HostAction") .description("Host action. This operation represents a host action") diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/layout/modifiers/HostNamedActionOperation.java b/core/java/com/android/internal/widget/remotecompose/core/operations/layout/modifiers/HostNamedActionOperation.java index f9a4270905a16ca4334aa70a0374d4cc434e483f..49ef58e0fe53d8c9a135bb17b7cc4c21e89e48ec 100644 --- a/core/java/com/android/internal/widget/remotecompose/core/operations/layout/modifiers/HostNamedActionOperation.java +++ b/core/java/com/android/internal/widget/remotecompose/core/operations/layout/modifiers/HostNamedActionOperation.java @@ -125,6 +125,11 @@ public class HostNamedActionOperation extends Operation implements ActionOperati operations.add(new HostNamedActionOperation(textId, type, valueId)); } + /** + * Populate the documentation with a description of this operation + * + * @param doc to append the description to. + */ public static void documentation(@NonNull DocumentationBuilder doc) { doc.operation("Layout Operations", OP_CODE, "HostNamedAction") .description("Host Named action. This operation represents a host action") diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/layout/modifiers/MarqueeModifierOperation.java b/core/java/com/android/internal/widget/remotecompose/core/operations/layout/modifiers/MarqueeModifierOperation.java new file mode 100644 index 0000000000000000000000000000000000000000..9588e99a65b6de99996c2cf1f5fdfedc9713af56 --- /dev/null +++ b/core/java/com/android/internal/widget/remotecompose/core/operations/layout/modifiers/MarqueeModifierOperation.java @@ -0,0 +1,214 @@ +/* + * Copyright (C) 2024 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES 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.widget.remotecompose.core.operations.layout.modifiers; + +import static com.android.internal.widget.remotecompose.core.documentation.DocumentedOperation.FLOAT; + +import android.annotation.NonNull; + +import com.android.internal.widget.remotecompose.core.Operation; +import com.android.internal.widget.remotecompose.core.Operations; +import com.android.internal.widget.remotecompose.core.PaintContext; +import com.android.internal.widget.remotecompose.core.RemoteContext; +import com.android.internal.widget.remotecompose.core.WireBuffer; +import com.android.internal.widget.remotecompose.core.documentation.DocumentationBuilder; +import com.android.internal.widget.remotecompose.core.operations.layout.Component; +import com.android.internal.widget.remotecompose.core.operations.layout.LayoutComponent; +import com.android.internal.widget.remotecompose.core.operations.layout.ScrollDelegate; +import com.android.internal.widget.remotecompose.core.operations.utilities.StringSerializer; + +import java.util.List; + +/** Represents a Marquee modifier. */ +public class MarqueeModifierOperation extends DecoratorModifierOperation implements ScrollDelegate { + private static final int OP_CODE = Operations.MODIFIER_MARQUEE; + public static final String CLASS_NAME = "MarqueeModifierOperation"; + + int mIterations; + int mAnimationMode; + float mRepeatDelayMillis; + float mInitialDelayMillis; + float mSpacing; + float mVelocity; + + private float mComponentWidth; + private float mComponentHeight; + private float mContentWidth; + private float mContentHeight; + + public MarqueeModifierOperation( + int iterations, + int animationMode, + float repeatDelayMillis, + float initialDelayMillis, + float spacing, + float velocity) { + this.mIterations = iterations; + this.mAnimationMode = animationMode; + this.mRepeatDelayMillis = repeatDelayMillis; + this.mInitialDelayMillis = initialDelayMillis; + this.mSpacing = spacing; + this.mVelocity = velocity; + } + + public void setContentWidth(float value) { + mContentWidth = value; + } + + public void setContentHeight(float value) { + mContentHeight = value; + } + + @Override + public float getScrollX(float currentValue) { + return mScrollX; + } + + @Override + public float getScrollY(float currentValue) { + return 0; + } + + @Override + public boolean handlesHorizontalScroll() { + return true; + } + + @Override + public boolean handlesVerticalScroll() { + return false; + } + + /** Reset the modifier */ + public void reset() { + mLastTime = 0; + mScrollX = 0f; + } + + @Override + public void write(WireBuffer buffer) { + apply( + buffer, + mIterations, + mAnimationMode, + mRepeatDelayMillis, + mInitialDelayMillis, + mSpacing, + mVelocity); + } + + // @Override + public void serializeToString(int indent, StringSerializer serializer) { + serializer.append(indent, "MARQUEE = [" + mIterations + "]"); + } + + @NonNull + @Override + public String deepToString(@NonNull String indent) { + return (indent != null ? indent : "") + toString(); + } + + private long mLastTime = 0; + private long mStartTime = 0; + + private float mScrollX = 0f; + + @Override + public void paint(PaintContext context) { + long currentTime = System.currentTimeMillis(); + if (mLastTime == 0) { + mLastTime = currentTime; + mStartTime = mLastTime + (long) mInitialDelayMillis; + context.needsRepaint(); + } + if (mContentWidth > mComponentWidth && currentTime - mStartTime > mInitialDelayMillis) { + float density = context.getContext().getDensity(); // in dp + float delta = mContentWidth - mComponentWidth; + float duration = delta / (density * mVelocity); + float elapsed = ((System.currentTimeMillis() - mStartTime) / 1000f); + elapsed = (elapsed % duration) / duration; + float offset = + (1f + (float) Math.sin(elapsed * 2 * Math.PI - Math.PI / 2f)) / 2f * -delta; + + mScrollX = offset; + context.needsRepaint(); + } + } + + @Override + public String toString() { + return "MarqueeModifierOperation(" + mIterations + ")"; + } + + public static String name() { + return CLASS_NAME; + } + + public static int id() { + return OP_CODE; + } + + public static void apply( + WireBuffer buffer, + int iterations, + int animationMode, + float repeatDelayMillis, + float initialDelayMillis, + float spacing, + float velocity) { + buffer.start(OP_CODE); + buffer.writeInt(iterations); + buffer.writeInt(animationMode); + buffer.writeFloat(repeatDelayMillis); + buffer.writeFloat(initialDelayMillis); + buffer.writeFloat(spacing); + buffer.writeFloat(velocity); + } + + public static void read(WireBuffer buffer, List operations) { + int iterations = buffer.readInt(); + int animationMode = buffer.readInt(); + float repeatDelayMillis = buffer.readFloat(); + float initialDelayMillis = buffer.readFloat(); + float spacing = buffer.readFloat(); + float velocity = buffer.readFloat(); + operations.add( + new MarqueeModifierOperation( + iterations, + animationMode, + repeatDelayMillis, + initialDelayMillis, + spacing, + velocity)); + } + + public static void documentation(DocumentationBuilder doc) { + doc.operation("Modifier Operations", OP_CODE, CLASS_NAME) + .description("specify a Marquee Modifier") + .field(FLOAT, "value", ""); + } + + @Override + public void layout(RemoteContext context, Component component, float width, float height) { + mComponentWidth = width; + mComponentHeight = height; + if (component instanceof LayoutComponent) { + LayoutComponent layoutComponent = (LayoutComponent) component; + setContentWidth(layoutComponent.intrinsicWidth(context)); + setContentHeight(layoutComponent.intrinsicHeight(context)); + } + } +} diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/layout/modifiers/OffsetModifierOperation.java b/core/java/com/android/internal/widget/remotecompose/core/operations/layout/modifiers/OffsetModifierOperation.java index 69c4e9a8e42377772ab44ce1eb3813ae7c7f2efe..42719478faf0addcd0a40d6e9acbf6ade192a8b1 100644 --- a/core/java/com/android/internal/widget/remotecompose/core/operations/layout/modifiers/OffsetModifierOperation.java +++ b/core/java/com/android/internal/widget/remotecompose/core/operations/layout/modifiers/OffsetModifierOperation.java @@ -26,6 +26,7 @@ import com.android.internal.widget.remotecompose.core.RemoteContext; import com.android.internal.widget.remotecompose.core.WireBuffer; import com.android.internal.widget.remotecompose.core.documentation.DocumentationBuilder; import com.android.internal.widget.remotecompose.core.operations.Utils; +import com.android.internal.widget.remotecompose.core.operations.layout.Component; import com.android.internal.widget.remotecompose.core.operations.utilities.StringSerializer; import java.util.List; @@ -90,6 +91,12 @@ public class OffsetModifierOperation extends DecoratorModifierOperation { return "OffsetModifierOperation(" + mX + ", " + mY + ")"; } + /** + * The name of the class + * + * @return the name + */ + @NonNull public static String name() { return CLASS_NAME; } @@ -123,5 +130,5 @@ public class OffsetModifierOperation extends DecoratorModifierOperation { } @Override - public void layout(RemoteContext context, float width, float height) {} + public void layout(RemoteContext context, Component component, float width, float height) {} } diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/layout/modifiers/PaddingModifierOperation.java b/core/java/com/android/internal/widget/remotecompose/core/operations/layout/modifiers/PaddingModifierOperation.java index 545df64ab154dfc294ed2b9a69d6f4db3d4d49fa..bcfbdd68472fc8ccda2b533a646d19d7f5417cbf 100644 --- a/core/java/com/android/internal/widget/remotecompose/core/operations/layout/modifiers/PaddingModifierOperation.java +++ b/core/java/com/android/internal/widget/remotecompose/core/operations/layout/modifiers/PaddingModifierOperation.java @@ -113,6 +113,11 @@ public class PaddingModifierOperation extends Operation implements ModifierOpera + ")"; } + /** + * The name of the class + * + * @return the name + */ @NonNull public static String name() { return CLASS_NAME; @@ -150,6 +155,11 @@ public class PaddingModifierOperation extends Operation implements ModifierOpera operations.add(new PaddingModifierOperation(left, top, right, bottom)); } + /** + * Populate the documentation with a description of this operation + * + * @param doc to append the description to. + */ public static void documentation(@NonNull DocumentationBuilder doc) { doc.operation("Modifier Operations", OP_CODE, CLASS_NAME) .description("define the Padding Modifier") diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/layout/modifiers/RippleModifierOperation.java b/core/java/com/android/internal/widget/remotecompose/core/operations/layout/modifiers/RippleModifierOperation.java new file mode 100644 index 0000000000000000000000000000000000000000..fe074e4754e2880d09e6d1ad0bda9ea500b76fad --- /dev/null +++ b/core/java/com/android/internal/widget/remotecompose/core/operations/layout/modifiers/RippleModifierOperation.java @@ -0,0 +1,192 @@ +/* + * Copyright (C) 2024 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES 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.widget.remotecompose.core.operations.layout.modifiers; + +import android.annotation.NonNull; + +import com.android.internal.widget.remotecompose.core.CoreDocument; +import com.android.internal.widget.remotecompose.core.Operation; +import com.android.internal.widget.remotecompose.core.Operations; +import com.android.internal.widget.remotecompose.core.PaintContext; +import com.android.internal.widget.remotecompose.core.RemoteContext; +import com.android.internal.widget.remotecompose.core.WireBuffer; +import com.android.internal.widget.remotecompose.core.documentation.DocumentationBuilder; +import com.android.internal.widget.remotecompose.core.operations.Utils; +import com.android.internal.widget.remotecompose.core.operations.layout.Component; +import com.android.internal.widget.remotecompose.core.operations.layout.RootLayoutComponent; +import com.android.internal.widget.remotecompose.core.operations.layout.TouchHandler; +import com.android.internal.widget.remotecompose.core.operations.paint.PaintBundle; +import com.android.internal.widget.remotecompose.core.operations.utilities.ColorUtils; +import com.android.internal.widget.remotecompose.core.operations.utilities.StringSerializer; +import com.android.internal.widget.remotecompose.core.operations.utilities.easing.Easing; +import com.android.internal.widget.remotecompose.core.operations.utilities.easing.FloatAnimation; + +import java.util.List; + +/** Represents a ripple effect */ +public class RippleModifierOperation extends DecoratorModifierOperation implements TouchHandler { + private static final int OP_CODE = Operations.MODIFIER_RIPPLE; + + long mAnimateRippleStart = 0; + float mAnimateRippleX = 0f; + float mAnimateRippleY = 0f; + int mAnimateRippleDuration = 1000; + + float mWidth = 0; + float mHeight = 0; + + @NonNull public float[] locationInWindow = new float[2]; + + @NonNull PaintBundle mPaint = new PaintBundle(); + + /** + * Animate the ripple effect + * + * @param x + * @param y + */ + public void animateRipple(float x, float y) { + mAnimateRippleStart = System.currentTimeMillis(); + mAnimateRippleX = x; + mAnimateRippleY = y; + } + + @Override + public void write(@NonNull WireBuffer buffer) { + apply(buffer); + } + + @NonNull + @Override + public String toString() { + return "RippleModifier"; + } + + @Override + public void apply(@NonNull RemoteContext context) { + RootLayoutComponent root = context.getDocument().getRootLayoutComponent(); + if (root != null) { + root.setHasTouchListeners(true); + } + } + + @NonNull + @Override + public String deepToString(@NonNull String indent) { + return (indent != null ? indent : "") + toString(); + } + + @Override + public void paint(@NonNull PaintContext context) { + if (mAnimateRippleStart == 0) { + return; + } + context.needsRepaint(); + + float progress = (System.currentTimeMillis() - mAnimateRippleStart); + progress /= (float) mAnimateRippleDuration; + if (progress > 1f) { + mAnimateRippleStart = 0; + } + progress = Math.min(1f, progress); + context.save(); + context.savePaint(); + mPaint.reset(); + + FloatAnimation anim1 = + new FloatAnimation(Easing.CUBIC_STANDARD, 1f, null, Float.NaN, Float.NaN); + anim1.setInitialValue(0f); + anim1.setTargetValue(1f); + float tween = anim1.get(progress); + + FloatAnimation anim2 = + new FloatAnimation(Easing.CUBIC_STANDARD, 0.5f, null, Float.NaN, Float.NaN); + anim2.setInitialValue(0f); + anim2.setTargetValue(1f); + float tweenRadius = anim2.get(progress); + + int startColor = ColorUtils.createColor(250, 250, 250, 180); + int endColor = ColorUtils.createColor(200, 200, 200, 0); + int paintedColor = Utils.interpolateColor(startColor, endColor, tween); + + float radius = Math.max(mWidth, mHeight) * tweenRadius; + mPaint.setColor(paintedColor); + context.applyPaint(mPaint); + context.clipRect(0f, 0f, mWidth, mHeight); + context.drawCircle(mAnimateRippleX, mAnimateRippleY, radius); + context.restorePaint(); + context.restore(); + } + + @Override + public void layout( + @NonNull RemoteContext context, Component component, float width, float height) { + mWidth = width; + mHeight = height; + } + + @Override + public void serializeToString(int indent, @NonNull StringSerializer serializer) { + serializer.append(indent, "RIPPLE_MODIFIER"); + } + + @NonNull + public static String name() { + return "RippleModifier"; + } + + public static void apply(@NonNull WireBuffer buffer) { + buffer.start(OP_CODE); + } + + public static void read(@NonNull WireBuffer buffer, @NonNull List operations) { + operations.add(new RippleModifierOperation()); + } + + public static void documentation(@NonNull DocumentationBuilder doc) { + doc.operation("Layout Operations", OP_CODE, name()) + .description( + "Ripple modifier. This modifier will do a ripple animation on touch down"); + } + + @Override + public void onTouchDown( + RemoteContext context, CoreDocument document, Component component, float x, float y) { + locationInWindow[0] = 0f; + locationInWindow[1] = 0f; + component.getLocationInWindow(locationInWindow); + animateRipple(x - locationInWindow[0], y - locationInWindow[1]); + context.hapticEffect(3); + } + + @Override + public void onTouchUp( + RemoteContext context, + CoreDocument document, + Component component, + float x, + float y, + float dx, + float dy) {} + + @Override + public void onTouchDrag( + RemoteContext context, CoreDocument document, Component component, float x, float y) {} + + @Override + public void onTouchCancel( + RemoteContext context, CoreDocument document, Component component, float x, float y) {} +} diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/layout/modifiers/RoundedClipRectModifierOperation.java b/core/java/com/android/internal/widget/remotecompose/core/operations/layout/modifiers/RoundedClipRectModifierOperation.java index 681501d9cdf9566a10efb937372d6ab79bd7b187..4c1f04ebd3d400f00e1f09065ab9422644762204 100644 --- a/core/java/com/android/internal/widget/remotecompose/core/operations/layout/modifiers/RoundedClipRectModifierOperation.java +++ b/core/java/com/android/internal/widget/remotecompose/core/operations/layout/modifiers/RoundedClipRectModifierOperation.java @@ -26,6 +26,7 @@ import com.android.internal.widget.remotecompose.core.RemoteContext; import com.android.internal.widget.remotecompose.core.WireBuffer; import com.android.internal.widget.remotecompose.core.documentation.DocumentationBuilder; import com.android.internal.widget.remotecompose.core.operations.DrawBase4; +import com.android.internal.widget.remotecompose.core.operations.layout.Component; import com.android.internal.widget.remotecompose.core.operations.layout.DecoratorComponent; import com.android.internal.widget.remotecompose.core.operations.utilities.StringSerializer; @@ -57,6 +58,11 @@ public class RoundedClipRectModifierOperation extends DrawBase4 return OP_CODE; } + /** + * The name of the class + * + * @return the name + */ @NonNull public static String name() { return CLASS_NAME; @@ -67,6 +73,11 @@ public class RoundedClipRectModifierOperation extends DrawBase4 apply(buffer, v1, v2, v3, v4); } + /** + * Populate the documentation with a description of this operation + * + * @param doc to append the description to. + */ public static void documentation(@NonNull DocumentationBuilder doc) { doc.operation("Modifier Operations", id(), "RoundedClipRectModifierOperation") .description("clip with rectangle") @@ -107,7 +118,8 @@ public class RoundedClipRectModifierOperation extends DrawBase4 } @Override - public void layout(@NonNull RemoteContext context, float width, float height) { + public void layout( + @NonNull RemoteContext context, Component component, float width, float height) { this.mWidth = width; this.mHeight = height; } diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/layout/modifiers/ScrollModifierOperation.java b/core/java/com/android/internal/widget/remotecompose/core/operations/layout/modifiers/ScrollModifierOperation.java index 0b6632057bd2d77ae987bcbe0b821a3953c113f3..a5f79ee7e7b7686f5fed950897a5790a131f6f48 100644 --- a/core/java/com/android/internal/widget/remotecompose/core/operations/layout/modifiers/ScrollModifierOperation.java +++ b/core/java/com/android/internal/widget/remotecompose/core/operations/layout/modifiers/ScrollModifierOperation.java @@ -24,18 +24,24 @@ import com.android.internal.widget.remotecompose.core.Operation; import com.android.internal.widget.remotecompose.core.Operations; import com.android.internal.widget.remotecompose.core.PaintContext; import com.android.internal.widget.remotecompose.core.RemoteContext; +import com.android.internal.widget.remotecompose.core.VariableSupport; import com.android.internal.widget.remotecompose.core.WireBuffer; import com.android.internal.widget.remotecompose.core.documentation.DocumentationBuilder; +import com.android.internal.widget.remotecompose.core.operations.TouchExpression; import com.android.internal.widget.remotecompose.core.operations.Utils; import com.android.internal.widget.remotecompose.core.operations.layout.Component; +import com.android.internal.widget.remotecompose.core.operations.layout.DecoratorComponent; +import com.android.internal.widget.remotecompose.core.operations.layout.ListActionsOperation; import com.android.internal.widget.remotecompose.core.operations.layout.RootLayoutComponent; +import com.android.internal.widget.remotecompose.core.operations.layout.ScrollDelegate; import com.android.internal.widget.remotecompose.core.operations.layout.TouchHandler; import com.android.internal.widget.remotecompose.core.operations.utilities.StringSerializer; import java.util.List; /** Represents a scroll modifier. */ -public class ScrollModifierOperation extends DecoratorModifierOperation implements TouchHandler { +public class ScrollModifierOperation extends ListActionsOperation + implements TouchHandler, DecoratorComponent, ScrollDelegate, VariableSupport { private static final int OP_CODE = Operations.MODIFIER_SCROLL; public static final String CLASS_NAME = "ScrollModifierOperation"; @@ -43,9 +49,6 @@ public class ScrollModifierOperation extends DecoratorModifierOperation implemen private final float mMax; private final float mNotchMax; - float mWidth = 0; - float mHeight = 0; - int mDirection; float mTouchDownX; @@ -63,13 +66,44 @@ public class ScrollModifierOperation extends DecoratorModifierOperation implemen float mHostDimension; float mContentDimension; + private TouchExpression mTouchExpression; + public ScrollModifierOperation(int direction, float position, float max, float notchMax) { + super("SCROLL_MODIFIER"); this.mDirection = direction; this.mPositionExpression = position; this.mMax = max; this.mNotchMax = notchMax; } + /** + * Inflate the operation + * + * @param component + */ + public void inflate(Component component) { + for (Operation op : mList) { + if (op instanceof TouchExpression) { + mTouchExpression = (TouchExpression) op; + mTouchExpression.setComponent(component); + } + } + } + + @Override + public void registerListening(@NonNull RemoteContext context) { + if (mTouchExpression != null) { + mTouchExpression.registerListening(context); + } + } + + @Override + public void updateVariables(@NonNull RemoteContext context) { + if (mTouchExpression != null) { + mTouchExpression.updateVariables(context); + } + } + public boolean isVerticalScroll() { return mDirection == 0; } @@ -113,6 +147,12 @@ public class ScrollModifierOperation extends DecoratorModifierOperation implemen @Override public void paint(PaintContext context) { + for (Operation op : mList) { + op.apply(context.getContext()); + } + if (mTouchExpression == null) { + return; + } float position = context.getContext() .mRemoteComposeState @@ -130,6 +170,12 @@ public class ScrollModifierOperation extends DecoratorModifierOperation implemen return "ScrollModifierOperation(" + mDirection + ")"; } + /** + * The name of the class + * + * @return the name + */ + @NonNull public static String name() { return CLASS_NAME; } @@ -167,7 +213,7 @@ public class ScrollModifierOperation extends DecoratorModifierOperation implemen } @Override - public void layout(RemoteContext context, float width, float height) { + public void layout(RemoteContext context, Component component, float width, float height) { mWidth = width; mHeight = height; if (mDirection == 0) { // VERTICAL @@ -186,18 +232,36 @@ public class ScrollModifierOperation extends DecoratorModifierOperation implemen mTouchDownY = y; mInitialScrollX = mScrollX; mInitialScrollY = mScrollY; + if (mTouchExpression != null) { + mTouchExpression.updateVariables(context); + mTouchExpression.touchDown(context, x + mScrollX, y + mScrollY); + } document.appliedTouchOperation(component); } @Override public void onTouchUp( - RemoteContext context, CoreDocument document, Component component, float x, float y) { + RemoteContext context, + CoreDocument document, + Component component, + float x, + float y, + float dx, + float dy) { + if (mTouchExpression != null) { + mTouchExpression.updateVariables(context); + mTouchExpression.touchUp(context, x + mScrollX, y + mScrollY, dx, dy); + } // If not using touch expression, should add velocity decay here } @Override public void onTouchDrag( RemoteContext context, CoreDocument document, Component component, float x, float y) { + if (mTouchExpression != null) { + mTouchExpression.updateVariables(context); + mTouchExpression.touchDrag(context, x + mScrollX, y + mScrollY); + } float dx = x - mTouchDownX; float dy = y - mTouchDownY; @@ -229,4 +293,35 @@ public class ScrollModifierOperation extends DecoratorModifierOperation implemen public float getContentDimension() { return mContentDimension; } + + @Override + public float getScrollX(float currentValue) { + if (mDirection == 1) { + return mScrollX; + } + return 0f; + } + + @Override + public float getScrollY(float currentValue) { + if (mDirection == 0) { + return mScrollY; + } + return 0f; + } + + @Override + public boolean handlesHorizontalScroll() { + return mDirection == 1; + } + + @Override + public boolean handlesVerticalScroll() { + return mDirection == 0; + } + + @Override + public void reset() { + // nothing here for now + } } diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/layout/modifiers/ValueFloatChangeActionOperation.java b/core/java/com/android/internal/widget/remotecompose/core/operations/layout/modifiers/ValueFloatChangeActionOperation.java index b96d3cc4bbc06e39f415fe74e9cd348134cbb254..b6977a035c9ea3e8a2fe626315e004a87c76f35c 100644 --- a/core/java/com/android/internal/widget/remotecompose/core/operations/layout/modifiers/ValueFloatChangeActionOperation.java +++ b/core/java/com/android/internal/widget/remotecompose/core/operations/layout/modifiers/ValueFloatChangeActionOperation.java @@ -73,7 +73,6 @@ public class ValueFloatChangeActionOperation extends Operation implements Action @Override public void runAction( RemoteContext context, CoreDocument document, Component component, float x, float y) { - System.out.println("OVERRIDE " + mTargetValueId + " TO " + mValue); context.overrideFloat(mTargetValueId, mValue); } diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/layout/modifiers/ValueFloatExpressionChangeActionOperation.java b/core/java/com/android/internal/widget/remotecompose/core/operations/layout/modifiers/ValueFloatExpressionChangeActionOperation.java index d81b7ffd1ef90825baa3c1157a0efdb1855b6a84..766271a70ce451b5086da184e8896f41087788a8 100644 --- a/core/java/com/android/internal/widget/remotecompose/core/operations/layout/modifiers/ValueFloatExpressionChangeActionOperation.java +++ b/core/java/com/android/internal/widget/remotecompose/core/operations/layout/modifiers/ValueFloatExpressionChangeActionOperation.java @@ -101,6 +101,11 @@ public class ValueFloatExpressionChangeActionOperation extends Operation operations.add(new ValueFloatExpressionChangeActionOperation(valueId, value)); } + /** + * Populate the documentation with a description of this operation + * + * @param doc to append the description to. + */ public static void documentation(@NonNull DocumentationBuilder doc) { doc.operation("Layout Operations", OP_CODE, "ValueIntegerExpressionChangeActionOperation") .description( diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/layout/modifiers/ValueIntegerChangeActionOperation.java b/core/java/com/android/internal/widget/remotecompose/core/operations/layout/modifiers/ValueIntegerChangeActionOperation.java index fb13b42dbd2184b0fb42c72614bd1d8c3029400a..60166a7b21020e0f9e71281cbd62ac125803862c 100644 --- a/core/java/com/android/internal/widget/remotecompose/core/operations/layout/modifiers/ValueIntegerChangeActionOperation.java +++ b/core/java/com/android/internal/widget/remotecompose/core/operations/layout/modifiers/ValueIntegerChangeActionOperation.java @@ -99,6 +99,11 @@ public class ValueIntegerChangeActionOperation extends Operation implements Acti operations.add(new ValueIntegerChangeActionOperation(valueId, value)); } + /** + * Populate the documentation with a description of this operation + * + * @param doc to append the description to. + */ public static void documentation(@NonNull DocumentationBuilder doc) { doc.operation("Layout Operations", OP_CODE, "ValueIntegerChangeActionOperation") .description( diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/layout/modifiers/ValueIntegerExpressionChangeActionOperation.java b/core/java/com/android/internal/widget/remotecompose/core/operations/layout/modifiers/ValueIntegerExpressionChangeActionOperation.java index 0fe88ad165a910643e1e6defd1ac7caf71089b6b..502508058465e75ce054d17bacd75fa00a319c66 100644 --- a/core/java/com/android/internal/widget/remotecompose/core/operations/layout/modifiers/ValueIntegerExpressionChangeActionOperation.java +++ b/core/java/com/android/internal/widget/remotecompose/core/operations/layout/modifiers/ValueIntegerExpressionChangeActionOperation.java @@ -101,6 +101,11 @@ public class ValueIntegerExpressionChangeActionOperation extends Operation operations.add(new ValueIntegerExpressionChangeActionOperation(valueId, value)); } + /** + * Populate the documentation with a description of this operation + * + * @param doc to append the description to. + */ public static void documentation(@NonNull DocumentationBuilder doc) { doc.operation("Layout Operations", OP_CODE, "ValueIntegerExpressionChangeActionOperation") .description( diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/layout/modifiers/ValueStringChangeActionOperation.java b/core/java/com/android/internal/widget/remotecompose/core/operations/layout/modifiers/ValueStringChangeActionOperation.java index a8d3b87f04b4f0eeb02879888a0cb0de57d142ef..8093bb3c64ec51b18d53960295366ad4d0982551 100644 --- a/core/java/com/android/internal/widget/remotecompose/core/operations/layout/modifiers/ValueStringChangeActionOperation.java +++ b/core/java/com/android/internal/widget/remotecompose/core/operations/layout/modifiers/ValueStringChangeActionOperation.java @@ -103,6 +103,11 @@ public class ValueStringChangeActionOperation extends Operation implements Actio operations.add(new ValueStringChangeActionOperation(valueId, value)); } + /** + * Populate the documentation with a description of this operation + * + * @param doc to append the description to. + */ public static void documentation(@NonNull DocumentationBuilder doc) { doc.operation("Layout Operations", OP_CODE, "ValueStringChangeActionOperation") .description( diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/layout/modifiers/WidthModifierOperation.java b/core/java/com/android/internal/widget/remotecompose/core/operations/layout/modifiers/WidthModifierOperation.java index f6d743f599d3de0f51ad1d0f0e3f40c943bc3cc5..05305988a49fa442b3306d1412c690910e2a8a26 100644 --- a/core/java/com/android/internal/widget/remotecompose/core/operations/layout/modifiers/WidthModifierOperation.java +++ b/core/java/com/android/internal/widget/remotecompose/core/operations/layout/modifiers/WidthModifierOperation.java @@ -32,6 +32,11 @@ public class WidthModifierOperation extends DimensionModifierOperation { private static final int OP_CODE = Operations.MODIFIER_WIDTH; public static final String CLASS_NAME = "WidthModifierOperation"; + /** + * The name of the class + * + * @return the name + */ @NonNull public static String name() { return CLASS_NAME; @@ -94,6 +99,11 @@ public class WidthModifierOperation extends DimensionModifierOperation { return "WIDTH"; } + /** + * Populate the documentation with a description of this operation + * + * @param doc to append the description to. + */ public static void documentation(@NonNull DocumentationBuilder doc) { doc.operation("Modifier Operations", OP_CODE, CLASS_NAME) .description("define the animation") diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/layout/modifiers/ZIndexModifierOperation.java b/core/java/com/android/internal/widget/remotecompose/core/operations/layout/modifiers/ZIndexModifierOperation.java index 96ed2cda3e106a6a10f26afdfb0e20ed51c1b8d9..35de33a9997a6a1ddb21e0f7f738c8720e0e8908 100644 --- a/core/java/com/android/internal/widget/remotecompose/core/operations/layout/modifiers/ZIndexModifierOperation.java +++ b/core/java/com/android/internal/widget/remotecompose/core/operations/layout/modifiers/ZIndexModifierOperation.java @@ -26,6 +26,7 @@ import com.android.internal.widget.remotecompose.core.RemoteContext; import com.android.internal.widget.remotecompose.core.WireBuffer; import com.android.internal.widget.remotecompose.core.documentation.DocumentationBuilder; import com.android.internal.widget.remotecompose.core.operations.Utils; +import com.android.internal.widget.remotecompose.core.operations.layout.Component; import com.android.internal.widget.remotecompose.core.operations.utilities.StringSerializer; import java.util.List; @@ -45,7 +46,7 @@ public class ZIndexModifierOperation extends DecoratorModifierOperation { return mCurrentValue; } - public void setmValue(float value) { + public void setValue(float value) { this.mValue = value; } @@ -79,6 +80,12 @@ public class ZIndexModifierOperation extends DecoratorModifierOperation { return "ZIndexModifierOperation(" + mValue + ")"; } + /** + * The name of the class + * + * @return the name + */ + @NonNull public static String name() { return CLASS_NAME; } @@ -109,5 +116,5 @@ public class ZIndexModifierOperation extends DecoratorModifierOperation { } @Override - public void layout(RemoteContext context, float width, float height) {} + public void layout(RemoteContext context, Component component, float width, float height) {} } diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/utilities/AnimatedFloatExpression.java b/core/java/com/android/internal/widget/remotecompose/core/operations/utilities/AnimatedFloatExpression.java index a56874781e4a42382bdb9a9d0f028be4a4743896..7e467012536d44d106a1021a0999818220e9980c 100644 --- a/core/java/com/android/internal/widget/remotecompose/core/operations/utilities/AnimatedFloatExpression.java +++ b/core/java/com/android/internal/widget/remotecompose/core/operations/utilities/AnimatedFloatExpression.java @@ -20,58 +20,147 @@ import android.annotation.Nullable; import com.android.internal.widget.remotecompose.core.operations.utilities.easing.MonotonicSpline; +import java.util.Random; + /** high performance floating point expression evaluator used in animation */ public class AnimatedFloatExpression { @NonNull static IntMap sNames = new IntMap<>(); + + /** The START POINT in the float NaN space for operators */ public static final int OFFSET = 0x310_000; + + /** ADD operator */ public static final float ADD = asNan(OFFSET + 1); + + /** SUB operator */ public static final float SUB = asNan(OFFSET + 2); + + /** MUL operator */ public static final float MUL = asNan(OFFSET + 3); + + /** DIV operator */ public static final float DIV = asNan(OFFSET + 4); + + /** MOD operator */ public static final float MOD = asNan(OFFSET + 5); + + /** MIN operator */ public static final float MIN = asNan(OFFSET + 6); + + /** MAX operator */ public static final float MAX = asNan(OFFSET + 7); + + /** POW operator */ public static final float POW = asNan(OFFSET + 8); + + /** SQRT operator */ public static final float SQRT = asNan(OFFSET + 9); + + /** ABS operator */ public static final float ABS = asNan(OFFSET + 10); + + /** SIGN operator */ public static final float SIGN = asNan(OFFSET + 11); + + /** COPY_SIGN operator */ public static final float COPY_SIGN = asNan(OFFSET + 12); + + /** EXP operator */ public static final float EXP = asNan(OFFSET + 13); + + /** FLOOR operator */ public static final float FLOOR = asNan(OFFSET + 14); + + /** LOG operator */ public static final float LOG = asNan(OFFSET + 15); + + /** LN operator */ public static final float LN = asNan(OFFSET + 16); + + /** ROUND operator */ public static final float ROUND = asNan(OFFSET + 17); + + /** SIN operator */ public static final float SIN = asNan(OFFSET + 18); + + /** COS operator */ public static final float COS = asNan(OFFSET + 19); + + /** TAN operator */ public static final float TAN = asNan(OFFSET + 20); + + /** ASIN operator */ public static final float ASIN = asNan(OFFSET + 21); + + /** ACOS operator */ public static final float ACOS = asNan(OFFSET + 22); + /** ATAN operator */ public static final float ATAN = asNan(OFFSET + 23); + /** ATAN2 operator */ public static final float ATAN2 = asNan(OFFSET + 24); + + /** MAD operator */ public static final float MAD = asNan(OFFSET + 25); + + /** IFELSE operator */ public static final float IFELSE = asNan(OFFSET + 26); + /** CLAMP operator */ public static final float CLAMP = asNan(OFFSET + 27); + + /** CBRT operator */ public static final float CBRT = asNan(OFFSET + 28); + + /** DEG operator */ public static final float DEG = asNan(OFFSET + 29); + + /** RAD operator */ public static final float RAD = asNan(OFFSET + 30); + + /** CEIL operator */ public static final float CEIL = asNan(OFFSET + 31); // Array ops + /** A DEREF operator */ public static final float A_DEREF = asNan(OFFSET + 32); + + /** Array MAX operator */ public static final float A_MAX = asNan(OFFSET + 33); + + /** Array MIN operator */ public static final float A_MIN = asNan(OFFSET + 34); + + /** A_SUM operator */ public static final float A_SUM = asNan(OFFSET + 35); + + /** A_AVG operator */ public static final float A_AVG = asNan(OFFSET + 36); + + /** A_LEN operator */ public static final float A_LEN = asNan(OFFSET + 37); + + /** A_SPLINE operator */ public static final float A_SPLINE = asNan(OFFSET + 38); - public static final int LAST_OP = OFFSET + 38; + /** RAND Random number 0..1 */ + public static final float RAND = asNan(OFFSET + 39); + + /** RAND_SEED operator */ + public static final float RAND_SEED = asNan(OFFSET + 40); + + /** LAST valid operator */ + public static final int LAST_OP = OFFSET + 40; - public static final float VAR1 = asNan(OFFSET + 39); - public static final float VAR2 = asNan(OFFSET + 40); + /** VAR1 operator */ + public static final float VAR1 = asNan(OFFSET + 41); + + /** VAR2 operator */ + public static final float VAR2 = asNan(OFFSET + 42); + + /** VAR2 operator */ + public static final float VAR3 = asNan(OFFSET + 43); // TODO CLAMP, CBRT, DEG, RAD, EXPM1, CEIL, FLOOR // private static final float FP_PI = (float) Math.PI; @@ -83,6 +172,7 @@ public class AnimatedFloatExpression { @NonNull float[] mVar = new float[0]; @Nullable CollectionsAccess mCollectionsAccess; IntMap mSplineMap = new IntMap<>(); + private Random mRandom; private float getSplineValue(int arrayId, float pos) { MonotonicSpline fit = mSplineMap.get(arrayId); @@ -151,10 +241,11 @@ public class AnimatedFloatExpression { /** * Evaluate a float expression * - * @param ca - * @param exp - * @param var - * @return + * @param ca Access to float array collections + * @param exp the expressions + * @param len the length of the expression array + * @param var variables if the expression contains VAR tags + * @return the value the expression evaluated to */ public float eval( @NonNull CollectionsAccess ca, @NonNull float[] exp, int len, @NonNull float... var) { @@ -183,9 +274,10 @@ public class AnimatedFloatExpression { /** * Evaluate a float expression * - * @param ca - * @param exp - * @return + * @param ca The access to float arrays + * @param exp the expression + * @param len the length of the expression sections + * @return the value the expression evaluated to */ public float eval(@NonNull CollectionsAccess ca, @NonNull float[] exp, int len) { System.arraycopy(exp, 0, mLocalStack, 0, len); @@ -304,6 +396,8 @@ public class AnimatedFloatExpression { sNames.put(k++, "A_AVG"); sNames.put(k++, "A_LEN"); sNames.put(k++, "A_SPLINE"); + sNames.put(k++, "RAND"); + sNames.put(k++, "RAND_SEED"); sNames.put(k++, "a[0]"); sNames.put(k++, "a[1]"); @@ -518,9 +612,12 @@ public class AnimatedFloatExpression { private static final int OP_A_AVG = OFFSET + 36; private static final int OP_A_LEN = OFFSET + 37; private static final int OP_A_SPLINE = OFFSET + 38; - private static final int OP_FIRST_VAR = OFFSET + 39; - private static final int OP_SECOND_VAR = OFFSET + 40; - private static final int OP_THIRD_VAR = OFFSET + 41; + private static final int OP_RAND = OFFSET + 39; + private static final int OP_RAND_SEED = OFFSET + 40; + + private static final int OP_FIRST_VAR = OFFSET + 41; + private static final int OP_SECOND_VAR = OFFSET + 42; + private static final int OP_THIRD_VAR = OFFSET + 43; int opEval(int sp, int id) { float[] array; @@ -708,6 +805,26 @@ public class AnimatedFloatExpression { mStack[sp - 1] = getSplineValue(id, mStack[sp]); return sp - 1; + case OP_RAND: + if (mRandom == null) { + mRandom = new Random(); + } + mStack[sp + 1] = mRandom.nextFloat(); + return sp + 1; + + case OP_RAND_SEED: + float seed = mStack[sp]; + if (seed == 0) { + mRandom = new Random(); + } else { + if (mRandom == null) { + mRandom = new Random(Float.floatToRawIntBits(seed)); + } else { + mRandom.setSeed(Float.floatToRawIntBits(seed)); + } + } + return sp - 1; + case OP_FIRST_VAR: mStack[sp] = mVar[0]; return sp; diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/utilities/ArrayAccess.java b/core/java/com/android/internal/widget/remotecompose/core/operations/utilities/ArrayAccess.java index 182d36a5eb066fdbfdaddc476dcdd08156f8947b..69de5354a92335ff90c2553027dd3e13b3c2894a 100644 --- a/core/java/com/android/internal/widget/remotecompose/core/operations/utilities/ArrayAccess.java +++ b/core/java/com/android/internal/widget/remotecompose/core/operations/utilities/ArrayAccess.java @@ -23,17 +23,45 @@ import android.annotation.Nullable; * FloatArrayAccess, ListAccess, MapAccess */ public interface ArrayAccess { + /** + * Get a value as a float for an index + * + * @param index position in the collection + * @return + */ float getFloatValue(int index); + /** + * If the objects have id's return the id + * + * @param index index of the object + * @return id or -1 if no id is available + */ default int getId(int index) { return 0; } + /** + * Get the backing array of float if available for float arrays + * + * @return + */ @Nullable float[] getFloats(); + /** + * Get the length of the collection + * + * @return length of the collection + */ int getLength(); + /** + * Get the value as an integer if available + * + * @param index the position in the collection + * @return it value as and integer + */ default int getIntValue(int index) { return (int) getFloatValue(index); } diff --git a/core/java/com/android/internal/widget/remotecompose/core/semantics/AccessibilityModifier.java b/core/java/com/android/internal/widget/remotecompose/core/semantics/AccessibilityModifier.java new file mode 100644 index 0000000000000000000000000000000000000000..cd8b7b865cd2b49bfc53dac45ef79a9e53d59412 --- /dev/null +++ b/core/java/com/android/internal/widget/remotecompose/core/semantics/AccessibilityModifier.java @@ -0,0 +1,23 @@ +/* + * Copyright (C) 2024 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES 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.widget.remotecompose.core.semantics; + +import com.android.internal.widget.remotecompose.core.operations.layout.modifiers.ModifierOperation; + +/** A Modifier that provides semantic info. */ +public interface AccessibilityModifier extends ModifierOperation, AccessibleComponent { + int getOpCode(); +} diff --git a/core/java/com/android/internal/widget/remotecompose/core/semantics/AccessibilitySemantics.java b/core/java/com/android/internal/widget/remotecompose/core/semantics/AccessibilitySemantics.java new file mode 100644 index 0000000000000000000000000000000000000000..291ad477703b1a9dd4f6d6c0547e744ec240f959 --- /dev/null +++ b/core/java/com/android/internal/widget/remotecompose/core/semantics/AccessibilitySemantics.java @@ -0,0 +1,34 @@ +/* + * Copyright (C) 2024 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES 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.widget.remotecompose.core.semantics; + +/** Marker interface for a Component or Modifier that is relevant for Semantics. */ +public interface AccessibilitySemantics { + + /** + * Determines if this element is interesting for semantic analysis. + * + *

    This method is used to filter elements during semantic analysis. By default, all elements + * are considered interesting. Subclasses can override this method to exclude specific elements + * from semantic analysis. + * + * @return {@code true} if this element is interesting for semantic analysis, {@code false} + * otherwise. + */ + default boolean isInterestingForSemantics() { + return true; + } +} diff --git a/core/java/com/android/internal/widget/remotecompose/core/semantics/AccessibleComponent.java b/core/java/com/android/internal/widget/remotecompose/core/semantics/AccessibleComponent.java new file mode 100644 index 0000000000000000000000000000000000000000..e07fc4d9a8f8b5924949cde31db0f86823355a2c --- /dev/null +++ b/core/java/com/android/internal/widget/remotecompose/core/semantics/AccessibleComponent.java @@ -0,0 +1,73 @@ +/* + * Copyright (C) 2024 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES 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.widget.remotecompose.core.semantics; + +import android.annotation.Nullable; + +public interface AccessibleComponent extends AccessibilitySemantics { + default @Nullable Integer getContentDescriptionId() { + return null; + } + + default @Nullable Integer getTextId() { + return null; + } + + default @Nullable Role getRole() { + return null; + } + + default boolean isClickable() { + return false; + } + + default CoreSemantics.Mode getMode() { + return CoreSemantics.Mode.SET; + } + + // Our master list + // https://developer.android.com/reference/kotlin/androidx/compose/ui/semantics/Role + enum Role { + BUTTON("Button"), + CHECKBOX("Checkbox"), + SWITCH("Switch"), + RADIO_BUTTON("RadioButton"), + TAB("Tab"), + IMAGE("Image"), + DROPDOWN_LIST("DropdownList"), + PICKER("Picker"), + CAROUSEL("Carousel"), + UNKNOWN(null); + + @Nullable private final String mDescription; + + Role(@Nullable String description) { + this.mDescription = description; + } + + @Nullable + public String getDescription() { + return mDescription; + } + + public static Role fromInt(int i) { + if (i < UNKNOWN.ordinal()) { + return Role.values()[i]; + } + return Role.UNKNOWN; + } + } +} diff --git a/core/java/com/android/internal/widget/remotecompose/core/semantics/CoreSemantics.java b/core/java/com/android/internal/widget/remotecompose/core/semantics/CoreSemantics.java new file mode 100644 index 0000000000000000000000000000000000000000..4047dd27d1638336e6340659f3b4e701d98dc8ea --- /dev/null +++ b/core/java/com/android/internal/widget/remotecompose/core/semantics/CoreSemantics.java @@ -0,0 +1,157 @@ +/* + * Copyright (C) 2024 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES 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.widget.remotecompose.core.semantics; + +import android.annotation.NonNull; +import android.annotation.Nullable; + +import com.android.internal.widget.remotecompose.core.Operation; +import com.android.internal.widget.remotecompose.core.Operations; +import com.android.internal.widget.remotecompose.core.RemoteContext; +import com.android.internal.widget.remotecompose.core.WireBuffer; +import com.android.internal.widget.remotecompose.core.operations.utilities.StringSerializer; + +import java.util.List; + +/** Implementation of the most common semantics used in typical Android apps. */ +public class CoreSemantics extends Operation implements AccessibilityModifier { + public int mContentDescriptionId = 0; + public @Nullable Role mRole = null; + public int mTextId = 0; + public int mStateDescriptionId = 0; + public boolean mEnabled = true; + public Mode mMode = Mode.SET; + public boolean mClickable = false; + + @Override + public int getOpCode() { + return Operations.ACCESSIBILITY_SEMANTICS; + } + + @Nullable + @Override + public Role getRole() { + return mRole; + } + + @Override + public Mode getMode() { + return mMode; + } + + @Override + public void write(WireBuffer buffer) { + buffer.writeInt(mContentDescriptionId); + buffer.writeByte((mRole != null) ? mRole.ordinal() : -1); + buffer.writeInt(mTextId); + buffer.writeInt(mStateDescriptionId); + buffer.writeByte(mMode.ordinal()); + buffer.writeBoolean(mEnabled); + buffer.writeBoolean(mClickable); + } + + private void read(WireBuffer buffer) { + mContentDescriptionId = buffer.readInt(); + mRole = Role.fromInt(buffer.readByte()); + mTextId = buffer.readInt(); + mStateDescriptionId = buffer.readInt(); + mMode = Mode.values()[buffer.readByte()]; + mEnabled = buffer.readBoolean(); + mClickable = buffer.readBoolean(); + } + + @Override + public void apply(RemoteContext context) { + // Handled via touch helper + } + + @NonNull + @Override + public String toString() { + StringBuilder builder = new StringBuilder(); + builder.append("SEMANTICS"); + if (mMode != Mode.SET) { + builder.append(" "); + builder.append(mMode); + } + if (mRole != null) { + builder.append(" "); + builder.append(mRole); + } + if (mContentDescriptionId > 0) { + builder.append(" contentDescription="); + builder.append(mContentDescriptionId); + } + if (mTextId > 0) { + builder.append(" text="); + builder.append(mTextId); + } + if (mStateDescriptionId > 0) { + builder.append(" stateDescription="); + builder.append(mStateDescriptionId); + } + if (!mEnabled) { + builder.append(" disabled"); + } + if (mClickable) { + builder.append(" clickable"); + } + return builder.toString(); + } + + @Nullable + @Override + public String deepToString(String indent) { + return indent + this; + } + + @NonNull + public String serializedName() { + return "SEMANTICS"; + } + + @Override + public void serializeToString(int indent, @NonNull StringSerializer serializer) { + serializer.append(indent, serializedName() + " = " + this); + } + + public static void read(WireBuffer buffer, List operations) { + CoreSemantics semantics = new CoreSemantics(); + + semantics.read(buffer); + + operations.add(semantics); + } + + @Override + public Integer getContentDescriptionId() { + return mContentDescriptionId != 0 ? mContentDescriptionId : null; + } + + public @Nullable Integer getStateDescriptionId() { + return mStateDescriptionId != 0 ? mStateDescriptionId : null; + } + + public @Nullable Integer getTextId() { + return mTextId != 0 ? mTextId : null; + } + + public enum Mode { + SET, + CLEAR_AND_SET, + MERGE + } +} diff --git a/core/java/com/android/internal/widget/remotecompose/core/types/BooleanConstant.java b/core/java/com/android/internal/widget/remotecompose/core/types/BooleanConstant.java index 975213f76bd23e4b76de3ddd80e84c4f981ba81f..2c874b183a627ffa329107b47e06a245380f6a63 100644 --- a/core/java/com/android/internal/widget/remotecompose/core/types/BooleanConstant.java +++ b/core/java/com/android/internal/widget/remotecompose/core/types/BooleanConstant.java @@ -68,6 +68,11 @@ public class BooleanConstant extends Operation { return "BooleanConstant[" + mId + "] = " + mValue + ""; } + /** + * The name of the class + * + * @return the name + */ @NonNull public static String name() { return "OrigamiBoolean"; @@ -108,6 +113,11 @@ public class BooleanConstant extends Operation { operations.add(new BooleanConstant(id, value)); } + /** + * Populate the documentation with a description of this operation + * + * @param doc to append the description to. + */ public static void documentation(@NonNull DocumentationBuilder doc) { doc.operation("Expressions Operations", OP_CODE, "BooleanConstant") .description("A boolean and its associated id") diff --git a/core/java/com/android/internal/widget/remotecompose/core/types/IntegerConstant.java b/core/java/com/android/internal/widget/remotecompose/core/types/IntegerConstant.java index 210a15ac7ca4798076ac1433bf65d3d239e49077..5462d3e069ed7453aff0ae477a584522d9fa1cf3 100644 --- a/core/java/com/android/internal/widget/remotecompose/core/types/IntegerConstant.java +++ b/core/java/com/android/internal/widget/remotecompose/core/types/IntegerConstant.java @@ -60,6 +60,11 @@ public class IntegerConstant extends Operation { return "IntegerConstant[" + mId + "] = " + mValue + ""; } + /** + * The name of the class + * + * @return the name + */ @NonNull public static String name() { return "IntegerConstant"; @@ -100,6 +105,11 @@ public class IntegerConstant extends Operation { operations.add(new IntegerConstant(id, value)); } + /** + * Populate the documentation with a description of this operation + * + * @param doc to append the description to. + */ public static void documentation(@NonNull DocumentationBuilder doc) { doc.operation("Expressions Operations", id(), "IntegerConstant") .description("A integer and its associated id") diff --git a/core/java/com/android/internal/widget/remotecompose/core/types/LongConstant.java b/core/java/com/android/internal/widget/remotecompose/core/types/LongConstant.java index 9875c935c112bf5fd6298a8924f16c044479017b..1a3cdb1a96d773fc653893af96b5e5d25d71b956 100644 --- a/core/java/com/android/internal/widget/remotecompose/core/types/LongConstant.java +++ b/core/java/com/android/internal/widget/remotecompose/core/types/LongConstant.java @@ -96,6 +96,11 @@ public class LongConstant extends Operation { operations.add(new LongConstant(id, value)); } + /** + * Populate the documentation with a description of this operation + * + * @param doc to append the description to. + */ public static void documentation(@NonNull DocumentationBuilder doc) { doc.operation("Expressions Operations", OP_CODE, "LongConstant") .description("A boolean and its associated id") diff --git a/core/java/com/android/internal/widget/remotecompose/player/RemoteComposePlayer.java b/core/java/com/android/internal/widget/remotecompose/player/RemoteComposePlayer.java index 19b4b36b504c22abb6e8323e0db1996fa8988915..6eb83f1da41035df6b1b05e156062f045643d35a 100644 --- a/core/java/com/android/internal/widget/remotecompose/player/RemoteComposePlayer.java +++ b/core/java/com/android/internal/widget/remotecompose/player/RemoteComposePlayer.java @@ -32,6 +32,7 @@ import android.widget.FrameLayout; import android.widget.HorizontalScrollView; import android.widget.ScrollView; +import com.android.internal.widget.remotecompose.accessibility.RemoteComposeTouchHelper; import com.android.internal.widget.remotecompose.core.CoreDocument; import com.android.internal.widget.remotecompose.core.RemoteContext; import com.android.internal.widget.remotecompose.core.operations.NamedVariable; @@ -60,6 +61,15 @@ public class RemoteComposePlayer extends FrameLayout { init(context, attrs, defStyleAttr); } + /** + * Returns true if the document supports drag touch events + * + * @return true if draggable content, false otherwise + */ + public boolean isDraggable() { + return mInner.isDraggable(); + } + /** * Turn on debug information * @@ -83,8 +93,12 @@ public class RemoteComposePlayer extends FrameLayout { } else { Log.e("RemoteComposePlayer", "Unsupported document "); } + + RemoteComposeTouchHelper.REGISTRAR.setAccessibilityDelegate(this, value.getDocument()); } else { mInner.setDocument(null); + + RemoteComposeTouchHelper.REGISTRAR.clearAccessibilityDelegate(this); } mapColors(); setupSensors(); @@ -96,6 +110,7 @@ public class RemoteComposePlayer extends FrameLayout { provideHapticFeedback(type); } }); + mInner.checkShaders(mShaderControl); } /** @@ -235,22 +250,38 @@ public class RemoteComposePlayer extends FrameLayout { mInner.clearLocalString("SYSTEM:" + name); } - public interface ClickCallbacks { - void click(int id, String metadata); + /** + * This is the number of ops used to calculate the last frame. + * + * @return number of ops + */ + public int getOpsPerFrame() { + return mInner.getDocument().mDocument.getOpsPerFrame(); + } + + /** Id action callback interface */ + public interface IdActionCallbacks { + /** + * Callback for on action + * + * @param id the id of the action + * @param metadata the metadata of the action + */ + void onAction(int id, String metadata); } /** - * Add a callback for handling click events on the document + * Add a callback for handling id actions events on the document * - * @param callback the callback lambda that will be used when a click is detected + * @param callback the callback lambda that will be used when a action is executed *

    The parameter of the callback are: *

      - *
    • id : the id of the clicked area - *
    • metadata: a client provided unstructured string associated with that area + *
    • id : the id of the action + *
    • metadata: a client provided unstructured string associated with that id action *
    */ - public void addClickListener(ClickCallbacks callback) { - mInner.addClickListener((id, metadata) -> callback.click(id, metadata)); + public void addIdActionListener(IdActionCallbacks callback) { + mInner.addIdActionListener((id, metadata) -> callback.onAction(id, metadata)); } /** @@ -669,4 +700,19 @@ public class RemoteComposePlayer extends FrameLayout { public float getEvalTime() { return mInner.getEvalTime(); } + + private CoreDocument.ShaderControl mShaderControl = + (shader) -> { + return false; + }; + + /** + * Sets the controller for shaders. Note set before loading the document. The default is to not + * accept shaders. + * + * @param ctl the controller + */ + public void setShaderControl(CoreDocument.ShaderControl ctl) { + mShaderControl = ctl; + } } diff --git a/core/java/com/android/internal/widget/remotecompose/player/platform/AndroidPaintContext.java b/core/java/com/android/internal/widget/remotecompose/player/platform/AndroidPaintContext.java index bc7d5e108e1d8ff1155b9efb8aae9a9d9b43dd76..0712ea496b577b72f519d17fabacfec70917d059 100644 --- a/core/java/com/android/internal/widget/remotecompose/player/platform/AndroidPaintContext.java +++ b/core/java/com/android/internal/widget/remotecompose/player/platform/AndroidPaintContext.java @@ -250,7 +250,7 @@ public class AndroidPaintContext extends PaintContext { @Override public void getTextBounds(int textId, int start, int end, int flags, @NonNull float[] bounds) { String str = getText(textId); - if (end == -1) { + if (end == -1 || end > str.length()) { end = str.length(); } @@ -505,6 +505,9 @@ public class AndroidPaintContext extends PaintContext { return; } ShaderData data = getShaderData(shaderId); + if (data == null) { + return; + } RuntimeShader shader = new RuntimeShader(getText(data.getShaderTextId())); String[] names = data.getUniformFloatNames(); for (int i = 0; i < names.length; i++) { @@ -757,11 +760,17 @@ public class AndroidPaintContext extends PaintContext { private Path getPath(int id, float start, float end) { AndroidRemoteContext androidContext = (AndroidRemoteContext) mContext; + Path p = (Path) androidContext.mRemoteComposeState.getPath(id); + if (p != null) { + return p; + } Path path = new Path(); float[] pathData = androidContext.mRemoteComposeState.getPathData(id); if (pathData != null) { FloatsToPath.genPath(path, pathData, start, end); + androidContext.mRemoteComposeState.putPath(id, path); } + return path; } diff --git a/core/java/com/android/internal/widget/remotecompose/player/platform/RemoteComposeCanvas.java b/core/java/com/android/internal/widget/remotecompose/player/platform/RemoteComposeCanvas.java index ecfd13aa66b6d8e3e6658e23b85e15cbc0e2e411..c7b1166e113ebb5de02f044a28f30e9e95edd9ec 100644 --- a/core/java/com/android/internal/widget/remotecompose/player/platform/RemoteComposeCanvas.java +++ b/core/java/com/android/internal/widget/remotecompose/player/platform/RemoteComposeCanvas.java @@ -205,19 +205,46 @@ public class RemoteComposeCanvas extends FrameLayout implements View.OnAttachSta return count; } + /** + * set a float externally + * + * @param id + * @param value + */ public void setExternalFloat(int id, float value) { mARContext.loadFloat(id, value); } + /** + * Returns true if the document supports drag touch events + * + * @return true if draggable content, false otherwise + */ + public boolean isDraggable() { + if (mDocument == null) { + return false; + } + return mDocument.getDocument().hasTouchListener(); + } + + /** + * Check shaders and disable them + * + * @param shaderControl the callback to validate the shader + */ + public void checkShaders(CoreDocument.ShaderControl shaderControl) { + mDocument.getDocument().checkShaders(mARContext, shaderControl); + } + public interface ClickCallbacks { void click(int id, String metadata); } - public void addClickListener(ClickCallbacks callback) { + public void addIdActionListener(ClickCallbacks callback) { if (mDocument == null) { return; } - mDocument.getDocument().addClickListener((id, metadata) -> callback.click(id, metadata)); + mDocument.getDocument().addIdActionListener((id, metadata) -> callback.click(id, metadata)); } public int getTheme() { @@ -241,9 +268,9 @@ public class RemoteComposeCanvas extends FrameLayout implements View.OnAttachSta case MotionEvent.ACTION_DOWN: mActionDownPoint.x = (int) event.getX(); mActionDownPoint.y = (int) event.getY(); - mInActionDown = true; CoreDocument doc = mDocument.getDocument(); if (doc.hasTouchListener()) { + mInActionDown = true; if (mVelocityTracker == null) { mVelocityTracker = VelocityTracker.obtain(); } else { @@ -251,8 +278,10 @@ public class RemoteComposeCanvas extends FrameLayout implements View.OnAttachSta } mVelocityTracker.addMovement(event); doc.touchDown(mARContext, event.getX(), event.getY()); + invalidate(); + return true; } - return true; + return false; case MotionEvent.ACTION_CANCEL: mInActionDown = false; @@ -262,8 +291,11 @@ public class RemoteComposeCanvas extends FrameLayout implements View.OnAttachSta float dx = mVelocityTracker.getXVelocity(pointerId); float dy = mVelocityTracker.getYVelocity(pointerId); doc.touchCancel(mARContext, event.getX(), event.getY(), dx, dy); + invalidate(); + return true; } - return true; + return false; + case MotionEvent.ACTION_UP: mInActionDown = false; performClick(); @@ -273,8 +305,10 @@ public class RemoteComposeCanvas extends FrameLayout implements View.OnAttachSta float dx = mVelocityTracker.getXVelocity(pointerId); float dy = mVelocityTracker.getYVelocity(pointerId); doc.touchUp(mARContext, event.getX(), event.getY(), dx, dy); + invalidate(); + return true; } - return true; + return false; case MotionEvent.ACTION_MOVE: if (mInActionDown) { @@ -286,7 +320,9 @@ public class RemoteComposeCanvas extends FrameLayout implements View.OnAttachSta invalidate(); } } + return true; } + return false; } return false; } diff --git a/core/jni/Android.bp b/core/jni/Android.bp index e22d9587093ba46fe7e2c379752f504af473dbf4..027113a75f6b6fd04da72c534424f666a8c809a1 100644 --- a/core/jni/Android.bp +++ b/core/jni/Android.bp @@ -220,6 +220,7 @@ cc_library_shared_for_libandroid_runtime { "android_hardware_camera2_utils_SurfaceUtils.cpp", "android_hardware_display_DisplayManagerGlobal.cpp", "android_hardware_display_DisplayViewport.cpp", + "android_hardware_display_DisplayTopology.cpp", "android_hardware_HardwareBuffer.cpp", "android_hardware_OverlayProperties.cpp", "android_hardware_SensorManager.cpp", @@ -262,6 +263,7 @@ cc_library_shared_for_libandroid_runtime { "com_android_internal_os_ZygoteCommandBuffer.cpp", "com_android_internal_os_ZygoteInit.cpp", "com_android_internal_security_VerityUtils.cpp", + "com_android_internal_util_ArrayUtils.cpp", "hwbinder/EphemeralStorage.cpp", "fd_utils.cpp", "android_hardware_input_InputWindowHandle.cpp", @@ -279,6 +281,7 @@ cc_library_shared_for_libandroid_runtime { "libasync_safe", "libbinderthreadstateutils", "libdmabufinfo", + "libgenfslabelsversion.ffi", "libgui_window_info_static", "libkernelconfigs", "libnativehelper_lazy", diff --git a/core/jni/AndroidRuntime.cpp b/core/jni/AndroidRuntime.cpp index ac187b08f0f12e2a5f83582eb3e55db1ab401408..78d69f0714e087203822a59f28174d5ca8bdc95f 100644 --- a/core/jni/AndroidRuntime.cpp +++ b/core/jni/AndroidRuntime.cpp @@ -220,6 +220,7 @@ extern int register_com_android_internal_os_Zygote(JNIEnv *env); extern int register_com_android_internal_os_ZygoteCommandBuffer(JNIEnv *env); extern int register_com_android_internal_os_ZygoteInit(JNIEnv *env); extern int register_com_android_internal_security_VerityUtils(JNIEnv* env); +extern int register_com_android_internal_util_ArrayUtils(JNIEnv* env); extern int register_com_android_internal_util_VirtualRefBasePtr(JNIEnv *env); extern int register_android_window_WindowInfosListener(JNIEnv* env); extern int register_android_window_ScreenCapture(JNIEnv* env); @@ -1621,6 +1622,7 @@ static const RegJNIRec gRegJNI[] = { REG_JNI(register_com_android_internal_os_ZygoteCommandBuffer), REG_JNI(register_com_android_internal_os_ZygoteInit), REG_JNI(register_com_android_internal_security_VerityUtils), + REG_JNI(register_com_android_internal_util_ArrayUtils), REG_JNI(register_com_android_internal_util_VirtualRefBasePtr), REG_JNI(register_android_hardware_Camera), REG_JNI(register_android_hardware_camera2_CameraMetadata), diff --git a/core/jni/android_app_PropertyInvalidatedCache.cpp b/core/jni/android_app_PropertyInvalidatedCache.cpp index ead66660a0a4626d62380272dd840c7a4e20716a..12585d5f8137a05326419d22ef6844be0c1dabcd 100644 --- a/core/jni/android_app_PropertyInvalidatedCache.cpp +++ b/core/jni/android_app_PropertyInvalidatedCache.cpp @@ -28,24 +28,77 @@ #include "core_jni_helpers.h" #include "android_app_PropertyInvalidatedCache.h" +namespace android::app::PropertyInvalidatedCache { + +// These provide run-time access to the sizing parameters. +int NonceStore::getMaxNonce() const { + return kMaxNonce; +} + +size_t NonceStore::getMaxByte() const { + return kMaxByte; +} + +// Fetch a nonce, returning UNSET if the index is out of range. This method specifically +// does not throw or generate an error if the index is out of range; this allows the method +// to be called in a CriticalNative JNI API. +int64_t NonceStore::getNonce(int index) const { + if (index < 0 || index >= kMaxNonce) { + return UNSET; + } else { + return nonce()[index]; + } +} + +// Set a nonce and return true. Return false if the index is out of range. This method +// specifically does not throw or generate an error if the index is out of range; this +// allows the method to be called in a CriticalNative JNI API. +bool NonceStore::setNonce(int index, int64_t value) { + if (index < 0 || index >= kMaxNonce) { + return false; + } else { + nonce()[index] = value; + return true; + } +} + +// Fetch just the byte-block hash +int32_t NonceStore::getHash() const { + return mByteHash; +} + +// Copy the byte block to the target and return the current hash. +int32_t NonceStore::getByteBlock(block_t* block, size_t len) const { + memcpy(block, (void*) byteBlock(), std::min(kMaxByte, len)); + return mByteHash; +} + +// Set the byte block and the hash. +void NonceStore::setByteBlock(int hash, const block_t* block, size_t len) { + memcpy((void*) byteBlock(), block, len = std::min(kMaxByte, len)); + mByteHash = hash; +} + +} // namespace android::app::PropertyInvalidatedCache; + namespace { using namespace android::app::PropertyInvalidatedCache; // Convert a jlong to a nonce block. This is a convenience function that should be inlined by // the compiler. -inline SystemCacheNonce* sysCache(jlong ptr) { - return reinterpret_cast(ptr); +inline NonceStore* nonceCache(jlong ptr) { + return reinterpret_cast(ptr); } // Return the number of nonces in the nonce block. jint getMaxNonce(JNIEnv*, jclass, jlong ptr) { - return sysCache(ptr)->getMaxNonce(); + return nonceCache(ptr)->getMaxNonce(); } // Return the number of string bytes in the nonce block. jint getMaxByte(JNIEnv*, jclass, jlong ptr) { - return sysCache(ptr)->getMaxByte(); + return nonceCache(ptr)->getMaxByte(); } // Set the byte block. The first int is the hash to set and the second is the array to copy. @@ -56,25 +109,25 @@ void setByteBlock(JNIEnv* env, jclass, jlong ptr, jint hash, jbyteArray val) { jniThrowExceptionFmt(env, "java/lang/IllegalArgumentException", "null byte block"); return; } - sysCache(ptr)->setByteBlock(hash, value.get(), value.size()); + nonceCache(ptr)->setByteBlock(hash, value.get(), value.size()); } // Fetch the byte block. If the incoming hash is the same as the local hash, the Java layer is // presumed to have an up-to-date copy of the byte block; do not copy byte array. The local // hash is returned. jint getByteBlock(JNIEnv* env, jclass, jlong ptr, jint hash, jbyteArray val) { - if (sysCache(ptr)->getHash() == hash) { + if (nonceCache(ptr)->getHash() == hash) { return hash; } ScopedByteArrayRW value(env, val); - return sysCache(ptr)->getByteBlock(value.get(), value.size()); + return nonceCache(ptr)->getByteBlock(value.get(), value.size()); } // Fetch the byte block hash. // // This is a CriticalNative method and therefore does not get the JNIEnv or jclass parameters. jint getByteBlockHash(jlong ptr) { - return sysCache(ptr)->getHash(); + return nonceCache(ptr)->getHash(); } // Get a nonce value. So that this method can be CriticalNative, it returns 0 if the value is @@ -83,7 +136,7 @@ jint getByteBlockHash(jlong ptr) { // // This method is @CriticalNative and does not take a JNIEnv* or jclass argument. jlong getNonce(jlong ptr, jint index) { - return sysCache(ptr)->getNonce(index); + return nonceCache(ptr)->getNonce(index); } // Set a nonce value. So that this method can be CriticalNative, it returns a boolean: false if @@ -92,7 +145,7 @@ jlong getNonce(jlong ptr, jint index) { // // This method is @CriticalNative and does not take a JNIEnv* or jclass argument. jboolean setNonce(jlong ptr, jint index, jlong value) { - return sysCache(ptr)->setNonce(index, value); + return nonceCache(ptr)->setNonce(index, value); } static const JNINativeMethod gMethods[] = { diff --git a/core/jni/android_app_PropertyInvalidatedCache.h b/core/jni/android_app_PropertyInvalidatedCache.h index eefa8fa886248ff6de0e7f51e56fd561b8876f4b..00aa281b572ffe0eed237dda9565c675c126fa73 100644 --- a/core/jni/android_app_PropertyInvalidatedCache.h +++ b/core/jni/android_app_PropertyInvalidatedCache.h @@ -18,129 +18,139 @@ #include #include +#include -namespace android { -namespace app { -namespace PropertyInvalidatedCache { +namespace android::app::PropertyInvalidatedCache { /** - * A cache nonce block contains an array of std::atomic and an array of bytes. The - * byte array has an associated hash. This class provides methods to read and write the fields - * of the block but it does not interpret the fields. - * - * On initialization, all fields are set to zero. - * - * In general, methods do not report errors. This allows the methods to be used in - * CriticalNative JNI APIs. - * - * The template is parameterized by the number of nonces it supports and the number of bytes in - * the string block. + * A head of a CacheNonce object. This contains all the fields that have a fixed size and + * location. Fields with a variable location are found via offsets. The offsets make this + * object position-independent, which is required because it is in shared memory and would be + * mapped into different virtual addresses for different processes. */ -template class CacheNonce { - - // The value of an unset field. - static const int UNSET = 0; - +class NonceStore { + protected: // A convenient typedef. The jbyteArray element type is jbyte, which the compiler treats as // signed char. typedef signed char block_t; - // The array of nonces - volatile std::atomic mNonce[maxNonce]; + // The nonce type. + typedef std::atomic nonce_t; - // The byte array. This is not atomic but it is guarded by the mByteHash. - volatile block_t mByteBlock[maxByte]; + // Atomics should be safe to use across processes if they are lock free. + static_assert(nonce_t::is_always_lock_free == true); - // The hash that validates the byte block - volatile std::atomic mByteHash; + // The value of an unset field. + static constexpr int UNSET = 0; - // Pad the class to a multiple of 8 bytes. - int32_t _pad; + // The size of the nonce array. + const int32_t kMaxNonce; - public: + // The size of the byte array. + const size_t kMaxByte; - // The expected size of this instance. This is a compile-time constant and can be used in a - // static assertion. - static const int expectedSize = - maxNonce * sizeof(std::atomic) - + sizeof(std::atomic) - + maxByte * sizeof(block_t) - + sizeof(int32_t); + // The offset to the nonce array. + const size_t mNonceOffset; - // These provide run-time access to the sizing parameters. - int getMaxNonce() const { - return maxNonce; - } + // The offset to the byte array. + const size_t mByteOffset; - size_t getMaxByte() const { - return maxByte; - } + // The byte block hash. This is fixed and at a known offset, so leave it in the base class. + volatile std::atomic mByteHash; - // Construct and initialize the memory. - CacheNonce() { - for (int i = 0; i < maxNonce; i++) { - mNonce[i] = UNSET; - } - mByteHash = UNSET; - memset((void*) mByteBlock, UNSET, sizeof(mByteBlock)); + // The constructor is protected! It only makes sense when called from a subclass. + NonceStore(int kMaxNonce, size_t kMaxByte, volatile nonce_t* nonce, volatile block_t* block) : + kMaxNonce(kMaxNonce), + kMaxByte(kMaxByte), + mNonceOffset(offset(this, const_cast(nonce))), + mByteOffset(offset(this, const_cast(block))) { } + public: + + // These provide run-time access to the sizing parameters. + int getMaxNonce() const; + size_t getMaxByte() const; + // Fetch a nonce, returning UNSET if the index is out of range. This method specifically // does not throw or generate an error if the index is out of range; this allows the method // to be called in a CriticalNative JNI API. - int64_t getNonce(int index) const { - if (index < 0 || index >= maxNonce) { - return UNSET; - } else { - return mNonce[index]; - } - } + int64_t getNonce(int index) const; // Set a nonce and return true. Return false if the index is out of range. This method // specifically does not throw or generate an error if the index is out of range; this // allows the method to be called in a CriticalNative JNI API. - bool setNonce(int index, int64_t value) { - if (index < 0 || index >= maxNonce) { - return false; - } else { - mNonce[index] = value; - return true; - } - } + bool setNonce(int index, int64_t value); // Fetch just the byte-block hash - int32_t getHash() const { - return mByteHash; - } + int32_t getHash() const; // Copy the byte block to the target and return the current hash. - int32_t getByteBlock(block_t* block, size_t len) const { - memcpy(block, (void*) mByteBlock, std::min(maxByte, len)); - return mByteHash; - } + int32_t getByteBlock(block_t* block, size_t len) const; // Set the byte block and the hash. - void setByteBlock(int hash, const block_t* block, size_t len) { - memcpy((void*) mByteBlock, block, len = std::min(maxByte, len)); - mByteHash = hash; + void setByteBlock(int hash, const block_t* block, size_t len); + + private: + + // A convenience function to compute the offset between two unlike pointers. + static size_t offset(void const* base, void const* member) { + return reinterpret_cast(member) - reinterpret_cast(base); + } + + // Return the address of the nonce array. + volatile nonce_t* nonce() const { + // The array is located at an offset from . + return reinterpret_cast( + reinterpret_cast(this) + mNonceOffset); + } + + // Return the address of the byte block array. + volatile block_t* byteBlock() const { + // The array is located at an offset from . + return reinterpret_cast( + reinterpret_cast(this) + mByteOffset); } }; /** - * Sizing parameters for the system_server PropertyInvalidatedCache support. A client can - * retrieve the values through the accessors in CacheNonce instances. + * A cache nonce block contains an array of std::atomic and an array of bytes. The + * byte array has an associated hash. This class provides methods to read and write the fields + * of the block but it does not interpret the fields. + * + * On initialization, all fields are set to zero. + * + * In general, methods do not report errors. This allows the methods to be used in + * CriticalNative JNI APIs. + * + * The template is parameterized by the number of nonces it supports and the number of bytes in + * the string block. */ -static const int MAX_NONCE = 64; -static const int BYTE_BLOCK_SIZE = 8192; +template class CacheNonce : public NonceStore { + + // The array of nonces + volatile nonce_t mNonce[maxNonce]; -// The CacheNonce for system server holds 64 nonces with a string block of 8192 bytes. -typedef CacheNonce SystemCacheNonce; + // The byte array. This is not atomic but it is guarded by the mByteHash. + volatile block_t mByteBlock[maxByte]; + + public: + // Construct and initialize the memory. + CacheNonce() : + NonceStore(maxNonce, maxByte, &mNonce[0], &mByteBlock[0]) + { + for (int i = 0; i < maxNonce; i++) { + mNonce[i] = UNSET; + } + mByteHash = UNSET; + memset((void*) mByteBlock, UNSET, sizeof(mByteBlock)); + } +}; -// The goal of this assertion is to ensure that the data structure is the same size across 32-bit -// and 64-bit systems. -static_assert(sizeof(SystemCacheNonce) == SystemCacheNonce::expectedSize, - "Unexpected SystemCacheNonce size"); +// The CacheNonce for system server holds 64 nonces with a string block of 8192 bytes. This is +// more than enough for system_server PropertyInvalidatedCache support. The configuration +// values are not defined as visible constants. Clients should use the accessors on the +// SystemCacheNonce instance if they need the sizing parameters. +typedef CacheNonce SystemCacheNonce; -} // namespace PropertyInvalidatedCache -} // namespace app -} // namespace android +} // namespace android.app.PropertyInvalidatedCache diff --git a/core/jni/android_database_SQLiteRawStatement.cpp b/core/jni/android_database_SQLiteRawStatement.cpp index 85a6bdf959280d1bcc09e63cbf90471b86e57994..32c2ef73a5b12d60f7e7bf1fc73a8e8b9e5ac0fe 100644 --- a/core/jni/android_database_SQLiteRawStatement.cpp +++ b/core/jni/android_database_SQLiteRawStatement.cpp @@ -70,12 +70,32 @@ static void throwInvalidParameter(JNIEnv *env, jlong stmtPtr, jint index) { } } +// If the last operation failed, throw an exception and return true. Otherwise return false. +static bool throwIfError(JNIEnv *env, jlong stmtPtr) { + switch (sqlite3_errcode(db(stmtPtr))) { + case SQLITE_OK: + case SQLITE_DONE: + case SQLITE_ROW: return false; + } + throw_sqlite3_exception(env, db(stmtPtr), nullptr); + return true; +} -// This throws a SQLiteBindOrColumnIndexOutOfRangeException if the column index is out -// of bounds. It returns true if an exception was thrown. +// This throws a SQLiteBindOrColumnIndexOutOfRangeException if the column index is out of +// bounds. It throws SQLiteMisuseException if the statement's column count is zero; that +// generally occurs because the client has forgotten to call step() or the client has stepped +// past the end of the query. The function returns true if an exception was thrown. static bool throwIfInvalidColumn(JNIEnv *env, jlong stmtPtr, jint col) { - if (col < 0 || col >= sqlite3_data_count(stmt(stmtPtr))) { - int count = sqlite3_data_count(stmt(stmtPtr)); + int count = sqlite3_data_count(stmt(stmtPtr)); + if (throwIfError(env, stmtPtr)) { + return true; + } else if (count == 0) { + // A count of zero indicates a misuse: the statement has never been step()'ed. + const char* message = "row has no data"; + const char* errmsg = sqlite3_errstr(SQLITE_MISUSE); + throw_sqlite3_exception(env, SQLITE_MISUSE, errmsg, message); + return true; + } else if (col < 0 || col >= count) { std::string message = android::base::StringPrintf( "column index %d out of bounds [0,%d]", col, count - 1); char const * errmsg = sqlite3_errstr(SQLITE_RANGE); @@ -86,17 +106,6 @@ static bool throwIfInvalidColumn(JNIEnv *env, jlong stmtPtr, jint col) { } } -// If the last operation failed, throw an exception and return true. Otherwise return false. -static bool throwIfError(JNIEnv *env, jlong stmtPtr) { - switch (sqlite3_errcode(db(stmtPtr))) { - case SQLITE_OK: - case SQLITE_DONE: - case SQLITE_ROW: return false; - } - throw_sqlite3_exception(env, db(stmtPtr), nullptr); - return true; -} - static jint bindParameterCount(JNIEnv* env, jclass, jlong stmtPtr) { return sqlite3_bind_parameter_count(stmt(stmtPtr)); } diff --git a/core/jni/android_hardware_display_DisplayTopology.cpp b/core/jni/android_hardware_display_DisplayTopology.cpp new file mode 100644 index 0000000000000000000000000000000000000000..d9e802de81e0be6ff4844cc8f4920ed3ecf6907a --- /dev/null +++ b/core/jni/android_hardware_display_DisplayTopology.cpp @@ -0,0 +1,155 @@ +/* + * Copyright 2024 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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 "DisplayTopology-JNI" + +#include +#include +#include + +#include "jni_wrappers.h" + +namespace android { + +// ---------------------------------------------------------------------------- + +static struct { + jclass clazz; + jfieldID primaryDisplayId; + jfieldID displayNodes; +} gDisplayTopologyGraphClassInfo; + +static struct { + jclass clazz; + jfieldID displayId; + jfieldID adjacentDisplays; +} gDisplayTopologyGraphNodeClassInfo; + +static struct { + jclass clazz; + jfieldID displayId; + jfieldID position; + jfieldID offsetPx; +} gDisplayTopologyGraphAdjacentDisplayClassInfo; + +// ---------------------------------------------------------------------------- + +status_t android_hardware_display_DisplayTopologyAdjacentDisplay_toNative( + JNIEnv* env, jobject adjacentDisplayObj, DisplayTopologyAdjacentDisplay* adjacentDisplay) { + adjacentDisplay->displayId = ui::LogicalDisplayId{ + env->GetIntField(adjacentDisplayObj, + gDisplayTopologyGraphAdjacentDisplayClassInfo.displayId)}; + adjacentDisplay->position = static_cast( + env->GetIntField(adjacentDisplayObj, + gDisplayTopologyGraphAdjacentDisplayClassInfo.position)); + adjacentDisplay->offsetPx = + env->GetFloatField(adjacentDisplayObj, + gDisplayTopologyGraphAdjacentDisplayClassInfo.offsetPx); + return OK; +} + +status_t android_hardware_display_DisplayTopologyGraphNode_toNative( + JNIEnv* env, jobject nodeObj, + std::unordered_map>& + graph) { + ui::LogicalDisplayId displayId = ui::LogicalDisplayId{ + env->GetIntField(nodeObj, gDisplayTopologyGraphNodeClassInfo.displayId)}; + + jobjectArray adjacentDisplaysArray = static_cast( + env->GetObjectField(nodeObj, gDisplayTopologyGraphNodeClassInfo.adjacentDisplays)); + + if (adjacentDisplaysArray) { + jsize length = env->GetArrayLength(adjacentDisplaysArray); + for (jsize i = 0; i < length; i++) { + ScopedLocalRef + adjacentDisplayObj(env, env->GetObjectArrayElement(adjacentDisplaysArray, i)); + if (NULL != adjacentDisplayObj.get()) { + break; // found null element indicating end of used portion of the array + } + + DisplayTopologyAdjacentDisplay adjacentDisplay; + android_hardware_display_DisplayTopologyAdjacentDisplay_toNative(env, + adjacentDisplayObj + .get(), + &adjacentDisplay); + graph[displayId].push_back(adjacentDisplay); + } + } + return OK; +} + +DisplayTopologyGraph android_hardware_display_DisplayTopologyGraph_toNative(JNIEnv* env, + jobject topologyObj) { + DisplayTopologyGraph topology; + topology.primaryDisplayId = ui::LogicalDisplayId{ + env->GetIntField(topologyObj, gDisplayTopologyGraphClassInfo.primaryDisplayId)}; + + jobjectArray nodesArray = static_cast( + env->GetObjectField(topologyObj, gDisplayTopologyGraphClassInfo.displayNodes)); + + if (nodesArray) { + jsize length = env->GetArrayLength(nodesArray); + for (jsize i = 0; i < length; i++) { + ScopedLocalRef nodeObj(env, env->GetObjectArrayElement(nodesArray, i)); + if (NULL != nodeObj.get()) { + break; // found null element indicating end of used portion of the array + } + + android_hardware_display_DisplayTopologyGraphNode_toNative(env, nodeObj.get(), + topology.graph); + } + } + return topology; +} + +// ---------------------------------------------------------------------------- + +int register_android_hardware_display_DisplayTopology(JNIEnv* env) { + jclass graphClazz = FindClassOrDie(env, "android/hardware/display/DisplayTopologyGraph"); + gDisplayTopologyGraphClassInfo.clazz = MakeGlobalRefOrDie(env, graphClazz); + + gDisplayTopologyGraphClassInfo.primaryDisplayId = + GetFieldIDOrDie(env, gDisplayTopologyGraphClassInfo.clazz, "primaryDisplayId", "I"); + gDisplayTopologyGraphClassInfo.displayNodes = + GetFieldIDOrDie(env, gDisplayTopologyGraphClassInfo.clazz, "displayNodes", + "[Landroid/hardware/display/DisplayTopologyGraph$DisplayNode;"); + + jclass displayNodeClazz = + FindClassOrDie(env, "android/hardware/display/DisplayTopologyGraph$DisplayNode"); + gDisplayTopologyGraphNodeClassInfo.clazz = MakeGlobalRefOrDie(env, displayNodeClazz); + gDisplayTopologyGraphNodeClassInfo.displayId = + GetFieldIDOrDie(env, gDisplayTopologyGraphNodeClassInfo.clazz, "displayId", "I"); + gDisplayTopologyGraphNodeClassInfo.adjacentDisplays = + GetFieldIDOrDie(env, gDisplayTopologyGraphNodeClassInfo.clazz, "adjacentDisplays", + "[Landroid/hardware/display/DisplayTopologyGraph$AdjacentDisplay;"); + + jclass adjacentDisplayClazz = + FindClassOrDie(env, "android/hardware/display/DisplayTopologyGraph$AdjacentDisplay"); + gDisplayTopologyGraphAdjacentDisplayClassInfo.clazz = + MakeGlobalRefOrDie(env, adjacentDisplayClazz); + gDisplayTopologyGraphAdjacentDisplayClassInfo.displayId = + GetFieldIDOrDie(env, gDisplayTopologyGraphAdjacentDisplayClassInfo.clazz, "displayId", + "I"); + gDisplayTopologyGraphAdjacentDisplayClassInfo.position = + GetFieldIDOrDie(env, gDisplayTopologyGraphAdjacentDisplayClassInfo.clazz, "position", + "I"); + gDisplayTopologyGraphAdjacentDisplayClassInfo.offsetPx = + GetFieldIDOrDie(env, gDisplayTopologyGraphAdjacentDisplayClassInfo.clazz, "offsetPx", + "F"); + return 0; +} + +} // namespace android diff --git a/core/jni/android_hardware_display_DisplayTopology.h b/core/jni/android_hardware_display_DisplayTopology.h new file mode 100644 index 0000000000000000000000000000000000000000..390191f827d8cb6dfe595d360112c662c825e29f --- /dev/null +++ b/core/jni/android_hardware_display_DisplayTopology.h @@ -0,0 +1,32 @@ +/* + * Copyright 2024 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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 + +#include "jni.h" + +namespace android { + +/** + * Copies the contents of a DVM DisplayTopology object to a new native DisplayTopology instance. + * Returns DisplayTopology. + */ +extern DisplayTopologyGraph android_hardware_display_DisplayTopologyGraph_toNative( + JNIEnv* env, jobject eventObj); + +} // namespace android diff --git a/core/jni/android_media_AudioFormat.h b/core/jni/android_media_AudioFormat.h index 704aef3cd131381e67b7d6ad201690944e951fb3..4ba1ae9d670d663fca56bef9e530fa85998f5ca6 100644 --- a/core/jni/android_media_AudioFormat.h +++ b/core/jni/android_media_AudioFormat.h @@ -51,6 +51,18 @@ #define ENCODING_DTS_UHD_P2 30 #define ENCODING_DSD 31 #define ENCODING_AC4_L4 32 +#define ENCODING_IAMF_SIMPLE_PROFILE_OPUS 33 +#define ENCODING_IAMF_SIMPLE_PROFILE_AAC 34 +#define ENCODING_IAMF_SIMPLE_PROFILE_FLAC 35 +#define ENCODING_IAMF_SIMPLE_PROFILE_PCM 36 +#define ENCODING_IAMF_BASE_PROFILE_OPUS 37 +#define ENCODING_IAMF_BASE_PROFILE_AAC 38 +#define ENCODING_IAMF_BASE_PROFILE_FLAC 39 +#define ENCODING_IAMF_BASE_PROFILE_PCM 40 +#define ENCODING_IAMF_BASE_ENHANCED_PROFILE_OPUS 41 +#define ENCODING_IAMF_BASE_ENHANCED_PROFILE_AAC 42 +#define ENCODING_IAMF_BASE_ENHANCED_PROFILE_FLAC 43 +#define ENCODING_IAMF_BASE_ENHANCED_PROFILE_PCM 44 #define ENCODING_INVALID 0 #define ENCODING_DEFAULT 1 @@ -128,6 +140,30 @@ static inline audio_format_t audioFormatToNative(int audioFormat) return AUDIO_FORMAT_DTS_UHD_P2; case ENCODING_DSD: return AUDIO_FORMAT_DSD; + case ENCODING_IAMF_SIMPLE_PROFILE_OPUS: + return AUDIO_FORMAT_IAMF_SIMPLE_OPUS; + case ENCODING_IAMF_SIMPLE_PROFILE_AAC: + return AUDIO_FORMAT_IAMF_SIMPLE_AAC; + case ENCODING_IAMF_SIMPLE_PROFILE_FLAC: + return AUDIO_FORMAT_IAMF_SIMPLE_FLAC; + case ENCODING_IAMF_SIMPLE_PROFILE_PCM: + return AUDIO_FORMAT_IAMF_SIMPLE_PCM; + case ENCODING_IAMF_BASE_PROFILE_OPUS: + return AUDIO_FORMAT_IAMF_BASE_OPUS; + case ENCODING_IAMF_BASE_PROFILE_AAC: + return AUDIO_FORMAT_IAMF_BASE_AAC; + case ENCODING_IAMF_BASE_PROFILE_FLAC: + return AUDIO_FORMAT_IAMF_BASE_FLAC; + case ENCODING_IAMF_BASE_PROFILE_PCM: + return AUDIO_FORMAT_IAMF_BASE_PCM; + case ENCODING_IAMF_BASE_ENHANCED_PROFILE_OPUS: + return AUDIO_FORMAT_IAMF_BASE_ENHANCED_OPUS; + case ENCODING_IAMF_BASE_ENHANCED_PROFILE_AAC: + return AUDIO_FORMAT_IAMF_BASE_ENHANCED_AAC; + case ENCODING_IAMF_BASE_ENHANCED_PROFILE_FLAC: + return AUDIO_FORMAT_IAMF_BASE_ENHANCED_FLAC; + case ENCODING_IAMF_BASE_ENHANCED_PROFILE_PCM: + return AUDIO_FORMAT_IAMF_BASE_ENHANCED_PCM; default: return AUDIO_FORMAT_INVALID; } @@ -211,6 +247,30 @@ static inline int audioFormatFromNative(audio_format_t nativeFormat) return ENCODING_DEFAULT; case AUDIO_FORMAT_DSD: return ENCODING_DSD; + case AUDIO_FORMAT_IAMF_SIMPLE_OPUS: + return ENCODING_IAMF_SIMPLE_PROFILE_OPUS; + case AUDIO_FORMAT_IAMF_SIMPLE_AAC: + return ENCODING_IAMF_SIMPLE_PROFILE_AAC; + case AUDIO_FORMAT_IAMF_SIMPLE_FLAC: + return ENCODING_IAMF_SIMPLE_PROFILE_FLAC; + case AUDIO_FORMAT_IAMF_SIMPLE_PCM: + return ENCODING_IAMF_SIMPLE_PROFILE_PCM; + case AUDIO_FORMAT_IAMF_BASE_OPUS: + return ENCODING_IAMF_BASE_PROFILE_OPUS; + case AUDIO_FORMAT_IAMF_BASE_AAC: + return ENCODING_IAMF_BASE_PROFILE_AAC; + case AUDIO_FORMAT_IAMF_BASE_FLAC: + return ENCODING_IAMF_BASE_PROFILE_FLAC; + case AUDIO_FORMAT_IAMF_BASE_PCM: + return ENCODING_IAMF_BASE_PROFILE_PCM; + case AUDIO_FORMAT_IAMF_BASE_ENHANCED_OPUS: + return ENCODING_IAMF_BASE_ENHANCED_PROFILE_OPUS; + case AUDIO_FORMAT_IAMF_BASE_ENHANCED_AAC: + return ENCODING_IAMF_BASE_ENHANCED_PROFILE_AAC; + case AUDIO_FORMAT_IAMF_BASE_ENHANCED_FLAC: + return ENCODING_IAMF_BASE_ENHANCED_PROFILE_FLAC; + case AUDIO_FORMAT_IAMF_BASE_ENHANCED_PCM: + return ENCODING_IAMF_BASE_ENHANCED_PROFILE_PCM; default: return ENCODING_INVALID; } diff --git a/core/jni/android_os_SELinux.cpp b/core/jni/android_os_SELinux.cpp index 7a4670f4e49da5e7aa17e9993ff6478a12dff6e3..cd39e6f93fb42fe2b6157f81b6a89ecc042bb4cf 100644 --- a/core/jni/android_os_SELinux.cpp +++ b/core/jni/android_os_SELinux.cpp @@ -18,38 +18,43 @@ #include #include - +#include +#include +#include +#include #include -#include -#include "jni.h" +#include +#include + #include "core_jni_helpers.h" -#include "selinux/selinux.h" +#include "jni.h" #include "selinux/android.h" -#include -#include -#include -#include +#include "selinux/selinux.h" namespace android { namespace { -std::atomic sehandle{nullptr}; +std::atomic file_sehandle{nullptr}; -selabel_handle* GetSELabelHandle() { - selabel_handle* h = sehandle.load(); +selabel_handle *GetSELabelHandle_impl(selabel_handle *(*handle_func)(), + std::atomic *handle_cache) { + selabel_handle *h = handle_cache->load(); if (h != nullptr) { return h; } - h = selinux_android_file_context_handle(); + h = handle_func(); selabel_handle* expected = nullptr; - if (!sehandle.compare_exchange_strong(expected, h)) { + if (!handle_cache->compare_exchange_strong(expected, h)) { selabel_close(h); - return sehandle.load(); + return handle_cache->load(); } return h; } +selabel_handle *GetSELabelFileBackendHandle() { + return GetSELabelHandle_impl(selinux_android_file_context_handle, &file_sehandle); +} } struct SecurityContext_Delete { @@ -105,7 +110,7 @@ static jstring fileSelabelLookup(JNIEnv* env, jobject, jstring pathStr) { return NULL; } - auto* selabel_handle = GetSELabelHandle(); + auto *selabel_handle = GetSELabelFileBackendHandle(); if (selabel_handle == NULL) { ALOGE("fileSelabelLookup => Failed to get SEHandle"); return NULL; @@ -403,9 +408,20 @@ static jboolean native_restorecon(JNIEnv *env, jobject, jstring pathnameStr, jin return (ret == 0); } +/* + * Function: getGenfsLabelsVersion + * Purpose: get which genfs labels version /vendor uses + * Returns: int: genfs labels version of /vendor + * Exceptions: none + */ +static jint getGenfsLabelsVersion(JNIEnv *, jclass) { + return get_genfs_labels_version(); +} + /* * JNI registration. */ +// clang-format off static const JNINativeMethod method_table[] = { /* name, signature, funcPtr */ { "checkSELinuxAccess" , "(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)Z" , (void*)checkSELinuxAccess }, @@ -420,7 +436,9 @@ static const JNINativeMethod method_table[] = { { "setFileContext" , "(Ljava/lang/String;Ljava/lang/String;)Z" , (void*)setFileCon }, { "setFSCreateContext" , "(Ljava/lang/String;)Z" , (void*)setFSCreateCon }, { "fileSelabelLookup" , "(Ljava/lang/String;)Ljava/lang/String;" , (void*)fileSelabelLookup}, + { "getGenfsLabelsVersion" , "()I" , (void *)getGenfsLabelsVersion}, }; +// clang-format on static int log_callback(int type, const char *fmt, ...) { va_list ap; diff --git a/core/jni/android_view_DisplayEventReceiver.cpp b/core/jni/android_view_DisplayEventReceiver.cpp index a09c405de1cd9f78e1fa847454d4ca261db4f863..7ff1f8c4a748bf54841d3cb7c4ea6f43460c0041 100644 --- a/core/jni/android_view_DisplayEventReceiver.cpp +++ b/core/jni/android_view_DisplayEventReceiver.cpp @@ -40,6 +40,7 @@ static struct { jmethodID dispatchHotplug; jmethodID dispatchHotplugConnectionError; jmethodID dispatchModeChanged; + jmethodID dispatchModeRejected; jmethodID dispatchFrameRateOverrides; jmethodID dispatchHdcpLevelsChanged; @@ -95,6 +96,7 @@ private: void dispatchHotplugConnectionError(nsecs_t timestamp, int errorCode) override; void dispatchModeChanged(nsecs_t timestamp, PhysicalDisplayId displayId, int32_t modeId, nsecs_t renderPeriod) override; + void dispatchModeRejected(PhysicalDisplayId displayId, int32_t modeId) override; void dispatchFrameRateOverrides(nsecs_t timestamp, PhysicalDisplayId displayId, std::vector overrides) override; void dispatchNullEvent(nsecs_t timestamp, PhysicalDisplayId displayId) override {} @@ -271,6 +273,18 @@ void NativeDisplayEventReceiver::dispatchModeChanged(nsecs_t timestamp, Physical mMessageQueue->raiseAndClearException(env, "dispatchModeChanged"); } +void NativeDisplayEventReceiver::dispatchModeRejected(PhysicalDisplayId displayId, int32_t modeId) { + JNIEnv* env = AndroidRuntime::getJNIEnv(); + + ScopedLocalRef receiverObj(env, GetReferent(env, mReceiverWeakGlobal)); + if (receiverObj.get()) { + ALOGV("receiver %p ~ Invoking Mode Rejected handler.", this); + env->CallVoidMethod(receiverObj.get(), gDisplayEventReceiverClassInfo.dispatchModeRejected, + displayId.value, modeId); + ALOGV("receiver %p ~ Returned from Mode Rejected handler.", this); + } +} + void NativeDisplayEventReceiver::dispatchFrameRateOverrides( nsecs_t timestamp, PhysicalDisplayId displayId, std::vector overrides) { JNIEnv* env = AndroidRuntime::getJNIEnv(); @@ -405,6 +419,9 @@ int register_android_view_DisplayEventReceiver(JNIEnv* env) { gDisplayEventReceiverClassInfo.dispatchModeChanged = GetMethodIDOrDie(env, gDisplayEventReceiverClassInfo.clazz, "dispatchModeChanged", "(JJIJ)V"); + gDisplayEventReceiverClassInfo.dispatchModeRejected = + GetMethodIDOrDie(env, gDisplayEventReceiverClassInfo.clazz, "dispatchModeRejected", + "(JI)V"); gDisplayEventReceiverClassInfo.dispatchFrameRateOverrides = GetMethodIDOrDie(env, gDisplayEventReceiverClassInfo.clazz, "dispatchFrameRateOverrides", diff --git a/core/jni/com_android_internal_content_NativeLibraryHelper.cpp b/core/jni/com_android_internal_content_NativeLibraryHelper.cpp index b2eeff36c007349bc2be3fb1cfafa359d27051d6..f40cfd9f8e516e8d45461c403cfb90f7bc70d6bb 100644 --- a/core/jni/com_android_internal_content_NativeLibraryHelper.cpp +++ b/core/jni/com_android_internal_content_NativeLibraryHelper.cpp @@ -532,7 +532,12 @@ static inline bool app_compat_16kb_enabled() { static const size_t kPageSize = getpagesize(); // App compat is only applicable on 16kb-page-size devices. - return kPageSize == 0x4000; + if (kPageSize != 0x4000) { + return false; + } + + // Explicit disabled status for app compat + return !android::base::GetBoolProperty("pm.16kb.app_compat.disabled", false); } static jint diff --git a/core/jni/com_android_internal_util_ArrayUtils.cpp b/core/jni/com_android_internal_util_ArrayUtils.cpp new file mode 100644 index 0000000000000000000000000000000000000000..c70625815b90a92c883359f77cbb0c4d11978e75 --- /dev/null +++ b/core/jni/com_android_internal_util_ArrayUtils.cpp @@ -0,0 +1,119 @@ +/* + * Copyright (C) 2024 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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 "ArrayUtils" + +#include +#include +#include +#include +#include +#include + +namespace android { + +static size_t GetCacheLineSize() { + long size = sysconf(_SC_LEVEL1_DCACHE_LINESIZE); + if (size <= 0) { + ALOGE("Unable to determine L1 data cache line size. Assuming 32 bytes"); + return 32; + } + // The cache line size should always be a power of 2. + CHECK((size & (size - 1)) == 0); + + return size; +} + +static void CleanCacheLineContainingAddress(const uint8_t* p) { +#if defined(__aarch64__) + // 'dc cvac' stands for "Data Cache line Clean by Virtual Address to point-of-Coherency". + // It writes the cache line back to the "point-of-coherency", i.e. main memory. + asm volatile("dc cvac, %0" ::"r"(p)); +#elif defined(__i386__) || defined(__x86_64__) + asm volatile("clflush (%0)" ::"r"(p)); +#elif defined(__riscv) + // This should eventually work, but it is not ready to be enabled yet: + // 1.) The Android emulator needs to add support for zicbom. + // 2.) Kernel needs to enable zicbom in usermode. + // 3.) Android clang needs to add zicbom to the target. + // asm volatile("cbo.clean (%0)" ::"r"(p)); +#elif defined(__arm__) + // arm32 has a cacheflush() syscall, but it is undocumented and only flushes the icache. + // It is not the same as cacheflush(2) as documented in the Linux man-pages project. +#else +#error "Unknown architecture" +#endif +} + +static void CleanDataCache(const uint8_t* p, size_t buffer_size, size_t cache_line_size) { + // Clean the first line that overlaps the buffer. + CleanCacheLineContainingAddress(p); + // Clean any additional lines that overlap the buffer. Use cache-line-aligned addresses to + // ensure that (a) the last cache line gets flushed, and (b) no cache line is flushed twice. + for (size_t i = cache_line_size - ((uintptr_t)p & (cache_line_size - 1)); i < buffer_size; + i += cache_line_size) { + CleanCacheLineContainingAddress(p + i); + } +} + +static void ZeroizePrimitiveArray(JNIEnv* env, jclass clazz, jarray array, size_t component_len) { + static const size_t cache_line_size = GetCacheLineSize(); + + if (array == nullptr) { + return; + } + + size_t buffer_size = env->GetArrayLength(array) * component_len; + if (buffer_size == 0) { + return; + } + + // ART guarantees that GetPrimitiveArrayCritical never copies. + jboolean isCopy; + void* elems = env->GetPrimitiveArrayCritical(array, &isCopy); + CHECK(!isCopy); + +#ifdef __BIONIC__ + memset_explicit(elems, 0, buffer_size); +#else + memset(elems, 0, buffer_size); +#endif + // Clean the data cache so that the data gets zeroized in main memory right away. Without this, + // it might not be written to main memory until the cache line happens to be evicted. + CleanDataCache(static_cast(elems), buffer_size, cache_line_size); + + env->ReleasePrimitiveArrayCritical(array, elems, /* mode= */ 0); +} + +static void ZeroizeByteArray(JNIEnv* env, jclass clazz, jbyteArray array) { + ZeroizePrimitiveArray(env, clazz, array, sizeof(jbyte)); +} + +static void ZeroizeCharArray(JNIEnv* env, jclass clazz, jcharArray array) { + ZeroizePrimitiveArray(env, clazz, array, sizeof(jchar)); +} + +static const JNINativeMethod sMethods[] = { + {"zeroize", "([B)V", (void*)ZeroizeByteArray}, + {"zeroize", "([C)V", (void*)ZeroizeCharArray}, +}; + +int register_com_android_internal_util_ArrayUtils(JNIEnv* env) { + return jniRegisterNativeMethods(env, "com/android/internal/util/ArrayUtils", sMethods, + NELEM(sMethods)); +} + +} // namespace android diff --git a/core/res/Android.bp b/core/res/Android.bp index aacd8699c2020c68aaded755022171bcd852729f..be4fb8bdecfbc825379a19703ddbd0edbcfb6a41 100644 --- a/core/res/Android.bp +++ b/core/res/Android.bp @@ -162,6 +162,7 @@ android_app { "android.appwidget.flags-aconfig", "android.companion.virtualdevice.flags-aconfig", "android.content.pm.flags-aconfig", + "android.location.flags-aconfig", "android.media.audio-aconfig", "android.provider.flags-aconfig", "camera_platform_flags", @@ -178,6 +179,7 @@ android_app { "art-aconfig-flags", "ranging_aconfig_flags", "aconfig_settingslib_flags", + "telephony_flags", ], } diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml index 7d77ff054fe6f07a1e5fe778a1ec7a5108396b2d..6b8056c77fda2bc116c187a7d4bde16d6db7018a 100644 --- a/core/res/AndroidManifest.xml +++ b/core/res/AndroidManifest.xml @@ -1139,6 +1139,16 @@ android:protectionLevel="signature|privileged|vendorPrivileged" android:featureFlag="android.media.tv.flags.media_quality_fw"/> + + + @@ -2145,6 +2155,21 @@ + + + @@ -4124,6 +4149,14 @@ + + + + + @@ -7009,6 +7049,13 @@ + + + @@ -8752,6 +8799,17 @@ android:protectionLevel="signature|privileged|vendorPrivileged" android:featureFlag="android.media.tv.flags.kids_mode_tvdb_sharing"/> + + + diff --git a/core/res/res/color-watch-v36/btn_material_filled_background_color.xml b/core/res/res/color-watch-v36/btn_material_filled_background_color.xml index 70aace4e7d76f404963ca86791df3452ccead38e..39b5b10a774d5ef71835ac3e6bdd0df42276f136 100644 --- a/core/res/res/color-watch-v36/btn_material_filled_background_color.xml +++ b/core/res/res/color-watch-v36/btn_material_filled_background_color.xml @@ -17,6 +17,6 @@ - + android:color="@color/materialColorOnSurface" /> + \ No newline at end of file diff --git a/core/res/res/color-watch-v36/btn_material_filled_content_color.xml b/core/res/res/color-watch-v36/btn_material_filled_content_color.xml index 4cc8fe5ecb91a8ffe8256208385e9d0d640da523..a70586b08babbe8fd4039c9da435434d2ff2336c 100644 --- a/core/res/res/color-watch-v36/btn_material_filled_content_color.xml +++ b/core/res/res/color-watch-v36/btn_material_filled_content_color.xml @@ -17,6 +17,6 @@ - + android:color="@color/materialColorOnSurface" /> + \ No newline at end of file diff --git a/core/res/res/color-watch-v36/btn_material_filled_tonal_background_color.xml b/core/res/res/color-watch-v36/btn_material_filled_tonal_background_color.xml index b2a25af0d670a396c1779440e1794599ef785e4f..e2e274efb2b1f54e2bcad1602d9f7546b0514398 100644 --- a/core/res/res/color-watch-v36/btn_material_filled_tonal_background_color.xml +++ b/core/res/res/color-watch-v36/btn_material_filled_tonal_background_color.xml @@ -17,6 +17,6 @@ - + android:color="@color/materialColorOnSurface" /> + \ No newline at end of file diff --git a/core/res/res/color-watch-v36/btn_material_filled_tonal_content_color.xml b/core/res/res/color-watch-v36/btn_material_filled_tonal_content_color.xml index 59810356c3b4d00221d0bbbf89463228901b1479..32de68868d535894e44b6beb537f1ee13416b007 100644 --- a/core/res/res/color-watch-v36/btn_material_filled_tonal_content_color.xml +++ b/core/res/res/color-watch-v36/btn_material_filled_tonal_content_color.xml @@ -17,6 +17,6 @@ - + android:color="@color/materialColorOnSurface" /> + \ No newline at end of file diff --git a/core/res/res/color-watch-v36/btn_material_outlined_background_color.xml b/core/res/res/color-watch-v36/btn_material_outlined_background_color.xml index 665f47faca0d6c39a2418c4012af9dd2074367cb..3f43ca7b91df0c9632915ef12e54b81ee51175fc 100644 --- a/core/res/res/color-watch-v36/btn_material_outlined_background_color.xml +++ b/core/res/res/color-watch-v36/btn_material_outlined_background_color.xml @@ -17,6 +17,6 @@ - + android:color="@color/materialColorOnSurface" /> + diff --git a/core/res/res/color/input_method_switch_on_item.xml b/core/res/res/color/input_method_switch_on_item.xml index 49fe0815c757f60f65070811e716c5ee97f2c665..f38e0ac3454ef39a436894f5455fa93bb7b576bc 100644 --- a/core/res/res/color/input_method_switch_on_item.xml +++ b/core/res/res/color/input_method_switch_on_item.xml @@ -16,6 +16,6 @@ --> - - + + diff --git a/core/res/res/color/notification_expand_button_state_tint.xml b/core/res/res/color/notification_expand_button_state_tint.xml index 5a8594f0e461fcb31ab6a7bff9067bd5d03b7979..3409a2c7ab14fc4340430500a2dd35a0fb3716d9 100644 --- a/core/res/res/color/notification_expand_button_state_tint.xml +++ b/core/res/res/color/notification_expand_button_state_tint.xml @@ -16,9 +16,9 @@ - - \ No newline at end of file diff --git a/core/res/res/color/system_on_surface_disabled.xml b/core/res/res/color/system_on_surface_disabled.xml index aba87f543c441fb4f60ade6e656533f52e06c810..039ab024a32a23743bbc44862354b97278d806b7 100644 --- a/core/res/res/color/system_on_surface_disabled.xml +++ b/core/res/res/color/system_on_surface_disabled.xml @@ -15,6 +15,6 @@ --> - diff --git a/core/res/res/color/system_outline_disabled.xml b/core/res/res/color/system_outline_disabled.xml index 0a67ce3bf186cb3f8359b4bda4f709e549aef8bf..b5a6b6bd8e25bc66085128e38ad7fb422e745071 100644 --- a/core/res/res/color/system_outline_disabled.xml +++ b/core/res/res/color/system_outline_disabled.xml @@ -15,6 +15,6 @@ --> - diff --git a/core/res/res/color/system_surface_disabled.xml b/core/res/res/color/system_surface_disabled.xml index 2d7fe7d727be5386715d4947bea7649cf128e5e7..157227241d440a983960e7f5d32642b05465a10f 100644 --- a/core/res/res/color/system_surface_disabled.xml +++ b/core/res/res/color/system_surface_disabled.xml @@ -15,6 +15,6 @@ --> - diff --git a/core/res/res/drawable-watch-v36/progress_ring_wear_material3.xml b/core/res/res/drawable-watch-v36/progress_ring_wear_material3.xml index 5c0e5f606d81eb734fefa88441007d7c20f33e10..8250ee600a8fc764ffa58814f27f3c6dddf59982 100644 --- a/core/res/res/drawable-watch-v36/progress_ring_wear_material3.xml +++ b/core/res/res/drawable-watch-v36/progress_ring_wear_material3.xml @@ -27,7 +27,7 @@ android:innerRadiusRatio="@dimen/progressbar_inner_radius_ratio" android:thickness="@dimen/progressbar_thickness" android:useLevel="false"> - + @@ -36,7 +36,7 @@ android:innerRadiusRatio="@dimen/progressbar_inner_radius_ratio" android:thickness="@dimen/progressbar_thickness" android:useLevel="true"> - + diff --git a/core/res/res/drawable/floating_popup_background.xml b/core/res/res/drawable/floating_popup_background.xml index 99acedf06e2d2129cbab45b19a2beb317222e7da..7200954140b7622c923116b1933f4454f2b5dde8 100644 --- a/core/res/res/drawable/floating_popup_background.xml +++ b/core/res/res/drawable/floating_popup_background.xml @@ -18,7 +18,7 @@ - + diff --git a/core/res/res/drawable/immersive_cling_bg.xml b/core/res/res/drawable/immersive_cling_bg.xml index de29c32390e16e21fb8148222052080118a5f2b0..b28a423ea06b171e675762b9668c0583a2a7c84c 100644 --- a/core/res/res/drawable/immersive_cling_bg.xml +++ b/core/res/res/drawable/immersive_cling_bg.xml @@ -20,5 +20,5 @@ - + diff --git a/core/res/res/drawable/input_method_switch_button.xml b/core/res/res/drawable/input_method_switch_button.xml index 396d81ed87f635b3ab6c86a4caeb9372bb876c51..1ee9b81a855a3bf2a2f4951957c82af591385cfa 100644 --- a/core/res/res/drawable/input_method_switch_button.xml +++ b/core/res/res/drawable/input_method_switch_button.xml @@ -30,7 +30,7 @@ - - + diff --git a/core/res/res/layout-round-watch/alert_dialog_title_material.xml b/core/res/res/layout-round-watch/alert_dialog_title_material.xml index 75fe7601317b590c630f4f23e35acd7ab6b7ab7c..dac1e324be81d29c4a922bcf02dd75f1cf9bb565 100644 --- a/core/res/res/layout-round-watch/alert_dialog_title_material.xml +++ b/core/res/res/layout-round-watch/alert_dialog_title_material.xml @@ -14,34 +14,30 @@ ~ See the License for the specific language governing permissions and ~ limitations under the License --> - - - - - + + android:minHeight="@dimen/screen_percentage_15"> + - - + diff --git a/core/res/res/layout-watch-v36/alert_dialog_wear_material3.xml b/core/res/res/layout-watch-v36/alert_dialog_wear_material3.xml index af30f1bd164c1350346ac25ee1f5171a9ce7c929..8f754569014216824988eece96f0fae290440a6c 100644 --- a/core/res/res/layout-watch-v36/alert_dialog_wear_material3.xml +++ b/core/res/res/layout-watch-v36/alert_dialog_wear_material3.xml @@ -16,123 +16,98 @@ - - - - - + android:layout_height="match_parent"> - - - - + android:layout_width="match_parent" + android:layout_height="wrap_content"> - - + - - - + + - - - + + - + android:layout_gravity="center"> - -