diff --git a/AconfigFlags.bp b/AconfigFlags.bp index 6393fdb910e3466dbd2d8706607781ee2c09ce26..e18470498f391d107dc07d113f2ef6ababc85dcf 100644 --- a/AconfigFlags.bp +++ b/AconfigFlags.bp @@ -56,7 +56,7 @@ 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", + "android.net.vcn.flags-aconfig-java-export", "android.net.wifi.flags-aconfig-java", "android.nfc.flags-aconfig-java", "android.os.flags-aconfig-java", @@ -100,7 +100,7 @@ aconfig_declarations_group { "com.android.media.flags.performance-aconfig-java", "com.android.media.flags.projection-aconfig-java", "com.android.net.thread.platform.flags-aconfig-java", - "com.android.ranging.flags.ranging-aconfig-java", + "com.android.ranging.flags.ranging-aconfig-java-export", "com.android.server.contextualsearch.flags-java", "com.android.server.flags.services-aconfig-java", "com.android.text.flags-aconfig-java", @@ -373,6 +373,11 @@ java_aconfig_library { name: "android.security.flags-aconfig-java-export", aconfig_declarations: "android.security.flags-aconfig", mode: "exported", + min_sdk_version: "30", + apex_available: [ + "//apex_available:platform", + "com.android.wifi", + ], defaults: ["framework-minus-apex-aconfig-java-defaults"], } @@ -1170,16 +1175,21 @@ java_aconfig_library { } // 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: "system", + container: "com.android.tethering", + exportable: true, srcs: ["core/java/android/net/vcn/*.aconfig"], } java_aconfig_library { - name: "android.net.vcn.flags-aconfig-java", + 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"], } @@ -1646,13 +1656,6 @@ java_aconfig_library { defaults: ["framework-minus-apex-aconfig-java-defaults"], } -// Ranging -java_aconfig_library { - name: "com.android.ranging.flags.ranging-aconfig-java", - aconfig_declarations: "ranging_aconfig_flags", - defaults: ["framework-minus-apex-aconfig-java-defaults"], -} - // System Server aconfig_declarations { name: "android.systemserver.flags-aconfig", diff --git a/Android.bp b/Android.bp index 54cb2684068dff0633def876e19762eb4d123929..424a4a71ce404a3fad3bd63989a996c44194b6a6 100644 --- a/Android.bp +++ b/Android.bp @@ -103,10 +103,10 @@ filegroup { ":android.hardware.gnss-V2-java-source", ":android.hardware.graphics.common-V3-java-source", ":android.hardware.keymaster-V4-java-source", - ":android.hardware.radio-V3-java-source", - ":android.hardware.radio.data-V3-java-source", - ":android.hardware.radio.network-V3-java-source", - ":android.hardware.radio.voice-V3-java-source", + ":android.hardware.radio-V4-java-source", + ":android.hardware.radio.data-V4-java-source", + ":android.hardware.radio.network-V4-java-source", + ":android.hardware.radio.voice-V4-java-source", ":android.hardware.security.secureclock-V1-java-source", ":android.hardware.thermal-V3-java-source", ":android.hardware.tv.tuner-V3-java-source", @@ -232,13 +232,13 @@ java_library { "android.hardware.gnss-V2.1-java", "android.hardware.health-V1.0-java-constants", "android.hardware.radio-V1.6-java", - "android.hardware.radio.data-V3-java", - "android.hardware.radio.ims-V2-java", - "android.hardware.radio.messaging-V3-java", - "android.hardware.radio.modem-V3-java", - "android.hardware.radio.network-V3-java", - "android.hardware.radio.sim-V3-java", - "android.hardware.radio.voice-V3-java", + "android.hardware.radio.data-V4-java", + "android.hardware.radio.ims-V3-java", + "android.hardware.radio.messaging-V4-java", + "android.hardware.radio.modem-V4-java", + "android.hardware.radio.network-V4-java", + "android.hardware.radio.sim-V4-java", + "android.hardware.radio.voice-V4-java", "android.hardware.thermal-V1.0-java-constants", "android.hardware.thermal-V1.0-java", "android.hardware.thermal-V1.1-java", @@ -397,6 +397,8 @@ java_defaults { "ext", "framework-updatable-stubs-module_libs_api", "unsupportedappusage", + // TODO(b/379770939): remove prod version of flags from other containers in framework + "aconfig_storage_stub", ], sdk_version: "core_platform", static_libs: [ diff --git a/PREUPLOAD.cfg b/PREUPLOAD.cfg index a92a54337f9693c51f722a7a25771b35791873eb..d748a3bebfef2740e8a29a8d6454a4246ab69e16 100644 --- a/PREUPLOAD.cfg +++ b/PREUPLOAD.cfg @@ -18,7 +18,7 @@ clang_format = --commit ${PREUPLOAD_COMMIT} --style file --extensions c,h,cc,cpp tests/ tools/ bpfmt = -d -ktfmt = --kotlinlang-style --include-dirs=services/permission,packages/SystemUI,libs/WindowManager/Shell/src/com/android/wm/shell/freeform +ktfmt = --kotlinlang-style --include-dirs=services/permission,packages/SystemUI,libs/WindowManager/Shell/src/com/android/wm/shell/freeform,libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/education [Hook Scripts] checkstyle_hook = ${REPO_ROOT}/prebuilts/checkstyle/checkstyle.py --sha ${PREUPLOAD_COMMIT} diff --git a/apct-tests/perftests/textclassifier/src/android/view/textclassifier/TextClassificationManagerPerfTest.java b/apct-tests/perftests/textclassifier/src/android/view/textclassifier/TextClassificationManagerPerfTest.java index 46250d74a4e3fb388f7bfa6fec2c116d758bc868..d950b708dcc6e76341dcfb5ce3009d530ff41b67 100644 --- a/apct-tests/perftests/textclassifier/src/android/view/textclassifier/TextClassificationManagerPerfTest.java +++ b/apct-tests/perftests/textclassifier/src/android/view/textclassifier/TextClassificationManagerPerfTest.java @@ -34,6 +34,8 @@ import org.junit.Test; public class TextClassificationManagerPerfTest { private static final String WRITE_DEVICE_CONFIG_PERMISSION = "android.permission.WRITE_DEVICE_CONFIG"; + private static final String WRITE_ALLOWLISTED_DEVICE_CONFIG_PERMISSION = + "android.permission.WRITE_ALLOWLISTED_DEVICE_CONFIG"; @Rule public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter(); @@ -44,7 +46,7 @@ public class TextClassificationManagerPerfTest { public static void setUpClass() { InstrumentationRegistry.getInstrumentation().getUiAutomation() .adoptShellPermissionIdentity( - WRITE_DEVICE_CONFIG_PERMISSION); + WRITE_DEVICE_CONFIG_PERMISSION, WRITE_ALLOWLISTED_DEVICE_CONFIG_PERMISSION); } @AfterClass diff --git a/apct-tests/perftests/tracing/src/com/android/internal/protolog/ProtoLogPerfTest.java b/apct-tests/perftests/tracing/src/com/android/internal/protolog/ProtoLogPerfTest.java index 7ef8c53d1d62c732465aebdee8dcad0981d730ff..7168fbec07bcfc4dfa66b73646f7983d694cd49c 100644 --- a/apct-tests/perftests/tracing/src/com/android/internal/protolog/ProtoLogPerfTest.java +++ b/apct-tests/perftests/tracing/src/com/android/internal/protolog/ProtoLogPerfTest.java @@ -19,6 +19,9 @@ import android.app.Activity; import android.os.Bundle; import android.os.ServiceManager.ServiceNotFoundException; import android.perftests.utils.Stats; +import android.tracing.perfetto.DataSourceParams; +import android.tracing.perfetto.InitArguments; +import android.tracing.perfetto.Producer; import androidx.test.InstrumentationRegistry; @@ -70,6 +73,8 @@ public class ProtoLogPerfTest { } private IProtoLog mProcessedProtoLogger; + private static ProtoLogDataSource sTestDataSource; + private static final String TEST_PROTOLOG_DATASOURCE_NAME = "test.android.protolog"; private static final String MOCK_TEST_FILE_PATH = "mock/file/path"; private static final perfetto.protos.Protolog.ProtoLogViewerConfig VIEWER_CONFIG = perfetto.protos.Protolog.ProtoLogViewerConfig.newBuilder() @@ -89,6 +94,17 @@ public class ProtoLogPerfTest { @BeforeClass public static void init() { + Producer.init(InitArguments.DEFAULTS); + + sTestDataSource = new ProtoLogDataSource(TEST_PROTOLOG_DATASOURCE_NAME); + DataSourceParams params = + new DataSourceParams.Builder() + .setBufferExhaustedPolicy( + DataSourceParams + .PERFETTO_DS_BUFFER_EXHAUSTED_POLICY_DROP) + .build(); + sTestDataSource.register(params); + ProtoLog.init(TestProtoLogGroup.values()); } @@ -98,9 +114,10 @@ public class ProtoLogPerfTest { TestProtoLogGroup.TEST_GROUP.setLogToLogcat(mLogToLogcat); mProcessedProtoLogger = new ProcessedPerfettoProtoLogImpl( + sTestDataSource, MOCK_TEST_FILE_PATH, () -> new AutoClosableProtoInputStream(VIEWER_CONFIG.toByteArray()), - () -> {}, + (instance) -> {}, TestProtoLogGroup.values() ); } diff --git a/apex/jobscheduler/service/aconfig/app_idle.aconfig b/apex/jobscheduler/service/aconfig/app_idle.aconfig index f079c02707e07d81b325453480119d1ccede5f10..74d2a590086f5773f325cbc6dcd851f216c8a7e0 100644 --- a/apex/jobscheduler/service/aconfig/app_idle.aconfig +++ b/apex/jobscheduler/service/aconfig/app_idle.aconfig @@ -21,3 +21,10 @@ flag { purpose: PURPOSE_BUGFIX } } + +flag { + name: "adjust_default_bucket_elevation_params" + namespace: "backstage_power" + description: "Adjust the default bucket evaluation parameters" + bug: "379909479" +} 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 1c6e40e25a92ef16158233d3083662711d91b590..a5a08fb9997c926570ce440e06a9a3d450b938d6 100644 --- a/apex/jobscheduler/service/java/com/android/server/job/JobSchedulerService.java +++ b/apex/jobscheduler/service/java/com/android/server/job/JobSchedulerService.java @@ -573,6 +573,7 @@ public class JobSchedulerService extends com.android.server.SystemService case Constants.KEY_MIN_LINEAR_BACKOFF_TIME_MS: case Constants.KEY_MIN_EXP_BACKOFF_TIME_MS: case Constants.KEY_SYSTEM_STOP_TO_FAILURE_RATIO: + case Constants.KEY_ABANDONED_JOB_TIMEOUTS_BEFORE_AGGRESSIVE_BACKOFF: mConstants.updateBackoffConstantsLocked(); break; case Constants.KEY_CONN_CONGESTION_DELAY_FRAC: @@ -679,6 +680,8 @@ public class JobSchedulerService extends com.android.server.SystemService private static final String KEY_MIN_EXP_BACKOFF_TIME_MS = "min_exp_backoff_time_ms"; private static final String KEY_SYSTEM_STOP_TO_FAILURE_RATIO = "system_stop_to_failure_ratio"; + private static final String KEY_ABANDONED_JOB_TIMEOUTS_BEFORE_AGGRESSIVE_BACKOFF = + "abandoned_job_timeouts_before_aggressive_backoff"; private static final String KEY_CONN_CONGESTION_DELAY_FRAC = "conn_congestion_delay_frac"; private static final String KEY_CONN_PREFETCH_RELAX_FRAC = "conn_prefetch_relax_frac"; private static final String KEY_CONN_USE_CELL_SIGNAL_STRENGTH = @@ -750,6 +753,7 @@ public class JobSchedulerService extends com.android.server.SystemService private static final long DEFAULT_MIN_LINEAR_BACKOFF_TIME_MS = JobInfo.MIN_BACKOFF_MILLIS; private static final long DEFAULT_MIN_EXP_BACKOFF_TIME_MS = JobInfo.MIN_BACKOFF_MILLIS; private static final int DEFAULT_SYSTEM_STOP_TO_FAILURE_RATIO = 3; + private static final int DEFAULT_ABANDONED_JOB_TIMEOUTS_BEFORE_AGGRESSIVE_BACKOFF = 3; private static final float DEFAULT_CONN_CONGESTION_DELAY_FRAC = 0.5f; private static final float DEFAULT_CONN_PREFETCH_RELAX_FRAC = 0.5f; private static final boolean DEFAULT_CONN_USE_CELL_SIGNAL_STRENGTH = true; @@ -845,7 +849,12 @@ public class JobSchedulerService extends com.android.server.SystemService * incremental failure in the backoff policy calculation. */ int SYSTEM_STOP_TO_FAILURE_RATIO = DEFAULT_SYSTEM_STOP_TO_FAILURE_RATIO; - + /** + * Number of consecutive timeouts by abandoned jobs before we change to aggressive backoff + * policy. + */ + int ABANDONED_JOB_TIMEOUTS_BEFORE_AGGRESSIVE_BACKOFF = + DEFAULT_ABANDONED_JOB_TIMEOUTS_BEFORE_AGGRESSIVE_BACKOFF; /** * The fraction of a job's running window that must pass before we * consider running it when the network is congested. @@ -1078,6 +1087,10 @@ public class JobSchedulerService extends com.android.server.SystemService SYSTEM_STOP_TO_FAILURE_RATIO = DeviceConfig.getInt(DeviceConfig.NAMESPACE_JOB_SCHEDULER, KEY_SYSTEM_STOP_TO_FAILURE_RATIO, DEFAULT_SYSTEM_STOP_TO_FAILURE_RATIO); + ABANDONED_JOB_TIMEOUTS_BEFORE_AGGRESSIVE_BACKOFF = DeviceConfig.getInt( + DeviceConfig.NAMESPACE_JOB_SCHEDULER, + KEY_ABANDONED_JOB_TIMEOUTS_BEFORE_AGGRESSIVE_BACKOFF, + DEFAULT_ABANDONED_JOB_TIMEOUTS_BEFORE_AGGRESSIVE_BACKOFF); } // TODO(141645789): move into ConnectivityController.CcConfig @@ -1287,6 +1300,8 @@ public class JobSchedulerService extends com.android.server.SystemService pw.print(KEY_MIN_LINEAR_BACKOFF_TIME_MS, MIN_LINEAR_BACKOFF_TIME_MS).println(); pw.print(KEY_MIN_EXP_BACKOFF_TIME_MS, MIN_EXP_BACKOFF_TIME_MS).println(); pw.print(KEY_SYSTEM_STOP_TO_FAILURE_RATIO, SYSTEM_STOP_TO_FAILURE_RATIO).println(); + pw.print(KEY_ABANDONED_JOB_TIMEOUTS_BEFORE_AGGRESSIVE_BACKOFF, + ABANDONED_JOB_TIMEOUTS_BEFORE_AGGRESSIVE_BACKOFF).println(); pw.print(KEY_CONN_CONGESTION_DELAY_FRAC, CONN_CONGESTION_DELAY_FRAC).println(); pw.print(KEY_CONN_PREFETCH_RELAX_FRAC, CONN_PREFETCH_RELAX_FRAC).println(); pw.print(KEY_CONN_USE_CELL_SIGNAL_STRENGTH, CONN_USE_CELL_SIGNAL_STRENGTH).println(); @@ -2085,8 +2100,12 @@ public class JobSchedulerService extends com.android.server.SystemService if (DEBUG) { Slog.v(TAG, debugPrefix + " ready=" + jobReady); } - if (!jobReady) { - return job.getPendingJobReasons(); + final JobRestriction restriction = checkIfRestricted(job); + if (DEBUG) { + Slog.v(TAG, debugPrefix + " restriction=" + restriction); + } + if (!jobReady || restriction != null) { + return job.getPendingJobReasons(restriction); } final boolean userStarted = areUsersStartedLocked(job); @@ -2106,18 +2125,6 @@ public class JobSchedulerService extends com.android.server.SystemService return new int[] { JobScheduler.PENDING_JOB_REASON_APP }; } - final JobRestriction restriction = checkIfRestricted(job); - if (DEBUG) { - Slog.v(TAG, debugPrefix + " restriction=" + restriction); - } - if (restriction != null) { - // Currently this will return _DEVICE_STATE because of thermal reasons. - // TODO (b/372031023): does it make sense to move this along with the - // pendingJobReasons() call above and also get the pending reasons from - // all of the restriction controllers? - return new int[] { restriction.getPendingReason() }; - } - // The following can be a little more expensive, so we are doing it later, // but still before checking with the package manager! final boolean jobPending = mPendingJobQueue.contains(job); @@ -3005,6 +3012,7 @@ public class JobSchedulerService extends com.android.server.SystemService final long initialBackoffMillis = job.getInitialBackoffMillis(); int numFailures = failureToReschedule.getNumFailures(); + int numAbandonedFailures = failureToReschedule.getNumAbandonedFailures(); int numSystemStops = failureToReschedule.getNumSystemStops(); // We should back off slowly if JobScheduler keeps stopping the job, // but back off immediately if the issue appeared to be the app's fault @@ -3014,9 +3022,19 @@ public class JobSchedulerService extends com.android.server.SystemService || internalStopReason == JobParameters.INTERNAL_STOP_REASON_ANR || stopReason == JobParameters.STOP_REASON_USER) { numFailures++; + } else if (android.app.job.Flags.handleAbandonedJobs() + && internalStopReason == JobParameters.INTERNAL_STOP_REASON_TIMEOUT_ABANDONED) { + numAbandonedFailures++; + numFailures++; } else { numSystemStops++; } + + int backoffPolicy = job.getBackoffPolicy(); + if (shouldUseAggressiveBackoff(numAbandonedFailures)) { + backoffPolicy = JobInfo.BACKOFF_POLICY_EXPONENTIAL; + } + final int backoffAttempts = numFailures + numSystemStops / mConstants.SYSTEM_STOP_TO_FAILURE_RATIO; final long earliestRuntimeMs; @@ -3025,7 +3043,7 @@ public class JobSchedulerService extends com.android.server.SystemService earliestRuntimeMs = JobStatus.NO_EARLIEST_RUNTIME; } else { long delayMillis; - switch (job.getBackoffPolicy()) { + switch (backoffPolicy) { case JobInfo.BACKOFF_POLICY_LINEAR: { long backoff = initialBackoffMillis; if (backoff < mConstants.MIN_LINEAR_BACKOFF_TIME_MS) { @@ -3054,7 +3072,7 @@ public class JobSchedulerService extends com.android.server.SystemService } JobStatus newJob = new JobStatus(failureToReschedule, earliestRuntimeMs, - JobStatus.NO_LATEST_RUNTIME, numFailures, numSystemStops, + JobStatus.NO_LATEST_RUNTIME, numFailures, numAbandonedFailures, numSystemStops, failureToReschedule.getLastSuccessfulRunTime(), sSystemClock.millis(), failureToReschedule.getCumulativeExecutionTimeMs()); if (stopReason == JobParameters.STOP_REASON_USER) { @@ -3076,6 +3094,20 @@ public class JobSchedulerService extends com.android.server.SystemService return newJob; } + /** + * Returns {@code true} if the given number of abandoned failures indicates that JobScheduler + * should use an aggressive backoff policy. + * + * @param numAbandonedFailures The number of abandoned failures. + * @return {@code true} if the given number of abandoned failures indicates that JobScheduler + * should use an aggressive backoff policy. + */ + public boolean shouldUseAggressiveBackoff(int numAbandonedFailures) { + return android.app.job.Flags.handleAbandonedJobs() + && numAbandonedFailures + > mConstants.ABANDONED_JOB_TIMEOUTS_BEFORE_AGGRESSIVE_BACKOFF; + } + /** * Maximum time buffer in which JobScheduler will try to optimize periodic job scheduling. This * does not cause a job's period to be larger than requested (eg: if the requested period is @@ -3155,6 +3187,7 @@ public class JobSchedulerService extends com.android.server.SystemService return new JobStatus(periodicToReschedule, elapsedNow + period - flex, elapsedNow + period, 0 /* numFailures */, 0 /* numSystemStops */, + 0 /* numAbandonedFailures */, sSystemClock.millis() /* lastSuccessfulRunTime */, periodicToReschedule.getLastFailedRunTime(), 0 /* Reset cumulativeExecutionTime because of successful execution */); @@ -3171,6 +3204,7 @@ public class JobSchedulerService extends com.android.server.SystemService return new JobStatus(periodicToReschedule, newEarliestRunTimeElapsed, newLatestRuntimeElapsed, 0 /* numFailures */, 0 /* numSystemStops */, + 0 /* numAbandonedFailures */, sSystemClock.millis() /* lastSuccessfulRunTime */, periodicToReschedule.getLastFailedRunTime(), 0 /* Reset cumulativeExecutionTime because of successful execution */); @@ -3179,6 +3213,10 @@ public class JobSchedulerService extends com.android.server.SystemService @VisibleForTesting void maybeProcessBuggyJob(@NonNull JobStatus jobStatus, int debugStopReason) { boolean jobTimedOut = debugStopReason == JobParameters.INTERNAL_STOP_REASON_TIMEOUT; + if (android.app.job.Flags.handleAbandonedJobs()) { + jobTimedOut |= (debugStopReason + == JobParameters.INTERNAL_STOP_REASON_TIMEOUT_ABANDONED); + } // If madeActive = 0, the job never actually started. if (!jobTimedOut && jobStatus.madeActive > 0) { final long executionDurationMs = sUptimeMillisClock.millis() - jobStatus.madeActive; @@ -3260,9 +3298,12 @@ public class JobSchedulerService extends com.android.server.SystemService // we stop it. final JobStatus rescheduledJob = needsReschedule ? getRescheduleJobForFailureLocked(jobStatus, stopReason, debugStopReason) : null; + final boolean isStopReasonAbandoned = android.app.job.Flags.handleAbandonedJobs() + && (debugStopReason == JobParameters.INTERNAL_STOP_REASON_TIMEOUT_ABANDONED); if (rescheduledJob != null && !rescheduledJob.shouldTreatAsUserInitiatedJob() && (debugStopReason == JobParameters.INTERNAL_STOP_REASON_TIMEOUT + || isStopReasonAbandoned || debugStopReason == JobParameters.INTERNAL_STOP_REASON_PREEMPT)) { rescheduledJob.disallowRunInBatterySaverAndDoze(); } diff --git a/apex/jobscheduler/service/java/com/android/server/job/JobStore.java b/apex/jobscheduler/service/java/com/android/server/job/JobStore.java index d8934d8f83b818ca1be2a524f8acae5ffda09bcd..dfb36818c818e960109bd783d5c12c490a8b56f7 100644 --- a/apex/jobscheduler/service/java/com/android/server/job/JobStore.java +++ b/apex/jobscheduler/service/java/com/android/server/job/JobStore.java @@ -269,7 +269,9 @@ public final class JobStore { convertRtcBoundsToElapsed(utcTimes, elapsedNow); JobStatus newJob = new JobStatus(job, elapsedRuntimes.first, elapsedRuntimes.second, - 0, 0, job.getLastSuccessfulRunTime(), job.getLastFailedRunTime(), + 0 /* numFailures */, 0 /* numAbandonedFailures */, + 0 /* numSystemStops */, job.getLastSuccessfulRunTime(), + job.getLastFailedRunTime(), job.getCumulativeExecutionTimeMs()); newJob.prepareLocked(); toAdd.add(newJob); diff --git a/apex/jobscheduler/service/java/com/android/server/job/controllers/JobStatus.java b/apex/jobscheduler/service/java/com/android/server/job/controllers/JobStatus.java index b0784f1c69fdaacde8e3c186ae3b9b32d58004d6..5a33aa0ab7eb611f14db3429bbc62fbd8a4a3939 100644 --- a/apex/jobscheduler/service/java/com/android/server/job/controllers/JobStatus.java +++ b/apex/jobscheduler/service/java/com/android/server/job/controllers/JobStatus.java @@ -66,6 +66,7 @@ import com.android.server.job.JobSchedulerService; import com.android.server.job.JobServerProtoEnums; import com.android.server.job.JobStatusDumpProto; import com.android.server.job.JobStatusShortInfoProto; +import com.android.server.job.restrictions.JobRestriction; import dalvik.annotation.optimization.NeverCompile; @@ -314,6 +315,12 @@ public final class JobStatus { */ private final int numFailures; + /** + * How many times this job has stopped due to {@link + * JobParameters#STOP_REASON_TIMEOUT_ABANDONED}. + */ + private final int mNumAbandonedFailures; + /** * The number of times JobScheduler has forced this job to stop due to reasons mostly outside * of the app's control. @@ -604,6 +611,8 @@ public final class JobStatus { * @param tag A string associated with the job for debugging/logging purposes. * @param numFailures Count of how many times this job has requested a reschedule because * its work was not yet finished. + * @param mNumAbandonedFailures Count of how many times this job has requested a reschedule + * because it was abandoned. * @param numSystemStops Count of how many times JobScheduler has forced this job to stop due to * factors mostly out of the app's control. * @param earliestRunTimeElapsedMillis Milestone: earliest point in time at which the job @@ -616,7 +625,7 @@ public final class JobStatus { */ private JobStatus(JobInfo job, int callingUid, String sourcePackageName, int sourceUserId, int standbyBucket, @Nullable String namespace, String tag, - int numFailures, int numSystemStops, + int numFailures, int mNumAbandonedFailures, int numSystemStops, long earliestRunTimeElapsedMillis, long latestRunTimeElapsedMillis, long lastSuccessfulRunTime, long lastFailedRunTime, long cumulativeExecutionTimeMs, int internalFlags, @@ -676,6 +685,7 @@ public final class JobStatus { this.latestRunTimeElapsedMillis = latestRunTimeElapsedMillis; this.mOriginalLatestRunTimeElapsedMillis = latestRunTimeElapsedMillis; this.numFailures = numFailures; + this.mNumAbandonedFailures = mNumAbandonedFailures; mNumSystemStops = numSystemStops; int requiredConstraints = job.getConstraintFlags(); @@ -749,7 +759,8 @@ public final class JobStatus { this(jobStatus.getJob(), jobStatus.getUid(), jobStatus.getSourcePackageName(), jobStatus.getSourceUserId(), jobStatus.getStandbyBucket(), jobStatus.getNamespace(), - jobStatus.getSourceTag(), jobStatus.getNumFailures(), jobStatus.getNumSystemStops(), + jobStatus.getSourceTag(), jobStatus.getNumFailures(), + jobStatus.getNumAbandonedFailures(), jobStatus.getNumSystemStops(), jobStatus.getEarliestRunTime(), jobStatus.getLatestRunTimeElapsed(), jobStatus.getLastSuccessfulRunTime(), jobStatus.getLastFailedRunTime(), jobStatus.getCumulativeExecutionTimeMs(), @@ -786,6 +797,7 @@ public final class JobStatus { this(job, callingUid, sourcePkgName, sourceUserId, standbyBucket, namespace, sourceTag, /* numFailures */ 0, /* numSystemStops */ 0, + /* mNumAbandonedFailures */ 0, earliestRunTimeElapsedMillis, latestRunTimeElapsedMillis, lastSuccessfulRunTime, lastFailedRunTime, cumulativeExecutionTimeMs, innerFlags, dynamicConstraints); @@ -805,13 +817,15 @@ public final class JobStatus { /** Create a new job to be rescheduled with the provided parameters. */ public JobStatus(JobStatus rescheduling, long newEarliestRuntimeElapsedMillis, - long newLatestRuntimeElapsedMillis, int numFailures, int numSystemStops, + long newLatestRuntimeElapsedMillis, int numFailures, + int mNumAbandonedFailures, int numSystemStops, long lastSuccessfulRunTime, long lastFailedRunTime, long cumulativeExecutionTimeMs) { this(rescheduling.job, rescheduling.getUid(), rescheduling.getSourcePackageName(), rescheduling.getSourceUserId(), rescheduling.getStandbyBucket(), rescheduling.getNamespace(), - rescheduling.getSourceTag(), numFailures, numSystemStops, + rescheduling.getSourceTag(), numFailures, + mNumAbandonedFailures, numSystemStops, newEarliestRuntimeElapsedMillis, newLatestRuntimeElapsedMillis, lastSuccessfulRunTime, lastFailedRunTime, cumulativeExecutionTimeMs, @@ -850,7 +864,8 @@ public final class JobStatus { int standbyBucket = JobSchedulerService.standbyBucketForPackage(jobPackage, sourceUserId, elapsedNow); return new JobStatus(job, callingUid, sourcePkg, sourceUserId, - standbyBucket, namespace, tag, /* numFailures */ 0, /* numSystemStops */ 0, + standbyBucket, namespace, tag, /* numFailures */ 0, + /* mNumAbandonedFailures */ 0, /* numSystemStops */ 0, earliestRunTimeElapsedMillis, latestRunTimeElapsedMillis, 0 /* lastSuccessfulRunTime */, 0 /* lastFailedRunTime */, /* cumulativeExecutionTime */ 0, @@ -1144,6 +1159,13 @@ public final class JobStatus { return numFailures; } + /** + * Returns the number of times the job stopped previously for STOP_REASON_TIMEOUT_ABANDONED. + */ + public int getNumAbandonedFailures() { + return mNumAbandonedFailures; + } + /** * Returns the number of times the system stopped a previous execution of this job for reasons * that were likely outside the app's control. @@ -2179,11 +2201,20 @@ public final class JobStatus { * This will return all potential reasons why the job is pending. */ @NonNull - public int[] getPendingJobReasons() { + public int[] getPendingJobReasons(@Nullable JobRestriction restriction) { final int unsatisfiedConstraints = ~satisfiedConstraints & (requiredConstraints | mDynamicConstraints | IMPLICIT_CONSTRAINTS); final ArrayList reasons = constraintsToPendingJobReasons(unsatisfiedConstraints); + if (restriction != null) { + // Currently only ThermalStatusRestriction extends the JobRestriction class and + // returns PENDING_JOB_REASON_DEVICE_STATE if the job is restricted because of thermal. + @JobScheduler.PendingJobReason final int reason = restriction.getPendingReason(); + if (!reasons.contains(reason)) { + reasons.addLast(reason); + } + } + if (reasons.isEmpty()) { if (getEffectiveStandbyBucket() == NEVER_INDEX) { Slog.wtf(TAG, "App in NEVER bucket querying pending job reason"); diff --git a/apex/jobscheduler/service/java/com/android/server/job/controllers/QuotaController.java b/apex/jobscheduler/service/java/com/android/server/job/controllers/QuotaController.java index 8bd3ef4f4d1a1b4ff972228ad51051a97cef5d29..637c726a9bd1c8041e55081096734a3229ce0f1a 100644 --- a/apex/jobscheduler/service/java/com/android/server/job/controllers/QuotaController.java +++ b/apex/jobscheduler/service/java/com/android/server/job/controllers/QuotaController.java @@ -36,10 +36,14 @@ import android.annotation.UserIdInt; import android.app.ActivityManager; import android.app.AlarmManager; import android.app.UidObserver; +import android.app.compat.CompatChanges; import android.app.job.JobInfo; import android.app.usage.UsageEvents; import android.app.usage.UsageStatsManagerInternal; import android.app.usage.UsageStatsManagerInternal.UsageEventListener; +import android.compat.annotation.ChangeId; +import android.compat.annotation.Disabled; +import android.compat.annotation.Overridable; import android.content.Context; import android.content.pm.ApplicationInfo; import android.content.pm.PackageInfo; @@ -132,6 +136,27 @@ public final class QuotaController extends StateController { return (int) (val ^ (val >>> 32)); } + /** + * When enabled this change id overrides the default quota policy enforcement to the jobs + * running in the foreground process state. + */ + // TODO: b/379681266 - Might need some refactoring for a better app-compat strategy. + @VisibleForTesting + @ChangeId + @Disabled // Disabled by default + @Overridable // The change can be overridden in user build + static final long OVERRIDE_QUOTA_ENFORCEMENT_TO_FGS_JOBS = 341201311L; + + /** + * When enabled this change id overrides the default quota policy enforcement policy + * the jobs started when app was in the TOP state. + */ + @VisibleForTesting + @ChangeId + @Disabled // Disabled by default + @Overridable // The change can be overridden in user build. + static final long OVERRIDE_QUOTA_ENFORCEMENT_TO_TOP_STARTED_JOBS = 374323858L; + @VisibleForTesting static class ExecutionStats { /** @@ -622,7 +647,9 @@ public final class QuotaController extends StateController { } final int uid = jobStatus.getSourceUid(); - if (!Flags.enforceQuotaPolicyToTopStartedJobs() && mTopAppCache.get(uid)) { + if ((!Flags.enforceQuotaPolicyToTopStartedJobs() + || CompatChanges.isChangeEnabled(OVERRIDE_QUOTA_ENFORCEMENT_TO_TOP_STARTED_JOBS, + uid)) && mTopAppCache.get(uid)) { if (DEBUG) { Slog.d(TAG, jobStatus.toShortString() + " is top started job"); } @@ -659,7 +686,9 @@ public final class QuotaController extends StateController { timer.stopTrackingJob(jobStatus); } } - if (!Flags.enforceQuotaPolicyToTopStartedJobs()) { + if (!Flags.enforceQuotaPolicyToTopStartedJobs() + || CompatChanges.isChangeEnabled(OVERRIDE_QUOTA_ENFORCEMENT_TO_TOP_STARTED_JOBS, + jobStatus.getSourceUid())) { mTopStartedJobs.remove(jobStatus); } } @@ -772,7 +801,13 @@ public final class QuotaController extends StateController { /** @return true if the job was started while the app was in the TOP state. */ private boolean isTopStartedJobLocked(@NonNull final JobStatus jobStatus) { - return !Flags.enforceQuotaPolicyToTopStartedJobs() && mTopStartedJobs.contains(jobStatus); + if (!Flags.enforceQuotaPolicyToTopStartedJobs() + || CompatChanges.isChangeEnabled(OVERRIDE_QUOTA_ENFORCEMENT_TO_TOP_STARTED_JOBS, + jobStatus.getSourceUid())) { + return mTopStartedJobs.contains(jobStatus); + } + + return false; } /** Returns the maximum amount of time this job could run for. */ @@ -2634,9 +2669,13 @@ public final class QuotaController extends StateController { } @VisibleForTesting - int getProcessStateQuotaFreeThreshold() { - return Flags.enforceQuotaPolicyToFgsJobs() ? ActivityManager.PROCESS_STATE_BOUND_TOP : - ActivityManager.PROCESS_STATE_FOREGROUND_SERVICE; + int getProcessStateQuotaFreeThreshold(int uid) { + if (Flags.enforceQuotaPolicyToFgsJobs() + && !CompatChanges.isChangeEnabled(OVERRIDE_QUOTA_ENFORCEMENT_TO_FGS_JOBS, uid)) { + return ActivityManager.PROCESS_STATE_BOUND_TOP; + } + + return ActivityManager.PROCESS_STATE_FOREGROUND_SERVICE; } private class QcHandler extends Handler { @@ -2776,7 +2815,7 @@ public final class QuotaController extends StateController { isQuotaFree = true; } else { final boolean reprocess; - if (procState <= getProcessStateQuotaFreeThreshold()) { + if (procState <= getProcessStateQuotaFreeThreshold(uid)) { reprocess = !mForegroundUids.get(uid); mForegroundUids.put(uid, true); isQuotaFree = true; diff --git a/apex/jobscheduler/service/java/com/android/server/usage/AppStandbyController.java b/apex/jobscheduler/service/java/com/android/server/usage/AppStandbyController.java index c9d340757c6bf5cf1dcfea4aa29a56a8fbd13188..9871d713178e14a609a3fadb51b5fbcee6fc9635 100644 --- a/apex/jobscheduler/service/java/com/android/server/usage/AppStandbyController.java +++ b/apex/jobscheduler/service/java/com/android/server/usage/AppStandbyController.java @@ -337,11 +337,11 @@ public class AppStandbyController */ long[] mAppStandbyElapsedThresholds = DEFAULT_ELAPSED_TIME_THRESHOLDS; /** Minimum time a strong usage event should keep the bucket elevated. */ - long mStrongUsageTimeoutMillis = ConstantsObserver.DEFAULT_STRONG_USAGE_TIMEOUT; + long mStrongUsageTimeoutMillis = ConstantsObserver.DEFAULT_LEGACY_STRONG_USAGE_TIMEOUT; /** Minimum time a notification seen event should keep the bucket elevated. */ long mNotificationSeenTimeoutMillis = ConstantsObserver.DEFAULT_NOTIFICATION_TIMEOUT; /** Minimum time a slice pinned event should keep the bucket elevated. */ - long mSlicePinnedTimeoutMillis = ConstantsObserver.DEFAULT_SLICE_PINNED_TIMEOUT; + long mSlicePinnedTimeoutMillis = ConstantsObserver.DEFAULT_LEGACY_SLICE_PINNED_TIMEOUT; /** The standby bucket that an app will be promoted on a notification-seen event */ int mNotificationSeenPromotedBucket = ConstantsObserver.DEFAULT_NOTIFICATION_SEEN_PROMOTED_BUCKET; @@ -362,7 +362,9 @@ public class AppStandbyController /** Maximum time to wait for a prediction before using simple timeouts to downgrade buckets. */ long mPredictionTimeoutMillis = DEFAULT_PREDICTION_TIMEOUT; /** Maximum time a sync adapter associated with a CP should keep the buckets elevated. */ - long mSyncAdapterTimeoutMillis = ConstantsObserver.DEFAULT_SYNC_ADAPTER_TIMEOUT; + long mSyncAdapterTimeoutMillis = ConstantsObserver.DEFAULT_LEGACY_SYNC_ADAPTER_TIMEOUT; + /** The bucket that an app will be promoted on a sync adapter associated with a CP */ + int mSyncAdapaterPromotedBucket = STANDBY_BUCKET_ACTIVE; /** * Maximum time an exempted sync should keep the buckets elevated, when sync is scheduled in * non-doze @@ -751,7 +753,7 @@ public class AppStandbyController userId); synchronized (mAppIdleLock) { reportNoninteractiveUsageCrossUserLocked(packageName, userId, - STANDBY_BUCKET_ACTIVE, REASON_SUB_USAGE_SYNC_ADAPTER, + mSyncAdapaterPromotedBucket, REASON_SUB_USAGE_SYNC_ADAPTER, elapsedRealtime, mSyncAdapterTimeoutMillis, linkedProfiles); } } @@ -2446,6 +2448,8 @@ public class AppStandbyController pw.println("Flags: "); pw.println(" " + Flags.FLAG_AVOID_IDLE_CHECK + ": " + Flags.avoidIdleCheck()); + pw.println(" " + Flags.FLAG_ADJUST_DEFAULT_BUCKET_ELEVATION_PARAMS + + ": " + Flags.adjustDefaultBucketElevationParams()); pw.println(); synchronized (mCarrierPrivilegedLock) { @@ -2481,6 +2485,9 @@ public class AppStandbyController pw.print(" mSyncAdapterTimeoutMillis="); TimeUtils.formatDuration(mSyncAdapterTimeoutMillis, pw); pw.println(); + pw.print(" mSyncAdapaterPromotedBucket="); + pw.print(standbyBucketToString(mSyncAdapaterPromotedBucket)); + pw.println(); pw.print(" mSystemInteractionTimeoutMillis="); TimeUtils.formatDuration(mSystemInteractionTimeoutMillis, pw); pw.println(); @@ -3059,12 +3066,18 @@ public class AppStandbyController public static final long DEFAULT_CHECK_IDLE_INTERVAL_MS = COMPRESS_TIME ? ONE_MINUTE : 4 * ONE_HOUR; - public static final long DEFAULT_STRONG_USAGE_TIMEOUT = + public static final long DEFAULT_LEGACY_STRONG_USAGE_TIMEOUT = COMPRESS_TIME ? ONE_MINUTE : 1 * ONE_HOUR; + + public static final long DEFAULT_CURRENT_STRONG_USAGE_TIMEOUT = + COMPRESS_TIME ? ONE_MINUTE : 5 * ONE_MINUTE; public static final long DEFAULT_NOTIFICATION_TIMEOUT = COMPRESS_TIME ? 12 * ONE_MINUTE : 12 * ONE_HOUR; - public static final long DEFAULT_SLICE_PINNED_TIMEOUT = + public static final long DEFAULT_LEGACY_SLICE_PINNED_TIMEOUT = COMPRESS_TIME ? 12 * ONE_MINUTE : 12 * ONE_HOUR; + + public static final long DEFAULT_CURRENT_SLICE_PINNED_TIMEOUT = + COMPRESS_TIME ? 12 * ONE_MINUTE : 2 * ONE_HOUR; public static final int DEFAULT_NOTIFICATION_SEEN_PROMOTED_BUCKET = STANDBY_BUCKET_WORKING_SET; public static final boolean DEFAULT_RETAIN_NOTIFICATION_SEEN_IMPACT_FOR_PRE_T_APPS = false; @@ -3073,8 +3086,11 @@ public class AppStandbyController COMPRESS_TIME ? 2 * ONE_MINUTE : 2 * ONE_HOUR; public static final long DEFAULT_SYSTEM_INTERACTION_TIMEOUT = COMPRESS_TIME ? ONE_MINUTE : 10 * ONE_MINUTE; - public static final long DEFAULT_SYNC_ADAPTER_TIMEOUT = + public static final long DEFAULT_LEGACY_SYNC_ADAPTER_TIMEOUT = COMPRESS_TIME ? ONE_MINUTE : 10 * ONE_MINUTE; + + public static final long DEFAULT_CURRENT_SYNC_ADAPTER_TIMEOUT = + COMPRESS_TIME ? ONE_MINUTE : 2 * ONE_HOUR; public static final long DEFAULT_EXEMPTED_SYNC_SCHEDULED_NON_DOZE_TIMEOUT = COMPRESS_TIME ? (ONE_MINUTE / 2) : 10 * ONE_MINUTE; public static final long DEFAULT_EXEMPTED_SYNC_SCHEDULED_DOZE_TIMEOUT = @@ -3117,6 +3133,9 @@ public class AppStandbyController cr.registerContentObserver(Global.getUriFor(Global.ADAPTIVE_BATTERY_MANAGEMENT_ENABLED), false, this); mInjector.registerDeviceConfigPropertiesChangedListener(this); + + processDefaultConstants(); + // Load all the constants. // postOneTimeCheckIdleStates() doesn't need to be called on boot. processProperties(mInjector.getDeviceConfigProperties()); @@ -3135,6 +3154,17 @@ public class AppStandbyController postOneTimeCheckIdleStates(); } + private void processDefaultConstants() { + if (!Flags.adjustDefaultBucketElevationParams()) { + return; + } + + mSlicePinnedTimeoutMillis = DEFAULT_CURRENT_SLICE_PINNED_TIMEOUT; + mSyncAdapterTimeoutMillis = DEFAULT_CURRENT_SYNC_ADAPTER_TIMEOUT; + mSyncAdapaterPromotedBucket = STANDBY_BUCKET_WORKING_SET; + mStrongUsageTimeoutMillis = DEFAULT_CURRENT_STRONG_USAGE_TIMEOUT; + } + private void processProperties(DeviceConfig.Properties properties) { boolean timeThresholdsUpdated = false; synchronized (mAppIdleLock) { @@ -3182,11 +3212,16 @@ public class AppStandbyController case KEY_SLICE_PINNED_HOLD_DURATION: mSlicePinnedTimeoutMillis = properties.getLong( KEY_SLICE_PINNED_HOLD_DURATION, - DEFAULT_SLICE_PINNED_TIMEOUT); + Flags.adjustDefaultBucketElevationParams() + ? DEFAULT_CURRENT_SLICE_PINNED_TIMEOUT + : DEFAULT_LEGACY_SLICE_PINNED_TIMEOUT); break; case KEY_STRONG_USAGE_HOLD_DURATION: mStrongUsageTimeoutMillis = properties.getLong( - KEY_STRONG_USAGE_HOLD_DURATION, DEFAULT_STRONG_USAGE_TIMEOUT); + KEY_STRONG_USAGE_HOLD_DURATION, + Flags.adjustDefaultBucketElevationParams() + ? DEFAULT_CURRENT_STRONG_USAGE_TIMEOUT + : DEFAULT_LEGACY_STRONG_USAGE_TIMEOUT); break; case KEY_PREDICTION_TIMEOUT: mPredictionTimeoutMillis = properties.getLong( @@ -3203,7 +3238,10 @@ public class AppStandbyController break; case KEY_SYNC_ADAPTER_HOLD_DURATION: mSyncAdapterTimeoutMillis = properties.getLong( - KEY_SYNC_ADAPTER_HOLD_DURATION, DEFAULT_SYNC_ADAPTER_TIMEOUT); + KEY_SYNC_ADAPTER_HOLD_DURATION, + Flags.adjustDefaultBucketElevationParams() + ? DEFAULT_CURRENT_SYNC_ADAPTER_TIMEOUT + : DEFAULT_LEGACY_SYNC_ADAPTER_TIMEOUT); break; case KEY_EXEMPTED_SYNC_SCHEDULED_DOZE_HOLD_DURATION: mExemptedSyncScheduledDozeTimeoutMillis = properties.getLong( diff --git a/boot/boot-image-profile-extra.txt b/boot/boot-image-profile-extra.txt index e31eb3a993f0f59038ffbdc16330d2e330deb580..fd51f9cbcee1eee2d4f8d18f79002dd759eea832 100644 --- a/boot/boot-image-profile-extra.txt +++ b/boot/boot-image-profile-extra.txt @@ -23,4 +23,25 @@ HSPLandroid/graphics/Color;->luminance()F # For now, compile all methods in MessageQueue to avoid performance cliffs for # flagged/evolving hot code paths. See: b/338098106 HSPLandroid/os/MessageQueue;->* -HSPLandroid/os/MessageQueue$*;->* +HSPLandroid/os/MessageQueue$FileDescriptorRecord;->* +HSPLandroid/os/MessageQueue$IdleHandler;->* +HSPLandroid/os/MessageQueue$MessageCompare;->* +HSPLandroid/os/MessageQueue$MatchAllFutureMessages;->* +HSPLandroid/os/MessageQueue$MatchAllMessages;->* +HSPLandroid/os/MessageQueue$MatchBarrierToken;->* +HSPLandroid/os/MessageQueue$MatchDeliverableMessages;->* +HSPLandroid/os/MessageQueue$MatchHandler;->* +HSPLandroid/os/MessageQueue$MatchHandlerAndObject;->* +HSPLandroid/os/MessageQueue$MatchHandlerAndObjectEquals;->* +HSPLandroid/os/MessageQueue$MatchHandlerRunnableAndObject;->* +HSPLandroid/os/MessageQueue$MatchHandlerRunnableAndObjectEquals;->* +HSPLandroid/os/MessageQueue$MatchHandlerWhatAndObject;->* +HSPLandroid/os/MessageQueue$MatchHandlerWhatAndObjectEquals;->* +HSPLandroid/os/MessageQueue$MessageCounts;->* +HSPLandroid/os/MessageQueue$StackNode;->* +HSPLandroid/os/MessageQueue$MessageNode;->* +HSPLandroid/os/MessageQueue$OnFileDescriptorEventListener$Events;->* +HSPLandroid/os/MessageQueue$OnFileDescriptorEventListener;->* +HSPLandroid/os/MessageQueue$StackNodeType;->* +HSPLandroid/os/MessageQueue$StateNode;->* +HSPLandroid/os/MessageQueue$TimedParkStateNode;->* diff --git a/cmds/idmap2/idmap2/CreateMultiple.cpp b/cmds/idmap2/idmap2/CreateMultiple.cpp index 68800cde610175e29bdcf75edd0effb035ebf09c..2608c69be66f8fedb81380683a297f03954b7995 100644 --- a/cmds/idmap2/idmap2/CreateMultiple.cpp +++ b/cmds/idmap2/idmap2/CreateMultiple.cpp @@ -99,7 +99,7 @@ Result CreateMultiple(const std::vector& args) { std::vector idmap_paths; for (const std::string& overlay_apk_path : overlay_apk_paths) { - const std::string idmap_path = Idmap::CanonicalIdmapPathFor(idmap_dir, overlay_apk_path); + std::string idmap_path = Idmap::CanonicalIdmapPathFor(idmap_dir, overlay_apk_path); const uid_t uid = getuid(); if (!UidHasWriteAccessToPath(uid, idmap_path)) { LOG(WARNING) << "uid " << uid << "does not have write access to " << idmap_path.c_str(); @@ -111,7 +111,7 @@ Result CreateMultiple(const std::vector& args) { !ignore_overlayable)) { const auto overlay = OverlayResourceContainer::FromPath(overlay_apk_path); if (!overlay) { - LOG(WARNING) << "failed to load apk " << overlay_apk_path.c_str(); + LOG(WARNING) << "failed to load apk " << overlay_apk_path; continue; } @@ -138,7 +138,7 @@ Result CreateMultiple(const std::vector& args) { } } - idmap_paths.emplace_back(idmap_path); + idmap_paths.emplace_back(std::move(idmap_path)); } for (const std::string& idmap_path : idmap_paths) { diff --git a/cmds/interrupter/Android.bp b/cmds/interrupter/Android.bp deleted file mode 100644 index d7f744d0834e00dfeae37eac1ff4fb02827f36dc..0000000000000000000000000000000000000000 --- a/cmds/interrupter/Android.bp +++ /dev/null @@ -1,20 +0,0 @@ -package { - // See: http://go/android-license-faq - // A large-scale-change added 'default_applicable_licenses' to import - // all of the 'license_kinds' from "frameworks_base_license" - // to get the below license kinds: - // SPDX-license-identifier-Apache-2.0 - default_applicable_licenses: ["frameworks_base_license"], -} - -cc_library_shared { - name: "interrupter", - host_supported: true, - srcs: ["interrupter.c"], - cflags: [ - "-Wall", - "-Werror", - "-Wunused", - "-Wunreachable-code", - ], -} diff --git a/cmds/interrupter/interrupter.c b/cmds/interrupter/interrupter.c deleted file mode 100644 index ae555150c969467f3d74bc42620838660de0230a..0000000000000000000000000000000000000000 --- a/cmds/interrupter/interrupter.c +++ /dev/null @@ -1,53 +0,0 @@ -/* - * Copyright 2012, The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - - -/** - * The probability of a syscall failing from 0.0 to 1.0 - */ -#define PROBABILITY 0.9 - - - -#include -#include -#include - -/* for various intercepted calls */ -#include -#include -#include -#include - -/* For builds on glibc */ -#define __USE_GNU -#include - -#include "interrupter.h" - -static int probability = PROBABILITY * RAND_MAX; - -static int maybe_interrupt() { - if (rand() < probability) { - return 1; - } - return 0; -} - -DEFINE_INTERCEPT(read, ssize_t, int, void*, size_t); -DEFINE_INTERCEPT(write, ssize_t, int, const void*, size_t); -DEFINE_INTERCEPT(accept, int, int, struct sockaddr*, socklen_t*); -DEFINE_INTERCEPT(creat, int, const char*, mode_t); diff --git a/cmds/interrupter/interrupter.h b/cmds/interrupter/interrupter.h deleted file mode 100644 index 9ad0277eebbe407b3dca1d44ed9b8768370ab07d..0000000000000000000000000000000000000000 --- a/cmds/interrupter/interrupter.h +++ /dev/null @@ -1,79 +0,0 @@ -/* - * Copyright 2012, The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT 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 CONCATENATE(arg1, arg2) CONCATENATE1(arg1, arg2) -#define CONCATENATE1(arg1, arg2) CONCATENATE2(arg1, arg2) -#define CONCATENATE2(arg1, arg2) arg1##arg2 - -#define INTERRUPTER(sym) \ - if (real_##sym == NULL) \ - __init_##sym(); \ - if (maybe_interrupt()) { \ - errno = EINTR; \ - return -1; \ - } - -#define CALL_FUNCTION_1(sym, ret, type1) \ -ret (*real_##sym)(type1) = NULL; \ -ret sym(type1 arg1) { \ - INTERRUPTER(sym) \ - return real_##sym(arg1); \ -} - -#define CALL_FUNCTION_2(sym, ret, type1, type2) \ -ret (*real_##sym)(type1, type2) = NULL; \ -ret sym(type1 arg1, type2 arg2) { \ - INTERRUPTER(sym) \ - return real_##sym(arg1, arg2); \ -} - -#define CALL_FUNCTION_3(sym, ret, type1, type2, type3) \ -ret (*real_##sym)(type1, type2, type3) = NULL; \ -ret sym(type1 arg1, type2 arg2, type3 arg3) { \ - INTERRUPTER(sym) \ - return real_##sym(arg1, arg2, arg3); \ -} - -#define CALL_FUNCTION_4(sym, ret, type1, type2, type3, type4) \ -ret (*real_##sym)(type1, type2, type3, type4) = NULL; \ -ret sym(type1 arg1, type2 arg2, type3 arg3, type4 arg4) { \ - INTERRUPTER(sym) \ - return real_##sym(arg1, arg2, arg3, arg4); \ -} - -#define CALL_FUNCTION_5(sym, ret, type1, type2, type3, type4, type5) \ -ret (*real_##sym)(type1, type2, type3, type4, type5) = NULL; \ -ret sym(type1 arg1, type2 arg2, type3 arg3, type4 arg4, type5 arg5) { \ - INTERRUPTER(sym) \ - return real_##sym(arg1, arg2, arg3, arg4, arg5); \ -} - -#define DEFINE_INTERCEPT_N(N, sym, ret, ...) \ -static void __init_##sym(void); \ -CONCATENATE(CALL_FUNCTION_, N)(sym, ret, __VA_ARGS__) \ -static void __init_##sym(void) { \ - real_##sym = dlsym(RTLD_NEXT, #sym); \ - if (real_##sym == NULL) { \ - fprintf(stderr, "Error hooking " #sym ": %s\n", dlerror()); \ - } \ -} - -#define INTERCEPT_NARG(...) INTERCEPT_NARG_N(__VA_ARGS__, INTERCEPT_RSEQ_N()) -#define INTERCEPT_NARG_N(...) INTERCEPT_ARG_N(__VA_ARGS__) -#define INTERCEPT_ARG_N(_1, _2, _3, _4, _5, _6, _7, _8, N, ...) N -#define INTERCEPT_RSEQ_N() 8, 7, 6, 5, 4, 3, 2, 1, 0 - -#define DEFINE_INTERCEPT(sym, ret, ...) DEFINE_INTERCEPT_N(INTERCEPT_NARG(__VA_ARGS__), sym, ret, __VA_ARGS__) diff --git a/core/api/current.txt b/core/api/current.txt index c83212feab6739d32431708b91e96783d053f6cc..af7d6f1a5da1a8d514b3a930b6c04f782d805824 100644 --- a/core/api/current.txt +++ b/core/api/current.txt @@ -1502,6 +1502,7 @@ package android { field public static final int shadowRadius = 16843108; // 0x1010164 field public static final int shape = 16843162; // 0x101019a field public static final int shareInterpolator = 16843195; // 0x10101bb + field @FlaggedApi("android.nfc.nfc_associated_role_services") public static final int shareRolePriority; field @Deprecated public static final int sharedUserId = 16842763; // 0x101000b field @Deprecated public static final int sharedUserLabel = 16843361; // 0x1010261 field public static final int sharedUserMaxSdkVersion = 16844365; // 0x101064d @@ -2451,6 +2452,7 @@ package android { field public static final int primary = 16908300; // 0x102000c field public static final int progress = 16908301; // 0x102000d field public static final int redo = 16908339; // 0x1020033 + field @FlaggedApi("android.appwidget.flags.engagement_metrics") public static final int remoteViewsMetricsId; field public static final int replaceText = 16908340; // 0x1020034 field public static final int secondaryProgress = 16908303; // 0x102000f field public static final int selectAll = 16908319; // 0x102001f @@ -3830,7 +3832,7 @@ package android.accounts { method @RequiresPermission(value="android.permission.AUTHENTICATE_ACCOUNTS", apis="..22") public boolean notifyAccountAuthenticated(android.accounts.Account); method @RequiresPermission(value="android.permission.AUTHENTICATE_ACCOUNTS", apis="..22") public String peekAuthToken(android.accounts.Account, String); method @Deprecated @RequiresPermission(value="android.permission.MANAGE_ACCOUNTS", apis="..22") public android.accounts.AccountManagerFuture removeAccount(android.accounts.Account, android.accounts.AccountManagerCallback, android.os.Handler); - method @RequiresPermission(value="android.permission.MANAGE_ACCOUNTS", apis="..22") public android.accounts.AccountManagerFuture removeAccount(android.accounts.Account, android.app.Activity, android.accounts.AccountManagerCallback, android.os.Handler); + method @FlaggedApi("android.app.admin.flags.split_create_managed_profile_enabled") @RequiresPermission(value="android.permission.REMOVE_ACCOUNTS", conditional=true) public android.accounts.AccountManagerFuture removeAccount(android.accounts.Account, android.app.Activity, android.accounts.AccountManagerCallback, android.os.Handler); method @RequiresPermission(value="android.permission.AUTHENTICATE_ACCOUNTS", apis="..22") public boolean removeAccountExplicitly(android.accounts.Account); method public void removeOnAccountsUpdatedListener(android.accounts.OnAccountsUpdateListener); method @RequiresPermission(value="android.permission.AUTHENTICATE_ACCOUNTS", apis="..22") public android.accounts.AccountManagerFuture renameAccount(android.accounts.Account, @Size(min=1) String, android.accounts.AccountManagerCallback, android.os.Handler); @@ -4614,6 +4616,7 @@ package android.app { method public void reportFullyDrawn(); method public android.view.DragAndDropPermissions requestDragAndDropPermissions(android.view.DragEvent); method public void requestFullscreenMode(int, @Nullable android.os.OutcomeReceiver); + method @FlaggedApi("com.android.window.flags.enable_desktop_windowing_app_to_web_education") public final void requestOpenInBrowserEducation(); method public final void requestPermissions(@NonNull String[], int); method @FlaggedApi("android.permission.flags.device_aware_permission_apis_enabled") public final void requestPermissions(@NonNull String[], int, int); method public final void requestShowKeyboardShortcuts(); @@ -4639,7 +4642,6 @@ package android.app { method public void setInheritShowWhenLocked(boolean); method public void setIntent(android.content.Intent); method @FlaggedApi("android.security.content_uri_permission_apis") public void setIntent(@Nullable android.content.Intent, @Nullable android.app.ComponentCaller); - method @FlaggedApi("com.android.window.flags.enable_desktop_windowing_app_to_web_education") public final void setLimitSystemEducationDialogs(boolean); method public void setLocusContext(@Nullable android.content.LocusId, @Nullable android.os.Bundle); method public final void setMediaController(android.media.session.MediaController); method public void setPictureInPictureParams(@NonNull android.app.PictureInPictureParams); @@ -5110,8 +5112,11 @@ package android.app { } public class AppOpsManager { - method @Deprecated public int checkOp(@NonNull String, int, @NonNull String); - method @Deprecated public int checkOpNoThrow(@NonNull String, int, @NonNull String); + method @FlaggedApi("android.permission.flags.check_op_overload_api_enabled") public int checkOp(@NonNull String, int, @NonNull String); + method @FlaggedApi("android.permission.flags.check_op_overload_api_enabled") public int checkOp(@NonNull String, int, @NonNull String, @Nullable String); + method @FlaggedApi("android.permission.flags.check_op_overload_api_enabled") public int checkOpNoThrow(@NonNull String, int, @NonNull String, @Nullable String); + method @FlaggedApi("android.permission.flags.check_op_overload_api_enabled") public int checkOpNoThrow(@NonNull String, int, @NonNull String); + method @FlaggedApi("android.permission.flags.check_op_overload_api_enabled") public int checkOpRawNoThrow(@NonNull String, int, @NonNull String, @Nullable String); method @Deprecated public void checkPackage(int, @NonNull String); method @Deprecated public void finishOp(@NonNull String, int, @NonNull String); method public void finishOp(@NonNull String, int, @NonNull String, @Nullable String); @@ -5140,10 +5145,10 @@ package android.app { method public void startWatchingMode(@NonNull String, @Nullable String, int, @NonNull android.app.AppOpsManager.OnOpChangedListener); method public void stopWatchingActive(@NonNull android.app.AppOpsManager.OnOpActiveChangedListener); method public void stopWatchingMode(@NonNull android.app.AppOpsManager.OnOpChangedListener); - method public int unsafeCheckOp(@NonNull String, int, @NonNull String); - method public int unsafeCheckOpNoThrow(@NonNull String, int, @NonNull String); - method public int unsafeCheckOpRaw(@NonNull String, int, @NonNull String); - method public int unsafeCheckOpRawNoThrow(@NonNull String, int, @NonNull String); + method @Deprecated @FlaggedApi("android.permission.flags.check_op_overload_api_enabled") public int unsafeCheckOp(@NonNull String, int, @NonNull String); + method @Deprecated @FlaggedApi("android.permission.flags.check_op_overload_api_enabled") public int unsafeCheckOpNoThrow(@NonNull String, int, @NonNull String); + method @Deprecated @FlaggedApi("android.permission.flags.check_op_overload_api_enabled") public int unsafeCheckOpRaw(@NonNull String, int, @NonNull String); + method @Deprecated @FlaggedApi("android.permission.flags.check_op_overload_api_enabled") public int unsafeCheckOpRawNoThrow(@NonNull String, int, @NonNull String); field public static final int MODE_ALLOWED = 0; // 0x0 field public static final int MODE_DEFAULT = 3; // 0x3 field public static final int MODE_ERRORED = 2; // 0x2 @@ -9889,6 +9894,8 @@ package android.appwidget { field public static final String ACTION_APPWIDGET_PICK = "android.appwidget.action.APPWIDGET_PICK"; field public static final String ACTION_APPWIDGET_RESTORED = "android.appwidget.action.APPWIDGET_RESTORED"; field public static final String ACTION_APPWIDGET_UPDATE = "android.appwidget.action.APPWIDGET_UPDATE"; + field @FlaggedApi("android.appwidget.flags.engagement_metrics") public static final String EVENT_CATEGORY_APPWIDGET = "android.appwidget"; + field @FlaggedApi("android.appwidget.flags.engagement_metrics") public static final String EVENT_TYPE_WIDGET_INTERACTION = "widget_interaction"; field public static final String EXTRA_APPWIDGET_ID = "appWidgetId"; field public static final String EXTRA_APPWIDGET_IDS = "appWidgetIds"; field public static final String EXTRA_APPWIDGET_OLD_IDS = "appWidgetOldIds"; @@ -9898,6 +9905,10 @@ package android.appwidget { field public static final String EXTRA_APPWIDGET_PROVIDER_PROFILE = "appWidgetProviderProfile"; field public static final String EXTRA_CUSTOM_EXTRAS = "customExtras"; field public static final String EXTRA_CUSTOM_INFO = "customInfo"; + field @FlaggedApi("android.appwidget.flags.engagement_metrics") public static final String EXTRA_EVENT_CLICKED_VIEWS = "android.appwidget.extra.EVENT_CLICKED_VIEWS"; + field @FlaggedApi("android.appwidget.flags.engagement_metrics") public static final String EXTRA_EVENT_DURATION_MS = "android.appwidget.extra.EVENT_DURATION_MS"; + field @FlaggedApi("android.appwidget.flags.engagement_metrics") public static final String EXTRA_EVENT_POSITION_RECT = "android.appwidget.extra.EVENT_POSITION_RECT"; + field @FlaggedApi("android.appwidget.flags.engagement_metrics") public static final String EXTRA_EVENT_SCROLLED_VIEWS = "android.appwidget.extra.EVENT_SCROLLED_VIEWS"; field public static final String EXTRA_HOST_ID = "hostId"; field public static final int INVALID_APPWIDGET_ID = 0; // 0x0 field public static final String META_DATA_APPWIDGET_PROVIDER = "android.appwidget.provider"; @@ -13143,9 +13154,9 @@ package android.content.pm { method public void setAppLabel(@Nullable CharSequence); method public void setAppPackageName(@Nullable String); method public void setApplicationEnabledSettingPersistent(); + method @FlaggedApi("android.content.pm.sdk_dependency_installer") public void setAutoInstallDependenciesEnabled(boolean); method @Deprecated public void setAutoRevokePermissionsMode(boolean); method public void setDontKillApp(boolean); - method @FlaggedApi("android.content.pm.sdk_dependency_installer") public void setEnableAutoInstallDependencies(boolean); method public void setInstallLocation(int); method public void setInstallReason(int); method public void setInstallScenario(int); @@ -13214,8 +13225,8 @@ package android.content.pm { public abstract class PackageManager { ctor @Deprecated public PackageManager(); method @Deprecated public abstract void addPackageToPreferred(@NonNull String); - method public abstract boolean addPermission(@NonNull android.content.pm.PermissionInfo); - method public abstract boolean addPermissionAsync(@NonNull android.content.pm.PermissionInfo); + method @Deprecated @FlaggedApi("android.permission.flags.permission_tree_apis_deprecated") public abstract boolean addPermission(@NonNull android.content.pm.PermissionInfo); + method @Deprecated @FlaggedApi("android.permission.flags.permission_tree_apis_deprecated") public abstract boolean addPermissionAsync(@NonNull android.content.pm.PermissionInfo); method @Deprecated public abstract void addPreferredActivity(@NonNull android.content.IntentFilter, int, @Nullable android.content.ComponentName[], @NonNull android.content.ComponentName); method @RequiresPermission(value="android.permission.WHITELIST_RESTRICTED_PERMISSIONS", conditional=true) public boolean addWhitelistedRestrictedPermission(@NonNull String, @NonNull String, int); method public boolean canPackageQuery(@NonNull String, @NonNull String) throws android.content.pm.PackageManager.NameNotFoundException; @@ -13356,7 +13367,7 @@ package android.content.pm { method @NonNull public java.util.List queryServiceProperty(@NonNull String); method public void relinquishUpdateOwnership(@NonNull String); method @Deprecated public abstract void removePackageFromPreferred(@NonNull String); - method public abstract void removePermission(@NonNull String); + method @Deprecated @FlaggedApi("android.permission.flags.permission_tree_apis_deprecated") public abstract void removePermission(@NonNull String); method @RequiresPermission(value="android.permission.WHITELIST_RESTRICTED_PERMISSIONS", conditional=true) public boolean removeWhitelistedRestrictedPermission(@NonNull String, @NonNull String, int); method public void requestChecksums(@NonNull String, boolean, int, @NonNull java.util.List, @NonNull android.content.pm.PackageManager.OnChecksumsReadyListener) throws java.security.cert.CertificateEncodingException, android.content.pm.PackageManager.NameNotFoundException; method @Nullable public abstract android.content.pm.ResolveInfo resolveActivity(@NonNull android.content.Intent, int); @@ -13396,6 +13407,7 @@ package android.content.pm { field public static final String FEATURE_BACKUP = "android.software.backup"; field public static final String FEATURE_BLUETOOTH = "android.hardware.bluetooth"; field public static final String FEATURE_BLUETOOTH_LE = "android.hardware.bluetooth_le"; + field @FlaggedApi("com.android.ranging.flags.ranging_cs_enabled") public static final String FEATURE_BLUETOOTH_LE_CHANNEL_SOUNDING = "android.hardware.bluetooth_le.channel_sounding"; field public static final String FEATURE_CAMERA = "android.hardware.camera"; field public static final String FEATURE_CAMERA_ANY = "android.hardware.camera.any"; field public static final String FEATURE_CAMERA_AR = "android.hardware.camera.ar"; @@ -13805,7 +13817,7 @@ package android.content.pm { field @RequiresPermission(allOf={android.Manifest.permission.FOREGROUND_SERVICE_CAMERA}, anyOf={android.Manifest.permission.CAMERA}, conditional=true) public static final int FOREGROUND_SERVICE_TYPE_CAMERA = 64; // 0x40 field @RequiresPermission(allOf={android.Manifest.permission.FOREGROUND_SERVICE_CONNECTED_DEVICE}, anyOf={android.Manifest.permission.BLUETOOTH_ADVERTISE, android.Manifest.permission.BLUETOOTH_CONNECT, android.Manifest.permission.BLUETOOTH_SCAN, android.Manifest.permission.CHANGE_NETWORK_STATE, android.Manifest.permission.CHANGE_WIFI_STATE, android.Manifest.permission.CHANGE_WIFI_MULTICAST_STATE, android.Manifest.permission.NFC, android.Manifest.permission.TRANSMIT_IR, android.Manifest.permission.UWB_RANGING, android.Manifest.permission.RANGING}, conditional=true) public static final int FOREGROUND_SERVICE_TYPE_CONNECTED_DEVICE = 16; // 0x10 field @RequiresPermission(value=android.Manifest.permission.FOREGROUND_SERVICE_DATA_SYNC, conditional=true) public static final int FOREGROUND_SERVICE_TYPE_DATA_SYNC = 1; // 0x1 - field @RequiresPermission(allOf={android.Manifest.permission.FOREGROUND_SERVICE_HEALTH}, anyOf={android.Manifest.permission.ACTIVITY_RECOGNITION, android.Manifest.permission.BODY_SENSORS, android.Manifest.permission.HIGH_SAMPLING_RATE_SENSORS}) public static final int FOREGROUND_SERVICE_TYPE_HEALTH = 256; // 0x100 + field @FlaggedApi("android.permission.flags.replace_body_sensor_permission_enabled") @RequiresPermission(allOf={android.Manifest.permission.FOREGROUND_SERVICE_HEALTH}, anyOf={android.Manifest.permission.ACTIVITY_RECOGNITION, android.Manifest.permission.HIGH_SAMPLING_RATE_SENSORS, android.health.connect.HealthPermissions.READ_HEART_RATE, android.health.connect.HealthPermissions.READ_SKIN_TEMPERATURE, android.health.connect.HealthPermissions.READ_OXYGEN_SATURATION}) public static final int FOREGROUND_SERVICE_TYPE_HEALTH = 256; // 0x100 field @RequiresPermission(allOf={android.Manifest.permission.FOREGROUND_SERVICE_LOCATION}, anyOf={android.Manifest.permission.ACCESS_COARSE_LOCATION, android.Manifest.permission.ACCESS_FINE_LOCATION}, conditional=true) public static final int FOREGROUND_SERVICE_TYPE_LOCATION = 8; // 0x8 field public static final int FOREGROUND_SERVICE_TYPE_MANIFEST = -1; // 0xffffffff field @RequiresPermission(value=android.Manifest.permission.FOREGROUND_SERVICE_MEDIA_PLAYBACK, conditional=true) public static final int FOREGROUND_SERVICE_TYPE_MEDIA_PLAYBACK = 2; // 0x2 @@ -18950,6 +18962,7 @@ package android.hardware { method @FlaggedApi("android.hardware.flags.luts_api") @NonNull public int[] getSamplingKeys(); method @FlaggedApi("android.hardware.flags.luts_api") public int getSize(); field @FlaggedApi("android.hardware.flags.luts_api") public static final int ONE_DIMENSION = 1; // 0x1 + field @FlaggedApi("android.hardware.flags.luts_api") public static final int SAMPLING_KEY_CIE_Y = 2; // 0x2 field @FlaggedApi("android.hardware.flags.luts_api") public static final int SAMPLING_KEY_MAX_RGB = 1; // 0x1 field @FlaggedApi("android.hardware.flags.luts_api") public static final int SAMPLING_KEY_RGB = 0; // 0x0 field @FlaggedApi("android.hardware.flags.luts_api") public static final int THREE_DIMENSION = 3; // 0x3 @@ -21094,6 +21107,7 @@ package android.inputmethodservice { method public abstract android.inputmethodservice.AbstractInputMethodService.AbstractInputMethodImpl onCreateInputMethodInterface(); method public abstract android.inputmethodservice.AbstractInputMethodService.AbstractInputMethodSessionImpl onCreateInputMethodSessionInterface(); method public boolean onGenericMotionEvent(android.view.MotionEvent); + method @FlaggedApi("android.view.inputmethod.verify_key_event") public boolean onShouldVerifyKeyEvent(@NonNull android.view.KeyEvent); method public boolean onTrackballEvent(android.view.MotionEvent); } @@ -21111,6 +21125,7 @@ package android.inputmethodservice { method public void dispatchTrackballEvent(int, android.view.MotionEvent, android.view.inputmethod.InputMethodSession.EventCallback); method public boolean isEnabled(); method public boolean isRevoked(); + method @FlaggedApi("android.view.inputmethod.verify_key_event") public boolean onShouldVerifyKeyEvent(@NonNull android.view.KeyEvent); method public void revokeSelf(); method public void setEnabled(boolean); } @@ -21210,6 +21225,7 @@ package android.inputmethodservice { method public void setExtractView(android.view.View); method public void setExtractViewShown(boolean); method public void setInputView(android.view.View); + method @FlaggedApi("android.view.inputmethod.adaptive_handwriting_bounds") public final void setStylusHandwritingRegion(@NonNull android.graphics.Region); method public final void setStylusHandwritingSessionTimeout(@NonNull java.time.Duration); method public final boolean shouldOfferSwitchingToNextInputMethod(); method public void showStatusIcon(@DrawableRes int); @@ -23186,7 +23202,6 @@ package android.media { method public boolean isVendor(); field @FlaggedApi("android.media.codec.in_process_sw_audio_codec") public static final int SECURITY_MODEL_MEMORY_SAFE = 1; // 0x1 field @FlaggedApi("android.media.codec.in_process_sw_audio_codec") public static final int SECURITY_MODEL_SANDBOXED = 0; // 0x0 - field @FlaggedApi("android.media.codec.in_process_sw_audio_codec") public static final int SECURITY_MODEL_TRUSTED_CONTENT_ONLY = 2; // 0x2 } public static final class MediaCodecInfo.AudioCapabilities { @@ -23503,6 +23518,18 @@ package android.media { field public static final int HEVCProfileMain10HDR10 = 4096; // 0x1000 field public static final int HEVCProfileMain10HDR10Plus = 8192; // 0x2000 field public static final int HEVCProfileMainStill = 4; // 0x4 + field @FlaggedApi("android.media.audio.iamf_definitions_api") public static final int IAMFProfileBaseAac = 16908290; // 0x1020002 + field @FlaggedApi("android.media.audio.iamf_definitions_api") public static final int IAMFProfileBaseEnhancedAac = 17039362; // 0x1040002 + field @FlaggedApi("android.media.audio.iamf_definitions_api") public static final int IAMFProfileBaseEnhancedFlac = 17039364; // 0x1040004 + field @FlaggedApi("android.media.audio.iamf_definitions_api") public static final int IAMFProfileBaseEnhancedOpus = 17039361; // 0x1040001 + field @FlaggedApi("android.media.audio.iamf_definitions_api") public static final int IAMFProfileBaseEnhancedPcm = 17039368; // 0x1040008 + field @FlaggedApi("android.media.audio.iamf_definitions_api") public static final int IAMFProfileBaseFlac = 16908292; // 0x1020004 + field @FlaggedApi("android.media.audio.iamf_definitions_api") public static final int IAMFProfileBaseOpus = 16908289; // 0x1020001 + field @FlaggedApi("android.media.audio.iamf_definitions_api") public static final int IAMFProfileBasePcm = 16908296; // 0x1020008 + field @FlaggedApi("android.media.audio.iamf_definitions_api") public static final int IAMFProfileSimpleAac = 16842754; // 0x1010002 + field @FlaggedApi("android.media.audio.iamf_definitions_api") public static final int IAMFProfileSimpleFlac = 16842756; // 0x1010004 + field @FlaggedApi("android.media.audio.iamf_definitions_api") public static final int IAMFProfileSimpleOpus = 16842753; // 0x1010001 + field @FlaggedApi("android.media.audio.iamf_definitions_api") public static final int IAMFProfileSimplePcm = 16842760; // 0x1010008 field public static final int MPEG2LevelH14 = 2; // 0x2 field public static final int MPEG2LevelHL = 3; // 0x3 field public static final int MPEG2LevelHP = 4; // 0x4 @@ -24077,7 +24104,6 @@ package android.media { field public static final int COLOR_TRANSFER_ST2084 = 6; // 0x6 field @FlaggedApi("android.media.codec.in_process_sw_audio_codec") public static final int FLAG_SECURITY_MODEL_MEMORY_SAFE = 2; // 0x2 field @FlaggedApi("android.media.codec.in_process_sw_audio_codec") public static final int FLAG_SECURITY_MODEL_SANDBOXED = 1; // 0x1 - field @FlaggedApi("android.media.codec.in_process_sw_audio_codec") public static final int FLAG_SECURITY_MODEL_TRUSTED_CONTENT_ONLY = 4; // 0x4 field public static final String KEY_AAC_DRC_ALBUM_MODE = "aac-drc-album-mode"; field public static final String KEY_AAC_DRC_ATTENUATION_FACTOR = "aac-drc-cut-level"; field public static final String KEY_AAC_DRC_BOOST_FACTOR = "aac-drc-boost-level"; @@ -24149,6 +24175,8 @@ package android.media { field public static final String KEY_OPERATING_RATE = "operating-rate"; field public static final String KEY_OUTPUT_REORDER_DEPTH = "output-reorder-depth"; field public static final String KEY_PCM_ENCODING = "pcm-encoding"; + field @FlaggedApi("android.media.tv.flags.apply_picture_profiles") public static final String KEY_PICTURE_PROFILE_ID = "picture-profile-id"; + field @FlaggedApi("android.media.tv.flags.apply_picture_profiles") public static final String KEY_PICTURE_PROFILE_INSTANCE = "picture-profile-instance"; field public static final String KEY_PICTURE_TYPE = "picture-type"; field public static final String KEY_PIXEL_ASPECT_RATIO_HEIGHT = "sar-height"; field public static final String KEY_PIXEL_ASPECT_RATIO_WIDTH = "sar-width"; @@ -24201,6 +24229,7 @@ package android.media { field public static final String MIMETYPE_AUDIO_FLAC = "audio/flac"; field public static final String MIMETYPE_AUDIO_G711_ALAW = "audio/g711-alaw"; field public static final String MIMETYPE_AUDIO_G711_MLAW = "audio/g711-mlaw"; + field @FlaggedApi("android.media.audio.iamf_definitions_api") public static final String MIMETYPE_AUDIO_IAMF = "audio/iamf"; field public static final String MIMETYPE_AUDIO_IEC61937 = "audio/x-iec61937"; field public static final String MIMETYPE_AUDIO_MPEG = "audio/mpeg"; field public static final String MIMETYPE_AUDIO_MPEGH_BL_L3 = "audio/mhm1.03"; @@ -25595,6 +25624,7 @@ package android.media { method public void addOnSpatializerStateChangedListener(@NonNull java.util.concurrent.Executor, @NonNull android.media.Spatializer.OnSpatializerStateChangedListener); method public boolean canBeSpatialized(@NonNull android.media.AudioAttributes, @NonNull android.media.AudioFormat); method public int getImmersiveAudioLevel(); + method @FlaggedApi("android.media.audio.spatializer_capabilities") @NonNull public java.util.List getSpatializedChannelMasks(); method public boolean isAvailable(); method public boolean isEnabled(); method public boolean isHeadTrackerAvailable(); @@ -27057,6 +27087,53 @@ package android.media.projection { package android.media.quality { + @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(); + method public int getEventType(); + method @Nullable public android.media.quality.AmbientBacklightMetadata getMetadata(); + method public void writeToParcel(@NonNull android.os.Parcel, int); + field public static final int AMBIENT_BACKLIGHT_EVENT_DISABLED = 2; // 0x2 + field public static final int AMBIENT_BACKLIGHT_EVENT_ENABLED = 1; // 0x1 + field public static final int AMBIENT_BACKLIGHT_EVENT_INTERRUPTED = 4; // 0x4 + field public static final int AMBIENT_BACKLIGHT_EVENT_METADATA = 3; // 0x3 + field @NonNull public static final android.os.Parcelable.Creator CREATOR; + } + + @FlaggedApi("android.media.tv.flags.media_quality_fw") public final class AmbientBacklightMetadata implements android.os.Parcelable { + ctor public AmbientBacklightMetadata(@NonNull String, int, int, int, int, int, @NonNull int[]); + method public int describeContents(); + method public int getColorFormat(); + method public int getCompressAlgorithm(); + method @IntRange(from=0) public int getHorizontalZonesNumber(); + method @NonNull public String getPackageName(); + method public int getSource(); + method @IntRange(from=0) 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; + } + + @FlaggedApi("android.media.tv.flags.media_quality_fw") public final class AmbientBacklightSettings implements android.os.Parcelable { + ctor public AmbientBacklightSettings(int, int, int, int, int, boolean, int); + method public int describeContents(); + method public int getColorFormat(); + method @IntRange(from=0) public int getHorizontalZonesNumber(); + method @IntRange(from=1) public int getMaxFps(); + method public int getSource(); + method public int getThreshold(); + method @IntRange(from=0) public int getVerticalZonesNumber(); + method public boolean isLetterboxOmitted(); + method public void writeToParcel(@NonNull android.os.Parcel, int); + field public static final int ALGORITHM_NONE = 0; // 0x0 + field public static final int ALGORITHM_RLE = 1; // 0x1 + field @NonNull public static final android.os.Parcelable.Creator CREATOR; + field public static final int SOURCE_AUDIO = 1; // 0x1 + field public static final int SOURCE_AUDIO_VIDEO = 3; // 0x3 + field public static final int SOURCE_NONE = 0; // 0x0 + field public static final int SOURCE_VIDEO = 2; // 0x2 + } + @FlaggedApi("android.media.tv.flags.media_quality_fw") public class MediaQualityContract { } @@ -27067,17 +27144,41 @@ package android.media.quality { field public static final String PARAMETER_SHARPNESS = "sharpness"; } + public static final class MediaQualityContract.SoundQuality { + field public static final String PARAMETER_BALANCE = "balance"; + field public static final String PARAMETER_BASS = "bass"; + field public static final String PARAMETER_TREBLE = "treble"; + } + @FlaggedApi("android.media.tv.flags.media_quality_fw") public final class MediaQualityManager { 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 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 public boolean isAmbientBacklightEnabled(); method public boolean isAutoPictureQualityEnabled(); + method public boolean isAutoSoundQualityEnabled(); method public boolean isSuperResolutionEnabled(); + 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 removePictureProfile(@NonNull String); + method public void removeSoundProfile(@NonNull String); + method public void setAmbientBacklightEnabled(boolean); + method public void setAmbientBacklightSettings(@NonNull android.media.quality.AmbientBacklightSettings); + method public void unregisterAmbientBacklightCallback(@NonNull android.media.quality.MediaQualityManager.AmbientBacklightCallback); method public void unregisterPictureProfileCallback(@NonNull android.media.quality.MediaQualityManager.PictureProfileCallback); + method public void unregisterSoundProfileCallback(@NonNull android.media.quality.MediaQualityManager.SoundProfileCallback); method public void updatePictureProfile(@NonNull String, @NonNull android.media.quality.PictureProfile); + method public void updateSoundProfile(@NonNull String, @NonNull android.media.quality.SoundProfile); + } + + public abstract static class MediaQualityManager.AmbientBacklightCallback { + ctor public MediaQualityManager.AmbientBacklightCallback(); + method public void onAmbientBacklightEvent(@NonNull android.media.quality.AmbientBacklightEvent); } public abstract static class MediaQualityManager.PictureProfileCallback { @@ -27089,6 +27190,15 @@ package android.media.quality { method public void onPictureProfileUpdated(@NonNull String, @NonNull android.media.quality.PictureProfile); } + public abstract static class MediaQualityManager.SoundProfileCallback { + ctor public MediaQualityManager.SoundProfileCallback(); + method public void onError(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); + method public void onSoundProfileUpdated(@NonNull String, @NonNull android.media.quality.SoundProfile); + } + @FlaggedApi("android.media.tv.flags.media_quality_fw") public final class ParamCapability implements android.os.Parcelable { method public int describeContents(); method @NonNull public android.os.Bundle getCapabilities(); @@ -27133,6 +27243,32 @@ package android.media.quality { method @NonNull public android.media.quality.PictureProfile.Builder setParameters(@NonNull android.os.PersistableBundle); } + @FlaggedApi("android.media.tv.flags.media_quality_fw") public final class SoundProfile implements android.os.Parcelable { + method public int describeContents(); + method @Nullable public String getInputId(); + method @NonNull public String getName(); + method @Nullable public String getPackageName(); + method @NonNull public android.os.PersistableBundle getParameters(); + method @Nullable public String getProfileId(); + method public int getProfileType(); + method public void writeToParcel(@NonNull android.os.Parcel, int); + field @NonNull public static final android.os.Parcelable.Creator CREATOR; + field public static final int ERROR_DUPLICATE = 2; // 0x2 + field public static final int ERROR_INVALID_ARGUMENT = 3; // 0x3 + field public static final int ERROR_NOT_ALLOWLISTED = 4; // 0x4 + field public static final int ERROR_NO_PERMISSION = 1; // 0x1 + field public static final int ERROR_UNKNOWN = 0; // 0x0 + field public static final int TYPE_APPLICATION = 2; // 0x2 + field public static final int TYPE_SYSTEM = 1; // 0x1 + } + + public static final class SoundProfile.Builder { + ctor public SoundProfile.Builder(@NonNull String); + ctor public SoundProfile.Builder(@NonNull android.media.quality.SoundProfile); + method @NonNull public android.media.quality.SoundProfile build(); + method @NonNull public android.media.quality.SoundProfile.Builder setParameters(@NonNull android.os.PersistableBundle); + } + } package android.media.session { @@ -33476,9 +33612,14 @@ package android.os { @FlaggedApi("android.os.cpu_gpu_headrooms") public final class CpuHeadroomParams { ctor public CpuHeadroomParams(); method public int getCalculationType(); + method @IntRange(from=android.os.CpuHeadroomParams.CPU_HEADROOM_CALCULATION_WINDOW_MILLIS_MIN, to=android.os.CpuHeadroomParams.CPU_HEADROOM_CALCULATION_WINDOW_MILLIS_MAX) public long getCalculationWindowMillis(); method public void setCalculationType(int); + method public void setCalculationWindowMillis(@IntRange(from=android.os.CpuHeadroomParams.CPU_HEADROOM_CALCULATION_WINDOW_MILLIS_MIN, to=android.os.CpuHeadroomParams.CPU_HEADROOM_CALCULATION_WINDOW_MILLIS_MAX) int); + method public void setTids(@NonNull int...); field public static final int CPU_HEADROOM_CALCULATION_TYPE_AVERAGE = 1; // 0x1 field public static final int CPU_HEADROOM_CALCULATION_TYPE_MIN = 0; // 0x0 + field public static final int CPU_HEADROOM_CALCULATION_WINDOW_MILLIS_MAX = 10000; // 0x2710 + field public static final int CPU_HEADROOM_CALCULATION_WINDOW_MILLIS_MIN = 50; // 0x32 } public final class CpuUsageInfo implements android.os.Parcelable { @@ -33731,9 +33872,13 @@ package android.os { @FlaggedApi("android.os.cpu_gpu_headrooms") public final class GpuHeadroomParams { ctor public GpuHeadroomParams(); method public int getCalculationType(); + method @IntRange(from=android.os.GpuHeadroomParams.GPU_HEADROOM_CALCULATION_WINDOW_MILLIS_MIN, to=android.os.GpuHeadroomParams.GPU_HEADROOM_CALCULATION_WINDOW_MILLIS_MAX) public int getCalculationWindowMillis(); method public void setCalculationType(int); + method public void setCalculationWindowMillis(@IntRange(from=android.os.GpuHeadroomParams.GPU_HEADROOM_CALCULATION_WINDOW_MILLIS_MIN, to=android.os.GpuHeadroomParams.GPU_HEADROOM_CALCULATION_WINDOW_MILLIS_MAX) int); field public static final int GPU_HEADROOM_CALCULATION_TYPE_AVERAGE = 1; // 0x1 field public static final int GPU_HEADROOM_CALCULATION_TYPE_MIN = 0; // 0x0 + field public static final int GPU_HEADROOM_CALCULATION_WINDOW_MILLIS_MAX = 10000; // 0x2710 + field public static final int GPU_HEADROOM_CALCULATION_WINDOW_MILLIS_MIN = 50; // 0x32 } public class Handler { @@ -33806,7 +33951,7 @@ package android.os { } public interface IBinder { - method @FlaggedApi("android.os.binder_frozen_state_change_callback") public default void addFrozenStateChangeCallback(@NonNull android.os.IBinder.FrozenStateChangeCallback) throws android.os.RemoteException; + method @FlaggedApi("android.os.binder_frozen_state_change_callback") public default void addFrozenStateChangeCallback(@NonNull java.util.concurrent.Executor, @NonNull android.os.IBinder.FrozenStateChangeCallback) throws android.os.RemoteException; method public void dump(@NonNull java.io.FileDescriptor, @Nullable String[]) throws android.os.RemoteException; method public void dumpAsync(@NonNull java.io.FileDescriptor, @Nullable String[]) throws android.os.RemoteException; method @Nullable public String getInterfaceDescriptor() throws android.os.RemoteException; @@ -34437,6 +34582,7 @@ package android.os { method public void finishBroadcast(); method public Object getBroadcastCookie(int); method public E getBroadcastItem(int); + method @FlaggedApi("android.os.binder_frozen_state_change_callback") @Nullable public java.util.concurrent.Executor getExecutor(); method @FlaggedApi("android.os.binder_frozen_state_change_callback") public int getFrozenCalleePolicy(); method @FlaggedApi("android.os.binder_frozen_state_change_callback") public int getMaxQueueSize(); method public Object getRegisteredCallbackCookie(int); @@ -34457,6 +34603,7 @@ package android.os { @FlaggedApi("android.os.binder_frozen_state_change_callback") public static final class RemoteCallbackList.Builder { ctor public RemoteCallbackList.Builder(int); method @NonNull public android.os.RemoteCallbackList build(); + method @NonNull public android.os.RemoteCallbackList.Builder setExecutor(@NonNull java.util.concurrent.Executor); method @NonNull public android.os.RemoteCallbackList.Builder setInterfaceDiedCallback(@NonNull android.os.RemoteCallbackList.Builder.InterfaceDiedCallback); method @NonNull public android.os.RemoteCallbackList.Builder setMaxQueueSize(int); } @@ -34844,6 +34991,13 @@ package android.os { field public static final int EFFECT_TICK = 2; // 0x2 } + @FlaggedApi("android.os.vibrator.normalized_pwle_effects") public static final class VibrationEffect.BasicEnvelopeBuilder { + ctor public VibrationEffect.BasicEnvelopeBuilder(); + method @FlaggedApi("android.os.vibrator.normalized_pwle_effects") @NonNull public android.os.VibrationEffect.BasicEnvelopeBuilder addControlPoint(@FloatRange(from=0, to=1) float, @FloatRange(from=0, to=1) float, long); + method @FlaggedApi("android.os.vibrator.normalized_pwle_effects") @NonNull public android.os.VibrationEffect build(); + method @FlaggedApi("android.os.vibrator.normalized_pwle_effects") @NonNull public android.os.VibrationEffect.BasicEnvelopeBuilder setInitialSharpness(@FloatRange(from=0, to=1) float); + } + public static final class VibrationEffect.Composition { method @NonNull public android.os.VibrationEffect.Composition addPrimitive(int); method @NonNull public android.os.VibrationEffect.Composition addPrimitive(int, @FloatRange(from=0.0f, to=1.0f) float); @@ -34864,7 +35018,7 @@ package android.os { @FlaggedApi("android.os.vibrator.normalized_pwle_effects") public static final class VibrationEffect.WaveformEnvelopeBuilder { ctor public VibrationEffect.WaveformEnvelopeBuilder(); - method @FlaggedApi("android.os.vibrator.normalized_pwle_effects") @NonNull public android.os.VibrationEffect.WaveformEnvelopeBuilder addControlPoint(@FloatRange(from=0, to=1) float, @FloatRange(from=0) float, int); + method @FlaggedApi("android.os.vibrator.normalized_pwle_effects") @NonNull public android.os.VibrationEffect.WaveformEnvelopeBuilder addControlPoint(@FloatRange(from=0, to=1) float, @FloatRange(from=0) float, long); method @FlaggedApi("android.os.vibrator.normalized_pwle_effects") @NonNull public android.os.VibrationEffect build(); method @FlaggedApi("android.os.vibrator.normalized_pwle_effects") @NonNull public android.os.VibrationEffect.WaveformEnvelopeBuilder setInitialFrequencyHz(@FloatRange(from=0) float); } @@ -37568,7 +37722,6 @@ package android.provider { } @FlaggedApi("android.provider.new_default_account_api_enabled") public static final class ContactsContract.RawContacts.DefaultAccount.DefaultAccountAndState { - ctor public ContactsContract.RawContacts.DefaultAccount.DefaultAccountAndState(int, @Nullable android.accounts.Account); method @Nullable public android.accounts.Account getAccount(); method public int getState(); method @NonNull public static android.provider.ContactsContract.RawContacts.DefaultAccount.DefaultAccountAndState ofCloud(@NonNull android.accounts.Account); @@ -41176,6 +41329,18 @@ package android.service.carrier { method @Deprecated public void onSendTextSms(@NonNull String, int, @NonNull String, @NonNull android.service.carrier.CarrierMessagingService.ResultCallback); method public void onSendTextSms(@NonNull String, int, @NonNull String, int, @NonNull android.service.carrier.CarrierMessagingService.ResultCallback); field public static final int DOWNLOAD_STATUS_ERROR = 2; // 0x2 + field @FlaggedApi("com.android.internal.telephony.flags.temporary_failures_in_carrier_messaging_service") public static final int DOWNLOAD_STATUS_MMS_ERROR_CONFIGURATION_ERROR = 606; // 0x25e + field @FlaggedApi("com.android.internal.telephony.flags.temporary_failures_in_carrier_messaging_service") public static final int DOWNLOAD_STATUS_MMS_ERROR_DATA_DISABLED = 610; // 0x262 + field @FlaggedApi("com.android.internal.telephony.flags.temporary_failures_in_carrier_messaging_service") public static final int DOWNLOAD_STATUS_MMS_ERROR_HTTP_FAILURE = 603; // 0x25b + field @FlaggedApi("com.android.internal.telephony.flags.temporary_failures_in_carrier_messaging_service") public static final int DOWNLOAD_STATUS_MMS_ERROR_INACTIVE_SUBSCRIPTION = 609; // 0x261 + field @FlaggedApi("com.android.internal.telephony.flags.temporary_failures_in_carrier_messaging_service") public static final int DOWNLOAD_STATUS_MMS_ERROR_INVALID_APN = 601; // 0x259 + field @FlaggedApi("com.android.internal.telephony.flags.temporary_failures_in_carrier_messaging_service") public static final int DOWNLOAD_STATUS_MMS_ERROR_INVALID_SUBSCRIPTION_ID = 608; // 0x260 + field @FlaggedApi("com.android.internal.telephony.flags.temporary_failures_in_carrier_messaging_service") public static final int DOWNLOAD_STATUS_MMS_ERROR_IO_ERROR = 604; // 0x25c + field @FlaggedApi("com.android.internal.telephony.flags.temporary_failures_in_carrier_messaging_service") public static final int DOWNLOAD_STATUS_MMS_ERROR_MMS_DISABLED_BY_CARRIER = 611; // 0x263 + field @FlaggedApi("com.android.internal.telephony.flags.temporary_failures_in_carrier_messaging_service") public static final int DOWNLOAD_STATUS_MMS_ERROR_NO_DATA_NETWORK = 607; // 0x25f + field @FlaggedApi("com.android.internal.telephony.flags.temporary_failures_in_carrier_messaging_service") public static final int DOWNLOAD_STATUS_MMS_ERROR_RETRY = 605; // 0x25d + field @FlaggedApi("com.android.internal.telephony.flags.temporary_failures_in_carrier_messaging_service") public static final int DOWNLOAD_STATUS_MMS_ERROR_UNABLE_CONNECT_MMS = 602; // 0x25a + field @FlaggedApi("com.android.internal.telephony.flags.temporary_failures_in_carrier_messaging_service") public static final int DOWNLOAD_STATUS_MMS_ERROR_UNSPECIFIED = 600; // 0x258 field public static final int DOWNLOAD_STATUS_OK = 0; // 0x0 field public static final int DOWNLOAD_STATUS_RETRY_ON_CARRIER_NETWORK = 1; // 0x1 field public static final int RECEIVE_OPTIONS_DEFAULT = 0; // 0x0 @@ -41183,7 +41348,38 @@ package android.service.carrier { field public static final int RECEIVE_OPTIONS_SKIP_NOTIFY_WHEN_CREDENTIAL_PROTECTED_STORAGE_UNAVAILABLE = 2; // 0x2 field public static final int SEND_FLAG_REQUEST_DELIVERY_STATUS = 1; // 0x1 field public static final int SEND_STATUS_ERROR = 2; // 0x2 + field @FlaggedApi("com.android.internal.telephony.flags.temporary_failures_in_carrier_messaging_service") public static final int SEND_STATUS_MMS_ERROR_CONFIGURATION_ERROR = 406; // 0x196 + field @FlaggedApi("com.android.internal.telephony.flags.temporary_failures_in_carrier_messaging_service") public static final int SEND_STATUS_MMS_ERROR_DATA_DISABLED = 410; // 0x19a + field @FlaggedApi("com.android.internal.telephony.flags.temporary_failures_in_carrier_messaging_service") public static final int SEND_STATUS_MMS_ERROR_HTTP_FAILURE = 403; // 0x193 + field @FlaggedApi("com.android.internal.telephony.flags.temporary_failures_in_carrier_messaging_service") public static final int SEND_STATUS_MMS_ERROR_INACTIVE_SUBSCRIPTION = 409; // 0x199 + field @FlaggedApi("com.android.internal.telephony.flags.temporary_failures_in_carrier_messaging_service") public static final int SEND_STATUS_MMS_ERROR_INVALID_APN = 401; // 0x191 + field @FlaggedApi("com.android.internal.telephony.flags.temporary_failures_in_carrier_messaging_service") public static final int SEND_STATUS_MMS_ERROR_INVALID_SUBSCRIPTION_ID = 408; // 0x198 + field @FlaggedApi("com.android.internal.telephony.flags.temporary_failures_in_carrier_messaging_service") public static final int SEND_STATUS_MMS_ERROR_IO_ERROR = 404; // 0x194 + field @FlaggedApi("com.android.internal.telephony.flags.temporary_failures_in_carrier_messaging_service") public static final int SEND_STATUS_MMS_ERROR_MMS_DISABLED_BY_CARRIER = 411; // 0x19b + field @FlaggedApi("com.android.internal.telephony.flags.temporary_failures_in_carrier_messaging_service") public static final int SEND_STATUS_MMS_ERROR_NO_DATA_NETWORK = 407; // 0x197 + field @FlaggedApi("com.android.internal.telephony.flags.temporary_failures_in_carrier_messaging_service") public static final int SEND_STATUS_MMS_ERROR_RETRY = 405; // 0x195 + field @FlaggedApi("com.android.internal.telephony.flags.temporary_failures_in_carrier_messaging_service") public static final int SEND_STATUS_MMS_ERROR_UNABLE_CONNECT_MMS = 402; // 0x192 + field @FlaggedApi("com.android.internal.telephony.flags.temporary_failures_in_carrier_messaging_service") public static final int SEND_STATUS_MMS_ERROR_UNSPECIFIED = 400; // 0x190 field public static final int SEND_STATUS_OK = 0; // 0x0 + field @FlaggedApi("com.android.internal.telephony.flags.temporary_failures_in_carrier_messaging_service") public static final int SEND_STATUS_RESULT_CANCELLED = 215; // 0xd7 + field @FlaggedApi("com.android.internal.telephony.flags.temporary_failures_in_carrier_messaging_service") public static final int SEND_STATUS_RESULT_ENCODING_ERROR = 212; // 0xd4 + field @FlaggedApi("com.android.internal.telephony.flags.temporary_failures_in_carrier_messaging_service") public static final int SEND_STATUS_RESULT_ERROR_FDN_CHECK_FAILURE = 204; // 0xcc + field @FlaggedApi("com.android.internal.telephony.flags.temporary_failures_in_carrier_messaging_service") public static final int SEND_STATUS_RESULT_ERROR_GENERIC_FAILURE = 200; // 0xc8 + field @FlaggedApi("com.android.internal.telephony.flags.temporary_failures_in_carrier_messaging_service") public static final int SEND_STATUS_RESULT_ERROR_LIMIT_EXCEEDED = 203; // 0xcb + field @FlaggedApi("com.android.internal.telephony.flags.temporary_failures_in_carrier_messaging_service") public static final int SEND_STATUS_RESULT_ERROR_NO_SERVICE = 202; // 0xca + field @FlaggedApi("com.android.internal.telephony.flags.temporary_failures_in_carrier_messaging_service") public static final int SEND_STATUS_RESULT_ERROR_NULL_PDU = 201; // 0xc9 + field @FlaggedApi("com.android.internal.telephony.flags.temporary_failures_in_carrier_messaging_service") public static final int SEND_STATUS_RESULT_ERROR_SHORT_CODE_NEVER_ALLOWED = 206; // 0xce + field @FlaggedApi("com.android.internal.telephony.flags.temporary_failures_in_carrier_messaging_service") public static final int SEND_STATUS_RESULT_ERROR_SHORT_CODE_NOT_ALLOWED = 205; // 0xcd + field @FlaggedApi("com.android.internal.telephony.flags.temporary_failures_in_carrier_messaging_service") public static final int SEND_STATUS_RESULT_INVALID_ARGUMENTS = 208; // 0xd0 + field @FlaggedApi("com.android.internal.telephony.flags.temporary_failures_in_carrier_messaging_service") public static final int SEND_STATUS_RESULT_INVALID_SMSC_ADDRESS = 213; // 0xd5 + field @FlaggedApi("com.android.internal.telephony.flags.temporary_failures_in_carrier_messaging_service") public static final int SEND_STATUS_RESULT_INVALID_SMS_FORMAT = 210; // 0xd2 + field @FlaggedApi("com.android.internal.telephony.flags.temporary_failures_in_carrier_messaging_service") public static final int SEND_STATUS_RESULT_INVALID_STATE = 209; // 0xd1 + field @FlaggedApi("com.android.internal.telephony.flags.temporary_failures_in_carrier_messaging_service") public static final int SEND_STATUS_RESULT_NETWORK_ERROR = 211; // 0xd3 + field @FlaggedApi("com.android.internal.telephony.flags.temporary_failures_in_carrier_messaging_service") public static final int SEND_STATUS_RESULT_NETWORK_REJECT = 207; // 0xcf + field @FlaggedApi("com.android.internal.telephony.flags.temporary_failures_in_carrier_messaging_service") public static final int SEND_STATUS_RESULT_OPERATION_NOT_ALLOWED = 214; // 0xd6 + field @FlaggedApi("com.android.internal.telephony.flags.temporary_failures_in_carrier_messaging_service") public static final int SEND_STATUS_RESULT_REQUEST_NOT_SUPPORTED = 216; // 0xd8 + field @FlaggedApi("com.android.internal.telephony.flags.temporary_failures_in_carrier_messaging_service") public static final int SEND_STATUS_RESULT_SMS_BLOCKED_DURING_EMERGENCY = 217; // 0xd9 + field @FlaggedApi("com.android.internal.telephony.flags.temporary_failures_in_carrier_messaging_service") public static final int SEND_STATUS_RESULT_SMS_SEND_RETRY_FAILED = 218; // 0xda field public static final int SEND_STATUS_RETRY_ON_CARRIER_NETWORK = 1; // 0x1 field public static final String SERVICE_INTERFACE = "android.service.carrier.CarrierMessagingService"; } @@ -42407,7 +42603,7 @@ package android.service.settings.preferences { method @NonNull public java.util.List getBreadcrumbs(); method @NonNull public android.os.Bundle getExtras(); method @NonNull public String getKey(); - method @Nullable public android.app.PendingIntent getLaunchIntent(); + method @Nullable public android.content.Intent getLaunchIntent(); method @NonNull public java.util.List getReadPermissions(); method @NonNull public String getScreenKey(); method @Nullable public String getSummary(); @@ -42432,7 +42628,7 @@ package android.service.settings.preferences { method @NonNull public android.service.settings.preferences.SettingsPreferenceMetadata.Builder setBreadcrumbs(@NonNull java.util.List); method @NonNull public android.service.settings.preferences.SettingsPreferenceMetadata.Builder setEnabled(boolean); method @NonNull public android.service.settings.preferences.SettingsPreferenceMetadata.Builder setExtras(@NonNull android.os.Bundle); - method @NonNull public android.service.settings.preferences.SettingsPreferenceMetadata.Builder setLaunchIntent(@Nullable android.app.PendingIntent); + method @NonNull public android.service.settings.preferences.SettingsPreferenceMetadata.Builder setLaunchIntent(@Nullable android.content.Intent); method @NonNull public android.service.settings.preferences.SettingsPreferenceMetadata.Builder setReadPermissions(@NonNull java.util.List); method @NonNull public android.service.settings.preferences.SettingsPreferenceMetadata.Builder setRestricted(boolean); method @NonNull public android.service.settings.preferences.SettingsPreferenceMetadata.Builder setSummary(@Nullable String); @@ -42452,19 +42648,18 @@ package android.service.settings.preferences { } @FlaggedApi("com.android.settingslib.flags.settings_catalyst") public class SettingsPreferenceServiceClient implements java.lang.AutoCloseable { - ctor public SettingsPreferenceServiceClient(@NonNull android.content.Context, @NonNull String); + ctor public SettingsPreferenceServiceClient(@NonNull android.content.Context, @NonNull String, @NonNull java.util.concurrent.Executor, @NonNull android.os.OutcomeReceiver); method public void close(); method public void getAllPreferenceMetadata(@NonNull android.service.settings.preferences.MetadataRequest, @NonNull java.util.concurrent.Executor, @NonNull android.os.OutcomeReceiver); method public void getPreferenceValue(@NonNull android.service.settings.preferences.GetValueRequest, @NonNull java.util.concurrent.Executor, @NonNull android.os.OutcomeReceiver); method public void setPreferenceValue(@NonNull android.service.settings.preferences.SetValueRequest, @NonNull java.util.concurrent.Executor, @NonNull android.os.OutcomeReceiver); - method public void start(); - method public void stop(); } @FlaggedApi("com.android.settingslib.flags.settings_catalyst") public final class SettingsPreferenceValue implements android.os.Parcelable { method public int describeContents(); method public boolean getBooleanValue(); method public double getDoubleValue(); + method public int getIntValue(); method public long getLongValue(); method @Nullable public String getStringValue(); method public int getType(); @@ -42472,6 +42667,7 @@ package android.service.settings.preferences { field @NonNull public static final android.os.Parcelable.Creator CREATOR; field public static final int TYPE_BOOLEAN = 0; // 0x0 field public static final int TYPE_DOUBLE = 2; // 0x2 + field public static final int TYPE_INT = 4; // 0x4 field public static final int TYPE_LONG = 1; // 0x1 field public static final int TYPE_STRING = 3; // 0x3 } @@ -42481,6 +42677,7 @@ package android.service.settings.preferences { method @NonNull public android.service.settings.preferences.SettingsPreferenceValue build(); method @NonNull public android.service.settings.preferences.SettingsPreferenceValue.Builder setBooleanValue(boolean); method @NonNull public android.service.settings.preferences.SettingsPreferenceValue.Builder setDoubleValue(double); + method @NonNull public android.service.settings.preferences.SettingsPreferenceValue.Builder setIntValue(int); method @NonNull public android.service.settings.preferences.SettingsPreferenceValue.Builder setLongValue(long); method @NonNull public android.service.settings.preferences.SettingsPreferenceValue.Builder setStringValue(@Nullable String); } @@ -50264,9 +50461,9 @@ package android.text.style { public static class TtsSpan.TimeBuilder extends android.text.style.TtsSpan.SemioticClassBuilder { ctor public TtsSpan.TimeBuilder(); ctor public TtsSpan.TimeBuilder(int, int); - method public android.text.style.TtsSpan.TimeBuilder setHours(int); - method public android.text.style.TtsSpan.TimeBuilder setMinutes(int); - method @FlaggedApi("com.android.text.flags.tts_span_duration") @NonNull public android.text.style.TtsSpan.TimeBuilder setSeconds(int); + method public android.text.style.TtsSpan.TimeBuilder setHours(@IntRange(from=0, to=24) int); + method public android.text.style.TtsSpan.TimeBuilder setMinutes(@IntRange(from=0, to=59) int); + method @FlaggedApi("com.android.text.flags.tts_span_duration") @NonNull public android.text.style.TtsSpan.TimeBuilder setSeconds(@IntRange(from=0, to=59) int); } public static class TtsSpan.VerbatimBuilder extends android.text.style.TtsSpan.SemioticClassBuilder { @@ -51749,7 +51946,7 @@ package android.view { method public int getState(); method @FlaggedApi("com.android.server.display.feature.flags.enable_get_suggested_frame_rate") public float getSuggestedFrameRate(int); method public android.view.Display.Mode[] getSupportedModes(); - method @Deprecated public float[] getSupportedRefreshRates(); + method @FlaggedApi("com.android.server.display.feature.flags.enable_get_supported_refresh_rates") @NonNull public float[] getSupportedRefreshRates(); method @Deprecated public int getWidth(); method @FlaggedApi("com.android.server.display.feature.flags.enable_has_arr_support") public boolean hasArrSupport(); method public boolean isHdr(); @@ -53358,6 +53555,7 @@ package android.view { method @NonNull public android.view.SurfaceControl.Transaction setBuffer(@NonNull android.view.SurfaceControl, @Nullable android.hardware.HardwareBuffer, @Nullable android.hardware.SyncFence, @Nullable java.util.function.Consumer); method @NonNull public android.view.SurfaceControl.Transaction setBufferSize(@NonNull android.view.SurfaceControl, @IntRange(from=0) int, @IntRange(from=0) int); method @NonNull public android.view.SurfaceControl.Transaction setBufferTransform(@NonNull android.view.SurfaceControl, int); + method @FlaggedApi("android.media.tv.flags.apply_picture_profiles") @NonNull public android.view.SurfaceControl.Transaction setContentPriority(@NonNull android.view.SurfaceControl, int); method @NonNull public android.view.SurfaceControl.Transaction setCrop(@NonNull android.view.SurfaceControl, @Nullable android.graphics.Rect); method @NonNull public android.view.SurfaceControl.Transaction setDamageRegion(@NonNull android.view.SurfaceControl, @Nullable android.graphics.Region); method @NonNull public android.view.SurfaceControl.Transaction setDataSpace(@NonNull android.view.SurfaceControl, int); @@ -56306,6 +56504,7 @@ package android.view.accessibility { method public float getMin(); method public int getType(); method @Deprecated public static android.view.accessibility.AccessibilityNodeInfo.RangeInfo obtain(int, float, float, float); + field @FlaggedApi("android.view.accessibility.indeterminate_range_info") @NonNull public static final android.view.accessibility.AccessibilityNodeInfo.RangeInfo INDETERMINATE; field public static final int RANGE_TYPE_FLOAT = 1; // 0x1 field @FlaggedApi("android.view.accessibility.indeterminate_range_info") public static final int RANGE_TYPE_INDETERMINATE = 3; // 0x3 field public static final int RANGE_TYPE_INT = 0; // 0x0 diff --git a/core/api/system-current.txt b/core/api/system-current.txt index bc0037d9318f7524edac0c84f3d837376a783a8a..83699ac30939bc3a16607bf30b08af585524fb66 100644 --- a/core/api/system-current.txt +++ b/core/api/system-current.txt @@ -34,6 +34,7 @@ package android { field public static final String ACCESS_VIBRATOR_STATE = "android.permission.ACCESS_VIBRATOR_STATE"; field public static final String ACTIVITY_EMBEDDING = "android.permission.ACTIVITY_EMBEDDING"; field public static final String ADD_ALWAYS_UNLOCKED_DISPLAY = "android.permission.ADD_ALWAYS_UNLOCKED_DISPLAY"; + field @FlaggedApi("android.companion.virtualdevice.flags.enable_limited_vdm_role") public static final String ADD_MIRROR_DISPLAY = "android.permission.ADD_MIRROR_DISPLAY"; field public static final String ADD_TRUSTED_DISPLAY = "android.permission.ADD_TRUSTED_DISPLAY"; field public static final String ADJUST_RUNTIME_PERMISSIONS_POLICY = "android.permission.ADJUST_RUNTIME_PERMISSIONS_POLICY"; field public static final String ALLOCATE_AGGRESSIVE = "android.permission.ALLOCATE_AGGRESSIVE"; @@ -66,10 +67,10 @@ package android { field @FlaggedApi("android.crashrecovery.flags.enable_crashrecovery") public static final String BIND_EXPLICIT_HEALTH_CHECK_SERVICE = "android.permission.BIND_EXPLICIT_HEALTH_CHECK_SERVICE"; field public static final String BIND_EXTERNAL_STORAGE_SERVICE = "android.permission.BIND_EXTERNAL_STORAGE_SERVICE"; field public static final String BIND_FIELD_CLASSIFICATION_SERVICE = "android.permission.BIND_FIELD_CLASSIFICATION_SERVICE"; - field @FlaggedApi("android.security.afl_api") public static final String BIND_FORENSIC_EVENT_TRANSPORT_SERVICE = "android.permission.BIND_FORENSIC_EVENT_TRANSPORT_SERVICE"; field public static final String BIND_GBA_SERVICE = "android.permission.BIND_GBA_SERVICE"; field public static final String BIND_HOTWORD_DETECTION_SERVICE = "android.permission.BIND_HOTWORD_DETECTION_SERVICE"; field public static final String BIND_IMS_SERVICE = "android.permission.BIND_IMS_SERVICE"; + field @FlaggedApi("android.security.afl_api") public static final String BIND_INTRUSION_DETECTION_EVENT_TRANSPORT_SERVICE = "android.permission.BIND_INTRUSION_DETECTION_EVENT_TRANSPORT_SERVICE"; field public static final String BIND_KEYGUARD_APPWIDGET = "android.permission.BIND_KEYGUARD_APPWIDGET"; field public static final String BIND_MUSIC_RECOGNITION_SERVICE = "android.permission.BIND_MUSIC_RECOGNITION_SERVICE"; field public static final String BIND_NETWORK_RECOMMENDATION_SERVICE = "android.permission.BIND_NETWORK_RECOMMENDATION_SERVICE"; @@ -94,7 +95,6 @@ package android { field public static final String BIND_TRANSLATION_SERVICE = "android.permission.BIND_TRANSLATION_SERVICE"; field public static final String BIND_TRUST_AGENT = "android.permission.BIND_TRUST_AGENT"; field public static final String BIND_TV_REMOTE_SERVICE = "android.permission.BIND_TV_REMOTE_SERVICE"; - field @FlaggedApi("android.content.pm.verification_service") public static final String BIND_VERIFICATION_AGENT = "android.permission.BIND_VERIFICATION_AGENT"; field public static final String BIND_VISUAL_QUERY_DETECTION_SERVICE = "android.permission.BIND_VISUAL_QUERY_DETECTION_SERVICE"; field public static final String BIND_WALLPAPER_EFFECTS_GENERATION_SERVICE = "android.permission.BIND_WALLPAPER_EFFECTS_GENERATION_SERVICE"; field public static final String BIND_WEARABLE_SENSING_SERVICE = "android.permission.BIND_WEARABLE_SENSING_SERVICE"; @@ -103,6 +103,7 @@ package android { field public static final String BRIGHTNESS_SLIDER_USAGE = "android.permission.BRIGHTNESS_SLIDER_USAGE"; field public static final String BROADCAST_CLOSE_SYSTEM_DIALOGS = "android.permission.BROADCAST_CLOSE_SYSTEM_DIALOGS"; field @Deprecated public static final String BROADCAST_NETWORK_PRIVILEGED = "android.permission.BROADCAST_NETWORK_PRIVILEGED"; + field @FlaggedApi("android.media.audio.concurrent_audio_record_bypass_permission") public static final String BYPASS_CONCURRENT_RECORD_AUDIO_RESTRICTION = "android.permission.BYPASS_CONCURRENT_RECORD_AUDIO_RESTRICTION"; field public static final String BYPASS_ROLE_QUALIFICATION = "android.permission.BYPASS_ROLE_QUALIFICATION"; field public static final String CALL_AUDIO_INTERCEPTION = "android.permission.CALL_AUDIO_INTERCEPTION"; field public static final String CAMERA_DISABLE_TRANSMIT_LED = "android.permission.CAMERA_DISABLE_TRANSMIT_LED"; @@ -134,6 +135,7 @@ package android { field public static final String CONTROL_KEYGUARD_SECURE_NOTIFICATIONS = "android.permission.CONTROL_KEYGUARD_SECURE_NOTIFICATIONS"; field public static final String CONTROL_OEM_PAID_NETWORK_PREFERENCE = "android.permission.CONTROL_OEM_PAID_NETWORK_PREFERENCE"; field public static final String CONTROL_VPN = "android.permission.CONTROL_VPN"; + field @FlaggedApi("android.app.admin.flags.split_create_managed_profile_enabled") public static final String COPY_ACCOUNTS = "android.permission.COPY_ACCOUNTS"; field public static final String CREATE_USERS = "android.permission.CREATE_USERS"; field public static final String CREATE_VIRTUAL_DEVICE = "android.permission.CREATE_VIRTUAL_DEVICE"; field public static final String CRYPT_KEEPER = "android.permission.CRYPT_KEEPER"; @@ -192,6 +194,7 @@ package android { field public static final String MANAGE_ACCESSIBILITY = "android.permission.MANAGE_ACCESSIBILITY"; field @Deprecated public static final String MANAGE_ACTIVITY_STACKS = "android.permission.MANAGE_ACTIVITY_STACKS"; field public static final String MANAGE_ACTIVITY_TASKS = "android.permission.MANAGE_ACTIVITY_TASKS"; + field @FlaggedApi("android.security.aapm_api") public static final String MANAGE_ADVANCED_PROTECTION_MODE = "android.permission.MANAGE_ADVANCED_PROTECTION_MODE"; field public static final String MANAGE_APP_HIBERNATION = "android.permission.MANAGE_APP_HIBERNATION"; field public static final String MANAGE_APP_OPS_RESTRICTIONS = "android.permission.MANAGE_APP_OPS_RESTRICTIONS"; field public static final String MANAGE_APP_PREDICTIONS = "android.permission.MANAGE_APP_PREDICTIONS"; @@ -212,12 +215,12 @@ package android { field @FlaggedApi("android.permission.flags.enhanced_confirmation_mode_apis_enabled") public static final String MANAGE_ENHANCED_CONFIRMATION_STATES = "android.permission.MANAGE_ENHANCED_CONFIRMATION_STATES"; field public static final String MANAGE_ETHERNET_NETWORKS = "android.permission.MANAGE_ETHERNET_NETWORKS"; field public static final String MANAGE_FACTORY_RESET_PROTECTION = "android.permission.MANAGE_FACTORY_RESET_PROTECTION"; - field @FlaggedApi("android.security.afl_api") public static final String MANAGE_FORENSIC_STATE = "android.permission.MANAGE_FORENSIC_STATE"; field public static final String MANAGE_GAME_ACTIVITY = "android.permission.MANAGE_GAME_ACTIVITY"; field public static final String MANAGE_GAME_MODE = "android.permission.MANAGE_GAME_MODE"; field @FlaggedApi("android.media.tv.flags.media_quality_fw") public static final String MANAGE_GLOBAL_PICTURE_QUALITY_SERVICE = "android.permission.MANAGE_GLOBAL_PICTURE_QUALITY_SERVICE"; field @FlaggedApi("android.media.tv.flags.media_quality_fw") public static final String MANAGE_GLOBAL_SOUND_QUALITY_SERVICE = "android.permission.MANAGE_GLOBAL_SOUND_QUALITY_SERVICE"; field public static final String MANAGE_HOTWORD_DETECTION = "android.permission.MANAGE_HOTWORD_DETECTION"; + field @FlaggedApi("android.security.afl_api") public static final String MANAGE_INTRUSION_DETECTION_STATE = "android.permission.MANAGE_INTRUSION_DETECTION_STATE"; field public static final String MANAGE_IPSEC_TUNNELS = "android.permission.MANAGE_IPSEC_TUNNELS"; field public static final String MANAGE_LOW_POWER_STANDBY = "android.permission.MANAGE_LOW_POWER_STANDBY"; field public static final String MANAGE_MUSIC_RECOGNITION = "android.permission.MANAGE_MUSIC_RECOGNITION"; @@ -229,6 +232,7 @@ package android { field public static final String MANAGE_ROTATION_RESOLVER = "android.permission.MANAGE_ROTATION_RESOLVER"; field public static final String MANAGE_SAFETY_CENTER = "android.permission.MANAGE_SAFETY_CENTER"; field public static final String MANAGE_SEARCH_UI = "android.permission.MANAGE_SEARCH_UI"; + field @FlaggedApi("android.security.secure_lockdown") public static final String MANAGE_SECURE_LOCK_DEVICE = "android.permission.MANAGE_SECURE_LOCK_DEVICE"; field public static final String MANAGE_SENSOR_PRIVACY = "android.permission.MANAGE_SENSOR_PRIVACY"; field public static final String MANAGE_SMARTSPACE = "android.permission.MANAGE_SMARTSPACE"; field public static final String MANAGE_SOUND_TRIGGER = "android.permission.MANAGE_SOUND_TRIGGER"; @@ -308,10 +312,10 @@ package android { field public static final String READ_CONTENT_RATING_SYSTEMS = "android.permission.READ_CONTENT_RATING_SYSTEMS"; field public static final String READ_DEVICE_CONFIG = "android.permission.READ_DEVICE_CONFIG"; field public static final String READ_DREAM_STATE = "android.permission.READ_DREAM_STATE"; - field @FlaggedApi("android.security.afl_api") public static final String READ_FORENSIC_STATE = "android.permission.READ_FORENSIC_STATE"; field public static final String READ_GLOBAL_APP_SEARCH_DATA = "android.permission.READ_GLOBAL_APP_SEARCH_DATA"; field @FlaggedApi("android.content.pm.get_resolved_apk_path") public static final String READ_INSTALLED_SESSION_PATHS = "android.permission.READ_INSTALLED_SESSION_PATHS"; field public static final String READ_INSTALL_SESSIONS = "android.permission.READ_INSTALL_SESSIONS"; + field @FlaggedApi("android.security.afl_api") public static final String READ_INTRUSION_DETECTION_STATE = "android.permission.READ_INTRUSION_DETECTION_STATE"; field public static final String READ_NETWORK_USAGE_HISTORY = "android.permission.READ_NETWORK_USAGE_HISTORY"; field public static final String READ_OEM_UNLOCK_STATE = "android.permission.READ_OEM_UNLOCK_STATE"; field public static final String READ_PEOPLE_DATA = "android.permission.READ_PEOPLE_DATA"; @@ -345,6 +349,7 @@ package android { field public static final String REGISTER_SIM_SUBSCRIPTION = "android.permission.REGISTER_SIM_SUBSCRIPTION"; field public static final String REGISTER_STATS_PULL_ATOM = "android.permission.REGISTER_STATS_PULL_ATOM"; field public static final String REMOTE_DISPLAY_PROVIDER = "android.permission.REMOTE_DISPLAY_PROVIDER"; + field @FlaggedApi("android.app.admin.flags.split_create_managed_profile_enabled") public static final String REMOVE_ACCOUNTS = "android.permission.REMOVE_ACCOUNTS"; field public static final String REMOVE_DRM_CERTIFICATES = "android.permission.REMOVE_DRM_CERTIFICATES"; field public static final String REMOVE_TASKS = "android.permission.REMOVE_TASKS"; field public static final String RENOUNCE_PERMISSIONS = "android.permission.RENOUNCE_PERMISSIONS"; @@ -372,7 +377,6 @@ package android { field public static final String SERIAL_PORT = "android.permission.SERIAL_PORT"; field @FlaggedApi("android.security.fsverity_api") public static final String SETUP_FSVERITY = "android.permission.SETUP_FSVERITY"; field public static final String SET_ACTIVITY_WATCHER = "android.permission.SET_ACTIVITY_WATCHER"; - field @FlaggedApi("android.security.aapm_api") public static final String SET_ADVANCED_PROTECTION_MODE = "android.permission.SET_ADVANCED_PROTECTION_MODE"; field public static final String SET_CLIP_SOURCE = "android.permission.SET_CLIP_SOURCE"; field public static final String SET_DEFAULT_ACCOUNT_FOR_CONTACTS = "android.permission.SET_DEFAULT_ACCOUNT_FOR_CONTACTS"; field public static final String SET_HARMFUL_APP_WARNINGS = "android.permission.SET_HARMFUL_APP_WARNINGS"; @@ -426,7 +430,6 @@ package android { field @FlaggedApi("android.app.ondeviceintelligence.flags.enable_on_device_intelligence") public static final String USE_ON_DEVICE_INTELLIGENCE = "android.permission.USE_ON_DEVICE_INTELLIGENCE"; field public static final String USE_RESERVED_DISK = "android.permission.USE_RESERVED_DISK"; field public static final String UWB_PRIVILEGED = "android.permission.UWB_PRIVILEGED"; - field @FlaggedApi("android.content.pm.verification_service") public static final String VERIFICATION_AGENT = "android.permission.VERIFICATION_AGENT"; field @FlaggedApi("android.os.vibrator.vendor_vibration_effects") public static final String VIBRATE_VENDOR_EFFECTS = "android.permission.VIBRATE_VENDOR_EFFECTS"; field public static final String WHITELIST_AUTO_REVOKE_PERMISSIONS = "android.permission.WHITELIST_AUTO_REVOKE_PERMISSIONS"; field public static final String WHITELIST_RESTRICTED_PERMISSIONS = "android.permission.WHITELIST_RESTRICTED_PERMISSIONS"; @@ -570,6 +573,7 @@ package android.accessibilityservice { package android.accounts { public class AccountManager { + method @FlaggedApi("android.app.admin.flags.split_create_managed_profile_enabled") @NonNull @RequiresPermission(anyOf={android.Manifest.permission.COPY_ACCOUNTS, android.Manifest.permission.INTERACT_ACROSS_USERS_FULL}) public android.accounts.AccountManagerFuture copyAccountToUser(@NonNull android.accounts.Account, @NonNull android.os.UserHandle, @NonNull android.os.UserHandle, @Nullable android.accounts.AccountManagerCallback, @Nullable android.os.Handler); method @RequiresPermission(android.Manifest.permission.INTERACT_ACROSS_USERS_FULL) public android.accounts.AccountManagerFuture finishSessionAsUser(android.os.Bundle, android.app.Activity, android.os.UserHandle, android.accounts.AccountManagerCallback, android.os.Handler); } @@ -2319,6 +2323,24 @@ package android.app.ondeviceintelligence { 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); @@ -2348,6 +2370,7 @@ package android.app.ondeviceintelligence { @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>); @@ -3413,14 +3436,14 @@ package android.app.wearable { public class WearableSensingManager { method @FlaggedApi("android.app.wearable.enable_concurrent_wearable_connections") @RequiresPermission(android.Manifest.permission.MANAGE_WEARABLE_SENSING_SERVICE) public int getAvailableConnectionCount(); method @Nullable public static android.app.wearable.WearableSensingDataRequest getDataRequestFromIntent(@NonNull android.content.Intent); - method @RequiresPermission(android.Manifest.permission.MANAGE_WEARABLE_SENSING_SERVICE) public void provideConnection(@NonNull android.os.ParcelFileDescriptor, @NonNull java.util.concurrent.Executor, @NonNull java.util.function.Consumer); + method @Deprecated @FlaggedApi("android.app.wearable.enable_concurrent_wearable_connections") @RequiresPermission(android.Manifest.permission.MANAGE_WEARABLE_SENSING_SERVICE) public void provideConnection(@NonNull android.os.ParcelFileDescriptor, @NonNull java.util.concurrent.Executor, @NonNull java.util.function.Consumer); method @FlaggedApi("android.app.wearable.enable_concurrent_wearable_connections") @RequiresPermission(android.Manifest.permission.MANAGE_WEARABLE_SENSING_SERVICE) public void provideConnection(@NonNull android.app.wearable.WearableConnection, @NonNull java.util.concurrent.Executor); method @RequiresPermission(android.Manifest.permission.MANAGE_WEARABLE_SENSING_SERVICE) public void provideData(@NonNull android.os.PersistableBundle, @Nullable android.os.SharedMemory, @NonNull java.util.concurrent.Executor, @NonNull java.util.function.Consumer); method @Deprecated @RequiresPermission(android.Manifest.permission.MANAGE_WEARABLE_SENSING_SERVICE) public void provideDataStream(@NonNull android.os.ParcelFileDescriptor, @NonNull java.util.concurrent.Executor, @NonNull java.util.function.Consumer); method @FlaggedApi("android.app.wearable.enable_provide_read_only_pfd") @RequiresPermission(android.Manifest.permission.MANAGE_WEARABLE_SENSING_SERVICE) public void provideReadOnlyParcelFileDescriptor(@NonNull android.os.ParcelFileDescriptor, @NonNull android.os.PersistableBundle, @NonNull java.util.concurrent.Executor, @NonNull java.util.function.Consumer); method @RequiresPermission(android.Manifest.permission.MANAGE_WEARABLE_SENSING_SERVICE) public void registerDataRequestObserver(int, @NonNull android.app.PendingIntent, @NonNull java.util.concurrent.Executor, @NonNull java.util.function.Consumer); method @FlaggedApi("android.app.wearable.enable_concurrent_wearable_connections") @RequiresPermission(android.Manifest.permission.MANAGE_WEARABLE_SENSING_SERVICE) public void removeAllConnections(); - method @FlaggedApi("android.app.wearable.enable_concurrent_wearable_connections") @RequiresPermission(android.Manifest.permission.MANAGE_WEARABLE_SENSING_SERVICE) public boolean removeConnection(@NonNull android.app.wearable.WearableConnection); + method @FlaggedApi("android.app.wearable.enable_concurrent_wearable_connections") @RequiresPermission(android.Manifest.permission.MANAGE_WEARABLE_SENSING_SERVICE) public void removeConnection(@NonNull android.app.wearable.WearableConnection); method @FlaggedApi("android.app.wearable.enable_hotword_wearable_sensing_api") @RequiresPermission(android.Manifest.permission.MANAGE_WEARABLE_SENSING_SERVICE) public void startHotwordRecognition(@Nullable android.content.ComponentName, @NonNull java.util.concurrent.Executor, @NonNull java.util.function.Consumer); method @FlaggedApi("android.app.wearable.enable_hotword_wearable_sensing_api") @RequiresPermission(android.Manifest.permission.MANAGE_WEARABLE_SENSING_SERVICE) public void stopHotwordRecognition(@NonNull java.util.concurrent.Executor, @NonNull java.util.function.Consumer); method @RequiresPermission(android.Manifest.permission.MANAGE_WEARABLE_SENSING_SERVICE) public void unregisterDataRequestObserver(int, @NonNull android.app.PendingIntent, @NonNull java.util.concurrent.Executor, @NonNull java.util.function.Consumer); @@ -3869,6 +3892,7 @@ package android.content { field public static final String APP_INTEGRITY_SERVICE = "app_integrity"; field public static final String APP_PREDICTION_SERVICE = "app_prediction"; field public static final String AUDIO_DEVICE_VOLUME_SERVICE = "audio_device_volume"; + field @FlaggedApi("android.security.secure_lockdown") public static final String AUTHENTICATION_POLICY_SERVICE = "authentication_policy"; field public static final String BACKUP_SERVICE = "backup"; field public static final String BATTERY_STATS_SERVICE = "batterystats"; field public static final int BIND_ALLOW_BACKGROUND_ACTIVITY_STARTS = 1048576; // 0x100000 @@ -3916,6 +3940,7 @@ package android.content { field public static final String WIFI_NL80211_SERVICE = "wifinl80211"; field @Deprecated public static final String WIFI_RTT_SERVICE = "rttmanager"; field public static final String WIFI_SCANNING_SERVICE = "wifiscanner"; + field @FlaggedApi("android.net.wifi.flags.usd") public static final String WIFI_USD_SERVICE = "wifi_usd"; } public final class ContextParams { @@ -4221,13 +4246,12 @@ package android.content.pm { } public class PackageInstaller { - method @FlaggedApi("android.content.pm.verification_service") @RequiresPermission(android.Manifest.permission.VERIFICATION_AGENT) public final int getVerificationPolicy(); method @NonNull public android.content.pm.PackageInstaller.InstallInfo readInstallInfo(@NonNull java.io.File, int) throws android.content.pm.PackageInstaller.PackageParsingException; method @FlaggedApi("android.content.pm.read_install_info") @NonNull public android.content.pm.PackageInstaller.InstallInfo readInstallInfo(@NonNull android.os.ParcelFileDescriptor, @Nullable String, int) throws android.content.pm.PackageInstaller.PackageParsingException; method @RequiresPermission(android.Manifest.permission.INSTALL_PACKAGES) public void setPermissionsResult(int, boolean); - method @FlaggedApi("android.content.pm.verification_service") @RequiresPermission(android.Manifest.permission.VERIFICATION_AGENT) public final boolean setVerificationPolicy(int); field public static final String ACTION_CONFIRM_INSTALL = "android.content.pm.action.CONFIRM_INSTALL"; field public static final String ACTION_CONFIRM_PRE_APPROVAL = "android.content.pm.action.CONFIRM_PRE_APPROVAL"; + field @FlaggedApi("android.content.pm.sdk_dependency_installer") public static final String ACTION_INSTALL_DEPENDENCY = "android.content.pm.action.INSTALL_DEPENDENCY"; field public static final int DATA_LOADER_TYPE_INCREMENTAL = 2; // 0x2 field public static final int DATA_LOADER_TYPE_NONE = 0; // 0x0 field public static final int DATA_LOADER_TYPE_STREAMING = 1; // 0x1 @@ -4236,20 +4260,12 @@ package android.content.pm { field @FlaggedApi("android.content.pm.archiving") public static final String EXTRA_DELETE_FLAGS = "android.content.pm.extra.DELETE_FLAGS"; field public static final String EXTRA_LEGACY_STATUS = "android.content.pm.extra.LEGACY_STATUS"; field @Deprecated public static final String EXTRA_RESOLVED_BASE_PATH = "android.content.pm.extra.RESOLVED_BASE_PATH"; - field @FlaggedApi("android.content.pm.verification_service") public static final String EXTRA_VERIFICATION_FAILURE_REASON = "android.content.pm.extra.VERIFICATION_FAILURE_REASON"; field public static final int LOCATION_DATA_APP = 0; // 0x0 field public static final int LOCATION_MEDIA_DATA = 2; // 0x2 field public static final int LOCATION_MEDIA_OBB = 1; // 0x1 field public static final int REASON_CONFIRM_PACKAGE_CHANGE = 0; // 0x0 field public static final int REASON_OWNERSHIP_CHANGED = 1; // 0x1 field public static final int REASON_REMIND_OWNERSHIP = 2; // 0x2 - field @FlaggedApi("android.content.pm.verification_service") public static final int VERIFICATION_FAILED_REASON_NETWORK_UNAVAILABLE = 1; // 0x1 - field @FlaggedApi("android.content.pm.verification_service") public static final int VERIFICATION_FAILED_REASON_PACKAGE_BLOCKED = 2; // 0x2 - field @FlaggedApi("android.content.pm.verification_service") public static final int VERIFICATION_FAILED_REASON_UNKNOWN = 0; // 0x0 - field @FlaggedApi("android.content.pm.verification_service") public static final int VERIFICATION_POLICY_BLOCK_FAIL_CLOSED = 3; // 0x3 - field @FlaggedApi("android.content.pm.verification_service") public static final int VERIFICATION_POLICY_BLOCK_FAIL_OPEN = 1; // 0x1 - field @FlaggedApi("android.content.pm.verification_service") public static final int VERIFICATION_POLICY_BLOCK_FAIL_WARN = 2; // 0x2 - field @FlaggedApi("android.content.pm.verification_service") public static final int VERIFICATION_POLICY_NONE = 0; // 0x0 } public static class PackageInstaller.InstallInfo { @@ -4369,7 +4385,6 @@ package android.content.pm { method @Deprecated @RequiresPermission(android.Manifest.permission.INTENT_FILTER_VERIFICATION_AGENT) public abstract void verifyIntentFilter(int, int, @NonNull java.util.List); field public static final String ACTION_REQUEST_PERMISSIONS = "android.content.pm.action.REQUEST_PERMISSIONS"; field public static final String ACTION_REQUEST_PERMISSIONS_FOR_OTHER = "android.content.pm.action.REQUEST_PERMISSIONS_FOR_OTHER"; - field @FlaggedApi("android.content.pm.verification_service") public static final String ACTION_VERIFY_PACKAGE = "android.content.pm.action.VERIFY_PACKAGE"; field @FlaggedApi("android.content.pm.asl_in_apk_app_metadata_source") public static final int APP_METADATA_SOURCE_APK = 1; // 0x1 field @FlaggedApi("android.content.pm.asl_in_apk_app_metadata_source") public static final int APP_METADATA_SOURCE_INSTALLER = 2; // 0x2 field @FlaggedApi("android.content.pm.asl_in_apk_app_metadata_source") public static final int APP_METADATA_SOURCE_SYSTEM_IMAGE = 3; // 0x3 @@ -4701,62 +4716,6 @@ package android.content.pm.verify.domain { } -package android.content.pm.verify.pkg { - - @FlaggedApi("android.content.pm.verification_service") public final class VerificationSession implements android.os.Parcelable { - method public int describeContents(); - method public long extendTimeRemaining(long); - method @NonNull public java.util.List getDeclaredLibraries(); - method @NonNull public android.os.PersistableBundle getExtensionParams(); - method public int getId(); - method public int getInstallSessionId(); - method @NonNull public String getPackageName(); - method @NonNull public android.content.pm.SigningInfo getSigningInfo(); - method @NonNull public android.net.Uri getStagedPackageUri(); - method public long getTimeoutTime(); - method public int getVerificationPolicy(); - method public void reportVerificationComplete(@NonNull android.content.pm.verify.pkg.VerificationStatus); - method public void reportVerificationComplete(@NonNull android.content.pm.verify.pkg.VerificationStatus, @NonNull android.os.PersistableBundle); - method public void reportVerificationIncomplete(int); - method public boolean setVerificationPolicy(int); - method public void writeToParcel(@NonNull android.os.Parcel, int); - field @NonNull public static final android.os.Parcelable.Creator CREATOR; - field public static final int VERIFICATION_INCOMPLETE_NETWORK_UNAVAILABLE = 1; // 0x1 - field public static final int VERIFICATION_INCOMPLETE_UNKNOWN = 0; // 0x0 - } - - @FlaggedApi("android.content.pm.verification_service") public final class VerificationStatus implements android.os.Parcelable { - method public int describeContents(); - method public int getAslStatus(); - method @NonNull public String getFailureMessage(); - method public boolean isVerified(); - method public void writeToParcel(@NonNull android.os.Parcel, int); - field @NonNull public static final android.os.Parcelable.Creator CREATOR; - field public static final int VERIFIER_STATUS_ASL_BAD = 2; // 0x2 - field public static final int VERIFIER_STATUS_ASL_GOOD = 1; // 0x1 - field public static final int VERIFIER_STATUS_ASL_UNDEFINED = 0; // 0x0 - } - - public static final class VerificationStatus.Builder { - ctor public VerificationStatus.Builder(); - method @NonNull public android.content.pm.verify.pkg.VerificationStatus build(); - method @NonNull public android.content.pm.verify.pkg.VerificationStatus.Builder setAslStatus(int); - method @NonNull public android.content.pm.verify.pkg.VerificationStatus.Builder setFailureMessage(@NonNull String); - method @NonNull public android.content.pm.verify.pkg.VerificationStatus.Builder setVerified(boolean); - } - - @FlaggedApi("android.content.pm.verification_service") public abstract class VerifierService extends android.app.Service { - ctor public VerifierService(); - method @Nullable public android.os.IBinder onBind(@Nullable android.content.Intent); - method public abstract void onPackageNameAvailable(@NonNull String); - method public abstract void onVerificationCancelled(@NonNull String); - method public abstract void onVerificationRequired(@NonNull android.content.pm.verify.pkg.VerificationSession); - method public abstract void onVerificationRetry(@NonNull android.content.pm.verify.pkg.VerificationSession); - method public abstract void onVerificationTimeout(int); - } - -} - package android.content.rollback { public final class PackageRollbackInfo implements android.os.Parcelable { @@ -5251,6 +5210,11 @@ package android.hardware.contexthub { method @NonNull public java.util.Collection getServiceInfoCollection(); method @Nullable public String getTag(); method public int getVersion(); + field public static final int REASON_CLOSE_ENDPOINT_SESSION_REQUESTED = 4; // 0x4 + field public static final int REASON_ENDPOINT_INVALID = 5; // 0x5 + field public static final int REASON_ENDPOINT_STOPPED = 6; // 0x6 + field public static final int REASON_FAILURE = 0; // 0x0 + field public static final int REASON_OPEN_ENDPOINT_SESSION_REQUEST_REJECTED = 3; // 0x3 } public static final class HubEndpoint.Builder { @@ -5317,9 +5281,8 @@ package android.hardware.contexthub { } @FlaggedApi("android.chre.flags.offload_api") public final class HubServiceInfo implements android.os.Parcelable { - ctor public HubServiceInfo(@NonNull String, int, int, int, @NonNull android.os.ParcelableHolder); + ctor public HubServiceInfo(@NonNull String, int, int, int); method public int describeContents(); - method @NonNull public android.os.ParcelableHolder getExtendedInfo(); method public int getFormat(); method public int getMajorVersion(); method public int getMinorVersion(); @@ -5334,16 +5297,17 @@ package android.hardware.contexthub { public static final class HubServiceInfo.Builder { ctor public HubServiceInfo.Builder(@NonNull String, int, int, int); method @NonNull public android.hardware.contexthub.HubServiceInfo build(); - method @NonNull public android.hardware.contexthub.HubServiceInfo.Builder setExtendedInfo(@Nullable android.os.Parcelable); + } + + @FlaggedApi("android.chre.flags.offload_api") public interface IHubEndpointDiscoveryCallback { + method public void onEndpointsStarted(@NonNull java.util.List); + method public void onEndpointsStopped(@NonNull java.util.List, int); } @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 public void onSessionOpened(@NonNull android.hardware.contexthub.HubEndpointSession); - field public static final int REASON_CLOSE_ENDPOINT_SESSION_REQUESTED = 4; // 0x4 - field public static final int REASON_OPEN_ENDPOINT_SESSION_REQUEST_REJECTED = 3; // 0x3 - field public static final int REASON_UNSPECIFIED = 0; // 0x0 } @FlaggedApi("android.chre.flags.offload_api") public interface IHubEndpointMessageCallback { @@ -6359,11 +6323,16 @@ package android.hardware.location { method @Deprecated public int registerCallback(@NonNull android.hardware.location.ContextHubManager.Callback); method @Deprecated public int registerCallback(android.hardware.location.ContextHubManager.Callback, android.os.Handler); method @FlaggedApi("android.chre.flags.offload_api") @RequiresPermission(android.Manifest.permission.ACCESS_CONTEXT_HUB) public void registerEndpoint(@NonNull android.hardware.contexthub.HubEndpoint); + method @FlaggedApi("android.chre.flags.offload_api") @RequiresPermission(android.Manifest.permission.ACCESS_CONTEXT_HUB) public void registerEndpointDiscoveryCallback(long, @NonNull android.hardware.contexthub.IHubEndpointDiscoveryCallback); + method @FlaggedApi("android.chre.flags.offload_api") @RequiresPermission(android.Manifest.permission.ACCESS_CONTEXT_HUB) public void registerEndpointDiscoveryCallback(long, @NonNull android.hardware.contexthub.IHubEndpointDiscoveryCallback, @NonNull java.util.concurrent.Executor); + method @FlaggedApi("android.chre.flags.offload_api") @RequiresPermission(android.Manifest.permission.ACCESS_CONTEXT_HUB) public void registerEndpointDiscoveryCallback(@NonNull String, @NonNull android.hardware.contexthub.IHubEndpointDiscoveryCallback); + method @FlaggedApi("android.chre.flags.offload_api") @RequiresPermission(android.Manifest.permission.ACCESS_CONTEXT_HUB) public void registerEndpointDiscoveryCallback(@NonNull String, @NonNull android.hardware.contexthub.IHubEndpointDiscoveryCallback, @NonNull java.util.concurrent.Executor); method @Deprecated @RequiresPermission(android.Manifest.permission.ACCESS_CONTEXT_HUB) public int sendMessage(int, int, @NonNull android.hardware.location.ContextHubMessage); method @Deprecated @RequiresPermission(android.Manifest.permission.ACCESS_CONTEXT_HUB) public int unloadNanoApp(int); method @NonNull @RequiresPermission(android.Manifest.permission.ACCESS_CONTEXT_HUB) public android.hardware.location.ContextHubTransaction unloadNanoApp(@NonNull android.hardware.location.ContextHubInfo, long); method @Deprecated public int unregisterCallback(@NonNull android.hardware.location.ContextHubManager.Callback); method @FlaggedApi("android.chre.flags.offload_api") @RequiresPermission(android.Manifest.permission.ACCESS_CONTEXT_HUB) public void unregisterEndpoint(@NonNull android.hardware.contexthub.HubEndpoint); + method @FlaggedApi("android.chre.flags.offload_api") @RequiresPermission(android.Manifest.permission.ACCESS_CONTEXT_HUB) public void unregisterEndpointDiscoveryCallback(@NonNull android.hardware.contexthub.IHubEndpointDiscoveryCallback); field public static final int AUTHORIZATION_DENIED = 0; // 0x0 field public static final int AUTHORIZATION_DENIED_GRACE_PERIOD = 1; // 0x1 field public static final int AUTHORIZATION_GRANTED = 2; // 0x2 @@ -7668,9 +7637,11 @@ package android.media { method public boolean isActive(); method @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) public boolean isMuted(); method public boolean isSpatialized(); - field @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) public static final int MUTED_BY_APP_OPS = 8; // 0x8 + field @Deprecated @FlaggedApi("android.media.audio.muted_by_port_volume_api") @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) public static final int MUTED_BY_APP_OPS = 8; // 0x8 field @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) public static final int MUTED_BY_CLIENT_VOLUME = 16; // 0x10 field @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) public static final int MUTED_BY_MASTER = 1; // 0x1 + field @FlaggedApi("android.media.audio.muted_by_port_volume_api") @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) public static final int MUTED_BY_OP_CONTROL_AUDIO = 128; // 0x80 + field @FlaggedApi("android.media.audio.muted_by_port_volume_api") @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) public static final int MUTED_BY_OP_PLAY_AUDIO = 8; // 0x8 field @FlaggedApi("android.media.audio.muted_by_port_volume_api") @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) public static final int MUTED_BY_PORT_VOLUME = 64; // 0x40 field @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) public static final int MUTED_BY_STREAM_MUTED = 4; // 0x4 field @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) public static final int MUTED_BY_STREAM_VOLUME = 2; // 0x2 @@ -8154,8 +8125,13 @@ package android.media.quality { 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 getSoundProfileAllowList(); + method @NonNull public java.util.List getSoundProfilePackageNames(); + method @NonNull public java.util.List getSoundProfilesByPackage(@NonNull String); method public void setAutoPictureQualityEnabled(boolean); + method public void setAutoSoundQualityEnabled(boolean); method public void setPictureProfileAllowList(@NonNull java.util.List); + method public void setSoundProfileAllowList(@NonNull java.util.List); method public void setSuperResolutionEnabled(boolean); } @@ -8165,6 +8141,20 @@ package android.media.quality { method @NonNull public android.media.quality.PictureProfile.Builder setProfileType(int); } + @FlaggedApi("android.media.tv.flags.apply_picture_profiles") public final class PictureProfileHandle implements android.os.Parcelable { + method @FlaggedApi("android.media.tv.flags.apply_picture_profiles") public int describeContents(); + method @FlaggedApi("android.media.tv.flags.apply_picture_profiles") public long getId(); + method @FlaggedApi("android.media.tv.flags.apply_picture_profiles") public void writeToParcel(@NonNull android.os.Parcel, int); + field @FlaggedApi("android.media.tv.flags.apply_picture_profiles") @NonNull public static final android.os.Parcelable.Creator CREATOR; + field @NonNull public static final android.media.quality.PictureProfileHandle NONE; + } + + public static final class SoundProfile.Builder { + method @NonNull public android.media.quality.SoundProfile.Builder setInputId(@NonNull String); + method @NonNull public android.media.quality.SoundProfile.Builder setPackageName(@NonNull String); + method @NonNull public android.media.quality.SoundProfile.Builder setProfileType(int); + } + } package android.media.session { @@ -9893,7 +9883,7 @@ package android.media.tv.tuner.frontend { method public int getSignalStrength(); method public int getSnr(); method public int getSpectralInversion(); - method @FlaggedApi("android.media.tv.flags.tuner_w_apis") @NonNull public android.media.tv.tuner.frontend.StandardExt getStandardExt(); + method @FlaggedApi("android.media.tv.flags.tuner_w_apis") @NonNull public android.media.tv.tuner.frontend.StandardExtension getStandardExtension(); method @NonNull public int[] getStreamIds(); method public int getSymbolRate(); method @IntRange(from=0, to=65535) public int getSystemId(); @@ -9948,7 +9938,7 @@ package android.media.tv.tuner.frontend { field public static final int FRONTEND_STATUS_TYPE_SIGNAL_STRENGTH = 6; // 0x6 field public static final int FRONTEND_STATUS_TYPE_SNR = 1; // 0x1 field public static final int FRONTEND_STATUS_TYPE_SPECTRAL = 10; // 0xa - field @FlaggedApi("android.media.tv.flags.tuner_w_apis") public static final int FRONTEND_STATUS_TYPE_STANDARD_EXT = 47; // 0x2f + field @FlaggedApi("android.media.tv.flags.tuner_w_apis") public static final int FRONTEND_STATUS_TYPE_STANDARD_EXTENSION = 47; // 0x2f field public static final int FRONTEND_STATUS_TYPE_STREAM_IDS = 39; // 0x27 field public static final int FRONTEND_STATUS_TYPE_SYMBOL_RATE = 7; // 0x7 field public static final int FRONTEND_STATUS_TYPE_T2_SYSTEM_ID = 29; // 0x1d @@ -10240,9 +10230,9 @@ package android.media.tv.tuner.frontend { method public default void onUnlocked(); } - @FlaggedApi("android.media.tv.flags.tuner_w_apis") public final class StandardExt { - method public int getDvbsStandardExt(); - method public int getDvbtStandardExt(); + @FlaggedApi("android.media.tv.flags.tuner_w_apis") public final class StandardExtension { + method public int getDvbsStandardExtension(); + method public int getDvbtStandardExtension(); } } @@ -11135,6 +11125,7 @@ package android.nfc.cardemulation { method @FlaggedApi("android.nfc.enable_nfc_mainline") public void setDynamicAidGroup(@NonNull android.nfc.cardemulation.AidGroup); method @FlaggedApi("android.nfc.enable_nfc_mainline") public void setOffHostSecureElement(@NonNull String); method @FlaggedApi("android.nfc.nfc_observe_mode") public void setShouldDefaultToObserveMode(boolean); + method @FlaggedApi("android.nfc.nfc_associated_role_services") public boolean shareRolePriority(); method @FlaggedApi("android.nfc.nfc_observe_mode") public boolean shouldDefaultToObserveMode(); method @FlaggedApi("android.nfc.enable_nfc_mainline") public void writeToParcel(@NonNull android.os.Parcel, int); field @FlaggedApi("android.nfc.enable_nfc_mainline") @NonNull public static final android.os.Parcelable.Creator CREATOR; @@ -12842,8 +12833,8 @@ package android.security.advancedprotection { @FlaggedApi("android.security.aapm_api") public final class AdvancedProtectionManager { method @NonNull public android.content.Intent createSupportIntent(@NonNull String, @Nullable String); - method @NonNull @RequiresPermission(android.Manifest.permission.SET_ADVANCED_PROTECTION_MODE) public java.util.List getAdvancedProtectionFeatures(); - method @RequiresPermission(android.Manifest.permission.SET_ADVANCED_PROTECTION_MODE) public void setAdvancedProtectionEnabled(boolean); + method @NonNull @RequiresPermission(android.Manifest.permission.MANAGE_ADVANCED_PROTECTION_MODE) public java.util.List getAdvancedProtectionFeatures(); + method @RequiresPermission(android.Manifest.permission.MANAGE_ADVANCED_PROTECTION_MODE) public void setAdvancedProtectionEnabled(boolean); field @FlaggedApi("android.security.aapm_api") public static final String ACTION_SHOW_ADVANCED_PROTECTION_SUPPORT_DIALOG = "android.security.advancedprotection.action.SHOW_ADVANCED_PROTECTION_SUPPORT_DIALOG"; field public static final String EXTRA_SUPPORT_DIALOG_FEATURE = "android.security.advancedprotection.extra.SUPPORT_DIALOG_FEATURE"; field public static final String EXTRA_SUPPORT_DIALOG_TYPE = "android.security.advancedprotection.extra.SUPPORT_DIALOG_TYPE"; @@ -12858,13 +12849,67 @@ package android.security.advancedprotection { } -package android.security.forensic { +package android.security.authenticationpolicy { + + @FlaggedApi("android.security.secure_lockdown") public final class AuthenticationPolicyManager { + method @FlaggedApi("android.security.secure_lockdown") @RequiresPermission(android.Manifest.permission.MANAGE_SECURE_LOCK_DEVICE) public int disableSecureLockDevice(@NonNull android.security.authenticationpolicy.DisableSecureLockDeviceParams); + method @FlaggedApi("android.security.secure_lockdown") @RequiresPermission(android.Manifest.permission.MANAGE_SECURE_LOCK_DEVICE) public int enableSecureLockDevice(@NonNull android.security.authenticationpolicy.EnableSecureLockDeviceParams); + field @FlaggedApi("android.security.secure_lockdown") public static final int ERROR_ALREADY_ENABLED = 6; // 0x6 + field @FlaggedApi("android.security.secure_lockdown") public static final int ERROR_INSUFFICIENT_BIOMETRICS = 5; // 0x5 + field @FlaggedApi("android.security.secure_lockdown") public static final int ERROR_INVALID_PARAMS = 3; // 0x3 + field @FlaggedApi("android.security.secure_lockdown") public static final int ERROR_NO_BIOMETRICS_ENROLLED = 4; // 0x4 + field @FlaggedApi("android.security.secure_lockdown") public static final int ERROR_UNKNOWN = 0; // 0x0 + field @FlaggedApi("android.security.secure_lockdown") public static final int ERROR_UNSUPPORTED = 2; // 0x2 + field @FlaggedApi("android.security.secure_lockdown") public static final int SUCCESS = 1; // 0x1 + } + + @FlaggedApi("android.security.secure_lockdown") public final class DisableSecureLockDeviceParams implements android.os.Parcelable { + ctor public DisableSecureLockDeviceParams(@NonNull String); + 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); + method public int describeContents(); + method public void writeToParcel(@NonNull android.os.Parcel, int); + field @NonNull public static final android.os.Parcelable.Creator CREATOR; + } + +} + +package android.security.intrusiondetection { + + @FlaggedApi("android.security.afl_api") public final class IntrusionDetectionEvent implements android.os.Parcelable { + ctor public IntrusionDetectionEvent(@NonNull android.app.admin.SecurityLog.SecurityEvent); + ctor public IntrusionDetectionEvent(@NonNull android.app.admin.DnsEvent); + ctor public IntrusionDetectionEvent(@NonNull android.app.admin.ConnectEvent); + method @FlaggedApi("android.security.afl_api") public int describeContents(); + method @NonNull public android.app.admin.ConnectEvent getConnectEvent(); + method @NonNull public android.app.admin.DnsEvent getDnsEvent(); + method @NonNull public android.app.admin.SecurityLog.SecurityEvent getSecurityEvent(); + method @NonNull public int getType(); + method public void writeToParcel(@NonNull android.os.Parcel, int); + field @NonNull public static final android.os.Parcelable.Creator CREATOR; + field public static final int NETWORK_EVENT_CONNECT = 2; // 0x2 + field public static final int NETWORK_EVENT_DNS = 1; // 0x1 + field public static final int SECURITY_EVENT = 0; // 0x0 + } - @FlaggedApi("android.security.afl_api") public class ForensicManager { - method @RequiresPermission(android.Manifest.permission.READ_FORENSIC_STATE) public void addStateCallback(@NonNull java.util.concurrent.Executor, @NonNull java.util.function.Consumer); - method @RequiresPermission(android.Manifest.permission.MANAGE_FORENSIC_STATE) public void disable(@NonNull java.util.concurrent.Executor, @NonNull android.security.forensic.ForensicManager.CommandCallback); - method @RequiresPermission(android.Manifest.permission.MANAGE_FORENSIC_STATE) public void enable(@NonNull java.util.concurrent.Executor, @NonNull android.security.forensic.ForensicManager.CommandCallback); - method @RequiresPermission(android.Manifest.permission.READ_FORENSIC_STATE) public void removeStateCallback(@NonNull java.util.function.Consumer); + @FlaggedApi("android.security.afl_api") public class IntrusionDetectionEventTransport { + ctor public IntrusionDetectionEventTransport(); + method public boolean addData(@NonNull java.util.List); + method @NonNull public android.os.IBinder getBinder(); + method public boolean initialize(); + method public boolean release(); + } + + @FlaggedApi("android.security.afl_api") public class IntrusionDetectionManager { + method @RequiresPermission(android.Manifest.permission.READ_INTRUSION_DETECTION_STATE) public void addStateCallback(@NonNull java.util.concurrent.Executor, @NonNull java.util.function.Consumer); + method @RequiresPermission(android.Manifest.permission.MANAGE_INTRUSION_DETECTION_STATE) public void disable(@NonNull java.util.concurrent.Executor, @NonNull android.security.intrusiondetection.IntrusionDetectionManager.CommandCallback); + method @RequiresPermission(android.Manifest.permission.MANAGE_INTRUSION_DETECTION_STATE) public void enable(@NonNull java.util.concurrent.Executor, @NonNull android.security.intrusiondetection.IntrusionDetectionManager.CommandCallback); + method @RequiresPermission(android.Manifest.permission.READ_INTRUSION_DETECTION_STATE) public void removeStateCallback(@NonNull java.util.function.Consumer); field public static final int ERROR_DATA_SOURCE_UNAVAILABLE = 4; // 0x4 field public static final int ERROR_PERMISSION_DENIED = 1; // 0x1 field public static final int ERROR_TRANSPORT_UNAVAILABLE = 3; // 0x3 @@ -12874,7 +12919,7 @@ package android.security.forensic { field public static final int STATE_UNKNOWN = 0; // 0x0 } - public static interface ForensicManager.CommandCallback { + public static interface IntrusionDetectionManager.CommandCallback { method public void onFailure(int); method public void onSuccess(); } @@ -14546,7 +14591,7 @@ package android.service.wearable { method @BinderThread public abstract void onDataStreamProvided(@NonNull android.os.ParcelFileDescriptor, @NonNull java.util.function.Consumer); method @BinderThread public abstract void onQueryServiceStatus(@NonNull java.util.Set, @NonNull String, @NonNull java.util.function.Consumer); method @FlaggedApi("android.app.wearable.enable_provide_read_only_pfd") @BinderThread public void onReadOnlyParcelFileDescriptorProvided(@NonNull android.os.ParcelFileDescriptor, @NonNull android.os.PersistableBundle, @NonNull java.util.function.Consumer); - method @BinderThread public void onSecureConnectionProvided(@NonNull android.os.ParcelFileDescriptor, @NonNull java.util.function.Consumer); + method @Deprecated @FlaggedApi("android.app.wearable.enable_concurrent_wearable_connections") @BinderThread public void onSecureConnectionProvided(@NonNull android.os.ParcelFileDescriptor, @NonNull java.util.function.Consumer); method @FlaggedApi("android.app.wearable.enable_concurrent_wearable_connections") @BinderThread public void onSecureConnectionProvided(@NonNull android.os.ParcelFileDescriptor, @NonNull android.os.PersistableBundle, @NonNull java.util.function.Consumer); method @BinderThread public abstract void onStartDetection(@NonNull android.app.ambientcontext.AmbientContextEventRequest, @NonNull String, @NonNull java.util.function.Consumer, @NonNull java.util.function.Consumer); method @FlaggedApi("android.app.wearable.enable_hotword_wearable_sensing_api") @BinderThread public void onStartHotwordRecognition(@NonNull java.util.function.Consumer, @NonNull java.util.function.Consumer); @@ -16191,6 +16236,7 @@ package android.telephony { method @Nullable @RequiresPermission(android.Manifest.permission.INTERACT_ACROSS_USERS) public android.content.ComponentName getAndUpdateDefaultRespondViaMessageApplication(); method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public void getCallForwarding(int, @NonNull java.util.concurrent.Executor, @NonNull android.telephony.TelephonyManager.CallForwardingInfoCallback); method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public void getCallWaitingStatus(@NonNull java.util.concurrent.Executor, @NonNull java.util.function.Consumer); + method @FlaggedApi("com.android.internal.telephony.flags.carrier_id_from_carrier_identifier") @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) @WorkerThread public int getCarrierIdFromCarrierIdentifier(@NonNull android.service.carrier.CarrierIdentifier); method @Nullable @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public android.telephony.ImsiEncryptionInfo getCarrierInfoForImsiEncryption(int); method public java.util.List getCarrierPackageNamesForIntent(android.content.Intent); method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public java.util.List getCarrierPackageNamesForIntentAndPhone(android.content.Intent, int); @@ -18963,6 +19009,10 @@ package android.util { package android.view { + public static class SurfaceControl.Transaction implements java.io.Closeable android.os.Parcelable { + method @FlaggedApi("android.media.tv.flags.apply_picture_profiles") @NonNull public android.view.SurfaceControl.Transaction setPictureProfileHandle(@NonNull android.view.SurfaceControl, @NonNull android.media.quality.PictureProfileHandle); + } + @UiThread public class View implements android.view.accessibility.AccessibilityEventSource android.graphics.drawable.Drawable.Callback android.view.KeyEvent.Callback { method @NonNull public final java.util.List getUnrestrictedPreferKeepClearRects(); method @RequiresPermission(android.Manifest.permission.SET_UNRESTRICTED_KEEP_CLEAR_AREAS) public final void setUnrestrictedPreferKeepClearRects(@NonNull java.util.List); diff --git a/core/api/test-current.txt b/core/api/test-current.txt index 44bcc2a737b9042cb44d295dd9b43b5894476f71..967f6194969e1e563c3dfc3939fde5855b47968c 100644 --- a/core/api/test-current.txt +++ b/core/api/test-current.txt @@ -1805,6 +1805,7 @@ package android.hardware.input { method @RequiresPermission(android.Manifest.permission.REMAP_MODIFIER_KEYS) public void remapModifierKey(int, int); method @FlaggedApi("com.android.input.flags.device_associations") @RequiresPermission("android.permission.ASSOCIATE_INPUT_DEVICE_TO_DISPLAY") public void removeUniqueIdAssociationByDescriptor(@NonNull String); method @RequiresPermission("android.permission.ASSOCIATE_INPUT_DEVICE_TO_DISPLAY") public void removeUniqueIdAssociationByPort(@NonNull String); + method public void resetLockedModifierState(); field public static final long BLOCK_UNTRUSTED_TOUCHES = 158002302L; // 0x96aec7eL } @@ -2492,6 +2493,7 @@ package android.os { method public boolean areAutoPowerSaveModesEnabled(); method @RequiresPermission(anyOf={android.Manifest.permission.MANAGE_LOW_POWER_STANDBY, android.Manifest.permission.DEVICE_POWER}) public void forceLowPowerStandbyActive(boolean); method @FlaggedApi("android.os.battery_saver_supported_check_api") public boolean isBatterySaverSupported(); + method public boolean isInteractive(int); field public static final String ACTION_ENHANCED_DISCHARGE_PREDICTION_CHANGED = "android.os.action.ENHANCED_DISCHARGE_PREDICTION_CHANGED"; field @RequiresPermission(android.Manifest.permission.DEVICE_POWER) public static final int SYSTEM_WAKELOCK = -2147483648; // 0x80000000 } @@ -2781,6 +2783,17 @@ package android.os.storage { package android.os.vibrator { + @FlaggedApi("android.os.vibrator.normalized_pwle_effects") public final class BasicPwleSegment extends android.os.vibrator.VibrationEffectSegment { + method public int describeContents(); + method public long getDuration(); + method public float getEndIntensity(); + method public float getEndSharpness(); + method public float getStartIntensity(); + method public float getStartSharpness(); + method public void writeToParcel(@NonNull android.os.Parcel, int); + field @NonNull public static final android.os.Parcelable.Creator CREATOR; + } + public final class PrebakedSegment extends android.os.vibrator.VibrationEffectSegment { method public int describeContents(); method public long getDuration(); @@ -3282,7 +3295,7 @@ package android.service.quicksettings { package android.service.settings.preferences { @FlaggedApi("com.android.settingslib.flags.settings_catalyst") public class SettingsPreferenceServiceClient implements java.lang.AutoCloseable { - ctor public SettingsPreferenceServiceClient(@NonNull android.content.Context, @NonNull String, boolean, @Nullable android.content.ServiceConnection); + ctor public SettingsPreferenceServiceClient(@NonNull android.content.Context, @NonNull String, boolean, @NonNull java.util.concurrent.Executor, @NonNull android.os.OutcomeReceiver); } } @@ -3717,6 +3730,7 @@ package android.view { method @NonNull public android.view.Display.Mode getDefaultMode(); method public int getRemoveMode(); method @NonNull public int[] getReportedHdrTypes(); + method @NonNull public float[] getSupportedRefreshRatesLegacy(); method @NonNull public android.graphics.ColorSpace[] getSupportedWideColorGamut(); method @Nullable public android.view.Display.Mode getSystemPreferredDisplayMode(); method public int getType(); @@ -3739,6 +3753,7 @@ package android.view { public static final class Display.Mode implements android.os.Parcelable { ctor public Display.Mode(int, int, float); + method public float getVsyncRate(); method public boolean isSynthetic(); method public boolean matches(int, int, float); } diff --git a/core/api/test-lint-baseline.txt b/core/api/test-lint-baseline.txt index c2fac70d1f68d9fd23b7e33664c17af554ae7ffc..9140bdf4fba790251139e9e4424fbec60acde3e6 100644 --- a/core/api/test-lint-baseline.txt +++ b/core/api/test-lint-baseline.txt @@ -2139,6 +2139,8 @@ UnflaggedApi: android.os.BugreportParams#BUGREPORT_MODE_MAX_VALUE: New API must be flagged with @FlaggedApi: field android.os.BugreportParams.BUGREPORT_MODE_MAX_VALUE UnflaggedApi: android.os.PowerManager#isBatterySaverSupported(): New API must be flagged with @FlaggedApi: method android.os.PowerManager.isBatterySaverSupported() +UnflaggedApi: android.os.PowerManager#isInteractive(int): + New API must be flagged with @FlaggedApi: method android.os.PowerManager.isInteractive(int) UnflaggedApi: android.os.UserHandle#USER_CURRENT: New API must be flagged with @FlaggedApi: field android.os.UserHandle.USER_CURRENT UnflaggedApi: android.os.UserManager#getAliveUsers(): diff --git a/core/java/Android.bp b/core/java/Android.bp index bc38294279a82367bfd915d44238c1c01d5eb2e6..ce767f46dd5006869ea0997f2ab78b1345de73e3 100644 --- a/core/java/Android.bp +++ b/core/java/Android.bp @@ -236,6 +236,7 @@ aidl_interface { "android/os/GpuHeadroomParamsInternal.aidl", "android/os/IHintManager.aidl", "android/os/IHintSession.aidl", + "android/os/SessionCreationConfig.aidl", ], unstable: true, backend: { @@ -689,43 +690,8 @@ java_library { // protolog end -// Whether to enable read-only system feature codegen. -gen_readonly_feature_apis = select(release_flag("RELEASE_USE_SYSTEM_FEATURE_BUILD_FLAGS"), { - true: "true", - false: "false", - default: "false", -}) - -// Generates com.android.internal.pm.RoSystemFeatures, optionally compiling in -// details about fixed system features defined by build flags. When disabled, -// the APIs are simply passthrough stubs with no meaningful side effects. -// TODO(b/203143243): Implement the `--feature=` aggregation directly with a native soong module. -genrule { +java_system_features_srcs { name: "systemfeatures-gen-srcs", - cmd: "$(location systemfeatures-gen-tool) com.android.internal.pm.RoSystemFeatures " + - // --readonly=false (default) makes the codegen an effective no-op passthrough API. - " --readonly=" + gen_readonly_feature_apis + - " --feature=AUTOMOTIVE:" + select(release_flag("RELEASE_SYSTEM_FEATURE_AUTOMOTIVE"), { - any @ value: value, - default: "", - }) + " --feature=EMBEDDED:" + select(release_flag("RELEASE_SYSTEM_FEATURE_EMBEDDED"), { - any @ value: value, - default: "", - }) + " --feature=LEANBACK:" + select(release_flag("RELEASE_SYSTEM_FEATURE_LEANBACK"), { - any @ value: value, - default: "", - }) + " --feature=PC:" + select(release_flag("RELEASE_SYSTEM_FEATURE_PC"), { - any @ value: value, - default: "", - }) + " --feature=TELEVISION:" + select(release_flag("RELEASE_SYSTEM_FEATURE_TELEVISION"), { - any @ value: value, - default: "", - }) + " --feature=WATCH:" + select(release_flag("RELEASE_SYSTEM_FEATURE_WATCH"), { - any @ value: value, - default: "", - }) + " > $(out)", - out: [ - "RoSystemFeatures.java", - ], - tools: ["systemfeatures-gen-tool"], + full_class_name: "com.android.internal.pm.RoSystemFeatures", + visibility: ["//visibility:private"], } diff --git a/core/java/android/accounts/AccountManager.java b/core/java/android/accounts/AccountManager.java index 87acbbf65b2f84e9bb649c58c787d1ea5dc47599..72450999993decb09555e8306dc7fe80cca3582e 100644 --- a/core/java/android/accounts/AccountManager.java +++ b/core/java/android/accounts/AccountManager.java @@ -16,9 +16,13 @@ package android.accounts; +import static android.Manifest.permission.COPY_ACCOUNTS; +import static android.Manifest.permission.REMOVE_ACCOUNTS; import static android.Manifest.permission.INTERACT_ACROSS_USERS_FULL; +import static android.app.admin.flags.Flags.FLAG_SPLIT_CREATE_MANAGED_PROFILE_ENABLED; import android.annotation.BroadcastBehavior; +import android.annotation.FlaggedApi; import android.annotation.IntDef; import android.annotation.NonNull; import android.annotation.Nullable; @@ -26,6 +30,7 @@ import android.annotation.RequiresPermission; import android.annotation.SdkConstant; import android.annotation.SdkConstant.SdkConstantType; import android.annotation.Size; +import android.annotation.SuppressLint; import android.annotation.SystemApi; import android.annotation.SystemService; import android.annotation.UserHandleAware; @@ -1312,7 +1317,8 @@ public class AccountManager { * {@link AccountManagerFuture} must not be used on the main thread. * *

This method requires the caller to have a signature match with the - * authenticator that manages the specified account. + * authenticator that manages the specified account, be a profile owner or have the + * {@link android.Manifest.permission#REMOVE_ACCOUNTS} permission. * *

NOTE: If targeting your app to work on API level 22 and before, * MANAGE_ACCOUNTS permission is needed for those platforms. See docs for @@ -1344,6 +1350,8 @@ public class AccountManager { * */ @UserHandleAware + @RequiresPermission(value = REMOVE_ACCOUNTS, conditional = true) + @FlaggedApi(FLAG_SPLIT_CREATE_MANAGED_PROFILE_ENABLED) public AccountManagerFuture removeAccount(final Account account, final Activity activity, AccountManagerCallback callback, Handler handler) { return removeAccountAsUser(account, activity, callback, handler, mContext.getUser()); @@ -2019,9 +2027,15 @@ public class AccountManager { * succeeded. * @hide */ + @SuppressLint("SamShouldBeLast") + @NonNull + @SystemApi + @RequiresPermission(anyOf = {COPY_ACCOUNTS, INTERACT_ACROSS_USERS_FULL}) + @FlaggedApi(FLAG_SPLIT_CREATE_MANAGED_PROFILE_ENABLED) public AccountManagerFuture copyAccountToUser( - final Account account, final UserHandle fromUser, final UserHandle toUser, - AccountManagerCallback callback, Handler handler) { + @NonNull final Account account, @NonNull final UserHandle fromUser, + @NonNull final UserHandle toUser, @Nullable AccountManagerCallback callback, + @Nullable Handler handler) { if (account == null) throw new IllegalArgumentException("account is null"); if (toUser == null || fromUser == null) { throw new IllegalArgumentException("fromUser and toUser cannot be null"); diff --git a/core/java/android/animation/AnimatorSet.java b/core/java/android/animation/AnimatorSet.java index 76098db2dc5b3a85319039fffd64c343d8725822..78566d2fe98dc19e90d99046e55e22c9302c353c 100644 --- a/core/java/android/animation/AnimatorSet.java +++ b/core/java/android/animation/AnimatorSet.java @@ -1227,7 +1227,7 @@ public final class AnimatorSet extends Animator implements AnimationHandler.Anim } if (finished) { - endAnimation(); + endAnimation(true /* fromLastFrame */); return true; } return false; @@ -1442,8 +1442,12 @@ public final class AnimatorSet extends Animator implements AnimationHandler.Anim } private void endAnimation() { + endAnimation(false /* fromLastFrame */); + } + + private void endAnimation(boolean fromLastFrame) { final boolean postNotifyEndListener = sPostNotifyEndListenerEnabled && mListeners != null - && mLastFrameTime > 0; + && fromLastFrame && mTotalDuration > 0; mStarted = false; mLastFrameTime = -1; mFirstFrame = -1; diff --git a/core/java/android/animation/ValueAnimator.java b/core/java/android/animation/ValueAnimator.java index e849abaf4aec9990b75f22f8ab961ad9e50f1f7c..492c2ffc561f45adf0afe32f5e2a95bb6cb43eb6 100644 --- a/core/java/android/animation/ValueAnimator.java +++ b/core/java/android/animation/ValueAnimator.java @@ -1281,16 +1281,20 @@ public class ValueAnimator extends Animator implements AnimationHandler.Animatio return true; } + private void endAnimation() { + endAnimation(false /* fromLastFrame */); + } + /** * Called internally to end an animation by removing it from the animations list. Must be * called on the UI thread. */ - private void endAnimation() { + private void endAnimation(boolean fromLastFrame) { if (mAnimationEndRequested) { return; } final boolean postNotifyEndListener = sPostNotifyEndListenerEnabled && mListeners != null - && mLastFrameTime > 0; + && fromLastFrame && getScaledDuration() > 0; removeAnimationCallback(); mAnimationEndRequested = true; @@ -1570,7 +1574,7 @@ public class ValueAnimator extends Animator implements AnimationHandler.Animatio boolean finished = animateBasedOnTime(currentTime); if (finished) { - endAnimation(); + endAnimation(true /* fromLastFrame */); } return finished; } diff --git a/core/java/android/app/Activity.java b/core/java/android/app/Activity.java index 419eb7dac5f081dc90e7079461f48e79c611548a..38aea64386a0e32b32f400afeda298df8b63d6f8 100644 --- a/core/java/android/app/Activity.java +++ b/core/java/android/app/Activity.java @@ -1270,27 +1270,22 @@ public class Activity extends ContextThemeWrapper } /** - * To make users aware of system features such as the app header menu and its various - * functionalities, educational dialogs are shown to demonstrate how to find and utilize these - * features. Using this method, an activity can specify if it wants these educational dialogs to - * be shown. When set to {@code true}, these dialogs are not completely blocked; however, the - * system will be notified that they should not be shown unless necessary. If this API is not - * called, the system's educational dialogs are not limited by default. - * - *

This method can be utilized when activities have states where showing an - * educational dialog would be disruptive to the user. For example, if a game application is - * expecting prompt user input, this method can be used to limit educational dialogs such as the - * dialogs that showcase the app header's features which, in this instance, would disrupt the - * user's experience if shown.

- * - *

Note that educational dialogs may be shown soon after this activity is launched, so - * this method must be called early if the intent is to limit the dialogs from the start.

+ * Requests to show the “Open in browser” education. “Open in browser” is a feature + * within the app header that allows users to switch from an app to the web. The feature + * is made available when an application is opened by a user clicking a link or when a + * link is provided by an application. Links can be provided by utilizing + * {@link AssistContent#EXTRA_AUTHENTICATING_USER_WEB_URI} or + * {@link AssistContent#setWebUri}. + * + *

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.

*/ @FlaggedApi(com.android.window.flags.Flags.FLAG_ENABLE_DESKTOP_WINDOWING_APP_TO_WEB_EDUCATION) - public final void setLimitSystemEducationDialogs(boolean limitSystemEducationDialogs) { + public final void requestOpenInBrowserEducation() { try { ActivityTaskManager - .getService().setLimitSystemEducationDialogs(mToken, limitSystemEducationDialogs); + .getService().requestOpenInBrowserEducation(mToken); } catch (RemoteException e) { // Empty } diff --git a/core/java/android/app/ActivityManager.java b/core/java/android/app/ActivityManager.java index ab75069cc5d8b42d11015b6b1d9ab3f2b8f80616..33ba0586504243a3fee4fd5bdc7f5ea2390565a9 100644 --- a/core/java/android/app/ActivityManager.java +++ b/core/java/android/app/ActivityManager.java @@ -2678,62 +2678,6 @@ public class ActivityManager { * started or visited. */ public static class RecentTaskInfo extends TaskInfo implements Parcelable { - /** - * @hide - */ - public static class PersistedTaskSnapshotData { - /** - * The bounds of the task when the last snapshot was taken, may be null if the task is - * not yet attached to the hierarchy. - * @see {@link android.window.TaskSnapshot#mTaskSize}. - * @hide - */ - public @Nullable Point taskSize; - - /** - * The content insets of the task when the task snapshot was taken. - * @see {@link android.window.TaskSnapshot#mContentInsets}. - * @hide - */ - public @Nullable Rect contentInsets; - - /** - * The size of the last snapshot taken, may be null if there is no associated snapshot. - * @see {@link android.window.TaskSnapshot#mSnapshot}. - * @hide - */ - public @Nullable Point bufferSize; - - /** - * Sets the data from the other data. - * @hide - */ - public void set(PersistedTaskSnapshotData other) { - taskSize = other.taskSize; - contentInsets = other.contentInsets; - bufferSize = other.bufferSize; - } - - /** - * Sets the data from the provided {@param snapshot}. - * @hide - */ - public void set(TaskSnapshot snapshot) { - if (snapshot == null) { - taskSize = null; - contentInsets = null; - bufferSize = null; - return; - } - final HardwareBuffer buffer = snapshot.getHardwareBuffer(); - taskSize = new Point(snapshot.getTaskSize()); - contentInsets = new Rect(snapshot.getContentInsets()); - bufferSize = buffer != null - ? new Point(buffer.getWidth(), buffer.getHeight()) - : null; - } - } - /** * If this task is currently running, this is the identifier for it. * If it is not running, this will be -1. @@ -2770,24 +2714,6 @@ public class ActivityManager { @Deprecated public int affiliatedTaskId; - /** - * Information of organized child tasks. - * - * @deprecated No longer used - * @hide - */ - @Deprecated - public ArrayList childrenTaskInfos = new ArrayList<>(); - - /** - * Information about the last snapshot taken for this task. - * - * @deprecated No longer used - * @hide - */ - @Deprecated - public PersistedTaskSnapshotData lastSnapshotData = new PersistedTaskSnapshotData(); - public RecentTaskInfo() { } @@ -2803,10 +2729,6 @@ public class ActivityManager { public void readFromParcel(Parcel source) { id = source.readInt(); persistentId = source.readInt(); - childrenTaskInfos = source.readArrayList(RecentTaskInfo.class.getClassLoader(), android.app.ActivityManager.RecentTaskInfo.class); - lastSnapshotData.taskSize = source.readTypedObject(Point.CREATOR); - lastSnapshotData.contentInsets = source.readTypedObject(Rect.CREATOR); - lastSnapshotData.bufferSize = source.readTypedObject(Point.CREATOR); super.readTaskFromParcel(source); } @@ -2814,10 +2736,6 @@ public class ActivityManager { public void writeToParcel(Parcel dest, int flags) { dest.writeInt(id); dest.writeInt(persistentId); - dest.writeList(childrenTaskInfos); - dest.writeTypedObject(lastSnapshotData.taskSize, flags); - dest.writeTypedObject(lastSnapshotData.contentInsets, flags); - dest.writeTypedObject(lastSnapshotData.bufferSize, flags); super.writeTaskToParcel(dest, flags); } @@ -2884,11 +2802,6 @@ public class ActivityManager { pw.println(" }"); } pw.print(" "); - pw.print(" lastSnapshotData {"); - pw.print(" taskSize=" + lastSnapshotData.taskSize); - pw.print(" contentInsets=" + lastSnapshotData.contentInsets); - pw.print(" bufferSize=" + lastSnapshotData.bufferSize); - pw.println(" }"); } } diff --git a/core/java/android/app/ActivityManagerInternal.java b/core/java/android/app/ActivityManagerInternal.java index f80121d0c9b6914d4d2e55942a5558e7c3b4b9c4..eccb6ffb281c34866fa8c8efe34c78fbdbf6f969 100644 --- a/core/java/android/app/ActivityManagerInternal.java +++ b/core/java/android/app/ActivityManagerInternal.java @@ -1149,6 +1149,33 @@ public abstract class ActivityManagerInternal { */ public abstract void stopForegroundServiceDelegate(@NonNull ServiceConnection connection); + /** + * Notifies that a media foreground service associated with a media session has + * transitioned to a "user-disengaged" state. + * Upon receiving this notification, service may be removed from the foreground state. It + * should only be called by {@link com.android.server.media.MediaSessionService} + * + * @param packageName The package name of the app running the media foreground service. + * @param userId The user ID associated with the foreground service. + * @param notificationId The ID of the media notification associated with the foreground + * service. + */ + public abstract void notifyInactiveMediaForegroundService(@NonNull String packageName, + @UserIdInt int userId, int notificationId); + + /** + * Notifies that a media service associated with a media session has transitioned to a + * "user-engaged" state. Upon receiving this notification, service will transition to the + * foreground state. It should only be called by + * {@link com.android.server.media.MediaSessionService} + * + * @param packageName The package name of the app running the media service. + * @param userId The user ID associated with the service. + * @param notificationId The ID of the media notification associated with the service. + */ + public abstract void notifyActiveMediaForegroundService(@NonNull String packageName, + @UserIdInt int userId, int notificationId); + /** * Same as {@link android.app.IActivityManager#startProfile(int userId)}, but it would succeed * even if the profile is disabled - it should only be called by diff --git a/core/java/android/app/ActivityThread.java b/core/java/android/app/ActivityThread.java index cb7b1153988af4973746ad334ed95732ca74b475..f8186d68e21034f27b35c5aeb0a20fce27b689d8 100644 --- a/core/java/android/app/ActivityThread.java +++ b/core/java/android/app/ActivityThread.java @@ -8843,10 +8843,10 @@ public final class ActivityThread extends ClientTransactionHandler // Call per-process mainline module initialization. initializeMainlineModules(); - Process.setArgV0(""); - Looper.prepareMainLooper(); + Process.setArgV0(""); + // Find the value for {@link #PROC_START_SEQ_IDENT} if provided on the command line. // It will be in the format "seq=114" long startSeq = 0; diff --git a/core/java/android/app/AppOpsManager.java b/core/java/android/app/AppOpsManager.java index ce0ec602e612bb9a05561ddc7926f99b496f0a92..34765781d1059bbd36028cf9e6331c61c5bee9e6 100644 --- a/core/java/android/app/AppOpsManager.java +++ b/core/java/android/app/AppOpsManager.java @@ -8934,12 +8934,21 @@ public class AppOpsManager { } /** - * Do a quick check for whether an application might be able to perform an operation. - * This is not a security check; you must use {@link #noteOp(String, int, String, - * String, String)} or {@link #startOp(String, int, String, String, String)} for your actual - * security checks. This function can just be used for a quick check to see if an operation has - * been disabled for the application, as an early reject of some work. This does not modify the - * time stamp or other data about the operation. + * Check whether an application might be able to perform an operation. + *

+ * For platform versions before {@link android.os.Build.VERSION_CODES#BAKLAVA}, this is + * not a security check; you must use {@link #noteOp(String, int, String, String, + * String)} or {@link #startOp(String, int, String, String, String)} for your actual security + * checks. This function can just be used for a quick check to see if an operation has been + * disabled for the application, as an early reject of some work. + *

+ * For platform versions equal to or after {@link android.os.Build.VERSION_CODES#BAKLAVA}, this + * is no longer an unsafe check, and it does the same security check as {@link #noteOp(String, + * int, String, String, String)} and {@link #startOp(String, int, String, String, String)}. + * However, it's preferred to use {@link #checkOp(String, int, String)}, since the word "unsafe" + * in the name of this API is no longer accurate. + *

+ * This API does not modify the time stamp or other data about the operation. * * @param op The operation to check. One of the OPSTR_* constants. * @param uid The user id of the application attempting to perform the operation. @@ -8948,31 +8957,108 @@ public class AppOpsManager { * {@link #MODE_IGNORED} if it is not allowed and should be silently ignored (without * causing the app to crash). * @throws SecurityException If the app has been configured to crash on this op. + * + * @deprecated Use {@link #checkOp(String, int, String)} */ + @Deprecated + @FlaggedApi(android.permission.flags.Flags.FLAG_CHECK_OP_OVERLOAD_API_ENABLED) public int unsafeCheckOp(@NonNull String op, int uid, @NonNull String packageName) { return checkOp(strOpToOp(op), uid, packageName); } /** - * @deprecated Renamed to {@link #unsafeCheckOp(String, int, String)}. + * Check whether an application can perform an operation. + *

+ * For platform versions before {@link android.os.Build.VERSION_CODES#BAKLAVA}, this is + * not a security check; you must use {@link #noteOp(String, int, String, String, + * String)} or {@link #startOp(String, int, String, String, String)} for your actual security + * checks. This function can just be used for a quick check to see if an operation has been + * disabled for the application, as an early reject of some work. + *

+ * For platform versions equal to or after {@link android.os.Build.VERSION_CODES#BAKLAVA}, it + * does the same security check as {@link #noteOp(String, int, String, String, String)} and + * {@link #startOp(String, int, String, String, String)}, and should be preferred to use. + *

+ * This API does not modify the time stamp or other data about the operation. + * + * @param op The operation to check. One of the OPSTR_* constants. + * @param uid The uid of the application attempting to perform the operation. + * @param packageName The name of the application attempting to perform the operation. + * @return Returns {@link #MODE_ALLOWED} if the operation is allowed, or + * {@link #MODE_IGNORED} if it is not allowed and should be silently ignored (without + * causing the app to crash). + * @throws SecurityException If the app has been configured to crash on this op. */ - @Deprecated + @FlaggedApi(android.permission.flags.Flags.FLAG_CHECK_OP_OVERLOAD_API_ENABLED) public int checkOp(@NonNull String op, int uid, @NonNull String packageName) { return checkOp(strOpToOp(op), uid, packageName); } /** - * Like {@link #checkOp} but instead of throwing a {@link SecurityException} it - * returns {@link #MODE_ERRORED}. + * Like {@link #unsafeCheckOp(String, int, String)} but instead of throwing a + * {@link SecurityException} it returns {@link #MODE_ERRORED}. + * + * @deprecated Use {@link #checkOpNoThrow(String, int, String)} */ + @Deprecated + @FlaggedApi(android.permission.flags.Flags.FLAG_CHECK_OP_OVERLOAD_API_ENABLED) public int unsafeCheckOpNoThrow(@NonNull String op, int uid, @NonNull String packageName) { return checkOpNoThrow(strOpToOp(op), uid, packageName); } /** - * @deprecated Renamed to {@link #unsafeCheckOpNoThrow(String, int, String)}. + * Check whether an application can perform an operation. It does the same security check as + * {@link #noteOp(String, int, String, String, String)} and {@link #startOp(String, int, String, + * String, String)}, but does not modify the time stamp or other data about the operation. + * + * @param op The operation to check. One of the OPSTR_* constants. + * @param uid The uid of the application attempting to perform the operation. + * @param packageName The name of the application attempting to perform the operation. + * @param attributionTag The {@link Context#createAttributionContext attribution tag} of the + * calling context or {@code null} for default attribution + * @return Returns {@link #MODE_ALLOWED} if the operation is allowed, or {@link #MODE_IGNORED} + * if it is not allowed and should be silently ignored (without causing the app to crash). + * @throws SecurityException If the app has been configured to crash on this op. */ - @Deprecated + @FlaggedApi(android.permission.flags.Flags.FLAG_CHECK_OP_OVERLOAD_API_ENABLED) + public int checkOp(@NonNull String op, int uid, @NonNull String packageName, + @Nullable String attributionTag) { + int mode = checkOpNoThrow(strOpToOp(op), uid, packageName, attributionTag, + Context.DEVICE_ID_DEFAULT); + if (mode == MODE_ERRORED) { + throw new SecurityException(buildSecurityExceptionMsg(strOpToOp(op), uid, packageName)); + } + return mode; + } + + /** + * Like {@link #checkOp(String, int, String, String)} but instead of throwing a + * {@link SecurityException} it returns {@link #MODE_ERRORED}. + */ + @FlaggedApi(android.permission.flags.Flags.FLAG_CHECK_OP_OVERLOAD_API_ENABLED) + public int checkOpNoThrow(@NonNull String op, int uid, @NonNull String packageName, + @Nullable String attributionTag) { + return checkOpNoThrow(strOpToOp(op), uid, packageName, attributionTag, + Context.DEVICE_ID_DEFAULT); + } + + /** + * Like {@link #checkOp(String, int, String, String)} but returns the raw mode + * associated with the op. Does not throw a security exception, does not translate + * {@link #MODE_FOREGROUND}. + */ + @FlaggedApi(android.permission.flags.Flags.FLAG_CHECK_OP_OVERLOAD_API_ENABLED) + public int checkOpRawNoThrow(@NonNull String op, int uid, @NonNull String packageName, + @Nullable String attributionTag) { + return checkOpRawNoThrow(strOpToOp(op), uid, packageName, attributionTag, + Context.DEVICE_ID_DEFAULT); + } + + /** + * Like {@link #checkOp(String, int, String)} but instead of throwing a + * {@link SecurityException} it returns {@link #MODE_ERRORED}. + */ + @FlaggedApi(android.permission.flags.Flags.FLAG_CHECK_OP_OVERLOAD_API_ENABLED) public int checkOpNoThrow(@NonNull String op, int uid, @NonNull String packageName) { return checkOpNoThrow(strOpToOp(op), uid, packageName); } @@ -8980,16 +9066,23 @@ public class AppOpsManager { /** * Like {@link #checkOp} but returns the raw mode associated with the op. * Does not throw a security exception, does not translate {@link #MODE_FOREGROUND}. + * + * @deprecated Use {@link #checkOpRawNoThrow(String, int, String, String)} instead */ + @Deprecated + @FlaggedApi(android.permission.flags.Flags.FLAG_CHECK_OP_OVERLOAD_API_ENABLED) public int unsafeCheckOpRaw(@NonNull String op, int uid, @NonNull String packageName) { return unsafeCheckOpRawNoThrow(op, uid, packageName); } /** - * Like {@link #unsafeCheckOpNoThrow(String, int, String)} but returns the raw - * mode associated with the op. Does not throw a security exception, does not translate - * {@link #MODE_FOREGROUND}. + * Like {@link #checkOp} but returns the raw mode associated with the op. + * Does not throw a security exception, does not translate {@link #MODE_FOREGROUND}. + * + * @deprecated Use {@link #checkOpRawNoThrow(String, int, String, String)} instead */ + @Deprecated + @FlaggedApi(android.permission.flags.Flags.FLAG_CHECK_OP_OVERLOAD_API_ENABLED) public int unsafeCheckOpRawNoThrow(@NonNull String op, int uid, @NonNull String packageName) { return unsafeCheckOpRawNoThrow(strOpToOp(op), uid, packageName); } @@ -9000,8 +9093,9 @@ public class AppOpsManager { * @hide */ public int unsafeCheckOpRawNoThrow(int op, @NonNull AttributionSource attributionSource) { - return unsafeCheckOpRawNoThrow(op, attributionSource.getUid(), - attributionSource.getPackageName(), attributionSource.getDeviceId()); + return checkOpRawNoThrow(op, attributionSource.getUid(), + attributionSource.getPackageName(), attributionSource.getAttributionTag(), + attributionSource.getDeviceId()); } /** @@ -9022,20 +9116,20 @@ public class AppOpsManager { * @hide */ public int unsafeCheckOpRawNoThrow(int op, int uid, @NonNull String packageName) { - return unsafeCheckOpRawNoThrow(op, uid, packageName, Context.DEVICE_ID_DEFAULT); + return checkOpRawNoThrow(op, uid, packageName, null, Context.DEVICE_ID_DEFAULT); } - private int unsafeCheckOpRawNoThrow(int op, int uid, @NonNull String packageName, - int virtualDeviceId) { + private int checkOpRawNoThrow(int op, int uid, @NonNull String packageName, + @Nullable String attributionTag, int virtualDeviceId) { try { int mode; if (isAppOpModeCachingEnabled(op)) { mode = sAppOpModeCache.query( - new AppOpModeQuery(op, uid, packageName, virtualDeviceId, null, + new AppOpModeQuery(op, uid, packageName, virtualDeviceId, attributionTag, "unsafeCheckOpRawNoThrow")); } else { mode = mService.checkOperationRawForDevice( - op, uid, packageName, null, virtualDeviceId); + op, uid, packageName, attributionTag, virtualDeviceId); } return mode; } catch (RemoteException e) { @@ -9434,10 +9528,12 @@ public class AppOpsManager { } /** - * Do a quick check for whether an application might be able to perform an operation. - * This is not a security check; you must use {@link #noteOp(String, int, String, - * String, String)} or {@link #startOp(int, int, String, boolean, String, String)} for your - * actual security checks, which also ensure that the given uid and package name are consistent. + * Check whether an application can perform an operation. + *

+ * For platform versions before {@link android.os.Build.VERSION_CODES#BAKLAVA}, this is + * not a security check; you must use {@link #noteOp(String, int, String, String, + * String)} or {@link #startOp(int, int, String, boolean, String, String)} for your actual + * security checks, which also ensure that the given uid and package name are consistent. * This function can just be used for a quick check to see if an operation has been disabled for * the application, as an early reject of some work. This does not modify the time stamp or * other data about the operation. @@ -9453,6 +9549,13 @@ public class AppOpsManager { * as {@link #MODE_ALLOWED}. * * + *

+ * For platform versions equal to or after {@link android.os.Build.VERSION_CODES#BAKLAVA}, it + * does the same security check as {@link #noteOp(String, int, String, String, String)} and + * {@link #startOp(String, int, String, String, String)}. + *

+ * This API does not modify the time stamp or other data about the operation. + * * @param op The operation to check. One of the OP_* constants. * @param uid The user id of the application attempting to perform the operation. * @param packageName The name of the application attempting to perform the operation. @@ -9464,29 +9567,11 @@ public class AppOpsManager { */ @UnsupportedAppUsage public int checkOp(int op, int uid, String packageName) { - try { - int mode; - if (isAppOpModeCachingEnabled(op)) { - mode = sAppOpModeCache.query( - new AppOpModeQuery(op, uid, packageName, Context.DEVICE_ID_DEFAULT, null, - "checkOp")); - if (mode == MODE_FOREGROUND) { - // We only cache raw mode. If the mode is FOREGROUND, we need another binder - // call to fetch translated value based on the process state. - mode = mService.checkOperationForDevice(op, uid, packageName, - Context.DEVICE_ID_DEFAULT); - } - } else { - mode = mService.checkOperationForDevice(op, uid, packageName, - Context.DEVICE_ID_DEFAULT); - } - if (mode == MODE_ERRORED) { - throw new SecurityException(buildSecurityExceptionMsg(op, uid, packageName)); - } - return mode; - } catch (RemoteException e) { - throw e.rethrowFromSystemServer(); + int mode = checkOpNoThrow(op, uid, packageName, null, Context.DEVICE_ID_DEFAULT); + if (mode == MODE_ERRORED) { + throw new SecurityException(buildSecurityExceptionMsg(op, uid, packageName)); } + return mode; } /** @@ -9499,7 +9584,7 @@ public class AppOpsManager { */ public int checkOpNoThrow(int op, AttributionSource attributionSource) { return checkOpNoThrow(op, attributionSource.getUid(), attributionSource.getPackageName(), - attributionSource.getDeviceId()); + attributionSource.getAttributionTag(), attributionSource.getDeviceId()); } /** @@ -9512,23 +9597,26 @@ public class AppOpsManager { */ @UnsupportedAppUsage public int checkOpNoThrow(int op, int uid, String packageName) { - return checkOpNoThrow(op, uid, packageName, Context.DEVICE_ID_DEFAULT); + return checkOpNoThrow(op, uid, packageName, null, Context.DEVICE_ID_DEFAULT); } - private int checkOpNoThrow(int op, int uid, String packageName, int virtualDeviceId) { + private int checkOpNoThrow(int op, int uid, String packageName, @Nullable String attributionTag, + int virtualDeviceId) { try { int mode; if (isAppOpModeCachingEnabled(op)) { mode = sAppOpModeCache.query( - new AppOpModeQuery(op, uid, packageName, virtualDeviceId, null, + new AppOpModeQuery(op, uid, packageName, virtualDeviceId, attributionTag, "checkOpNoThrow")); if (mode == MODE_FOREGROUND) { // We only cache raw mode. If the mode is FOREGROUND, we need another binder // call to fetch translated value based on the process state. - mode = mService.checkOperationForDevice(op, uid, packageName, virtualDeviceId); + mode = mService.checkOperationForDevice(op, uid, packageName, attributionTag, + virtualDeviceId); } } else { - mode = mService.checkOperationForDevice(op, uid, packageName, virtualDeviceId); + mode = mService.checkOperationForDevice(op, uid, packageName, attributionTag, + virtualDeviceId); } return mode; } catch (RemoteException e) { diff --git a/core/java/android/app/ApplicationPackageManager.java b/core/java/android/app/ApplicationPackageManager.java index 7e0a9b69b7bd16149232a696708e1251ef5d573a..3cbea87e135e42370dfba09e2bf6a495f080d311 100644 --- a/core/java/android/app/ApplicationPackageManager.java +++ b/core/java/android/app/ApplicationPackageManager.java @@ -130,7 +130,6 @@ import android.util.Slog; import android.util.Xml; import com.android.internal.annotations.GuardedBy; -import com.android.internal.annotations.Immutable; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.os.SomeArgs; import com.android.internal.pm.RoSystemFeatures; @@ -1020,6 +1019,33 @@ public class ApplicationPackageManager extends PackageManager { } } + @Override + public void setPageSizeAppCompatFlagsSettingsOverride(String packageName, boolean enabled) { + try { + mPM.setPageSizeAppCompatFlagsSettingsOverride(packageName, enabled); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + } + + @Override + public boolean isPageSizeCompatEnabled(String packageName) { + try { + return mPM.isPageSizeCompatEnabled(packageName); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + } + + @Override + public String getPageSizeCompatWarningMessage(String packageName) { + try { + return mPM.getPageSizeCompatWarningMessage(packageName); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + } + private static List encodeCertificates(List certs) throws CertificateEncodingException { if (certs == null) { diff --git a/core/java/android/app/ForegroundServiceTypePolicy.java b/core/java/android/app/ForegroundServiceTypePolicy.java index 16444dc5adde877d7b257053b579a9e7d0b42285..6efc4ef55180c2048c1d598499c7ff449962328f 100644 --- a/core/java/android/app/ForegroundServiceTypePolicy.java +++ b/core/java/android/app/ForegroundServiceTypePolicy.java @@ -62,6 +62,7 @@ import android.content.pm.ServiceInfo.ForegroundServiceType; import android.hardware.usb.UsbAccessory; import android.hardware.usb.UsbDevice; import android.hardware.usb.UsbManager; +import android.health.connect.HealthPermissions; import android.os.RemoteException; import android.os.ServiceManager; import android.os.UserHandle; @@ -484,21 +485,35 @@ public abstract class ForegroundServiceTypePolicy { */ public static final @NonNull ForegroundServiceTypePolicyInfo FGS_TYPE_POLICY_HEALTH = new ForegroundServiceTypePolicyInfo( - FOREGROUND_SERVICE_TYPE_HEALTH, - ForegroundServiceTypePolicyInfo.INVALID_CHANGE_ID, - ForegroundServiceTypePolicyInfo.INVALID_CHANGE_ID, - new ForegroundServiceTypePermissions(new ForegroundServiceTypePermission[] { - new RegularPermission(Manifest.permission.FOREGROUND_SERVICE_HEALTH) - }, true), - new ForegroundServiceTypePermissions(new ForegroundServiceTypePermission[] { - new RegularPermission(Manifest.permission.ACTIVITY_RECOGNITION), - new RegularPermission(Manifest.permission.BODY_SENSORS), - new RegularPermission(Manifest.permission.HIGH_SAMPLING_RATE_SENSORS), - }, false), - FGS_TYPE_PERM_ENFORCEMENT_FLAG_HEALTH /* permissionEnforcementFlag */, - true /* permissionEnforcementFlagDefaultValue */, - false /* foregroundOnlyPermission */ - ); + FOREGROUND_SERVICE_TYPE_HEALTH, + ForegroundServiceTypePolicyInfo.INVALID_CHANGE_ID, + ForegroundServiceTypePolicyInfo.INVALID_CHANGE_ID, + new ForegroundServiceTypePermissions( + new ForegroundServiceTypePermission[] { + new RegularPermission(Manifest.permission.FOREGROUND_SERVICE_HEALTH) + }, + true), + new ForegroundServiceTypePermissions(getAllowedHealthPermissions(), false), + FGS_TYPE_PERM_ENFORCEMENT_FLAG_HEALTH /* permissionEnforcementFlag */, + true /* permissionEnforcementFlagDefaultValue */, + false /* foregroundOnlyPermission */); + + /** Returns the permissions needed for the policy of the health foreground service type. */ + private static ForegroundServiceTypePermission[] getAllowedHealthPermissions() { + final ArrayList permissions = new ArrayList<>(); + permissions.add(new RegularPermission(Manifest.permission.ACTIVITY_RECOGNITION)); + permissions.add(new RegularPermission(Manifest.permission.HIGH_SAMPLING_RATE_SENSORS)); + + if (android.permission.flags.Flags.replaceBodySensorPermissionEnabled()) { + permissions.add(new RegularPermission(HealthPermissions.READ_HEART_RATE)); + permissions.add(new RegularPermission(HealthPermissions.READ_SKIN_TEMPERATURE)); + permissions.add(new RegularPermission(HealthPermissions.READ_OXYGEN_SATURATION)); + } else { + permissions.add(new RegularPermission(Manifest.permission.BODY_SENSORS)); + } + + return permissions.toArray(new ForegroundServiceTypePermission[permissions.size()]); + } /** * The policy for the {@link ServiceInfo#FOREGROUND_SERVICE_TYPE_REMOTE_MESSAGING}. diff --git a/core/java/android/app/IActivityManager.aidl b/core/java/android/app/IActivityManager.aidl index a8412fa666095c6ecbb2fa7e531925d628059eb1..0668958b2d5ca1f0f4dd2db2186b097e182886c9 100644 --- a/core/java/android/app/IActivityManager.aidl +++ b/core/java/android/app/IActivityManager.aidl @@ -864,7 +864,8 @@ interface IActivityManager { /** * Suppress or reenable the rate limit on foreground service notification deferral. - * This is for use within CTS and is protected by android.permission.WRITE_DEVICE_CONFIG. + * This is for use within CTS and is protected by android.permission.WRITE_DEVICE_CONFIG + * and WRITE_ALLOWLISTED_DEVICE_CONFIG. * * @param enable false to suppress rate-limit policy; true to reenable it. */ diff --git a/core/java/android/app/IActivityTaskManager.aidl b/core/java/android/app/IActivityTaskManager.aidl index ec7b72ec677e08f98a2be71350c88e96f48de859..c6f62a21641dd3375f6d02236b7f670ef1ef055e 100644 --- a/core/java/android/app/IActivityTaskManager.aidl +++ b/core/java/android/app/IActivityTaskManager.aidl @@ -242,8 +242,8 @@ interface IActivityTaskManager { boolean supportsLocalVoiceInteraction(); - // Sets whether system educational dialogs should be limited - void setLimitSystemEducationDialogs(IBinder appToken, boolean limitSystemEducationDialogs); + // Requests the "Open in browser" education to be shown + void requestOpenInBrowserEducation(IBinder appToken); // Get device configuration ConfigurationInfo getDeviceConfigurationInfo(); diff --git a/core/java/android/app/INotificationManager.aidl b/core/java/android/app/INotificationManager.aidl index 9bb16ae7fa0211fe70f2c8552c81c172c8edb38f..a6c1a57a81319d852e7fda07554b0ad325d99b24 100644 --- a/core/java/android/app/INotificationManager.aidl +++ b/core/java/android/app/INotificationManager.aidl @@ -270,4 +270,6 @@ interface INotificationManager int[] getAllowedAdjustmentKeyTypes(); void setAssistantAdjustmentKeyTypeState(int type, boolean enabled); + String[] getTypeAdjustmentDeniedPackages(); + void setTypeAdjustmentForPackageState(String pkg, boolean enabled); } diff --git a/core/java/android/app/ITaskStackListener.aidl b/core/java/android/app/ITaskStackListener.aidl index f2228f94ff01c2ae4a592fc84c6f4b5d641c3828..4a9a28607796d148a8ca5ea1468f53f356892f74 100644 --- a/core/java/android/app/ITaskStackListener.aidl +++ b/core/java/android/app/ITaskStackListener.aidl @@ -177,6 +177,11 @@ oneway interface ITaskStackListener { */ void onRecentTaskListFrozenChanged(boolean frozen); + /** + * Called when a task is removed from the recent tasks list as a result of adding a new task. + */ + void onRecentTaskRemovedForAddTask(int taskId); + /** * Called when a task gets or loses focus. * diff --git a/core/java/android/app/Notification.java b/core/java/android/app/Notification.java index 1c23ec7995992b6a442982eeca3a72a6c85b1b2b..7fcae45ea4525dcda956c4b7dade42d3219ea99b 100644 --- a/core/java/android/app/Notification.java +++ b/core/java/android/app/Notification.java @@ -441,8 +441,8 @@ public class Notification implements Parcelable /** * A large-format version of {@link #contentView}, giving the Notification an - * opportunity to show more detail. The system UI may choose to show this - * instead of the normal content view at its discretion. + * opportunity to show more detail when expanded. The system UI may choose + * to show this instead of the normal content view at its discretion. * * As of N, this field may be null. The expanded notification view is determined by the * inputs to {@link Notification.Builder}; a custom RemoteViews can optionally be @@ -811,20 +811,32 @@ public class Notification implements Parcelable } private static boolean isStandardLayout(int layoutId) { - // TODO: b/359128724 - Add to static list when inlining the flag. + if (Flags.notificationsRedesignTemplates()) { + return switch (layoutId) { + case R.layout.notification_2025_template_collapsed_base, + R.layout.notification_2025_template_expanded_base, + R.layout.notification_2025_template_heads_up_base, + R.layout.notification_2025_template_header, + R.layout.notification_2025_template_collapsed_messaging, + R.layout.notification_2025_template_collapsed_media, + R.layout.notification_template_material_big_picture, + R.layout.notification_template_material_big_text, + R.layout.notification_template_material_inbox, + R.layout.notification_template_material_big_messaging, + R.layout.notification_template_material_conversation, + R.layout.notification_template_material_big_media, + R.layout.notification_template_material_call, + R.layout.notification_template_material_big_call, + R.layout.notification_template_header -> true; + case R.layout.notification_template_material_progress -> Flags.apiRichOngoing(); + default -> false; + }; + } if (Flags.apiRichOngoing()) { if (layoutId == R.layout.notification_template_material_progress) { return true; } } - // TODO: b/378660052 - Add to static list when inlining the flag. - if (Flags.notificationsRedesignTemplates()) { - switch(layoutId) { - case R.layout.notification_2025_template_collapsed_base: - case R.layout.notification_2025_template_header: - return true; - } - } return STANDARD_LAYOUTS.contains(layoutId); } @@ -1325,7 +1337,7 @@ public class Notification implements Parcelable public static final String EXTRA_SUMMARY_TEXT = "android.summaryText"; /** - * {@link #extras} key: this is the longer text shown in the big form of a + * {@link #extras} key: this is the longer text shown in the expanded form of a * {@link BigTextStyle} notification, as supplied to * {@link BigTextStyle#bigText(CharSequence)}. */ @@ -3148,12 +3160,16 @@ public class Notification implements Parcelable callPerson.visitUris(visitor); } visitIconUri(visitor, extras.getParcelable(EXTRA_VERIFICATION_ICON, Icon.class)); - } - if (Flags.apiRichOngoing()) { - visitIconUri(visitor, extras.getParcelable(EXTRA_PROGRESS_TRACKER_ICON, Icon.class)); - visitIconUri(visitor, extras.getParcelable(EXTRA_PROGRESS_START_ICON, Icon.class)); - visitIconUri(visitor, extras.getParcelable(EXTRA_PROGRESS_END_ICON, Icon.class)); + + if (Flags.apiRichOngoing()) { + visitIconUri(visitor, extras.getParcelable(EXTRA_PROGRESS_TRACKER_ICON, + Icon.class)); + visitIconUri(visitor, extras.getParcelable(EXTRA_PROGRESS_START_ICON, + Icon.class)); + visitIconUri(visitor, extras.getParcelable(EXTRA_PROGRESS_END_ICON, + Icon.class)); + } } if (mBubbleMetadata != null) { @@ -3245,8 +3261,9 @@ public class Notification implements Parcelable */ @FlaggedApi(Flags.FLAG_UI_RICH_ONGOING) public boolean hasPromotableCharacteristics() { - return isColorized() + return isColorizedRequested() && hasTitle() + && !isGroupSummary() && !containsCustomViews() && hasPromotableStyle(); } @@ -4071,6 +4088,12 @@ public class Notification implements Parcelable flags &= ~FLAG_LIFETIME_EXTENDED_BY_DIRECT_REPLY; } } + if (Flags.apiRichOngoing()) { + if ((flags & FLAG_PROMOTED_ONGOING) != 0) { + flagStrings.add("PROMOTED_ONGOING"); + flags &= ~FLAG_PROMOTED_ONGOING; + } + } if (android.service.notification.Flags.notificationSilentFlag()) { if ((flags & FLAG_SILENT) != 0) { @@ -5896,12 +5919,12 @@ public class Notification implements Parcelable private RemoteViews applyStandardTemplate(int resId, StandardTemplateParams p, TemplateBindResult result) { - p.headerless(resId == getBaseLayoutResource() + p.headerless(resId == getCollapsedBaseLayoutResource() || resId == getHeadsUpBaseLayoutResource() || resId == getCompactHeadsUpBaseLayoutResource() || resId == getMessagingCompactHeadsUpLayoutResource() - || resId == getMessagingLayoutResource() - || resId == R.layout.notification_template_material_media); + || resId == getCollapsedMessagingLayoutResource() + || resId == getCollapsedMediaLayoutResource()); RemoteViews contentView = new BuilderRemoteViews(mContext.getApplicationInfo(), resId); resetStandardTemplate(contentView); @@ -6355,7 +6378,7 @@ public class Notification implements Parcelable boolean hideSnoozeButton = mN.isFgsOrUij() || mN.fullScreenIntent != null || isBackgroundColorized(p) - || p.mViewType != StandardTemplateParams.VIEW_TYPE_BIG; + || p.mViewType != StandardTemplateParams.VIEW_TYPE_EXPANDED; big.setBoolean(R.id.snooze_button, "setEnabled", !hideSnoozeButton); if (hideSnoozeButton) { // Only hide; NotificationContentView will show it when it adds the click listener @@ -6560,19 +6583,21 @@ public class Notification implements Parcelable .decorationType(StandardTemplateParams.DECORATION_MINIMAL) .fillTextsFrom(this); TemplateBindResult result = new TemplateBindResult(); - RemoteViews standard = applyStandardTemplate(getBaseLayoutResource(), p, result); + RemoteViews standard = applyStandardTemplate(getCollapsedBaseLayoutResource(), + p, result); buildCustomContentIntoTemplate(mContext, standard, customContent, p, result); return standard; } - private RemoteViews minimallyDecoratedBigContentView(@NonNull RemoteViews customContent) { + private RemoteViews minimallyDecoratedExpandedContentView( + @NonNull RemoteViews customContent) { StandardTemplateParams p = mParams.reset() - .viewType(StandardTemplateParams.VIEW_TYPE_BIG) + .viewType(StandardTemplateParams.VIEW_TYPE_EXPANDED) .decorationType(StandardTemplateParams.DECORATION_MINIMAL) .fillTextsFrom(this); TemplateBindResult result = new TemplateBindResult(); - RemoteViews standard = applyStandardTemplateWithActions(getBigBaseLayoutResource(), + RemoteViews standard = applyStandardTemplateWithActions(getExpandedBaseLayoutResource(), p, result); buildCustomContentIntoTemplate(mContext, standard, customContent, p, result); @@ -6618,7 +6643,7 @@ public class Notification implements Parcelable StandardTemplateParams p = mParams.reset() .viewType(StandardTemplateParams.VIEW_TYPE_NORMAL) .fillTextsFrom(this); - return applyStandardTemplate(getBaseLayoutResource(), p, null /* result */); + return applyStandardTemplate(getCollapsedBaseLayoutResource(), p, null /* result */); } private boolean useExistingRemoteView(RemoteViews customContent) { @@ -6656,24 +6681,29 @@ public class Notification implements Parcelable */ @Deprecated public RemoteViews createBigContentView() { + return createExpandedContentView(); + } + + private RemoteViews createExpandedContentView() { RemoteViews result = null; if (useExistingRemoteView(mN.bigContentView)) { return fullyCustomViewRequiresDecoration(false /* fromStyle */) - ? minimallyDecoratedBigContentView(mN.bigContentView) : mN.bigContentView; + ? minimallyDecoratedExpandedContentView(mN.bigContentView) + : mN.bigContentView; } if (mStyle != null) { - result = mStyle.makeBigContentView(); + result = mStyle.makeExpandedContentView(); if (fullyCustomViewRequiresDecoration(true /* fromStyle */)) { - result = minimallyDecoratedBigContentView(result); + result = minimallyDecoratedExpandedContentView(result); } } if (result == null) { - if (bigContentViewRequired()) { + if (expandedContentViewRequired()) { StandardTemplateParams p = mParams.reset() - .viewType(StandardTemplateParams.VIEW_TYPE_BIG) + .viewType(StandardTemplateParams.VIEW_TYPE_EXPANDED) .allowTextWithProgress(true) .fillTextsFrom(this); - result = applyStandardTemplateWithActions(getBigBaseLayoutResource(), p, + result = applyStandardTemplateWithActions(getExpandedBaseLayoutResource(), p, null /* result */); } } @@ -6687,7 +6717,7 @@ public class Notification implements Parcelable // apps can detect the change, it's most likely that the changes will simply result in // visual regressions. @SuppressWarnings("AndroidFrameworkCompatChange") - private boolean bigContentViewRequired() { + private boolean expandedContentViewRequired() { if (Flags.notificationExpansionOptional()) { // Notifications without a bigContentView, style, or actions do not need to expand boolean exempt = mN.bigContentView == null @@ -7116,7 +7146,9 @@ public class Notification implements Parcelable */ public CharSequence ensureColorSpanContrastOrStripStyling(CharSequence cs, int buttonFillColor) { - if (Flags.cleanUpSpansAndNewLines()) { + // Ongoing promoted notifications are allowed to have styling. + final boolean isPromotedOngoing = mN.isPromotedOngoing(); + if (!isPromotedOngoing && Flags.cleanUpSpansAndNewLines()) { return stripStyling(cs); } @@ -7496,7 +7528,7 @@ public class Notification implements Parcelable } @UnsupportedAppUsage - private int getBaseLayoutResource() { + private int getCollapsedBaseLayoutResource() { if (Flags.notificationsRedesignTemplates()) { return R.layout.notification_2025_template_collapsed_base; } else { @@ -7505,7 +7537,11 @@ public class Notification implements Parcelable } private int getHeadsUpBaseLayoutResource() { - return R.layout.notification_template_material_heads_up_base; + if (Flags.notificationsRedesignTemplates()) { + return R.layout.notification_2025_template_heads_up_base; + } else { + return R.layout.notification_template_material_heads_up_base; + } } private int getCompactHeadsUpBaseLayoutResource() { @@ -7516,8 +7552,12 @@ public class Notification implements Parcelable return R.layout.notification_template_material_messaging_compact_heads_up; } - private int getBigBaseLayoutResource() { - return R.layout.notification_template_material_big_base; + private int getExpandedBaseLayoutResource() { + if (Flags.notificationsRedesignTemplates()) { + return R.layout.notification_2025_template_expanded_base; + } else { + return R.layout.notification_template_material_big_base; + } } private int getBigPictureLayoutResource() { @@ -7532,14 +7572,26 @@ public class Notification implements Parcelable return R.layout.notification_template_material_inbox; } - private int getMessagingLayoutResource() { - return R.layout.notification_template_material_messaging; + private int getCollapsedMessagingLayoutResource() { + if (Flags.notificationsRedesignTemplates()) { + return R.layout.notification_2025_template_collapsed_messaging; + } else { + return R.layout.notification_template_material_messaging; + } } - private int getBigMessagingLayoutResource() { + private int getExpandedMessagingLayoutResource() { return R.layout.notification_template_material_big_messaging; } + private int getCollapsedMediaLayoutResource() { + if (Flags.notificationsRedesignTemplates()) { + return R.layout.notification_2025_template_collapsed_media; + } else { + return R.layout.notification_template_material_media; + } + } + private int getConversationLayoutResource() { return R.layout.notification_template_material_conversation; } @@ -7776,8 +7828,16 @@ public class Notification implements Parcelable * @hide */ public boolean isColorized() { - return extras.getBoolean(EXTRA_COLORIZED) - && (hasColorizedPermission() || isFgsOrUij()); + return isColorizedRequested() + && (hasColorizedPermission() || isFgsOrUij() || isPromotedOngoing()); + } + + /** + * @return true if this notification has requested to be colorized, regardless of whether it + * meets the requirements to be displayed that way. + */ + private boolean isColorizedRequested() { + return extras.getBoolean(EXTRA_COLORIZED); } /** @@ -7790,6 +7850,19 @@ public class Notification implements Parcelable return (flags & Notification.FLAG_CAN_COLORIZE) != 0; } + /** + * Returns whether this notification is a promoted ongoing notification. + * + * This requires the Notification.FLAG_PROMOTED_ONGOING flag to be set + * (which may be true once the api_rich_ongoing feature flag is enabled), + * and requires that the ui_rich_ongoing feature flag is enabled. + * + * @hide + */ + public boolean isPromotedOngoing() { + return Flags.uiRichOngoing() && (flags & Notification.FLAG_PROMOTED_ONGOING) != 0; + } + /** * @return true if this is a media style notification with a media session * @@ -7984,7 +8057,7 @@ public class Notification implements Parcelable protected Builder mBuilder; /** - * Overrides ContentTitle in the big form of the template. + * Overrides ContentTitle in the expanded form of the template. * This defaults to the value passed to setContentTitle(). */ protected void internalSetBigContentTitle(CharSequence title) { @@ -7992,7 +8065,7 @@ public class Notification implements Parcelable } /** - * Set the first line of text after the detail section in the big form of the template. + * Set the first line of text after the detail section in the expanded form of the template. */ protected void internalSetSummaryText(CharSequence cs) { mSummaryText = cs; @@ -8055,10 +8128,10 @@ public class Notification implements Parcelable } /** - * Construct a Style-specific RemoteViews for the final big notification layout. + * Construct a Style-specific RemoteViews for the final expanded notification layout. * @hide */ - public RemoteViews makeBigContentView() { + public RemoteViews makeExpandedContentView() { return null; } @@ -8222,7 +8295,7 @@ public class Notification implements Parcelable } /** - * Overrides ContentTitle in the big form of the template. + * Overrides ContentTitle in the expanded form of the template. * This defaults to the value passed to setContentTitle(). */ @NonNull @@ -8232,7 +8305,7 @@ public class Notification implements Parcelable } /** - * Set the first line of text after the detail section in the big form of the template. + * Set the first line of text after the detail section in the expanded form of the template. */ @NonNull public BigPictureStyle setSummaryText(@Nullable CharSequence cs) { @@ -8291,7 +8364,7 @@ public class Notification implements Parcelable } /** - * Override the large icon when the big notification is shown. + * Override the large icon when the expanded notification is shown. */ @NonNull public BigPictureStyle bigLargeIcon(@Nullable Bitmap b) { @@ -8299,7 +8372,7 @@ public class Notification implements Parcelable } /** - * Override the large icon when the big notification is shown. + * Override the large icon when the expanded notification is shown. */ @NonNull public BigPictureStyle bigLargeIcon(@Nullable Icon icon) { @@ -8363,7 +8436,7 @@ public class Notification implements Parcelable .viewType(StandardTemplateParams.VIEW_TYPE_NORMAL) .fillTextsFrom(mBuilder) .promotedPicture(mPictureIcon); - return getStandardView(mBuilder.getBaseLayoutResource(), p, null /* result */); + return getStandardView(mBuilder.getCollapsedBaseLayoutResource(), p, null /* result */); } /** @@ -8385,7 +8458,7 @@ public class Notification implements Parcelable /** * @hide */ - public RemoteViews makeBigContentView() { + public RemoteViews makeExpandedContentView() { // Replace mN.mLargeIcon with mBigLargeIcon if mBigLargeIconSet // This covers the following cases: // 1. mBigLargeIconSet -> mBigLargeIcon (null or non-null) applies, overrides @@ -8404,7 +8477,7 @@ public class Notification implements Parcelable } StandardTemplateParams p = mBuilder.mParams.reset() - .viewType(StandardTemplateParams.VIEW_TYPE_BIG).fillTextsFrom(mBuilder); + .viewType(StandardTemplateParams.VIEW_TYPE_EXPANDED).fillTextsFrom(mBuilder); RemoteViews contentView = getStandardView(mBuilder.getBigPictureLayoutResource(), p, null /* result */); if (mSummaryTextSet) { @@ -8551,7 +8624,7 @@ public class Notification implements Parcelable } /** - * Overrides ContentTitle in the big form of the template. + * Overrides ContentTitle in the expanded form of the template. * This defaults to the value passed to setContentTitle(). */ public BigTextStyle setBigContentTitle(CharSequence title) { @@ -8560,7 +8633,7 @@ public class Notification implements Parcelable } /** - * Set the first line of text after the detail section in the big form of the template. + * Set the first line of text after the detail section in the expanded form of the template. */ public BigTextStyle setSummaryText(CharSequence cs) { internalSetSummaryText(safeCharSequence(cs)); @@ -8568,7 +8641,7 @@ public class Notification implements Parcelable } /** - * Provide the longer text to be displayed in the big form of the + * Provide the longer text to be displayed in the expanded form of the * template in place of the content text. */ public BigTextStyle bigText(CharSequence cs) { @@ -8612,7 +8685,7 @@ public class Notification implements Parcelable if (increasedHeight) { ArrayList originalActions = mBuilder.mActions; mBuilder.mActions = new ArrayList<>(); - RemoteViews remoteViews = makeBigContentView(); + RemoteViews remoteViews = makeExpandedContentView(); mBuilder.mActions = originalActions; return remoteViews; } @@ -8626,7 +8699,7 @@ public class Notification implements Parcelable public RemoteViews makeHeadsUpContentView(boolean increasedHeight) { if (increasedHeight && mBuilder.mActions.size() > 0) { // TODO(b/163626038): pass VIEW_TYPE_HEADS_UP? - return makeBigContentView(); + return makeExpandedContentView(); } return super.makeHeadsUpContentView(increasedHeight); } @@ -8634,16 +8707,18 @@ public class Notification implements Parcelable /** * @hide */ - public RemoteViews makeBigContentView() { + public RemoteViews makeExpandedContentView() { StandardTemplateParams p = mBuilder.mParams.reset() - .viewType(StandardTemplateParams.VIEW_TYPE_BIG) + .viewType(StandardTemplateParams.VIEW_TYPE_EXPANDED) .allowTextWithProgress(true) .textViewId(R.id.big_text) .fillTextsFrom(mBuilder); // Replace the text with the big text, but only if the big text is not empty. CharSequence bigTextText = mBuilder.processLegacyText(mBigText); - if (Flags.cleanUpSpansAndNewLines()) { + // Ongoing promoted notifications are allowed to have styling. + final boolean isPromotedOngoing = mBuilder.mN.isPromotedOngoing(); + if (!isPromotedOngoing && Flags.cleanUpSpansAndNewLines()) { bigTextText = normalizeBigText(stripStyling(bigTextText)); } if (!TextUtils.isEmpty(bigTextText)) { @@ -9306,20 +9381,20 @@ public class Notification implements Parcelable * @hide */ @Override - public RemoteViews makeBigContentView() { - return makeMessagingView(StandardTemplateParams.VIEW_TYPE_BIG); + public RemoteViews makeExpandedContentView() { + return makeMessagingView(StandardTemplateParams.VIEW_TYPE_EXPANDED); } /** * Create a messaging layout. * - * @param viewType one of StandardTemplateParams.VIEW_TYPE_NORMAL, VIEW_TYPE_BIG, + * @param viewType one of StandardTemplateParams.VIEW_TYPE_NORMAL, VIEW_TYPE_EXPANDEDIG, * VIEW_TYPE_HEADS_UP * @return the created remoteView. */ @NonNull private RemoteViews makeMessagingView(int viewType) { - boolean isCollapsed = viewType != StandardTemplateParams.VIEW_TYPE_BIG; + boolean isCollapsed = viewType != StandardTemplateParams.VIEW_TYPE_EXPANDED; boolean hideRightIcons = viewType != StandardTemplateParams.VIEW_TYPE_NORMAL; boolean isConversationLayout = mConversationType != CONVERSATION_TYPE_LEGACY; boolean isImportantConversation = mConversationType == CONVERSATION_TYPE_IMPORTANT; @@ -9363,8 +9438,8 @@ public class Notification implements Parcelable isConversationLayout ? mBuilder.getConversationLayoutResource() : isCollapsed - ? mBuilder.getMessagingLayoutResource() - : mBuilder.getBigMessagingLayoutResource(), + ? mBuilder.getCollapsedMessagingLayoutResource() + : mBuilder.getExpandedMessagingLayoutResource(), p, bindResult); if (isConversationLayout) { @@ -9987,7 +10062,7 @@ public class Notification implements Parcelable } /** - * Overrides ContentTitle in the big form of the template. + * Overrides ContentTitle in the expanded form of the template. * This defaults to the value passed to setContentTitle(). */ public InboxStyle setBigContentTitle(CharSequence title) { @@ -9996,7 +10071,7 @@ public class Notification implements Parcelable } /** - * Set the first line of text after the detail section in the big form of the template. + * Set the first line of text after the detail section in the expanded form of the template. */ public InboxStyle setSummaryText(CharSequence cs) { internalSetSummaryText(safeCharSequence(cs)); @@ -10044,9 +10119,9 @@ public class Notification implements Parcelable /** * @hide */ - public RemoteViews makeBigContentView() { + public RemoteViews makeExpandedContentView() { StandardTemplateParams p = mBuilder.mParams.reset() - .viewType(StandardTemplateParams.VIEW_TYPE_BIG) + .viewType(StandardTemplateParams.VIEW_TYPE_EXPANDED) .fillTextsFrom(mBuilder).text(null); TemplateBindResult result = new TemplateBindResult(); RemoteViews contentView = getStandardView(mBuilder.getInboxLayoutResource(), p, result); @@ -10301,8 +10376,8 @@ public class Notification implements Parcelable * @hide */ @Override - public RemoteViews makeBigContentView() { - return makeMediaBigContentView(null /* customContent */); + public RemoteViews makeExpandedContentView() { + return makeMediaExpandedContentView(null /* customContent */); } /** @@ -10417,7 +10492,7 @@ public class Notification implements Parcelable .fillTextsFrom(mBuilder); TemplateBindResult result = new TemplateBindResult(); RemoteViews template = mBuilder.applyStandardTemplate( - R.layout.notification_template_material_media, p, + mBuilder.getCollapsedMediaLayoutResource(), p, null /* result */); for (int i = 0; i < MAX_MEDIA_BUTTONS_IN_COMPACT; i++) { @@ -10438,10 +10513,10 @@ public class Notification implements Parcelable } /** @hide */ - protected RemoteViews makeMediaBigContentView(@Nullable RemoteViews customContent) { + protected RemoteViews makeMediaExpandedContentView(@Nullable RemoteViews customContent) { final int actionCount = Math.min(mBuilder.mActions.size(), MAX_MEDIA_BUTTONS); StandardTemplateParams p = mBuilder.mParams.reset() - .viewType(StandardTemplateParams.VIEW_TYPE_BIG) + .viewType(StandardTemplateParams.VIEW_TYPE_EXPANDED) .hideProgress(true) .fillTextsFrom(mBuilder); TemplateBindResult result = new TemplateBindResult(); @@ -10747,8 +10822,8 @@ public class Notification implements Parcelable /** * @hide */ - public RemoteViews makeBigContentView() { - return makeCallLayout(StandardTemplateParams.VIEW_TYPE_BIG); + public RemoteViews makeExpandedContentView() { + return makeCallLayout(StandardTemplateParams.VIEW_TYPE_EXPANDED); } @NonNull @@ -11494,7 +11569,7 @@ public class Notification implements Parcelable .hideProgress(true) .fillTextsFrom(mBuilder); - return getStandardView(mBuilder.getBaseLayoutResource(), p, null /* result */); + return getStandardView(mBuilder.getCollapsedBaseLayoutResource(), p, null /* result */); } /** * @hide @@ -11512,9 +11587,9 @@ public class Notification implements Parcelable * @hide */ @Override - public RemoteViews makeBigContentView() { + public RemoteViews makeExpandedContentView() { StandardTemplateParams p = mBuilder.mParams.reset() - .viewType(StandardTemplateParams.VIEW_TYPE_BIG) + .viewType(StandardTemplateParams.VIEW_TYPE_EXPANDED) .allowTextWithProgress(true) .hideProgress(true) .fillTextsFrom(mBuilder); @@ -11547,11 +11622,9 @@ public class Notification implements Parcelable contentView.setBundle(R.id.progress, "setProgressModel", model.toBundle()); - if (mTrackerIcon != null) { - contentView.setIcon(R.id.progress, - "setProgressTrackerIcon", - mTrackerIcon); - } + contentView.setIcon(R.id.progress, + "setProgressTrackerIcon", + mTrackerIcon); return contentView; } @@ -11657,8 +11730,10 @@ public class Notification implements Parcelable return points; } - @NonNull - private NotificationProgressModel createProgressModel(int defaultProgressColor, + /** + * @hide + */ + public @NonNull NotificationProgressModel createProgressModel(int defaultProgressColor, int backgroundColor) { final NotificationProgressModel model; if (mIndeterminate) { @@ -11958,8 +12033,8 @@ public class Notification implements Parcelable * @hide */ @Override - public RemoteViews makeBigContentView() { - return makeDecoratedBigContentView(); + public RemoteViews makeExpandedContentView() { + return makeDecoratedExpandedContentView(); } /** @@ -12002,13 +12077,13 @@ public class Notification implements Parcelable .decorationType(StandardTemplateParams.DECORATION_PARTIAL) .fillTextsFrom(mBuilder); RemoteViews remoteViews = mBuilder.applyStandardTemplate( - mBuilder.getBaseLayoutResource(), p, result); + mBuilder.getCollapsedBaseLayoutResource(), p, result); buildCustomContentIntoTemplate(mBuilder.mContext, remoteViews, customContent, p, result); return remoteViews; } - private RemoteViews makeDecoratedBigContentView() { + private RemoteViews makeDecoratedExpandedContentView() { RemoteViews bigContentView = mBuilder.mN.bigContentView == null ? mBuilder.mN.contentView : mBuilder.mN.bigContentView; @@ -12017,11 +12092,11 @@ public class Notification implements Parcelable } TemplateBindResult result = new TemplateBindResult(); StandardTemplateParams p = mBuilder.mParams.reset() - .viewType(StandardTemplateParams.VIEW_TYPE_BIG) + .viewType(StandardTemplateParams.VIEW_TYPE_EXPANDED) .decorationType(StandardTemplateParams.DECORATION_PARTIAL) .fillTextsFrom(mBuilder); RemoteViews remoteViews = mBuilder.applyStandardTemplateWithActions( - mBuilder.getBigBaseLayoutResource(), p, result); + mBuilder.getExpandedBaseLayoutResource(), p, result); buildCustomContentIntoTemplate(mBuilder.mContext, remoteViews, bigContentView, p, result); return remoteViews; @@ -12094,11 +12169,11 @@ public class Notification implements Parcelable * @hide */ @Override - public RemoteViews makeBigContentView() { + public RemoteViews makeExpandedContentView() { RemoteViews customContent = mBuilder.mN.bigContentView != null ? mBuilder.mN.bigContentView : mBuilder.mN.contentView; - return makeMediaBigContentView(customContent); + return makeMediaExpandedContentView(customContent); } /** @@ -12109,7 +12184,7 @@ public class Notification implements Parcelable RemoteViews customContent = mBuilder.mN.headsUpContentView != null ? mBuilder.mN.headsUpContentView : mBuilder.mN.contentView; - return makeMediaBigContentView(customContent); + return makeMediaExpandedContentView(customContent); } /** @@ -14435,7 +14510,7 @@ public class Notification implements Parcelable public static int VIEW_TYPE_UNSPECIFIED = 0; public static int VIEW_TYPE_NORMAL = 1; - public static int VIEW_TYPE_BIG = 2; + public static int VIEW_TYPE_EXPANDED = 2; public static int VIEW_TYPE_HEADS_UP = 3; public static int VIEW_TYPE_MINIMIZED = 4; // header only for minimized state public static int VIEW_TYPE_PUBLIC = 5; // header only for automatic public version diff --git a/core/java/android/app/NotificationManager.java b/core/java/android/app/NotificationManager.java index c49b02210dd45e575de4f02c87d9c086e36eaebe..87c86191203671df6699433524dd187930f70009 100644 --- a/core/java/android/app/NotificationManager.java +++ b/core/java/android/app/NotificationManager.java @@ -16,6 +16,8 @@ package android.app; +import static android.Manifest.permission.POST_NOTIFICATIONS; +import static android.content.pm.PackageManager.PERMISSION_GRANTED; import static android.service.notification.Flags.notificationClassification; import android.annotation.CallbackExecutor; @@ -1597,11 +1599,15 @@ public class NotificationManager { * Returns whether notifications from the calling package are enabled. */ public boolean areNotificationsEnabled() { - INotificationManager service = getService(); - try { - return service.areNotificationsEnabled(mContext.getPackageName()); - } catch (RemoteException e) { - throw e.rethrowFromSystemServer(); + if (Flags.nmBinderPerfPermissionCheck()) { + return mContext.checkSelfPermission(POST_NOTIFICATIONS) == PERMISSION_GRANTED; + } else { + INotificationManager service = getService(); + try { + return service.areNotificationsEnabled(mContext.getPackageName()); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } } } @@ -1859,6 +1865,19 @@ public class NotificationManager { } } + /** + * @hide + */ + @FlaggedApi(android.app.Flags.FLAG_NOTIFICATION_CLASSIFICATION_UI) + public void setTypeAdjustmentForPackageState(@NonNull String pkg, boolean enabled) { + INotificationManager service = getService(); + try { + service.setTypeAdjustmentForPackageState(pkg, enabled); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + } + /** * @hide */ diff --git a/core/java/android/app/PropertyInvalidatedCache.java b/core/java/android/app/PropertyInvalidatedCache.java index e218418336c54a559801f902d49edd0a1e4dca4a..3973c58c070841d1952633606edb29e0551243fb 100644 --- a/core/java/android/app/PropertyInvalidatedCache.java +++ b/core/java/android/app/PropertyInvalidatedCache.java @@ -61,6 +61,8 @@ import java.util.Random; import java.util.Set; import java.util.WeakHashMap; import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.Semaphore; +import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicLong; /** @@ -680,12 +682,17 @@ public class PropertyInvalidatedCache { @GuardedBy("mLock") private boolean mTestMode = false; - /** - * The local value of the handler, used during testing but also used directly by the - * NonceLocal handler. - */ + // This is the local value of the nonce, as last set by the NonceHandler. It is always + // updated by the setNonce() operation. The getNonce() operation returns this value in + // NonceLocal handlers and handlers in test mode. + @GuardedBy("mLock") + protected long mShadowNonce = NONCE_UNSET; + + // A list of watchers to be notified of changes. This is null until at least one watcher + // registers. Checking for null is meant to be the fastest way the handler can determine + // that there are no watchers to be notified. @GuardedBy("mLock") - protected long mTestNonce = NONCE_UNSET; + private ArrayList mWatchers; /** * The methods to get and set a nonce from whatever storage is being used. mLock may be @@ -701,27 +708,60 @@ public class PropertyInvalidatedCache { /** * Get a nonce from storage. If the handler is in test mode, the nonce is returned from - * the local mTestNonce. + * the local mShadowNonce. */ long getNonce() { synchronized (mLock) { - if (mTestMode) return mTestNonce; + if (mTestMode) return mShadowNonce; } return getNonceInternal(); } /** - * Write a nonce to storage. If the handler is in test mode, the nonce is written to the - * local mTestNonce and storage is not affected. + * Write a nonce to storage. The nonce is always written to the local mShadowNonce. If + * the handler is not in test mode the nonce is also written to storage. */ void setNonce(long val) { synchronized (mLock) { - if (mTestMode) { - mTestNonce = val; - return; + mShadowNonce = val; + if (!mTestMode) { + setNonceInternal(val); + } + wakeAllWatchersLocked(); + } + } + + @GuardedBy("mLock") + private void wakeAllWatchersLocked() { + if (mWatchers != null) { + for (int i = 0; i < mWatchers.size(); i++) { + mWatchers.get(i).release(); + } + } + } + + /** + * Register a watcher to be notified when a nonce changes. There is no check for + * duplicates. In general, this method is called only from {@link NonceWatcher}. + */ + void registerWatcher(Semaphore s) { + synchronized (mLock) { + if (mWatchers == null) { + mWatchers = new ArrayList<>(); + } + mWatchers.add(s); + } + } + + /** + * Unregister a watcher. Nothing happens if the watcher is not registered. + */ + void unregisterWatcher(Semaphore s) { + synchronized (mLock) { + if (mWatchers != null) { + mWatchers.remove(s); } } - setNonceInternal(val); } /** @@ -854,7 +894,7 @@ public class PropertyInvalidatedCache { void setTestMode(boolean mode) { synchronized (mLock) { mTestMode = mode; - mTestNonce = NONCE_UNSET; + mShadowNonce = NONCE_UNSET; } } @@ -1028,7 +1068,7 @@ public class PropertyInvalidatedCache { /** * SystemProperties and shared storage are protected and cannot be written by random * processes. So, for testing purposes, the NonceLocal handler stores the nonce locally. The - * NonceLocal uses the mTestNonce in the superclass, regardless of test mode. + * NonceLocal uses the mShadowNonce in the superclass, regardless of test mode. */ private static class NonceLocal extends NonceHandler { // The saved nonce. @@ -1040,15 +1080,129 @@ public class PropertyInvalidatedCache { @Override long getNonceInternal() { - return mTestNonce; + return mShadowNonce; } @Override void setNonceInternal(long value) { - mTestNonce = value; + mShadowNonce = value; + } + } + + /** + * A NonceWatcher lets an external client test if a nonce value has changed from the last time + * the watcher was checked. + * @hide + */ + public static class NonceWatcher implements AutoCloseable { + // The handler for the key. + private final NonceHandler mHandler; + + // The last-seen value. This is initialized to "unset". + private long mLastSeen = NONCE_UNSET; + + // The semaphore that the watcher waits on. A permit is released every time the nonce + // changes. Permits are acquired in the wait method. + private final Semaphore mSem = new Semaphore(0); + + /** + * Create a watcher for a handler. The last-seen value is not set here and will be + * "unset". Therefore, a call to isChanged() will return true if the nonce has ever been + * set, no matter when the watcher is first created. Clients may want to flush that + * change by calling isChanged() immediately after constructing the object. + */ + private NonceWatcher(@NonNull NonceHandler handler) { + mHandler = handler; + mHandler.registerWatcher(mSem); + } + + /** + * Unregister to be notified when a nonce changes. NonceHandler allows a call to + * unregisterWatcher with a semaphore that is not registered, so there is no check inside + * this method to guard against multiple closures. + */ + @Override + public void close() { + mHandler.unregisterWatcher(mSem); + } + + /** + * Return the last seen value of the nonce. This does not update that value. Only + * {@link #isChanged()} updates the value. + */ + public long lastSeen() { + return mLastSeen; + } + + /** + * Return true if the nonce has changed from the last time isChanged() was called. The + * method is not thread safe. + * @hide + */ + public boolean isChanged() { + long current = mHandler.getNonce(); + if (current != mLastSeen) { + mLastSeen = current; + return true; + } + return false; + } + + /** + * Wait for the nonce value to change. It is not guaranteed that the nonce has changed when + * this returns: clients must confirm with {@link #isChanged}. The wait operation is only + * effective in a process that writes the nonces. The function returns the number of times + * the nonce had changed since the last call to the method. + * @hide + */ + public int waitForChange() throws InterruptedException { + mSem.acquire(1); + return 1 + mSem.drainPermits(); + } + + /** + * Wait for the nonce value to change. It is not guaranteed that the nonce has changed when + * this returns: clients must confirm with {@link #isChanged}. The wait operation is only + * effective in a process that writes the nonces. The function returns the number of times + * the nonce changed since the last call to the method. A return value of zero means the + * timeout expired. Beware that a timeout of 0 means the function will not wait at all. + * @hide + */ + public int waitForChange(long timeout, TimeUnit timeUnit) throws InterruptedException { + if (mSem.tryAcquire(1, timeout, timeUnit)) { + return 1 + mSem.drainPermits(); + } else { + return 0; + } + } + + /** + * Wake the watcher by releasing the semaphore. This can be used to wake clients that are + * blocked in {@link #waitForChange} without affecting the underlying nonce. + * @hide + */ + public void wakeUp() { + mSem.release(); } } + /** + * Return a NonceWatcher for the cache. + * @hide + */ + public NonceWatcher getNonceWatcher() { + return new NonceWatcher(mNonce); + } + + /** + * Return a NonceWatcher for the given property. If a handler does not exist for the + * property, one is created. This throws if the property name is not a valid cache key. + * @hide + */ + public static NonceWatcher getNonceWatcher(@NonNull String propertyName) { + return new NonceWatcher(getNonceHandler(propertyName)); + } + /** * Complete key prefixes. */ @@ -1662,6 +1816,26 @@ public class PropertyInvalidatedCache { mNonce.invalidate(); } + /** + * Non-static version of corkInvalidations() for situations in which the cache instance is + * available. This is slightly faster than than the static versions because it does not have + * to look up the NonceHandler for a given property name. + * @hide + */ + public void corkInvalidations() { + mNonce.cork(); + } + + /** + * Non-static version of uncorkInvalidations() for situations in which the cache instance is + * available. This is slightly faster than than the static versions because it does not have + * to look up the NonceHandler for a given property name. + * @hide + */ + public void uncorkInvalidations() { + mNonce.uncork(); + } + /** * Invalidate caches in all processes that are keyed for the module and api. * @hide diff --git a/core/java/android/app/ResourcesManager.java b/core/java/android/app/ResourcesManager.java index 087e246e8841f636f39c09c38b887dc36f2ff126..3cffca796680f98c418928306e7f62b2d486ecff 100644 --- a/core/java/android/app/ResourcesManager.java +++ b/core/java/android/app/ResourcesManager.java @@ -206,11 +206,15 @@ public class ResourcesManager { assets.addPresetApkKeys(extractApkKeys(collector.collectedKey())); return new Pair<>(assets, size); } - final var newAssetsBuilder = new AssetManager.Builder(); + final var newAssetsBuilder = new AssetManager.Builder().setNoInit(); for (final var asset : assets.getApkAssets()) { - if (!asset.isForLoader()) { - newAssetsBuilder.addApkAssets(asset); + // Skip everything that's either default, or will get added by the collector (builder + // doesn't check for duplicates at all). + if (asset.isSystem() || asset.isForLoader() || asset.isOverlay() + || asset.isSharedLib()) { + continue; } + newAssetsBuilder.addApkAssets(asset); } for (final var key : extractApkKeys(collector.collectedKey())) { try { diff --git a/core/java/android/app/SystemServiceRegistry.java b/core/java/android/app/SystemServiceRegistry.java index 53a7dad76788063d05a1eaf9ff0db4cfa7d4a2a2..2bd2d34d54a24d923277f6519f9c31c647aefa34 100644 --- a/core/java/android/app/SystemServiceRegistry.java +++ b/core/java/android/app/SystemServiceRegistry.java @@ -241,8 +241,10 @@ import android.security.advancedprotection.AdvancedProtectionManager; import android.security.advancedprotection.IAdvancedProtectionService; import android.security.attestationverification.AttestationVerificationManager; import android.security.attestationverification.IAttestationVerificationManagerService; -import android.security.forensic.ForensicManager; -import android.security.forensic.IForensicService; +import android.security.authenticationpolicy.AuthenticationPolicyManager; +import android.security.authenticationpolicy.IAuthenticationPolicyService; +import android.security.intrusiondetection.IIntrusionDetectionService; +import android.security.intrusiondetection.IntrusionDetectionManager; import android.security.keystore.KeyStoreManager; import android.service.oemlock.IOemLockService; import android.service.oemlock.OemLockManager; @@ -1025,6 +1027,25 @@ public final class SystemServiceRegistry { } }); + registerService(Context.AUTHENTICATION_POLICY_SERVICE, + AuthenticationPolicyManager.class, + new CachedServiceFetcher() { + @Override + public AuthenticationPolicyManager createService(ContextImpl ctx) + throws ServiceNotFoundException { + if (!android.security.Flags.secureLockdown()) { + throw new ServiceNotFoundException( + Context.AUTHENTICATION_POLICY_SERVICE); + } + + final IBinder binder = ServiceManager.getServiceOrThrow( + Context.AUTHENTICATION_POLICY_SERVICE); + final IAuthenticationPolicyService service = + IAuthenticationPolicyService.Stub.asInterface(binder); + return new AuthenticationPolicyManager(ctx.getOuterContext(), service); + } + }); + registerService(Context.TV_INTERACTIVE_APP_SERVICE, TvInteractiveAppManager.class, new CachedServiceFetcher() { @Override @@ -1797,15 +1818,20 @@ public final class SystemServiceRegistry { } }); - registerService(Context.FORENSIC_SERVICE, ForensicManager.class, - new CachedServiceFetcher() { + registerService(Context.INTRUSION_DETECTION_SERVICE, IntrusionDetectionManager.class, + new CachedServiceFetcher() { @Override - public ForensicManager createService(ContextImpl ctx) + public IntrusionDetectionManager createService(ContextImpl ctx) throws ServiceNotFoundException { + if (!android.security.Flags.aflApi()) { + throw new ServiceNotFoundException( + "Intrusion Detection is not supported"); + } IBinder b = ServiceManager.getServiceOrThrow( - Context.FORENSIC_SERVICE); - IForensicService service = IForensicService.Stub.asInterface(b); - return new ForensicManager(service); + Context.INTRUSION_DETECTION_SERVICE); + IIntrusionDetectionService service = + IIntrusionDetectionService.Stub.asInterface(b); + return new IntrusionDetectionManager(service); } }); diff --git a/core/java/android/app/TaskInfo.java b/core/java/android/app/TaskInfo.java index aac963ade7269a6b6ca94f27b8d843e2ae441f8e..01cc9d82d56d591be11a141ea6d6d10edda7ba45 100644 --- a/core/java/android/app/TaskInfo.java +++ b/core/java/android/app/TaskInfo.java @@ -340,10 +340,10 @@ public class TaskInfo { public int requestedVisibleTypes; /** - * Whether the top activity has requested to limit educational dialogs shown by the system. + * The timestamp of the top activity's last request to show the "Open in Browser" education. * @hide */ - public boolean isTopActivityLimitSystemEducationDialogs; + public long topActivityRequestOpenInBrowserEducationTimestamp; /** * Encapsulate specific App Compat information. @@ -493,8 +493,8 @@ public class TaskInfo { && Objects.equals(capturedLink, that.capturedLink) && capturedLinkTimestamp == that.capturedLinkTimestamp && requestedVisibleTypes == that.requestedVisibleTypes - && isTopActivityLimitSystemEducationDialogs - == that.isTopActivityLimitSystemEducationDialogs + && topActivityRequestOpenInBrowserEducationTimestamp + == that.topActivityRequestOpenInBrowserEducationTimestamp && appCompatTaskInfo.equalsForTaskOrganizer(that.appCompatTaskInfo) && Objects.equals(topActivityMainWindowFrame, that.topActivityMainWindowFrame); } @@ -571,7 +571,7 @@ public class TaskInfo { capturedLink = source.readTypedObject(Uri.CREATOR); capturedLinkTimestamp = source.readLong(); requestedVisibleTypes = source.readInt(); - isTopActivityLimitSystemEducationDialogs = source.readBoolean(); + topActivityRequestOpenInBrowserEducationTimestamp = source.readLong(); appCompatTaskInfo = source.readTypedObject(AppCompatTaskInfo.CREATOR); topActivityMainWindowFrame = source.readTypedObject(Rect.CREATOR); } @@ -627,7 +627,7 @@ public class TaskInfo { dest.writeTypedObject(capturedLink, flags); dest.writeLong(capturedLinkTimestamp); dest.writeInt(requestedVisibleTypes); - dest.writeBoolean(isTopActivityLimitSystemEducationDialogs); + dest.writeLong(topActivityRequestOpenInBrowserEducationTimestamp); dest.writeTypedObject(appCompatTaskInfo, flags); dest.writeTypedObject(topActivityMainWindowFrame, flags); } @@ -672,8 +672,8 @@ public class TaskInfo { + " capturedLink=" + capturedLink + " capturedLinkTimestamp=" + capturedLinkTimestamp + " requestedVisibleTypes=" + requestedVisibleTypes - + " isTopActivityLimitSystemEducationDialogs=" - + isTopActivityLimitSystemEducationDialogs + + " topActivityRequestOpenInBrowserEducationTimestamp=" + + topActivityRequestOpenInBrowserEducationTimestamp + " appCompatTaskInfo=" + appCompatTaskInfo + " topActivityMainWindowFrame=" + topActivityMainWindowFrame + "}"; diff --git a/core/java/android/app/TaskStackListener.java b/core/java/android/app/TaskStackListener.java index 36f61fd3ef596bd5ae6387a675df772c2a365f72..b9b582a7d66001377466487f7d615f446bde4635 100644 --- a/core/java/android/app/TaskStackListener.java +++ b/core/java/android/app/TaskStackListener.java @@ -197,6 +197,10 @@ public abstract class TaskStackListener extends ITaskStackListener.Stub { public void onRecentTaskListFrozenChanged(boolean frozen) { } + @Override + public void onRecentTaskRemovedForAddTask(int taskId) { + } + @Override public void onTaskFocusChanged(int taskId, boolean focused) { } diff --git a/core/java/android/app/admin/DevicePolicyManager.java b/core/java/android/app/admin/DevicePolicyManager.java index e766ae2fce0db1fa66b963d23b7e45bcb761bbbe..74d729857cc8da9daefcdb73a74fe77a12c73c25 100644 --- a/core/java/android/app/admin/DevicePolicyManager.java +++ b/core/java/android/app/admin/DevicePolicyManager.java @@ -4177,6 +4177,35 @@ public class DevicePolicyManager { } } + + /** + * Similar to the public variant of {@link #setMtePolicy} but for use by the system. + * + *

Called by a system service only, meaning that the caller's UID must be equal to + * {@link Process#SYSTEM_UID}. + * + * @throws SecurityException if caller is not permitted to set Mte policy + * @throws UnsupportedOperationException if the device does not support MTE + * @param systemEntity The service entity that adds the restriction. A user restriction set by + * a service entity can only be cleared by the same entity. This can be + * just the calling package name, or any string of the caller's choice + * can be used. + * @param policy the MTE policy to be set + * @hide + */ + public void setMtePolicy(@NonNull String systemEntity, @MtePolicy int policy) { + throwIfParentInstance("setMtePolicyForUser"); + if (mService != null) { + try { + mService.setMtePolicyBySystem(systemEntity, policy); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + } + } + + + /** * Called by a device owner, profile owner of an organization-owned device to * get the Memory Tagging Extension (MTE) policy @@ -14453,7 +14482,7 @@ public class DevicePolicyManager { * *

* The following methods are supported for the parent instance but can only be called by the - * profile owner of a managed profile that was created during the device provisioning flow: + * profile owner on an organization owned managed profile: *

    *
  • {@link #getPasswordComplexity}
  • *
  • {@link #setCameraDisabled}
  • @@ -14461,11 +14490,6 @@ public class DevicePolicyManager { *
  • {@link #setAccountManagementDisabled(ComponentName, String, boolean)}
  • *
  • {@link #setPermittedInputMethods}
  • *
  • {@link #getPermittedInputMethods}
  • - *
- * - *

The following methods can be called by the profile owner of a managed profile - * on an organization-owned device: - *

    *
  • {@link #wipeData}
  • *
* @@ -18177,4 +18201,4 @@ public class DevicePolicyManager { } return HEADLESS_DEVICE_OWNER_MODE_UNSUPPORTED; } -} \ No newline at end of file +} diff --git a/core/java/android/app/admin/IDevicePolicyManager.aidl b/core/java/android/app/admin/IDevicePolicyManager.aidl index d048b5371fc4c0c5ec84416131d9f84524230b9a..e7be822d52d3367193241cf91069b1b5ee04e64c 100644 --- a/core/java/android/app/admin/IDevicePolicyManager.aidl +++ b/core/java/android/app/admin/IDevicePolicyManager.aidl @@ -617,6 +617,7 @@ interface IDevicePolicyManager { int[] getApplicationExemptions(String packageName); void setMtePolicy(int flag, String callerPackageName); + void setMtePolicyBySystem(in String systemEntity, int policy); int getMtePolicy(String callerPackageName); void setManagedSubscriptionsPolicy(in ManagedSubscriptionsPolicy policy); diff --git a/core/java/android/app/background_install_control_manager.aconfig b/core/java/android/app/background_install_control_manager.aconfig index d29c5b58092d25476c38ac184b2fe5d00662a6a0..39f10dc0647ffd048cc4994746073fca80be04fc 100644 --- a/core/java/android/app/background_install_control_manager.aconfig +++ b/core/java/android/app/background_install_control_manager.aconfig @@ -9,3 +9,10 @@ flag { is_fixed_read_only: true bug: "287507984" } + +flag { + name: "background_install_control_callback_api" + namespace: "preload_safety" + description: "Feature flag to enable the use of push API in background install control service" + bug: "369382811" +} \ No newline at end of file diff --git a/core/java/android/app/jank/FrameOverrunHistogram.java b/core/java/android/app/jank/FrameOverrunHistogram.java index e28ac126a90af45c597c51171e440644c05489b9..3ad6531a46bf9b117881e383582a378835462c48 100644 --- a/core/java/android/app/jank/FrameOverrunHistogram.java +++ b/core/java/android/app/jank/FrameOverrunHistogram.java @@ -39,7 +39,7 @@ public class FrameOverrunHistogram { * Create a new instance of FrameOverrunHistogram. */ public FrameOverrunHistogram() { - mBucketCounts = new int[sBucketEndpoints.length - 1]; + mBucketCounts = new int[sBucketEndpoints.length]; } /** diff --git a/core/java/android/app/jank/JankDataProcessor.java b/core/java/android/app/jank/JankDataProcessor.java index 7525d0402ee49f4b2fe8915394dea74c36771f25..7ceaeb3fb07059ca589b3f23cbd74fcba3d08f41 100644 --- a/core/java/android/app/jank/JankDataProcessor.java +++ b/core/java/android/app/jank/JankDataProcessor.java @@ -59,7 +59,6 @@ public class JankDataProcessor { * @param appUid the uid of the app. */ public void processJankData(List jankData, String activityName, int appUid) { - mCurrentBatchCount++; // add all the previous and active states to the pending states list. mStateTracker.retrieveAllStates(mPendingStates); @@ -79,9 +78,8 @@ public class JankDataProcessor { } } // At this point we have attributed all frames to a state. - if (mCurrentBatchCount >= LOG_BATCH_FREQUENCY) { - logMetricCounts(); - } + incrementBatchCountAndMaybeLogStats(); + // return the StatData object back to the pool to be reused. jankDataProcessingComplete(); } @@ -91,7 +89,73 @@ public class JankDataProcessor { * stats */ public void mergeJankStats(AppJankStats jankStats, String activityName) { - // TODO b/377572463 Add Merging Logic + // Each state has a key which is a combination of widget category, widget id and widget + // state, this key is also used to identify pending stats, a pending stat is essentially a + // state with frames associated with it. + String stateKey = mStateTracker.getStateKey(jankStats.getWidgetCategory(), + jankStats.getWidgetId(), jankStats.getWidgetState()); + + if (mPendingJankStats.containsKey(stateKey)) { + mergeExistingStat(stateKey, jankStats); + } else { + mergeNewStat(stateKey, activityName, jankStats); + } + + incrementBatchCountAndMaybeLogStats(); + } + + private void mergeExistingStat(String stateKey, AppJankStats jankStat) { + PendingJankStat pendingStat = mPendingJankStats.get(stateKey); + + pendingStat.mJankyFrames += jankStat.getJankyFrameCount(); + pendingStat.mTotalFrames += jankStat.getTotalFrameCount(); + + mergeOverrunHistograms(pendingStat.mFrameOverrunBuckets, + jankStat.getFrameOverrunHistogram().getBucketCounters()); + } + + private void mergeNewStat(String stateKey, String activityName, AppJankStats jankStats) { + // Check if we have space for a new stat + if (mPendingJankStats.size() > MAX_IN_MEMORY_STATS) { + return; + } + + PendingJankStat pendingStat = mPendingJankStatsPool.acquire(); + if (pendingStat == null) { + pendingStat = new PendingJankStat(); + + } + pendingStat.clearStats(); + + pendingStat.mActivityName = activityName; + pendingStat.mUid = jankStats.getUid(); + pendingStat.mWidgetId = jankStats.getWidgetId(); + pendingStat.mWidgetCategory = jankStats.getWidgetCategory(); + pendingStat.mWidgetState = jankStats.getWidgetState(); + pendingStat.mTotalFrames = jankStats.getTotalFrameCount(); + pendingStat.mJankyFrames = jankStats.getJankyFrameCount(); + + mergeOverrunHistograms(pendingStat.mFrameOverrunBuckets, + jankStats.getFrameOverrunHistogram().getBucketCounters()); + + mPendingJankStats.put(stateKey, pendingStat); + } + + private void mergeOverrunHistograms(int[] mergeTarget, int[] mergeSource) { + // The length of each histogram should be identical, if they are not then its possible the + // buckets are not in sync, these records should not be recorded. + if (mergeTarget.length != mergeSource.length) return; + + for (int i = 0; i < mergeTarget.length; i++) { + mergeTarget[i] += mergeSource[i]; + } + } + + private void incrementBatchCountAndMaybeLogStats() { + mCurrentBatchCount++; + if (mCurrentBatchCount >= LOG_BATCH_FREQUENCY) { + logMetricCounts(); + } } /** diff --git a/core/java/android/app/jank/JankTracker.java b/core/java/android/app/jank/JankTracker.java index 202281f98c972ef4bb20797579c9ba2f9ef4497e..469521668d2546c4d6902322faab0a34bad6c9e4 100644 --- a/core/java/android/app/jank/JankTracker.java +++ b/core/java/android/app/jank/JankTracker.java @@ -89,7 +89,12 @@ public class JankTracker { * stats */ public void mergeAppJankStats(AppJankStats appJankStats) { - mJankDataProcessor.mergeJankStats(appJankStats, mActivityName); + getHandler().post(new Runnable() { + @Override + public void run() { + mJankDataProcessor.mergeJankStats(appJankStats, mActivityName); + } + }); } public void setActivityName(@NonNull String activityName) { diff --git a/core/java/android/app/jank/StateTracker.java b/core/java/android/app/jank/StateTracker.java index c86d5a5cff20c22d608b37e2f7f6b4505ff621ad..21bb5e8280eed8536be30e5033cd7cd8df616f5c 100644 --- a/core/java/android/app/jank/StateTracker.java +++ b/core/java/android/app/jank/StateTracker.java @@ -180,7 +180,11 @@ public class StateTracker { } } - private String getStateKey(String widgetCategory, String widgetId, String widgetState) { + /** + * Returns a concatenated string of the inputs. This key can be used to retrieve both pending + * stats and the state that was used to create the pending stat. + */ + public String getStateKey(String widgetCategory, String widgetId, String widgetState) { return widgetCategory + widgetId + widgetState; } diff --git a/core/java/android/app/notification.aconfig b/core/java/android/app/notification.aconfig index 2e3d5e15e03742e263b2bf7b4f7dd053678d2e0e..8b6840c1b552b3e2ee8e8d81dfa2ff613cc49ef9 100644 --- a/core/java/android/app/notification.aconfig +++ b/core/java/android/app/notification.aconfig @@ -276,6 +276,13 @@ flag { bug: "367996732" } +flag { + name: "nm_binder_perf_permission_check" + namespace: "systemui" + description: "Use PermissionManager for areNotificationsEnabled() instead of NMS" + bug: "362981561" +} + flag { name: "no_sbnholder" namespace: "systemui" diff --git a/core/java/android/app/ondeviceintelligence/InferenceInfo.java b/core/java/android/app/ondeviceintelligence/InferenceInfo.java index 5557a81cbe40869e7bfc9c1049179330a2b4340d..cae8db27a435b0396165de6d287706455fe8ccb9 100644 --- a/core/java/android/app/ondeviceintelligence/InferenceInfo.java +++ b/core/java/android/app/ondeviceintelligence/InferenceInfo.java @@ -16,6 +16,12 @@ package android.app.ondeviceintelligence; +import static android.app.ondeviceintelligence.flags.Flags.FLAG_ENABLE_ON_DEVICE_INTELLIGENCE_MODULE; + +import android.annotation.CurrentTimeMillisLong; +import android.annotation.FlaggedApi; +import android.annotation.NonNull; +import android.annotation.SystemApi; import android.os.Parcel; import android.os.Parcelable; @@ -25,7 +31,9 @@ import android.os.Parcelable; * * @hide */ -public class InferenceInfo implements Parcelable { +@SystemApi +@FlaggedApi(FLAG_ENABLE_ON_DEVICE_INTELLIGENCE_MODULE) +public final class InferenceInfo implements Parcelable { /** * Uid for the caller app. @@ -55,7 +63,7 @@ public class InferenceInfo implements Parcelable { * @param endTimeMs Inference end time (milliseconds from the epoch time). * @param suspendedTimeMs Suspended time in milliseconds. */ - public InferenceInfo(int uid, long startTimeMs, long endTimeMs, + InferenceInfo(int uid, long startTimeMs, long endTimeMs, long suspendedTimeMs) { this.uid = uid; this.startTimeMs = startTimeMs; @@ -68,7 +76,7 @@ public class InferenceInfo implements Parcelable { * * @param in The Parcel to read the object's data from. */ - protected InferenceInfo(Parcel in) { + private InferenceInfo(@NonNull Parcel in) { uid = in.readInt(); startTimeMs = in.readLong(); endTimeMs = in.readLong(); @@ -79,11 +87,11 @@ public class InferenceInfo implements Parcelable { /** * Writes the object's data to the provided Parcel. * - * @param dest The Parcel to write the object's data to. + * @param dest The Parcel to write the object's data to. * @param flags Additional flags about how the object should be written. */ @Override - public void writeToParcel(Parcel dest, int flags) { + public void writeToParcel(@NonNull Parcel dest, int flags) { dest.writeInt(uid); dest.writeLong(startTimeMs); dest.writeLong(endTimeMs); @@ -104,7 +112,8 @@ public class InferenceInfo implements Parcelable { * * @return the inference start time in milliseconds from the epoch time. */ - public long getStartTimeMs() { + @CurrentTimeMillisLong + public long getStartTimeMillis() { return startTimeMs; } @@ -113,7 +122,8 @@ public class InferenceInfo implements Parcelable { * * @return the inference end time in milliseconds from the epoch time. */ - public long getEndTimeMs() { + @CurrentTimeMillisLong + public long getEndTimeMillis() { return endTimeMs; } @@ -122,7 +132,8 @@ public class InferenceInfo implements Parcelable { * * @return the suspended time in milliseconds. */ - public long getSuspendedTimeMs() { + @CurrentTimeMillisLong + public long getSuspendedTimeMillis() { return suspendedTimeMs; } @@ -148,21 +159,19 @@ public class InferenceInfo implements Parcelable { /** * Builder class for creating instances of {@link InferenceInfo}. */ - public static class Builder { - private int uid; + public static final class Builder { + private final int uid; private long startTimeMs; private long endTimeMs; private long suspendedTimeMs; /** - * Sets the UID for the caller app. + * Provides a builder instance to create a InferenceInfo for given caller uid. * - * @param uid the UID for the caller app. - * @return the Builder instance. + * @param uid the caller uid associated with the inference info. */ - public Builder setUid(int uid) { + public Builder(int uid) { this.uid = uid; - return this; } /** @@ -171,7 +180,7 @@ public class InferenceInfo implements Parcelable { * @param startTimeMs the inference start time in milliseconds from the epoch time. * @return the Builder instance. */ - public Builder setStartTimeMs(long startTimeMs) { + public @NonNull Builder setStartTimeMillis(@CurrentTimeMillisLong long startTimeMs) { this.startTimeMs = startTimeMs; return this; } @@ -182,7 +191,7 @@ public class InferenceInfo implements Parcelable { * @param endTimeMs the inference end time in milliseconds from the epoch time. * @return the Builder instance. */ - public Builder setEndTimeMs(long endTimeMs) { + public @NonNull Builder setEndTimeMillis(@CurrentTimeMillisLong long endTimeMs) { this.endTimeMs = endTimeMs; return this; } @@ -193,7 +202,7 @@ public class InferenceInfo implements Parcelable { * @param suspendedTimeMs the suspended time in milliseconds. * @return the Builder instance. */ - public Builder setSuspendedTimeMs(long suspendedTimeMs) { + public @NonNull Builder setSuspendedTimeMillis(@CurrentTimeMillisLong long suspendedTimeMs) { this.suspendedTimeMs = suspendedTimeMs; return this; } @@ -203,7 +212,7 @@ public class InferenceInfo implements Parcelable { * * @return an instance of {@link InferenceInfo}. */ - public InferenceInfo build() { + public @NonNull InferenceInfo build() { return new InferenceInfo(uid, startTimeMs, endTimeMs, suspendedTimeMs); } diff --git a/core/java/android/app/ondeviceintelligence/OnDeviceIntelligenceManager.java b/core/java/android/app/ondeviceintelligence/OnDeviceIntelligenceManager.java index 937a9cde1097712e7b04b14c1f7484fd259d776b..91651e317b185aff59cae22c066918bab1e227d7 100644 --- a/core/java/android/app/ondeviceintelligence/OnDeviceIntelligenceManager.java +++ b/core/java/android/app/ondeviceintelligence/OnDeviceIntelligenceManager.java @@ -17,9 +17,11 @@ package android.app.ondeviceintelligence; import static android.app.ondeviceintelligence.flags.Flags.FLAG_ENABLE_ON_DEVICE_INTELLIGENCE; +import static android.app.ondeviceintelligence.flags.Flags.FLAG_ENABLE_ON_DEVICE_INTELLIGENCE_MODULE; import android.Manifest; import android.annotation.CallbackExecutor; +import android.annotation.CurrentTimeMillisLong; import android.annotation.FlaggedApi; import android.annotation.NonNull; import android.annotation.Nullable; @@ -502,11 +504,10 @@ public final class OnDeviceIntelligenceManager { * * @param startTimeEpochMillis epoch millis used to filter the InferenceInfo events. * @return InferenceInfo events since the passed in startTimeEpochMillis. - * - * @hide */ @RequiresPermission(Manifest.permission.DUMP) - public List getLatestInferenceInfo(long startTimeEpochMillis) { + @FlaggedApi(FLAG_ENABLE_ON_DEVICE_INTELLIGENCE_MODULE) + public @NonNull List getLatestInferenceInfo(@CurrentTimeMillisLong long startTimeEpochMillis) { try { return mService.getLatestInferenceInfo(startTimeEpochMillis); } catch (RemoteException e) { diff --git a/core/java/android/app/wearable/WearableSensingManager.java b/core/java/android/app/wearable/WearableSensingManager.java index f0763752e05477a0d3f7929358f9e0490755f5d8..5b14b038f1309db695801e4517b9b5cf86b1ee11 100644 --- a/core/java/android/app/wearable/WearableSensingManager.java +++ b/core/java/android/app/wearable/WearableSensingManager.java @@ -55,6 +55,7 @@ import java.io.OutputStream; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.util.Map; +import java.util.NoSuchElementException; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.Executor; import java.util.function.Consumer; @@ -248,7 +249,11 @@ public class WearableSensingManager { * @param executor Executor on which to run the consumer callback * @param statusConsumer A consumer that handles the status codes for providing the connection * and errors in the encrypted channel. + * @deprecated Use {@link #provideConnection(WearableConnection, Executor)} instead to provide a + * remote wearable device connection to the WearableSensingService */ + @FlaggedApi(Flags.FLAG_ENABLE_CONCURRENT_WEARABLE_CONNECTIONS) + @Deprecated @RequiresPermission(Manifest.permission.MANAGE_WEARABLE_SENSING_SERVICE) public void provideConnection( @NonNull ParcelFileDescriptor wearableConnection, @@ -348,9 +353,7 @@ public class WearableSensingManager { wearableConnection.getMetadata(), createWearableSensingCallback(executor), statusCallback); - if (connectionId != CONNECTION_ID_INVALID) { - mWearableConnectionIdMap.put(wearableConnection, connectionId); - } + mWearableConnectionIdMap.put(wearableConnection, connectionId); // For invalid connection IDs, the status callback will remove the connection from // mWearableConnectionIdMap } catch (RemoteException e) { @@ -367,36 +370,37 @@ public class WearableSensingManager { *

After this method returns, there will be no new invocation to callback methods in the * removed {@link WearableConnection}. Ongoing invocations will continue to run. * - *

This method does nothing if the provided {@code wearableConnection} does not match any - * open connection. + *

This method throws a {@link NoSuchElementException} if the provided {@code + * wearableConnection} does not match any open connection. * *

This method should not be called before the corresponding {@link * #provideConnection(WearableConnection, Executor)} invocation returns. Otherwise, the - * connection may not be removed. + * connection may not be removed, and an {@link IllegalStateException} may be thrown. * * @param wearableConnection The WearableConnection instance previously provided to {@link * #provideConnection(WearableConnection, Executor)}. - * @return true if a concurrent connection quota has been freed due to this method invocation. - * Returns false otherwise. + * @throws NoSuchElementException if the connection was never provided or was already removed. + * @throws IllegalStateException if the {@link #provideConnection(WearableConnection, Executor)} + * invocation for the given connection has not returned. */ @RequiresPermission(Manifest.permission.MANAGE_WEARABLE_SENSING_SERVICE) @FlaggedApi(Flags.FLAG_ENABLE_CONCURRENT_WEARABLE_CONNECTIONS) - public boolean removeConnection(@NonNull WearableConnection wearableConnection) { - int connectionId = - mWearableConnectionIdMap.getOrDefault(wearableConnection, CONNECTION_ID_INVALID); - if (connectionId == CONNECTION_ID_INVALID) { - return false; + public void removeConnection(@NonNull WearableConnection wearableConnection) { + Integer connectionId = mWearableConnectionIdMap.remove(wearableConnection); + if (connectionId == null || connectionId == CONNECTION_ID_INVALID) { + throw new NoSuchElementException( + "The provided connection was never provided or was already removed."); } if (connectionId == CONNECTION_ID_PLACEHOLDER) { - Slog.w( - TAG, + throw new IllegalStateException( "Attempt to remove connection before provideConnection returns. The connection" + " will not be removed."); - return false; } - mWearableConnectionIdMap.remove(wearableConnection); try { - return mService.removeConnection(connectionId); + if (!mService.removeConnection(connectionId)) { + throw new NoSuchElementException( + "The provided connection was never provided or was already removed."); + } } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } diff --git a/core/java/android/appwidget/AppWidgetManager.java b/core/java/android/appwidget/AppWidgetManager.java index 8f20ea034cf69fab8eaa8f5b5a90cebfbf55a55f..40de2985f68a133e4c6753969554098a3ac35295 100644 --- a/core/java/android/appwidget/AppWidgetManager.java +++ b/core/java/android/appwidget/AppWidgetManager.java @@ -31,6 +31,7 @@ import android.annotation.UiThread; import android.annotation.UserIdInt; import android.app.IServiceConnection; import android.app.PendingIntent; +import android.app.usage.UsageStatsManager; import android.appwidget.flags.Flags; import android.compat.annotation.UnsupportedAppUsage; import android.content.ComponentName; @@ -41,12 +42,14 @@ 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.Build; import android.os.Bundle; import android.os.Handler; import android.os.HandlerExecutor; import android.os.HandlerThread; import android.os.Looper; +import android.os.PersistableBundle; import android.os.Process; import android.os.RemoteException; import android.os.UserHandle; @@ -485,6 +488,67 @@ public class AppWidgetManager { public static final String ACTION_APPWIDGET_HOST_RESTORED = "android.appwidget.action.APPWIDGET_HOST_RESTORED"; + /** + * This is the value of {@link UsageStatsManager.EXTRA_EVENT_ACTION} in the event bundle for + * widget user interaction events. + * + * A single widget interaction event describes what user interactions happened during a single + * impression of the widget. + */ + @FlaggedApi(Flags.FLAG_ENGAGEMENT_METRICS) + public static final String EVENT_TYPE_WIDGET_INTERACTION = "widget_interaction"; + + /** + * This is the value of {@link UsageStatsManager.EXTRA_EVENT_CATEGORY} in the event bundle for + * widget user interaction events. + */ + @FlaggedApi(Flags.FLAG_ENGAGEMENT_METRICS) + public static final String EVENT_CATEGORY_APPWIDGET = "android.appwidget"; + + /** + * This bundle extra describes which views have been clicked during a single impression of the + * widget. It is an integer array of view IDs of the clicked views. + * + * Widget providers may set a different ID for event purposes by setting the + * {@link android.R.id.remoteViewsMetricsId} int tag on the view. + * + * @see android.views.RemoteViews.setIntTag + */ + @FlaggedApi(Flags.FLAG_ENGAGEMENT_METRICS) + public static final String EXTRA_EVENT_CLICKED_VIEWS = + "android.appwidget.extra.EVENT_CLICKED_VIEWS"; + + /** + * This bundle extra describes which views have been scrolled during a single impression of the + * widget. It is an integer array of view IDs of the scrolled views. + * + * Widget providers may set a different ID for event purposes by setting the + * {@link android.R.id.remoteViewsMetricsId} int tag on the view. + * + * @see android.views.RemoteViews.setIntTag + */ + @FlaggedApi(Flags.FLAG_ENGAGEMENT_METRICS) + public static final String EXTRA_EVENT_SCROLLED_VIEWS = + "android.appwidget.extra.EVENT_SCROLLED_VIEWS"; + + /** + * This bundle extra contains a long that represents the duration of time in milliseconds + * during which the widget was visible. + */ + @FlaggedApi(Flags.FLAG_ENGAGEMENT_METRICS) + public static final String EXTRA_EVENT_DURATION_MS = + "android.appwidget.extra.EVENT_DURATION_MS"; + + /** + * This bundle extra contains an integer array with 4 elements that describe the left, top, + * right, and bottom coordinates of the widget at the end of the interaction event. + * + * This Rect indicates the current position and size of the widget. + */ + @FlaggedApi(Flags.FLAG_ENGAGEMENT_METRICS) + public static final String EXTRA_EVENT_POSITION_RECT = + "android.appwidget.extra.EVENT_POSITION_RECT"; + private static final String TAG = "AppWidgetManager"; private static Executor sUpdateExecutor; @@ -1516,6 +1580,39 @@ public class AppWidgetManager { } } + /** + * Create a {@link PersistableBundle} that represents a single widget interaction event. + * + * @param appWidgetId App Widget ID of the widget. + * @param durationMs Duration of the impression in milliseconds + * @param position Current position of the widget. + * @param clickedIds IDs of views clicked during this event. + * @param scrolledIds IDs of views scrolled during this event. + * + * @hide + */ + @FlaggedApi(Flags.FLAG_ENGAGEMENT_METRICS) + @NonNull + public static PersistableBundle createWidgetInteractionEvent(int appWidgetId, long durationMs, + @Nullable Rect position, @Nullable int[] clickedIds, @Nullable int[] scrolledIds) { + PersistableBundle extras = new PersistableBundle(); + extras.putString(UsageStatsManager.EXTRA_EVENT_ACTION, EVENT_TYPE_WIDGET_INTERACTION); + extras.putString(UsageStatsManager.EXTRA_EVENT_CATEGORY, EVENT_CATEGORY_APPWIDGET); + extras.putInt(EXTRA_APPWIDGET_ID, appWidgetId); + extras.putLong(EXTRA_EVENT_DURATION_MS, durationMs); + if (position != null) { + extras.putIntArray(EXTRA_EVENT_POSITION_RECT, + new int[]{position.left, position.top, position.right, position.bottom}); + } + if (clickedIds != null && clickedIds.length > 0) { + extras.putIntArray(EXTRA_EVENT_CLICKED_VIEWS, clickedIds); + } + if (scrolledIds != null && scrolledIds.length > 0) { + extras.putIntArray(EXTRA_EVENT_SCROLLED_VIEWS, scrolledIds); + } + return extras; + } + @UiThread private static @NonNull Executor createUpdateExecutorIfNull() { diff --git a/core/java/android/appwidget/flags.aconfig b/core/java/android/appwidget/flags.aconfig index fb33348d9c26474434f98d4302a9b948da8fe6e1..17bcdb013673ed42fdaa1925e727ac954b82684f 100644 --- a/core/java/android/appwidget/flags.aconfig +++ b/core/java/android/appwidget/flags.aconfig @@ -76,12 +76,15 @@ flag { } flag { - name: "use_smaller_app_widget_radius" + name: "use_smaller_app_widget_system_radius" namespace: "app_widgets" description: "Updates system corner radius for app widgets to 24.dp instead of 28.dp" bug: "373351337" is_exported: true is_fixed_read_only: true + metadata { + purpose: PURPOSE_BUGFIX + } } flag { @@ -102,3 +105,10 @@ flag { purpose: PURPOSE_BUGFIX } } + +flag { + name: "engagement_metrics" + namespace: "app_widgets" + description: "Enable collection of widget engagement metrics" + bug: "364655296" +} diff --git a/core/java/android/companion/CompanionDeviceService.java b/core/java/android/companion/CompanionDeviceService.java index 5ad2348254e283cca674c837eb64fbc849d7257f..db080fcc7702786afac51d8e151519180e3a9f41 100644 --- a/core/java/android/companion/CompanionDeviceService.java +++ b/core/java/android/companion/CompanionDeviceService.java @@ -249,7 +249,7 @@ public abstract class CompanionDeviceService extends Service { // TODO(b/315163162) Add @Deprecated keyword after 24Q2 cut. /** - * Called by system whenever a device associated with this app is connected. + * Called by the system when an associated device is nearby or connected. * * @param associationInfo A record for the companion device. */ @@ -262,7 +262,7 @@ public abstract class CompanionDeviceService extends Service { // TODO(b/315163162) Add @Deprecated keyword after 24Q2 cut. /** - * Called by system whenever a device associated with this app is disconnected. + * Called by the system when an associated device is out of range or disconnected. * * @param associationInfo A record for the companion device. */ @@ -274,7 +274,7 @@ public abstract class CompanionDeviceService extends Service { } /** - * Called by the system during device events. + * Called by the system when an associated device's presence state changes. * * @see CompanionDeviceManager#startObservingDevicePresence(ObservingDevicePresenceRequest) */ diff --git a/core/java/android/companion/virtual/IVirtualDevice.aidl b/core/java/android/companion/virtual/IVirtualDevice.aidl index d3a1c25b74d5967e0835ec792afb2132af463796..367f1afc912be28b1d7ef48fe0eb9623908ca505 100644 --- a/core/java/android/companion/virtual/IVirtualDevice.aidl +++ b/core/java/android/companion/virtual/IVirtualDevice.aidl @@ -90,11 +90,6 @@ interface IVirtualDevice { */ boolean hasCustomAudioInputSupport(); - /** - * Returns whether this device is allowed to create mirror displays. - */ - boolean canCreateMirrorDisplays(); - /* * Turns off all trusted non-mirror displays of the virtual device. */ diff --git a/core/java/android/companion/virtual/flags.aconfig b/core/java/android/companion/virtual/flags.aconfig index 3e6919bac5fa6bd8f001767a938db3869efac83c..46da4a3d99bc48a855d030e7e694a15b615c61a2 100644 --- a/core/java/android/companion/virtual/flags.aconfig +++ b/core/java/android/companion/virtual/flags.aconfig @@ -81,14 +81,3 @@ flag { description: "Enable virtual stylus input" bug: "304829446" } - -flag { - name: "impulse_velocity_strategy_for_touch_navigation" - is_exported: true - namespace: "virtual_devices" - description: "Use impulse velocity strategy during conversion of touch navigation flings into Dpad events" - bug: "338426241" - metadata { - purpose: PURPOSE_BUGFIX - } -} \ No newline at end of file diff --git a/core/java/android/content/Context.java b/core/java/android/content/Context.java index 6086f2455a31200054c7fedbc4060321c3b1d74a..6e2ca2c109f157258187be4b94d82c1c02d79688 100644 --- a/core/java/android/content/Context.java +++ b/core/java/android/content/Context.java @@ -18,6 +18,7 @@ package android.content; import static android.app.appfunctions.flags.Flags.FLAG_ENABLE_APP_FUNCTION_MANAGER; import static android.content.flags.Flags.FLAG_ENABLE_BIND_PACKAGE_ISOLATED_PROCESS; +import static android.security.Flags.FLAG_SECURE_LOCKDOWN; import android.annotation.AttrRes; import android.annotation.CallbackExecutor; @@ -4249,6 +4250,7 @@ public abstract class Context { //@hide: WIFI_RTT_SERVICE, //@hide: ETHERNET_SERVICE, WIFI_RTT_RANGING_SERVICE, + WIFI_USD_SERVICE, NSD_SERVICE, AUDIO_SERVICE, AUDIO_DEVICE_VOLUME_SERVICE, @@ -4256,6 +4258,7 @@ public abstract class Context { FINGERPRINT_SERVICE, //@hide: FACE_SERVICE, BIOMETRIC_SERVICE, + AUTHENTICATION_POLICY_SERVICE, MEDIA_ROUTER_SERVICE, TELEPHONY_SERVICE, TELEPHONY_SUBSCRIPTION_SERVICE, @@ -4437,6 +4440,9 @@ public abstract class Context { * web domain approval state. *

{@link #DISPLAY_HASH_SERVICE} ("display_hash") *
A {@link android.view.displayhash.DisplayHashManager} for management of display hashes. + *
{@link #AUTHENTICATION_POLICY_SERVICE} ("authentication_policy") + *
A {@link android.security.authenticationpolicy.AuthenticationPolicyManager} + * for managing authentication related policies on the device. * * *

Note: System services obtained via this API may be closely associated with @@ -4521,8 +4527,9 @@ public abstract class Context { * @see android.content.pm.verify.domain.DomainVerificationManager * @see #DISPLAY_HASH_SERVICE * @see android.view.displayhash.DisplayHashManager + * @see #AUTHENTICATION_POLICY_SERVICE + * @see android.security.authenticationpolicy.AuthenticationPolicyManager */ - // TODO(b/347269120): Re-add @Nullable public abstract Object getSystemService(@ServiceName @NonNull String name); /** @@ -4543,7 +4550,8 @@ public abstract class Context { * {@link android.os.BatteryManager}, {@link android.app.job.JobScheduler}, * {@link android.app.usage.NetworkStatsManager}, * {@link android.content.pm.verify.domain.DomainVerificationManager}, - * {@link android.view.displayhash.DisplayHashManager}. + * {@link android.view.displayhash.DisplayHashManager} + * {@link android.security.authenticationpolicy.AuthenticationPolicyManager}. *

* *

@@ -4568,7 +4576,6 @@ public abstract class Context { */ @SuppressWarnings("unchecked") @RavenwoodKeep - // TODO(b/347269120): Re-add @Nullable public final T getSystemService(@NonNull Class serviceClass) { // Because subclasses may override getSystemService(String) we cannot // perform a lookup by class alone. We must first map the class to its @@ -5090,6 +5097,19 @@ public abstract class Context { */ public static final String WIFI_RTT_RANGING_SERVICE = "wifirtt"; + + /** + * Use with {@link #getSystemService(String)} to retrieve a {@link + * android.net.wifi.usd.UsdManager} for Unsynchronized Service Discovery (USD) operation. + * + * @see #getSystemService(String) + * @see android.net.wifi.usd.UsdManager + * @hide + */ + @FlaggedApi(android.net.wifi.flags.Flags.FLAG_USD) + @SystemApi + public static final String WIFI_USD_SERVICE = "wifi_usd"; + /** * Use with {@link #getSystemService(String)} to retrieve a {@link * android.net.lowpan.LowpanManager} for handling management of @@ -5182,6 +5202,18 @@ public abstract class Context { */ public static final String AUTH_SERVICE = "auth"; + /** + * Use with {@link #getSystemService(String)} to retrieve an {@link + * android.security.authenticationpolicy.AuthenticationPolicyManager}. + * @see #getSystemService + * @see android.security.authenticationpolicy.AuthenticationPolicyManager + * + * @hide + */ + @SystemApi + @FlaggedApi(FLAG_SECURE_LOCKDOWN) + public static final String AUTHENTICATION_POLICY_SERVICE = "authentication_policy"; + /** * Use with {@link #getSystemService(String)} to retrieve a * {@link android.hardware.fingerprint.FingerprintManager} for handling management @@ -5695,12 +5727,12 @@ public abstract class Context { public static final String BINARY_TRANSPARENCY_SERVICE = "transparency"; /** - * System service name for ForensicService. - * The service manages the forensic info on device. + * System service name for IntrusionDetectionService. + * The service manages the intrusion detection info on device. * @hide */ @FlaggedApi(android.security.Flags.FLAG_AFL_API) - public static final String FORENSIC_SERVICE = "forensic"; + public static final String INTRUSION_DETECTION_SERVICE = "intrusion_detection"; /** * System service name for the DeviceIdleManager. diff --git a/core/java/android/content/ContextWrapper.java b/core/java/android/content/ContextWrapper.java index 23d17cb5ce5018eb7ece91a60c4587e44caf368b..413eb9886392b862640a76b45b917975f7da5692 100644 --- a/core/java/android/content/ContextWrapper.java +++ b/core/java/android/content/ContextWrapper.java @@ -960,7 +960,6 @@ public class ContextWrapper extends Context { } @Override - // TODO(b/347269120): Re-add @Nullable public Object getSystemService(String name) { return mBase.getSystemService(name); } diff --git a/core/java/android/content/Intent.java b/core/java/android/content/Intent.java index 88533049f97058ebe4a06f13b47ff22a350fc751..02eed1a7553f9ebb5c6442ddd7d46ce46d8076b1 100644 --- a/core/java/android/content/Intent.java +++ b/core/java/android/content/Intent.java @@ -1211,8 +1211,8 @@ public class Intent implements Parcelable, Cloneable { * {@link android.telecom.TelecomManager#placeCall(Uri, Bundle)} to place calls rather than * relying on this intent. * - *

Note: if you app targets {@link android.os.Build.VERSION_CODES#M M} - * and above and declares as using the {@link android.Manifest.permission#CALL_PHONE} + *

Note: If your app targets {@link android.os.Build.VERSION_CODES#M M} + * or higher and declares as using the {@link android.Manifest.permission#CALL_PHONE} * permission which is not granted, then attempting to use this action will * result in a {@link java.lang.SecurityException}. */ @@ -7720,6 +7720,7 @@ public class Intent implements Parcelable, Cloneable { @IntDef(flag = true, prefix = { "EXTENDED_FLAG_" }, value = { EXTENDED_FLAG_FILTER_MISMATCH, EXTENDED_FLAG_MISSING_CREATOR_OR_INVALID_TOKEN, + EXTENDED_FLAG_NESTED_INTENT_KEYS_COLLECTED, }) @Retention(RetentionPolicy.SOURCE) public @interface ExtendedFlags {} @@ -7740,6 +7741,13 @@ public class Intent implements Parcelable, Cloneable { */ public static final int EXTENDED_FLAG_MISSING_CREATOR_OR_INVALID_TOKEN = 1 << 1; + /** + * This flag indicates this intent called {@link #collectExtraIntentKeys()}. + * + * @hide + */ + public static final int EXTENDED_FLAG_NESTED_INTENT_KEYS_COLLECTED = 1 << 2; + // --------------------------------------------------------------------- // --------------------------------------------------------------------- // toUri() and parseUri() options. @@ -12328,7 +12336,8 @@ public class Intent implements Parcelable, Cloneable { } private void collectNestedIntentKeysRecur(Set visited) { - if (mExtras != null && !mExtras.isParcelled() && !mExtras.isEmpty()) { + addExtendedFlags(EXTENDED_FLAG_NESTED_INTENT_KEYS_COLLECTED); + if (mExtras != null && !mExtras.isEmpty()) { for (String key : mExtras.keySet()) { Object value = mExtras.get(key); diff --git a/core/java/android/content/om/OverlayManager.java b/core/java/android/content/om/OverlayManager.java index ed965b3d17777dc27ccf4f1b968a54f8d3cf972c..6db7dfe4f705a7e14de6f246c5a185fd401076f9 100644 --- a/core/java/android/content/om/OverlayManager.java +++ b/core/java/android/content/om/OverlayManager.java @@ -78,7 +78,8 @@ public class OverlayManager { /** * Applications can use OverlayManager to create overlays to overlay on itself resources. The - * overlay target is itself and the work range is only in caller application. + * overlay target is itself, or the Android package, and the work range is only in caller + * application. * *

In {@link android.content.Context#getSystemService(String)}, it crashes because of {@link * java.lang.NullPointerException} if the parameter is OverlayManager. if the self-targeting is @@ -401,7 +402,7 @@ public class OverlayManager { } /** - * Get the related information of overlays for {@code targetPackageName}. + * Get the related information of self-targeting overlays for {@code targetPackageName}. * * @param targetPackageName the target package name * @return a list of overlay information diff --git a/core/java/android/content/om/OverlayManagerTransaction.java b/core/java/android/content/om/OverlayManagerTransaction.java index becd0ea285afd4cc4382e26f4269537f70dd84ae..87b2e9350aa14a1453664c7ebde732f1e57cd804 100644 --- a/core/java/android/content/om/OverlayManagerTransaction.java +++ b/core/java/android/content/om/OverlayManagerTransaction.java @@ -209,6 +209,7 @@ public final class OverlayManagerTransaction implements Parcelable { */ public static final class Builder { private final List mRequests = new ArrayList<>(); + private boolean mSelfTargeting = false; /** * Request that an overlay package be enabled and change its loading @@ -245,6 +246,18 @@ public final class OverlayManagerTransaction implements Parcelable { return this; } + /** + * Request that an overlay package be self-targeting. Self-targeting overlays enable + * applications to overlay on itself resources. The overlay target is itself, or the Android + * package, and the work range is only in caller application. + * @param selfTargeting whether the overlay is self-targeting, the default is false. + * @hide + */ + public Builder setSelfTargeting(boolean selfTargeting) { + mSelfTargeting = selfTargeting; + return this; + } + /** * Registers the fabricated overlay with the overlay manager so it can be enabled and * disabled for any user. @@ -286,7 +299,7 @@ public final class OverlayManagerTransaction implements Parcelable { */ @NonNull public OverlayManagerTransaction build() { - return new OverlayManagerTransaction(mRequests, false /* selfTargeting */); + return new OverlayManagerTransaction(mRequests, mSelfTargeting); } } diff --git a/core/java/android/content/pm/ActivityInfo.java b/core/java/android/content/pm/ActivityInfo.java index ce52825ddb7377896d9a0c9ecff05510b0b2462f..37f3f17ebe429baf7bba7814f0f3e1598663df94 100644 --- a/core/java/android/content/pm/ActivityInfo.java +++ b/core/java/android/content/pm/ActivityInfo.java @@ -453,6 +453,13 @@ public class ActivityInfo extends ComponentInfo implements Parcelable { * Value of {@link #colorMode} indicating that the activity should use a * high dynamic range if the presentation display supports it. * + *

Note: This does not impact SurfaceViews or SurfaceControls, as those have their own + * independent HDR support.

+ * + *

Important: Although this value was added in API 26, it is strongly recommended + * to avoid using it until API 34 which is when HDR support for the UI toolkit was officially + * added.

+ * * @see android.R.attr#colorMode */ public static final int COLOR_MODE_HDR = 2; @@ -1320,23 +1327,23 @@ public class ActivityInfo extends ComponentInfo implements Parcelable { 264301586L; // buganizer id /** - * Excludes the packages the override is applied to from the camera compatibility treatment - * in free-form windowing mode for fixed-orientation apps. + * Includes the packages the override is applied to in the camera compatibility treatment in + * free-form windowing mode for fixed-orientation apps. * *

In free-form windowing mode, the compatibility treatment emulates running on a portrait * device by letterboxing the app window and changing the camera characteristics to what apps * commonly expect in a portrait device: 90 and 270 degree sensor rotation for back and front * cameras, respectively, and setting display rotation to 0. * - *

Use this flag to disable the compatibility treatment for apps that do not respond well to - * the treatment. + *

Use this flag to enable the compatibility treatment for apps in which camera doesn't work + * well in freeform windowing. * * @hide */ @ChangeId @Overridable @Disabled - public static final long OVERRIDE_CAMERA_COMPAT_DISABLE_FREEFORM_WINDOWING_TREATMENT = + public static final long OVERRIDE_CAMERA_COMPAT_ENABLE_FREEFORM_WINDOWING_TREATMENT = 314961188L; /** diff --git a/core/java/android/content/pm/ApplicationInfo.java b/core/java/android/content/pm/ApplicationInfo.java index cccfdb0938e594cedbe8e6cfc194ce2ba6a81587..94784227049d8b9eb19507020d2bf5661d80027e 100644 --- a/core/java/android/content/pm/ApplicationInfo.java +++ b/core/java/android/content/pm/ApplicationInfo.java @@ -1449,6 +1449,97 @@ public class ApplicationInfo extends PackageItemInfo implements Parcelable { } } + /** + * Use this to report any errors during alignment checks + * + * @hide + */ + public static final int PAGE_SIZE_APP_COMPAT_FLAG_ERROR = -1; + + /** + * Initial value for mPageSizeAppCompatFlags + * + * @hide + */ + public static final int PAGE_SIZE_APP_COMPAT_FLAG_UNDEFINED = 0; + + /** + * if set, extract libs forcefully for 16 KB device and show warning dialog. + * + * @hide + */ + public static final int PAGE_SIZE_APP_COMPAT_FLAG_UNCOMPRESSED_LIBS_NOT_ALIGNED = 1 << 1; + + /** + * if set, load 4 KB aligned ELFs on 16 KB device in compat mode and show warning dialog. + * + * @hide + */ + public static final int PAGE_SIZE_APP_COMPAT_FLAG_ELF_NOT_ALIGNED = 1 << 2; + + /** + * Run in 16 KB app compat mode. This flag will be set explicitly through settings. If set, 16 + * KB app compat warning dialogs will still show up. + * + * @hide + */ + public static final int PAGE_SIZE_APP_COMPAT_FLAG_SETTINGS_OVERRIDE_ENABLED = 1 << 3; + + /** + * Disable 16 KB app compat mode through settings. It should only affect ELF loading as app is + * already installed. + * + * @hide + */ + public static final int PAGE_SIZE_APP_COMPAT_FLAG_SETTINGS_OVERRIDE_DISABLED = 1 << 4; + + /** + * Run in 16 KB app compat mode. This flag will be set explicitly through manifest. If set, hide + * the 16 KB app compat warning dialogs. This has the highest priority to enable compat mode. + * + * @hide + */ + public static final int PAGE_SIZE_APP_COMPAT_FLAG_MANIFEST_OVERRIDE_ENABLED = 1 << 5; + + /** + * Disable 16 KB app compat mode. This has the highest priority to disable compat mode. + * + * @hide + */ + public static final int PAGE_SIZE_APP_COMPAT_FLAG_MANIFEST_OVERRIDE_DISABLED = 1 << 6; + + /** + * Max value for page size app compat + * + * @hide + */ + public static final int PAGE_SIZE_APP_COMPAT_FLAG_MAX = 1 << 7; + + /** + * 16 KB app compat status for the app. App can have native shared libs which are not page + * aligned, LOAD segments inside the shared libs have to be page aligned. Apps can specify the + * override in manifest file as well. + */ + private @PageSizeAppCompatFlags int mPageSizeAppCompatFlags = + ApplicationInfo.PAGE_SIZE_APP_COMPAT_FLAG_UNDEFINED; + + /** {@hide} */ + @IntDef( + prefix = {"PAGE_SIZE_APP_COMPAT_FLAG_"}, + value = { + PAGE_SIZE_APP_COMPAT_FLAG_ERROR, + PAGE_SIZE_APP_COMPAT_FLAG_UNDEFINED, + PAGE_SIZE_APP_COMPAT_FLAG_UNCOMPRESSED_LIBS_NOT_ALIGNED, + PAGE_SIZE_APP_COMPAT_FLAG_ELF_NOT_ALIGNED, + PAGE_SIZE_APP_COMPAT_FLAG_MANIFEST_OVERRIDE_ENABLED, + PAGE_SIZE_APP_COMPAT_FLAG_MANIFEST_OVERRIDE_DISABLED, + PAGE_SIZE_APP_COMPAT_FLAG_SETTINGS_OVERRIDE_ENABLED, + PAGE_SIZE_APP_COMPAT_FLAG_SETTINGS_OVERRIDE_DISABLED, + PAGE_SIZE_APP_COMPAT_FLAG_MAX, + }) + @Retention(RetentionPolicy.SOURCE) + public @interface PageSizeAppCompatFlags {} + /** @hide */ public String classLoaderName; @@ -1777,7 +1868,7 @@ public class ApplicationInfo extends PackageItemInfo implements Parcelable { pw.println(prefix + "enableOnBackInvokedCallback=" + isOnBackInvokedCallbackEnabled()); pw.println(prefix + "allowCrossUidActivitySwitchFromBelow=" + allowCrossUidActivitySwitchFromBelow); - + pw.println(prefix + "mPageSizeAppCompatFlags=" + mPageSizeAppCompatFlags); } pw.println(prefix + "createTimestamp=" + createTimestamp); if (mKnownActivityEmbeddingCerts != null) { @@ -1897,6 +1988,10 @@ public class ApplicationInfo extends PackageItemInfo implements Parcelable { } proto.write(ApplicationInfoProto.Detail.ALLOW_CROSS_UID_ACTIVITY_SWITCH_FROM_BELOW, allowCrossUidActivitySwitchFromBelow); + + proto.write(ApplicationInfoProto.Detail.ENABLE_PAGE_SIZE_APP_COMPAT, + mPageSizeAppCompatFlags); + proto.end(detailToken); } if (!ArrayUtils.isEmpty(mKnownActivityEmbeddingCerts)) { @@ -2024,6 +2119,7 @@ public class ApplicationInfo extends PackageItemInfo implements Parcelable { localeConfigRes = orig.localeConfigRes; allowCrossUidActivitySwitchFromBelow = orig.allowCrossUidActivitySwitchFromBelow; createTimestamp = SystemClock.uptimeMillis(); + mPageSizeAppCompatFlags = orig.mPageSizeAppCompatFlags; } public String toString() { @@ -2128,6 +2224,7 @@ public class ApplicationInfo extends PackageItemInfo implements Parcelable { } dest.writeInt(localeConfigRes); dest.writeInt(allowCrossUidActivitySwitchFromBelow ? 1 : 0); + dest.writeInt(mPageSizeAppCompatFlags); sForStringSet.parcel(mKnownActivityEmbeddingCerts, dest, flags); } @@ -2228,6 +2325,7 @@ public class ApplicationInfo extends PackageItemInfo implements Parcelable { } localeConfigRes = source.readInt(); allowCrossUidActivitySwitchFromBelow = source.readInt() != 0; + mPageSizeAppCompatFlags = source.readInt(); mKnownActivityEmbeddingCerts = sForStringSet.unparcel(source); if (mKnownActivityEmbeddingCerts.isEmpty()) { @@ -2765,6 +2863,11 @@ public class ApplicationInfo extends PackageItemInfo implements Parcelable { requestRawExternalStorageAccess = value; } + /** {@hide} */ + public void setPageSizeAppCompatFlags(@PageSizeAppCompatFlags int value) { + mPageSizeAppCompatFlags |= value; + } + /** * Replaces {@link #mAppClassNamesByProcess}. This takes over the ownership of the passed map. * Do not modify the argument at the callsite. diff --git a/core/java/android/content/pm/IPackageInstaller.aidl b/core/java/android/content/pm/IPackageInstaller.aidl index 4fdbf1e9e622e41cf4c9b91322f83552fbfcab36..451c0e5e079ad0c7314c7421e61a6be182831703 100644 --- a/core/java/android/content/pm/IPackageInstaller.aidl +++ b/core/java/android/content/pm/IPackageInstaller.aidl @@ -93,10 +93,4 @@ interface IPackageInstaller { @JavaPassthrough(annotation="@android.annotation.RequiresPermission(anyOf={android.Manifest.permission.INSTALL_PACKAGES,android.Manifest.permission.REQUEST_INSTALL_PACKAGES})") void reportUnarchivalStatus(int unarchiveId, int status, long requiredStorageBytes, in PendingIntent userActionIntent, in UserHandle userHandle); - - @EnforcePermission("VERIFICATION_AGENT") - int getVerificationPolicy(int userId); - - @EnforcePermission("VERIFICATION_AGENT") - boolean setVerificationPolicy(int policy, int userId); } diff --git a/core/java/android/content/pm/IPackageManager.aidl b/core/java/android/content/pm/IPackageManager.aidl index 5d4babb8a36db116a4bfe75fbb7f10a23dfd854d..9f898b823a766f68ea1e9c12273de6697061f018 100644 --- a/core/java/android/content/pm/IPackageManager.aidl +++ b/core/java/android/content/pm/IPackageManager.aidl @@ -848,4 +848,12 @@ interface IPackageManager { int getAppMetadataSource(String packageName, int userId); ComponentName getDomainVerificationAgent(int userId); + + void setPageSizeAppCompatFlagsSettingsOverride(in String packageName, boolean enabled); + + boolean isPageSizeCompatEnabled(in String packageName); + + String getPageSizeCompatWarningMessage(in String packageName); + + List getAllApexDirectories(); } diff --git a/core/java/android/content/pm/PackageInstaller.java b/core/java/android/content/pm/PackageInstaller.java index 63279af8480d85c3b25dd155e0c7e0e590ae0af7..cd62573f6e4e114f51775696ce0720fab0eabc13 100644 --- a/core/java/android/content/pm/PackageInstaller.java +++ b/core/java/android/content/pm/PackageInstaller.java @@ -62,8 +62,6 @@ import android.content.pm.parsing.PackageLite; import android.content.pm.parsing.result.ParseResult; import android.content.pm.parsing.result.ParseTypeImpl; import android.content.pm.verify.domain.DomainSet; -import android.content.pm.verify.pkg.VerificationSession; -import android.content.pm.verify.pkg.VerificationStatus; import android.graphics.Bitmap; import android.icu.util.ULocale; import android.net.Uri; @@ -219,6 +217,17 @@ public class PackageInstaller { public static final String ACTION_CONFIRM_PRE_APPROVAL = "android.content.pm.action.CONFIRM_PRE_APPROVAL"; + /** + * Intent action to be sent to the implementer of + * {@link android.content.pm.dependencyinstaller.DependencyInstallerService}. + * + * @hide + */ + @FlaggedApi(Flags.FLAG_SDK_DEPENDENCY_INSTALLER) + @SystemApi + public static final String ACTION_INSTALL_DEPENDENCY = + "android.content.pm.action.INSTALL_DEPENDENCY"; + /** * An integer session ID that an operation is working with. * @@ -419,21 +428,6 @@ public class PackageInstaller { */ public static final String EXTRA_WARNINGS = "android.content.pm.extra.WARNINGS"; - /** - * When verification is blocked as part of the installation, additional reason for the block - * will be provided to the installer with a {@link VerificationFailedReason} as part of the - * installation result returned via the {@link IntentSender} in - * {@link Session#commit(IntentSender)}. This extra is provided only when the installation has - * failed. Installers can use this extra to check if the installation failure was caused by a - * verification failure. - * - * @hide - */ - @FlaggedApi(Flags.FLAG_VERIFICATION_SERVICE) - @SystemApi - public static final String EXTRA_VERIFICATION_FAILURE_REASON = - "android.content.pm.extra.VERIFICATION_FAILURE_REASON"; - /** * Streaming installation pending. * Caller should make sure DataLoader is able to prepare image and reinitiate the operation. @@ -777,90 +771,6 @@ public class PackageInstaller { @Retention(RetentionPolicy.SOURCE) public @interface UnarchivalStatus {} - /** - * Verification failed because of unknown reasons, such as when the verifier times out or cannot - * be connected. It can also corresponds to the status of - * {@link VerificationSession#VERIFICATION_INCOMPLETE_UNKNOWN} reported by the verifier via - * {@link VerificationSession#reportVerificationIncomplete(int)}. - * @hide - */ - @FlaggedApi(Flags.FLAG_VERIFICATION_SERVICE) - @SystemApi - public static final int VERIFICATION_FAILED_REASON_UNKNOWN = 0; - - /** - * Verification failed because the network is unavailable. This corresponds to the status of - * {@link VerificationSession#VERIFICATION_INCOMPLETE_NETWORK_UNAVAILABLE} reported by the - * verifier via {@link VerificationSession#reportVerificationIncomplete(int)}. - * - * @hide - */ - @FlaggedApi(Flags.FLAG_VERIFICATION_SERVICE) - @SystemApi - public static final int VERIFICATION_FAILED_REASON_NETWORK_UNAVAILABLE = 1; - - /** - * Verification failed because the package is blocked, as reported by the verifier via - * {@link VerificationSession#reportVerificationComplete(VerificationStatus)} or - * {@link VerificationSession#reportVerificationComplete(VerificationStatus, PersistableBundle)} - * @hide - */ - @FlaggedApi(Flags.FLAG_VERIFICATION_SERVICE) - @SystemApi - public static final int VERIFICATION_FAILED_REASON_PACKAGE_BLOCKED = 2; - - /** - * @hide - */ - @IntDef(value = { - VERIFICATION_FAILED_REASON_UNKNOWN, - VERIFICATION_FAILED_REASON_NETWORK_UNAVAILABLE, - VERIFICATION_FAILED_REASON_PACKAGE_BLOCKED, - }) - public @interface VerificationFailedReason { - } - - /** - * Do not block installs, regardless of verification status. - * @hide - */ - @FlaggedApi(Flags.FLAG_VERIFICATION_SERVICE) - @SystemApi - public static final int VERIFICATION_POLICY_NONE = 0; // platform default - /** - * Only block installations on {@link #VERIFICATION_FAILED_REASON_PACKAGE_BLOCKED}. - * @hide - */ - @FlaggedApi(Flags.FLAG_VERIFICATION_SERVICE) - @SystemApi - public static final int VERIFICATION_POLICY_BLOCK_FAIL_OPEN = 1; - /** - * Only block installations on {@link #VERIFICATION_FAILED_REASON_PACKAGE_BLOCKED} and ask the - * user if they'd like to install anyway when the verification is blocked for other reason. - * @hide - */ - @FlaggedApi(Flags.FLAG_VERIFICATION_SERVICE) - @SystemApi - public static final int VERIFICATION_POLICY_BLOCK_FAIL_WARN = 2; - /** - * Block installations whose verification status is blocked for any reason. - * @hide - */ - @FlaggedApi(Flags.FLAG_VERIFICATION_SERVICE) - @SystemApi - public static final int VERIFICATION_POLICY_BLOCK_FAIL_CLOSED = 3; - /** - * @hide - */ - @IntDef(value = { - VERIFICATION_POLICY_NONE, - VERIFICATION_POLICY_BLOCK_FAIL_OPEN, - VERIFICATION_POLICY_BLOCK_FAIL_WARN, - VERIFICATION_POLICY_BLOCK_FAIL_CLOSED, - }) - @Retention(RetentionPolicy.SOURCE) - public @interface VerificationPolicy { - } /** Default set of checksums - includes all available checksums. * @see Session#requestChecksums */ @@ -1603,40 +1513,6 @@ public class PackageInstaller { } } - /** - * Return the current verification enforcement policy. This may only be called by the - * package currently set by the system as the verifier agent. - * @hide - */ - @FlaggedApi(Flags.FLAG_VERIFICATION_SERVICE) - @SystemApi - @RequiresPermission(android.Manifest.permission.VERIFICATION_AGENT) - public final @VerificationPolicy int getVerificationPolicy() { - try { - return mInstaller.getVerificationPolicy(mUserId); - } catch (RemoteException e) { - throw e.rethrowFromSystemServer(); - } - } - - /** - * Set the current verification enforcement policy which will be applied to all the future - * installation sessions. This may only be called by the package currently set by the system as - * the verifier agent. - * @hide - * @return whether the new policy was successfully set. - */ - @FlaggedApi(Flags.FLAG_VERIFICATION_SERVICE) - @SystemApi - @RequiresPermission(android.Manifest.permission.VERIFICATION_AGENT) - public final boolean setVerificationPolicy(@VerificationPolicy int policy) { - try { - return mInstaller.setVerificationPolicy(policy, mUserId); - } catch (RemoteException e) { - throw e.rethrowFromSystemServer(); - } - } - /** * An installation that is being actively staged. For an install to succeed, * all existing and new packages must have identical package names, version @@ -2935,8 +2811,6 @@ public class PackageInstaller { /** {@hide} */ public @Nullable String dexoptCompilerFilter = null; /** {@hide} */ - public boolean forceVerification; - /** {@hide} */ public boolean isAutoInstallDependenciesEnabled = true; private final ArrayMap mPermissionStates; @@ -2992,7 +2866,6 @@ public class PackageInstaller { developmentInstallFlags = source.readInt(); unarchiveId = source.readInt(); dexoptCompilerFilter = source.readString(); - forceVerification = source.readBoolean(); isAutoInstallDependenciesEnabled = source.readBoolean(); } @@ -3030,7 +2903,6 @@ public class PackageInstaller { ret.developmentInstallFlags = developmentInstallFlags; ret.unarchiveId = unarchiveId; ret.dexoptCompilerFilter = dexoptCompilerFilter; - ret.forceVerification = forceVerification; ret.isAutoInstallDependenciesEnabled = isAutoInstallDependenciesEnabled; return ret; } @@ -3740,14 +3612,6 @@ public class PackageInstaller { return grantedPermissions.toArray(ArrayUtils.emptyArray(String.class)); } - /** - * Used by adb installations to force enable the verification for this install. - * {@hide} - */ - public void setForceVerification() { - this.forceVerification = true; - } - /** * Optionally indicate whether missing SDK or static shared library dependencies should be * automatically fetched and installed when installing an app that wants to use these @@ -3761,7 +3625,7 @@ public class PackageInstaller { * dependencies aren't already installed. */ @FlaggedApi(Flags.FLAG_SDK_DEPENDENCY_INSTALLER) - public void setEnableAutoInstallDependencies(boolean enableAutoInstallDependencies) { + public void setAutoInstallDependenciesEnabled(boolean enableAutoInstallDependencies) { isAutoInstallDependenciesEnabled = enableAutoInstallDependencies; } @@ -3800,7 +3664,6 @@ public class PackageInstaller { pw.printHexPair("developmentInstallFlags", developmentInstallFlags); pw.printPair("unarchiveId", unarchiveId); pw.printPair("dexoptCompilerFilter", dexoptCompilerFilter); - pw.printPair("forceVerification", forceVerification); pw.printPair("isAutoInstallDependenciesEnabled", isAutoInstallDependenciesEnabled); pw.println(); } @@ -3848,7 +3711,6 @@ public class PackageInstaller { dest.writeInt(developmentInstallFlags); dest.writeInt(unarchiveId); dest.writeString(dexoptCompilerFilter); - dest.writeBoolean(forceVerification); dest.writeBoolean(isAutoInstallDependenciesEnabled); } diff --git a/core/java/android/content/pm/PackageManager.java b/core/java/android/content/pm/PackageManager.java index 37295ac94823f89f11f44defb7b0dadf00e1c6d1..23d3693628e77bc8cc6f2d985f81c2daf61f6e43 100644 --- a/core/java/android/content/pm/PackageManager.java +++ b/core/java/android/content/pm/PackageManager.java @@ -804,7 +804,6 @@ public abstract class PackageManager { @Deprecated private void __metadata() {} - //@formatter:on // End of generated code @@ -3198,6 +3197,16 @@ public abstract class PackageManager { @SdkConstant(SdkConstantType.FEATURE) public static final String FEATURE_BLUETOOTH_LE = "android.hardware.bluetooth_le"; + /** + * Feature for {@link #getSystemAvailableFeatures} and + * {@link #hasSystemFeature}: The device is capable of ranging with + * other devices using channel sounding via Bluetooth Low Energy radio. + */ + @FlaggedApi(com.android.ranging.flags.Flags.FLAG_RANGING_CS_ENABLED) + @SdkConstant(SdkConstantType.FEATURE) + public static final String FEATURE_BLUETOOTH_LE_CHANNEL_SOUNDING = + "android.hardware.bluetooth_le.channel_sounding"; + /** * Feature for {@link #getSystemAvailableFeatures} and * {@link #hasSystemFeature}: The device has a camera facing away @@ -5171,25 +5180,6 @@ public abstract class PackageManager { public static final String ACTION_REQUEST_PERMISSIONS_FOR_OTHER = "android.content.pm.action.REQUEST_PERMISSIONS_FOR_OTHER"; - /** - * Used by the system to query a {@link android.content.pm.verify.pkg.VerifierService} provider, - * which registers itself via an intent-filter handling this action. - * - *

Only the system can bind to such a verifier service. This is protected by the - * {@link android.Manifest.permission#BIND_VERIFICATION_AGENT} permission. The verifier service - * app should protect the service by adding this permission in the service declaration in its - * manifest. - *

- * A verifier service must be a privileged app and hold the - * {@link android.Manifest.permission#VERIFICATION_AGENT} permission. - * - * @hide - */ - @SystemApi - @FlaggedApi(android.content.pm.Flags.FLAG_VERIFICATION_SERVICE) - @SdkConstant(SdkConstantType.SERVICE_ACTION) - public static final String ACTION_VERIFY_PACKAGE = "android.content.pm.action.VERIFY_PACKAGE"; - /** * The names of the requested permissions. *

@@ -6738,6 +6728,11 @@ public abstract class PackageManager { * If the given permission already exists, the info you supply here * will be used to update it. * + * @deprecated Support for dynamic permissions is going to be removed, and apps that use dynamic + * permissions should declare their permissions statically inside their app manifest instead. + * This method will become a no-op in a future Android release and eventually be removed from + * the SDK. + * * @param info Description of the permission to be added. * * @return Returns true if a new permission was created, false if an @@ -6748,7 +6743,9 @@ public abstract class PackageManager { * * @see #removePermission(String) */ - //@Deprecated + @SuppressWarnings("HiddenAbstractMethod") + @FlaggedApi(android.permission.flags.Flags.FLAG_PERMISSION_TREE_APIS_DEPRECATED) + @Deprecated public abstract boolean addPermission(@NonNull PermissionInfo info); /** @@ -6757,8 +6754,15 @@ public abstract class PackageManager { * allowing it to return quicker and batch a series of adds at the * expense of no guarantee the added permission will be retained if * the device is rebooted before it is written. + * + * @deprecated Support for dynamic permissions is going to be removed, and apps that use dynamic + * permissions should declare their permissions statically inside their app manifest instead. + * This method will become a no-op in a future Android release and eventually be removed from + * the SDK. */ - //@Deprecated + @SuppressWarnings("HiddenAbstractMethod") + @FlaggedApi(android.permission.flags.Flags.FLAG_PERMISSION_TREE_APIS_DEPRECATED) + @Deprecated public abstract boolean addPermissionAsync(@NonNull PermissionInfo info); /** @@ -6767,6 +6771,11 @@ public abstract class PackageManager { * -- you are only allowed to remove permissions that you are allowed * to add. * + * @deprecated Support for dynamic permissions is going to be removed, and apps that use dynamic + * permissions should declare their permissions statically inside their app manifest instead. + * This method will become a no-op in a future Android release and eventually be removed from + * the SDK. + * * @param permName The name of the permission to remove. * * @throws SecurityException if you are not allowed to remove the @@ -6774,7 +6783,9 @@ public abstract class PackageManager { * * @see #addPermission(PermissionInfo) */ - //@Deprecated + @SuppressWarnings("HiddenAbstractMethod") + @FlaggedApi(android.permission.flags.Flags.FLAG_PERMISSION_TREE_APIS_DEPRECATED) + @Deprecated public abstract void removePermission(@NonNull String permName); /** @@ -10996,6 +11007,41 @@ public abstract class PackageManager { } /** + * Set the page compat mode override for given package + * + * @hide + */ + @FlaggedApi(android.content.pm.Flags.FLAG_APP_COMPAT_OPTION_16KB) + public void setPageSizeAppCompatFlagsSettingsOverride(@NonNull String packageName, + boolean enabled) { + throw new UnsupportedOperationException( + "setPageSizeAppCompatFlagsSettingsOverride not implemented in subclass"); + } + + /** + * Check whether page size app compat mode is enabled for given package + * + * @hide + */ + @FlaggedApi(android.content.pm.Flags.FLAG_APP_COMPAT_OPTION_16KB) + public boolean isPageSizeCompatEnabled(@NonNull String packageName) { + throw new UnsupportedOperationException( + "isPageSizeCompatEnabled not implemented in subclass"); + } + + /** + * Get the page size app compat warning dialog to show at app launch time + * + * @hide + */ + @Nullable + @FlaggedApi(android.content.pm.Flags.FLAG_APP_COMPAT_OPTION_16KB) + public String getPageSizeCompatWarningMessage(@NonNull String packageName) { + throw new UnsupportedOperationException( + "getPageSizeCompatWarningMessage not implemented in subclass"); + } + + /** * Returns the harmful app warning string for the given app, or null if there is none set. * * @param packageName The full name of the desired package. diff --git a/core/java/android/content/pm/ServiceInfo.java b/core/java/android/content/pm/ServiceInfo.java index 4285b0a2b91afd5b669d4d79284cfdd6d20ebee5..8243d88e6260b61a00e047bfba4ba1b6ccece439 100644 --- a/core/java/android/content/pm/ServiceInfo.java +++ b/core/java/android/content/pm/ServiceInfo.java @@ -20,6 +20,7 @@ import android.Manifest; import android.annotation.FlaggedApi; import android.annotation.IntDef; import android.annotation.RequiresPermission; +import android.health.connect.HealthPermissions; import android.os.Parcel; import android.os.Parcelable; import android.util.Printer; @@ -361,8 +362,10 @@ public class ServiceInfo extends ComponentInfo * {@link android.Manifest.permission#FOREGROUND_SERVICE_HEALTH} and one of the following * permissions: * {@link android.Manifest.permission#ACTIVITY_RECOGNITION}, - * {@link android.Manifest.permission#BODY_SENSORS}, * {@link android.Manifest.permission#HIGH_SAMPLING_RATE_SENSORS}. + * {@link android.health.connect.HealthPermissions#READ_HEART_RATE}, + * {@link android.health.connect.HealthPermissions#READ_SKIN_TEMPERATURE}, + * {@link android.health.connect.HealthPermissions#READ_OXYGEN_SATURATION}, */ @RequiresPermission( allOf = { @@ -370,10 +373,13 @@ public class ServiceInfo extends ComponentInfo }, anyOf = { Manifest.permission.ACTIVITY_RECOGNITION, - Manifest.permission.BODY_SENSORS, Manifest.permission.HIGH_SAMPLING_RATE_SENSORS, + HealthPermissions.READ_HEART_RATE, + HealthPermissions.READ_SKIN_TEMPERATURE, + HealthPermissions.READ_OXYGEN_SATURATION, } ) + @FlaggedApi(android.permission.flags.Flags.FLAG_REPLACE_BODY_SENSOR_PERMISSION_ENABLED) public static final int FOREGROUND_SERVICE_TYPE_HEALTH = 1 << 8; /** diff --git a/core/java/android/content/pm/flags.aconfig b/core/java/android/content/pm/flags.aconfig index e181ae8ef3c7d39972a552a436eef467f6127e6b..fbe581c5d524e4d033510f0af99562621f65f29e 100644 --- a/core/java/android/content/pm/flags.aconfig +++ b/core/java/android/content/pm/flags.aconfig @@ -311,14 +311,6 @@ flag { bug: "361776825" } -flag { - name: "verification_service" - namespace: "package_manager_service" - description: "Feature flag to enable the new verification service." - bug: "360129103" - is_fixed_read_only: true -} - flag { name: "sdk_dependency_installer" is_exported: true @@ -364,7 +356,7 @@ flag { name: "support_minor_versions_in_minsdkversion" namespace: "package_manager_service" description: "Block app installations that specify an incompatible minor SDK version" - bug: "377474232" + bug: "377302905" } flag { diff --git a/core/java/android/content/pm/multiuser.aconfig b/core/java/android/content/pm/multiuser.aconfig index 813208d7ff388e52b89d472cca3edaf5f61d8216..833260a15c45d0176f22ce376dd53c936d83d65d 100644 --- a/core/java/android/content/pm/multiuser.aconfig +++ b/core/java/android/content/pm/multiuser.aconfig @@ -341,6 +341,28 @@ flag { is_fixed_read_only: true } +flag { + name: "cache_user_start_realtime_read_only" + namespace: "multiuser" + description: "Cache getUserStartRealtime to avoid unnecessary binder calls" + bug: "350416205" + metadata { + purpose: PURPOSE_BUGFIX + } + is_fixed_read_only: true +} + +flag { + name: "cache_user_unlock_realtime_read_only" + namespace: "multiuser" + description: "Cache getUserUnlockRealtime to avoid unnecessary binder calls" + bug: "350421407" + metadata { + purpose: PURPOSE_BUGFIX + } + is_fixed_read_only: true +} + # This flag guards the private space feature and all its implementations excluding the APIs. APIs are guarded by android.os.Flags.allow_private_profile. flag { name: "enable_private_space_features" diff --git a/core/java/android/content/pm/parsing/ApkLite.java b/core/java/android/content/pm/parsing/ApkLite.java index c83cf9601cd778f52181c68b645a4e5e1eb3784c..1d8209da6559e4839deac72afce7bbf809fff3d0 100644 --- a/core/java/android/content/pm/parsing/ApkLite.java +++ b/core/java/android/content/pm/parsing/ApkLite.java @@ -141,6 +141,11 @@ public class ApkLite { */ private final boolean mIsSdkLibrary; + /** + * Indicates if this apk is a static library. + */ + private final boolean mIsStaticLibrary; + /** * List of SDK names used by this apk. */ @@ -191,7 +196,7 @@ public class ApkLite { Set requiredSplitTypes, Set splitTypes, boolean hasDeviceAdminReceiver, boolean isSdkLibrary, List usesSdkLibraries, long[] usesSdkLibrariesVersionsMajor, - String[][] usesSdkLibrariesCertDigests, + String[][] usesSdkLibrariesCertDigests, boolean isStaticLibrary, List usesStaticLibraries, long[] usesStaticLibrariesVersionsMajor, String[][] usesStaticLibrariesCertDigests, boolean updatableSystem, @@ -229,6 +234,7 @@ public class ApkLite { mRollbackDataPolicy = rollbackDataPolicy; mHasDeviceAdminReceiver = hasDeviceAdminReceiver; mIsSdkLibrary = isSdkLibrary; + mIsStaticLibrary = isStaticLibrary; mUsesSdkLibraries = usesSdkLibraries; mUsesSdkLibrariesVersionsMajor = usesSdkLibrariesVersionsMajor; mUsesSdkLibrariesCertDigests = usesSdkLibrariesCertDigests; @@ -275,6 +281,7 @@ public class ApkLite { mRollbackDataPolicy = 0; mHasDeviceAdminReceiver = false; mIsSdkLibrary = false; + mIsStaticLibrary = false; mUsesSdkLibraries = Collections.emptyList(); mUsesSdkLibrariesVersionsMajor = null; mUsesSdkLibrariesCertDigests = null; @@ -593,6 +600,14 @@ public class ApkLite { return mIsSdkLibrary; } + /** + * Indicates if this apk is a static library. + */ + @DataClass.Generated.Member + public boolean isIsStaticLibrary() { + return mIsStaticLibrary; + } + /** * List of SDK names used by this apk. */ @@ -662,10 +677,10 @@ public class ApkLite { } @DataClass.Generated( - time = 1730202160705L, + time = 1731589363302L, codegenVersion = "1.0.23", sourceFile = "frameworks/base/core/java/android/content/pm/parsing/ApkLite.java", - inputSignatures = "private final @android.annotation.NonNull java.lang.String mPackageName\nprivate final @android.annotation.NonNull java.lang.String mPath\nprivate final @android.annotation.Nullable java.lang.String mSplitName\nprivate final @android.annotation.Nullable java.lang.String mUsesSplitName\nprivate final @android.annotation.Nullable java.lang.String mConfigForSplit\nprivate final @android.annotation.Nullable java.util.Set mRequiredSplitTypes\nprivate final @android.annotation.Nullable java.util.Set mSplitTypes\nprivate final int mVersionCodeMajor\nprivate final int mVersionCode\nprivate final int mRevisionCode\nprivate final int mInstallLocation\nprivate final int mMinSdkVersion\nprivate final int mTargetSdkVersion\nprivate final @android.annotation.NonNull android.content.pm.VerifierInfo[] mVerifiers\nprivate final @android.annotation.NonNull android.content.pm.SigningDetails mSigningDetails\nprivate final boolean mFeatureSplit\nprivate final boolean mIsolatedSplits\nprivate final boolean mSplitRequired\nprivate final boolean mCoreApp\nprivate final boolean mDebuggable\nprivate final boolean mProfileableByShell\nprivate final boolean mMultiArch\nprivate final boolean mUse32bitAbi\nprivate final boolean mExtractNativeLibs\nprivate final boolean mUseEmbeddedDex\nprivate final @android.annotation.Nullable java.lang.String mTargetPackageName\nprivate final boolean mOverlayIsStatic\nprivate final int mOverlayPriority\nprivate final @android.annotation.Nullable java.lang.String mRequiredSystemPropertyName\nprivate final @android.annotation.Nullable java.lang.String mRequiredSystemPropertyValue\nprivate final int mRollbackDataPolicy\nprivate final boolean mHasDeviceAdminReceiver\nprivate final boolean mIsSdkLibrary\nprivate final @android.annotation.NonNull java.util.List mUsesSdkLibraries\nprivate final @android.annotation.Nullable long[] mUsesSdkLibrariesVersionsMajor\nprivate final @android.annotation.Nullable java.lang.String[][] mUsesSdkLibrariesCertDigests\nprivate final @android.annotation.NonNull java.util.List mUsesStaticLibraries\nprivate final @android.annotation.Nullable long[] mUsesStaticLibrariesVersions\nprivate final @android.annotation.Nullable java.lang.String[][] mUsesStaticLibrariesCertDigests\nprivate final boolean mUpdatableSystem\nprivate final @android.annotation.Nullable java.lang.String mEmergencyInstaller\nprivate final @android.annotation.NonNull java.util.List mDeclaredLibraries\nprivate final @android.annotation.Nullable android.content.pm.ArchivedPackageParcel mArchivedPackage\npublic long getLongVersionCode()\nprivate boolean hasAnyRequiredSplitTypes()\nclass ApkLite extends java.lang.Object implements []\n@com.android.internal.util.DataClass(genConstructor=false, genConstDefs=false)") + inputSignatures = "private final @android.annotation.NonNull java.lang.String mPackageName\nprivate final @android.annotation.NonNull java.lang.String mPath\nprivate final @android.annotation.Nullable java.lang.String mSplitName\nprivate final @android.annotation.Nullable java.lang.String mUsesSplitName\nprivate final @android.annotation.Nullable java.lang.String mConfigForSplit\nprivate final @android.annotation.Nullable java.util.Set mRequiredSplitTypes\nprivate final @android.annotation.Nullable java.util.Set mSplitTypes\nprivate final int mVersionCodeMajor\nprivate final int mVersionCode\nprivate final int mRevisionCode\nprivate final int mInstallLocation\nprivate final int mMinSdkVersion\nprivate final int mTargetSdkVersion\nprivate final @android.annotation.NonNull android.content.pm.VerifierInfo[] mVerifiers\nprivate final @android.annotation.NonNull android.content.pm.SigningDetails mSigningDetails\nprivate final boolean mFeatureSplit\nprivate final boolean mIsolatedSplits\nprivate final boolean mSplitRequired\nprivate final boolean mCoreApp\nprivate final boolean mDebuggable\nprivate final boolean mProfileableByShell\nprivate final boolean mMultiArch\nprivate final boolean mUse32bitAbi\nprivate final boolean mExtractNativeLibs\nprivate final boolean mUseEmbeddedDex\nprivate final @android.annotation.Nullable java.lang.String mTargetPackageName\nprivate final boolean mOverlayIsStatic\nprivate final int mOverlayPriority\nprivate final @android.annotation.Nullable java.lang.String mRequiredSystemPropertyName\nprivate final @android.annotation.Nullable java.lang.String mRequiredSystemPropertyValue\nprivate final int mRollbackDataPolicy\nprivate final boolean mHasDeviceAdminReceiver\nprivate final boolean mIsSdkLibrary\nprivate final boolean mIsStaticLibrary\nprivate final @android.annotation.NonNull java.util.List mUsesSdkLibraries\nprivate final @android.annotation.Nullable long[] mUsesSdkLibrariesVersionsMajor\nprivate final @android.annotation.Nullable java.lang.String[][] mUsesSdkLibrariesCertDigests\nprivate final @android.annotation.NonNull java.util.List mUsesStaticLibraries\nprivate final @android.annotation.Nullable long[] mUsesStaticLibrariesVersions\nprivate final @android.annotation.Nullable java.lang.String[][] mUsesStaticLibrariesCertDigests\nprivate final boolean mUpdatableSystem\nprivate final @android.annotation.Nullable java.lang.String mEmergencyInstaller\nprivate final @android.annotation.NonNull java.util.List mDeclaredLibraries\nprivate final @android.annotation.Nullable android.content.pm.ArchivedPackageParcel mArchivedPackage\npublic long getLongVersionCode()\nprivate boolean hasAnyRequiredSplitTypes()\nclass ApkLite extends java.lang.Object implements []\n@com.android.internal.util.DataClass(genConstructor=false, genConstDefs=false)") @Deprecated private void __metadata() {} diff --git a/core/java/android/content/pm/parsing/ApkLiteParseUtils.java b/core/java/android/content/pm/parsing/ApkLiteParseUtils.java index 05c8f31df5d62f935ae26df0e92992a5f89122e9..18a45d8d442e0179dbb737a64bcd885e47b8052c 100644 --- a/core/java/android/content/pm/parsing/ApkLiteParseUtils.java +++ b/core/java/android/content/pm/parsing/ApkLiteParseUtils.java @@ -44,6 +44,7 @@ import android.util.Slog; import com.android.internal.pm.pkg.component.flags.Flags; import com.android.internal.util.ArrayUtils; +import com.android.internal.util.XmlUtils; import libcore.io.IoUtils; import libcore.util.HexEncoding; @@ -465,6 +466,7 @@ public class ApkLiteParseUtils { boolean hasDeviceAdminReceiver = false; boolean isSdkLibrary = false; + boolean isStaticLibrary = false; List usesSdkLibraries = new ArrayList<>(); long[] usesSdkLibrariesVersionsMajor = new long[0]; String[][] usesSdkLibrariesCertDigests = new String[0][0]; @@ -542,8 +544,13 @@ public class ApkLiteParseUtils { } String usesSdkLibName = parser.getAttributeValue( ANDROID_RES_NAMESPACE, "name"); - long usesSdkLibVersionMajor = parser.getAttributeIntValue( - ANDROID_RES_NAMESPACE, "versionMajor", -1); + // TODO(b/379219371): Due to a bug in bundletool, some apps can use + // versionMajor as string. Until it is resolved, we are adding a + // workaround here. + String usesSdkLibVersionMajorString = parser.getAttributeValue( + ANDROID_RES_NAMESPACE, "versionMajor"); + long usesSdkLibVersionMajor = XmlUtils.convertValueToInt( + usesSdkLibVersionMajorString, -1); String usesSdkCertDigest = parser.getAttributeValue( ANDROID_RES_NAMESPACE, "certDigest"); @@ -656,6 +663,7 @@ public class ApkLiteParseUtils { SharedLibraryInfo.TYPE_SDK_PACKAGE)); break; case TAG_STATIC_LIBRARY: + isStaticLibrary = true; // Mirrors ParsingPackageUtils#parseStaticLibrary until lite and full // parsing are combined String staticLibName = parser.getAttributeValue( @@ -809,7 +817,7 @@ public class ApkLiteParseUtils { requiredSystemPropertyValue, minSdkVersion, targetSdkVersion, rollbackDataPolicy, requiredSplitTypes.first, requiredSplitTypes.second, hasDeviceAdminReceiver, isSdkLibrary, usesSdkLibraries, - usesSdkLibrariesVersionsMajor, usesSdkLibrariesCertDigests, + usesSdkLibrariesVersionsMajor, usesSdkLibrariesCertDigests, isStaticLibrary, usesStaticLibraries, usesStaticLibrariesVersions, usesStaticLibrariesCertDigests, updatableSystem, emergencyInstaller, declaredLibraries)); diff --git a/core/java/android/content/pm/parsing/PackageLite.java b/core/java/android/content/pm/parsing/PackageLite.java index 76b25fed2ac29c7d2374b67d9e216982b5a02e41..0e11eecfc7ecf4f77e977dff610f7ffa5b8ae3f8 100644 --- a/core/java/android/content/pm/parsing/PackageLite.java +++ b/core/java/android/content/pm/parsing/PackageLite.java @@ -114,6 +114,10 @@ public class PackageLite { * Indicates if this package is a sdk. */ private final boolean mIsSdkLibrary; + /** + * Indicates if this package is a static library. + */ + private final boolean mIsStaticLibrary; private final @NonNull List mUsesSdkLibraries; @@ -164,6 +168,7 @@ public class PackageLite { mUsesSdkLibraries = baseApk.getUsesSdkLibraries(); mUsesSdkLibrariesVersionsMajor = baseApk.getUsesSdkLibrariesVersionsMajor(); mUsesSdkLibrariesCertDigests = baseApk.getUsesSdkLibrariesCertDigests(); + mIsStaticLibrary = baseApk.isIsStaticLibrary(); mUsesStaticLibraries = baseApk.getUsesStaticLibraries(); mUsesStaticLibrariesVersions = baseApk.getUsesStaticLibrariesVersions(); mUsesStaticLibrariesCertDigests = baseApk.getUsesStaticLibrariesCertDigests(); @@ -455,6 +460,14 @@ public class PackageLite { return mIsSdkLibrary; } + /** + * Indicates if this package is a static library. + */ + @DataClass.Generated.Member + public boolean isIsStaticLibrary() { + return mIsStaticLibrary; + } + @DataClass.Generated.Member public @NonNull List getUsesSdkLibraries() { return mUsesSdkLibraries; @@ -499,10 +512,10 @@ public class PackageLite { } @DataClass.Generated( - time = 1730203707341L, + time = 1731591578587L, codegenVersion = "1.0.23", sourceFile = "frameworks/base/core/java/android/content/pm/parsing/PackageLite.java", - inputSignatures = "private final @android.annotation.NonNull java.lang.String mPackageName\nprivate final @android.annotation.NonNull java.lang.String mPath\nprivate final @android.annotation.NonNull java.lang.String mBaseApkPath\nprivate final @android.annotation.Nullable java.lang.String[] mSplitApkPaths\nprivate final @android.annotation.Nullable java.lang.String[] mSplitNames\nprivate final @android.annotation.Nullable java.lang.String[] mUsesSplitNames\nprivate final @android.annotation.Nullable java.lang.String[] mConfigForSplit\nprivate final @android.annotation.Nullable java.util.Set mBaseRequiredSplitTypes\nprivate final @android.annotation.Nullable java.util.Set[] mRequiredSplitTypes\nprivate final @android.annotation.Nullable java.util.Set[] mSplitTypes\nprivate final int mVersionCodeMajor\nprivate final int mVersionCode\nprivate final int mTargetSdk\nprivate final int mBaseRevisionCode\nprivate final @android.annotation.Nullable int[] mSplitRevisionCodes\nprivate final int mInstallLocation\nprivate final @android.annotation.NonNull android.content.pm.VerifierInfo[] mVerifiers\nprivate final @android.annotation.NonNull android.content.pm.SigningDetails mSigningDetails\nprivate final @android.annotation.Nullable boolean[] mIsFeatureSplits\nprivate final boolean mIsolatedSplits\nprivate final boolean mSplitRequired\nprivate final boolean mCoreApp\nprivate final boolean mDebuggable\nprivate final boolean mMultiArch\nprivate final boolean mUse32bitAbi\nprivate final boolean mExtractNativeLibs\nprivate final boolean mProfileableByShell\nprivate final boolean mUseEmbeddedDex\nprivate final boolean mIsSdkLibrary\nprivate final @android.annotation.NonNull java.util.List mUsesSdkLibraries\nprivate final @android.annotation.Nullable long[] mUsesSdkLibrariesVersionsMajor\nprivate final @android.annotation.Nullable java.lang.String[][] mUsesSdkLibrariesCertDigests\nprivate final @android.annotation.NonNull java.util.List mUsesStaticLibraries\nprivate final @android.annotation.Nullable long[] mUsesStaticLibrariesVersions\nprivate final @android.annotation.Nullable java.lang.String[][] mUsesStaticLibrariesCertDigests\nprivate final @android.annotation.NonNull java.util.List mDeclaredLibraries\nprivate final @android.annotation.Nullable android.content.pm.ArchivedPackageParcel mArchivedPackage\npublic java.util.List getAllApkPaths()\npublic long getLongVersionCode()\nprivate boolean hasAnyRequiredSplitTypes()\nclass PackageLite extends java.lang.Object implements []\n@com.android.internal.util.DataClass(genConstructor=false, genConstDefs=false)") + inputSignatures = "private final @android.annotation.NonNull java.lang.String mPackageName\nprivate final @android.annotation.NonNull java.lang.String mPath\nprivate final @android.annotation.NonNull java.lang.String mBaseApkPath\nprivate final @android.annotation.Nullable java.lang.String[] mSplitApkPaths\nprivate final @android.annotation.Nullable java.lang.String[] mSplitNames\nprivate final @android.annotation.Nullable java.lang.String[] mUsesSplitNames\nprivate final @android.annotation.Nullable java.lang.String[] mConfigForSplit\nprivate final @android.annotation.Nullable java.util.Set mBaseRequiredSplitTypes\nprivate final @android.annotation.Nullable java.util.Set[] mRequiredSplitTypes\nprivate final @android.annotation.Nullable java.util.Set[] mSplitTypes\nprivate final int mVersionCodeMajor\nprivate final int mVersionCode\nprivate final int mTargetSdk\nprivate final int mBaseRevisionCode\nprivate final @android.annotation.Nullable int[] mSplitRevisionCodes\nprivate final int mInstallLocation\nprivate final @android.annotation.NonNull android.content.pm.VerifierInfo[] mVerifiers\nprivate final @android.annotation.NonNull android.content.pm.SigningDetails mSigningDetails\nprivate final @android.annotation.Nullable boolean[] mIsFeatureSplits\nprivate final boolean mIsolatedSplits\nprivate final boolean mSplitRequired\nprivate final boolean mCoreApp\nprivate final boolean mDebuggable\nprivate final boolean mMultiArch\nprivate final boolean mUse32bitAbi\nprivate final boolean mExtractNativeLibs\nprivate final boolean mProfileableByShell\nprivate final boolean mUseEmbeddedDex\nprivate final boolean mIsSdkLibrary\nprivate final boolean mIsStaticLibrary\nprivate final @android.annotation.NonNull java.util.List mUsesSdkLibraries\nprivate final @android.annotation.Nullable long[] mUsesSdkLibrariesVersionsMajor\nprivate final @android.annotation.Nullable java.lang.String[][] mUsesSdkLibrariesCertDigests\nprivate final @android.annotation.NonNull java.util.List mUsesStaticLibraries\nprivate final @android.annotation.Nullable long[] mUsesStaticLibrariesVersions\nprivate final @android.annotation.Nullable java.lang.String[][] mUsesStaticLibrariesCertDigests\nprivate final @android.annotation.NonNull java.util.List mDeclaredLibraries\nprivate final @android.annotation.Nullable android.content.pm.ArchivedPackageParcel mArchivedPackage\npublic java.util.List getAllApkPaths()\npublic long getLongVersionCode()\nprivate boolean hasAnyRequiredSplitTypes()\nclass PackageLite extends java.lang.Object implements []\n@com.android.internal.util.DataClass(genConstructor=false, genConstDefs=false)") @Deprecated private void __metadata() {} diff --git a/core/java/android/content/pm/verify/pkg/IVerificationSessionInterface.aidl b/core/java/android/content/pm/verify/pkg/IVerificationSessionInterface.aidl deleted file mode 100644 index 2ab745205193d7f686ba483d9f227c1ee6a619d1..0000000000000000000000000000000000000000 --- a/core/java/android/content/pm/verify/pkg/IVerificationSessionInterface.aidl +++ /dev/null @@ -1,32 +0,0 @@ -/* - * 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.content.pm.verify.pkg; - -import android.content.pm.verify.pkg.VerificationStatus; -import android.os.PersistableBundle; - -/** - * Non-oneway interface that allows the verifier to communicate with the system. - * @hide - */ -interface IVerificationSessionInterface { - long getTimeoutTime(int verificationId); - long extendTimeRemaining(int verificationId, long additionalMs); - boolean setVerificationPolicy(int verificationId, int policy); - void reportVerificationIncomplete(int verificationId, int reason); - void reportVerificationComplete(int verificationId, in VerificationStatus status, in @nullable PersistableBundle extensionResponse); -} \ No newline at end of file diff --git a/core/java/android/content/pm/verify/pkg/VerificationSession.java b/core/java/android/content/pm/verify/pkg/VerificationSession.java deleted file mode 100644 index 97f78e0978fa42b6b0707b288678ff838898f31d..0000000000000000000000000000000000000000 --- a/core/java/android/content/pm/verify/pkg/VerificationSession.java +++ /dev/null @@ -1,311 +0,0 @@ -/* - * 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.content.pm.verify.pkg; - -import android.annotation.FlaggedApi; -import android.annotation.IntDef; -import android.annotation.NonNull; -import android.annotation.SystemApi; -import android.content.pm.Flags; -import android.content.pm.PackageInstaller; -import android.content.pm.SharedLibraryInfo; -import android.content.pm.SigningInfo; -import android.net.Uri; -import android.os.Parcel; -import android.os.Parcelable; -import android.os.PersistableBundle; -import android.os.RemoteException; - -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; -import java.util.Collections; -import java.util.List; - -/** - * This class is used by the system to describe the details about a verification request sent to the - * verification agent, aka the verifier. It includes the interfaces for the verifier to communicate - * back to the system. - * @hide - */ -@FlaggedApi(Flags.FLAG_VERIFICATION_SERVICE) -@SystemApi -public final class VerificationSession implements Parcelable { - /** - * The verification cannot be completed because of unknown reasons. - */ - public static final int VERIFICATION_INCOMPLETE_UNKNOWN = 0; - /** - * The verification cannot be completed because the network is unavailable. - */ - public static final int VERIFICATION_INCOMPLETE_NETWORK_UNAVAILABLE = 1; - - /** - * @hide - */ - @IntDef(prefix = {"VERIFICATION_INCOMPLETE_"}, value = { - VERIFICATION_INCOMPLETE_NETWORK_UNAVAILABLE, - VERIFICATION_INCOMPLETE_UNKNOWN, - }) - @Retention(RetentionPolicy.SOURCE) - public @interface VerificationIncompleteReason { - } - - private final int mId; - private final int mInstallSessionId; - @NonNull - private final String mPackageName; - @NonNull - private final Uri mStagedPackageUri; - @NonNull - private final SigningInfo mSigningInfo; - @NonNull - private final List mDeclaredLibraries; - @NonNull - private final PersistableBundle mExtensionParams; - @NonNull - private final IVerificationSessionInterface mSession; - /** - * The current policy that is active for the session. It might not be - * the same as the original policy that was initially assigned for this verification session, - * because the active policy can be overridden by {@link #setVerificationPolicy(int)}. - *

To improve the latency, store the original policy value and any changes made to it, - * so that {@link #getVerificationPolicy()} does not need to make a binder call to retrieve the - * currently active policy.

- */ - private volatile @PackageInstaller.VerificationPolicy int mVerificationPolicy; - - /** - * Constructor used by the system to describe the details of a verification session. - * @hide - */ - public VerificationSession(int id, int installSessionId, @NonNull String packageName, - @NonNull Uri stagedPackageUri, @NonNull SigningInfo signingInfo, - @NonNull List declaredLibraries, - @NonNull PersistableBundle extensionParams, - @PackageInstaller.VerificationPolicy int defaultPolicy, - @NonNull IVerificationSessionInterface session) { - mId = id; - mInstallSessionId = installSessionId; - mPackageName = packageName; - mStagedPackageUri = stagedPackageUri; - mSigningInfo = signingInfo; - mDeclaredLibraries = declaredLibraries; - mExtensionParams = extensionParams; - mVerificationPolicy = defaultPolicy; - mSession = session; - } - - /** - * A unique identifier tied to this specific verification session. - */ - public int getId() { - return mId; - } - - /** - * The package name of the app that is to be verified. - */ - public @NonNull String getPackageName() { - return mPackageName; - } - - /** - * The id of the installation session associated with the verification. - */ - public int getInstallSessionId() { - return mInstallSessionId; - } - - /** - * The Uri of the path where the package's code files are located. - */ - public @NonNull Uri getStagedPackageUri() { - return mStagedPackageUri; - } - - /** - * Signing info of the package to be verified. - */ - public @NonNull SigningInfo getSigningInfo() { - return mSigningInfo; - } - - /** - * Returns a mapping of any shared libraries declared in the manifest - * to the {@link SharedLibraryInfo.Type} that is declared. This will be an empty - * map if no shared libraries are declared by the package. - */ - @NonNull - public List getDeclaredLibraries() { - return Collections.unmodifiableList(mDeclaredLibraries); - } - - /** - * Returns any extension params associated with the verification request. - */ - @NonNull - public PersistableBundle getExtensionParams() { - return mExtensionParams; - } - - /** - * Get the value of Clock.elapsedRealtime() at which time this verification - * will timeout as incomplete if no other verification response is provided. - * @throws SecurityException if the caller is not the current verifier bound by the system. - */ - public long getTimeoutTime() { - try { - return mSession.getTimeoutTime(mId); - } catch (RemoteException e) { - throw e.rethrowFromSystemServer(); - } - } - - /** - * Return the current policy that is active for this session. - *

If the policy for this session has been changed by {@link #setVerificationPolicy}, - * the return value of this method is the current policy that is active for this session. - * Otherwise, the return value is the same as the initial policy that was assigned to the - * session when it was first created.

- */ - public @PackageInstaller.VerificationPolicy int getVerificationPolicy() { - return mVerificationPolicy; - } - - /** - * Override the verification policy for this session. - * @return True if the override was successful, False otherwise. - * @throws SecurityException if the caller is not the current verifier bound by the system. - */ - public boolean setVerificationPolicy(@PackageInstaller.VerificationPolicy int policy) { - if (mVerificationPolicy == policy) { - // No effective policy change - return true; - } - try { - if (mSession.setVerificationPolicy(mId, policy)) { - mVerificationPolicy = policy; - return true; - } else { - return false; - } - } catch (RemoteException e) { - throw e.rethrowFromSystemServer(); - } - } - - /** - * Extend the timeout for this session by the provided additionalMs to - * fetch relevant information over the network or wait for the network. - * This may be called multiple times. If the request would bypass any max - * duration by the system, the method will return a lower value than the - * requested amount that indicates how much the time was extended. - * @throws SecurityException if the caller is not the current verifier bound by the system. - */ - public long extendTimeRemaining(long additionalMs) { - try { - return mSession.extendTimeRemaining(mId, additionalMs); - } catch (RemoteException e) { - throw e.rethrowFromSystemServer(); - } - } - - /** - * Report to the system that verification could not be completed along - * with an approximate reason to pass on to the installer.] - * @throws SecurityException if the caller is not the current verifier bound by the system. - */ - public void reportVerificationIncomplete(@VerificationIncompleteReason int reason) { - try { - mSession.reportVerificationIncomplete(mId, reason); - } catch (RemoteException e) { - throw e.rethrowFromSystemServer(); - } - } - - /** - * Report to the system that the verification has completed and the - * install process may act on that status to either block in the case - * of failure or continue to process the install in the case of success. - * @throws SecurityException if the caller is not the current verifier bound by the system. - */ - public void reportVerificationComplete(@NonNull VerificationStatus status) { - try { - mSession.reportVerificationComplete(mId, status, /* extensionResponse= */ null); - } catch (RemoteException e) { - throw e.rethrowFromSystemServer(); - } - } - - /** - * Same as {@link #reportVerificationComplete(VerificationStatus)}, but also provide - * a result to the extension params provided in the request, which will be passed to the - * installer in the installation result. - * @throws SecurityException if the caller is not the current verifier bound by the system. - */ - public void reportVerificationComplete(@NonNull VerificationStatus status, - @NonNull PersistableBundle extensionResponse) { - try { - mSession.reportVerificationComplete(mId, status, extensionResponse); - } catch (RemoteException e) { - throw e.rethrowFromSystemServer(); - } - } - - private VerificationSession(@NonNull Parcel in) { - mId = in.readInt(); - mInstallSessionId = in.readInt(); - mPackageName = in.readString8(); - mStagedPackageUri = Uri.CREATOR.createFromParcel(in); - mSigningInfo = SigningInfo.CREATOR.createFromParcel(in); - mDeclaredLibraries = in.createTypedArrayList(SharedLibraryInfo.CREATOR); - mExtensionParams = in.readPersistableBundle(getClass().getClassLoader()); - mVerificationPolicy = in.readInt(); - mSession = IVerificationSessionInterface.Stub.asInterface(in.readStrongBinder()); - } - - @Override - public int describeContents() { - return 0; - } - - @Override - public void writeToParcel(@NonNull Parcel dest, int flags) { - dest.writeInt(mId); - dest.writeInt(mInstallSessionId); - dest.writeString8(mPackageName); - Uri.writeToParcel(dest, mStagedPackageUri); - mSigningInfo.writeToParcel(dest, flags); - dest.writeTypedList(mDeclaredLibraries); - dest.writePersistableBundle(mExtensionParams); - dest.writeInt(mVerificationPolicy); - dest.writeStrongBinder(mSession.asBinder()); - } - - @NonNull - public static final Creator CREATOR = new Creator<>() { - @Override - public VerificationSession createFromParcel(@NonNull Parcel in) { - return new VerificationSession(in); - } - - @Override - public VerificationSession[] newArray(int size) { - return new VerificationSession[size]; - } - }; -} diff --git a/core/java/android/content/pm/verify/pkg/VerificationStatus.java b/core/java/android/content/pm/verify/pkg/VerificationStatus.java deleted file mode 100644 index 4d0379d7977330c80d81856ba89904f6b9b1c615..0000000000000000000000000000000000000000 --- a/core/java/android/content/pm/verify/pkg/VerificationStatus.java +++ /dev/null @@ -1,166 +0,0 @@ -/* - * 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.content.pm.verify.pkg; - -import android.annotation.FlaggedApi; -import android.annotation.IntDef; -import android.annotation.NonNull; -import android.annotation.SystemApi; -import android.content.pm.Flags; -import android.os.Parcel; -import android.os.Parcelable; - -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; - -/** - * This class is used by the verifier to describe the status of the verification request, whether - * it's successful or it has failed along with any relevant details. - * @hide - */ -@SystemApi -@FlaggedApi(Flags.FLAG_VERIFICATION_SERVICE) -public final class VerificationStatus implements Parcelable { - /** - * The ASL status has not been determined. This happens in situations where the verification - * service is not monitoring ASLs, and means the ASL data in the app is not necessarily bad but - * can't be trusted. - */ - public static final int VERIFIER_STATUS_ASL_UNDEFINED = 0; - - /** - * The app's ASL data is considered to be in a good state. - */ - public static final int VERIFIER_STATUS_ASL_GOOD = 1; - - /** - * There is something bad in the app's ASL data; the user should be warned about this when shown - * the ASL data and/or appropriate decisions made about the use of this data by the platform. - */ - public static final int VERIFIER_STATUS_ASL_BAD = 2; - - /** @hide */ - @IntDef(prefix = {"VERIFIER_STATUS_ASL_"}, value = { - VERIFIER_STATUS_ASL_UNDEFINED, - VERIFIER_STATUS_ASL_GOOD, - VERIFIER_STATUS_ASL_BAD, - }) - @Retention(RetentionPolicy.SOURCE) - public @interface VerifierStatusAsl {} - - private boolean mIsVerified; - private @VerifierStatusAsl int mAslStatus; - @NonNull - private String mFailuresMessage = ""; - - private VerificationStatus() {} - - /** - * @return whether the status is set to verified or not. - */ - public boolean isVerified() { - return mIsVerified; - } - - /** - * @return the failure message associated with the failure status. - */ - @NonNull - public String getFailureMessage() { - return mFailuresMessage; - } - - /** - * @return the asl status. - */ - public @VerifierStatusAsl int getAslStatus() { - return mAslStatus; - } - - /** - * Builder to construct a {@link VerificationStatus} object. - */ - public static final class Builder { - final VerificationStatus mStatus = new VerificationStatus(); - - /** - * Set in the status whether the verification has succeeded or failed. - */ - @NonNull - public Builder setVerified(boolean verified) { - mStatus.mIsVerified = verified; - return this; - } - - /** - * Set a developer-facing failure message to include in the verification failure status. - */ - @NonNull - public Builder setFailureMessage(@NonNull String failureMessage) { - mStatus.mFailuresMessage = failureMessage; - return this; - } - - /** - * Set the ASL status, as defined in {@link VerifierStatusAsl}. - */ - @NonNull - public Builder setAslStatus(@VerifierStatusAsl int aslStatus) { - mStatus.mAslStatus = aslStatus; - return this; - } - - /** - * Build the status object. - */ - @NonNull - public VerificationStatus build() { - return mStatus; - } - } - - private VerificationStatus(Parcel in) { - mIsVerified = in.readBoolean(); - mAslStatus = in.readInt(); - mFailuresMessage = in.readString8(); - } - - @Override - public void writeToParcel(@NonNull Parcel dest, int flags) { - dest.writeBoolean(mIsVerified); - dest.writeInt(mAslStatus); - dest.writeString8(mFailuresMessage); - } - - @Override - public int describeContents() { - return 0; - } - - @NonNull - public static final Creator CREATOR = new Creator<>() { - @Override - public VerificationStatus createFromParcel(@NonNull Parcel in) { - return new VerificationStatus(in); - } - - @Override - public VerificationStatus[] newArray(int size) { - return new VerificationStatus[size]; - } - }; -} diff --git a/core/java/android/content/pm/verify/pkg/VerifierService.java b/core/java/android/content/pm/verify/pkg/VerifierService.java deleted file mode 100644 index ccf211915326086552061a9a2e5f06170d095841..0000000000000000000000000000000000000000 --- a/core/java/android/content/pm/verify/pkg/VerifierService.java +++ /dev/null @@ -1,113 +0,0 @@ -/* - * 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.content.pm.verify.pkg; - -import android.annotation.FlaggedApi; -import android.annotation.NonNull; -import android.annotation.Nullable; -import android.annotation.SystemApi; -import android.app.Service; -import android.content.Intent; -import android.content.pm.Flags; -import android.content.pm.PackageManager; -import android.os.IBinder; - -/** - * A base service implementation for the verifier agent to implement. - * - * @hide - */ -@SystemApi -@FlaggedApi(Flags.FLAG_VERIFICATION_SERVICE) -public abstract class VerifierService extends Service { - /** - * Called when a package name is available for a pending verification, - * giving the verifier opportunity to pre-fetch any relevant information - * that may be needed should a verification for the package be required. - */ - public abstract void onPackageNameAvailable(@NonNull String packageName); - - /** - * Called when a package recently provided via {@link #onPackageNameAvailable} - * is no longer expected to be installed. This is a hint that any pre-fetch or - * cache created as a result of the previous call may be be cleared. - *

This method will never be called after {@link #onVerificationRequired} is called for the - * same package. Once a verification is officially requested by - * {@link #onVerificationRequired}, it cannot be cancelled. - *

- */ - public abstract void onVerificationCancelled(@NonNull String packageName); - - /** - * Called when an application needs to be verified. Details about the - * verification and actions that can be taken on it will be encapsulated in - * the provided {@link VerificationSession} parameter. - */ - public abstract void onVerificationRequired(@NonNull VerificationSession session); - - /** - * Called when a verification needs to be retried. This can be encountered - * when a prior verification was marked incomplete and the user has indicated - * that they've resolved the issue, or when a timeout is reached, but the - * the system is attempting to retry. Details about the - * verification and actions that can be taken on it will be encapsulated in - * the provided {@link VerificationSession} parameter. - */ - public abstract void onVerificationRetry(@NonNull VerificationSession session); - - /** - * Called in the case that an active verification has failed. Any APIs called - * on the {@link VerificationSession} instance associated with this {@code verificationId} will - * throw an {@link IllegalStateException}. - */ - public abstract void onVerificationTimeout(int verificationId); - - /** - * Called when the verifier service is bound to the system. - */ - public @Nullable IBinder onBind(@Nullable Intent intent) { - if (intent == null || !PackageManager.ACTION_VERIFY_PACKAGE.equals(intent.getAction())) { - return null; - } - return new IVerifierService.Stub() { - @Override - public void onPackageNameAvailable(@NonNull String packageName) { - VerifierService.this.onPackageNameAvailable(packageName); - } - - @Override - public void onVerificationCancelled(@NonNull String packageName) { - VerifierService.this.onVerificationCancelled(packageName); - } - - @Override - public void onVerificationRequired(@NonNull VerificationSession session) { - VerifierService.this.onVerificationRequired(session); - } - - @Override - public void onVerificationRetry(@NonNull VerificationSession session) { - VerifierService.this.onVerificationRetry(session); - } - - @Override - public void onVerificationTimeout(int verificationId) { - VerifierService.this.onVerificationTimeout(verificationId); - } - }; - } -} diff --git a/core/java/android/content/res/AssetManager.java b/core/java/android/content/res/AssetManager.java index 4551bd52c960827a9e1a6ecc05e42a61b54cde79..bbfae8117b163696f404234ca333151e8c3c07ae 100644 --- a/core/java/android/content/res/AssetManager.java +++ b/core/java/android/content/res/AssetManager.java @@ -75,7 +75,10 @@ public final class AssetManager implements AutoCloseable { private static final String TAG = "AssetManager"; private static final boolean DEBUG_REFS = false; - private static final String FRAMEWORK_APK_PATH = getFrameworkApkPath(); + /** + * @hide + */ + public static final String FRAMEWORK_APK_PATH = getFrameworkApkPath(); private static final String FRAMEWORK_APK_PATH_DEVICE = "/system/framework/framework-res.apk"; private static final String FRAMEWORK_APK_PATH_RAVENWOOD = "ravenwood-data/framework-res.apk"; diff --git a/core/java/android/content/res/flags.aconfig b/core/java/android/content/res/flags.aconfig index f23c193e2da047cc7a1fb2681f65a80bafdf9961..6fc7d90a8237a38162bb791c5fbbe4004f3f2ead 100644 --- a/core/java/android/content/res/flags.aconfig +++ b/core/java/android/content/res/flags.aconfig @@ -105,3 +105,12 @@ flag { # This flag is used to control aapt2 behavior. is_fixed_read_only: true } + +flag { + name: "resources_minor_version_support" + is_exported: true + namespace: "resource_manager" + description: "Feature flag for supporting minor version in Resources" + bug: "373535266" + is_fixed_read_only: true +} diff --git a/core/java/android/content/res/loader/ResourcesProvider.java b/core/java/android/content/res/loader/ResourcesProvider.java index b097bc0dcd8cfd1a4fbdc2550da369214f248029..830b7e0fa2d011ff6734a39b9dfb8b1b981d06d9 100644 --- a/core/java/android/content/res/loader/ResourcesProvider.java +++ b/core/java/android/content/res/loader/ResourcesProvider.java @@ -90,8 +90,6 @@ public class ResourcesProvider implements AutoCloseable, Closeable { throws IOException { Objects.requireNonNull(overlayInfo); Preconditions.checkArgument(overlayInfo.isFabricated(), "Not accepted overlay"); - Preconditions.checkStringNotEmpty( - overlayInfo.getTargetOverlayableName(), "Without overlayable name"); final String overlayName = OverlayManagerImpl.checkOverlayNameValid(overlayInfo.getOverlayName()); final String path = diff --git a/core/java/android/hardware/DisplayLuts.java b/core/java/android/hardware/DisplayLuts.java index 6343ba19f56904f50b6b4a8a16ede78b73a763f6..0abb30f8c24d4be2e71090970ec171341e6be2d9 100644 --- a/core/java/android/hardware/DisplayLuts.java +++ b/core/java/android/hardware/DisplayLuts.java @@ -177,6 +177,8 @@ public final class DisplayLuts { return "SAMPLING_KEY_RGB"; case LutProperties.SAMPLING_KEY_MAX_RGB: return "SAMPLING_KEY_MAX_RGB"; + case LutProperties.SAMPLING_KEY_CIE_Y: + return "SAMPLING_KEY_CIE_Y"; default: return ""; } diff --git a/core/java/android/hardware/LutProperties.java b/core/java/android/hardware/LutProperties.java index bf40a415b0f785f5d913af0d6cd452d09aa25fe4..abb303adac158db221f3a24351bc406b1c962128 100644 --- a/core/java/android/hardware/LutProperties.java +++ b/core/java/android/hardware/LutProperties.java @@ -44,7 +44,8 @@ public final class LutProperties { @Retention(RetentionPolicy.SOURCE) @IntDef(prefix = {"SAMPLING_KEY_"}, value = { SAMPLING_KEY_RGB, - SAMPLING_KEY_MAX_RGB + SAMPLING_KEY_MAX_RGB, + SAMPLING_KEY_CIE_Y }) public @interface SamplingKey { } @@ -57,6 +58,10 @@ public final class LutProperties { @FlaggedApi(Flags.FLAG_LUTS_API) public static final int SAMPLING_KEY_MAX_RGB = 1; + /** use y of CIE XYZ as the gain value of a lut */ + @FlaggedApi(Flags.FLAG_LUTS_API) + public static final int SAMPLING_KEY_CIE_Y = 2; + /** @hide */ @Retention(RetentionPolicy.SOURCE) @IntDef(value = { diff --git a/core/java/android/hardware/camera2/CameraExtensionCharacteristics.java b/core/java/android/hardware/camera2/CameraExtensionCharacteristics.java index 3cf508a6db00f260fac12b8f0ab2d85edf6dca42..58fe4774f17884e78d77241e97ff1e51f662d2c8 100644 --- a/core/java/android/hardware/camera2/CameraExtensionCharacteristics.java +++ b/core/java/android/hardware/camera2/CameraExtensionCharacteristics.java @@ -1066,6 +1066,7 @@ public final class CameraExtensionCharacteristics { case ImageFormat.YUV_420_888: case ImageFormat.JPEG: case ImageFormat.JPEG_R: + case ImageFormat.DEPTH_JPEG: case ImageFormat.YCBCR_P010: break; default: @@ -1096,9 +1097,10 @@ public final class CameraExtensionCharacteristics { // processed YUV_420 buffers. return getSupportedSizes( extenders.second.getSupportedPostviewResolutions(sz), format); - } else if (format == ImageFormat.JPEG_R || format == ImageFormat.YCBCR_P010) { - // Jpeg_R/UltraHDR + YCBCR_P010 is currently not supported in the basic - // extension case + } else if (format == ImageFormat.JPEG_R || format == ImageFormat.YCBCR_P010 || + (Flags.depthJpegExtensions() && (format == ImageFormat.DEPTH_JPEG))) { + // DepthJpeg/Jpeg_R/UltraHDR + YCBCR_P010 is currently not supported in the + // basic extension case return new ArrayList<>(); } else { throw new IllegalArgumentException("Unsupported format: " + format); @@ -1194,8 +1196,8 @@ public final class CameraExtensionCharacteristics { * *

Device-specific extensions currently support at most three * multi-frame capture surface formats. ImageFormat.JPEG will be supported by all - * extensions while ImageFormat.YUV_420_888, ImageFormat.JPEG_R, or ImageFormat.YCBCR_P010 - * may or may not be supported.

+ * extensions while ImageFormat.YUV_420_888, ImageFormat.JPEG_R, ImageFormat.YCBCR_P010 or + * ImageFormat.DEPTH_JPEG may or may not be supported.

* * @param extension the extension type * @param format device-specific extension output format @@ -1203,7 +1205,8 @@ public final class CameraExtensionCharacteristics { * supported. * @throws IllegalArgumentException in case of format different from ImageFormat.JPEG, * ImageFormat.YUV_420_888, ImageFormat.JPEG_R, - * ImageFormat.YCBCR_P010; or unsupported extension. + * ImageFormat.DEPTH_JPEG, ImageFormat.YCBCR_P010; or + * unsupported extension. */ public @NonNull List getExtensionSupportedSizes(@Extension int extension, int format) { @@ -1227,6 +1230,7 @@ public final class CameraExtensionCharacteristics { case ImageFormat.YUV_420_888: case ImageFormat.JPEG: case ImageFormat.JPEG_R: + case ImageFormat.DEPTH_JPEG: case ImageFormat.YCBCR_P010: break; default: @@ -1260,8 +1264,9 @@ public final class CameraExtensionCharacteristics { } else { return generateSupportedSizes(null, format, streamMap); } - } else if (format == ImageFormat.JPEG_R || format == ImageFormat.YCBCR_P010) { - // Jpeg_R/UltraHDR + YCBCR_P010 is currently not supported in the + } else if (format == ImageFormat.JPEG_R || format == ImageFormat.YCBCR_P010 || + (Flags.depthJpegExtensions() && (format == ImageFormat.DEPTH_JPEG))) { + // DepthJpeg/Jpeg_R/UltraHDR + YCBCR_P010 is currently not supported in the // basic extension case return new ArrayList<>(); } else { @@ -1292,7 +1297,8 @@ public final class CameraExtensionCharacteristics { * or null if no capture latency info can be provided * @throws IllegalArgumentException in case of format different from {@link ImageFormat#JPEG}, * {@link ImageFormat#YUV_420_888}, {@link ImageFormat#JPEG_R} - * {@link ImageFormat#YCBCR_P010}; + * {@link ImageFormat#YCBCR_P010}, + * {@link ImageFormat#DEPTH_JPEG}; * or unsupported extension. */ public @Nullable Range getEstimatedCaptureLatencyRangeMillis(@Extension int extension, @@ -1301,6 +1307,7 @@ public final class CameraExtensionCharacteristics { case ImageFormat.YUV_420_888: case ImageFormat.JPEG: case ImageFormat.JPEG_R: + case ImageFormat.DEPTH_JPEG: case ImageFormat.YCBCR_P010: //No op break; @@ -1349,8 +1356,9 @@ public final class CameraExtensionCharacteristics { // specific and cannot be estimated accurately enough. return null; } - if (format == ImageFormat.JPEG_R || format == ImageFormat.YCBCR_P010) { - // JpegR/UltraHDR + YCBCR_P010 is not supported for basic extensions + if (format == ImageFormat.JPEG_R || format == ImageFormat.YCBCR_P010 || + (Flags.depthJpegExtensions() && (format == ImageFormat.DEPTH_JPEG))) { + // DepthJpeg/JpegR/UltraHDR + YCBCR_P010 is not supported for basic extensions return null; } diff --git a/core/java/android/hardware/camera2/impl/CameraAdvancedExtensionSessionImpl.java b/core/java/android/hardware/camera2/impl/CameraAdvancedExtensionSessionImpl.java index fc03b517e6d42b9283659456e6a60c17c0c2b524..d511e9f64c1702d0d5ec36b58bd88edcd04d554b 100644 --- a/core/java/android/hardware/camera2/impl/CameraAdvancedExtensionSessionImpl.java +++ b/core/java/android/hardware/camera2/impl/CameraAdvancedExtensionSessionImpl.java @@ -186,12 +186,12 @@ public final class CameraAdvancedExtensionSessionImpl extends CameraExtensionSes HashMap> supportedCaptureSizes = new HashMap<>(); - IntArray supportedCaptureOutputFormats = - new IntArray(CameraExtensionUtils.SUPPORTED_CAPTURE_OUTPUT_FORMATS.length); - supportedCaptureOutputFormats.addAll( - CameraExtensionUtils.SUPPORTED_CAPTURE_OUTPUT_FORMATS); - supportedCaptureOutputFormats.add(ImageFormat.YCBCR_P010); - for (int format : supportedCaptureOutputFormats.toArray()) { + Integer[] supportedCaptureOutputFormats = + new Integer[CameraExtensionUtils.SUPPORTED_CAPTURE_OUTPUT_FORMATS.size()]; + supportedCaptureOutputFormats = + CameraExtensionUtils.SUPPORTED_CAPTURE_OUTPUT_FORMATS.toArray( + supportedCaptureOutputFormats); + for (int format : supportedCaptureOutputFormats) { List supportedSizes = extensionChars.getExtensionSupportedSizes( config.getExtension(), format); if (supportedSizes != null) { @@ -230,7 +230,7 @@ public final class CameraAdvancedExtensionSessionImpl extends CameraExtensionSes Size burstCaptureSurfaceSize = new Size(burstCaptureSurfaceInfo.mWidth, burstCaptureSurfaceInfo.mHeight); HashMap> supportedPostviewSizes = new HashMap<>(); - for (int format : supportedCaptureOutputFormats.toArray()) { + for (int format : supportedCaptureOutputFormats) { List supportedSizesPostview = extensionChars.getPostviewSupportedSizes( config.getExtension(), burstCaptureSurfaceSize, format); if (supportedSizesPostview != null) { diff --git a/core/java/android/hardware/camera2/impl/CameraExtensionSessionImpl.java b/core/java/android/hardware/camera2/impl/CameraExtensionSessionImpl.java index ce1609dec4e6affb5044200f4f5f71d842f1bcd9..ed73e624e242b1a6dd074d4dbd9e4ebf80dd37fd 100644 --- a/core/java/android/hardware/camera2/impl/CameraExtensionSessionImpl.java +++ b/core/java/android/hardware/camera2/impl/CameraExtensionSessionImpl.java @@ -186,12 +186,12 @@ public final class CameraExtensionSessionImpl extends CameraExtensionSession { } HashMap> supportedCaptureSizes = new HashMap<>(); - IntArray supportedCaptureOutputFormats = - new IntArray(CameraExtensionUtils.SUPPORTED_CAPTURE_OUTPUT_FORMATS.length); - supportedCaptureOutputFormats.addAll( - CameraExtensionUtils.SUPPORTED_CAPTURE_OUTPUT_FORMATS); - supportedCaptureOutputFormats.add(ImageFormat.YCBCR_P010); - for (int format : supportedCaptureOutputFormats.toArray()) { + Integer[] supportedCaptureOutputFormats = + new Integer[CameraExtensionUtils.SUPPORTED_CAPTURE_OUTPUT_FORMATS.size()]; + supportedCaptureOutputFormats = + CameraExtensionUtils.SUPPORTED_CAPTURE_OUTPUT_FORMATS.toArray( + supportedCaptureOutputFormats); + for (int format : supportedCaptureOutputFormats) { List supportedSizes = extensionChars.getExtensionSupportedSizes( config.getExtension(), format); if (supportedSizes != null) { @@ -223,7 +223,7 @@ public final class CameraExtensionSessionImpl extends CameraExtensionSession { Size burstCaptureSurfaceSize = new Size(burstCaptureSurfaceInfo.mWidth, burstCaptureSurfaceInfo.mHeight); HashMap> supportedPostviewSizes = new HashMap<>(); - for (int format : supportedCaptureOutputFormats.toArray()) { + for (int format : supportedCaptureOutputFormats) { List supportedSizesPostview = extensionChars.getPostviewSupportedSizes( config.getExtension(), burstCaptureSurfaceSize, format); if (supportedSizesPostview != null) { diff --git a/core/java/android/hardware/camera2/impl/CameraExtensionUtils.java b/core/java/android/hardware/camera2/impl/CameraExtensionUtils.java index f91d277d571f3c605a8b9fd0b8b790cced886d16..212c909bcbba120a218683c1e111a5b1a1b53fef 100644 --- a/core/java/android/hardware/camera2/impl/CameraExtensionUtils.java +++ b/core/java/android/hardware/camera2/impl/CameraExtensionUtils.java @@ -32,11 +32,14 @@ import android.os.Handler; import android.util.IntArray; import android.util.Log; import android.util.Size; +import android.util.SparseIntArray; import android.view.Surface; import com.android.internal.camera.flags.Flags; +import java.util.Arrays; import java.util.HashMap; +import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.concurrent.Executor; @@ -48,11 +51,16 @@ public final class CameraExtensionUtils { public final static int JPEG_DEFAULT_QUALITY = 100; public final static int JPEG_DEFAULT_ROTATION = 0; - public static final int[] SUPPORTED_CAPTURE_OUTPUT_FORMATS = { - CameraExtensionCharacteristics.PROCESSING_INPUT_FORMAT, - ImageFormat.JPEG, - ImageFormat.JPEG_R - }; + public static HashSet SUPPORTED_CAPTURE_OUTPUT_FORMATS = new HashSet<>(); + + static { + SUPPORTED_CAPTURE_OUTPUT_FORMATS.addAll(Arrays.asList( + CameraExtensionCharacteristics.PROCESSING_INPUT_FORMAT, ImageFormat.JPEG, + ImageFormat.YCBCR_P010, ImageFormat.JPEG_R )); + if (Flags.depthJpegExtensions()) { + SUPPORTED_CAPTURE_OUTPUT_FORMATS.add(ImageFormat.DEPTH_JPEG); + } + } public static class SurfaceInfo { public int mWidth = 0; @@ -101,6 +109,13 @@ public final class CameraExtensionUtils { surfaceInfo.mFormat = ImageFormat.JPEG_R; return surfaceInfo; } + if (Flags.depthJpegExtensions()) { + if ((nativeFormat == StreamConfigurationMap.HAL_PIXEL_FORMAT_BLOB) + && (dataspace == StreamConfigurationMap.HAL_DATASPACE_DYNAMIC_DEPTH)) { + surfaceInfo.mFormat = ImageFormat.DEPTH_JPEG; + return surfaceInfo; + } + } return surfaceInfo; } @@ -125,14 +140,14 @@ public final class CameraExtensionUtils { public static Surface getBurstCaptureSurface( @NonNull List outputConfigs, @NonNull HashMap> supportedCaptureSizes) { - IntArray supportedCaptureOutputFormats = - new IntArray(CameraExtensionUtils.SUPPORTED_CAPTURE_OUTPUT_FORMATS.length); - supportedCaptureOutputFormats.addAll( - CameraExtensionUtils.SUPPORTED_CAPTURE_OUTPUT_FORMATS); - supportedCaptureOutputFormats.add(ImageFormat.YCBCR_P010); + Integer[] supportedCaptureOutputFormats = + new Integer[CameraExtensionUtils.SUPPORTED_CAPTURE_OUTPUT_FORMATS.size()]; + supportedCaptureOutputFormats = + CameraExtensionUtils.SUPPORTED_CAPTURE_OUTPUT_FORMATS.toArray( + supportedCaptureOutputFormats); for (OutputConfiguration config : outputConfigs) { SurfaceInfo surfaceInfo = querySurface(config.getSurface()); - for (int supportedFormat : supportedCaptureOutputFormats.toArray()) { + for (int supportedFormat : supportedCaptureOutputFormats) { if (surfaceInfo.mFormat == supportedFormat) { Size captureSize = new Size(surfaceInfo.mWidth, surfaceInfo.mHeight); if (supportedCaptureSizes.containsKey(supportedFormat)) { diff --git a/core/java/android/hardware/contexthub/HubEndpoint.java b/core/java/android/hardware/contexthub/HubEndpoint.java index 078b4d4629e0ea441976283037c6813ed8446a50..7efdd6dbdf4196c7f4ddf40929c3fb8563bb4409 100644 --- a/core/java/android/hardware/contexthub/HubEndpoint.java +++ b/core/java/android/hardware/contexthub/HubEndpoint.java @@ -18,6 +18,7 @@ package android.hardware.contexthub; import android.annotation.CallbackExecutor; import android.annotation.FlaggedApi; +import android.annotation.IntDef; import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.SystemApi; @@ -31,6 +32,8 @@ import android.util.SparseArray; import androidx.annotation.GuardedBy; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; @@ -48,6 +51,46 @@ import java.util.concurrent.Executor; public class HubEndpoint { private static final String TAG = "HubEndpoint"; + /** + * Constants describing the outcome of operations through HubEndpoints (like opening/closing of + * sessions or stopping of endpoints). + * + * @hide + */ + @Retention(RetentionPolicy.SOURCE) + @IntDef( + prefix = {"REASON_"}, + value = { + REASON_FAILURE, + REASON_OPEN_ENDPOINT_SESSION_REQUEST_REJECTED, + REASON_CLOSE_ENDPOINT_SESSION_REQUESTED, + REASON_ENDPOINT_INVALID, + REASON_ENDPOINT_STOPPED, + }) + public @interface Reason {} + + /** Unclassified failure */ + public static final int REASON_FAILURE = 0; + + // The values 1 and 2 are reserved at the Context Hub HAL but not exposed to apps. + + /** The peer rejected the request to open this endpoint session. */ + public static final int REASON_OPEN_ENDPOINT_SESSION_REQUEST_REJECTED = 3; + + /** The peer closed this endpoint session. */ + public static final int REASON_CLOSE_ENDPOINT_SESSION_REQUESTED = 4; + + /** The peer endpoint is invalid. */ + public static final int REASON_ENDPOINT_INVALID = 5; + + /** + * The endpoint is now stopped. The app should retrieve the endpoint info using {@link + * android.hardware.location.ContextHubManager#findEndpoints} or register updates through + * {@link android.hardware.location.ContextHubManager#registerEndpointDiscoveryCallback} + * to get notified if the endpoint restarts. + */ + public static final int REASON_ENDPOINT_STOPPED = 6; + private final Object mLock = new Object(); private final HubEndpointInfo mPendingHubEndpointInfo; @Nullable private final IHubEndpointLifecycleCallback mLifecycleCallback; @@ -173,9 +216,7 @@ public class HubEndpoint { try { mServiceToken.closeSession( - sessionId, - IHubEndpointLifecycleCallback - .REASON_OPEN_ENDPOINT_SESSION_REQUEST_REJECTED); + sessionId, REASON_OPEN_ENDPOINT_SESSION_REQUEST_REJECTED); } catch (RemoteException e) { e.rethrowFromSystemServer(); } @@ -396,9 +437,7 @@ public class HubEndpoint { try { // Oneway notification to system service - serviceToken.closeSession( - session.getId(), - IHubEndpointLifecycleCallback.REASON_CLOSE_ENDPOINT_SESSION_REQUESTED); + serviceToken.closeSession(session.getId(), REASON_CLOSE_ENDPOINT_SESSION_REQUESTED); } catch (RemoteException e) { Log.e(TAG, "closeSession: failed to close session " + session, e); e.rethrowFromSystemServer(); diff --git a/core/java/android/hardware/contexthub/HubEndpointInfo.java b/core/java/android/hardware/contexthub/HubEndpointInfo.java index b1d55239ac438d0d2e389e12da7e7fda7b44fea3..5265d56634590eadd2259be71ecb4a5a485990f2 100644 --- a/core/java/android/hardware/contexthub/HubEndpointInfo.java +++ b/core/java/android/hardware/contexthub/HubEndpointInfo.java @@ -156,7 +156,7 @@ public final class HubEndpointInfo implements Parcelable { mRequiredPermissions = Arrays.asList(endpointInfo.requiredPermissions); mHubServiceInfos = new ArrayList<>(endpointInfo.services.length); for (int i = 0; i < endpointInfo.services.length; i++) { - mHubServiceInfos.set(i, new HubServiceInfo(endpointInfo.services[i])); + mHubServiceInfos.add(new HubServiceInfo(endpointInfo.services[i])); } } diff --git a/core/java/android/hardware/contexthub/HubServiceInfo.java b/core/java/android/hardware/contexthub/HubServiceInfo.java index c7fe77c4a0f1589aeab1dda96e0d4bc02d71ed95..a1c52fb5864f034b0b53d0a243302373b2c2a0a8 100644 --- a/core/java/android/hardware/contexthub/HubServiceInfo.java +++ b/core/java/android/hardware/contexthub/HubServiceInfo.java @@ -17,12 +17,10 @@ package android.hardware.contexthub; import android.annotation.FlaggedApi; import android.annotation.IntDef; -import android.annotation.Nullable; import android.annotation.SystemApi; import android.chre.flags.Flags; import android.os.Parcel; import android.os.Parcelable; -import android.os.ParcelableHolder; import androidx.annotation.NonNull; @@ -76,15 +74,12 @@ public final class HubServiceInfo implements Parcelable { private final int mMajorVersion; private final int mMinorVersion; - @NonNull private final ParcelableHolder mExtendedInfo; - /** @hide */ public HubServiceInfo(android.hardware.contexthub.Service service) { mServiceDescriptor = service.serviceDescriptor; mFormat = service.format; mMajorVersion = service.majorVersion; mMinorVersion = service.minorVersion; - mExtendedInfo = service.extendedInfo; } private HubServiceInfo(Parcel in) { @@ -92,20 +87,17 @@ public final class HubServiceInfo implements Parcelable { mFormat = in.readInt(); mMajorVersion = in.readInt(); mMinorVersion = in.readInt(); - mExtendedInfo = ParcelableHolder.CREATOR.createFromParcel(in); } public HubServiceInfo( @NonNull String serviceDescriptor, @ServiceFormat int format, int majorVersion, - int minorVersion, - @NonNull ParcelableHolder extendedInfo) { + int minorVersion) { mServiceDescriptor = serviceDescriptor; mFormat = format; mMajorVersion = majorVersion; mMinorVersion = minorVersion; - mExtendedInfo = extendedInfo; } /** Get the unique identifier of this service. See {@link Builder} for more information. */ @@ -134,17 +126,10 @@ public final class HubServiceInfo implements Parcelable { return mMinorVersion; } - /** Get the {@link ParcelableHolder} for the extended information about the service. */ - @NonNull - public ParcelableHolder getExtendedInfo() { - return mExtendedInfo; - } - /** Parcel implementation details */ @Override public int describeContents() { - // Passthrough describeContents flags for mExtendedInfo because we don't have FD otherwise. - return mExtendedInfo.describeContents(); + return 0; } /** Parcel implementation details */ @@ -154,7 +139,6 @@ public final class HubServiceInfo implements Parcelable { dest.writeInt(mFormat); dest.writeInt(mMajorVersion); dest.writeInt(mMinorVersion); - mExtendedInfo.writeToParcel(dest, flags); } /** Builder for a {@link HubServiceInfo} object. */ @@ -165,9 +149,6 @@ public final class HubServiceInfo implements Parcelable { private final int mMajorVersion; private final int mMinorVersion; - private final ParcelableHolder mExtendedInfo = - new ParcelableHolder(Parcelable.PARCELABLE_STABILITY_VINTF); - /** * Create a builder for {@link HubServiceInfo} with a service descriptor. * @@ -219,20 +200,6 @@ public final class HubServiceInfo implements Parcelable { mServiceDescriptor = serviceDescriptor; } - /** - * Set the extended information of this service. - * - * @param extendedInfo Parcelable with extended information about this service. The - * parcelable needs to have at least VINTF stability. Null can be used to clear a - * previously set value. - * @throws android.os.BadParcelableException if the parcelable cannot be used. - */ - @NonNull - public Builder setExtendedInfo(@Nullable Parcelable extendedInfo) { - mExtendedInfo.setParcelable(extendedInfo); - return this; - } - /** * Build the {@link HubServiceInfo} object. * @@ -244,7 +211,7 @@ public final class HubServiceInfo implements Parcelable { throw new IllegalStateException("Major and minor version must be set."); } return new HubServiceInfo( - mServiceDescriptor, mFormat, mMajorVersion, mMinorVersion, mExtendedInfo); + mServiceDescriptor, mFormat, mMajorVersion, mMinorVersion); } } diff --git a/core/java/android/hardware/contexthub/IContextHubEndpointDiscoveryCallback.aidl b/core/java/android/hardware/contexthub/IContextHubEndpointDiscoveryCallback.aidl new file mode 100644 index 0000000000000000000000000000000000000000..245be930a897093429c903ebbf30bbe1f0e905b1 --- /dev/null +++ b/core/java/android/hardware/contexthub/IContextHubEndpointDiscoveryCallback.aidl @@ -0,0 +1,37 @@ +/* + * 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.contexthub; + +import android.hardware.contexthub.HubEndpointInfo; + +/** + * @hide + */ +oneway interface IContextHubEndpointDiscoveryCallback { + /** + * Called when endpoint(s) start. + * @param hubEndpointInfoList The list of endpoints that started. + */ + void onEndpointsStarted(in HubEndpointInfo[] hubEndpointInfoList); + + /** + * Called when endpoint(s) stopped. + * @param hubEndpointInfoList The list of endpoints that started. + * @param reason The reason why the endpoints stopped. + */ + void onEndpointsStopped(in HubEndpointInfo[] hubEndpointInfoList, int reason); +} diff --git a/core/java/android/hardware/contexthub/IHubEndpointDiscoveryCallback.java b/core/java/android/hardware/contexthub/IHubEndpointDiscoveryCallback.java new file mode 100644 index 0000000000000000000000000000000000000000..a61a7ebd0de9f45aab173d0a41d78cf8e2c9efb2 --- /dev/null +++ b/core/java/android/hardware/contexthub/IHubEndpointDiscoveryCallback.java @@ -0,0 +1,49 @@ +/* + * 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.hardware.contexthub; + +import android.annotation.FlaggedApi; +import android.annotation.NonNull; +import android.annotation.SystemApi; +import android.chre.flags.Flags; + +import java.util.List; + +/** + * Interface for listening to updates about endpoint availability. + * + * @hide + */ +@SystemApi +@FlaggedApi(Flags.FLAG_OFFLOAD_API) +public interface IHubEndpointDiscoveryCallback { + /** + * Called when a list of hub endpoints have started. + * + * @param discoveryInfoList The list containing hub discovery information. + */ + void onEndpointsStarted(@NonNull List discoveryInfoList); + + /** + * Called when a list of hub endpoints have stopped. + * + * @param discoveryInfoList The list containing hub discovery information. + * @param reason The reason the endpoints stopped. + */ + void onEndpointsStopped( + @NonNull List discoveryInfoList, @HubEndpoint.Reason int reason); +} diff --git a/core/java/android/hardware/contexthub/IHubEndpointLifecycleCallback.java b/core/java/android/hardware/contexthub/IHubEndpointLifecycleCallback.java index 46884393b49ba9ec89bc5ddd5b0b606943be301a..fe449bb5ce0e92d13a91b8e774bdd54a54bbc18f 100644 --- a/core/java/android/hardware/contexthub/IHubEndpointLifecycleCallback.java +++ b/core/java/android/hardware/contexthub/IHubEndpointLifecycleCallback.java @@ -17,15 +17,11 @@ package android.hardware.contexthub; import android.annotation.FlaggedApi; -import android.annotation.IntDef; import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.SystemApi; import android.chre.flags.Flags; -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; - /** * Interface for listening to lifecycle events of a hub endpoint. * @@ -34,24 +30,6 @@ import java.lang.annotation.RetentionPolicy; @SystemApi @FlaggedApi(Flags.FLAG_OFFLOAD_API) public interface IHubEndpointLifecycleCallback { - /** Unknown reason. */ - int REASON_UNSPECIFIED = 0; - - /** The peer rejected the request to open this endpoint session. */ - int REASON_OPEN_ENDPOINT_SESSION_REQUEST_REJECTED = 3; - - /** The peer closed this endpoint session. */ - int REASON_CLOSE_ENDPOINT_SESSION_REQUESTED = 4; - - /** @hide */ - @Retention(RetentionPolicy.SOURCE) - @IntDef({ - REASON_UNSPECIFIED, - REASON_OPEN_ENDPOINT_SESSION_REQUEST_REJECTED, - REASON_CLOSE_ENDPOINT_SESSION_REQUESTED, - }) - @interface EndpointLifecycleReason {} - /** * Called when an endpoint is requesting a session be opened with another endpoint. * @@ -78,5 +56,5 @@ public interface IHubEndpointLifecycleCallback { * used. * @param reason The reason why this session was closed. */ - void onSessionClosed(@NonNull HubEndpointSession session, @EndpointLifecycleReason int reason); + void onSessionClosed(@NonNull HubEndpointSession session, @HubEndpoint.Reason int reason); } diff --git a/core/java/android/hardware/input/IInputManager.aidl b/core/java/android/hardware/input/IInputManager.aidl index 3284761eb27310fe6fb214b04c0b953273e03a9a..ed510e467f82551803ee9ab6191e8324d2214eca 100644 --- a/core/java/android/hardware/input/IInputManager.aidl +++ b/core/java/android/hardware/input/IInputManager.aidl @@ -281,4 +281,6 @@ interface IInputManager { AidlInputGestureData[] getCustomInputGestures(int userId, int tag); AidlInputGestureData[] getAppLaunchBookmarks(); + + void resetLockedModifierState(); } diff --git a/core/java/android/hardware/input/InputManager.java b/core/java/android/hardware/input/InputManager.java index f8241925dff0483e2c5c50dace114e231cb46b95..10224c1be788437a284ed68bd6a326815544e241 100644 --- a/core/java/android/hardware/input/InputManager.java +++ b/core/java/android/hardware/input/InputManager.java @@ -260,7 +260,7 @@ public final class InputManager { } /** - * Custom input gesture error: Input gesture already exists + * Custom input gesture result success * * @hide */ @@ -1589,6 +1589,21 @@ public final class InputManager { } } + /** + * Resets locked modifier state (i.e.. Caps Lock, Num Lock, Scroll Lock state) + * + * @hide + */ + @TestApi + @SuppressLint("UnflaggedApi") // @TestApi without associated feature. + public void resetLockedModifierState() { + try { + mIm.resetLockedModifierState(); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + } + /** * A callback used to be notified about battery state changes for an input device. The * {@link #onBatteryStateChanged(int, long, BatteryState)} method will be called once after the diff --git a/core/java/android/hardware/input/InputSettings.java b/core/java/android/hardware/input/InputSettings.java index 71b60cff936762d77706f8b0448230bcf4b55475..114459e5e81991ed28de05115febdef251f165f6 100644 --- a/core/java/android/hardware/input/InputSettings.java +++ b/core/java/android/hardware/input/InputSettings.java @@ -31,7 +31,7 @@ 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; -import static com.android.hardware.input.Flags.useKeyGestureEventHandlerMultiPressGestures; +import static com.android.hardware.input.Flags.useKeyGestureEventHandlerMultiKeyGestures; import static com.android.input.flags.Flags.FLAG_KEYBOARD_REPEAT_KEYS; import static com.android.input.flags.Flags.enableInputFilterRustImpl; import static com.android.input.flags.Flags.keyboardRepeatKeys; @@ -522,8 +522,11 @@ public class InputSettings { * @hide */ public static boolean useTouchpadThreeFingerTapShortcut(@NonNull Context context) { - // TODO(b/365063048): determine whether to enable the shortcut based on the settings. - return isTouchpadThreeFingerTapShortcutFeatureFlagEnabled(); + int customizedShortcut = Settings.System.getIntForUser(context.getContentResolver(), + Settings.System.TOUCHPAD_THREE_FINGER_TAP_CUSTOMIZATION, + KeyGestureEvent.KEY_GESTURE_TYPE_UNSPECIFIED, UserHandle.USER_CURRENT); + return customizedShortcut != KeyGestureEvent.KEY_GESTURE_TYPE_UNSPECIFIED + && isTouchpadThreeFingerTapShortcutFeatureFlagEnabled(); } /** @@ -1155,6 +1158,6 @@ public class InputSettings { * @hide */ public static boolean doesKeyGestureEventHandlerSupportMultiKeyGestures() { - return useKeyGestureEventHandler() && useKeyGestureEventHandlerMultiPressGestures(); + return useKeyGestureEventHandler() && useKeyGestureEventHandlerMultiKeyGestures(); } } diff --git a/core/java/android/hardware/input/KeyGlyphMap.java b/core/java/android/hardware/input/KeyGlyphMap.java index f82d1cf276b9f07f79d67c07fd41476d702c8d8a..de5df9188c17bbbdc7ac14b1f95d4771164bc0d5 100644 --- a/core/java/android/hardware/input/KeyGlyphMap.java +++ b/core/java/android/hardware/input/KeyGlyphMap.java @@ -133,6 +133,14 @@ public final class KeyGlyphMap implements Parcelable { } }; + public int getModifierState() { + return mModifierState; + } + + public int getKeycode() { + return mKeycode; + } + @Override public int describeContents() { return 0; diff --git a/core/java/android/hardware/input/input_framework.aconfig b/core/java/android/hardware/input/input_framework.aconfig index fee074901c10f8f1593c58d1fb74f59fa5cb1c56..0c89059a475a5eb25d7d094a33f38fd524410637 100644 --- a/core/java/android/hardware/input/input_framework.aconfig +++ b/core/java/android/hardware/input/input_framework.aconfig @@ -87,6 +87,17 @@ flag { bug: "358603902" } +flag { + name: "input_manager_lifecycle_support" + namespace: "input" + description: "Add support for Lifecycle support in input manager" + bug: "362473586" + is_fixed_read_only: true + metadata { + purpose: PURPOSE_BUGFIX + } +} + flag { namespace: "input_native" name: "manage_key_gestures" @@ -103,8 +114,8 @@ flag { } flag { - namespace: "input_native" - name: "use_key_gesture_event_handler_multi_press_gestures" + namespace: "input" + name: "use_key_gesture_event_handler_multi_key_gestures" description: "Use KeyGestureEvent handler APIs to control multi key press gestures" bug: "358569822" } diff --git a/core/java/android/hardware/location/ContextHubManager.java b/core/java/android/hardware/location/ContextHubManager.java index 426cd69f76a0a245c11c640952170f5fcb8ef921..117d8fe24809c85c1be69ab22c29966d2d0abd44 100644 --- a/core/java/android/hardware/location/ContextHubManager.java +++ b/core/java/android/hardware/location/ContextHubManager.java @@ -38,6 +38,8 @@ import android.hardware.contexthub.HubDiscoveryInfo; import android.hardware.contexthub.HubEndpoint; import android.hardware.contexthub.HubEndpointInfo; import android.hardware.contexthub.HubServiceInfo; +import android.hardware.contexthub.IContextHubEndpointDiscoveryCallback; +import android.hardware.contexthub.IHubEndpointDiscoveryCallback; import android.hardware.contexthub.IHubEndpointLifecycleCallback; import android.os.Handler; import android.os.HandlerExecutor; @@ -49,7 +51,9 @@ import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.util.ArrayList; import java.util.List; +import java.util.Map; import java.util.Objects; +import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.Executor; /** @@ -202,6 +206,10 @@ public final class ContextHubManager { private Callback mCallback; private Handler mCallbackHandler; + /** A map of endpoint discovery callbacks currently registered */ + private Map + mDiscoveryCallbacks = new ConcurrentHashMap<>(); + /** * @deprecated Use {@code mCallback} instead. */ @@ -694,8 +702,6 @@ public final class ContextHubManager { @RequiresPermission(android.Manifest.permission.ACCESS_CONTEXT_HUB) @NonNull public List findEndpoints(long endpointId) { - // TODO(b/379323274): Consider improving these getters to avoid racing with nano app load - // timing. try { List endpointInfos = mService.findEndpoints(endpointId); List results = new ArrayList<>(endpointInfos.size()); @@ -720,8 +726,6 @@ public final class ContextHubManager { @RequiresPermission(android.Manifest.permission.ACCESS_CONTEXT_HUB) @NonNull public List findEndpoints(@NonNull String serviceDescriptor) { - // TODO(b/379323274): Consider improving these getters to avoid racing with nano app load - // timing. if (serviceDescriptor.isBlank()) { throw new IllegalArgumentException("Invalid service descriptor: " + serviceDescriptor); } @@ -743,6 +747,188 @@ public final class ContextHubManager { } } + /** + * Creates an interface to invoke endpoint discovery callbacks to send down to the service. + * + * @param callback the callback to invoke at the client process + * @param executor the executor to invoke callbacks for this client + * @return the callback interface + */ + private IContextHubEndpointDiscoveryCallback createDiscoveryCallback( + IHubEndpointDiscoveryCallback callback, + Executor executor, + @Nullable String serviceDescriptor) { + return new IContextHubEndpointDiscoveryCallback.Stub() { + @Override + public void onEndpointsStarted(HubEndpointInfo[] hubEndpointInfoList) { + if (hubEndpointInfoList.length == 0) { + Log.w(TAG, "onEndpointsStarted: received empty discovery list"); + return; + } + executor.execute( + () -> { + // TODO(b/380293951): Refactor + List discoveryList = + new ArrayList<>(hubEndpointInfoList.length); + for (HubEndpointInfo info : hubEndpointInfoList) { + if (serviceDescriptor != null) { + for (HubServiceInfo sInfo : info.getServiceInfoCollection()) { + if (sInfo.getServiceDescriptor() + .equals(serviceDescriptor)) { + discoveryList.add(new HubDiscoveryInfo(info, sInfo)); + } + } + } else { + discoveryList.add(new HubDiscoveryInfo(info)); + } + } + if (discoveryList.isEmpty()) { + Log.w(TAG, "onEndpointsStarted: no matching service descriptor"); + } else { + callback.onEndpointsStarted(discoveryList); + } + }); + } + + @Override + public void onEndpointsStopped(HubEndpointInfo[] hubEndpointInfoList, int reason) { + if (hubEndpointInfoList.length == 0) { + Log.w(TAG, "onEndpointsStopped: received empty discovery list"); + return; + } + executor.execute( + () -> { + List discoveryList = + new ArrayList<>(hubEndpointInfoList.length); + for (HubEndpointInfo info : hubEndpointInfoList) { + if (serviceDescriptor != null) { + for (HubServiceInfo sInfo : info.getServiceInfoCollection()) { + if (sInfo.getServiceDescriptor() + .equals(serviceDescriptor)) { + discoveryList.add(new HubDiscoveryInfo(info, sInfo)); + } + } + } else { + discoveryList.add(new HubDiscoveryInfo(info)); + } + } + if (discoveryList.isEmpty()) { + Log.w(TAG, "onEndpointsStopped: no matching service descriptor"); + } else { + callback.onEndpointsStopped(discoveryList, reason); + } + }); + } + }; + } + + /** + * Equivalent to {@link #registerEndpointDiscoveryCallback(long, IHubEndpointDiscoveryCallback, + * Executor)} with the default executor in the main thread. + */ + @RequiresPermission(android.Manifest.permission.ACCESS_CONTEXT_HUB) + @FlaggedApi(Flags.FLAG_OFFLOAD_API) + public void registerEndpointDiscoveryCallback( + long endpointId, @NonNull IHubEndpointDiscoveryCallback callback) { + registerEndpointDiscoveryCallback( + endpointId, callback, new HandlerExecutor(Handler.getMain())); + } + + /** + * Registers a callback to be notified when the hub endpoint with the corresponding endpoint ID + * has started or stopped. + * + * @param endpointId The identifier of the hub endpoint. + * @param callback The callback to be invoked. + * @param executor The executor to invoke the callback on. + */ + @RequiresPermission(android.Manifest.permission.ACCESS_CONTEXT_HUB) + @FlaggedApi(Flags.FLAG_OFFLOAD_API) + public void registerEndpointDiscoveryCallback( + long endpointId, + @NonNull IHubEndpointDiscoveryCallback callback, + @NonNull Executor executor) { + Objects.requireNonNull(callback, "callback cannot be null"); + Objects.requireNonNull(executor, "executor cannot be null"); + IContextHubEndpointDiscoveryCallback iCallback = + createDiscoveryCallback(callback, executor, null); + try { + mService.registerEndpointDiscoveryCallbackId(endpointId, iCallback); + } catch (RemoteException e) { + e.rethrowFromSystemServer(); + } + + mDiscoveryCallbacks.put(callback, iCallback); + } + + /** + * Equivalent to {@link #registerEndpointDiscoveryCallback(String, + * IHubEndpointDiscoveryCallback, Executor)} with the default executor in the main thread. + */ + @RequiresPermission(android.Manifest.permission.ACCESS_CONTEXT_HUB) + @FlaggedApi(Flags.FLAG_OFFLOAD_API) + public void registerEndpointDiscoveryCallback( + @NonNull String serviceDescriptor, @NonNull IHubEndpointDiscoveryCallback callback) { + registerEndpointDiscoveryCallback( + serviceDescriptor, callback, new HandlerExecutor(Handler.getMain())); + } + + /** + * Registers a callback to be notified when the hub endpoint with the corresponding service + * descriptor has started or stopped. + * + * @param serviceDescriptor The service descriptor of the hub endpoint. + * @param callback The callback to be invoked. + * @param executor The executor to invoke the callback on. + * @throws IllegalArgumentException if the serviceDescriptor is empty. + */ + @RequiresPermission(android.Manifest.permission.ACCESS_CONTEXT_HUB) + @FlaggedApi(Flags.FLAG_OFFLOAD_API) + public void registerEndpointDiscoveryCallback( + @NonNull String serviceDescriptor, + @NonNull IHubEndpointDiscoveryCallback callback, + @NonNull Executor executor) { + Objects.requireNonNull(serviceDescriptor, "serviceDescriptor cannot be null"); + Objects.requireNonNull(callback, "callback cannot be null"); + Objects.requireNonNull(executor, "executor cannot be null"); + if (serviceDescriptor.isBlank()) { + throw new IllegalArgumentException("Invalid service descriptor: " + serviceDescriptor); + } + + IContextHubEndpointDiscoveryCallback iCallback = + createDiscoveryCallback(callback, executor, serviceDescriptor); + try { + mService.registerEndpointDiscoveryCallbackDescriptor(serviceDescriptor, iCallback); + } catch (RemoteException e) { + e.rethrowFromSystemServer(); + } + + mDiscoveryCallbacks.put(callback, iCallback); + } + + /** + * Unregisters a previously registered endpoint discovery callback. + * + * @param callback The callback previously registered. + * @throws IllegalArgumentException If the callback was not previously registered. + */ + @RequiresPermission(android.Manifest.permission.ACCESS_CONTEXT_HUB) + @FlaggedApi(Flags.FLAG_OFFLOAD_API) + public void unregisterEndpointDiscoveryCallback( + @NonNull IHubEndpointDiscoveryCallback callback) { + Objects.requireNonNull(callback, "callback cannot be null"); + IContextHubEndpointDiscoveryCallback iCallback = mDiscoveryCallbacks.remove(callback); + if (iCallback == null) { + throw new IllegalArgumentException("Callback not previously registered"); + } + + try { + mService.unregisterEndpointDiscoveryCallback(iCallback); + } catch (RemoteException e) { + e.rethrowFromSystemServer(); + } + } + /** * Set a callback to receive messages from the context hub * diff --git a/core/java/android/hardware/location/IContextHubService.aidl b/core/java/android/hardware/location/IContextHubService.aidl index f9f41244603880e7ca58372c3b216854e5e5a3da..f14aadcab474e647512bc7b0bfc239b635dab716 100644 --- a/core/java/android/hardware/location/IContextHubService.aidl +++ b/core/java/android/hardware/location/IContextHubService.aidl @@ -21,6 +21,7 @@ import android.app.PendingIntent; import android.hardware.contexthub.HubEndpointInfo; import android.hardware.contexthub.IContextHubEndpoint; import android.hardware.contexthub.IContextHubEndpointCallback; +import android.hardware.contexthub.IContextHubEndpointDiscoveryCallback; import android.hardware.location.ContextHubInfo; import android.hardware.location.ContextHubMessage; import android.hardware.location.HubInfo; @@ -137,4 +138,16 @@ interface IContextHubService { // Register an endpoint with the context hub @EnforcePermission("ACCESS_CONTEXT_HUB") IContextHubEndpoint registerEndpoint(in HubEndpointInfo pendingEndpointInfo, in IContextHubEndpointCallback callback); + + // Register an endpoint discovery callback (id) + @EnforcePermission("ACCESS_CONTEXT_HUB") + void registerEndpointDiscoveryCallbackId(long endpointId, in IContextHubEndpointDiscoveryCallback callback); + + // Register an endpoint discovery callback (descriptor) + @EnforcePermission("ACCESS_CONTEXT_HUB") + void registerEndpointDiscoveryCallbackDescriptor(String serviceDescriptor, in IContextHubEndpointDiscoveryCallback callback); + + // Unregister an endpoint with the context hub + @EnforcePermission("ACCESS_CONTEXT_HUB") + void unregisterEndpointDiscoveryCallback(in IContextHubEndpointDiscoveryCallback callback); } diff --git a/core/java/android/inputmethodservice/AbstractInputMethodService.java b/core/java/android/inputmethodservice/AbstractInputMethodService.java index 4bc5bd2427ea4565c2407ea5652a04947f8dc164..26308f69cfbe991ed80c53b36564bea8052de43d 100644 --- a/core/java/android/inputmethodservice/AbstractInputMethodService.java +++ b/core/java/android/inputmethodservice/AbstractInputMethodService.java @@ -16,6 +16,9 @@ package android.inputmethodservice; +import static android.view.inputmethod.Flags.FLAG_VERIFY_KEY_EVENT; + +import android.annotation.FlaggedApi; import android.annotation.MainThread; import android.annotation.NonNull; import android.annotation.Nullable; @@ -193,6 +196,12 @@ public abstract class AbstractInputMethodService extends WindowProviderService } } + @FlaggedApi(FLAG_VERIFY_KEY_EVENT) + @Override + public boolean onShouldVerifyKeyEvent(@NonNull KeyEvent event) { + return AbstractInputMethodService.this.onShouldVerifyKeyEvent(event); + } + /** * Take care of dispatching incoming trackball events to the appropriate * callbacks on the service, and tell the client when this is done. @@ -308,6 +317,14 @@ public abstract class AbstractInputMethodService extends WindowProviderService return false; } + /** + * @see InputMethodService#onShouldVerifyKeyEvent(KeyEvent) + */ + @FlaggedApi(FLAG_VERIFY_KEY_EVENT) + public boolean onShouldVerifyKeyEvent(@NonNull KeyEvent event) { + return false; + } + /** @hide */ @Override public final int getWindowType() { diff --git a/core/java/android/inputmethodservice/IInputMethodSessionWrapper.java b/core/java/android/inputmethodservice/IInputMethodSessionWrapper.java index 62b131af74fe0c72041c8bea17020843e178bf7b..9b37533f5b02dcf5899e9a46fd3b6a52760e29c8 100644 --- a/core/java/android/inputmethodservice/IInputMethodSessionWrapper.java +++ b/core/java/android/inputmethodservice/IInputMethodSessionWrapper.java @@ -16,12 +16,16 @@ package android.inputmethodservice; +import static android.view.inputmethod.Flags.verifyKeyEvent; + import android.compat.annotation.UnsupportedAppUsage; import android.content.Context; import android.graphics.Rect; +import android.hardware.input.InputManager; import android.os.Bundle; import android.os.Looper; import android.os.Message; +import android.os.SystemClock; import android.util.Log; import android.util.SparseArray; import android.view.InputChannel; @@ -41,6 +45,8 @@ import com.android.internal.inputmethod.IRemoteInputConnection; import com.android.internal.os.HandlerCaller; import com.android.internal.os.SomeArgs; +import java.util.Objects; + class IInputMethodSessionWrapper extends IInputMethodSession.Stub implements HandlerCaller.Callback { private static final String TAG = "InputMethodWrapper"; @@ -56,6 +62,7 @@ class IInputMethodSessionWrapper extends IInputMethodSession.Stub private static final int DO_REMOVE_IME_SURFACE = 130; private static final int DO_FINISH_INPUT = 140; private static final int DO_INVALIDATE_INPUT = 150; + private final Context mContext; @UnsupportedAppUsage @@ -66,6 +73,7 @@ class IInputMethodSessionWrapper extends IInputMethodSession.Stub public IInputMethodSessionWrapper(Context context, InputMethodSession inputMethodSession, InputChannel channel) { + mContext = context; mCaller = new HandlerCaller(context, null, this, true /*asyncHandler*/); mInputMethodSession = inputMethodSession; @@ -233,6 +241,8 @@ class IInputMethodSessionWrapper extends IInputMethodSession.Stub } private final class ImeInputEventReceiver extends InputEventReceiver implements InputMethodSession.EventCallback { + // Time after which a KeyEvent is invalid + private static final long KEY_EVENT_ALLOW_PERIOD_MS = 100L; private final SparseArray mPendingEvents = new SparseArray(); public ImeInputEventReceiver(InputChannel inputChannel, Looper looper) { @@ -247,10 +257,23 @@ class IInputMethodSessionWrapper extends IInputMethodSession.Stub return; } + if (event instanceof KeyEvent keyEvent && needsVerification(keyEvent)) { + // any KeyEvent with modifiers (e.g. Ctrl/Alt/Fn) must be verified that + // they originated from system. + InputManager im = mContext.getSystemService(InputManager.class); + Objects.requireNonNull(im); + final long age = SystemClock.uptimeMillis() - keyEvent.getEventTime(); + if (age >= KEY_EVENT_ALLOW_PERIOD_MS && im.verifyInputEvent(keyEvent) == null) { + Log.w(TAG, "Unverified or Invalid KeyEvent injected into IME. Dropping " + + keyEvent); + finishInputEvent(event, false /* handled */); + return; + } + } + final int seq = event.getSequenceNumber(); mPendingEvents.put(seq, event); - if (event instanceof KeyEvent) { - KeyEvent keyEvent = (KeyEvent)event; + if (event instanceof KeyEvent keyEvent) { mInputMethodSession.dispatchKeyEvent(seq, keyEvent, this); } else { MotionEvent motionEvent = (MotionEvent)event; @@ -271,5 +294,21 @@ class IInputMethodSessionWrapper extends IInputMethodSession.Stub finishInputEvent(event, handled); } } + + private boolean hasKeyModifiers(KeyEvent event) { + if (event.hasNoModifiers()) { + return false; + } + return event.hasModifiers(KeyEvent.META_CTRL_ON) + || event.hasModifiers(KeyEvent.META_ALT_ON) + || event.hasModifiers(KeyEvent.KEYCODE_FUNCTION); + } + + private boolean needsVerification(KeyEvent event) { + //TODO(b/331730488): Handle a11y events as well. + return verifyKeyEvent() + && (hasKeyModifiers(event) + || mInputMethodSession.onShouldVerifyKeyEvent(event)); + } } } diff --git a/core/java/android/inputmethodservice/InputMethodService.java b/core/java/android/inputmethodservice/InputMethodService.java index dadb5c386b76965ccdc41ef1f896c7fc3474e0e2..5f3c15d1842e8bb90267cd109b977baa276c66fb 100644 --- a/core/java/android/inputmethodservice/InputMethodService.java +++ b/core/java/android/inputmethodservice/InputMethodService.java @@ -56,6 +56,7 @@ import static android.view.inputmethod.ConnectionlessHandwritingCallback.CONNECT import static android.view.inputmethod.ConnectionlessHandwritingCallback.CONNECTIONLESS_HANDWRITING_ERROR_UNSUPPORTED; import static android.view.inputmethod.Flags.FLAG_CONNECTIONLESS_HANDWRITING; import static android.view.inputmethod.Flags.FLAG_IME_SWITCHER_REVAMP_API; +import static android.view.inputmethod.Flags.FLAG_VERIFY_KEY_EVENT; import static android.view.inputmethod.Flags.ctrlShiftShortcut; import static android.view.inputmethod.Flags.predictiveBackIme; @@ -406,6 +407,12 @@ public class InputMethodService extends AbstractInputMethodService { **/ private boolean mUsingCtrlShiftShortcut = false; + /** + * Last handwriting bounds used for stylus handwriting + * {@link #setStylusHandwritingRegion(Region)}. + */ + private Region mLastHandwritingRegion; + /** * Returns whether {@link InputMethodService} is responsible for rendering the back button and * the IME switcher button or not when the gestural navigation is enabled. @@ -1192,6 +1199,11 @@ public class InputMethodService extends AbstractInputMethodService { // when the stylus is not down. mPrivOps.setHandwritingSurfaceNotTouchable(true); break; + case MotionEvent.ACTION_OUTSIDE: + // TODO(b/350047836): determine if there is use-case for simultaneous touch + // and stylus handwriting and we shouldn't finish for that. + finishStylusHandwriting(); + break; } } @@ -1532,6 +1544,7 @@ public class InputMethodService extends AbstractInputMethodService { return; } editorInfo.makeCompatible(getApplicationInfo().targetSdkVersion); + mLastHandwritingRegion = null; getInputMethodInternal().restartInput(new RemoteInputConnection(ric, sessionId), editorInfo); } @@ -2840,6 +2853,7 @@ public class InputMethodService extends AbstractInputMethodService { mHandler.removeCallbacks(mFinishHwRunnable); } mFinishHwRunnable = null; + mLastHandwritingRegion = null; final int requestId = mHandwritingRequestId.getAsInt(); mHandwritingRequestId = OptionalInt.empty(); @@ -3166,6 +3180,41 @@ public class InputMethodService extends AbstractInputMethodService { registerDefaultOnBackInvokedCallback(); } + /** + * Sets a new stylus handwriting region as user continues to write on an editor on screen. + * Stylus strokes that are started within the {@code touchableRegion} are treated as + * continuation of handwriting and all the events outside are passed-through to the IME target + * app, causing stylus handwriting to finish {@link #finishStylusHandwriting()}. + * By default, {@link WindowManager#getMaximumWindowMetrics()} is handwritable and + * {@code touchableRegion} resets after each handwriting session. + *

+ * For example, the IME can use this API to dynamically expand the stylus handwriting region on + * every stylus stroke as user continues to write on an editor. The region should grow around + * the last stroke so that a UI element below the IME window is still interactable when it is + * spaced sufficiently away (~2 character dimensions) from last stroke. + *

+ *

+ * Note: Setting handwriting touchable region is supported on IMEs that support stylus + * handwriting {@link InputMethodInfo#supportsStylusHandwriting()}. + *

+ * + * @param handwritingRegion new stylus handwritable {@link Region} that can accept stylus touch. + */ + @FlaggedApi(Flags.FLAG_ADAPTIVE_HANDWRITING_BOUNDS) + public final void setStylusHandwritingRegion(@NonNull Region handwritingRegion) { + if (handwritingRegion.equals(mLastHandwritingRegion)) { + Log.v(TAG, "Failed to set setStylusHandwritingRegion():" + + " same region set twice."); + return; + } + + if (DEBUG) { + Log.d(TAG, "Setting new handwriting region for stylus handwriting " + + handwritingRegion + " from last " + mLastHandwritingRegion); + } + mPrivOps.setHandwritingTouchableRegion(handwritingRegion); + mLastHandwritingRegion = handwritingRegion; + } /** * Registers an {@link OnBackInvokedCallback} to handle back invocation when ahead-of-time @@ -3734,6 +3783,23 @@ public class InputMethodService extends AbstractInputMethodService { return doMovementKey(keyCode, event, MOVEMENT_DOWN); } + /** + * Received by the IME before dispatch to {@link #onKeyDown(int, KeyEvent)} to let the system + * know if the {@link KeyEvent} needs to be verified that it originated from the system. + * {@link KeyEvent}s may originate from outside of the system and any sensitive keys should be + * marked for verification. One example of this could be using key shortcuts for switching to + * another IME. + * + * @param keyEvent the event that may need verification. + * @return {@code true} if {@link KeyEvent} should have its HMAC verified before dispatch, + * {@code false} otherwise. + */ + @FlaggedApi(FLAG_VERIFY_KEY_EVENT) + @Override + public boolean onShouldVerifyKeyEvent(@NonNull KeyEvent keyEvent) { + return false; + } + /** * Default implementation of {@link KeyEvent.Callback#onKeyLongPress(int, KeyEvent) * KeyEvent.Callback.onKeyLongPress()}: always returns false (doesn't handle diff --git a/core/java/android/net/vcn/VcnGatewayConnectionConfig.java b/core/java/android/net/vcn/VcnGatewayConnectionConfig.java index 3219ce81c25691e78e266534a5b526b2a71fee3e..b270062cbffc75ede140f867e3ab43562d9dda91 100644 --- a/core/java/android/net/vcn/VcnGatewayConnectionConfig.java +++ b/core/java/android/net/vcn/VcnGatewayConnectionConfig.java @@ -789,11 +789,17 @@ public final class VcnGatewayConnectionConfig { public Builder setMinUdpPort4500NatTimeoutSeconds( @IntRange(from = MIN_UDP_PORT_4500_NAT_TIMEOUT_SECONDS) int minUdpPort4500NatTimeoutSeconds) { - Preconditions.checkArgument( - minUdpPort4500NatTimeoutSeconds == MIN_UDP_PORT_4500_NAT_TIMEOUT_UNSET - || minUdpPort4500NatTimeoutSeconds - >= MIN_UDP_PORT_4500_NAT_TIMEOUT_SECONDS, - "Timeout must be at least 120s or MIN_UDP_PORT_4500_NAT_TIMEOUT_UNSET"); + if (Flags.mainlineVcnModuleApi()) { + Preconditions.checkArgument( + minUdpPort4500NatTimeoutSeconds == MIN_UDP_PORT_4500_NAT_TIMEOUT_UNSET + || minUdpPort4500NatTimeoutSeconds + >= MIN_UDP_PORT_4500_NAT_TIMEOUT_SECONDS, + "Timeout must be at least 120s or MIN_UDP_PORT_4500_NAT_TIMEOUT_UNSET"); + } else { + Preconditions.checkArgument( + minUdpPort4500NatTimeoutSeconds >= MIN_UDP_PORT_4500_NAT_TIMEOUT_SECONDS, + "Timeout must be at least 120s"); + } mMinUdpPort4500NatTimeoutSeconds = minUdpPort4500NatTimeoutSeconds; return this; diff --git a/core/java/android/net/vcn/flags.aconfig b/core/java/android/net/vcn/flags.aconfig index 1b2c575917b263379d64a55e8bbe8b102f0cc3c8..b461f95fec53609e40ba3d820cdfa7923732c184 100644 --- a/core/java/android/net/vcn/flags.aconfig +++ b/core/java/android/net/vcn/flags.aconfig @@ -1,5 +1,5 @@ package: "android.net.vcn" -container: "system" +container: "com.android.tethering" flag { name: "safe_mode_config" @@ -15,14 +15,4 @@ flag { description: "Expose APIs from VCN for mainline migration" is_exported: true bug: "376339506" -} - -flag { - name: "fix_config_garbage_collection" - namespace: "vcn" - description: "Handle race condition in subscription change" - bug: "370862489" - metadata { - purpose: PURPOSE_BUGFIX - } } \ No newline at end of file diff --git a/core/java/android/os/AggregateBatteryConsumer.java b/core/java/android/os/AggregateBatteryConsumer.java index f0e12ca644dd6ccd16d2489342d3d0d6d7c63c99..f5fee4f2d9beb09ec19eda32c3e34bfbc09bd550 100644 --- a/core/java/android/os/AggregateBatteryConsumer.java +++ b/core/java/android/os/AggregateBatteryConsumer.java @@ -17,7 +17,6 @@ package android.os; import android.annotation.NonNull; -import android.util.proto.ProtoOutputStream; import com.android.modules.utils.TypedXmlPullParser; import com.android.modules.utils.TypedXmlSerializer; @@ -100,19 +99,6 @@ public final class AggregateBatteryConsumer extends BatteryConsumer { } } - void writePowerComponentModelProto(@NonNull ProtoOutputStream proto) { - for (int i = 0; i < POWER_COMPONENT_COUNT; i++) { - final int powerModel = getPowerModel(i); - if (powerModel == BatteryConsumer.POWER_MODEL_UNDEFINED) continue; - - final long token = proto.start(BatteryUsageStatsAtomsProto.COMPONENT_MODELS); - proto.write(BatteryUsageStatsAtomsProto.PowerComponentModel.COMPONENT, i); - proto.write(BatteryUsageStatsAtomsProto.PowerComponentModel.POWER_MODEL, - powerModelToProtoEnum(powerModel)); - proto.end(token); - } - } - /** * Builder for DeviceBatteryConsumer. */ diff --git a/core/java/android/os/BatteryConsumer.java b/core/java/android/os/BatteryConsumer.java index 14b67f64b6da85549171baa48a64817ef360e7e9..96ea1683b5cfea9d2edfb81525a5af2a88d52d8f 100644 --- a/core/java/android/os/BatteryConsumer.java +++ b/core/java/android/os/BatteryConsumer.java @@ -161,18 +161,27 @@ public abstract class BatteryConsumer { /** * Unspecified power model. + * + * @deprecated PowerModel is no longer supported */ + @Deprecated public static final int POWER_MODEL_UNDEFINED = 0; /** * Power model that is based on average consumption rates that hardware components * consume in various states. + * + * @deprecated PowerModel is no longer supported */ + @Deprecated public static final int POWER_MODEL_POWER_PROFILE = 1; /** * Power model that is based on energy consumption stats provided by PowerStats HAL. + * + * @deprecated PowerModel is no longer supported */ + @Deprecated public static final int POWER_MODEL_ENERGY_CONSUMPTION = 2; /** @@ -380,19 +389,17 @@ public abstract class BatteryConsumer { public final @ScreenState int screenState; public final @PowerState int powerState; - final int mPowerModelColumnIndex; final int mPowerColumnIndex; final int mDurationColumnIndex; private Key(@PowerComponentId int powerComponentId, @ProcessState int processState, - @ScreenState int screenState, @PowerState int powerState, int powerModelColumnIndex, + @ScreenState int screenState, @PowerState int powerState, int powerColumnIndex, int durationColumnIndex) { this.powerComponentId = powerComponentId; this.processState = processState; this.screenState = screenState; this.powerState = powerState; - mPowerModelColumnIndex = powerModelColumnIndex; mPowerColumnIndex = powerColumnIndex; mDurationColumnIndex = durationColumnIndex; } @@ -577,11 +584,11 @@ public abstract class BatteryConsumer { * * @param componentId The ID of the power component, e.g. * {@link BatteryConsumer#POWER_COMPONENT_CPU}. + * @deprecated PowerModel is no longer supported */ + @Deprecated public @PowerModel int getPowerModel(@PowerComponentId int componentId) { - return mPowerComponents.getPowerModel( - mData.layout.getKeyOrThrow(componentId, PROCESS_STATE_UNSPECIFIED, - SCREEN_STATE_UNSPECIFIED, POWER_STATE_UNSPECIFIED)); + return POWER_MODEL_UNDEFINED; } /** @@ -589,9 +596,11 @@ public abstract class BatteryConsumer { * * @param key The key of the power component, obtained by calling {@link #getKey} or * {@link #getKeys} method. + * @deprecated PowerModel is no longer supported */ + @Deprecated public @PowerModel int getPowerModel(@NonNull BatteryConsumer.Key key) { - return mPowerComponents.getPowerModel(key); + return POWER_MODEL_UNDEFINED; } /** @@ -656,20 +665,6 @@ public abstract class BatteryConsumer { return sPowerComponentNames[componentId]; } - /** - * Returns the name of the specified power model. Intended for logging and debugging. - */ - public static String powerModelToString(@BatteryConsumer.PowerModel int powerModel) { - switch (powerModel) { - case BatteryConsumer.POWER_MODEL_ENERGY_CONSUMPTION: - return "energy consumption"; - case BatteryConsumer.POWER_MODEL_POWER_PROFILE: - return "power profile"; - default: - return ""; - } - } - /** * Returns the equivalent PowerModel enum for the specified power model. * {@see BatteryUsageStatsAtomsProto.BatteryConsumerData.PowerComponentUsage.PowerModel} @@ -857,10 +852,8 @@ public abstract class BatteryConsumer { static class BatteryConsumerDataLayout { private static final Key[] KEY_ARRAY = new Key[0]; - public static final int POWER_MODEL_NOT_INCLUDED = -1; public final String[] customPowerComponentNames; public final int customPowerComponentCount; - public final boolean powerModelsIncluded; public final boolean processStateDataIncluded; public final boolean screenStateDataIncluded; public final boolean powerStateDataIncluded; @@ -872,11 +865,10 @@ public abstract class BatteryConsumer { private SparseArray mPerComponentKeys; private BatteryConsumerDataLayout(int firstColumn, String[] customPowerComponentNames, - boolean powerModelsIncluded, boolean includeProcessStateData, - boolean includeScreenState, boolean includePowerState) { + boolean includeProcessStateData, boolean includeScreenState, + boolean includePowerState) { this.customPowerComponentNames = customPowerComponentNames; this.customPowerComponentCount = customPowerComponentNames.length; - this.powerModelsIncluded = powerModelsIncluded; this.processStateDataIncluded = includeProcessStateData; this.screenStateDataIncluded = includeScreenState; this.powerStateDataIncluded = includePowerState; @@ -904,7 +896,7 @@ public abstract class BatteryConsumer { continue; } for (int i = 0; i < powerComponentIds.length; i++) { - columnIndex = addKeys(keyList, powerModelsIncluded, includeProcessStateData, + columnIndex = addKeys(keyList, includeProcessStateData, powerComponentIds[i], screenState, powerState, columnIndex); } } @@ -934,13 +926,10 @@ public abstract class BatteryConsumer { } } - private int addKeys(List keys, boolean powerModelsIncluded, - boolean includeProcessStateData, @PowerComponentId int componentId, - int screenState, int powerState, int columnIndex) { + private int addKeys(List keys, boolean includeProcessStateData, + @PowerComponentId int componentId, int screenState, int powerState, + int columnIndex) { keys.add(new Key(componentId, PROCESS_STATE_UNSPECIFIED, screenState, powerState, - powerModelsIncluded - ? columnIndex++ - : POWER_MODEL_NOT_INCLUDED, // power model columnIndex++, // power columnIndex++ // usage duration )); @@ -956,9 +945,6 @@ public abstract class BatteryConsumer { continue; } keys.add(new Key(componentId, processState, screenState, powerState, - powerModelsIncluded - ? columnIndex++ - : POWER_MODEL_NOT_INCLUDED, // power model columnIndex++, // power columnIndex++ // usage duration )); @@ -1016,7 +1002,7 @@ public abstract class BatteryConsumer { } static BatteryConsumerDataLayout createBatteryConsumerDataLayout( - String[] customPowerComponentNames, boolean includePowerModels, + String[] customPowerComponentNames, boolean includeProcessStateData, boolean includeScreenStateData, boolean includePowerStateData) { int columnCount = BatteryConsumer.COLUMN_COUNT; @@ -1025,8 +1011,7 @@ public abstract class BatteryConsumer { columnCount = Math.max(columnCount, UserBatteryConsumer.COLUMN_COUNT); return new BatteryConsumerDataLayout(columnCount, customPowerComponentNames, - includePowerModels, includeProcessStateData, includeScreenStateData, - includePowerStateData); + includeProcessStateData, includeScreenStateData, includePowerStateData); } protected abstract static class BaseBuilder> { @@ -1086,7 +1071,7 @@ public abstract class BatteryConsumer { public T setConsumedPower(@PowerComponentId int componentId, double componentPower, @PowerModel int powerModel) { mPowerComponentsBuilder.setConsumedPower(getKey(componentId, PROCESS_STATE_UNSPECIFIED), - componentPower, powerModel); + componentPower); return (T) this; } @@ -1095,14 +1080,14 @@ public abstract class BatteryConsumer { public T addConsumedPower(@PowerComponentId int componentId, double componentPower, @PowerModel int powerModel) { mPowerComponentsBuilder.addConsumedPower(getKey(componentId, PROCESS_STATE_UNSPECIFIED), - componentPower, powerModel); + componentPower); return (T) this; } @SuppressWarnings("unchecked") @NonNull public T setConsumedPower(Key key, double componentPower, @PowerModel int powerModel) { - mPowerComponentsBuilder.setConsumedPower(key, componentPower, powerModel); + mPowerComponentsBuilder.setConsumedPower(key, componentPower); return (T) this; } @@ -1110,21 +1095,14 @@ public abstract class BatteryConsumer { @NonNull public T addConsumedPower(@PowerComponentId int componentId, double componentPower) { mPowerComponentsBuilder.addConsumedPower(getKey(componentId, PROCESS_STATE_UNSPECIFIED), - componentPower, POWER_MODEL_UNDEFINED); + componentPower); return (T) this; } @SuppressWarnings("unchecked") @NonNull public T addConsumedPower(Key key, double componentPower) { - mPowerComponentsBuilder.addConsumedPower(key, componentPower, POWER_MODEL_UNDEFINED); - return (T) this; - } - - @SuppressWarnings("unchecked") - @NonNull - public T addConsumedPower(Key key, double componentPower, @PowerModel int powerModel) { - mPowerComponentsBuilder.addConsumedPower(key, componentPower, powerModel); + mPowerComponentsBuilder.addConsumedPower(key, componentPower); return (T) this; } diff --git a/core/java/android/os/BatteryManager.java b/core/java/android/os/BatteryManager.java index 8b267bf28c7e58a22ce9218b37fee9771756857f..b63ad5f0148ee8acb90ccef1cb7f788b9e41d123 100644 --- a/core/java/android/os/BatteryManager.java +++ b/core/java/android/os/BatteryManager.java @@ -167,75 +167,89 @@ public class BatteryManager { public static final String EXTRA_CHARGING_STATUS = "android.os.extra.CHARGING_STATUS"; /** - * Extra for {@link android.content.Intent#ACTION_BATTERY_CHANGED}: - * Int value representing the battery's capacity level. These constants are key indicators of - * battery status and system capabilities, guiding power management decisions for both the - * system and apps: - * {@link #BATTERY_CAPACITY_LEVEL_UNSUPPORTED}: Feature not supported on this device. - * {@link #BATTERY_CAPACITY_LEVEL_UNKNOWN}: Battery status is unavailable or uninitialized. - * {@link #BATTERY_CAPACITY_LEVEL_CRITICAL}: Battery is critically low and the Android - * framework has been notified to schedule a shutdown by this value - * {@link #BATTERY_CAPACITY_LEVEL_LOW}: Android framework must limit background jobs to - * avoid impacting charging speed - * {@link #BATTERY_CAPACITY_LEVEL_NORMAL}: Battery level and charging rates are normal, - * battery temperature is within normal range and adapter power is enough to charge the - * battery at an acceptable rate. Android framework can run light background tasks without - * affecting charging performance severely. - * {@link #BATTERY_CAPACITY_LEVEL_HIGH}: Battery level is high, battery temperature is - * within normal range and adapter power is enough to charge the battery at an acceptable - * rate while running background loads. Android framework can run background tasks without - * affecting charging or battery performance. - * {@link #BATTERY_CAPACITY_LEVEL_FULL}: The battery is full, battery temperature is - * within normal range and adapter power is enough to sustain running background loads. - * Android framework can run background tasks without affecting the battery level or - * battery performance. - */ - - @FlaggedApi(FLAG_BATTERY_PART_STATUS_API) - public static final String EXTRA_CAPACITY_LEVEL = "android.os.extra.CAPACITY_LEVEL"; - - /** - * Battery capacity level is unsupported. @see EXTRA_CAPACITY_LEVEL + * Battery capacity level is unsupported. + * + * @see #EXTRA_CAPACITY_LEVEL */ @FlaggedApi(FLAG_BATTERY_PART_STATUS_API) public static final int BATTERY_CAPACITY_LEVEL_UNSUPPORTED = -1; /** - * Battery capacity level is unknown. @see EXTRA_CAPACITY_LEVEL + * Battery capacity level is unknown. + * + * @see #EXTRA_CAPACITY_LEVEL */ @FlaggedApi(FLAG_BATTERY_PART_STATUS_API) public static final int BATTERY_CAPACITY_LEVEL_UNKNOWN = 0; /** - * Battery capacity level is critical. @see EXTRA_CAPACITY_LEVEL + * Battery capacity level is critical. The Android framework has been notified to schedule + * a shutdown by this value. + * + * @see #EXTRA_CAPACITY_LEVEL */ @FlaggedApi(FLAG_BATTERY_PART_STATUS_API) public static final int BATTERY_CAPACITY_LEVEL_CRITICAL = 1; /** - * Battery capacity level is low. @see EXTRA_CAPACITY_LEVEL + * Battery capacity level is low. The Android framework must limit background jobs to avoid + * impacting charging speed. + * + * @see #EXTRA_CAPACITY_LEVEL */ @FlaggedApi(FLAG_BATTERY_PART_STATUS_API) public static final int BATTERY_CAPACITY_LEVEL_LOW = 2; /** - * Battery capacity level is normal. @see EXTRA_CAPACITY_LEVEL + * Battery capacity level is normal. Battery level and charging rates are normal, battery + * temperature is within the normal range, and adapter power is enough to charge the battery + * at an acceptable rate. The Android framework can run light background tasks without + * affecting charging performance severely. + * + * @see #EXTRA_CAPACITY_LEVEL */ @FlaggedApi(FLAG_BATTERY_PART_STATUS_API) public static final int BATTERY_CAPACITY_LEVEL_NORMAL = 3; /** - * Battery capacity level is high. @see EXTRA_CAPACITY_LEVEL + * Battery capacity level is high. Battery level is high, battery temperature is within the + * normal range, and adapter power is enough to charge the battery at an acceptable rate + * while running background loads. The Android framework can run background tasks without + * affecting charging or battery performance. + * + * @see #EXTRA_CAPACITY_LEVEL */ @FlaggedApi(FLAG_BATTERY_PART_STATUS_API) public static final int BATTERY_CAPACITY_LEVEL_HIGH = 4; /** - * Battery capacity level is full. @see EXTRA_CAPACITY_LEVEL + * Battery capacity level is full. The battery is full, the battery temperature is within the + * normal range, and adapter power is enough to sustain running background loads. The Android + * framework can run background tasks without affecting the battery level or battery + * performance. + * + * @see #EXTRA_CAPACITY_LEVEL */ @FlaggedApi(FLAG_BATTERY_PART_STATUS_API) public static final int BATTERY_CAPACITY_LEVEL_FULL = 5; + /** + * Extra for {@link android.content.Intent#ACTION_BATTERY_CHANGED}: + * Int value representing the battery's capacity level. These constants are key indicators of + * battery status and system capabilities, guiding power management decisions for both the + * system and apps. + * + * @see #BATTERY_CAPACITY_LEVEL_UNSUPPORTED + * @see #BATTERY_CAPACITY_LEVEL_UNKNOWN + * @see #BATTERY_CAPACITY_LEVEL_CRITICAL + * @see #BATTERY_CAPACITY_LEVEL_LOW + * @see #BATTERY_CAPACITY_LEVEL_NORMAL + * @see #BATTERY_CAPACITY_LEVEL_HIGH + * @see #BATTERY_CAPACITY_LEVEL_FULL + */ + @FlaggedApi(FLAG_BATTERY_PART_STATUS_API) + public static final String EXTRA_CAPACITY_LEVEL = "android.os.extra.CAPACITY_LEVEL"; + /** * Extra for {@link android.content.Intent#ACTION_BATTERY_LEVEL_CHANGED}: * Contains list of Bundles representing battery events diff --git a/core/java/android/os/BatteryUsageStats.java b/core/java/android/os/BatteryUsageStats.java index 72e4cef2f6ebbd3bf642f724ebf795eabfe61eea..f913fcfd56d40a54dfbbcc34f85e0d4530b12032 100644 --- a/core/java/android/os/BatteryUsageStats.java +++ b/core/java/android/os/BatteryUsageStats.java @@ -114,7 +114,6 @@ public final class BatteryUsageStats implements Parcelable, Closeable { static final String XML_ATTR_POWER_STATE = "power_state"; static final String XML_ATTR_POWER = "power"; static final String XML_ATTR_DURATION = "duration"; - static final String XML_ATTR_MODEL = "model"; static final String XML_ATTR_BATTERY_CAPACITY = "battery_capacity"; static final String XML_ATTR_DISCHARGE_PERCENT = "discharge_pct"; static final String XML_ATTR_DISCHARGE_LOWER = "discharge_lower"; @@ -155,7 +154,6 @@ public final class BatteryUsageStats implements Parcelable, Closeable { private final long mBatteryTimeRemainingMs; private final long mChargeTimeRemainingMs; private final String[] mCustomPowerComponentNames; - private final boolean mIncludesPowerModels; private final boolean mIncludesProcessStateData; private final boolean mIncludesScreenStateData; private final boolean mIncludesPowerStateData; @@ -179,7 +177,6 @@ public final class BatteryUsageStats implements Parcelable, Closeable { mBatteryTimeRemainingMs = builder.mBatteryTimeRemainingMs; mChargeTimeRemainingMs = builder.mChargeTimeRemainingMs; mCustomPowerComponentNames = builder.mCustomPowerComponentNames; - mIncludesPowerModels = builder.mIncludePowerModels; mIncludesProcessStateData = builder.mIncludesProcessStateData; mIncludesScreenStateData = builder.mIncludesScreenStateData; mIncludesPowerStateData = builder.mIncludesPowerStateData; @@ -364,14 +361,13 @@ public final class BatteryUsageStats implements Parcelable, Closeable { mBatteryTimeRemainingMs = source.readLong(); mChargeTimeRemainingMs = source.readLong(); mCustomPowerComponentNames = source.readStringArray(); - mIncludesPowerModels = source.readBoolean(); mIncludesProcessStateData = source.readBoolean(); mIncludesScreenStateData = source.readBoolean(); mIncludesPowerStateData = source.readBoolean(); mBatteryConsumersCursorWindow = CursorWindow.newFromParcel(source); mBatteryConsumerDataLayout = BatteryConsumer.createBatteryConsumerDataLayout( - mCustomPowerComponentNames, mIncludesPowerModels, mIncludesProcessStateData, + mCustomPowerComponentNames, mIncludesProcessStateData, mIncludesScreenStateData, mIncludesPowerStateData); final int numRows = mBatteryConsumersCursorWindow.getNumRows(); @@ -424,7 +420,6 @@ public final class BatteryUsageStats implements Parcelable, Closeable { dest.writeLong(mBatteryTimeRemainingMs); dest.writeLong(mChargeTimeRemainingMs); dest.writeStringArray(mCustomPowerComponentNames); - dest.writeBoolean(mIncludesPowerModels); dest.writeBoolean(mIncludesProcessStateData); dest.writeBoolean(mIncludesScreenStateData); dest.writeBoolean(mIncludesPowerStateData); @@ -506,9 +501,6 @@ public final class BatteryUsageStats implements Parcelable, Closeable { getDischargeDurationMs()); deviceBatteryConsumer.writeStatsProto(proto, BatteryUsageStatsAtomsProto.DEVICE_BATTERY_CONSUMER); - if (mIncludesPowerModels) { - deviceBatteryConsumer.writePowerComponentModelProto(proto); - } writeUidBatteryConsumersProto(proto, maxRawSize); } @@ -629,7 +621,7 @@ public final class BatteryUsageStats implements Parcelable, Closeable { printPowerComponent(pw, prefix, mBatteryConsumerDataLayout.getPowerComponentName(powerComponent), - devicePowerMah, appsPowerMah, BatteryConsumer.POWER_MODEL_UNDEFINED, + devicePowerMah, appsPowerMah, deviceConsumer.getUsageDurationMillis(powerComponent)); } @@ -716,23 +708,15 @@ public final class BatteryUsageStats implements Parcelable, Closeable { printPowerComponent(pw, prefix, mBatteryConsumerDataLayout.getPowerComponentName(powerComponent), devicePowerMah, appsPowerMah, - mIncludesPowerModels ? deviceConsumer.getPowerModel(powerComponent) - : BatteryConsumer.POWER_MODEL_UNDEFINED, deviceConsumer.getUsageDurationMillis(dimensions)); } } private void printPowerComponent(PrintWriter pw, String prefix, String label, - double devicePowerMah, double appsPowerMah, int powerModel, long durationMs) { + double devicePowerMah, double appsPowerMah, long durationMs) { StringBuilder sb = new StringBuilder(); sb.append(prefix).append(" ").append(label).append(": ") .append(BatteryStats.formatCharge(devicePowerMah)); - if (powerModel != BatteryConsumer.POWER_MODEL_UNDEFINED - && powerModel != BatteryConsumer.POWER_MODEL_POWER_PROFILE) { - sb.append(" ["); - sb.append(BatteryConsumer.powerModelToString(powerModel)); - sb.append("]"); - } sb.append(" apps: ").append(BatteryStats.formatCharge(appsPowerMah)); if (durationMs != 0) { sb.append(" duration: "); @@ -828,7 +812,7 @@ public final class BatteryUsageStats implements Parcelable, Closeable { final boolean includesPowerStateData = parser.getAttributeBoolean(null, XML_ATTR_PREFIX_INCLUDES_POWER_STATE_DATA, false); - builder = new Builder(customComponentNames.toArray(new String[0]), true, + builder = new Builder(customComponentNames.toArray(new String[0]), includesProcStateData, includesScreenStateData, includesPowerStateData, 0); builder.setStatsStartTimestamp( @@ -913,7 +897,6 @@ public final class BatteryUsageStats implements Parcelable, Closeable { private final CursorWindow mBatteryConsumersCursorWindow; @NonNull private final String[] mCustomPowerComponentNames; - private final boolean mIncludePowerModels; private final boolean mIncludesProcessStateData; private final boolean mIncludesScreenStateData; private final boolean mIncludesPowerStateData; @@ -938,22 +921,21 @@ public final class BatteryUsageStats implements Parcelable, Closeable { private BatteryStatsHistory mBatteryStatsHistory; public Builder(@NonNull String[] customPowerComponentNames) { - this(customPowerComponentNames, false, false, false, false, 0); + this(customPowerComponentNames, false, false, false, 0); } - public Builder(@NonNull String[] customPowerComponentNames, boolean includePowerModels, + public Builder(@NonNull String[] customPowerComponentNames, boolean includeProcessStateData, boolean includeScreenStateData, boolean includesPowerStateData, double minConsumedPowerThreshold) { mBatteryConsumersCursorWindow = new CursorWindow(null, BATTERY_CONSUMER_CURSOR_WINDOW_SIZE); onCursorWindowAllocated(mBatteryConsumersCursorWindow); mBatteryConsumerDataLayout = BatteryConsumer.createBatteryConsumerDataLayout( - customPowerComponentNames, includePowerModels, includeProcessStateData, + customPowerComponentNames, includeProcessStateData, includeScreenStateData, includesPowerStateData); mBatteryConsumersCursorWindow.setNumColumns(mBatteryConsumerDataLayout.columnCount); mCustomPowerComponentNames = customPowerComponentNames; - mIncludePowerModels = includePowerModels; mIncludesProcessStateData = includeProcessStateData; mIncludesScreenStateData = includeScreenStateData; mIncludesPowerStateData = includesPowerStateData; diff --git a/core/java/android/os/BatteryUsageStatsQuery.java b/core/java/android/os/BatteryUsageStatsQuery.java index 6325b003a99904d6383128a173e1b1d307764c54..6e67578fadc8b5fb83dd6e6d04b6477d9f63bc60 100644 --- a/core/java/android/os/BatteryUsageStatsQuery.java +++ b/core/java/android/os/BatteryUsageStatsQuery.java @@ -24,6 +24,7 @@ import com.android.internal.os.MonotonicClock; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; +import java.util.Arrays; /** * Query parameters for the {@link BatteryStatsManager#getBatteryUsageStats()} call. @@ -65,12 +66,6 @@ public final class BatteryUsageStatsQuery implements Parcelable { */ public static final int FLAG_BATTERY_USAGE_STATS_INCLUDE_HISTORY = 0x0002; - /** - * Indicates that identifiers of power models used for computations of power - * consumption should be included in the BatteryUsageStats. - */ - public static final int FLAG_BATTERY_USAGE_STATS_INCLUDE_POWER_MODELS = 0x0004; - public static final int FLAG_BATTERY_USAGE_STATS_INCLUDE_PROCESS_STATE_DATA = 0x0008; public static final int FLAG_BATTERY_USAGE_STATS_INCLUDE_VIRTUAL_UIDS = 0x0010; @@ -202,7 +197,24 @@ public final class BatteryUsageStatsQuery implements Parcelable { return mAggregatedToTimestamp; } + @Override + public String toString() { + return "BatteryUsageStatsQuery{" + + "mFlags=" + Integer.toHexString(mFlags) + + ", mUserIds=" + Arrays.toString(mUserIds) + + ", mMaxStatsAgeMs=" + mMaxStatsAgeMs + + ", mAggregatedFromTimestamp=" + mAggregatedFromTimestamp + + ", mAggregatedToTimestamp=" + mAggregatedToTimestamp + + ", mMonotonicStartTime=" + mMonotonicStartTime + + ", mMonotonicEndTime=" + mMonotonicEndTime + + ", mMinConsumedPowerThreshold=" + mMinConsumedPowerThreshold + + ", mPowerComponents=" + Arrays.toString(mPowerComponents) + + '}'; + } + private BatteryUsageStatsQuery(Parcel in) { + mMonotonicStartTime = in.readLong(); + mMonotonicEndTime = in.readLong(); mFlags = in.readInt(); mUserIds = new int[in.readInt()]; in.readIntArray(mUserIds); @@ -215,6 +227,8 @@ public final class BatteryUsageStatsQuery implements Parcelable { @Override public void writeToParcel(Parcel dest, int flags) { + dest.writeLong(mMonotonicStartTime); + dest.writeLong(mMonotonicEndTime); dest.writeInt(mFlags); dest.writeInt(mUserIds.length); dest.writeIntArray(mUserIds); @@ -311,7 +325,10 @@ public final class BatteryUsageStatsQuery implements Parcelable { * power monitoring data is available. * * Should only be used for testing and debugging. + * + * @deprecated PowerModel is no longer supported */ + @Deprecated public Builder powerProfileModeledOnly() { mFlags |= BatteryUsageStatsQuery.FLAG_BATTERY_USAGE_STATS_POWER_PROFILE_MODEL; return this; @@ -322,9 +339,10 @@ public final class BatteryUsageStatsQuery implements Parcelable { * of power consumption. * * Should only be used for testing and debugging. + * @deprecated PowerModel is no longer supported */ + @Deprecated public Builder includePowerModels() { - mFlags |= BatteryUsageStatsQuery.FLAG_BATTERY_USAGE_STATS_INCLUDE_POWER_MODELS; return this; } diff --git a/core/java/android/os/BinderProxy.java b/core/java/android/os/BinderProxy.java index 3b5a99ed089a42f30f2092d35cf58d00e3ec69f6..01222cdd38b37baad2739f896965fe4b8ccb10b2 100644 --- a/core/java/android/os/BinderProxy.java +++ b/core/java/android/os/BinderProxy.java @@ -36,6 +36,7 @@ import java.util.Collections; import java.util.HashMap; import java.util.List; import java.util.Map; +import java.util.concurrent.Executor; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.TimeUnit; @@ -651,28 +652,39 @@ public final class BinderProxy implements IBinder { private native boolean unlinkToDeathNative(DeathRecipient recipient, int flags); /** - * This list is to hold strong reference to the frozen state callbacks. The callbacks are only - * weakly referenced by JNI so the strong references here are needed to keep the callbacks - * around until the proxy is GC'ed. + * This map is to hold strong reference to the frozen state callbacks. + * + * The callbacks are only weakly referenced by JNI so the strong references here are needed to + * keep the callbacks around until the proxy is GC'ed. + * + * The key is the original callback passed into {@link #addFrozenStateChangeCallback}. The value + * is the wrapped callback created in {@link #addFrozenStateChangeCallback} to dispatch the + * calls on the desired executor. */ - private List mFrozenStateChangeCallbacks = - Collections.synchronizedList(new ArrayList<>()); + private Map mFrozenStateChangeCallbacks = + Collections.synchronizedMap(new HashMap<>()); /** * See {@link IBinder#addFrozenStateChangeCallback(FrozenStateChangeCallback)} */ - public void addFrozenStateChangeCallback(FrozenStateChangeCallback callback) + public void addFrozenStateChangeCallback(Executor executor, FrozenStateChangeCallback callback) throws RemoteException { - addFrozenStateChangeCallbackNative(callback); - mFrozenStateChangeCallbacks.add(callback); + FrozenStateChangeCallback wrappedCallback = (who, state) -> + executor.execute(() -> callback.onFrozenStateChanged(who, state)); + addFrozenStateChangeCallbackNative(wrappedCallback); + mFrozenStateChangeCallbacks.put(callback, wrappedCallback); } /** * See {@link IBinder#removeFrozenStateChangeCallback} */ - public boolean removeFrozenStateChangeCallback(FrozenStateChangeCallback callback) { - mFrozenStateChangeCallbacks.remove(callback); - return removeFrozenStateChangeCallbackNative(callback); + public boolean removeFrozenStateChangeCallback(FrozenStateChangeCallback callback) + throws IllegalArgumentException { + FrozenStateChangeCallback wrappedCallback = mFrozenStateChangeCallbacks.remove(callback); + if (wrappedCallback == null) { + throw new IllegalArgumentException("callback not found"); + } + return removeFrozenStateChangeCallbackNative(wrappedCallback); } private native void addFrozenStateChangeCallbackNative(FrozenStateChangeCallback callback) diff --git a/core/java/android/os/CombinedMessageQueue/MessageQueue.java b/core/java/android/os/CombinedMessageQueue/MessageQueue.java index 036ccd84a600dd40fad8ebce3f11e65a593b7be9..476968151e18e8f06d6d8dcb6a7ffbf2c770c47b 100644 --- a/core/java/android/os/CombinedMessageQueue/MessageQueue.java +++ b/core/java/android/os/CombinedMessageQueue/MessageQueue.java @@ -19,8 +19,6 @@ package android.os; import android.annotation.IntDef; import android.annotation.NonNull; 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; @@ -88,14 +86,20 @@ public final class MessageQueue { // queue for async messages when inserting a message at the tail. private int mAsyncMessageCount; - /* + /** * Select between two implementations of message queue. The legacy implementation is used * by default as it provides maximum compatibility with applications and tests that * reach into MessageQueue via the mMessages field. The concurrent implemmentation is used for * system processes and provides a higher level of concurrency and higher enqueue throughput * than the legacy implementation. */ - private boolean mUseConcurrent; + private final boolean mUseConcurrent; + + /** + * Caches process-level checks that determine `mUseConcurrent`. + * This is to avoid redoing checks that shouldn't change during the process's lifetime. + */ + private static Boolean sIsProcessAllowedToUseConcurrent = null; @RavenwoodRedirect private native static long nativeInit(); @@ -112,37 +116,39 @@ public final class MessageQueue { private native static void nativeSetFileDescriptorEvents(long ptr, int fd, int events); MessageQueue(boolean quitAllowed) { - // Concurrent mode modifies behavior that is observable via reflection and is commonly used - // by tests. - // For now, we limit it to system processes to avoid breaking apps and their tests. - mUseConcurrent = UserHandle.isCore(Process.myUid()); - // Even then, we don't use it if instrumentation is loaded as it breaks some - // platform tests. - final Instrumentation instrumentation = getInstrumentation(); - mUseConcurrent &= instrumentation == null || !instrumentation.isInstrumenting(); - // We can lift this restriction in the future after we've made it possible for test authors - // to test Looper and MessageQueue without resorting to reflection. - - // Holdback study. - if (mUseConcurrent && Flags.messageQueueForceLegacy()) { - mUseConcurrent = false; - } + if (sIsProcessAllowedToUseConcurrent == null) { + // Concurrent mode modifies behavior that is observable via reflection and is commonly + // used by tests. + // For now, we limit it to system processes to avoid breaking apps and their tests. + boolean useConcurrent = UserHandle.isCore(Process.myUid()); - mQuitAllowed = quitAllowed; - mPtr = nativeInit(); - } + // Some platform tests run in system UIDs. + // Use this awful heuristic to detect them. + if (useConcurrent) { + final String processName = Process.myProcessName(); + if (processName == null + || processName.contains("test") + || processName.contains("Test")) { + useConcurrent = false; + } + } + + // We can lift this restriction in the future after we've made it possible for test + // authors to test Looper and MessageQueue without resorting to reflection. - @android.ravenwood.annotation.RavenwoodReplace(blockedBy = ActivityThread.class) - private static Instrumentation getInstrumentation() { - final ActivityThread activityThread = ActivityThread.currentActivityThread(); - if (activityThread != null) { - return activityThread.getInstrumentation(); + // Holdback study. + if (useConcurrent && Flags.messageQueueForceLegacy()) { + useConcurrent = false; + } + + sIsProcessAllowedToUseConcurrent = useConcurrent; + mUseConcurrent = useConcurrent; + } else { + mUseConcurrent = sIsProcessAllowedToUseConcurrent; } - return null; - } - private static Instrumentation getInstrumentation$ravenwood() { - return null; // Instrumentation not supported on Ravenwood yet. + mQuitAllowed = quitAllowed; + mPtr = nativeInit(); } @Override diff --git a/core/java/android/os/CpuHeadroomParams.java b/core/java/android/os/CpuHeadroomParams.java index f0d4f7d8737fadf080c20e929853ee8c4bd7fcb4..8e78b7e355f91745c495bcaae2444c5d623d8b32 100644 --- a/core/java/android/os/CpuHeadroomParams.java +++ b/core/java/android/os/CpuHeadroomParams.java @@ -18,10 +18,13 @@ package android.os; import android.annotation.FlaggedApi; import android.annotation.IntDef; +import android.annotation.IntRange; +import android.annotation.NonNull; import android.os.health.SystemHealthManager; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; +import java.util.Arrays; /** * Headroom request params used by {@link SystemHealthManager#getCpuHeadroom(CpuHeadroomParams)}. @@ -53,6 +56,16 @@ public final class CpuHeadroomParams { */ public static final int CPU_HEADROOM_CALCULATION_TYPE_AVERAGE = 1; + /** + * Minimum CPU headroom calculation window size. + */ + public static final int CPU_HEADROOM_CALCULATION_WINDOW_MILLIS_MIN = 50; + + /** + * Maximum CPU headroom calculation window size. + */ + public static final int CPU_HEADROOM_CALCULATION_WINDOW_MILLIS_MAX = 10000; + /** * Sets the headroom calculation type. *

@@ -82,6 +95,63 @@ public final class CpuHeadroomParams { return validatedType; } + /** + * Sets the headroom calculation window size in milliseconds. + *

+ * + * @param windowMillis the window size in milliseconds, ranged from + * [{@link #CPU_HEADROOM_CALCULATION_WINDOW_MILLIS_MIN}, + * {@link #CPU_HEADROOM_CALCULATION_WINDOW_MILLIS_MAX}]. The smaller + * the value, the larger fluctuation in value should be expected. The + * default value can be retrieved from the + * {@link #getCalculationWindowMillis}. The device will try to use the + * closest feasible window size to this param. + * @throws IllegalArgumentException if the window size is not in allowed range. + */ + public void setCalculationWindowMillis( + @IntRange(from = CPU_HEADROOM_CALCULATION_WINDOW_MILLIS_MIN, to = + CPU_HEADROOM_CALCULATION_WINDOW_MILLIS_MAX) int windowMillis) { + if (windowMillis < CPU_HEADROOM_CALCULATION_WINDOW_MILLIS_MIN + || windowMillis > CPU_HEADROOM_CALCULATION_WINDOW_MILLIS_MAX) { + throw new IllegalArgumentException("Invalid calculation window: " + windowMillis); + } + mInternal.calculationWindowMillis = windowMillis; + } + + /** + * Gets the headroom calculation window size in milliseconds. + *

+ * This will return the default value chosen by the device if not set. + */ + public @IntRange(from = CPU_HEADROOM_CALCULATION_WINDOW_MILLIS_MIN, to = + CPU_HEADROOM_CALCULATION_WINDOW_MILLIS_MAX) long getCalculationWindowMillis() { + return mInternal.calculationWindowMillis; + } + + /** + * Sets the thread TIDs to track. + *

+ * The TIDs should belong to the same of the process that will the headroom call. And they + * should not have different core affinity. + *

+ * If not set, the headroom will be based on the PID of the process making the call. + * + * @param tids non-empty list of TIDs, maximum 5. + * @throws IllegalArgumentException if the list size is not in allowed range or TID is not + * positive. + */ + public void setTids(@NonNull int... tids) { + if (tids.length == 0 || tids.length > 5) { + throw new IllegalArgumentException("Invalid number of TIDs: " + tids.length); + } + for (int tid : tids) { + if (tid <= 0) { + throw new IllegalArgumentException("Invalid TID: " + tid); + } + } + mInternal.tids = Arrays.copyOf(tids, tids.length); + } + /** * @hide */ diff --git a/core/java/android/os/CpuHeadroomParamsInternal.aidl b/core/java/android/os/CpuHeadroomParamsInternal.aidl index 6cc4699a809e1705bed50fd3cb663e832177dbd0..d572f965579b71dcff174a645b48b0797b42623c 100644 --- a/core/java/android/os/CpuHeadroomParamsInternal.aidl +++ b/core/java/android/os/CpuHeadroomParamsInternal.aidl @@ -25,6 +25,8 @@ import android.hardware.power.CpuHeadroomParams; @JavaDerive(equals = true, toString = true) parcelable CpuHeadroomParamsInternal { boolean usesDeviceHeadroom = false; + int[] tids; + int calculationWindowMillis = 1000; CpuHeadroomParams.CalculationType calculationType = CpuHeadroomParams.CalculationType.MIN; CpuHeadroomParams.SelectionType selectionType = CpuHeadroomParams.SelectionType.ALL; } diff --git a/core/java/android/os/GpuHeadroomParams.java b/core/java/android/os/GpuHeadroomParams.java index efb2a28ad2b56350a6eb9a35e6ef1f466617180b..4dc98264e57b94df70206eb8b673cb1c4e7ec389 100644 --- a/core/java/android/os/GpuHeadroomParams.java +++ b/core/java/android/os/GpuHeadroomParams.java @@ -18,6 +18,7 @@ package android.os; import android.annotation.FlaggedApi; import android.annotation.IntDef; +import android.annotation.IntRange; import android.os.health.SystemHealthManager; import java.lang.annotation.Retention; @@ -53,6 +54,16 @@ public final class GpuHeadroomParams { */ public static final int GPU_HEADROOM_CALCULATION_TYPE_AVERAGE = 1; + /** + * Minimum GPU headroom calculation window size. + */ + public static final int GPU_HEADROOM_CALCULATION_WINDOW_MILLIS_MIN = 50; + + /** + * Maximum GPU headroom calculation window size. + */ + public static final int GPU_HEADROOM_CALCULATION_WINDOW_MILLIS_MAX = 10000; + /** * Sets the headroom calculation type. *

@@ -82,6 +93,39 @@ public final class GpuHeadroomParams { return validatedType; } + /** + * Sets the headroom calculation window size in milliseconds. + *

+ * + * @param windowMillis the window size in milliseconds, ranged from + * [{@link #GPU_HEADROOM_CALCULATION_WINDOW_MILLIS_MIN}, + * {@link #GPU_HEADROOM_CALCULATION_WINDOW_MILLIS_MAX}]. The smaller + * the value, the larger fluctuation in value should be expected. The + * default value can be retrieved from the + * {@link #getCalculationWindowMillis}. If the device will try to use the + * closest feasible window size to this param. + * @throws IllegalArgumentException if the window is invalid. + */ + public void setCalculationWindowMillis( + @IntRange(from = GPU_HEADROOM_CALCULATION_WINDOW_MILLIS_MIN, to = + GPU_HEADROOM_CALCULATION_WINDOW_MILLIS_MAX) int windowMillis) { + if (windowMillis < GPU_HEADROOM_CALCULATION_WINDOW_MILLIS_MIN + || windowMillis > GPU_HEADROOM_CALCULATION_WINDOW_MILLIS_MAX) { + throw new IllegalArgumentException("Invalid calculation window: " + windowMillis); + } + mInternal.calculationWindowMillis = windowMillis; + } + + /** + * Gets the headroom calculation window size in milliseconds. + *

+ * This will return the default value chosen by the device if not set. + */ + public @IntRange(from = GPU_HEADROOM_CALCULATION_WINDOW_MILLIS_MIN, to = + GPU_HEADROOM_CALCULATION_WINDOW_MILLIS_MAX) int getCalculationWindowMillis() { + return mInternal.calculationWindowMillis; + } + /** * @hide */ diff --git a/core/java/android/os/GpuHeadroomParamsInternal.aidl b/core/java/android/os/GpuHeadroomParamsInternal.aidl index 20309e7673f20b37b41dd3b1cfb55572ebee0c9f..40d5d8e409ef0e7f9b61c4edac0f1193d50a656e 100644 --- a/core/java/android/os/GpuHeadroomParamsInternal.aidl +++ b/core/java/android/os/GpuHeadroomParamsInternal.aidl @@ -24,5 +24,6 @@ import android.hardware.power.GpuHeadroomParams; */ @JavaDerive(equals = true, toString = true) parcelable GpuHeadroomParamsInternal { + int calculationWindowMillis = 1000; GpuHeadroomParams.CalculationType calculationType = GpuHeadroomParams.CalculationType.MIN; } diff --git a/core/java/android/os/IBinder.java b/core/java/android/os/IBinder.java index a997f4c86704d35a7278e1184e297940da2225f7..8cfd32449537beb5f5a101a06c1f6275c642e329 100644 --- a/core/java/android/os/IBinder.java +++ b/core/java/android/os/IBinder.java @@ -16,6 +16,7 @@ package android.os; +import android.annotation.CallbackExecutor; import android.annotation.FlaggedApi; import android.annotation.IntDef; import android.annotation.NonNull; @@ -25,6 +26,7 @@ import android.compat.annotation.UnsupportedAppUsage; import java.io.FileDescriptor; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; +import java.util.concurrent.Executor; /** * Base interface for a remotable object, the core part of a lightweight @@ -397,12 +399,31 @@ public interface IBinder { @interface State { } + /** + * Represents the frozen state of the remote process. + * + * While in this state, the remote process won't be able to receive and handle a + * transaction. Therefore, any asynchronous transactions will be buffered and delivered when + * the process is unfrozen, and any synchronous transactions will result in an error. + * + * Buffered transactions may be stale by the time that the process is unfrozen and handles + * them. To avoid overwhelming the remote process with stale events or overflowing their + * buffers, it's best to avoid sending binder transactions to a frozen process. + */ int STATE_FROZEN = 0; + + /** + * Represents the unfrozen state of the remote process. + * + * In this state, the process hosting the object can execute and is not restricted + * by the freezer from using the CPU or responding to binder transactions. + */ int STATE_UNFROZEN = 1; /** * Interface for receiving a callback when the process hosting an IBinder * has changed its frozen state. + * * @param who The IBinder whose hosting process has changed state. * @param state The latest state. */ @@ -427,15 +448,31 @@ public interface IBinder { *

You will only receive state change notifications for remote binders, as local binders by * definition can't be frozen without you being frozen too.

* + * @param executor The executor on which to run the callback. + * @param callback The callback used to deliver state change notifications. + * *

@throws {@link UnsupportedOperationException} if the kernel binder driver does not support * this feature. */ @FlaggedApi(Flags.FLAG_BINDER_FROZEN_STATE_CHANGE_CALLBACK) - default void addFrozenStateChangeCallback(@NonNull FrozenStateChangeCallback callback) + default void addFrozenStateChangeCallback( + @NonNull @CallbackExecutor Executor executor, + @NonNull FrozenStateChangeCallback callback) throws RemoteException { throw new UnsupportedOperationException(); } + /** + * Same as {@link #addFrozenStateChangeCallback(Executor, FrozenStateChangeCallback)} except + * that callbacks are invoked on a binder thread. + * + * @hide + */ + default void addFrozenStateChangeCallback(@NonNull FrozenStateChangeCallback callback) + throws RemoteException { + addFrozenStateChangeCallback(Runnable::run, callback); + } + /** * Unregister a {@link FrozenStateChangeCallback}. The callback will no longer be invoked when * the hosting process changes its frozen state. diff --git a/core/java/android/os/IHintManager.aidl b/core/java/android/os/IHintManager.aidl index 33120556339f42a4f31db42e0df62b63d58062e9..f1936b5e0ff9b714fdafbc3b3623ebbf3c8e6537 100644 --- a/core/java/android/os/IHintManager.aidl +++ b/core/java/android/os/IHintManager.aidl @@ -20,7 +20,10 @@ package android.os; 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.GpuHeadroomResult; import android.hardware.power.SessionConfig; import android.hardware.power.SessionTag; @@ -34,8 +37,8 @@ interface IHintManager { * Throws UnsupportedOperationException if ADPF is not supported, and IllegalStateException * if creation is supported but fails. */ - IHintSession createHintSessionWithConfig(in IBinder token, in int[] threadIds, - in long durationNanos, in SessionTag tag, out SessionConfig config); + IHintSession createHintSessionWithConfig(in IBinder token, in SessionTag tag, + in SessionCreationConfig creationConfig, out SessionConfig config); /** * Get preferred rate limit in nanoseconds. @@ -52,8 +55,13 @@ interface IHintManager { */ @nullable ChannelConfig getSessionChannel(in IBinder token); oneway void closeSessionChannel(); - float[] getCpuHeadroom(in CpuHeadroomParamsInternal params); + @nullable CpuHeadroomResult getCpuHeadroom(in CpuHeadroomParamsInternal params); long getCpuHeadroomMinIntervalMillis(); - float getGpuHeadroom(in GpuHeadroomParamsInternal params); + @nullable GpuHeadroomResult getGpuHeadroom(in GpuHeadroomParamsInternal params); long getGpuHeadroomMinIntervalMillis(); + + /** + * Get Maximum number of graphics pipeline threads allowed per-app. + */ + int getMaxGraphicsPipelineThreadsCount(); } diff --git a/core/java/android/os/OWNERS b/core/java/android/os/OWNERS index e63b6648a9efd6bd3e592abb7f3f4f2fc988f6fb..f9789c19b0d58dbebec40bb401708d2de957d62a 100644 --- a/core/java/android/os/OWNERS +++ b/core/java/android/os/OWNERS @@ -89,6 +89,10 @@ per-file DdmSyncState.java = sanglardf@google.com, rpaquay@google.com per-file DdmSyncStageUpdater.java = sanglardf@google.com, rpaquay@google.com # PerformanceHintManager +per-file CpuHeadroom*.aidl = file:/ADPF_OWNERS +per-file GpuHeadroom*.aidl = file:/ADPF_OWNERS +per-file CpuHeadroom*.java = file:/ADPF_OWNERS +per-file GpuHeadroom*.java = file:/ADPF_OWNERS per-file PerformanceHintManager.java = file:/ADPF_OWNERS per-file WorkDuration.java = file:/ADPF_OWNERS per-file IHintManager.aidl = file:/ADPF_OWNERS diff --git a/core/java/android/os/PerformanceHintManager.java b/core/java/android/os/PerformanceHintManager.java index 224b10d0eaca2ae1d16f8fafa74bf066bdda3f88..2b0042d653b19e2c73ec6d697caead9aba426c6c 100644 --- a/core/java/android/os/PerformanceHintManager.java +++ b/core/java/android/os/PerformanceHintManager.java @@ -22,6 +22,7 @@ import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.SystemService; import android.annotation.TestApi; +import android.compat.annotation.UnsupportedAppUsage; import android.content.Context; import com.android.internal.util.Preconditions; @@ -106,7 +107,9 @@ public final class PerformanceHintManager { * All timings should be in {@link SystemClock#uptimeNanos()}. */ public static class Session implements Closeable { - private long mNativeSessionPtr; + /** @hide */ + @UnsupportedAppUsage + public long mNativeSessionPtr; /** @hide */ public Session(long nativeSessionPtr) { diff --git a/core/java/android/os/PowerComponents.java b/core/java/android/os/PowerComponents.java index d116e0737c460685f69a408296cf962bd99457d4..4db1f1b32407f5efd3e42c5291a6cdd08204c2c5 100644 --- a/core/java/android/os/PowerComponents.java +++ b/core/java/android/os/PowerComponents.java @@ -15,7 +15,6 @@ */ package android.os; -import static android.os.BatteryConsumer.BatteryConsumerDataLayout.POWER_MODEL_NOT_INCLUDED; import static android.os.BatteryConsumer.POWER_COMPONENT_ANY; import static android.os.BatteryConsumer.POWER_COMPONENT_BASE; import static android.os.BatteryConsumer.POWER_STATE_ANY; @@ -156,15 +155,6 @@ class PowerComponents { return mData.layout.getPowerComponentName(componentId); } - @BatteryConsumer.PowerModel - int getPowerModel(BatteryConsumer.Key key) { - if (key.mPowerModelColumnIndex == POWER_MODEL_NOT_INCLUDED) { - throw new IllegalStateException( - "Power model IDs were not requested in the BatteryUsageStatsQuery"); - } - return mData.getInt(key.mPowerModelColumnIndex); - } - /** * Returns the amount of time used by the specified component, e.g. CPU, WiFi etc. * @@ -378,10 +368,6 @@ class PowerComponents { if (durationMs != 0) { serializer.attributeLong(null, BatteryUsageStats.XML_ATTR_DURATION, durationMs); } - if (mData.layout.powerModelsIncluded) { - serializer.attributeInt(null, BatteryUsageStats.XML_ATTR_MODEL, - getPowerModel(key)); - } serializer.endTag(null, BatteryUsageStats.XML_TAG_COMPONENT); } serializer.endTag(null, BatteryUsageStats.XML_TAG_POWER_COMPONENTS); @@ -411,7 +397,6 @@ class PowerComponents { int powerState = POWER_STATE_UNSPECIFIED; double powerMah = 0; long durationMs = 0; - int model = BatteryConsumer.POWER_MODEL_UNDEFINED; for (int i = 0; i < parser.getAttributeCount(); i++) { switch (parser.getAttributeName(i)) { case BatteryUsageStats.XML_ATTR_ID: @@ -432,14 +417,11 @@ class PowerComponents { case BatteryUsageStats.XML_ATTR_DURATION: durationMs = parser.getAttributeLong(i); break; - case BatteryUsageStats.XML_ATTR_MODEL: - model = parser.getAttributeInt(i); - break; } } final BatteryConsumer.Key key = builder.mData.layout.getKey(componentId, processState, screenState, powerState); - builder.addConsumedPower(key, powerMah, model); + builder.addConsumedPower(key, powerMah); builder.addUsageDurationMillis(key, durationMs); break; } @@ -453,43 +435,28 @@ class PowerComponents { * Builder for PowerComponents. */ static final class Builder { - private static final byte POWER_MODEL_UNINITIALIZED = -1; - private final BatteryConsumer.BatteryConsumerData mData; private final double mMinConsumedPowerThreshold; Builder(BatteryConsumer.BatteryConsumerData data, double minConsumedPowerThreshold) { mData = data; mMinConsumedPowerThreshold = minConsumedPowerThreshold; - for (BatteryConsumer.Key key : mData.layout.keys) { - if (key.mPowerModelColumnIndex != POWER_MODEL_NOT_INCLUDED) { - mData.putInt(key.mPowerModelColumnIndex, POWER_MODEL_UNINITIALIZED); - } - } } /** - * @deprecated use {@link #addConsumedPower(BatteryConsumer.Key, double, int)} + * @deprecated use {@link #addConsumedPower(BatteryConsumer.Key, double)} */ @Deprecated @NonNull - public Builder setConsumedPower(BatteryConsumer.Key key, double componentPower, - int powerModel) { + public Builder setConsumedPower(BatteryConsumer.Key key, double componentPower) { mData.putDouble(key.mPowerColumnIndex, componentPower); - if (key.mPowerModelColumnIndex != POWER_MODEL_NOT_INCLUDED) { - mData.putInt(key.mPowerModelColumnIndex, powerModel); - } return this; } @NonNull - public Builder addConsumedPower(BatteryConsumer.Key key, double componentPower, - int powerModel) { + public Builder addConsumedPower(BatteryConsumer.Key key, double componentPower) { mData.putDouble(key.mPowerColumnIndex, mData.getDouble(key.mPowerColumnIndex) + componentPower); - if (key.mPowerModelColumnIndex != POWER_MODEL_NOT_INCLUDED) { - mData.putInt(key.mPowerModelColumnIndex, powerModel); - } return this; } @@ -547,28 +514,6 @@ class PowerComponents { mData.getLong(key.mDurationColumnIndex) + otherData.getLong(otherKey.mDurationColumnIndex)); } - if (key.mPowerModelColumnIndex == POWER_MODEL_NOT_INCLUDED) { - continue; - } - - boolean undefined = false; - if (otherKey.mPowerModelColumnIndex == POWER_MODEL_NOT_INCLUDED) { - undefined = true; - } else { - final int powerModel = mData.getInt(key.mPowerModelColumnIndex); - int otherPowerModel = otherData.getInt(otherKey.mPowerModelColumnIndex); - if (powerModel == POWER_MODEL_UNINITIALIZED) { - mData.putInt(key.mPowerModelColumnIndex, otherPowerModel); - } else if (powerModel != otherPowerModel - && otherPowerModel != POWER_MODEL_UNINITIALIZED) { - undefined = true; - } - } - - if (undefined) { - mData.putInt(key.mPowerModelColumnIndex, - BatteryConsumer.POWER_MODEL_UNDEFINED); - } } } @@ -594,13 +539,6 @@ class PowerComponents { @NonNull public PowerComponents build() { for (BatteryConsumer.Key key : mData.layout.keys) { - if (key.mPowerModelColumnIndex != POWER_MODEL_NOT_INCLUDED) { - if (mData.getInt(key.mPowerModelColumnIndex) == POWER_MODEL_UNINITIALIZED) { - mData.putInt(key.mPowerModelColumnIndex, - BatteryConsumer.POWER_MODEL_UNDEFINED); - } - } - if (mMinConsumedPowerThreshold != 0) { if (mData.getDouble(key.mPowerColumnIndex) < mMinConsumedPowerThreshold) { mData.putDouble(key.mPowerColumnIndex, 0); diff --git a/core/java/android/os/PowerManager.java b/core/java/android/os/PowerManager.java index 07fded19c79943f8e9e2d706916002b5583cd399..9e7bf47ae83f1ab307a03568cfe0d031541a2b7b 100644 --- a/core/java/android/os/PowerManager.java +++ b/core/java/android/os/PowerManager.java @@ -1823,14 +1823,16 @@ public final class PowerManager { } /** - * Returns the interactive state for a specific display, which may not be the same as the - * global wakefulness (which is true when any display is awake). + * Returns true if the specified display is in an interactive state. This may not be the + * same as the global wakefulness (which is true when any display is interactive). + * @see #isInteractive() * - * @param displayId - * @return whether the given display is present and interactive, or false + * @param displayId The Display ID to check for interactivity. + * @return True if the display is in an interactive state. * * @hide */ + @TestApi public boolean isInteractive(int displayId) { return mInteractiveCache.query(displayId); } diff --git a/core/java/android/os/RemoteCallbackList.java b/core/java/android/os/RemoteCallbackList.java index 91c482faf7d753cb4581e6e5166c7b70bc535f61..4123209eb755837144728740f54ebfae3e3c15e7 100644 --- a/core/java/android/os/RemoteCallbackList.java +++ b/core/java/android/os/RemoteCallbackList.java @@ -16,6 +16,7 @@ package android.os; +import android.annotation.CallbackExecutor; import android.annotation.FlaggedApi; import android.annotation.IntDef; import android.annotation.NonNull; @@ -29,6 +30,7 @@ import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.util.Queue; import java.util.concurrent.ConcurrentLinkedQueue; +import java.util.concurrent.Executor; import java.util.function.BiConsumer; import java.util.function.Consumer; @@ -134,6 +136,7 @@ public class RemoteCallbackList { private final @FrozenCalleePolicy int mFrozenCalleePolicy; private final int mMaxQueueSize; + private final Executor mExecutor; private final class Interface implements IBinder.DeathRecipient, IBinder.FrozenStateChangeCallback { @@ -197,7 +200,7 @@ public class RemoteCallbackList { void maybeSubscribeToFrozenCallback() throws RemoteException { if (mFrozenCalleePolicy != FROZEN_CALLEE_POLICY_UNSET) { try { - mBinder.addFrozenStateChangeCallback(this); + mBinder.addFrozenStateChangeCallback(mExecutor, this); } catch (UnsupportedOperationException e) { // The kernel does not support frozen notifications. In this case we want to // silently fall back to FROZEN_CALLEE_POLICY_UNSET. This is done by simply @@ -211,7 +214,7 @@ public class RemoteCallbackList { if (mFrozenCalleePolicy != FROZEN_CALLEE_POLICY_UNSET) { try { mBinder.removeFrozenStateChangeCallback(this); - } catch (UnsupportedOperationException e) { + } catch (UnsupportedOperationException | IllegalArgumentException e) { // The kernel does not support frozen notifications. Ignore the error and move // on. } @@ -237,6 +240,7 @@ public class RemoteCallbackList { private @FrozenCalleePolicy int mFrozenCalleePolicy; private int mMaxQueueSize = DEFAULT_MAX_QUEUE_SIZE; private InterfaceDiedCallback mInterfaceDiedCallback; + private Executor mExecutor; /** * Creates a Builder for {@link RemoteCallbackList}. @@ -284,6 +288,18 @@ public class RemoteCallbackList { return this; } + /** + * Sets the executor to be used when invoking callbacks asynchronously. + * + * This is only used when callbacks need to be invoked asynchronously, e.g. when the process + * hosting a callback becomes unfrozen. Callbacks that can be invoked immediately run on the + * same thread that calls {@link #broadcast} synchronously. + */ + public @NonNull Builder setExecutor(@NonNull @CallbackExecutor Executor executor) { + mExecutor = executor; + return this; + } + /** * For notifying when the process hosting a callback interface has died. * @@ -308,15 +324,21 @@ public class RemoteCallbackList { * @return The built {@link RemoteCallbackList} object. */ public @NonNull RemoteCallbackList build() { + Executor executor = mExecutor; + if (executor == null && mFrozenCalleePolicy != FROZEN_CALLEE_POLICY_UNSET) { + // TODO Throw an exception here once the existing API caller is updated to provide + // an executor. + executor = new HandlerExecutor(Handler.getMain()); + } if (mInterfaceDiedCallback != null) { - return new RemoteCallbackList(mFrozenCalleePolicy, mMaxQueueSize) { + return new RemoteCallbackList(mFrozenCalleePolicy, mMaxQueueSize, executor) { @Override public void onCallbackDied(E deadInterface, Object cookie) { mInterfaceDiedCallback.onInterfaceDied(this, deadInterface, cookie); } }; } - return new RemoteCallbackList(mFrozenCalleePolicy, mMaxQueueSize); + return new RemoteCallbackList(mFrozenCalleePolicy, mMaxQueueSize, executor); } } @@ -340,6 +362,16 @@ public class RemoteCallbackList { return mMaxQueueSize; } + /** + * Returns the executor used when invoking callbacks asynchronously. + * + * @return The executor. + */ + @FlaggedApi(Flags.FLAG_BINDER_FROZEN_STATE_CHANGE_CALLBACK) + public @Nullable Executor getExecutor() { + return mExecutor; + } + /** * Creates a RemoteCallbackList with {@link #FROZEN_CALLEE_POLICY_UNSET}. This is equivalent to *

@@ -347,7 +379,7 @@ public class RemoteCallbackList {
      * 
*/ public RemoteCallbackList() { - this(FROZEN_CALLEE_POLICY_UNSET, DEFAULT_MAX_QUEUE_SIZE); + this(FROZEN_CALLEE_POLICY_UNSET, DEFAULT_MAX_QUEUE_SIZE, null); } /** @@ -362,10 +394,14 @@ public class RemoteCallbackList { * recipient's process is frozen. Once the limit is reached, the oldest callbacks would be * dropped to keep the size under limit. Ignored except for * {@link #FROZEN_CALLEE_POLICY_ENQUEUE_ALL}. + * + * @param executor The executor used when invoking callbacks asynchronously. */ - private RemoteCallbackList(@FrozenCalleePolicy int frozenCalleePolicy, int maxQueueSize) { + private RemoteCallbackList(@FrozenCalleePolicy int frozenCalleePolicy, int maxQueueSize, + @CallbackExecutor Executor executor) { mFrozenCalleePolicy = frozenCalleePolicy; mMaxQueueSize = maxQueueSize; + mExecutor = executor; } /** diff --git a/core/java/android/os/SessionCreationConfig.aidl b/core/java/android/os/SessionCreationConfig.aidl new file mode 100644 index 0000000000000000000000000000000000000000..cdc0ef461e0cf8766e7fa499d10046dd79ea4d87 --- /dev/null +++ b/core/java/android/os/SessionCreationConfig.aidl @@ -0,0 +1,39 @@ +/* + * + * 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.os; + +import android.hardware.power.SessionTag; +import android.hardware.power.SessionMode; + +/** {@hide} */ +parcelable SessionCreationConfig { + /** + * List of tids to be included in the hint session. + */ + int[] tids; + + /** + * The initial target work duration of this hint session in nanoseconds. + */ + long targetWorkDurationNanos; + + /** + * List of the modes to be enabled upon session creation. + */ + SessionMode[] modesToEnable; +} diff --git a/core/java/android/os/UserManager.java b/core/java/android/os/UserManager.java index 5a53bc1552b84ce43a1316c8205ffd423029b457..a1ede5fee3f307f32eae2d1480d1c992d820f5b0 100644 --- a/core/java/android/os/UserManager.java +++ b/core/java/android/os/UserManager.java @@ -3878,7 +3878,11 @@ public class UserManager { Manifest.permission.MANAGE_USERS, Manifest.permission.CREATE_USERS, Manifest.permission.QUERY_USERS}) + @CachedProperty(api = "user_manager_user_data") public UserInfo getUserInfo(@UserIdInt int userId) { + if (android.multiuser.Flags.cacheUserInfoReadOnly()) { + return UserManagerCache.getUserInfo(mService::getUserInfo, userId); + } try { return mService.getUserInfo(userId); } catch (RemoteException re) { diff --git a/core/java/android/os/VibrationEffect.java b/core/java/android/os/VibrationEffect.java index f6bc3894be4bad0f9d14cd634e209694149edc39..0a0e80614fa79073e42b827532927cb8dfee6190 100644 --- a/core/java/android/os/VibrationEffect.java +++ b/core/java/android/os/VibrationEffect.java @@ -18,6 +18,7 @@ package android.os; import static android.os.vibrator.Flags.FLAG_VENDOR_VIBRATION_EFFECTS; +import android.annotation.DurationMillisLong; import android.annotation.FlaggedApi; import android.annotation.FloatRange; import android.annotation.IntDef; @@ -34,6 +35,7 @@ import android.hardware.vibrator.IVibrator; import android.hardware.vibrator.V1_0.EffectStrength; import android.hardware.vibrator.V1_3.Effect; import android.net.Uri; +import android.os.vibrator.BasicPwleSegment; import android.os.vibrator.Flags; import android.os.vibrator.PrebakedSegment; import android.os.vibrator.PrimitiveSegment; @@ -1713,10 +1715,13 @@ public abstract class VibrationEffect implements Parcelable { /** * Add a haptic primitive to the end of the current composition. * + *

Similar to {@link #addPrimitive(int, float, int, int)}, but default + * delay type applied is {@link #DELAY_TYPE_PAUSE}. + * * @param primitiveId The primitive to add * @param scale The scale to apply to the intensity of the primitive. - * @param delay The amount of time in milliseconds to wait before playing this primitive, - * starting at the time the previous element in this composition is finished. + * @param delay The amount of time in milliseconds to wait between the end of the last + * primitive and the beginning of this one (i.e. a pause in the composition). * @return This {@link Composition} object to enable adding multiple elements in one chain. */ @NonNull @@ -1843,6 +1848,8 @@ public abstract class VibrationEffect implements Parcelable { * .build(); * } * + *

The builder automatically starts all effects at 0 amplitude. + * *

It is crucial to ensure that the frequency range used in your effect is compatible with * the device's capabilities. The framework will not play any frequencies that fall partially * or completely outside the device's supported range. It will also not attempt to correct or @@ -1908,7 +1915,7 @@ public abstract class VibrationEffect implements Parcelable { firstSegment.getEndAmplitude(), initialFrequencyHz, // Update start frequency firstSegment.getEndFrequencyHz(), - (int) firstSegment.getDuration())); + firstSegment.getDuration())); } return this; @@ -1930,25 +1937,26 @@ public abstract class VibrationEffect implements Parcelable { * transition as quickly as possible, use * {@link VibratorEnvelopeEffectInfo#getMinControlPointDurationMillis()}. * - * @param amplitude The amplitude value between 0 and 1, inclusive. 0 represents the - * vibrator being off, and 1 represents the maximum achievable amplitude - * at this frequency. - * @param frequencyHz The frequency in Hz, must be greater than zero. - * @param timeMillis The transition time in milliseconds. + * @param amplitude The amplitude value between 0 and 1, inclusive. 0 represents the + * vibrator being off, and 1 represents the maximum achievable + * amplitude + * at this frequency. + * @param frequencyHz The frequency in Hz, must be greater than zero. + * @param durationMillis The transition time in milliseconds. */ @FlaggedApi(Flags.FLAG_NORMALIZED_PWLE_EFFECTS) @SuppressWarnings("MissingGetterMatchingBuilder") // No getters to segments once created. @NonNull public WaveformEnvelopeBuilder addControlPoint( @FloatRange(from = 0, to = 1) float amplitude, - @FloatRange(from = 0) float frequencyHz, int timeMillis) { + @FloatRange(from = 0) float frequencyHz, @DurationMillisLong long durationMillis) { if (Float.isNaN(mLastFrequencyHz)) { mLastFrequencyHz = frequencyHz; } mSegments.add(new PwleSegment(mLastAmplitude, amplitude, mLastFrequencyHz, frequencyHz, - timeMillis)); + durationMillis)); mLastAmplitude = amplitude; mLastFrequencyHz = frequencyHz; @@ -1979,6 +1987,168 @@ public abstract class VibrationEffect implements Parcelable { } } + /** + * A builder for waveform effects defined by their envelope, designed to provide a consistent + * haptic perception across devices with varying capabilities. + * + *

This builder simplifies the creation of waveform effects by automatically adapting them + * to different devices based on their capabilities. Effects are defined by control points + * specifying target vibration intensity and sharpness, along with durations to reach those + * targets. The vibrator will smoothly transition between these control points. + * + *

Intensity: Defines the overall strength of the vibration, ranging from + * 0 (off) to 1 (maximum achievable strength). Higher values result in stronger + * vibrations. Supported intensity values guarantee sensitivity levels (SL) above + * 10 dB SL to ensure human perception. + * + *

Sharpness: Defines the crispness of the vibration, ranging from 0 to 1. + * Lower values produce smoother vibrations, while higher values create a sharper, + * more snappy sensation. Sharpness is mapped to its equivalent frequency within + * the device's supported frequency range. + * + *

While this builder handles most of the adaptation logic, it does come with some + * limitations: + *

    + *
  • It may not use the full range of frequencies
  • + *
  • It's restricted to a frequency range that can generate output of at least 10 db + * SL
  • + *
  • Effects must end with a zero intensity control point. Failure to end at a zero + * intensity control point will result in an {@link IllegalStateException}.
  • + *
+ * + *

The builder automatically starts all effects at 0 intensity. + * + *

To avoid these limitations and to have more control over the effects output, use + * {@link WaveformEnvelopeBuilder}, where direct amplitude and frequency values can be used. + * + *

For optimal cross-device consistency, it's recommended to limit the number of control + * points to a maximum of 16. However this is not mandatory, and if a pattern exceeds the + * maximum number of allowed control points, the framework will automatically break down the + * effect to ensure it plays correctly. + * + *

For example, the following code creates a vibration effect that ramps up the intensity + * from a low-pitched to a high-pitched strong vibration over 500ms and then ramps it down to + * 0 (off) over 100ms: + * + *

{@code
+     * VibrationEffect effect = new VibrationEffect.BasicEnvelopeBuilder()
+     *     .setInitialSharpness(0.0f)
+     *     .addControlPoint(1.0f, 1.0f, 500)
+     *     .addControlPoint(0.0f, 1.0f, 100)
+     *     .build();
+     * }
+ */ + @FlaggedApi(Flags.FLAG_NORMALIZED_PWLE_EFFECTS) + public static final class BasicEnvelopeBuilder { + + private ArrayList mSegments = new ArrayList<>(); + private float mLastIntensity = 0f; + private float mLastSharpness = Float.NaN; + + public BasicEnvelopeBuilder() {} + + /** + * Sets the initial sharpness for the basic envelope effect. + * + *

The effect will start vibrating at this sharpness when it transitions to the + * intensity and sharpness defined by the first control point. + * + *

The sharpness defines the crispness of the vibration, ranging from 0 to 1. Lower + * values translate to smoother vibrations, while higher values create a sharper more snappy + * sensation. This value is mapped to the supported frequency range of the device. + * + * @param initialSharpness The starting sharpness of the vibration in the range of [0, 1]. + */ + @FlaggedApi(Flags.FLAG_NORMALIZED_PWLE_EFFECTS) + @SuppressWarnings("MissingGetterMatchingBuilder")// No getter to initial sharpness once set. + @NonNull + public BasicEnvelopeBuilder setInitialSharpness( + @FloatRange(from = 0, to = 1) float initialSharpness) { + + if (mSegments.isEmpty()) { + mLastSharpness = initialSharpness; + } else { + BasicPwleSegment firstSegment = mSegments.getFirst(); + mSegments.set(0, new BasicPwleSegment( + firstSegment.getStartIntensity(), + firstSegment.getEndIntensity(), + initialSharpness, // Update start sharpness + firstSegment.getEndSharpness(), + firstSegment.getDuration())); + } + + return this; + } + + /** + * Adds a new control point to the end of this waveform envelope. + * + *

Intensity defines the overall strength of the vibration, ranging from 0 (off) to 1 + * (maximum achievable strength). Higher values translate to stronger vibrations. + * + *

Sharpness defines the crispness of the vibration, ranging from 0 to 1. Lower + * values translate to smoother vibrations, while higher values create a sharper more snappy + * sensation. This value is mapped to the supported frequency range of the device. + * + *

Time specifies the duration (in milliseconds) for the vibrator to smoothly transition + * from the previous control point to this new one. It must be greater than zero. To + * transition as quickly as possible, use + * {@link VibratorEnvelopeEffectInfo#getMinControlPointDurationMillis()}. + * + * @param intensity The target vibration intensity, ranging from 0 (off) to 1 (maximum + * strength). + * @param sharpness The target sharpness, ranging from 0 (smoothest) to 1 (sharpest). + * @param durationMillis The transition time in milliseconds. + */ + @FlaggedApi(Flags.FLAG_NORMALIZED_PWLE_EFFECTS) + @SuppressWarnings("MissingGetterMatchingBuilder") // No getters to segments once created. + @NonNull + public BasicEnvelopeBuilder addControlPoint( + @FloatRange(from = 0, to = 1) float intensity, + @FloatRange(from = 0, to = 1) float sharpness, + @DurationMillisLong long durationMillis) { + + if (Float.isNaN(mLastSharpness)) { + mLastSharpness = sharpness; + } + + mSegments.add(new BasicPwleSegment(mLastIntensity, intensity, mLastSharpness, sharpness, + durationMillis)); + + mLastIntensity = intensity; + mLastSharpness = sharpness; + + return this; + } + + /** + * Build the waveform as a single {@link VibrationEffect}. + * + *

The {@link BasicEnvelopeBuilder} object is still valid after this call, so you can + * continue adding more primitives to it and generating more {@link VibrationEffect}s by + * calling this method again. + * + * @return The {@link VibrationEffect} resulting from the list of control points. + * @throws IllegalStateException if the last control point does not end at zero intensity. + */ + @FlaggedApi(Flags.FLAG_NORMALIZED_PWLE_EFFECTS) + @NonNull + public VibrationEffect build() { + if (mSegments.isEmpty()) { + throw new IllegalStateException( + "BasicEnvelopeBuilder must have at least one control point to build."); + } + if (mSegments.getLast().getEndIntensity() != 0) { + throw new IllegalStateException( + "Basic envelope effects must end at a zero intensity control point."); + } + VibrationEffect effect = new Composed(mSegments, /* repeatIndex= */ -1); + effect.validate(); + return effect; + } + + } + /** * A builder for waveform haptic effects. * diff --git a/core/java/android/os/flags.aconfig b/core/java/android/os/flags.aconfig index 9b1bf057b81574654ec1e193be7eb79a36df77e7..3001fbd4fafa3ceee54badf4daaceb52fab11e63 100644 --- a/core/java/android/os/flags.aconfig +++ b/core/java/android/os/flags.aconfig @@ -20,6 +20,15 @@ flag { bug: "284324521" } +flag { + name: "adpf_graphics_pipeline" + is_exported: true + namespace: "game" + description: "Guards use of SessionCreationConfig and Graphics Pipeline mode" + is_fixed_read_only: true + bug: "367803904" +} + flag { name: "adpf_hwui_gpu" namespace: "game" @@ -221,6 +230,15 @@ flag { is_fixed_read_only: true } +flag { + name: "message_queue_testability" + namespace: "system_performance" + is_exported: true + description: "Whether MessageQueue implements test APIs." + bug: "379472827" + is_fixed_read_only: true +} + flag { name: "network_time_uses_shared_memory" namespace: "system_performance" diff --git a/core/java/android/os/health/SystemHealthManager.java b/core/java/android/os/health/SystemHealthManager.java index 4db9bc333e2bff9a872edf3a02fd018cdfcfa673..cd79e416531a866e2fc000a554628881271ef2e7 100644 --- a/core/java/android/os/health/SystemHealthManager.java +++ b/core/java/android/os/health/SystemHealthManager.java @@ -23,6 +23,8 @@ import android.annotation.Nullable; import android.annotation.SystemService; import android.compat.annotation.UnsupportedAppUsage; import android.content.Context; +import android.hardware.power.CpuHeadroomResult; +import android.hardware.power.GpuHeadroomResult; import android.os.BatteryStats; import android.os.Build; import android.os.Bundle; @@ -110,15 +112,16 @@ public class SystemHealthManager { } /** - * Provides an estimate of global available CPU headroom of the calling thread. + * Provides an estimate of global available CPU headroom. *

* * @param params params to customize the CPU headroom calculation, null to use default params. - * @return a single value a {@code Float.NaN} if it's temporarily unavailable. + * @return a single value headroom or a {@code Float.NaN} if it's temporarily unavailable. * A valid value is ranged from [0, 100], where 0 indicates no more CPU resources can be * granted. - * @throws UnsupportedOperationException if the API is unsupported or the request params can't - * be served. + * @throws UnsupportedOperationException if the API is unsupported. + * @throws SecurityException if the TIDs of the params don't belong to the same process. + * @throws IllegalStateException if the TIDs of the params don't have the same affinity setting. */ @FlaggedApi(android.os.Flags.FLAG_CPU_GPU_HEADROOMS) public @FloatRange(from = 0f, to = 100f) float getCpuHeadroom( @@ -127,8 +130,12 @@ public class SystemHealthManager { throw new UnsupportedOperationException(); } try { - return mHintManager.getCpuHeadroom( - params != null ? params.getInternal() : new CpuHeadroomParamsInternal())[0]; + final CpuHeadroomResult ret = mHintManager.getCpuHeadroom( + params != null ? params.getInternal() : new CpuHeadroomParamsInternal()); + if (ret == null || ret.getTag() != CpuHeadroomResult.globalHeadroom) { + return Float.NaN; + } + return ret.getGlobalHeadroom(); } catch (RemoteException re) { throw re.rethrowFromSystemServer(); } @@ -144,8 +151,7 @@ public class SystemHealthManager { * @return a single value headroom or a {@code Float.NaN} if it's temporarily unavailable. * A valid value is ranged from [0, 100], where 0 indicates no more GPU resources can be * granted. - * @throws UnsupportedOperationException if the API is unsupported or the request params can't - * be served. + * @throws UnsupportedOperationException if the API is unsupported. */ @FlaggedApi(android.os.Flags.FLAG_CPU_GPU_HEADROOMS) public @FloatRange(from = 0f, to = 100f) float getGpuHeadroom( @@ -154,8 +160,12 @@ public class SystemHealthManager { throw new UnsupportedOperationException(); } try { - return mHintManager.getGpuHeadroom( + final GpuHeadroomResult ret = mHintManager.getGpuHeadroom( params != null ? params.getInternal() : new GpuHeadroomParamsInternal()); + if (ret == null || ret.getTag() != GpuHeadroomResult.globalHeadroom) { + return Float.NaN; + } + return ret.getGlobalHeadroom(); } catch (RemoteException re) { throw re.rethrowFromSystemServer(); } diff --git a/core/java/android/os/vibrator/BasicPwleSegment.java b/core/java/android/os/vibrator/BasicPwleSegment.java new file mode 100644 index 0000000000000000000000000000000000000000..ed68173404a122be50c265f161a60821a420bc20 --- /dev/null +++ b/core/java/android/os/vibrator/BasicPwleSegment.java @@ -0,0 +1,222 @@ +/* + * 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.vibrator; + +import android.annotation.FlaggedApi; +import android.annotation.NonNull; +import android.annotation.TestApi; +import android.os.Parcel; +import android.os.VibrationEffect; +import android.os.VibratorInfo; + +import com.android.internal.util.Preconditions; + +import java.util.Locale; +import java.util.Objects; + +/** + * A {@link VibrationEffectSegment} that represents a smooth transition from the starting + * intensity and sharpness to new values over a specified duration. + * + *

The intensity and sharpness are expressed by float values in the range [0, 1], where + * intensity represents the user-perceived strength of the vibration, while sharpness represents + * the crispness of the vibration. + * + * @hide + */ +@TestApi +@FlaggedApi(Flags.FLAG_NORMALIZED_PWLE_EFFECTS) +public final class BasicPwleSegment extends VibrationEffectSegment { + private final float mStartIntensity; + private final float mEndIntensity; + private final float mStartSharpness; + private final float mEndSharpness; + private final long mDuration; + + BasicPwleSegment(@NonNull Parcel in) { + this(in.readFloat(), in.readFloat(), in.readFloat(), in.readFloat(), in.readLong()); + } + + /** @hide */ + @FlaggedApi(Flags.FLAG_NORMALIZED_PWLE_EFFECTS) + public BasicPwleSegment(float startIntensity, float endIntensity, float startSharpness, + float endSharpness, long duration) { + mStartIntensity = startIntensity; + mEndIntensity = endIntensity; + mStartSharpness = startSharpness; + mEndSharpness = endSharpness; + mDuration = duration; + } + + public float getStartIntensity() { + return mStartIntensity; + } + + public float getEndIntensity() { + return mEndIntensity; + } + + public float getStartSharpness() { + return mStartSharpness; + } + + public float getEndSharpness() { + return mEndSharpness; + } + + @Override + public long getDuration() { + return mDuration; + } + + @Override + public boolean equals(Object o) { + if (!(o instanceof BasicPwleSegment)) { + return false; + } + BasicPwleSegment other = (BasicPwleSegment) o; + return Float.compare(mStartIntensity, other.mStartIntensity) == 0 + && Float.compare(mEndIntensity, other.mEndIntensity) == 0 + && Float.compare(mStartSharpness, other.mStartSharpness) == 0 + && Float.compare(mEndSharpness, other.mEndSharpness) == 0 + && mDuration == other.mDuration; + } + + /** @hide */ + @Override + public boolean areVibrationFeaturesSupported(@NonNull VibratorInfo vibratorInfo) { + return vibratorInfo.areEnvelopeEffectsSupported(); + } + + /** @hide */ + @Override + public boolean isHapticFeedbackCandidate() { + return true; + } + + /** @hide */ + @Override + public void validate() { + Preconditions.checkArgumentInRange(mStartSharpness, 0f, 1f, "startSharpness"); + Preconditions.checkArgumentInRange(mEndSharpness, 0f, 1f, "endSharpness"); + Preconditions.checkArgumentInRange(mStartIntensity, 0f, 1f, "startIntensity"); + Preconditions.checkArgumentInRange(mEndIntensity, 0f, 1f, "endIntensity"); + Preconditions.checkArgumentPositive(mDuration, "Time must be greater than zero."); + } + + /** @hide */ + @NonNull + @Override + public BasicPwleSegment resolve(int defaultAmplitude) { + return this; + } + + /** @hide */ + @NonNull + @Override + public BasicPwleSegment scale(float scaleFactor) { + float newStartIntensity = VibrationEffect.scale(mStartIntensity, scaleFactor); + float newEndIntensity = VibrationEffect.scale(mEndIntensity, scaleFactor); + if (Float.compare(mStartIntensity, newStartIntensity) == 0 + && Float.compare(mEndIntensity, newEndIntensity) == 0) { + return this; + } + return new BasicPwleSegment(newStartIntensity, newEndIntensity, mStartSharpness, + mEndSharpness, + mDuration); + } + + /** @hide */ + @NonNull + @Override + public BasicPwleSegment scaleLinearly(float scaleFactor) { + float newStartIntensity = VibrationEffect.scaleLinearly(mStartIntensity, scaleFactor); + float newEndIntensity = VibrationEffect.scaleLinearly(mEndIntensity, scaleFactor); + if (Float.compare(mStartIntensity, newStartIntensity) == 0 + && Float.compare(mEndIntensity, newEndIntensity) == 0) { + return this; + } + return new BasicPwleSegment(newStartIntensity, newEndIntensity, mStartSharpness, + mEndSharpness, + mDuration); + } + + /** @hide */ + @NonNull + @Override + public BasicPwleSegment applyEffectStrength(int effectStrength) { + return this; + } + + @Override + public int hashCode() { + return Objects.hash(mStartIntensity, mEndIntensity, mStartSharpness, mEndSharpness, + mDuration); + } + + @Override + public String toString() { + return "BasicPwle{startIntensity=" + mStartIntensity + + ", endIntensity=" + mEndIntensity + + ", startSharpness=" + mStartSharpness + + ", endSharpness=" + mEndSharpness + + ", duration=" + mDuration + + "}"; + } + + /** @hide */ + @Override + public String toDebugString() { + return String.format(Locale.US, "Pwle=%dms(intensity=%.2f @ %.2f to %.2f @ %.2f)", + mDuration, + mStartIntensity, + mStartSharpness, + mEndIntensity, + mEndSharpness); + } + + @Override + public int describeContents() { + return 0; + } + + @Override + public void writeToParcel(@NonNull Parcel dest, int flags) { + dest.writeInt(PARCEL_TOKEN_PWLE); + dest.writeFloat(mStartIntensity); + dest.writeFloat(mEndIntensity); + dest.writeFloat(mStartSharpness); + dest.writeFloat(mEndSharpness); + dest.writeLong(mDuration); + } + + @NonNull + public static final Creator CREATOR = + new Creator() { + @Override + public BasicPwleSegment createFromParcel(Parcel in) { + // Skip the type token + in.readInt(); + return new BasicPwleSegment(in); + } + + @Override + public BasicPwleSegment[] newArray(int size) { + return new BasicPwleSegment[size]; + } + }; +} diff --git a/core/java/android/os/vibrator/PwlePoint.java b/core/java/android/os/vibrator/PwlePoint.java index ea3ae6c4649dd41f477278a4b095d752db64a093..4be5c681f70891832abc4f0f7bd6d41243de2acc 100644 --- a/core/java/android/os/vibrator/PwlePoint.java +++ b/core/java/android/os/vibrator/PwlePoint.java @@ -63,4 +63,12 @@ public final class PwlePoint { public int hashCode() { return Objects.hash(mAmplitude, mFrequencyHz, mTimeMillis); } + + @Override + public String toString() { + return "PwlePoint{amplitude=" + mAmplitude + + ", frequency=" + mFrequencyHz + + ", time=" + mTimeMillis + + "}"; + } } diff --git a/core/java/android/os/vibrator/PwleSegment.java b/core/java/android/os/vibrator/PwleSegment.java index 9074bde19321f05790d34c1397390b798fe952fa..942b7b3e524de1237329273ece476f8aabef9220 100644 --- a/core/java/android/os/vibrator/PwleSegment.java +++ b/core/java/android/os/vibrator/PwleSegment.java @@ -44,16 +44,16 @@ public final class PwleSegment extends VibrationEffectSegment { private final float mStartFrequencyHz; private final float mEndAmplitude; private final float mEndFrequencyHz; - private final int mDuration; + private final long mDuration; PwleSegment(@android.annotation.NonNull Parcel in) { - this(in.readFloat(), in.readFloat(), in.readFloat(), in.readFloat(), in.readInt()); + this(in.readFloat(), in.readFloat(), in.readFloat(), in.readFloat(), in.readLong()); } /** @hide */ @FlaggedApi(Flags.FLAG_NORMALIZED_PWLE_EFFECTS) public PwleSegment(float startAmplitude, float endAmplitude, float startFrequencyHz, - float endFrequencyHz, int duration) { + float endFrequencyHz, long duration) { mStartAmplitude = startAmplitude; mEndAmplitude = endAmplitude; mStartFrequencyHz = startFrequencyHz; @@ -213,7 +213,7 @@ public final class PwleSegment extends VibrationEffectSegment { dest.writeFloat(mEndAmplitude); dest.writeFloat(mStartFrequencyHz); dest.writeFloat(mEndFrequencyHz); - dest.writeInt(mDuration); + dest.writeLong(mDuration); } @android.annotation.NonNull diff --git a/core/java/android/os/vibrator/VibrationEffectSegment.java b/core/java/android/os/vibrator/VibrationEffectSegment.java index b934e11415d1108a67950adc7138e589ac3f4dde..325a058e3aa30b2be2f28a0075814f7f1538bb95 100644 --- a/core/java/android/os/vibrator/VibrationEffectSegment.java +++ b/core/java/android/os/vibrator/VibrationEffectSegment.java @@ -47,6 +47,7 @@ public abstract class VibrationEffectSegment implements Parcelable { static final int PARCEL_TOKEN_STEP = 3; static final int PARCEL_TOKEN_RAMP = 4; static final int PARCEL_TOKEN_PWLE = 5; + static final int PARCEL_TOKEN_BASIC_PWLE = 6; /** Prevent subclassing from outside of this package */ VibrationEffectSegment() { @@ -228,7 +229,12 @@ public abstract class VibrationEffectSegment implements Parcelable { if (Flags.normalizedPwleEffects()) { return new PwleSegment(in); } - // Fall through if the flag is not enabled. + // Fall through to default if the flag is not enabled. + case PARCEL_TOKEN_BASIC_PWLE: + if (Flags.normalizedPwleEffects()) { + return new BasicPwleSegment(in); + } + // Fall through to default if the flag is not enabled. default: throw new IllegalStateException( "Unexpected vibration event type token in parcel."); diff --git a/core/java/android/permission/flags.aconfig b/core/java/android/permission/flags.aconfig index 0a35fe3995318d505d6ea18f006d506d92e89fd2..a7195834e6bb08005dbac3f4728da42f57f9fece 100644 --- a/core/java/android/permission/flags.aconfig +++ b/core/java/android/permission/flags.aconfig @@ -58,7 +58,7 @@ flag { is_fixed_read_only: true namespace: "permissions" description: "enable enhanced confirmation incall apis" - bug: "310220212" + bug: "364535720" } flag { @@ -67,7 +67,7 @@ flag { is_fixed_read_only: true namespace: "permissions" description: "enable the blocking of certain app installs during an unknown call" - bug: "310220212" + bug: "364535720" } flag { @@ -383,7 +383,7 @@ flag { bug: "363318732" } -flag{ +flag { name: "note_op_batching_enabled" is_fixed_read_only: true is_exported: true @@ -409,3 +409,39 @@ flag { description: "This flag is used to short circuit the request for permananently denied permissions" bug: "378923900" } + +flag { + name: "check_op_overload_api_enabled" + is_exported: true + is_fixed_read_only: true + namespace: "permissions" + description: "Add new checkOp APIs that accept attributionTag" + bug: "240617242" +} + +flag { + name: "device_policy_management_role_split_create_managed_profile_enabled" + is_fixed_read_only: true + is_exported: true + namespace: "enterprise" + description: "Gives the device policy management role the ability to create a managed profile using new APIs" + bug: "375382324" +} + +flag { + name: "use_profile_labels_for_default_app_section_titles" + is_exported: true + is_fixed_read_only: true + namespace: "profile_experiences" + description: "Use profile labels from UserManager for default app section titles to allow partner customization" + bug: "358369931" +} + +flag { + name: "wallet_role_cross_user_enabled" + is_exported: true + is_fixed_read_only: true + namespace: "wallet_integration" + description: "Enable the Wallet role within profiles" + bug: "356107987" +} diff --git a/core/java/android/provider/ContactsContract.java b/core/java/android/provider/ContactsContract.java index 1b289fdabbd1e2de4fa63f9898fb1a3e2b94d973..99ff38b43adcf06f468d07cf21b7629d35937476 100644 --- a/core/java/android/provider/ContactsContract.java +++ b/core/java/android/provider/ContactsContract.java @@ -3151,7 +3151,7 @@ public final class ContactsContract { * {@link #DEFAULT_ACCOUNT_STATE_CLOUD} or * {@link #DEFAULT_ACCOUNT_STATE_SIM}, or null otherwise. */ - public DefaultAccountAndState(@DefaultAccountState int state, + private DefaultAccountAndState(@DefaultAccountState int state, @Nullable Account account) { if (!isValidDefaultAccountState(state)) { throw new IllegalArgumentException("Invalid default account state."); diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java index a35c9c1cd4ece87f7553eb9364c9ca965f6f0298..d5b525884ac181156ac58e812f8b6a5e6c42e2ac 100644 --- a/core/java/android/provider/Settings.java +++ b/core/java/android/provider/Settings.java @@ -6270,6 +6270,14 @@ public final class Settings { */ public static final String TOUCHPAD_TAP_DRAGGING = "touchpad_tap_dragging"; + /** + * Whether to enable three finger tap customization on touchpads. + * + * @hide + */ + public static final String TOUCHPAD_THREE_FINGER_TAP_CUSTOMIZATION = + "touchpad_three_finger_tap_customization"; + /** * Whether to enable a right-click zone on touchpads. * @@ -10990,6 +10998,25 @@ public final class Settings { public static final String EMERGENCY_GESTURE_UI_LAST_STARTED_MILLIS = "emergency_gesture_ui_last_started_millis"; + /** + * Whether double tap the power button gesture is enabled. + * + * @hide + */ + @Readable + public static final String DOUBLE_TAP_POWER_BUTTON_GESTURE_ENABLED = + "double_tap_power_button_gesture_enabled"; + + /** + * Double tap power button gesture behavior. + * 0 = Camera launch + * 1 = Wallet launch + * @hide + */ + @Readable + public static final String DOUBLE_TAP_POWER_BUTTON_GESTURE = + "double_tap_power_button_gesture"; + /** * Whether the camera launch gesture to double tap the power button when the screen is off * should be disabled. @@ -20454,6 +20481,29 @@ public final class Settings { * @hide */ public static final String AUTO_BEDTIME_MODE = "auto_bedtime_mode"; + + /** + * Indicates that all elements of the system status tray on wear should be rendered + * by default wear system. + * + * @hide + */ + public static final int STATUS_TRAY_CONFIGURATION_DEFAULT = 0; + + /** + * Indicates that all elements of the system status tray on wear should be hidden. + * + * @hide + */ + public static final int STATUS_TRAY_CONFIGURATION_SYSTEM_HIDDEN = 1; + + /** + * Configuration of system status tray in wear. + * + * @hide + */ + public static final String WEAR_SYSTEM_STATUS_TRAY_CONFIGURATION = + "wear_system_status_tray_configuration"; } } diff --git a/core/java/android/security/advancedprotection/AdvancedProtectionManager.java b/core/java/android/security/advancedprotection/AdvancedProtectionManager.java index 9fe0dda136d1744441d65104cff1b906968037ba..0302fafd2f6c2e40d437779811744ba9acdc2ffa 100644 --- a/core/java/android/security/advancedprotection/AdvancedProtectionManager.java +++ b/core/java/android/security/advancedprotection/AdvancedProtectionManager.java @@ -281,7 +281,7 @@ public final class AdvancedProtectionManager { * @hide */ @SystemApi - @RequiresPermission(Manifest.permission.SET_ADVANCED_PROTECTION_MODE) + @RequiresPermission(Manifest.permission.MANAGE_ADVANCED_PROTECTION_MODE) public void setAdvancedProtectionEnabled(boolean enabled) { try { mService.setAdvancedProtectionEnabled(enabled); @@ -297,7 +297,7 @@ public final class AdvancedProtectionManager { */ @SystemApi @NonNull - @RequiresPermission(Manifest.permission.SET_ADVANCED_PROTECTION_MODE) + @RequiresPermission(Manifest.permission.MANAGE_ADVANCED_PROTECTION_MODE) public List getAdvancedProtectionFeatures() { try { return mService.getAdvancedProtectionFeatures(); diff --git a/core/java/android/security/advancedprotection/IAdvancedProtectionService.aidl b/core/java/android/security/advancedprotection/IAdvancedProtectionService.aidl index 68307632027a9a2a1b085018f2f4fd228981fb67..1939f829c70003d77a4a7368f8ae97f398b8784a 100644 --- a/core/java/android/security/advancedprotection/IAdvancedProtectionService.aidl +++ b/core/java/android/security/advancedprotection/IAdvancedProtectionService.aidl @@ -31,8 +31,8 @@ interface IAdvancedProtectionService { void registerAdvancedProtectionCallback(IAdvancedProtectionCallback callback); @EnforcePermission("QUERY_ADVANCED_PROTECTION_MODE") void unregisterAdvancedProtectionCallback(IAdvancedProtectionCallback callback); - @EnforcePermission("SET_ADVANCED_PROTECTION_MODE") + @EnforcePermission("MANAGE_ADVANCED_PROTECTION_MODE") void setAdvancedProtectionEnabled(boolean enabled); - @EnforcePermission("SET_ADVANCED_PROTECTION_MODE") + @EnforcePermission("MANAGE_ADVANCED_PROTECTION_MODE") List getAdvancedProtectionFeatures(); } \ No newline at end of file diff --git a/core/java/android/security/authenticationpolicy/AuthenticationPolicyManager.java b/core/java/android/security/authenticationpolicy/AuthenticationPolicyManager.java new file mode 100644 index 0000000000000000000000000000000000000000..75abd5fa4bb0ae95ee583f667c0d2ae4c5a158d5 --- /dev/null +++ b/core/java/android/security/authenticationpolicy/AuthenticationPolicyManager.java @@ -0,0 +1,237 @@ +/* + * 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.security.authenticationpolicy; + +import static android.Manifest.permission.MANAGE_SECURE_LOCK_DEVICE; +import static android.security.Flags.FLAG_SECURE_LOCKDOWN; + +import android.annotation.FlaggedApi; +import android.annotation.IntDef; +import android.annotation.NonNull; +import android.annotation.RequiresPermission; +import android.annotation.SystemApi; +import android.annotation.SystemService; +import android.content.Context; +import android.os.RemoteException; + +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; + +/** + * AuthenticationPolicyManager is a centralized interface for managing authentication related + * policies on the device. This includes device locking capabilities to protect users in "at risk" + * environments. + * + * AuthenticationPolicyManager is designed to protect Android users by integrating with apps and + * key system components, such as the lock screen. It is not related to enterprise control surfaces + * and does not offer additional administrative controls. + * + *

+ * To use this class, call {@link #enableSecureLockDevice} to enable secure lock on the device. + * This will require the caller to have the + * {@link android.Manifest.permission#MANAGE_SECURE_LOCK_DEVICE} permission. + * + *

+ * To disable secure lock on the device, call {@link #disableSecureLockDevice}. This will require + * the caller to have the {@link android.Manifest.permission#MANAGE_SECURE_LOCK_DEVICE} permission. + * + * @hide + */ +@SystemApi +@FlaggedApi(FLAG_SECURE_LOCKDOWN) +@SystemService(Context.AUTHENTICATION_POLICY_SERVICE) +public final class AuthenticationPolicyManager { + private static final String TAG = "AuthenticationPolicyManager"; + + @NonNull private final IAuthenticationPolicyService mAuthenticationPolicyService; + @NonNull private final Context mContext; + + /** + * Error result code for {@link #enableSecureLockDevice} and {@link + * #disableSecureLockDevice}. + * + * Secure lock device request status unknown. + * + * @hide + */ + @SystemApi + @FlaggedApi(FLAG_SECURE_LOCKDOWN) + public static final int ERROR_UNKNOWN = 0; + + /** + * Success result code for {@link #enableSecureLockDevice} and {@link #disableSecureLockDevice}. + * + * Secure lock device request successful. + * + * @hide + */ + @SystemApi + @FlaggedApi(FLAG_SECURE_LOCKDOWN) + public static final int SUCCESS = 1; + + /** + * Error result code for {@link #enableSecureLockDevice} and {@link #disableSecureLockDevice}. + * + * Secure lock device is unsupported. + * + * @hide + */ + @SystemApi + @FlaggedApi(FLAG_SECURE_LOCKDOWN) + public static final int ERROR_UNSUPPORTED = 2; + + + /** + * Error result code for {@link #enableSecureLockDevice} and {@link #disableSecureLockDevice}. + * + * Invalid secure lock device request params provided. + * + * @hide + */ + @SystemApi + @FlaggedApi(FLAG_SECURE_LOCKDOWN) + public static final int ERROR_INVALID_PARAMS = 3; + + + /** + * Error result code for {@link #enableSecureLockDevice} and {@link #disableSecureLockDevice}. + * + * Secure lock device is unavailable because there are no biometrics enrolled on the device. + * + * @hide + */ + @SystemApi + @FlaggedApi(FLAG_SECURE_LOCKDOWN) + public static final int ERROR_NO_BIOMETRICS_ENROLLED = 4; + + /** + * Error result code for {@link #enableSecureLockDevice} and {@link #disableSecureLockDevice}. + * + * Secure lock device is unavailable because the device has no biometric hardware or the + * biometric sensors do not meet + * {@link android.hardware.biometrics.BiometricManager.Authenticators#BIOMETRIC_STRONG} + * + * @hide + */ + @SystemApi + @FlaggedApi(FLAG_SECURE_LOCKDOWN) + public static final int ERROR_INSUFFICIENT_BIOMETRICS = 5; + + /** + * Error result code for {@link #enableSecureLockDevice}. + * + * Secure lock is already enabled. + * + * @hide + */ + @SystemApi + @FlaggedApi(FLAG_SECURE_LOCKDOWN) + public static final int ERROR_ALREADY_ENABLED = 6; + + /** + * Communicates the current status of a request to enable secure lock on the device. + * + * @hide + */ + @IntDef(prefix = {"ENABLE_SECURE_LOCK_DEVICE_STATUS_"}, value = { + ERROR_UNKNOWN, + SUCCESS, + ERROR_UNSUPPORTED, + ERROR_INVALID_PARAMS, + ERROR_NO_BIOMETRICS_ENROLLED, + ERROR_INSUFFICIENT_BIOMETRICS, + ERROR_ALREADY_ENABLED + }) + @Retention(RetentionPolicy.SOURCE) + public @interface EnableSecureLockDeviceRequestStatus {} + + /** + * Communicates the current status of a request to disable secure lock on the device. + * + * @hide + */ + @IntDef(prefix = {"DISABLE_SECURE_LOCK_DEVICE_STATUS_"}, value = { + ERROR_UNKNOWN, + SUCCESS, + ERROR_UNSUPPORTED, + ERROR_INVALID_PARAMS, + }) + @Retention(RetentionPolicy.SOURCE) + public @interface DisableSecureLockDeviceRequestStatus {} + + /** @hide */ + public AuthenticationPolicyManager(@NonNull Context context, + @NonNull IAuthenticationPolicyService authenticationPolicyService) { + mContext = context; + mAuthenticationPolicyService = authenticationPolicyService; + } + + /** + * Called by a privileged component to remotely enable secure lock on the device. + * + * Secure lock is an enhanced security state that restricts access to sensitive data (app + * notifications, widgets, quick settings, assistant, etc) and requires multi-factor + * authentication for device entry, such as + * {@link android.hardware.biometrics.BiometricManager.Authenticators#DEVICE_CREDENTIAL} and + * {@link android.hardware.biometrics.BiometricManager.Authenticators#BIOMETRIC_STRONG}. + * + * If secure lock is already enabled when this method is called, it will return + * {@link ERROR_ALREADY_ENABLED}. + * + * @param params EnableSecureLockDeviceParams for caller to supply params related to the secure + * lock device request + * @return @EnableSecureLockDeviceRequestStatus int indicating the result of the secure lock + * device request + * + * @hide + */ + @EnableSecureLockDeviceRequestStatus + @RequiresPermission(MANAGE_SECURE_LOCK_DEVICE) + @SystemApi + @FlaggedApi(FLAG_SECURE_LOCKDOWN) + public int enableSecureLockDevice(@NonNull EnableSecureLockDeviceParams params) { + try { + return mAuthenticationPolicyService.enableSecureLockDevice(params); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + } + + /** + * Called by a privileged component to disable secure lock on the device. + * + * If secure lock is already disabled when this method is called, it will return + * {@link SUCCESS}. + * + * @param params @DisableSecureLockDeviceParams for caller to supply params related to the + * secure lock device request + * @return @DisableSecureLockDeviceRequestStatus int indicating the result of the secure lock + * device request + * + * @hide + */ + @DisableSecureLockDeviceRequestStatus + @RequiresPermission(MANAGE_SECURE_LOCK_DEVICE) + @SystemApi + @FlaggedApi(FLAG_SECURE_LOCKDOWN) + public int disableSecureLockDevice(@NonNull DisableSecureLockDeviceParams params) { + try { + return mAuthenticationPolicyService.disableSecureLockDevice(params); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + } +} diff --git a/core/java/android/security/authenticationpolicy/DisableSecureLockDeviceParams.aidl b/core/java/android/security/authenticationpolicy/DisableSecureLockDeviceParams.aidl new file mode 100644 index 0000000000000000000000000000000000000000..81f7726a500c423e65a8a7a351b064232c5d79ec --- /dev/null +++ b/core/java/android/security/authenticationpolicy/DisableSecureLockDeviceParams.aidl @@ -0,0 +1,21 @@ +/* + * 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.security.authenticationpolicy; + +/** + * @hide + */ +parcelable DisableSecureLockDeviceParams; \ No newline at end of file diff --git a/core/java/android/security/authenticationpolicy/DisableSecureLockDeviceParams.java b/core/java/android/security/authenticationpolicy/DisableSecureLockDeviceParams.java new file mode 100644 index 0000000000000000000000000000000000000000..64a3f0f60f961c0e732b4907608c75232854c7ee --- /dev/null +++ b/core/java/android/security/authenticationpolicy/DisableSecureLockDeviceParams.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.security.authenticationpolicy; + +import static android.security.Flags.FLAG_SECURE_LOCKDOWN; + +import android.annotation.FlaggedApi; +import android.annotation.NonNull; +import android.annotation.SystemApi; +import android.os.Parcel; +import android.os.Parcelable; + +import java.util.Objects; + +/** + * Parameters related to a request to disable secure lock on the device. + * + * @hide + */ +@SystemApi +@FlaggedApi(FLAG_SECURE_LOCKDOWN) +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. + */ + private final @NonNull String 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.") + */ + public DisableSecureLockDeviceParams(@NonNull String message) { + mMessage = message; + } + + private DisableSecureLockDeviceParams(@NonNull Parcel in) { + mMessage = Objects.requireNonNull(in.readString8()); + } + + public static final @NonNull Creator CREATOR = + new Creator() { + @Override + public DisableSecureLockDeviceParams createFromParcel(Parcel in) { + return new DisableSecureLockDeviceParams(in); + } + + @Override + public DisableSecureLockDeviceParams[] newArray(int size) { + return new DisableSecureLockDeviceParams[size]; + } + }; + + @Override + public int describeContents() { + return 0; + } + + @Override + public void writeToParcel(@NonNull Parcel dest, int flags) { + dest.writeString8(mMessage); + } +} diff --git a/core/java/android/content/pm/verify/pkg/VerificationStatus.aidl b/core/java/android/security/authenticationpolicy/EnableSecureLockDeviceParams.aidl similarity index 85% rename from core/java/android/content/pm/verify/pkg/VerificationStatus.aidl rename to core/java/android/security/authenticationpolicy/EnableSecureLockDeviceParams.aidl index 6a1cb4f2d1d245c376de704b84217e5ffba03914..9e496f82ec69512aac35be194664f99e750ac2ad 100644 --- a/core/java/android/content/pm/verify/pkg/VerificationStatus.aidl +++ b/core/java/android/security/authenticationpolicy/EnableSecureLockDeviceParams.aidl @@ -13,8 +13,9 @@ * See the License for the specific language governing permissions and * limitations under the License. */ +package android.security.authenticationpolicy; -package android.content.pm.verify.pkg; - -/** @hide */ -parcelable VerificationStatus; +/** + * @hide + */ +parcelable EnableSecureLockDeviceParams; \ No newline at end of file diff --git a/core/java/android/security/authenticationpolicy/EnableSecureLockDeviceParams.java b/core/java/android/security/authenticationpolicy/EnableSecureLockDeviceParams.java new file mode 100644 index 0000000000000000000000000000000000000000..1d727727ce37dce3a15b4f223d08fc0550feaf11 --- /dev/null +++ b/core/java/android/security/authenticationpolicy/EnableSecureLockDeviceParams.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.security.authenticationpolicy; + +import static android.security.Flags.FLAG_SECURE_LOCKDOWN; + +import android.annotation.FlaggedApi; +import android.annotation.NonNull; +import android.annotation.SystemApi; +import android.os.Parcel; +import android.os.Parcelable; + +import java.util.Objects; + + +/** + * Parameters related to a request to enable secure lock on the device. + * + * @hide + */ +@SystemApi +@FlaggedApi(FLAG_SECURE_LOCKDOWN) +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. + */ + private final @NonNull String 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.") + */ + public EnableSecureLockDeviceParams(@NonNull String message) { + mMessage = message; + } + + private EnableSecureLockDeviceParams(@NonNull Parcel in) { + mMessage = Objects.requireNonNull(in.readString8()); + } + + public static final @NonNull Creator CREATOR = + new Creator() { + @Override + public EnableSecureLockDeviceParams createFromParcel(Parcel in) { + return new EnableSecureLockDeviceParams(in); + } + + @Override + public EnableSecureLockDeviceParams[] newArray(int size) { + return new EnableSecureLockDeviceParams[size]; + } + }; + + @Override + public int describeContents() { + return 0; + } + + @Override + public void writeToParcel(@NonNull Parcel dest, int flags) { + dest.writeString8(mMessage); + } +} diff --git a/core/java/android/security/authenticationpolicy/IAuthenticationPolicyService.aidl b/core/java/android/security/authenticationpolicy/IAuthenticationPolicyService.aidl new file mode 100644 index 0000000000000000000000000000000000000000..5ad4534c257a4d7cc9e2bfd1219e0e74fa2522bf --- /dev/null +++ b/core/java/android/security/authenticationpolicy/IAuthenticationPolicyService.aidl @@ -0,0 +1,32 @@ +/* + * 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.security.authenticationpolicy; + +import android.security.authenticationpolicy.EnableSecureLockDeviceParams; +import android.security.authenticationpolicy.DisableSecureLockDeviceParams; + +/** + * Communication channel from AuthenticationPolicyManager to AuthenticationPolicyService. + * @hide + */ +interface IAuthenticationPolicyService { + @EnforcePermission("MANAGE_SECURE_LOCK_DEVICE") + int enableSecureLockDevice(in EnableSecureLockDeviceParams params); + + @EnforcePermission("MANAGE_SECURE_LOCK_DEVICE") + int disableSecureLockDevice(in DisableSecureLockDeviceParams params); +} \ No newline at end of file diff --git a/core/java/android/security/authenticationpolicy/OWNERS b/core/java/android/security/authenticationpolicy/OWNERS new file mode 100644 index 0000000000000000000000000000000000000000..4310d1a3a9db2e7005e9b19f92c70702cfdfd8d8 --- /dev/null +++ b/core/java/android/security/authenticationpolicy/OWNERS @@ -0,0 +1 @@ +include /services/core/java/com/android/server/security/authenticationpolicy/OWNERS \ No newline at end of file diff --git a/core/java/android/security/forensic/IForensicService.aidl b/core/java/android/security/forensic/IForensicService.aidl deleted file mode 100644 index 8039b264f0e5be7b9f943a2689243cc551328461..0000000000000000000000000000000000000000 --- a/core/java/android/security/forensic/IForensicService.aidl +++ /dev/null @@ -1,35 +0,0 @@ -/* - * 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.security.forensic; - -import android.security.forensic.IForensicServiceCommandCallback; -import android.security.forensic.IForensicServiceStateCallback; - -/** - * Binder interface to communicate with ForensicService. - * @hide - */ -interface IForensicService { - @EnforcePermission("READ_FORENSIC_STATE") - void addStateCallback(IForensicServiceStateCallback callback); - @EnforcePermission("READ_FORENSIC_STATE") - void removeStateCallback(IForensicServiceStateCallback callback); - @EnforcePermission("MANAGE_FORENSIC_STATE") - void enable(IForensicServiceCommandCallback callback); - @EnforcePermission("MANAGE_FORENSIC_STATE") - void disable(IForensicServiceCommandCallback callback); -} diff --git a/core/java/android/security/forensic/IForensicEventTransport.aidl b/core/java/android/security/intrusiondetection/IIntrusionDetectionEventTransport.aidl similarity index 56% rename from core/java/android/security/forensic/IForensicEventTransport.aidl rename to core/java/android/security/intrusiondetection/IIntrusionDetectionEventTransport.aidl index 80e78eb9cf4948fae76a78ae1daf8ae0c98c8ef1..eab1c156b6be8c4e4d264680f258d3058026f598 100644 --- a/core/java/android/security/forensic/IForensicEventTransport.aidl +++ b/core/java/android/security/intrusiondetection/IIntrusionDetectionEventTransport.aidl @@ -14,28 +14,31 @@ * limitations under the License. */ -package android.security.forensic; -import android.security.forensic.ForensicEvent; +package android.security.intrusiondetection; + +import android.security.intrusiondetection.IntrusionDetectionEvent; import com.android.internal.infra.AndroidFuture; /** {@hide} */ -oneway interface IForensicEventTransport { +oneway interface IIntrusionDetectionEventTransport { /** * Initialize the server side. */ - void initialize(in AndroidFuture resultFuture); + void initialize(in AndroidFuture resultFuture); /** - * Send forensic logging data to the backup destination. - * The data is a list of ForensicEvent. - * The ForensicEvent is an abstract class that represents - * different type of events. + * Send intrusiondetection logging data to the transport destination. + * The data is a list of IntrusionDetectionEvent. + * The IntrusionDetectionEvent is an abstract class that represents + * different types of events. */ - void addData(in List events, in AndroidFuture resultFuture); + void addData( + in List events, + in AndroidFuture resultFuture); /** * Release the binder to the server. */ - void release(in AndroidFuture resultFuture); + void release(in AndroidFuture resultFuture); } diff --git a/core/java/android/security/intrusiondetection/IIntrusionDetectionService.aidl b/core/java/android/security/intrusiondetection/IIntrusionDetectionService.aidl new file mode 100644 index 0000000000000000000000000000000000000000..0ba94185ddecb6498738f8ad0cca6b6d1e15fc29 --- /dev/null +++ b/core/java/android/security/intrusiondetection/IIntrusionDetectionService.aidl @@ -0,0 +1,35 @@ +/* + * 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.security.intrusiondetection; + +import android.security.intrusiondetection.IIntrusionDetectionServiceCommandCallback; +import android.security.intrusiondetection.IIntrusionDetectionServiceStateCallback; + +/** + * Binder interface to communicate with IntrusionDetectionService. + * @hide + */ +interface IIntrusionDetectionService { + @EnforcePermission("READ_INTRUSION_DETECTION_STATE") + void addStateCallback(IIntrusionDetectionServiceStateCallback callback); + @EnforcePermission("READ_INTRUSION_DETECTION_STATE") + void removeStateCallback(IIntrusionDetectionServiceStateCallback callback); + @EnforcePermission("MANAGE_INTRUSION_DETECTION_STATE") + void enable(IIntrusionDetectionServiceCommandCallback callback); + @EnforcePermission("MANAGE_INTRUSION_DETECTION_STATE") + void disable(IIntrusionDetectionServiceCommandCallback callback); +} diff --git a/core/java/android/security/forensic/IForensicServiceCommandCallback.aidl b/core/java/android/security/intrusiondetection/IIntrusionDetectionServiceCommandCallback.aidl similarity index 89% rename from core/java/android/security/forensic/IForensicServiceCommandCallback.aidl rename to core/java/android/security/intrusiondetection/IIntrusionDetectionServiceCommandCallback.aidl index 6d1456ea04261d6d4fffd82f7811a17296e79529..80f09d520cc8c76fae30c1df67bff36eb9b83c5a 100644 --- a/core/java/android/security/forensic/IForensicServiceCommandCallback.aidl +++ b/core/java/android/security/intrusiondetection/IIntrusionDetectionServiceCommandCallback.aidl @@ -14,12 +14,12 @@ * limitations under the License. */ -package android.security.forensic; +package android.security.intrusiondetection; /** * @hide */ - oneway interface IForensicServiceCommandCallback { + oneway interface IIntrusionDetectionServiceCommandCallback { @Backing(type="int") enum ErrorCode{ UNKNOWN = 0, diff --git a/core/java/android/security/forensic/IForensicServiceStateCallback.aidl b/core/java/android/security/intrusiondetection/IIntrusionDetectionServiceStateCallback.aidl similarity index 88% rename from core/java/android/security/forensic/IForensicServiceStateCallback.aidl rename to core/java/android/security/intrusiondetection/IIntrusionDetectionServiceStateCallback.aidl index 1b68c7b14bcac647a552cb0690f8cc9f8dabf973..c88dc210320c25a40efdc39f4b0cf5c96d7008d6 100644 --- a/core/java/android/security/forensic/IForensicServiceStateCallback.aidl +++ b/core/java/android/security/intrusiondetection/IIntrusionDetectionServiceStateCallback.aidl @@ -14,12 +14,12 @@ * limitations under the License. */ -package android.security.forensic; +package android.security.intrusiondetection; /** * @hide */ - oneway interface IForensicServiceStateCallback { + oneway interface IIntrusionDetectionServiceStateCallback { @Backing(type="int") enum State{ UNKNOWN = 0, diff --git a/core/java/android/content/pm/verify/pkg/VerificationSession.aidl b/core/java/android/security/intrusiondetection/IntrusionDetectionEvent.aidl similarity index 86% rename from core/java/android/content/pm/verify/pkg/VerificationSession.aidl rename to core/java/android/security/intrusiondetection/IntrusionDetectionEvent.aidl index ac855850a86c908b3e3eb532375fd9a5219b3ee5..80b439673b3de9ce6fba3ec3094b0301a09b9082 100644 --- a/core/java/android/content/pm/verify/pkg/VerificationSession.aidl +++ b/core/java/android/security/intrusiondetection/IntrusionDetectionEvent.aidl @@ -14,7 +14,7 @@ * limitations under the License. */ -package android.content.pm.verify.pkg; +package android.security.intrusiondetection; -/** @hide */ -parcelable VerificationSession; +/** {@hide} */ +parcelable IntrusionDetectionEvent; diff --git a/core/java/android/security/forensic/ForensicEvent.java b/core/java/android/security/intrusiondetection/IntrusionDetectionEvent.java similarity index 67% rename from core/java/android/security/forensic/ForensicEvent.java rename to core/java/android/security/intrusiondetection/IntrusionDetectionEvent.java index 3d908cca150c288e5a3e68387a23f88d9d5cc995..b479ca7a0b6f2a94d4362069706085ef4d4e8d6d 100644 --- a/core/java/android/security/forensic/ForensicEvent.java +++ b/core/java/android/security/intrusiondetection/IntrusionDetectionEvent.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package android.security.forensic; +package android.security.intrusiondetection; import android.annotation.FlaggedApi; import android.annotation.IntDef; @@ -22,6 +22,7 @@ import android.annotation.NonNull; import android.app.admin.ConnectEvent; import android.app.admin.DnsEvent; import android.app.admin.SecurityLog.SecurityEvent; +import android.annotation.SystemApi; import android.os.Parcel; import android.os.Parcelable; import android.security.Flags; @@ -30,23 +31,45 @@ import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; /** - * A class that represents a forensic event. + * A class that represents a intrusiondetection event. + * * @hide */ +@SystemApi @FlaggedApi(Flags.FLAG_AFL_API) -public final class ForensicEvent implements Parcelable { - private static final String TAG = "ForensicEvent"; - +public final class IntrusionDetectionEvent implements Parcelable { + private static final String TAG = "IntrusionDetectionEvent"; + + /** + * Event type representing a security-related event. + * This type is associated with a {@link SecurityEvent} object. + * + * @see SecurityEvent + */ public static final int SECURITY_EVENT = 0; + + /** + * Event type representing a network DNS event. + * This type is associated with a {@link DnsEvent} object. + * + * @see DnsEvent + */ public static final int NETWORK_EVENT_DNS = 1; + + /** + * Event type representing a network connection event. + * This type is associated with a {@link ConnectEvent} object. + * + * @see ConnectEvent + */ public static final int NETWORK_EVENT_CONNECT = 2; /** @hide */ @Retention(RetentionPolicy.SOURCE) @IntDef({ - ForensicEvent.SECURITY_EVENT, - ForensicEvent.NETWORK_EVENT_DNS, - ForensicEvent.NETWORK_EVENT_CONNECT, + IntrusionDetectionEvent.SECURITY_EVENT, + IntrusionDetectionEvent.NETWORK_EVENT_DNS, + IntrusionDetectionEvent.NETWORK_EVENT_CONNECT, }) public @interface EventType {} @@ -56,39 +79,57 @@ public final class ForensicEvent implements Parcelable { private final DnsEvent mNetworkEventDns; private final ConnectEvent mNetworkEventConnect; - public static final @NonNull Parcelable.Creator CREATOR = + public static final @NonNull Parcelable.Creator CREATOR = new Parcelable.Creator<>() { - public ForensicEvent createFromParcel(Parcel in) { - return new ForensicEvent(in); + public IntrusionDetectionEvent createFromParcel(Parcel in) { + return new IntrusionDetectionEvent(in); } - public ForensicEvent[] newArray(int size) { - return new ForensicEvent[size]; + public IntrusionDetectionEvent[] newArray(int size) { + return new IntrusionDetectionEvent[size]; } }; - public ForensicEvent(@NonNull SecurityEvent securityEvent) { + /** + * Creates an IntrusionDetectionEvent object with a + * {@link SecurityEvent} object as the event source. + * + * @param securityEvent The SecurityEvent object. + */ + public IntrusionDetectionEvent(@NonNull SecurityEvent securityEvent) { mType = SECURITY_EVENT; mSecurityEvent = securityEvent; mNetworkEventDns = null; mNetworkEventConnect = null; } - public ForensicEvent(@NonNull DnsEvent dnsEvent) { + /** + * Creates an IntrusionDetectionEvent object with a + * {@link DnsEvent} object as the event source. + * + * @param dnsEvent The DnsEvent object. + */ + public IntrusionDetectionEvent(@NonNull DnsEvent dnsEvent) { mType = NETWORK_EVENT_DNS; mNetworkEventDns = dnsEvent; mSecurityEvent = null; mNetworkEventConnect = null; } - public ForensicEvent(@NonNull ConnectEvent connectEvent) { + /** + * Creates an IntrusionDetectionEvent object with a + * {@link ConnectEvent} object as the event source. + * + * @param connectEvent The ConnectEvent object. + */ + public IntrusionDetectionEvent(@NonNull ConnectEvent connectEvent) { mType = NETWORK_EVENT_CONNECT; mNetworkEventConnect = connectEvent; mSecurityEvent = null; mNetworkEventDns = null; } - private ForensicEvent(@NonNull Parcel in) { + private IntrusionDetectionEvent(@NonNull Parcel in) { mType = in.readInt(); switch (mType) { case SECURITY_EVENT: @@ -111,7 +152,7 @@ public final class ForensicEvent implements Parcelable { } } - /** Returns the type of the forensic event. */ + /** Returns the type of the IntrusionDetectionEvent. */ @NonNull public @EventType int getType() { return mType; @@ -170,7 +211,7 @@ public final class ForensicEvent implements Parcelable { @Override public String toString() { - return "ForensicEvent{" + return "IntrusionDetectionEvent{" + "mType=" + mType + '}'; } diff --git a/core/java/android/security/intrusiondetection/IntrusionDetectionEventTransport.java b/core/java/android/security/intrusiondetection/IntrusionDetectionEventTransport.java new file mode 100644 index 0000000000000000000000000000000000000000..2e2d0f7f2dd2da5fd6d3639ce2a324ffd9412892 --- /dev/null +++ b/core/java/android/security/intrusiondetection/IntrusionDetectionEventTransport.java @@ -0,0 +1,145 @@ +/* + * 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.security.intrusiondetection; + +import android.annotation.FlaggedApi; +import android.annotation.NonNull; +import android.annotation.SystemApi; +import android.annotation.SuppressLint; +import android.content.ComponentName; +import android.content.Context; +import android.os.IBinder; +import android.util.CloseGuard; + +import android.security.Flags; +import android.security.intrusiondetection.IntrusionDetectionEvent; +import android.security.intrusiondetection.IIntrusionDetectionEventTransport; + +import com.android.internal.infra.AndroidFuture; + +import java.lang.AutoCloseable; +import java.util.List; + +/** + * A class that provides a stable API for transporting intrusion detection events + * to a transport location, such as a file or a network endpoint. + * + * This class acts as a bridge between the {@link IIntrusionDetectionEventTransport} + * interface and its implementations. It allows system components to add intrusion + * detection events ({@link IntrusionDetectionEvent}) to a transport queue, + * which will then be delivered to the specified location. + * + * Usage: + * 1. Obtain an instance of {@link IntrusionDetectionEventTransport} using the constructor. + * 2. Initialize the transport by calling {@link #initialize()}. + * 3. Add events to the transport queue using {@link #addData(List)}. + * 4. Release the transport when finished by calling {@link #release()}. + * + * Key Components: + * - {@link IIntrusionDetectionEventTransport}: The underlying AIDL interface + * for interacting with transport implementations. + * - {@link IntrusionDetectionEvent}: Represents a single event. + * + * @hide + */ +@SystemApi +@FlaggedApi(Flags.FLAG_AFL_API) +@SuppressLint("NotCloseable") +public class IntrusionDetectionEventTransport { + IIntrusionDetectionEventTransport mBinderImpl = new TransportImpl(); + + /** + * Returns the binder interface for this transport. + */ + @NonNull + public IBinder getBinder() { + return mBinderImpl.asBinder(); + } + + /** + * Initializes the transport. + * + * @return whether the initialization was successful. + */ + public boolean initialize() { + return false; + } + + /** + * Adds data to the transport. + * + * @param events the events to add. + * @return whether the addition was successful. + */ + public boolean addData(@NonNull List events) { + return false; + } + + /** + * Releases the transport. + * + * The release() method is a callback implemented by the concrete transport + * endpoint. + * The "SuppressLint" annotation is used to allow the release() method to be + * included in the API without requiring the class to implement AutoCloseable. + * + * @return whether the release was successful. + */ + public boolean release() { + return false; + } + + /** + * Bridge between the actual IIntrusionDetectionEventTransport implementation + * and the stable API. If the binder interface needs to change, we use this + * layer to translate so that we can decouple those framework-side changes + * from the IntrusionDetectionEventTransport implementations. + */ + class TransportImpl extends IIntrusionDetectionEventTransport.Stub { + @Override + public void initialize(AndroidFuture resultFuture) { + try { + boolean result = IntrusionDetectionEventTransport.this.initialize(); + resultFuture.complete(result); + } catch (RuntimeException e) { + resultFuture.cancel(/* mayInterruptIfRunning */ true); + } + } + + @Override + public void addData( + List events, + AndroidFuture resultFuture) { + try { + boolean result = IntrusionDetectionEventTransport.this.addData(events); + resultFuture.complete(result); + } catch (RuntimeException e) { + resultFuture.cancel(/* mayInterruptIfRunning */ true); + } + } + + @Override + public void release(AndroidFuture resultFuture) { + try { + boolean result = IntrusionDetectionEventTransport.this.release(); + resultFuture.complete(result); + } catch (RuntimeException e) { + resultFuture.cancel(/* mayInterruptIfRunning */ true); + } + } + } +} \ No newline at end of file diff --git a/core/java/android/security/forensic/ForensicManager.java b/core/java/android/security/intrusiondetection/IntrusionDetectionManager.java similarity index 62% rename from core/java/android/security/forensic/ForensicManager.java rename to core/java/android/security/intrusiondetection/IntrusionDetectionManager.java index 9126182eda7b32cc70631c7e902de78f8088c585..e2463384d0c8e77780fb446752df9acf95ede3d9 100644 --- a/core/java/android/security/forensic/ForensicManager.java +++ b/core/java/android/security/intrusiondetection/IntrusionDetectionManager.java @@ -14,10 +14,10 @@ * limitations under the License. */ -package android.security.forensic; +package android.security.intrusiondetection; -import static android.Manifest.permission.MANAGE_FORENSIC_STATE; -import static android.Manifest.permission.READ_FORENSIC_STATE; +import static android.Manifest.permission.MANAGE_INTRUSION_DETECTION_STATE; +import static android.Manifest.permission.READ_INTRUSION_DETECTION_STATE; import android.annotation.CallbackExecutor; import android.annotation.FlaggedApi; @@ -41,23 +41,23 @@ import java.util.concurrent.Executor; import java.util.function.Consumer; /** - * ForensicManager manages the forensic logging on Android devices. - * Upon user consent, forensic logging collects various device events for + * IntrusionDetectionManager manages the intrusion detection on Android devices. + * Upon user consent, intrusion detection collects various device events for * off-device investigation of potential device compromise. *

- * Forensic logging can either be enabled ({@link #STATE_ENABLED} + * Intrusion detection logging can either be enabled ({@link #STATE_ENABLED} * or disabled ({@link #STATE_DISABLED}). *

- * The Forensic logs will be transferred to - * {@link android.security.forensic.ForensicEventTransport}. + * The intrusion detection logs will be transferred to + * {@link android.security.intrusiondetection.IntrusionDetectionEventTransport}. * * @hide */ @SystemApi @FlaggedApi(Flags.FLAG_AFL_API) -@SystemService(Context.FORENSIC_SERVICE) -public class ForensicManager { - private static final String TAG = "ForensicManager"; +@SystemService(Context.INTRUSION_DETECTION_SERVICE) +public class IntrusionDetectionManager { + private static final String TAG = "IntrusionDetectionManager"; /** @hide */ @Target(ElementType.TYPE_USE) @@ -67,7 +67,7 @@ public class ForensicManager { STATE_DISABLED, STATE_ENABLED }) - public @interface ForensicState {} + public @interface IntrusionDetectionState {} /** @hide */ @Retention(RetentionPolicy.SOURCE) @@ -77,64 +77,65 @@ public class ForensicManager { ERROR_TRANSPORT_UNAVAILABLE, ERROR_DATA_SOURCE_UNAVAILABLE }) - public @interface ForensicError {} + public @interface IntrusionDetectionError {} /** * Indicates an unknown state */ - public static final int STATE_UNKNOWN = IForensicServiceStateCallback.State.UNKNOWN; + public static final int STATE_UNKNOWN = IIntrusionDetectionServiceStateCallback.State.UNKNOWN; /** - * Indicates an state that the forensic is turned off. + * Indicates an state that the intrusion detection is turned off. */ - public static final int STATE_DISABLED = IForensicServiceStateCallback.State.DISABLED; + public static final int STATE_DISABLED = IIntrusionDetectionServiceStateCallback.State.DISABLED; /** - * Indicates an state that the forensic is turned on. + * Indicates an state that the intrusion detection is turned on. */ - public static final int STATE_ENABLED = IForensicServiceStateCallback.State.ENABLED; + public static final int STATE_ENABLED = IIntrusionDetectionServiceStateCallback.State.ENABLED; /** * Indicates an unknown error */ - public static final int ERROR_UNKNOWN = IForensicServiceCommandCallback.ErrorCode.UNKNOWN; + public static final int ERROR_UNKNOWN = + IIntrusionDetectionServiceCommandCallback.ErrorCode.UNKNOWN; /** * Indicates an error due to insufficient access rights. */ public static final int ERROR_PERMISSION_DENIED = - IForensicServiceCommandCallback.ErrorCode.PERMISSION_DENIED; + IIntrusionDetectionServiceCommandCallback.ErrorCode.PERMISSION_DENIED; /** - * Indicates an error due to unavailability of the forensic event transport. + * Indicates an error due to unavailability of the intrusion detection event transport. */ public static final int ERROR_TRANSPORT_UNAVAILABLE = - IForensicServiceCommandCallback.ErrorCode.TRANSPORT_UNAVAILABLE; + IIntrusionDetectionServiceCommandCallback.ErrorCode.TRANSPORT_UNAVAILABLE; /** * Indicates an error due to unavailability of the data source. */ public static final int ERROR_DATA_SOURCE_UNAVAILABLE = - IForensicServiceCommandCallback.ErrorCode.DATA_SOURCE_UNAVAILABLE; + IIntrusionDetectionServiceCommandCallback.ErrorCode.DATA_SOURCE_UNAVAILABLE; - private final IForensicService mService; + private final IIntrusionDetectionService mService; - private final ConcurrentHashMap, IForensicServiceStateCallback> + private final ConcurrentHashMap, IIntrusionDetectionServiceStateCallback> mStateCallbacks = new ConcurrentHashMap<>(); /** * Constructor * - * @param service A valid instance of IForensicService. + * @param service A valid instance of IIntrusionDetectionService. * @hide */ - public ForensicManager(IForensicService service) { + public IntrusionDetectionManager(IIntrusionDetectionService service) { mService = service; } /** - * Add a callback to monitor the state of the ForensicService. + * Add a callback to monitor the state of the IntrusionDetectionService. * * @param executor The executor through which the callback should be invoked. * @param callback The callback for state change. @@ -142,9 +143,9 @@ public class ForensicManager { * to reflect the init state. * The callback can be registered only once. */ - @RequiresPermission(READ_FORENSIC_STATE) + @RequiresPermission(READ_INTRUSION_DETECTION_STATE) public void addStateCallback(@NonNull @CallbackExecutor Executor executor, - @NonNull @ForensicState Consumer callback) { + @NonNull @IntrusionDetectionState Consumer callback) { Objects.requireNonNull(executor); Objects.requireNonNull(callback); @@ -153,8 +154,8 @@ public class ForensicManager { return; } - final IForensicServiceStateCallback wrappedCallback = - new IForensicServiceStateCallback.Stub() { + final IIntrusionDetectionServiceStateCallback wrappedCallback = + new IIntrusionDetectionServiceStateCallback.Stub() { @Override public void onStateChange(int state) { executor.execute(() -> callback.accept(state)); @@ -170,19 +171,19 @@ public class ForensicManager { } /** - * Remove a callback to monitor the state of the ForensicService. + * Remove a callback to monitor the state of the IntrusionDetectionService. * * @param callback The callback to remove. */ - @RequiresPermission(READ_FORENSIC_STATE) - public void removeStateCallback(@NonNull Consumer<@ForensicState Integer> callback) { + @RequiresPermission(READ_INTRUSION_DETECTION_STATE) + public void removeStateCallback(@NonNull Consumer<@IntrusionDetectionState Integer> callback) { Objects.requireNonNull(callback); if (!mStateCallbacks.containsKey(callback)) { Log.d(TAG, "removeStateCallback callback not present"); return; } - IForensicServiceStateCallback wrappedCallback = mStateCallbacks.get(callback); + IIntrusionDetectionServiceStateCallback wrappedCallback = mStateCallbacks.get(callback); try { mService.removeStateCallback(wrappedCallback); @@ -194,22 +195,23 @@ public class ForensicManager { } /** - * Enable forensic logging. - * If successful, ForensicService will transition to {@link #STATE_ENABLED} state. + * Enable intrusion detection. + * If successful, IntrusionDetectionService will transition to {@link #STATE_ENABLED} state. *

- * When forensic logging is enabled, various device events will be collected and - * sent over to the registered {@link android.security.forensic.ForensicEventTransport}. + * When intrusion detection is enabled, various device events will be collected and + * sent over to the registered + * {@link android.security.intrusiondetection.IntrusionDetectionEventTransport}. * * @param executor The executor through which the callback should be invoked. * @param callback The callback for the command result. */ - @RequiresPermission(MANAGE_FORENSIC_STATE) + @RequiresPermission(MANAGE_INTRUSION_DETECTION_STATE) public void enable(@NonNull @CallbackExecutor Executor executor, @NonNull CommandCallback callback) { Objects.requireNonNull(executor); Objects.requireNonNull(callback); try { - mService.enable(new IForensicServiceCommandCallback.Stub() { + mService.enable(new IIntrusionDetectionServiceCommandCallback.Stub() { @Override public void onSuccess() { executor.execute(callback::onSuccess); @@ -226,23 +228,23 @@ public class ForensicManager { } /** - * Disable forensic logging. - * If successful, ForensicService will transition to {@link #STATE_DISABLED}. + * Disable intrusion detection. + * If successful, IntrusionDetectionService will transition to {@link #STATE_DISABLED}. *

- * When forensic logging is disabled, device events will no longer be collected. - * Any events that have been collected but not yet sent to ForensicEventTransport + * When intrusion detection is disabled, device events will no longer be collected. + * Any events that have been collected but not yet sent to IntrusionDetectionEventTransport * will be transferred as a final batch. * * @param executor The executor through which the callback should be invoked. * @param callback The callback for the command result. */ - @RequiresPermission(MANAGE_FORENSIC_STATE) + @RequiresPermission(MANAGE_INTRUSION_DETECTION_STATE) public void disable(@NonNull @CallbackExecutor Executor executor, @NonNull CommandCallback callback) { Objects.requireNonNull(executor); Objects.requireNonNull(callback); try { - mService.disable(new IForensicServiceCommandCallback.Stub() { + mService.disable(new IIntrusionDetectionServiceCommandCallback.Stub() { @Override public void onSuccess() { executor.execute(callback::onSuccess); @@ -271,6 +273,6 @@ public class ForensicManager { * Called when command fails. * @param error The error number. */ - void onFailure(@ForensicError int error); + void onFailure(@IntrusionDetectionError int error); } } diff --git a/core/java/android/security/forensic/OWNERS b/core/java/android/security/intrusiondetection/OWNERS similarity index 100% rename from core/java/android/security/forensic/OWNERS rename to core/java/android/security/intrusiondetection/OWNERS diff --git a/core/java/android/security/responsible_apis_flags.aconfig b/core/java/android/security/responsible_apis_flags.aconfig index 6c92991ceff6a4c8bca980c58ac7ac4a7077c4c6..a5c837b88fa4759a260caca6d5aa528ac736bb07 100644 --- a/core/java/android/security/responsible_apis_flags.aconfig +++ b/core/java/android/security/responsible_apis_flags.aconfig @@ -95,6 +95,21 @@ flag { is_fixed_read_only: true } +flag { + name: "prevent_intent_redirect_throw_exception_if_nested_keys_not_collected" + namespace: "responsible_apis" + description: "Prevent intent redirect attacks by throwing exception if the intent does not collect nested keys" + bug: "361143368" +} + +flag { + name: "prevent_intent_redirect_collect_nested_keys_on_server_if_not_collected" + namespace: "responsible_apis" + description: "Prevent intent redirect attacks by collecting nested keys on server if not yet collected" + bug: "361143368" + is_fixed_read_only: true +} + flag { name: "enable_intent_matching_flags" is_exported: true @@ -110,3 +125,16 @@ flag { description: "Android Advanced Protection Mode Feature: Disable Install Unknown Sources" bug: "369361373" } + +flag { + name: "aapm_feature_memory_tagging_extension" + namespace: "responsible_apis" + description: "Android Advanced Protection Mode Feature: Memory Tagging Extension" + bug: "378931989" +} +flag { + name: "aapm_feature_disable_cellular_2g" + namespace: "responsible_apis" + description: "Android Advanced Protection Mode Feature: Disable Cellular 2G" + bug: "377748286" +} diff --git a/core/java/android/service/carrier/CarrierMessagingService.java b/core/java/android/service/carrier/CarrierMessagingService.java index 61213e6293ba4410b8fe22eb3f9342395bff15e3..a825a7e110f5e0afecef8f02a503db3713f0989a 100644 --- a/core/java/android/service/carrier/CarrierMessagingService.java +++ b/core/java/android/service/carrier/CarrierMessagingService.java @@ -16,6 +16,7 @@ package android.service.carrier; +import android.annotation.FlaggedApi; import android.annotation.IntDef; import android.annotation.NonNull; import android.annotation.Nullable; @@ -26,6 +27,8 @@ import android.net.Uri; import android.os.IBinder; import android.os.RemoteException; +import com.android.internal.telephony.flags.Flags; + import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.util.List; @@ -97,16 +100,317 @@ public abstract class CarrierMessagingService extends Service { public static final int SEND_STATUS_RETRY_ON_CARRIER_NETWORK = 1; /** - * SMS/MMS sending failed. We should not retry via the carrier network. + * SMS/MMS sending failed due to an unspecified issue. Sending will not be retried via the + * carrier network. + * + *

Maps to SmsManager.RESULT_RIL_GENERIC_FAILURE for SMS and SmsManager.MMS_ERROR_UNSPECIFIED + * for MMS. */ public static final int SEND_STATUS_ERROR = 2; + /** + * More precise error reasons for outbound SMS send requests. These will not be retried on the + * carrier network. + * + *

Each code maps directly to an SmsManager code (e.g. SEND_STATS_RESULT_ERROR_NULL_PDU maps + * to SmsManager.RESULT_ERROR_NULL_PDU). + */ + + /** + * Generic failure cause. + * + * @see android.telephony.SmsManager.RESULT_ERROR_GENERIC_FAILURE + */ + @FlaggedApi(Flags.FLAG_TEMPORARY_FAILURES_IN_CARRIER_MESSAGING_SERVICE) + public static final int SEND_STATUS_RESULT_ERROR_GENERIC_FAILURE = 200; + + /** + * Failed because no pdu provided. + * + * @see android.telephony.SmsManager.RESULT_ERROR_NULL_PDU + */ + @FlaggedApi(Flags.FLAG_TEMPORARY_FAILURES_IN_CARRIER_MESSAGING_SERVICE) + public static final int SEND_STATUS_RESULT_ERROR_NULL_PDU = 201; + + /** + * Failed because service is currently unavailable. + * + * @see android.telephony.SmsManager.RESULT_ERROR_NO_SERVICE + */ + @FlaggedApi(Flags.FLAG_TEMPORARY_FAILURES_IN_CARRIER_MESSAGING_SERVICE) + public static final int SEND_STATUS_RESULT_ERROR_NO_SERVICE = 202; + + /** + * Failed because we reached the sending queue limit. + * + * @see android.telephony.SmsManager.RESULT_ERROR_LIMIT_EXCEEDED + */ + @FlaggedApi(Flags.FLAG_TEMPORARY_FAILURES_IN_CARRIER_MESSAGING_SERVICE) + public static final int SEND_STATUS_RESULT_ERROR_LIMIT_EXCEEDED = 203; + + /** + * Failed because FDN is enabled. + * + * @see android.telephony.SmsManager.RESULT_ERROR_FDN_CHECK_FAILURE + */ + @FlaggedApi(Flags.FLAG_TEMPORARY_FAILURES_IN_CARRIER_MESSAGING_SERVICE) + public static final int SEND_STATUS_RESULT_ERROR_FDN_CHECK_FAILURE = 204; + + /** + * Failed because user denied the sending of this short code. + * + * @see android.telephony.SmsManager.RESULT_ERROR_SHORT_CODE_NOT_ALLOWED + */ + @FlaggedApi(Flags.FLAG_TEMPORARY_FAILURES_IN_CARRIER_MESSAGING_SERVICE) + public static final int SEND_STATUS_RESULT_ERROR_SHORT_CODE_NOT_ALLOWED = 205; + + /** + * Failed because the user has denied this app ever send premium short codes. + * + * @see android.telephony.SmsManager.RESULT_ERROR_SHORT_CODE_NEVER_ALLOWED + */ + @FlaggedApi(Flags.FLAG_TEMPORARY_FAILURES_IN_CARRIER_MESSAGING_SERVICE) + public static final int SEND_STATUS_RESULT_ERROR_SHORT_CODE_NEVER_ALLOWED = 206; + + /** + * Failed because of network rejection. + * + * @see android.telephony.SmsManager.RESULT_NETWORK_REJECT + */ + @FlaggedApi(Flags.FLAG_TEMPORARY_FAILURES_IN_CARRIER_MESSAGING_SERVICE) + public static final int SEND_STATUS_RESULT_NETWORK_REJECT = 207; + + /** + * Failed because of invalid arguments. + * + * @see android.telephony.SmsManager.RESULT_INVALID_ARGUMENTS + */ + @FlaggedApi(Flags.FLAG_TEMPORARY_FAILURES_IN_CARRIER_MESSAGING_SERVICE) + public static final int SEND_STATUS_RESULT_INVALID_ARGUMENTS = 208; + + /** + * Failed because of an invalid state. + * + * @see android.telephony.SmsManager.RESULT_INVALID_STATE + */ + @FlaggedApi(Flags.FLAG_TEMPORARY_FAILURES_IN_CARRIER_MESSAGING_SERVICE) + public static final int SEND_STATUS_RESULT_INVALID_STATE = 209; + + /** + * Failed because the sms format is not valid. + * + * @see android.telephony.SmsManager.RESULT_INVALID_SMS_FORMAT + */ + @FlaggedApi(Flags.FLAG_TEMPORARY_FAILURES_IN_CARRIER_MESSAGING_SERVICE) + public static final int SEND_STATUS_RESULT_INVALID_SMS_FORMAT = 210; + + /** + * Failed because of a network error. + * + * @see android.telephony.SmsManager.RESULT_NETWORK_ERROR + */ + @FlaggedApi(Flags.FLAG_TEMPORARY_FAILURES_IN_CARRIER_MESSAGING_SERVICE) + public static final int SEND_STATUS_RESULT_NETWORK_ERROR = 211; + + /** + * Failed because of an encoding error. + * + * @see android.telephony.SmsManager.RESULT_ENCODING_ERROR + */ + @FlaggedApi(Flags.FLAG_TEMPORARY_FAILURES_IN_CARRIER_MESSAGING_SERVICE) + public static final int SEND_STATUS_RESULT_ENCODING_ERROR = 212; + + /** + * Failed because of an invalid smsc address + * + * @see android.telephony.SmsManager.RESULT_INVALID_SMSC_ADDRESS + */ + @FlaggedApi(Flags.FLAG_TEMPORARY_FAILURES_IN_CARRIER_MESSAGING_SERVICE) + public static final int SEND_STATUS_RESULT_INVALID_SMSC_ADDRESS = 213; + + /** + * Failed because the operation is not allowed. + * + * @see android.telephony.SmsManager.RESULT_OPERATION_NOT_ALLOWED + */ + @FlaggedApi(Flags.FLAG_TEMPORARY_FAILURES_IN_CARRIER_MESSAGING_SERVICE) + public static final int SEND_STATUS_RESULT_OPERATION_NOT_ALLOWED = 214; + + /** + * Failed because the operation was cancelled. + * + * @see android.telephony.SmsManager.RESULT_CANCELLED + */ + @FlaggedApi(Flags.FLAG_TEMPORARY_FAILURES_IN_CARRIER_MESSAGING_SERVICE) + public static final int SEND_STATUS_RESULT_CANCELLED = 215; + + /** + * Failed because the request is not supported. + * + * @see android.telephony.SmsManager.RESULT_REQUEST_NOT_SUPPORTED + */ + @FlaggedApi(Flags.FLAG_TEMPORARY_FAILURES_IN_CARRIER_MESSAGING_SERVICE) + public static final int SEND_STATUS_RESULT_REQUEST_NOT_SUPPORTED = 216; + + /** + * Failed sending during an emergency call. + * + * @see android.telephony.SmsManager.RESULT_SMS_BLOCKED_DURING_EMERGENCY + */ + @FlaggedApi(Flags.FLAG_TEMPORARY_FAILURES_IN_CARRIER_MESSAGING_SERVICE) + public static final int SEND_STATUS_RESULT_SMS_BLOCKED_DURING_EMERGENCY = 217; + + /** + * Failed to send an sms retry. + * + * @see android.telephony.SmsManager.RESULT_SMS_SEND_RETRY_FAILED + */ + @FlaggedApi(Flags.FLAG_TEMPORARY_FAILURES_IN_CARRIER_MESSAGING_SERVICE) + public static final int SEND_STATUS_RESULT_SMS_SEND_RETRY_FAILED = 218; + + /** + * More precise error reasons for outbound MMS send requests. These will not be retried on the + * carrier network. + * + *

Each code maps directly to an SmsManager code (e.g. + * SEND_STATUS_MMS_ERROR_UNABLE_CONNECT_MMS maps to SmsManager.MMS_ERROR_UNABLE_CONNECT_MMS). + */ + + /** + * Unspecific MMS error occurred during send. + * + * @see android.telephony.SmsManager.MMS_ERROR_UNSPECIFIED + */ + @FlaggedApi(Flags.FLAG_TEMPORARY_FAILURES_IN_CARRIER_MESSAGING_SERVICE) + public static final int SEND_STATUS_MMS_ERROR_UNSPECIFIED = 400; + + /** + * ApnException occurred during MMS network setup. + * + * @see android.telephony.SmsManager.MMS_ERROR_INVALID_APN + */ + @FlaggedApi(Flags.FLAG_TEMPORARY_FAILURES_IN_CARRIER_MESSAGING_SERVICE) + public static final int SEND_STATUS_MMS_ERROR_INVALID_APN = 401; + + /** + * An error occurred during the MMS connection setup. + * + * @see android.telephony.SmsManager.MMS_ERROR_UNABLE_CONNECT_MMS + */ + @FlaggedApi(Flags.FLAG_TEMPORARY_FAILURES_IN_CARRIER_MESSAGING_SERVICE) + public static final int SEND_STATUS_MMS_ERROR_UNABLE_CONNECT_MMS = 402; + + /** + * An error occurred during the HTTP client setup. + * + * @see android.telephony.SmsManager.MMS_ERROR_HTTP_FAILURE + */ + @FlaggedApi(Flags.FLAG_TEMPORARY_FAILURES_IN_CARRIER_MESSAGING_SERVICE) + public static final int SEND_STATUS_MMS_ERROR_HTTP_FAILURE = 403; + + /** + * An I/O error occurred reading the PDU. + * + * @see android.telephony.SmsManager.MMS_ERROR_IO_ERROR + */ + @FlaggedApi(Flags.FLAG_TEMPORARY_FAILURES_IN_CARRIER_MESSAGING_SERVICE) + public static final int SEND_STATUS_MMS_ERROR_IO_ERROR = 404; + + /** + * An error occurred while retrying sending the MMS. + * + * @see android.telephony.SmsManager.MMS_ERROR_RETRY + */ + @FlaggedApi(Flags.FLAG_TEMPORARY_FAILURES_IN_CARRIER_MESSAGING_SERVICE) + public static final int SEND_STATUS_MMS_ERROR_RETRY = 405; + + /** + * The carrier-dependent configuration values could not be loaded. + * + * @see android.telephony.SmsManager.MMS_ERROR_CONFIGURATION_ERROR + */ + @FlaggedApi(Flags.FLAG_TEMPORARY_FAILURES_IN_CARRIER_MESSAGING_SERVICE) + public static final int SEND_STATUS_MMS_ERROR_CONFIGURATION_ERROR = 406; + + /** + * There is neither Wi-Fi nor mobile data network. + * + * @see android.telephony.SmsManager.MMS_ERROR_NO_DATA_NETWORK + */ + @FlaggedApi(Flags.FLAG_TEMPORARY_FAILURES_IN_CARRIER_MESSAGING_SERVICE) + public static final int SEND_STATUS_MMS_ERROR_NO_DATA_NETWORK = 407; + + /** + * The subscription id for the send is invalid. + * + * @see android.telephony.SmsManager.MMS_ERROR_INVALID_SUBSCRIPTION_ID + */ + @FlaggedApi(Flags.FLAG_TEMPORARY_FAILURES_IN_CARRIER_MESSAGING_SERVICE) + public static final int SEND_STATUS_MMS_ERROR_INVALID_SUBSCRIPTION_ID = 408; + + /** + * The subscription id for the send is inactive. + * + * @see android.telephony.SmsManager.MMS_ERROR_INACTIVE_SUBSCRIPTION + */ + @FlaggedApi(Flags.FLAG_TEMPORARY_FAILURES_IN_CARRIER_MESSAGING_SERVICE) + public static final int SEND_STATUS_MMS_ERROR_INACTIVE_SUBSCRIPTION = 409; + + /** + * Data is disabled for the MMS APN. + * + * @see android.telephony.SmsManager.MMS_ERROR_DATA_DISABLED + */ + @FlaggedApi(Flags.FLAG_TEMPORARY_FAILURES_IN_CARRIER_MESSAGING_SERVICE) + public static final int SEND_STATUS_MMS_ERROR_DATA_DISABLED = 410; + + /** + * MMS is disabled by a carrier. + * + * @see android.telephony.SmsManager.MMS_ERROR_MMS_DISABLED_BY_CARRIER + */ + @FlaggedApi(Flags.FLAG_TEMPORARY_FAILURES_IN_CARRIER_MESSAGING_SERVICE) + public static final int SEND_STATUS_MMS_ERROR_MMS_DISABLED_BY_CARRIER = 411; + /** @hide */ - @IntDef(prefix = { "SEND_STATUS_" }, value = { - SEND_STATUS_OK, - SEND_STATUS_RETRY_ON_CARRIER_NETWORK, - SEND_STATUS_ERROR - }) + @IntDef( + prefix = {"SEND_STATUS_"}, + value = { + SEND_STATUS_OK, + SEND_STATUS_RETRY_ON_CARRIER_NETWORK, + SEND_STATUS_ERROR, + SEND_STATUS_RESULT_ERROR_GENERIC_FAILURE, + SEND_STATUS_RESULT_ERROR_NULL_PDU, + SEND_STATUS_RESULT_ERROR_NO_SERVICE, + SEND_STATUS_RESULT_ERROR_LIMIT_EXCEEDED, + SEND_STATUS_RESULT_ERROR_FDN_CHECK_FAILURE, + SEND_STATUS_RESULT_ERROR_SHORT_CODE_NOT_ALLOWED, + SEND_STATUS_RESULT_ERROR_SHORT_CODE_NEVER_ALLOWED, + SEND_STATUS_RESULT_NETWORK_REJECT, + SEND_STATUS_RESULT_INVALID_ARGUMENTS, + SEND_STATUS_RESULT_INVALID_STATE, + SEND_STATUS_RESULT_INVALID_SMS_FORMAT, + SEND_STATUS_RESULT_NETWORK_ERROR, + SEND_STATUS_RESULT_ENCODING_ERROR, + SEND_STATUS_RESULT_INVALID_SMSC_ADDRESS, + SEND_STATUS_RESULT_OPERATION_NOT_ALLOWED, + SEND_STATUS_RESULT_CANCELLED, + SEND_STATUS_RESULT_REQUEST_NOT_SUPPORTED, + SEND_STATUS_RESULT_SMS_BLOCKED_DURING_EMERGENCY, + SEND_STATUS_RESULT_SMS_SEND_RETRY_FAILED, + SEND_STATUS_MMS_ERROR_UNSPECIFIED, + SEND_STATUS_MMS_ERROR_INVALID_APN, + SEND_STATUS_MMS_ERROR_UNABLE_CONNECT_MMS, + SEND_STATUS_MMS_ERROR_HTTP_FAILURE, + SEND_STATUS_MMS_ERROR_IO_ERROR, + SEND_STATUS_MMS_ERROR_RETRY, + SEND_STATUS_MMS_ERROR_CONFIGURATION_ERROR, + SEND_STATUS_MMS_ERROR_NO_DATA_NETWORK, + SEND_STATUS_MMS_ERROR_INVALID_SUBSCRIPTION_ID, + SEND_STATUS_MMS_ERROR_INACTIVE_SUBSCRIPTION, + SEND_STATUS_MMS_ERROR_DATA_DISABLED, + SEND_STATUS_MMS_ERROR_MMS_DISABLED_BY_CARRIER + }) @Retention(RetentionPolicy.SOURCE) public @interface SendResult {} @@ -121,16 +425,138 @@ public abstract class CarrierMessagingService extends Service { public static final int DOWNLOAD_STATUS_RETRY_ON_CARRIER_NETWORK = 1; /** - * MMS downloading failed. We should not retry via the carrier network. + * MMS downloading failed due to an unspecified issue. Downloading will not be retried via the + * carrier network. + * + *

Maps to SmsManager.MMR_ERROR_UNSPECIFIED. */ public static final int DOWNLOAD_STATUS_ERROR = 2; + /** + * More precise error reasons for inbound MMS download requests. These will not be retried on + * the carrier network. + * + *

Each code maps directly to an SmsManager code (e.g. + * DOWNLOAD_STATUS_MMS_ERROR_UNABLE_CONNECT_MMS maps to + * SmsManager.MMS_ERROR_UNABLE_CONNECT_MMS). + */ + + /** + * Unspecific MMS error occurred during download. + * + * @see android.telephony.SmsManager.MMS_ERROR_UNSPECIFIED + */ + @FlaggedApi(Flags.FLAG_TEMPORARY_FAILURES_IN_CARRIER_MESSAGING_SERVICE) + public static final int DOWNLOAD_STATUS_MMS_ERROR_UNSPECIFIED = 600; + + /** + * ApnException occurred during MMS network setup. + * + * @see android.telephony.SmsManager.MMS_ERROR_INVALID_APN + */ + @FlaggedApi(Flags.FLAG_TEMPORARY_FAILURES_IN_CARRIER_MESSAGING_SERVICE) + public static final int DOWNLOAD_STATUS_MMS_ERROR_INVALID_APN = 601; + + /** + * An error occurred during the MMS connection setup. + * + * @see android.telephony.SmsManager.MMS_ERROR_UNABLE_CONNECT_MMS + */ + @FlaggedApi(Flags.FLAG_TEMPORARY_FAILURES_IN_CARRIER_MESSAGING_SERVICE) + public static final int DOWNLOAD_STATUS_MMS_ERROR_UNABLE_CONNECT_MMS = 602; + + /** + * An error occurred during the HTTP client setup. + * + * @see android.telephony.SmsManager.MMS_ERROR_HTTP_FAILURE + */ + @FlaggedApi(Flags.FLAG_TEMPORARY_FAILURES_IN_CARRIER_MESSAGING_SERVICE) + public static final int DOWNLOAD_STATUS_MMS_ERROR_HTTP_FAILURE = 603; + + /** + * An I/O error occurred reading the PDU. + * + * @see android.telephony.SmsManager.MMS_ERROR_IO_ERROR + */ + @FlaggedApi(Flags.FLAG_TEMPORARY_FAILURES_IN_CARRIER_MESSAGING_SERVICE) + public static final int DOWNLOAD_STATUS_MMS_ERROR_IO_ERROR = 604; + + /** + * An error occurred while retrying downloading the MMS. + * + * @see android.telephony.SmsManager.MMS_ERROR_RETRY + */ + @FlaggedApi(Flags.FLAG_TEMPORARY_FAILURES_IN_CARRIER_MESSAGING_SERVICE) + public static final int DOWNLOAD_STATUS_MMS_ERROR_RETRY = 605; + + /** + * The carrier-dependent configuration values could not be loaded. + * + * @see android.telephony.SmsManager.MMS_ERROR_CONFIGURATION_ERROR + */ + @FlaggedApi(Flags.FLAG_TEMPORARY_FAILURES_IN_CARRIER_MESSAGING_SERVICE) + public static final int DOWNLOAD_STATUS_MMS_ERROR_CONFIGURATION_ERROR = 606; + + /** + * There is neither Wi-Fi nor mobile data network. + * + * @see android.telephony.SmsManager.MMS_ERROR_NO_DATA_NETWORK + */ + @FlaggedApi(Flags.FLAG_TEMPORARY_FAILURES_IN_CARRIER_MESSAGING_SERVICE) + public static final int DOWNLOAD_STATUS_MMS_ERROR_NO_DATA_NETWORK = 607; + + /** + * The subscription id for the download is invalid. + * + * @see android.telephony.SmsManager.MMS_ERROR_INVALID_SUBSCRIPTION_ID + */ + @FlaggedApi(Flags.FLAG_TEMPORARY_FAILURES_IN_CARRIER_MESSAGING_SERVICE) + public static final int DOWNLOAD_STATUS_MMS_ERROR_INVALID_SUBSCRIPTION_ID = 608; + + /** + * The subscription id for the download is inactive. + * + * @see android.telephony.SmsManager.MMS_ERROR_INACTIVE_SUBSCRIPTION + */ + @FlaggedApi(Flags.FLAG_TEMPORARY_FAILURES_IN_CARRIER_MESSAGING_SERVICE) + public static final int DOWNLOAD_STATUS_MMS_ERROR_INACTIVE_SUBSCRIPTION = 609; + + /** + * Data is disabled for the MMS APN. + * + * @see android.telephony.SmsManager.MMS_ERROR_DATA_DISABLED + */ + @FlaggedApi(Flags.FLAG_TEMPORARY_FAILURES_IN_CARRIER_MESSAGING_SERVICE) + public static final int DOWNLOAD_STATUS_MMS_ERROR_DATA_DISABLED = 610; + + /** + * MMS is disabled by a carrier. + * + * @see android.telephony.SmsManager.MMS_ERROR_MMS_DISABLED_BY_CARRIER + */ + @FlaggedApi(Flags.FLAG_TEMPORARY_FAILURES_IN_CARRIER_MESSAGING_SERVICE) + public static final int DOWNLOAD_STATUS_MMS_ERROR_MMS_DISABLED_BY_CARRIER = 611; + /** @hide */ - @IntDef(prefix = { "DOWNLOAD_STATUS_" }, value = { - DOWNLOAD_STATUS_OK, - DOWNLOAD_STATUS_RETRY_ON_CARRIER_NETWORK, - DOWNLOAD_STATUS_ERROR - }) + @IntDef( + prefix = {"DOWNLOAD_STATUS_"}, + value = { + DOWNLOAD_STATUS_OK, + DOWNLOAD_STATUS_RETRY_ON_CARRIER_NETWORK, + DOWNLOAD_STATUS_ERROR, + DOWNLOAD_STATUS_MMS_ERROR_UNSPECIFIED, + DOWNLOAD_STATUS_MMS_ERROR_INVALID_APN, + DOWNLOAD_STATUS_MMS_ERROR_UNABLE_CONNECT_MMS, + DOWNLOAD_STATUS_MMS_ERROR_HTTP_FAILURE, + DOWNLOAD_STATUS_MMS_ERROR_IO_ERROR, + DOWNLOAD_STATUS_MMS_ERROR_RETRY, + DOWNLOAD_STATUS_MMS_ERROR_CONFIGURATION_ERROR, + DOWNLOAD_STATUS_MMS_ERROR_NO_DATA_NETWORK, + DOWNLOAD_STATUS_MMS_ERROR_INVALID_SUBSCRIPTION_ID, + DOWNLOAD_STATUS_MMS_ERROR_INACTIVE_SUBSCRIPTION, + DOWNLOAD_STATUS_MMS_ERROR_DATA_DISABLED, + DOWNLOAD_STATUS_MMS_ERROR_MMS_DISABLED_BY_CARRIER + }) @Retention(RetentionPolicy.SOURCE) public @interface DownloadResult {} diff --git a/core/java/android/service/notification/SystemZenRules.java b/core/java/android/service/notification/SystemZenRules.java index ebb8569ead491a7886d6033e05604f773839b66a..f11ce1621f93a8bf1063e039e41fb76f0af54e35 100644 --- a/core/java/android/service/notification/SystemZenRules.java +++ b/core/java/android/service/notification/SystemZenRules.java @@ -122,17 +122,16 @@ public final class SystemZenRules { @Nullable public static String getTriggerDescriptionForScheduleTime(Context context, @NonNull ScheduleInfo schedule) { - final StringBuilder sb = new StringBuilder(); String daysSummary = getDaysOfWeekShort(context, schedule); if (daysSummary == null) { // no use outputting times without dates return null; } - sb.append(daysSummary); - sb.append(context.getString(R.string.zen_mode_trigger_summary_divider_text)); - sb.append(getTimeSummary(context, schedule)); - - return sb.toString(); + return context.getString( + R.string.zen_mode_trigger_summary_combined, + daysSummary, + getTimeSummary(context, schedule) + ); } /** diff --git a/core/java/android/service/notification/ZenModeConfig.java b/core/java/android/service/notification/ZenModeConfig.java index 24328eb1e825c9558af3a9766153efd7937e581a..13887781f1eca40f5ca761238784027d885d6ab5 100644 --- a/core/java/android/service/notification/ZenModeConfig.java +++ b/core/java/android/service/notification/ZenModeConfig.java @@ -2532,7 +2532,7 @@ public class ZenModeConfig implements Parcelable { /** Returns whether the rule id corresponds to an implicit rule. */ public static boolean isImplicitRuleId(@NonNull String ruleId) { - return ruleId.startsWith(IMPLICIT_RULE_ID_PREFIX); + return ruleId != null && ruleId.startsWith(IMPLICIT_RULE_ID_PREFIX); } private static int[] tryParseHourAndMinute(String value) { diff --git a/core/java/android/service/quickaccesswallet/flags.aconfig b/core/java/android/service/quickaccesswallet/flags.aconfig index 75a93091eec3433afbbb5b6d3984f9fda039650f..7225f27c4555641f34a76f914b84ca343d4a0218 100644 --- a/core/java/android/service/quickaccesswallet/flags.aconfig +++ b/core/java/android/service/quickaccesswallet/flags.aconfig @@ -6,4 +6,11 @@ flag { namespace: "wallet_integration" description: "Option to launch the Wallet app on double-tap of the power button" bug: "378469025" +} + +flag { + name: "launch_selected_card_from_qs_tile" + namespace: "wallet_integration" + description: "When the wallet QS tile is tapped, launch the selected card pending intent instead of the home screen pending intent." + bug: "378469025" } \ No newline at end of file diff --git a/core/java/android/service/settings/preferences/SettingsPreferenceMetadata.java b/core/java/android/service/settings/preferences/SettingsPreferenceMetadata.java index 1d08c5217129b662439ebb9152ae497a50b873c4..1acb7b8460cf1992d129f2bc67ca34d5cf65ed6a 100644 --- a/core/java/android/service/settings/preferences/SettingsPreferenceMetadata.java +++ b/core/java/android/service/settings/preferences/SettingsPreferenceMetadata.java @@ -19,7 +19,7 @@ package android.service.settings.preferences; import android.annotation.FlaggedApi; import android.annotation.IntDef; import android.annotation.SuppressLint; -import android.app.PendingIntent; +import android.content.Intent; import android.os.Bundle; import android.os.Parcel; import android.os.Parcelable; @@ -63,7 +63,7 @@ public final class SettingsPreferenceMetadata implements Parcelable { private final boolean mRestricted; private final int mSensitivity; @Nullable - private final PendingIntent mLaunchIntent; + private final Intent mLaunchIntent; @NonNull private final Bundle mExtras; @@ -149,6 +149,8 @@ public final class SettingsPreferenceMetadata implements Parcelable { /** * Returns whether Preference is restricted. + *

If true, this means the Preference is treated as a Restricted Preference which indicates + * that it could be conditionally disabled/unavailable due to admin settings. */ public boolean isRestricted() { return mRestricted; @@ -165,14 +167,18 @@ public final class SettingsPreferenceMetadata implements Parcelable { /** * Returns the intent to launch the host app page for this Preference. */ + @SuppressLint("IntentBuilderName") @Nullable - public PendingIntent getLaunchIntent() { + public Intent getLaunchIntent() { return mLaunchIntent; } /** * Returns any additional fields specific to this preference. - *

Treat all data as optional. + *

Treat all data as optional. This may contain unstructured data for a given preference, + * where the type and format of this data may only known by inspecting the source code of that + * preference. As such, any access of this data must handle failures gracefully to account for + * changing or missing data. */ @NonNull public Bundle getExtras() { @@ -236,8 +242,8 @@ public final class SettingsPreferenceMetadata implements Parcelable { mWritable = in.readBoolean(); mRestricted = in.readBoolean(); mSensitivity = in.readInt(); - mLaunchIntent = in.readParcelable(PendingIntent.class.getClassLoader(), - PendingIntent.class); + mLaunchIntent = in.readParcelable(Intent.class.getClassLoader(), + Intent.class); mExtras = Objects.requireNonNullElseGet(in.readBundle(), Bundle::new); } @@ -298,7 +304,7 @@ public final class SettingsPreferenceMetadata implements Parcelable { private boolean mWritable = false; private boolean mRestricted = false; @WriteSensitivity private int mSensitivity = INTENT_ONLY; - private PendingIntent mLaunchIntent; + private Intent mLaunchIntent; private Bundle mExtras; /** @@ -411,7 +417,7 @@ public final class SettingsPreferenceMetadata implements Parcelable { * Sets the intent to launch the host app page for this preference. */ @NonNull - public Builder setLaunchIntent(@Nullable PendingIntent launchIntent) { + public Builder setLaunchIntent(@Nullable Intent launchIntent) { mLaunchIntent = launchIntent; return this; } diff --git a/core/java/android/service/settings/preferences/SettingsPreferenceServiceClient.java b/core/java/android/service/settings/preferences/SettingsPreferenceServiceClient.java index 39995a47fcbe65a803803831c42c74eab78e922d..f6d85d51ddd47748d220df1073f29a77698e97ce 100644 --- a/core/java/android/service/settings/preferences/SettingsPreferenceServiceClient.java +++ b/core/java/android/service/settings/preferences/SettingsPreferenceServiceClient.java @@ -49,67 +49,55 @@ import java.util.concurrent.Executor; * available services, a caller may query {@link android.content.pm.PackageManager} for applications * that provide the intent action {@link SettingsPreferenceService#ACTION_PREFERENCE_SERVICE} that * are also system applications ({@link android.content.pm.ApplicationInfo#FLAG_SYSTEM}). + *

+ * Note: Each instance of this client will open a binding to an application. This can be resource + * intensive and affect the health of the system. It is essential that each client instance is + * only used when needed and the number of calls made are minimal. */ @FlaggedApi(Flags.FLAG_SETTINGS_CATALYST) public class SettingsPreferenceServiceClient implements AutoCloseable { + @NonNull private final Context mContext; + @NonNull private final Intent mServiceIntent; + @NonNull private final ServiceConnection mServiceConnection; - private final boolean mSystemOnly; + @Nullable private ISettingsPreferenceService mRemoteService; /** * Construct a client for binding to a {@link SettingsPreferenceService} provided by the * application corresponding to the provided package name. - * @param packageName - package name for which this client will initiate a service binding + * @param context Application context + * @param packageName package name for which this client will initiate a service binding + * @param callbackExecutor executor on which to invoke clientReadyCallback + * @param clientReadyCallback callback invoked once the client is ready, error otherwise */ - public SettingsPreferenceServiceClient(@NonNull Context context, - @NonNull String packageName) { - this(context, packageName, true, null); + public SettingsPreferenceServiceClient( + @NonNull Context context, + @NonNull String packageName, + @CallbackExecutor @NonNull Executor callbackExecutor, + @NonNull + OutcomeReceiver clientReadyCallback) { + this(context, packageName, true, callbackExecutor, clientReadyCallback); } /** * @hide Only to be called directly by test */ @TestApi - public SettingsPreferenceServiceClient(@NonNull Context context, - @NonNull String packageName, - boolean systemOnly, - @Nullable ServiceConnection connectionListener) { + public SettingsPreferenceServiceClient( + @NonNull Context context, + @NonNull String packageName, + boolean systemOnly, + @CallbackExecutor @NonNull Executor callbackExecutor, + @NonNull + OutcomeReceiver clientReadyCallback) { mContext = context.getApplicationContext(); mServiceIntent = new Intent(ACTION_PREFERENCE_SERVICE).setPackage(packageName); - mSystemOnly = systemOnly; - mServiceConnection = createServiceConnection(connectionListener); - } - - /** - * Initiate binding to service. - *

If no service exists for the package provided or the package is not for a system - * application, no binding will occur. - */ - public void start() { - PackageManager pm = mContext.getPackageManager(); - PackageManager.ResolveInfoFlags flags; - if (mSystemOnly) { - flags = PackageManager.ResolveInfoFlags.of(PackageManager.MATCH_SYSTEM_ONLY); - } else { - flags = PackageManager.ResolveInfoFlags.of(PackageManager.MATCH_ALL); - } - List infos = pm.queryIntentServices(mServiceIntent, flags); - if (infos.size() == 1) { - mContext.bindService(mServiceIntent, mServiceConnection, Context.BIND_AUTO_CREATE); - } - } - - /** - * If there is an active service binding, unbind from that service. - */ - public void stop() { - if (mRemoteService != null) { - mRemoteService = null; - mContext.unbindService(mServiceConnection); - } + mServiceConnection = createServiceConnection(callbackExecutor, clientReadyCallback); + connect(systemOnly, callbackExecutor, clientReadyCallback); } /** @@ -209,40 +197,73 @@ public class SettingsPreferenceServiceClient implements AutoCloseable { } } + /** + * This client handles a resource, thus is it important to appropriately close that resource + * when it is no longer needed. + *

This method is provided by {@link AutoCloseable} and calling it + * will unbind any service binding. + */ + @Override + public void close() { + if (mRemoteService != null) { + mRemoteService = null; + mContext.unbindService(mServiceConnection); + } + } + + /* + * Initiate binding to service. + *

If no service exists for the package provided or the package is not for a system + * application, no binding will occur. + */ + private void connect( + boolean matchSystemOnly, + @NonNull Executor callbackExecutor, + @NonNull OutcomeReceiver clientCallback) { + PackageManager pm = mContext.getPackageManager(); + PackageManager.ResolveInfoFlags flags; + if (matchSystemOnly) { + flags = PackageManager.ResolveInfoFlags.of(PackageManager.MATCH_SYSTEM_ONLY); + } else { + flags = PackageManager.ResolveInfoFlags.of(PackageManager.MATCH_ALL); + } + List infos = pm.queryIntentServices(mServiceIntent, flags); + if (infos.size() != 1 + || !mContext.bindService(mServiceIntent, mServiceConnection, + Context.BIND_AUTO_CREATE)) { + callbackExecutor.execute(() -> + clientCallback.onError(new IllegalStateException("Unable to bind service"))); + } + } + @NonNull - private ServiceConnection createServiceConnection(@Nullable ServiceConnection listener) { + private ServiceConnection createServiceConnection( + @NonNull Executor callbackExecutor, + @NonNull OutcomeReceiver clientCallback) { return new ServiceConnection() { @Override public void onServiceConnected(ComponentName name, IBinder service) { - mRemoteService = getPreferenceServiceInterface(service); - if (listener != null) { - listener.onServiceConnected(name, service); - } + mRemoteService = ISettingsPreferenceService.Stub.asInterface(service); + callbackExecutor.execute(() -> + clientCallback.onResult(SettingsPreferenceServiceClient.this)); } @Override public void onServiceDisconnected(ComponentName name) { mRemoteService = null; - if (listener != null) { - listener.onServiceDisconnected(name); - } } - }; - } - @NonNull - private ISettingsPreferenceService getPreferenceServiceInterface(@NonNull IBinder service) { - return ISettingsPreferenceService.Stub.asInterface(service); - } + @Override + public void onBindingDied(ComponentName name) { + close(); + } - /** - * This client handles a resource, thus is it important to appropriately close that resource - * when it is no longer needed. - *

This method is provided by {@link AutoCloseable} and calling it - * will unbind any service binding. - */ - @Override - public void close() { - stop(); + @Override + public void onNullBinding(ComponentName name) { + callbackExecutor.execute(() -> clientCallback.onError( + new IllegalStateException("Unable to connect client"))); + close(); + } + }; } } diff --git a/core/java/android/service/settings/preferences/SettingsPreferenceValue.java b/core/java/android/service/settings/preferences/SettingsPreferenceValue.java index f056e34a0dd2f73d853c2a15d53cc01e100b6d86..08826ca9776b5cd342fbb43c9bfe51e41f433d83 100644 --- a/core/java/android/service/settings/preferences/SettingsPreferenceValue.java +++ b/core/java/android/service/settings/preferences/SettingsPreferenceValue.java @@ -44,6 +44,7 @@ public final class SettingsPreferenceValue implements Parcelable { @Type private final int mType; private final boolean mBooleanValue; + private final int mIntValue; private final long mLongValue; private final double mDoubleValue; @Nullable @@ -64,6 +65,13 @@ public final class SettingsPreferenceValue implements Parcelable { return mBooleanValue; } + /** + * Returns the int value for Preference if type is {@link #TYPE_INT}. + */ + public int getIntValue() { + return mIntValue; + } + /** * Returns the long value for Preference if type is {@link #TYPE_LONG}. */ @@ -92,6 +100,7 @@ public final class SettingsPreferenceValue implements Parcelable { TYPE_LONG, TYPE_DOUBLE, TYPE_STRING, + TYPE_INT, }) @Retention(RetentionPolicy.SOURCE) public @interface Type {} @@ -104,6 +113,8 @@ public final class SettingsPreferenceValue implements Parcelable { public static final int TYPE_DOUBLE = 2; /** Value is of type string. Access via {@link #getStringValue}. */ public static final int TYPE_STRING = 3; + /** Value is of type int. Access via {@link #getIntValue}. */ + public static final int TYPE_INT = 4; private SettingsPreferenceValue(@NonNull Builder builder) { mType = builder.mType; @@ -111,6 +122,7 @@ public final class SettingsPreferenceValue implements Parcelable { mLongValue = builder.mLongValue; mDoubleValue = builder.mDoubleValue; mStringValue = builder.mStringValue; + mIntValue = builder.mIntValue; } private SettingsPreferenceValue(@NonNull Parcel in) { @@ -119,6 +131,7 @@ public final class SettingsPreferenceValue implements Parcelable { mLongValue = in.readLong(); mDoubleValue = in.readDouble(); mStringValue = in.readString8(); + mIntValue = in.readInt(); } /** @hide */ @@ -129,6 +142,7 @@ public final class SettingsPreferenceValue implements Parcelable { dest.writeLong(mLongValue); dest.writeDouble(mDoubleValue); dest.writeString8(mStringValue); + dest.writeInt(mIntValue); } /** @hide */ @@ -163,6 +177,7 @@ public final class SettingsPreferenceValue implements Parcelable { private long mLongValue; private double mDoubleValue; private String mStringValue; + private int mIntValue; /** * Create Builder instance. @@ -182,6 +197,15 @@ public final class SettingsPreferenceValue implements Parcelable { return this; } + /** + * Sets the int value for Preference. + */ + @NonNull + public Builder setIntValue(int intValue) { + mIntValue = intValue; + return this; + } + /** * Sets long value for Preference. */ diff --git a/core/java/android/service/wearable/WearableSensingService.java b/core/java/android/service/wearable/WearableSensingService.java index 47ec0801f5512e850565b2e539a1570e6786f826..e20d5e996e664287854ea5d47cc4b6d42d047502 100644 --- a/core/java/android/service/wearable/WearableSensingService.java +++ b/core/java/android/service/wearable/WearableSensingService.java @@ -27,6 +27,7 @@ import android.app.ambientcontext.AmbientContextEvent; import android.app.ambientcontext.AmbientContextEventRequest; import android.app.wearable.Flags; import android.app.wearable.IWearableSensingCallback; +import android.app.wearable.WearableConnection; import android.app.wearable.WearableSensingDataRequest; import android.app.wearable.WearableSensingManager; import android.content.Context; @@ -380,7 +381,11 @@ public abstract class WearableSensingService extends Service { * * @param secureWearableConnection The secure connection to the wearable. * @param statusConsumer The consumer for the service status. + * @deprecated Use {@link #onSecureConnectionProvided(ParcelFileDescriptor, PersistableBundle, + * Consumer)} instead to receive a remote wearable device connection. */ + @FlaggedApi(Flags.FLAG_ENABLE_CONCURRENT_WEARABLE_CONNECTIONS) + @Deprecated @BinderThread public void onSecureConnectionProvided( @NonNull ParcelFileDescriptor secureWearableConnection, @@ -389,12 +394,20 @@ public abstract class WearableSensingService extends Service { } /** - * Called when a secure connection to the wearable is available. + * Called when a secure connection to the wearable is available. See {@link + * WearableSensingManager#provideConnection(WearableConnection, Executor)} for details about the + * secure connection. + * + *

When the {@code secureWearableConnection} is closed, the system will send a {@link + * WearableSensingManager#STATUS_CHANNEL_ERROR} status code to the error callback provided by + * the caller of {@link WearableSensingManager#provideConnection(WearableConnection, Executor)}. + * + *

The implementing class should override this method. It should return an appropriate status + * code via {@code statusConsumer} after receiving the {@code secureWearableConnection}. * * @param secureWearableConnection The secure connection to the wearable. * @param metadata Metadata related to the provided connection. * @param statusConsumer The consumer for the service status. - * @see #onSecureConnectionProvided(ParcelFileDescriptor, Consumer) */ @FlaggedApi(Flags.FLAG_ENABLE_CONCURRENT_WEARABLE_CONNECTIONS) @BinderThread diff --git a/core/java/android/text/style/TtsSpan.java b/core/java/android/text/style/TtsSpan.java index b7b8f0b1b5d8bf3126d4b843b8c3df845d919431..a337ba2a57fb0b4dcf662ba51c326ea36ff46f81 100644 --- a/core/java/android/text/style/TtsSpan.java +++ b/core/java/android/text/style/TtsSpan.java @@ -19,6 +19,7 @@ package android.text.style; import static com.android.text.flags.Flags.FLAG_TTS_SPAN_DURATION; import android.annotation.FlaggedApi; +import android.annotation.IntRange; import android.annotation.NonNull; import android.os.Parcel; import android.os.PersistableBundle; @@ -324,7 +325,8 @@ public class TtsSpan implements ParcelableSpan { /** * Argument used to specify the seconds of a time or duration. The seconds should be - * provided as an integer in the range from 0 up to and including 59. + * provided as an integer in the range from 0 up to and including 59 for + * {@link #TYPE_TIME}. * Can be used with {@link #TYPE_TIME} or {@link #TYPE_DURATION}. */ @FlaggedApi(FLAG_TTS_SPAN_DURATION) @@ -1140,7 +1142,7 @@ public class TtsSpan implements ParcelableSpan { * @return This instance. * @see #ARG_HOURS */ - public TimeBuilder setHours(int hours) { + public TimeBuilder setHours(@IntRange(from = 0, to = 24) int hours) { return setIntArgument(TtsSpan.ARG_HOURS, hours); } @@ -1151,7 +1153,7 @@ public class TtsSpan implements ParcelableSpan { * @return This instance. * @see #ARG_MINUTES */ - public TimeBuilder setMinutes(int minutes) { + public TimeBuilder setMinutes(@IntRange(from = 0, to = 59) int minutes) { return setIntArgument(TtsSpan.ARG_MINUTES, minutes); } @@ -1162,7 +1164,7 @@ public class TtsSpan implements ParcelableSpan { */ @FlaggedApi(FLAG_TTS_SPAN_DURATION) @NonNull - public TimeBuilder setSeconds(int seconds) { + public TimeBuilder setSeconds(@IntRange(from = 0, to = 59) int seconds) { return setIntArgument(TtsSpan.ARG_SECONDS, seconds); } } diff --git a/core/java/android/view/AttachedSurfaceControl.java b/core/java/android/view/AttachedSurfaceControl.java index 264db4a604ffd9d8138f8e9e78d4597c243ad54e..239da87b71ee40f729f3b88afecc8bfff10781c0 100644 --- a/core/java/android/view/AttachedSurfaceControl.java +++ b/core/java/android/view/AttachedSurfaceControl.java @@ -210,6 +210,9 @@ public interface AttachedSurfaceControl { /** * Registers a {@link OnJankDataListener} to receive jank classification data about rendered * frames. + *

+ * Use {@link SurfaceControl.OnJankDataListenerRegistration#removeAfter} to unregister the + * listener. * * @param executor The executor on which the listener will be invoked. * @param listener The listener to add. diff --git a/core/java/android/view/Display.java b/core/java/android/view/Display.java index a1a9fc697271cf2411df978e7ea8af4cd38bc54e..c9d560c3424bc63d890dba0cf5dedb2df841363a 100644 --- a/core/java/android/view/Display.java +++ b/core/java/android/view/Display.java @@ -20,6 +20,7 @@ import static android.Manifest.permission.CONFIGURE_DISPLAY_COLOR_MODE; import static android.Manifest.permission.CONTROL_DISPLAY_BRIGHTNESS; import static android.hardware.flags.Flags.FLAG_OVERLAYPROPERTIES_CLASS_API; +import static com.android.server.display.feature.flags.Flags.FLAG_ENABLE_GET_SUPPORTED_REFRESH_RATES; import static com.android.server.display.feature.flags.Flags.FLAG_HIGHEST_HDR_SDR_RATIO_API; import static com.android.server.display.feature.flags.Flags.FLAG_ENABLE_HAS_ARR_SUPPORT; import static com.android.server.display.feature.flags.Flags.FLAG_ENABLE_GET_SUGGESTED_FRAME_RATE; @@ -63,6 +64,7 @@ import java.lang.annotation.RetentionPolicy; import java.util.ArrayList; import java.util.Arrays; import java.util.List; +import java.util.Objects; import java.util.concurrent.Executor; import java.util.function.Consumer; @@ -1207,17 +1209,36 @@ public final class Display { /** * Get the supported refresh rates of this display in frames per second. - *

- * This method only returns refresh rates for the display's default modes. For more options, use - * {@link #getSupportedModes()}. * - * @deprecated use {@link #getSupportedModes()} instead + *

    + *
  • Android version {@link Build.VERSION_CODES#BAKLAVA} and above: + * returns display supported render rates. + *
  • Android version {@link Build.VERSION_CODES#VANILLA_ICE_CREAM} and below: + * This method only returns refresh rates for the display's default modes. For more options, + * use {@link #getSupportedModes()}. + *
*/ - @Deprecated - public float[] getSupportedRefreshRates() { + @FlaggedApi(FLAG_ENABLE_GET_SUPPORTED_REFRESH_RATES) + public @NonNull float[] getSupportedRefreshRates() { + synchronized (mLock) { + updateDisplayInfoLocked(); + final float[] refreshRates = mDisplayInfo.getDefaultRefreshRates(); + Objects.requireNonNull(refreshRates); + return refreshRates; + } + } + + /** + * @hide + */ + @TestApi + @SuppressLint({"UnflaggedApi"}) // Usage in the CTS to test backward compatibility. + public @NonNull float[] getSupportedRefreshRatesLegacy() { synchronized (mLock) { updateDisplayInfoLocked(); - return mDisplayInfo.getDefaultRefreshRates(); + final float[] refreshRates = mDisplayInfo.getDefaultRefreshRatesLegacy(); + Objects.requireNonNull(refreshRates); + return refreshRates; } } @@ -1279,8 +1300,19 @@ public final class Display { } } + /** + * Represents the {@link FrameRateCategory} for the Normal frame rate + * + * @see FrameRateCategory + */ @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 + * + * @see FrameRateCategory + */ @FlaggedApi(FLAG_ENABLE_GET_SUGGESTED_FRAME_RATE) public static final int FRAME_RATE_CATEGORY_HIGH = 1; @@ -2438,6 +2470,8 @@ public final class Display { * constrained by the system. * @hide */ + @SuppressWarnings("UnflaggedApi") // For testing only + @TestApi public float getVsyncRate() { return mVsyncRate; } diff --git a/core/java/android/view/DisplayInfo.java b/core/java/android/view/DisplayInfo.java index 4ff04d5c1fa6c3bf88bb6ddcefdf4024a780c39e..8b6458a54c43c3ff44ff8d4967500c6b0ebb073a 100644 --- a/core/java/android/view/DisplayInfo.java +++ b/core/java/android/view/DisplayInfo.java @@ -209,6 +209,11 @@ public final class DisplayInfo implements Parcelable { */ public FrameRateCategoryRate frameRateCategoryRate; + /** + * All the refresh rates supported in the active mode. + */ + public float[] supportedRefreshRates = new float[0]; + /** * The default display mode. */ @@ -449,6 +454,7 @@ public final class DisplayInfo implements Parcelable { && modeId == other.modeId && hasArrSupport == other.hasArrSupport && Objects.equals(frameRateCategoryRate, other.frameRateCategoryRate) + && Arrays.equals(supportedRefreshRates, other.supportedRefreshRates) && defaultModeId == other.defaultModeId && userPreferredModeId == other.userPreferredModeId && Arrays.equals(supportedModes, other.supportedModes) @@ -512,6 +518,8 @@ public final class DisplayInfo implements Parcelable { renderFrameRate = other.renderFrameRate; hasArrSupport = other.hasArrSupport; frameRateCategoryRate = other.frameRateCategoryRate; + supportedRefreshRates = Arrays.copyOf( + other.supportedRefreshRates, other.supportedRefreshRates.length); defaultModeId = other.defaultModeId; userPreferredModeId = other.userPreferredModeId; supportedModes = Arrays.copyOf(other.supportedModes, other.supportedModes.length); @@ -571,6 +579,11 @@ public final class DisplayInfo implements Parcelable { hasArrSupport = source.readBoolean(); frameRateCategoryRate = source.readParcelable(null, android.view.FrameRateCategoryRate.class); + int numOfSupportedRefreshRates = source.readInt(); + supportedRefreshRates = new float[numOfSupportedRefreshRates]; + for (int i = 0; i < numOfSupportedRefreshRates; i++) { + supportedRefreshRates[i] = source.readFloat(); + } defaultModeId = source.readInt(); userPreferredModeId = source.readInt(); int nModes = source.readInt(); @@ -646,6 +659,10 @@ public final class DisplayInfo implements Parcelable { dest.writeFloat(renderFrameRate); dest.writeBoolean(hasArrSupport); dest.writeParcelable(frameRateCategoryRate, flags); + dest.writeInt(supportedRefreshRates.length); + for (float supportedRefreshRate : supportedRefreshRates) { + dest.writeFloat(supportedRefreshRate); + } dest.writeInt(defaultModeId); dest.writeInt(userPreferredModeId); dest.writeInt(supportedModes.length); @@ -750,9 +767,19 @@ public final class DisplayInfo implements Parcelable { } /** - * Returns the list of supported refresh rates in the default mode. + * Returns the list of supported refresh rates in the active mode. */ public float[] getDefaultRefreshRates() { + if (supportedRefreshRates.length == 0) { + return getDefaultRefreshRatesLegacy(); + } + return Arrays.copyOf(supportedRefreshRates, supportedRefreshRates.length); + } + + /** + * Returns the list of supported refresh rates in the default mode. + */ + public float[] getDefaultRefreshRatesLegacy() { Display.Mode[] modes = appsSupportedModes; ArraySet rates = new ArraySet<>(); Display.Mode defaultMode = getDefaultMode(); @@ -898,6 +925,8 @@ public final class DisplayInfo implements Parcelable { sb.append(hasArrSupport); sb.append(", frameRateCategoryRate "); sb.append(frameRateCategoryRate); + sb.append(", supportedRefreshRates "); + sb.append(Arrays.toString(supportedRefreshRates)); sb.append(", defaultMode "); sb.append(defaultModeId); sb.append(", userPreferredModeId "); diff --git a/core/java/android/view/IWindowSession.aidl b/core/java/android/view/IWindowSession.aidl index 11a3168daa0e9e609158b61aeec498c2df46bcf5..1f8f0820ca3af59da18a4744083171a01d5aa326 100644 --- a/core/java/android/view/IWindowSession.aidl +++ b/core/java/android/view/IWindowSession.aidl @@ -372,4 +372,14 @@ interface IWindowSession { */ oneway void notifyImeWindowVisibilityChangedFromClient(IWindow window, boolean visible, in ImeTracker.Token statsToken); + + /** + * Notifies WindowState whether inset animations are currently running within the Window. + * This value is used by the server to vote for refresh rate. + * see {@link com.android.server.wm.WindowState#mInsetsAnimationRunning). + * + * @param window The window that is insets animaiton is running. + * @param running Indicates the insets animation state. + */ + oneway void notifyInsetsAnimationRunningStateChanged(IWindow window, boolean running); } diff --git a/core/java/android/view/InputWindowHandle.java b/core/java/android/view/InputWindowHandle.java index 58ef5efe846fcc90f928c22fba78a18adf8f4d71..6cd4a4033adf29026555254ad3f7e9ee949f3f9e 100644 --- a/core/java/android/view/InputWindowHandle.java +++ b/core/java/android/view/InputWindowHandle.java @@ -260,6 +260,15 @@ public final class InputWindowHandle { touchableRegionSurfaceControl = new WeakReference<>(bounds); } + /** + * Resize the window touchable region. + * @param rect new touchable region rectangle. + */ + public void setTouchableRegion(Rect rect) { + touchableRegion.set(rect); + } + + public void setWindowToken(IBinder iwindow) { windowToken = iwindow; } diff --git a/core/java/android/view/ScrollCaptureSearchResults.java b/core/java/android/view/ScrollCaptureSearchResults.java index 3469b9dc7103e84c3d4a31c4a3cf31d199c3b3c4..b1ce949f991949c5c8372cd14b5e4e781c6b5caf 100644 --- a/core/java/android/view/ScrollCaptureSearchResults.java +++ b/core/java/android/view/ScrollCaptureSearchResults.java @@ -16,10 +16,16 @@ package android.view; +import static android.view.flags.Flags.scrollCaptureTargetZOrderFix; + +import static java.util.Comparator.comparing; import static java.util.Objects.requireNonNull; +import static java.util.Objects.requireNonNullElse; import android.annotation.NonNull; +import android.annotation.Nullable; import android.annotation.UiThread; +import android.graphics.Point; import android.graphics.Rect; import android.os.CancellationSignal; import android.util.IndentingPrintWriter; @@ -113,7 +119,9 @@ public final class ScrollCaptureSearchResults { private void signalComplete() { mComplete = true; - mTargets.sort(PRIORITY_ORDER); + if (!scrollCaptureTargetZOrderFix()) { + mTargets.sort(PRIORITY_ORDER); + } if (mOnCompleteListener != null) { mOnCompleteListener.run(); mOnCompleteListener = null; @@ -125,14 +133,73 @@ public final class ScrollCaptureSearchResults { return new ArrayList<>(mTargets); } + private Rect getScrollBoundsInWindow(@Nullable ScrollCaptureTarget target) { + if (target == null || target.getScrollBounds() == null) { + return new Rect(); + } + Rect windowRect = new Rect(target.getScrollBounds()); + Point windowPosition = target.getPositionInWindow(); + windowRect.offset(windowPosition.x, windowPosition.y); + return windowRect; + } + /** * Get the top ranked result out of all completed requests. * * @return the top ranked result */ + @Nullable public ScrollCaptureTarget getTopResult() { - ScrollCaptureTarget target = mTargets.isEmpty() ? null : mTargets.get(0); - return target != null && target.getScrollBounds() != null ? target : null; + if (!scrollCaptureTargetZOrderFix()) { + ScrollCaptureTarget target = mTargets.isEmpty() ? null : mTargets.get(0); + return target != null && target.getScrollBounds() != null ? target : null; + } + List filtered = new ArrayList<>(); + + mTargets.removeIf(a -> nullOrEmpty(a.getScrollBounds())); + + // Remove scroll targets obscured or covered by other scrolling views. + nextTarget: + for (int i = 0; i < mTargets.size(); i++) { + ScrollCaptureTarget current = mTargets.get(i); + + View currentView = current.getContainingView(); + + // Nested scroll containers: + // Check if the next view is a child of the current. If so, skip the current. + if (i + 1 < mTargets.size()) { + ScrollCaptureTarget next = mTargets.get(i + 1); + View nextView = next.getContainingView(); + // Honor explicit include hint on parent as escape hatch (unless both have it) + if (isDescendant(currentView, nextView) + && (!hasIncludeHint(currentView) || hasIncludeHint(nextView))) { + continue; + } + } + + // Check if any views will be drawn partially or fully over this one. + for (int j = i + 1; j < mTargets.size(); j++) { + ScrollCaptureTarget above = mTargets.get(j); + if (Rect.intersects(getScrollBoundsInWindow(current), + getScrollBoundsInWindow(above))) { + continue nextTarget; + } + } + + filtered.add(current); + } + + // natural order, false->true + Comparator byIncludeHintPresence = comparing( + ScrollCaptureSearchResults::hasIncludeHint); + + // natural order, smallest->largest area + Comparator byArea = comparing( + target -> area(requireNonNullElse(target.getScrollBounds(), new Rect()))); + + // The top result is the last one (with include hint if present, then by largest area) + filtered.sort(byIncludeHintPresence.thenComparing(byArea)); + return filtered.isEmpty() ? null : filtered.getLast(); } private class SearchRequest implements Consumer { @@ -226,6 +293,10 @@ public final class ScrollCaptureSearchResults { return r == null || r.isEmpty(); } + private static boolean hasIncludeHint(ScrollCaptureTarget target) { + return hasIncludeHint(target.getContainingView()); + } + private static boolean hasIncludeHint(View view) { return (view.getScrollCaptureHint() & View.SCROLL_CAPTURE_HINT_INCLUDE) != 0; } diff --git a/core/java/android/view/SurfaceControl.java b/core/java/android/view/SurfaceControl.java index d56768d2db031e26c1b57067ccda5a4f9aa9e635..dd9a95e58bd1c7488ae97953bc439f7d69406315 100644 --- a/core/java/android/view/SurfaceControl.java +++ b/core/java/android/view/SurfaceControl.java @@ -37,6 +37,7 @@ import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.RequiresPermission; import android.annotation.Size; +import android.annotation.SystemApi; import android.annotation.TestApi; import android.compat.annotation.UnsupportedAppUsage; import android.graphics.ColorSpace; @@ -58,6 +59,7 @@ import android.hardware.display.DeviceProductInfo; import android.hardware.display.DisplayedContentSample; import android.hardware.display.DisplayedContentSamplingAttributes; import android.hardware.graphics.common.DisplayDecorationSupport; +import android.media.quality.PictureProfileHandle; import android.opengl.EGLDisplay; import android.opengl.EGLSync; import android.os.Build; @@ -234,7 +236,6 @@ public final class SurfaceControl implements Parcelable { long nativeObject, float currentBufferRatio, float desiredRatio); private static native void nativeSetDesiredHdrHeadroom(long transactionObj, long nativeObject, float desiredRatio); - private static native void nativeSetCachingHint(long transactionObj, long nativeObject, int cachingHint); private static native void nativeSetDamageRegion(long transactionObj, long nativeObject, @@ -314,6 +315,11 @@ public final class SurfaceControl implements Parcelable { private static native void nativeSetLuts(long transactionObj, long nativeObject, float[] buffers, int[] slots, int[] dimensions, int[] sizes, int[] samplingKeys); private static native void nativeEnableDebugLogCallPoints(long transactionObj); + private static native int nativeGetMaxPictureProfiles(); + private static native void nativeSetPictureProfileId(long transactionObj, + long nativeObject, long pictureProfileId); + private static native void nativeSetContentPriority(long transactionObj, long nativeObject, + int priority); /** * Transforms that can be applied to buffers as they are displayed to a window. @@ -598,8 +604,11 @@ public final class SurfaceControl implements Parcelable { } /** - * Request a flush of any pending jank classification data. May cause the registered - * listener to be invoked inband. + * Request a flush of any pending jank classification data. + *

+ * May cause the registered listener to be invoked inband. Since jank is tracked by the + * system compositor by surface, flushing the data on one listener, will also cause other + * listeners on the same surface to receive jank classification data. */ public void flush() { nativeFlushJankData(mNativeObject); @@ -1923,6 +1932,7 @@ public final class SurfaceControl implements Parcelable { public float renderFrameRate; public boolean hasArrSupport; public FrameRateCategoryRate frameRateCategoryRate; + public float[] supportedRefreshRates; public int[] supportedColorModes; public int activeColorMode; @@ -1942,6 +1952,7 @@ public final class SurfaceControl implements Parcelable { + ", renderFrameRate=" + renderFrameRate + ", hasArrSupport=" + hasArrSupport + ", frameRateCategoryRate=" + frameRateCategoryRate + + ", supportedRefreshRates=" + Arrays.toString(supportedRefreshRates) + ", supportedColorModes=" + Arrays.toString(supportedColorModes) + ", activeColorMode=" + activeColorMode + ", hdrCapabilities=" + hdrCapabilities @@ -1963,14 +1974,15 @@ public final class SurfaceControl implements Parcelable { && Objects.equals(hdrCapabilities, that.hdrCapabilities) && preferredBootDisplayMode == that.preferredBootDisplayMode && hasArrSupport == that.hasArrSupport - && Objects.equals(frameRateCategoryRate, that.frameRateCategoryRate); + && Objects.equals(frameRateCategoryRate, that.frameRateCategoryRate) + && Arrays.equals(supportedRefreshRates, that.supportedRefreshRates); } @Override public int hashCode() { return Objects.hash(Arrays.hashCode(supportedDisplayModes), activeDisplayModeId, renderFrameRate, activeColorMode, hdrCapabilities, hasArrSupport, - frameRateCategoryRate); + frameRateCategoryRate, Arrays.hashCode(supportedRefreshRates)); } } @@ -2832,6 +2844,33 @@ public final class SurfaceControl implements Parcelable { return nativeBootFinished(); } + /** + * Retrieve the maximum number of concurrent picture profiles allowed across all displays. + * + * A picture profile is assigned to a layer via: + *

    + *
  • Picture processing via {@link MediaCodec.KEY_PICTURE_PROFILE}
  • + *
  • Picture processing via {@link SurfaceControl.Transaction#setPictureProfileHandle} + *
  • + *
+ * + * If the maximum number is exceeded, some layers will not receive profiles based on: + *
    + *
  • The content priority assigned by the app
  • + *
  • The system-determined priority of the app owning the layer
  • + *
+ * + * @see MediaCodec.KEY_PICTURE_PROFILE + * @see SurfaceControl.Transaction#setPictureProfileHandle + * @see SurfaceControl.Transaction#setContentPriority + * + * @hide + */ + @IntRange(from = 0) + public static int getMaxPictureProfiles() { + return nativeGetMaxPictureProfiles(); + } + /** * Interface to handle request to * {@link SurfaceControl.Transaction#addTransactionCommittedListener(Executor, TransactionCommittedListener)} @@ -4594,6 +4633,71 @@ public final class SurfaceControl implements Parcelable { return this; } + /** + * Sets the desired picture profile handle for a layer. + *

+ * A handle, retrieved from {@link MediaQualityManager#getProfileHandles}, which + * refers a set of parameters that are used to configure picture processing that is applied + * to all subsequent buffers to enhance the quality of their contents (e.g. gamma, color + * temperature, hue, saturation, etc.). + *

+ * Setting a handle does not guarantee access to limited picture processing. The content + * priority for the as well as the prominance of app to the current user experience plays a + * role in which layer(s) get access to the limited picture processing resources. A maximum + * number of {@link MediaQualityManager.getMaxPictureProfiles} can be applied at any given + * point in time. + * + * @param sc The SurfaceControl of the layer that should be updated + * @param handle The picture profile handle which refers to the set of desired parameters + * + * @see MediaQualityManager#getMaxPictureProfiles + * @see MediaQualityManager#getProfileHandles + * @see MediaCodec.KEY_PICTURE_PROFILE + * @see SurfaceControl.Transaction#setContentPriority + * + * @hide + */ + @FlaggedApi(android.media.tv.flags.Flags.FLAG_APPLY_PICTURE_PROFILES) + @SystemApi + public @NonNull Transaction setPictureProfileHandle(@NonNull SurfaceControl sc, + @NonNull PictureProfileHandle handle) { + checkPreconditions(sc); + + nativeSetPictureProfileId(mNativeObject, sc.mNativeObject, handle.getId()); + return this; + } + + /** + * Sets the importance the layer's contents has to the app's user experience. + *

+ * When a two layers within the same app are competing for a limited rendering resource, + * the priority will determine which layer gets access to the resource. The lower the + * priority, the more likely the layer will get access to the resource. + *

+ * Resources managed by this priority: + *

    + *
  • Picture processing via {@link MediaCodec.KEY_PICTURE_PROFILE}
  • + *
  • Picture processing via {@link SurfaceControl.Transaction#setPictureProfileHandle} + *
  • + *
+ * + * @param sc The SurfaceControl of the layer that should be updated + * @param priority The priority this layer should have with respect to other layers in the + * app. The default priority is zero. + * + * @see MediaQualityManager#getMaxPictureProfiles + * @see MediaCodec.KEY_PICTURE_PROFILE + * @see SurfaceControl.Transaction#setPictureProfileHandle + */ + @FlaggedApi(android.media.tv.flags.Flags.FLAG_APPLY_PICTURE_PROFILES) + public @NonNull Transaction setContentPriority(@NonNull SurfaceControl sc, + int priority) { + checkPreconditions(sc); + + nativeSetContentPriority(mNativeObject, sc.mNativeObject, priority); + return this; + } + /** * Sets the caching hint for the layer. By default, the caching hint is * {@link CACHING_ENABLED}. diff --git a/core/java/android/view/SurfaceControlActivePicture.java b/core/java/android/view/SurfaceControlActivePicture.java new file mode 100644 index 0000000000000000000000000000000000000000..569159d73d2d76072a3f082063ed9eba0cc1c8f8 --- /dev/null +++ b/core/java/android/view/SurfaceControlActivePicture.java @@ -0,0 +1,58 @@ +/* + * 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.view; + +import android.annotation.NonNull; +import android.media.quality.PictureProfileHandle; + +/** + * A record of a visible layer that is using picture processing. + * @hide + */ +public class SurfaceControlActivePicture { + private final int mLayerId; + private final int mOwnerUid; + private final @NonNull PictureProfileHandle mPictureProfileHandle; + + /** + * Create a record of a visible layer that is using picture processing. + * + * @param layerId the layer that is using picture processing + * @param ownerUid the UID of the package that owns the layer + * @param handle the handle for the picture profile that configured the processing + */ + private SurfaceControlActivePicture(int layerId, int ownerUid, PictureProfileHandle handle) { + mLayerId = layerId; + mOwnerUid = ownerUid; + mPictureProfileHandle = handle; + } + + /** The layer that is using picture processing. */ + public int getLayerId() { + return mLayerId; + } + + /** The UID of the package that owns the layer using picture processing. */ + public int getOwnerUid() { + return mOwnerUid; + } + + /** A handle that indicates which picture profile has configured the picture processing. */ + public @NonNull PictureProfileHandle getPictureProfileHandle() { + return mPictureProfileHandle; + } +} diff --git a/core/java/android/view/SurfaceControlActivePictureListener.java b/core/java/android/view/SurfaceControlActivePictureListener.java new file mode 100644 index 0000000000000000000000000000000000000000..d7c53748784fd3cc543f668e38134b45cbf112e0 --- /dev/null +++ b/core/java/android/view/SurfaceControlActivePictureListener.java @@ -0,0 +1,69 @@ +/* + * 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.view; + +import android.annotation.RequiresPermission; + +import libcore.util.NativeAllocationRegistry; + +/** + * Allows for the monitoring of visible layers that are using picture processing. + * @hide + */ +public abstract class SurfaceControlActivePictureListener { + private static final NativeAllocationRegistry sRegistry = + NativeAllocationRegistry.createMalloced( + SurfaceControlActivePictureListener.class.getClassLoader(), + nativeGetDestructor()); + + /** + * Callback when there are changes in the visible layers that are using picture processing. + * + * @param activePictures The visible layers that are using picture processing. + */ + public abstract void onActivePicturesChanged(SurfaceControlActivePicture[] activePictures); + + /** + * Start listening to changes in active pictures. + */ + @RequiresPermission(android.Manifest.permission.OBSERVE_PICTURE_PROFILES) + public void startListening() { + synchronized (this) { + long nativePtr = nativeMakeAndStartListening(); + mDestructor = sRegistry.registerNativeAllocation(this, nativePtr); + } + } + + /** + * Stop listening to changes in active pictures. + */ + @RequiresPermission(android.Manifest.permission.OBSERVE_PICTURE_PROFILES) + public void stopListening() { + final Runnable destructor; + synchronized (this) { + destructor = mDestructor; + } + if (destructor != null) { + destructor.run(); + } + } + + private native long nativeMakeAndStartListening(); + private static native long nativeGetDestructor(); + + private Runnable mDestructor; +} diff --git a/core/java/android/view/SurfaceView.java b/core/java/android/view/SurfaceView.java index 4df7649e1c9b442020f3db4e98a0dca525b75b77..b0051cefb21bc2375c31dbab8dd5a0becaf02a68 100644 --- a/core/java/android/view/SurfaceView.java +++ b/core/java/android/view/SurfaceView.java @@ -932,7 +932,8 @@ public class SurfaceView extends View implements ViewRootImpl.SurfaceChangedCall /** * Sets the desired amount of HDR headroom to be used when HDR content is presented on this - * SurfaceView. + * SurfaceView. This is expressed as the ratio of maximum HDR white point over the SDR + * white point, not as absolute nits. * *

By default the system will choose an amount of HDR headroom that is appropriate * for the underlying device capabilities & bit-depth of the panel. However, for some types @@ -946,6 +947,10 @@ public class SurfaceView extends View implements ViewRootImpl.SurfaceChangedCall * See {@link Display#getHdrSdrRatio()} for more information as well as how to query the * current value.

* + *

Note: This API operates independently of both the + * {@link Window#setColorMode Widow color mode} and the + * {@link Window#setDesiredHdrHeadroom Window desiredHdrHeadroom}

+ * * @param desiredHeadroom The amount of HDR headroom that is desired. Must be >= 1.0 (no HDR) * and <= 10,000.0. Passing 0.0 will reset to the default, automatically * chosen value. diff --git a/core/java/android/view/ViewGroup.java b/core/java/android/view/ViewGroup.java index 4a9916c007c496975188d5f8b790d860693f33f2..949b667f0b7a1bbb5a449fee0bfc1b166f32ce35 100644 --- a/core/java/android/view/ViewGroup.java +++ b/core/java/android/view/ViewGroup.java @@ -20,6 +20,7 @@ import static android.view.WindowInsetsAnimation.Callback.DISPATCH_MODE_CONTINUE import static android.view.WindowInsetsAnimation.Callback.DISPATCH_MODE_STOP; import static android.view.flags.Flags.FLAG_TOOLKIT_VIEWGROUP_SET_REQUESTED_FRAME_RATE_API; import static android.view.flags.Flags.toolkitViewgroupSetRequestedFrameRateApi; +import static android.view.flags.Flags.scrollCaptureTargetZOrderFix; import android.animation.LayoutTransition; import android.annotation.CallSuper; @@ -7657,6 +7658,11 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager @NonNull Rect localVisibleRect, @NonNull Point windowOffset, @NonNull Consumer targets) { + // Only visible views can be captured. + if (getVisibility() != View.VISIBLE) { + return; + } + if (getClipToPadding() && !localVisibleRect.intersect(mPaddingLeft, mPaddingTop, (mRight - mLeft) - mPaddingRight, (mBottom - mTop) - mPaddingBottom)) { return; @@ -7665,19 +7671,39 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager // Dispatch to self first. super.dispatchScrollCaptureSearch(localVisibleRect, windowOffset, targets); + final int childrenCount = mChildrenCount; + if (childrenCount == 0) { + return; + } + // Skip children if descendants excluded. if ((getScrollCaptureHint() & SCROLL_CAPTURE_HINT_EXCLUDE_DESCENDANTS) != 0) { return; } - final Rect tmpRect = getTempRect(); - final int childCount = getChildCount(); - for (int i = 0; i < childCount; i++) { - View child = getChildAt(i); + + ArrayList preorderedList = null; + boolean customOrder = false; + if (scrollCaptureTargetZOrderFix()) { + preorderedList = buildOrderedChildList(); + customOrder = preorderedList == null && isChildrenDrawingOrderEnabled(); + } + final View[] children = mChildren; + for (int i = 0; i < childrenCount; i++) { + View child; + if (scrollCaptureTargetZOrderFix()) { + // Traverse children in the same order they will be drawn (honors Z if set) + final int childIndex = getAndVerifyPreorderedIndex(childrenCount, i, customOrder); + child = getAndVerifyPreorderedView(preorderedList, children, childIndex); + } else { + child = children[i]; + } + // Only visible views can be captured. if (child.getVisibility() != View.VISIBLE) { continue; } + // Offset the given rectangle (in parent's local coordinates) into child's coordinate // space and clip the result to the child View's bounds, padding and clipRect as needed. // If the resulting rectangle is not empty, the request is forwarded to the child. @@ -7706,6 +7732,9 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager child.dispatchScrollCaptureSearch(tmpRect, childWindowOffset, targets); } } + if (preorderedList != null) { + preorderedList.clear(); + } } /** diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java index 19d3dc4df04e83784a0d7f1c712735e0fb52f123..a0feccd87a81d24c8e0a160b97dc1e9c9fc7cd42 100644 --- a/core/java/android/view/ViewRootImpl.java +++ b/core/java/android/view/ViewRootImpl.java @@ -110,7 +110,6 @@ import static android.view.WindowManager.PROPERTY_COMPAT_ALLOW_SANDBOXING_VIEW_B import static android.view.WindowManagerGlobal.RELAYOUT_RES_CANCEL_AND_REDRAW; import static android.view.WindowManagerGlobal.RELAYOUT_RES_CONSUME_ALWAYS_SYSTEM_BARS; import static android.view.WindowManagerGlobal.RELAYOUT_RES_SURFACE_CHANGED; -import static android.view.accessibility.Flags.fixMergedContentChangeEventV2; import static android.view.accessibility.Flags.forceInvertColor; import static android.view.accessibility.Flags.reduceWindowContentChangedEventThrottle; import static android.view.flags.Flags.addSchandleToVriSurface; @@ -1237,6 +1236,8 @@ public final class ViewRootImpl implements ViewParent, private @ActivityInfo.ColorMode int mCurrentColorMode = ActivityInfo.COLOR_MODE_DEFAULT; private long mColorModeLastSetMillis = -1; + private final boolean mIsSubscribeGranularDisplayEventsEnabled; + public ViewRootImpl(Context context, Display display) { this(context, display, WindowManagerGlobal.getWindowSession(), new WindowLayout()); } @@ -1334,6 +1335,8 @@ public final class ViewRootImpl implements ViewParent, // Disable DRAW_WAKE_LOCK starting U. mDisableDrawWakeLock = CompatChanges.isChangeEnabled(DISABLE_DRAW_WAKE_LOCK) && disableDrawWakeLock(); + mIsSubscribeGranularDisplayEventsEnabled = + com.android.server.display.feature.flags.Flags.subscribeGranularDisplayEvents(); } public static void addFirstDrawHandler(Runnable callback) { @@ -1811,14 +1814,22 @@ public final class ViewRootImpl implements ViewParent, mAccessibilityInteractionConnectionManager, mHandler); mAccessibilityManager.addHighContrastTextStateChangeListener( mExecutor, mHighContrastTextManager); + + + long eventsToBeRegistered = + (mIsSubscribeGranularDisplayEventsEnabled) + ? DisplayManagerGlobal.INTERNAL_EVENT_FLAG_DISPLAY_ADDED + | DisplayManagerGlobal.INTERNAL_EVENT_FLAG_DISPLAY_STATE + | DisplayManagerGlobal.INTERNAL_EVENT_FLAG_DISPLAY_REMOVED + : DisplayManagerGlobal.INTERNAL_EVENT_FLAG_DISPLAY_ADDED + | DisplayManagerGlobal.INTERNAL_EVENT_FLAG_DISPLAY_CHANGED + | DisplayManagerGlobal.INTERNAL_EVENT_FLAG_DISPLAY_REMOVED; DisplayManagerGlobal .getInstance() .registerDisplayListener( mDisplayListener, mHandler, - DisplayManagerGlobal.INTERNAL_EVENT_FLAG_DISPLAY_ADDED - | DisplayManagerGlobal.INTERNAL_EVENT_FLAG_DISPLAY_CHANGED - | DisplayManagerGlobal.INTERNAL_EVENT_FLAG_DISPLAY_REMOVED, + eventsToBeRegistered, mBasePackageName); if (forceInvertColor()) { @@ -2515,12 +2526,16 @@ public final class ViewRootImpl implements ViewParent, @VisibleForTesting public void notifyInsetsAnimationRunningStateChanged(boolean running) { if (sToolkitSetFrameRateReadOnlyFlagValue) { - mInsetsAnimationRunning = running; if (Trace.isTagEnabled(Trace.TRACE_TAG_VIEW)) { Trace.instant(Trace.TRACE_TAG_VIEW, TextUtils.formatSimple("notifyInsetsAnimationRunningStateChanged(%s)", Boolean.toString(running))); } + mInsetsAnimationRunning = running; + try { + mWindowSession.notifyInsetsAnimationRunningStateChanged(mWindow, running); + } catch (RemoteException e) { + } } } @@ -8873,11 +8888,6 @@ public final class ViewRootImpl implements ViewParent, SyntheticTouchNavigationHandler() { super(true); - int gestureDetectorVelocityStrategy = - android.companion.virtual.flags.Flags - .impulseVelocityStrategyForTouchNavigation() - ? VelocityTracker.VELOCITY_TRACKER_STRATEGY_IMPULSE - : VelocityTracker.VELOCITY_TRACKER_STRATEGY_DEFAULT; mGestureDetector = new GestureDetector(mContext, new GestureDetector.OnGestureListener() { @Override @@ -8917,7 +8927,7 @@ public final class ViewRootImpl implements ViewParent, } }, /* handler= */ null, - gestureDetectorVelocityStrategy); + VelocityTracker.VELOCITY_TRACKER_STRATEGY_IMPULSE); } public void process(MotionEvent event) { @@ -12290,31 +12300,20 @@ public final class ViewRootImpl implements ViewParent, } if (mSource != null) { - if (fixMergedContentChangeEventV2()) { - View newSource = getCommonPredecessor(mSource, source); - if (newSource != null) { - newSource = newSource.getSelfOrParentImportantForA11y(); - } - if (newSource == null) { - // If there is no common predecessor, then mSource points to - // a removed view, hence in this case always prefer the source. - newSource = source; - } - - mChangeTypes |= changeType; - if (mSource != newSource) { - mChangeTypes |= AccessibilityEvent.CONTENT_CHANGE_TYPE_SUBTREE; - mSource = newSource; - } - } else { + View newSource = getCommonPredecessor(mSource, source); + if (newSource != null) { + newSource = newSource.getSelfOrParentImportantForA11y(); + } + if (newSource == null) { // If there is no common predecessor, then mSource points to // a removed view, hence in this case always prefer the source. - View predecessor = getCommonPredecessor(mSource, source); - if (predecessor != null) { - predecessor = predecessor.getSelfOrParentImportantForA11y(); - } - mSource = (predecessor != null) ? predecessor : source; - mChangeTypes |= changeType; + newSource = source; + } + + mChangeTypes |= changeType; + if (mSource != newSource) { + mChangeTypes |= AccessibilityEvent.CONTENT_CHANGE_TYPE_SUBTREE; + mSource = newSource; } final int performingAction = mAccessibilityManager.getPerformingAction(); diff --git a/core/java/android/view/Window.java b/core/java/android/view/Window.java index 381006c8a21bbbd902ec56a4ea745f1e649d717a..39533344173beb118d92e39c2c656e40d472a605 100644 --- a/core/java/android/view/Window.java +++ b/core/java/android/view/Window.java @@ -1334,6 +1334,9 @@ public abstract class Window { *

The requested color mode is not guaranteed to be honored. Please refer to * {@link #getColorMode()} for more information.

* + *

Note: This does not impact SurfaceViews or SurfaceControls, as those have their own + * independent color mode and HDR parameters.

+ * * @see #getColorMode() * @see Display#isWideColorGamut() * @see Configuration#isScreenWideColorGamut() @@ -1361,6 +1364,9 @@ public abstract class Window { * See {@link Display#getHdrSdrRatio()} for more information as well as how to query the * current value.

* + *

Note: This does not impact SurfaceViews or SurfaceControls, as those have their own + * independent desired HDR headroom and HDR capabilities.

+ * * @param desiredHeadroom The amount of HDR headroom that is desired. Must be >= 1.0 (no HDR) * and <= 10,000.0. Passing 0.0 will reset to the default, automatically * chosen value. diff --git a/core/java/android/view/WindowManager.java b/core/java/android/view/WindowManager.java index b4b0687eb4983cc1c57a28c22b607431d03faba1..1e8cad61381c257d87a451fc4670d5c126d6ebb1 100644 --- a/core/java/android/view/WindowManager.java +++ b/core/java/android/view/WindowManager.java @@ -1426,8 +1426,9 @@ public interface WindowManager extends ViewManager { "android.window.PROPERTY_COMPAT_ALLOW_USER_ASPECT_RATIO_FULLSCREEN_OVERRIDE"; /** - * Activity-level {@link android.content.pm.PackageManager.Property PackageManager.Property} - * that specifies whether this activity can declare or request + * Application or Activity level + * {@link android.content.pm.PackageManager.Property PackageManager.Property} + * that specifies whether this package or activity can declare or request * {@link android.R.attr#screenOrientation fixed orientation}, * {@link android.R.attr#minAspectRatio max aspect ratio}, * {@link android.R.attr#maxAspectRatio min aspect ratio} @@ -1438,6 +1439,13 @@ public interface WindowManager extends ViewManager { * *

Syntax: *

+     * <application>
+     *   <property
+     *     android:name="android.window.PROPERTY_COMPAT_ALLOW_USER_ASPECT_RATIO_FULLSCREEN_OVERRIDE"
+     *     android:value="false"/>
+     * </application>
+     * 
or + *
      * <activity>
      *   <property
      *     android:name="android.window.PROPERTY_COMPAT_ALLOW_RESTRICTED_RESIZABILITY"
@@ -1446,7 +1454,7 @@ public interface WindowManager extends ViewManager {
      * 
* @hide */ - // TODO(b/357141415): Make this public API. + // TODO(b/357141415): Remove this from sdk 37 String PROPERTY_COMPAT_ALLOW_RESTRICTED_RESIZABILITY = "android.window.PROPERTY_COMPAT_ALLOW_RESTRICTED_RESIZABILITY"; diff --git a/core/java/android/view/WindowlessWindowManager.java b/core/java/android/view/WindowlessWindowManager.java index 65e99304997956c2e2c36411fd291e2ac86e479c..72a595d95ec2b526cd76806a03717c5f2849bd01 100644 --- a/core/java/android/view/WindowlessWindowManager.java +++ b/core/java/android/view/WindowlessWindowManager.java @@ -679,6 +679,11 @@ public class WindowlessWindowManager implements IWindowSession { @NonNull ImeTracker.Token statsToken) { } + @Override + public void notifyInsetsAnimationRunningStateChanged(IWindow window, boolean running) { + // NO-OP + } + void setParentInterface(@Nullable ISurfaceControlViewHostParent parentInterface) { IBinder oldInterface = mParentInterface == null ? null : mParentInterface.asBinder(); IBinder newInterface = parentInterface == null ? null : parentInterface.asBinder(); diff --git a/core/java/android/view/accessibility/AccessibilityEvent.java b/core/java/android/view/accessibility/AccessibilityEvent.java index 0dfaf4149ce5b616954c386f221f517fd9e6a605..88ccf88d40f68f997f3f9b676a32ad91bb779ebb 100644 --- a/core/java/android/view/accessibility/AccessibilityEvent.java +++ b/core/java/android/view/accessibility/AccessibilityEvent.java @@ -959,6 +959,8 @@ public final class AccessibilityEvent extends AccessibilityRecord implements Par CONTENT_CHANGE_TYPE_CONTENT_INVALID, CONTENT_CHANGE_TYPE_ERROR, CONTENT_CHANGE_TYPE_ENABLED, + CONTENT_CHANGE_TYPE_CHECKED, + CONTENT_CHANGE_TYPE_EXPANDED, CONTENT_CHANGE_TYPE_SUPPLEMENTAL_DESCRIPTION, }) public @interface ContentChangeTypes {} @@ -1241,6 +1243,16 @@ public final class AccessibilityEvent extends AccessibilityRecord implements Par case CONTENT_CHANGE_TYPE_ERROR: return "CONTENT_CHANGE_TYPE_ERROR"; case CONTENT_CHANGE_TYPE_ENABLED: return "CONTENT_CHANGE_TYPE_ENABLED"; default: { + if (Flags.triStateChecked()) { + if (type == CONTENT_CHANGE_TYPE_CHECKED) { + return "CONTENT_CHANGE_TYPE_CHECKED"; + } + } + if (Flags.a11yExpansionStateApi()) { + if (type == CONTENT_CHANGE_TYPE_EXPANDED) { + return "CONTENT_CHANGE_TYPE_EXPANDED"; + } + } if (Flags.supplementalDescription()) { if (type == CONTENT_CHANGE_TYPE_SUPPLEMENTAL_DESCRIPTION) { return "CONTENT_CHANGE_TYPE_SUPPLEMENTAL_DESCRIPTION"; diff --git a/core/java/android/view/accessibility/AccessibilityNodeInfo.java b/core/java/android/view/accessibility/AccessibilityNodeInfo.java index 0204517e869a466da20cf4e20f42bdfce6e686eb..df0c5a34e9923d60bfd374e8ba7ffab62a63e870 100644 --- a/core/java/android/view/accessibility/AccessibilityNodeInfo.java +++ b/core/java/android/view/accessibility/AccessibilityNodeInfo.java @@ -6551,15 +6551,23 @@ public class AccessibilityNodeInfo implements Parcelable { /** * Range type: indeterminate. * + * When using this type, the {@code min}, {@code max}, and {@code current} values used to + * construct an instance may be ignored. + * + * @see #INDETERMINATE + */ + @FlaggedApi(Flags.FLAG_INDETERMINATE_RANGE_INFO) + public static final int RANGE_TYPE_INDETERMINATE = 3; + + /** * A {@link RangeInfo} type used to represent a node which may typically expose range * information but is presently in an indeterminate state, such as a {@link * android.widget.ProgressBar} representing a loading operation of unknown duration. - * When using this type, the {@code min}, {@code max}, and {@code current} values used to - * construct an instance may be ignored. It is recommended to use {@code Float.NaN} for - * these values. */ + @NonNull @FlaggedApi(Flags.FLAG_INDETERMINATE_RANGE_INFO) - public static final int RANGE_TYPE_INDETERMINATE = 3; + public static final RangeInfo INDETERMINATE = new RangeInfo(RANGE_TYPE_INDETERMINATE, 0.0f, + 0.0f, 0.0f); private int mType; private float mMin; diff --git a/core/java/android/view/accessibility/flags/accessibility_flags.aconfig b/core/java/android/view/accessibility/flags/accessibility_flags.aconfig index 8a006fa5b509aec59b96970652316665e5ce22f0..e60fc3ae6b472fb519879e9d3ee1b56dc4b9cb53 100644 --- a/core/java/android/view/accessibility/flags/accessibility_flags.aconfig +++ b/core/java/android/view/accessibility/flags/accessibility_flags.aconfig @@ -97,16 +97,6 @@ flag { bug: "333783827" } -flag { - namespace: "accessibility" - name: "fix_merged_content_change_event_v2" - description: "Fixes event type and source of content change event merged in ViewRootImpl" - bug: "277305460" - metadata { - purpose: PURPOSE_BUGFIX - } -} - flag { namespace: "accessibility" name: "flash_notification_system_api" diff --git a/core/java/android/view/flags/scroll_capture.aconfig b/core/java/android/view/flags/scroll_capture.aconfig new file mode 100644 index 0000000000000000000000000000000000000000..fdf9c1ed8ad267d10945f23aa721bc627d03d0b1 --- /dev/null +++ b/core/java/android/view/flags/scroll_capture.aconfig @@ -0,0 +1,13 @@ +package: "android.view.flags" +container: "system" + +flag { + name: "scroll_capture_target_z_order_fix" + namespace: "system_ui" + description: "Always prefer targets with higher z-order" + bug: "365969802" + metadata { + purpose: PURPOSE_BUGFIX + } +} + diff --git a/core/java/android/view/inputmethod/InputMethodSession.java b/core/java/android/view/inputmethod/InputMethodSession.java index 4f48cb684e8cccefbd0346d843de6dab6d33f7f0..1806a8369d013e62b19dd50f669cd0a90fa29202 100644 --- a/core/java/android/view/inputmethod/InputMethodSession.java +++ b/core/java/android/view/inputmethod/InputMethodSession.java @@ -16,6 +16,7 @@ package android.view.inputmethod; +import android.annotation.NonNull; import android.graphics.Rect; import android.inputmethodservice.InputMethodService; import android.os.Bundle; @@ -124,6 +125,23 @@ public interface InputMethodSession { */ public void dispatchKeyEvent(int seq, KeyEvent event, EventCallback callback); + /** + * Received by the IME before dispatch to {@link InputMethodService#onKeyDown(int, KeyEvent)} + * to let the system know if the {@link KeyEvent} needs to be verified that it originated from + * the system. {@link KeyEvent}s may originate from outside of the system and any sensitive keys + * should be marked for verification. One example of this could be using key shortcuts for + * switching to another IME. + * + * @param event the event that may need verification. + * @return {@code true} if {@link KeyEvent} should have its HMAC verified before dispatch, + * {@code false} otherwise. + * + * @hide + */ + default boolean onShouldVerifyKeyEvent(@NonNull KeyEvent event) { + return false; + } + /** * This method is called when there is a track ball event. * diff --git a/core/java/android/view/inputmethod/flags.aconfig b/core/java/android/view/inputmethod/flags.aconfig index deaf95797127b9c8ed5770e9d00ffb2e1aa41a82..73abc472be6d6f388ad3a25b25b650364e9145ed 100644 --- a/core/java/android/view/inputmethod/flags.aconfig +++ b/core/java/android/view/inputmethod/flags.aconfig @@ -184,3 +184,11 @@ flag { bug: "350047836" is_fixed_read_only: true } + +flag { + name: "verify_key_event" + namespace: "input_method" + description: "Verify KeyEvents in IME" + bug: "331730488" + is_fixed_read_only: true +} diff --git a/core/java/android/widget/Button.java b/core/java/android/widget/Button.java index 98c00ac7f6f7cad5ef1b19732177f1c085d28eca..0bf6380eb904db077f7a5faddfe407ca63382b9d 100644 --- a/core/java/android/widget/Button.java +++ b/core/java/android/widget/Button.java @@ -16,17 +16,22 @@ package android.widget; -import static android.view.flags.Flags.enableArrowIconOnHoverWhenClickable; import static android.view.flags.Flags.FLAG_ENABLE_ARROW_ICON_ON_HOVER_WHEN_CLICKABLE; +import static android.view.flags.Flags.enableArrowIconOnHoverWhenClickable; import android.annotation.FlaggedApi; +import android.app.compat.CompatChanges; +import android.compat.annotation.ChangeId; +import android.compat.annotation.EnabledSince; import android.content.Context; +import android.content.pm.PackageManager; import android.util.AttributeSet; import android.view.InputDevice; import android.view.LayoutInflater; import android.view.MotionEvent; import android.view.PointerIcon; import android.widget.RemoteViews.RemoteView; +import android.widget.flags.Flags; /** * A user interface element the user can tap or click to perform an action. @@ -88,6 +93,12 @@ import android.widget.RemoteViews.RemoteView; @RemoteView public class Button extends TextView { + @ChangeId + @EnabledSince(targetSdkVersion = 36) + private static final long WEAR_MATERIAL3_BUTTON = 376561342L; + + private static Boolean sUseWearMaterial3Style; + /** * Simple constructor to use when creating a button from code. * @@ -118,7 +129,18 @@ public class Button extends TextView { * @see android.view.View#View(Context, AttributeSet) */ public Button(Context context, AttributeSet attrs) { - this(context, attrs, com.android.internal.R.attr.buttonStyle); + // Starting sdk 36+, wear devices will use a specific material3 + // design. The new design will be applied when all of following conditions are met: + // 1. app target sdk is 36 or above. + // 2. feature flag rolled-out. + // 3. device is a watch. + // getButtonDefaultStyleAttr and getButtonDefaultStyleRes works together to alter the UI + // while considering the conditions above. + // Their results are mutual exclusive. i.e. when conditions above are all true, + // getButtonDefaultStyleRes returns non-zero value(new wear material3), abd + // getButtonDefaultStyleAttr returns 0. Otherwise, getButtonDefaultStyleAttr returns system + // attr com.android.internal.R.attr.buttonStyle and getButtonDefaultStyleRes returns 0. + this(context, attrs, getButtonDefaultStyleAttr(context), getButtonDefaultStyleRes()); } /** @@ -189,4 +211,24 @@ public class Button extends TextView { } return super.onResolvePointerIcon(event, pointerIndex); } + + private static int getButtonDefaultStyleAttr(Context context) { + sUseWearMaterial3Style = useWearMaterial3Style(context); + if (sUseWearMaterial3Style) { + return 0; + } + return com.android.internal.R.attr.buttonStyle; + } + + private static int getButtonDefaultStyleRes() { + if (sUseWearMaterial3Style != null && sUseWearMaterial3Style) { + return com.android.internal.R.style.Widget_DeviceDefault_Button_WearMaterial3; + } + return 0; + } + + private static boolean useWearMaterial3Style(Context context) { + return Flags.useWearMaterial3Ui() && CompatChanges.isChangeEnabled(WEAR_MATERIAL3_BUTTON) + && context.getPackageManager().hasSystemFeature(PackageManager.FEATURE_WATCH); + } } diff --git a/core/java/android/widget/ProgressBar.java b/core/java/android/widget/ProgressBar.java index 6e43d0f1c6cd79bcba55fe729e85c9c228bdc7b2..2a8a92882310c05fa47f1ea6f88a2955718f1e3b 100644 --- a/core/java/android/widget/ProgressBar.java +++ b/core/java/android/widget/ProgressBar.java @@ -16,6 +16,8 @@ package android.widget; +import static android.view.accessibility.Flags.indeterminateRangeInfo; + import android.animation.Animator; import android.animation.AnimatorListenerAdapter; import android.animation.ObjectAnimator; @@ -2364,15 +2366,22 @@ public class ProgressBar extends View { public void onInitializeAccessibilityNodeInfoInternal(AccessibilityNodeInfo info) { super.onInitializeAccessibilityNodeInfoInternal(info); - if (!isIndeterminate()) { - AccessibilityNodeInfo.RangeInfo rangeInfo = AccessibilityNodeInfo.RangeInfo.obtain( + AccessibilityNodeInfo.RangeInfo rangeInfo = null; + if (isIndeterminate()) { + if (indeterminateRangeInfo()) { + rangeInfo = AccessibilityNodeInfo.RangeInfo.INDETERMINATE; + } + } else { + rangeInfo = new AccessibilityNodeInfo.RangeInfo( AccessibilityNodeInfo.RangeInfo.RANGE_TYPE_INT, getMin(), getMax(), getProgress()); - info.setRangeInfo(rangeInfo); } - // Only set the default state description when custom state descripton is null. + info.setRangeInfo(rangeInfo); + + // Only set the default state description when custom state description is null. if (getStateDescription() == null) { + // TODO(b/380340432): Remove after accessibility services stop relying on this. if (isIndeterminate()) { info.setStateDescription(getResources().getString(R.string.in_progress)); } else { diff --git a/core/java/android/widget/RemoteViews.java b/core/java/android/widget/RemoteViews.java index 9b6311f35d170660182def0b6998449955d869cf..7e3b904444292ac97eadffa861c77794d9fe94ae 100644 --- a/core/java/android/widget/RemoteViews.java +++ b/core/java/android/widget/RemoteViews.java @@ -20,6 +20,7 @@ import static android.appwidget.flags.Flags.FLAG_DRAW_DATA_PARCEL; import static android.appwidget.flags.Flags.FLAG_REMOTE_VIEWS_PROTO; import static android.appwidget.flags.Flags.drawDataParcel; import static android.appwidget.flags.Flags.remoteAdapterConversion; +import static android.util.TypedValue.TYPE_INT_COLOR_ARGB8; import static android.util.proto.ProtoInputStream.NO_MORE_FIELDS; import static android.view.inputmethod.Flags.FLAG_HOME_SCREEN_HANDWRITING_DELEGATOR; @@ -54,6 +55,10 @@ 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; +import android.content.om.OverlayManagerTransaction; import android.content.pm.ApplicationInfo; import android.content.pm.PackageManager.NameNotFoundException; import android.content.res.ColorStateList; @@ -1293,7 +1298,13 @@ public class RemoteViews implements Parcelable, Filter { @Override public void visitUris(@NonNull Consumer visitor) { - if (mIntentId != -1 || mItems == null) { + if (mItems == null) { + // Null item indicates adapter conversion took place, so the URIs in cached items + // need to be validated. + RemoteCollectionItems cachedItems = mCollectionCache.getItemsForId(mIntentId); + if (cachedItems != null) { + cachedItems.visitUris(visitor); + } return; } @@ -1559,6 +1570,16 @@ public class RemoteViews implements Parcelable, Filter { final Context context = ActivityThread.currentApplication(); final CompletableFuture result = new CompletableFuture<>(); + String contextPackageName = context.getPackageName(); + ComponentName intentComponent = intent.getComponent(); + if (contextPackageName != null + && intentComponent != null + && (!contextPackageName.equals(intentComponent.getPackageName()))) { + // We shouldn't allow for connections to other packages + result.complete(new RemoteCollectionItems.Builder().build()); + return result; + } + context.bindService(intent, Context.BindServiceFlags.of(Context.BIND_AUTO_CREATE), result.defaultExecutor(), new ServiceConnection() { @Override @@ -8468,8 +8489,11 @@ public class RemoteViews implements Parcelable, Filter { } try { LoadedApk.checkAndUpdateApkPaths(mApplication); - return context.createApplicationContext(mApplication, + Context applicationContext = context.createApplicationContext(mApplication, Context.CONTEXT_RESTRICTED); + // Get the correct apk paths while maintaining the current context's configuration. + return applicationContext.createConfigurationContext( + context.getResources().getConfiguration()); } catch (NameNotFoundException e) { Log.e(LOG_TAG, "Package name " + mApplication.packageName + " not found"); } @@ -8547,8 +8571,6 @@ public class RemoteViews implements Parcelable, Filter { /** * Object allowing the modification of a context to overload the system's dynamic colors. * - * Only colors from {@link android.R.color#system_accent1_0} to - * {@link android.R.color#system_neutral2_1000} can be overloaded. * @hide */ public static final class ColorResources { @@ -8559,6 +8581,9 @@ public class RemoteViews implements Parcelable, Filter { // Size, in bytes, of an entry in the array of colors in an ARSC file. private static final int ARSC_ENTRY_SIZE = 16; + private static final String OVERLAY_NAME = "remote_views_color_resources"; + private static final String OVERLAY_TARGET_PACKAGE_NAME = "android"; + private final ResourcesLoader mLoader; private final SparseIntArray mColorMapping; @@ -8629,7 +8654,11 @@ public class RemoteViews implements Parcelable, Filter { } /** - * Adds a resource loader for theme colors to the given context. + * Adds a resource loader for theme colors to the given context. The loader is created + * based on resource files created at build time. + * + *

Only colors from {@link android.R.color#system_accent1_0} to + * {@link android.R.color#system_error_1000} can be overloaded.

* * @param context Context of the view hosting the widget. * @param colorMapping Mapping of resources to color values. @@ -8667,6 +8696,57 @@ public class RemoteViews implements Parcelable, Filter { } return null; } + + /** + * Adds a resource loader for theme colors to the given context. The loader is created + * using fabricated runtime resource overlay (FRRO). + * + *

The created class can overlay any color resources, private or public, at runtime.

+ * + * @param context Context of the view hosting the widget. + * @param colorMapping Mapping of resources to color values. + * + * @hide + */ + @Nullable + public static ColorResources createWithOverlay(Context context, + SparseIntArray colorMapping) { + try { + String owningPackage = context.getPackageName(); + FabricatedOverlay overlay = new FabricatedOverlay.Builder(owningPackage, + OVERLAY_NAME, OVERLAY_TARGET_PACKAGE_NAME).build(); + + for (int i = 0; i < colorMapping.size(); i++) { + overlay.setResourceValue( + context.getResources().getResourceName(colorMapping.keyAt(i)), + TYPE_INT_COLOR_ARGB8, colorMapping.valueAt(i), null); + } + OverlayManager overlayManager = context.getSystemService(OverlayManager.class); + OverlayManagerTransaction.Builder transaction = + new OverlayManagerTransaction.Builder() + .registerFabricatedOverlay(overlay) + .setSelfTargeting(true); + overlayManager.commit(transaction.build()); + + OverlayInfo overlayInfo = + overlayManager.getOverlayInfosForTarget(OVERLAY_TARGET_PACKAGE_NAME) + .stream() + .filter(info -> TextUtils.equals(info.overlayName, OVERLAY_NAME) + && TextUtils.equals(info.packageName, owningPackage)) + .findFirst() + .orElse(null); + if (overlayInfo == null) { + Log.e(LOG_TAG, "Failed to get overlay info ", new Throwable()); + return null; + } + ResourcesLoader colorsLoader = new ResourcesLoader(); + colorsLoader.addProvider(ResourcesProvider.loadOverlay(overlayInfo)); + return new ColorResources(colorsLoader, colorMapping.clone()); + } catch (Exception e) { + Log.e(LOG_TAG, "Failed to add theme color overlay into loader", e); + } + return null; + } } /** @@ -9259,7 +9339,11 @@ public class RemoteViews implements Parcelable, Filter { Set bitmapIdSet = getBitmapIdsUsedByActions(new HashSet<>()); int result = 0; for (int bitmapId: bitmapIdSet) { - result += mBitmapCache.getBitmapForId(bitmapId).getAllocationByteCount(); + Bitmap currentBitmap = mBitmapCache.getBitmapForId(bitmapId); + if (currentBitmap == null) { + continue; + } + result += currentBitmap.getAllocationByteCount(); } return result; diff --git a/core/java/android/widget/flags/flags.aconfig b/core/java/android/widget/flags/flags.aconfig index f0ed83be8f1e70908e9f62fe7bf77935e0b72593..d9dc36ccc8c376ea509254a07cf6abdf13177180 100644 --- a/core/java/android/widget/flags/flags.aconfig +++ b/core/java/android/widget/flags/flags.aconfig @@ -8,4 +8,12 @@ flag { metadata { purpose: PURPOSE_BUGFIX } -} \ No newline at end of file +} + +flag { + name: "use_wear_material3_ui" + namespace: "wear_frameworks" + description: "Whether enable material3 style for wear frameworks' widgets." + is_exported: true + bug: "369480667" +} diff --git a/core/java/android/window/BackProgressAnimator.java b/core/java/android/window/BackProgressAnimator.java index 16eb43700aeff7aaf8a3a6e05a002abcf8e67560..b535effd393ae5e2d76b593be6fbfd275b5bced5 100644 --- a/core/java/android/window/BackProgressAnimator.java +++ b/core/java/android/window/BackProgressAnimator.java @@ -67,7 +67,6 @@ public class BackProgressAnimator implements DynamicAnimation.OnAnimationUpdateL .setStiffness(SpringForce.STIFFNESS_MEDIUM) .setDampingRatio(SpringForce.DAMPING_RATIO_NO_BOUNCY); private final SpringForce mButtonSpringForce = new SpringForce() - .setStiffness(500) .setDampingRatio(SpringForce.DAMPING_RATIO_NO_BOUNCY); private final DynamicAnimation.OnAnimationEndListener mOnAnimationEndListener = (animation, canceled, value, velocity) -> { @@ -157,6 +156,7 @@ public class BackProgressAnimator implements DynamicAnimation.OnAnimationUpdateL /* frameTime */ System.nanoTime() / TimeUtils.NANOS_PER_MS); if (predictiveBackSwipeEdgeNoneApi()) { if (event.getSwipeEdge() == EDGE_NONE) { + mButtonSpringForce.setStiffness(SpringForce.STIFFNESS_LOW); mSpring.setSpring(mButtonSpringForce); mSpring.animateToFinalPosition(SCALE_FACTOR); } else { @@ -228,6 +228,7 @@ public class BackProgressAnimator implements DynamicAnimation.OnAnimationUpdateL * @param finishCallback the callback to be invoked when the progress is reach to 0. */ public void onBackCancelled(@NonNull Runnable finishCallback) { + mButtonSpringForce.setStiffness(SpringForce.STIFFNESS_MEDIUM); mBackCancelledFinishRunnable = finishCallback; mSpring.addEndListener(mOnAnimationEndListener); mSpring.animateToFinalPosition(0); diff --git a/core/java/android/window/IBackAnimationHandoffHandler.aidl b/core/java/android/window/IBackAnimationHandoffHandler.aidl new file mode 100644 index 0000000000000000000000000000000000000000..577948dd0abcd401d5668fb2df2eb8293e150742 --- /dev/null +++ b/core/java/android/window/IBackAnimationHandoffHandler.aidl @@ -0,0 +1,40 @@ +/* + * 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.window; + +import android.os.Bundle; +import android.view.RemoteAnimationTarget; +import android.window.BackMotionEvent; +import android.window.WindowAnimationState; + + +/** + * Interface that allows an {@link OnBackInvokedCallback} object to hand off an animation to another + * handler. + * + * @hide + */ +oneway interface IBackAnimationHandoffHandler { + /** + * Triggers a handoff of the animation of the given targets and their associated states. + * Important: since this is a one-way method, the caller must first make sure that the animation + * can indeed be taken over. + */ + oneway void handOffAnimation(in RemoteAnimationTarget[] targets, + in WindowAnimationState[] states); +} diff --git a/core/java/android/window/IOnBackInvokedCallback.aidl b/core/java/android/window/IOnBackInvokedCallback.aidl index e07d4a9fc61bfeb3f90725b01be5fff619e28e38..81ad4b7bd19e7e169469f0ecd30c7a8e0d920fe3 100644 --- a/core/java/android/window/IOnBackInvokedCallback.aidl +++ b/core/java/android/window/IOnBackInvokedCallback.aidl @@ -18,6 +18,7 @@ package android.window; import android.window.BackMotionEvent; +import android.window.IBackAnimationHandoffHandler; /** * Interface that wraps a {@link OnBackInvokedCallback} object, to be stored in window manager @@ -61,4 +62,9 @@ oneway interface IOnBackInvokedCallback { * Sets whether the back gesture is past the trigger threshold. */ void setTriggerBack(in boolean triggerBack); + + /** + * Sets a {@link IBackAnimationHandoffHandler} that can be used to hand off the back animation. + */ + void setHandoffHandler(in IBackAnimationHandoffHandler handoffHandler); } diff --git a/core/java/android/window/ImeOnBackInvokedDispatcher.java b/core/java/android/window/ImeOnBackInvokedDispatcher.java index c67b9cac250baa1a34e4ec3974d36f02844f8869..d478108d928a369d5bcbaffd3b288a430ea31df3 100644 --- a/core/java/android/window/ImeOnBackInvokedDispatcher.java +++ b/core/java/android/window/ImeOnBackInvokedDispatcher.java @@ -392,6 +392,11 @@ public class ImeOnBackInvokedDispatcher implements OnBackInvokedDispatcher, Parc // no-op } + @Override + public void setHandoffHandler(IBackAnimationHandoffHandler handoffHandler) { + // no-op + } + private void maybeRunOnAnimationCallback(Consumer block) { if (mCallback instanceof OnBackAnimationCallback) { mHandler.post(() -> block.accept((OnBackAnimationCallback) mCallback)); diff --git a/core/java/android/window/WindowContext.java b/core/java/android/window/WindowContext.java index fdaab66f2de3c4b5566a42ed5382f7b9d78b65a9..2b370b9797e572245874f9296d87ee136da44b78 100644 --- a/core/java/android/window/WindowContext.java +++ b/core/java/android/window/WindowContext.java @@ -94,6 +94,23 @@ public class WindowContext extends ContextWrapper implements WindowProvider { mController.attachToDisplayArea(mType, getDisplayId(), mOptions); } + /** + * Updates this context to a new displayId. + *

+ * 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. + */ + @Override + public void updateDisplay(int displayId) { + if (displayId == getDisplayId()) { + return; + } + super.updateDisplay(displayId); + mController.detachIfNeeded(); + mController.attachToDisplayArea(mType, displayId, mOptions); + } + @Override public Object getSystemService(String name) { if (WINDOW_SERVICE.equals(name)) { diff --git a/core/java/android/window/WindowOnBackInvokedDispatcher.java b/core/java/android/window/WindowOnBackInvokedDispatcher.java index 0ea4bb41d3a4bb368ec8cd1f67184e48dd995f12..20e3f6b93bd035aba6832a9cc6a8249606bee51f 100644 --- a/core/java/android/window/WindowOnBackInvokedDispatcher.java +++ b/core/java/android/window/WindowOnBackInvokedDispatcher.java @@ -545,6 +545,11 @@ public class WindowOnBackInvokedDispatcher implements OnBackInvokedDispatcher { }); } + @Override + public void setHandoffHandler(IBackAnimationHandoffHandler handoffHandler) { + // no-op + } + @Override public void onBackProgressed(BackMotionEvent backEvent) { // This is only called in some special cases such as when activity embedding is active diff --git a/core/java/android/window/WindowTokenClient.java b/core/java/android/window/WindowTokenClient.java index 15adc80add01665e7ed27fb3f719d776527fd8c4..6e76d8d345b2cb6b975f2a70a3cb06f96ccb4550 100644 --- a/core/java/android/window/WindowTokenClient.java +++ b/core/java/android/window/WindowTokenClient.java @@ -19,6 +19,8 @@ import static android.window.ConfigurationHelper.freeTextLayoutCachesIfNeeded; import static android.window.ConfigurationHelper.isDifferentDisplay; import static android.window.ConfigurationHelper.shouldUpdateResources; +import static com.android.internal.annotations.VisibleForTesting.Visibility.PACKAGE; + import android.annotation.AnyThread; import android.annotation.MainThread; import android.annotation.NonNull; @@ -104,7 +106,7 @@ public class WindowTokenClient extends Binder { * @param newConfig the updated {@link Configuration} * @param newDisplayId the updated {@link android.view.Display} ID */ - @VisibleForTesting + @VisibleForTesting(visibility = PACKAGE) @MainThread public void onConfigurationChanged(Configuration newConfig, int newDisplayId) { onConfigurationChanged(newConfig, newDisplayId, true /* shouldReportConfigChange */); @@ -113,7 +115,7 @@ public class WindowTokenClient extends Binder { /** * Posts an {@link #onConfigurationChanged} to the main thread. */ - @VisibleForTesting + @VisibleForTesting(visibility = PACKAGE) public void postOnConfigurationChanged(@NonNull Configuration newConfig, int newDisplayId) { mHandler.post(PooledLambda.obtainRunnable(this::onConfigurationChanged, newConfig, newDisplayId, true /* shouldReportConfigChange */).recycleOnUse()); @@ -232,7 +234,7 @@ public class WindowTokenClient extends Binder { /** * Called when the attached window is removed from the display. */ - @VisibleForTesting + @VisibleForTesting(visibility = PACKAGE) @MainThread public void onWindowTokenRemoved() { final Context context = mContextRef.get(); diff --git a/core/java/android/window/WindowTokenClientController.java b/core/java/android/window/WindowTokenClientController.java index abf7bb15b3d85be9e1ead0ca3ddd52d7dad5fc7d..fa345956ec4d120c9bd1db299645e8fdca7811bf 100644 --- a/core/java/android/window/WindowTokenClientController.java +++ b/core/java/android/window/WindowTokenClientController.java @@ -28,7 +28,7 @@ import android.content.Context; import android.os.Bundle; import android.os.IBinder; import android.os.RemoteException; -import android.util.ArrayMap; +import android.util.ArraySet; import android.util.Log; import android.view.IWindowManager; import android.view.WindowManagerGlobal; @@ -50,9 +50,9 @@ public class WindowTokenClientController { private final IApplicationThread mAppThread = ActivityThread.currentActivityThread() .getApplicationThread(); - /** Mapping from a client defined token to the {@link WindowTokenClient} it represents. */ + /** Attached {@link WindowTokenClient}. */ @GuardedBy("mLock") - private final ArrayMap mWindowTokenClientMap = new ArrayMap<>(); + private final ArraySet mWindowTokenClients = new ArraySet<>(); /** Gets the singleton controller. */ @NonNull @@ -85,11 +85,15 @@ public class WindowTokenClientController { /** Gets the {@link WindowContext} instance for the token. */ @Nullable public Context getWindowContext(@NonNull IBinder clientToken) { - final WindowTokenClient windowTokenClient; + if (!(clientToken instanceof WindowTokenClient windowTokenClient)) { + return null; + } synchronized (mLock) { - windowTokenClient = mWindowTokenClientMap.get(clientToken); + if (!mWindowTokenClients.contains(windowTokenClient)) { + return null; + } } - return windowTokenClient != null ? windowTokenClient.getContext() : null; + return windowTokenClient.getContext(); } /** @@ -126,8 +130,14 @@ public class WindowTokenClientController { */ public boolean attachToDisplayContent(@NonNull WindowTokenClient client, int displayId) { final IWindowManager wms = getWindowManagerService(); - // #createSystemUiContext may call this method before WindowManagerService is initialized. if (wms == null) { + // #createSystemUiContext may call this method before WindowManagerService is + // initialized. + // Regardless of whether or not it is ready, keep track of the token so that when WMS + // is initialized later, the SystemUiContext will start reporting from + // DisplayContent#registerSystemUiContext, and WindowTokenClientController can report + // the Configuration to the correct client. + recordWindowContextToken(client); return false; } final WindowContextInfo info; @@ -170,12 +180,18 @@ public class WindowTokenClientController { /** Detaches a {@link WindowTokenClient} from associated WindowContainer if there's one. */ public void detachIfNeeded(@NonNull WindowTokenClient client) { synchronized (mLock) { - if (mWindowTokenClientMap.remove(client) == null) { + if (!mWindowTokenClients.remove(client)) { return; } } + final IWindowManager wms = getWindowManagerService(); + if (wms == null) { + // #createSystemUiContext may call this method before WindowManagerService is + // initialized. If it is GC'ed before WMS is initialized, skip calling into WMS. + return; + } try { - getWindowManagerService().detachWindowContext(client); + wms.detachWindowContext(client); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } @@ -183,9 +199,7 @@ public class WindowTokenClientController { private void onWindowContextTokenAttached(@NonNull WindowTokenClient client, @NonNull WindowContextInfo info, boolean shouldReportConfigChange) { - synchronized (mLock) { - mWindowTokenClientMap.put(client, client); - } + recordWindowContextToken(client); if (shouldReportConfigChange) { // Should trigger an #onConfigurationChanged callback to the WindowContext. Post the // dispatch in the next loop to prevent the callback from being dispatched before @@ -199,10 +213,16 @@ public class WindowTokenClientController { } } + private void recordWindowContextToken(@NonNull WindowTokenClient client) { + synchronized (mLock) { + mWindowTokenClients.add(client); + } + } + /** Called when receives {@link WindowContextInfoChangeItem}. */ public void onWindowContextInfoChanged(@NonNull IBinder clientToken, @NonNull WindowContextInfo info) { - final WindowTokenClient windowTokenClient = getWindowTokenClient(clientToken); + final WindowTokenClient windowTokenClient = getWindowTokenClientIfAttached(clientToken); if (windowTokenClient != null) { windowTokenClient.onConfigurationChanged(info.getConfiguration(), info.getDisplayId()); } @@ -210,20 +230,23 @@ public class WindowTokenClientController { /** Called when receives {@link WindowContextWindowRemovalItem}. */ public void onWindowContextWindowRemoved(@NonNull IBinder clientToken) { - final WindowTokenClient windowTokenClient = getWindowTokenClient(clientToken); + final WindowTokenClient windowTokenClient = getWindowTokenClientIfAttached(clientToken); if (windowTokenClient != null) { windowTokenClient.onWindowTokenRemoved(); } } @Nullable - private WindowTokenClient getWindowTokenClient(@NonNull IBinder clientToken) { - final WindowTokenClient windowTokenClient; - synchronized (mLock) { - windowTokenClient = mWindowTokenClientMap.get(clientToken); + private WindowTokenClient getWindowTokenClientIfAttached(@NonNull IBinder clientToken) { + if (!(clientToken instanceof WindowTokenClient windowTokenClient)) { + Log.e(TAG, "getWindowTokenClient failed for non-window token " + clientToken); + return null; } - if (windowTokenClient == null) { - Log.w(TAG, "Can't find attached WindowTokenClient for " + clientToken); + synchronized (mLock) { + if (!mWindowTokenClients.contains(windowTokenClient)) { + Log.w(TAG, "Can't find attached WindowTokenClient for " + clientToken); + return null; + } } return windowTokenClient; } diff --git a/core/java/android/window/flags/lse_desktop_experience.aconfig b/core/java/android/window/flags/lse_desktop_experience.aconfig index eebdeadcdeb295d64ff962cbf7282b8df5a36c61..8019e6791cf1628c9097b07f6d8a71ec42bea9f0 100644 --- a/core/java/android/window/flags/lse_desktop_experience.aconfig +++ b/core/java/android/window/flags/lse_desktop_experience.aconfig @@ -241,6 +241,13 @@ flag { bug: "316006079" } +flag { + name: "enable_desktop_windowing_app_handle_education_integration" + namespace: "lse_desktop_experience" + description: "Enables desktop windowing app handle education and integrates new APIs" + bug: "380272815" +} + flag { name: "enable_desktop_windowing_transitions" namespace: "lse_desktop_experience" @@ -255,6 +262,16 @@ flag { bug: "369763947" } +flag { + name: "enable_desktop_windowing_enter_transition_bugfix" + namespace: "lse_desktop_experience" + description: "Enables enter desktop windowing transition & motion polish changes" + bug: "380224875" + metadata { + purpose: PURPOSE_BUGFIX + } +} + flag { name: "enable_desktop_windowing_exit_transitions" namespace: "lse_desktop_experience" @@ -262,6 +279,16 @@ flag { bug: "353650462" } +flag { + name: "enable_desktop_windowing_exit_transitions_bugfix" + namespace: "lse_desktop_experience" + description: "Enables exit desktop windowing transition & motion polish changes" + bug: "380224768" + metadata { + purpose: PURPOSE_BUGFIX + } +} + flag { name: "enable_compat_ui_visibility_status" namespace: "lse_desktop_experience" @@ -345,6 +372,16 @@ flag { bug: "370735595" } +flag { + name: "enable_desktop_app_launch_alttab_transitions_bugfix" + namespace: "lse_desktop_experience" + description: "Enables custom transitions for alt-tab app launches in Desktop Mode." + bug: "380225486" + metadata { + purpose: PURPOSE_BUGFIX + } +} + flag { name: "enable_desktop_app_launch_transitions" namespace: "lse_desktop_experience" @@ -352,6 +389,16 @@ flag { bug: "375992828" } +flag { + name: "enable_desktop_app_launch_transitions_bugfix" + namespace: "lse_desktop_experience" + description: "Enables custom transitions for app launches in Desktop Mode." + bug: "380224832" + metadata { + purpose: PURPOSE_BUGFIX + } +} + flag { name: "enable_desktop_system_dialogs_transitions" namespace: "lse_desktop_experience" diff --git a/core/java/android/window/flags/window_surfaces.aconfig b/core/java/android/window/flags/window_surfaces.aconfig index 96b9dc7cab0efec0a9ba215f1df53a7f3a804355..bb4770768cb1a3ef0e84047545e74c58ac303a2a 100644 --- a/core/java/android/window/flags/window_surfaces.aconfig +++ b/core/java/android/window/flags/window_surfaces.aconfig @@ -27,14 +27,6 @@ flag { bug: "262477923" } -flag { - namespace: "window_surfaces" - name: "secure_window_state" - description: "Move SC secure flag to WindowState level" - is_fixed_read_only: true - bug: "308662081" -} - flag { namespace: "window_surfaces" name: "trusted_presentation_listener_for_window" diff --git a/core/java/android/window/flags/windowing_frontend.aconfig b/core/java/android/window/flags/windowing_frontend.aconfig index ff69610dbf0e56c16a9029b7e82ec1d7b8bcc07d..ebbe4830009c49655dc5e69c7993cd1fb4767899 100644 --- a/core/java/android/window/flags/windowing_frontend.aconfig +++ b/core/java/android/window/flags/windowing_frontend.aconfig @@ -199,6 +199,13 @@ flag { bug: "357141415" } +flag { + name: "show_app_handle_large_screens" + namespace: "windowing_frontend" + description: "Show the app handle and the app menu also on large screens that don't enable desktop mode" + bug: "377689543" +} + flag { name: "filter_irrelevant_input_device_change" namespace: "windowing_frontend" @@ -434,3 +441,11 @@ flag { description: "Enable Predictive Back Animation for 3-button-nav" bug: "373544911" } + +flag { + name: "predictive_back_default_enable_sdk_36" + namespace: "systemui" + description: "Enable Predictive Back by default with targetSdk>=36" + is_fixed_read_only: true + bug: "376407910" +} diff --git a/core/java/com/android/internal/app/IAppOpsService.aidl b/core/java/com/android/internal/app/IAppOpsService.aidl index 3ec70649294b61d7d807fc29861a4431097d8cd8..2cfc680a3fe82359a23fc0c98f01013c53e53393 100644 --- a/core/java/com/android/internal/app/IAppOpsService.aidl +++ b/core/java/com/android/internal/app/IAppOpsService.aidl @@ -152,7 +152,7 @@ interface IAppOpsService { in AttributionSourceState attributionSourceStateState, boolean skipProxyOperation); int checkOperationRawForDevice(int code, int uid, String packageName, @nullable String attributionTag, int virtualDeviceId); - int checkOperationForDevice(int code, int uid, String packageName, int virtualDeviceId); + int checkOperationForDevice(int code, int uid, String packageName, @nullable String attributionTag, int virtualDeviceId); SyncNotedAppOp noteOperationForDevice(int code, int uid, String packageName, @nullable String attributionTag, int virtualDeviceId, boolean shouldCollectAsyncNotedOp, String message, boolean shouldCollectMessage); diff --git a/core/java/com/android/internal/content/NativeLibraryHelper.java b/core/java/com/android/internal/content/NativeLibraryHelper.java index 0c56c677e06f9b0738bf72b7543a1bbb5510d098..6ad7fef953571840a1a1faa3c8221ead6b55321f 100644 --- a/core/java/com/android/internal/content/NativeLibraryHelper.java +++ b/core/java/com/android/internal/content/NativeLibraryHelper.java @@ -26,6 +26,7 @@ import static android.system.OsConstants.S_IXGRP; import static android.system.OsConstants.S_IXOTH; import android.content.Context; +import android.content.pm.ApplicationInfo; import android.content.pm.PackageManager; import android.content.pm.parsing.ApkLiteParseUtils; import android.content.pm.parsing.PackageLite; @@ -177,6 +178,13 @@ public class NativeLibraryHelper { private native static int nativeCopyNativeBinaries(long handle, String sharedLibraryPath, String abiToCopy, boolean extractNativeLibs, boolean debuggable); + private static native int nativeCheckAlignment( + long handle, + String sharedLibraryPath, + String abi, + boolean extractNativeLibs, + boolean debuggable); + private static long sumNativeBinaries(Handle handle, String abi) { long sum = 0; for (long apkHandle : handle.apkHandles) { @@ -432,6 +440,51 @@ public class NativeLibraryHelper { } } + /** + * Checks alignment of APK and native libraries for 16KB device + * + * @param handle APK file to scan for native libraries + * @param libraryRoot directory for libraries + * @param abiOverride abiOverride for package + * @return {@link Modes from ApplicationInfo.PageSizeAppCompat} if successful or error code + * which suggests undefined mode + */ + @ApplicationInfo.PageSizeAppCompatFlags + public static int checkAlignmentForCompatMode( + Handle handle, + String libraryRoot, + boolean nativeLibraryRootRequiresIsa, + String abiOverride) { + // Keep the code below in sync with copyNativeBinariesForSupportedAbi + int abi = findSupportedAbi(handle, Build.SUPPORTED_64_BIT_ABIS); + if (abi < 0) { + return ApplicationInfo.PAGE_SIZE_APP_COMPAT_FLAG_ERROR; + } + + final String supportedAbi = Build.SUPPORTED_64_BIT_ABIS[abi]; + final String instructionSet = VMRuntime.getInstructionSet(supportedAbi); + String subDir = libraryRoot; + if (nativeLibraryRootRequiresIsa) { + subDir += "/" + instructionSet; + } + + int mode = ApplicationInfo.PAGE_SIZE_APP_COMPAT_FLAG_UNDEFINED; + for (long apkHandle : handle.apkHandles) { + int res = + nativeCheckAlignment( + apkHandle, + subDir, + Build.SUPPORTED_64_BIT_ABIS[abi], + handle.extractNativeLibs, + handle.debuggable); + if (res == ApplicationInfo.PAGE_SIZE_APP_COMPAT_FLAG_ERROR) { + return res; + } + mode |= res; + } + return mode; + } + public static long sumNativeBinariesWithOverride(Handle handle, String abiOverride) throws IOException { long sum = 0; diff --git a/core/java/com/android/internal/content/om/OverlayConfig.java b/core/java/com/android/internal/content/om/OverlayConfig.java index 07e178c0ba270a1fe4be2e7f050bb8d0b39aae56..38593b4a2a9900db4fde2899391f9bab62412f44 100644 --- a/core/java/com/android/internal/content/om/OverlayConfig.java +++ b/core/java/com/android/internal/content/om/OverlayConfig.java @@ -19,6 +19,7 @@ package com.android.internal.content.om; import android.annotation.NonNull; import android.annotation.Nullable; import android.content.pm.PackagePartitions; +import android.content.res.AssetManager; import android.os.Build; import android.os.Trace; import android.util.ArrayMap; @@ -533,7 +534,7 @@ public class OverlayConfig { */ @NonNull public String[] createImmutableFrameworkIdmapsInZygote() { - final String targetPath = "/system/framework/framework-res.apk"; + final String targetPath = AssetManager.FRAMEWORK_APK_PATH; final ArrayList idmapPaths = new ArrayList<>(); final ArrayList idmapInvocations = getImmutableFrameworkOverlayIdmapInvocations(); diff --git a/core/java/com/android/internal/content/om/OverlayManagerImpl.java b/core/java/com/android/internal/content/om/OverlayManagerImpl.java index c4624498138d62cccdafb1a5bcf6a099b746ea25..fa5cf2a396b98de34efe2a0918494d18cdd99f8c 100644 --- a/core/java/com/android/internal/content/om/OverlayManagerImpl.java +++ b/core/java/com/android/internal/content/om/OverlayManagerImpl.java @@ -35,6 +35,7 @@ import android.content.om.OverlayManagerTransaction.Request; import android.content.pm.ApplicationInfo; import android.content.pm.PackageManager; import android.content.pm.parsing.FrameworkParsingPackageUtils; +import android.content.res.AssetManager; import android.os.FabricatedOverlayInfo; import android.os.FabricatedOverlayInternal; import android.os.FabricatedOverlayInternalEntry; @@ -60,8 +61,8 @@ import java.util.List; import java.util.Objects; /** - * This class provides the functionalities of registering an overlay, unregistering an overlay, and - * getting the list of overlays information. + * This class provides the functionalities for managing self-targeting overlays, including + * registering an overlay, unregistering an overlay, and getting the list of overlays information. */ public class OverlayManagerImpl { private static final String TAG = "OverlayManagerImpl"; @@ -234,14 +235,17 @@ public class OverlayManagerImpl { Preconditions.checkArgument(!entryList.isEmpty(), "overlay entries shouldn't be empty"); final String overlayName = checkOverlayNameValid(overlayInternal.overlayName); checkPackageName(overlayInternal.packageName); - checkPackageName(overlayInternal.targetPackageName); - Preconditions.checkStringNotEmpty( - overlayInternal.targetOverlayable, - "Target overlayable should be neither null nor empty string."); + Preconditions.checkStringNotEmpty(overlayInternal.targetPackageName); final ApplicationInfo applicationInfo = mContext.getApplicationInfo(); - final String targetPackage = Preconditions.checkStringNotEmpty( - applicationInfo.getBaseCodePath()); + String targetPackage = null; + if (TextUtils.equals(overlayInternal.targetPackageName, "android")) { + targetPackage = AssetManager.FRAMEWORK_APK_PATH; + } else { + targetPackage = Preconditions.checkStringNotEmpty( + applicationInfo.getBaseCodePath()); + } + final Path frroPath = mBasePath.resolve(overlayName + FRRO_EXTENSION); final Path idmapPath = mBasePath.resolve(overlayName + IDMAP_EXTENSION); diff --git a/core/java/com/android/internal/inputmethod/IInputMethodPrivilegedOperations.aidl b/core/java/com/android/internal/inputmethod/IInputMethodPrivilegedOperations.aidl index ac4c066a992fd1d9b58db5b18514c7a612c32ff9..5fbb92de46a02111d3f9c2f0449eeb49b8b3d2ad 100644 --- a/core/java/com/android/internal/inputmethod/IInputMethodPrivilegedOperations.aidl +++ b/core/java/com/android/internal/inputmethod/IInputMethodPrivilegedOperations.aidl @@ -16,6 +16,7 @@ package com.android.internal.inputmethod; +import android.graphics.Region; import android.net.Uri; import android.view.inputmethod.ImeTracker; import android.view.inputmethod.InputMethodSubtype; @@ -51,4 +52,5 @@ oneway interface IInputMethodPrivilegedOperations { void resetStylusHandwriting(int requestId); void switchKeyboardLayoutAsync(int direction); void setHandwritingSurfaceNotTouchable(boolean notTouchable); + void setHandwritingTouchableRegion(in Region region); } diff --git a/core/java/com/android/internal/inputmethod/InputMethodPrivilegedOperations.java b/core/java/com/android/internal/inputmethod/InputMethodPrivilegedOperations.java index b009c99dc9e3c49bacf1c77bb09576d778bf9fc5..36333a993c443c6009dea76eec2eca6906d8b246 100644 --- a/core/java/com/android/internal/inputmethod/InputMethodPrivilegedOperations.java +++ b/core/java/com/android/internal/inputmethod/InputMethodPrivilegedOperations.java @@ -20,6 +20,7 @@ import android.annotation.AnyThread; import android.annotation.DrawableRes; import android.annotation.NonNull; import android.annotation.Nullable; +import android.graphics.Region; import android.inputmethodservice.InputMethodService.BackDispositionMode; import android.inputmethodservice.InputMethodService.ImeWindowVisibility; import android.net.Uri; @@ -159,6 +160,25 @@ public final class InputMethodPrivilegedOperations { } } + + /** + * Calls {@link IInputMethodPrivilegedOperations#setHandwritingTouchableRegion(Region)}. + * + * @param region {@link Region} to set handwritable. + */ + @AnyThread + public void setHandwritingTouchableRegion(Region region) { + final IInputMethodPrivilegedOperations ops = mOps.getAndWarnIfNull(); + if (ops == null) { + return; + } + try { + ops.setHandwritingTouchableRegion(region); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + } + /** * Calls {@link IInputMethodPrivilegedOperations#createInputContentUriToken(Uri, String, * AndroidFuture)}. diff --git a/core/java/com/android/internal/jank/Cuj.java b/core/java/com/android/internal/jank/Cuj.java index 1204ef3f48fcc1a1df04ef1571abd536ff857e02..fc415377f1ee9198c2b12e2892ba9c816b9044ab 100644 --- a/core/java/com/android/internal/jank/Cuj.java +++ b/core/java/com/android/internal/jank/Cuj.java @@ -235,8 +235,19 @@ public class Cuj { */ public static final int CUJ_DESKTOP_MODE_SNAP_RESIZE = 118; + /** + * Track unmaximize window interaction in desktop mode. + * + *

Tracking starts when the maximize button or option is clicked {@link + * com.android.wm.shell.windowdecor.DesktopModeWindowDecorViewModel#onClick} + * and finishes when the animation finishes {@link + * com.android.wm.shell.windowdecor.ToggleResizeDesktopTaskTransitionHandler#startAnimation} + *

+ */ + public static final int CUJ_DESKTOP_MODE_UNMAXIMIZE_WINDOW = 119; + // When adding a CUJ, update this and make sure to also update CUJ_TO_STATSD_INTERACTION_TYPE. - @VisibleForTesting static final int LAST_CUJ = CUJ_DESKTOP_MODE_SNAP_RESIZE; + @VisibleForTesting static final int LAST_CUJ = CUJ_DESKTOP_MODE_UNMAXIMIZE_WINDOW; /** @hide */ @IntDef({ @@ -346,7 +357,8 @@ public class Cuj { CUJ_LAUNCHER_KEYBOARD_QUICK_SWITCH_APP_LAUNCH, CUJ_DESKTOP_MODE_ENTER_APP_HANDLE_DRAG_RELEASE, CUJ_DESKTOP_MODE_EXIT_MODE_ON_LAST_WINDOW_CLOSE, - CUJ_DESKTOP_MODE_SNAP_RESIZE + CUJ_DESKTOP_MODE_SNAP_RESIZE, + CUJ_DESKTOP_MODE_UNMAXIMIZE_WINDOW }) @Retention(RetentionPolicy.SOURCE) public @interface CujType {} @@ -467,6 +479,7 @@ public class Cuj { CUJ_TO_STATSD_INTERACTION_TYPE[CUJ_DESKTOP_MODE_ENTER_APP_HANDLE_DRAG_RELEASE] = FrameworkStatsLog.UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__DESKTOP_MODE_ENTER_APP_HANDLE_DRAG_RELEASE; CUJ_TO_STATSD_INTERACTION_TYPE[CUJ_DESKTOP_MODE_EXIT_MODE_ON_LAST_WINDOW_CLOSE] = FrameworkStatsLog.UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__DESKTOP_MODE_EXIT_MODE_ON_LAST_WINDOW_CLOSE; CUJ_TO_STATSD_INTERACTION_TYPE[CUJ_DESKTOP_MODE_SNAP_RESIZE] = FrameworkStatsLog.UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__DESKTOP_MODE_SNAP_RESIZE; + CUJ_TO_STATSD_INTERACTION_TYPE[CUJ_DESKTOP_MODE_UNMAXIMIZE_WINDOW] = FrameworkStatsLog.UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__DESKTOP_MODE_UNMAXIMIZE_WINDOW; } private Cuj() { @@ -699,6 +712,8 @@ public class Cuj { return "DESKTOP_MODE_EXIT_MODE_ON_LAST_WINDOW_CLOSE"; case CUJ_DESKTOP_MODE_SNAP_RESIZE: return "DESKTOP_MODE_SNAP_RESIZE"; + case CUJ_DESKTOP_MODE_UNMAXIMIZE_WINDOW: + return "DESKTOP_MODE_UNMAXIMIZE_WINDOW"; } return "UNKNOWN"; } diff --git a/core/java/com/android/internal/pm/parsing/pkg/PackageImpl.java b/core/java/com/android/internal/pm/parsing/pkg/PackageImpl.java index 48d0d6c777debcf4c906ca3851af91f01af7deff..5ec5762c05332f8e53184c52040de44fe9773f7b 100644 --- a/core/java/com/android/internal/pm/parsing/pkg/PackageImpl.java +++ b/core/java/com/android/internal/pm/parsing/pkg/PackageImpl.java @@ -392,6 +392,10 @@ public class PackageImpl implements ParsedPackage, AndroidPackageInternal, private int memtagMode; @ApplicationInfo.NativeHeapZeroInitialized private int nativeHeapZeroInitialized; + + @ApplicationInfo.PageSizeAppCompatFlags private int mPageSizeAppCompatFlags = + ApplicationInfo.PAGE_SIZE_APP_COMPAT_FLAG_UNDEFINED; + @Nullable @DataClass.ParcelWith(Parcelling.BuiltIn.ForBoolean.class) private Boolean requestRawExternalStorageAccess; @@ -1118,6 +1122,12 @@ public class PackageImpl implements ParsedPackage, AndroidPackageInternal, return nativeHeapZeroInitialized; } + @ApplicationInfo.PageSizeAppCompatFlags + @Override + public int getPageSizeAppCompatFlags() { + return mPageSizeAppCompatFlags; + } + @Override public int getNetworkSecurityConfigResourceId() { return networkSecurityConfigRes; @@ -2220,6 +2230,12 @@ public class PackageImpl implements ParsedPackage, AndroidPackageInternal, return this; } + @Override + public PackageImpl setPageSizeAppCompatFlags(@ApplicationInfo.PageSizeAppCompatFlags int flag) { + mPageSizeAppCompatFlags = flag; + return this; + } + @Override public PackageImpl setNetworkSecurityConfigResourceId(int value) { networkSecurityConfigRes = value; @@ -2703,6 +2719,7 @@ public class PackageImpl implements ParsedPackage, AndroidPackageInternal, appInfo.setKnownActivityEmbeddingCerts(mKnownActivityEmbeddingCerts); } appInfo.allowCrossUidActivitySwitchFromBelow = mAllowCrossUidActivitySwitchFromBelow; + appInfo.setPageSizeAppCompatFlags(mPageSizeAppCompatFlags); return appInfo; } @@ -3305,6 +3322,7 @@ public class PackageImpl implements ParsedPackage, AndroidPackageInternal, dest.writeInt(this.mIntentMatchingFlags); dest.writeIntArray(this.mAlternateLauncherIconResIds); dest.writeIntArray(this.mAlternateLauncherLabelResIds); + dest.writeInt(this.mPageSizeAppCompatFlags); } private void writeFeatureFlagState(@NonNull Parcel dest) { @@ -3499,6 +3517,7 @@ public class PackageImpl implements ParsedPackage, AndroidPackageInternal, this.mIntentMatchingFlags = in.readInt(); this.mAlternateLauncherIconResIds = in.createIntArray(); this.mAlternateLauncherLabelResIds = in.createIntArray(); + this.mPageSizeAppCompatFlags = in.readInt(); assignDerivedFields(); assignDerivedFields2(); diff --git a/core/java/com/android/internal/pm/pkg/parsing/ParsingPackage.java b/core/java/com/android/internal/pm/pkg/parsing/ParsingPackage.java index 67b985a614553f95f16741484dc141cbff618a7a..5062d58d4dca6d1b445b2bbb955d7cd7e68cb87c 100644 --- a/core/java/com/android/internal/pm/pkg/parsing/ParsingPackage.java +++ b/core/java/com/android/internal/pm/pkg/parsing/ParsingPackage.java @@ -31,7 +31,6 @@ import android.util.ArraySet; import android.util.SparseArray; import android.util.SparseIntArray; -import com.android.internal.R; import com.android.internal.pm.parsing.pkg.ParsedPackage; import com.android.internal.pm.pkg.component.ParsedActivity; import com.android.internal.pm.pkg.component.ParsedApexSystemService; @@ -280,6 +279,9 @@ public interface ParsingPackage { ParsingPackage setNativeHeapZeroInitialized( @ApplicationInfo.NativeHeapZeroInitialized int nativeHeapZeroInitialized); + /** Manifest option pageSizeCompat will populate this field */ + ParsingPackage setPageSizeAppCompatFlags(@ApplicationInfo.PageSizeAppCompatFlags int value); + ParsingPackage setRequestRawExternalStorageAccess( @Nullable Boolean requestRawExternalStorageAccess); diff --git a/core/java/com/android/internal/pm/pkg/parsing/ParsingPackageUtils.java b/core/java/com/android/internal/pm/pkg/parsing/ParsingPackageUtils.java index 8a6e6be1abbf45ce5488dc546e876a1f751411cf..0f93e6e8109bf0e4dfcc7810e57798af4cb7e7fe 100644 --- a/core/java/com/android/internal/pm/pkg/parsing/ParsingPackageUtils.java +++ b/core/java/com/android/internal/pm/pkg/parsing/ParsingPackageUtils.java @@ -541,6 +541,7 @@ public class ParsingPackageUtils { pkg.setGwpAsanMode(-1); pkg.setMemtagMode(-1); + pkg.setPageSizeAppCompatFlags(ApplicationInfo.PAGE_SIZE_APP_COMPAT_FLAG_UNDEFINED); afterParseBaseApplication(pkg); @@ -2182,6 +2183,13 @@ public class ParsingPackageUtils { pkg.setGwpAsanMode(sa.getInt(R.styleable.AndroidManifestApplication_gwpAsanMode, -1)); pkg.setMemtagMode(sa.getInt(R.styleable.AndroidManifestApplication_memtagMode, -1)); + + if (Flags.appCompatOption16kb()) { + pkg.setPageSizeAppCompatFlags( + sa.getInt(R.styleable.AndroidManifestApplication_pageSizeCompat, + ApplicationInfo.PAGE_SIZE_APP_COMPAT_FLAG_UNDEFINED)); + } + if (sa.hasValue(R.styleable.AndroidManifestApplication_nativeHeapZeroInitialized)) { final boolean v = sa.getBoolean( R.styleable.AndroidManifestApplication_nativeHeapZeroInitialized, false); @@ -2377,6 +2385,7 @@ public class ParsingPackageUtils { * Flags are separated by type and by default value. They are sorted alphabetically within each * section. */ + @SuppressWarnings("AndroidFrameworkCompatChange") private void parseBaseAppBasicFlags(ParsingPackage pkg, TypedArray sa) { int targetSdk = pkg.getTargetSdkVersion(); //@formatter:off @@ -2414,12 +2423,20 @@ public class ParsingPackageUtils { .setResetEnabledSettingsOnAppDataCleared(bool(false, R.styleable.AndroidManifestApplication_resetEnabledSettingsOnAppDataCleared, sa)) - .setOnBackInvokedCallbackEnabled(bool(false, R.styleable.AndroidManifestApplication_enableOnBackInvokedCallback, sa)) // targetSdkVersion gated .setAllowAudioPlaybackCapture(bool(targetSdk >= Build.VERSION_CODES.Q, R.styleable.AndroidManifestApplication_allowAudioPlaybackCapture, sa)) .setHardwareAccelerated(bool(targetSdk >= Build.VERSION_CODES.ICE_CREAM_SANDWICH, R.styleable.AndroidManifestApplication_hardwareAccelerated, sa)) .setRequestLegacyExternalStorage(bool(targetSdk < Build.VERSION_CODES.Q, R.styleable.AndroidManifestApplication_requestLegacyExternalStorage, sa)) .setCleartextTrafficAllowed(bool(targetSdk < Build.VERSION_CODES.P, R.styleable.AndroidManifestApplication_usesCleartextTraffic, sa)) + // CompatChange.isChangeEnabled() can't be used here because this is called during + // PackageManagerService initialization. PlatformCompat can't be used because this + // code is not guaranteed to be called from the system_server process. Therefore + // accessing Build.VERSION_CODES directly and suppressing + // AndroidFrameworkCompatChange warning + .setOnBackInvokedCallbackEnabled(bool( + com.android.window.flags.Flags.predictiveBackDefaultEnableSdk36() + && targetSdk > Build.VERSION_CODES.VANILLA_ICE_CREAM, + R.styleable.AndroidManifestApplication_enableOnBackInvokedCallback, sa)) // Ints Default 0 .setUiOptions(anInt(R.styleable.AndroidManifestApplication_uiOptions, sa)) // Ints diff --git a/core/java/com/android/internal/protolog/LegacyProtoLogImpl.java b/core/java/com/android/internal/protolog/LegacyProtoLogImpl.java index 8771cde1de46ab355b5eb2a05323fa2e80d2d598..be3bbb2d1d946940938b57de62d29521fd935c08 100644 --- a/core/java/com/android/internal/protolog/LegacyProtoLogImpl.java +++ b/core/java/com/android/internal/protolog/LegacyProtoLogImpl.java @@ -70,7 +70,7 @@ public class LegacyProtoLogImpl implements IProtoLog { private final TraceBuffer mBuffer; private final LegacyProtoLogViewerConfigReader mViewerConfig; private final Map mLogGroups = new TreeMap<>(); - private final Runnable mCacheUpdater; + private final ProtoLogCacheUpdater mCacheUpdater; private final int mPerChunkSize; private boolean mProtoLogEnabled; @@ -78,14 +78,14 @@ public class LegacyProtoLogImpl implements IProtoLog { private final Object mProtoLogEnabledLock = new Object(); public LegacyProtoLogImpl(String outputFile, String viewerConfigFilename, - Runnable cacheUpdater) { + ProtoLogCacheUpdater cacheUpdater) { this(new File(outputFile), viewerConfigFilename, BUFFER_CAPACITY, new LegacyProtoLogViewerConfigReader(), PER_CHUNK_SIZE, cacheUpdater); } public LegacyProtoLogImpl(File file, String viewerConfigFilename, int bufferCapacity, LegacyProtoLogViewerConfigReader viewerConfig, int perChunkSize, - Runnable cacheUpdater) { + ProtoLogCacheUpdater cacheUpdater) { mLogFile = file; mBuffer = new TraceBuffer(bufferCapacity); mLegacyViewerConfigFilename = viewerConfigFilename; @@ -298,7 +298,7 @@ public class LegacyProtoLogImpl implements IProtoLog { } } - mCacheUpdater.run(); + mCacheUpdater.update(this); return 0; } diff --git a/core/java/com/android/internal/protolog/PerfettoProtoLogImpl.java b/core/java/com/android/internal/protolog/PerfettoProtoLogImpl.java index eb682dff14de7ddfe4d5566086efe43c806530ac..05a33fe830e8943ac15bede6aa05205c8006a61d 100644 --- a/core/java/com/android/internal/protolog/PerfettoProtoLogImpl.java +++ b/core/java/com/android/internal/protolog/PerfettoProtoLogImpl.java @@ -51,7 +51,6 @@ import android.os.ServiceManager; import android.os.ShellCommand; import android.os.SystemClock; import android.text.TextUtils; -import android.tracing.perfetto.DataSourceParams; import android.tracing.perfetto.InitArguments; import android.tracing.perfetto.Producer; import android.tracing.perfetto.TracingContext; @@ -86,7 +85,6 @@ import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicInteger; import java.util.concurrent.locks.Lock; import java.util.concurrent.locks.ReentrantLock; -import java.util.stream.Stream; /** * A service for the ProtoLog logging system. @@ -98,10 +96,12 @@ public abstract class PerfettoProtoLogImpl extends IProtoLogClient.Stub implemen @NonNull protected final ProtoLogDataSource mDataSource; + @Nullable + protected final IProtoLogConfigurationService mConfigurationService; @NonNull protected final TreeMap mLogGroups = new TreeMap<>(); @NonNull - private final Runnable mCacheUpdater; + private final ProtoLogCacheUpdater mCacheUpdater; @NonNull private final int[] mDefaultLogLevelCounts = new int[LogLevel.values().length]; @@ -117,10 +117,10 @@ public abstract class PerfettoProtoLogImpl extends IProtoLogClient.Stub implemen private boolean mLogcatReady = false; protected PerfettoProtoLogImpl( - @NonNull Runnable cacheUpdater, + @NonNull ProtoLogDataSource dataSource, + @NonNull ProtoLogCacheUpdater cacheUpdater, @NonNull IProtoLogGroup[] groups) throws ServiceManager.ServiceNotFoundException { - this(cacheUpdater, groups, - ProtoLogDataSource::new, + this(dataSource, cacheUpdater, groups, android.tracing.Flags.clientSideProtoLogging() ? IProtoLogConfigurationService.Stub.asInterface( ServiceManager.getServiceOrThrow(PROTOLOG_CONFIGURATION_SERVICE) @@ -129,49 +129,62 @@ public abstract class PerfettoProtoLogImpl extends IProtoLogClient.Stub implemen } protected PerfettoProtoLogImpl( - @NonNull Runnable cacheUpdater, + @NonNull ProtoLogDataSource dataSource, + @NonNull ProtoLogCacheUpdater cacheUpdater, @NonNull IProtoLogGroup[] groups, - @NonNull ProtoLogDataSourceBuilder dataSourceBuilder, @Nullable IProtoLogConfigurationService configurationService) { - mDataSource = dataSourceBuilder.build( - this::onTracingInstanceStart, - this::onTracingFlush, - this::onTracingInstanceStop); - Producer.init(InitArguments.DEFAULTS); - DataSourceParams params = - new DataSourceParams.Builder() - .setBufferExhaustedPolicy( - DataSourceParams - .PERFETTO_DS_BUFFER_EXHAUSTED_POLICY_DROP) - .build(); - // NOTE: Registering that datasource is an async operation, so there may be no data traced - // for some messages logged right after the construction of this class. - mDataSource.register(params); - - this.mCacheUpdater = cacheUpdater; + mDataSource = dataSource; + mCacheUpdater = cacheUpdater; + mConfigurationService = configurationService; registerGroupsLocally(groups); + } + + /** + * To be called to enable the ProtoLogImpl to start tracing to ProtoLog and register with all + * the expected ProtoLog components. + */ + public void enable() { + Producer.init(InitArguments.DEFAULTS); if (android.tracing.Flags.clientSideProtoLogging()) { - Objects.requireNonNull(configurationService, - "A null ProtoLog Configuration Service was provided!"); + connectToConfigurationService(); + } - try { - var args = createConfigurationServiceRegisterClientArgs(); + mDataSource.registerOnStartCallback(this::onTracingInstanceStart); + mDataSource.registerOnFlushCallback(this::onTracingFlush); + mDataSource.registerOnStopCallback(this::onTracingInstanceStop); + } - final var groupArgs = Stream.of(groups) - .map(group -> new RegisterClientArgs - .GroupConfig(group.name(), group.isLogToLogcat())) - .toArray(RegisterClientArgs.GroupConfig[]::new); - args.setGroups(groupArgs); + private void connectToConfigurationService() { + Objects.requireNonNull(mConfigurationService, + "A null ProtoLog Configuration Service was provided!"); - configurationService.registerClient(this, args); - } catch (RemoteException e) { - throw new RuntimeException("Failed to register ProtoLog client"); - } + try { + var args = createConfigurationServiceRegisterClientArgs(); + + final var groupArgs = mLogGroups.values().stream() + .map(group -> new RegisterClientArgs + .GroupConfig(group.name(), group.isLogToLogcat())) + .toArray(RegisterClientArgs.GroupConfig[]::new); + args.setGroups(groupArgs); + + mConfigurationService.registerClient(this, args); + } catch (RemoteException e) { + throw new RuntimeException("Failed to register ProtoLog client"); } } + /** + * Should be called when we no longer want to use the ProtoLog logger to unlink ourselves from + * the datasource and the configuration service to ensure we no longer receive the callback. + */ + public void disable() { + mDataSource.unregisterOnStartCallback(this::onTracingInstanceStart); + mDataSource.unregisterOnFlushCallback(this::onTracingFlush); + mDataSource.unregisterOnStopCallback(this::onTracingInstanceStop); + } + @NonNull protected abstract RegisterClientArgs createConfigurationServiceRegisterClientArgs(); @@ -703,7 +716,7 @@ public abstract class PerfettoProtoLogImpl extends IProtoLogClient.Stub implemen } } - mCacheUpdater.run(); + mCacheUpdater.update(this); return 0; } @@ -746,7 +759,7 @@ public abstract class PerfettoProtoLogImpl extends IProtoLogClient.Stub implemen } } - mCacheUpdater.run(); + mCacheUpdater.update(this); this.mTracingInstances.incrementAndGet(); @@ -786,7 +799,7 @@ public abstract class PerfettoProtoLogImpl extends IProtoLogClient.Stub implemen } } - mCacheUpdater.run(); + mCacheUpdater.update(this); Log.d(LOG_TAG, "Finished onTracingInstanceStop"); } diff --git a/core/java/com/android/internal/protolog/ProcessedPerfettoProtoLogImpl.java b/core/java/com/android/internal/protolog/ProcessedPerfettoProtoLogImpl.java index 967a5ed1744de1b2203118b76057fd5c25b742b0..e0a77d2be724736357ee012d4aa405af83c5e731 100644 --- a/core/java/com/android/internal/protolog/ProcessedPerfettoProtoLogImpl.java +++ b/core/java/com/android/internal/protolog/ProcessedPerfettoProtoLogImpl.java @@ -42,10 +42,11 @@ public class ProcessedPerfettoProtoLogImpl extends PerfettoProtoLogImpl { private final String mViewerConfigFilePath; public ProcessedPerfettoProtoLogImpl( + @NonNull ProtoLogDataSource datasource, @NonNull String viewerConfigFilePath, - @NonNull Runnable cacheUpdater, + @NonNull ProtoLogCacheUpdater cacheUpdater, @NonNull IProtoLogGroup[] groups) throws ServiceManager.ServiceNotFoundException { - this(viewerConfigFilePath, new ViewerConfigInputStreamProvider() { + this(datasource, viewerConfigFilePath, new ViewerConfigInputStreamProvider() { @NonNull @Override public AutoClosableProtoInputStream getInputStream() { @@ -64,11 +65,12 @@ public class ProcessedPerfettoProtoLogImpl extends PerfettoProtoLogImpl { @VisibleForTesting public ProcessedPerfettoProtoLogImpl( + @NonNull ProtoLogDataSource datasource, @NonNull String viewerConfigFilePath, @NonNull ViewerConfigInputStreamProvider viewerConfigInputStreamProvider, - @NonNull Runnable cacheUpdater, + @NonNull ProtoLogCacheUpdater cacheUpdater, @NonNull IProtoLogGroup[] groups) throws ServiceManager.ServiceNotFoundException { - super(cacheUpdater, groups); + super(datasource, cacheUpdater, groups); this.mViewerConfigFilePath = viewerConfigFilePath; @@ -80,15 +82,15 @@ public class ProcessedPerfettoProtoLogImpl extends PerfettoProtoLogImpl { @VisibleForTesting public ProcessedPerfettoProtoLogImpl( + @NonNull ProtoLogDataSource datasource, @NonNull String viewerConfigFilePath, @NonNull ViewerConfigInputStreamProvider viewerConfigInputStreamProvider, @NonNull ProtoLogViewerConfigReader viewerConfigReader, - @NonNull Runnable cacheUpdater, + @NonNull ProtoLogCacheUpdater cacheUpdater, @NonNull IProtoLogGroup[] groups, - @NonNull ProtoLogDataSourceBuilder dataSourceBuilder, @Nullable IProtoLogConfigurationService configurationService) throws ServiceManager.ServiceNotFoundException { - super(cacheUpdater, groups, dataSourceBuilder, configurationService); + super(datasource, cacheUpdater, groups, configurationService); this.mViewerConfigFilePath = viewerConfigFilePath; diff --git a/core/java/com/android/internal/protolog/ProtoLog.java b/core/java/com/android/internal/protolog/ProtoLog.java index d117e93d7de7d1521246786c7525c6c1bbb0bebf..c81af959f36ccc9e39ca307fd0eab709b5b8ad79 100644 --- a/core/java/com/android/internal/protolog/ProtoLog.java +++ b/core/java/com/android/internal/protolog/ProtoLog.java @@ -17,6 +17,9 @@ package com.android.internal.protolog; import android.os.ServiceManager; +import android.tracing.perfetto.DataSourceParams; +import android.tracing.perfetto.InitArguments; +import android.tracing.perfetto.Producer; import com.android.internal.protolog.common.IProtoLog; import com.android.internal.protolog.common.IProtoLogGroup; @@ -54,6 +57,8 @@ public class ProtoLog { private static IProtoLog sProtoLogInstance; + private static ProtoLogDataSource sDataSource; + private static final Object sInitLock = new Object(); /** @@ -69,26 +74,45 @@ public class ProtoLog { // files to extract out the log strings. Otherwise, the trace calls are replaced with calls // directly to the generated tracing implementations. if (android.tracing.Flags.perfettoProtologTracing()) { - synchronized (sInitLock) { - final var allGroups = new HashSet<>(Arrays.stream(groups).toList()); - if (sProtoLogInstance != null) { - // The ProtoLog instance has already been initialized in this process - final var alreadyRegisteredGroups = sProtoLogInstance.getRegisteredGroups(); - allGroups.addAll(alreadyRegisteredGroups); - } - - try { - sProtoLogInstance = new UnprocessedPerfettoProtoLogImpl( - allGroups.toArray(new IProtoLogGroup[0])); - } catch (ServiceManager.ServiceNotFoundException e) { - throw new RuntimeException(e); - } - } + initializePerfettoProtoLog(groups); } else { sProtoLogInstance = new LogcatOnlyProtoLogImpl(); } } + private static void initializePerfettoProtoLog(IProtoLogGroup... groups) { + var datasource = getSharedSingleInstanceDataSource(); + + synchronized (sInitLock) { + final var allGroups = new HashSet<>(Arrays.stream(groups).toList()); + final var previousProtoLogImpl = sProtoLogInstance; + if (previousProtoLogImpl != null) { + // The ProtoLog instance has already been initialized in this process + final var alreadyRegisteredGroups = previousProtoLogImpl.getRegisteredGroups(); + allGroups.addAll(alreadyRegisteredGroups); + } + + sProtoLogInstance = createAndEnableNewPerfettoProtoLogImpl( + datasource, allGroups.toArray(new IProtoLogGroup[0])); + if (previousProtoLogImpl instanceof PerfettoProtoLogImpl) { + ((PerfettoProtoLogImpl) previousProtoLogImpl).disable(); + } + } + } + + private static PerfettoProtoLogImpl createAndEnableNewPerfettoProtoLogImpl( + ProtoLogDataSource datasource, IProtoLogGroup[] groups) { + try { + var unprocessedPerfettoProtoLogImpl = + new UnprocessedPerfettoProtoLogImpl(datasource, groups); + unprocessedPerfettoProtoLogImpl.enable(); + + return unprocessedPerfettoProtoLogImpl; + } catch (ServiceManager.ServiceNotFoundException e) { + throw new RuntimeException(e); + } + } + /** * DEBUG level log. * @@ -190,6 +214,32 @@ public class ProtoLog { return sProtoLogInstance; } + /** + * Gets or creates if it doesn't exist yet the protolog datasource to use in this process. + * We should re-use the same datasource to avoid registering the datasource multiple times in + * the same process, since there is no way to unregister the datasource after registration. + * + * @return The single ProtoLog datasource instance to be shared across all ProtoLog tracing + * objects. + */ + public static synchronized ProtoLogDataSource getSharedSingleInstanceDataSource() { + if (sDataSource == null) { + Producer.init(InitArguments.DEFAULTS); + sDataSource = new ProtoLogDataSource(); + DataSourceParams params = + new DataSourceParams.Builder() + .setBufferExhaustedPolicy( + DataSourceParams + .PERFETTO_DS_BUFFER_EXHAUSTED_POLICY_DROP) + .build(); + // NOTE: Registering that datasource is an async operation, so there may be no data + // traced for some messages logged right after the construction of this class. + sDataSource.register(params); + } + + return sDataSource; + } + private static void logStringMessage(LogLevel logLevel, IProtoLogGroup group, String stringMessage, Object... args) { if (sProtoLogInstance == null) { diff --git a/core/java/com/android/internal/protolog/ProtoLogCacheUpdater.java b/core/java/com/android/internal/protolog/ProtoLogCacheUpdater.java new file mode 100644 index 0000000000000000000000000000000000000000..4f8655c6377b3bbbfb52424d824ecbb25502b91b --- /dev/null +++ b/core/java/com/android/internal/protolog/ProtoLogCacheUpdater.java @@ -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 com.android.internal.protolog; + +import com.android.internal.protolog.common.IProtoLog; + +public interface ProtoLogCacheUpdater { + /** + * Update the cache based on the latest state of the active tracing configurations. + * + * @param protoLogInstance the instance to use to query the latest state of tracing. + */ + void update(IProtoLog protoLogInstance); +} diff --git a/core/java/com/android/internal/protolog/ProtoLogConfigurationServiceImpl.java b/core/java/com/android/internal/protolog/ProtoLogConfigurationServiceImpl.java index e9a8770deb73abdae9be4df411d95f340af771e7..23f7c2a3d98714e17788b0d39fa7efd80b5807d5 100644 --- a/core/java/com/android/internal/protolog/ProtoLogConfigurationServiceImpl.java +++ b/core/java/com/android/internal/protolog/ProtoLogConfigurationServiceImpl.java @@ -34,9 +34,6 @@ import android.content.Context; import android.os.RemoteException; import android.os.ResultReceiver; import android.os.ShellCallback; -import android.tracing.perfetto.DataSourceParams; -import android.tracing.perfetto.InitArguments; -import android.tracing.perfetto.Producer; import android.util.Log; import android.util.proto.ProtoInputStream; import android.util.proto.ProtoOutputStream; @@ -110,39 +107,31 @@ public class ProtoLogConfigurationServiceImpl extends IProtoLogConfigurationServ private final ViewerConfigFileTracer mViewerConfigFileTracer; public ProtoLogConfigurationServiceImpl() { - this(ProtoLogDataSource::new, ProtoLogConfigurationServiceImpl::dumpViewerConfig); + this(ProtoLog.getSharedSingleInstanceDataSource(), + ProtoLogConfigurationServiceImpl::dumpViewerConfig); } @VisibleForTesting - public ProtoLogConfigurationServiceImpl(@NonNull ProtoLogDataSourceBuilder dataSourceBuilder) { - this(dataSourceBuilder, ProtoLogConfigurationServiceImpl::dumpViewerConfig); + public ProtoLogConfigurationServiceImpl(@NonNull ProtoLogDataSource datasource) { + this(datasource, ProtoLogConfigurationServiceImpl::dumpViewerConfig); } @VisibleForTesting public ProtoLogConfigurationServiceImpl(@NonNull ViewerConfigFileTracer tracer) { - this(ProtoLogDataSource::new, tracer); + this(ProtoLog.getSharedSingleInstanceDataSource(), tracer); } @VisibleForTesting public ProtoLogConfigurationServiceImpl( - @NonNull ProtoLogDataSourceBuilder dataSourceBuilder, + @NonNull ProtoLogDataSource datasource, @NonNull ViewerConfigFileTracer tracer) { - mDataSource = dataSourceBuilder.build( - this::onTracingInstanceStart, - this::onTracingInstanceFlush, - this::onTracingInstanceStop - ); - - // Initialize the Perfetto producer and register the Perfetto ProtoLog datasource to be - // receive the lifecycle callbacks of the datasource and write the viewer configs if and - // when required to the datasource. - Producer.init(InitArguments.DEFAULTS); - final var params = new DataSourceParams.Builder() - .setBufferExhaustedPolicy(DataSourceParams.PERFETTO_DS_BUFFER_EXHAUSTED_POLICY_DROP) - .build(); - mDataSource.register(params); - mViewerConfigFileTracer = tracer; + + datasource.registerOnStartCallback(this::onTracingInstanceStart); + datasource.registerOnFlushCallback(this::onTracingInstanceFlush); + datasource.registerOnStopCallback(this::onTracingInstanceStop); + + mDataSource = datasource; } public static class RegisterClientArgs extends IRegisterClientArgs.Stub { diff --git a/core/java/com/android/internal/protolog/ProtoLogDataSource.java b/core/java/com/android/internal/protolog/ProtoLogDataSource.java index 0afb135ac6d98ecf8c8bb6c9f7e6828b28096fff..ea452494b88d3b1aed84b1baf63347e5bf231f33 100644 --- a/core/java/com/android/internal/protolog/ProtoLogDataSource.java +++ b/core/java/com/android/internal/protolog/ProtoLogDataSource.java @@ -46,36 +46,30 @@ import java.util.HashMap; import java.util.HashSet; import java.util.Map; import java.util.Set; +import java.util.TreeMap; public class ProtoLogDataSource extends DataSource { private static final String DATASOURCE_NAME = "android.protolog"; + private final Map mRunningInstances = new TreeMap<>(); + @NonNull - private final Instance.TracingInstanceStartCallback mOnStart; + private final Set mOnStartCallbacks = new HashSet<>(); @NonNull - private final Runnable mOnFlush; + private final Set mOnFlushCallbacks = new HashSet<>(); @NonNull - private final Instance.TracingInstanceStopCallback mOnStop; + private final Set mOnStopCallbacks = new HashSet<>(); - public ProtoLogDataSource( - @NonNull Instance.TracingInstanceStartCallback onStart, - @NonNull Runnable onFlush, - @NonNull Instance.TracingInstanceStopCallback onStop) { - this(onStart, onFlush, onStop, DATASOURCE_NAME); + public ProtoLogDataSource() { + this(DATASOURCE_NAME); } @VisibleForTesting public ProtoLogDataSource( - @NonNull Instance.TracingInstanceStartCallback onStart, - @NonNull Runnable onFlush, - @NonNull Instance.TracingInstanceStopCallback onStop, @NonNull String dataSourceName) { super(dataSourceName); - this.mOnStart = onStart; - this.mOnFlush = onFlush; - this.mOnStop = onStop; } @Override @@ -106,7 +100,8 @@ public class ProtoLogDataSource extends DataSource sLogGroups; @ProtoLogToolInjected(CACHE_UPDATER) - private static Runnable sCacheUpdater; + private static ProtoLogCacheUpdater sCacheUpdater; /** Used by the ProtoLogTool, do not call directly - use {@code ProtoLog} class instead. */ public static void d(IProtoLogGroup group, long messageHash, int paramsMask, Object... args) { @@ -93,7 +93,12 @@ public class ProtoLogImpl { * and log level. */ public static boolean isEnabled(IProtoLogGroup group, LogLevel level) { - return getSingleInstance().isEnabled(group, level); + return isEnabled(getSingleInstance(), group, level); + } + + private static boolean isEnabled( + IProtoLog protoLogInstance, IProtoLogGroup group, LogLevel level) { + return protoLogInstance.isEnabled(group, level); } /** @@ -106,36 +111,37 @@ public class ProtoLogImpl { final var groups = sLogGroups.values().toArray(new IProtoLogGroup[0]); if (android.tracing.Flags.perfettoProtologTracing()) { - sServiceInstance = createProtoLogImpl(groups); + var viewerConfigFile = new File(sViewerConfigPath); + if (!viewerConfigFile.exists()) { + // TODO(b/353530422): Remove - temporary fix to unblock b/352290057 + // In robolectric tests the viewer config file isn't current available, so we + // cannot use the ProcessedPerfettoProtoLogImpl. + Log.e(LOG_TAG, "Failed to find viewer config file " + sViewerConfigPath + + " when setting up " + ProtoLogImpl.class.getSimpleName() + ". " + + "ProtoLog will not work here!"); + + sServiceInstance = new NoViewerConfigProtoLogImpl(); + } else { + var datasource = ProtoLog.getSharedSingleInstanceDataSource(); + try { + var processedProtoLogImpl = + new ProcessedPerfettoProtoLogImpl(datasource, sViewerConfigPath, + sCacheUpdater, groups); + sServiceInstance = processedProtoLogImpl; + processedProtoLogImpl.enable(); + } catch (ServiceManager.ServiceNotFoundException e) { + throw new RuntimeException(e); + } + } } else { sServiceInstance = createLegacyProtoLogImpl(groups); } - sCacheUpdater.run(); + sCacheUpdater.update(sServiceInstance); } return sServiceInstance; } - private static IProtoLog createProtoLogImpl(IProtoLogGroup[] groups) { - try { - File f = new File(sViewerConfigPath); - if (!f.exists()) { - // TODO(b/353530422): Remove - temporary fix to unblock b/352290057 - // In robolectric tests the viewer config file isn't current available, so we cannot - // use the ProcessedPerfettoProtoLogImpl. - Log.e(LOG_TAG, "Failed to find viewer config file " + sViewerConfigPath - + " when setting up " + ProtoLogImpl.class.getSimpleName() + ". " - + "ProtoLog will not work here!"); - - return new NoViewerConfigProtoLogImpl(); - } else { - return new ProcessedPerfettoProtoLogImpl(sViewerConfigPath, sCacheUpdater, groups); - } - } catch (ServiceManager.ServiceNotFoundException e) { - throw new RuntimeException(e); - } - } - private static LegacyProtoLogImpl createLegacyProtoLogImpl(IProtoLogGroup[] groups) { var protologImpl = new LegacyProtoLogImpl( sLegacyOutputFilePath, sLegacyViewerConfigPath, sCacheUpdater); diff --git a/core/java/com/android/internal/protolog/UnprocessedPerfettoProtoLogImpl.java b/core/java/com/android/internal/protolog/UnprocessedPerfettoProtoLogImpl.java index f3fe58070fa973425b776461e1f5adfed3fc110e..ebb07a04270da4c93cfb7db87b2a668eeeecaa73 100644 --- a/core/java/com/android/internal/protolog/UnprocessedPerfettoProtoLogImpl.java +++ b/core/java/com/android/internal/protolog/UnprocessedPerfettoProtoLogImpl.java @@ -23,14 +23,10 @@ import com.android.internal.protolog.ProtoLogConfigurationServiceImpl.RegisterCl import com.android.internal.protolog.common.IProtoLogGroup; public class UnprocessedPerfettoProtoLogImpl extends PerfettoProtoLogImpl { - public UnprocessedPerfettoProtoLogImpl(@NonNull IProtoLogGroup[] groups) + public UnprocessedPerfettoProtoLogImpl( + @NonNull ProtoLogDataSource dataSource, @NonNull IProtoLogGroup[] groups) throws ServiceManager.ServiceNotFoundException { - this(() -> {}, groups); - } - - public UnprocessedPerfettoProtoLogImpl(@NonNull Runnable cacheUpdater, - @NonNull IProtoLogGroup[] groups) throws ServiceManager.ServiceNotFoundException { - super(cacheUpdater, groups); + super(dataSource, (instance) -> {}, groups); readyToLogToLogcat(); } diff --git a/core/java/com/android/internal/vibrator/persistence/SerializedCompositionPrimitive.java b/core/java/com/android/internal/vibrator/persistence/SerializedCompositionPrimitive.java index 862f7cb1d4767053620ed7ee01e7b1e54220128c..5eedec6a63e4345de3cb73db4ffc00ff48f5cf48 100644 --- a/core/java/com/android/internal/vibrator/persistence/SerializedCompositionPrimitive.java +++ b/core/java/com/android/internal/vibrator/persistence/SerializedCompositionPrimitive.java @@ -17,6 +17,7 @@ package com.android.internal.vibrator.persistence; import static com.android.internal.vibrator.persistence.XmlConstants.ATTRIBUTE_DELAY_MS; +import static com.android.internal.vibrator.persistence.XmlConstants.ATTRIBUTE_DELAY_TYPE; import static com.android.internal.vibrator.persistence.XmlConstants.ATTRIBUTE_NAME; import static com.android.internal.vibrator.persistence.XmlConstants.ATTRIBUTE_SCALE; import static com.android.internal.vibrator.persistence.XmlConstants.NAMESPACE; @@ -25,9 +26,11 @@ import static com.android.internal.vibrator.persistence.XmlConstants.TAG_PRIMITI import android.annotation.NonNull; import android.annotation.Nullable; import android.os.VibrationEffect; +import android.os.vibrator.Flags; import android.os.vibrator.PrimitiveSegment; import com.android.internal.vibrator.persistence.SerializedComposedEffect.SerializedSegment; +import com.android.internal.vibrator.persistence.XmlConstants.PrimitiveDelayType; import com.android.internal.vibrator.persistence.XmlConstants.PrimitiveEffectName; import com.android.modules.utils.TypedXmlPullParser; import com.android.modules.utils.TypedXmlSerializer; @@ -46,17 +49,26 @@ final class SerializedCompositionPrimitive implements SerializedSegment { private final PrimitiveEffectName mPrimitiveName; private final float mPrimitiveScale; private final int mPrimitiveDelayMs; + @Nullable + private final PrimitiveDelayType mDelayType; - SerializedCompositionPrimitive(PrimitiveEffectName primitiveName, float scale, int delayMs) { + SerializedCompositionPrimitive(PrimitiveEffectName primitiveName, float scale, int delayMs, + @Nullable PrimitiveDelayType delayType) { mPrimitiveName = primitiveName; mPrimitiveScale = scale; mPrimitiveDelayMs = delayMs; + mDelayType = delayType; } @Override public void deserializeIntoComposition(@NonNull VibrationEffect.Composition composition) { - composition.addPrimitive(mPrimitiveName.getPrimitiveId(), mPrimitiveScale, - mPrimitiveDelayMs); + if (Flags.primitiveCompositionAbsoluteDelay() && mDelayType != null) { + composition.addPrimitive(mPrimitiveName.getPrimitiveId(), mPrimitiveScale, + mPrimitiveDelayMs, mDelayType.getDelayType()); + } else { + composition.addPrimitive(mPrimitiveName.getPrimitiveId(), mPrimitiveScale, + mPrimitiveDelayMs); + } } @Override @@ -72,6 +84,12 @@ final class SerializedCompositionPrimitive implements SerializedSegment { serializer.attributeInt(NAMESPACE, ATTRIBUTE_DELAY_MS, mPrimitiveDelayMs); } + if (Flags.primitiveCompositionAbsoluteDelay() && mDelayType != null) { + if (mDelayType.getDelayType() != PrimitiveSegment.DEFAULT_DELAY_TYPE) { + serializer.attribute(NAMESPACE, ATTRIBUTE_DELAY_TYPE, mDelayType.toString()); + } + } + serializer.endTag(NAMESPACE, TAG_PRIMITIVE_EFFECT); } @@ -81,6 +99,7 @@ final class SerializedCompositionPrimitive implements SerializedSegment { + "name=" + mPrimitiveName + ", scale=" + mPrimitiveScale + ", delayMs=" + mPrimitiveDelayMs + + ", delayType=" + mDelayType + '}'; } @@ -91,8 +110,14 @@ final class SerializedCompositionPrimitive implements SerializedSegment { static SerializedCompositionPrimitive parseNext(@NonNull TypedXmlPullParser parser) throws XmlParserException, IOException { XmlValidator.checkStartTag(parser, TAG_PRIMITIVE_EFFECT); - XmlValidator.checkTagHasNoUnexpectedAttributes(parser, - ATTRIBUTE_NAME, ATTRIBUTE_DELAY_MS, ATTRIBUTE_SCALE); + + if (Flags.primitiveCompositionAbsoluteDelay()) { + XmlValidator.checkTagHasNoUnexpectedAttributes(parser, + ATTRIBUTE_NAME, ATTRIBUTE_DELAY_MS, ATTRIBUTE_SCALE, ATTRIBUTE_DELAY_TYPE); + } else { + XmlValidator.checkTagHasNoUnexpectedAttributes(parser, + ATTRIBUTE_NAME, ATTRIBUTE_DELAY_MS, ATTRIBUTE_SCALE); + } PrimitiveEffectName primitiveName = parsePrimitiveName( parser.getAttributeValue(NAMESPACE, ATTRIBUTE_NAME)); @@ -100,11 +125,13 @@ final class SerializedCompositionPrimitive implements SerializedSegment { parser, ATTRIBUTE_SCALE, 0, 1, PrimitiveSegment.DEFAULT_SCALE); int delayMs = XmlReader.readAttributeIntNonNegative( parser, ATTRIBUTE_DELAY_MS, PrimitiveSegment.DEFAULT_DELAY_MILLIS); + PrimitiveDelayType delayType = parseDelayType( + parser.getAttributeValue(NAMESPACE, ATTRIBUTE_DELAY_TYPE)); // Consume tag XmlReader.readEndTag(parser); - return new SerializedCompositionPrimitive(primitiveName, scale, delayMs); + return new SerializedCompositionPrimitive(primitiveName, scale, delayMs, delayType); } @NonNull @@ -119,5 +146,21 @@ final class SerializedCompositionPrimitive implements SerializedSegment { } return effectName; } + + @Nullable + private static PrimitiveDelayType parseDelayType(@Nullable String name) + throws XmlParserException { + if (name == null) { + return null; + } + if (!Flags.primitiveCompositionAbsoluteDelay()) { + throw new XmlParserException("Unexpected primitive delay type " + name); + } + PrimitiveDelayType delayType = PrimitiveDelayType.findByName(name); + if (delayType == null) { + throw new XmlParserException("Unexpected primitive delay type " + name); + } + return delayType; + } } } diff --git a/core/java/com/android/internal/vibrator/persistence/VibrationEffectXmlSerializer.java b/core/java/com/android/internal/vibrator/persistence/VibrationEffectXmlSerializer.java index d74a23d47f4a166230a4be30a5f60eb660c1a05a..cb834a5eac7e816eaaedabcc54e29eb633205116 100644 --- a/core/java/com/android/internal/vibrator/persistence/VibrationEffectXmlSerializer.java +++ b/core/java/com/android/internal/vibrator/persistence/VibrationEffectXmlSerializer.java @@ -27,6 +27,7 @@ import android.os.vibrator.VibrationEffectSegment; import com.android.internal.vibrator.persistence.SerializedComposedEffect.SerializedSegment; import com.android.internal.vibrator.persistence.XmlConstants.PredefinedEffectName; +import com.android.internal.vibrator.persistence.XmlConstants.PrimitiveDelayType; import com.android.internal.vibrator.persistence.XmlConstants.PrimitiveEffectName; import java.util.List; @@ -170,8 +171,20 @@ public final class VibrationEffectXmlSerializer { XmlValidator.checkSerializerCondition(primitiveName != null, "Unsupported primitive effect id %s", primitive.getPrimitiveId()); + PrimitiveDelayType delayType = null; + + if (Flags.primitiveCompositionAbsoluteDelay()) { + delayType = PrimitiveDelayType.findByType(primitive.getDelayType()); + XmlValidator.checkSerializerCondition(delayType != null, + "Unsupported primitive delay type %s", primitive.getDelayType()); + } else { + XmlValidator.checkSerializerCondition( + primitive.getDelayType() == PrimitiveSegment.DEFAULT_DELAY_TYPE, + "Unsupported primitive delay type %s", primitive.getDelayType()); + } + return new SerializedCompositionPrimitive( - primitiveName, primitive.getScale(), primitive.getDelay()); + primitiveName, primitive.getScale(), primitive.getDelay(), delayType); } private static int toAmplitudeInt(float amplitude) { diff --git a/core/java/com/android/internal/vibrator/persistence/XmlConstants.java b/core/java/com/android/internal/vibrator/persistence/XmlConstants.java index 2a55d999bc0fc0917d65c6892ef917d861cefdd6..4122215a2b04a5d197a0d26cb9f0b46cb28dff45 100644 --- a/core/java/com/android/internal/vibrator/persistence/XmlConstants.java +++ b/core/java/com/android/internal/vibrator/persistence/XmlConstants.java @@ -20,6 +20,7 @@ import android.annotation.IntDef; import android.annotation.NonNull; import android.annotation.Nullable; import android.os.VibrationEffect; +import android.os.VibrationEffect.Composition.DelayType; import android.os.VibrationEffect.Composition.PrimitiveType; import java.lang.annotation.Retention; @@ -51,6 +52,7 @@ public final class XmlConstants { public static final String ATTRIBUTE_AMPLITUDE = "amplitude"; public static final String ATTRIBUTE_SCALE = "scale"; public static final String ATTRIBUTE_DELAY_MS = "delayMs"; + public static final String ATTRIBUTE_DELAY_TYPE = "delayType"; public static final String VALUE_AMPLITUDE_DEFAULT = "default"; @@ -87,7 +89,7 @@ public final class XmlConstants { /** * Return the {@link PrimitiveEffectName} that represents given primitive id, or null if - * none of the available names maps to the given id. + * none of the available names map to the given id. */ @Nullable public static PrimitiveEffectName findById(int primitiveId) { @@ -200,4 +202,53 @@ public final class XmlConstants { return name().toLowerCase(Locale.ROOT); } } + + /** Represent supported values for attribute delay type in {@link #TAG_PRIMITIVE_EFFECT} */ + public enum PrimitiveDelayType { + PAUSE(VibrationEffect.Composition.DELAY_TYPE_PAUSE), + RELATIVE_START_OFFSET(VibrationEffect.Composition.DELAY_TYPE_RELATIVE_START_OFFSET); + + @DelayType private final int mDelayType; + + PrimitiveDelayType(@DelayType int type) { + mDelayType = type; + } + + /** + * Return the {@link PrimitiveEffectName} that represents given primitive id, or null if + * none of the available names maps to the given id. + */ + @Nullable + public static PrimitiveDelayType findByType(int delayType) { + for (PrimitiveDelayType type : PrimitiveDelayType.values()) { + if (type.mDelayType == delayType) { + return type; + } + } + return null; + } + + /** + * Return the {@link PrimitiveEffectName} that represents given primitive name, or null if + * none of the available names maps to the given name. + */ + @Nullable + public static PrimitiveDelayType findByName(@NonNull String delayType) { + try { + return PrimitiveDelayType.valueOf(delayType.toUpperCase(Locale.ROOT)); + } catch (IllegalArgumentException e) { + return null; + } + } + + @DelayType + public int getDelayType() { + return mDelayType; + } + + @Override + public String toString() { + return name().toLowerCase(Locale.ROOT); + } + } } diff --git a/core/java/com/android/internal/widget/NotificationProgressBar.java b/core/java/com/android/internal/widget/NotificationProgressBar.java index 7a21275d611e96a604a81b2a18422d8b61769f7d..8cd7843fe1d920bf06dd7ff5400ad4fe94c317c1 100644 --- a/core/java/com/android/internal/widget/NotificationProgressBar.java +++ b/core/java/com/android/internal/widget/NotificationProgressBar.java @@ -68,12 +68,18 @@ public final class NotificationProgressBar extends ProgressBar { @Nullable private Drawable mTracker = null; + + /** @see R.styleable#NotificationProgressBar_trackerHeight */ private final int mTrackerHeight; private int mTrackerWidth; private int mTrackerPos; private final Matrix mMatrix = new Matrix(); private Matrix mTrackerDrawMatrix = null; + private float mScale = 0; + /** Indicates whether mTrackerPos needs to be recalculated before the tracker is drawn. */ + private boolean mTrackerPosIsDirty = false; + public NotificationProgressBar(Context context) { this(context, null); } @@ -107,8 +113,8 @@ public final class NotificationProgressBar extends ProgressBar { final Drawable tracker = a.getDrawable(R.styleable.NotificationProgressBar_tracker); setTracker(tracker); - // If this is configured to be non-zero, will scale the tracker drawable and ensure its - // aspect ration is between 2:1 to 1:2. + // If this is configured to be a non-zero size, will scale and crop the tracker drawable to + // ensure its aspect ratio is between 2:1 to 1:2. mTrackerHeight = a.getDimensionPixelSize(R.styleable.NotificationProgressBar_trackerHeight, 0); } @@ -200,8 +206,9 @@ public final class NotificationProgressBar extends ProgressBar { } private void setTracker(@Nullable Drawable tracker) { - final boolean needUpdate = mTracker != null && tracker != mTracker; - if (needUpdate) { + if (tracker == mTracker) return; + + if (mTracker != null) { mTracker.setCallback(null); } @@ -214,33 +221,41 @@ public final class NotificationProgressBar extends ProgressBar { if (canResolveLayoutDirection()) { tracker.setLayoutDirection(getLayoutDirection()); } - - // If we're updating get the new states - if (needUpdate && (tracker.getIntrinsicWidth() != mTracker.getIntrinsicWidth() - || tracker.getIntrinsicHeight() != mTracker.getIntrinsicHeight())) { - requestLayout(); - } } + final boolean trackerSizeChanged = trackerSizeChanged(tracker, mTracker); + mTracker = tracker; if (mNotificationProgressDrawable != null) { mNotificationProgressDrawable.setHasTrackerIcon(mTracker != null); } configureTrackerBounds(); + updateTrackerAndBarPos(getWidth(), getHeight()); + + // Change in tracker size may lead to change in measured view size. + // @see #onMeasure. + if (trackerSizeChanged) requestLayout(); invalidate(); - if (needUpdate) { - updateTrackerAndBarPos(getWidth(), getHeight()); - if (tracker != null && tracker.isStateful()) { - // Note that if the states are different this won't work. - // For now, let's consider that an app bug. - tracker.setState(getDrawableState()); - } + if (tracker != null && tracker.isStateful()) { + // Note that if the states are different this won't work. + // For now, let's consider that an app bug. + tracker.setState(getDrawableState()); } } + private static boolean trackerSizeChanged(@Nullable Drawable newTracker, + @Nullable Drawable oldTracker) { + if (newTracker == null && oldTracker == null) return false; + if (newTracker == null && oldTracker != null) return true; + if (newTracker != null && oldTracker == null) return true; + + return newTracker.getIntrinsicWidth() != oldTracker.getIntrinsicWidth() + || newTracker.getIntrinsicHeight() != oldTracker.getIntrinsicHeight(); + } + private void configureTrackerBounds() { // Reset the tracker draw matrix to null mTrackerDrawMatrix = null; @@ -278,6 +293,44 @@ public final class NotificationProgressBar extends ProgressBar { mTrackerDrawMatrix.postTranslate(Math.round(dx), Math.round(dy)); } + @Override + public synchronized void setProgress(int progress) { + super.setProgress(progress); + + onMaybeVisualProgressChanged(); + } + + @Override + public void setProgress(int progress, boolean animate) { + // Animation isn't supported by NotificationProgressBar. + super.setProgress(progress, false); + + onMaybeVisualProgressChanged(); + } + + @Override + public synchronized void setMin(int min) { + super.setMin(min); + + onMaybeVisualProgressChanged(); + } + + @Override + public synchronized void setMax(int max) { + super.setMax(max); + + onMaybeVisualProgressChanged(); + } + + private void onMaybeVisualProgressChanged() { + float scale = getScale(); + if (mScale == scale) return; + + mScale = scale; + mTrackerPosIsDirty = true; + invalidate(); + } + @Override protected boolean verifyDrawable(@NonNull Drawable who) { return who == mTracker || super.verifyDrawable(who); @@ -328,7 +381,7 @@ public final class NotificationProgressBar extends ProgressBar { // parameter does. final int barHeight = Math.min(getMaxHeight(), paddedHeight); final int trackerHeight = tracker == null ? 0 - : ((mTrackerHeight == 0) ? tracker.getIntrinsicHeight() : mTrackerHeight); + : ((mTrackerHeight <= 0) ? tracker.getIntrinsicHeight() : mTrackerHeight); // Apply offset to whichever item is taller. final int barOffsetY; @@ -349,7 +402,7 @@ public final class NotificationProgressBar extends ProgressBar { } if (tracker != null) { - setTrackerPos(w, tracker, getScale(), trackerOffsetY); + setTrackerPos(w, tracker, mScale, trackerOffsetY); } } @@ -373,7 +426,7 @@ public final class NotificationProgressBar extends ProgressBar { int available = w - mPaddingLeft - mPaddingRight; final int trackerWidth = tracker.getIntrinsicWidth(); final int trackerHeight = tracker.getIntrinsicHeight(); - available -= ((mTrackerHeight == 0) ? trackerWidth : mTrackerWidth); + available -= ((mTrackerHeight <= 0) ? trackerWidth : mTrackerWidth); final int trackerPos = (int) (scale * available + 0.5f); @@ -401,6 +454,8 @@ public final class NotificationProgressBar extends ProgressBar { // Canvas will be translated, so 0,0 is where we start drawing tracker.setBounds(left, top, right, bottom); + + mTrackerPosIsDirty = false; } @Override @@ -424,18 +479,26 @@ public final class NotificationProgressBar extends ProgressBar { * Draw the tracker. */ private void drawTracker(Canvas canvas) { - if (mTracker != null) { - final int saveCount = canvas.save(); - // Translate the canvas origin to tracker position to make the draw matrix and the RtL - // transformations work. - canvas.translate(mPaddingLeft + mTrackerPos, mPaddingTop); + if (mTracker == null) return; + + if (mTrackerPosIsDirty) { + setTrackerPos(getWidth(), mTracker, mScale, Integer.MIN_VALUE); + } + + final int saveCount = canvas.save(); + // Translate the canvas origin to tracker position to make the draw matrix and the RtL + // transformations work. + canvas.translate(mPaddingLeft + mTrackerPos, mPaddingTop); + + if (mTrackerHeight > 0) { canvas.clipRect(0, 0, mTrackerWidth, mTrackerHeight); - if (mTrackerDrawMatrix != null) { - canvas.concat(mTrackerDrawMatrix); - } - mTracker.draw(canvas); - canvas.restoreToCount(saveCount); } + + if (mTrackerDrawMatrix != null) { + canvas.concat(mTrackerDrawMatrix); + } + mTracker.draw(canvas); + canvas.restoreToCount(saveCount); } @Override @@ -468,7 +531,7 @@ public final class NotificationProgressBar extends ProgressBar { final Drawable tracker = mTracker; if (tracker != null) { - setTrackerPos(getWidth(), tracker, getScale(), Integer.MIN_VALUE); + setTrackerPos(getWidth(), tracker, mScale, Integer.MIN_VALUE); // Since we draw translated, the drawable's bounds that it signals // for invalidation won't be the actual bounds we want invalidated, diff --git a/core/java/com/android/internal/widget/remotecompose/core/CompanionOperation.java b/core/java/com/android/internal/widget/remotecompose/core/CompanionOperation.java index 244bb3d6380b10649a0de22e9995b21742096ee7..b5d3895401850cc49f01d04ceaa2918f3b7ce073 100644 --- a/core/java/com/android/internal/widget/remotecompose/core/CompanionOperation.java +++ b/core/java/com/android/internal/widget/remotecompose/core/CompanionOperation.java @@ -15,6 +15,8 @@ */ package com.android.internal.widget.remotecompose.core; +import android.annotation.NonNull; + import java.util.List; /** Interface for the companion operations */ @@ -25,5 +27,5 @@ public interface CompanionOperation { * @param buffer data to read to create operation * @param operations command is to be added */ - void read(WireBuffer buffer, List operations); + void read(@NonNull WireBuffer buffer, @NonNull List operations); } 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 0761a244b9f2119604e4f92087a93b376f9dbfa8..370289a84502f24cdb33d0404046c0af9e9f40c5 100644 --- a/core/java/com/android/internal/widget/remotecompose/core/CoreDocument.java +++ b/core/java/com/android/internal/widget/remotecompose/core/CoreDocument.java @@ -19,6 +19,7 @@ import android.annotation.NonNull; import android.annotation.Nullable; 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; @@ -53,15 +54,16 @@ public class CoreDocument { private static final boolean DEBUG = false; - ArrayList mOperations; + @NonNull ArrayList mOperations = new ArrayList<>(); @Nullable RootLayoutComponent mRootLayoutComponent = null; - RemoteComposeState mRemoteComposeState = new RemoteComposeState(); + @NonNull RemoteComposeState mRemoteComposeState = new RemoteComposeState(); @NonNull TimeVariables mTimeVariables = new TimeVariables(); // Semantic version of the document @NonNull Version mVersion = new Version(0, 1, 0); + @Nullable String mContentDescription; // text description of the document (used for accessibility) long mRequiredCapabilities = 0L; // bitmask indicating needed capabilities of the player(unused) @@ -74,19 +76,22 @@ public class CoreDocument { int mContentAlignment = RootContentBehavior.ALIGNMENT_CENTER; - RemoteComposeBuffer mBuffer = new RemoteComposeBuffer(mRemoteComposeState); + @NonNull RemoteComposeBuffer mBuffer = new RemoteComposeBuffer(mRemoteComposeState); private final HashMap mIntegerExpressions = new HashMap<>(); + private final HashMap mFloatExpressions = new HashMap<>(); + private HashSet mAppliedTouchOperations = new HashSet<>(); private int mLastId = 1; // last component id when inflating the file + @Nullable public String getContentDescription() { return mContentDescription; } - public void setContentDescription(String contentDescription) { + public void setContentDescription(@Nullable String contentDescription) { this.mContentDescription = contentDescription; } @@ -116,19 +121,21 @@ public class CoreDocument { mRemoteComposeState.setWindowHeight(height); } + @NonNull public RemoteComposeBuffer getBuffer() { return mBuffer; } - public void setBuffer(RemoteComposeBuffer buffer) { + public void setBuffer(@NonNull RemoteComposeBuffer buffer) { this.mBuffer = buffer; } + @NonNull public RemoteComposeState getRemoteComposeState() { return mRemoteComposeState; } - public void setRemoteComposeState(RemoteComposeState remoteComposeState) { + public void setRemoteComposeState(@NonNull RemoteComposeState remoteComposeState) { this.mRemoteComposeState = remoteComposeState; } @@ -171,7 +178,7 @@ public class CoreDocument { * @param h vertical dimension of the rendering area * @param scaleOutput will contain the computed scale factor */ - public void computeScale(float w, float h, float[] scaleOutput) { + public void computeScale(float w, float h, @NonNull float[] scaleOutput) { float contentScaleX = 1f; float contentScaleY = 1f; if (mContentSizing == RootContentBehavior.SIZING_SCALE) { @@ -236,7 +243,11 @@ public class CoreDocument { * @param translateOutput will contain the computed translation */ private void computeTranslate( - float w, float h, float contentScaleX, float contentScaleY, float[] translateOutput) { + float w, + float h, + float contentScaleX, + float contentScaleY, + @NonNull float[] translateOutput) { int horizontalContentAlignment = mContentAlignment & 0xF0; int verticalContentAlignment = mContentAlignment & 0xF; float translateX = 0f; @@ -350,6 +361,22 @@ public class CoreDocument { } } + /** + * Execute an integer expression with the given id and put its value on the targetId + * + * @param expressionId the id of the integer expression + * @param targetId the id of the value to update with the expression + * @param context the current context + */ + public void evaluateFloatExpression( + int expressionId, int targetId, @NonNull RemoteContext context) { + FloatExpression expression = mFloatExpressions.get(expressionId); + if (expression != null) { + float v = expression.evaluate(context); + context.overrideFloat(targetId, v); + } + } + // ============== Haptic support ================== public interface HapticEngine { void haptic(int type); @@ -375,7 +402,7 @@ public class CoreDocument { /** Callback interface for host actions */ public interface ActionCallback { - void onAction(String name, Object value); + void onAction(@NonNull String name, Object value); } @NonNull HashSet mActionListeners = new HashSet(); @@ -386,7 +413,7 @@ public class CoreDocument { * @param name the action name * @param value a parameter to the action */ - public void runNamedAction(String name, Object value) { + public void runNamedAction(@NonNull String name, Object value) { // TODO: we might add an interface to group all valid parameter types for (ActionCallback callback : mActionListeners) { callback.onAction(name, value); @@ -398,7 +425,7 @@ public class CoreDocument { * * @param callback */ - public void addActionCallback(ActionCallback callback) { + public void addActionCallback(@NonNull ActionCallback callback) { mActionListeners.add(callback); } @@ -408,7 +435,7 @@ public class CoreDocument { } public interface ClickCallbacks { - void click(int id, String metadata); + void click(int id, @Nullable String metadata); } @NonNull HashSet mClickListeners = new HashSet<>(); @@ -429,21 +456,21 @@ public class CoreDocument { public static class ClickAreaRepresentation { int mId; - String mContentDescription; + @Nullable final String mContentDescription; float mLeft; float mTop; float mRight; float mBottom; - String mMetadata; + @Nullable final String mMetadata; public ClickAreaRepresentation( int id, - String contentDescription, + @Nullable String contentDescription, float left, float top, float right, float bottom, - String metadata) { + @Nullable String metadata) { this.mId = id; this.mContentDescription = contentDescription; this.mLeft = left; @@ -484,10 +511,11 @@ public class CoreDocument { return mId; } - public String getContentDescription() { + public @Nullable String getContentDescription() { return mContentDescription; } + @Nullable public String getMetadata() { return mMetadata; } @@ -502,6 +530,10 @@ public class CoreDocument { IntegerExpression expression = (IntegerExpression) op; mIntegerExpressions.put((long) expression.mId, expression); } + if (op instanceof FloatExpression) { + FloatExpression expression = (FloatExpression) op; + mFloatExpressions.put(expression.mId, expression); + } } mOperations = inflateComponents(mOperations); mBuffer = buffer; @@ -605,7 +637,8 @@ public class CoreDocument { @NonNull private HashMap mComponentMap = new HashMap(); - private void registerVariables(RemoteContext context, @NonNull ArrayList list) { + private void registerVariables( + @NonNull RemoteContext context, @NonNull ArrayList list) { for (Operation op : list) { if (op instanceof VariableSupport) { ((VariableSupport) op).updateVariables(context); @@ -701,12 +734,12 @@ public class CoreDocument { */ public void addClickArea( int id, - String contentDescription, + @Nullable String contentDescription, float left, float top, float right, float bottom, - String metadata) { + @Nullable String metadata) { mClickAreas.add( new ClickAreaRepresentation( id, contentDescription, left, top, right, bottom, metadata)); @@ -726,7 +759,7 @@ public class CoreDocument { * * @param callback called when a click area has been hit, passing the click are id and metadata. */ - public void addClickListener(ClickCallbacks callback) { + public void addClickListener(@NonNull ClickCallbacks callback) { mClickListeners.add(callback); } @@ -744,7 +777,7 @@ public class CoreDocument { * Passing a click event to the document. This will possibly result in calling the click * listeners. */ - public void onClick(RemoteContext context, float x, float y) { + public void onClick(@NonNull RemoteContext context, float x, float y) { for (ClickAreaRepresentation clickArea : mClickAreas) { if (clickArea.contains(x, y)) { warnClickListeners(clickArea); @@ -802,6 +835,14 @@ public class CoreDocument { for (TouchListener clickArea : mTouchListeners) { clickArea.touchDrag(context, x, y); } + if (mRootLayoutComponent != null) { + for (Component component : mAppliedTouchOperations) { + component.onTouchDrag(context, this, x, y, true); + } + if (!mAppliedTouchOperations.isEmpty()) { + return true; + } + } if (!mTouchListeners.isEmpty()) { return true; } @@ -940,6 +981,7 @@ public class CoreDocument { */ public void paint(@NonNull RemoteContext context, int theme) { context.getPaintContext().clearNeedsRepaint(); + context.loadFloat(RemoteContext.ID_DENSITY, context.getDensity()); context.mMode = RemoteContext.ContextMode.UNSET; // current theme starts as UNSPECIFIED, until a Theme setter // operation gets executed and modify it. @@ -1097,6 +1139,7 @@ public class CoreDocument { } } + @NonNull public List getOperations() { return mOperations; } 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 f1885f942ee19d60f40220b314314a2200684812..102003e2e371f84a95d7f0921c8c0f052b8eae85 100644 --- a/core/java/com/android/internal/widget/remotecompose/core/Operation.java +++ b/core/java/com/android/internal/widget/remotecompose/core/Operation.java @@ -15,22 +15,22 @@ */ package com.android.internal.widget.remotecompose.core; -import android.annotation.Nullable; +import android.annotation.NonNull; /** Base interface for RemoteCompose operations */ public interface Operation { /** add the operation to the buffer */ - void write(WireBuffer buffer); + void write(@NonNull WireBuffer buffer); /** * paint an operation * * @param context the paint context used to paint the operation */ - void apply(RemoteContext context); + void apply(@NonNull RemoteContext context); /** Debug utility to display an operation + indentation */ - @Nullable - String deepToString(String indent); + @NonNull + String deepToString(@NonNull String indent); } 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 53c45fac826c80561b8b9758c9b792d6d0769671..687a99baff83c5b0334157697204e9ff2ce24a54 100644 --- a/core/java/com/android/internal/widget/remotecompose/core/Operations.java +++ b/core/java/com/android/internal/widget/remotecompose/core/Operations.java @@ -98,7 +98,9 @@ import com.android.internal.widget.remotecompose.core.operations.layout.modifier 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.RoundedClipRectModifierOperation; +import com.android.internal.widget.remotecompose.core.operations.layout.modifiers.ScrollModifierOperation; import com.android.internal.widget.remotecompose.core.operations.layout.modifiers.ValueFloatChangeActionOperation; +import com.android.internal.widget.remotecompose.core.operations.layout.modifiers.ValueFloatExpressionChangeActionOperation; import com.android.internal.widget.remotecompose.core.operations.layout.modifiers.ValueIntegerChangeActionOperation; import com.android.internal.widget.remotecompose.core.operations.layout.modifiers.ValueIntegerExpressionChangeActionOperation; import com.android.internal.widget.remotecompose.core.operations.layout.modifiers.ValueStringChangeActionOperation; @@ -214,6 +216,7 @@ public class Operations { public static final int MODIFIER_OFFSET = 221; 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 LOOP_START = 215; public static final int LOOP_END = 216; @@ -226,6 +229,7 @@ public class Operations { public static final int VALUE_STRING_CHANGE_ACTION = 213; public static final int VALUE_INTEGER_EXPRESSION_CHANGE_ACTION = 218; public static final int VALUE_FLOAT_CHANGE_ACTION = 222; + public static final int VALUE_FLOAT_EXPRESSION_CHANGE_ACTION = 227; public static final int ANIMATION_SPEC = 14; @@ -235,7 +239,7 @@ public class Operations { static class UniqueIntMap extends IntMap { @Override - public T put(int key, T value) { + public T put(int key, @NonNull T value) { assert null == get(key) : "Opcode " + key + " already used in Operations !"; return super.put(key, value); } @@ -316,6 +320,7 @@ public class Operations { map.put(MODIFIER_OFFSET, OffsetModifierOperation::read); map.put(MODIFIER_ZINDEX, ZIndexModifierOperation::read); map.put(MODIFIER_GRAPHICS_LAYER, GraphicsLayerModifierOperation::read); + map.put(MODIFIER_SCROLL, ScrollModifierOperation::read); map.put(OPERATIONS_LIST_END, OperationsListEnd::read); @@ -327,6 +332,9 @@ public class Operations { ValueIntegerExpressionChangeActionOperation::read); map.put(VALUE_STRING_CHANGE_ACTION, ValueStringChangeActionOperation::read); map.put(VALUE_FLOAT_CHANGE_ACTION, ValueFloatChangeActionOperation::read); + map.put( + VALUE_FLOAT_EXPRESSION_CHANGE_ACTION, + ValueFloatExpressionChangeActionOperation::read); map.put(LAYOUT_ROOT, RootLayoutComponent::read); map.put(LAYOUT_CONTENT, LayoutComponentContent::read); diff --git a/core/java/com/android/internal/widget/remotecompose/core/PaintContext.java b/core/java/com/android/internal/widget/remotecompose/core/PaintContext.java index 1a71afe068bdc2f765db41cd130ad932c7015f82..38b08e9b0ab352de1c62b77a29bde19847354a29 100644 --- a/core/java/com/android/internal/widget/remotecompose/core/PaintContext.java +++ b/core/java/com/android/internal/widget/remotecompose/core/PaintContext.java @@ -15,6 +15,8 @@ */ package com.android.internal.widget.remotecompose.core; +import android.annotation.NonNull; + import com.android.internal.widget.remotecompose.core.operations.paint.PaintBundle; /** Specify an abstract paint context used by RemoteCompose commands to draw */ @@ -22,9 +24,10 @@ public abstract class PaintContext { public static final int TEXT_MEASURE_MONOSPACE_WIDTH = 0x01; public static final int TEXT_MEASURE_FONT_HEIGHT = 0x02; - protected RemoteContext mContext; + protected @NonNull RemoteContext mContext; private boolean mNeedsRepaint = false; + @NonNull public RemoteContext getContext() { return mContext; } @@ -37,11 +40,11 @@ public abstract class PaintContext { mNeedsRepaint = false; } - public PaintContext(RemoteContext context) { + public PaintContext(@NonNull RemoteContext context) { this.mContext = context; } - public void setContext(RemoteContext context) { + public void setContext(@NonNull RemoteContext context) { this.mContext = context; } @@ -117,7 +120,8 @@ public abstract class PaintContext { * descent of the font (not just of the measured text) * @param bounds the bounds (left, top, right, bottom) */ - public abstract void getTextBounds(int textId, int start, int end, int flags, float[] bounds); + public abstract void getTextBounds( + int textId, int start, int end, int flags, @NonNull float[] bounds); /** * Draw a text starting ast x,y @@ -158,7 +162,7 @@ public abstract class PaintContext { * * @param mPaintData the list of changes */ - public abstract void applyPaint(PaintBundle mPaintData); + public abstract void applyPaint(@NonNull PaintBundle mPaintData); /** * Scale the rendering by scaleX and saleY (1.0 = no scale). Scaling is done about @@ -264,7 +268,7 @@ public abstract class PaintContext { * * @param content the content to log */ - public void log(String content) { + public void log(@NonNull String content) { System.out.println("[LOG] " + content); } diff --git a/core/java/com/android/internal/widget/remotecompose/core/PaintOperation.java b/core/java/com/android/internal/widget/remotecompose/core/PaintOperation.java index 049e47744ce833d74abcee932fac882a2ee931ac..9999182b53fc8bb85bdb7b61996d2044f7fae56f 100644 --- a/core/java/com/android/internal/widget/remotecompose/core/PaintOperation.java +++ b/core/java/com/android/internal/widget/remotecompose/core/PaintOperation.java @@ -35,17 +35,17 @@ public abstract class PaintOperation implements Operation { @NonNull @Override - public String deepToString(String indent) { + public String deepToString(@NonNull String indent) { return indent + toString(); } - public abstract void paint(PaintContext context); + public abstract void paint(@NonNull PaintContext context); /** * Will return true if the operation is similar enough to the current one, in the context of an * animated transition. */ - public boolean suitableForTransition(Operation op) { + public boolean suitableForTransition(@NonNull Operation op) { // by default expects the op to not be suitable return false; } diff --git a/core/java/com/android/internal/widget/remotecompose/core/Platform.java b/core/java/com/android/internal/widget/remotecompose/core/Platform.java index 7fbcfae54bcb104b072059f74028d5728321c855..dcb8efebeecc7f31de0e56d295f58e4da3877c32 100644 --- a/core/java/com/android/internal/widget/remotecompose/core/Platform.java +++ b/core/java/com/android/internal/widget/remotecompose/core/Platform.java @@ -15,19 +15,20 @@ */ package com.android.internal.widget.remotecompose.core; +import android.annotation.NonNull; import android.annotation.Nullable; /** Services that are needed to be provided by the platform during encoding. */ public interface Platform { @Nullable - byte[] imageToByteArray(Object image); + byte[] imageToByteArray(@NonNull Object image); - int getImageWidth(Object image); + int getImageWidth(@NonNull Object image); - int getImageHeight(Object image); + int getImageHeight(@NonNull Object image); @Nullable - float[] pathToFloatArray(Object path); + float[] pathToFloatArray(@NonNull Object path); enum LogCategory { DEBUG, @@ -42,22 +43,22 @@ public interface Platform { Platform None = new Platform() { @Override - public byte[] imageToByteArray(Object image) { + public byte[] imageToByteArray(@NonNull Object image) { throw new UnsupportedOperationException(); } @Override - public int getImageWidth(Object image) { + public int getImageWidth(@NonNull Object image) { throw new UnsupportedOperationException(); } @Override - public int getImageHeight(Object image) { + public int getImageHeight(@NonNull Object image) { throw new UnsupportedOperationException(); } @Override - public float[] pathToFloatArray(Object path) { + public float[] pathToFloatArray(@NonNull Object path) { throw new UnsupportedOperationException(); } 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 7d9439dd186b692246033ec0376756bc831358d8..c05079e3450524fc9032a549690772ede6818abf 100644 --- a/core/java/com/android/internal/widget/remotecompose/core/RemoteComposeBuffer.java +++ b/core/java/com/android/internal/widget/remotecompose/core/RemoteComposeBuffer.java @@ -15,6 +15,9 @@ */ 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; import android.annotation.Nullable; @@ -89,6 +92,7 @@ import com.android.internal.widget.remotecompose.core.operations.layout.modifier 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.RoundedClipRectModifierOperation; +import com.android.internal.widget.remotecompose.core.operations.layout.modifiers.ScrollModifierOperation; import com.android.internal.widget.remotecompose.core.operations.layout.modifiers.ZIndexModifierOperation; import com.android.internal.widget.remotecompose.core.operations.paint.PaintBundle; import com.android.internal.widget.remotecompose.core.operations.utilities.NanMap; @@ -117,9 +121,9 @@ public class RemoteComposeBuffer { public static final int EASING_SPLINE_CUSTOM = FloatAnimation.SPLINE_CUSTOM; public static final int EASING_EASE_OUT_BOUNCE = FloatAnimation.EASE_OUT_BOUNCE; public static final int EASING_EASE_OUT_ELASTIC = FloatAnimation.EASE_OUT_ELASTIC; - WireBuffer mBuffer = new WireBuffer(); - @Nullable Platform mPlatform = null; - RemoteComposeState mRemoteComposeState; + private @NonNull WireBuffer mBuffer = new WireBuffer(); + @Nullable private Platform mPlatform = null; + @NonNull private final RemoteComposeState mRemoteComposeState; private static final boolean DEBUG = false; private int mLastComponentId = 0; @@ -130,7 +134,7 @@ public class RemoteComposeBuffer { * * @param remoteComposeState the state used while encoding on the buffer */ - public RemoteComposeBuffer(RemoteComposeState remoteComposeState) { + public RemoteComposeBuffer(@NonNull RemoteComposeState remoteComposeState) { this.mRemoteComposeState = remoteComposeState; } @@ -155,15 +159,15 @@ public class RemoteComposeBuffer { return mPlatform; } - public void setPlatform(Platform platform) { + public void setPlatform(@NonNull Platform platform) { this.mPlatform = platform; } - public WireBuffer getBuffer() { + public @NonNull WireBuffer getBuffer() { return mBuffer; } - public void setBuffer(WireBuffer buffer) { + public void setBuffer(@NonNull WireBuffer buffer) { this.mBuffer = buffer; } @@ -200,7 +204,7 @@ public class RemoteComposeBuffer { * @param height the height of the document in pixels * @param contentDescription content description of the document */ - public void header(int width, int height, String contentDescription) { + public void header(int width, int height, @Nullable String contentDescription) { header(width, height, contentDescription, 1f, 0); } @@ -220,7 +224,7 @@ public class RemoteComposeBuffer { * @param dstBottom bottom coordinate of the destination area */ public void drawBitmap( - Object image, + @NonNull Object image, int imageWidth, int imageHeight, int srcLeft, @@ -235,8 +239,9 @@ public class RemoteComposeBuffer { int imageId = mRemoteComposeState.dataGetId(image); if (imageId == -1) { imageId = mRemoteComposeState.cacheData(image); - byte[] data = mPlatform.imageToByteArray(image); - BitmapData.apply(mBuffer, imageId, imageWidth, imageHeight, data); + byte[] data = mPlatform.imageToByteArray(image); // todo: potential npe + BitmapData.apply( + mBuffer, imageId, imageWidth, imageHeight, data); // todo: potential npe } int contentDescriptionId = 0; if (contentDescription != null) { @@ -387,7 +392,7 @@ public class RemoteComposeBuffer { * @param contentDescription content description of the image */ public void addDrawBitmap( - Object image, + @NonNull Object image, float left, float top, float right, @@ -396,11 +401,12 @@ public class RemoteComposeBuffer { int imageId = mRemoteComposeState.dataGetId(image); if (imageId == -1) { imageId = mRemoteComposeState.cacheData(image); - byte[] data = mPlatform.imageToByteArray(image); + byte[] data = mPlatform.imageToByteArray(image); // todo: potential npe int imageWidth = mPlatform.getImageWidth(image); int imageHeight = mPlatform.getImageHeight(image); - BitmapData.apply(mBuffer, imageId, imageWidth, imageHeight, data); + BitmapData.apply( + mBuffer, imageId, imageWidth, imageHeight, data); // todo: potential npe } int contentDescriptionId = 0; if (contentDescription != null) { @@ -446,7 +452,7 @@ public class RemoteComposeBuffer { * @param contentDescription associate a string with image for accessibility */ public void drawScaledBitmap( - Object image, + @NonNull Object image, float srcLeft, float srcTop, float srcRight, @@ -461,11 +467,11 @@ public class RemoteComposeBuffer { int imageId = mRemoteComposeState.dataGetId(image); if (imageId == -1) { imageId = mRemoteComposeState.cacheData(image); - byte[] data = mPlatform.imageToByteArray(image); + byte[] data = mPlatform.imageToByteArray(image); // todo: potential npe int imageWidth = mPlatform.getImageWidth(image); int imageHeight = mPlatform.getImageHeight(image); - BitmapData.apply(mBuffer, imageId, imageWidth, imageHeight, data); + BitmapData.apply(mBuffer, imageId, imageWidth, imageHeight, data); // todo: potential pe } int contentDescriptionId = 0; if (contentDescription != null) { @@ -493,11 +499,11 @@ public class RemoteComposeBuffer { * @param image drawScaledBitmap * @return id of the image useful with */ - public int addBitmap(Object image) { + public int addBitmap(@NonNull Object image) { int imageId = mRemoteComposeState.dataGetId(image); if (imageId == -1) { imageId = mRemoteComposeState.cacheData(image); - byte[] data = mPlatform.imageToByteArray(image); + byte[] data = mPlatform.imageToByteArray(image); // tODO: potential npe int imageWidth = mPlatform.getImageWidth(image); int imageHeight = mPlatform.getImageHeight(image); @@ -512,11 +518,11 @@ public class RemoteComposeBuffer { * @param image drawScaledBitmap * @return id of the image useful with */ - public int addBitmap(Object image, @NonNull String name) { + public int addBitmap(@NonNull Object image, @NonNull String name) { int imageId = mRemoteComposeState.dataGetId(image); if (imageId == -1) { imageId = mRemoteComposeState.cacheData(image); - byte[] data = mPlatform.imageToByteArray(image); + byte[] data = mPlatform.imageToByteArray(image); // todo: potential npe int imageWidth = mPlatform.getImageWidth(image); int imageHeight = mPlatform.getImageHeight(image); @@ -629,7 +635,7 @@ public class RemoteComposeBuffer { * * @param path The path to be drawn */ - public void addDrawPath(Object path) { + public void addDrawPath(@NonNull Object path) { int id = mRemoteComposeState.dataGetId(path); if (id == -1) { // never been seen before id = addPathData(path); @@ -681,7 +687,8 @@ public class RemoteComposeBuffer { * @param hOffset The distance along the path to add to the text's starting position * @param vOffset The distance above(-) or below(+) the path to position the text */ - public void addDrawTextOnPath(@NonNull String text, Object path, float hOffset, float vOffset) { + public void addDrawTextOnPath( + @NonNull String text, @NonNull Object path, float hOffset, float vOffset) { int pathId = mRemoteComposeState.dataGetId(path); if (pathId == -1) { // never been seen before pathId = addPathData(path); @@ -752,7 +759,7 @@ public class RemoteComposeBuffer { *
  • Panning of 1.0, 0.0 - the test is centered & to the right of x,y * * - * Setting panY to NaN results in y being the baseline of the text. + *

    Setting panY to NaN results in y being the baseline of the text. * * @param text text to draw * @param x Coordinate of the Anchor @@ -836,7 +843,7 @@ public class RemoteComposeBuffer { *

  • Panning of 1.0, 0.0 - the test is centered & to the right of x,y * * - * Setting panY to NaN results in y being the baseline of the text. + *

    Setting panY to NaN results in y being the baseline of the text. * * @param textId text to draw * @param x Coordinate of the Anchor @@ -861,7 +868,8 @@ public class RemoteComposeBuffer { * @param start The start of the subrange of paths to draw 0 = start form start 0.5 is half way * @param stop The end of the subrange of paths to draw 1 = end at the end 0.5 is end half way */ - public void addDrawTweenPath(Object path1, Object path2, float tween, float start, float stop) { + public void addDrawTweenPath( + @NonNull Object path1, @NonNull Object path2, float tween, float start, float stop) { int path1Id = mRemoteComposeState.dataGetId(path1); if (path1Id == -1) { // never been seen before path1Id = addPathData(path1); @@ -892,7 +900,7 @@ public class RemoteComposeBuffer { * @param path * @return the id of the path on the wire */ - public int addPathData(Object path) { + public int addPathData(@NonNull Object path) { float[] pathData = mPlatform.pathToFloatArray(path); int id = mRemoteComposeState.cacheData(path); PathData.apply(mBuffer, id, pathData); @@ -910,7 +918,7 @@ public class RemoteComposeBuffer { /////////////////////////////////////////////////////////////////////////////////////////////// - public void inflateFromBuffer(ArrayList operations) { + public void inflateFromBuffer(@NonNull ArrayList operations) { mBuffer.setIndex(0); while (mBuffer.available()) { int opId = mBuffer.readByte(); @@ -926,7 +934,7 @@ public class RemoteComposeBuffer { } public static void readNextOperation( - @NonNull WireBuffer buffer, ArrayList operations) { + @NonNull WireBuffer buffer, @NonNull ArrayList operations) { int opId = buffer.readByte(); if (DEBUG) { Utils.log(">> " + opId); @@ -957,15 +965,16 @@ public class RemoteComposeBuffer { @NonNull public static RemoteComposeBuffer fromFile( - @NonNull String path, RemoteComposeState remoteComposeState) throws IOException { + @NonNull String path, @NonNull RemoteComposeState remoteComposeState) + throws IOException { RemoteComposeBuffer buffer = new RemoteComposeBuffer(remoteComposeState); read(new File(path), buffer); return buffer; } @NonNull - public RemoteComposeBuffer fromFile(@NonNull File file, RemoteComposeState remoteComposeState) - throws IOException { + public RemoteComposeBuffer fromFile( + @NonNull File file, @NonNull RemoteComposeState remoteComposeState) throws IOException { RemoteComposeBuffer buffer = new RemoteComposeBuffer(remoteComposeState); read(file, buffer); return buffer; @@ -973,7 +982,7 @@ public class RemoteComposeBuffer { @NonNull public static RemoteComposeBuffer fromInputStream( - @NonNull InputStream inputStream, RemoteComposeState remoteComposeState) { + @NonNull InputStream inputStream, @NonNull RemoteComposeState remoteComposeState) { RemoteComposeBuffer buffer = new RemoteComposeBuffer(remoteComposeState); read(inputStream, buffer); return buffer; @@ -1205,6 +1214,7 @@ public class RemoteComposeBuffer { /** * Add a touch handle system * + * @param id the float NaN id used for the returned position * @param value the default value * @param min the minimum value * @param max the maximum value @@ -1213,9 +1223,9 @@ public class RemoteComposeBuffer { * @param touchMode the touch up handling behaviour * @param touchSpec the touch up handling parameters * @param easingSpec the easing parameter TODO support in v2 - * @return id of the variable to be used controlled by touch handling */ - public float addTouchExpression( + public void addTouchExpression( + float id, float value, float min, float max, @@ -1225,9 +1235,45 @@ public class RemoteComposeBuffer { int touchMode, float[] touchSpec, float[] easingSpec) { - int id = mRemoteComposeState.nextId(); TouchExpression.apply( mBuffer, + Utils.idFromNan(id), + value, + min, + max, + velocityId, + touchEffects, + exp, + touchMode, + touchSpec, + easingSpec); + } + + /** + * Add a touch handle system + * + * @param value the default value + * @param min the minimum value + * @param max the maximum value + * @param velocityId the id for the velocity TODO support in v2 + * @param exp The Float Expression + * @param touchMode the touch up handling behaviour + * @param touchSpec the touch up handling parameters + * @param easingSpec the easing parameter TODO support in v2 + * @return id of the variable to be used controlled by touch handling + */ + public float addTouchExpression( + float value, + float min, + float max, + float velocityId, + int touchEffects, + float[] exp, + int touchMode, + float[] touchSpec, + float[] easingSpec) { + float id = Utils.asNan(mRemoteComposeState.nextId()); + addTouchExpression( id, value, min, @@ -1238,7 +1284,7 @@ public class RemoteComposeBuffer { touchMode, touchSpec, easingSpec); - return Utils.asNan(id); + return id; } /** @@ -1248,7 +1294,7 @@ public class RemoteComposeBuffer { * @param animation Array of floats that represents animation * @return NaN id of the result of the calculation */ - public float addAnimatedFloat(@NonNull float[] value, float[] animation) { + public float addAnimatedFloat(@NonNull float[] value, @Nullable float[] animation) { int id = mRemoteComposeState.cacheData(value); FloatExpression.apply(mBuffer, id, value, animation); return Utils.asNan(id); @@ -1345,7 +1391,7 @@ public class RemoteComposeBuffer { * @param listId * @return the id of the map, encoded as a float NaN */ - public int addMap(@NonNull String[] keys, byte[] types, int[] listId) { + public int addMap(@NonNull String[] keys, @Nullable byte[] types, @NonNull int[] listId) { int id = mRemoteComposeState.cacheData(listId, NanMap.TYPE_ARRAY); DataMapIds.apply(mBuffer, id, keys, types, listId); return id; @@ -1354,14 +1400,18 @@ public class RemoteComposeBuffer { /** * This provides access to text in RemoteList * + *

    TODO: do we want both a float and an int index version of this method? bbade@ TODO + * for @hoford - add a unit test for this method + * * @param dataSet * @param index index as a float variable * @return */ public int textLookup(float dataSet, float index) { long hash = - ((long) Float.floatToRawIntBits(dataSet)) - << (32 + Float.floatToRawIntBits(index)); // TODO: is this the correct ()s? + (((long) Float.floatToRawIntBits(dataSet)) << 32) + + Float.floatToRawIntBits( + index); // TODO: is this the correct ()s? -- bbade@ int id = mRemoteComposeState.cacheData(hash); TextLookup.apply(mBuffer, id, Utils.idFromNan(dataSet), index); return id; @@ -1370,14 +1420,16 @@ public class RemoteComposeBuffer { /** * This provides access to text in RemoteList * + *

    TODO for hoford - add a unit test for this method + * * @param dataSet * @param index index as an int variable * @return */ public int textLookup(float dataSet, int index) { long hash = - ((long) Float.floatToRawIntBits(dataSet)) - << (32 + Float.floatToRawIntBits(index)); // TODO: is this the correct ()s? + (((long) Float.floatToRawIntBits(dataSet)) << 32) + + Float.floatToRawIntBits(index); // TODO: is this the correct ()s? int id = mRemoteComposeState.cacheData(hash); TextLookupInt.apply(mBuffer, id, Utils.idFromNan(dataSet), index); return id; @@ -1521,8 +1573,8 @@ public class RemoteComposeBuffer { * @param wrap the wraps value so (e.g 360 so angles 355 would animate to 5) * @return */ - public static float[] packAnimation( - float duration, int type, float[] spec, float initialValue, float wrap) { + public static @NonNull float[] packAnimation( + float duration, int type, @Nullable float[] spec, float initialValue, float wrap) { return FloatAnimation.packToFloatArray(duration, type, spec, initialValue, wrap); } @@ -1590,6 +1642,43 @@ public class RemoteComposeBuffer { ComponentEnd.apply(mBuffer); } + /** + * Add a scroll modifier + * + * @param direction HORIZONTAL(0) or VERTICAL(1) + * @param positionId the position id as a NaN + * @param notches + */ + public void addModifierScroll(int direction, float positionId, int notches) { + // TODO: add support for non-notch behaviors etc. + float max = this.addFloat(0f); + float notchMax = this.addFloat(0f); + float touchExpressionDirection = + direction != 0 ? RemoteContext.FLOAT_TOUCH_POS_X : RemoteContext.FLOAT_TOUCH_POS_Y; + this.addTouchExpression( + positionId, + 0f, + 0f, + max, + 0f, + 3, + new float[] { + touchExpressionDirection, + -1, + // TODO: remove this CONTINUOUS_SEC hack... + MUL, + RemoteContext.FLOAT_CONTINUOUS_SEC, + 0f, + MUL, + ADD + }, + TouchExpression.STOP_NOTCHES_EVEN, + new float[] {notches, notchMax}, + null); + + ScrollModifierOperation.apply(mBuffer, direction, positionId, max, notchMax); + } + /** * Add a background modifier of provided color * @@ -1869,4 +1958,8 @@ public class RemoteComposeBuffer { public int createID(int type) { return mRemoteComposeState.nextId(type); } + + public int nextId() { + return mRemoteComposeState.nextId(); + } } 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 3039328149099e029bb75840f6ae198e9aea5ca0..a903e6ee1f27878f495b010ad94b0c3800646091 100644 --- a/core/java/com/android/internal/widget/remotecompose/core/RemoteComposeState.java +++ b/core/java/com/android/internal/widget/remotecompose/core/RemoteComposeState.java @@ -49,7 +49,7 @@ public class RemoteComposeState implements CollectionsAccess { private final IntMap mObjectMap = new IntMap<>(); private final boolean[] mColorOverride = new boolean[MAX_COLORS]; - private final IntMap mCollectionMap = new IntMap<>(); + @NonNull private final IntMap mCollectionMap = new IntMap<>(); private final boolean[] mDataOverride = new boolean[MAX_DATA]; private final boolean[] mIntegerOverride = new boolean[MAX_DATA]; @@ -82,7 +82,7 @@ public class RemoteComposeState implements CollectionsAccess { } /** Return the id of an item from the cache. */ - public int dataGetId(Object data) { + public int dataGetId(@NonNull Object data) { Integer res = mDataIntMap.get(data); if (res == null) { return -1; @@ -94,7 +94,7 @@ public class RemoteComposeState implements CollectionsAccess { * Add an item to the cache. Generates an id for the item and adds it to the cache based on that * id. */ - public int cacheData(Object item) { + public int cacheData(@NonNull Object item) { int id = nextId(); mDataIntMap.put(item, id); mIntDataMap.put(id, item); @@ -105,7 +105,7 @@ public class RemoteComposeState implements CollectionsAccess { * Add an item to the cache. Generates an id for the item and adds it to the cache based on that * id. */ - public int cacheData(Object item, int type) { + public int cacheData(@NonNull Object item, int type) { int id = nextId(type); mDataIntMap.put(item, id); mIntDataMap.put(id, item); @@ -113,13 +113,13 @@ public class RemoteComposeState implements CollectionsAccess { } /** Insert an item in the cache */ - public void cacheData(int id, Object item) { + public void cacheData(int id, @NonNull Object item) { mDataIntMap.put(item, id); mIntDataMap.put(id, item); } /** Insert an item in the cache */ - public void updateData(int id, Object item) { + public void updateData(int id, @NonNull Object item) { if (!mDataOverride[id]) { Object previous = mIntDataMap.get(id); if (previous != item) { @@ -137,7 +137,7 @@ public class RemoteComposeState implements CollectionsAccess { * @param id * @param item the new value */ - public void overrideData(int id, Object item) { + public void overrideData(int id, @NonNull Object item) { Object previous = mIntDataMap.get(id); if (previous != item) { mDataIntMap.remove(previous); @@ -379,7 +379,7 @@ public class RemoteComposeState implements CollectionsAccess { @NonNull IntMap> mVarListeners = new IntMap<>(); @NonNull ArrayList mAllVarListeners = new ArrayList<>(); - private void add(int id, VariableSupport variableSupport) { + private void add(int id, @NonNull VariableSupport variableSupport) { ArrayList v = mVarListeners.get(id); if (v == null) { v = new ArrayList(); @@ -395,17 +395,27 @@ public class RemoteComposeState implements CollectionsAccess { * @param id * @param variableSupport */ - public void listenToVar(int id, VariableSupport variableSupport) { + public void listenToVar(int id, @NonNull VariableSupport variableSupport) { add(id, variableSupport); } + /** + * Is any command listening to this variable + * + * @param id + * @return + */ + public boolean hasListener(int id) { + return mVarListeners.get(id) != null; + } + /** * List of Commands that need to be updated * * @param context * @return */ - public int getOpsToUpdate(RemoteContext context) { + public int getOpsToUpdate(@NonNull RemoteContext context) { for (VariableSupport vs : mAllVarListeners) { vs.updateVariables(context); } @@ -439,18 +449,18 @@ public class RemoteComposeState implements CollectionsAccess { updateFloat(RemoteContext.ID_WINDOW_HEIGHT, height); } - public void addCollection(int id, ArrayAccess collection) { + public void addCollection(int id, @NonNull ArrayAccess collection) { mCollectionMap.put(id & 0xFFFFF, collection); } @Override public float getFloatValue(int id, int index) { - return mCollectionMap.get(id & 0xFFFFF).getFloatValue(index); + return mCollectionMap.get(id & 0xFFFFF).getFloatValue(index); // TODO: potential npe } @Override - public float[] getFloats(int id) { - return mCollectionMap.get(id & 0xFFFFF).getFloats(); + public @Nullable float[] getFloats(int id) { + return mCollectionMap.get(id & 0xFFFFF).getFloats(); // TODO: potential npe } @Override @@ -458,11 +468,11 @@ public class RemoteComposeState implements CollectionsAccess { return mCollectionMap.get(id & 0xFFFFF).getId(index); } - public void putDataMap(int id, DataMap map) { + public void putDataMap(int id, @NonNull DataMap map) { mDataMapMap.put(id, map); } - public DataMap getDataMap(int id) { + public @Nullable DataMap getDataMap(int id) { return mDataMapMap.get(id); } @@ -471,15 +481,15 @@ public class RemoteComposeState implements CollectionsAccess { return mCollectionMap.get(id & 0xFFFFF).getLength(); } - public void setContext(RemoteContext context) { + public void setContext(@NonNull RemoteContext context) { mRemoteContext = context; } - public void updateObject(int id, Object value) { + public void updateObject(int id, @NonNull Object value) { mObjectMap.put(id, value); } - public Object getObject(int id) { + public @Nullable Object getObject(int id) { return mObjectMap.get(id); } } 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 23cc5b89d916b466ec849e9531ac38a27b3f0891..26305bf124f7f01bae3d42bd63a807085a90b92b 100644 --- a/core/java/com/android/internal/widget/remotecompose/core/RemoteContext.java +++ b/core/java/com/android/internal/widget/remotecompose/core/RemoteContext.java @@ -15,6 +15,7 @@ */ package com.android.internal.widget.remotecompose.core; +import android.annotation.NonNull; import android.annotation.Nullable; import com.android.internal.widget.remotecompose.core.operations.FloatExpression; @@ -39,13 +40,15 @@ import java.time.ZoneOffset; *

    We also contain a PaintContext, so that any operation can draw as needed. */ public abstract class RemoteContext { - protected CoreDocument mDocument; - public RemoteComposeState mRemoteComposeState; + protected @NonNull CoreDocument mDocument = + new CoreDocument(); // todo: is this a valid way to initialize? bbade@ + public @NonNull RemoteComposeState mRemoteComposeState = + new RemoteComposeState(); // todo, is this a valid use of RemoteComposeState -- bbade@ long mStart = System.nanoTime(); // todo This should be set at a hi level @Nullable protected PaintContext mPaintContext = null; protected float mDensity = 2.75f; - ContextMode mMode = ContextMode.UNSET; + @NonNull ContextMode mMode = ContextMode.UNSET; int mDebug = 0; @@ -57,7 +60,7 @@ public abstract class RemoteContext { private boolean mAnimate = true; - public Component lastComponent; + public @Nullable Component mLastComponent; public long currentTime = 0L; public float getDensity() { @@ -65,7 +68,9 @@ public abstract class RemoteContext { } public void setDensity(float density) { - mDensity = density; + if (density > 0) { + mDensity = density; + } } public boolean isAnimationEnabled() { @@ -81,7 +86,7 @@ public abstract class RemoteContext { * * @return the CollectionsAccess implementation */ - public CollectionsAccess getCollectionsAccess() { + public @Nullable CollectionsAccess getCollectionsAccess() { return mRemoteComposeState; } @@ -91,7 +96,7 @@ public abstract class RemoteContext { * @param instanceId * @param floatPath */ - public abstract void loadPathData(int instanceId, float[] floatPath); + public abstract void loadPathData(int instanceId, @NonNull float[] floatPath); /** * Associate a name with a give id. @@ -100,7 +105,7 @@ public abstract class RemoteContext { * @param varId the id (color,integer,float etc.) * @param varType thetype */ - public abstract void loadVariableName(String varName, int varId, int varType); + public abstract void loadVariableName(@NonNull String varName, int varId, int varType); /** * Save a color under a given id @@ -135,7 +140,7 @@ public abstract class RemoteContext { * @param colorName the name of the color to override * @param color Override the default color */ - public abstract void setNamedColorOverride(String colorName, int color); + public abstract void setNamedColorOverride(@NonNull String colorName, int color); /** * Set the value of a named String. This overrides the string in the document @@ -143,7 +148,7 @@ public abstract class RemoteContext { * @param stringName the name of the string to override * @param value Override the default string */ - public abstract void setNamedStringOverride(String stringName, String value); + public abstract void setNamedStringOverride(@NonNull String stringName, @NonNull String value); /** * Allows to clear a named String. @@ -152,7 +157,7 @@ public abstract class RemoteContext { * * @param stringName the name of the string to override */ - public abstract void clearNamedStringOverride(String stringName); + public abstract void clearNamedStringOverride(@NonNull String stringName); /** * Set the value of a named Integer. This overrides the integer in the document @@ -160,7 +165,7 @@ public abstract class RemoteContext { * @param integerName the name of the integer to override * @param value Override the default integer */ - public abstract void setNamedIntegerOverride(String integerName, int value); + public abstract void setNamedIntegerOverride(@NonNull String integerName, int value); /** * Allows to clear a named Integer. @@ -169,7 +174,7 @@ public abstract class RemoteContext { * * @param integerName the name of the integer to override */ - public abstract void clearNamedIntegerOverride(String integerName); + public abstract void clearNamedIntegerOverride(@NonNull String integerName); /** * Support Collections by registering this collection @@ -177,20 +182,20 @@ public abstract class RemoteContext { * @param id id of the collection * @param collection the collection under this id */ - public abstract void addCollection(int id, ArrayAccess collection); + public abstract void addCollection(int id, @NonNull ArrayAccess collection); - public abstract void putDataMap(int id, DataMap map); + public abstract void putDataMap(int id, @NonNull DataMap map); - public abstract DataMap getDataMap(int id); + public abstract @Nullable DataMap getDataMap(int id); - public abstract void runAction(int id, String metadata); + public abstract void runAction(int id, @NonNull String metadata); // TODO: we might add an interface to group all valid parameter types public abstract void runNamedAction(int textId, Object value); - public abstract void putObject(int mId, Object command); + public abstract void putObject(int mId, @NonNull Object command); - public abstract Object getObject(int mId); + public abstract @Nullable Object getObject(int mId); public void addTouchListener(TouchListener touchExpression) {} @@ -220,11 +225,11 @@ public abstract class RemoteContext { this.mTheme = theme; } - public ContextMode getMode() { + public @NonNull ContextMode getMode() { return mMode; } - public void setMode(ContextMode mode) { + public void setMode(@NonNull ContextMode mode) { this.mMode = mode; } @@ -233,11 +238,11 @@ public abstract class RemoteContext { return mPaintContext; } - public void setPaintContext(PaintContext paintContext) { + public void setPaintContext(@NonNull PaintContext paintContext) { this.mPaintContext = paintContext; } - public CoreDocument getDocument() { + public @Nullable CoreDocument getDocument() { return mDocument; } @@ -253,7 +258,7 @@ public abstract class RemoteContext { this.mDebug = debug; } - public void setDocument(CoreDocument document) { + public void setDocument(@NonNull CoreDocument document) { this.mDocument = document; } @@ -310,11 +315,14 @@ public abstract class RemoteContext { * Save a bitmap under an imageId * * @param imageId the id of the image + * @param encoding how the data is encoded 0 = png, 1 = raw, 2 = url + * @param type the type of the data 0 = RGBA 8888, 1 = 888, 2 = 8 gray * @param width the width of the image * @param height the height of the image * @param bitmap the bytes that represent the image */ - public abstract void loadBitmap(int imageId, int width, int height, byte[] bitmap); + public abstract void loadBitmap( + int imageId, short encoding, short type, int width, int height, @NonNull byte[] bitmap); /** * Save a string under a given id @@ -322,7 +330,7 @@ public abstract class RemoteContext { * @param id the id of the string * @param text the value to set */ - public abstract void loadText(int id, String text); + public abstract void loadText(int id, @NonNull String text); /** * Get a string given an id @@ -330,7 +338,7 @@ public abstract class RemoteContext { * @param id the id of the string * @return */ - public abstract String getText(int id); + public abstract @Nullable String getText(int id); /** * Load a float @@ -373,12 +381,12 @@ public abstract class RemoteContext { public abstract void overrideText(int id, int valueId); /** - * Load an animated float associated with an id Todo: Remove? + * Load an animated float associated with an id Todo: Remove? cc @hoford * * @param id the id of the float * @param animatedFloat The animated float */ - public abstract void loadAnimatedFloat(int id, FloatExpression animatedFloat); + public abstract void loadAnimatedFloat(int id, @NonNull FloatExpression animatedFloat); /** * Save a shader under and ID @@ -386,7 +394,7 @@ public abstract class RemoteContext { * @param id the id of the Shader * @param value the shader */ - public abstract void loadShader(int id, ShaderData value); + public abstract void loadShader(int id, @NonNull ShaderData value); /** * Get a float given an id @@ -418,7 +426,7 @@ public abstract class RemoteContext { * @param id track when this id changes value * @param variableSupport call back when value changes */ - public abstract void listensTo(int id, VariableSupport variableSupport); + public abstract void listensTo(int id, @NonNull VariableSupport variableSupport); /** * Notify commands with variables have changed @@ -433,6 +441,7 @@ public abstract class RemoteContext { * @param id get a shader given the id * @return The shader */ + @Nullable public abstract ShaderData getShader(int id); public static final int ID_CONTINUOUS_SEC = 1; @@ -467,6 +476,10 @@ public abstract class RemoteContext { public static final int ID_LIGHT = 26; + public static final int ID_DENSITY = 27; + + public static final float FLOAT_DENSITY = Utils.asNan(ID_DENSITY); + /** CONTINUOUS_SEC is seconds from midnight looping every hour 0-3600 */ public static final float FLOAT_CONTINUOUS_SEC = Utils.asNan(ID_CONTINUOUS_SEC); diff --git a/core/java/com/android/internal/widget/remotecompose/core/SerializableToString.java b/core/java/com/android/internal/widget/remotecompose/core/SerializableToString.java index 8f9741dd41955f0cce4dd033b9209d2645037eee..79ac789a454e08aeadbb634d857082773a66b76e 100644 --- a/core/java/com/android/internal/widget/remotecompose/core/SerializableToString.java +++ b/core/java/com/android/internal/widget/remotecompose/core/SerializableToString.java @@ -15,8 +15,10 @@ */ package com.android.internal.widget.remotecompose.core; +import android.annotation.NonNull; + import com.android.internal.widget.remotecompose.core.operations.utilities.StringSerializer; public interface SerializableToString { - void serializeToString(int indent, StringSerializer serializer); + void serializeToString(int indent, @NonNull StringSerializer serializer); } 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 51e58a1aeddd6ea9766757053aa12d4f143aee52..e9fa8976637e37f4be11dbe07a31632db19c8cc3 100644 --- a/core/java/com/android/internal/widget/remotecompose/core/VariableSupport.java +++ b/core/java/com/android/internal/widget/remotecompose/core/VariableSupport.java @@ -15,6 +15,8 @@ */ package com.android.internal.widget.remotecompose.core; +import android.annotation.NonNull; + /** * Interface for operators that interact with variables Through this they register to listen to * particular variables and are notified when they change @@ -26,12 +28,12 @@ public interface VariableSupport { * * @param context */ - void registerListening(RemoteContext context); + void registerListening(@NonNull RemoteContext context); /** * Called to be notified that the variables you are interested have changed. * * @param context */ - void updateVariables(RemoteContext context); + void updateVariables(@NonNull RemoteContext context); } diff --git a/core/java/com/android/internal/widget/remotecompose/core/WireBuffer.java b/core/java/com/android/internal/widget/remotecompose/core/WireBuffer.java index 738e42baae0b7da7f54ecd0d15feb058ebcee459..a64b706fea3bef35a67c026ea7fc72d71dcdec98 100644 --- a/core/java/com/android/internal/widget/remotecompose/core/WireBuffer.java +++ b/core/java/com/android/internal/widget/remotecompose/core/WireBuffer.java @@ -23,7 +23,7 @@ import java.util.Arrays; public class WireBuffer { private static final int BUFFER_SIZE = 1024 * 1024 * 1; int mMaxSize; - byte[] mBuffer; + @NonNull byte[] mBuffer; int mIndex = 0; int mStartingIndex = 0; int mSize = 0; @@ -44,7 +44,7 @@ public class WireBuffer { } } - public byte[] getBuffer() { + public @NonNull byte[] getBuffer() { return mBuffer; } @@ -168,14 +168,14 @@ public class WireBuffer { return java.lang.Double.longBitsToDouble(readLong()); } - public byte[] readBuffer() { + public @NonNull byte[] readBuffer() { int count = readInt(); byte[] b = Arrays.copyOfRange(mBuffer, mIndex, mIndex + count); mIndex += count; return b; } - public byte[] readBuffer(int maxSize) { + public @NonNull byte[] readBuffer(int maxSize) { int count = readInt(); if (count < 0 || count > maxSize) { throw new RuntimeException( diff --git a/core/java/com/android/internal/widget/remotecompose/core/documentation/DocumentationBuilder.java b/core/java/com/android/internal/widget/remotecompose/core/documentation/DocumentationBuilder.java index f6dfe2ebe1714bc0caf3e479021e547798d43fcb..0174ce531d3f847f30a2f34278bf94c992d247df 100644 --- a/core/java/com/android/internal/widget/remotecompose/core/documentation/DocumentationBuilder.java +++ b/core/java/com/android/internal/widget/remotecompose/core/documentation/DocumentationBuilder.java @@ -15,10 +15,14 @@ */ package com.android.internal.widget.remotecompose.core.documentation; +import android.annotation.NonNull; + public interface DocumentationBuilder { - void add(String value); + void add(@NonNull String value); - DocumentedOperation operation(String category, int id, String name); + @NonNull + DocumentedOperation operation(@NonNull String category, int id, @NonNull String name); - DocumentedOperation wipOperation(String category, int id, String name); + @NonNull + DocumentedOperation wipOperation(@NonNull String category, int id, @NonNull String name); } diff --git a/core/java/com/android/internal/widget/remotecompose/core/documentation/DocumentedCompanionOperation.java b/core/java/com/android/internal/widget/remotecompose/core/documentation/DocumentedCompanionOperation.java index 4b84291aa5feb4f42ebedb026dc724b826c7d914..2806a5e1ad1d12518dc9341b16bf49aae3beb364 100644 --- a/core/java/com/android/internal/widget/remotecompose/core/documentation/DocumentedCompanionOperation.java +++ b/core/java/com/android/internal/widget/remotecompose/core/documentation/DocumentedCompanionOperation.java @@ -15,6 +15,8 @@ */ package com.android.internal.widget.remotecompose.core.documentation; +import android.annotation.NonNull; + public interface DocumentedCompanionOperation { - void documentation(DocumentationBuilder doc); + void documentation(@NonNull DocumentationBuilder doc); } diff --git a/core/java/com/android/internal/widget/remotecompose/core/documentation/DocumentedOperation.java b/core/java/com/android/internal/widget/remotecompose/core/documentation/DocumentedOperation.java index 5edecaa01f823e5b615ec88149a79ae001e0cb18..bfab62365736dfa9cc651eb4eab611df9d56d8df 100644 --- a/core/java/com/android/internal/widget/remotecompose/core/documentation/DocumentedOperation.java +++ b/core/java/com/android/internal/widget/remotecompose/core/documentation/DocumentedOperation.java @@ -16,6 +16,7 @@ package com.android.internal.widget.remotecompose.core.documentation; import android.annotation.NonNull; +import android.annotation.Nullable; import java.util.ArrayList; @@ -34,13 +35,13 @@ public class DocumentedOperation { public static final int FLOAT_ARRAY = 10; public static final int INT_ARRAY = 11; - String mCategory; + @NonNull final String mCategory; int mId; - String mName; - String mDescription; + @NonNull final String mName; + @NonNull String mDescription = ""; boolean mWIP; - String mTextExamples; + @Nullable String mTextExamples; @NonNull ArrayList mExamples = new ArrayList<>(); @NonNull ArrayList mFields = new ArrayList<>(); @@ -77,14 +78,15 @@ public class DocumentedOperation { return "UNKNOWN"; } - public DocumentedOperation(String category, int id, String name, boolean wip) { + public DocumentedOperation( + @NonNull String category, int id, @NonNull String name, boolean wip) { mCategory = category; mId = id; mName = name; mWIP = wip; } - public DocumentedOperation(String category, int id, String name) { + public DocumentedOperation(@NonNull String category, int id, @NonNull String name) { this(category, id, name, false); } @@ -93,7 +95,7 @@ public class DocumentedOperation { return mFields; } - public String getCategory() { + public @NonNull String getCategory() { return mCategory; } @@ -101,6 +103,7 @@ public class DocumentedOperation { return mId; } + @NonNull public String getName() { return mName; } @@ -126,10 +129,12 @@ public class DocumentedOperation { return size; } + @Nullable public String getDescription() { return mDescription; } + @Nullable public String getTextExamples() { return mTextExamples; } @@ -148,19 +153,20 @@ public class DocumentedOperation { } @NonNull - public DocumentedOperation field(int type, String name, String description) { + public DocumentedOperation field(int type, @NonNull String name, @NonNull String description) { mFields.add(new OperationField(type, name, description)); return this; } @NonNull - public DocumentedOperation field(int type, String name, String varSize, String description) { + public DocumentedOperation field( + int type, @NonNull String name, @NonNull String varSize, @NonNull String description) { mFields.add(new OperationField(type, name, varSize, description)); return this; } @NonNull - public DocumentedOperation possibleValues(String name, int value) { + public DocumentedOperation possibleValues(@NonNull String name, int value) { if (!mFields.isEmpty()) { mFields.get(mFields.size() - 1).possibleValue(name, "" + value); } @@ -168,19 +174,19 @@ public class DocumentedOperation { } @NonNull - public DocumentedOperation description(String description) { + public DocumentedOperation description(@NonNull String description) { mDescription = description; return this; } @NonNull - public DocumentedOperation examples(String examples) { + public DocumentedOperation examples(@NonNull String examples) { mTextExamples = examples; return this; } @NonNull - public DocumentedOperation exampleImage(String name, String imagePath) { + public DocumentedOperation exampleImage(@NonNull String name, @NonNull String imagePath) { mExamples.add(new StringPair(name, imagePath)); return this; } diff --git a/core/java/com/android/internal/widget/remotecompose/core/documentation/OperationField.java b/core/java/com/android/internal/widget/remotecompose/core/documentation/OperationField.java index cbb5ca9821c35db5b6b564d689a4b8d5fc694fc7..9febcfe57047690167040ba440b69b819f9c3321 100644 --- a/core/java/com/android/internal/widget/remotecompose/core/documentation/OperationField.java +++ b/core/java/com/android/internal/widget/remotecompose/core/documentation/OperationField.java @@ -21,20 +21,21 @@ import android.annotation.Nullable; import java.util.ArrayList; public class OperationField { - int mType; - String mName; - String mDescription; + final int mType; + @NonNull final String mName; + @NonNull final String mDescription; @Nullable String mVarSize = null; @NonNull ArrayList mPossibleValues = new ArrayList<>(); - public OperationField(int type, String name, String description) { + public OperationField(int type, @NonNull String name, @NonNull String description) { mType = type; mName = name; mDescription = description; } - public OperationField(int type, String name, String varSize, String description) { + public OperationField( + int type, @NonNull String name, @Nullable String varSize, @NonNull String description) { mType = type; mName = name; mDescription = description; @@ -45,10 +46,12 @@ public class OperationField { return mType; } + @NonNull public String getName() { return mName; } + @NonNull public String getDescription() { return mDescription; } @@ -58,7 +61,7 @@ public class OperationField { return mPossibleValues; } - public void possibleValue(String name, String value) { + public void possibleValue(@NonNull String name, @NonNull String value) { mPossibleValues.add(new StringPair(name, value)); } diff --git a/core/java/com/android/internal/widget/remotecompose/core/documentation/StringPair.java b/core/java/com/android/internal/widget/remotecompose/core/documentation/StringPair.java index 5b0cedbaf6af86447b8112655180d2f467c1997d..c1d885806b44e30fee5dd8cf4db458a8ab7533ba 100644 --- a/core/java/com/android/internal/widget/remotecompose/core/documentation/StringPair.java +++ b/core/java/com/android/internal/widget/remotecompose/core/documentation/StringPair.java @@ -15,20 +15,22 @@ */ package com.android.internal.widget.remotecompose.core.documentation; +import android.annotation.NonNull; + public class StringPair { - String mName; - String mValue; + final @NonNull String mName; + final @NonNull String mValue; - StringPair(String name, String value) { + StringPair(@NonNull String name, @NonNull String value) { mName = name; mValue = value; } - public String getName() { + public @NonNull String getName() { return mName; } - public String getValue() { + public @NonNull String getValue() { return mValue; } } 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 8da0e184cbe787c557c79631b6bfed3d64bf41d6..948007699b80804eab84f65a5109b238b43df1b7 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 @@ -17,6 +17,7 @@ package com.android.internal.widget.remotecompose.core.operations; import static com.android.internal.widget.remotecompose.core.documentation.DocumentedOperation.INT; import static com.android.internal.widget.remotecompose.core.documentation.DocumentedOperation.INT_ARRAY; +import static com.android.internal.widget.remotecompose.core.documentation.DocumentedOperation.SHORT; import android.annotation.NonNull; @@ -41,10 +42,19 @@ public class BitmapData implements Operation, SerializableToString { int mImageId; int mImageWidth; int mImageHeight; - byte[] mBitmap; + short mType; + short mEncoding; + @NonNull final byte[] mBitmap; public static final int MAX_IMAGE_DIMENSION = 8000; - - public BitmapData(int imageId, int width, int height, byte[] bitmap) { + public static final short ENCODING_INLINE = 0; + public static final short ENCODING_URL = 1; + public static final short ENCODING_FILE = 2; + public static final short TYPE_PNG_8888 = 0; + public static final short TYPE_PNG = 1; + public static final short TYPE_RAW8 = 2; + public static final short TYPE_RAW8888 = 3; + + public BitmapData(int imageId, int width, int height, @NonNull byte[] bitmap) { this.mImageId = imageId; this.mImageWidth = width; this.mImageHeight = height; @@ -92,6 +102,23 @@ public class BitmapData implements Operation, SerializableToString { buffer.writeBuffer(bitmap); } + public static void apply( + @NonNull WireBuffer buffer, + int imageId, + short type, + short width, + short encoding, + short height, + @NonNull byte[] bitmap) { + buffer.start(OP_CODE); + buffer.writeInt(imageId); + int w = (((int) type) << 16) | width; + int h = (((int) encoding) << 16) | height; + buffer.writeInt(w); + buffer.writeInt(h); + buffer.writeBuffer(bitmap); + } + public static void read(@NonNull WireBuffer buffer, @NonNull List operations) { int imageId = buffer.readInt(); int width = buffer.readInt(); @@ -110,19 +137,22 @@ public class BitmapData implements Operation, SerializableToString { doc.operation("Data Operations", OP_CODE, CLASS_NAME) .description("Bitmap data") .field(DocumentedOperation.INT, "id", "id of bitmap data") + .field(SHORT, "type", "width of the image") + .field(SHORT, "width", "width of the image") + .field(SHORT, "encoding", "height of the image") .field(INT, "width", "width of the image") - .field(INT, "height", "height of the image") + .field(SHORT, "height", "height of the image") .field(INT_ARRAY, "values", "length", "Array of ints"); } @Override public void apply(@NonNull RemoteContext context) { - context.loadBitmap(mImageId, mImageWidth, mImageHeight, mBitmap); + context.loadBitmap(mImageId, mEncoding, mType, mImageWidth, mImageHeight, mBitmap); } @NonNull @Override - public String deepToString(String indent) { + public String deepToString(@NonNull String indent) { return indent + toString(); } 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 83d0ac7a1eb2b9f1d2e174b6b05b36249846bce4..310b194ec4860b6943ed40f140d96e4ec88887ac 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 @@ -109,7 +109,7 @@ public class ClickArea implements RemoteComposeOperation { @NonNull @Override - public String deepToString(String indent) { + public String deepToString(@NonNull String indent) { return indent + toString(); } 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 929c9a603079996b7ebba4f602c6d492c25f0dbe..34e93f590dbe30fe52c1e40cc81f49937526f16d 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 @@ -93,7 +93,7 @@ public class ColorConstant implements Operation { @NonNull @Override - public String deepToString(String indent) { + public String deepToString(@NonNull String indent) { return indent + toString(); } } 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 3d840c5b82039a2208fd8da7e58e2622430548da..c947d1139a2ebe9b48a7bf50200010dcc1bf7eb4 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 @@ -255,7 +255,7 @@ public class ColorExpression implements Operation, VariableSupport { @NonNull @Override - public String deepToString(String indent) { + public String deepToString(@NonNull String indent) { return indent + toString(); } } 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 142c97b24d2e531dc9a4a5488c05970271b46c4d..b0ccd1871fd2197a1de8d6438eab65c885bc0625 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 @@ -18,7 +18,6 @@ package com.android.internal.widget.remotecompose.core.operations; import static com.android.internal.widget.remotecompose.core.documentation.DocumentedOperation.INT; import android.annotation.NonNull; -import android.annotation.Nullable; import com.android.internal.widget.remotecompose.core.Operation; import com.android.internal.widget.remotecompose.core.Operations; @@ -75,7 +74,7 @@ public class ComponentValue implements Operation, SerializableToString { } @Override - public void apply(RemoteContext context) { + public void apply(@NonNull RemoteContext context) { // Nothing } @@ -123,9 +122,9 @@ public class ComponentValue implements Operation, SerializableToString { buffer.writeInt(valueId); } - @Nullable + @NonNull @Override - public String deepToString(String indent) { + public String deepToString(@NonNull String indent) { return null; } diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/DataListFloat.java b/core/java/com/android/internal/widget/remotecompose/core/operations/DataListFloat.java index ba02b91b36eda72c0aab9a0e7e6dd6eddd75be5e..bfaf139da21baa5b24d999e5d3cb98b66c98e2cb 100644 --- a/core/java/com/android/internal/widget/remotecompose/core/operations/DataListFloat.java +++ b/core/java/com/android/internal/widget/remotecompose/core/operations/DataListFloat.java @@ -35,17 +35,17 @@ import java.util.List; public class DataListFloat implements VariableSupport, ArrayAccess, Operation { private static final int OP_CODE = Operations.FLOAT_LIST; private static final String CLASS_NAME = "IdListData"; - int mId; - float[] mValues; + private final int mId; + @NonNull private final float[] mValues; private static final int MAX_FLOAT_ARRAY = 2000; - public DataListFloat(int id, float[] values) { + public DataListFloat(int id, @NonNull float[] values) { mId = id; mValues = values; } @Override - public void updateVariables(RemoteContext context) { + public void updateVariables(@NonNull RemoteContext context) { // TODO add support for variables in arrays } @@ -103,7 +103,7 @@ public class DataListFloat implements VariableSupport, ArrayAccess, Operation { @NonNull @Override - public String deepToString(String indent) { + public String deepToString(@NonNull String indent) { return indent + toString(); } @@ -117,6 +117,7 @@ public class DataListFloat implements VariableSupport, ArrayAccess, Operation { return mValues[index]; } + @NonNull @Override public float[] getFloats() { return mValues; diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/DataListIds.java b/core/java/com/android/internal/widget/remotecompose/core/operations/DataListIds.java index b9820f856a92bf93a926f5f31cde04bb973a94cf..9b286b94d553ec6a755254143bb00634767b1aae 100644 --- a/core/java/com/android/internal/widget/remotecompose/core/operations/DataListIds.java +++ b/core/java/com/android/internal/widget/remotecompose/core/operations/DataListIds.java @@ -19,6 +19,7 @@ import static com.android.internal.widget.remotecompose.core.documentation.Docum import static com.android.internal.widget.remotecompose.core.documentation.DocumentedOperation.INT_ARRAY; import android.annotation.NonNull; +import android.annotation.Nullable; import com.android.internal.widget.remotecompose.core.Operation; import com.android.internal.widget.remotecompose.core.Operations; @@ -35,20 +36,20 @@ import java.util.List; public class DataListIds implements VariableSupport, ArrayAccess, Operation { private static final int OP_CODE = Operations.ID_LIST; private static final String CLASS_NAME = "IdListData"; - int mId; - int[] mIds; + private final int mId; + @NonNull private final int[] mIds; private static final int MAX_LIST = 2000; - public DataListIds(int id, int[] ids) { + public DataListIds(int id, @NonNull int[] ids) { mId = id; mIds = ids; } @Override - public void updateVariables(RemoteContext context) {} + public void updateVariables(@NonNull RemoteContext context) {} @Override - public void registerListening(RemoteContext context) {} + public void registerListening(@NonNull RemoteContext context) {} @Override public void write(@NonNull WireBuffer buffer) { @@ -94,7 +95,7 @@ public class DataListIds implements VariableSupport, ArrayAccess, Operation { @NonNull @Override - public String deepToString(String indent) { + public String deepToString(@NonNull String indent) { return indent + toString(); } @@ -113,6 +114,7 @@ public class DataListIds implements VariableSupport, ArrayAccess, Operation { return mIds[index]; } + @Nullable @Override public float[] getFloats() { return null; 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 fb559bbf18635754f494a3ac01d276bf587a4629..643afc85e69f5bc4e66ee9c121897307c5ca6b2c 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 @@ -19,6 +19,7 @@ import static com.android.internal.widget.remotecompose.core.documentation.Docum import static com.android.internal.widget.remotecompose.core.documentation.DocumentedOperation.UTF8; import android.annotation.NonNull; +import android.annotation.Nullable; import com.android.internal.widget.remotecompose.core.Operation; import com.android.internal.widget.remotecompose.core.Operations; @@ -34,7 +35,7 @@ public class DataMapIds implements Operation { private static final int OP_CODE = Operations.ID_MAP; private static final String CLASS_NAME = "DataMapIds"; int mId; - DataMap mDataMap; + final DataMap mDataMap; private static final int MAX_MAP = 2000; @@ -44,6 +45,7 @@ public class DataMapIds implements Operation { public static final byte TYPE_LONG = 3; public static final byte TYPE_BOOLEAN = 4; + @NonNull private String typeString(byte type) { switch (type) { case TYPE_STRING: @@ -60,7 +62,7 @@ public class DataMapIds implements Operation { return "?"; } - public DataMapIds(int id, String[] names, byte[] types, int[] ids) { + public DataMapIds(int id, @NonNull String[] names, @NonNull byte[] types, @NonNull int[] ids) { mId = id; mDataMap = new DataMap(names, types, ids); } @@ -88,7 +90,11 @@ public class DataMapIds implements Operation { } public static void apply( - @NonNull WireBuffer buffer, int id, @NonNull String[] names, byte[] type, int[] ids) { + @NonNull WireBuffer buffer, + int id, + @NonNull String[] names, + @Nullable byte[] type, // todo: can we make this not nullable? + @NonNull int[] ids) { buffer.start(OP_CODE); buffer.writeInt(id); buffer.writeInt(names.length); @@ -128,7 +134,7 @@ public class DataMapIds implements Operation { @NonNull @Override - public String deepToString(String indent) { + public String deepToString(@NonNull String indent) { return indent + toString(); } diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/DataMapLookup.java b/core/java/com/android/internal/widget/remotecompose/core/operations/DataMapLookup.java index fb5e5d1734e6329c1fe00f7229ea2b5da7646a12..eae532c1434417971816739d4ca88d9974c15dad 100644 --- a/core/java/com/android/internal/widget/remotecompose/core/operations/DataMapLookup.java +++ b/core/java/com/android/internal/widget/remotecompose/core/operations/DataMapLookup.java @@ -17,6 +17,8 @@ package com.android.internal.widget.remotecompose.core.operations; import static com.android.internal.widget.remotecompose.core.documentation.DocumentedOperation.INT; +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.RemoteContext; @@ -50,10 +52,11 @@ public class DataMapLookup implements Operation { } @Override - public void write(WireBuffer buffer) { + public void write(@NonNull WireBuffer buffer) { apply(buffer, mId, mDataMapId, mStringId); } + @NonNull @Override public String toString() { return "DataMapLookup[" + mId + "] = " + Utils.idString(mDataMapId) + " " + mStringId; @@ -64,6 +67,7 @@ public class DataMapLookup implements Operation { * * @return the name of the class */ + @NonNull public static String name() { return CLASS_NAME; } @@ -85,7 +89,7 @@ public class DataMapLookup implements Operation { * @param dataMapId the map to extract from * @param keyStringId the map to extract from */ - public static void apply(WireBuffer buffer, int id, int dataMapId, int keyStringId) { + public static void apply(@NonNull WireBuffer buffer, int id, int dataMapId, int keyStringId) { buffer.start(OP_CODE); buffer.writeInt(id); buffer.writeInt(dataMapId); @@ -98,14 +102,14 @@ public class DataMapLookup implements Operation { * @param buffer buffer * @param operations the created command is added to the list */ - public static void read(WireBuffer buffer, List operations) { + public static void read(@NonNull WireBuffer buffer, @NonNull List operations) { int id = buffer.readInt(); int mapId = buffer.readInt(); int stringId = buffer.readInt(); operations.add(new DataMapLookup(id, mapId, stringId)); } - public static void documentation(DocumentationBuilder doc) { + public static void documentation(@NonNull DocumentationBuilder doc) { doc.operation("Expressions Operations", OP_CODE, CLASS_NAME) .description("A float and its associated id") .field(INT, "id", "id of float") @@ -114,7 +118,7 @@ public class DataMapLookup implements Operation { } @Override - public void apply(RemoteContext context) { + public void apply(@NonNull RemoteContext context) { String str = context.getText(mStringId); DataMap data = context.getDataMap(mDataMapId); int pos = data.getPos(str); @@ -141,8 +145,9 @@ public class DataMapLookup implements Operation { } } + @NonNull @Override - public String deepToString(String indent) { + public String deepToString(@NonNull String indent) { return indent + toString(); } } diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/DrawBase2.java b/core/java/com/android/internal/widget/remotecompose/core/operations/DrawBase2.java index 984599e09c1944d0cafe5883efd8e4d5919524bf..c1e2e662ca80fab706d8db9a8ccb07b8eecf0428 100644 --- a/core/java/com/android/internal/widget/remotecompose/core/operations/DrawBase2.java +++ b/core/java/com/android/internal/widget/remotecompose/core/operations/DrawBase2.java @@ -60,11 +60,11 @@ public abstract class DrawBase2 extends PaintOperation implements VariableSuppor } @Override - public void write(WireBuffer buffer) { + public void write(@NonNull WireBuffer buffer) { write(buffer, mV1, mV2); } - protected abstract void write(WireBuffer buffer, float v1, float v2); + protected abstract void write(@NonNull WireBuffer buffer, float v1, float v2); protected interface Maker { DrawBase2 create(float v1, float v2); diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/DrawBase3.java b/core/java/com/android/internal/widget/remotecompose/core/operations/DrawBase3.java index 825da52400324fd9bd3bf06894851396953327f7..6fedea3245a2bfea189e1d5f64e1f97b2c873fcc 100644 --- a/core/java/com/android/internal/widget/remotecompose/core/operations/DrawBase3.java +++ b/core/java/com/android/internal/widget/remotecompose/core/operations/DrawBase3.java @@ -70,11 +70,11 @@ public abstract class DrawBase3 extends PaintOperation implements VariableSuppor } @Override - public void write(WireBuffer buffer) { + public void write(@NonNull WireBuffer buffer) { write(buffer, mV1, mV2, mV3); } - protected abstract void write(WireBuffer buffer, float v1, float v2, float v3); + protected abstract void write(@NonNull WireBuffer buffer, float v1, float v2, float v3); interface Maker { DrawBase3 create(float v1, float v2, float v3); diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/DrawBase4.java b/core/java/com/android/internal/widget/remotecompose/core/operations/DrawBase4.java index a23bcb9dca78392c75e488f11b1e022e945162cf..aa9cc68e6552c78111ca8427ecec36bced587504 100644 --- a/core/java/com/android/internal/widget/remotecompose/core/operations/DrawBase4.java +++ b/core/java/com/android/internal/widget/remotecompose/core/operations/DrawBase4.java @@ -77,11 +77,12 @@ public abstract class DrawBase4 extends PaintOperation implements VariableSuppor } @Override - public void write(WireBuffer buffer) { + public void write(@NonNull WireBuffer buffer) { write(buffer, mX1, mY1, mX2, mY2); } - protected abstract void write(WireBuffer buffer, float v1, float v2, float v3, float v4); + protected abstract void write( + @NonNull WireBuffer buffer, float v1, float v2, float v3, float v4); protected interface Maker { DrawBase4 create(float v1, float v2, float v3, float v4); 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 68c9f8cdc462514e87f0338191ecb471328365f3..6c288a35621db3da57ba394d0a7d9bbbbfeec69f 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 @@ -91,12 +91,12 @@ public abstract class DrawBase6 extends PaintOperation implements VariableSuppor } @Override - public void write(WireBuffer buffer) { + public void write(@NonNull WireBuffer buffer) { write(buffer, mV1, mV2, mV3, mV4, mV5, mV6); } protected abstract void write( - WireBuffer buffer, float v1, float v2, float v3, float v4, float v5, float v6); + @NonNull WireBuffer buffer, float v1, float v2, float v3, float v4, float v5, float v6); @NonNull @Override 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 e20bcd2d79b56e38f30df0a9fc4cd5280b52193c..e9f81d52d67fa5bb246fa07da5100910e7d37414 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 @@ -46,6 +46,7 @@ public class DrawBitmapScaled extends PaintOperation implements VariableSupport int mContentDescId; float mScaleFactor, mOutScaleFactor; int mScaleType; + int mMode; @NonNull ImageScaling mScaling = new ImageScaling(); public static final int SCALE_NONE = ImageScaling.SCALE_NONE; @@ -79,7 +80,8 @@ public class DrawBitmapScaled extends PaintOperation implements VariableSupport mOutDstTop = mDstTop = dstTop; mOutDstRight = mDstRight = dstRight; mOutDstBottom = mDstBottom = dstBottom; - mScaleType = type; + mScaleType = type & 0xFF; + mMode = type >> 8; mOutScaleFactor = mScaleFactor = scale; this.mContentDescId = cdId; } @@ -308,8 +310,14 @@ public class DrawBitmapScaled extends PaintOperation implements VariableSupport mOutScaleFactor); context.save(); context.clipRect(mOutDstLeft, mOutDstTop, mOutDstRight, mOutDstBottom); + + int imageId = mImageId; + if ((mMode & 0x1) != 0) { + imageId = context.getContext().getInteger(imageId); + } + context.drawBitmap( - mImageId, + imageId, (int) mOutSrcLeft, (int) mOutSrcTop, (int) mOutSrcRight, 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 89390acb8c507fdbf505e01b4442633dac9545b0..17aaf3bb9cd8cc8d247fc32baac6dff8f229293f 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 @@ -94,7 +94,7 @@ public class FloatConstant implements com.android.internal.widget.remotecompose. @NonNull @Override - public String deepToString(String indent) { + public String deepToString(@NonNull String indent) { return indent + toString(); } } 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 e1c6c257786060de998ac37588d91298aa966d45..eef9746ffaf698be0720d130b0d8b3789ee89777 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 @@ -33,6 +33,7 @@ import com.android.internal.widget.remotecompose.core.documentation.DocumentedOp 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.easing.FloatAnimation; +import com.android.internal.widget.remotecompose.core.operations.utilities.easing.SpringStopEngine; import java.util.List; @@ -45,21 +46,26 @@ public class FloatExpression implements Operation, VariableSupport { private static final int OP_CODE = Operations.ANIMATED_FLOAT; private static final String CLASS_NAME = "FloatExpression"; public int mId; - public float[] mSrcValue; - public float[] mSrcAnimation; - public FloatAnimation mFloatAnimation; - public float[] mPreCalcValue; + @NonNull public float[] mSrcValue; + @Nullable public float[] mSrcAnimation; + @Nullable public FloatAnimation mFloatAnimation; + @Nullable private SpringStopEngine mSpring; + @Nullable public float[] mPreCalcValue; private float mLastChange = Float.NaN; private float mLastCalculatedValue = Float.NaN; @NonNull AnimatedFloatExpression mExp = new AnimatedFloatExpression(); public static final int MAX_EXPRESSION_SIZE = 32; - public FloatExpression(int id, float[] value, float[] animation) { + public FloatExpression(int id, @NonNull float[] value, @Nullable float[] animation) { this.mId = id; this.mSrcValue = value; this.mSrcAnimation = animation; if (mSrcAnimation != null) { - mFloatAnimation = new FloatAnimation(mSrcAnimation); + if (mSrcAnimation.length > 4 && mSrcAnimation[0] == 0) { + mSpring = new SpringStopEngine(mSrcAnimation); + } else { + mFloatAnimation = new FloatAnimation(mSrcAnimation); + } } } @@ -75,12 +81,23 @@ public class FloatExpression implements Operation, VariableSupport { if (Float.isNaN(v) && !AnimatedFloatExpression.isMathOperator(v) && !NanMap.isDataVariable(v)) { + int id = Utils.idFromNan(v); float newValue = context.getFloat(Utils.idFromNan(v)); + + // TODO: rethink the lifecycle for variable updates + if (id == RemoteContext.ID_DENSITY && newValue == 0f) { + newValue = 1f; + } if (mFloatAnimation != null) { if (mPreCalcValue[i] != newValue) { value_changed = true; mPreCalcValue[i] = newValue; } + } else if (mSpring != null) { + if (mPreCalcValue[i] != newValue) { + value_changed = true; + mPreCalcValue[i] = newValue; + } } else { mPreCalcValue[i] = newValue; } @@ -106,6 +123,8 @@ public class FloatExpression implements Operation, VariableSupport { mFloatAnimation.setInitialValue(mFloatAnimation.getTargetValue()); } mFloatAnimation.setTargetValue(v); + } else if (value_changed && mSpring != null) { + mSpring.setTargetValue(v); } } @@ -130,6 +149,9 @@ public class FloatExpression implements Operation, VariableSupport { if (mFloatAnimation != null) { float f = mFloatAnimation.get(t - mLastChange); context.loadFloat(mId, f); + } else if (mSpring != null) { + float f = mSpring.get(t - mLastChange); + context.loadFloat(mId, f); } else { context.loadFloat( mId, @@ -137,6 +159,21 @@ public class FloatExpression implements Operation, VariableSupport { } } + /** + * Evaluate the expression + * + * @param context current context + * @return the resulting value + */ + public float evaluate(@NonNull RemoteContext context) { + updateVariables(context); + float t = context.getAnimationTime(); + if (Float.isNaN(mLastChange)) { + mLastChange = t; + } + return mExp.eval(context.getCollectionsAccess(), mPreCalcValue, mPreCalcValue.length); + } + @Override public void write(@NonNull WireBuffer buffer) { apply(buffer, mId, mSrcValue, mSrcAnimation); @@ -256,7 +293,7 @@ public class FloatExpression implements Operation, VariableSupport { @NonNull @Override - public String deepToString(String indent) { + public String deepToString(@NonNull String indent) { return indent + toString(); } } 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 1979bc5f4331eb086fdcc041a4acadf95b4d2f48..009aa0339625e697480f07e6f0862ef7de94991e 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 @@ -111,7 +111,7 @@ public class Header implements RemoteComposeOperation { @NonNull @Override - public String deepToString(String indent) { + public String deepToString(@NonNull String indent) { return toString(); } 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 6375f001c81823b868f5fd2259f56b9477ad0fea..c49f74de789335cfbc75a8fb6ba09723bf859b35 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 @@ -19,6 +19,7 @@ import static com.android.internal.widget.remotecompose.core.documentation.Docum import static com.android.internal.widget.remotecompose.core.documentation.DocumentedOperation.INT_ARRAY; import android.annotation.NonNull; +import android.annotation.Nullable; import com.android.internal.widget.remotecompose.core.Operation; import com.android.internal.widget.remotecompose.core.Operations; @@ -43,13 +44,13 @@ public class IntegerExpression implements Operation, VariableSupport { public int mId; private int mMask; private int mPreMask; - public int[] mSrcValue; - public int[] mPreCalcValue; + @NonNull public final int[] mSrcValue; + @Nullable public int[] mPreCalcValue; private float mLastChange = Float.NaN; public static final int MAX_SIZE = 320; @NonNull IntegerExpressionEvaluator mExp = new IntegerExpressionEvaluator(); - public IntegerExpression(int id, int mask, int[] value) { + public IntegerExpression(int id, int mask, @NonNull int[] value) { this.mId = id; this.mMask = mask; this.mSrcValue = value; @@ -188,7 +189,7 @@ public class IntegerExpression implements Operation, VariableSupport { @NonNull @Override - public String deepToString(String indent) { + public String deepToString(@NonNull String indent) { return indent + toString(); } 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 6a620e58570ae33ef77e46ac7f2a7b2384cac41b..4e7ee4d135ee2e33c0b77fce167cbcc0d36db5fd 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 @@ -37,7 +37,7 @@ public class MatrixRestore extends PaintOperation { apply(buffer); } - public static void read(WireBuffer buffer, @NonNull List operations) { + public static void read(@NonNull WireBuffer buffer, @NonNull List operations) { MatrixRestore op = new MatrixRestore(); operations.add(op); } 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 1880b19be1a79ded053c4c1eae324fd1ba002b67..09f54a52e6a3c4bfe5090182a521657d915a2d8c 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 @@ -41,7 +41,7 @@ public class MatrixSave extends PaintOperation { return "MatrixSave;"; } - public static void read(WireBuffer buffer, @NonNull List operations) { + public static void read(@NonNull WireBuffer buffer, @NonNull List operations) { MatrixSave op = new MatrixSave(); operations.add(op); } 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 6310521e40108ed1f4c20f08344d30b7238bc37f..5ca91af91f8649f98d28403a5daedd1d0514f7db 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 @@ -33,16 +33,16 @@ import java.util.List; public class NamedVariable implements Operation { private static final int OP_CODE = Operations.NAMED_VARIABLE; private static final String CLASS_NAME = "NamedVariable"; - public int mVarId; - public String mVarName; - public int mVarType; + public final int mVarId; + public final @NonNull String mVarName; + public final int mVarType; public static final int MAX_STRING_SIZE = 4000; public static final int COLOR_TYPE = 2; public static final int FLOAT_TYPE = 1; public static final int STRING_TYPE = 0; public static final int IMAGE_TYPE = 3; - public NamedVariable(int varId, int varType, String name) { + public NamedVariable(int varId, int varType, @NonNull String name) { this.mVarId = varId; this.mVarType = varType; this.mVarName = name; @@ -111,7 +111,7 @@ public class NamedVariable implements Operation { @NonNull @Override - public String deepToString(String indent) { + public String deepToString(@NonNull String indent) { return indent + toString(); } } 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 527d5610788c4927562e3601fccb3d8ad284fb95..b24df8a6a91eb7e08ed03f178e03ff6d5962d8ba 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 @@ -90,7 +90,7 @@ public class PaintData extends PaintOperation implements VariableSupport { @NonNull @Override - public String deepToString(String indent) { + public String deepToString(@NonNull String indent) { return indent + toString(); } 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 06a1fec361964634868e38146454474161afeecd..509f362c02ed54aa4861f7e1571ca3390d636258 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 @@ -73,7 +73,7 @@ public class PathData implements Operation, VariableSupport { @NonNull @Override - public String deepToString(String indent) { + public String deepToString(@NonNull String indent) { return pathString(mFloatPath); } 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 6ff9ad73e35f27e9694e814e10b8ac3f37b0468a..849412618c2ccbe587d6e7a51c9b5376d483dba3 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 @@ -196,7 +196,7 @@ public class RootContentBehavior implements RemoteComposeOperation { @NonNull @Override - public String deepToString(String indent) { + public String deepToString(@NonNull String indent) { return toString(); } 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 c2d62a7b3ac446127885fca84fa9752b77e8c1c0..109945f21ec5263fd503826d624a496df93ddaaa 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 @@ -60,7 +60,7 @@ public class RootContentDescription implements RemoteComposeOperation { @NonNull @Override - public String deepToString(String indent) { + public String deepToString(@NonNull String indent) { return toString(); } 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 ae61c3aa01c953b476398d27861ad4519d697526..e967ff4f4ff4edfa9bbb08cb33f0e0f72befeb6a 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 @@ -48,7 +48,7 @@ public class ShaderData implements Operation, VariableSupport { int mShaderID; // allows shaders to be referenced by number @Nullable HashMap mUniformRawFloatMap = null; @Nullable HashMap mUniformFloatMap = null; - @Nullable HashMap mUniformIntMap = null; + @Nullable HashMap mUniformIntMap; @Nullable HashMap mUniformBitmapMap = null; public ShaderData( @@ -104,8 +104,8 @@ public class ShaderData implements Operation, VariableSupport { * @param name name of uniform * @return value of uniform */ - public float[] getUniformFloats(String name) { - return mUniformFloatMap.get(name); + public @NonNull float[] getUniformFloats(@NonNull String name) { + return mUniformFloatMap != null ? mUniformFloatMap.get(name) : new float[0]; } /** @@ -125,8 +125,8 @@ public class ShaderData implements Operation, VariableSupport { * @param name Name of uniform * @return value of uniform */ - public int[] getUniformInts(String name) { - return mUniformIntMap.get(name); + public @NonNull int[] getUniformInts(@NonNull String name) { + return mUniformIntMap != null ? mUniformIntMap.get(name) : new int[0]; } /** @@ -146,8 +146,10 @@ public class ShaderData implements Operation, VariableSupport { * @param name Name of bitmap uniform * @return Bitmap ID */ - public int getUniformBitmapId(String name) { - return mUniformBitmapMap.get(name); + public int getUniformBitmapId(@NonNull String name) { + return mUniformBitmapMap != null + ? mUniformBitmapMap.get(name) + : -1; // TODO: what is the proper return value here? -- bbade@ } @Override @@ -169,7 +171,7 @@ public class ShaderData implements Operation, VariableSupport { @Override public void updateVariables(@NonNull RemoteContext context) { - for (String name : mUniformRawFloatMap.keySet()) { + for (String name : mUniformRawFloatMap.keySet()) { // TODO: potential npe float[] value = mUniformRawFloatMap.get(name); float[] out = null; for (int i = 0; i < value.length; i++) { @@ -186,7 +188,7 @@ public class ShaderData implements Operation, VariableSupport { @Override public void registerListening(@NonNull RemoteContext context) { - for (String name : mUniformRawFloatMap.keySet()) { + for (String name : mUniformRawFloatMap.keySet()) { // TODO: potential npe float[] value = mUniformRawFloatMap.get(name); for (float v : value) { if (Float.isNaN(v)) { @@ -340,7 +342,7 @@ public class ShaderData implements Operation, VariableSupport { @NonNull @Override - public String deepToString(String indent) { + public String deepToString(@NonNull String indent) { return indent + toString(); } } 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 dbaef7ef7ae14c906eb4eec9d74ca3ffbf8bf851..ade008e3bdb4c0925c8f7652d3bf68767d4347f3 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 @@ -34,11 +34,11 @@ import java.util.List; public class TextData implements Operation, SerializableToString { private static final int OP_CODE = Operations.DATA_TEXT; private static final String CLASS_NAME = "TextData"; - public int mTextId; - public String mText; + public final int mTextId; + @NonNull public final String mText; public static final int MAX_STRING_SIZE = 4000; - public TextData(int textId, String text) { + public TextData(int textId, @NonNull String text) { this.mTextId = textId; this.mText = text; } @@ -90,7 +90,7 @@ public class TextData implements Operation, SerializableToString { @NonNull @Override - public String deepToString(String indent) { + public String deepToString(@NonNull String indent) { return indent + toString(); } 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 fb5087f3fee333a3ea022a1aa957f0f8e1ddf9ee..865ee81f2725f08fd450e8f532edf9b61b80e6aa 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 @@ -185,7 +185,7 @@ public class TextFromFloat implements Operation, VariableSupport { @NonNull @Override - public String deepToString(String indent) { + public String deepToString(@NonNull String indent) { return indent + toString(); } } diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/TextLength.java b/core/java/com/android/internal/widget/remotecompose/core/operations/TextLength.java index e148fb9849fc9ac47f9b096ec9b72b75c715c0d2..6ff687b7494e35ffc8b3c1d4bfa32166be4ac0b2 100644 --- a/core/java/com/android/internal/widget/remotecompose/core/operations/TextLength.java +++ b/core/java/com/android/internal/widget/remotecompose/core/operations/TextLength.java @@ -17,6 +17,8 @@ package com.android.internal.widget.remotecompose.core.operations; import static com.android.internal.widget.remotecompose.core.documentation.DocumentedOperation.INT; +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.RemoteContext; @@ -38,16 +40,17 @@ public class TextLength implements Operation { } @Override - public void write(WireBuffer buffer) { + public void write(@NonNull WireBuffer buffer) { apply(buffer, mLengthId, mTextId); } + @NonNull @Override public String toString() { return CLASS_NAME + "[" + mLengthId + "] = " + mTextId; } - public static String name() { + public static @NonNull String name() { return CLASS_NAME; } @@ -62,19 +65,19 @@ public class TextLength implements Operation { * @param lengthId the id to output * @param textId the id of the text to measure */ - public static void apply(WireBuffer buffer, int lengthId, int textId) { + public static void apply(@NonNull WireBuffer buffer, int lengthId, int textId) { buffer.start(OP_CODE); buffer.writeInt(lengthId); buffer.writeInt(textId); } - public static void read(WireBuffer buffer, List operations) { + public static void read(@NonNull WireBuffer buffer, @NonNull List operations) { int lengthId = buffer.readInt(); int textId = buffer.readInt(); operations.add(new TextLength(lengthId, textId)); } - public static void documentation(DocumentationBuilder doc) { + public static void documentation(@NonNull DocumentationBuilder doc) { doc.operation("Expressions Operations", OP_CODE, CLASS_NAME) .description("get the length of the text and store in float table") .field(INT, "id", "id of float length") @@ -82,12 +85,13 @@ public class TextLength implements Operation { } @Override - public void apply(RemoteContext context) { + public void apply(@NonNull RemoteContext context) { context.loadFloat(mLengthId, context.getText(mTextId).length()); } + @NonNull @Override - public String deepToString(String indent) { + public String deepToString(@NonNull String indent) { return indent + toString(); } } 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 2129edde2f59d64dbce821fa08305e2ca29cc3ee..cc812a8e160ea967f890466b6c0d10b0a510d995 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 @@ -126,7 +126,7 @@ public class TextLookup implements Operation, VariableSupport { @NonNull @Override - public String deepToString(String indent) { + public String deepToString(@NonNull String indent) { return indent + toString(); } } 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 ea550cbe010c7dd9d2bdb5d5d29c6c303ec7dfdf..74be698872fa86515081a68edeca8c07c82d7d5f 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 @@ -119,7 +119,7 @@ public class TextLookupInt implements Operation, VariableSupport { @NonNull @Override - public String deepToString(String indent) { + public String deepToString(@NonNull String indent) { return indent + toString(); } } diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/TextMeasure.java b/core/java/com/android/internal/widget/remotecompose/core/operations/TextMeasure.java index 0281d6980e0f9e4aaafbf7ce21994bdc1fcc22d8..6d48f67ed8c80c66d5f5ce24cce8014a21e3495e 100644 --- a/core/java/com/android/internal/widget/remotecompose/core/operations/TextMeasure.java +++ b/core/java/com/android/internal/widget/remotecompose/core/operations/TextMeasure.java @@ -19,6 +19,8 @@ import static com.android.internal.widget.remotecompose.core.PaintContext.TEXT_M import static com.android.internal.widget.remotecompose.core.PaintContext.TEXT_MEASURE_MONOSPACE_WIDTH; import static com.android.internal.widget.remotecompose.core.documentation.DocumentedOperation.INT; +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; @@ -55,16 +57,16 @@ public class TextMeasure extends PaintOperation { } @Override - public void write(WireBuffer buffer) { + public void write(@NonNull WireBuffer buffer) { apply(buffer, mId, mTextId, mType); } @Override - public String toString() { + public @NonNull String toString() { return "FloatConstant[" + mId + "] = " + mTextId + " " + mType; } - public static String name() { + public static @NonNull String name() { return CLASS_NAME; } @@ -80,21 +82,21 @@ public class TextMeasure extends PaintOperation { * @param textId the id * @param type the value of the float */ - public static void apply(WireBuffer buffer, int id, int textId, int type) { + public static void apply(@NonNull WireBuffer buffer, int id, int textId, int type) { buffer.start(OP_CODE); buffer.writeInt(id); buffer.writeInt(textId); buffer.writeInt(type); } - public static void read(WireBuffer buffer, List operations) { + public static void read(@NonNull WireBuffer buffer, @NonNull List operations) { int id = buffer.readInt(); int textId = buffer.readInt(); int type = buffer.readInt(); operations.add(new TextMeasure(id, textId, type)); } - public static void documentation(DocumentationBuilder doc) { + public static void documentation(@NonNull DocumentationBuilder doc) { doc.operation("Expressions Operations", OP_CODE, CLASS_NAME) .description("A float and its associated id") .field(INT, "id", "id of float result of the measure") @@ -102,15 +104,16 @@ public class TextMeasure extends PaintOperation { .field(INT, "type", "type: measure 0=width,1=height"); } + @NonNull @Override - public String deepToString(String indent) { + public String deepToString(@NonNull String indent) { return indent + toString(); } - float[] mBounds = new float[4]; + @NonNull float[] mBounds = new float[4]; @Override - public void paint(PaintContext context) { + public void paint(@NonNull PaintContext context) { int val = mType & 255; int flags = mType >> 8; context.getTextBounds(mTextId, 0, -1, flags, mBounds); 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 fa18b4ddb2a2eb42e255bf9d1c15612eb7855c54..ecd5baaf0dd2b8af133efd92022d17420f34621b 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 @@ -102,7 +102,7 @@ public class TextMerge implements Operation { @NonNull @Override - public String deepToString(String indent) { + public String deepToString(@NonNull String indent) { return indent + toString(); } } 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 1e90ab128e932a0388ff826fabfda6b26adf306c..d265070a50bfcf742886e005ff62229b04b3fa67 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 @@ -68,7 +68,7 @@ public class Theme implements RemoteComposeOperation { @NonNull @Override - public String deepToString(String indent) { + public String deepToString(@NonNull String indent) { return indent + toString(); } 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 b25a7f6ea09d97064f3fa5d5333ae5d9ac07e37c..1bb7b2a183a2e468e1852e9ea7083891c73f823f 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 @@ -20,6 +20,8 @@ import static com.android.internal.widget.remotecompose.core.documentation.Docum import static com.android.internal.widget.remotecompose.core.documentation.DocumentedOperation.INT; import static com.android.internal.widget.remotecompose.core.documentation.DocumentedOperation.SHORT; +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.RemoteContext; @@ -71,6 +73,7 @@ public class TouchExpression implements Operation, VariableSupport, TouchListene boolean mWrapMode = false; float[] mNotches; float[] mStopSpec; + float[] mOutStopSpec; int mTouchEffects; float mVelocityId; @@ -98,6 +101,9 @@ public class TouchExpression implements Operation, VariableSupport, TouchListene mOutDefValue = mDefValue = defValue; mMode = STOP_ABSOLUTE_POS == stopMode ? 1 : 0; mOutMax = mMax = max; + if (stopSpec != null) { + mOutStopSpec = Arrays.copyOf(stopSpec, stopSpec.length); + } mTouchEffects = touchEffects; mVelocityId = velocityId; if (Float.isNaN(min) && Utils.idFromNan(min) == 0) { @@ -108,10 +114,8 @@ public class TouchExpression implements Operation, VariableSupport, TouchListene mStopMode = stopMode; mStopSpec = stopSpec; if (easingSpec != null) { - Utils.log("easingSpec " + Arrays.toString(easingSpec)); if (easingSpec.length >= 4) { if (Float.floatToRawIntBits(easingSpec[0]) == 0) { - Utils.log("easingSpec[2] " + easingSpec[2]); mMaxTime = easingSpec[1]; mMaxAcceleration = easingSpec[2]; mMaxVelocity = easingSpec[3]; @@ -126,6 +130,9 @@ public class TouchExpression implements Operation, VariableSupport, TouchListene if (mPreCalcValue == null || mPreCalcValue.length != mSrcExp.length) { mPreCalcValue = new float[mSrcExp.length]; } + if (mOutStopSpec == null || mOutStopSpec.length != mStopSpec.length) { + mOutStopSpec = new float[mStopSpec.length]; + } if (Float.isNaN(mMax)) { mOutMax = context.getFloat(Utils.idFromNan(mMax)); } @@ -150,6 +157,15 @@ public class TouchExpression implements Operation, VariableSupport, TouchListene mPreCalcValue[i] = mSrcExp[i]; } } + for (int i = 0; i < mStopSpec.length; i++) { + float v = mStopSpec[i]; + if (Float.isNaN(v)) { + float newValue = context.getFloat(Utils.idFromNan(v)); + mOutStopSpec[i] = newValue; + } else { + mOutStopSpec[i] = v; + } + } float v = mLastCalculatedValue; if (value_changed) { // inputs changed check if output changed v = mExp.eval(mPreCalcValue, mPreCalcValue.length); @@ -181,6 +197,11 @@ public class TouchExpression implements Operation, VariableSupport, TouchListene context.listensTo(Utils.idFromNan(v), this); } } + for (float v : mStopSpec) { + if (Float.isNaN(v)) { + context.listensTo(Utils.idFromNan(v), this); + } + } } private float wrap(float pos) { @@ -211,12 +232,14 @@ public class TouchExpression implements Operation, VariableSupport, TouchListene case STOP_INSTANTLY: return pos; case STOP_NOTCHES_EVEN: - int evenSpacing = (int) mStopSpec[0]; - float step = (mOutMax - min) / evenSpacing; + int evenSpacing = (int) mOutStopSpec[0]; + float notchMax = (mOutStopSpec.length > 1) ? mOutStopSpec[1] : mOutMax; + float step = (notchMax - min) / evenSpacing; float notch = min + step * (int) (0.5f + (target - mOutMin) / step); - - notch = Math.max(Math.min(notch, mOutMax), min); + if (!mWrapMode) { + notch = Math.max(Math.min(notch, mOutMax), min); + } return notch; case STOP_NOTCHES_PERCENTS: positions = new float[mStopSpec.length]; @@ -265,7 +288,6 @@ public class TouchExpression implements Operation, VariableSupport, TouchListene float next = mCurrentValue; mLastValue = next; - // System.out.println(mStopMode + " " + prev + " -> " + next); float min = (mWrapMode) ? 0 : mOutMin; float max = mOutMax; @@ -309,7 +331,7 @@ public class TouchExpression implements Operation, VariableSupport, TouchListene @Override public void apply(RemoteContext context) { - Component comp = context.lastComponent; + Component comp = context.mLastComponent; if (comp != null) { float x = comp.getX(); float y = comp.getY(); @@ -329,7 +351,6 @@ public class TouchExpression implements Operation, VariableSupport, TouchListene updateVariables(context); if (mUnmodified) { mCurrentValue = mOutDefValue; - context.loadFloat(mId, wrap(mCurrentValue)); return; } @@ -337,7 +358,11 @@ public class TouchExpression implements Operation, VariableSupport, TouchListene float time = context.getAnimationTime() - mTouchUpTime; float value = mEasyTouch.getPos(time); mCurrentValue = value; - value = wrap(value); + if (mWrapMode) { + value = wrap(value); + } else { + value = Math.min(Math.max(value, mOutMin), mOutMax); + } context.loadFloat(mId, value); if (mEasyTouch.getDuration() < time) { mEasingToStop = false; @@ -410,7 +435,8 @@ public class TouchExpression implements Operation, VariableSupport, TouchListene mTouchUpTime = context.getAnimationTime(); float dest = getStopPosition(value, slope); - mEasyTouch.config(value, dest, slope, mMaxTime, mMaxAcceleration, mMaxVelocity, null); + float time = mMaxTime * Math.abs(dest - value) / (2 * mMaxVelocity); + mEasyTouch.config(value, dest, slope, time, mMaxAcceleration, mMaxVelocity, null); mEasingToStop = true; } @@ -543,7 +569,6 @@ public class TouchExpression implements Operation, VariableSupport, TouchListene int stopLen = stopLogic & 0xFFFF; int stopMode = stopLogic >> 16; - Utils.log("stopMode " + stopMode + " stopLen " + stopLen); float[] stopsData = new float[stopLen]; for (int i = 0; i < stopsData.length; i++) { stopsData[i] = buffer.readFloat(); @@ -592,8 +617,9 @@ public class TouchExpression implements Operation, VariableSupport, TouchListene .field(FLOAT, "wrapValue", "> [Wrap value] "); } + @NonNull @Override - public String deepToString(String indent) { + public String deepToString(@NonNull String indent) { return indent + toString(); } } diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/Utils.java b/core/java/com/android/internal/widget/remotecompose/core/operations/Utils.java index 03f7e0563eeb5cde846612b6ddc2ed6f5043aa84..baca3e0dc99af5204572222cef13ff5cec737f2c 100644 --- a/core/java/com/android/internal/widget/remotecompose/core/operations/Utils.java +++ b/core/java/com/android/internal/widget/remotecompose/core/operations/Utils.java @@ -69,7 +69,7 @@ public class Utils { * @param value * @return */ - public static String floatToString(float idvalue, float value) { + public static @NonNull String floatToString(float idvalue, float value) { if (Float.isNaN(idvalue)) { if (idFromNan(value) == 0) { return "NaN"; @@ -85,7 +85,7 @@ public class Utils { * @param value * @return */ - public static String floatToString(float value) { + public static @NonNull String floatToString(float value) { if (Float.isNaN(value)) { if (idFromNan(value) == 0) { return "NaN"; @@ -100,7 +100,7 @@ public class Utils { * * @param str */ - public static void log(String str) { + public static void log(@NonNull String str) { StackTraceElement s = new Throwable().getStackTrace()[1]; System.out.println( "(" @@ -119,7 +119,7 @@ public class Utils { * @param str * @param n */ - public static void logStack(String str, int n) { + public static void logStack(@NonNull String str, int n) { StackTraceElement[] st = new Throwable().getStackTrace(); for (int i = 1; i < n + 1; i++) { StackTraceElement s = st[i]; 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 bdc2a886ffd629689d6772ff0e6e707ed98172f0..7f1d101cff16fca67dad5a456fc7884b76ae5e44 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 @@ -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.RemoteContext; @@ -22,8 +24,12 @@ import com.android.internal.widget.remotecompose.core.operations.utilities.Strin /** Operations representing actions on the document */ public interface ActionOperation extends Operation { - void serializeToString(int indent, StringSerializer serializer); + void serializeToString(int indent, @NonNull StringSerializer serializer); void runAction( - RemoteContext context, CoreDocument document, Component component, float x, float y); + @NonNull RemoteContext context, + @NonNull CoreDocument document, + @NonNull Component component, + float x, + float y); } 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 e789710bb11385ddb458689a0e4079ef3ef8be0c..19f4c2b049565666f38795e63840c0b5915e8282 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 @@ -77,4 +77,9 @@ public class AnimatableValue { return mValue; } + + @Override + public String toString() { + return "AnimatableValue{mId=" + mId + "}"; + } } 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 988651895bae06c194de8fccc8e1571e78ffb317..aa8f758071416e90ea27973f2849d11fc2f7691f 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 @@ -18,6 +18,7 @@ package com.android.internal.widget.remotecompose.core.operations.layout; import static com.android.internal.widget.remotecompose.core.documentation.DocumentedOperation.INT; import android.annotation.NonNull; +import android.annotation.Nullable; import com.android.internal.widget.remotecompose.core.Operation; import com.android.internal.widget.remotecompose.core.Operations; @@ -35,7 +36,7 @@ public class CanvasContent extends Component implements ComponentStartOperation float y, float width, float height, - Component parent, + @Nullable Component parent, int animationId) { super(parent, componentId, animationId, x, y, width, height); } 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 b567538b1c4e174e76b4958f83f78a41d131a211..f44e20ddcdac63a0bd032071bb056fb3323b6356 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,7 +16,6 @@ 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; @@ -80,7 +79,7 @@ public class ClickModifierOperation extends PaintOperation } @Override - public void apply(RemoteContext context) { + public void apply(@NonNull RemoteContext context) { for (Operation op : mList) { if (op instanceof TextData) { op.apply(context); @@ -90,7 +89,7 @@ public class ClickModifierOperation extends PaintOperation @NonNull @Override - public String deepToString(@Nullable String indent) { + public String deepToString(@NonNull String indent) { return (indent != null ? indent : "") + toString(); } @@ -137,7 +136,7 @@ public class ClickModifierOperation extends PaintOperation } @Override - public void layout(RemoteContext context, float width, float height) { + public void layout(@NonNull RemoteContext context, float width, float height) { mWidth = width; mHeight = height; } @@ -154,8 +153,8 @@ public class ClickModifierOperation extends PaintOperation @Override public void onClick( - RemoteContext context, - CoreDocument document, + @NonNull RemoteContext context, + @NonNull CoreDocument document, @NonNull Component component, float x, float y) { @@ -171,6 +170,7 @@ public class ClickModifierOperation extends PaintOperation ((ActionOperation) o).runAction(context, document, component, x, y); } } + context.hapticEffect(3); } @NonNull @@ -182,7 +182,7 @@ public class ClickModifierOperation extends PaintOperation buffer.start(OP_CODE); } - public static void read(WireBuffer buffer, @NonNull List operations) { + public static void read(@NonNull WireBuffer buffer, @NonNull List operations) { operations.add(new ClickModifierOperation()); } 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 f4f4ee2a3416fc9d3c585622da0699c3220010ec..fbfc796e092a05f75e2f3248852ee43f17d661e3 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 @@ -50,12 +50,12 @@ public class Component extends PaintOperation implements Measurable, Serializabl protected float mY; protected float mWidth; protected float mHeight; - protected Component mParent; + @Nullable protected Component mParent; protected int mAnimationId = -1; - public Visibility mVisibility = Visibility.VISIBLE; - public Visibility mScheduledVisibility = Visibility.VISIBLE; + @NonNull public Visibility mVisibility = Visibility.VISIBLE; + @NonNull public Visibility mScheduledVisibility = Visibility.VISIBLE; @NonNull public ArrayList mList = new ArrayList<>(); - public PaintOperation mPreTranslate; + public PaintOperation mPreTranslate; // todo, can we initialize this here and make it NonNull? public boolean mNeedsMeasure = true; public boolean mNeedsRepaint = false; @Nullable public AnimateMeasure mAnimateMeasure; @@ -99,6 +99,7 @@ public class Component extends PaintOperation implements Measurable, Serializabl return mAnimationId; } + @Nullable public Component getParent() { return mParent; } @@ -160,7 +161,7 @@ public class Component extends PaintOperation implements Measurable, Serializabl } public Component( - Component parent, + @Nullable Component parent, int componentId, int animationId, float x, @@ -177,7 +178,12 @@ public class Component extends PaintOperation implements Measurable, Serializabl } public Component( - int componentId, float x, float y, float width, float height, Component parent) { + int componentId, + float x, + float y, + float width, + float height, + @Nullable Component parent) { this(parent, componentId, -1, x, y, width, height); } @@ -211,7 +217,7 @@ public class Component extends PaintOperation implements Measurable, Serializabl return mNeedsMeasure; } - public void setParent(Component parent) { + public void setParent(@Nullable Component parent) { mParent = parent; } @@ -222,8 +228,8 @@ public class Component extends PaintOperation implements Measurable, Serializabl * @param context the current context */ public void updateVariables(@NonNull RemoteContext context) { - Component prev = context.lastComponent; - context.lastComponent = this; + Component prev = context.mLastComponent; + context.mLastComponent = this; if (!mComponentValues.isEmpty()) { updateComponentValues(context); @@ -236,13 +242,21 @@ public class Component extends PaintOperation implements Measurable, Serializabl o.apply(context); } } - context.lastComponent = prev; + context.mLastComponent = prev; } - public void addComponentValue(ComponentValue v) { + public void addComponentValue(@NonNull ComponentValue v) { mComponentValues.add(v); } + public float intrinsicWidth() { + return getWidth(); + } + + public float intrinsicHeight() { + return getHeight(); + } + public enum Visibility { GONE, VISIBLE, @@ -253,13 +267,13 @@ public class Component extends PaintOperation implements Measurable, Serializabl if (mVisibility != Visibility.VISIBLE || mParent == null) { return mVisibility == Visibility.VISIBLE; } - if (mParent != null) { + if (mParent != null) { // TODO: this is always true -- bbade@ return mParent.isVisible(); } return true; } - public void setVisibility(Visibility visibility) { + public void setVisibility(@NonNull Visibility visibility) { if (visibility != mVisibility || visibility != mScheduledVisibility) { mScheduledVisibility = visibility; invalidateMeasure(); @@ -267,7 +281,7 @@ public class Component extends PaintOperation implements Measurable, Serializabl } @Override - public boolean suitableForTransition(Operation o) { + public boolean suitableForTransition(@NonNull Operation o) { if (!(o instanceof Component)) { return false; } @@ -291,7 +305,7 @@ public class Component extends PaintOperation implements Measurable, Serializabl @Override public void measure( - PaintContext context, + @NonNull PaintContext context, float minWidth, float maxWidth, float minHeight, @@ -358,16 +372,27 @@ public class Component extends PaintOperation implements Measurable, Serializabl return x >= lx1 && x < lx2 && y >= ly1 && y < ly2; } - public void onClick(RemoteContext context, CoreDocument document, float x, float y) { + public float getScrollX() { + return 0; + } + + public float getScrollY() { + return 0; + } + + public void onClick( + @NonNull RemoteContext context, @NonNull CoreDocument document, float x, float y) { if (!contains(x, y)) { return; } + float cx = x - getScrollX(); + float cy = y - getScrollY(); for (Operation op : mList) { if (op instanceof Component) { - ((Component) op).onClick(context, document, x, y); + ((Component) op).onClick(context, document, cx, cy); } if (op instanceof ClickHandler) { - ((ClickHandler) op).onClick(context, document, this, x, y); + ((ClickHandler) op).onClick(context, document, this, cx, cy); } } } @@ -376,12 +401,14 @@ public class Component extends PaintOperation implements Measurable, Serializabl if (!contains(x, y)) { return; } + float cx = x - getScrollX(); + float cy = y - getScrollY(); for (Operation op : mList) { if (op instanceof Component) { - ((Component) op).onTouchDown(context, document, x, y); + ((Component) op).onTouchDown(context, document, cx, cy); } if (op instanceof TouchHandler) { - ((TouchHandler) op).onTouchDown(context, document, this, x, y); + ((TouchHandler) op).onTouchDown(context, document, this, cx, cy); } } } @@ -391,12 +418,14 @@ public class Component extends PaintOperation implements Measurable, Serializabl if (!force && !contains(x, y)) { return; } + float cx = x - getScrollX(); + float cy = y - getScrollY(); for (Operation op : mList) { if (op instanceof Component) { - ((Component) op).onTouchUp(context, document, x, y, force); + ((Component) op).onTouchUp(context, document, cx, cy, force); } if (op instanceof TouchHandler) { - ((TouchHandler) op).onTouchUp(context, document, this, x, y); + ((TouchHandler) op).onTouchUp(context, document, this, cx, cy); } } } @@ -406,12 +435,31 @@ public class Component extends PaintOperation implements Measurable, Serializabl if (!force && !contains(x, y)) { return; } + float cx = x - getScrollX(); + float cy = y - getScrollY(); + for (Operation op : mList) { + if (op instanceof Component) { + ((Component) op).onTouchCancel(context, document, cx, cy, force); + } + if (op instanceof TouchHandler) { + ((TouchHandler) op).onTouchCancel(context, document, this, cx, cy); + } + } + } + + public void onTouchDrag( + RemoteContext context, CoreDocument document, float x, float y, boolean force) { + if (!force && !contains(x, y)) { + return; + } + float cx = x - getScrollX(); + float cy = y - getScrollY(); for (Operation op : mList) { if (op instanceof Component) { - ((Component) op).onTouchCancel(context, document, x, y, force); + ((Component) op).onTouchDrag(context, document, cx, cy, force); } if (op instanceof TouchHandler) { - ((TouchHandler) op).onTouchCancel(context, document, this, x, y); + ((TouchHandler) op).onTouchDrag(context, document, this, cx, cy); } } } @@ -480,7 +528,7 @@ public class Component extends PaintOperation implements Measurable, Serializabl } @Override - public void write(WireBuffer buffer) { + public void write(@NonNull WireBuffer buffer) { // nothing } @@ -502,7 +550,7 @@ public class Component extends PaintOperation implements Measurable, Serializabl @NonNull @Override - public String deepToString(String indent) { + public String deepToString(@NonNull String indent) { StringBuilder builder = new StringBuilder(); builder.append(indent); builder.append(toString()); @@ -602,8 +650,8 @@ public class Component extends PaintOperation implements Measurable, Serializabl if (mPreTranslate != null) { mPreTranslate.paint(context); } - Component prev = context.getContext().lastComponent; - context.getContext().lastComponent = this; + Component prev = context.getContext().mLastComponent; + context.getContext().mLastComponent = this; context.save(); context.translate(mX, mY); if (context.isVisualDebug()) { @@ -618,7 +666,7 @@ public class Component extends PaintOperation implements Measurable, Serializabl } } context.restore(); - context.getContext().lastComponent = prev; + context.getContext().mLastComponent = prev; } public boolean applyAnimationAsNeeded(@NonNull PaintContext context) { 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 f370e20677e87a88e5cd523cdeba72b4d131dc4f..476b73c8fe7d6674e576e7411458c5b3aa3aa312 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 @@ -16,7 +16,6 @@ package com.android.internal.widget.remotecompose.core.operations.layout; import android.annotation.NonNull; -import android.annotation.Nullable; import com.android.internal.widget.remotecompose.core.Operation; import com.android.internal.widget.remotecompose.core.Operations; @@ -40,13 +39,13 @@ public class ComponentEnd implements Operation { } @Override - public void apply(RemoteContext context) { + public void apply(@NonNull RemoteContext context) { // nothing } @NonNull @Override - public String deepToString(@Nullable String indent) { + public String deepToString(@NonNull String indent) { return (indent != null ? indent : "") + toString(); } @@ -67,7 +66,7 @@ public class ComponentEnd implements Operation { return 1 + 4 + 4 + 4; } - public static void read(WireBuffer buffer, @NonNull List operations) { + public static void read(@NonNull WireBuffer buffer, @NonNull List operations) { operations.add(new ComponentEnd()); } 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 f250d9ac4a0193691eb5931bc6541333b451be30..def9f780ba7f2c827a7ccb6e6d344bb594273ecf 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 @@ -19,7 +19,6 @@ import static com.android.internal.widget.remotecompose.core.documentation.Docum import static com.android.internal.widget.remotecompose.core.documentation.DocumentedOperation.INT; import android.annotation.NonNull; -import android.annotation.Nullable; import com.android.internal.widget.remotecompose.core.Operation; import com.android.internal.widget.remotecompose.core.Operations; @@ -96,12 +95,12 @@ public class ComponentStart implements ComponentStartOperation { @NonNull @Override - public String deepToString(@Nullable String indent) { + public String deepToString(@NonNull String indent) { return (indent != null ? indent : "") + toString(); } @Override - public void apply(RemoteContext context) { + public void apply(@NonNull RemoteContext context) { // nothing } 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 bb4311996df013a6886322883c420c174f70e905..d6170074238a4ebc5e8d2a543d1c3a50b25a25e0 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 @@ -15,6 +15,8 @@ */ package com.android.internal.widget.remotecompose.core.operations.layout; +import android.annotation.NonNull; + import com.android.internal.widget.remotecompose.core.RemoteContext; /** @@ -22,5 +24,5 @@ import com.android.internal.widget.remotecompose.core.RemoteContext; * measured. Eg borders, background, clips, etc. */ public interface DecoratorComponent { - void layout(RemoteContext context, float width, float height); + void layout(@NonNull RemoteContext context, 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 e0923dfb48fb33cab80b576f8f2f363bdd59ed5d..0041582f718939f48f399a8ac7419d4470988d12 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 @@ -24,7 +24,9 @@ import com.android.internal.widget.remotecompose.core.operations.BitmapData; import com.android.internal.widget.remotecompose.core.operations.MatrixRestore; import com.android.internal.widget.remotecompose.core.operations.MatrixSave; import com.android.internal.widget.remotecompose.core.operations.MatrixTranslate; +import com.android.internal.widget.remotecompose.core.operations.PaintData; 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.modifiers.ComponentModifiers; import com.android.internal.widget.remotecompose.core.operations.layout.modifiers.ComponentVisibilityOperation; import com.android.internal.widget.remotecompose.core.operations.layout.modifiers.DimensionModifierOperation; @@ -57,12 +59,14 @@ public class LayoutComponent extends Component { protected float mPaddingBottom = 0f; @NonNull protected ComponentModifiers mComponentModifiers = new ComponentModifiers(); - @NonNull protected ArrayList mChildrenComponents = new ArrayList<>(); + + @NonNull + protected ArrayList mChildrenComponents = new ArrayList<>(); // members are not null protected boolean mChildrenHaveZIndex = false; public LayoutComponent( - Component parent, + @Nullable Component parent, int componentId, int animationId, float x, @@ -129,6 +133,9 @@ public class LayoutComponent extends Component { public void inflate() { ArrayList data = new ArrayList<>(); + ArrayList touchExpressions = new ArrayList<>(); + ArrayList paintData = new ArrayList<>(); + for (Operation op : mList) { if (op instanceof LayoutComponentContent) { mContent = (LayoutComponentContent) op; @@ -172,6 +179,10 @@ public class LayoutComponent extends Component { mComponentModifiers.add((ModifierOperation) op); } else if (op instanceof TextData) { data.add((TextData) op); + } else if (op instanceof TouchExpression) { + touchExpressions.add((TouchExpression) op); + } else if (op instanceof PaintData) { + paintData.add((PaintData) op); } else { // nothing } @@ -179,6 +190,8 @@ public class LayoutComponent extends Component { mList.clear(); mList.addAll(data); + mList.addAll(touchExpressions); + mList.addAll(paintData); mList.add(mComponentModifiers); for (Component c : mChildrenComponents) { c.mParent = this; @@ -254,12 +267,25 @@ public class LayoutComponent extends Component { return "UNKNOWN LAYOUT_COMPONENT"; } + @Override + public float getScrollX() { + return mComponentModifiers.getScrollX(); + } + + @Override + public float getScrollY() { + return mComponentModifiers.getScrollY(); + } + @Override public void paintingComponent(@NonNull PaintContext context) { - Component prev = context.getContext().lastComponent; - context.getContext().lastComponent = this; + Component prev = context.getContext().mLastComponent; + context.getContext().mLastComponent = this; context.save(); context.translate(mX, mY); + if (context.isVisualDebug()) { + debugBox(this, context); + } if (mGraphicsLayerModifier != null) { context.startGraphicsLayer((int) getWidth(), (int) getHeight()); float scaleX = mGraphicsLayerModifier.getScaleX(); @@ -285,8 +311,8 @@ public class LayoutComponent extends Component { renderEffectId); } mComponentModifiers.paint(context); - float tx = mPaddingLeft; - float ty = mPaddingTop; + float tx = mPaddingLeft + getScrollX(); + float ty = mPaddingTop + getScrollY(); context.translate(tx, ty); if (mChildrenHaveZIndex) { // TODO -- should only sort when something has changed @@ -305,7 +331,7 @@ public class LayoutComponent extends Component { } context.translate(-tx, -ty); context.restore(); - context.getContext().lastComponent = prev; + context.getContext().mLastComponent = prev; } /** Traverse the modifiers to compute indicated dimension */ @@ -337,7 +363,7 @@ public class LayoutComponent extends Component { * @param padding output start and end padding values * @return padding width */ - public float computeModifierDefinedPaddingWidth(float[] padding) { + public float computeModifierDefinedPaddingWidth(@NonNull float[] padding) { float s = 0f; float e = 0f; for (Operation c : mComponentModifiers.getList()) { @@ -381,7 +407,7 @@ public class LayoutComponent extends Component { * @param padding output top and bottom padding values * @return padding height */ - public float computeModifierDefinedPaddingHeight(float[] padding) { + public float computeModifierDefinedPaddingHeight(@NonNull float[] padding) { float t = 0f; float b = 0f; for (Operation c : mComponentModifiers.getList()) { 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 0a085b43401c69f99fde7caf6da97d5e1eb24e2d..7eea885f6b6d2c2b1d51ebd7e87b47c47b5b69f3 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 @@ -18,6 +18,7 @@ package com.android.internal.widget.remotecompose.core.operations.layout; import static com.android.internal.widget.remotecompose.core.documentation.DocumentedOperation.INT; import android.annotation.NonNull; +import android.annotation.Nullable; import com.android.internal.widget.remotecompose.core.Operation; import com.android.internal.widget.remotecompose.core.Operations; @@ -35,7 +36,7 @@ public class LayoutComponentContent extends Component implements ComponentStartO float y, float width, float height, - Component parent, + @Nullable Component parent, int animationId) { super(parent, componentId, animationId, x, y, width, height); } 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 c4df075bb9e8ffd59c9f902af0de201879a812e8..df960e45736ece2d24fb8157b0179eacfc30354d 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 @@ -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.PaintContext; @@ -59,8 +61,9 @@ public abstract class ListActionsOperation extends PaintOperation } } + @NonNull @Override - public String deepToString(String indent) { + public String deepToString(@NonNull String indent) { return (indent != null ? indent : "") + toString(); } 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 c90077b887823cf4905d5df2d6c57b858c32312f..71de2857258b803810b005376368a4ee6a4b9e18 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 @@ -16,7 +16,6 @@ package com.android.internal.widget.remotecompose.core.operations.layout; import android.annotation.NonNull; -import android.annotation.Nullable; import com.android.internal.widget.remotecompose.core.Operation; import com.android.internal.widget.remotecompose.core.Operations; @@ -40,13 +39,13 @@ public class LoopEnd implements Operation { } @Override - public void apply(RemoteContext context) { + public void apply(@NonNull RemoteContext context) { // nothing } @NonNull @Override - public String deepToString(@Nullable String indent) { + public String deepToString(@NonNull String indent) { return (indent != null ? indent : "") + toString(); } @@ -63,7 +62,7 @@ public class LoopEnd implements Operation { buffer.start(id()); } - public static void read(WireBuffer buffer, @NonNull List operations) { + public static void read(@NonNull WireBuffer buffer, @NonNull List operations) { operations.add(new LoopEnd()); } 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 eeaeafd284c03bea8c6012d35cfc24795299339d..d88382dde7e04d587d939f7a930150b9a35508ff 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 @@ -16,7 +16,6 @@ package com.android.internal.widget.remotecompose.core.operations.layout; import android.annotation.NonNull; -import android.annotation.Nullable; import com.android.internal.widget.remotecompose.core.Operation; import com.android.internal.widget.remotecompose.core.Operations; @@ -70,7 +69,7 @@ public class LoopOperation extends PaintOperation { @NonNull @Override - public String deepToString(@Nullable String indent) { + public String deepToString(@NonNull String indent) { return (indent != null ? indent : "") + toString(); } 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 bd8d1f0ba9dd2cd609952825f4b7d6b91247c0e0..ca79003448e73235d3e310500a975b92521ae6f1 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 @@ -16,7 +16,6 @@ package com.android.internal.widget.remotecompose.core.operations.layout; import android.annotation.NonNull; -import android.annotation.Nullable; import com.android.internal.widget.remotecompose.core.Operation; import com.android.internal.widget.remotecompose.core.Operations; @@ -40,13 +39,13 @@ public class OperationsListEnd implements Operation { } @Override - public void apply(RemoteContext context) { + public void apply(@NonNull RemoteContext context) { // nothing } @NonNull @Override - public String deepToString(@Nullable String indent) { + public String deepToString(@NonNull String indent) { return (indent != null ? indent : "") + toString(); } @@ -63,7 +62,7 @@ public class OperationsListEnd implements Operation { buffer.start(id()); } - public static void read(WireBuffer buffer, @NonNull List operations) { + public static void read(@NonNull WireBuffer buffer, @NonNull List operations) { operations.add(new OperationsListEnd()); } 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 524ae59e70ec3e94272bd19fef39d68678d810ca..85c71537540c3ad3255678e52ddda2456500263a 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 @@ -18,6 +18,7 @@ package com.android.internal.widget.remotecompose.core.operations.layout; import static com.android.internal.widget.remotecompose.core.documentation.DocumentedOperation.INT; import android.annotation.NonNull; +import android.annotation.Nullable; import com.android.internal.widget.remotecompose.core.Operation; import com.android.internal.widget.remotecompose.core.Operations; @@ -45,13 +46,18 @@ public class RootLayoutComponent extends Component implements ComponentStartOper float y, float width, float height, - Component parent, + @Nullable Component parent, int animationId) { super(parent, componentId, animationId, x, y, width, height); } public RootLayoutComponent( - int componentId, float x, float y, float width, float height, Component parent) { + int componentId, + float x, + float y, + float width, + float height, + @Nullable Component parent) { super(parent, componentId, -1, x, y, width, height); } @@ -130,7 +136,7 @@ public class RootLayoutComponent extends Component implements ComponentStartOper if (!mNeedsMeasure) { return; } - context.lastComponent = this; + context.mLastComponent = this; mWidth = context.mWidth; mHeight = context.mHeight; @@ -149,7 +155,7 @@ public class RootLayoutComponent extends Component implements ComponentStartOper @Override public void paint(@NonNull PaintContext context) { mNeedsRepaint = false; - context.getContext().lastComponent = this; + context.getContext().mLastComponent = this; context.save(); if (mParent == null) { // root layout 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 486efbd6e00f35d75b368235e408bbdf91e9eda9..0316f96bfc3e3146160f30263c62fc096b7d70a8 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 @@ -70,6 +70,12 @@ public class TouchCancelModifierOperation extends ListActionsOperation implement applyActions(context, document, component, x, y, true); } + @Override + public void onTouchDrag( + RemoteContext context, CoreDocument document, Component component, float x, float y) { + // nothing + } + 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 5d379fe01d618492a3708f8706ae537a7f126fca..d98911f82060c268dae3264be295e1189c54d3b9 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 @@ -72,6 +72,12 @@ public class TouchDownModifierOperation extends ListActionsOperation implements // nothing } + @Override + public void onTouchDrag( + RemoteContext context, CoreDocument document, Component component, float x, float y) { + // nothing + } + 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 5adfc33b5ef59d2aa3d358c7e322d3f79e8236c8..ac9dd908d6a400351b402b7ec29cd62c7247acbd 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 @@ -45,6 +45,18 @@ public interface TouchHandler { void onTouchUp( RemoteContext context, CoreDocument document, Component component, float x, float y); + /** + * callback for a touch move event + * + * @param context the current context + * @param document the current document + * @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 + */ + void onTouchDrag( + RemoteContext context, CoreDocument document, Component component, float x, float y); + /** * callback for a touch cancel 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 263cc43d5e74e0be1c7adaf64b6f65f3703b13b3..f6cb3750906fbccd35d3b87873af42a5d7388861 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 @@ -70,6 +70,12 @@ public class TouchUpModifierOperation extends ListActionsOperation implements To // nothing } + @Override + public void onTouchDrag( + RemoteContext context, CoreDocument document, Component component, float x, float y) { + // nothing + } + 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 6036b74efad31721ee08892aa19760a19a90294a..b3430998a5203dc09c985054917a5e64087b9787 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 @@ -33,40 +33,40 @@ import com.android.internal.widget.remotecompose.core.operations.utilities.easin *

    Handles position, size and visibility */ public class AnimateMeasure { - long mStartTime = System.currentTimeMillis(); - Component mComponent; - ComponentMeasure mOriginal; - ComponentMeasure mTarget; - int mDuration; - int mDurationVisibilityChange = mDuration; - AnimationSpec.ANIMATION mEnterAnimation = AnimationSpec.ANIMATION.FADE_IN; - AnimationSpec.ANIMATION mExitAnimation = AnimationSpec.ANIMATION.FADE_OUT; - int mMotionEasingType = GeneralEasing.CUBIC_STANDARD; - int mVisibilityEasingType = GeneralEasing.CUBIC_ACCELERATE; + private long mStartTime = System.currentTimeMillis(); + private final @NonNull Component mComponent; + private final @NonNull ComponentMeasure mOriginal; + private final @NonNull ComponentMeasure mTarget; + private int mDuration; + private int mDurationVisibilityChange = mDuration; + private @NonNull AnimationSpec.ANIMATION mEnterAnimation = AnimationSpec.ANIMATION.FADE_IN; + private @NonNull AnimationSpec.ANIMATION mExitAnimation = AnimationSpec.ANIMATION.FADE_OUT; + private int mMotionEasingType = GeneralEasing.CUBIC_STANDARD; + private int mVisibilityEasingType = GeneralEasing.CUBIC_ACCELERATE; - float mP = 0f; - float mVp = 0f; + private float mP = 0f; + private float mVp = 0f; @NonNull - FloatAnimation mMotionEasing = + private FloatAnimation mMotionEasing = new FloatAnimation(mMotionEasingType, mDuration / 1000f, null, 0f, Float.NaN); @NonNull - FloatAnimation mVisibilityEasing = + private FloatAnimation mVisibilityEasing = new FloatAnimation( mVisibilityEasingType, mDurationVisibilityChange / 1000f, null, 0f, Float.NaN); - ParticleAnimation mParticleAnimation; + private ParticleAnimation mParticleAnimation; public AnimateMeasure( long startTime, @NonNull Component component, - ComponentMeasure original, + @NonNull ComponentMeasure original, @NonNull ComponentMeasure target, int duration, int durationVisibilityChange, - AnimationSpec.ANIMATION enterAnimation, - AnimationSpec.ANIMATION exitAnimation, + @NonNull AnimationSpec.ANIMATION enterAnimation, + @NonNull AnimationSpec.ANIMATION exitAnimation, int motionEasingType, int visibilityEasingType) { this.mStartTime = startTime; 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 47abadeb70fa2db72ae5d5ed3ad417f552cf1462..6fb70598571172c533ef7d8c124789a8b20eb4fc 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 @@ -18,7 +18,6 @@ package com.android.internal.widget.remotecompose.core.operations.layout.animati import static com.android.internal.widget.remotecompose.core.documentation.DocumentedOperation.INT; import android.annotation.NonNull; -import android.annotation.Nullable; import com.android.internal.widget.remotecompose.core.Operation; import com.android.internal.widget.remotecompose.core.Operations; @@ -36,8 +35,8 @@ public class AnimationSpec implements Operation { int mMotionEasingType = GeneralEasing.CUBIC_STANDARD; int mVisibilityDuration = 300; int mVisibilityEasingType = GeneralEasing.CUBIC_STANDARD; - ANIMATION mEnterAnimation = ANIMATION.FADE_IN; - ANIMATION mExitAnimation = ANIMATION.FADE_OUT; + @NonNull ANIMATION mEnterAnimation = ANIMATION.FADE_IN; + @NonNull ANIMATION mExitAnimation = ANIMATION.FADE_OUT; public AnimationSpec( int animationId, @@ -45,8 +44,8 @@ public class AnimationSpec implements Operation { int motionEasingType, int visibilityDuration, int visibilityEasingType, - ANIMATION enterAnimation, - ANIMATION exitAnimation) { + @NonNull ANIMATION enterAnimation, + @NonNull ANIMATION exitAnimation) { this.mAnimationId = animationId; this.mMotionDuration = motionDuration; this.mMotionEasingType = motionEasingType; @@ -87,10 +86,12 @@ public class AnimationSpec implements Operation { return mVisibilityEasingType; } + @NonNull public ANIMATION getEnterAnimation() { return mEnterAnimation; } + @NonNull public ANIMATION getExitAnimation() { return mExitAnimation; } @@ -126,13 +127,13 @@ public class AnimationSpec implements Operation { } @Override - public void apply(RemoteContext context) { + public void apply(@NonNull RemoteContext context) { // nothing here } @NonNull @Override - public String deepToString(@Nullable String indent) { + public String deepToString(@NonNull String indent) { return (indent != null ? indent : "") + toString(); } diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/layout/animation/ParticleAnimation.java b/core/java/com/android/internal/widget/remotecompose/core/operations/layout/animation/ParticleAnimation.java index 37d20781f4fa4f602750020325bd600f277c7672..64e2f004cb6504330cc22066134888d387ebc575 100644 --- a/core/java/com/android/internal/widget/remotecompose/core/operations/layout/animation/ParticleAnimation.java +++ b/core/java/com/android/internal/widget/remotecompose/core/operations/layout/animation/ParticleAnimation.java @@ -34,7 +34,7 @@ public class ParticleAnimation { @NonNull PaintContext context, @NonNull Component component, @NonNull ComponentMeasure start, - ComponentMeasure end, + @NonNull ComponentMeasure end, float progress) { ArrayList particles = mAllParticles.get(component.getComponentId()); if (particles == null) { 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 f3e550903a6507787d4c12c70b55430667dbc33d..47a9421879002fae6468e1195b601a7e30dd535a 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 @@ -18,6 +18,7 @@ package com.android.internal.widget.remotecompose.core.operations.layout.manager import static com.android.internal.widget.remotecompose.core.documentation.DocumentedOperation.INT; import android.annotation.NonNull; +import android.annotation.Nullable; import com.android.internal.widget.remotecompose.core.Operation; import com.android.internal.widget.remotecompose.core.Operations; @@ -45,7 +46,7 @@ public class BoxLayout extends LayoutManager implements ComponentStartOperation int mVerticalPositioning; public BoxLayout( - Component parent, + @Nullable Component parent, int componentId, int animationId, float x, @@ -60,7 +61,7 @@ public class BoxLayout extends LayoutManager implements ComponentStartOperation } public BoxLayout( - Component parent, + @Nullable Component parent, int componentId, int animationId, int horizontalPositioning, @@ -104,7 +105,7 @@ public class BoxLayout extends LayoutManager implements ComponentStartOperation @Override public void computeWrapSize( - PaintContext context, + @NonNull PaintContext context, float maxWidth, float maxHeight, @NonNull MeasurePass measure, @@ -122,7 +123,7 @@ public class BoxLayout extends LayoutManager implements ComponentStartOperation @Override public void computeSize( - PaintContext context, + @NonNull PaintContext context, float minWidth, float maxWidth, float minHeight, @@ -134,7 +135,7 @@ public class BoxLayout extends LayoutManager implements ComponentStartOperation } @Override - public void internalLayoutMeasure(PaintContext context, @NonNull MeasurePass measure) { + public void internalLayoutMeasure(@NonNull PaintContext context, @NonNull MeasurePass measure) { ComponentMeasure selfMeasure = measure.get(this); float selfWidth = selfMeasure.getW() - mPaddingLeft - mPaddingRight; float selfHeight = selfMeasure.getH() - mPaddingTop - mPaddingBottom; 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 12ff969530b3f9dee6f9799922ec04c3ff3381e9..476b1a666fe98f2c1c592ecd968e8db3412e8622 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 @@ -18,6 +18,7 @@ package com.android.internal.widget.remotecompose.core.operations.layout.manager import static com.android.internal.widget.remotecompose.core.documentation.DocumentedOperation.INT; import android.annotation.NonNull; +import android.annotation.Nullable; import com.android.internal.widget.remotecompose.core.Operation; import com.android.internal.widget.remotecompose.core.Operations; @@ -32,7 +33,7 @@ import java.util.List; public class CanvasLayout extends BoxLayout { public CanvasLayout( - Component parent, + @Nullable Component parent, int componentId, int animationId, float x, @@ -42,7 +43,7 @@ public class CanvasLayout extends BoxLayout { super(parent, componentId, animationId, x, y, width, height, 0, 0); } - public CanvasLayout(Component parent, int componentId, int animationId) { + public CanvasLayout(@Nullable Component parent, int componentId, int animationId) { this(parent, componentId, animationId, 0, 0, 0, 0); } @@ -103,7 +104,7 @@ public class CanvasLayout extends BoxLayout { } @Override - public void internalLayoutMeasure(PaintContext context, @NonNull MeasurePass measure) { + public void internalLayoutMeasure(@NonNull PaintContext context, @NonNull MeasurePass measure) { ComponentMeasure selfMeasure = measure.get(this); float selfWidth = selfMeasure.getW() - mPaddingLeft - mPaddingRight; float selfHeight = selfMeasure.getH() - mPaddingTop - mPaddingBottom; 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 52bf4c54faf69c2b90bde3ef82ff6eb5a5c8ce9e..68e18c699539ad60bdcb3776b73280d0a45e802b 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 @@ -19,6 +19,7 @@ import static com.android.internal.widget.remotecompose.core.documentation.Docum import static com.android.internal.widget.remotecompose.core.documentation.DocumentedOperation.INT; import android.annotation.NonNull; +import android.annotation.Nullable; import com.android.internal.widget.remotecompose.core.Operation; import com.android.internal.widget.remotecompose.core.Operations; @@ -53,7 +54,7 @@ public class ColumnLayout extends LayoutManager implements ComponentStartOperati float mSpacedBy = 0f; public ColumnLayout( - Component parent, + @Nullable Component parent, int componentId, int animationId, float x, @@ -70,7 +71,7 @@ public class ColumnLayout extends LayoutManager implements ComponentStartOperati } public ColumnLayout( - Component parent, + @Nullable Component parent, int componentId, int animationId, int horizontalPositioning, @@ -121,7 +122,7 @@ public class ColumnLayout extends LayoutManager implements ComponentStartOperati @Override public void computeWrapSize( - PaintContext context, + @NonNull PaintContext context, float maxWidth, float maxHeight, @NonNull MeasurePass measure, @@ -145,7 +146,7 @@ public class ColumnLayout extends LayoutManager implements ComponentStartOperati @Override public void computeSize( - PaintContext context, + @NonNull PaintContext context, float minWidth, float maxWidth, float minHeight, @@ -164,7 +165,17 @@ public class ColumnLayout extends LayoutManager implements ComponentStartOperati } @Override - public void internalLayoutMeasure(PaintContext context, @NonNull MeasurePass measure) { + public float intrinsicHeight() { + float height = computeModifierDefinedHeight(); + float componentHeights = 0f; + for (Component c : mChildrenComponents) { + componentHeights += c.intrinsicHeight(); + } + return Math.max(height, componentHeights); + } + + @Override + public void internalLayoutMeasure(@NonNull PaintContext context, @NonNull MeasurePass measure) { ComponentMeasure selfMeasure = measure.get(this); DebugLog.s( () -> @@ -188,6 +199,16 @@ public class ColumnLayout extends LayoutManager implements ComponentStartOperati float childrenWidth = 0f; float childrenHeight = 0f; + if (mComponentModifiers.hasHorizontalScroll()) { + selfWidth = + mComponentModifiers.getHorizontalScrollDimension() + - mPaddingLeft + - mPaddingRight; + } + if (mComponentModifiers.hasVerticalScroll()) { + selfHeight = + mComponentModifiers.getVerticalScrollDimension() - mPaddingTop - mPaddingBottom; + } boolean hasWeights = false; float totalWeights = 0f; for (Component child : mChildrenComponents) { @@ -286,6 +307,7 @@ public class ColumnLayout extends LayoutManager implements ComponentStartOperati ty = verticalGap / 2f; break; } + for (Component child : mChildrenComponents) { ComponentMeasure childMeasure = measure.get(child); switch (mHorizontalPositioning) { 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 0c4d24a4561a36486d5540f0977898f3fd026967..3b5aaf38fb5b3b5fb94b5195e761a1bf4b02ab90 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 @@ -16,6 +16,7 @@ package com.android.internal.widget.remotecompose.core.operations.layout.managers; import android.annotation.NonNull; +import android.annotation.Nullable; import com.android.internal.widget.remotecompose.core.PaintContext; import com.android.internal.widget.remotecompose.core.RemoteContext; @@ -32,7 +33,7 @@ public abstract class LayoutManager extends LayoutComponent implements Measurabl @NonNull Size mCachedWrapSize = new Size(0f, 0f); public LayoutManager( - Component parent, + @Nullable Component parent, int componentId, int animationId, float x, @@ -43,24 +44,46 @@ public abstract class LayoutManager extends LayoutComponent implements Measurabl } /** Implemented by subclasses to provide a layout/measure pass */ - public void internalLayoutMeasure(PaintContext context, MeasurePass measure) { + public void internalLayoutMeasure(@NonNull PaintContext context, @NonNull MeasurePass measure) { // nothing here } /** Subclasses can implement this to provide wrap sizing */ public void computeWrapSize( - PaintContext context, float maxWidth, float maxHeight, MeasurePass measure, Size size) { + @NonNull PaintContext context, + float maxWidth, + float maxHeight, + @NonNull MeasurePass measure, + @NonNull Size size) { // nothing here } + @Override + public float intrinsicHeight() { + float height = computeModifierDefinedHeight(); + for (Component c : mChildrenComponents) { + height = Math.max(c.intrinsicHeight(), height); + } + return height; + } + + @Override + public float intrinsicWidth() { + float width = computeModifierDefinedWidth(); + for (Component c : mChildrenComponents) { + width = Math.max(c.intrinsicWidth(), width); + } + return width; + } + /** Subclasses can implement this when not in wrap sizing */ public void computeSize( - PaintContext context, + @NonNull PaintContext context, float minWidth, float maxWidth, float minHeight, float maxHeight, - MeasurePass measure) { + @NonNull MeasurePass measure) { // nothing here } @@ -99,7 +122,7 @@ public abstract class LayoutManager extends LayoutComponent implements Measurabl /** Base implementation of the measure resolution */ @Override public void measure( - PaintContext context, + @NonNull PaintContext context, float minWidth, float maxWidth, float minHeight, @@ -112,7 +135,13 @@ public abstract class LayoutManager extends LayoutComponent implements Measurabl Math.min(maxHeight, computeModifierDefinedHeight() - mMarginTop - mMarginBottom); float insetMaxWidth = maxWidth - mMarginLeft - mMarginRight; float insetMaxHeight = maxHeight - mMarginTop - mMarginBottom; - if (mWidthModifier.isWrap() || mHeightModifier.isWrap()) { + if (mWidthModifier.isIntrinsicMin()) { + maxWidth = intrinsicWidth(); + } + if (mHeightModifier.isIntrinsicMin()) { + maxHeight = intrinsicHeight(); + } + if (mWidthModifier.isWrap() || mHeightModifier.isWrap()) { // TODO: potential npe -- bbade@ mCachedWrapSize.setWidth(0f); mCachedWrapSize.setHeight(0f); computeWrapSize(context, maxWidth, maxHeight, measure, mCachedWrapSize); @@ -129,7 +158,7 @@ public abstract class LayoutManager extends LayoutComponent implements Measurabl measuredWidth = Math.max(measuredWidth, minWidth); measuredWidth = Math.min(measuredWidth, insetMaxWidth); } - if (isInVerticalFill()) { + if (isInVerticalFill()) { // todo: potential npe -- bbade@ measuredHeight = insetMaxHeight; } else if (mHeightModifier.hasWeight()) { measuredHeight = Math.max(measuredHeight, computeModifierDefinedHeight()); @@ -146,7 +175,23 @@ public abstract class LayoutManager extends LayoutComponent implements Measurabl measuredWidth = Math.min(measuredWidth, insetMaxWidth); measuredHeight = Math.min(measuredHeight, insetMaxHeight); if (!hasWrap) { - computeSize(context, 0f, measuredWidth, 0f, measuredHeight, measure); + if (hasHorizontalScroll()) { + mCachedWrapSize.setWidth(0f); + mCachedWrapSize.setHeight(0f); + computeWrapSize(context, Float.MAX_VALUE, maxHeight, measure, mCachedWrapSize); + float w = mCachedWrapSize.getWidth(); + computeSize(context, 0f, w, 0, measuredHeight, measure); + mComponentModifiers.setHorizontalScrollDimension(measuredWidth, w); + } else if (hasVerticalScroll()) { + mCachedWrapSize.setWidth(0f); + mCachedWrapSize.setHeight(0f); + computeWrapSize(context, maxWidth, Float.MAX_VALUE, measure, mCachedWrapSize); + float h = mCachedWrapSize.getHeight(); + computeSize(context, 0f, measuredWidth, 0, h, measure); + mComponentModifiers.setVerticalScrollDimension(measuredHeight, h); + } else { + computeSize(context, 0f, measuredWidth, 0f, measuredHeight, measure); + } } if (mContent != null) { @@ -168,6 +213,14 @@ public abstract class LayoutManager extends LayoutComponent implements Measurabl internalLayoutMeasure(context, measure); } + private boolean hasHorizontalScroll() { + return mComponentModifiers.hasHorizontalScroll(); + } + + private boolean hasVerticalScroll() { + return mComponentModifiers.hasVerticalScroll(); + } + /** basic layout of internal components */ @Override public void layout(@NonNull RemoteContext context, @NonNull MeasurePass measure) { 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 a366dc804758149fa8e2e85d59fc8e0433d36a13..0ce634f9c1ab69202c156aaaabac69b83dcdd774 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 @@ -19,6 +19,7 @@ import static com.android.internal.widget.remotecompose.core.documentation.Docum import static com.android.internal.widget.remotecompose.core.documentation.DocumentedOperation.INT; import android.annotation.NonNull; +import android.annotation.Nullable; import com.android.internal.widget.remotecompose.core.Operation; import com.android.internal.widget.remotecompose.core.Operations; @@ -51,7 +52,7 @@ public class RowLayout extends LayoutManager implements ComponentStartOperation float mSpacedBy = 0f; public RowLayout( - Component parent, + @Nullable Component parent, int componentId, int animationId, float x, @@ -68,7 +69,7 @@ public class RowLayout extends LayoutManager implements ComponentStartOperation } public RowLayout( - Component parent, + @Nullable Component parent, int componentId, int animationId, int horizontalPositioning, @@ -119,7 +120,7 @@ public class RowLayout extends LayoutManager implements ComponentStartOperation @Override public void computeWrapSize( - PaintContext context, + @NonNull PaintContext context, float maxWidth, float maxHeight, @NonNull MeasurePass measure, @@ -143,7 +144,7 @@ public class RowLayout extends LayoutManager implements ComponentStartOperation @Override public void computeSize( - PaintContext context, + @NonNull PaintContext context, float minWidth, float maxWidth, float minHeight, @@ -162,7 +163,17 @@ public class RowLayout extends LayoutManager implements ComponentStartOperation } @Override - public void internalLayoutMeasure(PaintContext context, @NonNull MeasurePass measure) { + public float intrinsicWidth() { + float width = computeModifierDefinedWidth(); + float componentWidths = 0f; + for (Component c : mChildrenComponents) { + componentWidths += c.intrinsicWidth(); + } + return Math.max(width, componentWidths); + } + + @Override + public void internalLayoutMeasure(@NonNull PaintContext context, @NonNull MeasurePass measure) { ComponentMeasure selfMeasure = measure.get(this); DebugLog.s( () -> @@ -186,6 +197,17 @@ public class RowLayout extends LayoutManager implements ComponentStartOperation float childrenWidth = 0f; float childrenHeight = 0f; + if (mComponentModifiers.hasHorizontalScroll()) { + selfWidth = + mComponentModifiers.getHorizontalScrollDimension() + - mPaddingLeft + - mPaddingRight; + } + if (mComponentModifiers.hasVerticalScroll()) { + selfHeight = + mComponentModifiers.getVerticalScrollDimension() - mPaddingTop - mPaddingBottom; + } + boolean hasWeights = false; float totalWeights = 0f; for (Component child : mChildrenComponents) { diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/layout/managers/StateLayout.java b/core/java/com/android/internal/widget/remotecompose/core/operations/layout/managers/StateLayout.java index e47ffdebb25397484422039da1dc8f1c49a2c6fb..73a104bcafa67935bab1511e1dc51ecbefec45b1 100644 --- a/core/java/com/android/internal/widget/remotecompose/core/operations/layout/managers/StateLayout.java +++ b/core/java/com/android/internal/widget/remotecompose/core/operations/layout/managers/StateLayout.java @@ -16,6 +16,7 @@ package com.android.internal.widget.remotecompose.core.operations.layout.managers; import android.annotation.NonNull; +import android.annotation.Nullable; import com.android.internal.widget.remotecompose.core.CoreDocument; import com.android.internal.widget.remotecompose.core.Operation; @@ -60,7 +61,7 @@ public class StateLayout extends LayoutManager implements ComponentStartOperatio public boolean inTransition = false; public StateLayout( - Component parent, + @Nullable Component parent, int componentId, int animationId, float x, @@ -132,21 +133,21 @@ public class StateLayout extends LayoutManager implements ComponentStartOperatio @Override public void computeSize( - PaintContext context, + @NonNull PaintContext context, float minWidth, float maxWidth, float minHeight, float maxHeight, - MeasurePass measure) { + @NonNull MeasurePass measure) { LayoutManager layout = getLayout(currentLayoutIndex); layout.computeSize(context, minWidth, maxWidth, minHeight, maxHeight, measure); } @Override public void internalLayoutMeasure( - PaintContext context, + @NonNull PaintContext context, // layoutInfo: LayoutInfo, - MeasurePass measure) { + @NonNull MeasurePass measure) { LayoutManager layout = getLayout(currentLayoutIndex); // layout.internalLayoutMeasure(context, layoutInfo, measure) layout.internalLayoutMeasure(context, measure); @@ -155,13 +156,18 @@ public class StateLayout extends LayoutManager implements ComponentStartOperatio /** Subclasses can implement this to provide wrap sizing */ @Override public void computeWrapSize( - PaintContext context, float maxWidth, float maxHeight, MeasurePass measure, Size size) { + @NonNull PaintContext context, + float maxWidth, + float maxHeight, + @NonNull MeasurePass measure, + @NonNull Size size) { LayoutManager layout = getLayout(currentLayoutIndex); layout.computeWrapSize(context, maxWidth, maxHeight, measure, size); } @Override - public void onClick(RemoteContext context, CoreDocument document, float x, float y) { + public void onClick( + @NonNull RemoteContext context, @NonNull CoreDocument document, float x, float y) { if (!contains(x, y)) { return; } @@ -352,7 +358,7 @@ public class StateLayout extends LayoutManager implements ComponentStartOperatio } } - public LayoutManager getLayout(int idx) { + public @NonNull LayoutManager getLayout(int idx) { int index = 0; for (Component pane : mChildrenComponents) { if (pane instanceof LayoutComponent) { 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 8aa7712635fc5473ce1b36909d2aab769f4206a2..a527e5ad40777fca20f1c40e6f41cd595da31f83 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 @@ -19,6 +19,7 @@ import static com.android.internal.widget.remotecompose.core.documentation.Docum import static com.android.internal.widget.remotecompose.core.documentation.DocumentedOperation.INT; import android.annotation.NonNull; +import android.annotation.Nullable; import com.android.internal.widget.remotecompose.core.Operation; import com.android.internal.widget.remotecompose.core.Operations; @@ -52,8 +53,9 @@ public class TextLayout extends LayoutManager implements ComponentStartOperation private float mTextX; private float mTextY; private float mTextW; + private float mTextH; - private String mCachedString = ""; + @Nullable private String mCachedString = ""; @Override public void registerListening(@NonNull RemoteContext context) { @@ -89,7 +91,7 @@ public class TextLayout extends LayoutManager implements ComponentStartOperation } public TextLayout( - Component parent, + @Nullable Component parent, int componentId, int animationId, float x, @@ -114,7 +116,7 @@ public class TextLayout extends LayoutManager implements ComponentStartOperation } public TextLayout( - Component parent, + @Nullable Component parent, int componentId, int animationId, int textId, @@ -162,6 +164,9 @@ public class TextLayout extends LayoutManager implements ComponentStartOperation mPaint.setTextSize(mFontSize); mPaint.setTextStyle(mType, (int) mFontWeight, mFontStyle == 1); context.applyPaint(mPaint); + if (mCachedString == null) { + return; + } int length = mCachedString.length(); context.drawTextRun(mTextId, 0, length, 0, 0, mTextX, mTextY, false); if (DEBUG) { @@ -241,7 +246,7 @@ public class TextLayout extends LayoutManager implements ComponentStartOperation @NonNull PaintContext context, float maxWidth, float maxHeight, - MeasurePass measure, + @NonNull MeasurePass measure, @NonNull Size size) { context.savePaint(); mPaint.reset(); @@ -250,6 +255,9 @@ public class TextLayout extends LayoutManager implements ComponentStartOperation context.applyPaint(mPaint); float[] bounds = new float[4]; int flags = PaintContext.TEXT_MEASURE_FONT_HEIGHT; + if (mCachedString == null) { + return; + } context.getTextBounds(mTextId, 0, mCachedString.length(), flags, bounds); context.restorePaint(); float w = bounds[2] - bounds[0]; @@ -259,6 +267,17 @@ public class TextLayout extends LayoutManager implements ComponentStartOperation size.setHeight(h); mTextY = -bounds[1]; mTextW = w; + mTextH = h; + } + + @Override + public float intrinsicHeight() { + return mTextH; + } + + @Override + public float intrinsicWidth() { + return mTextW; } @NonNull diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/layout/measure/ComponentMeasure.java b/core/java/com/android/internal/widget/remotecompose/core/operations/layout/measure/ComponentMeasure.java index 426e02337f5bac42ca72bfcc1551837f0faf3f14..82f23cdcf7668cf5fec106362e30f05cc2d3d478 100644 --- a/core/java/com/android/internal/widget/remotecompose/core/operations/layout/measure/ComponentMeasure.java +++ b/core/java/com/android/internal/widget/remotecompose/core/operations/layout/measure/ComponentMeasure.java @@ -26,7 +26,7 @@ public class ComponentMeasure { float mY; float mW; float mH; - Component.Visibility mVisibility = Component.Visibility.VISIBLE; + @NonNull Component.Visibility mVisibility = Component.Visibility.VISIBLE; public void setX(float value) { mX = value; @@ -60,16 +60,16 @@ public class ComponentMeasure { return mH; } - public Component.Visibility getVisibility() { + public @NonNull Component.Visibility getVisibility() { return mVisibility; } - public void setVisibility(Component.Visibility visibility) { + public void setVisibility(@NonNull Component.Visibility visibility) { mVisibility = visibility; } public ComponentMeasure( - int id, float x, float y, float w, float h, Component.Visibility visibility) { + int id, float x, float y, float w, float h, @NonNull Component.Visibility visibility) { this.mId = id; this.mX = x; this.mY = y; 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 b48c2d5ae88b868d0cab41936252816a9d6a6bdc..fbf2784be84357dfe5b21e2a506898400821c6b9 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 @@ -15,6 +15,8 @@ */ package com.android.internal.widget.remotecompose.core.operations.layout.measure; +import android.annotation.NonNull; + import com.android.internal.widget.remotecompose.core.PaintContext; import com.android.internal.widget.remotecompose.core.RemoteContext; @@ -26,15 +28,15 @@ public interface Measurable { * does not apply the measure to the component. */ void measure( - PaintContext context, + @NonNull PaintContext context, float minWidth, float maxWidth, float minHeight, float maxHeight, - MeasurePass measure); + @NonNull MeasurePass measure); /** Apply a given measure to the component */ - void layout(RemoteContext context, MeasurePass measure); + void layout(@NonNull RemoteContext context, @NonNull MeasurePass measure); /** * Return true if the component needs to be remeasured diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/layout/measure/MeasurePass.java b/core/java/com/android/internal/widget/remotecompose/core/operations/layout/measure/MeasurePass.java index 112ab1b93474825871791eecd17d3b5302e44463..5cfb1b43cf15e0df73cdec3b61748b21c4413c9b 100644 --- a/core/java/com/android/internal/widget/remotecompose/core/operations/layout/measure/MeasurePass.java +++ b/core/java/com/android/internal/widget/remotecompose/core/operations/layout/measure/MeasurePass.java @@ -43,7 +43,7 @@ public class MeasurePass { return mList.containsKey(id); } - public ComponentMeasure get(@NonNull Component c) { + public @NonNull ComponentMeasure get(@NonNull Component c) { if (!mList.containsKey(c.getComponentId())) { ComponentMeasure measure = new ComponentMeasure( @@ -54,7 +54,7 @@ public class MeasurePass { return mList.get(c.getComponentId()); } - public ComponentMeasure get(int id) { + public @NonNull ComponentMeasure get(int id) { if (!mList.containsKey(id)) { ComponentMeasure measure = new ComponentMeasure(id, 0f, 0f, 0f, 0f, Component.Visibility.GONE); 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 76a97ca0eb51ee3987c2e3d2b89d2f935275d703..71d2ba6edf21a39ee979ae745e5c3f991d560488 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 @@ -98,7 +98,7 @@ public class BackgroundModifierOperation extends DecoratorModifierOperation { } @Override - public void layout(RemoteContext context, float width, float height) { + public void layout(@NonNull RemoteContext context, float width, float height) { this.mWidth = width; this.mHeight = height; } 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 d48a9c732cd52053f924f7d5534c6fa26c14bd8b..0707cd62767802a8e0b4d4da011508f98679e26c 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 @@ -124,7 +124,7 @@ public class BorderModifierOperation extends DecoratorModifierOperation { } @Override - public void layout(RemoteContext context, float width, float height) { + public void layout(@NonNull RemoteContext context, float width, float height) { this.mWidth = width; this.mHeight = height; } 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 78b51c3f83aa7fe6cbfb678243a069ce9cf34fcf..e05b02781e10283c7a81ba3367f572b9e8dff0e8 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 @@ -40,7 +40,7 @@ public class ClipRectModifierOperation extends DecoratorModifierOperation { } @Override - public void layout(RemoteContext context, float width, float height) { + public void layout(@NonNull RemoteContext context, float width, float height) { this.mWidth = width; this.mHeight = height; } @@ -68,7 +68,7 @@ public class ClipRectModifierOperation extends DecoratorModifierOperation { buffer.start(OP_CODE); } - public static void read(WireBuffer buffer, @NonNull List operations) { + public static void read(@NonNull WireBuffer buffer, @NonNull List operations) { operations.add(new ClipRectModifierOperation()); } 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 011d7edd18c8e89e74244226550829e28fd81731..d11f26f83ebd370bbb422947888d2d007414737f 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 @@ -62,7 +62,7 @@ public class ComponentModifiers extends PaintOperation } @Override - public void write(WireBuffer buffer) { + public void write(@NonNull WireBuffer buffer) { // nothing } @@ -73,7 +73,7 @@ public class ComponentModifiers extends PaintOperation } } - public void add(ModifierOperation operation) { + public void add(@NonNull ModifierOperation operation) { mList.add(operation); } @@ -109,7 +109,7 @@ public class ComponentModifiers extends PaintOperation } @Override - public void layout(RemoteContext context, float width, float height) { + public void layout(@NonNull RemoteContext context, float width, float height) { float w = width; float h = height; for (ModifierOperation op : mList) { @@ -126,13 +126,17 @@ public class ComponentModifiers extends PaintOperation } } - public void addAll(ArrayList operations) { + public void addAll(@NonNull ArrayList operations) { mList.addAll(operations); } @Override public void onClick( - RemoteContext context, CoreDocument document, Component component, float x, float y) { + @NonNull RemoteContext context, + @NonNull CoreDocument document, + @NonNull Component component, + float x, + float y) { for (ModifierOperation op : mList) { if (op instanceof ClickHandler) { ((ClickHandler) op).onClick(context, document, component, x, y); @@ -169,4 +173,110 @@ public class ComponentModifiers extends PaintOperation } } } + + @Override + public void onTouchDrag( + RemoteContext context, CoreDocument document, Component component, float x, float y) { + for (ModifierOperation op : mList) { + if (op instanceof TouchHandler) { + ((TouchHandler) op).onTouchDrag(context, document, component, x, y); + } + } + } + + public boolean hasHorizontalScroll() { + for (ModifierOperation op : mList) { + if (op instanceof ScrollModifierOperation) { + ScrollModifierOperation scrollModifier = (ScrollModifierOperation) op; + if (scrollModifier.isHorizontalScroll()) { + return true; + } + } + } + return false; + } + + public boolean hasVerticalScroll() { + for (ModifierOperation op : mList) { + if (op instanceof ScrollModifierOperation) { + ScrollModifierOperation scrollModifier = (ScrollModifierOperation) op; + if (scrollModifier.isVerticalScroll()) { + return true; + } + } + } + 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) { + ScrollModifierOperation scrollModifier = (ScrollModifierOperation) op; + if (scrollModifier.isHorizontalScroll()) { + scrollModifier.setHorizontalScrollDimension(hostDimension, contentDimension); + } + } + } + } + + public void setVerticalScrollDimension(float hostDimension, float contentDimension) { + for (ModifierOperation op : mList) { + if (op instanceof ScrollModifierOperation) { + ScrollModifierOperation scrollModifier = (ScrollModifierOperation) op; + if (scrollModifier.isVerticalScroll()) { + scrollModifier.setVerticalScrollDimension(hostDimension, contentDimension); + } + } + } + } + + public float getHorizontalScrollDimension() { + for (ModifierOperation op : mList) { + if (op instanceof ScrollModifierOperation) { + ScrollModifierOperation scrollModifier = (ScrollModifierOperation) op; + if (scrollModifier.isHorizontalScroll()) { + return scrollModifier.getContentDimension(); + } + } + } + return 0f; + } + + public float getVerticalScrollDimension() { + for (ModifierOperation op : mList) { + if (op instanceof ScrollModifierOperation) { + ScrollModifierOperation scrollModifier = (ScrollModifierOperation) op; + if (scrollModifier.isVerticalScroll()) { + return scrollModifier.getContentDimension(); + } + } + } + return 0f; + } } 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 26e737b32027231e166e11742fb6b09bc36cdc3b..471db0bedb1198e7bdedff8a706f858221209043 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 @@ -63,16 +63,16 @@ public class ComponentVisibilityOperation } @Override - public void apply(RemoteContext context) {} + public void apply(@NonNull RemoteContext context) {} @NonNull @Override - public String deepToString(@Nullable String indent) { + public String deepToString(@NonNull String indent) { return (indent != null ? indent : "") + toString(); } @Override - public void write(WireBuffer buffer) {} + public void write(@NonNull WireBuffer buffer) {} public static void apply(@NonNull WireBuffer buffer, int valueId) { buffer.start(OP_CODE); @@ -114,10 +114,10 @@ public class ComponentVisibilityOperation } } - public void setParent(LayoutComponent parent) { + public void setParent(@Nullable LayoutComponent parent) { mParent = parent; } @Override - public void layout(RemoteContext context, float width, float height) {} + public void layout(@NonNull RemoteContext context, float width, float height) {} } diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/layout/modifiers/DimensionModifierOperation.java b/core/java/com/android/internal/widget/remotecompose/core/operations/layout/modifiers/DimensionModifierOperation.java index 3c2d85cfee5bbdf120e92dc7b2971f63073fcad8..b9324f0320d36392e30b24b73c7715f5044a80a8 100644 --- a/core/java/com/android/internal/widget/remotecompose/core/operations/layout/modifiers/DimensionModifierOperation.java +++ b/core/java/com/android/internal/widget/remotecompose/core/operations/layout/modifiers/DimensionModifierOperation.java @@ -16,7 +16,6 @@ package com.android.internal.widget.remotecompose.core.operations.layout.modifiers; import android.annotation.NonNull; -import android.annotation.Nullable; import com.android.internal.widget.remotecompose.core.RemoteContext; import com.android.internal.widget.remotecompose.core.VariableSupport; @@ -57,16 +56,16 @@ public abstract class DimensionModifierOperation implements ModifierOperation, V } } - Type mType = Type.EXACT; + @NonNull Type mType = Type.EXACT; float mValue = Float.NaN; float mOutValue = Float.NaN; - public DimensionModifierOperation(Type type, float value) { + public DimensionModifierOperation(@NonNull Type type, float value) { mType = type; mOutValue = mValue = value; } - public DimensionModifierOperation(Type type) { + public DimensionModifierOperation(@NonNull Type type) { this(type, Float.NaN); } @@ -115,7 +114,15 @@ public abstract class DimensionModifierOperation implements ModifierOperation, V return mType == Type.FILL; } - public Type getType() { + public boolean isIntrinsicMin() { + return mType == Type.INTRINSIC_MIN; + } + + public boolean isIntrinsicMax() { + return mType == Type.INTRINSIC_MAX; + } + + public @NonNull Type getType() { return mType; } @@ -143,11 +150,11 @@ public abstract class DimensionModifierOperation implements ModifierOperation, V } @Override - public void apply(RemoteContext context) {} + public void apply(@NonNull RemoteContext context) {} @NonNull @Override - public String deepToString(@Nullable String indent) { + public String deepToString(@NonNull String indent) { return (indent != null ? indent : "") + toString(); } 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 2b3038281d57fd6307a98fba621c717ff9a2dcf9..571e554b9c71136ab44ef3c1dcb9cc18b992bd67 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 @@ -18,6 +18,8 @@ package com.android.internal.widget.remotecompose.core.operations.layout.modifie import static com.android.internal.widget.remotecompose.core.documentation.DocumentedOperation.FLOAT; import static com.android.internal.widget.remotecompose.core.documentation.DocumentedOperation.INT; +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; @@ -175,8 +177,9 @@ public class GraphicsLayerModifierOperation extends DecoratorModifierOperation { serializer.append(indent, "GRAPHICS_LAYER = [" + mScaleX + ", " + mScaleY + "]"); } + @NonNull @Override - public String deepToString(String indent) { + public String deepToString(@NonNull String indent) { return (indent != null ? indent : "") + toString(); } 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 97c76c0aedf7343dacb4b7d2b43c93a43f9039fd..7bb4a756afa577d39933a0d2895aa4af8f65800e 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 @@ -59,11 +59,11 @@ public class HeightModifierOperation extends DimensionModifierOperation { apply(buffer, mType.ordinal(), mValue); } - public HeightModifierOperation(Type type, float value) { + public HeightModifierOperation(@NonNull Type type, float value) { super(type, value); } - public HeightModifierOperation(Type type) { + public HeightModifierOperation(@NonNull Type type) { super(type); } 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 836321fff8e6d93ed5023c291ef2d72789bb7bbf..d239bc85744634f61e948fcb67b57bc54f9a034f 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 @@ -18,7 +18,6 @@ package com.android.internal.widget.remotecompose.core.operations.layout.modifie import static com.android.internal.widget.remotecompose.core.documentation.DocumentedOperation.INT; import android.annotation.NonNull; -import android.annotation.Nullable; import com.android.internal.widget.remotecompose.core.CoreDocument; import com.android.internal.widget.remotecompose.core.Operation; @@ -63,22 +62,22 @@ public class HostActionOperation implements ActionOperation { } @Override - public void apply(RemoteContext context) {} + public void apply(@NonNull RemoteContext context) {} @NonNull @Override - public String deepToString(@Nullable String indent) { + public String deepToString(@NonNull String indent) { return (indent != null ? indent : "") + toString(); } @Override - public void write(WireBuffer buffer) {} + public void write(@NonNull WireBuffer buffer) {} @Override public void runAction( @NonNull RemoteContext context, - CoreDocument document, - Component component, + @NonNull CoreDocument document, + @NonNull Component component, float x, float y) { context.runAction(mActionId, ""); 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 e97e89784a230baeb2fd467d6d8b0b068f3b2408..3268e5efd4492f976e9928495aec24e524a469ed 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 @@ -18,7 +18,6 @@ package com.android.internal.widget.remotecompose.core.operations.layout.modifie import static com.android.internal.widget.remotecompose.core.documentation.DocumentedOperation.INT; import android.annotation.NonNull; -import android.annotation.Nullable; import com.android.internal.widget.remotecompose.core.CoreDocument; import com.android.internal.widget.remotecompose.core.Operation; @@ -39,6 +38,7 @@ public class HostNamedActionOperation implements ActionOperation { public static final int FLOAT_TYPE = 0; public static final int INT_TYPE = 1; public static final int STRING_TYPE = 2; + public static final int FLOAT_ARRAY_TYPE = 3; public static final int NONE_TYPE = -1; int mTextId = -1; @@ -72,22 +72,22 @@ public class HostNamedActionOperation implements ActionOperation { } @Override - public void apply(RemoteContext context) {} + public void apply(@NonNull RemoteContext context) {} @NonNull @Override - public String deepToString(@Nullable String indent) { + public String deepToString(@NonNull String indent) { return (indent != null ? indent : "") + toString(); } @Override - public void write(WireBuffer buffer) {} + public void write(@NonNull WireBuffer buffer) {} @Override public void runAction( @NonNull RemoteContext context, - CoreDocument document, - Component component, + @NonNull CoreDocument document, + @NonNull Component component, float x, float y) { Object value = null; @@ -98,6 +98,8 @@ public class HostNamedActionOperation implements ActionOperation { value = context.mRemoteComposeState.getFromId(mValueId); } else if (mType == FLOAT_TYPE) { value = context.mRemoteComposeState.getFloat(mValueId); + } else if (mType == FLOAT_ARRAY_TYPE) { + value = context.mRemoteComposeState.getFloats(mValueId); } } context.runNamedAction(mTextId, value); diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/layout/modifiers/ModifierOperation.java b/core/java/com/android/internal/widget/remotecompose/core/operations/layout/modifiers/ModifierOperation.java index 50f098e25f6af068cf2a249ea0f5af2983b47dbb..8f08f1417add3cf44e5800c17cb2f4092d07df7a 100644 --- a/core/java/com/android/internal/widget/remotecompose/core/operations/layout/modifiers/ModifierOperation.java +++ b/core/java/com/android/internal/widget/remotecompose/core/operations/layout/modifiers/ModifierOperation.java @@ -15,10 +15,12 @@ */ package com.android.internal.widget.remotecompose.core.operations.layout.modifiers; +import android.annotation.NonNull; + import com.android.internal.widget.remotecompose.core.Operation; import com.android.internal.widget.remotecompose.core.operations.utilities.StringSerializer; /** Represents a modifier */ public interface ModifierOperation extends Operation { - void serializeToString(int indent, StringSerializer serializer); + void serializeToString(int indent, @NonNull StringSerializer serializer); } 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 65fe345ac920aa3471aaade1516fc86dd930b447..8c07059369ab39d090d922e21e6f677deaef60db 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 @@ -17,6 +17,8 @@ package com.android.internal.widget.remotecompose.core.operations.layout.modifie 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; @@ -67,8 +69,9 @@ public class OffsetModifierOperation extends DecoratorModifierOperation { serializer.append(indent, "OFFSET = [" + mX + ", " + mY + "]"); } + @NonNull @Override - public String deepToString(String indent) { + public String deepToString(@NonNull String indent) { return (indent != null ? indent : "") + toString(); } 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 ed5522ea865f8dbc2bfb1952c1189adb2d71c412..2b6621e4fd58dcb05744c09d9d18df7d18c26c13 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 @@ -18,7 +18,6 @@ package com.android.internal.widget.remotecompose.core.operations.layout.modifie import static com.android.internal.widget.remotecompose.core.documentation.DocumentedOperation.FLOAT; import android.annotation.NonNull; -import android.annotation.Nullable; import com.android.internal.widget.remotecompose.core.Operation; import com.android.internal.widget.remotecompose.core.Operations; @@ -92,11 +91,11 @@ public class PaddingModifierOperation implements ModifierOperation { } @Override - public void apply(RemoteContext context) {} + public void apply(@NonNull RemoteContext context) {} @NonNull @Override - public String deepToString(@Nullable String indent) { + public String deepToString(@NonNull String indent) { return (indent != null ? indent : "") + toString(); } 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 6218dd5f331110ab413a5b90a7c61e18ecea713f..3fefc58172709d2ebcefa08825b64aad1efef268 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 @@ -96,7 +96,7 @@ public class RoundedClipRectModifierOperation extends DrawBase4 } @Override - public void layout(RemoteContext context, float width, float height) { + public void layout(@NonNull RemoteContext context, 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 new file mode 100644 index 0000000000000000000000000000000000000000..8dcfed999c5c5bd82e4110934ea95424d9937490 --- /dev/null +++ b/core/java/com/android/internal/widget/remotecompose/core/operations/layout/modifiers/ScrollModifierOperation.java @@ -0,0 +1,227 @@ +/* + * 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.INT; + +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.utilities.StringSerializer; + +import java.util.List; + +/** Represents a scroll modifier. */ +public class ScrollModifierOperation extends DecoratorModifierOperation implements TouchHandler { + private static final int OP_CODE = Operations.MODIFIER_SCROLL; + public static final String CLASS_NAME = "ScrollModifierOperation"; + + private final float mPositionExpression; + private final float mMax; + private final float mNotchMax; + + float mWidth = 0; + float mHeight = 0; + + int mDirection; + + float mTouchDownX; + float mTouchDownY; + + float mInitialScrollX; + float mInitialScrollY; + + float mScrollX; + float mScrollY; + + float mMaxScrollX; + float mMaxScrollY; + + float mHostDimension; + float mContentDimension; + + public ScrollModifierOperation(int direction, float position, float max, float notchMax) { + this.mDirection = direction; + this.mPositionExpression = position; + this.mMax = max; + this.mNotchMax = notchMax; + } + + public boolean isVerticalScroll() { + return mDirection == 0; + } + + public boolean isHorizontalScroll() { + return mDirection != 0; + } + + public float getScrollX() { + return mScrollX; + } + + public float getScrollY() { + return mScrollY; + } + + @Override + public void apply(RemoteContext context) { + RootLayoutComponent root = context.getDocument().getRootLayoutComponent(); + if (root != null) { + root.setHasTouchListeners(true); + } + super.apply(context); + } + + @Override + public void write(WireBuffer buffer) { + apply(buffer, mDirection, mPositionExpression, mMax, mNotchMax); + } + + // @Override + public void serializeToString(int indent, StringSerializer serializer) { + serializer.append(indent, "SCROLL = [" + mDirection + "]"); + } + + @NonNull + @Override + public String deepToString(@NonNull String indent) { + return (indent != null ? indent : "") + toString(); + } + + @Override + public void paint(PaintContext context) { + float position = + context.getContext() + .mRemoteComposeState + .getFloat(Utils.idFromNan(mPositionExpression)); + + if (mDirection == 0) { + mScrollY = -position; + } else { + mScrollX = -position; + } + } + + @Override + public String toString() { + return "ScrollModifierOperation(" + mDirection + ")"; + } + + public static String name() { + return CLASS_NAME; + } + + public static int id() { + return OP_CODE; + } + + public static void apply( + WireBuffer buffer, int direction, float position, float max, float notchMax) { + buffer.start(OP_CODE); + buffer.writeInt(direction); + buffer.writeFloat(position); + buffer.writeFloat(max); + buffer.writeFloat(notchMax); + } + + public static void read(WireBuffer buffer, List operations) { + int direction = buffer.readInt(); + float position = buffer.readFloat(); + float max = buffer.readFloat(); + float notchMax = buffer.readFloat(); + operations.add(new ScrollModifierOperation(direction, position, max, notchMax)); + } + + public static void documentation(DocumentationBuilder doc) { + doc.operation("Modifier Operations", OP_CODE, CLASS_NAME) + .description("define a Scroll Modifier") + .field(INT, "direction", ""); + } + + @Override + public void layout(RemoteContext context, float width, float height) { + mWidth = width; + mHeight = height; + if (mDirection == 0) { // VERTICAL + context.loadFloat(Utils.idFromNan(mMax), mMaxScrollY); + context.loadFloat(Utils.idFromNan(mNotchMax), mContentDimension); + } else { + context.loadFloat(Utils.idFromNan(mMax), mMaxScrollX); + context.loadFloat(Utils.idFromNan(mNotchMax), mContentDimension); + } + } + + @Override + public void onTouchDown( + RemoteContext context, CoreDocument document, Component component, float x, float y) { + mTouchDownX = x; + mTouchDownY = y; + mInitialScrollX = mScrollX; + mInitialScrollY = mScrollY; + document.appliedTouchOperation(component); + } + + @Override + public void onTouchUp( + RemoteContext context, CoreDocument document, Component component, float x, float y) { + // If not using touch expression, should add velocity decay here + } + + @Override + public void onTouchDrag( + RemoteContext context, CoreDocument document, Component component, float x, float y) { + float dx = x - mTouchDownX; + float dy = y - mTouchDownY; + + if (!Utils.isVariable(mPositionExpression)) { + if (mDirection == 0) { + mScrollY = Math.max(-mMaxScrollY, Math.min(0, mInitialScrollY + dy)); + } else { + mScrollX = Math.max(-mMaxScrollX, Math.min(0, mInitialScrollX + dx)); + } + } + } + + @Override + public void onTouchCancel( + RemoteContext context, CoreDocument document, Component component, float x, float y) {} + + public void setHorizontalScrollDimension(float hostDimension, float contentDimension) { + mHostDimension = hostDimension; + mContentDimension = contentDimension; + mMaxScrollX = contentDimension - hostDimension; + } + + public void setVerticalScrollDimension(float hostDimension, float contentDimension) { + mHostDimension = hostDimension; + mContentDimension = contentDimension; + mMaxScrollY = contentDimension - hostDimension; + } + + public float getContentDimension() { + return mContentDimension; + } +} 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 29ec82810a7c679b537408f915a2a502577597cb..a97fcffdf75cedcaa3a3e3c1945c549dca7282c8 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 @@ -18,6 +18,8 @@ package com.android.internal.widget.remotecompose.core.operations.layout.modifie import static com.android.internal.widget.remotecompose.core.documentation.DocumentedOperation.FLOAT; import static com.android.internal.widget.remotecompose.core.documentation.DocumentedOperation.INT; +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; @@ -59,8 +61,9 @@ public class ValueFloatChangeActionOperation implements ActionOperation { @Override public void apply(RemoteContext context) {} + @NonNull @Override - public String deepToString(String indent) { + public String deepToString(@NonNull String indent) { return (indent != null ? indent : "") + toString(); } 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 new file mode 100644 index 0000000000000000000000000000000000000000..41586b4939a6140ada63df8ae1a221ff514ea26a --- /dev/null +++ b/core/java/com/android/internal/widget/remotecompose/core/operations/layout/modifiers/ValueFloatExpressionChangeActionOperation.java @@ -0,0 +1,105 @@ +/* + * 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.INT; + +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.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.ActionOperation; +import com.android.internal.widget.remotecompose.core.operations.layout.Component; +import com.android.internal.widget.remotecompose.core.operations.utilities.StringSerializer; + +import java.util.List; + +/** Apply a value change on an integer variable. */ +public class ValueFloatExpressionChangeActionOperation implements ActionOperation { + private static final int OP_CODE = Operations.VALUE_FLOAT_EXPRESSION_CHANGE_ACTION; + + int mTargetValueId = -1; + int mValueExpressionId = -1; + + public ValueFloatExpressionChangeActionOperation(int id, int valueId) { + mTargetValueId = id; + mValueExpressionId = valueId; + } + + @NonNull + @Override + public String toString() { + return "ValueFloatExpressionChangeActionOperation(" + mTargetValueId + ")"; + } + + @NonNull + public String serializedName() { + return "VALUE_FLOAT_EXPRESSION_CHANGE"; + } + + @Override + public void serializeToString(int indent, @NonNull StringSerializer serializer) { + serializer.append( + indent, serializedName() + " = " + mTargetValueId + " -> " + mValueExpressionId); + } + + @Override + public void apply(RemoteContext context) {} + + @NonNull + @Override + public String deepToString(@NonNull String indent) { + return (indent != null ? indent : "") + toString(); + } + + @Override + public void write(WireBuffer buffer) {} + + @Override + public void runAction( + @NonNull RemoteContext context, + @NonNull CoreDocument document, + Component component, + float x, + float y) { + document.evaluateFloatExpression(mValueExpressionId, mTargetValueId, context); + } + + public static void apply(@NonNull WireBuffer buffer, int valueId, int value) { + buffer.start(OP_CODE); + buffer.writeInt(valueId); + buffer.writeInt(value); + } + + public static void read(@NonNull WireBuffer buffer, @NonNull List operations) { + int valueId = buffer.readInt(); + int value = buffer.readInt(); + operations.add(new ValueFloatExpressionChangeActionOperation(valueId, value)); + } + + public static void documentation(@NonNull DocumentationBuilder doc) { + doc.operation("Layout Operations", OP_CODE, "ValueIntegerExpressionChangeActionOperation") + .description( + "ValueIntegerExpressionChange action. " + + " This operation represents a value change for the given id") + .field(INT, "TARGET_VALUE_ID", "Value ID") + .field(INT, "VALUE_ID", "id of the value to be assigned to the target"); + } +} 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 d7ce8acc72bfdb8ff9f8b3eb4659b90ce10dd9d9..c2cd2ab32bb7da60dffd0549d48a9351b1beb4cf 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 @@ -18,7 +18,6 @@ package com.android.internal.widget.remotecompose.core.operations.layout.modifie import static com.android.internal.widget.remotecompose.core.documentation.DocumentedOperation.INT; import android.annotation.NonNull; -import android.annotation.Nullable; import com.android.internal.widget.remotecompose.core.CoreDocument; import com.android.internal.widget.remotecompose.core.Operation; @@ -61,22 +60,22 @@ public class ValueIntegerChangeActionOperation implements ActionOperation { } @Override - public void apply(RemoteContext context) {} + public void apply(@NonNull RemoteContext context) {} @NonNull @Override - public String deepToString(@Nullable String indent) { + public String deepToString(@NonNull String indent) { return (indent != null ? indent : "") + toString(); } @Override - public void write(WireBuffer buffer) {} + public void write(@NonNull WireBuffer buffer) {} @Override public void runAction( @NonNull RemoteContext context, - CoreDocument document, - Component component, + @NonNull CoreDocument document, + @NonNull Component component, float x, float y) { context.overrideInteger(mTargetValueId, mValue); 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 75d13e785d4c49c4c5e644ccfbc1135666dce59a..43fbb8546b9d137ac43d14bfe5f3612815b31692 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 @@ -18,7 +18,6 @@ package com.android.internal.widget.remotecompose.core.operations.layout.modifie import static com.android.internal.widget.remotecompose.core.documentation.DocumentedOperation.INT; import android.annotation.NonNull; -import android.annotation.Nullable; import com.android.internal.widget.remotecompose.core.CoreDocument; import com.android.internal.widget.remotecompose.core.Operation; @@ -62,22 +61,22 @@ public class ValueIntegerExpressionChangeActionOperation implements ActionOperat } @Override - public void apply(RemoteContext context) {} + public void apply(@NonNull RemoteContext context) {} @NonNull @Override - public String deepToString(@Nullable String indent) { + public String deepToString(@NonNull String indent) { return (indent != null ? indent : "") + toString(); } @Override - public void write(WireBuffer buffer) {} + public void write(@NonNull WireBuffer buffer) {} @Override public void runAction( @NonNull RemoteContext context, @NonNull CoreDocument document, - Component component, + @NonNull Component component, float x, float y) { document.evaluateIntExpression(mValueExpressionId, (int) mTargetValueId, context); 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 26d7244eee8c95c5a76707a23e095b30357fc306..1107889faaab77fec396ebe2038ba5026aac345e 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 @@ -18,7 +18,6 @@ package com.android.internal.widget.remotecompose.core.operations.layout.modifie import static com.android.internal.widget.remotecompose.core.documentation.DocumentedOperation.INT; import android.annotation.NonNull; -import android.annotation.Nullable; import com.android.internal.widget.remotecompose.core.CoreDocument; import com.android.internal.widget.remotecompose.core.Operation; @@ -65,22 +64,22 @@ public class ValueStringChangeActionOperation implements ActionOperation { } @Override - public void apply(RemoteContext context) {} + public void apply(@NonNull RemoteContext context) {} @NonNull @Override - public String deepToString(@Nullable String indent) { + public String deepToString(@NonNull String indent) { return (indent != null ? indent : "") + toString(); } @Override - public void write(WireBuffer buffer) {} + public void write(@NonNull WireBuffer buffer) {} @Override public void runAction( @NonNull RemoteContext context, - CoreDocument document, - Component component, + @NonNull CoreDocument document, + @NonNull Component component, float x, float y) { context.overrideText(mTargetValueId, mValueId); 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 e2f899ce2b462535eab01a063bb274544572228b..3c757a893a57089f7f33c2d860f22c5b9d262824 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 @@ -54,7 +54,7 @@ public class WidthModifierOperation extends DimensionModifierOperation { operations.add(op); } - public WidthModifierOperation(Type type, float value) { + public WidthModifierOperation(@NonNull Type type, float value) { super(type, value); } @@ -63,7 +63,7 @@ public class WidthModifierOperation extends DimensionModifierOperation { apply(buffer, mType.ordinal(), mValue); } - public WidthModifierOperation(Type type) { + public WidthModifierOperation(@NonNull Type type) { super(type); } 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 aa20e0388d31b305fcc88802022690ad649475c9..82c8f343565e1f94e6ef410c9cfe0a7b291bbd80 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 @@ -17,6 +17,8 @@ package com.android.internal.widget.remotecompose.core.operations.layout.modifie 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; @@ -57,8 +59,9 @@ public class ZIndexModifierOperation extends DecoratorModifierOperation { serializer.append(indent, "ZINDEX = [" + mValue + "]"); } + @NonNull @Override - public String deepToString(String indent) { + public String deepToString(@NonNull String indent) { return (indent != null ? indent : "") + toString(); } diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/layout/utils/DebugLog.java b/core/java/com/android/internal/widget/remotecompose/core/operations/layout/utils/DebugLog.java index d8e49b0a9ccd3438107a97cc2291fca4dc08b6c3..842c9c161aee2d234af02b71f5edb0d6b1df1971 100644 --- a/core/java/com/android/internal/widget/remotecompose/core/operations/layout/utils/DebugLog.java +++ b/core/java/com/android/internal/widget/remotecompose/core/operations/layout/utils/DebugLog.java @@ -27,11 +27,11 @@ public class DebugLog { public static class Node { @Nullable public Node parent; - public String name; - public String endString; + @NonNull public String name; + @NonNull public String endString; @NonNull public ArrayList list = new ArrayList<>(); - public Node(@Nullable Node parent, String name) { + public Node(@Nullable Node parent, @NonNull String name) { this.parent = parent; this.name = name; this.endString = name + " DONE"; @@ -40,13 +40,13 @@ public class DebugLog { } } - public void add(Node node) { + public void add(@NonNull Node node) { list.add(node); } } public static class LogNode extends Node { - public LogNode(Node parent, String name) { + public LogNode(@Nullable Node parent, @NonNull String name) { super(parent, name); } } diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/layout/utils/StringValueSupplier.java b/core/java/com/android/internal/widget/remotecompose/core/operations/layout/utils/StringValueSupplier.java index 701167abb8f00529b22a7a87939578a5c88e63bd..5ec149390b84f05d174e8f5e3548c75a77c6a7e1 100644 --- a/core/java/com/android/internal/widget/remotecompose/core/operations/layout/utils/StringValueSupplier.java +++ b/core/java/com/android/internal/widget/remotecompose/core/operations/layout/utils/StringValueSupplier.java @@ -15,6 +15,8 @@ */ package com.android.internal.widget.remotecompose.core.operations.layout.utils; +import android.annotation.NonNull; + /** Basic interface for a lambda (used for logging) */ public interface StringValueSupplier { /** @@ -22,5 +24,6 @@ public interface StringValueSupplier { * * @return a string */ + @NonNull String getString(); } diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/paint/PaintBundle.java b/core/java/com/android/internal/widget/remotecompose/core/operations/paint/PaintBundle.java index e714947c6a5c229cf6eb4c6a867ada38df964082..07cf7627e24d0a00a342f9edf14f46987114bafb 100644 --- a/core/java/com/android/internal/widget/remotecompose/core/operations/paint/PaintBundle.java +++ b/core/java/com/android/internal/widget/remotecompose/core/operations/paint/PaintBundle.java @@ -15,6 +15,9 @@ */ package com.android.internal.widget.remotecompose.core.operations.paint; +import android.annotation.NonNull; +import android.annotation.Nullable; + import com.android.internal.widget.remotecompose.core.PaintContext; import com.android.internal.widget.remotecompose.core.RemoteContext; import com.android.internal.widget.remotecompose.core.VariableSupport; @@ -25,8 +28,8 @@ import java.util.Arrays; /** Paint Bundle represents a delta of changes to a paint object */ public class PaintBundle { - int[] mArray = new int[200]; - int[] mOutArray = null; + @NonNull int[] mArray = new int[200]; + @Nullable int[] mOutArray = null; int mPos = 0; /** @@ -35,7 +38,7 @@ public class PaintBundle { * @param paintContext * @param p */ - public void applyPaintChange(PaintContext paintContext, PaintChanges p) { + public void applyPaintChange(@NonNull PaintContext paintContext, @NonNull PaintChanges p) { int i = 0; int mask = 0; if (mOutArray == null) { @@ -138,12 +141,14 @@ public class PaintBundle { // return "????" + id + "????"; // } + @NonNull private static String colorInt(int color) { String str = "000000000000" + Integer.toHexString(color); return "0x" + str.substring(str.length() - 8); } - private static String colorInt(int[] color) { + @NonNull + private static String colorInt(@NonNull int[] color) { String str = "["; for (int i = 0; i < color.length; i++) { if (i > 0) { @@ -162,6 +167,7 @@ public class PaintBundle { return Float.toString(fValue); } + @NonNull @Override public String toString() { StringBuilder ret = new StringBuilder("\n"); @@ -244,7 +250,8 @@ public class PaintBundle { return ret.toString(); } - private void registerFloat(int iv, RemoteContext context, VariableSupport support) { + private void registerFloat( + int iv, @NonNull RemoteContext context, @NonNull VariableSupport support) { float v = Float.intBitsToFloat(iv); if (Float.isNaN(v)) { context.listensTo(Utils.idFromNan(v), support); @@ -252,7 +259,11 @@ public class PaintBundle { } int callRegisterGradient( - int cmd, int[] array, int i, RemoteContext context, VariableSupport support) { + int cmd, + int[] array, + int i, + @NonNull RemoteContext context, + @NonNull VariableSupport support) { int ret = i; int type = (cmd >> 16); int control = array[ret++]; @@ -343,7 +354,7 @@ public class PaintBundle { return ret; } - int callPrintGradient(int cmd, int[] array, int i, StringBuilder p) { + int callPrintGradient(int cmd, int[] array, int i, @NonNull StringBuilder p) { int ret = i; int type = (cmd >> 16); int tileMode = 0; @@ -432,7 +443,7 @@ public class PaintBundle { return ret; } - int callSetGradient(int cmd, int[] array, int i, PaintChanges p) { + int callSetGradient(int cmd, @NonNull int[] array, int i, @NonNull PaintChanges p) { int ret = i; int gradientType = (cmd >> 16); @@ -487,14 +498,14 @@ public class PaintBundle { return ret; } - public void writeBundle(WireBuffer buffer) { + public void writeBundle(@NonNull WireBuffer buffer) { buffer.writeInt(mPos); for (int index = 0; index < mPos; index++) { buffer.writeInt(mArray[index]); } } - public void readBundle(WireBuffer buffer) { + public void readBundle(@NonNull WireBuffer buffer) { int len = buffer.readInt(); if (len <= 0 || len > 1024) { throw new RuntimeException("buffer corrupt paint len = " + len); @@ -589,9 +600,9 @@ public class PaintBundle { * @param tileMode The Shader tiling mode */ public void setLinearGradient( - int[] colors, + @NonNull int[] colors, int idMask, - float[] stops, + @Nullable float[] stops, float startX, float startY, float endX, @@ -600,7 +611,7 @@ public class PaintBundle { // int startPos = mPos; int len; mArray[mPos++] = GRADIENT | (LINEAR_GRADIENT << 16); - mArray[mPos++] = (idMask << 16) | (len = (colors == null) ? 0 : colors.length); + mArray[mPos++] = (idMask << 16) | (len = colors.length); for (int i = 0; i < len; i++) { mArray[mPos++] = colors[i]; } @@ -629,7 +640,12 @@ public class PaintBundle { * spaced evenly. */ public void setSweepGradient( - int[] colors, int idMask, float[] stops, float centerX, float centerY) { + @NonNull int[] colors, + int idMask, + @Nullable float[] stops, // TODO: rename positions to stops or stops to positions, but + // don't have both in the same file + float centerX, + float centerY) { int len; mArray[mPos++] = GRADIENT | (SWEEP_GRADIENT << 16); mArray[mPos++] = (idMask << 16) | (len = (colors == null) ? 0 : colors.length); @@ -659,9 +675,9 @@ public class PaintBundle { * @param tileMode The Shader tiling mode */ public void setRadialGradient( - int[] colors, + @NonNull int[] colors, int idMask, - float[] stops, + @Nullable float[] stops, float centerX, float centerY, float radius, @@ -900,7 +916,7 @@ public class PaintBundle { mPos = 0; } - public static String blendModeString(int mode) { + public static @NonNull String blendModeString(int mode) { switch (mode) { case PaintBundle.BLEND_MODE_CLEAR: return "CLEAR"; @@ -974,7 +990,7 @@ public class PaintBundle { * @param context * @param support */ - public void registerVars(RemoteContext context, VariableSupport support) { + public void registerVars(@NonNull RemoteContext context, @NonNull VariableSupport support) { int i = 0; while (i < mPos) { int cmd = mArray[i++]; @@ -1020,7 +1036,7 @@ public class PaintBundle { * * @param context */ - public void updateVariables(RemoteContext context) { + public void updateVariables(@NonNull RemoteContext context) { if (mOutArray == null) { mOutArray = Arrays.copyOf(mArray, mArray.length); } else { @@ -1066,7 +1082,7 @@ public class PaintBundle { } } - private int fixFloatVar(int val, RemoteContext context) { + private int fixFloatVar(int val, @NonNull RemoteContext context) { float v = Float.intBitsToFloat(val); if (Float.isNaN(v)) { int id = Utils.idFromNan(v); @@ -1075,12 +1091,13 @@ public class PaintBundle { return val; } - private int fixColor(int colorId, RemoteContext context) { + private int fixColor(int colorId, @NonNull RemoteContext context) { int n = context.getColor(colorId); return n; } - int updateFloatsInGradient(int cmd, int[] out, int[] array, int i, RemoteContext context) { + int updateFloatsInGradient( + int cmd, int[] out, int[] array, int i, @NonNull RemoteContext context) { int ret = i; int type = (cmd >> 16); int control = array[ret++]; diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/paint/PaintChangeAdapter.java b/core/java/com/android/internal/widget/remotecompose/core/operations/paint/PaintChangeAdapter.java index e2402be4e4d4df62b44d18085e05ab092f287c2e..87a663266e0eaeb10ae2288cd66a480b4f5f356f 100644 --- a/core/java/com/android/internal/widget/remotecompose/core/operations/paint/PaintChangeAdapter.java +++ b/core/java/com/android/internal/widget/remotecompose/core/operations/paint/PaintChangeAdapter.java @@ -15,6 +15,9 @@ */ package com.android.internal.widget.remotecompose.core.operations.paint; +import android.annotation.NonNull; +import android.annotation.Nullable; + public class PaintChangeAdapter implements PaintChanges { @Override @@ -64,8 +67,8 @@ public class PaintChangeAdapter implements PaintChanges { @Override public void setLinearGradient( - int[] colorsArray, - float[] stopsArray, + @NonNull int[] colorsArray, + @Nullable float[] stopsArray, float startX, float startY, float endX, @@ -74,8 +77,8 @@ public class PaintChangeAdapter implements PaintChanges { @Override public void setRadialGradient( - int[] colorsArray, - float[] stopsArray, + @NonNull int[] colorsArray, + @Nullable float[] stopsArray, float centerX, float centerY, float radius, @@ -83,7 +86,10 @@ public class PaintChangeAdapter implements PaintChanges { @Override public void setSweepGradient( - int[] colorsArray, float[] stopsArray, float centerX, float centerY) {} + @NonNull int[] colorsArray, + @Nullable float[] stopsArray, + float centerX, + float centerY) {} @Override public void setColorFilter(int color, int mode) {} diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/paint/PaintChanges.java b/core/java/com/android/internal/widget/remotecompose/core/operations/paint/PaintChanges.java index 486d763cb6d5b8b0a69528eac2b8ce33fdec8ab6..e68164716a44875ff6d3508a37aeaa1ec0dff886 100644 --- a/core/java/com/android/internal/widget/remotecompose/core/operations/paint/PaintChanges.java +++ b/core/java/com/android/internal/widget/remotecompose/core/operations/paint/PaintChanges.java @@ -15,6 +15,9 @@ */ package com.android.internal.widget.remotecompose.core.operations.paint; +import android.annotation.NonNull; +import android.annotation.Nullable; + /** Interface to a paint object For more details see Android Paint */ public interface PaintChanges { @@ -135,7 +138,7 @@ public interface PaintChanges { * Set a linear gradient fill * * @param colorsArray - * @param stopsArray + * @param stopsArray // todo: standardize naming * @param startX * @param startY * @param endX @@ -143,8 +146,8 @@ public interface PaintChanges { * @param tileMode */ void setLinearGradient( - int[] colorsArray, - float[] stopsArray, + @NonNull int[] colorsArray, + @Nullable float[] stopsArray, float startX, float startY, float endX, @@ -155,15 +158,15 @@ public interface PaintChanges { * Set a radial gradient fill * * @param colorsArray - * @param stopsArray + * @param stopsArray // todo: standardize naming * @param centerX * @param centerY * @param radius * @param tileMode */ void setRadialGradient( - int[] colorsArray, - float[] stopsArray, + @NonNull int[] colorsArray, + @Nullable float[] stopsArray, float centerX, float centerY, float radius, @@ -173,11 +176,12 @@ public interface PaintChanges { * Set a sweep gradient fill * * @param colorsArray - * @param stopsArray + * @param stopsArray // todo: standardize naming to either "positions" or "stops" * @param centerX * @param centerY */ - void setSweepGradient(int[] colorsArray, float[] stopsArray, float centerX, float centerY); + void setSweepGradient( + @NonNull int[] colorsArray, @Nullable float[] stopsArray, float centerX, float centerY); /** * Set Color filter mod diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/paint/Painter.java b/core/java/com/android/internal/widget/remotecompose/core/operations/paint/Painter.java index a808cf0e17b360861944edb09972b6fcec25cf3b..e5f6f2838d34adc320e82e38f28fca7b41439a68 100644 --- a/core/java/com/android/internal/widget/remotecompose/core/operations/paint/Painter.java +++ b/core/java/com/android/internal/widget/remotecompose/core/operations/paint/Painter.java @@ -16,6 +16,7 @@ package com.android.internal.widget.remotecompose.core.operations.paint; import android.annotation.NonNull; +import android.annotation.Nullable; /** Provides a Builder pattern for a PaintBundle */ class Painter { @@ -173,8 +174,8 @@ class Painter { float centerX, float centerY, float radius, - int[] colors, - float[] positions, + @NonNull int[] colors, + @NonNull float[] positions, int tileMode) { mPaint.setRadialGradient(colors, 0, positions, centerX, centerY, radius, tileMode); return this; @@ -193,7 +194,8 @@ class Painter { * spaced evenly. */ @NonNull - public Painter setSweepGradient(float centerX, float centerY, int[] colors, float[] positions) { + public Painter setSweepGradient( + float centerX, float centerY, @NonNull int[] colors, @Nullable float[] positions) { mPaint.setSweepGradient(colors, 0, positions, centerX, centerY); return this; } diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/paint/TextPaint.java b/core/java/com/android/internal/widget/remotecompose/core/operations/paint/TextPaint.java index 1c0bec76bb62f78c6112f7ba44c7c067c8bfe74c..ff6f45db53850481bf286b6de23dce2c4c44ea7c 100644 --- a/core/java/com/android/internal/widget/remotecompose/core/operations/paint/TextPaint.java +++ b/core/java/com/android/internal/widget/remotecompose/core/operations/paint/TextPaint.java @@ -15,6 +15,9 @@ */ package com.android.internal.widget.remotecompose.core.operations.paint; +import android.annotation.NonNull; + +// TODO: this interface is unused. Delete it. public interface TextPaint { void setARGB(int a, int r, int g, int b); @@ -28,7 +31,7 @@ public interface TextPaint { void setFlags(int flags); - void setFontFeatureSettings(String settings); + void setFontFeatureSettings(@NonNull String settings); void setHinting(int mode); 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 b25f4cd3c5304c17dc85dfd732eeea09dee0c3e9..e5633c70faee3f91839d590147955e7e13dc143a 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 @@ -18,6 +18,9 @@ package com.android.internal.widget.remotecompose.core.operations.utilities; import android.annotation.NonNull; import android.annotation.Nullable; +import com.android.internal.widget.remotecompose.core.operations.Utils; +import com.android.internal.widget.remotecompose.core.operations.utilities.easing.MonotonicSpline; + /** high performance floating point expression evaluator used in animation */ public class AnimatedFloatExpression { @NonNull static IntMap sNames = new IntMap<>(); @@ -64,20 +67,37 @@ public class AnimatedFloatExpression { public static final float A_SUM = asNan(OFFSET + 35); public static final float A_AVG = asNan(OFFSET + 36); public static final float A_LEN = asNan(OFFSET + 37); - public static final int LAST_OP = OFFSET + 37; + public static final float A_SPLINE = asNan(OFFSET + 38); + + public static final int LAST_OP = OFFSET + 38; - public static final float VAR1 = asNan(OFFSET + 38); - public static final float VAR2 = asNan(OFFSET + 39); + public static final float VAR1 = asNan(OFFSET + 39); + public static final float VAR2 = asNan(OFFSET + 40); // TODO CLAMP, CBRT, DEG, RAD, EXPM1, CEIL, FLOOR // private static final float FP_PI = (float) Math.PI; private static final float FP_TO_RAD = 57.29578f; // 180/PI private static final float FP_TO_DEG = 0.017453292f; // 180/PI - float[] mStack; + @NonNull float[] mStack = new float[0]; @NonNull float[] mLocalStack = new float[128]; - float[] mVar; - CollectionsAccess mCollectionsAccess; + @NonNull float[] mVar = new float[0]; + @Nullable CollectionsAccess mCollectionsAccess; + IntMap mSplineMap = new IntMap<>(); + + private float getSplineValue(int arrayId, float pos) { + MonotonicSpline fit = mSplineMap.get(arrayId); + float[] f = mCollectionsAccess.getFloats(arrayId); + if (fit != null) { + if (fit.getArray() == f) { // the array has not changed. + return fit.getPos(pos); + } + } + + fit = new MonotonicSpline(null, f); + mSplineMap.put(arrayId, fit); + return fit.getPos(pos); + } /** * is float a math operator @@ -114,7 +134,7 @@ public class AnimatedFloatExpression { * @param var * @return */ - public float eval(float[] exp, float... var) { + public float eval(@NonNull float[] exp, @NonNull float... var) { mStack = exp; mVar = var; int sp = -1; @@ -137,7 +157,8 @@ public class AnimatedFloatExpression { * @param var * @return */ - public float eval(CollectionsAccess ca, float[] exp, int len, float... var) { + public float eval( + @NonNull CollectionsAccess ca, @NonNull float[] exp, int len, @NonNull float... var) { System.arraycopy(exp, 0, mLocalStack, 0, len); mStack = mLocalStack; mVar = var; @@ -167,7 +188,7 @@ public class AnimatedFloatExpression { * @param exp * @return */ - public float eval(CollectionsAccess ca, float[] exp, int len) { + public float eval(@NonNull CollectionsAccess ca, @NonNull float[] exp, int len) { System.arraycopy(exp, 0, mLocalStack, 0, len); mStack = mLocalStack; mCollectionsAccess = ca; @@ -189,7 +210,7 @@ public class AnimatedFloatExpression { return mStack[sp]; } - private int dereference(CollectionsAccess ca, int id, int sp) { + private int dereference(@NonNull CollectionsAccess ca, int id, int sp) { mStack[sp] = ca.getFloatValue(id, (int) (mStack[sp])); return sp; } @@ -202,7 +223,7 @@ public class AnimatedFloatExpression { * @param var * @return */ - public float eval(@NonNull float[] exp, int len, float... var) { + public float eval(@NonNull float[] exp, int len, @NonNull float... var) { System.arraycopy(exp, 0, mLocalStack, 0, len); mStack = mLocalStack; mVar = var; @@ -225,13 +246,12 @@ public class AnimatedFloatExpression { * @param var * @return */ - public float evalDB(@NonNull float[] exp, float... var) { + public float evalDB(@NonNull float[] exp, @NonNull float... var) { mStack = exp; mVar = var; int sp = -1; for (float v : exp) { if (Float.isNaN(v)) { - System.out.print(" " + sNames.get((fromNaN(v) - OFFSET))); sp = mOps[fromNaN(v) - OFFSET].eval(sp); } else { System.out.print(" " + v); @@ -375,12 +395,12 @@ public class AnimatedFloatExpression { return sp - 2; }; Op mCLAMP = - (sp) -> { // CLAMP + (sp) -> { // CLAMP (min, max, value) mStack[sp - 2] = Math.min(Math.max(mStack[sp - 2], mStack[sp]), mStack[sp - 1]); return sp - 2; }; Op mCBRT = - (sp) -> { // CBRT + (sp) -> { // CBRT is cube root mStack[sp] = (float) Math.pow(mStack[sp], 1 / 3.); return sp; }; @@ -401,8 +421,10 @@ public class AnimatedFloatExpression { }; Op mA_DEREF = (sp) -> { // A_DEREF - int id = fromNaN(mStack[sp]); - mStack[sp - 1] = mCollectionsAccess.getFloatValue(id, (int) mStack[sp - 1]); + Utils.log(" \n >>> DREF " + Integer.toHexString(fromNaN(mStack[sp - 1]))); + Utils.log(" >>> DREF " + mStack[sp] + " " + mStack[sp - 1]); + int id = fromNaN(mStack[sp - 1]); + mStack[sp - 1] = mCollectionsAccess.getFloatValue(id, (int) mStack[sp]); return sp - 1; }; Op mA_MAX = @@ -420,11 +442,14 @@ public class AnimatedFloatExpression { (sp) -> { // A_MIN int id = fromNaN(mStack[sp]); float[] array = mCollectionsAccess.getFloats(id); - float max = array[0]; + if (array.length == 0) { + return sp; + } + float min = array[0]; for (int i = 1; i < array.length; i++) { - max = Math.max(max, array[i]); + min = Math.min(min, array[i]); } - mStack[sp] = max; + mStack[sp] = min; return sp; }; Op mA_SUM = @@ -455,6 +480,12 @@ public class AnimatedFloatExpression { mStack[sp] = mCollectionsAccess.getListLength(id); return sp; }; + Op mA_SPLINE = + (sp) -> { // A_SPLINE + int id = fromNaN(mStack[sp - 1]); + mStack[sp - 1] = getSplineValue(id, mStack[sp]); + return sp - 1; + }; Op mFIRST_VAR = (sp) -> { // FIRST_VAR mStack[sp] = mVar[0]; @@ -510,6 +541,7 @@ public class AnimatedFloatExpression { mA_SUM, mA_AVG, mA_LEN, + mA_SPLINE, mFIRST_VAR, mSECOND_VAR, mTHIRD_VAR, @@ -558,6 +590,7 @@ public class AnimatedFloatExpression { sNames.put(k++, "A_SUM"); sNames.put(k++, "A_AVG"); sNames.put(k++, "A_LEN"); + sNames.put(k++, "A_SPLINE"); sNames.put(k++, "a[0]"); sNames.put(k++, "a[1]"); 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 eb5e4828f2a0779ee5f242be82e302cab23513ca..182d36a5eb066fdbfdaddc476dcdd08156f8947b 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 @@ -15,6 +15,8 @@ */ package com.android.internal.widget.remotecompose.core.operations.utilities; +import android.annotation.Nullable; + /** * Support a standardized interface to commands that contain arrays All commands that implement * array access will be collected in a map in the state TODO refactor to DataAccess, @@ -27,6 +29,7 @@ public interface ArrayAccess { return 0; } + @Nullable float[] getFloats(); int getLength(); diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/utilities/CollectionsAccess.java b/core/java/com/android/internal/widget/remotecompose/core/operations/utilities/CollectionsAccess.java index 0128253e1f90fcebf9a1d016bd559fd67211aa21..4f1287265d75d572413723d430703102d10b58ff 100644 --- a/core/java/com/android/internal/widget/remotecompose/core/operations/utilities/CollectionsAccess.java +++ b/core/java/com/android/internal/widget/remotecompose/core/operations/utilities/CollectionsAccess.java @@ -15,6 +15,8 @@ */ package com.android.internal.widget.remotecompose.core.operations.utilities; +import android.annotation.Nullable; + /** * interface to allow expressions to access collections Todo define a convention for when access is * unavailable @@ -22,6 +24,7 @@ package com.android.internal.widget.remotecompose.core.operations.utilities; public interface CollectionsAccess { float getFloatValue(int id, int index); + @Nullable float[] getFloats(int id); int getListLength(int id); diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/utilities/DataMap.java b/core/java/com/android/internal/widget/remotecompose/core/operations/utilities/DataMap.java index 24f17d7b00c798513ceb82632182170a6431d940..07a3d8482db238196e24d9fac449ea8af7f0c670 100644 --- a/core/java/com/android/internal/widget/remotecompose/core/operations/utilities/DataMap.java +++ b/core/java/com/android/internal/widget/remotecompose/core/operations/utilities/DataMap.java @@ -15,18 +15,20 @@ */ package com.android.internal.widget.remotecompose.core.operations.utilities; +import android.annotation.NonNull; + public class DataMap { - public String[] mNames; - public int[] mIds; - public byte[] mTypes; + @NonNull public final String[] mNames; + @NonNull public final int[] mIds; + @NonNull public final byte[] mTypes; - public DataMap(String[] names, byte[] types, int[] ids) { + public DataMap(@NonNull String[] names, @NonNull byte[] types, @NonNull int[] ids) { mNames = names; mTypes = types; mIds = ids; } - public int getPos(String str) { + public int getPos(@NonNull String str) { for (int i = 0; i < mNames.length; i++) { String name = mNames[i]; if (str.equals(name)) { diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/utilities/ImageScaling.java b/core/java/com/android/internal/widget/remotecompose/core/operations/utilities/ImageScaling.java index e74b3350f4278e713f5a9171d59a8d06c65a2a44..98ee91b370e0d81e7e2fbd8bcde802471539dc59 100644 --- a/core/java/com/android/internal/widget/remotecompose/core/operations/utilities/ImageScaling.java +++ b/core/java/com/android/internal/widget/remotecompose/core/operations/utilities/ImageScaling.java @@ -17,6 +17,8 @@ package com.android.internal.widget.remotecompose.core.operations.utilities; import android.annotation.NonNull; +import com.android.internal.widget.remotecompose.core.operations.Utils; + /** Implement the scaling logic for Compose Image or ImageView */ public class ImageScaling { @@ -109,7 +111,7 @@ public class ImageScaling { String s = str; s += str(left) + ", " + str(top) + ", " + str(right) + ", " + str(bottom) + ", "; s += " [" + str(right - left) + " x " + str(bottom - top) + "]"; - System.out.println(s); + Utils.log(s); } /** This adjust destnation on the DrawBitMapInt to support all contentScale types */ @@ -128,7 +130,7 @@ public class ImageScaling { print("test rc ", mSrcLeft, mSrcTop, mSrcRight, mSrcBottom); print("test dst ", mDstLeft, mDstTop, mDstRight, mDstBottom); } - + if (sh == 0 || sw == 0) return; switch (mScaleType) { case SCALE_NONE: dh = sh; diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/utilities/IntMap.java b/core/java/com/android/internal/widget/remotecompose/core/operations/utilities/IntMap.java index 749c0fe0dcc3e45affa1f9570025359df5ac0aea..b9aa88146f2a0bfb1cc3a44acdcc070dba3eae9a 100644 --- a/core/java/com/android/internal/widget/remotecompose/core/operations/utilities/IntMap.java +++ b/core/java/com/android/internal/widget/remotecompose/core/operations/utilities/IntMap.java @@ -15,6 +15,7 @@ */ package com.android.internal.widget.remotecompose.core.operations.utilities; +import android.annotation.NonNull; import android.annotation.Nullable; import java.util.ArrayList; @@ -45,7 +46,7 @@ public class IntMap { } @Nullable - public T put(int key, T value) { + public T put(int key, @NonNull T value) { if (key == NOT_PRESENT) throw new IllegalArgumentException("Key cannot be NOT_PRESENT"); if (mSize > mKeys.length * LOAD_FACTOR) { resize(); @@ -66,7 +67,7 @@ public class IntMap { } @Nullable - private T insert(int key, T value) { + private T insert(int key, @NonNull T value) { int index = hash(key) % mKeys.length; while (mKeys[index] != NOT_PRESENT && mKeys[index] != key) { index = (index + 1) % mKeys.length; @@ -116,6 +117,7 @@ public class IntMap { } } + @Nullable public T remove(int key) { int index = hash(key) % mKeys.length; int initialIndex = index; diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/utilities/IntegerExpressionEvaluator.java b/core/java/com/android/internal/widget/remotecompose/core/operations/utilities/IntegerExpressionEvaluator.java index 8905431d14d7955213a5f33c6775f322118ad2e3..f73ab39e496efec23cbea8836fa369796e785eb3 100644 --- a/core/java/com/android/internal/widget/remotecompose/core/operations/utilities/IntegerExpressionEvaluator.java +++ b/core/java/com/android/internal/widget/remotecompose/core/operations/utilities/IntegerExpressionEvaluator.java @@ -59,9 +59,9 @@ public class IntegerExpressionEvaluator { public static final int I_VAR1 = OFFSET + 24; public static final int I_VAR2 = OFFSET + 25; - int[] mStack; + @NonNull int[] mStack = new int[0]; @NonNull int[] mLocalStack = new int[128]; - int[] mVar; + @NonNull int[] mVar = new int[0]; interface Op { int eval(int sp); @@ -75,7 +75,7 @@ public class IntegerExpressionEvaluator { * @param var variables if the expression is a function * @return return the results of evaluating the expression */ - public int eval(int mask, int[] exp, int... var) { + public int eval(int mask, @NonNull int[] exp, @NonNull int... var) { mStack = exp; mVar = var; int sp = -1; @@ -99,7 +99,7 @@ public class IntegerExpressionEvaluator { * @param var variables if the expression is a function * @return return the results of evaluating the expression */ - public int eval(int mask, @NonNull int[] exp, int len, int... var) { + public int eval(int mask, @NonNull int[] exp, int len, @NonNull int... var) { System.arraycopy(exp, 0, mLocalStack, 0, len); mStack = mLocalStack; mVar = var; @@ -123,17 +123,15 @@ public class IntegerExpressionEvaluator { * @param var variables if the expression is a function * @return return the results of evaluating the expression */ - public int evalDB(int opMask, @NonNull int[] exp, int... var) { + public int evalDB(int opMask, @NonNull int[] exp, @NonNull int... var) { mStack = exp; mVar = var; int sp = -1; for (int i = 0; i < exp.length; i++) { int v = mStack[i]; if (((1 << i) & opMask) != 0) { - System.out.print(" " + sNames.get((v - OFFSET))); sp = mOps[v - OFFSET].eval(sp); } else { - System.out.print(" " + v); mStack[++sp] = v; } } @@ -199,7 +197,7 @@ public class IntegerExpressionEvaluator { return sp - 1; }; Op mCOPY_SIGN = - (sp) -> { // COPY_SIGN + (sp) -> { // COPY_SIGN copy the sign via bit manipulation mStack[sp - 1] = (mStack[sp - 1] ^ (mStack[sp] >> 31)) - (mStack[sp] >> 31); return sp - 1; }; @@ -239,12 +237,12 @@ public class IntegerExpressionEvaluator { return sp; }; Op mSIGN = - (sp) -> { // SIGN + (sp) -> { // SIGN x<0 = -1,x==0 = 0 , x>0 = 1 mStack[sp] = (mStack[sp] >> 31) | (-mStack[sp] >>> 31); return sp; }; Op mCLAMP = - (sp) -> { // CLAMP + (sp) -> { // CLAMP(min,max, val) mStack[sp - 2] = Math.min(Math.max(mStack[sp - 2], mStack[sp]), mStack[sp - 1]); return sp - 2; }; @@ -360,7 +358,7 @@ public class IntegerExpressionEvaluator { * @return */ @NonNull - public static String toString(int opMask, @NonNull int[] exp, String[] labels) { + public static String toString(int opMask, @NonNull int[] exp, @NonNull String[] labels) { StringBuilder s = new StringBuilder(); for (int i = 0; i < exp.length; i++) { int v = exp[i]; diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/utilities/easing/FloatAnimation.java b/core/java/com/android/internal/widget/remotecompose/core/operations/utilities/easing/FloatAnimation.java index ebb22b6e98c5fb854739204dbfd9b731e988148a..465c95d067264b42f2b062f80af86ab0acb7c432 100644 --- a/core/java/com/android/internal/widget/remotecompose/core/operations/utilities/easing/FloatAnimation.java +++ b/core/java/com/android/internal/widget/remotecompose/core/operations/utilities/easing/FloatAnimation.java @@ -57,13 +57,17 @@ public class FloatAnimation extends Easing { mEasingCurve = new CubicEasing(mType); } - public FloatAnimation(float... description) { + public FloatAnimation(@NonNull float... description) { mType = CUBIC_STANDARD; setAnimationDescription(description); } public FloatAnimation( - int type, float duration, float[] description, float initialValue, float wrap) { + int type, + float duration, + @Nullable float[] description, + float initialValue, + float wrap) { mType = CUBIC_STANDARD; setAnimationDescription(packToFloatArray(duration, type, description, initialValue, wrap)); } @@ -77,7 +81,7 @@ public class FloatAnimation extends Easing { * @param initialValue * @return */ - public static float[] packToFloatArray( + public static @NonNull float[] packToFloatArray( float duration, int type, @Nullable float[] spec, float initialValue, float wrap) { int count = 0; @@ -221,7 +225,7 @@ public class FloatAnimation extends Easing { * * @param description */ - public void setAnimationDescription(float[] description) { + public void setAnimationDescription(@NonNull float[] description) { mSpec = description; mDuration = (mSpec.length == 0) ? 1 : mSpec[0]; int len = 0; @@ -242,7 +246,7 @@ public class FloatAnimation extends Easing { create(mType, description, 2, len); } - private void create(int type, float[] params, int offset, int len) { + private void create(int type, @Nullable float[] params, int offset, int len) { switch (type) { case CUBIC_STANDARD: case CUBIC_ACCELERATE: diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/utilities/easing/GeneralEasing.java b/core/java/com/android/internal/widget/remotecompose/core/operations/utilities/easing/GeneralEasing.java index 90b65bf2353a043c64fb665270848231008a707d..06969ccd1b10a225a507ae3bbe2ef6c77c2d9ed7 100644 --- a/core/java/com/android/internal/widget/remotecompose/core/operations/utilities/easing/GeneralEasing.java +++ b/core/java/com/android/internal/widget/remotecompose/core/operations/utilities/easing/GeneralEasing.java @@ -19,7 +19,7 @@ import android.annotation.NonNull; /** Provides and interface to create easing functions */ public class GeneralEasing extends Easing { - float[] mEasingData = new float[0]; + @NonNull float[] mEasingData = new float[0]; @NonNull Easing mEasingCurve = new CubicEasing(CUBIC_STANDARD); /** @@ -27,12 +27,12 @@ public class GeneralEasing extends Easing { * * @param data */ - public void setCurveSpecification(float[] data) { + public void setCurveSpecification(@NonNull float[] data) { mEasingData = data; createEngine(); } - public float[] getCurveSpecification() { + public @NonNull float[] getCurveSpecification() { return mEasingData; } diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/utilities/easing/MonotonicCurveFit.java b/core/java/com/android/internal/widget/remotecompose/core/operations/utilities/easing/MonotonicCurveFit.java index f540e7008471107fd9b1708c46fa19c21401e23b..f4579a24fd44f9f6a47beb3cfb59a43f0f988a4a 100644 --- a/core/java/com/android/internal/widget/remotecompose/core/operations/utilities/easing/MonotonicCurveFit.java +++ b/core/java/com/android/internal/widget/remotecompose/core/operations/utilities/easing/MonotonicCurveFit.java @@ -22,11 +22,11 @@ import java.util.Arrays; /** This performs a spline interpolation in multiple dimensions */ public class MonotonicCurveFit { private static final String TAG = "MonotonicCurveFit"; - private double[] mT; - private double[][] mY; - private double[][] mTangent; + @NonNull private final double[] mT; + @NonNull private final double[][] mY; + @NonNull private final double[][] mTangent; private boolean mExtrapolate = true; - double[] mSlopeTemp; + @NonNull final double[] mSlopeTemp; /** * create a collection of curves @@ -81,7 +81,7 @@ public class MonotonicCurveFit { * @param t * @param v */ - public void getPos(double t, double[] v) { + public void getPos(double t, @NonNull double[] v) { final int n = mT.length; final int dim = mY[0].length; if (mExtrapolate) { @@ -141,7 +141,7 @@ public class MonotonicCurveFit { * @param t * @param v */ - public void getPos(double t, float[] v) { + public void getPos(double t, @NonNull float[] v) { final int n = mT.length; final int dim = mY[0].length; if (mExtrapolate) { @@ -243,7 +243,7 @@ public class MonotonicCurveFit { * @param t * @param v */ - public void getSlope(double t, double[] v) { + public void getSlope(double t, @NonNull double[] v) { final int n = mT.length; int dim = mY[0].length; if (t <= mT[0]) { @@ -297,7 +297,7 @@ public class MonotonicCurveFit { return 0; // should never reach here } - public double[] getTimePoints() { + public @NonNull double[] getTimePoints() { return mT; } diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/utilities/easing/MonotonicSpline.java b/core/java/com/android/internal/widget/remotecompose/core/operations/utilities/easing/MonotonicSpline.java new file mode 100644 index 0000000000000000000000000000000000000000..23a664336c5fe7d3a3699847e4da9c1fcb4bf598 --- /dev/null +++ b/core/java/com/android/internal/widget/remotecompose/core/operations/utilities/easing/MonotonicSpline.java @@ -0,0 +1,203 @@ +/* + * 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.utilities.easing; + +import android.annotation.NonNull; +import android.annotation.Nullable; + +/** This performs a spline interpolation in multiple dimensions */ +public class MonotonicSpline { + private static final String TAG = "MonotonicCurveFit"; + private float[] mT; + private float[] mY; + private float[] mTangent; + private boolean mExtrapolate = true; + float[] mSlopeTemp; + + /** + * create a collection of curves + * + * @param time the point along the curve + * @param y the parameter at those points + */ + public MonotonicSpline(@Nullable float[] time, @NonNull float[] y) { + if (time == null) { // if time is null assume even 0 to 1; + time = new float[y.length]; + for (int i = 0; i < time.length; i++) { + time[i] = i / (float) (time.length - 1); + } + } + mT = time; + mY = y; + final int n = time.length; + final int dim = 1; + mSlopeTemp = new float[dim]; + float[] slope = new float[n - 1]; // could optimize this out + float[] tangent = new float[n]; + for (int i = 0; i < n - 1; i++) { + float dt = time[i + 1] - time[i]; + slope[i] = (y[i + 1] - y[i]) / dt; + if (i == 0) { + tangent[i] = slope[i]; + } else { + tangent[i] = (slope[i - 1] + slope[i]) * 0.5f; + } + } + tangent[n - 1] = slope[n - 2]; + + for (int i = 0; i < n - 1; i++) { + if (slope[i] == 0.) { + tangent[i] = 0f; + tangent[i + 1] = 0f; + } else { + float a = tangent[i] / slope[i]; + float b = tangent[i + 1] / slope[i]; + float h = (float) Math.hypot(a, b); + if (h > 9.0) { + float t = 3f / h; + tangent[i] = t * a * slope[i]; + tangent[i + 1] = t * b * slope[i]; + } + } + } + mTangent = tangent; + } + + public float[] getArray() { + return mY; + } + + /** + * Get the position of all curves at time t + * + * @param t + * @return position at t + */ + public float getPos(float t) { + final int n = mT.length; + float v; + if (mExtrapolate) { + if (t <= mT[0]) { + float slopeTemp = getSlope(mT[0]); + v = mY[0] + (t - mT[0]) * slopeTemp; + + return v; + } + if (t >= mT[n - 1]) { + float slopeTemp = getSlope(mT[n - 1]); + v = mY[n - 1] + (t - mT[n - 1]) * slopeTemp; + + return v; + } + } else { + if (t <= mT[0]) { + v = mY[0]; + + return v; + } + if (t >= mT[n - 1]) { + v = mY[n - 1]; + + return v; + } + } + + for (int i = 0; i < n - 1; i++) { + if (t == mT[i]) { + + v = mY[i]; + } + if (t < mT[i + 1]) { + float h = mT[i + 1] - mT[i]; + float x = (t - mT[i]) / h; + + float y1 = mY[i]; + float y2 = mY[i + 1]; + float t1 = mTangent[i]; + float t2 = mTangent[i + 1]; + v = interpolate(h, x, y1, y2, t1, t2); + + return v; + } + } + return 0f; + } + + /** + * Get the slope of the curve at position t + * + * @param t + * @return slope at t + */ + public float getSlope(float t) { + final int n = mT.length; + float v = 0; + + if (t <= mT[0]) { + t = mT[0]; + } else if (t >= mT[n - 1]) { + t = mT[n - 1]; + } + + for (int i = 0; i < n - 1; i++) { + if (t <= mT[i + 1]) { + float h = mT[i + 1] - mT[i]; + float x = (t - mT[i]) / h; + float y1 = mY[i]; + float y2 = mY[i + 1]; + float t1 = mTangent[i]; + float t2 = mTangent[i + 1]; + v = diff(h, x, y1, y2, t1, t2) / h; + } + break; + } + return v; + } + + public float[] getTimePoints() { + return mT; + } + + /** Cubic Hermite spline */ + private static float interpolate(float h, float x, float y1, float y2, float t1, float t2) { + float x2 = x * x; + float x3 = x2 * x; + return -2 * x3 * y2 + + 3 * x2 * y2 + + 2 * x3 * y1 + - 3 * x2 * y1 + + y1 + + h * t2 * x3 + + h * t1 * x3 + - h * t2 * x2 + - 2 * h * t1 * x2 + + h * t1 * x; + } + + /** Cubic Hermite spline slope differentiated */ + private static float diff(float h, float x, float y1, float y2, float t1, float t2) { + float x2 = x * x; + return -6 * x2 * y2 + + 6 * x * y2 + + 6 * x2 * y1 + - 6 * x * y1 + + 3 * h * t2 * x2 + + 3 * h * t1 * x2 + - 2 * h * t2 * x + - 4 * h * t1 * x + + h * t1; + } +} diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/utilities/easing/SpringStopEngine.java b/core/java/com/android/internal/widget/remotecompose/core/operations/utilities/easing/SpringStopEngine.java new file mode 100644 index 0000000000000000000000000000000000000000..03e45031e515d5f2a296dfd5e709c7fde69f703b --- /dev/null +++ b/core/java/com/android/internal/widget/remotecompose/core/operations/utilities/easing/SpringStopEngine.java @@ -0,0 +1,188 @@ +/* + * 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.utilities.easing; + +/** + * This contains the class to provide the logic for an animation to come to a stop using a spring + * model. String debug(String desc, float time); float getVelocity(float time); float + * getInterpolation(float time); float getVelocity(); boolean isStopped(); + */ +public class SpringStopEngine { + double mDamping = 0.5f; + + @SuppressWarnings("unused") + private static final double UNSET = Double.MAX_VALUE; + + @SuppressWarnings("unused") + private boolean mInitialized = false; + + private double mStiffness; + private double mTargetPos; + + @SuppressWarnings("unused") + private double mLastVelocity; + + private float mLastTime; + private float mPos; + private float mV; + private float mMass; + private float mStopThreshold; + private int mBoundaryMode = 0; + + public String debug(String desc, float time) { + return null; + } + + void log(String str) { + StackTraceElement s = new Throwable().getStackTrace()[1]; + String line = + ".(" + s.getFileName() + ":" + s.getLineNumber() + ") " + s.getMethodName() + "() "; + System.out.println(line + str); + } + + public SpringStopEngine() {} + + public float getTargetValue() { + return (float) mTargetPos; + } + + public void setInitialValue(float v) { + mPos = v; + } + + public void setTargetValue(float v) { + mTargetPos = v; + } + + public SpringStopEngine(float[] parameters) { + if (parameters[0] != 0) { + throw new RuntimeException(" parameter[0] should be 0"); + } + + springParameters( + 1, + parameters[1], + parameters[2], + parameters[3], + Float.floatToRawIntBits(parameters[4])); + } + + /** + * Config the spring starting conditions + * + * @param currentPos + * @param target + * @param currentVelocity + */ + public void springStart(float currentPos, float target, float currentVelocity) { + mTargetPos = target; + mInitialized = false; + mPos = currentPos; + mLastVelocity = currentVelocity; + mLastTime = 0; + } + + /** + * Config the spring parameters + * + * @param mass The mass of the spring + * @param stiffness The stiffness of the spring + * @param damping The dampening factor + * @param stopThreshold how low energy must you be to stop + * @param boundaryMode The boundary behaviour + */ + public void springParameters( + float mass, float stiffness, float damping, float stopThreshold, int boundaryMode) { + mDamping = damping; + mInitialized = false; + mStiffness = stiffness; + mMass = mass; + mStopThreshold = stopThreshold; + mBoundaryMode = boundaryMode; + mLastTime = 0; + } + + public float getVelocity(float time) { + return (float) mV; + } + + public float get(float time) { + compute(time - mLastTime); + mLastTime = time; + if (isStopped()) { + mPos = (float) mTargetPos; + } + return (float) mPos; + } + + public float getAcceleration() { + double k = mStiffness; + double c = mDamping; + double x = (mPos - mTargetPos); + return (float) (-k * x - c * mV) / mMass; + } + + public float getVelocity() { + return 0; + } + + public boolean isStopped() { + double x = (mPos - mTargetPos); + double k = mStiffness; + double v = mV; + double m = mMass; + double energy = v * v * m + k * x * x; + double max_def = Math.sqrt(energy / k); + return max_def <= mStopThreshold; + } + + private void compute(double dt) { + if (dt <= 0) { + // Nothing to compute if there's no time difference + return; + } + + double k = mStiffness; + double c = mDamping; + // Estimate how many time we should over sample based on the frequency and current sampling + int overSample = (int) (1 + 9 / (Math.sqrt(mStiffness / mMass) * dt * 4)); + dt /= overSample; + + for (int i = 0; i < overSample; i++) { + double x = (mPos - mTargetPos); + double a = (-k * x - c * mV) / mMass; + // This refinement of a simple coding of the acceleration increases accuracy + double avgV = mV + a * dt / 2; // pass 1 calculate the average velocity + double avgX = mPos + dt * avgV / 2 - mTargetPos; // pass 1 calculate the average pos + a = (-avgX * k - avgV * c) / mMass; // calculate acceleration over that average pos + + double dv = a * dt; // calculate change in velocity + avgV = mV + dv / 2; // average velocity is current + half change + mV += (float) dv; + mPos += (float) (avgV * dt); + if (mBoundaryMode > 0) { + if (mPos < 0 && ((mBoundaryMode & 1) == 1)) { + mPos = -mPos; + mV = -mV; + } + if (mPos > 1 && ((mBoundaryMode & 2) == 2)) { + mPos = 2 - mPos; + mV = -mV; + } + } + } + } +} diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/utilities/easing/StepCurve.java b/core/java/com/android/internal/widget/remotecompose/core/operations/utilities/easing/StepCurve.java index c7be3cab4c0b1ead09968b82317e8010cd3fcb9b..b1eb8041b0b3816be8a5b28a6d7a2183b6fa819b 100644 --- a/core/java/com/android/internal/widget/remotecompose/core/operations/utilities/easing/StepCurve.java +++ b/core/java/com/android/internal/widget/remotecompose/core/operations/utilities/easing/StepCurve.java @@ -24,14 +24,14 @@ import android.annotation.NonNull; */ public class StepCurve extends Easing { // private static final boolean DEBUG = false; - MonotonicCurveFit mCurveFit; + @NonNull private final MonotonicCurveFit mCurveFit; - public StepCurve(float[] params, int offset, int len) { + public StepCurve(@NonNull float[] params, int offset, int len) { mCurveFit = genSpline(params, offset, len); } @NonNull - private static MonotonicCurveFit genSpline(float[] values, int off, int arrayLen) { + private static MonotonicCurveFit genSpline(@NonNull float[] values, int off, int arrayLen) { int length = arrayLen * 3 - 2; int len = arrayLen - 1; double gap = 1.0 / len; diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/utilities/touch/VelocityEasing.java b/core/java/com/android/internal/widget/remotecompose/core/operations/utilities/touch/VelocityEasing.java index 3e24372f9b8cc9fd6cb74ada3c59dd50e2a950f2..7e02bc9416a9a35b67d42fc764fe99468fed0250 100644 --- a/core/java/com/android/internal/widget/remotecompose/core/operations/utilities/touch/VelocityEasing.java +++ b/core/java/com/android/internal/widget/remotecompose/core/operations/utilities/touch/VelocityEasing.java @@ -212,7 +212,6 @@ public class VelocityEasing { mStage[1].setUp(peak_v, d1, t1, 0f, destination, t2 + t1); mDuration = t2 + t1; if (mDuration > maxTime) { - System.out.println(" fail "); return false; } } 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 3fba8acf8bca2a632b227649d0a0bf1fca4a7280..4af79f3ce4f492f93a176deee2c4369531a2d71d 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 @@ -54,11 +54,11 @@ public class BooleanConstant implements Operation { } @Override - public void apply(RemoteContext context) {} + public void apply(@NonNull RemoteContext context) {} @NonNull @Override - public String deepToString(String indent) { + public String deepToString(@NonNull String indent) { return toString(); } 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 79f2a8d8dec52053f622bc4e4aff91c4a76d3386..613e7328e24ad0125447c0fd29c7f51fa083892a 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 @@ -50,7 +50,7 @@ public class IntegerConstant implements Operation { @NonNull @Override - public String deepToString(String indent) { + public String deepToString(@NonNull String indent) { return toString(); } 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 01672b469728bc740898b4ed3d73d341ace737f7..745caa384e4c4c2e8596ee4f78364a3ebf47607f 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 @@ -54,13 +54,13 @@ public class LongConstant implements Operation { } @Override - public void apply(RemoteContext context) { + public void apply(@NonNull RemoteContext context) { context.putObject(mId, this); } @NonNull @Override - public String deepToString(String indent) { + public String deepToString(@NonNull String indent) { return toString(); } diff --git a/core/java/com/android/internal/widget/remotecompose/player/RemoteComposeDocument.java b/core/java/com/android/internal/widget/remotecompose/player/RemoteComposeDocument.java index aaee9c565fbbde204f7443bc97c1874ec06fccf3..2a3f3be714b986454075f506d38729934316c533 100644 --- a/core/java/com/android/internal/widget/remotecompose/player/RemoteComposeDocument.java +++ b/core/java/com/android/internal/widget/remotecompose/player/RemoteComposeDocument.java @@ -141,4 +141,9 @@ public class RemoteComposeDocument { } return mDocument.getStats(); } + + public int hasSensorListeners(int[] ids) { + + return 0; + } } 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 cc74b119866de097d6f21f4a04911cb9539ce55d..648f7bf06dd4fd7706246850c4484aa29cc79815 100644 --- a/core/java/com/android/internal/widget/remotecompose/player/RemoteComposePlayer.java +++ b/core/java/com/android/internal/widget/remotecompose/player/RemoteComposePlayer.java @@ -15,9 +15,14 @@ */ package com.android.internal.widget.remotecompose.player; +import android.app.Application; import android.content.Context; import android.content.res.TypedArray; import android.graphics.Color; +import android.hardware.Sensor; +import android.hardware.SensorEvent; +import android.hardware.SensorEventListener; +import android.hardware.SensorManager; import android.util.AttributeSet; import android.util.Log; import android.util.TypedValue; @@ -28,6 +33,7 @@ import android.widget.HorizontalScrollView; import android.widget.ScrollView; 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; import com.android.internal.widget.remotecompose.core.operations.RootContentBehavior; import com.android.internal.widget.remotecompose.player.platform.RemoteComposeCanvas; @@ -81,6 +87,7 @@ public class RemoteComposePlayer extends FrameLayout { mInner.setDocument(null); } mapColors(); + setupSensors(); mInner.setHapticEngine( new CoreDocument.HapticEngine() { @@ -543,4 +550,113 @@ public class RemoteComposePlayer extends FrameLayout { private void provideHapticFeedback(int type) { performHapticFeedback(sHapticTable[type % sHapticTable.length]); } + + SensorManager mSensorManager; + Sensor mAcc = null, mGyro = null, mMag = null, mLight = null; + SensorEventListener mListener; + + private void setupSensors() { + + int minId = RemoteContext.ID_ACCELERATION_X; + int maxId = RemoteContext.ID_LIGHT; + int[] ids = new int[1 + maxId - minId]; + + int count = mInner.hasSensorListeners(ids); + mAcc = null; + mGyro = null; + mMag = null; + mLight = null; + if (count > 0) { + Application app = (Application) getContext().getApplicationContext(); + + mSensorManager = (SensorManager) app.getSystemService(Context.SENSOR_SERVICE); + for (int i = 0; i < count; i++) { + switch (ids[i]) { + case RemoteContext.ID_ACCELERATION_X: + case RemoteContext.ID_ACCELERATION_Y: + case RemoteContext.ID_ACCELERATION_Z: + if (mAcc == null) { + mAcc = mSensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER); + } + break; + case RemoteContext.ID_GYRO_ROT_X: + case RemoteContext.ID_GYRO_ROT_Y: + case RemoteContext.ID_GYRO_ROT_Z: + if (mGyro == null) { + mGyro = mSensorManager.getDefaultSensor(Sensor.TYPE_GYROSCOPE); + } + break; + case RemoteContext.ID_MAGNETIC_X: + case RemoteContext.ID_MAGNETIC_Y: + case RemoteContext.ID_MAGNETIC_Z: + if (mMag == null) { + mMag = mSensorManager.getDefaultSensor(Sensor.TYPE_MAGNETIC_FIELD); + } + break; + case RemoteContext.ID_LIGHT: + if (mLight == null) { + mLight = mSensorManager.getDefaultSensor(Sensor.TYPE_LIGHT); + } + } + } + } + registerListener(); + } + + @Override + protected void onDetachedFromWindow() { + super.onDetachedFromWindow(); + unregisterListener(); + } + + public void registerListener() { + Sensor[] s = {mAcc, mGyro, mMag, mLight}; + if (mListener != null) { + unregisterListener(); + } + SensorEventListener listener = + new SensorEventListener() { + @Override + public void onSensorChanged(SensorEvent event) { + if (event.sensor == mAcc) { + mInner.setExternalFloat( + RemoteContext.ID_ACCELERATION_X, event.values[0]); + mInner.setExternalFloat( + RemoteContext.ID_ACCELERATION_Y, event.values[1]); + mInner.setExternalFloat( + RemoteContext.ID_ACCELERATION_Z, event.values[2]); + } else if (event.sensor == mGyro) { + mInner.setExternalFloat(RemoteContext.ID_GYRO_ROT_X, event.values[0]); + mInner.setExternalFloat(RemoteContext.ID_GYRO_ROT_Y, event.values[1]); + mInner.setExternalFloat(RemoteContext.ID_GYRO_ROT_Z, event.values[2]); + } else if (event.sensor == mMag) { + mInner.setExternalFloat(RemoteContext.ID_MAGNETIC_X, event.values[0]); + mInner.setExternalFloat(RemoteContext.ID_MAGNETIC_Y, event.values[1]); + mInner.setExternalFloat(RemoteContext.ID_MAGNETIC_Z, event.values[2]); + } else if (event.sensor == mLight) { + mInner.setExternalFloat(RemoteContext.ID_LIGHT, event.values[0]); + } + } + + @Override + public void onAccuracyChanged(Sensor sensor, int accuracy) {} + }; + + Sensor[] sensors = {mAcc, mGyro, mMag, mLight}; + for (int i = 0; i < sensors.length; i++) { + Sensor sensor = sensors[i]; + if (sensor != null) { + mListener = listener; + mSensorManager.registerListener( + mListener, sensor, SensorManager.SENSOR_DELAY_NORMAL); + } + } + } + + public void unregisterListener() { + if (mListener != null && mSensorManager != null) { + mSensorManager.unregisterListener(mListener); + } + mListener = null; + } } 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 0b650a93c9dba5b452ce29bb64188a4f7f5af6d5..3c91cffcec3f0951abe75a758cb61f6a8077eccc 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 @@ -15,6 +15,7 @@ */ package com.android.internal.widget.remotecompose.player.platform; +import android.annotation.NonNull; import android.graphics.Bitmap; import android.graphics.BlendMode; import android.graphics.Canvas; @@ -247,7 +248,7 @@ public class AndroidPaintContext extends PaintContext { } @Override - public void getTextBounds(int textId, int start, int end, int flags, float[] bounds) { + public void getTextBounds(int textId, int start, int end, int flags, @NonNull float[] bounds) { String str = getText(textId); if (end == -1) { end = str.length(); @@ -420,7 +421,7 @@ public class AndroidPaintContext extends PaintContext { * @param paintData the list change to the paint */ @Override - public void applyPaint(PaintBundle paintData) { + public void applyPaint(@NonNull PaintBundle paintData) { paintData.applyPaintChange( (PaintContext) this, new PaintChanges() { @@ -576,8 +577,8 @@ public class AndroidPaintContext extends PaintContext { @Override public void setLinearGradient( - int[] colors, - float[] stops, + @NonNull int[] colors, + @NonNull float[] stops, float startX, float startY, float endX, @@ -596,8 +597,8 @@ public class AndroidPaintContext extends PaintContext { @Override public void setRadialGradient( - int[] colors, - float[] stops, + @NonNull int[] colors, + @NonNull float[] stops, float centerX, float centerY, float radius, @@ -614,7 +615,10 @@ public class AndroidPaintContext extends PaintContext { @Override public void setSweepGradient( - int[] colors, float[] stops, float centerX, float centerY) { + @NonNull int[] colors, + @NonNull float[] stops, + float centerX, + float centerY) { mPaint.setShader(new SweepGradient(centerX, centerY, colors, stops)); } diff --git a/core/java/com/android/internal/widget/remotecompose/player/platform/AndroidPlatformServices.java b/core/java/com/android/internal/widget/remotecompose/player/platform/AndroidPlatformServices.java index f28e85a44c1bdaa4919a6847f705958aa37a0a72..ba8d83bff51f4d295e3ba6d72f7ee3510725c781 100644 --- a/core/java/com/android/internal/widget/remotecompose/player/platform/AndroidPlatformServices.java +++ b/core/java/com/android/internal/widget/remotecompose/player/platform/AndroidPlatformServices.java @@ -15,6 +15,8 @@ */ package com.android.internal.widget.remotecompose.player.platform; +import android.annotation.NonNull; +import android.annotation.Nullable; import android.graphics.Bitmap; import android.graphics.Path; import android.graphics.PathIterator; @@ -31,7 +33,7 @@ public class AndroidPlatformServices implements Platform { private static final String LOG_TAG = "RemoteCompose"; @Override - public byte[] imageToByteArray(Object image) { + public byte[] imageToByteArray(@NonNull Object image) { if (image instanceof Bitmap) { // let's create a bitmap ByteArrayOutputStream byteArrayBitmapStream = new ByteArrayOutputStream(); @@ -42,7 +44,7 @@ public class AndroidPlatformServices implements Platform { } @Override - public int getImageWidth(Object image) { + public int getImageWidth(@NonNull Object image) { if (image instanceof Bitmap) { return ((Bitmap) image).getWidth(); } @@ -50,7 +52,7 @@ public class AndroidPlatformServices implements Platform { } @Override - public int getImageHeight(Object image) { + public int getImageHeight(@NonNull Object image) { if (image instanceof Bitmap) { return ((Bitmap) image).getHeight(); } @@ -58,7 +60,8 @@ public class AndroidPlatformServices implements Platform { } @Override - public float[] pathToFloatArray(Object path) { + @Nullable + public float[] pathToFloatArray(@NonNull Object path) { // if (path is RemotePath) { // return path.createFloatArray() // } @@ -88,7 +91,7 @@ public class AndroidPlatformServices implements Platform { } } - private float[] androidPathToFloatArray(Path path) { + private @NonNull float[] androidPathToFloatArray(@NonNull Path path) { PathIterator i = path.getPathIterator(); int estimatedSize = 0; diff --git a/core/java/com/android/internal/widget/remotecompose/player/platform/AndroidRemoteContext.java b/core/java/com/android/internal/widget/remotecompose/player/platform/AndroidRemoteContext.java index 7a7edba160c8abaf6b77b3d0300298c54b4ee9f5..77c25147b1fd61c6d2f14cdf1043a5233d0383af 100644 --- a/core/java/com/android/internal/widget/remotecompose/player/platform/AndroidRemoteContext.java +++ b/core/java/com/android/internal/widget/remotecompose/player/platform/AndroidRemoteContext.java @@ -15,6 +15,8 @@ */ package com.android.internal.widget.remotecompose.player.platform; +import android.annotation.NonNull; +import android.annotation.Nullable; import android.graphics.Bitmap; import android.graphics.BitmapFactory; import android.graphics.Canvas; @@ -22,11 +24,15 @@ import android.graphics.Canvas; import com.android.internal.widget.remotecompose.core.RemoteContext; import com.android.internal.widget.remotecompose.core.TouchListener; 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.ShaderData; import com.android.internal.widget.remotecompose.core.operations.utilities.ArrayAccess; import com.android.internal.widget.remotecompose.core.operations.utilities.DataMap; +import java.io.IOException; +import java.net.MalformedURLException; +import java.net.URL; import java.util.HashMap; /** @@ -53,7 +59,7 @@ class AndroidRemoteContext extends RemoteContext { /////////////////////////////////////////////////////////////////////////////////////////////// @Override - public void loadPathData(int instanceId, float[] floatPath) { + public void loadPathData(int instanceId, @NonNull float[] floatPath) { if (!mRemoteComposeState.containsId(instanceId)) { mRemoteComposeState.cacheData(instanceId, floatPath); } @@ -74,12 +80,12 @@ class AndroidRemoteContext extends RemoteContext { HashMap mVarNameHashMap = new HashMap<>(); @Override - public void loadVariableName(String varName, int varId, int varType) { + public void loadVariableName(@NonNull String varName, int varId, int varType) { mVarNameHashMap.put(varName, new VarName(varName, varId, varType)); } @Override - public void setNamedStringOverride(String stringName, String value) { + public void setNamedStringOverride(@NonNull String stringName, @NonNull String value) { if (mVarNameHashMap.get(stringName) != null) { int id = mVarNameHashMap.get(stringName).mId; overrideText(id, value); @@ -87,7 +93,7 @@ class AndroidRemoteContext extends RemoteContext { } @Override - public void clearNamedStringOverride(String stringName) { + public void clearNamedStringOverride(@NonNull String stringName) { if (mVarNameHashMap.get(stringName) != null) { int id = mVarNameHashMap.get(stringName).mId; clearDataOverride(id); @@ -96,7 +102,7 @@ class AndroidRemoteContext extends RemoteContext { } @Override - public void setNamedIntegerOverride(String stringName, int value) { + public void setNamedIntegerOverride(@NonNull String stringName, int value) { if (mVarNameHashMap.get(stringName) != null) { int id = mVarNameHashMap.get(stringName).mId; overrideInt(id, value); @@ -104,7 +110,7 @@ class AndroidRemoteContext extends RemoteContext { } @Override - public void clearNamedIntegerOverride(String integerName) { + public void clearNamedIntegerOverride(@NonNull String integerName) { if (mVarNameHashMap.get(integerName) != null) { int id = mVarNameHashMap.get(integerName).mId; clearIntegerOverride(id); @@ -118,18 +124,18 @@ class AndroidRemoteContext extends RemoteContext { * @param colorName name of color * @param color */ - public void setNamedColorOverride(String colorName, int color) { + public void setNamedColorOverride(@NonNull String colorName, int color) { int id = mVarNameHashMap.get(colorName).mId; mRemoteComposeState.overrideColor(id, color); } @Override - public void addCollection(int id, ArrayAccess collection) { + public void addCollection(int id, @NonNull ArrayAccess collection) { mRemoteComposeState.addCollection(id, collection); } @Override - public void putDataMap(int id, DataMap map) { + public void putDataMap(int id, @NonNull DataMap map) { mRemoteComposeState.putDataMap(id, map); } @@ -139,7 +145,7 @@ class AndroidRemoteContext extends RemoteContext { } @Override - public void runAction(int id, String metadata) { + public void runAction(int id, @NonNull String metadata) { mDocument.performClick(id); } @@ -152,21 +158,66 @@ class AndroidRemoteContext extends RemoteContext { /** * Decode a byte array into an image and cache it using the given imageId * - * @param width with of image to be loaded + * @param encoding how the data is encoded 0 = png, 1 = raw, 2 = url + * @param type the type of the data 0 = RGBA 8888, 1 = 888, 2 = 8 gray + * @param width with of image to be loaded largest dimension is 32767 * @param height height of image to be loaded * @param bitmap a byte array containing the image information * @oaram imageId the id of the image */ @Override - public void loadBitmap(int imageId, int width, int height, byte[] bitmap) { + public void loadBitmap( + int imageId, short encoding, short type, int width, int height, @NonNull byte[] data) { if (!mRemoteComposeState.containsId(imageId)) { - Bitmap image = BitmapFactory.decodeByteArray(bitmap, 0, bitmap.length); + Bitmap image = null; + switch (encoding) { + case BitmapData.ENCODING_INLINE: + switch (type) { + case BitmapData.TYPE_PNG_8888: + image = BitmapFactory.decodeByteArray(data, 0, data.length); + break; + case BitmapData.TYPE_RAW8888: + image = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888); + int[] idata = new int[data.length / 4]; + for (int i = 0; i < idata.length; i++) { + int p = i * 4; + idata[i] = + (data[p] << 24) + | (data[p + 1] << 16) + | (data[p + 2] << 8) + | data[p + 3]; + } + image.setPixels(idata, 0, width, 0, 0, width, height); + break; + case BitmapData.TYPE_RAW8: + image = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888); + int[] bdata = new int[data.length / 4]; + for (int i = 0; i < bdata.length; i++) { + + bdata[i] = 0x1010101 * data[i]; + } + image.setPixels(bdata, 0, width, 0, 0, width, height); + break; + } + break; + case BitmapData.ENCODING_FILE: + image = BitmapFactory.decodeFile(new String(data)); + break; + case BitmapData.ENCODING_URL: + try { + image = BitmapFactory.decodeStream(new URL(new String(data)).openStream()); + } catch (MalformedURLException e) { + throw new RuntimeException(e); + } catch (IOException e) { + throw new RuntimeException(e); + } + } mRemoteComposeState.cacheData(imageId, image); } } @Override - public void loadText(int id, String text) { + public void loadText(int id, @NonNull String text) { if (!mRemoteComposeState.containsId(id)) { mRemoteComposeState.cacheData(id, text); } else { @@ -225,12 +276,12 @@ class AndroidRemoteContext extends RemoteContext { } @Override - public void loadAnimatedFloat(int id, FloatExpression animatedFloat) { + public void loadAnimatedFloat(int id, @NonNull FloatExpression animatedFloat) { mRemoteComposeState.cacheData(id, animatedFloat); } @Override - public void loadShader(int id, ShaderData value) { + public void loadShader(int id, @NonNull ShaderData value) { mRemoteComposeState.cacheData(id, value); } @@ -240,7 +291,7 @@ class AndroidRemoteContext extends RemoteContext { } @Override - public void putObject(int id, Object value) { + public void putObject(int id, @NonNull Object value) { mRemoteComposeState.updateObject(id, value); } @@ -260,7 +311,7 @@ class AndroidRemoteContext extends RemoteContext { } @Override - public void listensTo(int id, VariableSupport variableSupport) { + public void listensTo(int id, @NonNull VariableSupport variableSupport) { mRemoteComposeState.listenToVar(id, variableSupport); } @@ -270,6 +321,7 @@ class AndroidRemoteContext extends RemoteContext { } @Override + @Nullable public ShaderData getShader(int id) { return (ShaderData) mRemoteComposeState.getFromId(id); } diff --git a/core/java/com/android/internal/widget/remotecompose/player/platform/ClickAreaView.java b/core/java/com/android/internal/widget/remotecompose/player/platform/ClickAreaView.java index fdd9aad68d47455ba469719a065e28adde565bea..41ed017b3896460965f2d4a9f89e3ec85f4ef12d 100644 --- a/core/java/com/android/internal/widget/remotecompose/player/platform/ClickAreaView.java +++ b/core/java/com/android/internal/widget/remotecompose/player/platform/ClickAreaView.java @@ -15,6 +15,7 @@ */ package com.android.internal.widget.remotecompose.player.platform; +import android.annotation.Nullable; import android.content.Context; import android.graphics.Canvas; import android.graphics.Paint; @@ -23,13 +24,17 @@ import android.view.View; /** Implementation for the click handling */ class ClickAreaView extends View { private int mId; - private String mMetadata; + private final String mMetadata; Paint mPaint = new Paint(); private boolean mDebug; ClickAreaView( - Context context, boolean debug, int id, String contentDescription, String metadata) { + Context context, + boolean debug, + int id, + @Nullable String contentDescription, + String metadata) { super(context); this.mId = id; this.mMetadata = metadata; 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 b54ed8a77ec5bc88b4f7f45f38495075325fef80..8f55f8abf713da060a6b1bceb0ab6ec1f2e24789 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 @@ -26,6 +26,7 @@ import android.view.View; import android.widget.FrameLayout; import com.android.internal.widget.remotecompose.core.CoreDocument; +import com.android.internal.widget.remotecompose.core.RemoteContext; import com.android.internal.widget.remotecompose.core.operations.RootContentBehavior; import com.android.internal.widget.remotecompose.core.operations.Theme; import com.android.internal.widget.remotecompose.player.RemoteComposeDocument; @@ -194,6 +195,20 @@ public class RemoteComposeCanvas extends FrameLayout implements View.OnAttachSta } } + public int hasSensorListeners(int[] ids) { + int count = 0; + for (int id = RemoteContext.ID_ACCELERATION_X; id <= RemoteContext.ID_LIGHT; id++) { + if (mARContext.mRemoteComposeState.hasListener(id)) { + ids[count++] = id; + } + } + return count; + } + + public void setExternalFloat(int id, float value) { + mARContext.loadFloat(id, value); + } + public interface ClickCallbacks { void click(int id, String metadata); } @@ -344,7 +359,9 @@ public class RemoteComposeCanvas extends FrameLayout implements View.OnAttachSta mARContext.setAnimationEnabled(true); mARContext.currentTime = System.currentTimeMillis(); mARContext.setDebug(mDebug); + float density = getContext().getResources().getDisplayMetrics().density; mARContext.useCanvas(canvas); + mARContext.setDensity(density); mARContext.mWidth = getWidth(); mARContext.mHeight = getHeight(); mDocument.paint(mARContext, mTheme); diff --git a/core/java/com/android/server/pm/pkg/AndroidPackage.java b/core/java/com/android/server/pm/pkg/AndroidPackage.java index d05f5e3950b41bc3b67e68f3872e55b1d7306754..70dd10f2c371c1c706c5752f8ffb188aff707a1d 100644 --- a/core/java/com/android/server/pm/pkg/AndroidPackage.java +++ b/core/java/com/android/server/pm/pkg/AndroidPackage.java @@ -874,6 +874,14 @@ public interface AndroidPackage { @ApplicationInfo.MemtagMode int getMemtagMode(); + /** + * @see ApplicationInfo#getPageSizeAppCompatFlags() + * @see R.styleable#AndroidManifestApplication_pageSizeCompat + * @hide + */ + @ApplicationInfo.PageSizeAppCompatFlags + int getPageSizeAppCompatFlags(); + /** * TODO(b/135203078): Make all the Bundles immutable (and non-null by shared empty reference?) * @see R.styleable#AndroidManifestMetaData diff --git a/core/jni/Android.bp b/core/jni/Android.bp index a21bf9abdd7b19630beea732e7b3e5a43bbfef67..5c03c5cca66d7d159a572dd62219d69f48fc9940 100644 --- a/core/jni/Android.bp +++ b/core/jni/Android.bp @@ -161,6 +161,7 @@ cc_library_shared_for_libandroid_runtime { "android_view_MotionPredictor.cpp", "android_view_PointerIcon.cpp", "android_view_SurfaceControl.cpp", + "android_view_SurfaceControlActivePictureListener.cpp", "android_view_SurfaceControlHdrLayerInfoListener.cpp", "android_view_WindowManagerGlobal.cpp", "android_graphics_BLASTBufferQueue.cpp", diff --git a/core/jni/AndroidRuntime.cpp b/core/jni/AndroidRuntime.cpp index 821861efd59b8011f48ca19730fdfd5ef3a70b8c..00a62977de43acd4533af87bb6c6dfca1b4ee5a4 100644 --- a/core/jni/AndroidRuntime.cpp +++ b/core/jni/AndroidRuntime.cpp @@ -128,6 +128,7 @@ extern int register_android_view_InputApplicationHandle(JNIEnv* env); extern int register_android_view_InputWindowHandle(JNIEnv* env); extern int register_android_view_Surface(JNIEnv* env); extern int register_android_view_SurfaceControl(JNIEnv* env); +extern int register_android_view_SurfaceControlActivePictureListener(JNIEnv* env); extern int register_android_view_SurfaceControlHdrLayerInfoListener(JNIEnv* env); extern int register_android_view_SurfaceSession(JNIEnv* env); extern int register_android_view_CompositionSamplingListener(JNIEnv* env); @@ -1563,6 +1564,7 @@ static const RegJNIRec gRegJNI[] = { REG_JNI(register_android_view_DisplayEventReceiver), REG_JNI(register_android_view_Surface), REG_JNI(register_android_view_SurfaceControl), + REG_JNI(register_android_view_SurfaceControlActivePictureListener), REG_JNI(register_android_view_SurfaceControlHdrLayerInfoListener), REG_JNI(register_android_view_SurfaceSession), REG_JNI(register_android_view_InputApplicationHandle), diff --git a/core/jni/android_content_res_ApkAssets.cpp b/core/jni/android_content_res_ApkAssets.cpp index ded1a9949ef8fa0f63e36306cc118d0f6d82fed8..1e7bfe32ba79dae64e36890424bf674bbc3d0670 100644 --- a/core/jni/android_content_res_ApkAssets.cpp +++ b/core/jni/android_content_res_ApkAssets.cpp @@ -36,6 +36,8 @@ using ::android::base::unique_fd; namespace android { +static constexpr bool kLogWeakReachableDeletedAssets = false; + static struct overlayableinfo_offsets_t { jclass classObject; jmethodID constructor; @@ -97,7 +99,7 @@ static void DeleteGuardedApkAssets(Guarded& apk_ass if (useCount > 1) { ALOGW("ApkAssets: Deleting an object '%s' with %d > 1 strong and %d weak references", (*assets)->GetDebugName().c_str(), int(useCount), int(weakCount)); - } else if (weakCount > 0) { + } else if constexpr (kLogWeakReachableDeletedAssets) if (weakCount > 0) { ALOGW("ApkAssets: Deleting an ApkAssets object '%s' with %d weak references", (*assets)->GetDebugName().c_str(), int(weakCount)); } diff --git a/core/jni/android_os_PerformanceHintManager.cpp b/core/jni/android_os_PerformanceHintManager.cpp index aebe7ea7ee61aeb54d56c277ccae96717de42ebd..0f78c9e93a00d13ab9c9307c5fb6b81178faa725 100644 --- a/core/jni/android_os_PerformanceHintManager.cpp +++ b/core/jni/android_os_PerformanceHintManager.cpp @@ -88,9 +88,10 @@ void ensureAPerformanceHintBindingInitialized() { "Failed to find required symbol " "APerformanceHint_getPreferredUpdateRateNanos!"); - gAPH_createSessionFn = (APH_createSession)dlsym(handle_, "APerformanceHint_createSession"); + gAPH_createSessionFn = + (APH_createSession)dlsym(handle_, "APerformanceHint_createSessionFromJava"); LOG_ALWAYS_FATAL_IF(gAPH_createSessionFn == nullptr, - "Failed to find required symbol APerformanceHint_createSession!"); + "Failed to find required symbol APerformanceHint_createSessionFromJava!"); gAPH_updateTargetWorkDurationFn = (APH_updateTargetWorkDuration)dlsym(handle_, @@ -106,9 +107,9 @@ void ensureAPerformanceHintBindingInitialized() { "Failed to find required symbol " "APerformanceHint_reportActualWorkDuration!"); - gAPH_closeSessionFn = (APH_closeSession)dlsym(handle_, "APerformanceHint_closeSession"); + gAPH_closeSessionFn = (APH_closeSession)dlsym(handle_, "APerformanceHint_closeSessionFromJava"); LOG_ALWAYS_FATAL_IF(gAPH_closeSessionFn == nullptr, - "Failed to find required symbol APerformanceHint_closeSession!"); + "Failed to find required symbol APerformanceHint_closeSessionFromJava!"); gAPH_sendHintFn = (APH_sendHint)dlsym(handle_, "APerformanceHint_sendHint"); LOG_ALWAYS_FATAL_IF(gAPH_sendHintFn == nullptr, diff --git a/core/jni/android_view_SurfaceControl.cpp b/core/jni/android_view_SurfaceControl.cpp index 593b982d4cf209ad53d984c7b6664522c681c70b..0c243d1dc1857be6e2aebc690ff577e9c980dd26 100644 --- a/core/jni/android_view_SurfaceControl.cpp +++ b/core/jni/android_view_SurfaceControl.cpp @@ -55,6 +55,7 @@ #include #include #include +#include #include #include #include @@ -118,6 +119,7 @@ static struct { jfieldID renderFrameRate; jfieldID hasArrSupport; jfieldID frameRateCategoryRate; + jfieldID supportedRefreshRates; jfieldID supportedColorModes; jfieldID activeColorMode; jfieldID hdrCapabilities; @@ -820,6 +822,21 @@ static void nativeSetLuts(JNIEnv* env, jclass clazz, jlong transactionObj, jlong transaction->setLuts(ctrl, base::unique_fd(fd), offsets, dimensions, sizes, samplingKeys); } +static void nativeSetPictureProfileId(JNIEnv* env, jclass clazz, jlong transactionObj, + jlong surfaceControlObj, jlong pictureProfileId) { + auto transaction = reinterpret_cast(transactionObj); + SurfaceControl* const surfaceControl = reinterpret_cast(surfaceControlObj); + PictureProfileHandle handle(pictureProfileId); + transaction->setPictureProfileHandle(surfaceControl, handle); +} + +static void nativeSetContentPriority(JNIEnv* env, jclass clazz, jlong transactionObj, + jlong surfaceControlObj, jint priority) { + auto transaction = reinterpret_cast(transactionObj); + SurfaceControl* const surfaceControl = reinterpret_cast(surfaceControlObj); + transaction->setContentPriority(surfaceControl, priority); +} + static void nativeSetCachingHint(JNIEnv* env, jclass clazz, jlong transactionObj, jlong nativeObject, jint cachingHint) { auto transaction = reinterpret_cast(transactionObj); @@ -1492,6 +1509,21 @@ static jobject nativeGetDynamicDisplayInfo(JNIEnv* env, jclass clazz, jlong disp env->SetBooleanField(object, gDynamicDisplayInfoClassInfo.hasArrSupport, info.hasArrSupport); env->SetObjectField(object, gDynamicDisplayInfoClassInfo.frameRateCategoryRate, convertFrameRateCategoryRateToJavaObject(env, info.frameRateCategoryRate)); + + jfloatArray supportedRefreshRatesArray = env->NewFloatArray(info.supportedRefreshRates.size()); + if (supportedRefreshRatesArray == NULL) { + jniThrowException(env, "java/lang/OutOfMemoryError", NULL); + return NULL; + } + jfloat* supportedRefreshRatesArrayValues = + env->GetFloatArrayElements(supportedRefreshRatesArray, 0); + for (size_t i = 0; i < info.supportedRefreshRates.size(); i++) { + supportedRefreshRatesArrayValues[i] = static_cast(info.supportedRefreshRates[i]); + } + env->ReleaseFloatArrayElements(supportedRefreshRatesArray, supportedRefreshRatesArrayValues, 0); + env->SetObjectField(object, gDynamicDisplayInfoClassInfo.supportedRefreshRates, + supportedRefreshRatesArray); + jintArray colorModesArray = env->NewIntArray(info.supportedColorModes.size()); if (colorModesArray == NULL) { jniThrowException(env, "java/lang/OutOfMemoryError", NULL); @@ -2351,6 +2383,20 @@ static jboolean nativeBootFinished(JNIEnv* env, jclass clazz) { return error == OK ? JNI_TRUE : JNI_FALSE; } +static jint nativeGetMaxPictureProfiles(JNIEnv* env, jclass clazz) { + const auto displayIds = SurfaceComposerClient::SurfaceComposerClient::getPhysicalDisplayIds(); + int largestMaxProfiles = 0; + for (auto displayId : displayIds) { + sp token = SurfaceComposerClient::getPhysicalDisplayToken(displayId); + int32_t maxProfiles = 0; + SurfaceComposerClient::getMaxLayerPictureProfiles(token, &maxProfiles); + if (maxProfiles > largestMaxProfiles) { + largestMaxProfiles = maxProfiles; + } + } + return largestMaxProfiles; +} + jlong nativeCreateTpc(JNIEnv* env, jclass clazz, jobject trustedPresentationCallback) { return reinterpret_cast( new TrustedPresentationCallbackWrapper(env, trustedPresentationCallback)); @@ -2672,6 +2718,8 @@ static const JNINativeMethod sSurfaceControlMethods[] = { (void*)nativeGetDefaultApplyToken }, {"nativeBootFinished", "()Z", (void*)nativeBootFinished }, + {"nativeGetMaxPictureProfiles", "()I", + (void*)nativeGetMaxPictureProfiles }, {"nativeCreateTpc", "(Landroid/view/SurfaceControl$TrustedPresentationCallback;)J", (void*)nativeCreateTpc}, {"getNativeTrustedPresentationCallbackFinalizer", "()J", (void*)getNativeTrustedPresentationCallbackFinalizer }, @@ -2683,6 +2731,8 @@ static const JNINativeMethod sSurfaceControlMethods[] = { (void*)nativeNotifyShutdown }, {"nativeSetLuts", "(JJ[F[I[I[I[I)V", (void*)nativeSetLuts }, {"nativeEnableDebugLogCallPoints", "(J)V", (void*)nativeEnableDebugLogCallPoints }, + {"nativeSetPictureProfileId", "(JJJ)V", (void*)nativeSetPictureProfileId }, + {"nativeSetContentPriority", "(JJI)V", (void*)nativeSetContentPriority }, // clang-format on }; @@ -2732,6 +2782,8 @@ int register_android_view_SurfaceControl(JNIEnv* env) gFrameRateCategoryRateClassInfo.ctor = GetMethodIDOrDie(env, frameRateCategoryRateClazz, "", "(FF)V"); + gDynamicDisplayInfoClassInfo.supportedRefreshRates = + GetFieldIDOrDie(env, dynamicInfoClazz, "supportedRefreshRates", "[F"); gDynamicDisplayInfoClassInfo.supportedColorModes = GetFieldIDOrDie(env, dynamicInfoClazz, "supportedColorModes", "[I"); gDynamicDisplayInfoClassInfo.activeColorMode = diff --git a/core/jni/android_view_SurfaceControlActivePictureListener.cpp b/core/jni/android_view_SurfaceControlActivePictureListener.cpp new file mode 100644 index 0000000000000000000000000000000000000000..91849c1514cc865033c8d52f6f74236fb2afa656 --- /dev/null +++ b/core/jni/android_view_SurfaceControlActivePictureListener.cpp @@ -0,0 +1,191 @@ +/* + * Copyright 2021 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#define LOG_TAG "SurfaceControlActivePictureListener" + +#include +#include +#include +#include +#include +#include +#include + +#include "android_util_Binder.h" +#include "core_jni_helpers.h" + +namespace android { + +namespace { + +struct { + jclass clazz; + jmethodID onActivePicturesChanged; +} gListenerClassInfo; + +static struct { + jclass clazz; + jmethodID constructor; +} gActivePictureClassInfo; + +static struct { + jclass clazz; + jmethodID constructor; + jfieldID id; +} gPictureProfileHandleClassInfo; + +struct SurfaceControlActivePictureListener : public gui::BnActivePictureListener { + SurfaceControlActivePictureListener(JNIEnv* env, jobject listener) + : mListener(env->NewGlobalRef(listener)) { + LOG_ALWAYS_FATAL_IF(env->GetJavaVM(&mVm) != JNI_OK, "Failed to GetJavaVm"); + } + + binder::Status onActivePicturesChanged( + const std::vector& activePictures) override { + JNIEnv* env = requireEnv(); + + ScopedLocalRef activePictureArrayObj(env); + activePictureArrayObj.reset( + env->NewObjectArray(activePictures.size(), gActivePictureClassInfo.clazz, NULL)); + if (env->ExceptionCheck() || !activePictureArrayObj.get()) { + LOGE_EX(env); + LOG_ALWAYS_FATAL("Failed to create an active picture array."); + } + + { + std::vector> pictureProfileHandleObjs; + std::vector> activePictureObjs; + + for (size_t i = 0; i < activePictures.size(); ++i) { + pictureProfileHandleObjs.push_back(ScopedLocalRef(env)); + pictureProfileHandleObjs[i].reset( + env->NewObject(gPictureProfileHandleClassInfo.clazz, + gPictureProfileHandleClassInfo.constructor, + activePictures[i].pictureProfileId)); + if (env->ExceptionCheck() || !pictureProfileHandleObjs[i].get()) { + LOGE_EX(env); + LOG_ALWAYS_FATAL("Failed to create a picture profile handle."); + } + activePictureObjs.push_back(ScopedLocalRef(env)); + activePictureObjs[i].reset(env->NewObject(gActivePictureClassInfo.clazz, + gActivePictureClassInfo.constructor, + activePictures[i].layerId, + activePictures[i].ownerUid, + pictureProfileHandleObjs[i].get())); + if (env->ExceptionCheck() || !activePictureObjs[i].get()) { + LOGE_EX(env); + LOG_ALWAYS_FATAL("Failed to create an active picture."); + } + env->SetObjectArrayElement(activePictureArrayObj.get(), i, + activePictureObjs[i].get()); + } + + env->CallVoidMethod(mListener, gListenerClassInfo.onActivePicturesChanged, + activePictureArrayObj.get()); + } + + if (env->ExceptionCheck()) { + ALOGE("SurfaceControlActivePictureListener.onActivePicturesChanged failed"); + LOGE_EX(env); + env->ExceptionClear(); + } + return binder::Status::ok(); + } + + status_t startListening() { + // TODO(b/337330263): Make SF multiple-listener capable + return SurfaceComposerClient::setActivePictureListener(this); + } + + status_t stopListening() { + return SurfaceComposerClient::setActivePictureListener(nullptr); + } + +protected: + virtual ~SurfaceControlActivePictureListener() { + JNIEnv* env = requireEnv(); + env->DeleteGlobalRef(mListener); + } + + JNIEnv* requireEnv() { + JNIEnv* env = nullptr; + if (mVm->GetEnv(reinterpret_cast(&env), JNI_VERSION_1_6) != JNI_OK) { + if (mVm->AttachCurrentThreadAsDaemon(&env, nullptr) != JNI_OK) { + LOG_ALWAYS_FATAL("Failed to AttachCurrentThread!"); + } + } + return env; + } + +private: + jobject mListener; + JavaVM* mVm; +}; + +jlong nativeMakeAndStartListening(JNIEnv* env, jobject jthis) { + auto listener = sp::make(env, jthis); + status_t err = listener->startListening(); + if (err != OK) { + auto errStr = statusToString(err); + jniThrowExceptionFmt(env, "java/lang/IllegalStateException", + "Failed to start listening, err = %d (%s)", err, errStr.c_str()); + return 0; + } + SurfaceControlActivePictureListener* listenerRawPtr = listener.get(); + listenerRawPtr->incStrong(0); + return static_cast(reinterpret_cast(listenerRawPtr)); +} + +static void destroy(SurfaceControlActivePictureListener* listener) { + listener->stopListening(); + listener->decStrong(0); +} + +static jlong nativeGetDestructor(JNIEnv* env, jobject clazz) { + return static_cast(reinterpret_cast(&destroy)); +} + +const JNINativeMethod gMethods[] = { + /* name, signature, funcPtr */ + {"nativeGetDestructor", "()J", (void*)nativeGetDestructor}, + {"nativeMakeAndStartListening", "()J", (void*)nativeMakeAndStartListening}}; +} // namespace + +int register_android_view_SurfaceControlActivePictureListener(JNIEnv* env) { + int res = jniRegisterNativeMethods(env, "android/view/SurfaceControlActivePictureListener", + gMethods, NELEM(gMethods)); + LOG_ALWAYS_FATAL_IF(res < 0, "Unable to register native methods."); + + jclass listenerClazz = env->FindClass("android/view/SurfaceControlActivePictureListener"); + gListenerClassInfo.clazz = MakeGlobalRefOrDie(env, listenerClazz); + gListenerClassInfo.onActivePicturesChanged = + env->GetMethodID(listenerClazz, "onActivePicturesChanged", + "([Landroid/view/SurfaceControlActivePicture;)V"); + + gActivePictureClassInfo.clazz = static_cast( + env->NewGlobalRef(env->FindClass("android/view/SurfaceControlActivePicture"))); + gActivePictureClassInfo.constructor = + env->GetMethodID(gActivePictureClassInfo.clazz, "", + "(IILandroid/media/quality/PictureProfileHandle;)V"); + + gPictureProfileHandleClassInfo.clazz = static_cast( + env->NewGlobalRef(env->FindClass("android/media/quality/PictureProfileHandle"))); + gPictureProfileHandleClassInfo.constructor = + env->GetMethodID(gPictureProfileHandleClassInfo.clazz, "", "(J)V"); + return 0; +} + +} // namespace android diff --git a/core/jni/com_android_internal_content_NativeLibraryHelper.cpp b/core/jni/com_android_internal_content_NativeLibraryHelper.cpp index 7ad18b83f0d6b0cbb25eb97b2338e4bfe368508b..b2eeff36c007349bc2be3fb1cfafa359d27051d6 100644 --- a/core/jni/com_android_internal_content_NativeLibraryHelper.cpp +++ b/core/jni/com_android_internal_content_NativeLibraryHelper.cpp @@ -21,6 +21,7 @@ #include #include #include +#include #include #include #include @@ -38,6 +39,7 @@ #include #include +#include #include "com_android_internal_content_FileSystemUtils.h" #include "core_jni_helpers.h" @@ -60,6 +62,12 @@ enum install_status_t { NO_NATIVE_LIBRARIES = -114 }; +// These code should match with PageSizeAppCompatFlags inside ApplicationInfo.java +constexpr int PAGE_SIZE_APP_COMPAT_FLAG_ERROR = -1; +constexpr int PAGE_SIZE_APP_COMPAT_FLAG_UNDEFINED = 0; +constexpr int PAGE_SIZE_APP_COMPAT_FLAG_UNCOMPRESSED_LIBS_NOT_ALIGNED = 1 << 1; +constexpr int PAGE_SIZE_APP_COMPAT_FLAG_ELF_NOT_ALIGNED = 1 << 2; + typedef install_status_t (*iterFunc)(JNIEnv*, void*, ZipFileRO*, ZipEntryRO, const char*); static bool @@ -524,11 +532,7 @@ static inline bool app_compat_16kb_enabled() { static const size_t kPageSize = getpagesize(); // App compat is only applicable on 16kb-page-size devices. - if (kPageSize != 0x4000) { - return false; - } - - return android::base::GetBoolProperty("bionic.linker.16kb.app_compat.enabled", false); + return kPageSize == 0x4000; } static jint @@ -626,6 +630,166 @@ com_android_internal_content_NativeLibraryHelper_openApkFd(JNIEnv *env, jclass, return reinterpret_cast(zipFile); } +static jint checkLoadSegmentAlignment(const char* fileName, off64_t offset) { + std::vector programHeaders; + if (!getLoadSegmentPhdrs(fileName, offset, programHeaders)) { + ALOGE("Failed to read program headers from ELF file."); + return PAGE_SIZE_APP_COMPAT_FLAG_ERROR; + } + + int mode = PAGE_SIZE_APP_COMPAT_FLAG_UNDEFINED; + for (auto programHeader : programHeaders) { + if (programHeader.p_type != PT_LOAD) { + continue; + } + + // Set ELF alignment bit if 4 KB aligned LOAD segment is found + if (programHeader.p_align == 0x1000) { + ALOGI("Setting page size compat mode PAGE_SIZE_APP_COMPAT_FLAG_ELF_NOT_ALIGNED"); + mode |= PAGE_SIZE_APP_COMPAT_FLAG_ELF_NOT_ALIGNED; + break; + } + } + + return mode; +} + +static jint checkExtractedLibAlignment(ZipFileRO* zipFile, ZipEntryRO zipEntry, + const char* fileName, const std::string nativeLibPath) { + // Build local file path + const size_t fileNameLen = strlen(fileName); + char localFileName[nativeLibPath.size() + fileNameLen + 2]; + + if (strlcpy(localFileName, nativeLibPath.c_str(), sizeof(localFileName)) != + nativeLibPath.size()) { + ALOGE("Couldn't allocate local file name for library"); + return PAGE_SIZE_APP_COMPAT_FLAG_ERROR; + } + + *(localFileName + nativeLibPath.size()) = '/'; + + if (strlcpy(localFileName + nativeLibPath.size() + 1, fileName, + sizeof(localFileName) - nativeLibPath.size() - 1) != fileNameLen) { + ALOGE("Couldn't allocate local file name for library"); + return PAGE_SIZE_APP_COMPAT_FLAG_ERROR; + } + + struct statfs64 fsInfo; + int result = statfs64(localFileName, &fsInfo); + if (result < 0) { + ALOGE("Failed to stat file :%s", localFileName); + return PAGE_SIZE_APP_COMPAT_FLAG_ERROR; + } + + return checkLoadSegmentAlignment(localFileName, 0); +} + +static jint checkAlignment(JNIEnv* env, jstring javaNativeLibPath, jboolean extractNativeLibs, + ZipFileRO* zipFile, ZipEntryRO zipEntry, const char* fileName) { + int mode = PAGE_SIZE_APP_COMPAT_FLAG_UNDEFINED; + // Need two separate install status for APK and ELF alignment + static const size_t kPageSize = getpagesize(); + jint ret = INSTALL_SUCCEEDED; + + ScopedUtfChars nativeLibPath(env, javaNativeLibPath); + if (extractNativeLibs) { + ALOGI("extractNativeLibs specified, checking for extracted lib %s", fileName); + return checkExtractedLibAlignment(zipFile, zipEntry, fileName, nativeLibPath.c_str()); + } + + uint16_t method; + off64_t offset; + if (!zipFile->getEntryInfo(zipEntry, &method, nullptr, nullptr, &offset, nullptr, nullptr, + nullptr)) { + ALOGE("Couldn't read zip entry info from zipFile %s", zipFile->getZipFileName()); + return PAGE_SIZE_APP_COMPAT_FLAG_ERROR; + } + + // check if library is uncompressed and page-aligned + if (method != ZipFileRO::kCompressStored) { + ALOGE("Library '%s' is compressed - will not be able to open it directly from apk.\n", + fileName); + return PAGE_SIZE_APP_COMPAT_FLAG_ERROR; + } + + if (offset % kPageSize != 0) { + ALOGW("Library '%s' is not PAGE(%zu)-aligned - will not be able to open it directly " + "from apk.\n", + fileName, kPageSize); + mode |= PAGE_SIZE_APP_COMPAT_FLAG_UNCOMPRESSED_LIBS_NOT_ALIGNED; + ALOGI("Setting page size compat mode " + "PAGE_SIZE_APP_COMPAT_FLAG_UNCOMPRESSED_LIBS_NOT_ALIGNED for %s", + zipFile->getZipFileName()); + } + + int loadMode = checkLoadSegmentAlignment(zipFile->getZipFileName(), offset); + if (loadMode == PAGE_SIZE_APP_COMPAT_FLAG_ERROR) { + return PAGE_SIZE_APP_COMPAT_FLAG_ERROR; + } + mode |= loadMode; + return mode; +} + +// TODO(b/371049373): This function is copy of iterateOverNativeFiles with different way of handling +// and combining return values for all ELF and APKs. Find a way to consolidate two functions. +static jint com_android_internal_content_NativeLibraryHelper_checkApkAlignment( + JNIEnv* env, jclass clazz, jlong apkHandle, jstring javaNativeLibPath, jstring javaCpuAbi, + jboolean extractNativeLibs, jboolean debuggable) { + int mode = PAGE_SIZE_APP_COMPAT_FLAG_UNDEFINED; + ZipFileRO* zipFile = reinterpret_cast(apkHandle); + if (zipFile == nullptr) { + ALOGE("zipfile handle is null"); + return PAGE_SIZE_APP_COMPAT_FLAG_ERROR; + } + + auto result = NativeLibrariesIterator::create(zipFile, debuggable); + if (!result.ok()) { + ALOGE("Can't iterate over native libs for file:%s", zipFile->getZipFileName()); + return PAGE_SIZE_APP_COMPAT_FLAG_ERROR; + } + std::unique_ptr it(std::move(result.value())); + + const ScopedUtfChars cpuAbi(env, javaCpuAbi); + if (cpuAbi.c_str() == nullptr) { + ALOGE("cpuAbi is nullptr"); + // This would've thrown, so this return code isn't observable by Java. + return PAGE_SIZE_APP_COMPAT_FLAG_ERROR; + } + + while (true) { + auto next = it->next(); + if (!next.ok()) { + ALOGE("next iterator not found Error:%d", next.error()); + return PAGE_SIZE_APP_COMPAT_FLAG_ERROR; + } + auto entry = next.value(); + if (entry == nullptr) { + break; + } + + const char* fileName = it->currentEntry(); + const char* lastSlash = it->lastSlash(); + + // Check to make sure the CPU ABI of this file is one we support. + const char* cpuAbiOffset = fileName + APK_LIB_LEN; + const size_t cpuAbiRegionSize = lastSlash - cpuAbiOffset; + + if (cpuAbi.size() == cpuAbiRegionSize && + !strncmp(cpuAbiOffset, cpuAbi.c_str(), cpuAbiRegionSize)) { + int ret = checkAlignment(env, javaNativeLibPath, extractNativeLibs, zipFile, entry, + lastSlash + 1); + if (ret == PAGE_SIZE_APP_COMPAT_FLAG_ERROR) { + ALOGE("Alignment check returned for zipfile: %s, entry:%s", + zipFile->getZipFileName(), lastSlash + 1); + return PAGE_SIZE_APP_COMPAT_FLAG_ERROR; + } + mode |= ret; + } + } + + return mode; +} + static void com_android_internal_content_NativeLibraryHelper_close(JNIEnv *env, jclass, jlong apkHandle) { @@ -633,29 +797,23 @@ com_android_internal_content_NativeLibraryHelper_close(JNIEnv *env, jclass, jlon } static const JNINativeMethod gMethods[] = { - {"nativeOpenApk", - "(Ljava/lang/String;)J", - (void *)com_android_internal_content_NativeLibraryHelper_openApk}, - {"nativeOpenApkFd", - "(Ljava/io/FileDescriptor;Ljava/lang/String;)J", - (void *)com_android_internal_content_NativeLibraryHelper_openApkFd}, - {"nativeClose", - "(J)V", - (void *)com_android_internal_content_NativeLibraryHelper_close}, - {"nativeCopyNativeBinaries", - "(JLjava/lang/String;Ljava/lang/String;ZZ)I", - (void *)com_android_internal_content_NativeLibraryHelper_copyNativeBinaries}, - {"nativeSumNativeBinaries", - "(JLjava/lang/String;Z)J", - (void *)com_android_internal_content_NativeLibraryHelper_sumNativeBinaries}, - {"nativeFindSupportedAbi", - "(J[Ljava/lang/String;Z)I", - (void *)com_android_internal_content_NativeLibraryHelper_findSupportedAbi}, - {"hasRenderscriptBitcode", "(J)I", - (void *)com_android_internal_content_NativeLibraryHelper_hasRenderscriptBitcode}, + {"nativeOpenApk", "(Ljava/lang/String;)J", + (void*)com_android_internal_content_NativeLibraryHelper_openApk}, + {"nativeOpenApkFd", "(Ljava/io/FileDescriptor;Ljava/lang/String;)J", + (void*)com_android_internal_content_NativeLibraryHelper_openApkFd}, + {"nativeClose", "(J)V", (void*)com_android_internal_content_NativeLibraryHelper_close}, + {"nativeCopyNativeBinaries", "(JLjava/lang/String;Ljava/lang/String;ZZ)I", + (void*)com_android_internal_content_NativeLibraryHelper_copyNativeBinaries}, + {"nativeSumNativeBinaries", "(JLjava/lang/String;Z)J", + (void*)com_android_internal_content_NativeLibraryHelper_sumNativeBinaries}, + {"nativeFindSupportedAbi", "(J[Ljava/lang/String;Z)I", + (void*)com_android_internal_content_NativeLibraryHelper_findSupportedAbi}, + {"hasRenderscriptBitcode", "(J)I", + (void*)com_android_internal_content_NativeLibraryHelper_hasRenderscriptBitcode}, + {"nativeCheckAlignment", "(JLjava/lang/String;Ljava/lang/String;ZZ)I", + (void*)com_android_internal_content_NativeLibraryHelper_checkApkAlignment}, }; - int register_com_android_internal_content_NativeLibraryHelper(JNIEnv *env) { return RegisterMethodsOrDie(env, diff --git a/core/proto/android/content/package_item_info.proto b/core/proto/android/content/package_item_info.proto index b7408a4da381fc675e2a70e3c38e58ac54719d7d..facadeedd1f8faace6674cd1233d07805f116ca2 100644 --- a/core/proto/android/content/package_item_info.proto +++ b/core/proto/android/content/package_item_info.proto @@ -114,6 +114,7 @@ message ApplicationInfoProto { optional int32 enable_memtag = 20; optional bool native_heap_zero_init = 21; optional bool allow_cross_uid_activity_switch_from_below = 22; + optional int32 enable_page_size_app_compat = 23; } optional Detail detail = 17; repeated string overlay_paths = 18; diff --git a/core/proto/android/providers/settings/secure.proto b/core/proto/android/providers/settings/secure.proto index 6af742fb23f4adf43e5d68a0bd6a1e15134b7d78..2e0fe9eb13d932602a49c2ef1a48cb4a39e86749 100644 --- a/core/proto/android/providers/settings/secure.proto +++ b/core/proto/android/providers/settings/secure.proto @@ -256,6 +256,12 @@ message SecureSettingsProto { } optional Display display = 100; + message DoubleTapPowerButton { + optional SettingProto gesture_enabled = 1 [ (android.privacy).dest = DEST_AUTOMATIC ]; + optional SettingProto gesture = 2 [ (android.privacy).dest = DEST_AUTOMATIC ]; + } + optional DoubleTapPowerButton double_tap_power_button = 103; + message Doze { option (android.msg_privacy).dest = DEST_EXPLICIT; @@ -737,5 +743,5 @@ message SecureSettingsProto { // Please insert fields in alphabetical order and group them into messages // if possible (to avoid reaching the method limit). - // Next tag = 103; + // Next tag = 104; } diff --git a/core/proto/android/providers/settings/system.proto b/core/proto/android/providers/settings/system.proto index 9779dc0e00b811a2a0861378664f70d645040487..16d25657f08e2ebe6fdb1b60e1f59731b9ffa300 100644 --- a/core/proto/android/providers/settings/system.proto +++ b/core/proto/android/providers/settings/system.proto @@ -217,6 +217,7 @@ message SystemSettingsProto { optional SettingProto right_click_zone = 3 [ (android.privacy).dest = DEST_AUTOMATIC ]; optional SettingProto tap_to_click = 4 [ (android.privacy).dest = DEST_AUTOMATIC ]; optional SettingProto tap_dragging = 5 [ (android.privacy).dest = DEST_AUTOMATIC ]; + optional SettingProto three_finger_tap_customization = 6 [ (android.privacy).dest = DEST_AUTOMATIC ]; } optional Touchpad touchpad = 36; diff --git a/core/res/Android.bp b/core/res/Android.bp index 0e4e22b09e24bee1a65df5fb0be1d55313b7fa11..aacd8699c2020c68aaded755022171bcd852729f 100644 --- a/core/res/Android.bp +++ b/core/res/Android.bp @@ -160,7 +160,9 @@ android_app { "android.app.contextualsearch.flags-aconfig", "android.app.flags-aconfig", "android.appwidget.flags-aconfig", + "android.companion.virtualdevice.flags-aconfig", "android.content.pm.flags-aconfig", + "android.media.audio-aconfig", "android.provider.flags-aconfig", "camera_platform_flags", "android.net.platform.flags-aconfig", @@ -170,6 +172,7 @@ android_app { "android.os.vibrator.flags-aconfig", "android.media.tv.flags-aconfig", "android.security.flags-aconfig", + "device_policy_aconfig_flags", "com.android.hardware.input.input-aconfig", "aconfig_trade_in_mode_flags", "art-aconfig-flags", diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml index 7fcbf19d137fb6caa9514cfb006c0eb0506300ca..e2f3d2a32d0bdecceaf8e246f0acdb58cc268327 100644 --- a/core/res/AndroidManifest.xml +++ b/core/res/AndroidManifest.xml @@ -848,10 +848,10 @@ - + - + @@ -2649,6 +2649,22 @@ android:label="@string/permlab_getAccounts" /> + + + + + + - - - + @FlaggedApi(android.security.Flags.FLAG_AAPM_API) --> - - - - - - - - - @@ -6492,6 +6509,15 @@ + + + @@ -8034,6 +8060,13 @@ + + + @@ -8651,6 +8684,17 @@ + + + - - - - - + + + + + + + + + + + + + + + + + + + + + + + +